Add validation support for the ray tracing built-in variables (#4041)

* Add validation for ray tracing builtins

- Remove existing InstanceId testing that was combined with VertexId in awkward ways.
- Rather than adding a new set of functions for each ray tracing builtin, add
  an error table that maps the builtin ID to the 3 common VUIDs for each builtin
  (I could see this being extended for other builtins in the future).
- add F32 matrix validation function
- augment existing PrimitiveId validation to verify Input storage class for the
  RT stages this is accepted in, and correct the list of stages that it is actually
  accepted in (only Intersection / Any Hit / Closest Hit)

* add testing for ray tracing builtins

- remove exising InstanceId testing as it was tangled in with VertexId in now weird ways
  and combine it with the new tests
- add testing for ray tracing builtins
- builtins accepted in the same stages and of the same types are combined into test functions
- add some new matrix types to the code generator so they can be used for testing
diff --git a/source/val/validate_builtins.cpp b/source/val/validate_builtins.cpp
index d9e0666..1d8a140 100644
--- a/source/val/validate_builtins.cpp
+++ b/source/val/validate_builtins.cpp
@@ -16,6 +16,7 @@
 
 // Validates correctness of built-in variables.
 
+#include <array>
 #include <functional>
 #include <list>
 #include <map>
@@ -134,6 +135,114 @@
   return false;
 }
 
+typedef enum VUIDError_ {
+  VUIDErrorExecutionModel = 0,
+  VUIDErrorStorageClass = 1,
+  VUIDErrorType = 2,
+  VUIDErrorMax,
+} VUIDError;
+
+const static uint32_t NumRtBuiltins = 16;
+
+typedef struct {
+  SpvBuiltIn builtIn;
+  uint32_t vuid[VUIDErrorMax];  // execution mode, storage class, type VUIDs
+} RtBuiltinVUIDMapping;
+
+std::array<RtBuiltinVUIDMapping, NumRtBuiltins> rtBuiltinInfo = {{
+    // clang-format off
+    {SpvBuiltInHitKindKHR,                {4242, 4243, 4244}},
+    {SpvBuiltInHitTNV,                    {4245, 4246, 4247}},
+    {SpvBuiltInInstanceCustomIndexKHR,    {4251, 4252, 4253}},
+    {SpvBuiltInInstanceId,                {4254, 4255, 4256}},
+    {SpvBuiltInRayGeometryIndexKHR,       {4345, 4346, 4347}},
+    {SpvBuiltInObjectRayDirectionKHR,     {4299, 4300, 4301}},
+    {SpvBuiltInObjectRayOriginKHR,        {4302, 4303, 4304}},
+    {SpvBuiltInObjectToWorldKHR,          {4305, 4306, 4307}},
+    {SpvBuiltInWorldToObjectKHR,          {4434, 4435, 4436}},
+    {SpvBuiltInIncomingRayFlagsKHR,       {4248, 4249, 4250}},
+    {SpvBuiltInRayTminKHR,                {4351, 4352, 4353}},
+    {SpvBuiltInRayTmaxKHR,                {4348, 4349, 4350}},
+    {SpvBuiltInWorldRayDirectionKHR,      {4428, 4429, 4430}},
+    {SpvBuiltInWorldRayOriginKHR,         {4431, 4432, 4433}},
+    {SpvBuiltInLaunchIdKHR,               {4266, 4267, 4268}},
+    {SpvBuiltInLaunchSizeKHR,             {4269, 4270, 4271}},
+    // clang-format off
+} };
+
+uint32_t GetVUIDForRTBuiltin(SpvBuiltIn builtIn, VUIDError type) {
+  uint32_t vuid = 0;
+  for (const auto& iter: rtBuiltinInfo) {
+    if (iter.builtIn == builtIn) {
+      assert(type < VUIDErrorMax);
+      vuid = iter.vuid[type];
+      break;
+    }
+  }
+  return vuid;
+}
+
+bool IsExecutionModelValidForRtBuiltIn(SpvBuiltIn builtin,
+                                       SpvExecutionModel stage) {
+  switch (builtin) {
+    case SpvBuiltInHitKindKHR:
+    case SpvBuiltInHitTNV:
+      if (stage == SpvExecutionModelAnyHitKHR ||
+          stage == SpvExecutionModelClosestHitKHR) {
+        return true;
+      }
+      break;
+    case SpvBuiltInInstanceCustomIndexKHR:
+    case SpvBuiltInInstanceId:
+    case SpvBuiltInRayGeometryIndexKHR:
+    case SpvBuiltInObjectRayDirectionKHR:
+    case SpvBuiltInObjectRayOriginKHR:
+    case SpvBuiltInObjectToWorldKHR:
+    case SpvBuiltInWorldToObjectKHR:
+      switch (stage) {
+        case SpvExecutionModelIntersectionKHR:
+        case SpvExecutionModelAnyHitKHR:
+        case SpvExecutionModelClosestHitKHR:
+          return true;
+        default:
+          return false;
+      }
+      break;
+    case SpvBuiltInIncomingRayFlagsKHR:
+    case SpvBuiltInRayTminKHR:
+    case SpvBuiltInRayTmaxKHR:
+    case SpvBuiltInWorldRayDirectionKHR:
+    case SpvBuiltInWorldRayOriginKHR:
+      switch (stage) {
+        case SpvExecutionModelIntersectionKHR:
+        case SpvExecutionModelAnyHitKHR:
+        case SpvExecutionModelClosestHitKHR:
+        case SpvExecutionModelMissKHR:
+          return true;
+        default:
+          return false;
+      }
+      break;
+    case SpvBuiltInLaunchIdKHR:
+    case SpvBuiltInLaunchSizeKHR:
+      switch (stage) {
+        case SpvExecutionModelRayGenerationKHR:
+        case SpvExecutionModelIntersectionKHR:
+        case SpvExecutionModelAnyHitKHR:
+        case SpvExecutionModelClosestHitKHR:
+        case SpvExecutionModelMissKHR:
+        case SpvExecutionModelCallableKHR:
+          return true;
+        default:
+          return false;
+      }
+      break;
+    default:
+      break;
+  }
+  return false;
+}
+
 // Helper class managing validation of built-ins.
 // TODO: Generic functionality of this class can be moved into
 // ValidationState_t to be made available to other users.
@@ -200,8 +309,8 @@
                                                   const Instruction& inst);
   spv_result_t ValidateVertexIndexAtDefinition(const Decoration& decoration,
                                                const Instruction& inst);
-  spv_result_t ValidateVertexIdOrInstanceIdAtDefinition(
-      const Decoration& decoration, const Instruction& inst);
+  spv_result_t ValidateVertexIdAtDefinition(const Decoration& decoration,
+                                            const Instruction& inst);
   spv_result_t ValidateLocalInvocationIndexAtDefinition(
       const Decoration& decoration, const Instruction& inst);
   spv_result_t ValidateWorkgroupSizeAtDefinition(const Decoration& decoration,
@@ -237,6 +346,9 @@
   spv_result_t ValidateShadingRateAtDefinition(const Decoration& decoration,
                                                const Instruction& inst);
 
+  spv_result_t ValidateRayTracingBuiltinsAtDefinition(
+      const Decoration& decoration, const Instruction& inst);
+
   // The following section contains functions which are called when id defined
   // by |referenced_inst| is
   // 1. referenced by |referenced_from_inst|
@@ -269,11 +381,6 @@
       const Instruction& referenced_inst,
       const Instruction& referenced_from_inst);
 
-  spv_result_t ValidateInstanceIdAtReference(
-      const Decoration& decoration, const Instruction& built_in_inst,
-      const Instruction& referenced_inst,
-      const Instruction& referenced_from_inst);
-
   spv_result_t ValidateInstanceIndexAtReference(
       const Decoration& decoration, const Instruction& built_in_inst,
       const Instruction& referenced_inst,
@@ -400,6 +507,11 @@
       const Instruction& referenced_inst,
       const Instruction& referenced_from_inst);
 
+  spv_result_t ValidateRayTracingBuiltinsAtReference(
+      const Decoration& decoration, const Instruction& built_in_inst,
+      const Instruction& referenced_inst,
+      const Instruction& referenced_from_inst);
+
   // Validates that |built_in_inst| is not (even indirectly) referenced from
   // within a function which can be called with |execution_model|.
   //
@@ -476,6 +588,10 @@
       uint32_t num_components,
       const std::function<spv_result_t(const std::string& message)>& diag,
       uint32_t underlying_type);
+  spv_result_t ValidateF32Mat(
+      const Decoration& decoration, const Instruction& inst,
+      uint32_t req_num_rows, uint32_t req_num_columns,
+      const std::function<spv_result_t(const std::string& message)>& diag);
 
   // Generates strings like "Member #0 of struct ID <2>".
   std::string GetDefinitionDesc(const Decoration& decoration,
@@ -909,6 +1025,32 @@
   return SPV_SUCCESS;
 }
 
+spv_result_t BuiltInsValidator::ValidateF32Mat(
+    const Decoration& decoration, const Instruction& inst,
+    uint32_t req_num_rows, uint32_t req_num_columns,
+    const std::function<spv_result_t(const std::string& message)>& diag) {
+  uint32_t underlying_type = 0;
+  uint32_t num_rows = 0;
+  uint32_t num_cols = 0;
+  uint32_t col_type = 0;
+  uint32_t component_type = 0;
+  if (spv_result_t error =
+          GetUnderlyingType(_, decoration, inst, &underlying_type)) {
+    return error;
+  }
+  if (!_.GetMatrixTypeInfo(underlying_type, &num_rows, &num_cols, &col_type,
+                           &component_type) ||
+      num_rows != req_num_rows || num_cols != req_num_columns) {
+    std::ostringstream ss;
+    ss << GetDefinitionDesc(decoration, inst) << " has columns " << num_cols
+       << " and rows " << num_rows << " not equal to expected "
+       << req_num_columns << "x" << req_num_rows << ".";
+    return diag(ss.str());
+  }
+
+  return ValidateF32VecHelper(decoration, inst, req_num_rows, diag, col_type);
+}
+
 spv_result_t BuiltInsValidator::ValidateNotCalledWithExecutionModel(
     int vuid, const char* comment, SpvExecutionModel execution_model,
     const Decoration& decoration, const Instruction& built_in_inst,
@@ -1947,6 +2089,27 @@
           "Fragment.",
           SpvExecutionModelFragment, decoration, built_in_inst,
           referenced_from_inst, std::placeholders::_1));
+      id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
+          &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, 4334,
+          "Vulkan spec doesn't allow BuiltIn PrimitiveId to be used for "
+          "variables with Output storage class if execution model is "
+          "IntersectionKHR.",
+          SpvExecutionModelIntersectionKHR, decoration, built_in_inst,
+          referenced_from_inst, std::placeholders::_1));
+      id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
+          &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, 4334,
+          "Vulkan spec doesn't allow BuiltIn PrimitiveId to be used for "
+          "variables with Output storage class if execution model is "
+          "AnyHitKHR.",
+          SpvExecutionModelAnyHitKHR, decoration, built_in_inst,
+          referenced_from_inst, std::placeholders::_1));
+      id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
+          &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, 4334,
+          "Vulkan spec doesn't allow BuiltIn PrimitiveId to be used for "
+          "variables with Output storage class if execution model is "
+          "ClosestHitKHR.",
+          SpvExecutionModelClosestHitKHR, decoration, built_in_inst,
+          referenced_from_inst, std::placeholders::_1));
     }
 
     for (const SpvExecutionModel execution_model : execution_models_) {
@@ -1956,12 +2119,9 @@
         case SpvExecutionModelTessellationEvaluation:
         case SpvExecutionModelGeometry:
         case SpvExecutionModelMeshNV:
-        case SpvExecutionModelRayGenerationNV:
-        case SpvExecutionModelIntersectionNV:
-        case SpvExecutionModelAnyHitNV:
-        case SpvExecutionModelClosestHitNV:
-        case SpvExecutionModelMissNV:
-        case SpvExecutionModelCallableNV: {
+        case SpvExecutionModelIntersectionKHR:
+        case SpvExecutionModelAnyHitKHR:
+        case SpvExecutionModelClosestHitKHR: {
           // Ok.
           break;
         }
@@ -1971,7 +2131,9 @@
                  << _.VkErrorID(4330)
                  << "Vulkan spec allows BuiltIn PrimitiveId to be used only "
                     "with Fragment, TessellationControl, "
-                    "TessellationEvaluation or Geometry execution models. "
+                    "TessellationEvaluation, Geometry, MeshNV, "
+                    "IntersectionKHR, "
+                    "AnyHitKHR, and ClosestHitKHR execution models. "
                  << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
                                      referenced_from_inst, execution_model);
         }
@@ -2372,54 +2534,13 @@
   return ValidateVertexIndexAtReference(decoration, inst, inst, inst);
 }
 
-spv_result_t BuiltInsValidator::ValidateVertexIdOrInstanceIdAtDefinition(
+spv_result_t BuiltInsValidator::ValidateVertexIdAtDefinition(
     const Decoration& decoration, const Instruction& inst) {
-  const SpvBuiltIn label = SpvBuiltIn(decoration.params()[0]);
-  bool allow_instance_id = (_.HasCapability(SpvCapabilityRayTracingNV) ||
-                            _.HasCapability(SpvCapabilityRayTracingKHR)) &&
-                           label == SpvBuiltInInstanceId;
-
-  if (spvIsVulkanEnv(_.context()->target_env) && !allow_instance_id) {
-    return _.diag(SPV_ERROR_INVALID_DATA, &inst)
-           << "Vulkan spec doesn't allow BuiltIn VertexId/InstanceId "
-              "to be used.";
-  }
-
-  if (label == SpvBuiltInInstanceId) {
-    return ValidateInstanceIdAtReference(decoration, inst, inst, inst);
-  }
-  return SPV_SUCCESS;
-}
-
-spv_result_t BuiltInsValidator::ValidateInstanceIdAtReference(
-    const Decoration& decoration, const Instruction& built_in_inst,
-    const Instruction& referenced_inst,
-    const Instruction& referenced_from_inst) {
+  (void)decoration;
   if (spvIsVulkanEnv(_.context()->target_env)) {
-    for (const SpvExecutionModel execution_model : execution_models_) {
-      switch (execution_model) {
-        case SpvExecutionModelIntersectionNV:
-        case SpvExecutionModelClosestHitNV:
-        case SpvExecutionModelAnyHitNV:
-          // Do nothing, valid stages
-          break;
-        default:
-          return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
-                 << "Vulkan spec allows BuiltIn InstanceId to be used "
-                    "only with IntersectionNV, ClosestHitNV and AnyHitNV "
-                    "execution models. "
-                 << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
-                                     referenced_from_inst);
-          break;
-      }
-    }
-  }
-
-  if (function_id_ == 0) {
-    // Propagate this rule to all dependant ids in the global scope.
-    id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
-        &BuiltInsValidator::ValidateInstanceIdAtReference, this, decoration,
-        built_in_inst, referenced_from_inst, std::placeholders::_1));
+    return _.diag(SPV_ERROR_INVALID_DATA, &inst)
+           << "Vulkan spec doesn't allow BuiltIn VertexId "
+              "to be used.";
   }
 
   return SPV_SUCCESS;
@@ -3474,6 +3595,174 @@
   return SPV_SUCCESS;
 }
 
+spv_result_t BuiltInsValidator::ValidateRayTracingBuiltinsAtDefinition(
+    const Decoration& decoration, const Instruction& inst) {
+  if (spvIsVulkanEnv(_.context()->target_env)) {
+    const SpvBuiltIn builtin = SpvBuiltIn(decoration.params()[0]);
+    switch (builtin) {
+      case SpvBuiltInHitTNV:
+      case SpvBuiltInRayTminKHR:
+      case SpvBuiltInRayTmaxKHR:
+        // f32 scalar
+        if (spv_result_t error = ValidateF32(
+                decoration, inst,
+                [this, &inst,
+                 builtin](const std::string& message) -> spv_result_t {
+                  uint32_t vuid = GetVUIDForRTBuiltin(builtin, VUIDErrorType);
+                  return _.diag(SPV_ERROR_INVALID_DATA, &inst)
+                         << _.VkErrorID(vuid)
+                         << "According to the Vulkan spec BuiltIn "
+                         << _.grammar().lookupOperandName(
+                                SPV_OPERAND_TYPE_BUILT_IN, builtin)
+                         << " variable needs to be a 32-bit float scalar. "
+                         << message;
+                })) {
+          return error;
+        }
+        break;
+      case SpvBuiltInHitKindKHR:
+      case SpvBuiltInInstanceCustomIndexKHR:
+      case SpvBuiltInInstanceId:
+      case SpvBuiltInRayGeometryIndexKHR:
+      case SpvBuiltInIncomingRayFlagsKHR:
+        // i32 scalar
+        if (spv_result_t error = ValidateI32(
+                decoration, inst,
+                [this, &inst,
+                 builtin](const std::string& message) -> spv_result_t {
+                  uint32_t vuid = GetVUIDForRTBuiltin(builtin, VUIDErrorType);
+                  return _.diag(SPV_ERROR_INVALID_DATA, &inst)
+                         << _.VkErrorID(vuid)
+                         << "According to the Vulkan spec BuiltIn "
+                         << _.grammar().lookupOperandName(
+                                SPV_OPERAND_TYPE_BUILT_IN, builtin)
+                         << " variable needs to be a 32-bit int scalar. "
+                         << message;
+                })) {
+          return error;
+        }
+        break;
+      case SpvBuiltInObjectRayDirectionKHR:
+      case SpvBuiltInObjectRayOriginKHR:
+      case SpvBuiltInWorldRayDirectionKHR:
+      case SpvBuiltInWorldRayOriginKHR:
+        // f32 vec3
+        if (spv_result_t error = ValidateF32Vec(
+                decoration, inst, 3,
+                [this, &inst,
+                 builtin](const std::string& message) -> spv_result_t {
+                  uint32_t vuid = GetVUIDForRTBuiltin(builtin, VUIDErrorType);
+                  return _.diag(SPV_ERROR_INVALID_DATA, &inst)
+                         << _.VkErrorID(vuid)
+                         << "According to the Vulkan spec BuiltIn "
+                         << _.grammar().lookupOperandName(
+                                SPV_OPERAND_TYPE_BUILT_IN, builtin)
+                         << " variable needs to be a 3-component 32-bit float "
+                            "vector. "
+                         << message;
+                })) {
+          return error;
+        }
+        break;
+      case SpvBuiltInLaunchIdKHR:
+      case SpvBuiltInLaunchSizeKHR:
+        // i32 vec3
+        if (spv_result_t error = ValidateI32Vec(
+                decoration, inst, 3,
+                [this, &inst,
+                 builtin](const std::string& message) -> spv_result_t {
+                  uint32_t vuid = GetVUIDForRTBuiltin(builtin, VUIDErrorType);
+                  return _.diag(SPV_ERROR_INVALID_DATA, &inst)
+                         << _.VkErrorID(vuid)
+                         << "According to the Vulkan spec BuiltIn "
+                         << _.grammar().lookupOperandName(
+                                SPV_OPERAND_TYPE_BUILT_IN, builtin)
+                         << " variable needs to be a 3-component 32-bit int "
+                            "vector. "
+                         << message;
+                })) {
+          return error;
+        }
+        break;
+      case SpvBuiltInObjectToWorldKHR:
+      case SpvBuiltInWorldToObjectKHR:
+        // f32 mat4x3
+        if (spv_result_t error = ValidateF32Mat(
+                decoration, inst, 3, 4,
+                [this, &inst,
+                 builtin](const std::string& message) -> spv_result_t {
+                  uint32_t vuid = GetVUIDForRTBuiltin(builtin, VUIDErrorType);
+                  return _.diag(SPV_ERROR_INVALID_DATA, &inst)
+                         << _.VkErrorID(vuid)
+                         << "According to the Vulkan spec BuiltIn "
+                         << _.grammar().lookupOperandName(
+                                SPV_OPERAND_TYPE_BUILT_IN, builtin)
+                         << " variable needs to be a matrix with"
+                         << " 4 columns of 3-component vectors of 32-bit "
+                            "floats. "
+                         << message;
+                })) {
+          return error;
+        }
+        break;
+      default:
+        assert(0 && "Unexpected ray tracing builtin");
+        break;
+    }
+  }
+
+  // Seed at reference checks with this built-in.
+  return ValidateRayTracingBuiltinsAtReference(decoration, inst, inst, inst);
+}
+
+spv_result_t BuiltInsValidator::ValidateRayTracingBuiltinsAtReference(
+    const Decoration& decoration, const Instruction& built_in_inst,
+    const Instruction& referenced_inst,
+    const Instruction& referenced_from_inst) {
+  if (spvIsVulkanEnv(_.context()->target_env)) {
+    const SpvBuiltIn builtin = SpvBuiltIn(decoration.params()[0]);
+    const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst);
+    if (storage_class != SpvStorageClassMax &&
+        storage_class != SpvStorageClassInput) {
+      uint32_t vuid = GetVUIDForRTBuiltin(builtin, VUIDErrorStorageClass);
+      return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
+             << _.VkErrorID(vuid) << "Vulkan spec allows BuiltIn "
+             << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
+                                              decoration.params()[0])
+             << " to be only used for variables with Input storage class. "
+             << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
+                                 referenced_from_inst)
+             << " " << GetStorageClassDesc(referenced_from_inst);
+    }
+
+    for (const SpvExecutionModel execution_model : execution_models_) {
+      if (!IsExecutionModelValidForRtBuiltIn(builtin, execution_model)) {
+        uint32_t vuid = GetVUIDForRTBuiltin(builtin, VUIDErrorExecutionModel);
+        return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
+               << _.VkErrorID(vuid) << "Vulkan spec does not allow BuiltIn "
+               << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
+                                                decoration.params()[0])
+               << " to be used with the execution model "
+               << _.grammar().lookupOperandName(
+                      SPV_OPERAND_TYPE_EXECUTION_MODEL, execution_model)
+               << ".\n"
+               << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
+                                   referenced_from_inst, execution_model);
+      }
+    }
+  }
+
+  if (function_id_ == 0) {
+    // Propagate this rule to all dependant ids in the global scope.
+    id_to_at_reference_checks_[referenced_from_inst.id()].push_back(
+        std::bind(&BuiltInsValidator::ValidateRayTracingBuiltinsAtReference,
+                  this, decoration, built_in_inst, referenced_from_inst,
+                  std::placeholders::_1));
+  }
+
+  return SPV_SUCCESS;
+}
+
 spv_result_t BuiltInsValidator::ValidateSingleBuiltInAtDefinition(
     const Decoration& decoration, const Instruction& inst) {
   const SpvBuiltIn label = SpvBuiltIn(decoration.params()[0]);
@@ -3596,9 +3885,8 @@
     case SpvBuiltInWorkgroupSize: {
       return ValidateWorkgroupSizeAtDefinition(decoration, inst);
     }
-    case SpvBuiltInVertexId:
-    case SpvBuiltInInstanceId: {
-      return ValidateVertexIdOrInstanceIdAtDefinition(decoration, inst);
+    case SpvBuiltInVertexId: {
+      return ValidateVertexIdAtDefinition(decoration, inst);
     }
     case SpvBuiltInLocalInvocationIndex: {
       return ValidateLocalInvocationIndexAtDefinition(decoration, inst);
@@ -3622,6 +3910,27 @@
     case SpvBuiltInDeviceIndex: {
       return ValidateDeviceIndexAtDefinition(decoration, inst);
     }
+    // Ray tracing builtins
+    case SpvBuiltInHitKindKHR:  // alias SpvBuiltInHitKindNV
+    case SpvBuiltInHitTNV:      // NOT present in KHR
+    case SpvBuiltInInstanceId:
+    case SpvBuiltInLaunchIdKHR:           // alias SpvBuiltInLaunchIdNV
+    case SpvBuiltInLaunchSizeKHR:         // alias SpvBuiltInLaunchSizeNV
+    case SpvBuiltInWorldRayOriginKHR:     // alias SpvBuiltInWorldRayOriginNV
+    case SpvBuiltInWorldRayDirectionKHR:  // alias SpvBuiltInWorldRayDirectionNV
+    case SpvBuiltInObjectRayOriginKHR:    // alias SpvBuiltInObjectRayOriginNV
+    case SpvBuiltInObjectRayDirectionKHR:   // alias
+                                            // SpvBuiltInObjectRayDirectionNV
+    case SpvBuiltInRayTminKHR:              // alias SpvBuiltInRayTminNV
+    case SpvBuiltInRayTmaxKHR:              // alias SpvBuiltInRayTmaxNV
+    case SpvBuiltInInstanceCustomIndexKHR:  // alias
+                                            // SpvBuiltInInstanceCustomIndexNV
+    case SpvBuiltInObjectToWorldKHR:        // alias SpvBuiltInObjectToWorldNV
+    case SpvBuiltInWorldToObjectKHR:        // alias SpvBuiltInWorldToObjectNV
+    case SpvBuiltInIncomingRayFlagsKHR:    // alias SpvBuiltInIncomingRayFlagsNV
+    case SpvBuiltInRayGeometryIndexKHR: {  // NOT present in NV
+      return ValidateRayTracingBuiltinsAtDefinition(decoration, inst);
+    }
     case SpvBuiltInWorkDim:
     case SpvBuiltInGlobalSize:
     case SpvBuiltInEnqueuedWorkgroupSize:
@@ -3657,28 +3966,14 @@
     case SpvBuiltInFragmentSizeNV:         // alias SpvBuiltInFragSizeEXT
     case SpvBuiltInInvocationsPerPixelNV:  // alias
                                            // SpvBuiltInFragInvocationCountEXT
-    case SpvBuiltInLaunchIdNV:
-    case SpvBuiltInLaunchSizeNV:
-    case SpvBuiltInWorldRayOriginNV:
-    case SpvBuiltInWorldRayDirectionNV:
-    case SpvBuiltInObjectRayOriginNV:
-    case SpvBuiltInObjectRayDirectionNV:
-    case SpvBuiltInRayTminNV:
-    case SpvBuiltInRayTmaxNV:
-    case SpvBuiltInInstanceCustomIndexNV:
-    case SpvBuiltInObjectToWorldNV:
-    case SpvBuiltInWorldToObjectNV:
-    case SpvBuiltInHitTNV:
-    case SpvBuiltInHitKindNV:
-    case SpvBuiltInIncomingRayFlagsNV:
-    case SpvBuiltInRayGeometryIndexKHR: {
       // No validation rules (for the moment).
       break;
 
-      case SpvBuiltInPrimitiveShadingRateKHR:
-        return ValidatePrimitiveShadingRateAtDefinition(decoration, inst);
-      case SpvBuiltInShadingRateKHR:
-        return ValidateShadingRateAtDefinition(decoration, inst);
+    case SpvBuiltInPrimitiveShadingRateKHR: {
+      return ValidatePrimitiveShadingRateAtDefinition(decoration, inst);
+    }
+    case SpvBuiltInShadingRateKHR: {
+      return ValidateShadingRateAtDefinition(decoration, inst);
     }
   }
   return SPV_SUCCESS;
diff --git a/source/val/validation_state.cpp b/source/val/validation_state.cpp
index cb69dda..06abb54 100644
--- a/source/val/validation_state.cpp
+++ b/source/val/validation_state.cpp
@@ -1363,6 +1363,36 @@
       return VUID_WRAP(VUID-HelperInvocation-HelperInvocation-04240);
     case 4241:
       return VUID_WRAP(VUID-HelperInvocation-HelperInvocation-04241);
+    case 4242:
+      return VUID_WRAP(VUID-HitKindKHR-HitKindKHR-04242);
+    case 4243:
+      return VUID_WRAP(VUID-HitKindKHR-HitKindKHR-04243);
+    case 4244:
+      return VUID_WRAP(VUID-HitKindKHR-HitKindKHR-04244);
+    case 4245:
+      return VUID_WRAP(VUID-HitTNV-HitTNV-04245);
+    case 4246:
+      return VUID_WRAP(VUID-HitTNV-HitTNV-04246);
+    case 4247:
+      return VUID_WRAP(VUID-HitTNV-HitTNV-04247);
+    case 4248:
+      return VUID_WRAP(VUID-IncomingRayFlagsKHR-IncomingRayFlagsKHR-04248);
+    case 4249:
+      return VUID_WRAP(VUID-IncomingRayFlagsKHR-IncomingRayFlagsKHR-04249);
+    case 4250:
+      return VUID_WRAP(VUID-IncomingRayFlagsKHR-IncomingRayFlagsKHR-04250);
+    case 4251:
+      return VUID_WRAP(VUID-InstanceCustomIndexKHR-InstanceCustomIndexKHR-04251);
+    case 4252:
+      return VUID_WRAP(VUID-InstanceCustomIndexKHR-InstanceCustomIndexKHR-04252);
+    case 4253:
+      return VUID_WRAP(VUID-InstanceCustomIndexKHR-InstanceCustomIndexKHR-04253);
+    case 4254:
+      return VUID_WRAP(VUID-InstanceId-InstanceId-04254);
+    case 4255:
+      return VUID_WRAP(VUID-InstanceId-InstanceId-04255);
+    case 4256:
+      return VUID_WRAP(VUID-InstanceId-InstanceId-04256);
     case 4257:
       return VUID_WRAP(VUID-InvocationId-InvocationId-04257);
     case 4258:
@@ -1375,6 +1405,18 @@
       return VUID_WRAP(VUID-InstanceIndex-InstanceIndex-04264);
     case 4265:
       return VUID_WRAP(VUID-InstanceIndex-InstanceIndex-04265);
+    case 4266:
+      return VUID_WRAP(VUID-LaunchIdKHR-LaunchIdKHR-04266);
+    case 4267:
+      return VUID_WRAP(VUID-LaunchIdKHR-LaunchIdKHR-04267);
+    case 4268:
+      return VUID_WRAP(VUID-LaunchIdKHR-LaunchIdKHR-04268);
+    case 4269:
+      return VUID_WRAP(VUID-LaunchSizeKHR-LaunchSizeKHR-04269);
+    case 4270:
+      return VUID_WRAP(VUID-LaunchSizeKHR-LaunchSizeKHR-04270);
+    case 4271:
+      return VUID_WRAP(VUID-LaunchSizeKHR-LaunchSizeKHR-04271);
     case 4272:
       return VUID_WRAP(VUID-Layer-Layer-04272);
     case 4274:
@@ -1395,6 +1437,24 @@
       return VUID_WRAP(VUID-NumWorkgroups-NumWorkgroups-04297);
     case 4298:
       return VUID_WRAP(VUID-NumWorkgroups-NumWorkgroups-04298);
+    case 4299:
+      return VUID_WRAP(VUID-ObjectRayDirectionKHR-ObjectRayDirectionKHR-04299);
+    case 4300:
+      return VUID_WRAP(VUID-ObjectRayDirectionKHR-ObjectRayDirectionKHR-04300);
+    case 4301:
+      return VUID_WRAP(VUID-ObjectRayDirectionKHR-ObjectRayDirectionKHR-04301);
+    case 4302:
+      return VUID_WRAP(VUID-ObjectRayOriginKHR-ObjectRayOriginKHR-04302);
+    case 4303:
+      return VUID_WRAP(VUID-ObjectRayOriginKHR-ObjectRayOriginKHR-04303);
+    case 4304:
+      return VUID_WRAP(VUID-ObjectRayOriginKHR-ObjectRayOriginKHR-04304);
+    case 4305:
+      return VUID_WRAP(VUID-ObjectToWorldKHR-ObjectToWorldKHR-04305);
+    case 4306:
+      return VUID_WRAP(VUID-ObjectToWorldKHR-ObjectToWorldKHR-04306);
+    case 4307:
+      return VUID_WRAP(VUID-ObjectToWorldKHR-ObjectToWorldKHR-04307);
     case 4308:
       return VUID_WRAP(VUID-PatchVertices-PatchVertices-04308);
     case 4309:
@@ -1427,6 +1487,24 @@
       return VUID_WRAP(VUID-PrimitiveId-PrimitiveId-04334);
     case 4337:
       return VUID_WRAP(VUID-PrimitiveId-PrimitiveId-04337);
+    case 4345:
+      return VUID_WRAP(VUID-RayGeometryIndexKHR-RayGeometryIndexKHR-04345);
+    case 4346:
+      return VUID_WRAP(VUID-RayGeometryIndexKHR-RayGeometryIndexKHR-04346);
+    case 4347:
+      return VUID_WRAP(VUID-RayGeometryIndexKHR-RayGeometryIndexKHR-04347);
+    case 4348:
+      return VUID_WRAP(VUID-RayTmaxKHR-RayTmaxKHR-04348);
+    case 4349:
+      return VUID_WRAP(VUID-RayTmaxKHR-RayTmaxKHR-04349);
+    case 4350:
+      return VUID_WRAP(VUID-RayTmaxKHR-RayTmaxKHR-04350);
+    case 4351:
+      return VUID_WRAP(VUID-RayTminKHR-RayTminKHR-04351);
+    case 4352:
+      return VUID_WRAP(VUID-RayTminKHR-RayTminKHR-04352);
+    case 4353:
+      return VUID_WRAP(VUID-RayTminKHR-RayTminKHR-04353);
     case 4354:
       return VUID_WRAP(VUID-SampleId-SampleId-04354);
     case 4355:
@@ -1491,6 +1569,24 @@
       return VUID_WRAP(VUID-WorkgroupSize-WorkgroupSize-04426);
     case 4427:
       return VUID_WRAP(VUID-WorkgroupSize-WorkgroupSize-04427);
+    case 4428:
+      return VUID_WRAP(VUID-WorldRayDirectionKHR-WorldRayDirectionKHR-04428);
+    case 4429:
+      return VUID_WRAP(VUID-WorldRayDirectionKHR-WorldRayDirectionKHR-04429);
+    case 4430:
+      return VUID_WRAP(VUID-WorldRayDirectionKHR-WorldRayDirectionKHR-04430);
+    case 4431:
+      return VUID_WRAP(VUID-WorldRayOriginKHR-WorldRayOriginKHR-04431);
+    case 4432:
+      return VUID_WRAP(VUID-WorldRayOriginKHR-WorldRayOriginKHR-04432);
+    case 4433:
+      return VUID_WRAP(VUID-WorldRayOriginKHR-WorldRayOriginKHR-04433);
+    case 4434:
+      return VUID_WRAP(VUID-WorldToObjectKHR-WorldToObjectKHR-04434);
+    case 4435:
+      return VUID_WRAP(VUID-WorldToObjectKHR-WorldToObjectKHR-04435);
+    case 4436:
+      return VUID_WRAP(VUID-WorldToObjectKHR-WorldToObjectKHR-04436);
     case 4484:
       return VUID_WRAP(VUID-PrimitiveShadingRateKHR-PrimitiveShadingRateKHR-04484);
     case 4485:
diff --git a/test/val/val_builtins_test.cpp b/test/val/val_builtins_test.cpp
index 74d5c3a..936279a 100644
--- a/test/val/val_builtins_test.cpp
+++ b/test/val/val_builtins_test.cpp
@@ -654,14 +654,14 @@
                 "which is called with execution model Fragment."))));
 
 INSTANTIATE_TEST_SUITE_P(
-    VertexIdAndInstanceIdVertexInput,
+    VertexIdVertexInput,
     ValidateVulkanCombineBuiltInExecutionModelDataTypeResult,
-    Combine(Values("VertexId", "InstanceId"), Values("Vertex"), Values("Input"),
-            Values("%u32"), Values(nullptr),
-            Values(TestResult(
-                SPV_ERROR_INVALID_DATA,
-                "Vulkan spec doesn't allow BuiltIn VertexId/InstanceId to be "
-                "used."))));
+    Combine(
+        Values("VertexId"), Values("Vertex"), Values("Input"), Values("%u32"),
+        Values(nullptr),
+        Values(TestResult(SPV_ERROR_INVALID_DATA,
+                          "Vulkan spec doesn't allow BuiltIn VertexId to be "
+                          "used."))));
 
 INSTANTIATE_TEST_SUITE_P(
     ClipAndCullDistanceVertexInput,
@@ -1632,7 +1632,8 @@
             Values(TestResult(
                 SPV_ERROR_INVALID_DATA,
                 "to be used only with Fragment, TessellationControl, "
-                "TessellationEvaluation or Geometry execution models"))));
+                "TessellationEvaluation, Geometry, MeshNV, IntersectionKHR, "
+                "AnyHitKHR, and ClosestHitKHR execution models"))));
 
 INSTANTIATE_TEST_SUITE_P(
     PrimitiveIdFragmentNotInput,
@@ -1645,7 +1646,7 @@
                           "which is called with execution model Fragment"))));
 
 INSTANTIATE_TEST_SUITE_P(
-    PrimitiveIdGeometryNotInput,
+    PrimitiveIdTessellationNotInput,
     ValidateVulkanCombineBuiltInExecutionModelDataTypeResult,
     Combine(Values("PrimitiveId"),
             Values("TessellationControl", "TessellationEvaluation"),
@@ -2362,6 +2363,581 @@
                               "needs to be a 32-bit int scalar",
                               "is not an int scalar"))));
 
+// Test HitKind in NV RT shaders
+INSTANTIATE_TEST_SUITE_P(
+    HitKindNVSuccess,
+    ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+    Combine(Values(SPV_ENV_VULKAN_1_2), Values("HitKindNV"),
+            Values("AnyHitNV", "ClosestHitNV"), Values("Input"), Values("%u32"),
+            Values("OpCapability RayTracingNV\n"),
+            Values("OpExtension \"SPV_NV_ray_tracing\"\n"), Values(nullptr),
+            Values(TestResult())));
+
+// HitKind is valid in AH, CH shaders as input i32 scalar
+INSTANTIATE_TEST_SUITE_P(
+    HitKindSuccess,
+    ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+    Combine(Values(SPV_ENV_VULKAN_1_2), Values("HitKindKHR"),
+            Values("AnyHitKHR", "ClosestHitKHR"), Values("Input"),
+            Values("%u32"), Values("OpCapability RayTracingKHR\n"),
+            Values("OpExtension \"SPV_KHR_ray_tracing\"\n"), Values(nullptr),
+            Values(TestResult())));
+
+INSTANTIATE_TEST_SUITE_P(
+    HitKindNotExecutionMode,
+    ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+    Combine(Values(SPV_ENV_VULKAN_1_2), Values("HitKindKHR"),
+            Values("Vertex", "Fragment", "TessellationControl",
+                   "TessellationEvaluation", "Geometry", "Fragment",
+                   "GLCompute", "RayGenerationKHR", "IntersectionKHR",
+                   "MissKHR", "CallableKHR"),
+            Values("Input"), Values("%u32"),
+            Values("OpCapability RayTracingKHR\n"),
+            Values("OpExtension \"SPV_KHR_ray_tracing\"\n"),
+            Values("VUID-HitKindKHR-HitKindKHR-04242"),
+            Values(TestResult(SPV_ERROR_INVALID_DATA,
+                              "Vulkan spec does not allow BuiltIn",
+                              "to be used with the execution model"))));
+
+INSTANTIATE_TEST_SUITE_P(
+    HitKindNotInput,
+    ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+    Combine(Values(SPV_ENV_VULKAN_1_2), Values("HitKindKHR"),
+            Values("AnyHitKHR", "ClosestHitKHR"), Values("Output"),
+            Values("%u32"), Values("OpCapability RayTracingKHR\n"),
+            Values("OpExtension \"SPV_KHR_ray_tracing\"\n"),
+            Values("VUID-HitKindKHR-HitKindKHR-04243"),
+            Values(TestResult(SPV_ERROR_INVALID_DATA, "Vulkan spec allows",
+                              "used for variables with Input storage class"))));
+
+INSTANTIATE_TEST_SUITE_P(
+    HitKindNotIntScalar,
+    ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+    Combine(Values(SPV_ENV_VULKAN_1_2), Values("HitKindKHR"),
+            Values("AnyHitKHR", "ClosestHitKHR"), Values("Input"),
+            Values("%f32", "%u32vec3"), Values("OpCapability RayTracingKHR\n"),
+            Values("OpExtension \"SPV_KHR_ray_tracing\"\n"),
+            Values("VUID-HitKindKHR-HitKindKHR-04244"),
+            Values(TestResult(SPV_ERROR_INVALID_DATA,
+                              "needs to be a 32-bit int scalar",
+                              "is not an int scalar"))));
+
+// Ensure HitT is not supported in KHR RT shaders
+INSTANTIATE_TEST_SUITE_P(
+    HitTNVNotSupportedInKHR,
+    ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+    Combine(Values(SPV_ENV_VULKAN_1_2), Values("HitTNV"),
+            Values("AnyHitKHR", "ClosestHitKHR"), Values("Input"),
+            Values("%u32"), Values("OpCapability RayTracingKHR\n"),
+            Values("OpExtension \"SPV_KHR_ray_tracing\"\n"), Values(nullptr),
+            Values(TestResult(
+                SPV_ERROR_INVALID_CAPABILITY,
+                "of MemberDecorate requires one of these capabilities"))));
+
+// HitT is valid in AH, CH shaders as input f32 scalar (NV RT only)
+INSTANTIATE_TEST_SUITE_P(
+    HitTNVSuccess,
+    ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+    Combine(Values(SPV_ENV_VULKAN_1_2), Values("HitTNV"),
+            Values("AnyHitNV", "ClosestHitNV"), Values("Input"), Values("%f32"),
+            Values("OpCapability RayTracingNV\n"),
+            Values("OpExtension \"SPV_NV_ray_tracing\"\n"), Values(nullptr),
+            Values(TestResult())));
+
+INSTANTIATE_TEST_SUITE_P(
+    HitTNVNotExecutionMode,
+    ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+    Combine(Values(SPV_ENV_VULKAN_1_2), Values("HitTNV"),
+            Values("Vertex", "Fragment", "TessellationControl",
+                   "TessellationEvaluation", "Geometry", "Fragment",
+                   "GLCompute", "RayGenerationNV", "IntersectionNV", "MissNV",
+                   "CallableNV"),
+            Values("Input"), Values("%f32"),
+            Values("OpCapability RayTracingNV\n"),
+            Values("OpExtension \"SPV_NV_ray_tracing\"\n"),
+            Values("VUID-HitTNV-HitTNV-04245"),
+            Values(TestResult(SPV_ERROR_INVALID_DATA,
+                              "Vulkan spec does not allow BuiltIn",
+                              "to be used with the execution model"))));
+
+INSTANTIATE_TEST_SUITE_P(
+    HitTNVNotInput,
+    ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+    Combine(Values(SPV_ENV_VULKAN_1_2), Values("HitTNV"),
+            Values("AnyHitNV", "ClosestHitNV"), Values("Output"),
+            Values("%f32"), Values("OpCapability RayTracingNV\n"),
+            Values("OpExtension \"SPV_NV_ray_tracing\"\n"),
+            Values("VUID-HitTNV-HitTNV-04246"),
+            Values(TestResult(SPV_ERROR_INVALID_DATA, "Vulkan spec allows",
+                              "used for variables with Input storage class"))));
+INSTANTIATE_TEST_SUITE_P(
+    HitTNVNotIntScalar,
+    ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+    Combine(Values(SPV_ENV_VULKAN_1_2), Values("HitTNV"),
+            Values("AnyHitNV", "ClosestHitNV"), Values("Input"),
+            Values("%u32", "%f32vec3"), Values("OpCapability RayTracingNV\n"),
+            Values("OpExtension \"SPV_NV_ray_tracing\"\n"),
+            Values("VUID-HitTNV-HitTNV-04247"),
+            Values(TestResult(SPV_ERROR_INVALID_DATA,
+                              "needs to be a 32-bit float scalar",
+                              "is not a float scalar"))));
+
+// InstanceCustomIndexKHR, InstanceId, PrimitiveId, RayGeometryIndexKHR are
+// valid in IS, AH, CH shaders as input i32 scalars
+INSTANTIATE_TEST_SUITE_P(
+    RTBuiltIn3StageI32Success,
+    ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+    Combine(Values(SPV_ENV_VULKAN_1_2),
+            Values("InstanceCustomIndexKHR", "RayGeometryIndexKHR",
+                   "InstanceId", "PrimitiveId"),
+            Values("AnyHitKHR", "ClosestHitKHR", "IntersectionKHR"),
+            Values("Input"), Values("%u32"),
+            Values("OpCapability RayTracingKHR\n"),
+            Values("OpExtension \"SPV_KHR_ray_tracing\"\n"), Values(nullptr),
+            Values(TestResult())));
+
+INSTANTIATE_TEST_SUITE_P(
+    RTBuiltIn3StageI32NotExecutionMode,
+    ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+    Combine(Values(SPV_ENV_VULKAN_1_2),
+            Values("InstanceCustomIndexKHR", "RayGeometryIndexKHR",
+                   "InstanceId"),
+            Values("Vertex", "Fragment", "TessellationControl",
+                   "TessellationEvaluation", "Geometry", "Fragment",
+                   "GLCompute", "RayGenerationKHR", "MissKHR", "CallableKHR"),
+            Values("Input"), Values("%u32"),
+            Values("OpCapability RayTracingKHR\n"),
+            Values("OpExtension \"SPV_KHR_ray_tracing\"\n"),
+            Values("VUID-InstanceCustomIndexKHR-InstanceCustomIndexKHR-04251 "
+                   "VUID-RayGeometryIndexKHR-RayGeometryIndexKHR-04345 "
+                   "VUID-InstanceId-InstanceId-04254 "),
+            Values(TestResult(SPV_ERROR_INVALID_DATA,
+                              "Vulkan spec does not allow BuiltIn",
+                              "to be used with the execution model"))));
+
+INSTANTIATE_TEST_SUITE_P(
+    RTBuiltIn3StageI32NotInput,
+    ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+    Combine(Values(SPV_ENV_VULKAN_1_2),
+            Values("InstanceCustomIndexKHR", "RayGeometryIndexKHR",
+                   "InstanceId"),
+            Values("AnyHitKHR", "ClosestHitKHR", "IntersectionKHR"),
+            Values("Output"), Values("%u32"),
+            Values("OpCapability RayTracingKHR\n"),
+            Values("OpExtension \"SPV_KHR_ray_tracing\"\n"),
+            Values("VUID-InstanceCustomIndexKHR-InstanceCustomIndexKHR-04252 "
+                   "VUID-RayGeometryIndexKHR-RayGeometryIndexKHR-04346 "
+                   "VUID-InstanceId-InstanceId-04255 "),
+            Values(TestResult(SPV_ERROR_INVALID_DATA, "Vulkan spec allows",
+                              "used for variables with Input storage class"))));
+
+INSTANTIATE_TEST_SUITE_P(
+    RTBuiltIn3StageI32NotIntScalar,
+    ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+    Combine(Values(SPV_ENV_VULKAN_1_2),
+            Values("InstanceCustomIndexKHR", "RayGeometryIndexKHR",
+                   "InstanceId"),
+            Values("AnyHitKHR", "ClosestHitKHR", "IntersectionKHR"),
+            Values("Input"), Values("%f32", "%u32vec3"),
+            Values("OpCapability RayTracingKHR\n"),
+            Values("OpExtension \"SPV_KHR_ray_tracing\"\n"),
+            Values("VUID-InstanceCustomIndexKHR-InstanceCustomIndexKHR-04253 "
+                   "VUID-RayGeometryIndexKHR-RayGeometryIndexKHR-04347 "
+                   "VUID-InstanceId-InstanceId-04256 "),
+            Values(TestResult(SPV_ERROR_INVALID_DATA,
+                              "needs to be a 32-bit int scalar",
+                              "is not an int scalar"))));
+
+// PrimitiveId needs special negative testing because it has non-RT uses
+INSTANTIATE_TEST_SUITE_P(
+    PrimitiveIdRTNotExecutionMode,
+    ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+    Combine(Values(SPV_ENV_VULKAN_1_2), Values("PrimitiveId"),
+            Values("RayGenerationKHR", "MissKHR", "CallableKHR"),
+            Values("Input"), Values("%u32"),
+            Values("OpCapability RayTracingKHR\n"),
+            Values("OpExtension \"SPV_KHR_ray_tracing\"\n"),
+            Values("VUID-PrimitiveId-PrimitiveId-04330"),
+            Values(TestResult(
+                SPV_ERROR_INVALID_DATA,
+                "to be used only with Fragment, TessellationControl, "
+                "TessellationEvaluation, Geometry, MeshNV, IntersectionKHR, "
+                "AnyHitKHR, and ClosestHitKHR execution models"))));
+
+INSTANTIATE_TEST_SUITE_P(
+    PrimitiveIdRTNotInput,
+    ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+    Combine(Values(SPV_ENV_VULKAN_1_2), Values("PrimitiveId"),
+            Values("AnyHitKHR", "ClosestHitKHR", "IntersectionKHR"),
+            Values("Output"), Values("%u32"),
+            Values("OpCapability RayTracingKHR\n"),
+            Values("OpExtension \"SPV_KHR_ray_tracing\"\n"),
+            Values("VUID-PrimitiveId-PrimitiveId-04334"),
+            Values(TestResult(SPV_ERROR_INVALID_DATA,
+                              "Output storage class if execution model is "))));
+
+INSTANTIATE_TEST_SUITE_P(
+    PrimitiveIdRTNotIntScalar,
+    ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+    Combine(Values(SPV_ENV_VULKAN_1_2), Values("PrimitiveId"),
+            Values("AnyHitKHR", "ClosestHitKHR", "IntersectionKHR"),
+            Values("Input"), Values("%f32", "%u32vec3"),
+            Values("OpCapability RayTracingKHR\n"),
+            Values("OpExtension \"SPV_KHR_ray_tracing\"\n"),
+            Values("VUID-PrimitiveId-PrimitiveId-04337"),
+            Values(TestResult(SPV_ERROR_INVALID_DATA,
+                              "needs to be a 32-bit int scalar",
+                              "is not an int scalar"))));
+
+// ObjectRayDirectionKHR and ObjectRayOriginKHR valid
+// in IS, AH, CH shaders as input 32-bit float vec3
+INSTANTIATE_TEST_SUITE_P(
+    ObjectRayDirectionAndOriginSuccess,
+    ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+    Combine(Values(SPV_ENV_VULKAN_1_2),
+            Values("ObjectRayDirectionKHR", "ObjectRayOriginKHR"),
+            Values("AnyHitKHR", "ClosestHitKHR", "IntersectionKHR"),
+            Values("Input"), Values("%f32vec3"),
+            Values("OpCapability RayTracingKHR\n"),
+            Values("OpExtension \"SPV_KHR_ray_tracing\"\n"), Values(nullptr),
+            Values(TestResult())));
+
+INSTANTIATE_TEST_SUITE_P(
+    ObjectRayDirectionAndOriginNotExecutionMode,
+    ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+    Combine(Values(SPV_ENV_VULKAN_1_2),
+            Values("ObjectRayDirectionKHR", "ObjectRayOriginKHR"),
+            Values("Vertex", "Fragment", "TessellationControl",
+                   "TessellationEvaluation", "Geometry", "Fragment",
+                   "GLCompute", "RayGenerationKHR", "MissKHR", "CallableKHR"),
+            Values("Input"), Values("%f32vec3"),
+            Values("OpCapability RayTracingKHR\n"),
+            Values("OpExtension \"SPV_KHR_ray_tracing\"\n"),
+            Values("VUID-ObjectRayDirectionKHR-ObjectRayDirectionKHR-04299 "
+                   "VUID-ObjectRayOriginKHR-ObjectRayOriginKHR-04302 "),
+            Values(TestResult(SPV_ERROR_INVALID_DATA,
+                              "Vulkan spec does not allow BuiltIn",
+                              "to be used with the execution model"))));
+
+INSTANTIATE_TEST_SUITE_P(
+    ObjectRayDirectionAndOriginNotInput,
+    ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+    Combine(Values(SPV_ENV_VULKAN_1_2),
+            Values("ObjectRayDirectionKHR", "ObjectRayOriginKHR"),
+            Values("AnyHitKHR", "ClosestHitKHR", "IntersectionKHR"),
+            Values("Output"), Values("%f32vec3"),
+            Values("OpCapability RayTracingKHR\n"),
+            Values("OpExtension \"SPV_KHR_ray_tracing\"\n"),
+            Values("VUID-ObjectRayDirectionKHR-ObjectRayDirectionKHR-04300 "
+                   "VUID-ObjectRayOriginKHR-ObjectRayOriginKHR-04303 "),
+            Values(TestResult(SPV_ERROR_INVALID_DATA, "Vulkan spec allows",
+                              "used for variables with Input storage class"))));
+
+INSTANTIATE_TEST_SUITE_P(
+    ObjectRayDirectionAndOriginNotFloatVec3,
+    ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+    Combine(
+        Values(SPV_ENV_VULKAN_1_2),
+        Values("ObjectRayDirectionKHR", "ObjectRayOriginKHR"),
+        Values("AnyHitKHR", "ClosestHitKHR", "IntersectionKHR"),
+        Values("Input"), Values("%u32vec3", "%f32", "%f32vec2", "%f32vec4"),
+        Values("OpCapability RayTracingKHR\n"),
+        Values("OpExtension \"SPV_KHR_ray_tracing\"\n"),
+        Values("VUID-ObjectRayDirectionKHR-ObjectRayDirectionKHR-04301 "
+               "VUID-ObjectRayOriginKHR-ObjectRayOriginKHR-04304 "),
+        Values(TestResult(SPV_ERROR_INVALID_DATA,
+                          "needs to be a 3-component 32-bit float vector"))));
+
+// ObjectToWorldKHR and WorldToObjectKHR valid
+// in IS, AH, CH shaders as input mat4x3
+INSTANTIATE_TEST_SUITE_P(
+    RTObjectMatrixSuccess,
+    ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+    Combine(Values(SPV_ENV_VULKAN_1_2),
+            Values("ObjectToWorldKHR", "WorldToObjectKHR"),
+            Values("AnyHitKHR", "ClosestHitKHR", "IntersectionKHR"),
+            Values("Input"), Values("%f32mat34"),
+            Values("OpCapability RayTracingKHR\n"),
+            Values("OpExtension \"SPV_KHR_ray_tracing\"\n"), Values(nullptr),
+            Values(TestResult())));
+
+INSTANTIATE_TEST_SUITE_P(
+    RTObjectMatrixNotExecutionMode,
+    ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+    Combine(Values(SPV_ENV_VULKAN_1_2),
+            Values("ObjectToWorldKHR", "WorldToObjectKHR"),
+            Values("Vertex", "Fragment", "TessellationControl",
+                   "TessellationEvaluation", "Geometry", "Fragment",
+                   "GLCompute", "RayGenerationKHR", "MissKHR", "CallableKHR"),
+            Values("Input"), Values("%f32mat34"),
+            Values("OpCapability RayTracingKHR\n"),
+            Values("OpExtension \"SPV_KHR_ray_tracing\"\n"),
+            Values("VUID-ObjectToWorldKHR-ObjectToWorldKHR-04305 "
+                   "VUID-WorldToObjectKHR-WorldToObjectKHR-04434 "),
+            Values(TestResult(SPV_ERROR_INVALID_DATA,
+                              "Vulkan spec does not allow BuiltIn",
+                              "to be used with the execution model"))));
+
+INSTANTIATE_TEST_SUITE_P(
+    RTObjectMatrixNotInput,
+    ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+    Combine(Values(SPV_ENV_VULKAN_1_2),
+            Values("ObjectToWorldKHR", "WorldToObjectKHR"),
+            Values("AnyHitKHR", "ClosestHitKHR", "IntersectionKHR"),
+            Values("Output"), Values("%f32mat34"),
+            Values("OpCapability RayTracingKHR\n"),
+            Values("OpExtension \"SPV_KHR_ray_tracing\"\n"),
+            Values("VUID-ObjectToWorldKHR-ObjectToWorldKHR-04306 "
+                   "VUID-WorldToObjectKHR-WorldToObjectKHR-04435 "),
+            Values(TestResult(SPV_ERROR_INVALID_DATA, "Vulkan spec allows",
+                              "used for variables with Input storage class"))));
+
+INSTANTIATE_TEST_SUITE_P(
+    RTObjectMatrixNotMat4x3,
+    ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+    Combine(Values(SPV_ENV_VULKAN_1_2),
+            Values("ObjectToWorldKHR", "WorldToObjectKHR"),
+            Values("AnyHitKHR", "ClosestHitKHR", "IntersectionKHR"),
+            Values("Input"), Values("%f32mat43", "%f32mat44", "%f32vec4"),
+            Values("OpCapability RayTracingKHR\n"),
+            Values("OpExtension \"SPV_KHR_ray_tracing\"\n"),
+            Values("VUID-ObjectToWorldKHR-ObjectToWorldKHR-04307 "
+                   "VUID-WorldToObjectKHR-WorldToObjectKHR-04436 "),
+            Values(TestResult(
+                SPV_ERROR_INVALID_DATA,
+                "variable needs to be a matrix with "
+                "4 columns of 3-component vectors of 32-bit floats"))));
+
+// IncomingRayFlagsKHR is valid
+// in IS, AH, CH, MS shaders as an input i32 scalar
+INSTANTIATE_TEST_SUITE_P(
+    IncomingRayFlagsSuccess,
+    ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+    Combine(Values(SPV_ENV_VULKAN_1_2), Values("IncomingRayFlagsKHR"),
+            Values("AnyHitKHR", "ClosestHitKHR", "IntersectionKHR", "MissKHR"),
+            Values("Input"), Values("%u32"),
+            Values("OpCapability RayTracingKHR\n"),
+            Values("OpExtension \"SPV_KHR_ray_tracing\"\n"), Values(nullptr),
+            Values(TestResult())));
+
+INSTANTIATE_TEST_SUITE_P(
+    IncomingRayFlagsNotExecutionMode,
+    ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+    Combine(Values(SPV_ENV_VULKAN_1_2), Values("IncomingRayFlagsKHR"),
+            Values("Vertex", "Fragment", "TessellationControl",
+                   "TessellationEvaluation", "Geometry", "Fragment",
+                   "GLCompute", "RayGenerationKHR", "CallableKHR"),
+            Values("Input"), Values("%u32"),
+            Values("OpCapability RayTracingKHR\n"),
+            Values("OpExtension \"SPV_KHR_ray_tracing\"\n"),
+            Values("VUID-IncomingRayFlagsKHR-IncomingRayFlagsKHR-04248 "
+                   "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(
+    IncomingRayFlagsNotInput,
+    ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+    Combine(Values(SPV_ENV_VULKAN_1_2), Values("IncomingRayFlagsKHR"),
+            Values("AnyHitKHR", "ClosestHitKHR", "IntersectionKHR", "MissKHR"),
+            Values("Output"), Values("%u32"),
+            Values("OpCapability RayTracingKHR\n"),
+            Values("OpExtension \"SPV_KHR_ray_tracing\"\n"),
+            Values("VUID-IncomingRayFlagsKHR-IncomingRayFlagsKHR-04249 "
+                   "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(
+    IncomingRayFlagsNotIntScalar,
+    ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+    Combine(Values(SPV_ENV_VULKAN_1_2), Values("IncomingRayFlagsKHR"),
+            Values("AnyHitKHR", "ClosestHitKHR", "IntersectionKHR", "MissKHR"),
+            Values("Input"), Values("%f32", "%u32vec3"),
+            Values("OpCapability RayTracingKHR\n"),
+            Values("OpExtension \"SPV_KHR_ray_tracing\"\n"),
+            Values("VUID-IncomingRayFlagsKHR-IncomingRayFlagsKHR-04250 "
+                   "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(
+    RayTSuccess,
+    ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+    Combine(Values(SPV_ENV_VULKAN_1_2), Values("RayTmaxKHR", "RayTminKHR"),
+            Values("AnyHitKHR", "ClosestHitKHR", "IntersectionKHR", "MissKHR"),
+            Values("Input"), Values("%f32"),
+            Values("OpCapability RayTracingKHR\n"),
+            Values("OpExtension \"SPV_KHR_ray_tracing\"\n"), Values(nullptr),
+            Values(TestResult())));
+
+INSTANTIATE_TEST_SUITE_P(
+    RayTNotExecutionMode,
+    ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+    Combine(Values(SPV_ENV_VULKAN_1_2), Values("RayTmaxKHR", "RayTminKHR"),
+            Values("Vertex", "Fragment", "TessellationControl",
+                   "TessellationEvaluation", "Geometry", "Fragment",
+                   "GLCompute", "RayGenerationKHR", "CallableKHR"),
+            Values("Input"), Values("%f32"),
+            Values("OpCapability RayTracingKHR\n"),
+            Values("OpExtension \"SPV_KHR_ray_tracing\"\n"),
+            Values("VUID-IncomingRayFlagsKHR-IncomingRayFlagsKHR-04248 "
+                   "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(
+    RayTNotInput,
+    ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+    Combine(Values(SPV_ENV_VULKAN_1_2), Values("RayTmaxKHR", "RayTminKHR"),
+            Values("AnyHitKHR", "ClosestHitKHR", "IntersectionKHR", "MissKHR"),
+            Values("Output"), Values("%f32"),
+            Values("OpCapability RayTracingKHR\n"),
+            Values("OpExtension \"SPV_KHR_ray_tracing\"\n"),
+            Values("VUID-IncomingRayFlagsKHR-IncomingRayFlagsKHR-04249 "
+                   "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(
+    RayTNotFloatScalar,
+    ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+    Combine(Values(SPV_ENV_VULKAN_1_2), Values("RayTmaxKHR", "RayTminKHR"),
+            Values("AnyHitKHR", "ClosestHitKHR", "IntersectionKHR", "MissKHR"),
+            Values("Input"), Values("%u32", "%f32vec3"),
+            Values("OpCapability RayTracingKHR\n"),
+            Values("OpExtension \"SPV_KHR_ray_tracing\"\n"),
+            Values("VUID-IncomingRayFlagsKHR-IncomingRayFlagsKHR-04250 "
+                   "VUID-RayTmaxKHR-RayTmaxKHR-04350 "
+                   "VUID-RayTminKHR-RayTminKHR-04353 "),
+            Values(TestResult(SPV_ERROR_INVALID_DATA,
+                              "needs to be a 32-bit float scalar",
+                              "is not a float scalar"))));
+
+// WorldRayDirectionKHR and WorldRayOriginKHR are valid
+// in IS, AH, CH, MS shaders as input 32-bit float vec3
+INSTANTIATE_TEST_SUITE_P(
+    WorldRayDirectionAndOriginSuccess,
+    ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+    Combine(Values(SPV_ENV_VULKAN_1_2),
+            Values("WorldRayDirectionKHR", "WorldRayOriginKHR"),
+            Values("AnyHitKHR", "ClosestHitKHR", "IntersectionKHR", "MissKHR"),
+            Values("Input"), Values("%f32vec3"),
+            Values("OpCapability RayTracingKHR\n"),
+            Values("OpExtension \"SPV_KHR_ray_tracing\"\n"), Values(nullptr),
+            Values(TestResult())));
+
+INSTANTIATE_TEST_SUITE_P(
+    WorldRayDirectionAndOriginNotExecutionMode,
+    ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+    Combine(Values(SPV_ENV_VULKAN_1_2),
+            Values("WorldRayDirectionKHR", "WorldRayOriginKHR"),
+            Values("Vertex", "Fragment", "TessellationControl",
+                   "TessellationEvaluation", "Geometry", "Fragment",
+                   "GLCompute", "RayGenerationKHR", "CallableKHR"),
+            Values("Input"), Values("%f32vec3"),
+            Values("OpCapability RayTracingKHR\n"),
+            Values("OpExtension \"SPV_KHR_ray_tracing\"\n"),
+            Values("VUID-WorldRayDirectionKHR-WorldRayDirectionKHR-04428 "
+                   "VUID-WorldRayOriginKHR-WorldRayOriginKHR-04431 "),
+            Values(TestResult(SPV_ERROR_INVALID_DATA,
+                              "Vulkan spec does not allow BuiltIn",
+                              "to be used with the execution model"))));
+
+INSTANTIATE_TEST_SUITE_P(
+    WorldRayDirectionAndOriginNotInput,
+    ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+    Combine(Values(SPV_ENV_VULKAN_1_2),
+            Values("WorldRayDirectionKHR", "WorldRayOriginKHR"),
+            Values("AnyHitKHR", "ClosestHitKHR", "IntersectionKHR", "MissKHR"),
+            Values("Output"), Values("%f32vec3"),
+            Values("OpCapability RayTracingKHR\n"),
+            Values("OpExtension \"SPV_KHR_ray_tracing\"\n"),
+            Values("VUID-WorldRayDirectionKHR-WorldRayDirectionKHR-04429 "
+                   "VUID-WorldRayOriginKHR-WorldRayOriginKHR-04432 "),
+            Values(TestResult(SPV_ERROR_INVALID_DATA, "Vulkan spec allows",
+                              "used for variables with Input storage class"))));
+
+INSTANTIATE_TEST_SUITE_P(
+    WorldRayDirectionAndOriginNotFloatVec3,
+    ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+    Combine(
+        Values(SPV_ENV_VULKAN_1_2),
+        Values("WorldRayDirectionKHR", "WorldRayOriginKHR"),
+        Values("AnyHitKHR", "ClosestHitKHR", "IntersectionKHR", "MissKHR"),
+        Values("Input"), Values("%u32vec3", "%f32", "%f32vec2", "%f32vec4"),
+        Values("OpCapability RayTracingKHR\n"),
+        Values("OpExtension \"SPV_KHR_ray_tracing\"\n"),
+        Values("VUID-WorldRayDirectionKHR-WorldRayDirectionKHR-04430 "
+               "VUID-WorldRayOriginKHR-WorldRayOriginKHR-04433 "),
+        Values(TestResult(SPV_ERROR_INVALID_DATA,
+                          "needs to be a 3-component 32-bit float vector"))));
+
+// LaunchIdKHR and LaunchSizeKHR are valid
+// in RG, IS, AH, CH, MS shaders as input 32-bit ivec3
+INSTANTIATE_TEST_SUITE_P(
+    LaunchRTSuccess,
+    ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+    Combine(Values(SPV_ENV_VULKAN_1_2), Values("LaunchIdKHR", "LaunchSizeKHR"),
+            Values("RayGenerationKHR", "AnyHitKHR", "ClosestHitKHR",
+                   "IntersectionKHR", "MissKHR", "CallableKHR"),
+            Values("Input"), Values("%u32vec3"),
+            Values("OpCapability RayTracingKHR\n"),
+            Values("OpExtension \"SPV_KHR_ray_tracing\"\n"), Values(nullptr),
+            Values(TestResult())));
+
+INSTANTIATE_TEST_SUITE_P(
+    LaunchRTNotExecutionMode,
+    ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+    Combine(Values(SPV_ENV_VULKAN_1_2), Values("LaunchIdKHR", "LaunchSizeKHR"),
+            Values("Vertex", "Fragment", "TessellationControl",
+                   "TessellationEvaluation", "Geometry", "Fragment",
+                   "GLCompute"),
+            Values("Input"), Values("%u32vec3"),
+            Values("OpCapability RayTracingKHR\n"),
+            Values("OpExtension \"SPV_KHR_ray_tracing\"\n"),
+            Values("VUID-LaunchIdKHR-LaunchIdKHR-04266 "
+                   "VUID-LaunchSizeKHR-LaunchSizeKHR-04269 "),
+            Values(TestResult(SPV_ERROR_INVALID_DATA,
+                              "Vulkan spec does not allow BuiltIn",
+                              "to be used with the execution model"))));
+
+INSTANTIATE_TEST_SUITE_P(
+    LaunchRTNotInput,
+    ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+    Combine(Values(SPV_ENV_VULKAN_1_2), Values("LaunchIdKHR", "LaunchSizeKHR"),
+            Values("RayGenerationKHR", "AnyHitKHR", "ClosestHitKHR",
+                   "IntersectionKHR", "MissKHR", "CallableKHR"),
+            Values("Output"), Values("%u32vec3"),
+            Values("OpCapability RayTracingKHR\n"),
+            Values("OpExtension \"SPV_KHR_ray_tracing\"\n"),
+            Values("VUID-LaunchIdKHR-LaunchIdKHR-04267 "
+                   "VUID-LaunchSizeKHR-LaunchSizeKHR-04270 "),
+            Values(TestResult(SPV_ERROR_INVALID_DATA, "Vulkan spec allows",
+                              "used for variables with Input storage class"))));
+
+INSTANTIATE_TEST_SUITE_P(
+    LaunchRTNotIntVec3,
+    ValidateGenericCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult,
+    Combine(Values(SPV_ENV_VULKAN_1_2), Values("LaunchIdKHR", "LaunchSizeKHR"),
+            Values("RayGenerationKHR", "AnyHitKHR", "ClosestHitKHR",
+                   "IntersectionKHR", "MissKHR", "CallableKHR"),
+            Values("Input"), Values("%f32vec3", "%u32", "%u32vec2", "%u32vec4"),
+            Values("OpCapability RayTracingKHR\n"),
+            Values("OpExtension \"SPV_KHR_ray_tracing\"\n"),
+            Values("VUID-LaunchIdKHR-LaunchIdKHR-04268 "
+                   "VUID-LaunchSizeKHR-LaunchSizeKHR-04271 "),
+            Values(TestResult(SPV_ERROR_INVALID_DATA,
+                              "needs to be a 3-component 32-bit int vector"))));
+
 CodeGenerator GetArrayedVariableCodeGenerator(spv_target_env env,
                                               const char* const built_in,
                                               const char* const execution_model,
@@ -3358,44 +3934,6 @@
   EXPECT_THAT(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
 }
 
-TEST_F(ValidateBuiltIns, DisallowInstanceIdWithRayGenShader) {
-  CodeGenerator generator = CodeGenerator::GetDefaultShaderCodeGenerator();
-  generator.capabilities_ += R"(
-OpCapability RayTracingNV
-)";
-
-  generator.extensions_ = R"(
-OpExtension "SPV_NV_ray_tracing"
-)";
-
-  generator.before_types_ = R"(
-OpMemberDecorate %input_type 0 BuiltIn InstanceId
-)";
-
-  generator.after_types_ = R"(
-%input_type = OpTypeStruct %u32
-%input_ptr = OpTypePointer Input %input_type
-%input_ptr_u32 = OpTypePointer Input %u32
-%input = OpVariable %input_ptr Input
-)";
-
-  EntryPoint entry_point;
-  entry_point.name = "main_d_r";
-  entry_point.execution_model = "RayGenerationNV";
-  entry_point.interfaces = "%input";
-  entry_point.body = R"(
-%input_member = OpAccessChain %input_ptr_u32 %input %u32_0
-)";
-  generator.entry_points_.push_back(std::move(entry_point));
-
-  CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_0);
-  ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
-  EXPECT_THAT(getDiagnosticString(),
-              HasSubstr("Vulkan spec allows BuiltIn InstanceId to be used "
-                        "only with IntersectionNV, ClosestHitNV and "
-                        "AnyHitNV execution models"));
-}
-
 TEST_F(ValidateBuiltIns, ValidBuiltinsForMeshShader) {
   CodeGenerator generator = CodeGenerator::GetDefaultShaderCodeGenerator();
   generator.capabilities_ += R"(
diff --git a/test/val/val_code_generator.cpp b/test/val/val_code_generator.cpp
index 62aae9c..96971f9 100644
--- a/test/val/val_code_generator.cpp
+++ b/test/val/val_code_generator.cpp
@@ -115,6 +115,15 @@
 %f32vec3arr3 = OpTypeArray %f32vec3 %u32_3
 %f32vec4arr3 = OpTypeArray %f32vec4 %u32_3
 %f64vec4arr3 = OpTypeArray %f64vec4 %u32_3
+
+%f32mat22 = OpTypeMatrix %f32vec2 2
+%f32mat23 = OpTypeMatrix %f32vec2 3
+%f32mat32 = OpTypeMatrix %f32vec3 2
+%f32mat33 = OpTypeMatrix %f32vec3 3
+%f64mat22 = OpTypeMatrix %f64vec2 2
+%f32mat34 = OpTypeMatrix %f32vec3 4
+%f32mat43 = OpTypeMatrix %f32vec4 3
+%f32mat44 = OpTypeMatrix %f32vec4 4
 )";
 }