From 5bfe484f5daff1531ff2b3efef7836fabbeae78c Mon Sep 17 00:00:00 2001 From: ssdfasd <2156608475@qq.com> Date: Tue, 7 Apr 2026 04:30:26 +0800 Subject: [PATCH] Formalize builtin fullscreen shaders --- .../color-scale-post-process.frag.glsl | 16 - .../color-scale-post-process.frag.vk.glsl | 17 - .../color-scale-post-process.ps.hlsl | 16 - .../color-scale-post-process.shader | 57 ++- .../color-scale-post-process.vert.glsl | 16 - .../color-scale-post-process.vert.vk.glsl | 18 - .../color-scale-post-process.vs.hlsl | 22 -- .../shaders/final-color/final-color.frag.glsl | 65 --- .../final-color/final-color.frag.vk.glsl | 66 ---- .../shaders/final-color/final-color.ps.hlsl | 65 --- .../shaders/final-color/final-color.shader | 111 +++++- .../shaders/final-color/final-color.vert.glsl | 16 - .../final-color/final-color.vert.vk.glsl | 18 - .../shaders/final-color/final-color.vs.hlsl | 22 -- .../builtin/shaders/skybox/skybox.frag.glsl | 79 ---- .../shaders/skybox/skybox.frag.vk.glsl | 80 ---- .../builtin/shaders/skybox/skybox.ps.hlsl | 79 ---- .../builtin/shaders/skybox/skybox.shader | 117 +++++- .../builtin/shaders/skybox/skybox.vert.glsl | 16 - .../shaders/skybox/skybox.vert.vk.glsl | 16 - .../builtin/shaders/skybox/skybox.vs.hlsl | 18 - .../camera_post_process_scene/main.cpp | 2 +- .../integration/final_color_scene/main.cpp | 2 +- .../integration/post_process_scene/main.cpp | 2 +- .../unit/test_builtin_forward_pipeline.cpp | 369 ++++++++++++++++-- tests/Resources/Shader/test_shader_loader.cpp | 154 ++++++++ 26 files changed, 746 insertions(+), 713 deletions(-) delete mode 100644 engine/assets/builtin/shaders/color-scale-post-process/color-scale-post-process.frag.glsl delete mode 100644 engine/assets/builtin/shaders/color-scale-post-process/color-scale-post-process.frag.vk.glsl delete mode 100644 engine/assets/builtin/shaders/color-scale-post-process/color-scale-post-process.ps.hlsl delete mode 100644 engine/assets/builtin/shaders/color-scale-post-process/color-scale-post-process.vert.glsl delete mode 100644 engine/assets/builtin/shaders/color-scale-post-process/color-scale-post-process.vert.vk.glsl delete mode 100644 engine/assets/builtin/shaders/color-scale-post-process/color-scale-post-process.vs.hlsl delete mode 100644 engine/assets/builtin/shaders/final-color/final-color.frag.glsl delete mode 100644 engine/assets/builtin/shaders/final-color/final-color.frag.vk.glsl delete mode 100644 engine/assets/builtin/shaders/final-color/final-color.ps.hlsl delete mode 100644 engine/assets/builtin/shaders/final-color/final-color.vert.glsl delete mode 100644 engine/assets/builtin/shaders/final-color/final-color.vert.vk.glsl delete mode 100644 engine/assets/builtin/shaders/final-color/final-color.vs.hlsl delete mode 100644 engine/assets/builtin/shaders/skybox/skybox.frag.glsl delete mode 100644 engine/assets/builtin/shaders/skybox/skybox.frag.vk.glsl delete mode 100644 engine/assets/builtin/shaders/skybox/skybox.ps.hlsl delete mode 100644 engine/assets/builtin/shaders/skybox/skybox.vert.glsl delete mode 100644 engine/assets/builtin/shaders/skybox/skybox.vert.vk.glsl delete mode 100644 engine/assets/builtin/shaders/skybox/skybox.vs.hlsl diff --git a/engine/assets/builtin/shaders/color-scale-post-process/color-scale-post-process.frag.glsl b/engine/assets/builtin/shaders/color-scale-post-process/color-scale-post-process.frag.glsl deleted file mode 100644 index 02c1c96d..00000000 --- a/engine/assets/builtin/shaders/color-scale-post-process/color-scale-post-process.frag.glsl +++ /dev/null @@ -1,16 +0,0 @@ -// XC_BUILTIN_COLOR_SCALE_POST_PROCESS_OPENGL_PS -#version 430 - -layout(binding = 0) uniform sampler2D uSourceColorTexture; - -layout(std140, binding = 0) uniform PostProcessConstants { - vec4 gColorScale; -}; - -in vec2 vTexCoord; - -layout(location = 0) out vec4 fragColor; - -void main() { - fragColor = texture(uSourceColorTexture, vTexCoord) * gColorScale; -} diff --git a/engine/assets/builtin/shaders/color-scale-post-process/color-scale-post-process.frag.vk.glsl b/engine/assets/builtin/shaders/color-scale-post-process/color-scale-post-process.frag.vk.glsl deleted file mode 100644 index 7a06bf1a..00000000 --- a/engine/assets/builtin/shaders/color-scale-post-process/color-scale-post-process.frag.vk.glsl +++ /dev/null @@ -1,17 +0,0 @@ -// XC_BUILTIN_COLOR_SCALE_POST_PROCESS_VULKAN_PS -#version 450 - -layout(set = 0, binding = 0, std140) uniform PostProcessConstants { - vec4 gColorScale; -}; - -layout(set = 1, binding = 0) uniform texture2D uSourceColorTexture; -layout(set = 2, binding = 0) uniform sampler uLinearClampSampler; - -layout(location = 0) in vec2 vTexCoord; - -layout(location = 0) out vec4 fragColor; - -void main() { - fragColor = texture(sampler2D(uSourceColorTexture, uLinearClampSampler), vTexCoord) * gColorScale; -} diff --git a/engine/assets/builtin/shaders/color-scale-post-process/color-scale-post-process.ps.hlsl b/engine/assets/builtin/shaders/color-scale-post-process/color-scale-post-process.ps.hlsl deleted file mode 100644 index 6774ac3a..00000000 --- a/engine/assets/builtin/shaders/color-scale-post-process/color-scale-post-process.ps.hlsl +++ /dev/null @@ -1,16 +0,0 @@ -// XC_BUILTIN_COLOR_SCALE_POST_PROCESS_D3D12_PS -Texture2D gSourceColorTexture : register(t0); -SamplerState gLinearClampSampler : register(s0); - -cbuffer PostProcessConstants : register(b0) { - float4 gColorScale; -}; - -struct PSInput { - float4 position : SV_POSITION; - float2 texcoord : TEXCOORD0; -}; - -float4 MainPS(PSInput input) : SV_TARGET { - return gSourceColorTexture.Sample(gLinearClampSampler, input.texcoord) * gColorScale; -} diff --git a/engine/assets/builtin/shaders/color-scale-post-process/color-scale-post-process.shader b/engine/assets/builtin/shaders/color-scale-post-process/color-scale-post-process.shader index 5ae4f4de..cc06c4fd 100644 --- a/engine/assets/builtin/shaders/color-scale-post-process/color-scale-post-process.shader +++ b/engine/assets/builtin/shaders/color-scale-post-process/color-scale-post-process.shader @@ -4,24 +4,63 @@ Shader "Builtin Color Scale Post Process" { _ColorScale ("Color Scale", Color) = (0.65,0.80,1.00,1.0) } + HLSLINCLUDE + cbuffer PostProcessConstants : register(b0) + { + float4 gColorScale; + }; + + Texture2D gSourceColorTexture : register(t0); + SamplerState gLinearClampSampler : register(s0); + + struct VSOutput + { + float4 position : SV_POSITION; + float2 texcoord : TEXCOORD0; + }; + + VSOutput MainVS(uint vertexId : SV_VertexID) + { + const float2 positions[3] = { + float2(-1.0f, -1.0f), + float2(-1.0f, 3.0f), + float2( 3.0f, -1.0f) + }; + + const float2 position = positions[vertexId]; + + VSOutput output; + output.position = float4(position, 1.0f, 1.0f); + + float2 uv = float2( + position.x * 0.5f + 0.5f, + position.y * 0.5f + 0.5f); + #if UNITY_UV_STARTS_AT_TOP + uv.y = 1.0f - uv.y; + #endif + output.texcoord = uv; + return output; + } + + float4 MainPS(VSOutput input) : SV_TARGET + { + return gSourceColorTexture.Sample(gLinearClampSampler, input.texcoord) * gColorScale; + } + ENDHLSL SubShader { Pass { Name "ColorScale" Tags { "LightMode" = "PostProcess" } - Resources - { - PostProcessConstants (ConstantBuffer, 0, 0) - SourceColorTexture (Texture2D, 1, 0) - LinearClampSampler (Sampler, 2, 0) - } + Cull Off + ZWrite Off + ZTest Always + Blend Off HLSLPROGRAM + #pragma target 4.5 #pragma vertex MainVS #pragma fragment MainPS - #pragma backend D3D12 HLSL "color-scale-post-process.vs.hlsl" "color-scale-post-process.ps.hlsl" vs_5_0 ps_5_0 - #pragma backend OpenGL GLSL "color-scale-post-process.vert.glsl" "color-scale-post-process.frag.glsl" - #pragma backend Vulkan GLSL "color-scale-post-process.vert.vk.glsl" "color-scale-post-process.frag.vk.glsl" ENDHLSL } } diff --git a/engine/assets/builtin/shaders/color-scale-post-process/color-scale-post-process.vert.glsl b/engine/assets/builtin/shaders/color-scale-post-process/color-scale-post-process.vert.glsl deleted file mode 100644 index 78b7e98a..00000000 --- a/engine/assets/builtin/shaders/color-scale-post-process/color-scale-post-process.vert.glsl +++ /dev/null @@ -1,16 +0,0 @@ -// XC_BUILTIN_COLOR_SCALE_POST_PROCESS_OPENGL_VS -#version 430 - -out vec2 vTexCoord; - -void main() { - const vec2 positions[3] = vec2[3]( - vec2(-1.0, -1.0), - vec2(-1.0, 3.0), - vec2( 3.0, -1.0) - ); - - vec2 position = positions[gl_VertexID]; - gl_Position = vec4(position, 1.0, 1.0); - vTexCoord = position * 0.5 + 0.5; -} diff --git a/engine/assets/builtin/shaders/color-scale-post-process/color-scale-post-process.vert.vk.glsl b/engine/assets/builtin/shaders/color-scale-post-process/color-scale-post-process.vert.vk.glsl deleted file mode 100644 index 7afd9bb8..00000000 --- a/engine/assets/builtin/shaders/color-scale-post-process/color-scale-post-process.vert.vk.glsl +++ /dev/null @@ -1,18 +0,0 @@ -// XC_BUILTIN_COLOR_SCALE_POST_PROCESS_VULKAN_VS -#version 450 - -layout(location = 0) out vec2 vTexCoord; - -void main() { - const vec2 positions[3] = vec2[3]( - vec2(-1.0, -1.0), - vec2(-1.0, 3.0), - vec2( 3.0, -1.0) - ); - - vec2 position = positions[gl_VertexIndex]; - gl_Position = vec4(position, 1.0, 1.0); - vTexCoord = vec2( - position.x * 0.5 + 0.5, - 1.0 - (position.y * 0.5 + 0.5)); -} diff --git a/engine/assets/builtin/shaders/color-scale-post-process/color-scale-post-process.vs.hlsl b/engine/assets/builtin/shaders/color-scale-post-process/color-scale-post-process.vs.hlsl deleted file mode 100644 index c3b9002d..00000000 --- a/engine/assets/builtin/shaders/color-scale-post-process/color-scale-post-process.vs.hlsl +++ /dev/null @@ -1,22 +0,0 @@ -// XC_BUILTIN_COLOR_SCALE_POST_PROCESS_D3D12_VS -struct VSOutput { - float4 position : SV_POSITION; - float2 texcoord : TEXCOORD0; -}; - -VSOutput MainVS(uint vertexId : SV_VertexID) { - const float2 positions[3] = { - float2(-1.0f, -1.0f), - float2(-1.0f, 3.0f), - float2( 3.0f, -1.0f) - }; - - const float2 position = positions[vertexId]; - - VSOutput output; - output.position = float4(position, 1.0f, 1.0f); - output.texcoord = float2( - position.x * 0.5f + 0.5f, - 1.0f - (position.y * 0.5f + 0.5f)); - return output; -} diff --git a/engine/assets/builtin/shaders/final-color/final-color.frag.glsl b/engine/assets/builtin/shaders/final-color/final-color.frag.glsl deleted file mode 100644 index 891e0949..00000000 --- a/engine/assets/builtin/shaders/final-color/final-color.frag.glsl +++ /dev/null @@ -1,65 +0,0 @@ -// XC_BUILTIN_FINAL_COLOR_OPENGL_PS -#version 430 - -layout(binding = 0) uniform sampler2D uSourceColorTexture; - -layout(std140, binding = 0) uniform FinalColorConstants { - vec4 gColorScale; - vec4 gFinalColorParams; -}; - -in vec2 vTexCoord; - -layout(location = 0) out vec4 fragColor; - -float SRGBEncodeChannel(float value) { - float linear = max(value, 0.0); - return linear <= 0.0031308 - ? linear * 12.92 - : 1.055 * pow(linear, 1.0 / 2.4) - 0.055; -} - -vec3 ApplyLinearToSRGB(vec3 color) { - return vec3( - SRGBEncodeChannel(color.r), - SRGBEncodeChannel(color.g), - SRGBEncodeChannel(color.b)); -} - -vec3 ApplyNeutralToneMapping(vec3 color) { - return color / (color + vec3(1.0)); -} - -vec3 ApplyAcesToneMapping(vec3 color) { - const float a = 2.51; - const float b = 0.03; - const float c = 2.43; - const float d = 0.59; - const float e = 0.14; - return clamp((color * (a * color + b)) / (color * (c * color + d) + e), 0.0, 1.0); -} - -vec3 ApplyToneMapping(vec3 color, float toneMappingMode) { - if (toneMappingMode > 1.5) { - return ApplyAcesToneMapping(color); - } - - if (toneMappingMode > 0.5) { - return ApplyNeutralToneMapping(color); - } - - return color; -} - -void main() { - vec4 color = texture(uSourceColorTexture, vTexCoord); - color.rgb *= max(gFinalColorParams.x, 0.0); - color *= gColorScale; - color.rgb = ApplyToneMapping(color.rgb, gFinalColorParams.z); - - if (gFinalColorParams.y > 0.5) { - color.rgb = ApplyLinearToSRGB(color.rgb); - } - - fragColor = color; -} diff --git a/engine/assets/builtin/shaders/final-color/final-color.frag.vk.glsl b/engine/assets/builtin/shaders/final-color/final-color.frag.vk.glsl deleted file mode 100644 index b4e595a3..00000000 --- a/engine/assets/builtin/shaders/final-color/final-color.frag.vk.glsl +++ /dev/null @@ -1,66 +0,0 @@ -// XC_BUILTIN_FINAL_COLOR_VULKAN_PS -#version 450 - -layout(set = 0, binding = 0, std140) uniform FinalColorConstants { - vec4 gColorScale; - vec4 gFinalColorParams; -}; - -layout(set = 1, binding = 0) uniform texture2D uSourceColorTexture; -layout(set = 2, binding = 0) uniform sampler uLinearClampSampler; - -layout(location = 0) in vec2 vTexCoord; - -layout(location = 0) out vec4 fragColor; - -float SRGBEncodeChannel(float value) { - float linear = max(value, 0.0); - return linear <= 0.0031308 - ? linear * 12.92 - : 1.055 * pow(linear, 1.0 / 2.4) - 0.055; -} - -vec3 ApplyLinearToSRGB(vec3 color) { - return vec3( - SRGBEncodeChannel(color.r), - SRGBEncodeChannel(color.g), - SRGBEncodeChannel(color.b)); -} - -vec3 ApplyNeutralToneMapping(vec3 color) { - return color / (color + vec3(1.0)); -} - -vec3 ApplyAcesToneMapping(vec3 color) { - const float a = 2.51; - const float b = 0.03; - const float c = 2.43; - const float d = 0.59; - const float e = 0.14; - return clamp((color * (a * color + b)) / (color * (c * color + d) + e), 0.0, 1.0); -} - -vec3 ApplyToneMapping(vec3 color, float toneMappingMode) { - if (toneMappingMode > 1.5) { - return ApplyAcesToneMapping(color); - } - - if (toneMappingMode > 0.5) { - return ApplyNeutralToneMapping(color); - } - - return color; -} - -void main() { - vec4 color = texture(sampler2D(uSourceColorTexture, uLinearClampSampler), vTexCoord); - color.rgb *= max(gFinalColorParams.x, 0.0); - color *= gColorScale; - color.rgb = ApplyToneMapping(color.rgb, gFinalColorParams.z); - - if (gFinalColorParams.y > 0.5) { - color.rgb = ApplyLinearToSRGB(color.rgb); - } - - fragColor = color; -} diff --git a/engine/assets/builtin/shaders/final-color/final-color.ps.hlsl b/engine/assets/builtin/shaders/final-color/final-color.ps.hlsl deleted file mode 100644 index 82067959..00000000 --- a/engine/assets/builtin/shaders/final-color/final-color.ps.hlsl +++ /dev/null @@ -1,65 +0,0 @@ -// XC_BUILTIN_FINAL_COLOR_D3D12_PS -Texture2D gSourceColorTexture : register(t0); -SamplerState gLinearClampSampler : register(s0); - -cbuffer FinalColorConstants : register(b0) { - float4 gColorScale; - float4 gFinalColorParams; -}; - -struct PSInput { - float4 position : SV_POSITION; - float2 texcoord : TEXCOORD0; -}; - -float SRGBEncodeChannel(float value) { - const float linearValue = max(value, 0.0f); - return linearValue <= 0.0031308f - ? linearValue * 12.92f - : 1.055f * pow(linearValue, 1.0f / 2.4f) - 0.055f; -} - -float3 ApplyLinearToSRGB(float3 color) { - return float3( - SRGBEncodeChannel(color.r), - SRGBEncodeChannel(color.g), - SRGBEncodeChannel(color.b)); -} - -float3 ApplyNeutralToneMapping(float3 color) { - return color / (color + 1.0f); -} - -float3 ApplyAcesToneMapping(float3 color) { - const float a = 2.51f; - const float b = 0.03f; - const float c = 2.43f; - const float d = 0.59f; - const float e = 0.14f; - return saturate((color * (a * color + b)) / (color * (c * color + d) + e)); -} - -float3 ApplyToneMapping(float3 color, float toneMappingMode) { - if (toneMappingMode > 1.5f) { - return ApplyAcesToneMapping(color); - } - - if (toneMappingMode > 0.5f) { - return ApplyNeutralToneMapping(color); - } - - return color; -} - -float4 MainPS(PSInput input) : SV_TARGET { - float4 color = gSourceColorTexture.Sample(gLinearClampSampler, input.texcoord); - color.rgb *= max(gFinalColorParams.x, 0.0f); - color *= gColorScale; - color.rgb = ApplyToneMapping(color.rgb, gFinalColorParams.z); - - if (gFinalColorParams.y > 0.5f) { - color.rgb = ApplyLinearToSRGB(color.rgb); - } - - return color; -} diff --git a/engine/assets/builtin/shaders/final-color/final-color.shader b/engine/assets/builtin/shaders/final-color/final-color.shader index e7c55d09..cae6b422 100644 --- a/engine/assets/builtin/shaders/final-color/final-color.shader +++ b/engine/assets/builtin/shaders/final-color/final-color.shader @@ -7,24 +7,117 @@ Shader "Builtin Final Color" _OutputTransferMode ("Output Transfer Mode", Float) = 0.0 _ToneMappingMode ("Tone Mapping Mode", Float) = 0.0 } + HLSLINCLUDE + cbuffer FinalColorConstants : register(b0) + { + float4 gColorScale; + float4 gFinalColorParams; + }; + + Texture2D gSourceColorTexture : register(t0); + SamplerState gLinearClampSampler : register(s0); + + struct VSOutput + { + float4 position : SV_POSITION; + float2 texcoord : TEXCOORD0; + }; + + VSOutput MainVS(uint vertexId : SV_VertexID) + { + const float2 positions[3] = { + float2(-1.0f, -1.0f), + float2(-1.0f, 3.0f), + float2( 3.0f, -1.0f) + }; + + const float2 position = positions[vertexId]; + + VSOutput output; + output.position = float4(position, 1.0f, 1.0f); + + float2 uv = float2( + position.x * 0.5f + 0.5f, + position.y * 0.5f + 0.5f); + #if UNITY_UV_STARTS_AT_TOP + uv.y = 1.0f - uv.y; + #endif + output.texcoord = uv; + return output; + } + + float SRGBEncodeChannel(float value) + { + const float linearValue = max(value, 0.0f); + return linearValue <= 0.0031308f + ? linearValue * 12.92f + : 1.055f * pow(linearValue, 1.0f / 2.4f) - 0.055f; + } + + float3 ApplyLinearToSRGB(float3 color) + { + return float3( + SRGBEncodeChannel(color.r), + SRGBEncodeChannel(color.g), + SRGBEncodeChannel(color.b)); + } + + float3 ApplyNeutralToneMapping(float3 color) + { + return color / (color + 1.0f); + } + + float3 ApplyAcesToneMapping(float3 color) + { + const float a = 2.51f; + const float b = 0.03f; + const float c = 2.43f; + const float d = 0.59f; + const float e = 0.14f; + return saturate((color * (a * color + b)) / (color * (c * color + d) + e)); + } + + float3 ApplyToneMapping(float3 color, float toneMappingMode) + { + if (toneMappingMode > 1.5f) { + return ApplyAcesToneMapping(color); + } + + if (toneMappingMode > 0.5f) { + return ApplyNeutralToneMapping(color); + } + + return color; + } + + float4 MainPS(VSOutput input) : SV_TARGET + { + float4 color = gSourceColorTexture.Sample(gLinearClampSampler, input.texcoord); + color.rgb *= max(gFinalColorParams.x, 0.0f); + color *= gColorScale; + color.rgb = ApplyToneMapping(color.rgb, gFinalColorParams.z); + + if (gFinalColorParams.y > 0.5f) { + color.rgb = ApplyLinearToSRGB(color.rgb); + } + + return color; + } + ENDHLSL SubShader { Pass { Name "FinalColor" Tags { "LightMode" = "FinalOutput" } - Resources - { - FinalColorConstants (ConstantBuffer, 0, 0) - SourceColorTexture (Texture2D, 1, 0) - LinearClampSampler (Sampler, 2, 0) - } + Cull Off + ZWrite Off + ZTest Always + Blend Off HLSLPROGRAM + #pragma target 4.5 #pragma vertex MainVS #pragma fragment MainPS - #pragma backend D3D12 HLSL "final-color.vs.hlsl" "final-color.ps.hlsl" vs_5_0 ps_5_0 - #pragma backend OpenGL GLSL "final-color.vert.glsl" "final-color.frag.glsl" - #pragma backend Vulkan GLSL "final-color.vert.vk.glsl" "final-color.frag.vk.glsl" ENDHLSL } } diff --git a/engine/assets/builtin/shaders/final-color/final-color.vert.glsl b/engine/assets/builtin/shaders/final-color/final-color.vert.glsl deleted file mode 100644 index 708404f2..00000000 --- a/engine/assets/builtin/shaders/final-color/final-color.vert.glsl +++ /dev/null @@ -1,16 +0,0 @@ -// XC_BUILTIN_FINAL_COLOR_OPENGL_VS -#version 430 - -out vec2 vTexCoord; - -void main() { - const vec2 positions[3] = vec2[3]( - vec2(-1.0, -1.0), - vec2(-1.0, 3.0), - vec2( 3.0, -1.0) - ); - - vec2 position = positions[gl_VertexID]; - gl_Position = vec4(position, 1.0, 1.0); - vTexCoord = position * 0.5 + 0.5; -} diff --git a/engine/assets/builtin/shaders/final-color/final-color.vert.vk.glsl b/engine/assets/builtin/shaders/final-color/final-color.vert.vk.glsl deleted file mode 100644 index ef33e95d..00000000 --- a/engine/assets/builtin/shaders/final-color/final-color.vert.vk.glsl +++ /dev/null @@ -1,18 +0,0 @@ -// XC_BUILTIN_FINAL_COLOR_VULKAN_VS -#version 450 - -layout(location = 0) out vec2 vTexCoord; - -void main() { - const vec2 positions[3] = vec2[3]( - vec2(-1.0, -1.0), - vec2(-1.0, 3.0), - vec2( 3.0, -1.0) - ); - - vec2 position = positions[gl_VertexIndex]; - gl_Position = vec4(position, 1.0, 1.0); - vTexCoord = vec2( - position.x * 0.5 + 0.5, - 1.0 - (position.y * 0.5 + 0.5)); -} diff --git a/engine/assets/builtin/shaders/final-color/final-color.vs.hlsl b/engine/assets/builtin/shaders/final-color/final-color.vs.hlsl deleted file mode 100644 index 2c2b687b..00000000 --- a/engine/assets/builtin/shaders/final-color/final-color.vs.hlsl +++ /dev/null @@ -1,22 +0,0 @@ -// XC_BUILTIN_FINAL_COLOR_D3D12_VS -struct VSOutput { - float4 position : SV_POSITION; - float2 texcoord : TEXCOORD0; -}; - -VSOutput MainVS(uint vertexId : SV_VertexID) { - const float2 positions[3] = { - float2(-1.0f, -1.0f), - float2(-1.0f, 3.0f), - float2( 3.0f, -1.0f) - }; - - const float2 position = positions[vertexId]; - - VSOutput output; - output.position = float4(position, 1.0f, 1.0f); - output.texcoord = float2( - position.x * 0.5f + 0.5f, - 1.0f - (position.y * 0.5f + 0.5f)); - return output; -} diff --git a/engine/assets/builtin/shaders/skybox/skybox.frag.glsl b/engine/assets/builtin/shaders/skybox/skybox.frag.glsl deleted file mode 100644 index 39df4bf4..00000000 --- a/engine/assets/builtin/shaders/skybox/skybox.frag.glsl +++ /dev/null @@ -1,79 +0,0 @@ -// XC_BUILTIN_SKYBOX_OPENGL_PS -#version 430 - -layout(binding = 0) uniform sampler2D uSkyboxPanoramicTexture; -layout(binding = 1) uniform samplerCube uSkyboxTexture; - -layout(std140, binding = 0) uniform EnvironmentConstants { - vec4 gSkyboxTopColor; - vec4 gSkyboxHorizonColor; - vec4 gSkyboxBottomColor; - vec4 gCameraRightAndTanHalfFov; - vec4 gCameraUpAndAspect; - vec4 gCameraForwardAndUnused; -}; - -layout(std140, binding = 1) uniform MaterialConstants { - vec4 gSkyboxTintAndExposure; - vec4 gSkyboxRotationAndMode; -}; - -in vec2 vNdc; - -layout(location = 0) out vec4 fragColor; - -const float XC_PI = 3.14159265358979323846; -const float XC_INV_PI = 0.31830988618379067154; -const float XC_INV_TWO_PI = 0.15915494309189533577; - -vec3 EvaluateProceduralSkybox(vec3 viewRay) { - float vertical = clamp(viewRay.y, -1.0, 1.0); - vec3 color = gSkyboxHorizonColor.rgb; - if (vertical >= 0.0) { - color = mix(gSkyboxHorizonColor.rgb, gSkyboxTopColor.rgb, pow(clamp(vertical, 0.0, 1.0), 0.65)); - } else { - color = mix(gSkyboxHorizonColor.rgb, gSkyboxBottomColor.rgb, pow(clamp(-vertical, 0.0, 1.0), 0.55)); - } - - return color; -} - -vec3 RotateAroundY(vec3 viewRay) { - float rotation = gSkyboxRotationAndMode.x; - float sinTheta = sin(rotation); - float cosTheta = cos(rotation); - return normalize(vec3( - viewRay.x * cosTheta - viewRay.z * sinTheta, - viewRay.y, - viewRay.x * sinTheta + viewRay.z * cosTheta)); -} - -vec2 ComputePanoramicUv(vec3 viewRay) { - vec3 rotatedRay = RotateAroundY(viewRay); - float u = fract(atan(rotatedRay.z, rotatedRay.x) * XC_INV_TWO_PI + 0.5); - float v = acos(clamp(rotatedRay.y, -1.0, 1.0)) * XC_INV_PI; - return vec2(u, clamp(v, 0.0, 1.0)); -} - -void main() { - float tanHalfFov = gCameraRightAndTanHalfFov.w; - float aspect = gCameraUpAndAspect.w; - - vec3 viewRay = normalize( - gCameraForwardAndUnused.xyz + - vNdc.x * aspect * tanHalfFov * gCameraRightAndTanHalfFov.xyz + - vNdc.y * tanHalfFov * gCameraUpAndAspect.xyz); - - vec3 color = EvaluateProceduralSkybox(viewRay); - if (gSkyboxRotationAndMode.y > 1.5) { - color = texture(uSkyboxTexture, RotateAroundY(viewRay)).rgb * - gSkyboxTintAndExposure.rgb * - gSkyboxTintAndExposure.w; - } else if (gSkyboxRotationAndMode.y > 0.5) { - color = texture(uSkyboxPanoramicTexture, ComputePanoramicUv(viewRay)).rgb * - gSkyboxTintAndExposure.rgb * - gSkyboxTintAndExposure.w; - } - - fragColor = vec4(color, 1.0); -} diff --git a/engine/assets/builtin/shaders/skybox/skybox.frag.vk.glsl b/engine/assets/builtin/shaders/skybox/skybox.frag.vk.glsl deleted file mode 100644 index a207f474..00000000 --- a/engine/assets/builtin/shaders/skybox/skybox.frag.vk.glsl +++ /dev/null @@ -1,80 +0,0 @@ -// XC_BUILTIN_SKYBOX_VULKAN_PS -#version 450 - -layout(set = 0, binding = 0, std140) uniform EnvironmentConstants { - vec4 gSkyboxTopColor; - vec4 gSkyboxHorizonColor; - vec4 gSkyboxBottomColor; - vec4 gCameraRightAndTanHalfFov; - vec4 gCameraUpAndAspect; - vec4 gCameraForwardAndUnused; -}; - -layout(set = 1, binding = 0, std140) uniform MaterialConstants { - vec4 gSkyboxTintAndExposure; - vec4 gSkyboxRotationAndMode; -}; - -layout(set = 2, binding = 0) uniform texture2D uSkyboxPanoramicTexture; -layout(set = 3, binding = 0) uniform textureCube uSkyboxTexture; -layout(set = 4, binding = 0) uniform sampler uLinearSampler; - -layout(location = 0) in vec2 vNdc; - -layout(location = 0) out vec4 fragColor; - -const float XC_PI = 3.14159265358979323846; -const float XC_INV_PI = 0.31830988618379067154; -const float XC_INV_TWO_PI = 0.15915494309189533577; - -vec3 EvaluateProceduralSkybox(vec3 viewRay) { - float vertical = clamp(viewRay.y, -1.0, 1.0); - vec3 color = gSkyboxHorizonColor.rgb; - if (vertical >= 0.0) { - color = mix(gSkyboxHorizonColor.rgb, gSkyboxTopColor.rgb, pow(clamp(vertical, 0.0, 1.0), 0.65)); - } else { - color = mix(gSkyboxHorizonColor.rgb, gSkyboxBottomColor.rgb, pow(clamp(-vertical, 0.0, 1.0), 0.55)); - } - - return color; -} - -vec3 RotateAroundY(vec3 viewRay) { - float rotation = gSkyboxRotationAndMode.x; - float sinTheta = sin(rotation); - float cosTheta = cos(rotation); - return normalize(vec3( - viewRay.x * cosTheta - viewRay.z * sinTheta, - viewRay.y, - viewRay.x * sinTheta + viewRay.z * cosTheta)); -} - -vec2 ComputePanoramicUv(vec3 viewRay) { - vec3 rotatedRay = RotateAroundY(viewRay); - float u = fract(atan(rotatedRay.z, rotatedRay.x) * XC_INV_TWO_PI + 0.5); - float v = acos(clamp(rotatedRay.y, -1.0, 1.0)) * XC_INV_PI; - return vec2(u, clamp(v, 0.0, 1.0)); -} - -void main() { - float tanHalfFov = gCameraRightAndTanHalfFov.w; - float aspect = gCameraUpAndAspect.w; - - vec3 viewRay = normalize( - gCameraForwardAndUnused.xyz + - vNdc.x * aspect * tanHalfFov * gCameraRightAndTanHalfFov.xyz + - vNdc.y * tanHalfFov * gCameraUpAndAspect.xyz); - - vec3 color = EvaluateProceduralSkybox(viewRay); - if (gSkyboxRotationAndMode.y > 1.5) { - color = texture(samplerCube(uSkyboxTexture, uLinearSampler), RotateAroundY(viewRay)).rgb * - gSkyboxTintAndExposure.rgb * - gSkyboxTintAndExposure.w; - } else if (gSkyboxRotationAndMode.y > 0.5) { - color = texture(sampler2D(uSkyboxPanoramicTexture, uLinearSampler), ComputePanoramicUv(viewRay)).rgb * - gSkyboxTintAndExposure.rgb * - gSkyboxTintAndExposure.w; - } - - fragColor = vec4(color, 1.0); -} diff --git a/engine/assets/builtin/shaders/skybox/skybox.ps.hlsl b/engine/assets/builtin/shaders/skybox/skybox.ps.hlsl deleted file mode 100644 index 7e6cdf0a..00000000 --- a/engine/assets/builtin/shaders/skybox/skybox.ps.hlsl +++ /dev/null @@ -1,79 +0,0 @@ -// XC_BUILTIN_SKYBOX_D3D12_PS -Texture2D gSkyboxPanoramicTexture : register(t0); -TextureCube gSkyboxTexture : register(t1); -SamplerState gLinearSampler : register(s0); - -cbuffer EnvironmentConstants : register(b0) { - float4 gSkyboxTopColor; - float4 gSkyboxHorizonColor; - float4 gSkyboxBottomColor; - float4 gCameraRightAndTanHalfFov; - float4 gCameraUpAndAspect; - float4 gCameraForwardAndUnused; -} - -cbuffer MaterialConstants : register(b1) { - float4 gSkyboxTintAndExposure; - float4 gSkyboxRotationAndMode; -} - -struct PSInput { - float4 position : SV_POSITION; - float2 ndc : TEXCOORD0; -}; - -static const float XC_PI = 3.14159265358979323846f; -static const float XC_INV_PI = 0.31830988618379067154f; -static const float XC_INV_TWO_PI = 0.15915494309189533577f; - -float3 EvaluateProceduralSkybox(float3 viewRay) { - const float vertical = clamp(viewRay.y, -1.0f, 1.0f); - float3 color = gSkyboxHorizonColor.rgb; - if (vertical >= 0.0f) { - color = lerp(gSkyboxHorizonColor.rgb, gSkyboxTopColor.rgb, pow(saturate(vertical), 0.65f)); - } else { - color = lerp(gSkyboxHorizonColor.rgb, gSkyboxBottomColor.rgb, pow(saturate(-vertical), 0.55f)); - } - - return color; -} - -float3 RotateAroundY(float3 viewRay) { - const float rotation = gSkyboxRotationAndMode.x; - const float sinTheta = sin(rotation); - const float cosTheta = cos(rotation); - return normalize(float3( - viewRay.x * cosTheta - viewRay.z * sinTheta, - viewRay.y, - viewRay.x * sinTheta + viewRay.z * cosTheta)); -} - -float2 ComputePanoramicUv(float3 viewRay) { - const float3 rotatedRay = RotateAroundY(viewRay); - const float u = frac(atan2(rotatedRay.z, rotatedRay.x) * XC_INV_TWO_PI + 0.5f); - const float v = acos(clamp(rotatedRay.y, -1.0f, 1.0f)) * XC_INV_PI; - return float2(u, saturate(v)); -} - -float4 MainPS(PSInput input) : SV_Target { - const float tanHalfFov = gCameraRightAndTanHalfFov.w; - const float aspect = gCameraUpAndAspect.w; - - float3 viewRay = normalize( - gCameraForwardAndUnused.xyz + - input.ndc.x * aspect * tanHalfFov * gCameraRightAndTanHalfFov.xyz + - input.ndc.y * tanHalfFov * gCameraUpAndAspect.xyz); - - float3 color = EvaluateProceduralSkybox(viewRay); - if (gSkyboxRotationAndMode.y > 1.5f) { - color = gSkyboxTexture.Sample(gLinearSampler, RotateAroundY(viewRay)).rgb * - gSkyboxTintAndExposure.rgb * - gSkyboxTintAndExposure.w; - } else if (gSkyboxRotationAndMode.y > 0.5f) { - color = gSkyboxPanoramicTexture.Sample(gLinearSampler, ComputePanoramicUv(viewRay)).rgb * - gSkyboxTintAndExposure.rgb * - gSkyboxTintAndExposure.w; - } - - return float4(color, 1.0f); -} diff --git a/engine/assets/builtin/shaders/skybox/skybox.shader b/engine/assets/builtin/shaders/skybox/skybox.shader index 708111f7..597ab351 100644 --- a/engine/assets/builtin/shaders/skybox/skybox.shader +++ b/engine/assets/builtin/shaders/skybox/skybox.shader @@ -8,26 +8,121 @@ Shader "Builtin Skybox" _MainTex ("Panoramic", 2D) = "white" [Semantic(SkyboxPanoramicTexture)] _Tex ("Cubemap (HDR)", Cube) = "white" [Semantic(SkyboxTexture)] } + HLSLINCLUDE + cbuffer EnvironmentConstants : register(b0) + { + float4 gSkyboxTopColor; + float4 gSkyboxHorizonColor; + float4 gSkyboxBottomColor; + float4 gCameraRightAndTanHalfFov; + float4 gCameraUpAndAspect; + float4 gCameraForwardAndUnused; + }; + + cbuffer MaterialConstants : register(b1) + { + float4 gSkyboxTintAndExposure; + float4 gSkyboxRotationAndMode; + }; + + Texture2D SkyboxPanoramicTexture : register(t0); + TextureCube SkyboxTexture : register(t1); + SamplerState LinearClampSampler : register(s0); + + struct VSOutput + { + float4 position : SV_POSITION; + float2 ndc : TEXCOORD0; + }; + + static const float XC_PI = 3.14159265358979323846f; + static const float XC_INV_PI = 0.31830988618379067154f; + static const float XC_INV_TWO_PI = 0.15915494309189533577f; + + VSOutput MainVS(uint vertexId : SV_VertexID) + { + const float2 positions[3] = { + float2(-1.0f, -1.0f), + float2(-1.0f, 3.0f), + float2( 3.0f, -1.0f) + }; + + VSOutput output; + output.position = float4(positions[vertexId], 1.0f, 1.0f); + output.ndc = positions[vertexId]; + return output; + } + + float3 EvaluateProceduralSkybox(float3 viewRay) + { + const float vertical = clamp(viewRay.y, -1.0f, 1.0f); + float3 color = gSkyboxHorizonColor.rgb; + if (vertical >= 0.0f) { + color = lerp(gSkyboxHorizonColor.rgb, gSkyboxTopColor.rgb, pow(saturate(vertical), 0.65f)); + } else { + color = lerp(gSkyboxHorizonColor.rgb, gSkyboxBottomColor.rgb, pow(saturate(-vertical), 0.55f)); + } + + return color; + } + + float3 RotateAroundY(float3 viewRay) + { + const float rotation = gSkyboxRotationAndMode.x; + const float sinTheta = sin(rotation); + const float cosTheta = cos(rotation); + return normalize(float3( + viewRay.x * cosTheta - viewRay.z * sinTheta, + viewRay.y, + viewRay.x * sinTheta + viewRay.z * cosTheta)); + } + + float2 ComputePanoramicUv(float3 viewRay) + { + const float3 rotatedRay = RotateAroundY(viewRay); + const float u = frac(atan2(rotatedRay.z, rotatedRay.x) * XC_INV_TWO_PI + 0.5f); + const float v = acos(clamp(rotatedRay.y, -1.0f, 1.0f)) * XC_INV_PI; + return float2(u, saturate(v)); + } + + float4 MainPS(VSOutput input) : SV_TARGET + { + const float tanHalfFov = gCameraRightAndTanHalfFov.w; + const float aspect = gCameraUpAndAspect.w; + + const float3 viewRay = normalize( + gCameraForwardAndUnused.xyz + + input.ndc.x * aspect * tanHalfFov * gCameraRightAndTanHalfFov.xyz + + input.ndc.y * tanHalfFov * gCameraUpAndAspect.xyz); + + float3 color = EvaluateProceduralSkybox(viewRay); + if (gSkyboxRotationAndMode.y > 1.5f) { + color = SkyboxTexture.Sample(LinearClampSampler, RotateAroundY(viewRay)).rgb * + gSkyboxTintAndExposure.rgb * + gSkyboxTintAndExposure.w; + } else if (gSkyboxRotationAndMode.y > 0.5f) { + color = SkyboxPanoramicTexture.Sample(LinearClampSampler, ComputePanoramicUv(viewRay)).rgb * + gSkyboxTintAndExposure.rgb * + gSkyboxTintAndExposure.w; + } + + return float4(color, 1.0f); + } + ENDHLSL SubShader { Pass { Name "Skybox" Tags { "LightMode" = "Skybox" } - Resources - { - EnvironmentConstants (ConstantBuffer, 0, 0) [Semantic(Environment)] - MaterialConstants (ConstantBuffer, 1, 0) [Semantic(Material)] - SkyboxPanoramicTexture (Texture2D, 2, 0) [Semantic(SkyboxPanoramicTexture)] - SkyboxTexture (TextureCube, 3, 0) [Semantic(SkyboxTexture)] - LinearClampSampler (Sampler, 4, 0) [Semantic(LinearClampSampler)] - } + Cull Off + ZWrite Off + ZTest LEqual + Blend Off HLSLPROGRAM + #pragma target 4.5 #pragma vertex MainVS #pragma fragment MainPS - #pragma backend D3D12 HLSL "skybox.vs.hlsl" "skybox.ps.hlsl" vs_5_0 ps_5_0 - #pragma backend OpenGL GLSL "skybox.vert.glsl" "skybox.frag.glsl" - #pragma backend Vulkan GLSL "skybox.vert.vk.glsl" "skybox.frag.vk.glsl" ENDHLSL } } diff --git a/engine/assets/builtin/shaders/skybox/skybox.vert.glsl b/engine/assets/builtin/shaders/skybox/skybox.vert.glsl deleted file mode 100644 index 0951b7f4..00000000 --- a/engine/assets/builtin/shaders/skybox/skybox.vert.glsl +++ /dev/null @@ -1,16 +0,0 @@ -// XC_BUILTIN_SKYBOX_OPENGL_VS -#version 430 - -out vec2 vNdc; - -void main() { - const vec2 positions[3] = vec2[3]( - vec2(-1.0, -1.0), - vec2(-1.0, 3.0), - vec2( 3.0, -1.0) - ); - - vec2 position = positions[gl_VertexID]; - gl_Position = vec4(position, 1.0, 1.0); - vNdc = position; -} diff --git a/engine/assets/builtin/shaders/skybox/skybox.vert.vk.glsl b/engine/assets/builtin/shaders/skybox/skybox.vert.vk.glsl deleted file mode 100644 index 06fdb710..00000000 --- a/engine/assets/builtin/shaders/skybox/skybox.vert.vk.glsl +++ /dev/null @@ -1,16 +0,0 @@ -// XC_BUILTIN_SKYBOX_VULKAN_VS -#version 450 - -layout(location = 0) out vec2 vNdc; - -void main() { - const vec2 positions[3] = vec2[3]( - vec2(-1.0, -1.0), - vec2(-1.0, 3.0), - vec2( 3.0, -1.0) - ); - - vec2 position = positions[gl_VertexIndex]; - gl_Position = vec4(position, 1.0, 1.0); - vNdc = position; -} diff --git a/engine/assets/builtin/shaders/skybox/skybox.vs.hlsl b/engine/assets/builtin/shaders/skybox/skybox.vs.hlsl deleted file mode 100644 index 6afa67c0..00000000 --- a/engine/assets/builtin/shaders/skybox/skybox.vs.hlsl +++ /dev/null @@ -1,18 +0,0 @@ -// XC_BUILTIN_SKYBOX_D3D12_VS -struct VSOutput { - float4 position : SV_POSITION; - float2 ndc : TEXCOORD0; -}; - -VSOutput MainVS(uint vertexId : SV_VertexID) { - const float2 positions[3] = { - float2(-1.0f, -1.0f), - float2(-1.0f, 3.0f), - float2( 3.0f, -1.0f) - }; - - VSOutput output; - output.position = float4(positions[vertexId], 1.0f, 1.0f); - output.ndc = positions[vertexId]; - return output; -} diff --git a/tests/Rendering/integration/camera_post_process_scene/main.cpp b/tests/Rendering/integration/camera_post_process_scene/main.cpp index be65a88d..e875301d 100644 --- a/tests/Rendering/integration/camera_post_process_scene/main.cpp +++ b/tests/Rendering/integration/camera_post_process_scene/main.cpp @@ -59,7 +59,7 @@ Mesh* CreateQuadMesh() { vertices[3].position = Vector3(1.0f, 1.0f, 0.0f); vertices[3].uv0 = Vector2(1.0f, 0.0f); - const uint32_t indices[6] = { 0, 1, 2, 2, 1, 3 }; + const uint32_t indices[6] = { 0, 2, 1, 2, 3, 1 }; mesh->SetVertexData( vertices, sizeof(vertices), diff --git a/tests/Rendering/integration/final_color_scene/main.cpp b/tests/Rendering/integration/final_color_scene/main.cpp index 9a0dccf9..5b81d6ad 100644 --- a/tests/Rendering/integration/final_color_scene/main.cpp +++ b/tests/Rendering/integration/final_color_scene/main.cpp @@ -60,7 +60,7 @@ Mesh* CreateQuadMesh() { vertices[3].position = Vector3(1.0f, 1.0f, 0.0f); vertices[3].uv0 = Vector2(1.0f, 0.0f); - const uint32_t indices[6] = { 0, 1, 2, 2, 1, 3 }; + const uint32_t indices[6] = { 0, 2, 1, 2, 3, 1 }; mesh->SetVertexData( vertices, sizeof(vertices), diff --git a/tests/Rendering/integration/post_process_scene/main.cpp b/tests/Rendering/integration/post_process_scene/main.cpp index 2d0902da..9da211a2 100644 --- a/tests/Rendering/integration/post_process_scene/main.cpp +++ b/tests/Rendering/integration/post_process_scene/main.cpp @@ -59,7 +59,7 @@ Mesh* CreateQuadMesh() { vertices[3].position = Vector3(1.0f, 1.0f, 0.0f); vertices[3].uv0 = Vector2(1.0f, 0.0f); - const uint32_t indices[6] = { 0, 1, 2, 2, 1, 3 }; + const uint32_t indices[6] = { 0, 2, 1, 2, 3, 1 }; mesh->SetVertexData( vertices, sizeof(vertices), diff --git a/tests/Rendering/unit/test_builtin_forward_pipeline.cpp b/tests/Rendering/unit/test_builtin_forward_pipeline.cpp index 44ee8743..5ae70764 100644 --- a/tests/Rendering/unit/test_builtin_forward_pipeline.cpp +++ b/tests/Rendering/unit/test_builtin_forward_pipeline.cpp @@ -455,7 +455,7 @@ TEST(BuiltinDepthStylePass_Test, OpenGLRuntimeTranspilesShadowCasterAlphaVariant delete shader; } -TEST(BuiltinForwardPipeline_Test, BuiltinSkyboxShaderDeclaresExplicitEnvironmentResourceContract) { +TEST(BuiltinForwardPipeline_Test, BuiltinSkyboxShaderUsesUnityStyleSingleSourceContract) { ShaderLoader loader; LoadResult result = loader.Load(GetBuiltinSkyboxShaderPath()); ASSERT_TRUE(result); @@ -466,7 +466,11 @@ TEST(BuiltinForwardPipeline_Test, BuiltinSkyboxShaderDeclaresExplicitEnvironment const ShaderPass* pass = shader->FindPass("Skybox"); ASSERT_NE(pass, nullptr); - ASSERT_EQ(pass->resources.Size(), 5u); + EXPECT_TRUE(pass->resources.Empty()); + EXPECT_TRUE(pass->hasFixedFunctionState); + EXPECT_EQ(pass->fixedFunctionState.cullMode, MaterialCullMode::None); + EXPECT_FALSE(pass->fixedFunctionState.depthWriteEnable); + EXPECT_EQ(pass->fixedFunctionState.depthFunc, MaterialComparisonFunc::LessEqual); const ShaderPropertyDesc* tint = shader->FindProperty("_Tint"); ASSERT_NE(tint, nullptr); @@ -493,35 +497,37 @@ TEST(BuiltinForwardPipeline_Test, BuiltinSkyboxShaderDeclaresExplicitEnvironment EXPECT_EQ(cubemap->type, ShaderPropertyType::TextureCube); EXPECT_EQ(cubemap->semantic, "SkyboxTexture"); - EXPECT_EQ(pass->resources[0].semantic, "Environment"); - EXPECT_EQ(pass->resources[0].type, ShaderResourceType::ConstantBuffer); - EXPECT_EQ(pass->resources[0].set, 0u); - EXPECT_EQ(pass->resources[0].binding, 0u); + delete shader; +} - EXPECT_EQ(pass->resources[1].semantic, "Material"); - EXPECT_EQ(pass->resources[1].type, ShaderResourceType::ConstantBuffer); - EXPECT_EQ(pass->resources[1].set, 1u); - EXPECT_EQ(pass->resources[1].binding, 0u); +TEST(BuiltinForwardPipeline_Test, BuildsBuiltinPassResourceBindingPlanFromImplicitSkyboxShaderContract) { + ShaderLoader loader; + LoadResult result = loader.Load(GetBuiltinSkyboxShaderPath()); + ASSERT_TRUE(result); + ASSERT_NE(result.resource, nullptr); - EXPECT_EQ(pass->resources[2].semantic, "SkyboxPanoramicTexture"); - EXPECT_EQ(pass->resources[2].type, ShaderResourceType::Texture2D); - EXPECT_EQ(pass->resources[2].set, 2u); - EXPECT_EQ(pass->resources[2].binding, 0u); + Shader* shader = static_cast(result.resource); + ASSERT_NE(shader, nullptr); - EXPECT_EQ(pass->resources[3].semantic, "SkyboxTexture"); - EXPECT_EQ(pass->resources[3].type, ShaderResourceType::TextureCube); - EXPECT_EQ(pass->resources[3].set, 3u); - EXPECT_EQ(pass->resources[3].binding, 0u); + const ShaderPass* pass = shader->FindPass("Skybox"); + ASSERT_NE(pass, nullptr); - EXPECT_EQ(pass->resources[4].semantic, "LinearClampSampler"); - EXPECT_EQ(pass->resources[4].type, ShaderResourceType::Sampler); - EXPECT_EQ(pass->resources[4].set, 4u); - EXPECT_EQ(pass->resources[4].binding, 0u); + BuiltinPassResourceBindingPlan plan = {}; + String error; + EXPECT_TRUE(TryBuildBuiltinPassResourceBindingPlan(*pass, plan, &error)) << error.CStr(); + ASSERT_EQ(plan.bindings.Size(), 5u); + EXPECT_TRUE(plan.environment.IsValid()); + EXPECT_TRUE(plan.material.IsValid()); + EXPECT_TRUE(plan.skyboxPanoramicTexture.IsValid()); + EXPECT_TRUE(plan.skyboxTexture.IsValid()); + EXPECT_TRUE(plan.linearClampSampler.IsValid()); + EXPECT_EQ(plan.firstDescriptorSet, 0u); + EXPECT_EQ(plan.descriptorSetCount, 5u); delete shader; } -TEST(BuiltinForwardPipeline_Test, BuiltinFinalColorShaderDeclaresExplicitFullscreenResourceContract) { +TEST(BuiltinForwardPipeline_Test, BuiltinFinalColorShaderUsesUnityStyleSingleSourceContract) { ShaderLoader loader; LoadResult result = loader.Load(GetBuiltinFinalColorShaderPath()); ASSERT_TRUE(result); @@ -532,7 +538,11 @@ TEST(BuiltinForwardPipeline_Test, BuiltinFinalColorShaderDeclaresExplicitFullscr const ShaderPass* pass = shader->FindPass("FinalColor"); ASSERT_NE(pass, nullptr); - ASSERT_EQ(pass->resources.Size(), 3u); + EXPECT_TRUE(pass->resources.Empty()); + EXPECT_TRUE(pass->hasFixedFunctionState); + EXPECT_EQ(pass->fixedFunctionState.cullMode, MaterialCullMode::None); + EXPECT_FALSE(pass->fixedFunctionState.depthWriteEnable); + EXPECT_EQ(pass->fixedFunctionState.depthFunc, MaterialComparisonFunc::Always); const ShaderPropertyDesc* colorScale = shader->FindProperty("_ColorScale"); ASSERT_NE(colorScale, nullptr); @@ -550,20 +560,307 @@ TEST(BuiltinForwardPipeline_Test, BuiltinFinalColorShaderDeclaresExplicitFullscr ASSERT_NE(toneMappingMode, nullptr); EXPECT_EQ(toneMappingMode->type, ShaderPropertyType::Float); - EXPECT_STREQ(pass->resources[0].name.CStr(), "FinalColorConstants"); - EXPECT_EQ(pass->resources[0].type, ShaderResourceType::ConstantBuffer); - EXPECT_EQ(pass->resources[0].set, 0u); - EXPECT_EQ(pass->resources[0].binding, 0u); + delete shader; +} - EXPECT_STREQ(pass->resources[1].name.CStr(), "SourceColorTexture"); - EXPECT_EQ(pass->resources[1].type, ShaderResourceType::Texture2D); - EXPECT_EQ(pass->resources[1].set, 1u); - EXPECT_EQ(pass->resources[1].binding, 0u); +TEST(BuiltinForwardPipeline_Test, BuildsBuiltinPassResourceBindingPlanFromImplicitFinalColorShaderContract) { + ShaderLoader loader; + LoadResult result = loader.Load(GetBuiltinFinalColorShaderPath()); + ASSERT_TRUE(result); + ASSERT_NE(result.resource, nullptr); - EXPECT_STREQ(pass->resources[2].name.CStr(), "LinearClampSampler"); - EXPECT_EQ(pass->resources[2].type, ShaderResourceType::Sampler); - EXPECT_EQ(pass->resources[2].set, 2u); - EXPECT_EQ(pass->resources[2].binding, 0u); + Shader* shader = static_cast(result.resource); + ASSERT_NE(shader, nullptr); + + const ShaderPass* pass = shader->FindPass("FinalColor"); + ASSERT_NE(pass, nullptr); + + BuiltinPassResourceBindingPlan plan = {}; + String error; + EXPECT_TRUE(TryBuildBuiltinPassResourceBindingPlan(*pass, plan, &error)) << error.CStr(); + ASSERT_EQ(plan.bindings.Size(), 3u); + EXPECT_TRUE(plan.passConstants.IsValid()); + EXPECT_TRUE(plan.sourceColorTexture.IsValid()); + EXPECT_TRUE(plan.linearClampSampler.IsValid()); + EXPECT_EQ(plan.firstDescriptorSet, 0u); + EXPECT_EQ(plan.descriptorSetCount, 3u); + + delete shader; +} + +TEST(BuiltinForwardPipeline_Test, BuiltinColorScalePostProcessShaderUsesUnityStyleSingleSourceContract) { + ShaderLoader loader; + LoadResult result = loader.Load(GetBuiltinColorScalePostProcessShaderPath()); + ASSERT_TRUE(result); + ASSERT_NE(result.resource, nullptr); + + Shader* shader = static_cast(result.resource); + ASSERT_NE(shader, nullptr); + + const ShaderPass* pass = shader->FindPass("ColorScale"); + ASSERT_NE(pass, nullptr); + EXPECT_TRUE(pass->resources.Empty()); + EXPECT_TRUE(pass->hasFixedFunctionState); + EXPECT_EQ(pass->fixedFunctionState.cullMode, MaterialCullMode::None); + EXPECT_FALSE(pass->fixedFunctionState.depthWriteEnable); + EXPECT_EQ(pass->fixedFunctionState.depthFunc, MaterialComparisonFunc::Always); + + const ShaderPropertyDesc* colorScale = shader->FindProperty("_ColorScale"); + ASSERT_NE(colorScale, nullptr); + EXPECT_EQ(colorScale->type, ShaderPropertyType::Color); + + delete shader; +} + +TEST(BuiltinForwardPipeline_Test, BuildsBuiltinPassResourceBindingPlanFromImplicitColorScalePostProcessShaderContract) { + ShaderLoader loader; + LoadResult result = loader.Load(GetBuiltinColorScalePostProcessShaderPath()); + ASSERT_TRUE(result); + ASSERT_NE(result.resource, nullptr); + + Shader* shader = static_cast(result.resource); + ASSERT_NE(shader, nullptr); + + const ShaderPass* pass = shader->FindPass("ColorScale"); + ASSERT_NE(pass, nullptr); + + BuiltinPassResourceBindingPlan plan = {}; + String error; + EXPECT_TRUE(TryBuildBuiltinPassResourceBindingPlan(*pass, plan, &error)) << error.CStr(); + ASSERT_EQ(plan.bindings.Size(), 3u); + EXPECT_TRUE(plan.passConstants.IsValid()); + EXPECT_TRUE(plan.sourceColorTexture.IsValid()); + EXPECT_TRUE(plan.linearClampSampler.IsValid()); + EXPECT_EQ(plan.firstDescriptorSet, 0u); + EXPECT_EQ(plan.descriptorSetCount, 3u); + + delete shader; +} + +TEST(BuiltinForwardPipeline_Test, VulkanRuntimeCompileDescRewritesUnityStyleFinalColorBindingsToDescriptorSpaces) { + ShaderLoader loader; + LoadResult result = loader.Load(GetBuiltinFinalColorShaderPath()); + ASSERT_TRUE(result); + ASSERT_NE(result.resource, nullptr); + + Shader* shader = static_cast(result.resource); + ASSERT_NE(shader, nullptr); + + const ShaderPass* pass = shader->FindPass("FinalColor"); + ASSERT_NE(pass, nullptr); + + const ShaderStageVariant* d3d12Fragment = shader->FindVariant( + "FinalColor", + XCEngine::Resources::ShaderType::Fragment, + XCEngine::Resources::ShaderBackend::D3D12); + ASSERT_NE(d3d12Fragment, nullptr); + + ShaderCompileDesc d3d12CompileDesc = {}; + ::XCEngine::Rendering::Detail::ApplyShaderStageVariant( + *pass, + XCEngine::Resources::ShaderBackend::D3D12, + *d3d12Fragment, + d3d12CompileDesc); + const std::string d3d12Source( + reinterpret_cast(d3d12CompileDesc.source.data()), + d3d12CompileDesc.source.size()); + EXPECT_NE(d3d12Source.find("cbuffer FinalColorConstants : register(b0)"), std::string::npos); + EXPECT_NE(d3d12Source.find("Texture2D gSourceColorTexture : register(t0)"), std::string::npos); + EXPECT_NE(d3d12Source.find("SamplerState gLinearClampSampler : register(s0)"), std::string::npos); + EXPECT_EQ(d3d12Source.find("space1"), std::string::npos); + EXPECT_EQ(d3d12Source.find("space2"), std::string::npos); + + const ShaderStageVariant* vulkanFragment = shader->FindVariant( + "FinalColor", + XCEngine::Resources::ShaderType::Fragment, + XCEngine::Resources::ShaderBackend::Vulkan); + ASSERT_NE(vulkanFragment, nullptr); + + const std::string runtimeSource = + ::XCEngine::Rendering::Detail::BuildRuntimeShaderSource( + *pass, + XCEngine::Resources::ShaderBackend::Vulkan, + *vulkanFragment); + EXPECT_NE( + runtimeSource.find("cbuffer FinalColorConstants : register(b0, space0)"), + std::string::npos); + EXPECT_NE( + runtimeSource.find("Texture2D gSourceColorTexture : register(t0, space1)"), + std::string::npos); + EXPECT_NE( + runtimeSource.find("SamplerState gLinearClampSampler : register(s0, space2)"), + std::string::npos); + + ShaderCompileDesc vulkanCompileDesc = {}; + ::XCEngine::Rendering::Detail::ApplyShaderStageVariant( + *pass, + XCEngine::Resources::ShaderBackend::Vulkan, + *vulkanFragment, + vulkanCompileDesc); + const std::string vulkanSource( + reinterpret_cast(vulkanCompileDesc.source.data()), + vulkanCompileDesc.source.size()); + EXPECT_NE(vulkanSource.find("ApplyLinearToSRGB"), std::string::npos); + EXPECT_NE(vulkanSource.find("ApplyToneMapping"), std::string::npos); + + delete shader; +} + +TEST(BuiltinForwardPipeline_Test, OpenGLRuntimeTranspilesFinalColorVariantToCombinedSourceSampler) { + ShaderLoader loader; + LoadResult result = loader.Load(GetBuiltinFinalColorShaderPath()); + ASSERT_TRUE(result); + ASSERT_NE(result.resource, nullptr); + + Shader* shader = static_cast(result.resource); + ASSERT_NE(shader, nullptr); + + const ShaderPass* pass = shader->FindPass("FinalColor"); + ASSERT_NE(pass, nullptr); + + const ShaderStageVariant* openGLFragment = shader->FindVariant( + "FinalColor", + XCEngine::Resources::ShaderType::Fragment, + XCEngine::Resources::ShaderBackend::OpenGL); + ASSERT_NE(openGLFragment, nullptr); + + ShaderCompileDesc compileDesc = {}; + ::XCEngine::Rendering::Detail::ApplyShaderStageVariant( + *pass, + XCEngine::Resources::ShaderBackend::OpenGL, + *openGLFragment, + compileDesc); + + XCEngine::RHI::CompiledSpirvShader spirvShader = {}; + std::string errorMessage; + ASSERT_TRUE( + XCEngine::RHI::CompileSpirvShader( + compileDesc, + XCEngine::RHI::SpirvTargetEnvironment::Vulkan, + spirvShader, + &errorMessage)) + << errorMessage; + + std::string glslSource; + ASSERT_TRUE(XCEngine::RHI::TranspileSpirvToOpenGLGLSL(spirvShader, glslSource, &errorMessage)) + << errorMessage; + EXPECT_NE(glslSource.find("uniform sampler2D SPIRV_Cross_Combined"), std::string::npos); + EXPECT_NE(glslSource.find("texture(SPIRV_Cross_Combined"), std::string::npos); + EXPECT_NE(glslSource.find("FinalColorConstants"), std::string::npos); + + delete shader; +} + +TEST(BuiltinForwardPipeline_Test, VulkanRuntimeCompileDescRewritesUnityStyleColorScaleBindingsToDescriptorSpaces) { + ShaderLoader loader; + LoadResult result = loader.Load(GetBuiltinColorScalePostProcessShaderPath()); + ASSERT_TRUE(result); + ASSERT_NE(result.resource, nullptr); + + Shader* shader = static_cast(result.resource); + ASSERT_NE(shader, nullptr); + + const ShaderPass* pass = shader->FindPass("ColorScale"); + ASSERT_NE(pass, nullptr); + + const ShaderStageVariant* d3d12Fragment = shader->FindVariant( + "ColorScale", + XCEngine::Resources::ShaderType::Fragment, + XCEngine::Resources::ShaderBackend::D3D12); + ASSERT_NE(d3d12Fragment, nullptr); + + ShaderCompileDesc d3d12CompileDesc = {}; + ::XCEngine::Rendering::Detail::ApplyShaderStageVariant( + *pass, + XCEngine::Resources::ShaderBackend::D3D12, + *d3d12Fragment, + d3d12CompileDesc); + const std::string d3d12Source( + reinterpret_cast(d3d12CompileDesc.source.data()), + d3d12CompileDesc.source.size()); + EXPECT_NE(d3d12Source.find("cbuffer PostProcessConstants : register(b0)"), std::string::npos); + EXPECT_NE(d3d12Source.find("Texture2D gSourceColorTexture : register(t0)"), std::string::npos); + EXPECT_NE(d3d12Source.find("SamplerState gLinearClampSampler : register(s0)"), std::string::npos); + EXPECT_EQ(d3d12Source.find("space1"), std::string::npos); + EXPECT_EQ(d3d12Source.find("space2"), std::string::npos); + + const ShaderStageVariant* vulkanFragment = shader->FindVariant( + "ColorScale", + XCEngine::Resources::ShaderType::Fragment, + XCEngine::Resources::ShaderBackend::Vulkan); + ASSERT_NE(vulkanFragment, nullptr); + + const std::string runtimeSource = + ::XCEngine::Rendering::Detail::BuildRuntimeShaderSource( + *pass, + XCEngine::Resources::ShaderBackend::Vulkan, + *vulkanFragment); + EXPECT_NE( + runtimeSource.find("cbuffer PostProcessConstants : register(b0, space0)"), + std::string::npos); + EXPECT_NE( + runtimeSource.find("Texture2D gSourceColorTexture : register(t0, space1)"), + std::string::npos); + EXPECT_NE( + runtimeSource.find("SamplerState gLinearClampSampler : register(s0, space2)"), + std::string::npos); + + ShaderCompileDesc vulkanCompileDesc = {}; + ::XCEngine::Rendering::Detail::ApplyShaderStageVariant( + *pass, + XCEngine::Resources::ShaderBackend::Vulkan, + *vulkanFragment, + vulkanCompileDesc); + const std::string vulkanSource( + reinterpret_cast(vulkanCompileDesc.source.data()), + vulkanCompileDesc.source.size()); + EXPECT_NE(vulkanSource.find("gSourceColorTexture.Sample"), std::string::npos); + EXPECT_NE(vulkanSource.find("gColorScale"), std::string::npos); + + delete shader; +} + +TEST(BuiltinForwardPipeline_Test, OpenGLRuntimeTranspilesColorScaleVariantToCombinedSourceSampler) { + ShaderLoader loader; + LoadResult result = loader.Load(GetBuiltinColorScalePostProcessShaderPath()); + ASSERT_TRUE(result); + ASSERT_NE(result.resource, nullptr); + + Shader* shader = static_cast(result.resource); + ASSERT_NE(shader, nullptr); + + const ShaderPass* pass = shader->FindPass("ColorScale"); + ASSERT_NE(pass, nullptr); + + const ShaderStageVariant* openGLFragment = shader->FindVariant( + "ColorScale", + XCEngine::Resources::ShaderType::Fragment, + XCEngine::Resources::ShaderBackend::OpenGL); + ASSERT_NE(openGLFragment, nullptr); + + ShaderCompileDesc compileDesc = {}; + ::XCEngine::Rendering::Detail::ApplyShaderStageVariant( + *pass, + XCEngine::Resources::ShaderBackend::OpenGL, + *openGLFragment, + compileDesc); + + XCEngine::RHI::CompiledSpirvShader spirvShader = {}; + std::string errorMessage; + ASSERT_TRUE( + XCEngine::RHI::CompileSpirvShader( + compileDesc, + XCEngine::RHI::SpirvTargetEnvironment::Vulkan, + spirvShader, + &errorMessage)) + << errorMessage; + + std::string glslSource; + ASSERT_TRUE(XCEngine::RHI::TranspileSpirvToOpenGLGLSL(spirvShader, glslSource, &errorMessage)) + << errorMessage; + EXPECT_NE(glslSource.find("uniform sampler2D SPIRV_Cross_Combined"), std::string::npos); + EXPECT_NE(glslSource.find("texture(SPIRV_Cross_Combined"), std::string::npos); + EXPECT_NE(glslSource.find("PostProcessConstants"), std::string::npos); delete shader; } diff --git a/tests/Resources/Shader/test_shader_loader.cpp b/tests/Resources/Shader/test_shader_loader.cpp index 8497a150..88cd3da2 100644 --- a/tests/Resources/Shader/test_shader_loader.cpp +++ b/tests/Resources/Shader/test_shader_loader.cpp @@ -2117,6 +2117,160 @@ TEST(ShaderLoader, LoadBuiltinShadowCasterShaderBuildsUnityStyleSingleSourceVari delete shader; } +TEST(ShaderLoader, LoadBuiltinFinalColorShaderBuildsUnityStyleSingleSourceVariants) { + ShaderLoader loader; + LoadResult result = loader.Load(GetBuiltinFinalColorShaderPath()); + ASSERT_TRUE(result); + ASSERT_NE(result.resource, nullptr); + + Shader* shader = static_cast(result.resource); + ASSERT_NE(shader, nullptr); + ASSERT_TRUE(shader->IsValid()); + + const ShaderPass* pass = shader->FindPass("FinalColor"); + ASSERT_NE(pass, nullptr); + ASSERT_EQ(shader->GetProperties().Size(), 4u); + ASSERT_EQ(pass->variants.Size(), 2u); + ASSERT_EQ(pass->tags.Size(), 1u); + EXPECT_TRUE(pass->resources.Empty()); + EXPECT_TRUE(pass->hasFixedFunctionState); + EXPECT_EQ(pass->fixedFunctionState.cullMode, MaterialCullMode::None); + EXPECT_FALSE(pass->fixedFunctionState.depthWriteEnable); + EXPECT_EQ(pass->fixedFunctionState.depthFunc, MaterialComparisonFunc::Always); + EXPECT_EQ(pass->tags[0].name, "LightMode"); + EXPECT_EQ(pass->tags[0].value, "FinalOutput"); + + const ShaderPropertyDesc* colorScaleProperty = shader->FindProperty("_ColorScale"); + ASSERT_NE(colorScaleProperty, nullptr); + EXPECT_EQ(colorScaleProperty->type, ShaderPropertyType::Color); + + const ShaderPropertyDesc* exposureProperty = shader->FindProperty("_Exposure"); + ASSERT_NE(exposureProperty, nullptr); + EXPECT_EQ(exposureProperty->type, ShaderPropertyType::Float); + + const ShaderPropertyDesc* outputTransferProperty = shader->FindProperty("_OutputTransferMode"); + ASSERT_NE(outputTransferProperty, nullptr); + EXPECT_EQ(outputTransferProperty->type, ShaderPropertyType::Float); + + const ShaderPropertyDesc* toneMappingProperty = shader->FindProperty("_ToneMappingMode"); + ASSERT_NE(toneMappingProperty, nullptr); + EXPECT_EQ(toneMappingProperty->type, ShaderPropertyType::Float); + + EXPECT_NE(shader->FindVariant("FinalColor", ShaderType::Vertex, ShaderBackend::D3D12), nullptr); + EXPECT_NE(shader->FindVariant("FinalColor", ShaderType::Fragment, ShaderBackend::D3D12), nullptr); + EXPECT_NE(shader->FindVariant("FinalColor", ShaderType::Vertex, ShaderBackend::OpenGL), nullptr); + EXPECT_NE(shader->FindVariant("FinalColor", ShaderType::Fragment, ShaderBackend::OpenGL), nullptr); + EXPECT_NE(shader->FindVariant("FinalColor", ShaderType::Vertex, ShaderBackend::Vulkan), nullptr); + EXPECT_NE(shader->FindVariant("FinalColor", ShaderType::Fragment, ShaderBackend::Vulkan), nullptr); + + const ShaderStageVariant* d3d12Vertex = shader->FindVariant( + "FinalColor", + ShaderType::Vertex, + ShaderBackend::D3D12); + ASSERT_NE(d3d12Vertex, nullptr); + EXPECT_EQ(d3d12Vertex->backend, ShaderBackend::Generic); + EXPECT_EQ(d3d12Vertex->language, ShaderLanguage::HLSL); + EXPECT_EQ(d3d12Vertex->entryPoint, "MainVS"); + EXPECT_EQ(d3d12Vertex->profile, "vs_5_0"); + EXPECT_NE(std::string(d3d12Vertex->sourceCode.CStr()).find("UNITY_UV_STARTS_AT_TOP"), std::string::npos); + + const ShaderStageVariant* openglFragment = shader->FindVariant( + "FinalColor", + ShaderType::Fragment, + ShaderBackend::OpenGL); + ASSERT_NE(openglFragment, nullptr); + EXPECT_EQ(openglFragment->backend, ShaderBackend::Generic); + EXPECT_EQ(openglFragment->language, ShaderLanguage::HLSL); + EXPECT_EQ(openglFragment->entryPoint, "MainPS"); + EXPECT_EQ(openglFragment->profile, "ps_5_0"); + EXPECT_NE(std::string(openglFragment->sourceCode.CStr()).find("gSourceColorTexture.Sample"), std::string::npos); + + const ShaderStageVariant* vulkanFragment = shader->FindVariant( + "FinalColor", + ShaderType::Fragment, + ShaderBackend::Vulkan); + ASSERT_NE(vulkanFragment, nullptr); + EXPECT_EQ(vulkanFragment->backend, ShaderBackend::Generic); + EXPECT_EQ(vulkanFragment->language, ShaderLanguage::HLSL); + EXPECT_EQ(vulkanFragment->entryPoint, "MainPS"); + EXPECT_EQ(vulkanFragment->profile, "ps_5_0"); + EXPECT_NE(std::string(vulkanFragment->sourceCode.CStr()).find("ApplyToneMapping"), std::string::npos); + EXPECT_NE(std::string(vulkanFragment->sourceCode.CStr()).find("gFinalColorParams"), std::string::npos); + + delete shader; +} + +TEST(ShaderLoader, LoadBuiltinColorScalePostProcessShaderBuildsUnityStyleSingleSourceVariants) { + ShaderLoader loader; + LoadResult result = loader.Load(GetBuiltinColorScalePostProcessShaderPath()); + ASSERT_TRUE(result); + ASSERT_NE(result.resource, nullptr); + + Shader* shader = static_cast(result.resource); + ASSERT_NE(shader, nullptr); + ASSERT_TRUE(shader->IsValid()); + + const ShaderPass* pass = shader->FindPass("ColorScale"); + ASSERT_NE(pass, nullptr); + ASSERT_EQ(shader->GetProperties().Size(), 1u); + ASSERT_EQ(pass->variants.Size(), 2u); + ASSERT_EQ(pass->tags.Size(), 1u); + EXPECT_TRUE(pass->resources.Empty()); + EXPECT_TRUE(pass->hasFixedFunctionState); + EXPECT_EQ(pass->fixedFunctionState.cullMode, MaterialCullMode::None); + EXPECT_FALSE(pass->fixedFunctionState.depthWriteEnable); + EXPECT_EQ(pass->fixedFunctionState.depthFunc, MaterialComparisonFunc::Always); + EXPECT_EQ(pass->tags[0].name, "LightMode"); + EXPECT_EQ(pass->tags[0].value, "PostProcess"); + + const ShaderPropertyDesc* colorScaleProperty = shader->FindProperty("_ColorScale"); + ASSERT_NE(colorScaleProperty, nullptr); + EXPECT_EQ(colorScaleProperty->type, ShaderPropertyType::Color); + + EXPECT_NE(shader->FindVariant("ColorScale", ShaderType::Vertex, ShaderBackend::D3D12), nullptr); + EXPECT_NE(shader->FindVariant("ColorScale", ShaderType::Fragment, ShaderBackend::D3D12), nullptr); + EXPECT_NE(shader->FindVariant("ColorScale", ShaderType::Vertex, ShaderBackend::OpenGL), nullptr); + EXPECT_NE(shader->FindVariant("ColorScale", ShaderType::Fragment, ShaderBackend::OpenGL), nullptr); + EXPECT_NE(shader->FindVariant("ColorScale", ShaderType::Vertex, ShaderBackend::Vulkan), nullptr); + EXPECT_NE(shader->FindVariant("ColorScale", ShaderType::Fragment, ShaderBackend::Vulkan), nullptr); + + const ShaderStageVariant* d3d12Vertex = shader->FindVariant( + "ColorScale", + ShaderType::Vertex, + ShaderBackend::D3D12); + ASSERT_NE(d3d12Vertex, nullptr); + EXPECT_EQ(d3d12Vertex->backend, ShaderBackend::Generic); + EXPECT_EQ(d3d12Vertex->language, ShaderLanguage::HLSL); + EXPECT_EQ(d3d12Vertex->entryPoint, "MainVS"); + EXPECT_EQ(d3d12Vertex->profile, "vs_5_0"); + EXPECT_NE(std::string(d3d12Vertex->sourceCode.CStr()).find("UNITY_UV_STARTS_AT_TOP"), std::string::npos); + + const ShaderStageVariant* openglFragment = shader->FindVariant( + "ColorScale", + ShaderType::Fragment, + ShaderBackend::OpenGL); + ASSERT_NE(openglFragment, nullptr); + EXPECT_EQ(openglFragment->backend, ShaderBackend::Generic); + EXPECT_EQ(openglFragment->language, ShaderLanguage::HLSL); + EXPECT_EQ(openglFragment->entryPoint, "MainPS"); + EXPECT_EQ(openglFragment->profile, "ps_5_0"); + EXPECT_NE(std::string(openglFragment->sourceCode.CStr()).find("gSourceColorTexture.Sample"), std::string::npos); + + const ShaderStageVariant* vulkanFragment = shader->FindVariant( + "ColorScale", + ShaderType::Fragment, + ShaderBackend::Vulkan); + ASSERT_NE(vulkanFragment, nullptr); + EXPECT_EQ(vulkanFragment->backend, ShaderBackend::Generic); + EXPECT_EQ(vulkanFragment->language, ShaderLanguage::HLSL); + EXPECT_EQ(vulkanFragment->entryPoint, "MainPS"); + EXPECT_EQ(vulkanFragment->profile, "ps_5_0"); + EXPECT_NE(std::string(vulkanFragment->sourceCode.CStr()).find("gColorScale"), std::string::npos); + EXPECT_NE(std::string(vulkanFragment->sourceCode.CStr()).find("gSourceColorTexture.Sample"), std::string::npos); + + delete shader; +} + TEST(ShaderLoader, ResourceManagerLazilyLoadsBuiltinForwardLitShader) { ResourceManager& manager = ResourceManager::Get(); manager.Shutdown();