LocalSizeId for VK_KHR_maintenance4
This CL adds support in SPIR-V for spv::ExecutionModeLocalSizeId and
spv::OpExecutionModeId. This is required for VK_KHR_maintenance4
support.
Bug: b/204502926
Change-Id: I00113b9f0e649c49c2c81b68aedd8340ea003297
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/63294
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
Tested-by: Alexis Hétu <sugoi@google.com>
Commit-Queue: Alexis Hétu <sugoi@google.com>
Kokoro-Result: kokoro <noreply+kokoro@google.com>
diff --git a/src/Pipeline/ComputeProgram.cpp b/src/Pipeline/ComputeProgram.cpp
index 3a771f0..f235d8fb 100644
--- a/src/Pipeline/ComputeProgram.cpp
+++ b/src/Pipeline/ComputeProgram.cpp
@@ -217,10 +217,12 @@
uint32_t baseGroupX, uint32_t baseGroupY, uint32_t baseGroupZ,
uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ)
{
- auto &executionModes = shader->getExecutionModes();
+ uint32_t workgroupSizeX = shader->getWorkgroupSizeX();
+ uint32_t workgroupSizeY = shader->getWorkgroupSizeY();
+ uint32_t workgroupSizeZ = shader->getWorkgroupSizeZ();
auto invocationsPerSubgroup = SIMD::Width;
- auto invocationsPerWorkgroup = executionModes.WorkgroupSizeX * executionModes.WorkgroupSizeY * executionModes.WorkgroupSizeZ;
+ auto invocationsPerWorkgroup = workgroupSizeX * workgroupSizeY * workgroupSizeZ;
auto subgroupsPerWorkgroup = (invocationsPerWorkgroup + invocationsPerSubgroup - 1) / invocationsPerSubgroup;
Data data;
@@ -230,9 +232,9 @@
data.numWorkgroups[Y] = groupCountY;
data.numWorkgroups[Z] = groupCountZ;
data.numWorkgroups[3] = 0;
- data.workgroupSize[X] = executionModes.WorkgroupSizeX;
- data.workgroupSize[Y] = executionModes.WorkgroupSizeY;
- data.workgroupSize[Z] = executionModes.WorkgroupSizeZ;
+ data.workgroupSize[X] = workgroupSizeX;
+ data.workgroupSize[Y] = workgroupSizeY;
+ data.workgroupSize[Z] = workgroupSizeZ;
data.workgroupSize[3] = 0;
data.invocationsPerSubgroup = invocationsPerSubgroup;
data.invocationsPerWorkgroup = invocationsPerWorkgroup;
@@ -273,7 +275,7 @@
// Make a function call per subgroup so each subgroup
// can yield, bringing all subgroups to the barrier
// together.
- for(int subgroupIndex = 0; subgroupIndex < subgroupsPerWorkgroup; subgroupIndex++)
+ for(uint32_t subgroupIndex = 0; subgroupIndex < subgroupsPerWorkgroup; subgroupIndex++)
{
auto coroutine = (*this)(device, &data, groupX, groupY, groupZ, workgroupMemory.data(), subgroupIndex, 1);
coroutines.push(std::move(coroutine));
diff --git a/src/Pipeline/SpirvShader.cpp b/src/Pipeline/SpirvShader.cpp
index 446059d..d3fb589 100644
--- a/src/Pipeline/SpirvShader.cpp
+++ b/src/Pipeline/SpirvShader.cpp
@@ -99,6 +99,7 @@
break;
case spv::OpExecutionMode:
+ case spv::OpExecutionModeId:
ProcessExecutionMode(insn);
break;
@@ -396,6 +397,7 @@
executionModes.WorkgroupSizeX = object.constantValue[0];
executionModes.WorkgroupSizeY = object.constantValue[1];
executionModes.WorkgroupSizeZ = object.constantValue[2];
+ executionModes.useWorkgroupSizeId = false;
}
}
break;
@@ -1014,9 +1016,11 @@
executionModes.DepthUnchanged = true;
break;
case spv::ExecutionModeLocalSize:
+ case spv::ExecutionModeLocalSizeId:
executionModes.WorkgroupSizeX = insn.word(3);
executionModes.WorkgroupSizeY = insn.word(4);
executionModes.WorkgroupSizeZ = insn.word(5);
+ executionModes.useWorkgroupSizeId = (mode == spv::ExecutionModeLocalSizeId);
break;
case spv::ExecutionModeOriginUpperLeft:
// This is always the case for a Vulkan shader. Do nothing.
@@ -1026,6 +1030,21 @@
}
}
+uint32_t SpirvShader::getWorkgroupSizeX() const
+{
+ return executionModes.useWorkgroupSizeId ? getObject(executionModes.WorkgroupSizeX).constantValue[0] : executionModes.WorkgroupSizeX.value();
+}
+
+uint32_t SpirvShader::getWorkgroupSizeY() const
+{
+ return executionModes.useWorkgroupSizeId ? getObject(executionModes.WorkgroupSizeY).constantValue[0] : executionModes.WorkgroupSizeY.value();
+}
+
+uint32_t SpirvShader::getWorkgroupSizeZ() const
+{
+ return executionModes.useWorkgroupSizeId ? getObject(executionModes.WorkgroupSizeZ).constantValue[0] : executionModes.WorkgroupSizeZ.value();
+}
+
uint32_t SpirvShader::ComputeTypeSize(InsnIterator insn)
{
// Types are always built from the bottom up (with the exception of forward ptrs, which
@@ -1806,6 +1825,7 @@
case spv::OpTypeSampledImage:
case spv::OpTypeSampler:
case spv::OpExecutionMode:
+ case spv::OpExecutionModeId:
case spv::OpMemoryModel:
case spv::OpFunction:
case spv::OpFunctionEnd:
diff --git a/src/Pipeline/SpirvShader.hpp b/src/Pipeline/SpirvShader.hpp
index 6c90535..6aab7a7 100644
--- a/src/Pipeline/SpirvShader.hpp
+++ b/src/Pipeline/SpirvShader.hpp
@@ -631,9 +631,10 @@
bool DepthUnchanged : 1;
// Compute workgroup dimensions
- int WorkgroupSizeX = 1;
- int WorkgroupSizeY = 1;
- int WorkgroupSizeZ = 1;
+ Object::ID WorkgroupSizeX = 1;
+ Object::ID WorkgroupSizeY = 1;
+ Object::ID WorkgroupSizeZ = 1;
+ bool useWorkgroupSizeId = false;
};
const ExecutionModes &getExecutionModes() const
@@ -879,6 +880,10 @@
void emitEpilog(SpirvRoutine *routine) const;
void clearPhis(SpirvRoutine *routine) const;
+ uint32_t getWorkgroupSizeX() const;
+ uint32_t getWorkgroupSizeY() const;
+ uint32_t getWorkgroupSizeZ() const;
+
bool containsImageWrite() const { return imageWriteEmitted; }
using BuiltInHash = std::hash<std::underlying_type<spv::BuiltIn>::type>;
diff --git a/src/Vulkan/VkPipeline.cpp b/src/Vulkan/VkPipeline.cpp
index 782aecc..79ed55d 100644
--- a/src/Vulkan/VkPipeline.cpp
+++ b/src/Vulkan/VkPipeline.cpp
@@ -93,6 +93,7 @@
spvtools::ValidatorOptions validatorOptions = {};
validatorOptions.SetScalarBlockLayout(true); // VK_EXT_scalar_block_layout
validatorOptions.SetUniformBufferStandardLayout(true); // VK_KHR_uniform_buffer_standard_layout
+ validatorOptions.SetAllowLocalSizeId(true); // VK_KHR_maintenance4
optimizerOptions.set_validator_options(validatorOptions);
#endif
diff --git a/src/Vulkan/VkShaderModule.cpp b/src/Vulkan/VkShaderModule.cpp
index c97be88..ea75eae 100644
--- a/src/Vulkan/VkShaderModule.cpp
+++ b/src/Vulkan/VkShaderModule.cpp
@@ -25,7 +25,7 @@
{
#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
spvtools::SpirvTools spirvTools(SPIRV_VERSION);
- spirvTools.SetMessageConsumer([](spv_message_level_t level, const char *source, const spv_position_t &position, const char *message) {
+ spirvTools.SetMessageConsumer([](spv_message_level_t level, const char *source, const spv_position_t &position, const char *message) {
switch(level)
{
case SPV_MSG_FATAL: sw::warn("SPIR-V FATAL: %d:%d %s\n", int(position.line), int(position.column), message);
@@ -41,6 +41,7 @@
spvtools::ValidatorOptions validatorOptions = {};
validatorOptions.SetScalarBlockLayout(true); // VK_EXT_scalar_block_layout
validatorOptions.SetUniformBufferStandardLayout(true); // VK_KHR_uniform_buffer_standard_layout
+ validatorOptions.SetAllowLocalSizeId(true); // VK_KHR_maintenance4
ASSERT(spirvTools.Validate(binary.data(), binary.size(), validatorOptions)); // The SPIR-V code passed to vkCreateShaderModule must be valid (b/158228522)
#endif