1
0
mirror of https://github.com/RPCS3/rpcs3.git synced 2024-11-25 12:12:50 +01: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:
kd-11 2019-06-10 12:29:46 +03:00 committed by kd-11
parent 57196f0504
commit d361eedbec
8 changed files with 77 additions and 446 deletions

View File

@ -1,4 +1,4 @@
#ifdef _MSC_VER #ifdef _MSC_VER
#include "stdafx.h" #include "stdafx.h"
#include "stdafx_d3d12.h" #include "stdafx_d3d12.h"
#include "D3D12GSRender.h" #include "D3D12GSRender.h"
@ -308,12 +308,6 @@ void D3D12GSRender::on_exit()
void D3D12GSRender::do_local_task(rsx::FIFO_state state) 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); rsx::thread::do_local_task(state);
} }

View File

@ -939,12 +939,8 @@ void GLGSRender::on_init_thread()
if (!supports_native_ui) if (!supports_native_ui)
{ {
m_frame->disable_wm_event_queue();
m_frame->hide(); m_frame->hide();
m_shaders_cache->load(nullptr); m_shaders_cache->load(nullptr);
m_frame->enable_wm_event_queue();
m_frame->show(); m_frame->show();
} }
else else
@ -1004,7 +1000,6 @@ void GLGSRender::on_init_thread()
} }
helper(this); helper(this);
m_frame->enable_wm_event_queue();
m_shaders_cache->load(&helper); m_shaders_cache->load(&helper);
} }
} }
@ -1918,8 +1913,6 @@ void GLGSRender::do_local_task(rsx::FIFO_state state)
return; return;
} }
m_frame->clear_wm_events();
if (m_overlay_manager) if (m_overlay_manager)
{ {
if (!in_begin_end && async_flip_requested & flip_request::native_ui) if (!in_begin_end && async_flip_requested & flip_request::native_ui)

View File

@ -1,4 +1,4 @@
#include "stdafx.h" #include "stdafx.h"
#include "Emu/Memory/vm.h" #include "Emu/Memory/vm.h"
#include "Emu/System.h" #include "Emu/System.h"
@ -41,8 +41,6 @@ void GSRender::on_exit()
{ {
if (m_frame) if (m_frame)
{ {
m_frame->disable_wm_event_queue();
m_frame->clear_wm_events();
m_frame->delete_context(m_context); m_frame->delete_context(m_context);
m_context = nullptr; m_context = nullptr;
} }

View File

@ -84,78 +84,6 @@ using draw_context_t = void*;
virtual int client_height() = 0; virtual int client_height() = 0;
virtual display_handle_t handle() const = 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 class GSRender : public rsx::thread

View File

@ -444,10 +444,13 @@ VKGSRender::VKGSRender() : GSRender()
vk::set_current_thread_ctx(m_thread_context); vk::set_current_thread_ctx(m_thread_context);
vk::set_current_renderer(m_swapchain->get_device()); vk::set_current_renderer(m_swapchain->get_device());
m_client_width = m_frame->client_width(); m_swapchain_dims.width = m_frame->client_width();
m_client_height = m_frame->client_height(); m_swapchain_dims.height = m_frame->client_height();
if (!m_swapchain->init(m_client_width, m_client_height))
present_surface_dirty_flag = true; if (!m_swapchain->init(m_swapchain_dims.width, m_swapchain_dims.height))
{
swapchain_unavailable = true;
}
//create command buffer... //create command buffer...
m_command_buffer_pool.create((*m_device)); 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() VkDescriptorSet VKGSRender::allocate_descriptor_set()
{ {
verify(HERE), m_current_frame->used_descriptors < DESCRIPTOR_MAX_DRAW_CALLS; verify(HERE), m_current_frame->used_descriptors < DESCRIPTOR_MAX_DRAW_CALLS;
@ -1024,7 +920,7 @@ void VKGSRender::begin()
{ {
rsx::thread::begin(); rsx::thread::begin();
if (skip_frame || renderer_unavailable || if (skip_frame || swapchain_unavailable ||
(conditional_render_enabled && conditional_render_test_failed)) (conditional_render_enabled && conditional_render_test_failed))
return; return;
@ -1300,7 +1196,7 @@ void VKGSRender::emit_geometry(u32 sub_index)
void VKGSRender::end() 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)) (conditional_render_enabled && conditional_render_test_failed))
{ {
execute_nop_draw(); execute_nop_draw();
@ -1876,10 +1772,8 @@ void VKGSRender::on_init_thread()
if (!supports_native_ui) if (!supports_native_ui)
{ {
m_frame->disable_wm_event_queue();
m_frame->hide(); m_frame->hide();
m_shaders_cache->load(nullptr, *m_device, pipeline_layout); m_shaders_cache->load(nullptr, *m_device, pipeline_layout);
m_frame->enable_wm_event_queue();
m_frame->show(); m_frame->show();
} }
else else
@ -1939,18 +1833,8 @@ void VKGSRender::on_init_thread()
} }
helper(this); helper(this);
//TODO: Handle window resize messages during loading on GPUs without OUT_OF_DATE_KHR support // TODO: Handle window resize messages during loading on GPUs without OUT_OF_DATE_KHR support
m_frame->disable_wm_event_queue();
m_shaders_cache->load(&helper, *m_device, pipeline_layout); 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) 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 stencil write mask is disabled, remove clear_stencil bit
if (!rsx::method_registers.stencil_mask()) mask &= ~0x2u; 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; 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)) 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: case VK_SUBOPTIMAL_KHR:
break; break;
case VK_ERROR_OUT_OF_DATE_KHR: case VK_ERROR_OUT_OF_DATE_KHR:
present_surface_dirty_flag = true; swapchain_unavailable = true;
break; break;
default: default:
vk::die_with_error(HERE, error); 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 // Perform hard swap here
if (ctx->swap_command_buffer->wait(FRAME_PRESENT_TIMEOUT) != VK_SUCCESS) if (ctx->swap_command_buffer->wait(FRAME_PRESENT_TIMEOUT) != VK_SUCCESS)
{ {
// Lost surface, release renderer // Lost surface/device, release swapchain
present_surface_dirty_flag = true; swapchain_unavailable = true;
renderer_unavailable = true;
} }
free_resources = true; free_resources = true;
@ -2447,8 +2330,6 @@ void VKGSRender::do_local_task(rsx::FIFO_state state)
break; break;
} }
check_window_status();
if (m_overlay_manager) if (m_overlay_manager)
{ {
if (!in_begin_end && async_flip_requested & flip_request::native_ui) 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() void VKGSRender::reinitialize_swapchain()
{ {
const auto new_width = m_frame->client_width(); m_swapchain_dims.width = m_frame->client_width();
const auto new_height = m_frame->client_height(); m_swapchain_dims.height = m_frame->client_height();
// Reject requests to acquire new swapchain if the window is minimized // 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 // 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 // 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; return;
}
// NOTE: This operation will create a hard sync point // NOTE: This operation will create a hard sync point
close_and_submit_command_buffer(m_current_command_buffer->submit_fence); close_and_submit_command_buffer(m_current_command_buffer->submit_fence);
@ -3073,18 +2957,14 @@ void VKGSRender::reinitialize_swapchain()
vkDeviceWaitIdle(*m_device); vkDeviceWaitIdle(*m_device);
// Rebuild swapchain. Old swapchain destruction is handled by the init_swapchain call // 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); LOG_WARNING(RSX, "Swapchain initialization failed. Request ignored [%dx%d]", m_swapchain_dims.width, m_swapchain_dims.height);
present_surface_dirty_flag = true; swapchain_unavailable = true;
renderer_unavailable = true;
open_command_buffer(); open_command_buffer();
return; return;
} }
m_client_width = new_width;
m_client_height = new_height;
// Prepare new swapchain images for use // Prepare new swapchain images for use
open_command_buffer(); open_command_buffer();
@ -3115,26 +2995,24 @@ void VKGSRender::reinitialize_swapchain()
m_current_command_buffer->reset(); m_current_command_buffer->reset();
open_command_buffer(); open_command_buffer();
present_surface_dirty_flag = false; swapchain_unavailable = false;
renderer_unavailable = false;
} }
void VKGSRender::flip(int buffer, bool emu_flip) 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); if (m_swapchain_dims.width != m_frame->client_width() ||
rsx::thread::flip(buffer, emu_flip); m_swapchain_dims.height != m_frame->client_height())
if (!skip_frame)
{ {
m_draw_time = 0; swapchain_unavailable = true;
m_setup_time = 0;
m_vertex_upload_time = 0;
m_textures_upload_time = 0;
} }
}
return; if (swapchain_unavailable)
{
reinitialize_swapchain();
} }
std::chrono::time_point<steady_clock> flip_start = steady_clock::now(); 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) 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"); 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); frame_context_cleanup(m_current_frame, true);
} }
if (present_surface_dirty_flag) if (skip_frame || swapchain_unavailable)
{ {
//Recreate swapchain and continue as usual m_frame->flip(m_context);
reinitialize_swapchain(); 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; return;
}
u32 buffer_width = display_buffers[buffer].width; u32 buffer_width = display_buffers[buffer].width;
u32 buffer_height = display_buffers[buffer].height; u32 buffer_height = display_buffers[buffer].height;
@ -3196,7 +3089,7 @@ void VKGSRender::flip(int buffer, bool emu_flip)
coordi aspect_ratio; coordi aspect_ratio;
sizei csize = { (s32)m_client_width, (s32)m_client_height }; sizei csize = m_swapchain_dims;
sizei new_size = csize; sizei new_size = csize;
if (!g_cfg.video.stretch_to_display_area) 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 //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 //Found on AMD Crimson 17.7.2
//Whatever returned from status, this is now a spin //Whatever returned from status, this is now a spin
timeout = 0ull; timeout = 0ull;
check_present_status(); check_present_status();
continue; continue;
} }
case VK_ERROR_OUT_OF_DATE_KHR: 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."); 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(); reinitialize_swapchain();
return; continue;
default: default:
vk::die_with_error(HERE, status); 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); VkRenderPass single_target_pass = vk::get_renderpass(*m_device, key);
verify("Usupported renderpass configuration" HERE), single_target_pass != VK_NULL_HANDLE; 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(); direct_fbo->add_ref();
if (has_overlay) 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) 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; return false;
// Verify enough memory exists before attempting to handle data transfer // Verify enough memory exists before attempting to handle data transfer

View File

@ -414,8 +414,8 @@ private:
vk::framebuffer_holder* m_draw_fbo = nullptr; vk::framebuffer_holder* m_draw_fbo = nullptr;
bool present_surface_dirty_flag = false; sizeu m_swapchain_dims{};
bool renderer_unavailable = false; bool swapchain_unavailable = false;
u64 m_last_heap_sync_time = 0; u64 m_last_heap_sync_time = 0;
u32 m_texbuffer_view_size = 0; u32 m_texbuffer_view_size = 0;
@ -445,9 +445,6 @@ private:
frame_context_t* m_current_frame = nullptr; frame_context_t* m_current_frame = nullptr;
std::deque<frame_context_t*> m_queued_frames; std::deque<frame_context_t*> m_queued_frames;
u32 m_client_width = 0;
u32 m_client_height = 0;
VkViewport m_viewport{}; VkViewport m_viewport{};
VkRect2D m_scissor{}; VkRect2D m_scissor{};
@ -506,6 +503,7 @@ private:
void update_draw_state(); void update_draw_state();
void check_heap_status(u32 flags = VK_HEAP_CHECK_ALL); void check_heap_status(u32 flags = VK_HEAP_CHECK_ALL);
void check_present_status();
void check_descriptors(); void check_descriptors();
VkDescriptorSet allocate_descriptor_set(); VkDescriptorSet allocate_descriptor_set();
@ -524,9 +522,6 @@ public:
void set_scissor(); void set_scissor();
void bind_viewport(); void bind_viewport();
void check_window_status();
void check_present_status();
void sync_hint(rsx::FIFO_hint hint) override; void sync_hint(rsx::FIFO_hint hint) override;
void begin_occlusion_query(rsx::reports::occlusion_query_info* query) override; void begin_occlusion_query(rsx::reports::occlusion_query_info* query) override;

View File

@ -436,9 +436,6 @@ namespace vk
const auto gpu_name = get_name(); const auto gpu_name = get_name();
if (gpu_name.find("Radeon") != std::string::npos) 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; return driver_vendor::AMD;
} }
@ -2036,13 +2033,9 @@ public:
switch (gpu.get_driver_vendor()) switch (gpu.get_driver_vendor())
{ {
case driver_vendor::NVIDIA:
#ifndef _WIN32
m_wm_reports_flag = true;
#endif
break;
case driver_vendor::AMD: case driver_vendor::AMD:
break; break;
case driver_vendor::NVIDIA:
case driver_vendor::INTEL: case driver_vendor::INTEL:
case driver_vendor::RADV: case driver_vendor::RADV:
m_wm_reports_flag = true; m_wm_reports_flag = true;

View File

@ -27,155 +27,6 @@
constexpr auto qstr = QString::fromStdString; 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) 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) : 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->setRange(0, m_gauge_max);
m_tb_progress->setVisible(false); m_tb_progress->setVisible(false);
win32::_ReleaseHook();
#elif HAVE_QTDBUS #elif HAVE_QTDBUS
UpdateProgress(0); UpdateProgress(0);
m_progress_value = 0; m_progress_value = 0;
@ -309,28 +159,19 @@ void gs_frame::keyPressEvent(QKeyEvent *keyEvent)
void gs_frame::toggle_fullscreen() void gs_frame::toggle_fullscreen()
{ {
if (wm_allow_fullscreen) auto l_setFullScreenVis = [&]()
{ {
auto l_setFullScreenVis = [&]() if (visibility() == FullScreen)
{ {
if (visibility() == FullScreen) setVisibility(Windowed);
{ }
setVisibility(Windowed); else
} {
else setVisibility(FullScreen);
{ }
setVisibility(FullScreen); };
}
};
Emu.CallAfter(l_setFullScreenVis); 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() void gs_frame::close()
@ -405,10 +246,6 @@ draw_context_t gs_frame::make_context()
void gs_frame::set_current(draw_context_t ctx) void gs_frame::set_current(draw_context_t ctx)
{ {
Q_UNUSED(ctx); Q_UNUSED(ctx);
#ifdef _WIN32
win32::_InstallHook();
#endif
} }
void gs_frame::delete_context(draw_context_t ctx) void gs_frame::delete_context(draw_context_t ctx)