renderer_vulkan: Use raw surface handles and improve release logic (#75)
All checks were successful
eden-build / source (push) Successful in 4m52s
eden-build / linux (push) Successful in 24m55s
eden-build / android (push) Successful in 17m21s
eden-build / windows (msvc) (push) Successful in 1h8m31s

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: #75
Co-authored-by: Briar <205427297+icy-briar@users.noreply.github.com>
Co-committed-by: Briar <205427297+icy-briar@users.noreply.github.com>
This commit is contained in:
Briar 2025-05-02 18:42:58 +00:00 committed by CamilleLaVey
parent 0d034ba584
commit 3fe0cbe3fb
6 changed files with 57 additions and 26 deletions

View file

@ -120,12 +120,13 @@ RendererVulkan::RendererVulkan(Core::Frontend::EmuWindow& emu_window,
// Create surface // Create surface
surface(CreateSurface(instance, render_window.GetWindowInfo())), surface(CreateSurface(instance, render_window.GetWindowInfo())),
managed_surface(MakeManagedSurface(surface, instance, dld)), 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), scheduler(device, state_tracker),
swapchain(*surface, device, scheduler, render_window.GetFramebufferLayout().width, swapchain(*surface, device, scheduler, render_window.GetFramebufferLayout().width,
render_window.GetFramebufferLayout().height), render_window.GetFramebufferLayout().height),
present_manager(instance, render_window, device, memory_allocator, scheduler, swapchain, present_manager(instance, render_window, device, memory_allocator, scheduler, swapchain,
surface), *surface),
blit_swapchain(device_memory, device, memory_allocator, present_manager, scheduler, blit_swapchain(device_memory, device, memory_allocator, present_manager, scheduler,
PresentFiltersForDisplay), PresentFiltersForDisplay),
blit_capture(device_memory, device, memory_allocator, present_manager, scheduler, blit_capture(device_memory, device, memory_allocator, present_manager, scheduler,
@ -136,11 +137,19 @@ RendererVulkan::RendererVulkan(Core::Frontend::EmuWindow& emu_window,
scheduler), scheduler),
hybrid_memory(std::make_unique<HybridMemory>(device, memory_allocator)), hybrid_memory(std::make_unique<HybridMemory>(device, memory_allocator)),
applet_frame() { 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); turbo_mode.emplace(instance, dld);
scheduler.RegisterOnSubmit([this] { turbo_mode->QueueSubmitted(); }); 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 // Initialize HybridMemory system
if (Settings::values.use_gpu_memory_manager.GetValue()) { if (Settings::values.use_gpu_memory_manager.GetValue()) {
#if defined(__linux__) || defined(__ANDROID__) || defined(_WIN32) #if defined(__linux__) || defined(__ANDROID__) || defined(_WIN32)

View file

@ -10,6 +10,7 @@
#include "video_core/renderer_vulkan/vk_swapchain.h" #include "video_core/renderer_vulkan/vk_swapchain.h"
#include "video_core/vulkan_common/vulkan_device.h" #include "video_core/vulkan_common/vulkan_device.h"
#include "video_core/vulkan_common/vulkan_surface.h" #include "video_core/vulkan_common/vulkan_surface.h"
#include "video_core/vulkan_common/vulkan_wrapper.h"
namespace Vulkan { namespace Vulkan {
@ -94,13 +95,13 @@ bool CanBlitToSwapchain(const vk::PhysicalDevice& physical_device, VkFormat form
} // Anonymous namespace } // Anonymous namespace
PresentManager::PresentManager(const vk::Instance& instance_, PresentManager::PresentManager(const vk::Instance& instance_, Core::Frontend::EmuWindow& render_window_,
Core::Frontend::EmuWindow& render_window_, const Device& device_, const Device& device_, MemoryAllocator& memory_allocator_, Scheduler& scheduler_,
MemoryAllocator& memory_allocator_, Scheduler& scheduler_, Swapchain& swapchain_, VkSurfaceKHR_T* surface_handle_)
Swapchain& swapchain_, vk::SurfaceKHR& surface_)
: instance{instance_}, render_window{render_window_}, device{device_}, : instance{instance_}, render_window{render_window_}, device{device_},
memory_allocator{memory_allocator_}, scheduler{scheduler_}, swapchain{swapchain_}, memory_allocator{memory_allocator_}, scheduler{scheduler_}, swapchain{swapchain_},
surface{surface_}, blit_supported{CanBlitToSwapchain(device.GetPhysical(), surface_handle{surface_handle_},
blit_supported{CanBlitToSwapchain(device.GetPhysical(),
swapchain.GetImageViewFormat())}, swapchain.GetImageViewFormat())},
use_present_thread{Settings::values.async_presentation.GetValue()} { use_present_thread{Settings::values.async_presentation.GetValue()} {
SetImageCount(); SetImageCount();
@ -288,7 +289,7 @@ void PresentManager::PresentThread(std::stop_token token) {
} }
void PresentManager::RecreateSwapchain(Frame* frame) { void PresentManager::RecreateSwapchain(Frame* frame) {
swapchain.Create(*surface, frame->width, frame->height); swapchain.Create(surface_handle, frame->width, frame->height); // Pass raw pointer
SetImageCount(); SetImageCount();
} }
@ -306,7 +307,6 @@ void PresentManager::CopyToSwapchain(Frame* frame) {
try { try {
// Recreate surface and swapchain if needed. // Recreate surface and swapchain if needed.
if (requires_recreation) { if (requires_recreation) {
surface = CreateSurface(instance, render_window.GetWindowInfo());
RecreateSwapchain(frame); RecreateSwapchain(frame);
} }

View file

@ -12,6 +12,8 @@
#include "video_core/vulkan_common/vulkan_memory_allocator.h" #include "video_core/vulkan_common/vulkan_memory_allocator.h"
#include "video_core/vulkan_common/vulkan_wrapper.h" #include "video_core/vulkan_common/vulkan_wrapper.h"
struct VkSurfaceKHR_T;
namespace Core::Frontend { namespace Core::Frontend {
class EmuWindow; class EmuWindow;
} // namespace Core::Frontend } // namespace Core::Frontend
@ -37,7 +39,7 @@ class PresentManager {
public: public:
PresentManager(const vk::Instance& instance, Core::Frontend::EmuWindow& render_window, PresentManager(const vk::Instance& instance, Core::Frontend::EmuWindow& render_window,
const Device& device, MemoryAllocator& memory_allocator, Scheduler& scheduler, const Device& device, MemoryAllocator& memory_allocator, Scheduler& scheduler,
Swapchain& swapchain, vk::SurfaceKHR& surface); Swapchain& swapchain, VkSurfaceKHR_T* surface_handle);
~PresentManager(); ~PresentManager();
/// Returns the last used presentation frame /// Returns the last used presentation frame
@ -71,7 +73,7 @@ private:
MemoryAllocator& memory_allocator; MemoryAllocator& memory_allocator;
Scheduler& scheduler; Scheduler& scheduler;
Swapchain& swapchain; Swapchain& swapchain;
vk::SurfaceKHR& surface; VkSurfaceKHR_T* surface_handle;
vk::CommandPool cmdpool; vk::CommandPool cmdpool;
std::vector<Frame> frames; std::vector<Frame> frames;
std::queue<Frame*> present_queue; std::queue<Frame*> present_queue;

View file

@ -105,23 +105,23 @@ VkCompositeAlphaFlagBitsKHR ChooseAlphaFlags(const VkSurfaceCapabilitiesKHR& cap
} // Anonymous namespace } // 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_) u32 width_, u32 height_)
: surface{surface_}, device{device_}, scheduler{scheduler_} { : surface_handle{surface_handle_}, device{device_}, scheduler{scheduler_} {
Create(surface_, width_, height_); Create(surface_handle, width_, height_);
} }
Swapchain::~Swapchain() = default; 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_outdated = false;
is_suboptimal = false; is_suboptimal = false;
width = width_; width = width_;
height = height_; height = height_;
surface = surface_; surface_handle = surface_handle_;
const auto physical_device = device.GetPhysical(); 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) { if (capabilities.maxImageExtent.width == 0 || capabilities.maxImageExtent.height == 0) {
return; return;
} }
@ -199,8 +199,8 @@ void Swapchain::Present(VkSemaphore render_semaphore) {
void Swapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities) { void Swapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities) {
const auto physical_device{device.GetPhysical()}; const auto physical_device{device.GetPhysical()};
const auto formats{physical_device.GetSurfaceFormatsKHR(surface)}; const auto formats{physical_device.GetSurfaceFormatsKHR(surface_handle)};
const auto present_modes = physical_device.GetSurfacePresentModesKHR(surface); const auto present_modes = physical_device.GetSurfacePresentModesKHR(surface_handle);
has_mailbox = std::find(present_modes.begin(), present_modes.end(), has_mailbox = std::find(present_modes.begin(), present_modes.end(),
VK_PRESENT_MODE_MAILBOX_KHR) != present_modes.end(); VK_PRESENT_MODE_MAILBOX_KHR) != present_modes.end();
has_imm = std::find(present_modes.begin(), 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, .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
.pNext = nullptr, .pNext = nullptr,
.flags = 0, .flags = 0,
.surface = surface, .surface = surface_handle,
.minImageCount = requested_image_count, .minImageCount = requested_image_count,
.imageFormat = surface_format.format, .imageFormat = surface_format.format,
.imageColorSpace = surface_format.colorSpace, .imageColorSpace = surface_format.colorSpace,
@ -269,7 +269,7 @@ void Swapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities) {
swapchain_ci.flags |= VK_SWAPCHAIN_CREATE_MUTABLE_FORMAT_BIT_KHR; swapchain_ci.flags |= VK_SWAPCHAIN_CREATE_MUTABLE_FORMAT_BIT_KHR;
} }
// Request the size again to reduce the possibility of a TOCTOU race condition. // 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); swapchain_ci.imageExtent = ChooseSwapExtent(updated_capabilities, width, height);
// Don't add code within this and the swapchain creation. // Don't add code within this and the swapchain creation.
swapchain = device.GetLogical().CreateSwapchainKHR(swapchain_ci); swapchain = device.GetLogical().CreateSwapchainKHR(swapchain_ci);

View file

@ -8,6 +8,8 @@
#include "common/common_types.h" #include "common/common_types.h"
#include "video_core/vulkan_common/vulkan_wrapper.h" #include "video_core/vulkan_common/vulkan_wrapper.h"
struct VkSurfaceKHR_T;
namespace Layout { namespace Layout {
struct FramebufferLayout; struct FramebufferLayout;
} }
@ -19,12 +21,12 @@ class Scheduler;
class Swapchain { class Swapchain {
public: 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); u32 height);
~Swapchain(); ~Swapchain();
/// Creates (or recreates) the swapchain with a given size. /// 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. /// Acquires the next image in the swapchain, waits as needed.
bool AcquireNextImage(); bool AcquireNextImage();
@ -108,7 +110,7 @@ private:
bool NeedsPresentModeUpdate() const; bool NeedsPresentModeUpdate() const;
VkSurfaceKHR surface; VkSurfaceKHR_T* surface_handle;
const Device& device; const Device& device;
Scheduler& scheduler; Scheduler& scheduler;

View file

@ -430,6 +430,15 @@ public:
return handle != nullptr; 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: protected:
Type handle = nullptr; Type handle = nullptr;
OwnerType owner = nullptr; OwnerType owner = nullptr;
@ -501,6 +510,15 @@ public:
return handle != nullptr; 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: protected:
Type handle = nullptr; Type handle = nullptr;
const Dispatch* dld = nullptr; const Dispatch* dld = nullptr;