From 937f502158bc761a0ea7ab80d7a7e99417f8dc50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hajo=20Nils=20Krabbenh=C3=B6ft?= Date: Wed, 2 Jun 2021 15:04:23 +0200 Subject: [PATCH] Improve accelerated supersampling 2x antialiasing Avoid fractional pixel offsets by forcing integer division of m_screenSize. Shift rounded lookAtPoint onto OpenGL pixel center to ensure consistent rounding to int. The pixel 0..1 @ 1x needs to fill the area 0..2 @ 2x so its center moves by 0.5 * (pixel size @ 1x). --- common/gal/graphics_abstraction_layer.cpp | 3 ++- common/gal/opengl/gl_builtin_shaders.cpp | 2 ++ common/gal/opengl/opengl_compositor.cpp | 10 ++++++++++ common/gal/opengl/opengl_gal.cpp | 21 +++++++++++++++------ include/gal/opengl/opengl_compositor.h | 1 + include/gal/opengl/opengl_gal.h | 1 + 6 files changed, 31 insertions(+), 7 deletions(-) diff --git a/common/gal/graphics_abstraction_layer.cpp b/common/gal/graphics_abstraction_layer.cpp index 770a749b32..9f19cfbb57 100644 --- a/common/gal/graphics_abstraction_layer.cpp +++ b/common/gal/graphics_abstraction_layer.cpp @@ -189,7 +189,8 @@ void GAL::ComputeWorldScreenMatrix() MATRIX3x3D translation; translation.SetIdentity(); - translation.SetTranslation( 0.5 * VECTOR2D( m_screenSize ) ); + // We're deliberately dividing integers to avoid fractional pixel offsets. + translation.SetTranslation( VECTOR2D( m_screenSize.x/2, m_screenSize.y/2 ) ); MATRIX3x3D rotate; rotate.SetIdentity(); diff --git a/common/gal/opengl/gl_builtin_shaders.cpp b/common/gal/opengl/gl_builtin_shaders.cpp index ab0a57c2f3..7d074fda34 100644 --- a/common/gal/opengl/gl_builtin_shaders.cpp +++ b/common/gal/opengl/gl_builtin_shaders.cpp @@ -83,6 +83,7 @@ uniform float worldPixelSize; uniform vec2 screenPixelSize; uniform float pixelSizeMultiplier; uniform float minLinePixelWidth; +uniform vec2 antialiasingOffset; float roundr( float f, float r ) @@ -239,6 +240,7 @@ void main() } + gl_Position.xy += antialiasingOffset; } )SHADER_SOURCE"; diff --git a/common/gal/opengl/opengl_compositor.cpp b/common/gal/opengl/opengl_compositor.cpp index e7016f51cd..2b7110deaa 100644 --- a/common/gal/opengl/opengl_compositor.cpp +++ b/common/gal/opengl/opengl_compositor.cpp @@ -439,3 +439,13 @@ int OPENGL_COMPOSITOR::GetAntialiasSupersamplingFactor() const default: return 1; } } + +VECTOR2D OPENGL_COMPOSITOR::GetAntialiasRenderingOffset() const +{ + switch( m_currentAntialiasingMode ) + { + case OPENGL_ANTIALIASING_MODE::SUPERSAMPLING_X2: return VECTOR2D( 0.5, -0.5 ); + case OPENGL_ANTIALIASING_MODE::SUPERSAMPLING_X4: return VECTOR2D( 0.25, -0.25 ); + default: return VECTOR2D( 0, 0 ); + } +} diff --git a/common/gal/opengl/opengl_gal.cpp b/common/gal/opengl/opengl_gal.cpp index 95690a75d8..72d58beb33 100644 --- a/common/gal/opengl/opengl_gal.cpp +++ b/common/gal/opengl/opengl_gal.cpp @@ -281,6 +281,7 @@ OPENGL_GAL::OPENGL_GAL( GAL_DISPLAY_OPTIONS& aDisplayOptions, wxWindow* aParent, ufm_worldPixelSize = 1; ufm_screenPixelSize = 1; ufm_pixelSizeMultiplier = 1; + ufm_antialiasingOffset = 1; } @@ -528,6 +529,7 @@ void OPENGL_GAL::beginDrawing() ufm_worldPixelSize = m_shader->AddParameter( "worldPixelSize" ); ufm_screenPixelSize = m_shader->AddParameter( "screenPixelSize" ); ufm_pixelSizeMultiplier = m_shader->AddParameter( "pixelSizeMultiplier" ); + ufm_antialiasingOffset = m_shader->AddParameter( "antialiasingOffset" ); m_shader->Use(); m_shader->SetParameter( ufm_fontTexture, (int) FONT_TEXTURE_UNIT ); @@ -541,9 +543,14 @@ void OPENGL_GAL::beginDrawing() m_shader->Use(); m_shader->SetParameter( ufm_worldPixelSize, (float) ( getWorldPixelSize() / GetScaleFactor() ) ); - m_shader->SetParameter( ufm_screenPixelSize, getScreenPixelSize() ); + const VECTOR2D& screenPixelSize = getScreenPixelSize(); + m_shader->SetParameter( ufm_screenPixelSize, screenPixelSize ); double pixelSizeMultiplier = m_compositor->GetAntialiasSupersamplingFactor(); m_shader->SetParameter( ufm_pixelSizeMultiplier, (float) pixelSizeMultiplier ); + VECTOR2D renderingOffset = m_compositor->GetAntialiasRenderingOffset(); + renderingOffset.x *= screenPixelSize.x; + renderingOffset.y *= screenPixelSize.y; + m_shader->SetParameter( ufm_antialiasingOffset, renderingOffset ); m_shader->Deactivate(); // Something betreen BeginDrawing and EndDrawing seems to depend on @@ -2321,18 +2328,20 @@ void OPENGL_GAL::EnableDepthTest( bool aEnabled ) } -static double roundr( double f, double r ) +inline double round_to_half_pixel( double f, double r ) { - return floor( f / r + 0.5 ) * r; + return ( ceil( f / r ) - 0.5 ) * r; } - void OPENGL_GAL::ComputeWorldScreenMatrix() { + computeWorldScale(); auto pixelSize = m_worldScale; - m_lookAtPoint.x = roundr( m_lookAtPoint.x, pixelSize ); - m_lookAtPoint.y = roundr( m_lookAtPoint.y, pixelSize ); + // we need -m_lookAtPoint == -k * pixelSize + 0.5 * pixelSize for OpenGL + // meaning m_lookAtPoint = (k-0.5)*pixelSize with integer k + m_lookAtPoint.x = round_to_half_pixel( m_lookAtPoint.x, pixelSize ); + m_lookAtPoint.y = round_to_half_pixel( m_lookAtPoint.y, pixelSize ); GAL::ComputeWorldScreenMatrix(); } diff --git a/include/gal/opengl/opengl_compositor.h b/include/gal/opengl/opengl_compositor.h index 65685e70bd..ae295cedc2 100644 --- a/include/gal/opengl/opengl_compositor.h +++ b/include/gal/opengl/opengl_compositor.h @@ -94,6 +94,7 @@ public: OPENGL_ANTIALIASING_MODE GetAntialiasingMode() const; int GetAntialiasSupersamplingFactor() const; + VECTOR2D GetAntialiasRenderingOffset() const; protected: /// Binds a specific Framebuffer Object. diff --git a/include/gal/opengl/opengl_gal.h b/include/gal/opengl/opengl_gal.h index 4a8fd6bafd..93262a3f2b 100644 --- a/include/gal/opengl/opengl_gal.h +++ b/include/gal/opengl/opengl_gal.h @@ -336,6 +336,7 @@ private: GLint ufm_worldPixelSize; GLint ufm_screenPixelSize; GLint ufm_pixelSizeMultiplier; + GLint ufm_antialiasingOffset; wxCursor m_currentwxCursor; ///< wxCursor showing the current native cursor