1094 lines
50 KiB
C#
1094 lines
50 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;
|
|
using System.Runtime.CompilerServices;
|
|
|
|
#if XR_MANAGEMENT_4_0_1_OR_NEWER
|
|
using UnityEditor.XR.Management;
|
|
#endif
|
|
|
|
namespace UnityEditor.Rendering.Universal
|
|
{
|
|
[Flags]
|
|
enum ShaderFeatures
|
|
{
|
|
None = 0,
|
|
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
|
|
AccurateGbufferNormals = (1 << 9),
|
|
ScreenSpaceOcclusion = (1 << 10),
|
|
ScreenSpaceShadows = (1 << 11),
|
|
UseFastSRGBLinearConversion = (1 << 12),
|
|
LightLayers = (1 << 13),
|
|
ReflectionProbeBlending = (1 << 14),
|
|
ReflectionProbeBoxProjection = (1 << 15),
|
|
DBufferMRT1 = (1 << 16),
|
|
DBufferMRT2 = (1 << 17),
|
|
DBufferMRT3 = (1 << 18),
|
|
DecalScreenSpace = (1 << 19),
|
|
DecalGBuffer = (1 << 20),
|
|
DecalNormalBlendLow = (1 << 21),
|
|
DecalNormalBlendMedium = (1 << 22),
|
|
DecalNormalBlendHigh = (1 << 23),
|
|
ClusteredRendering = (1 << 24),
|
|
RenderPassEnabled = (1 << 25),
|
|
MainLightShadowsCascade = (1 << 26),
|
|
DrawProcedural = (1 << 27),
|
|
ScreenSpaceOcclusionAfterOpaque = (1 << 28),
|
|
AdditionalLightsKeepOffVariants = (1 << 29),
|
|
ShadowsKeepOffVariants = (1 << 30),
|
|
}
|
|
|
|
[Flags]
|
|
enum VolumeFeatures
|
|
{
|
|
None = 0,
|
|
Calculated = (1 << 0),
|
|
LensDistortion = (1 << 1),
|
|
Bloom = (1 << 2),
|
|
ChromaticAberration = (1 << 3),
|
|
ToneMaping = (1 << 4),
|
|
FilmGrain = (1 << 5),
|
|
DepthOfField = (1 << 6),
|
|
CameraMotionBlur = (1 << 7),
|
|
PaniniProjection = (1 << 8),
|
|
}
|
|
|
|
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();
|
|
|
|
LocalKeyword m_MainLightShadows;
|
|
LocalKeyword m_MainLightShadowsCascades;
|
|
LocalKeyword m_MainLightShadowsScreen;
|
|
LocalKeyword m_AdditionalLightsVertex;
|
|
LocalKeyword m_AdditionalLightsPixel;
|
|
LocalKeyword m_AdditionalLightShadows;
|
|
LocalKeyword m_ReflectionProbeBlending;
|
|
LocalKeyword m_ReflectionProbeBoxProjection;
|
|
LocalKeyword m_CastingPunctualLightShadow;
|
|
LocalKeyword m_SoftShadows;
|
|
LocalKeyword m_MixedLightingSubtractive;
|
|
LocalKeyword m_LightmapShadowMixing;
|
|
LocalKeyword m_ShadowsShadowMask;
|
|
LocalKeyword m_Lightmap;
|
|
LocalKeyword m_DynamicLightmap;
|
|
LocalKeyword m_DirectionalLightmap;
|
|
LocalKeyword m_AlphaTestOn;
|
|
LocalKeyword m_DeferredStencil;
|
|
LocalKeyword m_GbufferNormalsOct;
|
|
LocalKeyword m_UseDrawProcedural;
|
|
LocalKeyword m_ScreenSpaceOcclusion;
|
|
LocalKeyword m_UseFastSRGBLinearConversion;
|
|
LocalKeyword m_LightLayers;
|
|
LocalKeyword m_RenderPassEnabled;
|
|
LocalKeyword m_DebugDisplay;
|
|
LocalKeyword m_DBufferMRT1;
|
|
LocalKeyword m_DBufferMRT2;
|
|
LocalKeyword m_DBufferMRT3;
|
|
LocalKeyword m_DecalNormalBlendLow;
|
|
LocalKeyword m_DecalNormalBlendMedium;
|
|
LocalKeyword m_DecalNormalBlendHigh;
|
|
LocalKeyword m_ClusteredRendering;
|
|
LocalKeyword m_EditorVisualization;
|
|
|
|
LocalKeyword m_LocalDetailMulx2;
|
|
LocalKeyword m_LocalDetailScaled;
|
|
LocalKeyword m_LocalClearCoat;
|
|
LocalKeyword m_LocalClearCoatMap;
|
|
|
|
LocalKeyword m_LensDistortion;
|
|
LocalKeyword m_ChromaticAberration;
|
|
LocalKeyword m_BloomLQ;
|
|
LocalKeyword m_BloomHQ;
|
|
LocalKeyword m_BloomLQDirt;
|
|
LocalKeyword m_BloomHQDirt;
|
|
LocalKeyword m_HdrGrading;
|
|
LocalKeyword m_ToneMapACES;
|
|
LocalKeyword m_ToneMapNeutral;
|
|
LocalKeyword m_FilmGrain;
|
|
|
|
Shader m_BokehDepthOfField = Shader.Find("Hidden/Universal Render Pipeline/BokehDepthOfField");
|
|
Shader m_GaussianDepthOfField = Shader.Find("Hidden/Universal Render Pipeline/GaussianDepthOfField");
|
|
Shader m_CameraMotionBlur = Shader.Find("Hidden/Universal Render Pipeline/CameraMotionBlur");
|
|
Shader m_PaniniProjection = Shader.Find("Hidden/Universal Render Pipeline/PaniniProjection");
|
|
Shader m_Bloom = Shader.Find("Hidden/Universal Render Pipeline/Bloom");
|
|
|
|
Shader StencilDeferred = Shader.Find("Hidden/Universal Render Pipeline/StencilDeferred");
|
|
|
|
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; } }
|
|
|
|
LocalKeyword TryGetLocalKeyword(Shader shader, string name)
|
|
{
|
|
return shader.keywordSpace.FindKeyword(name);
|
|
}
|
|
|
|
void InitializeLocalShaderKeywords(Shader shader)
|
|
{
|
|
m_MainLightShadows = TryGetLocalKeyword(shader, ShaderKeywordStrings.MainLightShadows);
|
|
m_MainLightShadowsCascades = TryGetLocalKeyword(shader, ShaderKeywordStrings.MainLightShadowCascades);
|
|
m_MainLightShadowsScreen = TryGetLocalKeyword(shader, ShaderKeywordStrings.MainLightShadowScreen);
|
|
m_AdditionalLightsVertex = TryGetLocalKeyword(shader, ShaderKeywordStrings.AdditionalLightsVertex);
|
|
m_AdditionalLightsPixel = TryGetLocalKeyword(shader, ShaderKeywordStrings.AdditionalLightsPixel);
|
|
m_AdditionalLightShadows = TryGetLocalKeyword(shader, ShaderKeywordStrings.AdditionalLightShadows);
|
|
m_ReflectionProbeBlending = TryGetLocalKeyword(shader, ShaderKeywordStrings.ReflectionProbeBlending);
|
|
m_ReflectionProbeBoxProjection = TryGetLocalKeyword(shader, ShaderKeywordStrings.ReflectionProbeBoxProjection);
|
|
m_CastingPunctualLightShadow = TryGetLocalKeyword(shader, ShaderKeywordStrings.CastingPunctualLightShadow);
|
|
m_SoftShadows = TryGetLocalKeyword(shader, ShaderKeywordStrings.SoftShadows);
|
|
m_MixedLightingSubtractive = TryGetLocalKeyword(shader, ShaderKeywordStrings.MixedLightingSubtractive);
|
|
m_LightmapShadowMixing = TryGetLocalKeyword(shader, ShaderKeywordStrings.LightmapShadowMixing);
|
|
m_ShadowsShadowMask = TryGetLocalKeyword(shader, ShaderKeywordStrings.ShadowsShadowMask);
|
|
m_Lightmap = TryGetLocalKeyword(shader, ShaderKeywordStrings.LIGHTMAP_ON);
|
|
m_DynamicLightmap = TryGetLocalKeyword(shader, ShaderKeywordStrings.DYNAMICLIGHTMAP_ON);
|
|
m_DirectionalLightmap = TryGetLocalKeyword(shader, ShaderKeywordStrings.DIRLIGHTMAP_COMBINED);
|
|
m_AlphaTestOn = TryGetLocalKeyword(shader, ShaderKeywordStrings._ALPHATEST_ON);
|
|
m_DeferredStencil = TryGetLocalKeyword(shader, ShaderKeywordStrings._DEFERRED_STENCIL);
|
|
m_GbufferNormalsOct = TryGetLocalKeyword(shader, ShaderKeywordStrings._GBUFFER_NORMALS_OCT);
|
|
m_UseDrawProcedural = TryGetLocalKeyword(shader, ShaderKeywordStrings.UseDrawProcedural);
|
|
m_ScreenSpaceOcclusion = TryGetLocalKeyword(shader, ShaderKeywordStrings.ScreenSpaceOcclusion);
|
|
m_UseFastSRGBLinearConversion = TryGetLocalKeyword(shader, ShaderKeywordStrings.UseFastSRGBLinearConversion);
|
|
m_LightLayers = TryGetLocalKeyword(shader, ShaderKeywordStrings.LightLayers);
|
|
m_RenderPassEnabled = TryGetLocalKeyword(shader, ShaderKeywordStrings.RenderPassEnabled);
|
|
m_DebugDisplay = TryGetLocalKeyword(shader, ShaderKeywordStrings.DEBUG_DISPLAY);
|
|
m_DBufferMRT1 = TryGetLocalKeyword(shader, ShaderKeywordStrings.DBufferMRT1);
|
|
m_DBufferMRT2 = TryGetLocalKeyword(shader, ShaderKeywordStrings.DBufferMRT2);
|
|
m_DBufferMRT3 = TryGetLocalKeyword(shader, ShaderKeywordStrings.DBufferMRT3);
|
|
m_DecalNormalBlendLow = TryGetLocalKeyword(shader, ShaderKeywordStrings.DecalNormalBlendLow);
|
|
m_DecalNormalBlendMedium = TryGetLocalKeyword(shader, ShaderKeywordStrings.DecalNormalBlendMedium);
|
|
m_DecalNormalBlendHigh = TryGetLocalKeyword(shader, ShaderKeywordStrings.DecalNormalBlendHigh);
|
|
m_ClusteredRendering = TryGetLocalKeyword(shader, ShaderKeywordStrings.ClusteredRendering);
|
|
m_EditorVisualization = TryGetLocalKeyword(shader, ShaderKeywordStrings.EDITOR_VISUALIZATION);
|
|
|
|
m_LocalDetailMulx2 = TryGetLocalKeyword(shader, ShaderKeywordStrings._DETAIL_MULX2);
|
|
m_LocalDetailScaled = TryGetLocalKeyword(shader, ShaderKeywordStrings._DETAIL_SCALED);
|
|
m_LocalClearCoat = TryGetLocalKeyword(shader, ShaderKeywordStrings._CLEARCOAT);
|
|
m_LocalClearCoatMap = TryGetLocalKeyword(shader, ShaderKeywordStrings._CLEARCOATMAP);
|
|
|
|
// Post processing
|
|
m_LensDistortion = TryGetLocalKeyword(shader, ShaderKeywordStrings.Distortion);
|
|
m_ChromaticAberration = TryGetLocalKeyword(shader, ShaderKeywordStrings.ChromaticAberration);
|
|
m_BloomLQ = TryGetLocalKeyword(shader, ShaderKeywordStrings.BloomLQ);
|
|
m_BloomHQ = TryGetLocalKeyword(shader, ShaderKeywordStrings.BloomHQ);
|
|
m_BloomLQDirt = TryGetLocalKeyword(shader, ShaderKeywordStrings.BloomLQDirt);
|
|
m_BloomHQDirt = TryGetLocalKeyword(shader, ShaderKeywordStrings.BloomHQDirt);
|
|
m_HdrGrading = TryGetLocalKeyword(shader, ShaderKeywordStrings.HDRGrading);
|
|
m_ToneMapACES = TryGetLocalKeyword(shader, ShaderKeywordStrings.TonemapACES);
|
|
m_ToneMapNeutral = TryGetLocalKeyword(shader, ShaderKeywordStrings.TonemapNeutral);
|
|
m_FilmGrain = TryGetLocalKeyword(shader, ShaderKeywordStrings.FilmGrain);
|
|
}
|
|
|
|
bool IsFeatureEnabled(ShaderFeatures featureMask, ShaderFeatures feature)
|
|
{
|
|
return (featureMask & feature) != 0;
|
|
}
|
|
|
|
bool IsFeatureEnabled(VolumeFeatures featureMask, VolumeFeatures feature)
|
|
{
|
|
return (featureMask & feature) != 0;
|
|
}
|
|
|
|
bool StripUnusedPass(ShaderFeatures features, ShaderSnippetData snippetData)
|
|
{
|
|
// Meta pass is needed in the player for Enlighten Precomputed Realtime GI albedo and emission.
|
|
if (snippetData.passType == PassType.Meta)
|
|
{
|
|
if (SupportedRenderingFeatures.active.enlighten == false ||
|
|
((int)SupportedRenderingFeatures.active.lightmapBakeTypes | (int)LightmapBakeType.Realtime) == 0)
|
|
return true;
|
|
}
|
|
|
|
if (snippetData.passType == PassType.ShadowCaster)
|
|
if (!IsFeatureEnabled(features, ShaderFeatures.MainLightShadows) && !IsFeatureEnabled(features, ShaderFeatures.AdditionalLightShadows))
|
|
return true;
|
|
|
|
// DBuffer
|
|
if (snippetData.passName == DecalShaderPassNames.DBufferMesh || snippetData.passName == DecalShaderPassNames.DBufferProjector ||
|
|
snippetData.passName == DecalShaderPassNames.DecalMeshForwardEmissive || snippetData.passName == DecalShaderPassNames.DecalProjectorForwardEmissive)
|
|
if (!IsFeatureEnabled(features, ShaderFeatures.DBufferMRT1) && !IsFeatureEnabled(features, ShaderFeatures.DBufferMRT2) && !IsFeatureEnabled(features, ShaderFeatures.DBufferMRT3))
|
|
return true;
|
|
|
|
// Decal Screen Space
|
|
if (snippetData.passName == DecalShaderPassNames.DecalScreenSpaceMesh || snippetData.passName == DecalShaderPassNames.DecalScreenSpaceProjector)
|
|
if (!IsFeatureEnabled(features, ShaderFeatures.DecalScreenSpace))
|
|
return true;
|
|
|
|
// Decal GBuffer
|
|
if (snippetData.passName == DecalShaderPassNames.DecalGBufferMesh || snippetData.passName == DecalShaderPassNames.DecalGBufferProjector)
|
|
if (!IsFeatureEnabled(features, ShaderFeatures.DecalGBuffer))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
struct StripTool<T> where T : System.Enum
|
|
{
|
|
T m_Features;
|
|
Shader m_Shader;
|
|
ShaderKeywordSet m_KeywordSet;
|
|
ShaderSnippetData m_SnippetData;
|
|
bool m_stripUnusedVariants;
|
|
|
|
public StripTool(T features, Shader shader, ShaderSnippetData snippetData, in ShaderKeywordSet keywordSet, bool stripUnusedVariants)
|
|
{
|
|
m_Features = features;
|
|
m_Shader = shader;
|
|
m_SnippetData = snippetData;
|
|
m_KeywordSet = keywordSet;
|
|
m_stripUnusedVariants = stripUnusedVariants;
|
|
}
|
|
|
|
bool ContainsKeyword(in LocalKeyword kw)
|
|
{
|
|
return ShaderUtil.PassHasKeyword(m_Shader, m_SnippetData.pass, kw, m_SnippetData.shaderType);
|
|
}
|
|
|
|
public bool StripMultiCompileKeepOffVariant(in LocalKeyword kw, T feature, in LocalKeyword kw2, T feature2, in LocalKeyword kw3, T feature3)
|
|
{
|
|
if (StripMultiCompileKeepOffVariant(kw, feature))
|
|
return true;
|
|
if (StripMultiCompileKeepOffVariant(kw2, feature2))
|
|
return true;
|
|
if (StripMultiCompileKeepOffVariant(kw3, feature3))
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
public bool StripMultiCompile(in LocalKeyword kw, T feature, in LocalKeyword kw2, T feature2, in LocalKeyword kw3, T feature3)
|
|
{
|
|
if (StripMultiCompileKeepOffVariant(kw, feature, kw2, feature2, kw3, feature3))
|
|
return true;
|
|
|
|
bool containsKeywords = ContainsKeyword(kw) && ContainsKeyword(kw2) && ContainsKeyword(kw3);
|
|
bool keywordsDisabled = !m_KeywordSet.IsEnabled(kw) && !m_KeywordSet.IsEnabled(kw2) && !m_KeywordSet.IsEnabled(kw3);
|
|
bool hasAnyFeatureEnabled = m_Features.HasFlag(feature) || m_Features.HasFlag(feature2) || m_Features.HasFlag(feature3);
|
|
if (m_stripUnusedVariants && containsKeywords && keywordsDisabled && hasAnyFeatureEnabled)
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
public bool StripMultiCompileKeepOffVariant(in LocalKeyword kw, T feature, in LocalKeyword kw2, T feature2)
|
|
{
|
|
if (StripMultiCompileKeepOffVariant(kw, feature))
|
|
return true;
|
|
if (StripMultiCompileKeepOffVariant(kw2, feature2))
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
public bool StripMultiCompile(in LocalKeyword kw, T feature, in LocalKeyword kw2, T feature2)
|
|
{
|
|
if (StripMultiCompileKeepOffVariant(kw, feature, kw2, feature2))
|
|
return true;
|
|
|
|
bool containsKeywords = ContainsKeyword(kw) && ContainsKeyword(kw2);
|
|
bool keywordsDisabled = !m_KeywordSet.IsEnabled(kw) && !m_KeywordSet.IsEnabled(kw2);
|
|
bool hasAnyFeatureEnabled = m_Features.HasFlag(feature) || m_Features.HasFlag(feature2);
|
|
if (m_stripUnusedVariants && containsKeywords && keywordsDisabled && hasAnyFeatureEnabled)
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public bool StripMultiCompileKeepOffVariant(in LocalKeyword kw, T feature)
|
|
{
|
|
return !m_Features.HasFlag(feature) && m_KeywordSet.IsEnabled(kw);
|
|
}
|
|
|
|
public bool StripMultiCompile(in LocalKeyword kw, T feature)
|
|
{
|
|
if (!m_Features.HasFlag(feature))
|
|
{
|
|
if (m_KeywordSet.IsEnabled(kw))
|
|
return true;
|
|
}
|
|
else if (m_stripUnusedVariants)
|
|
{
|
|
if (!m_KeywordSet.IsEnabled(kw) && ContainsKeyword(kw))
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool StripUnusedFeatures(ShaderFeatures features, Shader shader, ShaderSnippetData snippetData, ShaderCompilerData compilerData)
|
|
{
|
|
var globalSettings = UniversalRenderPipelineGlobalSettings.instance;
|
|
bool stripDebugDisplayShaders = !Debug.isDebugBuild || (globalSettings == null || globalSettings.stripDebugVariants);
|
|
|
|
#if XR_MANAGEMENT_4_0_1_OR_NEWER
|
|
var buildTargetSettings = XRGeneralSettingsPerBuildTarget.XRGeneralSettingsForBuildTarget(BuildTargetGroup.Standalone);
|
|
if (buildTargetSettings != null && buildTargetSettings.AssignedSettings != null && buildTargetSettings.AssignedSettings.activeLoaders.Count > 0)
|
|
{
|
|
stripDebugDisplayShaders = true;
|
|
}
|
|
#endif
|
|
|
|
if (stripDebugDisplayShaders && compilerData.shaderKeywordSet.IsEnabled(m_DebugDisplay))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
var stripUnusedVariants = UniversalRenderPipelineGlobalSettings.instance?.stripUnusedVariants == true;
|
|
var stripTool = new StripTool<ShaderFeatures>(features, shader, snippetData, compilerData.shaderKeywordSet, stripUnusedVariants);
|
|
|
|
// strip main light shadows, cascade and screen variants
|
|
if (IsFeatureEnabled(ShaderFeatures.ShadowsKeepOffVariants, features))
|
|
{
|
|
if (stripTool.StripMultiCompileKeepOffVariant(
|
|
m_MainLightShadows, ShaderFeatures.MainLightShadows,
|
|
m_MainLightShadowsCascades, ShaderFeatures.MainLightShadowsCascade,
|
|
m_MainLightShadowsScreen, ShaderFeatures.ScreenSpaceShadows))
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
if (stripTool.StripMultiCompile(
|
|
m_MainLightShadows, ShaderFeatures.MainLightShadows,
|
|
m_MainLightShadowsCascades, ShaderFeatures.MainLightShadowsCascade,
|
|
m_MainLightShadowsScreen, ShaderFeatures.ScreenSpaceShadows))
|
|
return true;
|
|
}
|
|
|
|
// TODO: Strip off variants once we have global soft shadows option for forcing instead as support
|
|
if (stripTool.StripMultiCompileKeepOffVariant(m_SoftShadows, ShaderFeatures.SoftShadows))
|
|
return true;
|
|
|
|
// Left for backward compatibility
|
|
if (compilerData.shaderKeywordSet.IsEnabled(m_MixedLightingSubtractive) &&
|
|
!IsFeatureEnabled(features, ShaderFeatures.MixedLighting))
|
|
return true;
|
|
|
|
if (stripTool.StripMultiCompile(m_UseFastSRGBLinearConversion, 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.shaderCompilerPlatform == ShaderCompilerPlatform.GLES20)
|
|
{
|
|
// GLES2 does not support bitwise operations.
|
|
if (compilerData.shaderKeywordSet.IsEnabled(m_LightLayers))
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
if (stripTool.StripMultiCompile(m_LightLayers, ShaderFeatures.LightLayers))
|
|
return true;
|
|
}
|
|
|
|
if (stripTool.StripMultiCompile(m_RenderPassEnabled, ShaderFeatures.RenderPassEnabled))
|
|
return true;
|
|
|
|
// No additional light shadows
|
|
if (IsFeatureEnabled(ShaderFeatures.ShadowsKeepOffVariants, features))
|
|
{
|
|
if (stripTool.StripMultiCompileKeepOffVariant(m_AdditionalLightShadows, ShaderFeatures.AdditionalLightShadows))
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
if (stripTool.StripMultiCompile(m_AdditionalLightShadows, ShaderFeatures.AdditionalLightShadows))
|
|
return true;
|
|
}
|
|
|
|
if (stripTool.StripMultiCompile(m_ReflectionProbeBlending, ShaderFeatures.ReflectionProbeBlending))
|
|
return true;
|
|
|
|
if (stripTool.StripMultiCompile(m_ReflectionProbeBoxProjection, ShaderFeatures.ReflectionProbeBoxProjection))
|
|
return true;
|
|
|
|
// Shadow caster punctual light strip
|
|
if (snippetData.passType == PassType.ShadowCaster && ShaderUtil.PassHasKeyword(shader, snippetData.pass, m_CastingPunctualLightShadow, snippetData.shaderType))
|
|
{
|
|
if (!IsFeatureEnabled(features, ShaderFeatures.AdditionalLightShadows) && compilerData.shaderKeywordSet.IsEnabled(m_CastingPunctualLightShadow))
|
|
return true;
|
|
|
|
bool mainLightShadows =
|
|
!IsFeatureEnabled(features, ShaderFeatures.MainLightShadows) &&
|
|
!IsFeatureEnabled(features, ShaderFeatures.MainLightShadowsCascade) &&
|
|
!IsFeatureEnabled(features, ShaderFeatures.ScreenSpaceShadows);
|
|
if (mainLightShadows && !compilerData.shaderKeywordSet.IsEnabled(m_CastingPunctualLightShadow))
|
|
return true;
|
|
}
|
|
|
|
// Additional light are shaded per-vertex or per-pixel.
|
|
if (IsFeatureEnabled(ShaderFeatures.AdditionalLightsKeepOffVariants, features))
|
|
{
|
|
if (stripTool.StripMultiCompileKeepOffVariant(m_AdditionalLightsVertex, ShaderFeatures.VertexLighting,
|
|
m_AdditionalLightsPixel, ShaderFeatures.AdditionalLights))
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
if (stripTool.StripMultiCompile(m_AdditionalLightsVertex, ShaderFeatures.VertexLighting,
|
|
m_AdditionalLightsPixel, ShaderFeatures.AdditionalLights))
|
|
return true;
|
|
}
|
|
|
|
if (stripTool.StripMultiCompile(m_ClusteredRendering, ShaderFeatures.ClusteredRendering))
|
|
return true;
|
|
|
|
// Screen Space Occlusion
|
|
//Hardcoding a check for android platform. If android, then normal stripping. If not, skip stripping because we need the multicomplie to toggle SSAO. UNITY WHYU DUMB
|
|
#if UNITY_ANDROID
|
|
if (IsFeatureEnabled(features, ShaderFeatures.ScreenSpaceOcclusionAfterOpaque))
|
|
{
|
|
// SSAO after opaque setting requires off variants
|
|
if (stripTool.StripMultiCompileKeepOffVariant(m_ScreenSpaceOcclusion, ShaderFeatures.ScreenSpaceOcclusion))
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
if (stripTool.StripMultiCompile(m_ScreenSpaceOcclusion, ShaderFeatures.ScreenSpaceOcclusion))
|
|
return true;
|
|
}
|
|
#endif
|
|
// Decal DBuffer
|
|
if (stripTool.StripMultiCompile(
|
|
m_DBufferMRT1, ShaderFeatures.DBufferMRT1,
|
|
m_DBufferMRT2, ShaderFeatures.DBufferMRT2,
|
|
m_DBufferMRT3, ShaderFeatures.DBufferMRT3))
|
|
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 (compilerData.shaderCompilerPlatform != ShaderCompilerPlatform.Vulkan &&
|
|
stripTool.StripMultiCompile(m_GbufferNormalsOct, ShaderFeatures.AccurateGbufferNormals))
|
|
return true;
|
|
|
|
if (compilerData.shaderKeywordSet.IsEnabled(m_UseDrawProcedural) &&
|
|
!IsFeatureEnabled(features, ShaderFeatures.DrawProcedural))
|
|
return true;
|
|
|
|
// Decal Normal Blend
|
|
if (stripTool.StripMultiCompile(
|
|
m_DecalNormalBlendLow, ShaderFeatures.DecalNormalBlendLow,
|
|
m_DecalNormalBlendMedium, ShaderFeatures.DecalNormalBlendMedium,
|
|
m_DecalNormalBlendHigh, ShaderFeatures.DecalNormalBlendHigh))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
bool StripVolumeFeatures(VolumeFeatures features, Shader shader, ShaderSnippetData snippetData, ShaderCompilerData compilerData)
|
|
{
|
|
var stripUnusedVariants = UniversalRenderPipelineGlobalSettings.instance?.stripUnusedVariants == true;
|
|
var stripTool = new StripTool<VolumeFeatures>(features, shader, snippetData, compilerData.shaderKeywordSet, stripUnusedVariants);
|
|
|
|
if (stripTool.StripMultiCompileKeepOffVariant(m_LensDistortion, VolumeFeatures.LensDistortion))
|
|
return true;
|
|
|
|
if (stripTool.StripMultiCompileKeepOffVariant(m_ChromaticAberration, VolumeFeatures.ChromaticAberration))
|
|
return true;
|
|
|
|
if (stripTool.StripMultiCompileKeepOffVariant(m_BloomLQ, VolumeFeatures.Bloom))
|
|
return true;
|
|
if (stripTool.StripMultiCompileKeepOffVariant(m_BloomHQ, VolumeFeatures.Bloom))
|
|
return true;
|
|
if (stripTool.StripMultiCompileKeepOffVariant(m_BloomLQDirt, VolumeFeatures.Bloom))
|
|
return true;
|
|
if (stripTool.StripMultiCompileKeepOffVariant(m_BloomHQDirt, VolumeFeatures.Bloom))
|
|
return true;
|
|
|
|
if (stripTool.StripMultiCompileKeepOffVariant(m_HdrGrading, VolumeFeatures.ToneMaping))
|
|
return true;
|
|
if (stripTool.StripMultiCompileKeepOffVariant(m_ToneMapACES, VolumeFeatures.ToneMaping))
|
|
return true;
|
|
if (stripTool.StripMultiCompileKeepOffVariant(m_ToneMapNeutral, VolumeFeatures.ToneMaping))
|
|
return true;
|
|
if (stripTool.StripMultiCompileKeepOffVariant(m_FilmGrain, VolumeFeatures.FilmGrain))
|
|
return true;
|
|
|
|
// Strip post processing shaders
|
|
if (shader == m_BokehDepthOfField && !IsFeatureEnabled(ShaderBuildPreprocessor.volumeFeatures, VolumeFeatures.DepthOfField))
|
|
return true;
|
|
if (shader == m_GaussianDepthOfField && !IsFeatureEnabled(ShaderBuildPreprocessor.volumeFeatures, VolumeFeatures.DepthOfField))
|
|
return true;
|
|
if (shader == m_CameraMotionBlur && !IsFeatureEnabled(ShaderBuildPreprocessor.volumeFeatures, VolumeFeatures.CameraMotionBlur))
|
|
return true;
|
|
if (shader == m_PaniniProjection && !IsFeatureEnabled(ShaderBuildPreprocessor.volumeFeatures, VolumeFeatures.PaniniProjection))
|
|
return true;
|
|
if (shader == m_Bloom && !IsFeatureEnabled(ShaderBuildPreprocessor.volumeFeatures, VolumeFeatures.Bloom))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
bool StripUnsupportedVariants(ShaderCompilerData compilerData)
|
|
{
|
|
// We can strip variants that have directional lightmap enabled but not static nor dynamic lightmap.
|
|
if (compilerData.shaderKeywordSet.IsEnabled(m_DirectionalLightmap) &&
|
|
!(compilerData.shaderKeywordSet.IsEnabled(m_Lightmap) ||
|
|
compilerData.shaderKeywordSet.IsEnabled(m_DynamicLightmap)))
|
|
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;
|
|
}
|
|
|
|
// Editor visualization is only used in scene view debug modes.
|
|
if (compilerData.shaderKeywordSet.IsEnabled(m_EditorVisualization))
|
|
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;
|
|
}
|
|
|
|
bool StripUnusedShaders(ShaderFeatures features, Shader shader)
|
|
{
|
|
if (!IsFeatureEnabled(features, ShaderFeatures.DeferredShading))
|
|
{
|
|
if (shader == StencilDeferred)
|
|
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;
|
|
|
|
if (UniversalRenderPipelineGlobalSettings.instance?.stripUnusedVariants == true)
|
|
{
|
|
if (StripUnusedShaders(features, shader))
|
|
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;
|
|
|
|
return false;
|
|
}
|
|
|
|
void LogShaderVariants(Shader shader, ShaderSnippetData snippetData, ShaderVariantLogLevel logLevel, int prevVariantsCount, int currVariantsCount, double stripTimeMs)
|
|
{
|
|
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}% TimeMs={9}",
|
|
shader.name, snippetData.passName, snippetData.shaderType.ToString(), currVariantsCount,
|
|
prevVariantsCount, percentageCurrent, m_TotalVariantsOutputCount, m_TotalVariantsInputCount,
|
|
percentageTotal, stripTimeMs);
|
|
Debug.Log(result);
|
|
}
|
|
}
|
|
|
|
public void OnProcessShader(Shader shader, ShaderSnippetData snippetData, IList<ShaderCompilerData> compilerDataList)
|
|
{
|
|
#if PROFILE_BUILD
|
|
Profiler.BeginSample(k_ProcessShaderTag);
|
|
#endif
|
|
|
|
UniversalRenderPipelineAsset urpAsset = UniversalRenderPipeline.asset;
|
|
if (urpAsset == null || compilerDataList == null || compilerDataList.Count == 0)
|
|
return;
|
|
|
|
m_stripTimer.Start();
|
|
|
|
InitializeLocalShaderKeywords(shader);
|
|
|
|
int prevVariantCount = compilerDataList.Count;
|
|
var inputShaderVariantCount = compilerDataList.Count;
|
|
for (int i = 0; i < inputShaderVariantCount;)
|
|
{
|
|
bool removeInput = true;
|
|
|
|
foreach (var supportedFeatures in ShaderBuildPreprocessor.supportedFeaturesList)
|
|
{
|
|
if (!StripUnused(supportedFeatures, shader, snippetData, compilerDataList[i]))
|
|
{
|
|
removeInput = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (UniversalRenderPipelineGlobalSettings.instance?.stripUnusedPostProcessingVariants == true)
|
|
{
|
|
if (!removeInput && StripVolumeFeatures(ShaderBuildPreprocessor.volumeFeatures, shader, snippetData, compilerDataList[i]))
|
|
{
|
|
removeInput = true;
|
|
}
|
|
}
|
|
|
|
// Remove at swap back
|
|
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);
|
|
}
|
|
|
|
m_stripTimer.Stop();
|
|
double stripTimeMs = m_stripTimer.Elapsed.TotalMilliseconds;
|
|
m_stripTimer.Reset();
|
|
|
|
if (urpAsset.shaderVariantLogLevel != ShaderVariantLogLevel.Disabled)
|
|
{
|
|
m_TotalVariantsInputCount += prevVariantCount;
|
|
m_TotalVariantsOutputCount += compilerDataList.Count;
|
|
LogShaderVariants(shader, snippetData, urpAsset.shaderVariantLogLevel, prevVariantCount, compilerDataList.Count, stripTimeMs);
|
|
}
|
|
|
|
#if PROFILE_BUILD
|
|
Profiler.EndSample();
|
|
#endif
|
|
shaderPreprocessed?.Invoke(shader, snippetData, prevVariantCount, stripTimeMs);
|
|
}
|
|
}
|
|
class ShaderBuildPreprocessor : IPreprocessBuildWithReport
|
|
#if PROFILE_BUILD
|
|
, IPostprocessBuildWithReport
|
|
#endif
|
|
{
|
|
public static List<ShaderFeatures> supportedFeaturesList
|
|
{
|
|
get
|
|
{
|
|
if (s_SupportedFeaturesList.Count == 0)
|
|
FetchAllSupportedFeatures();
|
|
return s_SupportedFeaturesList;
|
|
}
|
|
}
|
|
|
|
private static List<ShaderFeatures> s_SupportedFeaturesList = new List<ShaderFeatures>();
|
|
|
|
public static VolumeFeatures volumeFeatures
|
|
{
|
|
get
|
|
{
|
|
if (s_VolumeFeatures == VolumeFeatures.None)
|
|
FetchAllSupportedFeaturesFromVolumes();
|
|
return s_VolumeFeatures;
|
|
}
|
|
}
|
|
private static VolumeFeatures s_VolumeFeatures;
|
|
|
|
public int callbackOrder { get { return 0; } }
|
|
#if PROFILE_BUILD
|
|
public void OnPostprocessBuild(BuildReport report)
|
|
{
|
|
Profiler.enabled = false;
|
|
}
|
|
|
|
#endif
|
|
|
|
public void OnPreprocessBuild(BuildReport report)
|
|
{
|
|
FetchAllSupportedFeatures();
|
|
FetchAllSupportedFeaturesFromVolumes();
|
|
#if PROFILE_BUILD
|
|
Profiler.enableBinaryLog = true;
|
|
Profiler.logFile = "profilerlog.raw";
|
|
Profiler.enabled = true;
|
|
#endif
|
|
}
|
|
|
|
static bool TryGetRenderPipelineAssetsForBuildTarget(BuildTarget buildTarget, List<UniversalRenderPipelineAsset> urps)
|
|
{
|
|
var qualitySettings = new SerializedObject(QualitySettings.GetQualitySettings());
|
|
if (qualitySettings == null)
|
|
return false;
|
|
|
|
var property = qualitySettings.FindProperty("m_QualitySettings");
|
|
if (property == null)
|
|
return false;
|
|
|
|
var activeBuildTargetGroup = BuildPipeline.GetBuildTargetGroup(buildTarget);
|
|
var activeBuildTargetGroupName = activeBuildTargetGroup.ToString();
|
|
|
|
for (int i = 0; i < property.arraySize; i++)
|
|
{
|
|
bool isExcluded = false;
|
|
|
|
var excludedTargetPlatforms = property.GetArrayElementAtIndex(i).FindPropertyRelative("excludedTargetPlatforms");
|
|
if (excludedTargetPlatforms == null)
|
|
return false;
|
|
|
|
foreach (SerializedProperty excludedTargetPlatform in excludedTargetPlatforms)
|
|
{
|
|
var excludedBuildTargetGroupName = excludedTargetPlatform.stringValue;
|
|
if (activeBuildTargetGroupName == excludedBuildTargetGroupName)
|
|
{
|
|
Debug.Log($"Excluding quality level {QualitySettings.names[i]} from stripping."); // TODO: remove after QA
|
|
isExcluded = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!isExcluded)
|
|
urps.Add(QualitySettings.GetRenderPipelineAssetAt(i) as UniversalRenderPipelineAsset);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
private static void FetchAllSupportedFeatures()
|
|
{
|
|
List<UniversalRenderPipelineAsset> urps = new List<UniversalRenderPipelineAsset>();
|
|
urps.Add(GraphicsSettings.defaultRenderPipeline as UniversalRenderPipelineAsset);
|
|
|
|
// TODO: Replace once we have official API for filtering urps per build target
|
|
if (!TryGetRenderPipelineAssetsForBuildTarget(EditorUserBuildSettings.activeBuildTarget, urps))
|
|
{
|
|
// Fallback
|
|
Debug.LogWarning("Shader stripping per enabled quality levels failed! Stripping will use all quality levels. Please report a bug!");
|
|
for (int i = 0; i < QualitySettings.names.Length; i++)
|
|
{
|
|
urps.Add(QualitySettings.GetRenderPipelineAssetAt(i) as UniversalRenderPipelineAsset);
|
|
}
|
|
}
|
|
|
|
s_SupportedFeaturesList.Clear();
|
|
|
|
foreach (UniversalRenderPipelineAsset urp in urps)
|
|
{
|
|
if (urp != null)
|
|
{
|
|
int rendererCount = urp.m_RendererDataList.Length;
|
|
|
|
for (int i = 0; i < rendererCount; ++i)
|
|
s_SupportedFeaturesList.Add(GetSupportedShaderFeatures(urp, i));
|
|
}
|
|
}
|
|
}
|
|
|
|
private static void FetchAllSupportedFeaturesFromVolumes()
|
|
{
|
|
if (UniversalRenderPipelineGlobalSettings.instance?.stripUnusedPostProcessingVariants == false)
|
|
return;
|
|
|
|
s_VolumeFeatures = VolumeFeatures.Calculated;
|
|
var guids = AssetDatabase.FindAssets("t:VolumeProfile");
|
|
foreach (var guid in guids)
|
|
{
|
|
var path = AssetDatabase.GUIDToAssetPath(guid);
|
|
|
|
// We only care what is in assets folder
|
|
if (!path.StartsWith("Assets"))
|
|
continue;
|
|
|
|
var asset = AssetDatabase.LoadAssetAtPath<VolumeProfile>(path);
|
|
if (asset == null)
|
|
continue;
|
|
|
|
if (asset.Has<LensDistortion>())
|
|
s_VolumeFeatures |= VolumeFeatures.LensDistortion;
|
|
if (asset.Has<Bloom>())
|
|
s_VolumeFeatures |= VolumeFeatures.Bloom;
|
|
if (asset.Has<Tonemapping>())
|
|
s_VolumeFeatures |= VolumeFeatures.ToneMaping;
|
|
if (asset.Has<FilmGrain>())
|
|
s_VolumeFeatures |= VolumeFeatures.FilmGrain;
|
|
if (asset.Has<DepthOfField>())
|
|
s_VolumeFeatures |= VolumeFeatures.DepthOfField;
|
|
if (asset.Has<MotionBlur>())
|
|
s_VolumeFeatures |= VolumeFeatures.CameraMotionBlur;
|
|
if (asset.Has<PaniniProjection>())
|
|
s_VolumeFeatures |= VolumeFeatures.PaniniProjection;
|
|
if (asset.Has<ChromaticAberration>())
|
|
s_VolumeFeatures |= VolumeFeatures.ChromaticAberration;
|
|
}
|
|
}
|
|
|
|
private static ShaderFeatures GetSupportedShaderFeatures(UniversalRenderPipelineAsset pipelineAsset, int rendererIndex)
|
|
{
|
|
ShaderFeatures shaderFeatures;
|
|
shaderFeatures = ShaderFeatures.MainLight;
|
|
|
|
if (pipelineAsset.supportsMainLightShadows)
|
|
{
|
|
// User can change cascade count at runtime, so we have to include both of them for now
|
|
shaderFeatures |= ShaderFeatures.MainLightShadows;
|
|
shaderFeatures |= ShaderFeatures.MainLightShadowsCascade;
|
|
}
|
|
|
|
if (pipelineAsset.additionalLightsRenderingMode == LightRenderingMode.PerVertex)
|
|
{
|
|
shaderFeatures |= ShaderFeatures.VertexLighting;
|
|
}
|
|
else if (pipelineAsset.additionalLightsRenderingMode == LightRenderingMode.PerPixel)
|
|
{
|
|
shaderFeatures |= ShaderFeatures.AdditionalLights;
|
|
}
|
|
|
|
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;
|
|
|
|
if (pipelineAsset.supportsLightLayers)
|
|
shaderFeatures |= ShaderFeatures.LightLayers;
|
|
|
|
bool hasScreenSpaceShadows = false;
|
|
bool hasScreenSpaceOcclusion = false;
|
|
bool hasDeferredRenderer = false;
|
|
bool accurateGbufferNormals = false;
|
|
bool clusteredRendering = false;
|
|
bool onlyClusteredRendering = false;
|
|
bool usesRenderPass = false;
|
|
|
|
{
|
|
ScriptableRenderer renderer = pipelineAsset.GetRenderer(rendererIndex);
|
|
if (renderer is UniversalRenderer)
|
|
{
|
|
UniversalRenderer universalRenderer = (UniversalRenderer)renderer;
|
|
if (universalRenderer.renderingMode == RenderingMode.Deferred)
|
|
{
|
|
hasDeferredRenderer |= true;
|
|
accurateGbufferNormals |= universalRenderer.accurateGbufferNormals;
|
|
usesRenderPass |= universalRenderer.useRenderPassEnabled;
|
|
}
|
|
}
|
|
|
|
if (!renderer.stripShadowsOffVariants)
|
|
shaderFeatures |= ShaderFeatures.ShadowsKeepOffVariants;
|
|
|
|
if (!renderer.stripAdditionalLightOffVariants)
|
|
shaderFeatures |= ShaderFeatures.AdditionalLightsKeepOffVariants;
|
|
|
|
var rendererClustered = false;
|
|
|
|
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;
|
|
|
|
// Check for Screen Space Ambient Occlusion Renderer Feature
|
|
ScreenSpaceAmbientOcclusion ssao = rendererFeature as ScreenSpaceAmbientOcclusion;
|
|
hasScreenSpaceOcclusion |= ssao != null;
|
|
|
|
if (ssao?.afterOpaque ?? false)
|
|
shaderFeatures |= ShaderFeatures.ScreenSpaceOcclusionAfterOpaque;
|
|
|
|
// Check for Decal Renderer Feature
|
|
DecalRendererFeature decal = rendererFeature as DecalRendererFeature;
|
|
if (decal != null)
|
|
{
|
|
var technique = decal.GetTechnique(renderer);
|
|
switch (technique)
|
|
{
|
|
case DecalTechnique.DBuffer:
|
|
shaderFeatures |= GetFromDecalSurfaceData(decal.GetDBufferSettings().surfaceData);
|
|
break;
|
|
case DecalTechnique.ScreenSpace:
|
|
shaderFeatures |= GetFromNormalBlend(decal.GetScreenSpaceSettings().normalBlend);
|
|
shaderFeatures |= ShaderFeatures.DecalScreenSpace;
|
|
break;
|
|
case DecalTechnique.GBuffer:
|
|
shaderFeatures |= GetFromNormalBlend(decal.GetScreenSpaceSettings().normalBlend);
|
|
shaderFeatures |= ShaderFeatures.DecalGBuffer;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (rendererData is UniversalRendererData universalRendererData)
|
|
{
|
|
rendererClustered = universalRendererData.renderingMode == RenderingMode.Forward &&
|
|
universalRendererData.clusteredRendering;
|
|
|
|
#if ENABLE_VR && ENABLE_XR_MODULE
|
|
if (universalRendererData.xrSystemData != null)
|
|
shaderFeatures |= ShaderFeatures.DrawProcedural;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
clusteredRendering |= rendererClustered;
|
|
onlyClusteredRendering &= rendererClustered;
|
|
}
|
|
|
|
if (hasDeferredRenderer)
|
|
shaderFeatures |= ShaderFeatures.DeferredShading;
|
|
|
|
if (accurateGbufferNormals)
|
|
shaderFeatures |= ShaderFeatures.AccurateGbufferNormals;
|
|
|
|
if (hasScreenSpaceShadows)
|
|
shaderFeatures |= ShaderFeatures.ScreenSpaceShadows;
|
|
|
|
if (hasScreenSpaceOcclusion)
|
|
shaderFeatures |= ShaderFeatures.ScreenSpaceOcclusion;
|
|
|
|
if (usesRenderPass)
|
|
shaderFeatures |= ShaderFeatures.RenderPassEnabled;
|
|
|
|
if (pipelineAsset.reflectionProbeBlending)
|
|
shaderFeatures |= ShaderFeatures.ReflectionProbeBlending;
|
|
|
|
if (pipelineAsset.reflectionProbeBoxProjection)
|
|
shaderFeatures |= ShaderFeatures.ReflectionProbeBoxProjection;
|
|
|
|
if (clusteredRendering)
|
|
{
|
|
shaderFeatures |= ShaderFeatures.ClusteredRendering;
|
|
}
|
|
|
|
if (onlyClusteredRendering)
|
|
{
|
|
shaderFeatures &= ~(ShaderFeatures.AdditionalLights | ShaderFeatures.VertexLighting);
|
|
}
|
|
|
|
if (pipelineAsset.additionalLightsRenderingMode == LightRenderingMode.PerPixel || clusteredRendering)
|
|
{
|
|
if (pipelineAsset.supportsAdditionalLightShadows)
|
|
{
|
|
shaderFeatures |= ShaderFeatures.AdditionalLightShadows;
|
|
}
|
|
}
|
|
|
|
return shaderFeatures;
|
|
}
|
|
|
|
private static ShaderFeatures GetFromDecalSurfaceData(DecalSurfaceData surfaceData)
|
|
{
|
|
ShaderFeatures shaderFeatures = ShaderFeatures.None;
|
|
switch (surfaceData)
|
|
{
|
|
case DecalSurfaceData.Albedo:
|
|
shaderFeatures |= ShaderFeatures.DBufferMRT1;
|
|
break;
|
|
case DecalSurfaceData.AlbedoNormal:
|
|
shaderFeatures |= ShaderFeatures.DBufferMRT2;
|
|
break;
|
|
case DecalSurfaceData.AlbedoNormalMAOS:
|
|
shaderFeatures |= ShaderFeatures.DBufferMRT3;
|
|
break;
|
|
}
|
|
return shaderFeatures;
|
|
}
|
|
|
|
private static ShaderFeatures GetFromNormalBlend(DecalNormalBlend normalBlend)
|
|
{
|
|
ShaderFeatures shaderFeatures = ShaderFeatures.None;
|
|
switch (normalBlend)
|
|
{
|
|
case DecalNormalBlend.Low:
|
|
shaderFeatures |= ShaderFeatures.DecalNormalBlendLow;
|
|
break;
|
|
case DecalNormalBlend.Medium:
|
|
shaderFeatures |= ShaderFeatures.DecalNormalBlendMedium;
|
|
break;
|
|
case DecalNormalBlend.High:
|
|
shaderFeatures |= ShaderFeatures.DecalNormalBlendHigh;
|
|
break;
|
|
}
|
|
return shaderFeatures;
|
|
}
|
|
}
|
|
}
|