From 7e89beb36c5f1adac747a5a81df867d6fd4b49b8 Mon Sep 17 00:00:00 2001 From: Locke Lin Date: Mon, 1 Jul 2024 17:26:21 -0600 Subject: [PATCH 1/3] Allocator support VideoSession Allocator does something for VideoSession, that is similar with Buffer and Image. The different is that a VideoSeesion could bind plural memories. See GetVideoSessionMemoryRequirements and BindVideoSessionMemory. --- framework/decode/vulkan_default_allocator.cpp | 117 +++++++++++++ framework/decode/vulkan_default_allocator.h | 23 +++ framework/decode/vulkan_object_info.h | 8 + framework/decode/vulkan_realign_allocator.cpp | 38 ++++ framework/decode/vulkan_realign_allocator.h | 7 + framework/decode/vulkan_rebind_allocator.cpp | 162 ++++++++++++++++-- framework/decode/vulkan_rebind_allocator.h | 37 +++- .../decode/vulkan_replay_consumer_base.cpp | 143 ++++++++++++++++ .../decode/vulkan_replay_consumer_base.h | 20 +++ framework/decode/vulkan_resource_allocator.h | 27 +++ .../generated_vulkan_replay_consumer.cpp | 26 ++- .../vulkan_generators/replay_overrides.json | 5 +- 12 files changed, 582 insertions(+), 31 deletions(-) diff --git a/framework/decode/vulkan_default_allocator.cpp b/framework/decode/vulkan_default_allocator.cpp index a37e20609d..aaa407b2c2 100644 --- a/framework/decode/vulkan_default_allocator.cpp +++ b/framework/decode/vulkan_default_allocator.cpp @@ -138,6 +138,51 @@ void VulkanDefaultAllocator::DestroyImage(VkImage image, functions_.destroy_image(device_, image, allocation_callbacks); } +VkResult VulkanDefaultAllocator::CreateVideoSession(const VkVideoSessionCreateInfoKHR* create_info, + const VkAllocationCallbacks* allocation_callbacks, + format::HandleId capture_id, + VkVideoSessionKHR* session, + std::vector* allocator_datas) +{ + VkResult result = VK_ERROR_INITIALIZATION_FAILED; + + if (allocator_datas != nullptr) + { + result = functions_.create_video_session(device_, create_info, allocation_callbacks, session); + + if (result >= 0) + { + uint32_t count = 0; + functions_.get_video_session_memory_requirements(device_, *session, &count, nullptr); + allocator_datas->resize(count); + for (auto& allocator_data : *allocator_datas) + { + auto resource_alloc_info = new ResourceAllocInfo; + resource_alloc_info->capture_id = capture_id; + allocator_data = reinterpret_cast(resource_alloc_info); + } + } + } + + return result; +} + +void VulkanDefaultAllocator::DestroyVideoSession(VkVideoSessionKHR session, + const VkAllocationCallbacks* allocation_callbacks, + std::vector allocator_datas) +{ + for (auto allocator_data : allocator_datas) + { + if (allocator_data != 0) + { + auto resource_alloc_info = reinterpret_cast(allocator_data); + delete resource_alloc_info; + } + } + + functions_.destroy_video_session(device_, session, allocation_callbacks); +} + void VulkanDefaultAllocator::GetImageSubresourceLayout(VkImage image, const VkImageSubresource* subresource, VkSubresourceLayout* layout, @@ -344,6 +389,48 @@ VkResult VulkanDefaultAllocator::BindImageMemory2(uint32_t b return result; } +VkResult VulkanDefaultAllocator::BindVideoSessionMemory(VkVideoSessionKHR video_session, + uint32_t bind_info_count, + const VkBindVideoSessionMemoryInfoKHR* bind_infos, + const ResourceData* allocator_session_datas, + const MemoryData* allocator_memory_datas, + VkMemoryPropertyFlags* bind_memory_properties) +{ + VkResult result = VK_ERROR_INITIALIZATION_FAILED; + + if ((bind_infos != nullptr) && (allocator_session_datas != nullptr) && (allocator_memory_datas != nullptr) && + (bind_memory_properties != nullptr)) + { + result = functions_.bind_video_session_memory(device_, video_session, bind_info_count, bind_infos); + + if (result == VK_SUCCESS) + { + for (uint32_t i = 0; i < bind_info_count; ++i) + { + auto allocator_session_data = allocator_session_datas[i]; + auto allocator_memory_data = allocator_memory_datas[i]; + + if ((allocator_session_data != 0) && (allocator_memory_data != 0)) + { + auto resource_alloc_info = reinterpret_cast(allocator_session_data); + resource_alloc_info->bound_memory = bind_infos[i].memory; + resource_alloc_info->bound_offset = bind_infos[i].memoryOffset; + + auto memory_alloc_info = reinterpret_cast(allocator_memory_data); + bind_memory_properties[i] = memory_alloc_info->property_flags; + } + else + { + GFXRECON_LOG_WARNING("VulkanDefaultAllocator binding a VkVideoSessionKHR object to a " + "VkDeviceMemory object without allocator data"); + } + } + } + } + + return result; +} + VkResult VulkanDefaultAllocator::MapMemory(VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize size, @@ -513,6 +600,36 @@ void VulkanDefaultAllocator::ReportBindImage2Incompatibility(uint32_t } } +void VulkanDefaultAllocator::ReportBindVideoSessionIncompatibility(VkVideoSessionKHR video_session, + uint32_t bind_info_count, + const VkBindVideoSessionMemoryInfoKHR* bind_infos, + const ResourceData* allocator_resource_datas, + const MemoryData* allocator_memory_datas) +{ + GFXRECON_UNREFERENCED_PARAMETER(allocator_resource_datas); + + if ((bind_infos != nullptr) && (allocator_memory_datas != nullptr)) + { + uint32_t session_requirements_count = 0; + functions_.get_video_session_memory_requirements(device_, video_session, &session_requirements_count, nullptr); + + VkVideoSessionMemoryRequirementsKHR reqs = {}; + reqs.sType = VK_STRUCTURE_TYPE_VIDEO_SESSION_MEMORY_REQUIREMENTS_KHR; + std::vector session_requirements(session_requirements_count, reqs); + functions_.get_video_session_memory_requirements( + device_, video_session, &session_requirements_count, session_requirements.data()); + + std::vector requirements; + for (uint32_t i = 0; i < bind_info_count; ++i) + { + auto mem_index = bind_infos[i].memoryBindIndex; + requirements.emplace_back(session_requirements[mem_index].memoryRequirements); + } + + ReportBindIncompatibility(requirements.data(), allocator_memory_datas, bind_info_count); + } +} + void VulkanDefaultAllocator::ReportBindIncompatibility(const VkMemoryRequirements* requirements, const MemoryData* allocator_memory_datas, uint32_t resource_count) diff --git a/framework/decode/vulkan_default_allocator.h b/framework/decode/vulkan_default_allocator.h index 70bad33f66..935811f2cd 100644 --- a/framework/decode/vulkan_default_allocator.h +++ b/framework/decode/vulkan_default_allocator.h @@ -72,6 +72,16 @@ class VulkanDefaultAllocator : public VulkanResourceAllocator const VkAllocationCallbacks* allocation_callbacks, ResourceData allocator_data) override; + virtual VkResult CreateVideoSession(const VkVideoSessionCreateInfoKHR* create_info, + const VkAllocationCallbacks* allocation_callbacks, + format::HandleId capture_id, + VkVideoSessionKHR* session, + std::vector* allocator_datas) override; + + virtual void DestroyVideoSession(VkVideoSessionKHR session, + const VkAllocationCallbacks* allocation_callbacks, + std::vector allocator_datas) override; + virtual void GetImageSubresourceLayout(VkImage image, const VkImageSubresource* subresource, VkSubresourceLayout* layout, @@ -118,6 +128,13 @@ class VulkanDefaultAllocator : public VulkanResourceAllocator const MemoryData* allocator_memory_datas, VkMemoryPropertyFlags* bind_memory_properties) override; + virtual VkResult BindVideoSessionMemory(VkVideoSessionKHR video_session, + uint32_t bind_info_count, + const VkBindVideoSessionMemoryInfoKHR* bind_infos, + const ResourceData* allocator_session_datas, + const MemoryData* allocator_memory_datas, + VkMemoryPropertyFlags* bind_memory_properties) override; + virtual VkResult MapMemory(VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize size, @@ -158,6 +175,12 @@ class VulkanDefaultAllocator : public VulkanResourceAllocator const ResourceData* allocator_resource_datas, const MemoryData* allocator_memory_datas) override; + virtual void ReportBindVideoSessionIncompatibility(VkVideoSessionKHR video_session, + uint32_t bind_info_count, + const VkBindVideoSessionMemoryInfoKHR* bind_infos, + const ResourceData* allocator_resource_datas, + const MemoryData* allocator_memory_datas) override; + // Direct allocation methods that perform memory allocation and resource creation without performing memory // translation. These methods allow the replay tool to allocate staging resources through the resource allocator so // that the allocator is aware of all allocations performed at replay. diff --git a/framework/decode/vulkan_object_info.h b/framework/decode/vulkan_object_info.h index 51c56ef373..8a2862e3ba 100644 --- a/framework/decode/vulkan_object_info.h +++ b/framework/decode/vulkan_object_info.h @@ -537,6 +537,14 @@ struct DeferredOperationKHRInfo : public VulkanObjectInfo { std::unordered_map array_counts; + + // The following values are only used for memory portability. + std::vector allocator_datas; + + // This is only used when loading the initial state for trimmed files. + std::vector memory_property_flags; + + uint32_t queue_family_index{ 0 }; }; struct ShaderEXTInfo : VulkanObjectInfo diff --git a/framework/decode/vulkan_realign_allocator.cpp b/framework/decode/vulkan_realign_allocator.cpp index ce9f01cf37..9fad7fda01 100644 --- a/framework/decode/vulkan_realign_allocator.cpp +++ b/framework/decode/vulkan_realign_allocator.cpp @@ -207,6 +207,44 @@ VkResult VulkanRealignAllocator::BindImageMemory2(uint32_t b bind_memory_properties); } +VkResult VulkanRealignAllocator::BindVideoSessionMemory(VkVideoSessionKHR video_session, + uint32_t bind_info_count, + const VkBindVideoSessionMemoryInfoKHR* bind_infos, + const ResourceData* allocator_session_datas, + const MemoryData* allocator_memory_datas, + VkMemoryPropertyFlags* bind_memory_properties) +{ + std::unique_ptr realign_bind_infos; + + if ((allocator_session_datas != nullptr) && (bind_infos != nullptr)) + { + realign_bind_infos = std::make_unique(bind_info_count); + + for (uint32_t i = 0; i < bind_info_count; ++i) + { + realign_bind_infos[i] = bind_infos[i]; + + auto resource_info = GetResourceAllocInfo(allocator_session_datas[i]); + if (resource_info != nullptr) + { + // Update video seesion to new binding offset from first pass data collected from resource tracking. + auto tracked_session_info = tracked_object_table_->GetTrackedResourceInfo(resource_info->capture_id); + if (tracked_session_info != nullptr) + { + realign_bind_infos[i].memoryOffset = tracked_session_info->GetReplayBindOffset(); + } + } + } + } + + return VulkanDefaultAllocator::BindVideoSessionMemory(video_session, + bind_info_count, + realign_bind_infos.get(), + allocator_session_datas, + allocator_memory_datas, + bind_memory_properties); +} + VkResult VulkanRealignAllocator::MapMemory(VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize size, diff --git a/framework/decode/vulkan_realign_allocator.h b/framework/decode/vulkan_realign_allocator.h index a5211d068b..e21a715e53 100644 --- a/framework/decode/vulkan_realign_allocator.h +++ b/framework/decode/vulkan_realign_allocator.h @@ -75,6 +75,13 @@ class VulkanRealignAllocator : public VulkanDefaultAllocator const MemoryData* allocator_memory_datas, VkMemoryPropertyFlags* bind_memory_properties) override; + virtual VkResult BindVideoSessionMemory(VkVideoSessionKHR video_session, + uint32_t bind_info_count, + const VkBindVideoSessionMemoryInfoKHR* bind_infos, + const ResourceData* allocator_session_datas, + const MemoryData* allocator_memory_datas, + VkMemoryPropertyFlags* bind_memory_properties) override; + virtual VkResult MapMemory(VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize size, diff --git a/framework/decode/vulkan_rebind_allocator.cpp b/framework/decode/vulkan_rebind_allocator.cpp index d9ea751b5a..2cee081bb1 100644 --- a/framework/decode/vulkan_rebind_allocator.cpp +++ b/framework/decode/vulkan_rebind_allocator.cpp @@ -244,10 +244,10 @@ VkResult VulkanRebindAllocator::CreateBuffer(const VkBufferCreateInfo* create if (result >= 0) { - auto resource_alloc_info = new ResourceAllocInfo; - resource_alloc_info->usage = create_info->usage; - resource_alloc_info->is_image = false; - (*allocator_data) = reinterpret_cast(resource_alloc_info); + auto resource_alloc_info = new ResourceAllocInfo; + resource_alloc_info->usage = create_info->usage; + resource_alloc_info->object_type = ObjectType::buffer; + (*allocator_data) = reinterpret_cast(resource_alloc_info); if (create_info->pNext != nullptr) { @@ -305,12 +305,12 @@ VkResult VulkanRebindAllocator::CreateImage(const VkImageCreateInfo* create_ if (result >= 0) { - auto resource_alloc_info = new ResourceAllocInfo; - resource_alloc_info->usage = create_info->usage; - resource_alloc_info->tiling = create_info->tiling; - resource_alloc_info->height = create_info->extent.height; - resource_alloc_info->is_image = true; - (*allocator_data) = reinterpret_cast(resource_alloc_info); + auto resource_alloc_info = new ResourceAllocInfo; + resource_alloc_info->usage = create_info->usage; + resource_alloc_info->tiling = create_info->tiling; + resource_alloc_info->height = create_info->extent.height; + resource_alloc_info->object_type = ObjectType::image; + (*allocator_data) = reinterpret_cast(resource_alloc_info); if (create_info->pNext != nullptr) { @@ -351,6 +351,50 @@ void VulkanRebindAllocator::DestroyImage(VkImage image, } } +VkResult VulkanRebindAllocator::CreateVideoSession(const VkVideoSessionCreateInfoKHR* create_info, + const VkAllocationCallbacks* allocation_callbacks, + format::HandleId capture_id, + VkVideoSessionKHR* session, + std::vector* allocator_datas) +{ + GFXRECON_UNREFERENCED_PARAMETER(allocation_callbacks); + GFXRECON_UNREFERENCED_PARAMETER(capture_id); + + VkResult result = VK_ERROR_INITIALIZATION_FAILED; + + if ((create_info != nullptr) && (session != nullptr) && (allocator_datas != nullptr)) + { + result = functions_.create_video_session(device_, create_info, allocation_callbacks, session); + + if (result >= 0) + { + uint32_t count = 0; + functions_.get_video_session_memory_requirements(device_, *session, &count, nullptr); + allocator_datas->resize(count); + for (auto& allocator_data : *allocator_datas) + { + auto resource_alloc_info = new ResourceAllocInfo; + resource_alloc_info->object_type = ObjectType::video_session; + allocator_data = reinterpret_cast(resource_alloc_info); + + if (create_info->pNext != nullptr) + { + resource_alloc_info->uses_extensions = true; + } + } + } + } + + return result; +} + +void VulkanRebindAllocator::DestroyVideoSession(VkVideoSessionKHR session, + const VkAllocationCallbacks* allocation_callbacks, + std::vector allocator_datas) +{ + // TODO: VMA doesn't support video session(vmaDestroyVideoSession). Do it ourselves until VMA support it. +} + void VulkanRebindAllocator::GetImageSubresourceLayout(VkImage image, const VkImageSubresource* subresource, VkSubresourceLayout* layout, @@ -435,6 +479,11 @@ void VulkanRebindAllocator::FreeMemory(VkDeviceMemory memory, entry.second->memory_info = nullptr; } + for (const auto& entry : memory_alloc_info->original_sessions) + { + entry.second->memory_info = nullptr; + } + delete memory_alloc_info; } } @@ -785,6 +834,18 @@ VkResult VulkanRebindAllocator::BindImageMemory2(uint32_t bi return result; } +VkResult VulkanRebindAllocator::BindVideoSessionMemory(VkVideoSessionKHR video_session, + uint32_t bind_info_count, + const VkBindVideoSessionMemoryInfoKHR* bind_infos, + const ResourceData* allocator_session_datas, + const MemoryData* allocator_memory_datas, + VkMemoryPropertyFlags* bind_memory_properties) +{ + // TODO: VMA doesn't support video session(vmaAllocateMemoryForVideoSession and vmaBindVideoSessionMemory). + // Do it ourselves until VMA support it. + return VK_ERROR_INITIALIZATION_FAILED; +} + VkResult VulkanRebindAllocator::MapMemory(VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize size, @@ -879,6 +940,11 @@ VkResult VulkanRebindAllocator::WriteMappedMemoryRange(MemoryData allocator_ UpdateBoundResource(entry.second, write_start, write_end, data); } + for (const auto& entry : memory_alloc_info->original_sessions) + { + UpdateBoundResource(entry.second, write_start, write_end, data); + } + result = VK_SUCCESS; } else @@ -939,17 +1005,30 @@ void VulkanRebindAllocator::ReportBindImage2Incompatibility(uint32_t ReportBindIncompatibility(allocator_resource_datas, bind_info_count); } +void VulkanRebindAllocator::ReportBindVideoSessionIncompatibility(VkVideoSessionKHR video_session, + uint32_t bind_info_count, + const VkBindVideoSessionMemoryInfoKHR* bind_infos, + const ResourceData* allocator_resource_datas, + const MemoryData* allocator_memory_datas) +{ + GFXRECON_UNREFERENCED_PARAMETER(video_session); + GFXRECON_UNREFERENCED_PARAMETER(bind_infos); + GFXRECON_UNREFERENCED_PARAMETER(allocator_memory_datas); + + ReportBindIncompatibility(allocator_resource_datas, bind_info_count); +} + void VulkanRebindAllocator::WriteBoundResourceDirect( ResourceAllocInfo* resource_alloc_info, size_t src_offset, size_t dst_offset, size_t data_size, const uint8_t* data) { - if (!resource_alloc_info->is_image) + if (resource_alloc_info->object_type == ObjectType::buffer) { util::platform::MemoryCopy(static_cast(resource_alloc_info->mapped_pointer) + dst_offset, data_size, data + src_offset, data_size); } - else + else if (resource_alloc_info->object_type == ObjectType::image) { if (!resource_alloc_info->layouts.empty()) { @@ -989,18 +1068,30 @@ void VulkanRebindAllocator::WriteBoundResourceDirect( data_size); } } + else if (resource_alloc_info->object_type == ObjectType::video_session) + { + // TODO: implement direct video session copy + GFXRECON_LOG_WARNING("Skipping video session in direct write: support not yet implemented"); + } } void VulkanRebindAllocator::WriteBoundResourceStaging( ResourceAllocInfo* resource_alloc_info, size_t src_offset, size_t dst_offset, size_t data_size, const uint8_t* data) { - if (resource_alloc_info->is_image && dst_offset != 0) + if (resource_alloc_info->object_type == ObjectType::image && dst_offset != 0) { // TODO: implement offset based stagging image copy GFXRECON_LOG_WARNING("Skipping image with offset in staging write: support not yet implemented"); return; } + if (resource_alloc_info->object_type == ObjectType::video_session) + { + // TODO: implement stagging video session copy + GFXRECON_LOG_WARNING("Skipping video session in staging write: support not yet implemented"); + return; + } + VkBuffer staging_buf{}; VkBufferCreateInfo staging_buf_create_info{}; staging_buf_create_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; @@ -1043,7 +1134,7 @@ void VulkanRebindAllocator::WriteBoundResourceStaging( if (result == VK_SUCCESS) { - if (resource_alloc_info->is_image) + if (resource_alloc_info->object_type == ObjectType::image) { VkImage original_image{}; @@ -1077,7 +1168,7 @@ void VulkanRebindAllocator::WriteBoundResourceStaging( result = functions_.end_command_buffer(cmd_buffer_); } } - else + else if (resource_alloc_info->object_type == ObjectType::buffer) { VkBuffer original_buffer{}; for (const std::pair& elt : @@ -1305,6 +1396,14 @@ VkResult VulkanRebindAllocator::UpdateMappedMemoryRanges( result = VK_ERROR_MEMORY_MAP_FAILED; } } + + for (const auto& entry : memory_alloc_info->original_sessions) + { + if (UpdateMappedMemoryRange(entry.second, range_start, range_end, update_func) != VK_SUCCESS) + { + result = VK_ERROR_MEMORY_MAP_FAILED; + } + } } } } @@ -1436,6 +1535,39 @@ VmaMemoryUsage VulkanRebindAllocator::GetImageMemoryUsage(VkImageUsageFlags return AdjustMemoryUsage(memory_usage, replay_requirements); } +VmaMemoryUsage VulkanRebindAllocator::GetVideoSeesionMemoryUsage(VkMemoryPropertyFlags capture_properties, + const VkMemoryRequirements& replay_requirements) +{ + // Start with CPU_TO_GPU usage. + VmaMemoryUsage memory_usage = VMA_MEMORY_USAGE_CPU_TO_GPU; + + // Adjust memory usage based on capture memory properties. + // If present, remove AMD device extension property flags and perform checks using only the core property flags. + capture_properties &= ~(VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD | VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD); + + if ((memory_usage != VMA_MEMORY_USAGE_GPU_TO_CPU) && + (capture_properties & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) == VK_MEMORY_PROPERTY_HOST_CACHED_BIT) + { + // If the resource was bound to HOST_CACHED memory, make it GPU_TO_CPU usage to continue using HOST_CACHED. + memory_usage = VMA_MEMORY_USAGE_GPU_TO_CPU; + } + else if ((memory_usage != VMA_MEMORY_USAGE_GPU_ONLY) && (capture_properties == VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)) + { + // If the resource was bound to memory that was exclusively DEVICE_LOCAL, make it GPU_ONLY. + memory_usage = VMA_MEMORY_USAGE_GPU_ONLY; + } + else if ((memory_usage == VMA_MEMORY_USAGE_GPU_ONLY) && + ((capture_properties & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) != VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)) + { + // If the resource was bound to memory that did not have the DEVICE_LOCAL property, pick a HOST_VISIBLE + // usage option. + memory_usage = VMA_MEMORY_USAGE_CPU_TO_GPU; + } + + // Adjust memory usage based on replay memory requirements. + return AdjustMemoryUsage(memory_usage, replay_requirements); +} + VmaMemoryUsage VulkanRebindAllocator::AdjustMemoryUsage(VmaMemoryUsage desired_usage, const VkMemoryRequirements& replay_requirements) { diff --git a/framework/decode/vulkan_rebind_allocator.h b/framework/decode/vulkan_rebind_allocator.h index 5df05c1aa3..556437b5ce 100644 --- a/framework/decode/vulkan_rebind_allocator.h +++ b/framework/decode/vulkan_rebind_allocator.h @@ -76,6 +76,16 @@ class VulkanRebindAllocator : public VulkanResourceAllocator const VkAllocationCallbacks* allocation_callbacks, ResourceData allocator_data) override; + virtual VkResult CreateVideoSession(const VkVideoSessionCreateInfoKHR* create_info, + const VkAllocationCallbacks* allocation_callbacks, + format::HandleId capture_id, + VkVideoSessionKHR* session, + std::vector* allocator_datas) override; + + virtual void DestroyVideoSession(VkVideoSessionKHR session, + const VkAllocationCallbacks* allocation_callbacks, + std::vector allocator_datas) override; + virtual void GetImageSubresourceLayout(VkImage image, const VkImageSubresource* subresource, VkSubresourceLayout* layout, @@ -140,6 +150,13 @@ class VulkanRebindAllocator : public VulkanResourceAllocator const MemoryData* allocator_memory_datas, VkMemoryPropertyFlags* bind_memory_properties) override; + virtual VkResult BindVideoSessionMemory(VkVideoSessionKHR video_session, + uint32_t bind_info_count, + const VkBindVideoSessionMemoryInfoKHR* bind_infos, + const ResourceData* allocator_session_datas, + const MemoryData* allocator_memory_datas, + VkMemoryPropertyFlags* bind_memory_properties) override; + virtual VkResult MapMemory(VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize size, @@ -180,6 +197,12 @@ class VulkanRebindAllocator : public VulkanResourceAllocator const ResourceData* allocator_resource_datas, const MemoryData* allocator_memory_datas) override; + virtual void ReportBindVideoSessionIncompatibility(VkVideoSessionKHR video_session, + uint32_t bind_info_count, + const VkBindVideoSessionMemoryInfoKHR* bind_infos, + const ResourceData* allocator_resource_datas, + const MemoryData* allocator_memory_datas) override; + // Direct allocation methods that perform memory allocation and resource creation without performing memory // translation. These methods allow the replay tool to allocate staging resources through the resource allocator so // that the allocator is aware of all allocations performed at replay. @@ -293,6 +316,14 @@ class VulkanRebindAllocator : public VulkanResourceAllocator VkSubresourceLayout rebind{}; }; + enum ObjectType + { + none = 0, + buffer = 1, + image = 2, + video_session = 3, + }; + struct ResourceAllocInfo { MemoryAllocInfo* memory_info{ nullptr }; @@ -302,7 +333,7 @@ class VulkanRebindAllocator : public VulkanResourceAllocator VkDeviceSize original_offset{ 0 }; VkDeviceSize rebind_offset{ 0 }; VkDeviceSize size{ 0 }; - bool is_image{ false }; + ObjectType object_type{ none }; VkFlags usage{ 0 }; VkImageTiling tiling{}; uint32_t height{ 0 }; @@ -322,6 +353,7 @@ class VulkanRebindAllocator : public VulkanResourceAllocator std::unique_ptr original_content; std::unordered_map original_buffers; std::unordered_map original_images; + std::unordered_map original_sessions; }; private: @@ -378,6 +410,9 @@ class VulkanRebindAllocator : public VulkanResourceAllocator VkMemoryPropertyFlags capture_properties, const VkMemoryRequirements& replay_requirements); + VmaMemoryUsage GetVideoSeesionMemoryUsage(VkMemoryPropertyFlags capture_properties, + const VkMemoryRequirements& replay_requirements); + VmaMemoryUsage AdjustMemoryUsage(VmaMemoryUsage desired_usage, const VkMemoryRequirements& replay_requirements); void ReportBindIncompatibility(const ResourceData* allocator_resource_datas, uint32_t resource_count); diff --git a/framework/decode/vulkan_replay_consumer_base.cpp b/framework/decode/vulkan_replay_consumer_base.cpp index 735e3984dc..a8f81f37e5 100644 --- a/framework/decode/vulkan_replay_consumer_base.cpp +++ b/framework/decode/vulkan_replay_consumer_base.cpp @@ -1840,7 +1840,12 @@ void VulkanReplayConsumerBase::InitializeResourceAllocator(const PhysicalDeviceI functions.reset_command_buffer = device_table->ResetCommandBuffer; functions.free_command_buffers = device_table->FreeCommandBuffers; functions.destroy_command_pool = device_table->DestroyCommandPool; + functions.create_video_session = device_table->CreateVideoSessionKHR; + functions.destroy_video_session = device_table->DestroyVideoSessionKHR; + functions.bind_video_session_memory = device_table->BindVideoSessionMemoryKHR; + functions.get_video_session_memory_requirements = device_table->GetVideoSessionMemoryRequirementsKHR; functions.get_physical_device_queue_family_properties = instance_table->GetPhysicalDeviceQueueFamilyProperties; + if (physical_device_info->parent_api_version >= VK_MAKE_VERSION(1, 1, 0)) { functions.get_physical_device_memory_properties2 = instance_table->GetPhysicalDeviceMemoryProperties2; @@ -4612,6 +4617,80 @@ VkResult VulkanReplayConsumerBase::OverrideBindImageMemory2( return result; } +VkResult VulkanReplayConsumerBase::OverrideBindVideoSessionMemoryKHR( + PFN_vkBindVideoSessionMemoryKHR func, + VkResult original_result, + const DeviceInfo* device_info, + VideoSessionKHRInfo* video_session_info, + uint32_t bindSessionMemoryInfoCount, + StructPointerDecoder* pBindSessionMemoryInfos) +{ + GFXRECON_UNREFERENCED_PARAMETER(func); + GFXRECON_UNREFERENCED_PARAMETER(original_result); + + GFXRECON_ASSERT((device_info != nullptr) && (video_session_info != nullptr) && + (pBindSessionMemoryInfos != nullptr)); + + auto replay_bind_infos = pBindSessionMemoryInfos->GetPointer(); + auto replay_bind_meta_infos = pBindSessionMemoryInfos->GetMetaStructPointer(); + GFXRECON_ASSERT((replay_bind_infos != nullptr) && (replay_bind_meta_infos != nullptr)); + + uint32_t session_mem_count = video_session_info->allocator_datas.size(); + std::vector memory_infos; + std::vector allocator_session_datas(session_mem_count, 0); + std::vector allocator_memory_datas(session_mem_count, 0); + std::vector memory_property_flags(session_mem_count, 0); + + for (uint32_t i = 0; i < bindSessionMemoryInfoCount; ++i) + { + const auto* bind_meta_info = &replay_bind_meta_infos[i]; + auto mem_index = bind_meta_info->decoded_value->memoryBindIndex; + GFXRECON_ASSERT(mem_index < session_mem_count); + + auto memory_info = object_info_table_.GetDeviceMemoryInfo(bind_meta_info->memory); + + memory_infos.push_back(memory_info); + + allocator_session_datas[mem_index] = video_session_info->allocator_datas[mem_index]; + + if (memory_info != nullptr) + { + allocator_memory_datas[mem_index] = memory_info->allocator_data; + } + } + + auto allocator = device_info->allocator.get(); + GFXRECON_ASSERT(allocator != nullptr); + + VkResult result = allocator->BindVideoSessionMemory(video_session_info->handle, + bindSessionMemoryInfoCount, + replay_bind_infos, + allocator_session_datas.data(), + allocator_memory_datas.data(), + memory_property_flags.data()); + + if (result == VK_SUCCESS) + { + video_session_info->memory_property_flags.resize(session_mem_count); + for (uint32_t i = 0; i < session_mem_count; ++i) + { + video_session_info->memory_property_flags[i] = memory_property_flags[i]; + } + } + else if (original_result == VK_SUCCESS) + { + // When bind fails at replay, but succeeded at capture, check for memory incompatibilities and recommend + // enabling memory translation. + allocator->ReportBindVideoSessionIncompatibility(video_session_info->handle, + bindSessionMemoryInfoCount, + replay_bind_infos, + allocator_session_datas.data(), + allocator_memory_datas.data()); + } + + return result; +} + VkResult VulkanReplayConsumerBase::OverrideCreateBuffer(PFN_vkCreateBuffer func, VkResult original_result, @@ -4849,6 +4928,70 @@ void VulkanReplayConsumerBase::OverrideDestroyImage( allocator->DestroyImage(image, GetAllocationCallbacks(pAllocator), allocator_data); } +VkResult VulkanReplayConsumerBase::OverrideCreateVideoSessionKHR( + PFN_vkCreateVideoSessionKHR func, + VkResult original_result, + const DeviceInfo* device_info, + const StructPointerDecoder* pCreateInfo, + const StructPointerDecoder* pAllocator, + HandlePointerDecoder* pVideoSession) +{ + GFXRECON_UNREFERENCED_PARAMETER(original_result); + + GFXRECON_ASSERT((device_info != nullptr) && (pCreateInfo != nullptr) && (pVideoSession != nullptr) && + !pVideoSession->IsNull() && (pVideoSession->GetHandlePointer() != nullptr)); + + auto allocator = device_info->allocator.get(); + GFXRECON_ASSERT(allocator != nullptr); + + VkResult result = VK_SUCCESS; + std::vector allocator_datas; + auto replay_session = pVideoSession->GetHandlePointer(); + auto capture_id = (*pVideoSession->GetPointer()); + auto replay_create_info = pCreateInfo->GetPointer(); + + result = allocator->CreateVideoSession( + replay_create_info, GetAllocationCallbacks(pAllocator), capture_id, replay_session, &allocator_datas); + + if ((result == VK_SUCCESS) && (replay_create_info != nullptr) && ((*replay_session) != VK_NULL_HANDLE)) + { + auto session_info = reinterpret_cast(pVideoSession->GetConsumerData(0)); + GFXRECON_ASSERT(session_info != nullptr); + + session_info->allocator_datas = allocator_datas; + session_info->queue_family_index = replay_create_info->queueFamilyIndex; + } + + return result; +} + +void VulkanReplayConsumerBase::OverrideDestroyVideoSessionKHR( + PFN_vkDestroyVideoSessionKHR func, + const DeviceInfo* device_info, + VideoSessionKHRInfo* video_session_info, + const StructPointerDecoder* pAllocator) +{ + GFXRECON_UNREFERENCED_PARAMETER(func); + + GFXRECON_ASSERT(device_info != nullptr); + + auto allocator = device_info->allocator.get(); + GFXRECON_ASSERT(allocator != nullptr); + + VkVideoSessionKHR session = VK_NULL_HANDLE; + std::vector allocator_datas; + + if (video_session_info != nullptr) + { + session = video_session_info->handle; + allocator_datas = video_session_info->allocator_datas; + + video_session_info->allocator_datas.clear(); + } + + allocator->DestroyVideoSession(session, GetAllocationCallbacks(pAllocator), allocator_datas); +} + void VulkanReplayConsumerBase::OverrideGetImageSubresourceLayout( PFN_vkGetImageSubresourceLayout func, const DeviceInfo* device_info, diff --git a/framework/decode/vulkan_replay_consumer_base.h b/framework/decode/vulkan_replay_consumer_base.h index bab984123d..d1002b35b1 100644 --- a/framework/decode/vulkan_replay_consumer_base.h +++ b/framework/decode/vulkan_replay_consumer_base.h @@ -676,6 +676,14 @@ class VulkanReplayConsumerBase : public VulkanConsumer uint32_t bindInfoCount, const StructPointerDecoder* pBindInfos); + VkResult OverrideBindVideoSessionMemoryKHR( + PFN_vkBindVideoSessionMemoryKHR func, + VkResult original_result, + const DeviceInfo* device_info, + VideoSessionKHRInfo* video_session_info, + uint32_t bindSessionMemoryInfoCount, + StructPointerDecoder* pBindSessionMemoryInfos); + VkResult OverrideCreateBuffer(PFN_vkCreateBuffer func, VkResult original_result, const DeviceInfo* device_info, @@ -700,6 +708,18 @@ class VulkanReplayConsumerBase : public VulkanConsumer ImageInfo* image_info, const StructPointerDecoder* pAllocator); + VkResult OverrideCreateVideoSessionKHR(PFN_vkCreateVideoSessionKHR func, + VkResult original_result, + const DeviceInfo* device_info, + const StructPointerDecoder* pCreateInfo, + const StructPointerDecoder* pAllocator, + HandlePointerDecoder* pVideoSession); + + void OverrideDestroyVideoSessionKHR(PFN_vkDestroyVideoSessionKHR func, + const DeviceInfo* device_info, + VideoSessionKHRInfo* video_session_info, + const StructPointerDecoder* pAllocator); + void OverrideGetImageSubresourceLayout(PFN_vkGetImageSubresourceLayout func, const DeviceInfo* device_info, const ImageInfo* image_info, diff --git a/framework/decode/vulkan_resource_allocator.h b/framework/decode/vulkan_resource_allocator.h index defc2cb850..b6578e4f48 100644 --- a/framework/decode/vulkan_resource_allocator.h +++ b/framework/decode/vulkan_resource_allocator.h @@ -68,11 +68,15 @@ class VulkanResourceAllocator PFN_vkCmdCopyBuffer cmd_copy_buffer{ nullptr }; PFN_vkCreateImage create_image{ nullptr }; PFN_vkDestroyImage destroy_image{ nullptr }; + PFN_vkCreateVideoSessionKHR create_video_session{ nullptr }; + PFN_vkDestroyVideoSessionKHR destroy_video_session{ nullptr }; PFN_vkGetImageMemoryRequirements get_image_memory_requirements{ nullptr }; PFN_vkGetImageMemoryRequirements2 get_image_memory_requirements2{ nullptr }; + PFN_vkGetVideoSessionMemoryRequirementsKHR get_video_session_memory_requirements{ nullptr }; PFN_vkGetImageSubresourceLayout get_image_subresource_layout{ nullptr }; PFN_vkBindImageMemory bind_image_memory{ nullptr }; PFN_vkBindImageMemory2 bind_image_memory2{ nullptr }; + PFN_vkBindVideoSessionMemoryKHR bind_video_session_memory{ nullptr }; PFN_vkGetInstanceProcAddr get_instance_proc_addr{ nullptr }; PFN_vkGetDeviceProcAddr get_device_proc_addr{ nullptr }; PFN_vkGetDeviceQueue get_device_queue{ nullptr }; @@ -122,6 +126,16 @@ class VulkanResourceAllocator virtual void DestroyImage(VkImage image, const VkAllocationCallbacks* allocation_callbacks, ResourceData allocator_data) = 0; + virtual VkResult CreateVideoSession(const VkVideoSessionCreateInfoKHR* create_info, + const VkAllocationCallbacks* allocation_callbacks, + format::HandleId capture_id, + VkVideoSessionKHR* session, + std::vector* allocator_datas) = 0; + + virtual void DestroyVideoSession(VkVideoSessionKHR session, + const VkAllocationCallbacks* allocation_callbacks, + std::vector allocator_datas) = 0; + virtual void GetImageSubresourceLayout(VkImage image, const VkImageSubresource* subresource, VkSubresourceLayout* layout, @@ -167,6 +181,13 @@ class VulkanResourceAllocator const MemoryData* allocator_memory_datas, VkMemoryPropertyFlags* bind_memory_properties) = 0; + virtual VkResult BindVideoSessionMemory(VkVideoSessionKHR video_session, + uint32_t bind_info_count, + const VkBindVideoSessionMemoryInfoKHR* bind_infos, + const ResourceData* allocator_session_datas, + const MemoryData* allocator_memory_datas, + VkMemoryPropertyFlags* bind_memory_properties) = 0; + virtual VkResult MapMemory(VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize size, @@ -208,6 +229,12 @@ class VulkanResourceAllocator const ResourceData* allocator_resource_datas, const MemoryData* allocator_memory_datas) = 0; + virtual void ReportBindVideoSessionIncompatibility(VkVideoSessionKHR video_session, + uint32_t bind_info_count, + const VkBindVideoSessionMemoryInfoKHR* bind_infos, + const ResourceData* allocator_resource_datas, + const MemoryData* allocator_memory_datas) = 0; + // Direct allocation methods that perform memory allocation and resource creation without performing memory // translation. These methods allow the replay tool to allocate staging resources through the resource allocator so // that the allocator is aware of all allocations performed at replay. diff --git a/framework/generated/generated_vulkan_replay_consumer.cpp b/framework/generated/generated_vulkan_replay_consumer.cpp index 59e1a406ce..d3fe968cd6 100644 --- a/framework/generated/generated_vulkan_replay_consumer.cpp +++ b/framework/generated/generated_vulkan_replay_consumer.cpp @@ -4126,16 +4126,15 @@ void VulkanReplayConsumer::Process_vkCreateVideoSessionKHR( StructPointerDecoder* pAllocator, HandlePointerDecoder* pVideoSession) { - VkDevice in_device = MapHandle(device, &VulkanObjectInfoTable::GetDeviceInfo); - const VkVideoSessionCreateInfoKHR* in_pCreateInfo = pCreateInfo->GetPointer(); - const VkAllocationCallbacks* in_pAllocator = GetAllocationCallbacks(pAllocator); + auto in_device = GetObjectInfoTable().GetDeviceInfo(device); if (!pVideoSession->IsNull()) { pVideoSession->SetHandleLength(1); } - VkVideoSessionKHR* out_pVideoSession = pVideoSession->GetHandlePointer(); + VideoSessionKHRInfo handle_info; + pVideoSession->SetConsumerData(0, &handle_info); - VkResult replay_result = GetDeviceTable(in_device)->CreateVideoSessionKHR(in_device, in_pCreateInfo, in_pAllocator, out_pVideoSession); + VkResult replay_result = OverrideCreateVideoSessionKHR(GetDeviceTable(in_device->handle)->CreateVideoSessionKHR, returnValue, in_device, pCreateInfo, pAllocator, pVideoSession); CheckResult("vkCreateVideoSessionKHR", returnValue, replay_result, call_info); - AddHandle(device, pVideoSession->GetPointer(), out_pVideoSession, &VulkanObjectInfoTable::AddVideoSessionKHRInfo); + AddHandle(device, pVideoSession->GetPointer(), pVideoSession->GetHandlePointer(), std::move(handle_info), &VulkanObjectInfoTable::AddVideoSessionKHRInfo); } void VulkanReplayConsumer::Process_vkDestroyVideoSessionKHR( @@ -4144,11 +4143,10 @@ void VulkanReplayConsumer::Process_vkDestroyVideoSessionKHR( format::HandleId videoSession, StructPointerDecoder* pAllocator) { - VkDevice in_device = MapHandle(device, &VulkanObjectInfoTable::GetDeviceInfo); - VkVideoSessionKHR in_videoSession = MapHandle(videoSession, &VulkanObjectInfoTable::GetVideoSessionKHRInfo); - const VkAllocationCallbacks* in_pAllocator = GetAllocationCallbacks(pAllocator); + auto in_device = GetObjectInfoTable().GetDeviceInfo(device); + auto in_videoSession = GetObjectInfoTable().GetVideoSessionKHRInfo(videoSession); - GetDeviceTable(in_device)->DestroyVideoSessionKHR(in_device, in_videoSession, in_pAllocator); + OverrideDestroyVideoSessionKHR(GetDeviceTable(in_device->handle)->DestroyVideoSessionKHR, in_device, in_videoSession, pAllocator); RemoveHandle(videoSession, &VulkanObjectInfoTable::RemoveVideoSessionKHRInfo); } @@ -4179,12 +4177,12 @@ void VulkanReplayConsumer::Process_vkBindVideoSessionMemoryKHR( uint32_t bindSessionMemoryInfoCount, StructPointerDecoder* pBindSessionMemoryInfos) { - VkDevice in_device = MapHandle(device, &VulkanObjectInfoTable::GetDeviceInfo); - VkVideoSessionKHR in_videoSession = MapHandle(videoSession, &VulkanObjectInfoTable::GetVideoSessionKHRInfo); - const VkBindVideoSessionMemoryInfoKHR* in_pBindSessionMemoryInfos = pBindSessionMemoryInfos->GetPointer(); + auto in_device = GetObjectInfoTable().GetDeviceInfo(device); + auto in_videoSession = GetObjectInfoTable().GetVideoSessionKHRInfo(videoSession); + MapStructArrayHandles(pBindSessionMemoryInfos->GetMetaStructPointer(), pBindSessionMemoryInfos->GetLength(), GetObjectInfoTable()); - VkResult replay_result = GetDeviceTable(in_device)->BindVideoSessionMemoryKHR(in_device, in_videoSession, bindSessionMemoryInfoCount, in_pBindSessionMemoryInfos); + VkResult replay_result = OverrideBindVideoSessionMemoryKHR(GetDeviceTable(in_device->handle)->BindVideoSessionMemoryKHR, returnValue, in_device, in_videoSession, bindSessionMemoryInfoCount, pBindSessionMemoryInfos); CheckResult("vkBindVideoSessionMemoryKHR", returnValue, replay_result, call_info); } diff --git a/framework/generated/vulkan_generators/replay_overrides.json b/framework/generated/vulkan_generators/replay_overrides.json index 57302d087d..e17b466776 100644 --- a/framework/generated/vulkan_generators/replay_overrides.json +++ b/framework/generated/vulkan_generators/replay_overrides.json @@ -114,6 +114,9 @@ "vkCmdInsertDebugUtilsLabelEXT": "OverrideCmdInsertDebugUtilsLabelEXT", "vkUpdateDescriptorSets": "OverrideUpdateDescriptorSets", "vkCreateGraphicsPipelines": "OverrideCreateGraphicsPipelines", - "vkCreateComputePipelines": "OverrideCreateComputePipelines" + "vkCreateComputePipelines": "OverrideCreateComputePipelines", + "vkCreateVideoSessionKHR": "OverrideCreateVideoSessionKHR", + "vkDestroyVideoSessionKHR": "OverrideDestroyVideoSessionKHR", + "vkBindVideoSessionMemoryKHR": "OverrideBindVideoSessionMemoryKHR" } } From 959267c77b8b069443998aac5371600863690a70 Mon Sep 17 00:00:00 2001 From: Locke Lin Date: Mon, 8 Jul 2024 18:10:36 -0600 Subject: [PATCH 2/3] Fill VMA unsupported part VMA doesn't support VideoSession See https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator/issues/307 We need to do the unsupported part ourselves. --- .../include/vk_mem_alloc.h | 3 + framework/decode/vulkan_rebind_allocator.cpp | 157 +++++++++++++++++- 2 files changed, 159 insertions(+), 1 deletion(-) diff --git a/external/VulkanMemoryAllocator/include/vk_mem_alloc.h b/external/VulkanMemoryAllocator/include/vk_mem_alloc.h index 2307325d4e..25ca080bb3 100644 --- a/external/VulkanMemoryAllocator/include/vk_mem_alloc.h +++ b/external/VulkanMemoryAllocator/include/vk_mem_alloc.h @@ -6144,6 +6144,7 @@ class VmaDeviceMemoryBlock VmaPool m_hParentPool; // VK_NULL_HANDLE if not belongs to custom pool. uint32_t m_MemoryTypeIndex; uint32_t m_Id; +public: VkDeviceMemory m_hMemory; /* @@ -6151,7 +6152,9 @@ class VmaDeviceMemoryBlock Also protects m_MapCount, m_pMappedData. Allocations, deallocations, any change in m_pMetadata is protected by parent's VmaBlockVector::m_Mutex. */ +public: VMA_MUTEX m_MapAndBindMutex; +private: VmaMappingHysteresis m_MappingHysteresis; uint32_t m_MapCount; void* m_pMappedData; diff --git a/framework/decode/vulkan_rebind_allocator.cpp b/framework/decode/vulkan_rebind_allocator.cpp index 2cee081bb1..228bf1c161 100644 --- a/framework/decode/vulkan_rebind_allocator.cpp +++ b/framework/decode/vulkan_rebind_allocator.cpp @@ -393,6 +393,36 @@ void VulkanRebindAllocator::DestroyVideoSession(VkVideoSessionKHR ses std::vector allocator_datas) { // TODO: VMA doesn't support video session(vmaDestroyVideoSession). Do it ourselves until VMA support it. + GFXRECON_UNREFERENCED_PARAMETER(allocation_callbacks); + + uint32_t index = 0; + for (auto& allocator_data : allocator_datas) + { + if (allocator_data != 0) + { + auto resource_alloc_info = reinterpret_cast(allocator_data); + auto memory_alloc_info = resource_alloc_info->memory_info; + + if (memory_alloc_info != nullptr) + { + memory_alloc_info->original_sessions.erase(session); + } + + if (resource_alloc_info->allocation != VK_NULL_HANDLE) + { + if (resource_alloc_info->mapped_pointer != nullptr) + { + vmaUnmapMemory(allocator_, resource_alloc_info->allocation); + } + allocator_->FreeMemory(1, &resource_alloc_info->allocation); + } + delete resource_alloc_info; + } + ++index; + } + allocator_datas.clear(); + GFXRECON_ASSERT(session != VK_NULL_HANDLE); + functions_.destroy_video_session(allocator_->m_hDevice, session, allocator_->GetAllocationCallbacks()); } void VulkanRebindAllocator::GetImageSubresourceLayout(VkImage image, @@ -843,7 +873,132 @@ VkResult VulkanRebindAllocator::BindVideoSessionMemory(VkVideoSessionKHR { // TODO: VMA doesn't support video session(vmaAllocateMemoryForVideoSession and vmaBindVideoSessionMemory). // Do it ourselves until VMA support it. - return VK_ERROR_INITIALIZATION_FAILED; + VkResult result = VK_ERROR_INITIALIZATION_FAILED; + + if ((video_session != VK_NULL_HANDLE) && (bind_infos != nullptr) && (allocator_session_datas != nullptr) && + (allocator_memory_datas != nullptr) && (bind_memory_properties != nullptr)) + { + uint32_t session_requirements_count = 0; + functions_.get_video_session_memory_requirements(device_, video_session, &session_requirements_count, nullptr); + + VkVideoSessionMemoryRequirementsKHR reqs = {}; + reqs.sType = VK_STRUCTURE_TYPE_VIDEO_SESSION_MEMORY_REQUIREMENTS_KHR; + std::vector session_requirements(session_requirements_count, reqs); + functions_.get_video_session_memory_requirements( + device_, video_session, &session_requirements_count, session_requirements.data()); + + for (uint32_t i = 0; i < bind_info_count; ++i) + { + uint32_t mem_index = bind_infos[i].memoryBindIndex; + uintptr_t allocator_session_data = allocator_session_datas[mem_index]; + uintptr_t allocator_memory_data = allocator_memory_datas[mem_index]; + + if ((allocator_session_data != 0) && (allocator_memory_data != 0)) + { + VmaAllocation allocation = VK_NULL_HANDLE; + auto resource_alloc_info = reinterpret_cast(allocator_session_data); + auto memory_alloc_info = reinterpret_cast(allocator_memory_data); + + VmaAllocationCreateInfo create_info; + create_info.flags = 0; + create_info.usage = GetVideoSeesionMemoryUsage( + capture_memory_properties_.memoryTypes[memory_alloc_info->original_index].propertyFlags, + session_requirements[mem_index].memoryRequirements); + create_info.requiredFlags = 0; + create_info.preferredFlags = 0; + create_info.memoryTypeBits = 0; + create_info.pool = VK_NULL_HANDLE; + create_info.pUserData = nullptr; + + VmaAllocationInfo allocation_info; + result = allocator_->AllocateMemory(session_requirements[mem_index].memoryRequirements, + false, + false, + VK_NULL_HANDLE, // dedicatedBuffer + VK_NULL_HANDLE, // dedicatedImage + VmaBufferImageUsage::UNKNOWN, // dedicatedBufferImageUsage + create_info, + VMA_SUBALLOCATION_TYPE_FREE, + 1, // allocationCount + &allocation); + + if (result == VK_SUCCESS) + { + allocator_->GetAllocationInfo(allocation, &allocation_info); + } + + if (result >= 0) + { + auto bind_info = &bind_infos[i]; + auto modified_bind_info = *bind_info; + + switch (allocation->GetType()) + { + case VmaAllocation_T::ALLOCATION_TYPE_DEDICATED: + { + modified_bind_info.memory = allocation->GetMemory(); + result = + functions_.bind_video_session_memory(device_, video_session, 1, &modified_bind_info); + break; + } + case VmaAllocation_T::ALLOCATION_TYPE_BLOCK: + { + VmaDeviceMemoryBlock* const pBlock = allocation->GetBlock(); + VMA_ASSERT(pBlock && + "Binding Video Seesion to allocation that doesn't belong to any block."); + + // This lock is important so that we don't call vkBind... and/or vkMap... simultaneously + // on the same VkDeviceMemory from multiple threads. + VmaMutexLock lock(pBlock->m_MapAndBindMutex, allocator_->m_UseMutex); + modified_bind_info.memory = pBlock->m_hMemory; + modified_bind_info.memoryOffset += allocation->GetOffset(); + result = + functions_.bind_video_session_memory(device_, video_session, 1, &modified_bind_info); + break; + } + default: + VMA_ASSERT(0); + } + + if (result >= 0) + { + resource_alloc_info->allocation = allocation; + resource_alloc_info->mapped_pointer = nullptr; + resource_alloc_info->memory_info = memory_alloc_info; + resource_alloc_info->original_offset = bind_info->memoryOffset; + resource_alloc_info->rebind_offset = allocation_info.offset; + resource_alloc_info->size = allocation_info.size; + + VkMemoryPropertyFlags property_flags = + replay_memory_properties_.memoryTypes[allocation_info.memoryType].propertyFlags; + + if ((property_flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) + { + resource_alloc_info->is_host_visible = true; + } + + if (memory_alloc_info->original_content != nullptr) + { + // Memory has been mapped and written prior to bind. Copy the original content to the new + // allocation to ensure it contains the correct data. + WriteBoundResource(resource_alloc_info, + bind_info->memoryOffset, + 0, + allocation_info.size, + memory_alloc_info->original_content.get()); + } + + memory_alloc_info->original_sessions.insert(std::make_pair(video_session, resource_alloc_info)); + + bind_memory_properties[i] = property_flags; + } + } + } + } + } + + return result; } VkResult VulkanRebindAllocator::MapMemory(VkDeviceMemory memory, From ee58b7c4037df321213b0e52fcda5cefdd7398ec Mon Sep 17 00:00:00 2001 From: Locke Lin Date: Thu, 11 Jul 2024 17:33:50 -0600 Subject: [PATCH 3/3] Use replay MemoryRequirements of VideoSession replay MemoryRequirements could have different count and size. Depend on device, driver, and queue. Some have one big MemoryRequirements. Some have plural small. Use replay MemoryRequirements to AllocateMemory and Bind on RebindAllocator. --- framework/decode/vulkan_default_allocator.h | 2 + framework/decode/vulkan_rebind_allocator.cpp | 51 ++++++++++++++----- framework/decode/vulkan_rebind_allocator.h | 1 + .../decode/vulkan_replay_consumer_base.cpp | 37 ++++++++------ framework/decode/vulkan_resource_allocator.h | 1 + 5 files changed, 64 insertions(+), 28 deletions(-) diff --git a/framework/decode/vulkan_default_allocator.h b/framework/decode/vulkan_default_allocator.h index 935811f2cd..4fb13f6c54 100644 --- a/framework/decode/vulkan_default_allocator.h +++ b/framework/decode/vulkan_default_allocator.h @@ -274,6 +274,8 @@ class VulkanDefaultAllocator : public VulkanResourceAllocator virtual bool SupportsOpaqueDeviceAddresses() override { return true; } + virtual bool SupportBindVideoSessionMemory() override { return false; } + protected: struct ResourceAllocInfo { diff --git a/framework/decode/vulkan_rebind_allocator.cpp b/framework/decode/vulkan_rebind_allocator.cpp index 228bf1c161..38e64ac063 100644 --- a/framework/decode/vulkan_rebind_allocator.cpp +++ b/framework/decode/vulkan_rebind_allocator.cpp @@ -887,23 +887,32 @@ VkResult VulkanRebindAllocator::BindVideoSessionMemory(VkVideoSessionKHR functions_.get_video_session_memory_requirements( device_, video_session, &session_requirements_count, session_requirements.data()); - for (uint32_t i = 0; i < bind_info_count; ++i) + // Use replay MemoryRequeirements to AllocateMemory and Bind. + for (uint32_t mem_index = 0; mem_index < session_requirements_count; ++mem_index) { - uint32_t mem_index = bind_infos[i].memoryBindIndex; uintptr_t allocator_session_data = allocator_session_datas[mem_index]; uintptr_t allocator_memory_data = allocator_memory_datas[mem_index]; - if ((allocator_session_data != 0) && (allocator_memory_data != 0)) + if (allocator_session_data != 0) { VmaAllocation allocation = VK_NULL_HANDLE; auto resource_alloc_info = reinterpret_cast(allocator_session_data); - auto memory_alloc_info = reinterpret_cast(allocator_memory_data); + // if allocator_memory_data is 0, it means replay MemoryRequirements has more count. + MemoryAllocInfo* memory_alloc_info = (allocator_memory_data == 0) + ? new MemoryAllocInfo + : reinterpret_cast(allocator_memory_data); + auto requirements = session_requirements[mem_index].memoryRequirements; + if (allocator_memory_data == 0) + { + memory_alloc_info->allocation_size = requirements.size; + memory_alloc_info->original_index = requirements.memoryTypeBits; + } VmaAllocationCreateInfo create_info; create_info.flags = 0; create_info.usage = GetVideoSeesionMemoryUsage( capture_memory_properties_.memoryTypes[memory_alloc_info->original_index].propertyFlags, - session_requirements[mem_index].memoryRequirements); + requirements); create_info.requiredFlags = 0; create_info.preferredFlags = 0; create_info.memoryTypeBits = 0; @@ -929,8 +938,11 @@ VkResult VulkanRebindAllocator::BindVideoSessionMemory(VkVideoSessionKHR if (result >= 0) { - auto bind_info = &bind_infos[i]; - auto modified_bind_info = *bind_info; + VkBindVideoSessionMemoryInfoKHR modified_bind_info{}; + modified_bind_info.sType = VK_STRUCTURE_TYPE_BIND_VIDEO_SESSION_MEMORY_INFO_KHR; + modified_bind_info.memoryBindIndex = mem_index; + modified_bind_info.memoryOffset = 0; + modified_bind_info.memorySize = session_requirements[mem_index].memoryRequirements.size; switch (allocation->GetType()) { @@ -962,10 +974,23 @@ VkResult VulkanRebindAllocator::BindVideoSessionMemory(VkVideoSessionKHR if (result >= 0) { - resource_alloc_info->allocation = allocation; - resource_alloc_info->mapped_pointer = nullptr; - resource_alloc_info->memory_info = memory_alloc_info; - resource_alloc_info->original_offset = bind_info->memoryOffset; + resource_alloc_info->allocation = allocation; + resource_alloc_info->mapped_pointer = nullptr; + resource_alloc_info->memory_info = memory_alloc_info; + + // The new bind_infos's index and captured bind_infos's index meanings are different. + VkDeviceSize src_offset = 0; + + for (uint32_t i = 0; i < bind_info_count; ++i) + { + if (bind_infos[i].memoryBindIndex == mem_index) + { + src_offset = bind_infos[mem_index].memoryOffset; + break; + } + } + + resource_alloc_info->original_offset = src_offset; resource_alloc_info->rebind_offset = allocation_info.offset; resource_alloc_info->size = allocation_info.size; @@ -983,7 +1008,7 @@ VkResult VulkanRebindAllocator::BindVideoSessionMemory(VkVideoSessionKHR // Memory has been mapped and written prior to bind. Copy the original content to the new // allocation to ensure it contains the correct data. WriteBoundResource(resource_alloc_info, - bind_info->memoryOffset, + src_offset, 0, allocation_info.size, memory_alloc_info->original_content.get()); @@ -991,7 +1016,7 @@ VkResult VulkanRebindAllocator::BindVideoSessionMemory(VkVideoSessionKHR memory_alloc_info->original_sessions.insert(std::make_pair(video_session, resource_alloc_info)); - bind_memory_properties[i] = property_flags; + bind_memory_properties[mem_index] = property_flags; } } } diff --git a/framework/decode/vulkan_rebind_allocator.h b/framework/decode/vulkan_rebind_allocator.h index 556437b5ce..1c0549c365 100644 --- a/framework/decode/vulkan_rebind_allocator.h +++ b/framework/decode/vulkan_rebind_allocator.h @@ -305,6 +305,7 @@ class VulkanRebindAllocator : public VulkanResourceAllocator } virtual bool SupportsOpaqueDeviceAddresses() override { return false; } + virtual bool SupportBindVideoSessionMemory() override { return true; } private: struct MemoryAllocInfo; diff --git a/framework/decode/vulkan_replay_consumer_base.cpp b/framework/decode/vulkan_replay_consumer_base.cpp index a8f81f37e5..1faa6578c5 100644 --- a/framework/decode/vulkan_replay_consumer_base.cpp +++ b/framework/decode/vulkan_replay_consumer_base.cpp @@ -4631,6 +4631,15 @@ VkResult VulkanReplayConsumerBase::OverrideBindVideoSessionMemoryKHR( GFXRECON_ASSERT((device_info != nullptr) && (video_session_info != nullptr) && (pBindSessionMemoryInfos != nullptr)); + auto allocator = device_info->allocator.get(); + GFXRECON_ASSERT(allocator != nullptr); + + if (!allocator->SupportBindVideoSessionMemory()) + { + GFXRECON_LOG_WARNING_ONCE("The replay VideoSession's MemoryRequirements could be different, so replay may " + "fail. Try '-m rebind', if it fails."); + } + auto replay_bind_infos = pBindSessionMemoryInfos->GetPointer(); auto replay_bind_meta_infos = pBindSessionMemoryInfos->GetMetaStructPointer(); GFXRECON_ASSERT((replay_bind_infos != nullptr) && (replay_bind_meta_infos != nullptr)); @@ -4641,27 +4650,25 @@ VkResult VulkanReplayConsumerBase::OverrideBindVideoSessionMemoryKHR( std::vector allocator_memory_datas(session_mem_count, 0); std::vector memory_property_flags(session_mem_count, 0); - for (uint32_t i = 0; i < bindSessionMemoryInfoCount; ++i) + for (uint32_t mem_index = 0; mem_index < session_mem_count; ++mem_index) { - const auto* bind_meta_info = &replay_bind_meta_infos[i]; - auto mem_index = bind_meta_info->decoded_value->memoryBindIndex; - GFXRECON_ASSERT(mem_index < session_mem_count); - - auto memory_info = object_info_table_.GetDeviceMemoryInfo(bind_meta_info->memory); - - memory_infos.push_back(memory_info); - allocator_session_datas[mem_index] = video_session_info->allocator_datas[mem_index]; - if (memory_info != nullptr) + for (uint32_t i = 0; i < bindSessionMemoryInfoCount; ++i) { - allocator_memory_datas[mem_index] = memory_info->allocator_data; + const auto* bind_meta_info = &replay_bind_meta_infos[i]; + if (mem_index == bind_meta_info->decoded_value->memoryBindIndex) + { + auto memory_info = object_info_table_.GetDeviceMemoryInfo(bind_meta_info->memory); + memory_infos.push_back(memory_info); + + if (memory_info != nullptr) + { + allocator_memory_datas[mem_index] = memory_info->allocator_data; + } + } } } - - auto allocator = device_info->allocator.get(); - GFXRECON_ASSERT(allocator != nullptr); - VkResult result = allocator->BindVideoSessionMemory(video_session_info->handle, bindSessionMemoryInfoCount, replay_bind_infos, diff --git a/framework/decode/vulkan_resource_allocator.h b/framework/decode/vulkan_resource_allocator.h index b6578e4f48..fb29edf4fe 100644 --- a/framework/decode/vulkan_resource_allocator.h +++ b/framework/decode/vulkan_resource_allocator.h @@ -295,6 +295,7 @@ class VulkanResourceAllocator const MemoryData* allocator_datas) = 0; virtual bool SupportsOpaqueDeviceAddresses() = 0; + virtual bool SupportBindVideoSessionMemory() = 0; }; GFXRECON_END_NAMESPACE(decode)