Add forward shadow receiving support

This commit is contained in:
2026-04-04 23:01:34 +08:00
parent 353d129613
commit 96a44da2cb
22 changed files with 889 additions and 89 deletions

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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; }

View File

@@ -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;

View File

@@ -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:

View File

@@ -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 {

View File

@@ -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()

View File

@@ -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 ||

View File

@@ -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>();

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;
}