diff options
| -rw-r--r-- | src/video_core/vulkan_common/vulkan_device.cpp | 21 | ||||
| -rw-r--r-- | src/video_core/vulkan_common/vulkan_device.h | 4 | ||||
| -rw-r--r-- | src/video_core/vulkan_common/vulkan_memory_allocator.cpp | 78 | ||||
| -rw-r--r-- | src/video_core/vulkan_common/vulkan_memory_allocator.h | 18 |
4 files changed, 100 insertions, 21 deletions
diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp index 42a19d6fa..403257375 100644 --- a/src/video_core/vulkan_common/vulkan_device.cpp +++ b/src/video_core/vulkan_common/vulkan_device.cpp | |||
| @@ -34,7 +34,6 @@ constexpr std::array DEPTH16_UNORM_STENCIL8_UINT{ | |||
| 34 | } // namespace Alternatives | 34 | } // namespace Alternatives |
| 35 | 35 | ||
| 36 | constexpr std::array REQUIRED_EXTENSIONS{ | 36 | constexpr std::array REQUIRED_EXTENSIONS{ |
| 37 | VK_KHR_SWAPCHAIN_EXTENSION_NAME, | ||
| 38 | VK_KHR_MAINTENANCE1_EXTENSION_NAME, | 37 | VK_KHR_MAINTENANCE1_EXTENSION_NAME, |
| 39 | VK_KHR_STORAGE_BUFFER_STORAGE_CLASS_EXTENSION_NAME, | 38 | VK_KHR_STORAGE_BUFFER_STORAGE_CLASS_EXTENSION_NAME, |
| 40 | VK_KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME, | 39 | VK_KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME, |
| @@ -536,16 +535,18 @@ bool Device::IsFormatSupported(VkFormat wanted_format, VkFormatFeatureFlags want | |||
| 536 | return (supported_usage & wanted_usage) == wanted_usage; | 535 | return (supported_usage & wanted_usage) == wanted_usage; |
| 537 | } | 536 | } |
| 538 | 537 | ||
| 539 | void Device::CheckSuitability() const { | 538 | void Device::CheckSuitability(bool requires_swapchain) const { |
| 540 | std::bitset<REQUIRED_EXTENSIONS.size()> available_extensions; | 539 | std::bitset<REQUIRED_EXTENSIONS.size()> available_extensions; |
| 540 | bool has_swapchain = false; | ||
| 541 | for (const VkExtensionProperties& property : physical.EnumerateDeviceExtensionProperties()) { | 541 | for (const VkExtensionProperties& property : physical.EnumerateDeviceExtensionProperties()) { |
| 542 | for (std::size_t i = 0; i < REQUIRED_EXTENSIONS.size(); ++i) { | 542 | const std::string_view name{property.extensionName}; |
| 543 | for (size_t i = 0; i < REQUIRED_EXTENSIONS.size(); ++i) { | ||
| 543 | if (available_extensions[i]) { | 544 | if (available_extensions[i]) { |
| 544 | continue; | 545 | continue; |
| 545 | } | 546 | } |
| 546 | const std::string_view name{property.extensionName}; | ||
| 547 | available_extensions[i] = name == REQUIRED_EXTENSIONS[i]; | 547 | available_extensions[i] = name == REQUIRED_EXTENSIONS[i]; |
| 548 | } | 548 | } |
| 549 | has_swapchain = has_swapchain || name == VK_KHR_SWAPCHAIN_EXTENSION_NAME; | ||
| 549 | } | 550 | } |
| 550 | for (size_t i = 0; i < REQUIRED_EXTENSIONS.size(); ++i) { | 551 | for (size_t i = 0; i < REQUIRED_EXTENSIONS.size(); ++i) { |
| 551 | if (available_extensions[i]) { | 552 | if (available_extensions[i]) { |
| @@ -554,6 +555,11 @@ void Device::CheckSuitability() const { | |||
| 554 | LOG_ERROR(Render_Vulkan, "Missing required extension: {}", REQUIRED_EXTENSIONS[i]); | 555 | LOG_ERROR(Render_Vulkan, "Missing required extension: {}", REQUIRED_EXTENSIONS[i]); |
| 555 | throw vk::Exception(VK_ERROR_EXTENSION_NOT_PRESENT); | 556 | throw vk::Exception(VK_ERROR_EXTENSION_NOT_PRESENT); |
| 556 | } | 557 | } |
| 558 | if (requires_swapchain && !has_swapchain) { | ||
| 559 | LOG_ERROR(Render_Vulkan, "Missing required extension: VK_KHR_swapchain"); | ||
| 560 | throw vk::Exception(VK_ERROR_EXTENSION_NOT_PRESENT); | ||
| 561 | } | ||
| 562 | |||
| 557 | struct LimitTuple { | 563 | struct LimitTuple { |
| 558 | u32 minimum; | 564 | u32 minimum; |
| 559 | u32 value; | 565 | u32 value; |
| @@ -601,10 +607,13 @@ void Device::CheckSuitability() const { | |||
| 601 | } | 607 | } |
| 602 | } | 608 | } |
| 603 | 609 | ||
| 604 | std::vector<const char*> Device::LoadExtensions() { | 610 | std::vector<const char*> Device::LoadExtensions(bool requires_surface) { |
| 605 | std::vector<const char*> extensions; | 611 | std::vector<const char*> extensions; |
| 606 | extensions.reserve(7 + REQUIRED_EXTENSIONS.size()); | 612 | extensions.reserve(8 + REQUIRED_EXTENSIONS.size()); |
| 607 | extensions.insert(extensions.begin(), REQUIRED_EXTENSIONS.begin(), REQUIRED_EXTENSIONS.end()); | 613 | extensions.insert(extensions.begin(), REQUIRED_EXTENSIONS.begin(), REQUIRED_EXTENSIONS.end()); |
| 614 | if (requires_surface) { | ||
| 615 | extensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME); | ||
| 616 | } | ||
| 608 | 617 | ||
| 609 | bool has_khr_shader_float16_int8{}; | 618 | bool has_khr_shader_float16_int8{}; |
| 610 | bool has_ext_subgroup_size_control{}; | 619 | bool has_ext_subgroup_size_control{}; |
diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h index f1697b79a..e0711f733 100644 --- a/src/video_core/vulkan_common/vulkan_device.h +++ b/src/video_core/vulkan_common/vulkan_device.h | |||
| @@ -227,10 +227,10 @@ public: | |||
| 227 | 227 | ||
| 228 | private: | 228 | private: |
| 229 | /// Checks if the physical device is suitable. | 229 | /// Checks if the physical device is suitable. |
| 230 | void CheckSuitability() const; | 230 | void CheckSuitability(bool requires_swapchain) const; |
| 231 | 231 | ||
| 232 | /// Loads extensions into a vector and stores available ones in this object. | 232 | /// Loads extensions into a vector and stores available ones in this object. |
| 233 | std::vector<const char*> LoadExtensions(); | 233 | std::vector<const char*> LoadExtensions(bool requires_surface); |
| 234 | 234 | ||
| 235 | /// Sets up queue families. | 235 | /// Sets up queue families. |
| 236 | void SetupFamilies(VkSurfaceKHR surface); | 236 | void SetupFamilies(VkSurfaceKHR surface); |
diff --git a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp index d6eb3af31..2a8b7a907 100644 --- a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp +++ b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp | |||
| @@ -7,6 +7,8 @@ | |||
| 7 | #include <optional> | 7 | #include <optional> |
| 8 | #include <vector> | 8 | #include <vector> |
| 9 | 9 | ||
| 10 | #include <glad/glad.h> | ||
| 11 | |||
| 10 | #include "common/alignment.h" | 12 | #include "common/alignment.h" |
| 11 | #include "common/assert.h" | 13 | #include "common/assert.h" |
| 12 | #include "common/common_types.h" | 14 | #include "common/common_types.h" |
| @@ -55,10 +57,24 @@ struct Range { | |||
| 55 | 57 | ||
| 56 | class MemoryAllocation { | 58 | class MemoryAllocation { |
| 57 | public: | 59 | public: |
| 58 | explicit MemoryAllocation(const Device& device_, vk::DeviceMemory memory_, | 60 | explicit MemoryAllocation(vk::DeviceMemory memory_, VkMemoryPropertyFlags properties, |
| 59 | VkMemoryPropertyFlags properties, u64 allocation_size_, u32 type) | 61 | u64 allocation_size_, u32 type) |
| 60 | : device{device_}, memory{std::move(memory_)}, allocation_size{allocation_size_}, | 62 | : memory{std::move(memory_)}, allocation_size{allocation_size_}, property_flags{properties}, |
| 61 | property_flags{properties}, shifted_memory_type{1U << type} {} | 63 | shifted_memory_type{1U << type} {} |
| 64 | |||
| 65 | #if defined(_WIN32) || defined(__linux__) | ||
| 66 | ~MemoryAllocation() { | ||
| 67 | if (owning_opengl_handle != 0) { | ||
| 68 | glDeleteMemoryObjectsEXT(1, &owning_opengl_handle); | ||
| 69 | } | ||
| 70 | } | ||
| 71 | #endif | ||
| 72 | |||
| 73 | MemoryAllocation& operator=(const MemoryAllocation&) = delete; | ||
| 74 | MemoryAllocation(const MemoryAllocation&) = delete; | ||
| 75 | |||
| 76 | MemoryAllocation& operator=(MemoryAllocation&&) = delete; | ||
| 77 | MemoryAllocation(MemoryAllocation&&) = delete; | ||
| 62 | 78 | ||
| 63 | [[nodiscard]] std::optional<MemoryCommit> Commit(VkDeviceSize size, VkDeviceSize alignment) { | 79 | [[nodiscard]] std::optional<MemoryCommit> Commit(VkDeviceSize size, VkDeviceSize alignment) { |
| 64 | const std::optional<u64> alloc = FindFreeRegion(size, alignment); | 80 | const std::optional<u64> alloc = FindFreeRegion(size, alignment); |
| @@ -88,6 +104,31 @@ public: | |||
| 88 | return memory_mapped_span; | 104 | return memory_mapped_span; |
| 89 | } | 105 | } |
| 90 | 106 | ||
| 107 | #ifdef _WIN32 | ||
| 108 | [[nodiscard]] u32 ExportOpenGLHandle() { | ||
| 109 | if (!owning_opengl_handle) { | ||
| 110 | glCreateMemoryObjectsEXT(1, &owning_opengl_handle); | ||
| 111 | glImportMemoryWin32HandleEXT(owning_opengl_handle, allocation_size, | ||
| 112 | GL_HANDLE_TYPE_OPAQUE_WIN32_EXT, | ||
| 113 | memory.GetMemoryWin32HandleKHR()); | ||
| 114 | } | ||
| 115 | return owning_opengl_handle; | ||
| 116 | } | ||
| 117 | #elif __linux__ | ||
| 118 | [[nodiscard]] u32 ExportOpenGLHandle() { | ||
| 119 | if (!owning_opengl_handle) { | ||
| 120 | glCreateMemoryObjectsEXT(1, &owning_opengl_handle); | ||
| 121 | glImportMemoryFdEXT(owning_opengl_handle, allocation_size, GL_HANDLE_TYPE_OPAQUE_FD_EXT, | ||
| 122 | memory.GetMemoryFdKHR()); | ||
| 123 | } | ||
| 124 | return owning_opengl_handle; | ||
| 125 | } | ||
| 126 | #else | ||
| 127 | [[nodiscard]] u32 ExportOpenGLHandle() { | ||
| 128 | return 0; | ||
| 129 | } | ||
| 130 | #endif | ||
| 131 | |||
| 91 | /// Returns whether this allocation is compatible with the arguments. | 132 | /// Returns whether this allocation is compatible with the arguments. |
| 92 | [[nodiscard]] bool IsCompatible(VkMemoryPropertyFlags flags, u32 type_mask) const { | 133 | [[nodiscard]] bool IsCompatible(VkMemoryPropertyFlags flags, u32 type_mask) const { |
| 93 | return (flags & property_flags) && (type_mask & shifted_memory_type) != 0; | 134 | return (flags & property_flags) && (type_mask & shifted_memory_type) != 0; |
| @@ -118,13 +159,15 @@ private: | |||
| 118 | return candidate; | 159 | return candidate; |
| 119 | } | 160 | } |
| 120 | 161 | ||
| 121 | const Device& device; ///< Vulkan device. | ||
| 122 | const vk::DeviceMemory memory; ///< Vulkan memory allocation handler. | 162 | const vk::DeviceMemory memory; ///< Vulkan memory allocation handler. |
| 123 | const u64 allocation_size; ///< Size of this allocation. | 163 | const u64 allocation_size; ///< Size of this allocation. |
| 124 | const VkMemoryPropertyFlags property_flags; ///< Vulkan memory property flags. | 164 | const VkMemoryPropertyFlags property_flags; ///< Vulkan memory property flags. |
| 125 | const u32 shifted_memory_type; ///< Shifted Vulkan memory type. | 165 | const u32 shifted_memory_type; ///< Shifted Vulkan memory type. |
| 126 | std::vector<Range> commits; ///< All commit ranges done from this allocation. | 166 | std::vector<Range> commits; ///< All commit ranges done from this allocation. |
| 127 | std::span<u8> memory_mapped_span; ///< Memory mapped span. Empty if not queried before. | 167 | std::span<u8> memory_mapped_span; ///< Memory mapped span. Empty if not queried before. |
| 168 | #if defined(_WIN32) || defined(__linux__) | ||
| 169 | u32 owning_opengl_handle{}; ///< Owning OpenGL memory object handle. | ||
| 170 | #endif | ||
| 128 | }; | 171 | }; |
| 129 | 172 | ||
| 130 | MemoryCommit::MemoryCommit(MemoryAllocation* allocation_, VkDeviceMemory memory_, u64 begin_, | 173 | MemoryCommit::MemoryCommit(MemoryAllocation* allocation_, VkDeviceMemory memory_, u64 begin_, |
| @@ -156,14 +199,19 @@ std::span<u8> MemoryCommit::Map() { | |||
| 156 | return span; | 199 | return span; |
| 157 | } | 200 | } |
| 158 | 201 | ||
| 202 | u32 MemoryCommit::ExportOpenGLHandle() const { | ||
| 203 | return allocation->ExportOpenGLHandle(); | ||
| 204 | } | ||
| 205 | |||
| 159 | void MemoryCommit::Release() { | 206 | void MemoryCommit::Release() { |
| 160 | if (allocation) { | 207 | if (allocation) { |
| 161 | allocation->Free(begin); | 208 | allocation->Free(begin); |
| 162 | } | 209 | } |
| 163 | } | 210 | } |
| 164 | 211 | ||
| 165 | MemoryAllocator::MemoryAllocator(const Device& device_) | 212 | MemoryAllocator::MemoryAllocator(const Device& device_, bool export_allocations_) |
| 166 | : device{device_}, properties{device_.GetPhysical().GetMemoryProperties()} {} | 213 | : device{device_}, properties{device_.GetPhysical().GetMemoryProperties()}, |
| 214 | export_allocations{export_allocations_} {} | ||
| 167 | 215 | ||
| 168 | MemoryAllocator::~MemoryAllocator() = default; | 216 | MemoryAllocator::~MemoryAllocator() = default; |
| 169 | 217 | ||
| @@ -196,14 +244,24 @@ MemoryCommit MemoryAllocator::Commit(const vk::Image& image, MemoryUsage usage) | |||
| 196 | 244 | ||
| 197 | void MemoryAllocator::AllocMemory(VkMemoryPropertyFlags flags, u32 type_mask, u64 size) { | 245 | void MemoryAllocator::AllocMemory(VkMemoryPropertyFlags flags, u32 type_mask, u64 size) { |
| 198 | const u32 type = FindType(flags, type_mask).value(); | 246 | const u32 type = FindType(flags, type_mask).value(); |
| 247 | const VkExportMemoryAllocateInfo export_allocate_info{ | ||
| 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 __linux__ | ||
| 253 | .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT, | ||
| 254 | #else | ||
| 255 | .handleTypes = 0, | ||
| 256 | #endif | ||
| 257 | }; | ||
| 199 | vk::DeviceMemory memory = device.GetLogical().AllocateMemory({ | 258 | vk::DeviceMemory memory = device.GetLogical().AllocateMemory({ |
| 200 | .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, | 259 | .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, |
| 201 | .pNext = nullptr, | 260 | .pNext = export_allocations ? &export_allocate_info : nullptr, |
| 202 | .allocationSize = size, | 261 | .allocationSize = size, |
| 203 | .memoryTypeIndex = type, | 262 | .memoryTypeIndex = type, |
| 204 | }); | 263 | }); |
| 205 | allocations.push_back( | 264 | allocations.push_back(std::make_unique<MemoryAllocation>(std::move(memory), flags, size, type)); |
| 206 | std::make_unique<MemoryAllocation>(device, std::move(memory), flags, size, type)); | ||
| 207 | } | 265 | } |
| 208 | 266 | ||
| 209 | std::optional<MemoryCommit> MemoryAllocator::TryCommit(const VkMemoryRequirements& requirements, | 267 | std::optional<MemoryCommit> MemoryAllocator::TryCommit(const VkMemoryRequirements& requirements, |
diff --git a/src/video_core/vulkan_common/vulkan_memory_allocator.h b/src/video_core/vulkan_common/vulkan_memory_allocator.h index 9e6cfabf9..86393310a 100644 --- a/src/video_core/vulkan_common/vulkan_memory_allocator.h +++ b/src/video_core/vulkan_common/vulkan_memory_allocator.h | |||
| @@ -43,6 +43,9 @@ public: | |||
| 43 | /// It will map the backing allocation if it hasn't been mapped before. | 43 | /// It will map the backing allocation if it hasn't been mapped before. |
| 44 | std::span<u8> Map(); | 44 | std::span<u8> Map(); |
| 45 | 45 | ||
| 46 | /// Returns an non-owning OpenGL handle, creating one if it doesn't exist. | ||
| 47 | u32 ExportOpenGLHandle() const; | ||
| 48 | |||
| 46 | /// Returns the Vulkan memory handler. | 49 | /// Returns the Vulkan memory handler. |
| 47 | VkDeviceMemory Memory() const { | 50 | VkDeviceMemory Memory() const { |
| 48 | return memory; | 51 | return memory; |
| @@ -67,7 +70,15 @@ private: | |||
| 67 | /// Allocates and releases memory allocations on demand. | 70 | /// Allocates and releases memory allocations on demand. |
| 68 | class MemoryAllocator { | 71 | class MemoryAllocator { |
| 69 | public: | 72 | public: |
| 70 | explicit MemoryAllocator(const Device& device_); | 73 | /** |
| 74 | * Construct memory allocator | ||
| 75 | * | ||
| 76 | * @param device_ Device to allocate from | ||
| 77 | * @param export_allocations_ True when allocations have to be exported | ||
| 78 | * | ||
| 79 | * @throw vk::Exception on failure | ||
| 80 | */ | ||
| 81 | explicit MemoryAllocator(const Device& device_, bool export_allocations_ = false); | ||
| 71 | ~MemoryAllocator(); | 82 | ~MemoryAllocator(); |
| 72 | 83 | ||
| 73 | MemoryAllocator& operator=(const MemoryAllocator&) = delete; | 84 | MemoryAllocator& operator=(const MemoryAllocator&) = delete; |
| @@ -106,8 +117,9 @@ private: | |||
| 106 | /// Returns index to the fastest memory type compatible with the passed requirements. | 117 | /// Returns index to the fastest memory type compatible with the passed requirements. |
| 107 | std::optional<u32> FindType(VkMemoryPropertyFlags flags, u32 type_mask) const; | 118 | std::optional<u32> FindType(VkMemoryPropertyFlags flags, u32 type_mask) const; |
| 108 | 119 | ||
| 109 | const Device& device; ///< Device handle. | 120 | const Device& device; ///< Device handle. |
| 110 | const VkPhysicalDeviceMemoryProperties properties; ///< Physical device properties. | 121 | const VkPhysicalDeviceMemoryProperties properties; ///< Physical device properties. |
| 122 | const bool export_allocations; ///< True when memory allocations have to be exported. | ||
| 111 | std::vector<std::unique_ptr<MemoryAllocation>> allocations; ///< Current allocations. | 123 | std::vector<std::unique_ptr<MemoryAllocation>> allocations; ///< Current allocations. |
| 112 | }; | 124 | }; |
| 113 | 125 | ||