summaryrefslogtreecommitdiff
path: root/LibGUI
diff options
context:
space:
mode:
authorAndreas Kling <awesomekling@gmail.com>2019-04-10 15:39:28 +0200
committerAndreas Kling <awesomekling@gmail.com>2019-04-10 15:39:28 +0200
commit55811f233fa0150f2d1de269b53f050b86e4c98f (patch)
tree5bbda4f2b2154b356c426c964034668406051dff /LibGUI
parent0ac55f2c38efccdc795295e4bfa9f2a187ecb1b3 (diff)
downloadserenity-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.cpp41
-rw-r--r--LibGUI/GWindow.cpp8
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));