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
cb8f449dca
commit
559eb0a488
6 changed files with 57 additions and 26 deletions
|
@ -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<HybridMemory>(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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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<Frame> frames;
|
||||
std::queue<Frame*> present_queue;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue