From e95ae4a1431039fbb34a09b274f3ebf096609a2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?kleines=20Filmr=C3=B6llchen?= Date: Thu, 31 Mar 2022 18:03:39 +0200 Subject: [PATCH] WindowServer: Make Screen use ScreenBackend This will allow us to use other screen backends in the future instead. --- Userland/Services/WindowServer/Screen.cpp | 124 +++++++--------------- Userland/Services/WindowServer/Screen.h | 22 ++-- 2 files changed, 45 insertions(+), 101 deletions(-) diff --git a/Userland/Services/WindowServer/Screen.cpp b/Userland/Services/WindowServer/Screen.cpp index 2ff498ff10..52200b9afc 100644 --- a/Userland/Services/WindowServer/Screen.cpp +++ b/Userland/Services/WindowServer/Screen.cpp @@ -1,5 +1,6 @@ /* * Copyright (c) 2018-2020, Andreas Kling + * Copyright (c) 2022, kleines Filmröllchen * * SPDX-License-Identifier: BSD-2-Clause */ @@ -8,8 +9,10 @@ #include "Compositor.h" #include "Event.h" #include "EventLoop.h" +#include "ScreenBackend.h" #include "WindowManager.h" #include +#include #include #include #include @@ -224,38 +227,22 @@ bool Screen::open_device() { close_device(); auto& info = screen_layout_info(); - m_framebuffer_fd = open(info.device.characters(), O_RDWR | O_CLOEXEC); - if (m_framebuffer_fd < 0) { - perror(String::formatted("failed to open {}", info.device).characters()); + + // TODO: Support other backends + m_backend = make(info.device); + auto return_value = m_backend->open(); + if (return_value.is_error()) { + dbgln("Screen #{}: Failed to open backend: {}", index(), return_value.error()); return false; } - FBProperties properties; - if (fb_get_properties(m_framebuffer_fd, &properties) < 0) { - perror(String::formatted("failed to ioctl {}", info.device).characters()); - return false; - } - - m_can_device_flush_buffers = properties.partial_flushing_support; - m_can_set_buffer = properties.doublebuffer_support; - set_resolution(true); return true; } void Screen::close_device() { - if (m_framebuffer_fd >= 0) { - close(m_framebuffer_fd); - m_framebuffer_fd = -1; - } - if (m_framebuffer) { - int rc = munmap(m_framebuffer, m_size_in_bytes); - VERIFY(rc == 0); - - m_framebuffer = nullptr; - m_size_in_bytes = 0; - } + m_backend = nullptr; } void Screen::update_virtual_rect() @@ -320,48 +307,22 @@ bool Screen::set_resolution(bool initial) auto& info = screen_layout_info(); - int rc = -1; + ErrorOr return_value = Error::from_errno(EINVAL); { // FIXME: Add multihead support for one framebuffer FBHeadResolution physical_resolution { 0, 0, info.resolution.width(), info.resolution.height() }; - rc = fb_set_resolution(m_framebuffer_fd, &physical_resolution); + return_value = m_backend->set_head_resolution(physical_resolution); } - dbgln_if(WSSCREEN_DEBUG, "Screen #{}: fb_set_resolution() - return code {}", index(), rc); + dbgln_if(WSSCREEN_DEBUG, "Screen #{}: fb_set_resolution() - success", index()); - auto on_change_resolution = [&]() { + auto on_change_resolution = [&]() -> ErrorOr { if (initial) { - if (m_framebuffer) { - size_t previous_size_in_bytes = m_size_in_bytes; - int rc = munmap(m_framebuffer, previous_size_in_bytes); - VERIFY(rc == 0); - } - FBHeadProperties properties; - properties.head_index = 0; - int rc = fb_get_head_properties(m_framebuffer_fd, &properties); - VERIFY(rc == 0); - m_size_in_bytes = properties.buffer_length; - - m_framebuffer = (Gfx::ARGB32*)mmap(nullptr, m_size_in_bytes, PROT_READ | PROT_WRITE, MAP_SHARED, m_framebuffer_fd, 0); - VERIFY(m_framebuffer && m_framebuffer != (void*)-1); - - if (m_can_set_buffer) { - // Note: fall back to assuming the second buffer starts right after the last line of the first - // Note: for now, this calculation works quite well, so need to defer it to another function - // that does ioctl to figure out the correct offset. If a Framebuffer device ever happens to - // to set the second buffer at different location than this, we might need to consider bringing - // back a function with ioctl to check this. - m_back_buffer_offset = properties.pitch * properties.height; - } else { - m_back_buffer_offset = 0; - } + TRY(m_backend->unmap_framebuffer()); + TRY(m_backend->map_framebuffer()); } - FBHeadProperties properties; - properties.head_index = 0; - int rc = fb_get_head_properties(m_framebuffer_fd, &properties); - VERIFY(rc == 0); + auto properties = TRY(m_backend->get_head_properties()); info.resolution = { properties.width, properties.height }; - m_pitch = properties.pitch; update_virtual_rect(); @@ -373,16 +334,17 @@ bool Screen::set_resolution(bool initial) auto& screen_input = ScreenInput::the(); screen_input.set_cursor_location(screen_input.cursor_location().constrained(rect())); } + return {}; }; - if (rc == 0) { - on_change_resolution(); - return true; + if (!return_value.is_error()) { + return_value = on_change_resolution(); + if (!return_value.is_error()) + return true; } - if (rc == -1) { - int err = errno; - dbgln("Screen #{}: Failed to set resolution {}: {}", index(), info.resolution, strerror(err)); - on_change_resolution(); + if (return_value.is_error()) { + dbgln("Screen #{}: Failed to set resolution {}: {}", index(), info.resolution, return_value.error()); + MUST(on_change_resolution()); return false; } VERIFY_NOT_REACHED(); @@ -390,14 +352,7 @@ bool Screen::set_resolution(bool initial) void Screen::set_buffer(int index) { - VERIFY(m_can_set_buffer); - VERIFY(index <= 1 && index >= 0); - FBHeadVerticalOffset offset; - memset(&offset, 0, sizeof(FBHeadVerticalOffset)); - if (index == 1) - offset.offsetted = 1; - int rc = fb_set_head_vertical_offset_buffer(m_framebuffer_fd, &offset); - VERIFY(rc == 0); + m_backend->set_head_buffer(index); } size_t Screen::buffer_offset(int index) const @@ -405,7 +360,7 @@ size_t Screen::buffer_offset(int index) const if (index == 0) return 0; if (index == 1) - return m_back_buffer_offset; + return m_backend->m_back_buffer_offset; VERIFY_NOT_REACHED(); } @@ -546,7 +501,7 @@ void Screen::queue_flush_display_rect(Gfx::IntRect const& flush_region) void Screen::flush_display(int buffer_index) { - VERIFY(m_can_device_flush_buffers); + VERIFY(m_backend->m_can_device_flush_buffers); auto& flush_rects = *m_flush_rects; if (flush_rects.pending_flush_rects.is_empty()) return; @@ -561,13 +516,9 @@ void Screen::flush_display(int buffer_index) flush_rect.height *= scale_factor; } - if (fb_flush_buffers(m_framebuffer_fd, buffer_index, flush_rects.pending_flush_rects.data(), (unsigned)flush_rects.pending_flush_rects.size()) < 0) { - int err = errno; - if (err == ENOTSUP) - m_can_device_flush_buffers = false; - else - dbgln("Screen #{}: Error ({}) flushing display: {}", index(), err, strerror(err)); - } + 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(); @@ -575,7 +526,7 @@ void Screen::flush_display(int buffer_index) void Screen::flush_display_front_buffer(int front_buffer_index, Gfx::IntRect& rect) { - VERIFY(m_can_device_flush_buffers); + VERIFY(m_backend->m_can_device_flush_buffers); auto scale_factor = this->scale_factor(); FBRect flush_rect { .head_index = 0, @@ -586,13 +537,10 @@ void Screen::flush_display_front_buffer(int front_buffer_index, Gfx::IntRect& re }; VERIFY(Gfx::IntRect({}, m_virtual_rect.size()).contains(rect)); - 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)); - } + + auto return_value = m_backend->flush_framebuffer_rects(front_buffer_index, { &flush_rect, 1 }); + if (return_value.is_error()) + dbgln("Screen #{}: Error flushing display front buffer: {}", index(), return_value.error()); } } diff --git a/Userland/Services/WindowServer/Screen.h b/Userland/Services/WindowServer/Screen.h index 6938aa8fbe..44f1510d8c 100644 --- a/Userland/Services/WindowServer/Screen.h +++ b/Userland/Services/WindowServer/Screen.h @@ -1,11 +1,14 @@ /* * Copyright (c) 2018-2020, Andreas Kling + * Copyright (c) 2022, kleines Filmröllchen * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once +#include "HardwareScreenBackend.h" +#include "ScreenBackend.h" #include "ScreenLayout.h" #include #include @@ -145,13 +148,13 @@ public: void make_main_screen() { s_main_screen = this; } bool is_main_screen() const { return s_main_screen == this; } - bool can_set_buffer() { return m_can_set_buffer; } + bool can_set_buffer() { return m_backend->m_can_set_head_buffer; } void set_buffer(int index); size_t buffer_offset(int index) const; int physical_width() const { return width() * scale_factor(); } int physical_height() const { return height() * scale_factor(); } - size_t pitch() const { return m_pitch; } + size_t pitch() const { return m_backend->m_pitch; } int width() const { return m_virtual_rect.width(); } int height() const { return m_virtual_rect.height(); } @@ -164,7 +167,7 @@ public: Gfx::IntSize size() const { return { m_virtual_rect.width(), m_virtual_rect.height() }; } Gfx::IntRect rect() const { return m_virtual_rect; } - bool can_device_flush_buffers() const { return m_can_device_flush_buffers; } + bool can_device_flush_buffers() const { return m_backend->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&); @@ -187,7 +190,7 @@ private: static void update_bounding_rect(); static void update_scale_factors_in_use(); - bool is_opened() const { return m_framebuffer_fd >= 0; } + bool is_opened() const { return m_backend != nullptr; } void set_index(size_t index) { m_index = index; } void update_virtual_rect(); @@ -201,23 +204,16 @@ private: static Vector s_scale_factors_in_use; size_t m_index { 0 }; - size_t m_size_in_bytes { 0 }; - size_t m_back_buffer_offset { 0 }; + OwnPtr m_backend; - Gfx::ARGB32* m_framebuffer { nullptr }; - bool m_can_set_buffer { false }; - bool m_can_device_flush_buffers { true }; // If the device can't do it we revert to false - - int m_pitch { 0 }; Gfx::IntRect m_virtual_rect; - int m_framebuffer_fd { -1 }; NonnullOwnPtr m_flush_rects; NonnullOwnPtr m_compositor_screen_data; }; inline Gfx::ARGB32* Screen::scanline(int buffer_index, int y) { - return reinterpret_cast(((u8*)m_framebuffer) + buffer_offset(buffer_index) + (y * m_pitch)); + return reinterpret_cast(((u8*)m_backend->m_framebuffer) + buffer_offset(buffer_index) + (y * m_backend->m_pitch)); } }