Serenity Operating System
1/*
2 * Copyright (c) 2021, Sahan Fernando <sahan.h.fernando@gmail.com>
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7#include <Kernel/Graphics/VirtIOGPU/Console.h>
8#include <Kernel/TTY/ConsoleManagement.h>
9#include <Kernel/WorkQueue.h>
10
11namespace Kernel::Graphics::VirtIOGPU {
12
13constexpr static AK::Time refresh_interval = AK::Time::from_milliseconds(16);
14
15NonnullLockRefPtr<Console> Console::initialize(VirtIODisplayConnector& parent_display_connector)
16{
17 auto current_resolution = parent_display_connector.current_mode_setting();
18 return adopt_lock_ref(*new Console(parent_display_connector, current_resolution));
19}
20
21Console::Console(VirtIODisplayConnector const& parent_display_connector, DisplayConnector::ModeSetting current_resolution)
22 : GenericFramebufferConsole(current_resolution.horizontal_active, current_resolution.vertical_active, current_resolution.horizontal_stride)
23 , m_parent_display_connector(parent_display_connector)
24{
25 // NOTE: Clear the framebuffer, in case it's left with some garbage.
26 memset(framebuffer_data(), 0, current_resolution.horizontal_stride * current_resolution.vertical_active);
27 enqueue_refresh_timer();
28}
29
30void Console::set_resolution(size_t width, size_t height, size_t pitch)
31{
32 m_width = width;
33 m_height = height;
34 m_pitch = pitch;
35
36 // Just to start cleanly, we clean the entire framebuffer
37 memset(framebuffer_data(), 0, pitch * height);
38
39 ConsoleManagement::the().resolution_was_changed();
40}
41
42void Console::set_cursor(size_t x, size_t y)
43{
44 GenericFramebufferConsole::hide_cursor();
45 m_x = x;
46 m_y = y;
47 GenericFramebufferConsole::show_cursor();
48 m_dirty = true;
49}
50
51void Console::hide_cursor()
52{
53 GenericFramebufferConsole::hide_cursor();
54 m_dirty = true;
55}
56
57void Console::show_cursor()
58{
59 GenericFramebufferConsole::show_cursor();
60 m_dirty = true;
61}
62
63void Console::flush(size_t, size_t, size_t, size_t)
64{
65 m_dirty = true;
66}
67
68void Console::enqueue_refresh_timer()
69{
70 NonnullLockRefPtr<Timer> refresh_timer = adopt_lock_ref(*new Timer());
71 refresh_timer->setup(CLOCK_MONOTONIC, refresh_interval, [this]() {
72 if (m_enabled.load() && m_dirty) {
73 MUST(g_io_work->try_queue([this]() {
74 {
75 MutexLocker locker(m_parent_display_connector->m_flushing_lock);
76 MUST(m_parent_display_connector->flush_first_surface());
77 }
78 m_dirty = false;
79 }));
80 }
81 enqueue_refresh_timer();
82 });
83 TimerQueue::the().add_timer(move(refresh_timer));
84}
85
86void Console::enable()
87{
88 // FIXME: Do we need some locking here to ensure the resolution doesn't change
89 // while we enable the console?
90 auto current_resolution = m_parent_display_connector->current_mode_setting();
91 m_width = current_resolution.horizontal_active;
92 m_height = current_resolution.vertical_active;
93 m_pitch = current_resolution.horizontal_stride;
94 GenericFramebufferConsole::enable();
95 m_dirty = true;
96}
97
98u8* Console::framebuffer_data()
99{
100 return m_parent_display_connector->framebuffer_data();
101}
102
103}