From 7efd61fcf5b6b993cb8a142c8bf84ec7c2de16b5 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Sat, 20 Apr 2019 17:19:56 +0200 Subject: [PATCH] WindowSerer+LibGUI: Send multiple rects in invalidation/flush messages. This patch moves to sending up to 32 rects at a time when coordinating the painting between WindowServer and its clients. Rects are also merged into a minimal DisjointRectSet on the server side before painting. Interactive resize looks a lot better after this change, since we can usually do all the repainting needed in one go. --- LibGUI/GEventLoop.cpp | 3 ++- LibGUI/GWindow.cpp | 16 +++++++------ Servers/WindowServer/WSAPITypes.h | 23 ++++++++++++++----- Servers/WindowServer/WSClientConnection.cpp | 25 +++++++++++++-------- Servers/WindowServer/WSClientConnection.h | 2 +- Servers/WindowServer/WSEvent.h | 8 +++---- Servers/WindowServer/WSEventLoop.cpp | 9 ++++++-- Servers/WindowServer/WSWindow.cpp | 10 +++++++++ Servers/WindowServer/WSWindow.h | 5 +++++ SharedGraphics/DisjointRectSet.h | 2 ++ 10 files changed, 74 insertions(+), 29 deletions(-) diff --git a/LibGUI/GEventLoop.cpp b/LibGUI/GEventLoop.cpp index 809943a738f..027e583b8be 100644 --- a/LibGUI/GEventLoop.cpp +++ b/LibGUI/GEventLoop.cpp @@ -84,7 +84,8 @@ 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 - post_event(window, make(event.paint.rect, event.paint.window_size)); + for (int i = 0; i < event.rect_count; ++i) + post_event(window, make(event.rects[i], 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 d3d38a73a70..310f2e657c6 100644 --- a/LibGUI/GWindow.cpp +++ b/LibGUI/GWindow.cpp @@ -302,13 +302,15 @@ void GWindow::update(const Rect& a_rect) if (m_pending_paint_event_rects.is_empty()) { deferred_invoke([this] (auto&) { - for (auto& rect : m_pending_paint_event_rects) { - WSAPI_ClientMessage request; - request.type = WSAPI_ClientMessage::Type::InvalidateRect; - request.window_id = m_window_id; - request.window.rect = rect; - GEventLoop::current().post_message_to_server(request); - } + // FIXME: Break it into multiple batches if needed. + ASSERT(m_pending_paint_event_rects.size() <= 32); + WSAPI_ClientMessage request; + request.type = WSAPI_ClientMessage::Type::InvalidateRect; + request.window_id = m_window_id; + for (int i = 0; i < m_pending_paint_event_rects.size(); ++i) + request.rects[i] = m_pending_paint_event_rects[i]; + request.rect_count = m_pending_paint_event_rects.size(); + GEventLoop::current().post_message_to_server(request); m_pending_paint_event_rects.clear_with_capacity(); }); } diff --git a/Servers/WindowServer/WSAPITypes.h b/Servers/WindowServer/WSAPITypes.h index 99f74bbb1d2..8d866a5846c 100644 --- a/Servers/WindowServer/WSAPITypes.h +++ b/Servers/WindowServer/WSAPITypes.h @@ -109,8 +109,16 @@ struct WSAPI_ServerMessage { }; Type type { Invalid }; int window_id { -1 }; - int text_length { 0 }; - char text[256]; + + union { + int text_length { 0 }; + int rect_count; + }; + + union { + char text[512]; + WSAPI_Rect rects[32]; + }; int value { 0 }; union { @@ -134,7 +142,6 @@ struct WSAPI_ServerMessage { WSAPI_Rect old_rect; } window; struct { - WSAPI_Rect rect; WSAPI_Size window_size; } paint; struct { @@ -207,8 +214,14 @@ struct WSAPI_ClientMessage { }; Type type { Invalid }; int window_id { -1 }; - int text_length { 0 }; - char text[256]; + union { + int text_length { 0 }; + int rect_count; + }; + union { + char text[512]; + WSAPI_Rect rects[32]; + }; int value { 0 }; union { diff --git a/Servers/WindowServer/WSClientConnection.cpp b/Servers/WindowServer/WSClientConnection.cpp index c081765fdea..b5eef4cae83 100644 --- a/Servers/WindowServer/WSClientConnection.cpp +++ b/Servers/WindowServer/WSClientConnection.cpp @@ -383,7 +383,7 @@ void WSClientConnection::handle_request(const WSAPISetWindowRectRequest& request } auto& window = *(*it).value; window.set_rect(request.rect()); - post_paint_request(window, request.rect()); + window.request_update(request.rect()); } void WSClientConnection::handle_request(const WSAPIGetWindowRectRequest& request) @@ -477,14 +477,20 @@ void WSClientConnection::handle_request(const WSAPIDestroyWindowRequest& request post_message(response); } -void WSClientConnection::post_paint_request(const WSWindow& window, const Rect& rect) +void WSClientConnection::post_paint_message(WSWindow& window) { - WSAPI_ServerMessage response; - response.type = WSAPI_ServerMessage::Type::Paint; - response.window_id = window.window_id(); - response.paint.rect = rect; - response.paint.window_size = window.size(); - post_message(response); + WSAPI_ServerMessage message; + message.type = WSAPI_ServerMessage::Type::Paint; + message.window_id = window.window_id(); + auto rect_set = window.take_pending_paint_rects(); + auto& rects = rect_set.rects(); + // FIXME: Break it into multiple batches if needed. + ASSERT(rects.size() <= 32); + message.rect_count = rects.size(); + for (int i = 0; i < rects.size(); ++i) + message.rects[i] = rects[i]; + message.paint.window_size = window.size(); + post_message(message); } void WSClientConnection::handle_request(const WSAPIInvalidateRectRequest& request) @@ -496,7 +502,8 @@ void WSClientConnection::handle_request(const WSAPIInvalidateRectRequest& reques return; } auto& window = *(*it).value; - post_paint_request(window, request.rect()); + for (int i = 0; i < request.rects().size(); ++i) + window.request_update(request.rects()[i]); } void WSClientConnection::handle_request(const WSAPIDidFinishPaintingNotification& request) diff --git a/Servers/WindowServer/WSClientConnection.h b/Servers/WindowServer/WSClientConnection.h index 44b7c8e3968..5410f7d0837 100644 --- a/Servers/WindowServer/WSClientConnection.h +++ b/Servers/WindowServer/WSClientConnection.h @@ -37,7 +37,7 @@ public: template void for_each_window(Callback); void notify_about_new_screen_rect(const Rect&); - void post_paint_request(const WSWindow&, const Rect&); + void post_paint_message(WSWindow&); private: virtual void event(CEvent&) override; diff --git a/Servers/WindowServer/WSEvent.h b/Servers/WindowServer/WSEvent.h index e667fd5053e..4ab2369dcd2 100644 --- a/Servers/WindowServer/WSEvent.h +++ b/Servers/WindowServer/WSEvent.h @@ -564,19 +564,19 @@ private: class WSAPIInvalidateRectRequest final : public WSAPIClientRequest { public: - explicit WSAPIInvalidateRectRequest(int client_id, int window_id, const Rect& rect) + explicit WSAPIInvalidateRectRequest(int client_id, int window_id, const Vector& rects) : WSAPIClientRequest(WSEvent::APIInvalidateRectRequest, 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; }; class WSAPIGetWindowBackingStoreRequest final : public WSAPIClientRequest { diff --git a/Servers/WindowServer/WSEventLoop.cpp b/Servers/WindowServer/WSEventLoop.cpp index 4d99cc7c8a3..d56a8ab8391 100644 --- a/Servers/WindowServer/WSEventLoop.cpp +++ b/Servers/WindowServer/WSEventLoop.cpp @@ -191,9 +191,14 @@ void WSEventLoop::on_receive_from_client(int client_id, const WSAPI_ClientMessag case WSAPI_ClientMessage::Type::GetClipboardContents: post_event(client, make(client_id)); break; - case WSAPI_ClientMessage::Type::InvalidateRect: - post_event(client, make(client_id, message.window_id, message.window.rect)); + case WSAPI_ClientMessage::Type::InvalidateRect: { + 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::DidFinishPainting: post_event(client, make(client_id, message.window_id, message.window.rect)); break; diff --git a/Servers/WindowServer/WSWindow.cpp b/Servers/WindowServer/WSWindow.cpp index 4bb1e16cd8a..a89679a940a 100644 --- a/Servers/WindowServer/WSWindow.cpp +++ b/Servers/WindowServer/WSWindow.cpp @@ -271,3 +271,13 @@ void WSWindow::set_default_icon() m_icon = default_window_icon(); m_icon_path = default_window_icon_path(); } + +void WSWindow::request_update(const Rect& rect) +{ + if (m_pending_paint_rects.is_empty()) { + deferred_invoke([this] (auto&) { + client()->post_paint_message(*this); + }); + } + m_pending_paint_rects.add(rect); +} diff --git a/Servers/WindowServer/WSWindow.h b/Servers/WindowServer/WSWindow.h index b256504a04d..0d33fa07ef4 100644 --- a/Servers/WindowServer/WSWindow.h +++ b/Servers/WindowServer/WSWindow.h @@ -7,6 +7,7 @@ #include #include #include +#include class WSClientConnection; class WSCursor; @@ -127,6 +128,9 @@ public: const WSCursor* override_cursor() const { return m_override_cursor.ptr(); } void set_override_cursor(RetainPtr&& cursor) { m_override_cursor = move(cursor); } + void request_update(const Rect&); + DisjointRectSet take_pending_paint_rects() { return move(m_pending_paint_rects); } + // For InlineLinkedList. // FIXME: Maybe make a ListHashSet and then WSWindowManager can just use that. WSWindow* m_next { nullptr }; @@ -160,4 +164,5 @@ private: WSWindowFrame m_frame; Color m_background_color { Color::LightGray }; unsigned m_wm_event_mask { 0 }; + DisjointRectSet m_pending_paint_rects; }; diff --git a/SharedGraphics/DisjointRectSet.h b/SharedGraphics/DisjointRectSet.h index 4256b933db3..301c51d9049 100644 --- a/SharedGraphics/DisjointRectSet.h +++ b/SharedGraphics/DisjointRectSet.h @@ -11,6 +11,8 @@ public: void add(const Rect&); + bool is_empty() const { return m_rects.is_empty(); } + void clear() { m_rects.clear(); } void clear_with_capacity() { m_rects.clear_with_capacity(); } const Vector& rects() const { return m_rects; }