490 lines
23 KiB
C#
490 lines
23 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using UnityEditor;
|
|
using UnityEditor.Build;
|
|
using UnityEditor.Build.Reporting;
|
|
using UnityEngine;
|
|
using UnityEngine.Profiling;
|
|
using UnityEngine.Rendering.Universal;
|
|
using UnityEngine.Rendering;
|
|
|
|
namespace UnityEditor.Rendering.Universal
|
|
{
|
|
[Flags]
|
|
enum ShaderFeatures
|
|
{
|
|
MainLight = (1 << 0),
|
|
MainLightShadows = (1 << 1),
|
|
AdditionalLights = (1 << 2),
|
|
AdditionalLightShadows = (1 << 3),
|
|
VertexLighting = (1 << 4),
|
|
SoftShadows = (1 << 5),
|
|
MixedLighting = (1 << 6),
|
|
TerrainHoles = (1 << 7),
|
|
DeferredShading = (1 << 8), // DeferredRenderer is in the list of renderer
|
|
DeferredWithAccurateGbufferNormals = (1 << 9),
|
|
DeferredWithoutAccurateGbufferNormals = (1 << 10),
|
|
ScreenSpaceOcclusion = (1 << 11),
|
|
ScreenSpaceShadows = (1 << 12),
|
|
UseFastSRGBLinearConversion = (1 << 13)
|
|
}
|
|
|
|
internal class ShaderPreprocessor : IPreprocessShaders
|
|
{
|
|
public static readonly string kPassNameGBuffer = "GBuffer";
|
|
public static readonly string kTerrainShaderName = "Universal Render Pipeline/Terrain/Lit";
|
|
#if PROFILE_BUILD
|
|
private const string k_ProcessShaderTag = "OnProcessShader";
|
|
#endif
|
|
// Event callback to report shader stripping info. Form:
|
|
// ReportShaderStrippingData(Shader shader, ShaderSnippetData data, int currentVariantCount, double strippingTime)
|
|
internal static event Action<Shader, ShaderSnippetData, int, double> shaderPreprocessed;
|
|
private static readonly System.Diagnostics.Stopwatch m_stripTimer = new System.Diagnostics.Stopwatch();
|
|
|
|
ShaderKeyword m_MainLightShadows = new ShaderKeyword(ShaderKeywordStrings.MainLightShadows);
|
|
ShaderKeyword m_MainLightShadowsCascades = new ShaderKeyword(ShaderKeywordStrings.MainLightShadowCascades);
|
|
ShaderKeyword m_MainLightShadowsScreen = new ShaderKeyword(ShaderKeywordStrings.MainLightShadowScreen);
|
|
ShaderKeyword m_AdditionalLightsVertex = new ShaderKeyword(ShaderKeywordStrings.AdditionalLightsVertex);
|
|
ShaderKeyword m_AdditionalLightsPixel = new ShaderKeyword(ShaderKeywordStrings.AdditionalLightsPixel);
|
|
ShaderKeyword m_AdditionalLightShadows = new ShaderKeyword(ShaderKeywordStrings.AdditionalLightShadows);
|
|
ShaderKeyword m_DeferredAdditionalLightShadows = new ShaderKeyword(ShaderKeywordStrings._DEFERRED_ADDITIONAL_LIGHT_SHADOWS);
|
|
ShaderKeyword m_CastingPunctualLightShadow = new ShaderKeyword(ShaderKeywordStrings.CastingPunctualLightShadow);
|
|
ShaderKeyword m_SoftShadows = new ShaderKeyword(ShaderKeywordStrings.SoftShadows);
|
|
ShaderKeyword m_MixedLightingSubtractive = new ShaderKeyword(ShaderKeywordStrings.MixedLightingSubtractive);
|
|
ShaderKeyword m_LightmapShadowMixing = new ShaderKeyword(ShaderKeywordStrings.LightmapShadowMixing);
|
|
ShaderKeyword m_ShadowsShadowMask = new ShaderKeyword(ShaderKeywordStrings.ShadowsShadowMask);
|
|
ShaderKeyword m_Lightmap = new ShaderKeyword(ShaderKeywordStrings.LIGHTMAP_ON);
|
|
ShaderKeyword m_DirectionalLightmap = new ShaderKeyword(ShaderKeywordStrings.DIRLIGHTMAP_COMBINED);
|
|
ShaderKeyword m_AlphaTestOn = new ShaderKeyword(ShaderKeywordStrings._ALPHATEST_ON);
|
|
ShaderKeyword m_GbufferNormalsOct = new ShaderKeyword(ShaderKeywordStrings._GBUFFER_NORMALS_OCT);
|
|
ShaderKeyword m_UseDrawProcedural = new ShaderKeyword(ShaderKeywordStrings.UseDrawProcedural);
|
|
ShaderKeyword m_ScreenSpaceOcclusion = new ShaderKeyword(ShaderKeywordStrings.ScreenSpaceOcclusion);
|
|
ShaderKeyword m_UseFastSRGBLinearConversion = new ShaderKeyword(ShaderKeywordStrings.UseFastSRGBLinearConversion);
|
|
|
|
ShaderKeyword m_LocalDetailMulx2;
|
|
ShaderKeyword m_LocalDetailScaled;
|
|
ShaderKeyword m_LocalClearCoat;
|
|
ShaderKeyword m_LocalClearCoatMap;
|
|
|
|
int m_TotalVariantsInputCount;
|
|
int m_TotalVariantsOutputCount;
|
|
|
|
// Multiple callback may be implemented.
|
|
// The first one executed is the one where callbackOrder is returning the smallest number.
|
|
public int callbackOrder { get { return 0; } }
|
|
|
|
void InitializeLocalShaderKeywords(Shader shader)
|
|
{
|
|
m_LocalDetailMulx2 = new ShaderKeyword(shader, ShaderKeywordStrings._DETAIL_MULX2);
|
|
m_LocalDetailScaled = new ShaderKeyword(shader, ShaderKeywordStrings._DETAIL_SCALED);
|
|
m_LocalClearCoat = new ShaderKeyword(shader, ShaderKeywordStrings._CLEARCOAT);
|
|
m_LocalClearCoatMap = new ShaderKeyword(shader, ShaderKeywordStrings._CLEARCOATMAP);
|
|
}
|
|
|
|
bool IsFeatureEnabled(ShaderFeatures featureMask, ShaderFeatures feature)
|
|
{
|
|
return (featureMask & feature) != 0;
|
|
}
|
|
|
|
bool StripUnusedPass(ShaderFeatures features, ShaderSnippetData snippetData)
|
|
{
|
|
if (snippetData.passType == PassType.Meta)
|
|
return true;
|
|
|
|
if (snippetData.passType == PassType.ShadowCaster)
|
|
if (!IsFeatureEnabled(features, ShaderFeatures.MainLightShadows) && !IsFeatureEnabled(features, ShaderFeatures.AdditionalLightShadows))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
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;
|
|
|
|
|
|
// 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)
|
|
if (compilerData.shaderCompilerPlatform != ShaderCompilerPlatform.GLES3x) // [Work-around] We do not strip this variant on GLES3 because it could make some scenes crash current Unity GLES3 AndroidPlayer on OnePlus6T - TODO: remove this line once https://issuetracker.unity3d.com/product/unity/issues/guid/1293454/ is fixed
|
|
return true;
|
|
|
|
bool isDeferredAdditionalShadow = compilerData.shaderKeywordSet.IsEnabled(m_DeferredAdditionalLightShadows);
|
|
if (!IsFeatureEnabled(features, ShaderFeatures.AdditionalLightShadows) && isDeferredAdditionalShadow)
|
|
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;
|
|
}
|
|
|
|
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_MainLightShadowsCascades))
|
|
return true;
|
|
|
|
// Screen space shadows
|
|
if (compilerData.shaderKeywordSet.IsEnabled(m_MainLightShadowsScreen))
|
|
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;
|
|
}
|
|
|
|
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))
|
|
return true;
|
|
|
|
bool isDeferredAdditionalShadow = compilerData.shaderKeywordSet.IsEnabled(m_DeferredAdditionalLightShadows);
|
|
if (isDeferredAdditionalShadow && !compilerData.shaderKeywordSet.IsEnabled(m_AdditionalLightsPixel))
|
|
return true;
|
|
|
|
bool isShadowVariant = isMainShadow || isAdditionalShadow || isDeferredAdditionalShadow;
|
|
if (!isShadowVariant && compilerData.shaderKeywordSet.IsEnabled(m_SoftShadows))
|
|
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;
|
|
if (IsFeatureEnabled(features, ShaderFeatures.DeferredWithAccurateGbufferNormals) && !compilerData.shaderKeywordSet.IsEnabled(m_GbufferNormalsOct))
|
|
return true;
|
|
if (IsFeatureEnabled(features, ShaderFeatures.DeferredWithoutAccurateGbufferNormals) && compilerData.shaderKeywordSet.IsEnabled(m_GbufferNormalsOct))
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void LogShaderVariants(Shader shader, ShaderSnippetData snippetData, ShaderVariantLogLevel logLevel, int prevVariantsCount, int currVariantsCount)
|
|
{
|
|
if (logLevel == ShaderVariantLogLevel.AllShaders || shader.name.Contains("Universal Render Pipeline"))
|
|
{
|
|
float percentageCurrent = (float)currVariantsCount / (float)prevVariantsCount * 100f;
|
|
float percentageTotal = (float)m_TotalVariantsOutputCount / (float)m_TotalVariantsInputCount * 100f;
|
|
|
|
string result = string.Format("STRIPPING: {0} ({1} pass) ({2}) -" +
|
|
" Remaining shader variants = {3}/{4} = {5}% - Total = {6}/{7} = {8}%",
|
|
shader.name, snippetData.passName, snippetData.shaderType.ToString(), currVariantsCount,
|
|
prevVariantsCount, percentageCurrent, m_TotalVariantsOutputCount, m_TotalVariantsInputCount,
|
|
percentageTotal);
|
|
Debug.Log(result);
|
|
}
|
|
}
|
|
|
|
public void OnProcessShader(Shader shader, ShaderSnippetData snippetData, IList<ShaderCompilerData> compilerDataList)
|
|
{
|
|
#if PROFILE_BUILD
|
|
Profiler.BeginSample(k_ProcessShaderTag);
|
|
#endif
|
|
UniversalRenderPipelineAsset urpAsset = GraphicsSettings.renderPipelineAsset as UniversalRenderPipelineAsset;
|
|
if (urpAsset == null || compilerDataList == null || compilerDataList.Count == 0)
|
|
return;
|
|
|
|
// Local Keywords need to be initialized with the shader
|
|
InitializeLocalShaderKeywords(shader);
|
|
|
|
m_stripTimer.Start();
|
|
|
|
int prevVariantCount = compilerDataList.Count;
|
|
var inputShaderVariantCount = compilerDataList.Count;
|
|
for (int i = 0; i < inputShaderVariantCount;)
|
|
{
|
|
bool removeInput = StripUnused(ShaderBuildPreprocessor.supportedFeatures, shader, snippetData, compilerDataList[i]);
|
|
if (removeInput)
|
|
compilerDataList[i] = compilerDataList[--inputShaderVariantCount];
|
|
else
|
|
++i;
|
|
}
|
|
|
|
if (compilerDataList is List<ShaderCompilerData> inputDataList)
|
|
inputDataList.RemoveRange(inputShaderVariantCount, inputDataList.Count - inputShaderVariantCount);
|
|
else
|
|
{
|
|
for (int i = compilerDataList.Count - 1; i >= inputShaderVariantCount; --i)
|
|
compilerDataList.RemoveAt(i);
|
|
}
|
|
|
|
if (urpAsset.shaderVariantLogLevel != ShaderVariantLogLevel.Disabled)
|
|
{
|
|
m_TotalVariantsInputCount += prevVariantCount;
|
|
m_TotalVariantsOutputCount += compilerDataList.Count;
|
|
LogShaderVariants(shader, snippetData, urpAsset.shaderVariantLogLevel, prevVariantCount, compilerDataList.Count);
|
|
}
|
|
m_stripTimer.Stop();
|
|
double stripTimeMs = m_stripTimer.Elapsed.TotalMilliseconds;
|
|
m_stripTimer.Reset();
|
|
|
|
#if PROFILE_BUILD
|
|
Profiler.EndSample();
|
|
#endif
|
|
shaderPreprocessed?.Invoke(shader, snippetData, prevVariantCount, stripTimeMs);
|
|
}
|
|
}
|
|
class ShaderBuildPreprocessor : IPreprocessBuildWithReport
|
|
#if PROFILE_BUILD
|
|
, IPostprocessBuildWithReport
|
|
#endif
|
|
{
|
|
public static ShaderFeatures supportedFeatures
|
|
{
|
|
get
|
|
{
|
|
if (_supportedFeatures <= 0)
|
|
{
|
|
FetchAllSupportedFeatures();
|
|
}
|
|
return _supportedFeatures;
|
|
}
|
|
}
|
|
|
|
private static ShaderFeatures _supportedFeatures = 0;
|
|
public int callbackOrder { get { return 0; } }
|
|
#if PROFILE_BUILD
|
|
public void OnPostprocessBuild(BuildReport report)
|
|
{
|
|
Profiler.enabled = false;
|
|
}
|
|
|
|
#endif
|
|
|
|
public void OnPreprocessBuild(BuildReport report)
|
|
{
|
|
FetchAllSupportedFeatures();
|
|
#if PROFILE_BUILD
|
|
Profiler.enableBinaryLog = true;
|
|
Profiler.logFile = "profilerlog.raw";
|
|
Profiler.enabled = true;
|
|
#endif
|
|
}
|
|
|
|
private static void FetchAllSupportedFeatures()
|
|
{
|
|
List<UniversalRenderPipelineAsset> urps = new List<UniversalRenderPipelineAsset>();
|
|
urps.Add(GraphicsSettings.defaultRenderPipeline as UniversalRenderPipelineAsset);
|
|
for (int i = 0; i < QualitySettings.names.Length; i++)
|
|
{
|
|
urps.Add(QualitySettings.GetRenderPipelineAssetAt(i) as UniversalRenderPipelineAsset);
|
|
}
|
|
|
|
// Must reset flags.
|
|
_supportedFeatures = 0;
|
|
foreach (UniversalRenderPipelineAsset urp in urps)
|
|
{
|
|
if (urp != null)
|
|
{
|
|
_supportedFeatures |= GetSupportedShaderFeatures(urp);
|
|
}
|
|
}
|
|
}
|
|
|
|
private static ShaderFeatures GetSupportedShaderFeatures(UniversalRenderPipelineAsset pipelineAsset)
|
|
{
|
|
ShaderFeatures shaderFeatures;
|
|
shaderFeatures = ShaderFeatures.MainLight;
|
|
|
|
if (pipelineAsset.supportsMainLightShadows)
|
|
shaderFeatures |= ShaderFeatures.MainLightShadows;
|
|
|
|
if (pipelineAsset.additionalLightsRenderingMode == LightRenderingMode.PerVertex)
|
|
{
|
|
shaderFeatures |= ShaderFeatures.VertexLighting;
|
|
}
|
|
else if (pipelineAsset.additionalLightsRenderingMode == LightRenderingMode.PerPixel)
|
|
{
|
|
shaderFeatures |= ShaderFeatures.AdditionalLights;
|
|
|
|
if (pipelineAsset.supportsAdditionalLightShadows)
|
|
shaderFeatures |= ShaderFeatures.AdditionalLightShadows;
|
|
}
|
|
|
|
bool anyShadows = pipelineAsset.supportsMainLightShadows ||
|
|
(shaderFeatures & ShaderFeatures.AdditionalLightShadows) != 0;
|
|
if (pipelineAsset.supportsSoftShadows && anyShadows)
|
|
shaderFeatures |= ShaderFeatures.SoftShadows;
|
|
|
|
if (pipelineAsset.supportsMixedLighting)
|
|
shaderFeatures |= ShaderFeatures.MixedLighting;
|
|
|
|
if (pipelineAsset.supportsTerrainHoles)
|
|
shaderFeatures |= ShaderFeatures.TerrainHoles;
|
|
|
|
if (pipelineAsset.useFastSRGBLinearConversion)
|
|
shaderFeatures |= ShaderFeatures.UseFastSRGBLinearConversion;
|
|
|
|
bool hasScreenSpaceShadows = false;
|
|
bool hasScreenSpaceOcclusion = false;
|
|
bool hasDeferredRenderer = false;
|
|
bool withAccurateGbufferNormals = false;
|
|
bool withoutAccurateGbufferNormals = false;
|
|
|
|
int rendererCount = pipelineAsset.m_RendererDataList.Length;
|
|
for (int rendererIndex = 0; rendererIndex < rendererCount; ++rendererIndex)
|
|
{
|
|
ScriptableRenderer renderer = pipelineAsset.GetRenderer(rendererIndex);
|
|
if (renderer is ForwardRenderer)
|
|
{
|
|
ForwardRenderer forwardRenderer = (ForwardRenderer)renderer;
|
|
if (forwardRenderer.renderingMode == RenderingMode.Deferred)
|
|
{
|
|
hasDeferredRenderer |= true;
|
|
withAccurateGbufferNormals |= forwardRenderer.accurateGbufferNormals;
|
|
withoutAccurateGbufferNormals |= !forwardRenderer.accurateGbufferNormals;
|
|
}
|
|
}
|
|
|
|
// Check for Screen Space Ambient Occlusion Renderer Feature
|
|
ScriptableRendererData rendererData = pipelineAsset.m_RendererDataList[rendererIndex];
|
|
if (rendererData != null)
|
|
{
|
|
for (int rendererFeatureIndex = 0; rendererFeatureIndex < rendererData.rendererFeatures.Count; rendererFeatureIndex++)
|
|
{
|
|
ScriptableRendererFeature rendererFeature = rendererData.rendererFeatures[rendererFeatureIndex];
|
|
|
|
ScreenSpaceShadows ssshadows = rendererFeature as ScreenSpaceShadows;
|
|
hasScreenSpaceShadows |= ssshadows != null;
|
|
|
|
ScreenSpaceAmbientOcclusion ssao = rendererFeature as ScreenSpaceAmbientOcclusion;
|
|
hasScreenSpaceOcclusion |= ssao != null;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (hasDeferredRenderer)
|
|
shaderFeatures |= ShaderFeatures.DeferredShading;
|
|
|
|
// We can only strip accurateGbufferNormals related variants if all DeferredRenderers use the same option.
|
|
if (withAccurateGbufferNormals && !withoutAccurateGbufferNormals)
|
|
shaderFeatures |= ShaderFeatures.DeferredWithAccurateGbufferNormals;
|
|
|
|
if (!withAccurateGbufferNormals && withoutAccurateGbufferNormals)
|
|
shaderFeatures |= ShaderFeatures.DeferredWithoutAccurateGbufferNormals;
|
|
|
|
if (hasScreenSpaceShadows)
|
|
shaderFeatures |= ShaderFeatures.ScreenSpaceShadows;
|
|
|
|
if (hasScreenSpaceOcclusion)
|
|
shaderFeatures |= ShaderFeatures.ScreenSpaceOcclusion;
|
|
|
|
return shaderFeatures;
|
|
}
|
|
}
|
|
}
|