summaryrefslogtreecommitdiff
path: root/Userland
diff options
context:
space:
mode:
Diffstat (limited to 'Userland')
-rw-r--r--Userland/Libraries/LibC/sys/ioctl_numbers.h3
-rw-r--r--Userland/Services/WindowServer/Compositor.cpp75
-rw-r--r--Userland/Services/WindowServer/Compositor.h2
-rw-r--r--Userland/Services/WindowServer/Screen.cpp4
-rw-r--r--Userland/Services/WindowServer/Screen.h2
5 files changed, 68 insertions, 18 deletions
diff --git a/Userland/Libraries/LibC/sys/ioctl_numbers.h b/Userland/Libraries/LibC/sys/ioctl_numbers.h
index e046d79517..c22f884ff6 100644
--- a/Userland/Libraries/LibC/sys/ioctl_numbers.h
+++ b/Userland/Libraries/LibC/sys/ioctl_numbers.h
@@ -30,7 +30,8 @@ struct FBRect {
unsigned height;
};
-struct FBRects {
+struct FBFlushRects {
+ int buffer_index;
unsigned count;
struct FBRect const* rects;
};
diff --git a/Userland/Services/WindowServer/Compositor.cpp b/Userland/Services/WindowServer/Compositor.cpp
index 9430e11677..c77373998e 100644
--- a/Userland/Services/WindowServer/Compositor.cpp
+++ b/Userland/Services/WindowServer/Compositor.cpp
@@ -80,13 +80,18 @@ const Gfx::Bitmap& Compositor::front_bitmap_for_screenshot(Badge<ClientConnectio
void Compositor::ScreenData::init_bitmaps(Compositor& compositor, Screen& screen)
{
+ m_has_flipped = false;
+ m_have_flush_rects = false;
+ m_buffers_are_flipped = false;
+ m_screen_can_set_buffer = screen.can_set_buffer();
+
auto size = screen.size();
m_front_bitmap = Gfx::Bitmap::create_wrapper(Gfx::BitmapFormat::BGRx8888, size, screen.scale_factor(), screen.pitch(), screen.scanline(0));
m_front_painter = make<Gfx::Painter>(*m_front_bitmap);
m_front_painter->translate(-screen.rect().location());
- if (screen.can_set_buffer())
+ if (m_screen_can_set_buffer)
m_back_bitmap = Gfx::Bitmap::create_wrapper(Gfx::BitmapFormat::BGRx8888, size, screen.scale_factor(), screen.pitch(), screen.scanline(screen.physical_height()));
else
m_back_bitmap = Gfx::Bitmap::create(Gfx::BitmapFormat::BGRx8888, size, screen.scale_factor());
@@ -97,9 +102,6 @@ void Compositor::ScreenData::init_bitmaps(Compositor& compositor, Screen& screen
m_temp_painter = make<Gfx::Painter>(*m_temp_bitmap);
m_temp_painter->translate(-screen.rect().location());
- m_buffers_are_flipped = false;
- m_screen_can_set_buffer = screen.can_set_buffer();
-
// Recreate the screen-number overlay as the Screen instances may have changed, or get rid of it if we no longer need it
if (compositor.showing_screen_numbers()) {
m_screen_number_overlay = compositor.create_overlay<ScreenNumberOverlay>(screen);
@@ -232,6 +234,7 @@ void Compositor::compose()
auto& cursor_screen = ScreenInput::the().cursor_location_screen();
for (auto& screen_data : m_screen_data) {
+ screen_data.m_have_flush_rects = false;
screen_data.m_flush_rects.clear_with_capacity();
screen_data.m_flush_transparent_rects.clear_with_capacity();
screen_data.m_flush_special_rects.clear_with_capacity();
@@ -268,6 +271,7 @@ void Compositor::compose()
dbgln_if(COMPOSE_DEBUG, " -> flush opaque: {}", rect);
VERIFY(!screen_data.m_flush_rects.intersects(rect));
VERIFY(!screen_data.m_flush_transparent_rects.intersects(rect));
+ screen_data.m_have_flush_rects = true;
screen_data.m_flush_rects.add(rect);
check_restore_cursor_back(screen, rect);
};
@@ -281,6 +285,7 @@ void Compositor::compose()
return;
}
+ screen_data.m_have_flush_rects = true;
screen_data.m_flush_transparent_rects.add(rect);
check_restore_cursor_back(screen, rect);
};
@@ -554,6 +559,8 @@ void Compositor::compose()
Screen::for_each([&](auto& screen) {
auto& screen_data = m_screen_data[screen.index()];
update_animations(screen, screen_data.m_flush_special_rects);
+ if (!screen_data.m_flush_special_rects.is_empty())
+ screen_data.m_have_flush_rects = true;
return IterationDecision::Continue;
});
// As long as animations are running make sure we keep rendering frames
@@ -564,9 +571,6 @@ void Compositor::compose()
if (need_to_draw_cursor) {
auto& screen_data = m_screen_data[cursor_screen.index()];
screen_data.draw_cursor(cursor_screen, cursor_rect);
- screen_data.m_flush_rects.add(cursor_rect.intersected(cursor_screen.rect()));
- if (previous_cursor_screen && cursor_rect != previous_cursor_rect)
- m_screen_data[previous_cursor_screen->index()].m_flush_rects.add(previous_cursor_rect);
}
Screen::for_each([&](auto& screen) {
@@ -578,16 +582,45 @@ void Compositor::compose()
void Compositor::flush(Screen& screen)
{
auto& screen_data = m_screen_data[screen.index()];
+
+ bool device_can_flush_buffers = screen.can_device_flush_buffers();
+ if (!screen_data.m_have_flush_rects && (!screen_data.m_screen_can_set_buffer || screen_data.m_has_flipped)) {
+ dbgln_if(COMPOSE_DEBUG, "Nothing to flush on screen #{} {}", screen.index(), screen_data.m_have_flush_rects);
+ return;
+ }
+ screen_data.m_have_flush_rects = false;
+
if (m_flash_flush) {
for (auto& rect : screen_data.m_flush_rects.rects())
screen_data.m_front_painter->fill_rect(rect, Color::Yellow);
}
- if (screen_data.m_screen_can_set_buffer)
+ auto screen_rect = screen.rect();
+ if (device_can_flush_buffers && screen_data.m_screen_can_set_buffer) {
+ if (!screen_data.m_has_flipped) {
+ // If we have not flipped any buffers before, we should be flushing
+ // the entire buffer to make sure that the device has all the bits we wrote
+ screen_data.m_flush_rects = { screen.rect() };
+ }
+
+ // If we also support buffer flipping we need to make sure we transfer all
+ // updated areas to the device before we flip. We already modified the framebuffer
+ // memory, but the device needs to know what areas we actually did update.
+ for (auto& rect : screen_data.m_flush_rects.rects())
+ screen.queue_flush_display_rect(rect.translated(-screen_rect.location()));
+ for (auto& rect : screen_data.m_flush_transparent_rects.rects())
+ screen.queue_flush_display_rect(rect.translated(-screen_rect.location()));
+ for (auto& rect : screen_data.m_flush_special_rects.rects())
+ screen.queue_flush_display_rect(rect.translated(-screen_rect.location()));
+
+ screen.flush_display((!screen_data.m_screen_can_set_buffer || screen_data.m_buffers_are_flipped) ? 0 : 1);
+ }
+
+ if (screen_data.m_screen_can_set_buffer) {
screen_data.flip_buffers(screen);
+ screen_data.m_has_flipped = true;
+ }
- auto screen_rect = screen.rect();
- bool device_can_flush_buffers = screen.can_device_flush_buffers();
auto do_flush = [&](Gfx::IntRect rect) {
VERIFY(screen_rect.contains(rect));
rect.translate_by(-screen_rect.location());
@@ -625,8 +658,12 @@ void Compositor::flush(Screen& screen)
from_ptr = (const Gfx::RGBA32*)((const u8*)from_ptr + pitch);
to_ptr = (Gfx::RGBA32*)((u8*)to_ptr + pitch);
}
- if (device_can_flush_buffers)
+ if (device_can_flush_buffers) {
+ // Whether or not we need to flush buffers, we need to at least track what we modified
+ // so that we can flush these areas next time before we flip buffers. Or, if we don't
+ // support buffer flipping then we will flush them shortly.
screen.queue_flush_display_rect(rect);
+ }
};
for (auto& rect : screen_data.m_flush_rects.rects())
do_flush(rect);
@@ -634,8 +671,13 @@ void Compositor::flush(Screen& screen)
do_flush(rect);
for (auto& rect : screen_data.m_flush_special_rects.rects())
do_flush(rect);
- if (device_can_flush_buffers)
- screen.flush_display();
+ if (device_can_flush_buffers && !screen_data.m_screen_can_set_buffer) {
+ // If we also support flipping buffers we don't really need to flush these areas right now.
+ // Instead, we skip this step and just keep track of them until shortly before the next flip.
+ // If we however don't support flipping buffers then we need to flush the changed areas right
+ // now so that they can be sent to the device.
+ screen.flush_display(screen_data.m_buffers_are_flipped ? 0 : 1);
+ }
}
void Compositor::invalidate_screen()
@@ -848,7 +890,10 @@ void Compositor::ScreenData::draw_cursor(Screen& screen, const Gfx::IntRect& cur
auto& current_cursor = compositor.m_current_cursor ? *compositor.m_current_cursor : wm.active_cursor();
auto screen_rect = screen.rect();
m_cursor_back_painter->blit({ 0, 0 }, *m_back_bitmap, current_cursor.rect().translated(cursor_rect.location()).intersected(screen_rect).translated(-screen_rect.location()));
- m_back_painter->blit(cursor_rect.location(), current_cursor.bitmap(screen.scale_factor()), current_cursor.source_rect(compositor.m_current_cursor_frame));
+ auto cursor_src_rect = current_cursor.source_rect(compositor.m_current_cursor_frame);
+ m_back_painter->blit(cursor_rect.location(), current_cursor.bitmap(screen.scale_factor()), cursor_src_rect);
+ m_flush_special_rects.add(Gfx::IntRect(cursor_rect.location(), cursor_src_rect.size()).intersected(screen.rect()));
+ m_have_flush_rects = true;
m_last_cursor_rect = cursor_rect;
VERIFY(compositor.m_current_cursor_screen == &screen);
m_cursor_back_is_valid = true;
@@ -861,6 +906,8 @@ bool Compositor::ScreenData::restore_cursor_back(Screen& screen, Gfx::IntRect& l
last_cursor_rect = m_last_cursor_rect.intersected(screen.rect());
m_back_painter->blit(last_cursor_rect.location(), *m_cursor_back_bitmap, { { 0, 0 }, last_cursor_rect.size() });
+ m_flush_special_rects.add(last_cursor_rect.intersected(screen.rect()));
+ m_have_flush_rects = true;
m_cursor_back_is_valid = false;
return true;
}
diff --git a/Userland/Services/WindowServer/Compositor.h b/Userland/Services/WindowServer/Compositor.h
index 52a871d004..d1a33da67f 100644
--- a/Userland/Services/WindowServer/Compositor.h
+++ b/Userland/Services/WindowServer/Compositor.h
@@ -171,7 +171,9 @@ private:
OwnPtr<WindowStackSwitchOverlay> m_window_stack_switch_overlay;
bool m_buffers_are_flipped { false };
bool m_screen_can_set_buffer { false };
+ bool m_has_flipped { false };
bool m_cursor_back_is_valid { false };
+ bool m_have_flush_rects { false };
Gfx::DisjointRectSet m_flush_rects;
Gfx::DisjointRectSet m_flush_transparent_rects;
diff --git a/Userland/Services/WindowServer/Screen.cpp b/Userland/Services/WindowServer/Screen.cpp
index ca4f6f7f45..0214717e1a 100644
--- a/Userland/Services/WindowServer/Screen.cpp
+++ b/Userland/Services/WindowServer/Screen.cpp
@@ -364,7 +364,7 @@ void Screen::queue_flush_display_rect(Gfx::IntRect const& flush_region)
}
}
-void Screen::flush_display()
+void Screen::flush_display(int buffer_index)
{
VERIFY(m_can_device_flush_buffers);
auto& fb_data = *m_framebuffer_data;
@@ -380,7 +380,7 @@ void Screen::flush_display()
flush_rect.height *= scale_factor;
}
- if (fb_flush_buffers(m_framebuffer_fd, fb_data.pending_flush_rects.data(), (unsigned)fb_data.pending_flush_rects.size()) < 0) {
+ if (fb_flush_buffers(m_framebuffer_fd, buffer_index, fb_data.pending_flush_rects.data(), (unsigned)fb_data.pending_flush_rects.size()) < 0) {
int err = errno;
if (err == ENOTSUP)
m_can_device_flush_buffers = false;
diff --git a/Userland/Services/WindowServer/Screen.h b/Userland/Services/WindowServer/Screen.h
index 520b1fa5fe..4233cc78f1 100644
--- a/Userland/Services/WindowServer/Screen.h
+++ b/Userland/Services/WindowServer/Screen.h
@@ -165,7 +165,7 @@ public:
bool can_device_flush_buffers() const { return m_can_device_flush_buffers; }
void queue_flush_display_rect(Gfx::IntRect const& rect);
- void flush_display();
+ void flush_display(int buffer_index);
private:
Screen(ScreenLayout::Screen&);