Skip to content

Commit

Permalink
[D3D11] Notify all binding tables when resources are released (fixes #…
Browse files Browse the repository at this point in the history
…126).

- Evict all bindings from binding tables when buffer, texture, or render-target is released.
- Keep reference to state manager of all deferred device contexts so they can be notified as well.
- Updated ResourceBinding unit test to delete and re-create resources intermittently.
  • Loading branch information
LukasBanana committed Aug 14, 2024
1 parent 2232eb6 commit 2a63951
Show file tree
Hide file tree
Showing 7 changed files with 215 additions and 107 deletions.
6 changes: 6 additions & 0 deletions sources/Renderer/Direct3D11/Command/D3D11CommandContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,12 @@ class D3D11CommandContext
return context_.Get();
}

// Returns a pointer to the state manager for this command context.
inline D3D11StateManager* GetStateManagerPtr() const
{
return stateMngr_.get();
}

// Returns the state manager for this command context.
inline D3D11StateManager& GetStateManager() const
{
Expand Down
38 changes: 22 additions & 16 deletions sources/Renderer/Direct3D11/Command/D3D11PrimaryCommandBuffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,28 +44,19 @@ class D3D11PrimaryCommandBuffer final : public D3D11CommandBuffer
return commandList_.Get();
}

private:

void ClearWithIntermediateUAV(ID3D11Buffer* buffer, UINT offset, UINT size, const UINT (&valuesVec4)[4]);

// Creates a copy of this buffer as ByteAddressBuffer; 'size' must be a multiple of 4.
void CreateByteAddressBufferR32Typeless(
ID3D11Device* device,
ID3D11DeviceContext* context,
ID3D11Buffer** bufferOutput,
ID3D11ShaderResourceView** srvOutput,
ID3D11UnorderedAccessView** uavOutput,
UINT size,
D3D11_USAGE usage = D3D11_USAGE_DEFAULT
);

// Returns the native D3D11 device context.
inline ID3D11DeviceContext* GetNative() const
{
return context_.GetNative();
}

// Returns the state manager for this command context.
// Returns a pointer to the state manager for this command buffer.
inline D3D11StateManager* GetStateManagerPtr() const
{
return context_.GetStateManagerPtr();
}

// Returns the state manager for this command buffer.
inline D3D11StateManager& GetStateManager() const
{
return context_.GetStateManager();
Expand All @@ -77,6 +68,21 @@ class D3D11PrimaryCommandBuffer final : public D3D11CommandBuffer
return context_.GetBindingTable();
}

private:

void ClearWithIntermediateUAV(ID3D11Buffer* buffer, UINT offset, UINT size, const UINT (&valuesVec4)[4]);

// Creates a copy of this buffer as ByteAddressBuffer; 'size' must be a multiple of 4.
void CreateByteAddressBufferR32Typeless(
ID3D11Device* device,
ID3D11DeviceContext* context,
ID3D11Buffer** bufferOutput,
ID3D11ShaderResourceView** srvOutput,
ID3D11UnorderedAccessView** uavOutput,
UINT size,
D3D11_USAGE usage = D3D11_USAGE_DEFAULT
);

private:

// Device object to create on-demand objects like temporary SRVs and UAVs
Expand Down
41 changes: 41 additions & 0 deletions sources/Renderer/Direct3D11/D3D11RenderSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -126,13 +126,32 @@ CommandBuffer* D3D11RenderSystem::CreateCommandBuffer(const CommandBufferDescrip
/* Create state manager dedicated to deferred context */
std::shared_ptr<D3D11StateManager> deferredStateMngr = std::make_shared<D3D11StateManager>(device_.Get(), deferredContext);

/* Store references to unique state manager - we need to notify all binding tables on resource release */
deferredStateMngrRefs_.push_back(deferredStateMngr.get());

/* Create command buffer with deferred context and dedicated state manager */
return commandBuffers_.emplace<D3D11PrimaryCommandBuffer>(device_.Get(), deferredContext, std::move(deferredStateMngr), commandBufferDesc);
}
}

void D3D11RenderSystem::Release(CommandBuffer& commandBuffer)
{
auto& commandBufferD3D = LLGL_CAST(D3D11CommandBuffer, commandBuffer);
if (!commandBufferD3D.IsSecondaryCmdBuffer())
{
/* If this is command buffer has a unique state manager, remove it from the list of deferred state managers */
auto& primaryCmdBufferD3D = LLGL_CAST(D3D11PrimaryCommandBuffer, commandBufferD3D);
if (primaryCmdBufferD3D.GetStateManagerPtr() != stateMngr_.get())
{
RemoveFromListIf(
deferredStateMngrRefs_,
[stateMngr = primaryCmdBufferD3D.GetStateManagerPtr()](D3D11StateManager* entry) -> bool
{
return (entry == stateMngr);
}
);
}
}
commandBuffers_.erase(&commandBuffer);
}

Expand All @@ -155,6 +174,8 @@ BufferArray* D3D11RenderSystem::CreateBufferArray(std::uint32_t numBuffers, Buff

void D3D11RenderSystem::Release(Buffer& buffer)
{
auto& bufferD3D = LLGL_CAST(D3D11Buffer&, buffer);
NotifyBindingTablesOnRelease(bufferD3D.GetBindingLocator());
buffers_.erase(&buffer);
}

Expand Down Expand Up @@ -212,6 +233,8 @@ Texture* D3D11RenderSystem::CreateTexture(const TextureDescriptor& textureDesc,

void D3D11RenderSystem::Release(Texture& texture)
{
auto& textureD3D = LLGL_CAST(D3D11Texture&, texture);
NotifyBindingTablesOnRelease(textureD3D.GetBindingLocator());
textures_.erase(&texture);
}

Expand Down Expand Up @@ -377,6 +400,11 @@ RenderTarget* D3D11RenderSystem::CreateRenderTarget(const RenderTargetDescriptor

void D3D11RenderSystem::Release(RenderTarget& renderTarget)
{
auto& renderTargetD3D = LLGL_CAST(D3D11RenderTarget&, renderTarget);
const D3D11RenderTargetHandles& rtHandles = renderTargetD3D.GetRenderTargetHandles();
NotifyBindingTablesOnRelease(rtHandles.GetDepthStencilLocator());
for_range(i, rtHandles.GetNumRenderTargetViews())
NotifyBindingTablesOnRelease(rtHandles.GetRenderTargetLocators()[i]);
renderTargets_.erase(&renderTarget);
}

Expand Down Expand Up @@ -1097,6 +1125,19 @@ bool D3D11RenderSystem::CheckFactoryFeatureSupport(DXGI_FEATURE feature) const

#endif

void D3D11RenderSystem::NotifyBindingTablesOnRelease(D3D11BindingLocator* locator)
{
if (locator != nullptr)
{
/* Notify state manager that is shared across the primary D3D device context */
stateMngr_->GetBindingTable().NotifyResourceRelease(locator);

/* Notify state managers for all deferred device contexts */
for (D3D11StateManager* deferredStateMngr : deferredStateMngrRefs_)
deferredStateMngr->GetBindingTable().NotifyResourceRelease(locator);
}
}


} // /namespace LLGL

Expand Down
3 changes: 3 additions & 0 deletions sources/Renderer/Direct3D11/D3D11RenderSystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,8 @@ class D3D11RenderSystem final : public RenderSystem
bool CheckFactoryFeatureSupport(DXGI_FEATURE feature) const;
#endif

void NotifyBindingTablesOnRelease(D3D11BindingLocator* locator);

private:

/* ----- Common objects ----- */
Expand Down Expand Up @@ -164,6 +166,7 @@ class D3D11RenderSystem final : public RenderSystem
bool tearingSupported_ = false;

std::shared_ptr<D3D11StateManager> stateMngr_;
std::vector<D3D11StateManager*> deferredStateMngrRefs_;

/* ----- Hardware object containers ----- */

Expand Down
12 changes: 10 additions & 2 deletions sources/Renderer/Direct3D11/RenderState/D3D11BindingTable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,7 @@ void D3D11BindingTable::SetRenderTargets(

void D3D11BindingTable::ClearState()
{
/* Clear binding locators from all tables */
ClearBindingLocators(vb_);
ClearBindingLocators(ib_);
ClearBindingLocators(srvVS_);
Expand Down Expand Up @@ -279,16 +280,23 @@ void D3D11BindingTable::FlushOutputMergerUAVs()
}
}

void D3D11BindingTable::NotifyResourceRelease(D3D11BindingLocator* locator)
{
/* When a resource is about to be released, evict all of its bindings from this binding table */
EvictAllBindings(locator);
}


/*
* ======= Private: =======
*/

static void* const g_nullArray[D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT] = {};

template <typename T>
static T* const* GetNullPointerArray()
{
static void* const nullArray[D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT] = {};
return reinterpret_cast<T* const*>(nullArray);
return reinterpret_cast<T* const*>(g_nullArray);
}

void D3D11BindingTable::InsertInput(D3D11BindingLocator** container, D3D11BindingLocator::D3DInputs input, UINT slot, D3D11BindingLocator* locator)
Expand Down
4 changes: 4 additions & 0 deletions sources/Renderer/Direct3D11/RenderState/D3D11BindingTable.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,11 +99,15 @@ class D3D11BindingTable
D3D11BindingLocator* depthStencilLocators
);

// Clears the binding table state but doesn't perform any operations on the D3D device context.
void ClearState();

// Binds all pending output merger UAVs to the device context if they have previosuly changed.
void FlushOutputMergerUAVs();

// Notifies the binding table that a resource, represented by the specified binding locator, is about to be released.
void NotifyResourceRelease(D3D11BindingLocator* locator);

private:

using D3D11BindingLocatorIterator = SparseForwardIterator<D3D11BindingLocator*>;
Expand Down
Loading

0 comments on commit 2a63951

Please sign in to comment.