WindowServer: Make Screen use ScreenBackend

This will allow us to use other screen backends in the future instead.
This commit is contained in:
kleines Filmröllchen 2022-03-31 18:03:39 +02:00 committed by Linus Groh
parent 0acffa5ef4
commit e95ae4a143
Notes: sideshowbarker 2024-07-17 11:37:44 +09:00
2 changed files with 45 additions and 101 deletions

View file

@ -1,5 +1,6 @@
/*
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
* Copyright (c) 2022, kleines Filmröllchen <filmroellchen@serenityos.org>
*
* 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 <AK/Debug.h>
#include <AK/Format.h>
#include <Kernel/API/FB.h>
#include <Kernel/API/MousePacket.h>
#include <fcntl.h>
@ -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<HardwareScreenBackend>(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<void> 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<void> {
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());
}
}

View file

@ -1,11 +1,14 @@
/*
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
* Copyright (c) 2022, kleines Filmröllchen <filmroellchen@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include "HardwareScreenBackend.h"
#include "ScreenBackend.h"
#include "ScreenLayout.h"
#include <AK/NonnullRefPtrVector.h>
#include <AK/OwnPtr.h>
@ -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<int, default_scale_factors_in_use_count> 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<ScreenBackend> 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<FlushRectData> m_flush_rects;
NonnullOwnPtr<CompositorScreenData> m_compositor_screen_data;
};
inline Gfx::ARGB32* Screen::scanline(int buffer_index, int y)
{
return reinterpret_cast<Gfx::ARGB32*>(((u8*)m_framebuffer) + buffer_offset(buffer_index) + (y * m_pitch));
return reinterpret_cast<Gfx::ARGB32*>(((u8*)m_backend->m_framebuffer) + buffer_offset(buffer_index) + (y * m_backend->m_pitch));
}
}