Просмотр исходного кода

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. :^)
Andreas Kling 6 лет назад
Родитель
Сommit
7234900f61

+ 18 - 0
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<Rect, 32>& rects, const Size& window_size)
+        : GEvent(GEvent::MultiPaint)
+        , m_rects(rects)
+        , m_window_size(window_size)
+    {
+    }
+
+    const Vector<Rect, 32>& rects() const { return m_rects; }
+    Size window_size() const { return m_window_size; }
+
+private:
+    Vector<Rect, 32> m_rects;
+    Size m_window_size;
+};
+
 class GPaintEvent final : public GEvent {
 public:
     explicit GPaintEvent(const Rect& rect, const Size& window_size = Size())

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

+ 19 - 10
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<GPaintEvent&>(event);
-        auto rect = paint_event.rect();
+        auto& paint_event = static_cast<GMultiPaintEvent&>(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<GPaintEvent>(rect));
+        auto rect = rects.first();
+        if (rect.is_empty() || created_new_backing_store) {
+            rects.clear();
+            rects.append({ { }, paint_event.window_size() });
+        }
+
+        for (auto& rect : rects) {
+            m_main_widget->event(*make<GPaintEvent>(rect));
+            if (m_double_buffering_enabled)
+                flip(rect);
+        }
 
-        if (m_double_buffering_enabled)
-            flip(rect);
-        else if (created_new_backing_store)
+        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;

+ 2 - 1
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)

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

+ 7 - 2
Servers/WindowServer/WSEventLoop.cpp

@@ -199,9 +199,14 @@ void WSEventLoop::on_receive_from_client(int client_id, const WSAPI_ClientMessag
         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));
+    case WSAPI_ClientMessage::Type::DidFinishPainting: {
+        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<WSAPIDidFinishPaintingNotification>(client_id, message.window_id, rects));
         break;
+    }
     case WSAPI_ClientMessage::Type::GetWindowBackingStore:
         post_event(client, make<WSAPIGetWindowBackingStoreRequest>(client_id, message.window_id));
         break;