mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-22 15:40:19 +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:
parent
ec365b82d5
commit
7efd61fcf5
Notes:
sideshowbarker
2024-07-19 14:38:25 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/7efd61fcf5b
10 changed files with 74 additions and 29 deletions
|
@ -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)
|
||||
|
|
|
@ -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();
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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; }
|
||||
|
|
Loading…
Reference in a new issue