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() {}
};
/**
* @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
*/
@ -218,6 +227,8 @@ class ShaderCacheManager
};
std::vector<IndexEntry> m_entries;
std::unordered_map<Hash, size_t> m_entryLookup;
std::unordered_map<Hash, std::weak_ptr<ShaderPipelines>> 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<boo::IShaderPipeline*> buildExtendedShader(const ShaderTag& tag, const std::string& source,
const std::string& diagName,
boo::IGraphicsDataFactory::Context& ctx);
std::vector<boo::IShaderPipeline*> buildExtendedShader(const ShaderTag& tag, const hecl::Frontend::IR& ir,
const std::string& diagName,
boo::IGraphicsDataFactory::Context& ctx);
std::shared_ptr<ShaderPipelines> buildShader(const ShaderTag& tag, const std::string& source,
const std::string& diagName,
boo::IGraphicsDataFactory& factory);
std::shared_ptr<ShaderPipelines> buildShader(const ShaderTag& tag, const hecl::Frontend::IR& ir,
const std::string& diagName,
boo::IGraphicsDataFactory& factory);
std::shared_ptr<ShaderPipelines> buildExtendedShader(const ShaderTag& tag, const std::string& source,
const std::string& diagName,
boo::IGraphicsDataFactory& factory);
std::shared_ptr<ShaderPipelines> buildExtendedShader(const ShaderTag& tag, const hecl::Frontend::IR& ir,
const std::string& diagName,
boo::IGraphicsDataFactory& factory);
};
/**

View File

@ -363,40 +363,98 @@ ShaderCacheManager::buildFromCache(const ShaderCachedData& foundData,
return m_factory->buildShaderFromCache(foundData, ctx);
}
boo::IShaderPipeline*
std::shared_ptr<ShaderPipelines>
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<ShaderPipelines> ret = std::make_shared<ShaderPipelines>();
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<ShaderPipelines>
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<ShaderPipelines> ret = std::make_shared<ShaderPipelines>();
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<boo::IShaderPipeline*>
std::shared_ptr<ShaderPipelines>
ShaderCacheManager::buildExtendedShader(const ShaderTag& tag, const std::string& source,
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);
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<boo::IShaderPipeline*>
std::shared_ptr<ShaderPipelines>
ShaderCacheManager::buildExtendedShader(const ShaderTag& tag, const hecl::Frontend::IR& ir,
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);
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;
}
}

View File

@ -74,23 +74,23 @@ struct HECLApplicationCallback : boo::IApplicationCallback
std::unique_lock<std::mutex> 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<hecl::Runtime::ShaderPipelines> 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;
});