Optimize SPIR-V binary cache reuse
This change removes state from the SPIR-V binary cache's key that isn't
used to uniquely identify optimized SPIR-V. Specifically, SPIR-V
optimization is done on entire shader modules, and the result can be
reused for multiple entry points.
The renderpass/subpass information also isn't used to affect SPIR-V
optimization.
Bug: b/197982536
Change-Id: I4894b40163946836b0f1831d3222fe4dc668f68a
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/57149
Tested-by: Nicolas Capens <nicolascapens@google.com>
Kokoro-Result: kokoro <noreply+kokoro@google.com>
Reviewed-by: Alexis Hétu <sugoi@google.com>
diff --git a/src/Vulkan/VkPipeline.cpp b/src/Vulkan/VkPipeline.cpp
index ef2da43..0ff6777 100644
--- a/src/Vulkan/VkPipeline.cpp
+++ b/src/Vulkan/VkPipeline.cpp
@@ -113,22 +113,6 @@
return code;
}
-std::shared_ptr<sw::SpirvShader> createShader(
- const vk::PipelineCache::SpirvShaderKey &key,
- const vk::ShaderModule *module,
- const sw::SpirvBinary &spirv,
- bool robustBufferAccess,
- const std::shared_ptr<vk::dbg::Context> &dbgctx)
-{
- // If the pipeline has specialization constants, assume they're unique and
- // use a new serial ID so the shader gets recompiled.
- uint32_t codeSerialID = (key.getSpecializationInfo() ? vk::ShaderModule::nextSerialID() : module->getSerialID());
-
- // TODO(b/119409619): use allocator.
- return std::make_shared<sw::SpirvShader>(codeSerialID, key.getPipelineStage(), key.getEntryPointName().c_str(),
- spirv, key.getRenderPass(), key.getSubpassIndex(), robustBufferAccess, dbgctx);
-}
-
std::shared_ptr<sw::ComputeProgram> createProgram(vk::Device *device, std::shared_ptr<sw::SpirvShader> shader, const vk::PipelineLayout *layout)
{
MARL_SCOPED_EVENT("createProgram");
@@ -241,10 +225,7 @@
const bool optimize = !dbgctx;
const ShaderModule *module = vk::Cast(pStage->module);
- const PipelineCache::SpirvShaderKey key(pStage->stage, pStage->pName, module->getCode(),
- vk::Cast(pCreateInfo->renderPass), pCreateInfo->subpass,
- pStage->pSpecializationInfo, optimize);
- auto pipelineStage = key.getPipelineStage();
+ const PipelineCache::SpirvShaderKey key(module->getCode(), pStage->pSpecializationInfo, optimize);
sw::SpirvBinary spirv;
@@ -259,9 +240,15 @@
spirv = optimizeSpirv(key);
}
- auto shader = createShader(key, module, spirv, robustBufferAccess, dbgctx);
+ // If the pipeline has specialization constants, assume they're unique and
+ // use a new serial ID so the shader gets recompiled.
+ uint32_t codeSerialID = (key.getSpecializationInfo() ? vk::ShaderModule::nextSerialID() : module->getSerialID());
- setShader(pipelineStage, shader);
+ // TODO(b/119409619): use allocator.
+ auto shader = std::make_shared<sw::SpirvShader>(codeSerialID, pStage->stage, pStage->pName, spirv,
+ vk::Cast(pCreateInfo->renderPass), pCreateInfo->subpass, robustBufferAccess, dbgctx);
+
+ setShader(pStage->stage, shader);
}
}
@@ -295,8 +282,7 @@
// instructions.
const bool optimize = !dbgctx;
- const PipelineCache::SpirvShaderKey shaderKey(
- stage.stage, stage.pName, module->getCode(), nullptr, 0, stage.pSpecializationInfo, optimize);
+ const PipelineCache::SpirvShaderKey shaderKey(module->getCode(), stage.pSpecializationInfo, optimize);
sw::SpirvBinary spirv;
@@ -311,7 +297,13 @@
spirv = optimizeSpirv(shaderKey);
}
- shader = createShader(shaderKey, module, spirv, robustBufferAccess, dbgctx);
+ // If the pipeline has specialization constants, assume they're unique and
+ // use a new serial ID so the shader gets recompiled.
+ uint32_t codeSerialID = (stage.pSpecializationInfo ? vk::ShaderModule::nextSerialID() : module->getSerialID());
+
+ // TODO(b/119409619): use allocator.
+ shader = std::make_shared<sw::SpirvShader>(codeSerialID, stage.stage, stage.pName, spirv,
+ nullptr, 0, robustBufferAccess, dbgctx);
const PipelineCache::ComputeProgramKey programKey(shader->getSerialID(), layout->identifier);
diff --git a/src/Vulkan/VkPipelineCache.cpp b/src/Vulkan/VkPipelineCache.cpp
index 87b4c89..506e670 100644
--- a/src/Vulkan/VkPipelineCache.cpp
+++ b/src/Vulkan/VkPipelineCache.cpp
@@ -18,18 +18,10 @@
namespace vk {
-PipelineCache::SpirvShaderKey::SpirvShaderKey(const VkShaderStageFlagBits pipelineStage,
- const std::string &entryPointName,
- const sw::SpirvBinary &insns,
- const vk::RenderPass *renderPass,
- const uint32_t subpassIndex,
+PipelineCache::SpirvShaderKey::SpirvShaderKey(const sw::SpirvBinary &insns,
const vk::SpecializationInfo &specializationInfo,
bool optimize)
- : pipelineStage(pipelineStage)
- , entryPointName(entryPointName)
- , insns(insns)
- , renderPass(renderPass)
- , subpassIndex(subpassIndex)
+ : insns(insns)
, specializationInfo(specializationInfo)
, optimize(optimize)
{
@@ -37,38 +29,12 @@
bool PipelineCache::SpirvShaderKey::operator<(const SpirvShaderKey &other) const
{
- if(pipelineStage != other.pipelineStage)
- {
- return pipelineStage < other.pipelineStage;
- }
-
- if(renderPass != other.renderPass)
- {
- return renderPass < other.renderPass;
- }
-
- if(subpassIndex != other.subpassIndex)
- {
- return subpassIndex < other.subpassIndex;
- }
-
if(insns.size() != other.insns.size())
{
return insns.size() < other.insns.size();
}
- if(entryPointName.size() != other.entryPointName.size())
- {
- return entryPointName.size() < other.entryPointName.size();
- }
-
- int cmp = memcmp(entryPointName.c_str(), other.entryPointName.c_str(), entryPointName.size());
- if(cmp != 0)
- {
- return cmp < 0;
- }
-
- cmp = memcmp(insns.data(), other.insns.data(), insns.size() * sizeof(uint32_t));
+ int cmp = memcmp(insns.data(), other.insns.data(), insns.size() * sizeof(uint32_t));
if(cmp != 0)
{
return cmp < 0;
diff --git a/src/Vulkan/VkPipelineCache.hpp b/src/Vulkan/VkPipelineCache.hpp
index 9e950c6..3b00cb6 100644
--- a/src/Vulkan/VkPipelineCache.hpp
+++ b/src/Vulkan/VkPipelineCache.hpp
@@ -55,30 +55,18 @@
struct SpirvShaderKey
{
- SpirvShaderKey(const VkShaderStageFlagBits pipelineStage,
- const std::string &entryPointName,
- const sw::SpirvBinary &insns,
- const vk::RenderPass *renderPass,
- const uint32_t subpassIndex,
+ SpirvShaderKey(const sw::SpirvBinary &insns,
const vk::SpecializationInfo &specializationInfo,
bool optimize);
bool operator<(const SpirvShaderKey &other) const;
- const VkShaderStageFlagBits &getPipelineStage() const { return pipelineStage; }
- const std::string &getEntryPointName() const { return entryPointName; }
const sw::SpirvBinary &getInsns() const { return insns; }
- const vk::RenderPass *getRenderPass() const { return renderPass; }
- uint32_t getSubpassIndex() const { return subpassIndex; }
const VkSpecializationInfo *getSpecializationInfo() const { return specializationInfo.get(); }
bool getOptimization() const { return optimize; }
private:
- const VkShaderStageFlagBits pipelineStage;
- const std::string entryPointName;
const sw::SpirvBinary insns;
- const vk::RenderPass *renderPass;
- const uint32_t subpassIndex;
const vk::SpecializationInfo specializationInfo;
const bool optimize;
};