Support for per-stage shader hashing

This commit is contained in:
Jack Andersen 2019-06-05 14:07:29 -10:00
parent 82fc24ebe6
commit 7cc157c8b9
4 changed files with 49 additions and 15 deletions

View File

@ -12,6 +12,7 @@ class FileStoreManager;
extern CVar* com_developer;
extern CVar* com_configfile;
extern CVar* com_enableCheats;
extern CVar* com_cubemaps;
class CVarManager final {
using CVarContainer = DNACVAR::CVarContainer;
template <typename T>

View File

@ -295,8 +295,8 @@ public:
template <class FromTp>
StageTargetTp convert(FactoryCtx& ctx, const FromTp& in) {
if (FromTp::HasHash) {
uint64_t hash = in.Hash();
if constexpr (FromTp::HasStageHash) {
uint64_t hash = in.template StageHash<S>();
auto search = m_stageCache.find(hash);
if (search != m_stageCache.end())
return search->second;
@ -406,7 +406,7 @@ public:
template <class FromTp>
PipelineTargetTp convert(FactoryCtx& ctx, const FromTp& in) {
if (FromTp::HasHash) {
if constexpr (FromTp::HasHash) {
uint64_t hash = in.Hash();
auto search = m_pipelineCache.find(hash);
if (search != m_pipelineCache.end())

View File

@ -12,6 +12,7 @@ namespace hecl {
CVar* com_developer = nullptr;
CVar* com_configfile = nullptr;
CVar* com_enableCheats = nullptr;
CVar* com_cubemaps = nullptr;
static const std::regex cmdLineRegex("\\+([\\w\\.]+)=([\\w\\.\\-]+)");
CVarManager* CVarManager::m_instance = nullptr;
@ -26,6 +27,9 @@ CVarManager::CVarManager(hecl::Runtime::FileStoreManager& store, bool useBinary)
com_enableCheats =
newCVar("cheats", "Enable cheats", false,
(CVar::EFlags::System | CVar::EFlags::ReadOnly | CVar::EFlags::Hidden | CVar::EFlags::InternalArchivable));
com_cubemaps =
newCVar("cubemaps", "Enable cubemaps", false,
(CVar::EFlags::Game | CVar::EFlags::ReadOnly | CVar::EFlags::InternalArchivable));
}
CVarManager::~CVarManager() {}

View File

@ -31,6 +31,14 @@ Format(const char* format, ...) {
return std::string(resultBuf, printSz);
}
static const char* StageNames[] = {
"hecl::PipelineStage::Vertex",
"hecl::PipelineStage::Fragment",
"hecl::PipelineStage::Geometry",
"hecl::PipelineStage::Control",
"hecl::PipelineStage::Evaluation"
};
const std::string* Compiler::getFileContents(SystemStringView path) {
auto search = m_fileContents.find(path.data());
if (search == m_fileContents.end()) {
@ -59,6 +67,9 @@ static const char* ShaderHeaderTemplate =
" static const boo::AdditionalPipelineInfo PipelineInfo;\n"
" static constexpr bool HasHash = true;\n"
" static constexpr uint64_t Hash() { return 0x%016llX; }\n"
" static constexpr bool HasStageHash = true;\n"
" template <typename S>\n"
" static constexpr uint64_t StageHash();\n"
"};\n\n";
static const char* StageObjectHeaderTemplate =
@ -445,7 +456,12 @@ bool Compiler::compileFile(SystemStringView file, std::string_view baseName, std
StageType stageType;
auto stageBegin = includesPass.cend();
auto stageEnd = includesPass.cend();
std::unordered_map<std::string, std::pair<std::bitset<6>, std::set<std::string>>> shaderStageUses;
struct ShaderStageUse {
std::bitset<6> stages;
std::array<unsigned long long, 6> stageHashes = {};
std::set<std::string> platforms;
};
std::unordered_map<std::string, ShaderStageUse> shaderStageUses;
std::unordered_map<std::string, std::string> shaderBases;
auto _DoCompile = [&]() {
@ -465,9 +481,10 @@ bool Compiler::compileFile(SystemStringView file, std::string_view baseName, std
}
}
stageBegin = includesPass.end();
std::pair<std::bitset<6>, std::set<std::string>>& uses = shaderStageUses[shaderName];
uses.first.set(size_t(stageType));
uses.second.insert(stagePlatforms);
ShaderStageUse& uses = shaderStageUses[shaderName];
uses.stages.set(size_t(stageType));
uses.stageHashes[size_t(stageType)] = XXH64(stage.c_str(), stage.size(), 0);
uses.platforms.insert(stagePlatforms);
return StageAction<CompileStageAction>(stagePlatforms, stageType, shaderName, shaderBase, stage, out.second);
};
auto DoCompile = [&](std::string platform, StageType type, std::string::const_iterator end,
@ -482,8 +499,8 @@ bool Compiler::compileFile(SystemStringView file, std::string_view baseName, std
auto DoShader = [&]() {
if (shaderBase.empty() && shaderStageUses.find(shaderName) == shaderStageUses.cend())
return true;
std::pair<std::bitset<6>, std::set<std::string>>& uses = shaderStageUses[shaderName];
if (uses.first.test(5))
ShaderStageUse& uses = shaderStageUses[shaderName];
if (uses.stages.test(5))
return true;
out.first += Format(ShaderHeaderTemplate, shaderName.c_str(), XXH64(shaderName.c_str(), shaderName.size(), 0));
@ -494,22 +511,23 @@ bool Compiler::compileFile(SystemStringView file, std::string_view baseName, std
shaderBases[shaderName] = shaderBase;
for (int i = 0; i < 5; ++i) {
if (uses.first.test(size_t(i)))
if (uses.stages.test(size_t(i)))
continue;
std::string useBase = shaderBase;
std::unordered_map<std::string, std::pair<std::bitset<6>, std::set<std::string>>>::const_iterator baseUses =
std::unordered_map<std::string, ShaderStageUse>::const_iterator baseUses =
shaderStageUses.find(useBase);
while (baseUses == shaderStageUses.cend() || !baseUses->second.first.test(size_t(i))) {
while (baseUses == shaderStageUses.cend() || !baseUses->second.stages.test(size_t(i))) {
auto search = shaderBases.find(useBase);
if (search == shaderBases.cend())
break;
useBase = search->second;
baseUses = shaderStageUses.find(useBase);
}
if (baseUses == shaderStageUses.cend() || !baseUses->second.first.test(size_t(i)))
if (baseUses == shaderStageUses.cend() || !baseUses->second.stages.test(size_t(i)))
continue;
for (const std::string& basePlatforms : baseUses->second.second) {
for (const std::string& basePlatforms : baseUses->second.platforms) {
uses.stageHashes[size_t(i)] = baseUses->second.stageHashes[size_t(i)];
StageAction<CompileSubStageAction>(basePlatforms, StageType(i), shaderName, useBase, {}, out.second);
}
}
@ -587,7 +605,7 @@ bool Compiler::compileFile(SystemStringView file, std::string_view baseName, std
out.second += ", ";
out.second += "};\n\n";
uses.first.set(5);
uses.stages.set(5);
return true;
};
@ -751,6 +769,17 @@ bool Compiler::compileFile(SystemStringView file, std::string_view baseName, std
if (!_DoCompile() || !DoShader())
return false;
for (const auto& shader : shaderStageUses) {
for (int i = 0; i < 5; ++i) {
if (shader.second.stageHashes[i]) {
out.first += "template <> constexpr uint64_t Shader_";
out.first += shader.first;
out.first += Format("::StageHash<%s>() { return 0x%016llX; }\n", StageNames[i], shader.second.stageHashes[i]);
}
}
}
out.first += "\n";
out.first += "#define UNIVERSAL_PIPELINES_";
out.first += baseName;
for (const auto& shader : shaderStageUses) {