From ce2b790d8f44fee4104e327dfe8a797a3ba85901 Mon Sep 17 00:00:00 2001 From: kd-11 Date: Sat, 28 Oct 2017 15:34:24 +0300 Subject: [PATCH] rsx/qt: GsFrame improvements - Identify minimize/restore events as separate from regular resize and do not react to them - Enable message queue consumption after loading the shaders cache. Also hides the frame in this step -- This fixes the 'start fullscreen' bug when running vulkan --- rpcs3/Emu/RSX/GL/GLGSRender.cpp | 6 ++ rpcs3/Emu/RSX/GSRender.h | 16 +++- rpcs3/Emu/RSX/VK/VKGSRender.cpp | 15 +++- rpcs3/rpcs3qt/gs_frame.cpp | 140 ++++++++++++++++++-------------- rpcs3/rpcs3qt/gs_frame.h | 1 + 5 files changed, 115 insertions(+), 63 deletions(-) diff --git a/rpcs3/Emu/RSX/GL/GLGSRender.cpp b/rpcs3/Emu/RSX/GL/GLGSRender.cpp index ce252c10db..c355528caa 100644 --- a/rpcs3/Emu/RSX/GL/GLGSRender.cpp +++ b/rpcs3/Emu/RSX/GL/GLGSRender.cpp @@ -631,6 +631,9 @@ void GLGSRender::on_init_thread() { GSRender::on_init_thread(); + m_frame->disable_wm_event_queue(); + m_frame->hide(); + gl::init(); //Enable adaptive vsync if vsync is requested @@ -771,6 +774,9 @@ void GLGSRender::on_init_thread() m_thread_id = std::this_thread::get_id(); m_shaders_cache->load(); + + m_frame->enable_wm_event_queue(); + m_frame->show(); } void GLGSRender::on_exit() diff --git a/rpcs3/Emu/RSX/GSRender.h b/rpcs3/Emu/RSX/GSRender.h index f6f5693c09..ebac990b37 100644 --- a/rpcs3/Emu/RSX/GSRender.h +++ b/rpcs3/Emu/RSX/GSRender.h @@ -24,7 +24,10 @@ enum wm_event geometry_change_notice, //about to start resizing and/or moving the window geometry_change_in_progress, //window being resized and/or moved window_resized, //window was resized - window_moved //window moved without resize + window_minimized, //window was minimized + window_restored, //window was restored from a minimized state + window_moved, //window moved without resize + window_visibility_changed }; using RSXDebuggerPrograms = std::vector; @@ -58,6 +61,7 @@ protected: //window manager event management wm_event m_raised_event; std::atomic_bool wm_event_raised = {}; + std::atomic_bool wm_event_queue_enabled = {}; public: //synchronize native window access @@ -83,6 +87,16 @@ public: return get_default_wm_event(); } + + void disable_wm_event_queue() + { + wm_event_queue_enabled.store(false); + } + + void enable_wm_event_queue() + { + wm_event_queue_enabled.store(true); + } }; class GSRender : public rsx::thread diff --git a/rpcs3/Emu/RSX/VK/VKGSRender.cpp b/rpcs3/Emu/RSX/VK/VKGSRender.cpp index 771bd058ba..16c247258b 100644 --- a/rpcs3/Emu/RSX/VK/VKGSRender.cpp +++ b/rpcs3/Emu/RSX/VK/VKGSRender.cpp @@ -1332,7 +1332,13 @@ void VKGSRender::on_init_thread() GSRender::on_init_thread(); rsx_thread = std::this_thread::get_id(); + m_frame->disable_wm_event_queue(); + m_frame->hide(); + m_shaders_cache->load(*m_device, pipeline_layout); + + m_frame->enable_wm_event_queue(); + m_frame->show(); } void VKGSRender::on_exit() @@ -1747,12 +1753,15 @@ void VKGSRender::do_local_task() handled = true; present_surface_dirty_flag = true; break; - case wm_event::window_moved: - handled = 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_visibility_changed: + case wm_event::window_minimized: + case wm_event::window_restored: + case wm_event::window_moved: + handled = true; //ignore these events as they do not alter client area + break; } if (handled) diff --git a/rpcs3/rpcs3qt/gs_frame.cpp b/rpcs3/rpcs3qt/gs_frame.cpp index de075d906a..0b916672af 100644 --- a/rpcs3/rpcs3qt/gs_frame.cpp +++ b/rpcs3/rpcs3qt/gs_frame.cpp @@ -246,77 +246,99 @@ bool gs_frame::event(QEvent* ev) bool gs_frame::nativeEvent(const QByteArray &eventType, void *message, long *result) { #ifdef _WIN32 - //Wait for consumer to clear notification pending flag - while (wm_event_raised.load(std::memory_order_consume)); - + if (wm_event_queue_enabled.load(std::memory_order_consume)) { - std::lock_guard lock(wm_event_lock); - MSG* msg = static_cast(message); - switch (msg->message) - { - case WM_WINDOWPOSCHANGING: - { - const auto flags = reinterpret_cast(msg->lParam)->flags & SWP_NOSIZE; - if (m_in_sizing_event || flags != 0) - break; + //Wait for consumer to clear notification pending flag + while (wm_event_raised.load(std::memory_order_consume)); - //About to resize - m_in_sizing_event = true; - m_interactive_resize = false; - m_raised_event = wm_event::geometry_change_notice; - wm_event_raised.store(true); - break; - } - case WM_WINDOWPOSCHANGED: { - const auto flags = reinterpret_cast(msg->lParam)->flags & (SWP_NOSIZE | SWP_NOMOVE); - if (!m_in_sizing_event || m_user_interaction_active || flags == (SWP_NOSIZE | SWP_NOMOVE)) - break; - - if (flags & SWP_NOSIZE) - m_raised_event = wm_event::window_moved; - else - m_raised_event = wm_event::window_resized; - - //Just finished resizing using maximize or SWP - m_in_sizing_event = false; - wm_event_raised.store(true); - break; - } - case WM_ENTERSIZEMOVE: - m_user_interaction_active = true; - break; - case WM_EXITSIZEMOVE: - m_user_interaction_active = false; - if (m_in_sizing_event && !m_user_interaction_active) + std::lock_guard lock(wm_event_lock); + MSG* msg = static_cast(message); + switch (msg->message) { - //Just finished resizing using manual interaction. The corresponding WM_SIZE is consumed before this event fires - m_raised_event = m_interactive_resize ? wm_event::window_resized : wm_event::window_moved; + case WM_WINDOWPOSCHANGING: + { + const auto flags = reinterpret_cast(msg->lParam)->flags & SWP_NOSIZE; + if (m_in_sizing_event || flags != 0) + break; + + //About to resize + m_in_sizing_event = true; + m_interactive_resize = false; + m_raised_event = wm_event::geometry_change_notice; + wm_event_raised.store(true); + break; + } + case WM_WINDOWPOSCHANGED: + { + const auto flags = reinterpret_cast(msg->lParam)->flags & (SWP_NOSIZE | SWP_NOMOVE); + if (!m_in_sizing_event || m_user_interaction_active || flags == (SWP_NOSIZE | SWP_NOMOVE)) + break; + + if (flags & SWP_NOSIZE) + { + m_raised_event = wm_event::window_moved; + } + else + { + LPWINDOWPOS wpos = reinterpret_cast(msg->lParam); + if (wpos->cx <= GetSystemMetrics(SM_CXMINIMIZED) || wpos->cy <= GetSystemMetrics(SM_CYMINIMIZED)) + { + //Minimize event + m_minimized = true; + m_raised_event = wm_event::window_minimized; + } + else if (m_minimized) + { + m_minimized = false; + m_raised_event = wm_event::window_restored; + } + else + { + m_raised_event = wm_event::window_resized; + } + } + + //Just finished resizing using maximize or SWP m_in_sizing_event = false; wm_event_raised.store(true); + break; } - break; - case WM_SIZE: - { - if (m_user_interaction_active) + case WM_ENTERSIZEMOVE: + m_user_interaction_active = true; + break; + case WM_EXITSIZEMOVE: + m_user_interaction_active = false; + if (m_in_sizing_event && !m_user_interaction_active) + { + //Just finished resizing using manual interaction. The corresponding WM_SIZE is consumed before this event fires + m_raised_event = m_interactive_resize ? wm_event::window_resized : wm_event::window_moved; + m_in_sizing_event = false; + wm_event_raised.store(true); + } + break; + case WM_SIZE: { - //Interaction is a resize not a move - m_interactive_resize = true; + if (m_user_interaction_active) + { + //Interaction is a resize not a move + m_interactive_resize = true; + } + else if (m_in_sizing_event) + { + //Any other unexpected resize mode will give an unconsumed WM_SIZE event + m_raised_event = wm_event::window_resized; + m_in_sizing_event = false; + wm_event_raised.store(true); + } + break; } - else if (m_in_sizing_event) - { - //Any other unexpected resize mode will give an unconsumed WM_SIZE event - m_raised_event = wm_event::window_resized; - m_in_sizing_event = false; - wm_event_raised.store(true); } - break; - } } + + //Do not enter DefWndProc until the consumer has consumed the message + while (wm_event_raised.load(std::memory_order_consume)); } - - //Do not enter DefWndProc until the consumer has consumed the message - while (wm_event_raised.load(std::memory_order_consume)); #endif //Let the default handler deal with this. Only the notification is required diff --git a/rpcs3/rpcs3qt/gs_frame.h b/rpcs3/rpcs3qt/gs_frame.h index b29c523a52..06517c92d0 100644 --- a/rpcs3/rpcs3qt/gs_frame.h +++ b/rpcs3/rpcs3qt/gs_frame.h @@ -17,6 +17,7 @@ class gs_frame : public QWindow, public GSFrameBase bool m_in_sizing_event = false; //a signal that the window is about to be resized was received bool m_user_interaction_active = false; //a signal indicating the window is being manually moved/resized was received bool m_interactive_resize = false; //resize signal received while dragging window + bool m_minimized = false; public: gs_frame(const QString& title, int w, int h, QIcon appIcon, bool disableMouse);