mirror of
https://github.com/SerenityOS/serenity.git
synced 2025-01-23 09:51:57 -05:00
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. :^)
This commit is contained in:
parent
7efd61fcf5
commit
7234900f61
6 changed files with 54 additions and 18 deletions
|
@ -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())
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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() });
|
||||
}
|
||||
|
||||
if (m_double_buffering_enabled)
|
||||
flip(rect);
|
||||
else if (created_new_backing_store)
|
||||
for (auto& rect : rects) {
|
||||
m_main_widget->event(*make<GPaintEvent>(rect));
|
||||
if (m_double_buffering_enabled)
|
||||
flip(rect);
|
||||
}
|
||||
|
||||
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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue