Kernel: Put VirtIOGPU related types into a namespace

This commit is contained in:
Sahan Fernando 2021-07-07 23:51:33 +10:00 committed by Ali Mohammad Pur
parent 215f383b12
commit 1c77f80676
Notes: sideshowbarker 2024-07-18 08:49:28 +09:00
12 changed files with 326 additions and 300 deletions

View file

@ -71,10 +71,10 @@ set(KERNEL_SOURCES
Graphics/FramebufferDevice.cpp
Graphics/GraphicsManagement.cpp
Graphics/Intel/NativeGraphicsAdapter.cpp
Graphics/VirtIOGPU/VirtIOFrameBufferDevice.cpp
Graphics/VirtIOGPU/VirtIOGPUConsole.cpp
Graphics/VirtIOGPU/FrameBufferDevice.cpp
Graphics/VirtIOGPU/Console.cpp
Graphics/VirtIOGPU/VirtIOGPU.cpp
Graphics/VirtIOGPU/VirtIOGraphicsAdapter.cpp
Graphics/VirtIOGPU/GraphicsAdapter.cpp
Graphics/VGACompatibleAdapter.cpp
Storage/Partition/DiskPartition.cpp
Storage/Partition/DiskPartitionMetadata.cpp

View file

@ -11,7 +11,7 @@
#include <Kernel/Graphics/GraphicsManagement.h>
#include <Kernel/Graphics/Intel/NativeGraphicsAdapter.h>
#include <Kernel/Graphics/VGACompatibleAdapter.h>
#include <Kernel/Graphics/VirtIOGPU/VirtIOGraphicsAdapter.h>
#include <Kernel/Graphics/VirtIOGPU/GraphicsAdapter.h>
#include <Kernel/IO.h>
#include <Kernel/Multiboot.h>
#include <Kernel/Sections.h>
@ -91,7 +91,7 @@ UNMAP_AFTER_INIT bool GraphicsManagement::determine_and_initialize_graphics_devi
break;
case PCI::VendorID::VirtIO:
dmesgln("Graphics: Using VirtIO console");
adapter = Graphics::VirtIOGraphicsAdapter::initialize(address);
adapter = Graphics::VirtIOGPU::GraphicsAdapter::initialize(address);
break;
default:
if (!is_vga_compatible_pci_device(address))

View file

@ -14,7 +14,7 @@
#include <Kernel/Graphics/Console/Console.h>
#include <Kernel/Graphics/GraphicsDevice.h>
#include <Kernel/Graphics/VGACompatibleAdapter.h>
#include <Kernel/Graphics/VirtIOGPU/VirtIOGraphicsAdapter.h>
#include <Kernel/Graphics/VirtIOGPU/GraphicsAdapter.h>
#include <Kernel/VM/Region.h>
namespace Kernel {
@ -26,7 +26,7 @@ class GraphicsManagement {
friend class BochsGraphicsAdapter;
friend class IntelNativeGraphicsAdapter;
friend class VGACompatibleAdapter;
friend class Graphics::VirtIOGraphicsAdapter;
friend class Graphics::VirtIOGPU::GraphicsAdapter;
AK_MAKE_ETERNAL
public:

View file

@ -4,11 +4,11 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <Kernel/Graphics/VirtIOGPU/VirtIOFrameBufferDevice.h>
#include <Kernel/Graphics/VirtIOGPU/VirtIOGPUConsole.h>
#include <Kernel/Graphics/VirtIOGPU/Console.h>
#include <Kernel/Graphics/VirtIOGPU/FrameBufferDevice.h>
#include <Kernel/WorkQueue.h>
namespace Kernel::Graphics {
namespace Kernel::Graphics::VirtIOGPU {
constexpr static AK::Time refresh_interval = AK::Time::from_milliseconds(16);
@ -30,36 +30,36 @@ void DirtyRect::union_rect(size_t x, size_t y, size_t width, size_t height)
}
}
NonnullRefPtr<VirtIOGPUConsole> VirtIOGPUConsole::initialize(RefPtr<VirtIOFrameBufferDevice> const& framebuffer_device)
NonnullRefPtr<Console> Console::initialize(RefPtr<FrameBufferDevice> const& framebuffer_device)
{
return adopt_ref(*new VirtIOGPUConsole(framebuffer_device));
return adopt_ref(*new Console(framebuffer_device));
}
VirtIOGPUConsole::VirtIOGPUConsole(RefPtr<VirtIOFrameBufferDevice> const& 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 VirtIOGPUConsole::set_resolution(size_t width, size_t height, size_t)
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 VirtIOGPUConsole::flush(size_t x, size_t y, size_t width, size_t height)
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 VirtIOGPUConsole::enqueue_refresh_timer()
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()) {
VirtIOGPURect dirty_rect {
Protocol::Rect dirty_rect {
.x = (u32)rect.x(),
.y = (u32)rect.y(),
.width = (u32)rect.width(),
@ -75,7 +75,7 @@ void VirtIOGPUConsole::enqueue_refresh_timer()
TimerQueue::the().add_timer(move(refresh_timer));
}
void VirtIOGPUConsole::enable()
void Console::enable()
{
GenericFramebufferConsole::enable();
m_width = m_framebuffer_device->width();
@ -84,7 +84,7 @@ void VirtIOGPUConsole::enable()
m_dirty_rect.union_rect(0, 0, m_width, m_height);
}
u8* VirtIOGPUConsole::framebuffer_data()
u8* Console::framebuffer_data()
{
return m_framebuffer_device->framebuffer_data();
}

View file

@ -10,7 +10,7 @@
#include <Kernel/Graphics/VirtIOGPU/VirtIOGPU.h>
#include <Kernel/TimerQueue.h>
namespace Kernel::Graphics {
namespace Kernel::Graphics::VirtIOGPU {
class DirtyRect {
public:
@ -30,9 +30,9 @@ private:
size_t m_y1 { 0 };
};
class VirtIOGPUConsole final : public GenericFramebufferConsole {
class Console final : public GenericFramebufferConsole {
public:
static NonnullRefPtr<VirtIOGPUConsole> initialize(RefPtr<VirtIOFrameBufferDevice> const&);
static NonnullRefPtr<Console> initialize(RefPtr<FrameBufferDevice> const&);
virtual void set_resolution(size_t width, size_t height, size_t pitch) override;
virtual void flush(size_t x, size_t y, size_t width, size_t height) override;
@ -42,8 +42,8 @@ private:
void enqueue_refresh_timer();
virtual u8* framebuffer_data() override;
VirtIOGPUConsole(RefPtr<VirtIOFrameBufferDevice> const&);
RefPtr<VirtIOFrameBufferDevice> m_framebuffer_device;
Console(RefPtr<FrameBufferDevice> const&);
RefPtr<FrameBufferDevice> m_framebuffer_device;
DirtyRect m_dirty_rect;
};

View file

@ -5,12 +5,12 @@
*/
#include <Kernel/Graphics/GraphicsManagement.h>
#include <Kernel/Graphics/VirtIOGPU/VirtIOFrameBufferDevice.h>
#include <Kernel/Graphics/VirtIOGPU/FrameBufferDevice.h>
#include <LibC/sys/ioctl_numbers.h>
namespace Kernel::Graphics {
namespace Kernel::Graphics::VirtIOGPU {
VirtIOFrameBufferDevice::VirtIOFrameBufferDevice(VirtIOGPU& virtio_gpu, VirtIOGPUScanoutID scanout)
FrameBufferDevice::FrameBufferDevice(GPU& virtio_gpu, ScanoutID scanout)
: BlockDevice(29, GraphicsManagement::the().allocate_minor_device_number())
, m_gpu(virtio_gpu)
, m_scanout(scanout)
@ -19,11 +19,11 @@ VirtIOFrameBufferDevice::VirtIOFrameBufferDevice(VirtIOGPU& virtio_gpu, VirtIOGP
create_framebuffer();
}
VirtIOFrameBufferDevice::~VirtIOFrameBufferDevice()
FrameBufferDevice::~FrameBufferDevice()
{
}
void VirtIOFrameBufferDevice::create_framebuffer()
void FrameBufferDevice::create_framebuffer()
{
// First delete any existing framebuffers to free the memory first
m_framebuffer = nullptr;
@ -48,7 +48,7 @@ void VirtIOFrameBufferDevice::create_framebuffer()
create_buffer(m_back_buffer, m_buffer_size, m_buffer_size);
}
void VirtIOFrameBufferDevice::create_buffer(Buffer& buffer, size_t framebuffer_offset, size_t framebuffer_size)
void FrameBufferDevice::create_buffer(Buffer& buffer, size_t framebuffer_offset, size_t framebuffer_size)
{
buffer.framebuffer_offset = framebuffer_offset;
buffer.framebuffer_data = m_framebuffer->vaddr().as_ptr() + framebuffer_offset;
@ -76,32 +76,32 @@ void VirtIOFrameBufferDevice::create_buffer(Buffer& buffer, size_t framebuffer_o
info.enabled = 1;
}
VirtIOGPURespDisplayInfo::VirtIOGPUDisplayOne const& VirtIOFrameBufferDevice::display_info() const
Protocol::DisplayInfoResponse::Display const& FrameBufferDevice::display_info() const
{
return m_gpu.display_info(m_scanout);
}
VirtIOGPURespDisplayInfo::VirtIOGPUDisplayOne& VirtIOFrameBufferDevice::display_info()
Protocol::DisplayInfoResponse::Display& FrameBufferDevice::display_info()
{
return m_gpu.display_info(m_scanout);
}
void VirtIOFrameBufferDevice::transfer_framebuffer_data_to_host(VirtIOGPURect const& rect, Buffer& buffer)
void FrameBufferDevice::transfer_framebuffer_data_to_host(Protocol::Rect const& rect, Buffer& buffer)
{
m_gpu.transfer_framebuffer_data_to_host(m_scanout, rect, buffer.resource_id);
}
void VirtIOFrameBufferDevice::flush_dirty_window(VirtIOGPURect const& dirty_rect, Buffer& buffer)
void FrameBufferDevice::flush_dirty_window(Protocol::Rect const& dirty_rect, Buffer& buffer)
{
m_gpu.flush_dirty_window(m_scanout, dirty_rect, buffer.resource_id);
}
void VirtIOFrameBufferDevice::flush_displayed_image(VirtIOGPURect const& dirty_rect, Buffer& buffer)
void FrameBufferDevice::flush_displayed_image(Protocol::Rect const& dirty_rect, Buffer& buffer)
{
m_gpu.flush_displayed_image(dirty_rect, buffer.resource_id);
}
bool VirtIOFrameBufferDevice::try_to_set_resolution(size_t width, size_t height)
bool FrameBufferDevice::try_to_set_resolution(size_t width, size_t height)
{
if (width > MAX_VIRTIOGPU_RESOLUTION_WIDTH || height > MAX_VIRTIOGPU_RESOLUTION_HEIGHT)
return false;
@ -120,7 +120,7 @@ bool VirtIOFrameBufferDevice::try_to_set_resolution(size_t width, size_t height)
return true;
}
void VirtIOFrameBufferDevice::set_buffer(int buffer_index)
void FrameBufferDevice::set_buffer(int buffer_index)
{
auto& buffer = buffer_index == 0 ? m_main_buffer : m_back_buffer;
MutexLocker locker(m_gpu.operation_lock());
@ -132,7 +132,7 @@ void VirtIOFrameBufferDevice::set_buffer(int buffer_index)
buffer.dirty_rect = {};
}
int VirtIOFrameBufferDevice::ioctl(FileDescription&, unsigned request, FlatPtr arg)
int FrameBufferDevice::ioctl(FileDescription&, unsigned request, FlatPtr arg)
{
REQUIRE_PROMISE(video);
switch (request) {
@ -188,7 +188,7 @@ int VirtIOFrameBufferDevice::ioctl(FileDescription&, unsigned request, FlatPtr a
FBRect user_dirty_rect;
if (!copy_from_user(&user_dirty_rect, &user_flush_rects.rects[i]))
return -EFAULT;
VirtIOGPURect dirty_rect {
Protocol::Rect dirty_rect {
.x = user_dirty_rect.x,
.y = user_dirty_rect.y,
.width = user_dirty_rect.width,
@ -231,7 +231,7 @@ int VirtIOFrameBufferDevice::ioctl(FileDescription&, unsigned request, FlatPtr a
};
}
KResultOr<Region*> VirtIOFrameBufferDevice::mmap(Process& process, FileDescription&, const Range& range, u64 offset, int prot, bool shared)
KResultOr<Region*> FrameBufferDevice::mmap(Process& process, FileDescription&, const Range& range, u64 offset, int prot, bool shared)
{
REQUIRE_PROMISE(video);
if (!shared)
@ -262,7 +262,7 @@ KResultOr<Region*> VirtIOFrameBufferDevice::mmap(Process& process, FileDescripti
return result;
}
void VirtIOFrameBufferDevice::deactivate_writes()
void FrameBufferDevice::deactivate_writes()
{
m_are_writes_active = false;
if (m_userspace_mmap_region) {
@ -276,7 +276,7 @@ void VirtIOFrameBufferDevice::deactivate_writes()
clear_to_black(buffer_from_index(0));
}
void VirtIOFrameBufferDevice::activate_writes()
void FrameBufferDevice::activate_writes()
{
m_are_writes_active = true;
auto last_set_buffer_index = m_last_set_buffer_index.load();
@ -288,7 +288,7 @@ void VirtIOFrameBufferDevice::activate_writes()
set_buffer(last_set_buffer_index);
}
void VirtIOFrameBufferDevice::clear_to_black(Buffer& buffer)
void FrameBufferDevice::clear_to_black(Buffer& buffer)
{
auto& info = display_info();
size_t width = info.rect.width;
@ -302,7 +302,7 @@ void VirtIOFrameBufferDevice::clear_to_black(Buffer& buffer)
}
}
void VirtIOFrameBufferDevice::draw_ntsc_test_pattern(Buffer& buffer)
void FrameBufferDevice::draw_ntsc_test_pattern(Buffer& buffer)
{
static constexpr u8 colors[12][4] = {
{ 0xff, 0xff, 0xff, 0xff }, // White
@ -359,7 +359,7 @@ void VirtIOFrameBufferDevice::draw_ntsc_test_pattern(Buffer& buffer)
dbgln_if(VIRTIO_DEBUG, "Finish drawing the pattern");
}
u8* VirtIOFrameBufferDevice::framebuffer_data()
u8* FrameBufferDevice::framebuffer_data()
{
return m_current_buffer->framebuffer_data;
}

View file

@ -11,20 +11,20 @@
#include <Kernel/VirtIO/VirtIO.h>
#include <Kernel/VirtIO/VirtIOQueue.h>
namespace Kernel::Graphics {
namespace Kernel::Graphics::VirtIOGPU {
class VirtIOFrameBufferDevice final : public BlockDevice {
friend class VirtIOGPUConsole;
class FrameBufferDevice final : public BlockDevice {
friend class Console;
struct Buffer {
size_t framebuffer_offset { 0 };
u8* framebuffer_data { nullptr };
VirtIOGPUResourceID resource_id { 0 };
VirtIOGPURect dirty_rect {};
Protocol::Rect dirty_rect {};
ResourceID resource_id { 0 };
};
public:
VirtIOFrameBufferDevice(VirtIOGPU& virtio_gpu, VirtIOGPUScanoutID);
virtual ~VirtIOFrameBufferDevice() override;
FrameBufferDevice(VirtIOGPU::GPU& virtio_gpu, ScanoutID);
virtual ~FrameBufferDevice() override;
virtual void deactivate_writes();
virtual void activate_writes();
@ -42,9 +42,9 @@ public:
return page_round_up(sizeof(u32) * width * height);
}
void flush_dirty_window(VirtIOGPURect const&, Buffer&);
void transfer_framebuffer_data_to_host(VirtIOGPURect const&, Buffer&);
void flush_displayed_image(VirtIOGPURect const&, Buffer&);
void flush_dirty_window(Protocol::Rect const&, Buffer&);
void transfer_framebuffer_data_to_host(Protocol::Rect const&, Buffer&);
void flush_displayed_image(Protocol::Rect const&, Buffer&);
void draw_ntsc_test_pattern(Buffer&);
@ -53,8 +53,8 @@ public:
private:
virtual StringView class_name() const override { return "VirtIOFrameBuffer"; }
VirtIOGPURespDisplayInfo::VirtIOGPUDisplayOne const& display_info() const;
VirtIOGPURespDisplayInfo::VirtIOGPUDisplayOne& display_info();
Protocol::DisplayInfoResponse::Display const& display_info() const;
Protocol::DisplayInfoResponse::Display& display_info();
void create_framebuffer();
void create_buffer(Buffer&, size_t, size_t);
@ -82,8 +82,8 @@ private:
}
Buffer& current_buffer() const { return *m_current_buffer; }
VirtIOGPU& m_gpu;
const VirtIOGPUScanoutID m_scanout;
GPU& m_gpu;
const ScanoutID m_scanout;
Buffer* m_current_buffer { nullptr };
Atomic<int, AK::memory_order_relaxed> m_last_set_buffer_index { 0 };
Buffer m_main_buffer;

View file

@ -8,25 +8,25 @@
#include <Kernel/Graphics/Console/GenericFramebufferConsole.h>
#include <Kernel/Graphics/GraphicsManagement.h>
#include <Kernel/Graphics/VirtIOGPU/VirtIOGPU.h>
#include <Kernel/Graphics/VirtIOGPU/VirtIOGraphicsAdapter.h>
#include <Kernel/Graphics/VirtIOGPU/GraphicsAdapter.h>
namespace Kernel::Graphics {
namespace Kernel::Graphics::VirtIOGPU {
NonnullRefPtr<VirtIOGraphicsAdapter> VirtIOGraphicsAdapter::initialize(PCI::Address base_address)
NonnullRefPtr<GraphicsAdapter> GraphicsAdapter::initialize(PCI::Address base_address)
{
VERIFY(PCI::get_id(base_address).vendor_id == PCI::VendorID::VirtIO);
return adopt_ref(*new VirtIOGraphicsAdapter(base_address));
return adopt_ref(*new GraphicsAdapter(base_address));
}
VirtIOGraphicsAdapter::VirtIOGraphicsAdapter(PCI::Address base_address)
GraphicsAdapter::GraphicsAdapter(PCI::Address base_address)
: PCI::DeviceController(base_address)
{
m_gpu_device = adopt_ref(*new VirtIOGPU(base_address)).leak_ref();
m_gpu_device = adopt_ref(*new GPU(base_address)).leak_ref();
}
void VirtIOGraphicsAdapter::initialize_framebuffer_devices()
void GraphicsAdapter::initialize_framebuffer_devices()
{
dbgln_if(VIRTIO_DEBUG, "VirtIOGPU: Initializing framebuffer devices");
dbgln_if(VIRTIO_DEBUG, "GPU: Initializing framebuffer devices");
VERIFY(!m_created_framebuffer_devices);
m_gpu_device->create_framebuffer_devices();
m_created_framebuffer_devices = true;
@ -35,9 +35,9 @@ void VirtIOGraphicsAdapter::initialize_framebuffer_devices()
GraphicsManagement::the().m_console = m_gpu_device->default_console();
}
void VirtIOGraphicsAdapter::enable_consoles()
void GraphicsAdapter::enable_consoles()
{
dbgln_if(VIRTIO_DEBUG, "VirtIOGPU: Enabling consoles");
dbgln_if(VIRTIO_DEBUG, "GPU: Enabling consoles");
m_gpu_device->for_each_framebuffer([&](auto& framebuffer, auto& console) {
framebuffer.deactivate_writes();
console.enable();
@ -45,9 +45,9 @@ void VirtIOGraphicsAdapter::enable_consoles()
});
}
void VirtIOGraphicsAdapter::disable_consoles()
void GraphicsAdapter::disable_consoles()
{
dbgln_if(VIRTIO_DEBUG, "VirtIOGPU: Disabling consoles");
dbgln_if(VIRTIO_DEBUG, "GPU: Disabling consoles");
m_gpu_device->for_each_framebuffer([&](auto& framebuffer, auto& console) {
console.disable();
framebuffer.activate_writes();

View file

@ -6,24 +6,24 @@
#pragma once
#include <Kernel/Graphics/VirtIOGPU/VirtIOFrameBufferDevice.h>
#include <Kernel/Graphics/VirtIOGPU/Console.h>
#include <Kernel/Graphics/VirtIOGPU/FrameBufferDevice.h>
#include <Kernel/Graphics/VirtIOGPU/VirtIOGPU.h>
#include <Kernel/Graphics/VirtIOGPU/VirtIOGPUConsole.h>
namespace Kernel::Graphics {
namespace Kernel::Graphics::VirtIOGPU {
class VirtIOGraphicsAdapter final
class GraphicsAdapter final
: public GraphicsDevice
, public PCI::DeviceController {
AK_MAKE_ETERNAL
public:
static NonnullRefPtr<VirtIOGraphicsAdapter> initialize(PCI::Address);
static NonnullRefPtr<GraphicsAdapter> initialize(PCI::Address);
virtual bool framebuffer_devices_initialized() const override { return m_created_framebuffer_devices; }
private:
explicit VirtIOGraphicsAdapter(PCI::Address base_address);
explicit GraphicsAdapter(PCI::Address base_address);
virtual void initialize_framebuffer_devices() override;
virtual Type type() const override { return Type::Raw; }
@ -37,7 +37,7 @@ private:
virtual bool try_to_set_resolution(size_t, size_t, size_t) override { return false; }
virtual bool set_y_offset(size_t, size_t) override { return false; }
RefPtr<VirtIOGPU> m_gpu_device;
RefPtr<GPU> m_gpu_device;
bool m_created_framebuffer_devices { false };
};

View file

@ -0,0 +1,153 @@
/*
* Copyright (c) 2021, Sahan Fernando <sahan.h.fernando@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#define VIRTIO_GPU_MAX_SCANOUTS 16
namespace Kernel::Graphics::VirtIOGPU::Protocol {
// Specification equivalent: enum virtio_gpu_ctrl_type
enum class CommandType : u32 {
/* 2d commands */
VIRTIO_GPU_CMD_GET_DISPLAY_INFO = 0x0100,
VIRTIO_GPU_CMD_RESOURCE_CREATE_2D,
VIRTIO_GPU_CMD_RESOURCE_UNREF,
VIRTIO_GPU_CMD_SET_SCANOUT,
VIRTIO_GPU_CMD_RESOURCE_FLUSH,
VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D,
VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING,
VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING,
VIRTIO_GPU_CMD_GET_CAPSET_INFO,
VIRTIO_GPU_CMD_GET_CAPSET,
VIRTIO_GPU_CMD_GET_EDID,
/* cursor commands */
VIRTIO_GPU_CMD_UPDATE_CURSOR = 0x0300,
VIRTIO_GPU_CMD_MOVE_CURSOR,
/* success responses */
VIRTIO_GPU_RESP_OK_NODATA = 0x1100,
VIRTIO_GPU_RESP_OK_DISPLAY_INFO,
VIRTIO_GPU_RESP_OK_CAPSET_INFO,
VIRTIO_GPU_RESP_OK_CAPSET,
VIRTIO_GPU_RESP_OK_EDID,
/* error responses */
VIRTIO_GPU_RESP_ERR_UNSPEC = 0x1200,
VIRTIO_GPU_RESP_ERR_OUT_OF_MEMORY,
VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID,
VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID,
VIRTIO_GPU_RESP_ERR_INVALID_CONTEXT_ID,
VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER,
};
// Specification equivalent: struct virtio_gpu_ctrl_hdr
struct ControlHeader {
u32 type;
u32 flags;
u64 fence_id;
u32 context_id;
u32 padding;
};
// Specification equivalent: struct virtio_gpu_rect
struct Rect {
u32 x;
u32 y;
u32 width;
u32 height;
};
// Specification equivalent: struct virtio_gpu_resp_display_info
struct DisplayInfoResponse {
ControlHeader header;
// Specification equivalent: struct virtio_gpu_display_one
struct Display {
Rect rect;
u32 enabled;
u32 flags;
} scanout_modes[VIRTIO_GPU_MAX_SCANOUTS];
};
// Specification equivalent: enum virtio_gpu_formats
enum class TextureFormat : u32 {
VIRTIO_GPU_FORMAT_B8G8R8A8_UNORM = 1,
VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM = 2,
VIRTIO_GPU_FORMAT_A8R8G8B8_UNORM = 3,
VIRTIO_GPU_FORMAT_X8R8G8B8_UNORM = 4,
VIRTIO_GPU_FORMAT_R8G8B8A8_UNORM = 67,
VIRTIO_GPU_FORMAT_X8B8G8R8_UNORM = 68,
VIRTIO_GPU_FORMAT_A8B8G8R8_UNORM = 121,
VIRTIO_GPU_FORMAT_R8G8B8X8_UNORM = 134,
};
// Specification equivalent: struct virtio_gpu_resource_create_2d
struct ResourceCreate2D {
ControlHeader header;
u32 resource_id;
u32 format;
u32 width;
u32 height;
};
// Specification equivalent: struct virtio_gpu_resource_unref
struct ResourceUnref {
ControlHeader header;
u32 resource_id;
u32 padding;
};
// Specification equivalent: struct virtio_gpu_set_scanout
struct SetScanOut {
ControlHeader header;
Rect rect;
u32 scanout_id;
u32 resource_id;
};
// Specification equivalent: struct virtio_gpu_mem_entry
struct MemoryEntry {
u64 address;
u32 length;
u32 padding;
};
// Specification equivalent: struct virtio_gpu_resource_attach_backing
struct ResourceAttachBacking {
ControlHeader header;
u32 resource_id;
u32 num_entries;
MemoryEntry entries[];
};
// Specification equivalent: struct virtio_gpu_resource_detach_backing
struct ResourceDetachBacking {
ControlHeader header;
u32 resource_id;
u32 padding;
};
// Specification equivalent: struct virtio_gpu_transfer_to_host_2d
struct TransferToHost2D {
ControlHeader header;
Rect rect;
u64 offset;
u32 resource_id;
u32 padding;
};
// Specification equivalent: struct virtio_gpu_resource_flush
struct ResourceFlush {
ControlHeader header;
Rect rect;
u32 resource_id;
u32 padding;
};
}

View file

@ -4,18 +4,18 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <Kernel/Graphics/VirtIOGPU/VirtIOFrameBufferDevice.h>
#include <Kernel/Graphics/VirtIOGPU/FrameBufferDevice.h>
#include <Kernel/Graphics/VirtIOGPU/VirtIOGPU.h>
#include <Kernel/Graphics/VirtIOGPU/VirtIOGPUConsole.h>
#include <Kernel/Graphics/VirtIOGPU/Console.h>
#define DEVICE_EVENTS_READ 0x0
#define DEVICE_EVENTS_CLEAR 0x4
#define DEVICE_NUM_SCANOUTS 0x8
namespace Kernel::Graphics {
namespace Kernel::Graphics::VirtIOGPU {
VirtIOGPU::VirtIOGPU(PCI::Address address)
: VirtIODevice(address, "VirtIOGPU")
GPU::GPU(PCI::Address address)
: VirtIODevice(address, "GPU")
, m_scratch_space(MM.allocate_contiguous_kernel_region(32 * PAGE_SIZE, "VirtGPU Scratch Space", Region::Access::Read | Region::Access::Write))
{
VERIFY(!!m_scratch_space);
@ -24,16 +24,16 @@ VirtIOGPU::VirtIOGPU(PCI::Address address)
bool success = negotiate_features([&](u64 supported_features) {
u64 negotiated = 0;
if (is_feature_set(supported_features, VIRTIO_GPU_F_VIRGL))
dbgln_if(VIRTIO_DEBUG, "VirtIOGPU: VIRGL is not yet supported!");
dbgln_if(VIRTIO_DEBUG, "GPU: VIRGL is not yet supported!");
if (is_feature_set(supported_features, VIRTIO_GPU_F_EDID))
dbgln_if(VIRTIO_DEBUG, "VirtIOGPU: EDID is not yet supported!");
dbgln_if(VIRTIO_DEBUG, "GPU: EDID is not yet supported!");
return negotiated;
});
if (success) {
read_config_atomic([&]() {
m_num_scanouts = config_read32(*cfg, DEVICE_NUM_SCANOUTS);
});
dbgln_if(VIRTIO_DEBUG, "VirtIOGPU: num_scanouts: {}", m_num_scanouts);
dbgln_if(VIRTIO_DEBUG, "GPU: num_scanouts: {}", m_num_scanouts);
success = setup_queues(2); // CONTROLQ + CURSORQ
}
VERIFY(success);
@ -46,27 +46,27 @@ VirtIOGPU::VirtIOGPU(PCI::Address address)
}
}
VirtIOGPU::~VirtIOGPU()
GPU::~GPU()
{
}
void VirtIOGPU::create_framebuffer_devices()
void GPU::create_framebuffer_devices()
{
for (size_t i = 0; i < min(m_num_scanouts, VIRTIO_GPU_MAX_SCANOUTS); i++) {
auto& scanout = m_scanouts[i];
scanout.framebuffer = adopt_ref(*new VirtIOFrameBufferDevice(*this, i));
scanout.console = Kernel::Graphics::VirtIOGPUConsole::initialize(scanout.framebuffer);
scanout.framebuffer = adopt_ref(*new VirtIOGPU::FrameBufferDevice(*this, i));
scanout.console = Kernel::Graphics::VirtIOGPU::Console::initialize(scanout.framebuffer);
}
}
bool VirtIOGPU::handle_device_config_change()
bool GPU::handle_device_config_change()
{
return false;
}
void VirtIOGPU::handle_queue_update(u16 queue_index)
void GPU::handle_queue_update(u16 queue_index)
{
dbgln_if(VIRTIO_DEBUG, "VirtIOGPU: Handle queue update");
dbgln_if(VIRTIO_DEBUG, "GPU: Handle queue update");
VERIFY(queue_index == CONTROLQ);
auto& queue = get_queue(CONTROLQ);
@ -75,23 +75,23 @@ void VirtIOGPU::handle_queue_update(u16 queue_index)
m_outstanding_request.wake_all();
}
u32 VirtIOGPU::get_pending_events()
u32 GPU::get_pending_events()
{
return config_read32(*m_device_configuration, DEVICE_EVENTS_READ);
}
void VirtIOGPU::clear_pending_events(u32 event_bitmask)
void GPU::clear_pending_events(u32 event_bitmask)
{
config_write32(*m_device_configuration, DEVICE_EVENTS_CLEAR, event_bitmask);
}
void VirtIOGPU::query_display_information()
void GPU::query_display_information()
{
VERIFY(m_operation_lock.is_locked());
auto& request = *reinterpret_cast<VirtIOGPUCtrlHeader*>(m_scratch_space->vaddr().as_ptr());
auto& response = *reinterpret_cast<VirtIOGPURespDisplayInfo*>((m_scratch_space->vaddr().offset(sizeof(request)).as_ptr()));
auto& request = *reinterpret_cast<Protocol::ControlHeader*>(m_scratch_space->vaddr().as_ptr());
auto& response = *reinterpret_cast<Protocol::DisplayInfoResponse*>((m_scratch_space->vaddr().offset(sizeof(request)).as_ptr()));
populate_virtio_gpu_request_header(request, VirtIOGPUCtrlType::VIRTIO_GPU_CMD_GET_DISPLAY_INFO, VIRTIO_GPU_FLAG_FENCE);
populate_virtio_gpu_request_header(request, Protocol::CommandType::VIRTIO_GPU_CMD_GET_DISPLAY_INFO, VIRTIO_GPU_FLAG_FENCE);
synchronous_virtio_gpu_command(start_of_scratch_space(), sizeof(request), sizeof(response));
@ -105,28 +105,28 @@ void VirtIOGPU::query_display_information()
VERIFY(m_default_scanout.has_value());
}
VirtIOGPUResourceID VirtIOGPU::create_2d_resource(VirtIOGPURect rect)
ResourceID GPU::create_2d_resource(Protocol::Rect rect)
{
VERIFY(m_operation_lock.is_locked());
auto& request = *reinterpret_cast<VirtIOGPUResourceCreate2D*>(m_scratch_space->vaddr().as_ptr());
auto& response = *reinterpret_cast<VirtIOGPUCtrlHeader*>((m_scratch_space->vaddr().offset(sizeof(request)).as_ptr()));
auto& request = *reinterpret_cast<Protocol::ResourceCreate2D*>(m_scratch_space->vaddr().as_ptr());
auto& response = *reinterpret_cast<Protocol::ControlHeader*>((m_scratch_space->vaddr().offset(sizeof(request)).as_ptr()));
populate_virtio_gpu_request_header(request.header, VirtIOGPUCtrlType::VIRTIO_GPU_CMD_RESOURCE_CREATE_2D, VIRTIO_GPU_FLAG_FENCE);
populate_virtio_gpu_request_header(request.header, Protocol::CommandType::VIRTIO_GPU_CMD_RESOURCE_CREATE_2D, VIRTIO_GPU_FLAG_FENCE);
auto resource_id = allocate_resource_id();
request.resource_id = resource_id.value();
request.width = rect.width;
request.height = rect.height;
request.format = static_cast<u32>(VirtIOGPUFormats::VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM);
request.format = static_cast<u32>(Protocol::TextureFormat::VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM);
synchronous_virtio_gpu_command(start_of_scratch_space(), sizeof(request), sizeof(response));
VERIFY(response.type == static_cast<u32>(VirtIOGPUCtrlType::VIRTIO_GPU_RESP_OK_NODATA));
dbgln_if(VIRTIO_DEBUG, "VirtIOGPU: Allocated 2d resource with id {}", resource_id.value());
VERIFY(response.type == static_cast<u32>(Protocol::CommandType::VIRTIO_GPU_RESP_OK_NODATA));
dbgln_if(VIRTIO_DEBUG, "GPU: Allocated 2d resource with id {}", resource_id.value());
return resource_id;
}
void VirtIOGPU::ensure_backing_storage(Region const& region, size_t buffer_offset, size_t buffer_length, VirtIOGPUResourceID resource_id)
void GPU::ensure_backing_storage(Region const& region, size_t buffer_offset, size_t buffer_length, ResourceID resource_id)
{
VERIFY(m_operation_lock.is_locked());
@ -136,11 +136,11 @@ void VirtIOGPU::ensure_backing_storage(Region const& region, size_t buffer_offse
size_t num_mem_regions = buffer_length / PAGE_SIZE;
// Send request
auto& request = *reinterpret_cast<VirtIOGPUResourceAttachBacking*>(m_scratch_space->vaddr().as_ptr());
const size_t header_block_size = sizeof(request) + num_mem_regions * sizeof(VirtIOGPUMemEntry);
auto& response = *reinterpret_cast<VirtIOGPUCtrlHeader*>((m_scratch_space->vaddr().offset(header_block_size).as_ptr()));
auto& request = *reinterpret_cast<Protocol::ResourceAttachBacking*>(m_scratch_space->vaddr().as_ptr());
const size_t header_block_size = sizeof(request) + num_mem_regions * sizeof(Protocol::MemoryEntry);
auto& response = *reinterpret_cast<Protocol::ControlHeader*>((m_scratch_space->vaddr().offset(header_block_size).as_ptr()));
populate_virtio_gpu_request_header(request.header, VirtIOGPUCtrlType::VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING, VIRTIO_GPU_FLAG_FENCE);
populate_virtio_gpu_request_header(request.header, Protocol::CommandType::VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING, VIRTIO_GPU_FLAG_FENCE);
request.resource_id = resource_id.value();
request.num_entries = num_mem_regions;
for (size_t i = 0; i < num_mem_regions; ++i) {
@ -150,74 +150,74 @@ void VirtIOGPU::ensure_backing_storage(Region const& region, size_t buffer_offse
synchronous_virtio_gpu_command(start_of_scratch_space(), header_block_size, sizeof(response));
VERIFY(response.type == static_cast<u32>(VirtIOGPUCtrlType::VIRTIO_GPU_RESP_OK_NODATA));
dbgln_if(VIRTIO_DEBUG, "VirtIOGPU: Allocated backing storage");
VERIFY(response.type == static_cast<u32>(Protocol::CommandType::VIRTIO_GPU_RESP_OK_NODATA));
dbgln_if(VIRTIO_DEBUG, "GPU: Allocated backing storage");
}
void VirtIOGPU::detach_backing_storage(VirtIOGPUResourceID resource_id)
void GPU::detach_backing_storage(ResourceID resource_id)
{
VERIFY(m_operation_lock.is_locked());
auto& request = *reinterpret_cast<VirtIOGPUResourceDetachBacking*>(m_scratch_space->vaddr().as_ptr());
auto& response = *reinterpret_cast<VirtIOGPUCtrlHeader*>((m_scratch_space->vaddr().offset(sizeof(request)).as_ptr()));
auto& request = *reinterpret_cast<Protocol::ResourceDetachBacking*>(m_scratch_space->vaddr().as_ptr());
auto& response = *reinterpret_cast<Protocol::ControlHeader*>((m_scratch_space->vaddr().offset(sizeof(request)).as_ptr()));
populate_virtio_gpu_request_header(request.header, VirtIOGPUCtrlType::VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING, VIRTIO_GPU_FLAG_FENCE);
populate_virtio_gpu_request_header(request.header, Protocol::CommandType::VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING, VIRTIO_GPU_FLAG_FENCE);
request.resource_id = resource_id.value();
synchronous_virtio_gpu_command(start_of_scratch_space(), sizeof(request), sizeof(response));
VERIFY(response.type == static_cast<u32>(VirtIOGPUCtrlType::VIRTIO_GPU_RESP_OK_NODATA));
dbgln_if(VIRTIO_DEBUG, "VirtIOGPU: Detached backing storage");
VERIFY(response.type == static_cast<u32>(Protocol::CommandType::VIRTIO_GPU_RESP_OK_NODATA));
dbgln_if(VIRTIO_DEBUG, "GPU: Detached backing storage");
}
void VirtIOGPU::set_scanout_resource(VirtIOGPUScanoutID scanout, VirtIOGPUResourceID resource_id, VirtIOGPURect rect)
void GPU::set_scanout_resource(ScanoutID scanout, ResourceID resource_id, Protocol::Rect rect)
{
VERIFY(m_operation_lock.is_locked());
auto& request = *reinterpret_cast<VirtIOGPUSetScanOut*>(m_scratch_space->vaddr().as_ptr());
auto& response = *reinterpret_cast<VirtIOGPUCtrlHeader*>((m_scratch_space->vaddr().offset(sizeof(request)).as_ptr()));
auto& request = *reinterpret_cast<Protocol::SetScanOut*>(m_scratch_space->vaddr().as_ptr());
auto& response = *reinterpret_cast<Protocol::ControlHeader*>((m_scratch_space->vaddr().offset(sizeof(request)).as_ptr()));
populate_virtio_gpu_request_header(request.header, VirtIOGPUCtrlType::VIRTIO_GPU_CMD_SET_SCANOUT, VIRTIO_GPU_FLAG_FENCE);
populate_virtio_gpu_request_header(request.header, Protocol::CommandType::VIRTIO_GPU_CMD_SET_SCANOUT, VIRTIO_GPU_FLAG_FENCE);
request.resource_id = resource_id.value();
request.scanout_id = scanout.value();
request.rect = rect;
synchronous_virtio_gpu_command(start_of_scratch_space(), sizeof(request), sizeof(response));
VERIFY(response.type == static_cast<u32>(VirtIOGPUCtrlType::VIRTIO_GPU_RESP_OK_NODATA));
dbgln_if(VIRTIO_DEBUG, "VirtIOGPU: Set backing scanout");
VERIFY(response.type == static_cast<u32>(Protocol::CommandType::VIRTIO_GPU_RESP_OK_NODATA));
dbgln_if(VIRTIO_DEBUG, "GPU: Set backing scanout");
}
void VirtIOGPU::transfer_framebuffer_data_to_host(VirtIOGPUScanoutID scanout, VirtIOGPURect const& dirty_rect, VirtIOGPUResourceID resource_id)
void GPU::transfer_framebuffer_data_to_host(ScanoutID scanout, Protocol::Rect const& dirty_rect, ResourceID resource_id)
{
VERIFY(m_operation_lock.is_locked());
auto& request = *reinterpret_cast<VirtIOGPUTransferToHost2D*>(m_scratch_space->vaddr().as_ptr());
auto& response = *reinterpret_cast<VirtIOGPUCtrlHeader*>((m_scratch_space->vaddr().offset(sizeof(request)).as_ptr()));
auto& request = *reinterpret_cast<Protocol::TransferToHost2D*>(m_scratch_space->vaddr().as_ptr());
auto& response = *reinterpret_cast<Protocol::ControlHeader*>((m_scratch_space->vaddr().offset(sizeof(request)).as_ptr()));
populate_virtio_gpu_request_header(request.header, VirtIOGPUCtrlType::VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D, VIRTIO_GPU_FLAG_FENCE);
populate_virtio_gpu_request_header(request.header, Protocol::CommandType::VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D, VIRTIO_GPU_FLAG_FENCE);
request.offset = (dirty_rect.x + (dirty_rect.y * m_scanouts[scanout.value()].display_info.rect.width)) * sizeof(u32);
request.resource_id = resource_id.value();
request.rect = dirty_rect;
synchronous_virtio_gpu_command(start_of_scratch_space(), sizeof(request), sizeof(response));
VERIFY(response.type == static_cast<u32>(VirtIOGPUCtrlType::VIRTIO_GPU_RESP_OK_NODATA));
VERIFY(response.type == static_cast<u32>(Protocol::CommandType::VIRTIO_GPU_RESP_OK_NODATA));
}
void VirtIOGPU::flush_displayed_image(VirtIOGPURect const& dirty_rect, VirtIOGPUResourceID resource_id)
void GPU::flush_displayed_image(Protocol::Rect const& dirty_rect, ResourceID resource_id)
{
VERIFY(m_operation_lock.is_locked());
auto& request = *reinterpret_cast<VirtIOGPUResourceFlush*>(m_scratch_space->vaddr().as_ptr());
auto& response = *reinterpret_cast<VirtIOGPUCtrlHeader*>((m_scratch_space->vaddr().offset(sizeof(request)).as_ptr()));
auto& request = *reinterpret_cast<Protocol::ResourceFlush*>(m_scratch_space->vaddr().as_ptr());
auto& response = *reinterpret_cast<Protocol::ControlHeader*>((m_scratch_space->vaddr().offset(sizeof(request)).as_ptr()));
populate_virtio_gpu_request_header(request.header, VirtIOGPUCtrlType::VIRTIO_GPU_CMD_RESOURCE_FLUSH, VIRTIO_GPU_FLAG_FENCE);
populate_virtio_gpu_request_header(request.header, Protocol::CommandType::VIRTIO_GPU_CMD_RESOURCE_FLUSH, VIRTIO_GPU_FLAG_FENCE);
request.resource_id = resource_id.value();
request.rect = dirty_rect;
synchronous_virtio_gpu_command(start_of_scratch_space(), sizeof(request), sizeof(response));
VERIFY(response.type == static_cast<u32>(VirtIOGPUCtrlType::VIRTIO_GPU_RESP_OK_NODATA));
VERIFY(response.type == static_cast<u32>(Protocol::CommandType::VIRTIO_GPU_RESP_OK_NODATA));
}
void VirtIOGPU::synchronous_virtio_gpu_command(PhysicalAddress buffer_start, size_t request_size, size_t response_size)
void GPU::synchronous_virtio_gpu_command(PhysicalAddress buffer_start, size_t request_size, size_t response_size)
{
VERIFY(m_operation_lock.is_locked());
VERIFY(m_outstanding_request.is_empty());
@ -233,7 +233,7 @@ void VirtIOGPU::synchronous_virtio_gpu_command(PhysicalAddress buffer_start, siz
m_outstanding_request.wait_forever();
}
void VirtIOGPU::populate_virtio_gpu_request_header(VirtIOGPUCtrlHeader& header, VirtIOGPUCtrlType ctrl_type, u32 flags)
void GPU::populate_virtio_gpu_request_header(Protocol::ControlHeader& header, Protocol::CommandType ctrl_type, u32 flags)
{
header.type = static_cast<u32>(ctrl_type);
header.flags = flags;
@ -242,32 +242,32 @@ void VirtIOGPU::populate_virtio_gpu_request_header(VirtIOGPUCtrlHeader& header,
header.padding = 0;
}
void VirtIOGPU::flush_dirty_window(VirtIOGPUScanoutID scanout, VirtIOGPURect const& dirty_rect, VirtIOGPUResourceID resource_id)
void GPU::flush_dirty_window(ScanoutID scanout, Protocol::Rect const& dirty_rect, ResourceID resource_id)
{
MutexLocker locker(m_operation_lock);
transfer_framebuffer_data_to_host(scanout, dirty_rect, resource_id);
flush_displayed_image(dirty_rect, resource_id);
}
VirtIOGPUResourceID VirtIOGPU::allocate_resource_id()
ResourceID GPU::allocate_resource_id()
{
VERIFY(m_operation_lock.is_locked());
m_resource_id_counter = m_resource_id_counter.value() + 1;
return m_resource_id_counter;
}
void VirtIOGPU::delete_resource(VirtIOGPUResourceID resource_id)
void GPU::delete_resource(ResourceID resource_id)
{
VERIFY(m_operation_lock.is_locked());
auto& request = *reinterpret_cast<VirtioGPUResourceUnref*>(m_scratch_space->vaddr().as_ptr());
auto& response = *reinterpret_cast<VirtIOGPUCtrlHeader*>((m_scratch_space->vaddr().offset(sizeof(request)).as_ptr()));
auto& request = *reinterpret_cast<Protocol::ResourceUnref*>(m_scratch_space->vaddr().as_ptr());
auto& response = *reinterpret_cast<Protocol::ControlHeader*>((m_scratch_space->vaddr().offset(sizeof(request)).as_ptr()));
populate_virtio_gpu_request_header(request.header, VirtIOGPUCtrlType::VIRTIO_GPU_CMD_RESOURCE_UNREF, VIRTIO_GPU_FLAG_FENCE);
populate_virtio_gpu_request_header(request.header, Protocol::CommandType::VIRTIO_GPU_CMD_RESOURCE_UNREF, VIRTIO_GPU_FLAG_FENCE);
request.resource_id = resource_id.value();
synchronous_virtio_gpu_command(start_of_scratch_space(), sizeof(request), sizeof(response));
VERIFY(response.type == static_cast<u32>(VirtIOGPUCtrlType::VIRTIO_GPU_RESP_OK_NODATA));
VERIFY(response.type == static_cast<u32>(Protocol::CommandType::VIRTIO_GPU_RESP_OK_NODATA));
}
}

View file

@ -8,6 +8,7 @@
#include <AK/DistinctNumeric.h>
#include <Kernel/Devices/BlockDevice.h>
#include <Kernel/Graphics/VirtIOGPU/Protocol.h>
#include <Kernel/VirtIO/VirtIO.h>
#include <Kernel/VirtIO/VirtIOQueue.h>
@ -16,165 +17,37 @@
#define VIRTIO_GPU_FLAG_FENCE (1 << 0)
#define VIRTIO_GPU_MAX_SCANOUTS 16
#define CONTROLQ 0
#define CURSORQ 1
#define MAX_VIRTIOGPU_RESOLUTION_WIDTH 3840
#define MAX_VIRTIOGPU_RESOLUTION_HEIGHT 2160
namespace Kernel::Graphics {
namespace Kernel::Graphics::VirtIOGPU {
class VirtIOGPUConsole;
class VirtIOFrameBufferDevice;
class Console;
class FrameBufferDevice;
TYPEDEF_DISTINCT_ORDERED_ID(u32, VirtIOGPUResourceID);
TYPEDEF_DISTINCT_ORDERED_ID(u32, VirtIOGPUScanoutID);
TYPEDEF_DISTINCT_ORDERED_ID(u32, ResourceID);
TYPEDEF_DISTINCT_ORDERED_ID(u32, ScanoutID);
enum class VirtIOGPUCtrlType : u32 {
/* 2d commands */
VIRTIO_GPU_CMD_GET_DISPLAY_INFO = 0x0100,
VIRTIO_GPU_CMD_RESOURCE_CREATE_2D,
VIRTIO_GPU_CMD_RESOURCE_UNREF,
VIRTIO_GPU_CMD_SET_SCANOUT,
VIRTIO_GPU_CMD_RESOURCE_FLUSH,
VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D,
VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING,
VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING,
VIRTIO_GPU_CMD_GET_CAPSET_INFO,
VIRTIO_GPU_CMD_GET_CAPSET,
VIRTIO_GPU_CMD_GET_EDID,
/* cursor commands */
VIRTIO_GPU_CMD_UPDATE_CURSOR = 0x0300,
VIRTIO_GPU_CMD_MOVE_CURSOR,
/* success responses */
VIRTIO_GPU_RESP_OK_NODATA = 0x1100,
VIRTIO_GPU_RESP_OK_DISPLAY_INFO,
VIRTIO_GPU_RESP_OK_CAPSET_INFO,
VIRTIO_GPU_RESP_OK_CAPSET,
VIRTIO_GPU_RESP_OK_EDID,
/* error responses */
VIRTIO_GPU_RESP_ERR_UNSPEC = 0x1200,
VIRTIO_GPU_RESP_ERR_OUT_OF_MEMORY,
VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID,
VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID,
VIRTIO_GPU_RESP_ERR_INVALID_CONTEXT_ID,
VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER,
};
struct VirtIOGPUCtrlHeader {
u32 type;
u32 flags;
u64 fence_id;
u32 context_id;
u32 padding;
};
struct VirtIOGPURect {
u32 x;
u32 y;
u32 width;
u32 height;
};
struct VirtIOGPURespDisplayInfo {
VirtIOGPUCtrlHeader header;
struct VirtIOGPUDisplayOne {
VirtIOGPURect rect;
u32 enabled;
u32 flags;
} scanout_modes[VIRTIO_GPU_MAX_SCANOUTS];
};
enum class VirtIOGPUFormats : u32 {
VIRTIO_GPU_FORMAT_B8G8R8A8_UNORM = 1,
VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM = 2,
VIRTIO_GPU_FORMAT_A8R8G8B8_UNORM = 3,
VIRTIO_GPU_FORMAT_X8R8G8B8_UNORM = 4,
VIRTIO_GPU_FORMAT_R8G8B8A8_UNORM = 67,
VIRTIO_GPU_FORMAT_X8B8G8R8_UNORM = 68,
VIRTIO_GPU_FORMAT_A8B8G8R8_UNORM = 121,
VIRTIO_GPU_FORMAT_R8G8B8X8_UNORM = 134,
};
struct VirtIOGPUResourceCreate2D {
VirtIOGPUCtrlHeader header;
u32 resource_id;
u32 format;
u32 width;
u32 height;
};
struct VirtioGPUResourceUnref {
VirtIOGPUCtrlHeader header;
u32 resource_id;
u32 padding;
};
struct VirtIOGPUSetScanOut {
VirtIOGPUCtrlHeader header;
VirtIOGPURect rect;
u32 scanout_id;
u32 resource_id;
};
struct VirtIOGPUMemEntry {
u64 address;
u32 length;
u32 padding;
};
struct VirtIOGPUResourceAttachBacking {
VirtIOGPUCtrlHeader header;
u32 resource_id;
u32 num_entries;
VirtIOGPUMemEntry entries[];
};
struct VirtIOGPUResourceDetachBacking {
VirtIOGPUCtrlHeader header;
u32 resource_id;
u32 padding;
};
struct VirtIOGPUTransferToHost2D {
VirtIOGPUCtrlHeader header;
VirtIOGPURect rect;
u64 offset;
u32 resource_id;
u32 padding;
};
struct VirtIOGPUResourceFlush {
VirtIOGPUCtrlHeader header;
VirtIOGPURect rect;
u32 resource_id;
u32 padding;
};
class VirtIOGPU final
class GPU final
: public VirtIODevice
, public RefCounted<VirtIOGPU> {
friend class VirtIOFrameBufferDevice;
, public RefCounted<GPU> {
friend class FrameBufferDevice;
public:
VirtIOGPU(PCI::Address);
virtual ~VirtIOGPU() override;
GPU(PCI::Address);
virtual ~GPU() override;
void flush_dirty_window(VirtIOGPUScanoutID, VirtIOGPURect const& dirty_rect, VirtIOGPUResourceID);
void flush_dirty_window(ScanoutID, Protocol::Rect const& dirty_rect, ResourceID);
auto& display_info(VirtIOGPUScanoutID scanout) const
auto& display_info(ScanoutID scanout) const
{
VERIFY(scanout.value() < VIRTIO_GPU_MAX_SCANOUTS);
return m_scanouts[scanout.value()].display_info;
}
auto& display_info(VirtIOGPUScanoutID scanout)
auto& display_info(ScanoutID scanout)
{
VERIFY(scanout.value() < VIRTIO_GPU_MAX_SCANOUTS);
return m_scanouts[scanout.value()].display_info;
@ -195,7 +68,7 @@ public:
return IterationDecision::Continue;
}
RefPtr<VirtIOGPUConsole> default_console()
RefPtr<Console> default_console()
{
if (m_default_scanout.has_value())
return m_scanouts[m_default_scanout.value().value()].console;
@ -211,32 +84,32 @@ private:
u32 get_pending_events();
void clear_pending_events(u32 event_bitmask);
VirtIOGPUResourceID allocate_resource_id();
ResourceID allocate_resource_id();
PhysicalAddress start_of_scratch_space() const { return m_scratch_space->physical_page(0)->paddr(); }
void synchronous_virtio_gpu_command(PhysicalAddress buffer_start, size_t request_size, size_t response_size);
void populate_virtio_gpu_request_header(VirtIOGPUCtrlHeader& header, VirtIOGPUCtrlType ctrl_type, u32 flags = 0);
void populate_virtio_gpu_request_header(Protocol::ControlHeader& header, Protocol::CommandType ctrl_type, u32 flags = 0);
void query_display_information();
VirtIOGPUResourceID create_2d_resource(VirtIOGPURect rect);
void delete_resource(VirtIOGPUResourceID resource_id);
void ensure_backing_storage(Region const&, size_t buffer_offset, size_t buffer_length, VirtIOGPUResourceID resource_id);
void detach_backing_storage(VirtIOGPUResourceID resource_id);
void set_scanout_resource(VirtIOGPUScanoutID scanout, VirtIOGPUResourceID resource_id, VirtIOGPURect rect);
void transfer_framebuffer_data_to_host(VirtIOGPUScanoutID scanout, VirtIOGPURect const& rect, VirtIOGPUResourceID resource_id);
void flush_displayed_image(VirtIOGPURect const& dirty_rect, VirtIOGPUResourceID resource_id);
ResourceID create_2d_resource(Protocol::Rect rect);
void delete_resource(ResourceID resource_id);
void ensure_backing_storage(Region const& region, size_t buffer_offset, size_t buffer_length, ResourceID resource_id);
void detach_backing_storage(ResourceID resource_id);
void set_scanout_resource(ScanoutID scanout, ResourceID resource_id, Protocol::Rect rect);
void transfer_framebuffer_data_to_host(ScanoutID scanout, Protocol::Rect const& rect, ResourceID resource_id);
void flush_displayed_image(Protocol::Rect const& dirty_rect, ResourceID resource_id);
struct Scanout {
RefPtr<VirtIOFrameBufferDevice> framebuffer;
RefPtr<VirtIOGPUConsole> console;
VirtIOGPURespDisplayInfo::VirtIOGPUDisplayOne display_info {};
RefPtr<FrameBufferDevice> framebuffer;
RefPtr<Console> console;
Protocol::DisplayInfoResponse::Display display_info {};
};
Optional<VirtIOGPUScanoutID> m_default_scanout;
Optional<ScanoutID> m_default_scanout;
size_t m_num_scanouts { 0 };
Scanout m_scanouts[VIRTIO_GPU_MAX_SCANOUTS];
Configuration const* m_device_configuration { nullptr };
VirtIOGPUResourceID m_resource_id_counter { 0 };
ResourceID m_resource_id_counter { 0 };
// Synchronous commands
WaitQueue m_outstanding_request;