From 83b512789c2de764d61c9a1cf97fdbbe22e47e56 Mon Sep 17 00:00:00 2001 From: Tom Date: Sat, 10 Jul 2021 11:28:26 -0600 Subject: [PATCH] WindowServer: Flush display buffer when flashing If the device requires a flush and we modify the front buffer, we need to flush those changes to the front buffer. This makes the flashing work using the VirtIOGPU. Also fix a minor bug where we flushed the front buffer instead of the back buffer after flipping, which caused the VirtIOGPU to not work as expected when using the SDL backend and disabling buffer flipping. --- Userland/Services/WindowServer/Compositor.cpp | 23 +++++++++++++++---- Userland/Services/WindowServer/Screen.cpp | 21 +++++++++++++++++ Userland/Services/WindowServer/Screen.h | 1 + 3 files changed, 40 insertions(+), 5 deletions(-) diff --git a/Userland/Services/WindowServer/Compositor.cpp b/Userland/Services/WindowServer/Compositor.cpp index c1ae95202d..83c7116318 100644 --- a/Userland/Services/WindowServer/Compositor.cpp +++ b/Userland/Services/WindowServer/Compositor.cpp @@ -591,15 +591,28 @@ void Compositor::flush(Screen& screen) } screen_data.m_have_flush_rects = false; + auto screen_rect = screen.rect(); if (m_flash_flush) { - for (auto& rect : screen_data.m_flush_rects.rects()) + Gfx::IntRect bounding_flash; + for (auto& rect : screen_data.m_flush_rects.rects()) { screen_data.m_front_painter->fill_rect(rect, Color::Yellow); - for (auto& rect : screen_data.m_flush_transparent_rects.rects()) + bounding_flash = bounding_flash.united(rect); + } + for (auto& rect : screen_data.m_flush_transparent_rects.rects()) { screen_data.m_front_painter->fill_rect(rect, Color::Green); - usleep(10000); + bounding_flash = bounding_flash.united(rect); + } + if (!bounding_flash.is_empty()) { + if (device_can_flush_buffers) { + // If the device needs a flush we need to let it know that we + // modified the front buffer! + bounding_flash.translate_by(-screen_rect.location()); + screen.flush_display_front_buffer((!screen_data.m_screen_can_set_buffer || !screen_data.m_buffers_are_flipped) ? 0 : 1, bounding_flash); + } + usleep(10000); + } } - 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 @@ -680,7 +693,7 @@ void Compositor::flush(Screen& screen) // 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); + screen.flush_display(screen_data.m_buffers_are_flipped ? 1 : 0); } } diff --git a/Userland/Services/WindowServer/Screen.cpp b/Userland/Services/WindowServer/Screen.cpp index 12703f8889..d108156578 100644 --- a/Userland/Services/WindowServer/Screen.cpp +++ b/Userland/Services/WindowServer/Screen.cpp @@ -413,4 +413,25 @@ void Screen::flush_display(int buffer_index) fb_data.too_many_pending_flush_rects = false; fb_data.pending_flush_rects.clear_with_capacity(); } + +void Screen::flush_display_front_buffer(int front_buffer_index, Gfx::IntRect& rect) +{ + VERIFY(m_can_device_flush_buffers); + auto scale_factor = this->scale_factor(); + FBRect flush_rect { + x : (unsigned)(rect.x() * scale_factor), + y : (unsigned)(rect.y() * scale_factor), + width : (unsigned)(rect.width() * scale_factor), + height : (unsigned)(rect.height() * scale_factor) + }; + + if (fb_flush_buffers(m_framebuffer_fd, front_buffer_index, &flush_rect, 1) < 0) { + int err = errno; + if (err == ENOTSUP) + m_can_device_flush_buffers = false; + else + dbgln("Screen #{}: Error ({}) flushing display front buffer: {}", index(), err, strerror(err)); + } +} + } diff --git a/Userland/Services/WindowServer/Screen.h b/Userland/Services/WindowServer/Screen.h index 159e830584..2182c9c139 100644 --- a/Userland/Services/WindowServer/Screen.h +++ b/Userland/Services/WindowServer/Screen.h @@ -167,6 +167,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(int buffer_index); + void flush_display_front_buffer(int front_buffer_index, Gfx::IntRect&); private: Screen(ScreenLayout::Screen&);