1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-26 02:27:43 +00:00

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
12 changed files with 326 additions and 300 deletions

View file

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

View file

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

View file

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

View file

@ -4,11 +4,11 @@
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
*/ */
#include <Kernel/Graphics/VirtIOGPU/VirtIOFrameBufferDevice.h> #include <Kernel/Graphics/VirtIOGPU/Console.h>
#include <Kernel/Graphics/VirtIOGPU/VirtIOGPUConsole.h> #include <Kernel/Graphics/VirtIOGPU/FrameBufferDevice.h>
#include <Kernel/WorkQueue.h> #include <Kernel/WorkQueue.h>
namespace Kernel::Graphics { namespace Kernel::Graphics::VirtIOGPU {
constexpr static AK::Time refresh_interval = AK::Time::from_milliseconds(16); 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()) : GenericFramebufferConsole(framebuffer_device->width(), framebuffer_device->height(), framebuffer_device->pitch())
, m_framebuffer_device(framebuffer_device) , m_framebuffer_device(framebuffer_device)
{ {
enqueue_refresh_timer(); 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); auto did_set_resolution = m_framebuffer_device->try_to_set_resolution(width, height);
VERIFY(did_set_resolution); 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); 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()); NonnullRefPtr<Timer> refresh_timer = adopt_ref(*new Timer());
refresh_timer->setup(CLOCK_MONOTONIC, refresh_interval, [this]() { refresh_timer->setup(CLOCK_MONOTONIC, refresh_interval, [this]() {
auto rect = m_dirty_rect; auto rect = m_dirty_rect;
if (rect.is_dirty()) { if (rect.is_dirty()) {
VirtIOGPURect dirty_rect { Protocol::Rect dirty_rect {
.x = (u32)rect.x(), .x = (u32)rect.x(),
.y = (u32)rect.y(), .y = (u32)rect.y(),
.width = (u32)rect.width(), .width = (u32)rect.width(),
@ -75,7 +75,7 @@ void VirtIOGPUConsole::enqueue_refresh_timer()
TimerQueue::the().add_timer(move(refresh_timer)); TimerQueue::the().add_timer(move(refresh_timer));
} }
void VirtIOGPUConsole::enable() void Console::enable()
{ {
GenericFramebufferConsole::enable(); GenericFramebufferConsole::enable();
m_width = m_framebuffer_device->width(); m_width = m_framebuffer_device->width();
@ -84,7 +84,7 @@ void VirtIOGPUConsole::enable()
m_dirty_rect.union_rect(0, 0, m_width, m_height); 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(); return m_framebuffer_device->framebuffer_data();
} }

View file

@ -10,7 +10,7 @@
#include <Kernel/Graphics/VirtIOGPU/VirtIOGPU.h> #include <Kernel/Graphics/VirtIOGPU/VirtIOGPU.h>
#include <Kernel/TimerQueue.h> #include <Kernel/TimerQueue.h>
namespace Kernel::Graphics { namespace Kernel::Graphics::VirtIOGPU {
class DirtyRect { class DirtyRect {
public: public:
@ -30,9 +30,9 @@ private:
size_t m_y1 { 0 }; size_t m_y1 { 0 };
}; };
class VirtIOGPUConsole final : public GenericFramebufferConsole { class Console final : public GenericFramebufferConsole {
public: 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 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; 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(); void enqueue_refresh_timer();
virtual u8* framebuffer_data() override; virtual u8* framebuffer_data() override;
VirtIOGPUConsole(RefPtr<VirtIOFrameBufferDevice> const&); Console(RefPtr<FrameBufferDevice> const&);
RefPtr<VirtIOFrameBufferDevice> m_framebuffer_device; RefPtr<FrameBufferDevice> m_framebuffer_device;
DirtyRect m_dirty_rect; DirtyRect m_dirty_rect;
}; };

View file

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

View file

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

View file

@ -8,25 +8,25 @@
#include <Kernel/Graphics/Console/GenericFramebufferConsole.h> #include <Kernel/Graphics/Console/GenericFramebufferConsole.h>
#include <Kernel/Graphics/GraphicsManagement.h> #include <Kernel/Graphics/GraphicsManagement.h>
#include <Kernel/Graphics/VirtIOGPU/VirtIOGPU.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); 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) : 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); VERIFY(!m_created_framebuffer_devices);
m_gpu_device->create_framebuffer_devices(); m_gpu_device->create_framebuffer_devices();
m_created_framebuffer_devices = true; m_created_framebuffer_devices = true;
@ -35,9 +35,9 @@ void VirtIOGraphicsAdapter::initialize_framebuffer_devices()
GraphicsManagement::the().m_console = m_gpu_device->default_console(); 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) { m_gpu_device->for_each_framebuffer([&](auto& framebuffer, auto& console) {
framebuffer.deactivate_writes(); framebuffer.deactivate_writes();
console.enable(); 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) { m_gpu_device->for_each_framebuffer([&](auto& framebuffer, auto& console) {
console.disable(); console.disable();
framebuffer.activate_writes(); framebuffer.activate_writes();

View file

@ -6,24 +6,24 @@
#pragma once #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/VirtIOGPU.h>
#include <Kernel/Graphics/VirtIOGPU/VirtIOGPUConsole.h>
namespace Kernel::Graphics { namespace Kernel::Graphics::VirtIOGPU {
class VirtIOGraphicsAdapter final class GraphicsAdapter final
: public GraphicsDevice : public GraphicsDevice
, public PCI::DeviceController { , public PCI::DeviceController {
AK_MAKE_ETERNAL AK_MAKE_ETERNAL
public: 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; } virtual bool framebuffer_devices_initialized() const override { return m_created_framebuffer_devices; }
private: private:
explicit VirtIOGraphicsAdapter(PCI::Address base_address); explicit GraphicsAdapter(PCI::Address base_address);
virtual void initialize_framebuffer_devices() override; virtual void initialize_framebuffer_devices() override;
virtual Type type() const override { return Type::Raw; } 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 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; } 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 }; 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 * 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/VirtIOGPU.h>
#include <Kernel/Graphics/VirtIOGPU/VirtIOGPUConsole.h> #include <Kernel/Graphics/VirtIOGPU/Console.h>
#define DEVICE_EVENTS_READ 0x0 #define DEVICE_EVENTS_READ 0x0
#define DEVICE_EVENTS_CLEAR 0x4 #define DEVICE_EVENTS_CLEAR 0x4
#define DEVICE_NUM_SCANOUTS 0x8 #define DEVICE_NUM_SCANOUTS 0x8
namespace Kernel::Graphics { namespace Kernel::Graphics::VirtIOGPU {
VirtIOGPU::VirtIOGPU(PCI::Address address) GPU::GPU(PCI::Address address)
: VirtIODevice(address, "VirtIOGPU") : VirtIODevice(address, "GPU")
, m_scratch_space(MM.allocate_contiguous_kernel_region(32 * PAGE_SIZE, "VirtGPU Scratch Space", Region::Access::Read | Region::Access::Write)) , m_scratch_space(MM.allocate_contiguous_kernel_region(32 * PAGE_SIZE, "VirtGPU Scratch Space", Region::Access::Read | Region::Access::Write))
{ {
VERIFY(!!m_scratch_space); VERIFY(!!m_scratch_space);
@ -24,16 +24,16 @@ VirtIOGPU::VirtIOGPU(PCI::Address address)
bool success = negotiate_features([&](u64 supported_features) { bool success = negotiate_features([&](u64 supported_features) {
u64 negotiated = 0; u64 negotiated = 0;
if (is_feature_set(supported_features, VIRTIO_GPU_F_VIRGL)) 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)) 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; return negotiated;
}); });
if (success) { if (success) {
read_config_atomic([&]() { read_config_atomic([&]() {
m_num_scanouts = config_read32(*cfg, DEVICE_NUM_SCANOUTS); 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 success = setup_queues(2); // CONTROLQ + CURSORQ
} }
VERIFY(success); 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++) { for (size_t i = 0; i < min(m_num_scanouts, VIRTIO_GPU_MAX_SCANOUTS); i++) {
auto& scanout = m_scanouts[i]; auto& scanout = m_scanouts[i];
scanout.framebuffer = adopt_ref(*new VirtIOFrameBufferDevice(*this, i)); scanout.framebuffer = adopt_ref(*new VirtIOGPU::FrameBufferDevice(*this, i));
scanout.console = Kernel::Graphics::VirtIOGPUConsole::initialize(scanout.framebuffer); scanout.console = Kernel::Graphics::VirtIOGPU::Console::initialize(scanout.framebuffer);
} }
} }
bool VirtIOGPU::handle_device_config_change() bool GPU::handle_device_config_change()
{ {
return false; 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); VERIFY(queue_index == CONTROLQ);
auto& queue = get_queue(CONTROLQ); auto& queue = get_queue(CONTROLQ);
@ -75,23 +75,23 @@ void VirtIOGPU::handle_queue_update(u16 queue_index)
m_outstanding_request.wake_all(); m_outstanding_request.wake_all();
} }
u32 VirtIOGPU::get_pending_events() u32 GPU::get_pending_events()
{ {
return config_read32(*m_device_configuration, DEVICE_EVENTS_READ); 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); 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()); VERIFY(m_operation_lock.is_locked());
auto& request = *reinterpret_cast<VirtIOGPUCtrlHeader*>(m_scratch_space->vaddr().as_ptr()); auto& request = *reinterpret_cast<Protocol::ControlHeader*>(m_scratch_space->vaddr().as_ptr());
auto& response = *reinterpret_cast<VirtIOGPURespDisplayInfo*>((m_scratch_space->vaddr().offset(sizeof(request)).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)); 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()); 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()); VERIFY(m_operation_lock.is_locked());
auto& request = *reinterpret_cast<VirtIOGPUResourceCreate2D*>(m_scratch_space->vaddr().as_ptr()); auto& request = *reinterpret_cast<Protocol::ResourceCreate2D*>(m_scratch_space->vaddr().as_ptr());
auto& response = *reinterpret_cast<VirtIOGPUCtrlHeader*>((m_scratch_space->vaddr().offset(sizeof(request)).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(); auto resource_id = allocate_resource_id();
request.resource_id = resource_id.value(); request.resource_id = resource_id.value();
request.width = rect.width; request.width = rect.width;
request.height = rect.height; 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)); 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));
dbgln_if(VIRTIO_DEBUG, "VirtIOGPU: Allocated 2d resource with id {}", resource_id.value()); dbgln_if(VIRTIO_DEBUG, "GPU: Allocated 2d resource with id {}", resource_id.value());
return resource_id; 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()); 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; size_t num_mem_regions = buffer_length / PAGE_SIZE;
// Send request // Send request
auto& request = *reinterpret_cast<VirtIOGPUResourceAttachBacking*>(m_scratch_space->vaddr().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(VirtIOGPUMemEntry); const size_t header_block_size = sizeof(request) + num_mem_regions * sizeof(Protocol::MemoryEntry);
auto& response = *reinterpret_cast<VirtIOGPUCtrlHeader*>((m_scratch_space->vaddr().offset(header_block_size).as_ptr())); 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.resource_id = resource_id.value();
request.num_entries = num_mem_regions; request.num_entries = num_mem_regions;
for (size_t i = 0; i < num_mem_regions; ++i) { 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)); 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)); VERIFY(response.type == static_cast<u32>(Protocol::CommandType::VIRTIO_GPU_RESP_OK_NODATA));
dbgln_if(VIRTIO_DEBUG, "VirtIOGPU: Allocated backing storage"); 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()); VERIFY(m_operation_lock.is_locked());
auto& request = *reinterpret_cast<VirtIOGPUResourceDetachBacking*>(m_scratch_space->vaddr().as_ptr()); auto& request = *reinterpret_cast<Protocol::ResourceDetachBacking*>(m_scratch_space->vaddr().as_ptr());
auto& response = *reinterpret_cast<VirtIOGPUCtrlHeader*>((m_scratch_space->vaddr().offset(sizeof(request)).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(); request.resource_id = resource_id.value();
synchronous_virtio_gpu_command(start_of_scratch_space(), sizeof(request), sizeof(response)); 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));
dbgln_if(VIRTIO_DEBUG, "VirtIOGPU: Detached backing storage"); 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()); VERIFY(m_operation_lock.is_locked());
auto& request = *reinterpret_cast<VirtIOGPUSetScanOut*>(m_scratch_space->vaddr().as_ptr()); auto& request = *reinterpret_cast<Protocol::SetScanOut*>(m_scratch_space->vaddr().as_ptr());
auto& response = *reinterpret_cast<VirtIOGPUCtrlHeader*>((m_scratch_space->vaddr().offset(sizeof(request)).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.resource_id = resource_id.value();
request.scanout_id = scanout.value(); request.scanout_id = scanout.value();
request.rect = rect; request.rect = rect;
synchronous_virtio_gpu_command(start_of_scratch_space(), sizeof(request), sizeof(response)); 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));
dbgln_if(VIRTIO_DEBUG, "VirtIOGPU: Set backing scanout"); 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()); VERIFY(m_operation_lock.is_locked());
auto& request = *reinterpret_cast<VirtIOGPUTransferToHost2D*>(m_scratch_space->vaddr().as_ptr()); auto& request = *reinterpret_cast<Protocol::TransferToHost2D*>(m_scratch_space->vaddr().as_ptr());
auto& response = *reinterpret_cast<VirtIOGPUCtrlHeader*>((m_scratch_space->vaddr().offset(sizeof(request)).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.offset = (dirty_rect.x + (dirty_rect.y * m_scanouts[scanout.value()].display_info.rect.width)) * sizeof(u32);
request.resource_id = resource_id.value(); request.resource_id = resource_id.value();
request.rect = dirty_rect; request.rect = dirty_rect;
synchronous_virtio_gpu_command(start_of_scratch_space(), sizeof(request), sizeof(response)); 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()); VERIFY(m_operation_lock.is_locked());
auto& request = *reinterpret_cast<VirtIOGPUResourceFlush*>(m_scratch_space->vaddr().as_ptr()); auto& request = *reinterpret_cast<Protocol::ResourceFlush*>(m_scratch_space->vaddr().as_ptr());
auto& response = *reinterpret_cast<VirtIOGPUCtrlHeader*>((m_scratch_space->vaddr().offset(sizeof(request)).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.resource_id = resource_id.value();
request.rect = dirty_rect; request.rect = dirty_rect;
synchronous_virtio_gpu_command(start_of_scratch_space(), sizeof(request), sizeof(response)); 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_operation_lock.is_locked());
VERIFY(m_outstanding_request.is_empty()); 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(); 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.type = static_cast<u32>(ctrl_type);
header.flags = flags; header.flags = flags;
@ -242,32 +242,32 @@ void VirtIOGPU::populate_virtio_gpu_request_header(VirtIOGPUCtrlHeader& header,
header.padding = 0; 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); MutexLocker locker(m_operation_lock);
transfer_framebuffer_data_to_host(scanout, dirty_rect, resource_id); transfer_framebuffer_data_to_host(scanout, dirty_rect, resource_id);
flush_displayed_image(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()); VERIFY(m_operation_lock.is_locked());
m_resource_id_counter = m_resource_id_counter.value() + 1; m_resource_id_counter = m_resource_id_counter.value() + 1;
return m_resource_id_counter; 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()); VERIFY(m_operation_lock.is_locked());
auto& request = *reinterpret_cast<VirtioGPUResourceUnref*>(m_scratch_space->vaddr().as_ptr()); auto& request = *reinterpret_cast<Protocol::ResourceUnref*>(m_scratch_space->vaddr().as_ptr());
auto& response = *reinterpret_cast<VirtIOGPUCtrlHeader*>((m_scratch_space->vaddr().offset(sizeof(request)).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(); request.resource_id = resource_id.value();
synchronous_virtio_gpu_command(start_of_scratch_space(), sizeof(request), sizeof(response)); 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 <AK/DistinctNumeric.h>
#include <Kernel/Devices/BlockDevice.h> #include <Kernel/Devices/BlockDevice.h>
#include <Kernel/Graphics/VirtIOGPU/Protocol.h>
#include <Kernel/VirtIO/VirtIO.h> #include <Kernel/VirtIO/VirtIO.h>
#include <Kernel/VirtIO/VirtIOQueue.h> #include <Kernel/VirtIO/VirtIOQueue.h>
@ -16,165 +17,37 @@
#define VIRTIO_GPU_FLAG_FENCE (1 << 0) #define VIRTIO_GPU_FLAG_FENCE (1 << 0)
#define VIRTIO_GPU_MAX_SCANOUTS 16
#define CONTROLQ 0 #define CONTROLQ 0
#define CURSORQ 1 #define CURSORQ 1
#define MAX_VIRTIOGPU_RESOLUTION_WIDTH 3840 #define MAX_VIRTIOGPU_RESOLUTION_WIDTH 3840
#define MAX_VIRTIOGPU_RESOLUTION_HEIGHT 2160 #define MAX_VIRTIOGPU_RESOLUTION_HEIGHT 2160
namespace Kernel::Graphics { namespace Kernel::Graphics::VirtIOGPU {
class VirtIOGPUConsole; class Console;
class VirtIOFrameBufferDevice; class FrameBufferDevice;
TYPEDEF_DISTINCT_ORDERED_ID(u32, VirtIOGPUResourceID); TYPEDEF_DISTINCT_ORDERED_ID(u32, ResourceID);
TYPEDEF_DISTINCT_ORDERED_ID(u32, VirtIOGPUScanoutID); TYPEDEF_DISTINCT_ORDERED_ID(u32, ScanoutID);
enum class VirtIOGPUCtrlType : u32 { class GPU final
/* 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
: public VirtIODevice : public VirtIODevice
, public RefCounted<VirtIOGPU> { , public RefCounted<GPU> {
friend class VirtIOFrameBufferDevice; friend class FrameBufferDevice;
public: public:
VirtIOGPU(PCI::Address); GPU(PCI::Address);
virtual ~VirtIOGPU() override; 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); VERIFY(scanout.value() < VIRTIO_GPU_MAX_SCANOUTS);
return m_scanouts[scanout.value()].display_info; return m_scanouts[scanout.value()].display_info;
} }
auto& display_info(VirtIOGPUScanoutID scanout) auto& display_info(ScanoutID scanout)
{ {
VERIFY(scanout.value() < VIRTIO_GPU_MAX_SCANOUTS); VERIFY(scanout.value() < VIRTIO_GPU_MAX_SCANOUTS);
return m_scanouts[scanout.value()].display_info; return m_scanouts[scanout.value()].display_info;
@ -195,7 +68,7 @@ public:
return IterationDecision::Continue; return IterationDecision::Continue;
} }
RefPtr<VirtIOGPUConsole> default_console() RefPtr<Console> default_console()
{ {
if (m_default_scanout.has_value()) if (m_default_scanout.has_value())
return m_scanouts[m_default_scanout.value().value()].console; return m_scanouts[m_default_scanout.value().value()].console;
@ -211,32 +84,32 @@ private:
u32 get_pending_events(); u32 get_pending_events();
void clear_pending_events(u32 event_bitmask); 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(); } 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 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(); void query_display_information();
VirtIOGPUResourceID create_2d_resource(VirtIOGPURect rect); ResourceID create_2d_resource(Protocol::Rect rect);
void delete_resource(VirtIOGPUResourceID resource_id); void delete_resource(ResourceID resource_id);
void ensure_backing_storage(Region const&, size_t buffer_offset, size_t buffer_length, VirtIOGPUResourceID resource_id); void ensure_backing_storage(Region const& region, size_t buffer_offset, size_t buffer_length, ResourceID resource_id);
void detach_backing_storage(VirtIOGPUResourceID resource_id); void detach_backing_storage(ResourceID resource_id);
void set_scanout_resource(VirtIOGPUScanoutID scanout, VirtIOGPUResourceID resource_id, VirtIOGPURect rect); void set_scanout_resource(ScanoutID scanout, ResourceID resource_id, Protocol::Rect rect);
void transfer_framebuffer_data_to_host(VirtIOGPUScanoutID scanout, VirtIOGPURect const& rect, VirtIOGPUResourceID resource_id); void transfer_framebuffer_data_to_host(ScanoutID scanout, Protocol::Rect const& rect, ResourceID resource_id);
void flush_displayed_image(VirtIOGPURect const& dirty_rect, VirtIOGPUResourceID resource_id); void flush_displayed_image(Protocol::Rect const& dirty_rect, ResourceID resource_id);
struct Scanout { struct Scanout {
RefPtr<VirtIOFrameBufferDevice> framebuffer; RefPtr<FrameBufferDevice> framebuffer;
RefPtr<VirtIOGPUConsole> console; RefPtr<Console> console;
VirtIOGPURespDisplayInfo::VirtIOGPUDisplayOne display_info {}; Protocol::DisplayInfoResponse::Display display_info {};
}; };
Optional<VirtIOGPUScanoutID> m_default_scanout; Optional<ScanoutID> m_default_scanout;
size_t m_num_scanouts { 0 }; size_t m_num_scanouts { 0 };
Scanout m_scanouts[VIRTIO_GPU_MAX_SCANOUTS]; Scanout m_scanouts[VIRTIO_GPU_MAX_SCANOUTS];
Configuration const* m_device_configuration { nullptr }; Configuration const* m_device_configuration { nullptr };
VirtIOGPUResourceID m_resource_id_counter { 0 }; ResourceID m_resource_id_counter { 0 };
// Synchronous commands // Synchronous commands
WaitQueue m_outstanding_request; WaitQueue m_outstanding_request;