mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2024-12-25 17:21:06 +00:00
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:
parent
69197ba90b
commit
b951948eaa
2
DEPS
2
DEPS
@ -13,7 +13,7 @@ vars = {
|
||||
'protobuf_revision': 'v21.12',
|
||||
|
||||
're2_revision': '264e71e88e1c8a4b5ec326e70e9cf1d476f58a58',
|
||||
'spirv_headers_revision': 'ae6a8b39717523d96683bc0d20b541944e28072f',
|
||||
'spirv_headers_revision': '5aa1dd8a11182ea9a6a0eabd6a9edc639d5dbecd',
|
||||
}
|
||||
|
||||
deps = {
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -4376,6 +4376,9 @@ export default {
|
||||
"ShaderClockKHR": {
|
||||
"value": 5055
|
||||
},
|
||||
"QuadControlKHR": {
|
||||
"value": 5087
|
||||
},
|
||||
"FragmentFullyCoveredEXT": {
|
||||
"value": 5265
|
||||
},
|
||||
|
Loading…
Reference in New Issue
Block a user