summaryrefslogtreecommitdiff
path: root/src/video_core/vulkan_common
diff options
context:
space:
mode:
authorGravatar liamwhite2023-06-27 11:21:36 -0400
committerGravatar GitHub2023-06-27 11:21:36 -0400
commitc6959449d1e28f16d6eaf3a215f2bce5fab5ed0f (patch)
tree1ceac7222976e40bb12c3919cd3412d36b7ec93b /src/video_core/vulkan_common
parentMerge pull request #10495 from bm01/master (diff)
parentexternals: Use cmake subdirectory (diff)
downloadyuzu-c6959449d1e28f16d6eaf3a215f2bce5fab5ed0f.tar.gz
yuzu-c6959449d1e28f16d6eaf3a215f2bce5fab5ed0f.tar.xz
yuzu-c6959449d1e28f16d6eaf3a215f2bce5fab5ed0f.zip
Merge pull request #10473 from GPUCode/vma
Use vulkan memory allocator
Diffstat (limited to 'src/video_core/vulkan_common')
-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
6 files changed, 299 insertions, 147 deletions
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;