1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-28 16:57:36 +00:00

LibGUI+WindowServer: Improve window resizing performance

The old `GUI::Window` resizing behavior created a new backing store for
each resize event (i.e. every visible window size). This caused a lot of
trashing and on my machine, caused up to 25% of CPU time spent in
creating new backing stores.

The new behavior is a bit more sensible:

  * If the window size is shrinking, the backing store is already large
    enough to contain the entire window - so we don't create a new one.

  * If the window size is growing, as soon as the backing store can no
    longer contain the window, it is inflated with a large margin (of an
    arbitrary chosen 64 pixels) in both directions to accommodate some
    leeway in resizing before an even larger backing store is required.

  * When the user stops resizing the window, the backing store is
    resized to the exact dimensions of the window.

For me, this brings the CPU time for creating backing stores down to 0%.
This commit is contained in:
Jelle Raaijmakers 2023-01-11 21:46:14 +01:00 committed by Andreas Kling
parent 45e85d20b6
commit 634d1e0197
8 changed files with 73 additions and 39 deletions

View file

@ -386,6 +386,10 @@ void Compositor::compose()
});
}
auto update_window_rect = window_rect.intersected(rect);
if (update_window_rect.is_empty())
return;
auto clear_window_rect = [&](const Gfx::IntRect& clear_rect) {
auto fill_color = wm.palette().window();
if (!window.is_opaque())
@ -394,7 +398,7 @@ void Compositor::compose()
};
if (!backing_store) {
clear_window_rect(window_rect.intersected(rect));
clear_window_rect(update_window_rect);
return;
}
@ -407,7 +411,7 @@ void Compositor::compose()
// it was previously, and fill the rest of the window with its
// background color.
Gfx::IntRect backing_rect;
backing_rect.set_size(backing_store->size());
backing_rect.set_size(window.backing_store_visible_size());
switch (WindowManager::the().resize_direction_of_window(window)) {
case ResizeDirection::None:
case ResizeDirection::Right:
@ -434,8 +438,7 @@ void Compositor::compose()
break;
}
Gfx::IntRect dirty_rect_in_backing_coordinates = rect.intersected(window_rect)
.intersected(backing_rect)
Gfx::IntRect dirty_rect_in_backing_coordinates = update_window_rect.intersected(backing_rect)
.translated(-backing_rect.location());
if (!dirty_rect_in_backing_coordinates.is_empty()) {
@ -459,7 +462,7 @@ void Compositor::compose()
}
}
for (auto background_rect : window_rect.shatter(backing_rect))
for (auto background_rect : update_window_rect.shatter(backing_rect))
clear_window_rect(background_rect);
};

View file

@ -733,7 +733,7 @@ void ConnectionFromClient::did_finish_painting(i32 window_id, Vector<Gfx::IntRec
void ConnectionFromClient::set_window_backing_store(i32 window_id, [[maybe_unused]] i32 bpp,
[[maybe_unused]] i32 pitch, IPC::File const& anon_file, i32 serial, bool has_alpha_channel,
Gfx::IntSize size, bool flush_immediately)
Gfx::IntSize size, Gfx::IntSize visible_size, bool flush_immediately)
{
auto it = m_windows.find(window_id);
if (it == m_windows.end()) {
@ -761,6 +761,7 @@ void ConnectionFromClient::set_window_backing_store(i32 window_id, [[maybe_unuse
}
window.set_backing_store(backing_store_or_error.release_value(), serial);
}
window.set_backing_store_visible_size(visible_size);
if (flush_immediately)
window.invalidate(false);

View file

@ -121,7 +121,7 @@ private:
virtual void did_finish_painting(i32, Vector<Gfx::IntRect> const&) override;
virtual void set_global_mouse_tracking(bool) override;
virtual void set_window_opacity(i32, float) override;
virtual void set_window_backing_store(i32, i32, i32, IPC::File const&, i32, bool, Gfx::IntSize, bool) override;
virtual void set_window_backing_store(i32, i32, i32, IPC::File const&, i32, bool, Gfx::IntSize, Gfx::IntSize, bool) override;
virtual void set_window_has_alpha_channel(i32, bool) override;
virtual void set_window_alpha_hit_threshold(i32, float) override;
virtual void move_window_to_front(i32) override;

View file

@ -153,6 +153,7 @@ void Window::set_rect(Gfx::IntRect const& rect)
} else if (is_internal() && (!m_backing_store || old_rect.size() != rect.size())) {
auto format = has_alpha_channel() ? Gfx::BitmapFormat::BGRA8888 : Gfx::BitmapFormat::BGRx8888;
m_backing_store = Gfx::Bitmap::try_create(format, m_rect.size()).release_value_but_fixme_should_propagate_errors();
m_backing_store_visible_size = m_rect.size();
}
if (m_floating_rect.is_empty())

View file

@ -242,6 +242,9 @@ public:
m_backing_store_serial = serial;
}
Gfx::IntSize backing_store_visible_size() const { return m_backing_store_visible_size; }
void set_backing_store_visible_size(Gfx::IntSize visible_size) { m_backing_store_visible_size = visible_size; }
void swap_backing_stores()
{
swap(m_backing_store, m_last_backing_store);
@ -434,6 +437,7 @@ private:
bool m_occluded { false };
RefPtr<Gfx::Bitmap> m_backing_store;
RefPtr<Gfx::Bitmap> m_last_backing_store;
Gfx::IntSize m_backing_store_visible_size {};
i32 m_backing_store_serial { -1 };
i32 m_last_backing_store_serial { -1 };
int m_window_id { -1 };

View file

@ -98,7 +98,7 @@ endpoint WindowServer
set_window_alpha_hit_threshold(i32 window_id, float threshold) =|
set_window_backing_store(i32 window_id, i32 bpp, i32 pitch, IPC::File anon_file, i32 serial, bool has_alpha_channel, Gfx::IntSize size, bool flush_immediately) => ()
set_window_backing_store(i32 window_id, i32 bpp, i32 pitch, IPC::File anon_file, i32 serial, bool has_alpha_channel, Gfx::IntSize size, Gfx::IntSize visible_size, bool flush_immediately) => ()
set_window_has_alpha_channel(i32 window_id, bool has_alpha_channel) =|
move_window_to_front(i32 window_id) =|