diff --git a/include/boo/System.hpp b/include/boo/System.hpp index f62c42f..6631004 100644 --- a/include/boo/System.hpp +++ b/include/boo/System.hpp @@ -7,6 +7,9 @@ #include template using ComPtr = Microsoft::WRL::ComPtr; +template +static inline ComPtr* ReferenceComPtr(ComPtr& ptr) +{ return reinterpret_cast*>(ptr.GetAddressOf()); } #endif #include diff --git a/include/boo/graphicsdev/D3D.hpp b/include/boo/graphicsdev/D3D.hpp index 55b946d..3f46a41 100644 --- a/include/boo/graphicsdev/D3D.hpp +++ b/include/boo/graphicsdev/D3D.hpp @@ -28,8 +28,8 @@ public: public: bool bindingNeedsVertexFormat() const {return false;} virtual IShaderPipeline* newShaderPipeline(const char* vertSource, const char* fragSource, - ComPtr& vertBlobOut, ComPtr& fragBlobOut, - ComPtr& pipelineBlob, IVertexFormat* vtxFmt, + ComPtr* vertBlobOut, ComPtr* fragBlobOut, + ComPtr* pipelineBlob, IVertexFormat* vtxFmt, BlendFactor srcFac, BlendFactor dstFac, Primitive prim, bool depthTest, bool depthWrite, bool backfaceCulling)=0; }; diff --git a/include/boo/graphicsdev/IGraphicsDataFactory.hpp b/include/boo/graphicsdev/IGraphicsDataFactory.hpp index 0cd731b..e2c5f31 100644 --- a/include/boo/graphicsdev/IGraphicsDataFactory.hpp +++ b/include/boo/graphicsdev/IGraphicsDataFactory.hpp @@ -280,7 +280,7 @@ class GraphicsDataToken friend class D3D12DataFactory; friend class D3D11DataFactory; friend class MetalDataFactoryImpl; - friend class VulkanDataFactory; + friend class VulkanDataFactoryImpl; IGraphicsDataFactory* m_factory = nullptr; IGraphicsData* m_data = nullptr; GraphicsDataToken(IGraphicsDataFactory* factory, IGraphicsData* data) @@ -327,7 +327,7 @@ class GraphicsBufferPoolToken friend class D3D12DataFactory; friend class D3D11DataFactory; friend class MetalDataFactoryImpl; - friend class VulkanDataFactory; + friend class VulkanDataFactoryImpl; IGraphicsDataFactory* m_factory = nullptr; IGraphicsBufferPool* m_pool = nullptr; GraphicsBufferPoolToken(IGraphicsDataFactory* factory, IGraphicsBufferPool* pool) diff --git a/include/boo/graphicsdev/Vulkan.hpp b/include/boo/graphicsdev/Vulkan.hpp index 97689b6..3134c31 100644 --- a/include/boo/graphicsdev/Vulkan.hpp +++ b/include/boo/graphicsdev/Vulkan.hpp @@ -103,31 +103,10 @@ extern VulkanContext g_VulkanContext; class VulkanDataFactory : public IGraphicsDataFactory { - friend struct VulkanCommandQueue; - IGraphicsContext* m_parent; - VulkanContext* m_ctx; - uint32_t m_drawSamples; - static ThreadLocalPtr m_deferredData; - std::unordered_set m_committedData; - std::unordered_set m_committedPools; - std::mutex m_committedMutex; - std::vector m_texUnis; - void destroyData(IGraphicsData*); - void destroyPool(IGraphicsBufferPool*); - void destroyAllData(); - IGraphicsBufferD* newPoolBuffer(IGraphicsBufferPool *pool, BufferUse use, - size_t stride, size_t count); - void deletePoolBuffer(IGraphicsBufferPool* p, IGraphicsBufferD* buf); public: - VulkanDataFactory(IGraphicsContext* parent, VulkanContext* ctx, uint32_t drawSamples); - ~VulkanDataFactory() {destroyAllData();} - - Platform platform() const {return Platform::Vulkan;} - const SystemChar* platformName() const {return _S("Vulkan");} - class Context : public IGraphicsDataFactory::Context { - friend class VulkanDataFactory; + friend class VulkanDataFactoryImpl; VulkanDataFactory& m_parent; Context(VulkanDataFactory& parent) : m_parent(parent) {} public: @@ -150,8 +129,8 @@ public: size_t baseVert = 0, size_t baseInst = 0); IShaderPipeline* newShaderPipeline(const char* vertSource, const char* fragSource, - std::vector& vertBlobOut, std::vector& fragBlobOut, - std::vector& pipelineBlob, IVertexFormat* vtxFmt, + std::vector* vertBlobOut, std::vector* fragBlobOut, + std::vector* pipelineBlob, IVertexFormat* vtxFmt, BlendFactor srcFac, BlendFactor dstFac, Primitive prim, bool depthTest, bool depthWrite, bool backfaceCulling); @@ -159,10 +138,7 @@ public: BlendFactor srcFac, BlendFactor dstFac, Primitive prim, bool depthTest, bool depthWrite, bool backfaceCulling) { - std::vector vertBlob; - std::vector fragBlob; - std::vector pipelineBlob; - return newShaderPipeline(vertSource, fragSource, vertBlob, fragBlob, pipelineBlob, + return newShaderPipeline(vertSource, fragSource, nullptr, nullptr, nullptr, vtxFmt, srcFac, dstFac, prim, depthTest, depthWrite, backfaceCulling); } @@ -175,9 +151,6 @@ public: size_t texCount, ITexture** texs, size_t baseVert = 0, size_t baseInst = 0); }; - - GraphicsDataToken commitTransaction(const FactoryCommitFunc&); - GraphicsBufferPoolToken newBufferPool(); }; } diff --git a/lib/graphicsdev/Common.hpp b/lib/graphicsdev/Common.hpp index 73ea4b7..afcabbb 100644 --- a/lib/graphicsdev/Common.hpp +++ b/lib/graphicsdev/Common.hpp @@ -55,15 +55,15 @@ class IShareableShader { std::atomic_int m_refCount = {0}; FactoryImpl& m_factory; - uint64_t m_key; + uint64_t m_srckey, m_binKey; public: - IShareableShader(FactoryImpl& factory, uint64_t key) - : m_factory(factory), m_key(key) {} + IShareableShader(FactoryImpl& factory, uint64_t srcKey, uint64_t binKey) + : m_factory(factory), m_srckey(srcKey), m_binKey(binKey) {} void increment() { m_refCount++; } void decrement() { if (m_refCount.fetch_sub(1) == 1) - m_factory._unregisterShareableShader(m_key); + m_factory._unregisterShareableShader(m_srckey, m_binKey); } class Token diff --git a/lib/graphicsdev/D3D11.cpp b/lib/graphicsdev/D3D11.cpp index 205ff99..d8c9b9d 100644 --- a/lib/graphicsdev/D3D11.cpp +++ b/lib/graphicsdev/D3D11.cpp @@ -12,6 +12,7 @@ #include #include #include +#include "xxhash.h" #undef min #undef max @@ -21,6 +22,19 @@ extern pD3DCompile D3DCompilePROC; namespace boo { static logvisor::Module Log("boo::D3D11"); +class D3D11DataFactory; + +struct D3D11ShareableShader : IShareableShader +{ + ComPtr m_shader; + ComPtr m_vtxBlob; + D3D11ShareableShader(D3D11DataFactory& fac, uint64_t srcKey, uint64_t binKey, + ComPtr&& s, ComPtr&& vb) + : IShareableShader(fac, srcKey, binKey), m_shader(std::move(s)), m_vtxBlob(std::move(vb)) {} + D3D11ShareableShader(D3D11DataFactory& fac, uint64_t srcKey, uint64_t binKey, + ComPtr&& s) + : IShareableShader(fac, srcKey, binKey), m_shader(std::move(s)) {} +}; static inline void ThrowIfFailed(HRESULT hr) { @@ -479,15 +493,20 @@ class D3D11ShaderPipeline : public IShaderPipeline friend class D3D11DataFactory; friend struct D3D11ShaderDataBinding; const D3D11VertexFormat* m_vtxFmt; + D3D11ShareableShader::Token m_vert; + D3D11ShareableShader::Token m_pixel; - D3D11ShaderPipeline(D3D11Context* ctx, ID3DBlob* vert, ID3DBlob* pixel, + D3D11ShaderPipeline(D3D11Context* ctx, + D3D11ShareableShader::Token&& vert, + D3D11ShareableShader::Token&& pixel, const D3D11VertexFormat* vtxFmt, BlendFactor srcFac, BlendFactor dstFac, Primitive prim, bool depthTest, bool depthWrite, bool backfaceCulling) - : m_vtxFmt(vtxFmt), m_topology(PRIMITIVE_TABLE[int(prim)]) + : m_vtxFmt(vtxFmt), m_vert(std::move(vert)), m_pixel(std::move(pixel)), + m_topology(PRIMITIVE_TABLE[int(prim)]) { - ThrowIfFailed(ctx->m_dev->CreateVertexShader(vert->GetBufferPointer(), vert->GetBufferSize(), nullptr, &m_vShader)); - ThrowIfFailed(ctx->m_dev->CreatePixelShader(pixel->GetBufferPointer(), pixel->GetBufferSize(), nullptr, &m_pShader)); + m_vert.get().m_shader.As(&m_vShader); + m_pixel.get().m_shader.As(&m_pShader); CD3D11_RASTERIZER_DESC rasDesc(D3D11_FILL_SOLID, backfaceCulling ? D3D11_CULL_BACK : D3D11_CULL_NONE, true, D3D11_DEFAULT_DEPTH_BIAS, D3D11_DEFAULT_DEPTH_BIAS_CLAMP, D3D11_DEFAULT_SLOPE_SCALED_DEPTH_BIAS, @@ -506,8 +525,9 @@ class D3D11ShaderPipeline : public IShaderPipeline blDesc.RenderTarget[0].DestBlend = BLEND_FACTOR_TABLE[int(dstFac)]; ThrowIfFailed(ctx->m_dev->CreateBlendState(&blDesc, &m_blState)); + const auto& vertBuf = m_vert.get().m_vtxBlob; ThrowIfFailed(ctx->m_dev->CreateInputLayout(vtxFmt->m_elements.get(), vtxFmt->m_elementCount, - vert->GetBufferPointer(), vert->GetBufferSize(), &m_inLayout)); + vertBuf->GetBufferPointer(), vertBuf->GetBufferSize(), &m_inLayout)); } public: ComPtr m_vShader; @@ -1125,6 +1145,8 @@ class D3D11DataFactory : public ID3DDataFactory std::unordered_set m_committedData; std::unordered_set m_committedPools; std::mutex m_committedMutex; + std::unordered_map> m_sharedShaders; + std::unordered_map m_sourceToBinary; uint32_t m_sampleCount; void destroyData(IGraphicsData* d) @@ -1258,37 +1280,149 @@ public: #define BOO_D3DCOMPILE_FLAG D3DCOMPILE_OPTIMIZATION_LEVEL3 #endif + static uint64_t CompileVert(ComPtr& vertBlobOut, const char* vertSource, uint64_t srcKey, + D3D11DataFactory& factory) + { + ComPtr errBlob; + if (FAILED(D3DCompilePROC(vertSource, strlen(vertSource), "HECL Vert Source", nullptr, nullptr, "main", + "vs_5_0", BOO_D3DCOMPILE_FLAG, 0, &vertBlobOut, &errBlob))) + { + Log.report(logvisor::Fatal, "error compiling vert shader: %s", errBlob->GetBufferPointer()); + } + + XXH64_state_t hashState; + XXH64_reset(&hashState, 0); + XXH64_update(&hashState, vertBlobOut->GetBufferPointer(), vertBlobOut->GetBufferSize()); + uint64_t binKey = XXH64_digest(&hashState); + factory.m_sourceToBinary[srcKey] = binKey; + return binKey; + } + + static uint64_t CompileFrag(ComPtr& fragBlobOut, const char* fragSource, uint64_t srcKey, + D3D11DataFactory& factory) + { + ComPtr errBlob; + if (FAILED(D3DCompilePROC(fragSource, strlen(fragSource), "HECL Pixel Source", nullptr, nullptr, "main", + "ps_5_0", BOO_D3DCOMPILE_FLAG, 0, &fragBlobOut, &errBlob))) + { + Log.report(logvisor::Fatal, "error compiling pixel shader: %s", errBlob->GetBufferPointer()); + } + + XXH64_state_t hashState; + XXH64_reset(&hashState, 0); + XXH64_update(&hashState, fragBlobOut->GetBufferPointer(), fragBlobOut->GetBufferSize()); + uint64_t binKey = XXH64_digest(&hashState); + factory.m_sourceToBinary[srcKey] = binKey; + return binKey; + } + IShaderPipeline* newShaderPipeline (const char* vertSource, const char* fragSource, - ComPtr& vertBlobOut, ComPtr& fragBlobOut, - ComPtr& pipelineBlob, IVertexFormat* vtxFmt, + ComPtr* vertBlobOut, ComPtr* fragBlobOut, + ComPtr* pipelineBlob, IVertexFormat* vtxFmt, BlendFactor srcFac, BlendFactor dstFac, Primitive prim, bool depthTest, bool depthWrite, bool backfaceCulling) { - ComPtr errBlob; - - if (!vertBlobOut) + XXH64_state_t hashState; + uint64_t srcHashes[2] = {}; + uint64_t binHashes[2] = {}; + XXH64_reset(&hashState, 0); + if (vertSource) { - if (FAILED(D3DCompilePROC(vertSource, strlen(vertSource), "HECL Vert Source", nullptr, nullptr, "main", - "vs_5_0", BOO_D3DCOMPILE_FLAG, 0, &vertBlobOut, &errBlob))) - { - Log.report(logvisor::Fatal, "error compiling vert shader: %s", errBlob->GetBufferPointer()); - return nullptr; - } + XXH64_update(&hashState, vertSource, strlen(vertSource)); + srcHashes[0] = XXH64_digest(&hashState); + auto binSearch = m_parent.m_sourceToBinary.find(srcHashes[0]); + if (binSearch != m_parent.m_sourceToBinary.cend()) + binHashes[0] = binSearch->second; + } + else if (vertBlobOut && *vertBlobOut) + { + XXH64_update(&hashState, (*vertBlobOut)->GetBufferPointer(), (*vertBlobOut)->GetBufferSize()); + binHashes[0] = XXH64_digest(&hashState); + } + XXH64_reset(&hashState, 0); + if (fragSource) + { + XXH64_update(&hashState, fragSource, strlen(fragSource)); + srcHashes[1] = XXH64_digest(&hashState); + auto binSearch = m_parent.m_sourceToBinary.find(srcHashes[1]); + if (binSearch != m_parent.m_sourceToBinary.cend()) + binHashes[1] = binSearch->second; + } + else if (fragBlobOut && *fragBlobOut) + { + XXH64_update(&hashState, (*fragBlobOut)->GetBufferPointer(), (*fragBlobOut)->GetBufferSize()); + binHashes[1] = XXH64_digest(&hashState); } - if (!fragBlobOut) + if (vertBlobOut && !*vertBlobOut) + binHashes[0] = CompileVert(*vertBlobOut, vertSource, srcHashes[0], m_parent); + + if (fragBlobOut && !*fragBlobOut) + binHashes[1] = CompileFrag(*fragBlobOut, fragSource, srcHashes[1], m_parent); + + + struct D3D11Context* ctx = m_parent.m_ctx; + D3D11ShareableShader::Token vertShader; + D3D11ShareableShader::Token fragShader; + auto vertFind = binHashes[0] ? m_parent.m_sharedShaders.find(binHashes[0]) : + m_parent.m_sharedShaders.end(); + if (vertFind != m_parent.m_sharedShaders.end()) { - if (FAILED(D3DCompilePROC(fragSource, strlen(fragSource), "HECL Pixel Source", nullptr, nullptr, "main", - "ps_5_0", BOO_D3DCOMPILE_FLAG, 0, &fragBlobOut, &errBlob))) + vertShader = vertFind->second->lock(); + } + else + { + ComPtr vertBlob; + if (vertBlobOut) + vertBlob = *vertBlobOut; + else + binHashes[0] = CompileVert(vertBlob, vertSource, srcHashes[0], m_parent); + + ComPtr vShader; + ThrowIfFailed(ctx->m_dev->CreateVertexShader(vertBlob->GetBufferPointer(), + vertBlob->GetBufferSize(), nullptr, &vShader)); + + auto it = + m_parent.m_sharedShaders.emplace(std::make_pair(binHashes[0], + std::make_unique(m_parent, srcHashes[0], binHashes[0], + std::move(vShader), std::move(vertBlob)))).first; + vertShader = it->second->lock(); + } + auto fragFind = binHashes[1] ? m_parent.m_sharedShaders.find(binHashes[1]) : + m_parent.m_sharedShaders.end(); + if (fragFind != m_parent.m_sharedShaders.end()) + { + fragShader = fragFind->second->lock(); + } + else + { + ComPtr fragBlob; + ComPtr* useFragBlob; + if (fragBlobOut) { - Log.report(logvisor::Fatal, "error compiling pixel shader: %s", errBlob->GetBufferPointer()); - return nullptr; + useFragBlob = fragBlobOut; } + else + { + useFragBlob = &fragBlob; + binHashes[1] = CompileFrag(fragBlob, fragSource, srcHashes[1], m_parent); + } + + ComPtr pShader; + ThrowIfFailed(ctx->m_dev->CreatePixelShader((*useFragBlob)->GetBufferPointer(), + (*useFragBlob)->GetBufferSize(), nullptr, &pShader)); + + auto it = + m_parent.m_sharedShaders.emplace(std::make_pair(binHashes[1], + std::make_unique(m_parent, srcHashes[1], binHashes[1], + std::move(pShader)))).first; + fragShader = it->second->lock(); } D3D11Data* d = static_cast(m_deferredData); - D3D11ShaderPipeline* retval = new D3D11ShaderPipeline(m_parent.m_ctx, vertBlobOut.Get(), fragBlobOut.Get(), + D3D11ShaderPipeline* retval = new D3D11ShaderPipeline(ctx, + std::move(vertShader), std::move(fragShader), static_cast(vtxFmt), srcFac, dstFac, prim, depthTest, depthWrite, backfaceCulling); d->m_SPs.emplace_back(retval); @@ -1342,6 +1476,13 @@ public: m_committedPools.insert(retval); return GraphicsBufferPoolToken(this, retval); } + + void _unregisterShareableShader(uint64_t srcKey, uint64_t binKey) + { + if (srcKey) + m_sourceToBinary.erase(srcKey); + m_sharedShaders.erase(binKey); + } }; thread_local D3D11Data* D3D11DataFactory::m_deferredData; diff --git a/lib/graphicsdev/D3D12.cpp b/lib/graphicsdev/D3D12.cpp index e394db0..95795b6 100644 --- a/lib/graphicsdev/D3D12.cpp +++ b/lib/graphicsdev/D3D12.cpp @@ -10,6 +10,7 @@ #include #include #include +#include "xxhash.h" #define MAX_UNIFORM_COUNT 8 #define MAX_TEXTURE_COUNT 8 @@ -23,6 +24,14 @@ extern pD3DCompile D3DCompilePROC; namespace boo { static logvisor::Module Log("boo::D3D12"); +class D3D12DataFactory; + +struct D3D12ShareableShader : IShareableShader +{ + ComPtr m_shader; + D3D12ShareableShader(D3D12DataFactory& fac, uint64_t srcKey, uint64_t binKey, ComPtr&& s) + : IShareableShader(fac, srcKey, binKey), m_shader(std::move(s)) {} +}; static inline void ThrowIfFailed(HRESULT hr) { @@ -638,17 +647,23 @@ class D3D12ShaderPipeline : public IShaderPipeline friend class D3D12DataFactory; friend struct D3D12ShaderDataBinding; const D3D12VertexFormat* m_vtxFmt; + D3D12ShareableShader::Token m_vert; + D3D12ShareableShader::Token m_pixel; - D3D12ShaderPipeline(D3D12Context* ctx, ID3DBlob* vert, ID3DBlob* pixel, ID3DBlob* pipeline, + D3D12ShaderPipeline(D3D12Context* ctx, D3D12ShareableShader::Token&& vert, + D3D12ShareableShader::Token&& pixel, ID3DBlob* pipeline, const D3D12VertexFormat* vtxFmt, BlendFactor srcFac, BlendFactor dstFac, Primitive prim, bool depthTest, bool depthWrite, bool backfaceCulling) - : m_vtxFmt(vtxFmt), m_topology(PRIMITIVE_TABLE[int(prim)]) + : m_vtxFmt(vtxFmt), m_vert(std::move(vert)), m_pixel(std::move(pixel)), + m_topology(PRIMITIVE_TABLE[int(prim)]) { D3D12_GRAPHICS_PIPELINE_STATE_DESC desc = {}; desc.pRootSignature = ctx->m_rs.Get(); - desc.VS = {vert->GetBufferPointer(), vert->GetBufferSize()}; - desc.PS = {pixel->GetBufferPointer(), pixel->GetBufferSize()}; + const auto& vBlob = m_vert.get().m_shader; + const auto& pBlob = m_pixel.get().m_shader; + desc.VS = {vBlob->GetBufferPointer(), vBlob->GetBufferSize()}; + desc.PS = {pBlob->GetBufferPointer(), pBlob->GetBufferSize()}; desc.BlendState = CD3DX12_BLEND_DESC(D3D12_DEFAULT); if (dstFac != BlendFactor::Zero) { @@ -1532,6 +1547,8 @@ class D3D12DataFactory : public ID3DDataFactory std::unordered_set m_committedData; std::unordered_set m_committedPools; std::mutex m_committedMutex; + std::unordered_map> m_sharedShaders; + std::unordered_map m_sourceToBinary; uint32_t m_sampleCount; void destroyData(IGraphicsData* d) @@ -1693,43 +1710,138 @@ public: #define BOO_D3DCOMPILE_FLAG D3DCOMPILE_OPTIMIZATION_LEVEL3 #endif + static uint64_t CompileVert(ComPtr& vertBlobOut, const char* vertSource, uint64_t srcKey, + D3D12DataFactory& factory) + { + ComPtr errBlob; + if (FAILED(D3DCompilePROC(vertSource, strlen(vertSource), "HECL Vert Source", nullptr, nullptr, "main", + "vs_5_0", BOO_D3DCOMPILE_FLAG, 0, &vertBlobOut, &errBlob))) + { + printf("%s\n", vertSource); + Log.report(logvisor::Fatal, "error compiling vert shader: %s", errBlob->GetBufferPointer()); + } + + XXH64_state_t hashState; + XXH64_reset(&hashState, 0); + XXH64_update(&hashState, vertBlobOut->GetBufferPointer(), vertBlobOut->GetBufferSize()); + uint64_t binKey = XXH64_digest(&hashState); + factory.m_sourceToBinary[srcKey] = binKey; + return binKey; + } + + static uint64_t CompileFrag(ComPtr& fragBlobOut, const char* fragSource, uint64_t srcKey, + D3D12DataFactory& factory) + { + ComPtr errBlob; + if (FAILED(D3DCompilePROC(fragSource, strlen(fragSource), "HECL Pixel Source", nullptr, nullptr, "main", + "ps_5_0", BOO_D3DCOMPILE_FLAG, 0, &fragBlobOut, &errBlob))) + { + printf("%s\n", fragSource); + Log.report(logvisor::Fatal, "error compiling pixel shader: %s", errBlob->GetBufferPointer()); + } + + XXH64_state_t hashState; + XXH64_reset(&hashState, 0); + XXH64_update(&hashState, fragBlobOut->GetBufferPointer(), fragBlobOut->GetBufferSize()); + uint64_t binKey = XXH64_digest(&hashState); + factory.m_sourceToBinary[srcKey] = binKey; + return binKey; + } + IShaderPipeline* newShaderPipeline (const char* vertSource, const char* fragSource, - ComPtr& vertBlobOut, ComPtr& fragBlobOut, - ComPtr& pipelineBlob, IVertexFormat* vtxFmt, + ComPtr* vertBlobOut, ComPtr* fragBlobOut, + ComPtr* pipelineBlob, IVertexFormat* vtxFmt, BlendFactor srcFac, BlendFactor dstFac, Primitive prim, bool depthTest, bool depthWrite, bool backfaceCulling) { - ComPtr errBlob; - - //printf("%s\n", vertSource); - //printf("%s\n", fragSource); - - if (!vertBlobOut) + XXH64_state_t hashState; + uint64_t srcHashes[2] = {}; + uint64_t binHashes[2] = {}; + XXH64_reset(&hashState, 0); + if (vertSource) { - if (FAILED(D3DCompilePROC(vertSource, strlen(vertSource), "HECL Vert Source", nullptr, nullptr, "main", - "vs_5_0", BOO_D3DCOMPILE_FLAG, 0, &vertBlobOut, &errBlob))) - { - Log.report(logvisor::Fatal, "error compiling vert shader: %s", errBlob->GetBufferPointer()); - return nullptr; - } + XXH64_update(&hashState, vertSource, strlen(vertSource)); + srcHashes[0] = XXH64_digest(&hashState); + auto binSearch = m_parent.m_sourceToBinary.find(srcHashes[0]); + if (binSearch != m_parent.m_sourceToBinary.cend()) + binHashes[0] = binSearch->second; + } + else if (vertBlobOut && *vertBlobOut) + { + XXH64_update(&hashState, (*vertBlobOut)->GetBufferPointer(), (*vertBlobOut)->GetBufferSize()); + binHashes[0] = XXH64_digest(&hashState); + } + XXH64_reset(&hashState, 0); + if (fragSource) + { + XXH64_update(&hashState, fragSource, strlen(fragSource)); + srcHashes[1] = XXH64_digest(&hashState); + auto binSearch = m_parent.m_sourceToBinary.find(srcHashes[1]); + if (binSearch != m_parent.m_sourceToBinary.cend()) + binHashes[1] = binSearch->second; + } + else if (fragBlobOut && *fragBlobOut) + { + XXH64_update(&hashState, (*fragBlobOut)->GetBufferPointer(), (*fragBlobOut)->GetBufferSize()); + binHashes[1] = XXH64_digest(&hashState); } - if (!fragBlobOut) + if (vertBlobOut && !*vertBlobOut) + binHashes[0] = CompileVert(*vertBlobOut, vertSource, srcHashes[0], m_parent); + + if (fragBlobOut && !*fragBlobOut) + binHashes[1] = CompileFrag(*fragBlobOut, fragSource, srcHashes[1], m_parent); + + D3D12ShareableShader::Token vertShader; + D3D12ShareableShader::Token fragShader; + auto vertFind = binHashes[0] ? m_parent.m_sharedShaders.find(binHashes[0]) : + m_parent.m_sharedShaders.end(); + if (vertFind != m_parent.m_sharedShaders.end()) { - if (FAILED(D3DCompilePROC(fragSource, strlen(fragSource), "HECL Pixel Source", nullptr, nullptr, "main", - "ps_5_0", BOO_D3DCOMPILE_FLAG, 0, &fragBlobOut, &errBlob))) - { - Log.report(logvisor::Fatal, "error compiling pixel shader: %s", errBlob->GetBufferPointer()); - return nullptr; - } + vertShader = vertFind->second->lock(); + } + else + { + ComPtr vertBlob; + if (vertBlobOut) + vertBlob = *vertBlobOut; + else + binHashes[0] = CompileVert(vertBlob, vertSource, srcHashes[0], m_parent); + + auto it = + m_parent.m_sharedShaders.emplace(std::make_pair(binHashes[0], + std::make_unique(m_parent, srcHashes[0], binHashes[0], + std::move(vertBlob)))).first; + vertShader = it->second->lock(); + } + auto fragFind = binHashes[1] ? m_parent.m_sharedShaders.find(binHashes[1]) : + m_parent.m_sharedShaders.end(); + if (fragFind != m_parent.m_sharedShaders.end()) + { + fragShader = fragFind->second->lock(); + } + else + { + ComPtr fragBlob; + if (fragBlobOut) + fragBlob = *fragBlobOut; + else + binHashes[1] = CompileFrag(fragBlob, fragSource, srcHashes[1], m_parent); + + auto it = + m_parent.m_sharedShaders.emplace(std::make_pair(binHashes[1], + std::make_unique(m_parent, srcHashes[0], binHashes[1], + std::move(fragBlob)))).first; + fragShader = it->second->lock(); } - D3D12ShaderPipeline* retval = new D3D12ShaderPipeline(m_parent.m_ctx, vertBlobOut.Get(), fragBlobOut.Get(), pipelineBlob.Get(), - static_cast(vtxFmt), + ID3DBlob* pipeline = pipelineBlob ? pipelineBlob->Get() : nullptr; + D3D12ShaderPipeline* retval = new D3D12ShaderPipeline(m_parent.m_ctx, std::move(vertShader), std::move(fragShader), + pipeline, static_cast(vtxFmt), srcFac, dstFac, prim, depthTest, depthWrite, backfaceCulling); - if (!pipelineBlob) - retval->m_state->GetCachedBlob(&pipelineBlob); + if (pipelineBlob && !*pipelineBlob) + retval->m_state->GetCachedBlob(&*pipelineBlob); static_cast(m_deferredData)->m_SPs.emplace_back(retval); return retval; } @@ -1877,6 +1989,13 @@ public: m_committedPools.insert(retval); return GraphicsBufferPoolToken(this, retval); } + + void _unregisterShareableShader(uint64_t srcKey, uint64_t binKey) + { + if (srcKey) + m_sourceToBinary.erase(srcKey); + m_sharedShaders.erase(binKey); + } }; thread_local D3D12Data* D3D12DataFactory::m_deferredData; diff --git a/lib/graphicsdev/GL.cpp b/lib/graphicsdev/GL.cpp index b60b193..032d31a 100644 --- a/lib/graphicsdev/GL.cpp +++ b/lib/graphicsdev/GL.cpp @@ -26,8 +26,8 @@ class GLDataFactoryImpl; struct GLShareableShader : IShareableShader { GLuint m_shader = 0; - GLShareableShader(GLDataFactoryImpl& fac, uint64_t key, GLuint s) - : IShareableShader(fac, key), m_shader(s) {} + GLShareableShader(GLDataFactoryImpl& fac, uint64_t srcKey, GLuint s) + : IShareableShader(fac, srcKey, 0), m_shader(s) {} ~GLShareableShader() { glDeleteShader(m_shader); } }; @@ -58,7 +58,10 @@ public: GraphicsDataToken commitTransaction(const FactoryCommitFunc&); GraphicsBufferPoolToken newBufferPool(); - void _unregisterShareableShader(uint64_t key) { m_sharedShaders.erase(key); } + void _unregisterShareableShader(uint64_t srcKey, uint64_t binKey) + { + m_sharedShaders.erase(srcKey); + } }; ThreadLocalPtr GLDataFactoryImpl::m_deferredData; @@ -421,21 +424,8 @@ public: ~GLShaderPipeline() { glDeleteProgram(m_prog); } GLShaderPipeline& operator=(const GLShaderPipeline&) = delete; GLShaderPipeline(const GLShaderPipeline&) = delete; - GLShaderPipeline& operator=(GLShaderPipeline&& other) - { - m_vert = std::move(other.m_vert); - m_frag = std::move(other.m_frag); - m_prog = std::move(other.m_prog); - m_sfactor = other.m_sfactor; - m_dfactor = other.m_dfactor; - m_depthTest = other.m_depthTest; - m_depthWrite = other.m_depthWrite; - m_backfaceCulling = other.m_backfaceCulling; - m_uniLocs = std::move(other.m_uniLocs); - m_drawPrim = other.m_drawPrim; - return *this; - } - GLShaderPipeline(GLShaderPipeline&& other) {*this = std::move(other);} + GLShaderPipeline& operator=(GLShaderPipeline&& other) = default; + GLShaderPipeline(GLShaderPipeline&& other) = default; GLuint bind() const { diff --git a/lib/graphicsdev/Vulkan.cpp b/lib/graphicsdev/Vulkan.cpp index 75f9774..af6c493 100644 --- a/lib/graphicsdev/Vulkan.cpp +++ b/lib/graphicsdev/Vulkan.cpp @@ -9,6 +9,7 @@ #include #include "boo/graphicsdev/GLSLMacros.hpp" #include "Common.hpp" +#include "xxhash.h" #include "logvisor/logvisor.hpp" @@ -20,6 +21,55 @@ namespace boo { static logvisor::Module Log("boo::Vulkan"); VulkanContext g_VulkanContext; +class VulkanDataFactoryImpl; + +struct VulkanShareableShader : IShareableShader +{ + VkDevice m_dev; + VkShaderModule m_shader; + VulkanShareableShader(VulkanDataFactoryImpl& fac, uint64_t srcKey, uint64_t binKey, + VkDevice dev, VkShaderModule s) + : IShareableShader(fac, srcKey, binKey), m_dev(dev), m_shader(s) {} + ~VulkanShareableShader() { vk::DestroyShaderModule(m_dev, m_shader, nullptr); } +}; + +class VulkanDataFactoryImpl : public VulkanDataFactory +{ + friend struct VulkanCommandQueue; + friend class VulkanDataFactory::Context; + IGraphicsContext* m_parent; + VulkanContext* m_ctx; + uint32_t m_drawSamples; + static ThreadLocalPtr m_deferredData; + std::unordered_set m_committedData; + std::unordered_set m_committedPools; + std::mutex m_committedMutex; + std::unordered_map> m_sharedShaders; + std::vector m_texUnis; + void destroyData(IGraphicsData*); + void destroyPool(IGraphicsBufferPool*); + void destroyAllData(); + IGraphicsBufferD* newPoolBuffer(IGraphicsBufferPool *pool, BufferUse use, + size_t stride, size_t count); + void deletePoolBuffer(IGraphicsBufferPool* p, IGraphicsBufferD* buf); +public: + std::unordered_map m_sourceToBinary; + VulkanDataFactoryImpl(IGraphicsContext* parent, VulkanContext* ctx, uint32_t drawSamples); + ~VulkanDataFactoryImpl() {destroyAllData();} + + Platform platform() const {return Platform::Vulkan;} + const SystemChar* platformName() const {return _S("Vulkan");} + + GraphicsDataToken commitTransaction(const FactoryCommitFunc&); + GraphicsBufferPoolToken newBufferPool(); + + void _unregisterShareableShader(uint64_t srcKey, uint64_t binKey) + { + if (srcKey) + m_sourceToBinary.erase(srcKey); + m_sharedShaders.erase(binKey); + } +}; static inline void ThrowIfFailed(VkResult res) { @@ -809,6 +859,7 @@ public: class VulkanGraphicsBufferD : public IGraphicsBufferD { friend class VulkanDataFactory; + friend class VulkanDataFactoryImpl; friend struct VulkanCommandQueue; struct VulkanCommandQueue* m_q; size_t m_cpuSz; @@ -1782,14 +1833,17 @@ class VulkanShaderPipeline : public IShaderPipeline VulkanContext* m_ctx; VkPipelineCache m_pipelineCache; const VulkanVertexFormat* m_vtxFmt; + VulkanShareableShader::Token m_vert; + VulkanShareableShader::Token m_frag; VulkanShaderPipeline(VulkanContext* ctx, - VkShaderModule vert, - VkShaderModule frag, + VulkanShareableShader::Token&& vert, + VulkanShareableShader::Token&& frag, VkPipelineCache pipelineCache, const VulkanVertexFormat* vtxFmt, BlendFactor srcFac, BlendFactor dstFac, Primitive prim, bool depthTest, bool depthWrite, bool backfaceCulling) - : m_ctx(ctx), m_pipelineCache(pipelineCache), m_vtxFmt(vtxFmt) + : m_ctx(ctx), m_pipelineCache(pipelineCache), m_vtxFmt(vtxFmt), + m_vert(std::move(vert)), m_frag(std::move(frag)) { VkDynamicState dynamicStateEnables[VK_DYNAMIC_STATE_RANGE_SIZE] = {}; VkPipelineDynamicStateCreateInfo dynamicState = {}; @@ -1804,7 +1858,7 @@ class VulkanShaderPipeline : public IShaderPipeline stages[0].pNext = nullptr; stages[0].flags = 0; stages[0].stage = VK_SHADER_STAGE_VERTEX_BIT; - stages[0].module = vert; + stages[0].module = m_vert.get().m_shader; stages[0].pName = "main"; stages[0].pSpecializationInfo = nullptr; @@ -1812,7 +1866,7 @@ class VulkanShaderPipeline : public IShaderPipeline stages[1].pNext = nullptr; stages[1].flags = 0; stages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT; - stages[1].module = frag; + stages[1].module = m_frag.get().m_shader; stages[1].pName = "main"; stages[1].pSpecializationInfo = nullptr; @@ -1905,7 +1959,8 @@ public: ~VulkanShaderPipeline() { vk::DestroyPipeline(m_ctx->m_dev, m_pipeline, nullptr); - vk::DestroyPipelineCache(m_ctx->m_dev, m_pipelineCache, nullptr); + if (m_pipelineCache) + vk::DestroyPipelineCache(m_ctx->m_dev, m_pipelineCache, nullptr); } VulkanShaderPipeline& operator=(const VulkanShaderPipeline&) = delete; VulkanShaderPipeline(const VulkanShaderPipeline&) = delete; @@ -2847,19 +2902,19 @@ void VulkanTextureD::unmap() m_validSlots = 0; } -void VulkanDataFactory::destroyData(IGraphicsData* d) +void VulkanDataFactoryImpl::destroyData(IGraphicsData* d) { VulkanData* data = static_cast(d); data->m_dead = true; } -void VulkanDataFactory::destroyPool(IGraphicsBufferPool* p) +void VulkanDataFactoryImpl::destroyPool(IGraphicsBufferPool* p) { VulkanPool* pool = static_cast(p); pool->m_dead = true; } -void VulkanDataFactory::destroyAllData() +void VulkanDataFactoryImpl::destroyAllData() { std::unique_lock lk(m_committedMutex); for (VulkanData* data : m_committedData) @@ -2870,7 +2925,8 @@ void VulkanDataFactory::destroyAllData() m_committedPools.clear(); } -VulkanDataFactory::VulkanDataFactory(IGraphicsContext* parent, VulkanContext* ctx, uint32_t drawSamples) +VulkanDataFactoryImpl::VulkanDataFactoryImpl(IGraphicsContext* parent, + VulkanContext* ctx, uint32_t drawSamples) : m_parent(parent), m_ctx(ctx), m_drawSamples(drawSamples) { VkDescriptorSetLayoutBinding layoutBindings[BOO_GLSL_MAX_UNIFORM_COUNT + BOO_GLSL_MAX_TEXTURE_COUNT]; @@ -2947,152 +3003,268 @@ VulkanDataFactory::VulkanDataFactory(IGraphicsContext* parent, VulkanContext* ct ThrowIfFailed(vk::CreateRenderPass(ctx->m_dev, &renderPass, nullptr, &ctx->m_pass)); } +static uint64_t CompileVert(std::vector& out, const char* vertSource, uint64_t srcKey, + VulkanDataFactoryImpl& factory) +{ + const EShMessages messages = EShMessages(EShMsgSpvRules | EShMsgVulkanRules); + glslang::TShader vs(EShLangVertex); + vs.setStrings(&vertSource, 1); + if (!vs.parse(&glslang::DefaultTBuiltInResource, 110, false, messages)) + { + printf("%s\n", vertSource); + Log.report(logvisor::Fatal, "unable to compile vertex shader\n%s", vs.getInfoLog()); + } + + glslang::TProgram prog; + prog.addShader(&vs); + if (!prog.link(messages)) + { + Log.report(logvisor::Fatal, "unable to link shader program\n%s", prog.getInfoLog()); + } + glslang::GlslangToSpv(*prog.getIntermediate(EShLangVertex), out); + //spv::Disassemble(std::cerr, out); + + XXH64_state_t hashState; + XXH64_reset(&hashState, 0); + XXH64_update(&hashState, out.data(), out.size() * sizeof(unsigned int)); + uint64_t binKey = XXH64_digest(&hashState); + factory.m_sourceToBinary[srcKey] = binKey; + return binKey; +} + +static uint64_t CompileFrag(std::vector& out, const char* fragSource, uint64_t srcKey, + VulkanDataFactoryImpl& factory) +{ + const EShMessages messages = EShMessages(EShMsgSpvRules | EShMsgVulkanRules); + glslang::TShader fs(EShLangFragment); + fs.setStrings(&fragSource, 1); + if (!fs.parse(&glslang::DefaultTBuiltInResource, 110, false, messages)) + { + printf("%s\n", fragSource); + Log.report(logvisor::Fatal, "unable to compile fragment shader\n%s", fs.getInfoLog()); + } + + glslang::TProgram prog; + prog.addShader(&fs); + if (!prog.link(messages)) + { + Log.report(logvisor::Fatal, "unable to link shader program\n%s", prog.getInfoLog()); + } + glslang::GlslangToSpv(*prog.getIntermediate(EShLangFragment), out); + //spv::Disassemble(std::cerr, out); + + XXH64_state_t hashState; + XXH64_reset(&hashState, 0); + XXH64_update(&hashState, out.data(), out.size() * sizeof(unsigned int)); + uint64_t binKey = XXH64_digest(&hashState); + factory.m_sourceToBinary[srcKey] = binKey; + return binKey; +} + IShaderPipeline* VulkanDataFactory::Context::newShaderPipeline (const char* vertSource, const char* fragSource, - std::vector& vertBlobOut, std::vector& fragBlobOut, - std::vector& pipelineBlob, IVertexFormat* vtxFmt, + std::vector* vertBlobOut, std::vector* fragBlobOut, + std::vector* pipelineBlob, IVertexFormat* vtxFmt, BlendFactor srcFac, BlendFactor dstFac, Primitive prim, bool depthTest, bool depthWrite, bool backfaceCulling) { - if (vertBlobOut.empty() || fragBlobOut.empty()) + VulkanDataFactoryImpl& factory = static_cast(m_parent); + + XXH64_state_t hashState; + uint64_t srcHashes[2] = {}; + uint64_t binHashes[2] = {}; + XXH64_reset(&hashState, 0); + if (vertSource) { - const EShMessages messages = EShMessages(EShMsgSpvRules | EShMsgVulkanRules); - - //printf("%s\n", vertSource); - //printf("%s\n", fragSource); - - glslang::TShader vs(EShLangVertex); - vs.setStrings(&vertSource, 1); - if (!vs.parse(&glslang::DefaultTBuiltInResource, 110, false, messages)) - { - printf("%s\n", vertSource); - Log.report(logvisor::Fatal, "unable to compile vertex shader\n%s", vs.getInfoLog()); - return nullptr; - } - - glslang::TShader fs(EShLangFragment); - fs.setStrings(&fragSource, 1); - if (!fs.parse(&glslang::DefaultTBuiltInResource, 110, false, messages)) - { - printf("%s\n", fragSource); - Log.report(logvisor::Fatal, "unable to compile fragment shader\n%s", fs.getInfoLog()); - return nullptr; - } - - glslang::TProgram prog; - prog.addShader(&vs); - prog.addShader(&fs); - if (!prog.link(messages)) - { - Log.report(logvisor::Fatal, "unable to link shader program\n%s", prog.getInfoLog()); - return nullptr; - } - if (vertBlobOut.empty()) - { - glslang::GlslangToSpv(*prog.getIntermediate(EShLangVertex), vertBlobOut); - //spv::Disassemble(std::cerr, vertBlobOut); - } - if (fragBlobOut.empty()) - { - glslang::GlslangToSpv(*prog.getIntermediate(EShLangFragment), fragBlobOut); - //spv::Disassemble(std::cerr, fragBlobOut); - } + XXH64_update(&hashState, vertSource, strlen(vertSource)); + srcHashes[0] = XXH64_digest(&hashState); + auto binSearch = factory.m_sourceToBinary.find(srcHashes[0]); + if (binSearch != factory.m_sourceToBinary.cend()) + binHashes[0] = binSearch->second; } + else if (vertBlobOut && vertBlobOut->size()) + { + XXH64_update(&hashState, vertBlobOut->data(), vertBlobOut->size() * sizeof(unsigned int)); + binHashes[0] = XXH64_digest(&hashState); + } + XXH64_reset(&hashState, 0); + if (fragSource) + { + XXH64_update(&hashState, fragSource, strlen(fragSource)); + srcHashes[1] = XXH64_digest(&hashState); + auto binSearch = factory.m_sourceToBinary.find(srcHashes[1]); + if (binSearch != factory.m_sourceToBinary.cend()) + binHashes[1] = binSearch->second; + } + else if (fragBlobOut && fragBlobOut->size()) + { + XXH64_update(&hashState, fragBlobOut->data(), fragBlobOut->size() * sizeof(unsigned int)); + binHashes[1] = XXH64_digest(&hashState); + } + + if (vertBlobOut && vertBlobOut->empty()) + binHashes[0] = CompileVert(*vertBlobOut, vertSource, srcHashes[0], factory); + + if (fragBlobOut && fragBlobOut->empty()) + binHashes[1] = CompileFrag(*fragBlobOut, fragSource, srcHashes[1], factory); VkShaderModuleCreateInfo smCreateInfo = {}; smCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; smCreateInfo.pNext = nullptr; smCreateInfo.flags = 0; - smCreateInfo.codeSize = vertBlobOut.size() * sizeof(unsigned int); - smCreateInfo.pCode = vertBlobOut.data(); - VkShaderModule vertModule; - ThrowIfFailed(vk::CreateShaderModule(m_parent.m_ctx->m_dev, &smCreateInfo, nullptr, &vertModule)); + VulkanShareableShader::Token vertShader; + VulkanShareableShader::Token fragShader; + auto vertFind = binHashes[0] ? factory.m_sharedShaders.find(binHashes[0]) : + factory.m_sharedShaders.end(); + if (vertFind != factory.m_sharedShaders.end()) + { + vertShader = vertFind->second->lock(); + } + else + { + std::vector vertBlob; + const std::vector* useVertBlob; + if (vertBlobOut) + { + useVertBlob = vertBlobOut; + } + else + { + useVertBlob = &vertBlob; + binHashes[0] = CompileVert(vertBlob, vertSource, srcHashes[0], factory); + } - smCreateInfo.codeSize = fragBlobOut.size() * sizeof(unsigned int); - smCreateInfo.pCode = fragBlobOut.data(); - VkShaderModule fragModule; - ThrowIfFailed(vk::CreateShaderModule(m_parent.m_ctx->m_dev, &smCreateInfo, nullptr, &fragModule)); + smCreateInfo.codeSize = useVertBlob->size() * sizeof(unsigned int); + smCreateInfo.pCode = useVertBlob->data(); + VkShaderModule vertModule; + ThrowIfFailed(vk::CreateShaderModule(factory.m_ctx->m_dev, &smCreateInfo, nullptr, &vertModule)); - VkPipelineCacheCreateInfo cacheDataInfo = {}; - cacheDataInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO; - cacheDataInfo.pNext = nullptr; - cacheDataInfo.initialDataSize = pipelineBlob.size(); - if (cacheDataInfo.initialDataSize) - cacheDataInfo.pInitialData = pipelineBlob.data(); + auto it = + factory.m_sharedShaders.emplace(std::make_pair(binHashes[0], + std::make_unique(factory, srcHashes[0], binHashes[0], + factory.m_ctx->m_dev, vertModule))).first; + vertShader = it->second->lock(); + } + auto fragFind = binHashes[1] ? factory.m_sharedShaders.find(binHashes[1]) : + factory.m_sharedShaders.end(); + if (fragFind != factory.m_sharedShaders.end()) + { + fragShader = fragFind->second->lock(); + } + else + { + std::vector fragBlob; + const std::vector* useFragBlob; + if (fragBlobOut) + { + useFragBlob = fragBlobOut; + } + else + { + useFragBlob = &fragBlob; + binHashes[1] = CompileFrag(fragBlob, fragSource, srcHashes[1], factory); + } - VkPipelineCache pipelineCache; - ThrowIfFailed(vk::CreatePipelineCache(m_parent.m_ctx->m_dev, &cacheDataInfo, nullptr, &pipelineCache)); + smCreateInfo.codeSize = useFragBlob->size() * sizeof(unsigned int); + smCreateInfo.pCode = useFragBlob->data(); + VkShaderModule fragModule; + ThrowIfFailed(vk::CreateShaderModule(factory.m_ctx->m_dev, &smCreateInfo, nullptr, &fragModule)); - VulkanShaderPipeline* retval = new VulkanShaderPipeline(m_parent.m_ctx, vertModule, fragModule, pipelineCache, - static_cast(vtxFmt), + auto it = + factory.m_sharedShaders.emplace(std::make_pair(binHashes[1], + std::make_unique(factory, srcHashes[1], binHashes[1], + factory.m_ctx->m_dev, fragModule))).first; + fragShader = it->second->lock(); + } + + + VkPipelineCache pipelineCache = VK_NULL_HANDLE; + if (pipelineBlob) + { + VkPipelineCacheCreateInfo cacheDataInfo = {}; + cacheDataInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO; + cacheDataInfo.pNext = nullptr; + + cacheDataInfo.initialDataSize = pipelineBlob->size(); + if (cacheDataInfo.initialDataSize) + cacheDataInfo.pInitialData = pipelineBlob->data(); + + ThrowIfFailed(vk::CreatePipelineCache(factory.m_ctx->m_dev, &cacheDataInfo, nullptr, &pipelineCache)); + } + + VulkanShaderPipeline* retval = new VulkanShaderPipeline(factory.m_ctx, std::move(vertShader), std::move(fragShader), + pipelineCache, static_cast(vtxFmt), srcFac, dstFac, prim, depthTest, depthWrite, backfaceCulling); - if (pipelineBlob.empty()) + if (pipelineBlob && pipelineBlob->empty()) { size_t cacheSz = 0; - ThrowIfFailed(vk::GetPipelineCacheData(m_parent.m_ctx->m_dev, pipelineCache, &cacheSz, nullptr)); + ThrowIfFailed(vk::GetPipelineCacheData(factory.m_ctx->m_dev, pipelineCache, &cacheSz, nullptr)); if (cacheSz) { - pipelineBlob.resize(cacheSz); - ThrowIfFailed(vk::GetPipelineCacheData(m_parent.m_ctx->m_dev, pipelineCache, &cacheSz, pipelineBlob.data())); - pipelineBlob.resize(cacheSz); + pipelineBlob->resize(cacheSz); + ThrowIfFailed(vk::GetPipelineCacheData(factory.m_ctx->m_dev, pipelineCache, &cacheSz, pipelineBlob->data())); + pipelineBlob->resize(cacheSz); } } - vk::DestroyShaderModule(m_parent.m_ctx->m_dev, fragModule, nullptr); - vk::DestroyShaderModule(m_parent.m_ctx->m_dev, vertModule, nullptr); - - static_cast(m_deferredData.get())->m_SPs.emplace_back(retval); + static_cast(VulkanDataFactoryImpl::m_deferredData.get())->m_SPs.emplace_back(retval); return retval; } IGraphicsBufferS* VulkanDataFactory::Context::newStaticBuffer(BufferUse use, const void* data, size_t stride, size_t count) { - VulkanGraphicsBufferS* retval = new VulkanGraphicsBufferS(use, m_parent.m_ctx, data, stride, count); - static_cast(m_deferredData.get())->m_SBufs.emplace_back(retval); + VulkanDataFactoryImpl& factory = static_cast(m_parent); + VulkanGraphicsBufferS* retval = new VulkanGraphicsBufferS(use, factory.m_ctx, data, stride, count); + static_cast(VulkanDataFactoryImpl::m_deferredData.get())->m_SBufs.emplace_back(retval); return retval; } IGraphicsBufferD* VulkanDataFactory::Context::newDynamicBuffer(BufferUse use, size_t stride, size_t count) { - VulkanCommandQueue* q = static_cast(m_parent.m_parent->getCommandQueue()); - VulkanGraphicsBufferD* retval = new VulkanGraphicsBufferD(q, use, m_parent.m_ctx, stride, count); - static_cast(m_deferredData.get())->m_DBufs.emplace_back(retval); + VulkanDataFactoryImpl& factory = static_cast(m_parent); + VulkanCommandQueue* q = static_cast(factory.m_parent->getCommandQueue()); + VulkanGraphicsBufferD* retval = new VulkanGraphicsBufferD(q, use, factory.m_ctx, stride, count); + static_cast(VulkanDataFactoryImpl::m_deferredData.get())->m_DBufs.emplace_back(retval); return retval; } ITextureS* VulkanDataFactory::Context::newStaticTexture(size_t width, size_t height, size_t mips, TextureFormat fmt, const void* data, size_t sz) { - VulkanTextureS* retval = new VulkanTextureS(m_parent.m_ctx, width, height, mips, fmt, data, sz); - static_cast(m_deferredData.get())->m_STexs.emplace_back(retval); + VulkanDataFactoryImpl& factory = static_cast(m_parent); + VulkanTextureS* retval = new VulkanTextureS(factory.m_ctx, width, height, mips, fmt, data, sz); + static_cast(VulkanDataFactoryImpl::m_deferredData.get())->m_STexs.emplace_back(retval); return retval; } ITextureSA* VulkanDataFactory::Context::newStaticArrayTexture(size_t width, size_t height, size_t layers, size_t mips, TextureFormat fmt, const void* data, size_t sz) { - VulkanTextureSA* retval = new VulkanTextureSA(m_parent.m_ctx, width, height, layers, mips, fmt, data, sz); - static_cast(m_deferredData.get())->m_SATexs.emplace_back(retval); + VulkanDataFactoryImpl& factory = static_cast(m_parent); + VulkanTextureSA* retval = new VulkanTextureSA(factory.m_ctx, width, height, layers, mips, fmt, data, sz); + static_cast(VulkanDataFactoryImpl::m_deferredData.get())->m_SATexs.emplace_back(retval); return retval; } ITextureD* VulkanDataFactory::Context::newDynamicTexture(size_t width, size_t height, TextureFormat fmt) { - VulkanCommandQueue* q = static_cast(m_parent.m_parent->getCommandQueue()); - VulkanTextureD* retval = new VulkanTextureD(q, m_parent.m_ctx, width, height, fmt); - static_cast(m_deferredData.get())->m_DTexs.emplace_back(retval); + VulkanDataFactoryImpl& factory = static_cast(m_parent); + VulkanCommandQueue* q = static_cast(factory.m_parent->getCommandQueue()); + VulkanTextureD* retval = new VulkanTextureD(q, factory.m_ctx, width, height, fmt); + static_cast(VulkanDataFactoryImpl::m_deferredData.get())->m_DTexs.emplace_back(retval); return retval; } ITextureR* VulkanDataFactory::Context::newRenderTexture(size_t width, size_t height, bool enableShaderColorBinding, bool enableShaderDepthBinding) { - VulkanCommandQueue* q = static_cast(m_parent.m_parent->getCommandQueue()); - VulkanTextureR* retval = new VulkanTextureR(m_parent.m_ctx, q, width, height, m_parent.m_drawSamples, + VulkanDataFactoryImpl& factory = static_cast(m_parent); + VulkanCommandQueue* q = static_cast(factory.m_parent->getCommandQueue()); + VulkanTextureR* retval = new VulkanTextureR(factory.m_ctx, q, width, height, factory.m_drawSamples, enableShaderColorBinding, enableShaderDepthBinding); - static_cast(m_deferredData.get())->m_RTexs.emplace_back(retval); + static_cast(VulkanDataFactoryImpl::m_deferredData.get())->m_RTexs.emplace_back(retval); return retval; } @@ -3101,7 +3273,7 @@ IVertexFormat* VulkanDataFactory::Context::newVertexFormat(size_t elementCount, size_t baseVert, size_t baseInst) { VulkanVertexFormat* retval = new struct VulkanVertexFormat(elementCount, elements); - static_cast(m_deferredData.get())->m_VFmts.emplace_back(retval); + static_cast(VulkanDataFactoryImpl::m_deferredData.get())->m_VFmts.emplace_back(retval); return retval; } @@ -3113,16 +3285,17 @@ IShaderDataBinding* VulkanDataFactory::Context::newShaderDataBinding(IShaderPipe size_t texCount, ITexture** texs, size_t baseVert, size_t baseInst) { - VulkanData* d = static_cast(m_deferredData.get()); + VulkanDataFactoryImpl& factory = static_cast(m_parent); + VulkanData* d = static_cast(VulkanDataFactoryImpl::m_deferredData.get()); VulkanShaderDataBinding* retval = - new VulkanShaderDataBinding(d, m_parent.m_ctx, pipeline, vbuf, instVbuf, ibuf, + new VulkanShaderDataBinding(d, factory.m_ctx, pipeline, vbuf, instVbuf, ibuf, ubufCount, ubufs, ubufOffs, ubufSizes, texCount, texs, baseVert, baseInst); d->m_SBinds.emplace_back(retval); return retval; } -GraphicsDataToken VulkanDataFactory::commitTransaction +GraphicsDataToken VulkanDataFactoryImpl::commitTransaction (const std::function& trans) { if (m_deferredData.get()) @@ -3245,8 +3418,8 @@ GraphicsDataToken VulkanDataFactory::commitTransaction return GraphicsDataToken(this, retval); } -IGraphicsBufferD* VulkanDataFactory::newPoolBuffer(IGraphicsBufferPool* p, BufferUse use, - size_t stride, size_t count) +IGraphicsBufferD* VulkanDataFactoryImpl::newPoolBuffer(IGraphicsBufferPool* p, BufferUse use, + size_t stride, size_t count) { VulkanPool* pool = static_cast(p); VulkanCommandQueue* q = static_cast(m_parent->getCommandQueue()); @@ -3277,7 +3450,7 @@ IGraphicsBufferD* VulkanDataFactory::newPoolBuffer(IGraphicsBufferPool* p, Buffe return retval; } -void VulkanDataFactory::deletePoolBuffer(IGraphicsBufferPool* p, IGraphicsBufferD* buf) +void VulkanDataFactoryImpl::deletePoolBuffer(IGraphicsBufferPool* p, IGraphicsBufferD* buf) { VulkanPool* pool = static_cast(p); auto search = pool->m_DBufs.find(static_cast(buf)); @@ -3285,7 +3458,7 @@ void VulkanDataFactory::deletePoolBuffer(IGraphicsBufferPool* p, IGraphicsBuffer search->second.m_dead = true; } -GraphicsBufferPoolToken VulkanDataFactory::newBufferPool() +GraphicsBufferPoolToken VulkanDataFactoryImpl::newBufferPool() { std::unique_lock lk(m_committedMutex); VulkanPool* retval = new VulkanPool(m_ctx); @@ -3293,7 +3466,7 @@ GraphicsBufferPoolToken VulkanDataFactory::newBufferPool() return GraphicsBufferPoolToken(this, retval); } -ThreadLocalPtr VulkanDataFactory::m_deferredData; +ThreadLocalPtr VulkanDataFactoryImpl::m_deferredData; void VulkanCommandQueue::execute() { @@ -3301,7 +3474,7 @@ void VulkanCommandQueue::execute() return; /* Stage dynamic uploads */ - VulkanDataFactory* gfxF = static_cast(m_parent->getDataFactory()); + VulkanDataFactoryImpl* gfxF = static_cast(m_parent->getDataFactory()); std::unique_lock datalk(gfxF->m_committedMutex); for (VulkanData* d : gfxF->m_committedData) { @@ -3452,5 +3625,10 @@ IGraphicsCommandQueue* _NewVulkanCommandQueue(VulkanContext* ctx, VulkanContext: return new struct VulkanCommandQueue(ctx, windowCtx, parent); } +IGraphicsDataFactory* _NewVulkanDataFactory(IGraphicsContext* parent, VulkanContext* ctx, + uint32_t drawSamples) +{ + return new class VulkanDataFactoryImpl(parent, ctx, drawSamples); +} } diff --git a/lib/win/WindowWin32.cpp b/lib/win/WindowWin32.cpp index db4932a..c74b06b 100644 --- a/lib/win/WindowWin32.cpp +++ b/lib/win/WindowWin32.cpp @@ -41,6 +41,8 @@ IGraphicsDataFactory* _NewGLDataFactory(IGraphicsContext* parent, uint32_t drawS IGraphicsCommandQueue* _NewVulkanCommandQueue(VulkanContext* ctx, VulkanContext::Window* windowCtx, IGraphicsContext* parent); +IGraphicsDataFactory* _NewVulkanDataFactory(IGraphicsContext* parent, VulkanContext* ctx, + uint32_t drawSamples); #endif struct GraphicsContextWin32 : IGraphicsContext @@ -597,7 +599,7 @@ public: m_ctx->initSwapChain(*m_windowCtx, m_surface, m_format, m_colorspace); - m_dataFactory = new class VulkanDataFactory(this, m_ctx, m_sampleCount); + m_dataFactory = _NewVulkanDataFactory(this, m_ctx, m_sampleCount); m_commandQueue = _NewVulkanCommandQueue(m_ctx, m_ctx->m_windows[m_parentWindow].get(), this); return true; } diff --git a/lib/x11/WindowXlib.cpp b/lib/x11/WindowXlib.cpp index 2b93680..8c1cf38 100644 --- a/lib/x11/WindowXlib.cpp +++ b/lib/x11/WindowXlib.cpp @@ -119,6 +119,8 @@ IGraphicsDataFactory* _NewGLDataFactory(IGraphicsContext* parent, uint32_t drawS IGraphicsCommandQueue* _NewVulkanCommandQueue(VulkanContext* ctx, VulkanContext::Window* windowCtx, IGraphicsContext* parent); +IGraphicsDataFactory* _NewVulkanDataFactory(IGraphicsContext* parent, VulkanContext* ctx, + uint32_t drawSamples); #endif void _XlibUpdateLastGlxCtx(GLXContext lastGlxCtx); void GLXExtensionCheck(); @@ -828,7 +830,7 @@ public: }); initcv.wait(outerLk); - m_dataFactory = new class VulkanDataFactory(this, m_ctx, m_drawSamples); + m_dataFactory = _NewVulkanDataFactory(Sthis, m_ctx, m_drawSamples); m_commandQueue = _NewVulkanCommandQueue(m_ctx, m_ctx->m_windows[m_parentWindow].get(), this); return true; diff --git a/test/main.cpp b/test/main.cpp index 98e0126..b61b0f4 100644 --- a/test/main.cpp +++ b/test/main.cpp @@ -369,10 +369,7 @@ struct TestApplicationCallback : IApplicationCallback " return tex.Sample(samp, d.out_uv);\n" "}\n"; - ComPtr vsCompile; - ComPtr psCompile; - ComPtr cachedPipeline; - pipeline = d3dF.newShaderPipeline(VS, PS, vsCompile, psCompile, cachedPipeline, vfmt, + pipeline = d3dF.newShaderPipeline(VS, PS, nullptr, nullptr, nullptr, vfmt, BlendFactor::One, BlendFactor::Zero, Primitive::TriStrips, true, true, false); }