From fd7ff8a3e72304aa633ec05fd388b07d991426fe Mon Sep 17 00:00:00 2001 From: John-Michael Mulesa Date: Sat, 19 Sep 2026 19:26:21 -0400 Subject: [PATCH] Prevent leaked menu soft-focus blur from rendering during live gameplay --- src/renderer/RenderSystem.cpp | 17 ++++++++++++++++- src/renderer/RenderSystem_init.cpp | 3 ++- src/renderer/ScenePackets.cpp | 3 +++ src/renderer/Vulkan/vk_GuiExecutor.cpp | 13 ++++++++++++- src/renderer/draw_common.cpp | 24 +++++++++++++++++++++++- src/renderer/tr_local.h | 1 + 6 files changed, 57 insertions(+), 4 deletions(-) diff --git a/src/renderer/RenderSystem.cpp b/src/renderer/RenderSystem.cpp index 8d246322c..9cedc1402 100644 --- a/src/renderer/RenderSystem.cpp +++ b/src/renderer/RenderSystem.cpp @@ -471,10 +471,25 @@ void R_AddSpecialEffects( viewDef_t *parms ) { } activeMask = tr.specialEffectsEnabled; - if ( r_forceSpecialEffects.GetInteger() > 0 ) { + if ( r_forceSpecialEffects.GetInteger() < 0 || !r_specialEffects.GetBool() || r_skipPostProcess.GetBool() ) { + activeMask = 0; + } else if ( r_forceSpecialEffects.GetInteger() > 0 ) { activeMask = r_forceSpecialEffects.GetInteger(); } + if ( ( activeMask & SPECIAL_EFFECT_BLUR ) != 0 ) { + const float focus = tr.specialEffectParms[ SPECIAL_EFFECT_BLUR ][5]; + const float strength = tr.specialEffectParms[ SPECIAL_EFFECT_BLUR ][6]; + const float distanceScale = tr.specialEffectParms[ SPECIAL_EFFECT_BLUR ][7]; + const bool isJoinSoftFocus = ( focus < 0.02f && distanceScale >= 256.0f && strength >= 0.5f ); + if ( isJoinSoftFocus ) { + if ( ( session != NULL && !session->IsGUIActive() ) || parms->renderView.viewID > 0 ) { + tr.specialEffectsEnabled &= ~SPECIAL_EFFECT_BLUR; + activeMask &= ~SPECIAL_EFFECT_BLUR; + } + } + } + if ( ( activeMask & ( SPECIAL_EFFECT_BLUR | SPECIAL_EFFECT_AL ) ) == 0 ) { return; } diff --git a/src/renderer/RenderSystem_init.cpp b/src/renderer/RenderSystem_init.cpp index 4f2388696..1431fdac5 100644 --- a/src/renderer/RenderSystem_init.cpp +++ b/src/renderer/RenderSystem_init.cpp @@ -258,8 +258,9 @@ idCVar r_motionBlurMaxPixels( "r_motionBlurMaxPixels", "10", CVAR_RENDERER | CVA idCVar r_motionBlurSamples( "r_motionBlurSamples", "8", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_INTEGER, "number of motion blur gather samples", 1, 16, idCmdSystem::ArgCompletion_Integer<1,16> ); idCVar r_motionBlurDebug( "r_motionBlurDebug", "0", CVAR_RENDERER | CVAR_BOOL, "visualize motion blur vectors instead of applying blur" ); idCVar r_motionBlurObjectVectors( "r_motionBlurObjectVectors", "1", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_BOOL, "include rigid-object motion vectors when r_motionBlur is enabled" ); +idCVar r_specialEffects( "r_specialEffects", "1", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_BOOL, "enable special-effect post-processing passes (blur, AL)" ); idCVar r_forceSpecialEffects( "r_forceSpecialEffects", "0", CVAR_RENDERER | CVAR_INTEGER, - "force legacy special-effect bitmask for debugging (1=blur, 2=AL, 3=both)", 0, 3, idCmdSystem::ArgCompletion_Integer<0,3> ); + "force legacy special-effect bitmask for debugging (-1=force all off, 1=blur, 2=AL, 3=both)", -1, 3, idCmdSystem::ArgCompletion_Integer<-1,3> ); idCVar r_hdrSceneTarget( "r_hdrSceneTarget", "1", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_BOOL, "render the main scene into an HDR scene target before post-processing" ); idCVar r_hdrToneMap( "r_hdrToneMap", "0", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_BOOL, "enable filmic tone mapping and color correction pass" ); idCVar r_hdrExposure( "r_hdrExposure", "1.0", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_FLOAT, "manual exposure multiplier applied after auto exposure", 0.1f, 16.0f ); diff --git a/src/renderer/ScenePackets.cpp b/src/renderer/ScenePackets.cpp index d97bf7e83..4bf776f0a 100644 --- a/src/renderer/ScenePackets.cpp +++ b/src/renderer/ScenePackets.cpp @@ -142,6 +142,9 @@ static bool R_ScenePackets_IsRenderDemoPlaybackView( const viewDef_t *viewDef ) // backend-derived packet retains the same special-frame provenance as the // front-end packet. static int R_ScenePackets_ActiveSpecialEffectsMask( void ) { + if ( r_forceSpecialEffects.GetInteger() < 0 || !r_specialEffects.GetBool() || r_skipPostProcess.GetBool() ) { + return 0; + } int activeMask = tr.specialEffectsEnabled; if ( r_forceSpecialEffects.GetInteger() > 0 ) { activeMask = r_forceSpecialEffects.GetInteger(); diff --git a/src/renderer/Vulkan/vk_GuiExecutor.cpp b/src/renderer/Vulkan/vk_GuiExecutor.cpp index e28506ee6..281446f41 100644 --- a/src/renderer/Vulkan/vk_GuiExecutor.cpp +++ b/src/renderer/Vulkan/vk_GuiExecutor.cpp @@ -8558,10 +8558,21 @@ after the scene color and depth are complete and before any later HUD view. */ void VK_GuiExecutor_PrepareSpecialEffects( const viewDef_t *viewDef ) { int activeMask = tr.specialEffectsEnabled; - if ( r_forceSpecialEffects.GetInteger() > 0 ) { + if ( r_forceSpecialEffects.GetInteger() < 0 || !r_specialEffects.GetBool() || r_skipPostProcess.GetBool() ) { + activeMask = 0; + } else if ( r_forceSpecialEffects.GetInteger() > 0 ) { activeMask = r_forceSpecialEffects.GetInteger(); } activeMask &= SPECIAL_EFFECT_BLUR | SPECIAL_EFFECT_AL; + if ( ( activeMask & SPECIAL_EFFECT_BLUR ) != 0 ) { + const float focus = tr.specialEffectParms[ SPECIAL_EFFECT_BLUR ][5]; + const float strength = tr.specialEffectParms[ SPECIAL_EFFECT_BLUR ][6]; + const float distanceScale = tr.specialEffectParms[ SPECIAL_EFFECT_BLUR ][7]; + const bool isJoinSoftFocus = ( focus < 0.02f && distanceScale >= 256.0f && strength >= 0.5f ); + if ( isJoinSoftFocus && viewDef != NULL && viewDef->renderView.viewID > 0 ) { + activeMask &= ~SPECIAL_EFFECT_BLUR; + } + } vkExec.pendingSpecialEffectsView = activeMask != 0 ? viewDef : NULL; diff --git a/src/renderer/draw_common.cpp b/src/renderer/draw_common.cpp index 1c3ce8168..1a161c6e5 100644 --- a/src/renderer/draw_common.cpp +++ b/src/renderer/draw_common.cpp @@ -7976,10 +7976,22 @@ void RB_DrawSpecialEffects( const void *data ) { rbRVSpecialBlurPrepared = false; rbRVSpecialALPrepared = false; rbRVSpecialActiveMask = tr.specialEffectsEnabled; - if ( r_forceSpecialEffects.GetInteger() > 0 ) { + if ( r_forceSpecialEffects.GetInteger() < 0 || !r_specialEffects.GetBool() || r_skipPostProcess.GetBool() ) { + rbRVSpecialActiveMask = 0; + } else if ( r_forceSpecialEffects.GetInteger() > 0 ) { rbRVSpecialActiveMask = r_forceSpecialEffects.GetInteger(); } + if ( ( rbRVSpecialActiveMask & SPECIAL_EFFECT_BLUR ) != 0 ) { + const float focus = tr.specialEffectParms[ SPECIAL_EFFECT_BLUR ][5]; + const float strength = tr.specialEffectParms[ SPECIAL_EFFECT_BLUR ][6]; + const float distanceScale = tr.specialEffectParms[ SPECIAL_EFFECT_BLUR ][7]; + const bool isJoinSoftFocus = ( focus < 0.02f && distanceScale >= 256.0f && strength >= 0.5f ); + if ( isJoinSoftFocus && backEnd.viewDef != NULL && backEnd.viewDef->renderView.viewID > 0 ) { + rbRVSpecialActiveMask &= ~SPECIAL_EFFECT_BLUR; + } + } + if ( backEnd.viewDef == NULL || backEnd.viewDef->renderWorld == NULL || backEnd.viewDef->numDrawSurfs <= 0 ) { return; } @@ -8010,12 +8022,22 @@ static void RB_DisplaySpecialEffects( const viewEntity_t *viewEnts, bool prePass if ( backEnd.viewDef == NULL || !glConfig.GLSLProgramAvailable ) { return; } + if ( r_forceSpecialEffects.GetInteger() < 0 || !r_specialEffects.GetBool() || r_skipPostProcess.GetBool() ) { + return; + } if ( prePass ) { // Legacy blur is authored as a fullscreen 2D overlay. The 3D pass only captures // its depth mask; the blur image itself is generated from the resolved scene when // the later HUD/UI view starts. if ( viewEnts == NULL && ( rbRVSpecialActiveMask & SPECIAL_EFFECT_BLUR ) != 0 ) { + const float focus = tr.specialEffectParms[ SPECIAL_EFFECT_BLUR ][5]; + const float strength = tr.specialEffectParms[ SPECIAL_EFFECT_BLUR ][6]; + const float distanceScale = tr.specialEffectParms[ SPECIAL_EFFECT_BLUR ][7]; + const bool isJoinSoftFocus = ( focus < 0.02f && distanceScale >= 256.0f && strength >= 0.5f ); + if ( isJoinSoftFocus && rbRVSpecialCommandView != NULL && rbRVSpecialCommandView->renderView.viewID > 0 ) { + return; + } bool restoredView = false; if ( RB_PrepareRVSpecialBlurImage() ) { restoredView |= RB_CompositeRVSpecialBlur(); diff --git a/src/renderer/tr_local.h b/src/renderer/tr_local.h index 61fea6fed..31c534e34 100644 --- a/src/renderer/tr_local.h +++ b/src/renderer/tr_local.h @@ -1065,6 +1065,7 @@ extern idCVar r_motionBlurMaxPixels; // maximum motion blur radius in pixels extern idCVar r_motionBlurSamples; // motion blur gather sample count extern idCVar r_motionBlurDebug; // visualize motion blur vectors extern idCVar r_motionBlurObjectVectors; // include rigid-object motion vectors +extern idCVar r_specialEffects; // enable special-effect post-processing passes (blur, AL) extern idCVar r_forceSpecialEffects; // force legacy special-effect bitmask for debugging extern idCVar r_hdrSceneTarget; // render the main scene into an HDR scene target before post-processing extern idCVar r_hdrToneMap; // enable filmic tone mapping and color correction