SPV_KHR_opacity_micromap (#6670)
diff --git a/source/val/validate_extensions.cpp b/source/val/validate_extensions.cpp
index f079954..d986442 100644
--- a/source/val/validate_extensions.cpp
+++ b/source/val/validate_extensions.cpp
@@ -1345,6 +1345,7 @@
   if (_.version() < SPV_SPIRV_VERSION_WORD(1, 4)) {
     if (extension ==
             ExtensionToString(kSPV_KHR_workgroup_memory_explicit_layout) ||
+        extension == ExtensionToString(kSPV_KHR_opacity_micromap) ||
         extension == ExtensionToString(kSPV_EXT_mesh_shader) ||
         extension == ExtensionToString(kSPV_NV_shader_invocation_reorder) ||
         extension == ExtensionToString(kSPV_EXT_shader_invocation_reorder) ||
diff --git a/source/val/validate_mode_setting.cpp b/source/val/validate_mode_setting.cpp
index 261f4af..dd1c731 100644
--- a/source/val/validate_mode_setting.cpp
+++ b/source/val/validate_mode_setting.cpp
@@ -549,6 +549,7 @@
       case spv::ExecutionMode::SubgroupsPerWorkgroupId:
       case spv::ExecutionMode::LocalSizeHintId:
       case spv::ExecutionMode::LocalSizeId:
+      case spv::ExecutionMode::OpacityMicromapIdKHR:
       case spv::ExecutionMode::FPFastMathDefault:
       case spv::ExecutionMode::MaximumRegistersIdINTEL:
       case spv::ExecutionMode::IsApiEntryAMDX:
@@ -635,6 +636,16 @@
             }
           }
           break;
+        case spv::ExecutionMode::OpacityMicromapIdKHR: {
+          spv::Op operand_opcode = operand_inst->opcode();
+          if (!spvOpcodeIsConstant(operand_opcode) ||
+              !_.IsBoolScalarType(operand_inst->type_id())) {
+            return _.diag(SPV_ERROR_INVALID_DATA, operand_inst)
+                   << "OpacityMicromapIdKHR's operand must be an <id> "
+                      "of a constant instruction of OpTypeBool.";
+          }
+          break;
+        }
         default:
           break;
       }
diff --git a/source/val/validate_ray_query.cpp b/source/val/validate_ray_query.cpp
index 980144d..ac5ef1e 100644
--- a/source/val/validate_ray_query.cpp
+++ b/source/val/validate_ray_query.cpp
@@ -99,6 +99,13 @@
                << "Ray Flags must be a 32-bit int scalar";
       }
 
+      if (!_.CheckForceOpacityMicromap2StateKHRCapabilityRequirement(inst, 2)) {
+        return _.diag(SPV_ERROR_INVALID_CAPABILITY, inst)
+               << "The ForceOpacityMicromap2StateKHR flag requires the "
+                  "RayTracingOpacityMicromapKHR and RayQueryKHR or "
+                  "RayTracingKHR capabilities";
+      }
+
       const uint32_t cull_mask = _.GetOperandTypeId(inst, 3);
       if (!_.IsIntScalarType(cull_mask, 32)) {
         return _.diag(SPV_ERROR_INVALID_DATA, inst)
diff --git a/source/val/validate_ray_tracing.cpp b/source/val/validate_ray_tracing.cpp
index 5fa14cc..a7b23a8 100644
--- a/source/val/validate_ray_tracing.cpp
+++ b/source/val/validate_ray_tracing.cpp
@@ -58,6 +58,13 @@
            << "Cull Mask must be a 32-bit int scalar";
   }
 
+  if (!_.CheckForceOpacityMicromap2StateKHRCapabilityRequirement(inst, 1)) {
+    return _.diag(SPV_ERROR_INVALID_CAPABILITY, inst)
+           << "The ForceOpacityMicromap2StateKHR flag requires the "
+              "RayTracingOpacityMicromapKHR and RayQueryKHR or "
+              "RayTracingKHR capabilities";
+  }
+
   const uint32_t sbt_offset = _.GetOperandTypeId(inst, 3);
   if (!_.IsIntScalarType(sbt_offset, 32)) {
     return _.diag(SPV_ERROR_INVALID_DATA, inst)
diff --git a/source/val/validation_state.h b/source/val/validation_state.h
index 0ab0ebd..59a62b3 100644
--- a/source/val/validation_state.h
+++ b/source/val/validation_state.h
@@ -932,6 +932,23 @@
     return SpvDecorationString(uint32_t(decoration));
   }
 
+  bool CheckForceOpacityMicromap2StateKHRCapabilityRequirement(
+      const Instruction* inst, uint32_t flag_operand) {
+    bool retval = true;
+    uint64_t flag_val = 0;
+    if (EvalConstantValUint64(inst->GetOperandAs<uint32_t>(flag_operand),
+                              &flag_val)) {
+      if ((flag_val & static_cast<uint64_t>(
+                          spv::RayFlagsMask::ForceOpacityMicromap2StateKHR)) !=
+          0) {
+        assert(HasCapability(spv::Capability::RayQueryKHR) ||
+               HasCapability(spv::Capability::RayTracingKHR));
+        retval = HasCapability(spv::Capability::RayTracingOpacityMicromapKHR);
+      }
+    }
+    return retval;
+  }
+
   // Returns whether type result_type_id and type m2 are cooperative matrices
   // with the same "shape" (matching scope, rows, cols). If any are
   // specialization constants, we assume they can match because we can't prove
diff --git a/test/val/val_ray_query_test.cpp b/test/val/val_ray_query_test.cpp
index c383b93..35e6270 100644
--- a/test/val/val_ray_query_test.cpp
+++ b/test/val/val_ray_query_test.cpp
@@ -870,6 +870,249 @@
                         "point vector as Result Type"));
 }
 
+TEST_F(ValidateRayQuery, RayQueryOpacityMicromapSpvVersionCheck) {
+  const std::string shader = R"(
+               OpCapability Shader
+               OpCapability RayQueryKHR
+               OpCapability RayTracingOpacityMicromapExecutionModeKHR
+               OpExtension "SPV_KHR_ray_query"
+               OpExtension "SPV_KHR_opacity_micromap"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 1 1
+               OpExecutionModeId %main OpacityMicromapIdKHR %enable
+               OpDecorate %enable SpecId 4
+       %void = OpTypeVoid
+          %3 = OpTypeFunction %void
+       %bool = OpTypeBool
+     %enable = OpSpecConstantFalse %bool
+       %main = OpFunction %void None %3
+ %main_label = OpLabel
+               OpReturn
+               OpFunctionEnd
+)";
+  CompileSuccessfully(shader.c_str(), SPV_ENV_UNIVERSAL_1_3);
+  ASSERT_EQ(SPV_ERROR_WRONG_VERSION,
+            ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("SPV_KHR_opacity_micromap extension requires SPIR-V "
+                        "version 1.4 or later."));
+}
+
+TEST_F(ValidateRayQuery, OpacityMicromapExtensionStringIsMissing) {
+  const std::string shader = R"(
+               OpCapability Shader
+               OpCapability RayQueryKHR
+               OpCapability RayTracingOpacityMicromapExecutionModeKHR
+               OpExtension "SPV_KHR_ray_query"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 1 1
+               OpExecutionModeId %main OpacityMicromapIdKHR %enable
+               OpDecorate %enable SpecId 4
+       %void = OpTypeVoid
+          %3 = OpTypeFunction %void
+       %bool = OpTypeBool
+     %enable = OpSpecConstantFalse %bool
+       %main = OpFunction %void None %3
+ %main_label = OpLabel
+               OpReturn
+               OpFunctionEnd
+)";
+  CompileSuccessfully(shader.c_str(), SPV_ENV_UNIVERSAL_1_4);
+  ASSERT_EQ(SPV_ERROR_MISSING_EXTENSION,
+            ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("requires one of these extensions: SPV_KHR_opacity_micromap"));
+}
+
+TEST_F(ValidateRayQuery,
+       OpacityMicromapExecutionModeRejectsEXTExtensionString) {
+  const std::string shader = R"(
+               OpCapability Shader
+               OpCapability RayQueryKHR
+               OpCapability RayTracingOpacityMicromapExecutionModeKHR
+               OpExtension "SPV_KHR_ray_query"
+               OpExtension "SPV_EXT_opacity_micromap"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 1 1
+               OpExecutionModeId %main OpacityMicromapIdKHR %enable
+               OpDecorate %enable SpecId 4
+       %void = OpTypeVoid
+          %3 = OpTypeFunction %void
+       %bool = OpTypeBool
+     %enable = OpSpecConstantFalse %bool
+       %main = OpFunction %void None %3
+ %main_label = OpLabel
+               OpReturn
+               OpFunctionEnd
+)";
+  CompileSuccessfully(shader.c_str(), SPV_ENV_UNIVERSAL_1_4);
+  ASSERT_EQ(SPV_ERROR_MISSING_EXTENSION,
+            ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("requires one of these extensions: SPV_KHR_opacity_micromap"));
+}
+
+TEST_F(ValidateRayQuery, RayQueryOpacityMicromapId_1) {
+  const std::string shader = R"(
+               OpCapability Shader
+               OpCapability RayQueryKHR
+               OpCapability RayTracingOpacityMicromapExecutionModeKHR
+               OpExtension "SPV_KHR_opacity_micromap"
+               OpExtension "SPV_KHR_ray_query"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 1 1
+               OpExecutionModeId %main OpacityMicromapIdKHR %omm
+       %void = OpTypeVoid
+          %3 = OpTypeFunction %void
+        %i32 = OpTypeInt 32 0
+        %omm = OpConstant %i32 9
+       %main = OpFunction %void None %3
+ %main_label = OpLabel
+               OpReturn
+               OpFunctionEnd
+)";
+  CompileSuccessfully(shader.c_str(), SPV_ENV_UNIVERSAL_1_4);
+  ASSERT_EQ(SPV_ERROR_INVALID_DATA,
+            ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("OpacityMicromapIdKHR's operand must be an <id> of a "
+                        "constant instruction of OpTypeBool"));
+}
+
+TEST_F(ValidateRayQuery, RayQueryOpacityMicromapId_2) {
+  const std::string shader = R"(
+               OpCapability Shader
+               OpCapability RayQueryKHR
+               OpCapability RayTracingOpacityMicromapExecutionModeKHR
+               OpExtension "SPV_KHR_opacity_micromap"
+               OpExtension "SPV_KHR_ray_query"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 1 1
+               OpExecutionModeId %main OpacityMicromapIdKHR %omm
+               OpDecorate %omm SpecId 4
+       %void = OpTypeVoid
+          %3 = OpTypeFunction %void
+        %i32 = OpTypeInt 32 0
+        %omm = OpSpecConstant %i32 9
+       %main = OpFunction %void None %3
+ %main_label = OpLabel
+               OpReturn
+               OpFunctionEnd
+)";
+  CompileSuccessfully(shader.c_str(), SPV_ENV_UNIVERSAL_1_4);
+  ASSERT_EQ(SPV_ERROR_INVALID_DATA,
+            ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("OpacityMicromapIdKHR's operand must be an <id> of a "
+                        "constant instruction of OpTypeBool"));
+}
+
+TEST_F(ValidateRayQuery, RayQueryOpacityMicromapId_4) {
+  const std::string shader = R"(
+               OpCapability Shader
+               OpCapability RayQueryKHR
+               OpCapability RayTracingOpacityMicromapKHR
+               OpExtension "SPV_KHR_opacity_micromap"
+               OpExtension "SPV_KHR_ray_query"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 1 1
+               OpExecutionModeId %main OpacityMicromapIdKHR %omm
+               OpDecorate %omm SpecId 4
+       %void = OpTypeVoid
+          %3 = OpTypeFunction %void
+       %bool = OpTypeBool
+        %omm = OpSpecConstantFalse %bool
+       %main = OpFunction %void None %3
+ %main_label = OpLabel
+               OpReturn
+               OpFunctionEnd
+)";
+  CompileSuccessfully(shader.c_str(), SPV_ENV_UNIVERSAL_1_4);
+  ASSERT_EQ(SPV_ERROR_INVALID_CAPABILITY,
+            ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr("Operand 2 of ExecutionModeId requires one of these "
+                "capabilities: RayTracingOpacityMicromapExecutionModeKHR"));
+}
+
+TEST_F(ValidateRayQuery,
+       RayQueryInitializeForceOpacityMicromap2StateKHRCapabilityCheck) {
+  const std::string shader = R"(
+               OpCapability Shader
+               OpCapability RayQueryKHR
+               OpExtension "SPV_KHR_opacity_micromap"
+               OpExtension "SPV_KHR_ray_query"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main" %4725
+       %void = OpTypeVoid
+          %3 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+   %_st_4530 = OpTypeStruct %uint
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+    %type_rq = OpTypeRayQueryKHR
+       %4723 = OpTypeAccelerationStructureKHR
+%_ptr_UniformConstant_4723 = OpTypePointer UniformConstant %4723
+     %rq_ptr = OpTypePointer Private %type_rq
+       %4725 = OpVariable %_ptr_UniformConstant_4723 UniformConstant
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+       %flag = OpConstant %uint 1024
+    %float_1 = OpConstant %float 1
+  %v3float_1 = OpConstantComposite %v3float %float_1 %float_1 %float_1
+     %ptr_rq = OpTypePointer Function %type_rq
+       %main = OpFunction %void None %3
+ %main_label = OpLabel
+  %ray_query = OpVariable %ptr_rq Function
+       %4726 = OpLoad %4723 %4725
+               OpRayQueryInitializeKHR %ray_query %4726 %flag %uint_1 %v3float_1 %float_1 %v3float_1 %float_1
+               OpReturn
+               OpFunctionEnd
+)";
+  CompileSuccessfully(shader.c_str(), SPV_ENV_UNIVERSAL_1_4);
+  ASSERT_EQ(SPV_ERROR_INVALID_CAPABILITY,
+            ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("The ForceOpacityMicromap2StateKHR flag requires the "
+                        "RayTracingOpacityMicromapKHR and RayQueryKHR or "
+                        "RayTracingKHR capabilities"));
+}
+
+TEST_F(ValidateRayQuery, RayQueryOpacityMicromapGood) {
+  const std::string shader = R"(
+               OpCapability Shader
+               OpCapability RayQueryKHR
+               OpCapability RayTracingOpacityMicromapKHR
+               OpCapability RayTracingOpacityMicromapExecutionModeKHR
+               OpExtension "SPV_KHR_opacity_micromap"
+               OpExtension "SPV_KHR_ray_query"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 1 1
+               OpExecutionModeId %main OpacityMicromapIdKHR %omm
+               OpDecorate %omm SpecId 4
+       %void = OpTypeVoid
+          %3 = OpTypeFunction %void
+       %bool = OpTypeBool
+        %omm = OpSpecConstantFalse %bool
+       %main = OpFunction %void None %3
+ %main_label = OpLabel
+               OpReturn
+               OpFunctionEnd
+)";
+  CompileSuccessfully(shader.c_str(), SPV_ENV_UNIVERSAL_1_4);
+  ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
+}
+
 }  // namespace
 }  // namespace val
 }  // namespace spvtools
diff --git a/test/val/val_ray_tracing_test.cpp b/test/val/val_ray_tracing_test.cpp
index 476b228..977bfae 100644
--- a/test/val/val_ray_tracing_test.cpp
+++ b/test/val/val_ray_tracing_test.cpp
@@ -698,6 +698,46 @@
                         "RayTracingPositionFetchKHR"));
 }
 
+TEST_F(ValidateRayTracing, ForceOpacityMicromap2StateKHRCapabilityCheck) {
+  const std::string shader = R"(
+               OpCapability Shader
+               OpCapability RayTracingKHR
+               OpExtension "SPV_KHR_opacity_micromap"
+               OpExtension "SPV_KHR_ray_tracing"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint RayGenerationKHR %main "main" %4725 %payload
+       %void = OpTypeVoid
+          %3 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+   %_st_4530 = OpTypeStruct %uint
+       %_ptr = OpTypePointer RayPayloadKHR %_st_4530
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+       %4723 = OpTypeAccelerationStructureKHR
+%_ptr_UniformConstant_4723 = OpTypePointer UniformConstant %4723
+       %4725 = OpVariable %_ptr_UniformConstant_4723 UniformConstant
+    %payload = OpVariable %_ptr RayPayloadKHR
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+       %flag = OpConstant %uint 1024
+    %float_1 = OpConstant %float 1
+  %v3float_1 = OpConstantComposite %v3float %float_1 %float_1 %float_1
+       %main = OpFunction %void None %3
+ %main_label = OpLabel
+       %4726 = OpLoad %4723 %4725
+               OpTraceRayKHR %4726 %flag %uint_1 %uint_2 %uint_1 %uint_2 %v3float_1 %float_1 %v3float_1 %float_1 %payload
+               OpReturn
+               OpFunctionEnd
+)";
+  CompileSuccessfully(shader.c_str(), SPV_ENV_UNIVERSAL_1_4);
+  ASSERT_EQ(SPV_ERROR_INVALID_CAPABILITY,
+            ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("The ForceOpacityMicromap2StateKHR flag requires the "
+                        "RayTracingOpacityMicromapKHR and RayQueryKHR or "
+                        "RayTracingKHR capabilities"));
+}
+
 }  // namespace
 }  // namespace val
 }  // namespace spvtools