diff --git a/DEPS b/DEPS index 7ba5521ae..1856d3c7e 100644 --- a/DEPS +++ b/DEPS @@ -13,7 +13,7 @@ vars = { 'protobuf_revision': 'v21.12', 're2_revision': '264e71e88e1c8a4b5ec326e70e9cf1d476f58a58', - 'spirv_headers_revision': 'ae6a8b39717523d96683bc0d20b541944e28072f', + 'spirv_headers_revision': '5aa1dd8a11182ea9a6a0eabd6a9edc639d5dbecd', } deps = { diff --git a/source/opcode.cpp b/source/opcode.cpp index ffbb2e8ba..38d1a1be6 100644 --- a/source/opcode.cpp +++ b/source/opcode.cpp @@ -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; diff --git a/source/val/validate_mode_setting.cpp b/source/val/validate_mode_setting.cpp index 10afa8298..82c6c3f0e 100644 --- a/source/val/validate_mode_setting.cpp +++ b/source/val/validate_mode_setting.cpp @@ -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; diff --git a/source/val/validate_non_uniform.cpp b/source/val/validate_non_uniform.cpp index 2c36ce332..74449e9dc 100644 --- a/source/val/validate_non_uniform.cpp +++ b/source/val/validate_non_uniform.cpp @@ -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(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(2); + if (auto error = ValidateExecutionScope(_, inst, execution_scope)) { + return error; + } } } diff --git a/source/val/validate_scopes.cpp b/source/val/validate_scopes.cpp index 40c49d1ff..6b493538a 100644 --- a/source/val/validate_scopes.cpp +++ b/source/val/validate_scopes.cpp @@ -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) diff --git a/test/val/val_modes_test.cpp b/test/val/val_modes_test.cpp index f17497747..a0ea4288d 100644 --- a/test/val/val_modes_test.cpp +++ b/test/val/val_modes_test.cpp @@ -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 diff --git a/test/val/val_non_uniform_test.cpp b/test/val/val_non_uniform_test.cpp index a020500d6..530676d5e 100644 --- a/test/val/val_non_uniform_test.cpp +++ b/test/val/val_non_uniform_test.cpp @@ -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 diff --git a/tools/sva/src/spirv.data.js b/tools/sva/src/spirv.data.js index ba969d86b..67c0966cd 100644 --- a/tools/sva/src/spirv.data.js +++ b/tools/sva/src/spirv.data.js @@ -4376,6 +4376,9 @@ export default { "ShaderClockKHR": { "value": 5055 }, + "QuadControlKHR": { + "value": 5087 + }, "FragmentFullyCoveredEXT": { "value": 5265 },