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: #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:
parent
0d034ba584
commit
3fe0cbe3fb
6 changed files with 57 additions and 26 deletions
|
@ -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)
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue