From e44aea2e677f6068168dfd8ac119bd96ba0a5f76 Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Mon, 15 Jun 2020 17:28:37 +0200 Subject: [PATCH 1/2] Compute shader stripping --- .../BuildProcessors/HDRPPreprocessShaders.cs | 179 +++++++++++++++++- .../Editor/Material/BaseShaderPreprocessor.cs | 35 +++- 2 files changed, 201 insertions(+), 13 deletions(-) diff --git a/com.unity.render-pipelines.high-definition/Editor/BuildProcessors/HDRPPreprocessShaders.cs b/com.unity.render-pipelines.high-definition/Editor/BuildProcessors/HDRPPreprocessShaders.cs index fe902196883..846edf391b5 100644 --- a/com.unity.render-pipelines.high-definition/Editor/BuildProcessors/HDRPPreprocessShaders.cs +++ b/com.unity.render-pipelines.high-definition/Editor/BuildProcessors/HDRPPreprocessShaders.cs @@ -19,12 +19,10 @@ public CommonShaderPreprocessor() { } protected override bool DoShadersStripper(HDRenderPipelineAsset hdrpAsset, Shader shader, ShaderSnippetData snippet, ShaderCompilerData inputData) { - // TODO: We need to perform compute shader stripping as soon as it is possible. Most egregious case would be the shadow filtering quality for Deferred.compute - // Strip every useless shadow configs var shadowInitParams = hdrpAsset.currentPlatformRenderPipelineSettings.hdShadowInitParams; - foreach (var shadowVariant in m_ShadowVariants) + foreach (var shadowVariant in m_ShadowKeywords.ShadowVariants) { if (shadowVariant.Key != shadowInitParams.shadowFilteringQuality) if (inputData.shaderKeywordSet.IsEnabled(shadowVariant.Value)) @@ -136,6 +134,181 @@ protected override bool DoShadersStripper(HDRenderPipelineAsset hdrpAsset, Shade } } + class HDRPPreprocessComputeShaders : IPreprocessComputeShaders + { + struct ExportComputeShaderStrip : System.IDisposable + { + bool m_ExportLog; + string m_OutFile; + ComputeShader m_Shader; + string m_KernelName; + IList m_InputData; + HDRPPreprocessComputeShaders m_PreProcess; + + public ExportComputeShaderStrip( + bool exportLog, + string outFile, + ComputeShader shader, + string kernelName, + IList inputData, + HDRPPreprocessComputeShaders preProcess + ) + { + m_ExportLog = exportLog; + m_OutFile = outFile; + m_Shader = shader; + m_KernelName = kernelName; + m_InputData = inputData; + m_PreProcess = preProcess; + + if (m_ExportLog) + { + System.IO.File.AppendAllText( + m_OutFile, + $"{{ \"Compute shader\": \"{m_Shader.name}\", \"kernel\": \"{m_KernelName}\", \"variantIn\": {m_InputData.Count} }}\r\n" + ); + } + } + + public void Dispose() + { + if (m_ExportLog) + { + try + { + System.IO.File.AppendAllText( + m_OutFile, + $"{{ \"shader\": \"{m_Shader?.name}\", \"kernel\": \"{m_KernelName}\", \"variantOut\": \"{m_InputData.Count}\", \"totalVariantIn\": \"{m_PreProcess?.m_TotalVariantsInputCount}\", \"totalVariantOut\": \"{m_PreProcess?.m_TotalVariantsOutputCount}\" }}\r\n" + ); + } + catch (System.Exception e) + { + Debug.LogException(e); + } + } + } + } + + uint m_TotalVariantsInputCount; + uint m_TotalVariantsOutputCount; + + protected ShadowKeywords m_ShadowKeywords = new ShadowKeywords(); + protected ShaderKeyword m_EnableAlpha = new ShaderKeyword("ENABLE_ALPHA"); + protected ShaderKeyword m_MSAA = new ShaderKeyword("ENABLE_MSAA"); + + public int callbackOrder { get { return 0; } } + + void LogShaderVariants(ComputeShader shader, string kernelName, ShaderVariantLogLevel logLevel, uint prevVariantsCount, uint currVariantsCount) + { + // We cannot yet differentiate whether a compute shader is HDRP specific or not. + if (logLevel == ShaderVariantLogLevel.AllShaders || logLevel == ShaderVariantLogLevel.OnlyHDRPShaders) + { + float percentageCurrent = ((float)currVariantsCount / prevVariantsCount) * 100.0f; + float percentageTotal = ((float)m_TotalVariantsOutputCount / m_TotalVariantsInputCount) * 100.0f; + + string result = string.Format("STRIPPING: {0} (kernel: {1}) -" + + " Remaining shader variants = {2}/{3} = {4}% - Total = {5}/{6} = {7}%", + shader.name, kernelName, currVariantsCount, + prevVariantsCount, percentageCurrent, m_TotalVariantsOutputCount, m_TotalVariantsInputCount, + percentageTotal); + Debug.Log(result); + } + } + + // 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; + } + } + } + + if(inputData.shaderKeywordSet.IsEnabled(m_MSAA) && !hdAsset.currentPlatformRenderPipelineSettings.supportMSAA) + { + return true; + } + + if(inputData.shaderKeywordSet.IsEnabled(m_EnableAlpha) && !hdAsset.currentPlatformRenderPipelineSettings.supportsAlpha) + { + return true; + } + + return false; + } + + public void OnProcessComputeShader(ComputeShader shader, string kernelName, IList 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 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); + } + } + } + } + } + class HDRPreprocessShaders : IPreprocessShaders { // Track list of materials asking for specific preprocessor step diff --git a/com.unity.render-pipelines.high-definition/Editor/Material/BaseShaderPreprocessor.cs b/com.unity.render-pipelines.high-definition/Editor/Material/BaseShaderPreprocessor.cs index 295fa305453..c3051691685 100644 --- a/com.unity.render-pipelines.high-definition/Editor/Material/BaseShaderPreprocessor.cs +++ b/com.unity.render-pipelines.high-definition/Editor/Material/BaseShaderPreprocessor.cs @@ -7,6 +7,29 @@ namespace UnityEditor.Rendering.HighDefinition { + internal class ShadowKeywords + { + ShaderKeyword ShadowLow; + ShaderKeyword ShadowMedium; + ShaderKeyword ShadowHigh; + + public Dictionary ShadowVariants; + + public ShadowKeywords() + { + ShadowLow = new ShaderKeyword("SHADOW_LOW"); + ShadowMedium = new ShaderKeyword("SHADOW_MEDIUM"); + ShadowHigh = new ShaderKeyword("SHADOW_HIGH"); + + ShadowVariants = new Dictionary + { + {HDShadowFilteringQuality.Low, ShadowLow}, + {HDShadowFilteringQuality.Medium, ShadowMedium}, + {HDShadowFilteringQuality.High, ShadowHigh}, + }; + } + } + abstract class BaseShaderPreprocessor { // Common keyword list @@ -26,6 +49,7 @@ abstract class BaseShaderPreprocessor protected ShaderKeyword m_WriteNormalBuffer; protected ShaderKeyword m_WriteMSAADepth; protected ShaderKeyword m_SubsurfaceScattering; + protected ShadowKeywords m_ShadowKeywords; protected Dictionary m_ShadowVariants; @@ -48,19 +72,10 @@ public BaseShaderPreprocessor() m_Decals3RT = new ShaderKeyword("DECALS_3RT"); m_Decals4RT = new ShaderKeyword("DECALS_4RT"); m_LightLayers = new ShaderKeyword("LIGHT_LAYERS"); - m_ShadowLow = new ShaderKeyword("SHADOW_LOW"); - m_ShadowMedium = new ShaderKeyword("SHADOW_MEDIUM"); - m_ShadowHigh = new ShaderKeyword("SHADOW_HIGH"); m_WriteNormalBuffer = new ShaderKeyword("WRITE_NORMAL_BUFFER"); m_WriteMSAADepth = new ShaderKeyword("WRITE_MSAA_DEPTH"); m_SubsurfaceScattering = new ShaderKeyword("OUTPUT_SPLIT_LIGHTING"); - - m_ShadowVariants = new Dictionary - { - {HDShadowFilteringQuality.Low, m_ShadowLow}, - {HDShadowFilteringQuality.Medium, m_ShadowMedium}, - {HDShadowFilteringQuality.High, m_ShadowHigh}, - }; + m_ShadowKeywords = new ShadowKeywords(); } public bool ShadersStripper(HDRenderPipelineAsset hdrpAsset, Shader shader, ShaderSnippetData snippet, From 2a9b862c0a449778da5344aaba86f38bc18119ef Mon Sep 17 00:00:00 2001 From: FrancescoC-Unity Date: Mon, 15 Jun 2020 18:05:12 +0200 Subject: [PATCH 2/2] changelog --- com.unity.render-pipelines.high-definition/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/com.unity.render-pipelines.high-definition/CHANGELOG.md b/com.unity.render-pipelines.high-definition/CHANGELOG.md index 6e5014a17a9..26c32b1d50e 100644 --- a/com.unity.render-pipelines.high-definition/CHANGELOG.md +++ b/com.unity.render-pipelines.high-definition/CHANGELOG.md @@ -148,6 +148,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - Added support to combine RTSSS and RTGI (1248733). - Added IES Profile support for Point, Spot and Rectangular-Area lights - Added support for multiple mapping modes in AxF. +- Added compute shader stripping. ### Fixed - Fix when rescale probe all direction below zero (1219246)