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_developer;
extern CVar* com_configfile; extern CVar* com_configfile;
extern CVar* com_enableCheats; extern CVar* com_enableCheats;
extern CVar* com_cubemaps;
class CVarManager final { class CVarManager final {
using CVarContainer = DNACVAR::CVarContainer; using CVarContainer = DNACVAR::CVarContainer;
template <typename T> template <typename T>

View File

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

View File

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

View File

@ -31,6 +31,14 @@ Format(const char* format, ...) {
return std::string(resultBuf, printSz); 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) { const std::string* Compiler::getFileContents(SystemStringView path) {
auto search = m_fileContents.find(path.data()); auto search = m_fileContents.find(path.data());
if (search == m_fileContents.end()) { if (search == m_fileContents.end()) {
@ -59,6 +67,9 @@ static const char* ShaderHeaderTemplate =
" static const boo::AdditionalPipelineInfo PipelineInfo;\n" " static const boo::AdditionalPipelineInfo PipelineInfo;\n"
" static constexpr bool HasHash = true;\n" " static constexpr bool HasHash = true;\n"
" static constexpr uint64_t Hash() { return 0x%016llX; }\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"; "};\n\n";
static const char* StageObjectHeaderTemplate = static const char* StageObjectHeaderTemplate =
@ -445,7 +456,12 @@ bool Compiler::compileFile(SystemStringView file, std::string_view baseName, std
StageType stageType; StageType stageType;
auto stageBegin = includesPass.cend(); auto stageBegin = includesPass.cend();
auto stageEnd = 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; std::unordered_map<std::string, std::string> shaderBases;
auto _DoCompile = [&]() { auto _DoCompile = [&]() {
@ -465,9 +481,10 @@ bool Compiler::compileFile(SystemStringView file, std::string_view baseName, std
} }
} }
stageBegin = includesPass.end(); stageBegin = includesPass.end();
std::pair<std::bitset<6>, std::set<std::string>>& uses = shaderStageUses[shaderName]; ShaderStageUse& uses = shaderStageUses[shaderName];
uses.first.set(size_t(stageType)); uses.stages.set(size_t(stageType));
uses.second.insert(stagePlatforms); 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); return StageAction<CompileStageAction>(stagePlatforms, stageType, shaderName, shaderBase, stage, out.second);
}; };
auto DoCompile = [&](std::string platform, StageType type, std::string::const_iterator end, 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 = [&]() { auto DoShader = [&]() {
if (shaderBase.empty() && shaderStageUses.find(shaderName) == shaderStageUses.cend()) if (shaderBase.empty() && shaderStageUses.find(shaderName) == shaderStageUses.cend())
return true; return true;
std::pair<std::bitset<6>, std::set<std::string>>& uses = shaderStageUses[shaderName]; ShaderStageUse& uses = shaderStageUses[shaderName];
if (uses.first.test(5)) if (uses.stages.test(5))
return true; return true;
out.first += Format(ShaderHeaderTemplate, shaderName.c_str(), XXH64(shaderName.c_str(), shaderName.size(), 0)); 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; shaderBases[shaderName] = shaderBase;
for (int i = 0; i < 5; ++i) { for (int i = 0; i < 5; ++i) {
if (uses.first.test(size_t(i))) if (uses.stages.test(size_t(i)))
continue; continue;
std::string useBase = shaderBase; 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); 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); auto search = shaderBases.find(useBase);
if (search == shaderBases.cend()) if (search == shaderBases.cend())
break; break;
useBase = search->second; useBase = search->second;
baseUses = shaderStageUses.find(useBase); 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; 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); 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 += ", ";
out.second += "};\n\n"; out.second += "};\n\n";
uses.first.set(5); uses.stages.set(5);
return true; return true;
}; };
@ -751,6 +769,17 @@ bool Compiler::compileFile(SystemStringView file, std::string_view baseName, std
if (!_DoCompile() || !DoShader()) if (!_DoCompile() || !DoShader())
return false; 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 += "#define UNIVERSAL_PIPELINES_";
out.first += baseName; out.first += baseName;
for (const auto& shader : shaderStageUses) { for (const auto& shader : shaderStageUses) {