mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-26 09:30:24 +00:00
WSCompositor: Allow a compose to bypass the timer when it first happens
d66fa60fcf
introduced the use of a timer
to coalesce screen updates. This is OK, but it does introduce update
latency.
To help mitigate the impact of this, we now have a second (immediate)
timer. When a compose pass is first triggered, the immediate timer will
allow the compose to happen on the next spin of the event loop (so, only
coalescing updates across a single event loop pass). Any updates that
trigger while the delayed timer is running, though, will be delayed to
that (~60fps) timer.
This fixes #103.
This commit is contained in:
parent
8df3e2516f
commit
9b86eb9fad
Notes:
sideshowbarker
2024-07-19 13:55:46 +09:00
Author: https://github.com/rburchell Commit: https://github.com/SerenityOS/serenity/commit/9b86eb9fadc Pull-request: https://github.com/SerenityOS/serenity/pull/116
3 changed files with 32 additions and 5 deletions
|
@ -30,12 +30,20 @@ WSCompositor::WSCompositor()
|
||||||
|
|
||||||
m_compose_timer.on_timeout = [=]() {
|
m_compose_timer.on_timeout = [=]() {
|
||||||
#if defined(COMPOSITOR_DEBUG)
|
#if defined(COMPOSITOR_DEBUG)
|
||||||
dbgprintf("WSCompositor: frame callback\n");
|
dbgprintf("WSCompositor: delayed frame callback: %d rects\n", m_dirty_rects.size());
|
||||||
#endif
|
#endif
|
||||||
compose();
|
compose();
|
||||||
};
|
};
|
||||||
m_compose_timer.set_single_shot(true);
|
m_compose_timer.set_single_shot(true);
|
||||||
m_compose_timer.set_interval(1000 / 60);
|
m_compose_timer.set_interval(1000 / 60);
|
||||||
|
m_immediate_compose_timer.on_timeout = [=]() {
|
||||||
|
#if defined(COMPOSITOR_DEBUG)
|
||||||
|
dbgprintf("WSCompositor: immediate frame callback: %d rects\n", m_dirty_rects.size());
|
||||||
|
#endif
|
||||||
|
compose();
|
||||||
|
};
|
||||||
|
m_immediate_compose_timer.set_single_shot(true);
|
||||||
|
m_immediate_compose_timer.set_interval(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WSCompositor::compose()
|
void WSCompositor::compose()
|
||||||
|
@ -43,6 +51,12 @@ void WSCompositor::compose()
|
||||||
auto& wm = WSWindowManager::the();
|
auto& wm = WSWindowManager::the();
|
||||||
|
|
||||||
auto dirty_rects = move(m_dirty_rects);
|
auto dirty_rects = move(m_dirty_rects);
|
||||||
|
|
||||||
|
if (dirty_rects.size() == 0) {
|
||||||
|
// nothing dirtied since the last compose pass.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
dirty_rects.add(Rect::intersection(m_last_geometry_label_rect, WSScreen::the().rect()));
|
dirty_rects.add(Rect::intersection(m_last_geometry_label_rect, WSScreen::the().rect()));
|
||||||
dirty_rects.add(Rect::intersection(m_last_cursor_rect, WSScreen::the().rect()));
|
dirty_rects.add(Rect::intersection(m_last_cursor_rect, WSScreen::the().rect()));
|
||||||
dirty_rects.add(Rect::intersection(current_cursor_rect(), WSScreen::the().rect()));
|
dirty_rects.add(Rect::intersection(current_cursor_rect(), WSScreen::the().rect()));
|
||||||
|
@ -161,11 +175,22 @@ void WSCompositor::invalidate(const Rect& a_rect)
|
||||||
if (rect.is_empty())
|
if (rect.is_empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
#if defined(COMPOSITOR_DEBUG)
|
|
||||||
dbgprintf("Invalidated: %dx%d %dx%d\n", a_rect.x(), a_rect.y(), a_rect.width(), a_rect.height());
|
|
||||||
#endif
|
|
||||||
m_dirty_rects.add(rect);
|
m_dirty_rects.add(rect);
|
||||||
|
|
||||||
|
// We delay composition by a timer interval, but to not affect latency too
|
||||||
|
// much, if a pending compose is not already scheduled, we also schedule an
|
||||||
|
// immediate compose the next spin of the event loop.
|
||||||
|
if (!m_compose_timer.is_active()) {
|
||||||
|
#if defined(COMPOSITOR_DEBUG)
|
||||||
|
dbgprintf("Invalidated (starting immediate frame): %dx%d %dx%d\n", a_rect.x(), a_rect.y(), a_rect.width(), a_rect.height());
|
||||||
|
#endif
|
||||||
m_compose_timer.start();
|
m_compose_timer.start();
|
||||||
|
m_immediate_compose_timer.start();
|
||||||
|
} else {
|
||||||
|
#if defined(COMPOSITOR_DEBUG)
|
||||||
|
dbgprintf("Invalidated (frame callback pending): %dx%d %dx%d\n", a_rect.x(), a_rect.y(), a_rect.width(), a_rect.height());
|
||||||
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WSCompositor::set_wallpaper(const String& path, Function<void(bool)>&& callback)
|
bool WSCompositor::set_wallpaper(const String& path, Function<void(bool)>&& callback)
|
||||||
|
|
|
@ -40,6 +40,7 @@ private:
|
||||||
unsigned m_compose_count { 0 };
|
unsigned m_compose_count { 0 };
|
||||||
unsigned m_flush_count { 0 };
|
unsigned m_flush_count { 0 };
|
||||||
CTimer m_compose_timer;
|
CTimer m_compose_timer;
|
||||||
|
CTimer m_immediate_compose_timer;
|
||||||
bool m_flash_flush { false };
|
bool m_flash_flush { false };
|
||||||
bool m_buffers_are_flipped { false };
|
bool m_buffers_are_flipped { false };
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@ public:
|
||||||
void add(const Rect&);
|
void add(const Rect&);
|
||||||
|
|
||||||
bool is_empty() const { return m_rects.is_empty(); }
|
bool is_empty() const { return m_rects.is_empty(); }
|
||||||
|
int size() const { return m_rects.size(); }
|
||||||
|
|
||||||
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(); }
|
||||||
|
|
Loading…
Reference in a new issue