From 3fe0cbe3fb5e2a937f942852a69c9156e294a158 Mon Sep 17 00:00:00 2001 From: Briar <205427297+icy-briar@users.noreply.github.com> Date: Fri, 2 May 2025 18:42:58 +0000 Subject: [PATCH] renderer_vulkan: Use raw surface handles and improve release logic (#75) Should fix or at least lessen the crashes when leaving runtime emulation on both Android / PC Also, may have improved the time required to leave the game Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/75 Co-authored-by: Briar <205427297+icy-briar@users.noreply.github.com> Co-committed-by: Briar <205427297+icy-briar@users.noreply.github.com> --- .../renderer_vulkan/renderer_vulkan.cpp | 15 +++++++++++--- .../renderer_vulkan/vk_present_manager.cpp | 16 +++++++-------- .../renderer_vulkan/vk_present_manager.h | 6 ++++-- .../renderer_vulkan/vk_swapchain.cpp | 20 +++++++++---------- src/video_core/renderer_vulkan/vk_swapchain.h | 8 +++++--- src/video_core/vulkan_common/vulkan_wrapper.h | 18 +++++++++++++++++ 6 files changed, 57 insertions(+), 26 deletions(-) diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index ebc50290a9..32a207bc26 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp @@ -120,12 +120,13 @@ RendererVulkan::RendererVulkan(Core::Frontend::EmuWindow& emu_window, // Create surface surface(CreateSurface(instance, render_window.GetWindowInfo())), managed_surface(MakeManagedSurface(surface, instance, dld)), - device(CreateDevice(instance, dld, *surface)), memory_allocator(device), state_tracker(), + device(CreateDevice(instance, dld, *surface)), + memory_allocator(device), state_tracker(), scheduler(device, state_tracker), swapchain(*surface, device, scheduler, render_window.GetFramebufferLayout().width, render_window.GetFramebufferLayout().height), present_manager(instance, render_window, device, memory_allocator, scheduler, swapchain, - surface), + *surface), blit_swapchain(device_memory, device, memory_allocator, present_manager, scheduler, PresentFiltersForDisplay), blit_capture(device_memory, device, memory_allocator, present_manager, scheduler, @@ -136,11 +137,19 @@ RendererVulkan::RendererVulkan(Core::Frontend::EmuWindow& emu_window, scheduler), hybrid_memory(std::make_unique(device, memory_allocator)), applet_frame() { - if (Settings::values.renderer_force_max_clock.GetValue() && device.ShouldBoostClocks()) { + + if (Settings::values.renderer_force_max_clock.GetValue() && device.ShouldBoostClocks()) { turbo_mode.emplace(instance, dld); scheduler.RegisterOnSubmit([this] { turbo_mode->QueueSubmitted(); }); } + // Release ownership from the old instance and surface + instance.release(); + surface.release(); + if (Settings::values.renderer_debug) { + debug_messenger.release(); + } + // Initialize HybridMemory system if (Settings::values.use_gpu_memory_manager.GetValue()) { #if defined(__linux__) || defined(__ANDROID__) || defined(_WIN32) diff --git a/src/video_core/renderer_vulkan/vk_present_manager.cpp b/src/video_core/renderer_vulkan/vk_present_manager.cpp index 5e7518d968..8f5edeae24 100644 --- a/src/video_core/renderer_vulkan/vk_present_manager.cpp +++ b/src/video_core/renderer_vulkan/vk_present_manager.cpp @@ -10,6 +10,7 @@ #include "video_core/renderer_vulkan/vk_swapchain.h" #include "video_core/vulkan_common/vulkan_device.h" #include "video_core/vulkan_common/vulkan_surface.h" +#include "video_core/vulkan_common/vulkan_wrapper.h" namespace Vulkan { @@ -94,14 +95,14 @@ bool CanBlitToSwapchain(const vk::PhysicalDevice& physical_device, VkFormat form } // Anonymous namespace -PresentManager::PresentManager(const vk::Instance& instance_, - Core::Frontend::EmuWindow& render_window_, const Device& device_, - MemoryAllocator& memory_allocator_, Scheduler& scheduler_, - Swapchain& swapchain_, vk::SurfaceKHR& surface_) +PresentManager::PresentManager(const vk::Instance& instance_, Core::Frontend::EmuWindow& render_window_, + const Device& device_, MemoryAllocator& memory_allocator_, Scheduler& scheduler_, + Swapchain& swapchain_, VkSurfaceKHR_T* surface_handle_) : instance{instance_}, render_window{render_window_}, device{device_}, memory_allocator{memory_allocator_}, scheduler{scheduler_}, swapchain{swapchain_}, - surface{surface_}, blit_supported{CanBlitToSwapchain(device.GetPhysical(), - swapchain.GetImageViewFormat())}, + surface_handle{surface_handle_}, + blit_supported{CanBlitToSwapchain(device.GetPhysical(), + swapchain.GetImageViewFormat())}, use_present_thread{Settings::values.async_presentation.GetValue()} { SetImageCount(); @@ -288,7 +289,7 @@ void PresentManager::PresentThread(std::stop_token token) { } void PresentManager::RecreateSwapchain(Frame* frame) { - swapchain.Create(*surface, frame->width, frame->height); + swapchain.Create(surface_handle, frame->width, frame->height); // Pass raw pointer SetImageCount(); } @@ -306,7 +307,6 @@ void PresentManager::CopyToSwapchain(Frame* frame) { try { // Recreate surface and swapchain if needed. if (requires_recreation) { - surface = CreateSurface(instance, render_window.GetWindowInfo()); RecreateSwapchain(frame); } diff --git a/src/video_core/renderer_vulkan/vk_present_manager.h b/src/video_core/renderer_vulkan/vk_present_manager.h index 23ee61c8c5..96850ed56f 100644 --- a/src/video_core/renderer_vulkan/vk_present_manager.h +++ b/src/video_core/renderer_vulkan/vk_present_manager.h @@ -12,6 +12,8 @@ #include "video_core/vulkan_common/vulkan_memory_allocator.h" #include "video_core/vulkan_common/vulkan_wrapper.h" +struct VkSurfaceKHR_T; + namespace Core::Frontend { class EmuWindow; } // namespace Core::Frontend @@ -37,7 +39,7 @@ class PresentManager { public: PresentManager(const vk::Instance& instance, Core::Frontend::EmuWindow& render_window, const Device& device, MemoryAllocator& memory_allocator, Scheduler& scheduler, - Swapchain& swapchain, vk::SurfaceKHR& surface); + Swapchain& swapchain, VkSurfaceKHR_T* surface_handle); ~PresentManager(); /// Returns the last used presentation frame @@ -71,7 +73,7 @@ private: MemoryAllocator& memory_allocator; Scheduler& scheduler; Swapchain& swapchain; - vk::SurfaceKHR& surface; + VkSurfaceKHR_T* surface_handle; vk::CommandPool cmdpool; std::vector frames; std::queue present_queue; diff --git a/src/video_core/renderer_vulkan/vk_swapchain.cpp b/src/video_core/renderer_vulkan/vk_swapchain.cpp index 4f1d3b4e3f..ec96b75036 100644 --- a/src/video_core/renderer_vulkan/vk_swapchain.cpp +++ b/src/video_core/renderer_vulkan/vk_swapchain.cpp @@ -105,23 +105,23 @@ VkCompositeAlphaFlagBitsKHR ChooseAlphaFlags(const VkSurfaceCapabilitiesKHR& cap } // Anonymous namespace -Swapchain::Swapchain(VkSurfaceKHR surface_, const Device& device_, Scheduler& scheduler_, +Swapchain::Swapchain(VkSurfaceKHR_T* surface_handle_, const Device& device_, Scheduler& scheduler_, u32 width_, u32 height_) - : surface{surface_}, device{device_}, scheduler{scheduler_} { - Create(surface_, width_, height_); + : surface_handle{surface_handle_}, device{device_}, scheduler{scheduler_} { + Create(surface_handle, width_, height_); } Swapchain::~Swapchain() = default; -void Swapchain::Create(VkSurfaceKHR surface_, u32 width_, u32 height_) { +void Swapchain::Create(VkSurfaceKHR_T* surface_handle_, u32 width_, u32 height_) { is_outdated = false; is_suboptimal = false; width = width_; height = height_; - surface = surface_; + surface_handle = surface_handle_; const auto physical_device = device.GetPhysical(); - const auto capabilities{physical_device.GetSurfaceCapabilitiesKHR(surface)}; + const auto capabilities{physical_device.GetSurfaceCapabilitiesKHR(surface_handle)}; if (capabilities.maxImageExtent.width == 0 || capabilities.maxImageExtent.height == 0) { return; } @@ -199,8 +199,8 @@ void Swapchain::Present(VkSemaphore render_semaphore) { void Swapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities) { const auto physical_device{device.GetPhysical()}; - const auto formats{physical_device.GetSurfaceFormatsKHR(surface)}; - const auto present_modes = physical_device.GetSurfacePresentModesKHR(surface); + const auto formats{physical_device.GetSurfaceFormatsKHR(surface_handle)}; + const auto present_modes = physical_device.GetSurfacePresentModesKHR(surface_handle); has_mailbox = std::find(present_modes.begin(), present_modes.end(), VK_PRESENT_MODE_MAILBOX_KHR) != present_modes.end(); has_imm = std::find(present_modes.begin(), present_modes.end(), @@ -228,7 +228,7 @@ void Swapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities) { .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, .pNext = nullptr, .flags = 0, - .surface = surface, + .surface = surface_handle, .minImageCount = requested_image_count, .imageFormat = surface_format.format, .imageColorSpace = surface_format.colorSpace, @@ -269,7 +269,7 @@ void Swapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities) { swapchain_ci.flags |= VK_SWAPCHAIN_CREATE_MUTABLE_FORMAT_BIT_KHR; } // Request the size again to reduce the possibility of a TOCTOU race condition. - const auto updated_capabilities = physical_device.GetSurfaceCapabilitiesKHR(surface); + const auto updated_capabilities = physical_device.GetSurfaceCapabilitiesKHR(surface_handle); swapchain_ci.imageExtent = ChooseSwapExtent(updated_capabilities, width, height); // Don't add code within this and the swapchain creation. swapchain = device.GetLogical().CreateSwapchainKHR(swapchain_ci); diff --git a/src/video_core/renderer_vulkan/vk_swapchain.h b/src/video_core/renderer_vulkan/vk_swapchain.h index d264f06e41..f5090c27f4 100644 --- a/src/video_core/renderer_vulkan/vk_swapchain.h +++ b/src/video_core/renderer_vulkan/vk_swapchain.h @@ -8,6 +8,8 @@ #include "common/common_types.h" #include "video_core/vulkan_common/vulkan_wrapper.h" +struct VkSurfaceKHR_T; + namespace Layout { struct FramebufferLayout; } @@ -19,12 +21,12 @@ class Scheduler; class Swapchain { public: - explicit Swapchain(VkSurfaceKHR surface, const Device& device, Scheduler& scheduler, u32 width, + explicit Swapchain(VkSurfaceKHR_T* surface_handle, const Device& device, Scheduler& scheduler, u32 width, u32 height); ~Swapchain(); /// Creates (or recreates) the swapchain with a given size. - void Create(VkSurfaceKHR surface, u32 width, u32 height); + void Create(VkSurfaceKHR_T* surface_handle, u32 width, u32 height); /// Acquires the next image in the swapchain, waits as needed. bool AcquireNextImage(); @@ -108,7 +110,7 @@ private: bool NeedsPresentModeUpdate() const; - VkSurfaceKHR surface; + VkSurfaceKHR_T* surface_handle; const Device& device; Scheduler& scheduler; diff --git a/src/video_core/vulkan_common/vulkan_wrapper.h b/src/video_core/vulkan_common/vulkan_wrapper.h index 1bb8a47bdf..aa9fb8e17b 100644 --- a/src/video_core/vulkan_common/vulkan_wrapper.h +++ b/src/video_core/vulkan_common/vulkan_wrapper.h @@ -430,6 +430,15 @@ public: return handle != nullptr; } + /** + * Releases ownership of the managed handle. + * The caller is responsible for managing the lifetime of the returned handle. + * The Handle object becomes invalid after this call. + */ + Type release() noexcept { + return std::exchange(handle, nullptr); + } + protected: Type handle = nullptr; OwnerType owner = nullptr; @@ -501,6 +510,15 @@ public: return handle != nullptr; } + /** + * Releases ownership of the managed handle. + * The caller is responsible for managing the lifetime of the returned handle. + * The Handle object becomes invalid after this call. + */ + Type release() noexcept { + return std::exchange(handle, nullptr); + } + protected: Type handle = nullptr; const Dispatch* dld = nullptr;