ShowFlag.ShaderComplexity

ShowFlag.ShaderComplexity

#Overview

name: ShowFlag.ShaderComplexity

This variable is created as a Console Variable (cvar).

It is referenced in 24 C++ source files.

#Summary

#Usage in the C++ source code

The purpose of ShowFlag.ShaderComplexity is to enable a visualization mode that renders the scene colored by shader complexity. This is primarily used for performance analysis and optimization of shaders in the rendering system.

ShowFlag.ShaderComplexity is used across various Unreal Engine subsystems and modules, including:

  1. The Renderer module
  2. The Engine module
  3. The Niagara plugin (for particle effects)
  4. The MediaIOCore plugin

The value of this variable is typically set through the engine’s show flags system, which allows developers to toggle various debug visualization modes.

This variable interacts with several other variables and systems:

  1. It’s often used in conjunction with EngineShowFlags.QuadOverdraw and EngineShowFlags.ShaderComplexityWithQuadOverdraw for more detailed shader complexity visualization.
  2. It affects the behavior of the base pass rendering, post-processing, and decal rendering.
  3. It can disable certain features like DBuffer decals when enabled.

Developers should be aware of the following when using this variable:

  1. Enabling shader complexity visualization will override normal scene rendering, so it should only be used for debugging and optimization purposes.
  2. It may have performance implications when enabled, as it requires additional processing to visualize shader complexity.
  3. It can affect other rendering features and may disable some post-processing effects.

Best practices for using this variable include:

  1. Use it in conjunction with profiling tools to identify areas of high shader complexity.
  2. Remember to disable it when not actively debugging shader performance.
  3. Be aware of its interactions with other debug visualization modes and rendering features.

The associated variable ShaderComplexity is used in similar contexts and shares the same value as ShowFlag.ShaderComplexity. It’s primarily used in conditional statements to determine whether shader complexity visualization is enabled and to adjust rendering behavior accordingly. The same considerations and best practices apply to this variable as well.

#References in C++ code

#Callsites

This variable is referenced in the following C++ source code:

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Public/ShowFlagsValues.inl:207

Scope: file

Source code excerpt:

SHOWFLAG_FIXED_IN_SHIPPING(0, LightComplexity, SFG_Hidden, NSLOCTEXT("UnrealEd", "LightComplexitySF", "Light Complexity"))
/** needed for VMI_ShaderComplexity, render world colored by shader complexity */
SHOWFLAG_FIXED_IN_SHIPPING(0, ShaderComplexity, SFG_Hidden, NSLOCTEXT("UnrealEd", "ShaderComplexitySF", "Shader Complexity"))
/** needed for VMI_StationaryLightOverlap, render world colored by stationary light overlap */
SHOWFLAG_FIXED_IN_SHIPPING(0, StationaryLightOverlap,  SFG_Hidden, NSLOCTEXT("UnrealEd", "StationaryLightOverlapSF", "Stationary Light Overlap"))
/** needed for VMI_LightmapDensity and VMI_LitLightmapDensity, render checkerboard material with UVs scaled by lightmap resolution w. color tint for world-space lightmap density */
SHOWFLAG_FIXED_IN_SHIPPING(0, LightMapDensity, SFG_Hidden, NSLOCTEXT("UnrealEd", "LightMapDensitySF", "Light Map Density"))
/** Render streaming bounding volumes for the currently selected texture */
SHOWFLAG_FIXED_IN_SHIPPING(0, StreamingBounds, SFG_Advanced, NSLOCTEXT("UnrealEd", "StreamingBoundsSF", "Streaming Bounds"))

#Associated Variable and Callsites

This variable is associated with another variable named ShaderComplexity. They share the same value. See the following C++ source code.

#Loc: <Workspace>/Engine/Plugins/FX/Niagara/Source/Niagara/Private/NiagaraRendererMeshes.cpp:343

Scope (from outer to inner):

file
function     void FNiagaraRendererMeshes::PrepareParticleMeshRenderData

Source code excerpt:

	//       For main pass scene captures we exclude the batches if they are translucent
	const bool bIsExcludedViewMode = AllowDebugViewmodes() &&
		(ViewFamily.EngineShowFlags.Wireframe || ViewFamily.EngineShowFlags.ShaderComplexity || ViewFamily.EngineShowFlags.ShaderComplexityWithQuadOverdraw);
	ParticleMeshRenderData.bIsGpuLowLatencyTranslucency =
		bGpuLowLatencyTranslucency &&
		GpuReadyTickStage >= CurrentParticleData->GetGPUDataReadyStage() &&
		!bIsExcludedViewMode &&
		!SceneProxy->CastsVolumetricTranslucentShadow() &&
		ParticleMeshRenderData.DynamicDataMesh->Materials.Num() > 0 &&

#Loc: <Workspace>/Engine/Plugins/Media/MediaIOFramework/Source/MediaIOCore/Private/MediaCaptureSceneViewExtension.h:53

Scope (from outer to inner):

file
class        class FMediaCaptureSceneViewExtension : public FSceneViewExtensionBase
function     virtual void SetupView

Source code excerpt:

					!InView.Family->EngineShowFlags.VisualizeVolumetricCloudConservativeDensity &&
					!InView.Family->EngineShowFlags.VisualizeVolumetricCloudEmptySpaceSkipping &&
					!InView.Family->EngineShowFlags.ShaderComplexity;
			}
			else
			{
				bPostProcessingEnabled = InView.Family->EngineShowFlags.PostProcessing && !InView.Family->EngineShowFlags.ShaderComplexity && IsMobileHDR();
			}

			if (CapturePhase != EMediaCapturePhase::BeforePostProcessing && CapturePhase != EMediaCapturePhase::EndFrame)
			{
				if (!bPostProcessingEnabled)
				{

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/SceneView.cpp:3056

Scope (from outer to inner):

file
function     EDebugViewShaderMode FSceneViewFamily::ChooseDebugViewShaderMode

Source code excerpt:

EDebugViewShaderMode FSceneViewFamily::ChooseDebugViewShaderMode() const
{
	if (EngineShowFlags.ShaderComplexity)
	{
		if (EngineShowFlags.QuadOverdraw)
		{
			return DVSM_QuadComplexity;
		}
		else if (EngineShowFlags.ShaderComplexityWithQuadOverdraw)

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/ShowFlags.cpp:727

Scope (from outer to inner):

file
function     EViewModeIndex FindViewMode

Source code excerpt:

		return VMI_StationaryLightOverlap;
	}
	// Test QuadComplexity before ShaderComplexity because QuadComplexity also use ShaderComplexity
	else if (EngineShowFlags.QuadOverdraw)
	{
		return VMI_QuadOverdraw;
	}
	else if (EngineShowFlags.ShaderComplexityWithQuadOverdraw)
	{

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/ShowFlags.cpp:756

Scope: file

Source code excerpt:

		return VMI_RequiredTextureResolution;
	}
	else if (EngineShowFlags.ShaderComplexity)
	{
		return VMI_ShaderComplexity;
	}
	else if (EngineShowFlags.VisualizeLightCulling)
	{
		return VMI_LightComplexity;

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Public/ShowFlagsValues.inl:207

Scope: file

Source code excerpt:

SHOWFLAG_FIXED_IN_SHIPPING(0, LightComplexity, SFG_Hidden, NSLOCTEXT("UnrealEd", "LightComplexitySF", "Light Complexity"))
/** needed for VMI_ShaderComplexity, render world colored by shader complexity */
SHOWFLAG_FIXED_IN_SHIPPING(0, ShaderComplexity, SFG_Hidden, NSLOCTEXT("UnrealEd", "ShaderComplexitySF", "Shader Complexity"))
/** needed for VMI_StationaryLightOverlap, render world colored by stationary light overlap */
SHOWFLAG_FIXED_IN_SHIPPING(0, StationaryLightOverlap,  SFG_Hidden, NSLOCTEXT("UnrealEd", "StationaryLightOverlapSF", "Stationary Light Overlap"))
/** needed for VMI_LightmapDensity and VMI_LitLightmapDensity, render checkerboard material with UVs scaled by lightmap resolution w. color tint for world-space lightmap density */
SHOWFLAG_FIXED_IN_SHIPPING(0, LightMapDensity, SFG_Hidden, NSLOCTEXT("UnrealEd", "LightMapDensitySF", "Light Map Density"))
/** Render streaming bounding volumes for the currently selected texture */
SHOWFLAG_FIXED_IN_SHIPPING(0, StreamingBounds, SFG_Advanced, NSLOCTEXT("UnrealEd", "StreamingBoundsSF", "Streaming Bounds"))

#Loc: <Workspace>/Engine/Source/Runtime/Renderer/Private/BasePassRendering.cpp:1028

Scope (from outer to inner):

file
function     void FDeferredShadingSceneRenderer::RenderBasePass

Source code excerpt:


	// Always perform a full buffer clear for wireframe, shader complexity view mode, and stationary light overlap viewmode.
	if (ViewFamily.EngineShowFlags.Wireframe || ViewFamily.EngineShowFlags.ShaderComplexity || ViewFamily.EngineShowFlags.StationaryLightOverlap)
	{
		bRequiresRHIClear = true;
		bRequiresFarZQuadClear = false;
	}

	const bool bIsWireframeRenderpass = ViewFamily.EngineShowFlags.Wireframe && FSceneRenderer::ShouldCompositeEditorPrimitives(InViews[0]);

#Loc: <Workspace>/Engine/Source/Runtime/Renderer/Private/BasePassRendering.cpp:1045

Scope (from outer to inner):

file
function     void FDeferredShadingSceneRenderer::RenderBasePass

Source code excerpt:

			ViewFamily.EngineShowFlags.MeshUVDensityAccuracy ||
			ViewFamily.EngineShowFlags.PrimitiveDistanceAccuracy ||
			ViewFamily.EngineShowFlags.ShaderComplexity ||
			ViewFamily.EngineShowFlags.LODColoration ||
			ViewFamily.EngineShowFlags.HLODColoration);

	const bool bForwardShadingEnabled = IsForwardShadingEnabled(SceneTextures.Config.ShaderPlatform);

	const FExclusiveDepthStencil ExclusiveDepthStencil(BasePassDepthStencilAccess);

#Loc: <Workspace>/Engine/Source/Runtime/Renderer/Private/BasePassRendering.cpp:1062

Scope (from outer to inner):

file
function     void FDeferredShadingSceneRenderer::RenderBasePass

Source code excerpt:

	if (bRequiresRHIClear)
	{
		if (ViewFamily.EngineShowFlags.ShaderComplexity && SceneTextures.QuadOverdraw)
		{
			AddClearUAVPass(GraphBuilder, GraphBuilder.CreateUAV(SceneTextures.QuadOverdraw), FUintVector4(0, 0, 0, 0));
		}

		if (ViewFamily.EngineShowFlags.ShaderComplexity || ViewFamily.EngineShowFlags.StationaryLightOverlap)
		{
			SceneColorClearValue = FLinearColor(0, 0, 0, kSceneColorClearAlpha);
		}
		else
		{
			SceneColorClearValue = FLinearColor(InViews[0].BackgroundColor.R, InViews[0].BackgroundColor.G, InViews[0].BackgroundColor.B, kSceneColorClearAlpha);

#Loc: <Workspace>/Engine/Source/Runtime/Renderer/Private/BasePassRendering.cpp:1364

Scope (from outer to inner):

file
function     void FDeferredShadingSceneRenderer::RenderBasePassInternal

Source code excerpt:

	    case DVSM_ShaderComplexityBleedingQuadOverhead:		// Show shader complexity with quad overdraw bleeding the PS instruction count over the quad.
	    case DVSM_QuadComplexity:							// Show quad overdraw only.
		    NaniteDebugViewMode = Nanite::EDebugViewMode::ShaderComplexity;
		    break;
    
	    default:
		    break;
	    }
	}

#Loc: <Workspace>/Engine/Source/Runtime/Renderer/Private/BasePassRendering.cpp:1489

Scope (from outer to inner):

file
function     void FDeferredShadingSceneRenderer::RenderBasePassInternal

Source code excerpt:


				FMeshPassProcessorRenderState DrawRenderState;
				SetupBasePassState(BasePassDepthStencilAccess, ViewFamily.EngineShowFlags.ShaderComplexity, DrawRenderState);

				FOpaqueBasePassParameters* PassParameters = GraphBuilder.AllocParameters<FOpaqueBasePassParameters>();
				PassParameters->View = View.GetShaderParameters();
				PassParameters->ReflectionCapture = View.ReflectionCaptureUniformBuffer;
				PassParameters->BasePass = CreateOpaqueBasePassUniformBuffer(GraphBuilder, View, ViewIndex, ForwardBasePassTextures, DBufferTextures, bLumenGIEnabled);
				PassParameters->RenderTargets = BasePassRenderTargets;

#Loc: <Workspace>/Engine/Source/Runtime/Renderer/Private/BasePassRendering.cpp:1561

Scope (from outer to inner):

file
function     void FDeferredShadingSceneRenderer::RenderBasePassInternal

Source code excerpt:


				FMeshPassProcessorRenderState DrawRenderState;
				SetupBasePassState(BasePassDepthStencilAccess, ViewFamily.EngineShowFlags.ShaderComplexity, DrawRenderState);

				FOpaqueBasePassParameters* PassParameters = GraphBuilder.AllocParameters<FOpaqueBasePassParameters>();
				PassParameters->View = View.GetShaderParameters();
				PassParameters->ReflectionCapture = View.ReflectionCaptureUniformBuffer;
				PassParameters->BasePass = CreateOpaqueBasePassUniformBuffer(GraphBuilder, View, ViewIndex, ForwardBasePassTextures, DBufferTextures, bLumenGIEnabled);
				PassParameters->RenderTargets = BasePassRenderTargets;

#Loc: <Workspace>/Engine/Source/Runtime/Renderer/Private/CompositionLighting/PostProcessDeferredDecals.cpp:63

Scope (from outer to inner):

file
function     bool IsDBufferEnabled

Source code excerpt:

	return IsUsingDBuffers(ShaderPlatform)
		&& AreDecalsEnabled(ViewFamily)
		&& !ViewFamily.EngineShowFlags.ShaderComplexity;
}

IMPLEMENT_STATIC_UNIFORM_BUFFER_STRUCT(FDecalPassUniformParameters, "DecalPass", SceneTextures);

FDeferredDecalPassTextures GetDeferredDecalPassTextures(
	FRDGBuilder& GraphBuilder, 

#Loc: <Workspace>/Engine/Source/Runtime/Renderer/Private/CompositionLighting/PostProcessDeferredDecals.cpp:602

Scope (from outer to inner):

file
function     void AddDeferredDecalPass

Source code excerpt:


	const bool bVisibleDecalsInView = MeshDecalCount > 0 || SortedDecalCount > 0;
	const bool bShaderComplexity = View.Family->EngineShowFlags.ShaderComplexity;
	const bool bStencilSizeThreshold = CVarStencilSizeThreshold.GetValueOnRenderThread() >= 0;

	// Attempt to clear the D-Buffer if it's appropriate for this view.
	const EDecalDBufferMaskTechnique DBufferMaskTechnique = GetDBufferMaskTechnique(ShaderPlatform);

	const auto RenderDecals = [&](uint32 DecalIndexBegin, uint32 DecalIndexEnd, EDecalRenderTargetMode RenderTargetMode)

#Loc: <Workspace>/Engine/Source/Runtime/Renderer/Private/CompositionLighting/PostProcessMeshDecals.cpp:242

Scope (from outer to inner):

file
function     bool FMeshDecalMeshProcessor::TryAddMeshBatch

Source code excerpt:

				{
					// Deferred decals can only use translucent blend mode
					if (ViewIfDynamicMeshCommand->Family->EngineShowFlags.ShaderComplexity)
					{
						// If we are in the translucent pass then override the blend mode, otherwise maintain additive blending.
						PassDrawRenderState.SetBlendState(TStaticBlendState<CW_RGBA, BO_Add, BF_One, BF_One, BO_Add, BF_Zero, BF_One>::GetRHI());
					}
					else if (ViewIfDynamicMeshCommand->Family->GetDebugViewShaderMode() != DVSM_OutputMaterialTextureScales)
					{

#Loc: <Workspace>/Engine/Source/Runtime/Renderer/Private/DecalRenderingShared.cpp:337

Scope (from outer to inner):

file
function     FTransientDecalRenderDataList BuildVisibleDecalList

Source code excerpt:

		// Don't draw for shader complexity mode.
		// todo: Handle shader complexity mode for deferred decal.
		if (View.Family->EngineShowFlags.ShaderComplexity)
		{
			return {};
		}

		FTransientDecalRenderDataList OutVisibleDecals;

#Loc: <Workspace>/Engine/Source/Runtime/Renderer/Private/DeferredShadingRenderer.cpp:1681

Scope (from outer to inner):

file
function     void FDeferredShadingSceneRenderer::Render

Source code excerpt:

	// Use read-only depth in the base pass if we have a full depth prepass.
	const bool bAllowReadOnlyDepthBasePass = bIsEarlyDepthComplete
		&& !ViewFamily.EngineShowFlags.ShaderComplexity
		&& !ViewFamily.UseDebugViewPS()
		&& !ViewFamily.EngineShowFlags.Wireframe
		&& !ViewFamily.EngineShowFlags.LightMapDensity;

	const FExclusiveDepthStencil::Type BasePassDepthStencilAccess =
		bAllowReadOnlyDepthBasePass

#Loc: <Workspace>/Engine/Source/Runtime/Renderer/Private/MobileShadingRenderer.cpp:1065

Scope (from outer to inner):

file
function     void FMobileSceneRenderer::Render

Source code excerpt:

	{
#if WITH_DEBUG_VIEW_MODES
		if (ViewFamily.UseDebugViewPS() && ViewFamily.EngineShowFlags.ShaderComplexity && SceneTextures.QuadOverdraw)
		{
			AddClearUAVPass(GraphBuilder, GraphBuilder.CreateUAV(SceneTextures.QuadOverdraw), FUintVector4(0, 0, 0, 0));
		}
#endif

		if (bUseVirtualTexturing)

#Loc: <Workspace>/Engine/Source/Runtime/Renderer/Private/Nanite/NaniteVisualize.h:35

Scope (from outer to inner):

file
namespace    Nanite

Source code excerpt:

	None = 0,
	Wireframe = 1,
	ShaderComplexity = 2,
	LightmapDensity = 3,
	PrimitiveColor = 4,
};

void RenderDebugViewMode(
	FRDGBuilder& GraphBuilder,

#Loc: <Workspace>/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessing.cpp:186

Scope (from outer to inner):

file
function     bool IsPostProcessingEnabled

Source code excerpt:

			!View.Family->EngineShowFlags.VisualizeVolumetricCloudConservativeDensity &&
			!View.Family->EngineShowFlags.VisualizeVolumetricCloudEmptySpaceSkipping &&
			!View.Family->EngineShowFlags.ShaderComplexity;
	}
	else
	{
		return View.Family->EngineShowFlags.PostProcessing && !View.Family->EngineShowFlags.ShaderComplexity && IsMobileHDR();
	}
}

bool IsPostProcessingWithAlphaChannelSupported()
{
	return CVarPostProcessingPropagateAlpha.GetValueOnAnyThread() != 0;

#Loc: <Workspace>/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessing.cpp:1817

Scope (from outer to inner):

file
function     void AddDebugViewPostProcessingPasses

Source code excerpt:

	// Some view modes do not actually output a color so they should not be tonemapped.
	const bool bTonemapAfter = View.Family->EngineShowFlags.RayTracingDebug || View.Family->EngineShowFlags.VisualizeGPUSkinCache;
	const bool bTonemapBefore = !bTonemapAfter && !View.Family->EngineShowFlags.ShaderComplexity;
	const bool bViewFamilyOutputInHDR = View.Family->RenderTarget->GetSceneHDREnabled();

	enum class EPass : uint32
	{
		Visualize,
		TonemapAfter,

#Loc: <Workspace>/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessing.cpp:2207

Scope (from outer to inner):

file
function     void AddMobilePostProcessingPasses

Source code excerpt:

	bool bUseMobileDof = bUseDof && !View.FinalPostProcessSettings.bMobileHQGaussian;

	bool bUseToneMapper = !View.Family->EngineShowFlags.ShaderComplexity && (IsMobileHDR() || IsMobileColorsRGB());

	bool bUseHighResolutionScreenshotMask = IsHighResolutionScreenshotMaskEnabled(View);

	bool bShouldPrimaryUpscale = (View.PrimaryScreenPercentageMethod == EPrimaryScreenPercentageMethod::SpatialUpscale && View.UnscaledViewRect != View.ViewRect) || PaniniConfig.IsEnabled();
	bShouldPrimaryUpscale |= View.Family->GetPrimarySpatialUpscalerInterface() != nullptr;

#Loc: <Workspace>/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessing.cpp:2230

Scope (from outer to inner):

file
function     void AddMobilePostProcessingPasses

Source code excerpt:

	PassSequence.SetEnabled(EPass::SecondaryUpscale, View.Family->GetSecondarySpatialUpscalerInterface() != nullptr);

	PassSequence.SetEnabled(EPass::Visualize, View.Family->EngineShowFlags.ShaderComplexity);

	PassSequence.SetEnabled(EPass::HMDDistortion, View.Family->EngineShowFlags.StereoRendering && View.Family->EngineShowFlags.HMDDistortion);

	// Always evaluate custom post processes
	// The scene color will be decoded at the first post-process material and output linear color space for the following passes
	// bMetalMSAAHDRDecode will be set to false if there is any post-process material exist