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
This commit is contained in:
kd-11 2019-01-07 01:03:56 +03:00 committed by kd-11
parent 987b607cb0
commit 3bfa564ef8
7 changed files with 420 additions and 314 deletions

View File

@ -1,4 +1,4 @@
#pragma once
#pragma once
#include "Emu/RSX/RSXThread.h"
#include <memory>
@ -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<wm_event> 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; };
};

View File

@ -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)

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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);

View File

@ -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<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)
{
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<MSG**>(message);
}
else
{
msg = reinterpret_cast<MSG*>(message);
}
std::lock_guard lock(wm_event_lock);
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;
m_in_sizing_event = false;
if (flags & SWP_NOSIZE)
{
m_raised_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
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

View File

@ -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>& 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: