From 7ee657d3309ce525ad4d38d7d08c65149a2fb07d Mon Sep 17 00:00:00 2001 From: slipher Date: Sat, 27 Sep 2025 17:06:42 -0500 Subject: [PATCH 1/2] Latch cvar r_arb_texture_barrier --- src/engine/sys/sdl_glimp.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/engine/sys/sdl_glimp.cpp b/src/engine/sys/sdl_glimp.cpp index e4fc7dc59b..49d4d6c568 100644 --- a/src/engine/sys/sdl_glimp.cpp +++ b/src/engine/sys/sdl_glimp.cpp @@ -2024,6 +2024,7 @@ static void GLimp_InitExtensions() Cvar::Latch( r_arb_shading_language_420pack ); Cvar::Latch( r_arb_shader_storage_buffer_object ); Cvar::Latch( r_arb_sync ); + Cvar::Latch( r_arb_texture_barrier ); Cvar::Latch( r_arb_texture_gather ); Cvar::Latch( r_arb_uniform_buffer_object ); Cvar::Latch( r_arb_vertex_attrib_binding ); From 89910907055ca5815d653ac604772ddae598686a Mon Sep 17 00:00:00 2001 From: slipher Date: Wed, 17 Sep 2025 12:52:40 -0500 Subject: [PATCH 2/2] Copy depth buffer if texture barrier unavailable If the texture barrier GL extension is enabled, make a read-only copy of the depth buffer to use for u_DepthMap sampling, thereby avoiding texture feedback loops in another way. Configurable by setting r_readonlyDepthBuffer 0 (skip the copy even if there is no texture barrier - useful for low-performance systems) or r_readonlyDepthBuffer 2 (always make the copy - useful for testing that code path). Fixes #1783 (broken depth fade on Apple Silicon). --- src/engine/renderer/Material.cpp | 4 ++-- src/engine/renderer/tr_backend.cpp | 22 +++++++++++++++++++--- src/engine/renderer/tr_fbo.cpp | 8 ++++++++ src/engine/renderer/tr_image.cpp | 6 ++++++ src/engine/renderer/tr_init.cpp | 29 +++++++++++++++++++++++++++++ src/engine/renderer/tr_local.h | 2 ++ src/engine/renderer/tr_public.h | 1 + src/engine/renderer/tr_shade.cpp | 4 ++-- 8 files changed, 69 insertions(+), 7 deletions(-) diff --git a/src/engine/renderer/Material.cpp b/src/engine/renderer/Material.cpp index 739b8fc6e9..6559446550 100644 --- a/src/engine/renderer/Material.cpp +++ b/src/engine/renderer/Material.cpp @@ -904,7 +904,7 @@ void BindShaderGeneric3D( Material* material ) { gl_genericShaderMaterial->SetUniform_ModelMatrix( backEnd.orientation.transformMatrix ); gl_genericShaderMaterial->SetUniform_ModelViewProjectionMatrix( glState.modelViewProjectionMatrix[glState.stackIndex] ); - gl_genericShaderMaterial->SetUniform_DepthMapBindless( GL_BindToTMU( 1, tr.currentDepthImage ) ); + gl_genericShaderMaterial->SetUniform_DepthMapBindless( GL_BindToTMU( 1, tr.depthSamplerImage ) ); // u_DeformGen gl_genericShaderMaterial->SetUniform_Time( backEnd.refdef.floatTime - backEnd.currentEntity->e.shaderTime ); @@ -1080,7 +1080,7 @@ void BindShaderLiquid( Material* material ) { gl_liquidShaderMaterial->SetUniform_ModelViewProjectionMatrix( glState.modelViewProjectionMatrix[glState.stackIndex] ); // depth texture - gl_liquidShaderMaterial->SetUniform_DepthMapBindless( GL_BindToTMU( 2, tr.currentDepthImage ) ); + gl_liquidShaderMaterial->SetUniform_DepthMapBindless( GL_BindToTMU( 2, tr.depthSamplerImage ) ); // bind u_PortalMap gl_liquidShaderMaterial->SetUniform_PortalMapBindless( GL_BindToTMU( 1, tr.portalRenderImage ) ); diff --git a/src/engine/renderer/tr_backend.cpp b/src/engine/renderer/tr_backend.cpp index ca32c29e4f..43f74375a0 100644 --- a/src/engine/renderer/tr_backend.cpp +++ b/src/engine/renderer/tr_backend.cpp @@ -1213,6 +1213,11 @@ void RB_RunVisTests( ) void RB_PrepareForSamplingDepthMap() { + if ( glConfig.usingReadonlyDepth ) + { + return; + } + if ( !glConfig.textureBarrierAvailable ) { return; @@ -1413,7 +1418,7 @@ void RB_RenderGlobalFog() // bind u_DepthMap gl_fogGlobalShader->SetUniform_DepthMapBindless( - GL_BindToTMU( 1, tr.currentDepthImage ) + GL_BindToTMU( 1, tr.depthSamplerImage ) ); Tess_InstantScreenSpaceQuad(); @@ -1535,7 +1540,7 @@ void RB_RenderMotionBlur() gl_motionblurShader->SetUniform_blurVec(tr.refdef.blurVec); gl_motionblurShader->SetUniform_DepthMapBindless( - GL_BindToTMU( 1, tr.currentDepthImage ) + GL_BindToTMU( 1, tr.depthSamplerImage ) ); Tess_InstantScreenSpaceQuad(); @@ -1586,7 +1591,7 @@ void RB_RenderSSAO() gl_ssaoShader->SetUniform_UnprojectionParams( unprojectionParams ); gl_ssaoShader->SetUniform_DepthMapBindless( - GL_BindToTMU( 0, tr.currentDepthImage ) + GL_BindToTMU( 0, tr.depthSamplerImage ) ); Tess_InstantScreenSpaceQuad(); @@ -2699,6 +2704,17 @@ static void RB_RenderView( bool depthPass ) return; } + if ( glConfig.usingReadonlyDepth ) + { + FBO_t *currentDrawFBO = glState.currentFBO; + R_BindFBO( GL_READ_FRAMEBUFFER, currentDrawFBO ); + R_BindFBO( GL_DRAW_FRAMEBUFFER, tr.readonlyDepthFBO ); + int x0 = backEnd.viewParms.viewportX, x1 = x0 + backEnd.viewParms.viewportWidth; + int y0 = backEnd.viewParms.viewportY, y1 = y0 + backEnd.viewParms.viewportHeight; + GL_fboShim.glBlitFramebuffer( x0, y0, x1, y1, x0, y0, x1, y1, GL_DEPTH_BUFFER_BIT, GL_NEAREST ); + R_BindFBO( currentDrawFBO ); + } + if( tr.refdef.blurVec[0] != 0.0f || tr.refdef.blurVec[1] != 0.0f || tr.refdef.blurVec[2] != 0.0f ) diff --git a/src/engine/renderer/tr_fbo.cpp b/src/engine/renderer/tr_fbo.cpp index d382c63b7f..642c645aa8 100644 --- a/src/engine/renderer/tr_fbo.cpp +++ b/src/engine/renderer/tr_fbo.cpp @@ -263,6 +263,14 @@ void R_InitFBOs() R_AttachFBOTexturePackedDepthStencil( tr.currentDepthImage->texnum ); R_CheckFBO( tr.mainFBO[1] ); + if ( glConfig.usingReadonlyDepth ) + { + tr.readonlyDepthFBO = R_CreateFBO( "_depthReadonly", width, height ); + R_BindFBO( tr.readonlyDepthFBO ); + R_AttachFBOTexturePackedDepthStencil( tr.depthSamplerImage->texnum ); + glConfig.usingReadonlyDepth = R_CheckFBO( tr.readonlyDepthFBO ); + } + if ( glConfig.realtimeLighting ) { /* It's only required to create frame buffers only used by the diff --git a/src/engine/renderer/tr_image.cpp b/src/engine/renderer/tr_image.cpp index 8353564c03..b430bedcd4 100644 --- a/src/engine/renderer/tr_image.cpp +++ b/src/engine/renderer/tr_image.cpp @@ -2473,6 +2473,12 @@ static void R_CreateCurrentRenderImage() tr.currentDepthImage = R_CreateImage( "*currentDepth", nullptr, width, height, 1, imageParams ); + if ( glConfig.usingReadonlyDepth ) + { + // For use with glBlitFramebuffer, format must be the same as currentDepthImage + tr.depthSamplerImage = R_CreateImage( "*readonlyDepth", nullptr, width, height, 1, imageParams ); + } + if ( glConfig.usingMaterialSystem ) { materialSystem.GenerateDepthImages( width, height, imageParams ); } diff --git a/src/engine/renderer/tr_init.cpp b/src/engine/renderer/tr_init.cpp index 00a8bcbb6d..1d9c5bb81d 100644 --- a/src/engine/renderer/tr_init.cpp +++ b/src/engine/renderer/tr_init.cpp @@ -92,6 +92,9 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Cvar::Cvar r_overbrightIgnoreMapSettings("r_overbrightIgnoreMapSettings", "force usage of r_overbrightDefaultClamp / r_overbrightDefaultExponent, ignoring worldspawn", Cvar::NONE, false); Cvar::Range> r_lightMode("r_lightMode", "lighting mode: 0: fullbright (cheat), 1: vertex light, 2: grid light (cheat), 3: light map", Cvar::NONE, Util::ordinal(lightMode_t::MAP), Util::ordinal(lightMode_t::FULLBRIGHT), Util::ordinal(lightMode_t::MAP)); Cvar::Cvar r_colorGrading( "r_colorGrading", "Use color grading", Cvar::NONE, true ); + static Cvar::Range> r_readonlyDepthBuffer( + "r_readonlyDepthBuffer", "sample depth from a copy of the depth texture: 0 = no (unsafe), 1 = if necessary depending on GL features, 2 = yes", + Cvar::NONE, 1, 0, 2); Cvar::Cvar r_preferBindlessTextures( "r_preferBindlessTextures", "use bindless textures even when material system is off", Cvar::NONE, false ); Cvar::Cvar r_materialSystem( "r_materialSystem", "Use Material System", Cvar::NONE, false ); Cvar::Cvar r_gpuFrustumCulling( "r_gpuFrustumCulling", "Use frustum culling on the GPU for the Material System", Cvar::NONE, true ); @@ -1193,6 +1196,7 @@ ScreenshotCmd screenshotPNGRegistration("screenshotPNG", ssFormat_t::SSF_PNG, "p Cvar::Latch( r_realtimeLighting ); Cvar::Latch( r_realtimeLightLayers ); + Cvar::Latch( r_readonlyDepthBuffer ); Cvar::Latch( r_preferBindlessTextures ); Cvar::Latch( r_materialSystem ); @@ -1407,12 +1411,37 @@ ScreenshotCmd screenshotPNGRegistration("screenshotPNG", ssFormat_t::SSF_PNG, "p backEndData[ 1 ] = nullptr; } + switch ( r_readonlyDepthBuffer.Get() ) + { + case 0: + glConfig.usingReadonlyDepth = false; + break; + case 1: + glConfig.usingReadonlyDepth = !glConfig.textureBarrierAvailable; + break; + case 2: + glConfig.usingReadonlyDepth = true; + break; + } + + if ( glConfig.usingReadonlyDepth && !r_depthShaders.Get() ) + { + Log::Warn( "Disabling read-only depth buffer because depth pre-pass is disabled" ); + glConfig.usingReadonlyDepth = false; + } + R_ToggleSmpFrame(); R_InitImages(); R_InitFBOs(); + // This is here in case creating the depth-only FBO failed. + if ( !glConfig.usingReadonlyDepth ) + { + tr.depthSamplerImage = tr.currentDepthImage; + } + R_InitVBOs(); R_InitShaders(); diff --git a/src/engine/renderer/tr_local.h b/src/engine/renderer/tr_local.h index d97ef87f3a..0ba092ed53 100644 --- a/src/engine/renderer/tr_local.h +++ b/src/engine/renderer/tr_local.h @@ -2454,6 +2454,7 @@ enum image_t *bloomRenderFBOImage[ 2 ]; image_t *currentRenderImage[ 2 ]; image_t *currentDepthImage; + image_t *depthSamplerImage; image_t *depthtile1RenderImage; image_t *depthtile2RenderImage; image_t *lighttileRenderImage; @@ -2465,6 +2466,7 @@ enum // framebuffer objects FBO_t *mainFBO[ 2 ]; + FBO_t *readonlyDepthFBO; FBO_t *depthtile1FBO; FBO_t *depthtile2FBO; FBO_t *lighttileFBO; diff --git a/src/engine/renderer/tr_public.h b/src/engine/renderer/tr_public.h index 92a144e1d4..3864e278b4 100644 --- a/src/engine/renderer/tr_public.h +++ b/src/engine/renderer/tr_public.h @@ -111,6 +111,7 @@ struct GLConfig bool computeShaderAvailable; bool bindlessTexturesAvailable; // do the driver/hardware support it bool usingBindlessTextures; // are we using them right now + bool usingReadonlyDepth; bool shaderDrawParametersAvailable; bool SSBOAvailable; bool multiDrawIndirectAvailable; diff --git a/src/engine/renderer/tr_shade.cpp b/src/engine/renderer/tr_shade.cpp index 9c118cac0c..19c481d928 100644 --- a/src/engine/renderer/tr_shade.cpp +++ b/src/engine/renderer/tr_shade.cpp @@ -951,7 +951,7 @@ void Render_generic3D( shaderStage_t *pStage ) if ( needDepthMap ) { gl_genericShader->SetUniform_DepthMapBindless( - GL_BindToTMU( 1, tr.currentDepthImage ) + GL_BindToTMU( 1, tr.depthSamplerImage ) ); } @@ -1550,7 +1550,7 @@ void Render_liquid( shaderStage_t *pStage ) gl_liquidShader->SetUniform_PortalMapBindless( GL_BindToTMU( 1, tr.portalRenderImage ) ); // depth texture - gl_liquidShader->SetUniform_DepthMapBindless( GL_BindToTMU( 2, tr.currentDepthImage ) ); + gl_liquidShader->SetUniform_DepthMapBindless( GL_BindToTMU( 2, tr.depthSamplerImage ) ); // bind u_HeightMap u_depthScale u_reliefOffsetBias if ( pStage->enableReliefMapping )