diff --git a/Kernel/CMakeLists.txt b/Kernel/CMakeLists.txt index 9fa0272813..f3acac594b 100644 --- a/Kernel/CMakeLists.txt +++ b/Kernel/CMakeLists.txt @@ -78,7 +78,6 @@ set(KERNEL_SOURCES Graphics/Intel/NativeGraphicsAdapter.cpp Graphics/VirtIOGPU/FramebufferDevice.cpp Graphics/VirtIOGPU/Console.cpp - Graphics/VirtIOGPU/GPU.cpp Graphics/VirtIOGPU/GraphicsAdapter.cpp Graphics/VGACompatibleAdapter.cpp SanCov.cpp diff --git a/Kernel/Graphics/FramebufferDevice.cpp b/Kernel/Graphics/FramebufferDevice.cpp index 35add1d2a9..547ca04b8a 100644 --- a/Kernel/Graphics/FramebufferDevice.cpp +++ b/Kernel/Graphics/FramebufferDevice.cpp @@ -101,19 +101,19 @@ UNMAP_AFTER_INIT KResult FramebufferDevice::initialize() UNMAP_AFTER_INIT FramebufferDevice::FramebufferDevice(const GraphicsDevice& adapter, size_t output_port_index) : BlockDevice(29, GraphicsManagement::the().allocate_minor_device_number()) - , m_output_port_index(output_port_index) , m_graphics_adapter(adapter) + , m_output_port_index(output_port_index) { } UNMAP_AFTER_INIT FramebufferDevice::FramebufferDevice(const GraphicsDevice& adapter, size_t output_port_index, PhysicalAddress addr, size_t width, size_t height, size_t pitch) : BlockDevice(29, GraphicsManagement::the().allocate_minor_device_number()) + , m_graphics_adapter(adapter) , m_framebuffer_address(addr) , m_framebuffer_pitch(pitch) , m_framebuffer_width(width) , m_framebuffer_height(height) , m_output_port_index(output_port_index) - , m_graphics_adapter(adapter) { VERIFY(!m_framebuffer_address.is_null()); VERIFY(m_framebuffer_pitch); diff --git a/Kernel/Graphics/FramebufferDevice.h b/Kernel/Graphics/FramebufferDevice.h index 0c048b684c..a838f1fb90 100644 --- a/Kernel/Graphics/FramebufferDevice.h +++ b/Kernel/Graphics/FramebufferDevice.h @@ -36,6 +36,7 @@ public: protected: FramebufferDevice(const GraphicsDevice&, size_t); + NonnullRefPtr m_graphics_adapter; private: FramebufferDevice(const GraphicsDevice&, size_t, PhysicalAddress, size_t, size_t, size_t); @@ -68,7 +69,6 @@ private: size_t m_y_offset { 0 }; size_t m_output_port_index; - NonnullRefPtr m_graphics_adapter; }; } diff --git a/Kernel/Graphics/VirtIOGPU/Console.h b/Kernel/Graphics/VirtIOGPU/Console.h index 16dfb2bac7..d046663205 100644 --- a/Kernel/Graphics/VirtIOGPU/Console.h +++ b/Kernel/Graphics/VirtIOGPU/Console.h @@ -7,7 +7,7 @@ #pragma once #include -#include +#include #include namespace Kernel::Graphics::VirtIOGPU { diff --git a/Kernel/Graphics/VirtIOGPU/FramebufferDevice.cpp b/Kernel/Graphics/VirtIOGPU/FramebufferDevice.cpp index a61a1678b3..6f11e06799 100644 --- a/Kernel/Graphics/VirtIOGPU/FramebufferDevice.cpp +++ b/Kernel/Graphics/VirtIOGPU/FramebufferDevice.cpp @@ -6,13 +6,23 @@ #include #include +#include #include namespace Kernel::Graphics::VirtIOGPU { -FramebufferDevice::FramebufferDevice(GraphicsDevice const& adapter, GPU& virtio_gpu, ScanoutID scanout) +GraphicsAdapter const& FramebufferDevice::adapter() const +{ + return static_cast(*m_graphics_adapter); +} + +GraphicsAdapter& FramebufferDevice::adapter() +{ + return static_cast(*m_graphics_adapter); +} + +FramebufferDevice::FramebufferDevice(GraphicsAdapter const& adapter, ScanoutID scanout) : Kernel::FramebufferDevice(adapter, scanout.value()) - , m_gpu(virtio_gpu) , m_scanout(scanout) { if (display_info().enabled) { @@ -45,7 +55,7 @@ KResult FramebufferDevice::create_framebuffer() } m_framebuffer_sink_vmobject = TRY(Memory::AnonymousVMObject::try_create_with_physical_pages(pages.span())); - MutexLocker locker(m_gpu.operation_lock()); + MutexLocker locker(adapter().operation_lock()); m_current_buffer = &buffer_from_index(m_last_set_buffer_index.load()); create_buffer(m_main_buffer, 0, m_buffer_size); create_buffer(m_back_buffer, m_buffer_size, m_buffer_size); @@ -62,14 +72,14 @@ void FramebufferDevice::create_buffer(Buffer& buffer, size_t framebuffer_offset, // 1. Create BUFFER using VIRTIO_GPU_CMD_RESOURCE_CREATE_2D if (buffer.resource_id.value() != 0) - m_gpu.delete_resource(buffer.resource_id); - buffer.resource_id = m_gpu.create_2d_resource(info.rect); + adapter().delete_resource(buffer.resource_id); + buffer.resource_id = adapter().create_2d_resource(info.rect); // 2. Attach backing storage using VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING - m_gpu.ensure_backing_storage(*m_framebuffer, buffer.framebuffer_offset, framebuffer_size, buffer.resource_id); + adapter().ensure_backing_storage(*m_framebuffer, buffer.framebuffer_offset, framebuffer_size, buffer.resource_id); // 3. Use VIRTIO_GPU_CMD_SET_SCANOUT to link the framebuffer to a display scanout. if (&buffer == m_current_buffer) - m_gpu.set_scanout_resource(m_scanout.value(), buffer.resource_id, info.rect); + adapter().set_scanout_resource(m_scanout.value(), buffer.resource_id, info.rect); // 4. Render our test pattern draw_ntsc_test_pattern(buffer); // 5. Use VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D to update the host resource from guest memory. @@ -91,27 +101,27 @@ void FramebufferDevice::create_buffer(Buffer& buffer, size_t framebuffer_offset, Protocol::DisplayInfoResponse::Display const& FramebufferDevice::display_info() const { - return m_gpu.display_info(m_scanout); + return adapter().display_info(m_scanout); } Protocol::DisplayInfoResponse::Display& FramebufferDevice::display_info() { - return m_gpu.display_info(m_scanout); + return adapter().display_info(m_scanout); } 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); + adapter().transfer_framebuffer_data_to_host(m_scanout, rect, buffer.resource_id); } void FramebufferDevice::flush_dirty_window(Protocol::Rect const& dirty_rect, Buffer& buffer) { - m_gpu.flush_dirty_rectangle(m_scanout, dirty_rect, buffer.resource_id); + adapter().flush_dirty_rectangle(m_scanout, dirty_rect, buffer.resource_id); } void FramebufferDevice::flush_displayed_image(Protocol::Rect const& dirty_rect, Buffer& buffer) { - m_gpu.flush_displayed_image(dirty_rect, buffer.resource_id); + adapter().flush_displayed_image(dirty_rect, buffer.resource_id); } KResult FramebufferDevice::try_to_set_resolution(size_t width, size_t height) @@ -121,7 +131,7 @@ KResult FramebufferDevice::try_to_set_resolution(size_t width, size_t height) auto& info = display_info(); - MutexLocker locker(m_gpu.operation_lock()); + MutexLocker locker(adapter().operation_lock()); info.rect = { .x = 0, @@ -136,12 +146,12 @@ KResult FramebufferDevice::try_to_set_resolution(size_t width, size_t height) void FramebufferDevice::set_buffer(int buffer_index) { auto& buffer = buffer_index == 0 ? m_main_buffer : m_back_buffer; - MutexLocker locker(m_gpu.operation_lock()); + MutexLocker locker(adapter().operation_lock()); if (&buffer == m_current_buffer) return; m_current_buffer = &buffer; - m_gpu.set_scanout_resource(m_scanout.value(), buffer.resource_id, display_info().rect); - m_gpu.flush_displayed_image(buffer.dirty_rect, buffer.resource_id); // QEMU SDL backend requires this (as per spec) + adapter().set_scanout_resource(m_scanout.value(), buffer.resource_id, display_info().rect); + adapter().flush_displayed_image(buffer.dirty_rect, buffer.resource_id); // QEMU SDL backend requires this (as per spec) buffer.dirty_rect = {}; } @@ -188,7 +198,7 @@ KResult FramebufferDevice::ioctl(OpenFileDescription&, unsigned request, Userspa return EFAULT; if (m_are_writes_active && flush_rects.count > 0) { auto& buffer = buffer_from_index(flush_rects.buffer_index); - MutexLocker locker(m_gpu.operation_lock()); + MutexLocker locker(adapter().operation_lock()); for (unsigned i = 0; i < flush_rects.count; i++) { FBRect user_dirty_rect; TRY(copy_from_user(&user_dirty_rect, &flush_rects.rects[i])); diff --git a/Kernel/Graphics/VirtIOGPU/FramebufferDevice.h b/Kernel/Graphics/VirtIOGPU/FramebufferDevice.h index b4bf08ce81..fa23fc3917 100644 --- a/Kernel/Graphics/VirtIOGPU/FramebufferDevice.h +++ b/Kernel/Graphics/VirtIOGPU/FramebufferDevice.h @@ -10,10 +10,11 @@ #include #include #include -#include +#include namespace Kernel::Graphics::VirtIOGPU { +class GraphicsAdapter; class FramebufferDevice final : public Kernel::FramebufferDevice { friend class Console; struct Buffer { @@ -24,7 +25,7 @@ class FramebufferDevice final : public Kernel::FramebufferDevice { }; public: - FramebufferDevice(GraphicsDevice const&, VirtIOGPU::GPU& virtio_gpu, ScanoutID); + FramebufferDevice(GraphicsAdapter const&, ScanoutID); virtual ~FramebufferDevice() override; virtual void deactivate_writes(); @@ -75,7 +76,9 @@ private: } Buffer& current_buffer() const { return *m_current_buffer; } - GPU& m_gpu; + GraphicsAdapter const& adapter() const; + GraphicsAdapter& adapter(); + const ScanoutID m_scanout; Buffer* m_current_buffer { nullptr }; Atomic m_last_set_buffer_index { 0 }; diff --git a/Kernel/Graphics/VirtIOGPU/GPU.cpp b/Kernel/Graphics/VirtIOGPU/GPU.cpp deleted file mode 100644 index a961ac1dcf..0000000000 --- a/Kernel/Graphics/VirtIOGPU/GPU.cpp +++ /dev/null @@ -1,303 +0,0 @@ -/* - * Copyright (c) 2021, Sahan Fernando - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include -#include - -#define DEVICE_EVENTS_READ 0x0 -#define DEVICE_EVENTS_CLEAR 0x4 -#define DEVICE_NUM_SCANOUTS 0x8 - -namespace Kernel::Graphics::VirtIOGPU { - -void GPU::initialize() -{ - Device::initialize(); - VERIFY(!!m_scratch_space); - if (auto cfg = get_config(VirtIO::ConfigurationType::Device)) { - m_device_configuration = cfg; - bool success = negotiate_features([&](u64 supported_features) { - u64 negotiated = 0; - if (is_feature_set(supported_features, VIRTIO_GPU_F_VIRGL)) - dbgln_if(VIRTIO_DEBUG, "GPU: VIRGL is not yet supported!"); - if (is_feature_set(supported_features, VIRTIO_GPU_F_EDID)) - 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, "GPU: num_scanouts: {}", m_num_scanouts); - success = setup_queues(2); // CONTROLQ + CURSORQ - } - VERIFY(success); - finish_init(); - MutexLocker locker(m_operation_lock); - // Get display information using VIRTIO_GPU_CMD_GET_DISPLAY_INFO - query_display_information(); - } else { - VERIFY_NOT_REACHED(); - } -} - -GPU::GPU(GraphicsDevice const& adapter, PCI::DeviceIdentifier const& device_identifier) - : VirtIO::Device(device_identifier) - , m_adapter(adapter) -{ - auto region_or_error = MM.allocate_contiguous_kernel_region(32 * PAGE_SIZE, "VirtGPU Scratch Space", Memory::Region::Access::ReadWrite); - if (region_or_error.is_error()) - TODO(); - m_scratch_space = region_or_error.release_value(); -} - -GPU::~GPU() -{ -} - -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 VirtIOGPU::FramebufferDevice(*m_adapter, *this, i)); - scanout.framebuffer->after_inserting(); - scanout.console = Kernel::Graphics::VirtIOGPU::Console::initialize(scanout.framebuffer); - } -} - -bool GPU::handle_device_config_change() -{ - auto events = get_pending_events(); - if (events & VIRTIO_GPU_EVENT_DISPLAY) { - // The host window was resized, in SerenityOS we completely ignore this event - dbgln_if(VIRTIO_DEBUG, "VirtIO::GPU: Ignoring virtio gpu display resize event"); - clear_pending_events(VIRTIO_GPU_EVENT_DISPLAY); - } - if (events & ~VIRTIO_GPU_EVENT_DISPLAY) { - dbgln("GPU: Got unknown device config change event: {:#x}", events); - return false; - } - return true; -} - -void GPU::handle_queue_update(u16 queue_index) -{ - dbgln_if(VIRTIO_DEBUG, "GPU: Handle queue update"); - VERIFY(queue_index == CONTROLQ); - - auto& queue = get_queue(CONTROLQ); - SpinlockLocker queue_lock(queue.lock()); - queue.discard_used_buffers(); - m_outstanding_request.wake_all(); -} - -u32 GPU::get_pending_events() -{ - return config_read32(*m_device_configuration, DEVICE_EVENTS_READ); -} - -void GPU::clear_pending_events(u32 event_bitmask) -{ - config_write32(*m_device_configuration, DEVICE_EVENTS_CLEAR, event_bitmask); -} - -void GPU::query_display_information() -{ - VERIFY(m_operation_lock.is_locked()); - auto writer = create_scratchspace_writer(); - auto& request = writer.append_structure(); - populate_virtio_gpu_request_header(request, Protocol::CommandType::VIRTIO_GPU_CMD_GET_DISPLAY_INFO, VIRTIO_GPU_FLAG_FENCE); - auto& response = writer.append_structure(); - - synchronous_virtio_gpu_command(start_of_scratch_space(), sizeof(request), sizeof(response)); - - for (size_t i = 0; i < VIRTIO_GPU_MAX_SCANOUTS; ++i) { - auto& scanout = m_scanouts[i].display_info; - scanout = response.scanout_modes[i]; - dbgln_if(VIRTIO_DEBUG, "GPU: Scanout {}: enabled: {} x: {}, y: {}, width: {}, height: {}", i, !!scanout.enabled, scanout.rect.x, scanout.rect.y, scanout.rect.width, scanout.rect.height); - if (scanout.enabled && !m_default_scanout.has_value()) - m_default_scanout = i; - } - VERIFY(m_default_scanout.has_value()); -} - -ResourceID GPU::create_2d_resource(Protocol::Rect rect) -{ - VERIFY(m_operation_lock.is_locked()); - auto writer = create_scratchspace_writer(); - auto& request = writer.append_structure(); - auto& response = writer.append_structure(); - - 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(Protocol::TextureFormat::VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM); - - synchronous_virtio_gpu_command(start_of_scratch_space(), sizeof(request), sizeof(response)); - - VERIFY(response.type == static_cast(Protocol::CommandType::VIRTIO_GPU_RESP_OK_NODATA)); - dbgln_if(VIRTIO_DEBUG, "GPU: Allocated 2d resource with id {}", resource_id.value()); - return resource_id; -} - -void GPU::ensure_backing_storage(Memory::Region const& region, size_t buffer_offset, size_t buffer_length, ResourceID resource_id) -{ - VERIFY(m_operation_lock.is_locked()); - - VERIFY(buffer_offset % PAGE_SIZE == 0); - VERIFY(buffer_length % PAGE_SIZE == 0); - auto first_page_index = buffer_offset / PAGE_SIZE; - size_t num_mem_regions = buffer_length / PAGE_SIZE; - - // Send request - auto writer = create_scratchspace_writer(); - auto& request = writer.append_structure(); - const size_t header_block_size = sizeof(request) + num_mem_regions * sizeof(Protocol::MemoryEntry); - - 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) { - auto& memory_entry = writer.append_structure(); - memory_entry.address = region.physical_page(first_page_index + i)->paddr().get(); - memory_entry.length = PAGE_SIZE; - } - - auto& response = writer.append_structure(); - - synchronous_virtio_gpu_command(start_of_scratch_space(), header_block_size, sizeof(response)); - - VERIFY(response.type == static_cast(Protocol::CommandType::VIRTIO_GPU_RESP_OK_NODATA)); - dbgln_if(VIRTIO_DEBUG, "GPU: Allocated backing storage"); -} - -void GPU::detach_backing_storage(ResourceID resource_id) -{ - VERIFY(m_operation_lock.is_locked()); - auto writer = create_scratchspace_writer(); - auto& request = writer.append_structure(); - auto& response = writer.append_structure(); - - 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(Protocol::CommandType::VIRTIO_GPU_RESP_OK_NODATA)); - dbgln_if(VIRTIO_DEBUG, "GPU: Detached backing storage"); -} - -void GPU::set_scanout_resource(ScanoutID scanout, ResourceID resource_id, Protocol::Rect rect) -{ - VERIFY(m_operation_lock.is_locked()); - auto writer = create_scratchspace_writer(); - auto& request = writer.append_structure(); - auto& response = writer.append_structure(); - - 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(Protocol::CommandType::VIRTIO_GPU_RESP_OK_NODATA)); - dbgln_if(VIRTIO_DEBUG, "GPU: Set backing scanout"); -} - -void GPU::transfer_framebuffer_data_to_host(ScanoutID scanout, Protocol::Rect const& dirty_rect, ResourceID resource_id) -{ - VERIFY(m_operation_lock.is_locked()); - auto writer = create_scratchspace_writer(); - auto& request = writer.append_structure(); - auto& response = writer.append_structure(); - - 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(Protocol::CommandType::VIRTIO_GPU_RESP_OK_NODATA)); -} - -void GPU::flush_displayed_image(Protocol::Rect const& dirty_rect, ResourceID resource_id) -{ - VERIFY(m_operation_lock.is_locked()); - auto writer = create_scratchspace_writer(); - auto& request = writer.append_structure(); - auto& response = writer.append_structure(); - - 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(Protocol::CommandType::VIRTIO_GPU_RESP_OK_NODATA)); -} - -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()); - auto& queue = get_queue(CONTROLQ); - { - SpinlockLocker lock(queue.lock()); - VirtIO::QueueChain chain { queue }; - chain.add_buffer_to_chain(buffer_start, request_size, VirtIO::BufferType::DeviceReadable); - chain.add_buffer_to_chain(buffer_start.offset(request_size), response_size, VirtIO::BufferType::DeviceWritable); - supply_chain_and_notify(CONTROLQ, chain); - full_memory_barrier(); - } - m_outstanding_request.wait_forever(); -} - -void GPU::populate_virtio_gpu_request_header(Protocol::ControlHeader& header, Protocol::CommandType ctrl_type, u32 flags) -{ - header.type = static_cast(ctrl_type); - header.flags = flags; - header.fence_id = 0; - header.context_id = 0; - header.padding = 0; -} - -void GPU::flush_dirty_rectangle(ScanoutID scanout_id, Protocol::Rect const& dirty_rect, ResourceID resource_id) -{ - MutexLocker locker(m_operation_lock); - transfer_framebuffer_data_to_host(scanout_id, dirty_rect, resource_id); - flush_displayed_image(dirty_rect, 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 GPU::delete_resource(ResourceID resource_id) -{ - VERIFY(m_operation_lock.is_locked()); - auto writer = create_scratchspace_writer(); - auto& request = writer.append_structure(); - auto& response = writer.append_structure(); - - 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(Protocol::CommandType::VIRTIO_GPU_RESP_OK_NODATA)); -} - -} diff --git a/Kernel/Graphics/VirtIOGPU/GPU.h b/Kernel/Graphics/VirtIOGPU/GPU.h deleted file mode 100644 index 533ad5a66d..0000000000 --- a/Kernel/Graphics/VirtIOGPU/GPU.h +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright (c) 2021, Sahan Fernando - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include -#include -#include -#include -#include - -#define VIRTIO_GPU_F_VIRGL (1 << 0) -#define VIRTIO_GPU_F_EDID (1 << 1) - -#define VIRTIO_GPU_FLAG_FENCE (1 << 0) - -#define CONTROLQ 0 -#define CURSORQ 1 - -#define MAX_VIRTIOGPU_RESOLUTION_WIDTH 3840 -#define MAX_VIRTIOGPU_RESOLUTION_HEIGHT 2160 - -#define VIRTIO_GPU_EVENT_DISPLAY (1 << 0) - -namespace Kernel::Graphics::VirtIOGPU { - -class Console; -class FramebufferDevice; - -TYPEDEF_DISTINCT_ORDERED_ID(u32, ResourceID); -TYPEDEF_DISTINCT_ORDERED_ID(u32, ScanoutID); - -class GPU final - : public VirtIO::Device - , public RefCounted { - friend class FramebufferDevice; - -public: - GPU(GraphicsDevice const&, PCI::DeviceIdentifier const&); - virtual ~GPU() override; - - void create_framebuffer_devices(); - template - IterationDecision for_each_framebuffer(F f) - { - for (auto& scanout : m_scanouts) { - if (!scanout.framebuffer) - continue; - IterationDecision decision = f(*scanout.framebuffer, *scanout.console); - if (decision != IterationDecision::Continue) - return decision; - } - return IterationDecision::Continue; - } - - virtual void initialize() override; - - RefPtr default_console() - { - if (m_default_scanout.has_value()) - return m_scanouts[m_default_scanout.value().value()].console; - return {}; - } - auto& display_info(ScanoutID scanout) const - { - VERIFY(scanout.value() < VIRTIO_GPU_MAX_SCANOUTS); - return m_scanouts[scanout.value()].display_info; - } - auto& display_info(ScanoutID scanout) - { - VERIFY(scanout.value() < VIRTIO_GPU_MAX_SCANOUTS); - return m_scanouts[scanout.value()].display_info; - } - - void flush_dirty_rectangle(ScanoutID, Protocol::Rect const& dirty_rect, ResourceID); - -private: - virtual StringView class_name() const override { return "VirtIOGPU"sv; } - - struct Scanout { - RefPtr framebuffer; - RefPtr console; - Protocol::DisplayInfoResponse::Display display_info {}; - }; - - virtual bool handle_device_config_change() override; - virtual void handle_queue_update(u16 queue_index) override; - u32 get_pending_events(); - void clear_pending_events(u32 event_bitmask); - - auto& operation_lock() { return m_operation_lock; } - ResourceID allocate_resource_id(); - - PhysicalAddress start_of_scratch_space() const { return m_scratch_space->physical_page(0)->paddr(); } - AK::BinaryBufferWriter create_scratchspace_writer() - { - return { Bytes(m_scratch_space->vaddr().as_ptr(), m_scratch_space->size()) }; - } - void synchronous_virtio_gpu_command(PhysicalAddress buffer_start, size_t request_size, size_t response_size); - void populate_virtio_gpu_request_header(Protocol::ControlHeader& header, Protocol::CommandType ctrl_type, u32 flags = 0); - - void query_display_information(); - ResourceID create_2d_resource(Protocol::Rect rect); - void delete_resource(ResourceID resource_id); - void ensure_backing_storage(Memory::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); - - Optional m_default_scanout; - size_t m_num_scanouts { 0 }; - Scanout m_scanouts[VIRTIO_GPU_MAX_SCANOUTS]; - - VirtIO::Configuration const* m_device_configuration { nullptr }; - ResourceID m_resource_id_counter { 0 }; - - NonnullRefPtr m_adapter; - - // Synchronous commands - WaitQueue m_outstanding_request; - Mutex m_operation_lock; - OwnPtr m_scratch_space; -}; - -} diff --git a/Kernel/Graphics/VirtIOGPU/GraphicsAdapter.cpp b/Kernel/Graphics/VirtIOGPU/GraphicsAdapter.cpp index 4043f81156..22f801cc43 100644 --- a/Kernel/Graphics/VirtIOGPU/GraphicsAdapter.cpp +++ b/Kernel/Graphics/VirtIOGPU/GraphicsAdapter.cpp @@ -4,43 +4,53 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include #include #include #include #include -#include +#include +#include #include namespace Kernel::Graphics::VirtIOGPU { +#define DEVICE_EVENTS_READ 0x0 +#define DEVICE_EVENTS_CLEAR 0x4 +#define DEVICE_NUM_SCANOUTS 0x8 + NonnullRefPtr GraphicsAdapter::initialize(PCI::DeviceIdentifier const& device_identifier) { VERIFY(device_identifier.hardware_id().vendor_id == PCI::VendorID::VirtIO); - return adopt_ref(*new GraphicsAdapter(device_identifier)); + auto adapter = adopt_ref(*new GraphicsAdapter(device_identifier)); + adapter->initialize(); + return adapter; } GraphicsAdapter::GraphicsAdapter(PCI::DeviceIdentifier const& device_identifier) - : PCI::Device(device_identifier.address()) + : VirtIO::Device(device_identifier) { - m_gpu_device = adopt_ref(*new GPU(*this, device_identifier)).leak_ref(); - m_gpu_device->initialize(); + auto region_or_error = MM.allocate_contiguous_kernel_region(32 * PAGE_SIZE, "VirtGPU Scratch Space", Memory::Region::Access::ReadWrite); + if (region_or_error.is_error()) + TODO(); + m_scratch_space = region_or_error.release_value(); } void GraphicsAdapter::initialize_framebuffer_devices() { - dbgln_if(VIRTIO_DEBUG, "GPU: Initializing framebuffer devices"); + dbgln_if(VIRTIO_DEBUG, "VirtIO::GraphicsAdapter: Initializing framebuffer devices"); VERIFY(!m_created_framebuffer_devices); - m_gpu_device->create_framebuffer_devices(); + create_framebuffer_devices(); m_created_framebuffer_devices = true; // FIXME: This is a very wrong way to do this... - GraphicsManagement::the().m_console = m_gpu_device->default_console(); + GraphicsManagement::the().m_console = default_console(); } void GraphicsAdapter::enable_consoles() { - dbgln_if(VIRTIO_DEBUG, "GPU: Enabling consoles"); - m_gpu_device->for_each_framebuffer([&](auto& framebuffer, auto& console) { + dbgln_if(VIRTIO_DEBUG, "VirtIO::GraphicsAdapter: Enabling consoles"); + for_each_framebuffer([&](auto& framebuffer, auto& console) { framebuffer.deactivate_writes(); console.enable(); return IterationDecision::Continue; @@ -49,12 +59,282 @@ void GraphicsAdapter::enable_consoles() void GraphicsAdapter::disable_consoles() { - dbgln_if(VIRTIO_DEBUG, "GPU: Disabling consoles"); - m_gpu_device->for_each_framebuffer([&](auto& framebuffer, auto& console) { + dbgln_if(VIRTIO_DEBUG, "VirtIO::GraphicsAdapter: Disabling consoles"); + for_each_framebuffer([&](auto& framebuffer, auto& console) { console.disable(); framebuffer.activate_writes(); return IterationDecision::Continue; }); } +void GraphicsAdapter::initialize() +{ + Device::initialize(); + VERIFY(!!m_scratch_space); + if (auto* config = get_config(VirtIO::ConfigurationType::Device)) { + m_device_configuration = config; + bool success = negotiate_features([&](u64 supported_features) { + u64 negotiated = 0; + if (is_feature_set(supported_features, VIRTIO_GPU_F_VIRGL)) + dbgln_if(VIRTIO_DEBUG, "VirtIO::GraphicsAdapter: VIRGL is not yet supported!"); + if (is_feature_set(supported_features, VIRTIO_GPU_F_EDID)) + dbgln_if(VIRTIO_DEBUG, "VirtIO::GraphicsAdapter: EDID is not yet supported!"); + return negotiated; + }); + if (success) { + read_config_atomic([&]() { + m_num_scanouts = config_read32(*config, DEVICE_NUM_SCANOUTS); + }); + dbgln_if(VIRTIO_DEBUG, "VirtIO::GraphicsAdapter: num_scanouts: {}", m_num_scanouts); + success = setup_queues(2); // CONTROLQ + CURSORQ + } + VERIFY(success); + finish_init(); + MutexLocker locker(m_operation_lock); + // Get display information using VIRTIO_GPU_CMD_GET_DISPLAY_INFO + query_display_information(); + } else { + VERIFY_NOT_REACHED(); + } +} + +void GraphicsAdapter::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 VirtIOGPU::FramebufferDevice(*this, i)); + scanout.framebuffer->after_inserting(); + scanout.console = Kernel::Graphics::VirtIOGPU::Console::initialize(scanout.framebuffer); + } +} + +bool GraphicsAdapter::handle_device_config_change() +{ + auto events = get_pending_events(); + if (events & VIRTIO_GPU_EVENT_DISPLAY) { + // The host window was resized, in SerenityOS we completely ignore this event + dbgln_if(VIRTIO_DEBUG, "VirtIO::GraphicsAdapter: Ignoring virtio gpu display resize event"); + clear_pending_events(VIRTIO_GPU_EVENT_DISPLAY); + } + if (events & ~VIRTIO_GPU_EVENT_DISPLAY) { + dbgln("VirtIO::GraphicsAdapter: Got unknown device config change event: {:#x}", events); + return false; + } + return true; +} + +void GraphicsAdapter::handle_queue_update(u16 queue_index) +{ + dbgln_if(VIRTIO_DEBUG, "VirtIO::GraphicsAdapter: Handle queue update"); + VERIFY(queue_index == CONTROLQ); + + auto& queue = get_queue(CONTROLQ); + SpinlockLocker queue_lock(queue.lock()); + queue.discard_used_buffers(); + m_outstanding_request.wake_all(); +} + +u32 GraphicsAdapter::get_pending_events() +{ + return config_read32(*m_device_configuration, DEVICE_EVENTS_READ); +} + +void GraphicsAdapter::clear_pending_events(u32 event_bitmask) +{ + config_write32(*m_device_configuration, DEVICE_EVENTS_CLEAR, event_bitmask); +} + +void GraphicsAdapter::query_display_information() +{ + VERIFY(m_operation_lock.is_locked()); + auto writer = create_scratchspace_writer(); + auto& request = writer.append_structure(); + populate_virtio_gpu_request_header(request, Protocol::CommandType::VIRTIO_GPU_CMD_GET_DISPLAY_INFO, VIRTIO_GPU_FLAG_FENCE); + auto& response = writer.append_structure(); + + synchronous_virtio_gpu_command(start_of_scratch_space(), sizeof(request), sizeof(response)); + + for (size_t i = 0; i < VIRTIO_GPU_MAX_SCANOUTS; ++i) { + auto& scanout = m_scanouts[i].display_info; + scanout = response.scanout_modes[i]; + dbgln_if(VIRTIO_DEBUG, "VirtIO::GraphicsAdapter: Scanout {}: enabled: {} x: {}, y: {}, width: {}, height: {}", i, !!scanout.enabled, scanout.rect.x, scanout.rect.y, scanout.rect.width, scanout.rect.height); + if (scanout.enabled && !m_default_scanout.has_value()) + m_default_scanout = i; + } + VERIFY(m_default_scanout.has_value()); +} + +ResourceID GraphicsAdapter::create_2d_resource(Protocol::Rect rect) +{ + VERIFY(m_operation_lock.is_locked()); + auto writer = create_scratchspace_writer(); + auto& request = writer.append_structure(); + auto& response = writer.append_structure(); + + 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(Protocol::TextureFormat::VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM); + + synchronous_virtio_gpu_command(start_of_scratch_space(), sizeof(request), sizeof(response)); + + VERIFY(response.type == static_cast(Protocol::CommandType::VIRTIO_GPU_RESP_OK_NODATA)); + dbgln_if(VIRTIO_DEBUG, "VirtIO::GraphicsAdapter: Allocated 2d resource with id {}", resource_id.value()); + return resource_id; +} + +void GraphicsAdapter::ensure_backing_storage(Memory::Region const& region, size_t buffer_offset, size_t buffer_length, ResourceID resource_id) +{ + VERIFY(m_operation_lock.is_locked()); + + VERIFY(buffer_offset % PAGE_SIZE == 0); + VERIFY(buffer_length % PAGE_SIZE == 0); + auto first_page_index = buffer_offset / PAGE_SIZE; + size_t num_mem_regions = buffer_length / PAGE_SIZE; + + auto writer = create_scratchspace_writer(); + auto& request = writer.append_structure(); + const size_t header_block_size = sizeof(request) + num_mem_regions * sizeof(Protocol::MemoryEntry); + + 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) { + auto& memory_entry = writer.append_structure(); + memory_entry.address = region.physical_page(first_page_index + i)->paddr().get(); + memory_entry.length = PAGE_SIZE; + } + + auto& response = writer.append_structure(); + + synchronous_virtio_gpu_command(start_of_scratch_space(), header_block_size, sizeof(response)); + + VERIFY(response.type == static_cast(Protocol::CommandType::VIRTIO_GPU_RESP_OK_NODATA)); + dbgln_if(VIRTIO_DEBUG, "VirtIO::GraphicsAdapter: Allocated backing storage"); +} + +void GraphicsAdapter::detach_backing_storage(ResourceID resource_id) +{ + VERIFY(m_operation_lock.is_locked()); + auto writer = create_scratchspace_writer(); + auto& request = writer.append_structure(); + auto& response = writer.append_structure(); + + 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(Protocol::CommandType::VIRTIO_GPU_RESP_OK_NODATA)); + dbgln_if(VIRTIO_DEBUG, "VirtIO::GraphicsAdapter: Detached backing storage"); +} + +void GraphicsAdapter::set_scanout_resource(ScanoutID scanout, ResourceID resource_id, Protocol::Rect rect) +{ + VERIFY(m_operation_lock.is_locked()); + auto writer = create_scratchspace_writer(); + auto& request = writer.append_structure(); + auto& response = writer.append_structure(); + + 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(Protocol::CommandType::VIRTIO_GPU_RESP_OK_NODATA)); + dbgln_if(VIRTIO_DEBUG, "VirtIO::GraphicsAdapter: Set backing scanout"); +} + +void GraphicsAdapter::transfer_framebuffer_data_to_host(ScanoutID scanout, Protocol::Rect const& dirty_rect, ResourceID resource_id) +{ + VERIFY(m_operation_lock.is_locked()); + auto writer = create_scratchspace_writer(); + auto& request = writer.append_structure(); + auto& response = writer.append_structure(); + + 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(Protocol::CommandType::VIRTIO_GPU_RESP_OK_NODATA)); +} + +void GraphicsAdapter::flush_displayed_image(Protocol::Rect const& dirty_rect, ResourceID resource_id) +{ + VERIFY(m_operation_lock.is_locked()); + auto writer = create_scratchspace_writer(); + auto& request = writer.append_structure(); + auto& response = writer.append_structure(); + + 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(Protocol::CommandType::VIRTIO_GPU_RESP_OK_NODATA)); +} + +void GraphicsAdapter::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()); + auto& queue = get_queue(CONTROLQ); + { + SpinlockLocker lock(queue.lock()); + VirtIO::QueueChain chain { queue }; + chain.add_buffer_to_chain(buffer_start, request_size, VirtIO::BufferType::DeviceReadable); + chain.add_buffer_to_chain(buffer_start.offset(request_size), response_size, VirtIO::BufferType::DeviceWritable); + supply_chain_and_notify(CONTROLQ, chain); + full_memory_barrier(); + } + m_outstanding_request.wait_forever(); +} + +void GraphicsAdapter::populate_virtio_gpu_request_header(Protocol::ControlHeader& header, Protocol::CommandType ctrl_type, u32 flags) +{ + header.type = static_cast(ctrl_type); + header.flags = flags; + header.fence_id = 0; + header.context_id = 0; + header.padding = 0; +} + +void GraphicsAdapter::flush_dirty_rectangle(ScanoutID scanout_id, Protocol::Rect const& dirty_rect, ResourceID resource_id) +{ + MutexLocker locker(m_operation_lock); + transfer_framebuffer_data_to_host(scanout_id, dirty_rect, resource_id); + flush_displayed_image(dirty_rect, resource_id); +} + +ResourceID GraphicsAdapter::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 GraphicsAdapter::delete_resource(ResourceID resource_id) +{ + VERIFY(m_operation_lock.is_locked()); + auto writer = create_scratchspace_writer(); + auto& request = writer.append_structure(); + auto& response = writer.append_structure(); + + 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(Protocol::CommandType::VIRTIO_GPU_RESP_OK_NODATA)); +} + } diff --git a/Kernel/Graphics/VirtIOGPU/GraphicsAdapter.h b/Kernel/Graphics/VirtIOGPU/GraphicsAdapter.h index 69d3f35230..9ffc881595 100644 --- a/Kernel/Graphics/VirtIOGPU/GraphicsAdapter.h +++ b/Kernel/Graphics/VirtIOGPU/GraphicsAdapter.h @@ -6,16 +6,37 @@ #pragma once +#include +#include +#include +#include +#include +#include #include #include -#include +#include namespace Kernel::Graphics::VirtIOGPU { +#define VIRTIO_GPU_F_VIRGL (1 << 0) +#define VIRTIO_GPU_F_EDID (1 << 1) + +#define VIRTIO_GPU_FLAG_FENCE (1 << 0) + +#define CONTROLQ 0 +#define CURSORQ 1 + +#define MAX_VIRTIOGPU_RESOLUTION_WIDTH 3840 +#define MAX_VIRTIOGPU_RESOLUTION_HEIGHT 2160 + +#define VIRTIO_GPU_EVENT_DISPLAY (1 << 0) + +class FramebufferDevice; class GraphicsAdapter final : public GraphicsDevice - , public PCI::Device { + , public VirtIO::Device { AK_MAKE_ETERNAL + friend class FramebufferDevice; public: static NonnullRefPtr initialize(PCI::DeviceIdentifier const&); @@ -25,9 +46,45 @@ public: // FIXME: There's a VirtIO VGA GPU variant, so we should consider that virtual bool vga_compatible() const override { return false; } + virtual void initialize() override; + private: + void flush_dirty_rectangle(ScanoutID, Protocol::Rect const& dirty_rect, ResourceID); + + template + IterationDecision for_each_framebuffer(F f) + { + for (auto& scanout : m_scanouts) { + if (!scanout.framebuffer) + continue; + IterationDecision decision = f(*scanout.framebuffer, *scanout.console); + if (decision != IterationDecision::Continue) + return decision; + } + return IterationDecision::Continue; + } + + RefPtr default_console() + { + if (m_default_scanout.has_value()) + return m_scanouts[m_default_scanout.value().value()].console; + return {}; + } + auto& display_info(ScanoutID scanout) const + { + VERIFY(scanout.value() < VIRTIO_GPU_MAX_SCANOUTS); + return m_scanouts[scanout.value()].display_info; + } + auto& display_info(ScanoutID scanout) + { + VERIFY(scanout.value() < VIRTIO_GPU_MAX_SCANOUTS); + return m_scanouts[scanout.value()].display_info; + } + explicit GraphicsAdapter(PCI::DeviceIdentifier const&); + void create_framebuffer_devices(); + virtual void initialize_framebuffer_devices() override; virtual void enable_consoles() override; virtual void disable_consoles() override; @@ -38,7 +95,48 @@ 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 m_gpu_device; + struct Scanout { + RefPtr framebuffer; + RefPtr console; + Protocol::DisplayInfoResponse::Display display_info {}; + }; + + virtual bool handle_device_config_change() override; + virtual void handle_queue_update(u16 queue_index) override; + u32 get_pending_events(); + void clear_pending_events(u32 event_bitmask); + + auto& operation_lock() { return m_operation_lock; } + ResourceID allocate_resource_id(); + + PhysicalAddress start_of_scratch_space() const { return m_scratch_space->physical_page(0)->paddr(); } + AK::BinaryBufferWriter create_scratchspace_writer() + { + return { Bytes(m_scratch_space->vaddr().as_ptr(), m_scratch_space->size()) }; + } + void synchronous_virtio_gpu_command(PhysicalAddress buffer_start, size_t request_size, size_t response_size); + void populate_virtio_gpu_request_header(Protocol::ControlHeader& header, Protocol::CommandType ctrl_type, u32 flags = 0); + + void query_display_information(); + ResourceID create_2d_resource(Protocol::Rect rect); + void delete_resource(ResourceID resource_id); + void ensure_backing_storage(Memory::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); + bool m_created_framebuffer_devices { false }; + Optional m_default_scanout; + size_t m_num_scanouts { 0 }; + Scanout m_scanouts[VIRTIO_GPU_MAX_SCANOUTS]; + + VirtIO::Configuration const* m_device_configuration { nullptr }; + ResourceID m_resource_id_counter { 0 }; + + // Synchronous commands + WaitQueue m_outstanding_request; + Mutex m_operation_lock; + OwnPtr m_scratch_space; }; } diff --git a/Kernel/Graphics/VirtIOGPU/Protocol.h b/Kernel/Graphics/VirtIOGPU/Protocol.h index 98eae39dce..c715084dd5 100644 --- a/Kernel/Graphics/VirtIOGPU/Protocol.h +++ b/Kernel/Graphics/VirtIOGPU/Protocol.h @@ -10,6 +10,11 @@ #define VIRTIO_GPU_MAX_SCANOUTS 16 +namespace Kernel::Graphics::VirtIOGPU { +TYPEDEF_DISTINCT_ORDERED_ID(u32, ResourceID); +TYPEDEF_DISTINCT_ORDERED_ID(u32, ScanoutID); +}; + namespace Kernel::Graphics::VirtIOGPU::Protocol { // Specification equivalent: enum virtio_gpu_ctrl_type