Skip to content

Commit

Permalink
Added IRenderDevice::CreateDeferredContext() method (API256007)
Browse files Browse the repository at this point in the history
  • Loading branch information
TheMostDiligent committed Feb 21, 2025
1 parent 70bdd5b commit b07a92c
Show file tree
Hide file tree
Showing 22 changed files with 158 additions and 88 deletions.
3 changes: 2 additions & 1 deletion Graphics/Archiver/include/SerializationDeviceImpl.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2019-2024 Diligent Graphics LLC
* Copyright 2019-2025 Diligent Graphics LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -72,6 +72,7 @@ class SerializationDeviceImpl final : public RenderDeviceBase<SerializationEngin
UNSUPPORTED_METHOD(void, CreatePipelineResourceSignature, const PipelineResourceSignatureDesc& Desc, IPipelineResourceSignature** ppSignature)
UNSUPPORTED_METHOD(void, CreateDeviceMemory, const DeviceMemoryCreateInfo& CreateInfo, IDeviceMemory** ppMemory)
UNSUPPORTED_METHOD(void, CreatePipelineStateCache, const PipelineStateCacheCreateInfo& CreateInfo, IPipelineStateCache** ppPSOCache)
UNSUPPORTED_METHOD(void, CreateDeferredContext, IDeviceContext** ppContext)
UNSUPPORTED_METHOD(void, IdleGPU)
UNSUPPORTED_METHOD(void, ReleaseStaleResources, bool ForceRelease)
// clang-format on
Expand Down
83 changes: 65 additions & 18 deletions Graphics/GraphicsEngine/include/RenderDeviceBase.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include <thread>
#include <vector>
#include <unordered_set>
#include <mutex>

#include "RenderDevice.h"
#include "DeviceObjectBase.hpp"
Expand Down Expand Up @@ -308,13 +309,6 @@ class RenderDeviceBase : public ObjectBase<typename EngineImplTraits::RenderDevi
m_wpImmediateContexts[Ctx] = pImmediateContext;
}

/// Set weak reference to the deferred context
void SetDeferredContext(size_t Ctx, DeviceContextImplType* pDeferredCtx)
{
VERIFY(m_wpDeferredContexts[Ctx].Lock() == nullptr, "Deferred context has already been set");
m_wpDeferredContexts[Ctx] = pDeferredCtx;
}

/// Returns the number of immediate contexts
size_t GetNumImmediateContexts() const
{
Expand All @@ -324,11 +318,23 @@ class RenderDeviceBase : public ObjectBase<typename EngineImplTraits::RenderDevi
/// Returns number of deferred contexts
size_t GetNumDeferredContexts() const
{
std::lock_guard<std::mutex> Guard{m_DeferredCtxMtx};
return m_wpDeferredContexts.size();
}

RefCntAutoPtr<DeviceContextImplType> GetImmediateContext(size_t Ctx) { return m_wpImmediateContexts[Ctx].Lock(); }
RefCntAutoPtr<DeviceContextImplType> GetDeferredContext(size_t Ctx) { return m_wpDeferredContexts[Ctx].Lock(); }
RefCntAutoPtr<DeviceContextImplType> GetImmediateContext(size_t Ctx)
{
return Ctx < m_wpImmediateContexts.size() ?
m_wpImmediateContexts[Ctx].Lock() :
RefCntAutoPtr<DeviceContextImplType>{};
}
RefCntAutoPtr<DeviceContextImplType> GetDeferredContext(size_t Ctx)
{
std::lock_guard<std::mutex> Guard{m_DeferredCtxMtx};
return Ctx < m_wpDeferredContexts.size() ?
m_wpDeferredContexts[Ctx].Lock() :
RefCntAutoPtr<DeviceContextImplType>{};
}

FixedBlockMemoryAllocator& GetTexViewObjAllocator() { return m_TexViewObjAllocator; }
FixedBlockMemoryAllocator& GetBuffViewObjAllocator() { return m_BuffViewObjAllocator; }
Expand Down Expand Up @@ -454,11 +460,11 @@ class RenderDeviceBase : public ObjectBase<typename EngineImplTraits::RenderDevi
const std::string ObjectDescString = GetObjectDescString(Desc);
if (!ObjectDescString.empty())
{
LOG_ERROR("Failed to create ", ObjectTypeName, " object '", (Desc.Name ? Desc.Name : ""), "'\n", ObjectDescString);
LOG_ERROR("Failed to create ", ObjectTypeName, " '", (Desc.Name ? Desc.Name : ""), "'\n", ObjectDescString);
}
else
{
LOG_ERROR("Failed to create ", ObjectTypeName, " object '", (Desc.Name ? Desc.Name : ""), "'");
LOG_ERROR("Failed to create ", ObjectTypeName, " '", (Desc.Name ? Desc.Name : ""), "'");
}
}
}
Expand Down Expand Up @@ -549,7 +555,7 @@ class RenderDeviceBase : public ObjectBase<typename EngineImplTraits::RenderDevi
template <typename... ExtraArgsType>
void CreateRenderPassImpl(IRenderPass** ppRenderPass, const RenderPassDesc& Desc, const ExtraArgsType&... ExtraArgs)
{
CreateDeviceObject("RenderPass", Desc, ppRenderPass,
CreateDeviceObject("Render Pass", Desc, ppRenderPass,
[&]() //
{
RenderPassImplType* pRenderPassImpl = NEW_RC_OBJ(m_RenderPassAllocator, "Render instance", RenderPassImplType)(static_cast<RenderDeviceImplType*>(this), Desc, ExtraArgs...);
Expand All @@ -571,7 +577,7 @@ class RenderDeviceBase : public ObjectBase<typename EngineImplTraits::RenderDevi
template <typename... ExtraArgsType>
void CreateBLASImpl(IBottomLevelAS** ppBLAS, const BottomLevelASDesc& Desc, const ExtraArgsType&... ExtraArgs)
{
CreateDeviceObject("BottomLevelAS", Desc, ppBLAS,
CreateDeviceObject("Bottom-level AS", Desc, ppBLAS,
[&]() //
{
BottomLevelASImplType* pBottomLevelASImpl = NEW_RC_OBJ(m_BLASAllocator, "BottomLevelAS instance", BottomLevelASImplType)(static_cast<RenderDeviceImplType*>(this), Desc, ExtraArgs...);
Expand All @@ -582,7 +588,7 @@ class RenderDeviceBase : public ObjectBase<typename EngineImplTraits::RenderDevi
template <typename... ExtraArgsType>
void CreateTLASImpl(ITopLevelAS** ppTLAS, const TopLevelASDesc& Desc, const ExtraArgsType&... ExtraArgs)
{
CreateDeviceObject("TopLevelAS", Desc, ppTLAS,
CreateDeviceObject("Top-level AS", Desc, ppTLAS,
[&]() //
{
TopLevelASImplType* pTopLevelASImpl = NEW_RC_OBJ(m_TLASAllocator, "TopLevelAS instance", TopLevelASImplType)(static_cast<RenderDeviceImplType*>(this), Desc, ExtraArgs...);
Expand All @@ -592,7 +598,7 @@ class RenderDeviceBase : public ObjectBase<typename EngineImplTraits::RenderDevi

void CreateSBTImpl(IShaderBindingTable** ppSBT, const ShaderBindingTableDesc& Desc)
{
CreateDeviceObject("ShaderBindingTable", Desc, ppSBT,
CreateDeviceObject("Shader Binding Table", Desc, ppSBT,
[&]() //
{
ShaderBindingTableImplType* pSBTImpl = NEW_RC_OBJ(m_SBTAllocator, "ShaderBindingTable instance", ShaderBindingTableImplType)(static_cast<RenderDeviceImplType*>(this), Desc);
Expand All @@ -603,7 +609,7 @@ class RenderDeviceBase : public ObjectBase<typename EngineImplTraits::RenderDevi
template <typename... ExtraArgsType>
void CreatePipelineResourceSignatureImpl(IPipelineResourceSignature** ppSignature, const PipelineResourceSignatureDesc& Desc, const ExtraArgsType&... ExtraArgs)
{
CreateDeviceObject("PipelineResourceSignature", Desc, ppSignature,
CreateDeviceObject("Pipeline Resource Signature", Desc, ppSignature,
[&]() //
{
PipelineResourceSignatureImplType* pPRSImpl = NEW_RC_OBJ(m_PipeResSignAllocator, "PipelineResourceSignature instance", PipelineResourceSignatureImplType)(static_cast<RenderDeviceImplType*>(this), Desc, ExtraArgs...);
Expand All @@ -614,7 +620,7 @@ class RenderDeviceBase : public ObjectBase<typename EngineImplTraits::RenderDevi
template <typename... ExtraArgsType>
void CreateDeviceMemoryImpl(IDeviceMemory** ppMemory, const DeviceMemoryCreateInfo& MemCI, const ExtraArgsType&... ExtraArgs)
{
CreateDeviceObject("DeviceMemory", MemCI.Desc, ppMemory,
CreateDeviceObject("Device Memory", MemCI.Desc, ppMemory,
[&]() //
{
DeviceMemoryImplType* pDevMemImpl = NEW_RC_OBJ(m_MemObjAllocator, "DeviceMemory instance", DeviceMemoryImplType)(static_cast<RenderDeviceImplType*>(this), MemCI, ExtraArgs...);
Expand All @@ -624,14 +630,54 @@ class RenderDeviceBase : public ObjectBase<typename EngineImplTraits::RenderDevi

void CreatePipelineStateCacheImpl(IPipelineStateCache** ppCache, const PipelineStateCacheCreateInfo& PSOCacheCI)
{
CreateDeviceObject("PSOCache", PSOCacheCI.Desc, ppCache,
CreateDeviceObject("PSO Cache", PSOCacheCI.Desc, ppCache,
[&]() //
{
PipelineStateCacheImplType* pPSOCacheImpl = NEW_RC_OBJ(m_PSOCacheAllocator, "PSOCache instance", PipelineStateCacheImplType)(static_cast<RenderDeviceImplType*>(this), PSOCacheCI);
pPSOCacheImpl->QueryInterface(IID_PipelineStateCache, reinterpret_cast<IObject**>(ppCache));
});
}

template <typename... ExtraArgsType>
void CreateDeferredContextImpl(IDeviceContext** ppContext, const ExtraArgsType&... ExtraArgs)
{
std::lock_guard<std::mutex> Guard{m_DeferredCtxMtx};

Uint32 CtxIndex = 0;
while (CtxIndex < m_wpDeferredContexts.size() && m_wpDeferredContexts[CtxIndex].IsValid())
++CtxIndex;

const Uint32 ContextId = static_cast<Uint32>(GetNumImmediateContexts()) + CtxIndex;
const std::string CtxName = std::string{"Deferred context "} + std::to_string(CtxIndex) + " (ContextId: " + std::to_string(ContextId) + ")";
DeviceContextDesc Desc{
CtxName.c_str(),
COMMAND_QUEUE_TYPE_UNKNOWN,
true, // IsDeferred
ContextId,
};

CreateDeviceObject("Device context", Desc, ppContext,
[&]() //
{
DeviceContextImplType* pCtxImpl = NEW_RC_OBJ(GetRawAllocator(), "DeviceContext instance", DeviceContextImplType)(
static_cast<RenderDeviceImplType*>(this),
Desc,
ExtraArgs...);
pCtxImpl->QueryInterface(IID_DeviceContext, reinterpret_cast<IObject**>(ppContext));
});

if (*ppContext != nullptr)
{
if (CtxIndex >= m_wpDeferredContexts.size())
{
VERIFY_EXPR(CtxIndex == m_wpDeferredContexts.size());
m_wpDeferredContexts.resize(CtxIndex + 1);
}

m_wpDeferredContexts[CtxIndex] = static_cast<DeviceContextImplType*>(*ppContext);
}
}

protected:
RefCntAutoPtr<IEngineFactory> m_pEngineFactory;

Expand All @@ -651,6 +697,7 @@ class RenderDeviceBase : public ObjectBase<typename EngineImplTraits::RenderDevi
std::vector<RefCntWeakPtr<DeviceContextImplType>, STDAllocatorRawMem<RefCntWeakPtr<DeviceContextImplType>>> m_wpImmediateContexts;

/// Weak references to deferred contexts.
mutable std::mutex m_DeferredCtxMtx;
std::vector<RefCntWeakPtr<DeviceContextImplType>, STDAllocatorRawMem<RefCntWeakPtr<DeviceContextImplType>>> m_wpDeferredContexts;

IMemoryAllocator& m_RawMemAllocator; ///< Raw memory allocator
Expand Down
2 changes: 1 addition & 1 deletion Graphics/GraphicsEngine/interface/APIInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
/// \file
/// Diligent API information

#define DILIGENT_API_VERSION 256006
#define DILIGENT_API_VERSION 256007

#include "../../../Primitives/interface/BasicTypes.h"

Expand Down
2 changes: 2 additions & 0 deletions Graphics/GraphicsEngine/interface/GraphicsTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -3462,6 +3462,8 @@ struct EngineCreateInfo
/// IEngineFactoryD3D12::CreateDeviceAndContextsD3D12, and IEngineFactoryVk::CreateDeviceAndContextsVk)
/// starting at position max(1, NumImmediateContexts).
///
/// \remarks Additional deferred contexts may be created later by calling IRenderDevice::CreateDeferredContext().
///
/// \warning An application must manually call IDeviceContext::FinishFrame for
/// deferred contexts to let the engine release stale resources.
Uint32 NumDeferredContexts DEFAULT_INITIALIZER(0);
Expand Down
14 changes: 13 additions & 1 deletion Graphics/GraphicsEngine/interface/RenderDevice.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2019-2024 Diligent Graphics LLC
* Copyright 2019-2025 Diligent Graphics LLC
* Copyright 2015-2019 Egor Yusov
*
* Licensed under the Apache License, Version 2.0 (the "License");
Expand Down Expand Up @@ -53,6 +53,7 @@
#include "ShaderBindingTable.h"
#include "PipelineResourceSignature.h"
#include "DeviceMemory.h"
#include "DeviceContext.h"

#include "DepthStencilState.h"
#include "RasterizerState.h"
Expand Down Expand Up @@ -335,6 +336,15 @@ DILIGENT_BEGIN_INTERFACE(IRenderDevice, IObject)
IPipelineStateCache** ppPSOCache) PURE;


/// Creates a deferred context.

/// \param [out] ppContext - Address of the memory location where a pointer to the
/// deferred context interface will be written.
///
/// \remarks Deferred contexts are not supported in OpenGL and WebGPU backends.
VIRTUAL void METHOD(CreateDeferredContext)(THIS_
IDeviceContext** ppContext) PURE;

/// Returns the device information, see Diligent::RenderDeviceInfo for details.
VIRTUAL const RenderDeviceInfo REF METHOD(GetDeviceInfo)(THIS) CONST PURE;

Expand Down Expand Up @@ -452,6 +462,8 @@ DILIGENT_END_INTERFACE
# define IRenderDevice_CreateSBT(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateSBT, This, __VA_ARGS__)
# define IRenderDevice_CreatePipelineResourceSignature(This, ...) CALL_IFACE_METHOD(RenderDevice, CreatePipelineResourceSignature, This, __VA_ARGS__)
# define IRenderDevice_CreateDeviceMemory(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateDeviceMemory, This, __VA_ARGS__)
# define IRenderDevice_CreatePipelineStateCache(This, ...) CALL_IFACE_METHOD(RenderDevice, CreatePipelineStateCache, This, __VA_ARGS__)
# define IRenderDevice_CreateDeferredContext(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateDeferredContext, This, __VA_ARGS__)
# define IRenderDevice_GetAdapterInfo(This) CALL_IFACE_METHOD(RenderDevice, GetAdapterInfo, This)
# define IRenderDevice_GetDeviceInfo(This) CALL_IFACE_METHOD(RenderDevice, GetDeviceInfo, This)
# define IRenderDevice_GetTextureFormatInfo(This, ...) CALL_IFACE_METHOD(RenderDevice, GetTextureFormatInfo, This, __VA_ARGS__)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,9 @@ class DeviceContextD3D11Impl final : public DeviceContextBase<EngineD3D11ImplTra
using TDeviceContextBase = DeviceContextBase<EngineD3D11ImplTraits>;

DeviceContextD3D11Impl(IReferenceCounters* pRefCounters,
IMemoryAllocator& Allocator,
RenderDeviceD3D11Impl* pDevice,
ID3D11DeviceContext1* pd3d11DeviceContext,
const DeviceContextDesc& Desc);
const DeviceContextDesc& Desc,
ID3D11DeviceContext1* pd3d11DeviceContext);
virtual void DILIGENT_CALL_TYPE QueryInterface(const INTERFACE_ID& IID, IObject** ppInterface) override final;

/// Implementation of IDeviceContext::Begin() in Direct3D11 backend.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,9 @@ class RenderDeviceD3D11Impl final : public RenderDeviceD3DBase<EngineD3D11ImplTr
virtual void DILIGENT_CALL_TYPE CreatePipelineStateCache(const PipelineStateCacheCreateInfo& CreateInfo,
IPipelineStateCache** ppPSOCache) override final;

/// Implementation of IRenderDevice::CreateDeferredContext() in Direct3D11 backend.
virtual void DILIGENT_CALL_TYPE CreateDeferredContext(IDeviceContext** ppContext) override final;

/// Implementation of IRenderDeviceD3D11::GetD3D11Device() in Direct3D11 backend.
ID3D11Device* DILIGENT_CALL_TYPE GetD3D11Device() override final { return m_pd3d11Device; }

Expand Down
7 changes: 3 additions & 4 deletions Graphics/GraphicsEngineD3D11/src/DeviceContextD3D11Impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,18 +48,17 @@ namespace Diligent
{

DeviceContextD3D11Impl::DeviceContextD3D11Impl(IReferenceCounters* pRefCounters,
IMemoryAllocator& Allocator,
RenderDeviceD3D11Impl* pDevice,
ID3D11DeviceContext1* pd3d11DeviceContext,
const DeviceContextDesc& Desc) :
const DeviceContextDesc& Desc,
ID3D11DeviceContext1* pd3d11DeviceContext) :
// clang-format off
TDeviceContextBase
{
pRefCounters,
pDevice,
Desc
},
m_pd3d11DeviceContext {pd3d11DeviceContext },
m_pd3d11DeviceContext {pd3d11DeviceContext},
#ifdef DILIGENT_DEVELOPMENT
m_D3D11ValidationFlags{pDevice->GetProperties().D3D11ValidationFlags},
#endif
Expand Down
29 changes: 4 additions & 25 deletions Graphics/GraphicsEngineD3D11/src/EngineFactoryD3D11.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -389,14 +389,15 @@ void EngineFactoryD3D11Impl::AttachToD3D11Device(void* pd

RefCntAutoPtr<DeviceContextD3D11Impl> pDeviceContextD3D11{
NEW_RC_OBJ(RawAllocator, "DeviceContextD3D11Impl instance", DeviceContextD3D11Impl)(
RawAllocator, pRenderDeviceD3D11, pd3d11ImmediateCtx1,
pRenderDeviceD3D11,
DeviceContextDesc{
EngineCI.pImmediateContextInfo ? EngineCI.pImmediateContextInfo[0].Name : nullptr,
pRenderDeviceD3D11->GetAdapterInfo().Queues[0].QueueType,
False, // IsDefered
0, // Context id
0 // Queue id
} //
},
pd3d11ImmediateCtx1 //
)};
// We must call AddRef() (implicitly through QueryInterface()) because pRenderDeviceD3D11 will
// keep a weak reference to the context
Expand All @@ -405,29 +406,7 @@ void EngineFactoryD3D11Impl::AttachToD3D11Device(void* pd

for (Uint32 DeferredCtx = 0; DeferredCtx < EngineCI.NumDeferredContexts; ++DeferredCtx)
{
CComPtr<ID3D11DeviceContext> pd3d11DeferredCtx;

HRESULT hr = pd3d11Device->CreateDeferredContext(0, &pd3d11DeferredCtx);
CHECK_D3D_RESULT_THROW(hr, "Failed to create D3D11 deferred context");

CComQIPtr<ID3D11DeviceContext1> pd3d11DeferredCtx1{pd3d11DeferredCtx};
if (!pd3d11DeferredCtx1)
LOG_ERROR_AND_THROW("Failed to get ID3D11DeviceContext1 interface from device context");

RefCntAutoPtr<DeviceContextD3D11Impl> pDeferredCtxD3D11{
NEW_RC_OBJ(RawAllocator, "DeviceContextD3D11Impl instance", DeviceContextD3D11Impl)(
RawAllocator, pRenderDeviceD3D11, pd3d11DeferredCtx1,
DeviceContextDesc{
nullptr,
COMMAND_QUEUE_TYPE_UNKNOWN,
true,
1 + DeferredCtx // Context id
} //
)};
// We must call AddRef() (implicitly through QueryInterface()) because pRenderDeviceD3D12 will
// keep a weak reference to the context
pDeferredCtxD3D11->QueryInterface(IID_DeviceContext, reinterpret_cast<IObject**>(ppContexts + 1 + DeferredCtx));
pRenderDeviceD3D11->SetDeferredContext(DeferredCtx, pDeferredCtxD3D11);
pRenderDeviceD3D11->CreateDeferredContext(ppContexts + 1 + DeferredCtx);
}
}
catch (const std::runtime_error&)
Expand Down
Loading

0 comments on commit b07a92c

Please # to comment.