mirror of
https://github.com/RGBCube/serenity
synced 2025-07-26 02:17:34 +00:00
WindowServer: Introduce the ScreenBackend concept
The ScreenBackend is a thin wrapper around the actual screen hardware connection. It contains all the variables specific to that hardware and abstracts away operations that deal with controlling the hardware. The standard ScreenBackend implementor is HardwareScreenBackend, which contains all the existing frame buffer & ioctl handling code of Screen. I took this opportunity to introduce ErrorOr wherever sensible.
This commit is contained in:
parent
1fce201d15
commit
0acffa5ef4
4 changed files with 213 additions and 0 deletions
|
@ -25,6 +25,7 @@ set(SOURCES
|
||||||
MultiScaleBitmaps.cpp
|
MultiScaleBitmaps.cpp
|
||||||
Overlays.cpp
|
Overlays.cpp
|
||||||
Screen.cpp
|
Screen.cpp
|
||||||
|
HardwareScreenBackend.cpp
|
||||||
ScreenLayout.cpp
|
ScreenLayout.cpp
|
||||||
Window.cpp
|
Window.cpp
|
||||||
WindowFrame.cpp
|
WindowFrame.cpp
|
||||||
|
|
126
Userland/Services/WindowServer/HardwareScreenBackend.cpp
Normal file
126
Userland/Services/WindowServer/HardwareScreenBackend.cpp
Normal file
|
@ -0,0 +1,126 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020, the SerenityOS developers.
|
||||||
|
* Copyright (c) 2022, kleines Filmröllchen <filmroellchen@serenityos.org>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "HardwareScreenBackend.h"
|
||||||
|
#include "ScreenBackend.h"
|
||||||
|
#include <AK/Try.h>
|
||||||
|
#include <Kernel/API/FB.h>
|
||||||
|
#include <LibCore/System.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
namespace WindowServer {
|
||||||
|
|
||||||
|
HardwareScreenBackend::HardwareScreenBackend(String device)
|
||||||
|
: m_device(move(device))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorOr<void> HardwareScreenBackend::open()
|
||||||
|
{
|
||||||
|
m_framebuffer_fd = TRY(Core::System::open(m_device.characters(), O_RDWR | O_CLOEXEC));
|
||||||
|
|
||||||
|
FBProperties properties;
|
||||||
|
if (fb_get_properties(m_framebuffer_fd, &properties) < 0)
|
||||||
|
return Error::from_syscall(String::formatted("failed to ioctl {}", m_device), errno);
|
||||||
|
|
||||||
|
m_can_device_flush_buffers = (properties.partial_flushing_support != 0);
|
||||||
|
m_can_set_head_buffer = (properties.doublebuffer_support != 0);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
HardwareScreenBackend::~HardwareScreenBackend()
|
||||||
|
{
|
||||||
|
if (m_framebuffer_fd >= 0) {
|
||||||
|
close(m_framebuffer_fd);
|
||||||
|
m_framebuffer_fd = -1;
|
||||||
|
}
|
||||||
|
if (m_framebuffer) {
|
||||||
|
MUST(Core::System::munmap(m_framebuffer, m_size_in_bytes));
|
||||||
|
|
||||||
|
m_framebuffer = nullptr;
|
||||||
|
m_size_in_bytes = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorOr<void> HardwareScreenBackend::set_head_resolution(FBHeadResolution resolution)
|
||||||
|
{
|
||||||
|
auto rc = fb_set_resolution(m_framebuffer_fd, &resolution);
|
||||||
|
if (rc != 0)
|
||||||
|
return Error::from_syscall("fb_set_resolution", rc);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorOr<void> HardwareScreenBackend::unmap_framebuffer()
|
||||||
|
{
|
||||||
|
if (m_framebuffer) {
|
||||||
|
size_t previous_size_in_bytes = m_size_in_bytes;
|
||||||
|
return Core::System::munmap(m_framebuffer, previous_size_in_bytes);
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorOr<void> HardwareScreenBackend::map_framebuffer()
|
||||||
|
{
|
||||||
|
FBHeadProperties properties;
|
||||||
|
properties.head_index = 0;
|
||||||
|
int rc = fb_get_head_properties(m_framebuffer_fd, &properties);
|
||||||
|
if (rc != 0)
|
||||||
|
return Error::from_syscall("fb_get_head_properties", rc);
|
||||||
|
m_size_in_bytes = properties.buffer_length;
|
||||||
|
|
||||||
|
m_framebuffer = (Gfx::ARGB32*)TRY(Core::System::mmap(nullptr, m_size_in_bytes, PROT_READ | PROT_WRITE, MAP_SHARED, m_framebuffer_fd, 0));
|
||||||
|
|
||||||
|
if (m_can_set_head_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 = static_cast<size_t>(properties.pitch) * properties.height;
|
||||||
|
} else {
|
||||||
|
m_back_buffer_offset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorOr<FBHeadProperties> HardwareScreenBackend::get_head_properties()
|
||||||
|
{
|
||||||
|
FBHeadProperties properties;
|
||||||
|
properties.head_index = 0;
|
||||||
|
int rc = fb_get_head_properties(m_framebuffer_fd, &properties);
|
||||||
|
if (rc != 0)
|
||||||
|
return Error::from_syscall("fb_get_head_properties", rc);
|
||||||
|
m_pitch = static_cast<int>(properties.pitch);
|
||||||
|
return properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HardwareScreenBackend::set_head_buffer(int head_index)
|
||||||
|
{
|
||||||
|
VERIFY(m_can_set_head_buffer);
|
||||||
|
VERIFY(head_index <= 1 && head_index >= 0);
|
||||||
|
FBHeadVerticalOffset offset { 0, 0 };
|
||||||
|
if (head_index == 1)
|
||||||
|
offset.offsetted = 1;
|
||||||
|
int rc = fb_set_head_vertical_offset_buffer(m_framebuffer_fd, &offset);
|
||||||
|
VERIFY(rc == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorOr<void> HardwareScreenBackend::flush_framebuffer_rects(int buffer_index, Span<FBRect const> flush_rects)
|
||||||
|
{
|
||||||
|
int rc = fb_flush_buffers(m_framebuffer_fd, buffer_index, flush_rects.data(), (unsigned)flush_rects.size());
|
||||||
|
if (rc == -ENOTSUP)
|
||||||
|
m_can_device_flush_buffers = false;
|
||||||
|
else
|
||||||
|
return Error::from_syscall("fb_flush_buffers", rc);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
39
Userland/Services/WindowServer/HardwareScreenBackend.h
Normal file
39
Userland/Services/WindowServer/HardwareScreenBackend.h
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2022, kleines Filmröllchen <filmroellchen@serenityos.org>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ScreenBackend.h"
|
||||||
|
#include "ScreenLayout.h"
|
||||||
|
#include <AK/Error.h>
|
||||||
|
#include <AK/Span.h>
|
||||||
|
#include <AK/String.h>
|
||||||
|
#include <sys/ioctl_numbers.h>
|
||||||
|
|
||||||
|
namespace WindowServer {
|
||||||
|
class HardwareScreenBackend : public ScreenBackend {
|
||||||
|
public:
|
||||||
|
virtual ~HardwareScreenBackend();
|
||||||
|
|
||||||
|
HardwareScreenBackend(String device);
|
||||||
|
|
||||||
|
virtual ErrorOr<void> open() override;
|
||||||
|
|
||||||
|
virtual void set_head_buffer(int index) override;
|
||||||
|
|
||||||
|
virtual ErrorOr<void> flush_framebuffer_rects(int buffer_index, Span<FBRect const> rects) override;
|
||||||
|
|
||||||
|
virtual ErrorOr<void> unmap_framebuffer() override;
|
||||||
|
virtual ErrorOr<void> map_framebuffer() override;
|
||||||
|
|
||||||
|
virtual ErrorOr<void> set_head_resolution(FBHeadResolution) override;
|
||||||
|
virtual ErrorOr<FBHeadProperties> get_head_properties() override;
|
||||||
|
|
||||||
|
String m_device {};
|
||||||
|
int m_framebuffer_fd { -1 };
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
47
Userland/Services/WindowServer/ScreenBackend.h
Normal file
47
Userland/Services/WindowServer/ScreenBackend.h
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2022, kleines Filmröllchen <filmroellchen@serenityos.org>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ScreenLayout.h"
|
||||||
|
#include <AK/Error.h>
|
||||||
|
#include <AK/Span.h>
|
||||||
|
#include <sys/ioctl_numbers.h>
|
||||||
|
|
||||||
|
namespace WindowServer {
|
||||||
|
|
||||||
|
// Handles low-level device interfacing for the screen.
|
||||||
|
// ScreenBackend is a thin transparent wrapper around framebuffer-related data which is responsible for setting up this data,
|
||||||
|
// tearing it down, changing its properties like size, and performing flushes.
|
||||||
|
// The screen is intended to directly access the members to perform its function, but it only ever reads from anything
|
||||||
|
// except the data in the framebuffer memory.
|
||||||
|
class ScreenBackend {
|
||||||
|
public:
|
||||||
|
virtual ~ScreenBackend() = default;
|
||||||
|
|
||||||
|
virtual ErrorOr<void> open() = 0;
|
||||||
|
|
||||||
|
virtual void set_head_buffer(int index) = 0;
|
||||||
|
|
||||||
|
virtual ErrorOr<void> flush_framebuffer_rects(int buffer_index, Span<FBRect const> rects) = 0;
|
||||||
|
|
||||||
|
virtual ErrorOr<void> unmap_framebuffer() = 0;
|
||||||
|
virtual ErrorOr<void> map_framebuffer() = 0;
|
||||||
|
|
||||||
|
virtual ErrorOr<void> set_head_resolution(FBHeadResolution) = 0;
|
||||||
|
virtual ErrorOr<FBHeadProperties> get_head_properties() = 0;
|
||||||
|
|
||||||
|
bool m_can_device_flush_buffers { true };
|
||||||
|
bool m_can_set_head_buffer { false };
|
||||||
|
|
||||||
|
Gfx::ARGB32* m_framebuffer { nullptr };
|
||||||
|
size_t m_size_in_bytes { 0 };
|
||||||
|
size_t m_back_buffer_offset { 0 };
|
||||||
|
|
||||||
|
int m_pitch { 0 };
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue