浏览代码

refactor shader variant per material + Add variant stripper for stacklit and selection

/main
Sebastien Lagarde 7 年前
当前提交
dcbff94f
共有 17 个文件被更改,包括 291 次插入98 次删除
  1. 103
      com.unity.render-pipelines.high-definition/HDRP/Editor/BuildProcessors/HDRPreprocessShaders.cs
  2. 14
      com.unity.render-pipelines.high-definition/HDRP/Editor/RenderPipeline/HDEditorUtils.cs
  3. 2
      com.unity.render-pipelines.high-definition/HDRP/Material/LayeredLit/LayeredLit.shader
  4. 2
      com.unity.render-pipelines.high-definition/HDRP/Material/LayeredLit/LayeredLitTessellation.shader
  5. 2
      com.unity.render-pipelines.high-definition/HDRP/Material/Lit/Lit.shader
  6. 2
      com.unity.render-pipelines.high-definition/HDRP/Material/Lit/LitTessellation.shader
  7. 23
      com.unity.render-pipelines.high-definition/HDRP/Material/StackLit/StackLit.shader
  8. 4
      com.unity.render-pipelines.high-definition/HDRP/Material/StackLit/StackLitProperties.hlsl
  9. 2
      com.unity.render-pipelines.high-definition/HDRP/Material/Unlit/Unlit.shader
  10. 69
      com.unity.render-pipelines.high-definition/HDRP/Editor/Material/Lit/LitShaderPreprocessor.cs
  11. 11
      com.unity.render-pipelines.high-definition/HDRP/Editor/Material/Lit/LitShaderPreprocessor.cs.meta
  12. 76
      com.unity.render-pipelines.high-definition/HDRP/Editor/Material/ShaderPreprocessorMaterial.cs
  13. 11
      com.unity.render-pipelines.high-definition/HDRP/Editor/Material/ShaderPreprocessorMaterial.cs.meta
  14. 23
      com.unity.render-pipelines.high-definition/HDRP/Editor/Material/StackLit/StackLitShaderPreprocessor.cs
  15. 11
      com.unity.render-pipelines.high-definition/HDRP/Editor/Material/StackLit/StackLitShaderPreprocessor.cs.meta
  16. 23
      com.unity.render-pipelines.high-definition/HDRP/Editor/Material/Unlit/UnlitShaderPreprocessor.cs
  17. 11
      com.unity.render-pipelines.high-definition/HDRP/Editor/Material/Unlit/UnlitShaderPreprocessor.cs.meta

103
com.unity.render-pipelines.high-definition/HDRP/Editor/BuildProcessors/HDRPreprocessShaders.cs


{
class HDRPreprocessShaders : IPreprocessShaders
{
// returns true if the variant should be stripped.
delegate bool VariantStrippingFunc(Shader shader, ShaderSnippetData snippet, ShaderCompilerData inputData);
ShaderKeyword m_ShadowMask;
ShaderKeyword m_Transparent;
ShaderKeyword m_DebugDisplay;
ShaderKeyword m_TileLighting;
ShaderKeyword m_ClusterLighting;
//ShaderKeyword m_FeatureSSS;
public HDRPreprocessShaders()
{
// TODO: Grab correct configuration/quality asset.

m_StripperFuncs = new Dictionary<string, VariantStrippingFunc>();
m_StripperFuncs.Add("HDRenderPipeline/Lit", LitShaderStripper);
m_StripperFuncs.Add("HDRenderPipeline/LitTessellation", LitShaderStripper);
m_StripperFuncs.Add("HDRenderPipeline/LayeredLit", LitShaderStripper);
m_StripperFuncs.Add("HDRenderPipeline/LayeredLitTessellation", LitShaderStripper);
m_StripperFuncs.Add("HDRenderPipeline/Unlit", UnlitShaderStripper);
m_Transparent = new ShaderKeyword("_SURFACE_TYPE_TRANSPARENT");
m_DebugDisplay = new ShaderKeyword("DEBUG_DISPLAY");
m_TileLighting = new ShaderKeyword("USE_FPTL_LIGHTLIST");
m_ClusterLighting = new ShaderKeyword("USE_CLUSTERED_LIGHTLIST");
//m_FeatureSSS = new ShaderKeyword("_MATERIAL_FEATURE_SUBSURFACE_SCATTERING");
}
bool UnlitShaderStripper(Shader shader, ShaderSnippetData snippet, ShaderCompilerData inputData)
{
bool isSceneSelectionPass = snippet.passName == "SceneSelectionPass";
if (isSceneSelectionPass)
return true;
return false;
}
bool LitShaderStripper(Shader shader, ShaderSnippetData snippet, ShaderCompilerData inputData)
{
bool isSceneSelectionPass = snippet.passName == "SceneSelectionPass";
if (isSceneSelectionPass)
return true;
List<ShaderPreprocessorMaterial> materialList = HDEditorUtils.GetShaderPreprocessorMaterialList();
bool isGBufferPass = snippet.passName == "GBuffer";
bool isForwardPass = snippet.passName == "Forward";
bool isTransparentForwardPass = snippet.passName == "TransparentDepthPostpass" || snippet.passName == "TransparentBackface" || snippet.passName == "TransparentDepthPrepass";
bool isMotionPass = snippet.passName == "Motion Vectors";
// 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
if (!m_CurrentHDRPAsset.renderPipelineSettings.supportMotionVectors && isMotionPass)
return true;
// When using forward only, we never need GBuffer pass (only Forward)
if (m_CurrentHDRPAsset.renderPipelineSettings.supportOnlyForward && isGBufferPass)
return true;
if (inputData.shaderKeywordSet.IsEnabled(m_Transparent))
// Fill the dictionary with material to handle
foreach (ShaderPreprocessorMaterial material in materialList)
// If transparent, we never need GBuffer pass.
if (isGBufferPass)
return true;
// We will also use cluster instead of tile
if (inputData.shaderKeywordSet.IsEnabled(m_TileLighting))
return true;
material.AddStripperFuncs(m_StripperFuncs);
else // Opaque
{
// If opaque, we never need transparent specific passes (even in forward only mode)
if (isTransparentForwardPass)
return true;
if (!m_CurrentHDRPAsset.renderPipelineSettings.supportOnlyForward && inputData.shaderKeywordSet.IsEnabled(m_ClusterLighting))
return true;
if (!m_CurrentHDRPAsset.renderPipelineSettings.supportOnlyForward)
{
// If opaque and not forward only, then we only need the forward debug pass.
if (isForwardPass && !inputData.shaderKeywordSet.IsEnabled(m_DebugDisplay))
return true;
}
}
// TODO: Expose development build flag.
//if (developmentBuild && 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 int callbackOrder { get { return 0; } }

for (int i = 0; i < inputData.Count; ++i)
{
ShaderCompilerData input = inputData[i];
if (stripperFunc(shader, snippet, input))
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);
}

14
com.unity.render-pipelines.high-definition/HDRP/Editor/RenderPipeline/HDEditorUtils.cs


}
return false;
}
public static List<ShaderPreprocessorMaterial> GetShaderPreprocessorMaterialList()
{
var baseType = typeof(ShaderPreprocessorMaterial);
var assembly = baseType.Assembly;
var types = assembly.GetTypes()
.Where(t => t.IsSubclassOf(baseType))
.Select(Activator.CreateInstance)
.Cast<ShaderPreprocessorMaterial>()
.ToList();
return types;
}
}
}

2
com.unity.render-pipelines.high-definition/HDRP/Material/LayeredLit/LayeredLit.shader


HLSLPROGRAM
// Note: Require _ObjectId and _PassValue variables
#define SHADERPASS SHADERPASS_DEPTH_ONLY
#define SCENESELECTIONPASS // This will drive the output of the scene selection shader
#include "../../ShaderVariables.hlsl"

2
com.unity.render-pipelines.high-definition/HDRP/Material/LayeredLit/LayeredLitTessellation.shader


HLSLPROGRAM
// Note: Require _ObjectId and _PassValue variables
#pragma hull Hull
#pragma domain Domain

2
com.unity.render-pipelines.high-definition/HDRP/Material/Lit/Lit.shader


HLSLPROGRAM
// Note: Require _ObjectId and _PassValue variables
// We reuse depth prepass for the scene selection, allow to handle alpha correctly as well as tessellation and vertex animation
#define SHADERPASS SHADERPASS_DEPTH_ONLY
#define SCENESELECTIONPASS // This will drive the output of the scene selection shader

2
com.unity.render-pipelines.high-definition/HDRP/Material/Lit/LitTessellation.shader


HLSLPROGRAM
// Note: Require _ObjectId and _PassValue variables
#pragma hull Hull
#pragma domain Domain

23
com.unity.render-pipelines.high-definition/HDRP/Material/StackLit/StackLit.shader


// This tags allow to use the shader replacement features
Tags{ "RenderPipeline" = "HDRenderPipeline" "RenderType" = "HDStackLitShader" }
// Caution: The outline selection in the editor use the vertex shader/hull/domain shader of the first pass declare. So it should not be the meta pass.
Pass
{
Name "SceneSelectionPass" // Name is not used
Tags { "LightMode" = "SceneSelectionPass" }
Cull Off
HLSLPROGRAM
// Note: Require _ObjectId and _PassValue variables
// We reuse depth prepass for the scene selection, allow to handle alpha correctly as well as tessellation and vertex animation
#define SHADERPASS SHADERPASS_DEPTH_ONLY
#define SCENESELECTIONPASS // This will drive the output of the scene selection shader
#include "../../ShaderVariables.hlsl"
#include "../../Material/Material.hlsl"
#include "ShaderPass/StackLitDepthPass.hlsl"
#include "StackLitData.hlsl"
#include "../../ShaderPass/ShaderPassDepthOnly.hlsl"
ENDHLSL
}
Pass
{

4
com.unity.render-pipelines.high-definition/HDRP/Material/StackLit/StackLitProperties.hlsl


// TODO: Fix the code in legacy unity so we can customize the behavior for GI
float3 _EmissionColor;
// Following two variables are feeded by the C++ Editor for Scene selection
int _ObjectId;
int _PassValue;
CBUFFER_END

2
com.unity.render-pipelines.high-definition/HDRP/Material/Unlit/Unlit.shader


HLSLPROGRAM
// Note: Require _ObjectId and _PassValue variables
#define SHADERPASS SHADERPASS_DEPTH_ONLY
#define SCENESELECTIONPASS // This will drive the output of the scene selection shader
#include "../../Material/Material.hlsl"

69
com.unity.render-pipelines.high-definition/HDRP/Editor/Material/Lit/LitShaderPreprocessor.cs


using System;
using System.Collections.Generic;
using UnityEditor.Build;
using UnityEditor.Rendering;
using UnityEngine;
using UnityEngine.Experimental.Rendering.HDPipeline;
namespace UnityEditor.Experimental.Rendering.HDPipeline
{
public class LitShaderPreprocessor : ShaderPreprocessorMaterial
{
bool LitShaderStripper(HDRenderPipelineAsset hdrpAsset, Shader shader, ShaderSnippetData snippet, ShaderCompilerData inputData)
{
if (CommonShaderStripper(hdrpAsset, shader, snippet, inputData))
return true;
bool isGBufferPass = snippet.passName == "GBuffer";
bool isForwardPass = snippet.passName == "Forward";
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.supportOnlyForward && 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;
// 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 (!hdrpAsset.renderPipelineSettings.supportOnlyForward)
{
// 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 void AddStripperFuncs(Dictionary<string, VariantStrippingFunc> stripperFuncs)
{
// Add name of the shader and corresponding delegate to call to strip variant
stripperFuncs.Add("HDRenderPipeline/Lit", LitShaderStripper);
stripperFuncs.Add("HDRenderPipeline/LitTessellation", LitShaderStripper);
stripperFuncs.Add("HDRenderPipeline/LayeredLit", LitShaderStripper);
stripperFuncs.Add("HDRenderPipeline/LayeredLitTessellation", LitShaderStripper);
}
}
}

11
com.unity.render-pipelines.high-definition/HDRP/Editor/Material/Lit/LitShaderPreprocessor.cs.meta


fileFormatVersion: 2
guid: 203e4ecfbd605d54d89374ef35e914c0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

76
com.unity.render-pipelines.high-definition/HDRP/Editor/Material/ShaderPreprocessorMaterial.cs


using System;
using System.Collections.Generic;
using UnityEditor.Build;
using UnityEditor.Rendering;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Experimental.Rendering.HDPipeline;
namespace UnityEditor.Experimental.Rendering.HDPipeline
{
// returns true if the variant should be stripped.
public delegate bool VariantStrippingFunc(HDRenderPipelineAsset hdrpAsset, Shader shader, ShaderSnippetData snippet, ShaderCompilerData inputData);
public class ShaderPreprocessorMaterial
{
protected ShaderKeyword m_ShadowMask;
protected ShaderKeyword m_Transparent;
protected ShaderKeyword m_DebugDisplay;
protected ShaderKeyword m_TileLighting;
protected ShaderKeyword m_ClusterLighting;
public ShaderPreprocessorMaterial()
{
m_Transparent = new ShaderKeyword("_SURFACE_TYPE_TRANSPARENT");
m_DebugDisplay = new ShaderKeyword("DEBUG_DISPLAY");
m_TileLighting = new ShaderKeyword("USE_FPTL_LIGHTLIST");
m_ClusterLighting = new ShaderKeyword("USE_CLUSTERED_LIGHTLIST");
}
public virtual void AddStripperFuncs(Dictionary<string, VariantStrippingFunc> stripperFuncs) {}
// 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 adn it depends on MSAA
}
// TODO: If static lighting we can remove meta pass, but how to know that?
// TODO: Expose development build flag.
//if (developmentBuild && inputData.shaderKeywordSet.IsEnabled(m_DebugDisplay))
// return true;
return false;
}
}
}

11
com.unity.render-pipelines.high-definition/HDRP/Editor/Material/ShaderPreprocessorMaterial.cs.meta


fileFormatVersion: 2
guid: c23f3fe1f63fff240a5cf70cf0a62c93
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

23
com.unity.render-pipelines.high-definition/HDRP/Editor/Material/StackLit/StackLitShaderPreprocessor.cs


using System;
using System.Collections.Generic;
using UnityEditor.Build;
using UnityEditor.Rendering;
using UnityEngine;
using UnityEngine.Experimental.Rendering.HDPipeline;
namespace UnityEditor.Experimental.Rendering.HDPipeline
{
public class StackLitShaderPreprocessor : ShaderPreprocessorMaterial
{
bool StackLitShaderStripper(HDRenderPipelineAsset hdrpAsset, Shader shader, ShaderSnippetData snippet, ShaderCompilerData inputData)
{
return CommonShaderStripper(hdrpAsset, shader, snippet, inputData);
}
public override void AddStripperFuncs(Dictionary<string, VariantStrippingFunc> stripperFuncs)
{
// Add name of the shader and corresponding delegate to call to strip variant
stripperFuncs.Add("HDRenderPipeline/StackLit", StackLitShaderStripper);
}
}
}

11
com.unity.render-pipelines.high-definition/HDRP/Editor/Material/StackLit/StackLitShaderPreprocessor.cs.meta


fileFormatVersion: 2
guid: 238a7258cd3744f4c9d619f4355c3019
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

23
com.unity.render-pipelines.high-definition/HDRP/Editor/Material/Unlit/UnlitShaderPreprocessor.cs


using System;
using System.Collections.Generic;
using UnityEditor.Build;
using UnityEditor.Rendering;
using UnityEngine;
using UnityEngine.Experimental.Rendering.HDPipeline;
namespace UnityEditor.Experimental.Rendering.HDPipeline
{
public class UnlitShaderPreprocessor : ShaderPreprocessorMaterial
{
bool UnlitShaderStripper(HDRenderPipelineAsset hdrpAsset, Shader shader, ShaderSnippetData snippet, ShaderCompilerData inputData)
{
return CommonShaderStripper(hdrpAsset, shader, snippet, inputData);
}
public override void AddStripperFuncs(Dictionary<string, VariantStrippingFunc> stripperFuncs)
{
// Add name of the shader and corresponding delegate to call to strip variant
stripperFuncs.Add("HDRenderPipeline/Unlit", UnlitShaderStripper);
}
}
}

11
com.unity.render-pipelines.high-definition/HDRP/Editor/Material/Unlit/UnlitShaderPreprocessor.cs.meta


fileFormatVersion: 2
guid: b9d6d9aeb9ea7a5449eb51aa059a75b8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
正在加载...
取消
保存