mirror of
https://gitee.com/openharmony/third_party_spirv-tools
synced 2025-02-25 17:22:02 +00:00
Validate that there is at most one push constant block (#2163)
Fixes #2006 Validates that there is at most one PushConstant interface per entry point for Vulkan environment.
This commit is contained in:
parent
3e645b9d67
commit
2f5f5308b6
@ -781,6 +781,8 @@ void ComputeMemberConstraintsForArray(MemberConstraints* constraints,
|
||||
}
|
||||
|
||||
spv_result_t CheckDecorationsOfBuffers(ValidationState_t& vstate) {
|
||||
// Set of entry points that are known to use a push constant.
|
||||
std::unordered_set<uint32_t> uses_push_constant;
|
||||
for (const auto& inst : vstate.ordered_instructions()) {
|
||||
const auto& words = inst.words();
|
||||
if (SpvOpVariable == inst.opcode()) {
|
||||
@ -794,9 +796,25 @@ spv_result_t CheckDecorationsOfBuffers(ValidationState_t& vstate) {
|
||||
const bool push_constant = storageClass == SpvStorageClassPushConstant;
|
||||
const bool storage_buffer = storageClass == SpvStorageClassStorageBuffer;
|
||||
|
||||
// Vulkan 14.5.2: Check DescriptorSet and Binding decoration for
|
||||
// UniformConstant which cannot be a struct.
|
||||
if (spvIsVulkanEnv(vstate.context()->target_env)) {
|
||||
// Vulkan 14.5.1: There must be no more than one PushConstant block
|
||||
// per entry point.
|
||||
if (push_constant) {
|
||||
auto entry_points = vstate.EntryPointReferences(var_id);
|
||||
for (auto ep_id : entry_points) {
|
||||
const bool already_used = !uses_push_constant.insert(ep_id).second;
|
||||
if (already_used) {
|
||||
return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(var_id))
|
||||
<< "Entry point id '" << ep_id
|
||||
<< "' uses more than one PushConstant interface.\n"
|
||||
<< "From Vulkan spec, section 14.5.1:\n"
|
||||
<< "There must be no more than one push constant block "
|
||||
<< "statically used per shader entry point.";
|
||||
}
|
||||
}
|
||||
}
|
||||
// Vulkan 14.5.2: Check DescriptorSet and Binding decoration for
|
||||
// UniformConstant which cannot be a struct.
|
||||
if (uniform_constant) {
|
||||
auto entry_points = vstate.EntryPointReferences(var_id);
|
||||
if (!entry_points.empty() &&
|
||||
|
@ -2283,6 +2283,272 @@ TEST_F(ValidateDecorations, VulkanPushConstantMissingBlockBad) {
|
||||
"decoration"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateDecorations, MultiplePushConstantsSingleEntryPointGood) {
|
||||
std::string spirv = R"(
|
||||
OpCapability Shader
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %1 "main"
|
||||
OpExecutionMode %1 OriginUpperLeft
|
||||
|
||||
OpDecorate %struct Block
|
||||
OpMemberDecorate %struct 0 Offset 0
|
||||
|
||||
%void = OpTypeVoid
|
||||
%voidfn = OpTypeFunction %void
|
||||
%float = OpTypeFloat 32
|
||||
%int = OpTypeInt 32 0
|
||||
%int_0 = OpConstant %int 0
|
||||
%struct = OpTypeStruct %float
|
||||
%ptr = OpTypePointer PushConstant %struct
|
||||
%ptr_float = OpTypePointer PushConstant %float
|
||||
%pc1 = OpVariable %ptr PushConstant
|
||||
%pc2 = OpVariable %ptr PushConstant
|
||||
|
||||
%1 = OpFunction %void None %voidfn
|
||||
%label = OpLabel
|
||||
%2 = OpAccessChain %ptr_float %pc1 %int_0
|
||||
%3 = OpLoad %float %2
|
||||
%4 = OpAccessChain %ptr_float %pc2 %int_0
|
||||
%5 = OpLoad %float %4
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(spirv);
|
||||
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState())
|
||||
<< getDiagnosticString();
|
||||
}
|
||||
|
||||
TEST_F(ValidateDecorations,
|
||||
VulkanMultiplePushConstantsDifferentEntryPointGood) {
|
||||
std::string spirv = R"(
|
||||
OpCapability Shader
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Vertex %1 "func1"
|
||||
OpEntryPoint Fragment %2 "func2"
|
||||
OpExecutionMode %2 OriginUpperLeft
|
||||
|
||||
OpDecorate %struct Block
|
||||
OpMemberDecorate %struct 0 Offset 0
|
||||
|
||||
%void = OpTypeVoid
|
||||
%voidfn = OpTypeFunction %void
|
||||
%float = OpTypeFloat 32
|
||||
%int = OpTypeInt 32 0
|
||||
%int_0 = OpConstant %int 0
|
||||
%struct = OpTypeStruct %float
|
||||
%ptr = OpTypePointer PushConstant %struct
|
||||
%ptr_float = OpTypePointer PushConstant %float
|
||||
%pc1 = OpVariable %ptr PushConstant
|
||||
%pc2 = OpVariable %ptr PushConstant
|
||||
|
||||
%1 = OpFunction %void None %voidfn
|
||||
%label1 = OpLabel
|
||||
%3 = OpAccessChain %ptr_float %pc1 %int_0
|
||||
%4 = OpLoad %float %3
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
|
||||
%2 = OpFunction %void None %voidfn
|
||||
%label2 = OpLabel
|
||||
%5 = OpAccessChain %ptr_float %pc2 %int_0
|
||||
%6 = OpLoad %float %5
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
|
||||
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1))
|
||||
<< getDiagnosticString();
|
||||
}
|
||||
|
||||
TEST_F(ValidateDecorations,
|
||||
VulkanMultiplePushConstantsUnusedSingleEntryPointGood) {
|
||||
std::string spirv = R"(
|
||||
OpCapability Shader
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %1 "main"
|
||||
OpExecutionMode %1 OriginUpperLeft
|
||||
|
||||
OpDecorate %struct Block
|
||||
OpMemberDecorate %struct 0 Offset 0
|
||||
|
||||
%void = OpTypeVoid
|
||||
%voidfn = OpTypeFunction %void
|
||||
%float = OpTypeFloat 32
|
||||
%int = OpTypeInt 32 0
|
||||
%int_0 = OpConstant %int 0
|
||||
%struct = OpTypeStruct %float
|
||||
%ptr = OpTypePointer PushConstant %struct
|
||||
%ptr_float = OpTypePointer PushConstant %float
|
||||
%pc1 = OpVariable %ptr PushConstant
|
||||
%pc2 = OpVariable %ptr PushConstant
|
||||
|
||||
%1 = OpFunction %void None %voidfn
|
||||
%label = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
|
||||
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1))
|
||||
<< getDiagnosticString();
|
||||
}
|
||||
|
||||
TEST_F(ValidateDecorations, VulkanMultiplePushConstantsSingleEntryPointBad) {
|
||||
std::string spirv = R"(
|
||||
OpCapability Shader
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %1 "main"
|
||||
OpExecutionMode %1 OriginUpperLeft
|
||||
|
||||
OpDecorate %struct Block
|
||||
OpMemberDecorate %struct 0 Offset 0
|
||||
|
||||
%void = OpTypeVoid
|
||||
%voidfn = OpTypeFunction %void
|
||||
%float = OpTypeFloat 32
|
||||
%int = OpTypeInt 32 0
|
||||
%int_0 = OpConstant %int 0
|
||||
%struct = OpTypeStruct %float
|
||||
%ptr = OpTypePointer PushConstant %struct
|
||||
%ptr_float = OpTypePointer PushConstant %float
|
||||
%pc1 = OpVariable %ptr PushConstant
|
||||
%pc2 = OpVariable %ptr PushConstant
|
||||
|
||||
%1 = OpFunction %void None %voidfn
|
||||
%label = OpLabel
|
||||
%2 = OpAccessChain %ptr_float %pc1 %int_0
|
||||
%3 = OpLoad %float %2
|
||||
%4 = OpAccessChain %ptr_float %pc2 %int_0
|
||||
%5 = OpLoad %float %4
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_ID,
|
||||
ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1));
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr(
|
||||
"Entry point id '1' uses more than one PushConstant interface.\n"
|
||||
"From Vulkan spec, section 14.5.1:\n"
|
||||
"There must be no more than one push constant block "
|
||||
"statically used per shader entry point."));
|
||||
}
|
||||
|
||||
TEST_F(ValidateDecorations,
|
||||
VulkanMultiplePushConstantsDifferentEntryPointSubFunctionGood) {
|
||||
std::string spirv = R"(
|
||||
OpCapability Shader
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Vertex %1 "func1"
|
||||
OpEntryPoint Fragment %2 "func2"
|
||||
OpExecutionMode %2 OriginUpperLeft
|
||||
|
||||
OpDecorate %struct Block
|
||||
OpMemberDecorate %struct 0 Offset 0
|
||||
|
||||
%void = OpTypeVoid
|
||||
%voidfn = OpTypeFunction %void
|
||||
%float = OpTypeFloat 32
|
||||
%int = OpTypeInt 32 0
|
||||
%int_0 = OpConstant %int 0
|
||||
%struct = OpTypeStruct %float
|
||||
%ptr = OpTypePointer PushConstant %struct
|
||||
%ptr_float = OpTypePointer PushConstant %float
|
||||
%pc1 = OpVariable %ptr PushConstant
|
||||
%pc2 = OpVariable %ptr PushConstant
|
||||
|
||||
%sub1 = OpFunction %void None %voidfn
|
||||
%label_sub1 = OpLabel
|
||||
%3 = OpAccessChain %ptr_float %pc1 %int_0
|
||||
%4 = OpLoad %float %3
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
|
||||
%sub2 = OpFunction %void None %voidfn
|
||||
%label_sub2 = OpLabel
|
||||
%5 = OpAccessChain %ptr_float %pc2 %int_0
|
||||
%6 = OpLoad %float %5
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
|
||||
%1 = OpFunction %void None %voidfn
|
||||
%label1 = OpLabel
|
||||
%call1 = OpFunctionCall %void %sub1
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
|
||||
%2 = OpFunction %void None %voidfn
|
||||
%label2 = OpLabel
|
||||
%call2 = OpFunctionCall %void %sub2
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
|
||||
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1))
|
||||
<< getDiagnosticString();
|
||||
}
|
||||
|
||||
TEST_F(ValidateDecorations,
|
||||
VulkanMultiplePushConstantsSingleEntryPointSubFunctionBad) {
|
||||
std::string spirv = R"(
|
||||
OpCapability Shader
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %1 "main"
|
||||
OpExecutionMode %1 OriginUpperLeft
|
||||
|
||||
OpDecorate %struct Block
|
||||
OpMemberDecorate %struct 0 Offset 0
|
||||
|
||||
%void = OpTypeVoid
|
||||
%voidfn = OpTypeFunction %void
|
||||
%float = OpTypeFloat 32
|
||||
%int = OpTypeInt 32 0
|
||||
%int_0 = OpConstant %int 0
|
||||
%struct = OpTypeStruct %float
|
||||
%ptr = OpTypePointer PushConstant %struct
|
||||
%ptr_float = OpTypePointer PushConstant %float
|
||||
%pc1 = OpVariable %ptr PushConstant
|
||||
%pc2 = OpVariable %ptr PushConstant
|
||||
|
||||
%sub1 = OpFunction %void None %voidfn
|
||||
%label_sub1 = OpLabel
|
||||
%3 = OpAccessChain %ptr_float %pc1 %int_0
|
||||
%4 = OpLoad %float %3
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
|
||||
%sub2 = OpFunction %void None %voidfn
|
||||
%label_sub2 = OpLabel
|
||||
%5 = OpAccessChain %ptr_float %pc2 %int_0
|
||||
%6 = OpLoad %float %5
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
|
||||
%1 = OpFunction %void None %voidfn
|
||||
%label1 = OpLabel
|
||||
%call1 = OpFunctionCall %void %sub1
|
||||
%call2 = OpFunctionCall %void %sub2
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_ID,
|
||||
ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1));
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr(
|
||||
"Entry point id '1' uses more than one PushConstant interface.\n"
|
||||
"From Vulkan spec, section 14.5.1:\n"
|
||||
"There must be no more than one push constant block "
|
||||
"statically used per shader entry point."));
|
||||
}
|
||||
|
||||
TEST_F(ValidateDecorations, VulkanUniformMissingDescriptorSetBad) {
|
||||
std::string spirv = R"(
|
||||
OpCapability Shader
|
||||
|
Loading…
x
Reference in New Issue
Block a user