summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/video_core/CMakeLists.txt2
-rw-r--r--src/video_core/renderer_vulkan/renderer_vulkan.cpp16
-rw-r--r--src/video_core/renderer_vulkan/vk_blit_screen.cpp18
-rw-r--r--src/video_core/renderer_vulkan/vk_blit_screen.h3
-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_fsr.cpp4
-rw-r--r--src/video_core/renderer_vulkan/vk_fsr.h1
-rw-r--r--src/video_core/renderer_vulkan/vk_present_manager.cpp4
-rw-r--r--src/video_core/renderer_vulkan/vk_present_manager.h1
-rw-r--r--src/video_core/renderer_vulkan/vk_smaa.cpp39
-rw-r--r--src/video_core/renderer_vulkan/vk_smaa.h2
-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.cpp23
-rw-r--r--src/video_core/renderer_vulkan/vk_texture_cache.h3
-rw-r--r--src/video_core/renderer_vulkan/vk_turbo_mode.cpp10
-rw-r--r--src/video_core/vulkan_common/vulkan_device.cpp26
-rw-r--r--src/video_core/vulkan_common/vulkan_device.h8
-rw-r--r--src/video_core/vulkan_common/vulkan_memory_allocator.cpp173
-rw-r--r--src/video_core/vulkan_common/vulkan_memory_allocator.h28
-rw-r--r--src/video_core/vulkan_common/vulkan_wrapper.cpp50
-rw-r--r--src/video_core/vulkan_common/vulkan_wrapper.h161
23 files changed, 398 insertions, 366 deletions
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt
index bf6439530..e9e6f278d 100644
--- a/src/video_core/CMakeLists.txt
+++ b/src/video_core/CMakeLists.txt
@@ -291,7 +291,7 @@ target_link_options(video_core PRIVATE ${FFmpeg_LDFLAGS})
291 291
292add_dependencies(video_core host_shaders) 292add_dependencies(video_core host_shaders)
293target_include_directories(video_core PRIVATE ${HOST_SHADERS_INCLUDE}) 293target_include_directories(video_core PRIVATE ${HOST_SHADERS_INCLUDE})
294target_link_libraries(video_core PRIVATE sirit Vulkan::Headers) 294target_link_libraries(video_core PRIVATE sirit Vulkan::Headers vma)
295 295
296if (ENABLE_NSIGHT_AFTERMATH) 296if (ENABLE_NSIGHT_AFTERMATH)
297 if (NOT DEFINED ENV{NSIGHT_AFTERMATH_SDK}) 297 if (NOT DEFINED ENV{NSIGHT_AFTERMATH_SDK})
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
index 77128c6e2..ddf28ca28 100644
--- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp
+++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
@@ -89,8 +89,8 @@ RendererVulkan::RendererVulkan(Core::TelemetrySession& telemetry_session_,
89 Settings::values.renderer_debug.GetValue())), 89 Settings::values.renderer_debug.GetValue())),
90 debug_callback(Settings::values.renderer_debug ? CreateDebugCallback(instance) : nullptr), 90 debug_callback(Settings::values.renderer_debug ? CreateDebugCallback(instance) : nullptr),
91 surface(CreateSurface(instance, render_window.GetWindowInfo())), 91 surface(CreateSurface(instance, render_window.GetWindowInfo())),
92 device(CreateDevice(instance, dld, *surface)), memory_allocator(device, false), 92 device(CreateDevice(instance, dld, *surface)), memory_allocator(device), state_tracker(),
93 state_tracker(), scheduler(device, state_tracker), 93 scheduler(device, state_tracker),
94 swapchain(*surface, device, scheduler, render_window.GetFramebufferLayout().width, 94 swapchain(*surface, device, scheduler, render_window.GetFramebufferLayout().width,
95 render_window.GetFramebufferLayout().height, false), 95 render_window.GetFramebufferLayout().height, false),
96 present_manager(instance, render_window, device, memory_allocator, scheduler, swapchain, 96 present_manager(instance, render_window, device, memory_allocator, scheduler, swapchain,
@@ -173,7 +173,7 @@ void Vulkan::RendererVulkan::RenderScreenshot(const Tegra::FramebufferConfig& fr
173 return; 173 return;
174 } 174 }
175 const Layout::FramebufferLayout layout{renderer_settings.screenshot_framebuffer_layout}; 175 const Layout::FramebufferLayout layout{renderer_settings.screenshot_framebuffer_layout};
176 vk::Image staging_image = device.GetLogical().CreateImage(VkImageCreateInfo{ 176 vk::Image staging_image = memory_allocator.CreateImage(VkImageCreateInfo{
177 .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, 177 .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
178 .pNext = nullptr, 178 .pNext = nullptr,
179 .flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT, 179 .flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT,
@@ -196,7 +196,6 @@ void Vulkan::RendererVulkan::RenderScreenshot(const Tegra::FramebufferConfig& fr
196 .pQueueFamilyIndices = nullptr, 196 .pQueueFamilyIndices = nullptr,
197 .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, 197 .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
198 }); 198 });
199 const auto image_commit = memory_allocator.Commit(staging_image, MemoryUsage::DeviceLocal);
200 199
201 const vk::ImageView dst_view = device.GetLogical().CreateImageView(VkImageViewCreateInfo{ 200 const vk::ImageView dst_view = device.GetLogical().CreateImageView(VkImageViewCreateInfo{
202 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, 201 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
@@ -234,8 +233,8 @@ void Vulkan::RendererVulkan::RenderScreenshot(const Tegra::FramebufferConfig& fr
234 .queueFamilyIndexCount = 0, 233 .queueFamilyIndexCount = 0,
235 .pQueueFamilyIndices = nullptr, 234 .pQueueFamilyIndices = nullptr,
236 }; 235 };
237 const vk::Buffer dst_buffer = device.GetLogical().CreateBuffer(dst_buffer_info); 236 const vk::Buffer dst_buffer =
238 MemoryCommit dst_buffer_memory = memory_allocator.Commit(dst_buffer, MemoryUsage::Download); 237 memory_allocator.CreateBuffer(dst_buffer_info, MemoryUsage::Download);
239 238
240 scheduler.RequestOutsideRenderPassOperationContext(); 239 scheduler.RequestOutsideRenderPassOperationContext();
241 scheduler.Record([&](vk::CommandBuffer cmdbuf) { 240 scheduler.Record([&](vk::CommandBuffer cmdbuf) {
@@ -309,8 +308,9 @@ void Vulkan::RendererVulkan::RenderScreenshot(const Tegra::FramebufferConfig& fr
309 scheduler.Finish(); 308 scheduler.Finish();
310 309
311 // Copy backing image data to the QImage screenshot buffer 310 // Copy backing image data to the QImage screenshot buffer
312 const auto dst_memory_map = dst_buffer_memory.Map(); 311 dst_buffer.Invalidate();
313 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());
314 renderer_settings.screenshot_complete_callback(false); 314 renderer_settings.screenshot_complete_callback(false);
315 renderer_settings.screenshot_requested = false; 315 renderer_settings.screenshot_requested = false;
316} 316}
diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.cpp b/src/video_core/renderer_vulkan/vk_blit_screen.cpp
index acb143fc7..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) {
@@ -1071,14 +1071,9 @@ void BlitScreen::ReleaseRawImages() {
1071 scheduler.Wait(tick); 1071 scheduler.Wait(tick);
1072 } 1072 }
1073 raw_images.clear(); 1073 raw_images.clear();
1074 raw_buffer_commits.clear();
1075
1076 aa_image_view.reset(); 1074 aa_image_view.reset();
1077 aa_image.reset(); 1075 aa_image.reset();
1078 aa_commit = MemoryCommit{};
1079
1080 buffer.reset(); 1076 buffer.reset();
1081 buffer_commit = MemoryCommit{};
1082} 1077}
1083 1078
1084void BlitScreen::CreateStagingBuffer(const Tegra::FramebufferConfig& framebuffer) { 1079void BlitScreen::CreateStagingBuffer(const Tegra::FramebufferConfig& framebuffer) {
@@ -1094,20 +1089,18 @@ void BlitScreen::CreateStagingBuffer(const Tegra::FramebufferConfig& framebuffer
1094 .pQueueFamilyIndices = nullptr, 1089 .pQueueFamilyIndices = nullptr,
1095 }; 1090 };
1096 1091
1097 buffer = device.GetLogical().CreateBuffer(ci); 1092 buffer = memory_allocator.CreateBuffer(ci, MemoryUsage::Upload);
1098 buffer_commit = memory_allocator.Commit(buffer, MemoryUsage::Upload);
1099} 1093}
1100 1094
1101void BlitScreen::CreateRawImages(const Tegra::FramebufferConfig& framebuffer) { 1095void BlitScreen::CreateRawImages(const Tegra::FramebufferConfig& framebuffer) {
1102 raw_images.resize(image_count); 1096 raw_images.resize(image_count);
1103 raw_image_views.resize(image_count); 1097 raw_image_views.resize(image_count);
1104 raw_buffer_commits.resize(image_count);
1105 1098
1106 const auto create_image = [&](bool used_on_framebuffer = false, u32 up_scale = 1, 1099 const auto create_image = [&](bool used_on_framebuffer = false, u32 up_scale = 1,
1107 u32 down_shift = 0) { 1100 u32 down_shift = 0) {
1108 u32 extra_usages = used_on_framebuffer ? VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT 1101 u32 extra_usages = used_on_framebuffer ? VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT
1109 : VK_IMAGE_USAGE_TRANSFER_DST_BIT; 1102 : VK_IMAGE_USAGE_TRANSFER_DST_BIT;
1110 return device.GetLogical().CreateImage(VkImageCreateInfo{ 1103 return memory_allocator.CreateImage(VkImageCreateInfo{
1111 .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, 1104 .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
1112 .pNext = nullptr, 1105 .pNext = nullptr,
1113 .flags = 0, 1106 .flags = 0,
@@ -1130,9 +1123,6 @@ void BlitScreen::CreateRawImages(const Tegra::FramebufferConfig& framebuffer) {
1130 .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, 1123 .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
1131 }); 1124 });
1132 }; 1125 };
1133 const auto create_commit = [&](vk::Image& image) {
1134 return memory_allocator.Commit(image, MemoryUsage::DeviceLocal);
1135 };
1136 const auto create_image_view = [&](vk::Image& image, bool used_on_framebuffer = false) { 1126 const auto create_image_view = [&](vk::Image& image, bool used_on_framebuffer = false) {
1137 return device.GetLogical().CreateImageView(VkImageViewCreateInfo{ 1127 return device.GetLogical().CreateImageView(VkImageViewCreateInfo{
1138 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, 1128 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
@@ -1161,7 +1151,6 @@ void BlitScreen::CreateRawImages(const Tegra::FramebufferConfig& framebuffer) {
1161 1151
1162 for (size_t i = 0; i < image_count; ++i) { 1152 for (size_t i = 0; i < image_count; ++i) {
1163 raw_images[i] = create_image(); 1153 raw_images[i] = create_image();
1164 raw_buffer_commits[i] = create_commit(raw_images[i]);
1165 raw_image_views[i] = create_image_view(raw_images[i]); 1154 raw_image_views[i] = create_image_view(raw_images[i]);
1166 } 1155 }
1167 1156
@@ -1169,7 +1158,6 @@ void BlitScreen::CreateRawImages(const Tegra::FramebufferConfig& framebuffer) {
1169 const u32 up_scale = Settings::values.resolution_info.up_scale; 1158 const u32 up_scale = Settings::values.resolution_info.up_scale;
1170 const u32 down_shift = Settings::values.resolution_info.down_shift; 1159 const u32 down_shift = Settings::values.resolution_info.down_shift;
1171 aa_image = create_image(true, up_scale, down_shift); 1160 aa_image = create_image(true, up_scale, down_shift);
1172 aa_commit = create_commit(aa_image);
1173 aa_image_view = create_image_view(aa_image, true); 1161 aa_image_view = create_image_view(aa_image, true);
1174 VkExtent2D size{ 1162 VkExtent2D size{
1175 .width = (up_scale * framebuffer.width) >> down_shift, 1163 .width = (up_scale * framebuffer.width) >> down_shift,
diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.h b/src/video_core/renderer_vulkan/vk_blit_screen.h
index 68ec20253..8365b5668 100644
--- a/src/video_core/renderer_vulkan/vk_blit_screen.h
+++ b/src/video_core/renderer_vulkan/vk_blit_screen.h
@@ -142,13 +142,11 @@ 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
149 std::vector<vk::Image> raw_images; 148 std::vector<vk::Image> raw_images;
150 std::vector<vk::ImageView> raw_image_views; 149 std::vector<vk::ImageView> raw_image_views;
151 std::vector<MemoryCommit> raw_buffer_commits;
152 150
153 vk::DescriptorPool aa_descriptor_pool; 151 vk::DescriptorPool aa_descriptor_pool;
154 vk::DescriptorSetLayout aa_descriptor_set_layout; 152 vk::DescriptorSetLayout aa_descriptor_set_layout;
@@ -159,7 +157,6 @@ private:
159 vk::DescriptorSets aa_descriptor_sets; 157 vk::DescriptorSets aa_descriptor_sets;
160 vk::Image aa_image; 158 vk::Image aa_image;
161 vk::ImageView aa_image_view; 159 vk::ImageView aa_image_view;
162 MemoryCommit aa_commit;
163 160
164 u32 raw_width = 0; 161 u32 raw_width = 0;
165 u32 raw_height = 0; 162 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 f47301ad5..660f7c9ff 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_fsr.cpp b/src/video_core/renderer_vulkan/vk_fsr.cpp
index df972cd54..9bcdca2fb 100644
--- a/src/video_core/renderer_vulkan/vk_fsr.cpp
+++ b/src/video_core/renderer_vulkan/vk_fsr.cpp
@@ -205,10 +205,9 @@ void FSR::CreateDescriptorSets() {
205void FSR::CreateImages() { 205void FSR::CreateImages() {
206 images.resize(image_count * 2); 206 images.resize(image_count * 2);
207 image_views.resize(image_count * 2); 207 image_views.resize(image_count * 2);
208 buffer_commits.resize(image_count * 2);
209 208
210 for (size_t i = 0; i < image_count * 2; ++i) { 209 for (size_t i = 0; i < image_count * 2; ++i) {
211 images[i] = device.GetLogical().CreateImage(VkImageCreateInfo{ 210 images[i] = memory_allocator.CreateImage(VkImageCreateInfo{
212 .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, 211 .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
213 .pNext = nullptr, 212 .pNext = nullptr,
214 .flags = 0, 213 .flags = 0,
@@ -231,7 +230,6 @@ void FSR::CreateImages() {
231 .pQueueFamilyIndices = nullptr, 230 .pQueueFamilyIndices = nullptr,
232 .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, 231 .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
233 }); 232 });
234 buffer_commits[i] = memory_allocator.Commit(images[i], MemoryUsage::DeviceLocal);
235 image_views[i] = device.GetLogical().CreateImageView(VkImageViewCreateInfo{ 233 image_views[i] = device.GetLogical().CreateImageView(VkImageViewCreateInfo{
236 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, 234 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
237 .pNext = nullptr, 235 .pNext = nullptr,
diff --git a/src/video_core/renderer_vulkan/vk_fsr.h b/src/video_core/renderer_vulkan/vk_fsr.h
index 5d872861f..8bb9fc23a 100644
--- a/src/video_core/renderer_vulkan/vk_fsr.h
+++ b/src/video_core/renderer_vulkan/vk_fsr.h
@@ -47,7 +47,6 @@ private:
47 vk::Sampler sampler; 47 vk::Sampler sampler;
48 std::vector<vk::Image> images; 48 std::vector<vk::Image> images;
49 std::vector<vk::ImageView> image_views; 49 std::vector<vk::ImageView> image_views;
50 std::vector<MemoryCommit> buffer_commits;
51}; 50};
52 51
53} // namespace Vulkan 52} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_present_manager.cpp b/src/video_core/renderer_vulkan/vk_present_manager.cpp
index 10ace0420..d681bd22a 100644
--- a/src/video_core/renderer_vulkan/vk_present_manager.cpp
+++ b/src/video_core/renderer_vulkan/vk_present_manager.cpp
@@ -181,7 +181,7 @@ void PresentManager::RecreateFrame(Frame* frame, u32 width, u32 height, bool is_
181 frame->height = height; 181 frame->height = height;
182 frame->is_srgb = is_srgb; 182 frame->is_srgb = is_srgb;
183 183
184 frame->image = dld.CreateImage({ 184 frame->image = memory_allocator.CreateImage({
185 .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, 185 .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
186 .pNext = nullptr, 186 .pNext = nullptr,
187 .flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT, 187 .flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT,
@@ -204,8 +204,6 @@ void PresentManager::RecreateFrame(Frame* frame, u32 width, u32 height, bool is_
204 .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, 204 .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
205 }); 205 });
206 206
207 frame->image_commit = memory_allocator.Commit(frame->image, MemoryUsage::DeviceLocal);
208
209 frame->image_view = dld.CreateImageView({ 207 frame->image_view = dld.CreateImageView({
210 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, 208 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
211 .pNext = nullptr, 209 .pNext = nullptr,
diff --git a/src/video_core/renderer_vulkan/vk_present_manager.h b/src/video_core/renderer_vulkan/vk_present_manager.h
index 4ac2e2395..83e859416 100644
--- a/src/video_core/renderer_vulkan/vk_present_manager.h
+++ b/src/video_core/renderer_vulkan/vk_present_manager.h
@@ -29,7 +29,6 @@ struct Frame {
29 vk::Image image; 29 vk::Image image;
30 vk::ImageView image_view; 30 vk::ImageView image_view;
31 vk::Framebuffer framebuffer; 31 vk::Framebuffer framebuffer;
32 MemoryCommit image_commit;
33 vk::CommandBuffer cmdbuf; 32 vk::CommandBuffer cmdbuf;
34 vk::Semaphore render_ready; 33 vk::Semaphore render_ready;
35 vk::Fence present_done; 34 vk::Fence present_done;
diff --git a/src/video_core/renderer_vulkan/vk_smaa.cpp b/src/video_core/renderer_vulkan/vk_smaa.cpp
index f8735189d..5efd7d66e 100644
--- a/src/video_core/renderer_vulkan/vk_smaa.cpp
+++ b/src/video_core/renderer_vulkan/vk_smaa.cpp
@@ -25,9 +25,7 @@ namespace {
25 25
26#define ARRAY_TO_SPAN(a) std::span(a, (sizeof(a) / sizeof(a[0]))) 26#define ARRAY_TO_SPAN(a) std::span(a, (sizeof(a) / sizeof(a[0])))
27 27
28std::pair<vk::Image, MemoryCommit> CreateWrappedImage(const Device& device, 28vk::Image CreateWrappedImage(MemoryAllocator& allocator, VkExtent2D dimensions, VkFormat format) {
29 MemoryAllocator& allocator,
30 VkExtent2D dimensions, VkFormat format) {
31 const VkImageCreateInfo image_ci{ 29 const VkImageCreateInfo image_ci{
32 .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, 30 .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
33 .pNext = nullptr, 31 .pNext = nullptr,
@@ -46,11 +44,7 @@ std::pair<vk::Image, MemoryCommit> CreateWrappedImage(const Device& device,
46 .pQueueFamilyIndices = nullptr, 44 .pQueueFamilyIndices = nullptr,
47 .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, 45 .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
48 }; 46 };
49 47 return allocator.CreateImage(image_ci);
50 auto image = device.GetLogical().CreateImage(image_ci);
51 auto commit = allocator.Commit(image, Vulkan::MemoryUsage::DeviceLocal);
52
53 return std::make_pair(std::move(image), std::move(commit));
54} 48}
55 49
56void TransitionImageLayout(vk::CommandBuffer& cmdbuf, VkImage image, VkImageLayout target_layout, 50void TransitionImageLayout(vk::CommandBuffer& cmdbuf, VkImage image, VkImageLayout target_layout,
@@ -82,7 +76,7 @@ void TransitionImageLayout(vk::CommandBuffer& cmdbuf, VkImage image, VkImageLayo
82void UploadImage(const Device& device, MemoryAllocator& allocator, Scheduler& scheduler, 76void UploadImage(const Device& device, MemoryAllocator& allocator, Scheduler& scheduler,
83 vk::Image& image, VkExtent2D dimensions, VkFormat format, 77 vk::Image& image, VkExtent2D dimensions, VkFormat format,
84 std::span<const u8> initial_contents = {}) { 78 std::span<const u8> initial_contents = {}) {
85 auto upload_buffer = device.GetLogical().CreateBuffer(VkBufferCreateInfo{ 79 const VkBufferCreateInfo upload_ci = {
86 .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, 80 .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
87 .pNext = nullptr, 81 .pNext = nullptr,
88 .flags = 0, 82 .flags = 0,
@@ -91,9 +85,10 @@ void UploadImage(const Device& device, MemoryAllocator& allocator, Scheduler& sc
91 .sharingMode = VK_SHARING_MODE_EXCLUSIVE, 85 .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
92 .queueFamilyIndexCount = 0, 86 .queueFamilyIndexCount = 0,
93 .pQueueFamilyIndices = nullptr, 87 .pQueueFamilyIndices = nullptr,
94 }); 88 };
95 auto upload_commit = allocator.Commit(upload_buffer, MemoryUsage::Upload); 89 auto upload_buffer = allocator.CreateBuffer(upload_ci, MemoryUsage::Upload);
96 std::ranges::copy(initial_contents, upload_commit.Map().begin()); 90 std::ranges::copy(initial_contents, upload_buffer.Mapped().begin());
91 upload_buffer.Flush();
97 92
98 const std::array<VkBufferImageCopy, 1> regions{{{ 93 const std::array<VkBufferImageCopy, 1> regions{{{
99 .bufferOffset = 0, 94 .bufferOffset = 0,
@@ -117,9 +112,6 @@ void UploadImage(const Device& device, MemoryAllocator& allocator, Scheduler& sc
117 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); 112 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
118 }); 113 });
119 scheduler.Finish(); 114 scheduler.Finish();
120
121 // This should go out of scope before the commit
122 auto upload_buffer2 = std::move(upload_buffer);
123} 115}
124 116
125vk::ImageView CreateWrappedImageView(const Device& device, vk::Image& image, VkFormat format) { 117vk::ImageView CreateWrappedImageView(const Device& device, vk::Image& image, VkFormat format) {
@@ -531,10 +523,8 @@ void SMAA::CreateImages() {
531 static constexpr VkExtent2D area_extent{AREATEX_WIDTH, AREATEX_HEIGHT}; 523 static constexpr VkExtent2D area_extent{AREATEX_WIDTH, AREATEX_HEIGHT};
532 static constexpr VkExtent2D search_extent{SEARCHTEX_WIDTH, SEARCHTEX_HEIGHT}; 524 static constexpr VkExtent2D search_extent{SEARCHTEX_WIDTH, SEARCHTEX_HEIGHT};
533 525
534 std::tie(m_static_images[Area], m_static_buffer_commits[Area]) = 526 m_static_images[Area] = CreateWrappedImage(m_allocator, area_extent, VK_FORMAT_R8G8_UNORM);
535 CreateWrappedImage(m_device, m_allocator, area_extent, VK_FORMAT_R8G8_UNORM); 527 m_static_images[Search] = CreateWrappedImage(m_allocator, search_extent, VK_FORMAT_R8_UNORM);
536 std::tie(m_static_images[Search], m_static_buffer_commits[Search]) =
537 CreateWrappedImage(m_device, m_allocator, search_extent, VK_FORMAT_R8_UNORM);
538 528
539 m_static_image_views[Area] = 529 m_static_image_views[Area] =
540 CreateWrappedImageView(m_device, m_static_images[Area], VK_FORMAT_R8G8_UNORM); 530 CreateWrappedImageView(m_device, m_static_images[Area], VK_FORMAT_R8G8_UNORM);
@@ -544,12 +534,11 @@ void SMAA::CreateImages() {
544 for (u32 i = 0; i < m_image_count; i++) { 534 for (u32 i = 0; i < m_image_count; i++) {
545 Images& images = m_dynamic_images.emplace_back(); 535 Images& images = m_dynamic_images.emplace_back();
546 536
547 std::tie(images.images[Blend], images.buffer_commits[Blend]) = 537 images.images[Blend] =
548 CreateWrappedImage(m_device, m_allocator, m_extent, VK_FORMAT_R16G16B16A16_SFLOAT); 538 CreateWrappedImage(m_allocator, m_extent, VK_FORMAT_R16G16B16A16_SFLOAT);
549 std::tie(images.images[Edges], images.buffer_commits[Edges]) = 539 images.images[Edges] = CreateWrappedImage(m_allocator, m_extent, VK_FORMAT_R16G16_SFLOAT);
550 CreateWrappedImage(m_device, m_allocator, m_extent, VK_FORMAT_R16G16_SFLOAT); 540 images.images[Output] =
551 std::tie(images.images[Output], images.buffer_commits[Output]) = 541 CreateWrappedImage(m_allocator, m_extent, VK_FORMAT_R16G16B16A16_SFLOAT);
552 CreateWrappedImage(m_device, m_allocator, m_extent, VK_FORMAT_R16G16B16A16_SFLOAT);
553 542
554 images.image_views[Blend] = 543 images.image_views[Blend] =
555 CreateWrappedImageView(m_device, images.images[Blend], VK_FORMAT_R16G16B16A16_SFLOAT); 544 CreateWrappedImageView(m_device, images.images[Blend], VK_FORMAT_R16G16B16A16_SFLOAT);
diff --git a/src/video_core/renderer_vulkan/vk_smaa.h b/src/video_core/renderer_vulkan/vk_smaa.h
index 99a369148..0e214258a 100644
--- a/src/video_core/renderer_vulkan/vk_smaa.h
+++ b/src/video_core/renderer_vulkan/vk_smaa.h
@@ -66,13 +66,11 @@ private:
66 std::array<vk::Pipeline, MaxSMAAStage> m_pipelines{}; 66 std::array<vk::Pipeline, MaxSMAAStage> m_pipelines{};
67 std::array<vk::RenderPass, MaxSMAAStage> m_renderpasses{}; 67 std::array<vk::RenderPass, MaxSMAAStage> m_renderpasses{};
68 68
69 std::array<MemoryCommit, MaxStaticImage> m_static_buffer_commits;
70 std::array<vk::Image, MaxStaticImage> m_static_images{}; 69 std::array<vk::Image, MaxStaticImage> m_static_images{};
71 std::array<vk::ImageView, MaxStaticImage> m_static_image_views{}; 70 std::array<vk::ImageView, MaxStaticImage> m_static_image_views{};
72 71
73 struct Images { 72 struct Images {
74 vk::DescriptorSets descriptor_sets{}; 73 vk::DescriptorSets descriptor_sets{};
75 std::array<MemoryCommit, MaxDynamicImage> buffer_commits;
76 std::array<vk::Image, MaxDynamicImage> images{}; 74 std::array<vk::Image, MaxDynamicImage> images{};
77 std::array<vk::ImageView, MaxDynamicImage> image_views{}; 75 std::array<vk::ImageView, MaxDynamicImage> image_views{};
78 std::array<vk::Framebuffer, MaxSMAAStage> framebuffers{}; 76 std::array<vk::Framebuffer, MaxSMAAStage> framebuffers{};
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 f3cef09dd..ce6acc30c 100644
--- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
@@ -15,7 +15,6 @@
15#include "video_core/renderer_vulkan/blit_image.h" 15#include "video_core/renderer_vulkan/blit_image.h"
16#include "video_core/renderer_vulkan/maxwell_to_vk.h" 16#include "video_core/renderer_vulkan/maxwell_to_vk.h"
17#include "video_core/renderer_vulkan/vk_compute_pass.h" 17#include "video_core/renderer_vulkan/vk_compute_pass.h"
18#include "video_core/renderer_vulkan/vk_rasterizer.h"
19#include "video_core/renderer_vulkan/vk_render_pass_cache.h" 18#include "video_core/renderer_vulkan/vk_render_pass_cache.h"
20#include "video_core/renderer_vulkan/vk_scheduler.h" 19#include "video_core/renderer_vulkan/vk_scheduler.h"
21#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" 20#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h"
@@ -163,11 +162,12 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) {
163 }; 162 };
164} 163}
165 164
166[[nodiscard]] vk::Image MakeImage(const Device& device, const ImageInfo& info) { 165[[nodiscard]] vk::Image MakeImage(const Device& device, const MemoryAllocator& allocator,
166 const ImageInfo& info) {
167 if (info.type == ImageType::Buffer) { 167 if (info.type == ImageType::Buffer) {
168 return vk::Image{}; 168 return vk::Image{};
169 } 169 }
170 return device.GetLogical().CreateImage(MakeImageCreateInfo(device, info)); 170 return allocator.CreateImage(MakeImageCreateInfo(device, info));
171} 171}
172 172
173[[nodiscard]] VkImageAspectFlags ImageAspectMask(PixelFormat format) { 173[[nodiscard]] VkImageAspectFlags ImageAspectMask(PixelFormat format) {
@@ -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
@@ -1266,8 +1265,8 @@ void TextureCacheRuntime::TickFrame() {}
1266Image::Image(TextureCacheRuntime& runtime_, const ImageInfo& info_, GPUVAddr gpu_addr_, 1265Image::Image(TextureCacheRuntime& runtime_, const ImageInfo& info_, GPUVAddr gpu_addr_,
1267 VAddr cpu_addr_) 1266 VAddr cpu_addr_)
1268 : VideoCommon::ImageBase(info_, gpu_addr_, cpu_addr_), scheduler{&runtime_.scheduler}, 1267 : VideoCommon::ImageBase(info_, gpu_addr_, cpu_addr_), scheduler{&runtime_.scheduler},
1269 runtime{&runtime_}, original_image(MakeImage(runtime_.device, info)), 1268 runtime{&runtime_},
1270 commit(runtime_.memory_allocator.Commit(original_image, MemoryUsage::DeviceLocal)), 1269 original_image(MakeImage(runtime_.device, runtime_.memory_allocator, info)),
1271 aspect_mask(ImageAspectMask(info.format)) { 1270 aspect_mask(ImageAspectMask(info.format)) {
1272 if (IsPixelFormatASTC(info.format) && !runtime->device.IsOptimalAstcSupported()) { 1271 if (IsPixelFormatASTC(info.format) && !runtime->device.IsOptimalAstcSupported()) {
1273 if (Settings::values.async_astc.GetValue()) { 1272 if (Settings::values.async_astc.GetValue()) {
@@ -1468,9 +1467,7 @@ bool Image::ScaleUp(bool ignore) {
1468 auto scaled_info = info; 1467 auto scaled_info = info;
1469 scaled_info.size.width = scaled_width; 1468 scaled_info.size.width = scaled_width;
1470 scaled_info.size.height = scaled_height; 1469 scaled_info.size.height = scaled_height;
1471 scaled_image = MakeImage(runtime->device, scaled_info); 1470 scaled_image = MakeImage(runtime->device, runtime->memory_allocator, scaled_info);
1472 auto& allocator = runtime->memory_allocator;
1473 scaled_commit = MemoryCommit(allocator.Commit(scaled_image, MemoryUsage::DeviceLocal));
1474 ignore = false; 1471 ignore = false;
1475 } 1472 }
1476 current_image = *scaled_image; 1473 current_image = *scaled_image;
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.h b/src/video_core/renderer_vulkan/vk_texture_cache.h
index f14525dcb..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 {
@@ -180,12 +179,10 @@ private:
180 TextureCacheRuntime* runtime{}; 179 TextureCacheRuntime* runtime{};
181 180
182 vk::Image original_image; 181 vk::Image original_image;
183 MemoryCommit commit;
184 std::vector<vk::ImageView> storage_image_views; 182 std::vector<vk::ImageView> storage_image_views;
185 VkImageAspectFlags aspect_mask = 0; 183 VkImageAspectFlags aspect_mask = 0;
186 bool initialized = false; 184 bool initialized = false;
187 vk::Image scaled_image{}; 185 vk::Image scaled_image{};
188 MemoryCommit scaled_commit{};
189 VkImage current_image{}; 186 VkImage current_image{};
190 187
191 std::unique_ptr<Framebuffer> scale_framebuffer; 188 std::unique_ptr<Framebuffer> scale_framebuffer;
diff --git a/src/video_core/renderer_vulkan/vk_turbo_mode.cpp b/src/video_core/renderer_vulkan/vk_turbo_mode.cpp
index a802d3c49..460d8d59d 100644
--- a/src/video_core/renderer_vulkan/vk_turbo_mode.cpp
+++ b/src/video_core/renderer_vulkan/vk_turbo_mode.cpp
@@ -18,7 +18,7 @@ using namespace Common::Literals;
18 18
19TurboMode::TurboMode(const vk::Instance& instance, const vk::InstanceDispatch& dld) 19TurboMode::TurboMode(const vk::Instance& instance, const vk::InstanceDispatch& dld)
20#ifndef ANDROID 20#ifndef ANDROID
21 : m_device{CreateDevice(instance, dld, VK_NULL_HANDLE)}, m_allocator{m_device, false} 21 : m_device{CreateDevice(instance, dld, VK_NULL_HANDLE)}, m_allocator{m_device}
22#endif 22#endif
23{ 23{
24 { 24 {
@@ -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 b11abe311..e4ca65b58 100644
--- a/src/video_core/vulkan_common/vulkan_device.cpp
+++ b/src/video_core/vulkan_common/vulkan_device.cpp
@@ -22,6 +22,8 @@
22#include <adrenotools/bcenabler.h> 22#include <adrenotools/bcenabler.h>
23#endif 23#endif
24 24
25#include <vk_mem_alloc.h>
26
25namespace Vulkan { 27namespace Vulkan {
26using namespace Common::Literals; 28using namespace Common::Literals;
27namespace { 29namespace {
@@ -596,9 +598,31 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
596 598
597 graphics_queue = logical.GetQueue(graphics_family); 599 graphics_queue = logical.GetQueue(graphics_family);
598 present_queue = logical.GetQueue(present_family); 600 present_queue = logical.GetQueue(present_family);
601
602 VmaVulkanFunctions functions{};
603 functions.vkGetInstanceProcAddr = dld.vkGetInstanceProcAddr;
604 functions.vkGetDeviceProcAddr = dld.vkGetDeviceProcAddr;
605
606 const VmaAllocatorCreateInfo allocator_info = {
607 .flags = VMA_ALLOCATOR_CREATE_EXTERNALLY_SYNCHRONIZED_BIT,
608 .physicalDevice = physical,
609 .device = *logical,
610 .preferredLargeHeapBlockSize = 0,
611 .pAllocationCallbacks = nullptr,
612 .pDeviceMemoryCallbacks = nullptr,
613 .pHeapSizeLimit = nullptr,
614 .pVulkanFunctions = &functions,
615 .instance = instance,
616 .vulkanApiVersion = VK_API_VERSION_1_1,
617 .pTypeExternalMemoryHandleTypes = nullptr,
618 };
619
620 vk::Check(vmaCreateAllocator(&allocator_info, &allocator));
599} 621}
600 622
601Device::~Device() = default; 623Device::~Device() {
624 vmaDestroyAllocator(allocator);
625}
602 626
603VkFormat Device::GetSupportedFormat(VkFormat wanted_format, VkFormatFeatureFlags wanted_usage, 627VkFormat Device::GetSupportedFormat(VkFormat wanted_format, VkFormatFeatureFlags wanted_usage,
604 FormatType format_type) const { 628 FormatType format_type) const {
diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h
index 0b634a876..b84af3dfb 100644
--- a/src/video_core/vulkan_common/vulkan_device.h
+++ b/src/video_core/vulkan_common/vulkan_device.h
@@ -14,6 +14,8 @@
14#include "common/settings.h" 14#include "common/settings.h"
15#include "video_core/vulkan_common/vulkan_wrapper.h" 15#include "video_core/vulkan_common/vulkan_wrapper.h"
16 16
17VK_DEFINE_HANDLE(VmaAllocator)
18
17// Define all features which may be used by the implementation here. 19// Define all features which may be used by the implementation here.
18// Vulkan version in the macro describes the minimum version required for feature availability. 20// Vulkan version in the macro describes the minimum version required for feature availability.
19// If the Vulkan version is lower than the required version, the named extension is required. 21// If the Vulkan version is lower than the required version, the named extension is required.
@@ -199,6 +201,11 @@ public:
199 return dld; 201 return dld;
200 } 202 }
201 203
204 /// Returns the VMA allocator.
205 VmaAllocator GetAllocator() const {
206 return allocator;
207 }
208
202 /// Returns the logical device. 209 /// Returns the logical device.
203 const vk::Device& GetLogical() const { 210 const vk::Device& GetLogical() const {
204 return logical; 211 return logical;
@@ -630,6 +637,7 @@ private:
630 637
631private: 638private:
632 VkInstance instance; ///< Vulkan instance. 639 VkInstance instance; ///< Vulkan instance.
640 VmaAllocator allocator; ///< VMA allocator.
633 vk::DeviceDispatch dld; ///< Device function pointers. 641 vk::DeviceDispatch dld; ///< Device function pointers.
634 vk::PhysicalDevice physical; ///< Physical device. 642 vk::PhysicalDevice physical; ///< Physical device.
635 vk::Device logical; ///< Logical device. 643 vk::Device logical; ///< Logical device.
diff --git a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp
index e28a556f8..a2ef0efa4 100644
--- a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp
+++ b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp
@@ -6,8 +6,6 @@
6#include <optional> 6#include <optional>
7#include <vector> 7#include <vector>
8 8
9#include <glad/glad.h>
10
11#include "common/alignment.h" 9#include "common/alignment.h"
12#include "common/assert.h" 10#include "common/assert.h"
13#include "common/common_types.h" 11#include "common/common_types.h"
@@ -17,6 +15,8 @@
17#include "video_core/vulkan_common/vulkan_memory_allocator.h" 15#include "video_core/vulkan_common/vulkan_memory_allocator.h"
18#include "video_core/vulkan_common/vulkan_wrapper.h" 16#include "video_core/vulkan_common/vulkan_wrapper.h"
19 17
18#include <vk_mem_alloc.h>
19
20namespace Vulkan { 20namespace Vulkan {
21namespace { 21namespace {
22struct Range { 22struct Range {
@@ -49,22 +49,45 @@ struct Range {
49 case MemoryUsage::Download: 49 case MemoryUsage::Download:
50 return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | 50 return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT |
51 VK_MEMORY_PROPERTY_HOST_CACHED_BIT; 51 VK_MEMORY_PROPERTY_HOST_CACHED_BIT;
52 case MemoryUsage::Stream:
53 return VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
54 VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
52 } 55 }
53 ASSERT_MSG(false, "Invalid memory usage={}", usage); 56 ASSERT_MSG(false, "Invalid memory usage={}", usage);
54 return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; 57 return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
55} 58}
56 59
57constexpr VkExportMemoryAllocateInfo EXPORT_ALLOCATE_INFO{ 60[[nodiscard]] VkMemoryPropertyFlags MemoryUsagePreferedVmaFlags(MemoryUsage usage) {
58 .sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO, 61 return usage != MemoryUsage::DeviceLocal ? VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
59 .pNext = nullptr, 62 : VkMemoryPropertyFlagBits{};
60#ifdef _WIN32 63}
61 .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT, 64
62#elif __unix__ 65[[nodiscard]] VmaAllocationCreateFlags MemoryUsageVmaFlags(MemoryUsage usage) {
63 .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT, 66 switch (usage) {
64#else 67 case MemoryUsage::Upload:
65 .handleTypes = 0, 68 case MemoryUsage::Stream:
66#endif 69 return VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT;
67}; 70 case MemoryUsage::Download:
71 return VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT;
72 case MemoryUsage::DeviceLocal:
73 return VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT |
74 VMA_ALLOCATION_CREATE_HOST_ACCESS_ALLOW_TRANSFER_INSTEAD_BIT;
75 }
76 return {};
77}
78
79[[nodiscard]] VmaMemoryUsage MemoryUsageVma(MemoryUsage usage) {
80 switch (usage) {
81 case MemoryUsage::DeviceLocal:
82 case MemoryUsage::Stream:
83 return VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE;
84 case MemoryUsage::Upload:
85 case MemoryUsage::Download:
86 return VMA_MEMORY_USAGE_AUTO_PREFER_HOST;
87 }
88 return VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE;
89}
90
68} // Anonymous namespace 91} // Anonymous namespace
69 92
70class MemoryAllocation { 93class MemoryAllocation {
@@ -74,14 +97,6 @@ public:
74 : allocator{allocator_}, memory{std::move(memory_)}, allocation_size{allocation_size_}, 97 : allocator{allocator_}, memory{std::move(memory_)}, allocation_size{allocation_size_},
75 property_flags{properties}, shifted_memory_type{1U << type} {} 98 property_flags{properties}, shifted_memory_type{1U << type} {}
76 99
77#if defined(_WIN32) || defined(__unix__)
78 ~MemoryAllocation() {
79 if (owning_opengl_handle != 0) {
80 glDeleteMemoryObjectsEXT(1, &owning_opengl_handle);
81 }
82 }
83#endif
84
85 MemoryAllocation& operator=(const MemoryAllocation&) = delete; 100 MemoryAllocation& operator=(const MemoryAllocation&) = delete;
86 MemoryAllocation(const MemoryAllocation&) = delete; 101 MemoryAllocation(const MemoryAllocation&) = delete;
87 102
@@ -120,31 +135,6 @@ public:
120 return memory_mapped_span; 135 return memory_mapped_span;
121 } 136 }
122 137
123#ifdef _WIN32
124 [[nodiscard]] u32 ExportOpenGLHandle() {
125 if (!owning_opengl_handle) {
126 glCreateMemoryObjectsEXT(1, &owning_opengl_handle);
127 glImportMemoryWin32HandleEXT(owning_opengl_handle, allocation_size,
128 GL_HANDLE_TYPE_OPAQUE_WIN32_EXT,
129 memory.GetMemoryWin32HandleKHR());
130 }
131 return owning_opengl_handle;
132 }
133#elif __unix__
134 [[nodiscard]] u32 ExportOpenGLHandle() {
135 if (!owning_opengl_handle) {
136 glCreateMemoryObjectsEXT(1, &owning_opengl_handle);
137 glImportMemoryFdEXT(owning_opengl_handle, allocation_size, GL_HANDLE_TYPE_OPAQUE_FD_EXT,
138 memory.GetMemoryFdKHR());
139 }
140 return owning_opengl_handle;
141 }
142#else
143 [[nodiscard]] u32 ExportOpenGLHandle() {
144 return 0;
145 }
146#endif
147
148 /// Returns whether this allocation is compatible with the arguments. 138 /// Returns whether this allocation is compatible with the arguments.
149 [[nodiscard]] bool IsCompatible(VkMemoryPropertyFlags flags, u32 type_mask) const { 139 [[nodiscard]] bool IsCompatible(VkMemoryPropertyFlags flags, u32 type_mask) const {
150 return (flags & property_flags) == flags && (type_mask & shifted_memory_type) != 0; 140 return (flags & property_flags) == flags && (type_mask & shifted_memory_type) != 0;
@@ -182,9 +172,6 @@ private:
182 const u32 shifted_memory_type; ///< Shifted Vulkan memory type. 172 const u32 shifted_memory_type; ///< Shifted Vulkan memory type.
183 std::vector<Range> commits; ///< All commit ranges done from this allocation. 173 std::vector<Range> commits; ///< All commit ranges done from this allocation.
184 std::span<u8> memory_mapped_span; ///< Memory mapped span. Empty if not queried before. 174 std::span<u8> memory_mapped_span; ///< Memory mapped span. Empty if not queried before.
185#if defined(_WIN32) || defined(__unix__)
186 u32 owning_opengl_handle{}; ///< Owning OpenGL memory object handle.
187#endif
188}; 175};
189 176
190MemoryCommit::MemoryCommit(MemoryAllocation* allocation_, VkDeviceMemory memory_, u64 begin_, 177MemoryCommit::MemoryCommit(MemoryAllocation* allocation_, VkDeviceMemory memory_, u64 begin_,
@@ -216,24 +203,70 @@ std::span<u8> MemoryCommit::Map() {
216 return span; 203 return span;
217} 204}
218 205
219u32 MemoryCommit::ExportOpenGLHandle() const {
220 return allocation->ExportOpenGLHandle();
221}
222
223void MemoryCommit::Release() { 206void MemoryCommit::Release() {
224 if (allocation) { 207 if (allocation) {
225 allocation->Free(begin); 208 allocation->Free(begin);
226 } 209 }
227} 210}
228 211
229MemoryAllocator::MemoryAllocator(const Device& device_, bool export_allocations_) 212MemoryAllocator::MemoryAllocator(const Device& device_)
230 : device{device_}, properties{device_.GetPhysical().GetMemoryProperties().memoryProperties}, 213 : device{device_}, allocator{device.GetAllocator()},
231 export_allocations{export_allocations_}, 214 properties{device_.GetPhysical().GetMemoryProperties().memoryProperties},
232 buffer_image_granularity{ 215 buffer_image_granularity{
233 device_.GetPhysical().GetProperties().limits.bufferImageGranularity} {} 216 device_.GetPhysical().GetProperties().limits.bufferImageGranularity} {}
234 217
235MemoryAllocator::~MemoryAllocator() = default; 218MemoryAllocator::~MemoryAllocator() = default;
236 219
220vk::Image MemoryAllocator::CreateImage(const VkImageCreateInfo& ci) const {
221 const VmaAllocationCreateInfo alloc_ci = {
222 .flags = VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT,
223 .usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE,
224 .requiredFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
225 .preferredFlags = 0,
226 .memoryTypeBits = 0,
227 .pool = VK_NULL_HANDLE,
228 .pUserData = nullptr,
229 .priority = 0.f,
230 };
231
232 VkImage handle{};
233 VmaAllocation allocation{};
234
235 vk::Check(vmaCreateImage(allocator, &ci, &alloc_ci, &handle, &allocation, nullptr));
236
237 return vk::Image(handle, *device.GetLogical(), allocator, allocation,
238 device.GetDispatchLoader());
239}
240
241vk::Buffer MemoryAllocator::CreateBuffer(const VkBufferCreateInfo& ci, MemoryUsage usage) const {
242 const VmaAllocationCreateInfo alloc_ci = {
243 .flags = VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT |
244 MemoryUsageVmaFlags(usage),
245 .usage = MemoryUsageVma(usage),
246 .requiredFlags = 0,
247 .preferredFlags = MemoryUsagePreferedVmaFlags(usage),
248 .memoryTypeBits = 0,
249 .pool = VK_NULL_HANDLE,
250 .pUserData = nullptr,
251 .priority = 0.f,
252 };
253
254 VkBuffer handle{};
255 VmaAllocationInfo alloc_info{};
256 VmaAllocation allocation{};
257 VkMemoryPropertyFlags property_flags{};
258
259 vk::Check(vmaCreateBuffer(allocator, &ci, &alloc_ci, &handle, &allocation, &alloc_info));
260 vmaGetAllocationMemoryProperties(allocator, allocation, &property_flags);
261
262 u8* data = reinterpret_cast<u8*>(alloc_info.pMappedData);
263 const std::span<u8> mapped_data = data ? std::span<u8>{data, ci.size} : std::span<u8>{};
264 const bool is_coherent = property_flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
265
266 return vk::Buffer(handle, *device.GetLogical(), allocator, allocation, mapped_data, is_coherent,
267 device.GetDispatchLoader());
268}
269
237MemoryCommit MemoryAllocator::Commit(const VkMemoryRequirements& requirements, MemoryUsage usage) { 270MemoryCommit MemoryAllocator::Commit(const VkMemoryRequirements& requirements, MemoryUsage usage) {
238 // Find the fastest memory flags we can afford with the current requirements 271 // Find the fastest memory flags we can afford with the current requirements
239 const u32 type_mask = requirements.memoryTypeBits; 272 const u32 type_mask = requirements.memoryTypeBits;
@@ -253,25 +286,11 @@ MemoryCommit MemoryAllocator::Commit(const VkMemoryRequirements& requirements, M
253 return TryCommit(requirements, flags).value(); 286 return TryCommit(requirements, flags).value();
254} 287}
255 288
256MemoryCommit MemoryAllocator::Commit(const vk::Buffer& buffer, MemoryUsage usage) {
257 auto commit = Commit(device.GetLogical().GetBufferMemoryRequirements(*buffer), usage);
258 buffer.BindMemory(commit.Memory(), commit.Offset());
259 return commit;
260}
261
262MemoryCommit MemoryAllocator::Commit(const vk::Image& image, MemoryUsage usage) {
263 VkMemoryRequirements requirements = device.GetLogical().GetImageMemoryRequirements(*image);
264 requirements.size = Common::AlignUp(requirements.size, buffer_image_granularity);
265 auto commit = Commit(requirements, usage);
266 image.BindMemory(commit.Memory(), commit.Offset());
267 return commit;
268}
269
270bool MemoryAllocator::TryAllocMemory(VkMemoryPropertyFlags flags, u32 type_mask, u64 size) { 289bool MemoryAllocator::TryAllocMemory(VkMemoryPropertyFlags flags, u32 type_mask, u64 size) {
271 const u32 type = FindType(flags, type_mask).value(); 290 const u32 type = FindType(flags, type_mask).value();
272 vk::DeviceMemory memory = device.GetLogical().TryAllocateMemory({ 291 vk::DeviceMemory memory = device.GetLogical().TryAllocateMemory({
273 .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, 292 .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
274 .pNext = export_allocations ? &EXPORT_ALLOCATE_INFO : nullptr, 293 .pNext = nullptr,
275 .allocationSize = size, 294 .allocationSize = size,
276 .memoryTypeIndex = type, 295 .memoryTypeIndex = type,
277 }); 296 });
@@ -342,16 +361,4 @@ std::optional<u32> MemoryAllocator::FindType(VkMemoryPropertyFlags flags, u32 ty
342 return std::nullopt; 361 return std::nullopt;
343} 362}
344 363
345bool IsHostVisible(MemoryUsage usage) noexcept {
346 switch (usage) {
347 case MemoryUsage::DeviceLocal:
348 return false;
349 case MemoryUsage::Upload:
350 case MemoryUsage::Download:
351 return true;
352 }
353 ASSERT_MSG(false, "Invalid memory usage={}", usage);
354 return false;
355}
356
357} // namespace Vulkan 364} // 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 a5bff03fe..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.
@@ -41,9 +45,6 @@ public:
41 /// It will map the backing allocation if it hasn't been mapped before. 45 /// It will map the backing allocation if it hasn't been mapped before.
42 std::span<u8> Map(); 46 std::span<u8> Map();
43 47
44 /// Returns an non-owning OpenGL handle, creating one if it doesn't exist.
45 u32 ExportOpenGLHandle() const;
46
47 /// Returns the Vulkan memory handler. 48 /// Returns the Vulkan memory handler.
48 VkDeviceMemory Memory() const { 49 VkDeviceMemory Memory() const {
49 return memory; 50 return memory;
@@ -74,16 +75,19 @@ public:
74 * Construct memory allocator 75 * Construct memory allocator
75 * 76 *
76 * @param device_ Device to allocate from 77 * @param device_ Device to allocate from
77 * @param export_allocations_ True when allocations have to be exported
78 * 78 *
79 * @throw vk::Exception on failure 79 * @throw vk::Exception on failure
80 */ 80 */
81 explicit MemoryAllocator(const Device& device_, bool export_allocations_); 81 explicit MemoryAllocator(const Device& device_);
82 ~MemoryAllocator(); 82 ~MemoryAllocator();
83 83
84 MemoryAllocator& operator=(const MemoryAllocator&) = delete; 84 MemoryAllocator& operator=(const MemoryAllocator&) = delete;
85 MemoryAllocator(const MemoryAllocator&) = delete; 85 MemoryAllocator(const MemoryAllocator&) = delete;
86 86
87 vk::Image CreateImage(const VkImageCreateInfo& ci) const;
88
89 vk::Buffer CreateBuffer(const VkBufferCreateInfo& ci, MemoryUsage usage) const;
90
87 /** 91 /**
88 * Commits a memory with the specified requirements. 92 * Commits a memory with the specified requirements.
89 * 93 *
@@ -97,9 +101,6 @@ public:
97 /// Commits memory required by the buffer and binds it. 101 /// Commits memory required by the buffer and binds it.
98 MemoryCommit Commit(const vk::Buffer& buffer, MemoryUsage usage); 102 MemoryCommit Commit(const vk::Buffer& buffer, MemoryUsage usage);
99 103
100 /// Commits memory required by the image and binds it.
101 MemoryCommit Commit(const vk::Image& image, MemoryUsage usage);
102
103private: 104private:
104 /// Tries to allocate a chunk of memory. 105 /// Tries to allocate a chunk of memory.
105 bool TryAllocMemory(VkMemoryPropertyFlags flags, u32 type_mask, u64 size); 106 bool TryAllocMemory(VkMemoryPropertyFlags flags, u32 type_mask, u64 size);
@@ -117,15 +118,12 @@ private:
117 /// Returns index to the fastest memory type compatible with the passed requirements. 118 /// Returns index to the fastest memory type compatible with the passed requirements.
118 std::optional<u32> FindType(VkMemoryPropertyFlags flags, u32 type_mask) const; 119 std::optional<u32> FindType(VkMemoryPropertyFlags flags, u32 type_mask) const;
119 120
120 const Device& device; ///< Device handle. 121 const Device& device; ///< Device handle.
121 const VkPhysicalDeviceMemoryProperties properties; ///< Physical device properties. 122 VmaAllocator allocator; ///< Vma allocator.
122 const bool export_allocations; ///< True when memory allocations have to be exported. 123 const VkPhysicalDeviceMemoryProperties properties; ///< Physical device properties.
123 std::vector<std::unique_ptr<MemoryAllocation>> allocations; ///< Current allocations. 124 std::vector<std::unique_ptr<MemoryAllocation>> allocations; ///< Current allocations.
124 VkDeviceSize buffer_image_granularity; // The granularity for adjacent offsets between buffers 125 VkDeviceSize buffer_image_granularity; // The granularity for adjacent offsets between buffers
125 // and optimal images 126 // and optimal images
126}; 127};
127 128
128/// Returns true when a memory usage is guaranteed to be host visible.
129bool IsHostVisible(MemoryUsage usage) noexcept;
130
131} // 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 336f53700..28fcb21a0 100644
--- a/src/video_core/vulkan_common/vulkan_wrapper.cpp
+++ b/src/video_core/vulkan_common/vulkan_wrapper.cpp
@@ -12,6 +12,8 @@
12 12
13#include "video_core/vulkan_common/vulkan_wrapper.h" 13#include "video_core/vulkan_common/vulkan_wrapper.h"
14 14
15#include <vk_mem_alloc.h>
16
15namespace Vulkan::vk { 17namespace Vulkan::vk {
16 18
17namespace { 19namespace {
@@ -547,24 +549,40 @@ DebugUtilsMessenger Instance::CreateDebugUtilsMessenger(
547 return DebugUtilsMessenger(object, handle, *dld); 549 return DebugUtilsMessenger(object, handle, *dld);
548} 550}
549 551
550void Buffer::BindMemory(VkDeviceMemory memory, VkDeviceSize offset) const { 552void Image::SetObjectNameEXT(const char* name) const {
551 Check(dld->vkBindBufferMemory(owner, handle, memory, offset)); 553 SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_IMAGE, name);
552} 554}
553 555
554void Buffer::SetObjectNameEXT(const char* name) const { 556void Image::Release() const noexcept {
555 SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_BUFFER, name); 557 if (handle) {
558 vmaDestroyImage(allocator, handle, allocation);
559 }
556} 560}
557 561
558void BufferView::SetObjectNameEXT(const char* name) const { 562void Buffer::Flush() const {
559 SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_BUFFER_VIEW, name); 563 if (!is_coherent) {
564 vmaFlushAllocation(allocator, allocation, 0, VK_WHOLE_SIZE);
565 }
560} 566}
561 567
562void Image::BindMemory(VkDeviceMemory memory, VkDeviceSize offset) const { 568void Buffer::Invalidate() const {
563 Check(dld->vkBindImageMemory(owner, handle, memory, offset)); 569 if (!is_coherent) {
570 vmaInvalidateAllocation(allocator, allocation, 0, VK_WHOLE_SIZE);
571 }
564} 572}
565 573
566void Image::SetObjectNameEXT(const char* name) const { 574void Buffer::SetObjectNameEXT(const char* name) const {
567 SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_IMAGE, name); 575 SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_BUFFER, name);
576}
577
578void Buffer::Release() const noexcept {
579 if (handle) {
580 vmaDestroyBuffer(allocator, handle, allocation);
581 }
582}
583
584void BufferView::SetObjectNameEXT(const char* name) const {
585 SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_BUFFER_VIEW, name);
568} 586}
569 587
570void ImageView::SetObjectNameEXT(const char* name) const { 588void ImageView::SetObjectNameEXT(const char* name) const {
@@ -701,24 +719,12 @@ Queue Device::GetQueue(u32 family_index) const noexcept {
701 return Queue(queue, *dld); 719 return Queue(queue, *dld);
702} 720}
703 721
704Buffer Device::CreateBuffer(const VkBufferCreateInfo& ci) const {
705 VkBuffer object;
706 Check(dld->vkCreateBuffer(handle, &ci, nullptr, &object));
707 return Buffer(object, handle, *dld);
708}
709
710BufferView Device::CreateBufferView(const VkBufferViewCreateInfo& ci) const { 722BufferView Device::CreateBufferView(const VkBufferViewCreateInfo& ci) const {
711 VkBufferView object; 723 VkBufferView object;
712 Check(dld->vkCreateBufferView(handle, &ci, nullptr, &object)); 724 Check(dld->vkCreateBufferView(handle, &ci, nullptr, &object));
713 return BufferView(object, handle, *dld); 725 return BufferView(object, handle, *dld);
714} 726}
715 727
716Image Device::CreateImage(const VkImageCreateInfo& ci) const {
717 VkImage object;
718 Check(dld->vkCreateImage(handle, &ci, nullptr, &object));
719 return Image(object, handle, *dld);
720}
721
722ImageView Device::CreateImageView(const VkImageViewCreateInfo& ci) const { 728ImageView Device::CreateImageView(const VkImageViewCreateInfo& ci) const {
723 VkImageView object; 729 VkImageView object;
724 Check(dld->vkCreateImageView(handle, &ci, nullptr, &object)); 730 Check(dld->vkCreateImageView(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 4ff328a21..44fce47a5 100644
--- a/src/video_core/vulkan_common/vulkan_wrapper.h
+++ b/src/video_core/vulkan_common/vulkan_wrapper.h
@@ -32,6 +32,9 @@
32#pragma warning(disable : 26812) // Disable prefer enum class over enum 32#pragma warning(disable : 26812) // Disable prefer enum class over enum
33#endif 33#endif
34 34
35VK_DEFINE_HANDLE(VmaAllocator)
36VK_DEFINE_HANDLE(VmaAllocation)
37
35namespace Vulkan::vk { 38namespace Vulkan::vk {
36 39
37/** 40/**
@@ -616,6 +619,138 @@ public:
616 } 619 }
617}; 620};
618 621
622class Image {
623public:
624 explicit Image(VkImage handle_, VkDevice owner_, VmaAllocator allocator_,
625 VmaAllocation allocation_, const DeviceDispatch& dld_) noexcept
626 : handle{handle_}, owner{owner_}, allocator{allocator_},
627 allocation{allocation_}, dld{&dld_} {}
628 Image() = default;
629
630 Image(const Image&) = delete;
631 Image& operator=(const Image&) = delete;
632
633 Image(Image&& rhs) noexcept
634 : handle{std::exchange(rhs.handle, nullptr)}, owner{rhs.owner}, allocator{rhs.allocator},
635 allocation{rhs.allocation}, dld{rhs.dld} {}
636
637 Image& operator=(Image&& rhs) noexcept {
638 Release();
639 handle = std::exchange(rhs.handle, nullptr);
640 owner = rhs.owner;
641 allocator = rhs.allocator;
642 allocation = rhs.allocation;
643 dld = rhs.dld;
644 return *this;
645 }
646
647 ~Image() noexcept {
648 Release();
649 }
650
651 VkImage operator*() const noexcept {
652 return handle;
653 }
654
655 void reset() noexcept {
656 Release();
657 handle = nullptr;
658 }
659
660 explicit operator bool() const noexcept {
661 return handle != nullptr;
662 }
663
664 void SetObjectNameEXT(const char* name) const;
665
666private:
667 void Release() const noexcept;
668
669 VkImage handle = nullptr;
670 VkDevice owner = nullptr;
671 VmaAllocator allocator = nullptr;
672 VmaAllocation allocation = nullptr;
673 const DeviceDispatch* dld = nullptr;
674};
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
619class Queue { 754class Queue {
620public: 755public:
621 /// Construct an empty queue handle. 756 /// Construct an empty queue handle.
@@ -639,17 +774,6 @@ private:
639 const DeviceDispatch* dld = nullptr; 774 const DeviceDispatch* dld = nullptr;
640}; 775};
641 776
642class Buffer : public Handle<VkBuffer, VkDevice, DeviceDispatch> {
643 using Handle<VkBuffer, VkDevice, DeviceDispatch>::Handle;
644
645public:
646 /// Attaches a memory allocation.
647 void BindMemory(VkDeviceMemory memory, VkDeviceSize offset) const;
648
649 /// Set object name.
650 void SetObjectNameEXT(const char* name) const;
651};
652
653class BufferView : public Handle<VkBufferView, VkDevice, DeviceDispatch> { 777class BufferView : public Handle<VkBufferView, VkDevice, DeviceDispatch> {
654 using Handle<VkBufferView, VkDevice, DeviceDispatch>::Handle; 778 using Handle<VkBufferView, VkDevice, DeviceDispatch>::Handle;
655 779
@@ -658,17 +782,6 @@ public:
658 void SetObjectNameEXT(const char* name) const; 782 void SetObjectNameEXT(const char* name) const;
659}; 783};
660 784
661class Image : public Handle<VkImage, VkDevice, DeviceDispatch> {
662 using Handle<VkImage, VkDevice, DeviceDispatch>::Handle;
663
664public:
665 /// Attaches a memory allocation.
666 void BindMemory(VkDeviceMemory memory, VkDeviceSize offset) const;
667
668 /// Set object name.
669 void SetObjectNameEXT(const char* name) const;
670};
671
672class ImageView : public Handle<VkImageView, VkDevice, DeviceDispatch> { 785class ImageView : public Handle<VkImageView, VkDevice, DeviceDispatch> {
673 using Handle<VkImageView, VkDevice, DeviceDispatch>::Handle; 786 using Handle<VkImageView, VkDevice, DeviceDispatch>::Handle;
674 787
@@ -840,12 +953,8 @@ public:
840 953
841 Queue GetQueue(u32 family_index) const noexcept; 954 Queue GetQueue(u32 family_index) const noexcept;
842 955
843 Buffer CreateBuffer(const VkBufferCreateInfo& ci) const;
844
845 BufferView CreateBufferView(const VkBufferViewCreateInfo& ci) const; 956 BufferView CreateBufferView(const VkBufferViewCreateInfo& ci) const;
846 957
847 Image CreateImage(const VkImageCreateInfo& ci) const;
848
849 ImageView CreateImageView(const VkImageViewCreateInfo& ci) const; 958 ImageView CreateImageView(const VkImageViewCreateInfo& ci) const;
850 959
851 Semaphore CreateSemaphore() const; 960 Semaphore CreateSemaphore() const;