summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/video_core/vulkan_common/vulkan_memory_allocator.cpp67
-rw-r--r--src/video_core/vulkan_common/vulkan_memory_allocator.h7
2 files changed, 43 insertions, 31 deletions
diff --git a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp
index fa37aa79a..5edd06ebc 100644
--- a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp
+++ b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp
@@ -53,6 +53,18 @@ struct Range {
53 UNREACHABLE_MSG("Invalid memory usage={}", usage); 53 UNREACHABLE_MSG("Invalid memory usage={}", usage);
54 return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; 54 return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
55} 55}
56
57constexpr VkExportMemoryAllocateInfo EXPORT_ALLOCATE_INFO{
58 .sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO,
59 .pNext = nullptr,
60#ifdef _WIN32
61 .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT,
62#elif __unix__
63 .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT,
64#else
65 .handleTypes = 0,
66#endif
67};
56} // Anonymous namespace 68} // Anonymous namespace
57 69
58class MemoryAllocation { 70class MemoryAllocation {
@@ -131,7 +143,7 @@ public:
131 143
132 /// Returns whether this allocation is compatible with the arguments. 144 /// Returns whether this allocation is compatible with the arguments.
133 [[nodiscard]] bool IsCompatible(VkMemoryPropertyFlags flags, u32 type_mask) const { 145 [[nodiscard]] bool IsCompatible(VkMemoryPropertyFlags flags, u32 type_mask) const {
134 return (flags & property_flags) && (type_mask & shifted_memory_type) != 0; 146 return (flags & property_flags) == property_flags && (type_mask & shifted_memory_type) != 0;
135 } 147 }
136 148
137private: 149private:
@@ -217,14 +229,18 @@ MemoryAllocator::~MemoryAllocator() = default;
217 229
218MemoryCommit MemoryAllocator::Commit(const VkMemoryRequirements& requirements, MemoryUsage usage) { 230MemoryCommit MemoryAllocator::Commit(const VkMemoryRequirements& requirements, MemoryUsage usage) {
219 // Find the fastest memory flags we can afford with the current requirements 231 // Find the fastest memory flags we can afford with the current requirements
220 const VkMemoryPropertyFlags flags = MemoryPropertyFlags(requirements.memoryTypeBits, usage); 232 const u32 type_mask = requirements.memoryTypeBits;
233 const VkMemoryPropertyFlags usage_flags = MemoryUsagePropertyFlags(usage);
234 const VkMemoryPropertyFlags flags = MemoryPropertyFlags(type_mask, usage_flags);
221 if (std::optional<MemoryCommit> commit = TryCommit(requirements, flags)) { 235 if (std::optional<MemoryCommit> commit = TryCommit(requirements, flags)) {
222 return std::move(*commit); 236 return std::move(*commit);
223 } 237 }
224 // Commit has failed, allocate more memory. 238 // Commit has failed, allocate more memory.
225 // TODO(Rodrigo): Handle out of memory situations in some way like flushing to guest memory. 239 const u64 chunk_size = AllocationChunkSize(requirements.size);
226 AllocMemory(flags, requirements.memoryTypeBits, AllocationChunkSize(requirements.size)); 240 if (!TryAllocMemory(flags, type_mask, chunk_size)) {
227 241 // TODO(Rodrigo): Handle out of memory situations in some way like flushing to guest memory.
242 throw vk::Exception(VK_ERROR_OUT_OF_DEVICE_MEMORY);
243 }
228 // Commit again, this time it won't fail since there's a fresh allocation above. 244 // Commit again, this time it won't fail since there's a fresh allocation above.
229 // If it does, there's a bug. 245 // If it does, there's a bug.
230 return TryCommit(requirements, flags).value(); 246 return TryCommit(requirements, flags).value();
@@ -242,26 +258,25 @@ MemoryCommit MemoryAllocator::Commit(const vk::Image& image, MemoryUsage usage)
242 return commit; 258 return commit;
243} 259}
244 260
245void MemoryAllocator::AllocMemory(VkMemoryPropertyFlags flags, u32 type_mask, u64 size) { 261bool MemoryAllocator::TryAllocMemory(VkMemoryPropertyFlags flags, u32 type_mask, u64 size) {
246 const u32 type = FindType(flags, type_mask).value(); 262 const u32 type = FindType(flags, type_mask).value();
247 const VkExportMemoryAllocateInfo export_allocate_info{ 263 vk::DeviceMemory memory = device.GetLogical().TryAllocateMemory({
248 .sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO,
249 .pNext = nullptr,
250#ifdef _WIN32
251 .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT,
252#elif __unix__
253 .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT,
254#else
255 .handleTypes = 0,
256#endif
257 };
258 vk::DeviceMemory memory = device.GetLogical().AllocateMemory({
259 .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, 264 .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
260 .pNext = export_allocations ? &export_allocate_info : nullptr, 265 .pNext = export_allocations ? &EXPORT_ALLOCATE_INFO : nullptr,
261 .allocationSize = size, 266 .allocationSize = size,
262 .memoryTypeIndex = type, 267 .memoryTypeIndex = type,
263 }); 268 });
269 if (!memory) {
270 if ((flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) != 0) {
271 // Try to allocate non device local memory
272 return TryAllocMemory(flags & ~VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, type_mask, size);
273 } else {
274 // RIP
275 return false;
276 }
277 }
264 allocations.push_back(std::make_unique<MemoryAllocation>(std::move(memory), flags, size, type)); 278 allocations.push_back(std::make_unique<MemoryAllocation>(std::move(memory), flags, size, type));
279 return true;
265} 280}
266 281
267std::optional<MemoryCommit> MemoryAllocator::TryCommit(const VkMemoryRequirements& requirements, 282std::optional<MemoryCommit> MemoryAllocator::TryCommit(const VkMemoryRequirements& requirements,
@@ -274,24 +289,24 @@ std::optional<MemoryCommit> MemoryAllocator::TryCommit(const VkMemoryRequirement
274 return commit; 289 return commit;
275 } 290 }
276 } 291 }
292 if ((flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) != 0) {
293 // Look for non device local commits on failure
294 return TryCommit(requirements, flags & ~VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
295 }
277 return std::nullopt; 296 return std::nullopt;
278} 297}
279 298
280VkMemoryPropertyFlags MemoryAllocator::MemoryPropertyFlags(u32 type_mask, MemoryUsage usage) const {
281 return MemoryPropertyFlags(type_mask, MemoryUsagePropertyFlags(usage));
282}
283
284VkMemoryPropertyFlags MemoryAllocator::MemoryPropertyFlags(u32 type_mask, 299VkMemoryPropertyFlags MemoryAllocator::MemoryPropertyFlags(u32 type_mask,
285 VkMemoryPropertyFlags flags) const { 300 VkMemoryPropertyFlags flags) const {
286 if (FindType(flags, type_mask)) { 301 if (FindType(flags, type_mask)) {
287 // Found a memory type with those requirements 302 // Found a memory type with those requirements
288 return flags; 303 return flags;
289 } 304 }
290 if (flags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) { 305 if ((flags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) != 0) {
291 // Remove host cached bit in case it's not supported 306 // Remove host cached bit in case it's not supported
292 return MemoryPropertyFlags(type_mask, flags & ~VK_MEMORY_PROPERTY_HOST_CACHED_BIT); 307 return MemoryPropertyFlags(type_mask, flags & ~VK_MEMORY_PROPERTY_HOST_CACHED_BIT);
293 } 308 }
294 if (flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) { 309 if ((flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) != 0) {
295 // Remove device local, if it's not supported by the requested resource 310 // Remove device local, if it's not supported by the requested resource
296 return MemoryPropertyFlags(type_mask, flags & ~VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); 311 return MemoryPropertyFlags(type_mask, flags & ~VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
297 } 312 }
@@ -302,7 +317,7 @@ VkMemoryPropertyFlags MemoryAllocator::MemoryPropertyFlags(u32 type_mask,
302std::optional<u32> MemoryAllocator::FindType(VkMemoryPropertyFlags flags, u32 type_mask) const { 317std::optional<u32> MemoryAllocator::FindType(VkMemoryPropertyFlags flags, u32 type_mask) const {
303 for (u32 type_index = 0; type_index < properties.memoryTypeCount; ++type_index) { 318 for (u32 type_index = 0; type_index < properties.memoryTypeCount; ++type_index) {
304 const VkMemoryPropertyFlags type_flags = properties.memoryTypes[type_index].propertyFlags; 319 const VkMemoryPropertyFlags type_flags = properties.memoryTypes[type_index].propertyFlags;
305 if ((type_mask & (1U << type_index)) && (type_flags & flags)) { 320 if ((type_mask & (1U << type_index)) != 0 && (type_flags & flags) == flags) {
306 // The type matches in type and in the wanted properties. 321 // The type matches in type and in the wanted properties.
307 return type_index; 322 return type_index;
308 } 323 }
diff --git a/src/video_core/vulkan_common/vulkan_memory_allocator.h b/src/video_core/vulkan_common/vulkan_memory_allocator.h
index d1ce29450..db12d02f4 100644
--- a/src/video_core/vulkan_common/vulkan_memory_allocator.h
+++ b/src/video_core/vulkan_common/vulkan_memory_allocator.h
@@ -101,16 +101,13 @@ public:
101 MemoryCommit Commit(const vk::Image& image, MemoryUsage usage); 101 MemoryCommit Commit(const vk::Image& image, MemoryUsage usage);
102 102
103private: 103private:
104 /// Allocates a chunk of memory. 104 /// Tries to allocate a chunk of memory.
105 void AllocMemory(VkMemoryPropertyFlags flags, u32 type_mask, u64 size); 105 bool TryAllocMemory(VkMemoryPropertyFlags flags, u32 type_mask, u64 size);
106 106
107 /// Tries to allocate a memory commit. 107 /// Tries to allocate a memory commit.
108 std::optional<MemoryCommit> TryCommit(const VkMemoryRequirements& requirements, 108 std::optional<MemoryCommit> TryCommit(const VkMemoryRequirements& requirements,
109 VkMemoryPropertyFlags flags); 109 VkMemoryPropertyFlags flags);
110 110
111 /// Returns the fastest compatible memory property flags from a wanted usage.
112 VkMemoryPropertyFlags MemoryPropertyFlags(u32 type_mask, MemoryUsage usage) const;
113
114 /// Returns the fastest compatible memory property flags from the wanted flags. 111 /// Returns the fastest compatible memory property flags from the wanted flags.
115 VkMemoryPropertyFlags MemoryPropertyFlags(u32 type_mask, VkMemoryPropertyFlags flags) const; 112 VkMemoryPropertyFlags MemoryPropertyFlags(u32 type_mask, VkMemoryPropertyFlags flags) const;
116 113