gpuav: Handle UntypedPointers in AccessPath
diff --git a/layers/gpuav/shaders/instrumentation/descriptor_heap.comp b/layers/gpuav/shaders/instrumentation/descriptor_heap.comp index 5adb555..955fd5d 100644 --- a/layers/gpuav/shaders/instrumentation/descriptor_heap.comp +++ b/layers/gpuav/shaders/instrumentation/descriptor_heap.comp
@@ -177,3 +177,29 @@ bool inst_heap_mapping_indirect_address(const uint inst_offset, const uint push_offset, const uint address_offset) { return true; // Saving function offset space, but currently not used } + +// Untyped Pointers +bool inst_heap_untyped(const uint inst_offset, const uint heap_offset, const uint address_stride, const uint desc_index, const bool is_sampler) { + uint error = 0; + uint param_0 = 0; + + uint offset = heap_offset + (desc_index * address_stride); + BoundHeapInfo bound_heap_info = is_sampler ? gpuav.bound_sampler_heap : gpuav.bound_resource_heap; + if (offset >= bound_heap_info.heap_size) { + error = kErrorSubCode_DescriptorHeap_HeapOOB; + param_0 = offset; + } + + if (error != 0) { + error_payload = ErrorPayload( + inst_offset, + SpecConstantLinkShaderId | (kErrorGroup_InstDescriptorHeap << kErrorGroup_Shift) | (error << kErrorSubCode_Shift), + desc_index, + param_0, + 0 + ); + + return false; + } + return true; +}
diff --git a/layers/gpuav/spirv/debug_printf_pass.cpp b/layers/gpuav/spirv/debug_printf_pass.cpp index c7ae4c7..cbc1415 100644 --- a/layers/gpuav/spirv/debug_printf_pass.cpp +++ b/layers/gpuav/spirv/debug_printf_pass.cpp
@@ -823,17 +823,7 @@ const ParamInfo& param = param_infos[i]; const uint32_t argument_id = meta.target_instruction->Word(first_argument_offset + i); - const Type* argument_type = nullptr; - if (const Constant* constant = type_manager_.FindConstantById(argument_id)) { - argument_type = &constant->type_; - } else { - const Instruction* inst = current_function.FindInstruction(argument_id); - if (!inst) { - module_.InternalWarning(tag, "Unable to find OpExtInst ID inside function block"); - return true; // possibily our error, so leave a warning - } - argument_type = type_manager_.FindTypeById(inst->TypeId()); - } + const Type* argument_type = type_manager_.FindTypeGlobal(current_function, argument_id); if (!argument_type) { module_.InternalWarning(tag, "Unable find OpExtInst ID type"); return true; // possibily our error, so leave a warning
diff --git a/layers/gpuav/spirv/descriptor_class_general_buffer_pass.cpp b/layers/gpuav/spirv/descriptor_class_general_buffer_pass.cpp index 0973a0f..5797b15 100644 --- a/layers/gpuav/spirv/descriptor_class_general_buffer_pass.cpp +++ b/layers/gpuav/spirv/descriptor_class_general_buffer_pass.cpp
@@ -18,6 +18,8 @@ #include "generated/spirv_grammar_helper.h" #include "containers/container_utils.h" #include "module.h" +#include <cassert> +#include <cstdint> #include <spirv/unified1/spirv.hpp> #include <iostream> @@ -54,14 +56,15 @@ void DescriptorClassGeneralBufferPass::CreateFunctionCall(BasicBlock& block, InstructionIt* inst_it, const InstructionMeta& meta) { assert(!meta.access_path.ac_list.empty()); - const Constant& desc_set_constant = type_manager_.GetConstantUInt32(meta.descriptor_set); - const uint32_t desc_index_id = CastToUint32(meta.descriptor_index_id, block, inst_it); // might be int32 + const DescriptorInterface& interface = meta.access_path.variable->interface_; + const Constant& desc_set_constant = type_manager_.GetConstantUInt32(interface.set); + const uint32_t desc_index_id = CastToUint32(meta.access_path.descriptor_index_id, block, inst_it); // might be int32 const uint32_t descriptor_offset_id = - GetLastByte(*meta.descriptor_type, meta.access_path.ac_list, meta.coop_mat_access, block, inst_it); + GetLastByte(*meta.access_path.pointer_type, meta.access_path.ac_list, meta.coop_mat_access, block, inst_it); const auto& layout_lut = module_.interface_.instrumentation_dsl.set_index_to_bindings_layout_lut; - BindingLayout binding_layout = layout_lut[meta.descriptor_set][meta.descriptor_binding]; + BindingLayout binding_layout = layout_lut[interface.set][interface.binding]; const Constant& binding_layout_offset = type_manager_.GetConstantUInt32(binding_layout.start); const uint32_t inst_position = meta.target_instruction->GetPositionOffset(); @@ -84,6 +87,7 @@ InstructionMeta& meta) { const uint32_t opcode = inst.Opcode(); + // Only known way to access a UBO/SSBO if (!IsValueIn(spv::Op(opcode), {spv::OpLoad, spv::OpStore, spv::OpCooperativeMatrixLoadKHR, spv::OpCooperativeMatrixStoreKHR}) && !AtomicOperation(opcode)) { @@ -99,51 +103,35 @@ if (!meta.access_path.IsValid()) { return false; } - const Variable& access_variable = *meta.access_path.variable; - uint32_t storage_class = access_variable.StorageClass(); + uint32_t storage_class = meta.access_path.variable->StorageClass(); + // The idea is General Buffer will not include any UniformConstant descriptor type if (storage_class != spv::StorageClassUniform && storage_class != spv::StorageClassStorageBuffer) { return false; } - meta.descriptor_type = access_variable.PointerType(type_manager_); - if (!meta.descriptor_type || meta.descriptor_type->spv_type_ == SpvType::kRuntimeArray) { + if (meta.access_path.pointer_type->spv_type_ == SpvType::kRuntimeArray) { return false; // TODO - Currently we mark these as "bindless" } - const bool is_descriptor_array = meta.descriptor_type->IsArray(); - meta.descriptor_id = is_descriptor_array ? meta.descriptor_type->inst_.Operand(0) : meta.descriptor_type->Id(); + const bool is_descriptor_array = meta.access_path.pointer_type->IsArray(); + meta.descriptor_block_type_id = + is_descriptor_array ? meta.access_path.pointer_type->inst_.Operand(0) : meta.access_path.pointer_type->Id(); + assert(type_manager_.FindTypeById(meta.descriptor_block_type_id)->spv_type_ == SpvType::kStruct && "unexpected block type"); // Check for deprecated storage block form if (storage_class == spv::StorageClassUniform) { - assert(type_manager_.FindTypeById(meta.descriptor_id)->spv_type_ == SpvType::kStruct && "unexpected block type"); - - const bool block_found = GetDecoration(meta.descriptor_id, spv::DecorationBlock) != nullptr; + const bool block_found = GetDecoration(meta.descriptor_block_type_id, spv::DecorationBlock) != nullptr; // If block decoration not found, verify deprecated form of SSBO if (!block_found) { - assert(GetDecoration(meta.descriptor_id, spv::DecorationBufferBlock) != nullptr && "block decoration not found"); + assert(GetDecoration(meta.descriptor_block_type_id, spv::DecorationBufferBlock) != nullptr && + "block decoration not found"); storage_class = spv::StorageClassStorageBuffer; } } - // Grab front() as it will be the "final" type we access - const Type* value_type = type_manager_.FindValueTypeById(meta.access_path.FinalAccessedType()); - if (!value_type) { - return false; - } - - if (is_descriptor_array) { - // Because you can't have 2D array of descriptors, the first index of the last accessChain is the descriptor index - meta.descriptor_index_id = meta.access_path.DescriptorIndexId(); - } else { - // There is no array of this descriptor, so we essentially have an array of 1 - meta.descriptor_index_id = type_manager_.GetConstantZeroUint32().Id(); - } - - GetDescriptorSetAndBinding(access_variable.Id(), meta.descriptor_set, meta.descriptor_binding); - - if (meta.descriptor_set >= glsl::kDebugInputBindlessMaxDescSets) { + if (meta.access_path.variable->interface_.set >= glsl::kDebugInputBindlessMaxDescSets) { module_.InternalWarning(Name(), "Tried to use a descriptor slot over the current max limit"); return false; } @@ -155,7 +143,7 @@ if (!module_.settings_.safe_mode) { meta.access_offset = - FindOffsetInStruct(meta.descriptor_id, &meta.coop_mat_access, is_descriptor_array, meta.access_path.ac_list); + FindOffsetInStruct(meta.descriptor_block_type_id, &meta.coop_mat_access, is_descriptor_array, meta.access_path.ac_list); } // Save information to be used to make the Function @@ -205,9 +193,9 @@ if (meta.access_offset != 0) { // set offset for the first loop of the block - auto map_it = block_highest_offset_map.find(meta.descriptor_id); + auto map_it = block_highest_offset_map.find(meta.descriptor_block_type_id); if (map_it == block_highest_offset_map.end()) { - block_highest_offset_map[meta.descriptor_id] = meta.access_offset; + block_highest_offset_map[meta.descriptor_block_type_id] = meta.access_offset; } else { map_it->second = std::max(map_it->second, meta.access_offset); } @@ -223,7 +211,7 @@ } if (!module_.settings_.safe_mode && meta.access_offset != 0) { - const uint32_t block_highest_offset = block_highest_offset_map[meta.descriptor_id]; + const uint32_t block_highest_offset = block_highest_offset_map[meta.descriptor_block_type_id]; if (meta.access_offset < block_highest_offset) { continue; // skipping because other instruction in block will be a higher offset }
diff --git a/layers/gpuav/spirv/descriptor_class_general_buffer_pass.h b/layers/gpuav/spirv/descriptor_class_general_buffer_pass.h index 180851a..c769b67 100644 --- a/layers/gpuav/spirv/descriptor_class_general_buffer_pass.h +++ b/layers/gpuav/spirv/descriptor_class_general_buffer_pass.h
@@ -37,14 +37,8 @@ struct InstructionMeta { const Instruction* target_instruction = nullptr; - uint32_t descriptor_set = 0; - uint32_t descriptor_binding = 0; - uint32_t descriptor_index_id = 0; // index input the descriptor array - - // The Type of the OpVariable that is being accessed - const Type* descriptor_type = nullptr; - // Id to the descriptor, will have array stripped if descriptor indexing - uint32_t descriptor_id = 0; + // The ID to the OpTypeStruct inside the SSBO/UBO + uint32_t descriptor_block_type_id = 0; AccessPath access_path;
diff --git a/layers/gpuav/spirv/descriptor_class_texel_buffer_pass.cpp b/layers/gpuav/spirv/descriptor_class_texel_buffer_pass.cpp index f9ea440..2cb420d 100644 --- a/layers/gpuav/spirv/descriptor_class_texel_buffer_pass.cpp +++ b/layers/gpuav/spirv/descriptor_class_texel_buffer_pass.cpp
@@ -14,6 +14,7 @@ */ #include "descriptor_class_texel_buffer_pass.h" +#include "function_basic_block.h" #include "module.h" #include <spirv/unified1/spirv.hpp> #include <iostream> @@ -38,8 +39,9 @@ uint32_t DescriptorClassTexelBufferPass::GetLinkFunctionId() { return GetLinkFunction(link_function_id_, kOfflineFunction); } void DescriptorClassTexelBufferPass::CreateFunctionCall(BasicBlock& block, InstructionIt* inst_it, const InstructionMeta& meta) { - assert(meta.access_chain_inst && meta.var_inst); - const Constant& set_constant = type_manager_.GetConstantUInt32(meta.descriptor_set); + assert(meta.access_chain_inst && meta.descriptor_var); + const DescriptorInterface& interface = meta.descriptor_var->interface_; + const Constant& set_constant = type_manager_.GetConstantUInt32(interface.set); const uint32_t descriptor_index_id = CastToUint32(meta.descriptor_index_id, block, inst_it); // might be int32 const uint32_t opcode = meta.target_instruction->Opcode(); @@ -56,7 +58,7 @@ const uint32_t descriptor_offset_id = CastToUint32(meta.target_instruction->Operand(1), block, inst_it); const auto& layout_lut = module_.interface_.instrumentation_dsl.set_index_to_bindings_layout_lut; - BindingLayout binding_layout = layout_lut[meta.descriptor_set][meta.descriptor_binding]; + BindingLayout binding_layout = layout_lut[interface.set][interface.binding]; const Constant& binding_layout_offset = type_manager_.GetConstantUInt32(binding_layout.start); const uint32_t inst_position = meta.target_instruction->GetPositionOffset(); @@ -74,6 +76,7 @@ module_.need_log_error_ = true; } +// TODO - use AccessPath bool DescriptorClassTexelBufferPass::RequiresInstrumentation(const Function& function, const Instruction& inst, InstructionMeta& meta) { const uint32_t opcode = inst.Opcode(); @@ -110,41 +113,39 @@ return false; // TODO: Handle additional possibilities? } - meta.var_inst = function.FindInstruction(load_inst->Operand(0)); - if (!meta.var_inst) { + const Instruction* var_inst = function.FindInstruction(load_inst->Operand(0)); + if (!var_inst) { // can be a global variable const Variable* global_var = type_manager_.FindVariableById(load_inst->Operand(0)); - meta.var_inst = global_var ? &global_var->inst_ : nullptr; + var_inst = global_var ? &global_var->inst_ : nullptr; } - if (!meta.var_inst || (!meta.var_inst->IsNonPtrAccessChain() && meta.var_inst->Opcode() != spv::OpVariable)) { + if (!var_inst || (!var_inst->IsNonPtrAccessChain() && var_inst->Opcode() != spv::OpVariable)) { return false; } // If OpVariable, access_chain_inst_ is never checked because it should be a direct image access - meta.access_chain_inst = meta.var_inst; + meta.access_chain_inst = var_inst; - if (meta.var_inst->IsNonPtrAccessChain()) { - meta.descriptor_index_id = meta.var_inst->Operand(1); + if (var_inst->IsNonPtrAccessChain()) { + meta.descriptor_index_id = var_inst->Operand(1); - if (meta.var_inst->Length() > 5) { + if (var_inst->Length() > 5) { module_.InternalError(Name(), "OpAccessChain has more than 1 indexes. 2D Texel Buffers not supported"); return false; } - const Variable* variable = type_manager_.FindVariableById(meta.var_inst->Operand(0)); - if (!variable) { + meta.descriptor_var = type_manager_.FindVariableById(var_inst->Operand(0)); + if (!meta.descriptor_var) { module_.InternalError(Name(), "OpAccessChain base is not a variable"); return false; } - meta.var_inst = &variable->inst_; } else { // There is no array of this descriptor, so we essentially have an array of 1 meta.descriptor_index_id = type_manager_.GetConstantZeroUint32().Id(); + meta.descriptor_var = type_manager_.FindVariableById(var_inst->ResultId()); } - GetDescriptorSetAndBinding(meta.var_inst->ResultId(), meta.descriptor_set, meta.descriptor_binding); - - if (meta.descriptor_set >= glsl::kDebugInputBindlessMaxDescSets) { + if (meta.descriptor_var->interface_.set >= glsl::kDebugInputBindlessMaxDescSets) { module_.InternalWarning(Name(), "Tried to use a descriptor slot over the current max limit"); return false; }
diff --git a/layers/gpuav/spirv/descriptor_class_texel_buffer_pass.h b/layers/gpuav/spirv/descriptor_class_texel_buffer_pass.h index dfbb1eb..b01b5e7 100644 --- a/layers/gpuav/spirv/descriptor_class_texel_buffer_pass.h +++ b/layers/gpuav/spirv/descriptor_class_texel_buffer_pass.h
@@ -1,4 +1,4 @@ -/* Copyright (c) 2024-2025 LunarG, Inc. +/* Copyright (c) 2024-2026 LunarG, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -35,12 +35,12 @@ struct InstructionMeta { const Instruction* target_instruction = nullptr; const Instruction* access_chain_inst = nullptr; - const Instruction* var_inst = nullptr; const Instruction* image_inst = nullptr; - uint32_t descriptor_set = 0; - uint32_t descriptor_binding = 0; - uint32_t descriptor_index_id = 0; // index input the descriptor array + const Variable* descriptor_var = nullptr; + + // This is the ID of the uint that indexes in the array (or constant zero if no array) + uint32_t descriptor_index_id = 0; }; bool RequiresInstrumentation(const Function& function, const Instruction& inst, InstructionMeta& meta);
diff --git a/layers/gpuav/spirv/descriptor_heap_pass.cpp b/layers/gpuav/spirv/descriptor_heap_pass.cpp index b34117b..ebe9644 100644 --- a/layers/gpuav/spirv/descriptor_heap_pass.cpp +++ b/layers/gpuav/spirv/descriptor_heap_pass.cpp
@@ -16,13 +16,16 @@ #include "descriptor_heap_pass.h" #include <vulkan/vulkan_core.h> #include "containers/container_utils.h" +#include "generated/spirv_grammar_helper.h" #include "link.h" #include "module.h" +#include <cassert> #include <spirv/unified1/spirv.hpp> #include <iostream> #include "generated/gpuav_offline_spirv.h" #include "pass.h" +#include "type_manager.h" namespace gpuav { namespace spirv { @@ -39,6 +42,7 @@ {"inst_heap_mapping_push_data", instrumentation_descriptor_heap_comp_function_5_offset}, {"inst_heap_mapping_push_address", instrumentation_descriptor_heap_comp_function_6_offset}, {"inst_heap_mapping_indirect_address", instrumentation_descriptor_heap_comp_function_7_offset}, + {"inst_heap_untyped", instrumentation_descriptor_heap_comp_function_8_offset}, }; DescriptorHeapPass::DescriptorHeapPass(Module& module) : Pass(module, kOfflineModule) { module.use_bda_ = true; } @@ -48,12 +52,15 @@ } // TODO - if we find this slow, we could pre-sort all the mappings -const VkDescriptorSetAndBindingMappingEXT* DescriptorHeapPass::GetMapping(uint32_t descriptor_set, uint32_t descriptor_binding) { +const VkDescriptorSetAndBindingMappingEXT* DescriptorHeapPass::GetMapping(const DescriptorInterface& interface) const { + if (interface.IsHeap()) { + return nullptr; + } for (uint32_t map_i = 0; map_i < module_.interface_.mapping_info->mappingCount; map_i++) { const VkDescriptorSetAndBindingMappingEXT& mapping = module_.interface_.mapping_info->pMappings[map_i]; const uint32_t last_binding = mapping.firstBinding + mapping.bindingCount; - if (mapping.descriptorSet == descriptor_set && descriptor_binding >= mapping.firstBinding && - descriptor_binding < last_binding) { + if (mapping.descriptorSet == interface.set && interface.binding >= mapping.firstBinding && + interface.binding < last_binding) { return &mapping; } } @@ -61,20 +68,22 @@ } uint32_t DescriptorHeapPass::CreateFunctionCall(BasicBlock& block, InstructionIt* inst_it, const InstructionMeta& meta, - bool is_sampler) { - const DescriptorMeta descriptor_meta = is_sampler ? meta.sampler : meta.resource; - const uint32_t descriptor_index_id = CastToUint32(descriptor_meta.descriptor_index_id, block, inst_it); // might be int32 + bool is_seperate_sampler) { + const Variable& descriptor_var = is_seperate_sampler ? *meta.access_path.sampler_variable : *meta.access_path.variable; + const uint32_t descriptor_index = + is_seperate_sampler ? meta.access_path.sampler_descriptor_index_id : meta.access_path.descriptor_index_id; + const uint32_t descriptor_index_id = CastToUint32(descriptor_index, block, inst_it); // might be int32 const uint32_t inst_position = meta.target_instruction->GetPositionOffset(); const uint32_t inst_position_id = type_manager_.CreateConstantUInt32(inst_position).Id(); - const uint32_t is_sampler_id = type_manager_.GetConstantBool(is_sampler).Id(); + const uint32_t is_sampler_id = type_manager_.GetConstantBool(is_seperate_sampler).Id(); uint32_t function_result = module_.TakeNextId(); const uint32_t bool_type = type_manager_.GetTypeBool().Id(); // TODO - This logic is not obvious and should be either fixed or moved to a common util // If dealing with a seperate sampler, only need to do it on the resource - if (meta.image_inst && !is_sampler) { + if (meta.access_path.image_load_inst && !is_seperate_sampler) { const uint32_t opcode = meta.target_instruction->Opcode(); if (opcode != spv::OpImageRead && opcode != spv::OpImageFetch && opcode != spv::OpImageWrite) { // if not a direct read/write/fetch, will be a OpSampledImage @@ -96,16 +105,45 @@ } else { copy_object_map_.emplace(image_id, copy_id); // slower, but need to guarantee it is placed after a OpSampledImage - block.function_->CreateInstruction(spv::OpCopyObject, {type_id, copy_id, image_id}, image_id); + block.function_->CreateInstruction(spv::OpCopyObject, {type_id, copy_id, image_id}, image_id, inst_it); } } } } - const VkDescriptorSetAndBindingMappingEXT* mapping = - GetMapping(descriptor_meta.descriptor_set, descriptor_meta.descriptor_binding); + assert(descriptor_var.IsDescriptor()); + const VkDescriptorSetAndBindingMappingEXT* mapping = GetMapping(descriptor_var.interface_); if (!mapping) { - // TODO - handle untyped + assert(descriptor_var.interface_.IsHeap()); + + uint32_t heap_offset_id = 0; + const Type* descriptor_array = nullptr; + if (meta.access_path.pointer_type->spv_type_ == SpvType::kStruct) { + const Instruction* offset_decoration = GetMemberDecoration( + meta.access_path.pointer_type->Id(), meta.access_path.heap_offset_member_index, spv::DecorationOffsetIdEXT); + assert(offset_decoration); + heap_offset_id = offset_decoration->Word(4); + heap_offset_id = CastToUint32(heap_offset_id, block, inst_it); + + descriptor_array = + type_manager_.FindTypeById(meta.access_path.pointer_type->inst_.Operand(meta.access_path.heap_offset_member_index)); + assert(descriptor_array->IsArray()); + } else { + assert(meta.access_path.pointer_type->IsArray()); + descriptor_array = meta.access_path.pointer_type; + heap_offset_id = type_manager_.GetConstantZeroUint32().Id(); + } + + const uint32_t array_stride_dec = GetDecoration(descriptor_array->Id(), spv::DecorationArrayStrideIdEXT)->Word(3); + const Constant* array_stride = type_manager_.FindConstantById(array_stride_dec); + const uint32_t array_stride_id = CastToUint32(array_stride->Id(), block, inst_it); // might be int32 + + const uint32_t function_def = GetLinkFunctionId(UNTYPED); + + block.CreateInstruction(spv::OpFunctionCall, + {bool_type, function_result, function_def, inst_position_id, heap_offset_id, array_stride_id, + descriptor_index_id, is_sampler_id}, + inst_it); } else if (mapping->source == VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_CONSTANT_OFFSET_EXT) { const VkDescriptorMappingSourceConstantOffsetEXT& map_data = mapping->sourceData.constantOffset; @@ -206,10 +244,10 @@ module_.need_log_error_ = true; // If there is a sampler, we have another descriptor at this spot we need to validate - if (!is_sampler && meta.HasSampler()) { + if (!is_seperate_sampler && meta.access_path.HasSampler()) { const uint32_t valid_image = function_result; uint32_t valid_sampler = 0; - if (meta.is_combined_image_sampler) { + if (meta.access_path.is_combined_image_sampler) { assert(mapping); // not allowed with untyped pointers valid_sampler = CreateFunctionCallCombinedSampler(block, inst_it, meta, *mapping, descriptor_index_id); } else { @@ -298,187 +336,9 @@ } bool DescriptorHeapPass::RequiresInstrumentation(const Function& function, const Instruction& inst, InstructionMeta& meta) { - const spv::Op opcode = (spv::Op)inst.Opcode(); - - const Instruction* sampler_load_inst = nullptr; - if (opcode == spv::OpAtomicLoad || opcode == spv::OpAtomicStore || opcode == spv::OpAtomicExchange) { - // Image Atomics - const Instruction* image_texel_ptr_inst = function.FindInstruction(inst.Operand(0)); - if (!image_texel_ptr_inst || image_texel_ptr_inst->Opcode() != spv::OpImageTexelPointer) { - return false; - } - - const Variable* variable = nullptr; - const Instruction* access_chain_inst = function.FindInstruction(image_texel_ptr_inst->Operand(0)); - if (access_chain_inst && access_chain_inst->IsNonPtrAccessChain()) { - variable = type_manager_.FindVariableById(access_chain_inst->Operand(0)); - } else { - // if no array, will point right to a variable - variable = type_manager_.FindVariableById(image_texel_ptr_inst->Operand(0)); - } - - if (!variable) { - return false; - } - meta.resource.var_inst = &variable->inst_; - - const Type* pointer_type = variable->PointerType(type_manager_); - if (!pointer_type) { - module_.InternalError(Name(), "Pointer type not found"); - return false; - } - - const bool non_empty_access_chain = access_chain_inst && access_chain_inst->Length() >= 5; - if (pointer_type->IsArray() && non_empty_access_chain) { - meta.resource.descriptor_index_id = access_chain_inst->Operand(1); - } else { - // There is no array of this descriptor, so we essentially have an array of 1 - meta.resource.descriptor_index_id = type_manager_.GetConstantZeroUint32().Id(); - } - } else if (IsValueIn(opcode, {spv::OpLoad, spv::OpStore, spv::OpCooperativeMatrixLoadKHR, spv::OpCooperativeMatrixStoreKHR}) || - AtomicOperation(opcode)) { - // Buffer and Buffer Atomics and Storage Images - - const AccessPath access_path = type_manager_.BuildAccessPath(function, inst); - if (!access_path.IsValid()) { - return false; - } - meta.resource.var_inst = &access_path.variable->inst_; - - const uint32_t storage_class = access_path.variable->StorageClass(); - if (storage_class == spv::StorageClassUniformConstant) { - // TODO - Need to add Storage Image support - return false; - } - if (storage_class != spv::StorageClassUniform && storage_class != spv::StorageClassStorageBuffer) { - return false; // Prevents things like Push Constants - } - - const Type* pointer_type = access_path.variable->PointerType(type_manager_); - if (!pointer_type) { - module_.InternalError(Name(), "Pointer type not found"); - return false; - } - - if (pointer_type->IsArray()) { - meta.resource.descriptor_index_id = access_path.DescriptorIndexId(); - } else { - // There is no array of this descriptor, so we essentially have an array of 1 - meta.resource.descriptor_index_id = type_manager_.GetConstantZeroUint32().Id(); - } - } else { - // sampled image (non-atomic) - - // Reference is not load or store, so if it isn't a image-based reference, move on - const uint32_t image_word = OpcodeImageAccessPosition(opcode); - if (image_word == 0) { - return false; - } - - // Things that have an OpImage (in OpcodeImageAccessPosition) but we don't want to handle - if (opcode == spv::OpImageRead || opcode == spv::OpImageWrite) { - return false; // Storage Images are handled at OpLoad - } else if (opcode == spv::OpImageTexelPointer) { - return false; // atomics are handled separately - } else if (opcode == spv::OpImage) { - return false; // Don't deal with the access directly - } - - meta.image_inst = function.FindInstruction(inst.Word(image_word)); - const Instruction* load_inst = meta.image_inst; - while (load_inst && (load_inst->Opcode() == spv::OpSampledImage || load_inst->Opcode() == spv::OpImage || - load_inst->Opcode() == spv::OpCopyObject)) { - const uint32_t load_operand = load_inst->Operand(0); - load_inst = function.FindInstruction(load_operand); - - if (!load_inst) { - assert(type_manager_.IsUndef(load_operand)); - return false; // - } else if (load_inst->Opcode() == spv::OpSampledImage) { - sampler_load_inst = function.FindInstruction(load_inst->Operand(1)); - } - } - - if (!sampler_load_inst && meta.image_inst->Opcode() == spv::OpSampledImage) { - sampler_load_inst = function.FindInstruction(meta.image_inst->Operand(1)); - } - - // If we can't find a seperate sampler, and non sampled images are check elsewhere - // we know this is actually a combined image sampler - meta.is_combined_image_sampler = sampler_load_inst == nullptr; - - if (!load_inst || load_inst->Opcode() != spv::OpLoad) { - return false; // TODO: Handle additional possibilities? - } - - meta.resource.var_inst = function.FindInstruction(load_inst->Operand(0)); - if (!meta.resource.var_inst) { - // can be a global variable - const Variable* global_var = type_manager_.FindVariableById(load_inst->Operand(0)); - meta.resource.var_inst = global_var ? &global_var->inst_ : nullptr; - } - if (!meta.resource.var_inst || - (!meta.resource.var_inst->IsNonPtrAccessChain() && meta.resource.var_inst->Opcode() != spv::OpVariable)) { - return false; - } - - if (meta.resource.var_inst->IsNonPtrAccessChain()) { - meta.resource.descriptor_index_id = meta.resource.var_inst->Operand(1); - - if (meta.resource.var_inst->Length() > 5) { - module_.InternalError(Name(), "OpAccessChain has more than 1 indexes"); - return false; - } - - const Variable* variable = type_manager_.FindVariableById(meta.resource.var_inst->Operand(0)); - if (!variable) { - module_.InternalError(Name(), "OpAccessChain base is not a variable"); - return false; - } - meta.resource.var_inst = &variable->inst_; - } else { - meta.resource.descriptor_index_id = type_manager_.GetConstantZeroUint32().Id(); - } - } - - assert(meta.resource.var_inst); - uint32_t variable_id = meta.resource.var_inst->ResultId(); - GetDescriptorSetAndBinding(variable_id, meta.resource.descriptor_set, meta.resource.descriptor_binding); - - // When using a SAMPLED_IMAGE and SAMPLER, they are accessed together so we need check for 2 descriptors at the same time - // TODO - This is currently 95% the same logic as above, find a way to combine it - if (sampler_load_inst && sampler_load_inst->Opcode() == spv::OpLoad) { - meta.sampler.var_inst = function.FindInstruction(sampler_load_inst->Operand(0)); - if (!meta.sampler.var_inst) { - // can be a global variable - const Variable* global_var = type_manager_.FindVariableById(sampler_load_inst->Operand(0)); - meta.sampler.var_inst = global_var ? &global_var->inst_ : nullptr; - } - if (!meta.sampler.var_inst || - (!meta.sampler.var_inst->IsNonPtrAccessChain() && meta.sampler.var_inst->Opcode() != spv::OpVariable)) { - return false; - } - - if (meta.sampler.var_inst->IsNonPtrAccessChain()) { - meta.sampler.descriptor_index_id = meta.sampler.var_inst->Operand(1); - - if (meta.sampler.var_inst->Length() > 5) { - module_.InternalError(Name(), "Sampler OpAccessChain has more than 1 indexes"); - return false; - } - - const Variable* variable = type_manager_.FindVariableById(meta.sampler.var_inst->Operand(0)); - if (!variable) { - module_.InternalError(Name(), "Sampler OpAccessChain base is not a variable"); - return false; - } - meta.sampler.var_inst = &variable->inst_; - } else { - meta.sampler.descriptor_index_id = type_manager_.GetConstantZeroUint32().Id(); - } - - variable_id = meta.sampler.var_inst->ResultId(); - GetDescriptorSetAndBinding(variable_id, meta.sampler.descriptor_set, meta.sampler.descriptor_binding); + meta.access_path = type_manager_.BuildAccessPath(function, inst); + if (!meta.access_path.IsValid() || !meta.access_path.variable->IsDescriptor()) { + return false; } meta.target_instruction = &inst; @@ -520,7 +380,7 @@ if (!module_.settings_.safe_mode) { CreateFunctionCall(current_block, &inst_it, meta, false); // This is just a dumb hack around iterators, for samplers we call a second function - if (meta.HasSampler()) { + if (meta.access_path.HasSampler()) { inst_it++; } } else {
diff --git a/layers/gpuav/spirv/descriptor_heap_pass.h b/layers/gpuav/spirv/descriptor_heap_pass.h index 897fb94..1227197 100644 --- a/layers/gpuav/spirv/descriptor_heap_pass.h +++ b/layers/gpuav/spirv/descriptor_heap_pass.h
@@ -15,6 +15,7 @@ #pragma once #include <stdint.h> +#include "type_manager.h" #include "pass.h" struct VkDescriptorSetAndBindingMappingEXT; @@ -22,6 +23,8 @@ namespace gpuav { namespace spirv { +struct DescriptorInterface; + class DescriptorHeapPass : public Pass { public: DescriptorHeapPass(Module& module); @@ -30,25 +33,10 @@ void PrintDebugInfo() const final; private: - struct DescriptorMeta { - const Instruction* var_inst = nullptr; - uint32_t descriptor_set = 0; - uint32_t descriptor_binding = 0; - uint32_t descriptor_index_id = 0; - }; - struct InstructionMeta { const Instruction* target_instruction = nullptr; - DescriptorMeta resource; - DescriptorMeta sampler; - - bool is_combined_image_sampler = false; - - // Used to move OpSampledImage into block we access it - const Instruction* image_inst = nullptr; - - bool HasSampler() const { return sampler.var_inst != nullptr || is_combined_image_sampler; } + AccessPath access_path; }; bool RequiresInstrumentation(const Function& function, const Instruction& inst, InstructionMeta& meta); @@ -57,7 +45,7 @@ const VkDescriptorSetAndBindingMappingEXT& mapping, const uint32_t descriptor_index_id); - const VkDescriptorSetAndBindingMappingEXT* GetMapping(uint32_t descriptor_set, uint32_t descriptor_binding); + const VkDescriptorSetAndBindingMappingEXT* GetMapping(const DescriptorInterface& interface) const; // < original ID, new CopyObject ID > vvl::unordered_map<uint32_t, uint32_t> copy_object_map_; @@ -72,7 +60,8 @@ MAPPING_PUSH_DATA = 5, MAPPING_PUSH_ADDRESS = 6, MAPPING_INDIRECT_ADDRESS = 7, - FUNC_COUNT = 8, + UNTYPED = 8, + FUNC_COUNT = 9, }; uint32_t link_function_id_[FUNC_COUNT]{}; uint32_t GetLinkFunctionId(const FunctionNames func_name);
diff --git a/layers/gpuav/spirv/descriptor_indexing_oob_pass.cpp b/layers/gpuav/spirv/descriptor_indexing_oob_pass.cpp index 1d215da..b94a45e 100644 --- a/layers/gpuav/spirv/descriptor_indexing_oob_pass.cpp +++ b/layers/gpuav/spirv/descriptor_indexing_oob_pass.cpp
@@ -14,7 +14,6 @@ */ #include "descriptor_indexing_oob_pass.h" -#include "containers/container_utils.h" #include "link.h" #include "module.h" #include <spirv/unified1/spirv.hpp> @@ -52,11 +51,12 @@ } uint32_t DescriptorIndexingOOBPass::CreateFunctionCall(BasicBlock& block, InstructionIt* inst_it, const InstructionMeta& meta) { - const Constant& set_constant = type_manager_.GetConstantUInt32(meta.descriptor_set); - const Constant& binding_constant = type_manager_.GetConstantUInt32(meta.descriptor_binding); - const uint32_t descriptor_index_id = CastToUint32(meta.descriptor_index_id, block, inst_it); // might be int32 + const DescriptorInterface& interface = meta.access_path.variable->interface_; + const Constant& set_constant = type_manager_.GetConstantUInt32(interface.set); + const Constant& binding_constant = type_manager_.GetConstantUInt32(interface.binding); + const uint32_t descriptor_index_id = CastToUint32(meta.access_path.descriptor_index_id, block, inst_it); // might be int32 - if (meta.image_inst) { + if (meta.access_path.image_load_inst) { const uint32_t opcode = meta.target_instruction->Opcode(); if (opcode != spv::OpImageRead && opcode != spv::OpImageFetch && opcode != spv::OpImageWrite) { // if not a direct read/write/fetch, will be a OpSampledImage @@ -78,14 +78,14 @@ } else { copy_object_map_.emplace(image_id, copy_id); // slower, but need to guarantee it is placed after a OpSampledImage - block.function_->CreateInstruction(spv::OpCopyObject, {type_id, copy_id, image_id}, image_id); + block.function_->CreateInstruction(spv::OpCopyObject, {type_id, copy_id, image_id}, image_id, inst_it); } } } } const auto& layout_lut = module_.interface_.instrumentation_dsl.set_index_to_bindings_layout_lut; - BindingLayout binding_layout = layout_lut[meta.descriptor_set][meta.descriptor_binding]; + BindingLayout binding_layout = layout_lut[interface.set][interface.binding]; const Constant& binding_layout_size = type_manager_.GetConstantUInt32(binding_layout.count); const Constant& binding_layout_offset = type_manager_.GetConstantUInt32(binding_layout.start); @@ -93,7 +93,7 @@ const uint32_t inst_position_id = type_manager_.CreateConstantUInt32(inst_position).Id(); uint32_t function_result = module_.TakeNextId(); - const uint32_t function_def = GetLinkFunctionId(meta.is_combined_image_sampler); + const uint32_t function_def = GetLinkFunctionId(meta.access_path.is_combined_image_sampler); const uint32_t bool_type = type_manager_.GetTypeBool().Id(); block.CreateInstruction(spv::OpFunctionCall, @@ -107,16 +107,16 @@ // bool valid_image = inst_descriptor_indexing_oob(image); // bool valid_sampler = inst_descriptor_indexing_oob(sampler); // bool valid_both = image_valid && sampler_valid; - if (meta.sampler_var_inst) { + if (meta.access_path.sampler_variable) { const uint32_t valid_image = function_result; const uint32_t valid_sampler = module_.TakeNextId(); + const DescriptorInterface& sampler_interface = meta.access_path.sampler_variable->interface_; - const Constant& sampler_set_constant = type_manager_.GetConstantUInt32(meta.sampler_descriptor_set); - const Constant& sampler_binding_constant = type_manager_.GetConstantUInt32(meta.sampler_descriptor_binding); - const uint32_t sampler_descriptor_index_id = - CastToUint32(meta.sampler_descriptor_index_id, block, inst_it); // might be int32 + const Constant& sampler_set_constant = type_manager_.GetConstantUInt32(sampler_interface.set); + const Constant& sampler_binding_constant = type_manager_.GetConstantUInt32(sampler_interface.binding); + const uint32_t sampler_descriptor_index_id = CastToUint32(meta.access_path.sampler_descriptor_index_id, block, inst_it); - BindingLayout sampler_binding_layout = layout_lut[meta.sampler_descriptor_set][meta.sampler_descriptor_binding]; + BindingLayout sampler_binding_layout = layout_lut[sampler_interface.set][sampler_interface.binding]; const Constant& sampler_binding_layout_size = type_manager_.GetConstantUInt32(sampler_binding_layout.count); const Constant& sampler_binding_layout_offset = type_manager_.GetConstantUInt32(sampler_binding_layout.start); @@ -134,218 +134,42 @@ } bool DescriptorIndexingOOBPass::RequiresInstrumentation(const Function& function, const Instruction& inst, InstructionMeta& meta) { - const spv::Op opcode = (spv::Op)inst.Opcode(); - - bool array_found = false; - const Instruction* sampler_load_inst = nullptr; - if (opcode == spv::OpAtomicLoad || opcode == spv::OpAtomicStore || opcode == spv::OpAtomicExchange) { - // Image Atomics - const Instruction* image_texel_ptr_inst = function.FindInstruction(inst.Operand(0)); - if (!image_texel_ptr_inst || image_texel_ptr_inst->Opcode() != spv::OpImageTexelPointer) { - return false; - } - - const Variable* variable = nullptr; - const Instruction* access_chain_inst = function.FindInstruction(image_texel_ptr_inst->Operand(0)); - if (access_chain_inst && access_chain_inst->IsNonPtrAccessChain()) { - variable = type_manager_.FindVariableById(access_chain_inst->Operand(0)); - } else { - // if no array, will point right to a variable - variable = type_manager_.FindVariableById(image_texel_ptr_inst->Operand(0)); - } - - if (!variable) { - return false; - } - meta.var_inst = &variable->inst_; - - const Type* pointer_type = variable->PointerType(type_manager_); - if (!pointer_type) { - module_.InternalError(Name(), "Pointer type not found"); - return false; - } - - const bool non_empty_access_chain = access_chain_inst && access_chain_inst->Length() >= 5; - if (pointer_type->IsArray() && non_empty_access_chain) { - array_found = true; - meta.descriptor_index_id = access_chain_inst->Operand(1); - } else { - // There is no array of this descriptor, so we essentially have an array of 1 - meta.descriptor_index_id = type_manager_.GetConstantZeroUint32().Id(); - } - } else if (IsValueIn(opcode, {spv::OpLoad, spv::OpStore, spv::OpCooperativeMatrixLoadKHR, spv::OpCooperativeMatrixStoreKHR}) || - AtomicOperation(opcode)) { - // Buffer and Buffer Atomics and Storage Images - - const AccessPath access_path = type_manager_.BuildAccessPath(function, inst); - if (!access_path.IsValid()) { - return false; - } - meta.var_inst = &access_path.variable->inst_; - - const uint32_t storage_class = access_path.variable->StorageClass(); - if (storage_class == spv::StorageClassUniformConstant) { - // TODO - Need to add Storage Image support - return false; - } - if (storage_class != spv::StorageClassUniform && storage_class != spv::StorageClassStorageBuffer) { - return false; // Prevents things like Push Constants - } - - const Type* pointer_type = access_path.variable->PointerType(type_manager_); - if (!pointer_type) { - module_.InternalError(Name(), "Pointer type not found"); - return false; - } - - if (pointer_type->IsArray()) { - array_found = true; - meta.descriptor_index_id = access_path.DescriptorIndexId(); - } else { - // There is no array of this descriptor, so we essentially have an array of 1 - meta.descriptor_index_id = type_manager_.GetConstantZeroUint32().Id(); - } - } else { - // sampled image (non-atomic) - - // Reference is not load or store, so if it isn't a image-based reference, move on - const uint32_t image_word = OpcodeImageAccessPosition(opcode); - if (image_word == 0) { - return false; - } - - // Things that have an OpImage (in OpcodeImageAccessPosition) but we don't want to handle - if (opcode == spv::OpImageRead || opcode == spv::OpImageWrite) { - return false; // Storage Images are handled at OpLoad - } else if (opcode == spv::OpImageTexelPointer) { - return false; // atomics are handled separately - } else if (opcode == spv::OpImage) { - return false; // Don't deal with the access directly - } - - meta.image_inst = function.FindInstruction(inst.Word(image_word)); - const Instruction* load_inst = meta.image_inst; - while (load_inst && (load_inst->Opcode() == spv::OpSampledImage || load_inst->Opcode() == spv::OpImage || - load_inst->Opcode() == spv::OpCopyObject)) { - const uint32_t load_operand = load_inst->Operand(0); - load_inst = function.FindInstruction(load_operand); - - if (!load_inst) { - assert(type_manager_.IsUndef(load_operand)); - return false; // - } else if (load_inst->Opcode() == spv::OpSampledImage) { - sampler_load_inst = function.FindInstruction(load_inst->Operand(1)); - } - } - - // If we can't find a seperate sampler, and non sampled images are check elsewhere, we know this is actually a combined - // image sampler - meta.is_combined_image_sampler = sampler_load_inst == nullptr; - - if (!load_inst || load_inst->Opcode() != spv::OpLoad) { - return false; // TODO: Handle additional possibilities? - } - - meta.var_inst = function.FindInstruction(load_inst->Operand(0)); - if (!meta.var_inst) { - // can be a global variable - const Variable* global_var = type_manager_.FindVariableById(load_inst->Operand(0)); - meta.var_inst = global_var ? &global_var->inst_ : nullptr; - } - if (!meta.var_inst || (!meta.var_inst->IsNonPtrAccessChain() && meta.var_inst->Opcode() != spv::OpVariable)) { - return false; - } - - if (meta.var_inst->IsNonPtrAccessChain()) { - array_found = true; - meta.descriptor_index_id = meta.var_inst->Operand(1); - - if (meta.var_inst->Length() > 5) { - module_.InternalError(Name(), "OpAccessChain has more than 1 indexes"); - return false; - } - - const Variable* variable = type_manager_.FindVariableById(meta.var_inst->Operand(0)); - if (!variable) { - module_.InternalError(Name(), "OpAccessChain base is not a variable"); - return false; - } - meta.var_inst = &variable->inst_; - } else { - meta.descriptor_index_id = type_manager_.GetConstantZeroUint32().Id(); - } - } - - // guaranteed to be valid already, save compiler time optimizing the check out - if (!array_found && !module_.has_bindless_descriptors_) { + meta.access_path = type_manager_.BuildAccessPath(function, inst); + if (!meta.access_path.IsValid() || !meta.access_path.variable->IsDescriptor()) { return false; } - assert(meta.var_inst); - uint32_t variable_id = meta.var_inst->ResultId(); - GetDescriptorSetAndBinding(variable_id, meta.descriptor_set, meta.descriptor_binding); + // guaranteed to be valid already, save compiler time optimizing the check out + if (!meta.access_path.pointer_type->IsArray() && !module_.has_bindless_descriptors_) { + return false; + } - if (meta.descriptor_set >= glsl::kDebugInputBindlessMaxDescSets) { + if (meta.access_path.variable->interface_.set >= glsl::kDebugInputBindlessMaxDescSets) { module_.InternalWarning(Name(), "Tried to use a descriptor slot over the current max limit"); return false; } if (!module_.settings_.safe_mode) { + uint32_t variable_id = meta.access_path.variable->Id(); auto variable_found_it = block_instrumented_table_.find(variable_id); if (variable_found_it == block_instrumented_table_.end()) { - block_instrumented_table_[variable_id] = {meta.descriptor_index_id}; + block_instrumented_table_[variable_id] = {meta.access_path.descriptor_index_id}; } else { vvl::unordered_set<uint32_t>& descriptor_index_set = variable_found_it->second; - if (descriptor_index_set.find(meta.descriptor_index_id) != descriptor_index_set.end()) { + if (descriptor_index_set.find(meta.access_path.descriptor_index_id) != descriptor_index_set.end()) { return false; // Already instrumented, can skip } else { - descriptor_index_set.emplace(meta.descriptor_index_id); + descriptor_index_set.emplace(meta.access_path.descriptor_index_id); } } } - // When using a SAMPLED_IMAGE and SAMPLER, they are accessed together so we need check for 2 descriptors at the same time - // TODO - This is currently 95% the same logic as above, find a way to combine it - if (sampler_load_inst && sampler_load_inst->Opcode() == spv::OpLoad) { - meta.sampler_var_inst = function.FindInstruction(sampler_load_inst->Operand(0)); - if (!meta.sampler_var_inst) { - // can be a global variable - const Variable* global_var = type_manager_.FindVariableById(sampler_load_inst->Operand(0)); - meta.sampler_var_inst = global_var ? &global_var->inst_ : nullptr; - } - if (!meta.sampler_var_inst || - (!meta.sampler_var_inst->IsNonPtrAccessChain() && meta.sampler_var_inst->Opcode() != spv::OpVariable)) { - return false; - } - - if (meta.sampler_var_inst->IsNonPtrAccessChain()) { - array_found = true; - meta.sampler_descriptor_index_id = meta.sampler_var_inst->Operand(1); - - if (meta.sampler_var_inst->Length() > 5) { - module_.InternalError(Name(), "Sampler OpAccessChain has more than 1 indexes"); - return false; - } - - const Variable* variable = type_manager_.FindVariableById(meta.sampler_var_inst->Operand(0)); - if (!variable) { - module_.InternalError(Name(), "Sampler OpAccessChain base is not a variable"); - return false; - } - meta.sampler_var_inst = &variable->inst_; - } else { - meta.sampler_descriptor_index_id = type_manager_.GetConstantZeroUint32().Id(); - } - - variable_id = meta.sampler_var_inst->ResultId(); - GetDescriptorSetAndBinding(variable_id, meta.sampler_descriptor_set, meta.sampler_descriptor_binding); - - if (meta.sampler_descriptor_set >= glsl::kDebugInputBindlessMaxDescSets) { - module_.InternalWarning(Name(), "Sampler Tried to use a descriptor slot over the current max limit"); - return false; - } + if (meta.access_path.sampler_variable && + meta.access_path.sampler_variable->interface_.set >= glsl::kDebugInputBindlessMaxDescSets) { + module_.InternalWarning(Name(), "Sampler Tried to use a descriptor slot over the current max limit"); + return false; } - // Save information to be used to make the Function + meta.target_instruction = &inst; return true; @@ -420,10 +244,11 @@ } if (!module_.settings_.safe_mode) { - const uint32_t hash_descriptor_index_id = pc_access.next_alias_id == meta.descriptor_index_id + const uint32_t hash_descriptor_index_id = pc_access.next_alias_id == meta.access_path.descriptor_index_id ? pc_access.descriptor_index_id - : meta.descriptor_index_id; - uint32_t hash_content[3] = {meta.descriptor_set, meta.descriptor_binding, hash_descriptor_index_id}; + : meta.access_path.descriptor_index_id; + uint32_t hash_content[3] = {meta.access_path.variable->interface_.set, + meta.access_path.variable->interface_.binding, hash_descriptor_index_id}; const uint32_t hash = hash_util::Hash32(hash_content, sizeof(uint32_t) * 3); if (function_duplicate_tracker.FindAndUpdate(block_duplicate_tracker, hash)) { continue; // duplicate detected
diff --git a/layers/gpuav/spirv/descriptor_indexing_oob_pass.h b/layers/gpuav/spirv/descriptor_indexing_oob_pass.h index 957c306..2c2a8b9 100644 --- a/layers/gpuav/spirv/descriptor_indexing_oob_pass.h +++ b/layers/gpuav/spirv/descriptor_indexing_oob_pass.h
@@ -1,4 +1,4 @@ -/* Copyright (c) 2024-2025 LunarG, Inc. +/* Copyright (c) 2024-2026 LunarG, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,6 +15,7 @@ #pragma once #include <stdint.h> +#include "type_manager.h" #include "pass.h" namespace gpuav { @@ -34,18 +35,7 @@ struct InstructionMeta { const Instruction* target_instruction = nullptr; - const Instruction* var_inst = nullptr; - const Instruction* image_inst = nullptr; - uint32_t descriptor_set = 0; - uint32_t descriptor_binding = 0; - uint32_t descriptor_index_id = 0; - bool is_combined_image_sampler = false; - - // Duplicate values if dealing with SAMPLED_IMAGE and SAMPLER together - const Instruction* sampler_var_inst = nullptr; - uint32_t sampler_descriptor_set = 0; - uint32_t sampler_descriptor_binding = 0; - uint32_t sampler_descriptor_index_id = 0; + AccessPath access_path; }; bool RequiresInstrumentation(const Function& function, const Instruction& inst, InstructionMeta& meta);
diff --git a/layers/gpuav/spirv/function_basic_block.cpp b/layers/gpuav/spirv/function_basic_block.cpp index faec7e5..b08bb9f 100644 --- a/layers/gpuav/spirv/function_basic_block.cpp +++ b/layers/gpuav/spirv/function_basic_block.cpp
@@ -129,12 +129,15 @@ return (it == inst_map_.end()) ? nullptr : it->second; } -void Function::CreateInstruction(spv::Op opcode, const std::vector<uint32_t>& words, uint32_t id) { +void Function::CreateInstruction(spv::Op opcode, const std::vector<uint32_t>& words, uint32_t id, InstructionIt* out_inst_it) { for (auto& block : blocks_) { for (auto inst_it = block->instructions_.begin(); inst_it != block->instructions_.end(); ++inst_it) { if ((*inst_it)->ResultId() == id) { inst_it++; // insert after block->CreateInstruction(opcode, words, &inst_it); + if (out_inst_it) { + *out_inst_it = inst_it; + } return; } }
diff --git a/layers/gpuav/spirv/function_basic_block.h b/layers/gpuav/spirv/function_basic_block.h index e1d3a07..6c31432 100644 --- a/layers/gpuav/spirv/function_basic_block.h +++ b/layers/gpuav/spirv/function_basic_block.h
@@ -120,7 +120,7 @@ // A slower version of BasicBlock::CreateInstruction() that will search the entire function for |id| and then inject the // instruction after. Only to be used if you need to suddenly walk back to find an instruction, but normally instructions should // be added as you go forward only. - void CreateInstruction(spv::Op opcode, const std::vector<uint32_t>& words, uint32_t id); + void CreateInstruction(spv::Op opcode, const std::vector<uint32_t>& words, uint32_t id, InstructionIt* out_inst_it); // This is the uvec4 most consumers will need uint32_t stage_info_id_ = 0;
diff --git a/layers/gpuav/spirv/mesh_shading_pass.cpp b/layers/gpuav/spirv/mesh_shading_pass.cpp index 6531130..968a1e0 100644 --- a/layers/gpuav/spirv/mesh_shading_pass.cpp +++ b/layers/gpuav/spirv/mesh_shading_pass.cpp
@@ -72,7 +72,7 @@ meta.function_id = SET_MESH_OUTPUT; return true; } else if (guard_all_task_payloads_ && (IsValueIn(opcode, {spv::OpLoad, spv::OpStore}) || AtomicOperation(opcode))) { - const AccessPath access_path = type_manager_.BuildAccessPath(function, inst); + const AccessPath access_path = type_manager_.BuildAccessPath(function, inst, true); if (!access_path.IsValid()) { return false; } else if (access_path.variable->StorageClass() != spv::StorageClassTaskPayloadWorkgroupEXT) {
diff --git a/layers/gpuav/spirv/module.cpp b/layers/gpuav/spirv/module.cpp index c454134..dba2e50 100644 --- a/layers/gpuav/spirv/module.cpp +++ b/layers/gpuav/spirv/module.cpp
@@ -16,6 +16,7 @@ #include "module.h" #include <cassert> #include <spirv/unified1/spirv.hpp> +#include "containers/container_utils.h" #include "containers/custom_containers.h" #include "containers/limits.h" #include "function_basic_block.h" @@ -115,6 +116,7 @@ types_values_constants_.emplace_back(std::move(new_inst)); break; case spv::OpMemberDecorate: + case spv::OpMemberDecorateIdEXT: case spv::OpDecorationGroup: case spv::OpGroupDecorate: case spv::OpGroupMemberDecorate: @@ -155,7 +157,8 @@ case spv::OpSpecConstantComposite: case spv::OpConstant: case spv::OpConstantNull: - case spv::OpConstantComposite: { + case spv::OpConstantComposite: + case spv::OpConstantSizeOfEXT: { const Type* type = type_manager_.FindTypeById(new_inst->TypeId()); if (opcode == spv::OpSpecConstant || opcode == spv::OpSpecConstantComposite) { SetSpecConstantValue(new_inst.get(), *type, id_to_spec_id); @@ -163,7 +166,8 @@ type_manager_.AddConstant(std::move(new_inst), *type); break; } - case spv::OpVariable: { + case spv::OpVariable: + case spv::OpUntypedVariableKHR: { const Type* type = type_manager_.FindTypeById(new_inst->TypeId()); const Variable& new_var = type_manager_.AddVariable(std::move(new_inst), *type); @@ -171,8 +175,9 @@ spv::StorageClass storage_class = new_var.StorageClass(); // These are the only storage classes that interface with a descriptor // see vkspec.html#interfaces-resources-descset - if (storage_class == spv::StorageClassUniform || storage_class == spv::StorageClassUniformConstant || - storage_class == spv::StorageClassStorageBuffer) { + if (opcode == spv::OpVariable && + IsValueIn(storage_class, + {spv::StorageClassUniform, spv::StorageClassUniformConstant, spv::StorageClassStorageBuffer})) { const Type* ptr_type = new_var.PointerType(type_manager_); // The shader will also have OpCapability RuntimeDescriptorArray if (ptr_type->spv_type_ == SpvType::kRuntimeArray) { @@ -183,11 +188,6 @@ break; } - case spv::OpUntypedVariableKHR: { - type_manager_.AddUntypedVariable(new_inst->ResultId()); - types_values_constants_.emplace_back(std::move(new_inst)); - break; - } case spv::OpSpecConstantOp: { const Type* type = type_manager_.FindTypeById(new_inst->TypeId()); // If folded, we drop the |new_inst| as we will add it inside the function
diff --git a/layers/gpuav/spirv/pass.cpp b/layers/gpuav/spirv/pass.cpp index 8fc89de..c26d5fc 100644 --- a/layers/gpuav/spirv/pass.cpp +++ b/layers/gpuav/spirv/pass.cpp
@@ -227,7 +227,8 @@ const Instruction* Pass::GetDecoration(uint32_t id, spv::Decoration decoration) const { for (const auto& annotation : module_.annotations_) { - if (annotation->Opcode() == spv::OpDecorate && annotation->Word(1) == id && + const uint32_t opcode = annotation->Opcode(); + if ((opcode == spv::OpDecorate || opcode == spv::OpDecorateId) && annotation->Word(1) == id && spv::Decoration(annotation->Word(2)) == decoration) { return annotation.get(); } @@ -237,26 +238,15 @@ const Instruction* Pass::GetMemberDecoration(uint32_t id, uint32_t member_index, spv::Decoration decoration) const { for (const auto& annotation : module_.annotations_) { - if (annotation->Opcode() == spv::OpMemberDecorate && annotation->Word(1) == id && annotation->Word(2) == member_index && - spv::Decoration(annotation->Word(3)) == decoration) { + const uint32_t opcode = annotation->Opcode(); + if ((opcode == spv::OpMemberDecorate || opcode == spv::OpMemberDecorateIdEXT) && annotation->Word(1) == id && + annotation->Word(2) == member_index && spv::Decoration(annotation->Word(3)) == decoration) { return annotation.get(); } } return nullptr; } -void Pass::GetDescriptorSetAndBinding(uint32_t variable_id, uint32_t& out_set, uint32_t& out_binding) const { - for (const auto& annotation : module_.annotations_) { - if (annotation->Opcode() == spv::OpDecorate && annotation->Word(1) == variable_id) { - if (annotation->Word(2) == spv::DecorationDescriptorSet) { - out_set = annotation->Word(3); - } else if (annotation->Word(2) == spv::DecorationBinding) { - out_binding = annotation->Word(3); - } - } - } -} - // In an ideal world, this would be baked into the Type class when we construct it. The core issue is OpTypeMatrix size can be // different depending where it is used. Because of this, we need to have a higher level view what is going on in order to correctly // figure out the size of a given type. @@ -748,16 +738,7 @@ // Generate code to convert integer id to 32bit, if needed. uint32_t Pass::ConvertTo32(uint32_t id, BasicBlock& block, InstructionIt* inst_it) const { // Find type doing the indexing into the access chain - const Type* type = nullptr; - const Constant* constant = type_manager_.FindConstantById(id); - if (constant) { - type = &constant->type_; - } else { - const Instruction* inst = block.function_->FindInstruction(id); - if (inst) { - type = type_manager_.FindTypeById(inst->TypeId()); - } - } + const Type* type = type_manager_.FindTypeGlobal(*block.function_, id); if (!type) { return id; } @@ -778,20 +759,12 @@ } // Generate code to cast integer it to 32bit unsigned, if needed. +// TODO - Have a fast path for int32 to uint32 uint32_t Pass::CastToUint32(uint32_t id, BasicBlock& block, InstructionIt* inst_it) const { // Convert value to 32-bit if necessary uint32_t int32_id = ConvertTo32(id, block, inst_it); - const Type* type = nullptr; - const Constant* constant = type_manager_.FindConstantById(int32_id); - if (constant) { - type = &constant->type_; - } else { - const Instruction* inst = block.function_->FindInstruction(int32_id); - if (inst) { - type = type_manager_.FindTypeById(inst->TypeId()); - } - } + const Type* type = type_manager_.FindTypeGlobal(*block.function_, int32_id); if (!type) { return int32_id; }
diff --git a/layers/gpuav/spirv/pass.h b/layers/gpuav/spirv/pass.h index 448eb82..172757d 100644 --- a/layers/gpuav/spirv/pass.h +++ b/layers/gpuav/spirv/pass.h
@@ -63,7 +63,6 @@ const Instruction* GetDecoration(uint32_t id, spv::Decoration decoration) const; const Instruction* GetMemberDecoration(uint32_t id, uint32_t member_index, spv::Decoration decoration) const; - void GetDescriptorSetAndBinding(uint32_t variable_id, uint32_t& out_set, uint32_t& out_binding) const; uint32_t FindTypeByteSize(uint32_t type_id, uint32_t matrix_stride = 0, bool col_major = false, bool in_matrix = false) const; // Currently only used in the General Buffer OOB check, put here so it can be adapted for general use if needed
diff --git a/layers/gpuav/spirv/post_process_descriptor_indexing_pass.cpp b/layers/gpuav/spirv/post_process_descriptor_indexing_pass.cpp index 2f3463b..97e64e2 100644 --- a/layers/gpuav/spirv/post_process_descriptor_indexing_pass.cpp +++ b/layers/gpuav/spirv/post_process_descriptor_indexing_pass.cpp
@@ -15,10 +15,10 @@ #include "post_process_descriptor_indexing_pass.h" -#include "containers/container_utils.h" #include "module.h" #include "generated/gpuav_offline_spirv.h" #include "gpuav/shaders/gpuav_shaders_constants.h" +#include "type_manager.h" #include "utils/hash_util.h" #include <iostream> @@ -40,14 +40,15 @@ uint32_t PostProcessDescriptorIndexingPass::GetLinkFunctionId() { return GetLinkFunction(link_function_id_, kOfflineFunction); } void PostProcessDescriptorIndexingPass::CreateFunctionCall(BasicBlock& block, InstructionIt* inst_it, const InstructionMeta& meta) { - const Constant& set_constant = type_manager_.GetConstantUInt32(meta.descriptor_set); - const Constant& binding_constant = type_manager_.GetConstantUInt32(meta.descriptor_binding); - const uint32_t descriptor_index_id = CastToUint32(meta.descriptor_index_id, block, inst_it); // might be int32 + const DescriptorInterface& interface = meta.access_path.variable->interface_; + const Constant& set_constant = type_manager_.GetConstantUInt32(interface.set); + const Constant& binding_constant = type_manager_.GetConstantUInt32(interface.binding); + const uint32_t descriptor_index_id = CastToUint32(meta.access_path.descriptor_index_id, block, inst_it); // might be int32 const auto& layout_lut = module_.interface_.instrumentation_dsl.set_index_to_bindings_layout_lut; - BindingLayout binding_layout = layout_lut[meta.descriptor_set][meta.descriptor_binding]; + BindingLayout binding_layout = layout_lut[interface.set][interface.binding]; const Constant& binding_layout_offset = type_manager_.GetConstantUInt32(binding_layout.start); - const Constant& variable_id_constant = type_manager_.GetConstantUInt32(meta.variable_id); + const Constant& variable_id_constant = type_manager_.GetConstantUInt32(meta.access_path.variable->Id()); const uint32_t inst_position = meta.target_instruction->GetPositionOffset(); const uint32_t inst_position_id = type_manager_.CreateConstantUInt32(inst_position).Id(); @@ -64,84 +65,12 @@ bool PostProcessDescriptorIndexingPass::RequiresInstrumentation(const Function& function, const Instruction& inst, InstructionMeta& meta) { - const spv::Op opcode = (spv::Op)inst.Opcode(); - - const Instruction* var_inst = nullptr; - if (IsValueIn(opcode, {spv::OpLoad, spv::OpStore, spv::OpCooperativeMatrixLoadKHR, spv::OpCooperativeMatrixStoreKHR})) { - const AccessPath access_path = type_manager_.BuildAccessPath(function, inst); - if (!access_path.IsValid()) { - return false; - } - - var_inst = &access_path.variable->inst_; - - const uint32_t storage_class = access_path.variable->StorageClass(); - if (storage_class != spv::StorageClassUniform && storage_class != spv::StorageClassStorageBuffer) { - return false; - } - - const Type* pointer_type = access_path.variable->PointerType(type_manager_); - if (pointer_type->IsArray()) { - meta.descriptor_index_id = access_path.DescriptorIndexId(); - } else { - // There is no array of this descriptor, so we essentially have an array of 1 - meta.descriptor_index_id = type_manager_.GetConstantZeroUint32().Id(); - } - - } else { - // Reference is not load or store, so if it isn't a image-based reference, move on - const uint32_t image_word = OpcodeImageAccessPosition(opcode); - if (image_word == 0) { - return false; - } - if (opcode == spv::OpImageTexelPointer || opcode == spv::OpImage) { - return false; // need to test if we can support these - } - - const Instruction* load_inst = function.FindInstruction(inst.Word(image_word)); - while (load_inst && (load_inst->Opcode() == spv::OpSampledImage || load_inst->Opcode() == spv::OpImage || - load_inst->Opcode() == spv::OpCopyObject)) { - load_inst = function.FindInstruction(load_inst->Operand(0)); - } - if (!load_inst || load_inst->Opcode() != spv::OpLoad) { - return false; // TODO: Handle additional possibilities? - } - - var_inst = function.FindInstruction(load_inst->Operand(0)); - if (!var_inst) { - // can be a global variable - const Variable* global_var = type_manager_.FindVariableById(load_inst->Operand(0)); - var_inst = global_var ? &global_var->inst_ : nullptr; - } - if (!var_inst || (!var_inst->IsNonPtrAccessChain() && var_inst->Opcode() != spv::OpVariable)) { - return false; - } - - if (var_inst->IsNonPtrAccessChain()) { - meta.descriptor_index_id = var_inst->Operand(1); - - if (var_inst->Length() > 5) { - module_.InternalError(Name(), "OpAccessChain has more than 1 indexes"); - return false; - } - - const Variable* variable = type_manager_.FindVariableById(var_inst->Operand(0)); - if (!variable) { - module_.InternalError(Name(), "OpAccessChain base is not a variable"); - return false; - } - var_inst = &variable->inst_; - } else { - meta.descriptor_index_id = type_manager_.GetConstantZeroUint32().Id(); - } + meta.access_path = type_manager_.BuildAccessPath(function, inst, true); + if (!meta.access_path.IsValid() || !meta.access_path.variable->IsDescriptor()) { + return false; } - assert(var_inst); - meta.variable_id = var_inst->ResultId(); - - GetDescriptorSetAndBinding(meta.variable_id, meta.descriptor_set, meta.descriptor_binding); - - if (meta.descriptor_set >= glsl::kDebugInputBindlessMaxDescSets) { + if (meta.access_path.variable->interface_.set >= glsl::kDebugInputBindlessMaxDescSets) { module_.InternalWarning(Name(), "Tried to use a descriptor slot over the current max limit"); return false; } @@ -185,10 +114,12 @@ continue; } - const uint32_t hash_descriptor_index_id = - pc_access.next_alias_id == meta.descriptor_index_id ? pc_access.descriptor_index_id : meta.descriptor_index_id; - uint32_t hash_content[4] = {meta.descriptor_set, meta.descriptor_binding, hash_descriptor_index_id, - meta.variable_id}; + const uint32_t hash_descriptor_index_id = pc_access.next_alias_id == meta.access_path.descriptor_index_id + ? pc_access.descriptor_index_id + : meta.access_path.descriptor_index_id; + uint32_t hash_content[4] = {meta.access_path.variable->interface_.set, + meta.access_path.variable->interface_.binding, hash_descriptor_index_id, + meta.access_path.variable->Id()}; const uint32_t hash = hash_util::Hash32(hash_content, sizeof(uint32_t) * 4); if (function_duplicate_tracker.FindAndUpdate(block_duplicate_tracker, hash)) { continue; // duplicate detected
diff --git a/layers/gpuav/spirv/post_process_descriptor_indexing_pass.h b/layers/gpuav/spirv/post_process_descriptor_indexing_pass.h index 3b7fdd5..fe68cc0 100644 --- a/layers/gpuav/spirv/post_process_descriptor_indexing_pass.h +++ b/layers/gpuav/spirv/post_process_descriptor_indexing_pass.h
@@ -1,4 +1,4 @@ -/* Copyright (c) 2024-2025 LunarG, Inc. +/* Copyright (c) 2024-2026 LunarG, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,6 +15,7 @@ #pragma once #include <stdint.h> +#include "type_manager.h" #include "pass.h" namespace gpuav { @@ -35,10 +36,8 @@ // This is metadata tied to a single instruction gathered during RequiresInstrumentation() to be used later struct InstructionMeta { const Instruction* target_instruction = nullptr; - uint32_t descriptor_set = 0; - uint32_t descriptor_binding = 0; - uint32_t descriptor_index_id = 0; - uint32_t variable_id = 0; + + AccessPath access_path; }; bool RequiresInstrumentation(const Function& function, const Instruction& inst, InstructionMeta& meta);
diff --git a/layers/gpuav/spirv/shared_memory_data_race_pass.cpp b/layers/gpuav/spirv/shared_memory_data_race_pass.cpp index 388f1b7..872099a 100644 --- a/layers/gpuav/spirv/shared_memory_data_race_pass.cpp +++ b/layers/gpuav/spirv/shared_memory_data_race_pass.cpp
@@ -45,21 +45,6 @@ return GetLinkFunction(link_function_id_[meta.function_idx], kOfflineFunction[meta.function_idx]); } -// The goal of Function::FindInstruction is you should know the instruction is in the Function. -// For walking the indexes of an access chain in this pass, we want a global lookup -const Instruction* SharedMemoryDataRacePass::FindInstructionGlobal(const Function& function, uint32_t id) const { - if (auto ret = function.FindInstruction(id)) { - return ret; - } - if (auto ret = module_.type_manager_.FindConstantById(id)) { - return &ret->inst_; - } - if (auto ret = module_.type_manager_.FindVariableById(id)) { - return &ret->inst_; - } - return nullptr; -} - void SharedMemoryDataRacePass::CreateFunctionCall(const Function& function, BasicBlock& block, InstructionIt* inst_it, const InstructionMeta& meta) { const uint32_t function_def = GetLinkFunctionId(meta); @@ -92,8 +77,7 @@ const Type* coopmat_type; if (store) { const uint32_t object_id = inst.Word(2); - const Instruction* object_inst = FindInstructionGlobal(function, object_id); - coopmat_type = type_manager_.FindTypeById(object_inst->TypeId()); + coopmat_type = type_manager_.FindTypeGlobal(function, object_id); } else { coopmat_type = type_manager_.FindTypeById(inst.TypeId()); } @@ -106,8 +90,7 @@ const uint32_t ptr_id = inst.Operand(0); // works with both store and loads // get type of pointee - auto ptr_inst = FindInstructionGlobal(function, ptr_id); - const Type* ptr_type = type_manager_.FindTypeById(ptr_inst->TypeId()); + const Type* ptr_type = type_manager_.FindTypeGlobal(function, ptr_id); const Type* scalar_elem_type = type_manager_.FindChildType(*ptr_type, 0); const Type& uint32_type = type_manager_.GetTypeInt(32, false); @@ -192,7 +175,7 @@ return true; } - const AccessPath access_path = type_manager_.BuildAccessPath(function, inst); + const AccessPath access_path = type_manager_.BuildAccessPath(function, inst, true); if (!access_path.IsValid()) { return false; } else if (access_path.variable->StorageClass() != spv::StorageClassWorkgroup) { @@ -206,16 +189,14 @@ // to the variable's pointee type in case of no access chains. const Type* ptr_elem_type = type_manager_.FindChildType(*type_manager_.FindTypeById(access_path.variable->inst_.Word(1)), 0); for (auto ac : access_path.ac_list) { - auto ptr = FindInstructionGlobal(function, ac->Word(3)); - const Type* base_ptr_type = type_manager_.FindTypeById(ptr->Word(1)); + const Type* base_ptr_type = type_manager_.FindTypeGlobal(function, ac->Word(3)); // Get the base pointer pointee type. ptr_elem_type = type_manager_.FindChildType(*base_ptr_type, 0); for (uint32_t i = 4; i < ac->Length(); ++i) { uint32_t idx_id = ac->Word(i); - auto idx_inst = FindInstructionGlobal(function, idx_id); - auto idx_type = type_manager_.FindTypeById(idx_inst->Word(1)); + auto idx_type = type_manager_.FindTypeGlobal(function, idx_id); assert(idx_type->inst_.Opcode() == spv::OpTypeInt); // convert to u32 if needed if (idx_type->inst_.Word(2) != 32) {
diff --git a/layers/gpuav/spirv/shared_memory_data_race_pass.h b/layers/gpuav/spirv/shared_memory_data_race_pass.h index 1839599..c9f451e 100644 --- a/layers/gpuav/spirv/shared_memory_data_race_pass.h +++ b/layers/gpuav/spirv/shared_memory_data_race_pass.h
@@ -53,8 +53,6 @@ uint32_t GetLinkFunctionId(const InstructionMeta& meta); - const Instruction* FindInstructionGlobal(const Function& function, uint32_t id) const; - // Function IDs to link in enum FunctionNames { INIT_SHADOW = 0,
diff --git a/layers/gpuav/spirv/trace_ray_pass.cpp b/layers/gpuav/spirv/trace_ray_pass.cpp index f43b8e7..c50aa95 100644 --- a/layers/gpuav/spirv/trace_ray_pass.cpp +++ b/layers/gpuav/spirv/trace_ray_pass.cpp
@@ -24,6 +24,7 @@ #include <iostream> #include "generated/gpuav_offline_spirv.h" +#include "type_manager.h" namespace gpuav { namespace spirv { @@ -58,52 +59,26 @@ return {}; } - const AccessPath access_path = type_manager_.BuildAccessPath(function, *as_op_load_inst); + const AccessPath access_path = type_manager_.BuildAccessPath(function, *as_op_load_inst, true); if (!access_path.IsValid()) { return {}; } - const Type* descriptor_type = access_path.variable->PointerType(type_manager_); - if (!descriptor_type || descriptor_type->spv_type_ == SpvType::kRuntimeArray) { + if (access_path.pointer_type->spv_type_ == SpvType::kRuntimeArray) { return {}; // TODO - Currently we mark these as "bindless" } - const bool is_descriptor_array = descriptor_type->IsArray(); - if (is_descriptor_array && access_path.ac_list.empty()) { - return {}; // array descriptor without an access chain is invalid SPIR-V - } - - uint32_t descriptor_index_id = 0; - if (is_descriptor_array) { - // Because you can't have 2D array of descriptors, the first index of the last accessChain is the descriptor index - descriptor_index_id = access_path.DescriptorIndexId(); - } else { - // There is no array of this descriptor, so we essentially have an array of 1 - descriptor_index_id = type_manager_.GetConstantZeroUint32().Id(); - } - - uint32_t descriptor_set = 0; - uint32_t descriptor_binding = 0; - for (const auto& annotation : module_.annotations_) { - if (annotation->Opcode() == spv::OpDecorate && annotation->Word(1) == access_path.variable->Id()) { - if (annotation->Word(2) == spv::DecorationDescriptorSet) { - descriptor_set = annotation->Word(3); - } else if (annotation->Word(2) == spv::DecorationBinding) { - descriptor_binding = annotation->Word(3); - } - } - } - - if (descriptor_set >= glsl::kDebugInputBindlessMaxDescSets) { + const DescriptorInterface& interface = access_path.variable->interface_; + if (interface.set >= glsl::kDebugInputBindlessMaxDescSets) { module_.InternalWarning(Name(), "Tried to use a descriptor slot over the current max limit"); return {}; } - const Constant& desc_set_constant = type_manager_.GetConstantUInt32(descriptor_set); - const uint32_t desc_index_id = CastToUint32(descriptor_index_id, block, trace_ray_inst_it); // might be int32 + const Constant& desc_set_constant = type_manager_.GetConstantUInt32(interface.set); + const uint32_t desc_index_id = CastToUint32(access_path.descriptor_index_id, block, trace_ray_inst_it); // might be int32 const auto& layout_lut = module_.interface_.instrumentation_dsl.set_index_to_bindings_layout_lut; - BindingLayout binding_layout = layout_lut[descriptor_set][descriptor_binding]; + BindingLayout binding_layout = layout_lut[interface.set][interface.binding]; const Constant& binding_layout_offset = type_manager_.GetConstantUInt32(binding_layout.start); const uint32_t function_result = module_.TakeNextId();
diff --git a/layers/gpuav/spirv/type_manager.cpp b/layers/gpuav/spirv/type_manager.cpp index 214de9d..4ef65a8 100644 --- a/layers/gpuav/spirv/type_manager.cpp +++ b/layers/gpuav/spirv/type_manager.cpp
@@ -16,6 +16,7 @@ #include "type_manager.h" #include <cstdint> #include <spirv/unified1/spirv.hpp> +#include "containers/container_utils.h" #include "generated/spirv_grammar_helper.h" #include "module.h" @@ -37,10 +38,41 @@ return true; } +DescriptorInterface Variable::FindDescriptorInterface(const Module& module, const Instruction& inst) { + DescriptorInterface descriptor; + // Only allowed descriptor storage classes + // https://docs.vulkan.org/spec/latest/chapters/interfaces.html#interfaces-resources-storage-class-correspondence + if (IsValueIn(inst.StorageClass(), { + spv::StorageClassUniform, + spv::StorageClassUniformConstant, + spv::StorageClassStorageBuffer, + spv::StorageClassTileAttachmentQCOM, + })) { + const uint32_t variable_id = inst.ResultId(); + for (const auto& annotation : module.annotations_) { + if (annotation->Opcode() == spv::OpDecorate && annotation->Word(1) == variable_id) { + if (annotation->Word(2) == spv::DecorationDescriptorSet) { + descriptor.set = annotation->Word(3); + } else if (annotation->Word(2) == spv::DecorationBinding) { + descriptor.binding = annotation->Word(3); + } else if (annotation->Word(2) == spv::DecorationBuiltIn && annotation->Word(3) == spv::BuiltInResourceHeapEXT) { + descriptor.is_resource_heap = true; + } else if (annotation->Word(2) == spv::DecorationBuiltIn && annotation->Word(3) == spv::BuiltInSamplerHeapEXT) { + descriptor.is_sampler_heap = true; + } + } + } + } + return descriptor; +} + // return %A in: // %B = OpTypePointer Input %A // %C = OpVariable %B Input -const Type* Variable::PointerType(TypeManager& type_manager_) const { +const Type* Variable::PointerType(const TypeManager& type_manager_) const { + // If we are hitting kUntypedPointer, the logic need to get the type info either from the Base Type of the UntypedAccessChain or + // if it cares about the type, it can find it at the access type (example to help show how to getting the type + // https://godbolt.org/z/ejf1TGx8Y) assert(type_.spv_type_ == SpvType::kPointer || type_.spv_type_ == SpvType::kForwardPointer); uint32_t type_id = type_.inst_.Word(3); return type_manager_.FindTypeById(type_id); @@ -161,26 +193,6 @@ return (type == id_to_type_.end()) ? nullptr : type->second.get(); } -// It is common to have things like -// -// %uint = OpTypeInt 32 0 -// %ptr_uint = OpTypePointer StorageBuffer %uint -// %ac = OpAccessChain %ptr_uint %var %int_1 -// -// Where you have %ptr_uint and want to know it is OpTypeInt -// This function is like FindTypeById() but it will bypass the OpTypePointer for you (if it is there) -// There is also a matching Variable::PointerType() -const Type* TypeManager::FindValueTypeById(uint32_t id) const { - const Type* pointer_type = FindTypeById(id); - if (!pointer_type) { - return nullptr; - } else if (pointer_type->spv_type_ != SpvType::kPointer && pointer_type->spv_type_ != SpvType::kForwardPointer) { - return pointer_type; - } else { - return FindTypeById(pointer_type->inst_.Word(3)); - } -} - const Type* TypeManager::FindFunctionType(const Instruction& inst) const { const uint32_t inst_length = inst.Length(); for (const auto& type : function_types_) { @@ -202,6 +214,23 @@ return nullptr; } +// ONLY USE IF NEEDED! +// The goal of Function::FindInstruction is you should know the instruction is in the Function. +// For walking the indexes of an access chain in this pass, we want a global lookup +// This manily happens because the value of the index could be both a OpConstant value or loaded in the function. +const Type* TypeManager::FindTypeGlobal(const Function& function, uint32_t id) const { + if (auto ret = function.FindInstruction(id)) { + return FindTypeById(ret->TypeId()); + } + if (auto ret = module_.type_manager_.FindConstantById(id)) { + return &ret->type_; + } + if (auto ret = module_.type_manager_.FindVariableById(id)) { + return &ret->type_; + } + return nullptr; +} + const Type& TypeManager::GetTypeVoid() { if (void_type) { return *void_type; @@ -736,32 +765,208 @@ return AddConstant(std::move(new_inst), type); } -const AccessPath TypeManager::BuildAccessPath(const Function& function, const Instruction& inst) const { +static bool IsAccessInstruction(const Instruction& inst) { + const spv::Op opcode = (spv::Op)inst.Opcode(); + if (IsValueIn(opcode, {spv::OpLoad, spv::OpStore, spv::OpCooperativeMatrixLoadKHR, spv::OpCooperativeMatrixStoreKHR})) { + return true; + } else if (IsValueIn(opcode, {spv::OpImageTexelPointer, spv::OpImage})) { + // OpImageTexelPointer is for image atomics handled at the atomic instruction + // OpImage is describing an action, rather than the input to or the output from an action. + return false; + } else if (AtomicOperation(opcode)) { + return true; // any atomic + } else if (OpcodeImageAccessPosition(opcode) != 0) { + return true; // image access + } + + return false; +} + +// |ignore_image_sampler_skip| used for passes that don't care about safe_mode that want to ignore until we fix support +const AccessPath TypeManager::BuildAccessPath(const Function& function, const Instruction& inst, bool ignore_image_sampler_skip) { AccessPath path; - // |Operand 0| works for both Store/Load - const uint32_t ptr_id = inst.Operand(0); + if (!IsAccessInstruction(inst)) { + return path; + } + + const spv::Op opcode = (spv::Op)inst.Opcode(); + path.access_type = FindTypeById(inst.TypeId()); + // if it is a store, then we need to look a the type it loading + if (!path.access_type) { + if (opcode == spv::OpStore || opcode == spv::OpCooperativeMatrixStoreKHR) { + path.access_type = FindTypeGlobal(function, inst.Operand(1)); // object id + } else if (opcode == spv::OpImageWrite) { + path.access_type = FindTypeGlobal(function, inst.Operand(2)); // texel id + } else if (opcode == spv::OpAtomicStore) { + path.access_type = FindTypeGlobal(function, inst.Operand(3)); // value id + } else { + assert(false); // not being handled + } + } + assert(path.access_type); + + const bool image_sampler_access = path.access_type->spv_type_ == SpvType::kImage || + path.access_type->spv_type_ == SpvType::kSampledImage || + path.access_type->spv_type_ == SpvType::kSampler; + + // This is just loading the image handle, this alone is the not the access. + // There will be an access (OpImageWrite, OpImageSampleImplicitLod, etc) later which has the real access information + if (opcode == spv::OpLoad && image_sampler_access) { + return path; + } + + // TODO - Need to add Storage Image support (https://gitlab.khronos.org/vulkan/vulkan/-/issues/3977) + // TODO - we currently don't handle storage image/sampled/samplers in safe mode as we put a OpConstantNull in the OpPhi which + // doesn't make sense as it needs to be a OpTypeImage. The way around this will be having a null descriptor ready and point + // there in the case it is wrong + if (!ignore_image_sampler_skip && module_.settings_.safe_mode && image_sampler_access) { + return path; + } + + const Instruction* sampler_load_inst = nullptr; + uint32_t ptr_id = OpcodeImageAccessPosition(opcode); + // Basically there are 2 flows, images and non-images + const bool image_access = ptr_id != 0; + if (image_access) { + path.image_load_inst = function.FindInstruction(inst.Word(ptr_id)); + const Instruction* load_inst = path.image_load_inst; + uint32_t load_operand = 0; + while (load_inst && (load_inst->Opcode() == spv::OpSampledImage || load_inst->Opcode() == spv::OpImage || + load_inst->Opcode() == spv::OpCopyObject)) { + if (load_inst->Opcode() == spv::OpSampledImage) { + sampler_load_inst = function.FindInstruction(load_inst->Operand(1)); + } + + load_operand = load_inst->Operand(0); + load_inst = function.FindInstruction(load_operand); + } + + // Note - we never "store" an image, we only load its handle and store the "texel" data + if (!load_inst || load_inst->Opcode() != spv::OpLoad) { + // TODO - should be able to remove this check, its invalid SPIR-V + // https://gitlab.khronos.org/vulkan/vulkan/-/merge_requests/7753 + assert(IsUndef(load_operand)); + return path; + } + + path.is_combined_image_sampler = sampler_load_inst == nullptr && ImageSampleOperation(opcode); + + // From here the load should look like a non-image access + ptr_id = load_inst->Operand(0); + } else { + // |Operand 0| works for both Store/Load + ptr_id = inst.Operand(0); + } // Buffer/Image Descriptor will always have an access chains, but some cases can have direct access. // TaskPayload can be a scalar that does a direct variable access // An non-array AccelerationStructure (which uses UniformConstant storage class) path.variable = FindVariableById(ptr_id); - if (path.variable) { + const Instruction* next_access_chain = nullptr; + if (!path.variable) { + next_access_chain = function.FindInstruction(ptr_id); + + // We need to walk down possibly multiple chained OpAccessChains or OpCopyObject to get the variable + while (next_access_chain && next_access_chain->IsNonPtrAccessChain()) { + // inserting in front allows us to walk over the loop from the front + path.ac_list.insert(path.ac_list.begin(), next_access_chain); + + const uint32_t base_operand = next_access_chain->IsUntypedAccessChain() ? 1 : 0; + const uint32_t access_chain_base_id = next_access_chain->Operand(base_operand); + path.variable = FindVariableById(access_chain_base_id); + if (path.variable) { + break; // found + } + next_access_chain = function.FindInstruction(access_chain_base_id); + } + + if (next_access_chain->Opcode() == spv::OpBufferPointerEXT) { + const uint32_t buffer_pointer_id = next_access_chain->Operand(0); + // For now assume this is a 1D array into the descriptor array + // https://gitlab.khronos.org/spirv/SPIR-V/-/issues/942 + next_access_chain = function.FindInstruction(buffer_pointer_id); + assert(next_access_chain->Opcode() == spv::OpUntypedAccessChainKHR); + path.ac_list.insert(path.ac_list.begin(), next_access_chain); + const uint32_t untyped_variable_id = next_access_chain->Operand(1); + path.variable = FindVariableById(untyped_variable_id); + } else if (next_access_chain->Opcode() == spv::OpImageTexelPointer) { + // Storage Images (and image atomics) + const Instruction* access_chain_inst = function.FindInstruction(next_access_chain->Operand(0)); + if (access_chain_inst && access_chain_inst->IsNonPtrAccessChain()) { + next_access_chain = access_chain_inst; + path.ac_list.insert(path.ac_list.begin(), next_access_chain); + path.variable = FindVariableById(access_chain_inst->Operand(0)); + } else { + // if no array, will point right to a variable + path.variable = FindVariableById(next_access_chain->Operand(0)); + } + } + } + + if (!path.variable) { + // Two know spots this occur is Function Variables and PhysicalStorageBuffer access + assert((next_access_chain->Opcode() == spv::OpVariable && next_access_chain->StorageClass() == spv::StorageClassFunction) || + FindTypeById(next_access_chain->TypeId())->spv_type_ == SpvType::kPointer); + return path; // not a valid access path + } + + // Welcome to SPV_KHR_untyped_pointers soldier! + // Untyped we get the pointer type from the last access chain + // But typed, the OpVariable had it + if (next_access_chain && next_access_chain->IsUntypedAccessChain()) { + const uint32_t pointer_type_id = next_access_chain->Operand(0); + path.pointer_type = FindTypeById(pointer_type_id); + } else { + path.pointer_type = path.variable->PointerType(*this); + } + assert(path.pointer_type); + + // Everything else is just for descriptor variable access + if (!path.variable->IsDescriptor()) { return path; } - const Instruction* next_access_chain = function.FindInstruction(ptr_id); - // We need to walk down possibly multiple chained OpAccessChains or OpCopyObject to get the variable - while (next_access_chain && next_access_chain->IsNonPtrAccessChain()) { - // inserting in front allows us to walk over the loop from the front - path.ac_list.insert(path.ac_list.begin(), next_access_chain); + if (path.pointer_type->IsArray()) { + assert(next_access_chain); // no way to have an array otherwise + const uint32_t index_0_operand = next_access_chain->IsUntypedAccessChain() ? 2 : 1; + path.descriptor_index_id = next_access_chain->Operand(index_0_operand); + } else { + // There is no array of this descriptor, so we essentially have an array of 1 + path.descriptor_index_id = GetConstantZeroUint32().Id(); - const uint32_t access_chain_base_id = next_access_chain->Operand(0); - path.variable = FindVariableById(access_chain_base_id); - if (path.variable) { - break; // found + // Hack for Offset in Heaps until get better understanding + if (path.variable->interface_.IsHeap() && path.pointer_type->spv_type_ == SpvType::kStruct) { + assert(next_access_chain->IsUntypedAccessChain() && next_access_chain->Length() == 7); + // https://godbolt.org/z/hWz84zdTW - this is required to be a constant + const Constant* struct_member_index_constant = FindConstantById(next_access_chain->Operand(2)); + assert(struct_member_index_constant); + path.heap_offset_member_index = struct_member_index_constant->GetValueUint32(); + path.descriptor_index_id = next_access_chain->Operand(3); } - next_access_chain = function.FindInstruction(access_chain_base_id); + } + + // When using a SAMPLED_IMAGE and SAMPLER, they are accessed together so we need check for 2 descriptors + if (sampler_load_inst) { + assert(sampler_load_inst->Opcode() == spv::OpLoad); + + ptr_id = sampler_load_inst->Operand(0); + path.sampler_variable = FindVariableById(ptr_id); + if (path.sampler_variable) { + path.sampler_descriptor_index_id = GetConstantZeroUint32().Id(); + } else { + // descriptor array + // this is a lazy way to assume the sampler is can only be 1D and a single access chain away + next_access_chain = function.FindInstruction(ptr_id); + assert(next_access_chain->IsNonPtrAccessChain()); + + const uint32_t base_operand = next_access_chain->IsUntypedAccessChain() ? 1 : 0; + const uint32_t access_chain_base_id = next_access_chain->Operand(base_operand); + path.sampler_variable = FindVariableById(access_chain_base_id); + + const uint32_t index_0_operand = base_operand + 1; + path.sampler_descriptor_index_id = next_access_chain->Operand(index_0_operand); + } } return path; @@ -770,7 +975,7 @@ const Variable& TypeManager::AddVariable(std::unique_ptr<Instruction> new_inst, const Type& type) { const auto& inst = module_.types_values_constants_.emplace_back(std::move(new_inst)); - id_to_variable_[inst->ResultId()] = std::make_unique<Variable>(type, *inst); + id_to_variable_[inst->ResultId()] = std::make_unique<Variable>(module_, type, *inst); const Variable* new_variable = id_to_variable_[inst->ResultId()].get(); if (new_variable->StorageClass() == spv::StorageClassInput) { @@ -788,6 +993,8 @@ return *new_variable; } +// Note - this does not include Function variables and will not find them +// currently no need to track them for any GPU-AV checks const Variable* TypeManager::FindVariableById(uint32_t id) const { auto variable = id_to_variable_.find(id); return (variable == id_to_variable_.end()) ? nullptr : variable->second.get();
diff --git a/layers/gpuav/spirv/type_manager.h b/layers/gpuav/spirv/type_manager.h index 23f943c..5e09a49 100644 --- a/layers/gpuav/spirv/type_manager.h +++ b/layers/gpuav/spirv/type_manager.h
@@ -18,6 +18,7 @@ #include <vector> #include <memory> #include "containers/custom_containers.h" +#include "containers/limits.h" #include "state_tracker/shader_instruction.h" #include "generated/spirv_grammar_helper.h" @@ -121,26 +122,59 @@ const bool is_spec_constant_; }; +struct DescriptorInterface { + // Set/Binding for decorations + uint32_t set = vvl::kNoIndex32; + uint32_t binding = vvl::kNoIndex32; + + // For SPV_EXT_descriptor_heap + bool is_resource_heap = false; + bool is_sampler_heap = false; + bool IsHeap() const { return is_resource_heap || is_sampler_heap; } +}; + // Represents a global OpVariable found before the first function struct Variable { - Variable(const Type& type, const Instruction& inst) : type_(type), inst_(inst) {} + Variable(const Module& module, const Type& type, const Instruction& inst) + : type_(type), inst_(inst), interface_(FindDescriptorInterface(module, inst)) {} uint32_t Id() const { return inst_.ResultId(); } - spv::StorageClass StorageClass() const { return spv::StorageClass(inst_.Word(3)); } - const Type* PointerType(TypeManager& type_manager_) const; + spv::StorageClass StorageClass() const { return inst_.StorageClass(); } + const Type* PointerType(const TypeManager& type_manager_) const; const Type& type_; const Instruction& inst_; + + const DescriptorInterface interface_; + + // Help used to know if you have a PushConstant, Input/Output, etc instead + bool IsDescriptor() const { + return interface_.IsHeap() || (interface_.set != vvl::kNoIndex32 && interface_.binding != vvl::kNoIndex32); + } + + protected: + static DescriptorInterface FindDescriptorInterface(const Module& module, const Instruction& inst); }; // We often want to walk the SSA from an "access" (load, store, atomic, etc) to the Variable it is referencing. There can be a // single OpAccessChain or multiple, and this struct holds this information. // Background info: https://github.com/KhronosGroup/SPIRV-Guide/blob/main/chapters/access_chains.md +// +// Note - currently this is very heavily leaned towards use of descriptors, but will work for any variable type struct AccessPath { + // The type of the access itself (what type it will store or load) + const Type* access_type = nullptr; + + // This the %ptr_type in + // %ptr_type = OpTypeArray + // %ptr = OpTypePointer StorageBuffer %ptr_type + // %var = OpVariable %ptr StorageBuffer + const Type* pointer_type = nullptr; + // The variable at the end of the access chain const Variable* variable = nullptr; - bool IsValid() const { return variable != nullptr; } + bool IsValid() const { return access_type != nullptr && pointer_type != nullptr && variable != nullptr; } // List of OpAccessChains from the variable to the "access" // - The front() will be closest to the OpVariable @@ -150,10 +184,26 @@ // Note: GLSL will try to always create a single large OpAccessChain std::vector<const Instruction*> ac_list; - // When dealing with an array of descriptors, the access closest to the variable will have it - uint32_t DescriptorIndexId() const { return ac_list.front()->Operand(1); } + // + // Descriptor variable access related info + // - uint32_t FinalAccessedType() const { return ac_list.back()->TypeId(); } + // Optional variable of seperate sampler descriptor (still null if combinedImageSampler) + const Variable* sampler_variable = nullptr; + bool is_combined_image_sampler = false; + bool HasSampler() const { return sampler_variable != nullptr || is_combined_image_sampler; } + + // The OpLoad to access an image descriptor + const Instruction* image_load_inst = nullptr; + + // Most access paths are used to get the descriptor variable. + // This is the ID of the uint that indexes in the array (or constant zero if no array) + uint32_t descriptor_index_id = 0; + // Optional index if there is a seperate sampler as well + uint32_t sampler_descriptor_index_id = 0; + + // TODO - Need to handle OffsetIdEXT correctly, this is a dumb hack + uint32_t heap_offset_member_index = 0; }; // In charge of tracking all Types, Constants, and Variable in the module. @@ -170,8 +220,8 @@ const Type& AddType(std::unique_ptr<Instruction> new_inst, SpvType spv_type); const Type* FindTypeById(uint32_t id) const; - const Type* FindValueTypeById(uint32_t id) const; const Type* FindFunctionType(const Instruction& inst) const; + const Type* FindTypeGlobal(const Function& function, uint32_t id) const; // There shouldn't be a case where we need to query for a specific type, but then not add it if not found. const Type& GetTypeVoid(); const Type& GetTypeBool(); @@ -215,7 +265,7 @@ const Constant& GetConstantZeroVector(const Type& vector_type); const Constant& GetConstantNull(const Type& type); - const AccessPath BuildAccessPath(const Function& function, const Instruction& inst) const; + const AccessPath BuildAccessPath(const Function& function, const Instruction& inst, bool ignore_image_sampler_skip = false); const Variable& AddVariable(std::unique_ptr<Instruction> new_inst, const Type& type); const Variable* FindVariableById(uint32_t id) const; @@ -230,9 +280,6 @@ void AddUndef(std::unique_ptr<Instruction> new_inst); bool IsUndef(uint32_t id) const; - void AddUntypedVariable(uint32_t id) { untyped_variable_set_.insert(id); }; - bool IsUntypedVariable(uint32_t id) const { return untyped_variable_set_.find(id) != untyped_variable_set_.end(); } - private: Module& module_; @@ -242,10 +289,6 @@ vvl::unordered_map<uint32_t, std::unique_ptr<Constant>> id_to_constant_; vvl::unordered_map<uint32_t, std::unique_ptr<Variable>> id_to_variable_; - // Currently don't fully support untyped pointers, but to allow things not to break, start tracking them so when searching for - // Variable, we can assert if not found, it is an OpUntypedVariableKHR - vvl::unordered_set<uint32_t> untyped_variable_set_; - // Create faster lookups for specific types // some types are base types and only will be one const Type* void_type = nullptr;
diff --git a/layers/gpuav/spirv/vertex_attribute_fetch_oob_pass.cpp b/layers/gpuav/spirv/vertex_attribute_fetch_oob_pass.cpp index d9f969b..7642771 100644 --- a/layers/gpuav/spirv/vertex_attribute_fetch_oob_pass.cpp +++ b/layers/gpuav/spirv/vertex_attribute_fetch_oob_pass.cpp
@@ -54,8 +54,6 @@ for (; word < total_words; word++) { const uint32_t interface_id = entry_point->Word(word); const Variable* variable = type_manager_.FindVariableById(interface_id); - // guaranteed by spirv-val to be a OpVariable/OpUntypedVariable - assert(variable || type_manager_.IsUntypedVariable(interface_id)); if (variable && variable->StorageClass() == spv::StorageClassInput) { found_input = true; break;
diff --git a/layers/state_tracker/shader_instruction.cpp b/layers/state_tracker/shader_instruction.cpp index ff95a6d..89e4146 100644 --- a/layers/state_tracker/shader_instruction.cpp +++ b/layers/state_tracker/shader_instruction.cpp
@@ -196,13 +196,20 @@ bool Instruction::IsNonPtrAccessChain() const { const uint32_t opcode = Opcode(); - return opcode == spv::OpAccessChain || opcode == spv::OpInBoundsAccessChain; + return opcode == spv::OpAccessChain || opcode == spv::OpInBoundsAccessChain || opcode == spv::OpUntypedAccessChainKHR || + opcode == spv::OpUntypedInBoundsAccessChainKHR; } bool Instruction::IsAccessChain() const { const uint32_t opcode = Opcode(); - return opcode == spv::OpAccessChain || opcode == spv::OpPtrAccessChain || opcode == spv::OpInBoundsAccessChain || - opcode == spv::OpInBoundsPtrAccessChain; + return IsNonPtrAccessChain() || opcode == spv::OpPtrAccessChain || opcode == spv::OpInBoundsPtrAccessChain || + opcode == spv::OpUntypedPtrAccessChainKHR || opcode == spv::OpUntypedInBoundsPtrAccessChainKHR; +} + +bool Instruction::IsUntypedAccessChain() const { + const uint32_t opcode = Opcode(); + return opcode == spv::OpUntypedAccessChainKHR || opcode == spv::OpUntypedInBoundsAccessChainKHR || + opcode == spv::OpUntypedPtrAccessChainKHR || opcode == spv::OpUntypedInBoundsPtrAccessChainKHR; } bool Instruction::IsTensor() const { return (Opcode() == spv::OpTypeTensorARM); } @@ -577,6 +584,10 @@ case spv::OpImageQueryLod: case spv::OpFragmentFetchAMD: case spv::OpFragmentMaskFetchAMD: + // Image atomics can only be accessed with these 3 atomics + case spv::OpAtomicLoad: + case spv::OpAtomicStore: + case spv::OpAtomicExchange: break; case spv::OpImageSparseTexelsResident:
diff --git a/layers/state_tracker/shader_instruction.h b/layers/state_tracker/shader_instruction.h index bb21241..18cca3b 100644 --- a/layers/state_tracker/shader_instruction.h +++ b/layers/state_tracker/shader_instruction.h
@@ -79,6 +79,7 @@ bool IsVector() const; bool IsNonPtrAccessChain() const; bool IsAccessChain() const; + bool IsUntypedAccessChain() const; // Helpers for OpTypeImage bool IsTensor() const; bool IsConstant() const;
diff --git a/layers/vulkan/generated/gpuav_offline_spirv.cpp b/layers/vulkan/generated/gpuav_offline_spirv.cpp index a0781fd..8222ca9 100644 --- a/layers/vulkan/generated/gpuav_offline_spirv.cpp +++ b/layers/vulkan/generated/gpuav_offline_spirv.cpp
@@ -282,9 +282,9 @@ 0x000100fd, 0x00010038}; [[maybe_unused]] const uint32_t instrumentation_descriptor_class_texel_buffer_comp_function_0_offset = 461; -[[maybe_unused]] const uint32_t instrumentation_descriptor_heap_comp_size = 2297; -[[maybe_unused]] const uint32_t instrumentation_descriptor_heap_comp[2297] = { - 0x07230203, 0x00010300, 0x0008000b, 0x000001d4, 0x00000000, 0x00020011, 0x00000001, 0x00020011, 0x00000005, 0x00020011, +[[maybe_unused]] const uint32_t instrumentation_descriptor_heap_comp_size = 2640; +[[maybe_unused]] const uint32_t instrumentation_descriptor_heap_comp[2640] = { + 0x07230203, 0x00010300, 0x0008000b, 0x00000216, 0x00000000, 0x00020011, 0x00000001, 0x00020011, 0x00000005, 0x00020011, 0x0000000b, 0x00020011, 0x000014e3, 0x0009000a, 0x5f565053, 0x5f52484b, 0x73796870, 0x6c616369, 0x6f74735f, 0x65676172, 0x6675625f, 0x00726566, 0x0006000b, 0x00000001, 0x4c534c47, 0x6474732e, 0x3035342e, 0x00000000, 0x0003000e, 0x000014e4, 0x00000001, 0x00030003, 0x00000002, 0x000001c2, 0x00070004, 0x415f4c47, 0x675f4252, 0x735f7570, 0x65646168, 0x6e695f72, @@ -323,205 +323,240 @@ 0x00746573, 0x00070005, 0x00000035, 0x68737570, 0x6464615f, 0x73736572, 0x66666f5f, 0x00746573, 0x000e0005, 0x0000003b, 0x74736e69, 0x6165685f, 0x616d5f70, 0x6e697070, 0x6e695f67, 0x65726964, 0x615f7463, 0x65726464, 0x75287373, 0x31753b31, 0x3b31753b, 0x00000000, 0x00050005, 0x00000038, 0x74736e69, 0x66666f5f, 0x00746573, 0x00050005, 0x00000039, 0x68737570, - 0x66666f5f, 0x00746573, 0x00060005, 0x0000003a, 0x72646461, 0x5f737365, 0x7366666f, 0x00007465, 0x00040005, 0x0000003e, - 0x6f727265, 0x00000072, 0x00040005, 0x00000040, 0x61726170, 0x00305f6d, 0x00060005, 0x00000044, 0x6e756f42, 0x61654864, - 0x666e4970, 0x0000006f, 0x00060006, 0x00000044, 0x00000000, 0x70616568, 0x7a69735f, 0x00000065, 0x00070006, 0x00000044, - 0x00000001, 0x65736572, 0x64657672, 0x6765625f, 0x00006e69, 0x00070006, 0x00000044, 0x00000002, 0x65736572, 0x64657672, - 0x646e655f, 0x00000000, 0x00060005, 0x00000046, 0x6e756f62, 0x65685f64, 0x695f7061, 0x006f666e, 0x00060005, 0x0000004a, - 0x6e756f42, 0x61654864, 0x666e4970, 0x0000006f, 0x00060006, 0x0000004a, 0x00000000, 0x70616568, 0x7a69735f, 0x00000065, - 0x00070006, 0x0000004a, 0x00000001, 0x65736572, 0x64657672, 0x6765625f, 0x00006e69, 0x00070006, 0x0000004a, 0x00000002, - 0x65736572, 0x64657672, 0x646e655f, 0x00000000, 0x00080005, 0x0000004c, 0x63736544, 0x74706972, 0x6548726f, 0x6e457061, - 0x69646f63, 0x0000676e, 0x00080006, 0x0000004c, 0x00000000, 0x6e756f62, 0x65725f64, 0x72756f73, 0x685f6563, 0x00706165, - 0x00080006, 0x0000004c, 0x00000001, 0x6e756f62, 0x61735f64, 0x656c706d, 0x65685f72, 0x00007061, 0x00060006, 0x0000004c, - 0x00000002, 0x68737570, 0x7461645f, 0x00000061, 0x00040005, 0x0000004e, 0x61757067, 0x00000076, 0x00060005, 0x00000072, - 0x6f727245, 0x79615072, 0x64616f6c, 0x00000000, 0x00060006, 0x00000072, 0x00000000, 0x74736e69, 0x66666f5f, 0x00746573, - 0x00090006, 0x00000072, 0x00000001, 0x64616873, 0x655f7265, 0x726f7272, 0x636e655f, 0x6e69646f, 0x00000067, 0x00060006, - 0x00000072, 0x00000002, 0x61726170, 0x6574656d, 0x00305f72, 0x00060006, 0x00000072, 0x00000003, 0x61726170, 0x6574656d, - 0x00315f72, 0x00060006, 0x00000072, 0x00000004, 0x61726170, 0x6574656d, 0x00325f72, 0x00060005, 0x00000074, 0x6f727265, - 0x61705f72, 0x616f6c79, 0x00000064, 0x00090005, 0x00000075, 0x63657053, 0x736e6f43, 0x746e6174, 0x6b6e694c, 0x64616853, - 0x64497265, 0x00000000, 0x00040005, 0x00000084, 0x6f727265, 0x00000072, 0x00040005, 0x00000085, 0x61726170, 0x00305f6d, - 0x00060005, 0x00000090, 0x6e756f62, 0x65685f64, 0x695f7061, 0x006f666e, 0x00040005, 0x000000ba, 0x6f727265, 0x00000072, - 0x00040005, 0x000000bb, 0x61726170, 0x00305f6d, 0x00060005, 0x000000c9, 0x69646e49, 0x74636572, 0x66667542, 0x00007265, - 0x00050006, 0x000000c9, 0x00000000, 0x61746164, 0x00000000, 0x00060005, 0x000000d9, 0x6e756f62, 0x65685f64, 0x695f7061, - 0x006f666e, 0x00040005, 0x00000103, 0x6f727265, 0x00000072, 0x00040005, 0x00000104, 0x61726170, 0x00305f6d, 0x00060005, - 0x0000011b, 0x6e756f62, 0x65685f64, 0x695f7061, 0x006f666e, 0x000d0047, 0x0000000a, 0x00000029, 0x74736e69, 0x6165685f, - 0x616d5f70, 0x6e697070, 0x6f635f67, 0x6174736e, 0x6f5f746e, 0x65736666, 0x00000074, 0x00000000, 0x000c0047, 0x00000014, - 0x00000029, 0x74736e69, 0x6165685f, 0x616d5f70, 0x6e697070, 0x75705f67, 0x695f6873, 0x7865646e, 0x00000000, 0x00000000, - 0x000d0047, 0x0000001f, 0x00000029, 0x74736e69, 0x6165685f, 0x616d5f70, 0x6e697070, 0x6e695f67, 0x65726964, 0x695f7463, - 0x7865646e, 0x00000000, 0x00000000, 0x000e0047, 0x00000028, 0x00000029, 0x74736e69, 0x6165685f, 0x616d5f70, 0x6e697070, - 0x6e695f67, 0x65726964, 0x695f7463, 0x7865646e, 0x7272615f, 0x00007961, 0x00000000, 0x000e0047, 0x0000002e, 0x00000029, - 0x74736e69, 0x6165685f, 0x616d5f70, 0x6e697070, 0x65725f67, 0x72756f73, 0x685f6563, 0x5f706165, 0x61746164, 0x00000000, - 0x00000000, 0x000b0047, 0x00000031, 0x00000029, 0x74736e69, 0x6165685f, 0x616d5f70, 0x6e697070, 0x75705f67, 0x645f6873, - 0x00617461, 0x00000000, 0x000c0047, 0x00000036, 0x00000029, 0x74736e69, 0x6165685f, 0x616d5f70, 0x6e697070, 0x75705f67, - 0x615f6873, 0x65726464, 0x00007373, 0x00000000, 0x000d0047, 0x0000003b, 0x00000029, 0x74736e69, 0x6165685f, 0x616d5f70, - 0x6e697070, 0x6e695f67, 0x65726964, 0x615f7463, 0x65726464, 0x00007373, 0x00000000, 0x00050048, 0x0000004a, 0x00000000, - 0x00000023, 0x00000000, 0x00050048, 0x0000004a, 0x00000001, 0x00000023, 0x00000004, 0x00050048, 0x0000004a, 0x00000002, - 0x00000023, 0x00000008, 0x00040047, 0x0000004b, 0x00000006, 0x00000004, 0x00030047, 0x0000004c, 0x00000002, 0x00050048, - 0x0000004c, 0x00000000, 0x00000023, 0x00000000, 0x00050048, 0x0000004c, 0x00000001, 0x00000023, 0x0000000c, 0x00050048, - 0x0000004c, 0x00000002, 0x00000023, 0x00000018, 0x00040047, 0x0000004e, 0x00000021, 0x00000004, 0x00040047, 0x0000004e, - 0x00000022, 0x00000007, 0x00040047, 0x00000075, 0x00000001, 0x00000000, 0x00040047, 0x000000c8, 0x00000006, 0x00000004, - 0x00030047, 0x000000c9, 0x00000002, 0x00050048, 0x000000c9, 0x00000000, 0x00000023, 0x00000000, 0x00040015, 0x00000002, + 0x66666f5f, 0x00746573, 0x00060005, 0x0000003a, 0x72646461, 0x5f737365, 0x7366666f, 0x00007465, 0x000b0005, 0x00000042, + 0x74736e69, 0x6165685f, 0x6e755f70, 0x65707974, 0x31752864, 0x3b31753b, 0x753b3175, 0x31623b31, 0x0000003b, 0x00050005, + 0x0000003d, 0x74736e69, 0x66666f5f, 0x00746573, 0x00050005, 0x0000003e, 0x70616568, 0x66666f5f, 0x00746573, 0x00060005, + 0x0000003f, 0x72646461, 0x5f737365, 0x69727473, 0x00006564, 0x00050005, 0x00000040, 0x63736564, 0x646e695f, 0x00007865, + 0x00050005, 0x00000041, 0x735f7369, 0x6c706d61, 0x00007265, 0x00040005, 0x00000045, 0x6f727265, 0x00000072, 0x00040005, + 0x00000047, 0x61726170, 0x00305f6d, 0x00060005, 0x0000004b, 0x6e756f42, 0x61654864, 0x666e4970, 0x0000006f, 0x00060006, + 0x0000004b, 0x00000000, 0x70616568, 0x7a69735f, 0x00000065, 0x00070006, 0x0000004b, 0x00000001, 0x65736572, 0x64657672, + 0x6765625f, 0x00006e69, 0x00070006, 0x0000004b, 0x00000002, 0x65736572, 0x64657672, 0x646e655f, 0x00000000, 0x00060005, + 0x0000004d, 0x6e756f62, 0x65685f64, 0x695f7061, 0x006f666e, 0x00060005, 0x00000051, 0x6e756f42, 0x61654864, 0x666e4970, + 0x0000006f, 0x00060006, 0x00000051, 0x00000000, 0x70616568, 0x7a69735f, 0x00000065, 0x00070006, 0x00000051, 0x00000001, + 0x65736572, 0x64657672, 0x6765625f, 0x00006e69, 0x00070006, 0x00000051, 0x00000002, 0x65736572, 0x64657672, 0x646e655f, + 0x00000000, 0x00080005, 0x00000053, 0x63736544, 0x74706972, 0x6548726f, 0x6e457061, 0x69646f63, 0x0000676e, 0x00080006, + 0x00000053, 0x00000000, 0x6e756f62, 0x65725f64, 0x72756f73, 0x685f6563, 0x00706165, 0x00080006, 0x00000053, 0x00000001, + 0x6e756f62, 0x61735f64, 0x656c706d, 0x65685f72, 0x00007061, 0x00060006, 0x00000053, 0x00000002, 0x68737570, 0x7461645f, + 0x00000061, 0x00040005, 0x00000055, 0x61757067, 0x00000076, 0x00060005, 0x00000079, 0x6f727245, 0x79615072, 0x64616f6c, + 0x00000000, 0x00060006, 0x00000079, 0x00000000, 0x74736e69, 0x66666f5f, 0x00746573, 0x00090006, 0x00000079, 0x00000001, + 0x64616873, 0x655f7265, 0x726f7272, 0x636e655f, 0x6e69646f, 0x00000067, 0x00060006, 0x00000079, 0x00000002, 0x61726170, + 0x6574656d, 0x00305f72, 0x00060006, 0x00000079, 0x00000003, 0x61726170, 0x6574656d, 0x00315f72, 0x00060006, 0x00000079, + 0x00000004, 0x61726170, 0x6574656d, 0x00325f72, 0x00060005, 0x0000007b, 0x6f727265, 0x61705f72, 0x616f6c79, 0x00000064, + 0x00090005, 0x0000007c, 0x63657053, 0x736e6f43, 0x746e6174, 0x6b6e694c, 0x64616853, 0x64497265, 0x00000000, 0x00040005, + 0x0000008b, 0x6f727265, 0x00000072, 0x00040005, 0x0000008c, 0x61726170, 0x00305f6d, 0x00060005, 0x00000097, 0x6e756f62, + 0x65685f64, 0x695f7061, 0x006f666e, 0x00040005, 0x000000c1, 0x6f727265, 0x00000072, 0x00040005, 0x000000c2, 0x61726170, + 0x00305f6d, 0x00060005, 0x000000d0, 0x69646e49, 0x74636572, 0x66667542, 0x00007265, 0x00050006, 0x000000d0, 0x00000000, + 0x61746164, 0x00000000, 0x00060005, 0x000000e0, 0x6e756f62, 0x65685f64, 0x695f7061, 0x006f666e, 0x00040005, 0x0000010a, + 0x6f727265, 0x00000072, 0x00040005, 0x0000010b, 0x61726170, 0x00305f6d, 0x00060005, 0x00000122, 0x6e756f62, 0x65685f64, + 0x695f7061, 0x006f666e, 0x00040005, 0x00000154, 0x6f727265, 0x00000072, 0x00040005, 0x00000155, 0x61726170, 0x00305f6d, + 0x00060005, 0x00000159, 0x6e756f62, 0x65685f64, 0x695f7061, 0x006f666e, 0x000d0047, 0x0000000a, 0x00000029, 0x74736e69, + 0x6165685f, 0x616d5f70, 0x6e697070, 0x6f635f67, 0x6174736e, 0x6f5f746e, 0x65736666, 0x00000074, 0x00000000, 0x000c0047, + 0x00000014, 0x00000029, 0x74736e69, 0x6165685f, 0x616d5f70, 0x6e697070, 0x75705f67, 0x695f6873, 0x7865646e, 0x00000000, + 0x00000000, 0x000d0047, 0x0000001f, 0x00000029, 0x74736e69, 0x6165685f, 0x616d5f70, 0x6e697070, 0x6e695f67, 0x65726964, + 0x695f7463, 0x7865646e, 0x00000000, 0x00000000, 0x000e0047, 0x00000028, 0x00000029, 0x74736e69, 0x6165685f, 0x616d5f70, + 0x6e697070, 0x6e695f67, 0x65726964, 0x695f7463, 0x7865646e, 0x7272615f, 0x00007961, 0x00000000, 0x000e0047, 0x0000002e, + 0x00000029, 0x74736e69, 0x6165685f, 0x616d5f70, 0x6e697070, 0x65725f67, 0x72756f73, 0x685f6563, 0x5f706165, 0x61746164, + 0x00000000, 0x00000000, 0x000b0047, 0x00000031, 0x00000029, 0x74736e69, 0x6165685f, 0x616d5f70, 0x6e697070, 0x75705f67, + 0x645f6873, 0x00617461, 0x00000000, 0x000c0047, 0x00000036, 0x00000029, 0x74736e69, 0x6165685f, 0x616d5f70, 0x6e697070, + 0x75705f67, 0x615f6873, 0x65726464, 0x00007373, 0x00000000, 0x000d0047, 0x0000003b, 0x00000029, 0x74736e69, 0x6165685f, + 0x616d5f70, 0x6e697070, 0x6e695f67, 0x65726964, 0x615f7463, 0x65726464, 0x00007373, 0x00000000, 0x00090047, 0x00000042, + 0x00000029, 0x74736e69, 0x6165685f, 0x6e755f70, 0x65707974, 0x00000064, 0x00000000, 0x00050048, 0x00000051, 0x00000000, + 0x00000023, 0x00000000, 0x00050048, 0x00000051, 0x00000001, 0x00000023, 0x00000004, 0x00050048, 0x00000051, 0x00000002, + 0x00000023, 0x00000008, 0x00040047, 0x00000052, 0x00000006, 0x00000004, 0x00030047, 0x00000053, 0x00000002, 0x00050048, + 0x00000053, 0x00000000, 0x00000023, 0x00000000, 0x00050048, 0x00000053, 0x00000001, 0x00000023, 0x0000000c, 0x00050048, + 0x00000053, 0x00000002, 0x00000023, 0x00000018, 0x00040047, 0x00000055, 0x00000021, 0x00000004, 0x00040047, 0x00000055, + 0x00000022, 0x00000007, 0x00040047, 0x0000007c, 0x00000001, 0x00000000, 0x00040047, 0x000000cf, 0x00000006, 0x00000004, + 0x00030047, 0x000000d0, 0x00000002, 0x00050048, 0x000000d0, 0x00000000, 0x00000023, 0x00000000, 0x00040015, 0x00000002, 0x00000020, 0x00000000, 0x00020014, 0x00000003, 0x00080021, 0x00000004, 0x00000003, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000003, 0x000a0021, 0x0000000c, 0x00000003, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000003, 0x000b0021, 0x00000016, 0x00000003, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000003, 0x00060021, 0x0000002a, 0x00000003, 0x00000002, 0x00000002, 0x00000002, 0x00030021, - 0x00000030, 0x00000003, 0x00050021, 0x00000033, 0x00000003, 0x00000002, 0x00000002, 0x00040020, 0x0000003d, 0x00000007, - 0x00000002, 0x0004002b, 0x00000002, 0x0000003f, 0x00000000, 0x0005001e, 0x00000044, 0x00000002, 0x00000002, 0x00000002, - 0x00040020, 0x00000045, 0x00000007, 0x00000044, 0x0005001e, 0x0000004a, 0x00000002, 0x00000002, 0x00000002, 0x0003001d, - 0x0000004b, 0x00000002, 0x0005001e, 0x0000004c, 0x0000004a, 0x0000004a, 0x0000004b, 0x00040020, 0x0000004d, 0x0000000c, - 0x0000004c, 0x0004003b, 0x0000004d, 0x0000004e, 0x0000000c, 0x00040015, 0x0000004f, 0x00000020, 0x00000001, 0x0004002b, - 0x0000004f, 0x00000050, 0x00000001, 0x00040020, 0x00000051, 0x0000000c, 0x0000004a, 0x0004002b, 0x0000004f, 0x00000055, - 0x00000000, 0x0004002b, 0x0000004f, 0x0000005a, 0x00000002, 0x0004002b, 0x00000002, 0x0000006c, 0x00000001, 0x0007001e, - 0x00000072, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00040020, 0x00000073, 0x00000006, 0x00000072, - 0x0004003b, 0x00000073, 0x00000074, 0x00000006, 0x00040032, 0x00000002, 0x00000075, 0x0dead001, 0x0004002b, 0x00000002, - 0x00000076, 0x11000000, 0x00060034, 0x00000002, 0x00000077, 0x000000c5, 0x00000075, 0x00000076, 0x0004002b, 0x0000004f, - 0x00000079, 0x00000012, 0x0003002a, 0x00000003, 0x0000007e, 0x00030029, 0x00000003, 0x00000080, 0x00040020, 0x00000087, - 0x0000000c, 0x00000002, 0x00060034, 0x00000002, 0x000000b1, 0x000000c5, 0x00000075, 0x00000076, 0x00040015, 0x000000bc, - 0x00000040, 0x00000000, 0x00040017, 0x000000c4, 0x00000002, 0x00000002, 0x00030027, 0x000000c7, 0x000014e5, 0x0003001d, - 0x000000c8, 0x00000002, 0x0003001e, 0x000000c9, 0x000000c8, 0x00040020, 0x000000c7, 0x000014e5, 0x000000c9, 0x00040020, - 0x000000d0, 0x000014e5, 0x00000002, 0x00060034, 0x00000002, 0x000000fa, 0x000000c5, 0x00000075, 0x00000076, 0x00060034, - 0x00000002, 0x0000013c, 0x000000c5, 0x00000075, 0x00000076, 0x0004002b, 0x00000002, 0x000001a7, 0x00000002, 0x00050036, - 0x00000003, 0x0000000a, 0x00000000, 0x00000004, 0x00030037, 0x00000002, 0x00000005, 0x00030037, 0x00000002, 0x00000006, - 0x00030037, 0x00000002, 0x00000007, 0x00030037, 0x00000002, 0x00000008, 0x00030037, 0x00000003, 0x00000009, 0x000200f8, - 0x0000000b, 0x0004003b, 0x0000003d, 0x0000003e, 0x00000007, 0x0004003b, 0x0000003d, 0x00000040, 0x00000007, 0x0004003b, - 0x00000045, 0x00000046, 0x00000007, 0x0004003b, 0x00000045, 0x00000047, 0x00000007, 0x0003003e, 0x0000003e, 0x0000003f, - 0x0003003e, 0x00000040, 0x0000003f, 0x00050084, 0x00000002, 0x00000042, 0x00000008, 0x00000007, 0x00050080, 0x00000002, - 0x00000043, 0x00000006, 0x00000042, 0x000300f7, 0x00000049, 0x00000000, 0x000400fa, 0x00000009, 0x00000048, 0x0000005c, - 0x000200f8, 0x00000048, 0x00050041, 0x00000051, 0x00000052, 0x0000004e, 0x00000050, 0x00050041, 0x00000087, 0x000001aa, - 0x00000052, 0x0000003f, 0x0004003d, 0x00000002, 0x000001ab, 0x000001aa, 0x00050041, 0x00000087, 0x000001ac, 0x00000052, - 0x0000006c, 0x0004003d, 0x00000002, 0x000001ad, 0x000001ac, 0x00050041, 0x00000087, 0x000001ae, 0x00000052, 0x000001a7, - 0x0004003d, 0x00000002, 0x000001af, 0x000001ae, 0x00050041, 0x0000003d, 0x00000056, 0x00000047, 0x00000055, 0x0003003e, - 0x00000056, 0x000001ab, 0x00050041, 0x0000003d, 0x00000058, 0x00000047, 0x00000050, 0x0003003e, 0x00000058, 0x000001ad, - 0x00050041, 0x0000003d, 0x0000005b, 0x00000047, 0x0000005a, 0x0003003e, 0x0000005b, 0x000001af, 0x000200f9, 0x00000049, - 0x000200f8, 0x0000005c, 0x00050041, 0x00000051, 0x0000005d, 0x0000004e, 0x00000055, 0x00050041, 0x00000087, 0x000001a3, - 0x0000005d, 0x0000003f, 0x0004003d, 0x00000002, 0x000001a4, 0x000001a3, 0x00050041, 0x00000087, 0x000001a5, 0x0000005d, - 0x0000006c, 0x0004003d, 0x00000002, 0x000001a6, 0x000001a5, 0x00050041, 0x00000087, 0x000001a8, 0x0000005d, 0x000001a7, - 0x0004003d, 0x00000002, 0x000001a9, 0x000001a8, 0x00050041, 0x0000003d, 0x00000060, 0x00000047, 0x00000055, 0x0003003e, - 0x00000060, 0x000001a4, 0x00050041, 0x0000003d, 0x00000062, 0x00000047, 0x00000050, 0x0003003e, 0x00000062, 0x000001a6, - 0x00050041, 0x0000003d, 0x00000064, 0x00000047, 0x0000005a, 0x0003003e, 0x00000064, 0x000001a9, 0x000200f9, 0x00000049, - 0x000200f8, 0x00000049, 0x0004003d, 0x00000044, 0x00000065, 0x00000047, 0x0003003e, 0x00000046, 0x00000065, 0x00050041, - 0x0000003d, 0x00000067, 0x00000046, 0x00000055, 0x0004003d, 0x00000002, 0x00000068, 0x00000067, 0x000500ae, 0x00000003, - 0x00000069, 0x00000043, 0x00000068, 0x000300f7, 0x0000006b, 0x00000000, 0x000400fa, 0x00000069, 0x0000006a, 0x0000006b, - 0x000200f8, 0x0000006a, 0x0003003e, 0x0000003e, 0x0000006c, 0x0003003e, 0x00000040, 0x00000043, 0x000200f9, 0x0000006b, - 0x000200f8, 0x0000006b, 0x0004003d, 0x00000002, 0x0000006e, 0x0000003e, 0x000500ab, 0x00000003, 0x0000006f, 0x0000006e, - 0x0000003f, 0x000300f7, 0x00000071, 0x00000000, 0x000400fa, 0x0000006f, 0x00000070, 0x00000071, 0x000200f8, 0x00000070, - 0x0004003d, 0x00000002, 0x00000078, 0x0000003e, 0x000500c4, 0x00000002, 0x0000007a, 0x00000078, 0x00000079, 0x000500c5, - 0x00000002, 0x0000007b, 0x00000077, 0x0000007a, 0x0004003d, 0x00000002, 0x0000007c, 0x00000040, 0x00080050, 0x00000072, - 0x0000007d, 0x00000005, 0x0000007b, 0x00000008, 0x0000007c, 0x0000003f, 0x0003003e, 0x00000074, 0x0000007d, 0x000200fe, - 0x0000007e, 0x000200f8, 0x00000071, 0x000200fe, 0x00000080, 0x00010038, 0x00050036, 0x00000003, 0x00000014, 0x00000000, - 0x0000000c, 0x00030037, 0x00000002, 0x0000000d, 0x00030037, 0x00000002, 0x0000000e, 0x00030037, 0x00000002, 0x0000000f, - 0x00030037, 0x00000002, 0x00000010, 0x00030037, 0x00000002, 0x00000011, 0x00030037, 0x00000002, 0x00000012, 0x00030037, - 0x00000003, 0x00000013, 0x000200f8, 0x00000015, 0x0004003b, 0x0000003d, 0x00000084, 0x00000007, 0x0004003b, 0x0000003d, - 0x00000085, 0x00000007, 0x0004003b, 0x00000045, 0x00000090, 0x00000007, 0x0004003b, 0x00000045, 0x00000091, 0x00000007, - 0x0003003e, 0x00000084, 0x0000003f, 0x0003003e, 0x00000085, 0x0000003f, 0x00060041, 0x00000087, 0x00000088, 0x0000004e, - 0x0000005a, 0x0000000f, 0x0004003d, 0x00000002, 0x00000089, 0x00000088, 0x00050084, 0x00000002, 0x0000008c, 0x00000089, - 0x00000010, 0x00050080, 0x00000002, 0x0000008d, 0x0000000e, 0x0000008c, 0x00050084, 0x00000002, 0x0000008e, 0x00000012, - 0x00000011, 0x00050080, 0x00000002, 0x0000008f, 0x0000008d, 0x0000008e, 0x000300f7, 0x00000093, 0x00000000, 0x000400fa, - 0x00000013, 0x00000092, 0x0000009c, 0x000200f8, 0x00000092, 0x00050041, 0x00000051, 0x00000094, 0x0000004e, 0x00000050, - 0x00050041, 0x00000087, 0x000001b6, 0x00000094, 0x0000003f, 0x0004003d, 0x00000002, 0x000001b7, 0x000001b6, 0x00050041, - 0x00000087, 0x000001b8, 0x00000094, 0x0000006c, 0x0004003d, 0x00000002, 0x000001b9, 0x000001b8, 0x00050041, 0x00000087, - 0x000001ba, 0x00000094, 0x000001a7, 0x0004003d, 0x00000002, 0x000001bb, 0x000001ba, 0x00050041, 0x0000003d, 0x00000097, - 0x00000091, 0x00000055, 0x0003003e, 0x00000097, 0x000001b7, 0x00050041, 0x0000003d, 0x00000099, 0x00000091, 0x00000050, - 0x0003003e, 0x00000099, 0x000001b9, 0x00050041, 0x0000003d, 0x0000009b, 0x00000091, 0x0000005a, 0x0003003e, 0x0000009b, - 0x000001bb, 0x000200f9, 0x00000093, 0x000200f8, 0x0000009c, 0x00050041, 0x00000051, 0x0000009d, 0x0000004e, 0x00000055, - 0x00050041, 0x00000087, 0x000001b0, 0x0000009d, 0x0000003f, 0x0004003d, 0x00000002, 0x000001b1, 0x000001b0, 0x00050041, - 0x00000087, 0x000001b2, 0x0000009d, 0x0000006c, 0x0004003d, 0x00000002, 0x000001b3, 0x000001b2, 0x00050041, 0x00000087, - 0x000001b4, 0x0000009d, 0x000001a7, 0x0004003d, 0x00000002, 0x000001b5, 0x000001b4, 0x00050041, 0x0000003d, 0x000000a0, - 0x00000091, 0x00000055, 0x0003003e, 0x000000a0, 0x000001b1, 0x00050041, 0x0000003d, 0x000000a2, 0x00000091, 0x00000050, - 0x0003003e, 0x000000a2, 0x000001b3, 0x00050041, 0x0000003d, 0x000000a4, 0x00000091, 0x0000005a, 0x0003003e, 0x000000a4, - 0x000001b5, 0x000200f9, 0x00000093, 0x000200f8, 0x00000093, 0x0004003d, 0x00000044, 0x000000a5, 0x00000091, 0x0003003e, - 0x00000090, 0x000000a5, 0x00050041, 0x0000003d, 0x000000a7, 0x00000090, 0x00000055, 0x0004003d, 0x00000002, 0x000000a8, - 0x000000a7, 0x000500ae, 0x00000003, 0x000000a9, 0x0000008f, 0x000000a8, 0x000300f7, 0x000000ab, 0x00000000, 0x000400fa, - 0x000000a9, 0x000000aa, 0x000000ab, 0x000200f8, 0x000000aa, 0x0003003e, 0x00000084, 0x0000006c, 0x0003003e, 0x00000085, - 0x0000008f, 0x000200f9, 0x000000ab, 0x000200f8, 0x000000ab, 0x0004003d, 0x00000002, 0x000000ad, 0x00000084, 0x000500ab, - 0x00000003, 0x000000ae, 0x000000ad, 0x0000003f, 0x000300f7, 0x000000b0, 0x00000000, 0x000400fa, 0x000000ae, 0x000000af, - 0x000000b0, 0x000200f8, 0x000000af, 0x0004003d, 0x00000002, 0x000000b2, 0x00000084, 0x000500c4, 0x00000002, 0x000000b3, - 0x000000b2, 0x00000079, 0x000500c5, 0x00000002, 0x000000b4, 0x000000b1, 0x000000b3, 0x0004003d, 0x00000002, 0x000000b5, - 0x00000085, 0x00080050, 0x00000072, 0x000000b6, 0x0000000d, 0x000000b4, 0x00000012, 0x000000b5, 0x0000003f, 0x0003003e, - 0x00000074, 0x000000b6, 0x000200fe, 0x0000007e, 0x000200f8, 0x000000b0, 0x000200fe, 0x00000080, 0x00010038, 0x00050036, - 0x00000003, 0x0000001f, 0x00000000, 0x00000016, 0x00030037, 0x00000002, 0x00000017, 0x00030037, 0x00000002, 0x00000018, - 0x00030037, 0x00000002, 0x00000019, 0x00030037, 0x00000002, 0x0000001a, 0x00030037, 0x00000002, 0x0000001b, 0x00030037, - 0x00000002, 0x0000001c, 0x00030037, 0x00000002, 0x0000001d, 0x00030037, 0x00000003, 0x0000001e, 0x000200f8, 0x00000020, - 0x0004003b, 0x0000003d, 0x000000ba, 0x00000007, 0x0004003b, 0x0000003d, 0x000000bb, 0x00000007, 0x0004003b, 0x00000045, - 0x000000d9, 0x00000007, 0x0004003b, 0x00000045, 0x000000da, 0x00000007, 0x0003003e, 0x000000ba, 0x0000003f, 0x0003003e, - 0x000000bb, 0x0000003f, 0x00060041, 0x00000087, 0x000000bf, 0x0000004e, 0x0000005a, 0x00000019, 0x0004003d, 0x00000002, - 0x000000c0, 0x000000bf, 0x00050080, 0x00000002, 0x000000c1, 0x00000019, 0x0000006c, 0x00060041, 0x00000087, 0x000000c2, - 0x0000004e, 0x0000005a, 0x000000c1, 0x0004003d, 0x00000002, 0x000000c3, 0x000000c2, 0x00050050, 0x000000c4, 0x000000c5, - 0x000000c0, 0x000000c3, 0x0004007c, 0x000000bc, 0x000000c6, 0x000000c5, 0x00040078, 0x000000c7, 0x000000cd, 0x000000c6, - 0x00060041, 0x000000d0, 0x000000d1, 0x000000cd, 0x00000055, 0x0000001a, 0x0006003d, 0x00000002, 0x000000d2, 0x000000d1, - 0x00000002, 0x00000004, 0x00050084, 0x00000002, 0x000000d5, 0x000000d2, 0x0000001b, 0x00050080, 0x00000002, 0x000000d6, - 0x00000018, 0x000000d5, 0x00050084, 0x00000002, 0x000000d7, 0x0000001d, 0x0000001c, 0x00050080, 0x00000002, 0x000000d8, - 0x000000d6, 0x000000d7, 0x000300f7, 0x000000dc, 0x00000000, 0x000400fa, 0x0000001e, 0x000000db, 0x000000e5, 0x000200f8, - 0x000000db, 0x00050041, 0x00000051, 0x000000dd, 0x0000004e, 0x00000050, 0x00050041, 0x00000087, 0x000001c2, 0x000000dd, - 0x0000003f, 0x0004003d, 0x00000002, 0x000001c3, 0x000001c2, 0x00050041, 0x00000087, 0x000001c4, 0x000000dd, 0x0000006c, - 0x0004003d, 0x00000002, 0x000001c5, 0x000001c4, 0x00050041, 0x00000087, 0x000001c6, 0x000000dd, 0x000001a7, 0x0004003d, - 0x00000002, 0x000001c7, 0x000001c6, 0x00050041, 0x0000003d, 0x000000e0, 0x000000da, 0x00000055, 0x0003003e, 0x000000e0, - 0x000001c3, 0x00050041, 0x0000003d, 0x000000e2, 0x000000da, 0x00000050, 0x0003003e, 0x000000e2, 0x000001c5, 0x00050041, - 0x0000003d, 0x000000e4, 0x000000da, 0x0000005a, 0x0003003e, 0x000000e4, 0x000001c7, 0x000200f9, 0x000000dc, 0x000200f8, - 0x000000e5, 0x00050041, 0x00000051, 0x000000e6, 0x0000004e, 0x00000055, 0x00050041, 0x00000087, 0x000001bc, 0x000000e6, - 0x0000003f, 0x0004003d, 0x00000002, 0x000001bd, 0x000001bc, 0x00050041, 0x00000087, 0x000001be, 0x000000e6, 0x0000006c, - 0x0004003d, 0x00000002, 0x000001bf, 0x000001be, 0x00050041, 0x00000087, 0x000001c0, 0x000000e6, 0x000001a7, 0x0004003d, - 0x00000002, 0x000001c1, 0x000001c0, 0x00050041, 0x0000003d, 0x000000e9, 0x000000da, 0x00000055, 0x0003003e, 0x000000e9, - 0x000001bd, 0x00050041, 0x0000003d, 0x000000eb, 0x000000da, 0x00000050, 0x0003003e, 0x000000eb, 0x000001bf, 0x00050041, - 0x0000003d, 0x000000ed, 0x000000da, 0x0000005a, 0x0003003e, 0x000000ed, 0x000001c1, 0x000200f9, 0x000000dc, 0x000200f8, - 0x000000dc, 0x0004003d, 0x00000044, 0x000000ee, 0x000000da, 0x0003003e, 0x000000d9, 0x000000ee, 0x00050041, 0x0000003d, - 0x000000f0, 0x000000d9, 0x00000055, 0x0004003d, 0x00000002, 0x000000f1, 0x000000f0, 0x000500ae, 0x00000003, 0x000000f2, - 0x000000d8, 0x000000f1, 0x000300f7, 0x000000f4, 0x00000000, 0x000400fa, 0x000000f2, 0x000000f3, 0x000000f4, 0x000200f8, - 0x000000f3, 0x0003003e, 0x000000ba, 0x0000006c, 0x0003003e, 0x000000bb, 0x000000d8, 0x000200f9, 0x000000f4, 0x000200f8, - 0x000000f4, 0x0004003d, 0x00000002, 0x000000f6, 0x000000ba, 0x000500ab, 0x00000003, 0x000000f7, 0x000000f6, 0x0000003f, - 0x000300f7, 0x000000f9, 0x00000000, 0x000400fa, 0x000000f7, 0x000000f8, 0x000000f9, 0x000200f8, 0x000000f8, 0x0004003d, - 0x00000002, 0x000000fb, 0x000000ba, 0x000500c4, 0x00000002, 0x000000fc, 0x000000fb, 0x00000079, 0x000500c5, 0x00000002, - 0x000000fd, 0x000000fa, 0x000000fc, 0x0004003d, 0x00000002, 0x000000fe, 0x000000bb, 0x00080050, 0x00000072, 0x000000ff, - 0x00000017, 0x000000fd, 0x0000001d, 0x000000fe, 0x0000003f, 0x0003003e, 0x00000074, 0x000000ff, 0x000200fe, 0x0000007e, - 0x000200f8, 0x000000f9, 0x000200fe, 0x00000080, 0x00010038, 0x00050036, 0x00000003, 0x00000028, 0x00000000, 0x0000000c, - 0x00030037, 0x00000002, 0x00000021, 0x00030037, 0x00000002, 0x00000022, 0x00030037, 0x00000002, 0x00000023, 0x00030037, - 0x00000002, 0x00000024, 0x00030037, 0x00000002, 0x00000025, 0x00030037, 0x00000002, 0x00000026, 0x00030037, 0x00000003, - 0x00000027, 0x000200f8, 0x00000029, 0x0004003b, 0x0000003d, 0x00000103, 0x00000007, 0x0004003b, 0x0000003d, 0x00000104, - 0x00000007, 0x0004003b, 0x00000045, 0x0000011b, 0x00000007, 0x0004003b, 0x00000045, 0x0000011c, 0x00000007, 0x0003003e, - 0x00000103, 0x0000003f, 0x0003003e, 0x00000104, 0x0000003f, 0x00060041, 0x00000087, 0x00000106, 0x0000004e, 0x0000005a, - 0x00000023, 0x0004003d, 0x00000002, 0x00000107, 0x00000106, 0x00050080, 0x00000002, 0x00000108, 0x00000023, 0x0000006c, - 0x00060041, 0x00000087, 0x00000109, 0x0000004e, 0x0000005a, 0x00000108, 0x0004003d, 0x00000002, 0x0000010a, 0x00000109, - 0x00050050, 0x000000c4, 0x0000010b, 0x00000107, 0x0000010a, 0x0004007c, 0x000000bc, 0x0000010c, 0x0000010b, 0x00040078, - 0x000000c7, 0x0000010f, 0x0000010c, 0x00050080, 0x00000002, 0x00000111, 0x00000024, 0x00000026, 0x00060041, 0x000000d0, - 0x00000115, 0x0000010f, 0x00000055, 0x00000111, 0x0006003d, 0x00000002, 0x00000116, 0x00000115, 0x00000002, 0x00000004, - 0x00050084, 0x00000002, 0x00000119, 0x00000116, 0x00000025, 0x00050080, 0x00000002, 0x0000011a, 0x00000022, 0x00000119, - 0x000300f7, 0x0000011e, 0x00000000, 0x000400fa, 0x00000027, 0x0000011d, 0x00000127, 0x000200f8, 0x0000011d, 0x00050041, - 0x00000051, 0x0000011f, 0x0000004e, 0x00000050, 0x00050041, 0x00000087, 0x000001ce, 0x0000011f, 0x0000003f, 0x0004003d, - 0x00000002, 0x000001cf, 0x000001ce, 0x00050041, 0x00000087, 0x000001d0, 0x0000011f, 0x0000006c, 0x0004003d, 0x00000002, - 0x000001d1, 0x000001d0, 0x00050041, 0x00000087, 0x000001d2, 0x0000011f, 0x000001a7, 0x0004003d, 0x00000002, 0x000001d3, - 0x000001d2, 0x00050041, 0x0000003d, 0x00000122, 0x0000011c, 0x00000055, 0x0003003e, 0x00000122, 0x000001cf, 0x00050041, - 0x0000003d, 0x00000124, 0x0000011c, 0x00000050, 0x0003003e, 0x00000124, 0x000001d1, 0x00050041, 0x0000003d, 0x00000126, - 0x0000011c, 0x0000005a, 0x0003003e, 0x00000126, 0x000001d3, 0x000200f9, 0x0000011e, 0x000200f8, 0x00000127, 0x00050041, - 0x00000051, 0x00000128, 0x0000004e, 0x00000055, 0x00050041, 0x00000087, 0x000001c8, 0x00000128, 0x0000003f, 0x0004003d, - 0x00000002, 0x000001c9, 0x000001c8, 0x00050041, 0x00000087, 0x000001ca, 0x00000128, 0x0000006c, 0x0004003d, 0x00000002, - 0x000001cb, 0x000001ca, 0x00050041, 0x00000087, 0x000001cc, 0x00000128, 0x000001a7, 0x0004003d, 0x00000002, 0x000001cd, - 0x000001cc, 0x00050041, 0x0000003d, 0x0000012b, 0x0000011c, 0x00000055, 0x0003003e, 0x0000012b, 0x000001c9, 0x00050041, - 0x0000003d, 0x0000012d, 0x0000011c, 0x00000050, 0x0003003e, 0x0000012d, 0x000001cb, 0x00050041, 0x0000003d, 0x0000012f, - 0x0000011c, 0x0000005a, 0x0003003e, 0x0000012f, 0x000001cd, 0x000200f9, 0x0000011e, 0x000200f8, 0x0000011e, 0x0004003d, - 0x00000044, 0x00000130, 0x0000011c, 0x0003003e, 0x0000011b, 0x00000130, 0x00050041, 0x0000003d, 0x00000132, 0x0000011b, - 0x00000055, 0x0004003d, 0x00000002, 0x00000133, 0x00000132, 0x000500ae, 0x00000003, 0x00000134, 0x0000011a, 0x00000133, - 0x000300f7, 0x00000136, 0x00000000, 0x000400fa, 0x00000134, 0x00000135, 0x00000136, 0x000200f8, 0x00000135, 0x0003003e, - 0x00000103, 0x0000006c, 0x0003003e, 0x00000104, 0x0000011a, 0x000200f9, 0x00000136, 0x000200f8, 0x00000136, 0x0004003d, - 0x00000002, 0x00000138, 0x00000103, 0x000500ab, 0x00000003, 0x00000139, 0x00000138, 0x0000003f, 0x000300f7, 0x0000013b, - 0x00000000, 0x000400fa, 0x00000139, 0x0000013a, 0x0000013b, 0x000200f8, 0x0000013a, 0x0004003d, 0x00000002, 0x0000013d, - 0x00000103, 0x000500c4, 0x00000002, 0x0000013e, 0x0000013d, 0x00000079, 0x000500c5, 0x00000002, 0x0000013f, 0x0000013c, - 0x0000013e, 0x0004003d, 0x00000002, 0x00000140, 0x00000104, 0x00080050, 0x00000072, 0x00000141, 0x00000021, 0x0000013f, - 0x00000026, 0x00000140, 0x0000003f, 0x0003003e, 0x00000074, 0x00000141, 0x000200fe, 0x0000007e, 0x000200f8, 0x0000013b, - 0x000200fe, 0x00000080, 0x00010038, 0x00050036, 0x00000003, 0x0000002e, 0x00000000, 0x0000002a, 0x00030037, 0x00000002, - 0x0000002b, 0x00030037, 0x00000002, 0x0000002c, 0x00030037, 0x00000002, 0x0000002d, 0x000200f8, 0x0000002f, 0x000200fe, - 0x00000080, 0x00010038, 0x00050036, 0x00000003, 0x00000031, 0x00000000, 0x00000030, 0x000200f8, 0x00000032, 0x000200fe, - 0x00000080, 0x00010038, 0x00050036, 0x00000003, 0x00000036, 0x00000000, 0x00000033, 0x00030037, 0x00000002, 0x00000034, - 0x00030037, 0x00000002, 0x00000035, 0x000200f8, 0x00000037, 0x000200fe, 0x00000080, 0x00010038, 0x00050036, 0x00000003, - 0x0000003b, 0x00000000, 0x0000002a, 0x00030037, 0x00000002, 0x00000038, 0x00030037, 0x00000002, 0x00000039, 0x00030037, - 0x00000002, 0x0000003a, 0x000200f8, 0x0000003c, 0x000200fe, 0x00000080, 0x00010038}; -[[maybe_unused]] const uint32_t instrumentation_descriptor_heap_comp_function_0_offset = 969; -[[maybe_unused]] const uint32_t instrumentation_descriptor_heap_comp_function_1_offset = 1246; -[[maybe_unused]] const uint32_t instrumentation_descriptor_heap_comp_function_2_offset = 1549; -[[maybe_unused]] const uint32_t instrumentation_descriptor_heap_comp_function_3_offset = 1895; -[[maybe_unused]] const uint32_t instrumentation_descriptor_heap_comp_function_4_offset = 2233; -[[maybe_unused]] const uint32_t instrumentation_descriptor_heap_comp_function_5_offset = 2252; -[[maybe_unused]] const uint32_t instrumentation_descriptor_heap_comp_function_6_offset = 2262; -[[maybe_unused]] const uint32_t instrumentation_descriptor_heap_comp_function_7_offset = 2278; + 0x00000030, 0x00000003, 0x00050021, 0x00000033, 0x00000003, 0x00000002, 0x00000002, 0x00040020, 0x00000044, 0x00000007, + 0x00000002, 0x0004002b, 0x00000002, 0x00000046, 0x00000000, 0x0005001e, 0x0000004b, 0x00000002, 0x00000002, 0x00000002, + 0x00040020, 0x0000004c, 0x00000007, 0x0000004b, 0x0005001e, 0x00000051, 0x00000002, 0x00000002, 0x00000002, 0x0003001d, + 0x00000052, 0x00000002, 0x0005001e, 0x00000053, 0x00000051, 0x00000051, 0x00000052, 0x00040020, 0x00000054, 0x0000000c, + 0x00000053, 0x0004003b, 0x00000054, 0x00000055, 0x0000000c, 0x00040015, 0x00000056, 0x00000020, 0x00000001, 0x0004002b, + 0x00000056, 0x00000057, 0x00000001, 0x00040020, 0x00000058, 0x0000000c, 0x00000051, 0x0004002b, 0x00000056, 0x0000005c, + 0x00000000, 0x0004002b, 0x00000056, 0x00000061, 0x00000002, 0x0004002b, 0x00000002, 0x00000073, 0x00000001, 0x0007001e, + 0x00000079, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00040020, 0x0000007a, 0x00000006, 0x00000079, + 0x0004003b, 0x0000007a, 0x0000007b, 0x00000006, 0x00040032, 0x00000002, 0x0000007c, 0x0dead001, 0x0004002b, 0x00000002, + 0x0000007d, 0x11000000, 0x00060034, 0x00000002, 0x0000007e, 0x000000c5, 0x0000007c, 0x0000007d, 0x0004002b, 0x00000056, + 0x00000080, 0x00000012, 0x0003002a, 0x00000003, 0x00000085, 0x00030029, 0x00000003, 0x00000087, 0x00040020, 0x0000008e, + 0x0000000c, 0x00000002, 0x00060034, 0x00000002, 0x000000b8, 0x000000c5, 0x0000007c, 0x0000007d, 0x00040015, 0x000000c3, + 0x00000040, 0x00000000, 0x00040017, 0x000000cb, 0x00000002, 0x00000002, 0x00030027, 0x000000ce, 0x000014e5, 0x0003001d, + 0x000000cf, 0x00000002, 0x0003001e, 0x000000d0, 0x000000cf, 0x00040020, 0x000000ce, 0x000014e5, 0x000000d0, 0x00040020, + 0x000000d7, 0x000014e5, 0x00000002, 0x00060034, 0x00000002, 0x00000101, 0x000000c5, 0x0000007c, 0x0000007d, 0x00060034, + 0x00000002, 0x00000143, 0x000000c5, 0x0000007c, 0x0000007d, 0x00060034, 0x00000002, 0x0000017a, 0x000000c5, 0x0000007c, + 0x0000007d, 0x0004002b, 0x00000002, 0x000001dd, 0x00000002, 0x00050036, 0x00000003, 0x0000000a, 0x00000000, 0x00000004, + 0x00030037, 0x00000002, 0x00000005, 0x00030037, 0x00000002, 0x00000006, 0x00030037, 0x00000002, 0x00000007, 0x00030037, + 0x00000002, 0x00000008, 0x00030037, 0x00000003, 0x00000009, 0x000200f8, 0x0000000b, 0x0004003b, 0x00000044, 0x00000045, + 0x00000007, 0x0004003b, 0x00000044, 0x00000047, 0x00000007, 0x0004003b, 0x0000004c, 0x0000004d, 0x00000007, 0x0004003b, + 0x0000004c, 0x0000004e, 0x00000007, 0x0003003e, 0x00000045, 0x00000046, 0x0003003e, 0x00000047, 0x00000046, 0x00050084, + 0x00000002, 0x00000049, 0x00000008, 0x00000007, 0x00050080, 0x00000002, 0x0000004a, 0x00000006, 0x00000049, 0x000300f7, + 0x00000050, 0x00000000, 0x000400fa, 0x00000009, 0x0000004f, 0x00000063, 0x000200f8, 0x0000004f, 0x00050041, 0x00000058, + 0x00000059, 0x00000055, 0x00000057, 0x00050041, 0x0000008e, 0x000001e0, 0x00000059, 0x00000046, 0x0004003d, 0x00000002, + 0x000001e1, 0x000001e0, 0x00050041, 0x0000008e, 0x000001e2, 0x00000059, 0x00000073, 0x0004003d, 0x00000002, 0x000001e3, + 0x000001e2, 0x00050041, 0x0000008e, 0x000001e4, 0x00000059, 0x000001dd, 0x0004003d, 0x00000002, 0x000001e5, 0x000001e4, + 0x00050041, 0x00000044, 0x0000005d, 0x0000004e, 0x0000005c, 0x0003003e, 0x0000005d, 0x000001e1, 0x00050041, 0x00000044, + 0x0000005f, 0x0000004e, 0x00000057, 0x0003003e, 0x0000005f, 0x000001e3, 0x00050041, 0x00000044, 0x00000062, 0x0000004e, + 0x00000061, 0x0003003e, 0x00000062, 0x000001e5, 0x000200f9, 0x00000050, 0x000200f8, 0x00000063, 0x00050041, 0x00000058, + 0x00000064, 0x00000055, 0x0000005c, 0x00050041, 0x0000008e, 0x000001d9, 0x00000064, 0x00000046, 0x0004003d, 0x00000002, + 0x000001da, 0x000001d9, 0x00050041, 0x0000008e, 0x000001db, 0x00000064, 0x00000073, 0x0004003d, 0x00000002, 0x000001dc, + 0x000001db, 0x00050041, 0x0000008e, 0x000001de, 0x00000064, 0x000001dd, 0x0004003d, 0x00000002, 0x000001df, 0x000001de, + 0x00050041, 0x00000044, 0x00000067, 0x0000004e, 0x0000005c, 0x0003003e, 0x00000067, 0x000001da, 0x00050041, 0x00000044, + 0x00000069, 0x0000004e, 0x00000057, 0x0003003e, 0x00000069, 0x000001dc, 0x00050041, 0x00000044, 0x0000006b, 0x0000004e, + 0x00000061, 0x0003003e, 0x0000006b, 0x000001df, 0x000200f9, 0x00000050, 0x000200f8, 0x00000050, 0x0004003d, 0x0000004b, + 0x0000006c, 0x0000004e, 0x0003003e, 0x0000004d, 0x0000006c, 0x00050041, 0x00000044, 0x0000006e, 0x0000004d, 0x0000005c, + 0x0004003d, 0x00000002, 0x0000006f, 0x0000006e, 0x000500ae, 0x00000003, 0x00000070, 0x0000004a, 0x0000006f, 0x000300f7, + 0x00000072, 0x00000000, 0x000400fa, 0x00000070, 0x00000071, 0x00000072, 0x000200f8, 0x00000071, 0x0003003e, 0x00000045, + 0x00000073, 0x0003003e, 0x00000047, 0x0000004a, 0x000200f9, 0x00000072, 0x000200f8, 0x00000072, 0x0004003d, 0x00000002, + 0x00000075, 0x00000045, 0x000500ab, 0x00000003, 0x00000076, 0x00000075, 0x00000046, 0x000300f7, 0x00000078, 0x00000000, + 0x000400fa, 0x00000076, 0x00000077, 0x00000078, 0x000200f8, 0x00000077, 0x0004003d, 0x00000002, 0x0000007f, 0x00000045, + 0x000500c4, 0x00000002, 0x00000081, 0x0000007f, 0x00000080, 0x000500c5, 0x00000002, 0x00000082, 0x0000007e, 0x00000081, + 0x0004003d, 0x00000002, 0x00000083, 0x00000047, 0x00080050, 0x00000079, 0x00000084, 0x00000005, 0x00000082, 0x00000008, + 0x00000083, 0x00000046, 0x0003003e, 0x0000007b, 0x00000084, 0x000200fe, 0x00000085, 0x000200f8, 0x00000078, 0x000200fe, + 0x00000087, 0x00010038, 0x00050036, 0x00000003, 0x00000014, 0x00000000, 0x0000000c, 0x00030037, 0x00000002, 0x0000000d, + 0x00030037, 0x00000002, 0x0000000e, 0x00030037, 0x00000002, 0x0000000f, 0x00030037, 0x00000002, 0x00000010, 0x00030037, + 0x00000002, 0x00000011, 0x00030037, 0x00000002, 0x00000012, 0x00030037, 0x00000003, 0x00000013, 0x000200f8, 0x00000015, + 0x0004003b, 0x00000044, 0x0000008b, 0x00000007, 0x0004003b, 0x00000044, 0x0000008c, 0x00000007, 0x0004003b, 0x0000004c, + 0x00000097, 0x00000007, 0x0004003b, 0x0000004c, 0x00000098, 0x00000007, 0x0003003e, 0x0000008b, 0x00000046, 0x0003003e, + 0x0000008c, 0x00000046, 0x00060041, 0x0000008e, 0x0000008f, 0x00000055, 0x00000061, 0x0000000f, 0x0004003d, 0x00000002, + 0x00000090, 0x0000008f, 0x00050084, 0x00000002, 0x00000093, 0x00000090, 0x00000010, 0x00050080, 0x00000002, 0x00000094, + 0x0000000e, 0x00000093, 0x00050084, 0x00000002, 0x00000095, 0x00000012, 0x00000011, 0x00050080, 0x00000002, 0x00000096, + 0x00000094, 0x00000095, 0x000300f7, 0x0000009a, 0x00000000, 0x000400fa, 0x00000013, 0x00000099, 0x000000a3, 0x000200f8, + 0x00000099, 0x00050041, 0x00000058, 0x0000009b, 0x00000055, 0x00000057, 0x00050041, 0x0000008e, 0x000001ec, 0x0000009b, + 0x00000046, 0x0004003d, 0x00000002, 0x000001ed, 0x000001ec, 0x00050041, 0x0000008e, 0x000001ee, 0x0000009b, 0x00000073, + 0x0004003d, 0x00000002, 0x000001ef, 0x000001ee, 0x00050041, 0x0000008e, 0x000001f0, 0x0000009b, 0x000001dd, 0x0004003d, + 0x00000002, 0x000001f1, 0x000001f0, 0x00050041, 0x00000044, 0x0000009e, 0x00000098, 0x0000005c, 0x0003003e, 0x0000009e, + 0x000001ed, 0x00050041, 0x00000044, 0x000000a0, 0x00000098, 0x00000057, 0x0003003e, 0x000000a0, 0x000001ef, 0x00050041, + 0x00000044, 0x000000a2, 0x00000098, 0x00000061, 0x0003003e, 0x000000a2, 0x000001f1, 0x000200f9, 0x0000009a, 0x000200f8, + 0x000000a3, 0x00050041, 0x00000058, 0x000000a4, 0x00000055, 0x0000005c, 0x00050041, 0x0000008e, 0x000001e6, 0x000000a4, + 0x00000046, 0x0004003d, 0x00000002, 0x000001e7, 0x000001e6, 0x00050041, 0x0000008e, 0x000001e8, 0x000000a4, 0x00000073, + 0x0004003d, 0x00000002, 0x000001e9, 0x000001e8, 0x00050041, 0x0000008e, 0x000001ea, 0x000000a4, 0x000001dd, 0x0004003d, + 0x00000002, 0x000001eb, 0x000001ea, 0x00050041, 0x00000044, 0x000000a7, 0x00000098, 0x0000005c, 0x0003003e, 0x000000a7, + 0x000001e7, 0x00050041, 0x00000044, 0x000000a9, 0x00000098, 0x00000057, 0x0003003e, 0x000000a9, 0x000001e9, 0x00050041, + 0x00000044, 0x000000ab, 0x00000098, 0x00000061, 0x0003003e, 0x000000ab, 0x000001eb, 0x000200f9, 0x0000009a, 0x000200f8, + 0x0000009a, 0x0004003d, 0x0000004b, 0x000000ac, 0x00000098, 0x0003003e, 0x00000097, 0x000000ac, 0x00050041, 0x00000044, + 0x000000ae, 0x00000097, 0x0000005c, 0x0004003d, 0x00000002, 0x000000af, 0x000000ae, 0x000500ae, 0x00000003, 0x000000b0, + 0x00000096, 0x000000af, 0x000300f7, 0x000000b2, 0x00000000, 0x000400fa, 0x000000b0, 0x000000b1, 0x000000b2, 0x000200f8, + 0x000000b1, 0x0003003e, 0x0000008b, 0x00000073, 0x0003003e, 0x0000008c, 0x00000096, 0x000200f9, 0x000000b2, 0x000200f8, + 0x000000b2, 0x0004003d, 0x00000002, 0x000000b4, 0x0000008b, 0x000500ab, 0x00000003, 0x000000b5, 0x000000b4, 0x00000046, + 0x000300f7, 0x000000b7, 0x00000000, 0x000400fa, 0x000000b5, 0x000000b6, 0x000000b7, 0x000200f8, 0x000000b6, 0x0004003d, + 0x00000002, 0x000000b9, 0x0000008b, 0x000500c4, 0x00000002, 0x000000ba, 0x000000b9, 0x00000080, 0x000500c5, 0x00000002, + 0x000000bb, 0x000000b8, 0x000000ba, 0x0004003d, 0x00000002, 0x000000bc, 0x0000008c, 0x00080050, 0x00000079, 0x000000bd, + 0x0000000d, 0x000000bb, 0x00000012, 0x000000bc, 0x00000046, 0x0003003e, 0x0000007b, 0x000000bd, 0x000200fe, 0x00000085, + 0x000200f8, 0x000000b7, 0x000200fe, 0x00000087, 0x00010038, 0x00050036, 0x00000003, 0x0000001f, 0x00000000, 0x00000016, + 0x00030037, 0x00000002, 0x00000017, 0x00030037, 0x00000002, 0x00000018, 0x00030037, 0x00000002, 0x00000019, 0x00030037, + 0x00000002, 0x0000001a, 0x00030037, 0x00000002, 0x0000001b, 0x00030037, 0x00000002, 0x0000001c, 0x00030037, 0x00000002, + 0x0000001d, 0x00030037, 0x00000003, 0x0000001e, 0x000200f8, 0x00000020, 0x0004003b, 0x00000044, 0x000000c1, 0x00000007, + 0x0004003b, 0x00000044, 0x000000c2, 0x00000007, 0x0004003b, 0x0000004c, 0x000000e0, 0x00000007, 0x0004003b, 0x0000004c, + 0x000000e1, 0x00000007, 0x0003003e, 0x000000c1, 0x00000046, 0x0003003e, 0x000000c2, 0x00000046, 0x00060041, 0x0000008e, + 0x000000c6, 0x00000055, 0x00000061, 0x00000019, 0x0004003d, 0x00000002, 0x000000c7, 0x000000c6, 0x00050080, 0x00000002, + 0x000000c8, 0x00000019, 0x00000073, 0x00060041, 0x0000008e, 0x000000c9, 0x00000055, 0x00000061, 0x000000c8, 0x0004003d, + 0x00000002, 0x000000ca, 0x000000c9, 0x00050050, 0x000000cb, 0x000000cc, 0x000000c7, 0x000000ca, 0x0004007c, 0x000000c3, + 0x000000cd, 0x000000cc, 0x00040078, 0x000000ce, 0x000000d4, 0x000000cd, 0x00060041, 0x000000d7, 0x000000d8, 0x000000d4, + 0x0000005c, 0x0000001a, 0x0006003d, 0x00000002, 0x000000d9, 0x000000d8, 0x00000002, 0x00000004, 0x00050084, 0x00000002, + 0x000000dc, 0x000000d9, 0x0000001b, 0x00050080, 0x00000002, 0x000000dd, 0x00000018, 0x000000dc, 0x00050084, 0x00000002, + 0x000000de, 0x0000001d, 0x0000001c, 0x00050080, 0x00000002, 0x000000df, 0x000000dd, 0x000000de, 0x000300f7, 0x000000e3, + 0x00000000, 0x000400fa, 0x0000001e, 0x000000e2, 0x000000ec, 0x000200f8, 0x000000e2, 0x00050041, 0x00000058, 0x000000e4, + 0x00000055, 0x00000057, 0x00050041, 0x0000008e, 0x000001f8, 0x000000e4, 0x00000046, 0x0004003d, 0x00000002, 0x000001f9, + 0x000001f8, 0x00050041, 0x0000008e, 0x000001fa, 0x000000e4, 0x00000073, 0x0004003d, 0x00000002, 0x000001fb, 0x000001fa, + 0x00050041, 0x0000008e, 0x000001fc, 0x000000e4, 0x000001dd, 0x0004003d, 0x00000002, 0x000001fd, 0x000001fc, 0x00050041, + 0x00000044, 0x000000e7, 0x000000e1, 0x0000005c, 0x0003003e, 0x000000e7, 0x000001f9, 0x00050041, 0x00000044, 0x000000e9, + 0x000000e1, 0x00000057, 0x0003003e, 0x000000e9, 0x000001fb, 0x00050041, 0x00000044, 0x000000eb, 0x000000e1, 0x00000061, + 0x0003003e, 0x000000eb, 0x000001fd, 0x000200f9, 0x000000e3, 0x000200f8, 0x000000ec, 0x00050041, 0x00000058, 0x000000ed, + 0x00000055, 0x0000005c, 0x00050041, 0x0000008e, 0x000001f2, 0x000000ed, 0x00000046, 0x0004003d, 0x00000002, 0x000001f3, + 0x000001f2, 0x00050041, 0x0000008e, 0x000001f4, 0x000000ed, 0x00000073, 0x0004003d, 0x00000002, 0x000001f5, 0x000001f4, + 0x00050041, 0x0000008e, 0x000001f6, 0x000000ed, 0x000001dd, 0x0004003d, 0x00000002, 0x000001f7, 0x000001f6, 0x00050041, + 0x00000044, 0x000000f0, 0x000000e1, 0x0000005c, 0x0003003e, 0x000000f0, 0x000001f3, 0x00050041, 0x00000044, 0x000000f2, + 0x000000e1, 0x00000057, 0x0003003e, 0x000000f2, 0x000001f5, 0x00050041, 0x00000044, 0x000000f4, 0x000000e1, 0x00000061, + 0x0003003e, 0x000000f4, 0x000001f7, 0x000200f9, 0x000000e3, 0x000200f8, 0x000000e3, 0x0004003d, 0x0000004b, 0x000000f5, + 0x000000e1, 0x0003003e, 0x000000e0, 0x000000f5, 0x00050041, 0x00000044, 0x000000f7, 0x000000e0, 0x0000005c, 0x0004003d, + 0x00000002, 0x000000f8, 0x000000f7, 0x000500ae, 0x00000003, 0x000000f9, 0x000000df, 0x000000f8, 0x000300f7, 0x000000fb, + 0x00000000, 0x000400fa, 0x000000f9, 0x000000fa, 0x000000fb, 0x000200f8, 0x000000fa, 0x0003003e, 0x000000c1, 0x00000073, + 0x0003003e, 0x000000c2, 0x000000df, 0x000200f9, 0x000000fb, 0x000200f8, 0x000000fb, 0x0004003d, 0x00000002, 0x000000fd, + 0x000000c1, 0x000500ab, 0x00000003, 0x000000fe, 0x000000fd, 0x00000046, 0x000300f7, 0x00000100, 0x00000000, 0x000400fa, + 0x000000fe, 0x000000ff, 0x00000100, 0x000200f8, 0x000000ff, 0x0004003d, 0x00000002, 0x00000102, 0x000000c1, 0x000500c4, + 0x00000002, 0x00000103, 0x00000102, 0x00000080, 0x000500c5, 0x00000002, 0x00000104, 0x00000101, 0x00000103, 0x0004003d, + 0x00000002, 0x00000105, 0x000000c2, 0x00080050, 0x00000079, 0x00000106, 0x00000017, 0x00000104, 0x0000001d, 0x00000105, + 0x00000046, 0x0003003e, 0x0000007b, 0x00000106, 0x000200fe, 0x00000085, 0x000200f8, 0x00000100, 0x000200fe, 0x00000087, + 0x00010038, 0x00050036, 0x00000003, 0x00000028, 0x00000000, 0x0000000c, 0x00030037, 0x00000002, 0x00000021, 0x00030037, + 0x00000002, 0x00000022, 0x00030037, 0x00000002, 0x00000023, 0x00030037, 0x00000002, 0x00000024, 0x00030037, 0x00000002, + 0x00000025, 0x00030037, 0x00000002, 0x00000026, 0x00030037, 0x00000003, 0x00000027, 0x000200f8, 0x00000029, 0x0004003b, + 0x00000044, 0x0000010a, 0x00000007, 0x0004003b, 0x00000044, 0x0000010b, 0x00000007, 0x0004003b, 0x0000004c, 0x00000122, + 0x00000007, 0x0004003b, 0x0000004c, 0x00000123, 0x00000007, 0x0003003e, 0x0000010a, 0x00000046, 0x0003003e, 0x0000010b, + 0x00000046, 0x00060041, 0x0000008e, 0x0000010d, 0x00000055, 0x00000061, 0x00000023, 0x0004003d, 0x00000002, 0x0000010e, + 0x0000010d, 0x00050080, 0x00000002, 0x0000010f, 0x00000023, 0x00000073, 0x00060041, 0x0000008e, 0x00000110, 0x00000055, + 0x00000061, 0x0000010f, 0x0004003d, 0x00000002, 0x00000111, 0x00000110, 0x00050050, 0x000000cb, 0x00000112, 0x0000010e, + 0x00000111, 0x0004007c, 0x000000c3, 0x00000113, 0x00000112, 0x00040078, 0x000000ce, 0x00000116, 0x00000113, 0x00050080, + 0x00000002, 0x00000118, 0x00000024, 0x00000026, 0x00060041, 0x000000d7, 0x0000011c, 0x00000116, 0x0000005c, 0x00000118, + 0x0006003d, 0x00000002, 0x0000011d, 0x0000011c, 0x00000002, 0x00000004, 0x00050084, 0x00000002, 0x00000120, 0x0000011d, + 0x00000025, 0x00050080, 0x00000002, 0x00000121, 0x00000022, 0x00000120, 0x000300f7, 0x00000125, 0x00000000, 0x000400fa, + 0x00000027, 0x00000124, 0x0000012e, 0x000200f8, 0x00000124, 0x00050041, 0x00000058, 0x00000126, 0x00000055, 0x00000057, + 0x00050041, 0x0000008e, 0x00000204, 0x00000126, 0x00000046, 0x0004003d, 0x00000002, 0x00000205, 0x00000204, 0x00050041, + 0x0000008e, 0x00000206, 0x00000126, 0x00000073, 0x0004003d, 0x00000002, 0x00000207, 0x00000206, 0x00050041, 0x0000008e, + 0x00000208, 0x00000126, 0x000001dd, 0x0004003d, 0x00000002, 0x00000209, 0x00000208, 0x00050041, 0x00000044, 0x00000129, + 0x00000123, 0x0000005c, 0x0003003e, 0x00000129, 0x00000205, 0x00050041, 0x00000044, 0x0000012b, 0x00000123, 0x00000057, + 0x0003003e, 0x0000012b, 0x00000207, 0x00050041, 0x00000044, 0x0000012d, 0x00000123, 0x00000061, 0x0003003e, 0x0000012d, + 0x00000209, 0x000200f9, 0x00000125, 0x000200f8, 0x0000012e, 0x00050041, 0x00000058, 0x0000012f, 0x00000055, 0x0000005c, + 0x00050041, 0x0000008e, 0x000001fe, 0x0000012f, 0x00000046, 0x0004003d, 0x00000002, 0x000001ff, 0x000001fe, 0x00050041, + 0x0000008e, 0x00000200, 0x0000012f, 0x00000073, 0x0004003d, 0x00000002, 0x00000201, 0x00000200, 0x00050041, 0x0000008e, + 0x00000202, 0x0000012f, 0x000001dd, 0x0004003d, 0x00000002, 0x00000203, 0x00000202, 0x00050041, 0x00000044, 0x00000132, + 0x00000123, 0x0000005c, 0x0003003e, 0x00000132, 0x000001ff, 0x00050041, 0x00000044, 0x00000134, 0x00000123, 0x00000057, + 0x0003003e, 0x00000134, 0x00000201, 0x00050041, 0x00000044, 0x00000136, 0x00000123, 0x00000061, 0x0003003e, 0x00000136, + 0x00000203, 0x000200f9, 0x00000125, 0x000200f8, 0x00000125, 0x0004003d, 0x0000004b, 0x00000137, 0x00000123, 0x0003003e, + 0x00000122, 0x00000137, 0x00050041, 0x00000044, 0x00000139, 0x00000122, 0x0000005c, 0x0004003d, 0x00000002, 0x0000013a, + 0x00000139, 0x000500ae, 0x00000003, 0x0000013b, 0x00000121, 0x0000013a, 0x000300f7, 0x0000013d, 0x00000000, 0x000400fa, + 0x0000013b, 0x0000013c, 0x0000013d, 0x000200f8, 0x0000013c, 0x0003003e, 0x0000010a, 0x00000073, 0x0003003e, 0x0000010b, + 0x00000121, 0x000200f9, 0x0000013d, 0x000200f8, 0x0000013d, 0x0004003d, 0x00000002, 0x0000013f, 0x0000010a, 0x000500ab, + 0x00000003, 0x00000140, 0x0000013f, 0x00000046, 0x000300f7, 0x00000142, 0x00000000, 0x000400fa, 0x00000140, 0x00000141, + 0x00000142, 0x000200f8, 0x00000141, 0x0004003d, 0x00000002, 0x00000144, 0x0000010a, 0x000500c4, 0x00000002, 0x00000145, + 0x00000144, 0x00000080, 0x000500c5, 0x00000002, 0x00000146, 0x00000143, 0x00000145, 0x0004003d, 0x00000002, 0x00000147, + 0x0000010b, 0x00080050, 0x00000079, 0x00000148, 0x00000021, 0x00000146, 0x00000026, 0x00000147, 0x00000046, 0x0003003e, + 0x0000007b, 0x00000148, 0x000200fe, 0x00000085, 0x000200f8, 0x00000142, 0x000200fe, 0x00000087, 0x00010038, 0x00050036, + 0x00000003, 0x0000002e, 0x00000000, 0x0000002a, 0x00030037, 0x00000002, 0x0000002b, 0x00030037, 0x00000002, 0x0000002c, + 0x00030037, 0x00000002, 0x0000002d, 0x000200f8, 0x0000002f, 0x000200fe, 0x00000087, 0x00010038, 0x00050036, 0x00000003, + 0x00000031, 0x00000000, 0x00000030, 0x000200f8, 0x00000032, 0x000200fe, 0x00000087, 0x00010038, 0x00050036, 0x00000003, + 0x00000036, 0x00000000, 0x00000033, 0x00030037, 0x00000002, 0x00000034, 0x00030037, 0x00000002, 0x00000035, 0x000200f8, + 0x00000037, 0x000200fe, 0x00000087, 0x00010038, 0x00050036, 0x00000003, 0x0000003b, 0x00000000, 0x0000002a, 0x00030037, + 0x00000002, 0x00000038, 0x00030037, 0x00000002, 0x00000039, 0x00030037, 0x00000002, 0x0000003a, 0x000200f8, 0x0000003c, + 0x000200fe, 0x00000087, 0x00010038, 0x00050036, 0x00000003, 0x00000042, 0x00000000, 0x00000004, 0x00030037, 0x00000002, + 0x0000003d, 0x00030037, 0x00000002, 0x0000003e, 0x00030037, 0x00000002, 0x0000003f, 0x00030037, 0x00000002, 0x00000040, + 0x00030037, 0x00000003, 0x00000041, 0x000200f8, 0x00000043, 0x0004003b, 0x00000044, 0x00000154, 0x00000007, 0x0004003b, + 0x00000044, 0x00000155, 0x00000007, 0x0004003b, 0x0000004c, 0x00000159, 0x00000007, 0x0004003b, 0x0000004c, 0x0000015a, + 0x00000007, 0x0003003e, 0x00000154, 0x00000046, 0x0003003e, 0x00000155, 0x00000046, 0x00050084, 0x00000002, 0x00000157, + 0x00000040, 0x0000003f, 0x00050080, 0x00000002, 0x00000158, 0x0000003e, 0x00000157, 0x000300f7, 0x0000015c, 0x00000000, + 0x000400fa, 0x00000041, 0x0000015b, 0x00000165, 0x000200f8, 0x0000015b, 0x00050041, 0x00000058, 0x0000015d, 0x00000055, + 0x00000057, 0x00050041, 0x0000008e, 0x00000210, 0x0000015d, 0x00000046, 0x0004003d, 0x00000002, 0x00000211, 0x00000210, + 0x00050041, 0x0000008e, 0x00000212, 0x0000015d, 0x00000073, 0x0004003d, 0x00000002, 0x00000213, 0x00000212, 0x00050041, + 0x0000008e, 0x00000214, 0x0000015d, 0x000001dd, 0x0004003d, 0x00000002, 0x00000215, 0x00000214, 0x00050041, 0x00000044, + 0x00000160, 0x0000015a, 0x0000005c, 0x0003003e, 0x00000160, 0x00000211, 0x00050041, 0x00000044, 0x00000162, 0x0000015a, + 0x00000057, 0x0003003e, 0x00000162, 0x00000213, 0x00050041, 0x00000044, 0x00000164, 0x0000015a, 0x00000061, 0x0003003e, + 0x00000164, 0x00000215, 0x000200f9, 0x0000015c, 0x000200f8, 0x00000165, 0x00050041, 0x00000058, 0x00000166, 0x00000055, + 0x0000005c, 0x00050041, 0x0000008e, 0x0000020a, 0x00000166, 0x00000046, 0x0004003d, 0x00000002, 0x0000020b, 0x0000020a, + 0x00050041, 0x0000008e, 0x0000020c, 0x00000166, 0x00000073, 0x0004003d, 0x00000002, 0x0000020d, 0x0000020c, 0x00050041, + 0x0000008e, 0x0000020e, 0x00000166, 0x000001dd, 0x0004003d, 0x00000002, 0x0000020f, 0x0000020e, 0x00050041, 0x00000044, + 0x00000169, 0x0000015a, 0x0000005c, 0x0003003e, 0x00000169, 0x0000020b, 0x00050041, 0x00000044, 0x0000016b, 0x0000015a, + 0x00000057, 0x0003003e, 0x0000016b, 0x0000020d, 0x00050041, 0x00000044, 0x0000016d, 0x0000015a, 0x00000061, 0x0003003e, + 0x0000016d, 0x0000020f, 0x000200f9, 0x0000015c, 0x000200f8, 0x0000015c, 0x0004003d, 0x0000004b, 0x0000016e, 0x0000015a, + 0x0003003e, 0x00000159, 0x0000016e, 0x00050041, 0x00000044, 0x00000170, 0x00000159, 0x0000005c, 0x0004003d, 0x00000002, + 0x00000171, 0x00000170, 0x000500ae, 0x00000003, 0x00000172, 0x00000158, 0x00000171, 0x000300f7, 0x00000174, 0x00000000, + 0x000400fa, 0x00000172, 0x00000173, 0x00000174, 0x000200f8, 0x00000173, 0x0003003e, 0x00000154, 0x00000073, 0x0003003e, + 0x00000155, 0x00000158, 0x000200f9, 0x00000174, 0x000200f8, 0x00000174, 0x0004003d, 0x00000002, 0x00000176, 0x00000154, + 0x000500ab, 0x00000003, 0x00000177, 0x00000176, 0x00000046, 0x000300f7, 0x00000179, 0x00000000, 0x000400fa, 0x00000177, + 0x00000178, 0x00000179, 0x000200f8, 0x00000178, 0x0004003d, 0x00000002, 0x0000017b, 0x00000154, 0x000500c4, 0x00000002, + 0x0000017c, 0x0000017b, 0x00000080, 0x000500c5, 0x00000002, 0x0000017d, 0x0000017a, 0x0000017c, 0x0004003d, 0x00000002, + 0x0000017e, 0x00000155, 0x00080050, 0x00000079, 0x0000017f, 0x0000003d, 0x0000017d, 0x00000040, 0x0000017e, 0x00000046, + 0x0003003e, 0x0000007b, 0x0000017f, 0x000200fe, 0x00000085, 0x000200f8, 0x00000179, 0x000200fe, 0x00000087, 0x00010038}; +[[maybe_unused]] const uint32_t instrumentation_descriptor_heap_comp_function_0_offset = 1035; +[[maybe_unused]] const uint32_t instrumentation_descriptor_heap_comp_function_1_offset = 1312; +[[maybe_unused]] const uint32_t instrumentation_descriptor_heap_comp_function_2_offset = 1615; +[[maybe_unused]] const uint32_t instrumentation_descriptor_heap_comp_function_3_offset = 1961; +[[maybe_unused]] const uint32_t instrumentation_descriptor_heap_comp_function_4_offset = 2299; +[[maybe_unused]] const uint32_t instrumentation_descriptor_heap_comp_function_5_offset = 2318; +[[maybe_unused]] const uint32_t instrumentation_descriptor_heap_comp_function_6_offset = 2328; +[[maybe_unused]] const uint32_t instrumentation_descriptor_heap_comp_function_7_offset = 2344; +[[maybe_unused]] const uint32_t instrumentation_descriptor_heap_comp_function_8_offset = 2363; [[maybe_unused]] const uint32_t instrumentation_descriptor_indexing_oob_comp_size = 1599; [[maybe_unused]] const uint32_t instrumentation_descriptor_indexing_oob_comp[1599] = {
diff --git a/layers/vulkan/generated/gpuav_offline_spirv.h b/layers/vulkan/generated/gpuav_offline_spirv.h index 57d2675..4e2b2f0 100644 --- a/layers/vulkan/generated/gpuav_offline_spirv.h +++ b/layers/vulkan/generated/gpuav_offline_spirv.h
@@ -55,6 +55,7 @@ extern const uint32_t instrumentation_descriptor_heap_comp_function_5_offset; extern const uint32_t instrumentation_descriptor_heap_comp_function_6_offset; extern const uint32_t instrumentation_descriptor_heap_comp_function_7_offset; +extern const uint32_t instrumentation_descriptor_heap_comp_function_8_offset; extern const uint32_t instrumentation_descriptor_indexing_oob_comp_size; extern const uint32_t instrumentation_descriptor_indexing_oob_comp[];
diff --git a/tests/unit/gpu_av_descriptor_heap.cpp b/tests/unit/gpu_av_descriptor_heap.cpp index 335fe36..45e8249 100644 --- a/tests/unit/gpu_av_descriptor_heap.cpp +++ b/tests/unit/gpu_av_descriptor_heap.cpp
@@ -17,6 +17,7 @@ #include "../framework/buffer_helper.h" #include "../utils/math_utils.h" #include "gpuav/shaders/gpuav_shaders_constants.h" +#include "shader_helper.h" #include "shader_templates.h" void GpuAVDescriptorHeap::CreateResourceHeap(VkDeviceSize app_size, bool reserved_range_in_front) { @@ -1523,4 +1524,415 @@ m_errorMonitor->SetDesiredError("VUID-vkCmdDispatch-None-11309", 2); m_default_queue->SubmitAndWait(m_command_buffer); m_errorMonitor->VerifyFound(); +} + +TEST_F(NegativeGpuAVDescriptorHeap, ResourceOOBUntypedPointersBuffer) { + AddRequiredExtensions(VK_KHR_SHADER_UNTYPED_POINTERS_EXTENSION_NAME); + AddRequiredFeature(vkt::Feature::shaderUntypedPointers); + RETURN_IF_SKIP(InitGpuAVDescriptorHeap()); + if ((heap_props.minResourceHeapReservedRange / heap_props.bufferDescriptorSize) >= 10000) { + GTEST_SKIP() << "reserved range is too large, access will not be OOB"; + } + const VkDeviceSize resource_stride = heap_props.bufferDescriptorSize; + CreateResourceHeap(resource_stride); + + const char* cs_source = R"glsl( + #version 450 + #extension GL_EXT_descriptor_heap : require + layout (descriptor_heap) buffer SSBO_0 { + uint data; + } heapBuffer[]; + + void main() { + // Something large enough to get pass the reserved range + heapBuffer[10000].data = 0; + } + )glsl"; + + VkShaderObj cs_module = VkShaderObj(*m_device, cs_source, VK_SHADER_STAGE_COMPUTE_BIT, SPV_ENV_VULKAN_1_2); + + VkPipelineCreateFlags2CreateInfoKHR pipeline_create_flags_2_create_info = vku::InitStructHelper(); + pipeline_create_flags_2_create_info.flags = VK_PIPELINE_CREATE_2_DESCRIPTOR_HEAP_BIT_EXT; + + CreateComputePipelineHelper pipe(*this, &pipeline_create_flags_2_create_info); + pipe.cp_ci_.stage = cs_module.GetStageCreateInfo(); + pipe.cp_ci_.layout = VK_NULL_HANDLE; + pipe.CreateComputePipeline(false); + + m_command_buffer.Begin(); + BindResourceHeap(); + vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); + vk::CmdDispatch(m_command_buffer, 1, 1, 1); + m_command_buffer.End(); + + m_errorMonitor->SetDesiredError("VUID-vkCmdDispatch-None-11309"); + m_default_queue->SubmitAndWait(m_command_buffer); + m_errorMonitor->VerifyFound(); +} + +TEST_F(NegativeGpuAVDescriptorHeap, ResourceOOBUntypedPointersBufferOldGlsl) { + AddRequiredExtensions(VK_KHR_SHADER_UNTYPED_POINTERS_EXTENSION_NAME); + AddRequiredFeature(vkt::Feature::shaderUntypedPointers); + RETURN_IF_SKIP(InitGpuAVDescriptorHeap()); + if ((heap_props.minResourceHeapReservedRange / heap_props.bufferDescriptorSize) >= 10000) { + GTEST_SKIP() << "reserved range is too large, access will not be OOB"; + } + const VkDeviceSize resource_stride = heap_props.bufferDescriptorSize; + CreateResourceHeap(resource_stride); + + // Same shader above in ResourceOOBUntypedPointers, but using the old (still valid) GLSL output + const char* cs_source = R"asm( + OpCapability Shader + OpCapability UntypedPointersKHR + OpCapability DescriptorHeapEXT + OpExtension "SPV_EXT_descriptor_heap" + OpExtension "SPV_KHR_untyped_pointers" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %main "main" %resource_heap + OpExecutionMode %main LocalSize 1 1 1 + OpMemberName %SSBO_0 0 "data" + OpDecorate %resource_heap BuiltIn ResourceHeapEXT + OpDecorate %SSBO_0 Block + OpMemberDecorate %SSBO_0 0 Offset 0 + OpDecorateId %_runtimearr_16 ArrayStrideIdEXT %17 + %void = OpTypeVoid + %3 = OpTypeFunction %void +%_ptr_UniformConstant = OpTypeUntypedPointerKHR UniformConstant +%resource_heap = OpUntypedVariableKHR %_ptr_UniformConstant UniformConstant + %int = OpTypeInt 32 1 + %int_10000 = OpConstant %int 10000 + %uint = OpTypeInt 32 0 + %SSBO_0 = OpTypeStruct %uint + %int_0 = OpConstant %int 0 + %uint_0 = OpConstant %uint 0 +%_ptr_StorageBuffer = OpTypeUntypedPointerKHR StorageBuffer + %16 = OpTypeBufferEXT StorageBuffer + %17 = OpConstantSizeOfEXT %int %16 +%_runtimearr_16 = OpTypeRuntimeArray %16 + %main = OpFunction %void None %3 + %5 = OpLabel + %15 = OpUntypedAccessChainKHR %_ptr_UniformConstant %_runtimearr_16 %resource_heap %int_10000 + %19 = OpBufferPointerEXT %_ptr_StorageBuffer %15 + %20 = OpUntypedAccessChainKHR %_ptr_StorageBuffer %SSBO_0 %19 %int_0 + OpStore %20 %uint_0 + OpReturn + OpFunctionEnd + )asm"; + + VkShaderObj cs_module = VkShaderObj(*m_device, cs_source, VK_SHADER_STAGE_COMPUTE_BIT, SPV_ENV_VULKAN_1_2, SPV_SOURCE_ASM); + + VkPipelineCreateFlags2CreateInfoKHR pipeline_create_flags_2_create_info = vku::InitStructHelper(); + pipeline_create_flags_2_create_info.flags = VK_PIPELINE_CREATE_2_DESCRIPTOR_HEAP_BIT_EXT; + + CreateComputePipelineHelper pipe(*this, &pipeline_create_flags_2_create_info); + pipe.cp_ci_.stage = cs_module.GetStageCreateInfo(); + pipe.cp_ci_.layout = VK_NULL_HANDLE; + pipe.CreateComputePipeline(false); + + m_command_buffer.Begin(); + BindResourceHeap(); + vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); + vk::CmdDispatch(m_command_buffer, 1, 1, 1); + m_command_buffer.End(); + + m_errorMonitor->SetDesiredError("VUID-vkCmdDispatch-None-11309"); + m_default_queue->SubmitAndWait(m_command_buffer); + m_errorMonitor->VerifyFound(); +} + +TEST_F(NegativeGpuAVDescriptorHeap, ResourceOOBUntypedPointersBufferAtomics) { + AddRequiredExtensions(VK_KHR_SHADER_UNTYPED_POINTERS_EXTENSION_NAME); + AddRequiredFeature(vkt::Feature::shaderUntypedPointers); + RETURN_IF_SKIP(InitGpuAVDescriptorHeap()); + if ((heap_props.minResourceHeapReservedRange / heap_props.bufferDescriptorSize) >= 10000) { + GTEST_SKIP() << "reserved range is too large, access will not be OOB"; + } + const VkDeviceSize resource_stride = heap_props.bufferDescriptorSize; + CreateResourceHeap(resource_stride); + + const char* cs_source = R"glsl( + #version 450 + #extension GL_EXT_descriptor_heap : enable + #extension GL_KHR_memory_scope_semantics : enable + + layout (descriptor_heap) buffer heap { + uint a; + } heapBuffer[]; + + void main() { + atomicStore(heapBuffer[10000].a, 0u, gl_ScopeDevice, 0, 0); + } + )glsl"; + + VkShaderObj cs_module = VkShaderObj(*m_device, cs_source, VK_SHADER_STAGE_COMPUTE_BIT, SPV_ENV_VULKAN_1_2); + + VkPipelineCreateFlags2CreateInfoKHR pipeline_create_flags_2_create_info = vku::InitStructHelper(); + pipeline_create_flags_2_create_info.flags = VK_PIPELINE_CREATE_2_DESCRIPTOR_HEAP_BIT_EXT; + + CreateComputePipelineHelper pipe(*this, &pipeline_create_flags_2_create_info); + pipe.cp_ci_.stage = cs_module.GetStageCreateInfo(); + pipe.cp_ci_.layout = VK_NULL_HANDLE; + pipe.CreateComputePipeline(false); + + m_command_buffer.Begin(); + BindResourceHeap(); + vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); + vk::CmdDispatch(m_command_buffer, 1, 1, 1); + m_command_buffer.End(); + + m_errorMonitor->SetDesiredError("VUID-vkCmdDispatch-None-11309"); + m_default_queue->SubmitAndWait(m_command_buffer); + m_errorMonitor->VerifyFound(); +} + +// TODO - See not in DescriptorHeapPass, need a way to return a "safe" null descriptor +TEST_F(NegativeGpuAVDescriptorHeap, DISABLED_ResourceOOBUntypedPointersStorageImage) { + AddRequiredExtensions(VK_KHR_SHADER_UNTYPED_POINTERS_EXTENSION_NAME); + AddRequiredFeature(vkt::Feature::shaderUntypedPointers); + RETURN_IF_SKIP(InitGpuAVDescriptorHeap()); + if ((heap_props.minResourceHeapReservedRange / heap_props.imageDescriptorSize) >= 10000) { + GTEST_SKIP() << "reserved range is too large, access will not be OOB"; + } + const VkDeviceSize resource_stride = heap_props.bufferDescriptorSize; + CreateResourceHeap(resource_stride); + + vkt::Buffer ssbo_buffer(*m_device, 256, VK_BUFFER_USAGE_2_STORAGE_BUFFER_BIT_KHR, vkt::device_address); + VkHostAddressRangeEXT descriptor_host = {resource_heap_data_, static_cast<size_t>(resource_stride)}; + VkDeviceAddressRangeEXT device_range = ssbo_buffer.AddressRange(); + VkResourceDescriptorInfoEXT descriptor_info = vku::InitStructHelper(); + descriptor_info.type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + descriptor_info.data.pAddressRange = &device_range; + vk::WriteResourceDescriptorsEXT(*m_device, 1u, &descriptor_info, &descriptor_host); + + // Note - this looks the same in the "old" glslang code as well + const char* cs_source = R"glsl( + #version 450 + #extension GL_EXT_descriptor_heap : require + layout(descriptor_heap, rgba8i) uniform iimage2D heapImages[]; + layout(set = 0, binding = 0) buffer SSBO { ivec4 result; }; + void main() { + ivec4 data = imageLoad(heapImages[10000], ivec2(0)); + result = data; + } + )glsl"; + VkShaderObj cs_module = VkShaderObj(*m_device, cs_source, VK_SHADER_STAGE_COMPUTE_BIT, SPV_ENV_VULKAN_1_2); + + VkDescriptorSetAndBindingMappingEXT mapping = MakeSetAndBindingMapping(0, 0); + mapping.source = VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_CONSTANT_OFFSET_EXT; + mapping.sourceData.constantOffset.heapOffset = 0; + VkShaderDescriptorSetAndBindingMappingInfoEXT mapping_info = vku::InitStructHelper(); + mapping_info.mappingCount = 1u; + mapping_info.pMappings = &mapping; + + VkPipelineCreateFlags2CreateInfoKHR pipeline_create_flags_2_create_info = vku::InitStructHelper(); + pipeline_create_flags_2_create_info.flags = VK_PIPELINE_CREATE_2_DESCRIPTOR_HEAP_BIT_EXT; + + CreateComputePipelineHelper pipe(*this, &pipeline_create_flags_2_create_info); + pipe.cp_ci_.stage = cs_module.GetStageCreateInfo(&mapping_info); + pipe.cp_ci_.layout = VK_NULL_HANDLE; + pipe.CreateComputePipeline(false); + + m_command_buffer.Begin(); + BindResourceHeap(); + vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); + vk::CmdDispatch(m_command_buffer, 1, 1, 1); + m_command_buffer.End(); + + m_errorMonitor->SetDesiredError("VUID-vkCmdDispatch-None-11309"); + m_default_queue->SubmitAndWait(m_command_buffer); + m_errorMonitor->VerifyFound(); +} + +TEST_F(NegativeGpuAVDescriptorHeap, ResourceOOBUntypedPointersSampledImage) { + AddRequiredExtensions(VK_KHR_SHADER_UNTYPED_POINTERS_EXTENSION_NAME); + AddRequiredFeature(vkt::Feature::shaderUntypedPointers); + RETURN_IF_SKIP(InitGpuAVDescriptorHeap()); + if ((heap_props.minResourceHeapReservedRange / heap_props.imageDescriptorSize) >= 10000) { + GTEST_SKIP() << "reserved range is too large, access will not be OOB"; + } + const VkDeviceSize resource_stride = heap_props.bufferDescriptorSize; + const VkDeviceSize sampler_stride = heap_props.samplerDescriptorSize; + CreateResourceHeap(resource_stride); + CreateSamplerHeap(sampler_stride); + + vkt::Buffer ssbo_buffer(*m_device, 256, VK_BUFFER_USAGE_2_STORAGE_BUFFER_BIT_KHR, vkt::device_address); + VkHostAddressRangeEXT descriptor_host = {resource_heap_data_, static_cast<size_t>(resource_stride)}; + VkDeviceAddressRangeEXT device_range = ssbo_buffer.AddressRange(); + VkResourceDescriptorInfoEXT descriptor_info = vku::InitStructHelper(); + descriptor_info.type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + descriptor_info.data.pAddressRange = &device_range; + vk::WriteResourceDescriptorsEXT(*m_device, 1u, &descriptor_info, &descriptor_host); + + // Note - this looks the same in the "old" glslang code as well + const char* cs_source = R"glsl( + #version 450 + #extension GL_EXT_descriptor_heap : require + layout(descriptor_heap) uniform texture2D heapTextures[]; + layout(descriptor_heap) uniform sampler heapSamplers[]; + layout(set = 0, binding = 0) buffer SSBO { vec4 result; }; + void main() { + vec4 data = texture(sampler2D(heapTextures[10000], heapSamplers[0]), vec2(0.5f)); + result = data; + } + )glsl"; + VkShaderObj cs_module = VkShaderObj(*m_device, cs_source, VK_SHADER_STAGE_COMPUTE_BIT, SPV_ENV_VULKAN_1_2); + + VkDescriptorSetAndBindingMappingEXT mapping = MakeSetAndBindingMapping(0, 0); + mapping.source = VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_CONSTANT_OFFSET_EXT; + mapping.sourceData.constantOffset.heapOffset = 0; + VkShaderDescriptorSetAndBindingMappingInfoEXT mapping_info = vku::InitStructHelper(); + mapping_info.mappingCount = 1u; + mapping_info.pMappings = &mapping; + + VkPipelineCreateFlags2CreateInfoKHR pipeline_create_flags_2_create_info = vku::InitStructHelper(); + pipeline_create_flags_2_create_info.flags = VK_PIPELINE_CREATE_2_DESCRIPTOR_HEAP_BIT_EXT; + + CreateComputePipelineHelper pipe(*this, &pipeline_create_flags_2_create_info); + pipe.cp_ci_.stage = cs_module.GetStageCreateInfo(&mapping_info); + pipe.cp_ci_.layout = VK_NULL_HANDLE; + pipe.CreateComputePipeline(false); + + m_command_buffer.Begin(); + BindResourceHeap(); + BindSamplerHeap(); + vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); + vk::CmdDispatch(m_command_buffer, 1, 1, 1); + m_command_buffer.End(); + + m_errorMonitor->SetDesiredError("VUID-vkCmdDispatch-None-11309"); + m_default_queue->SubmitAndWait(m_command_buffer); + m_errorMonitor->VerifyFound(); +} + +TEST_F(NegativeGpuAVDescriptorHeap, SamplerOOBUntypedPointers) { + AddRequiredExtensions(VK_KHR_SHADER_UNTYPED_POINTERS_EXTENSION_NAME); + AddRequiredFeature(vkt::Feature::shaderUntypedPointers); + RETURN_IF_SKIP(InitGpuAVDescriptorHeap()); + if ((heap_props.minSamplerHeapReservedRange / heap_props.samplerDescriptorSize) >= 10000) { + GTEST_SKIP() << "reserved range is too large, access will not be OOB"; + } + const VkDeviceSize resource_stride = heap_props.imageDescriptorSize; + CreateResourceHeap(resource_stride); + CreateSamplerHeap(heap_props.samplerDescriptorSize); + + // Note - this looks the same in the "old" glslang code as well + const char* cs_source = R"glsl( + #version 450 + #extension GL_EXT_descriptor_heap : require + layout(descriptor_heap) uniform texture2D heapTextures[]; + layout(descriptor_heap) uniform sampler heapSamplers[]; + void main() { + vec4 data = texture(sampler2D(heapTextures[0], heapSamplers[10000]), vec2(0.5f)); + } + )glsl"; + VkShaderObj cs_module = VkShaderObj(*m_device, cs_source, VK_SHADER_STAGE_COMPUTE_BIT, SPV_ENV_VULKAN_1_2); + + VkPipelineCreateFlags2CreateInfoKHR pipeline_create_flags_2_create_info = vku::InitStructHelper(); + pipeline_create_flags_2_create_info.flags = VK_PIPELINE_CREATE_2_DESCRIPTOR_HEAP_BIT_EXT; + + CreateComputePipelineHelper pipe(*this, &pipeline_create_flags_2_create_info); + pipe.cp_ci_.stage = cs_module.GetStageCreateInfo(); + pipe.cp_ci_.layout = VK_NULL_HANDLE; + pipe.CreateComputePipeline(false); + + m_command_buffer.Begin(); + BindResourceHeap(); + BindSamplerHeap(); + vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); + vk::CmdDispatch(m_command_buffer, 1, 1, 1); + m_command_buffer.End(); + + m_errorMonitor->SetDesiredError("VUID-vkCmdDispatch-None-11309"); + m_default_queue->SubmitAndWait(m_command_buffer); + m_errorMonitor->VerifyFound(); +} + +TEST_F(NegativeGpuAVDescriptorHeap, ResourceOOBUntypedPointersOffsetId) { + AddRequiredExtensions(VK_KHR_SHADER_UNTYPED_POINTERS_EXTENSION_NAME); + AddRequiredFeature(vkt::Feature::shaderUntypedPointers); + RETURN_IF_SKIP(InitGpuAVDescriptorHeap()); + + const VkDeviceSize resource_stride = heap_props.bufferDescriptorSize; + CreateResourceHeap(resource_stride * 2); + + vkt::Buffer buffer_0(*m_device, 64, VK_BUFFER_USAGE_2_STORAGE_BUFFER_BIT_KHR, vkt::device_address); + + VkHostAddressRangeEXT descriptor_host = {resource_heap_data_ + resource_stride, static_cast<size_t>(resource_stride)}; + VkDeviceAddressRangeEXT device_range = buffer_0.AddressRange(); + VkResourceDescriptorInfoEXT descriptor_info = vku::InitStructHelper(); + descriptor_info.type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + descriptor_info.data.pAddressRange = &device_range; + vk::WriteResourceDescriptorsEXT(*m_device, 1u, &descriptor_info, &descriptor_host); + + // layout(storage_buffer) SSBO { + // uint a; + // }; + // layout(offset = buffer_size * 10000) heap { + // SSBO runtime_buffer[]; + // } heap_layout; + // + // heap_layout.runtime_buffer[0].a = 42; + char const* cs_source = R"( + OpCapability Shader + OpCapability UntypedPointersKHR + OpCapability DescriptorHeapEXT + OpExtension "SPV_EXT_descriptor_heap" + OpExtension "SPV_KHR_untyped_pointers" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %main "main" %resource_heap + OpExecutionMode %main LocalSize 1 1 1 + OpDecorate %resource_heap BuiltIn ResourceHeapEXT + OpDecorate %SSBO Block + OpMemberDecorate %SSBO 0 Offset 0 + OpDecorate %heap_layout Block + OpMemberDecorateIdEXT %heap_layout 0 OffsetIdEXT %crazy_offset + OpDecorateId %runtime_buffer ArrayStrideIdEXT %buf_size + %void = OpTypeVoid + %void_fn = OpTypeFunction %void + %int = OpTypeInt 32 1 + %uint = OpTypeInt 32 0 + %int_0 = OpConstant %int 0 + %uint_42 = OpConstant %uint 42 + %int_10k = OpConstant %int 10000 +%_ptr_UniformConstant = OpTypeUntypedPointerKHR UniformConstant +%resource_heap = OpUntypedVariableKHR %_ptr_UniformConstant UniformConstant + %SSBO = OpTypeStruct %uint +%_ptr_StorageBuffer = OpTypeUntypedPointerKHR StorageBuffer + +%type_buffer = OpTypeBufferEXT StorageBuffer + %buf_size = OpConstantSizeOfEXT %int %type_buffer +%crazy_offset = OpSpecConstantOp %int IMul %buf_size %int_10k +%runtime_buffer = OpTypeRuntimeArray %type_buffer + + %heap_layout = OpTypeStruct %runtime_buffer + + %main = OpFunction %void None %void_fn + %5 = OpLabel + +%heap_index_0 = OpUntypedAccessChainKHR %_ptr_UniformConstant %heap_layout %resource_heap %int_0 %int_0 + %buf_ptr_0 = OpBufferPointerEXT %_ptr_StorageBuffer %heap_index_0 + %member_0 = OpUntypedAccessChainKHR %_ptr_StorageBuffer %SSBO %buf_ptr_0 %int_0 + OpStore %member_0 %uint_42 + + OpReturn + OpFunctionEnd + )"; + VkShaderObj cs_module = VkShaderObj(*m_device, cs_source, VK_SHADER_STAGE_COMPUTE_BIT, SPV_ENV_VULKAN_1_2, SPV_SOURCE_ASM); + + VkPipelineCreateFlags2CreateInfoKHR pipeline_create_flags_2_create_info = vku::InitStructHelper(); + pipeline_create_flags_2_create_info.flags = VK_PIPELINE_CREATE_2_DESCRIPTOR_HEAP_BIT_EXT; + CreateComputePipelineHelper pipe(*this, &pipeline_create_flags_2_create_info); + pipe.cp_ci_.layout = VK_NULL_HANDLE; + pipe.cp_ci_.stage = cs_module.GetStageCreateInfo(); + pipe.CreateComputePipeline(false); + + m_command_buffer.Begin(); + BindResourceHeap(); + vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); + vk::CmdDispatch(m_command_buffer, 1, 1, 1); + m_command_buffer.End(); + + m_errorMonitor->SetDesiredError("VUID-vkCmdDispatch-None-11309"); + m_default_queue->SubmitAndWait(m_command_buffer); + m_errorMonitor->VerifyFound(); } \ No newline at end of file
diff --git a/tests/unit/gpu_av_descriptor_indexing.cpp b/tests/unit/gpu_av_descriptor_indexing.cpp index f212b20..24182f1 100644 --- a/tests/unit/gpu_av_descriptor_indexing.cpp +++ b/tests/unit/gpu_av_descriptor_indexing.cpp
@@ -12,6 +12,7 @@ */ #include <vulkan/vulkan_core.h> +#include <cstdint> #include "../framework/layer_validation_tests.h" #include "../framework/pipeline_helper.h" #include "../framework/descriptor_helper.h" @@ -3898,17 +3899,22 @@ #extension GL_KHR_memory_scope_semantics : enable layout(set = 0, binding = 0, R32ui) uniform uimage2D atomic_image_array[]; - + // Also a UniformConstant + layout(push_constant) uniform PC { + uint x; + }; void main() { - uint y = imageAtomicLoad(atomic_image_array[1], ivec2(0), gl_ScopeDevice, gl_StorageSemanticsImage, gl_SemanticsAcquire); - imageAtomicStore(atomic_image_array[1], ivec2(0), y, gl_ScopeDevice, gl_StorageSemanticsImage, gl_SemanticsRelease); - imageAtomicExchange(atomic_image_array[1], ivec2(0), y, gl_ScopeDevice, gl_StorageSemanticsImage, gl_SemanticsRelease); + ivec2 cord = ivec2(x, x); + uint y = imageAtomicLoad(atomic_image_array[1], cord, gl_ScopeDevice, gl_StorageSemanticsImage, gl_SemanticsAcquire); + imageAtomicStore(atomic_image_array[1], cord, y, gl_ScopeDevice, gl_StorageSemanticsImage, gl_SemanticsRelease); + imageAtomicExchange(atomic_image_array[1], cord, y, gl_ScopeDevice, gl_StorageSemanticsImage, gl_SemanticsRelease); } )glsl"; + VkPushConstantRange pc_range{VK_SHADER_STAGE_COMPUTE_BIT, 0, 4}; OneOffDescriptorIndexingSet descriptor_set(m_device, {{0, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 2, VK_SHADER_STAGE_ALL, nullptr, VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT}}); - vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set.layout_}); + vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set.layout_}, {pc_range}); descriptor_set.WriteDescriptorImageInfo(0, image_view, sampler, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_IMAGE_LAYOUT_GENERAL, 0); descriptor_set.UpdateDescriptorSets(); @@ -3919,6 +3925,8 @@ pipe.CreateComputePipeline(); m_command_buffer.Begin(); + uint32_t push_data = 0; + vk::CmdPushConstants(m_command_buffer, pipeline_layout, VK_SHADER_STAGE_COMPUTE_BIT, 0, 4, &push_data); vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline_layout, 0, 1, &descriptor_set.set_, 0, nullptr); @@ -4001,6 +4009,47 @@ m_errorMonitor->VerifyFound(); } +TEST_F(NegativeGpuAVDescriptorIndexing, AtomicBufferOOB) { + RETURN_IF_SKIP(InitGpuVUDescriptorIndexing()); + InitRenderTarget(); + + const char* cs_source = R"glsl( + #version 450 + #extension GL_EXT_nonuniform_qualifier : enable + #extension GL_KHR_memory_scope_semantics : enable + layout(set = 0, binding = 0) buffer ssbo { uint x; } atomic_buffers[]; + void main() { + uint index = atomic_buffers[0].x; + atomicStore(atomic_buffers[index].x, 1u, gl_ScopeDevice, 0, 0); + } + )glsl"; + + OneOffDescriptorIndexingSet descriptor_set(m_device, {{0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 2, VK_SHADER_STAGE_ALL, nullptr, + VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT}}); + vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set.layout_}); + + vkt::Buffer storage_buffer(*m_device, 32, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, kHostVisibleMemProps); + *((uint32_t*)storage_buffer.Memory().Map()) = 99; // OOB! + descriptor_set.WriteDescriptorBufferInfo(0, storage_buffer, 0, VK_WHOLE_SIZE, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 0); + descriptor_set.UpdateDescriptorSets(); + + CreateComputePipelineHelper pipe(*this); + pipe.cp_ci_.layout = pipeline_layout; + pipe.cs_ = VkShaderObj(*m_device, cs_source, VK_SHADER_STAGE_COMPUTE_BIT, SPV_ENV_VULKAN_1_1); + pipe.CreateComputePipeline(); + + m_command_buffer.Begin(); + vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); + vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline_layout, 0, 1, &descriptor_set.set_, 0, + nullptr); + vk::CmdDispatch(m_command_buffer, 1, 1, 1); + m_command_buffer.End(); + + m_errorMonitor->SetDesiredError("VUID-vkCmdDispatch-None-10068"); + m_default_queue->SubmitAndWait(m_command_buffer); + m_errorMonitor->VerifyFound(); +} + TEST_F(NegativeGpuAVDescriptorIndexing, StorageImagePartiallyBound) { RETURN_IF_SKIP(InitGpuVUDescriptorIndexing()); InitRenderTarget();