From e996f1ad09dcfe1e9eaa0273b710560a44d9a1da Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Wed, 30 Dec 2020 22:58:05 -0300 Subject: vk_memory_manager: Improve memory manager and its API Fix a bug where the memory allocator could leave gaps between commits. To fix this the allocation algorithm was reworked, although it's still short in number of lines of code. Rework the allocation API to self-contained movable objects instead of naively using an unique_ptr to do the job for us. Remove the VK prefix. --- src/video_core/renderer_vulkan/vk_blit_screen.cpp | 12 +- src/video_core/renderer_vulkan/vk_blit_screen.h | 4 +- src/video_core/renderer_vulkan/vk_buffer_cache.cpp | 30 ++- src/video_core/renderer_vulkan/vk_buffer_cache.h | 15 +- src/video_core/renderer_vulkan/vk_compute_pass.cpp | 32 +-- src/video_core/renderer_vulkan/vk_compute_pass.h | 14 +- .../renderer_vulkan/vk_memory_manager.cpp | 237 ++++++++++----------- src/video_core/renderer_vulkan/vk_memory_manager.h | 139 +++++------- src/video_core/renderer_vulkan/vk_rasterizer.h | 4 +- .../renderer_vulkan/vk_staging_buffer_pool.cpp | 106 ++++----- .../renderer_vulkan/vk_staging_buffer_pool.h | 49 +++-- .../renderer_vulkan/vk_texture_cache.cpp | 6 +- src/video_core/renderer_vulkan/vk_texture_cache.h | 13 +- 13 files changed, 318 insertions(+), 343 deletions(-) (limited to 'src') diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.cpp b/src/video_core/renderer_vulkan/vk_blit_screen.cpp index 5e184eb42..d8261526a 100644 --- a/src/video_core/renderer_vulkan/vk_blit_screen.cpp +++ b/src/video_core/renderer_vulkan/vk_blit_screen.cpp @@ -150,8 +150,8 @@ VkSemaphore VKBlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer, bool SetUniformData(data, framebuffer); SetVertexData(data, framebuffer); - auto map = buffer_commit->Map(); - std::memcpy(map.Address(), &data, sizeof(data)); + const std::span map = buffer_commit.Map(); + std::memcpy(map.data(), &data, sizeof(data)); if (!use_accelerated) { const u64 image_offset = GetRawImageOffset(framebuffer, image_index); @@ -165,8 +165,8 @@ VkSemaphore VKBlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer, bool constexpr u32 block_height_log2 = 4; const u32 bytes_per_pixel = GetBytesPerPixel(framebuffer); Tegra::Texture::UnswizzleTexture( - std::span(map.Address() + image_offset, size_bytes), std::span(host_ptr, size_bytes), - bytes_per_pixel, framebuffer.width, framebuffer.height, 1, block_height_log2, 0); + map.subspan(image_offset, size_bytes), std::span(host_ptr, size_bytes), bytes_per_pixel, + framebuffer.width, framebuffer.height, 1, block_height_log2, 0); const VkBufferImageCopy copy{ .bufferOffset = image_offset, @@ -224,8 +224,6 @@ VkSemaphore VKBlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer, bool VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, write_barrier); }); } - map.Release(); - scheduler.Record([renderpass = *renderpass, framebuffer = *framebuffers[image_index], descriptor_set = descriptor_sets[image_index], buffer = *buffer, size = swapchain.GetSize(), pipeline = *pipeline, @@ -642,7 +640,7 @@ void VKBlitScreen::ReleaseRawImages() { raw_images.clear(); raw_buffer_commits.clear(); buffer.reset(); - buffer_commit.reset(); + buffer_commit = MemoryCommit{}; } void VKBlitScreen::CreateStagingBuffer(const Tegra::FramebufferConfig& framebuffer) { diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.h b/src/video_core/renderer_vulkan/vk_blit_screen.h index 69ed61770..1aa8e3182 100644 --- a/src/video_core/renderer_vulkan/vk_blit_screen.h +++ b/src/video_core/renderer_vulkan/vk_blit_screen.h @@ -104,14 +104,14 @@ private: vk::Sampler sampler; vk::Buffer buffer; - VKMemoryCommit buffer_commit; + MemoryCommit buffer_commit; std::vector resource_ticks; std::vector semaphores; std::vector raw_images; std::vector raw_image_views; - std::vector raw_buffer_commits; + std::vector raw_buffer_commits; u32 raw_width = 0; u32 raw_height = 0; }; diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp index 58c710344..94c2e101b 100644 --- a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp @@ -37,10 +37,10 @@ constexpr VkAccessFlags TRANSFORM_FEEDBACK_WRITE_ACCESS = } // Anonymous namespace Buffer::Buffer(const Device& device_, VKMemoryManager& memory_manager, VKScheduler& scheduler_, - VKStagingBufferPool& staging_pool_, VAddr cpu_addr_, std::size_t size_) + StagingBufferPool& staging_pool_, VAddr cpu_addr_, std::size_t size_) : BufferBlock{cpu_addr_, size_}, device{device_}, scheduler{scheduler_}, staging_pool{ staging_pool_} { - const VkBufferCreateInfo ci{ + buffer = device.GetLogical().CreateBuffer(VkBufferCreateInfo{ .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, .pNext = nullptr, .flags = 0, @@ -49,22 +49,20 @@ Buffer::Buffer(const Device& device_, VKMemoryManager& memory_manager, VKSchedul .sharingMode = VK_SHARING_MODE_EXCLUSIVE, .queueFamilyIndexCount = 0, .pQueueFamilyIndices = nullptr, - }; - - buffer.handle = device.GetLogical().CreateBuffer(ci); - buffer.commit = memory_manager.Commit(buffer.handle, false); + }); + commit = memory_manager.Commit(buffer, false); } Buffer::~Buffer() = default; void Buffer::Upload(std::size_t offset, std::size_t data_size, const u8* data) { - const auto& staging = staging_pool.GetUnusedBuffer(data_size, true); - std::memcpy(staging.commit->Map(data_size), data, data_size); + const auto& staging = staging_pool.Request(data_size, true); + std::memcpy(staging.mapped_span.data(), data, data_size); scheduler.RequestOutsideRenderPassOperationContext(); const VkBuffer handle = Handle(); - scheduler.Record([staging = *staging.handle, handle, offset, data_size, + scheduler.Record([staging = staging.buffer, handle, offset, data_size, &device = device](vk::CommandBuffer cmdbuf) { const VkBufferMemoryBarrier read_barrier{ .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) { } void Buffer::Download(std::size_t offset, std::size_t data_size, u8* data) { - const auto& staging = staging_pool.GetUnusedBuffer(data_size, true); + auto staging = staging_pool.Request(data_size, true); scheduler.RequestOutsideRenderPassOperationContext(); const VkBuffer handle = Handle(); scheduler.Record( - [staging = *staging.handle, handle, offset, data_size](vk::CommandBuffer cmdbuf) { + [staging = staging.buffer, handle, offset, data_size](vk::CommandBuffer cmdbuf) { const VkBufferMemoryBarrier barrier{ .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, .pNext = nullptr, @@ -126,7 +124,7 @@ void Buffer::Download(std::size_t offset, std::size_t data_size, u8* data) { }); scheduler.Finish(); - std::memcpy(data, staging.commit->Map(data_size), data_size); + std::memcpy(data, staging.mapped_span.data(), data_size); } void Buffer::CopyFrom(const Buffer& src, std::size_t src_offset, std::size_t dst_offset, @@ -166,7 +164,7 @@ VKBufferCache::VKBufferCache(VideoCore::RasterizerInterface& rasterizer_, Tegra::MemoryManager& gpu_memory_, Core::Memory::Memory& cpu_memory_, const Device& device_, VKMemoryManager& memory_manager_, VKScheduler& scheduler_, VKStreamBuffer& stream_buffer_, - VKStagingBufferPool& staging_pool_) + StagingBufferPool& staging_pool_) : VideoCommon::BufferCache{rasterizer_, gpu_memory_, cpu_memory_, stream_buffer_}, device{device_}, memory_manager{memory_manager_}, scheduler{scheduler_}, staging_pool{ @@ -181,12 +179,12 @@ std::shared_ptr VKBufferCache::CreateBlock(VAddr cpu_addr, std::size_t s VKBufferCache::BufferInfo VKBufferCache::GetEmptyBuffer(std::size_t size) { size = std::max(size, std::size_t(4)); - const auto& empty = staging_pool.GetUnusedBuffer(size, false); + const auto& empty = staging_pool.Request(size, false); scheduler.RequestOutsideRenderPassOperationContext(); - scheduler.Record([size, buffer = *empty.handle](vk::CommandBuffer cmdbuf) { + scheduler.Record([size, buffer = empty.buffer](vk::CommandBuffer cmdbuf) { cmdbuf.FillBuffer(buffer, 0, size, 0); }); - return {*empty.handle, 0, 0}; + return {empty.buffer, 0, 0}; } } // 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..e54c107f2 100644 --- a/src/video_core/renderer_vulkan/vk_buffer_cache.h +++ b/src/video_core/renderer_vulkan/vk_buffer_cache.h @@ -10,19 +10,19 @@ #include "video_core/buffer_cache/buffer_cache.h" #include "video_core/renderer_vulkan/vk_memory_manager.h" #include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" +#include "video_core/renderer_vulkan/vk_memory_manager.h" #include "video_core/renderer_vulkan/vk_stream_buffer.h" #include "video_core/vulkan_common/vulkan_wrapper.h" namespace Vulkan { class Device; -class VKMemoryManager; class VKScheduler; class Buffer final : public VideoCommon::BufferBlock { public: explicit Buffer(const Device& device, VKMemoryManager& memory_manager, VKScheduler& scheduler, - VKStagingBufferPool& staging_pool, VAddr cpu_addr_, std::size_t size_); + StagingBufferPool& staging_pool, VAddr cpu_addr_, std::size_t size_); ~Buffer(); void Upload(std::size_t offset, std::size_t data_size, const u8* data); @@ -33,7 +33,7 @@ public: std::size_t copy_size); VkBuffer Handle() const { - return *buffer.handle; + return *buffer; } u64 Address() const { @@ -43,9 +43,10 @@ public: private: const Device& device; VKScheduler& scheduler; - VKStagingBufferPool& staging_pool; + StagingBufferPool& staging_pool; - VKBuffer buffer; + vk::Buffer buffer; + MemoryCommit commit; }; class VKBufferCache final : public VideoCommon::BufferCache { @@ -54,7 +55,7 @@ public: Tegra::MemoryManager& gpu_memory, Core::Memory::Memory& cpu_memory, const Device& device, VKMemoryManager& memory_manager, VKScheduler& scheduler, VKStreamBuffer& stream_buffer, - VKStagingBufferPool& staging_pool); + StagingBufferPool& staging_pool); ~VKBufferCache(); BufferInfo GetEmptyBuffer(std::size_t size) override; @@ -66,7 +67,7 @@ private: const Device& device; VKMemoryManager& memory_manager; VKScheduler& scheduler; - VKStagingBufferPool& staging_pool; + StagingBufferPool& staging_pool; }; } // 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..d38087f41 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( QuadArrayPass::QuadArrayPass(const Device& device_, VKScheduler& scheduler_, VKDescriptorPool& descriptor_pool_, - VKStagingBufferPool& staging_buffer_pool_, + StagingBufferPool& staging_buffer_pool_, VKUpdateDescriptorQueue& update_descriptor_queue_) : VKComputePass(device_, descriptor_pool_, BuildQuadArrayPassDescriptorSetLayoutBinding(), BuildQuadArrayPassDescriptorUpdateTemplateEntry(), @@ -177,18 +177,18 @@ QuadArrayPass::~QuadArrayPass() = default; std::pair QuadArrayPass::Assemble(u32 num_vertices, u32 first) { const u32 num_triangle_vertices = (num_vertices / 4) * 6; const std::size_t staging_size = num_triangle_vertices * sizeof(u32); - auto& buffer = staging_buffer_pool.GetUnusedBuffer(staging_size, false); + const auto staging_ref = staging_buffer_pool.Request(staging_size, false); update_descriptor_queue.Acquire(); - update_descriptor_queue.AddBuffer(*buffer.handle, 0, staging_size); + update_descriptor_queue.AddBuffer(staging_ref.buffer, 0, staging_size); const VkDescriptorSet set = CommitDescriptorSet(update_descriptor_queue); scheduler.RequestOutsideRenderPassOperationContext(); ASSERT(num_vertices % 4 == 0); const u32 num_quads = num_vertices / 4; - scheduler.Record([layout = *layout, pipeline = *pipeline, buffer = *buffer.handle, num_quads, - first, set](vk::CommandBuffer cmdbuf) { + scheduler.Record([layout = *layout, pipeline = *pipeline, buffer = staging_ref.buffer, + num_quads, first, set](vk::CommandBuffer cmdbuf) { constexpr u32 dispatch_size = 1024; cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE, pipeline); cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_COMPUTE, layout, 0, set, {}); @@ -208,11 +208,11 @@ std::pair QuadArrayPass::Assemble(u32 num_vertices, u32 cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, 0, {}, {barrier}, {}); }); - return {*buffer.handle, 0}; + return {staging_ref.buffer, 0}; } Uint8Pass::Uint8Pass(const Device& device, VKScheduler& scheduler_, - VKDescriptorPool& descriptor_pool, VKStagingBufferPool& staging_buffer_pool_, + VKDescriptorPool& descriptor_pool, StagingBufferPool& staging_buffer_pool_, VKUpdateDescriptorQueue& update_descriptor_queue_) : VKComputePass(device, descriptor_pool, BuildInputOutputDescriptorSetBindings(), BuildInputOutputDescriptorUpdateTemplate(), {}, VULKAN_UINT8_COMP_SPV), @@ -224,15 +224,15 @@ Uint8Pass::~Uint8Pass() = default; std::pair Uint8Pass::Assemble(u32 num_vertices, VkBuffer src_buffer, u64 src_offset) { const u32 staging_size = static_cast(num_vertices * sizeof(u16)); - auto& buffer = staging_buffer_pool.GetUnusedBuffer(staging_size, false); + const auto staging_ref = staging_buffer_pool.Request(staging_size, false); update_descriptor_queue.Acquire(); update_descriptor_queue.AddBuffer(src_buffer, src_offset, num_vertices); - update_descriptor_queue.AddBuffer(*buffer.handle, 0, staging_size); + update_descriptor_queue.AddBuffer(staging_ref.buffer, 0, staging_size); const VkDescriptorSet set = CommitDescriptorSet(update_descriptor_queue); scheduler.RequestOutsideRenderPassOperationContext(); - scheduler.Record([layout = *layout, pipeline = *pipeline, buffer = *buffer.handle, set, + scheduler.Record([layout = *layout, pipeline = *pipeline, buffer = staging_ref.buffer, set, num_vertices](vk::CommandBuffer cmdbuf) { constexpr u32 dispatch_size = 1024; cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE, pipeline); @@ -252,12 +252,12 @@ std::pair Uint8Pass::Assemble(u32 num_vertices, VkBuffer src_buff cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, 0, {}, barrier, {}); }); - return {*buffer.handle, 0}; + return {staging_ref.buffer, 0}; } QuadIndexedPass::QuadIndexedPass(const Device& device_, VKScheduler& scheduler_, VKDescriptorPool& descriptor_pool_, - VKStagingBufferPool& staging_buffer_pool_, + StagingBufferPool& staging_buffer_pool_, VKUpdateDescriptorQueue& update_descriptor_queue_) : VKComputePass(device_, descriptor_pool_, BuildInputOutputDescriptorSetBindings(), BuildInputOutputDescriptorUpdateTemplate(), @@ -286,15 +286,15 @@ std::pair QuadIndexedPass::Assemble( const u32 num_tri_vertices = (num_vertices / 4) * 6; const std::size_t staging_size = num_tri_vertices * sizeof(u32); - auto& buffer = staging_buffer_pool.GetUnusedBuffer(staging_size, false); + const auto staging_ref = staging_buffer_pool.Request(staging_size, false); update_descriptor_queue.Acquire(); update_descriptor_queue.AddBuffer(src_buffer, src_offset, input_size); - update_descriptor_queue.AddBuffer(*buffer.handle, 0, staging_size); + update_descriptor_queue.AddBuffer(staging_ref.buffer, 0, staging_size); const VkDescriptorSet set = CommitDescriptorSet(update_descriptor_queue); scheduler.RequestOutsideRenderPassOperationContext(); - scheduler.Record([layout = *layout, pipeline = *pipeline, buffer = *buffer.handle, set, + scheduler.Record([layout = *layout, pipeline = *pipeline, buffer = staging_ref.buffer, set, num_tri_vertices, base_vertex, index_shift](vk::CommandBuffer cmdbuf) { static constexpr u32 dispatch_size = 1024; const std::array push_constants = {base_vertex, index_shift}; @@ -317,7 +317,7 @@ std::pair QuadIndexedPass::Assemble( cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, 0, {}, barrier, {}); }); - return {*buffer.handle, 0}; + return {staging_ref.buffer, 0}; } } // 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..f4e4432a7 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 @@ namespace Vulkan { class Device; +class StagingBufferPool; class VKScheduler; -class VKStagingBufferPool; class VKUpdateDescriptorQueue; class VKComputePass { @@ -45,7 +45,7 @@ class QuadArrayPass final : public VKComputePass { public: explicit QuadArrayPass(const Device& device_, VKScheduler& scheduler_, VKDescriptorPool& descriptor_pool_, - VKStagingBufferPool& staging_buffer_pool_, + StagingBufferPool& staging_buffer_pool_, VKUpdateDescriptorQueue& update_descriptor_queue_); ~QuadArrayPass(); @@ -53,7 +53,7 @@ public: private: VKScheduler& scheduler; - VKStagingBufferPool& staging_buffer_pool; + StagingBufferPool& staging_buffer_pool; VKUpdateDescriptorQueue& update_descriptor_queue; }; @@ -61,7 +61,7 @@ class Uint8Pass final : public VKComputePass { public: explicit Uint8Pass(const Device& device_, VKScheduler& scheduler_, VKDescriptorPool& descriptor_pool_, - VKStagingBufferPool& staging_buffer_pool_, + StagingBufferPool& staging_buffer_pool_, VKUpdateDescriptorQueue& update_descriptor_queue_); ~Uint8Pass(); @@ -69,7 +69,7 @@ public: private: VKScheduler& scheduler; - VKStagingBufferPool& staging_buffer_pool; + StagingBufferPool& staging_buffer_pool; VKUpdateDescriptorQueue& update_descriptor_queue; }; @@ -77,7 +77,7 @@ class QuadIndexedPass final : public VKComputePass { public: explicit QuadIndexedPass(const Device& device_, VKScheduler& scheduler_, VKDescriptorPool& descriptor_pool_, - VKStagingBufferPool& staging_buffer_pool_, + StagingBufferPool& staging_buffer_pool_, VKUpdateDescriptorQueue& update_descriptor_queue_); ~QuadIndexedPass(); @@ -87,7 +87,7 @@ public: private: VKScheduler& scheduler; - VKStagingBufferPool& staging_buffer_pool; + StagingBufferPool& staging_buffer_pool; VKUpdateDescriptorQueue& update_descriptor_queue; }; diff --git a/src/video_core/renderer_vulkan/vk_memory_manager.cpp b/src/video_core/renderer_vulkan/vk_memory_manager.cpp index a6abd0eee..102987240 100644 --- a/src/video_core/renderer_vulkan/vk_memory_manager.cpp +++ b/src/video_core/renderer_vulkan/vk_memory_manager.cpp @@ -3,6 +3,7 @@ // Refer to the license.txt file included. #include +#include #include #include #include @@ -16,92 +17,93 @@ #include "video_core/vulkan_common/vulkan_wrapper.h" namespace Vulkan { - namespace { +struct Range { + u64 begin; + u64 end; -u64 GetAllocationChunkSize(u64 required_size) { - static constexpr u64 sizes[] = {16ULL << 20, 32ULL << 20, 64ULL << 20, 128ULL << 20}; - auto it = std::lower_bound(std::begin(sizes), std::end(sizes), required_size); - return it != std::end(sizes) ? *it : Common::AlignUp(required_size, 256ULL << 20); -} + [[nodiscard]] bool Contains(u64 iterator, u64 size) const noexcept { + return iterator < end && begin < iterator + size; + } +}; + +[[nodiscard]] u64 GetAllocationChunkSize(u64 required_size) { + static constexpr std::array sizes{ + 0x1000ULL << 10, 0x1400ULL << 10, 0x1800ULL << 10, 0x1c00ULL << 10, 0x2000ULL << 10, + 0x3200ULL << 10, 0x4000ULL << 10, 0x6000ULL << 10, 0x8000ULL << 10, 0xA000ULL << 10, + 0x10000ULL << 10, 0x18000ULL << 10, 0x20000ULL << 10, + }; + static_assert(std::is_sorted(sizes.begin(), sizes.end())); + const auto it = std::ranges::lower_bound(sizes, required_size); + return it != sizes.end() ? *it : Common::AlignUp(required_size, 4ULL << 20); +} } // Anonymous namespace -class VKMemoryAllocation final { +class MemoryAllocation { public: - explicit VKMemoryAllocation(const Device& device_, vk::DeviceMemory memory_, - VkMemoryPropertyFlags properties_, u64 allocation_size_, u32 type_) + explicit MemoryAllocation(const Device& device_, vk::DeviceMemory memory_, + VkMemoryPropertyFlags properties_, u64 allocation_size_, u32 type_) : device{device_}, memory{std::move(memory_)}, properties{properties_}, allocation_size{allocation_size_}, shifted_type{ShiftType(type_)} {} - VKMemoryCommit Commit(VkDeviceSize commit_size, VkDeviceSize alignment) { - auto found = TryFindFreeSection(free_iterator, allocation_size, - static_cast(commit_size), static_cast(alignment)); - if (!found) { - found = TryFindFreeSection(0, free_iterator, static_cast(commit_size), - static_cast(alignment)); - if (!found) { - // Signal out of memory, it'll try to do more allocations. - return nullptr; - } + [[nodiscard]] std::optional Commit(VkDeviceSize size, VkDeviceSize alignment) { + const std::optional alloc = FindFreeRegion(size, alignment); + if (!alloc) { + // Signal out of memory, it'll try to do more allocations. + return std::nullopt; } - auto commit = std::make_unique(device, this, memory, *found, - *found + commit_size); - commits.push_back(commit.get()); - - // Last commit's address is highly probable to be free. - free_iterator = *found + commit_size; - - return commit; + const Range range{ + .begin = *alloc, + .end = *alloc + size, + }; + commits.insert(std::ranges::upper_bound(commits, *alloc, {}, &Range::begin), range); + return std::make_optional(device, this, *memory, *alloc, *alloc + size); } - void Free(const VKMemoryCommitImpl* commit) { - ASSERT(commit); + void Free(u64 begin) { + const auto it = std::ranges::find(commits, begin, &Range::begin); + ASSERT_MSG(it != commits.end(), "Invalid commit"); + commits.erase(it); + } - const auto it = std::find(std::begin(commits), std::end(commits), commit); - if (it == commits.end()) { - UNREACHABLE_MSG("Freeing unallocated commit!"); - return; + [[nodiscard]] std::span Map() { + if (!memory_mapped_span.empty()) { + return memory_mapped_span; } - commits.erase(it); + u8* const raw_pointer = memory.Map(0, allocation_size); + memory_mapped_span = std::span(raw_pointer, allocation_size); + return memory_mapped_span; } /// Returns whether this allocation is compatible with the arguments. - bool IsCompatible(VkMemoryPropertyFlags wanted_properties, u32 type_mask) const { + [[nodiscard]] bool IsCompatible(VkMemoryPropertyFlags wanted_properties, u32 type_mask) const { return (wanted_properties & properties) && (type_mask & shifted_type) != 0; } private: - static constexpr u32 ShiftType(u32 type) { + [[nodiscard]] static constexpr u32 ShiftType(u32 type) { return 1U << type; } - /// A memory allocator, it may return a free region between "start" and "end" with the solicited - /// requirements. - std::optional TryFindFreeSection(u64 start, u64 end, u64 size, u64 alignment) const { - u64 iterator = Common::AlignUp(start, alignment); - while (iterator + size <= end) { - const u64 try_left = iterator; - const u64 try_right = try_left + size; - - bool overlap = false; - for (const auto& commit : commits) { - const auto [commit_left, commit_right] = commit->interval; - if (try_left < commit_right && commit_left < try_right) { - // There's an overlap, continue the search where the overlapping commit ends. - iterator = Common::AlignUp(commit_right, alignment); - overlap = true; - break; - } + [[nodiscard]] std::optional FindFreeRegion(u64 size, u64 alignment) noexcept { + ASSERT(std::has_single_bit(alignment)); + const u64 alignment_log2 = std::countr_zero(alignment); + std::optional candidate; + u64 iterator = 0; + auto commit = commits.begin(); + while (iterator + size <= allocation_size) { + candidate = candidate.value_or(iterator); + if (commit == commits.end()) { + break; } - if (!overlap) { - // A free address has been found. - return try_left; + if (commit->Contains(*candidate, size)) { + candidate = std::nullopt; } + iterator = Common::AlignUpLog2(commit->end, alignment_log2); + ++commit; } - - // No free regions where found, return an empty optional. - return std::nullopt; + return candidate; } const Device& device; ///< Vulkan device. @@ -109,21 +111,52 @@ private: const VkMemoryPropertyFlags properties; ///< Vulkan properties. const u64 allocation_size; ///< Size of this allocation. const u32 shifted_type; ///< Stored Vulkan type of this allocation, shifted. + std::vector commits; ///< All commit ranges done from this allocation. + std::span memory_mapped_span; ///< Memory mapped span. Empty if not queried before. +}; - /// Hints where the next free region is likely going to be. - u64 free_iterator{}; +MemoryCommit::MemoryCommit(const Device& device_, MemoryAllocation* allocation_, + VkDeviceMemory memory_, u64 begin, u64 end) noexcept + : device{&device_}, allocation{allocation_}, memory{memory_}, interval{begin, end} {} - /// Stores all commits done from this allocation. - std::vector commits; -}; +MemoryCommit::~MemoryCommit() { + Release(); +} + +MemoryCommit& MemoryCommit::operator=(MemoryCommit&& rhs) noexcept { + Release(); + device = rhs.device; + allocation = std::exchange(rhs.allocation, nullptr); + memory = rhs.memory; + interval = rhs.interval; + span = std::exchange(rhs.span, std::span{}); + return *this; +} + +MemoryCommit::MemoryCommit(MemoryCommit&& rhs) noexcept + : device{rhs.device}, allocation{std::exchange(rhs.allocation, nullptr)}, memory{rhs.memory}, + interval{rhs.interval}, span{std::exchange(rhs.span, std::span{})} {} + +std::span MemoryCommit::Map() { + if (!span.empty()) { + return span; + } + span = allocation->Map().subspan(interval.first, interval.second - interval.first); + return span; +} + +void MemoryCommit::Release() { + if (allocation) { + allocation->Free(interval.first); + } +} VKMemoryManager::VKMemoryManager(const Device& device_) : device{device_}, properties{device_.GetPhysical().GetMemoryProperties()} {} VKMemoryManager::~VKMemoryManager() = default; -VKMemoryCommit VKMemoryManager::Commit(const VkMemoryRequirements& requirements, - bool host_visible) { +MemoryCommit VKMemoryManager::Commit(const VkMemoryRequirements& requirements, bool host_visible) { const u64 chunk_size = GetAllocationChunkSize(requirements.size); // When a host visible commit is asked, search for host visible and coherent, otherwise search @@ -131,39 +164,31 @@ VKMemoryCommit VKMemoryManager::Commit(const VkMemoryRequirements& requirements, const VkMemoryPropertyFlags wanted_properties = host_visible ? VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT : VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; - - if (auto commit = TryAllocCommit(requirements, wanted_properties)) { - return commit; + if (std::optional commit = TryAllocCommit(requirements, wanted_properties)) { + return std::move(*commit); } - // Commit has failed, allocate more memory. - if (!AllocMemory(wanted_properties, requirements.memoryTypeBits, chunk_size)) { - // TODO(Rodrigo): Handle these situations in some way like flushing to guest memory. - // Allocation has failed, panic. - UNREACHABLE_MSG("Ran out of VRAM!"); - return {}; - } + // TODO(Rodrigo): Handle out of memory situations in some way like flushing to guest memory. + AllocMemory(wanted_properties, requirements.memoryTypeBits, chunk_size); - // Commit again, this time it won't fail since there's a fresh allocation above. If it does, - // there's a bug. - auto commit = TryAllocCommit(requirements, wanted_properties); - ASSERT(commit); - return commit; + // Commit again, this time it won't fail since there's a fresh allocation above. + // If it does, there's a bug. + return TryAllocCommit(requirements, wanted_properties).value(); } -VKMemoryCommit VKMemoryManager::Commit(const vk::Buffer& buffer, bool host_visible) { +MemoryCommit VKMemoryManager::Commit(const vk::Buffer& buffer, bool host_visible) { auto commit = Commit(device.GetLogical().GetBufferMemoryRequirements(*buffer), host_visible); - buffer.BindMemory(commit->GetMemory(), commit->GetOffset()); + buffer.BindMemory(commit.Memory(), commit.Offset()); return commit; } -VKMemoryCommit VKMemoryManager::Commit(const vk::Image& image, bool host_visible) { +MemoryCommit VKMemoryManager::Commit(const vk::Image& image, bool host_visible) { auto commit = Commit(device.GetLogical().GetImageMemoryRequirements(*image), host_visible); - image.BindMemory(commit->GetMemory(), commit->GetOffset()); + image.BindMemory(commit.Memory(), commit.Offset()); return commit; } -bool VKMemoryManager::AllocMemory(VkMemoryPropertyFlags wanted_properties, u32 type_mask, +void VKMemoryManager::AllocMemory(VkMemoryPropertyFlags wanted_properties, u32 type_mask, u64 size) { const u32 type = [&] { for (u32 type_index = 0; type_index < properties.memoryTypeCount; ++type_index) { @@ -176,26 +201,18 @@ bool VKMemoryManager::AllocMemory(VkMemoryPropertyFlags wanted_properties, u32 t UNREACHABLE_MSG("Couldn't find a compatible memory type!"); return 0U; }(); - - // Try to allocate found type. - vk::DeviceMemory memory = device.GetLogical().TryAllocateMemory({ + vk::DeviceMemory memory = device.GetLogical().AllocateMemory({ .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, .pNext = nullptr, .allocationSize = size, .memoryTypeIndex = type, }); - if (!memory) { - LOG_CRITICAL(Render_Vulkan, "Device allocation failed!"); - return false; - } - - allocations.push_back(std::make_unique(device, std::move(memory), - wanted_properties, size, type)); - return true; + allocations.push_back(std::make_unique(device, std::move(memory), + wanted_properties, size, type)); } -VKMemoryCommit VKMemoryManager::TryAllocCommit(const VkMemoryRequirements& requirements, - VkMemoryPropertyFlags wanted_properties) { +std::optional VKMemoryManager::TryAllocCommit( + const VkMemoryRequirements& requirements, VkMemoryPropertyFlags wanted_properties) { for (auto& allocation : allocations) { if (!allocation->IsCompatible(wanted_properties, requirements.memoryTypeBits)) { continue; @@ -204,27 +221,7 @@ VKMemoryCommit VKMemoryManager::TryAllocCommit(const VkMemoryRequirements& requi return commit; } } - return {}; -} - -VKMemoryCommitImpl::VKMemoryCommitImpl(const Device& device_, VKMemoryAllocation* allocation_, - const vk::DeviceMemory& memory_, u64 begin_, u64 end_) - : device{device_}, memory{memory_}, interval{begin_, end_}, allocation{allocation_} {} - -VKMemoryCommitImpl::~VKMemoryCommitImpl() { - allocation->Free(this); -} - -MemoryMap VKMemoryCommitImpl::Map(u64 size, u64 offset_) const { - return MemoryMap(this, std::span(memory.Map(interval.first + offset_, size), size)); -} - -void VKMemoryCommitImpl::Unmap() const { - memory.Unmap(); -} - -MemoryMap VKMemoryCommitImpl::Map() const { - return Map(interval.second - interval.first); + return std::nullopt; } } // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/vk_memory_manager.h b/src/video_core/renderer_vulkan/vk_memory_manager.h index 2452bca4e..2f7b836e1 100644 --- a/src/video_core/renderer_vulkan/vk_memory_manager.h +++ b/src/video_core/renderer_vulkan/vk_memory_manager.h @@ -15,118 +15,81 @@ namespace Vulkan { class Device; class MemoryMap; -class VKMemoryAllocation; -class VKMemoryCommitImpl; +class MemoryAllocation; -using VKMemoryCommit = std::unique_ptr; - -class VKMemoryManager final { +class MemoryCommit final { public: - explicit VKMemoryManager(const Device& device_); - VKMemoryManager(const VKMemoryManager&) = delete; - ~VKMemoryManager(); + explicit MemoryCommit() noexcept = default; + explicit MemoryCommit(const Device& device_, MemoryAllocation* allocation_, + VkDeviceMemory memory_, u64 begin, u64 end) noexcept; + ~MemoryCommit(); - /** - * Commits a memory with the specified requeriments. - * @param requirements Requirements returned from a Vulkan call. - * @param host_visible Signals the allocator that it *must* use host visible and coherent - * memory. When passing false, it will try to allocate device local memory. - * @returns A memory commit. - */ - VKMemoryCommit Commit(const VkMemoryRequirements& requirements, bool host_visible); + MemoryCommit& operator=(MemoryCommit&&) noexcept; + MemoryCommit(MemoryCommit&&) noexcept; - /// Commits memory required by the buffer and binds it. - VKMemoryCommit Commit(const vk::Buffer& buffer, bool host_visible); - - /// Commits memory required by the image and binds it. - VKMemoryCommit Commit(const vk::Image& image, bool host_visible); - -private: - /// Allocates a chunk of memory. - bool AllocMemory(VkMemoryPropertyFlags wanted_properties, u32 type_mask, u64 size); - - /// Tries to allocate a memory commit. - VKMemoryCommit TryAllocCommit(const VkMemoryRequirements& requirements, - VkMemoryPropertyFlags wanted_properties); - - const Device& device; ///< Device handler. - const VkPhysicalDeviceMemoryProperties properties; ///< Physical device properties. - std::vector> allocations; ///< Current allocations. -}; - -class VKMemoryCommitImpl final { - friend VKMemoryAllocation; - friend MemoryMap; - -public: - explicit VKMemoryCommitImpl(const Device& device_, VKMemoryAllocation* allocation_, - const vk::DeviceMemory& memory_, u64 begin_, u64 end_); - ~VKMemoryCommitImpl(); + MemoryCommit& operator=(const MemoryCommit&) = delete; + MemoryCommit(const MemoryCommit&) = delete; - /// Maps a memory region and returns a pointer to it. - /// It's illegal to have more than one memory map at the same time. - MemoryMap Map(u64 size, u64 offset = 0) const; - - /// Maps the whole commit and returns a pointer to it. - /// It's illegal to have more than one memory map at the same time. - MemoryMap Map() const; + /// Returns a host visible memory map. + /// It will map the backing allocation if it hasn't been mapped before. + std::span Map(); /// Returns the Vulkan memory handler. - VkDeviceMemory GetMemory() const { - return *memory; + VkDeviceMemory Memory() const { + return memory; } /// Returns the start position of the commit relative to the allocation. - VkDeviceSize GetOffset() const { + VkDeviceSize Offset() const { return static_cast(interval.first); } private: - /// Unmaps memory. - void Unmap() const; + void Release(); - const Device& device; ///< Vulkan device. - const vk::DeviceMemory& memory; ///< Vulkan device memory handler. - std::pair interval{}; ///< Interval where the commit exists. - VKMemoryAllocation* allocation{}; ///< Pointer to the large memory allocation. + const Device* device{}; ///< Vulkan device. + MemoryAllocation* allocation{}; ///< Pointer to the large memory allocation. + VkDeviceMemory memory{}; ///< Vulkan device memory handler. + std::pair interval{}; ///< Interval where the commit exists. + std::span span; ///< Host visible memory span. Empty if not queried before. }; -/// Holds ownership of a memory map. -class MemoryMap final { +class VKMemoryManager final { public: - explicit MemoryMap(const VKMemoryCommitImpl* commit_, std::span span_) - : commit{commit_}, span{span_} {} - - ~MemoryMap() { - if (commit) { - commit->Unmap(); - } - } + explicit VKMemoryManager(const Device& device_); + ~VKMemoryManager(); - /// Prematurely releases the memory map. - void Release() { - commit->Unmap(); - commit = nullptr; - } + VKMemoryManager& operator=(const VKMemoryManager&) = delete; + VKMemoryManager(const VKMemoryManager&) = delete; - /// Returns a span to the memory map. - [[nodiscard]] std::span Span() const noexcept { - return span; - } + /** + * Commits a memory with the specified requeriments. + * + * @param requirements Requirements returned from a Vulkan call. + * @param host_visible Signals the allocator that it *must* use host visible and coherent + * memory. When passing false, it will try to allocate device local memory. + * + * @returns A memory commit. + */ + MemoryCommit Commit(const VkMemoryRequirements& requirements, bool host_visible); - /// Returns the address of the memory map. - [[nodiscard]] u8* Address() const noexcept { - return span.data(); - } + /// Commits memory required by the buffer and binds it. + MemoryCommit Commit(const vk::Buffer& buffer, bool host_visible); - /// Returns the address of the memory map; - [[nodiscard]] operator u8*() const noexcept { - return span.data(); - } + /// Commits memory required by the image and binds it. + MemoryCommit Commit(const vk::Image& image, bool host_visible); private: - const VKMemoryCommitImpl* commit{}; ///< Mapped memory commit. - std::span span; ///< Address to the mapped memory. + /// Allocates a chunk of memory. + void AllocMemory(VkMemoryPropertyFlags wanted_properties, u32 type_mask, u64 size); + + /// Tries to allocate a memory commit. + std::optional TryAllocCommit(const VkMemoryRequirements& requirements, + VkMemoryPropertyFlags wanted_properties); + + const Device& device; ///< Device handler. + const VkPhysicalDeviceMemoryProperties properties; ///< Physical device properties. + std::vector> allocations; ///< Current allocations. }; } // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.h b/src/video_core/renderer_vulkan/vk_rasterizer.h index 4695718e9..c3316742f 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.h +++ b/src/video_core/renderer_vulkan/vk_rasterizer.h @@ -218,7 +218,7 @@ private: VKScheduler& scheduler; VKStreamBuffer stream_buffer; - VKStagingBufferPool staging_pool; + StagingBufferPool staging_pool; VKDescriptorPool descriptor_pool; VKUpdateDescriptorQueue update_descriptor_queue; BlitImageHelper blit_image; @@ -234,7 +234,7 @@ private: VKFenceManager fence_manager; vk::Buffer default_buffer; - VKMemoryCommit default_buffer_commit; + MemoryCommit default_buffer_commit; vk::Event wfi_event; VideoCommon::Shader::AsyncShaders async_shaders; 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..b085dcc1c 100644 --- a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp +++ b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp @@ -3,58 +3,64 @@ // Refer to the license.txt file included. #include -#include #include #include +#include + #include "common/bit_util.h" #include "common/common_types.h" #include "video_core/renderer_vulkan/vk_scheduler.h" #include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" -#include "video_core/vulkan_common/vulkan_device.h" #include "video_core/vulkan_common/vulkan_wrapper.h" +#include "video_core/vulkan_common/vulkan_device.h" namespace Vulkan { -VKStagingBufferPool::StagingBuffer::StagingBuffer(std::unique_ptr buffer_) - : buffer{std::move(buffer_)} {} - -VKStagingBufferPool::VKStagingBufferPool(const Device& device_, VKMemoryManager& memory_manager_, - VKScheduler& scheduler_) +StagingBufferPool::StagingBufferPool(const Device& device_, VKMemoryManager& memory_manager_, + VKScheduler& scheduler_) : device{device_}, memory_manager{memory_manager_}, scheduler{scheduler_} {} -VKStagingBufferPool::~VKStagingBufferPool() = default; +StagingBufferPool::~StagingBufferPool() = default; -VKBuffer& VKStagingBufferPool::GetUnusedBuffer(std::size_t size, bool host_visible) { - if (const auto buffer = TryGetReservedBuffer(size, host_visible)) { - return *buffer; +StagingBufferRef StagingBufferPool::Request(size_t size, bool host_visible) { + if (const std::optional ref = TryGetReservedBuffer(size, host_visible)) { + return *ref; } return CreateStagingBuffer(size, host_visible); } -void VKStagingBufferPool::TickFrame() { - current_delete_level = (current_delete_level + 1) % NumLevels; +void StagingBufferPool::TickFrame() { + current_delete_level = (current_delete_level + 1) % NUM_LEVELS; ReleaseCache(true); ReleaseCache(false); } -VKBuffer* VKStagingBufferPool::TryGetReservedBuffer(std::size_t size, bool host_visible) { - for (StagingBuffer& entry : GetCache(host_visible)[Common::Log2Ceil64(size)].entries) { - if (!scheduler.IsFree(entry.tick)) { - continue; +std::optional StagingBufferPool::TryGetReservedBuffer(size_t size, + bool host_visible) { + StagingBuffers& cache_level = GetCache(host_visible)[Common::Log2Ceil64(size)]; + + const auto is_free = [this](const StagingBuffer& entry) { + return scheduler.IsFree(entry.tick); + }; + auto& entries = cache_level.entries; + const auto hint_it = entries.begin() + cache_level.iterate_index; + auto it = std::find_if(entries.begin() + cache_level.iterate_index, entries.end(), is_free); + if (it == entries.end()) { + it = std::find_if(entries.begin(), hint_it, is_free); + if (it == hint_it) { + return std::nullopt; } - entry.tick = scheduler.CurrentTick(); - return &*entry.buffer; } - return nullptr; + cache_level.iterate_index = std::distance(entries.begin(), it) + 1; + it->tick = scheduler.CurrentTick(); + return it->Ref(); } -VKBuffer& VKStagingBufferPool::CreateStagingBuffer(std::size_t size, bool host_visible) { +StagingBufferRef StagingBufferPool::CreateStagingBuffer(size_t size, bool host_visible) { const u32 log2 = Common::Log2Ceil64(size); - - auto buffer = std::make_unique(); - buffer->handle = device.GetLogical().CreateBuffer({ + vk::Buffer buffer = device.GetLogical().CreateBuffer({ .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, .pNext = nullptr, .flags = 0, @@ -66,49 +72,53 @@ VKBuffer& VKStagingBufferPool::CreateStagingBuffer(std::size_t size, bool host_v .queueFamilyIndexCount = 0, .pQueueFamilyIndices = nullptr, }); - buffer->commit = memory_manager.Commit(buffer->handle, host_visible); - - std::vector& entries = GetCache(host_visible)[log2].entries; - StagingBuffer& entry = entries.emplace_back(std::move(buffer)); - entry.tick = scheduler.CurrentTick(); - return *entry.buffer; + if (device.HasDebuggingToolAttached()) { + ++buffer_index; + buffer.SetObjectNameEXT(fmt::format("Staging Buffer {}", buffer_index).c_str()); + } + MemoryCommit commit = memory_manager.Commit(buffer, host_visible); + const std::span mapped_span = host_visible ? commit.Map() : std::span{}; + + StagingBuffer& entry = GetCache(host_visible)[log2].entries.emplace_back(StagingBuffer{ + .buffer = std::move(buffer), + .commit = std::move(commit), + .mapped_span = mapped_span, + .tick = scheduler.CurrentTick(), + }); + return entry.Ref(); } -VKStagingBufferPool::StagingBuffersCache& VKStagingBufferPool::GetCache(bool host_visible) { +StagingBufferPool::StagingBuffersCache& StagingBufferPool::GetCache(bool host_visible) { return host_visible ? host_staging_buffers : device_staging_buffers; } -void VKStagingBufferPool::ReleaseCache(bool host_visible) { - auto& cache = GetCache(host_visible); - const u64 size = ReleaseLevel(cache, current_delete_level); - if (size == 0) { - return; - } +void StagingBufferPool::ReleaseCache(bool host_visible) { + ReleaseLevel(GetCache(host_visible), current_delete_level); } -u64 VKStagingBufferPool::ReleaseLevel(StagingBuffersCache& cache, std::size_t log2) { - static constexpr std::size_t deletions_per_tick = 16; - +void StagingBufferPool::ReleaseLevel(StagingBuffersCache& cache, size_t log2) { + constexpr size_t deletions_per_tick = 16; auto& staging = cache[log2]; auto& entries = staging.entries; - const std::size_t old_size = entries.size(); + const size_t old_size = entries.size(); const auto is_deleteable = [this](const StagingBuffer& entry) { return scheduler.IsFree(entry.tick); }; - const std::size_t begin_offset = staging.delete_index; - const std::size_t end_offset = std::min(begin_offset + deletions_per_tick, old_size); - const auto begin = std::begin(entries) + begin_offset; - const auto end = std::begin(entries) + end_offset; + const size_t begin_offset = staging.delete_index; + const size_t end_offset = std::min(begin_offset + deletions_per_tick, old_size); + const auto begin = entries.begin() + begin_offset; + const auto end = entries.begin() + end_offset; entries.erase(std::remove_if(begin, end, is_deleteable), end); - const std::size_t new_size = entries.size(); + const size_t new_size = entries.size(); staging.delete_index += deletions_per_tick; if (staging.delete_index >= new_size) { staging.delete_index = 0; } - - return (1ULL << log2) * (old_size - new_size); + if (staging.iterate_index > new_size) { + staging.iterate_index = 0; + } } } // 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..5234a95fa 100644 --- a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h +++ b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h @@ -17,46 +17,54 @@ namespace Vulkan { class Device; class VKScheduler; -struct VKBuffer final { - vk::Buffer handle; - VKMemoryCommit commit; +struct StagingBufferRef { + VkBuffer buffer; + std::span mapped_span; }; -class VKStagingBufferPool final { +class StagingBufferPool { public: - explicit VKStagingBufferPool(const Device& device, VKMemoryManager& memory_manager, - VKScheduler& scheduler); - ~VKStagingBufferPool(); + explicit StagingBufferPool(const Device& device, VKMemoryManager& memory_manager, + VKScheduler& scheduler); + ~StagingBufferPool(); - VKBuffer& GetUnusedBuffer(std::size_t size, bool host_visible); + StagingBufferRef Request(size_t size, bool host_visible); void TickFrame(); private: - struct StagingBuffer final { - explicit StagingBuffer(std::unique_ptr buffer); - - std::unique_ptr buffer; + struct StagingBuffer { + vk::Buffer buffer; + MemoryCommit commit; + std::span mapped_span; u64 tick = 0; + + StagingBufferRef Ref() const noexcept { + return { + .buffer = *buffer, + .mapped_span = mapped_span, + }; + } }; - struct StagingBuffers final { + struct StagingBuffers { std::vector entries; - std::size_t delete_index = 0; + size_t delete_index = 0; + size_t iterate_index = 0; }; - static constexpr std::size_t NumLevels = sizeof(std::size_t) * CHAR_BIT; - using StagingBuffersCache = std::array; + static constexpr size_t NUM_LEVELS = sizeof(size_t) * CHAR_BIT; + using StagingBuffersCache = std::array; - VKBuffer* TryGetReservedBuffer(std::size_t size, bool host_visible); + std::optional TryGetReservedBuffer(size_t size, bool host_visible); - VKBuffer& CreateStagingBuffer(std::size_t size, bool host_visible); + StagingBufferRef CreateStagingBuffer(size_t size, bool host_visible); StagingBuffersCache& GetCache(bool host_visible); void ReleaseCache(bool host_visible); - u64 ReleaseLevel(StagingBuffersCache& cache, std::size_t log2); + void ReleaseLevel(StagingBuffersCache& cache, size_t log2); const Device& device; VKMemoryManager& memory_manager; @@ -65,7 +73,8 @@ private: StagingBuffersCache host_staging_buffers; StagingBuffersCache device_staging_buffers; - std::size_t current_delete_level = 0; + size_t current_delete_level = 0; + u64 buffer_index = 0; }; } // 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..5acbcad76 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp @@ -554,10 +554,10 @@ void TextureCacheRuntime::Finish() { } ImageBufferMap TextureCacheRuntime::MapUploadBuffer(size_t size) { - const auto& buffer = staging_buffer_pool.GetUnusedBuffer(size, true); + const auto staging_ref = staging_buffer_pool.Request(size, true); return ImageBufferMap{ - .handle = *buffer.handle, - .map = buffer.commit->Map(size), + .handle = staging_ref.buffer, + .span = staging_ref.mapped_span, }; } diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.h b/src/video_core/renderer_vulkan/vk_texture_cache.h index 92a7aad8b..134465fd4 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.h +++ b/src/video_core/renderer_vulkan/vk_texture_cache.h @@ -19,14 +19,13 @@ using VideoCommon::Offset2D; using VideoCommon::RenderTargets; using VideoCore::Surface::PixelFormat; -class VKScheduler; -class VKStagingBufferPool; - class BlitImageHelper; class Device; class Image; class ImageView; class Framebuffer; +class StagingBufferPool; +class VKScheduler; struct RenderPassKey { constexpr auto operator<=>(const RenderPassKey&) const noexcept = default; @@ -60,18 +59,18 @@ struct ImageBufferMap { } [[nodiscard]] std::span Span() const noexcept { - return map.Span(); + return span; } VkBuffer handle; - MemoryMap map; + std::span span; }; struct TextureCacheRuntime { const Device& device; VKScheduler& scheduler; VKMemoryManager& memory_manager; - VKStagingBufferPool& staging_buffer_pool; + StagingBufferPool& staging_buffer_pool; BlitImageHelper& blit_image_helper; std::unordered_map renderpass_cache; @@ -141,7 +140,7 @@ private: VKScheduler* scheduler; vk::Image image; vk::Buffer buffer; - VKMemoryCommit commit; + MemoryCommit commit; VkImageAspectFlags aspect_mask = 0; bool initialized = false; }; -- cgit v1.2.3 From c2b550987b2eed4ead610222d6912868480c85f2 Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Sun, 3 Jan 2021 18:11:01 -0300 Subject: renderer_vulkan: Rename Vulkan memory manager to memory allocator "Memory manager" collides with the guest GPU memory manager, and a memory allocator sounds closer to what the abstraction aims to be. --- src/video_core/renderer_vulkan/renderer_vulkan.cpp | 8 ++++---- src/video_core/renderer_vulkan/renderer_vulkan.h | 4 ++-- src/video_core/renderer_vulkan/vk_blit_screen.cpp | 8 ++++---- src/video_core/renderer_vulkan/vk_blit_screen.h | 4 ++-- src/video_core/renderer_vulkan/vk_buffer_cache.cpp | 12 ++++++------ src/video_core/renderer_vulkan/vk_buffer_cache.h | 7 +++---- src/video_core/renderer_vulkan/vk_compute_pass.h | 3 +-- src/video_core/renderer_vulkan/vk_memory_manager.cpp | 14 +++++++------- src/video_core/renderer_vulkan/vk_memory_manager.h | 10 +++++----- src/video_core/renderer_vulkan/vk_rasterizer.cpp | 14 +++++++------- src/video_core/renderer_vulkan/vk_rasterizer.h | 4 ++-- src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp | 8 ++++---- src/video_core/renderer_vulkan/vk_staging_buffer_pool.h | 4 ++-- src/video_core/renderer_vulkan/vk_texture_cache.cpp | 4 ++-- src/video_core/renderer_vulkan/vk_texture_cache.h | 2 +- 15 files changed, 52 insertions(+), 54 deletions(-) (limited to 'src') diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index d7437e185..657de69a5 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp @@ -137,7 +137,7 @@ bool RendererVulkan::Init() try { InitializeDevice(); Report(); - memory_manager = std::make_unique(*device); + memory_allocator = std::make_unique(*device); state_tracker = std::make_unique(gpu); @@ -149,11 +149,11 @@ bool RendererVulkan::Init() try { rasterizer = std::make_unique(render_window, gpu, gpu.MemoryManager(), cpu_memory, screen_info, *device, - *memory_manager, *state_tracker, *scheduler); + *memory_allocator, *state_tracker, *scheduler); blit_screen = std::make_unique(cpu_memory, render_window, *rasterizer, *device, - *memory_manager, *swapchain, *scheduler, screen_info); + *memory_allocator, *swapchain, *scheduler, screen_info); return true; } catch (const vk::Exception& exception) { @@ -172,7 +172,7 @@ void RendererVulkan::ShutDown() { blit_screen.reset(); scheduler.reset(); swapchain.reset(); - memory_manager.reset(); + memory_allocator.reset(); device.reset(); } 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 { class Device; class StateTracker; +class MemoryAllocator; class VKBlitScreen; -class VKMemoryManager; class VKSwapchain; class VKScheduler; @@ -75,7 +75,7 @@ private: vk::DebugUtilsMessenger debug_callback; std::unique_ptr device; - std::unique_ptr memory_manager; + std::unique_ptr memory_allocator; std::unique_ptr state_tracker; std::unique_ptr scheduler; std::unique_ptr swapchain; diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.cpp b/src/video_core/renderer_vulkan/vk_blit_screen.cpp index d8261526a..79d8ef71a 100644 --- a/src/video_core/renderer_vulkan/vk_blit_screen.cpp +++ b/src/video_core/renderer_vulkan/vk_blit_screen.cpp @@ -115,10 +115,10 @@ struct VKBlitScreen::BufferData { VKBlitScreen::VKBlitScreen(Core::Memory::Memory& cpu_memory_, Core::Frontend::EmuWindow& render_window_, VideoCore::RasterizerInterface& rasterizer_, const Device& device_, - VKMemoryManager& memory_manager_, VKSwapchain& swapchain_, + MemoryAllocator& memory_allocator_, VKSwapchain& swapchain_, VKScheduler& scheduler_, const VKScreenInfo& screen_info_) : cpu_memory{cpu_memory_}, render_window{render_window_}, rasterizer{rasterizer_}, - device{device_}, memory_manager{memory_manager_}, swapchain{swapchain_}, + device{device_}, memory_allocator{memory_allocator_}, swapchain{swapchain_}, scheduler{scheduler_}, image_count{swapchain.GetImageCount()}, screen_info{screen_info_} { resource_ticks.resize(image_count); @@ -657,7 +657,7 @@ void VKBlitScreen::CreateStagingBuffer(const Tegra::FramebufferConfig& framebuff }; buffer = device.GetLogical().CreateBuffer(ci); - buffer_commit = memory_manager.Commit(buffer, true); + buffer_commit = memory_allocator.Commit(buffer, true); } void VKBlitScreen::CreateRawImages(const Tegra::FramebufferConfig& framebuffer) { @@ -688,7 +688,7 @@ void VKBlitScreen::CreateRawImages(const Tegra::FramebufferConfig& framebuffer) .pQueueFamilyIndices = nullptr, .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, }); - raw_buffer_commits[i] = memory_manager.Commit(raw_images[i], false); + raw_buffer_commits[i] = memory_allocator.Commit(raw_images[i], false); raw_image_views[i] = device.GetLogical().CreateImageView(VkImageViewCreateInfo{ .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, .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 1aa8e3182..e52d9885e 100644 --- a/src/video_core/renderer_vulkan/vk_blit_screen.h +++ b/src/video_core/renderer_vulkan/vk_blit_screen.h @@ -43,7 +43,7 @@ public: explicit VKBlitScreen(Core::Memory::Memory& cpu_memory, Core::Frontend::EmuWindow& render_window, VideoCore::RasterizerInterface& rasterizer, const Device& device, - VKMemoryManager& memory_manager, VKSwapchain& swapchain, + MemoryAllocator& memory_allocator, VKSwapchain& swapchain, VKScheduler& scheduler, const VKScreenInfo& screen_info); ~VKBlitScreen(); @@ -86,7 +86,7 @@ private: Core::Frontend::EmuWindow& render_window; VideoCore::RasterizerInterface& rasterizer; const Device& device; - VKMemoryManager& memory_manager; + MemoryAllocator& memory_allocator; VKSwapchain& swapchain; VKScheduler& scheduler; const std::size_t image_count; diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp index 94c2e101b..94d3a9134 100644 --- a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp @@ -36,7 +36,7 @@ constexpr VkAccessFlags TRANSFORM_FEEDBACK_WRITE_ACCESS = } // Anonymous namespace -Buffer::Buffer(const Device& device_, VKMemoryManager& memory_manager, VKScheduler& scheduler_, +Buffer::Buffer(const Device& device_, MemoryAllocator& memory_allocator, VKScheduler& scheduler_, StagingBufferPool& staging_pool_, VAddr cpu_addr_, std::size_t size_) : BufferBlock{cpu_addr_, size_}, device{device_}, scheduler{scheduler_}, staging_pool{ staging_pool_} { @@ -50,7 +50,7 @@ Buffer::Buffer(const Device& device_, VKMemoryManager& memory_manager, VKSchedul .queueFamilyIndexCount = 0, .pQueueFamilyIndices = nullptr, }); - commit = memory_manager.Commit(buffer, false); + commit = memory_allocator.Commit(buffer, false); } Buffer::~Buffer() = default; @@ -162,18 +162,18 @@ void Buffer::CopyFrom(const Buffer& src, std::size_t src_offset, std::size_t dst VKBufferCache::VKBufferCache(VideoCore::RasterizerInterface& rasterizer_, Tegra::MemoryManager& gpu_memory_, Core::Memory::Memory& cpu_memory_, - const Device& device_, VKMemoryManager& memory_manager_, + const Device& device_, MemoryAllocator& memory_allocator_, VKScheduler& scheduler_, VKStreamBuffer& stream_buffer_, StagingBufferPool& staging_pool_) : VideoCommon::BufferCache{rasterizer_, gpu_memory_, cpu_memory_, stream_buffer_}, - device{device_}, memory_manager{memory_manager_}, scheduler{scheduler_}, staging_pool{ - staging_pool_} {} + device{device_}, memory_allocator{memory_allocator_}, scheduler{scheduler_}, + staging_pool{staging_pool_} {} VKBufferCache::~VKBufferCache() = default; std::shared_ptr VKBufferCache::CreateBlock(VAddr cpu_addr, std::size_t size) { - return std::make_shared(device, memory_manager, scheduler, staging_pool, cpu_addr, + return std::make_shared(device, memory_allocator, scheduler, staging_pool, cpu_addr, size); } diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.h b/src/video_core/renderer_vulkan/vk_buffer_cache.h index e54c107f2..4db5259ef 100644 --- a/src/video_core/renderer_vulkan/vk_buffer_cache.h +++ b/src/video_core/renderer_vulkan/vk_buffer_cache.h @@ -10,7 +10,6 @@ #include "video_core/buffer_cache/buffer_cache.h" #include "video_core/renderer_vulkan/vk_memory_manager.h" #include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" -#include "video_core/renderer_vulkan/vk_memory_manager.h" #include "video_core/renderer_vulkan/vk_stream_buffer.h" #include "video_core/vulkan_common/vulkan_wrapper.h" @@ -21,7 +20,7 @@ class VKScheduler; class Buffer final : public VideoCommon::BufferBlock { public: - explicit Buffer(const Device& device, VKMemoryManager& memory_manager, VKScheduler& scheduler, + explicit Buffer(const Device& device, MemoryAllocator& memory_allocator, VKScheduler& scheduler, StagingBufferPool& staging_pool, VAddr cpu_addr_, std::size_t size_); ~Buffer(); @@ -53,7 +52,7 @@ class VKBufferCache final : public VideoCommon::BufferCache VKMemoryManager::TryAllocCommit( +std::optional MemoryAllocator::TryAllocCommit( const VkMemoryRequirements& requirements, VkMemoryPropertyFlags wanted_properties) { for (auto& allocation : allocations) { if (!allocation->IsCompatible(wanted_properties, requirements.memoryTypeBits)) { diff --git a/src/video_core/renderer_vulkan/vk_memory_manager.h b/src/video_core/renderer_vulkan/vk_memory_manager.h index 2f7b836e1..69a6341e1 100644 --- a/src/video_core/renderer_vulkan/vk_memory_manager.h +++ b/src/video_core/renderer_vulkan/vk_memory_manager.h @@ -54,13 +54,13 @@ private: std::span span; ///< Host visible memory span. Empty if not queried before. }; -class VKMemoryManager final { +class MemoryAllocator final { public: - explicit VKMemoryManager(const Device& device_); - ~VKMemoryManager(); + explicit MemoryAllocator(const Device& device_); + ~MemoryAllocator(); - VKMemoryManager& operator=(const VKMemoryManager&) = delete; - VKMemoryManager(const VKMemoryManager&) = delete; + MemoryAllocator& operator=(const MemoryAllocator&) = delete; + MemoryAllocator(const MemoryAllocator&) = delete; /** * Commits a memory with the specified requeriments. diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index ce3db49bd..f38ead9c2 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 { RasterizerVulkan::RasterizerVulkan(Core::Frontend::EmuWindow& emu_window_, Tegra::GPU& gpu_, Tegra::MemoryManager& gpu_memory_, Core::Memory::Memory& cpu_memory_, VKScreenInfo& screen_info_, - const Device& device_, VKMemoryManager& memory_manager_, + const Device& device_, MemoryAllocator& memory_allocator_, StateTracker& state_tracker_, VKScheduler& scheduler_) : RasterizerAccelerated{cpu_memory_}, gpu{gpu_}, gpu_memory{gpu_memory_}, maxwell3d{gpu.Maxwell3D()}, kepler_compute{gpu.KeplerCompute()}, - screen_info{screen_info_}, device{device_}, memory_manager{memory_manager_}, + screen_info{screen_info_}, device{device_}, memory_allocator{memory_allocator_}, state_tracker{state_tracker_}, scheduler{scheduler_}, stream_buffer(device, scheduler), - staging_pool(device, memory_manager, scheduler), descriptor_pool(device, scheduler), + staging_pool(device, memory_allocator, scheduler), descriptor_pool(device, scheduler), update_descriptor_queue(device, scheduler), blit_image(device, scheduler, state_tracker, descriptor_pool), quad_array_pass(device, scheduler, descriptor_pool, staging_pool, update_descriptor_queue), quad_indexed_pass(device, scheduler, descriptor_pool, staging_pool, update_descriptor_queue), uint8_pass(device, scheduler, descriptor_pool, staging_pool, update_descriptor_queue), - texture_cache_runtime{device, scheduler, memory_manager, staging_pool, blit_image}, + texture_cache_runtime{device, scheduler, memory_allocator, staging_pool, blit_image}, texture_cache(texture_cache_runtime, *this, maxwell3d, kepler_compute, gpu_memory), pipeline_cache(*this, gpu, maxwell3d, kepler_compute, gpu_memory, device, scheduler, descriptor_pool, update_descriptor_queue), - buffer_cache(*this, gpu_memory, cpu_memory_, device, memory_manager, scheduler, stream_buffer, - staging_pool), + buffer_cache(*this, gpu_memory, cpu_memory_, device, memory_allocator, scheduler, + stream_buffer, staging_pool), query_cache{*this, maxwell3d, gpu_memory, device, scheduler}, fence_manager(*this, gpu, gpu_memory, texture_cache, buffer_cache, query_cache, scheduler), wfi_event(device.GetLogical().CreateEvent()), async_shaders(emu_window_) { @@ -1445,7 +1445,7 @@ VkBuffer RasterizerVulkan::DefaultBuffer() { .queueFamilyIndexCount = 0, .pQueueFamilyIndices = nullptr, }); - default_buffer_commit = memory_manager.Commit(default_buffer, false); + default_buffer_commit = memory_allocator.Commit(default_buffer, false); scheduler.RequestOutsideRenderPassOperationContext(); 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 c3316742f..72e679ffd 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.h +++ b/src/video_core/renderer_vulkan/vk_rasterizer.h @@ -56,7 +56,7 @@ public: explicit RasterizerVulkan(Core::Frontend::EmuWindow& emu_window_, Tegra::GPU& gpu_, Tegra::MemoryManager& gpu_memory_, Core::Memory::Memory& cpu_memory_, VKScreenInfo& screen_info_, const Device& device_, - VKMemoryManager& memory_manager_, StateTracker& state_tracker_, + MemoryAllocator& memory_allocator_, StateTracker& state_tracker_, VKScheduler& scheduler_); ~RasterizerVulkan() override; @@ -213,7 +213,7 @@ private: VKScreenInfo& screen_info; const Device& device; - VKMemoryManager& memory_manager; + MemoryAllocator& memory_allocator; StateTracker& state_tracker; VKScheduler& scheduler; 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 b085dcc1c..44d332ed2 100644 --- a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp +++ b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp @@ -12,14 +12,14 @@ #include "common/common_types.h" #include "video_core/renderer_vulkan/vk_scheduler.h" #include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" -#include "video_core/vulkan_common/vulkan_wrapper.h" #include "video_core/vulkan_common/vulkan_device.h" +#include "video_core/vulkan_common/vulkan_wrapper.h" namespace Vulkan { -StagingBufferPool::StagingBufferPool(const Device& device_, VKMemoryManager& memory_manager_, +StagingBufferPool::StagingBufferPool(const Device& device_, MemoryAllocator& memory_allocator_, VKScheduler& scheduler_) - : device{device_}, memory_manager{memory_manager_}, scheduler{scheduler_} {} + : device{device_}, memory_allocator{memory_allocator_}, scheduler{scheduler_} {} StagingBufferPool::~StagingBufferPool() = default; @@ -76,7 +76,7 @@ StagingBufferRef StagingBufferPool::CreateStagingBuffer(size_t size, bool host_v ++buffer_index; buffer.SetObjectNameEXT(fmt::format("Staging Buffer {}", buffer_index).c_str()); } - MemoryCommit commit = memory_manager.Commit(buffer, host_visible); + MemoryCommit commit = memory_allocator.Commit(buffer, host_visible); const std::span mapped_span = host_visible ? commit.Map() : std::span{}; StagingBuffer& entry = GetCache(host_visible)[log2].entries.emplace_back(StagingBuffer{ 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 5234a95fa..05697e47c 100644 --- a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h +++ b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h @@ -24,7 +24,7 @@ struct StagingBufferRef { class StagingBufferPool { public: - explicit StagingBufferPool(const Device& device, VKMemoryManager& memory_manager, + explicit StagingBufferPool(const Device& device, MemoryAllocator& memory_allocator, VKScheduler& scheduler); ~StagingBufferPool(); @@ -67,7 +67,7 @@ private: void ReleaseLevel(StagingBuffersCache& cache, size_t log2); const Device& device; - VKMemoryManager& memory_manager; + MemoryAllocator& memory_allocator; VKScheduler& scheduler; StagingBuffersCache host_staging_buffers; diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index 5acbcad76..a0a9b9559 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp @@ -788,9 +788,9 @@ Image::Image(TextureCacheRuntime& runtime, const ImageInfo& info_, GPUVAddr gpu_ image(MakeImage(runtime.device, info)), buffer(MakeBuffer(runtime.device, info)), aspect_mask(ImageAspectMask(info.format)) { if (image) { - commit = runtime.memory_manager.Commit(image, false); + commit = runtime.memory_allocator.Commit(image, false); } else { - commit = runtime.memory_manager.Commit(buffer, false); + commit = runtime.memory_allocator.Commit(buffer, false); } if (IsPixelFormatASTC(info.format) && !runtime.device.IsOptimalAstcSupported()) { 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 134465fd4..6a276d578 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.h +++ b/src/video_core/renderer_vulkan/vk_texture_cache.h @@ -69,7 +69,7 @@ struct ImageBufferMap { struct TextureCacheRuntime { const Device& device; VKScheduler& scheduler; - VKMemoryManager& memory_manager; + MemoryAllocator& memory_allocator; StagingBufferPool& staging_buffer_pool; BlitImageHelper& blit_image_helper; std::unordered_map renderpass_cache; -- cgit v1.2.3 From fade63b58e020d7cc72fa8be26914a89ef21c653 Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Sun, 3 Jan 2021 18:17:57 -0300 Subject: vulkan_common: Move allocator to the common directory Allow using the abstraction from the OpenGL backend. --- src/video_core/CMakeLists.txt | 4 +- src/video_core/renderer_vulkan/renderer_vulkan.cpp | 2 +- src/video_core/renderer_vulkan/vk_blit_screen.cpp | 2 +- src/video_core/renderer_vulkan/vk_blit_screen.h | 2 +- src/video_core/renderer_vulkan/vk_buffer_cache.h | 2 +- .../renderer_vulkan/vk_memory_manager.cpp | 227 --------------------- src/video_core/renderer_vulkan/vk_memory_manager.h | 95 --------- src/video_core/renderer_vulkan/vk_rasterizer.h | 2 +- .../renderer_vulkan/vk_staging_buffer_pool.h | 2 +- .../renderer_vulkan/vk_texture_cache.cpp | 2 +- src/video_core/renderer_vulkan/vk_texture_cache.h | 2 +- .../vulkan_common/vulkan_memory_allocator.cpp | 227 +++++++++++++++++++++ .../vulkan_common/vulkan_memory_allocator.h | 95 +++++++++ 13 files changed, 332 insertions(+), 332 deletions(-) delete mode 100644 src/video_core/renderer_vulkan/vk_memory_manager.cpp delete mode 100644 src/video_core/renderer_vulkan/vk_memory_manager.h create mode 100644 src/video_core/vulkan_common/vulkan_memory_allocator.cpp create mode 100644 src/video_core/vulkan_common/vulkan_memory_allocator.h (limited to 'src') 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 renderer_vulkan/vk_graphics_pipeline.h renderer_vulkan/vk_master_semaphore.cpp renderer_vulkan/vk_master_semaphore.h - renderer_vulkan/vk_memory_manager.cpp - renderer_vulkan/vk_memory_manager.h renderer_vulkan/vk_pipeline_cache.cpp renderer_vulkan/vk_pipeline_cache.h renderer_vulkan/vk_query_cache.cpp @@ -259,6 +257,8 @@ add_library(video_core STATIC vulkan_common/vulkan_instance.h vulkan_common/vulkan_library.cpp vulkan_common/vulkan_library.h + vulkan_common/vulkan_memory_allocator.cpp + vulkan_common/vulkan_memory_allocator.h vulkan_common/vulkan_surface.cpp vulkan_common/vulkan_surface.h 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 657de69a5..61796e33a 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp @@ -23,7 +23,6 @@ #include "video_core/renderer_vulkan/renderer_vulkan.h" #include "video_core/renderer_vulkan/vk_blit_screen.h" #include "video_core/renderer_vulkan/vk_master_semaphore.h" -#include "video_core/renderer_vulkan/vk_memory_manager.h" #include "video_core/renderer_vulkan/vk_rasterizer.h" #include "video_core/renderer_vulkan/vk_scheduler.h" #include "video_core/renderer_vulkan/vk_state_tracker.h" @@ -32,6 +31,7 @@ #include "video_core/vulkan_common/vulkan_device.h" #include "video_core/vulkan_common/vulkan_instance.h" #include "video_core/vulkan_common/vulkan_library.h" +#include "video_core/vulkan_common/vulkan_memory_allocator.h" #include "video_core/vulkan_common/vulkan_surface.h" #include "video_core/vulkan_common/vulkan_wrapper.h" diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.cpp b/src/video_core/renderer_vulkan/vk_blit_screen.cpp index 79d8ef71a..f06af06c8 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 @@ #include "video_core/renderer_vulkan/renderer_vulkan.h" #include "video_core/renderer_vulkan/vk_blit_screen.h" #include "video_core/renderer_vulkan/vk_master_semaphore.h" -#include "video_core/renderer_vulkan/vk_memory_manager.h" #include "video_core/renderer_vulkan/vk_scheduler.h" #include "video_core/renderer_vulkan/vk_shader_util.h" #include "video_core/renderer_vulkan/vk_swapchain.h" #include "video_core/surface.h" #include "video_core/textures/decoders.h" #include "video_core/vulkan_common/vulkan_device.h" +#include "video_core/vulkan_common/vulkan_memory_allocator.h" #include "video_core/vulkan_common/vulkan_wrapper.h" namespace Vulkan { diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.h b/src/video_core/renderer_vulkan/vk_blit_screen.h index e52d9885e..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 @@ #include -#include "video_core/renderer_vulkan/vk_memory_manager.h" +#include "video_core/vulkan_common/vulkan_memory_allocator.h" #include "video_core/vulkan_common/vulkan_wrapper.h" namespace Core { diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.h b/src/video_core/renderer_vulkan/vk_buffer_cache.h index 4db5259ef..41d577510 100644 --- a/src/video_core/renderer_vulkan/vk_buffer_cache.h +++ b/src/video_core/renderer_vulkan/vk_buffer_cache.h @@ -8,9 +8,9 @@ #include "common/common_types.h" #include "video_core/buffer_cache/buffer_cache.h" -#include "video_core/renderer_vulkan/vk_memory_manager.h" #include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" #include "video_core/renderer_vulkan/vk_stream_buffer.h" +#include "video_core/vulkan_common/vulkan_memory_allocator.h" #include "video_core/vulkan_common/vulkan_wrapper.h" namespace Vulkan { 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 cabf0b6ca..000000000 --- a/src/video_core/renderer_vulkan/vk_memory_manager.cpp +++ /dev/null @@ -1,227 +0,0 @@ -// Copyright 2018 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include -#include -#include -#include -#include - -#include "common/alignment.h" -#include "common/assert.h" -#include "common/common_types.h" -#include "common/logging/log.h" -#include "video_core/renderer_vulkan/vk_memory_manager.h" -#include "video_core/vulkan_common/vulkan_device.h" -#include "video_core/vulkan_common/vulkan_wrapper.h" - -namespace Vulkan { -namespace { -struct Range { - u64 begin; - u64 end; - - [[nodiscard]] bool Contains(u64 iterator, u64 size) const noexcept { - return iterator < end && begin < iterator + size; - } -}; - -[[nodiscard]] u64 GetAllocationChunkSize(u64 required_size) { - static constexpr std::array sizes{ - 0x1000ULL << 10, 0x1400ULL << 10, 0x1800ULL << 10, 0x1c00ULL << 10, 0x2000ULL << 10, - 0x3200ULL << 10, 0x4000ULL << 10, 0x6000ULL << 10, 0x8000ULL << 10, 0xA000ULL << 10, - 0x10000ULL << 10, 0x18000ULL << 10, 0x20000ULL << 10, - }; - static_assert(std::is_sorted(sizes.begin(), sizes.end())); - - const auto it = std::ranges::lower_bound(sizes, required_size); - return it != sizes.end() ? *it : Common::AlignUp(required_size, 4ULL << 20); -} -} // Anonymous namespace - -class MemoryAllocation { -public: - explicit MemoryAllocation(const Device& device_, vk::DeviceMemory memory_, - VkMemoryPropertyFlags properties_, u64 allocation_size_, u32 type_) - : device{device_}, memory{std::move(memory_)}, properties{properties_}, - allocation_size{allocation_size_}, shifted_type{ShiftType(type_)} {} - - [[nodiscard]] std::optional Commit(VkDeviceSize size, VkDeviceSize alignment) { - const std::optional alloc = FindFreeRegion(size, alignment); - if (!alloc) { - // Signal out of memory, it'll try to do more allocations. - return std::nullopt; - } - const Range range{ - .begin = *alloc, - .end = *alloc + size, - }; - commits.insert(std::ranges::upper_bound(commits, *alloc, {}, &Range::begin), range); - return std::make_optional(device, this, *memory, *alloc, *alloc + size); - } - - void Free(u64 begin) { - const auto it = std::ranges::find(commits, begin, &Range::begin); - ASSERT_MSG(it != commits.end(), "Invalid commit"); - commits.erase(it); - } - - [[nodiscard]] std::span Map() { - if (!memory_mapped_span.empty()) { - return memory_mapped_span; - } - u8* const raw_pointer = memory.Map(0, allocation_size); - memory_mapped_span = std::span(raw_pointer, allocation_size); - return memory_mapped_span; - } - - /// Returns whether this allocation is compatible with the arguments. - [[nodiscard]] bool IsCompatible(VkMemoryPropertyFlags wanted_properties, u32 type_mask) const { - return (wanted_properties & properties) && (type_mask & shifted_type) != 0; - } - -private: - [[nodiscard]] static constexpr u32 ShiftType(u32 type) { - return 1U << type; - } - - [[nodiscard]] std::optional FindFreeRegion(u64 size, u64 alignment) noexcept { - ASSERT(std::has_single_bit(alignment)); - const u64 alignment_log2 = std::countr_zero(alignment); - std::optional candidate; - u64 iterator = 0; - auto commit = commits.begin(); - while (iterator + size <= allocation_size) { - candidate = candidate.value_or(iterator); - if (commit == commits.end()) { - break; - } - if (commit->Contains(*candidate, size)) { - candidate = std::nullopt; - } - iterator = Common::AlignUpLog2(commit->end, alignment_log2); - ++commit; - } - return candidate; - } - - const Device& device; ///< Vulkan device. - const vk::DeviceMemory memory; ///< Vulkan memory allocation handler. - const VkMemoryPropertyFlags properties; ///< Vulkan properties. - const u64 allocation_size; ///< Size of this allocation. - const u32 shifted_type; ///< Stored Vulkan type of this allocation, shifted. - std::vector commits; ///< All commit ranges done from this allocation. - std::span memory_mapped_span; ///< Memory mapped span. Empty if not queried before. -}; - -MemoryCommit::MemoryCommit(const Device& device_, MemoryAllocation* allocation_, - VkDeviceMemory memory_, u64 begin, u64 end) noexcept - : device{&device_}, allocation{allocation_}, memory{memory_}, interval{begin, end} {} - -MemoryCommit::~MemoryCommit() { - Release(); -} - -MemoryCommit& MemoryCommit::operator=(MemoryCommit&& rhs) noexcept { - Release(); - device = rhs.device; - allocation = std::exchange(rhs.allocation, nullptr); - memory = rhs.memory; - interval = rhs.interval; - span = std::exchange(rhs.span, std::span{}); - return *this; -} - -MemoryCommit::MemoryCommit(MemoryCommit&& rhs) noexcept - : device{rhs.device}, allocation{std::exchange(rhs.allocation, nullptr)}, memory{rhs.memory}, - interval{rhs.interval}, span{std::exchange(rhs.span, std::span{})} {} - -std::span MemoryCommit::Map() { - if (!span.empty()) { - return span; - } - span = allocation->Map().subspan(interval.first, interval.second - interval.first); - return span; -} - -void MemoryCommit::Release() { - if (allocation) { - allocation->Free(interval.first); - } -} - -MemoryAllocator::MemoryAllocator(const Device& device_) - : device{device_}, properties{device_.GetPhysical().GetMemoryProperties()} {} - -MemoryAllocator::~MemoryAllocator() = default; - -MemoryCommit MemoryAllocator::Commit(const VkMemoryRequirements& requirements, bool host_visible) { - const u64 chunk_size = GetAllocationChunkSize(requirements.size); - - // When a host visible commit is asked, search for host visible and coherent, otherwise search - // for a fast device local type. - const VkMemoryPropertyFlags wanted_properties = - host_visible ? VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT - : VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; - if (std::optional commit = TryAllocCommit(requirements, wanted_properties)) { - return std::move(*commit); - } - // Commit has failed, allocate more memory. - // TODO(Rodrigo): Handle out of memory situations in some way like flushing to guest memory. - AllocMemory(wanted_properties, requirements.memoryTypeBits, chunk_size); - - // Commit again, this time it won't fail since there's a fresh allocation above. - // If it does, there's a bug. - return TryAllocCommit(requirements, wanted_properties).value(); -} - -MemoryCommit MemoryAllocator::Commit(const vk::Buffer& buffer, bool host_visible) { - auto commit = Commit(device.GetLogical().GetBufferMemoryRequirements(*buffer), host_visible); - buffer.BindMemory(commit.Memory(), commit.Offset()); - return commit; -} - -MemoryCommit MemoryAllocator::Commit(const vk::Image& image, bool host_visible) { - auto commit = Commit(device.GetLogical().GetImageMemoryRequirements(*image), host_visible); - image.BindMemory(commit.Memory(), commit.Offset()); - return commit; -} - -void MemoryAllocator::AllocMemory(VkMemoryPropertyFlags wanted_properties, u32 type_mask, - u64 size) { - const u32 type = [&] { - for (u32 type_index = 0; type_index < properties.memoryTypeCount; ++type_index) { - const auto flags = properties.memoryTypes[type_index].propertyFlags; - if ((type_mask & (1U << type_index)) && (flags & wanted_properties)) { - // The type matches in type and in the wanted properties. - return type_index; - } - } - UNREACHABLE_MSG("Couldn't find a compatible memory type!"); - return 0U; - }(); - vk::DeviceMemory memory = device.GetLogical().AllocateMemory({ - .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, - .pNext = nullptr, - .allocationSize = size, - .memoryTypeIndex = type, - }); - allocations.push_back(std::make_unique(device, std::move(memory), - wanted_properties, size, type)); -} - -std::optional MemoryAllocator::TryAllocCommit( - const VkMemoryRequirements& requirements, VkMemoryPropertyFlags wanted_properties) { - for (auto& allocation : allocations) { - if (!allocation->IsCompatible(wanted_properties, requirements.memoryTypeBits)) { - continue; - } - if (auto commit = allocation->Commit(requirements.size, requirements.alignment)) { - return commit; - } - } - return std::nullopt; -} - -} // 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 69a6341e1..000000000 --- a/src/video_core/renderer_vulkan/vk_memory_manager.h +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright 2019 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include -#include -#include -#include -#include "common/common_types.h" -#include "video_core/vulkan_common/vulkan_wrapper.h" - -namespace Vulkan { - -class Device; -class MemoryMap; -class MemoryAllocation; - -class MemoryCommit final { -public: - explicit MemoryCommit() noexcept = default; - explicit MemoryCommit(const Device& device_, MemoryAllocation* allocation_, - VkDeviceMemory memory_, u64 begin, u64 end) noexcept; - ~MemoryCommit(); - - MemoryCommit& operator=(MemoryCommit&&) noexcept; - MemoryCommit(MemoryCommit&&) noexcept; - - MemoryCommit& operator=(const MemoryCommit&) = delete; - MemoryCommit(const MemoryCommit&) = delete; - - /// Returns a host visible memory map. - /// It will map the backing allocation if it hasn't been mapped before. - std::span Map(); - - /// Returns the Vulkan memory handler. - VkDeviceMemory Memory() const { - return memory; - } - - /// Returns the start position of the commit relative to the allocation. - VkDeviceSize Offset() const { - return static_cast(interval.first); - } - -private: - void Release(); - - const Device* device{}; ///< Vulkan device. - MemoryAllocation* allocation{}; ///< Pointer to the large memory allocation. - VkDeviceMemory memory{}; ///< Vulkan device memory handler. - std::pair interval{}; ///< Interval where the commit exists. - std::span span; ///< Host visible memory span. Empty if not queried before. -}; - -class MemoryAllocator final { -public: - explicit MemoryAllocator(const Device& device_); - ~MemoryAllocator(); - - MemoryAllocator& operator=(const MemoryAllocator&) = delete; - MemoryAllocator(const MemoryAllocator&) = delete; - - /** - * Commits a memory with the specified requeriments. - * - * @param requirements Requirements returned from a Vulkan call. - * @param host_visible Signals the allocator that it *must* use host visible and coherent - * memory. When passing false, it will try to allocate device local memory. - * - * @returns A memory commit. - */ - MemoryCommit Commit(const VkMemoryRequirements& requirements, bool host_visible); - - /// Commits memory required by the buffer and binds it. - MemoryCommit Commit(const vk::Buffer& buffer, bool host_visible); - - /// Commits memory required by the image and binds it. - MemoryCommit Commit(const vk::Image& image, bool host_visible); - -private: - /// Allocates a chunk of memory. - void AllocMemory(VkMemoryPropertyFlags wanted_properties, u32 type_mask, u64 size); - - /// Tries to allocate a memory commit. - std::optional TryAllocCommit(const VkMemoryRequirements& requirements, - VkMemoryPropertyFlags wanted_properties); - - const Device& device; ///< Device handler. - const VkPhysicalDeviceMemoryProperties properties; ///< Physical device properties. - std::vector> allocations; ///< Current allocations. -}; - -} // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.h b/src/video_core/renderer_vulkan/vk_rasterizer.h index 72e679ffd..8e261b9bd 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.h +++ b/src/video_core/renderer_vulkan/vk_rasterizer.h @@ -21,7 +21,6 @@ #include "video_core/renderer_vulkan/vk_compute_pass.h" #include "video_core/renderer_vulkan/vk_descriptor_pool.h" #include "video_core/renderer_vulkan/vk_fence_manager.h" -#include "video_core/renderer_vulkan/vk_memory_manager.h" #include "video_core/renderer_vulkan/vk_pipeline_cache.h" #include "video_core/renderer_vulkan/vk_query_cache.h" #include "video_core/renderer_vulkan/vk_scheduler.h" @@ -30,6 +29,7 @@ #include "video_core/renderer_vulkan/vk_texture_cache.h" #include "video_core/renderer_vulkan/vk_update_descriptor.h" #include "video_core/shader/async_shaders.h" +#include "video_core/vulkan_common/vulkan_memory_allocator.h" #include "video_core/vulkan_common/vulkan_wrapper.h" namespace Core { 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 05697e47c..1a4338609 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 @@ #include "common/common_types.h" -#include "video_core/renderer_vulkan/vk_memory_manager.h" +#include "video_core/vulkan_common/vulkan_memory_allocator.h" #include "video_core/vulkan_common/vulkan_wrapper.h" 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 a0a9b9559..15cd50c24 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 @@ #include "video_core/engines/fermi_2d.h" #include "video_core/renderer_vulkan/blit_image.h" #include "video_core/renderer_vulkan/maxwell_to_vk.h" -#include "video_core/renderer_vulkan/vk_memory_manager.h" #include "video_core/renderer_vulkan/vk_rasterizer.h" #include "video_core/renderer_vulkan/vk_scheduler.h" #include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" #include "video_core/renderer_vulkan/vk_texture_cache.h" #include "video_core/vulkan_common/vulkan_device.h" +#include "video_core/vulkan_common/vulkan_memory_allocator.h" #include "video_core/vulkan_common/vulkan_wrapper.h" namespace Vulkan { diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.h b/src/video_core/renderer_vulkan/vk_texture_cache.h index 6a276d578..5da791a56 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 @@ #include #include -#include "video_core/renderer_vulkan/vk_memory_manager.h" #include "video_core/texture_cache/texture_cache.h" +#include "video_core/vulkan_common/vulkan_memory_allocator.h" #include "video_core/vulkan_common/vulkan_wrapper.h" namespace Vulkan { 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..c1cf292af --- /dev/null +++ b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp @@ -0,0 +1,227 @@ +// Copyright 2018 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include +#include +#include +#include +#include + +#include "common/alignment.h" +#include "common/assert.h" +#include "common/common_types.h" +#include "common/logging/log.h" +#include "video_core/vulkan_common/vulkan_device.h" +#include "video_core/vulkan_common/vulkan_memory_allocator.h" +#include "video_core/vulkan_common/vulkan_wrapper.h" + +namespace Vulkan { +namespace { +struct Range { + u64 begin; + u64 end; + + [[nodiscard]] bool Contains(u64 iterator, u64 size) const noexcept { + return iterator < end && begin < iterator + size; + } +}; + +[[nodiscard]] u64 GetAllocationChunkSize(u64 required_size) { + static constexpr std::array sizes{ + 0x1000ULL << 10, 0x1400ULL << 10, 0x1800ULL << 10, 0x1c00ULL << 10, 0x2000ULL << 10, + 0x3200ULL << 10, 0x4000ULL << 10, 0x6000ULL << 10, 0x8000ULL << 10, 0xA000ULL << 10, + 0x10000ULL << 10, 0x18000ULL << 10, 0x20000ULL << 10, + }; + static_assert(std::is_sorted(sizes.begin(), sizes.end())); + + const auto it = std::ranges::lower_bound(sizes, required_size); + return it != sizes.end() ? *it : Common::AlignUp(required_size, 4ULL << 20); +} +} // Anonymous namespace + +class MemoryAllocation { +public: + explicit MemoryAllocation(const Device& device_, vk::DeviceMemory memory_, + VkMemoryPropertyFlags properties_, u64 allocation_size_, u32 type_) + : device{device_}, memory{std::move(memory_)}, properties{properties_}, + allocation_size{allocation_size_}, shifted_type{ShiftType(type_)} {} + + [[nodiscard]] std::optional Commit(VkDeviceSize size, VkDeviceSize alignment) { + const std::optional alloc = FindFreeRegion(size, alignment); + if (!alloc) { + // Signal out of memory, it'll try to do more allocations. + return std::nullopt; + } + const Range range{ + .begin = *alloc, + .end = *alloc + size, + }; + commits.insert(std::ranges::upper_bound(commits, *alloc, {}, &Range::begin), range); + return std::make_optional(device, this, *memory, *alloc, *alloc + size); + } + + void Free(u64 begin) { + const auto it = std::ranges::find(commits, begin, &Range::begin); + ASSERT_MSG(it != commits.end(), "Invalid commit"); + commits.erase(it); + } + + [[nodiscard]] std::span Map() { + if (!memory_mapped_span.empty()) { + return memory_mapped_span; + } + u8* const raw_pointer = memory.Map(0, allocation_size); + memory_mapped_span = std::span(raw_pointer, allocation_size); + return memory_mapped_span; + } + + /// Returns whether this allocation is compatible with the arguments. + [[nodiscard]] bool IsCompatible(VkMemoryPropertyFlags wanted_properties, u32 type_mask) const { + return (wanted_properties & properties) && (type_mask & shifted_type) != 0; + } + +private: + [[nodiscard]] static constexpr u32 ShiftType(u32 type) { + return 1U << type; + } + + [[nodiscard]] std::optional FindFreeRegion(u64 size, u64 alignment) noexcept { + ASSERT(std::has_single_bit(alignment)); + const u64 alignment_log2 = std::countr_zero(alignment); + std::optional candidate; + u64 iterator = 0; + auto commit = commits.begin(); + while (iterator + size <= allocation_size) { + candidate = candidate.value_or(iterator); + if (commit == commits.end()) { + break; + } + if (commit->Contains(*candidate, size)) { + candidate = std::nullopt; + } + iterator = Common::AlignUpLog2(commit->end, alignment_log2); + ++commit; + } + return candidate; + } + + const Device& device; ///< Vulkan device. + const vk::DeviceMemory memory; ///< Vulkan memory allocation handler. + const VkMemoryPropertyFlags properties; ///< Vulkan properties. + const u64 allocation_size; ///< Size of this allocation. + const u32 shifted_type; ///< Stored Vulkan type of this allocation, shifted. + std::vector commits; ///< All commit ranges done from this allocation. + std::span memory_mapped_span; ///< Memory mapped span. Empty if not queried before. +}; + +MemoryCommit::MemoryCommit(const Device& device_, MemoryAllocation* allocation_, + VkDeviceMemory memory_, u64 begin, u64 end) noexcept + : device{&device_}, allocation{allocation_}, memory{memory_}, interval{begin, end} {} + +MemoryCommit::~MemoryCommit() { + Release(); +} + +MemoryCommit& MemoryCommit::operator=(MemoryCommit&& rhs) noexcept { + Release(); + device = rhs.device; + allocation = std::exchange(rhs.allocation, nullptr); + memory = rhs.memory; + interval = rhs.interval; + span = std::exchange(rhs.span, std::span{}); + return *this; +} + +MemoryCommit::MemoryCommit(MemoryCommit&& rhs) noexcept + : device{rhs.device}, allocation{std::exchange(rhs.allocation, nullptr)}, memory{rhs.memory}, + interval{rhs.interval}, span{std::exchange(rhs.span, std::span{})} {} + +std::span MemoryCommit::Map() { + if (!span.empty()) { + return span; + } + span = allocation->Map().subspan(interval.first, interval.second - interval.first); + return span; +} + +void MemoryCommit::Release() { + if (allocation) { + allocation->Free(interval.first); + } +} + +MemoryAllocator::MemoryAllocator(const Device& device_) + : device{device_}, properties{device_.GetPhysical().GetMemoryProperties()} {} + +MemoryAllocator::~MemoryAllocator() = default; + +MemoryCommit MemoryAllocator::Commit(const VkMemoryRequirements& requirements, bool host_visible) { + const u64 chunk_size = GetAllocationChunkSize(requirements.size); + + // When a host visible commit is asked, search for host visible and coherent, otherwise search + // for a fast device local type. + const VkMemoryPropertyFlags wanted_properties = + host_visible ? VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT + : VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + if (std::optional commit = TryAllocCommit(requirements, wanted_properties)) { + return std::move(*commit); + } + // Commit has failed, allocate more memory. + // TODO(Rodrigo): Handle out of memory situations in some way like flushing to guest memory. + AllocMemory(wanted_properties, requirements.memoryTypeBits, chunk_size); + + // Commit again, this time it won't fail since there's a fresh allocation above. + // If it does, there's a bug. + return TryAllocCommit(requirements, wanted_properties).value(); +} + +MemoryCommit MemoryAllocator::Commit(const vk::Buffer& buffer, bool host_visible) { + auto commit = Commit(device.GetLogical().GetBufferMemoryRequirements(*buffer), host_visible); + buffer.BindMemory(commit.Memory(), commit.Offset()); + return commit; +} + +MemoryCommit MemoryAllocator::Commit(const vk::Image& image, bool host_visible) { + auto commit = Commit(device.GetLogical().GetImageMemoryRequirements(*image), host_visible); + image.BindMemory(commit.Memory(), commit.Offset()); + return commit; +} + +void MemoryAllocator::AllocMemory(VkMemoryPropertyFlags wanted_properties, u32 type_mask, + u64 size) { + const u32 type = [&] { + for (u32 type_index = 0; type_index < properties.memoryTypeCount; ++type_index) { + const auto flags = properties.memoryTypes[type_index].propertyFlags; + if ((type_mask & (1U << type_index)) && (flags & wanted_properties)) { + // The type matches in type and in the wanted properties. + return type_index; + } + } + UNREACHABLE_MSG("Couldn't find a compatible memory type!"); + return 0U; + }(); + vk::DeviceMemory memory = device.GetLogical().AllocateMemory({ + .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, + .pNext = nullptr, + .allocationSize = size, + .memoryTypeIndex = type, + }); + allocations.push_back(std::make_unique(device, std::move(memory), + wanted_properties, size, type)); +} + +std::optional MemoryAllocator::TryAllocCommit( + const VkMemoryRequirements& requirements, VkMemoryPropertyFlags wanted_properties) { + for (auto& allocation : allocations) { + if (!allocation->IsCompatible(wanted_properties, requirements.memoryTypeBits)) { + continue; + } + if (auto commit = allocation->Commit(requirements.size, requirements.alignment)) { + return commit; + } + } + return std::nullopt; +} + +} // 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..69a6341e1 --- /dev/null +++ b/src/video_core/vulkan_common/vulkan_memory_allocator.h @@ -0,0 +1,95 @@ +// Copyright 2019 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include +#include +#include +#include "common/common_types.h" +#include "video_core/vulkan_common/vulkan_wrapper.h" + +namespace Vulkan { + +class Device; +class MemoryMap; +class MemoryAllocation; + +class MemoryCommit final { +public: + explicit MemoryCommit() noexcept = default; + explicit MemoryCommit(const Device& device_, MemoryAllocation* allocation_, + VkDeviceMemory memory_, u64 begin, u64 end) noexcept; + ~MemoryCommit(); + + MemoryCommit& operator=(MemoryCommit&&) noexcept; + MemoryCommit(MemoryCommit&&) noexcept; + + MemoryCommit& operator=(const MemoryCommit&) = delete; + MemoryCommit(const MemoryCommit&) = delete; + + /// Returns a host visible memory map. + /// It will map the backing allocation if it hasn't been mapped before. + std::span Map(); + + /// Returns the Vulkan memory handler. + VkDeviceMemory Memory() const { + return memory; + } + + /// Returns the start position of the commit relative to the allocation. + VkDeviceSize Offset() const { + return static_cast(interval.first); + } + +private: + void Release(); + + const Device* device{}; ///< Vulkan device. + MemoryAllocation* allocation{}; ///< Pointer to the large memory allocation. + VkDeviceMemory memory{}; ///< Vulkan device memory handler. + std::pair interval{}; ///< Interval where the commit exists. + std::span span; ///< Host visible memory span. Empty if not queried before. +}; + +class MemoryAllocator final { +public: + explicit MemoryAllocator(const Device& device_); + ~MemoryAllocator(); + + MemoryAllocator& operator=(const MemoryAllocator&) = delete; + MemoryAllocator(const MemoryAllocator&) = delete; + + /** + * Commits a memory with the specified requeriments. + * + * @param requirements Requirements returned from a Vulkan call. + * @param host_visible Signals the allocator that it *must* use host visible and coherent + * memory. When passing false, it will try to allocate device local memory. + * + * @returns A memory commit. + */ + MemoryCommit Commit(const VkMemoryRequirements& requirements, bool host_visible); + + /// Commits memory required by the buffer and binds it. + MemoryCommit Commit(const vk::Buffer& buffer, bool host_visible); + + /// Commits memory required by the image and binds it. + MemoryCommit Commit(const vk::Image& image, bool host_visible); + +private: + /// Allocates a chunk of memory. + void AllocMemory(VkMemoryPropertyFlags wanted_properties, u32 type_mask, u64 size); + + /// Tries to allocate a memory commit. + std::optional TryAllocCommit(const VkMemoryRequirements& requirements, + VkMemoryPropertyFlags wanted_properties); + + const Device& device; ///< Device handler. + const VkPhysicalDeviceMemoryProperties properties; ///< Physical device properties. + std::vector> allocations; ///< Current allocations. +}; + +} // namespace Vulkan -- cgit v1.2.3 From 72541af3bc8973fba0f0e3d1302fcd0fa7fb9f06 Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Sun, 3 Jan 2021 18:38:15 -0300 Subject: vulkan_memory_allocator: Add "download" memory usage hint Allow users of the allocator to hint memory usage for downloads. This removes the non-descriptive boolean passed for "host visible" or not host visible memory commits, and uses an enum to hint device local, upload and download usages. --- src/video_core/renderer_vulkan/vk_blit_screen.cpp | 4 +-- src/video_core/renderer_vulkan/vk_buffer_cache.cpp | 8 ++--- src/video_core/renderer_vulkan/vk_compute_pass.cpp | 6 ++-- src/video_core/renderer_vulkan/vk_rasterizer.cpp | 2 +- .../renderer_vulkan/vk_staging_buffer_pool.cpp | 42 ++++++++++++++-------- .../renderer_vulkan/vk_staging_buffer_pool.h | 15 ++++---- .../renderer_vulkan/vk_texture_cache.cpp | 6 ++-- .../vulkan_common/vulkan_memory_allocator.cpp | 24 ++++++++++--- .../vulkan_common/vulkan_memory_allocator.h | 24 ++++++++++--- 9 files changed, 86 insertions(+), 45 deletions(-) (limited to 'src') diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.cpp b/src/video_core/renderer_vulkan/vk_blit_screen.cpp index f06af06c8..3e3b895e0 100644 --- a/src/video_core/renderer_vulkan/vk_blit_screen.cpp +++ b/src/video_core/renderer_vulkan/vk_blit_screen.cpp @@ -657,7 +657,7 @@ void VKBlitScreen::CreateStagingBuffer(const Tegra::FramebufferConfig& framebuff }; buffer = device.GetLogical().CreateBuffer(ci); - buffer_commit = memory_allocator.Commit(buffer, true); + buffer_commit = memory_allocator.Commit(buffer, MemoryUsage::Upload); } void VKBlitScreen::CreateRawImages(const Tegra::FramebufferConfig& framebuffer) { @@ -688,7 +688,7 @@ void VKBlitScreen::CreateRawImages(const Tegra::FramebufferConfig& framebuffer) .pQueueFamilyIndices = nullptr, .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, }); - raw_buffer_commits[i] = memory_allocator.Commit(raw_images[i], false); + raw_buffer_commits[i] = memory_allocator.Commit(raw_images[i], MemoryUsage::DeviceLocal); raw_image_views[i] = device.GetLogical().CreateImageView(VkImageViewCreateInfo{ .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, .pNext = nullptr, diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp index 94d3a9134..d8ad40a0f 100644 --- a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp @@ -50,13 +50,13 @@ Buffer::Buffer(const Device& device_, MemoryAllocator& memory_allocator, VKSched .queueFamilyIndexCount = 0, .pQueueFamilyIndices = nullptr, }); - commit = memory_allocator.Commit(buffer, false); + commit = memory_allocator.Commit(buffer, MemoryUsage::DeviceLocal); } Buffer::~Buffer() = default; void Buffer::Upload(std::size_t offset, std::size_t data_size, const u8* data) { - const auto& staging = staging_pool.Request(data_size, true); + const auto& staging = staging_pool.Request(data_size, MemoryUsage::Upload); std::memcpy(staging.mapped_span.data(), data, data_size); scheduler.RequestOutsideRenderPassOperationContext(); @@ -98,7 +98,7 @@ void Buffer::Upload(std::size_t offset, std::size_t data_size, const u8* data) { } void Buffer::Download(std::size_t offset, std::size_t data_size, u8* data) { - auto staging = staging_pool.Request(data_size, true); + auto staging = staging_pool.Request(data_size, MemoryUsage::Download); scheduler.RequestOutsideRenderPassOperationContext(); const VkBuffer handle = Handle(); @@ -179,7 +179,7 @@ std::shared_ptr VKBufferCache::CreateBlock(VAddr cpu_addr, std::size_t s VKBufferCache::BufferInfo VKBufferCache::GetEmptyBuffer(std::size_t size) { size = std::max(size, std::size_t(4)); - const auto& empty = staging_pool.Request(size, false); + const auto& empty = staging_pool.Request(size, MemoryUsage::DeviceLocal); scheduler.RequestOutsideRenderPassOperationContext(); scheduler.Record([size, buffer = empty.buffer](vk::CommandBuffer cmdbuf) { cmdbuf.FillBuffer(buffer, 0, size, 0); diff --git a/src/video_core/renderer_vulkan/vk_compute_pass.cpp b/src/video_core/renderer_vulkan/vk_compute_pass.cpp index d38087f41..5eb6a54be 100644 --- a/src/video_core/renderer_vulkan/vk_compute_pass.cpp +++ b/src/video_core/renderer_vulkan/vk_compute_pass.cpp @@ -177,7 +177,7 @@ QuadArrayPass::~QuadArrayPass() = default; std::pair QuadArrayPass::Assemble(u32 num_vertices, u32 first) { const u32 num_triangle_vertices = (num_vertices / 4) * 6; const std::size_t staging_size = num_triangle_vertices * sizeof(u32); - const auto staging_ref = staging_buffer_pool.Request(staging_size, false); + const auto staging_ref = staging_buffer_pool.Request(staging_size, MemoryUsage::DeviceLocal); update_descriptor_queue.Acquire(); update_descriptor_queue.AddBuffer(staging_ref.buffer, 0, staging_size); @@ -224,7 +224,7 @@ Uint8Pass::~Uint8Pass() = default; std::pair Uint8Pass::Assemble(u32 num_vertices, VkBuffer src_buffer, u64 src_offset) { const u32 staging_size = static_cast(num_vertices * sizeof(u16)); - const auto staging_ref = staging_buffer_pool.Request(staging_size, false); + const auto staging_ref = staging_buffer_pool.Request(staging_size, MemoryUsage::DeviceLocal); update_descriptor_queue.Acquire(); update_descriptor_queue.AddBuffer(src_buffer, src_offset, num_vertices); @@ -286,7 +286,7 @@ std::pair QuadIndexedPass::Assemble( const u32 num_tri_vertices = (num_vertices / 4) * 6; const std::size_t staging_size = num_tri_vertices * sizeof(u32); - const auto staging_ref = staging_buffer_pool.Request(staging_size, false); + const auto staging_ref = staging_buffer_pool.Request(staging_size, MemoryUsage::DeviceLocal); update_descriptor_queue.Acquire(); update_descriptor_queue.AddBuffer(src_buffer, src_offset, input_size); diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index f38ead9c2..f0a111829 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -1445,7 +1445,7 @@ VkBuffer RasterizerVulkan::DefaultBuffer() { .queueFamilyIndexCount = 0, .pQueueFamilyIndices = nullptr, }); - default_buffer_commit = memory_allocator.Commit(default_buffer, false); + default_buffer_commit = memory_allocator.Commit(default_buffer, MemoryUsage::DeviceLocal); scheduler.RequestOutsideRenderPassOperationContext(); scheduler.Record([buffer = *default_buffer](vk::CommandBuffer cmdbuf) { 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 44d332ed2..97fd41cc1 100644 --- a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp +++ b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp @@ -8,6 +8,7 @@ #include +#include "common/assert.h" #include "common/bit_util.h" #include "common/common_types.h" #include "video_core/renderer_vulkan/vk_scheduler.h" @@ -23,23 +24,24 @@ StagingBufferPool::StagingBufferPool(const Device& device_, MemoryAllocator& mem StagingBufferPool::~StagingBufferPool() = default; -StagingBufferRef StagingBufferPool::Request(size_t size, bool host_visible) { - if (const std::optional ref = TryGetReservedBuffer(size, host_visible)) { +StagingBufferRef StagingBufferPool::Request(size_t size, MemoryUsage usage) { + if (const std::optional ref = TryGetReservedBuffer(size, usage)) { return *ref; } - return CreateStagingBuffer(size, host_visible); + return CreateStagingBuffer(size, usage); } void StagingBufferPool::TickFrame() { current_delete_level = (current_delete_level + 1) % NUM_LEVELS; - ReleaseCache(true); - ReleaseCache(false); + ReleaseCache(MemoryUsage::DeviceLocal); + ReleaseCache(MemoryUsage::Upload); + ReleaseCache(MemoryUsage::Download); } std::optional StagingBufferPool::TryGetReservedBuffer(size_t size, - bool host_visible) { - StagingBuffers& cache_level = GetCache(host_visible)[Common::Log2Ceil64(size)]; + MemoryUsage usage) { + StagingBuffers& cache_level = GetCache(usage)[Common::Log2Ceil64(size)]; const auto is_free = [this](const StagingBuffer& entry) { return scheduler.IsFree(entry.tick); @@ -58,7 +60,7 @@ std::optional StagingBufferPool::TryGetReservedBuffer(size_t s return it->Ref(); } -StagingBufferRef StagingBufferPool::CreateStagingBuffer(size_t size, bool host_visible) { +StagingBufferRef StagingBufferPool::CreateStagingBuffer(size_t size, MemoryUsage usage) { const u32 log2 = Common::Log2Ceil64(size); vk::Buffer buffer = device.GetLogical().CreateBuffer({ .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, @@ -76,10 +78,10 @@ StagingBufferRef StagingBufferPool::CreateStagingBuffer(size_t size, bool host_v ++buffer_index; buffer.SetObjectNameEXT(fmt::format("Staging Buffer {}", buffer_index).c_str()); } - MemoryCommit commit = memory_allocator.Commit(buffer, host_visible); - const std::span mapped_span = host_visible ? commit.Map() : std::span{}; + MemoryCommit commit = memory_allocator.Commit(buffer, usage); + const std::span mapped_span = IsHostVisible(usage) ? commit.Map() : std::span{}; - StagingBuffer& entry = GetCache(host_visible)[log2].entries.emplace_back(StagingBuffer{ + StagingBuffer& entry = GetCache(usage)[log2].entries.emplace_back(StagingBuffer{ .buffer = std::move(buffer), .commit = std::move(commit), .mapped_span = mapped_span, @@ -88,12 +90,22 @@ StagingBufferRef StagingBufferPool::CreateStagingBuffer(size_t size, bool host_v return entry.Ref(); } -StagingBufferPool::StagingBuffersCache& StagingBufferPool::GetCache(bool host_visible) { - return host_visible ? host_staging_buffers : device_staging_buffers; +StagingBufferPool::StagingBuffersCache& StagingBufferPool::GetCache(MemoryUsage usage) { + switch (usage) { + case MemoryUsage::DeviceLocal: + return device_local_cache; + case MemoryUsage::Upload: + return upload_cache; + case MemoryUsage::Download: + return download_cache; + default: + UNREACHABLE_MSG("Invalid memory usage={}", usage); + return upload_cache; + } } -void StagingBufferPool::ReleaseCache(bool host_visible) { - ReleaseLevel(GetCache(host_visible), current_delete_level); +void StagingBufferPool::ReleaseCache(MemoryUsage usage) { + ReleaseLevel(GetCache(usage), current_delete_level); } void StagingBufferPool::ReleaseLevel(StagingBuffersCache& cache, size_t log2) { 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 1a4338609..d42918a47 100644 --- a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h +++ b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h @@ -28,7 +28,7 @@ public: VKScheduler& scheduler); ~StagingBufferPool(); - StagingBufferRef Request(size_t size, bool host_visible); + StagingBufferRef Request(size_t size, MemoryUsage usage); void TickFrame(); @@ -56,13 +56,13 @@ private: static constexpr size_t NUM_LEVELS = sizeof(size_t) * CHAR_BIT; using StagingBuffersCache = std::array; - std::optional TryGetReservedBuffer(size_t size, bool host_visible); + std::optional TryGetReservedBuffer(size_t size, MemoryUsage usage); - StagingBufferRef CreateStagingBuffer(size_t size, bool host_visible); + StagingBufferRef CreateStagingBuffer(size_t size, MemoryUsage usage); - StagingBuffersCache& GetCache(bool host_visible); + StagingBuffersCache& GetCache(MemoryUsage usage); - void ReleaseCache(bool host_visible); + void ReleaseCache(MemoryUsage usage); void ReleaseLevel(StagingBuffersCache& cache, size_t log2); @@ -70,8 +70,9 @@ private: MemoryAllocator& memory_allocator; VKScheduler& scheduler; - StagingBuffersCache host_staging_buffers; - StagingBuffersCache device_staging_buffers; + StagingBuffersCache device_local_cache; + StagingBuffersCache upload_cache; + StagingBuffersCache download_cache; size_t current_delete_level = 0; u64 buffer_index = 0; diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index 15cd50c24..a55f84045 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp @@ -554,7 +554,7 @@ void TextureCacheRuntime::Finish() { } ImageBufferMap TextureCacheRuntime::MapUploadBuffer(size_t size) { - const auto staging_ref = staging_buffer_pool.Request(size, true); + const auto staging_ref = staging_buffer_pool.Request(size, MemoryUsage::Upload); return ImageBufferMap{ .handle = staging_ref.buffer, .span = staging_ref.mapped_span, @@ -788,9 +788,9 @@ Image::Image(TextureCacheRuntime& runtime, const ImageInfo& info_, GPUVAddr gpu_ image(MakeImage(runtime.device, info)), buffer(MakeBuffer(runtime.device, info)), aspect_mask(ImageAspectMask(info.format)) { if (image) { - commit = runtime.memory_allocator.Commit(image, false); + commit = runtime.memory_allocator.Commit(image, MemoryUsage::DeviceLocal); } else { - commit = runtime.memory_allocator.Commit(buffer, false); + commit = runtime.memory_allocator.Commit(buffer, MemoryUsage::DeviceLocal); } if (IsPixelFormatASTC(info.format) && !runtime.device.IsOptimalAstcSupported()) { flags |= VideoCommon::ImageFlagBits::Converted; diff --git a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp index c1cf292af..8bb15794d 100644 --- a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp +++ b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp @@ -156,11 +156,13 @@ MemoryAllocator::MemoryAllocator(const Device& device_) MemoryAllocator::~MemoryAllocator() = default; -MemoryCommit MemoryAllocator::Commit(const VkMemoryRequirements& requirements, bool host_visible) { +MemoryCommit MemoryAllocator::Commit(const VkMemoryRequirements& requirements, MemoryUsage usage) { const u64 chunk_size = GetAllocationChunkSize(requirements.size); // When a host visible commit is asked, search for host visible and coherent, otherwise search // for a fast device local type. + // TODO: Deduce memory types from usage in a better way + const bool host_visible = IsHostVisible(usage); const VkMemoryPropertyFlags wanted_properties = host_visible ? VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT : VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; @@ -176,14 +178,14 @@ MemoryCommit MemoryAllocator::Commit(const VkMemoryRequirements& requirements, b return TryAllocCommit(requirements, wanted_properties).value(); } -MemoryCommit MemoryAllocator::Commit(const vk::Buffer& buffer, bool host_visible) { - auto commit = Commit(device.GetLogical().GetBufferMemoryRequirements(*buffer), host_visible); +MemoryCommit MemoryAllocator::Commit(const vk::Buffer& buffer, MemoryUsage usage) { + auto commit = Commit(device.GetLogical().GetBufferMemoryRequirements(*buffer), usage); buffer.BindMemory(commit.Memory(), commit.Offset()); return commit; } -MemoryCommit MemoryAllocator::Commit(const vk::Image& image, bool host_visible) { - auto commit = Commit(device.GetLogical().GetImageMemoryRequirements(*image), host_visible); +MemoryCommit MemoryAllocator::Commit(const vk::Image& image, MemoryUsage usage) { + auto commit = Commit(device.GetLogical().GetImageMemoryRequirements(*image), usage); image.BindMemory(commit.Memory(), commit.Offset()); return commit; } @@ -224,4 +226,16 @@ std::optional MemoryAllocator::TryAllocCommit( return std::nullopt; } +bool IsHostVisible(MemoryUsage usage) noexcept { + switch (usage) { + case MemoryUsage::DeviceLocal: + return false; + case MemoryUsage::Upload: + case MemoryUsage::Download: + return true; + } + UNREACHABLE_MSG("Invalid memory usage={}", usage); + return false; +} + } // namespace Vulkan diff --git a/src/video_core/vulkan_common/vulkan_memory_allocator.h b/src/video_core/vulkan_common/vulkan_memory_allocator.h index 69a6341e1..efb32167a 100644 --- a/src/video_core/vulkan_common/vulkan_memory_allocator.h +++ b/src/video_core/vulkan_common/vulkan_memory_allocator.h @@ -17,7 +17,16 @@ class Device; class MemoryMap; class MemoryAllocation; -class MemoryCommit final { +/// Hints and requirements for the backing memory type of a commit +enum class MemoryUsage { + DeviceLocal, ///< Hints device local usages, fastest memory type to read and write from the GPU + Upload, ///< Requires a host visible memory type optimized for CPU to GPU uploads + Download, ///< Requires a host visible memory type optimized for GPU to CPU readbacks +}; + +/// Ownership handle of a memory commitment. +/// Points to a subregion of a memory allocation. +class MemoryCommit { public: explicit MemoryCommit() noexcept = default; explicit MemoryCommit(const Device& device_, MemoryAllocation* allocation_, @@ -54,7 +63,9 @@ private: std::span span; ///< Host visible memory span. Empty if not queried before. }; -class MemoryAllocator final { +/// Memory allocator container. +/// Allocates and releases memory allocations on demand. +class MemoryAllocator { public: explicit MemoryAllocator(const Device& device_); ~MemoryAllocator(); @@ -71,13 +82,13 @@ public: * * @returns A memory commit. */ - MemoryCommit Commit(const VkMemoryRequirements& requirements, bool host_visible); + MemoryCommit Commit(const VkMemoryRequirements& requirements, MemoryUsage usage); /// Commits memory required by the buffer and binds it. - MemoryCommit Commit(const vk::Buffer& buffer, bool host_visible); + MemoryCommit Commit(const vk::Buffer& buffer, MemoryUsage usage); /// Commits memory required by the image and binds it. - MemoryCommit Commit(const vk::Image& image, bool host_visible); + MemoryCommit Commit(const vk::Image& image, MemoryUsage usage); private: /// Allocates a chunk of memory. @@ -92,4 +103,7 @@ private: std::vector> allocations; ///< Current allocations. }; +/// Returns true when a memory usage is guaranteed to be host visible. +bool IsHostVisible(MemoryUsage usage) noexcept; + } // namespace Vulkan -- cgit v1.2.3 From 8f22f5470c4875623f08019cb3d2556048710326 Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Sun, 3 Jan 2021 20:51:11 -0300 Subject: vulkan_memory_allocator: Add allocation support for download types Implements the allocator logic to handle download memory types. This will try to use HOST_CACHED_BIT when available. --- .../vulkan_common/vulkan_memory_allocator.cpp | 129 +++++++++++++-------- .../vulkan_common/vulkan_memory_allocator.h | 17 ++- 2 files changed, 91 insertions(+), 55 deletions(-) (limited to 'src') diff --git a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp index 8bb15794d..f15061d0c 100644 --- a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp +++ b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp @@ -5,7 +5,6 @@ #include #include #include -#include #include #include "common/alignment.h" @@ -27,7 +26,7 @@ struct Range { } }; -[[nodiscard]] u64 GetAllocationChunkSize(u64 required_size) { +[[nodiscard]] u64 AllocationChunkSize(u64 required_size) { static constexpr std::array sizes{ 0x1000ULL << 10, 0x1400ULL << 10, 0x1800ULL << 10, 0x1c00ULL << 10, 0x2000ULL << 10, 0x3200ULL << 10, 0x4000ULL << 10, 0x6000ULL << 10, 0x8000ULL << 10, 0xA000ULL << 10, @@ -38,14 +37,28 @@ struct Range { const auto it = std::ranges::lower_bound(sizes, required_size); return it != sizes.end() ? *it : Common::AlignUp(required_size, 4ULL << 20); } + +[[nodiscard]] VkMemoryPropertyFlags MemoryUsagePropertyFlags(MemoryUsage usage) { + switch (usage) { + case MemoryUsage::DeviceLocal: + return VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + case MemoryUsage::Upload: + return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; + case MemoryUsage::Download: + return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | + VK_MEMORY_PROPERTY_HOST_CACHED_BIT; + } + UNREACHABLE_MSG("Invalid memory usage={}", usage); + return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; +} } // Anonymous namespace class MemoryAllocation { public: explicit MemoryAllocation(const Device& device_, vk::DeviceMemory memory_, - VkMemoryPropertyFlags properties_, u64 allocation_size_, u32 type_) - : device{device_}, memory{std::move(memory_)}, properties{properties_}, - allocation_size{allocation_size_}, shifted_type{ShiftType(type_)} {} + VkMemoryPropertyFlags properties, u64 allocation_size_, u32 type) + : device{device_}, memory{std::move(memory_)}, allocation_size{allocation_size_}, + property_flags{properties}, shifted_memory_type{1U << type} {} [[nodiscard]] std::optional Commit(VkDeviceSize size, VkDeviceSize alignment) { const std::optional alloc = FindFreeRegion(size, alignment); @@ -68,17 +81,16 @@ public: } [[nodiscard]] std::span Map() { - if (!memory_mapped_span.empty()) { - return memory_mapped_span; + if (memory_mapped_span.empty()) { + u8* const raw_pointer = memory.Map(0, allocation_size); + memory_mapped_span = std::span(raw_pointer, allocation_size); } - u8* const raw_pointer = memory.Map(0, allocation_size); - memory_mapped_span = std::span(raw_pointer, allocation_size); return memory_mapped_span; } /// Returns whether this allocation is compatible with the arguments. - [[nodiscard]] bool IsCompatible(VkMemoryPropertyFlags wanted_properties, u32 type_mask) const { - return (wanted_properties & properties) && (type_mask & shifted_type) != 0; + [[nodiscard]] bool IsCompatible(VkMemoryPropertyFlags flags, u32 type_mask) const { + return (flags & property_flags) && (type_mask & shifted_memory_type) != 0; } private: @@ -106,13 +118,13 @@ private: return candidate; } - const Device& device; ///< Vulkan device. - const vk::DeviceMemory memory; ///< Vulkan memory allocation handler. - const VkMemoryPropertyFlags properties; ///< Vulkan properties. - const u64 allocation_size; ///< Size of this allocation. - const u32 shifted_type; ///< Stored Vulkan type of this allocation, shifted. - std::vector commits; ///< All commit ranges done from this allocation. - std::span memory_mapped_span; ///< Memory mapped span. Empty if not queried before. + const Device& device; ///< Vulkan device. + const vk::DeviceMemory memory; ///< Vulkan memory allocation handler. + const u64 allocation_size; ///< Size of this allocation. + const VkMemoryPropertyFlags property_flags; ///< Vulkan memory property flags. + const u32 shifted_memory_type; ///< Shifted Vulkan memory type. + std::vector commits; ///< All commit ranges done from this allocation. + std::span memory_mapped_span; ///< Memory mapped span. Empty if not queried before. }; MemoryCommit::MemoryCommit(const Device& device_, MemoryAllocation* allocation_, @@ -138,10 +150,9 @@ MemoryCommit::MemoryCommit(MemoryCommit&& rhs) noexcept interval{rhs.interval}, span{std::exchange(rhs.span, std::span{})} {} std::span MemoryCommit::Map() { - if (!span.empty()) { - return span; + if (span.empty()) { + span = allocation->Map().subspan(interval.first, interval.second - interval.first); } - span = allocation->Map().subspan(interval.first, interval.second - interval.first); return span; } @@ -157,25 +168,18 @@ MemoryAllocator::MemoryAllocator(const Device& device_) MemoryAllocator::~MemoryAllocator() = default; MemoryCommit MemoryAllocator::Commit(const VkMemoryRequirements& requirements, MemoryUsage usage) { - const u64 chunk_size = GetAllocationChunkSize(requirements.size); - - // When a host visible commit is asked, search for host visible and coherent, otherwise search - // for a fast device local type. - // TODO: Deduce memory types from usage in a better way - const bool host_visible = IsHostVisible(usage); - const VkMemoryPropertyFlags wanted_properties = - host_visible ? VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT - : VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; - if (std::optional commit = TryAllocCommit(requirements, wanted_properties)) { + // Find the fastest memory flags we can afford with the current requirements + const VkMemoryPropertyFlags flags = MemoryPropertyFlags(requirements.memoryTypeBits, usage); + if (std::optional commit = TryCommit(requirements, flags)) { return std::move(*commit); } // Commit has failed, allocate more memory. // TODO(Rodrigo): Handle out of memory situations in some way like flushing to guest memory. - AllocMemory(wanted_properties, requirements.memoryTypeBits, chunk_size); + AllocMemory(flags, requirements.memoryTypeBits, AllocationChunkSize(requirements.size)); // Commit again, this time it won't fail since there's a fresh allocation above. // If it does, there's a bug. - return TryAllocCommit(requirements, wanted_properties).value(); + return TryCommit(requirements, flags).value(); } MemoryCommit MemoryAllocator::Commit(const vk::Buffer& buffer, MemoryUsage usage) { @@ -190,33 +194,22 @@ MemoryCommit MemoryAllocator::Commit(const vk::Image& image, MemoryUsage usage) return commit; } -void MemoryAllocator::AllocMemory(VkMemoryPropertyFlags wanted_properties, u32 type_mask, - u64 size) { - const u32 type = [&] { - for (u32 type_index = 0; type_index < properties.memoryTypeCount; ++type_index) { - const auto flags = properties.memoryTypes[type_index].propertyFlags; - if ((type_mask & (1U << type_index)) && (flags & wanted_properties)) { - // The type matches in type and in the wanted properties. - return type_index; - } - } - UNREACHABLE_MSG("Couldn't find a compatible memory type!"); - return 0U; - }(); +void MemoryAllocator::AllocMemory(VkMemoryPropertyFlags flags, u32 type_mask, u64 size) { + const u32 type = FindType(flags, type_mask).value(); vk::DeviceMemory memory = device.GetLogical().AllocateMemory({ .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, .pNext = nullptr, .allocationSize = size, .memoryTypeIndex = type, }); - allocations.push_back(std::make_unique(device, std::move(memory), - wanted_properties, size, type)); + allocations.push_back( + std::make_unique(device, std::move(memory), flags, size, type)); } -std::optional MemoryAllocator::TryAllocCommit( - const VkMemoryRequirements& requirements, VkMemoryPropertyFlags wanted_properties) { +std::optional MemoryAllocator::TryCommit(const VkMemoryRequirements& requirements, + VkMemoryPropertyFlags flags) { for (auto& allocation : allocations) { - if (!allocation->IsCompatible(wanted_properties, requirements.memoryTypeBits)) { + if (!allocation->IsCompatible(flags, requirements.memoryTypeBits)) { continue; } if (auto commit = allocation->Commit(requirements.size, requirements.alignment)) { @@ -226,6 +219,40 @@ std::optional MemoryAllocator::TryAllocCommit( return std::nullopt; } +VkMemoryPropertyFlags MemoryAllocator::MemoryPropertyFlags(u32 type_mask, MemoryUsage usage) const { + return MemoryPropertyFlags(type_mask, MemoryUsagePropertyFlags(usage)); +} + +VkMemoryPropertyFlags MemoryAllocator::MemoryPropertyFlags(u32 type_mask, + VkMemoryPropertyFlags flags) const { + if (FindType(flags, type_mask)) { + // Found a memory type with those requirements + return flags; + } + if (flags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) { + // Remove host cached bit in case it's not supported + return MemoryPropertyFlags(type_mask, flags & ~VK_MEMORY_PROPERTY_HOST_CACHED_BIT); + } + if (flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) { + // Remove device local, if it's not supported by the requested resource + return MemoryPropertyFlags(type_mask, flags & ~VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + } + UNREACHABLE_MSG("No compatible memory types found"); + return 0; +} + +std::optional MemoryAllocator::FindType(VkMemoryPropertyFlags flags, u32 type_mask) const { + for (u32 type_index = 0; type_index < properties.memoryTypeCount; ++type_index) { + const VkMemoryPropertyFlags type_flags = properties.memoryTypes[type_index].propertyFlags; + if ((type_mask & (1U << type_index)) && (type_flags & flags)) { + // The type matches in type and in the wanted properties. + return type_index; + } + } + // Failed to find index + return std::nullopt; +} + bool IsHostVisible(MemoryUsage usage) noexcept { switch (usage) { case MemoryUsage::DeviceLocal: diff --git a/src/video_core/vulkan_common/vulkan_memory_allocator.h b/src/video_core/vulkan_common/vulkan_memory_allocator.h index efb32167a..d4e34c843 100644 --- a/src/video_core/vulkan_common/vulkan_memory_allocator.h +++ b/src/video_core/vulkan_common/vulkan_memory_allocator.h @@ -92,13 +92,22 @@ public: private: /// Allocates a chunk of memory. - void AllocMemory(VkMemoryPropertyFlags wanted_properties, u32 type_mask, u64 size); + void AllocMemory(VkMemoryPropertyFlags flags, u32 type_mask, u64 size); /// Tries to allocate a memory commit. - std::optional TryAllocCommit(const VkMemoryRequirements& requirements, - VkMemoryPropertyFlags wanted_properties); + std::optional TryCommit(const VkMemoryRequirements& requirements, + VkMemoryPropertyFlags flags); - const Device& device; ///< Device handler. + /// Returns the fastest compatible memory property flags from a wanted usage. + VkMemoryPropertyFlags MemoryPropertyFlags(u32 type_mask, MemoryUsage usage) const; + + /// Returns the fastest compatible memory property flags from the wanted flags. + VkMemoryPropertyFlags MemoryPropertyFlags(u32 type_mask, VkMemoryPropertyFlags flags) const; + + /// Returns index to the fastest memory type compatible with the passed requirements. + std::optional FindType(VkMemoryPropertyFlags flags, u32 type_mask) const; + + const Device& device; ///< Device handle. const VkPhysicalDeviceMemoryProperties properties; ///< Physical device properties. std::vector> allocations; ///< Current allocations. }; -- cgit v1.2.3 From 432f045dbaa9476b31530478d812067c9291f309 Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Sun, 3 Jan 2021 21:05:59 -0300 Subject: vk_texture_cache: Use Download memory types for texture flushes Use the Download memory type where it matters. --- src/video_core/renderer_vulkan/vk_texture_cache.cpp | 10 +++++++++- src/video_core/renderer_vulkan/vk_texture_cache.h | 5 +---- 2 files changed, 10 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index a55f84045..ab14922d7 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp @@ -555,7 +555,15 @@ void TextureCacheRuntime::Finish() { ImageBufferMap TextureCacheRuntime::MapUploadBuffer(size_t size) { const auto staging_ref = staging_buffer_pool.Request(size, MemoryUsage::Upload); - return ImageBufferMap{ + return { + .handle = staging_ref.buffer, + .span = staging_ref.mapped_span, + }; +} + +ImageBufferMap TextureCacheRuntime::MapDownloadBuffer(size_t size) { + const auto staging_ref = staging_buffer_pool.Request(size, MemoryUsage::Download); + return { .handle = staging_ref.buffer, .span = staging_ref.mapped_span, }; diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.h b/src/video_core/renderer_vulkan/vk_texture_cache.h index 5da791a56..a55d405d1 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.h +++ b/src/video_core/renderer_vulkan/vk_texture_cache.h @@ -78,10 +78,7 @@ struct TextureCacheRuntime { [[nodiscard]] ImageBufferMap MapUploadBuffer(size_t size); - [[nodiscard]] ImageBufferMap MapDownloadBuffer(size_t size) { - // TODO: Have a special function for this - return MapUploadBuffer(size); - } + [[nodiscard]] ImageBufferMap MapDownloadBuffer(size_t size); void BlitImage(Framebuffer* dst_framebuffer, ImageView& dst, ImageView& src, const std::array& dst_region, -- cgit v1.2.3 From 301e2b5b7a130730f42de2bb6615c0cacd78c7de Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Wed, 6 Jan 2021 01:18:37 -0300 Subject: vulkan_memory_allocator: Remove unnecesary 'device' memory from commits --- .../vulkan_common/vulkan_memory_allocator.cpp | 20 ++++++++++---------- .../vulkan_common/vulkan_memory_allocator.h | 10 +++++----- 2 files changed, 15 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp index f15061d0c..d6eb3af31 100644 --- a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp +++ b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp @@ -71,7 +71,7 @@ public: .end = *alloc + size, }; commits.insert(std::ranges::upper_bound(commits, *alloc, {}, &Range::begin), range); - return std::make_optional(device, this, *memory, *alloc, *alloc + size); + return std::make_optional(this, *memory, *alloc, *alloc + size); } void Free(u64 begin) { @@ -127,9 +127,9 @@ private: std::span memory_mapped_span; ///< Memory mapped span. Empty if not queried before. }; -MemoryCommit::MemoryCommit(const Device& device_, MemoryAllocation* allocation_, - VkDeviceMemory memory_, u64 begin, u64 end) noexcept - : device{&device_}, allocation{allocation_}, memory{memory_}, interval{begin, end} {} +MemoryCommit::MemoryCommit(MemoryAllocation* allocation_, VkDeviceMemory memory_, u64 begin_, + u64 end_) noexcept + : allocation{allocation_}, memory{memory_}, begin{begin_}, end{end_} {} MemoryCommit::~MemoryCommit() { Release(); @@ -137,28 +137,28 @@ MemoryCommit::~MemoryCommit() { MemoryCommit& MemoryCommit::operator=(MemoryCommit&& rhs) noexcept { Release(); - device = rhs.device; allocation = std::exchange(rhs.allocation, nullptr); memory = rhs.memory; - interval = rhs.interval; + begin = rhs.begin; + end = rhs.end; span = std::exchange(rhs.span, std::span{}); return *this; } MemoryCommit::MemoryCommit(MemoryCommit&& rhs) noexcept - : device{rhs.device}, allocation{std::exchange(rhs.allocation, nullptr)}, memory{rhs.memory}, - interval{rhs.interval}, span{std::exchange(rhs.span, std::span{})} {} + : allocation{std::exchange(rhs.allocation, nullptr)}, memory{rhs.memory}, begin{rhs.begin}, + end{rhs.end}, span{std::exchange(rhs.span, std::span{})} {} std::span MemoryCommit::Map() { if (span.empty()) { - span = allocation->Map().subspan(interval.first, interval.second - interval.first); + span = allocation->Map().subspan(begin, end - begin); } return span; } void MemoryCommit::Release() { if (allocation) { - allocation->Free(interval.first); + allocation->Free(begin); } } diff --git a/src/video_core/vulkan_common/vulkan_memory_allocator.h b/src/video_core/vulkan_common/vulkan_memory_allocator.h index d4e34c843..53b3b275a 100644 --- a/src/video_core/vulkan_common/vulkan_memory_allocator.h +++ b/src/video_core/vulkan_common/vulkan_memory_allocator.h @@ -29,8 +29,8 @@ enum class MemoryUsage { class MemoryCommit { public: explicit MemoryCommit() noexcept = default; - explicit MemoryCommit(const Device& device_, MemoryAllocation* allocation_, - VkDeviceMemory memory_, u64 begin, u64 end) noexcept; + explicit MemoryCommit(MemoryAllocation* allocation_, VkDeviceMemory memory_, u64 begin_, + u64 end_) noexcept; ~MemoryCommit(); MemoryCommit& operator=(MemoryCommit&&) noexcept; @@ -50,16 +50,16 @@ public: /// Returns the start position of the commit relative to the allocation. VkDeviceSize Offset() const { - return static_cast(interval.first); + return static_cast(begin); } private: void Release(); - const Device* device{}; ///< Vulkan device. MemoryAllocation* allocation{}; ///< Pointer to the large memory allocation. VkDeviceMemory memory{}; ///< Vulkan device memory handler. - std::pair interval{}; ///< Interval where the commit exists. + u64 begin{}; ///< Beginning offset in bytes to where the commit exists. + u64 end{}; ///< Offset in bytes where the commit ends. std::span span; ///< Host visible memory span. Empty if not queried before. }; -- cgit v1.2.3