Add forward shadow receiving support
This commit is contained in:
@@ -154,6 +154,38 @@ TEST_P(RHITestFixture, Device_CreateShaderResourceView_FromInitialDataTexture) {
|
||||
delete texture;
|
||||
}
|
||||
|
||||
TEST_P(RHITestFixture, Device_CreateShaderResourceView_FromDepthTexture) {
|
||||
TextureDesc texDesc = {};
|
||||
texDesc.width = 256;
|
||||
texDesc.height = 256;
|
||||
texDesc.depth = 1;
|
||||
texDesc.mipLevels = 1;
|
||||
texDesc.arraySize = 1;
|
||||
texDesc.format = static_cast<uint32_t>(Format::D24_UNorm_S8_UInt);
|
||||
texDesc.textureType = static_cast<uint32_t>(TextureType::Texture2D);
|
||||
texDesc.sampleCount = 1;
|
||||
texDesc.sampleQuality = 0;
|
||||
texDesc.flags = 0;
|
||||
|
||||
RHITexture* texture = GetDevice()->CreateTexture(texDesc);
|
||||
ASSERT_NE(texture, nullptr);
|
||||
|
||||
ResourceViewDesc viewDesc = {};
|
||||
viewDesc.format = static_cast<uint32_t>(Format::D24_UNorm_S8_UInt);
|
||||
viewDesc.dimension = ResourceViewDimension::Texture2D;
|
||||
viewDesc.mipLevel = 0;
|
||||
|
||||
RHIResourceView* srv = GetDevice()->CreateShaderResourceView(texture, viewDesc);
|
||||
ASSERT_NE(srv, nullptr);
|
||||
EXPECT_TRUE(srv->IsValid());
|
||||
EXPECT_EQ(srv->GetViewType(), ResourceViewType::ShaderResource);
|
||||
|
||||
srv->Shutdown();
|
||||
delete srv;
|
||||
texture->Shutdown();
|
||||
delete texture;
|
||||
}
|
||||
|
||||
TEST_P(RHITestFixture, Device_CreateVertexBufferView) {
|
||||
BufferDesc bufferDesc = {};
|
||||
bufferDesc.size = 256;
|
||||
|
||||
@@ -55,7 +55,7 @@ TEST(BuiltinForwardPipeline_Test, BuiltinForwardShaderDeclaresExplicitForwardRes
|
||||
|
||||
const ShaderPass* pass = shader->FindPass("ForwardLit");
|
||||
ASSERT_NE(pass, nullptr);
|
||||
ASSERT_EQ(pass->resources.Size(), 4u);
|
||||
ASSERT_EQ(pass->resources.Size(), 7u);
|
||||
|
||||
EXPECT_EQ(pass->resources[0].semantic, "PerObject");
|
||||
EXPECT_EQ(pass->resources[0].type, ShaderResourceType::ConstantBuffer);
|
||||
@@ -77,6 +77,21 @@ TEST(BuiltinForwardPipeline_Test, BuiltinForwardShaderDeclaresExplicitForwardRes
|
||||
EXPECT_EQ(pass->resources[3].set, 4u);
|
||||
EXPECT_EQ(pass->resources[3].binding, 0u);
|
||||
|
||||
EXPECT_EQ(pass->resources[4].semantic, "ShadowReceiver");
|
||||
EXPECT_EQ(pass->resources[4].type, ShaderResourceType::ConstantBuffer);
|
||||
EXPECT_EQ(pass->resources[4].set, 5u);
|
||||
EXPECT_EQ(pass->resources[4].binding, 0u);
|
||||
|
||||
EXPECT_EQ(pass->resources[5].semantic, "ShadowMapTexture");
|
||||
EXPECT_EQ(pass->resources[5].type, ShaderResourceType::Texture2D);
|
||||
EXPECT_EQ(pass->resources[5].set, 6u);
|
||||
EXPECT_EQ(pass->resources[5].binding, 0u);
|
||||
|
||||
EXPECT_EQ(pass->resources[6].semantic, "ShadowMapSampler");
|
||||
EXPECT_EQ(pass->resources[6].type, ShaderResourceType::Sampler);
|
||||
EXPECT_EQ(pass->resources[6].set, 7u);
|
||||
EXPECT_EQ(pass->resources[6].binding, 0u);
|
||||
|
||||
delete shader;
|
||||
}
|
||||
|
||||
@@ -133,10 +148,13 @@ TEST(BuiltinForwardPipeline_Test, BuildsBuiltinPassResourceBindingPlanFromExplic
|
||||
EXPECT_TRUE(TryBuildBuiltinPassResourceBindingPlan(pass->resources, plan, &error)) << error.CStr();
|
||||
EXPECT_TRUE(plan.perObject.IsValid());
|
||||
EXPECT_TRUE(plan.material.IsValid());
|
||||
EXPECT_TRUE(plan.shadowReceiver.IsValid());
|
||||
EXPECT_TRUE(plan.baseColorTexture.IsValid());
|
||||
EXPECT_TRUE(plan.linearClampSampler.IsValid());
|
||||
EXPECT_TRUE(plan.shadowMapTexture.IsValid());
|
||||
EXPECT_TRUE(plan.shadowMapSampler.IsValid());
|
||||
EXPECT_EQ(plan.firstDescriptorSet, 1u);
|
||||
EXPECT_EQ(plan.descriptorSetCount, 4u);
|
||||
EXPECT_EQ(plan.descriptorSetCount, 7u);
|
||||
EXPECT_TRUE(plan.usesConstantBuffers);
|
||||
EXPECT_TRUE(plan.usesTextures);
|
||||
EXPECT_TRUE(plan.usesSamplers);
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <XCEngine/RHI/RHIDevice.h>
|
||||
#include <XCEngine/RHI/RHIResourceView.h>
|
||||
#include <XCEngine/RHI/RHITexture.h>
|
||||
#include <XCEngine/Core/Math/Vector4.h>
|
||||
#include <XCEngine/Rendering/CameraRenderer.h>
|
||||
#include <XCEngine/Rendering/ObjectIdPass.h>
|
||||
#include <XCEngine/Rendering/RenderPipelineAsset.h>
|
||||
@@ -39,6 +40,10 @@ struct MockPipelineState {
|
||||
size_t lastVisibleItemCount = 0;
|
||||
RenderClearFlags lastClearFlags = RenderClearFlags::All;
|
||||
XCEngine::Math::Color lastClearColor = XCEngine::Math::Color::Black();
|
||||
bool lastHasMainDirectionalShadow = false;
|
||||
XCEngine::RHI::RHIResourceView* lastShadowMap = nullptr;
|
||||
XCEngine::Math::Matrix4x4 lastShadowViewProjection = XCEngine::Math::Matrix4x4::Identity();
|
||||
XCEngine::Math::Vector4 lastShadowParams = XCEngine::Math::Vector4::Zero();
|
||||
std::vector<CameraComponent*> renderedCameras;
|
||||
std::vector<RenderClearFlags> renderedClearFlags;
|
||||
std::vector<XCEngine::Math::Color> renderedClearColors;
|
||||
@@ -52,10 +57,14 @@ struct MockShadowAllocationState {
|
||||
int createDepthViewCalls = 0;
|
||||
int shutdownDepthViewCalls = 0;
|
||||
int destroyDepthViewCalls = 0;
|
||||
int createShaderViewCalls = 0;
|
||||
int shutdownShaderViewCalls = 0;
|
||||
int destroyShaderViewCalls = 0;
|
||||
uint32_t lastTextureWidth = 0;
|
||||
uint32_t lastTextureHeight = 0;
|
||||
XCEngine::RHI::Format lastTextureFormat = XCEngine::RHI::Format::Unknown;
|
||||
XCEngine::RHI::Format lastDepthViewFormat = XCEngine::RHI::Format::Unknown;
|
||||
XCEngine::RHI::Format lastShaderViewFormat = XCEngine::RHI::Format::Unknown;
|
||||
};
|
||||
|
||||
class MockShadowTexture final : public XCEngine::RHI::RHITexture {
|
||||
@@ -114,11 +123,19 @@ public:
|
||||
}
|
||||
|
||||
~MockShadowView() override {
|
||||
++m_state->destroyDepthViewCalls;
|
||||
if (m_viewType == XCEngine::RHI::ResourceViewType::ShaderResource) {
|
||||
++m_state->destroyShaderViewCalls;
|
||||
} else {
|
||||
++m_state->destroyDepthViewCalls;
|
||||
}
|
||||
}
|
||||
|
||||
void Shutdown() override {
|
||||
++m_state->shutdownDepthViewCalls;
|
||||
if (m_viewType == XCEngine::RHI::ResourceViewType::ShaderResource) {
|
||||
++m_state->shutdownShaderViewCalls;
|
||||
} else {
|
||||
++m_state->shutdownDepthViewCalls;
|
||||
}
|
||||
}
|
||||
|
||||
void* GetNativeHandle() override { return nullptr; }
|
||||
@@ -217,7 +234,15 @@ public:
|
||||
|
||||
XCEngine::RHI::RHIResourceView* CreateShaderResourceView(
|
||||
XCEngine::RHI::RHITexture*,
|
||||
const XCEngine::RHI::ResourceViewDesc&) override { return nullptr; }
|
||||
const XCEngine::RHI::ResourceViewDesc& desc) override {
|
||||
++m_state->createShaderViewCalls;
|
||||
m_state->lastShaderViewFormat = static_cast<XCEngine::RHI::Format>(desc.format);
|
||||
return new MockShadowView(
|
||||
m_state,
|
||||
XCEngine::RHI::ResourceViewType::ShaderResource,
|
||||
static_cast<XCEngine::RHI::Format>(desc.format),
|
||||
desc.dimension);
|
||||
}
|
||||
XCEngine::RHI::RHIResourceView* CreateUnorderedAccessView(
|
||||
XCEngine::RHI::RHITexture*,
|
||||
const XCEngine::RHI::ResourceViewDesc&) override { return nullptr; }
|
||||
@@ -271,6 +296,10 @@ public:
|
||||
m_state->lastVisibleItemCount = sceneData.visibleItems.size();
|
||||
m_state->lastClearFlags = sceneData.cameraData.clearFlags;
|
||||
m_state->lastClearColor = sceneData.cameraData.clearColor;
|
||||
m_state->lastHasMainDirectionalShadow = sceneData.lighting.HasMainDirectionalShadow();
|
||||
m_state->lastShadowMap = sceneData.lighting.mainDirectionalShadow.shadowMap;
|
||||
m_state->lastShadowViewProjection = sceneData.lighting.mainDirectionalShadow.viewProjection;
|
||||
m_state->lastShadowParams = sceneData.lighting.mainDirectionalShadow.shadowParams;
|
||||
m_state->renderedCameras.push_back(sceneData.camera);
|
||||
m_state->renderedClearFlags.push_back(sceneData.cameraData.clearFlags);
|
||||
m_state->renderedClearColors.push_back(sceneData.cameraData.clearColor);
|
||||
@@ -677,6 +706,8 @@ TEST(CameraRenderer_Test, AutoAllocatesDirectionalShadowSurfaceFromShadowPlan) {
|
||||
request.directionalShadow.cameraData.viewportHeight = 128;
|
||||
request.directionalShadow.cameraData.clearFlags = RenderClearFlags::Depth;
|
||||
request.directionalShadow.cameraData.worldPosition = XCEngine::Math::Vector3(3.0f, 4.0f, 5.0f);
|
||||
request.directionalShadow.cameraData.viewProjection =
|
||||
XCEngine::Math::Matrix4x4::Translation(XCEngine::Math::Vector3(11.0f, 12.0f, 13.0f));
|
||||
|
||||
ASSERT_TRUE(renderer.Render(request));
|
||||
EXPECT_EQ(
|
||||
@@ -693,14 +724,27 @@ TEST(CameraRenderer_Test, AutoAllocatesDirectionalShadowSurfaceFromShadowPlan) {
|
||||
EXPECT_EQ(shadowPassRaw->lastWorldPosition, XCEngine::Math::Vector3(3.0f, 4.0f, 5.0f));
|
||||
EXPECT_EQ(allocationState->createTextureCalls, 1);
|
||||
EXPECT_EQ(allocationState->createDepthViewCalls, 1);
|
||||
EXPECT_EQ(allocationState->createShaderViewCalls, 1);
|
||||
EXPECT_EQ(allocationState->lastTextureWidth, 256u);
|
||||
EXPECT_EQ(allocationState->lastTextureHeight, 128u);
|
||||
EXPECT_EQ(allocationState->lastTextureFormat, XCEngine::RHI::Format::D24_UNorm_S8_UInt);
|
||||
EXPECT_EQ(allocationState->lastDepthViewFormat, XCEngine::RHI::Format::D24_UNorm_S8_UInt);
|
||||
EXPECT_EQ(allocationState->lastShaderViewFormat, XCEngine::RHI::Format::D24_UNorm_S8_UInt);
|
||||
EXPECT_EQ(allocationState->shutdownDepthViewCalls, 1);
|
||||
EXPECT_EQ(allocationState->shutdownShaderViewCalls, 1);
|
||||
EXPECT_EQ(allocationState->shutdownTextureCalls, 1);
|
||||
EXPECT_EQ(allocationState->destroyDepthViewCalls, 1);
|
||||
EXPECT_EQ(allocationState->destroyShaderViewCalls, 1);
|
||||
EXPECT_EQ(allocationState->destroyTextureCalls, 1);
|
||||
EXPECT_TRUE(pipelineState->lastHasMainDirectionalShadow);
|
||||
EXPECT_NE(pipelineState->lastShadowMap, nullptr);
|
||||
EXPECT_FLOAT_EQ(pipelineState->lastShadowViewProjection.m[0][3], 11.0f);
|
||||
EXPECT_FLOAT_EQ(pipelineState->lastShadowViewProjection.m[1][3], 12.0f);
|
||||
EXPECT_FLOAT_EQ(pipelineState->lastShadowViewProjection.m[2][3], 13.0f);
|
||||
EXPECT_FLOAT_EQ(pipelineState->lastShadowParams.x, 0.0015f);
|
||||
EXPECT_FLOAT_EQ(pipelineState->lastShadowParams.y, 1.0f / 256.0f);
|
||||
EXPECT_FLOAT_EQ(pipelineState->lastShadowParams.z, 1.0f / 128.0f);
|
||||
EXPECT_FLOAT_EQ(pipelineState->lastShadowParams.w, 0.85f);
|
||||
}
|
||||
|
||||
TEST(CameraRenderer_Test, StopsRenderingWhenShadowCasterRequestIsInvalid) {
|
||||
|
||||
@@ -137,7 +137,10 @@ TEST(ShaderLoader, LoadShaderManifestBuildsMultiPassBackendVariants) {
|
||||
manifest << " { \"name\": \"PerObjectConstants\", \"type\": \"ConstantBuffer\", \"set\": 1, \"binding\": 0, \"semantic\": \"PerObject\" },\n";
|
||||
manifest << " { \"name\": \"MaterialConstants\", \"type\": \"ConstantBuffer\", \"set\": 2, \"binding\": 0, \"semantic\": \"Material\" },\n";
|
||||
manifest << " { \"name\": \"BaseColorTexture\", \"type\": \"Texture2D\", \"set\": 3, \"binding\": 0, \"semantic\": \"BaseColorTexture\" },\n";
|
||||
manifest << " { \"name\": \"LinearClampSampler\", \"type\": \"Sampler\", \"set\": 4, \"binding\": 0, \"semantic\": \"LinearClampSampler\" }\n";
|
||||
manifest << " { \"name\": \"LinearClampSampler\", \"type\": \"Sampler\", \"set\": 4, \"binding\": 0, \"semantic\": \"LinearClampSampler\" },\n";
|
||||
manifest << " { \"name\": \"ShadowReceiverConstants\", \"type\": \"ConstantBuffer\", \"set\": 5, \"binding\": 0, \"semantic\": \"ShadowReceiver\" },\n";
|
||||
manifest << " { \"name\": \"ShadowMapTexture\", \"type\": \"Texture2D\", \"set\": 6, \"binding\": 0, \"semantic\": \"ShadowMapTexture\" },\n";
|
||||
manifest << " { \"name\": \"ShadowMapSampler\", \"type\": \"Sampler\", \"set\": 7, \"binding\": 0, \"semantic\": \"ShadowMapSampler\" }\n";
|
||||
manifest << " ],\n";
|
||||
manifest << " \"variants\": [\n";
|
||||
manifest << " { \"stage\": \"Vertex\", \"backend\": \"D3D12\", \"language\": \"HLSL\", \"source\": \"stages/forward_lit.vs.hlsl\", \"entryPoint\": \"MainVS\", \"profile\": \"vs_5_0\" },\n";
|
||||
@@ -190,7 +193,7 @@ TEST(ShaderLoader, LoadShaderManifestBuildsMultiPassBackendVariants) {
|
||||
const ShaderPass* forwardLitPass = shader->FindPass("ForwardLit");
|
||||
ASSERT_NE(forwardLitPass, nullptr);
|
||||
ASSERT_EQ(forwardLitPass->tags.Size(), 2u);
|
||||
ASSERT_EQ(forwardLitPass->resources.Size(), 4u);
|
||||
ASSERT_EQ(forwardLitPass->resources.Size(), 7u);
|
||||
EXPECT_EQ(forwardLitPass->tags[0].name, "LightMode");
|
||||
EXPECT_EQ(forwardLitPass->tags[0].value, "ForwardBase");
|
||||
EXPECT_EQ(forwardLitPass->tags[1].name, "Queue");
|
||||
@@ -274,6 +277,9 @@ TEST(ShaderLoader, LoadUnityLikeShaderAuthoringBuildsRuntimeContract) {
|
||||
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
|
||||
@@ -325,7 +331,7 @@ TEST(ShaderLoader, LoadUnityLikeShaderAuthoringBuildsRuntimeContract) {
|
||||
const ShaderPass* forwardLitPass = shader->FindPass("ForwardLit");
|
||||
ASSERT_NE(forwardLitPass, nullptr);
|
||||
ASSERT_EQ(forwardLitPass->tags.Size(), 2u);
|
||||
ASSERT_EQ(forwardLitPass->resources.Size(), 4u);
|
||||
ASSERT_EQ(forwardLitPass->resources.Size(), 7u);
|
||||
EXPECT_EQ(forwardLitPass->tags[0].name, "Queue");
|
||||
EXPECT_EQ(forwardLitPass->tags[0].value, "Geometry");
|
||||
EXPECT_EQ(forwardLitPass->tags[1].name, "LightMode");
|
||||
@@ -671,7 +677,7 @@ TEST(ShaderLoader, LoadBuiltinForwardLitShaderBuildsBackendVariants) {
|
||||
ASSERT_EQ(shader->GetProperties().Size(), 2u);
|
||||
ASSERT_EQ(pass->variants.Size(), 6u);
|
||||
ASSERT_EQ(pass->tags.Size(), 1u);
|
||||
ASSERT_EQ(pass->resources.Size(), 4u);
|
||||
ASSERT_EQ(pass->resources.Size(), 7u);
|
||||
EXPECT_EQ(pass->tags[0].name, "LightMode");
|
||||
EXPECT_EQ(pass->tags[0].value, "ForwardBase");
|
||||
|
||||
@@ -693,6 +699,22 @@ TEST(ShaderLoader, LoadBuiltinForwardLitShaderBuildsBackendVariants) {
|
||||
EXPECT_EQ(perObjectBinding->binding, 0u);
|
||||
EXPECT_EQ(perObjectBinding->semantic, "PerObject");
|
||||
|
||||
const ShaderResourceBindingDesc* shadowReceiverBinding =
|
||||
shader->FindPassResourceBinding("ForwardLit", "ShadowReceiverConstants");
|
||||
ASSERT_NE(shadowReceiverBinding, nullptr);
|
||||
EXPECT_EQ(shadowReceiverBinding->type, ShaderResourceType::ConstantBuffer);
|
||||
EXPECT_EQ(shadowReceiverBinding->set, 5u);
|
||||
EXPECT_EQ(shadowReceiverBinding->binding, 0u);
|
||||
EXPECT_EQ(shadowReceiverBinding->semantic, "ShadowReceiver");
|
||||
|
||||
const ShaderResourceBindingDesc* shadowTextureBinding =
|
||||
shader->FindPassResourceBinding("ForwardLit", "ShadowMapTexture");
|
||||
ASSERT_NE(shadowTextureBinding, nullptr);
|
||||
EXPECT_EQ(shadowTextureBinding->type, ShaderResourceType::Texture2D);
|
||||
EXPECT_EQ(shadowTextureBinding->set, 6u);
|
||||
EXPECT_EQ(shadowTextureBinding->binding, 0u);
|
||||
EXPECT_EQ(shadowTextureBinding->semantic, "ShadowMapTexture");
|
||||
|
||||
EXPECT_NE(shader->FindVariant("ForwardLit", ShaderType::Vertex, ShaderBackend::D3D12), nullptr);
|
||||
EXPECT_NE(shader->FindVariant("ForwardLit", ShaderType::Fragment, ShaderBackend::D3D12), nullptr);
|
||||
EXPECT_NE(shader->FindVariant("ForwardLit", ShaderType::Vertex, ShaderBackend::OpenGL), nullptr);
|
||||
|
||||
Reference in New Issue
Block a user