diff options
author | Andreas Kling <awesomekling@gmail.com> | 2019-04-10 15:39:28 +0200 |
---|---|---|
committer | Andreas Kling <awesomekling@gmail.com> | 2019-04-10 15:39:28 +0200 |
commit | 55811f233fa0150f2d1de269b53f050b86e4c98f (patch) | |
tree | 5bbda4f2b2154b356c426c964034668406051dff /LibGUI | |
parent | 0ac55f2c38efccdc795295e4bfa9f2a187ecb1b3 (diff) | |
download | serenity-55811f233fa0150f2d1de269b53f050b86e4c98f.zip |
LibGUI+WindowServer: Coalesce paints and resizes on the client side.
Only process paint and resize events on the GUI client side if those events
have the latest up-to-date window size. This drastically reduces async
overdraw during interactive resize.
Diffstat (limited to 'LibGUI')
-rw-r--r-- | LibGUI/GEventLoop.cpp | 41 | ||||
-rw-r--r-- | LibGUI/GWindow.cpp | 8 |
2 files changed, 48 insertions, 1 deletions
diff --git a/LibGUI/GEventLoop.cpp b/LibGUI/GEventLoop.cpp index b91f4f9f86..e60ac985d8 100644 --- a/LibGUI/GEventLoop.cpp +++ b/LibGUI/GEventLoop.cpp @@ -20,6 +20,7 @@ #include <LibC/stdlib.h> //#define GEVENTLOOP_DEBUG +//#define COALESCING_DEBUG static HashMap<GShortcut, GAction*>* g_actions; static GEventLoop* s_main_event_loop; @@ -352,7 +353,32 @@ void GEventLoop::wait_for_event() void GEventLoop::process_unprocessed_messages() { + int coalesced_paints = 0; + int coalesced_resizes = 0; auto unprocessed_events = move(m_unprocessed_messages); + + HashMap<int, Size> latest_size_for_window_id; + for (auto& event : unprocessed_events) { + if (event.type == WSAPI_ServerMessage::Type::WindowResized) { + latest_size_for_window_id.set(event.window_id, event.window.rect.size); + } + } + + int paint_count = 0; + HashMap<int, Size> latest_paint_size_for_window_id; + for (auto& event : unprocessed_events) { + if (event.type == WSAPI_ServerMessage::Type::Paint) { + ++paint_count; +#ifdef COALESCING_DEBUG + dbgprintf(" %s (window: %s)\n", Rect(event.paint.rect).to_string().characters(), Size(event.paint.window_size).to_string().characters()); +#endif + latest_paint_size_for_window_id.set(event.window_id, event.paint.window_size); + } + } +#ifdef COALESCING_DEBUG + dbgprintf("paint_count: %d\n", paint_count); +#endif + for (auto& event : unprocessed_events) { if (event.type == WSAPI_ServerMessage::Type::Greeting) { s_server_pid = event.greeting.server_pid; @@ -387,6 +413,10 @@ void GEventLoop::process_unprocessed_messages() } switch (event.type) { case WSAPI_ServerMessage::Type::Paint: + if (Size(event.paint.window_size) != latest_paint_size_for_window_id.get(event.window_id)) { + ++coalesced_paints; + break; + } handle_paint_event(event, *window); break; case WSAPI_ServerMessage::Type::MouseDown: @@ -410,6 +440,10 @@ void GEventLoop::process_unprocessed_messages() handle_window_entered_or_left_event(event, *window); break; case WSAPI_ServerMessage::Type::WindowResized: + if (Size(event.window.rect.size) != latest_size_for_window_id.get(event.window_id)) { + ++coalesced_resizes; + break; + } handle_resize_event(event, *window); break; case WSAPI_ServerMessage::Type::WM_WindowRemoved: @@ -421,6 +455,13 @@ void GEventLoop::process_unprocessed_messages() } } +#ifdef COALESCING_DEBUG + if (coalesced_paints) + dbgprintf("Coalesced %d paints\n", coalesced_paints); + if (coalesced_resizes) + dbgprintf("Coalesced %d resizes\n", coalesced_resizes); +#endif + if (!m_unprocessed_messages.is_empty()) process_unprocessed_messages(); } diff --git a/LibGUI/GWindow.cpp b/LibGUI/GWindow.cpp index d2f41176ef..1c47ec3c6c 100644 --- a/LibGUI/GWindow.cpp +++ b/LibGUI/GWindow.cpp @@ -211,11 +211,17 @@ void GWindow::event(GEvent& event) return; auto& paint_event = static_cast<GPaintEvent&>(event); auto rect = paint_event.rect(); + if (m_back_bitmap && m_back_bitmap->size() != paint_event.window_size()) { + // Eagerly discard the backing store if we learn from this paint event that it needs to be bigger. + // Otherwise we would have to wait for a resize event to tell us. This way we don't waste the + // effort on painting into an undersized bitmap that will be thrown away anyway. + m_back_bitmap = nullptr; + } bool created_new_backing_store = !m_back_bitmap; if (!m_back_bitmap) m_back_bitmap = create_backing_bitmap(paint_event.window_size()); if (rect.is_empty() || created_new_backing_store) - rect = m_main_widget->rect(); + rect = { { }, paint_event.window_size() }; m_main_widget->event(*make<GPaintEvent>(rect)); |