D3D12: Keep a reference to pipelines until unused

Previously we would remove the reference to pipelines in the destructor
of the d3d12::*Pipeline objects which could cause the D3D12 pipeline
state to be destroyed while still used by in-flight commands. Add a
global queue of ComPtrs to keep alive in the d3d12::Device to fix this.
This commit is contained in:
Corentin Wallez 2018-03-02 11:07:07 -05:00 committed by Corentin Wallez
parent 57f7bc750a
commit cf0ac7570d
6 changed files with 32 additions and 3 deletions

View File

@ -24,7 +24,7 @@
namespace backend { namespace d3d12 { namespace backend { namespace d3d12 {
ComputePipeline::ComputePipeline(ComputePipelineBuilder* builder) ComputePipeline::ComputePipeline(ComputePipelineBuilder* builder)
: ComputePipelineBase(builder) { : ComputePipelineBase(builder), mDevice(ToBackend(builder->GetDevice())) {
uint32_t compileFlags = 0; uint32_t compileFlags = 0;
#if defined(_DEBUG) #if defined(_DEBUG)
// Enable better shader debugging with the graphics debugging tools. // Enable better shader debugging with the graphics debugging tools.
@ -57,6 +57,10 @@ namespace backend { namespace d3d12 {
IID_PPV_ARGS(&mPipelineState)); IID_PPV_ARGS(&mPipelineState));
} }
ComputePipeline::~ComputePipeline() {
mDevice->ReferenceUntilUnused(mPipelineState);
}
ComPtr<ID3D12PipelineState> ComputePipeline::GetPipelineState() { ComPtr<ID3D12PipelineState> ComputePipeline::GetPipelineState() {
return mPipelineState; return mPipelineState;
} }

View File

@ -21,14 +21,18 @@
namespace backend { namespace d3d12 { namespace backend { namespace d3d12 {
class Device;
class ComputePipeline : public ComputePipelineBase { class ComputePipeline : public ComputePipelineBase {
public: public:
ComputePipeline(ComputePipelineBuilder* builder); ComputePipeline(ComputePipelineBuilder* builder);
~ComputePipeline();
ComPtr<ID3D12PipelineState> GetPipelineState(); ComPtr<ID3D12PipelineState> GetPipelineState();
private: private:
ComPtr<ID3D12PipelineState> mPipelineState; ComPtr<ID3D12PipelineState> mPipelineState;
Device* mDevice = nullptr;
}; };
}} // namespace backend::d3d12 }} // namespace backend::d3d12

View File

@ -149,6 +149,8 @@ namespace backend { namespace d3d12 {
NextSerial(); NextSerial();
WaitForSerial(currentSerial); // Wait for all in-flight commands to finish executing WaitForSerial(currentSerial); // Wait for all in-flight commands to finish executing
TickImpl(); // Call tick one last time so resources are cleaned up TickImpl(); // Call tick one last time so resources are cleaned up
ASSERT(mUsedComObjectRefs.Empty());
delete mCommandAllocatorManager; delete mCommandAllocatorManager;
delete mDescriptorHeapAllocator; delete mDescriptorHeapAllocator;
delete mMapReadRequestTracker; delete mMapReadRequestTracker;
@ -214,6 +216,7 @@ namespace backend { namespace d3d12 {
mCommandAllocatorManager->Tick(lastCompletedSerial); mCommandAllocatorManager->Tick(lastCompletedSerial);
mDescriptorHeapAllocator->Tick(lastCompletedSerial); mDescriptorHeapAllocator->Tick(lastCompletedSerial);
mMapReadRequestTracker->Tick(lastCompletedSerial); mMapReadRequestTracker->Tick(lastCompletedSerial);
mUsedComObjectRefs.ClearUpTo(lastCompletedSerial);
ExecuteCommandLists({}); ExecuteCommandLists({});
NextSerial(); NextSerial();
} }
@ -234,6 +237,10 @@ namespace backend { namespace d3d12 {
} }
} }
void Device::ReferenceUntilUnused(ComPtr<IUnknown> object) {
mUsedComObjectRefs.Enqueue(object, mSerial);
}
void Device::ExecuteCommandLists(std::initializer_list<ID3D12CommandList*> commandLists) { void Device::ExecuteCommandLists(std::initializer_list<ID3D12CommandList*> commandLists) {
// If there are pending commands, prepend them to ExecuteCommandLists // If there are pending commands, prepend them to ExecuteCommandLists
if (mPendingCommands.open) { if (mPendingCommands.open) {

View File

@ -21,8 +21,8 @@
#include "backend/Device.h" #include "backend/Device.h"
#include "backend/RenderPass.h" #include "backend/RenderPass.h"
#include "backend/ToBackend.h" #include "backend/ToBackend.h"
#include "backend/d3d12/d3d12_platform.h" #include "backend/d3d12/d3d12_platform.h"
#include "common/SerialQueue.h"
namespace backend { namespace d3d12 { namespace backend { namespace d3d12 {
@ -127,6 +127,8 @@ namespace backend { namespace d3d12 {
void NextSerial(); void NextSerial();
void WaitForSerial(uint64_t serial); void WaitForSerial(uint64_t serial);
void ReferenceUntilUnused(ComPtr<IUnknown> object);
void ExecuteCommandLists(std::initializer_list<ID3D12CommandList*> commandLists); void ExecuteCommandLists(std::initializer_list<ID3D12CommandList*> commandLists);
private: private:
@ -149,6 +151,8 @@ namespace backend { namespace d3d12 {
ComPtr<ID3D12GraphicsCommandList> commandList; ComPtr<ID3D12GraphicsCommandList> commandList;
bool open = false; bool open = false;
} mPendingCommands; } mPendingCommands;
SerialQueue<ComPtr<IUnknown>> mUsedComObjectRefs;
}; };
class RenderPass : public RenderPassBase { class RenderPass : public RenderPassBase {

View File

@ -64,7 +64,8 @@ namespace backend { namespace d3d12 {
RenderPipeline::RenderPipeline(RenderPipelineBuilder* builder) RenderPipeline::RenderPipeline(RenderPipelineBuilder* builder)
: RenderPipelineBase(builder), : RenderPipelineBase(builder),
mD3d12PrimitiveTopology(D3D12PrimitiveTopology(GetPrimitiveTopology())) { mD3d12PrimitiveTopology(D3D12PrimitiveTopology(GetPrimitiveTopology())),
mDevice(ToBackend(builder->GetDevice())) {
uint32_t compileFlags = 0; uint32_t compileFlags = 0;
#if defined(_DEBUG) #if defined(_DEBUG)
// Enable better shader debugging with the graphics debugging tools. // Enable better shader debugging with the graphics debugging tools.
@ -171,6 +172,10 @@ namespace backend { namespace d3d12 {
&descriptor, IID_PPV_ARGS(&mPipelineState))); &descriptor, IID_PPV_ARGS(&mPipelineState)));
} }
RenderPipeline::~RenderPipeline() {
mDevice->ReferenceUntilUnused(mPipelineState);
}
D3D12_PRIMITIVE_TOPOLOGY RenderPipeline::GetD3D12PrimitiveTopology() const { D3D12_PRIMITIVE_TOPOLOGY RenderPipeline::GetD3D12PrimitiveTopology() const {
return mD3d12PrimitiveTopology; return mD3d12PrimitiveTopology;
} }

View File

@ -21,9 +21,12 @@
namespace backend { namespace d3d12 { namespace backend { namespace d3d12 {
class Device;
class RenderPipeline : public RenderPipelineBase { class RenderPipeline : public RenderPipelineBase {
public: public:
RenderPipeline(RenderPipelineBuilder* builder); RenderPipeline(RenderPipelineBuilder* builder);
~RenderPipeline();
D3D12_PRIMITIVE_TOPOLOGY GetD3D12PrimitiveTopology() const; D3D12_PRIMITIVE_TOPOLOGY GetD3D12PrimitiveTopology() const;
ComPtr<ID3D12PipelineState> GetPipelineState(); ComPtr<ID3D12PipelineState> GetPipelineState();
@ -31,6 +34,8 @@ namespace backend { namespace d3d12 {
private: private:
D3D12_PRIMITIVE_TOPOLOGY mD3d12PrimitiveTopology; D3D12_PRIMITIVE_TOPOLOGY mD3d12PrimitiveTopology;
ComPtr<ID3D12PipelineState> mPipelineState; ComPtr<ID3D12PipelineState> mPipelineState;
Device* mDevice = nullptr;
}; };
}} // namespace backend::d3d12 }} // namespace backend::d3d12