diff --git a/BUILD.gn b/BUILD.gn index 637e2bc4a99..42de2dda00d 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -157,6 +157,8 @@ vvl_sources = [ "layers/core_checks/cc_wsi.cpp", "layers/core_checks/cc_ycbcr.cpp", "layers/core_checks/core_validation.h", + "layers/drawdispatch/descriptor_heap_validator.cpp", + "layers/drawdispatch/descriptor_heap_validator.h", "layers/drawdispatch/descriptor_validator.cpp", "layers/drawdispatch/descriptor_validator.h", "layers/drawdispatch/drawdispatch_vuids.cpp", @@ -212,6 +214,8 @@ vvl_sources = [ "layers/gpuav/instrumentation/descriptor_checks.cpp", "layers/gpuav/instrumentation/descriptor_checks.h", "layers/gpuav/instrumentation/mesh_shading.cpp", + "layers/gpuav/instrumentation/post_process_descriptor_heap.cpp", + "layers/gpuav/instrumentation/post_process_descriptor_heap.h", "layers/gpuav/instrumentation/post_process_descriptor_indexing.cpp", "layers/gpuav/instrumentation/ray_query.cpp", "layers/gpuav/instrumentation/ray_hit_object.cpp", @@ -236,6 +240,8 @@ vvl_sources = [ "layers/gpuav/spirv/descriptor_class_general_buffer_pass.h", "layers/gpuav/spirv/descriptor_class_texel_buffer_pass.cpp", "layers/gpuav/spirv/descriptor_class_texel_buffer_pass.h", + "layers/gpuav/spirv/descriptor_heap_pass.cpp", + "layers/gpuav/spirv/descriptor_heap_pass.h", "layers/gpuav/spirv/buffer_device_address_pass.cpp", "layers/gpuav/spirv/buffer_device_address_pass.h", "layers/gpuav/spirv/mesh_shading_pass.cpp", diff --git a/layers/CMakeLists.txt b/layers/CMakeLists.txt index c94a7bd2c50..a9aedf9923a 100644 --- a/layers/CMakeLists.txt +++ b/layers/CMakeLists.txt @@ -256,6 +256,8 @@ target_sources(vvl PRIVATE core_checks/cc_vuid_maps.h core_checks/cc_wsi.cpp core_checks/cc_ycbcr.cpp + drawdispatch/descriptor_heap_validator.cpp + drawdispatch/descriptor_heap_validator.h drawdispatch/descriptor_validator.cpp drawdispatch/descriptor_validator.h drawdispatch/drawdispatch_vuids.cpp @@ -338,6 +340,8 @@ target_sources(vvl PRIVATE gpuav/instrumentation/descriptor_checks.cpp gpuav/instrumentation/mesh_shading.cpp gpuav/instrumentation/post_process_descriptor_indexing.cpp + gpuav/instrumentation/post_process_descriptor_heap.h + gpuav/instrumentation/post_process_descriptor_heap.cpp gpuav/instrumentation/ray_query.cpp gpuav/instrumentation/ray_hit_object.cpp gpuav/instrumentation/register_validation.h diff --git a/layers/drawdispatch/descriptor_heap_validator.cpp b/layers/drawdispatch/descriptor_heap_validator.cpp new file mode 100644 index 00000000000..3f4a09fc4fb --- /dev/null +++ b/layers/drawdispatch/descriptor_heap_validator.cpp @@ -0,0 +1,111 @@ +/* Copyright (c) 2025-2026 The Khronos Group Inc. + * Copyright (c) 2025-2026 Valve Corporation + * Copyright (c) 2025-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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "descriptor_heap_validator.h" +#include "state_tracker/pipeline_state.h" +#include "drawdispatch/drawdispatch_vuids.h" +#include "gpuav/core/gpuav.h" +#include "gpuav/resources/gpuav_state_trackers.h" +#include "state_tracker/shader_module.h" +#include "utils/math_utils.h" +#include "utils/shader_utils.h" +#include "../layers/containers/container_utils.h" +#include "../layers/core_checks/cc_buffer_address.h" +#include + +namespace vvl { + +DescriptorHeapValidator::DescriptorHeapValidator(vvl::DeviceProxy& dev, gpuav::CommandBufferSubState& cb_state, uint32_t set_index, + const LogObjectList* objlist, const Location& loc) + : Logger(dev.debug_report), + cb_state(cb_state), + loc(loc), + vuids(&GetDrawDispatchVuid(loc.function)), + objlist(objlist) {} + +bool DescriptorHeapValidator::ValidateBinding(gpuav::Validator &gpuav, const spirv::ResourceInterfaceVariable &resource_variable, + const VkDescriptorSetAndBindingMappingEXT &mapping, + const gpuav::vko::IndirectAccessMap &indirect_access, uint32_t byte_offset, + bool pipeline, bool robustness) { + bool skip = false; + + if (IsValueIn(mapping.source, + {VK_DESCRIPTOR_MAPPING_SOURCE_PUSH_ADDRESS_EXT, VK_DESCRIPTOR_MAPPING_SOURCE_SHADER_RECORD_ADDRESS_EXT, + VK_DESCRIPTOR_MAPPING_SOURCE_INDIRECT_ADDRESS_EXT})) { + VkDeviceAddress address = 0; + if (mapping.source == VK_DESCRIPTOR_MAPPING_SOURCE_PUSH_ADDRESS_EXT) { + address = cb_state.GetPushData(mapping.sourceData.pushAddressOffset); + } else if (mapping.source == VK_DESCRIPTOR_MAPPING_SOURCE_INDIRECT_ADDRESS_EXT) { + gpuav::vko::IndirectKey key = {false, mapping.sourceData.indirectAddress.pushOffset, + mapping.sourceData.indirectAddress.addressOffset}; + if (auto buffer = indirect_access->find(key); buffer != indirect_access->end()) { + VkDeviceAddress *indirect_address = static_cast(buffer->second.GetHostBufferPtr()); + address = *indirect_address; + } + } else if (mapping.source == VK_DESCRIPTOR_MAPPING_SOURCE_SHADER_RECORD_ADDRESS_EXT) { + gpuav::vko::IndirectKey key = {true, 0, mapping.sourceData.shaderRecordAddressOffset}; + if (auto buffer = indirect_access->find(key); buffer != indirect_access->end()) { + address = *static_cast(buffer->second.GetHostBufferPtr()); + } + } + std::string usage_vuid = {}; + VkBufferUsageFlagBits2 required_usage_bit = 0; + + if (resource_variable.is_uniform_buffer) { + usage_vuid = CreateActionVuid(vuids->function, ActionVUID::HEAP_USAGE_11438); + } + + if (mapping.source == VK_DESCRIPTOR_MAPPING_SOURCE_PUSH_ADDRESS_EXT || + mapping.source == VK_DESCRIPTOR_MAPPING_SOURCE_INDIRECT_ADDRESS_EXT) { + if (!usage_vuid.empty()) { + std::string msg = + "The following buffers are missing " + std::string(string_VkBufferUsageFlagBits2(required_usage_bit)); + BufferAddressValidation<1> buffer_address_validator = {{{{usage_vuid, + [required_usage_bit](const vvl::Buffer &buffer_state) { + return (buffer_state.usage & required_usage_bit) == 0; + }, + [msg]() { return msg; }, kUsageErrorMsgBuffer}}}}; + + skip |= + buffer_address_validator.ValidateDeviceAddress(gpuav, loc.Get(), *objlist, address, 0u); + } + } + } + + return skip; +} + +bool DescriptorHeapValidator::ValidateBinding(gpuav::Validator &gpuav, const spirv::ResourceInterfaceVariable &resource_variable, + const VkShaderDescriptorSetAndBindingMappingInfoEXT &mappings, + const gpuav::vko::IndirectAccessMap &indirect_access, uint32_t byte_offset, + bool pipeline, bool robustness) { + bool skip = false; + + for (uint32_t i = 0; i < mappings.mappingCount; ++i) { + const auto &mapping = mappings.pMappings[i]; + if (mapping.descriptorSet == resource_variable.decorations.set && + mapping.firstBinding == resource_variable.decorations.binding && + ResourceTypeMatchesBinding(mapping.resourceMask, resource_variable)) { + skip |= ValidateBinding(gpuav, resource_variable, mapping, indirect_access, byte_offset, pipeline, robustness); + break; + } + } + + return skip; +} + +} // namespace vvl \ No newline at end of file diff --git a/layers/drawdispatch/descriptor_heap_validator.h b/layers/drawdispatch/descriptor_heap_validator.h new file mode 100644 index 00000000000..4cc5c5e8121 --- /dev/null +++ b/layers/drawdispatch/descriptor_heap_validator.h @@ -0,0 +1,58 @@ +/* Copyright (c) 2025-2026 The Khronos Group Inc. + * Copyright (c) 2025-2026 Valve Corporation + * Copyright (c) 2025-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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include +#include "error_message/error_location.h" +#include "gpuav/resources/gpuav_vulkan_objects.h" + +namespace spirv { +struct ResourceInterfaceVariable; +} // namespace spirv + +namespace gpuav { +class Validator; +class CommandBufferSubState; +} // namespace gpuav + +namespace vvl { +struct DrawDispatchVuid; +class DeviceProxy; + +class DescriptorHeapValidator : public Logger { + public: + DescriptorHeapValidator(DeviceProxy& dev, gpuav::CommandBufferSubState& cb_state, uint32_t set_index, + const LogObjectList* objlist, const Location& loc); + + bool ValidateBinding(gpuav::Validator& gpuav, const spirv::ResourceInterfaceVariable& resource_variable, + const VkShaderDescriptorSetAndBindingMappingInfoEXT& mappings, + const gpuav::vko::IndirectAccessMap& indirect_access, uint32_t byte_offset, bool pipeline, + bool robustness); + + void SetObjlistForGpuAv(const LogObjectList* objlist) { this->objlist = objlist; } + + private: + bool ValidateBinding(gpuav::Validator& gpuav, const spirv::ResourceInterfaceVariable& resource_variable, + const VkDescriptorSetAndBindingMappingEXT& mapping, const gpuav::vko::IndirectAccessMap& indirect_access, + uint32_t byte_offset, bool pipeline, bool robustness); + + gpuav::CommandBufferSubState& cb_state; + LocationCapture loc; + const DrawDispatchVuid* vuids; + const LogObjectList* objlist; // VkPipeline or VkShaderObject +}; +} // namespace vvl \ No newline at end of file diff --git a/layers/drawdispatch/drawdispatch_vuids.cpp b/layers/drawdispatch/drawdispatch_vuids.cpp index 041e40a4a55..f0716b6eb11 100644 --- a/layers/drawdispatch/drawdispatch_vuids.cpp +++ b/layers/drawdispatch/drawdispatch_vuids.cpp @@ -1202,6 +1202,8 @@ std::string CreateActionVuid(vvl::Func function, const ActionVUID id) { case ActionVUID::DESCRIPTOR_INDEX_OOB_10068: suffix = "None-10068"; break; // ### VUID-vkCmdDrawIndirectCount-countBuffer-02717 case ActionVUID::INDIRECT_COUNT_LIMIT: suffix = "countBuffer-02717"; break; + // ### VUID-vkCmdDraw-None-11438 + case ActionVUID::HEAP_USAGE_11438: suffix = "None-11438"; break; } // clang-format on diff --git a/layers/drawdispatch/drawdispatch_vuids.h b/layers/drawdispatch/drawdispatch_vuids.h index 2e8d4537c85..66e06db9658 100644 --- a/layers/drawdispatch/drawdispatch_vuids.h +++ b/layers/drawdispatch/drawdispatch_vuids.h @@ -352,6 +352,7 @@ enum class ActionVUID { INVALID_DESCRIPTOR_08114, DESCRIPTOR_INDEX_OOB_10068, INDIRECT_COUNT_LIMIT, + HEAP_USAGE_11438, }; std::string CreateActionVuid(vvl::Func function, const ActionVUID id); diff --git a/layers/gpuav/core/gpuav.h b/layers/gpuav/core/gpuav.h index 8fc41e23f4c..76ed13d15d2 100644 --- a/layers/gpuav/core/gpuav.h +++ b/layers/gpuav/core/gpuav.h @@ -117,6 +117,8 @@ class Validator : public GpuShaderInstrumentor { const VkDescriptorBufferBindingInfoEXT* pBindingInfos, const RecordObject& record_obj, chassis::CmdBindDescriptorBuffers& chassis_state) final; + void PreCallRecordCmdPushDataEXT(VkCommandBuffer commandBuffer, const VkPushDataInfoEXT* pPushDataInfo, + const RecordObject& record_obj) final; void PreCallActionCommand(Validator& gpuav, CommandBufferSubState& cb_state, const LastBound& last_bound, const Location& loc); @@ -294,7 +296,7 @@ class Validator : public GpuShaderInstrumentor { // VK_EXT_descriptor_heap global tracking struct ResourceHeap { const vvl::Buffer* buffer_state_ = nullptr; - VkDeviceSize reserved_offset_ = 0; + VkDeviceSize size_ = 0; } resource_heap; vko::Buffer& GetGlobalDescriptorBuffer(); diff --git a/layers/gpuav/core/gpuav_record.cpp b/layers/gpuav/core/gpuav_record.cpp index 27620208e33..b7c3c79999f 100644 --- a/layers/gpuav/core/gpuav_record.cpp +++ b/layers/gpuav/core/gpuav_record.cpp @@ -23,6 +23,7 @@ #include "gpuav/instrumentation/descriptor_checks.h" #include "gpuav/instrumentation/gpuav_instrumentation.h" #include "gpuav/instrumentation/register_validation.h" +#include "gpuav/instrumentation/post_process_descriptor_heap.h" #include "gpuav/resources/gpuav_state_trackers.h" #include "gpuav/shaders/gpuav_shaders_constants.h" #include "gpuav/validation_cmd/gpuav_copy_buffer_to_image.h" @@ -81,6 +82,13 @@ void Validator::PreCallRecordCreateBuffer(VkDevice device, const VkBufferCreateI chassis_state.modified_create_info.size = Align(chassis_state.modified_create_info.size, 4); } + // If descriptor heaps are used, uniform buffers can be used for indirect indices and we need to be able to copy from them + if (gpuav_settings.shader_instrumentation.descriptor_heap) { + if (in_usage & VK_BUFFER_USAGE_2_UNIFORM_BUFFER_BIT) { + chassis_state.modified_create_info.usage |= VK_BUFFER_USAGE_TRANSFER_SRC_BIT; + } + } + chassis_state.create_info_copy = chassis_state.modified_create_info.ptr(); } @@ -153,6 +161,16 @@ void Validator::PreCallRecordCmdBindDescriptorBuffersEXT(VkCommandBuffer command chassis_state.pBindInfos = reinterpret_cast(chassis_state.modified_binding_infos.data()); } +void Validator::PreCallRecordCmdPushDataEXT(VkCommandBuffer commandBuffer, const VkPushDataInfoEXT* pPushDataInfo, + const RecordObject& record_obj) { + auto cb_state = GetWrite(commandBuffer); + CommandBufferSubState& gpuav_cb_state = SubState(*cb_state); + if (pPushDataInfo->offset + pPushDataInfo->data.size > gpuav_cb_state.push_data_.size()) { + gpuav_cb_state.push_data_.resize(pPushDataInfo->offset + pPushDataInfo->data.size); + } + memcpy(gpuav_cb_state.push_data_.data() + pPushDataInfo->offset, pPushDataInfo->data.address, pPushDataInfo->data.size); +} + void Validator::PreCallRecordBeginCommandBuffer(VkCommandBuffer commandBuffer, const VkCommandBufferBeginInfo* pBeginInfo, const RecordObject& record_obj) { auto cb_state = GetWrite(commandBuffer); @@ -160,6 +178,7 @@ void Validator::PreCallRecordBeginCommandBuffer(VkCommandBuffer commandBuffer, c CommandBufferSubState& gpuav_cb_state = SubState(*cb_state); RegisterDescriptorChecksValidation(*this, gpuav_cb_state); RegisterPostProcessingValidation(*this, gpuav_cb_state); + RegisterPostProcessingDescriptorHeap(*this, gpuav_cb_state); RegisterBufferDeviceAddressValidation(*this, gpuav_cb_state); RegisterVertexAttributeFetchOobValidation(*this, gpuav_cb_state); RegisterMeshShadingValidation(*this, gpuav_cb_state); diff --git a/layers/gpuav/core/gpuav_settings.cpp b/layers/gpuav/core/gpuav_settings.cpp index 96d4f4c3a16..23d838143fc 100644 --- a/layers/gpuav/core/gpuav_settings.cpp +++ b/layers/gpuav/core/gpuav_settings.cpp @@ -33,7 +33,8 @@ bool GpuAVSettings::IsShaderInstrumentationEnabled() const { return shader_instrumentation.descriptor_checks || shader_instrumentation.buffer_device_address || shader_instrumentation.ray_query || shader_instrumentation.ray_hit_object || shader_instrumentation.mesh_shading || shader_instrumentation.post_process_descriptor_indexing || shader_instrumentation.vertex_attribute_fetch_oob || - shader_instrumentation.sanitizer || shader_instrumentation.shared_memory_data_race; + shader_instrumentation.sanitizer || shader_instrumentation.shared_memory_data_race || + shader_instrumentation.descriptor_heap; } bool GpuAVSettings::IsSpirvModified() const { return IsShaderInstrumentationEnabled() || debug_printf_enabled; } @@ -48,6 +49,7 @@ void GpuAVSettings::DisableShaderInstrumentationAndOptions() { shader_instrumentation.vertex_attribute_fetch_oob = false; shader_instrumentation.sanitizer = false; shader_instrumentation.shared_memory_data_race = false; + shader_instrumentation.descriptor_heap = false; // Because of this setting, cannot really have an "enabled" parameter to pass to this method select_instrumented_shaders = false; } diff --git a/layers/gpuav/core/gpuav_settings.h b/layers/gpuav/core/gpuav_settings.h index f4f74a5cbe9..e5fa3af6983 100644 --- a/layers/gpuav/core/gpuav_settings.h +++ b/layers/gpuav/core/gpuav_settings.h @@ -68,6 +68,7 @@ struct GpuAVSettings { bool vertex_attribute_fetch_oob = true; bool sanitizer = true; bool shared_memory_data_race = true; + bool descriptor_heap = true; } shader_instrumentation; bool IsShaderInstrumentationEnabled() const; diff --git a/layers/gpuav/core/gpuav_setup.cpp b/layers/gpuav/core/gpuav_setup.cpp index 7be35f72507..b29be37c8a4 100644 --- a/layers/gpuav/core/gpuav_setup.cpp +++ b/layers/gpuav/core/gpuav_setup.cpp @@ -231,6 +231,10 @@ void Validator::FinishDeviceSetup(const VkDeviceCreateInfo* pCreateInfo, const L {glsl::kBindingInstCmdErrorsCount, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr}, // Vertex attribute fetch limits {glsl::kBindingInstVertexAttributeFetchLimits, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT, nullptr}, + // Descriptor heap post processing + {glsl::kBindingInstDescriptorHeapPostProcess, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr}, + // Descriptor heap valid descriptors buffer + {glsl::kBindingInstDescriptorHeapValidDescriptors, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr}, }; assert(instrumentation_bindings_.size() == glsl::kTotalBindings); diff --git a/layers/gpuav/instrumentation/gpuav_shader_instrumentor.cpp b/layers/gpuav/instrumentation/gpuav_shader_instrumentor.cpp index a17ed25f40a..acb6cd5d735 100644 --- a/layers/gpuav/instrumentation/gpuav_shader_instrumentor.cpp +++ b/layers/gpuav/instrumentation/gpuav_shader_instrumentor.cpp @@ -56,6 +56,7 @@ #include "gpuav/spirv/post_process_descriptor_indexing_pass.h" #include "gpuav/spirv/vertex_attribute_fetch_oob_pass.h" #include "gpuav/spirv/sanitizer_pass.h" +#include "gpuav/spirv/descriptor_heap_pass.h" #include #include @@ -204,7 +205,8 @@ void GpuShaderInstrumentor::SetupDescriptorHeap(const Location& loc) { resource_heap_reserved_bytes_ = bytes_to_reserve; buffer_descriptor_size_ = descriptor_heap_props.bufferDescriptorSize; - buffer_descriptor_alignment_ = descriptor_heap_props.bufferDescriptorAlignment; + image_descriptor_size_ = descriptor_heap_props.imageDescriptorSize; + sampler_descriptor_size_ = descriptor_heap_props.samplerDescriptorSize; push_data_offset_ = static_cast(descriptor_heap_props.maxPushDataSize) - 8u; } @@ -1704,6 +1706,17 @@ bool GpuShaderInstrumentor::InstrumentShader(const vvl::span& in modified |= pass.Run(); } + if (gpuav_settings.shader_instrumentation.descriptor_heap) { + if (interface.descriptor_mode == vvl::DescriptorModeHeap) { + VkPhysicalDeviceDescriptorHeapTensorPropertiesARM heap_tensor_props = vku::InitStructHelper(); + VkPhysicalDeviceDescriptorHeapPropertiesEXT heap_props = vku::InitStructHelper(&heap_tensor_props); + VkPhysicalDeviceProperties2 props2 = vku::InitStructHelper(&heap_props); + DispatchGetPhysicalDeviceProperties2(physical_device, &props2); + spirv::DescriptorHeapPass descriptor_heap_pass(module, heap_props, heap_tensor_props); + modified |= descriptor_heap_pass.Run(); + } + } + // If we have passes that require inject LogError before the shader end we do it now. // We have a dedicated pass to ensure the LogError is only added once if (module.need_log_error_) { diff --git a/layers/gpuav/instrumentation/gpuav_shader_instrumentor.h b/layers/gpuav/instrumentation/gpuav_shader_instrumentor.h index d02804b8e2d..ccf81301f1f 100644 --- a/layers/gpuav/instrumentation/gpuav_shader_instrumentor.h +++ b/layers/gpuav/instrumentation/gpuav_shader_instrumentor.h @@ -239,7 +239,8 @@ class GpuShaderInstrumentor : public vvl::DeviceProxy { // Size to reserve in front of reserved range in resource heap VkDeviceSize resource_heap_reserved_bytes_ = 0; VkDeviceSize buffer_descriptor_size_ = 0; - VkDeviceSize buffer_descriptor_alignment_ = 0; + VkDeviceSize image_descriptor_size_ = 0; + VkDeviceSize sampler_descriptor_size_ = 0; uint32_t push_data_offset_ = 0; // These are the same as enabled_features, but may have been altered at setup time. This should be use for any feature GPU-AV diff --git a/layers/gpuav/instrumentation/post_process_descriptor_heap.cpp b/layers/gpuav/instrumentation/post_process_descriptor_heap.cpp new file mode 100644 index 00000000000..b92bc1e196c --- /dev/null +++ b/layers/gpuav/instrumentation/post_process_descriptor_heap.cpp @@ -0,0 +1,321 @@ +/* Copyright (c) 2025-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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "gpuav/instrumentation/post_process_descriptor_heap.h" + +#include "gpuav/core/gpuav.h" +#include "gpuav/shaders/gpuav_shaders_constants.h" +#include "gpuav/resources/gpuav_state_trackers.h" +#include "drawdispatch/descriptor_heap_validator.h" +#include "state_tracker/shader_module.h" +#include "gpuav/shaders/gpuav_error_codes.h" +#include "gpuav/shaders/gpuav_error_header.h" +#include "generated/spirv_validation_helper.h" +#include "utils/math_utils.h" + +namespace gpuav { + +struct PostProcessingHeapCbState { + vko::BufferRange post_process_variables; +}; + +struct HeapSizes { + uint32_t resource_heap_size; + uint32_t resource_reserved_offset; + uint32_t resource_reserved_size; + uint32_t sampler_heap_size; + uint32_t sampler_reserved_offset; + uint32_t sampler_reserved_size; +}; + +struct ValidDescriptors { + vko::BufferRange descriptors; + uint8_t* resource_heap_memory; + uint8_t* sampler_heap_memory; +}; + +struct Slot { + // see gpuav_shaders_constants.h for how we split this metadata up + uint32_t meta_data; + // OpVariable ID of descriptor accessed. + // This is required to distinguish between 2 aliased descriptors + uint32_t variable_id; + // Used in order to print out information about which instruction caused the issue + uint32_t instruction_position_offset; + // Last accessed byte + uint32_t byte_offset; +}; + +void RegisterPostProcessingDescriptorHeap(Validator& gpuav, CommandBufferSubState& cb) { + if (!gpuav.gpuav_settings.shader_instrumentation.descriptor_heap) { + return; + } + + cb.on_instrumentation_common_desc_update_functions.emplace_back( + [](CommandBufferSubState& cb, VkPipelineBindPoint, const Location& loc, CommonDescriptorUpdate& out_update) mutable { + PostProcessingHeapCbState& pp_cb_state = cb.shared_resources_cache.GetOrCreate(); + pp_cb_state.post_process_variables = + cb.gpu_resources_manager.GetHostCoherentBufferRange(sizeof(Slot) * kDebugMaxDescSetAndBindings); + + out_update.buffer = pp_cb_state.post_process_variables.buffer; + out_update.offset = pp_cb_state.post_process_variables.offset; + out_update.range = pp_cb_state.post_process_variables.size; + out_update.address = pp_cb_state.post_process_variables.offset_address; + out_update.binding = glsl::kBindingInstDescriptorHeapPostProcess; + memset(pp_cb_state.post_process_variables.offset_mapped_ptr, 0, sizeof(VkDeviceAddressRangeEXT)); + }); + + gpuav::vko::IndirectAccessMap indirect_access_map = + std::make_shared>(); + cb.on_post_cb_submission_functions.emplace_back([indirect_access_map](Validator& gpuav, CommandBufferSubState& cb, + VkCommandBuffer per_post_submission_cb) { + PostProcessingHeapCbState* pp_cb_state = cb.shared_resources_cache.TryGet(); + if (pp_cb_state) { + DispatchDeviceWaitIdle(gpuav.device); // Todo + const Slot* data = reinterpret_cast(pp_cb_state->post_process_variables.offset_mapped_ptr); + if (!data) { + return; + } + for (uint32_t i = 0; i < kDebugMaxDescSetAndBindings; ++i) { + const Slot& slot = data[i]; + if ((slot.meta_data & glsl::kPostProcessMetaMaskAccessed) == 0) { + break; + } + + uint32_t shader_id = slot.meta_data & glsl::kShaderIdMask; + + auto it = gpuav.instrumented_shaders_map_.find(shader_id); + if (it == gpuav.instrumented_shaders_map_.end()) { + assert(false); + continue; + } + + const ::spirv::ResourceInterfaceVariable* resource_variable = nullptr; + const VkShaderDescriptorSetAndBindingMappingInfoEXT* mappings = nullptr; + VkShaderStageFlagBits stage = VK_SHADER_STAGE_ALL; + if (it->second.pipeline != VK_NULL_HANDLE) { + // We use pipeline over vkShaderModule as likely they will have been destroyed by now + const vvl::Pipeline* pipeline_state = gpuav.Get(it->second.pipeline).get(); + for (const ShaderStageState& stage_state : pipeline_state->stage_states) { + auto variable_it = stage_state.entrypoint->resource_interface_variable_map.find(slot.variable_id); + if (variable_it != stage_state.entrypoint->resource_interface_variable_map.end()) { + mappings = + vku::FindStructInPNextChain(stage_state.GetPNext()); + resource_variable = variable_it->second; + stage = stage_state.GetStage(); + break; + } + } + } else if (it->second.shader_object != VK_NULL_HANDLE) { + const vvl::ShaderObject* shader_object_state = gpuav.Get(it->second.shader_object).get(); + ASSERT_AND_CONTINUE(shader_object_state->stage.entrypoint); + mappings = vku::FindStructInPNextChain( + shader_object_state->create_info.pNext); + auto variable_it = + shader_object_state->stage.entrypoint->resource_interface_variable_map.find(slot.variable_id); + if (variable_it != shader_object_state->stage.entrypoint->resource_interface_variable_map.end()) { + resource_variable = variable_it->second; + stage = shader_object_state->create_info.stage; + } + } + ASSERT_AND_CONTINUE(resource_variable); + ASSERT_AND_CONTINUE(mappings); + + for (uint32_t j = 0; j < mappings->mappingCount; ++j) { + const auto& mapping = mappings->pMappings[j]; + if (mapping.descriptorSet != resource_variable->decorations.set || + mapping.firstBinding != resource_variable->decorations.binding) { + continue; + } + bool shader_record = false; + uint32_t push_offset = 0u; + uint32_t address_offset = 0u; + uint32_t size = 0u; + if (mapping.source == VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_INDIRECT_INDEX_EXT) { + if (mapping.resourceMask == VK_SPIRV_RESOURCE_TYPE_SAMPLER_BIT_EXT) { + push_offset = mapping.sourceData.indirectIndex.samplerPushOffset; + address_offset = mapping.sourceData.indirectIndex.samplerAddressOffset; + } else { + push_offset = mapping.sourceData.indirectIndex.pushOffset; + address_offset = mapping.sourceData.indirectIndex.addressOffset; + } + size = sizeof(uint32_t); + } else if (mapping.source == VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_INDIRECT_INDEX_ARRAY_EXT) { + // Todo, factor in array index + if (mapping.resourceMask == VK_SPIRV_RESOURCE_TYPE_SAMPLER_BIT_EXT) { + push_offset = mapping.sourceData.indirectIndexArray.samplerPushOffset; + address_offset = mapping.sourceData.indirectIndexArray.samplerAddressOffset; + } else { + push_offset = mapping.sourceData.indirectIndexArray.pushOffset; + address_offset = mapping.sourceData.indirectIndexArray.addressOffset; + } + size = sizeof(uint32_t); + } else if (mapping.source == VK_DESCRIPTOR_MAPPING_SOURCE_INDIRECT_ADDRESS_EXT) { + push_offset = mapping.sourceData.indirectAddress.pushOffset; + address_offset = mapping.sourceData.indirectAddress.addressOffset; + size = sizeof(VkDeviceAddress); + } else if (mapping.source == VK_DESCRIPTOR_MAPPING_SOURCE_SHADER_RECORD_ADDRESS_EXT) { + shader_record = true; + address_offset = mapping.sourceData.shaderRecordAddressOffset; + size = sizeof(VkDeviceAddress); + } else { + continue; + } + + VkDeviceAddress device_address = cb.GetPushData(push_offset); + // Temporary to mute warnings, until validation that requires this field is added + (void)stage; + + vko::IndirectKey key = {shader_record, push_offset, address_offset}; + vko::StagingBuffer staging_buffer(cb.gpu_resources_manager, size, per_post_submission_cb); + indirect_access_map->insert({key, staging_buffer}); + + if (shader_record) { + address_offset += gpuav.phys_dev_ext_props.ray_tracing_props_khr.shaderGroupHandleSize; + } + + const auto buffers = gpuav.GetBuffersByAddress(device_address); + if (buffers.size() == 1) { + VkBufferMemoryBarrier barrier_write_after_read = vku::InitStructHelper(); + barrier_write_after_read.srcAccessMask = VK_ACCESS_MEMORY_READ_BIT; + barrier_write_after_read.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + barrier_write_after_read.buffer = buffers[0]->VkHandle(); + barrier_write_after_read.offset = address_offset; + barrier_write_after_read.size = size; + + DispatchCmdPipelineBarrier(per_post_submission_cb, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 1, &barrier_write_after_read, 0, + nullptr); + VkBufferCopy copy; + copy.srcOffset = address_offset; + copy.dstOffset = staging_buffer.GetBufferRange().offset; + copy.size = size; + DispatchCmdCopyBuffer(per_post_submission_cb, buffers[0]->VkHandle(), + staging_buffer.GetBufferRange().buffer, 1, ©); + + VkBufferMemoryBarrier barrier_read_before_write = vku::InitStructHelper(); + barrier_read_before_write.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + barrier_read_before_write.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT; + barrier_read_before_write.buffer = buffers[0]->VkHandle(); + barrier_read_before_write.offset = address_offset; + barrier_read_before_write.size = size; + + DispatchCmdPipelineBarrier(per_post_submission_cb, VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 1, &barrier_read_before_write, + 0, nullptr); + + staging_buffer.CmdCopyDeviceToHost(per_post_submission_cb); + } + } + } + } + }); + + cb.on_cb_completion_functions.emplace_back([indirect_access_map](Validator& gpuav, CommandBufferSubState& cb, + const CommandBufferSubState::LabelLogging& label_logging, + const Location& submission_loc) { + PostProcessingHeapCbState* pp_cb_state = cb.shared_resources_cache.TryGet(); + if (pp_cb_state) { + const Slot* data = reinterpret_cast(pp_cb_state->post_process_variables.offset_mapped_ptr); + if (!data) { + return false; + } + std::vector validated_resource_variables; + for (uint32_t i = 0; i < kDebugMaxDescSetAndBindings; ++i) { + const Slot& slot = data[i]; + if ((slot.meta_data & glsl::kPostProcessMetaMaskAccessed) == 0) { + break; + } + + uint32_t shader_id = slot.meta_data & glsl::kShaderIdMask; + + const uint32_t error_logger_i = + (slot.meta_data & glsl::kPostProcessMetaMaskErrorLoggerIndex) >> glsl::kPostProcessMetaShiftErrorLoggerIndex; + const CommandBufferSubState::CommandErrorLogger& cmd_error_logger = cb.GetErrorLogger(error_logger_i); + std::string debug_region_name = + cb.GetDebugLabelRegion(cmd_error_logger.label_cmd_i, label_logging.initial_label_stack); + + Location access_loc(cmd_error_logger.loc.Get(), debug_region_name); + vvl::DescriptorHeapValidator context(gpuav, cb, 0, nullptr, access_loc); + context.SetObjlistForGpuAv(&cmd_error_logger.objlist); + + const ::spirv::ResourceInterfaceVariable* resource_variable = nullptr; + + const vvl::Pipeline* pipeline_state = nullptr; + const vvl::ShaderObject* shader_object_state = nullptr; + + auto it = gpuav.instrumented_shaders_map_.find(shader_id); + if (it == gpuav.instrumented_shaders_map_.end()) { + assert(false); + continue; + } + + if (it->second.pipeline != VK_NULL_HANDLE) { + // We use pipeline over vkShaderModule as likely they will have been destroyed by now + pipeline_state = gpuav.Get(it->second.pipeline).get(); + } else if (it->second.shader_object != VK_NULL_HANDLE) { + shader_object_state = gpuav.Get(it->second.shader_object).get(); + ASSERT_AND_CONTINUE(shader_object_state->stage.entrypoint); + } else { + assert(false); + continue; + } + + const VkShaderDescriptorSetAndBindingMappingInfoEXT* mappings = nullptr; + bool pipeline = false; + bool robustness = false; + + if (pipeline_state) { + for (const ShaderStageState& stage_state : pipeline_state->stage_states) { + ASSERT_AND_CONTINUE(stage_state.entrypoint); + auto variable_it = stage_state.entrypoint->resource_interface_variable_map.find(slot.variable_id); + if (variable_it != stage_state.entrypoint->resource_interface_variable_map.end()) { + mappings = + vku::FindStructInPNextChain(stage_state.GetPNext()); + resource_variable = variable_it->second; + pipeline = true; + if (pipeline_state->uses_pipeline_robustness) { + robustness = true; + } + break; // Only need to find a single entry point + } + } + } else if (shader_object_state) { + ASSERT_AND_CONTINUE(shader_object_state->stage.entrypoint); + mappings = vku::FindStructInPNextChain( + shader_object_state->create_info.pNext); + auto variable_it = + shader_object_state->stage.entrypoint->resource_interface_variable_map.find(slot.variable_id); + if (variable_it != shader_object_state->stage.entrypoint->resource_interface_variable_map.end()) { + resource_variable = variable_it->second; + } + } + ASSERT_AND_CONTINUE(resource_variable); + ASSERT_AND_CONTINUE(mappings); + if (std::find(validated_resource_variables.begin(), validated_resource_variables.end(), resource_variable) != + validated_resource_variables.end()) { + continue; + } + + context.ValidateBinding(gpuav, *resource_variable, *mappings, indirect_access_map, slot.byte_offset, pipeline, + robustness); + validated_resource_variables.push_back(resource_variable); + } + } + return true; + }); +} + +} // namespace gpuav diff --git a/layers/gpuav/instrumentation/post_process_descriptor_heap.h b/layers/gpuav/instrumentation/post_process_descriptor_heap.h new file mode 100644 index 00000000000..2f597093ca3 --- /dev/null +++ b/layers/gpuav/instrumentation/post_process_descriptor_heap.h @@ -0,0 +1,25 @@ +/* Copyright (c) 2025-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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +namespace gpuav { +class Validator; +class CommandBufferSubState; + +const int kDebugMaxDescSetAndBindings = 32 * 32; + +void RegisterPostProcessingDescriptorHeap(Validator& gpuav, CommandBufferSubState& cb); + +} // namespace gpuav diff --git a/layers/gpuav/resources/gpuav_state_trackers.h b/layers/gpuav/resources/gpuav_state_trackers.h index 46a21ce9190..54d7e625719 100644 --- a/layers/gpuav/resources/gpuav_state_trackers.h +++ b/layers/gpuav/resources/gpuav_state_trackers.h @@ -162,6 +162,14 @@ class CommandBufferSubState : public vvl::CommandBufferSubState { // Track which index we have bound our Descriptor Buffer in CmdBindDescriptorBuffersEXT uint32_t resource_descriptor_buffer_index_; + std::vector push_data_; + + template + T GetPushData(size_t offset) { + assert(offset + sizeof(T) <= push_data_.size()); + return *reinterpret_cast(push_data_.data() + offset); + } + private: void AllocateResources(const Location &loc); void ResetCBState(bool should_destroy); diff --git a/layers/gpuav/resources/gpuav_vulkan_objects.h b/layers/gpuav/resources/gpuav_vulkan_objects.h index 77bb7bbead0..d1d92e9f5e0 100644 --- a/layers/gpuav/resources/gpuav_vulkan_objects.h +++ b/layers/gpuav/resources/gpuav_vulkan_objects.h @@ -21,6 +21,7 @@ #include #include +#include #include "containers/custom_containers.h" #include "containers/range.h" @@ -324,6 +325,26 @@ class SharedResourcesCache { shared_validation_resources_map_; }; +struct IndirectKey { + bool shader_record; + uint32_t push_offset; + uint32_t address_offset; + bool operator==(const IndirectKey &other) const noexcept { + return shader_record == other.shader_record && push_offset == other.push_offset && address_offset == other.address_offset; + } +}; + +struct IndirectKeyHash { + size_t operator()(const gpuav::vko::IndirectKey &k) const noexcept { + size_t h1 = std::hash{}(k.shader_record); + size_t h2 = std::hash{}(k.push_offset); + size_t h3 = std::hash{}(k.address_offset); + return h1 ^ (h2 << 1) ^ (h3 << 2); + } +}; + +using IndirectAccessMap = std::shared_ptr>; + } // namespace vko } // namespace gpuav diff --git a/layers/gpuav/shaders/gpuav_error_codes.h b/layers/gpuav/shaders/gpuav_error_codes.h index d7830189a97..76c2ef2d5a6 100644 --- a/layers/gpuav/shaders/gpuav_error_codes.h +++ b/layers/gpuav/shaders/gpuav_error_codes.h @@ -43,6 +43,7 @@ const int kErrorGroup_GpuPreBuildAccelerationStructures = 12; const int kErrorGroup_InstMeshShading = 13; const int kErrorGroup_InstRayHitObject = 14; const int kErrorGroup_SharedMemoryDataRace = 15; +const int kErrorGroup_InstDescriptorHeap = 16; // We just take ExecutionModel and normalize it so we only use 5 bits to store it const int kExecutionModel_Vertex = 0; @@ -147,6 +148,24 @@ const int kErrorSubCode_Sanitizer_Fminmax = 5; const int kErrorSubCode_Sanitizer_CoopMatAlignment = 6; const int kErrorSubCode_Sanitizer_Count = 7; // update when adding new item +// Descriptor heap +const int kErrorSubCode_HeapBufferPointerAlignment = 1; +const int kErrorSubCode_HeapSamplerPointerAlignment = 2; +const int kErrorSubCode_HeapImagePointerAlignment = 3; +const int kErrorSubCode_HeapImageTexelPointerAlignment = 4; +const int kErrorSubCode_HeapAccelerationStructureAlignment = 5; +const int kErrorSubCode_HeapTensorAlignment = 6; +const int kErrorSubCode_HeapInvalidBufferDescriptor = 7; +const int kErrorSubCode_HeapInvalidSamplerDescriptor = 8; +const int kErrorSubCode_HeapInvalidImageDescriptor = 9; +const int kErrorSubCode_HeapInvalidTexelPointer = 10; +const int kErrorSubCode_HeapUnregisteredCustomBorderColor = 11; +const int kErrorSubCode_HeapDifferentCustomBorderColor = 12; +const int kErrorSubCode_HeapResourceOOB = 13; +const int kErrorSubCode_HeapResourceReservedRange = 14; +const int kErrorSubCode_HeapSamplerOOB = 15; +const int kErrorSubCode_HeapSamplerReservedRange = 16; + // Pre Draw // // The draw count exceeded the draw buffer size diff --git a/layers/gpuav/shaders/gpuav_shaders_constants.h b/layers/gpuav/shaders/gpuav_shaders_constants.h index de5c8a10bdb..0c73b67e72c 100644 --- a/layers/gpuav/shaders/gpuav_shaders_constants.h +++ b/layers/gpuav/shaders/gpuav_shaders_constants.h @@ -30,6 +30,7 @@ using uint = unsigned int; // This value only matters for host code, but it is defined here so it can be used // in unit tests. const uint kDebugInputBindlessMaxDescriptors = 1024u * 1024u * 4u; +const uint kDebugMaxDescSetAndBindings = 32 * 32; #endif @@ -62,7 +63,9 @@ const int kBindingInstActionIndex = 5; const int kBindingInstCmdResourceIndex = 6; const int kBindingInstCmdErrorsCount = 7; const int kBindingInstVertexAttributeFetchLimits = 8; -const int kTotalBindings = 9; +const int kBindingInstDescriptorHeapPostProcess = 9; +const int kBindingInstDescriptorHeapValidDescriptors = 10; +const int kTotalBindings = 11; // Validation pipelines // --- @@ -145,6 +148,22 @@ const uint kPostProcessMetaMaskAccessed = 1u << 31; const uint kPostProcessMetaShiftErrorLoggerIndex = 18; const uint kPostProcessMetaMaskErrorLoggerIndex = 0x1FFF << kPostProcessMetaShiftErrorLoggerIndex; +const uint kDescriptorHeapUniformBuffer = 1 << 0; +const uint kDescriptorHeapStorageBuffer = 1 << 1; +const uint kDescriptorHeapSampler = 1 << 2; +const uint kDescriptorHeapImage = 1 << 3; +const uint kDescriptorHeapTexelPointer = 1 << 4; +const uint kDescriptorHeapUnregisteredCustomBorder = 1 << 5; +const uint kDescriptorHeapCustomBorderDifferentColor = 1 << 6; +const uint kDescriptorHeapImageArrayed = 1 << 7; +const uint kDescriptorHeapImageMultiSampled = 1 << 8; +const uint kDescriptorHeapImageSampledMask = 0x3; +const uint kDescriptorHeapImageSampledShift = 9; +const uint kDescriptorHeapImageDimMask = 0x7; +const uint kDescriptorHeapImageDimShift = 11; +const uint kDescriptorHeapImageFormatMask = 0x3F; +const uint kDescriptorHeapImageFormatShift = 14; + #ifdef __cplusplus } // namespace glsl } // namespace gpuav diff --git a/layers/gpuav/shaders/instrumentation/descriptor_heap.comp b/layers/gpuav/shaders/instrumentation/descriptor_heap.comp new file mode 100644 index 00000000000..9e7c35fd40c --- /dev/null +++ b/layers/gpuav/shaders/instrumentation/descriptor_heap.comp @@ -0,0 +1,125 @@ +// Copyright (c) 2025-2026 The Khronos Group Inc. +// Copyright (c) 2025-2026 Valve Corporation +// Copyright (c) 2025-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. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// NOTE: This file doesn't contain any entrypoints and should be compiled with the --no-link option for glslang + +#version 450 +#extension GL_GOOGLE_include_directive : enable +#include "common_descriptor_sets.h" +#include "error_payload.h" + +struct Data { + uint meta; + uint variable_id; + uint inst_offset; + uint byte_offset; +}; + +layout(set = kInstDefaultDescriptorSet, binding = kBindingInstDescriptorHeapPostProcess, scalar) buffer PostProcessSSBO { + Data slot[]; // PostProcessDescriptorHeapSlot +} gpuav; + +layout(set = kInstDefaultDescriptorSet, binding = kBindingInstDescriptorHeapValidDescriptors, scalar) buffer ValidDescriptors { + uint resource_heap_size; + uint resource_reserved_offset; + uint resource_reserved_size; + uint sampler_heap_size; + uint sampler_reserved_offset; + uint sampler_reserved_size; + uint descriptors[]; +} heap; + +void inst_descriptor_heap(const uint inst_offset, const uint byte_offset, const uint slot_index, const uint variable_id) { + const uint cmd_id = inst_error_logger_index_buffer.index[0] << kPostProcessMetaShiftErrorLoggerIndex; + gpuav.slot[slot_index].meta = kPostProcessMetaMaskAccessed | cmd_id | SpecConstantLinkShaderId; + gpuav.slot[slot_index].variable_id = variable_id; + gpuav.slot[slot_index].inst_offset = inst_offset; + gpuav.slot[slot_index].byte_offset = byte_offset; +} + +void inst_descriptor(const uint inst_offset, const uint descriptor_type, const int array_stride, const int offset, const uint alignment, const uint descriptor_error, const uint alignment_error) { + if (((array_stride * offset) % alignment) != 0) { + error_payload = ErrorPayload( + inst_offset, + SpecConstantLinkShaderId | (kErrorGroup_InstDescriptorHeap << kErrorGroup_Shift) | (alignment_error << kErrorSubCode_Shift), + array_stride, + offset, + alignment + ); + } else if ((heap.descriptors[offset] & descriptor_type) != descriptor_type) { + error_payload = ErrorPayload( + inst_offset, + SpecConstantLinkShaderId | (kErrorGroup_InstDescriptorHeap << kErrorGroup_Shift) | (descriptor_error << kErrorSubCode_Shift), + offset, + descriptor_type, + heap.descriptors[offset] + ); + } + if ((descriptor_type & kDescriptorHeapSampler) != 0) { + uint heap_offset = array_stride * offset; + if (heap_offset >= heap.sampler_heap_size) { + error_payload = ErrorPayload( + inst_offset, + SpecConstantLinkShaderId | (kErrorGroup_InstDescriptorHeap << kErrorGroup_Shift) | (kErrorSubCode_HeapSamplerOOB << kErrorSubCode_Shift), + heap_offset, + heap.sampler_heap_size, + 0 + ); + } else if (heap_offset >= heap.sampler_reserved_offset && heap_offset < heap.sampler_reserved_offset + heap.sampler_reserved_size) { + error_payload = ErrorPayload( + inst_offset, + SpecConstantLinkShaderId | (kErrorGroup_InstDescriptorHeap << kErrorGroup_Shift) | (kErrorSubCode_HeapSamplerReservedRange << kErrorSubCode_Shift), + heap_offset, + heap.sampler_reserved_offset, + heap.sampler_reserved_size + ); + } + } else { + uint heap_offset = array_stride * offset; + if (heap_offset >= heap.resource_heap_size) { + error_payload = ErrorPayload( + inst_offset, + SpecConstantLinkShaderId | (kErrorGroup_InstDescriptorHeap << kErrorGroup_Shift) | (kErrorSubCode_HeapResourceOOB << kErrorSubCode_Shift), + heap_offset, + heap.resource_heap_size, + 0 + ); + } else if (heap_offset >= heap.resource_reserved_offset && heap_offset < heap.resource_reserved_offset + heap.resource_reserved_size) { + error_payload = ErrorPayload( + inst_offset, + SpecConstantLinkShaderId | (kErrorGroup_InstDescriptorHeap << kErrorGroup_Shift) | (kErrorSubCode_HeapResourceReservedRange << kErrorSubCode_Shift), + heap_offset, + heap.resource_reserved_offset, + heap.resource_reserved_size + ); + } + } + if ((heap.descriptors[offset] & (kDescriptorHeapUnregisteredCustomBorder | kDescriptorHeapCustomBorderDifferentColor)) != 0) { + uint error_sub_code = 0; + if ((heap.descriptors[offset] & kDescriptorHeapUnregisteredCustomBorder) != 0) { + error_sub_code = kErrorSubCode_HeapUnregisteredCustomBorderColor; + } else { + error_sub_code = kErrorSubCode_HeapDifferentCustomBorderColor; + } + error_payload = ErrorPayload( + inst_offset, + SpecConstantLinkShaderId | (kErrorGroup_InstDescriptorHeap << kErrorGroup_Shift) | (error_sub_code << kErrorSubCode_Shift), + offset, + 0, + 0 + ); + } +} diff --git a/layers/gpuav/spirv/CMakeLists.txt b/layers/gpuav/spirv/CMakeLists.txt index b1983f4f18f..6133127056f 100644 --- a/layers/gpuav/spirv/CMakeLists.txt +++ b/layers/gpuav/spirv/CMakeLists.txt @@ -23,6 +23,8 @@ target_sources(gpu_av_spirv PRIVATE descriptor_class_general_buffer_pass.cpp descriptor_class_texel_buffer_pass.h descriptor_class_texel_buffer_pass.cpp + descriptor_heap_pass.h + descriptor_heap_pass.cpp buffer_device_address_pass.h buffer_device_address_pass.cpp ray_query_pass.h diff --git a/layers/gpuav/spirv/descriptor_heap_pass.cpp b/layers/gpuav/spirv/descriptor_heap_pass.cpp new file mode 100644 index 00000000000..203d2101fe0 --- /dev/null +++ b/layers/gpuav/spirv/descriptor_heap_pass.cpp @@ -0,0 +1,195 @@ +/* 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "descriptor_heap_pass.h" +#include "generated/spirv_grammar_helper.h" +#include "containers/container_utils.h" +#include "state_tracker/shader_instruction.h" +#include "module.h" +#include +#include + +#include "generated/gpuav_offline_spirv.h" +#include "gpuav/shaders/gpuav_shaders_constants.h" +#include "gpuav/shaders/gpuav_error_codes.h" + +namespace gpuav { +namespace spirv { + +const static OfflineModule kOfflineModule = {instrumentation_descriptor_heap_comp, instrumentation_descriptor_heap_comp_size, + UseErrorPayloadVariable}; + +const static OfflineFunction kOfflineFunctionPostProcess = {"inst_descriptor_heap", + instrumentation_descriptor_heap_comp_function_0_offset}; + +DescriptorHeapPass::DescriptorHeapPass(Module& module, VkPhysicalDeviceDescriptorHeapPropertiesEXT heap_props, + VkPhysicalDeviceDescriptorHeapTensorPropertiesARM heap_tensor_props) + : Pass(module, kOfflineModule), heap_props_(heap_props), heap_tensor_props_(heap_tensor_props) { + module.use_bda_ = true; +} + +void DescriptorHeapPass::CreateFunctionCall(BasicBlock& block, InstructionIt* inst_it, const InstructionMeta& meta) { + if (meta.post_process) { + const uint32_t inst_position = meta.target_instruction->GetPositionOffset(); + const uint32_t inst_position_id = module_.type_manager_.CreateConstantUInt32(inst_position).Id(); + + const uint32_t function_result = module_.TakeNextId(); + const uint32_t function_def = GetLinkFunction(link_function_id_, kOfflineFunctionPostProcess); + const uint32_t void_type = module_.type_manager_.GetTypeVoid().Id(); + + const uint32_t zero = module_.type_manager_.CreateConstantUInt32(0).Id(); + const uint32_t descriptor_offset_id = + meta.access_chain_insts.empty() + ? zero + : GetLastByte(*meta.descriptor_type, meta.access_chain_insts, meta.coop_mat_access, block, inst_it); + + const Constant& slot_index = type_manager_.CreateConstantUInt32(slot_index_++); + if (slot_index_ > glsl::kDebugMaxDescSetAndBindings) { + return; + } + + const Constant& variable_id_constant = type_manager_.GetConstantUInt32(meta.variable_id); + block.CreateInstruction(spv::OpFunctionCall, + {void_type, function_result, function_def, inst_position_id, descriptor_offset_id, slot_index.Id(), + variable_id_constant.Id()}, + inst_it); + } + + // Temporary, to mute warnings until validation that requires these fields is added + (void)heap_props_; + (void)heap_tensor_props_; + + module_.need_log_error_ = true; +} + +bool DescriptorHeapPass::HeapPointerRequiresInstrumentation(const Function&, const Instruction&, InstructionMeta&) { return false; } + +bool DescriptorHeapPass::RequiresInstrumentation(const Function& function, const Instruction& inst, InstructionMeta& meta) { + const uint32_t opcode = inst.Opcode(); + + // Save information to be used to make the Function + meta.target_instruction = &inst; + + bool requires_instrumentation = HeapPointerRequiresInstrumentation(function, inst, meta); + + if (!IsValueIn(spv::Op(opcode), {spv::OpLoad, spv::OpStore, spv::OpAtomicStore, spv::OpAtomicLoad, spv::OpAtomicExchange})) { + return requires_instrumentation; + } + + const Variable* variable = nullptr; + const Instruction* next_access_chain = function.FindInstruction(inst.Operand(0)); + if (next_access_chain && next_access_chain->IsNonPtrAccessChain()) { + meta.access_chain_insts.push_back(next_access_chain); + // We need to walk down possibly multiple chained OpAccessChains or OpCopyObject to get the variable + while (next_access_chain && next_access_chain->IsNonPtrAccessChain()) { + const uint32_t access_chain_base_id = next_access_chain->Operand(0); + variable = module_.type_manager_.FindVariableById(access_chain_base_id); + if (variable) { + break; // found + } + next_access_chain = function.FindInstruction(access_chain_base_id); + } + } else { + variable = module_.type_manager_.FindVariableById(inst.Operand(0)); + } + + if (!variable) { + return requires_instrumentation; + } + meta.variable_id = variable->inst_.ResultId(); + meta.descriptor_type = variable->PointerType(type_manager_); + + bool is_coop_mat = opcode == spv::OpCooperativeMatrixLoadKHR || opcode == spv::OpCooperativeMatrixStoreKHR; + if (is_coop_mat) { + meta.coop_mat_access = GetCooperativeMatrixAccess(inst, function); + } + + bool set_found = false; + for (const auto& annotation : module_.annotations_) { + if (annotation->Opcode() == spv::OpDecorate && annotation->Word(1) == variable->Id()) { + if (annotation->Word(2) == spv::DecorationDescriptorSet) { + set_found = true; + } + } + } + + if (!set_found) { + return requires_instrumentation; + } + + meta.post_process = true; + return true; +} + +void DescriptorHeapPass::PrintDebugInfo() const { + std::cout << "DescriptorHeapPass instrumentation count: " << instrumentations_count_ << '\n'; +} + +// Created own Instrument() because need to control finding the largest offset in a given block +bool DescriptorHeapPass::Instrument() { + // Can safely loop function list as there is no injecting of new Functions until linking time + for (const auto& function : module_.functions_) { + if (!function.called_from_target_) { + continue; + } + + for (auto block_it = function.blocks_.begin(); block_it != function.blocks_.end(); ++block_it) { + BasicBlock& current_block = **block_it; + + cf_.Update(current_block); + if (debug_disable_loops_ && cf_.in_loop) continue; + + auto& block_instructions = current_block.instructions_; + + // < Descriptor SSA ID, Highest offset byte that will be accessed > + vvl::unordered_map block_highest_offset_map; + + if (!module_.settings_.safe_mode) { + // Pre-pass loop the Block to get the highest offset accessed (statically known) + // Do here before we inject instructions into the block list below + for (auto inst_it = block_instructions.begin(); inst_it != block_instructions.end(); ++inst_it) { + InstructionMeta meta; + // Every instruction is analyzed by the specific pass and lets us know if we need to inject a function or not + if (!RequiresInstrumentation(function, *(inst_it->get()), meta)) continue; + } + } + + for (auto inst_it = block_instructions.begin(); inst_it != block_instructions.end(); ++inst_it) { + InstructionMeta meta; + // Every instruction is analyzed by the specific pass and lets us know if we need to inject a function or not + if (!RequiresInstrumentation(function, *(inst_it->get()), meta)) continue; + + if (IsMaxInstrumentationsCount()) continue; + instrumentations_count_++; + + // inst_it is updated to the instruction after the new function call, it will not add/remove any Blocks + CreateFunctionCall(current_block, &inst_it, meta); + } + } + } + + if (instrumentations_count_ > 75) { + module_.InternalWarning( + "GPUAV-Compile-time-descriptor-heap", + "This shader will be very slow to compile and runtime performance may also be slow. This is due to the number of OOB " + "checks for storage/uniform " + "buffers. Turn on the |gpuav_force_on_robustness| setting to skip these checks and improve GPU-AV performance."); + } + + return instrumentations_count_ != 0; +} + +} // namespace spirv +} // namespace gpuav diff --git a/layers/gpuav/spirv/descriptor_heap_pass.h b/layers/gpuav/spirv/descriptor_heap_pass.h new file mode 100644 index 00000000000..0d84bdd4f3b --- /dev/null +++ b/layers/gpuav/spirv/descriptor_heap_pass.h @@ -0,0 +1,77 @@ +/* Copyright (c) 2025-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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +#include +#include "pass.h" + +#include "vulkan/vulkan_core.h" + +namespace gpuav { +namespace spirv { + +// Will make sure Descriptor Heap accesses are valid +class DescriptorHeapPass : public Pass { + public: + DescriptorHeapPass(Module& module, VkPhysicalDeviceDescriptorHeapPropertiesEXT heap_props, + VkPhysicalDeviceDescriptorHeapTensorPropertiesARM heap_tensor_props); + const char* Name() const final { return "DescriptorHeapPass"; } + + bool Instrument() final; + void PrintDebugInfo() const final; + + private: + VkPhysicalDeviceDescriptorHeapPropertiesEXT heap_props_{}; + VkPhysicalDeviceDescriptorHeapTensorPropertiesARM heap_tensor_props_{}; + + // This is metadata tied to a single instruction gathered during RequiresInstrumentation() to be used later + struct InstructionMeta { + const Instruction* target_instruction = nullptr; + + uint32_t variable_id = 0; + const Type* descriptor_type = nullptr; + CooperativeMatrixAccess coop_mat_access{}; + std::vector access_chain_insts; + + bool post_process = false; + bool buffer_pointer = false; + bool sampler_pointer = false; + bool image_pointer = false; + bool image_texel_pointer = false; + bool acceleration_structure_pointer = false; + bool tensor_pointer = false; + + uint32_t offset_id = 0; + uint32_t array_stride_id = 0; + uint32_t storage_class = 0; + uint32_t image_format = 0; + uint32_t image_dim = 0; + uint32_t image_arrayed = 0; + uint32_t image_multisampled = 0; + uint32_t image_sampled = 0; + }; + + bool HeapPointerRequiresInstrumentation(const Function& function, const Instruction& inst, InstructionMeta& meta); + bool RequiresInstrumentation(const Function& function, const Instruction& inst, InstructionMeta& meta); + void CreateFunctionCall(BasicBlock& block, InstructionIt* inst_it, const InstructionMeta& meta); + + // Function IDs to link in + uint32_t link_function_id_ = 0; + + uint32_t slot_index_ = 0; +}; + +} // namespace spirv +} // namespace gpuav \ No newline at end of file diff --git a/layers/layer_options.cpp b/layers/layer_options.cpp index 20cfdc68aff..2eb2a0027b7 100644 --- a/layers/layer_options.cpp +++ b/layers/layer_options.cpp @@ -200,6 +200,7 @@ const char* VK_LAYER_GPUAV_SHARED_MEMORY_DATA_RACE = "gpuav_shared_memory_data_r const char* VK_LAYER_GPUAV_MAX_INDICES_COUNT = "gpuav_max_indices_count"; const char* VK_LAYER_GPUAV_SELECT_INSTRUMENTED_SHADERS = "gpuav_select_instrumented_shaders"; const char* VK_LAYER_GPUAV_SHADERS_TO_INSTRUMENT = "gpuav_shaders_to_instrument"; +const char* VK_LAYER_GPUAV_DESCRIPTOR_HEAP = "gpuav_descriptor_heap"; const char* VK_LAYER_GPUAV_BUFFERS_VALIDATION = "gpuav_buffers_validation"; const char* VK_LAYER_GPUAV_INDIRECT_DRAWS_BUFFERS = "gpuav_indirect_draws_buffers"; @@ -981,6 +982,11 @@ void ProcessConfigAndEnvSettings(ConfigAndEnvSettings* settings_data) { gpuav_settings.shader_instrumentation.vertex_attribute_fetch_oob); } + if (vkuHasLayerSetting(layer_setting_set, VK_LAYER_GPUAV_DESCRIPTOR_HEAP)) { + vkuGetLayerSettingValue(layer_setting_set, VK_LAYER_GPUAV_DESCRIPTOR_HEAP, + gpuav_settings.shader_instrumentation.descriptor_heap); + } + if (vkuHasLayerSetting(layer_setting_set, VK_LAYER_GPUAV_BUFFER_ADDRESS_OOB)) { vkuGetLayerSettingValue(layer_setting_set, VK_LAYER_GPUAV_BUFFER_ADDRESS_OOB, gpuav_settings.shader_instrumentation.buffer_device_address); diff --git a/layers/vulkan/generated/gpuav_offline_spirv.cpp b/layers/vulkan/generated/gpuav_offline_spirv.cpp index 42cd289adc4..ec6c9964a26 100644 --- a/layers/vulkan/generated/gpuav_offline_spirv.cpp +++ b/layers/vulkan/generated/gpuav_offline_spirv.cpp @@ -272,6 +272,158 @@ 0x000200f9, 0x0000002d, 0x000200f8, 0x0000002d, 0x000100fd, 0x00010038}; [[maybe_unused]] const uint32_t instrumentation_descriptor_class_texel_buffer_comp_function_0_offset = 425; +[[maybe_unused]] const uint32_t instrumentation_descriptor_heap_comp_size = 1463; +[[maybe_unused]] const uint32_t instrumentation_descriptor_heap_comp[1463] = { + 0x07230203, 0x00010300, 0x0008000b, 0x000000cd, 0x00000000, 0x00020011, 0x00000001, 0x00020011, 0x00000005, 0x0006000b, + 0x00000001, 0x4c534c47, 0x6474732e, 0x3035342e, 0x00000000, 0x0003000e, 0x00000000, 0x00000001, 0x00030003, 0x00000002, + 0x000001c2, 0x00070004, 0x415f4c47, 0x675f4252, 0x735f7570, 0x65646168, 0x6e695f72, 0x00343674, 0x00070004, 0x455f4c47, + 0x625f5458, 0x65666675, 0x65725f72, 0x65726566, 0x0065636e, 0x00080004, 0x455f4c47, 0x625f5458, 0x65666675, 0x65725f72, + 0x65726566, 0x3265636e, 0x00000000, 0x00090004, 0x455f4c47, 0x625f5458, 0x65666675, 0x65725f72, 0x65726566, 0x5f65636e, + 0x63657675, 0x00000032, 0x00080004, 0x455f4c47, 0x735f5458, 0x616c6163, 0x6c625f72, 0x5f6b636f, 0x6f79616c, 0x00007475, + 0x000a0004, 0x475f4c47, 0x4c474f4f, 0x70635f45, 0x74735f70, 0x5f656c79, 0x656e696c, 0x7269645f, 0x69746365, 0x00006576, + 0x00080004, 0x475f4c47, 0x4c474f4f, 0x6e695f45, 0x64756c63, 0x69645f65, 0x74636572, 0x00657669, 0x000b0005, 0x00000009, + 0x74736e69, 0x7365645f, 0x70697263, 0x5f726f74, 0x70616568, 0x3b317528, 0x753b3175, 0x31753b31, 0x0000003b, 0x00050005, + 0x00000005, 0x74736e69, 0x66666f5f, 0x00746573, 0x00050005, 0x00000006, 0x65747962, 0x66666f5f, 0x00746573, 0x00050005, + 0x00000007, 0x746f6c73, 0x646e695f, 0x00007865, 0x00050005, 0x00000008, 0x69726176, 0x656c6261, 0x0064695f, 0x000c0005, + 0x00000014, 0x74736e69, 0x7365645f, 0x70697263, 0x28726f74, 0x753b3175, 0x31693b31, 0x3b31693b, 0x753b3175, 0x31753b31, + 0x0000003b, 0x00050005, 0x0000000d, 0x74736e69, 0x66666f5f, 0x00746573, 0x00060005, 0x0000000e, 0x63736564, 0x74706972, + 0x745f726f, 0x00657079, 0x00060005, 0x0000000f, 0x61727261, 0x74735f79, 0x65646972, 0x00000000, 0x00040005, 0x00000010, + 0x7366666f, 0x00007465, 0x00050005, 0x00000011, 0x67696c61, 0x6e656d6e, 0x00000074, 0x00070005, 0x00000012, 0x63736564, + 0x74706972, 0x655f726f, 0x726f7272, 0x00000000, 0x00060005, 0x00000013, 0x67696c61, 0x6e656d6e, 0x72655f74, 0x00726f72, + 0x00080005, 0x00000019, 0x6f727245, 0x676f4c72, 0x49726567, 0x7865646e, 0x66667542, 0x00007265, 0x00050006, 0x00000019, + 0x00000000, 0x65646e69, 0x00000078, 0x000a0005, 0x0000001b, 0x74736e69, 0x7272655f, 0x6c5f726f, 0x6567676f, 0x6e695f72, + 0x5f786564, 0x66667562, 0x00007265, 0x00040005, 0x00000022, 0x61746144, 0x00000000, 0x00050006, 0x00000022, 0x00000000, + 0x6174656d, 0x00000000, 0x00060006, 0x00000022, 0x00000001, 0x69726176, 0x656c6261, 0x0064695f, 0x00060006, 0x00000022, + 0x00000002, 0x74736e69, 0x66666f5f, 0x00746573, 0x00060006, 0x00000022, 0x00000003, 0x65747962, 0x66666f5f, 0x00746573, + 0x00060005, 0x00000024, 0x74736f50, 0x636f7250, 0x53737365, 0x004f4253, 0x00050006, 0x00000024, 0x00000000, 0x746f6c73, + 0x00000000, 0x00040005, 0x00000026, 0x61757067, 0x00000076, 0x00090005, 0x0000002a, 0x63657053, 0x736e6f43, 0x746e6174, + 0x6b6e694c, 0x64616853, 0x64497265, 0x00000000, 0x00060005, 0x0000003b, 0x6f727245, 0x79615072, 0x64616f6c, 0x00000000, + 0x00060006, 0x0000003b, 0x00000000, 0x74736e69, 0x66666f5f, 0x00746573, 0x00090006, 0x0000003b, 0x00000001, 0x64616873, + 0x655f7265, 0x726f7272, 0x636e655f, 0x6e69646f, 0x00000067, 0x00060006, 0x0000003b, 0x00000002, 0x61726170, 0x6574656d, + 0x00305f72, 0x00060006, 0x0000003b, 0x00000003, 0x61726170, 0x6574656d, 0x00315f72, 0x00060006, 0x0000003b, 0x00000004, + 0x61726170, 0x6574656d, 0x00325f72, 0x00060005, 0x0000003d, 0x6f727265, 0x61705f72, 0x616f6c79, 0x00000064, 0x00070005, + 0x00000048, 0x696c6156, 0x73654464, 0x70697263, 0x73726f74, 0x00000000, 0x00080006, 0x00000048, 0x00000000, 0x6f736572, + 0x65637275, 0x6165685f, 0x69735f70, 0x0000657a, 0x000a0006, 0x00000048, 0x00000001, 0x6f736572, 0x65637275, 0x7365725f, + 0x65767265, 0x666f5f64, 0x74657366, 0x00000000, 0x00090006, 0x00000048, 0x00000002, 0x6f736572, 0x65637275, 0x7365725f, + 0x65767265, 0x69735f64, 0x0000657a, 0x00080006, 0x00000048, 0x00000003, 0x706d6173, 0x5f72656c, 0x70616568, 0x7a69735f, + 0x00000065, 0x00090006, 0x00000048, 0x00000004, 0x706d6173, 0x5f72656c, 0x65736572, 0x64657672, 0x66666f5f, 0x00746573, + 0x00090006, 0x00000048, 0x00000005, 0x706d6173, 0x5f72656c, 0x65736572, 0x64657672, 0x7a69735f, 0x00000065, 0x00060006, + 0x00000048, 0x00000006, 0x63736564, 0x74706972, 0x0073726f, 0x00040005, 0x0000004a, 0x70616568, 0x00000000, 0x00060005, + 0x000000bc, 0x6f727265, 0x75735f72, 0x6f635f62, 0x00006564, 0x000a0047, 0x00000009, 0x00000029, 0x74736e69, 0x7365645f, + 0x70697263, 0x5f726f74, 0x70616568, 0x00000000, 0x00000000, 0x00080047, 0x00000014, 0x00000029, 0x74736e69, 0x7365645f, + 0x70697263, 0x00726f74, 0x00000000, 0x00040047, 0x00000018, 0x00000006, 0x00000004, 0x00030047, 0x00000019, 0x00000002, + 0x00050048, 0x00000019, 0x00000000, 0x00000023, 0x00000000, 0x00040047, 0x0000001b, 0x00000021, 0x00000006, 0x00040047, + 0x0000001b, 0x00000022, 0x00000007, 0x00050048, 0x00000022, 0x00000000, 0x00000023, 0x00000000, 0x00050048, 0x00000022, + 0x00000001, 0x00000023, 0x00000004, 0x00050048, 0x00000022, 0x00000002, 0x00000023, 0x00000008, 0x00050048, 0x00000022, + 0x00000003, 0x00000023, 0x0000000c, 0x00040047, 0x00000023, 0x00000006, 0x00000010, 0x00030047, 0x00000024, 0x00000002, + 0x00050048, 0x00000024, 0x00000000, 0x00000023, 0x00000000, 0x00040047, 0x00000026, 0x00000021, 0x00000009, 0x00040047, + 0x00000026, 0x00000022, 0x00000007, 0x00040047, 0x0000002a, 0x00000001, 0x00000000, 0x00040047, 0x00000047, 0x00000006, + 0x00000004, 0x00030047, 0x00000048, 0x00000002, 0x00050048, 0x00000048, 0x00000000, 0x00000023, 0x00000000, 0x00050048, + 0x00000048, 0x00000001, 0x00000023, 0x00000004, 0x00050048, 0x00000048, 0x00000002, 0x00000023, 0x00000008, 0x00050048, + 0x00000048, 0x00000003, 0x00000023, 0x0000000c, 0x00050048, 0x00000048, 0x00000004, 0x00000023, 0x00000010, 0x00050048, + 0x00000048, 0x00000005, 0x00000023, 0x00000014, 0x00050048, 0x00000048, 0x00000006, 0x00000023, 0x00000018, 0x00040047, + 0x0000004a, 0x00000021, 0x0000000a, 0x00040047, 0x0000004a, 0x00000022, 0x00000007, 0x00040015, 0x00000002, 0x00000020, + 0x00000000, 0x00020013, 0x00000003, 0x00070021, 0x00000004, 0x00000003, 0x00000002, 0x00000002, 0x00000002, 0x00000002, + 0x00040015, 0x0000000b, 0x00000020, 0x00000001, 0x000a0021, 0x0000000c, 0x00000003, 0x00000002, 0x00000002, 0x0000000b, + 0x0000000b, 0x00000002, 0x00000002, 0x00000002, 0x00040020, 0x00000016, 0x00000007, 0x00000002, 0x0003001d, 0x00000018, + 0x00000002, 0x0003001e, 0x00000019, 0x00000018, 0x00040020, 0x0000001a, 0x0000000c, 0x00000019, 0x0004003b, 0x0000001a, + 0x0000001b, 0x0000000c, 0x0004002b, 0x0000000b, 0x0000001c, 0x00000000, 0x00040020, 0x0000001d, 0x0000000c, 0x00000002, + 0x0004002b, 0x00000002, 0x00000020, 0x00000012, 0x0006001e, 0x00000022, 0x00000002, 0x00000002, 0x00000002, 0x00000002, + 0x0003001d, 0x00000023, 0x00000022, 0x0003001e, 0x00000024, 0x00000023, 0x00040020, 0x00000025, 0x0000000c, 0x00000024, + 0x0004003b, 0x00000025, 0x00000026, 0x0000000c, 0x0004002b, 0x00000002, 0x00000027, 0x80000000, 0x00040032, 0x00000002, + 0x0000002a, 0x0dead001, 0x0004002b, 0x0000000b, 0x0000002d, 0x00000001, 0x0004002b, 0x0000000b, 0x0000002f, 0x00000002, + 0x0004002b, 0x0000000b, 0x00000031, 0x00000003, 0x0004002b, 0x00000002, 0x00000036, 0x00000000, 0x00020014, 0x00000037, + 0x0007001e, 0x0000003b, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00040020, 0x0000003c, 0x00000006, + 0x0000003b, 0x0004003b, 0x0000003c, 0x0000003d, 0x00000006, 0x0004002b, 0x00000002, 0x0000003e, 0x10000000, 0x00060034, + 0x00000002, 0x0000003f, 0x000000c5, 0x0000002a, 0x0000003e, 0x0004002b, 0x0000000b, 0x00000040, 0x00000012, 0x0003001d, + 0x00000047, 0x00000002, 0x0009001e, 0x00000048, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000002, + 0x00000047, 0x00040020, 0x00000049, 0x0000000c, 0x00000048, 0x0004003b, 0x00000049, 0x0000004a, 0x0000000c, 0x0004002b, + 0x0000000b, 0x0000004b, 0x00000006, 0x00060034, 0x00000002, 0x00000052, 0x000000c5, 0x0000002a, 0x0000003e, 0x0004002b, + 0x00000002, 0x00000059, 0x00000004, 0x00060034, 0x00000002, 0x00000067, 0x000000c5, 0x0000002a, 0x0000003e, 0x0004002b, + 0x00000002, 0x00000068, 0x003c0000, 0x00060034, 0x00000002, 0x00000069, 0x000000c5, 0x00000067, 0x00000068, 0x0004002b, + 0x0000000b, 0x00000070, 0x00000004, 0x0004002b, 0x0000000b, 0x00000079, 0x00000005, 0x00060034, 0x00000002, 0x00000081, + 0x000000c5, 0x0000002a, 0x0000003e, 0x0004002b, 0x00000002, 0x00000082, 0x00400000, 0x00060034, 0x00000002, 0x00000083, + 0x000000c5, 0x00000081, 0x00000082, 0x00060034, 0x00000002, 0x00000094, 0x000000c5, 0x0000002a, 0x0000003e, 0x0004002b, + 0x00000002, 0x00000095, 0x00340000, 0x00060034, 0x00000002, 0x00000096, 0x000000c5, 0x00000094, 0x00000095, 0x00060034, + 0x00000002, 0x000000ac, 0x000000c5, 0x0000002a, 0x0000003e, 0x0004002b, 0x00000002, 0x000000ad, 0x00380000, 0x00060034, + 0x00000002, 0x000000ae, 0x000000c5, 0x000000ac, 0x000000ad, 0x0004002b, 0x00000002, 0x000000b7, 0x00000060, 0x0004002b, + 0x00000002, 0x000000bf, 0x00000020, 0x0004002b, 0x00000002, 0x000000c4, 0x0000000b, 0x0004002b, 0x00000002, 0x000000c6, + 0x0000000c, 0x00060034, 0x00000002, 0x000000c7, 0x000000c5, 0x0000002a, 0x0000003e, 0x00050036, 0x00000003, 0x00000009, + 0x00000000, 0x00000004, 0x00030037, 0x00000002, 0x00000005, 0x00030037, 0x00000002, 0x00000006, 0x00030037, 0x00000002, + 0x00000007, 0x00030037, 0x00000002, 0x00000008, 0x000200f8, 0x0000000a, 0x00060041, 0x0000001d, 0x0000001e, 0x0000001b, + 0x0000001c, 0x0000001c, 0x0004003d, 0x00000002, 0x0000001f, 0x0000001e, 0x000500c4, 0x00000002, 0x00000021, 0x0000001f, + 0x00000020, 0x000500c5, 0x00000002, 0x00000029, 0x00000027, 0x00000021, 0x000500c5, 0x00000002, 0x0000002b, 0x00000029, + 0x0000002a, 0x00070041, 0x0000001d, 0x0000002c, 0x00000026, 0x0000001c, 0x00000007, 0x0000001c, 0x0003003e, 0x0000002c, + 0x0000002b, 0x00070041, 0x0000001d, 0x0000002e, 0x00000026, 0x0000001c, 0x00000007, 0x0000002d, 0x0003003e, 0x0000002e, + 0x00000008, 0x00070041, 0x0000001d, 0x00000030, 0x00000026, 0x0000001c, 0x00000007, 0x0000002f, 0x0003003e, 0x00000030, + 0x00000005, 0x00070041, 0x0000001d, 0x00000032, 0x00000026, 0x0000001c, 0x00000007, 0x00000031, 0x0003003e, 0x00000032, + 0x00000006, 0x000100fd, 0x00010038, 0x00050036, 0x00000003, 0x00000014, 0x00000000, 0x0000000c, 0x00030037, 0x00000002, + 0x0000000d, 0x00030037, 0x00000002, 0x0000000e, 0x00030037, 0x0000000b, 0x0000000f, 0x00030037, 0x0000000b, 0x00000010, + 0x00030037, 0x00000002, 0x00000011, 0x00030037, 0x00000002, 0x00000012, 0x00030037, 0x00000002, 0x00000013, 0x000200f8, + 0x00000015, 0x0004003b, 0x00000016, 0x000000bc, 0x00000007, 0x00050084, 0x0000000b, 0x00000033, 0x0000000f, 0x00000010, + 0x0004007c, 0x00000002, 0x00000034, 0x00000033, 0x00050089, 0x00000002, 0x00000035, 0x00000034, 0x00000011, 0x000500ab, + 0x00000037, 0x00000038, 0x00000035, 0x00000036, 0x000300f7, 0x0000003a, 0x00000000, 0x000400fa, 0x00000038, 0x00000039, + 0x00000046, 0x000200f8, 0x00000039, 0x000500c4, 0x00000002, 0x00000041, 0x00000013, 0x00000040, 0x000500c5, 0x00000002, + 0x00000042, 0x0000003f, 0x00000041, 0x0004007c, 0x00000002, 0x00000043, 0x0000000f, 0x0004007c, 0x00000002, 0x00000044, + 0x00000010, 0x00080050, 0x0000003b, 0x00000045, 0x0000000d, 0x00000042, 0x00000043, 0x00000044, 0x00000011, 0x0003003e, + 0x0000003d, 0x00000045, 0x000200f9, 0x0000003a, 0x000200f8, 0x00000046, 0x00060041, 0x0000001d, 0x0000004c, 0x0000004a, + 0x0000004b, 0x00000010, 0x0004003d, 0x00000002, 0x0000004d, 0x0000004c, 0x000500c7, 0x00000002, 0x0000004e, 0x0000004d, + 0x0000000e, 0x000500ab, 0x00000037, 0x0000004f, 0x0000004e, 0x0000000e, 0x000300f7, 0x00000051, 0x00000000, 0x000400fa, + 0x0000004f, 0x00000050, 0x00000051, 0x000200f8, 0x00000050, 0x000500c4, 0x00000002, 0x00000053, 0x00000012, 0x00000040, + 0x000500c5, 0x00000002, 0x00000054, 0x00000052, 0x00000053, 0x0004007c, 0x00000002, 0x00000055, 0x00000010, 0x00060041, + 0x0000001d, 0x00000056, 0x0000004a, 0x0000004b, 0x00000010, 0x0004003d, 0x00000002, 0x00000057, 0x00000056, 0x00080050, + 0x0000003b, 0x00000058, 0x0000000d, 0x00000054, 0x00000055, 0x0000000e, 0x00000057, 0x0003003e, 0x0000003d, 0x00000058, + 0x000200f9, 0x00000051, 0x000200f8, 0x00000051, 0x000200f9, 0x0000003a, 0x000200f8, 0x0000003a, 0x000500c7, 0x00000002, + 0x0000005a, 0x0000000e, 0x00000059, 0x000500ab, 0x00000037, 0x0000005b, 0x0000005a, 0x00000036, 0x000300f7, 0x0000005d, + 0x00000000, 0x000400fa, 0x0000005b, 0x0000005c, 0x0000008a, 0x000200f8, 0x0000005c, 0x00050084, 0x0000000b, 0x0000005f, + 0x0000000f, 0x00000010, 0x0004007c, 0x00000002, 0x00000060, 0x0000005f, 0x00050041, 0x0000001d, 0x00000062, 0x0000004a, + 0x00000031, 0x0004003d, 0x00000002, 0x00000063, 0x00000062, 0x000500ae, 0x00000037, 0x00000064, 0x00000060, 0x00000063, + 0x000300f7, 0x00000066, 0x00000000, 0x000400fa, 0x00000064, 0x00000065, 0x0000006e, 0x000200f8, 0x00000065, 0x00050041, + 0x0000001d, 0x0000006b, 0x0000004a, 0x00000031, 0x0004003d, 0x00000002, 0x0000006c, 0x0000006b, 0x00080050, 0x0000003b, + 0x0000006d, 0x0000000d, 0x00000069, 0x00000060, 0x0000006c, 0x00000036, 0x0003003e, 0x0000003d, 0x0000006d, 0x000200f9, + 0x00000066, 0x000200f8, 0x0000006e, 0x00050041, 0x0000001d, 0x00000071, 0x0000004a, 0x00000070, 0x0004003d, 0x00000002, + 0x00000072, 0x00000071, 0x000500ae, 0x00000037, 0x00000073, 0x00000060, 0x00000072, 0x000300f7, 0x00000075, 0x00000000, + 0x000400fa, 0x00000073, 0x00000074, 0x00000075, 0x000200f8, 0x00000074, 0x00050041, 0x0000001d, 0x00000077, 0x0000004a, + 0x00000070, 0x0004003d, 0x00000002, 0x00000078, 0x00000077, 0x00050041, 0x0000001d, 0x0000007a, 0x0000004a, 0x00000079, + 0x0004003d, 0x00000002, 0x0000007b, 0x0000007a, 0x00050080, 0x00000002, 0x0000007c, 0x00000078, 0x0000007b, 0x000500b0, + 0x00000037, 0x0000007d, 0x00000060, 0x0000007c, 0x000200f9, 0x00000075, 0x000200f8, 0x00000075, 0x000700f5, 0x00000037, + 0x0000007e, 0x00000073, 0x0000006e, 0x0000007d, 0x00000074, 0x000300f7, 0x00000080, 0x00000000, 0x000400fa, 0x0000007e, + 0x0000007f, 0x00000080, 0x000200f8, 0x0000007f, 0x00050041, 0x0000001d, 0x00000085, 0x0000004a, 0x00000070, 0x0004003d, + 0x00000002, 0x00000086, 0x00000085, 0x00050041, 0x0000001d, 0x00000087, 0x0000004a, 0x00000079, 0x0004003d, 0x00000002, + 0x00000088, 0x00000087, 0x00080050, 0x0000003b, 0x00000089, 0x0000000d, 0x00000083, 0x00000060, 0x00000086, 0x00000088, + 0x0003003e, 0x0000003d, 0x00000089, 0x000200f9, 0x00000080, 0x000200f8, 0x00000080, 0x000200f9, 0x00000066, 0x000200f8, + 0x00000066, 0x000200f9, 0x0000005d, 0x000200f8, 0x0000008a, 0x00050084, 0x0000000b, 0x0000008c, 0x0000000f, 0x00000010, + 0x0004007c, 0x00000002, 0x0000008d, 0x0000008c, 0x00050041, 0x0000001d, 0x0000008f, 0x0000004a, 0x0000001c, 0x0004003d, + 0x00000002, 0x00000090, 0x0000008f, 0x000500ae, 0x00000037, 0x00000091, 0x0000008d, 0x00000090, 0x000300f7, 0x00000093, + 0x00000000, 0x000400fa, 0x00000091, 0x00000092, 0x0000009b, 0x000200f8, 0x00000092, 0x00050041, 0x0000001d, 0x00000098, + 0x0000004a, 0x0000001c, 0x0004003d, 0x00000002, 0x00000099, 0x00000098, 0x00080050, 0x0000003b, 0x0000009a, 0x0000000d, + 0x00000096, 0x0000008d, 0x00000099, 0x00000036, 0x0003003e, 0x0000003d, 0x0000009a, 0x000200f9, 0x00000093, 0x000200f8, + 0x0000009b, 0x00050041, 0x0000001d, 0x0000009d, 0x0000004a, 0x0000002d, 0x0004003d, 0x00000002, 0x0000009e, 0x0000009d, + 0x000500ae, 0x00000037, 0x0000009f, 0x0000008d, 0x0000009e, 0x000300f7, 0x000000a1, 0x00000000, 0x000400fa, 0x0000009f, + 0x000000a0, 0x000000a1, 0x000200f8, 0x000000a0, 0x00050041, 0x0000001d, 0x000000a3, 0x0000004a, 0x0000002d, 0x0004003d, + 0x00000002, 0x000000a4, 0x000000a3, 0x00050041, 0x0000001d, 0x000000a5, 0x0000004a, 0x0000002f, 0x0004003d, 0x00000002, + 0x000000a6, 0x000000a5, 0x00050080, 0x00000002, 0x000000a7, 0x000000a4, 0x000000a6, 0x000500b0, 0x00000037, 0x000000a8, + 0x0000008d, 0x000000a7, 0x000200f9, 0x000000a1, 0x000200f8, 0x000000a1, 0x000700f5, 0x00000037, 0x000000a9, 0x0000009f, + 0x0000009b, 0x000000a8, 0x000000a0, 0x000300f7, 0x000000ab, 0x00000000, 0x000400fa, 0x000000a9, 0x000000aa, 0x000000ab, + 0x000200f8, 0x000000aa, 0x00050041, 0x0000001d, 0x000000b0, 0x0000004a, 0x0000002d, 0x0004003d, 0x00000002, 0x000000b1, + 0x000000b0, 0x00050041, 0x0000001d, 0x000000b2, 0x0000004a, 0x0000002f, 0x0004003d, 0x00000002, 0x000000b3, 0x000000b2, + 0x00080050, 0x0000003b, 0x000000b4, 0x0000000d, 0x000000ae, 0x0000008d, 0x000000b1, 0x000000b3, 0x0003003e, 0x0000003d, + 0x000000b4, 0x000200f9, 0x000000ab, 0x000200f8, 0x000000ab, 0x000200f9, 0x00000093, 0x000200f8, 0x00000093, 0x000200f9, + 0x0000005d, 0x000200f8, 0x0000005d, 0x00060041, 0x0000001d, 0x000000b5, 0x0000004a, 0x0000004b, 0x00000010, 0x0004003d, + 0x00000002, 0x000000b6, 0x000000b5, 0x000500c7, 0x00000002, 0x000000b8, 0x000000b6, 0x000000b7, 0x000500ab, 0x00000037, + 0x000000b9, 0x000000b8, 0x00000036, 0x000300f7, 0x000000bb, 0x00000000, 0x000400fa, 0x000000b9, 0x000000ba, 0x000000bb, + 0x000200f8, 0x000000ba, 0x0003003e, 0x000000bc, 0x00000036, 0x00060041, 0x0000001d, 0x000000bd, 0x0000004a, 0x0000004b, + 0x00000010, 0x0004003d, 0x00000002, 0x000000be, 0x000000bd, 0x000500c7, 0x00000002, 0x000000c0, 0x000000be, 0x000000bf, + 0x000500ab, 0x00000037, 0x000000c1, 0x000000c0, 0x00000036, 0x000300f7, 0x000000c3, 0x00000000, 0x000400fa, 0x000000c1, + 0x000000c2, 0x000000c5, 0x000200f8, 0x000000c2, 0x0003003e, 0x000000bc, 0x000000c4, 0x000200f9, 0x000000c3, 0x000200f8, + 0x000000c5, 0x0003003e, 0x000000bc, 0x000000c6, 0x000200f9, 0x000000c3, 0x000200f8, 0x000000c3, 0x0004003d, 0x00000002, + 0x000000c8, 0x000000bc, 0x000500c4, 0x00000002, 0x000000c9, 0x000000c8, 0x00000040, 0x000500c5, 0x00000002, 0x000000ca, + 0x000000c7, 0x000000c9, 0x0004007c, 0x00000002, 0x000000cb, 0x00000010, 0x00080050, 0x0000003b, 0x000000cc, 0x0000000d, + 0x000000ca, 0x000000cb, 0x00000036, 0x00000036, 0x0003003e, 0x0000003d, 0x000000cc, 0x000200f9, 0x000000bb, 0x000200f8, + 0x000000bb, 0x000100fd, 0x00010038}; +[[maybe_unused]] const uint32_t instrumentation_descriptor_heap_comp_function_0_offset = 747; +[[maybe_unused]] const uint32_t instrumentation_descriptor_heap_comp_function_1_offset = 833; + [[maybe_unused]] const uint32_t instrumentation_descriptor_indexing_oob_comp_size = 1472; [[maybe_unused]] const uint32_t instrumentation_descriptor_indexing_oob_comp[1472] = { 0x07230203, 0x00010300, 0x0008000b, 0x000000ec, 0x00000000, 0x00020011, 0x00000001, 0x00020011, 0x00000005, 0x00020011, @@ -891,7 +1043,7 @@ [[maybe_unused]] const uint32_t instrumentation_sanitizer_comp_size = 959; [[maybe_unused]] const uint32_t instrumentation_sanitizer_comp[959] = { - 0x07230203, 0x00010300, 0x0008000b, 0x000000d2, 0x00000000, 0x00020011, 0x00000001, 0x00020011, 0x00000005, 0x0006000b, + 0x07230203, 0x00010300, 0x0008000b, 0x000000db, 0x00000000, 0x00020011, 0x00000001, 0x00020011, 0x00000005, 0x0006000b, 0x00000001, 0x4c534c47, 0x6474732e, 0x3035342e, 0x00000000, 0x0003000e, 0x00000000, 0x00000001, 0x00030003, 0x00000002, 0x000001c2, 0x00070004, 0x415f4c47, 0x675f4252, 0x735f7570, 0x65646168, 0x6e695f72, 0x00343674, 0x00070004, 0x455f4c47, 0x625f5458, 0x65666675, 0x65725f72, 0x65726566, 0x0065636e, 0x00080004, 0x455f4c47, 0x625f5458, 0x65666675, 0x65725f72, @@ -949,7 +1101,7 @@ 0x00000035, 0x00000036, 0x0004002b, 0x00000003, 0x0000005b, 0x00140000, 0x00060034, 0x00000003, 0x0000005c, 0x000000c5, 0x0000005a, 0x0000005b, 0x0004002b, 0x00000003, 0x0000005d, 0x00000001, 0x00060034, 0x00000003, 0x00000081, 0x000000c5, 0x00000035, 0x00000036, 0x0004002b, 0x00000003, 0x00000082, 0x00180000, 0x00060034, 0x00000003, 0x00000083, 0x000000c5, - 0x00000081, 0x00000082, 0x0004002b, 0x00000003, 0x000000d1, 0x00000002, 0x00050036, 0x00000002, 0x00000009, 0x00000000, + 0x00000081, 0x00000082, 0x0004002b, 0x00000003, 0x000000da, 0x00000002, 0x00050036, 0x00000002, 0x00000009, 0x00000000, 0x00000004, 0x00030037, 0x00000002, 0x00000005, 0x00030037, 0x00000003, 0x00000006, 0x00030037, 0x00000003, 0x00000007, 0x00030037, 0x00000003, 0x00000008, 0x000200f8, 0x0000000a, 0x000300f7, 0x00000031, 0x00000000, 0x000400fa, 0x00000005, 0x00000030, 0x00000031, 0x000200f8, 0x00000030, 0x00080050, 0x00000032, 0x0000003b, 0x00000006, 0x00000039, 0x00000007, @@ -970,7 +1122,7 @@ 0x00000021, 0x00030037, 0x00000003, 0x00000022, 0x00030037, 0x00000003, 0x00000023, 0x000200f8, 0x00000025, 0x000500a6, 0x00000002, 0x00000057, 0x0000001f, 0x00000020, 0x000300f7, 0x00000059, 0x00000000, 0x000400fa, 0x00000057, 0x00000058, 0x00000059, 0x000200f8, 0x00000058, 0x000600a9, 0x00000003, 0x0000005e, 0x0000001f, 0x0000005d, 0x0000003a, 0x000600a9, - 0x00000003, 0x00000062, 0x00000020, 0x000000d1, 0x0000003a, 0x000500c5, 0x00000003, 0x00000063, 0x0000005e, 0x00000062, + 0x00000003, 0x00000062, 0x00000020, 0x000000da, 0x0000003a, 0x000500c5, 0x00000003, 0x00000063, 0x0000005e, 0x00000062, 0x00080050, 0x00000032, 0x00000064, 0x00000021, 0x0000005c, 0x00000063, 0x00000022, 0x00000023, 0x0003003e, 0x00000034, 0x00000064, 0x000200fe, 0x0000003c, 0x000200f8, 0x00000059, 0x000200fe, 0x0000003e, 0x00010038, 0x00050036, 0x00000002, 0x0000002e, 0x00000000, 0x00000026, 0x00030037, 0x00000003, 0x00000027, 0x00030037, 0x00000003, 0x00000028, 0x00030037, @@ -984,7 +1136,7 @@ 0x00000077, 0x000200f8, 0x00000077, 0x000700f5, 0x00000002, 0x0000007b, 0x00000074, 0x0000002f, 0x0000007a, 0x00000076, 0x000500a6, 0x00000002, 0x0000007e, 0x00000071, 0x0000007b, 0x000300f7, 0x00000080, 0x00000000, 0x000400fa, 0x0000007e, 0x0000007f, 0x00000080, 0x000200f8, 0x0000007f, 0x000600a9, 0x00000003, 0x00000085, 0x00000071, 0x0000005d, 0x0000003a, - 0x000600a9, 0x00000003, 0x00000088, 0x0000007b, 0x000000d1, 0x0000003a, 0x000500c5, 0x00000003, 0x00000089, 0x00000085, + 0x000600a9, 0x00000003, 0x00000088, 0x0000007b, 0x000000da, 0x0000003a, 0x000500c5, 0x00000003, 0x00000089, 0x00000085, 0x00000088, 0x00080050, 0x00000032, 0x0000008a, 0x0000002c, 0x00000083, 0x0000002d, 0x00000029, 0x00000089, 0x0003003e, 0x00000034, 0x0000008a, 0x000200fe, 0x0000003c, 0x000200f8, 0x00000080, 0x000200fe, 0x0000003e, 0x00010038}; [[maybe_unused]] const uint32_t instrumentation_sanitizer_comp_function_0_offset = 586; diff --git a/layers/vulkan/generated/gpuav_offline_spirv.h b/layers/vulkan/generated/gpuav_offline_spirv.h index d5499540cee..e0da4f96cd9 100644 --- a/layers/vulkan/generated/gpuav_offline_spirv.h +++ b/layers/vulkan/generated/gpuav_offline_spirv.h @@ -44,6 +44,12 @@ extern const uint32_t instrumentation_descriptor_class_texel_buffer_comp[]; // These offset match the function in the order they are declared in the GLSL source extern const uint32_t instrumentation_descriptor_class_texel_buffer_comp_function_0_offset; +extern const uint32_t instrumentation_descriptor_heap_comp_size; +extern const uint32_t instrumentation_descriptor_heap_comp[]; +// These offset match the function in the order they are declared in the GLSL source +extern const uint32_t instrumentation_descriptor_heap_comp_function_0_offset; +extern const uint32_t instrumentation_descriptor_heap_comp_function_1_offset; + extern const uint32_t instrumentation_descriptor_indexing_oob_comp_size; extern const uint32_t instrumentation_descriptor_indexing_oob_comp[]; // These offset match the function in the order they are declared in the GLSL source diff --git a/tests/unit/gpu_av_descriptor_heap.cpp b/tests/unit/gpu_av_descriptor_heap.cpp index 25c9853c5fe..1fe0fee07e1 100644 --- a/tests/unit/gpu_av_descriptor_heap.cpp +++ b/tests/unit/gpu_av_descriptor_heap.cpp @@ -924,4 +924,126 @@ TEST_F(NegativeGpuAVDescriptorHeap, ShaderObjects) { m_default_queue->SubmitAndWait(m_command_buffer); m_errorMonitor->VerifyFound(); -} \ No newline at end of file +} + +TEST_F(NegativeGpuAVDescriptorHeap, PushAddressUniformBufferUsage) { + AddRequiredFeature(vkt::Feature::bufferDeviceAddress); + AddRequiredFeature(vkt::Feature::vertexPipelineStoresAndAtomics); + RETURN_IF_SKIP(InitGpuAVDescriptorHeap()); + InitRenderTarget(); + + vkt::Buffer read_buffer(*m_device, sizeof(uint32_t) * 4, VK_BUFFER_USAGE_2_STORAGE_BUFFER_BIT_KHR, vkt::device_address); + uint32_t* read_data = static_cast(read_buffer.Memory().Map()); + for (uint32_t i = 0; i < 4; ++i) { + read_data[i] = i + 1; + } + vkt::Buffer write_buffer(*m_device, sizeof(uint32_t) * 4, VK_BUFFER_USAGE_2_STORAGE_BUFFER_BIT_KHR, vkt::device_address); + + const uint32_t read_offset = 48u; + const VkDeviceSize write_offset = + Align(read_offset + heap_props.bufferDescriptorAlignment * 7u, heap_props.bufferDescriptorAlignment); + const VkDeviceSize resource_stride = heap_props.bufferDescriptorSize; + const VkDeviceSize descriptor_size = AlignResource(write_offset + resource_stride); + const VkDeviceSize heap_size = descriptor_size + heap_props.minResourceHeapReservedRange; + + vkt::Buffer heap(*m_device, heap_size, VK_BUFFER_USAGE_DESCRIPTOR_HEAP_BIT_EXT, vkt::device_address); + uint8_t* heap_data = static_cast(heap.Memory().Map()); + + VkHostAddressRangeEXT descriptor_host; + descriptor_host.address = heap_data + write_offset; + descriptor_host.size = resource_stride; + + VkDeviceAddressRangeEXT device_range; + device_range.address = write_buffer.Address(); + device_range.size = write_buffer.CreateInfo().size; + + VkResourceDescriptorInfoEXT descriptor_info; + 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); + + VkDescriptorSetAndBindingMappingEXT mappings[2]; + mappings[0] = vku::InitStructHelper(); + mappings[0].descriptorSet = 2u; + mappings[0].firstBinding = 3u; + mappings[0].bindingCount = 1u; + mappings[0].resourceMask = VK_SPIRV_RESOURCE_TYPE_UNIFORM_BUFFER_BIT_EXT; + mappings[0].source = VK_DESCRIPTOR_MAPPING_SOURCE_PUSH_ADDRESS_EXT; + mappings[0].sourceData.pushAddressOffset = static_cast(read_offset); + mappings[1] = vku::InitStructHelper(); + mappings[1].descriptorSet = 1u; + mappings[1].firstBinding = 0u; + mappings[1].bindingCount = 1u; + mappings[1].resourceMask = VK_SPIRV_RESOURCE_TYPE_READ_WRITE_STORAGE_BUFFER_BIT_EXT; + mappings[1].source = VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_CONSTANT_OFFSET_EXT; + mappings[1].sourceData.constantOffset.heapOffset = static_cast(write_offset); + mappings[1].sourceData.constantOffset.heapArrayStride = 0u; + + VkShaderDescriptorSetAndBindingMappingInfoEXT mapping_info = vku::InitStructHelper(); + mapping_info.mappingCount = 2u; + mapping_info.pMappings = mappings; + + char const* vert_source = R"glsl( + #version 450 + layout(set = 2, binding = 3) uniform ReadData { + uvec4 read_data; + }; + layout(set = 1, binding = 0) buffer WriteData { + uvec4 write_data; + }; + void main() { + if (gl_VertexIndex == 0) { + write_data[0] = read_data[3]; + } + gl_Position = vec4(1.0f); + gl_PointSize = 1.0f; + } + )glsl"; + + VkShaderObj vert_module = VkShaderObj(*m_device, vert_source, VK_SHADER_STAGE_VERTEX_BIT); + VkShaderObj frag_module = VkShaderObj(*m_device, kFragmentMinimalGlsl, VK_SHADER_STAGE_FRAGMENT_BIT); + + VkPipelineCreateFlags2CreateInfoKHR pipeline_create_flags_2_create_info = vku::InitStructHelper(); + pipeline_create_flags_2_create_info.flags = VK_PIPELINE_CREATE_2_DESCRIPTOR_HEAP_BIT_EXT; + + VkPipelineShaderStageCreateInfo stages[2]; + stages[0] = vert_module.GetStageCreateInfo(); + stages[0].pNext = &mapping_info; + stages[1] = frag_module.GetStageCreateInfo(); + + CreatePipelineHelper descriptor_heap_pipe(*this, &pipeline_create_flags_2_create_info); + descriptor_heap_pipe.gp_ci_.layout = VK_NULL_HANDLE; + descriptor_heap_pipe.gp_ci_.stageCount = 2u; + descriptor_heap_pipe.gp_ci_.pStages = stages; + descriptor_heap_pipe.CreateGraphicsPipeline(false); + + VkDeviceAddress read_address = read_buffer.Address(); + + VkPushDataInfoEXT push_data = vku::InitStructHelper(); + push_data.offset = read_offset; + push_data.data.address = &read_address; + push_data.data.size = sizeof(read_address); + + m_command_buffer.Begin(); + m_command_buffer.BeginRenderPass(m_renderPassBeginInfo); + + vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, descriptor_heap_pipe); + + VkBindHeapInfoEXT bind_resource_info = vku::InitStructHelper(); + bind_resource_info.heapRange.address = heap.Address(); + bind_resource_info.heapRange.size = heap_size; + bind_resource_info.reservedRangeOffset = descriptor_size; + bind_resource_info.reservedRangeSize = heap_props.minResourceHeapReservedRange; + vk::CmdBindResourceHeapEXT(m_command_buffer, &bind_resource_info); + + vk::CmdPushDataEXT(m_command_buffer, &push_data); + vk::CmdDraw(m_command_buffer, 3u, 1u, 0u, 0u); + + m_command_buffer.EndRenderPass(); + m_command_buffer.End(); + m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-None-11438"); + m_default_queue->SubmitAndWait(m_command_buffer); + m_errorMonitor->VerifyFound(); +}