From 37e50587ae70f58989e565761fc6d5ab354906b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=91=D1=80=D0=B0=D0=BD=D0=B8=D0=BC=D0=B8=D1=80=20=D0=9A?= =?UTF-8?q?=D0=B0=D1=80=D0=B0=D1=9F=D0=B8=D1=9B?= Date: Sat, 5 Dec 2020 19:13:13 -0800 Subject: [PATCH] Updated spirv-tools. --- 3rdparty/spirv-tools/CHANGES | 92 +++- .../include/generated/build-version.inc | 2 +- .../include/spirv-tools/instrument.hpp | 4 + .../include/spirv-tools/optimizer.hpp | 14 +- .../opt/aggressive_dead_code_elim_pass.cpp | 1 + .../opt/eliminate_dead_members_pass.cpp | 21 +- .../source/opt/inst_bindless_check_pass.cpp | 209 +++++--- .../source/opt/inst_bindless_check_pass.h | 50 +- 3rdparty/spirv-tools/source/opt/optimizer.cpp | 15 +- .../source/val/validate_builtins.cpp | 459 ++++++++++++++---- .../source/val/validation_state.cpp | 96 ++++ 11 files changed, 771 insertions(+), 192 deletions(-) diff --git a/3rdparty/spirv-tools/CHANGES b/3rdparty/spirv-tools/CHANGES index 3c81249df..94d6e2d23 100644 --- a/3rdparty/spirv-tools/CHANGES +++ b/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 diff --git a/3rdparty/spirv-tools/include/generated/build-version.inc b/3rdparty/spirv-tools/include/generated/build-version.inc index b1cec3596..b52e45045 100644 --- a/3rdparty/spirv-tools/include/generated/build-version.inc +++ b/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" diff --git a/3rdparty/spirv-tools/include/spirv-tools/instrument.hpp b/3rdparty/spirv-tools/include/spirv-tools/instrument.hpp index 9c01cb693..2b47a5645 100644 --- a/3rdparty/spirv-tools/include/spirv-tools/instrument.hpp +++ b/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 // diff --git a/3rdparty/spirv-tools/include/spirv-tools/optimizer.hpp b/3rdparty/spirv-tools/include/spirv-tools/optimizer.hpp index f12774d6d..27352b250 100644 --- a/3rdparty/spirv-tools/include/spirv-tools/optimizer.hpp +++ b/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 diff --git a/3rdparty/spirv-tools/source/opt/aggressive_dead_code_elim_pass.cpp b/3rdparty/spirv-tools/source/opt/aggressive_dead_code_elim_pass.cpp index 39d468f98..94451a29c 100644 --- a/3rdparty/spirv-tools/source/opt/aggressive_dead_code_elim_pass.cpp +++ b/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", diff --git a/3rdparty/spirv-tools/source/opt/eliminate_dead_members_pass.cpp b/3rdparty/spirv-tools/source/opt/eliminate_dead_members_pass.cpp index ab28932fe..173df6209 100644 --- a/3rdparty/spirv-tools/source/opt/eliminate_dead_members_pass.cpp +++ b/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(member_idx->GetU64())); - type_id = type_inst->GetSingleWordInOperand( - static_cast(member_idx->GetU64())); - } + uint32_t index = + static_cast(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(member_idx->GetU64()); - } + uint32_t orig_member_idx = + static_cast(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) { diff --git a/3rdparty/spirv-tools/source/opt/inst_bindless_check_pass.cpp b/3rdparty/spirv-tools/source/opt/inst_bindless_check_pass.cpp index 7eb2d1bb5..008573437 100644 --- a/3rdparty/spirv-tools/source/opt/inst_bindless_check_pass.cpp +++ b/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 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>* 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>* 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 ref_block_itr, uint32_t stage_idx, std::vector>* 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 ref_block_itr, uint32_t stage_idx, + std::vector>* 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 cap_image_query_inst(new Instruction( + context(), SpvOpCapability, 0, 0, + std::initializer_list{ + {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 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 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 ref_block_itr, + uint32_t stage_idx, + std::vector>* new_blocks) { + return GenTexBuffCheckCode(ref_inst_itr, ref_block_itr, stage_idx, + new_blocks); + }; + modified |= InstProcessEntryPointCallTree(pfn); + } return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange; } diff --git a/3rdparty/spirv-tools/source/opt/inst_bindless_check_pass.h b/3rdparty/spirv-tools/source/opt/inst_bindless_check_pass.h index 29da6f316..a7dff75f2 100644 --- a/3rdparty/spirv-tools/source/opt/inst_bindless_check_pass.h +++ b/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 ref_block_itr, uint32_t stage_idx, std::vector>* new_blocks); + void GenTexBuffCheckCode( + BasicBlock::iterator ref_inst_itr, + UptrVectorIterator ref_block_itr, uint32_t stage_idx, + std::vector>* 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>* 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 var2desc_set_; diff --git a/3rdparty/spirv-tools/source/opt/optimizer.cpp b/3rdparty/spirv-tools/source/opt/optimizer.cpp index 1ded2ee9b..8726ff93d 100644 --- a/3rdparty/spirv-tools/source/opt/optimizer.cpp +++ b/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()); } -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( MakeUnique( - 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, diff --git a/3rdparty/spirv-tools/source/val/validate_builtins.cpp b/3rdparty/spirv-tools/source/val/validate_builtins.cpp index d9e066653..1d8a14067 100644 --- a/3rdparty/spirv-tools/source/val/validate_builtins.cpp +++ b/3rdparty/spirv-tools/source/val/validate_builtins.cpp @@ -16,6 +16,7 @@ // Validates correctness of built-in variables. +#include #include #include #include @@ -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 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& 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& 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& 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,54 +2534,13 @@ 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) { - 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 @@ 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; diff --git a/3rdparty/spirv-tools/source/val/validation_state.cpp b/3rdparty/spirv-tools/source/val/validation_state.cpp index cb69dda30..06abb54f6 100644 --- a/3rdparty/spirv-tools/source/val/validation_state.cpp +++ b/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: