Selaa lähdekoodia

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.
Andreas Kling 6 vuotta sitten
vanhempi
commit
7efd61fcf5

+ 2 - 1
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<GPaintEvent>(event.paint.rect, event.paint.window_size));
+    for (int i = 0; i < event.rect_count; ++i)
+        post_event(window, make<GPaintEvent>(event.rects[i], event.paint.window_size));
 }
 
 void GEventLoop::handle_resize_event(const WSAPI_ServerMessage& event, GWindow& window)

+ 9 - 7
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();
         });
     }

+ 18 - 5
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 {

+ 16 - 9
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)

+ 1 - 1
Servers/WindowServer/WSClientConnection.h

@@ -37,7 +37,7 @@ public:
     template<typename Callback> 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;

+ 4 - 4
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<Rect, 32>& 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<Rect, 32>& rects() const { return m_rects; }
 
 private:
     int m_window_id { 0 };
-    Rect m_rect;
+    Vector<Rect, 32> m_rects;
 };
 
 class WSAPIGetWindowBackingStoreRequest final : public WSAPIClientRequest {

+ 7 - 2
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<WSAPIGetClipboardContentsRequest>(client_id));
         break;
-    case WSAPI_ClientMessage::Type::InvalidateRect:
-        post_event(client, make<WSAPIInvalidateRectRequest>(client_id, message.window_id, message.window.rect));
+    case WSAPI_ClientMessage::Type::InvalidateRect: {
+        Vector<Rect, 32> rects;
+        ASSERT(message.rect_count <= 32);
+        for (int i = 0; i < message.rect_count; ++i)
+            rects.append(message.rects[i]);
+        post_event(client, make<WSAPIInvalidateRectRequest>(client_id, message.window_id, rects));
         break;
+    }
     case WSAPI_ClientMessage::Type::DidFinishPainting:
         post_event(client, make<WSAPIDidFinishPaintingNotification>(client_id, message.window_id, message.window.rect));
         break;

+ 10 - 0
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);
+}

+ 5 - 0
Servers/WindowServer/WSWindow.h

@@ -7,6 +7,7 @@
 #include <LibCore/CObject.h>
 #include <WindowServer/WSWindowType.h>
 #include <WindowServer/WSWindowFrame.h>
+#include <SharedGraphics/DisjointRectSet.h>
 
 class WSClientConnection;
 class WSCursor;
@@ -127,6 +128,9 @@ public:
     const WSCursor* override_cursor() const { return m_override_cursor.ptr(); }
     void set_override_cursor(RetainPtr<WSCursor>&& 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;
 };

+ 2 - 0
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<Rect, 32>& rects() const { return m_rects; }