1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 11:48:10 +00:00

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.
This commit is contained in:
Andreas Kling 2019-04-20 17:19:56 +02:00
parent ec365b82d5
commit 7efd61fcf5
10 changed files with 74 additions and 29 deletions

View file

@ -84,7 +84,8 @@ void GEventLoop::handle_paint_event(const WSAPI_ServerMessage& event, GWindow& w
#ifdef GEVENTLOOP_DEBUG #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); 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 #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) void GEventLoop::handle_resize_event(const WSAPI_ServerMessage& event, GWindow& window)

View file

@ -302,13 +302,15 @@ void GWindow::update(const Rect& a_rect)
if (m_pending_paint_event_rects.is_empty()) { if (m_pending_paint_event_rects.is_empty()) {
deferred_invoke([this] (auto&) { deferred_invoke([this] (auto&) {
for (auto& rect : m_pending_paint_event_rects) { // FIXME: Break it into multiple batches if needed.
WSAPI_ClientMessage request; ASSERT(m_pending_paint_event_rects.size() <= 32);
request.type = WSAPI_ClientMessage::Type::InvalidateRect; WSAPI_ClientMessage request;
request.window_id = m_window_id; request.type = WSAPI_ClientMessage::Type::InvalidateRect;
request.window.rect = rect; request.window_id = m_window_id;
GEventLoop::current().post_message_to_server(request); 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(); m_pending_paint_event_rects.clear_with_capacity();
}); });
} }

View file

@ -109,8 +109,16 @@ struct WSAPI_ServerMessage {
}; };
Type type { Invalid }; Type type { Invalid };
int window_id { -1 }; 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 }; int value { 0 };
union { union {
@ -134,7 +142,6 @@ struct WSAPI_ServerMessage {
WSAPI_Rect old_rect; WSAPI_Rect old_rect;
} window; } window;
struct { struct {
WSAPI_Rect rect;
WSAPI_Size window_size; WSAPI_Size window_size;
} paint; } paint;
struct { struct {
@ -207,8 +214,14 @@ struct WSAPI_ClientMessage {
}; };
Type type { Invalid }; Type type { Invalid };
int window_id { -1 }; int window_id { -1 };
int text_length { 0 }; union {
char text[256]; int text_length { 0 };
int rect_count;
};
union {
char text[512];
WSAPI_Rect rects[32];
};
int value { 0 }; int value { 0 };
union { union {

View file

@ -383,7 +383,7 @@ void WSClientConnection::handle_request(const WSAPISetWindowRectRequest& request
} }
auto& window = *(*it).value; auto& window = *(*it).value;
window.set_rect(request.rect()); window.set_rect(request.rect());
post_paint_request(window, request.rect()); window.request_update(request.rect());
} }
void WSClientConnection::handle_request(const WSAPIGetWindowRectRequest& request) void WSClientConnection::handle_request(const WSAPIGetWindowRectRequest& request)
@ -477,14 +477,20 @@ void WSClientConnection::handle_request(const WSAPIDestroyWindowRequest& request
post_message(response); post_message(response);
} }
void WSClientConnection::post_paint_request(const WSWindow& window, const Rect& rect) void WSClientConnection::post_paint_message(WSWindow& window)
{ {
WSAPI_ServerMessage response; WSAPI_ServerMessage message;
response.type = WSAPI_ServerMessage::Type::Paint; message.type = WSAPI_ServerMessage::Type::Paint;
response.window_id = window.window_id(); message.window_id = window.window_id();
response.paint.rect = rect; auto rect_set = window.take_pending_paint_rects();
response.paint.window_size = window.size(); auto& rects = rect_set.rects();
post_message(response); // 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) void WSClientConnection::handle_request(const WSAPIInvalidateRectRequest& request)
@ -496,7 +502,8 @@ void WSClientConnection::handle_request(const WSAPIInvalidateRectRequest& reques
return; return;
} }
auto& window = *(*it).value; 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) void WSClientConnection::handle_request(const WSAPIDidFinishPaintingNotification& request)

View file

@ -37,7 +37,7 @@ public:
template<typename Callback> void for_each_window(Callback); template<typename Callback> void for_each_window(Callback);
void notify_about_new_screen_rect(const Rect&); void notify_about_new_screen_rect(const Rect&);
void post_paint_request(const WSWindow&, const Rect&); void post_paint_message(WSWindow&);
private: private:
virtual void event(CEvent&) override; virtual void event(CEvent&) override;

View file

@ -564,19 +564,19 @@ private:
class WSAPIInvalidateRectRequest final : public WSAPIClientRequest { class WSAPIInvalidateRectRequest final : public WSAPIClientRequest {
public: 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) : WSAPIClientRequest(WSEvent::APIInvalidateRectRequest, client_id)
, m_window_id(window_id) , m_window_id(window_id)
, m_rect(rect) , m_rects(rects)
{ {
} }
int window_id() const { return m_window_id; } int window_id() const { return m_window_id; }
Rect rect() const { return m_rect; } const Vector<Rect, 32>& rects() const { return m_rects; }
private: private:
int m_window_id { 0 }; int m_window_id { 0 };
Rect m_rect; Vector<Rect, 32> m_rects;
}; };
class WSAPIGetWindowBackingStoreRequest final : public WSAPIClientRequest { class WSAPIGetWindowBackingStoreRequest final : public WSAPIClientRequest {

View file

@ -191,9 +191,14 @@ void WSEventLoop::on_receive_from_client(int client_id, const WSAPI_ClientMessag
case WSAPI_ClientMessage::Type::GetClipboardContents: case WSAPI_ClientMessage::Type::GetClipboardContents:
post_event(client, make<WSAPIGetClipboardContentsRequest>(client_id)); post_event(client, make<WSAPIGetClipboardContentsRequest>(client_id));
break; break;
case WSAPI_ClientMessage::Type::InvalidateRect: case WSAPI_ClientMessage::Type::InvalidateRect: {
post_event(client, make<WSAPIInvalidateRectRequest>(client_id, message.window_id, message.window.rect)); 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; break;
}
case WSAPI_ClientMessage::Type::DidFinishPainting: case WSAPI_ClientMessage::Type::DidFinishPainting:
post_event(client, make<WSAPIDidFinishPaintingNotification>(client_id, message.window_id, message.window.rect)); post_event(client, make<WSAPIDidFinishPaintingNotification>(client_id, message.window_id, message.window.rect));
break; break;

View file

@ -271,3 +271,13 @@ void WSWindow::set_default_icon()
m_icon = default_window_icon(); m_icon = default_window_icon();
m_icon_path = default_window_icon_path(); 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);
}

View file

@ -7,6 +7,7 @@
#include <LibCore/CObject.h> #include <LibCore/CObject.h>
#include <WindowServer/WSWindowType.h> #include <WindowServer/WSWindowType.h>
#include <WindowServer/WSWindowFrame.h> #include <WindowServer/WSWindowFrame.h>
#include <SharedGraphics/DisjointRectSet.h>
class WSClientConnection; class WSClientConnection;
class WSCursor; class WSCursor;
@ -127,6 +128,9 @@ public:
const WSCursor* override_cursor() const { return m_override_cursor.ptr(); } const WSCursor* override_cursor() const { return m_override_cursor.ptr(); }
void set_override_cursor(RetainPtr<WSCursor>&& cursor) { m_override_cursor = move(cursor); } 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. // For InlineLinkedList.
// FIXME: Maybe make a ListHashSet and then WSWindowManager can just use that. // FIXME: Maybe make a ListHashSet and then WSWindowManager can just use that.
WSWindow* m_next { nullptr }; WSWindow* m_next { nullptr };
@ -160,4 +164,5 @@ private:
WSWindowFrame m_frame; WSWindowFrame m_frame;
Color m_background_color { Color::LightGray }; Color m_background_color { Color::LightGray };
unsigned m_wm_event_mask { 0 }; unsigned m_wm_event_mask { 0 };
DisjointRectSet m_pending_paint_rects;
}; };

View file

@ -11,6 +11,8 @@ public:
void add(const Rect&); void add(const Rect&);
bool is_empty() const { return m_rects.is_empty(); }
void clear() { m_rects.clear(); } void clear() { m_rects.clear(); }
void clear_with_capacity() { m_rects.clear_with_capacity(); } void clear_with_capacity() { m_rects.clear_with_capacity(); }
const Vector<Rect, 32>& rects() const { return m_rects; } const Vector<Rect, 32>& rects() const { return m_rects; }