From 5303b9bda1bb55381da0d304f5382221fb762bfc Mon Sep 17 00:00:00 2001 From: Jack Andersen Date: Sun, 11 Sep 2016 18:52:55 -1000 Subject: [PATCH] Dramatic shader cache performance improvement --- hecl/include/hecl/Runtime.hpp | 35 +++-- hecl/lib/Runtime/ShaderCacheManager.cpp | 188 +++++++++++++++++++----- hecl/test/main.cpp | 24 +-- 3 files changed, 186 insertions(+), 61 deletions(-) diff --git a/hecl/include/hecl/Runtime.hpp b/hecl/include/hecl/Runtime.hpp index 49a17752e..563367305 100644 --- a/hecl/include/hecl/Runtime.hpp +++ b/hecl/include/hecl/Runtime.hpp @@ -195,6 +195,15 @@ public: virtual ~IShaderBackendFactory() {} }; +/** + * @brief Stores token and pipeline set for sharing with ref-counting + */ +struct ShaderPipelines +{ + boo::GraphicsDataToken m_token; + std::vector m_pipelines; +}; + /** * @brief Maintains index/data file pair containing platform-dependent cached shader data */ @@ -218,6 +227,8 @@ class ShaderCacheManager }; std::vector m_entries; std::unordered_map m_entryLookup; + std::unordered_map> m_pipelineLookup; + uint64_t m_timeHash = 0; void bootstrapIndex(); ShaderCachedData lookupData(const Hash& hash); @@ -239,18 +250,18 @@ public: * for encoding the pipeline state. This must be called before building shaders */ void setRenderTargetSamples(unsigned samps) {m_factory->m_rtHint = samps;} - boo::IShaderPipeline* buildShader(const ShaderTag& tag, const std::string& source, - const std::string& diagName, - boo::IGraphicsDataFactory::Context& ctx); - boo::IShaderPipeline* buildShader(const ShaderTag& tag, const hecl::Frontend::IR& ir, - const std::string& diagName, - boo::IGraphicsDataFactory::Context& ctx); - std::vector buildExtendedShader(const ShaderTag& tag, const std::string& source, - const std::string& diagName, - boo::IGraphicsDataFactory::Context& ctx); - std::vector buildExtendedShader(const ShaderTag& tag, const hecl::Frontend::IR& ir, - const std::string& diagName, - boo::IGraphicsDataFactory::Context& ctx); + std::shared_ptr buildShader(const ShaderTag& tag, const std::string& source, + const std::string& diagName, + boo::IGraphicsDataFactory& factory); + std::shared_ptr buildShader(const ShaderTag& tag, const hecl::Frontend::IR& ir, + const std::string& diagName, + boo::IGraphicsDataFactory& factory); + std::shared_ptr buildExtendedShader(const ShaderTag& tag, const std::string& source, + const std::string& diagName, + boo::IGraphicsDataFactory& factory); + std::shared_ptr buildExtendedShader(const ShaderTag& tag, const hecl::Frontend::IR& ir, + const std::string& diagName, + boo::IGraphicsDataFactory& factory); }; /** diff --git a/hecl/lib/Runtime/ShaderCacheManager.cpp b/hecl/lib/Runtime/ShaderCacheManager.cpp index d54ba9072..a8a25b6ea 100644 --- a/hecl/lib/Runtime/ShaderCacheManager.cpp +++ b/hecl/lib/Runtime/ShaderCacheManager.cpp @@ -363,40 +363,98 @@ ShaderCacheManager::buildFromCache(const ShaderCachedData& foundData, return m_factory->buildShaderFromCache(foundData, ctx); } -boo::IShaderPipeline* +std::shared_ptr ShaderCacheManager::buildShader(const ShaderTag& tag, const std::string& source, const std::string& diagName, - boo::IGraphicsDataFactory::Context& ctx) + boo::IGraphicsDataFactory& factory) { - boo::IShaderPipeline* ret; + auto search = m_pipelineLookup.find(tag); + if (search != m_pipelineLookup.cend()) + if (auto ret = search->second.lock()) + return ret; + + std::shared_ptr ret = std::make_shared(); ShaderCachedData foundData = lookupData(tag); if (foundData) { - ret = buildFromCache(foundData, ctx); - if (ret) + ret->m_token = factory.commitTransaction([&](boo::IGraphicsDataFactory::Context& ctx) -> bool + { + Log.report(logvisor::Info, "building cached shader '%s' %016llX", diagName.c_str(), tag.val64()); + boo::IShaderPipeline* build = buildFromCache(foundData, ctx); + if (build) + { + ret->m_pipelines.push_back(build); + return true; + } + return false; + }); + + if (ret->m_token) + { + m_pipelineLookup[tag] = ret; return ret; + } Log.report(logvisor::Warning, "invalid cache read, rebuilding shader '%s'", diagName.c_str()); } - hecl::Frontend::IR ir = FE.compileSource(source, diagName); - return buildShader(tag, ir, diagName, ctx); + + ret->m_token = factory.commitTransaction([&](boo::IGraphicsDataFactory::Context& ctx) -> bool + { + hecl::Frontend::IR ir = FE.compileSource(source, diagName); + Log.report(logvisor::Info, "building shader '%s' %016llX", diagName.c_str(), tag.val64()); + FE.getDiagnostics().reset(diagName); + boo::IShaderPipeline* build; + addData(m_factory->buildShaderFromIR(tag, ir, FE.getDiagnostics(), ctx, build)); + ret->m_pipelines.push_back(build); + return true; + }); + m_pipelineLookup[tag] = ret; + return ret; } -boo::IShaderPipeline* +std::shared_ptr ShaderCacheManager::buildShader(const ShaderTag& tag, const hecl::Frontend::IR& ir, const std::string& diagName, - boo::IGraphicsDataFactory::Context& ctx) + boo::IGraphicsDataFactory& factory) { - boo::IShaderPipeline* ret; + auto search = m_pipelineLookup.find(tag); + if (search != m_pipelineLookup.cend()) + if (auto ret = search->second.lock()) + return ret; + + std::shared_ptr ret = std::make_shared(); ShaderCachedData foundData = lookupData(tag); if (foundData) { - ret = buildFromCache(foundData, ctx); - if (ret) + ret->m_token = factory.commitTransaction([&](boo::IGraphicsDataFactory::Context& ctx) -> bool + { + Log.report(logvisor::Info, "building cached shader '%s' %016llX", diagName.c_str(), tag.val64()); + boo::IShaderPipeline* build = buildFromCache(foundData, ctx); + if (build) + { + ret->m_pipelines.push_back(build); + return true; + } + return false; + }); + + if (ret->m_token) + { + m_pipelineLookup[tag] = ret; return ret; + } Log.report(logvisor::Warning, "invalid cache read, rebuilding shader '%s'", diagName.c_str()); } - FE.getDiagnostics().reset(diagName); - addData(m_factory->buildShaderFromIR(tag, ir, FE.getDiagnostics(), ctx, ret)); + + ret->m_token = factory.commitTransaction([&](boo::IGraphicsDataFactory::Context& ctx) -> bool + { + Log.report(logvisor::Info, "building shader '%s' %016llX", diagName.c_str(), tag.val64()); + FE.getDiagnostics().reset(diagName); + boo::IShaderPipeline* build; + addData(m_factory->buildShaderFromIR(tag, ir, FE.getDiagnostics(), ctx, build)); + ret->m_pipelines.push_back(build); + return true; + }); + m_pipelineLookup[tag] = ret; return ret; } @@ -415,48 +473,104 @@ ShaderCacheManager::buildExtendedFromCache(const ShaderCachedData& foundData, return shaders; } -std::vector +std::shared_ptr ShaderCacheManager::buildExtendedShader(const ShaderTag& tag, const std::string& source, const std::string& diagName, - boo::IGraphicsDataFactory::Context& ctx) + boo::IGraphicsDataFactory& factory) { - std::vector shaders; + auto search = m_pipelineLookup.find(tag); + if (search != m_pipelineLookup.cend()) + if (auto ret = search->second.lock()) + return ret; + + std::shared_ptr ret = std::make_shared(); ShaderCachedData foundData = lookupData(tag); if (foundData) { - shaders = buildExtendedFromCache(foundData, ctx); - if (shaders.size()) - return shaders; + ret->m_token = factory.commitTransaction([&](boo::IGraphicsDataFactory::Context& ctx) -> bool + { + Log.report(logvisor::Info, "building cached shader '%s' %016llX", diagName.c_str(), tag.val64()); + ret->m_pipelines = buildExtendedFromCache(foundData, ctx); + if (ret->m_pipelines.size()) + return true; + return false; + }); + + if (ret->m_token) + { + m_pipelineLookup[tag] = ret; + return ret; + } Log.report(logvisor::Warning, "invalid cache read, rebuilding shader '%s'", diagName.c_str()); } + hecl::Frontend::IR ir = FE.compileSource(source, diagName); - return buildExtendedShader(tag, ir, diagName, ctx); + + ret->m_token = factory.commitTransaction([&](boo::IGraphicsDataFactory::Context& ctx) -> bool + { + ret->m_pipelines.reserve(m_extensions.m_extensionSlots.size()); + FE.getDiagnostics().reset(diagName); + Log.report(logvisor::Info, "building shader '%s' %016llX", diagName.c_str(), tag.val64()); + ShaderCachedData data = + m_factory->buildExtendedShaderFromIR(tag, ir, FE.getDiagnostics(), m_extensions.m_extensionSlots, ctx, + [&](boo::IShaderPipeline* shader){ret->m_pipelines.push_back(shader);}); + if (ret->m_pipelines.size() != m_extensions.m_extensionSlots.size()) + Log.report(logvisor::Fatal, "buildShaderFromIR returned %" PRISize " times, expected %" PRISize, + ret->m_pipelines.size(), m_extensions.m_extensionSlots.size()); + addData(data); + return true; + }); + m_pipelineLookup[tag] = ret; + return ret; } -std::vector +std::shared_ptr ShaderCacheManager::buildExtendedShader(const ShaderTag& tag, const hecl::Frontend::IR& ir, const std::string& diagName, - boo::IGraphicsDataFactory::Context& ctx) + boo::IGraphicsDataFactory& factory) { - std::vector shaders; + auto search = m_pipelineLookup.find(tag); + if (search != m_pipelineLookup.cend()) + if (auto ret = search->second.lock()) + return ret; + + std::shared_ptr ret = std::make_shared(); ShaderCachedData foundData = lookupData(tag); if (foundData) { - shaders = buildExtendedFromCache(foundData, ctx); - if (shaders.size()) - return shaders; + ret->m_token = factory.commitTransaction([&](boo::IGraphicsDataFactory::Context& ctx) -> bool + { + Log.report(logvisor::Info, "building cached shader '%s' %016llX", diagName.c_str(), tag.val64()); + ret->m_pipelines = buildExtendedFromCache(foundData, ctx); + if (ret->m_pipelines.size()) + return true; + return false; + }); + + if (ret->m_token) + { + m_pipelineLookup[tag] = ret; + return ret; + } Log.report(logvisor::Warning, "invalid cache read, rebuilding shader '%s'", diagName.c_str()); } - shaders.reserve(m_extensions.m_extensionSlots.size()); - FE.getDiagnostics().reset(diagName); - ShaderCachedData data = - m_factory->buildExtendedShaderFromIR(tag, ir, FE.getDiagnostics(), m_extensions.m_extensionSlots, ctx, - [&](boo::IShaderPipeline* shader){shaders.push_back(shader);}); - if (shaders.size() != m_extensions.m_extensionSlots.size()) - Log.report(logvisor::Fatal, "buildShaderFromIR returned %" PRISize " times, expected %" PRISize, - shaders.size(), m_extensions.m_extensionSlots.size()); - addData(data); - return shaders; + + ret->m_token = factory.commitTransaction([&](boo::IGraphicsDataFactory::Context& ctx) -> bool + { + ret->m_pipelines.reserve(m_extensions.m_extensionSlots.size()); + FE.getDiagnostics().reset(diagName); + Log.report(logvisor::Info, "building shader '%s' %016llX", diagName.c_str(), tag.val64()); + ShaderCachedData data = + m_factory->buildExtendedShaderFromIR(tag, ir, FE.getDiagnostics(), m_extensions.m_extensionSlots, ctx, + [&](boo::IShaderPipeline* shader){ret->m_pipelines.push_back(shader);}); + if (ret->m_pipelines.size() != m_extensions.m_extensionSlots.size()) + Log.report(logvisor::Fatal, "buildShaderFromIR returned %" PRISize " times, expected %" PRISize, + ret->m_pipelines.size(), m_extensions.m_extensionSlots.size()); + addData(data); + return true; + }); + m_pipelineLookup[tag] = ret; + return ret; } } diff --git a/hecl/test/main.cpp b/hecl/test/main.cpp index e7fef6f8a..1002512f7 100644 --- a/hecl/test/main.cpp +++ b/hecl/test/main.cpp @@ -74,23 +74,23 @@ struct HECLApplicationCallback : boo::IApplicationCallback std::unique_lock innerLk(initmt); boo::IGraphicsDataFactory* gfxF = m_mainWindow->getLoadContextDataFactory(); + /* HECL managers */ + hecl::Runtime::FileStoreManager fileMgr(app->getUniqueName()); + hecl::Runtime::ShaderCacheManager shaderMgr(fileMgr, gfxF); + + /* Compile HECL shader */ + static std::string testShader = "HECLOpaque(Texture(0, UV(0)))"; + //static std::string testShader = "HECLOpaque(vec4(1.0,1.0,1.0,1.0))"; + hecl::Runtime::ShaderTag testShaderTag(testShader, 0, 1, 0, 0, 0, boo::Primitive::TriStrips, false, false, false); + std::shared_ptr testShaderObj = + shaderMgr.buildShader(testShaderTag, testShader, "testShader", *gfxF); + boo::GraphicsDataToken data = gfxF->commitTransaction([&](boo::IGraphicsDataFactory::Context& ctx) -> bool { boo::SWindowRect mainWindowRect = m_mainWindow->getWindowFrame(); renderTex = ctx.newRenderTexture(mainWindowRect.size[0], mainWindowRect.size[1], false, false); - /* HECL managers */ - hecl::Runtime::FileStoreManager fileMgr(app->getUniqueName()); - hecl::Runtime::ShaderCacheManager shaderMgr(fileMgr, gfxF); - - /* Compile HECL shader */ - static std::string testShader = "HECLOpaque(Texture(0, UV(0)))"; - //static std::string testShader = "HECLOpaque(vec4(1.0,1.0,1.0,1.0))"; - hecl::Runtime::ShaderTag testShaderTag(testShader, 0, 1, 0, 0, 0, boo::Primitive::TriStrips, false, false, false); - boo::IShaderPipeline* testShaderObj = - shaderMgr.buildShader(testShaderTag, testShader, "testShader", ctx); - /* Generate meta structure (usually statically serialized) */ hecl::HMDLMeta testMeta; testMeta.topology = hecl::HMDLTopology::TriStrips; @@ -146,7 +146,7 @@ struct HECLApplicationCallback : boo::IApplicationCallback vubo = ctx.newDynamicBuffer(boo::BufferUse::Uniform, sizeof(VertexUBO), 1); /* Assemble data binding */ - binding = testData.newShaderDataBindng(ctx, testShaderObj, 1, (boo::IGraphicsBuffer**)&vubo, nullptr, 1, &texture); + binding = testData.newShaderDataBindng(ctx, testShaderObj->m_pipelines[0], 1, (boo::IGraphicsBuffer**)&vubo, nullptr, 1, &texture); return true; });