ShaderPreprocessor.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. using System;
  2. using System.Collections.Generic;
  3. using UnityEditor;
  4. using UnityEditor.Build;
  5. using UnityEngine;
  6. using UnityEngine.Rendering.Universal;
  7. using UnityEngine.Rendering;
  8. namespace UnityEditor.Rendering.Universal
  9. {
  10. internal class ShaderPreprocessor : IPreprocessShaders
  11. {
  12. [Flags]
  13. enum ShaderFeatures
  14. {
  15. MainLight = (1 << 0),
  16. MainLightShadows = (1 << 1),
  17. AdditionalLights = (1 << 2),
  18. AdditionalLightShadows = (1 << 3),
  19. VertexLighting = (1 << 4),
  20. SoftShadows = (1 << 5),
  21. MixedLighting = (1 << 6),
  22. TerrainHoles = (1 << 7)
  23. }
  24. ShaderKeyword m_MainLightShadows = new ShaderKeyword(ShaderKeywordStrings.MainLightShadows);
  25. ShaderKeyword m_AdditionalLightsVertex = new ShaderKeyword(ShaderKeywordStrings.AdditionalLightsVertex);
  26. ShaderKeyword m_AdditionalLightsPixel = new ShaderKeyword(ShaderKeywordStrings.AdditionalLightsPixel);
  27. ShaderKeyword m_AdditionalLightShadows = new ShaderKeyword(ShaderKeywordStrings.AdditionalLightShadows);
  28. ShaderKeyword m_CascadeShadows = new ShaderKeyword(ShaderKeywordStrings.MainLightShadowCascades);
  29. ShaderKeyword m_SoftShadows = new ShaderKeyword(ShaderKeywordStrings.SoftShadows);
  30. ShaderKeyword m_MixedLightingSubtractive = new ShaderKeyword(ShaderKeywordStrings.MixedLightingSubtractive);
  31. ShaderKeyword m_Lightmap = new ShaderKeyword("LIGHTMAP_ON");
  32. ShaderKeyword m_DirectionalLightmap = new ShaderKeyword("DIRLIGHTMAP_COMBINED");
  33. ShaderKeyword m_AlphaTestOn = new ShaderKeyword("_ALPHATEST_ON");
  34. ShaderKeyword m_DeprecatedVertexLights = new ShaderKeyword("_VERTEX_LIGHTS");
  35. ShaderKeyword m_DeprecatedShadowsEnabled = new ShaderKeyword("_SHADOWS_ENABLED");
  36. ShaderKeyword m_DeprecatedShadowsCascade = new ShaderKeyword("_SHADOWS_CASCADE");
  37. ShaderKeyword m_DeprecatedLocalShadowsEnabled = new ShaderKeyword("_LOCAL_SHADOWS_ENABLED");
  38. int m_TotalVariantsInputCount;
  39. int m_TotalVariantsOutputCount;
  40. // Multiple callback may be implemented.
  41. // The first one executed is the one where callbackOrder is returning the smallest number.
  42. public int callbackOrder { get { return 0; } }
  43. bool StripUnusedShader(ShaderFeatures features, Shader shader, ShaderCompilerData compilerData)
  44. {
  45. if (!CoreUtils.HasFlag(features, ShaderFeatures.MainLightShadows) &&
  46. shader.name.Contains("ScreenSpaceShadows"))
  47. return true;
  48. return false;
  49. }
  50. bool StripUnusedPass(ShaderFeatures features, ShaderSnippetData snippetData)
  51. {
  52. if (snippetData.passType == PassType.Meta)
  53. return true;
  54. if (snippetData.passType == PassType.ShadowCaster)
  55. if (!CoreUtils.HasFlag(features, ShaderFeatures.MainLightShadows) && !CoreUtils.HasFlag(features, ShaderFeatures.AdditionalLightShadows))
  56. return true;
  57. return false;
  58. }
  59. bool StripUnusedFeatures(ShaderFeatures features, Shader shader, ShaderCompilerData compilerData)
  60. {
  61. // strip main light shadows and cascade variants
  62. if (!CoreUtils.HasFlag(features, ShaderFeatures.MainLightShadows))
  63. {
  64. if (compilerData.shaderKeywordSet.IsEnabled(m_MainLightShadows))
  65. return true;
  66. if (compilerData.shaderKeywordSet.IsEnabled(m_CascadeShadows))
  67. return true;
  68. }
  69. bool isAdditionalLightPerVertex = compilerData.shaderKeywordSet.IsEnabled(m_AdditionalLightsVertex);
  70. bool isAdditionalLightPerPixel = compilerData.shaderKeywordSet.IsEnabled(m_AdditionalLightsPixel);
  71. bool isAdditionalLightShadow = compilerData.shaderKeywordSet.IsEnabled(m_AdditionalLightShadows);
  72. // Additional light are shaded per-vertex. Strip additional lights per-pixel and shadow variants
  73. if (CoreUtils.HasFlag(features, ShaderFeatures.VertexLighting) &&
  74. (isAdditionalLightPerPixel || isAdditionalLightShadow))
  75. return true;
  76. // No additional lights
  77. if (!CoreUtils.HasFlag(features, ShaderFeatures.AdditionalLights) &&
  78. (isAdditionalLightPerPixel || isAdditionalLightPerVertex || isAdditionalLightShadow))
  79. return true;
  80. // No additional light shadows
  81. if (!CoreUtils.HasFlag(features, ShaderFeatures.AdditionalLightShadows) && isAdditionalLightShadow)
  82. return true;
  83. if (!CoreUtils.HasFlag(features, ShaderFeatures.SoftShadows) &&
  84. compilerData.shaderKeywordSet.IsEnabled(m_SoftShadows))
  85. return true;
  86. if (compilerData.shaderKeywordSet.IsEnabled(m_MixedLightingSubtractive) &&
  87. !CoreUtils.HasFlag(features, ShaderFeatures.MixedLighting))
  88. return true;
  89. bool isBuiltInTerrainLit = shader.name.Contains("Universal Render Pipeline/Terrain/Lit");
  90. if (isBuiltInTerrainLit && compilerData.shaderKeywordSet.IsEnabled(m_AlphaTestOn) &&
  91. !CoreUtils.HasFlag(features, ShaderFeatures.TerrainHoles))
  92. return true;
  93. return false;
  94. }
  95. bool StripUnsupportedVariants(ShaderCompilerData compilerData)
  96. {
  97. // Dynamic GI is not supported so we can strip variants that have directional lightmap
  98. // enabled but not baked lightmap.
  99. if (compilerData.shaderKeywordSet.IsEnabled(m_DirectionalLightmap) &&
  100. !compilerData.shaderKeywordSet.IsEnabled(m_Lightmap))
  101. return true;
  102. if (compilerData.shaderCompilerPlatform == ShaderCompilerPlatform.GLES20)
  103. {
  104. if (compilerData.shaderKeywordSet.IsEnabled(m_CascadeShadows))
  105. return true;
  106. }
  107. return false;
  108. }
  109. bool StripInvalidVariants(ShaderCompilerData compilerData)
  110. {
  111. bool isMainShadow = compilerData.shaderKeywordSet.IsEnabled(m_MainLightShadows);
  112. bool isAdditionalShadow = compilerData.shaderKeywordSet.IsEnabled(m_AdditionalLightShadows);
  113. bool isShadowVariant = isMainShadow || isAdditionalShadow;
  114. if (!isMainShadow && compilerData.shaderKeywordSet.IsEnabled(m_CascadeShadows))
  115. return true;
  116. if (!isShadowVariant && compilerData.shaderKeywordSet.IsEnabled(m_SoftShadows))
  117. return true;
  118. if (isAdditionalShadow && !compilerData.shaderKeywordSet.IsEnabled(m_AdditionalLightsPixel))
  119. return true;
  120. return false;
  121. }
  122. bool StripDeprecated(ShaderCompilerData compilerData)
  123. {
  124. if (compilerData.shaderKeywordSet.IsEnabled(m_DeprecatedVertexLights))
  125. return true;
  126. if (compilerData.shaderKeywordSet.IsEnabled(m_DeprecatedShadowsCascade))
  127. return true;
  128. if (compilerData.shaderKeywordSet.IsEnabled(m_DeprecatedShadowsEnabled))
  129. return true;
  130. if (compilerData.shaderKeywordSet.IsEnabled(m_DeprecatedLocalShadowsEnabled))
  131. return true;
  132. return false;
  133. }
  134. bool StripUnused(ShaderFeatures features, Shader shader, ShaderSnippetData snippetData, ShaderCompilerData compilerData)
  135. {
  136. if (StripUnusedShader(features, shader, compilerData))
  137. return true;
  138. if (StripUnusedPass(features, snippetData))
  139. return true;
  140. if (StripUnusedFeatures(features, shader, compilerData))
  141. return true;
  142. if (StripUnsupportedVariants(compilerData))
  143. return true;
  144. if (StripInvalidVariants(compilerData))
  145. return true;
  146. if (StripDeprecated(compilerData))
  147. return true;
  148. return false;
  149. }
  150. void LogShaderVariants(Shader shader, ShaderSnippetData snippetData, ShaderVariantLogLevel logLevel, int prevVariantsCount, int currVariantsCount)
  151. {
  152. if (logLevel == ShaderVariantLogLevel.AllShaders || shader.name.Contains("Universal Render Pipeline"))
  153. {
  154. float percentageCurrent = (float)currVariantsCount / (float)prevVariantsCount * 100f;
  155. float percentageTotal = (float)m_TotalVariantsOutputCount / (float)m_TotalVariantsInputCount * 100f;
  156. string result = string.Format("STRIPPING: {0} ({1} pass) ({2}) -" +
  157. " Remaining shader variants = {3}/{4} = {5}% - Total = {6}/{7} = {8}%",
  158. shader.name, snippetData.passName, snippetData.shaderType.ToString(), currVariantsCount,
  159. prevVariantsCount, percentageCurrent, m_TotalVariantsOutputCount, m_TotalVariantsInputCount,
  160. percentageTotal);
  161. Debug.Log(result);
  162. }
  163. }
  164. public void OnProcessShader(Shader shader, ShaderSnippetData snippetData, IList<ShaderCompilerData> compilerDataList)
  165. {
  166. UniversalRenderPipelineAsset urpAsset = GraphicsSettings.renderPipelineAsset as UniversalRenderPipelineAsset;
  167. if (urpAsset == null || compilerDataList == null || compilerDataList.Count == 0)
  168. return;
  169. ShaderFeatures features = GetSupportedShaderFeatures(urpAsset);
  170. int prevVariantCount = compilerDataList.Count;
  171. for (int i = 0; i < compilerDataList.Count; ++i)
  172. {
  173. if (StripUnused(features, shader, snippetData, compilerDataList[i]))
  174. {
  175. compilerDataList.RemoveAt(i);
  176. --i;
  177. }
  178. }
  179. if (urpAsset.shaderVariantLogLevel != ShaderVariantLogLevel.Disabled)
  180. {
  181. m_TotalVariantsInputCount += prevVariantCount;
  182. m_TotalVariantsOutputCount += compilerDataList.Count;
  183. LogShaderVariants(shader, snippetData, urpAsset.shaderVariantLogLevel, prevVariantCount, compilerDataList.Count);
  184. }
  185. }
  186. ShaderFeatures GetSupportedShaderFeatures(UniversalRenderPipelineAsset pipelineAsset)
  187. {
  188. ShaderFeatures shaderFeatures;
  189. shaderFeatures = ShaderFeatures.MainLight;
  190. if (pipelineAsset.supportsMainLightShadows)
  191. shaderFeatures |= ShaderFeatures.MainLightShadows;
  192. if (pipelineAsset.additionalLightsRenderingMode == LightRenderingMode.PerVertex)
  193. {
  194. shaderFeatures |= ShaderFeatures.AdditionalLights;
  195. shaderFeatures |= ShaderFeatures.VertexLighting;
  196. }
  197. else if (pipelineAsset.additionalLightsRenderingMode == LightRenderingMode.PerPixel)
  198. {
  199. shaderFeatures |= ShaderFeatures.AdditionalLights;
  200. if (pipelineAsset.supportsAdditionalLightShadows)
  201. shaderFeatures |= ShaderFeatures.AdditionalLightShadows;
  202. }
  203. bool anyShadows = pipelineAsset.supportsMainLightShadows ||
  204. CoreUtils.HasFlag(shaderFeatures, ShaderFeatures.AdditionalLightShadows);
  205. if (pipelineAsset.supportsSoftShadows && anyShadows)
  206. shaderFeatures |= ShaderFeatures.SoftShadows;
  207. if (pipelineAsset.supportsMixedLighting)
  208. shaderFeatures |= ShaderFeatures.MixedLighting;
  209. if (pipelineAsset.supportsTerrainHoles)
  210. shaderFeatures |= ShaderFeatures.TerrainHoles;
  211. return shaderFeatures;
  212. }
  213. }
  214. }