From 3bfa564ef8fc8267bd886dc8f5a5efc0e690d453 Mon Sep 17 00:00:00 2001 From: kd-11 Date: Mon, 7 Jan 2019 01:03:56 +0300 Subject: [PATCH] vk/windows: Try to keep msq thread from ever stopping - NVIDIA drivers hook into the msq before our nativeEvent handler. This means NV is aware of events before rpcs3 is aware of them and sometimes stops until a new event is triggered. If rpcs3 is inside a driver call at this time, the system will deadlock since the driver waits for msq which waits for the renderer which waits for the driver. - Use explicit hook management to control window events - Add fence timeout to attempt detection of surface loss events --- rpcs3/Emu/RSX/GSRender.h | 116 ++++++---- rpcs3/Emu/RSX/VK/VKGSRender.cpp | 195 +++++++++-------- rpcs3/Emu/RSX/VK/VKGSRender.h | 12 +- rpcs3/Emu/RSX/VK/VKHelpers.cpp | 25 ++- rpcs3/Emu/RSX/VK/VKHelpers.h | 7 +- rpcs3/rpcs3qt/gs_frame.cpp | 366 ++++++++++++++++++-------------- rpcs3/rpcs3qt/gs_frame.h | 13 +- 7 files changed, 420 insertions(+), 314 deletions(-) diff --git a/rpcs3/Emu/RSX/GSRender.h b/rpcs3/Emu/RSX/GSRender.h index f1d61cc7c2..82d40377f4 100644 --- a/rpcs3/Emu/RSX/GSRender.h +++ b/rpcs3/Emu/RSX/GSRender.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include "Emu/RSX/RSXThread.h" #include @@ -35,13 +35,14 @@ struct RSXDebuggerProgram enum wm_event { - none, //nothing - 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_minimized, //window was minimized - window_restored, //window was restored from a minimized state - window_moved, //window moved without resize + none, // nothing + toggle_fullscreen, // user is requesting a fullscreen switch + 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_minimized, // window was minimized + window_restored, // window was restored from a minimized state + window_moved, // window moved without resize window_visibility_changed }; @@ -62,57 +63,78 @@ using draw_context_t = void*; >; #endif -class GSFrameBase -{ -public: - GSFrameBase() = default; - GSFrameBase(const GSFrameBase&) = delete; - virtual ~GSFrameBase() {} + class GSFrameBase + { + public: + GSFrameBase() = default; + GSFrameBase(const GSFrameBase&) = delete; + virtual ~GSFrameBase() {} - virtual void close() = 0; - virtual bool shown() = 0; - virtual void hide() = 0; - virtual void show() = 0; + virtual void close() = 0; + virtual bool shown() = 0; + virtual void hide() = 0; + virtual void show() = 0; + virtual void toggle_fullscreen() = 0; - virtual void delete_context(draw_context_t ctx) = 0; - virtual draw_context_t make_context() = 0; - virtual void set_current(draw_context_t ctx) = 0; - virtual void flip(draw_context_t ctx, bool skip_frame=false) = 0; - virtual int client_width() = 0; - virtual int client_height() = 0; + virtual void delete_context(draw_context_t ctx) = 0; + virtual draw_context_t make_context() = 0; + virtual void set_current(draw_context_t ctx) = 0; + virtual void flip(draw_context_t ctx, bool skip_frame = false) = 0; + virtual int client_width() = 0; + virtual int client_height() = 0; - virtual display_handle_t handle() const = 0; + virtual display_handle_t handle() const = 0; -protected: + protected: - //window manager event management - wm_event m_raised_event; - std::atomic_bool wm_event_raised = {}; - std::atomic_bool wm_event_queue_enabled = {}; + // window manager event management + std::deque m_raised_events; + std::atomic_bool wm_event_queue_enabled = {}; + std::atomic_bool wm_allow_fullscreen = { true }; public: - //synchronize native window access - std::mutex wm_event_lock; + // synchronize native window access + shared_mutex wm_event_lock; - virtual wm_event get_default_wm_event() const = 0; + 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() { - m_raised_event = wm_event::none; - wm_event_raised.store(false); + 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 (wm_event_raised.load(std::memory_order_consume)) + if (m_raised_events.empty()) { - auto result = m_raised_event; - m_raised_event = wm_event::none; - wm_event_raised.store(false); - return result; + return wm_event::none; } + else + { + std::lock_guard lock(wm_event_lock); - return get_default_wm_event(); + const auto _event = m_raised_events.front(); + m_raised_events.pop_front(); + return _event; + } } void disable_wm_event_queue() @@ -124,6 +146,16 @@ public: { 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 @@ -141,4 +173,6 @@ public: void on_exit() override; void flip(int buffer) override; + + GSFrameBase* get_frame() { return m_frame; }; }; diff --git a/rpcs3/Emu/RSX/VK/VKGSRender.cpp b/rpcs3/Emu/RSX/VK/VKGSRender.cpp index 2085fd3067..24c11b1df5 100644 --- a/rpcs3/Emu/RSX/VK/VKGSRender.cpp +++ b/rpcs3/Emu/RSX/VK/VKGSRender.cpp @@ -918,7 +918,7 @@ bool VKGSRender::on_access_violation(u32 address, bool is_writing) if (target_cb) { - target_cb->wait(); + target_cb->wait(GENERAL_WAIT_TIMEOUT); } } @@ -1046,6 +1046,103 @@ void VKGSRender::check_descriptors() } } +void VKGSRender::check_window_status() +{ +#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 + + 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; @@ -1868,6 +1965,7 @@ void VKGSRender::on_init_thread() m_frame->disable_wm_event_queue(); m_shaders_cache->load(&helper, *m_device, pipeline_layout); m_frame->enable_wm_event_queue(); + m_frame->disable_wm_fullscreen(); } } @@ -2242,8 +2340,14 @@ void VKGSRender::process_swap_request(frame_context_t *ctx, bool free_resources) if (ctx->swap_command_buffer->pending) { - //Perform hard swap here - ctx->swap_command_buffer->wait(); + // 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; + } + free_resources = true; } @@ -2347,84 +2451,7 @@ void VKGSRender::do_local_task(rsx::FIFO_state state) return; } -#ifdef _WIN32 - - switch (m_frame->get_wm_event()) - { - case wm_event::none: - 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(10ms); - timeout -= 10; - } - - //reset renderer availability if something has changed about the window - renderer_unavailable = false; - } - - if (!timeout) - { - LOG_ERROR(RSX, "wm event handler timed out"); - } - - 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 - - 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 + check_window_status(); if (m_overlay_manager) { @@ -3052,8 +3079,8 @@ void VKGSRender::reinitialize_swapchain() if (ctx.present_image == UINT32_MAX) continue; - //Release present image by presenting it - ctx.swap_command_buffer->wait(); + // Release present image by presenting it + ctx.swap_command_buffer->wait(FRAME_PRESENT_TIMEOUT); ctx.swap_command_buffer = nullptr; present(&ctx); } @@ -3558,7 +3585,7 @@ void VKGSRender::get_occlusion_query_result(rsx::reports::occlusion_query_info* } if (data.command_buffer_to_wait->pending) - data.command_buffer_to_wait->wait(); + data.command_buffer_to_wait->wait(GENERAL_WAIT_TIMEOUT); //Gather data for (const auto occlusion_id : data.indices) diff --git a/rpcs3/Emu/RSX/VK/VKGSRender.h b/rpcs3/Emu/RSX/VK/VKGSRender.h index 7538b0c9f9..53eec5bbe8 100644 --- a/rpcs3/Emu/RSX/VK/VKGSRender.h +++ b/rpcs3/Emu/RSX/VK/VKGSRender.h @@ -96,7 +96,7 @@ struct command_buffer_chunk: public vk::command_buffer poke(); if (pending) - wait(); + wait(FRAME_PRESENT_TIMEOUT); CHECK_RESULT(vkResetCommandBuffer(commands, 0)); num_draws = 0; @@ -124,14 +124,14 @@ struct command_buffer_chunk: public vk::command_buffer return !pending; } - void wait() + VkResult wait(u64 timeout = 0ull) { reader_lock lock(guard_mutex); if (!pending) - return; + return VK_SUCCESS; - vk::wait_for_fence(submit_fence); + const auto ret = vk::wait_for_fence(submit_fence, timeout); lock.upgrade(); @@ -140,6 +140,8 @@ struct command_buffer_chunk: public vk::command_buffer vk::reset_fence(&submit_fence); pending = false; } + + return ret; } }; @@ -441,6 +443,8 @@ public: void set_scissor(); void bind_viewport(); + void check_window_status(); + void sync_hint(rsx::FIFO_hint hint) override; void begin_occlusion_query(rsx::reports::occlusion_query_info* query) override; diff --git a/rpcs3/Emu/RSX/VK/VKHelpers.cpp b/rpcs3/Emu/RSX/VK/VKHelpers.cpp index 26b131d575..fe4290b59f 100644 --- a/rpcs3/Emu/RSX/VK/VKHelpers.cpp +++ b/rpcs3/Emu/RSX/VK/VKHelpers.cpp @@ -592,18 +592,27 @@ namespace vk } } - void wait_for_fence(VkFence fence) + VkResult wait_for_fence(VkFence fence, u64 timeout) { - while (auto status = vkGetFenceStatus(*g_current_renderer, fence)) + if (timeout) { - switch (status) + return vkWaitForFences(*g_current_renderer, 1, &fence, VK_FALSE, timeout * 1000ull); + } + else + { + while (auto status = vkGetFenceStatus(*g_current_renderer, fence)) { - case VK_NOT_READY: - continue; - default: - die_with_error(HERE, status); - return; + switch (status) + { + case VK_NOT_READY: + continue; + default: + die_with_error(HERE, status); + return status; + } } + + return VK_SUCCESS; } } diff --git a/rpcs3/Emu/RSX/VK/VKHelpers.h b/rpcs3/Emu/RSX/VK/VKHelpers.h index f11c1f0ae5..722a84d4df 100644 --- a/rpcs3/Emu/RSX/VK/VKHelpers.h +++ b/rpcs3/Emu/RSX/VK/VKHelpers.h @@ -46,6 +46,9 @@ #define VK_NUM_DESCRIPTOR_BINDINGS (VERTEX_TEXTURES_FIRST_BIND_SLOT + 4) +#define FRAME_PRESENT_TIMEOUT 1000000ull // 1 second +#define GENERAL_WAIT_TIMEOUT 100000ull // 100ms + namespace rsx { class fragment_texture; @@ -175,9 +178,9 @@ namespace vk const u64 get_current_frame_id(); const u64 get_last_completed_frame_id(); - //Fence reset with driver workarounds in place + // Fence reset with driver workarounds in place void reset_fence(VkFence *pFence); - void wait_for_fence(VkFence pFence); + VkResult wait_for_fence(VkFence pFence, u64 timeout = 0ull); void die_with_error(const char* faulting_addr, VkResult error_code); diff --git a/rpcs3/rpcs3qt/gs_frame.cpp b/rpcs3/rpcs3qt/gs_frame.cpp index 38f9aee2be..a79ebd0818 100644 --- a/rpcs3/rpcs3qt/gs_frame.cpp +++ b/rpcs3/rpcs3qt/gs_frame.cpp @@ -27,13 +27,162 @@ 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 renderer; + + if (Emu.IsStopped()) + { + // Stop receiving events + _ReleaseHook(); + } + else + { + renderer = fxm::get(); + } + + 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(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(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(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) : QWindow(), m_windowTitle(title), m_gui_settings(gui_settings) { m_disable_mouse = gui_settings->GetValue(gui::gs_disableMouse).toBool(); // Workaround for a Qt bug affecting 5.11.1 binaries - m_use_5_11_1_workaround = QLibraryInfo::version() == QVersionNumber(5, 11, 1); + //m_use_5_11_1_workaround = QLibraryInfo::version() == QVersionNumber(5, 11, 1); //Get version by substringing VersionNumber-buildnumber-commithash to get just the part before the dash std::string version = rpcs3::version.to_string(); @@ -85,6 +234,8 @@ gs_frame::gs_frame(const QString& title, const QRect& geometry, const QIcon& app m_tb_progress = m_tb_button->progress(); m_tb_progress->setRange(0, m_gauge_max); m_tb_progress->setVisible(false); + + win32::_ReleaseHook(); #elif HAVE_QTDBUS UpdateProgress(0); m_progress_value = 0; @@ -126,54 +277,60 @@ void gs_frame::showEvent(QShowEvent *event) void gs_frame::keyPressEvent(QKeyEvent *keyEvent) { - auto l_handleKeyEvent = [this ,keyEvent]() + switch (keyEvent->key()) { - switch (keyEvent->key()) + case Qt::Key_L: + if (keyEvent->modifiers() == Qt::AltModifier) { static int count = 0; LOG_SUCCESS(GENERAL, "Made forced mark %d in log", ++count); } + break; + case Qt::Key_Return: + if (keyEvent->modifiers() == Qt::AltModifier) { toggle_fullscreen(); return; } + break; + case Qt::Key_Escape: + if (visibility() == FullScreen) { toggle_fullscreen(); return; } + break; + case Qt::Key_P: + if (keyEvent->modifiers() == Qt::ControlModifier && Emu.IsRunning()) { Emu.Pause(); return; } + break; + case Qt::Key_S: + if (keyEvent->modifiers() == Qt::ControlModifier && (!Emu.IsStopped())) { Emu.Stop(); return; } + break; + case Qt::Key_R: + if (keyEvent->modifiers() == Qt::ControlModifier && (!Emu.GetBoot().empty())) { Emu.Restart(); return; } + break; + case Qt::Key_E: + if (keyEvent->modifiers() == Qt::ControlModifier) { - case Qt::Key_L: - if (keyEvent->modifiers() == Qt::AltModifier) { static int count = 0; LOG_SUCCESS(GENERAL, "Made forced mark %d in log", ++count); } - break; - case Qt::Key_Return: - if (keyEvent->modifiers() == Qt::AltModifier) { OnFullScreen(); return; } - break; - case Qt::Key_Escape: - if (visibility() == FullScreen) { setVisibility(Windowed); return; } - break; - case Qt::Key_P: - if (keyEvent->modifiers() == Qt::ControlModifier && Emu.IsRunning()) { Emu.Pause(); return; } - break; - case Qt::Key_S: - if (keyEvent->modifiers() == Qt::ControlModifier && (!Emu.IsStopped())) { Emu.Stop(); return; } - break; - case Qt::Key_R: - if (keyEvent->modifiers() == Qt::ControlModifier && (!Emu.GetBoot().empty())) { Emu.Restart(); return; } - break; - case Qt::Key_E: - if (keyEvent->modifiers() == Qt::ControlModifier) - { - if (Emu.IsReady()) { Emu.Run(); return; } - else if (Emu.IsPaused()) { Emu.Resume(); return; } - } - break; + if (Emu.IsReady()) { Emu.Run(); return; } + else if (Emu.IsPaused()) { Emu.Resume(); return; } } - }; - Emu.CallAfter(l_handleKeyEvent); + break; + } } -void gs_frame::OnFullScreen() +void gs_frame::toggle_fullscreen() { - auto l_setFullScreenVis = [=]() + if (wm_allow_fullscreen) { - if (visibility() == FullScreen) + auto l_setFullScreenVis = [&]() { - setVisibility(Windowed); - } - else - { - setVisibility(FullScreen); - } - }; - Emu.CallAfter(l_setFullScreenVis); + if (visibility() == 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); + } } void gs_frame::close() @@ -248,6 +405,10 @@ 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) @@ -310,7 +471,7 @@ void gs_frame::mouseDoubleClickEvent(QMouseEvent* ev) if (ev->button() == Qt::LeftButton) { - OnFullScreen(); + toggle_fullscreen(); } } @@ -351,127 +512,6 @@ bool gs_frame::event(QEvent* ev) return QWindow::event(ev); } -bool gs_frame::nativeEvent(const QByteArray &eventType, void *message, long *result) -{ -#ifdef _WIN32 - if (wm_event_queue_enabled.load(std::memory_order_consume) && !Emu.IsStopped()) - { - //Wait for consumer to clear notification pending flag - while (wm_event_raised.load(std::memory_order_consume) && !Emu.IsStopped()); - - { - MSG* msg; - if (m_use_5_11_1_workaround) - { - // https://bugreports.qt.io/browse/QTBUG-69074?focusedCommentId=409797&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-409797 - msg = *reinterpret_cast(message); - } - else - { - msg = reinterpret_cast(message); - } - - std::lock_guard lock(wm_event_lock); - - switch (msg->message) - { - 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; - - m_in_sizing_event = false; - - 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 - { - //Handle the resize in WM_SIZE message - m_in_sizing_event = true; - break; - } - } - - //Possibly finished resizing using maximize or SWP - 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) - { - //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: - { - 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; - } - } - } - - //Do not enter DefWndProc until the consumer has consumed the message - while (wm_event_raised.load(std::memory_order_consume) && !Emu.IsStopped()); - } -#endif - - //Let the default handler deal with this. Only the notification is required - return false; -} - -wm_event gs_frame::get_default_wm_event() const -{ - return (m_user_interaction_active) ? wm_event::geometry_change_in_progress : wm_event::none; -} - void gs_frame::progress_reset(bool reset_limit) { #ifdef _WIN32 diff --git a/rpcs3/rpcs3qt/gs_frame.h b/rpcs3/rpcs3qt/gs_frame.h index 1cfa430a39..313d7ada86 100644 --- a/rpcs3/rpcs3qt/gs_frame.h +++ b/rpcs3/rpcs3qt/gs_frame.h @@ -40,13 +40,6 @@ private: bool m_show_fps; bool m_disable_mouse; - 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; - - bool m_use_5_11_1_workaround = false; // QT ABI bug workaround - public: gs_frame(const QString& title, const QRect& geometry, const QIcon& appIcon, const std::shared_ptr& gui_settings); ~gs_frame(); @@ -54,8 +47,7 @@ public: draw_context_t make_context() override; void set_current(draw_context_t context) override; void delete_context(draw_context_t context) override; - - wm_event get_default_wm_event() const override; + void toggle_fullscreen() override; // taskbar progress void progress_reset(bool reset_limit = false); @@ -67,7 +59,6 @@ protected: virtual void showEvent(QShowEvent *event) override; void keyPressEvent(QKeyEvent *keyEvent) override; - void OnFullScreen(); void close() override; @@ -82,8 +73,6 @@ protected: int client_width() override; int client_height() override; - bool nativeEvent(const QByteArray &eventType, void *message, long *result) override; - bool event(QEvent* ev) override; private Q_SLOTS: