summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/video_core/renderer_vulkan/renderer_vulkan.cpp9
-rw-r--r--src/video_core/renderer_vulkan/vk_blit_screen.cpp6
-rw-r--r--src/video_core/renderer_vulkan/vk_blit_screen.h1
-rw-r--r--src/video_core/renderer_vulkan/vk_buffer_cache.cpp81
-rw-r--r--src/video_core/renderer_vulkan/vk_buffer_cache.h2
-rw-r--r--src/video_core/renderer_vulkan/vk_smaa.cpp12
-rw-r--r--src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp105
-rw-r--r--src/video_core/renderer_vulkan/vk_staging_buffer_pool.h4
-rw-r--r--src/video_core/renderer_vulkan/vk_texture_cache.cpp9
-rw-r--r--src/video_core/renderer_vulkan/vk_texture_cache.h1
-rw-r--r--src/video_core/renderer_vulkan/vk_turbo_mode.cpp8
-rw-r--r--src/video_core/vulkan_common/vulkan_device.cpp1
-rw-r--r--src/video_core/vulkan_common/vulkan_memory_allocator.cpp107
-rw-r--r--src/video_core/vulkan_common/vulkan_memory_allocator.h12
-rw-r--r--src/video_core/vulkan_common/vulkan_wrapper.cpp24
-rw-r--r--src/video_core/vulkan_common/vulkan_wrapper.h91
16 files changed, 262 insertions, 211 deletions
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
index e569523b6..ddf28ca28 100644
--- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp
+++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
@@ -233,8 +233,8 @@ void Vulkan::RendererVulkan::RenderScreenshot(const Tegra::FramebufferConfig& fr
233 .queueFamilyIndexCount = 0, 233 .queueFamilyIndexCount = 0,
234 .pQueueFamilyIndices = nullptr, 234 .pQueueFamilyIndices = nullptr,
235 }; 235 };
236 const vk::Buffer dst_buffer = device.GetLogical().CreateBuffer(dst_buffer_info); 236 const vk::Buffer dst_buffer =
237 MemoryCommit dst_buffer_memory = memory_allocator.Commit(dst_buffer, MemoryUsage::Download); 237 memory_allocator.CreateBuffer(dst_buffer_info, MemoryUsage::Download);
238 238
239 scheduler.RequestOutsideRenderPassOperationContext(); 239 scheduler.RequestOutsideRenderPassOperationContext();
240 scheduler.Record([&](vk::CommandBuffer cmdbuf) { 240 scheduler.Record([&](vk::CommandBuffer cmdbuf) {
@@ -308,8 +308,9 @@ void Vulkan::RendererVulkan::RenderScreenshot(const Tegra::FramebufferConfig& fr
308 scheduler.Finish(); 308 scheduler.Finish();
309 309
310 // Copy backing image data to the QImage screenshot buffer 310 // Copy backing image data to the QImage screenshot buffer
311 const auto dst_memory_map = dst_buffer_memory.Map(); 311 dst_buffer.Invalidate();
312 std::memcpy(renderer_settings.screenshot_bits, dst_memory_map.data(), dst_memory_map.size()); 312 std::memcpy(renderer_settings.screenshot_bits, dst_buffer.Mapped().data(),
313 dst_buffer.Mapped().size());
313 renderer_settings.screenshot_complete_callback(false); 314 renderer_settings.screenshot_complete_callback(false);
314 renderer_settings.screenshot_requested = false; 315 renderer_settings.screenshot_requested = false;
315} 316}
diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.cpp b/src/video_core/renderer_vulkan/vk_blit_screen.cpp
index 82ca81c7e..ad3b29f0e 100644
--- a/src/video_core/renderer_vulkan/vk_blit_screen.cpp
+++ b/src/video_core/renderer_vulkan/vk_blit_screen.cpp
@@ -162,7 +162,7 @@ void BlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer,
162 SetUniformData(data, layout); 162 SetUniformData(data, layout);
163 SetVertexData(data, framebuffer, layout); 163 SetVertexData(data, framebuffer, layout);
164 164
165 const std::span<u8> mapped_span = buffer_commit.Map(); 165 const std::span<u8> mapped_span = buffer.Mapped();
166 std::memcpy(mapped_span.data(), &data, sizeof(data)); 166 std::memcpy(mapped_span.data(), &data, sizeof(data));
167 167
168 if (!use_accelerated) { 168 if (!use_accelerated) {
@@ -1074,7 +1074,6 @@ void BlitScreen::ReleaseRawImages() {
1074 aa_image_view.reset(); 1074 aa_image_view.reset();
1075 aa_image.reset(); 1075 aa_image.reset();
1076 buffer.reset(); 1076 buffer.reset();
1077 buffer_commit = MemoryCommit{};
1078} 1077}
1079 1078
1080void BlitScreen::CreateStagingBuffer(const Tegra::FramebufferConfig& framebuffer) { 1079void BlitScreen::CreateStagingBuffer(const Tegra::FramebufferConfig& framebuffer) {
@@ -1090,8 +1089,7 @@ void BlitScreen::CreateStagingBuffer(const Tegra::FramebufferConfig& framebuffer
1090 .pQueueFamilyIndices = nullptr, 1089 .pQueueFamilyIndices = nullptr,
1091 }; 1090 };
1092 1091
1093 buffer = device.GetLogical().CreateBuffer(ci); 1092 buffer = memory_allocator.CreateBuffer(ci, MemoryUsage::Upload);
1094 buffer_commit = memory_allocator.Commit(buffer, MemoryUsage::Upload);
1095} 1093}
1096 1094
1097void BlitScreen::CreateRawImages(const Tegra::FramebufferConfig& framebuffer) { 1095void BlitScreen::CreateRawImages(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 7fcfa9976..8365b5668 100644
--- a/src/video_core/renderer_vulkan/vk_blit_screen.h
+++ b/src/video_core/renderer_vulkan/vk_blit_screen.h
@@ -142,7 +142,6 @@ private:
142 vk::Sampler sampler; 142 vk::Sampler sampler;
143 143
144 vk::Buffer buffer; 144 vk::Buffer buffer;
145 MemoryCommit buffer_commit;
146 145
147 std::vector<u64> resource_ticks; 146 std::vector<u64> resource_ticks;
148 147
diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
index 8c33722d3..67356c679 100644
--- a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
@@ -50,7 +50,7 @@ size_t BytesPerIndex(VkIndexType index_type) {
50 } 50 }
51} 51}
52 52
53vk::Buffer CreateBuffer(const Device& device, u64 size) { 53vk::Buffer CreateBuffer(const Device& device, const MemoryAllocator& memory_allocator, u64 size) {
54 VkBufferUsageFlags flags = 54 VkBufferUsageFlags flags =
55 VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | 55 VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT |
56 VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT | 56 VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT |
@@ -60,7 +60,7 @@ vk::Buffer CreateBuffer(const Device& device, u64 size) {
60 if (device.IsExtTransformFeedbackSupported()) { 60 if (device.IsExtTransformFeedbackSupported()) {
61 flags |= VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT; 61 flags |= VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT;
62 } 62 }
63 return device.GetLogical().CreateBuffer({ 63 const VkBufferCreateInfo buffer_ci = {
64 .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, 64 .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
65 .pNext = nullptr, 65 .pNext = nullptr,
66 .flags = 0, 66 .flags = 0,
@@ -69,7 +69,8 @@ vk::Buffer CreateBuffer(const Device& device, u64 size) {
69 .sharingMode = VK_SHARING_MODE_EXCLUSIVE, 69 .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
70 .queueFamilyIndexCount = 0, 70 .queueFamilyIndexCount = 0,
71 .pQueueFamilyIndices = nullptr, 71 .pQueueFamilyIndices = nullptr,
72 }); 72 };
73 return memory_allocator.CreateBuffer(buffer_ci, MemoryUsage::DeviceLocal);
73} 74}
74} // Anonymous namespace 75} // Anonymous namespace
75 76
@@ -79,8 +80,8 @@ Buffer::Buffer(BufferCacheRuntime&, VideoCommon::NullBufferParams null_params)
79Buffer::Buffer(BufferCacheRuntime& runtime, VideoCore::RasterizerInterface& rasterizer_, 80Buffer::Buffer(BufferCacheRuntime& runtime, VideoCore::RasterizerInterface& rasterizer_,
80 VAddr cpu_addr_, u64 size_bytes_) 81 VAddr cpu_addr_, u64 size_bytes_)
81 : VideoCommon::BufferBase<VideoCore::RasterizerInterface>(rasterizer_, cpu_addr_, size_bytes_), 82 : VideoCommon::BufferBase<VideoCore::RasterizerInterface>(rasterizer_, cpu_addr_, size_bytes_),
82 device{&runtime.device}, buffer{CreateBuffer(*device, SizeBytes())}, 83 device{&runtime.device}, buffer{
83 commit{runtime.memory_allocator.Commit(buffer, MemoryUsage::DeviceLocal)} { 84 CreateBuffer(*device, runtime.memory_allocator, SizeBytes())} {
84 if (runtime.device.HasDebuggingToolAttached()) { 85 if (runtime.device.HasDebuggingToolAttached()) {
85 buffer.SetObjectNameEXT(fmt::format("Buffer 0x{:x}", CpuAddr()).c_str()); 86 buffer.SetObjectNameEXT(fmt::format("Buffer 0x{:x}", CpuAddr()).c_str());
86 } 87 }
@@ -138,7 +139,7 @@ public:
138 const u32 num_first_offset_copies = 4; 139 const u32 num_first_offset_copies = 4;
139 const size_t bytes_per_index = BytesPerIndex(index_type); 140 const size_t bytes_per_index = BytesPerIndex(index_type);
140 const size_t size_bytes = num_triangle_indices * bytes_per_index * num_first_offset_copies; 141 const size_t size_bytes = num_triangle_indices * bytes_per_index * num_first_offset_copies;
141 buffer = device.GetLogical().CreateBuffer(VkBufferCreateInfo{ 142 const VkBufferCreateInfo buffer_ci = {
142 .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, 143 .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
143 .pNext = nullptr, 144 .pNext = nullptr,
144 .flags = 0, 145 .flags = 0,
@@ -147,14 +148,21 @@ public:
147 .sharingMode = VK_SHARING_MODE_EXCLUSIVE, 148 .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
148 .queueFamilyIndexCount = 0, 149 .queueFamilyIndexCount = 0,
149 .pQueueFamilyIndices = nullptr, 150 .pQueueFamilyIndices = nullptr,
150 }); 151 };
152 buffer = memory_allocator.CreateBuffer(buffer_ci, MemoryUsage::DeviceLocal);
151 if (device.HasDebuggingToolAttached()) { 153 if (device.HasDebuggingToolAttached()) {
152 buffer.SetObjectNameEXT("Quad LUT"); 154 buffer.SetObjectNameEXT("Quad LUT");
153 } 155 }
154 memory_commit = memory_allocator.Commit(buffer, MemoryUsage::DeviceLocal);
155 156
156 const StagingBufferRef staging = staging_pool.Request(size_bytes, MemoryUsage::Upload); 157 const bool host_visible = buffer.IsHostVisible();
157 u8* staging_data = staging.mapped_span.data(); 158 const StagingBufferRef staging = [&] {
159 if (host_visible) {
160 return StagingBufferRef{};
161 }
162 return staging_pool.Request(size_bytes, MemoryUsage::Upload);
163 }();
164
165 u8* staging_data = host_visible ? buffer.Mapped().data() : staging.mapped_span.data();
158 const size_t quad_size = bytes_per_index * 6; 166 const size_t quad_size = bytes_per_index * 6;
159 167
160 for (u32 first = 0; first < num_first_offset_copies; ++first) { 168 for (u32 first = 0; first < num_first_offset_copies; ++first) {
@@ -164,29 +172,33 @@ public:
164 } 172 }
165 } 173 }
166 174
167 scheduler.RequestOutsideRenderPassOperationContext(); 175 if (!host_visible) {
168 scheduler.Record([src_buffer = staging.buffer, src_offset = staging.offset, 176 scheduler.RequestOutsideRenderPassOperationContext();
169 dst_buffer = *buffer, size_bytes](vk::CommandBuffer cmdbuf) { 177 scheduler.Record([src_buffer = staging.buffer, src_offset = staging.offset,
170 const VkBufferCopy copy{ 178 dst_buffer = *buffer, size_bytes](vk::CommandBuffer cmdbuf) {
171 .srcOffset = src_offset, 179 const VkBufferCopy copy{
172 .dstOffset = 0, 180 .srcOffset = src_offset,
173 .size = size_bytes, 181 .dstOffset = 0,
174 }; 182 .size = size_bytes,
175 const VkBufferMemoryBarrier write_barrier{ 183 };
176 .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, 184 const VkBufferMemoryBarrier write_barrier{
177 .pNext = nullptr, 185 .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
178 .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, 186 .pNext = nullptr,
179 .dstAccessMask = VK_ACCESS_INDEX_READ_BIT, 187 .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
180 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, 188 .dstAccessMask = VK_ACCESS_INDEX_READ_BIT,
181 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, 189 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
182 .buffer = dst_buffer, 190 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
183 .offset = 0, 191 .buffer = dst_buffer,
184 .size = size_bytes, 192 .offset = 0,
185 }; 193 .size = size_bytes,
186 cmdbuf.CopyBuffer(src_buffer, dst_buffer, copy); 194 };
187 cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, 195 cmdbuf.CopyBuffer(src_buffer, dst_buffer, copy);
188 VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, 0, write_barrier); 196 cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT,
189 }); 197 VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, 0, write_barrier);
198 });
199 } else {
200 buffer.Flush();
201 }
190 } 202 }
191 203
192 void BindBuffer(u32 first) { 204 void BindBuffer(u32 first) {
@@ -587,11 +599,10 @@ void BufferCacheRuntime::ReserveNullBuffer() {
587 create_info.usage |= VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT; 599 create_info.usage |= VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT;
588 } 600 }
589 create_info.usage |= VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT; 601 create_info.usage |= VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT;
590 null_buffer = device.GetLogical().CreateBuffer(create_info); 602 null_buffer = memory_allocator.CreateBuffer(create_info, MemoryUsage::DeviceLocal);
591 if (device.HasDebuggingToolAttached()) { 603 if (device.HasDebuggingToolAttached()) {
592 null_buffer.SetObjectNameEXT("Null buffer"); 604 null_buffer.SetObjectNameEXT("Null buffer");
593 } 605 }
594 null_buffer_commit = memory_allocator.Commit(null_buffer, MemoryUsage::DeviceLocal);
595 606
596 scheduler.RequestOutsideRenderPassOperationContext(); 607 scheduler.RequestOutsideRenderPassOperationContext();
597 scheduler.Record([buffer = *null_buffer](vk::CommandBuffer cmdbuf) { 608 scheduler.Record([buffer = *null_buffer](vk::CommandBuffer cmdbuf) {
diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.h b/src/video_core/renderer_vulkan/vk_buffer_cache.h
index cdeef8846..95446c732 100644
--- a/src/video_core/renderer_vulkan/vk_buffer_cache.h
+++ b/src/video_core/renderer_vulkan/vk_buffer_cache.h
@@ -48,7 +48,6 @@ private:
48 48
49 const Device* device{}; 49 const Device* device{};
50 vk::Buffer buffer; 50 vk::Buffer buffer;
51 MemoryCommit commit;
52 std::vector<BufferView> views; 51 std::vector<BufferView> views;
53}; 52};
54 53
@@ -142,7 +141,6 @@ private:
142 std::shared_ptr<QuadStripIndexBuffer> quad_strip_index_buffer; 141 std::shared_ptr<QuadStripIndexBuffer> quad_strip_index_buffer;
143 142
144 vk::Buffer null_buffer; 143 vk::Buffer null_buffer;
145 MemoryCommit null_buffer_commit;
146 144
147 std::unique_ptr<Uint8Pass> uint8_pass; 145 std::unique_ptr<Uint8Pass> uint8_pass;
148 QuadIndexedPass quad_index_pass; 146 QuadIndexedPass quad_index_pass;
diff --git a/src/video_core/renderer_vulkan/vk_smaa.cpp b/src/video_core/renderer_vulkan/vk_smaa.cpp
index ff7c3a419..5efd7d66e 100644
--- a/src/video_core/renderer_vulkan/vk_smaa.cpp
+++ b/src/video_core/renderer_vulkan/vk_smaa.cpp
@@ -76,7 +76,7 @@ void TransitionImageLayout(vk::CommandBuffer& cmdbuf, VkImage image, VkImageLayo
76void UploadImage(const Device& device, MemoryAllocator& allocator, Scheduler& scheduler, 76void UploadImage(const Device& device, MemoryAllocator& allocator, Scheduler& scheduler,
77 vk::Image& image, VkExtent2D dimensions, VkFormat format, 77 vk::Image& image, VkExtent2D dimensions, VkFormat format,
78 std::span<const u8> initial_contents = {}) { 78 std::span<const u8> initial_contents = {}) {
79 auto upload_buffer = device.GetLogical().CreateBuffer(VkBufferCreateInfo{ 79 const VkBufferCreateInfo upload_ci = {
80 .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, 80 .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
81 .pNext = nullptr, 81 .pNext = nullptr,
82 .flags = 0, 82 .flags = 0,
@@ -85,9 +85,10 @@ void UploadImage(const Device& device, MemoryAllocator& allocator, Scheduler& sc
85 .sharingMode = VK_SHARING_MODE_EXCLUSIVE, 85 .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
86 .queueFamilyIndexCount = 0, 86 .queueFamilyIndexCount = 0,
87 .pQueueFamilyIndices = nullptr, 87 .pQueueFamilyIndices = nullptr,
88 }); 88 };
89 auto upload_commit = allocator.Commit(upload_buffer, MemoryUsage::Upload); 89 auto upload_buffer = allocator.CreateBuffer(upload_ci, MemoryUsage::Upload);
90 std::ranges::copy(initial_contents, upload_commit.Map().begin()); 90 std::ranges::copy(initial_contents, upload_buffer.Mapped().begin());
91 upload_buffer.Flush();
91 92
92 const std::array<VkBufferImageCopy, 1> regions{{{ 93 const std::array<VkBufferImageCopy, 1> regions{{{
93 .bufferOffset = 0, 94 .bufferOffset = 0,
@@ -111,9 +112,6 @@ void UploadImage(const Device& device, MemoryAllocator& allocator, Scheduler& sc
111 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); 112 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
112 }); 113 });
113 scheduler.Finish(); 114 scheduler.Finish();
114
115 // This should go out of scope before the commit
116 auto upload_buffer2 = std::move(upload_buffer);
117} 115}
118 116
119vk::ImageView CreateWrappedImageView(const Device& device, vk::Image& image, VkFormat format) { 117vk::ImageView CreateWrappedImageView(const Device& device, vk::Image& image, VkFormat format) {
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 74ca77216..62b251a9b 100644
--- a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp
+++ b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp
@@ -30,55 +30,6 @@ constexpr VkDeviceSize MAX_STREAM_BUFFER_REQUEST_SIZE = 8_MiB;
30constexpr VkDeviceSize STREAM_BUFFER_SIZE = 128_MiB; 30constexpr VkDeviceSize STREAM_BUFFER_SIZE = 128_MiB;
31constexpr VkDeviceSize REGION_SIZE = STREAM_BUFFER_SIZE / StagingBufferPool::NUM_SYNCS; 31constexpr VkDeviceSize REGION_SIZE = STREAM_BUFFER_SIZE / StagingBufferPool::NUM_SYNCS;
32 32
33constexpr VkMemoryPropertyFlags HOST_FLAGS =
34 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
35constexpr VkMemoryPropertyFlags STREAM_FLAGS = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | HOST_FLAGS;
36
37bool IsStreamHeap(VkMemoryHeap heap) noexcept {
38 return STREAM_BUFFER_SIZE < (heap.size * 2) / 3;
39}
40
41std::optional<u32> FindMemoryTypeIndex(const VkPhysicalDeviceMemoryProperties& props, u32 type_mask,
42 VkMemoryPropertyFlags flags) noexcept {
43 for (u32 type_index = 0; type_index < props.memoryTypeCount; ++type_index) {
44 if (((type_mask >> type_index) & 1) == 0) {
45 // Memory type is incompatible
46 continue;
47 }
48 const VkMemoryType& memory_type = props.memoryTypes[type_index];
49 if ((memory_type.propertyFlags & flags) != flags) {
50 // Memory type doesn't have the flags we want
51 continue;
52 }
53 if (!IsStreamHeap(props.memoryHeaps[memory_type.heapIndex])) {
54 // Memory heap is not suitable for streaming
55 continue;
56 }
57 // Success!
58 return type_index;
59 }
60 return std::nullopt;
61}
62
63u32 FindMemoryTypeIndex(const VkPhysicalDeviceMemoryProperties& props, u32 type_mask,
64 bool try_device_local) {
65 std::optional<u32> type;
66 if (try_device_local) {
67 // Try to find a DEVICE_LOCAL_BIT type, Nvidia and AMD have a dedicated heap for this
68 type = FindMemoryTypeIndex(props, type_mask, STREAM_FLAGS);
69 if (type) {
70 return *type;
71 }
72 }
73 // Otherwise try without the DEVICE_LOCAL_BIT
74 type = FindMemoryTypeIndex(props, type_mask, HOST_FLAGS);
75 if (type) {
76 return *type;
77 }
78 // This should never happen, and in case it does, signal it as an out of memory situation
79 throw vk::Exception(VK_ERROR_OUT_OF_DEVICE_MEMORY);
80}
81
82size_t Region(size_t iterator) noexcept { 33size_t Region(size_t iterator) noexcept {
83 return iterator / REGION_SIZE; 34 return iterator / REGION_SIZE;
84} 35}
@@ -87,8 +38,7 @@ size_t Region(size_t iterator) noexcept {
87StagingBufferPool::StagingBufferPool(const Device& device_, MemoryAllocator& memory_allocator_, 38StagingBufferPool::StagingBufferPool(const Device& device_, MemoryAllocator& memory_allocator_,
88 Scheduler& scheduler_) 39 Scheduler& scheduler_)
89 : device{device_}, memory_allocator{memory_allocator_}, scheduler{scheduler_} { 40 : device{device_}, memory_allocator{memory_allocator_}, scheduler{scheduler_} {
90 const vk::Device& dev = device.GetLogical(); 41 const VkBufferCreateInfo stream_ci = {
91 stream_buffer = dev.CreateBuffer(VkBufferCreateInfo{
92 .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, 42 .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
93 .pNext = nullptr, 43 .pNext = nullptr,
94 .flags = 0, 44 .flags = 0,
@@ -99,46 +49,13 @@ StagingBufferPool::StagingBufferPool(const Device& device_, MemoryAllocator& mem
99 .sharingMode = VK_SHARING_MODE_EXCLUSIVE, 49 .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
100 .queueFamilyIndexCount = 0, 50 .queueFamilyIndexCount = 0,
101 .pQueueFamilyIndices = nullptr, 51 .pQueueFamilyIndices = nullptr,
102 });
103 if (device.HasDebuggingToolAttached()) {
104 stream_buffer.SetObjectNameEXT("Stream Buffer");
105 }
106 VkMemoryDedicatedRequirements dedicated_reqs{
107 .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS,
108 .pNext = nullptr,
109 .prefersDedicatedAllocation = VK_FALSE,
110 .requiresDedicatedAllocation = VK_FALSE,
111 };
112 const auto requirements = dev.GetBufferMemoryRequirements(*stream_buffer, &dedicated_reqs);
113 const bool make_dedicated = dedicated_reqs.prefersDedicatedAllocation == VK_TRUE ||
114 dedicated_reqs.requiresDedicatedAllocation == VK_TRUE;
115 const VkMemoryDedicatedAllocateInfo dedicated_info{
116 .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO,
117 .pNext = nullptr,
118 .image = nullptr,
119 .buffer = *stream_buffer,
120 }; 52 };
121 const auto memory_properties = device.GetPhysical().GetMemoryProperties().memoryProperties; 53 stream_buffer = memory_allocator.CreateBuffer(stream_ci, MemoryUsage::Stream);
122 VkMemoryAllocateInfo stream_memory_info{
123 .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
124 .pNext = make_dedicated ? &dedicated_info : nullptr,
125 .allocationSize = requirements.size,
126 .memoryTypeIndex =
127 FindMemoryTypeIndex(memory_properties, requirements.memoryTypeBits, true),
128 };
129 stream_memory = dev.TryAllocateMemory(stream_memory_info);
130 if (!stream_memory) {
131 LOG_INFO(Render_Vulkan, "Dynamic memory allocation failed, trying with system memory");
132 stream_memory_info.memoryTypeIndex =
133 FindMemoryTypeIndex(memory_properties, requirements.memoryTypeBits, false);
134 stream_memory = dev.AllocateMemory(stream_memory_info);
135 }
136
137 if (device.HasDebuggingToolAttached()) { 54 if (device.HasDebuggingToolAttached()) {
138 stream_memory.SetObjectNameEXT("Stream Buffer Memory"); 55 stream_buffer.SetObjectNameEXT("Stream Buffer");
139 } 56 }
140 stream_buffer.BindMemory(*stream_memory, 0); 57 stream_pointer = stream_buffer.Mapped();
141 stream_pointer = stream_memory.Map(0, STREAM_BUFFER_SIZE); 58 ASSERT_MSG(!stream_pointer.empty(), "Stream buffer must be host visible!");
142} 59}
143 60
144StagingBufferPool::~StagingBufferPool() = default; 61StagingBufferPool::~StagingBufferPool() = default;
@@ -199,7 +116,7 @@ StagingBufferRef StagingBufferPool::GetStreamBuffer(size_t size) {
199 return StagingBufferRef{ 116 return StagingBufferRef{
200 .buffer = *stream_buffer, 117 .buffer = *stream_buffer,
201 .offset = static_cast<VkDeviceSize>(offset), 118 .offset = static_cast<VkDeviceSize>(offset),
202 .mapped_span = std::span<u8>(stream_pointer + offset, size), 119 .mapped_span = stream_pointer.subspan(offset, size),
203 .usage{}, 120 .usage{},
204 .log2_level{}, 121 .log2_level{},
205 .index{}, 122 .index{},
@@ -247,7 +164,7 @@ std::optional<StagingBufferRef> StagingBufferPool::TryGetReservedBuffer(size_t s
247StagingBufferRef StagingBufferPool::CreateStagingBuffer(size_t size, MemoryUsage usage, 164StagingBufferRef StagingBufferPool::CreateStagingBuffer(size_t size, MemoryUsage usage,
248 bool deferred) { 165 bool deferred) {
249 const u32 log2 = Common::Log2Ceil64(size); 166 const u32 log2 = Common::Log2Ceil64(size);
250 vk::Buffer buffer = device.GetLogical().CreateBuffer({ 167 const VkBufferCreateInfo buffer_ci = {
251 .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, 168 .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
252 .pNext = nullptr, 169 .pNext = nullptr,
253 .flags = 0, 170 .flags = 0,
@@ -259,17 +176,15 @@ StagingBufferRef StagingBufferPool::CreateStagingBuffer(size_t size, MemoryUsage
259 .sharingMode = VK_SHARING_MODE_EXCLUSIVE, 176 .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
260 .queueFamilyIndexCount = 0, 177 .queueFamilyIndexCount = 0,
261 .pQueueFamilyIndices = nullptr, 178 .pQueueFamilyIndices = nullptr,
262 }); 179 };
180 vk::Buffer buffer = memory_allocator.CreateBuffer(buffer_ci, usage);
263 if (device.HasDebuggingToolAttached()) { 181 if (device.HasDebuggingToolAttached()) {
264 ++buffer_index; 182 ++buffer_index;
265 buffer.SetObjectNameEXT(fmt::format("Staging Buffer {}", buffer_index).c_str()); 183 buffer.SetObjectNameEXT(fmt::format("Staging Buffer {}", buffer_index).c_str());
266 } 184 }
267 MemoryCommit commit = memory_allocator.Commit(buffer, usage); 185 const std::span<u8> mapped_span = buffer.Mapped();
268 const std::span<u8> mapped_span = IsHostVisible(usage) ? commit.Map() : std::span<u8>{};
269
270 StagingBuffer& entry = GetCache(usage)[log2].entries.emplace_back(StagingBuffer{ 186 StagingBuffer& entry = GetCache(usage)[log2].entries.emplace_back(StagingBuffer{
271 .buffer = std::move(buffer), 187 .buffer = std::move(buffer),
272 .commit = std::move(commit),
273 .mapped_span = mapped_span, 188 .mapped_span = mapped_span,
274 .usage = usage, 189 .usage = usage,
275 .log2_level = log2, 190 .log2_level = 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 4fd15f11a..5f69f08b1 100644
--- a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h
+++ b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h
@@ -46,7 +46,6 @@ private:
46 46
47 struct StagingBuffer { 47 struct StagingBuffer {
48 vk::Buffer buffer; 48 vk::Buffer buffer;
49 MemoryCommit commit;
50 std::span<u8> mapped_span; 49 std::span<u8> mapped_span;
51 MemoryUsage usage; 50 MemoryUsage usage;
52 u32 log2_level; 51 u32 log2_level;
@@ -97,8 +96,7 @@ private:
97 Scheduler& scheduler; 96 Scheduler& scheduler;
98 97
99 vk::Buffer stream_buffer; 98 vk::Buffer stream_buffer;
100 vk::DeviceMemory stream_memory; 99 std::span<u8> stream_pointer;
101 u8* stream_pointer = nullptr;
102 100
103 size_t iterator = 0; 101 size_t iterator = 0;
104 size_t used_iterator = 0; 102 size_t used_iterator = 0;
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
index 10defe6cb..28985b6fe 100644
--- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
@@ -839,14 +839,14 @@ bool TextureCacheRuntime::ShouldReinterpret(Image& dst, Image& src) {
839 839
840VkBuffer TextureCacheRuntime::GetTemporaryBuffer(size_t needed_size) { 840VkBuffer TextureCacheRuntime::GetTemporaryBuffer(size_t needed_size) {
841 const auto level = (8 * sizeof(size_t)) - std::countl_zero(needed_size - 1ULL); 841 const auto level = (8 * sizeof(size_t)) - std::countl_zero(needed_size - 1ULL);
842 if (buffer_commits[level]) { 842 if (buffers[level]) {
843 return *buffers[level]; 843 return *buffers[level];
844 } 844 }
845 const auto new_size = Common::NextPow2(needed_size); 845 const auto new_size = Common::NextPow2(needed_size);
846 static constexpr VkBufferUsageFlags flags = 846 static constexpr VkBufferUsageFlags flags =
847 VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | 847 VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT |
848 VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT; 848 VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT;
849 buffers[level] = device.GetLogical().CreateBuffer({ 849 const VkBufferCreateInfo temp_ci = {
850 .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, 850 .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
851 .pNext = nullptr, 851 .pNext = nullptr,
852 .flags = 0, 852 .flags = 0,
@@ -855,9 +855,8 @@ VkBuffer TextureCacheRuntime::GetTemporaryBuffer(size_t needed_size) {
855 .sharingMode = VK_SHARING_MODE_EXCLUSIVE, 855 .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
856 .queueFamilyIndexCount = 0, 856 .queueFamilyIndexCount = 0,
857 .pQueueFamilyIndices = nullptr, 857 .pQueueFamilyIndices = nullptr,
858 }); 858 };
859 buffer_commits[level] = std::make_unique<MemoryCommit>( 859 buffers[level] = memory_allocator.CreateBuffer(temp_ci, MemoryUsage::DeviceLocal);
860 memory_allocator.Commit(buffers[level], MemoryUsage::DeviceLocal));
861 return *buffers[level]; 860 return *buffers[level];
862} 861}
863 862
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.h b/src/video_core/renderer_vulkan/vk_texture_cache.h
index 9481f2531..220943116 100644
--- a/src/video_core/renderer_vulkan/vk_texture_cache.h
+++ b/src/video_core/renderer_vulkan/vk_texture_cache.h
@@ -116,7 +116,6 @@ public:
116 116
117 static constexpr size_t indexing_slots = 8 * sizeof(size_t); 117 static constexpr size_t indexing_slots = 8 * sizeof(size_t);
118 std::array<vk::Buffer, indexing_slots> buffers{}; 118 std::array<vk::Buffer, indexing_slots> buffers{};
119 std::array<std::unique_ptr<MemoryCommit>, indexing_slots> buffer_commits{};
120}; 119};
121 120
122class Image : public VideoCommon::ImageBase { 121class Image : public VideoCommon::ImageBase {
diff --git a/src/video_core/renderer_vulkan/vk_turbo_mode.cpp b/src/video_core/renderer_vulkan/vk_turbo_mode.cpp
index 6417d7e31..460d8d59d 100644
--- a/src/video_core/renderer_vulkan/vk_turbo_mode.cpp
+++ b/src/video_core/renderer_vulkan/vk_turbo_mode.cpp
@@ -41,7 +41,7 @@ void TurboMode::Run(std::stop_token stop_token) {
41 auto& dld = m_device.GetLogical(); 41 auto& dld = m_device.GetLogical();
42 42
43 // Allocate buffer. 2MiB should be sufficient. 43 // Allocate buffer. 2MiB should be sufficient.
44 auto buffer = dld.CreateBuffer(VkBufferCreateInfo{ 44 const VkBufferCreateInfo buffer_ci = {
45 .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, 45 .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
46 .pNext = nullptr, 46 .pNext = nullptr,
47 .flags = 0, 47 .flags = 0,
@@ -50,10 +50,8 @@ void TurboMode::Run(std::stop_token stop_token) {
50 .sharingMode = VK_SHARING_MODE_EXCLUSIVE, 50 .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
51 .queueFamilyIndexCount = 0, 51 .queueFamilyIndexCount = 0,
52 .pQueueFamilyIndices = nullptr, 52 .pQueueFamilyIndices = nullptr,
53 }); 53 };
54 54 vk::Buffer buffer = m_allocator.CreateBuffer(buffer_ci, MemoryUsage::DeviceLocal);
55 // Commit some device local memory for the buffer.
56 auto commit = m_allocator.Commit(buffer, MemoryUsage::DeviceLocal);
57 55
58 // Create the descriptor pool to contain our descriptor. 56 // Create the descriptor pool to contain our descriptor.
59 static constexpr VkDescriptorPoolSize pool_size{ 57 static constexpr VkDescriptorPoolSize pool_size{
diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp
index 631d5e378..541f0c1da 100644
--- a/src/video_core/vulkan_common/vulkan_device.cpp
+++ b/src/video_core/vulkan_common/vulkan_device.cpp
@@ -603,6 +603,7 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
603 }; 603 };
604 604
605 const VmaAllocatorCreateInfo allocator_info = { 605 const VmaAllocatorCreateInfo allocator_info = {
606 .flags = VMA_ALLOCATOR_CREATE_EXTERNALLY_SYNCHRONIZED_BIT,
606 .physicalDevice = physical, 607 .physicalDevice = physical,
607 .device = *logical, 608 .device = *logical,
608 .pVulkanFunctions = &functions, 609 .pVulkanFunctions = &functions,
diff --git a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp
index 7f860cccd..d2e1ef58e 100644
--- a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp
+++ b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp
@@ -51,11 +51,59 @@ struct Range {
51 case MemoryUsage::Download: 51 case MemoryUsage::Download:
52 return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | 52 return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT |
53 VK_MEMORY_PROPERTY_HOST_CACHED_BIT; 53 VK_MEMORY_PROPERTY_HOST_CACHED_BIT;
54 case MemoryUsage::Stream:
55 return VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
56 VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
54 } 57 }
55 ASSERT_MSG(false, "Invalid memory usage={}", usage); 58 ASSERT_MSG(false, "Invalid memory usage={}", usage);
56 return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; 59 return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
57} 60}
58 61
62[[nodiscard]] VkMemoryPropertyFlags MemoryUsageRequiredVmaFlags(MemoryUsage usage) {
63 switch (usage) {
64 case MemoryUsage::DeviceLocal:
65 return VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
66 case MemoryUsage::Upload:
67 case MemoryUsage::Stream:
68 return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
69 case MemoryUsage::Download:
70 return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT;
71 }
72 ASSERT_MSG(false, "Invalid memory usage={}", usage);
73 return {};
74}
75
76[[nodiscard]] VkMemoryPropertyFlags MemoryUsagePreferedVmaFlags(MemoryUsage usage) {
77 return usage != MemoryUsage::DeviceLocal ? VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
78 : VkMemoryPropertyFlags{};
79}
80
81[[nodiscard]] VmaAllocationCreateFlags MemoryUsageVmaFlags(MemoryUsage usage) {
82 switch (usage) {
83 case MemoryUsage::Upload:
84 case MemoryUsage::Stream:
85 return VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT;
86 case MemoryUsage::Download:
87 return VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT;
88 case MemoryUsage::DeviceLocal:
89 return VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT |
90 VMA_ALLOCATION_CREATE_HOST_ACCESS_ALLOW_TRANSFER_INSTEAD_BIT;
91 }
92 return {};
93}
94
95[[nodiscard]] VmaMemoryUsage MemoryUsageVma(MemoryUsage usage) {
96 switch (usage) {
97 case MemoryUsage::DeviceLocal:
98 case MemoryUsage::Stream:
99 return VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE;
100 case MemoryUsage::Upload:
101 case MemoryUsage::Download:
102 return VMA_MEMORY_USAGE_AUTO_PREFER_HOST;
103 }
104 return VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE;
105}
106
59} // Anonymous namespace 107} // Anonymous namespace
60 108
61class MemoryAllocation { 109class MemoryAllocation {
@@ -178,17 +226,18 @@ void MemoryCommit::Release() {
178} 226}
179 227
180MemoryAllocator::MemoryAllocator(const Device& device_) 228MemoryAllocator::MemoryAllocator(const Device& device_)
181 : device{device_}, properties{device_.GetPhysical().GetMemoryProperties().memoryProperties}, 229 : device{device_}, allocator{device.GetAllocator()},
230 properties{device_.GetPhysical().GetMemoryProperties().memoryProperties},
182 buffer_image_granularity{ 231 buffer_image_granularity{
183 device_.GetPhysical().GetProperties().limits.bufferImageGranularity} {} 232 device_.GetPhysical().GetProperties().limits.bufferImageGranularity} {}
184 233
185MemoryAllocator::~MemoryAllocator() = default; 234MemoryAllocator::~MemoryAllocator() = default;
186 235
187vk::Image MemoryAllocator::CreateImage(const VkImageCreateInfo& ci) const { 236vk::Image MemoryAllocator::CreateImage(const VkImageCreateInfo& ci) const {
188 const VmaAllocationCreateInfo alloc_info = { 237 const VmaAllocationCreateInfo alloc_ci = {
189 .flags = VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT, 238 .flags = VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT,
190 .usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE, 239 .usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE,
191 .requiredFlags = 0, 240 .requiredFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
192 .preferredFlags = 0, 241 .preferredFlags = 0,
193 .pool = VK_NULL_HANDLE, 242 .pool = VK_NULL_HANDLE,
194 .pUserData = nullptr, 243 .pUserData = nullptr,
@@ -196,12 +245,40 @@ vk::Image MemoryAllocator::CreateImage(const VkImageCreateInfo& ci) const {
196 245
197 VkImage handle{}; 246 VkImage handle{};
198 VmaAllocation allocation{}; 247 VmaAllocation allocation{};
199 vk::Check( 248
200 vmaCreateImage(device.GetAllocator(), &ci, &alloc_info, &handle, &allocation, nullptr)); 249 vk::Check(vmaCreateImage(allocator, &ci, &alloc_ci, &handle, &allocation, nullptr));
201 return vk::Image(handle, *device.GetLogical(), device.GetAllocator(), allocation, 250
251 return vk::Image(handle, *device.GetLogical(), allocator, allocation,
202 device.GetDispatchLoader()); 252 device.GetDispatchLoader());
203} 253}
204 254
255vk::Buffer MemoryAllocator::CreateBuffer(const VkBufferCreateInfo& ci, MemoryUsage usage) const {
256 const VmaAllocationCreateInfo alloc_ci = {
257 .flags = VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT |
258 MemoryUsageVmaFlags(usage),
259 .usage = MemoryUsageVma(usage),
260 .requiredFlags = MemoryUsageRequiredVmaFlags(usage),
261 .preferredFlags = MemoryUsagePreferedVmaFlags(usage),
262 .pool = VK_NULL_HANDLE,
263 .pUserData = nullptr,
264 };
265
266 VkBuffer handle{};
267 VmaAllocationInfo alloc_info{};
268 VmaAllocation allocation{};
269 VkMemoryPropertyFlags property_flags{};
270
271 vk::Check(vmaCreateBuffer(allocator, &ci, &alloc_ci, &handle, &allocation, &alloc_info));
272 vmaGetAllocationMemoryProperties(allocator, allocation, &property_flags);
273
274 u8* data = reinterpret_cast<u8*>(alloc_info.pMappedData);
275 const std::span<u8> mapped_data = data ? std::span<u8>{data, ci.size} : std::span<u8>{};
276 const bool is_coherent = property_flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
277
278 return vk::Buffer(handle, *device.GetLogical(), allocator, allocation, mapped_data, is_coherent,
279 device.GetDispatchLoader());
280}
281
205MemoryCommit MemoryAllocator::Commit(const VkMemoryRequirements& requirements, MemoryUsage usage) { 282MemoryCommit MemoryAllocator::Commit(const VkMemoryRequirements& requirements, MemoryUsage usage) {
206 // Find the fastest memory flags we can afford with the current requirements 283 // Find the fastest memory flags we can afford with the current requirements
207 const u32 type_mask = requirements.memoryTypeBits; 284 const u32 type_mask = requirements.memoryTypeBits;
@@ -221,12 +298,6 @@ MemoryCommit MemoryAllocator::Commit(const VkMemoryRequirements& requirements, M
221 return TryCommit(requirements, flags).value(); 298 return TryCommit(requirements, flags).value();
222} 299}
223 300
224MemoryCommit MemoryAllocator::Commit(const vk::Buffer& buffer, MemoryUsage usage) {
225 auto commit = Commit(device.GetLogical().GetBufferMemoryRequirements(*buffer), usage);
226 buffer.BindMemory(commit.Memory(), commit.Offset());
227 return commit;
228}
229
230bool MemoryAllocator::TryAllocMemory(VkMemoryPropertyFlags flags, u32 type_mask, u64 size) { 301bool MemoryAllocator::TryAllocMemory(VkMemoryPropertyFlags flags, u32 type_mask, u64 size) {
231 const u32 type = FindType(flags, type_mask).value(); 302 const u32 type = FindType(flags, type_mask).value();
232 vk::DeviceMemory memory = device.GetLogical().TryAllocateMemory({ 303 vk::DeviceMemory memory = device.GetLogical().TryAllocateMemory({
@@ -302,16 +373,4 @@ std::optional<u32> MemoryAllocator::FindType(VkMemoryPropertyFlags flags, u32 ty
302 return std::nullopt; 373 return std::nullopt;
303} 374}
304 375
305bool IsHostVisible(MemoryUsage usage) noexcept {
306 switch (usage) {
307 case MemoryUsage::DeviceLocal:
308 return false;
309 case MemoryUsage::Upload:
310 case MemoryUsage::Download:
311 return true;
312 }
313 ASSERT_MSG(false, "Invalid memory usage={}", usage);
314 return false;
315}
316
317} // namespace Vulkan 376} // 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 f9ee53cfb..f449bc8d0 100644
--- a/src/video_core/vulkan_common/vulkan_memory_allocator.h
+++ b/src/video_core/vulkan_common/vulkan_memory_allocator.h
@@ -9,6 +9,8 @@
9#include "common/common_types.h" 9#include "common/common_types.h"
10#include "video_core/vulkan_common/vulkan_wrapper.h" 10#include "video_core/vulkan_common/vulkan_wrapper.h"
11 11
12VK_DEFINE_HANDLE(VmaAllocator)
13
12namespace Vulkan { 14namespace Vulkan {
13 15
14class Device; 16class Device;
@@ -17,9 +19,11 @@ class MemoryAllocation;
17 19
18/// Hints and requirements for the backing memory type of a commit 20/// Hints and requirements for the backing memory type of a commit
19enum class MemoryUsage { 21enum class MemoryUsage {
20 DeviceLocal, ///< Hints device local usages, fastest memory type to read and write from the GPU 22 DeviceLocal, ///< Requests device local host visible buffer, falling back to device local
23 ///< memory.
21 Upload, ///< Requires a host visible memory type optimized for CPU to GPU uploads 24 Upload, ///< Requires a host visible memory type optimized for CPU to GPU uploads
22 Download, ///< Requires a host visible memory type optimized for GPU to CPU readbacks 25 Download, ///< Requires a host visible memory type optimized for GPU to CPU readbacks
26 Stream, ///< Requests device local host visible buffer, falling back host memory.
23}; 27};
24 28
25/// Ownership handle of a memory commitment. 29/// Ownership handle of a memory commitment.
@@ -82,6 +86,8 @@ public:
82 86
83 vk::Image CreateImage(const VkImageCreateInfo& ci) const; 87 vk::Image CreateImage(const VkImageCreateInfo& ci) const;
84 88
89 vk::Buffer CreateBuffer(const VkBufferCreateInfo& ci, MemoryUsage usage) const;
90
85 /** 91 /**
86 * Commits a memory with the specified requirements. 92 * Commits a memory with the specified requirements.
87 * 93 *
@@ -113,13 +119,11 @@ private:
113 std::optional<u32> FindType(VkMemoryPropertyFlags flags, u32 type_mask) const; 119 std::optional<u32> FindType(VkMemoryPropertyFlags flags, u32 type_mask) const;
114 120
115 const Device& device; ///< Device handle. 121 const Device& device; ///< Device handle.
122 VmaAllocator allocator; ///< Vma allocator.
116 const VkPhysicalDeviceMemoryProperties properties; ///< Physical device properties. 123 const VkPhysicalDeviceMemoryProperties properties; ///< Physical device properties.
117 std::vector<std::unique_ptr<MemoryAllocation>> allocations; ///< Current allocations. 124 std::vector<std::unique_ptr<MemoryAllocation>> allocations; ///< Current allocations.
118 VkDeviceSize buffer_image_granularity; // The granularity for adjacent offsets between buffers 125 VkDeviceSize buffer_image_granularity; // The granularity for adjacent offsets between buffers
119 // and optimal images 126 // and optimal images
120}; 127};
121 128
122/// Returns true when a memory usage is guaranteed to be host visible.
123bool IsHostVisible(MemoryUsage usage) noexcept;
124
125} // namespace Vulkan 129} // namespace Vulkan
diff --git a/src/video_core/vulkan_common/vulkan_wrapper.cpp b/src/video_core/vulkan_common/vulkan_wrapper.cpp
index 5d088dc58..c01a9478e 100644
--- a/src/video_core/vulkan_common/vulkan_wrapper.cpp
+++ b/src/video_core/vulkan_common/vulkan_wrapper.cpp
@@ -561,14 +561,28 @@ void Image::Release() const noexcept {
561 } 561 }
562} 562}
563 563
564void Buffer::BindMemory(VkDeviceMemory memory, VkDeviceSize offset) const { 564void Buffer::Flush() const {
565 Check(dld->vkBindBufferMemory(owner, handle, memory, offset)); 565 if (!is_coherent) {
566 vmaFlushAllocation(allocator, allocation, 0, VK_WHOLE_SIZE);
567 }
568}
569
570void Buffer::Invalidate() const {
571 if (!is_coherent) {
572 vmaInvalidateAllocation(allocator, allocation, 0, VK_WHOLE_SIZE);
573 }
566} 574}
567 575
568void Buffer::SetObjectNameEXT(const char* name) const { 576void Buffer::SetObjectNameEXT(const char* name) const {
569 SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_BUFFER, name); 577 SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_BUFFER, name);
570} 578}
571 579
580void Buffer::Release() const noexcept {
581 if (handle) {
582 vmaDestroyBuffer(allocator, handle, allocation);
583 }
584}
585
572void BufferView::SetObjectNameEXT(const char* name) const { 586void BufferView::SetObjectNameEXT(const char* name) const {
573 SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_BUFFER_VIEW, name); 587 SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_BUFFER_VIEW, name);
574} 588}
@@ -707,12 +721,6 @@ Queue Device::GetQueue(u32 family_index) const noexcept {
707 return Queue(queue, *dld); 721 return Queue(queue, *dld);
708} 722}
709 723
710Buffer Device::CreateBuffer(const VkBufferCreateInfo& ci) const {
711 VkBuffer object;
712 Check(dld->vkCreateBuffer(handle, &ci, nullptr, &object));
713 return Buffer(object, handle, *dld);
714}
715
716BufferView Device::CreateBufferView(const VkBufferViewCreateInfo& ci) const { 724BufferView Device::CreateBufferView(const VkBufferViewCreateInfo& ci) const {
717 VkBufferView object; 725 VkBufferView object;
718 Check(dld->vkCreateBufferView(handle, &ci, nullptr, &object)); 726 Check(dld->vkCreateBufferView(handle, &ci, nullptr, &object));
diff --git a/src/video_core/vulkan_common/vulkan_wrapper.h b/src/video_core/vulkan_common/vulkan_wrapper.h
index 8ec708774..44fce47a5 100644
--- a/src/video_core/vulkan_common/vulkan_wrapper.h
+++ b/src/video_core/vulkan_common/vulkan_wrapper.h
@@ -673,6 +673,84 @@ private:
673 const DeviceDispatch* dld = nullptr; 673 const DeviceDispatch* dld = nullptr;
674}; 674};
675 675
676class Buffer {
677public:
678 explicit Buffer(VkBuffer handle_, VkDevice owner_, VmaAllocator allocator_,
679 VmaAllocation allocation_, std::span<u8> mapped_, bool is_coherent_,
680 const DeviceDispatch& dld_) noexcept
681 : handle{handle_}, owner{owner_}, allocator{allocator_},
682 allocation{allocation_}, mapped{mapped_}, is_coherent{is_coherent_}, dld{&dld_} {}
683 Buffer() = default;
684
685 Buffer(const Buffer&) = delete;
686 Buffer& operator=(const Buffer&) = delete;
687
688 Buffer(Buffer&& rhs) noexcept
689 : handle{std::exchange(rhs.handle, nullptr)}, owner{rhs.owner}, allocator{rhs.allocator},
690 allocation{rhs.allocation}, mapped{rhs.mapped},
691 is_coherent{rhs.is_coherent}, dld{rhs.dld} {}
692
693 Buffer& operator=(Buffer&& rhs) noexcept {
694 Release();
695 handle = std::exchange(rhs.handle, nullptr);
696 owner = rhs.owner;
697 allocator = rhs.allocator;
698 allocation = rhs.allocation;
699 mapped = rhs.mapped;
700 is_coherent = rhs.is_coherent;
701 dld = rhs.dld;
702 return *this;
703 }
704
705 ~Buffer() noexcept {
706 Release();
707 }
708
709 VkBuffer operator*() const noexcept {
710 return handle;
711 }
712
713 void reset() noexcept {
714 Release();
715 handle = nullptr;
716 }
717
718 explicit operator bool() const noexcept {
719 return handle != nullptr;
720 }
721
722 /// Returns the host mapped memory, an empty span otherwise.
723 std::span<u8> Mapped() noexcept {
724 return mapped;
725 }
726
727 std::span<const u8> Mapped() const noexcept {
728 return mapped;
729 }
730
731 /// Returns true if the buffer is mapped to the host.
732 bool IsHostVisible() const noexcept {
733 return !mapped.empty();
734 }
735
736 void Flush() const;
737
738 void Invalidate() const;
739
740 void SetObjectNameEXT(const char* name) const;
741
742private:
743 void Release() const noexcept;
744
745 VkBuffer handle = nullptr;
746 VkDevice owner = nullptr;
747 VmaAllocator allocator = nullptr;
748 VmaAllocation allocation = nullptr;
749 std::span<u8> mapped = {};
750 bool is_coherent = false;
751 const DeviceDispatch* dld = nullptr;
752};
753
676class Queue { 754class Queue {
677public: 755public:
678 /// Construct an empty queue handle. 756 /// Construct an empty queue handle.
@@ -696,17 +774,6 @@ private:
696 const DeviceDispatch* dld = nullptr; 774 const DeviceDispatch* dld = nullptr;
697}; 775};
698 776
699class Buffer : public Handle<VkBuffer, VkDevice, DeviceDispatch> {
700 using Handle<VkBuffer, VkDevice, DeviceDispatch>::Handle;
701
702public:
703 /// Attaches a memory allocation.
704 void BindMemory(VkDeviceMemory memory, VkDeviceSize offset) const;
705
706 /// Set object name.
707 void SetObjectNameEXT(const char* name) const;
708};
709
710class BufferView : public Handle<VkBufferView, VkDevice, DeviceDispatch> { 777class BufferView : public Handle<VkBufferView, VkDevice, DeviceDispatch> {
711 using Handle<VkBufferView, VkDevice, DeviceDispatch>::Handle; 778 using Handle<VkBufferView, VkDevice, DeviceDispatch>::Handle;
712 779
@@ -886,8 +953,6 @@ public:
886 953
887 Queue GetQueue(u32 family_index) const noexcept; 954 Queue GetQueue(u32 family_index) const noexcept;
888 955
889 Buffer CreateBuffer(const VkBufferCreateInfo& ci) const;
890
891 BufferView CreateBufferView(const VkBufferViewCreateInfo& ci) const; 956 BufferView CreateBufferView(const VkBufferViewCreateInfo& ci) const;
892 957
893 ImageView CreateImageView(const VkImageViewCreateInfo& ci) const; 958 ImageView CreateImageView(const VkImageViewCreateInfo& ci) const;