Add render graph runtime depth support

This commit is contained in:
2026-04-14 14:05:59 +08:00
parent 87bf83451b
commit 31a8125fc1
3 changed files with 202 additions and 14 deletions

View File

@@ -22,6 +22,9 @@ struct MockTransientAllocationState {
int createRenderTargetViewCalls = 0;
int shutdownRenderTargetViewCalls = 0;
int destroyRenderTargetViewCalls = 0;
int createDepthViewCalls = 0;
int shutdownDepthViewCalls = 0;
int destroyDepthViewCalls = 0;
int createShaderViewCalls = 0;
int shutdownShaderViewCalls = 0;
int destroyShaderViewCalls = 0;
@@ -83,6 +86,8 @@ public:
~MockTransientView() override {
if (m_viewType == ResourceViewType::RenderTarget) {
++m_state->destroyRenderTargetViewCalls;
} else if (m_viewType == ResourceViewType::DepthStencil) {
++m_state->destroyDepthViewCalls;
} else {
++m_state->destroyShaderViewCalls;
}
@@ -91,6 +96,8 @@ public:
void Shutdown() override {
if (m_viewType == ResourceViewType::RenderTarget) {
++m_state->shutdownRenderTargetViewCalls;
} else if (m_viewType == ResourceViewType::DepthStencil) {
++m_state->shutdownDepthViewCalls;
} else {
++m_state->shutdownShaderViewCalls;
}
@@ -110,12 +117,23 @@ private:
class MockImportedView final : public RHIResourceView {
public:
explicit MockImportedView(
ResourceViewType viewType = ResourceViewType::RenderTarget,
Format format = Format::R8G8B8A8_UNorm)
: m_viewType(viewType)
, m_format(format) {
}
void Shutdown() override {}
void* GetNativeHandle() override { return nullptr; }
bool IsValid() const override { return true; }
ResourceViewType GetViewType() const override { return ResourceViewType::RenderTarget; }
ResourceViewType GetViewType() const override { return m_viewType; }
ResourceViewDimension GetDimension() const override { return ResourceViewDimension::Texture2D; }
Format GetFormat() const override { return Format::R8G8B8A8_UNorm; }
Format GetFormat() const override { return m_format; }
private:
ResourceViewType m_viewType = ResourceViewType::RenderTarget;
Format m_format = Format::R8G8B8A8_UNorm;
};
class MockTransientDevice final : public RHIDevice {
@@ -183,7 +201,15 @@ public:
static_cast<Format>(desc.format));
}
RHIResourceView* CreateDepthStencilView(RHITexture*, const ResourceViewDesc&) override { return nullptr; }
RHIResourceView* CreateDepthStencilView(
RHITexture*,
const ResourceViewDesc& desc) override {
++m_state->createDepthViewCalls;
return new MockTransientView(
m_state,
ResourceViewType::DepthStencil,
static_cast<Format>(desc.format));
}
RHIResourceView* CreateShaderResourceView(RHIBuffer*, const ResourceViewDesc&) override { return nullptr; }
RHIResourceView* CreateShaderResourceView(
@@ -574,6 +600,127 @@ TEST(RenderGraph_Test, TracksDepthAttachmentTransitionPlan) {
EXPECT_EQ(transitionPlan.finalState, ResourceStates::DepthWrite);
}
TEST(RenderGraph_Test, ExecutesTransientDepthTransitionsWithDepthStencilView) {
RenderGraph graph;
RenderGraphBuilder builder(graph);
const RenderGraphTextureDesc depthDesc = BuildTestDepthTextureDesc();
const RenderGraphTextureHandle depthTexture =
builder.CreateTransientTexture("SceneDepth", depthDesc);
RHIResourceView* depthWriteView = nullptr;
RHIResourceView* depthReadView = nullptr;
builder.AddRasterPass(
"DepthPrepass",
[&](RenderGraphPassBuilder& pass) {
pass.WriteDepthTexture(depthTexture);
pass.SetExecuteCallback(
[&](const RenderGraphExecutionContext& executionContext) {
depthWriteView =
executionContext.ResolveTextureView(
depthTexture,
RenderGraphTextureViewType::DepthStencil);
EXPECT_NE(depthWriteView, nullptr);
});
});
builder.AddRasterPass(
"DepthConsumer",
[&](RenderGraphPassBuilder& pass) {
pass.ReadDepthTexture(depthTexture);
pass.SetExecuteCallback(
[&](const RenderGraphExecutionContext& executionContext) {
depthReadView =
executionContext.ResolveTextureView(
depthTexture,
RenderGraphTextureViewType::DepthStencil);
EXPECT_EQ(depthReadView, depthWriteView);
});
});
CompiledRenderGraph compiledGraph;
XCEngine::Containers::String errorMessage;
ASSERT_TRUE(RenderGraphCompiler::Compile(graph, compiledGraph, &errorMessage))
<< errorMessage.CStr();
auto allocationState = std::make_shared<MockTransientAllocationState>();
MockTransientDevice device(allocationState);
MockTransientCommandList commandList;
RenderContext renderContext = {};
renderContext.device = &device;
renderContext.commandList = &commandList;
renderContext.commandQueue = reinterpret_cast<RHICommandQueue*>(1);
ASSERT_TRUE(RenderGraphExecutor::Execute(compiledGraph, renderContext, &errorMessage))
<< errorMessage.CStr();
ASSERT_EQ(commandList.transitionCalls.size(), 2u);
EXPECT_EQ(commandList.transitionCalls[0].resource, depthWriteView);
EXPECT_EQ(commandList.transitionCalls[0].before, ResourceStates::Common);
EXPECT_EQ(commandList.transitionCalls[0].after, ResourceStates::DepthWrite);
EXPECT_EQ(commandList.transitionCalls[1].resource, depthReadView);
EXPECT_EQ(commandList.transitionCalls[1].before, ResourceStates::DepthWrite);
EXPECT_EQ(commandList.transitionCalls[1].after, ResourceStates::DepthRead);
EXPECT_EQ(allocationState->createTextureCalls, 1);
EXPECT_EQ(allocationState->createRenderTargetViewCalls, 0);
EXPECT_EQ(allocationState->createDepthViewCalls, 1);
EXPECT_EQ(allocationState->createShaderViewCalls, 0);
EXPECT_EQ(allocationState->shutdownTextureCalls, 1);
EXPECT_EQ(allocationState->shutdownRenderTargetViewCalls, 0);
EXPECT_EQ(allocationState->shutdownDepthViewCalls, 1);
EXPECT_EQ(allocationState->shutdownShaderViewCalls, 0);
EXPECT_EQ(allocationState->destroyTextureCalls, 1);
EXPECT_EQ(allocationState->destroyRenderTargetViewCalls, 0);
EXPECT_EQ(allocationState->destroyDepthViewCalls, 1);
EXPECT_EQ(allocationState->destroyShaderViewCalls, 0);
}
TEST(RenderGraph_Test, ExecutesGraphOwnedImportedDepthTransitionsAtGraphBoundaries) {
RenderGraph graph;
RenderGraphBuilder builder(graph);
const RenderGraphTextureDesc depthDesc = BuildTestDepthTextureDesc();
RenderGraphImportedTextureOptions importedOptions = {};
importedOptions.initialState = ResourceStates::DepthWrite;
importedOptions.finalState = ResourceStates::DepthWrite;
importedOptions.graphOwnsTransitions = true;
MockImportedView importedDepthView(
ResourceViewType::DepthStencil,
Format::D24_UNorm_S8_UInt);
const RenderGraphTextureHandle importedDepth = builder.ImportTexture(
"ImportedDepth",
depthDesc,
&importedDepthView,
importedOptions);
builder.AddRasterPass(
"ReadOnlyDepth",
[&](RenderGraphPassBuilder& pass) {
pass.ReadDepthTexture(importedDepth);
});
CompiledRenderGraph compiledGraph;
XCEngine::Containers::String errorMessage;
ASSERT_TRUE(RenderGraphCompiler::Compile(graph, compiledGraph, &errorMessage))
<< errorMessage.CStr();
MockTransientCommandList commandList;
RenderContext renderContext = {};
renderContext.device = reinterpret_cast<RHIDevice*>(1);
renderContext.commandList = &commandList;
renderContext.commandQueue = reinterpret_cast<RHICommandQueue*>(1);
ASSERT_TRUE(RenderGraphExecutor::Execute(compiledGraph, renderContext, &errorMessage))
<< errorMessage.CStr();
ASSERT_EQ(commandList.transitionCalls.size(), 2u);
EXPECT_EQ(commandList.transitionCalls[0].resource, &importedDepthView);
EXPECT_EQ(commandList.transitionCalls[0].before, ResourceStates::DepthWrite);
EXPECT_EQ(commandList.transitionCalls[0].after, ResourceStates::DepthRead);
EXPECT_EQ(commandList.transitionCalls[1].resource, &importedDepthView);
EXPECT_EQ(commandList.transitionCalls[1].before, ResourceStates::DepthRead);
EXPECT_EQ(commandList.transitionCalls[1].after, ResourceStates::DepthWrite);
}
TEST(RenderGraph_Test, ExecutesCompiledPassCallbacksInCompiledOrder) {
RenderGraph graph;
RenderGraphBuilder builder(graph);