mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-10 13:00:29 +03:00
LibGUI+WindowServer: Coalesce paints and resizes on the client side.
Only process paint and resize events on the GUI client side if those events have the latest up-to-date window size. This drastically reduces async overdraw during interactive resize.
This commit is contained in:
parent
0ac55f2c38
commit
55811f233f
Notes:
sideshowbarker
2024-07-19 14:46:28 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/55811f233fa
@ -20,6 +20,7 @@
|
||||
#include <LibC/stdlib.h>
|
||||
|
||||
//#define GEVENTLOOP_DEBUG
|
||||
//#define COALESCING_DEBUG
|
||||
|
||||
static HashMap<GShortcut, GAction*>* g_actions;
|
||||
static GEventLoop* s_main_event_loop;
|
||||
@ -352,7 +353,32 @@ void GEventLoop::wait_for_event()
|
||||
|
||||
void GEventLoop::process_unprocessed_messages()
|
||||
{
|
||||
int coalesced_paints = 0;
|
||||
int coalesced_resizes = 0;
|
||||
auto unprocessed_events = move(m_unprocessed_messages);
|
||||
|
||||
HashMap<int, Size> latest_size_for_window_id;
|
||||
for (auto& event : unprocessed_events) {
|
||||
if (event.type == WSAPI_ServerMessage::Type::WindowResized) {
|
||||
latest_size_for_window_id.set(event.window_id, event.window.rect.size);
|
||||
}
|
||||
}
|
||||
|
||||
int paint_count = 0;
|
||||
HashMap<int, Size> latest_paint_size_for_window_id;
|
||||
for (auto& event : unprocessed_events) {
|
||||
if (event.type == WSAPI_ServerMessage::Type::Paint) {
|
||||
++paint_count;
|
||||
#ifdef COALESCING_DEBUG
|
||||
dbgprintf(" %s (window: %s)\n", Rect(event.paint.rect).to_string().characters(), Size(event.paint.window_size).to_string().characters());
|
||||
#endif
|
||||
latest_paint_size_for_window_id.set(event.window_id, event.paint.window_size);
|
||||
}
|
||||
}
|
||||
#ifdef COALESCING_DEBUG
|
||||
dbgprintf("paint_count: %d\n", paint_count);
|
||||
#endif
|
||||
|
||||
for (auto& event : unprocessed_events) {
|
||||
if (event.type == WSAPI_ServerMessage::Type::Greeting) {
|
||||
s_server_pid = event.greeting.server_pid;
|
||||
@ -387,6 +413,10 @@ void GEventLoop::process_unprocessed_messages()
|
||||
}
|
||||
switch (event.type) {
|
||||
case WSAPI_ServerMessage::Type::Paint:
|
||||
if (Size(event.paint.window_size) != latest_paint_size_for_window_id.get(event.window_id)) {
|
||||
++coalesced_paints;
|
||||
break;
|
||||
}
|
||||
handle_paint_event(event, *window);
|
||||
break;
|
||||
case WSAPI_ServerMessage::Type::MouseDown:
|
||||
@ -410,6 +440,10 @@ void GEventLoop::process_unprocessed_messages()
|
||||
handle_window_entered_or_left_event(event, *window);
|
||||
break;
|
||||
case WSAPI_ServerMessage::Type::WindowResized:
|
||||
if (Size(event.window.rect.size) != latest_size_for_window_id.get(event.window_id)) {
|
||||
++coalesced_resizes;
|
||||
break;
|
||||
}
|
||||
handle_resize_event(event, *window);
|
||||
break;
|
||||
case WSAPI_ServerMessage::Type::WM_WindowRemoved:
|
||||
@ -421,6 +455,13 @@ void GEventLoop::process_unprocessed_messages()
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef COALESCING_DEBUG
|
||||
if (coalesced_paints)
|
||||
dbgprintf("Coalesced %d paints\n", coalesced_paints);
|
||||
if (coalesced_resizes)
|
||||
dbgprintf("Coalesced %d resizes\n", coalesced_resizes);
|
||||
#endif
|
||||
|
||||
if (!m_unprocessed_messages.is_empty())
|
||||
process_unprocessed_messages();
|
||||
}
|
||||
|
@ -211,11 +211,17 @@ void GWindow::event(GEvent& event)
|
||||
return;
|
||||
auto& paint_event = static_cast<GPaintEvent&>(event);
|
||||
auto rect = paint_event.rect();
|
||||
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
|
||||
// effort on painting into an undersized bitmap that will be thrown away anyway.
|
||||
m_back_bitmap = nullptr;
|
||||
}
|
||||
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 = m_main_widget->rect();
|
||||
rect = { { }, paint_event.window_size() };
|
||||
|
||||
m_main_widget->event(*make<GPaintEvent>(rect));
|
||||
|
||||
|
@ -438,10 +438,8 @@ void WSClientConnection::handle_request(const WSAPIDidFinishPaintingNotification
|
||||
auto& window = *(*it).value;
|
||||
|
||||
if (!window.has_painted_since_last_resize()) {
|
||||
if (window.last_lazy_resize_rect().size() == request.rect().size()) {
|
||||
window.set_has_painted_since_last_resize(true);
|
||||
WSMessageLoop::the().post_message(window, make<WSResizeEvent>(window.last_lazy_resize_rect(), window.rect()));
|
||||
}
|
||||
window.set_has_painted_since_last_resize(true);
|
||||
WSMessageLoop::the().post_message(window, make<WSResizeEvent>(window.rect(), window.rect()));
|
||||
}
|
||||
WSWindowManager::the().invalidate(window, request.rect());
|
||||
}
|
||||
|
@ -106,9 +106,6 @@ public:
|
||||
bool has_alpha_channel() const { return m_has_alpha_channel; }
|
||||
void set_has_alpha_channel(bool value) { m_has_alpha_channel = value; }
|
||||
|
||||
void set_last_lazy_resize_rect(const Rect& rect) { m_last_lazy_resize_rect = rect; }
|
||||
Rect last_lazy_resize_rect() const { return m_last_lazy_resize_rect; }
|
||||
|
||||
bool has_painted_since_last_resize() const { return m_has_painted_since_last_resize; }
|
||||
void set_has_painted_since_last_resize(bool b) { m_has_painted_since_last_resize = b; }
|
||||
|
||||
@ -150,7 +147,6 @@ private:
|
||||
RetainPtr<GraphicsBitmap> m_last_backing_store;
|
||||
int m_window_id { -1 };
|
||||
float m_opacity { 1 };
|
||||
Rect m_last_lazy_resize_rect;
|
||||
Size m_size_increment;
|
||||
Size m_base_size;
|
||||
Retained<GraphicsBitmap> m_icon;
|
||||
|
@ -613,10 +613,6 @@ bool WSWindowManager::process_ongoing_window_resize(const WSMouseEvent& event, W
|
||||
m_resize_window->set_rect(new_rect);
|
||||
if (m_resize_window->has_painted_since_last_resize()) {
|
||||
m_resize_window->set_has_painted_since_last_resize(false);
|
||||
#ifdef RESIZE_DEBUG
|
||||
dbgprintf("[WM] I'm gonna wait for %s\n", new_rect.to_string().characters());
|
||||
#endif
|
||||
m_resize_window->set_last_lazy_resize_rect(new_rect);
|
||||
WSMessageLoop::the().post_message(*m_resize_window, make<WSResizeEvent>(old_rect, new_rect));
|
||||
}
|
||||
return true;
|
||||
|
Loading…
Reference in New Issue
Block a user