mirror of
https://github.com/RPCS3/rpcs3.git
synced 2024-11-25 12:12:50 +01:00
rsx: Clean up window management code
- Removes a lot of wm_event code that was used to perform window management and is no longer needed. - Significantly simplifies the vulkan code. - Implements resource management when vulkan window is minimized to allow resources to be freed.
This commit is contained in:
parent
57196f0504
commit
d361eedbec
@ -1,4 +1,4 @@
|
|||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "stdafx_d3d12.h"
|
#include "stdafx_d3d12.h"
|
||||||
#include "D3D12GSRender.h"
|
#include "D3D12GSRender.h"
|
||||||
@ -308,12 +308,6 @@ void D3D12GSRender::on_exit()
|
|||||||
|
|
||||||
void D3D12GSRender::do_local_task(rsx::FIFO_state state)
|
void D3D12GSRender::do_local_task(rsx::FIFO_state state)
|
||||||
{
|
{
|
||||||
if (state != rsx::FIFO_state::lock_wait)
|
|
||||||
{
|
|
||||||
//TODO
|
|
||||||
m_frame->clear_wm_events();
|
|
||||||
}
|
|
||||||
|
|
||||||
rsx::thread::do_local_task(state);
|
rsx::thread::do_local_task(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -939,12 +939,8 @@ void GLGSRender::on_init_thread()
|
|||||||
|
|
||||||
if (!supports_native_ui)
|
if (!supports_native_ui)
|
||||||
{
|
{
|
||||||
m_frame->disable_wm_event_queue();
|
|
||||||
m_frame->hide();
|
m_frame->hide();
|
||||||
|
|
||||||
m_shaders_cache->load(nullptr);
|
m_shaders_cache->load(nullptr);
|
||||||
|
|
||||||
m_frame->enable_wm_event_queue();
|
|
||||||
m_frame->show();
|
m_frame->show();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -1004,7 +1000,6 @@ void GLGSRender::on_init_thread()
|
|||||||
}
|
}
|
||||||
helper(this);
|
helper(this);
|
||||||
|
|
||||||
m_frame->enable_wm_event_queue();
|
|
||||||
m_shaders_cache->load(&helper);
|
m_shaders_cache->load(&helper);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1918,8 +1913,6 @@ void GLGSRender::do_local_task(rsx::FIFO_state state)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_frame->clear_wm_events();
|
|
||||||
|
|
||||||
if (m_overlay_manager)
|
if (m_overlay_manager)
|
||||||
{
|
{
|
||||||
if (!in_begin_end && async_flip_requested & flip_request::native_ui)
|
if (!in_begin_end && async_flip_requested & flip_request::native_ui)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "Emu/Memory/vm.h"
|
#include "Emu/Memory/vm.h"
|
||||||
#include "Emu/System.h"
|
#include "Emu/System.h"
|
||||||
|
|
||||||
@ -41,8 +41,6 @@ void GSRender::on_exit()
|
|||||||
{
|
{
|
||||||
if (m_frame)
|
if (m_frame)
|
||||||
{
|
{
|
||||||
m_frame->disable_wm_event_queue();
|
|
||||||
m_frame->clear_wm_events();
|
|
||||||
m_frame->delete_context(m_context);
|
m_frame->delete_context(m_context);
|
||||||
m_context = nullptr;
|
m_context = nullptr;
|
||||||
}
|
}
|
||||||
|
@ -84,78 +84,6 @@ using draw_context_t = void*;
|
|||||||
virtual int client_height() = 0;
|
virtual int client_height() = 0;
|
||||||
|
|
||||||
virtual display_handle_t handle() const = 0;
|
virtual display_handle_t handle() const = 0;
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
// window manager event management
|
|
||||||
std::deque<wm_event> m_raised_events;
|
|
||||||
std::atomic_bool wm_event_queue_enabled = {};
|
|
||||||
std::atomic_bool wm_allow_fullscreen = { true };
|
|
||||||
|
|
||||||
public:
|
|
||||||
// synchronize native window access
|
|
||||||
shared_mutex wm_event_lock;
|
|
||||||
|
|
||||||
void wm_wait() const
|
|
||||||
{
|
|
||||||
while (!m_raised_events.empty() && !Emu.IsStopped()) _mm_pause();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool has_wm_events() const
|
|
||||||
{
|
|
||||||
return !m_raised_events.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
void clear_wm_events()
|
|
||||||
{
|
|
||||||
if (!m_raised_events.empty())
|
|
||||||
{
|
|
||||||
std::lock_guard lock(wm_event_lock);
|
|
||||||
m_raised_events.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void push_wm_event(wm_event&& _event)
|
|
||||||
{
|
|
||||||
std::lock_guard lock(wm_event_lock);
|
|
||||||
m_raised_events.push_back(_event);
|
|
||||||
}
|
|
||||||
|
|
||||||
wm_event get_wm_event()
|
|
||||||
{
|
|
||||||
if (m_raised_events.empty())
|
|
||||||
{
|
|
||||||
return wm_event::none;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
std::lock_guard lock(wm_event_lock);
|
|
||||||
|
|
||||||
const auto _event = m_raised_events.front();
|
|
||||||
m_raised_events.pop_front();
|
|
||||||
return _event;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void disable_wm_event_queue()
|
|
||||||
{
|
|
||||||
wm_event_queue_enabled.store(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void enable_wm_event_queue()
|
|
||||||
{
|
|
||||||
wm_event_queue_enabled.store(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void disable_wm_fullscreen()
|
|
||||||
{
|
|
||||||
wm_allow_fullscreen.store(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void enable_wm_fullscreen()
|
|
||||||
{
|
|
||||||
wm_allow_fullscreen.store(true);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class GSRender : public rsx::thread
|
class GSRender : public rsx::thread
|
||||||
|
@ -444,10 +444,13 @@ VKGSRender::VKGSRender() : GSRender()
|
|||||||
vk::set_current_thread_ctx(m_thread_context);
|
vk::set_current_thread_ctx(m_thread_context);
|
||||||
vk::set_current_renderer(m_swapchain->get_device());
|
vk::set_current_renderer(m_swapchain->get_device());
|
||||||
|
|
||||||
m_client_width = m_frame->client_width();
|
m_swapchain_dims.width = m_frame->client_width();
|
||||||
m_client_height = m_frame->client_height();
|
m_swapchain_dims.height = m_frame->client_height();
|
||||||
if (!m_swapchain->init(m_client_width, m_client_height))
|
|
||||||
present_surface_dirty_flag = true;
|
if (!m_swapchain->init(m_swapchain_dims.width, m_swapchain_dims.height))
|
||||||
|
{
|
||||||
|
swapchain_unavailable = true;
|
||||||
|
}
|
||||||
|
|
||||||
//create command buffer...
|
//create command buffer...
|
||||||
m_command_buffer_pool.create((*m_device));
|
m_command_buffer_pool.create((*m_device));
|
||||||
@ -896,113 +899,6 @@ void VKGSRender::check_descriptors()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VKGSRender::check_window_status()
|
|
||||||
{
|
|
||||||
if (m_swapchain->supports_automatic_wm_reports())
|
|
||||||
{
|
|
||||||
// This driver will report window events as VK_ERROR_OUT_OF_DATE_KHR
|
|
||||||
m_frame->clear_wm_events();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
|
|
||||||
if (LIKELY(!m_frame->has_wm_events()))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (const auto _event = m_frame->get_wm_event())
|
|
||||||
{
|
|
||||||
switch (_event)
|
|
||||||
{
|
|
||||||
case wm_event::toggle_fullscreen:
|
|
||||||
{
|
|
||||||
renderer_unavailable = true;
|
|
||||||
m_frame->enable_wm_fullscreen();
|
|
||||||
m_frame->toggle_fullscreen();
|
|
||||||
m_frame->disable_wm_fullscreen();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case wm_event::geometry_change_notice:
|
|
||||||
{
|
|
||||||
// Stall until finish notification is received. Also, raise surface dirty flag
|
|
||||||
u32 timeout = 1000;
|
|
||||||
bool handled = false;
|
|
||||||
|
|
||||||
while (timeout)
|
|
||||||
{
|
|
||||||
switch (m_frame->get_wm_event())
|
|
||||||
{
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
case wm_event::window_resized:
|
|
||||||
handled = true;
|
|
||||||
present_surface_dirty_flag = true;
|
|
||||||
break;
|
|
||||||
case wm_event::geometry_change_in_progress:
|
|
||||||
timeout += 10; // Extend timeout to wait for user to finish resizing
|
|
||||||
break;
|
|
||||||
case wm_event::window_restored:
|
|
||||||
case wm_event::window_visibility_changed:
|
|
||||||
case wm_event::window_minimized:
|
|
||||||
case wm_event::window_moved:
|
|
||||||
handled = true; // Ignore these events as they do not alter client area
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (handled)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Wait for window manager event
|
|
||||||
std::this_thread::sleep_for(1ms);
|
|
||||||
timeout --;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!timeout)
|
|
||||||
{
|
|
||||||
LOG_ERROR(RSX, "wm event handler timed out");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reset renderer availability if something has changed about the window
|
|
||||||
renderer_unavailable = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case wm_event::window_resized:
|
|
||||||
{
|
|
||||||
LOG_ERROR(RSX, "wm_event::window_resized received without corresponding wm_event::geometry_change_notice!");
|
|
||||||
std::this_thread::sleep_for(100ms);
|
|
||||||
renderer_unavailable = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
// If the queue is in use, it should be properly consumed
|
|
||||||
verify(HERE), !m_frame->has_wm_events();
|
|
||||||
|
|
||||||
const auto frame_width = m_frame->client_width();
|
|
||||||
const auto frame_height = m_frame->client_height();
|
|
||||||
|
|
||||||
if (m_client_height != frame_height ||
|
|
||||||
m_client_width != frame_width)
|
|
||||||
{
|
|
||||||
if (!!frame_width && !!frame_height)
|
|
||||||
{
|
|
||||||
present_surface_dirty_flag = true;
|
|
||||||
renderer_unavailable = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
VkDescriptorSet VKGSRender::allocate_descriptor_set()
|
VkDescriptorSet VKGSRender::allocate_descriptor_set()
|
||||||
{
|
{
|
||||||
verify(HERE), m_current_frame->used_descriptors < DESCRIPTOR_MAX_DRAW_CALLS;
|
verify(HERE), m_current_frame->used_descriptors < DESCRIPTOR_MAX_DRAW_CALLS;
|
||||||
@ -1024,7 +920,7 @@ void VKGSRender::begin()
|
|||||||
{
|
{
|
||||||
rsx::thread::begin();
|
rsx::thread::begin();
|
||||||
|
|
||||||
if (skip_frame || renderer_unavailable ||
|
if (skip_frame || swapchain_unavailable ||
|
||||||
(conditional_render_enabled && conditional_render_test_failed))
|
(conditional_render_enabled && conditional_render_test_failed))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -1300,7 +1196,7 @@ void VKGSRender::emit_geometry(u32 sub_index)
|
|||||||
|
|
||||||
void VKGSRender::end()
|
void VKGSRender::end()
|
||||||
{
|
{
|
||||||
if (skip_frame || !framebuffer_status_valid || renderer_unavailable ||
|
if (skip_frame || !framebuffer_status_valid || swapchain_unavailable ||
|
||||||
(conditional_render_enabled && conditional_render_test_failed))
|
(conditional_render_enabled && conditional_render_test_failed))
|
||||||
{
|
{
|
||||||
execute_nop_draw();
|
execute_nop_draw();
|
||||||
@ -1876,10 +1772,8 @@ void VKGSRender::on_init_thread()
|
|||||||
|
|
||||||
if (!supports_native_ui)
|
if (!supports_native_ui)
|
||||||
{
|
{
|
||||||
m_frame->disable_wm_event_queue();
|
|
||||||
m_frame->hide();
|
m_frame->hide();
|
||||||
m_shaders_cache->load(nullptr, *m_device, pipeline_layout);
|
m_shaders_cache->load(nullptr, *m_device, pipeline_layout);
|
||||||
m_frame->enable_wm_event_queue();
|
|
||||||
m_frame->show();
|
m_frame->show();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -1939,18 +1833,8 @@ void VKGSRender::on_init_thread()
|
|||||||
}
|
}
|
||||||
helper(this);
|
helper(this);
|
||||||
|
|
||||||
//TODO: Handle window resize messages during loading on GPUs without OUT_OF_DATE_KHR support
|
// TODO: Handle window resize messages during loading on GPUs without OUT_OF_DATE_KHR support
|
||||||
m_frame->disable_wm_event_queue();
|
|
||||||
m_shaders_cache->load(&helper, *m_device, pipeline_layout);
|
m_shaders_cache->load(&helper, *m_device, pipeline_layout);
|
||||||
m_frame->enable_wm_event_queue();
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
if (!m_swapchain->supports_automatic_wm_reports())
|
|
||||||
{
|
|
||||||
// If the renderer does not handle WM events itself, switching to fullscreen is done by the renderer, not the UI
|
|
||||||
m_frame->disable_wm_fullscreen();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1962,7 +1846,7 @@ void VKGSRender::on_exit()
|
|||||||
|
|
||||||
void VKGSRender::clear_surface(u32 mask)
|
void VKGSRender::clear_surface(u32 mask)
|
||||||
{
|
{
|
||||||
if (skip_frame || renderer_unavailable) return;
|
if (skip_frame || swapchain_unavailable) return;
|
||||||
|
|
||||||
// If stencil write mask is disabled, remove clear_stencil bit
|
// If stencil write mask is disabled, remove clear_stencil bit
|
||||||
if (!rsx::method_registers.stencil_mask()) mask &= ~0x2u;
|
if (!rsx::method_registers.stencil_mask()) mask &= ~0x2u;
|
||||||
@ -2261,7 +2145,7 @@ void VKGSRender::present(frame_context_t *ctx)
|
|||||||
{
|
{
|
||||||
verify(HERE), ctx->present_image != UINT32_MAX;
|
verify(HERE), ctx->present_image != UINT32_MAX;
|
||||||
|
|
||||||
if (!present_surface_dirty_flag)
|
if (!swapchain_unavailable)
|
||||||
{
|
{
|
||||||
switch (VkResult error = m_swapchain->present(ctx->present_wait_semaphore, ctx->present_image))
|
switch (VkResult error = m_swapchain->present(ctx->present_wait_semaphore, ctx->present_image))
|
||||||
{
|
{
|
||||||
@ -2270,7 +2154,7 @@ void VKGSRender::present(frame_context_t *ctx)
|
|||||||
case VK_SUBOPTIMAL_KHR:
|
case VK_SUBOPTIMAL_KHR:
|
||||||
break;
|
break;
|
||||||
case VK_ERROR_OUT_OF_DATE_KHR:
|
case VK_ERROR_OUT_OF_DATE_KHR:
|
||||||
present_surface_dirty_flag = true;
|
swapchain_unavailable = true;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
vk::die_with_error(HERE, error);
|
vk::die_with_error(HERE, error);
|
||||||
@ -2323,9 +2207,8 @@ void VKGSRender::frame_context_cleanup(frame_context_t *ctx, bool free_resources
|
|||||||
// Perform hard swap here
|
// Perform hard swap here
|
||||||
if (ctx->swap_command_buffer->wait(FRAME_PRESENT_TIMEOUT) != VK_SUCCESS)
|
if (ctx->swap_command_buffer->wait(FRAME_PRESENT_TIMEOUT) != VK_SUCCESS)
|
||||||
{
|
{
|
||||||
// Lost surface, release renderer
|
// Lost surface/device, release swapchain
|
||||||
present_surface_dirty_flag = true;
|
swapchain_unavailable = true;
|
||||||
renderer_unavailable = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
free_resources = true;
|
free_resources = true;
|
||||||
@ -2447,8 +2330,6 @@ void VKGSRender::do_local_task(rsx::FIFO_state state)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
check_window_status();
|
|
||||||
|
|
||||||
if (m_overlay_manager)
|
if (m_overlay_manager)
|
||||||
{
|
{
|
||||||
if (!in_begin_end && async_flip_requested & flip_request::native_ui)
|
if (!in_begin_end && async_flip_requested & flip_request::native_ui)
|
||||||
@ -3046,14 +2927,17 @@ void VKGSRender::prepare_rtts(rsx::framebuffer_creation_context context)
|
|||||||
|
|
||||||
void VKGSRender::reinitialize_swapchain()
|
void VKGSRender::reinitialize_swapchain()
|
||||||
{
|
{
|
||||||
const auto new_width = m_frame->client_width();
|
m_swapchain_dims.width = m_frame->client_width();
|
||||||
const auto new_height = m_frame->client_height();
|
m_swapchain_dims.height = m_frame->client_height();
|
||||||
|
|
||||||
// Reject requests to acquire new swapchain if the window is minimized
|
// Reject requests to acquire new swapchain if the window is minimized
|
||||||
// The NVIDIA driver will spam VK_ERROR_OUT_OF_DATE_KHR if you try to acquire an image from the swapchain and the window is minimized
|
// The NVIDIA driver will spam VK_ERROR_OUT_OF_DATE_KHR if you try to acquire an image from the swapchain and the window is minimized
|
||||||
// However, any attempt to actually renew the swapchain will crash the driver with VK_ERROR_DEVICE_LOST while the window is in this state
|
// However, any attempt to actually renew the swapchain will crash the driver with VK_ERROR_DEVICE_LOST while the window is in this state
|
||||||
if (new_width == 0 || new_height == 0)
|
if (m_swapchain_dims.width == 0 || m_swapchain_dims.height == 0)
|
||||||
|
{
|
||||||
|
swapchain_unavailable = true;
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// NOTE: This operation will create a hard sync point
|
// NOTE: This operation will create a hard sync point
|
||||||
close_and_submit_command_buffer(m_current_command_buffer->submit_fence);
|
close_and_submit_command_buffer(m_current_command_buffer->submit_fence);
|
||||||
@ -3073,18 +2957,14 @@ void VKGSRender::reinitialize_swapchain()
|
|||||||
vkDeviceWaitIdle(*m_device);
|
vkDeviceWaitIdle(*m_device);
|
||||||
|
|
||||||
// Rebuild swapchain. Old swapchain destruction is handled by the init_swapchain call
|
// Rebuild swapchain. Old swapchain destruction is handled by the init_swapchain call
|
||||||
if (!m_swapchain->init(new_width, new_height))
|
if (!m_swapchain->init(m_swapchain_dims.width, m_swapchain_dims.height))
|
||||||
{
|
{
|
||||||
LOG_WARNING(RSX, "Swapchain initialization failed. Request ignored [%dx%d]", new_width, new_height);
|
LOG_WARNING(RSX, "Swapchain initialization failed. Request ignored [%dx%d]", m_swapchain_dims.width, m_swapchain_dims.height);
|
||||||
present_surface_dirty_flag = true;
|
swapchain_unavailable = true;
|
||||||
renderer_unavailable = true;
|
|
||||||
open_command_buffer();
|
open_command_buffer();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_client_width = new_width;
|
|
||||||
m_client_height = new_height;
|
|
||||||
|
|
||||||
// Prepare new swapchain images for use
|
// Prepare new swapchain images for use
|
||||||
open_command_buffer();
|
open_command_buffer();
|
||||||
|
|
||||||
@ -3115,26 +2995,24 @@ void VKGSRender::reinitialize_swapchain()
|
|||||||
m_current_command_buffer->reset();
|
m_current_command_buffer->reset();
|
||||||
open_command_buffer();
|
open_command_buffer();
|
||||||
|
|
||||||
present_surface_dirty_flag = false;
|
swapchain_unavailable = false;
|
||||||
renderer_unavailable = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VKGSRender::flip(int buffer, bool emu_flip)
|
void VKGSRender::flip(int buffer, bool emu_flip)
|
||||||
{
|
{
|
||||||
if (skip_frame || renderer_unavailable)
|
// Check swapchain condition/status
|
||||||
|
if (!m_swapchain->supports_automatic_wm_reports())
|
||||||
{
|
{
|
||||||
m_frame->flip(m_context);
|
if (m_swapchain_dims.width != m_frame->client_width() ||
|
||||||
rsx::thread::flip(buffer, emu_flip);
|
m_swapchain_dims.height != m_frame->client_height())
|
||||||
|
|
||||||
if (!skip_frame)
|
|
||||||
{
|
{
|
||||||
m_draw_time = 0;
|
swapchain_unavailable = true;
|
||||||
m_setup_time = 0;
|
|
||||||
m_vertex_upload_time = 0;
|
|
||||||
m_textures_upload_time = 0;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
if (swapchain_unavailable)
|
||||||
|
{
|
||||||
|
reinitialize_swapchain();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::chrono::time_point<steady_clock> flip_start = steady_clock::now();
|
std::chrono::time_point<steady_clock> flip_start = steady_clock::now();
|
||||||
@ -3156,7 +3034,7 @@ void VKGSRender::flip(int buffer, bool emu_flip)
|
|||||||
{
|
{
|
||||||
if (m_draw_calls > 0)
|
if (m_draw_calls > 0)
|
||||||
{
|
{
|
||||||
// This can be 'legal' if the window was being resized and no polling happened because of renderer_unavailable flag
|
// This can be 'legal' if the window was being resized and no polling happened because of swapchain_unavailable flag
|
||||||
LOG_ERROR(RSX, "Possible data corruption on frame context storage detected");
|
LOG_ERROR(RSX, "Possible data corruption on frame context storage detected");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3164,14 +3042,29 @@ void VKGSRender::flip(int buffer, bool emu_flip)
|
|||||||
frame_context_cleanup(m_current_frame, true);
|
frame_context_cleanup(m_current_frame, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (present_surface_dirty_flag)
|
if (skip_frame || swapchain_unavailable)
|
||||||
{
|
{
|
||||||
//Recreate swapchain and continue as usual
|
m_frame->flip(m_context);
|
||||||
reinitialize_swapchain();
|
rsx::thread::flip(buffer, emu_flip);
|
||||||
}
|
|
||||||
|
if (!skip_frame)
|
||||||
|
{
|
||||||
|
verify(HERE), swapchain_unavailable;
|
||||||
|
|
||||||
|
// Perform a mini-flip here without invoking present code
|
||||||
|
m_current_frame->swap_command_buffer = m_current_command_buffer;
|
||||||
|
flush_command_queue(true);
|
||||||
|
vk::advance_frame_counter();
|
||||||
|
frame_context_cleanup(m_current_frame, true);
|
||||||
|
|
||||||
|
m_draw_time = 0;
|
||||||
|
m_setup_time = 0;
|
||||||
|
m_vertex_upload_time = 0;
|
||||||
|
m_textures_upload_time = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (renderer_unavailable)
|
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
u32 buffer_width = display_buffers[buffer].width;
|
u32 buffer_width = display_buffers[buffer].width;
|
||||||
u32 buffer_height = display_buffers[buffer].height;
|
u32 buffer_height = display_buffers[buffer].height;
|
||||||
@ -3196,7 +3089,7 @@ void VKGSRender::flip(int buffer, bool emu_flip)
|
|||||||
|
|
||||||
coordi aspect_ratio;
|
coordi aspect_ratio;
|
||||||
|
|
||||||
sizei csize = { (s32)m_client_width, (s32)m_client_height };
|
sizei csize = m_swapchain_dims;
|
||||||
sizei new_size = csize;
|
sizei new_size = csize;
|
||||||
|
|
||||||
if (!g_cfg.video.stretch_to_display_area)
|
if (!g_cfg.video.stretch_to_display_area)
|
||||||
@ -3237,17 +3130,17 @@ void VKGSRender::flip(int buffer, bool emu_flip)
|
|||||||
//This makes fullscreen performance slower than windowed performance as throughput is lowered due to losing one presentable image
|
//This makes fullscreen performance slower than windowed performance as throughput is lowered due to losing one presentable image
|
||||||
//Found on AMD Crimson 17.7.2
|
//Found on AMD Crimson 17.7.2
|
||||||
|
|
||||||
|
|
||||||
//Whatever returned from status, this is now a spin
|
//Whatever returned from status, this is now a spin
|
||||||
timeout = 0ull;
|
timeout = 0ull;
|
||||||
check_present_status();
|
check_present_status();
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
case VK_ERROR_OUT_OF_DATE_KHR:
|
case VK_ERROR_OUT_OF_DATE_KHR:
|
||||||
LOG_WARNING(RSX, "vkAcquireNextImageKHR failed with VK_ERROR_OUT_OF_DATE_KHR. Flip request ignored until surface is recreated.");
|
LOG_WARNING(RSX, "vkAcquireNextImageKHR failed with VK_ERROR_OUT_OF_DATE_KHR. Flip request ignored until surface is recreated.");
|
||||||
present_surface_dirty_flag = true;
|
swapchain_unavailable = true;
|
||||||
reinitialize_swapchain();
|
reinitialize_swapchain();
|
||||||
return;
|
continue;
|
||||||
default:
|
default:
|
||||||
vk::die_with_error(HERE, status);
|
vk::die_with_error(HERE, status);
|
||||||
}
|
}
|
||||||
@ -3389,7 +3282,7 @@ void VKGSRender::flip(int buffer, bool emu_flip)
|
|||||||
VkRenderPass single_target_pass = vk::get_renderpass(*m_device, key);
|
VkRenderPass single_target_pass = vk::get_renderpass(*m_device, key);
|
||||||
verify("Usupported renderpass configuration" HERE), single_target_pass != VK_NULL_HANDLE;
|
verify("Usupported renderpass configuration" HERE), single_target_pass != VK_NULL_HANDLE;
|
||||||
|
|
||||||
auto direct_fbo = vk::get_framebuffer(*m_device, m_client_width, m_client_height, single_target_pass, m_swapchain->get_surface_format(), target_image);
|
auto direct_fbo = vk::get_framebuffer(*m_device, m_swapchain_dims.width, m_swapchain_dims.height, single_target_pass, m_swapchain->get_surface_format(), target_image);
|
||||||
direct_fbo->add_ref();
|
direct_fbo->add_ref();
|
||||||
|
|
||||||
if (has_overlay)
|
if (has_overlay)
|
||||||
@ -3454,7 +3347,7 @@ void VKGSRender::flip(int buffer, bool emu_flip)
|
|||||||
|
|
||||||
bool VKGSRender::scaled_image_from_memory(rsx::blit_src_info& src, rsx::blit_dst_info& dst, bool interpolate)
|
bool VKGSRender::scaled_image_from_memory(rsx::blit_src_info& src, rsx::blit_dst_info& dst, bool interpolate)
|
||||||
{
|
{
|
||||||
if (renderer_unavailable)
|
if (swapchain_unavailable)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Verify enough memory exists before attempting to handle data transfer
|
// Verify enough memory exists before attempting to handle data transfer
|
||||||
|
@ -414,8 +414,8 @@ private:
|
|||||||
|
|
||||||
vk::framebuffer_holder* m_draw_fbo = nullptr;
|
vk::framebuffer_holder* m_draw_fbo = nullptr;
|
||||||
|
|
||||||
bool present_surface_dirty_flag = false;
|
sizeu m_swapchain_dims{};
|
||||||
bool renderer_unavailable = false;
|
bool swapchain_unavailable = false;
|
||||||
|
|
||||||
u64 m_last_heap_sync_time = 0;
|
u64 m_last_heap_sync_time = 0;
|
||||||
u32 m_texbuffer_view_size = 0;
|
u32 m_texbuffer_view_size = 0;
|
||||||
@ -445,9 +445,6 @@ private:
|
|||||||
frame_context_t* m_current_frame = nullptr;
|
frame_context_t* m_current_frame = nullptr;
|
||||||
std::deque<frame_context_t*> m_queued_frames;
|
std::deque<frame_context_t*> m_queued_frames;
|
||||||
|
|
||||||
u32 m_client_width = 0;
|
|
||||||
u32 m_client_height = 0;
|
|
||||||
|
|
||||||
VkViewport m_viewport{};
|
VkViewport m_viewport{};
|
||||||
VkRect2D m_scissor{};
|
VkRect2D m_scissor{};
|
||||||
|
|
||||||
@ -506,6 +503,7 @@ private:
|
|||||||
void update_draw_state();
|
void update_draw_state();
|
||||||
|
|
||||||
void check_heap_status(u32 flags = VK_HEAP_CHECK_ALL);
|
void check_heap_status(u32 flags = VK_HEAP_CHECK_ALL);
|
||||||
|
void check_present_status();
|
||||||
|
|
||||||
void check_descriptors();
|
void check_descriptors();
|
||||||
VkDescriptorSet allocate_descriptor_set();
|
VkDescriptorSet allocate_descriptor_set();
|
||||||
@ -524,9 +522,6 @@ public:
|
|||||||
void set_scissor();
|
void set_scissor();
|
||||||
void bind_viewport();
|
void bind_viewport();
|
||||||
|
|
||||||
void check_window_status();
|
|
||||||
void check_present_status();
|
|
||||||
|
|
||||||
void sync_hint(rsx::FIFO_hint hint) override;
|
void sync_hint(rsx::FIFO_hint hint) override;
|
||||||
|
|
||||||
void begin_occlusion_query(rsx::reports::occlusion_query_info* query) override;
|
void begin_occlusion_query(rsx::reports::occlusion_query_info* query) override;
|
||||||
|
@ -436,9 +436,6 @@ namespace vk
|
|||||||
const auto gpu_name = get_name();
|
const auto gpu_name = get_name();
|
||||||
if (gpu_name.find("Radeon") != std::string::npos)
|
if (gpu_name.find("Radeon") != std::string::npos)
|
||||||
{
|
{
|
||||||
#ifndef _WIN32
|
|
||||||
LOG_ERROR(RSX, "Using non RADV drivers on linux currently incurs a ~40% performance loss due to a window resizing workaround. Using RADV is recommended.");
|
|
||||||
#endif
|
|
||||||
return driver_vendor::AMD;
|
return driver_vendor::AMD;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2036,13 +2033,9 @@ public:
|
|||||||
|
|
||||||
switch (gpu.get_driver_vendor())
|
switch (gpu.get_driver_vendor())
|
||||||
{
|
{
|
||||||
case driver_vendor::NVIDIA:
|
|
||||||
#ifndef _WIN32
|
|
||||||
m_wm_reports_flag = true;
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
case driver_vendor::AMD:
|
case driver_vendor::AMD:
|
||||||
break;
|
break;
|
||||||
|
case driver_vendor::NVIDIA:
|
||||||
case driver_vendor::INTEL:
|
case driver_vendor::INTEL:
|
||||||
case driver_vendor::RADV:
|
case driver_vendor::RADV:
|
||||||
m_wm_reports_flag = true;
|
m_wm_reports_flag = true;
|
||||||
|
@ -27,155 +27,6 @@
|
|||||||
|
|
||||||
constexpr auto qstr = QString::fromStdString;
|
constexpr auto qstr = QString::fromStdString;
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
|
|
||||||
namespace win32
|
|
||||||
{
|
|
||||||
HHOOK _hook = NULL;
|
|
||||||
bool _in_sizing_event = false;
|
|
||||||
bool _interactive_resize = false;
|
|
||||||
bool _user_interaction_active = false;
|
|
||||||
bool _minimized = false;
|
|
||||||
|
|
||||||
void _ReleaseHook();
|
|
||||||
|
|
||||||
LRESULT CALLBACK __HookCallback(INT nCode, WPARAM wParam, LPARAM lParam)
|
|
||||||
{
|
|
||||||
std::shared_ptr<GSRender> renderer;
|
|
||||||
|
|
||||||
if (Emu.IsStopped())
|
|
||||||
{
|
|
||||||
// Stop receiving events
|
|
||||||
_ReleaseHook();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
renderer = fxm::get<GSRender>();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nCode >= 0 && renderer)
|
|
||||||
{
|
|
||||||
auto frame_wnd = renderer->get_frame();
|
|
||||||
auto msg = (CWPSTRUCT*)lParam;
|
|
||||||
|
|
||||||
switch ((msg->hwnd == frame_wnd->handle()) ? msg->message : 0)
|
|
||||||
{
|
|
||||||
case WM_WINDOWPOSCHANGING:
|
|
||||||
{
|
|
||||||
const auto flags = reinterpret_cast<LPWINDOWPOS>(msg->lParam)->flags & SWP_NOSIZE;
|
|
||||||
if (_in_sizing_event || flags != 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
// About to resize
|
|
||||||
_in_sizing_event = true;
|
|
||||||
_interactive_resize = false;
|
|
||||||
frame_wnd->push_wm_event(wm_event::geometry_change_notice);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case WM_WINDOWPOSCHANGED:
|
|
||||||
{
|
|
||||||
if (_user_interaction_active)
|
|
||||||
{
|
|
||||||
// Window dragged or resized by user causing position to change, but user is not yet done
|
|
||||||
frame_wnd->push_wm_event(wm_event::geometry_change_in_progress);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto flags = reinterpret_cast<LPWINDOWPOS>(msg->lParam)->flags & (SWP_NOSIZE | SWP_NOMOVE);
|
|
||||||
if (!_in_sizing_event || flags == (SWP_NOSIZE | SWP_NOMOVE))
|
|
||||||
break;
|
|
||||||
|
|
||||||
_in_sizing_event = false;
|
|
||||||
|
|
||||||
if (flags & SWP_NOSIZE)
|
|
||||||
{
|
|
||||||
frame_wnd->push_wm_event(wm_event::window_moved);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LPWINDOWPOS wpos = reinterpret_cast<LPWINDOWPOS>(msg->lParam);
|
|
||||||
if (wpos->cx <= GetSystemMetrics(SM_CXMINIMIZED) || wpos->cy <= GetSystemMetrics(SM_CYMINIMIZED))
|
|
||||||
{
|
|
||||||
// Minimize event
|
|
||||||
_minimized = true;
|
|
||||||
frame_wnd->push_wm_event(wm_event::window_minimized);
|
|
||||||
}
|
|
||||||
else if (_minimized)
|
|
||||||
{
|
|
||||||
_minimized = false;
|
|
||||||
frame_wnd->push_wm_event(wm_event::window_restored);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Handle the resize in WM_SIZE message
|
|
||||||
_in_sizing_event = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case WM_ENTERSIZEMOVE:
|
|
||||||
_user_interaction_active = true;
|
|
||||||
break;
|
|
||||||
case WM_EXITSIZEMOVE:
|
|
||||||
_user_interaction_active = false;
|
|
||||||
if (_in_sizing_event && !_user_interaction_active)
|
|
||||||
{
|
|
||||||
// Just finished resizing using manual interaction. The corresponding WM_SIZE is consumed before this event fires
|
|
||||||
frame_wnd->push_wm_event(_interactive_resize ? wm_event::window_resized : wm_event::window_moved);
|
|
||||||
_in_sizing_event = false;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case WM_SIZE:
|
|
||||||
{
|
|
||||||
if (_user_interaction_active)
|
|
||||||
{
|
|
||||||
// Interaction is a resize not a move
|
|
||||||
_interactive_resize = true;
|
|
||||||
frame_wnd->push_wm_event(wm_event::geometry_change_in_progress);
|
|
||||||
}
|
|
||||||
else if (_in_sizing_event)
|
|
||||||
{
|
|
||||||
// Any other unexpected resize mode will give an unconsumed WM_SIZE event
|
|
||||||
frame_wnd->push_wm_event(wm_event::window_resized);
|
|
||||||
_in_sizing_event = false;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return CallNextHookEx(_hook, nCode, wParam, lParam);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _InstallHook()
|
|
||||||
{
|
|
||||||
if (_hook)
|
|
||||||
{
|
|
||||||
_ReleaseHook();
|
|
||||||
}
|
|
||||||
|
|
||||||
Emu.CallAfter([&]()
|
|
||||||
{
|
|
||||||
if (_hook = SetWindowsHookEx(WH_CALLWNDPROC, __HookCallback, NULL, GetCurrentThreadId()); !_hook)
|
|
||||||
{
|
|
||||||
LOG_ERROR(RSX, "Failed to install window hook!");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void _ReleaseHook()
|
|
||||||
{
|
|
||||||
if (_hook)
|
|
||||||
{
|
|
||||||
UnhookWindowsHookEx(_hook);
|
|
||||||
_hook = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
gs_frame::gs_frame(const QString& title, const QRect& geometry, const QIcon& appIcon, const std::shared_ptr<gui_settings>& gui_settings)
|
gs_frame::gs_frame(const QString& title, const QRect& geometry, const QIcon& appIcon, const std::shared_ptr<gui_settings>& gui_settings)
|
||||||
: QWindow(), m_windowTitle(title), m_gui_settings(gui_settings)
|
: QWindow(), m_windowTitle(title), m_gui_settings(gui_settings)
|
||||||
{
|
{
|
||||||
@ -235,7 +86,6 @@ gs_frame::gs_frame(const QString& title, const QRect& geometry, const QIcon& app
|
|||||||
m_tb_progress->setRange(0, m_gauge_max);
|
m_tb_progress->setRange(0, m_gauge_max);
|
||||||
m_tb_progress->setVisible(false);
|
m_tb_progress->setVisible(false);
|
||||||
|
|
||||||
win32::_ReleaseHook();
|
|
||||||
#elif HAVE_QTDBUS
|
#elif HAVE_QTDBUS
|
||||||
UpdateProgress(0);
|
UpdateProgress(0);
|
||||||
m_progress_value = 0;
|
m_progress_value = 0;
|
||||||
@ -309,28 +159,19 @@ void gs_frame::keyPressEvent(QKeyEvent *keyEvent)
|
|||||||
|
|
||||||
void gs_frame::toggle_fullscreen()
|
void gs_frame::toggle_fullscreen()
|
||||||
{
|
{
|
||||||
if (wm_allow_fullscreen)
|
auto l_setFullScreenVis = [&]()
|
||||||
{
|
{
|
||||||
auto l_setFullScreenVis = [&]()
|
if (visibility() == FullScreen)
|
||||||
{
|
{
|
||||||
if (visibility() == FullScreen)
|
setVisibility(Windowed);
|
||||||
{
|
}
|
||||||
setVisibility(Windowed);
|
else
|
||||||
}
|
{
|
||||||
else
|
setVisibility(FullScreen);
|
||||||
{
|
}
|
||||||
setVisibility(FullScreen);
|
};
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Emu.CallAfter(l_setFullScreenVis);
|
Emu.CallAfter(l_setFullScreenVis);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Forward the request to the backend
|
|
||||||
push_wm_event(wm_event::toggle_fullscreen);
|
|
||||||
std::this_thread::sleep_for(1s);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void gs_frame::close()
|
void gs_frame::close()
|
||||||
@ -405,10 +246,6 @@ draw_context_t gs_frame::make_context()
|
|||||||
void gs_frame::set_current(draw_context_t ctx)
|
void gs_frame::set_current(draw_context_t ctx)
|
||||||
{
|
{
|
||||||
Q_UNUSED(ctx);
|
Q_UNUSED(ctx);
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
win32::_InstallHook();
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void gs_frame::delete_context(draw_context_t ctx)
|
void gs_frame::delete_context(draw_context_t ctx)
|
||||||
|
Loading…
Reference in New Issue
Block a user