spirv-val: Add CullMaskKHR support (#4792)

Co-authored-by: sfricke-samsung <s.fricke@samsung.com>
diff --git a/source/val/validate_builtins.cpp b/source/val/validate_builtins.cpp
index 6a2e919..0ee2b09 100644
--- a/source/val/validate_builtins.cpp
+++ b/source/val/validate_builtins.cpp
@@ -120,7 +120,7 @@
   VUIDErrorMax,
 } VUIDError;
 
-const static uint32_t NumVUIDBuiltins = 33;
+const static uint32_t NumVUIDBuiltins = 34;
 
 typedef struct {
   SpvBuiltIn builtIn;
@@ -162,6 +162,7 @@
     {SpvBuiltInFragSizeEXT,               {4220, 4221, 4222}},
     {SpvBuiltInFragStencilRefEXT,         {4223, 4224, 4225}},
     {SpvBuiltInFullyCoveredEXT,           {4232, 4233, 4234}},
+    {SpvBuiltInCullMaskKHR,               {6735, 6736, 6737}},
     // clang-format off
 } };
 
@@ -208,6 +209,7 @@
     case SpvBuiltInRayTmaxKHR:
     case SpvBuiltInWorldRayDirectionKHR:
     case SpvBuiltInWorldRayOriginKHR:
+    case SpvBuiltInCullMaskKHR:
       switch (stage) {
         case SpvExecutionModelIntersectionKHR:
         case SpvExecutionModelAnyHitKHR:
@@ -3851,6 +3853,7 @@
       case SpvBuiltInInstanceId:
       case SpvBuiltInRayGeometryIndexKHR:
       case SpvBuiltInIncomingRayFlagsKHR:
+      case SpvBuiltInCullMaskKHR:
         // i32 scalar
         if (spv_result_t error = ValidateI32(
                 decoration, inst,
@@ -4151,7 +4154,8 @@
     case SpvBuiltInObjectToWorldKHR:        // alias SpvBuiltInObjectToWorldNV
     case SpvBuiltInWorldToObjectKHR:        // alias SpvBuiltInWorldToObjectNV
     case SpvBuiltInIncomingRayFlagsKHR:    // alias SpvBuiltInIncomingRayFlagsNV
-    case SpvBuiltInRayGeometryIndexKHR: {  // NOT present in NV
+    case SpvBuiltInRayGeometryIndexKHR:    // NOT present in NV
+    case SpvBuiltInCullMaskKHR: {
       return ValidateRayTracingBuiltinsAtDefinition(decoration, inst);
     }
     case SpvBuiltInWorkDim:
@@ -4185,7 +4189,6 @@
     case SpvBuiltInBaryCoordNV:
     case SpvBuiltInBaryCoordNoPerspNV:
     case SpvBuiltInCurrentRayTimeNV:
-    case SpvBuiltInCullMaskKHR:
       // No validation rules (for the moment).
       break;
 
diff --git a/source/val/validation_state.cpp b/source/val/validation_state.cpp
index 9aa6c63..9ae6d07 100644
--- a/source/val/validation_state.cpp
+++ b/source/val/validation_state.cpp
@@ -1443,6 +1443,12 @@
       return VUID_WRAP(VUID-CullDistance-CullDistance-04199);
     case 4200:
       return VUID_WRAP(VUID-CullDistance-CullDistance-04200);
+    case 6735:
+      return VUID_WRAP(VUID-CullMaskKHR-CullMaskKHR-06735); // Execution Model
+    case 6736:
+      return VUID_WRAP(VUID-CullMaskKHR-CullMaskKHR-06736); // input storage
+    case 6737:
+      return VUID_WRAP(VUID-CullMaskKHR-CullMaskKHR-06737); // 32 int scalar
     case 4205:
       return VUID_WRAP(VUID-DeviceIndex-DeviceIndex-04205);
     case 4206:
@@ -1926,4 +1932,4 @@
 }
 
 }  // namespace val
-}  // namespace spvtools
\ No newline at end of file
+}  // namespace spvtools
diff --git a/test/val/val_builtins_test.cpp b/test/val/val_builtins_test.cpp
index d749c5a..454bab7 100644
--- a/test/val/val_builtins_test.cpp
+++ b/test/val/val_builtins_test.cpp
@@ -2372,6 +2372,67 @@
                               "needs to be a 32-bit int scalar",
                               "is not an int scalar"))));
 
+// CullMaskKHR is valid
+// in IS, AH, CH, MS shaders as an input i32 scalar
+INSTANTIATE_TEST_SUITE_P(
+    CullMaskSuccess,
+    ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+    Combine(Values(SPV_ENV_VULKAN_1_2), Values("CullMaskKHR"),
+            Values("AnyHitKHR", "ClosestHitKHR", "IntersectionKHR", "MissKHR"),
+            Values("Input"), Values("%u32"),
+            Values("OpCapability RayTracingKHR\nOpCapability RayCullMaskKHR\n"),
+            Values("OpExtension \"SPV_KHR_ray_tracing\"\nOpExtension "
+                   "\"SPV_KHR_ray_cull_mask\"\n"),
+            Values(nullptr), Values(TestResult())));
+
+INSTANTIATE_TEST_SUITE_P(
+    CullMaskNotExecutionMode,
+    ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+    Combine(Values(SPV_ENV_VULKAN_1_2), Values("CullMaskKHR"),
+            Values("Vertex", "Fragment", "TessellationControl",
+                   "TessellationEvaluation", "Geometry", "Fragment",
+                   "GLCompute", "RayGenerationKHR", "CallableKHR"),
+            Values("Input"), Values("%u32"),
+            Values("OpCapability RayTracingKHR\nOpCapability RayCullMaskKHR\n"),
+            Values("OpExtension \"SPV_KHR_ray_tracing\"\nOpExtension "
+                   "\"SPV_KHR_ray_cull_mask\"\n"),
+            Values("VUID-CullMaskKHR-CullMaskKHR-06735 "
+                   "VUID-RayTmaxKHR-RayTmaxKHR-04348 "
+                   "VUID-RayTminKHR-RayTminKHR-04351 "),
+            Values(TestResult(SPV_ERROR_INVALID_DATA,
+                              "Vulkan spec does not allow BuiltIn",
+                              "to be used with the execution model"))));
+
+INSTANTIATE_TEST_SUITE_P(
+    ICullMaskNotInput,
+    ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+    Combine(Values(SPV_ENV_VULKAN_1_2), Values("CullMaskKHR"),
+            Values("AnyHitKHR", "ClosestHitKHR", "IntersectionKHR", "MissKHR"),
+            Values("Output"), Values("%u32"),
+            Values("OpCapability RayTracingKHR\nOpCapability RayCullMaskKHR\n"),
+            Values("OpExtension \"SPV_KHR_ray_tracing\"\nOpExtension "
+                   "\"SPV_KHR_ray_cull_mask\"\n"),
+            Values("VUID-CullMaskKHR-CullMaskKHR-06736 "
+                   "VUID-RayTmaxKHR-RayTmaxKHR-04349 "
+                   "VUID-RayTminKHR-RayTminKHR-04352 "),
+            Values(TestResult(SPV_ERROR_INVALID_DATA, "Vulkan spec allows",
+                              "used for variables with Input storage class"))));
+INSTANTIATE_TEST_SUITE_P(
+    CullMaskNotIntScalar,
+    ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+    Combine(Values(SPV_ENV_VULKAN_1_2), Values("CullMaskKHR"),
+            Values("AnyHitKHR", "ClosestHitKHR", "IntersectionKHR", "MissKHR"),
+            Values("Input"), Values("%f32", "%u32vec3"),
+            Values("OpCapability RayTracingKHR\nOpCapability RayCullMaskKHR\n"),
+            Values("OpExtension \"SPV_KHR_ray_tracing\"\nOpExtension "
+                   "\"SPV_KHR_ray_cull_mask\"\n"),
+            Values("VUID-CullMaskKHR-CullMaskKHR-06737 "
+                   "VUID-RayTmaxKHR-RayTmaxKHR-04350 "
+                   "VUID-RayTminKHR-RayTminKHR-04353 "),
+            Values(TestResult(SPV_ERROR_INVALID_DATA,
+                              "needs to be a 32-bit int scalar",
+                              "is not an int scalar"))));
+
 // RayTmaxKHR, RayTminKHR are all valid
 // in IS, AH, CH, MS shaders as input f32 scalars
 INSTANTIATE_TEST_SUITE_P(