rsx/qt: Implement native window hooks for win32 windows to allow communication between WndProc thread and rsx::thread

- This communication is important in communicating window events. Helps properly synchronize swapchain management on vulkan and stops nvidia crashing
- Do not block the message queue lest the driver detect window as not responding
This commit is contained in:
kd-11 2017-10-11 01:09:04 +03:00
parent e8bde583ef
commit 58860614e3
8 changed files with 379 additions and 162 deletions

View file

@ -12,6 +12,10 @@
#include "rpcs3_version.h"
#ifdef _WIN32
#include <windows.h>
#endif
constexpr auto qstr = QString::fromStdString;
gs_frame::gs_frame(const QString& title, int w, int h, QIcon appIcon, bool disableMouse)
@ -238,3 +242,88 @@ bool gs_frame::event(QEvent* ev)
}
return QWindow::event(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));
{
std::lock_guard<std::mutex> lock(wm_event_lock);
MSG* msg = static_cast<MSG*>(message);
switch (msg->message)
{
case WM_WINDOWPOSCHANGING:
{
const auto flags = reinterpret_cast<LPWINDOWPOS>(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<LPWINDOWPOS>(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)
{
//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));
#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;
}