From 4ff6150f1b760b0674f32b44bbc58e5c2971ffa4 Mon Sep 17 00:00:00 2001 From: Liav A Date: Sat, 30 Apr 2022 13:55:00 +0300 Subject: WindowServer: Use FB_IOCTL_FLUSH_HEAD to flush a framebuffer if possible This ioctl is more appropriate when the hardware supports flushing of the entire framebuffer, so we use that instead of the previous default FB_IOCTL_FLUSH_HEAD_BUFFERS ioctl. --- Userland/Services/WindowServer/Compositor.cpp | 4 +++- .../WindowServer/HardwareScreenBackend.cpp | 10 ++++++++++ .../Services/WindowServer/HardwareScreenBackend.h | 2 ++ Userland/Services/WindowServer/Screen.cpp | 22 ++++++++++++++++++---- Userland/Services/WindowServer/Screen.h | 2 ++ Userland/Services/WindowServer/ScreenBackend.h | 3 +++ .../Services/WindowServer/VirtualScreenBackend.h | 2 ++ 7 files changed, 40 insertions(+), 5 deletions(-) (limited to 'Userland') diff --git a/Userland/Services/WindowServer/Compositor.cpp b/Userland/Services/WindowServer/Compositor.cpp index 6941a5c6ca..7a5243b45b 100644 --- a/Userland/Services/WindowServer/Compositor.cpp +++ b/Userland/Services/WindowServer/Compositor.cpp @@ -629,7 +629,9 @@ void Compositor::flush(Screen& screen) bounding_flash = bounding_flash.united(rect); } if (!bounding_flash.is_empty()) { - if (device_can_flush_buffers) { + if (screen.can_device_flush_entire_buffer()) { + screen.flush_display_entire_framebuffer(); + } else 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()); diff --git a/Userland/Services/WindowServer/HardwareScreenBackend.cpp b/Userland/Services/WindowServer/HardwareScreenBackend.cpp index f0bf2912b5..4784658ccb 100644 --- a/Userland/Services/WindowServer/HardwareScreenBackend.cpp +++ b/Userland/Services/WindowServer/HardwareScreenBackend.cpp @@ -32,6 +32,7 @@ ErrorOr HardwareScreenBackend::open() return Error::from_syscall(String::formatted("failed to ioctl {}", m_device), errno); m_can_device_flush_buffers = (properties.partial_flushing_support != 0); + m_can_device_flush_entire_framebuffer = (properties.flushing_support != 0); m_can_set_head_buffer = (properties.doublebuffer_support != 0); return {}; } @@ -209,4 +210,13 @@ ErrorOr HardwareScreenBackend::flush_framebuffer_rects(int buffer_index, S return {}; } +ErrorOr HardwareScreenBackend::flush_framebuffer() +{ + int rc = fb_flush_head(m_framebuffer_fd); + if (rc == -ENOTSUP) + m_can_device_flush_entire_framebuffer = false; + else + return Error::from_syscall("fb_flush_head", rc); + return {}; +} } diff --git a/Userland/Services/WindowServer/HardwareScreenBackend.h b/Userland/Services/WindowServer/HardwareScreenBackend.h index e1ce874ea2..16e3deeaa9 100644 --- a/Userland/Services/WindowServer/HardwareScreenBackend.h +++ b/Userland/Services/WindowServer/HardwareScreenBackend.h @@ -26,6 +26,8 @@ public: virtual ErrorOr flush_framebuffer_rects(int buffer_index, Span rects) override; + virtual ErrorOr flush_framebuffer() override; + virtual ErrorOr unmap_framebuffer() override; virtual ErrorOr map_framebuffer() override; diff --git a/Userland/Services/WindowServer/Screen.cpp b/Userland/Services/WindowServer/Screen.cpp index ef6b24165a..de3a1e75e3 100644 --- a/Userland/Services/WindowServer/Screen.cpp +++ b/Userland/Services/WindowServer/Screen.cpp @@ -527,7 +527,7 @@ void Screen::queue_flush_display_rect(Gfx::IntRect const& flush_region) void Screen::flush_display(int buffer_index) { - VERIFY(m_backend->m_can_device_flush_buffers); + VERIFY(m_backend->m_can_device_flush_buffers || m_backend->m_can_device_flush_entire_framebuffer); auto& flush_rects = *m_flush_rects; if (flush_rects.pending_flush_rects.is_empty()) return; @@ -542,9 +542,15 @@ void Screen::flush_display(int buffer_index) flush_rect.height *= scale_factor; } - auto return_value = m_backend->flush_framebuffer_rects(buffer_index, flush_rects.pending_flush_rects.span()); - if (return_value.is_error()) - dbgln("Screen #{}: Error flushing display: {}", index(), return_value.error()); + if (m_backend->m_can_device_flush_entire_framebuffer) { + auto return_value = m_backend->flush_framebuffer(); + if (return_value.is_error()) + dbgln("Screen #{}: Error flushing display: {}", index(), return_value.error()); + } else { + auto return_value = m_backend->flush_framebuffer_rects(buffer_index, flush_rects.pending_flush_rects.span()); + if (return_value.is_error()) + dbgln("Screen #{}: Error flushing display: {}", index(), return_value.error()); + } flush_rects.too_many_pending_flush_rects = false; flush_rects.pending_flush_rects.clear_with_capacity(); @@ -555,6 +561,14 @@ void Screen::write_all_display_contents() MUST(m_backend->write_all_contents(m_virtual_rect)); } +void Screen::flush_display_entire_framebuffer() +{ + VERIFY(m_backend->m_can_device_flush_entire_framebuffer); + auto return_value = m_backend->flush_framebuffer(); + if (return_value.is_error()) + dbgln("Screen #{}: Error flushing display front buffer: {}", index(), return_value.error()); +} + void Screen::flush_display_front_buffer(int front_buffer_index, Gfx::IntRect& rect) { VERIFY(m_backend->m_can_device_flush_buffers); diff --git a/Userland/Services/WindowServer/Screen.h b/Userland/Services/WindowServer/Screen.h index 8737a92eae..c54b1a274a 100644 --- a/Userland/Services/WindowServer/Screen.h +++ b/Userland/Services/WindowServer/Screen.h @@ -168,9 +168,11 @@ public: Gfx::IntRect rect() const { return m_virtual_rect; } bool can_device_flush_buffers() const { return m_backend->m_can_device_flush_buffers; } + bool can_device_flush_entire_buffer() const { return m_backend->m_can_device_flush_entire_framebuffer; } 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&); + void flush_display_entire_framebuffer(); CompositorScreenData& compositor_screen_data() { return *m_compositor_screen_data; } diff --git a/Userland/Services/WindowServer/ScreenBackend.h b/Userland/Services/WindowServer/ScreenBackend.h index 4e96bd7f2f..efc158e484 100644 --- a/Userland/Services/WindowServer/ScreenBackend.h +++ b/Userland/Services/WindowServer/ScreenBackend.h @@ -31,12 +31,15 @@ public: virtual ErrorOr unmap_framebuffer() = 0; virtual ErrorOr map_framebuffer() = 0; + virtual ErrorOr flush_framebuffer() = 0; + virtual ErrorOr set_head_resolution(FBHeadResolution) = 0; virtual ErrorOr get_head_properties() = 0; virtual ErrorOr write_all_contents(Gfx::IntRect const&) { return {}; } bool m_can_device_flush_buffers { true }; + bool m_can_device_flush_entire_framebuffer { true }; bool m_can_set_head_buffer { false }; Gfx::ARGB32* m_framebuffer { nullptr }; diff --git a/Userland/Services/WindowServer/VirtualScreenBackend.h b/Userland/Services/WindowServer/VirtualScreenBackend.h index 8d59b9cf5a..647acdd327 100644 --- a/Userland/Services/WindowServer/VirtualScreenBackend.h +++ b/Userland/Services/WindowServer/VirtualScreenBackend.h @@ -30,6 +30,8 @@ private: virtual ErrorOr flush_framebuffer_rects(int, Span) override { return {}; } + virtual ErrorOr flush_framebuffer() override { return {}; } + virtual ErrorOr unmap_framebuffer() override; virtual ErrorOr map_framebuffer() override; -- cgit v1.2.3