summaryrefslogtreecommitdiff
path: root/Kernel/Graphics/VirtIOGPU/Console.cpp
blob: 32e9a82023444bcaee3a77d25409e0599e62224d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
/*
 * Copyright (c) 2021, Sahan Fernando <sahan.h.fernando@gmail.com>
 *
 * SPDX-License-Identifier: BSD-2-Clause
 */

#include <Kernel/Graphics/VirtIOGPU/Console.h>
#include <Kernel/Graphics/VirtIOGPU/FrameBufferDevice.h>
#include <Kernel/WorkQueue.h>

namespace Kernel::Graphics::VirtIOGPU {

constexpr static AK::Time refresh_interval = AK::Time::from_milliseconds(16);

void DirtyRect::union_rect(size_t x, size_t y, size_t width, size_t height)
{
    if (width == 0 || height == 0)
        return;
    if (m_is_dirty) {
        m_x0 = min(x, m_x0);
        m_y0 = min(y, m_y0);
        m_x1 = max(x + width, m_x1);
        m_y1 = max(y + height, m_y1);
    } else {
        m_is_dirty = true;
        m_x0 = x;
        m_y0 = y;
        m_x1 = x + width;
        m_y1 = y + height;
    }
}

NonnullRefPtr<Console> Console::initialize(RefPtr<FrameBufferDevice> const& framebuffer_device)
{
    return adopt_ref(*new Console(framebuffer_device));
}

Console::Console(RefPtr<FrameBufferDevice> const& framebuffer_device)
    : GenericFramebufferConsole(framebuffer_device->width(), framebuffer_device->height(), framebuffer_device->pitch())
    , m_framebuffer_device(framebuffer_device)
{
    enqueue_refresh_timer();
}

void Console::set_resolution(size_t width, size_t height, size_t)
{
    auto did_set_resolution = m_framebuffer_device->try_to_set_resolution(width, height);
    VERIFY(did_set_resolution);
}

void Console::flush(size_t x, size_t y, size_t width, size_t height)
{
    m_dirty_rect.union_rect(x, y, width, height);
}

void Console::enqueue_refresh_timer()
{
    NonnullRefPtr<Timer> refresh_timer = adopt_ref(*new Timer());
    refresh_timer->setup(CLOCK_MONOTONIC, refresh_interval, [this]() {
        auto rect = m_dirty_rect;
        if (rect.is_dirty()) {
            Protocol::Rect dirty_rect {
                .x = (u32)rect.x(),
                .y = (u32)rect.y(),
                .width = (u32)rect.width(),
                .height = (u32)rect.height(),
            };
            g_io_work->queue([this, dirty_rect]() {
                m_framebuffer_device->flush_dirty_window(dirty_rect, m_framebuffer_device->current_buffer());
                m_dirty_rect.clear();
            });
        }
        enqueue_refresh_timer();
    });
    TimerQueue::the().add_timer(move(refresh_timer));
}

void Console::enable()
{
    GenericFramebufferConsole::enable();
    m_width = m_framebuffer_device->width();
    m_height = m_framebuffer_device->height();
    m_pitch = m_framebuffer_device->pitch();
    m_dirty_rect.union_rect(0, 0, m_width, m_height);
}

u8* Console::framebuffer_data()
{
    return m_framebuffer_device->framebuffer_data();
}

}