diff --git a/examples/D3D12Binding.cpp b/examples/D3D12Binding.cpp index 642abae2c6..1c796b9288 100644 --- a/examples/D3D12Binding.cpp +++ b/examples/D3D12Binding.cpp @@ -37,7 +37,7 @@ namespace d3d12 { void NextSerial(nxtDevice device); void ExecuteCommandLists(nxtDevice device, std::initializer_list commandLists); void WaitForSerial(nxtDevice device, uint64_t serial); - ComPtr ReserveCommandAllocator(nxtDevice device); + void OpenCommandList(nxtDevice device, ComPtr* commandList); } } @@ -130,14 +130,7 @@ class D3D12Binding : public BackendBinding { // Transition the first frame to be a render target { - ComPtr commandAllocator = backend::d3d12::ReserveCommandAllocator(backendDevice); - ASSERT_SUCCESS(d3d12Device->CreateCommandList( - 0, - D3D12_COMMAND_LIST_TYPE_DIRECT, - commandAllocator.Get(), - nullptr, - IID_PPV_ARGS(&commandList) - )); + backend::d3d12::OpenCommandList(backendDevice, &commandList); D3D12_RESOURCE_BARRIER resourceBarrier; resourceBarrier.Transition.pResource = renderTargetResources[renderTargetIndex].Get(); @@ -162,8 +155,7 @@ class D3D12Binding : public BackendBinding { void SwapBuffers() override { // Transition current frame's render target for presenting { - ComPtr commandAllocator = backend::d3d12::ReserveCommandAllocator(backendDevice); - ASSERT_SUCCESS(commandList->Reset(commandAllocator.Get(), nullptr)); + backend::d3d12::OpenCommandList(backendDevice, &commandList); D3D12_RESOURCE_BARRIER resourceBarrier; resourceBarrier.Transition.pResource = renderTargetResources[renderTargetIndex].Get(); resourceBarrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET; @@ -181,8 +173,7 @@ class D3D12Binding : public BackendBinding { // Transition last frame's render target back to being a render target { - ComPtr commandAllocator = backend::d3d12::ReserveCommandAllocator(backendDevice); - ASSERT_SUCCESS(commandList->Reset(commandAllocator.Get(), nullptr)); + backend::d3d12::OpenCommandList(backendDevice, &commandList); D3D12_RESOURCE_BARRIER resourceBarrier; resourceBarrier.Transition.pResource = renderTargetResources[previousRenderTargetIndex].Get(); resourceBarrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT; diff --git a/src/backend/d3d12/CommandAllocatorManager.h b/src/backend/d3d12/CommandAllocatorManager.h index 6569ede051..7c04db3c96 100644 --- a/src/backend/d3d12/CommandAllocatorManager.h +++ b/src/backend/d3d12/CommandAllocatorManager.h @@ -30,8 +30,8 @@ namespace d3d12 { public: CommandAllocatorManager(Device* device); - // A CommandAllocator that is reserved must be used before the next Device::Tick where the next serial has completed on the GPU - // at this time, the CommandAllocator will be reset + // A CommandAllocator that is reserved must be used on the next ExecuteCommandLists + // otherwise its commands may be reset before execution has completed on the GPU ComPtr ReserveCommandAllocator(); void ResetCompletedAllocators(uint64_t lastCompletedSerial); diff --git a/src/backend/d3d12/D3D12Backend.cpp b/src/backend/d3d12/D3D12Backend.cpp index 9447d710a7..ad6fe58cbd 100644 --- a/src/backend/d3d12/D3D12Backend.cpp +++ b/src/backend/d3d12/D3D12Backend.cpp @@ -68,9 +68,9 @@ namespace d3d12 { backendDevice->WaitForSerial(serial); } - ComPtr ReserveCommandAllocator(nxtDevice device) { + void OpenCommandList(nxtDevice device, ComPtr* commandList) { Device* backendDevice = reinterpret_cast(device); - return backendDevice->GetCommandAllocatorManager()->ReserveCommandAllocator(); + return backendDevice->OpenCommandList(commandList); } void ASSERT_SUCCESS(HRESULT hr) { @@ -81,23 +81,13 @@ namespace d3d12 { : d3d12Device(d3d12Device), commandAllocatorManager(new CommandAllocatorManager(this)), resourceAllocator(new ResourceAllocator(this)), - resourceUploader(new ResourceUploader(this)), - pendingCommands{ commandAllocatorManager->ReserveCommandAllocator() } { + resourceUploader(new ResourceUploader(this)) { D3D12_COMMAND_QUEUE_DESC queueDesc = {}; queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE; queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; ASSERT_SUCCESS(d3d12Device->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&commandQueue))); - ASSERT_SUCCESS(d3d12Device->CreateCommandList( - 0, - D3D12_COMMAND_LIST_TYPE_DIRECT, - pendingCommands.commandAllocator.Get(), - nullptr, - IID_PPV_ARGS(&pendingCommands.commandList) - )); - pendingCommands.open = true; - ASSERT_SUCCESS(d3d12Device->CreateFence(serial, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&fence))); fenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr); ASSERT(fenceEvent != nullptr); @@ -114,10 +104,6 @@ namespace d3d12 { return commandQueue; } - CommandAllocatorManager* Device::GetCommandAllocatorManager() { - return commandAllocatorManager; - } - ResourceAllocator* Device::GetResourceAllocator() { return resourceAllocator; } @@ -126,11 +112,25 @@ namespace d3d12 { return resourceUploader; } + void Device::OpenCommandList(ComPtr* commandList) { + ComPtr &cmdList = *commandList; + if (!cmdList) { + ASSERT_SUCCESS(d3d12Device->CreateCommandList( + 0, + D3D12_COMMAND_LIST_TYPE_DIRECT, + commandAllocatorManager->ReserveCommandAllocator().Get(), + nullptr, + IID_PPV_ARGS(&cmdList) + )); + } else { + ASSERT_SUCCESS(cmdList->Reset(commandAllocatorManager->ReserveCommandAllocator().Get(), nullptr)); + } + } + ComPtr Device::GetPendingCommandList() { // Callers of GetPendingCommandList do so to record commands. Only reserve a command allocator when it is needed so we don't submit empty command lists if (!pendingCommands.open) { - pendingCommands.commandAllocator = commandAllocatorManager->ReserveCommandAllocator(); - ASSERT_SUCCESS(pendingCommands.commandList->Reset(pendingCommands.commandAllocator.Get(), nullptr)); + OpenCommandList(&pendingCommands.commandList); pendingCommands.open = true; } return pendingCommands.commandList; diff --git a/src/backend/d3d12/D3D12Backend.h b/src/backend/d3d12/D3D12Backend.h index 6d3fb3e4bc..470851f2be 100644 --- a/src/backend/d3d12/D3D12Backend.h +++ b/src/backend/d3d12/D3D12Backend.h @@ -113,10 +113,10 @@ namespace d3d12 { ComPtr GetD3D12Device(); ComPtr GetCommandQueue(); - CommandAllocatorManager* GetCommandAllocatorManager(); ResourceAllocator* GetResourceAllocator(); ResourceUploader* GetResourceUploader(); + void OpenCommandList(ComPtr* commandList); ComPtr GetPendingCommandList(); D3D12_CPU_DESCRIPTOR_HANDLE GetCurrentRenderTargetDescriptor(); @@ -145,7 +145,6 @@ namespace d3d12 { ResourceUploader* resourceUploader; struct PendingCommandList { - ComPtr commandAllocator; ComPtr commandList; bool open = false; } pendingCommands; diff --git a/src/backend/d3d12/QueueD3D12.cpp b/src/backend/d3d12/QueueD3D12.cpp index 1e2de58c9d..a03162a151 100644 --- a/src/backend/d3d12/QueueD3D12.cpp +++ b/src/backend/d3d12/QueueD3D12.cpp @@ -15,7 +15,6 @@ #include "QueueD3D12.h" #include "D3D12Backend.h" -#include "CommandAllocatorManager.h" #include "CommandBufferD3D12.h" namespace backend { @@ -23,25 +22,12 @@ namespace d3d12 { Queue::Queue(Device* device, QueueBuilder* builder) : QueueBase(builder), device(device) { - - // TODO(enga@google.com): We don't need this allocator, but it's needed for command list initialization. Is there a better way to do this? - // Is CommandList creation expensive or can it be done every Queue::Submit? - ComPtr temporaryCommandAllocator; - ASSERT_SUCCESS(device->GetD3D12Device()->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&temporaryCommandAllocator))); - ASSERT_SUCCESS(device->GetD3D12Device()->CreateCommandList( - 0, - D3D12_COMMAND_LIST_TYPE_DIRECT, - temporaryCommandAllocator.Get(), - nullptr, - IID_PPV_ARGS(&commandList) - )); - ASSERT_SUCCESS(commandList->Close()); } void Queue::Submit(uint32_t numCommands, CommandBuffer* const * commands) { device->Tick(); - ASSERT_SUCCESS(commandList->Reset(device->GetCommandAllocatorManager()->ReserveCommandAllocator().Get(), nullptr)); + device->OpenCommandList(&commandList); for (uint32_t i = 0; i < numCommands; ++i) { commands[i]->FillCommands(commandList); } diff --git a/src/backend/d3d12/ResourceAllocator.h b/src/backend/d3d12/ResourceAllocator.h index 61a1ac7a11..98e33fe46a 100644 --- a/src/backend/d3d12/ResourceAllocator.h +++ b/src/backend/d3d12/ResourceAllocator.h @@ -19,8 +19,6 @@ #include "common/SerialQueue.h" -#include - namespace backend { namespace d3d12 {