Add 3DGS D3D12 composite debug checkpoint

This commit is contained in:
2026-04-13 20:17:13 +08:00
parent 5b89c2bb76
commit e462f7d6f7
7 changed files with 171 additions and 5 deletions

View File

@@ -42,6 +42,8 @@ add_executable(xc_3dgs_d3d12_mvs
shaders/DeviceRadixSort.hlsl
shaders/DebugPointsVS.hlsl
shaders/DebugPointsPS.hlsl
shaders/CompositeVS.hlsl
shaders/CompositePS.hlsl
)
set_source_files_properties(
@@ -52,6 +54,8 @@ set_source_files_properties(
shaders/DeviceRadixSort.hlsl
shaders/DebugPointsVS.hlsl
shaders/DebugPointsPS.hlsl
shaders/CompositeVS.hlsl
shaders/CompositePS.hlsl
PROPERTIES
HEADER_FILE_ONLY TRUE
)

View File

@@ -67,10 +67,12 @@ private:
bool InitializePreparePassResources();
bool InitializeSortResources();
bool InitializeDebugDrawResources();
bool InitializeCompositeResources();
void ShutdownGaussianGpuResources();
void ShutdownPreparePassResources();
void ShutdownSortResources();
void ShutdownDebugDrawResources();
void ShutdownCompositeResources();
void Shutdown();
bool CaptureSortSnapshot();
bool CapturePass3HistogramDebug();
@@ -137,6 +139,13 @@ private:
XCEngine::RHI::RHIPipelineState* m_debugPipelineState = nullptr;
XCEngine::RHI::RHIDescriptorPool* m_debugDescriptorPool = nullptr;
XCEngine::RHI::RHIDescriptorSet* m_debugDescriptorSet = nullptr;
XCEngine::RHI::D3D12Texture m_splatRenderTargetTexture;
std::unique_ptr<XCEngine::RHI::D3D12ResourceView> m_splatRenderTargetRtv;
std::unique_ptr<XCEngine::RHI::D3D12ResourceView> m_splatRenderTargetSrv;
XCEngine::RHI::RHIPipelineLayout* m_compositePipelineLayout = nullptr;
XCEngine::RHI::RHIPipelineState* m_compositePipelineState = nullptr;
XCEngine::RHI::RHIDescriptorPool* m_compositeDescriptorPool = nullptr;
XCEngine::RHI::RHIDescriptorSet* m_compositeDescriptorSet = nullptr;
XCEngine::RHI::D3D12Device m_device;
XCEngine::RHI::D3D12CommandQueue m_commandQueue;

View File

@@ -0,0 +1,12 @@
Texture2D<float4> gSplatTexture : register(t0);
struct PixelInput
{
float4 position : SV_Position;
};
float4 MainPS(PixelInput input) : SV_Target0
{
float4 color = gSplatTexture.Load(int3(int2(input.position.xy), 0));
return float4(color.rgb, color.a);
}

View File

@@ -0,0 +1,12 @@
struct VertexOutput
{
float4 position : SV_Position;
};
VertexOutput MainVS(uint vertexId : SV_VertexID)
{
VertexOutput output = (VertexOutput)0;
float2 quadPosition = float2(vertexId & 1, (vertexId >> 1) & 1) * 4.0 - 1.0;
output.position = float4(quadPosition, 1.0, 1.0);
return output;
}

View File

@@ -37,10 +37,8 @@ VertexOutput MainVS(uint vertexId : SV_VertexID, uint instanceId : SV_InstanceID
float2 quadPosition = float2(vertexId & 1, (vertexId >> 1) & 1) * 2.0 - 1.0;
quadPosition *= 2.0;
float2 scaledAxis1 = view.axis1 * gSettings.w;
float2 scaledAxis2 = view.axis2 * gSettings.w;
float2 deltaScreenPosition =
(quadPosition.x * scaledAxis1 + quadPosition.y * scaledAxis2) * 2.0 / gScreenParams.xy;
(quadPosition.x * view.axis1 + quadPosition.y * view.axis2) * 2.0 / gScreenParams.xy;
output.position = view.clipPosition;
output.position.xy += deltaScreenPosition * view.clipPosition.w;

View File

@@ -143,7 +143,7 @@ float3 CalcCovariance2D(float3 worldPosition, float3 covariance0, float3 covaria
focal / viewPosition.z, 0, -(focal * viewPosition.x) / (viewPosition.z * viewPosition.z),
0, focal / viewPosition.z, -(focal * viewPosition.y) / (viewPosition.z * viewPosition.z),
0, 0, 0);
float3x3 worldToView = (float3x3)gView;
float3x3 worldToView = transpose((float3x3)gView);
float3x3 transform = mul(jacobian, worldToView);
float3x3 covariance = float3x3(
covariance0.x, covariance0.y, covariance0.z,
@@ -253,6 +253,9 @@ void MainCS(uint3 dispatchThreadId : SV_DispatchThreadID)
float3 covariance0;
float3 covariance1;
CalcCovariance3D(rotationScale, covariance0, covariance1);
float splatScaleSquared = gSettings.w * gSettings.w;
covariance0 *= splatScaleSquared;
covariance1 *= splatScaleSquared;
float3 covariance2D = CalcCovariance2D(position, covariance0, covariance1);
DecomposeCovariance(covariance2D, view.axis1, view.axis2);

View File

@@ -1140,6 +1140,118 @@ bool App::InitializeDebugDrawResources() {
return true;
}
bool App::InitializeCompositeResources() {
D3D12_RESOURCE_DESC splatRenderTargetDesc = {};
splatRenderTargetDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
splatRenderTargetDesc.Alignment = 0;
splatRenderTargetDesc.Width = static_cast<UINT64>(m_width);
splatRenderTargetDesc.Height = static_cast<UINT>(m_height);
splatRenderTargetDesc.DepthOrArraySize = 1;
splatRenderTargetDesc.MipLevels = 1;
splatRenderTargetDesc.Format = DXGI_FORMAT_R16G16B16A16_FLOAT;
splatRenderTargetDesc.SampleDesc.Count = 1;
splatRenderTargetDesc.SampleDesc.Quality = 0;
splatRenderTargetDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
splatRenderTargetDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
if (!m_splatRenderTargetTexture.Initialize(
m_device.GetDevice(),
splatRenderTargetDesc,
D3D12_RESOURCE_STATE_RENDER_TARGET)) {
m_lastErrorMessage = L"Failed to create the splat accumulation render target texture.";
return false;
}
m_splatRenderTargetTexture.SetState(ResourceStates::RenderTarget);
ResourceViewDesc renderTargetViewDesc = {};
renderTargetViewDesc.dimension = ResourceViewDimension::Texture2D;
renderTargetViewDesc.format = static_cast<uint32_t>(Format::R16G16B16A16_Float);
m_splatRenderTargetRtv.reset(static_cast<D3D12ResourceView*>(
m_device.CreateRenderTargetView(&m_splatRenderTargetTexture, renderTargetViewDesc)));
if (!m_splatRenderTargetRtv) {
m_lastErrorMessage = L"Failed to create the splat accumulation render target view.";
return false;
}
m_splatRenderTargetSrv.reset(static_cast<D3D12ResourceView*>(
m_device.CreateShaderResourceView(&m_splatRenderTargetTexture, renderTargetViewDesc)));
if (!m_splatRenderTargetSrv) {
m_lastErrorMessage = L"Failed to create the splat accumulation shader resource view.";
return false;
}
DescriptorSetLayoutBinding bindings[1] = {};
bindings[0].binding = 0;
bindings[0].type = static_cast<uint32_t>(DescriptorType::SRV);
bindings[0].count = 1;
bindings[0].visibility = static_cast<uint32_t>(ShaderVisibility::Pixel);
bindings[0].resourceDimension = ResourceViewDimension::Texture2D;
DescriptorSetLayoutDesc setLayout = {};
setLayout.bindings = bindings;
setLayout.bindingCount = 1;
RHIPipelineLayoutDesc pipelineLayoutDesc = {};
pipelineLayoutDesc.setLayouts = &setLayout;
pipelineLayoutDesc.setLayoutCount = 1;
m_compositePipelineLayout = m_device.CreatePipelineLayout(pipelineLayoutDesc);
if (m_compositePipelineLayout == nullptr) {
m_lastErrorMessage = L"Failed to create the composite pipeline layout.";
return false;
}
DescriptorPoolDesc poolDesc = {};
poolDesc.type = DescriptorHeapType::CBV_SRV_UAV;
poolDesc.descriptorCount = 1;
poolDesc.shaderVisible = true;
m_compositeDescriptorPool = m_device.CreateDescriptorPool(poolDesc);
if (m_compositeDescriptorPool == nullptr) {
m_lastErrorMessage = L"Failed to create the composite descriptor pool.";
return false;
}
m_compositeDescriptorSet = m_compositeDescriptorPool->AllocateSet(setLayout);
if (m_compositeDescriptorSet == nullptr) {
m_lastErrorMessage = L"Failed to allocate the composite descriptor set.";
return false;
}
m_compositeDescriptorSet->Update(0, m_splatRenderTargetSrv.get());
GraphicsPipelineDesc pipelineDesc = {};
pipelineDesc.pipelineLayout = m_compositePipelineLayout;
pipelineDesc.topologyType = static_cast<uint32_t>(PrimitiveTopologyType::Triangle);
pipelineDesc.renderTargetCount = 1;
pipelineDesc.renderTargetFormats[0] = static_cast<uint32_t>(Format::R8G8B8A8_UNorm);
pipelineDesc.depthStencilFormat = static_cast<uint32_t>(Format::Unknown);
pipelineDesc.sampleCount = 1;
pipelineDesc.sampleQuality = 0;
pipelineDesc.rasterizerState.cullMode = static_cast<uint32_t>(CullMode::None);
pipelineDesc.depthStencilState.depthTestEnable = false;
pipelineDesc.depthStencilState.depthWriteEnable = false;
pipelineDesc.blendState.blendEnable = true;
pipelineDesc.blendState.srcBlend = static_cast<uint32_t>(BlendFactor::SrcAlpha);
pipelineDesc.blendState.dstBlend = static_cast<uint32_t>(BlendFactor::InvSrcAlpha);
pipelineDesc.blendState.srcBlendAlpha = static_cast<uint32_t>(BlendFactor::One);
pipelineDesc.blendState.dstBlendAlpha = static_cast<uint32_t>(BlendFactor::InvSrcAlpha);
pipelineDesc.vertexShader.fileName = ResolveShaderPath(L"CompositeVS.hlsl").wstring();
pipelineDesc.vertexShader.entryPoint = L"MainVS";
pipelineDesc.vertexShader.profile = L"vs_5_0";
pipelineDesc.fragmentShader.fileName = ResolveShaderPath(L"CompositePS.hlsl").wstring();
pipelineDesc.fragmentShader.entryPoint = L"MainPS";
pipelineDesc.fragmentShader.profile = L"ps_5_0";
m_compositePipelineState = m_device.CreatePipelineState(pipelineDesc);
if (m_compositePipelineState == nullptr) {
m_lastErrorMessage = L"Failed to create the composite pipeline state.";
return false;
}
return true;
}
void App::ShutdownGaussianGpuResources() {
m_gaussianColorView.reset();
m_gaussianShView.reset();
@@ -1256,6 +1368,20 @@ void App::ShutdownDebugDrawResources() {
ShutdownAndDelete(m_debugPipelineLayout);
}
void App::ShutdownCompositeResources() {
if (m_compositeDescriptorSet != nullptr) {
m_compositeDescriptorSet->Shutdown();
delete m_compositeDescriptorSet;
m_compositeDescriptorSet = nullptr;
}
ShutdownAndDelete(m_compositeDescriptorPool);
ShutdownAndDelete(m_compositePipelineState);
ShutdownAndDelete(m_compositePipelineLayout);
m_splatRenderTargetSrv.reset();
m_splatRenderTargetRtv.reset();
m_splatRenderTargetTexture.Shutdown();
}
void App::Shutdown() {
AppendTrace("Shutdown: begin");
if (!m_isInitialized && m_hwnd == nullptr) {
@@ -1670,8 +1796,8 @@ void App::RenderFrame(bool captureScreenshot) {
const int currentBackBufferIndex = m_swapChain.GetCurrentBackBufferIndex();
D3D12Texture& backBuffer = m_swapChain.GetBackBuffer(currentBackBufferIndex);
m_commandList.TransitionBarrier(backBuffer.GetResource(), ResourceStates::Present, ResourceStates::RenderTarget);
backBuffer.SetState(ResourceStates::RenderTarget);
const CPUDescriptorHandle rtvCpuHandle = m_rtvHeap.GetCPUDescriptorHandle(currentBackBufferIndex);
const CPUDescriptorHandle dsvCpuHandle = m_dsvHeap.GetCPUDescriptorHandle(0);
@@ -2034,12 +2160,14 @@ void App::RenderFrame(bool captureScreenshot) {
m_commandAllocator.Reset();
m_commandList.Reset();
m_commandList.TransitionBarrier(backBuffer.GetResource(), ResourceStates::RenderTarget, ResourceStates::Present);
backBuffer.SetState(ResourceStates::Present);
m_commandList.Close();
void* presentCommandLists[] = { &m_commandList };
AppendTrace("RenderFrame: execute final present-transition list");
m_commandQueue.ExecuteCommandLists(1, presentCommandLists);
} else {
m_commandList.TransitionBarrier(backBuffer.GetResource(), ResourceStates::RenderTarget, ResourceStates::Present);
backBuffer.SetState(ResourceStates::Present);
m_commandList.Close();
void* commandLists[] = { &m_commandList };
AppendTrace("RenderFrame: execute+present");