From 77a29986b0b796863e4bfa250e224634aad38529 Mon Sep 17 00:00:00 2001 From: Austin Eng <213reeses@gmail.com> Date: Wed, 12 Jul 2017 20:36:36 -0400 Subject: [PATCH] D3D12 Render Targets (#72) Implements BeginRenderSubpass on the D3D12 backend. Descriptors for render target and depth stencil views are recorded in a descriptor heap for each framebuffer. For now, we still have the hack where no attachment renders to the backbuffer, so the CommandBuffer records those when necessary when it is submitted. This PR also enables input states for D3D12 which are mostly working. One failure seems to be happening because our texture copies are not yet correct. --- src/backend/CMakeLists.txt | 2 + src/backend/d3d12/CommandBufferD3D12.cpp | 30 +++++-- src/backend/d3d12/D3D12Backend.cpp | 26 +++--- src/backend/d3d12/D3D12Backend.h | 16 ++-- src/backend/d3d12/FramebufferD3D12.cpp | 99 +++++++++++++++++++++++ src/backend/d3d12/FramebufferD3D12.h | 49 +++++++++++ src/backend/d3d12/GeneratedCodeIncludes.h | 1 + src/backend/d3d12/TextureD3D12.cpp | 24 ++++-- src/backend/d3d12/TextureD3D12.h | 3 + src/tests/NXTTest.cpp | 4 + src/tests/NXTTest.h | 1 + src/tests/end2end/InputStateTests.cpp | 8 +- src/utils/D3D12Binding.cpp | 62 ++++++++------ 13 files changed, 263 insertions(+), 62 deletions(-) create mode 100644 src/backend/d3d12/FramebufferD3D12.cpp create mode 100644 src/backend/d3d12/FramebufferD3D12.h diff --git a/src/backend/CMakeLists.txt b/src/backend/CMakeLists.txt index 04e35fa08d..b7e0dc93d8 100644 --- a/src/backend/CMakeLists.txt +++ b/src/backend/CMakeLists.txt @@ -243,6 +243,8 @@ if (WIN32) ${D3D12_DIR}/DescriptorHeapAllocator.h ${D3D12_DIR}/D3D12Backend.cpp ${D3D12_DIR}/D3D12Backend.h + ${D3D12_DIR}/FramebufferD3D12.cpp + ${D3D12_DIR}/FramebufferD3D12.h ${D3D12_DIR}/InputStateD3D12.cpp ${D3D12_DIR}/InputStateD3D12.h ${D3D12_DIR}/PipelineD3D12.cpp diff --git a/src/backend/d3d12/CommandBufferD3D12.cpp b/src/backend/d3d12/CommandBufferD3D12.cpp index 5de2b5b029..199419cfd5 100644 --- a/src/backend/d3d12/CommandBufferD3D12.cpp +++ b/src/backend/d3d12/CommandBufferD3D12.cpp @@ -20,6 +20,7 @@ #include "backend/d3d12/BindGroupLayoutD3D12.h" #include "backend/d3d12/BufferD3D12.h" #include "backend/d3d12/DescriptorHeapAllocator.h" +#include "backend/d3d12/FramebufferD3D12.h" #include "backend/d3d12/InputStateD3D12.h" #include "backend/d3d12/PipelineD3D12.h" #include "backend/d3d12/PipelineLayoutD3D12.h" @@ -192,7 +193,7 @@ namespace d3d12 { D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER); } } - + D3D12_TEXTURE_COPY_LOCATION D3D12PlacedTextureCopyLocation(BufferCopyLocation& bufferLocation, Texture* texture, const TextureCopyLocation& textureLocation) { D3D12_TEXTURE_COPY_LOCATION d3d12Location; d3d12Location.pResource = ToBackend(bufferLocation.buffer.Get())->GetD3D12Resource().Get(); @@ -205,9 +206,9 @@ namespace d3d12 { uint32_t texelSize = 0; switch (texture->GetFormat()) { - case nxt::TextureFormat::R8G8B8A8Unorm: - texelSize = 4; - break; + case nxt::TextureFormat::R8G8B8A8Unorm: + texelSize = 4; + break; } uint32_t rowSize = textureLocation.width * texelSize; d3d12Location.PlacedFootprint.Footprint.RowPitch = ((rowSize - 1) / D3D12_TEXTURE_DATA_PITCH_ALIGNMENT + 1) * D3D12_TEXTURE_DATA_PITCH_ALIGNMENT; @@ -252,6 +253,7 @@ namespace d3d12 { RenderPass* currentRenderPass = nullptr; Framebuffer* currentFramebuffer = nullptr; + uint32_t currentSubpass = 0; while(commands.NextCommandId(&type)) { switch (type) { @@ -266,6 +268,7 @@ namespace d3d12 { BeginRenderPassCmd* beginRenderPassCmd = commands.NextCommand(); currentRenderPass = ToBackend(beginRenderPassCmd->renderPass.Get()); currentFramebuffer = ToBackend(beginRenderPassCmd->framebuffer.Get()); + currentSubpass = 0; uint32_t width = currentFramebuffer->GetWidth(); uint32_t height = currentFramebuffer->GetHeight(); @@ -273,14 +276,28 @@ namespace d3d12 { D3D12_RECT scissorRect = { 0, 0, static_cast(width), static_cast(height) }; commandList->RSSetViewports(1, &viewport); commandList->RSSetScissorRects(1, &scissorRect); - D3D12_CPU_DESCRIPTOR_HANDLE rtv = device->GetCurrentRenderTargetDescriptor(); - commandList->OMSetRenderTargets(1, &rtv, FALSE, nullptr); } break; case Command::BeginRenderSubpass: { commands.NextCommand(); + Framebuffer::OMSetRenderTargetArgs args = currentFramebuffer->GetSubpassOMSetRenderTargetArgs(currentSubpass); + + // HACK(enga@google.com): Remove when clearing is implemented + for (uint32_t index = 0; index < args.numRTVs; ++index) { + static const float clearColor[] = { 0.0f, 0.0f, 0.0f, 0.0f }; + commandList->ClearRenderTargetView(args.RTVs[index], clearColor, 0, nullptr); + } + + if (args.dsv.ptr) { + // HACK(enga@google.com): Remove when clearing is implemented + commandList->ClearDepthStencilView(args.dsv, D3D12_CLEAR_FLAG_DEPTH | D3D12_CLEAR_FLAG_STENCIL, 1.0, 0, 0, nullptr); + + commandList->OMSetRenderTargets(args.numRTVs, args.RTVs, FALSE, &args.dsv); + } else { + commandList->OMSetRenderTargets(args.numRTVs, args.RTVs, FALSE, nullptr); + } } break; @@ -389,6 +406,7 @@ namespace d3d12 { case Command::EndRenderSubpass: { commands.NextCommand(); + currentSubpass += 1; } break; diff --git a/src/backend/d3d12/D3D12Backend.cpp b/src/backend/d3d12/D3D12Backend.cpp index b330bcebe8..8eb533c487 100644 --- a/src/backend/d3d12/D3D12Backend.cpp +++ b/src/backend/d3d12/D3D12Backend.cpp @@ -20,6 +20,7 @@ #include "backend/d3d12/CommandAllocatorManager.h" #include "backend/d3d12/CommandBufferD3D12.h" #include "backend/d3d12/DescriptorHeapAllocator.h" +#include "backend/d3d12/FramebufferD3D12.h" #include "backend/d3d12/InputStateD3D12.h" #include "backend/d3d12/PipelineD3D12.h" #include "backend/d3d12/PipelineLayoutD3D12.h" @@ -48,9 +49,9 @@ namespace d3d12 { return backendDevice->GetCommandQueue(); } - void SetNextRenderTargetDescriptor(nxtDevice device, D3D12_CPU_DESCRIPTOR_HANDLE renderTargetDescriptor) { + void SetNextTexture(nxtDevice device, ComPtr resource, ComPtr depthResource) { Device* backendDevice = reinterpret_cast(device); - backendDevice->SetNextRenderTargetDescriptor(renderTargetDescriptor); + backendDevice->SetNextTexture(resource, depthResource); } uint64_t GetSerial(const nxtDevice device) { @@ -155,14 +156,17 @@ namespace d3d12 { return pendingCommands.commandList; } - D3D12_CPU_DESCRIPTOR_HANDLE Device::GetCurrentRenderTargetDescriptor() { - return renderTargetDescriptor; + ComPtr Device::GetCurrentTexture() { + return nextTexture; } - void Device::SetNextRenderTargetDescriptor(D3D12_CPU_DESCRIPTOR_HANDLE renderTargetDescriptor) { - this->renderTargetDescriptor = renderTargetDescriptor; - static const float clearColor[] = { 0.0f, 0.0f, 0.0f, 1.0f }; - GetPendingCommandList()->ClearRenderTargetView(renderTargetDescriptor, clearColor, 0, nullptr); + ComPtr Device::GetCurrentDepthTexture() { + return nextDepthTexture; + } + + void Device::SetNextTexture(ComPtr resource, ComPtr depthResource) { + nextTexture = resource; + nextDepthTexture = depthResource; } void Device::TickImpl() { @@ -262,12 +266,6 @@ namespace d3d12 { : DepthStencilStateBase(builder), device(device) { } - // Framebuffer - - Framebuffer::Framebuffer(Device* device, FramebufferBuilder* builder) - : FramebufferBase(builder), device(device) { - } - // RenderPass RenderPass::RenderPass(Device* device, RenderPassBuilder* builder) diff --git a/src/backend/d3d12/D3D12Backend.h b/src/backend/d3d12/D3D12Backend.h index ec310f80bc..9f1c81f49c 100644 --- a/src/backend/d3d12/D3D12Backend.h +++ b/src/backend/d3d12/D3D12Backend.h @@ -123,8 +123,9 @@ namespace d3d12 { void OpenCommandList(ComPtr* commandList); ComPtr GetPendingCommandList(); - D3D12_CPU_DESCRIPTOR_HANDLE GetCurrentRenderTargetDescriptor(); - void SetNextRenderTargetDescriptor(D3D12_CPU_DESCRIPTOR_HANDLE renderTargetDescriptor); + ComPtr GetCurrentTexture(); + ComPtr GetCurrentDepthTexture(); + void SetNextTexture(ComPtr resource, ComPtr depthResource); uint64_t GetSerial() const; void NextSerial(); @@ -151,15 +152,8 @@ namespace d3d12 { bool open = false; } pendingCommands; - D3D12_CPU_DESCRIPTOR_HANDLE renderTargetDescriptor; - }; - - class Framebuffer : public FramebufferBase { - public: - Framebuffer(Device* device, FramebufferBuilder* builder); - - private: - Device* device; + ComPtr nextTexture; + ComPtr nextDepthTexture; }; class DepthStencilState : public DepthStencilStateBase { diff --git a/src/backend/d3d12/FramebufferD3D12.cpp b/src/backend/d3d12/FramebufferD3D12.cpp new file mode 100644 index 0000000000..992c336645 --- /dev/null +++ b/src/backend/d3d12/FramebufferD3D12.cpp @@ -0,0 +1,99 @@ +// Copyright 2017 The NXT Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "backend/d3d12/FramebufferD3D12.h" + +#include "common/BitSetIterator.h" +#include "backend/d3d12/D3D12Backend.h" +#include "backend/d3d12/TextureD3D12.h" + +namespace backend { +namespace d3d12 { + + Framebuffer::Framebuffer(Device* device, FramebufferBuilder* builder) + : FramebufferBase(builder), device(device) { + + RenderPass* renderPass = ToBackend(GetRenderPass()); + uint32_t attachmentCount = renderPass->GetAttachmentCount(); + rtvHeap = device->GetDescriptorHeapAllocator()->AllocateCPUHeap(D3D12_DESCRIPTOR_HEAP_TYPE_RTV, attachmentCount); + + bool usingBackbuffer = false; // HACK(enga@google.com): workaround for not having depth attachments + uint32_t rtvIndex = 0; + + for (uint32_t attachment = 0; attachment < attachmentCount; ++attachment) { + auto* textureView = GetTextureView(attachment); + if (textureView) { + ComPtr texture = ToBackend(textureView->GetTexture())->GetD3D12Resource(); + D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = rtvHeap.GetCPUHandle(rtvIndex++); + D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = ToBackend(textureView)->GetRTVDescriptor(); + + device->GetD3D12Device()->CreateRenderTargetView(texture.Get(), &rtvDesc, rtvHandle); + } else { + // TODO(enga@google.com) no attachment. This will use the backbuffer. Remove when this hack is removed + usingBackbuffer = true; + rtvIndex++; + } + } + + // TODO(enga@google.com): load depth attachment from subpass + if (usingBackbuffer) { + dsvHeap = device->GetDescriptorHeapAllocator()->AllocateCPUHeap(D3D12_DESCRIPTOR_HEAP_TYPE_DSV, 1); + D3D12_CPU_DESCRIPTOR_HANDLE dsvHandle = dsvHeap.GetCPUHandle(0); + + D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc; + dsvDesc.Format = DXGI_FORMAT_D32_FLOAT_S8X24_UINT; + dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D; + dsvDesc.Texture2D.MipSlice = 0; + dsvDesc.Flags = D3D12_DSV_FLAG_NONE; + + device->GetD3D12Device()->CreateDepthStencilView(device->GetCurrentDepthTexture().Get(), &dsvDesc, dsvHandle); + } + } + + Framebuffer::OMSetRenderTargetArgs Framebuffer::GetSubpassOMSetRenderTargetArgs(uint32_t subpassIndex) { + const auto& subpassInfo = GetRenderPass()->GetSubpassInfo(subpassIndex); + + bool usingBackbuffer = false; // HACK(enga@google.com): workaround for not having depth attachments + + OMSetRenderTargetArgs args; + args.numRTVs = 0; + + for (uint32_t index : IterateBitSet(subpassInfo.colorAttachmentsSet)) { + uint32_t attachment = subpassInfo.colorAttachments[index]; + const auto& attachmentInfo = GetRenderPass()->GetAttachmentInfo(attachment); + + D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = rtvHeap.GetCPUHandle(attachment); + args.RTVs[args.numRTVs++] = rtvHandle; + if (!GetTextureView(attachment)) { + usingBackbuffer = true; + + D3D12_RENDER_TARGET_VIEW_DESC rtvDesc; + rtvDesc.Format = D3D12TextureFormat(attachmentInfo.format); + rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D; + rtvDesc.Texture2D.MipSlice = 0; + rtvDesc.Texture2D.PlaneSlice = 0; + + device->GetD3D12Device()->CreateRenderTargetView(device->GetCurrentTexture().Get(), &rtvDesc, rtvHandle); + } + } + + if (usingBackbuffer) { + args.dsv = dsvHeap.GetCPUHandle(0); + } + + return args; + } + +} +} diff --git a/src/backend/d3d12/FramebufferD3D12.h b/src/backend/d3d12/FramebufferD3D12.h new file mode 100644 index 0000000000..c31daf3fdc --- /dev/null +++ b/src/backend/d3d12/FramebufferD3D12.h @@ -0,0 +1,49 @@ +// Copyright 2017 The NXT Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef BACKEND_D3D12_FRAMEBUFFERD3D12_H_ +#define BACKEND_D3D12_FRAMEBUFFERD3D12_H_ + +#include "backend/Framebuffer.h" + +#include "common/Constants.h" +#include "backend/d3d12/d3d12_platform.h" +#include "backend/d3d12/DescriptorHeapAllocator.h" + +namespace backend { +namespace d3d12 { + + class Device; + + class Framebuffer : public FramebufferBase { + public: + struct OMSetRenderTargetArgs { + unsigned int numRTVs; + D3D12_CPU_DESCRIPTOR_HANDLE RTVs[kMaxColorAttachments] = {}; + D3D12_CPU_DESCRIPTOR_HANDLE dsv = { 0 }; + }; + + Framebuffer(Device* device, FramebufferBuilder* builder); + OMSetRenderTargetArgs GetSubpassOMSetRenderTargetArgs(uint32_t subpassIndex); + + private: + Device* device; + DescriptorHeapHandle rtvHeap; + DescriptorHeapHandle dsvHeap; + }; + +} +} + +#endif // BACKEND_D3D12_FRAMEBUFFERD3D12_H_ diff --git a/src/backend/d3d12/GeneratedCodeIncludes.h b/src/backend/d3d12/GeneratedCodeIncludes.h index 7ec9e6f586..334c2d98b5 100644 --- a/src/backend/d3d12/GeneratedCodeIncludes.h +++ b/src/backend/d3d12/GeneratedCodeIncludes.h @@ -17,6 +17,7 @@ #include "backend/d3d12/BindGroupLayoutD3D12.h" #include "backend/d3d12/BufferD3D12.h" #include "backend/d3d12/CommandBufferD3D12.h" +#include "backend/d3d12/FramebufferD3D12.h" #include "backend/d3d12/InputStateD3D12.h" #include "backend/d3d12/PipelineD3D12.h" #include "backend/d3d12/PipelineLayoutD3D12.h" diff --git a/src/backend/d3d12/TextureD3D12.cpp b/src/backend/d3d12/TextureD3D12.cpp index 49a08b9d96..cedf57e019 100644 --- a/src/backend/d3d12/TextureD3D12.cpp +++ b/src/backend/d3d12/TextureD3D12.cpp @@ -71,13 +71,14 @@ namespace d3d12 { } } - DXGI_FORMAT D3D12TextureFormat(nxt::TextureFormat format) { - switch (format) { - case nxt::TextureFormat::R8G8B8A8Unorm: - return DXGI_FORMAT_R8G8B8A8_UNORM; - default: - UNREACHABLE(); - } + } + + DXGI_FORMAT D3D12TextureFormat(nxt::TextureFormat format) { + switch (format) { + case nxt::TextureFormat::R8G8B8A8Unorm: + return DXGI_FORMAT_R8G8B8A8_UNORM; + default: + UNREACHABLE(); } } @@ -157,5 +158,14 @@ namespace d3d12 { return srvDesc; } + D3D12_RENDER_TARGET_VIEW_DESC TextureView::GetRTVDescriptor() { + D3D12_RENDER_TARGET_VIEW_DESC rtvDesc; + rtvDesc.Format = ToBackend(GetTexture())->GetD3D12Format(); + rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D; + rtvDesc.Texture2D.MipSlice = 0; + rtvDesc.Texture2D.PlaneSlice = 0; + return rtvDesc; + } + } } diff --git a/src/backend/d3d12/TextureD3D12.h b/src/backend/d3d12/TextureD3D12.h index e8029b4fd4..5dea5d7241 100644 --- a/src/backend/d3d12/TextureD3D12.h +++ b/src/backend/d3d12/TextureD3D12.h @@ -24,6 +24,8 @@ namespace d3d12 { class Device; + DXGI_FORMAT D3D12TextureFormat(nxt::TextureFormat format); + class Texture : public TextureBase { public: Texture(Device* device, TextureBuilder* builder); @@ -46,6 +48,7 @@ namespace d3d12 { TextureView(TextureViewBuilder* builder); const D3D12_SHADER_RESOURCE_VIEW_DESC& GetSRVDescriptor() const; + D3D12_RENDER_TARGET_VIEW_DESC GetRTVDescriptor(); private: D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc; diff --git a/src/tests/NXTTest.cpp b/src/tests/NXTTest.cpp index 05935a9699..c59ebaaa81 100644 --- a/src/tests/NXTTest.cpp +++ b/src/tests/NXTTest.cpp @@ -101,6 +101,10 @@ NXTTest::~NXTTest() { nxtSetProcs(nullptr); } +bool NXTTest::IsD3D12() const { + return GetParam() == D3D12Backend; +} + void NXTTest::SetUp() { binding = utils::CreateBinding(ParamToBackendType(GetParam())); NXT_ASSERT(binding != nullptr); diff --git a/src/tests/NXTTest.h b/src/tests/NXTTest.h index be5dc74cf8..65fc2dd9d2 100644 --- a/src/tests/NXTTest.h +++ b/src/tests/NXTTest.h @@ -62,6 +62,7 @@ class NXTTest : public ::testing::TestWithParam { void SetUp() override; void TearDown() override; + bool IsD3D12() const; protected: nxt::Device device; diff --git a/src/tests/end2end/InputStateTests.cpp b/src/tests/end2end/InputStateTests.cpp index dc1db5daaf..99eb4ee207 100644 --- a/src/tests/end2end/InputStateTests.cpp +++ b/src/tests/end2end/InputStateTests.cpp @@ -188,6 +188,7 @@ class InputStateTest : public NXTTest { nxt::CommandBufferBuilder builder = device.CreateCommandBufferBuilder(); + renderTarget.TransitionUsage(nxt::TextureUsageBit::OutputAttachment); builder.BeginRenderPass(renderpass, framebuffer) .BeginRenderSubpass() .SetPipeline(pipeline); @@ -383,6 +384,11 @@ TEST_P(InputStateTest, TwoAttributesAtAnOffsetInstance) { // Test a pure-instance input state TEST_P(InputStateTest, PureInstance) { + if (IsD3D12()) { + printf("TODO(enga@google.com): SKIPPED. Incorrect texture copies cause this test to fail\n"); + return; + } + nxt::InputState inputState = MakeInputState({ {0, 4 * sizeof(float), InputStepMode::Instance} }, { @@ -437,7 +443,7 @@ TEST_P(InputStateTest, MixedEverything) { DoTestDraw(pipeline, 1, 1, {{0, &buffer0}, {1, &buffer1}}); } -NXT_INSTANTIATE_TEST(InputStateTest, MetalBackend) +NXT_INSTANTIATE_TEST(InputStateTest, MetalBackend, D3D12Backend) // TODO for the input state: // - Add more vertex formats diff --git a/src/utils/D3D12Binding.cpp b/src/utils/D3D12Binding.cpp index 4c4e5e3c8e..8d6d4331e0 100644 --- a/src/utils/D3D12Binding.cpp +++ b/src/utils/D3D12Binding.cpp @@ -31,7 +31,7 @@ namespace backend { namespace d3d12 { void Init(ComPtr d3d12Device, nxtProcTable* procs, nxtDevice* device); ComPtr GetCommandQueue(nxtDevice device); - void SetNextRenderTargetDescriptor(nxtDevice device, D3D12_CPU_DESCRIPTOR_HANDLE renderTargetDescriptor); + void SetNextTexture(nxtDevice device, ComPtr resource, ComPtr depthResource); uint64_t GetSerial(const nxtDevice device); void NextSerial(nxtDevice device); void ExecuteCommandLists(nxtDevice device, std::initializer_list commandLists); @@ -87,6 +87,7 @@ namespace utils { swapChainDesc.BufferCount = kFrameCount; swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; swapChainDesc.SampleDesc.Count = 1; + swapChainDesc.SampleDesc.Quality = 0; HWND win32Window = glfwGetWin32Window(window); ComPtr swapChain1; @@ -99,23 +100,43 @@ namespace utils { &swapChain1 )); ASSERT_SUCCESS(swapChain1.As(&swapChain)); - - // Describe and create a render target view (RTV) descriptor heap. - D3D12_DESCRIPTOR_HEAP_DESC rtvHeapDesc = {}; - rtvHeapDesc.NumDescriptors = kFrameCount; - rtvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV; - rtvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE; - ASSERT_SUCCESS(d3d12Device->CreateDescriptorHeap(&rtvHeapDesc, IID_PPV_ARGS(&renderTargetViewHeap))); - - rtvDescriptorSize = d3d12Device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV); - - // Create a RTV for each frame. + + // Create a render target and depth stencil resource for each frame. { - D3D12_CPU_DESCRIPTOR_HANDLE renderTargetViewHandle = renderTargetViewHeap->GetCPUDescriptorHandleForHeapStart(); + D3D12_HEAP_PROPERTIES dsvHeapProperties; + dsvHeapProperties.Type = D3D12_HEAP_TYPE_DEFAULT; + dsvHeapProperties.CreationNodeMask = 0; + dsvHeapProperties.VisibleNodeMask = 0; + dsvHeapProperties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; + dsvHeapProperties.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; + + D3D12_RESOURCE_DESC dsvDesc; + dsvDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; + dsvDesc.Alignment = 0; + dsvDesc.Width = width; + dsvDesc.Height = height; + dsvDesc.DepthOrArraySize = 1; + dsvDesc.MipLevels = 0; + dsvDesc.Format = DXGI_FORMAT_D32_FLOAT_S8X24_UINT; + dsvDesc.SampleDesc.Count = 1; + dsvDesc.SampleDesc.Quality = 0; + dsvDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; + dsvDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL; + + D3D12_CLEAR_VALUE dsvClear; + dsvClear.Format = DXGI_FORMAT_D32_FLOAT_S8X24_UINT; + dsvClear.DepthStencil.Depth = 1.0f; + dsvClear.DepthStencil.Stencil = 0; + for (uint32_t n = 0; n < kFrameCount; ++n) { ASSERT_SUCCESS(swapChain->GetBuffer(n, IID_PPV_ARGS(&renderTargetResources[n]))); - d3d12Device->CreateRenderTargetView(renderTargetResources[n].Get(), nullptr, renderTargetViewHandle); - renderTargetViewHandle.ptr += rtvDescriptorSize; + ASSERT_SUCCESS(d3d12Device->CreateCommittedResource( + &dsvHeapProperties, + D3D12_HEAP_FLAG_NONE, + &dsvDesc, + D3D12_RESOURCE_STATE_DEPTH_WRITE, + &dsvClear, + IID_PPV_ARGS(&depthStencilResources[n]))); } } @@ -147,9 +168,7 @@ namespace utils { backend::d3d12::NextSerial(backendDevice); } - D3D12_CPU_DESCRIPTOR_HANDLE renderTargetViewHandle = renderTargetViewHeap->GetCPUDescriptorHandleForHeapStart(); - renderTargetViewHandle.ptr += rtvDescriptorSize * renderTargetIndex; - backend::d3d12::SetNextRenderTargetDescriptor(backendDevice, renderTargetViewHandle); + backend::d3d12::SetNextTexture(backendDevice, renderTargetResources[renderTargetIndex], depthStencilResources[renderTargetIndex]); } void SwapBuffers() override { @@ -198,9 +217,7 @@ namespace utils { lastSerialRenderTargetWasUsed[renderTargetIndex] = backend::d3d12::GetSerial(backendDevice); // Tell the backend to render to the current render target - D3D12_CPU_DESCRIPTOR_HANDLE renderTargetViewHandle = renderTargetViewHeap->GetCPUDescriptorHandleForHeapStart(); - renderTargetViewHandle.ptr += rtvDescriptorSize * renderTargetIndex; - backend::d3d12::SetNextRenderTargetDescriptor(backendDevice, renderTargetViewHandle); + backend::d3d12::SetNextTexture(backendDevice, renderTargetResources[renderTargetIndex], depthStencilResources[renderTargetIndex]); } private: @@ -214,9 +231,8 @@ namespace utils { ComPtr d3d12Device; ComPtr commandQueue; ComPtr swapChain; - ComPtr renderTargetViewHeap; ComPtr renderTargetResources[kFrameCount]; - uint32_t rtvDescriptorSize; + ComPtr depthStencilResources[kFrameCount]; // Frame synchronization. Updated every frame uint32_t renderTargetIndex;