Explorar el Código

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.
Liav A hace 3 años
padre
commit
4ff6150f1b

+ 5 - 0
Kernel/API/FB.h

@@ -98,4 +98,9 @@ ALWAYS_INLINE int fb_flush_buffers(int fd, int index, FBRect const* rects, unsig
     return ioctl(fd, FB_IOCTL_FLUSH_HEAD_BUFFERS, &fb_flush_rects);
 }
 
+ALWAYS_INLINE int fb_flush_head(int fd)
+{
+    return ioctl(fd, FB_IOCTL_FLUSH_HEAD, nullptr);
+}
+
 __END_DECLS

+ 3 - 1
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());

+ 10 - 0
Userland/Services/WindowServer/HardwareScreenBackend.cpp

@@ -32,6 +32,7 @@ ErrorOr<void> 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<void> HardwareScreenBackend::flush_framebuffer_rects(int buffer_index, S
     return {};
 }
 
+ErrorOr<void> 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 {};
+}
 }

+ 2 - 0
Userland/Services/WindowServer/HardwareScreenBackend.h

@@ -26,6 +26,8 @@ public:
 
     virtual ErrorOr<void> flush_framebuffer_rects(int buffer_index, Span<FBRect const> rects) override;
 
+    virtual ErrorOr<void> flush_framebuffer() override;
+
     virtual ErrorOr<void> unmap_framebuffer() override;
     virtual ErrorOr<void> map_framebuffer() override;
 

+ 18 - 4
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);

+ 2 - 0
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; }
 

+ 3 - 0
Userland/Services/WindowServer/ScreenBackend.h

@@ -31,12 +31,15 @@ public:
     virtual ErrorOr<void> unmap_framebuffer() = 0;
     virtual ErrorOr<void> map_framebuffer() = 0;
 
+    virtual ErrorOr<void> flush_framebuffer() = 0;
+
     virtual ErrorOr<void> set_head_resolution(FBHeadResolution) = 0;
     virtual ErrorOr<FBHeadProperties> get_head_properties() = 0;
 
     virtual ErrorOr<void> 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 };

+ 2 - 0
Userland/Services/WindowServer/VirtualScreenBackend.h

@@ -30,6 +30,8 @@ private:
 
     virtual ErrorOr<void> flush_framebuffer_rects(int, Span<FBRect const>) override { return {}; }
 
+    virtual ErrorOr<void> flush_framebuffer() override { return {}; }
+
     virtual ErrorOr<void> unmap_framebuffer() override;
     virtual ErrorOr<void> map_framebuffer() override;