From a58799aca725e9afea8da91f5d8cba5954acee6f Mon Sep 17 00:00:00 2001 From: MrPurple666 Date: Thu, 24 Apr 2025 02:59:02 -0300 Subject: [PATCH] Initial RAII implementation --- .../renderer_vulkan/renderer_vulkan.cpp | 13 +- .../renderer_vulkan/renderer_vulkan.h | 10 + src/video_core/vulkan_common/vulkan_raii.h | 235 ++++++++++++++++++ 3 files changed, 256 insertions(+), 2 deletions(-) create mode 100644 src/video_core/vulkan_common/vulkan_raii.h diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index c4fe8235c7..cf7ce0cbbc 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp @@ -106,11 +106,20 @@ RendererVulkan::RendererVulkan(Core::Frontend::EmuWindow& emu_window, std::unique_ptr context_) try : RendererBase(emu_window, std::move(context_)), device_memory(device_memory_), gpu(gpu_), library(OpenLibrary(context.get())), + // Create raw Vulkan instance first instance(CreateInstance(*library, dld, VK_API_VERSION_1_1, render_window.GetWindowInfo().type, - Settings::values.renderer_debug.GetValue())), + Settings::values.renderer_debug.GetValue())), + // Now create RAII wrappers for the resources in the correct order + raii_instance(MakeInstance(instance, dld)), + // Create debug messenger if debug is enabled debug_messenger(Settings::values.renderer_debug ? CreateDebugUtilsCallback(instance) - : vk::DebugUtilsMessenger{}), + : vk::DebugUtilsMessenger{}), + raii_debug_messenger(Settings::values.renderer_debug + ? MakeDebugUtilsMessenger(debug_messenger, instance, dld) + : RaiiDebugUtilsMessenger{}), + // Create surface surface(CreateSurface(instance, render_window.GetWindowInfo())), + raii_surface(MakeSurface(surface, instance, dld)), device(CreateDevice(instance, dld, *surface)), memory_allocator(device), state_tracker(), scheduler(device, state_tracker), swapchain(*surface, device, scheduler, render_window.GetFramebufferLayout().width, diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.h b/src/video_core/renderer_vulkan/renderer_vulkan.h index 0a606d6fed..0333106113 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.h +++ b/src/video_core/renderer_vulkan/renderer_vulkan.h @@ -21,6 +21,7 @@ #include "video_core/vulkan_common/vulkan_memory_allocator.h" #include "video_core/vulkan_common/hybrid_memory.h" #include "video_core/vulkan_common/vulkan_wrapper.h" +#include "video_core/vulkan_common/vulkan_raii.h" namespace Core::Memory { class Memory; @@ -76,9 +77,18 @@ private: std::shared_ptr library; vk::InstanceDispatch dld; + // Keep original handles for compatibility with existing code vk::Instance instance; + // RAII wrapper for instance + RaiiInstance raii_instance; + vk::DebugUtilsMessenger debug_messenger; + // RAII wrapper for debug messenger + RaiiDebugUtilsMessenger raii_debug_messenger; + vk::SurfaceKHR surface; + // RAII wrapper for surface + RaiiSurface raii_surface; Device device; MemoryAllocator memory_allocator; diff --git a/src/video_core/vulkan_common/vulkan_raii.h b/src/video_core/vulkan_common/vulkan_raii.h new file mode 100644 index 0000000000..655b39a30c --- /dev/null +++ b/src/video_core/vulkan_common/vulkan_raii.h @@ -0,0 +1,235 @@ +// SPDX-FileCopyrightText: Copyright 2025 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include +#include +#include +#include + +#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 +class VulkanRaii { +public: + using DeleterFunc = std::function; + + // Default constructor - creates a null handle + VulkanRaii() : handle{}, deleter{}, dispatch{} {} + + // Constructor with handle and deleter + VulkanRaii(T handle_, DeleterFunc deleter_, const Dispatch& dispatch_, const std::string& resource_name = "Vulkan resource") + : handle{handle_}, deleter{std::move(deleter_)}, dispatch{dispatch_} { + LOG_WARNING(Render_Vulkan, "RAII wrapper created for {}", resource_name); + } + + // Move constructor + VulkanRaii(VulkanRaii&& other) noexcept + : handle{other.handle}, deleter{std::move(other.deleter)}, dispatch{other.dispatch} { + other.handle = VK_NULL_HANDLE; + } + + // Move assignment + VulkanRaii& operator=(VulkanRaii&& other) noexcept { + if (this != &other) { + cleanup(); + handle = other.handle; + deleter = std::move(other.deleter); + dispatch = other.dispatch; + other.handle = VK_NULL_HANDLE; + } + return *this; + } + + // Destructor - automatically cleans up the resource + ~VulkanRaii() { + if (handle != VK_NULL_HANDLE) { + LOG_WARNING(Render_Vulkan, "RAII wrapper destroying resource"); + } + 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 { + T result = handle; + handle = VK_NULL_HANDLE; + return result; + } + + // 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: + void cleanup() { + 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 +using RaiiInstance = VulkanRaii; +using RaiiDevice = VulkanRaii; +using RaiiSurface = VulkanRaii; +using RaiiSwapchain = VulkanRaii; +using RaiiCommandPool = VulkanRaii; +using RaiiBuffer = VulkanRaii; +using RaiiImage = VulkanRaii; +using RaiiImageView = VulkanRaii; +using RaiiSampler = VulkanRaii; +using RaiiShaderModule = VulkanRaii; +using RaiiPipeline = VulkanRaii; +using RaiiPipelineLayout = VulkanRaii; +using RaiiDescriptorSetLayout = VulkanRaii; +using RaiiDescriptorPool = VulkanRaii; +using RaiiSemaphore = VulkanRaii; +using RaiiFence = VulkanRaii; +using RaiiDebugUtilsMessenger = VulkanRaii; + +// Helper functions to create RAII wrappers + +/** + * Creates an RAII wrapper for a Vulkan instance + */ +inline RaiiInstance MakeInstance(const vk::Instance& instance, const vk::InstanceDispatch& dispatch) { + auto deleter = [](VkInstance handle, const vk::InstanceDispatch& dld) { + dld.vkDestroyInstance(handle, nullptr); + }; + return RaiiInstance(*instance, deleter, dispatch, "VkInstance"); +} + +/** + * Creates an RAII wrapper for a Vulkan device + */ +inline RaiiDevice MakeDevice(const vk::Device& device, const vk::DeviceDispatch& dispatch) { + auto deleter = [](VkDevice handle, const vk::DeviceDispatch& dld) { + dld.vkDestroyDevice(handle, nullptr); + }; + return RaiiDevice(*device, deleter, dispatch, "VkDevice"); +} + +/** + * Creates an RAII wrapper for a Vulkan surface + */ +inline RaiiSurface MakeSurface(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 RaiiSurface(*surface, deleter, dispatch, "VkSurfaceKHR"); +} + +/** + * Creates an RAII wrapper for a Vulkan debug messenger + */ +inline RaiiDebugUtilsMessenger MakeDebugUtilsMessenger(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 RaiiDebugUtilsMessenger(*messenger, deleter, dispatch, "VkDebugUtilsMessengerEXT"); +} + +/** + * Creates an RAII wrapper for a Vulkan swapchain + */ +inline RaiiSwapchain MakeSwapchain(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 RaiiSwapchain(swapchain_handle, deleter, dispatch); +} + +/** + * Creates an RAII wrapper for a Vulkan buffer + */ +inline RaiiBuffer MakeBuffer(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 RaiiBuffer(buffer_handle, deleter, dispatch); +} + +/** + * Creates an RAII wrapper for a Vulkan image + */ +inline RaiiImage MakeImage(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 RaiiImage(image_handle, deleter, dispatch); +} + +/** + * Creates an RAII wrapper for a Vulkan image view + */ +inline RaiiImageView MakeImageView(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 RaiiImageView(view_handle, deleter, dispatch); +} + +/** + * Creates an RAII wrapper for a Vulkan semaphore + */ +inline RaiiSemaphore MakeSemaphore(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 RaiiSemaphore(semaphore_handle, deleter, dispatch); +} + +/** + * Creates an RAII wrapper for a Vulkan fence + */ +inline RaiiFence MakeFence(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 RaiiFence(fence_handle, deleter, dispatch); +} + +} // namespace Vulkan