summaryrefslogtreecommitdiff
path: root/src/video_core/vulkan_common
diff options
context:
space:
mode:
authorGravatar GPUCode2023-05-27 17:09:17 +0300
committerGravatar GPUCode2023-06-18 12:45:18 +0300
commit7b2f680468bbac206f96b26a1300939be90f5f1b (patch)
treec8f506462c6d2b577ab0273e50c530fd7c71abbc /src/video_core/vulkan_common
parentrenderer_vulkan: Use VMA for images (diff)
downloadyuzu-7b2f680468bbac206f96b26a1300939be90f5f1b.tar.gz
yuzu-7b2f680468bbac206f96b26a1300939be90f5f1b.tar.xz
yuzu-7b2f680468bbac206f96b26a1300939be90f5f1b.zip
renderer_vulkan: Use VMA for buffers
Diffstat (limited to 'src/video_core/vulkan_common')
-rw-r--r--src/video_core/vulkan_common/vulkan_device.cpp1
-rw-r--r--src/video_core/vulkan_common/vulkan_memory_allocator.cpp107
-rw-r--r--src/video_core/vulkan_common/vulkan_memory_allocator.h12
-rw-r--r--src/video_core/vulkan_common/vulkan_wrapper.cpp24
-rw-r--r--src/video_core/vulkan_common/vulkan_wrapper.h91
5 files changed, 186 insertions, 49 deletions
diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp
index 631d5e378..541f0c1da 100644
--- a/src/video_core/vulkan_common/vulkan_device.cpp
+++ b/src/video_core/vulkan_common/vulkan_device.cpp
@@ -603,6 +603,7 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
603 }; 603 };
604 604
605 const VmaAllocatorCreateInfo allocator_info = { 605 const VmaAllocatorCreateInfo allocator_info = {
606 .flags = VMA_ALLOCATOR_CREATE_EXTERNALLY_SYNCHRONIZED_BIT,
606 .physicalDevice = physical, 607 .physicalDevice = physical,
607 .device = *logical, 608 .device = *logical,
608 .pVulkanFunctions = &functions, 609 .pVulkanFunctions = &functions,
diff --git a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp
index 7f860cccd..d2e1ef58e 100644
--- a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp
+++ b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp
@@ -51,11 +51,59 @@ struct Range {
51 case MemoryUsage::Download: 51 case MemoryUsage::Download:
52 return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | 52 return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT |
53 VK_MEMORY_PROPERTY_HOST_CACHED_BIT; 53 VK_MEMORY_PROPERTY_HOST_CACHED_BIT;
54 case MemoryUsage::Stream:
55 return VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
56 VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
54 } 57 }
55 ASSERT_MSG(false, "Invalid memory usage={}", usage); 58 ASSERT_MSG(false, "Invalid memory usage={}", usage);
56 return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; 59 return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
57} 60}
58 61
62[[nodiscard]] VkMemoryPropertyFlags MemoryUsageRequiredVmaFlags(MemoryUsage usage) {
63 switch (usage) {
64 case MemoryUsage::DeviceLocal:
65 return VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
66 case MemoryUsage::Upload:
67 case MemoryUsage::Stream:
68 return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
69 case MemoryUsage::Download:
70 return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT;
71 }
72 ASSERT_MSG(false, "Invalid memory usage={}", usage);
73 return {};
74}
75
76[[nodiscard]] VkMemoryPropertyFlags MemoryUsagePreferedVmaFlags(MemoryUsage usage) {
77 return usage != MemoryUsage::DeviceLocal ? VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
78 : VkMemoryPropertyFlags{};
79}
80
81[[nodiscard]] VmaAllocationCreateFlags MemoryUsageVmaFlags(MemoryUsage usage) {
82 switch (usage) {
83 case MemoryUsage::Upload:
84 case MemoryUsage::Stream:
85 return VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT;
86 case MemoryUsage::Download:
87 return VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT;
88 case MemoryUsage::DeviceLocal:
89 return VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT |
90 VMA_ALLOCATION_CREATE_HOST_ACCESS_ALLOW_TRANSFER_INSTEAD_BIT;
91 }
92 return {};
93}
94
95[[nodiscard]] VmaMemoryUsage MemoryUsageVma(MemoryUsage usage) {
96 switch (usage) {
97 case MemoryUsage::DeviceLocal:
98 case MemoryUsage::Stream:
99 return VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE;
100 case MemoryUsage::Upload:
101 case MemoryUsage::Download:
102 return VMA_MEMORY_USAGE_AUTO_PREFER_HOST;
103 }
104 return VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE;
105}
106
59} // Anonymous namespace 107} // Anonymous namespace
60 108
61class MemoryAllocation { 109class MemoryAllocation {
@@ -178,17 +226,18 @@ void MemoryCommit::Release() {
178} 226}
179 227
180MemoryAllocator::MemoryAllocator(const Device& device_) 228MemoryAllocator::MemoryAllocator(const Device& device_)
181 : device{device_}, properties{device_.GetPhysical().GetMemoryProperties().memoryProperties}, 229 : device{device_}, allocator{device.GetAllocator()},
230 properties{device_.GetPhysical().GetMemoryProperties().memoryProperties},
182 buffer_image_granularity{ 231 buffer_image_granularity{
183 device_.GetPhysical().GetProperties().limits.bufferImageGranularity} {} 232 device_.GetPhysical().GetProperties().limits.bufferImageGranularity} {}
184 233
185MemoryAllocator::~MemoryAllocator() = default; 234MemoryAllocator::~MemoryAllocator() = default;
186 235
187vk::Image MemoryAllocator::CreateImage(const VkImageCreateInfo& ci) const { 236vk::Image MemoryAllocator::CreateImage(const VkImageCreateInfo& ci) const {
188 const VmaAllocationCreateInfo alloc_info = { 237 const VmaAllocationCreateInfo alloc_ci = {
189 .flags = VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT, 238 .flags = VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT,
190 .usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE, 239 .usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE,
191 .requiredFlags = 0, 240 .requiredFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
192 .preferredFlags = 0, 241 .preferredFlags = 0,
193 .pool = VK_NULL_HANDLE, 242 .pool = VK_NULL_HANDLE,
194 .pUserData = nullptr, 243 .pUserData = nullptr,
@@ -196,12 +245,40 @@ vk::Image MemoryAllocator::CreateImage(const VkImageCreateInfo& ci) const {
196 245
197 VkImage handle{}; 246 VkImage handle{};
198 VmaAllocation allocation{}; 247 VmaAllocation allocation{};
199 vk::Check( 248
200 vmaCreateImage(device.GetAllocator(), &ci, &alloc_info, &handle, &allocation, nullptr)); 249 vk::Check(vmaCreateImage(allocator, &ci, &alloc_ci, &handle, &allocation, nullptr));
201 return vk::Image(handle, *device.GetLogical(), device.GetAllocator(), allocation, 250
251 return vk::Image(handle, *device.GetLogical(), allocator, allocation,
202 device.GetDispatchLoader()); 252 device.GetDispatchLoader());
203} 253}
204 254
255vk::Buffer MemoryAllocator::CreateBuffer(const VkBufferCreateInfo& ci, MemoryUsage usage) const {
256 const VmaAllocationCreateInfo alloc_ci = {
257 .flags = VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT |
258 MemoryUsageVmaFlags(usage),
259 .usage = MemoryUsageVma(usage),
260 .requiredFlags = MemoryUsageRequiredVmaFlags(usage),
261 .preferredFlags = MemoryUsagePreferedVmaFlags(usage),
262 .pool = VK_NULL_HANDLE,
263 .pUserData = nullptr,
264 };
265
266 VkBuffer handle{};
267 VmaAllocationInfo alloc_info{};
268 VmaAllocation allocation{};
269 VkMemoryPropertyFlags property_flags{};
270
271 vk::Check(vmaCreateBuffer(allocator, &ci, &alloc_ci, &handle, &allocation, &alloc_info));
272 vmaGetAllocationMemoryProperties(allocator, allocation, &property_flags);
273
274 u8* data = reinterpret_cast<u8*>(alloc_info.pMappedData);
275 const std::span<u8> mapped_data = data ? std::span<u8>{data, ci.size} : std::span<u8>{};
276 const bool is_coherent = property_flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
277
278 return vk::Buffer(handle, *device.GetLogical(), allocator, allocation, mapped_data, is_coherent,
279 device.GetDispatchLoader());
280}
281
205MemoryCommit MemoryAllocator::Commit(const VkMemoryRequirements& requirements, MemoryUsage usage) { 282MemoryCommit MemoryAllocator::Commit(const VkMemoryRequirements& requirements, MemoryUsage usage) {
206 // Find the fastest memory flags we can afford with the current requirements 283 // Find the fastest memory flags we can afford with the current requirements
207 const u32 type_mask = requirements.memoryTypeBits; 284 const u32 type_mask = requirements.memoryTypeBits;
@@ -221,12 +298,6 @@ MemoryCommit MemoryAllocator::Commit(const VkMemoryRequirements& requirements, M
221 return TryCommit(requirements, flags).value(); 298 return TryCommit(requirements, flags).value();
222} 299}
223 300
224MemoryCommit MemoryAllocator::Commit(const vk::Buffer& buffer, MemoryUsage usage) {
225 auto commit = Commit(device.GetLogical().GetBufferMemoryRequirements(*buffer), usage);
226 buffer.BindMemory(commit.Memory(), commit.Offset());
227 return commit;
228}
229
230bool MemoryAllocator::TryAllocMemory(VkMemoryPropertyFlags flags, u32 type_mask, u64 size) { 301bool MemoryAllocator::TryAllocMemory(VkMemoryPropertyFlags flags, u32 type_mask, u64 size) {
231 const u32 type = FindType(flags, type_mask).value(); 302 const u32 type = FindType(flags, type_mask).value();
232 vk::DeviceMemory memory = device.GetLogical().TryAllocateMemory({ 303 vk::DeviceMemory memory = device.GetLogical().TryAllocateMemory({
@@ -302,16 +373,4 @@ std::optional<u32> MemoryAllocator::FindType(VkMemoryPropertyFlags flags, u32 ty
302 return std::nullopt; 373 return std::nullopt;
303} 374}
304 375
305bool IsHostVisible(MemoryUsage usage) noexcept {
306 switch (usage) {
307 case MemoryUsage::DeviceLocal:
308 return false;
309 case MemoryUsage::Upload:
310 case MemoryUsage::Download:
311 return true;
312 }
313 ASSERT_MSG(false, "Invalid memory usage={}", usage);
314 return false;
315}
316
317} // namespace Vulkan 376} // namespace Vulkan
diff --git a/src/video_core/vulkan_common/vulkan_memory_allocator.h b/src/video_core/vulkan_common/vulkan_memory_allocator.h
index f9ee53cfb..f449bc8d0 100644
--- a/src/video_core/vulkan_common/vulkan_memory_allocator.h
+++ b/src/video_core/vulkan_common/vulkan_memory_allocator.h
@@ -9,6 +9,8 @@
9#include "common/common_types.h" 9#include "common/common_types.h"
10#include "video_core/vulkan_common/vulkan_wrapper.h" 10#include "video_core/vulkan_common/vulkan_wrapper.h"
11 11
12VK_DEFINE_HANDLE(VmaAllocator)
13
12namespace Vulkan { 14namespace Vulkan {
13 15
14class Device; 16class Device;
@@ -17,9 +19,11 @@ class MemoryAllocation;
17 19
18/// Hints and requirements for the backing memory type of a commit 20/// Hints and requirements for the backing memory type of a commit
19enum class MemoryUsage { 21enum class MemoryUsage {
20 DeviceLocal, ///< Hints device local usages, fastest memory type to read and write from the GPU 22 DeviceLocal, ///< Requests device local host visible buffer, falling back to device local
23 ///< memory.
21 Upload, ///< Requires a host visible memory type optimized for CPU to GPU uploads 24 Upload, ///< Requires a host visible memory type optimized for CPU to GPU uploads
22 Download, ///< Requires a host visible memory type optimized for GPU to CPU readbacks 25 Download, ///< Requires a host visible memory type optimized for GPU to CPU readbacks
26 Stream, ///< Requests device local host visible buffer, falling back host memory.
23}; 27};
24 28
25/// Ownership handle of a memory commitment. 29/// Ownership handle of a memory commitment.
@@ -82,6 +86,8 @@ public:
82 86
83 vk::Image CreateImage(const VkImageCreateInfo& ci) const; 87 vk::Image CreateImage(const VkImageCreateInfo& ci) const;
84 88
89 vk::Buffer CreateBuffer(const VkBufferCreateInfo& ci, MemoryUsage usage) const;
90
85 /** 91 /**
86 * Commits a memory with the specified requirements. 92 * Commits a memory with the specified requirements.
87 * 93 *
@@ -113,13 +119,11 @@ private:
113 std::optional<u32> FindType(VkMemoryPropertyFlags flags, u32 type_mask) const; 119 std::optional<u32> FindType(VkMemoryPropertyFlags flags, u32 type_mask) const;
114 120
115 const Device& device; ///< Device handle. 121 const Device& device; ///< Device handle.
122 VmaAllocator allocator; ///< Vma allocator.
116 const VkPhysicalDeviceMemoryProperties properties; ///< Physical device properties. 123 const VkPhysicalDeviceMemoryProperties properties; ///< Physical device properties.
117 std::vector<std::unique_ptr<MemoryAllocation>> allocations; ///< Current allocations. 124 std::vector<std::unique_ptr<MemoryAllocation>> allocations; ///< Current allocations.
118 VkDeviceSize buffer_image_granularity; // The granularity for adjacent offsets between buffers 125 VkDeviceSize buffer_image_granularity; // The granularity for adjacent offsets between buffers
119 // and optimal images 126 // and optimal images
120}; 127};
121 128
122/// Returns true when a memory usage is guaranteed to be host visible.
123bool IsHostVisible(MemoryUsage usage) noexcept;
124
125} // namespace Vulkan 129} // namespace Vulkan
diff --git a/src/video_core/vulkan_common/vulkan_wrapper.cpp b/src/video_core/vulkan_common/vulkan_wrapper.cpp
index 5d088dc58..c01a9478e 100644
--- a/src/video_core/vulkan_common/vulkan_wrapper.cpp
+++ b/src/video_core/vulkan_common/vulkan_wrapper.cpp
@@ -561,14 +561,28 @@ void Image::Release() const noexcept {
561 } 561 }
562} 562}
563 563
564void Buffer::BindMemory(VkDeviceMemory memory, VkDeviceSize offset) const { 564void Buffer::Flush() const {
565 Check(dld->vkBindBufferMemory(owner, handle, memory, offset)); 565 if (!is_coherent) {
566 vmaFlushAllocation(allocator, allocation, 0, VK_WHOLE_SIZE);
567 }
568}
569
570void Buffer::Invalidate() const {
571 if (!is_coherent) {
572 vmaInvalidateAllocation(allocator, allocation, 0, VK_WHOLE_SIZE);
573 }
566} 574}
567 575
568void Buffer::SetObjectNameEXT(const char* name) const { 576void Buffer::SetObjectNameEXT(const char* name) const {
569 SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_BUFFER, name); 577 SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_BUFFER, name);
570} 578}
571 579
580void Buffer::Release() const noexcept {
581 if (handle) {
582 vmaDestroyBuffer(allocator, handle, allocation);
583 }
584}
585
572void BufferView::SetObjectNameEXT(const char* name) const { 586void BufferView::SetObjectNameEXT(const char* name) const {
573 SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_BUFFER_VIEW, name); 587 SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_BUFFER_VIEW, name);
574} 588}
@@ -707,12 +721,6 @@ Queue Device::GetQueue(u32 family_index) const noexcept {
707 return Queue(queue, *dld); 721 return Queue(queue, *dld);
708} 722}
709 723
710Buffer Device::CreateBuffer(const VkBufferCreateInfo& ci) const {
711 VkBuffer object;
712 Check(dld->vkCreateBuffer(handle, &ci, nullptr, &object));
713 return Buffer(object, handle, *dld);
714}
715
716BufferView Device::CreateBufferView(const VkBufferViewCreateInfo& ci) const { 724BufferView Device::CreateBufferView(const VkBufferViewCreateInfo& ci) const {
717 VkBufferView object; 725 VkBufferView object;
718 Check(dld->vkCreateBufferView(handle, &ci, nullptr, &object)); 726 Check(dld->vkCreateBufferView(handle, &ci, nullptr, &object));
diff --git a/src/video_core/vulkan_common/vulkan_wrapper.h b/src/video_core/vulkan_common/vulkan_wrapper.h
index 8ec708774..44fce47a5 100644
--- a/src/video_core/vulkan_common/vulkan_wrapper.h
+++ b/src/video_core/vulkan_common/vulkan_wrapper.h
@@ -673,6 +673,84 @@ private:
673 const DeviceDispatch* dld = nullptr; 673 const DeviceDispatch* dld = nullptr;
674}; 674};
675 675
676class Buffer {
677public:
678 explicit Buffer(VkBuffer handle_, VkDevice owner_, VmaAllocator allocator_,
679 VmaAllocation allocation_, std::span<u8> mapped_, bool is_coherent_,
680 const DeviceDispatch& dld_) noexcept
681 : handle{handle_}, owner{owner_}, allocator{allocator_},
682 allocation{allocation_}, mapped{mapped_}, is_coherent{is_coherent_}, dld{&dld_} {}
683 Buffer() = default;
684
685 Buffer(const Buffer&) = delete;
686 Buffer& operator=(const Buffer&) = delete;
687
688 Buffer(Buffer&& rhs) noexcept
689 : handle{std::exchange(rhs.handle, nullptr)}, owner{rhs.owner}, allocator{rhs.allocator},
690 allocation{rhs.allocation}, mapped{rhs.mapped},
691 is_coherent{rhs.is_coherent}, dld{rhs.dld} {}
692
693 Buffer& operator=(Buffer&& rhs) noexcept {
694 Release();
695 handle = std::exchange(rhs.handle, nullptr);
696 owner = rhs.owner;
697 allocator = rhs.allocator;
698 allocation = rhs.allocation;
699 mapped = rhs.mapped;
700 is_coherent = rhs.is_coherent;
701 dld = rhs.dld;
702 return *this;
703 }
704
705 ~Buffer() noexcept {
706 Release();
707 }
708
709 VkBuffer operator*() const noexcept {
710 return handle;
711 }
712
713 void reset() noexcept {
714 Release();
715 handle = nullptr;
716 }
717
718 explicit operator bool() const noexcept {
719 return handle != nullptr;
720 }
721
722 /// Returns the host mapped memory, an empty span otherwise.
723 std::span<u8> Mapped() noexcept {
724 return mapped;
725 }
726
727 std::span<const u8> Mapped() const noexcept {
728 return mapped;
729 }
730
731 /// Returns true if the buffer is mapped to the host.
732 bool IsHostVisible() const noexcept {
733 return !mapped.empty();
734 }
735
736 void Flush() const;
737
738 void Invalidate() const;
739
740 void SetObjectNameEXT(const char* name) const;
741
742private:
743 void Release() const noexcept;
744
745 VkBuffer handle = nullptr;
746 VkDevice owner = nullptr;
747 VmaAllocator allocator = nullptr;
748 VmaAllocation allocation = nullptr;
749 std::span<u8> mapped = {};
750 bool is_coherent = false;
751 const DeviceDispatch* dld = nullptr;
752};
753
676class Queue { 754class Queue {
677public: 755public:
678 /// Construct an empty queue handle. 756 /// Construct an empty queue handle.
@@ -696,17 +774,6 @@ private:
696 const DeviceDispatch* dld = nullptr; 774 const DeviceDispatch* dld = nullptr;
697}; 775};
698 776
699class Buffer : public Handle<VkBuffer, VkDevice, DeviceDispatch> {
700 using Handle<VkBuffer, VkDevice, DeviceDispatch>::Handle;
701
702public:
703 /// Attaches a memory allocation.
704 void BindMemory(VkDeviceMemory memory, VkDeviceSize offset) const;
705
706 /// Set object name.
707 void SetObjectNameEXT(const char* name) const;
708};
709
710class BufferView : public Handle<VkBufferView, VkDevice, DeviceDispatch> { 777class BufferView : public Handle<VkBufferView, VkDevice, DeviceDispatch> {
711 using Handle<VkBufferView, VkDevice, DeviceDispatch>::Handle; 778 using Handle<VkBufferView, VkDevice, DeviceDispatch>::Handle;
712 779
@@ -886,8 +953,6 @@ public:
886 953
887 Queue GetQueue(u32 family_index) const noexcept; 954 Queue GetQueue(u32 family_index) const noexcept;
888 955
889 Buffer CreateBuffer(const VkBufferCreateInfo& ci) const;
890
891 BufferView CreateBufferView(const VkBufferViewCreateInfo& ci) const; 956 BufferView CreateBufferView(const VkBufferViewCreateInfo& ci) const;
892 957
893 ImageView CreateImageView(const VkImageViewCreateInfo& ci) const; 958 ImageView CreateImageView(const VkImageViewCreateInfo& ci) const;