From f693de869719ea3f1aef641162fab29aacdf5b4d Mon Sep 17 00:00:00 2001 From: Thomas Debesse Date: Sat, 7 Mar 2026 00:20:09 +0100 Subject: [PATCH 01/11] renderer: make r_FXAA a new-style cvar --- src/engine/renderer/tr_backend.cpp | 2 +- src/engine/renderer/tr_init.cpp | 9 +++++++-- src/engine/renderer/tr_local.h | 4 +++- src/engine/renderer/tr_shade.cpp | 2 +- 4 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/engine/renderer/tr_backend.cpp b/src/engine/renderer/tr_backend.cpp index f1921b96c6..b11b70cd35 100644 --- a/src/engine/renderer/tr_backend.cpp +++ b/src/engine/renderer/tr_backend.cpp @@ -1603,7 +1603,7 @@ void RB_RenderSSAO() void RB_FXAA() { - if ( !r_FXAA->integer || !gl_fxaaShader ) + if ( !r_FXAA.Get() || !gl_fxaaShader ) { return; } diff --git a/src/engine/renderer/tr_init.cpp b/src/engine/renderer/tr_init.cpp index 8d496d1b47..54dd78684c 100644 --- a/src/engine/renderer/tr_init.cpp +++ b/src/engine/renderer/tr_init.cpp @@ -285,8 +285,11 @@ Cvar::Cvar r_rendererAPI( "r_rendererAPI", "Renderer API: 0: OpenGL, 1: Vul Cvar::Cvar r_bloom( "r_bloom", "Use bloom", Cvar::ARCHIVE, false ); Cvar::Cvar r_bloomBlur( "r_bloomBlur", "Bloom strength", Cvar::NONE, 0.2 ); Cvar::Cvar r_bloomPasses( "r_bloomPasses", "Amount of bloom passes in each direction", Cvar::NONE, 2 ); - cvar_t *r_FXAA; + + Cvar::Cvar r_FXAA( "r_FXAA", "Fast approximate anti-aliasing", Cvar::NONE, false ); + Cvar::Range> r_msaa( "r_msaa", "Amount of MSAA samples. 0 to disable", Cvar::NONE, 0, 0, 64 ); + Cvar::Range> r_ssao( "r_ssao", "Screen space ambient occlusion: " "-1: show, 0: disabled, 1: enabled", @@ -1205,8 +1208,10 @@ ScreenshotCmd screenshotPNGRegistration("screenshotPNG", ssFormat_t::SSF_PNG, "p r_printShaders = Cvar_Get( "r_printShaders", "0", 0 ); Cvar::Latch( r_bloom ); - r_FXAA = Cvar_Get( "r_FXAA", "0", CVAR_LATCH | CVAR_ARCHIVE ); Cvar::Latch( r_ssao ); + + Cvar::Latch( r_FXAA ); + Cvar::Latch( r_msaa ); // temporary variables that can change at any time diff --git a/src/engine/renderer/tr_local.h b/src/engine/renderer/tr_local.h index 68328fde7d..9c2b0672a6 100644 --- a/src/engine/renderer/tr_local.h +++ b/src/engine/renderer/tr_local.h @@ -2779,8 +2779,10 @@ enum extern Cvar::Cvar r_bloom; extern Cvar::Cvar r_bloomBlur; extern Cvar::Cvar r_bloomPasses; - extern cvar_t *r_FXAA; extern Cvar::Range> r_ssao; + + extern Cvar::Cvar r_FXAA; + extern Cvar::Range> r_msaa; extern cvar_t *r_evsmPostProcess; diff --git a/src/engine/renderer/tr_shade.cpp b/src/engine/renderer/tr_shade.cpp index cb2044746d..98deddafba 100644 --- a/src/engine/renderer/tr_shade.cpp +++ b/src/engine/renderer/tr_shade.cpp @@ -369,7 +369,7 @@ static void GLSL_InitGPUShadersOrError() gl_ssaoShader->MarkProgramForBuilding(); } - if ( r_FXAA->integer != 0 ) + if ( r_FXAA.Get() ) { gl_shaderManager.LoadShader( gl_fxaaShader ); From 28d3cafddea27e77bf5903ef6460fd12738afdbe Mon Sep 17 00:00:00 2001 From: Thomas Debesse Date: Sat, 7 Mar 2026 00:30:19 +0100 Subject: [PATCH 02/11] glsl: move FXAA control knobs to fxaa_fp --- src/engine/renderer/glsl_source/fxaa3_11_fp.glsl | 14 -------------- src/engine/renderer/glsl_source/fxaa_fp.glsl | 13 ++++++++++--- 2 files changed, 10 insertions(+), 17 deletions(-) diff --git a/src/engine/renderer/glsl_source/fxaa3_11_fp.glsl b/src/engine/renderer/glsl_source/fxaa3_11_fp.glsl index 0619da2d4a..dd3757b08d 100644 --- a/src/engine/renderer/glsl_source/fxaa3_11_fp.glsl +++ b/src/engine/renderer/glsl_source/fxaa3_11_fp.glsl @@ -20,20 +20,6 @@ DAMAGES. kangz: This code has been set in the public domain by TIMOTHY LOTTES -============================================================================*/ - -//Due to our shader system, we put the defines for the control knobs here -#define FXAA_PC 1 -#if __VERSION__ == 120 -#define FXAA_GLSL_120 1 -#else -#define FXAA_GLSL_130 1 -#endif - -#define FXAA_QUALITY_PRESET 12 -#define FXAA_GREEN_AS_LUMA 1 - -/*============================================================================ ------------------------------------------------------------------------------ INTEGRATION CHECKLIST ------------------------------------------------------------------------------ diff --git a/src/engine/renderer/glsl_source/fxaa_fp.glsl b/src/engine/renderer/glsl_source/fxaa_fp.glsl index 873c90144c..a3fd19f06e 100644 --- a/src/engine/renderer/glsl_source/fxaa_fp.glsl +++ b/src/engine/renderer/glsl_source/fxaa_fp.glsl @@ -33,9 +33,16 @@ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT /* fxaa_fp.glsl */ -// The FXAA parameters are put directly in fxaa3_11_fp.glsl -// because we cannot #include in the middle of a shader -// ^This is no longer true, but I'm not touching that mess +// Control knobs. +#if __VERSION__ == 120 +#define FXAA_GLSL_120 1 +#else +#define FXAA_GLSL_130 1 +#endif + +#define FXAA_PC 1 +#define FXAA_QUALITY_PRESET 12 +#define FXAA_GREEN_AS_LUMA 1 #insert fxaa3_11_fp From f74f2ba206a28823796bf40449011a6b2efa059c Mon Sep 17 00:00:00 2001 From: Thomas Debesse Date: Sat, 7 Mar 2026 00:39:22 +0100 Subject: [PATCH 03/11] tr_backend: run FXAA after the camera shader (after tone mapping and color conversion) --- src/engine/renderer/tr_backend.cpp | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/src/engine/renderer/tr_backend.cpp b/src/engine/renderer/tr_backend.cpp index b11b70cd35..5c6340bb91 100644 --- a/src/engine/renderer/tr_backend.cpp +++ b/src/engine/renderer/tr_backend.cpp @@ -1621,12 +1621,12 @@ void RB_FXAA() // set the shader parameters gl_fxaaShader->BindProgram(); - // Swap main FBOs gl_fxaaShader->SetUniform_ColorMapBindless( GL_BindToTMU( 0, tr.currentRenderImage[backEnd.currentMainFBO] ) ); - backEnd.currentMainFBO = 1 - backEnd.currentMainFBO; - R_BindFBO( tr.mainFBO[ backEnd.currentMainFBO ] ); + + // This shader is run last, so let it render to screen. + R_BindNullFBO(); Tess_InstantScreenSpaceQuad(); @@ -1693,13 +1693,22 @@ void RB_CameraPostFX() { } gl_cameraEffectsShader->SetUniform_Tonemap( tonemap ); - // This shader is run last, so let it render to screen instead of - // tr.mainFBO - R_BindNullFBO(); gl_cameraEffectsShader->SetUniform_CurrentMapBindless( GL_BindToTMU( 0, tr.currentRenderImage[backEnd.currentMainFBO] ) ); + if ( r_FXAA.Get() && gl_fxaaShader ) + { + // Swap main FBOs. + backEnd.currentMainFBO = 1 - backEnd.currentMainFBO; + R_BindFBO( tr.mainFBO[ backEnd.currentMainFBO ] ); + } + else + { + // Without FXAA this shader is run last, so let it render to screen. + R_BindNullFBO(); + } + if ( glConfig.colorGrading ) { gl_cameraEffectsShader->SetUniform_ColorMap3DBindless( GL_BindToTMU( 3, tr.colorGradeImage ) ); } @@ -2815,11 +2824,11 @@ static void RB_RenderPostProcess() TransitionMSAAToMain( GL_COLOR_BUFFER_BIT ); - RB_FXAA(); - // render chromatic aberration RB_CameraPostFX(); + RB_FXAA(); + // copy to given byte buffer that is NOT a FBO if ( tr.refdef.pixelTarget != nullptr ) { glReadPixels( 0, 0, tr.refdef.pixelTargetWidth, tr.refdef.pixelTargetHeight, GL_RGBA, From f9430e151d4aae10ee1c18de24d209277b66562b Mon Sep 17 00:00:00 2001 From: Thomas Debesse Date: Sat, 7 Mar 2026 01:31:08 +0100 Subject: [PATCH 04/11] renderer: implement luma-based FXAA --- src/engine/renderer/gl_shader.cpp | 10 ++++++++++ .../renderer/glsl_source/cameraEffects_fp.glsl | 18 ++++++++++++++++++ src/engine/renderer/glsl_source/fxaa_fp.glsl | 6 ++++-- src/engine/renderer/tr_init.cpp | 4 ++++ src/engine/renderer/tr_local.h | 2 ++ 5 files changed, 38 insertions(+), 2 deletions(-) diff --git a/src/engine/renderer/gl_shader.cpp b/src/engine/renderer/gl_shader.cpp index 6274735e58..ddb4fc7074 100644 --- a/src/engine/renderer/gl_shader.cpp +++ b/src/engine/renderer/gl_shader.cpp @@ -797,6 +797,16 @@ static std::string GenEngineConstants() { AddDefine( str, "r_colorGrading", 1 ); } + if ( r_showLuma.Get() ) + { + AddDefine( str, "r_showLuma", 1 ); + } + + if ( r_FXAA.Get() ) + { + AddDefine( str, "r_FXAA", 1 ); + } + if ( r_highPrecisionRendering.Get() ) { AddDefine( str, "r_highPrecisionRendering", 1 ); } diff --git a/src/engine/renderer/glsl_source/cameraEffects_fp.glsl b/src/engine/renderer/glsl_source/cameraEffects_fp.glsl index 8b243fdb44..0c20768162 100644 --- a/src/engine/renderer/glsl_source/cameraEffects_fp.glsl +++ b/src/engine/renderer/glsl_source/cameraEffects_fp.glsl @@ -111,5 +111,23 @@ void main() color.xyz = pow(color.xyz, vec3(u_InverseGamma)); + #if defined(r_FXAA) || defined(r_showLuma) + { + // That luma vector comes from a comment in fxaa3_11_fp.glsl. + vec3 lumaVector = vec3( 0.299, 0.587, 0.114 ); + + float luma = dot( color.rgb, lumaVector ); + + #if defined(r_showLuma) + color.rgb = vec3( luma ); + #endif + + #if defined(r_FXAA) + // Encode luma in alpha channel. + color.a = luma; + #endif + } + #endif + outputColor = color; } diff --git a/src/engine/renderer/glsl_source/fxaa_fp.glsl b/src/engine/renderer/glsl_source/fxaa_fp.glsl index a3fd19f06e..bd1df7b334 100644 --- a/src/engine/renderer/glsl_source/fxaa_fp.glsl +++ b/src/engine/renderer/glsl_source/fxaa_fp.glsl @@ -42,7 +42,7 @@ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT #define FXAA_PC 1 #define FXAA_QUALITY_PRESET 12 -#define FXAA_GREEN_AS_LUMA 1 +#define FXAA_GREEN_AS_LUMA 0 #insert fxaa3_11_fp @@ -56,7 +56,7 @@ out vec4 outputColor; void main() { - outputColor = FxaaPixelShader( + vec4 color = FxaaPixelShader( gl_FragCoord.xy / r_FBufSize, //pos vec4(0.0), //not used u_ColorMap, //tex @@ -74,4 +74,6 @@ void main() 0.0, //not used vec4(0.0) //not used ); + + outputColor = vec4( color.rgb, 1.0f ); } diff --git a/src/engine/renderer/tr_init.cpp b/src/engine/renderer/tr_init.cpp index 54dd78684c..15da7c64d2 100644 --- a/src/engine/renderer/tr_init.cpp +++ b/src/engine/renderer/tr_init.cpp @@ -286,6 +286,8 @@ Cvar::Cvar r_rendererAPI( "r_rendererAPI", "Renderer API: 0: OpenGL, 1: Vul Cvar::Cvar r_bloomBlur( "r_bloomBlur", "Bloom strength", Cvar::NONE, 0.2 ); Cvar::Cvar r_bloomPasses( "r_bloomPasses", "Amount of bloom passes in each direction", Cvar::NONE, 2 ); + Cvar::Cvar r_showLuma( "r_showLuma", "Show luminance", Cvar::CHEAT, false ); + Cvar::Cvar r_FXAA( "r_FXAA", "Fast approximate anti-aliasing", Cvar::NONE, false ); Cvar::Range> r_msaa( "r_msaa", "Amount of MSAA samples. 0 to disable", Cvar::NONE, 0, 0, 64 ); @@ -1210,6 +1212,8 @@ ScreenshotCmd screenshotPNGRegistration("screenshotPNG", ssFormat_t::SSF_PNG, "p Cvar::Latch( r_bloom ); Cvar::Latch( r_ssao ); + Cvar::Latch( r_showLuma ); + Cvar::Latch( r_FXAA ); Cvar::Latch( r_msaa ); diff --git a/src/engine/renderer/tr_local.h b/src/engine/renderer/tr_local.h index 9c2b0672a6..64795c3aaf 100644 --- a/src/engine/renderer/tr_local.h +++ b/src/engine/renderer/tr_local.h @@ -2781,6 +2781,8 @@ enum extern Cvar::Cvar r_bloomPasses; extern Cvar::Range> r_ssao; + extern Cvar::Cvar r_showLuma; + extern Cvar::Cvar r_FXAA; extern Cvar::Range> r_msaa; From 03fae56005cd30b44f0f729706a79052ed785160 Mon Sep 17 00:00:00 2001 From: Thomas Debesse Date: Sat, 7 Mar 2026 01:55:32 +0100 Subject: [PATCH 05/11] renderer: add r_showFXAA --- src/engine/renderer/gl_shader.cpp | 5 +++++ src/engine/renderer/glsl_source/fxaa_fp.glsl | 13 +++++++++++++ src/engine/renderer/tr_init.cpp | 2 ++ src/engine/renderer/tr_local.h | 1 + 4 files changed, 21 insertions(+) diff --git a/src/engine/renderer/gl_shader.cpp b/src/engine/renderer/gl_shader.cpp index ddb4fc7074..67f22819ba 100644 --- a/src/engine/renderer/gl_shader.cpp +++ b/src/engine/renderer/gl_shader.cpp @@ -805,6 +805,11 @@ static std::string GenEngineConstants() { if ( r_FXAA.Get() ) { AddDefine( str, "r_FXAA", 1 ); + + if ( r_showFXAA.Get() ) + { + AddDefine( str, "r_showFXAA", 1 ); + } } if ( r_highPrecisionRendering.Get() ) { diff --git a/src/engine/renderer/glsl_source/fxaa_fp.glsl b/src/engine/renderer/glsl_source/fxaa_fp.glsl index bd1df7b334..885d501982 100644 --- a/src/engine/renderer/glsl_source/fxaa_fp.glsl +++ b/src/engine/renderer/glsl_source/fxaa_fp.glsl @@ -75,5 +75,18 @@ void main() vec4(0.0) //not used ); + #if defined(r_showFXAA) + { + vec4 originalColor = FxaaTexTop( u_ColorMap, gl_FragCoord.xy / r_FBufSize ); + + if ( color.r != originalColor.r + || color.g != originalColor.g + || color.b != originalColor.b ) + { + color.rgb = vec3(1.0, 0.0, 0.0); + } + } + #endif + outputColor = vec4( color.rgb, 1.0f ); } diff --git a/src/engine/renderer/tr_init.cpp b/src/engine/renderer/tr_init.cpp index 15da7c64d2..bf82244d7a 100644 --- a/src/engine/renderer/tr_init.cpp +++ b/src/engine/renderer/tr_init.cpp @@ -289,6 +289,7 @@ Cvar::Cvar r_rendererAPI( "r_rendererAPI", "Renderer API: 0: OpenGL, 1: Vul Cvar::Cvar r_showLuma( "r_showLuma", "Show luminance", Cvar::CHEAT, false ); Cvar::Cvar r_FXAA( "r_FXAA", "Fast approximate anti-aliasing", Cvar::NONE, false ); + Cvar::Cvar r_showFXAA( "r_showFXAA", "Show pixels modified by FXAA", Cvar::CHEAT, false ); Cvar::Range> r_msaa( "r_msaa", "Amount of MSAA samples. 0 to disable", Cvar::NONE, 0, 0, 64 ); @@ -1215,6 +1216,7 @@ ScreenshotCmd screenshotPNGRegistration("screenshotPNG", ssFormat_t::SSF_PNG, "p Cvar::Latch( r_showLuma ); Cvar::Latch( r_FXAA ); + Cvar::Latch( r_showFXAA ); Cvar::Latch( r_msaa ); diff --git a/src/engine/renderer/tr_local.h b/src/engine/renderer/tr_local.h index 64795c3aaf..dbee5bfc1d 100644 --- a/src/engine/renderer/tr_local.h +++ b/src/engine/renderer/tr_local.h @@ -2784,6 +2784,7 @@ enum extern Cvar::Cvar r_showLuma; extern Cvar::Cvar r_FXAA; + extern Cvar::Cvar r_showFXAA; extern Cvar::Range> r_msaa; From e5ac8852a391527be8fed2458fb056ab05e9ee21 Mon Sep 17 00:00:00 2001 From: Thomas Debesse Date: Sat, 7 Mar 2026 16:10:16 +0100 Subject: [PATCH 06/11] tr_backend: fix FXAA sampling by using GL_LINEAR on currentRender - fix FXAA by using GL_LINEAR on currentRender, - restore GL_NEAREST after that to not break other effects. --- src/engine/renderer/GLUtils.h | 1 + src/engine/renderer/glsl_source/fxaa_fp.glsl | 5 +++ src/engine/renderer/tr_backend.cpp | 41 +++++++++++++++++++- src/engine/renderer/tr_local.h | 2 + src/engine/renderer/tr_shade.cpp | 11 ++++++ src/engine/sys/sdl_glimp.cpp | 6 +++ 6 files changed, 64 insertions(+), 2 deletions(-) diff --git a/src/engine/renderer/GLUtils.h b/src/engine/renderer/GLUtils.h index e7a3a635ed..4101d54a75 100644 --- a/src/engine/renderer/GLUtils.h +++ b/src/engine/renderer/GLUtils.h @@ -140,6 +140,7 @@ struct GLConfig bool bufferStorageAvailable; bool uniformBufferObjectAvailable; bool mapBufferRangeAvailable; + bool samplerObjectsAvailable; bool syncAvailable; bool textureBarrierAvailable; bool halfFloatVertexAvailable; diff --git a/src/engine/renderer/glsl_source/fxaa_fp.glsl b/src/engine/renderer/glsl_source/fxaa_fp.glsl index 885d501982..22b202b709 100644 --- a/src/engine/renderer/glsl_source/fxaa_fp.glsl +++ b/src/engine/renderer/glsl_source/fxaa_fp.glsl @@ -46,7 +46,12 @@ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT #insert fxaa3_11_fp +#if defined(HAVE_ARB_bindless_texture) +uniform sampler2D u_ColorMap_linear; +#define u_ColorMap u_ColorMap_linear +#else uniform sampler2D u_ColorMap; +#endif #if __VERSION__ > 120 out vec4 outputColor; diff --git a/src/engine/renderer/tr_backend.cpp b/src/engine/renderer/tr_backend.cpp index 5c6340bb91..f739beab37 100644 --- a/src/engine/renderer/tr_backend.cpp +++ b/src/engine/renderer/tr_backend.cpp @@ -1603,7 +1603,7 @@ void RB_RenderSSAO() void RB_FXAA() { - if ( !r_FXAA.Get() || !gl_fxaaShader ) + if ( !r_FXAA.Get() || !gl_fxaaShader || !glConfig.samplerObjectsAvailable ) { return; } @@ -1625,11 +1625,42 @@ void RB_FXAA() GL_BindToTMU( 0, tr.currentRenderImage[backEnd.currentMainFBO] ) ); + // FXAA expects GL_LINEAR for the sampling to work. + GLuint64 handle = 0; + + if ( glConfig.usingBindlessTextures ) + { + // Set a handler. + GLuint texture = tr.currentRenderImage[backEnd.currentMainFBO]->texnum; + handle = glGetTextureSamplerHandleARB( texture, tr.linearSampler ); + glMakeTextureHandleResidentARB( handle ); + GLuint program = gl_fxaaShader->GetProgram()->id; + GLint location = glGetUniformLocation( program, "u_ColorMap_linear" ); + glUniformHandleui64ARB( location, handle ); + } + else + { + // Bind a sampler. + glBindSampler( 0, tr.linearSampler ); + } + // This shader is run last, so let it render to screen. R_BindNullFBO(); Tess_InstantScreenSpaceQuad(); + // Make sure we didn't break other effects expecting GL_NEAREST. + if ( glConfig.usingBindlessTextures ) + { + // Unset the handler. + glMakeTextureHandleNonResidentARB( handle ); + } + else + { + // Unbind the sampler. + glBindSampler( 0, 0 ); + } + GL_CheckErrors(); } @@ -1697,7 +1728,7 @@ void RB_CameraPostFX() { GL_BindToTMU( 0, tr.currentRenderImage[backEnd.currentMainFBO] ) ); - if ( r_FXAA.Get() && gl_fxaaShader ) + if ( r_FXAA.Get() && gl_fxaaShader && glConfig.samplerObjectsAvailable ) { // Swap main FBOs. backEnd.currentMainFBO = 1 - backEnd.currentMainFBO; @@ -3848,6 +3879,12 @@ void R_ShutdownBackend() glDisableVertexAttribArray( i ); } glState.vertexAttribsState = 0; + + if ( tr.linearSampler ) + { + glDeleteSamplers( 1, &tr.linearSampler ); + tr.linearSampler = 0; + } } const RenderCommand *EndOfListCommand::ExecuteSelf( ) const diff --git a/src/engine/renderer/tr_local.h b/src/engine/renderer/tr_local.h index dbee5bfc1d..441eb292ad 100644 --- a/src/engine/renderer/tr_local.h +++ b/src/engine/renderer/tr_local.h @@ -2595,6 +2595,8 @@ enum float inverseSawToothTable[ FUNCTABLE_SIZE ]; scissorState_t scissor; + + GLuint linearSampler; }; extern const matrix_t quakeToOpenGLMatrix; diff --git a/src/engine/renderer/tr_shade.cpp b/src/engine/renderer/tr_shade.cpp index 98deddafba..6cd3ec2c18 100644 --- a/src/engine/renderer/tr_shade.cpp +++ b/src/engine/renderer/tr_shade.cpp @@ -222,6 +222,8 @@ static void GLSL_InitGPUShadersOrError() GL_CheckErrors(); + bool requireLinearSampler = false; + gl_shaderManager.InitDriverInfo(); /* It must be done before GenerateBuiltinHeaders() because glConfig.realtimeLighting @@ -374,6 +376,15 @@ static void GLSL_InitGPUShadersOrError() gl_shaderManager.LoadShader( gl_fxaaShader ); gl_fxaaShader->MarkProgramForBuilding(); + + requireLinearSampler = true; + } + + if ( requireLinearSampler && !tr.linearSampler ) + { + glGenSamplers( 1, &tr.linearSampler ); + glSamplerParameteri( tr.linearSampler, GL_TEXTURE_MAG_FILTER, GL_LINEAR) ; + glSamplerParameteri( tr.linearSampler, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); } gl_shaderManager.PostProcessGlobalUniforms(); diff --git a/src/engine/sys/sdl_glimp.cpp b/src/engine/sys/sdl_glimp.cpp index 28adcf324b..976ca20b2e 100644 --- a/src/engine/sys/sdl_glimp.cpp +++ b/src/engine/sys/sdl_glimp.cpp @@ -90,6 +90,8 @@ static Cvar::Cvar r_arb_multi_draw_indirect( "r_arb_multi_draw_indirect", "Use GL_ARB_multi_draw_indirect if available", Cvar::NONE, true ); static Cvar::Cvar r_arb_program_interface_query( "r_arb_program_interface_query", "Load GL_ARB_program_interface_query if available", Cvar::NONE, true ); +static Cvar::Cvar r_arb_sampler_objects( "r_arb_sampler_objects", + "Use GL_ARB_sampler_objects if available", Cvar::NONE, true ); static Cvar::Cvar r_arb_shader_draw_parameters( "r_arb_shader_draw_parameters", "Use GL_ARB_shader_draw_parameters if available", Cvar::NONE, true ); static Cvar::Cvar r_arb_shader_atomic_counters( "r_arb_shader_atomic_counters", @@ -2018,6 +2020,7 @@ static void GLimp_InitExtensions() Cvar::Latch( r_arb_internalformat_query2 ); Cvar::Latch( r_arb_map_buffer_range ); Cvar::Latch( r_arb_multi_draw_indirect ); + Cvar::Latch( r_arb_sampler_objects ); Cvar::Latch( r_arb_shader_atomic_counters ); Cvar::Latch( r_arb_shader_atomic_counter_ops ); Cvar::Latch( r_arb_shader_draw_parameters ); @@ -2374,6 +2377,9 @@ static void GLimp_InitExtensions() // made required in OpenGL 3.0 glConfig.mapBufferRangeAvailable = LOAD_EXTENSION_WITH_TEST( ExtFlag_CORE, ARB_map_buffer_range, r_arb_map_buffer_range.Get() ); + // made required in OpenGL 3.3 + glConfig.samplerObjectsAvailable = LOAD_EXTENSION_WITH_TEST( ExtFlag_NONE, ARB_sampler_objects, r_arb_sampler_objects.Get() ); + // made required in OpenGL 3.2 glConfig.syncAvailable = LOAD_EXTENSION_WITH_TEST( ExtFlag_CORE, ARB_sync, r_arb_sync.Get() ); From 2e7885b7193238a61b190476a87aba65ad0cd750 Mon Sep 17 00:00:00 2001 From: Thomas Debesse Date: Sun, 8 Mar 2026 18:38:54 +0100 Subject: [PATCH 07/11] renderer: rename r_msaa as r_MSAA --- src/engine/renderer/tr_init.cpp | 4 ++-- src/engine/renderer/tr_local.h | 2 +- src/engine/renderer/tr_shade.cpp | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/engine/renderer/tr_init.cpp b/src/engine/renderer/tr_init.cpp index bf82244d7a..1337ef7c94 100644 --- a/src/engine/renderer/tr_init.cpp +++ b/src/engine/renderer/tr_init.cpp @@ -291,7 +291,7 @@ Cvar::Cvar r_rendererAPI( "r_rendererAPI", "Renderer API: 0: OpenGL, 1: Vul Cvar::Cvar r_FXAA( "r_FXAA", "Fast approximate anti-aliasing", Cvar::NONE, false ); Cvar::Cvar r_showFXAA( "r_showFXAA", "Show pixels modified by FXAA", Cvar::CHEAT, false ); - Cvar::Range> r_msaa( "r_msaa", "Amount of MSAA samples. 0 to disable", Cvar::NONE, 0, 0, 64 ); + Cvar::Range> r_MSAA( "r_MSAA", "Amount of MSAA samples. 0 to disable", Cvar::NONE, 0, 0, 64 ); Cvar::Range> r_ssao( "r_ssao", "Screen space ambient occlusion: " @@ -1218,7 +1218,7 @@ ScreenshotCmd screenshotPNGRegistration("screenshotPNG", ssFormat_t::SSF_PNG, "p Cvar::Latch( r_FXAA ); Cvar::Latch( r_showFXAA ); - Cvar::Latch( r_msaa ); + Cvar::Latch( r_MSAA ); // temporary variables that can change at any time r_showImages = Cvar_Get( "r_showImages", "0", CVAR_TEMP ); diff --git a/src/engine/renderer/tr_local.h b/src/engine/renderer/tr_local.h index 441eb292ad..5ed706e260 100644 --- a/src/engine/renderer/tr_local.h +++ b/src/engine/renderer/tr_local.h @@ -2788,7 +2788,7 @@ enum extern Cvar::Cvar r_FXAA; extern Cvar::Cvar r_showFXAA; - extern Cvar::Range> r_msaa; + extern Cvar::Range> r_MSAA; extern cvar_t *r_evsmPostProcess; diff --git a/src/engine/renderer/tr_shade.cpp b/src/engine/renderer/tr_shade.cpp index 6cd3ec2c18..e66a28333e 100644 --- a/src/engine/renderer/tr_shade.cpp +++ b/src/engine/renderer/tr_shade.cpp @@ -181,14 +181,14 @@ static void EnableAvailableFeatures() } if ( std::make_pair( glConfig.glMajor, glConfig.glMinor ) >= std::make_pair( 3, 2 ) ) { - glConfig.MSAA = r_msaa.Get(); + glConfig.MSAA = r_MSAA.Get(); const int maxSamples = std::min( glConfig.maxColorTextureSamples, glConfig.maxDepthTextureSamples ); if ( glConfig.MSAA > maxSamples ) { - Log::Warn( "MSAA samples %i > %i, setting to %i", r_msaa.Get(), maxSamples, maxSamples ); + Log::Warn( "MSAA samples %i > %i, setting to %i", r_MSAA.Get(), maxSamples, maxSamples ); glConfig.MSAA = maxSamples; } - } else if ( r_msaa.Get() ) { + } else if ( r_MSAA.Get() ) { Log::Warn( "MSAA unavailable because GL version is lower than required (%i.%i < %i.%i)", glConfig.glMajor, glConfig.glMinor, 3, 2 ); } From ba7da64bdbab01b9497052ac5c11bcaf8d920f6e Mon Sep 17 00:00:00 2001 From: Thomas Debesse Date: Sun, 8 Mar 2026 18:48:42 +0100 Subject: [PATCH 08/11] renderer: disable FXAA when MSAA is enabled (prefer MSAA) --- src/engine/renderer/GLUtils.h | 1 + src/engine/renderer/gl_shader.cpp | 2 +- src/engine/renderer/tr_backend.cpp | 4 ++-- src/engine/renderer/tr_shade.cpp | 16 +++++++++++++++- 4 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/engine/renderer/GLUtils.h b/src/engine/renderer/GLUtils.h index 4101d54a75..df61d1df7d 100644 --- a/src/engine/renderer/GLUtils.h +++ b/src/engine/renderer/GLUtils.h @@ -156,6 +156,7 @@ struct GLConfig bool reflectionMappingAvailable; bool reflectionMapping; bool bloom; + bool FXAA; // automatically disabled when MSAA is not null int MSAA; // 0 == disabled, otherwise used as sample count bool ssao; bool motionBlur; diff --git a/src/engine/renderer/gl_shader.cpp b/src/engine/renderer/gl_shader.cpp index 67f22819ba..2f6724c45e 100644 --- a/src/engine/renderer/gl_shader.cpp +++ b/src/engine/renderer/gl_shader.cpp @@ -802,7 +802,7 @@ static std::string GenEngineConstants() { AddDefine( str, "r_showLuma", 1 ); } - if ( r_FXAA.Get() ) + if ( glConfig.FXAA ) { AddDefine( str, "r_FXAA", 1 ); diff --git a/src/engine/renderer/tr_backend.cpp b/src/engine/renderer/tr_backend.cpp index f739beab37..72c4bfe7aa 100644 --- a/src/engine/renderer/tr_backend.cpp +++ b/src/engine/renderer/tr_backend.cpp @@ -1603,7 +1603,7 @@ void RB_RenderSSAO() void RB_FXAA() { - if ( !r_FXAA.Get() || !gl_fxaaShader || !glConfig.samplerObjectsAvailable ) + if ( !glConfig.FXAA || !gl_fxaaShader ) { return; } @@ -1728,7 +1728,7 @@ void RB_CameraPostFX() { GL_BindToTMU( 0, tr.currentRenderImage[backEnd.currentMainFBO] ) ); - if ( r_FXAA.Get() && gl_fxaaShader && glConfig.samplerObjectsAvailable ) + if ( r_FXAA.Get() && gl_fxaaShader ) { // Swap main FBOs. backEnd.currentMainFBO = 1 - backEnd.currentMainFBO; diff --git a/src/engine/renderer/tr_shade.cpp b/src/engine/renderer/tr_shade.cpp index e66a28333e..53af3cff26 100644 --- a/src/engine/renderer/tr_shade.cpp +++ b/src/engine/renderer/tr_shade.cpp @@ -192,6 +192,20 @@ static void EnableAvailableFeatures() Log::Warn( "MSAA unavailable because GL version is lower than required (%i.%i < %i.%i)", glConfig.glMajor, glConfig.glMinor, 3, 2 ); } + glConfig.FXAA = r_FXAA.Get(); + + if ( glConfig.FXAA && glConfig.MSAA ) + { + Log::Notice( "FXAA disabled because MSAA is enabled." ); + glConfig.FXAA = false; + } + + if ( glConfig.FXAA && !glConfig.samplerObjectsAvailable ) + { + Log::Warn( "FXAA disabled because ARB_sampler_objects is not available." ); + glConfig.FXAA = false; + } + glConfig.usingMaterialSystem = r_materialSystem.Get() && glConfig.materialSystemAvailable; glConfig.usingBindlessTextures = glConfig.usingMaterialSystem || ( r_preferBindlessTextures.Get() && glConfig.bindlessTexturesAvailable ); @@ -371,7 +385,7 @@ static void GLSL_InitGPUShadersOrError() gl_ssaoShader->MarkProgramForBuilding(); } - if ( r_FXAA.Get() ) + if ( glConfig.FXAA ) { gl_shaderManager.LoadShader( gl_fxaaShader ); From 901e9ee7c2f239ac940ba2979e37e19dd157a48a Mon Sep 17 00:00:00 2001 From: Thomas Debesse Date: Sun, 8 Mar 2026 19:28:39 +0100 Subject: [PATCH 09/11] renderer: make FXAA configurable with cvars --- src/engine/renderer/gl_shader.cpp | 4 ++++ src/engine/renderer/glsl_source/fxaa_fp.glsl | 6 +++--- src/engine/renderer/tr_init.cpp | 9 +++++++++ src/engine/renderer/tr_local.h | 3 +++ 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/engine/renderer/gl_shader.cpp b/src/engine/renderer/gl_shader.cpp index 2f6724c45e..64b942fae8 100644 --- a/src/engine/renderer/gl_shader.cpp +++ b/src/engine/renderer/gl_shader.cpp @@ -806,6 +806,10 @@ static std::string GenEngineConstants() { { AddDefine( str, "r_FXAA", 1 ); + AddDefine( str, "r_FXAASubPix", r_FXAASubPix.Get() ); + AddDefine( str, "r_FXAAEdgeThreshold", r_FXAAEdgeThreshold.Get() ); + AddDefine( str, "r_FXAAEdgeThresholdMin", r_FXAAEdgeThresholdMin.Get() ); + if ( r_showFXAA.Get() ) { AddDefine( str, "r_showFXAA", 1 ); diff --git a/src/engine/renderer/glsl_source/fxaa_fp.glsl b/src/engine/renderer/glsl_source/fxaa_fp.glsl index 22b202b709..380093c46f 100644 --- a/src/engine/renderer/glsl_source/fxaa_fp.glsl +++ b/src/engine/renderer/glsl_source/fxaa_fp.glsl @@ -71,9 +71,9 @@ void main() vec4(0.0), //not used vec4(0.0), //not used vec4(0.0), //not used - 0.75, //fxaaQualitySubpix - 0.166, //fxaaQualityEdgeThreshold - 0.0625, //fxaaQualityEdgeThresholdMin + r_FXAASubPix, //fxaaQualitySubpix + r_FXAAEdgeThreshold, //fxaaQualityEdgeThreshold + r_FXAAEdgeThresholdMin, //fxaaQualityEdgeThresholdMin 0.0, //not used 0.0, //not used 0.0, //not used diff --git a/src/engine/renderer/tr_init.cpp b/src/engine/renderer/tr_init.cpp index 1337ef7c94..ce509dde4c 100644 --- a/src/engine/renderer/tr_init.cpp +++ b/src/engine/renderer/tr_init.cpp @@ -289,6 +289,12 @@ Cvar::Cvar r_rendererAPI( "r_rendererAPI", "Renderer API: 0: OpenGL, 1: Vul Cvar::Cvar r_showLuma( "r_showLuma", "Show luminance", Cvar::CHEAT, false ); Cvar::Cvar r_FXAA( "r_FXAA", "Fast approximate anti-aliasing", Cvar::NONE, false ); + + // Values taken from comments in fxaa3_11_fp.glsl. + Cvar::Range> r_FXAASubPix( "r_FXAASubPix", "0: off, 0.25: almost off, 0.50: sharper, 0.75, standard, 1: softer", Cvar::NONE, 0.75f, 0.0f, 1.0f ); + Cvar::Range> r_FXAAEdgeThreshold( "r_FXAAEdgeThreshold", "0.063: overkill and slower, 0.125: high quality, 0.166: standard, 0.250: low quality, 0.333 too little and faster", Cvar::NONE, 0.166f, 0.063f, 0.333f ); + Cvar::Range> r_FXAAEdgeThresholdMin( "r_FXAAEdgeThresholdMin", "0.0312: visible limit, 0.0625: high quality, 0.0833: upper limit", Cvar::NONE, 0.0625f, 0.0312f, 0.0833f ); + Cvar::Cvar r_showFXAA( "r_showFXAA", "Show pixels modified by FXAA", Cvar::CHEAT, false ); Cvar::Range> r_MSAA( "r_MSAA", "Amount of MSAA samples. 0 to disable", Cvar::NONE, 0, 0, 64 ); @@ -1216,6 +1222,9 @@ ScreenshotCmd screenshotPNGRegistration("screenshotPNG", ssFormat_t::SSF_PNG, "p Cvar::Latch( r_showLuma ); Cvar::Latch( r_FXAA ); + Cvar::Latch( r_FXAASubPix ); + Cvar::Latch( r_FXAAEdgeThreshold ); + Cvar::Latch( r_FXAAEdgeThresholdMin ); Cvar::Latch( r_showFXAA ); Cvar::Latch( r_MSAA ); diff --git a/src/engine/renderer/tr_local.h b/src/engine/renderer/tr_local.h index 5ed706e260..51e59cb080 100644 --- a/src/engine/renderer/tr_local.h +++ b/src/engine/renderer/tr_local.h @@ -2786,6 +2786,9 @@ enum extern Cvar::Cvar r_showLuma; extern Cvar::Cvar r_FXAA; + extern Cvar::Range> r_FXAASubPix; + extern Cvar::Range> r_FXAAEdgeThreshold; + extern Cvar::Range> r_FXAAEdgeThresholdMin; extern Cvar::Cvar r_showFXAA; extern Cvar::Range> r_MSAA; From aab6ca8bd7d0c37c7e9662ce1869e3b0b2a64056 Mon Sep 17 00:00:00 2001 From: Thomas Debesse Date: Sun, 8 Mar 2026 20:00:28 +0100 Subject: [PATCH 10/11] tr_init: reduce r_FXAAEdgeThreshold to 0.250 --- src/engine/renderer/tr_init.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/renderer/tr_init.cpp b/src/engine/renderer/tr_init.cpp index ce509dde4c..87d24987ce 100644 --- a/src/engine/renderer/tr_init.cpp +++ b/src/engine/renderer/tr_init.cpp @@ -292,7 +292,7 @@ Cvar::Cvar r_rendererAPI( "r_rendererAPI", "Renderer API: 0: OpenGL, 1: Vul // Values taken from comments in fxaa3_11_fp.glsl. Cvar::Range> r_FXAASubPix( "r_FXAASubPix", "0: off, 0.25: almost off, 0.50: sharper, 0.75, standard, 1: softer", Cvar::NONE, 0.75f, 0.0f, 1.0f ); - Cvar::Range> r_FXAAEdgeThreshold( "r_FXAAEdgeThreshold", "0.063: overkill and slower, 0.125: high quality, 0.166: standard, 0.250: low quality, 0.333 too little and faster", Cvar::NONE, 0.166f, 0.063f, 0.333f ); + Cvar::Range> r_FXAAEdgeThreshold( "r_FXAAEdgeThreshold", "0.063: overkill and slower, 0.125: high quality, 0.166: standard, 0.250: low quality, 0.333 too little and faster", Cvar::NONE, 0.250f, 0.063f, 0.333f ); Cvar::Range> r_FXAAEdgeThresholdMin( "r_FXAAEdgeThresholdMin", "0.0312: visible limit, 0.0625: high quality, 0.0833: upper limit", Cvar::NONE, 0.0625f, 0.0312f, 0.0833f ); Cvar::Cvar r_showFXAA( "r_showFXAA", "Show pixels modified by FXAA", Cvar::CHEAT, false ); From 929f590ee3eb9cea9f3c1d71dca0741e3db4cf01 Mon Sep 17 00:00:00 2001 From: Thomas Debesse Date: Sun, 8 Mar 2026 20:25:27 +0100 Subject: [PATCH 11/11] renderer: rename r_ssao as r_SSAO --- src/engine/renderer/GLUtils.h | 2 +- src/engine/renderer/tr_backend.cpp | 4 ++-- src/engine/renderer/tr_init.cpp | 4 ++-- src/engine/renderer/tr_local.h | 2 +- src/engine/renderer/tr_shade.cpp | 6 +++--- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/engine/renderer/GLUtils.h b/src/engine/renderer/GLUtils.h index df61d1df7d..7c5645a99b 100644 --- a/src/engine/renderer/GLUtils.h +++ b/src/engine/renderer/GLUtils.h @@ -158,7 +158,7 @@ struct GLConfig bool bloom; bool FXAA; // automatically disabled when MSAA is not null int MSAA; // 0 == disabled, otherwise used as sample count - bool ssao; + bool SSAO; bool motionBlur; }; diff --git a/src/engine/renderer/tr_backend.cpp b/src/engine/renderer/tr_backend.cpp index 72c4bfe7aa..92a7381251 100644 --- a/src/engine/renderer/tr_backend.cpp +++ b/src/engine/renderer/tr_backend.cpp @@ -1552,7 +1552,7 @@ void RB_RenderMotionBlur() void RB_RenderSSAO() { - if ( !glConfig.ssao ) + if ( !glConfig.SSAO ) { return; } @@ -1570,7 +1570,7 @@ void RB_RenderSSAO() GL_State( GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO ); GL_Cull( cullType_t::CT_TWO_SIDED ); - if ( glConfig.ssao && r_ssao.Get() == Util::ordinal( ssaoMode::SHOW ) ) { + if ( glConfig.SSAO && r_SSAO.Get() == Util::ordinal( ssaoMode::SHOW ) ) { // clear the screen to show only SSAO GL_ClearColor( 1.0, 1.0, 1.0, 1.0 ); glClear( GL_COLOR_BUFFER_BIT ); diff --git a/src/engine/renderer/tr_init.cpp b/src/engine/renderer/tr_init.cpp index 87d24987ce..321253dbc5 100644 --- a/src/engine/renderer/tr_init.cpp +++ b/src/engine/renderer/tr_init.cpp @@ -299,7 +299,7 @@ Cvar::Cvar r_rendererAPI( "r_rendererAPI", "Renderer API: 0: OpenGL, 1: Vul Cvar::Range> r_MSAA( "r_MSAA", "Amount of MSAA samples. 0 to disable", Cvar::NONE, 0, 0, 64 ); - Cvar::Range> r_ssao( "r_ssao", + Cvar::Range> r_SSAO( "r_SSAO", "Screen space ambient occlusion: " "-1: show, 0: disabled, 1: enabled", Cvar::NONE, @@ -1217,7 +1217,7 @@ ScreenshotCmd screenshotPNGRegistration("screenshotPNG", ssFormat_t::SSF_PNG, "p r_printShaders = Cvar_Get( "r_printShaders", "0", 0 ); Cvar::Latch( r_bloom ); - Cvar::Latch( r_ssao ); + Cvar::Latch( r_SSAO ); Cvar::Latch( r_showLuma ); diff --git a/src/engine/renderer/tr_local.h b/src/engine/renderer/tr_local.h index 51e59cb080..2a1f6513c8 100644 --- a/src/engine/renderer/tr_local.h +++ b/src/engine/renderer/tr_local.h @@ -2781,7 +2781,7 @@ enum extern Cvar::Cvar r_bloom; extern Cvar::Cvar r_bloomBlur; extern Cvar::Cvar r_bloomPasses; - extern Cvar::Range> r_ssao; + extern Cvar::Range> r_SSAO; extern Cvar::Cvar r_showLuma; diff --git a/src/engine/renderer/tr_shade.cpp b/src/engine/renderer/tr_shade.cpp index 53af3cff26..239a92932d 100644 --- a/src/engine/renderer/tr_shade.cpp +++ b/src/engine/renderer/tr_shade.cpp @@ -135,7 +135,7 @@ static void EnableAvailableFeatures() glConfig.bloom = r_bloom.Get(); - glConfig.ssao = r_ssao.Get() != Util::ordinal( ssaoMode::DISABLED ); + glConfig.SSAO = r_SSAO.Get() != Util::ordinal( ssaoMode::DISABLED ); static const std::pair ssaoRequiredExtensions[] = { { &glConfig.textureGatherAvailable, "ARB_texture_gather" }, @@ -147,7 +147,7 @@ static void EnableAvailableFeatures() if ( !*e.first ) { Log::Warn( "SSAO disabled because %s is not available.", e.second ); - glConfig.ssao = false; + glConfig.SSAO = false; } } @@ -378,7 +378,7 @@ static void GLSL_InitGPUShadersOrError() gl_motionblurShader->MarkProgramForBuilding(); } - if ( glConfig.ssao ) + if ( glConfig.SSAO ) { gl_shaderManager.LoadShader( gl_ssaoShader );