mirror of
https://github.com/RPCS3/rpcs3
synced 2024-11-02 11:45:30 +00: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
8 changed files with 77 additions and 446 deletions
|
@ -1,4 +1,4 @@
|
|||
#ifdef _MSC_VER
|
||||
#ifdef _MSC_VER
|
||||
#include "stdafx.h"
|
||||
#include "stdafx_d3d12.h"
|
||||
#include "D3D12GSRender.h"
|
||||
|
@ -308,12 +308,6 @@ void D3D12GSRender::on_exit()
|
|||
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -939,12 +939,8 @@ void GLGSRender::on_init_thread()
|
|||
|
||||
if (!supports_native_ui)
|
||||
{
|
||||
m_frame->disable_wm_event_queue();
|
||||
m_frame->hide();
|
||||
|
||||
m_shaders_cache->load(nullptr);
|
||||
|
||||
m_frame->enable_wm_event_queue();
|
||||
m_frame->show();
|
||||
}
|
||||
else
|
||||
|
@ -1004,7 +1000,6 @@ void GLGSRender::on_init_thread()
|
|||
}
|
||||
helper(this);
|
||||
|
||||
m_frame->enable_wm_event_queue();
|
||||
m_shaders_cache->load(&helper);
|
||||
}
|
||||
}
|
||||
|
@ -1918,8 +1913,6 @@ void GLGSRender::do_local_task(rsx::FIFO_state state)
|
|||
return;
|
||||
}
|
||||
|
||||
m_frame->clear_wm_events();
|
||||
|
||||
if (m_overlay_manager)
|
||||
{
|
||||
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/System.h"
|
||||
|
||||
|
@ -41,8 +41,6 @@ void GSRender::on_exit()
|
|||
{
|
||||
if (m_frame)
|
||||
{
|
||||
m_frame->disable_wm_event_queue();
|
||||
m_frame->clear_wm_events();
|
||||
m_frame->delete_context(m_context);
|
||||
m_context = nullptr;
|
||||
}
|
||||
|
|
|
@ -84,78 +84,6 @@ using draw_context_t = void*;
|
|||
virtual int client_height() = 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
|
||||
|
|
|
@ -444,10 +444,13 @@ VKGSRender::VKGSRender() : GSRender()
|
|||
vk::set_current_thread_ctx(m_thread_context);
|
||||
vk::set_current_renderer(m_swapchain->get_device());
|
||||
|
||||
m_client_width = m_frame->client_width();
|
||||
m_client_height = m_frame->client_height();
|
||||
if (!m_swapchain->init(m_client_width, m_client_height))
|
||||
present_surface_dirty_flag = true;
|
||||
m_swapchain_dims.width = m_frame->client_width();
|
||||
m_swapchain_dims.height = m_frame->client_height();
|
||||
|
||||
if (!m_swapchain->init(m_swapchain_dims.width, m_swapchain_dims.height))
|
||||
{
|
||||
swapchain_unavailable = true;
|
||||
}
|
||||
|
||||
//create command buffer...
|
||||
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()
|
||||
{
|
||||
verify(HERE), m_current_frame->used_descriptors < DESCRIPTOR_MAX_DRAW_CALLS;
|
||||
|
@ -1024,7 +920,7 @@ void VKGSRender::begin()
|
|||
{
|
||||
rsx::thread::begin();
|
||||
|
||||
if (skip_frame || renderer_unavailable ||
|
||||
if (skip_frame || swapchain_unavailable ||
|
||||
(conditional_render_enabled && conditional_render_test_failed))
|
||||
return;
|
||||
|
||||
|
@ -1300,7 +1196,7 @@ void VKGSRender::emit_geometry(u32 sub_index)
|
|||
|
||||
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))
|
||||
{
|
||||
execute_nop_draw();
|
||||
|
@ -1876,10 +1772,8 @@ void VKGSRender::on_init_thread()
|
|||
|
||||
if (!supports_native_ui)
|
||||
{
|
||||
m_frame->disable_wm_event_queue();
|
||||
m_frame->hide();
|
||||
m_shaders_cache->load(nullptr, *m_device, pipeline_layout);
|
||||
m_frame->enable_wm_event_queue();
|
||||
m_frame->show();
|
||||
}
|
||||
else
|
||||
|
@ -1939,18 +1833,8 @@ void VKGSRender::on_init_thread()
|
|||
}
|
||||
helper(this);
|
||||
|
||||
//TODO: Handle window resize messages during loading on GPUs without OUT_OF_DATE_KHR support
|
||||
m_frame->disable_wm_event_queue();
|
||||
// TODO: Handle window resize messages during loading on GPUs without OUT_OF_DATE_KHR support
|
||||
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)
|
||||
{
|
||||
if (skip_frame || renderer_unavailable) return;
|
||||
if (skip_frame || swapchain_unavailable) return;
|
||||
|
||||
// If stencil write mask is disabled, remove clear_stencil bit
|
||||
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;
|
||||
|
||||
if (!present_surface_dirty_flag)
|
||||
if (!swapchain_unavailable)
|
||||
{
|
||||
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:
|
||||
break;
|
||||
case VK_ERROR_OUT_OF_DATE_KHR:
|
||||
present_surface_dirty_flag = true;
|
||||
swapchain_unavailable = true;
|
||||
break;
|
||||
default:
|
||||
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
|
||||
if (ctx->swap_command_buffer->wait(FRAME_PRESENT_TIMEOUT) != VK_SUCCESS)
|
||||
{
|
||||
// Lost surface, release renderer
|
||||
present_surface_dirty_flag = true;
|
||||
renderer_unavailable = true;
|
||||
// Lost surface/device, release swapchain
|
||||
swapchain_unavailable = true;
|
||||
}
|
||||
|
||||
free_resources = true;
|
||||
|
@ -2447,8 +2330,6 @@ void VKGSRender::do_local_task(rsx::FIFO_state state)
|
|||
break;
|
||||
}
|
||||
|
||||
check_window_status();
|
||||
|
||||
if (m_overlay_manager)
|
||||
{
|
||||
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()
|
||||
{
|
||||
const auto new_width = m_frame->client_width();
|
||||
const auto new_height = m_frame->client_height();
|
||||
m_swapchain_dims.width = m_frame->client_width();
|
||||
m_swapchain_dims.height = m_frame->client_height();
|
||||
|
||||
// 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
|
||||
// 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;
|
||||
}
|
||||
|
||||
// NOTE: This operation will create a hard sync point
|
||||
close_and_submit_command_buffer(m_current_command_buffer->submit_fence);
|
||||
|
@ -3073,18 +2957,14 @@ void VKGSRender::reinitialize_swapchain()
|
|||
vkDeviceWaitIdle(*m_device);
|
||||
|
||||
// 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);
|
||||
present_surface_dirty_flag = true;
|
||||
renderer_unavailable = true;
|
||||
LOG_WARNING(RSX, "Swapchain initialization failed. Request ignored [%dx%d]", m_swapchain_dims.width, m_swapchain_dims.height);
|
||||
swapchain_unavailable = true;
|
||||
open_command_buffer();
|
||||
return;
|
||||
}
|
||||
|
||||
m_client_width = new_width;
|
||||
m_client_height = new_height;
|
||||
|
||||
// Prepare new swapchain images for use
|
||||
open_command_buffer();
|
||||
|
||||
|
@ -3115,26 +2995,24 @@ void VKGSRender::reinitialize_swapchain()
|
|||
m_current_command_buffer->reset();
|
||||
open_command_buffer();
|
||||
|
||||
present_surface_dirty_flag = false;
|
||||
renderer_unavailable = false;
|
||||
swapchain_unavailable = false;
|
||||
}
|
||||
|
||||
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);
|
||||
rsx::thread::flip(buffer, emu_flip);
|
||||
|
||||
if (!skip_frame)
|
||||
if (m_swapchain_dims.width != m_frame->client_width() ||
|
||||
m_swapchain_dims.height != m_frame->client_height())
|
||||
{
|
||||
m_draw_time = 0;
|
||||
m_setup_time = 0;
|
||||
m_vertex_upload_time = 0;
|
||||
m_textures_upload_time = 0;
|
||||
swapchain_unavailable = true;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
if (swapchain_unavailable)
|
||||
{
|
||||
reinitialize_swapchain();
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
// 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");
|
||||
}
|
||||
|
||||
|
@ -3164,14 +3042,29 @@ void VKGSRender::flip(int buffer, bool emu_flip)
|
|||
frame_context_cleanup(m_current_frame, true);
|
||||
}
|
||||
|
||||
if (present_surface_dirty_flag)
|
||||
if (skip_frame || swapchain_unavailable)
|
||||
{
|
||||
//Recreate swapchain and continue as usual
|
||||
reinitialize_swapchain();
|
||||
}
|
||||
m_frame->flip(m_context);
|
||||
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;
|
||||
}
|
||||
|
||||
u32 buffer_width = display_buffers[buffer].width;
|
||||
u32 buffer_height = display_buffers[buffer].height;
|
||||
|
@ -3196,7 +3089,7 @@ void VKGSRender::flip(int buffer, bool emu_flip)
|
|||
|
||||
coordi aspect_ratio;
|
||||
|
||||
sizei csize = { (s32)m_client_width, (s32)m_client_height };
|
||||
sizei csize = m_swapchain_dims;
|
||||
sizei new_size = csize;
|
||||
|
||||
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
|
||||
//Found on AMD Crimson 17.7.2
|
||||
|
||||
|
||||
//Whatever returned from status, this is now a spin
|
||||
timeout = 0ull;
|
||||
check_present_status();
|
||||
|
||||
continue;
|
||||
}
|
||||
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.");
|
||||
present_surface_dirty_flag = true;
|
||||
swapchain_unavailable = true;
|
||||
reinitialize_swapchain();
|
||||
return;
|
||||
continue;
|
||||
default:
|
||||
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);
|
||||
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();
|
||||
|
||||
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)
|
||||
{
|
||||
if (renderer_unavailable)
|
||||
if (swapchain_unavailable)
|
||||
return false;
|
||||
|
||||
// Verify enough memory exists before attempting to handle data transfer
|
||||
|
|
|
@ -414,8 +414,8 @@ private:
|
|||
|
||||
vk::framebuffer_holder* m_draw_fbo = nullptr;
|
||||
|
||||
bool present_surface_dirty_flag = false;
|
||||
bool renderer_unavailable = false;
|
||||
sizeu m_swapchain_dims{};
|
||||
bool swapchain_unavailable = false;
|
||||
|
||||
u64 m_last_heap_sync_time = 0;
|
||||
u32 m_texbuffer_view_size = 0;
|
||||
|
@ -445,9 +445,6 @@ private:
|
|||
frame_context_t* m_current_frame = nullptr;
|
||||
std::deque<frame_context_t*> m_queued_frames;
|
||||
|
||||
u32 m_client_width = 0;
|
||||
u32 m_client_height = 0;
|
||||
|
||||
VkViewport m_viewport{};
|
||||
VkRect2D m_scissor{};
|
||||
|
||||
|
@ -506,6 +503,7 @@ private:
|
|||
void update_draw_state();
|
||||
|
||||
void check_heap_status(u32 flags = VK_HEAP_CHECK_ALL);
|
||||
void check_present_status();
|
||||
|
||||
void check_descriptors();
|
||||
VkDescriptorSet allocate_descriptor_set();
|
||||
|
@ -524,9 +522,6 @@ public:
|
|||
void set_scissor();
|
||||
void bind_viewport();
|
||||
|
||||
void check_window_status();
|
||||
void check_present_status();
|
||||
|
||||
void sync_hint(rsx::FIFO_hint hint) override;
|
||||
|
||||
void begin_occlusion_query(rsx::reports::occlusion_query_info* query) override;
|
||||
|
|
|
@ -436,9 +436,6 @@ namespace vk
|
|||
const auto gpu_name = get_name();
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -2036,13 +2033,9 @@ public:
|
|||
|
||||
switch (gpu.get_driver_vendor())
|
||||
{
|
||||
case driver_vendor::NVIDIA:
|
||||
#ifndef _WIN32
|
||||
m_wm_reports_flag = true;
|
||||
#endif
|
||||
break;
|
||||
case driver_vendor::AMD:
|
||||
break;
|
||||
case driver_vendor::NVIDIA:
|
||||
case driver_vendor::INTEL:
|
||||
case driver_vendor::RADV:
|
||||
m_wm_reports_flag = true;
|
||||
|
|
|
@ -27,155 +27,6 @@
|
|||
|
||||
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)
|
||||
: 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->setVisible(false);
|
||||
|
||||
win32::_ReleaseHook();
|
||||
#elif HAVE_QTDBUS
|
||||
UpdateProgress(0);
|
||||
m_progress_value = 0;
|
||||
|
@ -309,28 +159,19 @@ void gs_frame::keyPressEvent(QKeyEvent *keyEvent)
|
|||
|
||||
void gs_frame::toggle_fullscreen()
|
||||
{
|
||||
if (wm_allow_fullscreen)
|
||||
auto l_setFullScreenVis = [&]()
|
||||
{
|
||||
auto l_setFullScreenVis = [&]()
|
||||
if (visibility() == FullScreen)
|
||||
{
|
||||
if (visibility() == FullScreen)
|
||||
{
|
||||
setVisibility(Windowed);
|
||||
}
|
||||
else
|
||||
{
|
||||
setVisibility(FullScreen);
|
||||
}
|
||||
};
|
||||
setVisibility(Windowed);
|
||||
}
|
||||
else
|
||||
{
|
||||
setVisibility(FullScreen);
|
||||
}
|
||||
};
|
||||
|
||||
Emu.CallAfter(l_setFullScreenVis);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Forward the request to the backend
|
||||
push_wm_event(wm_event::toggle_fullscreen);
|
||||
std::this_thread::sleep_for(1s);
|
||||
}
|
||||
Emu.CallAfter(l_setFullScreenVis);
|
||||
}
|
||||
|
||||
void gs_frame::close()
|
||||
|
@ -405,10 +246,6 @@ draw_context_t gs_frame::make_context()
|
|||
void gs_frame::set_current(draw_context_t ctx)
|
||||
{
|
||||
Q_UNUSED(ctx);
|
||||
|
||||
#ifdef _WIN32
|
||||
win32::_InstallHook();
|
||||
#endif
|
||||
}
|
||||
|
||||
void gs_frame::delete_context(draw_context_t ctx)
|
||||
|
|
Loading…
Reference in a new issue