1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 13:47:45 +00:00

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.
This commit is contained in:
Liav A 2022-04-30 13:55:00 +03:00 committed by Andreas Kling
parent 41283a2de6
commit 4ff6150f1b
8 changed files with 45 additions and 5 deletions

View file

@ -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

View file

@ -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());

View file

@ -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 {};
}
}

View file

@ -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;

View file

@ -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;
}
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);

View file

@ -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; }

View file

@ -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 };

View file

@ -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;