From 7234900f61fdcb0f13b3555749d1590ea0b0b1d8 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Sat, 20 Apr 2019 17:37:28 +0200 Subject: [PATCH] WindowServer+LibGUI: Coalesce multiple client paints into GMultiPaintEvents. This allows GWindow to paint up to 32 separate rects before telling the WindowServer to flip the buffers. Quite a bit smoother. :^) --- LibGUI/GEvent.h | 18 +++++++++++++ LibGUI/GEventLoop.cpp | 5 +++- LibGUI/GWindow.cpp | 29 ++++++++++++++------- Servers/WindowServer/WSClientConnection.cpp | 3 ++- Servers/WindowServer/WSEvent.h | 8 +++--- Servers/WindowServer/WSEventLoop.cpp | 9 +++++-- 6 files changed, 54 insertions(+), 18 deletions(-) diff --git a/LibGUI/GEvent.h b/LibGUI/GEvent.h index 25636afbef..06a844fee4 100644 --- a/LibGUI/GEvent.h +++ b/LibGUI/GEvent.h @@ -14,6 +14,7 @@ public: Show = 1000, Hide, Paint, + MultiPaint, Resize, MouseMove, MouseDown, @@ -127,6 +128,23 @@ private: String m_icon_path; }; +class GMultiPaintEvent final : public GEvent { +public: + explicit GMultiPaintEvent(const Vector& rects, const Size& window_size) + : GEvent(GEvent::MultiPaint) + , m_rects(rects) + , m_window_size(window_size) + { + } + + const Vector& rects() const { return m_rects; } + Size window_size() const { return m_window_size; } + +private: + Vector m_rects; + Size m_window_size; +}; + class GPaintEvent final : public GEvent { public: explicit GPaintEvent(const Rect& rect, const Size& window_size = Size()) diff --git a/LibGUI/GEventLoop.cpp b/LibGUI/GEventLoop.cpp index 027e583b8b..c03eff530c 100644 --- a/LibGUI/GEventLoop.cpp +++ b/LibGUI/GEventLoop.cpp @@ -84,8 +84,11 @@ void GEventLoop::handle_paint_event(const WSAPI_ServerMessage& event, GWindow& w #ifdef GEVENTLOOP_DEBUG dbgprintf("WID=%x Paint [%d,%d %dx%d]\n", event.window_id, event.paint.rect.location.x, event.paint.rect.location.y, event.paint.rect.size.width, event.paint.rect.size.height); #endif + Vector rects; + ASSERT(event.rect_count <= 32); for (int i = 0; i < event.rect_count; ++i) - post_event(window, make(event.rects[i], event.paint.window_size)); + rects.append(event.rects[i]); + post_event(window, make(rects, event.paint.window_size)); } void GEventLoop::handle_resize_event(const WSAPI_ServerMessage& event, GWindow& window) diff --git a/LibGUI/GWindow.cpp b/LibGUI/GWindow.cpp index 310f2e657c..a9045b0bf0 100644 --- a/LibGUI/GWindow.cpp +++ b/LibGUI/GWindow.cpp @@ -203,13 +203,14 @@ void GWindow::event(CEvent& event) return; } - if (event.type() == GEvent::Paint) { + if (event.type() == GEvent::MultiPaint) { if (!m_window_id) return; if (!m_main_widget) return; - auto& paint_event = static_cast(event); - auto rect = paint_event.rect(); + auto& paint_event = static_cast(event); + auto rects = paint_event.rects(); + ASSERT(!rects.is_empty()); 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 @@ -219,21 +220,29 @@ void GWindow::event(CEvent& event) 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 = { { }, paint_event.window_size() }; - m_main_widget->event(*make(rect)); + auto rect = rects.first(); + if (rect.is_empty() || created_new_backing_store) { + rects.clear(); + rects.append({ { }, paint_event.window_size() }); + } - if (m_double_buffering_enabled) - flip(rect); - else if (created_new_backing_store) + for (auto& rect : rects) { + m_main_widget->event(*make(rect)); + if (m_double_buffering_enabled) + flip(rect); + } + + if (!m_double_buffering_enabled && created_new_backing_store) set_current_backing_bitmap(*m_back_bitmap, true); if (m_window_id) { WSAPI_ClientMessage message; message.type = WSAPI_ClientMessage::Type::DidFinishPainting; message.window_id = m_window_id; - message.window.rect = rect; + message.rect_count = paint_event.rects().size(); + for (int i = 0; i < paint_event.rects().size(); ++i) + message.rects[i] = paint_event.rects()[i]; GEventLoop::current().post_message_to_server(message); } return; diff --git a/Servers/WindowServer/WSClientConnection.cpp b/Servers/WindowServer/WSClientConnection.cpp index b5eef4cae8..f8f2fb13f7 100644 --- a/Servers/WindowServer/WSClientConnection.cpp +++ b/Servers/WindowServer/WSClientConnection.cpp @@ -515,7 +515,8 @@ void WSClientConnection::handle_request(const WSAPIDidFinishPaintingNotification return; } auto& window = *(*it).value; - WSWindowManager::the().invalidate(window, request.rect()); + for (auto& rect : request.rects()) + WSWindowManager::the().invalidate(window, rect); } void WSClientConnection::handle_request(const WSAPIGetWindowBackingStoreRequest& request) diff --git a/Servers/WindowServer/WSEvent.h b/Servers/WindowServer/WSEvent.h index 4ab2369dcd..c2d96f8821 100644 --- a/Servers/WindowServer/WSEvent.h +++ b/Servers/WindowServer/WSEvent.h @@ -595,19 +595,19 @@ private: class WSAPIDidFinishPaintingNotification final : public WSAPIClientRequest { public: - explicit WSAPIDidFinishPaintingNotification(int client_id, int window_id, const Rect& rect) + explicit WSAPIDidFinishPaintingNotification(int client_id, int window_id, const Vector& rects) : WSAPIClientRequest(WSEvent::APIDidFinishPaintingNotification, client_id) , m_window_id(window_id) - , m_rect(rect) + , m_rects(rects) { } int window_id() const { return m_window_id; } - Rect rect() const { return m_rect; } + const Vector& rects() const { return m_rects; } private: int m_window_id { 0 }; - Rect m_rect; + Vector m_rects; }; enum class MouseButton : byte { diff --git a/Servers/WindowServer/WSEventLoop.cpp b/Servers/WindowServer/WSEventLoop.cpp index d56a8ab839..4a5340f1c4 100644 --- a/Servers/WindowServer/WSEventLoop.cpp +++ b/Servers/WindowServer/WSEventLoop.cpp @@ -199,9 +199,14 @@ void WSEventLoop::on_receive_from_client(int client_id, const WSAPI_ClientMessag post_event(client, make(client_id, message.window_id, rects)); break; } - case WSAPI_ClientMessage::Type::DidFinishPainting: - post_event(client, make(client_id, message.window_id, message.window.rect)); + case WSAPI_ClientMessage::Type::DidFinishPainting: { + Vector rects; + ASSERT(message.rect_count <= 32); + for (int i = 0; i < message.rect_count; ++i) + rects.append(message.rects[i]); + post_event(client, make(client_id, message.window_id, rects)); break; + } case WSAPI_ClientMessage::Type::GetWindowBackingStore: post_event(client, make(client_id, message.window_id)); break;