mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 23:47:45 +00:00

This step would ideally not have been necessary (increases amount of refactoring and templates necessary, which in turn increases build times), but it gives us a couple of nice properties: - SpinlockProtected inside Singleton (a very common combination) can now obtain any lock rank just via the template parameter. It was not previously possible to do this with SingletonInstanceCreator magic. - SpinlockProtected's lock rank is now mandatory; this is the majority of cases and allows us to see where we're still missing proper ranks. - The type already informs us what lock rank a lock has, which aids code readability and (possibly, if gdb cooperates) lock mismatch debugging. - The rank of a lock can no longer be dynamic, which is not something we wanted in the first place (or made use of). Locks randomly changing their rank sounds like a disaster waiting to happen. - In some places, we might be able to statically check that locks are taken in the right order (with the right lock rank checking implementation) as rank information is fully statically known. This refactoring even more exposes the fact that Mutex has no lock rank capabilites, which is not fixed here.
122 lines
5.7 KiB
C++
122 lines
5.7 KiB
C++
/*
|
|
* Copyright (c) 2021, Sahan Fernando <sahan.h.fernando@gmail.com>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <AK/BinaryBufferWriter.h>
|
|
#include <AK/DistinctNumeric.h>
|
|
#include <Kernel/Bus/VirtIO/Device.h>
|
|
#include <Kernel/Bus/VirtIO/Queue.h>
|
|
#include <Kernel/Graphics/GenericGraphicsAdapter.h>
|
|
#include <Kernel/Graphics/VirtIOGPU/Protocol.h>
|
|
|
|
namespace Kernel {
|
|
|
|
#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 VirtIODisplayConnector;
|
|
class VirtIOGPU3DDevice;
|
|
class VirtIOGraphicsAdapter final
|
|
: public GenericGraphicsAdapter
|
|
, public VirtIO::Device {
|
|
friend class VirtIODisplayConnector;
|
|
friend class VirtIOGPU3DDevice;
|
|
|
|
public:
|
|
static NonnullLockRefPtr<VirtIOGraphicsAdapter> initialize(PCI::DeviceIdentifier const&);
|
|
|
|
virtual void initialize() override;
|
|
|
|
ErrorOr<void> mode_set_resolution(Badge<VirtIODisplayConnector>, VirtIODisplayConnector&, size_t width, size_t height);
|
|
void set_dirty_displayed_rect(Badge<VirtIODisplayConnector>, VirtIODisplayConnector&, Graphics::VirtIOGPU::Protocol::Rect const& dirty_rect, bool main_buffer);
|
|
ErrorOr<void> flush_displayed_image(Badge<VirtIODisplayConnector>, VirtIODisplayConnector&, Graphics::VirtIOGPU::Protocol::Rect const& dirty_rect, bool main_buffer);
|
|
ErrorOr<void> transfer_framebuffer_data_to_host(Badge<VirtIODisplayConnector>, VirtIODisplayConnector&, Graphics::VirtIOGPU::Protocol::Rect const& rect, bool main_buffer);
|
|
|
|
private:
|
|
ErrorOr<void> attach_physical_range_to_framebuffer(VirtIODisplayConnector& connector, bool main_buffer, size_t framebuffer_offset, size_t framebuffer_size);
|
|
|
|
ErrorOr<void> initialize_3d_device();
|
|
|
|
ErrorOr<void> flush_dirty_rectangle(Graphics::VirtIOGPU::ScanoutID, Graphics::VirtIOGPU::ResourceID, Graphics::VirtIOGPU::Protocol::Rect const& dirty_rect);
|
|
struct Scanout {
|
|
struct PhysicalBuffer {
|
|
size_t framebuffer_offset { 0 };
|
|
Graphics::VirtIOGPU::Protocol::Rect dirty_rect {};
|
|
Graphics::VirtIOGPU::ResourceID resource_id { 0 };
|
|
};
|
|
|
|
LockRefPtr<VirtIODisplayConnector> display_connector;
|
|
PhysicalBuffer main_buffer;
|
|
PhysicalBuffer back_buffer;
|
|
};
|
|
|
|
VirtIOGraphicsAdapter(PCI::DeviceIdentifier const&, Bitmap&& active_context_ids, NonnullOwnPtr<Memory::Region> scratch_space_region);
|
|
|
|
ErrorOr<void> initialize_adapter();
|
|
|
|
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);
|
|
|
|
// 2D framebuffer stuff
|
|
static ErrorOr<FlatPtr> calculate_framebuffer_size(size_t width, size_t height)
|
|
{
|
|
// VirtIO resources can only map on page boundaries!
|
|
return Memory::page_round_up(sizeof(u32) * width * height);
|
|
}
|
|
|
|
// 3D Command stuff
|
|
ErrorOr<Graphics::VirtIOGPU::ContextID> create_context();
|
|
ErrorOr<void> attach_resource_to_context(Graphics::VirtIOGPU::ResourceID resource_id, Graphics::VirtIOGPU::ContextID context_id);
|
|
ErrorOr<void> submit_command_buffer(Graphics::VirtIOGPU::ContextID, Function<size_t(Bytes)> buffer_writer);
|
|
Graphics::VirtIOGPU::Protocol::TextureFormat get_framebuffer_format() const { return Graphics::VirtIOGPU::Protocol::TextureFormat::VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM; }
|
|
|
|
auto& operation_lock() { return m_operation_lock; }
|
|
Graphics::VirtIOGPU::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()) };
|
|
}
|
|
ErrorOr<void> synchronous_virtio_gpu_command(size_t microseconds_timeout, PhysicalAddress buffer_start, size_t request_size, size_t response_size);
|
|
|
|
ErrorOr<Graphics::VirtIOGPU::ResourceID> create_2d_resource(Graphics::VirtIOGPU::Protocol::Rect rect);
|
|
ErrorOr<Graphics::VirtIOGPU::ResourceID> create_3d_resource(Graphics::VirtIOGPU::Protocol::Resource3DSpecification const& resource_3d_specification);
|
|
ErrorOr<void> delete_resource(Graphics::VirtIOGPU::ResourceID resource_id);
|
|
ErrorOr<void> ensure_backing_storage(Graphics::VirtIOGPU::ResourceID resource_id, Memory::Region const& region, size_t buffer_offset, size_t buffer_length);
|
|
ErrorOr<void> detach_backing_storage(Graphics::VirtIOGPU::ResourceID resource_id);
|
|
ErrorOr<void> set_scanout_resource(Graphics::VirtIOGPU::ScanoutID scanout, Graphics::VirtIOGPU::ResourceID resource_id, Graphics::VirtIOGPU::Protocol::Rect rect);
|
|
ErrorOr<void> transfer_framebuffer_data_to_host(Graphics::VirtIOGPU::ScanoutID scanout, Graphics::VirtIOGPU::ResourceID resource_id, Graphics::VirtIOGPU::Protocol::Rect const& rect);
|
|
ErrorOr<void> flush_displayed_image(Graphics::VirtIOGPU::ResourceID resource_id, Graphics::VirtIOGPU::Protocol::Rect const& dirty_rect);
|
|
ErrorOr<void> query_and_set_edid(u32 scanout_id, VirtIODisplayConnector& display_connector);
|
|
|
|
size_t m_num_scanouts { 0 };
|
|
Scanout m_scanouts[VIRTIO_GPU_MAX_SCANOUTS];
|
|
|
|
VirtIO::Configuration const* m_device_configuration { nullptr };
|
|
// Note: Resource ID 0 is invalid, and we must not allocate 0 as the first resource ID.
|
|
Atomic<u32> m_resource_id_counter { 1 };
|
|
SpinlockProtected<Bitmap, LockRank::None> m_active_context_ids {};
|
|
LockRefPtr<VirtIOGPU3DDevice> m_3d_device;
|
|
bool m_has_virgl_support { false };
|
|
|
|
Spinlock<LockRank::None> m_operation_lock {};
|
|
NonnullOwnPtr<Memory::Region> m_scratch_space;
|
|
};
|
|
}
|