From 935f401714cdf90de0db4b1f731af2614d5b4236 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?kleines=20Filmr=C3=B6llchen?= Date: Sat, 2 Apr 2022 00:30:52 +0200 Subject: [PATCH] WindowServer: Create the VirtualScreenBackend This screen backend is just memory-backed and doesn't connect to any screen hardware. That way, we can boot Serenity without video hardware but in full graphical mode :^) To create a virtual screen, put something like this in your WindowServer.ini. There's no way yet to do this through Display Settings, though an existing virtual screen's settings can be changed there. ```ini [Screen0] Mode=Virtual Left=1024 Top=0 Width=1920 Height=1080 ScaleFactor=1 ``` --- Userland/Services/WindowServer/CMakeLists.txt | 1 + Userland/Services/WindowServer/Screen.cpp | 18 ++++- .../WindowServer/VirtualScreenBackend.cpp | 81 +++++++++++++++++++ .../WindowServer/VirtualScreenBackend.h | 44 ++++++++++ 4 files changed, 140 insertions(+), 4 deletions(-) create mode 100644 Userland/Services/WindowServer/VirtualScreenBackend.cpp create mode 100644 Userland/Services/WindowServer/VirtualScreenBackend.h diff --git a/Userland/Services/WindowServer/CMakeLists.txt b/Userland/Services/WindowServer/CMakeLists.txt index fb52873f8a..f23ed083a7 100644 --- a/Userland/Services/WindowServer/CMakeLists.txt +++ b/Userland/Services/WindowServer/CMakeLists.txt @@ -26,6 +26,7 @@ set(SOURCES Overlays.cpp Screen.cpp HardwareScreenBackend.cpp + VirtualScreenBackend.cpp ScreenLayout.cpp Window.cpp WindowFrame.cpp diff --git a/Userland/Services/WindowServer/Screen.cpp b/Userland/Services/WindowServer/Screen.cpp index 816dec3ea9..710cfab10f 100644 --- a/Userland/Services/WindowServer/Screen.cpp +++ b/Userland/Services/WindowServer/Screen.cpp @@ -10,6 +10,7 @@ #include "Event.h" #include "EventLoop.h" #include "ScreenBackend.h" +#include "VirtualScreenBackend.h" #include "WindowManager.h" #include #include @@ -228,8 +229,8 @@ bool Screen::open_device() close_device(); auto& info = screen_layout_info(); - // TODO: Support other backends - if (info.mode == ScreenLayout::Screen::Mode::Device) { + switch (info.mode) { + case ScreenLayout::Screen::Mode::Device: { m_backend = make(info.device.value()); auto return_value = m_backend->open(); if (return_value.is_error()) { @@ -240,9 +241,18 @@ bool Screen::open_device() set_resolution(true); return true; } + case ScreenLayout::Screen::Mode::Virtual: { + m_backend = make(); + // Virtual device open should never fail. + MUST(m_backend->open()); - dbgln("Unsupported screen type {}", ScreenLayout::Screen::mode_to_string(info.mode)); - return false; + set_resolution(true); + return true; + } + default: + dbgln("Unsupported screen type {}", ScreenLayout::Screen::mode_to_string(info.mode)); + return false; + } } void Screen::close_device() diff --git a/Userland/Services/WindowServer/VirtualScreenBackend.cpp b/Userland/Services/WindowServer/VirtualScreenBackend.cpp new file mode 100644 index 0000000000..f6d2b3dfc1 --- /dev/null +++ b/Userland/Services/WindowServer/VirtualScreenBackend.cpp @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2018-2020, the SerenityOS developers. + * Copyright (c) 2022, kleines Filmröllchen + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include "VirtualScreenBackend.h" +#include "ScreenBackend.h" +#include +#include +#include + +namespace WindowServer { + +VirtualScreenBackend::~VirtualScreenBackend() +{ + MUST(unmap_framebuffer()); +} + +ErrorOr VirtualScreenBackend::open() +{ + m_can_device_flush_buffers = true; + m_can_set_head_buffer = true; + return {}; +} + +void VirtualScreenBackend::set_head_buffer(int index) +{ + VERIFY(index <= 1 && index >= 0); + m_first_buffer_active = index == 0; +} + +ErrorOr VirtualScreenBackend::set_head_resolution(FBHeadResolution resolution) +{ + if (resolution.head_index != 0) + return Error::from_string_literal("Only head index 0 is supported."sv); + m_height = resolution.height; + + if (resolution.pitch == 0) + resolution.pitch = static_cast(resolution.width * sizeof(Gfx::ARGB32)); + m_pitch = resolution.pitch; + if (static_cast(resolution.width * sizeof(Gfx::ARGB32)) != resolution.pitch) + return Error::from_string_literal("Unsupported pitch"sv); + + m_width = resolution.width; + return {}; +} + +ErrorOr VirtualScreenBackend::get_head_properties() +{ + return FBHeadProperties { + .head_index = 0, + .pitch = static_cast(m_pitch), + .width = static_cast(m_width), + .height = static_cast(m_height), + .offset = static_cast(m_first_buffer_active ? 0 : m_back_buffer_offset), + .buffer_length = static_cast(m_size_in_bytes), + }; +} + +ErrorOr VirtualScreenBackend::map_framebuffer() +{ + m_size_in_bytes = static_cast(m_pitch) * m_height * 2; + m_framebuffer = new Gfx::ARGB32[static_cast(m_width) * m_height * 2]; + if (m_framebuffer == nullptr) + return Error::from_errno(ENOMEM); + + m_back_buffer_offset = m_size_in_bytes / 2; + m_first_buffer_active = true; + + return {}; +} + +ErrorOr VirtualScreenBackend::unmap_framebuffer() +{ + delete[] m_framebuffer; + return {}; +} + +} diff --git a/Userland/Services/WindowServer/VirtualScreenBackend.h b/Userland/Services/WindowServer/VirtualScreenBackend.h new file mode 100644 index 0000000000..8d59b9cf5a --- /dev/null +++ b/Userland/Services/WindowServer/VirtualScreenBackend.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2022, kleines Filmröllchen + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include "ScreenBackend.h" +#include "ScreenLayout.h" +#include +#include +#include +#include + +namespace WindowServer { + +class VirtualScreenBackend : public ScreenBackend { +public: + virtual ~VirtualScreenBackend(); + + VirtualScreenBackend() = default; + +private: + friend class Screen; + + virtual ErrorOr open() override; + + virtual void set_head_buffer(int index) override; + + virtual ErrorOr flush_framebuffer_rects(int, Span) override { return {}; } + + virtual ErrorOr unmap_framebuffer() override; + virtual ErrorOr map_framebuffer() override; + + virtual ErrorOr set_head_resolution(FBHeadResolution) override; + virtual ErrorOr get_head_properties() override; + + int m_height { 0 }; + int m_width { 0 }; + bool m_first_buffer_active { true }; +}; + +}