WindowServer: Make Screen use ScreenBackend
This will allow us to use other screen backends in the future instead.
This commit is contained in:
parent
0acffa5ef4
commit
e95ae4a143
Notes:
sideshowbarker
2024-07-17 11:37:44 +09:00
Author: https://github.com/kleinesfilmroellchen Commit: https://github.com/SerenityOS/serenity/commit/e95ae4a143 Pull-request: https://github.com/SerenityOS/serenity/pull/13380 Reviewed-by: https://github.com/ADKaster ✅ Reviewed-by: https://github.com/linusg
2 changed files with 45 additions and 101 deletions
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue