Add forward shadow receiving support
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
// XC_BUILTIN_FORWARD_LIT_OPENGL_PS
|
||||
#version 430
|
||||
layout(binding = 1) uniform sampler2D uBaseColorTexture;
|
||||
layout(binding = 2) uniform sampler2D uShadowMapTexture;
|
||||
|
||||
layout(std140, binding = 1) uniform PerObjectConstants {
|
||||
mat4 gProjectionMatrix;
|
||||
@@ -15,11 +16,44 @@ layout(std140, binding = 2) uniform MaterialConstants {
|
||||
vec4 gBaseColorFactor;
|
||||
};
|
||||
|
||||
layout(std140, binding = 3) uniform ShadowReceiverConstants {
|
||||
mat4 gWorldToShadowMatrix;
|
||||
vec4 gShadowBiasAndTexelSize;
|
||||
vec4 gShadowOptions;
|
||||
};
|
||||
|
||||
in vec3 vNormalWS;
|
||||
in vec2 vTexCoord;
|
||||
in vec3 vPositionWS;
|
||||
|
||||
layout(location = 0) out vec4 fragColor;
|
||||
|
||||
float ComputeShadowAttenuation(vec3 positionWS) {
|
||||
if (gShadowOptions.x < 0.5) {
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
vec4 shadowClip = gWorldToShadowMatrix * vec4(positionWS, 1.0);
|
||||
if (shadowClip.w <= 0.0) {
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
vec3 shadowNdc = shadowClip.xyz / shadowClip.w;
|
||||
vec2 shadowUv = vec2(
|
||||
shadowNdc.x * 0.5 + 0.5,
|
||||
shadowNdc.y * -0.5 + 0.5);
|
||||
if (shadowUv.x < 0.0 || shadowUv.x > 1.0 ||
|
||||
shadowUv.y < 0.0 || shadowUv.y > 1.0 ||
|
||||
shadowNdc.z < 0.0 || shadowNdc.z > 1.0) {
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
float shadowDepth = texture(uShadowMapTexture, shadowUv).r;
|
||||
float receiverDepth = shadowNdc.z - gShadowBiasAndTexelSize.x;
|
||||
float shadowStrength = clamp(gShadowBiasAndTexelSize.w, 0.0, 1.0);
|
||||
return receiverDepth <= shadowDepth ? 1.0 : (1.0 - shadowStrength);
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec4 baseColor = texture(uBaseColorTexture, vTexCoord) * gBaseColorFactor;
|
||||
if (gMainLightColorAndFlags.w < 0.5) {
|
||||
@@ -30,7 +64,10 @@ void main() {
|
||||
vec3 normalWS = normalize(vNormalWS);
|
||||
vec3 directionToLightWS = normalize(gMainLightDirectionAndIntensity.xyz);
|
||||
float diffuse = max(dot(normalWS, directionToLightWS), 0.0);
|
||||
float shadowAttenuation = diffuse > 0.0
|
||||
? ComputeShadowAttenuation(vPositionWS)
|
||||
: 1.0;
|
||||
vec3 lighting = vec3(0.28) +
|
||||
gMainLightColorAndFlags.rgb * (diffuse * gMainLightDirectionAndIntensity.w);
|
||||
gMainLightColorAndFlags.rgb * (diffuse * gMainLightDirectionAndIntensity.w * shadowAttenuation);
|
||||
fragColor = vec4(baseColor.rgb * lighting, baseColor.a);
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
#version 450
|
||||
layout(set = 3, binding = 0) uniform texture2D uBaseColorTexture;
|
||||
layout(set = 4, binding = 0) uniform sampler uLinearSampler;
|
||||
layout(set = 6, binding = 0) uniform texture2D uShadowMapTexture;
|
||||
layout(set = 7, binding = 0) uniform sampler uShadowMapSampler;
|
||||
|
||||
layout(set = 1, binding = 0, std140) uniform PerObjectConstants {
|
||||
mat4 gProjectionMatrix;
|
||||
@@ -16,11 +18,44 @@ layout(set = 2, binding = 0, std140) uniform MaterialConstants {
|
||||
vec4 gBaseColorFactor;
|
||||
};
|
||||
|
||||
layout(set = 5, binding = 0, std140) uniform ShadowReceiverConstants {
|
||||
mat4 gWorldToShadowMatrix;
|
||||
vec4 gShadowBiasAndTexelSize;
|
||||
vec4 gShadowOptions;
|
||||
};
|
||||
|
||||
layout(location = 0) in vec3 vNormalWS;
|
||||
layout(location = 1) in vec2 vTexCoord;
|
||||
layout(location = 2) in vec3 vPositionWS;
|
||||
|
||||
layout(location = 0) out vec4 fragColor;
|
||||
|
||||
float ComputeShadowAttenuation(vec3 positionWS) {
|
||||
if (gShadowOptions.x < 0.5) {
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
vec4 shadowClip = gWorldToShadowMatrix * vec4(positionWS, 1.0);
|
||||
if (shadowClip.w <= 0.0) {
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
vec3 shadowNdc = shadowClip.xyz / shadowClip.w;
|
||||
vec2 shadowUv = vec2(
|
||||
shadowNdc.x * 0.5 + 0.5,
|
||||
shadowNdc.y * -0.5 + 0.5);
|
||||
if (shadowUv.x < 0.0 || shadowUv.x > 1.0 ||
|
||||
shadowUv.y < 0.0 || shadowUv.y > 1.0 ||
|
||||
shadowNdc.z < 0.0 || shadowNdc.z > 1.0) {
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
float shadowDepth = texture(sampler2D(uShadowMapTexture, uShadowMapSampler), shadowUv).r;
|
||||
float receiverDepth = shadowNdc.z - gShadowBiasAndTexelSize.x;
|
||||
float shadowStrength = clamp(gShadowBiasAndTexelSize.w, 0.0, 1.0);
|
||||
return receiverDepth <= shadowDepth ? 1.0 : (1.0 - shadowStrength);
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec4 baseColor = texture(sampler2D(uBaseColorTexture, uLinearSampler), vTexCoord) * gBaseColorFactor;
|
||||
if (gMainLightColorAndFlags.w < 0.5) {
|
||||
@@ -31,7 +66,10 @@ void main() {
|
||||
vec3 normalWS = normalize(vNormalWS);
|
||||
vec3 directionToLightWS = normalize(gMainLightDirectionAndIntensity.xyz);
|
||||
float diffuse = max(dot(normalWS, directionToLightWS), 0.0);
|
||||
float shadowAttenuation = diffuse > 0.0
|
||||
? ComputeShadowAttenuation(vPositionWS)
|
||||
: 1.0;
|
||||
vec3 lighting = vec3(0.28) +
|
||||
gMainLightColorAndFlags.rgb * (diffuse * gMainLightDirectionAndIntensity.w);
|
||||
gMainLightColorAndFlags.rgb * (diffuse * gMainLightDirectionAndIntensity.w * shadowAttenuation);
|
||||
fragColor = vec4(baseColor.rgb * lighting, baseColor.a);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
// XC_BUILTIN_FORWARD_LIT_D3D12_PS
|
||||
Texture2D gBaseColorTexture : register(t1);
|
||||
SamplerState gLinearSampler : register(s1);
|
||||
Texture2D gShadowMapTexture : register(t2);
|
||||
SamplerState gShadowMapSampler : register(s2);
|
||||
|
||||
cbuffer PerObjectConstants : register(b1) {
|
||||
float4x4 gProjectionMatrix;
|
||||
@@ -15,12 +17,45 @@ cbuffer MaterialConstants : register(b2) {
|
||||
float4 gBaseColorFactor;
|
||||
};
|
||||
|
||||
cbuffer ShadowReceiverConstants : register(b3) {
|
||||
float4x4 gWorldToShadowMatrix;
|
||||
float4 gShadowBiasAndTexelSize;
|
||||
float4 gShadowOptions;
|
||||
};
|
||||
|
||||
struct PSInput {
|
||||
float4 position : SV_POSITION;
|
||||
float3 normalWS : TEXCOORD0;
|
||||
float2 texcoord : TEXCOORD1;
|
||||
float3 positionWS : TEXCOORD2;
|
||||
};
|
||||
|
||||
float ComputeShadowAttenuation(float3 positionWS) {
|
||||
if (gShadowOptions.x < 0.5f) {
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
float4 shadowClip = mul(gWorldToShadowMatrix, float4(positionWS, 1.0f));
|
||||
if (shadowClip.w <= 0.0f) {
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
float3 shadowNdc = shadowClip.xyz / shadowClip.w;
|
||||
float2 shadowUv = float2(
|
||||
shadowNdc.x * 0.5f + 0.5f,
|
||||
shadowNdc.y * -0.5f + 0.5f);
|
||||
if (shadowUv.x < 0.0f || shadowUv.x > 1.0f ||
|
||||
shadowUv.y < 0.0f || shadowUv.y > 1.0f ||
|
||||
shadowNdc.z < 0.0f || shadowNdc.z > 1.0f) {
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
const float shadowDepth = gShadowMapTexture.Sample(gShadowMapSampler, shadowUv).r;
|
||||
const float receiverDepth = shadowNdc.z - gShadowBiasAndTexelSize.x;
|
||||
const float shadowStrength = saturate(gShadowBiasAndTexelSize.w);
|
||||
return receiverDepth <= shadowDepth ? 1.0f : (1.0f - shadowStrength);
|
||||
}
|
||||
|
||||
float4 MainPS(PSInput input) : SV_TARGET {
|
||||
float4 baseColor = gBaseColorTexture.Sample(gLinearSampler, input.texcoord) * gBaseColorFactor;
|
||||
if (gMainLightColorAndFlags.a < 0.5f) {
|
||||
@@ -30,7 +65,10 @@ float4 MainPS(PSInput input) : SV_TARGET {
|
||||
float3 normalWS = normalize(input.normalWS);
|
||||
float3 directionToLightWS = normalize(gMainLightDirectionAndIntensity.xyz);
|
||||
float diffuse = saturate(dot(normalWS, directionToLightWS));
|
||||
float shadowAttenuation = diffuse > 0.0f
|
||||
? ComputeShadowAttenuation(input.positionWS)
|
||||
: 1.0f;
|
||||
float3 lighting = float3(0.28f, 0.28f, 0.28f) +
|
||||
gMainLightColorAndFlags.rgb * (diffuse * gMainLightDirectionAndIntensity.w);
|
||||
gMainLightColorAndFlags.rgb * (diffuse * gMainLightDirectionAndIntensity.w * shadowAttenuation);
|
||||
return float4(baseColor.rgb * lighting, baseColor.a);
|
||||
}
|
||||
|
||||
@@ -17,6 +17,9 @@ Shader "Builtin Forward Lit"
|
||||
MaterialConstants (ConstantBuffer, 2, 0) [Semantic(Material)]
|
||||
BaseColorTexture (Texture2D, 3, 0) [Semantic(BaseColorTexture)]
|
||||
LinearClampSampler (Sampler, 4, 0) [Semantic(LinearClampSampler)]
|
||||
ShadowReceiverConstants (ConstantBuffer, 5, 0) [Semantic(ShadowReceiver)]
|
||||
ShadowMapTexture (Texture2D, 6, 0) [Semantic(ShadowMapTexture)]
|
||||
ShadowMapSampler (Sampler, 7, 0) [Semantic(ShadowMapSampler)]
|
||||
}
|
||||
HLSLPROGRAM
|
||||
#pragma vertex MainVS
|
||||
|
||||
@@ -15,6 +15,7 @@ layout(std140, binding = 1) uniform PerObjectConstants {
|
||||
|
||||
out vec3 vNormalWS;
|
||||
out vec2 vTexCoord;
|
||||
out vec3 vPositionWS;
|
||||
|
||||
void main() {
|
||||
vec4 positionWS = gModelMatrix * vec4(aPosition, 1.0);
|
||||
@@ -22,4 +23,5 @@ void main() {
|
||||
gl_Position = gProjectionMatrix * positionVS;
|
||||
vNormalWS = mat3(gNormalMatrix) * aNormal;
|
||||
vTexCoord = aTexCoord;
|
||||
vPositionWS = positionWS.xyz;
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ layout(set = 1, binding = 0, std140) uniform PerObjectConstants {
|
||||
|
||||
layout(location = 0) out vec3 vNormalWS;
|
||||
layout(location = 1) out vec2 vTexCoord;
|
||||
layout(location = 2) out vec3 vPositionWS;
|
||||
|
||||
void main() {
|
||||
vec4 positionWS = gModelMatrix * vec4(aPosition, 1.0);
|
||||
@@ -22,4 +23,5 @@ void main() {
|
||||
gl_Position = gProjectionMatrix * positionVS;
|
||||
vNormalWS = mat3(gNormalMatrix) * aNormal;
|
||||
vTexCoord = aTexCoord;
|
||||
vPositionWS = positionWS.xyz;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
// XC_BUILTIN_FORWARD_LIT_D3D12_VS
|
||||
Texture2D gBaseColorTexture : register(t1);
|
||||
SamplerState gLinearSampler : register(s1);
|
||||
|
||||
cbuffer PerObjectConstants : register(b1) {
|
||||
float4x4 gProjectionMatrix;
|
||||
float4x4 gViewMatrix;
|
||||
@@ -11,10 +8,6 @@ cbuffer PerObjectConstants : register(b1) {
|
||||
float4 gMainLightColorAndFlags;
|
||||
};
|
||||
|
||||
cbuffer MaterialConstants : register(b2) {
|
||||
float4 gBaseColorFactor;
|
||||
};
|
||||
|
||||
struct VSInput {
|
||||
float3 position : POSITION;
|
||||
float3 normal : NORMAL;
|
||||
@@ -25,6 +18,7 @@ struct PSInput {
|
||||
float4 position : SV_POSITION;
|
||||
float3 normalWS : TEXCOORD0;
|
||||
float2 texcoord : TEXCOORD1;
|
||||
float3 positionWS : TEXCOORD2;
|
||||
};
|
||||
|
||||
PSInput MainVS(VSInput input) {
|
||||
@@ -34,5 +28,6 @@ PSInput MainVS(VSInput input) {
|
||||
output.position = mul(gProjectionMatrix, positionVS);
|
||||
output.normalWS = mul((float3x3)gNormalMatrix, input.normal);
|
||||
output.texcoord = input.texcoord;
|
||||
output.positionWS = positionWS.xyz;
|
||||
return output;
|
||||
}
|
||||
|
||||
@@ -143,8 +143,12 @@ private:
|
||||
ComPtr<ID3D12GraphicsCommandList> m_commandList;
|
||||
ComPtr<ID3D12CommandAllocator> m_commandAllocator;
|
||||
ComPtr<ID3D12DescriptorHeap> m_rtvHeap;
|
||||
ComPtr<ID3D12DescriptorHeap> m_shaderVisibleCbvSrvUavHeap;
|
||||
ComPtr<ID3D12DescriptorHeap> m_shaderVisibleSamplerHeap;
|
||||
ID3D12Device* m_device = nullptr;
|
||||
CommandQueueType m_type;
|
||||
uint32_t m_shaderVisibleCbvSrvUavHeapCapacity = 0;
|
||||
uint32_t m_shaderVisibleSamplerHeapCapacity = 0;
|
||||
|
||||
std::unordered_map<ID3D12Resource*, ResourceStates> m_resourceStateMap;
|
||||
std::vector<ID3D12Resource*> m_trackedResources;
|
||||
|
||||
@@ -42,6 +42,8 @@ public:
|
||||
|
||||
D3D12_GPU_DESCRIPTOR_HANDLE GetGPUHandle(uint32_t index = 0) const;
|
||||
D3D12_GPU_DESCRIPTOR_HANDLE GetGPUHandleForBinding(uint32_t binding) const;
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE GetCPUHandleForBinding(uint32_t binding) const;
|
||||
uint32_t GetDescriptorCountForBinding(uint32_t binding) const;
|
||||
uint32_t GetOffset() const { return m_offset; }
|
||||
uint32_t GetCount() const { return m_count; }
|
||||
D3D12DescriptorHeap* GetHeap() const { return m_heap; }
|
||||
|
||||
@@ -68,6 +68,12 @@ private:
|
||||
Math::Vector4 mainLightColorAndFlags = Math::Vector4::Zero();
|
||||
};
|
||||
|
||||
struct ShadowReceiverConstants {
|
||||
Math::Matrix4x4 worldToShadow = Math::Matrix4x4::Identity();
|
||||
Math::Vector4 shadowBiasAndTexelSize = Math::Vector4::Zero();
|
||||
Math::Vector4 shadowOptions = Math::Vector4::Zero();
|
||||
};
|
||||
|
||||
struct FallbackPerMaterialConstants {
|
||||
Math::Vector4 baseColorFactor = Math::Vector4::One();
|
||||
};
|
||||
@@ -97,8 +103,11 @@ private:
|
||||
std::vector<OwnedDescriptorSet> staticDescriptorSets;
|
||||
PassResourceBindingLocation perObject = {};
|
||||
PassResourceBindingLocation material = {};
|
||||
PassResourceBindingLocation shadowReceiver = {};
|
||||
PassResourceBindingLocation baseColorTexture = {};
|
||||
PassResourceBindingLocation linearClampSampler = {};
|
||||
PassResourceBindingLocation shadowMapTexture = {};
|
||||
PassResourceBindingLocation shadowMapSampler = {};
|
||||
};
|
||||
|
||||
struct DynamicDescriptorSetKey {
|
||||
@@ -132,7 +141,8 @@ private:
|
||||
struct CachedDescriptorSet {
|
||||
OwnedDescriptorSet descriptorSet = {};
|
||||
Core::uint64 materialVersion = 0;
|
||||
RHI::RHIResourceView* textureView = nullptr;
|
||||
RHI::RHIResourceView* baseColorTextureView = nullptr;
|
||||
RHI::RHIResourceView* shadowMapTextureView = nullptr;
|
||||
};
|
||||
|
||||
struct ResolvedShaderPass {
|
||||
@@ -190,7 +200,9 @@ private:
|
||||
Core::uint64 objectId,
|
||||
const Resources::Material* material,
|
||||
const MaterialConstantPayloadView& materialConstants,
|
||||
RHI::RHIResourceView* textureView);
|
||||
const ShadowReceiverConstants& shadowReceiverConstants,
|
||||
RHI::RHIResourceView* baseColorTextureView,
|
||||
RHI::RHIResourceView* shadowMapTextureView);
|
||||
void DestroyOwnedDescriptorSet(OwnedDescriptorSet& descriptorSet);
|
||||
void DestroyPassResourceLayout(PassResourceLayout& passLayout);
|
||||
|
||||
@@ -214,6 +226,7 @@ private:
|
||||
std::unordered_map<PipelineStateKey, RHI::RHIPipelineState*, PipelineStateKeyHash> m_pipelineStates;
|
||||
std::unordered_map<DynamicDescriptorSetKey, CachedDescriptorSet, DynamicDescriptorSetKeyHash> m_dynamicDescriptorSets;
|
||||
RHI::RHISampler* m_sampler = nullptr;
|
||||
RHI::RHISampler* m_shadowSampler = nullptr;
|
||||
RHI::RHITexture* m_fallbackTexture = nullptr;
|
||||
RHI::RHIResourceView* m_fallbackTextureView = nullptr;
|
||||
RenderPassSequence m_passSequence;
|
||||
|
||||
@@ -37,8 +37,11 @@ enum class BuiltinPassResourceSemantic : Core::uint8 {
|
||||
Unknown = 0,
|
||||
PerObject,
|
||||
Material,
|
||||
ShadowReceiver,
|
||||
BaseColorTexture,
|
||||
LinearClampSampler
|
||||
ShadowMapTexture,
|
||||
LinearClampSampler,
|
||||
ShadowMapSampler
|
||||
};
|
||||
|
||||
struct BuiltinPassResourceBindingDesc {
|
||||
@@ -57,8 +60,11 @@ struct BuiltinPassResourceBindingPlan {
|
||||
bool usesSamplers = false;
|
||||
PassResourceBindingLocation perObject = {};
|
||||
PassResourceBindingLocation material = {};
|
||||
PassResourceBindingLocation shadowReceiver = {};
|
||||
PassResourceBindingLocation baseColorTexture = {};
|
||||
PassResourceBindingLocation linearClampSampler = {};
|
||||
PassResourceBindingLocation shadowMapTexture = {};
|
||||
PassResourceBindingLocation shadowMapSampler = {};
|
||||
|
||||
const BuiltinPassResourceBindingDesc* FindBinding(BuiltinPassResourceSemantic semantic) const {
|
||||
for (const BuiltinPassResourceBindingDesc& binding : bindings) {
|
||||
@@ -78,8 +84,13 @@ struct BuiltinPassSetLayoutMetadata {
|
||||
bool shaderVisible = false;
|
||||
bool usesPerObject = false;
|
||||
bool usesMaterial = false;
|
||||
bool usesShadowReceiver = false;
|
||||
bool usesTexture = false;
|
||||
bool usesBaseColorTexture = false;
|
||||
bool usesShadowMapTexture = false;
|
||||
bool usesSampler = false;
|
||||
bool usesLinearClampSampler = false;
|
||||
bool usesShadowMapSampler = false;
|
||||
};
|
||||
|
||||
inline Containers::String NormalizeBuiltinPassMetadataValue(const Containers::String& value) {
|
||||
@@ -198,15 +209,30 @@ inline BuiltinPassResourceSemantic ResolveBuiltinPassResourceSemantic(
|
||||
return BuiltinPassResourceSemantic::Material;
|
||||
}
|
||||
|
||||
if (semantic == Containers::String("shadowreceiver") ||
|
||||
semantic == Containers::String("shadowreceiverconstants")) {
|
||||
return BuiltinPassResourceSemantic::ShadowReceiver;
|
||||
}
|
||||
|
||||
if (semantic == Containers::String("basecolortexture") ||
|
||||
semantic == Containers::String("maintex")) {
|
||||
return BuiltinPassResourceSemantic::BaseColorTexture;
|
||||
}
|
||||
|
||||
if (semantic == Containers::String("shadowmaptexture") ||
|
||||
semantic == Containers::String("shadowmap")) {
|
||||
return BuiltinPassResourceSemantic::ShadowMapTexture;
|
||||
}
|
||||
|
||||
if (semantic == Containers::String("linearclampsampler")) {
|
||||
return BuiltinPassResourceSemantic::LinearClampSampler;
|
||||
}
|
||||
|
||||
if (semantic == Containers::String("shadowmapsampler") ||
|
||||
semantic == Containers::String("shadowsampler")) {
|
||||
return BuiltinPassResourceSemantic::ShadowMapSampler;
|
||||
}
|
||||
|
||||
return BuiltinPassResourceSemantic::Unknown;
|
||||
}
|
||||
|
||||
@@ -286,11 +312,14 @@ inline bool IsBuiltinPassResourceTypeCompatible(
|
||||
switch (semantic) {
|
||||
case BuiltinPassResourceSemantic::PerObject:
|
||||
case BuiltinPassResourceSemantic::Material:
|
||||
case BuiltinPassResourceSemantic::ShadowReceiver:
|
||||
return type == Resources::ShaderResourceType::ConstantBuffer;
|
||||
case BuiltinPassResourceSemantic::BaseColorTexture:
|
||||
case BuiltinPassResourceSemantic::ShadowMapTexture:
|
||||
return type == Resources::ShaderResourceType::Texture2D ||
|
||||
type == Resources::ShaderResourceType::TextureCube;
|
||||
case BuiltinPassResourceSemantic::LinearClampSampler:
|
||||
case BuiltinPassResourceSemantic::ShadowMapSampler:
|
||||
return type == Resources::ShaderResourceType::Sampler;
|
||||
case BuiltinPassResourceSemantic::Unknown:
|
||||
default:
|
||||
@@ -336,12 +365,21 @@ inline bool TryBuildBuiltinPassResourceBindingPlan(
|
||||
case BuiltinPassResourceSemantic::Material:
|
||||
location = &outPlan.material;
|
||||
break;
|
||||
case BuiltinPassResourceSemantic::ShadowReceiver:
|
||||
location = &outPlan.shadowReceiver;
|
||||
break;
|
||||
case BuiltinPassResourceSemantic::BaseColorTexture:
|
||||
location = &outPlan.baseColorTexture;
|
||||
break;
|
||||
case BuiltinPassResourceSemantic::LinearClampSampler:
|
||||
location = &outPlan.linearClampSampler;
|
||||
break;
|
||||
case BuiltinPassResourceSemantic::ShadowMapTexture:
|
||||
location = &outPlan.shadowMapTexture;
|
||||
break;
|
||||
case BuiltinPassResourceSemantic::ShadowMapSampler:
|
||||
location = &outPlan.shadowMapSampler;
|
||||
break;
|
||||
case BuiltinPassResourceSemantic::Unknown:
|
||||
default:
|
||||
break;
|
||||
@@ -520,11 +558,24 @@ inline bool TryBuildBuiltinPassSetLayouts(
|
||||
case BuiltinPassResourceSemantic::Material:
|
||||
setLayout.usesMaterial = true;
|
||||
break;
|
||||
case BuiltinPassResourceSemantic::ShadowReceiver:
|
||||
setLayout.usesShadowReceiver = true;
|
||||
break;
|
||||
case BuiltinPassResourceSemantic::BaseColorTexture:
|
||||
setLayout.usesTexture = true;
|
||||
setLayout.usesBaseColorTexture = true;
|
||||
break;
|
||||
case BuiltinPassResourceSemantic::ShadowMapTexture:
|
||||
setLayout.usesTexture = true;
|
||||
setLayout.usesShadowMapTexture = true;
|
||||
break;
|
||||
case BuiltinPassResourceSemantic::LinearClampSampler:
|
||||
setLayout.usesSampler = true;
|
||||
setLayout.usesLinearClampSampler = true;
|
||||
break;
|
||||
case BuiltinPassResourceSemantic::ShadowMapSampler:
|
||||
setLayout.usesSampler = true;
|
||||
setLayout.usesShadowMapSampler = true;
|
||||
break;
|
||||
case BuiltinPassResourceSemantic::Unknown:
|
||||
default:
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <XCEngine/Core/Math/Vector4.h>
|
||||
#include <XCEngine/Core/Math/Vector3.h>
|
||||
#include <XCEngine/Rendering/RenderCameraData.h>
|
||||
#include <XCEngine/Rendering/VisibleRenderObject.h>
|
||||
@@ -14,6 +15,10 @@ class GameObject;
|
||||
class Scene;
|
||||
} // namespace Components
|
||||
|
||||
namespace RHI {
|
||||
class RHIResourceView;
|
||||
} // namespace RHI
|
||||
|
||||
namespace Rendering {
|
||||
|
||||
struct RenderDirectionalLightData {
|
||||
@@ -24,12 +29,28 @@ struct RenderDirectionalLightData {
|
||||
Math::Color color = Math::Color::White();
|
||||
};
|
||||
|
||||
struct RenderDirectionalShadowData {
|
||||
bool enabled = false;
|
||||
Math::Matrix4x4 viewProjection = Math::Matrix4x4::Identity();
|
||||
Math::Vector4 shadowParams = Math::Vector4::Zero();
|
||||
RHI::RHIResourceView* shadowMap = nullptr;
|
||||
|
||||
bool IsValid() const {
|
||||
return enabled && shadowMap != nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
struct RenderLightingData {
|
||||
RenderDirectionalLightData mainDirectionalLight;
|
||||
RenderDirectionalShadowData mainDirectionalShadow;
|
||||
|
||||
bool HasMainDirectionalLight() const {
|
||||
return mainDirectionalLight.enabled;
|
||||
}
|
||||
|
||||
bool HasMainDirectionalShadow() const {
|
||||
return mainDirectionalShadow.IsValid();
|
||||
}
|
||||
};
|
||||
|
||||
struct RenderSceneData {
|
||||
|
||||
@@ -26,6 +26,45 @@ bool HasSamplerBindings(const D3D12DescriptorSet* descriptorSet) {
|
||||
return descriptorSet != nullptr && descriptorSet->HasBindingType(DescriptorType::Sampler);
|
||||
}
|
||||
|
||||
uint32_t CountDescriptorsOfType(const D3D12DescriptorSet* descriptorSet, DescriptorType type) {
|
||||
if (descriptorSet == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t descriptorCount = 0;
|
||||
const DescriptorSetLayoutBinding* bindings = descriptorSet->GetBindings();
|
||||
for (uint32_t bindingIndex = 0; bindingIndex < descriptorSet->GetBindingCount(); ++bindingIndex) {
|
||||
const DescriptorSetLayoutBinding& binding = bindings[bindingIndex];
|
||||
if (static_cast<DescriptorType>(binding.type) == type) {
|
||||
descriptorCount += binding.count > 0 ? binding.count : 1u;
|
||||
}
|
||||
}
|
||||
|
||||
return descriptorCount;
|
||||
}
|
||||
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE OffsetCPUHandle(
|
||||
ID3D12Device* device,
|
||||
ID3D12DescriptorHeap* heap,
|
||||
D3D12_DESCRIPTOR_HEAP_TYPE heapType,
|
||||
uint32_t descriptorIndex) {
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE handle = heap->GetCPUDescriptorHandleForHeapStart();
|
||||
const UINT descriptorSize = device->GetDescriptorHandleIncrementSize(heapType);
|
||||
handle.ptr += static_cast<SIZE_T>(descriptorIndex) * descriptorSize;
|
||||
return handle;
|
||||
}
|
||||
|
||||
D3D12_GPU_DESCRIPTOR_HANDLE OffsetGPUHandle(
|
||||
ID3D12Device* device,
|
||||
ID3D12DescriptorHeap* heap,
|
||||
D3D12_DESCRIPTOR_HEAP_TYPE heapType,
|
||||
uint32_t descriptorIndex) {
|
||||
D3D12_GPU_DESCRIPTOR_HANDLE handle = heap->GetGPUDescriptorHandleForHeapStart();
|
||||
const UINT descriptorSize = device->GetDescriptorHandleIncrementSize(heapType);
|
||||
handle.ptr += static_cast<UINT64>(descriptorIndex) * descriptorSize;
|
||||
return handle;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
D3D12CommandList::D3D12CommandList()
|
||||
@@ -84,6 +123,10 @@ bool D3D12CommandList::Initialize(ID3D12Device* device, CommandQueueType type, I
|
||||
void D3D12CommandList::Shutdown() {
|
||||
m_commandList.Reset();
|
||||
m_rtvHeap.Reset();
|
||||
m_shaderVisibleCbvSrvUavHeap.Reset();
|
||||
m_shaderVisibleSamplerHeap.Reset();
|
||||
m_shaderVisibleCbvSrvUavHeapCapacity = 0;
|
||||
m_shaderVisibleSamplerHeapCapacity = 0;
|
||||
m_resourceStateMap.clear();
|
||||
m_trackedResources.clear();
|
||||
m_currentShader = nullptr;
|
||||
@@ -186,8 +229,8 @@ void D3D12CommandList::SetGraphicsDescriptorSets(
|
||||
D3D12PipelineLayout* d3d12Layout = static_cast<D3D12PipelineLayout*>(pipelineLayout);
|
||||
SetPipelineLayout(d3d12Layout);
|
||||
|
||||
std::vector<ID3D12DescriptorHeap*> descriptorHeaps;
|
||||
descriptorHeaps.reserve(2);
|
||||
uint32_t requiredCbvSrvUavDescriptors = 0;
|
||||
uint32_t requiredSamplerDescriptors = 0;
|
||||
|
||||
for (uint32_t i = 0; i < count; ++i) {
|
||||
if (descriptorSets[i] == nullptr) {
|
||||
@@ -195,21 +238,73 @@ void D3D12CommandList::SetGraphicsDescriptorSets(
|
||||
}
|
||||
|
||||
D3D12DescriptorSet* d3d12Set = static_cast<D3D12DescriptorSet*>(descriptorSets[i]);
|
||||
D3D12DescriptorHeap* heap = d3d12Set->GetHeap();
|
||||
if (heap != nullptr && heap->IsShaderVisible() &&
|
||||
(HasDescriptorTableBindings(d3d12Set) || HasSamplerBindings(d3d12Set))) {
|
||||
ID3D12DescriptorHeap* nativeHeap = heap->GetDescriptorHeap();
|
||||
if (nativeHeap != nullptr &&
|
||||
std::find(descriptorHeaps.begin(), descriptorHeaps.end(), nativeHeap) == descriptorHeaps.end()) {
|
||||
descriptorHeaps.push_back(nativeHeap);
|
||||
}
|
||||
if (HasDescriptorTableBindings(d3d12Set)) {
|
||||
requiredCbvSrvUavDescriptors += CountDescriptorsOfType(d3d12Set, DescriptorType::SRV);
|
||||
requiredCbvSrvUavDescriptors += CountDescriptorsOfType(d3d12Set, DescriptorType::UAV);
|
||||
}
|
||||
if (HasSamplerBindings(d3d12Set)) {
|
||||
requiredSamplerDescriptors += CountDescriptorsOfType(d3d12Set, DescriptorType::Sampler);
|
||||
}
|
||||
}
|
||||
|
||||
auto ensureShaderVisibleHeap =
|
||||
[this](D3D12_DESCRIPTOR_HEAP_TYPE heapType,
|
||||
uint32_t requiredDescriptors,
|
||||
ComPtr<ID3D12DescriptorHeap>& heap,
|
||||
uint32_t& capacity) -> bool {
|
||||
if (requiredDescriptors == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (heap != nullptr && capacity >= requiredDescriptors) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const uint32_t newCapacity = std::max<uint32_t>(requiredDescriptors, capacity > 0 ? capacity * 2u : 32u);
|
||||
D3D12_DESCRIPTOR_HEAP_DESC heapDesc = {};
|
||||
heapDesc.Type = heapType;
|
||||
heapDesc.NumDescriptors = newCapacity;
|
||||
heapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
|
||||
heapDesc.NodeMask = 0;
|
||||
|
||||
ComPtr<ID3D12DescriptorHeap> newHeap;
|
||||
if (FAILED(m_device->CreateDescriptorHeap(&heapDesc, IID_PPV_ARGS(&newHeap)))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
heap = newHeap;
|
||||
capacity = newCapacity;
|
||||
return true;
|
||||
};
|
||||
|
||||
if (!ensureShaderVisibleHeap(
|
||||
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
|
||||
requiredCbvSrvUavDescriptors,
|
||||
m_shaderVisibleCbvSrvUavHeap,
|
||||
m_shaderVisibleCbvSrvUavHeapCapacity) ||
|
||||
!ensureShaderVisibleHeap(
|
||||
D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER,
|
||||
requiredSamplerDescriptors,
|
||||
m_shaderVisibleSamplerHeap,
|
||||
m_shaderVisibleSamplerHeapCapacity)) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<ID3D12DescriptorHeap*> descriptorHeaps;
|
||||
descriptorHeaps.reserve(2);
|
||||
if (requiredCbvSrvUavDescriptors > 0 && m_shaderVisibleCbvSrvUavHeap != nullptr) {
|
||||
descriptorHeaps.push_back(m_shaderVisibleCbvSrvUavHeap.Get());
|
||||
}
|
||||
if (requiredSamplerDescriptors > 0 && m_shaderVisibleSamplerHeap != nullptr) {
|
||||
descriptorHeaps.push_back(m_shaderVisibleSamplerHeap.Get());
|
||||
}
|
||||
if (!descriptorHeaps.empty()) {
|
||||
SetDescriptorHeaps(static_cast<uint32_t>(descriptorHeaps.size()), descriptorHeaps.data());
|
||||
}
|
||||
|
||||
uint32_t nextCbvSrvUavDescriptor = 0;
|
||||
uint32_t nextSamplerDescriptor = 0;
|
||||
|
||||
for (uint32_t i = 0; i < count; ++i) {
|
||||
if (descriptorSets[i] == nullptr) {
|
||||
continue;
|
||||
@@ -251,7 +346,24 @@ void D3D12CommandList::SetGraphicsDescriptorSets(
|
||||
|
||||
if (d3d12Set->HasBindingType(DescriptorType::SRV) && hasSrvTable) {
|
||||
const uint32_t srvBinding = d3d12Set->GetFirstBindingOfType(DescriptorType::SRV);
|
||||
const D3D12_GPU_DESCRIPTOR_HANDLE gpuHandle = d3d12Set->GetGPUHandleForBinding(srvBinding);
|
||||
const uint32_t srvDescriptorCount = CountDescriptorsOfType(d3d12Set, DescriptorType::SRV);
|
||||
const D3D12_CPU_DESCRIPTOR_HANDLE srcHandle = d3d12Set->GetCPUHandleForBinding(srvBinding);
|
||||
const D3D12_CPU_DESCRIPTOR_HANDLE dstHandle = OffsetCPUHandle(
|
||||
m_device,
|
||||
m_shaderVisibleCbvSrvUavHeap.Get(),
|
||||
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
|
||||
nextCbvSrvUavDescriptor);
|
||||
m_device->CopyDescriptorsSimple(
|
||||
srvDescriptorCount,
|
||||
dstHandle,
|
||||
srcHandle,
|
||||
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
|
||||
const D3D12_GPU_DESCRIPTOR_HANDLE gpuHandle = OffsetGPUHandle(
|
||||
m_device,
|
||||
m_shaderVisibleCbvSrvUavHeap.Get(),
|
||||
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
|
||||
nextCbvSrvUavDescriptor);
|
||||
nextCbvSrvUavDescriptor += srvDescriptorCount;
|
||||
if (gpuHandle.ptr != 0) {
|
||||
SetGraphicsRootDescriptorTable(
|
||||
d3d12Layout->UsesSetLayouts()
|
||||
@@ -263,7 +375,24 @@ void D3D12CommandList::SetGraphicsDescriptorSets(
|
||||
|
||||
if (d3d12Set->HasBindingType(DescriptorType::UAV) && hasUavTable) {
|
||||
const uint32_t uavBinding = d3d12Set->GetFirstBindingOfType(DescriptorType::UAV);
|
||||
const D3D12_GPU_DESCRIPTOR_HANDLE gpuHandle = d3d12Set->GetGPUHandleForBinding(uavBinding);
|
||||
const uint32_t uavDescriptorCount = CountDescriptorsOfType(d3d12Set, DescriptorType::UAV);
|
||||
const D3D12_CPU_DESCRIPTOR_HANDLE srcHandle = d3d12Set->GetCPUHandleForBinding(uavBinding);
|
||||
const D3D12_CPU_DESCRIPTOR_HANDLE dstHandle = OffsetCPUHandle(
|
||||
m_device,
|
||||
m_shaderVisibleCbvSrvUavHeap.Get(),
|
||||
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
|
||||
nextCbvSrvUavDescriptor);
|
||||
m_device->CopyDescriptorsSimple(
|
||||
uavDescriptorCount,
|
||||
dstHandle,
|
||||
srcHandle,
|
||||
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
|
||||
const D3D12_GPU_DESCRIPTOR_HANDLE gpuHandle = OffsetGPUHandle(
|
||||
m_device,
|
||||
m_shaderVisibleCbvSrvUavHeap.Get(),
|
||||
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
|
||||
nextCbvSrvUavDescriptor);
|
||||
nextCbvSrvUavDescriptor += uavDescriptorCount;
|
||||
if (gpuHandle.ptr != 0) {
|
||||
SetGraphicsRootDescriptorTable(
|
||||
d3d12Layout->UsesSetLayouts()
|
||||
@@ -278,7 +407,24 @@ void D3D12CommandList::SetGraphicsDescriptorSets(
|
||||
? d3d12Layout->HasSamplerTable(setIndex)
|
||||
: d3d12Layout->HasSamplerTable())) {
|
||||
const uint32_t samplerBinding = d3d12Set->GetFirstBindingOfType(DescriptorType::Sampler);
|
||||
const D3D12_GPU_DESCRIPTOR_HANDLE gpuHandle = d3d12Set->GetGPUHandleForBinding(samplerBinding);
|
||||
const uint32_t samplerDescriptorCount = CountDescriptorsOfType(d3d12Set, DescriptorType::Sampler);
|
||||
const D3D12_CPU_DESCRIPTOR_HANDLE srcHandle = d3d12Set->GetCPUHandleForBinding(samplerBinding);
|
||||
const D3D12_CPU_DESCRIPTOR_HANDLE dstHandle = OffsetCPUHandle(
|
||||
m_device,
|
||||
m_shaderVisibleSamplerHeap.Get(),
|
||||
D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER,
|
||||
nextSamplerDescriptor);
|
||||
m_device->CopyDescriptorsSimple(
|
||||
samplerDescriptorCount,
|
||||
dstHandle,
|
||||
srcHandle,
|
||||
D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER);
|
||||
const D3D12_GPU_DESCRIPTOR_HANDLE gpuHandle = OffsetGPUHandle(
|
||||
m_device,
|
||||
m_shaderVisibleSamplerHeap.Get(),
|
||||
D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER,
|
||||
nextSamplerDescriptor);
|
||||
nextSamplerDescriptor += samplerDescriptorCount;
|
||||
if (gpuHandle.ptr != 0) {
|
||||
SetGraphicsRootDescriptorTable(
|
||||
d3d12Layout->UsesSetLayouts()
|
||||
@@ -303,8 +449,8 @@ void D3D12CommandList::SetComputeDescriptorSets(
|
||||
SetPipelineLayout(d3d12Layout);
|
||||
m_commandList->SetComputeRootSignature(d3d12Layout->GetRootSignature());
|
||||
|
||||
std::vector<ID3D12DescriptorHeap*> descriptorHeaps;
|
||||
descriptorHeaps.reserve(2);
|
||||
uint32_t requiredCbvSrvUavDescriptors = 0;
|
||||
uint32_t requiredSamplerDescriptors = 0;
|
||||
|
||||
for (uint32_t i = 0; i < count; ++i) {
|
||||
if (descriptorSets[i] == nullptr) {
|
||||
@@ -312,21 +458,73 @@ void D3D12CommandList::SetComputeDescriptorSets(
|
||||
}
|
||||
|
||||
D3D12DescriptorSet* d3d12Set = static_cast<D3D12DescriptorSet*>(descriptorSets[i]);
|
||||
D3D12DescriptorHeap* heap = d3d12Set->GetHeap();
|
||||
if (heap != nullptr && heap->IsShaderVisible() &&
|
||||
(HasDescriptorTableBindings(d3d12Set) || HasSamplerBindings(d3d12Set))) {
|
||||
ID3D12DescriptorHeap* nativeHeap = heap->GetDescriptorHeap();
|
||||
if (nativeHeap != nullptr &&
|
||||
std::find(descriptorHeaps.begin(), descriptorHeaps.end(), nativeHeap) == descriptorHeaps.end()) {
|
||||
descriptorHeaps.push_back(nativeHeap);
|
||||
}
|
||||
if (HasDescriptorTableBindings(d3d12Set)) {
|
||||
requiredCbvSrvUavDescriptors += CountDescriptorsOfType(d3d12Set, DescriptorType::SRV);
|
||||
requiredCbvSrvUavDescriptors += CountDescriptorsOfType(d3d12Set, DescriptorType::UAV);
|
||||
}
|
||||
if (HasSamplerBindings(d3d12Set)) {
|
||||
requiredSamplerDescriptors += CountDescriptorsOfType(d3d12Set, DescriptorType::Sampler);
|
||||
}
|
||||
}
|
||||
|
||||
auto ensureShaderVisibleHeap =
|
||||
[this](D3D12_DESCRIPTOR_HEAP_TYPE heapType,
|
||||
uint32_t requiredDescriptors,
|
||||
ComPtr<ID3D12DescriptorHeap>& heap,
|
||||
uint32_t& capacity) -> bool {
|
||||
if (requiredDescriptors == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (heap != nullptr && capacity >= requiredDescriptors) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const uint32_t newCapacity = std::max<uint32_t>(requiredDescriptors, capacity > 0 ? capacity * 2u : 32u);
|
||||
D3D12_DESCRIPTOR_HEAP_DESC heapDesc = {};
|
||||
heapDesc.Type = heapType;
|
||||
heapDesc.NumDescriptors = newCapacity;
|
||||
heapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
|
||||
heapDesc.NodeMask = 0;
|
||||
|
||||
ComPtr<ID3D12DescriptorHeap> newHeap;
|
||||
if (FAILED(m_device->CreateDescriptorHeap(&heapDesc, IID_PPV_ARGS(&newHeap)))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
heap = newHeap;
|
||||
capacity = newCapacity;
|
||||
return true;
|
||||
};
|
||||
|
||||
if (!ensureShaderVisibleHeap(
|
||||
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
|
||||
requiredCbvSrvUavDescriptors,
|
||||
m_shaderVisibleCbvSrvUavHeap,
|
||||
m_shaderVisibleCbvSrvUavHeapCapacity) ||
|
||||
!ensureShaderVisibleHeap(
|
||||
D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER,
|
||||
requiredSamplerDescriptors,
|
||||
m_shaderVisibleSamplerHeap,
|
||||
m_shaderVisibleSamplerHeapCapacity)) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<ID3D12DescriptorHeap*> descriptorHeaps;
|
||||
descriptorHeaps.reserve(2);
|
||||
if (requiredCbvSrvUavDescriptors > 0 && m_shaderVisibleCbvSrvUavHeap != nullptr) {
|
||||
descriptorHeaps.push_back(m_shaderVisibleCbvSrvUavHeap.Get());
|
||||
}
|
||||
if (requiredSamplerDescriptors > 0 && m_shaderVisibleSamplerHeap != nullptr) {
|
||||
descriptorHeaps.push_back(m_shaderVisibleSamplerHeap.Get());
|
||||
}
|
||||
if (!descriptorHeaps.empty()) {
|
||||
SetDescriptorHeaps(static_cast<uint32_t>(descriptorHeaps.size()), descriptorHeaps.data());
|
||||
}
|
||||
|
||||
uint32_t nextCbvSrvUavDescriptor = 0;
|
||||
uint32_t nextSamplerDescriptor = 0;
|
||||
|
||||
for (uint32_t i = 0; i < count; ++i) {
|
||||
if (descriptorSets[i] == nullptr) {
|
||||
continue;
|
||||
@@ -368,7 +566,24 @@ void D3D12CommandList::SetComputeDescriptorSets(
|
||||
|
||||
if (d3d12Set->HasBindingType(DescriptorType::SRV) && hasSrvTable) {
|
||||
const uint32_t srvBinding = d3d12Set->GetFirstBindingOfType(DescriptorType::SRV);
|
||||
const D3D12_GPU_DESCRIPTOR_HANDLE gpuHandle = d3d12Set->GetGPUHandleForBinding(srvBinding);
|
||||
const uint32_t srvDescriptorCount = CountDescriptorsOfType(d3d12Set, DescriptorType::SRV);
|
||||
const D3D12_CPU_DESCRIPTOR_HANDLE srcHandle = d3d12Set->GetCPUHandleForBinding(srvBinding);
|
||||
const D3D12_CPU_DESCRIPTOR_HANDLE dstHandle = OffsetCPUHandle(
|
||||
m_device,
|
||||
m_shaderVisibleCbvSrvUavHeap.Get(),
|
||||
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
|
||||
nextCbvSrvUavDescriptor);
|
||||
m_device->CopyDescriptorsSimple(
|
||||
srvDescriptorCount,
|
||||
dstHandle,
|
||||
srcHandle,
|
||||
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
|
||||
const D3D12_GPU_DESCRIPTOR_HANDLE gpuHandle = OffsetGPUHandle(
|
||||
m_device,
|
||||
m_shaderVisibleCbvSrvUavHeap.Get(),
|
||||
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
|
||||
nextCbvSrvUavDescriptor);
|
||||
nextCbvSrvUavDescriptor += srvDescriptorCount;
|
||||
if (gpuHandle.ptr != 0) {
|
||||
m_commandList->SetComputeRootDescriptorTable(
|
||||
d3d12Layout->UsesSetLayouts()
|
||||
@@ -380,7 +595,24 @@ void D3D12CommandList::SetComputeDescriptorSets(
|
||||
|
||||
if (d3d12Set->HasBindingType(DescriptorType::UAV) && hasUavTable) {
|
||||
const uint32_t uavBinding = d3d12Set->GetFirstBindingOfType(DescriptorType::UAV);
|
||||
const D3D12_GPU_DESCRIPTOR_HANDLE gpuHandle = d3d12Set->GetGPUHandleForBinding(uavBinding);
|
||||
const uint32_t uavDescriptorCount = CountDescriptorsOfType(d3d12Set, DescriptorType::UAV);
|
||||
const D3D12_CPU_DESCRIPTOR_HANDLE srcHandle = d3d12Set->GetCPUHandleForBinding(uavBinding);
|
||||
const D3D12_CPU_DESCRIPTOR_HANDLE dstHandle = OffsetCPUHandle(
|
||||
m_device,
|
||||
m_shaderVisibleCbvSrvUavHeap.Get(),
|
||||
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
|
||||
nextCbvSrvUavDescriptor);
|
||||
m_device->CopyDescriptorsSimple(
|
||||
uavDescriptorCount,
|
||||
dstHandle,
|
||||
srcHandle,
|
||||
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
|
||||
const D3D12_GPU_DESCRIPTOR_HANDLE gpuHandle = OffsetGPUHandle(
|
||||
m_device,
|
||||
m_shaderVisibleCbvSrvUavHeap.Get(),
|
||||
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
|
||||
nextCbvSrvUavDescriptor);
|
||||
nextCbvSrvUavDescriptor += uavDescriptorCount;
|
||||
if (gpuHandle.ptr != 0) {
|
||||
m_commandList->SetComputeRootDescriptorTable(
|
||||
d3d12Layout->UsesSetLayouts()
|
||||
@@ -395,7 +627,24 @@ void D3D12CommandList::SetComputeDescriptorSets(
|
||||
? d3d12Layout->HasSamplerTable(setIndex)
|
||||
: d3d12Layout->HasSamplerTable())) {
|
||||
const uint32_t samplerBinding = d3d12Set->GetFirstBindingOfType(DescriptorType::Sampler);
|
||||
const D3D12_GPU_DESCRIPTOR_HANDLE gpuHandle = d3d12Set->GetGPUHandleForBinding(samplerBinding);
|
||||
const uint32_t samplerDescriptorCount = CountDescriptorsOfType(d3d12Set, DescriptorType::Sampler);
|
||||
const D3D12_CPU_DESCRIPTOR_HANDLE srcHandle = d3d12Set->GetCPUHandleForBinding(samplerBinding);
|
||||
const D3D12_CPU_DESCRIPTOR_HANDLE dstHandle = OffsetCPUHandle(
|
||||
m_device,
|
||||
m_shaderVisibleSamplerHeap.Get(),
|
||||
D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER,
|
||||
nextSamplerDescriptor);
|
||||
m_device->CopyDescriptorsSimple(
|
||||
samplerDescriptorCount,
|
||||
dstHandle,
|
||||
srcHandle,
|
||||
D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER);
|
||||
const D3D12_GPU_DESCRIPTOR_HANDLE gpuHandle = OffsetGPUHandle(
|
||||
m_device,
|
||||
m_shaderVisibleSamplerHeap.Get(),
|
||||
D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER,
|
||||
nextSamplerDescriptor);
|
||||
nextSamplerDescriptor += samplerDescriptorCount;
|
||||
if (gpuHandle.ptr != 0) {
|
||||
m_commandList->SetComputeRootDescriptorTable(
|
||||
d3d12Layout->UsesSetLayouts()
|
||||
|
||||
@@ -175,6 +175,25 @@ D3D12_GPU_DESCRIPTOR_HANDLE D3D12DescriptorSet::GetGPUHandleForBinding(uint32_t
|
||||
return GetGPUHandle(descriptorIndex);
|
||||
}
|
||||
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE D3D12DescriptorSet::GetCPUHandleForBinding(uint32_t binding) const {
|
||||
const uint32_t descriptorIndex = GetDescriptorIndexForBinding(binding);
|
||||
if (descriptorIndex == UINT32_MAX || m_heap == nullptr) {
|
||||
return D3D12_CPU_DESCRIPTOR_HANDLE{0};
|
||||
}
|
||||
|
||||
const CPUDescriptorHandle handle = m_heap->GetCPUDescriptorHandle(m_offset + descriptorIndex);
|
||||
return D3D12_CPU_DESCRIPTOR_HANDLE{handle.ptr};
|
||||
}
|
||||
|
||||
uint32_t D3D12DescriptorSet::GetDescriptorCountForBinding(uint32_t binding) const {
|
||||
const BindingRecord* bindingRecord = FindBindingRecord(binding);
|
||||
if (bindingRecord == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return bindingRecord->layout.count > 0 ? bindingRecord->layout.count : 1u;
|
||||
}
|
||||
|
||||
void D3D12DescriptorSet::WriteConstant(uint32_t binding, const void* data, size_t size, size_t offset) {
|
||||
BindingRecord* bindingRecord = FindBindingRecord(binding);
|
||||
if (bindingRecord == nullptr ||
|
||||
|
||||
@@ -196,6 +196,51 @@ D3D12_RTV_DIMENSION ResolveRTVDimension(const ResourceViewDesc& desc, TextureTyp
|
||||
}
|
||||
}
|
||||
|
||||
bool IsDepthFormat(Format format) {
|
||||
return format == Format::D16_UNorm ||
|
||||
format == Format::D24_UNorm_S8_UInt ||
|
||||
format == Format::D32_Float;
|
||||
}
|
||||
|
||||
DXGI_FORMAT ResolveD3D12ResourceFormat(Format format) {
|
||||
switch (format) {
|
||||
case Format::D16_UNorm:
|
||||
return DXGI_FORMAT_R16_TYPELESS;
|
||||
case Format::D24_UNorm_S8_UInt:
|
||||
return DXGI_FORMAT_R24G8_TYPELESS;
|
||||
case Format::D32_Float:
|
||||
return DXGI_FORMAT_R32_TYPELESS;
|
||||
default:
|
||||
return ToD3D12(format);
|
||||
}
|
||||
}
|
||||
|
||||
DXGI_FORMAT ResolveD3D12DepthStencilViewFormat(Format format) {
|
||||
switch (format) {
|
||||
case Format::D16_UNorm:
|
||||
return DXGI_FORMAT_D16_UNORM;
|
||||
case Format::D24_UNorm_S8_UInt:
|
||||
return DXGI_FORMAT_D24_UNORM_S8_UINT;
|
||||
case Format::D32_Float:
|
||||
return DXGI_FORMAT_D32_FLOAT;
|
||||
default:
|
||||
return ToD3D12(format);
|
||||
}
|
||||
}
|
||||
|
||||
DXGI_FORMAT ResolveD3D12ShaderResourceViewFormat(Format format) {
|
||||
switch (format) {
|
||||
case Format::D16_UNorm:
|
||||
return DXGI_FORMAT_R16_UNORM;
|
||||
case Format::D24_UNorm_S8_UInt:
|
||||
return DXGI_FORMAT_R24_UNORM_X8_TYPELESS;
|
||||
case Format::D32_Float:
|
||||
return DXGI_FORMAT_R32_FLOAT;
|
||||
default:
|
||||
return ToD3D12(format);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
D3D12Device::D3D12Device()
|
||||
@@ -595,16 +640,14 @@ RHITexture* D3D12Device::CreateTexture(const TextureDesc& desc) {
|
||||
|
||||
const TextureType textureType = ResolveTextureType(desc.textureType);
|
||||
const Format format = static_cast<Format>(desc.format);
|
||||
const bool isDepthFormat = format == Format::D24_UNorm_S8_UInt ||
|
||||
format == Format::D32_Float ||
|
||||
format == Format::D16_UNorm;
|
||||
const bool isDepthFormat = IsDepthFormat(format);
|
||||
|
||||
d3d12Desc.Dimension = ToD3D12(textureType);
|
||||
d3d12Desc.Width = desc.width;
|
||||
d3d12Desc.Height = desc.height;
|
||||
d3d12Desc.DepthOrArraySize = ResolveDepthOrArraySize(desc, textureType);
|
||||
d3d12Desc.MipLevels = desc.mipLevels > 0 ? desc.mipLevels : 1;
|
||||
d3d12Desc.Format = ToD3D12(format);
|
||||
d3d12Desc.Format = ResolveD3D12ResourceFormat(format);
|
||||
d3d12Desc.SampleDesc.Count = desc.sampleCount > 0 ? desc.sampleCount : 1;
|
||||
d3d12Desc.SampleDesc.Quality = desc.sampleQuality;
|
||||
d3d12Desc.Flags = static_cast<D3D12_RESOURCE_FLAGS>(desc.flags);
|
||||
@@ -1009,7 +1052,8 @@ RHIResourceView* D3D12Device::CreateDepthStencilView(RHITexture* texture, const
|
||||
ID3D12Resource* resource = d3d12Texture->GetResource();
|
||||
|
||||
D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = {};
|
||||
dsvDesc.Format = ToD3D12(static_cast<Format>(desc.format));
|
||||
const Format format = desc.format != 0 ? static_cast<Format>(desc.format) : texture->GetFormat();
|
||||
dsvDesc.Format = ResolveD3D12DepthStencilViewFormat(format);
|
||||
dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D;
|
||||
|
||||
auto heap = std::make_unique<D3D12DescriptorHeap>();
|
||||
@@ -1029,10 +1073,11 @@ RHIResourceView* D3D12Device::CreateShaderResourceView(RHITexture* texture, cons
|
||||
ID3D12Resource* resource = d3d12Texture->GetResource();
|
||||
|
||||
D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
|
||||
srvDesc.Format = ToD3D12(static_cast<Format>(desc.format));
|
||||
const Format format = desc.format != 0 ? static_cast<Format>(desc.format) : texture->GetFormat();
|
||||
srvDesc.Format = ResolveD3D12ShaderResourceViewFormat(format);
|
||||
srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
|
||||
srvDesc.Texture2D.MipLevels = desc.mipLevel > 0 ? desc.mipLevel : 1;
|
||||
srvDesc.Texture2D.MostDetailedMip = 0;
|
||||
srvDesc.Texture2D.MostDetailedMip = desc.mipLevel;
|
||||
srvDesc.Texture2D.MipLevels = 1;
|
||||
srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
|
||||
|
||||
auto heap = std::make_unique<D3D12DescriptorHeap>();
|
||||
|
||||
@@ -185,6 +185,21 @@ bool D3D12Texture::InitializeFromData(ID3D12Device* device, ID3D12GraphicsComman
|
||||
}
|
||||
|
||||
bool D3D12Texture::InitializeDepthStencil(ID3D12Device* device, uint32_t width, uint32_t height, DXGI_FORMAT format) {
|
||||
DXGI_FORMAT resourceFormat = format;
|
||||
switch (format) {
|
||||
case DXGI_FORMAT_D16_UNORM:
|
||||
resourceFormat = DXGI_FORMAT_R16_TYPELESS;
|
||||
break;
|
||||
case DXGI_FORMAT_D24_UNORM_S8_UINT:
|
||||
resourceFormat = DXGI_FORMAT_R24G8_TYPELESS;
|
||||
break;
|
||||
case DXGI_FORMAT_D32_FLOAT:
|
||||
resourceFormat = DXGI_FORMAT_R32_TYPELESS;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
D3D12_RESOURCE_DESC desc = {};
|
||||
desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
|
||||
desc.Alignment = 0;
|
||||
@@ -192,7 +207,7 @@ bool D3D12Texture::InitializeDepthStencil(ID3D12Device* device, uint32_t width,
|
||||
desc.Height = height;
|
||||
desc.DepthOrArraySize = 1;
|
||||
desc.MipLevels = 1;
|
||||
desc.Format = format;
|
||||
desc.Format = resourceFormat;
|
||||
desc.SampleDesc.Count = 1;
|
||||
desc.SampleDesc.Quality = 0;
|
||||
desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
|
||||
|
||||
@@ -19,6 +19,7 @@ namespace {
|
||||
struct OwnedShadowSurfaceResources {
|
||||
RHI::RHITexture* depthTexture = nullptr;
|
||||
RHI::RHIResourceView* depthView = nullptr;
|
||||
RHI::RHIResourceView* shaderView = nullptr;
|
||||
RenderSurface surface = {};
|
||||
|
||||
OwnedShadowSurfaceResources() = default;
|
||||
@@ -30,6 +31,12 @@ struct OwnedShadowSurfaceResources {
|
||||
}
|
||||
|
||||
void Reset() {
|
||||
if (shaderView != nullptr) {
|
||||
shaderView->Shutdown();
|
||||
delete shaderView;
|
||||
shaderView = nullptr;
|
||||
}
|
||||
|
||||
if (depthView != nullptr) {
|
||||
depthView->Shutdown();
|
||||
delete depthView;
|
||||
@@ -181,14 +188,48 @@ bool CreateDirectionalShadowSurface(
|
||||
return false;
|
||||
}
|
||||
|
||||
RHI::ResourceViewDesc shaderViewDesc = {};
|
||||
shaderViewDesc.format = depthDesc.format;
|
||||
shaderViewDesc.dimension = RHI::ResourceViewDimension::Texture2D;
|
||||
shaderViewDesc.mipLevel = 0;
|
||||
RHI::RHIResourceView* shaderView =
|
||||
context.device->CreateShaderResourceView(depthTexture, shaderViewDesc);
|
||||
if (shaderView == nullptr) {
|
||||
depthView->Shutdown();
|
||||
delete depthView;
|
||||
depthTexture->Shutdown();
|
||||
delete depthTexture;
|
||||
return false;
|
||||
}
|
||||
|
||||
outResources.Reset();
|
||||
outResources.depthTexture = depthTexture;
|
||||
outResources.depthView = depthView;
|
||||
outResources.shaderView = shaderView;
|
||||
outResources.surface = RenderSurface(plan.mapWidth, plan.mapHeight);
|
||||
outResources.surface.SetDepthAttachment(depthView);
|
||||
return true;
|
||||
}
|
||||
|
||||
RenderDirectionalShadowData BuildDirectionalShadowData(
|
||||
const DirectionalShadowRenderPlan& plan,
|
||||
RHI::RHIResourceView* shadowMapView) {
|
||||
RenderDirectionalShadowData shadowData = {};
|
||||
if (!plan.IsValid() || shadowMapView == nullptr) {
|
||||
return shadowData;
|
||||
}
|
||||
|
||||
shadowData.enabled = true;
|
||||
shadowData.viewProjection = plan.cameraData.viewProjection;
|
||||
shadowData.shadowMap = shadowMapView;
|
||||
shadowData.shadowParams = Math::Vector4(
|
||||
0.0015f,
|
||||
1.0f / static_cast<float>(plan.mapWidth),
|
||||
1.0f / static_cast<float>(plan.mapHeight),
|
||||
0.85f);
|
||||
return shadowData;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
CameraRenderer::CameraRenderer()
|
||||
@@ -351,6 +392,12 @@ bool CameraRenderer::Render(
|
||||
return false;
|
||||
}
|
||||
|
||||
if (request.directionalShadow.IsValid()) {
|
||||
RHI::RHIResourceView* shadowMapView = ownedShadowSurface.shaderView;
|
||||
sceneData.lighting.mainDirectionalShadow =
|
||||
BuildDirectionalShadowData(request.directionalShadow, shadowMapView);
|
||||
}
|
||||
|
||||
sceneData.cameraData.clearFlags = request.clearFlags;
|
||||
if (request.hasClearColorOverride) {
|
||||
sceneData.cameraData.clearColor = request.clearColorOverride;
|
||||
|
||||
@@ -283,6 +283,13 @@ bool BuiltinForwardPipeline::ExecuteForwardOpaquePass(const RenderPassContext& p
|
||||
|
||||
commandList->SetPrimitiveTopology(RHI::PrimitiveTopology::TriangleList);
|
||||
|
||||
if (sceneData.lighting.HasMainDirectionalShadow()) {
|
||||
commandList->TransitionBarrier(
|
||||
sceneData.lighting.mainDirectionalShadow.shadowMap,
|
||||
RHI::ResourceStates::DepthWrite,
|
||||
RHI::ResourceStates::PixelShaderResource);
|
||||
}
|
||||
|
||||
RHI::RHIPipelineState* currentPipelineState = nullptr;
|
||||
for (const VisibleRenderItem& visibleItem : sceneData.visibleItems) {
|
||||
const Resources::Material* material = ResolveMaterial(visibleItem);
|
||||
@@ -303,6 +310,13 @@ bool BuiltinForwardPipeline::ExecuteForwardOpaquePass(const RenderPassContext& p
|
||||
DrawVisibleItem(context, sceneData, visibleItem);
|
||||
}
|
||||
|
||||
if (sceneData.lighting.HasMainDirectionalShadow()) {
|
||||
commandList->TransitionBarrier(
|
||||
sceneData.lighting.mainDirectionalShadow.shadowMap,
|
||||
RHI::ResourceStates::PixelShaderResource,
|
||||
RHI::ResourceStates::DepthWrite);
|
||||
}
|
||||
|
||||
if (surface.IsAutoTransitionEnabled()) {
|
||||
commandList->EndRenderPass();
|
||||
for (RHI::RHIResourceView* renderTarget : renderTargets) {
|
||||
@@ -370,6 +384,13 @@ bool BuiltinForwardPipeline::CreatePipelineResources(const RenderContext& contex
|
||||
return false;
|
||||
}
|
||||
|
||||
RHI::SamplerDesc shadowSamplerDesc = samplerDesc;
|
||||
shadowSamplerDesc.filter = static_cast<uint32_t>(RHI::FilterMode::Point);
|
||||
m_shadowSampler = context.device->CreateSampler(shadowSamplerDesc);
|
||||
if (m_shadowSampler == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const unsigned char whitePixel[4] = { 255, 255, 255, 255 };
|
||||
RHI::TextureDesc textureDesc = {};
|
||||
textureDesc.width = 1;
|
||||
@@ -438,6 +459,12 @@ void BuiltinForwardPipeline::DestroyPipelineResources() {
|
||||
m_sampler = nullptr;
|
||||
}
|
||||
|
||||
if (m_shadowSampler != nullptr) {
|
||||
m_shadowSampler->Shutdown();
|
||||
delete m_shadowSampler;
|
||||
m_shadowSampler = nullptr;
|
||||
}
|
||||
|
||||
m_device = nullptr;
|
||||
m_initialized = false;
|
||||
m_builtinForwardShader.Reset();
|
||||
@@ -527,8 +554,11 @@ BuiltinForwardPipeline::PassResourceLayout* BuiltinForwardPipeline::GetOrCreateP
|
||||
|
||||
passLayout.perObject = bindingPlan.perObject;
|
||||
passLayout.material = bindingPlan.material;
|
||||
passLayout.shadowReceiver = bindingPlan.shadowReceiver;
|
||||
passLayout.baseColorTexture = bindingPlan.baseColorTexture;
|
||||
passLayout.linearClampSampler = bindingPlan.linearClampSampler;
|
||||
passLayout.shadowMapTexture = bindingPlan.shadowMapTexture;
|
||||
passLayout.shadowMapSampler = bindingPlan.shadowMapSampler;
|
||||
|
||||
if (!passLayout.perObject.IsValid()) {
|
||||
return failLayout("BuiltinForwardPipeline requires a PerObject resource binding");
|
||||
@@ -672,14 +702,33 @@ RHI::RHIDescriptorSet* BuiltinForwardPipeline::GetOrCreateStaticDescriptorSet(
|
||||
}
|
||||
|
||||
if (passLayout.setLayouts[setIndex].usesSampler) {
|
||||
if (m_sampler == nullptr ||
|
||||
!passLayout.linearClampSampler.IsValid() ||
|
||||
passLayout.linearClampSampler.set != setIndex) {
|
||||
RHI::RHISampler* sampler = nullptr;
|
||||
Core::uint32 binding = 0;
|
||||
|
||||
if (passLayout.setLayouts[setIndex].usesLinearClampSampler) {
|
||||
sampler = m_sampler;
|
||||
if (!passLayout.linearClampSampler.IsValid() ||
|
||||
passLayout.linearClampSampler.set != setIndex) {
|
||||
DestroyOwnedDescriptorSet(descriptorSet);
|
||||
return nullptr;
|
||||
}
|
||||
binding = passLayout.linearClampSampler.binding;
|
||||
} else if (passLayout.setLayouts[setIndex].usesShadowMapSampler) {
|
||||
sampler = m_shadowSampler;
|
||||
if (!passLayout.shadowMapSampler.IsValid() ||
|
||||
passLayout.shadowMapSampler.set != setIndex) {
|
||||
DestroyOwnedDescriptorSet(descriptorSet);
|
||||
return nullptr;
|
||||
}
|
||||
binding = passLayout.shadowMapSampler.binding;
|
||||
}
|
||||
|
||||
if (sampler == nullptr) {
|
||||
DestroyOwnedDescriptorSet(descriptorSet);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
descriptorSet.set->UpdateSampler(passLayout.linearClampSampler.binding, m_sampler);
|
||||
descriptorSet.set->UpdateSampler(binding, sampler);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -694,7 +743,9 @@ BuiltinForwardPipeline::CachedDescriptorSet* BuiltinForwardPipeline::GetOrCreate
|
||||
Core::uint64 objectId,
|
||||
const Resources::Material* material,
|
||||
const MaterialConstantPayloadView& materialConstants,
|
||||
RHI::RHIResourceView* textureView) {
|
||||
const ShadowReceiverConstants& shadowReceiverConstants,
|
||||
RHI::RHIResourceView* baseColorTextureView,
|
||||
RHI::RHIResourceView* shadowMapTextureView) {
|
||||
DynamicDescriptorSetKey key = {};
|
||||
key.passLayout = passLayoutKey;
|
||||
key.setIndex = setIndex;
|
||||
@@ -709,35 +760,61 @@ BuiltinForwardPipeline::CachedDescriptorSet* BuiltinForwardPipeline::GetOrCreate
|
||||
}
|
||||
|
||||
const Core::uint64 materialVersion = material != nullptr ? material->GetChangeVersion() : 0;
|
||||
if ((setLayout.usesMaterial || setLayout.usesTexture) &&
|
||||
(cachedDescriptorSet.materialVersion != materialVersion ||
|
||||
cachedDescriptorSet.textureView != textureView)) {
|
||||
if (setLayout.usesMaterial) {
|
||||
if (!passLayout.material.IsValid() || passLayout.material.set != setIndex) {
|
||||
return nullptr;
|
||||
}
|
||||
if (!materialConstants.IsValid()) {
|
||||
return nullptr;
|
||||
}
|
||||
if (setLayout.usesMaterial) {
|
||||
if (!passLayout.material.IsValid() || passLayout.material.set != setIndex) {
|
||||
return nullptr;
|
||||
}
|
||||
if (!materialConstants.IsValid()) {
|
||||
return nullptr;
|
||||
}
|
||||
if (cachedDescriptorSet.materialVersion != materialVersion) {
|
||||
cachedDescriptorSet.descriptorSet.set->WriteConstant(
|
||||
passLayout.material.binding,
|
||||
materialConstants.data,
|
||||
materialConstants.size);
|
||||
}
|
||||
|
||||
if (setLayout.usesTexture) {
|
||||
if (textureView == nullptr ||
|
||||
!passLayout.baseColorTexture.IsValid() ||
|
||||
passLayout.baseColorTexture.set != setIndex) {
|
||||
return nullptr;
|
||||
}
|
||||
cachedDescriptorSet.descriptorSet.set->Update(passLayout.baseColorTexture.binding, textureView);
|
||||
}
|
||||
|
||||
cachedDescriptorSet.materialVersion = materialVersion;
|
||||
cachedDescriptorSet.textureView = textureView;
|
||||
}
|
||||
|
||||
if (setLayout.usesShadowReceiver) {
|
||||
if (!passLayout.shadowReceiver.IsValid() || passLayout.shadowReceiver.set != setIndex) {
|
||||
return nullptr;
|
||||
}
|
||||
cachedDescriptorSet.descriptorSet.set->WriteConstant(
|
||||
passLayout.shadowReceiver.binding,
|
||||
&shadowReceiverConstants,
|
||||
sizeof(shadowReceiverConstants));
|
||||
}
|
||||
|
||||
if (setLayout.usesBaseColorTexture) {
|
||||
if (baseColorTextureView == nullptr ||
|
||||
!passLayout.baseColorTexture.IsValid() ||
|
||||
passLayout.baseColorTexture.set != setIndex) {
|
||||
return nullptr;
|
||||
}
|
||||
if (cachedDescriptorSet.baseColorTextureView != baseColorTextureView) {
|
||||
cachedDescriptorSet.descriptorSet.set->Update(
|
||||
passLayout.baseColorTexture.binding,
|
||||
baseColorTextureView);
|
||||
}
|
||||
}
|
||||
|
||||
if (setLayout.usesShadowMapTexture) {
|
||||
if (shadowMapTextureView == nullptr ||
|
||||
!passLayout.shadowMapTexture.IsValid() ||
|
||||
passLayout.shadowMapTexture.set != setIndex) {
|
||||
return nullptr;
|
||||
}
|
||||
if (cachedDescriptorSet.shadowMapTextureView != shadowMapTextureView) {
|
||||
cachedDescriptorSet.descriptorSet.set->Update(
|
||||
passLayout.shadowMapTexture.binding,
|
||||
shadowMapTextureView);
|
||||
}
|
||||
}
|
||||
|
||||
cachedDescriptorSet.materialVersion = materialVersion;
|
||||
cachedDescriptorSet.baseColorTextureView = baseColorTextureView;
|
||||
cachedDescriptorSet.shadowMapTextureView = shadowMapTextureView;
|
||||
|
||||
return &cachedDescriptorSet;
|
||||
}
|
||||
|
||||
@@ -772,8 +849,11 @@ void BuiltinForwardPipeline::DestroyPassResourceLayout(PassResourceLayout& passL
|
||||
passLayout.descriptorSetCount = 0;
|
||||
passLayout.perObject = {};
|
||||
passLayout.material = {};
|
||||
passLayout.shadowReceiver = {};
|
||||
passLayout.baseColorTexture = {};
|
||||
passLayout.linearClampSampler = {};
|
||||
passLayout.shadowMapTexture = {};
|
||||
passLayout.shadowMapSampler = {};
|
||||
}
|
||||
|
||||
const Resources::Texture* BuiltinForwardPipeline::ResolveTexture(const Resources::Material* material) const {
|
||||
@@ -833,6 +913,17 @@ bool BuiltinForwardPipeline::DrawVisibleItem(
|
||||
1.0f)
|
||||
: Math::Vector4::Zero()
|
||||
};
|
||||
const ShadowReceiverConstants shadowReceiverConstants = {
|
||||
sceneData.lighting.HasMainDirectionalShadow()
|
||||
? sceneData.lighting.mainDirectionalShadow.viewProjection
|
||||
: Math::Matrix4x4::Identity(),
|
||||
sceneData.lighting.HasMainDirectionalShadow()
|
||||
? sceneData.lighting.mainDirectionalShadow.shadowParams
|
||||
: Math::Vector4::Zero(),
|
||||
sceneData.lighting.HasMainDirectionalShadow()
|
||||
? Math::Vector4(1.0f, 0.0f, 0.0f, 0.0f)
|
||||
: Math::Vector4::Zero()
|
||||
};
|
||||
|
||||
const Resources::Material* material = ResolveMaterial(visibleItem);
|
||||
const ResolvedShaderPass resolvedShaderPass = ResolveSurfaceShaderPass(material);
|
||||
@@ -849,8 +940,15 @@ bool BuiltinForwardPipeline::DrawVisibleItem(
|
||||
return false;
|
||||
}
|
||||
|
||||
RHI::RHIResourceView* textureView = ResolveTextureView(visibleItem);
|
||||
if (passLayout->baseColorTexture.IsValid() && textureView == nullptr) {
|
||||
RHI::RHIResourceView* baseColorTextureView = ResolveTextureView(visibleItem);
|
||||
if (passLayout->baseColorTexture.IsValid() && baseColorTextureView == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RHI::RHIResourceView* shadowMapTextureView = sceneData.lighting.HasMainDirectionalShadow()
|
||||
? sceneData.lighting.mainDirectionalShadow.shadowMap
|
||||
: m_fallbackTextureView;
|
||||
if (passLayout->shadowMapTexture.IsValid() && shadowMapTextureView == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -887,13 +985,16 @@ bool BuiltinForwardPipeline::DrawVisibleItem(
|
||||
const BuiltinPassSetLayoutMetadata& setLayout = passLayout->setLayouts[setIndex];
|
||||
RHI::RHIDescriptorSet* descriptorSet = nullptr;
|
||||
|
||||
if (setLayout.usesPerObject || setLayout.usesMaterial || setLayout.usesTexture) {
|
||||
if (setLayout.usesPerObject ||
|
||||
setLayout.usesMaterial ||
|
||||
setLayout.usesShadowReceiver ||
|
||||
setLayout.usesTexture) {
|
||||
const Core::uint64 objectId =
|
||||
(setLayout.usesPerObject && visibleItem.gameObject != nullptr)
|
||||
? visibleItem.gameObject->GetID()
|
||||
: 0;
|
||||
const Resources::Material* materialKey =
|
||||
(setLayout.usesMaterial || setLayout.usesTexture) ? material : nullptr;
|
||||
(setLayout.usesMaterial || setLayout.usesBaseColorTexture) ? material : nullptr;
|
||||
|
||||
CachedDescriptorSet* cachedDescriptorSet = GetOrCreateDynamicDescriptorSet(
|
||||
passLayoutKey,
|
||||
@@ -903,7 +1004,9 @@ bool BuiltinForwardPipeline::DrawVisibleItem(
|
||||
objectId,
|
||||
materialKey,
|
||||
materialConstants,
|
||||
textureView);
|
||||
shadowReceiverConstants,
|
||||
baseColorTextureView,
|
||||
shadowMapTextureView);
|
||||
if (cachedDescriptorSet == nullptr || cachedDescriptorSet->descriptorSet.set == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user