1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 15:27:35 +00:00

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
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) 2018-2020, Andreas Kling <kling@serenityos.org>
* Copyright (c) 2022, kleines Filmröllchen <filmroellchen@serenityos.org>
* *
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
*/ */
@ -8,8 +9,10 @@
#include "Compositor.h" #include "Compositor.h"
#include "Event.h" #include "Event.h"
#include "EventLoop.h" #include "EventLoop.h"
#include "ScreenBackend.h"
#include "WindowManager.h" #include "WindowManager.h"
#include <AK/Debug.h> #include <AK/Debug.h>
#include <AK/Format.h>
#include <Kernel/API/FB.h> #include <Kernel/API/FB.h>
#include <Kernel/API/MousePacket.h> #include <Kernel/API/MousePacket.h>
#include <fcntl.h> #include <fcntl.h>
@ -224,38 +227,22 @@ bool Screen::open_device()
{ {
close_device(); close_device();
auto& info = screen_layout_info(); auto& info = screen_layout_info();
m_framebuffer_fd = open(info.device.characters(), O_RDWR | O_CLOEXEC);
if (m_framebuffer_fd < 0) { // TODO: Support other backends
perror(String::formatted("failed to open {}", info.device).characters()); 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; 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); set_resolution(true);
return true; return true;
} }
void Screen::close_device() void Screen::close_device()
{ {
if (m_framebuffer_fd >= 0) { m_backend = nullptr;
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;
}
} }
void Screen::update_virtual_rect() void Screen::update_virtual_rect()
@ -320,48 +307,22 @@ bool Screen::set_resolution(bool initial)
auto& info = screen_layout_info(); auto& info = screen_layout_info();
int rc = -1; ErrorOr<void> return_value = Error::from_errno(EINVAL);
{ {
// FIXME: Add multihead support for one framebuffer // FIXME: Add multihead support for one framebuffer
FBHeadResolution physical_resolution { 0, 0, info.resolution.width(), info.resolution.height() }; 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 (initial) {
if (m_framebuffer) { TRY(m_backend->unmap_framebuffer());
size_t previous_size_in_bytes = m_size_in_bytes; TRY(m_backend->map_framebuffer());
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;
}
} }
FBHeadProperties properties; auto properties = TRY(m_backend->get_head_properties());
properties.head_index = 0;
int rc = fb_get_head_properties(m_framebuffer_fd, &properties);
VERIFY(rc == 0);
info.resolution = { properties.width, properties.height }; info.resolution = { properties.width, properties.height };
m_pitch = properties.pitch;
update_virtual_rect(); update_virtual_rect();
@ -373,16 +334,17 @@ bool Screen::set_resolution(bool initial)
auto& screen_input = ScreenInput::the(); auto& screen_input = ScreenInput::the();
screen_input.set_cursor_location(screen_input.cursor_location().constrained(rect())); screen_input.set_cursor_location(screen_input.cursor_location().constrained(rect()));
} }
return {};
}; };
if (rc == 0) { if (!return_value.is_error()) {
on_change_resolution(); return_value = on_change_resolution();
return true; if (!return_value.is_error())
return true;
} }
if (rc == -1) { if (return_value.is_error()) {
int err = errno; dbgln("Screen #{}: Failed to set resolution {}: {}", index(), info.resolution, return_value.error());
dbgln("Screen #{}: Failed to set resolution {}: {}", index(), info.resolution, strerror(err)); MUST(on_change_resolution());
on_change_resolution();
return false; return false;
} }
VERIFY_NOT_REACHED(); VERIFY_NOT_REACHED();
@ -390,14 +352,7 @@ bool Screen::set_resolution(bool initial)
void Screen::set_buffer(int index) void Screen::set_buffer(int index)
{ {
VERIFY(m_can_set_buffer); m_backend->set_head_buffer(index);
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);
} }
size_t Screen::buffer_offset(int index) const size_t Screen::buffer_offset(int index) const
@ -405,7 +360,7 @@ size_t Screen::buffer_offset(int index) const
if (index == 0) if (index == 0)
return 0; return 0;
if (index == 1) if (index == 1)
return m_back_buffer_offset; return m_backend->m_back_buffer_offset;
VERIFY_NOT_REACHED(); 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) 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; auto& flush_rects = *m_flush_rects;
if (flush_rects.pending_flush_rects.is_empty()) if (flush_rects.pending_flush_rects.is_empty())
return; return;
@ -561,13 +516,9 @@ void Screen::flush_display(int buffer_index)
flush_rect.height *= scale_factor; 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) { auto return_value = m_backend->flush_framebuffer_rects(buffer_index, flush_rects.pending_flush_rects.span());
int err = errno; if (return_value.is_error())
if (err == ENOTSUP) dbgln("Screen #{}: Error flushing display: {}", index(), return_value.error());
m_can_device_flush_buffers = false;
else
dbgln("Screen #{}: Error ({}) flushing display: {}", index(), err, strerror(err));
}
flush_rects.too_many_pending_flush_rects = false; flush_rects.too_many_pending_flush_rects = false;
flush_rects.pending_flush_rects.clear_with_capacity(); 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) 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(); auto scale_factor = this->scale_factor();
FBRect flush_rect { FBRect flush_rect {
.head_index = 0, .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)); 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; auto return_value = m_backend->flush_framebuffer_rects(front_buffer_index, { &flush_rect, 1 });
if (err == ENOTSUP) if (return_value.is_error())
m_can_device_flush_buffers = false; dbgln("Screen #{}: Error flushing display front buffer: {}", index(), return_value.error());
else
dbgln("Screen #{}: Error ({}) flushing display front buffer: {}", index(), err, strerror(err));
}
} }
} }

View file

@ -1,11 +1,14 @@
/* /*
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
* Copyright (c) 2022, kleines Filmröllchen <filmroellchen@serenityos.org>
* *
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
*/ */
#pragma once #pragma once
#include "HardwareScreenBackend.h"
#include "ScreenBackend.h"
#include "ScreenLayout.h" #include "ScreenLayout.h"
#include <AK/NonnullRefPtrVector.h> #include <AK/NonnullRefPtrVector.h>
#include <AK/OwnPtr.h> #include <AK/OwnPtr.h>
@ -145,13 +148,13 @@ public:
void make_main_screen() { s_main_screen = this; } void make_main_screen() { s_main_screen = this; }
bool is_main_screen() const { return 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); void set_buffer(int index);
size_t buffer_offset(int index) const; size_t buffer_offset(int index) const;
int physical_width() const { return width() * scale_factor(); } int physical_width() const { return width() * scale_factor(); }
int physical_height() const { return height() * 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 width() const { return m_virtual_rect.width(); }
int height() const { return m_virtual_rect.height(); } 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::IntSize size() const { return { m_virtual_rect.width(), m_virtual_rect.height() }; }
Gfx::IntRect rect() const { return m_virtual_rect; } 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 queue_flush_display_rect(Gfx::IntRect const& rect);
void flush_display(int buffer_index); void flush_display(int buffer_index);
void flush_display_front_buffer(int front_buffer_index, Gfx::IntRect&); void flush_display_front_buffer(int front_buffer_index, Gfx::IntRect&);
@ -187,7 +190,7 @@ private:
static void update_bounding_rect(); static void update_bounding_rect();
static void update_scale_factors_in_use(); 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 set_index(size_t index) { m_index = index; }
void update_virtual_rect(); void update_virtual_rect();
@ -201,23 +204,16 @@ private:
static Vector<int, default_scale_factors_in_use_count> s_scale_factors_in_use; static Vector<int, default_scale_factors_in_use_count> s_scale_factors_in_use;
size_t m_index { 0 }; size_t m_index { 0 };
size_t m_size_in_bytes { 0 }; OwnPtr<ScreenBackend> m_backend;
size_t m_back_buffer_offset { 0 };
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; Gfx::IntRect m_virtual_rect;
int m_framebuffer_fd { -1 };
NonnullOwnPtr<FlushRectData> m_flush_rects; NonnullOwnPtr<FlushRectData> m_flush_rects;
NonnullOwnPtr<CompositorScreenData> m_compositor_screen_data; NonnullOwnPtr<CompositorScreenData> m_compositor_screen_data;
}; };
inline Gfx::ARGB32* Screen::scanline(int buffer_index, int y) 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));
} }
} }