فهرست منبع

Updated spirv-tools.

Бранимир Караџић 5 سال پیش
والد
کامیت
37e50587ae

+ 90 - 2
3rdparty/spirv-tools/CHANGES

@@ -1,7 +1,95 @@
 Revision history for SPIRV-Tools
 
-v2020.6 2020-09-24
- - Start SPIRV-Tools v2020.6
+v2020.7-dev 2020-12-03
+ - Start v2020.7-dev
+
+v2020.6 2020-12-02
+ - General
+    CMake: Add SPIRV_TOOLS_BUILD_STATIC flag (#3910)
+ - Disassembler
+    Add some context comments to disassembly. (#3847)
+ - Optimizer
+   - Do run DCE if SPV_KHR_ray_query is used. (#4047)
+   - Handle 8-bit index in elim dead member (#4043)
+   - Add texel buffer out-of-bounds checking instrumentation (#4038)
+   - Update MeshShadingNV dependencies (and land Ray tracing updates) (#4028)
+   - Fix buffer oob instrumentation for matrix refs (#4025)
+   - Fix SSA re-writing in the presence of variable pointers. (#4010)
+   - Add support to prevent functions from being inlined if they have
+     DontInline flag (#3858)
+   - Add SPV_EXT_shader_image_int64 (#3852)
+   - Support SPV_KHR_fragment_shading_rate (#3943)
+   - Fix use-after-move in val/validate.cpp (#3848)
+ - Debug Info
+   - properly preserve DebugValue indexes operand (#4022)
+   - Add DebugValue for invisible store in single_store_elim (#4002)
+   - Propagate OpLine to all applied instructions in spirv-opt (#3951)
+   - Add DebugValue for DebugDecl invisible to value assignment (#3973)
+   - Add DebugValue for function param regardless of scope (#3923)
+   - Debug info preservation in convert-local-access-chains pass (#3835)
+   - Debug info preservation in redundancy-elimination pass (#3839)
+   - Debug info preservation in if-conversion pass (#3861)
+ - Validator
+   - Add validation support for the ray tracing built-in variables (#4041)
+   - Use less stack space when validating Vulkan builtins (#4019)
+   - Fix SPV_KHR_fragment_shading_rate VUID label (#4014)
+   - Label Layer and ViewportIndex VUIDs (#4013)
+   - Allow the ViewportIndex and Layer built-ins on SPIR-V 1.5 (#3986)
+   - Fix validation of OpPhi instructions (#3919)
+ - Fuzz
+   - Fix facts arising from CompositeConstruct (#4034)
+   - Do not flatten conditionals that create synonyms (#4030)
+   - Add support for reining in rogue fuzzer passes (#3987)
+   - Fix assertion failure in FuzzerPassAddCompositeExtract (#3995)
+   - Fix invalid equation facts (#4009)
+   - Fix bugs in TransformationFlattenConditionalBranch (#4006)
+   - Fix bug related to transformation applicability (#3990)
+   - Add expand vector reduction transformation (#3869)
+   - Add FuzzerPassAddCompositeExtract (#3904)
+   - Fix mismatch with shrinker step limit (#3985)
+   - Fix off-by-one error in replayer (#3982)
+   - Get order right for OpSelect arguments (#3974)
+   - Do not add synonym-creating loops in dead blocks (#3975)
+   - Skip OpTypeSampledImage when propagating up (#3976)
+   - Pass OpUndef in function call if needed (#3978)
+   - Fix off-by-one in TransformationCompositeConstruct (#3979)
+   - Tolerate absent ids in data synonym fact management (#3966)
+   - Fix to id availability (#3971)
+   - Fix operand types (#3962)
+   - Don't flatten conditional if condition is irrelevant (#3944)
+   - Do not produce OpPhis of type OpTypeSampledImage (#3964)
+   - Restrict fuzzer pass to reachable blocks (#3970)
+   - Handle more types when extending OpPhi instructions (#3969)
+   - Skip early terminator wrappers when merging returns (#3968)
+   - Avoid irrelevant constants in synonym-creating loops (#3967)
+   - Skip dead blocks in FuzzerPassAddOpPhiSynonyms (#3965)
+   - Avoid the type manager when looking for struct types (#3963)
+   - Fix to TransformationDuplicateRegionWithSelection (#3941)
+   - Skip OpFunction when replacing irrelevant ids (#3932)
+   - Use component-wise selectors when flattening conditional branches (#3921)
+   - Avoid void struct member when outlining functions (#3936)
+   - Do not allow Block-decorated structs when adding parameters (#3931)
+   - Fix to operand id type (#3937)
+   - Handle dead blocks in TransformationEquationInstruction (#3933)
+   - Do not allow sampled image load when flattening conditionals (#3930)
+   - Take care of OpPhi instructions when inlining (#3939)
+   - Fix to TransformationInlineFunction (#3913)
+   - Wrap early terminators before merging returns (#3925)
+   - Lower probability of adding bit instruction synonyms (#3917)
+   - Fix handling of OpPhi in FlattenConditionalBranch (#3916)
+   - Avoid creating blocks without parents (#3908)
+   - Do not allow creation of constants of block-decorated structs (#3903)
+   - Fixes related to irrelevant ids (#3901)
+   - Fix to transformation that adds a synonym via a loop (#3898)
+   - Fix to duplicate region with selection (#3896)
+   - Do not expose synonym facts for non-existent ids (#3891)
+   - Do not add synonyms involving irrelevant ids (#3890)
+   - Do not replace irrelevant ids that are not in blocks (#3892)
+   - Wrap OpKill and similar in function calls (#3884)
+   - Integrate spirv-reduce with shrinker (#3849)
+   - Report fresh ids in transformations (#3856)
+   - Support OpNot bit instruction case (#3841)
+   - Return IR and transformation context after replay (#3846)
 
 v2020.5 2020-09-22
  - General

+ 1 - 1
3rdparty/spirv-tools/include/generated/build-version.inc

@@ -1 +1 @@
-"v2020.6", "SPIRV-Tools v2020.6 475fea23bc1061461168fd99de41ebc8ee321b3b"
+"v2020.7-dev", "SPIRV-Tools v2020.7-dev c73d8d8cf8076c3848338cc5a5f63d291afa2989"

+ 4 - 0
3rdparty/spirv-tools/include/spirv-tools/instrument.hpp

@@ -171,6 +171,10 @@ static const int kInstErrorBindlessBounds = 0;
 static const int kInstErrorBindlessUninit = 1;
 static const int kInstErrorBuffAddrUnallocRef = 2;
 static const int kInstErrorBindlessBuffOOB = 3;
+static const int kInstErrorBuffOOBUniform = 4;
+static const int kInstErrorBuffOOBStorage = 5;
+static const int kInstErrorBuffOOBUniformTexel = 6;
+static const int kInstErrorBuffOOBStorageTexel = 7;
 
 // Direct Input Buffer Offsets
 //

+ 9 - 5
3rdparty/spirv-tools/include/spirv-tools/optimizer.hpp

@@ -747,12 +747,16 @@ Optimizer::PassToken CreateCombineAccessChainsPass();
 // The instrumentation will read and write buffers in debug
 // descriptor set |desc_set|. It will write |shader_id| in each output record
 // to identify the shader module which generated the record.
-// |input_length_enable| controls instrumentation of runtime descriptor array
-// references, and |input_init_enable| controls instrumentation of descriptor
-// initialization checking, both of which require input buffer support.
+// |desc_length_enable| controls instrumentation of runtime descriptor array
+// references, |desc_init_enable| controls instrumentation of descriptor
+// initialization checking, and |buff_oob_enable| controls instrumentation
+// of storage and uniform buffer bounds checking, all of which require input
+// buffer support. |texbuff_oob_enable| controls instrumentation of texel
+// buffers, which does not require input buffer support.
 Optimizer::PassToken CreateInstBindlessCheckPass(
-    uint32_t desc_set, uint32_t shader_id, bool input_length_enable = false,
-    bool input_init_enable = false, bool input_buff_oob_enable = false);
+    uint32_t desc_set, uint32_t shader_id, bool desc_length_enable = false,
+    bool desc_init_enable = false, bool buff_oob_enable = false,
+    bool texbuff_oob_enable = false);
 
 // Create a pass to instrument physical buffer address checking
 // This pass instruments all physical buffer address references to check that

+ 1 - 0
3rdparty/spirv-tools/source/opt/aggressive_dead_code_elim_pass.cpp

@@ -991,6 +991,7 @@ void AggressiveDCEPass::InitExtensions() {
       "SPV_NV_mesh_shader",
       "SPV_NV_ray_tracing",
       "SPV_KHR_ray_tracing",
+      "SPV_KHR_ray_query",
       "SPV_EXT_fragment_invocation_density",
       "SPV_EXT_physical_storage_buffer",
       "SPV_KHR_terminate_invocation",

+ 6 - 15
3rdparty/spirv-tools/source/opt/eliminate_dead_members_pass.cpp

@@ -228,15 +228,10 @@ void EliminateDeadMembersPass::MarkMembersAsLiveForAccessChain(
             const_mgr->FindDeclaredConstant(inst->GetSingleWordInOperand(i))
                 ->AsIntConstant();
         assert(member_idx);
-        if (member_idx->type()->AsInteger()->width() == 32) {
-          used_members_[type_id].insert(member_idx->GetU32());
-          type_id = type_inst->GetSingleWordInOperand(member_idx->GetU32());
-        } else {
-          used_members_[type_id].insert(
-              static_cast<uint32_t>(member_idx->GetU64()));
-          type_id = type_inst->GetSingleWordInOperand(
-              static_cast<uint32_t>(member_idx->GetU64()));
-        }
+        uint32_t index =
+            static_cast<uint32_t>(member_idx->GetZeroExtendedValue());
+        used_members_[type_id].insert(index);
+        type_id = type_inst->GetSingleWordInOperand(index);
       } break;
       case SpvOpTypeArray:
       case SpvOpTypeRuntimeArray:
@@ -477,12 +472,8 @@ bool EliminateDeadMembersPass::UpdateAccessChain(Instruction* inst) {
             const_mgr->FindDeclaredConstant(inst->GetSingleWordInOperand(i))
                 ->AsIntConstant();
         assert(member_idx);
-        uint32_t orig_member_idx;
-        if (member_idx->type()->AsInteger()->width() == 32) {
-          orig_member_idx = member_idx->GetU32();
-        } else {
-          orig_member_idx = static_cast<uint32_t>(member_idx->GetU64());
-        }
+        uint32_t orig_member_idx =
+            static_cast<uint32_t>(member_idx->GetZeroExtendedValue());
         uint32_t new_member_idx = GetNewMemberIndex(type_id, orig_member_idx);
         assert(new_member_idx != kRemovedMember);
         if (orig_member_idx != new_member_idx) {

+ 151 - 58
3rdparty/spirv-tools/source/opt/inst_bindless_check_pass.cpp

@@ -23,13 +23,17 @@ static const int kSpvImageSampleImageIdInIdx = 0;
 static const int kSpvSampledImageImageIdInIdx = 0;
 static const int kSpvSampledImageSamplerIdInIdx = 1;
 static const int kSpvImageSampledImageIdInIdx = 0;
+static const int kSpvCopyObjectOperandIdInIdx = 0;
 static const int kSpvLoadPtrIdInIdx = 0;
 static const int kSpvAccessChainBaseIdInIdx = 0;
 static const int kSpvAccessChainIndex0IdInIdx = 1;
 static const int kSpvTypeArrayLengthIdInIdx = 1;
 static const int kSpvConstantValueInIdx = 0;
 static const int kSpvVariableStorageClassInIdx = 0;
-
+static const int kSpvTypeImageDim = 1;
+static const int kSpvTypeImageDepth = 2;
+static const int kSpvTypeImageArrayed = 3;
+static const int kSpvTypeImageMS = 4;
 }  // anonymous namespace
 
 // Avoid unused variable warning/error on Linux
@@ -75,42 +79,51 @@ uint32_t InstBindlessCheckPass::GenDebugReadInit(uint32_t var_id,
   }
 }
 
+uint32_t InstBindlessCheckPass::CloneOriginalImage(
+    uint32_t old_image_id, InstructionBuilder* builder) {
+  Instruction* new_image_inst;
+  Instruction* old_image_inst = get_def_use_mgr()->GetDef(old_image_id);
+  if (old_image_inst->opcode() == SpvOpLoad) {
+    new_image_inst = builder->AddLoad(
+        old_image_inst->type_id(),
+        old_image_inst->GetSingleWordInOperand(kSpvLoadPtrIdInIdx));
+  } else if (old_image_inst->opcode() == SpvOp::SpvOpSampledImage) {
+    uint32_t clone_id = CloneOriginalImage(
+        old_image_inst->GetSingleWordInOperand(kSpvSampledImageImageIdInIdx),
+        builder);
+    new_image_inst = builder->AddBinaryOp(
+        old_image_inst->type_id(), SpvOpSampledImage, clone_id,
+        old_image_inst->GetSingleWordInOperand(kSpvSampledImageSamplerIdInIdx));
+  } else if (old_image_inst->opcode() == SpvOp::SpvOpImage) {
+    uint32_t clone_id = CloneOriginalImage(
+        old_image_inst->GetSingleWordInOperand(kSpvImageSampledImageIdInIdx),
+        builder);
+    new_image_inst =
+        builder->AddUnaryOp(old_image_inst->type_id(), SpvOpImage, clone_id);
+  } else {
+    assert(old_image_inst->opcode() == SpvOp::SpvOpCopyObject &&
+           "expecting OpCopyObject");
+    uint32_t clone_id = CloneOriginalImage(
+        old_image_inst->GetSingleWordInOperand(kSpvCopyObjectOperandIdInIdx),
+        builder);
+    // Since we are cloning, no need to create new copy
+    new_image_inst = get_def_use_mgr()->GetDef(clone_id);
+  }
+  uid2offset_[new_image_inst->unique_id()] =
+      uid2offset_[old_image_inst->unique_id()];
+  uint32_t new_image_id = new_image_inst->result_id();
+  get_decoration_mgr()->CloneDecorations(old_image_id, new_image_id);
+  return new_image_id;
+}
+
 uint32_t InstBindlessCheckPass::CloneOriginalReference(
-    ref_analysis* ref, InstructionBuilder* builder) {
+    RefAnalysis* ref, InstructionBuilder* builder) {
   // If original is image based, start by cloning descriptor load
   uint32_t new_image_id = 0;
   if (ref->desc_load_id != 0) {
-    Instruction* desc_load_inst = get_def_use_mgr()->GetDef(ref->desc_load_id);
-    Instruction* new_load_inst = builder->AddLoad(
-        desc_load_inst->type_id(),
-        desc_load_inst->GetSingleWordInOperand(kSpvLoadPtrIdInIdx));
-    uid2offset_[new_load_inst->unique_id()] =
-        uid2offset_[desc_load_inst->unique_id()];
-    uint32_t new_load_id = new_load_inst->result_id();
-    get_decoration_mgr()->CloneDecorations(desc_load_inst->result_id(),
-                                           new_load_id);
-    new_image_id = new_load_id;
-    // Clone Image/SampledImage with new load, if needed
-    if (ref->image_id != 0) {
-      Instruction* image_inst = get_def_use_mgr()->GetDef(ref->image_id);
-      if (image_inst->opcode() == SpvOp::SpvOpSampledImage) {
-        Instruction* new_image_inst = builder->AddBinaryOp(
-            image_inst->type_id(), SpvOpSampledImage, new_load_id,
-            image_inst->GetSingleWordInOperand(kSpvSampledImageSamplerIdInIdx));
-        uid2offset_[new_image_inst->unique_id()] =
-            uid2offset_[image_inst->unique_id()];
-        new_image_id = new_image_inst->result_id();
-      } else {
-        assert(image_inst->opcode() == SpvOp::SpvOpImage &&
-               "expecting OpImage");
-        Instruction* new_image_inst =
-            builder->AddUnaryOp(image_inst->type_id(), SpvOpImage, new_load_id);
-        uid2offset_[new_image_inst->unique_id()] =
-            uid2offset_[image_inst->unique_id()];
-        new_image_id = new_image_inst->result_id();
-      }
-      get_decoration_mgr()->CloneDecorations(ref->image_id, new_image_id);
-    }
+    uint32_t old_image_id =
+        ref->ref_inst->GetSingleWordInOperand(kSpvImageSampleImageIdInIdx);
+    new_image_id = CloneOriginalImage(old_image_id, builder);
   }
   // Clone original reference
   std::unique_ptr<Instruction> new_ref_inst(ref->ref_inst->Clone(context()));
@@ -179,7 +192,7 @@ Instruction* InstBindlessCheckPass::GetPointeeTypeInst(Instruction* ptr_inst) {
 }
 
 bool InstBindlessCheckPass::AnalyzeDescriptorReference(Instruction* ref_inst,
-                                                       ref_analysis* ref) {
+                                                       RefAnalysis* ref) {
   ref->ref_inst = ref_inst;
   if (ref_inst->opcode() == SpvOpLoad || ref_inst->opcode() == SpvOpStore) {
     ref->desc_load_id = 0;
@@ -220,25 +233,28 @@ bool InstBindlessCheckPass::AnalyzeDescriptorReference(Instruction* ref_inst,
   // Reference is not load or store. If not an image-based reference, return.
   ref->image_id = GetImageId(ref_inst);
   if (ref->image_id == 0) return false;
-  Instruction* image_inst = get_def_use_mgr()->GetDef(ref->image_id);
-  Instruction* desc_load_inst = nullptr;
-  if (image_inst->opcode() == SpvOp::SpvOpSampledImage) {
-    ref->desc_load_id =
-        image_inst->GetSingleWordInOperand(kSpvSampledImageImageIdInIdx);
-    desc_load_inst = get_def_use_mgr()->GetDef(ref->desc_load_id);
-  } else if (image_inst->opcode() == SpvOp::SpvOpImage) {
-    ref->desc_load_id =
-        image_inst->GetSingleWordInOperand(kSpvImageSampledImageIdInIdx);
-    desc_load_inst = get_def_use_mgr()->GetDef(ref->desc_load_id);
-  } else {
-    ref->desc_load_id = ref->image_id;
-    desc_load_inst = image_inst;
-    ref->image_id = 0;
+  // Search for descriptor load
+  uint32_t desc_load_id = ref->image_id;
+  Instruction* desc_load_inst;
+  for (;;) {
+    desc_load_inst = get_def_use_mgr()->GetDef(desc_load_id);
+    if (desc_load_inst->opcode() == SpvOp::SpvOpSampledImage)
+      desc_load_id =
+          desc_load_inst->GetSingleWordInOperand(kSpvSampledImageImageIdInIdx);
+    else if (desc_load_inst->opcode() == SpvOp::SpvOpImage)
+      desc_load_id =
+          desc_load_inst->GetSingleWordInOperand(kSpvImageSampledImageIdInIdx);
+    else if (desc_load_inst->opcode() == SpvOp::SpvOpCopyObject)
+      desc_load_id =
+          desc_load_inst->GetSingleWordInOperand(kSpvCopyObjectOperandIdInIdx);
+    else
+      break;
   }
   if (desc_load_inst->opcode() != SpvOp::SpvOpLoad) {
     // TODO(greg-lunarg): Handle additional possibilities?
     return false;
   }
+  ref->desc_load_id = desc_load_id;
   ref->ptr_id = desc_load_inst->GetSingleWordInOperand(kSpvLoadPtrIdInIdx);
   Instruction* ptr_inst = get_def_use_mgr()->GetDef(ref->ptr_id);
   if (ptr_inst->opcode() == SpvOp::SpvOpVariable) {
@@ -322,7 +338,7 @@ uint32_t InstBindlessCheckPass::ByteSize(uint32_t ty_id, uint32_t matrix_stride,
   return size;
 }
 
-uint32_t InstBindlessCheckPass::GenLastByteIdx(ref_analysis* ref,
+uint32_t InstBindlessCheckPass::GenLastByteIdx(RefAnalysis* ref,
                                                InstructionBuilder* builder) {
   // Find outermost buffer type and its access chain index
   Instruction* var_inst = get_def_use_mgr()->GetDef(ref->var_id);
@@ -474,7 +490,7 @@ uint32_t InstBindlessCheckPass::GenLastByteIdx(ref_analysis* ref,
 
 void InstBindlessCheckPass::GenCheckCode(
     uint32_t check_id, uint32_t error_id, uint32_t offset_id,
-    uint32_t length_id, uint32_t stage_idx, ref_analysis* ref,
+    uint32_t length_id, uint32_t stage_idx, RefAnalysis* ref,
     std::vector<std::unique_ptr<BasicBlock>>* new_blocks) {
   BasicBlock* back_blk_ptr = &*new_blocks->back();
   InstructionBuilder builder(
@@ -508,7 +524,7 @@ void InstBindlessCheckPass::GenCheckCode(
     GenDebugStreamWrite(uid2offset_[ref->ref_inst->unique_id()], stage_idx,
                         {error_id, u_index_id, u_offset_id, u_length_id},
                         &builder);
-  } else if (buffer_bounds_enabled_) {
+  } else if (buffer_bounds_enabled_ || texel_buffer_enabled_) {
     // Uninitialized Descriptor - Return additional unused zero so all error
     // modes will use same debug stream write function
     uint32_t u_length_id = GenUintCastCode(length_id, &builder);
@@ -551,7 +567,7 @@ void InstBindlessCheckPass::GenDescIdxCheckCode(
     std::vector<std::unique_ptr<BasicBlock>>* new_blocks) {
   // Look for reference through indexed descriptor. If found, analyze and
   // save components. If not, return.
-  ref_analysis ref;
+  RefAnalysis ref;
   if (!AnalyzeDescriptorReference(&*ref_inst_itr, &ref)) return;
   Instruction* ptr_inst = get_def_use_mgr()->GetDef(ref.ptr_id);
   if (ptr_inst->opcode() != SpvOp::SpvOpAccessChain) return;
@@ -610,7 +626,7 @@ void InstBindlessCheckPass::GenDescInitCheckCode(
     UptrVectorIterator<BasicBlock> ref_block_itr, uint32_t stage_idx,
     std::vector<std::unique_ptr<BasicBlock>>* new_blocks) {
   // Look for reference through descriptor. If not, return.
-  ref_analysis ref;
+  RefAnalysis ref;
   if (!AnalyzeDescriptorReference(&*ref_inst_itr, &ref)) return;
   // Determine if we can only do initialization check
   bool init_check = false;
@@ -661,12 +677,77 @@ void InstBindlessCheckPass::GenDescInitCheckCode(
   MovePostludeCode(ref_block_itr, back_blk_ptr);
 }
 
+void InstBindlessCheckPass::GenTexBuffCheckCode(
+    BasicBlock::iterator ref_inst_itr,
+    UptrVectorIterator<BasicBlock> ref_block_itr, uint32_t stage_idx,
+    std::vector<std::unique_ptr<BasicBlock>>* new_blocks) {
+  // Only process OpImageRead and OpImageWrite with no optional operands
+  Instruction* ref_inst = &*ref_inst_itr;
+  SpvOp op = ref_inst->opcode();
+  uint32_t num_in_oprnds = ref_inst->NumInOperands();
+  if (!((op == SpvOpImageRead && num_in_oprnds == 2) ||
+        (op == SpvOpImageFetch && num_in_oprnds == 2) ||
+        (op == SpvOpImageWrite && num_in_oprnds == 3)))
+    return;
+  // Pull components from descriptor reference
+  RefAnalysis ref;
+  if (!AnalyzeDescriptorReference(ref_inst, &ref)) return;
+  // Only process if image is texel buffer
+  Instruction* image_inst = get_def_use_mgr()->GetDef(ref.image_id);
+  uint32_t image_ty_id = image_inst->type_id();
+  Instruction* image_ty_inst = get_def_use_mgr()->GetDef(image_ty_id);
+  if (image_ty_inst->GetSingleWordInOperand(kSpvTypeImageDim) != SpvDimBuffer)
+    return;
+  if (image_ty_inst->GetSingleWordInOperand(kSpvTypeImageDepth) != 0) return;
+  if (image_ty_inst->GetSingleWordInOperand(kSpvTypeImageArrayed) != 0) return;
+  if (image_ty_inst->GetSingleWordInOperand(kSpvTypeImageMS) != 0) return;
+  // Enable ImageQuery Capability if not yet enabled
+  if (!get_feature_mgr()->HasCapability(SpvCapabilityImageQuery)) {
+    std::unique_ptr<Instruction> cap_image_query_inst(new Instruction(
+        context(), SpvOpCapability, 0, 0,
+        std::initializer_list<Operand>{
+            {SPV_OPERAND_TYPE_CAPABILITY, {SpvCapabilityImageQuery}}}));
+    get_def_use_mgr()->AnalyzeInstDefUse(&*cap_image_query_inst);
+    context()->AddCapability(std::move(cap_image_query_inst));
+  }
+  // Move original block's preceding instructions into first new block
+  std::unique_ptr<BasicBlock> new_blk_ptr;
+  MovePreludeCode(ref_inst_itr, ref_block_itr, &new_blk_ptr);
+  InstructionBuilder builder(
+      context(), &*new_blk_ptr,
+      IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
+  new_blocks->push_back(std::move(new_blk_ptr));
+  // Get texel coordinate
+  uint32_t coord_id =
+      GenUintCastCode(ref_inst->GetSingleWordInOperand(1), &builder);
+  // If index id not yet set, binding is single descriptor, so set index to
+  // constant 0.
+  if (ref.desc_idx_id == 0) ref.desc_idx_id = builder.GetUintConstantId(0u);
+  // Get texel buffer size.
+  Instruction* size_inst =
+      builder.AddUnaryOp(GetUintId(), SpvOpImageQuerySize, ref.image_id);
+  uint32_t size_id = size_inst->result_id();
+  // Generate runtime initialization/bounds test code with true branch
+  // being full reference and false branch being debug output and zero
+  // for the referenced value.
+  Instruction* ult_inst =
+      builder.AddBinaryOp(GetBoolId(), SpvOpULessThan, coord_id, size_id);
+  uint32_t error_id = builder.GetUintConstantId(kInstErrorBindlessBuffOOB);
+  GenCheckCode(ult_inst->result_id(), error_id, coord_id, size_id, stage_idx,
+               &ref, new_blocks);
+  // Move original block's remaining code into remainder/merge block and add
+  // to new blocks
+  BasicBlock* back_blk_ptr = &*new_blocks->back();
+  MovePostludeCode(ref_block_itr, back_blk_ptr);
+}
+
 void InstBindlessCheckPass::InitializeInstBindlessCheck() {
   // Initialize base class
   InitializeInstrument();
-  // If runtime array length support enabled, create variable mappings. Length
-  // support is always enabled if descriptor init check is enabled.
-  if (desc_idx_enabled_ || buffer_bounds_enabled_)
+  // If runtime array length support or buffer bounds checking are enabled,
+  // create variable mappings. Length support is always enabled if descriptor
+  // init check is enabled.
+  if (desc_idx_enabled_ || buffer_bounds_enabled_ || texel_buffer_enabled_)
     for (auto& anno : get_module()->annotations())
       if (anno.opcode() == SpvOpDecorate) {
         if (anno.GetSingleWordInOperand(1u) == SpvDecorationDescriptorSet)
@@ -689,8 +770,8 @@ Pass::Status InstBindlessCheckPass::ProcessImpl() {
       };
   bool modified = InstProcessEntryPointCallTree(pfn);
   if (desc_init_enabled_ || buffer_bounds_enabled_) {
-    // Perform descriptor initialization check on each entry point function in
-    // module
+    // Perform descriptor initialization and/or buffer bounds check on each
+    // entry point function in module
     pfn = [this](BasicBlock::iterator ref_inst_itr,
                  UptrVectorIterator<BasicBlock> ref_block_itr,
                  uint32_t stage_idx,
@@ -700,6 +781,18 @@ Pass::Status InstBindlessCheckPass::ProcessImpl() {
     };
     modified |= InstProcessEntryPointCallTree(pfn);
   }
+  if (texel_buffer_enabled_) {
+    // Perform texel buffer bounds check on each entry point function in
+    // module. Generate after descriptor bounds and initialization checks.
+    pfn = [this](BasicBlock::iterator ref_inst_itr,
+                 UptrVectorIterator<BasicBlock> ref_block_itr,
+                 uint32_t stage_idx,
+                 std::vector<std::unique_ptr<BasicBlock>>* new_blocks) {
+      return GenTexBuffCheckCode(ref_inst_itr, ref_block_itr, stage_idx,
+                                 new_blocks);
+    };
+    modified |= InstProcessEntryPointCallTree(pfn);
+  }
   return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange;
 }
 

+ 29 - 21
3rdparty/spirv-tools/source/opt/inst_bindless_check_pass.h

@@ -28,24 +28,16 @@ namespace opt {
 // external design may change as the layer evolves.
 class InstBindlessCheckPass : public InstrumentPass {
  public:
-  // Old interface to support testing pre-buffer-overrun capability
-  InstBindlessCheckPass(uint32_t desc_set, uint32_t shader_id,
-                        bool desc_idx_enable, bool desc_init_enable)
-      : InstrumentPass(desc_set, shader_id, kInstValidationIdBindless, false),
-        desc_idx_enabled_(desc_idx_enable),
-        desc_init_enabled_(desc_init_enable),
-        buffer_bounds_enabled_(false) {}
-
-  // New interface supporting buffer overrun checking
   InstBindlessCheckPass(uint32_t desc_set, uint32_t shader_id,
                         bool desc_idx_enable, bool desc_init_enable,
-                        bool buffer_bounds_enable)
-      : InstrumentPass(
-            desc_set, shader_id, kInstValidationIdBindless,
-            desc_idx_enable || desc_init_enable || buffer_bounds_enable),
+                        bool buffer_bounds_enable, bool texel_buffer_enable,
+                        bool opt_direct_reads)
+      : InstrumentPass(desc_set, shader_id, kInstValidationIdBindless,
+                       opt_direct_reads),
         desc_idx_enabled_(desc_idx_enable),
         desc_init_enabled_(desc_init_enable),
-        buffer_bounds_enabled_(buffer_bounds_enable) {}
+        buffer_bounds_enabled_(buffer_bounds_enable),
+        texel_buffer_enabled_(texel_buffer_enable) {}
 
   ~InstBindlessCheckPass() override = default;
 
@@ -63,6 +55,10 @@ class InstBindlessCheckPass : public InstrumentPass {
   // checks that the referenced descriptor has been initialized, if the
   // SPV_EXT_descriptor_indexing extension is enabled, and initialized large
   // enough to handle the reference, if RobustBufferAccess is disabled.
+  // GenDescInitCheckCode checks for uniform and storage buffer overrun.
+  // GenTexBuffCheckCode checks for texel buffer overrun and should be
+  // run after GenDescInitCheckCode to first make sure that the descriptor
+  // is initialized because it uses OpImageQuerySize on the descriptor.
   //
   // The functions are designed to be passed to
   // InstrumentPass::InstProcessEntryPointCallTree(), which applies the
@@ -109,6 +105,11 @@ class InstBindlessCheckPass : public InstrumentPass {
       UptrVectorIterator<BasicBlock> ref_block_itr, uint32_t stage_idx,
       std::vector<std::unique_ptr<BasicBlock>>* new_blocks);
 
+  void GenTexBuffCheckCode(
+      BasicBlock::iterator ref_inst_itr,
+      UptrVectorIterator<BasicBlock> ref_block_itr, uint32_t stage_idx,
+      std::vector<std::unique_ptr<BasicBlock>>* new_blocks);
+
   // Generate instructions into |builder| to read length of runtime descriptor
   // array |var_id| from debug input buffer and return id of value.
   uint32_t GenDebugReadLength(uint32_t var_id, InstructionBuilder* builder);
@@ -122,7 +123,7 @@ class InstBindlessCheckPass : public InstrumentPass {
   // Analysis data for descriptor reference components, generated by
   // AnalyzeDescriptorReference. It is necessary and sufficient for further
   // analysis and regeneration of the reference.
-  typedef struct ref_analysis {
+  typedef struct RefAnalysis {
     uint32_t desc_load_id;
     uint32_t image_id;
     uint32_t load_id;
@@ -130,7 +131,7 @@ class InstBindlessCheckPass : public InstrumentPass {
     uint32_t var_id;
     uint32_t desc_idx_id;
     Instruction* ref_inst;
-  } ref_analysis;
+  } RefAnalysis;
 
   // Return size of type |ty_id| in bytes. Use |matrix_stride| and |col_major|
   // for matrix type, or for vector type if vector is |in_matrix|.
@@ -142,11 +143,15 @@ class InstBindlessCheckPass : public InstrumentPass {
   uint32_t FindStride(uint32_t ty_id, uint32_t stride_deco);
 
   // Generate index of last byte referenced by buffer reference |ref|
-  uint32_t GenLastByteIdx(ref_analysis* ref, InstructionBuilder* builder);
+  uint32_t GenLastByteIdx(RefAnalysis* ref, InstructionBuilder* builder);
+
+  // Clone original image computation starting at |image_id| into |builder|.
+  // This may generate more than one instruction if neccessary.
+  uint32_t CloneOriginalImage(uint32_t image_id, InstructionBuilder* builder);
 
   // Clone original original reference encapsulated by |ref| into |builder|.
   // This may generate more than one instruction if neccessary.
-  uint32_t CloneOriginalReference(ref_analysis* ref,
+  uint32_t CloneOriginalReference(RefAnalysis* ref,
                                   InstructionBuilder* builder);
 
   // If |inst| references through an image, return the id of the image it
@@ -158,7 +163,7 @@ class InstBindlessCheckPass : public InstrumentPass {
 
   // Analyze descriptor reference |ref_inst| and save components into |ref|.
   // Return true if |ref_inst| is a descriptor reference, false otherwise.
-  bool AnalyzeDescriptorReference(Instruction* ref_inst, ref_analysis* ref);
+  bool AnalyzeDescriptorReference(Instruction* ref_inst, RefAnalysis* ref);
 
   // Generate instrumentation code for generic test result |check_id|, starting
   // with |builder| of block |new_blk_ptr|, adding new blocks to |new_blocks|.
@@ -168,7 +173,7 @@ class InstBindlessCheckPass : public InstrumentPass {
   // |stage_idx|. Generate merge block for valid and invalid branches. Kill
   // original reference.
   void GenCheckCode(uint32_t check_id, uint32_t error_id, uint32_t offset_id,
-                    uint32_t length_id, uint32_t stage_idx, ref_analysis* ref,
+                    uint32_t length_id, uint32_t stage_idx, RefAnalysis* ref,
                     std::vector<std::unique_ptr<BasicBlock>>* new_blocks);
 
   // Initialize state for instrumenting bindless checking
@@ -184,9 +189,12 @@ class InstBindlessCheckPass : public InstrumentPass {
   // Enable instrumentation of descriptor initialization checking
   bool desc_init_enabled_;
 
-  // Enable instrumentation of buffer overrun checking
+  // Enable instrumentation of uniform and storage buffer overrun checking
   bool buffer_bounds_enabled_;
 
+  // Enable instrumentation of texel buffer overrun checking
+  bool texel_buffer_enabled_;
+
   // Mapping from variable to descriptor set
   std::unordered_map<uint32_t, uint32_t> var2desc_set_;
 

+ 7 - 8
3rdparty/spirv-tools/source/opt/optimizer.cpp

@@ -425,7 +425,7 @@ bool Optimizer::RegisterPassFromFlag(const std::string& flag) {
     RegisterPass(CreateBlockMergePass());
     RegisterPass(CreateAggressiveDCEPass());
   } else if (pass_name == "inst-buff-oob-check") {
-    RegisterPass(CreateInstBindlessCheckPass(7, 23, false, false, true));
+    RegisterPass(CreateInstBindlessCheckPass(7, 23, false, false, true, true));
     RegisterPass(CreateSimplificationPass());
     RegisterPass(CreateDeadBranchElimPass());
     RegisterPass(CreateBlockMergePass());
@@ -892,15 +892,14 @@ Optimizer::PassToken CreateUpgradeMemoryModelPass() {
       MakeUnique<opt::UpgradeMemoryModel>());
 }
 
-Optimizer::PassToken CreateInstBindlessCheckPass(uint32_t desc_set,
-                                                 uint32_t shader_id,
-                                                 bool input_length_enable,
-                                                 bool input_init_enable,
-                                                 bool input_buff_oob_enable) {
+Optimizer::PassToken CreateInstBindlessCheckPass(
+    uint32_t desc_set, uint32_t shader_id, bool desc_length_enable,
+    bool desc_init_enable, bool buff_oob_enable, bool texbuff_oob_enable) {
   return MakeUnique<Optimizer::PassToken::Impl>(
       MakeUnique<opt::InstBindlessCheckPass>(
-          desc_set, shader_id, input_length_enable, input_init_enable,
-          input_buff_oob_enable));
+          desc_set, shader_id, desc_length_enable, desc_init_enable,
+          buff_oob_enable, texbuff_oob_enable,
+          desc_length_enable || desc_init_enable || buff_oob_enable));
 }
 
 Optimizer::PassToken CreateInstDebugPrintfPass(uint32_t desc_set,

+ 376 - 81
3rdparty/spirv-tools/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 @@ bool IsBuiltInValidForWebGPU(SpvBuiltIn label) {
   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 @@ class BuiltInsValidator {
                                                   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 @@ class BuiltInsValidator {
   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 @@ class BuiltInsValidator {
       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 @@ class BuiltInsValidator {
       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 @@ class BuiltInsValidator {
       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 @@ spv_result_t BuiltInsValidator::ValidateF32ArrHelper(
   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 @@ spv_result_t BuiltInsValidator::ValidatePrimitiveIdAtReference(
           "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 @@ spv_result_t BuiltInsValidator::ValidatePrimitiveIdAtReference(
         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 @@ spv_result_t BuiltInsValidator::ValidatePrimitiveIdAtReference(
                  << _.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,56 +2534,15 @@ spv_result_t BuiltInsValidator::ValidateVertexIndexAtDefinition(
   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) {
+  (void)decoration;
+  if (spvIsVulkanEnv(_.context()->target_env)) {
     return _.diag(SPV_ERROR_INVALID_DATA, &inst)
-           << "Vulkan spec doesn't allow BuiltIn VertexId/InstanceId "
+           << "Vulkan spec doesn't allow BuiltIn VertexId "
               "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) {
-  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 SPV_SUCCESS;
 }
 
@@ -3474,6 +3595,174 @@ spv_result_t BuiltInsValidator::ValidateShadingRateAtReference(
   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 @@ spv_result_t BuiltInsValidator::ValidateSingleBuiltInAtDefinition(
     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 @@ spv_result_t BuiltInsValidator::ValidateSingleBuiltInAtDefinition(
     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 @@ spv_result_t BuiltInsValidator::ValidateSingleBuiltInAtDefinition(
     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;

+ 96 - 0
3rdparty/spirv-tools/source/val/validation_state.cpp

@@ -1363,6 +1363,36 @@ std::string ValidationState_t::VkErrorID(uint32_t id,
       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 @@ std::string ValidationState_t::VkErrorID(uint32_t id,
       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 @@ std::string ValidationState_t::VkErrorID(uint32_t id,
       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 @@ std::string ValidationState_t::VkErrorID(uint32_t id,
       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 @@ std::string ValidationState_t::VkErrorID(uint32_t id,
       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: