bool StripUnsupportedVariants(ShaderCompilerData compilerData) { // Dynamic GI is not supported so we can strip variants that have directional lightmap // enabled but not baked lightmap. if (compilerData.shaderKeywordSet.IsEnabled(m_DirectionalLightmap) && !compilerData.shaderKeywordSet.IsEnabled(m_Lightmap)) { return(true); } if (compilerData.shaderCompilerPlatform == ShaderCompilerPlatform.GLES20) { if (compilerData.shaderKeywordSet.IsEnabled(m_CascadeShadows)) { return(true); } } return(false); }
protected override bool MatchVariant(ShaderCompilerData variantData) { TierData t; if (_data.TryGetValue(variantData.shaderCompilerPlatform, out t)) { switch (variantData.graphicsTier) { case GraphicsTier.Tier1: return(t.stripTier1); case GraphicsTier.Tier2: return(t.stripTier2); case GraphicsTier.Tier3: return(t.stripTier3); } } return(false); }
private bool IsExist(Dictionary <Shader, HashSet <ShaderVariantsInfo> > shaderVariants, Shader shader, ShaderSnippetData snippet, ShaderCompilerData data) { var keywords = data.shaderKeywordSet.GetShaderKeywords(); var compiledKeyword = Convert(shader, keywords); var targetInfo = new ShaderVariantsInfo(shader, snippet.passType, compiledKeyword.ToArray()); if (compiledKeyword.Count == 0) { return(true); } HashSet <ShaderVariantsInfo> variantsHashSet = null; if (shaderVariants.TryGetValue(shader, out variantsHashSet)) { bool flag = (variantsHashSet.Contains(targetInfo)); return(flag); } return(false); }
bool StripUnsupportedVariants(ShaderCompilerData compilerData) { // Dynamic GI is not supported so we can strip variants that have directional lightmap // enabled but not baked lightmap. if (compilerData.shaderKeywordSet.IsEnabled(m_DirectionalLightmap) && !compilerData.shaderKeywordSet.IsEnabled(m_Lightmap)) return true; if (compilerData.shaderCompilerPlatform == ShaderCompilerPlatform.GLES20) { if (compilerData.shaderKeywordSet.IsEnabled(m_CascadeShadows)) return true; // GLES2 does not support VertexID that is required for full screen draw procedural pass; if (compilerData.shaderKeywordSet.IsEnabled(m_UseDrawProcedural)) return true; } return false; }
bool StripUnsupportedVariants(ShaderCompilerData compilerData) { // Dynamic GI is not supported so we can strip variants that have directional lightmap // enabled but not baked lightmap. if (compilerData.shaderKeywordSet.IsEnabled(m_DirectionalLightmap) && !compilerData.shaderKeywordSet.IsEnabled(m_Lightmap)) { return(true); } // As GLES2 has low amount of registers, we strip: if (compilerData.shaderCompilerPlatform == ShaderCompilerPlatform.GLES20) { // VertexID - as GLES2 does not support VertexID that is required for full screen draw procedural pass; if (compilerData.shaderKeywordSet.IsEnabled(m_UseDrawProcedural)) { return(true); } // Cascade shadows if (compilerData.shaderKeywordSet.IsEnabled(m_CascadeShadows)) { return(true); } // Detail if (compilerData.shaderKeywordSet.IsEnabled(m_LocalDetailMulx2) || compilerData.shaderKeywordSet.IsEnabled(m_LocalDetailScaled)) { return(true); } // Clear Coat if (compilerData.shaderKeywordSet.IsEnabled(m_LocalClearCoat) || compilerData.shaderKeywordSet.IsEnabled(m_LocalClearCoatMap)) { return(true); } } return(false); }
public void OnProcessShader(Shader shader, ShaderSnippetData snippet, IList <ShaderCompilerData> inputData) { // TODO: Grab correct configuration/quality asset. HDRenderPipelineAsset hdPipelineAsset = GraphicsSettings.renderPipelineAsset as HDRenderPipelineAsset; if (hdPipelineAsset == null) { return; } // This test will also return if we are not using HDRenderPipelineAsset if (hdPipelineAsset == null || !hdPipelineAsset.allowShaderVariantStripping) { return; } int inputShaderVariantCount = inputData.Count; for (int i = 0; i < inputData.Count; ++i) { ShaderCompilerData input = inputData[i]; bool removeInput = false; // Call list of strippers // Note that all strippers cumulate each other, so be aware of any conflict here foreach (BaseShaderPreprocessor material in materialList) { if (material.ShadersStripper(hdPipelineAsset, shader, snippet, input)) { removeInput = true; } } if (removeInput) { inputData.RemoveAt(i); i--; } } }
public void OnProcessShader(Shader shader, ShaderSnippetData snippet, IList <ShaderCompilerData> inputData) { // This test will also return if we are not using HDRenderPipelineAsset if (m_CurrentHDRPAsset == null || !m_CurrentHDRPAsset.allowShaderVariantStripping) { return; } // Do we have a shader variant stripper function for this shader? VariantStrippingFunc stripperFunc = null; m_StripperFuncs.TryGetValue(shader.name, out stripperFunc); if (stripperFunc == null) { return; } int inputShaderVariantCount = inputData.Count; ShaderCompilerData workaround = inputData[0]; for (int i = 0; i < inputData.Count; ++i) { ShaderCompilerData input = inputData[i]; if (stripperFunc(m_CurrentHDRPAsset, shader, snippet, input)) { inputData.RemoveAt(i); i--; } } // Currently if a certain snippet is completely stripped (for example if you remove a whole pass) other passes might get broken // To work around that, we make sure that we always have at least one variant. // TODO: Remove this one it is fixed if (inputData.Count == 0) { inputData.Add(workaround); } }
bool StripInvalidVariants(ShaderCompilerData compilerData) { bool isMainShadow = compilerData.shaderKeywordSet.IsEnabled(m_MainLightShadows); bool isAdditionalShadow = compilerData.shaderKeywordSet.IsEnabled(m_AdditionalLightShadows); bool isShadowVariant = isMainShadow || isAdditionalShadow; if (!isMainShadow && compilerData.shaderKeywordSet.IsEnabled(m_CascadeShadows)) { return(true); } if (!isShadowVariant && compilerData.shaderKeywordSet.IsEnabled(m_SoftShadows)) { return(true); } if (isAdditionalShadow && !compilerData.shaderKeywordSet.IsEnabled(m_AdditionalLightsPixel)) { return(true); } return(false); }
bool StripInvalidVariants(ShaderCompilerData compilerData) { bool isMainShadowNoCascades = compilerData.shaderKeywordSet.IsEnabled(m_MainLightShadows); bool isMainShadowCascades = compilerData.shaderKeywordSet.IsEnabled(m_MainLightShadowsCascades); bool isMainShadowScreen = compilerData.shaderKeywordSet.IsEnabled(m_MainLightShadowsScreen); bool isMainShadow = isMainShadowNoCascades || isMainShadowCascades || isMainShadowScreen; bool isAdditionalShadow = compilerData.shaderKeywordSet.IsEnabled(m_AdditionalLightShadows); if (isAdditionalShadow && !(compilerData.shaderKeywordSet.IsEnabled(m_AdditionalLightsPixel) || compilerData.shaderKeywordSet.IsEnabled(m_ClusteredRendering) || compilerData.shaderKeywordSet.IsEnabled(m_DeferredStencil))) { return(true); } bool isShadowVariant = isMainShadow || isAdditionalShadow; if (!isShadowVariant && compilerData.shaderKeywordSet.IsEnabled(m_SoftShadows)) { return(true); } return(false); }
public void OnProcessShader(Shader shader, ShaderSnippetData snippet, IList <ShaderCompilerData> inputData) { bool shouldStripNonShadowmaskVariant = false; // We always use shadow-mask // Need to check if this is really okay: // With no mixed light around, HDRP may set SHADOWS_SHADOWMASK off and not allocate resource needed by shader with SHADOWS_SHADOWMASK turned on // However as we test nothing looks broken, let's keep this to make shader compile faster // For final build/release, let's not strip SHADOWS_SHADOWMASK off shaders to be on the safe side if (shader.name == "HDRP/Lit" || shader.name == "HDRP/LayeredLit" || shader.name == "HDRP/LitTessellation" || shader.name == "HDRP/LayeredLitTessellation") { bool isGBufferPass = snippet.passName == "GBuffer"; bool isTransparentBackfacePass = snippet.passName == "TransparentBackface"; bool isForwardPass = snippet.passName == "Forward"; if (isGBufferPass || isTransparentBackfacePass || isForwardPass) { shouldStripNonShadowmaskVariant = true; } } for (int i = 0; i < inputData.Count; ++i) { ShaderCompilerData input = inputData[i]; if (ShouldStripShader(input, shouldStripNonShadowmaskVariant)) { inputData.RemoveAt(i); i--; } } }
bool StripDeprecated(ShaderCompilerData compilerData) { if (compilerData.shaderKeywordSet.IsEnabled(m_DeprecatedVertexLights)) { return(true); } if (compilerData.shaderKeywordSet.IsEnabled(m_DeprecatedShadowsCascade)) { return(true); } if (compilerData.shaderKeywordSet.IsEnabled(m_DeprecatedShadowsEnabled)) { return(true); } if (compilerData.shaderKeywordSet.IsEnabled(m_DeprecatedLocalShadowsEnabled)) { return(true); } return(false); }
public override bool ShadersStripper(HDRenderPipelineAsset hdrpAsset, Shader shader, ShaderSnippetData snippet, ShaderCompilerData inputData) { // Strip every useless shadow configs var shadowInitParams = hdrpAsset.renderPipelineSettings.hdShadowInitParams; foreach (var shadowVariant in m_ShadowVariants) { if (shadowVariant.Key != shadowInitParams.shadowQuality) { if (inputData.shaderKeywordSet.IsEnabled(shadowVariant.Value)) { return(true); } } } bool isSceneSelectionPass = snippet.passName == "SceneSelectionPass"; if (isSceneSelectionPass) { return(true); } bool isMotionPass = snippet.passName == "Motion Vectors"; if (!hdrpAsset.renderPipelineSettings.supportMotionVectors && isMotionPass) { return(true); } //bool isForwardPass = (snippet.passName == "Forward") || (snippet.passName == "ForwardOnly"); if (inputData.shaderKeywordSet.IsEnabled(m_Transparent)) { // If we are transparent we use cluster lighting and not tile lighting if (inputData.shaderKeywordSet.IsEnabled(m_TileLighting)) { return(true); } } else // Opaque { // Note: we can't assume anything regarding tile/cluster for opaque as multiple view could used different settings and it depends on MSAA } // TODO: If static lighting we can remove meta pass, but how to know that? // If we are in a release build, don't compile debug display variant // Also don't compile it if not requested by the render pipeline settings if ((/*!Debug.isDebugBuild || */ !hdrpAsset.renderPipelineSettings.supportRuntimeDebugDisplay) && inputData.shaderKeywordSet.IsEnabled(m_DebugDisplay)) { return(true); } if (inputData.shaderKeywordSet.IsEnabled(m_LodFadeCrossFade) && !hdrpAsset.renderPipelineSettings.supportDitheringCrossFade) { return(true); } // Decal case // If decal support, remove unused variant if (hdrpAsset.renderPipelineSettings.supportDecals) { // Remove the no decal case if (inputData.shaderKeywordSet.IsEnabled(m_DecalsOFF)) { return(true); } // If decal but with 4RT remove 3RT variant and vice versa if (inputData.shaderKeywordSet.IsEnabled(m_Decals3RT) && hdrpAsset.renderPipelineSettings.decalSettings.perChannelMask) { return(true); } if (inputData.shaderKeywordSet.IsEnabled(m_Decals4RT) && !hdrpAsset.renderPipelineSettings.decalSettings.perChannelMask) { return(true); } } else { // If no decal support, remove decal variant if (inputData.shaderKeywordSet.IsEnabled(m_Decals3RT) || inputData.shaderKeywordSet.IsEnabled(m_Decals4RT)) { return(true); } } if (inputData.shaderKeywordSet.IsEnabled(m_LightLayers) && !hdrpAsset.renderPipelineSettings.supportLightLayers) { return(true); } if (inputData.shaderKeywordSet.IsEnabled(m_WriteMSAADepth) && !hdrpAsset.renderPipelineSettings.supportMSAA) { return(true); } // Note that this is only going to affect the deferred shader and for a debug case, so it won't save much. if (inputData.shaderKeywordSet.IsEnabled(m_SubsurfaceScattering) && !hdrpAsset.renderPipelineSettings.supportSubsurfaceScattering) { return(true); } return(false); }
public override bool ShouldIncludeVariant(Shader shader, ShaderSnippetData snippet, ShaderCompilerData data) { var keywords = data.shaderKeywordSet.ToList(shader); var shaderFound = false; foreach (var variant in variantCollections) { if (variant.shader == shader) { shaderFound = true; if (variant.keywords.HasSameElements(keywords)) { return(true); } if (matchWithoutLocalKeywords && variant.globalKeywords.HasSameElements(keywords)) { return(true); } } } return(onlyStripShadersInCollections && !shaderFound); }
public void OnProcessComputeShader(ComputeShader shader, string kernelName, IList <ShaderCompilerData> inputData) { if (HDRenderPipeline.currentAsset == null) { return; } if (HDRenderPipelineGlobalSettings.Ensure(canCreateNewAsset: false) == null) { return; } // Discard any compute shader use for raytracing if none of the RP asset required it ComputeShader unused; if (!ShaderBuildPreprocessor.playerNeedRaytracing && ShaderBuildPreprocessor.computeShaderCache.TryGetValue(shader.GetInstanceID(), out unused)) { return; } var exportLog = ShaderBuildPreprocessor.hdrpAssets.Count > 0 && (HDRenderPipelineGlobalSettings.instance.shaderVariantLogLevel != ShaderVariantLogLevel.Disabled); Stopwatch shaderStripingWatch = new Stopwatch(); shaderStripingWatch.Start(); using (new ExportComputeShaderStrip(exportLog, "Temp/compute-shader-strip.json", shader, kernelName, inputData, this)) { var inputShaderVariantCount = inputData.Count; var hdPipelineAssets = ShaderBuildPreprocessor.hdrpAssets; if (hdPipelineAssets.Count == 0) { return; } uint preStrippingCount = (uint)inputData.Count; for (int i = 0; i < inputShaderVariantCount;) { ShaderCompilerData input = inputData[i]; bool removeInput = true; foreach (var hdAsset in hdPipelineAssets) { if (!StripShader(hdAsset, shader, kernelName, input)) { removeInput = false; break; } } if (removeInput) { inputData[i] = inputData[--inputShaderVariantCount]; } else { ++i; } } if (inputData is List <ShaderCompilerData> inputDataList) { inputDataList.RemoveRange(inputShaderVariantCount, inputDataList.Count - inputShaderVariantCount); } else { for (int i = inputData.Count - 1; i >= inputShaderVariantCount; --i) { inputData.RemoveAt(i); } } if (HDRenderPipelineGlobalSettings.instance.shaderVariantLogLevel != ShaderVariantLogLevel.Disabled) { foreach (var hdAsset in hdPipelineAssets) { m_TotalVariantsInputCount += preStrippingCount; m_TotalVariantsOutputCount += (uint)inputData.Count; LogShaderVariants(shader, kernelName, HDRenderPipelineGlobalSettings.instance.shaderVariantLogLevel, preStrippingCount, (uint)inputData.Count); } } } }
public void OnProcessShader(Shader shader, ShaderSnippetData snippet, IList <ShaderCompilerData> inputData) { if (HDRenderPipeline.currentAsset == null) { return; } if (HDRenderPipelineGlobalSettings.Ensure(canCreateNewAsset: false) == null) { return; } var exportLog = ShaderBuildPreprocessor.hdrpAssets.Count > 0 && (HDRenderPipelineGlobalSettings.instance.shaderVariantLogLevel != ShaderVariantLogLevel.Disabled); Stopwatch shaderStripingWatch = new Stopwatch(); shaderStripingWatch.Start(); using (new ExportShaderStrip(exportLog, "Temp/shader-strip.json", shader, snippet, inputData, this)) { // TODO: Grab correct configuration/quality asset. var hdPipelineAssets = ShaderBuildPreprocessor.hdrpAssets; if (hdPipelineAssets.Count == 0) { return; } uint preStrippingCount = (uint)inputData.Count; // Test if striping is enabled in any of the found HDRP assets. if (hdPipelineAssets.Count == 0 || !hdPipelineAssets.Any(a => a.allowShaderVariantStripping)) { return; } var inputShaderVariantCount = inputData.Count; for (int i = 0; i < inputShaderVariantCount;) { ShaderCompilerData input = inputData[i]; // Remove the input by default, until we find a HDRP Asset in the list that needs it. bool removeInput = true; foreach (var hdAsset in hdPipelineAssets) { var strippedByPreprocessor = false; // Call list of strippers // Note that all strippers cumulate each other, so be aware of any conflict here foreach (BaseShaderPreprocessor shaderPreprocessor in shaderProcessorsList) { if (shaderPreprocessor.ShadersStripper(hdAsset, shader, snippet, input)) { strippedByPreprocessor = true; break; } } if (!strippedByPreprocessor) { removeInput = false; break; } } if (removeInput) { inputData[i] = inputData[--inputShaderVariantCount]; } else { ++i; } } if (inputData is List <ShaderCompilerData> inputDataList) { inputDataList.RemoveRange(inputShaderVariantCount, inputDataList.Count - inputShaderVariantCount); } else { for (int i = inputData.Count - 1; i >= inputShaderVariantCount; --i) { inputData.RemoveAt(i); } } if (HDRenderPipelineGlobalSettings.instance.shaderVariantLogLevel != ShaderVariantLogLevel.Disabled) { foreach (var hdAsset in hdPipelineAssets) { m_TotalVariantsInputCount += preStrippingCount; m_TotalVariantsOutputCount += (uint)inputData.Count; LogShaderVariants(shader, snippet, HDRenderPipelineGlobalSettings.instance.shaderVariantLogLevel, preStrippingCount, (uint)inputData.Count); } } } shaderStripingWatch.Stop(); shaderPreprocessed?.Invoke(shader, snippet, inputData.Count, shaderStripingWatch.Elapsed.TotalMilliseconds); }
protected override bool DoShadersStripper(HDRenderPipelineAsset hdrpAsset, Shader shader, ShaderSnippetData snippet, ShaderCompilerData inputData) { // CAUTION: Pass Name and Lightmode name must match in master node and .shader. // HDRP use LightMode to do drawRenderer and pass name is use here for stripping! var globalSettings = HDRenderPipelineGlobalSettings.Ensure(); // Remove editor only pass bool isSceneSelectionPass = snippet.passName == "SceneSelectionPass"; bool isScenePickingPass = snippet.passName == "ScenePickingPass"; bool metaPassUnused = (snippet.passName == "META") && (SupportedRenderingFeatures.active.enlighten == false || ((int)SupportedRenderingFeatures.active.lightmapBakeTypes | (int)LightmapBakeType.Realtime) == 0); bool editorVisualization = inputData.shaderKeywordSet.IsEnabled(m_EditorVisualization); if (isSceneSelectionPass || isScenePickingPass || metaPassUnused || editorVisualization) { return(true); } // CAUTION: We can't identify transparent material in the stripped in a general way. // Shader Graph don't produce any keyword - However it will only generate the pass that are required, so it already handle transparent (Note that shader Graph still define _SURFACE_TYPE_TRANSPARENT but as a #define) // For inspector version of shader, we identify transparent with a shader feature _SURFACE_TYPE_TRANSPARENT. // Only our Lit (and inherited) shader use _SURFACE_TYPE_TRANSPARENT, so the specific stripping based on this keyword is in LitShadePreprocessor. // Here we can't strip based on opaque or transparent but we will strip based on HDRP Asset configuration. bool isMotionPass = snippet.passName == "MotionVectors"; if (isMotionPass && !hdrpAsset.currentPlatformRenderPipelineSettings.supportMotionVectors) { return(true); } bool isDistortionPass = snippet.passName == "DistortionVectors"; if (isDistortionPass && !hdrpAsset.currentPlatformRenderPipelineSettings.supportDistortion) { return(true); } bool isTransparentBackface = snippet.passName == "TransparentBackface"; if (isTransparentBackface && !hdrpAsset.currentPlatformRenderPipelineSettings.supportTransparentBackface) { return(true); } bool isTransparentPrepass = snippet.passName == "TransparentDepthPrepass"; if (isTransparentPrepass && !hdrpAsset.currentPlatformRenderPipelineSettings.supportTransparentDepthPrepass) { return(true); } bool isTransparentPostpass = snippet.passName == "TransparentDepthPostpass"; if (isTransparentPostpass && !hdrpAsset.currentPlatformRenderPipelineSettings.supportTransparentDepthPostpass) { return(true); } bool isRayTracingPrepass = snippet.passName == "RayTracingPrepass"; if (isRayTracingPrepass && !hdrpAsset.currentPlatformRenderPipelineSettings.supportRayTracing) { return(true); } // If requested by the render pipeline settings, or if we are in a release build, // don't compile fullscreen debug display variant bool isFullScreenDebugPass = snippet.passName == "FullScreenDebug"; if (isFullScreenDebugPass && (!Debug.isDebugBuild || !globalSettings.supportRuntimeDebugDisplay)) { return(true); } // Debug Display shader is currently the longest shader to compile, so we allow users to disable it at runtime. // We also don't want it in release build. // However our AOV API rely on several debug display shader. In case AOV API is requested at runtime (like for the Graphics Compositor) // we allow user to make explicit request for it and it bypass other request if (!hdrpAsset.currentPlatformRenderPipelineSettings.supportRuntimeAOVAPI) { if ((!Debug.isDebugBuild || !globalSettings.supportRuntimeDebugDisplay) && inputData.shaderKeywordSet.IsEnabled(m_DebugDisplay)) { return(true); } } if (inputData.shaderKeywordSet.IsEnabled(m_LodFadeCrossFade) && !hdrpAsset.currentPlatformRenderPipelineSettings.supportDitheringCrossFade) { return(true); } if (inputData.shaderKeywordSet.IsEnabled(m_WriteMSAADepth) && (hdrpAsset.currentPlatformRenderPipelineSettings.supportedLitShaderMode == RenderPipelineSettings.SupportedLitShaderMode.DeferredOnly)) { return(true); } // Note that this is only going to affect the deferred shader and for a debug case, so it won't save much. if (inputData.shaderKeywordSet.IsEnabled(m_SubsurfaceScattering) && !hdrpAsset.currentPlatformRenderPipelineSettings.supportSubsurfaceScattering) { return(true); } if (inputData.shaderKeywordSet.IsEnabled(m_Transparent)) { // If transparent we don't need the depth only pass bool isDepthOnlyPass = snippet.passName == "DepthForwardOnly"; if (isDepthOnlyPass) { return(true); } // If transparent we don't need the motion vector pass if (isMotionPass) { return(true); } // If we are transparent we use cluster lighting and not tile lighting if (inputData.shaderKeywordSet.IsEnabled(m_TileLighting)) { return(true); } } else // Opaque { // If opaque, we never need transparent specific passes (even in forward only mode) bool isTransparentForwardPass = isTransparentPostpass || isTransparentBackface || isTransparentPrepass || isDistortionPass; if (isTransparentForwardPass) { return(true); } // TODO: Should we remove Cluster version if we know MSAA is disabled ? This prevent to manipulate LightLoop Settings (useFPTL option) // For now comment following code // if (inputData.shaderKeywordSet.IsEnabled(m_ClusterLighting) && !hdrpAsset.currentPlatformRenderPipelineSettings.supportMSAA) // return true; } // SHADOW // Strip every useless shadow configs var shadowInitParams = hdrpAsset.currentPlatformRenderPipelineSettings.hdShadowInitParams; foreach (var shadowVariant in m_ShadowKeywords.ShadowVariants) { if (shadowVariant.Key != shadowInitParams.shadowFilteringQuality) { if (inputData.shaderKeywordSet.IsEnabled(shadowVariant.Value)) { return(true); } } } // Screen space shadow variant is exclusive, either we have a variant with dynamic if that support screen space shadow or not // either we have a variant that don't support at all. We can't have both at the same time. if (inputData.shaderKeywordSet.IsEnabled(m_ScreenSpaceShadowOFFKeywords) && shadowInitParams.supportScreenSpaceShadows) { return(true); } if (inputData.shaderKeywordSet.IsEnabled(m_ScreenSpaceShadowONKeywords) && !shadowInitParams.supportScreenSpaceShadows) { return(true); } // DECAL // Strip the decal prepass variant when decals are disabled if (inputData.shaderKeywordSet.IsEnabled(m_WriteDecalBuffer) && !(hdrpAsset.currentPlatformRenderPipelineSettings.supportDecals && hdrpAsset.currentPlatformRenderPipelineSettings.supportDecalLayers)) { return(true); } // If decal support, remove unused variant if (hdrpAsset.currentPlatformRenderPipelineSettings.supportDecals) { // Remove the no decal case if (inputData.shaderKeywordSet.IsEnabled(m_DecalsOFF)) { return(true); } // If decal but with 4RT remove 3RT variant and vice versa for both Material and Decal Material if (inputData.shaderKeywordSet.IsEnabled(m_Decals3RT) && hdrpAsset.currentPlatformRenderPipelineSettings.decalSettings.perChannelMask) { return(true); } if (inputData.shaderKeywordSet.IsEnabled(m_Decals4RT) && !hdrpAsset.currentPlatformRenderPipelineSettings.decalSettings.perChannelMask) { return(true); } // Remove the surface gradient blending if not enabled if (inputData.shaderKeywordSet.IsEnabled(m_DecalSurfaceGradient) && !hdrpAsset.currentPlatformRenderPipelineSettings.supportSurfaceGradient) { return(true); } } else { // Strip if it is a decal pass bool isDBufferMesh = snippet.passName == "DBufferMesh"; bool isDecalMeshForwardEmissive = snippet.passName == "DecalMeshForwardEmissive"; bool isDBufferProjector = snippet.passName == "DBufferProjector"; bool isDecalProjectorForwardEmissive = snippet.passName == "DecalProjectorForwardEmissive"; if (isDBufferMesh || isDecalMeshForwardEmissive || isDBufferProjector || isDecalProjectorForwardEmissive) { return(true); } // If no decal support, remove decal variant if (inputData.shaderKeywordSet.IsEnabled(m_Decals3RT) || inputData.shaderKeywordSet.IsEnabled(m_Decals4RT)) { return(true); } // Remove the surface gradient blending if (inputData.shaderKeywordSet.IsEnabled(m_DecalSurfaceGradient)) { return(true); } } // Global Illumination if (inputData.shaderKeywordSet.IsEnabled(m_ProbeVolumesL1) && (!hdrpAsset.currentPlatformRenderPipelineSettings.supportProbeVolume || !globalSettings.supportProbeVolumes || hdrpAsset.currentPlatformRenderPipelineSettings.probeVolumeSHBands != ProbeVolumeSHBands.SphericalHarmonicsL1)) { return(true); } if (inputData.shaderKeywordSet.IsEnabled(m_ProbeVolumesL2) && (!hdrpAsset.currentPlatformRenderPipelineSettings.supportProbeVolume || !globalSettings.supportProbeVolumes || hdrpAsset.currentPlatformRenderPipelineSettings.probeVolumeSHBands != ProbeVolumeSHBands.SphericalHarmonicsL2)) { return(true); } return(false); }
// Modify this function to add more stripping clauses internal bool StripShader(HDRenderPipelineAsset hdAsset, ComputeShader shader, string kernelName, ShaderCompilerData inputData) { // Strip every useless shadow configs var shadowInitParams = hdAsset.currentPlatformRenderPipelineSettings.hdShadowInitParams; foreach (var shadowVariant in m_ShadowKeywords.ShadowVariants) { if (shadowVariant.Key != shadowInitParams.shadowFilteringQuality) { if (inputData.shaderKeywordSet.IsEnabled(shadowVariant.Value)) { return(true); } } } // Screen space shadow variant is exclusive, either we have a variant with dynamic if that support screen space shadow or not // either we have a variant that don't support at all. We can't have both at the same time. if (inputData.shaderKeywordSet.IsEnabled(m_ScreenSpaceShadowOFFKeywords) && shadowInitParams.supportScreenSpaceShadows) { return(true); } if (inputData.shaderKeywordSet.IsEnabled(m_MSAA) && (hdAsset.currentPlatformRenderPipelineSettings.supportedLitShaderMode == RenderPipelineSettings.SupportedLitShaderMode.DeferredOnly)) { return(true); } if (inputData.shaderKeywordSet.IsEnabled(m_ScreenSpaceShadowONKeywords) && !shadowInitParams.supportScreenSpaceShadows) { return(true); } if (inputData.shaderKeywordSet.IsEnabled(m_EnableAlpha) && !hdAsset.currentPlatformRenderPipelineSettings.SupportsAlpha()) { return(true); } // Global Illumination if (inputData.shaderKeywordSet.IsEnabled(m_ProbeVolumesL1) && (!hdAsset.currentPlatformRenderPipelineSettings.supportProbeVolume || hdAsset.currentPlatformRenderPipelineSettings.probeVolumeSHBands != ProbeVolumeSHBands.SphericalHarmonicsL1)) { return(true); } if (inputData.shaderKeywordSet.IsEnabled(m_ProbeVolumesL2) && (!hdAsset.currentPlatformRenderPipelineSettings.supportProbeVolume || hdAsset.currentPlatformRenderPipelineSettings.probeVolumeSHBands != ProbeVolumeSHBands.SphericalHarmonicsL2)) { return(true); } return(false); }
bool StripUnused(ShaderFeatures features, Shader shader, ShaderSnippetData snippetData, ShaderCompilerData compilerData) { if (StripUnusedFeatures(features, shader, snippetData, compilerData)) { return(true); } if (StripInvalidVariants(compilerData)) { return(true); } if (StripUnsupportedVariants(compilerData)) { return(true); } if (StripUnusedPass(features, snippetData)) { return(true); } // Strip terrain holes // TODO: checking for the string name here is expensive // maybe we can rename alpha clip keyword name to be specific to terrain? if (compilerData.shaderKeywordSet.IsEnabled(m_AlphaTestOn) && !IsFeatureEnabled(features, ShaderFeatures.TerrainHoles) && shader.name.Contains(kTerrainShaderName)) { return(true); } // TODO: Test against lightMode tag instead. if (snippetData.passName == kPassNameGBuffer) { if (!IsFeatureEnabled(features, ShaderFeatures.DeferredShading)) { return(true); } // Do not strip accurateGbufferNormals on Mobile Vulkan as some GPUs do not support R8G8B8A8_SNorm, which then force us to use accurateGbufferNormals if (!IsFeatureEnabled(features, ShaderFeatures.DeferredWithAccurateGbufferNormals) && compilerData.shaderKeywordSet.IsEnabled(m_GbufferNormalsOct) && compilerData.shaderCompilerPlatform != ShaderCompilerPlatform.Vulkan) { return(true); } if (!IsFeatureEnabled(features, ShaderFeatures.DeferredWithoutAccurateGbufferNormals) && !compilerData.shaderKeywordSet.IsEnabled(m_GbufferNormalsOct)) { return(true); } } return(false); }
public override bool ShadersStripper(HDRenderPipelineAsset hdrpAsset, Shader shader, ShaderSnippetData snippet, ShaderCompilerData inputData) { // Strip every useless shadow configs var shadowInitParams = hdrpAsset.renderPipelineSettings.hdShadowInitParams; foreach (var shadowVariant in m_ShadowVariants) { if (shadowVariant.Key != shadowInitParams.shadowQuality) { if (inputData.shaderKeywordSet.IsEnabled(shadowVariant.Value)) { return(true); } } } // CAUTION: Pass Name and Lightmode name must match in master node and .shader. // HDRP use LightMode to do drawRenderer and pass name is use here for stripping! // Remove editor only pass bool isSceneSelectionPass = snippet.passName == "SceneSelectionPass"; if (isSceneSelectionPass) { return(true); } // CAUTION: We can't identify transparent material in the stripped in a general way. // Shader Graph don't produce any keyword - However it will only generate the pass that are required, so it already handle transparent (Note that shader Graph still define _SURFACE_TYPE_TRANSPARENT but as a #define) // For inspector version of shader, we identify transparent with a shader feature _SURFACE_TYPE_TRANSPARENT. // Only our Lit (and inherited) shader use _SURFACE_TYPE_TRANSPARENT, so the specific stripping based on this keyword is in LitShadePreprocessor. // Here we can't strip based on opaque or transparent but we will strip based on HDRP Asset configuration. bool isMotionPass = snippet.passName == "MotionVectors"; bool isTransparentPrepass = snippet.passName == "TransparentDepthPrepass"; bool isTransparentPostpass = snippet.passName == "TransparentDepthPostpass"; bool isTransparentBackface = snippet.passName == "TransparentBackface"; bool isDistortionPass = snippet.passName == "DistortionVectors"; if (isMotionPass && !hdrpAsset.renderPipelineSettings.supportMotionVectors) { return(true); } if (isDistortionPass && !hdrpAsset.renderPipelineSettings.supportDistortion) { return(true); } if (isTransparentBackface && !hdrpAsset.renderPipelineSettings.supportTransparentBackface) { return(true); } if (isTransparentPrepass && !hdrpAsset.renderPipelineSettings.supportTransparentDepthPrepass) { return(true); } if (isTransparentPostpass && !hdrpAsset.renderPipelineSettings.supportTransparentDepthPostpass) { return(true); } // If we are in a release build, don't compile debug display variant // Also don't compile it if not requested by the render pipeline settings if ((/*!Debug.isDebugBuild || */ !hdrpAsset.renderPipelineSettings.supportRuntimeDebugDisplay) && inputData.shaderKeywordSet.IsEnabled(m_DebugDisplay)) { return(true); } if (inputData.shaderKeywordSet.IsEnabled(m_LodFadeCrossFade) && !hdrpAsset.renderPipelineSettings.supportDitheringCrossFade) { return(true); } if (inputData.shaderKeywordSet.IsEnabled(m_WriteMSAADepth) && !hdrpAsset.renderPipelineSettings.supportMSAA) { return(true); } // Note that this is only going to affect the deferred shader and for a debug case, so it won't save much. if (inputData.shaderKeywordSet.IsEnabled(m_SubsurfaceScattering) && !hdrpAsset.renderPipelineSettings.supportSubsurfaceScattering) { return(true); } // DECAL // Identify when we compile a decal shader bool isDecal3RTPass = false; bool isDecal4RTPass = false; bool isDecalPass = false; if (snippet.passName.Contains("DBufferMesh") || snippet.passName.Contains("DBufferProjector")) { isDecalPass = true; // All decal pass name: // "ShaderGraph_DBufferMesh3RT" "ShaderGraph_DBufferProjector3RT" "DBufferMesh_3RT" // "DBufferProjector_M" "DBufferProjector_AO" "DBufferProjector_MAO" "DBufferProjector_S" "DBufferProjector_MS" "DBufferProjector_AOS" "DBufferProjector_MAOS" // "DBufferMesh_M" "DBufferMesh_AO" "DBufferMesh_MAO" "DBufferMesh_S" "DBufferMesh_MS" "DBufferMesh_AOS""DBufferMesh_MAOS" // Caution: As mention in Decal.shader DBufferProjector_S is also DBufferProjector_3RT so this pass is both 4RT and 3RT // there is a multi-compile to handle this pass, so it will be correctly removed by testing m_Decals3RT or m_Decals4RT if (snippet.passName != "DBufferProjector_S") { isDecal3RTPass = snippet.passName.Contains("3RT"); isDecal4RTPass = !isDecal3RTPass; } } // If decal support, remove unused variant if (hdrpAsset.renderPipelineSettings.supportDecals) { // Remove the no decal case if (inputData.shaderKeywordSet.IsEnabled(m_DecalsOFF)) { return(true); } // If decal but with 4RT remove 3RT variant and vice versa if ((inputData.shaderKeywordSet.IsEnabled(m_Decals3RT) || isDecal3RTPass) && hdrpAsset.renderPipelineSettings.decalSettings.perChannelMask) { return(true); } if ((inputData.shaderKeywordSet.IsEnabled(m_Decals4RT) || isDecal4RTPass) && !hdrpAsset.renderPipelineSettings.decalSettings.perChannelMask) { return(true); } } else { if (isDecalPass) { return(true); } // If no decal support, remove decal variant if (inputData.shaderKeywordSet.IsEnabled(m_Decals3RT) || inputData.shaderKeywordSet.IsEnabled(m_Decals4RT)) { return(true); } } return(false); }
public void OnProcessShader(Shader shader, ShaderSnippetData snippet, IList <ShaderCompilerData> inputData) { // TODO: Grab correct configuration/quality asset. var hdPipelineAssets = ShaderBuildPreprocessor.hdrpAssets; if (hdPipelineAssets.Count == 0) { return; } uint preStrippingCount = (uint)inputData.Count; // Test if striping is enabled in any of the found HDRP assets. if (hdPipelineAssets.Count == 0 || !hdPipelineAssets.Any(a => a.allowShaderVariantStripping)) { return; } int inputShaderVariantCount = inputData.Count; for (int i = 0; i < inputShaderVariantCount;) { ShaderCompilerData input = inputData[i]; // Remove the input by default, until we find a HDRP Asset in the list that needs it. bool removeInput = true; foreach (var hdAsset in hdPipelineAssets) { var strippedByPreprocessor = false; // Call list of strippers // Note that all strippers cumulate each other, so be aware of any conflict here foreach (BaseShaderPreprocessor shaderPreprocessor in shaderProcessorsList) { if (shaderPreprocessor.ShadersStripper(hdAsset, shader, snippet, input)) { strippedByPreprocessor = true; break; } } if (!strippedByPreprocessor) { removeInput = false; break; } } if (removeInput) { inputData[i] = inputData[--inputShaderVariantCount]; } else { ++i; } } if (inputData is List <ShaderCompilerData> inputDataList) { inputDataList.RemoveRange(inputShaderVariantCount, inputDataList.Count - inputShaderVariantCount); } else { for (int i = inputData.Count - 1; i >= inputShaderVariantCount; --i) { inputData.RemoveAt(i); } } foreach (var hdAsset in hdPipelineAssets) { if (hdAsset.shaderVariantLogLevel != ShaderVariantLogLevel.Disabled) { m_TotalVariantsInputCount += preStrippingCount; m_TotalVariantsOutputCount += (uint)inputData.Count; LogShaderVariants(shader, snippet, hdAsset.shaderVariantLogLevel, preStrippingCount, (uint)inputData.Count); } } }
bool StripUnusedFeatures(ShaderFeatures features, Shader shader, ShaderSnippetData snippetData, ShaderCompilerData compilerData) { // strip main light shadows, cascade and screen variants if (!IsFeatureEnabled(features, ShaderFeatures.MainLightShadows)) { if (compilerData.shaderKeywordSet.IsEnabled(m_MainLightShadows)) { return(true); } if (compilerData.shaderKeywordSet.IsEnabled(m_MainLightShadowsCascades)) { return(true); } if (compilerData.shaderKeywordSet.IsEnabled(m_MainLightShadowsScreen)) { return(true); } if (snippetData.passType == PassType.ShadowCaster && !compilerData.shaderKeywordSet.IsEnabled(m_CastingPunctualLightShadow)) { return(true); } } if (!IsFeatureEnabled(features, ShaderFeatures.SoftShadows) && compilerData.shaderKeywordSet.IsEnabled(m_SoftShadows)) { return(true); } // Left for backward compatibility if (compilerData.shaderKeywordSet.IsEnabled(m_MixedLightingSubtractive) && !IsFeatureEnabled(features, ShaderFeatures.MixedLighting)) { return(true); } if (compilerData.shaderKeywordSet.IsEnabled(m_UseFastSRGBLinearConversion) && !IsFeatureEnabled(features, ShaderFeatures.UseFastSRGBLinearConversion)) { return(true); } // Strip here only if mixed lighting is disabled // No need to check here if actually used by scenes as this taken care by builtin stripper if ((compilerData.shaderKeywordSet.IsEnabled(m_LightmapShadowMixing) || compilerData.shaderKeywordSet.IsEnabled(m_ShadowsShadowMask)) && !IsFeatureEnabled(features, ShaderFeatures.MixedLighting)) { return(true); } if (compilerData.shaderKeywordSet.IsEnabled(m_LightLayers) && !IsFeatureEnabled(features, ShaderFeatures.LightLayers)) { return(true); } // No additional light shadows bool isAdditionalLightShadow = compilerData.shaderKeywordSet.IsEnabled(m_AdditionalLightShadows); if (!IsFeatureEnabled(features, ShaderFeatures.AdditionalLightShadows) && isAdditionalLightShadow) { return(true); } bool isPunctualLightShadowCasterPass = (snippetData.passType == PassType.ShadowCaster) && compilerData.shaderKeywordSet.IsEnabled(m_CastingPunctualLightShadow); if (!IsFeatureEnabled(features, ShaderFeatures.AdditionalLightShadows) && isPunctualLightShadowCasterPass) { return(true); } bool isDeferredShadow = compilerData.shaderKeywordSet.IsEnabled(m_DeferredLightShadows); if (!IsFeatureEnabled(features, ShaderFeatures.AdditionalLightShadows) && isDeferredShadow) { return(true); } // Additional light are shaded per-vertex or per-pixel. bool isFeaturePerPixelLightingEnabled = IsFeatureEnabled(features, ShaderFeatures.AdditionalLights); bool isFeaturePerVertexLightingEnabled = IsFeatureEnabled(features, ShaderFeatures.VertexLighting); bool isAdditionalLightPerPixel = compilerData.shaderKeywordSet.IsEnabled(m_AdditionalLightsPixel); bool isAdditionalLightPerVertex = compilerData.shaderKeywordSet.IsEnabled(m_AdditionalLightsVertex); // Strip if Per-Pixel lighting is NOT used in the project and the // Per-Pixel (_ADDITIONAL_LIGHTS) or additional shadows (_ADDITIONAL_LIGHT_SHADOWS) // variants are enabled in the shader. if (!isFeaturePerPixelLightingEnabled && (isAdditionalLightPerPixel || isAdditionalLightShadow)) { return(true); } // Strip if Per-Vertex lighting is NOT used in the project and the // Per-Vertex (_ADDITIONAL_LIGHTS_VERTEX) variant is enabled in the shader. if (!isFeaturePerVertexLightingEnabled && isAdditionalLightPerVertex) { return(true); } // Screen Space Shadows if (!IsFeatureEnabled(features, ShaderFeatures.ScreenSpaceShadows) && compilerData.shaderKeywordSet.IsEnabled(m_MainLightShadowsScreen)) { return(true); } // Screen Space Occlusion if (!IsFeatureEnabled(features, ShaderFeatures.ScreenSpaceOcclusion) && compilerData.shaderKeywordSet.IsEnabled(m_ScreenSpaceOcclusion)) { return(true); } return(false); }
public override bool ShadersStripper(HDRenderPipelineAsset hdrpAsset, Shader shader, ShaderSnippetData snippet, ShaderCompilerData inputData) { bool isGBufferPass = snippet.passName == "GBuffer"; //bool isForwardPass = snippet.passName == "Forward"; bool isDepthOnlyPass = snippet.passName == "DepthOnly"; bool isTransparentForwardPass = snippet.passName == "TransparentDepthPostpass" || snippet.passName == "TransparentBackface" || snippet.passName == "TransparentDepthPrepass"; // When using forward only, we never need GBuffer pass (only Forward) if (hdrpAsset.renderPipelineSettings.supportedLitShaderMode == RenderPipelineSettings.SupportedLitShaderMode.ForwardOnly && isGBufferPass) { return(true); } if (inputData.shaderKeywordSet.IsEnabled(m_Transparent)) { // If transparent, we never need GBuffer pass. if (isGBufferPass) { return(true); } } else // Opaque { // If opaque, we never need transparent specific passes (even in forward only mode) if (isTransparentForwardPass) { return(true); } // TODO: This check is disabled currently as it doesn't work. We have issue with lit VFX from VFX graph not working correctly, mean we are too agressive on // removal. Need to check why. // When we are in deferred (i.e !hdrpAsset.renderPipelineSettings.supportOnlyForward), we only support tile lighting //if (!hdrpAsset.renderPipelineSettings.supportOnlyForward && inputData.shaderKeywordSet.IsEnabled(m_ClusterLighting)) // return true; if (isDepthOnlyPass) { // When we are full forward, we don't have depth prepass without writeNormalBuffer if (hdrpAsset.renderPipelineSettings.supportedLitShaderMode == RenderPipelineSettings.SupportedLitShaderMode.ForwardOnly && !inputData.shaderKeywordSet.IsEnabled(m_WriteNormalBuffer)) { return(true); } } // TODO: add an option to say we are using only the deferred shader variant (for Lit) //if (0) { // If opaque and not forward only, then we only need the forward debug pass. //if (isForwardPass && !inputData.shaderKeywordSet.IsEnabled(m_DebugDisplay)) // return true; } } // TODO: Tests for later // We need to find a way to strip useless shader features for passes/shader stages that don't need them (example, vertex shaders won't ever need SSS Feature flag) // This causes several problems: // - Runtime code that "finds" shader variants based on feature flags might not find them anymore... thus fall backing to the "let's give a score to variant" code path that may find the wrong variant. // - Another issue is that if a feature is declared without a "_" fall-back, if we strip the other variants, none may be left to use! This needs to be changed on our side. //if (snippet.shaderType == ShaderType.Vertex && inputData.shaderKeywordSet.IsEnabled(m_FeatureSSS)) // return true; return(false); }
public override bool ShouldStripVariant(Shader shader, ShaderSnippetData snippet, ShaderCompilerData data) { var shaderPath = AssetDatabase.GetAssetPath(shader); return(paths.Any(x => x.IsMatch(shaderPath))); }
bool StripUnused(ShaderFeatures features, Shader shader, ShaderSnippetData snippetData, ShaderCompilerData compilerData) { if (StripUnusedShader(features, shader, compilerData)) { return(true); } if (StripUnusedPass(features, snippetData)) { return(true); } if (StripUnusedFeatures(features, shader, compilerData)) { return(true); } if (StripUnsupportedVariants(compilerData)) { return(true); } if (StripInvalidVariants(compilerData)) { return(true); } if (StripDeprecated(compilerData)) { return(true); } return(false); }
protected override bool DoShadersStripper(HDRenderPipelineAsset hdrpAsset, Shader shader, ShaderSnippetData snippet, ShaderCompilerData inputData) { // If ray tracing is disabled, strip all ray tracing shaders if (hdrpAsset.currentPlatformRenderPipelineSettings.supportRayTracing == false) { // If transparent we don't need the depth only pass if (snippet.passName == "IndirectDXR" || snippet.passName == "ForwardDXR" || snippet.passName == "VisibilityDXR" || snippet.passName == "PathTracingDXR" || snippet.passName == "GBufferDXR" || snippet.passName == "SubSurfaceDXR") { return(true); } } return(false); }
public void OnProcessComputeShader(ComputeShader shader, string kernelName, IList <ShaderCompilerData> inputData) { if (HDRenderPipeline.currentAsset == null) { return; } var exportLog = ShaderBuildPreprocessor.hdrpAssets.Count > 0 && ShaderBuildPreprocessor.hdrpAssets.Any(hdrpAsset => hdrpAsset.shaderVariantLogLevel != ShaderVariantLogLevel.Disabled); Stopwatch shaderStripingWatch = new Stopwatch(); shaderStripingWatch.Start(); using (new ExportComputeShaderStrip(exportLog, "Temp/compute-shader-strip.json", shader, kernelName, inputData, this)) { var inputShaderVariantCount = inputData.Count; var hdPipelineAssets = ShaderBuildPreprocessor.hdrpAssets; if (hdPipelineAssets.Count == 0) { return; } uint preStrippingCount = (uint)inputData.Count; for (int i = 0; i < inputShaderVariantCount;) { ShaderCompilerData input = inputData[i]; bool removeInput = true; foreach (var hdAsset in hdPipelineAssets) { if (!StripShader(hdAsset, shader, kernelName, input)) { removeInput = false; break; } } if (removeInput) { inputData[i] = inputData[--inputShaderVariantCount]; } else { ++i; } } if (inputData is List <ShaderCompilerData> inputDataList) { inputDataList.RemoveRange(inputShaderVariantCount, inputDataList.Count - inputShaderVariantCount); } else { for (int i = inputData.Count - 1; i >= inputShaderVariantCount; --i) { inputData.RemoveAt(i); } } foreach (var hdAsset in hdPipelineAssets) { if (hdAsset.shaderVariantLogLevel != ShaderVariantLogLevel.Disabled) { m_TotalVariantsInputCount += preStrippingCount; m_TotalVariantsOutputCount += (uint)inputData.Count; LogShaderVariants(shader, kernelName, hdAsset.shaderVariantLogLevel, preStrippingCount, (uint)inputData.Count); } } } }
bool StripUnusedFeatures(ShaderFeatures features, Shader shader, ShaderCompilerData compilerData) { // strip main light shadows and cascade variants if (!CoreUtils.HasFlag(features, ShaderFeatures.MainLightShadows)) { if (compilerData.shaderKeywordSet.IsEnabled(m_MainLightShadows)) { return(true); } if (compilerData.shaderKeywordSet.IsEnabled(m_CascadeShadows)) { return(true); } } bool isAdditionalLightPerVertex = compilerData.shaderKeywordSet.IsEnabled(m_AdditionalLightsVertex); bool isAdditionalLightPerPixel = compilerData.shaderKeywordSet.IsEnabled(m_AdditionalLightsPixel); bool isAdditionalLightShadow = compilerData.shaderKeywordSet.IsEnabled(m_AdditionalLightShadows); // Additional light are shaded per-vertex. Strip additional lights per-pixel and shadow variants if (CoreUtils.HasFlag(features, ShaderFeatures.VertexLighting) && (isAdditionalLightPerPixel || isAdditionalLightShadow)) { return(true); } // No additional lights if (!CoreUtils.HasFlag(features, ShaderFeatures.AdditionalLights) && (isAdditionalLightPerPixel || isAdditionalLightPerVertex || isAdditionalLightShadow)) { return(true); } // No additional light shadows if (!CoreUtils.HasFlag(features, ShaderFeatures.AdditionalLightShadows) && isAdditionalLightShadow) { return(true); } if (!CoreUtils.HasFlag(features, ShaderFeatures.SoftShadows) && compilerData.shaderKeywordSet.IsEnabled(m_SoftShadows)) { return(true); } if (compilerData.shaderKeywordSet.IsEnabled(m_MixedLightingSubtractive) && !CoreUtils.HasFlag(features, ShaderFeatures.MixedLighting)) { return(true); } bool isBuiltInTerrainLit = shader.name.Contains("Universal Render Pipeline/Terrain/Lit"); if (isBuiltInTerrainLit && compilerData.shaderKeywordSet.IsEnabled(m_AlphaTestOn) && !CoreUtils.HasFlag(features, ShaderFeatures.TerrainHoles)) { return(true); } return(false); }
public override bool ShouldStripVariant(Shader shader, ShaderSnippetData snippet, ShaderCompilerData data) { return(!ShouldIncludeVariant(shader, snippet, data)); }
public override bool ShadersStripper(HDRenderPipelineAsset hdrpAsset, Shader shader, ShaderSnippetData snippet, ShaderCompilerData inputData) { bool isGBufferPass = snippet.passName == "GBuffer"; bool isForwardPass = snippet.passName == "Forward"; bool isDepthOnlyPass = snippet.passName == "DepthOnly"; bool isTransparentPrepass = snippet.passName == "TransparentDepthPrepass"; bool isTransparentPostpass = snippet.passName == "TransparentDepthPostpass"; bool isTransparentBackface = snippet.passName == "TransparentBackface"; bool isDistortionPass = snippet.passName == "DistortionVectors"; bool isTransparentForwardPass = isTransparentPostpass || isTransparentBackface || isTransparentPrepass; // Using Contains to include the Tessellation variants bool isBuiltInLit = shader.name.Contains("HDRenderPipeline/Lit") && shader.name.Contains("HDRenderPipeline/LayeredLit") && shader.name.Contains("HDRenderPipeline/TerrainLit"); if (isDistortionPass && !hdrpAsset.renderPipelineSettings.supportDistortion) { return(true); } if (isTransparentBackface && !hdrpAsset.renderPipelineSettings.supportTransparentBackface) { return(true); } if (isTransparentPrepass && !hdrpAsset.renderPipelineSettings.supportTransparentDepthPrepass) { return(true); } if (isTransparentPostpass && !hdrpAsset.renderPipelineSettings.supportTransparentDepthPostpass) { return(true); } // When using forward only, we never need GBuffer pass (only Forward) if (hdrpAsset.renderPipelineSettings.supportedLitShaderMode == RenderPipelineSettings.SupportedLitShaderMode.ForwardOnly && isGBufferPass) { return(true); } if (isBuiltInLit) { if (inputData.shaderKeywordSet.IsEnabled(m_Transparent)) { // If transparent, we never need GBuffer pass. if (isGBufferPass) { return(true); } // If transparent we don't need the depth only pass if (isDepthOnlyPass) { return(true); } } else // Opaque { // If opaque, we never need transparent specific passes (even in forward only mode) if (isTransparentForwardPass) { return(true); } if (hdrpAsset.renderPipelineSettings.supportedLitShaderMode == RenderPipelineSettings.SupportedLitShaderMode.DeferredOnly) { // When we are in deferred, we only support tile lighting if (inputData.shaderKeywordSet.IsEnabled(m_ClusterLighting)) { return(true); } // If we use deferred only, MSAA is not supported. if (inputData.shaderKeywordSet.IsEnabled(m_WriteMSAADepth)) { return(true); } if (isForwardPass && !inputData.shaderKeywordSet.IsEnabled(m_DebugDisplay)) { return(true); } if (inputData.shaderKeywordSet.IsEnabled(m_WriteNormalBuffer)) { return(true); } } if (isDepthOnlyPass) { // When we are full forward, we don't have depth prepass without writeNormalBuffer if (hdrpAsset.renderPipelineSettings.supportedLitShaderMode == RenderPipelineSettings.SupportedLitShaderMode.ForwardOnly && !inputData.shaderKeywordSet.IsEnabled(m_WriteNormalBuffer)) { return(true); } } } } // TODO: Tests for later // We need to find a way to strip useless shader features for passes/shader stages that don't need them (example, vertex shaders won't ever need SSS Feature flag) // This causes several problems: // - Runtime code that "finds" shader variants based on feature flags might not find them anymore... thus fall backing to the "let's give a score to variant" code path that may find the wrong variant. // - Another issue is that if a feature is declared without a "_" fall-back, if we strip the other variants, none may be left to use! This needs to be changed on our side. //if (snippet.shaderType == ShaderType.Vertex && inputData.shaderKeywordSet.IsEnabled(m_FeatureSSS)) // return true; return(false); }
// NOTE: All these keyword should be automatically stripped so there's no need to handle them ourselves. // LIGHTMAP_ON, DIRLIGHTMAP_COMBINED, DYNAMICLIGHTMAP_ON, LIGHTMAP_SHADOW_MIXING, SHADOWS_SHADOWMASK // FOG_LINEAR, FOG_EXP, FOG_EXP2 // STEREO_INSTANCING_ON, STEREO_MULTIVIEW_ON, STEREO_CUBEMAP_RENDER_ON, UNITY_SINGLE_PASS_STEREO // INSTANCING_ON // Several pass are common to all shader, let's share code here // This remove variant (return true) for: // - Scene Selection // - Motion vectors // - Tile pass for Transparent (not compatible) // - protected bool CommonShaderStripper(HDRenderPipelineAsset hdrpAsset, Shader shader, ShaderSnippetData snippet, ShaderCompilerData inputData) { bool isSceneSelectionPass = snippet.passName == "SceneSelectionPass"; if (isSceneSelectionPass) { return(true); } bool isMotionPass = snippet.passName == "Motion Vectors"; if (!hdrpAsset.renderPipelineSettings.supportMotionVectors && isMotionPass) { return(true); } //bool isForwardPass = (snippet.passName == "Forward") || (snippet.passName == "ForwardOnly"); if (inputData.shaderKeywordSet.IsEnabled(m_Transparent)) { // If we are transparent we use cluster lighting and not tile lighting if (inputData.shaderKeywordSet.IsEnabled(m_TileLighting)) { return(true); } } else // Opaque { // Note: we can't assume anything regarding tile/cluster for opaque as multiple view could used different settings and it depends on MSAA } // TODO: If static lighting we can remove meta pass, but how to know that? // If we are in a release build, don't compile debug display variant // Also don't compile it if not requested by the render pipeline settings if ((/*!Debug.isDebugBuild || */ !hdrpAsset.renderPipelineSettings.supportRuntimeDebugDisplay) && inputData.shaderKeywordSet.IsEnabled(m_DebugDisplay)) { return(true); } if (inputData.shaderKeywordSet.IsEnabled(m_LodFadeCrossFade) && !hdrpAsset.renderPipelineSettings.supportDitheringCrossFade) { return(true); } return(false); }