| /*************************************************************************** |
| * |
| * Copyright (c) 2015-2026 The Khronos Group Inc. |
| * Copyright (c) 2015-2026 Valve Corporation |
| * Copyright (c) 2015-2026 LunarG, Inc. |
| * Copyright (c) 2015-2026 Google Inc. |
| * Copyright (c) 2023-2024 RasterGrid Kft. |
| * Copyright (C) 2026 Qualcomm Technologies, Inc. |
| * Modifications Copyright (C) 2025-2026 Advanced Micro Devices, Inc. All rights reserved. |
| * |
| * 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 <atomic> |
| #include <vector> |
| |
| #include <vulkan/vulkan.h> |
| #include <vulkan/vk_enum_string_helper.h> |
| #include <vulkan/utility/vk_safe_struct.hpp> |
| |
| #include "error_message/logging.h" |
| #include "containers/custom_containers.h" |
| #include "layer_options.h" |
| #include "gpuav/core/gpuav_settings.h" |
| #include "sync/sync_settings.h" |
| #include "gpu_dump/gpu_dump_settings.h" |
| #include "generated/device_features.h" |
| #include "generated/vk_api_version.h" |
| #include "generated/vk_extension_helper.h" |
| #include "generated/vk_layer_dispatch_table.h" |
| #include "layer_object_id.h" |
| #include "state_tracker/special_supported.h" |
| |
| // To avoid re-hashing unique ids on each use, we precompute the hash and store the |
| // hash's LSBs in the high 24 bits. |
| struct HashedUint64 { |
| static const int HASHED_UINT64_SHIFT = 40; |
| size_t operator()(const uint64_t& t) const { return t >> HASHED_UINT64_SHIFT; } |
| |
| static uint64_t hash(uint64_t id) { |
| uint64_t h = (uint64_t)vvl::hash<uint64_t>()(id); |
| id |= h << HASHED_UINT64_SHIFT; |
| return id; |
| } |
| }; |
| |
| namespace vvl { |
| class BaseInstance; |
| class BaseDevice; |
| class DispatchInstance; |
| class DispatchDevice; |
| |
| // Device extension properties -- storing properties gathered from VkPhysicalDeviceProperties2::pNext chain |
| // TODO: this could be defined and initialized via generated code |
| struct DeviceExtensionProperties { |
| VkPhysicalDevicePartitionedAccelerationStructurePropertiesNV partitioned_acceleration_structure_props; |
| VkPhysicalDeviceClusterAccelerationStructurePropertiesNV cluster_acceleration_props; |
| VkPhysicalDeviceShadingRateImagePropertiesNV shading_rate_image_props; |
| VkPhysicalDeviceMeshShaderPropertiesNV mesh_shader_props_nv; |
| VkPhysicalDeviceMeshShaderPropertiesEXT mesh_shader_props_ext; |
| VkPhysicalDeviceCooperativeMatrixPropertiesNV cooperative_matrix_props; |
| VkPhysicalDeviceCooperativeMatrixPropertiesKHR cooperative_matrix_props_khr; |
| VkPhysicalDeviceCooperativeMatrix2PropertiesNV cooperative_matrix_props2_nv; |
| VkPhysicalDeviceTransformFeedbackPropertiesEXT transform_feedback_props; |
| VkPhysicalDeviceRayTracingPropertiesNV ray_tracing_props_nv; |
| VkPhysicalDeviceRayTracingPipelinePropertiesKHR ray_tracing_props_khr; |
| VkPhysicalDeviceAccelerationStructurePropertiesKHR acc_structure_props; |
| VkPhysicalDeviceFragmentDensityMapPropertiesEXT fragment_density_map_props; |
| VkPhysicalDeviceFragmentDensityMap2PropertiesEXT fragment_density_map2_props; |
| VkPhysicalDeviceFragmentDensityMapOffsetPropertiesEXT fragment_density_map_offset_props; |
| VkPhysicalDeviceFragmentDensityMapLayeredPropertiesVALVE fragment_density_map_layered_props; |
| VkPhysicalDevicePerformanceQueryPropertiesKHR performance_query_props; |
| VkPhysicalDeviceSampleLocationsPropertiesEXT sample_locations_props; |
| VkPhysicalDeviceCustomBorderColorPropertiesEXT custom_border_color_props; |
| VkPhysicalDeviceMultiviewProperties multiview_props; |
| VkPhysicalDevicePortabilitySubsetPropertiesKHR portability_props; |
| VkPhysicalDeviceFragmentShadingRatePropertiesKHR fragment_shading_rate_props; |
| VkPhysicalDeviceProvokingVertexPropertiesEXT provoking_vertex_props; |
| VkPhysicalDeviceMultiDrawPropertiesEXT multi_draw_props; |
| VkPhysicalDeviceDiscardRectanglePropertiesEXT discard_rectangle_props; |
| VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT blend_operation_advanced_props; |
| VkPhysicalDeviceConservativeRasterizationPropertiesEXT conservative_rasterization_props; |
| VkPhysicalDeviceSubgroupProperties subgroup_props; |
| VkPhysicalDeviceExtendedDynamicState3PropertiesEXT extended_dynamic_state3_props; |
| VkPhysicalDeviceImageProcessingPropertiesQCOM image_processing_props; |
| VkPhysicalDeviceImageAlignmentControlPropertiesMESA image_alignment_control_props; |
| VkPhysicalDeviceMaintenance7PropertiesKHR maintenance7_props; |
| VkPhysicalDeviceNestedCommandBufferPropertiesEXT nested_command_buffer_props; |
| VkPhysicalDeviceDescriptorBufferPropertiesEXT descriptor_buffer_props; |
| VkPhysicalDeviceDescriptorBufferDensityMapPropertiesEXT descriptor_buffer_density_props; |
| VkPhysicalDeviceDeviceGeneratedCommandsPropertiesEXT device_generated_commands_props; |
| VkPhysicalDevicePipelineBinaryPropertiesKHR pipeline_binary_props; |
| VkPhysicalDeviceMapMemoryPlacedPropertiesEXT map_memory_placed_props; |
| VkPhysicalDeviceComputeShaderDerivativesPropertiesKHR compute_shader_derivatives_props; |
| VkPhysicalDeviceCooperativeVectorPropertiesNV cooperative_vector_props_nv; |
| VkPhysicalDeviceRenderPassStripedPropertiesARM renderpass_striped_props; |
| VkPhysicalDeviceExternalMemoryHostPropertiesEXT external_memory_host_props; |
| VkPhysicalDeviceMaintenance9PropertiesKHR maintenance9_props; |
| VkPhysicalDeviceMaintenance10PropertiesKHR maintenance10_props; |
| VkPhysicalDeviceTensorPropertiesARM tensor_properties; |
| VkPhysicalDeviceCopyMemoryIndirectPropertiesKHR copy_memory_indirect_props; |
| VkPhysicalDeviceTileMemoryHeapPropertiesQCOM tile_memory_heap_props; |
| VkPhysicalDeviceDescriptorHeapPropertiesEXT descriptor_heap_props; |
| VkPhysicalDeviceDescriptorHeapTensorPropertiesARM descriptor_heap_tensor_props; |
| #if defined(VK_USE_PLATFORM_ANDROID_KHR) |
| VkPhysicalDeviceExternalFormatResolvePropertiesANDROID android_format_resolve_props; |
| #endif |
| VkPhysicalDeviceMemoryDecompressionPropertiesEXT memory_decompression_props; |
| VkPhysicalDevicePerformanceCountersByRegionPropertiesARM renderpass_counter_by_region_props; |
| VkPhysicalDeviceRayTracingInvocationReorderPropertiesEXT ray_tracing_invocation_reorder_props; |
| VkPhysicalDeviceShaderLongVectorPropertiesEXT shader_long_vector_props; |
| VkPhysicalDeviceTileShadingPropertiesQCOM tile_shading_props; |
| }; |
| |
| // This object holds all static state for the device (device properties, enabled extensions/features, etc.) |
| // It is initialized atomically in the constructor based on the provided physical device and device create info |
| // and then used by all downstream users (state tracker, stateless SPIR-V validator, etc.). |
| class StatelessDeviceData { |
| public: |
| StatelessDeviceData(DispatchInstance* instance, VkPhysicalDevice physical_device, const VkDeviceCreateInfo* pCreateInfo); |
| |
| APIVersion api_version; |
| |
| DeviceExtensions extensions{}; |
| DeviceFeatures enabled_features{}; |
| |
| VkPhysicalDeviceMemoryProperties phys_dev_mem_props{}; |
| VkPhysicalDeviceProperties phys_dev_props{}; |
| VkPhysicalDeviceVulkan11Properties phys_dev_props_core11{}; |
| VkPhysicalDeviceVulkan12Properties phys_dev_props_core12{}; |
| VkPhysicalDeviceVulkan13Properties phys_dev_props_core13{}; |
| VkPhysicalDeviceVulkan14Properties phys_dev_props_core14{}; |
| // To store the 2 lists from VkPhysicalDeviceHostImageCopyProperties |
| std::vector<VkImageLayout> host_image_copy_props_copy_src_layouts{}; |
| std::vector<VkImageLayout> host_image_copy_props_copy_dst_layouts{}; |
| DeviceExtensionProperties phys_dev_ext_props = {}; |
| |
| SpecialSupported special_supported; |
| }; |
| |
| class DispatchInstance; |
| void SetDispatchInstance(VkInstance instance, std::unique_ptr<DispatchInstance>&&); |
| DispatchInstance* GetDispatchInstance(VkInstance); |
| DispatchInstance* GetDispatchInstance(VkPhysicalDevice); |
| void FreeDispatchInstance(void* key); |
| |
| class DispatchDevice; |
| void SetDispatchDevice(VkDevice dev, std::unique_ptr<DispatchDevice>&&); |
| DispatchDevice* GetDispatchDevice(VkDevice); |
| DispatchDevice* GetDispatchDevice(VkQueue); |
| DispatchDevice* GetDispatchDevice(VkCommandBuffer); |
| DispatchDevice* GetDispatchDevice(VkExternalComputeQueueNV); |
| void FreeDispatchDevice(void* key); |
| |
| void FreeAllDispatchObjects(); |
| |
| struct TemplateState { |
| VkDescriptorUpdateTemplate desc_update_template; |
| vku::safe_VkDescriptorUpdateTemplateCreateInfo create_info; |
| bool destroyed; |
| |
| TemplateState(VkDescriptorUpdateTemplate update_template, vku::safe_VkDescriptorUpdateTemplateCreateInfo* pCreateInfo) |
| : desc_update_template(update_template), create_info(*pCreateInfo), destroyed(false) {} |
| }; |
| |
| struct Settings { |
| GlobalSettings global_settings = {}; |
| GpuAVSettings gpuav_settings = {}; |
| SyncValSettings syncval_settings = {}; |
| GpuDumpSettings gpu_dump_settings = {}; |
| |
| ValidationDisabled disabled = {}; |
| ValidationEnabled enabled = {}; |
| }; |
| |
| class HandleWrapper : public Logger { |
| public: |
| HandleWrapper(DebugReport* dr); |
| ~HandleWrapper(); |
| |
| // Unwrap a handle. |
| template <typename HandleType> |
| HandleType Unwrap(HandleType wrapped_handle) { |
| if (wrapped_handle == (HandleType)VK_NULL_HANDLE) return wrapped_handle; |
| auto iter = unique_id_mapping.find(CastToUint64(wrapped_handle)); |
| if (iter == unique_id_mapping.end()) return (HandleType)0; |
| return (HandleType)iter->second; |
| } |
| |
| // Wrap a newly created handle with a new unique ID, and return the new ID. |
| template <typename HandleType> |
| HandleType WrapNew(HandleType new_created_handle) { |
| if (new_created_handle == (HandleType)VK_NULL_HANDLE) return new_created_handle; |
| auto unique_id = global_unique_id++; |
| unique_id = HashedUint64::hash(unique_id); |
| assert(unique_id != 0); // can't be 0, otherwise unwrap will apply special rule for VK_NULL_HANDLE |
| unique_id_mapping.insert_or_assign(unique_id, CastToUint64(new_created_handle)); |
| return (HandleType)unique_id; |
| } |
| |
| template <typename HandleType> |
| HandleType Find(HandleType wrapped_handle) const { |
| uint64_t id = CastToUint64(wrapped_handle); |
| auto iter = unique_id_mapping.find(id); |
| if (iter != unique_id_mapping.end()) { |
| return CastFromUint64<HandleType>(iter->second); |
| } else { |
| return CastFromUint<HandleType>(0ULL); |
| } |
| } |
| |
| template <typename HandleType> |
| HandleType Erase(HandleType wrapped_handle) { |
| uint64_t id = CastToUint64(wrapped_handle); |
| auto iter = unique_id_mapping.pop(id); |
| if (iter != unique_id_mapping.end()) { |
| return CastFromUint64<HandleType>(iter->second); |
| } else { |
| return CastFromUint<HandleType>(0ULL); |
| } |
| } |
| |
| void UnwrapPnextChainHandles(const void* pNext); |
| |
| static std::atomic<uint64_t> global_unique_id; |
| static vvl::concurrent_unordered_map<uint64_t, uint64_t, 4, HashedUint64> unique_id_mapping; |
| static bool wrap_handles; |
| }; |
| |
| class DispatchInstance : public HandleWrapper { |
| public: |
| DispatchInstance(const VkInstanceCreateInfo* pCreateInfo); |
| ~DispatchInstance(); |
| |
| void InitValidationObjects(); |
| void FindSupportedExtensions(); |
| |
| // VkDisplayKHR objects are statically created in the driver at VkCreateInstance. |
| // They live with the PhyiscalDevice and apps never created/destroy them. |
| // Apps needs will query for them and the first time we see it we wrap it |
| VkDisplayKHR MaybeWrapDisplay(VkDisplayKHR handle) { |
| // See if this display is already known |
| auto it = display_id_reverse_mapping.find(handle); |
| if (it != display_id_reverse_mapping.end()) return (VkDisplayKHR)it->second; |
| |
| // First time see this VkDisplayKHR, so wrap |
| const uint64_t unique_id = (uint64_t)WrapNew(handle); |
| display_id_reverse_mapping.insert_or_assign(handle, unique_id); |
| return (VkDisplayKHR)unique_id; |
| } |
| BaseInstance* GetValidationObject(LayerObjectTypeId object_type) const; |
| |
| Settings settings; |
| |
| APIVersion api_version; |
| DeviceExtensions extensions{}; |
| |
| mutable std::vector<std::unique_ptr<BaseInstance>> object_dispatch; |
| |
| VkInstance instance = VK_NULL_HANDLE; |
| VkLayerInstanceDispatchTable instance_dispatch_table; |
| // Reverse map display handles |
| vvl::concurrent_unordered_map<VkDisplayKHR, uint64_t, 0> display_id_reverse_mapping; |
| |
| #include "generated/dispatch_object_instance_methods.h" |
| |
| template <bool init = true, typename ExtProp> |
| void GetPhysicalDeviceExtProperties(VkPhysicalDevice gpu, ExtEnabled enabled, ExtProp* ext_prop) { |
| assert(ext_prop); |
| // Extensions that use two calls to get properties don't want to init on the second call |
| if constexpr (init) { |
| *ext_prop = vku::InitStructHelper(); |
| } |
| if (IsExtEnabled(enabled)) { |
| VkPhysicalDeviceProperties2 prop2 = vku::InitStructHelper(ext_prop); |
| if (api_version >= VK_API_VERSION_1_1) { |
| GetPhysicalDeviceProperties2(gpu, &prop2); |
| } else { |
| GetPhysicalDeviceProperties2KHR(gpu, &prop2); |
| } |
| } |
| } |
| |
| void ReportErrorFeatureNotPresent(VkPhysicalDevice gpu, const VkDeviceCreateInfo& create_info); |
| }; |
| |
| class DispatchDevice : public HandleWrapper { |
| public: |
| DispatchDevice(DispatchInstance* instance, VkPhysicalDevice gpu, const VkDeviceCreateInfo* pCreateInfo); |
| ~DispatchDevice(); |
| |
| void InitObjectDispatchVectors(); |
| void InitValidationObjects(); |
| void ReleaseValidationObject(LayerObjectTypeId type_id) const; |
| BaseDevice* GetValidationObject(LayerObjectTypeId object_type) const; |
| |
| bool IsSecondary(VkCommandBuffer cb) const; |
| |
| Settings& settings; |
| DispatchInstance* dispatch_instance; |
| |
| const StatelessDeviceData stateless_device_data; |
| |
| const APIVersion api_version; |
| |
| const DeviceExtensions& extensions; |
| const DeviceFeatures& enabled_features; |
| |
| const VkPhysicalDeviceMemoryProperties& phys_dev_mem_props; |
| const VkPhysicalDeviceProperties& phys_dev_props; |
| const VkPhysicalDeviceVulkan11Properties& phys_dev_props_core11; |
| const VkPhysicalDeviceVulkan12Properties& phys_dev_props_core12; |
| const VkPhysicalDeviceVulkan13Properties& phys_dev_props_core13; |
| const VkPhysicalDeviceVulkan14Properties& phys_dev_props_core14; |
| // To store the 2 lists from VkPhysicalDeviceHostImageCopyProperties |
| const std::vector<VkImageLayout>& host_image_copy_props_copy_src_layouts; |
| const std::vector<VkImageLayout>& host_imape_copy_props_copy_dst_layouts; |
| const DeviceExtensionProperties& phys_dev_ext_props; |
| |
| VkPhysicalDevice physical_device = VK_NULL_HANDLE; |
| VkDevice device = VK_NULL_HANDLE; |
| VkLayerDispatchTable device_dispatch_table; |
| |
| mutable std::vector<std::unique_ptr<BaseDevice>> object_dispatch; |
| mutable std::vector<std::unique_ptr<BaseDevice>> aborted_object_dispatch; |
| mutable std::vector<std::vector<BaseDevice*>> intercept_vectors; |
| // Handle Wrapping Data |
| // Wrapping Descriptor Template Update structures requires access to the template createinfo structs |
| vvl::unordered_map<uint64_t, std::unique_ptr<TemplateState>> desc_template_createinfo_map; |
| struct SubpassesUsageStates { |
| vvl::unordered_set<uint32_t> subpasses_using_color_attachment; |
| vvl::unordered_set<uint32_t> subpasses_using_depthstencil_attachment; |
| }; |
| // Uses unwrapped handles |
| vvl::unordered_map<VkRenderPass, SubpassesUsageStates> renderpasses_states; |
| // Map of wrapped swapchain handles to arrays of wrapped swapchain image IDs |
| // Each swapchain has an immutable list of wrapped swapchain image IDs -- always return these IDs if they exist |
| vvl::unordered_map<VkSwapchainKHR, std::vector<VkImage>> swapchain_wrapped_image_handle_map; |
| // Map of wrapped descriptor pools to set of wrapped descriptor sets allocated from each pool |
| vvl::unordered_map<VkDescriptorPool, vvl::unordered_set<VkDescriptorSet>> pool_descriptor_sets_map; |
| |
| vvl::concurrent_unordered_map<VkDeferredOperationKHR, std::vector<std::function<void()>>, 0> deferred_operation_post_completion; |
| vvl::concurrent_unordered_map<VkDeferredOperationKHR, std::vector<std::function<void(std::pair<uint32_t, VkPipeline*>)>>, 0> |
| deferred_operation_post_check; |
| vvl::concurrent_unordered_map<VkDeferredOperationKHR, std::pair<uint32_t, VkPipeline*>, 0> deferred_operation_pipelines; |
| |
| // State we track in order to populate HandleData for things such as ignored pointers |
| vvl::unordered_map<VkCommandBuffer, VkCommandPool> secondary_cb_map{}; |
| mutable std::shared_mutex secondary_cb_map_mutex; |
| |
| #include "generated/dispatch_object_device_methods.h" |
| }; |
| } // namespace vvl |