Dramatic shader cache performance improvement

This commit is contained in:
Jack Andersen 2016-09-11 18:52:55 -10:00
parent 4bffe7bc8b
commit 5303b9bda1
3 changed files with 186 additions and 61 deletions

View File

@ -195,6 +195,15 @@ public:
virtual ~IShaderBackendFactory() {} virtual ~IShaderBackendFactory() {}
}; };
/**
* @brief Stores token and pipeline set for sharing with ref-counting
*/
struct ShaderPipelines
{
boo::GraphicsDataToken m_token;
std::vector<boo::IShaderPipeline*> m_pipelines;
};
/** /**
* @brief Maintains index/data file pair containing platform-dependent cached shader data * @brief Maintains index/data file pair containing platform-dependent cached shader data
*/ */
@ -218,6 +227,8 @@ class ShaderCacheManager
}; };
std::vector<IndexEntry> m_entries; std::vector<IndexEntry> m_entries;
std::unordered_map<Hash, size_t> m_entryLookup; std::unordered_map<Hash, size_t> m_entryLookup;
std::unordered_map<Hash, std::weak_ptr<ShaderPipelines>> m_pipelineLookup;
uint64_t m_timeHash = 0; uint64_t m_timeHash = 0;
void bootstrapIndex(); void bootstrapIndex();
ShaderCachedData lookupData(const Hash& hash); ShaderCachedData lookupData(const Hash& hash);
@ -239,18 +250,18 @@ public:
* for encoding the pipeline state. This must be called before building shaders */ * for encoding the pipeline state. This must be called before building shaders */
void setRenderTargetSamples(unsigned samps) {m_factory->m_rtHint = samps;} void setRenderTargetSamples(unsigned samps) {m_factory->m_rtHint = samps;}
boo::IShaderPipeline* buildShader(const ShaderTag& tag, const std::string& source, std::shared_ptr<ShaderPipelines> buildShader(const ShaderTag& tag, const std::string& source,
const std::string& diagName, const std::string& diagName,
boo::IGraphicsDataFactory::Context& ctx); boo::IGraphicsDataFactory& factory);
boo::IShaderPipeline* buildShader(const ShaderTag& tag, const hecl::Frontend::IR& ir, std::shared_ptr<ShaderPipelines> buildShader(const ShaderTag& tag, const hecl::Frontend::IR& ir,
const std::string& diagName, const std::string& diagName,
boo::IGraphicsDataFactory::Context& ctx); boo::IGraphicsDataFactory& factory);
std::vector<boo::IShaderPipeline*> buildExtendedShader(const ShaderTag& tag, const std::string& source, std::shared_ptr<ShaderPipelines> buildExtendedShader(const ShaderTag& tag, const std::string& source,
const std::string& diagName, const std::string& diagName,
boo::IGraphicsDataFactory::Context& ctx); boo::IGraphicsDataFactory& factory);
std::vector<boo::IShaderPipeline*> buildExtendedShader(const ShaderTag& tag, const hecl::Frontend::IR& ir, std::shared_ptr<ShaderPipelines> buildExtendedShader(const ShaderTag& tag, const hecl::Frontend::IR& ir,
const std::string& diagName, const std::string& diagName,
boo::IGraphicsDataFactory::Context& ctx); boo::IGraphicsDataFactory& factory);
}; };
/** /**

View File

@ -363,40 +363,98 @@ ShaderCacheManager::buildFromCache(const ShaderCachedData& foundData,
return m_factory->buildShaderFromCache(foundData, ctx); return m_factory->buildShaderFromCache(foundData, ctx);
} }
boo::IShaderPipeline* std::shared_ptr<ShaderPipelines>
ShaderCacheManager::buildShader(const ShaderTag& tag, const std::string& source, ShaderCacheManager::buildShader(const ShaderTag& tag, const std::string& source,
const std::string& diagName, 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<ShaderPipelines> ret = std::make_shared<ShaderPipelines>();
ShaderCachedData foundData = lookupData(tag); ShaderCachedData foundData = lookupData(tag);
if (foundData) if (foundData)
{ {
ret = buildFromCache(foundData, ctx); ret->m_token = factory.commitTransaction([&](boo::IGraphicsDataFactory::Context& ctx) -> bool
if (ret) {
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; return ret;
}
Log.report(logvisor::Warning, "invalid cache read, rebuilding shader '%s'", diagName.c_str()); 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<ShaderPipelines>
ShaderCacheManager::buildShader(const ShaderTag& tag, const hecl::Frontend::IR& ir, ShaderCacheManager::buildShader(const ShaderTag& tag, const hecl::Frontend::IR& ir,
const std::string& diagName, 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<ShaderPipelines> ret = std::make_shared<ShaderPipelines>();
ShaderCachedData foundData = lookupData(tag); ShaderCachedData foundData = lookupData(tag);
if (foundData) if (foundData)
{ {
ret = buildFromCache(foundData, ctx); ret->m_token = factory.commitTransaction([&](boo::IGraphicsDataFactory::Context& ctx) -> bool
if (ret) {
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; return ret;
}
Log.report(logvisor::Warning, "invalid cache read, rebuilding shader '%s'", diagName.c_str()); 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; return ret;
} }
@ -415,48 +473,104 @@ ShaderCacheManager::buildExtendedFromCache(const ShaderCachedData& foundData,
return shaders; return shaders;
} }
std::vector<boo::IShaderPipeline*> std::shared_ptr<ShaderPipelines>
ShaderCacheManager::buildExtendedShader(const ShaderTag& tag, const std::string& source, ShaderCacheManager::buildExtendedShader(const ShaderTag& tag, const std::string& source,
const std::string& diagName, const std::string& diagName,
boo::IGraphicsDataFactory::Context& ctx) boo::IGraphicsDataFactory& factory)
{ {
std::vector<boo::IShaderPipeline*> shaders; auto search = m_pipelineLookup.find(tag);
if (search != m_pipelineLookup.cend())
if (auto ret = search->second.lock())
return ret;
std::shared_ptr<ShaderPipelines> ret = std::make_shared<ShaderPipelines>();
ShaderCachedData foundData = lookupData(tag); ShaderCachedData foundData = lookupData(tag);
if (foundData) if (foundData)
{ {
shaders = buildExtendedFromCache(foundData, ctx); ret->m_token = factory.commitTransaction([&](boo::IGraphicsDataFactory::Context& ctx) -> bool
if (shaders.size()) {
return shaders; 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()); Log.report(logvisor::Warning, "invalid cache read, rebuilding shader '%s'", diagName.c_str());
} }
hecl::Frontend::IR ir = FE.compileSource(source, diagName); 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<boo::IShaderPipeline*> std::shared_ptr<ShaderPipelines>
ShaderCacheManager::buildExtendedShader(const ShaderTag& tag, const hecl::Frontend::IR& ir, ShaderCacheManager::buildExtendedShader(const ShaderTag& tag, const hecl::Frontend::IR& ir,
const std::string& diagName, const std::string& diagName,
boo::IGraphicsDataFactory::Context& ctx) boo::IGraphicsDataFactory& factory)
{ {
std::vector<boo::IShaderPipeline*> shaders; auto search = m_pipelineLookup.find(tag);
if (search != m_pipelineLookup.cend())
if (auto ret = search->second.lock())
return ret;
std::shared_ptr<ShaderPipelines> ret = std::make_shared<ShaderPipelines>();
ShaderCachedData foundData = lookupData(tag); ShaderCachedData foundData = lookupData(tag);
if (foundData) if (foundData)
{ {
shaders = buildExtendedFromCache(foundData, ctx); ret->m_token = factory.commitTransaction([&](boo::IGraphicsDataFactory::Context& ctx) -> bool
if (shaders.size()) {
return shaders; 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()); Log.report(logvisor::Warning, "invalid cache read, rebuilding shader '%s'", diagName.c_str());
} }
shaders.reserve(m_extensions.m_extensionSlots.size());
FE.getDiagnostics().reset(diagName); ret->m_token = factory.commitTransaction([&](boo::IGraphicsDataFactory::Context& ctx) -> bool
ShaderCachedData data = {
m_factory->buildExtendedShaderFromIR(tag, ir, FE.getDiagnostics(), m_extensions.m_extensionSlots, ctx, ret->m_pipelines.reserve(m_extensions.m_extensionSlots.size());
[&](boo::IShaderPipeline* shader){shaders.push_back(shader);}); FE.getDiagnostics().reset(diagName);
if (shaders.size() != m_extensions.m_extensionSlots.size()) Log.report(logvisor::Info, "building shader '%s' %016llX", diagName.c_str(), tag.val64());
Log.report(logvisor::Fatal, "buildShaderFromIR returned %" PRISize " times, expected %" PRISize, ShaderCachedData data =
shaders.size(), m_extensions.m_extensionSlots.size()); m_factory->buildExtendedShaderFromIR(tag, ir, FE.getDiagnostics(), m_extensions.m_extensionSlots, ctx,
addData(data); [&](boo::IShaderPipeline* shader){ret->m_pipelines.push_back(shader);});
return shaders; 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;
} }
} }

View File

@ -74,23 +74,23 @@ struct HECLApplicationCallback : boo::IApplicationCallback
std::unique_lock<std::mutex> innerLk(initmt); std::unique_lock<std::mutex> innerLk(initmt);
boo::IGraphicsDataFactory* gfxF = m_mainWindow->getLoadContextDataFactory(); 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<hecl::Runtime::ShaderPipelines> testShaderObj =
shaderMgr.buildShader(testShaderTag, testShader, "testShader", *gfxF);
boo::GraphicsDataToken data = boo::GraphicsDataToken data =
gfxF->commitTransaction([&](boo::IGraphicsDataFactory::Context& ctx) -> bool gfxF->commitTransaction([&](boo::IGraphicsDataFactory::Context& ctx) -> bool
{ {
boo::SWindowRect mainWindowRect = m_mainWindow->getWindowFrame(); boo::SWindowRect mainWindowRect = m_mainWindow->getWindowFrame();
renderTex = ctx.newRenderTexture(mainWindowRect.size[0], mainWindowRect.size[1], false, false); 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) */ /* Generate meta structure (usually statically serialized) */
hecl::HMDLMeta testMeta; hecl::HMDLMeta testMeta;
testMeta.topology = hecl::HMDLTopology::TriStrips; testMeta.topology = hecl::HMDLTopology::TriStrips;
@ -146,7 +146,7 @@ struct HECLApplicationCallback : boo::IApplicationCallback
vubo = ctx.newDynamicBuffer(boo::BufferUse::Uniform, sizeof(VertexUBO), 1); vubo = ctx.newDynamicBuffer(boo::BufferUse::Uniform, sizeof(VertexUBO), 1);
/* Assemble data binding */ /* 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; return true;
}); });