SPV_KHR_quad_control (#5547)

* SPV_KHR_quad_control

1. Add two new execute modes: RequireFullQuadsKHR and QuadDerivativesKHR
2. Add two opCodes: OpGroupNonUniformQuadAllKHR and
   OpGroupNonUniformQuadAnyKHR
3. Add one Capability: QuadControlKHR

* update DEPS

* Fixes

* Build fixes
* Formatting fixes
* Test fixes

* formatting

---------

Co-authored-by: Alan Baker <alanbaker@google.com>
This commit is contained in:
ruiminzhao 2024-01-27 04:49:56 +08:00 committed by GitHub
parent 69197ba90b
commit b951948eaa
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 232 additions and 8 deletions

2
DEPS
View File

@ -13,7 +13,7 @@ vars = {
'protobuf_revision': 'v21.12',
're2_revision': '264e71e88e1c8a4b5ec326e70e9cf1d476f58a58',
'spirv_headers_revision': 'ae6a8b39717523d96683bc0d20b541944e28072f',
'spirv_headers_revision': '5aa1dd8a11182ea9a6a0eabd6a9edc639d5dbecd',
}
deps = {

View File

@ -534,6 +534,8 @@ bool spvOpcodeIsNonUniformGroupOperation(spv::Op opcode) {
case spv::Op::OpGroupNonUniformQuadBroadcast:
case spv::Op::OpGroupNonUniformQuadSwap:
case spv::Op::OpGroupNonUniformRotateKHR:
case spv::Op::OpGroupNonUniformQuadAllKHR:
case spv::Op::OpGroupNonUniformQuadAnyKHR:
return true;
default:
return false;

View File

@ -557,6 +557,17 @@ spv_result_t ValidateExecutionMode(ValidationState_t& _,
"model.";
}
break;
case spv::ExecutionMode::QuadDerivativesKHR:
if (!std::all_of(models->begin(), models->end(),
[](const spv::ExecutionModel& model) {
return (model == spv::ExecutionModel::Fragment ||
model == spv::ExecutionModel::GLCompute);
})) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "Execution mode can only be used with the Fragment or "
"GLCompute execution model.";
}
break;
case spv::ExecutionMode::PixelCenterInteger:
case spv::ExecutionMode::OriginUpperLeft:
case spv::ExecutionMode::OriginLowerLeft:
@ -581,6 +592,7 @@ spv_result_t ValidateExecutionMode(ValidationState_t& _,
case spv::ExecutionMode::StencilRefUnchangedBackAMD:
case spv::ExecutionMode::StencilRefGreaterBackAMD:
case spv::ExecutionMode::StencilRefLessBackAMD:
case spv::ExecutionMode::RequireFullQuadsKHR:
if (!std::all_of(models->begin(), models->end(),
[](const spv::ExecutionModel& model) {
return model == spv::ExecutionModel::Fragment;

View File

@ -422,9 +422,14 @@ spv_result_t NonUniformPass(ValidationState_t& _, const Instruction* inst) {
const spv::Op opcode = inst->opcode();
if (spvOpcodeIsNonUniformGroupOperation(opcode)) {
const uint32_t execution_scope = inst->GetOperandAs<uint32_t>(2);
if (auto error = ValidateExecutionScope(_, inst, execution_scope)) {
return error;
// OpGroupNonUniformQuadAllKHR and OpGroupNonUniformQuadAnyKHR don't have
// scope paramter
if ((opcode != spv::Op::OpGroupNonUniformQuadAllKHR) &&
(opcode != spv::Op::OpGroupNonUniformQuadAnyKHR)) {
const uint32_t execution_scope = inst->GetOperandAs<uint32_t>(2);
if (auto error = ValidateExecutionScope(_, inst, execution_scope)) {
return error;
}
}
}

View File

@ -97,8 +97,10 @@ spv_result_t ValidateExecutionScope(ValidationState_t& _,
// Vulkan 1.1 specific rules
if (_.context()->target_env != SPV_ENV_VULKAN_1_0) {
// Scope for Non Uniform Group Operations must be limited to Subgroup
if (spvOpcodeIsNonUniformGroupOperation(opcode) &&
value != spv::Scope::Subgroup) {
if ((spvOpcodeIsNonUniformGroupOperation(opcode) &&
(opcode != spv::Op::OpGroupNonUniformQuadAllKHR) &&
(opcode != spv::Op::OpGroupNonUniformQuadAnyKHR)) &&
(value != spv::Scope::Subgroup)) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< _.VkErrorID(4642) << spvOpcodeString(opcode)
<< ": in Vulkan environment Execution scope is limited to "
@ -178,6 +180,8 @@ spv_result_t ValidateExecutionScope(ValidationState_t& _,
// Scope for execution must be limited to Workgroup or Subgroup for
// non-uniform operations
if (spvOpcodeIsNonUniformGroupOperation(opcode) &&
opcode != spv::Op::OpGroupNonUniformQuadAllKHR &&
opcode != spv::Op::OpGroupNonUniformQuadAnyKHR &&
value != spv::Scope::Subgroup && value != spv::Scope::Workgroup) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< spvOpcodeString(opcode)

View File

@ -1874,6 +1874,184 @@ OpFunctionEnd
"with the FPFastMathDefault execution mode"));
}
TEST_F(ValidateMode, FragmentShaderRequireFullQuadsKHR) {
const std::string spirv = R"(
OpCapability Shader
OpCapability GroupNonUniform
OpCapability GroupNonUniformVote
OpCapability GroupNonUniformBallot
OpCapability QuadControlKHR
OpExtension "SPV_KHR_quad_control"
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %4 "main"
OpExecutionMode %4 OriginUpperLeft
OpExecutionMode %4 RequireFullQuadsKHR
OpDecorate %17 Location 0
OpDecorate %31 BuiltIn HelperInvocation
OpDecorate %40 Location 0
OpDecorate %44 DescriptorSet 0
OpDecorate %44 Binding 0
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%6 = OpTypeInt 32 0
%7 = OpTypeVector %6 4
%8 = OpTypePointer Function %7
%10 = OpTypeBool
%11 = OpConstantTrue %10
%12 = OpConstant %6 7
%14 = OpTypeFloat 32
%15 = OpTypeVector %14 4
%16 = OpTypePointer Output %15
%17 = OpVariable %16 Output
%18 = OpConstant %14 1
%19 = OpConstant %14 0
%20 = OpConstantComposite %15 %18 %19 %19 %18
%23 = OpConstant %6 4
%27 = OpConstant %6 1
%28 = OpTypePointer Output %14
%30 = OpTypePointer Input %10
%31 = OpVariable %30 Input
%36 = OpConstant %6 2
%38 = OpTypeVector %14 2
%39 = OpTypePointer Input %38
%40 = OpVariable %39 Input
%41 = OpTypeImage %14 2D 0 0 0 1 Unknown
%42 = OpTypeSampledImage %41
%43 = OpTypePointer UniformConstant %42
%44 = OpVariable %43 UniformConstant
%4 = OpFunction %2 None %3
%5 = OpLabel
%9 = OpVariable %8 Function
%13 = OpGroupNonUniformBallot %7 %12 %11
OpStore %9 %13
OpStore %17 %20
%21 = OpLoad %7 %9
%22 = OpGroupNonUniformBallotBitCount %6 %12 Reduce %21
%24 = OpIEqual %10 %22 %23
OpSelectionMerge %26 None
OpBranchConditional %24 %25 %26
%25 = OpLabel
%29 = OpAccessChain %28 %17 %27
OpStore %29 %18
OpBranch %26
%26 = OpLabel
%32 = OpLoad %10 %31
%33 = OpGroupNonUniformAny %10 %12 %32
OpSelectionMerge %35 None
OpBranchConditional %33 %34 %35
%34 = OpLabel
%37 = OpAccessChain %28 %17 %36
OpStore %37 %18
OpBranch %35
%35 = OpLabel
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
EXPECT_THAT(SPV_ERROR_INVALID_DATA,
ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr(
"Execution mode can only be used with the Fragment execution model"));
}
TEST_F(ValidateMode, FragmentShaderQuadDerivativesKHR) {
const std::string spirv = R"(
OpCapability Shader
OpCapability GroupNonUniform
OpCapability GroupNonUniformVote
OpCapability QuadControlKHR
OpExtension "SPV_KHR_quad_control"
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %4 "main"
OpExecutionMode %4 OriginUpperLeft
OpExecutionMode %4 QuadDerivativesKHR
OpDecorate %12 BuiltIn FragCoord
OpDecorate %41 Location 0
OpDecorate %45 DescriptorSet 0
OpDecorate %45 Binding 0
OpDecorate %49 Location 0
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%6 = OpTypeBool
%7 = OpTypePointer Function %6
%9 = OpTypeFloat 32
%10 = OpTypeVector %9 4
%11 = OpTypePointer Input %10
%12 = OpVariable %11 Input
%13 = OpTypeInt 32 0
%14 = OpConstant %13 1
%15 = OpTypePointer Input %9
%18 = OpConstant %9 8.5
%21 = OpConstant %9 0.100000001
%25 = OpConstant %13 0
%28 = OpConstant %9 3.5
%30 = OpConstant %9 6
%36 = OpConstant %13 7
%40 = OpTypePointer Output %10
%41 = OpVariable %40 Output
%42 = OpTypeImage %9 2D 0 0 0 1 Unknown
%43 = OpTypeSampledImage %42
%44 = OpTypePointer UniformConstant %43
%45 = OpVariable %44 UniformConstant
%47 = OpTypeVector %9 2
%48 = OpTypePointer Input %47
%49 = OpVariable %48 Input
%53 = OpConstant %9 0.899999976
%54 = OpConstant %9 0.200000003
%55 = OpConstant %9 1
%56 = OpConstantComposite %10 %53 %54 %54 %55
%4 = OpFunction %2 None %3
%5 = OpLabel
%8 = OpVariable %7 Function
%16 = OpAccessChain %15 %12 %14
%17 = OpLoad %9 %16
%19 = OpFSub %9 %17 %18
%20 = OpExtInst %9 %1 FAbs %19
%22 = OpFOrdLessThan %6 %20 %21
OpSelectionMerge %24 None
OpBranchConditional %22 %23 %24
%23 = OpLabel
%26 = OpAccessChain %15 %12 %25
%27 = OpLoad %9 %26
%29 = OpFSub %9 %27 %28
%31 = OpFMod %9 %29 %30
%33 = OpFOrdLessThan %6 %31 %21
OpBranch %24
%24 = OpLabel
%34 = OpPhi %6 %22 %5 %33 %23
OpStore %8 %34
%35 = OpLoad %6 %8
%37 = OpGroupNonUniformAny %6 %36 %35
OpSelectionMerge %39 None
OpBranchConditional %37 %38 %52
%38 = OpLabel
%46 = OpLoad %43 %45
%50 = OpLoad %47 %49
%51 = OpImageSampleImplicitLod %10 %46 %50
OpStore %41 %51
OpBranch %39
%52 = OpLabel
OpStore %41 %56
OpBranch %39
%39 = OpLabel
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
EXPECT_THAT(SPV_ERROR_INVALID_DATA,
ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr(
"Execution mode can only be used with the Fragment execution model"));
}
} // namespace
} // namespace val
} // namespace spvtools

View File

@ -45,7 +45,9 @@ OpCapability GroupNonUniformArithmetic
OpCapability GroupNonUniformClustered
OpCapability GroupNonUniformQuad
OpCapability GroupNonUniformPartitionedNV
OpCapability QuadControlKHR
OpExtension "SPV_NV_shader_subgroup_partitioned"
OpExtension "SPV_KHR_quad_control"
)";
ss << capabilities_and_extensions;
@ -178,7 +180,10 @@ TEST_P(GroupNonUniform, Vulkan1p1) {
std::ostringstream sstr;
sstr << "%result = " << opcode << " ";
sstr << type << " ";
sstr << ConvertScope(execution_scope) << " ";
if (opcode != "OpGroupNonUniformQuadAllKHR" &&
opcode != "OpGroupNonUniformQuadAnyKHR") {
sstr << ConvertScope(execution_scope) << " ";
}
sstr << args << "\n";
CompileSuccessfully(GenerateShaderCode(sstr.str()), SPV_ENV_VULKAN_1_1);
@ -218,7 +223,10 @@ TEST_P(GroupNonUniform, Spirv1p3) {
std::ostringstream sstr;
sstr << "%result = " << opcode << " ";
sstr << type << " ";
sstr << ConvertScope(execution_scope) << " ";
if (opcode != "OpGroupNonUniformQuadAllKHR" &&
opcode != "OpGroupNonUniformQuadAnyKHR") {
sstr << ConvertScope(execution_scope) << " ";
}
sstr << args << "\n";
CompileSuccessfully(GenerateShaderCode(sstr.str()), SPV_ENV_UNIVERSAL_1_3);
@ -869,6 +877,18 @@ INSTANTIATE_TEST_SUITE_P(
Values("ClusteredReduce match_res %u32_undef"),
Values("ClusterSize must be a constant instruction")));
// Subgroup scope is not actual parameter, but used for test expectations,
INSTANTIATE_TEST_SUITE_P(GroupNonUniformQuadAllKHR, GroupNonUniform,
Combine(Values("OpGroupNonUniformQuadAllKHR"),
Values("%bool"), Values(spv::Scope::Subgroup),
Values("%true"), Values("")));
// Subgroup scope is not actual parameter, but used for test expectations,
INSTANTIATE_TEST_SUITE_P(GroupNonUniformQuadAnyKHR, GroupNonUniform,
Combine(Values("OpGroupNonUniformQuadAnyKHR"),
Values("%bool"), Values(spv::Scope::Subgroup),
Values("%true"), Values("")));
TEST_F(ValidateGroupNonUniform, VulkanGroupNonUniformBallotBitCountOperation) {
std::string test = R"(
OpCapability Shader

View File

@ -4376,6 +4376,9 @@ export default {
"ShaderClockKHR": {
"value": 5055
},
"QuadControlKHR": {
"value": 5087
},
"FragmentFullyCoveredEXT": {
"value": 5265
},