diff options
| author | Ribbit <ribbit@eden-emu.dev> | 2025-10-08 04:01:24 +0200 |
|---|---|---|
| committer | crueter <crueter@eden-emu.dev> | 2025-10-08 04:01:24 +0200 |
| commit | db65f107689f853141fd2cf4cb7b6b55b24aff3e (patch) | |
| tree | 9c142e5361fdff65ce329d97714f3bd879c435fa /src/video_core | |
| parent | acd7d792a34a809cf4e7f9270b3cee605fb6c35e (diff) | |
[vk] Unify RAII in Vulkan (#2679)
This PR consolidates Vulkan RAII on video_core/vulkan_common/vulkan_wrapper.h’s vk::Handle and remove the unused duplicate src/video_core/vulkan_common/vulkan_raii.h, reducing confusion and maintenance. Swapchain now uses RAII‑managed per‑image semaphores and clears them in Destroy(), providing correct present synchronization and automatic cleanup. Expected result: simpler lifetimes, fewer leak risks, and more stable presentation with negligible overhead.
Co-authored-by: Ribbit <ribbit@placeholder.com>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/2679
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Co-authored-by: Ribbit <ribbit@eden-emu.dev>
Co-committed-by: Ribbit <ribbit@eden-emu.dev>
Diffstat (limited to 'src/video_core')
| -rw-r--r-- | src/video_core/renderer_vulkan/renderer_vulkan.cpp | 9 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/renderer_vulkan.h | 10 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_swapchain.cpp | 1 | ||||
| -rw-r--r-- | src/video_core/vulkan_common/vulkan_raii.h | 231 | ||||
| -rw-r--r-- | src/video_core/vulkan_common/vulkan_wrapper.cpp | 11 | ||||
| -rw-r--r-- | src/video_core/vulkan_common/vulkan_wrapper.h | 66 |
6 files changed, 40 insertions, 288 deletions
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index 6f3a0e4cd1..e6e72cdca7 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp @@ -164,15 +164,6 @@ try PresentFiltersForAppletCapture) , rasterizer(render_window, gpu, device_memory, device, memory_allocator, state_tracker, scheduler) { - // Initialize RAII wrappers after creating the main objects - if (Settings::values.enable_raii.GetValue()) { - managed_instance = MakeManagedInstance(instance, dld); - if (Settings::values.renderer_debug) { - managed_debug_messenger = MakeManagedDebugUtilsMessenger(debug_messenger, instance, dld); - } - managed_surface = MakeManagedSurface(surface, instance, dld); - } - if (Settings::values.renderer_force_max_clock.GetValue() && device.ShouldBoostClocks()) { turbo_mode.emplace(instance, dld); scheduler.RegisterOnSubmit([this] { turbo_mode->QueueSubmitted(); }); diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.h b/src/video_core/renderer_vulkan/renderer_vulkan.h index c1e6d5db7f..4fb88b29de 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.h +++ b/src/video_core/renderer_vulkan/renderer_vulkan.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -20,7 +23,6 @@ #include "video_core/vulkan_common/vulkan_device.h" #include "video_core/vulkan_common/vulkan_memory_allocator.h" #include "video_core/vulkan_common/vulkan_wrapper.h" -#include "video_core/vulkan_common/vulkan_raii.h" namespace Core::Memory { class Memory; @@ -78,16 +80,10 @@ private: // Keep original handles for compatibility with existing code vk::Instance instance; - // RAII wrapper for instance - ManagedInstance managed_instance; vk::DebugUtilsMessenger debug_messenger; - // RAII wrapper for debug messenger - ManagedDebugUtilsMessenger managed_debug_messenger; vk::SurfaceKHR surface; - // RAII wrapper for surface - ManagedSurface managed_surface; Device device; MemoryAllocator memory_allocator; diff --git a/src/video_core/renderer_vulkan/vk_swapchain.cpp b/src/video_core/renderer_vulkan/vk_swapchain.cpp index 3b35e28c05..fdd2de2379 100644 --- a/src/video_core/renderer_vulkan/vk_swapchain.cpp +++ b/src/video_core/renderer_vulkan/vk_swapchain.cpp @@ -351,6 +351,7 @@ void Swapchain::CreateSemaphores() { void Swapchain::Destroy() { frame_index = 0; present_semaphores.clear(); + render_semaphores.clear(); swapchain.reset(); } diff --git a/src/video_core/vulkan_common/vulkan_raii.h b/src/video_core/vulkan_common/vulkan_raii.h deleted file mode 100644 index cf5e268b68..0000000000 --- a/src/video_core/vulkan_common/vulkan_raii.h +++ /dev/null @@ -1,231 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2025 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include <memory> -#include <utility> -#include <functional> -#include <string> - -#include "common/logging/log.h" - -#include "video_core/vulkan_common/vulkan_wrapper.h" - -namespace Vulkan { - -/** - * RAII wrapper for Vulkan resources. - * Automatically manages the lifetime of Vulkan objects using RAII principles. - */ -template <typename T, typename Owner = void*, typename Dispatch = vk::InstanceDispatch> -class VulkanRaii { -public: - using DeleterFunc = std::function<void(T, const Dispatch&)>; - - // Default constructor - creates a null handle - VulkanRaii() : handle{}, deleter{}, dispatch{} {} - - // Constructor with handle and deleter - VulkanRaii(T handle_, DeleterFunc deleter_, const Dispatch& dispatch_, const char* resource_name = "Vulkan resource") - : handle{handle_}, deleter{std::move(deleter_)}, dispatch{dispatch_} { - LOG_DEBUG(Render_Vulkan, "RAII wrapper created for {}", resource_name); - } - - // Move constructor - VulkanRaii(VulkanRaii&& other) noexcept - : handle{std::exchange(other.handle, VK_NULL_HANDLE)}, - deleter{std::move(other.deleter)}, - dispatch{other.dispatch} { - } - - // Move assignment - VulkanRaii& operator=(VulkanRaii&& other) noexcept { - if (this != &other) { - cleanup(); - handle = std::exchange(other.handle, VK_NULL_HANDLE); - deleter = std::move(other.deleter); - dispatch = other.dispatch; - } - return *this; - } - - // Destructor - automatically cleans up the resource - ~VulkanRaii() { - cleanup(); - } - - // Disallow copying - VulkanRaii(const VulkanRaii&) = delete; - VulkanRaii& operator=(const VulkanRaii&) = delete; - - // Get the underlying handle - T get() const noexcept { - return handle; - } - - // Check if the handle is valid - bool valid() const noexcept { - return handle != VK_NULL_HANDLE; - } - - // Release ownership of the handle without destroying it - T release() noexcept { - return std::exchange(handle, VK_NULL_HANDLE); - } - - // Reset the handle (destroying the current one if it exists) - void reset(T new_handle = VK_NULL_HANDLE, DeleterFunc new_deleter = {}) { - cleanup(); - handle = new_handle; - deleter = std::move(new_deleter); - } - - // Implicit conversion to handle type - operator T() const noexcept { - return handle; - } - - // Dereference operator for pointer-like access - T operator->() const noexcept { - return handle; - } - -private: - // Optimized cleanup function - void cleanup() noexcept { - if (handle != VK_NULL_HANDLE && deleter) { - deleter(handle, dispatch); - handle = VK_NULL_HANDLE; - } - } - - T handle; - DeleterFunc deleter; - Dispatch dispatch; -}; - -// Common type aliases for Vulkan RAII wrappers with clearer names -using ManagedInstance = VulkanRaii<VkInstance, void*, vk::InstanceDispatch>; -using ManagedDevice = VulkanRaii<VkDevice, void*, vk::DeviceDispatch>; -using ManagedSurface = VulkanRaii<VkSurfaceKHR, VkInstance, vk::InstanceDispatch>; -using ManagedSwapchain = VulkanRaii<VkSwapchainKHR, VkDevice, vk::DeviceDispatch>; -using ManagedCommandPool = VulkanRaii<VkCommandPool, VkDevice, vk::DeviceDispatch>; -using ManagedBuffer = VulkanRaii<VkBuffer, VkDevice, vk::DeviceDispatch>; -using ManagedImage = VulkanRaii<VkImage, VkDevice, vk::DeviceDispatch>; -using ManagedImageView = VulkanRaii<VkImageView, VkDevice, vk::DeviceDispatch>; -using ManagedSampler = VulkanRaii<VkSampler, VkDevice, vk::DeviceDispatch>; -using ManagedShaderModule = VulkanRaii<VkShaderModule, VkDevice, vk::DeviceDispatch>; -using ManagedPipeline = VulkanRaii<VkPipeline, VkDevice, vk::DeviceDispatch>; -using ManagedPipelineLayout = VulkanRaii<VkPipelineLayout, VkDevice, vk::DeviceDispatch>; -using ManagedDescriptorSetLayout = VulkanRaii<VkDescriptorSetLayout, VkDevice, vk::DeviceDispatch>; -using ManagedDescriptorPool = VulkanRaii<VkDescriptorPool, VkDevice, vk::DeviceDispatch>; -using ManagedSemaphore = VulkanRaii<VkSemaphore, VkDevice, vk::DeviceDispatch>; -using ManagedFence = VulkanRaii<VkFence, VkDevice, vk::DeviceDispatch>; -using ManagedDebugUtilsMessenger = VulkanRaii<VkDebugUtilsMessengerEXT, VkInstance, vk::InstanceDispatch>; - -// Helper functions to create RAII wrappers - -/** - * Creates an RAII wrapper for a Vulkan instance - */ -inline ManagedInstance MakeManagedInstance(const vk::Instance& instance, const vk::InstanceDispatch& dispatch) { - auto deleter = [](VkInstance handle, const vk::InstanceDispatch& dld) { - dld.vkDestroyInstance(handle, nullptr); - }; - return ManagedInstance(*instance, deleter, dispatch, "VkInstance"); -} - -/** - * Creates an RAII wrapper for a Vulkan device - */ -inline ManagedDevice MakeManagedDevice(const vk::Device& device, const vk::DeviceDispatch& dispatch) { - auto deleter = [](VkDevice handle, const vk::DeviceDispatch& dld) { - dld.vkDestroyDevice(handle, nullptr); - }; - return ManagedDevice(*device, deleter, dispatch, "VkDevice"); -} - -/** - * Creates an RAII wrapper for a Vulkan surface - */ -inline ManagedSurface MakeManagedSurface(const vk::SurfaceKHR& surface, const vk::Instance& instance, const vk::InstanceDispatch& dispatch) { - auto deleter = [instance_ptr = *instance](VkSurfaceKHR handle, const vk::InstanceDispatch& dld) { - dld.vkDestroySurfaceKHR(instance_ptr, handle, nullptr); - }; - return ManagedSurface(*surface, deleter, dispatch, "VkSurfaceKHR"); -} - -/** - * Creates an RAII wrapper for a Vulkan debug messenger - */ -inline ManagedDebugUtilsMessenger MakeManagedDebugUtilsMessenger(const vk::DebugUtilsMessenger& messenger, - const vk::Instance& instance, - const vk::InstanceDispatch& dispatch) { - auto deleter = [instance_ptr = *instance](VkDebugUtilsMessengerEXT handle, const vk::InstanceDispatch& dld) { - dld.vkDestroyDebugUtilsMessengerEXT(instance_ptr, handle, nullptr); - }; - return ManagedDebugUtilsMessenger(*messenger, deleter, dispatch, "VkDebugUtilsMessengerEXT"); -} - -/** - * Creates an RAII wrapper for a Vulkan swapchain - */ -inline ManagedSwapchain MakeManagedSwapchain(VkSwapchainKHR swapchain_handle, VkDevice device_handle, const vk::DeviceDispatch& dispatch) { - auto deleter = [device_handle](VkSwapchainKHR handle, const vk::DeviceDispatch& dld) { - dld.vkDestroySwapchainKHR(device_handle, handle, nullptr); - }; - return ManagedSwapchain(swapchain_handle, deleter, dispatch, "VkSwapchainKHR"); -} - -/** - * Creates an RAII wrapper for a Vulkan buffer - */ -inline ManagedBuffer MakeManagedBuffer(VkBuffer buffer_handle, VkDevice device_handle, const vk::DeviceDispatch& dispatch) { - auto deleter = [device_handle](VkBuffer handle, const vk::DeviceDispatch& dld) { - dld.vkDestroyBuffer(device_handle, handle, nullptr); - }; - return ManagedBuffer(buffer_handle, deleter, dispatch, "VkBuffer"); -} - -/** - * Creates an RAII wrapper for a Vulkan image - */ -inline ManagedImage MakeManagedImage(VkImage image_handle, VkDevice device_handle, const vk::DeviceDispatch& dispatch) { - auto deleter = [device_handle](VkImage handle, const vk::DeviceDispatch& dld) { - dld.vkDestroyImage(device_handle, handle, nullptr); - }; - return ManagedImage(image_handle, deleter, dispatch, "VkImage"); -} - -/** - * Creates an RAII wrapper for a Vulkan image view - */ -inline ManagedImageView MakeManagedImageView(VkImageView view_handle, VkDevice device_handle, const vk::DeviceDispatch& dispatch) { - auto deleter = [device_handle](VkImageView handle, const vk::DeviceDispatch& dld) { - dld.vkDestroyImageView(device_handle, handle, nullptr); - }; - return ManagedImageView(view_handle, deleter, dispatch, "VkImageView"); -} - -/** - * Creates an RAII wrapper for a Vulkan semaphore - */ -inline ManagedSemaphore MakeManagedSemaphore(VkSemaphore semaphore_handle, VkDevice device_handle, const vk::DeviceDispatch& dispatch) { - auto deleter = [device_handle](VkSemaphore handle, const vk::DeviceDispatch& dld) { - dld.vkDestroySemaphore(device_handle, handle, nullptr); - }; - return ManagedSemaphore(semaphore_handle, deleter, dispatch, "VkSemaphore"); -} - -/** - * Creates an RAII wrapper for a Vulkan fence - */ -inline ManagedFence MakeManagedFence(VkFence fence_handle, VkDevice device_handle, const vk::DeviceDispatch& dispatch) { - auto deleter = [device_handle](VkFence handle, const vk::DeviceDispatch& dld) { - dld.vkDestroyFence(device_handle, handle, nullptr); - }; - return ManagedFence(fence_handle, deleter, dispatch, "VkFence"); -} - -} // namespace Vulkan
\ No newline at end of file diff --git a/src/video_core/vulkan_common/vulkan_wrapper.cpp b/src/video_core/vulkan_common/vulkan_wrapper.cpp index 949b91499d..b77d01711a 100644 --- a/src/video_core/vulkan_common/vulkan_wrapper.cpp +++ b/src/video_core/vulkan_common/vulkan_wrapper.cpp @@ -12,7 +12,6 @@ #include "common/common_types.h" #include "common/logging/log.h" -#include "common/settings.h" #include "video_core/vulkan_common/vk_enum_string_helper.h" #include "video_core/vulkan_common/vma.h" #include "video_core/vulkan_common/vulkan_wrapper.h" @@ -311,10 +310,7 @@ const char* Exception::what() const noexcept { } void Destroy(VkInstance instance, const InstanceDispatch& dld) noexcept { - // FIXME: A double free occurs here if RAII is enabled. - if (!Settings::values.enable_raii.GetValue()) { - dld.vkDestroyInstance(instance, nullptr); - } + dld.vkDestroyInstance(instance, nullptr); } void Destroy(VkDevice device, const InstanceDispatch& dld) noexcept { @@ -417,10 +413,7 @@ void Destroy(VkInstance instance, VkDebugReportCallbackEXT handle, } void Destroy(VkInstance instance, VkSurfaceKHR handle, const InstanceDispatch& dld) noexcept { - // FIXME: A double free occurs here if RAII is enabled. - if (!Settings::values.enable_raii.GetValue()) { - dld.vkDestroySurfaceKHR(instance, handle, nullptr); - } + dld.vkDestroySurfaceKHR(instance, handle, nullptr); } VkResult Free(VkDevice device, VkDescriptorPool handle, Span<VkDescriptorSet> sets, diff --git a/src/video_core/vulkan_common/vulkan_wrapper.h b/src/video_core/vulkan_common/vulkan_wrapper.h index 6501094f05..39396b3279 100644 --- a/src/video_core/vulkan_common/vulkan_wrapper.h +++ b/src/video_core/vulkan_common/vulkan_wrapper.h @@ -516,7 +516,7 @@ public: } /// Returns true when there's a held object. - operator bool() const noexcept { + explicit operator bool() const noexcept { return handle != nullptr; } @@ -627,7 +627,7 @@ class Instance : public Handle<VkInstance, NoOwner, InstanceDispatch> { public: /// Creates a Vulkan instance. /// @throw Exception on initialization error. - static Instance Create(u32 version, Span<const char*> layers, Span<const char*> extensions, + [[nodiscard]] static Instance Create(u32 version, Span<const char*> layers, Span<const char*> extensions, InstanceDispatch& dispatch); /// Enumerates physical devices. @@ -637,12 +637,12 @@ public: /// Creates a debug callback messenger. /// @throw Exception on creation failure. - DebugUtilsMessenger CreateDebugUtilsMessenger( + [[nodiscard]] DebugUtilsMessenger CreateDebugUtilsMessenger( const VkDebugUtilsMessengerCreateInfoEXT& create_info) const; /// Creates a debug report callback. /// @throw Exception on creation failure. - DebugReportCallback CreateDebugReportCallback( + [[nodiscard]] DebugReportCallback CreateDebugReportCallback( const VkDebugReportCallbackCreateInfoEXT& create_info) const; /// Returns dispatch table. @@ -986,58 +986,60 @@ class Device : public Handle<VkDevice, NoOwner, DeviceDispatch> { using Handle<VkDevice, NoOwner, DeviceDispatch>::Handle; public: - static Device Create(VkPhysicalDevice physical_device, Span<VkDeviceQueueCreateInfo> queues_ci, - Span<const char*> enabled_extensions, const void* next, - DeviceDispatch& dispatch); + [[nodiscard]] static Device Create(VkPhysicalDevice physical_device, + Span<VkDeviceQueueCreateInfo> queues_ci, + Span<const char*> enabled_extensions, const void* next, + DeviceDispatch& dispatch); - Queue GetQueue(u32 family_index) const noexcept; + [[nodiscard]] Queue GetQueue(u32 family_index) const noexcept; - BufferView CreateBufferView(const VkBufferViewCreateInfo& ci) const; + [[nodiscard]] BufferView CreateBufferView(const VkBufferViewCreateInfo& ci) const; - ImageView CreateImageView(const VkImageViewCreateInfo& ci) const; + [[nodiscard]] ImageView CreateImageView(const VkImageViewCreateInfo& ci) const; - Semaphore CreateSemaphore() const; + [[nodiscard]] Semaphore CreateSemaphore() const; - Semaphore CreateSemaphore(const VkSemaphoreCreateInfo& ci) const; + [[nodiscard]] Semaphore CreateSemaphore(const VkSemaphoreCreateInfo& ci) const; - Fence CreateFence(const VkFenceCreateInfo& ci) const; + [[nodiscard]] Fence CreateFence(const VkFenceCreateInfo& ci) const; - DescriptorPool CreateDescriptorPool(const VkDescriptorPoolCreateInfo& ci) const; + [[nodiscard]] DescriptorPool CreateDescriptorPool(const VkDescriptorPoolCreateInfo& ci) const; - RenderPass CreateRenderPass(const VkRenderPassCreateInfo& ci) const; + [[nodiscard]] RenderPass CreateRenderPass(const VkRenderPassCreateInfo& ci) const; - DescriptorSetLayout CreateDescriptorSetLayout(const VkDescriptorSetLayoutCreateInfo& ci) const; + [[nodiscard]] DescriptorSetLayout CreateDescriptorSetLayout( + const VkDescriptorSetLayoutCreateInfo& ci) const; - PipelineCache CreatePipelineCache(const VkPipelineCacheCreateInfo& ci) const; + [[nodiscard]] PipelineCache CreatePipelineCache(const VkPipelineCacheCreateInfo& ci) const; - PipelineLayout CreatePipelineLayout(const VkPipelineLayoutCreateInfo& ci) const; + [[nodiscard]] PipelineLayout CreatePipelineLayout(const VkPipelineLayoutCreateInfo& ci) const; - Pipeline CreateGraphicsPipeline(const VkGraphicsPipelineCreateInfo& ci, - VkPipelineCache cache = nullptr) const; + [[nodiscard]] Pipeline CreateGraphicsPipeline(const VkGraphicsPipelineCreateInfo& ci, + VkPipelineCache cache = nullptr) const; - Pipeline CreateComputePipeline(const VkComputePipelineCreateInfo& ci, - VkPipelineCache cache = nullptr) const; + [[nodiscard]] Pipeline CreateComputePipeline(const VkComputePipelineCreateInfo& ci, + VkPipelineCache cache = nullptr) const; - Sampler CreateSampler(const VkSamplerCreateInfo& ci) const; + [[nodiscard]] Sampler CreateSampler(const VkSamplerCreateInfo& ci) const; - Framebuffer CreateFramebuffer(const VkFramebufferCreateInfo& ci) const; + [[nodiscard]] Framebuffer CreateFramebuffer(const VkFramebufferCreateInfo& ci) const; - CommandPool CreateCommandPool(const VkCommandPoolCreateInfo& ci) const; + [[nodiscard]] CommandPool CreateCommandPool(const VkCommandPoolCreateInfo& ci) const; - DescriptorUpdateTemplate CreateDescriptorUpdateTemplate( + [[nodiscard]] DescriptorUpdateTemplate CreateDescriptorUpdateTemplate( const VkDescriptorUpdateTemplateCreateInfo& ci) const; - QueryPool CreateQueryPool(const VkQueryPoolCreateInfo& ci) const; + [[nodiscard]] QueryPool CreateQueryPool(const VkQueryPoolCreateInfo& ci) const; - ShaderModule CreateShaderModule(const VkShaderModuleCreateInfo& ci) const; + [[nodiscard]] ShaderModule CreateShaderModule(const VkShaderModuleCreateInfo& ci) const; - Event CreateEvent() const; + [[nodiscard]] Event CreateEvent() const; - SwapchainKHR CreateSwapchainKHR(const VkSwapchainCreateInfoKHR& ci) const; + [[nodiscard]] SwapchainKHR CreateSwapchainKHR(const VkSwapchainCreateInfoKHR& ci) const; - DeviceMemory TryAllocateMemory(const VkMemoryAllocateInfo& ai) const noexcept; + [[nodiscard]] DeviceMemory TryAllocateMemory(const VkMemoryAllocateInfo& ai) const noexcept; - DeviceMemory AllocateMemory(const VkMemoryAllocateInfo& ai) const; + [[nodiscard]] DeviceMemory AllocateMemory(const VkMemoryAllocateInfo& ai) const; VkMemoryRequirements GetBufferMemoryRequirements(VkBuffer buffer, void* pnext = nullptr) const noexcept; |
