diff options
Diffstat (limited to 'src')
19 files changed, 609 insertions, 554 deletions
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index 25a4b1c5b..7a20d3a79 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt | |||
| @@ -135,8 +135,6 @@ add_library(video_core STATIC | |||
| 135 | renderer_vulkan/vk_graphics_pipeline.h | 135 | renderer_vulkan/vk_graphics_pipeline.h |
| 136 | renderer_vulkan/vk_master_semaphore.cpp | 136 | renderer_vulkan/vk_master_semaphore.cpp |
| 137 | renderer_vulkan/vk_master_semaphore.h | 137 | renderer_vulkan/vk_master_semaphore.h |
| 138 | renderer_vulkan/vk_memory_manager.cpp | ||
| 139 | renderer_vulkan/vk_memory_manager.h | ||
| 140 | renderer_vulkan/vk_pipeline_cache.cpp | 138 | renderer_vulkan/vk_pipeline_cache.cpp |
| 141 | renderer_vulkan/vk_pipeline_cache.h | 139 | renderer_vulkan/vk_pipeline_cache.h |
| 142 | renderer_vulkan/vk_query_cache.cpp | 140 | renderer_vulkan/vk_query_cache.cpp |
| @@ -259,6 +257,8 @@ add_library(video_core STATIC | |||
| 259 | vulkan_common/vulkan_instance.h | 257 | vulkan_common/vulkan_instance.h |
| 260 | vulkan_common/vulkan_library.cpp | 258 | vulkan_common/vulkan_library.cpp |
| 261 | vulkan_common/vulkan_library.h | 259 | vulkan_common/vulkan_library.h |
| 260 | vulkan_common/vulkan_memory_allocator.cpp | ||
| 261 | vulkan_common/vulkan_memory_allocator.h | ||
| 262 | vulkan_common/vulkan_surface.cpp | 262 | vulkan_common/vulkan_surface.cpp |
| 263 | vulkan_common/vulkan_surface.h | 263 | vulkan_common/vulkan_surface.h |
| 264 | vulkan_common/vulkan_wrapper.cpp | 264 | vulkan_common/vulkan_wrapper.cpp |
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index d7437e185..61796e33a 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp | |||
| @@ -23,7 +23,6 @@ | |||
| 23 | #include "video_core/renderer_vulkan/renderer_vulkan.h" | 23 | #include "video_core/renderer_vulkan/renderer_vulkan.h" |
| 24 | #include "video_core/renderer_vulkan/vk_blit_screen.h" | 24 | #include "video_core/renderer_vulkan/vk_blit_screen.h" |
| 25 | #include "video_core/renderer_vulkan/vk_master_semaphore.h" | 25 | #include "video_core/renderer_vulkan/vk_master_semaphore.h" |
| 26 | #include "video_core/renderer_vulkan/vk_memory_manager.h" | ||
| 27 | #include "video_core/renderer_vulkan/vk_rasterizer.h" | 26 | #include "video_core/renderer_vulkan/vk_rasterizer.h" |
| 28 | #include "video_core/renderer_vulkan/vk_scheduler.h" | 27 | #include "video_core/renderer_vulkan/vk_scheduler.h" |
| 29 | #include "video_core/renderer_vulkan/vk_state_tracker.h" | 28 | #include "video_core/renderer_vulkan/vk_state_tracker.h" |
| @@ -32,6 +31,7 @@ | |||
| 32 | #include "video_core/vulkan_common/vulkan_device.h" | 31 | #include "video_core/vulkan_common/vulkan_device.h" |
| 33 | #include "video_core/vulkan_common/vulkan_instance.h" | 32 | #include "video_core/vulkan_common/vulkan_instance.h" |
| 34 | #include "video_core/vulkan_common/vulkan_library.h" | 33 | #include "video_core/vulkan_common/vulkan_library.h" |
| 34 | #include "video_core/vulkan_common/vulkan_memory_allocator.h" | ||
| 35 | #include "video_core/vulkan_common/vulkan_surface.h" | 35 | #include "video_core/vulkan_common/vulkan_surface.h" |
| 36 | #include "video_core/vulkan_common/vulkan_wrapper.h" | 36 | #include "video_core/vulkan_common/vulkan_wrapper.h" |
| 37 | 37 | ||
| @@ -137,7 +137,7 @@ bool RendererVulkan::Init() try { | |||
| 137 | InitializeDevice(); | 137 | InitializeDevice(); |
| 138 | Report(); | 138 | Report(); |
| 139 | 139 | ||
| 140 | memory_manager = std::make_unique<VKMemoryManager>(*device); | 140 | memory_allocator = std::make_unique<MemoryAllocator>(*device); |
| 141 | 141 | ||
| 142 | state_tracker = std::make_unique<StateTracker>(gpu); | 142 | state_tracker = std::make_unique<StateTracker>(gpu); |
| 143 | 143 | ||
| @@ -149,11 +149,11 @@ bool RendererVulkan::Init() try { | |||
| 149 | 149 | ||
| 150 | rasterizer = std::make_unique<RasterizerVulkan>(render_window, gpu, gpu.MemoryManager(), | 150 | rasterizer = std::make_unique<RasterizerVulkan>(render_window, gpu, gpu.MemoryManager(), |
| 151 | cpu_memory, screen_info, *device, | 151 | cpu_memory, screen_info, *device, |
| 152 | *memory_manager, *state_tracker, *scheduler); | 152 | *memory_allocator, *state_tracker, *scheduler); |
| 153 | 153 | ||
| 154 | blit_screen = | 154 | blit_screen = |
| 155 | std::make_unique<VKBlitScreen>(cpu_memory, render_window, *rasterizer, *device, | 155 | std::make_unique<VKBlitScreen>(cpu_memory, render_window, *rasterizer, *device, |
| 156 | *memory_manager, *swapchain, *scheduler, screen_info); | 156 | *memory_allocator, *swapchain, *scheduler, screen_info); |
| 157 | return true; | 157 | return true; |
| 158 | 158 | ||
| 159 | } catch (const vk::Exception& exception) { | 159 | } catch (const vk::Exception& exception) { |
| @@ -172,7 +172,7 @@ void RendererVulkan::ShutDown() { | |||
| 172 | blit_screen.reset(); | 172 | blit_screen.reset(); |
| 173 | scheduler.reset(); | 173 | scheduler.reset(); |
| 174 | swapchain.reset(); | 174 | swapchain.reset(); |
| 175 | memory_manager.reset(); | 175 | memory_allocator.reset(); |
| 176 | device.reset(); | 176 | device.reset(); |
| 177 | } | 177 | } |
| 178 | 178 | ||
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.h b/src/video_core/renderer_vulkan/renderer_vulkan.h index 5575ffc54..daf55b9b4 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.h +++ b/src/video_core/renderer_vulkan/renderer_vulkan.h | |||
| @@ -29,8 +29,8 @@ namespace Vulkan { | |||
| 29 | 29 | ||
| 30 | class Device; | 30 | class Device; |
| 31 | class StateTracker; | 31 | class StateTracker; |
| 32 | class MemoryAllocator; | ||
| 32 | class VKBlitScreen; | 33 | class VKBlitScreen; |
| 33 | class VKMemoryManager; | ||
| 34 | class VKSwapchain; | 34 | class VKSwapchain; |
| 35 | class VKScheduler; | 35 | class VKScheduler; |
| 36 | 36 | ||
| @@ -75,7 +75,7 @@ private: | |||
| 75 | 75 | ||
| 76 | vk::DebugUtilsMessenger debug_callback; | 76 | vk::DebugUtilsMessenger debug_callback; |
| 77 | std::unique_ptr<Device> device; | 77 | std::unique_ptr<Device> device; |
| 78 | std::unique_ptr<VKMemoryManager> memory_manager; | 78 | std::unique_ptr<MemoryAllocator> memory_allocator; |
| 79 | std::unique_ptr<StateTracker> state_tracker; | 79 | std::unique_ptr<StateTracker> state_tracker; |
| 80 | std::unique_ptr<VKScheduler> scheduler; | 80 | std::unique_ptr<VKScheduler> scheduler; |
| 81 | std::unique_ptr<VKSwapchain> swapchain; | 81 | std::unique_ptr<VKSwapchain> swapchain; |
diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.cpp b/src/video_core/renderer_vulkan/vk_blit_screen.cpp index 5e184eb42..3e3b895e0 100644 --- a/src/video_core/renderer_vulkan/vk_blit_screen.cpp +++ b/src/video_core/renderer_vulkan/vk_blit_screen.cpp | |||
| @@ -22,13 +22,13 @@ | |||
| 22 | #include "video_core/renderer_vulkan/renderer_vulkan.h" | 22 | #include "video_core/renderer_vulkan/renderer_vulkan.h" |
| 23 | #include "video_core/renderer_vulkan/vk_blit_screen.h" | 23 | #include "video_core/renderer_vulkan/vk_blit_screen.h" |
| 24 | #include "video_core/renderer_vulkan/vk_master_semaphore.h" | 24 | #include "video_core/renderer_vulkan/vk_master_semaphore.h" |
| 25 | #include "video_core/renderer_vulkan/vk_memory_manager.h" | ||
| 26 | #include "video_core/renderer_vulkan/vk_scheduler.h" | 25 | #include "video_core/renderer_vulkan/vk_scheduler.h" |
| 27 | #include "video_core/renderer_vulkan/vk_shader_util.h" | 26 | #include "video_core/renderer_vulkan/vk_shader_util.h" |
| 28 | #include "video_core/renderer_vulkan/vk_swapchain.h" | 27 | #include "video_core/renderer_vulkan/vk_swapchain.h" |
| 29 | #include "video_core/surface.h" | 28 | #include "video_core/surface.h" |
| 30 | #include "video_core/textures/decoders.h" | 29 | #include "video_core/textures/decoders.h" |
| 31 | #include "video_core/vulkan_common/vulkan_device.h" | 30 | #include "video_core/vulkan_common/vulkan_device.h" |
| 31 | #include "video_core/vulkan_common/vulkan_memory_allocator.h" | ||
| 32 | #include "video_core/vulkan_common/vulkan_wrapper.h" | 32 | #include "video_core/vulkan_common/vulkan_wrapper.h" |
| 33 | 33 | ||
| 34 | namespace Vulkan { | 34 | namespace Vulkan { |
| @@ -115,10 +115,10 @@ struct VKBlitScreen::BufferData { | |||
| 115 | VKBlitScreen::VKBlitScreen(Core::Memory::Memory& cpu_memory_, | 115 | VKBlitScreen::VKBlitScreen(Core::Memory::Memory& cpu_memory_, |
| 116 | Core::Frontend::EmuWindow& render_window_, | 116 | Core::Frontend::EmuWindow& render_window_, |
| 117 | VideoCore::RasterizerInterface& rasterizer_, const Device& device_, | 117 | VideoCore::RasterizerInterface& rasterizer_, const Device& device_, |
| 118 | VKMemoryManager& memory_manager_, VKSwapchain& swapchain_, | 118 | MemoryAllocator& memory_allocator_, VKSwapchain& swapchain_, |
| 119 | VKScheduler& scheduler_, const VKScreenInfo& screen_info_) | 119 | VKScheduler& scheduler_, const VKScreenInfo& screen_info_) |
| 120 | : cpu_memory{cpu_memory_}, render_window{render_window_}, rasterizer{rasterizer_}, | 120 | : cpu_memory{cpu_memory_}, render_window{render_window_}, rasterizer{rasterizer_}, |
| 121 | device{device_}, memory_manager{memory_manager_}, swapchain{swapchain_}, | 121 | device{device_}, memory_allocator{memory_allocator_}, swapchain{swapchain_}, |
| 122 | scheduler{scheduler_}, image_count{swapchain.GetImageCount()}, screen_info{screen_info_} { | 122 | scheduler{scheduler_}, image_count{swapchain.GetImageCount()}, screen_info{screen_info_} { |
| 123 | resource_ticks.resize(image_count); | 123 | resource_ticks.resize(image_count); |
| 124 | 124 | ||
| @@ -150,8 +150,8 @@ VkSemaphore VKBlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer, bool | |||
| 150 | SetUniformData(data, framebuffer); | 150 | SetUniformData(data, framebuffer); |
| 151 | SetVertexData(data, framebuffer); | 151 | SetVertexData(data, framebuffer); |
| 152 | 152 | ||
| 153 | auto map = buffer_commit->Map(); | 153 | const std::span<u8> map = buffer_commit.Map(); |
| 154 | std::memcpy(map.Address(), &data, sizeof(data)); | 154 | std::memcpy(map.data(), &data, sizeof(data)); |
| 155 | 155 | ||
| 156 | if (!use_accelerated) { | 156 | if (!use_accelerated) { |
| 157 | const u64 image_offset = GetRawImageOffset(framebuffer, image_index); | 157 | const u64 image_offset = GetRawImageOffset(framebuffer, image_index); |
| @@ -165,8 +165,8 @@ VkSemaphore VKBlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer, bool | |||
| 165 | constexpr u32 block_height_log2 = 4; | 165 | constexpr u32 block_height_log2 = 4; |
| 166 | const u32 bytes_per_pixel = GetBytesPerPixel(framebuffer); | 166 | const u32 bytes_per_pixel = GetBytesPerPixel(framebuffer); |
| 167 | Tegra::Texture::UnswizzleTexture( | 167 | Tegra::Texture::UnswizzleTexture( |
| 168 | std::span(map.Address() + image_offset, size_bytes), std::span(host_ptr, size_bytes), | 168 | map.subspan(image_offset, size_bytes), std::span(host_ptr, size_bytes), bytes_per_pixel, |
| 169 | bytes_per_pixel, framebuffer.width, framebuffer.height, 1, block_height_log2, 0); | 169 | framebuffer.width, framebuffer.height, 1, block_height_log2, 0); |
| 170 | 170 | ||
| 171 | const VkBufferImageCopy copy{ | 171 | const VkBufferImageCopy copy{ |
| 172 | .bufferOffset = image_offset, | 172 | .bufferOffset = image_offset, |
| @@ -224,8 +224,6 @@ VkSemaphore VKBlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer, bool | |||
| 224 | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, write_barrier); | 224 | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, write_barrier); |
| 225 | }); | 225 | }); |
| 226 | } | 226 | } |
| 227 | map.Release(); | ||
| 228 | |||
| 229 | scheduler.Record([renderpass = *renderpass, framebuffer = *framebuffers[image_index], | 227 | scheduler.Record([renderpass = *renderpass, framebuffer = *framebuffers[image_index], |
| 230 | descriptor_set = descriptor_sets[image_index], buffer = *buffer, | 228 | descriptor_set = descriptor_sets[image_index], buffer = *buffer, |
| 231 | size = swapchain.GetSize(), pipeline = *pipeline, | 229 | size = swapchain.GetSize(), pipeline = *pipeline, |
| @@ -642,7 +640,7 @@ void VKBlitScreen::ReleaseRawImages() { | |||
| 642 | raw_images.clear(); | 640 | raw_images.clear(); |
| 643 | raw_buffer_commits.clear(); | 641 | raw_buffer_commits.clear(); |
| 644 | buffer.reset(); | 642 | buffer.reset(); |
| 645 | buffer_commit.reset(); | 643 | buffer_commit = MemoryCommit{}; |
| 646 | } | 644 | } |
| 647 | 645 | ||
| 648 | void VKBlitScreen::CreateStagingBuffer(const Tegra::FramebufferConfig& framebuffer) { | 646 | void VKBlitScreen::CreateStagingBuffer(const Tegra::FramebufferConfig& framebuffer) { |
| @@ -659,7 +657,7 @@ void VKBlitScreen::CreateStagingBuffer(const Tegra::FramebufferConfig& framebuff | |||
| 659 | }; | 657 | }; |
| 660 | 658 | ||
| 661 | buffer = device.GetLogical().CreateBuffer(ci); | 659 | buffer = device.GetLogical().CreateBuffer(ci); |
| 662 | buffer_commit = memory_manager.Commit(buffer, true); | 660 | buffer_commit = memory_allocator.Commit(buffer, MemoryUsage::Upload); |
| 663 | } | 661 | } |
| 664 | 662 | ||
| 665 | void VKBlitScreen::CreateRawImages(const Tegra::FramebufferConfig& framebuffer) { | 663 | void VKBlitScreen::CreateRawImages(const Tegra::FramebufferConfig& framebuffer) { |
| @@ -690,7 +688,7 @@ void VKBlitScreen::CreateRawImages(const Tegra::FramebufferConfig& framebuffer) | |||
| 690 | .pQueueFamilyIndices = nullptr, | 688 | .pQueueFamilyIndices = nullptr, |
| 691 | .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, | 689 | .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, |
| 692 | }); | 690 | }); |
| 693 | raw_buffer_commits[i] = memory_manager.Commit(raw_images[i], false); | 691 | raw_buffer_commits[i] = memory_allocator.Commit(raw_images[i], MemoryUsage::DeviceLocal); |
| 694 | raw_image_views[i] = device.GetLogical().CreateImageView(VkImageViewCreateInfo{ | 692 | raw_image_views[i] = device.GetLogical().CreateImageView(VkImageViewCreateInfo{ |
| 695 | .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, | 693 | .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, |
| 696 | .pNext = nullptr, | 694 | .pNext = nullptr, |
diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.h b/src/video_core/renderer_vulkan/vk_blit_screen.h index 69ed61770..b52576957 100644 --- a/src/video_core/renderer_vulkan/vk_blit_screen.h +++ b/src/video_core/renderer_vulkan/vk_blit_screen.h | |||
| @@ -6,7 +6,7 @@ | |||
| 6 | 6 | ||
| 7 | #include <memory> | 7 | #include <memory> |
| 8 | 8 | ||
| 9 | #include "video_core/renderer_vulkan/vk_memory_manager.h" | 9 | #include "video_core/vulkan_common/vulkan_memory_allocator.h" |
| 10 | #include "video_core/vulkan_common/vulkan_wrapper.h" | 10 | #include "video_core/vulkan_common/vulkan_wrapper.h" |
| 11 | 11 | ||
| 12 | namespace Core { | 12 | namespace Core { |
| @@ -43,7 +43,7 @@ public: | |||
| 43 | explicit VKBlitScreen(Core::Memory::Memory& cpu_memory, | 43 | explicit VKBlitScreen(Core::Memory::Memory& cpu_memory, |
| 44 | Core::Frontend::EmuWindow& render_window, | 44 | Core::Frontend::EmuWindow& render_window, |
| 45 | VideoCore::RasterizerInterface& rasterizer, const Device& device, | 45 | VideoCore::RasterizerInterface& rasterizer, const Device& device, |
| 46 | VKMemoryManager& memory_manager, VKSwapchain& swapchain, | 46 | MemoryAllocator& memory_allocator, VKSwapchain& swapchain, |
| 47 | VKScheduler& scheduler, const VKScreenInfo& screen_info); | 47 | VKScheduler& scheduler, const VKScreenInfo& screen_info); |
| 48 | ~VKBlitScreen(); | 48 | ~VKBlitScreen(); |
| 49 | 49 | ||
| @@ -86,7 +86,7 @@ private: | |||
| 86 | Core::Frontend::EmuWindow& render_window; | 86 | Core::Frontend::EmuWindow& render_window; |
| 87 | VideoCore::RasterizerInterface& rasterizer; | 87 | VideoCore::RasterizerInterface& rasterizer; |
| 88 | const Device& device; | 88 | const Device& device; |
| 89 | VKMemoryManager& memory_manager; | 89 | MemoryAllocator& memory_allocator; |
| 90 | VKSwapchain& swapchain; | 90 | VKSwapchain& swapchain; |
| 91 | VKScheduler& scheduler; | 91 | VKScheduler& scheduler; |
| 92 | const std::size_t image_count; | 92 | const std::size_t image_count; |
| @@ -104,14 +104,14 @@ private: | |||
| 104 | vk::Sampler sampler; | 104 | vk::Sampler sampler; |
| 105 | 105 | ||
| 106 | vk::Buffer buffer; | 106 | vk::Buffer buffer; |
| 107 | VKMemoryCommit buffer_commit; | 107 | MemoryCommit buffer_commit; |
| 108 | 108 | ||
| 109 | std::vector<u64> resource_ticks; | 109 | std::vector<u64> resource_ticks; |
| 110 | 110 | ||
| 111 | std::vector<vk::Semaphore> semaphores; | 111 | std::vector<vk::Semaphore> semaphores; |
| 112 | std::vector<vk::Image> raw_images; | 112 | std::vector<vk::Image> raw_images; |
| 113 | std::vector<vk::ImageView> raw_image_views; | 113 | std::vector<vk::ImageView> raw_image_views; |
| 114 | std::vector<VKMemoryCommit> raw_buffer_commits; | 114 | std::vector<MemoryCommit> raw_buffer_commits; |
| 115 | u32 raw_width = 0; | 115 | u32 raw_width = 0; |
| 116 | u32 raw_height = 0; | 116 | u32 raw_height = 0; |
| 117 | }; | 117 | }; |
diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp index 58c710344..d8ad40a0f 100644 --- a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp | |||
| @@ -36,11 +36,11 @@ constexpr VkAccessFlags TRANSFORM_FEEDBACK_WRITE_ACCESS = | |||
| 36 | 36 | ||
| 37 | } // Anonymous namespace | 37 | } // Anonymous namespace |
| 38 | 38 | ||
| 39 | Buffer::Buffer(const Device& device_, VKMemoryManager& memory_manager, VKScheduler& scheduler_, | 39 | Buffer::Buffer(const Device& device_, MemoryAllocator& memory_allocator, VKScheduler& scheduler_, |
| 40 | VKStagingBufferPool& staging_pool_, VAddr cpu_addr_, std::size_t size_) | 40 | StagingBufferPool& staging_pool_, VAddr cpu_addr_, std::size_t size_) |
| 41 | : BufferBlock{cpu_addr_, size_}, device{device_}, scheduler{scheduler_}, staging_pool{ | 41 | : BufferBlock{cpu_addr_, size_}, device{device_}, scheduler{scheduler_}, staging_pool{ |
| 42 | staging_pool_} { | 42 | staging_pool_} { |
| 43 | const VkBufferCreateInfo ci{ | 43 | buffer = device.GetLogical().CreateBuffer(VkBufferCreateInfo{ |
| 44 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, | 44 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, |
| 45 | .pNext = nullptr, | 45 | .pNext = nullptr, |
| 46 | .flags = 0, | 46 | .flags = 0, |
| @@ -49,22 +49,20 @@ Buffer::Buffer(const Device& device_, VKMemoryManager& memory_manager, VKSchedul | |||
| 49 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, | 49 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, |
| 50 | .queueFamilyIndexCount = 0, | 50 | .queueFamilyIndexCount = 0, |
| 51 | .pQueueFamilyIndices = nullptr, | 51 | .pQueueFamilyIndices = nullptr, |
| 52 | }; | 52 | }); |
| 53 | 53 | commit = memory_allocator.Commit(buffer, MemoryUsage::DeviceLocal); | |
| 54 | buffer.handle = device.GetLogical().CreateBuffer(ci); | ||
| 55 | buffer.commit = memory_manager.Commit(buffer.handle, false); | ||
| 56 | } | 54 | } |
| 57 | 55 | ||
| 58 | Buffer::~Buffer() = default; | 56 | Buffer::~Buffer() = default; |
| 59 | 57 | ||
| 60 | void Buffer::Upload(std::size_t offset, std::size_t data_size, const u8* data) { | 58 | void Buffer::Upload(std::size_t offset, std::size_t data_size, const u8* data) { |
| 61 | const auto& staging = staging_pool.GetUnusedBuffer(data_size, true); | 59 | const auto& staging = staging_pool.Request(data_size, MemoryUsage::Upload); |
| 62 | std::memcpy(staging.commit->Map(data_size), data, data_size); | 60 | std::memcpy(staging.mapped_span.data(), data, data_size); |
| 63 | 61 | ||
| 64 | scheduler.RequestOutsideRenderPassOperationContext(); | 62 | scheduler.RequestOutsideRenderPassOperationContext(); |
| 65 | 63 | ||
| 66 | const VkBuffer handle = Handle(); | 64 | const VkBuffer handle = Handle(); |
| 67 | scheduler.Record([staging = *staging.handle, handle, offset, data_size, | 65 | scheduler.Record([staging = staging.buffer, handle, offset, data_size, |
| 68 | &device = device](vk::CommandBuffer cmdbuf) { | 66 | &device = device](vk::CommandBuffer cmdbuf) { |
| 69 | const VkBufferMemoryBarrier read_barrier{ | 67 | const VkBufferMemoryBarrier read_barrier{ |
| 70 | .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, | 68 | .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, |
| @@ -100,12 +98,12 @@ void Buffer::Upload(std::size_t offset, std::size_t data_size, const u8* data) { | |||
| 100 | } | 98 | } |
| 101 | 99 | ||
| 102 | void Buffer::Download(std::size_t offset, std::size_t data_size, u8* data) { | 100 | void Buffer::Download(std::size_t offset, std::size_t data_size, u8* data) { |
| 103 | const auto& staging = staging_pool.GetUnusedBuffer(data_size, true); | 101 | auto staging = staging_pool.Request(data_size, MemoryUsage::Download); |
| 104 | scheduler.RequestOutsideRenderPassOperationContext(); | 102 | scheduler.RequestOutsideRenderPassOperationContext(); |
| 105 | 103 | ||
| 106 | const VkBuffer handle = Handle(); | 104 | const VkBuffer handle = Handle(); |
| 107 | scheduler.Record( | 105 | scheduler.Record( |
| 108 | [staging = *staging.handle, handle, offset, data_size](vk::CommandBuffer cmdbuf) { | 106 | [staging = staging.buffer, handle, offset, data_size](vk::CommandBuffer cmdbuf) { |
| 109 | const VkBufferMemoryBarrier barrier{ | 107 | const VkBufferMemoryBarrier barrier{ |
| 110 | .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, | 108 | .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, |
| 111 | .pNext = nullptr, | 109 | .pNext = nullptr, |
| @@ -126,7 +124,7 @@ void Buffer::Download(std::size_t offset, std::size_t data_size, u8* data) { | |||
| 126 | }); | 124 | }); |
| 127 | scheduler.Finish(); | 125 | scheduler.Finish(); |
| 128 | 126 | ||
| 129 | std::memcpy(data, staging.commit->Map(data_size), data_size); | 127 | std::memcpy(data, staging.mapped_span.data(), data_size); |
| 130 | } | 128 | } |
| 131 | 129 | ||
| 132 | void Buffer::CopyFrom(const Buffer& src, std::size_t src_offset, std::size_t dst_offset, | 130 | void Buffer::CopyFrom(const Buffer& src, std::size_t src_offset, std::size_t dst_offset, |
| @@ -164,29 +162,29 @@ void Buffer::CopyFrom(const Buffer& src, std::size_t src_offset, std::size_t dst | |||
| 164 | 162 | ||
| 165 | VKBufferCache::VKBufferCache(VideoCore::RasterizerInterface& rasterizer_, | 163 | VKBufferCache::VKBufferCache(VideoCore::RasterizerInterface& rasterizer_, |
| 166 | Tegra::MemoryManager& gpu_memory_, Core::Memory::Memory& cpu_memory_, | 164 | Tegra::MemoryManager& gpu_memory_, Core::Memory::Memory& cpu_memory_, |
| 167 | const Device& device_, VKMemoryManager& memory_manager_, | 165 | const Device& device_, MemoryAllocator& memory_allocator_, |
| 168 | VKScheduler& scheduler_, VKStreamBuffer& stream_buffer_, | 166 | VKScheduler& scheduler_, VKStreamBuffer& stream_buffer_, |
| 169 | VKStagingBufferPool& staging_pool_) | 167 | StagingBufferPool& staging_pool_) |
| 170 | : VideoCommon::BufferCache<Buffer, VkBuffer, VKStreamBuffer>{rasterizer_, gpu_memory_, | 168 | : VideoCommon::BufferCache<Buffer, VkBuffer, VKStreamBuffer>{rasterizer_, gpu_memory_, |
| 171 | cpu_memory_, stream_buffer_}, | 169 | cpu_memory_, stream_buffer_}, |
| 172 | device{device_}, memory_manager{memory_manager_}, scheduler{scheduler_}, staging_pool{ | 170 | device{device_}, memory_allocator{memory_allocator_}, scheduler{scheduler_}, |
| 173 | staging_pool_} {} | 171 | staging_pool{staging_pool_} {} |
| 174 | 172 | ||
| 175 | VKBufferCache::~VKBufferCache() = default; | 173 | VKBufferCache::~VKBufferCache() = default; |
| 176 | 174 | ||
| 177 | std::shared_ptr<Buffer> VKBufferCache::CreateBlock(VAddr cpu_addr, std::size_t size) { | 175 | std::shared_ptr<Buffer> VKBufferCache::CreateBlock(VAddr cpu_addr, std::size_t size) { |
| 178 | return std::make_shared<Buffer>(device, memory_manager, scheduler, staging_pool, cpu_addr, | 176 | return std::make_shared<Buffer>(device, memory_allocator, scheduler, staging_pool, cpu_addr, |
| 179 | size); | 177 | size); |
| 180 | } | 178 | } |
| 181 | 179 | ||
| 182 | VKBufferCache::BufferInfo VKBufferCache::GetEmptyBuffer(std::size_t size) { | 180 | VKBufferCache::BufferInfo VKBufferCache::GetEmptyBuffer(std::size_t size) { |
| 183 | size = std::max(size, std::size_t(4)); | 181 | size = std::max(size, std::size_t(4)); |
| 184 | const auto& empty = staging_pool.GetUnusedBuffer(size, false); | 182 | const auto& empty = staging_pool.Request(size, MemoryUsage::DeviceLocal); |
| 185 | scheduler.RequestOutsideRenderPassOperationContext(); | 183 | scheduler.RequestOutsideRenderPassOperationContext(); |
| 186 | scheduler.Record([size, buffer = *empty.handle](vk::CommandBuffer cmdbuf) { | 184 | scheduler.Record([size, buffer = empty.buffer](vk::CommandBuffer cmdbuf) { |
| 187 | cmdbuf.FillBuffer(buffer, 0, size, 0); | 185 | cmdbuf.FillBuffer(buffer, 0, size, 0); |
| 188 | }); | 186 | }); |
| 189 | return {*empty.handle, 0, 0}; | 187 | return {empty.buffer, 0, 0}; |
| 190 | } | 188 | } |
| 191 | 189 | ||
| 192 | } // namespace Vulkan | 190 | } // namespace Vulkan |
diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.h b/src/video_core/renderer_vulkan/vk_buffer_cache.h index 1c39aed34..41d577510 100644 --- a/src/video_core/renderer_vulkan/vk_buffer_cache.h +++ b/src/video_core/renderer_vulkan/vk_buffer_cache.h | |||
| @@ -8,21 +8,20 @@ | |||
| 8 | 8 | ||
| 9 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| 10 | #include "video_core/buffer_cache/buffer_cache.h" | 10 | #include "video_core/buffer_cache/buffer_cache.h" |
| 11 | #include "video_core/renderer_vulkan/vk_memory_manager.h" | ||
| 12 | #include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" | 11 | #include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" |
| 13 | #include "video_core/renderer_vulkan/vk_stream_buffer.h" | 12 | #include "video_core/renderer_vulkan/vk_stream_buffer.h" |
| 13 | #include "video_core/vulkan_common/vulkan_memory_allocator.h" | ||
| 14 | #include "video_core/vulkan_common/vulkan_wrapper.h" | 14 | #include "video_core/vulkan_common/vulkan_wrapper.h" |
| 15 | 15 | ||
| 16 | namespace Vulkan { | 16 | namespace Vulkan { |
| 17 | 17 | ||
| 18 | class Device; | 18 | class Device; |
| 19 | class VKMemoryManager; | ||
| 20 | class VKScheduler; | 19 | class VKScheduler; |
| 21 | 20 | ||
| 22 | class Buffer final : public VideoCommon::BufferBlock { | 21 | class Buffer final : public VideoCommon::BufferBlock { |
| 23 | public: | 22 | public: |
| 24 | explicit Buffer(const Device& device, VKMemoryManager& memory_manager, VKScheduler& scheduler, | 23 | explicit Buffer(const Device& device, MemoryAllocator& memory_allocator, VKScheduler& scheduler, |
| 25 | VKStagingBufferPool& staging_pool, VAddr cpu_addr_, std::size_t size_); | 24 | StagingBufferPool& staging_pool, VAddr cpu_addr_, std::size_t size_); |
| 26 | ~Buffer(); | 25 | ~Buffer(); |
| 27 | 26 | ||
| 28 | void Upload(std::size_t offset, std::size_t data_size, const u8* data); | 27 | void Upload(std::size_t offset, std::size_t data_size, const u8* data); |
| @@ -33,7 +32,7 @@ public: | |||
| 33 | std::size_t copy_size); | 32 | std::size_t copy_size); |
| 34 | 33 | ||
| 35 | VkBuffer Handle() const { | 34 | VkBuffer Handle() const { |
| 36 | return *buffer.handle; | 35 | return *buffer; |
| 37 | } | 36 | } |
| 38 | 37 | ||
| 39 | u64 Address() const { | 38 | u64 Address() const { |
| @@ -43,18 +42,19 @@ public: | |||
| 43 | private: | 42 | private: |
| 44 | const Device& device; | 43 | const Device& device; |
| 45 | VKScheduler& scheduler; | 44 | VKScheduler& scheduler; |
| 46 | VKStagingBufferPool& staging_pool; | 45 | StagingBufferPool& staging_pool; |
| 47 | 46 | ||
| 48 | VKBuffer buffer; | 47 | vk::Buffer buffer; |
| 48 | MemoryCommit commit; | ||
| 49 | }; | 49 | }; |
| 50 | 50 | ||
| 51 | class VKBufferCache final : public VideoCommon::BufferCache<Buffer, VkBuffer, VKStreamBuffer> { | 51 | class VKBufferCache final : public VideoCommon::BufferCache<Buffer, VkBuffer, VKStreamBuffer> { |
| 52 | public: | 52 | public: |
| 53 | explicit VKBufferCache(VideoCore::RasterizerInterface& rasterizer, | 53 | explicit VKBufferCache(VideoCore::RasterizerInterface& rasterizer, |
| 54 | Tegra::MemoryManager& gpu_memory, Core::Memory::Memory& cpu_memory, | 54 | Tegra::MemoryManager& gpu_memory, Core::Memory::Memory& cpu_memory, |
| 55 | const Device& device, VKMemoryManager& memory_manager, | 55 | const Device& device, MemoryAllocator& memory_allocator, |
| 56 | VKScheduler& scheduler, VKStreamBuffer& stream_buffer, | 56 | VKScheduler& scheduler, VKStreamBuffer& stream_buffer, |
| 57 | VKStagingBufferPool& staging_pool); | 57 | StagingBufferPool& staging_pool); |
| 58 | ~VKBufferCache(); | 58 | ~VKBufferCache(); |
| 59 | 59 | ||
| 60 | BufferInfo GetEmptyBuffer(std::size_t size) override; | 60 | BufferInfo GetEmptyBuffer(std::size_t size) override; |
| @@ -64,9 +64,9 @@ protected: | |||
| 64 | 64 | ||
| 65 | private: | 65 | private: |
| 66 | const Device& device; | 66 | const Device& device; |
| 67 | VKMemoryManager& memory_manager; | 67 | MemoryAllocator& memory_allocator; |
| 68 | VKScheduler& scheduler; | 68 | VKScheduler& scheduler; |
| 69 | VKStagingBufferPool& staging_pool; | 69 | StagingBufferPool& staging_pool; |
| 70 | }; | 70 | }; |
| 71 | 71 | ||
| 72 | } // namespace Vulkan | 72 | } // namespace Vulkan |
diff --git a/src/video_core/renderer_vulkan/vk_compute_pass.cpp b/src/video_core/renderer_vulkan/vk_compute_pass.cpp index 02a6d54b7..5eb6a54be 100644 --- a/src/video_core/renderer_vulkan/vk_compute_pass.cpp +++ b/src/video_core/renderer_vulkan/vk_compute_pass.cpp | |||
| @@ -164,7 +164,7 @@ VkDescriptorSet VKComputePass::CommitDescriptorSet( | |||
| 164 | 164 | ||
| 165 | QuadArrayPass::QuadArrayPass(const Device& device_, VKScheduler& scheduler_, | 165 | QuadArrayPass::QuadArrayPass(const Device& device_, VKScheduler& scheduler_, |
| 166 | VKDescriptorPool& descriptor_pool_, | 166 | VKDescriptorPool& descriptor_pool_, |
| 167 | VKStagingBufferPool& staging_buffer_pool_, | 167 | StagingBufferPool& staging_buffer_pool_, |
| 168 | VKUpdateDescriptorQueue& update_descriptor_queue_) | 168 | VKUpdateDescriptorQueue& update_descriptor_queue_) |
| 169 | : VKComputePass(device_, descriptor_pool_, BuildQuadArrayPassDescriptorSetLayoutBinding(), | 169 | : VKComputePass(device_, descriptor_pool_, BuildQuadArrayPassDescriptorSetLayoutBinding(), |
| 170 | BuildQuadArrayPassDescriptorUpdateTemplateEntry(), | 170 | BuildQuadArrayPassDescriptorUpdateTemplateEntry(), |
| @@ -177,18 +177,18 @@ QuadArrayPass::~QuadArrayPass() = default; | |||
| 177 | std::pair<VkBuffer, VkDeviceSize> QuadArrayPass::Assemble(u32 num_vertices, u32 first) { | 177 | std::pair<VkBuffer, VkDeviceSize> QuadArrayPass::Assemble(u32 num_vertices, u32 first) { |
| 178 | const u32 num_triangle_vertices = (num_vertices / 4) * 6; | 178 | const u32 num_triangle_vertices = (num_vertices / 4) * 6; |
| 179 | const std::size_t staging_size = num_triangle_vertices * sizeof(u32); | 179 | const std::size_t staging_size = num_triangle_vertices * sizeof(u32); |
| 180 | auto& buffer = staging_buffer_pool.GetUnusedBuffer(staging_size, false); | 180 | const auto staging_ref = staging_buffer_pool.Request(staging_size, MemoryUsage::DeviceLocal); |
| 181 | 181 | ||
| 182 | update_descriptor_queue.Acquire(); | 182 | update_descriptor_queue.Acquire(); |
| 183 | update_descriptor_queue.AddBuffer(*buffer.handle, 0, staging_size); | 183 | update_descriptor_queue.AddBuffer(staging_ref.buffer, 0, staging_size); |
| 184 | const VkDescriptorSet set = CommitDescriptorSet(update_descriptor_queue); | 184 | const VkDescriptorSet set = CommitDescriptorSet(update_descriptor_queue); |
| 185 | 185 | ||
| 186 | scheduler.RequestOutsideRenderPassOperationContext(); | 186 | scheduler.RequestOutsideRenderPassOperationContext(); |
| 187 | 187 | ||
| 188 | ASSERT(num_vertices % 4 == 0); | 188 | ASSERT(num_vertices % 4 == 0); |
| 189 | const u32 num_quads = num_vertices / 4; | 189 | const u32 num_quads = num_vertices / 4; |
| 190 | scheduler.Record([layout = *layout, pipeline = *pipeline, buffer = *buffer.handle, num_quads, | 190 | scheduler.Record([layout = *layout, pipeline = *pipeline, buffer = staging_ref.buffer, |
| 191 | first, set](vk::CommandBuffer cmdbuf) { | 191 | num_quads, first, set](vk::CommandBuffer cmdbuf) { |
| 192 | constexpr u32 dispatch_size = 1024; | 192 | constexpr u32 dispatch_size = 1024; |
| 193 | cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE, pipeline); | 193 | cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE, pipeline); |
| 194 | cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_COMPUTE, layout, 0, set, {}); | 194 | cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_COMPUTE, layout, 0, set, {}); |
| @@ -208,11 +208,11 @@ std::pair<VkBuffer, VkDeviceSize> QuadArrayPass::Assemble(u32 num_vertices, u32 | |||
| 208 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, | 208 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, |
| 209 | VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, 0, {}, {barrier}, {}); | 209 | VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, 0, {}, {barrier}, {}); |
| 210 | }); | 210 | }); |
| 211 | return {*buffer.handle, 0}; | 211 | return {staging_ref.buffer, 0}; |
| 212 | } | 212 | } |
| 213 | 213 | ||
| 214 | Uint8Pass::Uint8Pass(const Device& device, VKScheduler& scheduler_, | 214 | Uint8Pass::Uint8Pass(const Device& device, VKScheduler& scheduler_, |
| 215 | VKDescriptorPool& descriptor_pool, VKStagingBufferPool& staging_buffer_pool_, | 215 | VKDescriptorPool& descriptor_pool, StagingBufferPool& staging_buffer_pool_, |
| 216 | VKUpdateDescriptorQueue& update_descriptor_queue_) | 216 | VKUpdateDescriptorQueue& update_descriptor_queue_) |
| 217 | : VKComputePass(device, descriptor_pool, BuildInputOutputDescriptorSetBindings(), | 217 | : VKComputePass(device, descriptor_pool, BuildInputOutputDescriptorSetBindings(), |
| 218 | BuildInputOutputDescriptorUpdateTemplate(), {}, VULKAN_UINT8_COMP_SPV), | 218 | BuildInputOutputDescriptorUpdateTemplate(), {}, VULKAN_UINT8_COMP_SPV), |
| @@ -224,15 +224,15 @@ Uint8Pass::~Uint8Pass() = default; | |||
| 224 | std::pair<VkBuffer, u64> Uint8Pass::Assemble(u32 num_vertices, VkBuffer src_buffer, | 224 | std::pair<VkBuffer, u64> Uint8Pass::Assemble(u32 num_vertices, VkBuffer src_buffer, |
| 225 | u64 src_offset) { | 225 | u64 src_offset) { |
| 226 | const u32 staging_size = static_cast<u32>(num_vertices * sizeof(u16)); | 226 | const u32 staging_size = static_cast<u32>(num_vertices * sizeof(u16)); |
| 227 | auto& buffer = staging_buffer_pool.GetUnusedBuffer(staging_size, false); | 227 | const auto staging_ref = staging_buffer_pool.Request(staging_size, MemoryUsage::DeviceLocal); |
| 228 | 228 | ||
| 229 | update_descriptor_queue.Acquire(); | 229 | update_descriptor_queue.Acquire(); |
| 230 | update_descriptor_queue.AddBuffer(src_buffer, src_offset, num_vertices); | 230 | update_descriptor_queue.AddBuffer(src_buffer, src_offset, num_vertices); |
| 231 | update_descriptor_queue.AddBuffer(*buffer.handle, 0, staging_size); | 231 | update_descriptor_queue.AddBuffer(staging_ref.buffer, 0, staging_size); |
| 232 | const VkDescriptorSet set = CommitDescriptorSet(update_descriptor_queue); | 232 | const VkDescriptorSet set = CommitDescriptorSet(update_descriptor_queue); |
| 233 | 233 | ||
| 234 | scheduler.RequestOutsideRenderPassOperationContext(); | 234 | scheduler.RequestOutsideRenderPassOperationContext(); |
| 235 | scheduler.Record([layout = *layout, pipeline = *pipeline, buffer = *buffer.handle, set, | 235 | scheduler.Record([layout = *layout, pipeline = *pipeline, buffer = staging_ref.buffer, set, |
| 236 | num_vertices](vk::CommandBuffer cmdbuf) { | 236 | num_vertices](vk::CommandBuffer cmdbuf) { |
| 237 | constexpr u32 dispatch_size = 1024; | 237 | constexpr u32 dispatch_size = 1024; |
| 238 | cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE, pipeline); | 238 | cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE, pipeline); |
| @@ -252,12 +252,12 @@ std::pair<VkBuffer, u64> Uint8Pass::Assemble(u32 num_vertices, VkBuffer src_buff | |||
| 252 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, | 252 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, |
| 253 | VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, 0, {}, barrier, {}); | 253 | VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, 0, {}, barrier, {}); |
| 254 | }); | 254 | }); |
| 255 | return {*buffer.handle, 0}; | 255 | return {staging_ref.buffer, 0}; |
| 256 | } | 256 | } |
| 257 | 257 | ||
| 258 | QuadIndexedPass::QuadIndexedPass(const Device& device_, VKScheduler& scheduler_, | 258 | QuadIndexedPass::QuadIndexedPass(const Device& device_, VKScheduler& scheduler_, |
| 259 | VKDescriptorPool& descriptor_pool_, | 259 | VKDescriptorPool& descriptor_pool_, |
| 260 | VKStagingBufferPool& staging_buffer_pool_, | 260 | StagingBufferPool& staging_buffer_pool_, |
| 261 | VKUpdateDescriptorQueue& update_descriptor_queue_) | 261 | VKUpdateDescriptorQueue& update_descriptor_queue_) |
| 262 | : VKComputePass(device_, descriptor_pool_, BuildInputOutputDescriptorSetBindings(), | 262 | : VKComputePass(device_, descriptor_pool_, BuildInputOutputDescriptorSetBindings(), |
| 263 | BuildInputOutputDescriptorUpdateTemplate(), | 263 | BuildInputOutputDescriptorUpdateTemplate(), |
| @@ -286,15 +286,15 @@ std::pair<VkBuffer, u64> QuadIndexedPass::Assemble( | |||
| 286 | const u32 num_tri_vertices = (num_vertices / 4) * 6; | 286 | const u32 num_tri_vertices = (num_vertices / 4) * 6; |
| 287 | 287 | ||
| 288 | const std::size_t staging_size = num_tri_vertices * sizeof(u32); | 288 | const std::size_t staging_size = num_tri_vertices * sizeof(u32); |
| 289 | auto& buffer = staging_buffer_pool.GetUnusedBuffer(staging_size, false); | 289 | const auto staging_ref = staging_buffer_pool.Request(staging_size, MemoryUsage::DeviceLocal); |
| 290 | 290 | ||
| 291 | update_descriptor_queue.Acquire(); | 291 | update_descriptor_queue.Acquire(); |
| 292 | update_descriptor_queue.AddBuffer(src_buffer, src_offset, input_size); | 292 | update_descriptor_queue.AddBuffer(src_buffer, src_offset, input_size); |
| 293 | update_descriptor_queue.AddBuffer(*buffer.handle, 0, staging_size); | 293 | update_descriptor_queue.AddBuffer(staging_ref.buffer, 0, staging_size); |
| 294 | const VkDescriptorSet set = CommitDescriptorSet(update_descriptor_queue); | 294 | const VkDescriptorSet set = CommitDescriptorSet(update_descriptor_queue); |
| 295 | 295 | ||
| 296 | scheduler.RequestOutsideRenderPassOperationContext(); | 296 | scheduler.RequestOutsideRenderPassOperationContext(); |
| 297 | scheduler.Record([layout = *layout, pipeline = *pipeline, buffer = *buffer.handle, set, | 297 | scheduler.Record([layout = *layout, pipeline = *pipeline, buffer = staging_ref.buffer, set, |
| 298 | num_tri_vertices, base_vertex, index_shift](vk::CommandBuffer cmdbuf) { | 298 | num_tri_vertices, base_vertex, index_shift](vk::CommandBuffer cmdbuf) { |
| 299 | static constexpr u32 dispatch_size = 1024; | 299 | static constexpr u32 dispatch_size = 1024; |
| 300 | const std::array push_constants = {base_vertex, index_shift}; | 300 | const std::array push_constants = {base_vertex, index_shift}; |
| @@ -317,7 +317,7 @@ std::pair<VkBuffer, u64> QuadIndexedPass::Assemble( | |||
| 317 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, | 317 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, |
| 318 | VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, 0, {}, barrier, {}); | 318 | VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, 0, {}, barrier, {}); |
| 319 | }); | 319 | }); |
| 320 | return {*buffer.handle, 0}; | 320 | return {staging_ref.buffer, 0}; |
| 321 | } | 321 | } |
| 322 | 322 | ||
| 323 | } // namespace Vulkan | 323 | } // namespace Vulkan |
diff --git a/src/video_core/renderer_vulkan/vk_compute_pass.h b/src/video_core/renderer_vulkan/vk_compute_pass.h index 7ddb09afb..f5c6f5f17 100644 --- a/src/video_core/renderer_vulkan/vk_compute_pass.h +++ b/src/video_core/renderer_vulkan/vk_compute_pass.h | |||
| @@ -16,8 +16,8 @@ | |||
| 16 | namespace Vulkan { | 16 | namespace Vulkan { |
| 17 | 17 | ||
| 18 | class Device; | 18 | class Device; |
| 19 | class StagingBufferPool; | ||
| 19 | class VKScheduler; | 20 | class VKScheduler; |
| 20 | class VKStagingBufferPool; | ||
| 21 | class VKUpdateDescriptorQueue; | 21 | class VKUpdateDescriptorQueue; |
| 22 | 22 | ||
| 23 | class VKComputePass { | 23 | class VKComputePass { |
| @@ -45,7 +45,7 @@ class QuadArrayPass final : public VKComputePass { | |||
| 45 | public: | 45 | public: |
| 46 | explicit QuadArrayPass(const Device& device_, VKScheduler& scheduler_, | 46 | explicit QuadArrayPass(const Device& device_, VKScheduler& scheduler_, |
| 47 | VKDescriptorPool& descriptor_pool_, | 47 | VKDescriptorPool& descriptor_pool_, |
| 48 | VKStagingBufferPool& staging_buffer_pool_, | 48 | StagingBufferPool& staging_buffer_pool_, |
| 49 | VKUpdateDescriptorQueue& update_descriptor_queue_); | 49 | VKUpdateDescriptorQueue& update_descriptor_queue_); |
| 50 | ~QuadArrayPass(); | 50 | ~QuadArrayPass(); |
| 51 | 51 | ||
| @@ -53,15 +53,14 @@ public: | |||
| 53 | 53 | ||
| 54 | private: | 54 | private: |
| 55 | VKScheduler& scheduler; | 55 | VKScheduler& scheduler; |
| 56 | VKStagingBufferPool& staging_buffer_pool; | 56 | StagingBufferPool& staging_buffer_pool; |
| 57 | VKUpdateDescriptorQueue& update_descriptor_queue; | 57 | VKUpdateDescriptorQueue& update_descriptor_queue; |
| 58 | }; | 58 | }; |
| 59 | 59 | ||
| 60 | class Uint8Pass final : public VKComputePass { | 60 | class Uint8Pass final : public VKComputePass { |
| 61 | public: | 61 | public: |
| 62 | explicit Uint8Pass(const Device& device_, VKScheduler& scheduler_, | 62 | explicit Uint8Pass(const Device& device_, VKScheduler& scheduler_, |
| 63 | VKDescriptorPool& descriptor_pool_, | 63 | VKDescriptorPool& descriptor_pool_, StagingBufferPool& staging_buffer_pool_, |
| 64 | VKStagingBufferPool& staging_buffer_pool_, | ||
| 65 | VKUpdateDescriptorQueue& update_descriptor_queue_); | 64 | VKUpdateDescriptorQueue& update_descriptor_queue_); |
| 66 | ~Uint8Pass(); | 65 | ~Uint8Pass(); |
| 67 | 66 | ||
| @@ -69,7 +68,7 @@ public: | |||
| 69 | 68 | ||
| 70 | private: | 69 | private: |
| 71 | VKScheduler& scheduler; | 70 | VKScheduler& scheduler; |
| 72 | VKStagingBufferPool& staging_buffer_pool; | 71 | StagingBufferPool& staging_buffer_pool; |
| 73 | VKUpdateDescriptorQueue& update_descriptor_queue; | 72 | VKUpdateDescriptorQueue& update_descriptor_queue; |
| 74 | }; | 73 | }; |
| 75 | 74 | ||
| @@ -77,7 +76,7 @@ class QuadIndexedPass final : public VKComputePass { | |||
| 77 | public: | 76 | public: |
| 78 | explicit QuadIndexedPass(const Device& device_, VKScheduler& scheduler_, | 77 | explicit QuadIndexedPass(const Device& device_, VKScheduler& scheduler_, |
| 79 | VKDescriptorPool& descriptor_pool_, | 78 | VKDescriptorPool& descriptor_pool_, |
| 80 | VKStagingBufferPool& staging_buffer_pool_, | 79 | StagingBufferPool& staging_buffer_pool_, |
| 81 | VKUpdateDescriptorQueue& update_descriptor_queue_); | 80 | VKUpdateDescriptorQueue& update_descriptor_queue_); |
| 82 | ~QuadIndexedPass(); | 81 | ~QuadIndexedPass(); |
| 83 | 82 | ||
| @@ -87,7 +86,7 @@ public: | |||
| 87 | 86 | ||
| 88 | private: | 87 | private: |
| 89 | VKScheduler& scheduler; | 88 | VKScheduler& scheduler; |
| 90 | VKStagingBufferPool& staging_buffer_pool; | 89 | StagingBufferPool& staging_buffer_pool; |
| 91 | VKUpdateDescriptorQueue& update_descriptor_queue; | 90 | VKUpdateDescriptorQueue& update_descriptor_queue; |
| 92 | }; | 91 | }; |
| 93 | 92 | ||
diff --git a/src/video_core/renderer_vulkan/vk_memory_manager.cpp b/src/video_core/renderer_vulkan/vk_memory_manager.cpp deleted file mode 100644 index a6abd0eee..000000000 --- a/src/video_core/renderer_vulkan/vk_memory_manager.cpp +++ /dev/null | |||
| @@ -1,230 +0,0 @@ | |||
| 1 | // Copyright 2018 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <algorithm> | ||
| 6 | #include <optional> | ||
| 7 | #include <tuple> | ||
| 8 | #include <vector> | ||
| 9 | |||
| 10 | #include "common/alignment.h" | ||
| 11 | #include "common/assert.h" | ||
| 12 | #include "common/common_types.h" | ||
| 13 | #include "common/logging/log.h" | ||
| 14 | #include "video_core/renderer_vulkan/vk_memory_manager.h" | ||
| 15 | #include "video_core/vulkan_common/vulkan_device.h" | ||
| 16 | #include "video_core/vulkan_common/vulkan_wrapper.h" | ||
| 17 | |||
| 18 | namespace Vulkan { | ||
| 19 | |||
| 20 | namespace { | ||
| 21 | |||
| 22 | u64 GetAllocationChunkSize(u64 required_size) { | ||
| 23 | static constexpr u64 sizes[] = {16ULL << 20, 32ULL << 20, 64ULL << 20, 128ULL << 20}; | ||
| 24 | auto it = std::lower_bound(std::begin(sizes), std::end(sizes), required_size); | ||
| 25 | return it != std::end(sizes) ? *it : Common::AlignUp(required_size, 256ULL << 20); | ||
| 26 | } | ||
| 27 | |||
| 28 | } // Anonymous namespace | ||
| 29 | |||
| 30 | class VKMemoryAllocation final { | ||
| 31 | public: | ||
| 32 | explicit VKMemoryAllocation(const Device& device_, vk::DeviceMemory memory_, | ||
| 33 | VkMemoryPropertyFlags properties_, u64 allocation_size_, u32 type_) | ||
| 34 | : device{device_}, memory{std::move(memory_)}, properties{properties_}, | ||
| 35 | allocation_size{allocation_size_}, shifted_type{ShiftType(type_)} {} | ||
| 36 | |||
| 37 | VKMemoryCommit Commit(VkDeviceSize commit_size, VkDeviceSize alignment) { | ||
| 38 | auto found = TryFindFreeSection(free_iterator, allocation_size, | ||
| 39 | static_cast<u64>(commit_size), static_cast<u64>(alignment)); | ||
| 40 | if (!found) { | ||
| 41 | found = TryFindFreeSection(0, free_iterator, static_cast<u64>(commit_size), | ||
| 42 | static_cast<u64>(alignment)); | ||
| 43 | if (!found) { | ||
| 44 | // Signal out of memory, it'll try to do more allocations. | ||
| 45 | return nullptr; | ||
| 46 | } | ||
| 47 | } | ||
| 48 | auto commit = std::make_unique<VKMemoryCommitImpl>(device, this, memory, *found, | ||
| 49 | *found + commit_size); | ||
| 50 | commits.push_back(commit.get()); | ||
| 51 | |||
| 52 | // Last commit's address is highly probable to be free. | ||
| 53 | free_iterator = *found + commit_size; | ||
| 54 | |||
| 55 | return commit; | ||
| 56 | } | ||
| 57 | |||
| 58 | void Free(const VKMemoryCommitImpl* commit) { | ||
| 59 | ASSERT(commit); | ||
| 60 | |||
| 61 | const auto it = std::find(std::begin(commits), std::end(commits), commit); | ||
| 62 | if (it == commits.end()) { | ||
| 63 | UNREACHABLE_MSG("Freeing unallocated commit!"); | ||
| 64 | return; | ||
| 65 | } | ||
| 66 | commits.erase(it); | ||
| 67 | } | ||
| 68 | |||
| 69 | /// Returns whether this allocation is compatible with the arguments. | ||
| 70 | bool IsCompatible(VkMemoryPropertyFlags wanted_properties, u32 type_mask) const { | ||
| 71 | return (wanted_properties & properties) && (type_mask & shifted_type) != 0; | ||
| 72 | } | ||
| 73 | |||
| 74 | private: | ||
| 75 | static constexpr u32 ShiftType(u32 type) { | ||
| 76 | return 1U << type; | ||
| 77 | } | ||
| 78 | |||
| 79 | /// A memory allocator, it may return a free region between "start" and "end" with the solicited | ||
| 80 | /// requirements. | ||
| 81 | std::optional<u64> TryFindFreeSection(u64 start, u64 end, u64 size, u64 alignment) const { | ||
| 82 | u64 iterator = Common::AlignUp(start, alignment); | ||
| 83 | while (iterator + size <= end) { | ||
| 84 | const u64 try_left = iterator; | ||
| 85 | const u64 try_right = try_left + size; | ||
| 86 | |||
| 87 | bool overlap = false; | ||
| 88 | for (const auto& commit : commits) { | ||
| 89 | const auto [commit_left, commit_right] = commit->interval; | ||
| 90 | if (try_left < commit_right && commit_left < try_right) { | ||
| 91 | // There's an overlap, continue the search where the overlapping commit ends. | ||
| 92 | iterator = Common::AlignUp(commit_right, alignment); | ||
| 93 | overlap = true; | ||
| 94 | break; | ||
| 95 | } | ||
| 96 | } | ||
| 97 | if (!overlap) { | ||
| 98 | // A free address has been found. | ||
| 99 | return try_left; | ||
| 100 | } | ||
| 101 | } | ||
| 102 | |||
| 103 | // No free regions where found, return an empty optional. | ||
| 104 | return std::nullopt; | ||
| 105 | } | ||
| 106 | |||
| 107 | const Device& device; ///< Vulkan device. | ||
| 108 | const vk::DeviceMemory memory; ///< Vulkan memory allocation handler. | ||
| 109 | const VkMemoryPropertyFlags properties; ///< Vulkan properties. | ||
| 110 | const u64 allocation_size; ///< Size of this allocation. | ||
| 111 | const u32 shifted_type; ///< Stored Vulkan type of this allocation, shifted. | ||
| 112 | |||
| 113 | /// Hints where the next free region is likely going to be. | ||
| 114 | u64 free_iterator{}; | ||
| 115 | |||
| 116 | /// Stores all commits done from this allocation. | ||
| 117 | std::vector<const VKMemoryCommitImpl*> commits; | ||
| 118 | }; | ||
| 119 | |||
| 120 | VKMemoryManager::VKMemoryManager(const Device& device_) | ||
| 121 | : device{device_}, properties{device_.GetPhysical().GetMemoryProperties()} {} | ||
| 122 | |||
| 123 | VKMemoryManager::~VKMemoryManager() = default; | ||
| 124 | |||
| 125 | VKMemoryCommit VKMemoryManager::Commit(const VkMemoryRequirements& requirements, | ||
| 126 | bool host_visible) { | ||
| 127 | const u64 chunk_size = GetAllocationChunkSize(requirements.size); | ||
| 128 | |||
| 129 | // When a host visible commit is asked, search for host visible and coherent, otherwise search | ||
| 130 | // for a fast device local type. | ||
| 131 | const VkMemoryPropertyFlags wanted_properties = | ||
| 132 | host_visible ? VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | ||
| 133 | : VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; | ||
| 134 | |||
| 135 | if (auto commit = TryAllocCommit(requirements, wanted_properties)) { | ||
| 136 | return commit; | ||
| 137 | } | ||
| 138 | |||
| 139 | // Commit has failed, allocate more memory. | ||
| 140 | if (!AllocMemory(wanted_properties, requirements.memoryTypeBits, chunk_size)) { | ||
| 141 | // TODO(Rodrigo): Handle these situations in some way like flushing to guest memory. | ||
| 142 | // Allocation has failed, panic. | ||
| 143 | UNREACHABLE_MSG("Ran out of VRAM!"); | ||
| 144 | return {}; | ||
| 145 | } | ||
| 146 | |||
| 147 | // Commit again, this time it won't fail since there's a fresh allocation above. If it does, | ||
| 148 | // there's a bug. | ||
| 149 | auto commit = TryAllocCommit(requirements, wanted_properties); | ||
| 150 | ASSERT(commit); | ||
| 151 | return commit; | ||
| 152 | } | ||
| 153 | |||
| 154 | VKMemoryCommit VKMemoryManager::Commit(const vk::Buffer& buffer, bool host_visible) { | ||
| 155 | auto commit = Commit(device.GetLogical().GetBufferMemoryRequirements(*buffer), host_visible); | ||
| 156 | buffer.BindMemory(commit->GetMemory(), commit->GetOffset()); | ||
| 157 | return commit; | ||
| 158 | } | ||
| 159 | |||
| 160 | VKMemoryCommit VKMemoryManager::Commit(const vk::Image& image, bool host_visible) { | ||
| 161 | auto commit = Commit(device.GetLogical().GetImageMemoryRequirements(*image), host_visible); | ||
| 162 | image.BindMemory(commit->GetMemory(), commit->GetOffset()); | ||
| 163 | return commit; | ||
| 164 | } | ||
| 165 | |||
| 166 | bool VKMemoryManager::AllocMemory(VkMemoryPropertyFlags wanted_properties, u32 type_mask, | ||
| 167 | u64 size) { | ||
| 168 | const u32 type = [&] { | ||
| 169 | for (u32 type_index = 0; type_index < properties.memoryTypeCount; ++type_index) { | ||
| 170 | const auto flags = properties.memoryTypes[type_index].propertyFlags; | ||
| 171 | if ((type_mask & (1U << type_index)) && (flags & wanted_properties)) { | ||
| 172 | // The type matches in type and in the wanted properties. | ||
| 173 | return type_index; | ||
| 174 | } | ||
| 175 | } | ||
| 176 | UNREACHABLE_MSG("Couldn't find a compatible memory type!"); | ||
| 177 | return 0U; | ||
| 178 | }(); | ||
| 179 | |||
| 180 | // Try to allocate found type. | ||
| 181 | vk::DeviceMemory memory = device.GetLogical().TryAllocateMemory({ | ||
| 182 | .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, | ||
| 183 | .pNext = nullptr, | ||
| 184 | .allocationSize = size, | ||
| 185 | .memoryTypeIndex = type, | ||
| 186 | }); | ||
| 187 | if (!memory) { | ||
| 188 | LOG_CRITICAL(Render_Vulkan, "Device allocation failed!"); | ||
| 189 | return false; | ||
| 190 | } | ||
| 191 | |||
| 192 | allocations.push_back(std::make_unique<VKMemoryAllocation>(device, std::move(memory), | ||
| 193 | wanted_properties, size, type)); | ||
| 194 | return true; | ||
| 195 | } | ||
| 196 | |||
| 197 | VKMemoryCommit VKMemoryManager::TryAllocCommit(const VkMemoryRequirements& requirements, | ||
| 198 | VkMemoryPropertyFlags wanted_properties) { | ||
| 199 | for (auto& allocation : allocations) { | ||
| 200 | if (!allocation->IsCompatible(wanted_properties, requirements.memoryTypeBits)) { | ||
| 201 | continue; | ||
| 202 | } | ||
| 203 | if (auto commit = allocation->Commit(requirements.size, requirements.alignment)) { | ||
| 204 | return commit; | ||
| 205 | } | ||
| 206 | } | ||
| 207 | return {}; | ||
| 208 | } | ||
| 209 | |||
| 210 | VKMemoryCommitImpl::VKMemoryCommitImpl(const Device& device_, VKMemoryAllocation* allocation_, | ||
| 211 | const vk::DeviceMemory& memory_, u64 begin_, u64 end_) | ||
| 212 | : device{device_}, memory{memory_}, interval{begin_, end_}, allocation{allocation_} {} | ||
| 213 | |||
| 214 | VKMemoryCommitImpl::~VKMemoryCommitImpl() { | ||
| 215 | allocation->Free(this); | ||
| 216 | } | ||
| 217 | |||
| 218 | MemoryMap VKMemoryCommitImpl::Map(u64 size, u64 offset_) const { | ||
| 219 | return MemoryMap(this, std::span<u8>(memory.Map(interval.first + offset_, size), size)); | ||
| 220 | } | ||
| 221 | |||
| 222 | void VKMemoryCommitImpl::Unmap() const { | ||
| 223 | memory.Unmap(); | ||
| 224 | } | ||
| 225 | |||
| 226 | MemoryMap VKMemoryCommitImpl::Map() const { | ||
| 227 | return Map(interval.second - interval.first); | ||
| 228 | } | ||
| 229 | |||
| 230 | } // namespace Vulkan | ||
diff --git a/src/video_core/renderer_vulkan/vk_memory_manager.h b/src/video_core/renderer_vulkan/vk_memory_manager.h deleted file mode 100644 index 2452bca4e..000000000 --- a/src/video_core/renderer_vulkan/vk_memory_manager.h +++ /dev/null | |||
| @@ -1,132 +0,0 @@ | |||
| 1 | // Copyright 2019 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <memory> | ||
| 8 | #include <span> | ||
| 9 | #include <utility> | ||
| 10 | #include <vector> | ||
| 11 | #include "common/common_types.h" | ||
| 12 | #include "video_core/vulkan_common/vulkan_wrapper.h" | ||
| 13 | |||
| 14 | namespace Vulkan { | ||
| 15 | |||
| 16 | class Device; | ||
| 17 | class MemoryMap; | ||
| 18 | class VKMemoryAllocation; | ||
| 19 | class VKMemoryCommitImpl; | ||
| 20 | |||
| 21 | using VKMemoryCommit = std::unique_ptr<VKMemoryCommitImpl>; | ||
| 22 | |||
| 23 | class VKMemoryManager final { | ||
| 24 | public: | ||
| 25 | explicit VKMemoryManager(const Device& device_); | ||
| 26 | VKMemoryManager(const VKMemoryManager&) = delete; | ||
| 27 | ~VKMemoryManager(); | ||
| 28 | |||
| 29 | /** | ||
| 30 | * Commits a memory with the specified requeriments. | ||
| 31 | * @param requirements Requirements returned from a Vulkan call. | ||
| 32 | * @param host_visible Signals the allocator that it *must* use host visible and coherent | ||
| 33 | * memory. When passing false, it will try to allocate device local memory. | ||
| 34 | * @returns A memory commit. | ||
| 35 | */ | ||
| 36 | VKMemoryCommit Commit(const VkMemoryRequirements& requirements, bool host_visible); | ||
| 37 | |||
| 38 | /// Commits memory required by the buffer and binds it. | ||
| 39 | VKMemoryCommit Commit(const vk::Buffer& buffer, bool host_visible); | ||
| 40 | |||
| 41 | /// Commits memory required by the image and binds it. | ||
| 42 | VKMemoryCommit Commit(const vk::Image& image, bool host_visible); | ||
| 43 | |||
| 44 | private: | ||
| 45 | /// Allocates a chunk of memory. | ||
| 46 | bool AllocMemory(VkMemoryPropertyFlags wanted_properties, u32 type_mask, u64 size); | ||
| 47 | |||
| 48 | /// Tries to allocate a memory commit. | ||
| 49 | VKMemoryCommit TryAllocCommit(const VkMemoryRequirements& requirements, | ||
| 50 | VkMemoryPropertyFlags wanted_properties); | ||
| 51 | |||
| 52 | const Device& device; ///< Device handler. | ||
| 53 | const VkPhysicalDeviceMemoryProperties properties; ///< Physical device properties. | ||
| 54 | std::vector<std::unique_ptr<VKMemoryAllocation>> allocations; ///< Current allocations. | ||
| 55 | }; | ||
| 56 | |||
| 57 | class VKMemoryCommitImpl final { | ||
| 58 | friend VKMemoryAllocation; | ||
| 59 | friend MemoryMap; | ||
| 60 | |||
| 61 | public: | ||
| 62 | explicit VKMemoryCommitImpl(const Device& device_, VKMemoryAllocation* allocation_, | ||
| 63 | const vk::DeviceMemory& memory_, u64 begin_, u64 end_); | ||
| 64 | ~VKMemoryCommitImpl(); | ||
| 65 | |||
| 66 | /// Maps a memory region and returns a pointer to it. | ||
| 67 | /// It's illegal to have more than one memory map at the same time. | ||
| 68 | MemoryMap Map(u64 size, u64 offset = 0) const; | ||
| 69 | |||
| 70 | /// Maps the whole commit and returns a pointer to it. | ||
| 71 | /// It's illegal to have more than one memory map at the same time. | ||
| 72 | MemoryMap Map() const; | ||
| 73 | |||
| 74 | /// Returns the Vulkan memory handler. | ||
| 75 | VkDeviceMemory GetMemory() const { | ||
| 76 | return *memory; | ||
| 77 | } | ||
| 78 | |||
| 79 | /// Returns the start position of the commit relative to the allocation. | ||
| 80 | VkDeviceSize GetOffset() const { | ||
| 81 | return static_cast<VkDeviceSize>(interval.first); | ||
| 82 | } | ||
| 83 | |||
| 84 | private: | ||
| 85 | /// Unmaps memory. | ||
| 86 | void Unmap() const; | ||
| 87 | |||
| 88 | const Device& device; ///< Vulkan device. | ||
| 89 | const vk::DeviceMemory& memory; ///< Vulkan device memory handler. | ||
| 90 | std::pair<u64, u64> interval{}; ///< Interval where the commit exists. | ||
| 91 | VKMemoryAllocation* allocation{}; ///< Pointer to the large memory allocation. | ||
| 92 | }; | ||
| 93 | |||
| 94 | /// Holds ownership of a memory map. | ||
| 95 | class MemoryMap final { | ||
| 96 | public: | ||
| 97 | explicit MemoryMap(const VKMemoryCommitImpl* commit_, std::span<u8> span_) | ||
| 98 | : commit{commit_}, span{span_} {} | ||
| 99 | |||
| 100 | ~MemoryMap() { | ||
| 101 | if (commit) { | ||
| 102 | commit->Unmap(); | ||
| 103 | } | ||
| 104 | } | ||
| 105 | |||
| 106 | /// Prematurely releases the memory map. | ||
| 107 | void Release() { | ||
| 108 | commit->Unmap(); | ||
| 109 | commit = nullptr; | ||
| 110 | } | ||
| 111 | |||
| 112 | /// Returns a span to the memory map. | ||
| 113 | [[nodiscard]] std::span<u8> Span() const noexcept { | ||
| 114 | return span; | ||
| 115 | } | ||
| 116 | |||
| 117 | /// Returns the address of the memory map. | ||
| 118 | [[nodiscard]] u8* Address() const noexcept { | ||
| 119 | return span.data(); | ||
| 120 | } | ||
| 121 | |||
| 122 | /// Returns the address of the memory map; | ||
| 123 | [[nodiscard]] operator u8*() const noexcept { | ||
| 124 | return span.data(); | ||
| 125 | } | ||
| 126 | |||
| 127 | private: | ||
| 128 | const VKMemoryCommitImpl* commit{}; ///< Mapped memory commit. | ||
| 129 | std::span<u8> span; ///< Address to the mapped memory. | ||
| 130 | }; | ||
| 131 | |||
| 132 | } // namespace Vulkan | ||
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index ce3db49bd..f0a111829 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp | |||
| @@ -409,24 +409,24 @@ void RasterizerVulkan::DrawParameters::Draw(vk::CommandBuffer cmdbuf) const { | |||
| 409 | RasterizerVulkan::RasterizerVulkan(Core::Frontend::EmuWindow& emu_window_, Tegra::GPU& gpu_, | 409 | RasterizerVulkan::RasterizerVulkan(Core::Frontend::EmuWindow& emu_window_, Tegra::GPU& gpu_, |
| 410 | Tegra::MemoryManager& gpu_memory_, | 410 | Tegra::MemoryManager& gpu_memory_, |
| 411 | Core::Memory::Memory& cpu_memory_, VKScreenInfo& screen_info_, | 411 | Core::Memory::Memory& cpu_memory_, VKScreenInfo& screen_info_, |
| 412 | const Device& device_, VKMemoryManager& memory_manager_, | 412 | const Device& device_, MemoryAllocator& memory_allocator_, |
| 413 | StateTracker& state_tracker_, VKScheduler& scheduler_) | 413 | StateTracker& state_tracker_, VKScheduler& scheduler_) |
| 414 | : RasterizerAccelerated{cpu_memory_}, gpu{gpu_}, | 414 | : RasterizerAccelerated{cpu_memory_}, gpu{gpu_}, |
| 415 | gpu_memory{gpu_memory_}, maxwell3d{gpu.Maxwell3D()}, kepler_compute{gpu.KeplerCompute()}, | 415 | gpu_memory{gpu_memory_}, maxwell3d{gpu.Maxwell3D()}, kepler_compute{gpu.KeplerCompute()}, |
| 416 | screen_info{screen_info_}, device{device_}, memory_manager{memory_manager_}, | 416 | screen_info{screen_info_}, device{device_}, memory_allocator{memory_allocator_}, |
| 417 | state_tracker{state_tracker_}, scheduler{scheduler_}, stream_buffer(device, scheduler), | 417 | state_tracker{state_tracker_}, scheduler{scheduler_}, stream_buffer(device, scheduler), |
| 418 | staging_pool(device, memory_manager, scheduler), descriptor_pool(device, scheduler), | 418 | staging_pool(device, memory_allocator, scheduler), descriptor_pool(device, scheduler), |
| 419 | update_descriptor_queue(device, scheduler), | 419 | update_descriptor_queue(device, scheduler), |
| 420 | blit_image(device, scheduler, state_tracker, descriptor_pool), | 420 | blit_image(device, scheduler, state_tracker, descriptor_pool), |
| 421 | quad_array_pass(device, scheduler, descriptor_pool, staging_pool, update_descriptor_queue), | 421 | quad_array_pass(device, scheduler, descriptor_pool, staging_pool, update_descriptor_queue), |
| 422 | quad_indexed_pass(device, scheduler, descriptor_pool, staging_pool, update_descriptor_queue), | 422 | quad_indexed_pass(device, scheduler, descriptor_pool, staging_pool, update_descriptor_queue), |
| 423 | uint8_pass(device, scheduler, descriptor_pool, staging_pool, update_descriptor_queue), | 423 | uint8_pass(device, scheduler, descriptor_pool, staging_pool, update_descriptor_queue), |
| 424 | texture_cache_runtime{device, scheduler, memory_manager, staging_pool, blit_image}, | 424 | texture_cache_runtime{device, scheduler, memory_allocator, staging_pool, blit_image}, |
| 425 | texture_cache(texture_cache_runtime, *this, maxwell3d, kepler_compute, gpu_memory), | 425 | texture_cache(texture_cache_runtime, *this, maxwell3d, kepler_compute, gpu_memory), |
| 426 | pipeline_cache(*this, gpu, maxwell3d, kepler_compute, gpu_memory, device, scheduler, | 426 | pipeline_cache(*this, gpu, maxwell3d, kepler_compute, gpu_memory, device, scheduler, |
| 427 | descriptor_pool, update_descriptor_queue), | 427 | descriptor_pool, update_descriptor_queue), |
| 428 | buffer_cache(*this, gpu_memory, cpu_memory_, device, memory_manager, scheduler, stream_buffer, | 428 | buffer_cache(*this, gpu_memory, cpu_memory_, device, memory_allocator, scheduler, |
| 429 | staging_pool), | 429 | stream_buffer, staging_pool), |
| 430 | query_cache{*this, maxwell3d, gpu_memory, device, scheduler}, | 430 | query_cache{*this, maxwell3d, gpu_memory, device, scheduler}, |
| 431 | fence_manager(*this, gpu, gpu_memory, texture_cache, buffer_cache, query_cache, scheduler), | 431 | fence_manager(*this, gpu, gpu_memory, texture_cache, buffer_cache, query_cache, scheduler), |
| 432 | wfi_event(device.GetLogical().CreateEvent()), async_shaders(emu_window_) { | 432 | wfi_event(device.GetLogical().CreateEvent()), async_shaders(emu_window_) { |
| @@ -1445,7 +1445,7 @@ VkBuffer RasterizerVulkan::DefaultBuffer() { | |||
| 1445 | .queueFamilyIndexCount = 0, | 1445 | .queueFamilyIndexCount = 0, |
| 1446 | .pQueueFamilyIndices = nullptr, | 1446 | .pQueueFamilyIndices = nullptr, |
| 1447 | }); | 1447 | }); |
| 1448 | default_buffer_commit = memory_manager.Commit(default_buffer, false); | 1448 | default_buffer_commit = memory_allocator.Commit(default_buffer, MemoryUsage::DeviceLocal); |
| 1449 | 1449 | ||
| 1450 | scheduler.RequestOutsideRenderPassOperationContext(); | 1450 | scheduler.RequestOutsideRenderPassOperationContext(); |
| 1451 | scheduler.Record([buffer = *default_buffer](vk::CommandBuffer cmdbuf) { | 1451 | scheduler.Record([buffer = *default_buffer](vk::CommandBuffer cmdbuf) { |
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.h b/src/video_core/renderer_vulkan/vk_rasterizer.h index 4695718e9..8e261b9bd 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.h +++ b/src/video_core/renderer_vulkan/vk_rasterizer.h | |||
| @@ -21,7 +21,6 @@ | |||
| 21 | #include "video_core/renderer_vulkan/vk_compute_pass.h" | 21 | #include "video_core/renderer_vulkan/vk_compute_pass.h" |
| 22 | #include "video_core/renderer_vulkan/vk_descriptor_pool.h" | 22 | #include "video_core/renderer_vulkan/vk_descriptor_pool.h" |
| 23 | #include "video_core/renderer_vulkan/vk_fence_manager.h" | 23 | #include "video_core/renderer_vulkan/vk_fence_manager.h" |
| 24 | #include "video_core/renderer_vulkan/vk_memory_manager.h" | ||
| 25 | #include "video_core/renderer_vulkan/vk_pipeline_cache.h" | 24 | #include "video_core/renderer_vulkan/vk_pipeline_cache.h" |
| 26 | #include "video_core/renderer_vulkan/vk_query_cache.h" | 25 | #include "video_core/renderer_vulkan/vk_query_cache.h" |
| 27 | #include "video_core/renderer_vulkan/vk_scheduler.h" | 26 | #include "video_core/renderer_vulkan/vk_scheduler.h" |
| @@ -30,6 +29,7 @@ | |||
| 30 | #include "video_core/renderer_vulkan/vk_texture_cache.h" | 29 | #include "video_core/renderer_vulkan/vk_texture_cache.h" |
| 31 | #include "video_core/renderer_vulkan/vk_update_descriptor.h" | 30 | #include "video_core/renderer_vulkan/vk_update_descriptor.h" |
| 32 | #include "video_core/shader/async_shaders.h" | 31 | #include "video_core/shader/async_shaders.h" |
| 32 | #include "video_core/vulkan_common/vulkan_memory_allocator.h" | ||
| 33 | #include "video_core/vulkan_common/vulkan_wrapper.h" | 33 | #include "video_core/vulkan_common/vulkan_wrapper.h" |
| 34 | 34 | ||
| 35 | namespace Core { | 35 | namespace Core { |
| @@ -56,7 +56,7 @@ public: | |||
| 56 | explicit RasterizerVulkan(Core::Frontend::EmuWindow& emu_window_, Tegra::GPU& gpu_, | 56 | explicit RasterizerVulkan(Core::Frontend::EmuWindow& emu_window_, Tegra::GPU& gpu_, |
| 57 | Tegra::MemoryManager& gpu_memory_, Core::Memory::Memory& cpu_memory_, | 57 | Tegra::MemoryManager& gpu_memory_, Core::Memory::Memory& cpu_memory_, |
| 58 | VKScreenInfo& screen_info_, const Device& device_, | 58 | VKScreenInfo& screen_info_, const Device& device_, |
| 59 | VKMemoryManager& memory_manager_, StateTracker& state_tracker_, | 59 | MemoryAllocator& memory_allocator_, StateTracker& state_tracker_, |
| 60 | VKScheduler& scheduler_); | 60 | VKScheduler& scheduler_); |
| 61 | ~RasterizerVulkan() override; | 61 | ~RasterizerVulkan() override; |
| 62 | 62 | ||
| @@ -213,12 +213,12 @@ private: | |||
| 213 | 213 | ||
| 214 | VKScreenInfo& screen_info; | 214 | VKScreenInfo& screen_info; |
| 215 | const Device& device; | 215 | const Device& device; |
| 216 | VKMemoryManager& memory_manager; | 216 | MemoryAllocator& memory_allocator; |
| 217 | StateTracker& state_tracker; | 217 | StateTracker& state_tracker; |
| 218 | VKScheduler& scheduler; | 218 | VKScheduler& scheduler; |
| 219 | 219 | ||
| 220 | VKStreamBuffer stream_buffer; | 220 | VKStreamBuffer stream_buffer; |
| 221 | VKStagingBufferPool staging_pool; | 221 | StagingBufferPool staging_pool; |
| 222 | VKDescriptorPool descriptor_pool; | 222 | VKDescriptorPool descriptor_pool; |
| 223 | VKUpdateDescriptorQueue update_descriptor_queue; | 223 | VKUpdateDescriptorQueue update_descriptor_queue; |
| 224 | BlitImageHelper blit_image; | 224 | BlitImageHelper blit_image; |
| @@ -234,7 +234,7 @@ private: | |||
| 234 | VKFenceManager fence_manager; | 234 | VKFenceManager fence_manager; |
| 235 | 235 | ||
| 236 | vk::Buffer default_buffer; | 236 | vk::Buffer default_buffer; |
| 237 | VKMemoryCommit default_buffer_commit; | 237 | MemoryCommit default_buffer_commit; |
| 238 | vk::Event wfi_event; | 238 | vk::Event wfi_event; |
| 239 | VideoCommon::Shader::AsyncShaders async_shaders; | 239 | VideoCommon::Shader::AsyncShaders async_shaders; |
| 240 | 240 | ||
diff --git a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp index 1e0b8b922..97fd41cc1 100644 --- a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp +++ b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp | |||
| @@ -3,10 +3,12 @@ | |||
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <algorithm> | 5 | #include <algorithm> |
| 6 | #include <unordered_map> | ||
| 7 | #include <utility> | 6 | #include <utility> |
| 8 | #include <vector> | 7 | #include <vector> |
| 9 | 8 | ||
| 9 | #include <fmt/format.h> | ||
| 10 | |||
| 11 | #include "common/assert.h" | ||
| 10 | #include "common/bit_util.h" | 12 | #include "common/bit_util.h" |
| 11 | #include "common/common_types.h" | 13 | #include "common/common_types.h" |
| 12 | #include "video_core/renderer_vulkan/vk_scheduler.h" | 14 | #include "video_core/renderer_vulkan/vk_scheduler.h" |
| @@ -16,45 +18,51 @@ | |||
| 16 | 18 | ||
| 17 | namespace Vulkan { | 19 | namespace Vulkan { |
| 18 | 20 | ||
| 19 | VKStagingBufferPool::StagingBuffer::StagingBuffer(std::unique_ptr<VKBuffer> buffer_) | 21 | StagingBufferPool::StagingBufferPool(const Device& device_, MemoryAllocator& memory_allocator_, |
| 20 | : buffer{std::move(buffer_)} {} | 22 | VKScheduler& scheduler_) |
| 21 | 23 | : device{device_}, memory_allocator{memory_allocator_}, scheduler{scheduler_} {} | |
| 22 | VKStagingBufferPool::VKStagingBufferPool(const Device& device_, VKMemoryManager& memory_manager_, | ||
| 23 | VKScheduler& scheduler_) | ||
| 24 | : device{device_}, memory_manager{memory_manager_}, scheduler{scheduler_} {} | ||
| 25 | 24 | ||
| 26 | VKStagingBufferPool::~VKStagingBufferPool() = default; | 25 | StagingBufferPool::~StagingBufferPool() = default; |
| 27 | 26 | ||
| 28 | VKBuffer& VKStagingBufferPool::GetUnusedBuffer(std::size_t size, bool host_visible) { | 27 | StagingBufferRef StagingBufferPool::Request(size_t size, MemoryUsage usage) { |
| 29 | if (const auto buffer = TryGetReservedBuffer(size, host_visible)) { | 28 | if (const std::optional<StagingBufferRef> ref = TryGetReservedBuffer(size, usage)) { |
| 30 | return *buffer; | 29 | return *ref; |
| 31 | } | 30 | } |
| 32 | return CreateStagingBuffer(size, host_visible); | 31 | return CreateStagingBuffer(size, usage); |
| 33 | } | 32 | } |
| 34 | 33 | ||
| 35 | void VKStagingBufferPool::TickFrame() { | 34 | void StagingBufferPool::TickFrame() { |
| 36 | current_delete_level = (current_delete_level + 1) % NumLevels; | 35 | current_delete_level = (current_delete_level + 1) % NUM_LEVELS; |
| 37 | 36 | ||
| 38 | ReleaseCache(true); | 37 | ReleaseCache(MemoryUsage::DeviceLocal); |
| 39 | ReleaseCache(false); | 38 | ReleaseCache(MemoryUsage::Upload); |
| 39 | ReleaseCache(MemoryUsage::Download); | ||
| 40 | } | 40 | } |
| 41 | 41 | ||
| 42 | VKBuffer* VKStagingBufferPool::TryGetReservedBuffer(std::size_t size, bool host_visible) { | 42 | std::optional<StagingBufferRef> StagingBufferPool::TryGetReservedBuffer(size_t size, |
| 43 | for (StagingBuffer& entry : GetCache(host_visible)[Common::Log2Ceil64(size)].entries) { | 43 | MemoryUsage usage) { |
| 44 | if (!scheduler.IsFree(entry.tick)) { | 44 | StagingBuffers& cache_level = GetCache(usage)[Common::Log2Ceil64(size)]; |
| 45 | continue; | 45 | |
| 46 | const auto is_free = [this](const StagingBuffer& entry) { | ||
| 47 | return scheduler.IsFree(entry.tick); | ||
| 48 | }; | ||
| 49 | auto& entries = cache_level.entries; | ||
| 50 | const auto hint_it = entries.begin() + cache_level.iterate_index; | ||
| 51 | auto it = std::find_if(entries.begin() + cache_level.iterate_index, entries.end(), is_free); | ||
| 52 | if (it == entries.end()) { | ||
| 53 | it = std::find_if(entries.begin(), hint_it, is_free); | ||
| 54 | if (it == hint_it) { | ||
| 55 | return std::nullopt; | ||
| 46 | } | 56 | } |
| 47 | entry.tick = scheduler.CurrentTick(); | ||
| 48 | return &*entry.buffer; | ||
| 49 | } | 57 | } |
| 50 | return nullptr; | 58 | cache_level.iterate_index = std::distance(entries.begin(), it) + 1; |
| 59 | it->tick = scheduler.CurrentTick(); | ||
| 60 | return it->Ref(); | ||
| 51 | } | 61 | } |
| 52 | 62 | ||
| 53 | VKBuffer& VKStagingBufferPool::CreateStagingBuffer(std::size_t size, bool host_visible) { | 63 | StagingBufferRef StagingBufferPool::CreateStagingBuffer(size_t size, MemoryUsage usage) { |
| 54 | const u32 log2 = Common::Log2Ceil64(size); | 64 | const u32 log2 = Common::Log2Ceil64(size); |
| 55 | 65 | vk::Buffer buffer = device.GetLogical().CreateBuffer({ | |
| 56 | auto buffer = std::make_unique<VKBuffer>(); | ||
| 57 | buffer->handle = device.GetLogical().CreateBuffer({ | ||
| 58 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, | 66 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, |
| 59 | .pNext = nullptr, | 67 | .pNext = nullptr, |
| 60 | .flags = 0, | 68 | .flags = 0, |
| @@ -66,49 +74,63 @@ VKBuffer& VKStagingBufferPool::CreateStagingBuffer(std::size_t size, bool host_v | |||
| 66 | .queueFamilyIndexCount = 0, | 74 | .queueFamilyIndexCount = 0, |
| 67 | .pQueueFamilyIndices = nullptr, | 75 | .pQueueFamilyIndices = nullptr, |
| 68 | }); | 76 | }); |
| 69 | buffer->commit = memory_manager.Commit(buffer->handle, host_visible); | 77 | if (device.HasDebuggingToolAttached()) { |
| 70 | 78 | ++buffer_index; | |
| 71 | std::vector<StagingBuffer>& entries = GetCache(host_visible)[log2].entries; | 79 | buffer.SetObjectNameEXT(fmt::format("Staging Buffer {}", buffer_index).c_str()); |
| 72 | StagingBuffer& entry = entries.emplace_back(std::move(buffer)); | 80 | } |
| 73 | entry.tick = scheduler.CurrentTick(); | 81 | MemoryCommit commit = memory_allocator.Commit(buffer, usage); |
| 74 | return *entry.buffer; | 82 | const std::span<u8> mapped_span = IsHostVisible(usage) ? commit.Map() : std::span<u8>{}; |
| 75 | } | 83 | |
| 76 | 84 | StagingBuffer& entry = GetCache(usage)[log2].entries.emplace_back(StagingBuffer{ | |
| 77 | VKStagingBufferPool::StagingBuffersCache& VKStagingBufferPool::GetCache(bool host_visible) { | 85 | .buffer = std::move(buffer), |
| 78 | return host_visible ? host_staging_buffers : device_staging_buffers; | 86 | .commit = std::move(commit), |
| 87 | .mapped_span = mapped_span, | ||
| 88 | .tick = scheduler.CurrentTick(), | ||
| 89 | }); | ||
| 90 | return entry.Ref(); | ||
| 79 | } | 91 | } |
| 80 | 92 | ||
| 81 | void VKStagingBufferPool::ReleaseCache(bool host_visible) { | 93 | StagingBufferPool::StagingBuffersCache& StagingBufferPool::GetCache(MemoryUsage usage) { |
| 82 | auto& cache = GetCache(host_visible); | 94 | switch (usage) { |
| 83 | const u64 size = ReleaseLevel(cache, current_delete_level); | 95 | case MemoryUsage::DeviceLocal: |
| 84 | if (size == 0) { | 96 | return device_local_cache; |
| 85 | return; | 97 | case MemoryUsage::Upload: |
| 98 | return upload_cache; | ||
| 99 | case MemoryUsage::Download: | ||
| 100 | return download_cache; | ||
| 101 | default: | ||
| 102 | UNREACHABLE_MSG("Invalid memory usage={}", usage); | ||
| 103 | return upload_cache; | ||
| 86 | } | 104 | } |
| 87 | } | 105 | } |
| 88 | 106 | ||
| 89 | u64 VKStagingBufferPool::ReleaseLevel(StagingBuffersCache& cache, std::size_t log2) { | 107 | void StagingBufferPool::ReleaseCache(MemoryUsage usage) { |
| 90 | static constexpr std::size_t deletions_per_tick = 16; | 108 | ReleaseLevel(GetCache(usage), current_delete_level); |
| 109 | } | ||
| 91 | 110 | ||
| 111 | void StagingBufferPool::ReleaseLevel(StagingBuffersCache& cache, size_t log2) { | ||
| 112 | constexpr size_t deletions_per_tick = 16; | ||
| 92 | auto& staging = cache[log2]; | 113 | auto& staging = cache[log2]; |
| 93 | auto& entries = staging.entries; | 114 | auto& entries = staging.entries; |
| 94 | const std::size_t old_size = entries.size(); | 115 | const size_t old_size = entries.size(); |
| 95 | 116 | ||
| 96 | const auto is_deleteable = [this](const StagingBuffer& entry) { | 117 | const auto is_deleteable = [this](const StagingBuffer& entry) { |
| 97 | return scheduler.IsFree(entry.tick); | 118 | return scheduler.IsFree(entry.tick); |
| 98 | }; | 119 | }; |
| 99 | const std::size_t begin_offset = staging.delete_index; | 120 | const size_t begin_offset = staging.delete_index; |
| 100 | const std::size_t end_offset = std::min(begin_offset + deletions_per_tick, old_size); | 121 | const size_t end_offset = std::min(begin_offset + deletions_per_tick, old_size); |
| 101 | const auto begin = std::begin(entries) + begin_offset; | 122 | const auto begin = entries.begin() + begin_offset; |
| 102 | const auto end = std::begin(entries) + end_offset; | 123 | const auto end = entries.begin() + end_offset; |
| 103 | entries.erase(std::remove_if(begin, end, is_deleteable), end); | 124 | entries.erase(std::remove_if(begin, end, is_deleteable), end); |
| 104 | 125 | ||
| 105 | const std::size_t new_size = entries.size(); | 126 | const size_t new_size = entries.size(); |
| 106 | staging.delete_index += deletions_per_tick; | 127 | staging.delete_index += deletions_per_tick; |
| 107 | if (staging.delete_index >= new_size) { | 128 | if (staging.delete_index >= new_size) { |
| 108 | staging.delete_index = 0; | 129 | staging.delete_index = 0; |
| 109 | } | 130 | } |
| 110 | 131 | if (staging.iterate_index > new_size) { | |
| 111 | return (1ULL << log2) * (old_size - new_size); | 132 | staging.iterate_index = 0; |
| 133 | } | ||
| 112 | } | 134 | } |
| 113 | 135 | ||
| 114 | } // namespace Vulkan | 136 | } // namespace Vulkan |
diff --git a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h index 90dadcbbe..d42918a47 100644 --- a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h +++ b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h | |||
| @@ -9,7 +9,7 @@ | |||
| 9 | 9 | ||
| 10 | #include "common/common_types.h" | 10 | #include "common/common_types.h" |
| 11 | 11 | ||
| 12 | #include "video_core/renderer_vulkan/vk_memory_manager.h" | 12 | #include "video_core/vulkan_common/vulkan_memory_allocator.h" |
| 13 | #include "video_core/vulkan_common/vulkan_wrapper.h" | 13 | #include "video_core/vulkan_common/vulkan_wrapper.h" |
| 14 | 14 | ||
| 15 | namespace Vulkan { | 15 | namespace Vulkan { |
| @@ -17,55 +17,65 @@ namespace Vulkan { | |||
| 17 | class Device; | 17 | class Device; |
| 18 | class VKScheduler; | 18 | class VKScheduler; |
| 19 | 19 | ||
| 20 | struct VKBuffer final { | 20 | struct StagingBufferRef { |
| 21 | vk::Buffer handle; | 21 | VkBuffer buffer; |
| 22 | VKMemoryCommit commit; | 22 | std::span<u8> mapped_span; |
| 23 | }; | 23 | }; |
| 24 | 24 | ||
| 25 | class VKStagingBufferPool final { | 25 | class StagingBufferPool { |
| 26 | public: | 26 | public: |
| 27 | explicit VKStagingBufferPool(const Device& device, VKMemoryManager& memory_manager, | 27 | explicit StagingBufferPool(const Device& device, MemoryAllocator& memory_allocator, |
| 28 | VKScheduler& scheduler); | 28 | VKScheduler& scheduler); |
| 29 | ~VKStagingBufferPool(); | 29 | ~StagingBufferPool(); |
| 30 | 30 | ||
| 31 | VKBuffer& GetUnusedBuffer(std::size_t size, bool host_visible); | 31 | StagingBufferRef Request(size_t size, MemoryUsage usage); |
| 32 | 32 | ||
| 33 | void TickFrame(); | 33 | void TickFrame(); |
| 34 | 34 | ||
| 35 | private: | 35 | private: |
| 36 | struct StagingBuffer final { | 36 | struct StagingBuffer { |
| 37 | explicit StagingBuffer(std::unique_ptr<VKBuffer> buffer); | 37 | vk::Buffer buffer; |
| 38 | 38 | MemoryCommit commit; | |
| 39 | std::unique_ptr<VKBuffer> buffer; | 39 | std::span<u8> mapped_span; |
| 40 | u64 tick = 0; | 40 | u64 tick = 0; |
| 41 | |||
| 42 | StagingBufferRef Ref() const noexcept { | ||
| 43 | return { | ||
| 44 | .buffer = *buffer, | ||
| 45 | .mapped_span = mapped_span, | ||
| 46 | }; | ||
| 47 | } | ||
| 41 | }; | 48 | }; |
| 42 | 49 | ||
| 43 | struct StagingBuffers final { | 50 | struct StagingBuffers { |
| 44 | std::vector<StagingBuffer> entries; | 51 | std::vector<StagingBuffer> entries; |
| 45 | std::size_t delete_index = 0; | 52 | size_t delete_index = 0; |
| 53 | size_t iterate_index = 0; | ||
| 46 | }; | 54 | }; |
| 47 | 55 | ||
| 48 | static constexpr std::size_t NumLevels = sizeof(std::size_t) * CHAR_BIT; | 56 | static constexpr size_t NUM_LEVELS = sizeof(size_t) * CHAR_BIT; |
| 49 | using StagingBuffersCache = std::array<StagingBuffers, NumLevels>; | 57 | using StagingBuffersCache = std::array<StagingBuffers, NUM_LEVELS>; |
| 50 | 58 | ||
| 51 | VKBuffer* TryGetReservedBuffer(std::size_t size, bool host_visible); | 59 | std::optional<StagingBufferRef> TryGetReservedBuffer(size_t size, MemoryUsage usage); |
| 52 | 60 | ||
| 53 | VKBuffer& CreateStagingBuffer(std::size_t size, bool host_visible); | 61 | StagingBufferRef CreateStagingBuffer(size_t size, MemoryUsage usage); |
| 54 | 62 | ||
| 55 | StagingBuffersCache& GetCache(bool host_visible); | 63 | StagingBuffersCache& GetCache(MemoryUsage usage); |
| 56 | 64 | ||
| 57 | void ReleaseCache(bool host_visible); | 65 | void ReleaseCache(MemoryUsage usage); |
| 58 | 66 | ||
| 59 | u64 ReleaseLevel(StagingBuffersCache& cache, std::size_t log2); | 67 | void ReleaseLevel(StagingBuffersCache& cache, size_t log2); |
| 60 | 68 | ||
| 61 | const Device& device; | 69 | const Device& device; |
| 62 | VKMemoryManager& memory_manager; | 70 | MemoryAllocator& memory_allocator; |
| 63 | VKScheduler& scheduler; | 71 | VKScheduler& scheduler; |
| 64 | 72 | ||
| 65 | StagingBuffersCache host_staging_buffers; | 73 | StagingBuffersCache device_local_cache; |
| 66 | StagingBuffersCache device_staging_buffers; | 74 | StagingBuffersCache upload_cache; |
| 75 | StagingBuffersCache download_cache; | ||
| 67 | 76 | ||
| 68 | std::size_t current_delete_level = 0; | 77 | size_t current_delete_level = 0; |
| 78 | u64 buffer_index = 0; | ||
| 69 | }; | 79 | }; |
| 70 | 80 | ||
| 71 | } // namespace Vulkan | 81 | } // namespace Vulkan |
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index bd11de012..ab14922d7 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp | |||
| @@ -10,12 +10,12 @@ | |||
| 10 | #include "video_core/engines/fermi_2d.h" | 10 | #include "video_core/engines/fermi_2d.h" |
| 11 | #include "video_core/renderer_vulkan/blit_image.h" | 11 | #include "video_core/renderer_vulkan/blit_image.h" |
| 12 | #include "video_core/renderer_vulkan/maxwell_to_vk.h" | 12 | #include "video_core/renderer_vulkan/maxwell_to_vk.h" |
| 13 | #include "video_core/renderer_vulkan/vk_memory_manager.h" | ||
| 14 | #include "video_core/renderer_vulkan/vk_rasterizer.h" | 13 | #include "video_core/renderer_vulkan/vk_rasterizer.h" |
| 15 | #include "video_core/renderer_vulkan/vk_scheduler.h" | 14 | #include "video_core/renderer_vulkan/vk_scheduler.h" |
| 16 | #include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" | 15 | #include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" |
| 17 | #include "video_core/renderer_vulkan/vk_texture_cache.h" | 16 | #include "video_core/renderer_vulkan/vk_texture_cache.h" |
| 18 | #include "video_core/vulkan_common/vulkan_device.h" | 17 | #include "video_core/vulkan_common/vulkan_device.h" |
| 18 | #include "video_core/vulkan_common/vulkan_memory_allocator.h" | ||
| 19 | #include "video_core/vulkan_common/vulkan_wrapper.h" | 19 | #include "video_core/vulkan_common/vulkan_wrapper.h" |
| 20 | 20 | ||
| 21 | namespace Vulkan { | 21 | namespace Vulkan { |
| @@ -554,10 +554,18 @@ void TextureCacheRuntime::Finish() { | |||
| 554 | } | 554 | } |
| 555 | 555 | ||
| 556 | ImageBufferMap TextureCacheRuntime::MapUploadBuffer(size_t size) { | 556 | ImageBufferMap TextureCacheRuntime::MapUploadBuffer(size_t size) { |
| 557 | const auto& buffer = staging_buffer_pool.GetUnusedBuffer(size, true); | 557 | const auto staging_ref = staging_buffer_pool.Request(size, MemoryUsage::Upload); |
| 558 | return ImageBufferMap{ | 558 | return { |
| 559 | .handle = *buffer.handle, | 559 | .handle = staging_ref.buffer, |
| 560 | .map = buffer.commit->Map(size), | 560 | .span = staging_ref.mapped_span, |
| 561 | }; | ||
| 562 | } | ||
| 563 | |||
| 564 | ImageBufferMap TextureCacheRuntime::MapDownloadBuffer(size_t size) { | ||
| 565 | const auto staging_ref = staging_buffer_pool.Request(size, MemoryUsage::Download); | ||
| 566 | return { | ||
| 567 | .handle = staging_ref.buffer, | ||
| 568 | .span = staging_ref.mapped_span, | ||
| 561 | }; | 569 | }; |
| 562 | } | 570 | } |
| 563 | 571 | ||
| @@ -788,9 +796,9 @@ Image::Image(TextureCacheRuntime& runtime, const ImageInfo& info_, GPUVAddr gpu_ | |||
| 788 | image(MakeImage(runtime.device, info)), buffer(MakeBuffer(runtime.device, info)), | 796 | image(MakeImage(runtime.device, info)), buffer(MakeBuffer(runtime.device, info)), |
| 789 | aspect_mask(ImageAspectMask(info.format)) { | 797 | aspect_mask(ImageAspectMask(info.format)) { |
| 790 | if (image) { | 798 | if (image) { |
| 791 | commit = runtime.memory_manager.Commit(image, false); | 799 | commit = runtime.memory_allocator.Commit(image, MemoryUsage::DeviceLocal); |
| 792 | } else { | 800 | } else { |
| 793 | commit = runtime.memory_manager.Commit(buffer, false); | 801 | commit = runtime.memory_allocator.Commit(buffer, MemoryUsage::DeviceLocal); |
| 794 | } | 802 | } |
| 795 | if (IsPixelFormatASTC(info.format) && !runtime.device.IsOptimalAstcSupported()) { | 803 | if (IsPixelFormatASTC(info.format) && !runtime.device.IsOptimalAstcSupported()) { |
| 796 | flags |= VideoCommon::ImageFlagBits::Converted; | 804 | flags |= VideoCommon::ImageFlagBits::Converted; |
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.h b/src/video_core/renderer_vulkan/vk_texture_cache.h index 92a7aad8b..a55d405d1 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.h +++ b/src/video_core/renderer_vulkan/vk_texture_cache.h | |||
| @@ -7,8 +7,8 @@ | |||
| 7 | #include <compare> | 7 | #include <compare> |
| 8 | #include <span> | 8 | #include <span> |
| 9 | 9 | ||
| 10 | #include "video_core/renderer_vulkan/vk_memory_manager.h" | ||
| 11 | #include "video_core/texture_cache/texture_cache.h" | 10 | #include "video_core/texture_cache/texture_cache.h" |
| 11 | #include "video_core/vulkan_common/vulkan_memory_allocator.h" | ||
| 12 | #include "video_core/vulkan_common/vulkan_wrapper.h" | 12 | #include "video_core/vulkan_common/vulkan_wrapper.h" |
| 13 | 13 | ||
| 14 | namespace Vulkan { | 14 | namespace Vulkan { |
| @@ -19,14 +19,13 @@ using VideoCommon::Offset2D; | |||
| 19 | using VideoCommon::RenderTargets; | 19 | using VideoCommon::RenderTargets; |
| 20 | using VideoCore::Surface::PixelFormat; | 20 | using VideoCore::Surface::PixelFormat; |
| 21 | 21 | ||
| 22 | class VKScheduler; | ||
| 23 | class VKStagingBufferPool; | ||
| 24 | |||
| 25 | class BlitImageHelper; | 22 | class BlitImageHelper; |
| 26 | class Device; | 23 | class Device; |
| 27 | class Image; | 24 | class Image; |
| 28 | class ImageView; | 25 | class ImageView; |
| 29 | class Framebuffer; | 26 | class Framebuffer; |
| 27 | class StagingBufferPool; | ||
| 28 | class VKScheduler; | ||
| 30 | 29 | ||
| 31 | struct RenderPassKey { | 30 | struct RenderPassKey { |
| 32 | constexpr auto operator<=>(const RenderPassKey&) const noexcept = default; | 31 | constexpr auto operator<=>(const RenderPassKey&) const noexcept = default; |
| @@ -60,18 +59,18 @@ struct ImageBufferMap { | |||
| 60 | } | 59 | } |
| 61 | 60 | ||
| 62 | [[nodiscard]] std::span<u8> Span() const noexcept { | 61 | [[nodiscard]] std::span<u8> Span() const noexcept { |
| 63 | return map.Span(); | 62 | return span; |
| 64 | } | 63 | } |
| 65 | 64 | ||
| 66 | VkBuffer handle; | 65 | VkBuffer handle; |
| 67 | MemoryMap map; | 66 | std::span<u8> span; |
| 68 | }; | 67 | }; |
| 69 | 68 | ||
| 70 | struct TextureCacheRuntime { | 69 | struct TextureCacheRuntime { |
| 71 | const Device& device; | 70 | const Device& device; |
| 72 | VKScheduler& scheduler; | 71 | VKScheduler& scheduler; |
| 73 | VKMemoryManager& memory_manager; | 72 | MemoryAllocator& memory_allocator; |
| 74 | VKStagingBufferPool& staging_buffer_pool; | 73 | StagingBufferPool& staging_buffer_pool; |
| 75 | BlitImageHelper& blit_image_helper; | 74 | BlitImageHelper& blit_image_helper; |
| 76 | std::unordered_map<RenderPassKey, vk::RenderPass> renderpass_cache; | 75 | std::unordered_map<RenderPassKey, vk::RenderPass> renderpass_cache; |
| 77 | 76 | ||
| @@ -79,10 +78,7 @@ struct TextureCacheRuntime { | |||
| 79 | 78 | ||
| 80 | [[nodiscard]] ImageBufferMap MapUploadBuffer(size_t size); | 79 | [[nodiscard]] ImageBufferMap MapUploadBuffer(size_t size); |
| 81 | 80 | ||
| 82 | [[nodiscard]] ImageBufferMap MapDownloadBuffer(size_t size) { | 81 | [[nodiscard]] ImageBufferMap MapDownloadBuffer(size_t size); |
| 83 | // TODO: Have a special function for this | ||
| 84 | return MapUploadBuffer(size); | ||
| 85 | } | ||
| 86 | 82 | ||
| 87 | void BlitImage(Framebuffer* dst_framebuffer, ImageView& dst, ImageView& src, | 83 | void BlitImage(Framebuffer* dst_framebuffer, ImageView& dst, ImageView& src, |
| 88 | const std::array<Offset2D, 2>& dst_region, | 84 | const std::array<Offset2D, 2>& dst_region, |
| @@ -141,7 +137,7 @@ private: | |||
| 141 | VKScheduler* scheduler; | 137 | VKScheduler* scheduler; |
| 142 | vk::Image image; | 138 | vk::Image image; |
| 143 | vk::Buffer buffer; | 139 | vk::Buffer buffer; |
| 144 | VKMemoryCommit commit; | 140 | MemoryCommit commit; |
| 145 | VkImageAspectFlags aspect_mask = 0; | 141 | VkImageAspectFlags aspect_mask = 0; |
| 146 | bool initialized = false; | 142 | bool initialized = false; |
| 147 | }; | 143 | }; |
diff --git a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp new file mode 100644 index 000000000..d6eb3af31 --- /dev/null +++ b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp | |||
| @@ -0,0 +1,268 @@ | |||
| 1 | // Copyright 2018 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <algorithm> | ||
| 6 | #include <bit> | ||
| 7 | #include <optional> | ||
| 8 | #include <vector> | ||
| 9 | |||
| 10 | #include "common/alignment.h" | ||
| 11 | #include "common/assert.h" | ||
| 12 | #include "common/common_types.h" | ||
| 13 | #include "common/logging/log.h" | ||
| 14 | #include "video_core/vulkan_common/vulkan_device.h" | ||
| 15 | #include "video_core/vulkan_common/vulkan_memory_allocator.h" | ||
| 16 | #include "video_core/vulkan_common/vulkan_wrapper.h" | ||
| 17 | |||
| 18 | namespace Vulkan { | ||
| 19 | namespace { | ||
| 20 | struct Range { | ||
| 21 | u64 begin; | ||
| 22 | u64 end; | ||
| 23 | |||
| 24 | [[nodiscard]] bool Contains(u64 iterator, u64 size) const noexcept { | ||
| 25 | return iterator < end && begin < iterator + size; | ||
| 26 | } | ||
| 27 | }; | ||
| 28 | |||
| 29 | [[nodiscard]] u64 AllocationChunkSize(u64 required_size) { | ||
| 30 | static constexpr std::array sizes{ | ||
| 31 | 0x1000ULL << 10, 0x1400ULL << 10, 0x1800ULL << 10, 0x1c00ULL << 10, 0x2000ULL << 10, | ||
| 32 | 0x3200ULL << 10, 0x4000ULL << 10, 0x6000ULL << 10, 0x8000ULL << 10, 0xA000ULL << 10, | ||
| 33 | 0x10000ULL << 10, 0x18000ULL << 10, 0x20000ULL << 10, | ||
| 34 | }; | ||
| 35 | static_assert(std::is_sorted(sizes.begin(), sizes.end())); | ||
| 36 | |||
| 37 | const auto it = std::ranges::lower_bound(sizes, required_size); | ||
| 38 | return it != sizes.end() ? *it : Common::AlignUp(required_size, 4ULL << 20); | ||
| 39 | } | ||
| 40 | |||
| 41 | [[nodiscard]] VkMemoryPropertyFlags MemoryUsagePropertyFlags(MemoryUsage usage) { | ||
| 42 | switch (usage) { | ||
| 43 | case MemoryUsage::DeviceLocal: | ||
| 44 | return VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; | ||
| 45 | case MemoryUsage::Upload: | ||
| 46 | return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; | ||
| 47 | case MemoryUsage::Download: | ||
| 48 | return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | | ||
| 49 | VK_MEMORY_PROPERTY_HOST_CACHED_BIT; | ||
| 50 | } | ||
| 51 | UNREACHABLE_MSG("Invalid memory usage={}", usage); | ||
| 52 | return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; | ||
| 53 | } | ||
| 54 | } // Anonymous namespace | ||
| 55 | |||
| 56 | class MemoryAllocation { | ||
| 57 | public: | ||
| 58 | explicit MemoryAllocation(const Device& device_, vk::DeviceMemory memory_, | ||
| 59 | VkMemoryPropertyFlags properties, u64 allocation_size_, u32 type) | ||
| 60 | : device{device_}, memory{std::move(memory_)}, allocation_size{allocation_size_}, | ||
| 61 | property_flags{properties}, shifted_memory_type{1U << type} {} | ||
| 62 | |||
| 63 | [[nodiscard]] std::optional<MemoryCommit> Commit(VkDeviceSize size, VkDeviceSize alignment) { | ||
| 64 | const std::optional<u64> alloc = FindFreeRegion(size, alignment); | ||
| 65 | if (!alloc) { | ||
| 66 | // Signal out of memory, it'll try to do more allocations. | ||
| 67 | return std::nullopt; | ||
| 68 | } | ||
| 69 | const Range range{ | ||
| 70 | .begin = *alloc, | ||
| 71 | .end = *alloc + size, | ||
| 72 | }; | ||
| 73 | commits.insert(std::ranges::upper_bound(commits, *alloc, {}, &Range::begin), range); | ||
| 74 | return std::make_optional<MemoryCommit>(this, *memory, *alloc, *alloc + size); | ||
| 75 | } | ||
| 76 | |||
| 77 | void Free(u64 begin) { | ||
| 78 | const auto it = std::ranges::find(commits, begin, &Range::begin); | ||
| 79 | ASSERT_MSG(it != commits.end(), "Invalid commit"); | ||
| 80 | commits.erase(it); | ||
| 81 | } | ||
| 82 | |||
| 83 | [[nodiscard]] std::span<u8> Map() { | ||
| 84 | if (memory_mapped_span.empty()) { | ||
| 85 | u8* const raw_pointer = memory.Map(0, allocation_size); | ||
| 86 | memory_mapped_span = std::span<u8>(raw_pointer, allocation_size); | ||
| 87 | } | ||
| 88 | return memory_mapped_span; | ||
| 89 | } | ||
| 90 | |||
| 91 | /// Returns whether this allocation is compatible with the arguments. | ||
| 92 | [[nodiscard]] bool IsCompatible(VkMemoryPropertyFlags flags, u32 type_mask) const { | ||
| 93 | return (flags & property_flags) && (type_mask & shifted_memory_type) != 0; | ||
| 94 | } | ||
| 95 | |||
| 96 | private: | ||
| 97 | [[nodiscard]] static constexpr u32 ShiftType(u32 type) { | ||
| 98 | return 1U << type; | ||
| 99 | } | ||
| 100 | |||
| 101 | [[nodiscard]] std::optional<u64> FindFreeRegion(u64 size, u64 alignment) noexcept { | ||
| 102 | ASSERT(std::has_single_bit(alignment)); | ||
| 103 | const u64 alignment_log2 = std::countr_zero(alignment); | ||
| 104 | std::optional<u64> candidate; | ||
| 105 | u64 iterator = 0; | ||
| 106 | auto commit = commits.begin(); | ||
| 107 | while (iterator + size <= allocation_size) { | ||
| 108 | candidate = candidate.value_or(iterator); | ||
| 109 | if (commit == commits.end()) { | ||
| 110 | break; | ||
| 111 | } | ||
| 112 | if (commit->Contains(*candidate, size)) { | ||
| 113 | candidate = std::nullopt; | ||
| 114 | } | ||
| 115 | iterator = Common::AlignUpLog2(commit->end, alignment_log2); | ||
| 116 | ++commit; | ||
| 117 | } | ||
| 118 | return candidate; | ||
| 119 | } | ||
| 120 | |||
| 121 | const Device& device; ///< Vulkan device. | ||
| 122 | const vk::DeviceMemory memory; ///< Vulkan memory allocation handler. | ||
| 123 | const u64 allocation_size; ///< Size of this allocation. | ||
| 124 | const VkMemoryPropertyFlags property_flags; ///< Vulkan memory property flags. | ||
| 125 | const u32 shifted_memory_type; ///< Shifted Vulkan memory type. | ||
| 126 | std::vector<Range> commits; ///< All commit ranges done from this allocation. | ||
| 127 | std::span<u8> memory_mapped_span; ///< Memory mapped span. Empty if not queried before. | ||
| 128 | }; | ||
| 129 | |||
| 130 | MemoryCommit::MemoryCommit(MemoryAllocation* allocation_, VkDeviceMemory memory_, u64 begin_, | ||
| 131 | u64 end_) noexcept | ||
| 132 | : allocation{allocation_}, memory{memory_}, begin{begin_}, end{end_} {} | ||
| 133 | |||
| 134 | MemoryCommit::~MemoryCommit() { | ||
| 135 | Release(); | ||
| 136 | } | ||
| 137 | |||
| 138 | MemoryCommit& MemoryCommit::operator=(MemoryCommit&& rhs) noexcept { | ||
| 139 | Release(); | ||
| 140 | allocation = std::exchange(rhs.allocation, nullptr); | ||
| 141 | memory = rhs.memory; | ||
| 142 | begin = rhs.begin; | ||
| 143 | end = rhs.end; | ||
| 144 | span = std::exchange(rhs.span, std::span<u8>{}); | ||
| 145 | return *this; | ||
| 146 | } | ||
| 147 | |||
| 148 | MemoryCommit::MemoryCommit(MemoryCommit&& rhs) noexcept | ||
| 149 | : allocation{std::exchange(rhs.allocation, nullptr)}, memory{rhs.memory}, begin{rhs.begin}, | ||
| 150 | end{rhs.end}, span{std::exchange(rhs.span, std::span<u8>{})} {} | ||
| 151 | |||
| 152 | std::span<u8> MemoryCommit::Map() { | ||
| 153 | if (span.empty()) { | ||
| 154 | span = allocation->Map().subspan(begin, end - begin); | ||
| 155 | } | ||
| 156 | return span; | ||
| 157 | } | ||
| 158 | |||
| 159 | void MemoryCommit::Release() { | ||
| 160 | if (allocation) { | ||
| 161 | allocation->Free(begin); | ||
| 162 | } | ||
| 163 | } | ||
| 164 | |||
| 165 | MemoryAllocator::MemoryAllocator(const Device& device_) | ||
| 166 | : device{device_}, properties{device_.GetPhysical().GetMemoryProperties()} {} | ||
| 167 | |||
| 168 | MemoryAllocator::~MemoryAllocator() = default; | ||
| 169 | |||
| 170 | MemoryCommit MemoryAllocator::Commit(const VkMemoryRequirements& requirements, MemoryUsage usage) { | ||
| 171 | // Find the fastest memory flags we can afford with the current requirements | ||
| 172 | const VkMemoryPropertyFlags flags = MemoryPropertyFlags(requirements.memoryTypeBits, usage); | ||
| 173 | if (std::optional<MemoryCommit> commit = TryCommit(requirements, flags)) { | ||
| 174 | return std::move(*commit); | ||
| 175 | } | ||
| 176 | // Commit has failed, allocate more memory. | ||
| 177 | // TODO(Rodrigo): Handle out of memory situations in some way like flushing to guest memory. | ||
| 178 | AllocMemory(flags, requirements.memoryTypeBits, AllocationChunkSize(requirements.size)); | ||
| 179 | |||
| 180 | // Commit again, this time it won't fail since there's a fresh allocation above. | ||
| 181 | // If it does, there's a bug. | ||
| 182 | return TryCommit(requirements, flags).value(); | ||
| 183 | } | ||
| 184 | |||
| 185 | MemoryCommit MemoryAllocator::Commit(const vk::Buffer& buffer, MemoryUsage usage) { | ||
| 186 | auto commit = Commit(device.GetLogical().GetBufferMemoryRequirements(*buffer), usage); | ||
| 187 | buffer.BindMemory(commit.Memory(), commit.Offset()); | ||
| 188 | return commit; | ||
| 189 | } | ||
| 190 | |||
| 191 | MemoryCommit MemoryAllocator::Commit(const vk::Image& image, MemoryUsage usage) { | ||
| 192 | auto commit = Commit(device.GetLogical().GetImageMemoryRequirements(*image), usage); | ||
| 193 | image.BindMemory(commit.Memory(), commit.Offset()); | ||
| 194 | return commit; | ||
| 195 | } | ||
| 196 | |||
| 197 | void MemoryAllocator::AllocMemory(VkMemoryPropertyFlags flags, u32 type_mask, u64 size) { | ||
| 198 | const u32 type = FindType(flags, type_mask).value(); | ||
| 199 | vk::DeviceMemory memory = device.GetLogical().AllocateMemory({ | ||
| 200 | .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, | ||
| 201 | .pNext = nullptr, | ||
| 202 | .allocationSize = size, | ||
| 203 | .memoryTypeIndex = type, | ||
| 204 | }); | ||
| 205 | allocations.push_back( | ||
| 206 | std::make_unique<MemoryAllocation>(device, std::move(memory), flags, size, type)); | ||
| 207 | } | ||
| 208 | |||
| 209 | std::optional<MemoryCommit> MemoryAllocator::TryCommit(const VkMemoryRequirements& requirements, | ||
| 210 | VkMemoryPropertyFlags flags) { | ||
| 211 | for (auto& allocation : allocations) { | ||
| 212 | if (!allocation->IsCompatible(flags, requirements.memoryTypeBits)) { | ||
| 213 | continue; | ||
| 214 | } | ||
| 215 | if (auto commit = allocation->Commit(requirements.size, requirements.alignment)) { | ||
| 216 | return commit; | ||
| 217 | } | ||
| 218 | } | ||
| 219 | return std::nullopt; | ||
| 220 | } | ||
| 221 | |||
| 222 | VkMemoryPropertyFlags MemoryAllocator::MemoryPropertyFlags(u32 type_mask, MemoryUsage usage) const { | ||
| 223 | return MemoryPropertyFlags(type_mask, MemoryUsagePropertyFlags(usage)); | ||
| 224 | } | ||
| 225 | |||
| 226 | VkMemoryPropertyFlags MemoryAllocator::MemoryPropertyFlags(u32 type_mask, | ||
| 227 | VkMemoryPropertyFlags flags) const { | ||
| 228 | if (FindType(flags, type_mask)) { | ||
| 229 | // Found a memory type with those requirements | ||
| 230 | return flags; | ||
| 231 | } | ||
| 232 | if (flags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) { | ||
| 233 | // Remove host cached bit in case it's not supported | ||
| 234 | return MemoryPropertyFlags(type_mask, flags & ~VK_MEMORY_PROPERTY_HOST_CACHED_BIT); | ||
| 235 | } | ||
| 236 | if (flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) { | ||
| 237 | // Remove device local, if it's not supported by the requested resource | ||
| 238 | return MemoryPropertyFlags(type_mask, flags & ~VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); | ||
| 239 | } | ||
| 240 | UNREACHABLE_MSG("No compatible memory types found"); | ||
| 241 | return 0; | ||
| 242 | } | ||
| 243 | |||
| 244 | std::optional<u32> MemoryAllocator::FindType(VkMemoryPropertyFlags flags, u32 type_mask) const { | ||
| 245 | for (u32 type_index = 0; type_index < properties.memoryTypeCount; ++type_index) { | ||
| 246 | const VkMemoryPropertyFlags type_flags = properties.memoryTypes[type_index].propertyFlags; | ||
| 247 | if ((type_mask & (1U << type_index)) && (type_flags & flags)) { | ||
| 248 | // The type matches in type and in the wanted properties. | ||
| 249 | return type_index; | ||
| 250 | } | ||
| 251 | } | ||
| 252 | // Failed to find index | ||
| 253 | return std::nullopt; | ||
| 254 | } | ||
| 255 | |||
| 256 | bool IsHostVisible(MemoryUsage usage) noexcept { | ||
| 257 | switch (usage) { | ||
| 258 | case MemoryUsage::DeviceLocal: | ||
| 259 | return false; | ||
| 260 | case MemoryUsage::Upload: | ||
| 261 | case MemoryUsage::Download: | ||
| 262 | return true; | ||
| 263 | } | ||
| 264 | UNREACHABLE_MSG("Invalid memory usage={}", usage); | ||
| 265 | return false; | ||
| 266 | } | ||
| 267 | |||
| 268 | } // namespace Vulkan | ||
diff --git a/src/video_core/vulkan_common/vulkan_memory_allocator.h b/src/video_core/vulkan_common/vulkan_memory_allocator.h new file mode 100644 index 000000000..53b3b275a --- /dev/null +++ b/src/video_core/vulkan_common/vulkan_memory_allocator.h | |||
| @@ -0,0 +1,118 @@ | |||
| 1 | // Copyright 2019 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <memory> | ||
| 8 | #include <span> | ||
| 9 | #include <utility> | ||
| 10 | #include <vector> | ||
| 11 | #include "common/common_types.h" | ||
| 12 | #include "video_core/vulkan_common/vulkan_wrapper.h" | ||
| 13 | |||
| 14 | namespace Vulkan { | ||
| 15 | |||
| 16 | class Device; | ||
| 17 | class MemoryMap; | ||
| 18 | class MemoryAllocation; | ||
| 19 | |||
| 20 | /// Hints and requirements for the backing memory type of a commit | ||
| 21 | enum class MemoryUsage { | ||
| 22 | DeviceLocal, ///< Hints device local usages, fastest memory type to read and write from the GPU | ||
| 23 | Upload, ///< Requires a host visible memory type optimized for CPU to GPU uploads | ||
| 24 | Download, ///< Requires a host visible memory type optimized for GPU to CPU readbacks | ||
| 25 | }; | ||
| 26 | |||
| 27 | /// Ownership handle of a memory commitment. | ||
| 28 | /// Points to a subregion of a memory allocation. | ||
| 29 | class MemoryCommit { | ||
| 30 | public: | ||
| 31 | explicit MemoryCommit() noexcept = default; | ||
| 32 | explicit MemoryCommit(MemoryAllocation* allocation_, VkDeviceMemory memory_, u64 begin_, | ||
| 33 | u64 end_) noexcept; | ||
| 34 | ~MemoryCommit(); | ||
| 35 | |||
| 36 | MemoryCommit& operator=(MemoryCommit&&) noexcept; | ||
| 37 | MemoryCommit(MemoryCommit&&) noexcept; | ||
| 38 | |||
| 39 | MemoryCommit& operator=(const MemoryCommit&) = delete; | ||
| 40 | MemoryCommit(const MemoryCommit&) = delete; | ||
| 41 | |||
| 42 | /// Returns a host visible memory map. | ||
| 43 | /// It will map the backing allocation if it hasn't been mapped before. | ||
| 44 | std::span<u8> Map(); | ||
| 45 | |||
| 46 | /// Returns the Vulkan memory handler. | ||
| 47 | VkDeviceMemory Memory() const { | ||
| 48 | return memory; | ||
| 49 | } | ||
| 50 | |||
| 51 | /// Returns the start position of the commit relative to the allocation. | ||
| 52 | VkDeviceSize Offset() const { | ||
| 53 | return static_cast<VkDeviceSize>(begin); | ||
| 54 | } | ||
| 55 | |||
| 56 | private: | ||
| 57 | void Release(); | ||
| 58 | |||
| 59 | MemoryAllocation* allocation{}; ///< Pointer to the large memory allocation. | ||
| 60 | VkDeviceMemory memory{}; ///< Vulkan device memory handler. | ||
| 61 | u64 begin{}; ///< Beginning offset in bytes to where the commit exists. | ||
| 62 | u64 end{}; ///< Offset in bytes where the commit ends. | ||
| 63 | std::span<u8> span; ///< Host visible memory span. Empty if not queried before. | ||
| 64 | }; | ||
| 65 | |||
| 66 | /// Memory allocator container. | ||
| 67 | /// Allocates and releases memory allocations on demand. | ||
| 68 | class MemoryAllocator { | ||
| 69 | public: | ||
| 70 | explicit MemoryAllocator(const Device& device_); | ||
| 71 | ~MemoryAllocator(); | ||
| 72 | |||
| 73 | MemoryAllocator& operator=(const MemoryAllocator&) = delete; | ||
| 74 | MemoryAllocator(const MemoryAllocator&) = delete; | ||
| 75 | |||
| 76 | /** | ||
| 77 | * Commits a memory with the specified requeriments. | ||
| 78 | * | ||
| 79 | * @param requirements Requirements returned from a Vulkan call. | ||
| 80 | * @param host_visible Signals the allocator that it *must* use host visible and coherent | ||
| 81 | * memory. When passing false, it will try to allocate device local memory. | ||
| 82 | * | ||
| 83 | * @returns A memory commit. | ||
| 84 | */ | ||
| 85 | MemoryCommit Commit(const VkMemoryRequirements& requirements, MemoryUsage usage); | ||
| 86 | |||
| 87 | /// Commits memory required by the buffer and binds it. | ||
| 88 | MemoryCommit Commit(const vk::Buffer& buffer, MemoryUsage usage); | ||
| 89 | |||
| 90 | /// Commits memory required by the image and binds it. | ||
| 91 | MemoryCommit Commit(const vk::Image& image, MemoryUsage usage); | ||
| 92 | |||
| 93 | private: | ||
| 94 | /// Allocates a chunk of memory. | ||
| 95 | void AllocMemory(VkMemoryPropertyFlags flags, u32 type_mask, u64 size); | ||
| 96 | |||
| 97 | /// Tries to allocate a memory commit. | ||
| 98 | std::optional<MemoryCommit> TryCommit(const VkMemoryRequirements& requirements, | ||
| 99 | VkMemoryPropertyFlags flags); | ||
| 100 | |||
| 101 | /// Returns the fastest compatible memory property flags from a wanted usage. | ||
| 102 | VkMemoryPropertyFlags MemoryPropertyFlags(u32 type_mask, MemoryUsage usage) const; | ||
| 103 | |||
| 104 | /// Returns the fastest compatible memory property flags from the wanted flags. | ||
| 105 | VkMemoryPropertyFlags MemoryPropertyFlags(u32 type_mask, VkMemoryPropertyFlags flags) const; | ||
| 106 | |||
| 107 | /// Returns index to the fastest memory type compatible with the passed requirements. | ||
| 108 | std::optional<u32> FindType(VkMemoryPropertyFlags flags, u32 type_mask) const; | ||
| 109 | |||
| 110 | const Device& device; ///< Device handle. | ||
| 111 | const VkPhysicalDeviceMemoryProperties properties; ///< Physical device properties. | ||
| 112 | std::vector<std::unique_ptr<MemoryAllocation>> allocations; ///< Current allocations. | ||
| 113 | }; | ||
| 114 | |||
| 115 | /// Returns true when a memory usage is guaranteed to be host visible. | ||
| 116 | bool IsHostVisible(MemoryUsage usage) noexcept; | ||
| 117 | |||
| 118 | } // namespace Vulkan | ||