| /* Copyright (c) 2018-2026 The Khronos Group Inc. |
| * Copyright (c) 2018-2026 Valve Corporation |
| * Copyright (c) 2018-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 "containers/custom_containers.h" |
| #include "gpuav/descriptor_validation/gpuav_descriptor_set.h" |
| #include "gpuav/resources/gpuav_vulkan_objects.h" |
| #include "gpuav/instrumentation/gpuav_shader_instrumentor.h" |
| |
| #include <memory> |
| |
| struct LastBound; |
| namespace chassis { |
| struct ShaderObject; |
| struct CmdBindDescriptorBuffers; |
| } // namespace chassis |
| |
| namespace vvl { |
| class DeviceMemory; |
| } // namespace vvl |
| |
| namespace gpuav { |
| class CommandBufferSubState; |
| class DescriptorSetSubState; |
| class QueueSubState; |
| } // namespace gpuav |
| |
| namespace gpuav { |
| |
| class Instance : public vvl::InstanceProxy { |
| public: |
| Instance(vvl::DispatchInstance* dispatch) : InstanceProxy(dispatch, LayerObjectTypeGpuAssisted) {} |
| |
| void PreCallRecordCreateDevice(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo* pCreateInfo, |
| const VkAllocationCallbacks* pAllocator, VkDevice* pDevice, const RecordObject& record_obj, |
| vku::safe_VkDeviceCreateInfo* modified_create_info) final; |
| void ReserveBindingSlot(VkPhysicalDevice physicalDevice, VkPhysicalDeviceLimits& limits, const Location& loc); |
| void PostCallRecordGetPhysicalDeviceProperties(VkPhysicalDevice physicalDevice, |
| VkPhysicalDeviceProperties* pPhysicalDeviceProperties, |
| const RecordObject& record_obj) override; |
| void PostCallRecordGetPhysicalDeviceProperties2(VkPhysicalDevice physicalDevice, |
| VkPhysicalDeviceProperties2* pPhysicalDeviceProperties2, |
| const RecordObject& record_obj) final; |
| |
| void InternalWarning(LogObjectList objlist, const Location& loc, const char* const specific_message) const; |
| void AdjustmentWarning(LogObjectList objlist, const Location& loc, const char* const specific_message) const; |
| void AddFeatures(VkPhysicalDevice physical_device, vku::safe_VkDeviceCreateInfo* modified_create_info, const Location& loc); |
| bool timeline_khr_{false}; |
| }; |
| |
| class Validator : public GpuShaderInstrumentor { |
| using Func = vvl::Func; |
| using Struct = vvl::Struct; |
| using Field = vvl::Field; |
| |
| public: |
| Validator(vvl::DispatchDevice* dev, Instance* instance_vo) |
| : GpuShaderInstrumentor(dev, instance_vo, LayerObjectTypeGpuAssisted), |
| global_indices_buffer_(*this), |
| global_resource_descriptor_buffer_(*this), |
| global_resource_descriptor_heap_(*this), |
| gpu_resources_manager_(*this, true) {} |
| |
| // gpuav_setup.cpp |
| // ------------- |
| public: |
| void FinishDeviceSetup(const VkDeviceCreateInfo* pCreateInfo, const Location& loc) final; |
| |
| void InternalVmaError(LogObjectList objlist, VkResult result, const char* const specific_message) const; |
| bool IsAllDeviceLocalMappable() const; |
| |
| private: |
| void InitSettings(const Location& loc); |
| void DestroySubstate(); |
| void BindBufferMemory(VkBuffer buffer, VkDeviceMemory memory, VkDeviceSize offset, const Location& loc); |
| void SetMemoryWithNullDescriptor(const vvl::Buffer& buffer_state, VkDeviceMemory memory, VkDeviceSize offset, |
| const Location& loc); |
| |
| // gpuav_record.cpp |
| // -------------- |
| public: |
| void PreCallRecordDestroyDevice(VkDevice device, const VkAllocationCallbacks* pAllocator, const RecordObject& record_obj) final; |
| void PreCallRecordCreateBuffer(VkDevice device, const VkBufferCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, |
| VkBuffer* pBuffer, const RecordObject& record_obj, chassis::CreateBuffer& chassis_state) final; |
| void PreCallRecordBeginCommandBuffer(VkCommandBuffer commandBuffer, const VkCommandBufferBeginInfo* pBeginInfo, |
| const RecordObject& record_obj) final; |
| |
| void PostCallRecordCreateBuffer(VkDevice device, const VkBufferCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, |
| VkBuffer* pBuffer, const RecordObject& record_obj) final; |
| void PreCallRecordDestroyBuffer(VkDevice device, VkBuffer buffer, const VkAllocationCallbacks* pAllocator, |
| const RecordObject& record_obj) final; |
| void PreCallRecordFreeMemory(VkDevice device, VkDeviceMemory memory, const VkAllocationCallbacks* pAllocator, |
| const RecordObject& record_obj) final; |
| void PostCallRecordBindBufferMemory(VkDevice device, VkBuffer buffer, VkDeviceMemory memory, VkDeviceSize memoryOffset, |
| const RecordObject& record_obj) final; |
| void PostCallRecordBindBufferMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindBufferMemoryInfo* pBindInfos, |
| const RecordObject& record_obj) final; |
| void PostCallRecordBindBufferMemory2KHR(VkDevice device, uint32_t bindInfoCount, const VkBindBufferMemoryInfo* pBindInfos, |
| const RecordObject& record_obj) final; |
| void PreCallRecordCmdBindDescriptorBuffersEXT(VkCommandBuffer commandBuffer, uint32_t bufferCount, |
| const VkDescriptorBufferBindingInfoEXT* pBindingInfos, |
| const RecordObject& record_obj, |
| chassis::CmdBindDescriptorBuffers& chassis_state) final; |
| |
| void PreCallActionCommand(Validator& gpuav, CommandBufferSubState& cb_state, const LastBound& last_bound, const Location& loc); |
| |
| void PreCallRecordCmdDraw(VkCommandBuffer commandBuffer, uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, |
| uint32_t firstInstance, const RecordObject& record_obj) final; |
| void PreCallRecordCmdDrawMultiEXT(VkCommandBuffer commandBuffer, uint32_t drawCount, const VkMultiDrawInfoEXT* pVertexInfo, |
| uint32_t instanceCount, uint32_t firstInstance, uint32_t stride, |
| const RecordObject& record_obj) final; |
| void PreCallRecordCmdDrawIndexed(VkCommandBuffer commandBuffer, uint32_t indexCount, uint32_t instanceCount, |
| uint32_t firstIndex, int32_t vertexOffset, uint32_t firstInstance, |
| const RecordObject& record_obj) final; |
| void PreCallRecordCmdDrawMultiIndexedEXT(VkCommandBuffer commandBuffer, uint32_t drawCount, |
| const VkMultiDrawIndexedInfoEXT* pIndexInfo, uint32_t instanceCount, |
| uint32_t firstInstance, uint32_t stride, const int32_t* pVertexOffset, |
| const RecordObject& record_obj) final; |
| void PreCallRecordCmdDrawIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t count, |
| uint32_t stride, const RecordObject& record_obj) final; |
| void PreCallRecordCmdDrawIndexedIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t count, |
| uint32_t stride, const RecordObject& record_obj) final; |
| void PreCallRecordCmdDrawIndirectCountKHR(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, |
| VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, |
| uint32_t stride, const RecordObject& record_obj) final; |
| void PreCallRecordCmdDrawIndirectCount(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, |
| VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, |
| uint32_t stride, const RecordObject& record_obj) final; |
| void PreCallRecordCmdDrawIndirect2KHR(VkCommandBuffer commandBuffer, const VkDrawIndirect2InfoKHR* pInfo, |
| const RecordObject& record_obj) final; |
| void PreCallRecordCmdDrawIndexedIndirect2KHR(VkCommandBuffer commandBuffer, const VkDrawIndirect2InfoKHR* pInfo, |
| const RecordObject& record_obj) final; |
| void PreCallRecordCmdDrawIndirectCount2KHR(VkCommandBuffer commandBuffer, const VkDrawIndirectCount2InfoKHR* pInfo, |
| const RecordObject& record_obj) final; |
| void PreCallRecordCmdDrawIndexedIndirectCount2KHR(VkCommandBuffer commandBuffer, const VkDrawIndirectCount2InfoKHR* pInfo, |
| const RecordObject& record_obj) final; |
| void PreCallRecordCmdDrawMeshTasksIndirectCount2EXT(VkCommandBuffer commandBuffer, const VkDrawIndirectCount2InfoKHR* pInfo, |
| const RecordObject& record_obj) final; |
| void PreCallRecordCmdDrawIndirectByteCount(VkCommandBuffer commandBuffer, const RecordObject& record_obj); |
| void PreCallRecordCmdDrawIndirectByteCount2EXT(VkCommandBuffer commandBuffer, uint32_t instanceCount, uint32_t firstInstance, |
| const VkBindTransformFeedbackBuffer2InfoEXT* pCounterInfo, |
| uint32_t counterOffset, uint32_t vertexStride, |
| const RecordObject& record_obj) final; |
| void PreCallRecordCmdDrawIndirectByteCountEXT(VkCommandBuffer commandBuffer, uint32_t instanceCount, uint32_t firstInstance, |
| VkBuffer counterBuffer, VkDeviceSize counterBufferOffset, uint32_t counterOffset, |
| uint32_t vertexStride, const RecordObject& record_obj) final; |
| void PreCallRecordCmdDrawIndexedIndirectCountKHR(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, |
| VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, |
| uint32_t stride, const RecordObject& record_obj) final; |
| void PreCallRecordCmdDrawIndexedIndirectCount(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, |
| VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, |
| uint32_t stride, const RecordObject& record_obj) final; |
| void PreCallRecordCmdDrawMeshTasksNV(VkCommandBuffer commandBuffer, uint32_t taskCount, uint32_t firstTask, |
| const RecordObject& record_obj) final; |
| void PreCallRecordCmdDrawMeshTasksIndirectNV(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, |
| uint32_t drawCount, uint32_t stride, const RecordObject& record_obj) final; |
| void PreCallRecordCmdDrawMeshTasksIndirectCountNV(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, |
| VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, |
| uint32_t stride, const RecordObject& record_obj) final; |
| void PreCallRecordCmdDrawMeshTasksEXT(VkCommandBuffer commandBuffer, uint32_t groupCountX, uint32_t groupCountY, |
| uint32_t groupCountZ, const RecordObject& record_obj) final; |
| void PreCallRecordCmdDrawMeshTasksIndirectEXT(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, |
| uint32_t drawCount, uint32_t stride, const RecordObject& record_obj) final; |
| void PreCallRecordCmdDrawMeshTasksIndirectCountEXT(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, |
| VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, |
| uint32_t stride, const RecordObject& record_obj) final; |
| void PreCallRecordCmdDispatch(VkCommandBuffer commandBuffer, uint32_t x, uint32_t y, uint32_t z, |
| const RecordObject& record_obj) final; |
| void PreCallRecordCmdDispatchIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, |
| const RecordObject& record_obj) final; |
| void PreCallRecordCmdDispatchIndirect2KHR(VkCommandBuffer commandBuffer, const VkDispatchIndirect2InfoKHR* pInfo, |
| const RecordObject& record_obj) final; |
| void PreCallRecordCmdDispatchBase(VkCommandBuffer commandBuffer, uint32_t baseGroupX, uint32_t baseGroupY, uint32_t baseGroupZ, |
| uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ, |
| const RecordObject& record_obj) final; |
| void PreCallRecordCmdDispatchBaseKHR(VkCommandBuffer commandBuffer, uint32_t baseGroupX, uint32_t baseGroupY, |
| uint32_t baseGroupZ, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ, |
| const RecordObject& record_obj) final; |
| void PreCallRecordCmdBuildAccelerationStructuresKHR(VkCommandBuffer commandBuffer, uint32_t infoCount, |
| const VkAccelerationStructureBuildGeometryInfoKHR* pInfos, |
| const VkAccelerationStructureBuildRangeInfoKHR* const* ppBuildRangeInfos, |
| const RecordObject& record_obj) final; |
| void PostCallRecordCmdBuildAccelerationStructuresKHR(VkCommandBuffer commandBuffer, uint32_t infoCount, |
| const VkAccelerationStructureBuildGeometryInfoKHR* pInfos, |
| const VkAccelerationStructureBuildRangeInfoKHR* const* ppBuildRangeInfos, |
| const RecordObject& record_obj) final; |
| void PreCallRecordCmdTraceRaysNV(VkCommandBuffer commandBuffer, VkBuffer raygenShaderBindingTableBuffer, |
| VkDeviceSize raygenShaderBindingOffset, VkBuffer missShaderBindingTableBuffer, |
| VkDeviceSize missShaderBindingOffset, VkDeviceSize missShaderBindingStride, |
| VkBuffer hitShaderBindingTableBuffer, VkDeviceSize hitShaderBindingOffset, |
| VkDeviceSize hitShaderBindingStride, VkBuffer callableShaderBindingTableBuffer, |
| VkDeviceSize callableShaderBindingOffset, VkDeviceSize callableShaderBindingStride, |
| uint32_t width, uint32_t height, uint32_t depth, const RecordObject& record_obj) final; |
| void PreCallRecordCmdTraceRaysKHR(VkCommandBuffer commandBuffer, |
| const VkStridedDeviceAddressRegionKHR* pRaygenShaderBindingTable, |
| const VkStridedDeviceAddressRegionKHR* pMissShaderBindingTable, |
| const VkStridedDeviceAddressRegionKHR* pHitShaderBindingTable, |
| const VkStridedDeviceAddressRegionKHR* pCallableShaderBindingTable, uint32_t width, |
| uint32_t height, uint32_t depth, const RecordObject& record_obj) final; |
| void PreCallRecordCmdTraceRaysIndirectKHR(VkCommandBuffer commandBuffer, |
| const VkStridedDeviceAddressRegionKHR* pRaygenShaderBindingTable, |
| const VkStridedDeviceAddressRegionKHR* pMissShaderBindingTable, |
| const VkStridedDeviceAddressRegionKHR* pHitShaderBindingTable, |
| const VkStridedDeviceAddressRegionKHR* pCallableShaderBindingTable, |
| VkDeviceAddress indirectDeviceAddress, const RecordObject& record_obj) final; |
| void PreCallRecordCmdTraceRaysIndirect2KHR(VkCommandBuffer commandBuffer, VkDeviceAddress indirectDeviceAddress, |
| const RecordObject& record_obj) final; |
| void PreCallRecordCmdExecuteGeneratedCommandsEXT(VkCommandBuffer commandBuffer, VkBool32 isPreprocessed, |
| const VkGeneratedCommandsInfoEXT* pGeneratedCommandsInfo, |
| const RecordObject& record_obj) final; |
| void PreCallRecordCmdCopyBufferToImage(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkImage dstImage, |
| VkImageLayout dstImageLayout, uint32_t regionCount, const VkBufferImageCopy* pRegions, |
| const RecordObject&) final; |
| void PreCallRecordCmdCopyBufferToImage2KHR(VkCommandBuffer commandBuffer, |
| const VkCopyBufferToImageInfo2KHR* pCopyBufferToImageInfo2KHR, |
| const RecordObject&) final; |
| void PreCallRecordCmdCopyBufferToImage2(VkCommandBuffer commandBuffer, const VkCopyBufferToImageInfo2* pCopyBufferToImageInfo, |
| const RecordObject&) final; |
| void PreCallRecordCmdCopyMemoryIndirectKHR(VkCommandBuffer commandBuffer, |
| const VkCopyMemoryIndirectInfoKHR* pCopyMemoryIndirectInfo, |
| const RecordObject& record_obj) final; |
| void PreCallRecordCmdCopyMemoryToImageIndirectKHR(VkCommandBuffer commandBuffer, |
| const VkCopyMemoryToImageIndirectInfoKHR* pCopyMemoryToImageIndirectInfo, |
| const RecordObject& record_obj) final; |
| void PreCallRecordCmdCopyMemoryToImageKHR(VkCommandBuffer commandBuffer, const VkCopyDeviceMemoryImageInfoKHR* pCopyMemoryInfo, |
| const RecordObject& record_obj) final; |
| |
| bool PreCallValidateCmdPushDataEXT(VkCommandBuffer commandBuffer, const VkPushDataInfoEXT* pPushDataInfo, |
| const ErrorObject& error_obj) const override; |
| |
| bool ValidateProtectedImage(const vvl::CommandBuffer& cb_state, const vvl::Image& image_state, const Location& image_loc, |
| const char* vuid, const char* more_message = "") const final; |
| bool ValidateUnprotectedImage(const vvl::CommandBuffer& cb_state, const vvl::Image& image_state, const Location& image_loc, |
| const char* vuid, const char* more_message = "") const final; |
| bool ValidateProtectedBuffer(const vvl::CommandBuffer& cb_state, const vvl::Buffer& buffer_state, const Location& buffer_loc, |
| const char* vuid, const char* more_message = "") const final; |
| bool ValidateUnprotectedBuffer(const vvl::CommandBuffer& cb_state, const vvl::Buffer& buffer_state, const Location& buffer_loc, |
| const char* vuid, const char* more_message = "") const final; |
| bool ValidateProtectedTensor(const vvl::CommandBuffer& cb_state, const vvl::Tensor& tensor_state, const Location& tensor_loc, |
| const char* more_message = "") const final; |
| bool ValidateUnprotectedTensor(const vvl::CommandBuffer& cb_state, const vvl::Tensor& tensor_state, const Location& tensor_loc, |
| const char* more_message = "") const final; |
| |
| void Created(vvl::DescriptorSet& set) final; |
| void Created(vvl::CommandBuffer& cb_state) final; |
| void Created(vvl::Queue& queue) final; |
| void Created(vvl::Image&) final; |
| void Created(vvl::ImageView&) final; |
| void Created(vvl::Buffer&) final; |
| void Created(vvl::BufferView&) final; |
| void Created(vvl::Sampler&) final; |
| void Created(vvl::AccelerationStructureNV&) final; |
| void Created(vvl::AccelerationStructureKHR&) final; |
| void Created(vvl::Tensor&) final; |
| void Created(vvl::TensorView&) final; |
| void Created(vvl::ShaderObject&) final; |
| void Created(vvl::Pipeline&) final; |
| |
| void DebugCapture() final; |
| |
| public: |
| // We find ourselves constantly needing to create some resource for the "lifetime of GPU-AV" |
| // We don't want a messy global space to managae it and use this to allow each check to manage the resource where it is used. |
| // The goal is the first time we need the resource, we create it then, and afterwards, its cached and we can regain |
| vko::SharedResourcesCache<true> shared_resources_cache; |
| |
| PFN_vkSetDeviceLoaderData vk_set_device_loader_data_; |
| |
| VmaAllocator vma_allocator_ = {}; |
| std::unique_ptr<vko::DescriptorSetManager> desc_set_manager_; |
| |
| // This is so universally used, that we decided currently to not be in vko::SharedResourcesCache |
| // This is just a buffer with a uint32_t value from [0, GpuAVSettings::indices_count - 1] so we can update prior to an action command |
| // (draw/dispatch) to know where it came from |
| vko::Buffer global_indices_buffer_; |
| uint32_t indices_buffer_alignment_ = 0; |
| |
| // VK_EXT_descriptor_buffer global tracking |
| struct DescriptorBuffer { |
| // TODO - These are not needed for DebugPrintf, but will be needed for GPU-AV to track the descriptor used |
| // Most common apps will have few, but large descriptor buffers |
| vvl::unordered_set<VkBuffer> resource_handles_; |
| // We need to track handles in order to adjust vkMapMemory calls |
| vvl::unordered_set<VkDeviceMemory> resource_memory_handles_; |
| } descriptor_buffer; |
| |
| // VK_EXT_descriptor_heap global tracking |
| struct ResourceHeap { |
| const vvl::Buffer* buffer_state_ = nullptr; |
| VkDeviceSize reserved_offset_ = 0; |
| } resource_heap; |
| |
| vko::Buffer& GetGlobalDescriptorBuffer(); |
| vko::Buffer& GetGlobalDescriptorHeap(); |
| |
| private: |
| // For Descriptor Buffer/Heap we have our own global buffer, but lazily allocate it when first used |
| vko::Buffer global_resource_descriptor_buffer_; |
| vko::Buffer global_resource_descriptor_heap_; |
| |
| std::string instrumented_shader_cache_path_{}; |
| |
| // Make sure we call the right versions of any timeline semaphore functions. |
| bool timeline_khr_ = false; |
| |
| VkQueue internal_transfer_queue_handle_ = VK_NULL_HANDLE; |
| uint32_t internal_transfer_queue_family_index_ = 0; |
| |
| public: |
| vko::GpuResourcesManager gpu_resources_manager_; |
| }; |
| |
| } // namespace gpuav |