From ee9f3efe610814707f50c034fb419b91987064bf Mon Sep 17 00:00:00 2001 From: Jack Andersen Date: Thu, 19 Jan 2017 17:52:40 -1000 Subject: [PATCH] Hold shader data bindings through to rendering worker --- CMakeLists.txt | 1 + include/boo/graphicsdev/GL.hpp | 1 + lib/graphicsdev/Common.hpp | 54 ++++++++++++++++++++++++++++++++++ lib/graphicsdev/D3D11.cpp | 27 +++++++++-------- lib/graphicsdev/D3D12.cpp | 19 +++++++----- lib/graphicsdev/GL.cpp | 27 ++++++++++++----- lib/graphicsdev/Metal.mm | 20 ++++++++----- lib/graphicsdev/Vulkan.cpp | 20 ++++++++----- 8 files changed, 124 insertions(+), 45 deletions(-) create mode 100644 lib/graphicsdev/Common.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index c407c89..7645c89 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -230,6 +230,7 @@ add_library(boo include/boo/IGraphicsContext.hpp include/boo/graphicsdev/IGraphicsDataFactory.hpp include/boo/graphicsdev/IGraphicsCommandQueue.hpp + lib/graphicsdev/Common.hpp include/boo/audiodev/IAudioSubmix.hpp include/boo/audiodev/IAudioVoice.hpp include/boo/audiodev/IMIDIPort.hpp diff --git a/include/boo/graphicsdev/GL.hpp b/include/boo/graphicsdev/GL.hpp index b368e2b..352ddb8 100644 --- a/include/boo/graphicsdev/GL.hpp +++ b/include/boo/graphicsdev/GL.hpp @@ -7,6 +7,7 @@ #include "GLSLMacros.hpp" #include #include +#include #include namespace boo diff --git a/lib/graphicsdev/Common.hpp b/lib/graphicsdev/Common.hpp new file mode 100644 index 0000000..c493111 --- /dev/null +++ b/lib/graphicsdev/Common.hpp @@ -0,0 +1,54 @@ +#ifndef BOO_GRAPHICSDEV_COMMON_HPP +#define BOO_GRAPHICSDEV_COMMON_HPP + +/* Private header for managing shader data + * binding lifetimes through rendering cycle */ + +#include "boo/graphicsdev/IGraphicsDataFactory.hpp" + +namespace boo +{ + +template +class IGraphicsDataPriv : public IGraphicsData +{ + std::atomic_int m_refCount = {1}; +public: + void increment() { m_refCount++; } + void decrement() + { + if (m_refCount.fetch_sub(1) == 1) + delete static_cast(this); + } +}; + +template +class IShaderDataBindingPriv : public IShaderDataBinding +{ + IGraphicsDataPriv* m_parent; + +public: + IShaderDataBindingPriv(IGraphicsDataPriv* p) : m_parent(p) {} + class Token + { + IGraphicsDataPriv* m_data = nullptr; + public: + Token() = default; + Token(const IShaderDataBindingPriv* p) + : m_data(p->m_parent) + { m_data->increment(); } + Token& operator=(const Token&) = delete; + Token(const Token&) = delete; + Token& operator=(Token&& other) + { m_data = other.m_data; other.m_data = nullptr; return *this; } + Token(Token&& other) + { m_data = other.m_data; other.m_data = nullptr; } + ~Token() { if (m_data) m_data->decrement(); } + }; + + Token lock() const { return Token(this); } +}; + +} + +#endif // BOO_GRAPHICSDEV_COMMON_HPP diff --git a/lib/graphicsdev/D3D11.cpp b/lib/graphicsdev/D3D11.cpp index abc83d9..4f44949 100644 --- a/lib/graphicsdev/D3D11.cpp +++ b/lib/graphicsdev/D3D11.cpp @@ -2,6 +2,7 @@ #include "logvisor/logvisor.hpp" #include "boo/graphicsdev/D3D.hpp" #include "boo/IGraphicsContext.hpp" +#include "Common.hpp" #include #include #include @@ -32,7 +33,7 @@ static inline void ThrowIfFailed(HRESULT hr) } } -struct D3D11Data : IGraphicsData +struct D3D11Data : IGraphicsDataPriv { std::vector> m_SPs; std::vector> m_SBinds; @@ -576,9 +577,8 @@ public: } }; -struct D3D11ShaderDataBinding : IShaderDataBinding +struct D3D11ShaderDataBinding : IShaderDataBindingPriv { - std::weak_ptr m_selfPtr; std::shared_ptr m_pipeline; std::shared_ptr m_vbuf; std::shared_ptr m_instVbuf; @@ -590,13 +590,15 @@ struct D3D11ShaderDataBinding : IShaderDataBinding std::vector> m_texs; UINT m_baseOffsets[2]; - D3D11ShaderDataBinding(D3D11Context* ctx, + D3D11ShaderDataBinding(D3D11Data* d, + D3D11Context* ctx, IShaderPipeline* pipeline, IGraphicsBuffer* vbuf, IGraphicsBuffer* instVbuf, IGraphicsBuffer* ibuf, size_t ubufCount, IGraphicsBuffer** ubufs, const PipelineStage* ubufStages, const size_t* ubufOffs, const size_t* ubufSizes, size_t texCount, ITexture** texs, size_t baseVert, size_t baseInst) - : m_pipeline(static_cast(pipeline)->m_selfPtr), + : IShaderDataBindingPriv(d), + m_pipeline(static_cast(pipeline)->m_selfPtr), m_vbuf(D3D11GraphicsBuffer::getPtr(vbuf)), m_instVbuf(D3D11GraphicsBuffer::getPtr(instVbuf)), m_ibuf(D3D11GraphicsBuffer::getPtr(ibuf)) @@ -849,13 +851,13 @@ struct D3D11CommandQueue : IGraphicsCommandQueue struct CommandList { ComPtr list; - std::vector> bindings; + std::vector resTokens; std::shared_ptr workDoPresent; void reset() { list.Reset(); - bindings.clear(); + resTokens.clear(); workDoPresent.reset(); } }; @@ -965,7 +967,7 @@ struct D3D11CommandQueue : IGraphicsCommandQueue { D3D11ShaderDataBinding* cbind = static_cast(binding); cbind->bind(m_deferredCtx.Get(), m_fillBuf); - m_cmdLists[m_fillBuf].bindings.push_back(cbind->m_selfPtr.lock()); + m_cmdLists[m_fillBuf].resTokens.push_back(cbind->lock()); ID3D11SamplerState* samp[] = {m_ctx->m_ss.Get()}; m_deferredCtx->PSSetSamplers(0, 1, samp); @@ -1174,14 +1176,14 @@ class D3D11DataFactory : public ID3DDataFactory std::unique_lock lk(m_committedMutex); D3D11Data* data = static_cast(d); m_committedData.erase(data); - delete data; + data->decrement(); } void destroyAllData() { std::unique_lock lk(m_committedMutex); - for (IGraphicsData* data : m_committedData) - delete static_cast(data); + for (D3D11Data* data : m_committedData) + data->decrement(); for (IGraphicsBufferPool* pool : m_committedPools) delete static_cast(pool); m_committedData.clear(); @@ -1356,11 +1358,10 @@ public: { D3D11Data* d = static_cast(m_deferredData); D3D11ShaderDataBinding* retval = - new D3D11ShaderDataBinding(m_parent.m_ctx, pipeline, vbuf, instVbo, ibuf, + new D3D11ShaderDataBinding(d, m_parent.m_ctx, pipeline, vbuf, instVbo, ibuf, ubufCount, ubufs, ubufStages, ubufOffs, ubufSizes, texCount, texs, baseVert, baseInst); d->m_SBinds.emplace_back(retval); - retval->m_selfPtr = d->m_SBinds.back(); return retval; } }; diff --git a/lib/graphicsdev/D3D12.cpp b/lib/graphicsdev/D3D12.cpp index 2595f6e..3561488 100644 --- a/lib/graphicsdev/D3D12.cpp +++ b/lib/graphicsdev/D3D12.cpp @@ -3,6 +3,7 @@ #include "logvisor/logvisor.hpp" #include "boo/graphicsdev/D3D.hpp" #include "boo/IGraphicsContext.hpp" +#include "Common.hpp" #include #include "d3dx12.h" #include @@ -40,7 +41,7 @@ static inline UINT64 NextHeapOffset(UINT64 offset, const D3D12_RESOURCE_ALLOCATI return (offset + info.Alignment - 1) & ~(info.Alignment - 1); } -struct D3D12Data : IGraphicsData +struct D3D12Data : IGraphicsDataPriv { std::vector> m_SPs; std::vector> m_SBinds; @@ -909,7 +910,7 @@ static ID3D12Resource* GetTextureGPUResource(const ITexture* tex, int idx, return nullptr; } -struct D3D12ShaderDataBinding : IShaderDataBinding +struct D3D12ShaderDataBinding : IShaderDataBindingPriv { D3D12ShaderPipeline* m_pipeline; ComPtr m_gpuHeap; @@ -927,14 +928,16 @@ struct D3D12ShaderDataBinding : IShaderDataBinding D3D12_INDEX_BUFFER_VIEW m_iboView[2]; size_t m_vertOffset, m_instOffset; - D3D12ShaderDataBinding(D3D12Context* ctx, + D3D12ShaderDataBinding(D3D12Data* d, + D3D12Context* ctx, IShaderPipeline* pipeline, IGraphicsBuffer* vbuf, IGraphicsBuffer* instVbuf, IGraphicsBuffer* ibuf, size_t ubufCount, IGraphicsBuffer** ubufs, const size_t* ubufOffs, const size_t* ubufSizes, size_t texCount, ITexture** texs, size_t baseVert, size_t baseInst) - : m_pipeline(static_cast(pipeline)), + : IShaderDataBindingPriv(d), + m_pipeline(static_cast(pipeline)), m_vbuf(vbuf), m_instVbuf(instVbuf), m_ibuf(ibuf), @@ -1541,14 +1544,14 @@ class D3D12DataFactory : public ID3DDataFactory std::unique_lock lk(m_committedMutex); D3D12Data* data = static_cast(d); m_committedData.erase(data); - delete data; + data->decrement(); } void destroyAllData() { std::unique_lock lk(m_committedMutex); - for (IGraphicsData* data : m_committedData) - delete static_cast(data); + for (D3D12Data* data : m_committedData) + data->decrement(); for (IGraphicsBufferPool* pool : m_committedPools) delete static_cast(pool); m_committedData.clear(); @@ -1745,7 +1748,7 @@ public: size_t baseVert, size_t baseInst) { D3D12ShaderDataBinding* retval = - new D3D12ShaderDataBinding(m_parent.m_ctx, pipeline, vbuf, instVbuf, ibuf, + new D3D12ShaderDataBinding(m_deferredData.get(), m_parent.m_ctx, pipeline, vbuf, instVbuf, ibuf, ubufCount, ubufs, ubufOffs, ubufSizes, texCount, texs, baseVert, baseInst); static_cast(m_deferredData)->m_SBinds.emplace_back(retval); diff --git a/lib/graphicsdev/GL.cpp b/lib/graphicsdev/GL.cpp index 8ddec18..c323ea7 100644 --- a/lib/graphicsdev/GL.cpp +++ b/lib/graphicsdev/GL.cpp @@ -1,12 +1,14 @@ #include "boo/graphicsdev/GL.hpp" #include "boo/graphicsdev/glew.h" #include "boo/IGraphicsContext.hpp" +#include "Common.hpp" #include #include #include #include #include #include +#include #include "logvisor/logvisor.hpp" @@ -18,7 +20,7 @@ namespace boo static logvisor::Module Log("boo::GL"); ThreadLocalPtr GLDataFactory::m_deferredData; -struct GLData : IGraphicsData +struct GLData : IGraphicsDataPriv { std::vector> m_SPs; std::vector> m_SBinds; @@ -548,7 +550,7 @@ struct GLVertexFormat : IVertexFormat void bind(int idx) const {glBindVertexArray(m_vao[idx]);} }; -struct GLShaderDataBinding : IShaderDataBinding +struct GLShaderDataBinding : IShaderDataBindingPriv { const GLShaderPipeline* m_pipeline; const GLVertexFormat* m_vtxFormat; @@ -558,12 +560,14 @@ struct GLShaderDataBinding : IShaderDataBinding size_t m_texCount; std::unique_ptr m_texs; - GLShaderDataBinding(IShaderPipeline* pipeline, + GLShaderDataBinding(GLData* d, + IShaderPipeline* pipeline, IVertexFormat* vtxFormat, size_t ubufCount, IGraphicsBuffer** ubufs, const size_t* ubufOffs, const size_t* ubufSizes, size_t texCount, ITexture** texs) - : m_pipeline(static_cast(pipeline)), + : IShaderDataBindingPriv(d), + m_pipeline(static_cast(pipeline)), m_vtxFormat(static_cast(vtxFormat)), m_ubufCount(ubufCount), m_ubufs(new IGraphicsBuffer*[ubufCount]), @@ -663,7 +667,7 @@ GLDataFactory::Context::newShaderDataBinding(IShaderPipeline* pipeline, size_t texCount, ITexture** texs, size_t baseVert, size_t baseInst) { GLShaderDataBinding* retval = - new GLShaderDataBinding(pipeline, vtxFormat, ubufCount, ubufs, + new GLShaderDataBinding(m_deferredData.get(), pipeline, vtxFormat, ubufCount, ubufs, ubufOffs, ubufSizes, texCount, texs); m_deferredData->m_SBinds.emplace_back(retval); return retval; @@ -691,6 +695,7 @@ GraphicsDataToken GLDataFactory::commitTransaction(const FactoryCommitFunc& tran GLData* retval = m_deferredData.get(); m_deferredData.reset(); m_committedData.insert(retval); + lk.unlock(); /* Let's go ahead and flush to ensure our data gets to the GPU While this isn't strictly required, some drivers might behave @@ -712,14 +717,14 @@ void GLDataFactory::destroyData(IGraphicsData* d) std::unique_lock lk(m_committedMutex); GLData* data = static_cast(d); m_committedData.erase(data); - delete data; + data->decrement(); } void GLDataFactory::destroyAllData() { std::unique_lock lk(m_committedMutex); - for (IGraphicsData* data : m_committedData) - delete static_cast(data); + for (GLData* data : m_committedData) + data->decrement(); for (IGraphicsBufferPool* pool : m_committedPools) delete static_cast(pool); m_committedData.clear(); @@ -836,10 +841,15 @@ struct GLCommandQueue : IGraphicsCommandQueue size_t instCount; }; }; + IShaderDataBindingPriv::Token resToken; const ITextureR* resolveTex; bool resolveColor : 1; bool resolveDepth : 1; Command(Op op) : m_op(op) {} + Command(const Command&) = delete; + Command& operator=(const Command&) = delete; + Command(Command&&) = default; + Command& operator=(Command&&) = default; }; std::vector m_cmdBufs[3]; size_t m_fillBuf = 0; @@ -1129,6 +1139,7 @@ struct GLCommandQueue : IGraphicsCommandQueue std::vector& cmds = m_cmdBufs[m_fillBuf]; cmds.emplace_back(Command::Op::SetShaderDataBinding); cmds.back().binding = binding; + cmds.back().resToken = static_cast*>(binding)->lock(); } void setRenderTarget(ITextureR* target) diff --git a/lib/graphicsdev/Metal.mm b/lib/graphicsdev/Metal.mm index 1d73004..2c20e63 100644 --- a/lib/graphicsdev/Metal.mm +++ b/lib/graphicsdev/Metal.mm @@ -3,6 +3,7 @@ #include "logvisor/logvisor.hpp" #include "boo/graphicsdev/Metal.hpp" #include "boo/IGraphicsContext.hpp" +#include "Common.hpp" #include #if !__has_feature(objc_arc) @@ -18,7 +19,7 @@ static logvisor::Module Log("boo::Metal"); struct MetalCommandQueue; ThreadLocalPtr MetalDataFactory::m_deferredData; -struct MetalData : IGraphicsData +struct MetalData : IGraphicsDataPriv { std::vector> m_SPs; std::vector> m_SBinds; @@ -582,7 +583,7 @@ static id GetTextureGPUResource(const ITexture* tex, int idx) return nullptr; } -struct MetalShaderDataBinding : IShaderDataBinding +struct MetalShaderDataBinding : IShaderDataBindingPriv { MetalShaderPipeline* m_pipeline; IGraphicsBuffer* m_vbuf; @@ -597,13 +598,15 @@ struct MetalShaderDataBinding : IShaderDataBinding size_t m_baseVert; size_t m_baseInst; - MetalShaderDataBinding(MetalContext* ctx, + MetalShaderDataBinding(MetalData* d, + MetalContext* ctx, IShaderPipeline* pipeline, IGraphicsBuffer* vbuf, IGraphicsBuffer* instVbo, IGraphicsBuffer* ibuf, size_t ubufCount, IGraphicsBuffer** ubufs, const PipelineStage* ubufStages, const size_t* ubufOffs, const size_t* ubufSizes, size_t texCount, ITexture** texs, size_t baseVert, size_t baseInst) - : m_pipeline(static_cast(pipeline)), + : IShaderDataBindingPriv(d), + m_pipeline(static_cast(pipeline)), m_vbuf(vbuf), m_instVbo(instVbo), m_ibuf(ibuf), @@ -1122,7 +1125,8 @@ MetalDataFactory::Context::newShaderDataBinding(IShaderPipeline* pipeline, size_t texCount, ITexture** texs, size_t baseVert, size_t baseInst) { MetalShaderDataBinding* retval = - new MetalShaderDataBinding(m_parent.m_ctx, pipeline, vbuf, instVbo, ibuf, + new MetalShaderDataBinding(m_deferredData.get(), + m_parent.m_ctx, pipeline, vbuf, instVbo, ibuf, ubufCount, ubufs, ubufStages, ubufOffs, ubufSizes, texCount, texs, baseVert, baseInst); m_deferredData->m_SBinds.emplace_back(retval); @@ -1163,14 +1167,14 @@ void MetalDataFactory::destroyData(IGraphicsData* d) std::unique_lock lk(m_committedMutex); MetalData* data = static_cast(d); m_committedData.erase(data); - delete data; + data->decrement(); } void MetalDataFactory::destroyAllData() { std::unique_lock lk(m_committedMutex); - for (IGraphicsData* data : m_committedData) - delete static_cast(data); + for (MetalData* data : m_committedData) + data->decrement(); for (IGraphicsBufferPool* pool : m_committedPools) delete static_cast(pool); m_committedData.clear(); diff --git a/lib/graphicsdev/Vulkan.cpp b/lib/graphicsdev/Vulkan.cpp index 0cd12d9..1ac177b 100644 --- a/lib/graphicsdev/Vulkan.cpp +++ b/lib/graphicsdev/Vulkan.cpp @@ -8,6 +8,7 @@ #include #include #include "boo/graphicsdev/GLSLMacros.hpp" +#include "Common.hpp" #include "logvisor/logvisor.hpp" @@ -652,7 +653,7 @@ void VulkanContext::resizeSwapChain(VulkanContext::Window& windowCtx, VkSurfaceK } } -struct VulkanData : IGraphicsData +struct VulkanData : IGraphicsDataPriv { VulkanContext* m_ctx; VkDeviceMemory m_bufMem = VK_NULL_HANDLE; @@ -1947,7 +1948,7 @@ static const VkDescriptorImageInfo* GetTextureGPUResource(const ITexture* tex, i return nullptr; } -struct VulkanShaderDataBinding : IShaderDataBinding +struct VulkanShaderDataBinding : IShaderDataBindingPriv { VulkanContext* m_ctx; VulkanShaderPipeline* m_pipeline; @@ -1977,14 +1978,16 @@ struct VulkanShaderDataBinding : IShaderDataBinding bool m_committed = false; #endif - VulkanShaderDataBinding(VulkanContext* ctx, + VulkanShaderDataBinding(VulkanData* d, + VulkanContext* ctx, IShaderPipeline* pipeline, IGraphicsBuffer* vbuf, IGraphicsBuffer* instVbuf, IGraphicsBuffer* ibuf, size_t ubufCount, IGraphicsBuffer** ubufs, const size_t* ubufOffs, const size_t* ubufSizes, size_t texCount, ITexture** texs, size_t baseVert, size_t baseInst) - : m_ctx(ctx), + : IShaderDataBindingPriv(d), + m_ctx(ctx), m_pipeline(static_cast(pipeline)), m_vbuf(vbuf), m_instVbuf(instVbuf), @@ -2812,7 +2815,7 @@ void VulkanDataFactory::destroyAllData() { std::unique_lock lk(m_committedMutex); for (IGraphicsData* data : m_committedData) - delete static_cast(data); + data->decrement(); for (IGraphicsBufferPool* pool : m_committedPools) delete static_cast(pool); m_committedData.clear(); @@ -3062,11 +3065,12 @@ IShaderDataBinding* VulkanDataFactory::Context::newShaderDataBinding(IShaderPipe size_t texCount, ITexture** texs, size_t baseVert, size_t baseInst) { + VulkanData* d = static_cast(m_deferredData.get()); VulkanShaderDataBinding* retval = - new VulkanShaderDataBinding(m_parent.m_ctx, pipeline, vbuf, instVbuf, ibuf, + new VulkanShaderDataBinding(d, m_parent.m_ctx, pipeline, vbuf, instVbuf, ibuf, ubufCount, ubufs, ubufOffs, ubufSizes, texCount, texs, baseVert, baseInst); - static_cast(m_deferredData.get())->m_SBinds.emplace_back(retval); + d->m_SBinds.emplace_back(retval); return retval; } @@ -3301,7 +3305,7 @@ void VulkanCommandQueue::execute() { if ((*it)->m_dead) { - delete *it; + it->decrement(); it = gfxF->m_committedData.erase(it); continue; }