diff --git a/src/engine/renderer/GLUtils.h b/src/engine/renderer/GLUtils.h index e7a3a635ed..e88b099eba 100644 --- a/src/engine/renderer/GLUtils.h +++ b/src/engine/renderer/GLUtils.h @@ -155,6 +155,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 f23055feb4..a369e0bf73 100644 --- a/src/engine/renderer/gl_shader.cpp +++ b/src/engine/renderer/gl_shader.cpp @@ -795,6 +795,25 @@ static std::string GenEngineConstants() { AddDefine( str, "r_colorGrading", 1 ); } + if ( r_showLuminance.Get() ) + { + AddDefine( str, "r_showLuminance", 1 ); + } + + if ( glConfig.FXAA ) + { + 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 ); + } + } + if ( r_highPrecisionRendering.Get() ) { AddDefine( str, "r_highPrecisionRendering", 1 ); } @@ -3066,4 +3085,4 @@ GlobalUBOProxy::GlobalUBOProxy() : u_Tonemap( this ), u_TonemapParms( this ), u_Exposure( this ) { -} \ No newline at end of file +} diff --git a/src/engine/renderer/glsl_source/cameraEffects_fp.glsl b/src/engine/renderer/glsl_source/cameraEffects_fp.glsl index 8b243fdb44..64bbf23ab1 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_showLuminance) + { + // That luminance vector comes from a comment in fxaa3_11_fp.glsl. + vec3 luminanceVector = vec3( 0.299, 0.587, 0.114 ); + + float luminance = dot( color.rgb, luminanceVector ); + + #if defined(r_showLuminance) + color.rgb = vec3( luminance ); + #endif + + #if defined(r_FXAA) + // Encode luminance in alpha channel. + color.a = luminance; + #endif + } + #endif + outputColor = color; } 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..380093c46f 100644 --- a/src/engine/renderer/glsl_source/fxaa_fp.glsl +++ b/src/engine/renderer/glsl_source/fxaa_fp.glsl @@ -33,13 +33,25 @@ 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 0 #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; @@ -49,7 +61,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 @@ -59,12 +71,27 @@ 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 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_backend.cpp b/src/engine/renderer/tr_backend.cpp index d8604cc632..d0702b745f 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 ( !glConfig.FXAA || !gl_fxaaShader ) { return; } @@ -1621,15 +1621,71 @@ 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 ] ); + + bool greaterThanGL33 = std::make_pair( glConfig.glMajor, glConfig.glMinor ) >= std::make_pair( 3, 3 ); + + GLuint64 handle = 0; + + // FXAA expects GL_LINEAR for the sampling to work. + if ( greaterThanGL33 ) + { + GLuint sampler = 0; + glGenSamplers( 1, &sampler ); + glSamplerParameteri( sampler, GL_TEXTURE_MAG_FILTER, GL_LINEAR) ; + glSamplerParameteri( sampler, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); + + if ( glConfig.usingBindlessTextures ) + { + // Set a handler. + GLuint texture = tr.currentRenderImage[backEnd.currentMainFBO]->texnum; + handle = glGetTextureSamplerHandleARB( texture, sampler ); + glMakeTextureHandleResidentARB( handle ); + GLuint program = gl_fxaaShader->GetProgram()->id; + GLint location = glGetUniformLocation( program, "u_ColorMap_linear" ); + glUniformHandleui64ARB( location, handle ); + } + else + { + // Bind a sampler. + glBindSampler( 0, sampler ); + } + } + else + { + // Change the filter (requires a texture bind). + glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); + glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + } + + // 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 ( greaterThanGL33 ) + { + if ( glConfig.usingBindlessTextures ) + { + // Unset the handler. + glMakeTextureHandleNonResidentARB( handle ); + } + else + { + // Unbind the sampler. + glBindSampler( 0, 0 ); + } + } + else + { + // Restore the filter (requires a texture bind). + glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); + glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); + } + GL_CheckErrors(); } @@ -1693,13 +1749,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 ( glConfig.FXAA && 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 ) ); } @@ -2810,11 +2875,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, diff --git a/src/engine/renderer/tr_init.cpp b/src/engine/renderer/tr_init.cpp index 2885749bcd..c8715693c6 100644 --- a/src/engine/renderer/tr_init.cpp +++ b/src/engine/renderer/tr_init.cpp @@ -285,8 +285,20 @@ 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::Range> r_msaa( "r_msaa", "Amount of MSAA samples. 0 to disable", Cvar::NONE, 0, 0, 64 ); + + Cvar::Cvar r_showLuminance( "r_showLuminance", "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.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 ); + + 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,9 +1217,17 @@ 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_msaa ); + + Cvar::Latch( r_showLuminance ); + + Cvar::Latch( r_FXAA ); + Cvar::Latch( r_FXAASubPix ); + Cvar::Latch( r_FXAAEdgeThreshold ); + Cvar::Latch( r_FXAAEdgeThresholdMin ); + Cvar::Latch( r_showFXAA ); + + 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 c5570f8704..783f3427b6 100644 --- a/src/engine/renderer/tr_local.h +++ b/src/engine/renderer/tr_local.h @@ -2778,9 +2778,17 @@ 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::Range> r_msaa; + + extern Cvar::Cvar r_showLuminance; + + 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; extern cvar_t *r_evsmPostProcess; diff --git a/src/engine/renderer/tr_shade.cpp b/src/engine/renderer/tr_shade.cpp index b2c95800e5..a025e1b655 100644 --- a/src/engine/renderer/tr_shade.cpp +++ b/src/engine/renderer/tr_shade.cpp @@ -181,17 +181,25 @@ 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 ); } + glConfig.FXAA = r_FXAA.Get(); + + if ( glConfig.FXAA && glConfig.MSAA ) + { + Log::Notice( "FXAA disabled because MSAA is enabled." ); + glConfig.FXAA = false; + } + glConfig.usingMaterialSystem = r_materialSystem.Get() && glConfig.materialSystemAvailable; glConfig.usingBindlessTextures = glConfig.usingMaterialSystem || ( r_preferBindlessTextures.Get() && glConfig.bindlessTexturesAvailable ); @@ -374,7 +382,7 @@ static void GLSL_InitGPUShadersOrError() gl_ssaoShader->MarkProgramForBuilding(); } - if ( r_FXAA->integer != 0 ) + if ( r_FXAA.Get() ) { gl_shaderManager.LoadShader( gl_fxaaShader );