1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 17:37:34 +00:00

Kernel: Move all Graphics-related code into Devices/GPU directory

Like the HID, Audio and Storage subsystem, the Graphics subsystem (which
handles GPUs technically) exposes unix device files (typically in /dev).
To ensure consistency across the repository, move all related files to a
new directory under Kernel/Devices called "GPU".

Also remove the redundant "GPU" word from the VirtIO driver directory,
and the word "Graphics" from GraphicsManagement.{h,cpp} filenames.
This commit is contained in:
Liav A 2023-06-03 14:47:47 +03:00 committed by Jelle Raaijmakers
parent 31a7dabf02
commit 9ee098b119
69 changed files with 167 additions and 167 deletions

View file

@ -0,0 +1,91 @@
/*
* Copyright (c) 2022, the SerenityOS developers.
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <Kernel/Devices/GPU/Console/BootFramebufferConsole.h>
#include <Kernel/Locking/Spinlock.h>
#include <Kernel/Memory/MemoryManager.h>
namespace Kernel::Graphics {
BootFramebufferConsole::BootFramebufferConsole(PhysicalAddress framebuffer_addr, size_t width, size_t height, size_t pitch)
: GenericFramebufferConsoleImpl(width, height, pitch)
{
// NOTE: We're very early in the boot process, memory allocations shouldn't really fail
auto framebuffer_end = Memory::page_round_up(framebuffer_addr.offset(height * pitch).get()).release_value();
m_framebuffer = MM.allocate_kernel_region(framebuffer_addr.page_base(), framebuffer_end - framebuffer_addr.page_base().get(), "Boot Framebuffer"sv, Memory::Region::Access::ReadWrite).release_value();
[[maybe_unused]] auto result = m_framebuffer->set_write_combine(true);
m_framebuffer_data = m_framebuffer->vaddr().offset(framebuffer_addr.offset_in_page()).as_ptr();
memset(m_framebuffer_data, 0, height * pitch);
}
void BootFramebufferConsole::clear(size_t x, size_t y, size_t length)
{
SpinlockLocker lock(m_lock);
if (m_framebuffer_data)
GenericFramebufferConsoleImpl::clear(x, y, length);
}
void BootFramebufferConsole::clear_glyph(size_t x, size_t y)
{
VERIFY(m_lock.is_locked());
GenericFramebufferConsoleImpl::clear_glyph(x, y);
}
void BootFramebufferConsole::enable()
{
// Once disabled, ignore requests to re-enable
}
void BootFramebufferConsole::disable()
{
SpinlockLocker lock(m_lock);
GenericFramebufferConsoleImpl::disable();
m_framebuffer = nullptr;
m_framebuffer_data = nullptr;
}
void BootFramebufferConsole::write(size_t x, size_t y, char ch, Color background, Color foreground, bool critical)
{
SpinlockLocker lock(m_lock);
if (m_framebuffer_data)
GenericFramebufferConsoleImpl::write(x, y, ch, background, foreground, critical);
}
void BootFramebufferConsole::set_cursor(size_t x, size_t y)
{
// Note: To ensure we don't trigger a deadlock, let's assert in
// case we already locked the spinlock, so we know there's a bug
// in the call path.
VERIFY(!m_lock.is_locked());
SpinlockLocker lock(m_lock);
hide_cursor();
m_x = x;
m_y = y;
show_cursor();
}
void BootFramebufferConsole::hide_cursor()
{
VERIFY(m_lock.is_locked());
GenericFramebufferConsoleImpl::hide_cursor();
}
void BootFramebufferConsole::show_cursor()
{
VERIFY(m_lock.is_locked());
GenericFramebufferConsoleImpl::show_cursor();
}
u8* BootFramebufferConsole::framebuffer_data()
{
VERIFY(m_lock.is_locked());
VERIFY(m_framebuffer_data);
return m_framebuffer_data;
}
}

View file

@ -0,0 +1,45 @@
/*
* Copyright (c) 2022, the SerenityOS developers.
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <Kernel/Devices/GPU/Console/GenericFramebufferConsole.h>
#include <Kernel/Forward.h>
namespace Kernel::Graphics {
class BootFramebufferConsole : public GenericFramebufferConsoleImpl {
public:
virtual void clear(size_t x, size_t y, size_t length) override;
virtual void write(size_t x, size_t y, char ch, Color background, Color foreground, bool critical = false) override;
using GenericFramebufferConsoleImpl::write;
virtual void enable() override;
virtual void disable() override;
virtual void flush(size_t, size_t, size_t, size_t) override { }
virtual void set_resolution(size_t, size_t, size_t) override { }
u8* unsafe_framebuffer_data() { return m_framebuffer_data; }
BootFramebufferConsole(PhysicalAddress framebuffer_addr, size_t width, size_t height, size_t pitch);
private:
virtual void set_cursor(size_t x, size_t y) override;
virtual void hide_cursor() override;
virtual void show_cursor() override;
protected:
virtual void clear_glyph(size_t x, size_t y) override;
virtual u8* framebuffer_data() override;
OwnPtr<Memory::Region> m_framebuffer;
u8* m_framebuffer_data {};
mutable Spinlock<LockRank::None> m_lock {};
};
}

View file

@ -0,0 +1,81 @@
/*
* Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/AtomicRefCounted.h>
#include <AK/Types.h>
#include <Kernel/Devices/GPU/GenericGraphicsAdapter.h>
namespace Kernel::Graphics {
class Console : public AtomicRefCounted<Console> {
public:
// Stanadard VGA text mode colors
enum Color : u8 {
Black = 0,
Blue,
Green,
Cyan,
Red,
Magenta,
Brown,
LightGray,
DarkGray,
BrightBlue,
BrightGreen,
BrightCyan,
BrightRed,
BrightMagenta,
Yellow,
White,
};
public:
size_t width() const { return m_width; }
size_t height() const { return m_height; }
size_t pitch() const { return bytes_per_base_glyph() * width(); }
virtual size_t max_column() const { return m_width; }
virtual size_t max_row() const { return m_height; }
virtual size_t bytes_per_base_glyph() const = 0;
virtual size_t chars_per_line() const = 0;
virtual void enable() = 0;
virtual void disable() = 0;
virtual bool is_hardware_paged_capable() const = 0;
virtual bool has_hardware_cursor() const = 0;
virtual void set_cursor(size_t x, size_t y) = 0;
virtual void clear(size_t x, size_t y, size_t length) = 0;
virtual void write(size_t x, size_t y, char ch, Color background, Color foreground, bool critical = false) = 0;
virtual void write(size_t x, size_t y, char ch, bool critical = false) = 0;
virtual void write(char ch, bool critical = false) = 0;
virtual void flush(size_t x, size_t y, size_t width, size_t height) = 0;
virtual ~Console() = default;
protected:
virtual void hide_cursor() = 0;
virtual void show_cursor() = 0;
Console(size_t width, size_t height)
: m_width(width)
, m_height(height)
{
m_enabled.store(true);
}
Atomic<bool> m_enabled;
Color m_default_foreground_color { Color::White };
Color m_default_background_color { Color::Black };
size_t m_width;
size_t m_height;
mutable size_t m_x { 0 };
mutable size_t m_y { 0 };
};
}

View file

@ -0,0 +1,42 @@
/*
* Copyright (c) 2021, Sahan Fernando <sahan.h.fernando@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <Kernel/Devices/GPU/Console/ContiguousFramebufferConsole.h>
#include <Kernel/TTY/ConsoleManagement.h>
namespace Kernel::Graphics {
NonnullLockRefPtr<ContiguousFramebufferConsole> ContiguousFramebufferConsole::initialize(PhysicalAddress framebuffer_address, size_t width, size_t height, size_t pitch)
{
return adopt_lock_ref(*new ContiguousFramebufferConsole(framebuffer_address, width, height, pitch));
}
ContiguousFramebufferConsole::ContiguousFramebufferConsole(PhysicalAddress framebuffer_address, size_t width, size_t height, size_t pitch)
: GenericFramebufferConsole(width, height, pitch)
, m_framebuffer_address(framebuffer_address)
{
set_resolution(width, height, pitch);
}
void ContiguousFramebufferConsole::set_resolution(size_t width, size_t height, size_t pitch)
{
m_width = width;
m_height = height;
m_pitch = pitch;
size_t size = Memory::page_round_up(pitch * height).release_value_but_fixme_should_propagate_errors();
dbgln("Framebuffer Console: taking {} bytes", size);
auto region_or_error = MM.allocate_kernel_region(m_framebuffer_address, size, "Framebuffer Console"sv, Memory::Region::Access::ReadWrite, Memory::Region::Cacheable::Yes);
VERIFY(!region_or_error.is_error());
m_framebuffer_region = region_or_error.release_value();
// Just to start cleanly, we clean the entire framebuffer
memset(m_framebuffer_region->vaddr().as_ptr(), 0, pitch * height);
ConsoleManagement::the().resolution_was_changed();
}
}

View file

@ -0,0 +1,30 @@
/*
* Copyright (c) 2021, Sahan Fernando <sahan.h.fernando@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <Kernel/Devices/GPU/Console/GenericFramebufferConsole.h>
namespace Kernel::Graphics {
class ContiguousFramebufferConsole final : public GenericFramebufferConsole {
public:
static NonnullLockRefPtr<ContiguousFramebufferConsole> initialize(PhysicalAddress, size_t width, size_t height, size_t pitch);
virtual void set_resolution(size_t width, size_t height, size_t pitch) override;
virtual void flush(size_t, size_t, size_t, size_t) override { }
private:
virtual u8* framebuffer_data() override
{
return m_framebuffer_region->vaddr().as_ptr();
}
OwnPtr<Memory::Region> m_framebuffer_region;
ContiguousFramebufferConsole(PhysicalAddress, size_t width, size_t height, size_t pitch);
PhysicalAddress m_framebuffer_address;
};
}

View file

@ -0,0 +1,379 @@
/*
* Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il>
* Copyright (c) 2022, MacDue <macdue@dueutil.tech>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <Kernel/Devices/GPU/Console/GenericFramebufferConsole.h>
#include <Kernel/TTY/ConsoleManagement.h>
namespace Kernel::Graphics {
// Note: This bitmap was generated from CathodeRegular10.font
constexpr unsigned char const font_cathode_8x16[128][16] = {
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0000 (nul)
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0001
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0002
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0003
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0004
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0005
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0006
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0007
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0008
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0009
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+000A
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+000B
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+000C
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+000D
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+000E
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+000F
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0010
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0011
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0012
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0013
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0014
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0015
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0016
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0017
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0018
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0019
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+001A
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+001B
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+001C
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+001D
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+001E
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+001F
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0020 ( )
{ 0x00, 0x00, 0x30, 0x78, 0x78, 0x78, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00 }, // U+0021 (!)
{ 0x00, 0x00, 0x6C, 0x6C, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0022 (")
{ 0x00, 0x00, 0x6C, 0x6C, 0x6C, 0xFE, 0x6C, 0x6C, 0x6C, 0xFE, 0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00 }, // U+0023 (#)
{ 0x00, 0x00, 0x30, 0x30, 0x78, 0xCC, 0xCC, 0x60, 0x18, 0xCC, 0xCC, 0x78, 0x30, 0x30, 0x00, 0x00 }, // U+0024 ($)
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0xC2, 0xC4, 0x08, 0x10, 0x20, 0x46, 0x86, 0x00, 0x00, 0x00, 0x00 }, // U+0025 (%)
{ 0x00, 0x00, 0x78, 0xCC, 0xCC, 0xCC, 0x78, 0x36, 0x5C, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00 }, // U+0026 (&)
{ 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0027 (')
{ 0x00, 0x00, 0x0C, 0x18, 0x30, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x30, 0x18, 0x0C, 0x00, 0x00 }, // U+0028 (()
{ 0x00, 0x00, 0x60, 0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x18, 0x30, 0x60, 0x00, 0x00 }, // U+0029 ())
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0xCC, 0x30, 0xFC, 0x30, 0xCC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+002A (*)
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0xFC, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+002B (+)
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00 }, // U+002C (,)
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+002D (-)
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00 }, // U+002E (.)
{ 0x00, 0x00, 0x02, 0x06, 0x04, 0x0C, 0x18, 0x10, 0x30, 0x60, 0x40, 0xC0, 0x80, 0x00, 0x00, 0x00 }, // U+002F (/)
{ 0x00, 0x00, 0x7C, 0xC6, 0xCE, 0xCE, 0xDE, 0xD6, 0xF6, 0xE6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00 }, // U+0030 (0)
{ 0x00, 0x00, 0x30, 0x70, 0xF0, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0xFC, 0x00, 0x00, 0x00 }, // U+0031 (1)
{ 0x00, 0x00, 0x7C, 0xC6, 0x06, 0x06, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC6, 0xFE, 0x00, 0x00, 0x00 }, // U+0032 (2)
{ 0x00, 0x00, 0x7C, 0xC6, 0x06, 0x06, 0x04, 0x38, 0x04, 0x06, 0x06, 0xC6, 0x7C, 0x00, 0x00, 0x00 }, // U+0033 (3)
{ 0x00, 0x00, 0x0C, 0x1C, 0x3C, 0x6C, 0xCC, 0xFE, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00, 0x00, 0x00 }, // U+0034 (4)
{ 0x00, 0x00, 0xFE, 0xC0, 0xC0, 0xC0, 0xFC, 0x06, 0x06, 0x06, 0x06, 0xC6, 0x7C, 0x00, 0x00, 0x00 }, // U+0035 (5)
{ 0x00, 0x00, 0x1C, 0x30, 0x60, 0xC0, 0xC0, 0xFC, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00 }, // U+0036 (6)
{ 0x00, 0x00, 0xFE, 0xC6, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x60, 0x60, 0x60, 0x60, 0x00, 0x00, 0x00 }, // U+0037 (7)
{ 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00 }, // U+0038 (8)
{ 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0x7E, 0x06, 0x06, 0x0C, 0x18, 0x70, 0x00, 0x00, 0x00 }, // U+0039 (9)
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00 }, // U+003A (:)
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60, 0x00, 0x00 }, // U+003B (;)
{ 0x00, 0x00, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xE0, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x00, 0x00, 0x00 }, // U+003C (<)
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+003D (=)
{ 0x00, 0x00, 0xC0, 0x60, 0x30, 0x18, 0x0C, 0x0E, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0x00, 0x00, 0x00 }, // U+003E (>)
{ 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0x06, 0x0C, 0x18, 0x30, 0x30, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00 }, // U+003F (?)
{ 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, 0xDC, 0xC0, 0x7C, 0x00, 0x00, 0x00 }, // U+0040 (@)
{ 0x00, 0x00, 0x10, 0x38, 0x6C, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00 }, // U+0041 (A)
{ 0x00, 0x00, 0xFC, 0x66, 0x66, 0x66, 0x66, 0x7C, 0x66, 0x66, 0x66, 0x66, 0xFC, 0x00, 0x00, 0x00 }, // U+0042 (B)
{ 0x00, 0x00, 0x3C, 0x66, 0xC2, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC2, 0x66, 0x3C, 0x00, 0x00, 0x00 }, // U+0043 (C)
{ 0x00, 0x00, 0xF8, 0x6C, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6C, 0xF8, 0x00, 0x00, 0x00 }, // U+0044 (D)
{ 0x00, 0x00, 0xFE, 0x66, 0x62, 0x60, 0x68, 0x78, 0x68, 0x60, 0x62, 0x66, 0xFE, 0x00, 0x00, 0x00 }, // U+0045 (E)
{ 0x00, 0x00, 0xFE, 0x66, 0x62, 0x60, 0x64, 0x7C, 0x64, 0x60, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00 }, // U+0046 (F)
{ 0x00, 0x00, 0x3C, 0x66, 0xC2, 0xC0, 0xC0, 0xDE, 0xC6, 0xC6, 0xC6, 0x66, 0x3A, 0x00, 0x00, 0x00 }, // U+0047 (G)
{ 0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00 }, // U+0048 (H)
{ 0x00, 0x00, 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00, 0x00, 0x00 }, // U+0049 (I)
{ 0x00, 0x00, 0x1E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0xCC, 0xCC, 0x78, 0x00, 0x00, 0x00 }, // U+004A (J)
{ 0x00, 0x00, 0xE6, 0x66, 0x6C, 0x6C, 0x68, 0x78, 0x68, 0x6C, 0x6C, 0x66, 0xE6, 0x00, 0x00, 0x00 }, // U+004B (K)
{ 0x00, 0x00, 0xF0, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x62, 0x66, 0xFE, 0x00, 0x00, 0x00 }, // U+004C (L)
{ 0x00, 0x00, 0xC6, 0xEE, 0xFE, 0xFE, 0xD6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00 }, // U+004D (M)
{ 0x00, 0x00, 0xC6, 0xE6, 0xF6, 0xFE, 0xFE, 0xDE, 0xCE, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00 }, // U+004E (N)
{ 0x00, 0x00, 0x38, 0x6C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x6C, 0x38, 0x00, 0x00, 0x00 }, // U+004F (O)
{ 0x00, 0x00, 0xFC, 0x66, 0x66, 0x66, 0x66, 0x7C, 0x60, 0x60, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00 }, // U+0050 (P)
{ 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xD6, 0xDE, 0x7C, 0x0E, 0x00, 0x00 }, // U+0051 (Q)
{ 0x00, 0x00, 0xFC, 0x66, 0x66, 0x66, 0x66, 0x7C, 0x6C, 0x66, 0x66, 0x66, 0xF6, 0x00, 0x00, 0x00 }, // U+0052 (R)
{ 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC0, 0x60, 0x30, 0x18, 0x0C, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00 }, // U+0053 (S)
{ 0x00, 0x00, 0xFC, 0xFC, 0xB4, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00, 0x00, 0x00 }, // U+0054 (T)
{ 0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00 }, // U+0055 (U)
{ 0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x6C, 0x38, 0x10, 0x00, 0x00, 0x00 }, // U+0056 (V)
{ 0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xD6, 0xD6, 0xD6, 0xFE, 0x7C, 0x6C, 0x00, 0x00, 0x00 }, // U+0057 (W)
{ 0x00, 0x00, 0xC6, 0xC6, 0x6C, 0x38, 0x38, 0x38, 0x38, 0x38, 0x6C, 0xC6, 0xC6, 0x00, 0x00, 0x00 }, // U+0058 (X)
{ 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00, 0x00, 0x00 }, // U+0059 (Y)
{ 0x00, 0x00, 0xFE, 0xC6, 0x86, 0x0C, 0x18, 0x30, 0x60, 0x40, 0xC2, 0xC6, 0xFE, 0x00, 0x00, 0x00 }, // U+005A (Z)
{ 0x00, 0x00, 0xFC, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFC, 0x00, 0x00, 0x00 }, // U+005B ([)
{ 0x00, 0x00, 0x80, 0xC0, 0x40, 0x60, 0x30, 0x10, 0x18, 0x0C, 0x04, 0x06, 0x02, 0x00, 0x00, 0x00 }, // U+005C (\)
{ 0x00, 0x00, 0xFC, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0xFC, 0x00, 0x00, 0x00 }, // U+005D (])
{ 0x00, 0x00, 0x20, 0x70, 0xD8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+005E (^)
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00 }, // U+005F (_)
{ 0x00, 0x00, 0x60, 0x70, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0060 (`)
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0C, 0x0C, 0x7C, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00 }, // U+0061 (a)
{ 0x00, 0x00, 0xE0, 0x60, 0x60, 0x78, 0x6C, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7C, 0x00, 0x00, 0x00 }, // U+0062 (b)
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC0, 0xC0, 0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00 }, // U+0063 (c)
{ 0x00, 0x00, 0x1C, 0x0C, 0x0C, 0x3C, 0x6C, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00 }, // U+0064 (d)
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xFE, 0xC0, 0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00 }, // U+0065 (e)
{ 0x00, 0x00, 0x38, 0x6C, 0x64, 0x60, 0xF0, 0x60, 0x60, 0x60, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00 }, // U+0066 (f)
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xCC, 0xCC, 0xCC, 0xCC, 0x7C, 0x0C, 0xCC, 0x78, 0x00, 0x00 }, // U+0067 (g)
{ 0x00, 0x00, 0xE0, 0x60, 0x60, 0x6C, 0x76, 0x66, 0x66, 0x66, 0x66, 0x66, 0xE6, 0x00, 0x00, 0x00 }, // U+0068 (h)
{ 0x00, 0x00, 0x30, 0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00, 0x00, 0x00 }, // U+0069 (i)
{ 0x00, 0x00, 0x06, 0x06, 0x00, 0x0E, 0x06, 0x06, 0x06, 0x06, 0x06, 0xC6, 0xC6, 0x7C, 0x00, 0x00 }, // U+006A (j)
{ 0x00, 0x00, 0xE0, 0x60, 0x60, 0x66, 0x6C, 0x68, 0x70, 0x68, 0x6C, 0x66, 0xE6, 0x00, 0x00, 0x00 }, // U+006B (k)
{ 0x00, 0x00, 0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00, 0x00, 0x00 }, // U+006C (l)
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0xEC, 0xFE, 0xD6, 0xD6, 0xD6, 0xD6, 0xC6, 0xC6, 0x00, 0x00, 0x00 }, // U+006D (m)
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00 }, // U+006E (n)
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00 }, // U+006F (o)
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0x66, 0x66, 0x66, 0x66, 0x7C, 0x60, 0x60, 0xF0, 0x00, 0x00 }, // U+0070 (p)
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xCC, 0xCC, 0xCC, 0xCC, 0x7C, 0x0C, 0x0C, 0x1E, 0x00, 0x00 }, // U+0071 (q)
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0xD8, 0x76, 0x66, 0x60, 0x60, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00 }, // U+0072 (r)
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0x40, 0x70, 0x1C, 0x04, 0xC6, 0x7C, 0x00, 0x00, 0x00 }, // U+0073 (s)
{ 0x00, 0x00, 0x10, 0x30, 0x30, 0xFC, 0x30, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1C, 0x00, 0x00, 0x00 }, // U+0074 (t)
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00 }, // U+0075 (u)
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x00, 0x00, 0x00 }, // U+0076 (v)
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xD6, 0xD6, 0xD6, 0xFE, 0x6C, 0x00, 0x00, 0x00 }, // U+0077 (w)
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0x6C, 0x38, 0x38, 0x38, 0x38, 0x6C, 0xC6, 0x00, 0x00, 0x00 }, // U+0078 (x)
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0x7E, 0x06, 0x06, 0x0C, 0xF8, 0x00, 0x00 }, // U+0079 (y)
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xCC, 0x0C, 0x18, 0x30, 0x60, 0x66, 0xFE, 0x00, 0x00, 0x00 }, // U+007A (z)
{ 0x00, 0x00, 0x1E, 0x30, 0x30, 0x30, 0x30, 0xE0, 0x30, 0x30, 0x30, 0x30, 0x1E, 0x00, 0x00, 0x00 }, // U+007B ({)
{ 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00 }, // U+007C (|)
{ 0x00, 0x00, 0xF0, 0x18, 0x18, 0x18, 0x18, 0x0E, 0x18, 0x18, 0x18, 0x18, 0xF0, 0x00, 0x00, 0x00 }, // U+007D (})
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+007E (~)
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } // U+007F
};
// FIXME: This assumes 32 bit BGR (Blue-Green-Red) palette
enum BGRColor : u32 {
Black = 0,
Blue = 0x0000FF,
Green = 0x00FF00,
Cyan = 0x0000FFFF,
Red = 0xFF0000,
Magenta = 0x00FF00FF,
Brown = 0x00964B00,
LightGray = 0x00D3D3D3,
DarkGray = 0x00A9A9A9,
BrightBlue = 0x0ADD8E6,
BrightGreen = 0x0090EE90,
BrightCyan = 0x00E0FFFF,
BrightRed = 0x00D70A53,
BrightMagenta = 0x00F984E5,
Yellow = 0x00FFE135,
White = 0x00FFFFFF,
};
static inline BGRColor convert_standard_color_to_bgr_color(Console::Color color)
{
switch (color) {
case Console::Color::Black:
return BGRColor::Black;
case Console::Color::Red:
return BGRColor::Red;
case Console::Color::Brown:
return BGRColor::Brown;
case Console::Color::Blue:
return BGRColor::Blue;
case Console::Color::Magenta:
return BGRColor::Magenta;
case Console::Color::Green:
return BGRColor::Green;
case Console::Color::Cyan:
return BGRColor::Cyan;
case Console::Color::LightGray:
return BGRColor::LightGray;
case Console::Color::DarkGray:
return BGRColor::DarkGray;
case Console::Color::BrightRed:
return BGRColor::BrightRed;
case Console::Color::BrightGreen:
return BGRColor::BrightGreen;
case Console::Color::Yellow:
return BGRColor::Yellow;
case Console::Color::BrightBlue:
return BGRColor::BrightBlue;
case Console::Color::BrightMagenta:
return BGRColor::BrightMagenta;
case Console::Color::BrightCyan:
return BGRColor::BrightCyan;
case Console::Color::White:
return BGRColor::White;
default:
VERIFY_NOT_REACHED();
}
}
size_t GenericFramebufferConsoleImpl::bytes_per_base_glyph() const
{
// FIXME: We assume we have 32 bit bpp framebuffer.
return 8 * 32;
}
size_t GenericFramebufferConsoleImpl::chars_per_line() const
{
return max_column();
}
void GenericFramebufferConsoleImpl::set_cursor(size_t x, size_t y)
{
hide_cursor();
m_x = x;
m_y = y;
show_cursor();
}
GenericFramebufferConsoleImpl::FramebufferOffset GenericFramebufferConsoleImpl::framebuffer_offset(size_t x, size_t y)
{
return { (&framebuffer_data()[x * sizeof(u32) * (m_glyph_columns + m_glyph_spacing) + y * m_glyph_rows * framebuffer_pitch()]) };
}
void GenericFramebufferConsoleImpl::hide_cursor()
{
auto offset_in_framebuffer = framebuffer_offset(m_x, m_y);
offset_in_framebuffer.bytes += framebuffer_pitch() * (m_glyph_rows - 1);
for (size_t glyph_column = 0; glyph_column < m_glyph_columns; glyph_column++)
offset_in_framebuffer.pixels[glyph_column] = m_cursor_overriden_pixels[glyph_column];
}
void GenericFramebufferConsoleImpl::show_cursor()
{
auto offset_in_framebuffer = framebuffer_offset(m_x, m_y);
offset_in_framebuffer.bytes += framebuffer_pitch() * (m_glyph_rows - 1);
for (size_t glyph_column = 0; glyph_column < m_glyph_columns; glyph_column++) {
m_cursor_overriden_pixels[glyph_column] = offset_in_framebuffer.pixels[glyph_column];
memset(offset_in_framebuffer.pixels + glyph_column, 0xff, sizeof(u32));
}
}
void GenericFramebufferConsoleImpl::clear(size_t x, size_t y, size_t length)
{
if (x == 0 && length == max_column()) {
// If we need to clear the entire row, just clean it with quick memset :)
auto offset_in_framebuffer = framebuffer_offset(x, y);
for (size_t glyph_row = 0; glyph_row < m_glyph_rows; glyph_row++) {
memset(offset_in_framebuffer.pixels, 0, framebuffer_pitch());
offset_in_framebuffer.bytes += framebuffer_pitch();
}
flush(0, m_glyph_rows * y, (m_glyph_columns + m_glyph_spacing) * length, 1);
return;
}
for (size_t index = 0; index < length; index++) {
if (x >= max_column()) {
x = 0;
y++;
if (y >= max_row())
y = 0;
}
clear_glyph(x, y);
}
}
void GenericFramebufferConsoleImpl::clear_glyph(size_t x, size_t y)
{
auto offset_in_framebuffer = framebuffer_offset(x, y);
for (size_t glyph_row = 0; glyph_row < m_glyph_rows; glyph_row++) {
memset(offset_in_framebuffer.pixels, 0, (m_glyph_columns + m_glyph_spacing) * sizeof(u32));
offset_in_framebuffer.bytes += framebuffer_pitch();
}
flush_glyph(x, y);
}
void GenericFramebufferConsoleImpl::enable()
{
memset(framebuffer_data(), 0, height() * framebuffer_pitch());
m_enabled.store(true);
}
void GenericFramebufferConsoleImpl::disable()
{
m_enabled.store(false);
}
void GenericFramebufferConsoleImpl::write(size_t x, size_t y, char ch, Color background, Color foreground, bool critical)
{
if (!m_enabled.load())
return;
// If we are in critical printing mode, we need to handle new lines here
// because there's no other responsible object to do that in the print call path
if (critical && (ch == '\r' || ch == '\n')) {
m_x = 0;
m_y += 1;
if (m_y >= max_row())
m_y = 0;
return;
}
if ((int)ch < 0x20 || (int)ch == 0x7f) {
// FIXME: There's no point in printing empty glyphs...
// Maybe try to add these special glyphs and print them.
return;
}
clear_glyph(x, y);
auto bitmap = font_cathode_8x16[(int)ch];
auto offset_in_framebuffer = framebuffer_offset(x, y);
BGRColor foreground_color = convert_standard_color_to_bgr_color(foreground);
BGRColor background_color = convert_standard_color_to_bgr_color(background);
for (size_t glyph_row = 0; glyph_row < m_glyph_rows; glyph_row++) {
for (size_t glyph_column = m_glyph_columns; glyph_column > 0; glyph_column--) {
bool pixel_set = bitmap[glyph_row] & (1 << glyph_column);
offset_in_framebuffer.pixels[m_glyph_columns - glyph_column] = pixel_set ? foreground_color : background_color;
}
for (size_t spacing_column = 0; spacing_column < m_glyph_spacing; spacing_column++)
offset_in_framebuffer.pixels[m_glyph_columns + spacing_column] = background_color;
offset_in_framebuffer.bytes += framebuffer_pitch();
}
flush_glyph(x, y);
m_x = x + 1;
if (m_x >= max_column()) {
m_x = 0;
m_y = y + 1;
if (m_y >= max_row())
m_y = 0;
}
}
void GenericFramebufferConsoleImpl::flush_glyph(size_t x, size_t y)
{
flush((m_glyph_columns + m_glyph_spacing) * x, m_glyph_rows * y, m_glyph_columns + m_glyph_spacing, m_glyph_rows);
}
void GenericFramebufferConsoleImpl::write(size_t x, size_t y, char ch, bool critical)
{
write(x, y, ch, m_default_background_color, m_default_foreground_color, critical);
}
void GenericFramebufferConsoleImpl::write(char ch, bool critical)
{
write(m_x, m_y, ch, m_default_background_color, m_default_foreground_color, critical);
}
void GenericFramebufferConsole::clear(size_t x, size_t y, size_t length)
{
SpinlockLocker lock(m_lock);
GenericFramebufferConsoleImpl::clear(x, y, length);
}
void GenericFramebufferConsole::clear_glyph(size_t x, size_t y)
{
VERIFY(m_lock.is_locked());
GenericFramebufferConsoleImpl::clear_glyph(x, y);
}
void GenericFramebufferConsole::enable()
{
SpinlockLocker lock(m_lock);
GenericFramebufferConsoleImpl::enable();
}
void GenericFramebufferConsole::disable()
{
SpinlockLocker lock(m_lock);
GenericFramebufferConsoleImpl::disable();
}
void GenericFramebufferConsole::write(size_t x, size_t y, char ch, Color background, Color foreground, bool critical)
{
SpinlockLocker lock(m_lock);
GenericFramebufferConsoleImpl::write(x, y, ch, background, foreground, critical);
}
}

View file

@ -0,0 +1,87 @@
/*
* Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/Types.h>
#include <Kernel/Devices/GPU/Console/Console.h>
#include <Kernel/Memory/PhysicalAddress.h>
namespace Kernel::Graphics {
class GenericFramebufferConsoleImpl : public Console {
public:
virtual size_t bytes_per_base_glyph() const override;
virtual size_t chars_per_line() const override;
virtual size_t max_column() const override { return m_width / (m_glyph_columns + m_glyph_spacing); }
virtual size_t max_row() const override { return m_height / m_glyph_rows; }
virtual bool is_hardware_paged_capable() const override { return false; }
virtual bool has_hardware_cursor() const override { return false; }
virtual void set_cursor(size_t x, size_t y) override;
virtual void clear(size_t x, size_t y, size_t length) override;
virtual void write(size_t x, size_t y, char ch, Color background, Color foreground, bool critical = false) override;
virtual void write(size_t x, size_t y, char ch, bool critical = false) override;
virtual void write(char ch, bool critical = false) override;
virtual void enable() override;
virtual void disable() override;
virtual void set_resolution(size_t width, size_t height, size_t pitch) = 0;
protected:
virtual void hide_cursor() override;
virtual void show_cursor() override;
GenericFramebufferConsoleImpl(size_t width, size_t height, size_t pitch)
: Console(width, height)
, m_pitch(pitch)
{
m_cursor_overriden_pixels.fill(0);
}
virtual u8* framebuffer_data() = 0;
size_t framebuffer_pitch() const { return m_pitch; }
virtual void clear_glyph(size_t x, size_t y);
union FramebufferOffset {
u8* bytes;
u32* pixels;
};
FramebufferOffset framebuffer_offset(size_t x, size_t y);
void flush_glyph(size_t x, size_t y);
size_t const m_glyph_spacing { 1 };
size_t const m_glyph_columns { 8 };
size_t const m_glyph_rows { 16 };
Array<u32, 8> m_cursor_overriden_pixels;
size_t m_pitch;
};
class GenericFramebufferConsole : public GenericFramebufferConsoleImpl {
public:
virtual void clear(size_t x, size_t y, size_t length) override;
virtual void write(size_t x, size_t y, char ch, Color background, Color foreground, bool critical = false) override;
virtual void enable() override;
virtual void disable() override;
protected:
GenericFramebufferConsole(size_t width, size_t height, size_t pitch)
: GenericFramebufferConsoleImpl(width, height, pitch)
{
}
virtual void clear_glyph(size_t x, size_t y) override;
mutable Spinlock<LockRank::None> m_lock {};
};
}

View file

@ -0,0 +1,158 @@
/*
* Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <Kernel/Devices/GPU/Console/VGATextModeConsole.h>
#include <Kernel/Devices/GPU/Management.h>
#include <Kernel/Sections.h>
namespace Kernel::Graphics {
UNMAP_AFTER_INIT NonnullLockRefPtr<VGATextModeConsole> VGATextModeConsole::initialize()
{
auto vga_window_size = MUST(Memory::page_round_up(0xc0000 - 0xa0000));
auto vga_window_region = MUST(MM.allocate_kernel_region(PhysicalAddress(0xa0000), vga_window_size, "VGA Display"sv, Memory::Region::Access::ReadWrite));
return adopt_lock_ref(*new (nothrow) VGATextModeConsole(move(vga_window_region)));
}
UNMAP_AFTER_INIT VGATextModeConsole::VGATextModeConsole(NonnullOwnPtr<Memory::Region> vga_window_region)
: Console(80, 25)
, m_vga_window_region(move(vga_window_region))
, m_current_vga_window(m_vga_window_region->vaddr().offset(0x18000).as_ptr())
{
for (size_t index = 0; index < height(); index++) {
clear_vga_row(index);
}
dbgln("VGA Text mode console initialized!");
}
enum VGAColor : u8 {
Black = 0,
Blue,
Green,
Cyan,
Red,
Magenta,
Brown,
LightGray,
DarkGray,
BrightBlue,
BrightGreen,
BrightCyan,
BrightRed,
BrightMagenta,
Yellow,
White,
};
[[maybe_unused]] static inline VGAColor convert_standard_color_to_vga_color(Console::Color color)
{
switch (color) {
case Console::Color::Black:
return VGAColor::Black;
case Console::Color::Red:
return VGAColor::Red;
case Console::Color::Brown:
return VGAColor::Brown;
case Console::Color::Blue:
return VGAColor::Blue;
case Console::Color::Magenta:
return VGAColor::Magenta;
case Console::Color::Green:
return VGAColor::Green;
case Console::Color::Cyan:
return VGAColor::Cyan;
case Console::Color::LightGray:
return VGAColor::LightGray;
case Console::Color::DarkGray:
return VGAColor::DarkGray;
case Console::Color::BrightRed:
return VGAColor::BrightRed;
case Console::Color::BrightGreen:
return VGAColor::BrightGreen;
case Console::Color::Yellow:
return VGAColor::Yellow;
case Console::Color::BrightBlue:
return VGAColor::BrightBlue;
case Console::Color::BrightMagenta:
return VGAColor::BrightMagenta;
case Console::Color::BrightCyan:
return VGAColor::BrightCyan;
case Console::Color::White:
return VGAColor::White;
default:
VERIFY_NOT_REACHED();
}
}
void VGATextModeConsole::set_cursor(size_t x, size_t y)
{
SpinlockLocker lock(m_vga_lock);
GraphicsManagement::the().set_vga_text_mode_cursor(width(), x, y);
m_x = x;
m_y = y;
}
void VGATextModeConsole::hide_cursor()
{
SpinlockLocker lock(m_vga_lock);
GraphicsManagement::the().disable_vga_text_mode_console_cursor();
}
void VGATextModeConsole::show_cursor()
{
set_cursor(m_x, m_y);
}
void VGATextModeConsole::clear(size_t x, size_t y, size_t length)
{
SpinlockLocker lock(m_vga_lock);
auto* buf = (u16*)m_current_vga_window.offset((x * 2) + (y * width() * 2)).as_ptr();
for (size_t index = 0; index < length; index++) {
buf[index] = 0x0720;
}
}
void VGATextModeConsole::write(size_t x, size_t y, char ch, bool critical)
{
write(x, y, ch, m_default_background_color, m_default_foreground_color, critical);
}
void VGATextModeConsole::write(size_t x, size_t y, char ch, Color background, Color foreground, bool critical)
{
SpinlockLocker lock(m_vga_lock);
// If we are in critical printing mode, we need to handle new lines here
// because there's no other responsible object to do that in the print call path
if (critical && (ch == '\r' || ch == '\n')) {
// Disable hardware VGA cursor
GraphicsManagement::the().disable_vga_text_mode_console_cursor();
m_x = 0;
m_y += 1;
if (m_y >= max_row())
m_y = 0;
return;
}
auto* buf = (u16*)m_current_vga_window.offset((x * 2) + (y * width() * 2)).as_ptr();
*buf = foreground << 8 | background << 12 | ch;
m_x = x + 1;
if (m_x >= max_column()) {
m_x = 0;
m_y = y + 1;
if (m_y >= max_row())
m_y = 0;
}
}
void VGATextModeConsole::clear_vga_row(u16 row)
{
clear(0, row, width());
}
void VGATextModeConsole::write(char ch, bool critical)
{
write(m_x, m_y, ch, critical);
}
}

View file

@ -0,0 +1,47 @@
/*
* Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/Types.h>
#include <Kernel/Devices/GPU/Console/Console.h>
#include <Kernel/Locking/Spinlock.h>
namespace Kernel::Graphics {
class VGATextModeConsole final : public Console {
public:
static NonnullLockRefPtr<VGATextModeConsole> initialize();
virtual size_t chars_per_line() const override { return width(); };
virtual bool has_hardware_cursor() const override { return true; }
virtual bool is_hardware_paged_capable() const override { return true; }
virtual size_t bytes_per_base_glyph() const override { return 2; }
virtual void set_cursor(size_t x, size_t y) override;
virtual void clear(size_t x, size_t y, size_t length) override;
virtual void write(size_t x, size_t y, char ch, bool critical = false) override;
virtual void write(size_t x, size_t y, char ch, Color background, Color foreground, bool critical = false) override;
virtual void write(char ch, bool critical = false) override;
virtual void flush(size_t, size_t, size_t, size_t) override { }
virtual void enable() override { }
virtual void disable() override { }
private:
virtual void hide_cursor() override;
virtual void show_cursor() override;
void clear_vga_row(u16 row);
explicit VGATextModeConsole(NonnullOwnPtr<Memory::Region>);
mutable Spinlock<LockRank::None> m_vga_lock {};
NonnullOwnPtr<Memory::Region> m_vga_window_region;
VirtualAddress m_current_vga_window;
};
}