mirror of
https://github.com/RGBCube/serenity
synced 2025-07-26 01:27:43 +00:00
Kernel: Implement basic VirGL device
This commit flips VirtIOGPU back to using a Mutex for its operation lock (instead of a spinlock). This is necessary for avoiding a few system hangs when queuing actions on the driver from multiple processes, which becomes much more of an issue when using VirGL from multiple userspace process. This does result in a few code paths where we inevitably have to grab a mutex from inside a spinlock, the only way to fix both issues is to move to issuing asynchronous virtio gpu commands.
This commit is contained in:
parent
966989afe8
commit
fd6a536c60
7 changed files with 503 additions and 8 deletions
|
@ -86,6 +86,7 @@ set(KERNEL_SOURCES
|
|||
Graphics/VGA/PCIAdapter.cpp
|
||||
Graphics/VirtIOGPU/FramebufferDevice.cpp
|
||||
Graphics/VirtIOGPU/Console.cpp
|
||||
Graphics/VirtIOGPU/GPU3DDevice.cpp
|
||||
Graphics/VirtIOGPU/GraphicsAdapter.cpp
|
||||
Graphics/GenericFramebufferDevice.cpp
|
||||
SanCov.cpp
|
||||
|
|
|
@ -108,7 +108,7 @@ ErrorOr<void> FramebufferDevice::flush_head_buffer(size_t)
|
|||
}
|
||||
ErrorOr<void> FramebufferDevice::flush_rectangle(size_t buffer_index, FBRect const& rect)
|
||||
{
|
||||
SpinlockLocker locker(adapter()->operation_lock());
|
||||
MutexLocker locker(adapter()->operation_lock());
|
||||
Protocol::Rect dirty_rect {
|
||||
.x = rect.x,
|
||||
.y = rect.y,
|
||||
|
@ -165,7 +165,7 @@ FramebufferDevice::~FramebufferDevice()
|
|||
|
||||
ErrorOr<void> FramebufferDevice::create_framebuffer()
|
||||
{
|
||||
SpinlockLocker locker(adapter()->operation_lock());
|
||||
MutexLocker locker(adapter()->operation_lock());
|
||||
// First delete any existing framebuffers to free the memory first
|
||||
m_framebuffer = nullptr;
|
||||
m_framebuffer_sink_vmobject = nullptr;
|
||||
|
@ -255,7 +255,7 @@ void FramebufferDevice::flush_displayed_image(Protocol::Rect const& dirty_rect,
|
|||
void FramebufferDevice::set_buffer(int buffer_index)
|
||||
{
|
||||
auto& buffer = buffer_index == 0 ? m_main_buffer : m_back_buffer;
|
||||
SpinlockLocker locker(adapter()->operation_lock());
|
||||
MutexLocker locker(adapter()->operation_lock());
|
||||
if (&buffer == m_current_buffer)
|
||||
return;
|
||||
m_current_buffer = &buffer;
|
||||
|
|
97
Kernel/Graphics/VirtIOGPU/GPU3DDevice.cpp
Normal file
97
Kernel/Graphics/VirtIOGPU/GPU3DDevice.cpp
Normal file
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
* Copyright (c) 2021, Sahan Fernando <sahan.h.fernando@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <Kernel/API/VirGL.h>
|
||||
#include <Kernel/Graphics/GraphicsManagement.h>
|
||||
#include <Kernel/Graphics/VirtIOGPU/Console.h>
|
||||
#include <Kernel/Graphics/VirtIOGPU/GPU3DDevice.h>
|
||||
#include <Kernel/Graphics/VirtIOGPU/GraphicsAdapter.h>
|
||||
#include <Kernel/Graphics/VirtIOGPU/Protocol.h>
|
||||
#include <Kernel/Random.h>
|
||||
#include <LibC/sys/ioctl_numbers.h>
|
||||
|
||||
namespace Kernel::Graphics::VirtIOGPU {
|
||||
|
||||
GPU3DDevice::GPU3DDevice(GraphicsAdapter& graphics_adapter)
|
||||
: CharacterDevice(28, 0)
|
||||
, m_graphics_adapter(graphics_adapter)
|
||||
{
|
||||
m_kernel_context_id = m_graphics_adapter.create_context();
|
||||
|
||||
// Setup memory transfer region
|
||||
auto region_result = MM.allocate_kernel_region(
|
||||
NUM_TRANSFER_REGION_PAGES * PAGE_SIZE,
|
||||
"VIRGL3D upload buffer",
|
||||
Memory::Region::Access::ReadWrite,
|
||||
AllocationStrategy::AllocateNow);
|
||||
VERIFY(!region_result.is_error());
|
||||
m_transfer_buffer_region = region_result.release_value();
|
||||
}
|
||||
|
||||
ErrorOr<void> GPU3DDevice::ioctl(OpenFileDescription&, unsigned request, Userspace<void*> arg)
|
||||
{
|
||||
// TODO: We really should have ioctls for destroying resources as well
|
||||
switch (request) {
|
||||
case VIRGL_IOCTL_TRANSFER_DATA: {
|
||||
auto user_transfer_descriptor = static_ptr_cast<VirGLTransferDescriptor const*>(arg);
|
||||
auto transfer_descriptor = TRY(copy_typed_from_user(user_transfer_descriptor));
|
||||
if (transfer_descriptor.direction == VIRGL_DATA_DIR_GUEST_TO_HOST) {
|
||||
if (transfer_descriptor.offset_in_region + transfer_descriptor.num_bytes > NUM_TRANSFER_REGION_PAGES * PAGE_SIZE) {
|
||||
return EOVERFLOW;
|
||||
}
|
||||
auto target = m_transfer_buffer_region->vaddr().offset(transfer_descriptor.offset_in_region).as_ptr();
|
||||
return copy_from_user(target, transfer_descriptor.data, transfer_descriptor.num_bytes);
|
||||
} else if (transfer_descriptor.direction == VIRGL_DATA_DIR_HOST_TO_GUEST) {
|
||||
if (transfer_descriptor.offset_in_region + transfer_descriptor.num_bytes > NUM_TRANSFER_REGION_PAGES * PAGE_SIZE) {
|
||||
return EOVERFLOW;
|
||||
}
|
||||
auto source = m_transfer_buffer_region->vaddr().offset(transfer_descriptor.offset_in_region).as_ptr();
|
||||
return copy_to_user(transfer_descriptor.data, source, transfer_descriptor.num_bytes);
|
||||
} else {
|
||||
return EINVAL;
|
||||
}
|
||||
}
|
||||
case VIRGL_IOCTL_SUBMIT_CMD: {
|
||||
MutexLocker locker(m_graphics_adapter.operation_lock());
|
||||
auto user_command_buffer = static_ptr_cast<VirGLCommandBuffer const*>(arg);
|
||||
auto command_buffer = TRY(copy_typed_from_user(user_command_buffer));
|
||||
m_graphics_adapter.submit_command_buffer(m_kernel_context_id, [&](Bytes buffer) {
|
||||
auto num_bytes = command_buffer.num_elems * sizeof(u32);
|
||||
VERIFY(num_bytes <= buffer.size());
|
||||
MUST(copy_from_user(buffer.data(), command_buffer.data, num_bytes));
|
||||
return num_bytes;
|
||||
});
|
||||
return {};
|
||||
}
|
||||
case VIRGL_IOCTL_CREATE_RESOURCE: {
|
||||
auto user_spec = static_ptr_cast<VirGL3DResourceSpec const*>(arg);
|
||||
VirGL3DResourceSpec spec = TRY(copy_typed_from_user(user_spec));
|
||||
|
||||
Protocol::Resource3DSpecification const resource_spec = {
|
||||
.target = static_cast<Protocol::Gallium::PipeTextureTarget>(spec.target),
|
||||
.format = spec.format,
|
||||
.bind = spec.bind,
|
||||
.width = spec.width,
|
||||
.height = spec.height,
|
||||
.depth = spec.depth,
|
||||
.array_size = spec.array_size,
|
||||
.last_level = spec.last_level,
|
||||
.nr_samples = spec.nr_samples,
|
||||
.flags = spec.flags
|
||||
};
|
||||
MutexLocker locker(m_graphics_adapter.operation_lock());
|
||||
auto resource_id = m_graphics_adapter.create_3d_resource(resource_spec).value();
|
||||
m_graphics_adapter.attach_resource_to_context(resource_id, m_kernel_context_id);
|
||||
m_graphics_adapter.ensure_backing_storage(resource_id, *m_transfer_buffer_region, 0, NUM_TRANSFER_REGION_PAGES * PAGE_SIZE);
|
||||
spec.created_resource_id = resource_id;
|
||||
// FIXME: We should delete the resource we just created if we fail to copy the resource id out
|
||||
return copy_to_user(static_ptr_cast<VirGL3DResourceSpec*>(arg), &spec);
|
||||
}
|
||||
}
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
}
|
111
Kernel/Graphics/VirtIOGPU/GPU3DDevice.h
Normal file
111
Kernel/Graphics/VirtIOGPU/GPU3DDevice.h
Normal file
|
@ -0,0 +1,111 @@
|
|||
/*
|
||||
* Copyright (c) 2021, Sahan Fernando <sahan.h.fernando@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/DistinctNumeric.h>
|
||||
#include <Kernel/Devices/CharacterDevice.h>
|
||||
#include <Kernel/Graphics/VirtIOGPU/FramebufferDevice.h>
|
||||
#include <Kernel/Graphics/VirtIOGPU/Protocol.h>
|
||||
|
||||
namespace Kernel::Graphics::VirtIOGPU {
|
||||
|
||||
enum class VirGLCommand : u32 {
|
||||
NOP = 0,
|
||||
CREATE_OBJECT = 1,
|
||||
BIND_OBJECT,
|
||||
DESTROY_OBJECT,
|
||||
SET_VIEWPORT_STATE,
|
||||
SET_FRAMEBUFFER_STATE,
|
||||
SET_VERTEX_BUFFERS,
|
||||
CLEAR,
|
||||
DRAW_VBO,
|
||||
RESOURCE_INLINE_WRITE,
|
||||
SET_SAMPLER_VIEWS,
|
||||
SET_INDEX_BUFFER,
|
||||
SET_CONSTANT_BUFFER,
|
||||
SET_STENCIL_REF,
|
||||
SET_BLEND_COLOR,
|
||||
SET_SCISSOR_STATE,
|
||||
BLIT,
|
||||
RESOURCE_COPY_REGION,
|
||||
BIND_SAMPLER_STATES,
|
||||
BEGIN_QUERY,
|
||||
END_QUERY,
|
||||
GET_QUERY_RESULT,
|
||||
SET_POLYGON_STIPPLE,
|
||||
SET_CLIP_STATE,
|
||||
SET_SAMPLE_MASK,
|
||||
SET_STREAMOUT_TARGETS,
|
||||
SET_RENDER_CONDITION,
|
||||
SET_UNIFORM_BUFFER,
|
||||
|
||||
SET_SUB_CTX,
|
||||
CREATE_SUB_CTX,
|
||||
DESTROY_SUB_CTX,
|
||||
BIND_SHADER,
|
||||
SET_TESS_STATE,
|
||||
SET_MIN_SAMPLES,
|
||||
SET_SHADER_BUFFERS,
|
||||
SET_SHADER_IMAGES,
|
||||
MEMORY_BARRIER,
|
||||
LAUNCH_GRID,
|
||||
SET_FRAMEBUFFER_STATE_NO_ATTACH,
|
||||
TEXTURE_BARRIER,
|
||||
SET_ATOMIC_BUFFERS,
|
||||
SET_DBG_FLAGS,
|
||||
GET_QUERY_RESULT_QBO,
|
||||
TRANSFER3D,
|
||||
END_TRANSFERS,
|
||||
COPY_TRANSFER3D,
|
||||
SET_TWEAKS,
|
||||
CLEAR_TEXTURE,
|
||||
PIPE_RESOURCE_CREATE,
|
||||
PIPE_RESOURCE_SET_TYPE,
|
||||
GET_MEMORY_INFO,
|
||||
SEND_STRING_MARKER,
|
||||
MAX_COMMANDS
|
||||
};
|
||||
|
||||
union ClearType {
|
||||
struct {
|
||||
u32 depth : 1;
|
||||
u32 stencil : 1;
|
||||
u32 color0 : 1;
|
||||
u32 color1 : 1;
|
||||
u32 color2 : 1;
|
||||
u32 color3 : 1;
|
||||
u32 color4 : 1;
|
||||
u32 color5 : 1;
|
||||
u32 color6 : 1;
|
||||
u32 color7 : 1;
|
||||
} flags;
|
||||
u32 value;
|
||||
};
|
||||
|
||||
class GPU3DDevice : public CharacterDevice {
|
||||
public:
|
||||
GPU3DDevice() = delete;
|
||||
explicit GPU3DDevice(GraphicsAdapter& graphics_adapter);
|
||||
|
||||
virtual bool can_read(const OpenFileDescription&, u64) const override { return true; }
|
||||
virtual bool can_write(const OpenFileDescription&, u64) const override { return true; }
|
||||
virtual ErrorOr<size_t> read(OpenFileDescription&, u64, UserOrKernelBuffer&, size_t) override { return ENOTSUP; }
|
||||
virtual ErrorOr<size_t> write(OpenFileDescription&, u64, const UserOrKernelBuffer&, size_t) override { return ENOTSUP; }
|
||||
virtual StringView class_name() const override { return "virgl3d"; }
|
||||
|
||||
virtual ErrorOr<void> ioctl(OpenFileDescription&, unsigned request, Userspace<void*> arg) override;
|
||||
|
||||
private:
|
||||
Kernel::Graphics::VirtIOGPU::GraphicsAdapter& m_graphics_adapter;
|
||||
// Context used for kernel operations (e.g. flushing resources to scanout)
|
||||
ContextID m_kernel_context_id;
|
||||
// Memory management for backing buffers
|
||||
OwnPtr<Memory::Region> m_transfer_buffer_region;
|
||||
constexpr static size_t NUM_TRANSFER_REGION_PAGES = 256;
|
||||
};
|
||||
|
||||
}
|
|
@ -7,10 +7,12 @@
|
|||
#include <AK/BinaryBufferWriter.h>
|
||||
#include <Kernel/Bus/PCI/API.h>
|
||||
#include <Kernel/Bus/PCI/IDs.h>
|
||||
#include <Kernel/Devices/DeviceManagement.h>
|
||||
#include <Kernel/Graphics/Console/GenericFramebufferConsole.h>
|
||||
#include <Kernel/Graphics/GraphicsManagement.h>
|
||||
#include <Kernel/Graphics/VirtIOGPU/Console.h>
|
||||
#include <Kernel/Graphics/VirtIOGPU/FramebufferDevice.h>
|
||||
#include <Kernel/Graphics/VirtIOGPU/GPU3DDevice.h>
|
||||
#include <Kernel/Graphics/VirtIOGPU/GraphicsAdapter.h>
|
||||
|
||||
namespace Kernel::Graphics::VirtIOGPU {
|
||||
|
@ -74,8 +76,11 @@ void GraphicsAdapter::initialize()
|
|||
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_VIRGL)) {
|
||||
dbgln_if(VIRTIO_DEBUG, "VirtIO::GraphicsAdapter: VirGL is available, enabling");
|
||||
negotiated |= VIRTIO_GPU_F_VIRGL;
|
||||
m_has_virgl_support = true;
|
||||
}
|
||||
if (is_feature_set(supported_features, VIRTIO_GPU_F_EDID))
|
||||
negotiated |= VIRTIO_GPU_F_EDID;
|
||||
return negotiated;
|
||||
|
@ -89,7 +94,8 @@ void GraphicsAdapter::initialize()
|
|||
}
|
||||
VERIFY(success);
|
||||
finish_init();
|
||||
SpinlockLocker locker(m_operation_lock);
|
||||
initialize_3d_device();
|
||||
MutexLocker locker(m_operation_lock);
|
||||
// Get display information using VIRTIO_GPU_CMD_GET_DISPLAY_INFO
|
||||
query_display_information();
|
||||
query_display_edid({});
|
||||
|
@ -265,6 +271,28 @@ ResourceID GraphicsAdapter::create_2d_resource(Protocol::Rect rect)
|
|||
return resource_id;
|
||||
}
|
||||
|
||||
ResourceID GraphicsAdapter::create_3d_resource(Protocol::Resource3DSpecification const& resource_3d_specification)
|
||||
{
|
||||
VERIFY(m_operation_lock.is_locked());
|
||||
auto writer = create_scratchspace_writer();
|
||||
auto& request = writer.append_structure<Protocol::ResourceCreate3D>();
|
||||
auto& response = writer.append_structure<Protocol::ControlHeader>();
|
||||
|
||||
populate_virtio_gpu_request_header(request.header, Protocol::CommandType::VIRTIO_GPU_CMD_RESOURCE_CREATE_3D, VIRTIO_GPU_FLAG_FENCE);
|
||||
|
||||
auto resource_id = allocate_resource_id();
|
||||
request.resource_id = resource_id.value();
|
||||
// TODO: Abstract this out a bit more
|
||||
u32* start_of_copied_fields = &request.target;
|
||||
memcpy(start_of_copied_fields, &resource_3d_specification, sizeof(Protocol::Resource3DSpecification));
|
||||
|
||||
synchronous_virtio_gpu_command(start_of_scratch_space(), sizeof(request), sizeof(response));
|
||||
|
||||
VERIFY(response.type == static_cast<u32>(Protocol::CommandType::VIRTIO_GPU_RESP_OK_NODATA));
|
||||
dbgln_if(VIRTIO_DEBUG, "VirtIO::GraphicsAdapter: Allocated 3d resource with id {}", resource_id.value());
|
||||
return resource_id;
|
||||
}
|
||||
|
||||
void GraphicsAdapter::ensure_backing_storage(ResourceID resource_id, Memory::Region const& region, size_t buffer_offset, size_t buffer_length)
|
||||
{
|
||||
VERIFY(m_operation_lock.is_locked());
|
||||
|
@ -395,7 +423,7 @@ void GraphicsAdapter::populate_virtio_gpu_request_header(Protocol::ControlHeader
|
|||
|
||||
void GraphicsAdapter::flush_dirty_rectangle(ScanoutID scanout_id, ResourceID resource_id, Protocol::Rect const& dirty_rect)
|
||||
{
|
||||
SpinlockLocker locker(m_operation_lock);
|
||||
MutexLocker locker(m_operation_lock);
|
||||
transfer_framebuffer_data_to_host(scanout_id, resource_id, dirty_rect);
|
||||
flush_displayed_image(resource_id, dirty_rect);
|
||||
}
|
||||
|
@ -407,6 +435,14 @@ ResourceID GraphicsAdapter::allocate_resource_id()
|
|||
return m_resource_id_counter;
|
||||
}
|
||||
|
||||
ContextID GraphicsAdapter::allocate_context_id()
|
||||
{
|
||||
// FIXME: This should really be tracked using a bitmap, instead of an atomic counter
|
||||
VERIFY(m_operation_lock.is_locked());
|
||||
m_context_id_counter = m_context_id_counter.value() + 1;
|
||||
return m_context_id_counter;
|
||||
}
|
||||
|
||||
void GraphicsAdapter::delete_resource(ResourceID resource_id)
|
||||
{
|
||||
VERIFY(m_operation_lock.is_locked());
|
||||
|
@ -422,4 +458,79 @@ void GraphicsAdapter::delete_resource(ResourceID resource_id)
|
|||
VERIFY(response.type == to_underlying(Protocol::CommandType::VIRTIO_GPU_RESP_OK_NODATA));
|
||||
}
|
||||
|
||||
void GraphicsAdapter::initialize_3d_device()
|
||||
{
|
||||
if (m_has_virgl_support) {
|
||||
MutexLocker locker(m_operation_lock);
|
||||
m_3d_device = MUST(DeviceManagement::try_create_device<VirtIOGPU::GPU3DDevice>(*this));
|
||||
}
|
||||
}
|
||||
|
||||
ContextID GraphicsAdapter::create_context()
|
||||
{
|
||||
VERIFY(m_operation_lock.is_locked());
|
||||
auto ctx_id = allocate_context_id();
|
||||
auto writer = create_scratchspace_writer();
|
||||
auto& request = writer.append_structure<Protocol::ContextCreate>();
|
||||
auto& response = writer.append_structure<Protocol::ControlHeader>();
|
||||
|
||||
constexpr char const* region_name = "Serenity VirGL3D Context";
|
||||
populate_virtio_gpu_request_header(request.header, Protocol::CommandType::VIRTIO_GPU_CMD_CTX_CREATE, VIRTIO_GPU_FLAG_FENCE);
|
||||
request.header.context_id = ctx_id.value();
|
||||
request.name_length = strlen(region_name);
|
||||
memset(request.debug_name.data(), 0, 64);
|
||||
VERIFY(request.name_length <= 64);
|
||||
memcpy(request.debug_name.data(), region_name, request.name_length);
|
||||
|
||||
synchronous_virtio_gpu_command(start_of_scratch_space(), sizeof(request), sizeof(response));
|
||||
|
||||
VERIFY(response.type == to_underlying(Protocol::CommandType::VIRTIO_GPU_RESP_OK_NODATA));
|
||||
return ctx_id;
|
||||
}
|
||||
|
||||
void GraphicsAdapter::submit_command_buffer(ContextID context_id, Function<size_t(Bytes)> buffer_writer)
|
||||
{
|
||||
VERIFY(m_operation_lock.is_locked());
|
||||
auto writer = create_scratchspace_writer();
|
||||
auto& request = writer.append_structure<Protocol::CommandSubmit>();
|
||||
|
||||
populate_virtio_gpu_request_header(request.header, Protocol::CommandType::VIRTIO_GPU_CMD_SUBMIT_3D, VIRTIO_GPU_FLAG_FENCE);
|
||||
request.header.context_id = context_id.value();
|
||||
|
||||
auto max_command_buffer_length = m_scratch_space->size() - sizeof(request) - sizeof(Protocol::ControlHeader);
|
||||
// Truncate to nearest multiple of alignment, to ensure padding loop doesn't exhaust allocated space
|
||||
max_command_buffer_length -= max_command_buffer_length % alignof(Protocol::ControlHeader);
|
||||
Bytes command_buffer_buffer(m_scratch_space->vaddr().offset(sizeof(request)).as_ptr(), max_command_buffer_length);
|
||||
request.size = buffer_writer(command_buffer_buffer);
|
||||
writer.skip_bytes(request.size);
|
||||
// The alignment of a ControlHeader may be a few words larger than the length of a command buffer, so
|
||||
// we pad with no-ops until we reach the correct alignment
|
||||
while (writer.current_offset() % alignof(Protocol::ControlHeader) != 0) {
|
||||
VERIFY((writer.current_offset() % alignof(Protocol::ControlHeader)) % sizeof(u32) == 0);
|
||||
writer.append_structure<u32>() = to_underlying(VirGLCommand::NOP);
|
||||
request.size += 4;
|
||||
}
|
||||
dbgln_if(VIRTIO_DEBUG, "VirtIO::GraphicsAdapter: Sending command buffer of length {}", request.size);
|
||||
auto& response = writer.append_structure<Protocol::ControlHeader>();
|
||||
|
||||
synchronous_virtio_gpu_command(start_of_scratch_space(), sizeof(request) + request.size, sizeof(response));
|
||||
|
||||
VERIFY(response.type == to_underlying(Protocol::CommandType::VIRTIO_GPU_RESP_OK_NODATA));
|
||||
}
|
||||
|
||||
void GraphicsAdapter::attach_resource_to_context(ResourceID resource_id, ContextID context_id)
|
||||
{
|
||||
VERIFY(m_operation_lock.is_locked());
|
||||
auto writer = create_scratchspace_writer();
|
||||
auto& request = writer.append_structure<Protocol::ContextAttachResource>();
|
||||
auto& response = writer.append_structure<Protocol::ControlHeader>();
|
||||
populate_virtio_gpu_request_header(request.header, Protocol::CommandType::VIRTIO_GPU_CMD_CTX_ATTACH_RESOURCE, VIRTIO_GPU_FLAG_FENCE);
|
||||
request.header.context_id = context_id.value();
|
||||
request.resource_id = resource_id.value();
|
||||
|
||||
synchronous_virtio_gpu_command(start_of_scratch_space(), sizeof(request), sizeof(response));
|
||||
|
||||
VERIFY(response.type == to_underlying(Protocol::CommandType::VIRTIO_GPU_RESP_OK_NODATA));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
|
||||
namespace Kernel::Graphics::VirtIOGPU {
|
||||
|
||||
class GPU3DDevice;
|
||||
|
||||
#define VIRTIO_GPU_F_VIRGL (1 << 0)
|
||||
#define VIRTIO_GPU_F_EDID (1 << 1)
|
||||
|
||||
|
@ -47,6 +49,7 @@ public:
|
|||
virtual bool vga_compatible() const override { return false; }
|
||||
|
||||
virtual void initialize() override;
|
||||
void initialize_3d_device();
|
||||
|
||||
ErrorOr<ByteBuffer> get_edid(size_t output_port_index) const override;
|
||||
|
||||
|
@ -109,8 +112,15 @@ private:
|
|||
u32 get_pending_events();
|
||||
void clear_pending_events(u32 event_bitmask);
|
||||
|
||||
// 3D Command stuff
|
||||
ContextID create_context();
|
||||
void attach_resource_to_context(ResourceID resource_id, ContextID context_id);
|
||||
void submit_command_buffer(ContextID, Function<size_t(Bytes)> buffer_writer);
|
||||
Protocol::TextureFormat get_framebuffer_format() const { return Protocol::TextureFormat::VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM; }
|
||||
|
||||
auto& operation_lock() { return m_operation_lock; }
|
||||
ResourceID allocate_resource_id();
|
||||
ContextID allocate_context_id();
|
||||
|
||||
PhysicalAddress start_of_scratch_space() const { return m_scratch_space->physical_page(0)->paddr(); }
|
||||
AK::BinaryBufferWriter create_scratchspace_writer()
|
||||
|
@ -123,6 +133,7 @@ private:
|
|||
void query_display_information();
|
||||
void query_display_edid(Optional<ScanoutID>);
|
||||
ResourceID create_2d_resource(Protocol::Rect rect);
|
||||
ResourceID create_3d_resource(Protocol::Resource3DSpecification const& resource_3d_specification);
|
||||
void delete_resource(ResourceID resource_id);
|
||||
void ensure_backing_storage(ResourceID resource_id, Memory::Region const& region, size_t buffer_offset, size_t buffer_length);
|
||||
void detach_backing_storage(ResourceID resource_id);
|
||||
|
@ -138,10 +149,15 @@ private:
|
|||
|
||||
VirtIO::Configuration const* m_device_configuration { nullptr };
|
||||
ResourceID m_resource_id_counter { 0 };
|
||||
ContextID m_context_id_counter { 0 };
|
||||
RefPtr<GPU3DDevice> m_3d_device;
|
||||
bool m_has_virgl_support { false };
|
||||
|
||||
// Synchronous commands
|
||||
WaitQueue m_outstanding_request;
|
||||
Spinlock m_operation_lock;
|
||||
Mutex m_operation_lock;
|
||||
OwnPtr<Memory::Region> m_scratch_space;
|
||||
|
||||
friend class Kernel::Graphics::VirtIOGPU::GPU3DDevice;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -11,10 +11,28 @@
|
|||
#define VIRTIO_GPU_MAX_SCANOUTS 16
|
||||
|
||||
namespace Kernel::Graphics::VirtIOGPU {
|
||||
TYPEDEF_DISTINCT_ORDERED_ID(u32, ContextID);
|
||||
TYPEDEF_DISTINCT_ORDERED_ID(u32, ResourceID);
|
||||
TYPEDEF_DISTINCT_ORDERED_ID(u32, ScanoutID);
|
||||
};
|
||||
|
||||
#define VREND_MAX_CTX 64
|
||||
|
||||
#define VIRGL_BIND_DEPTH_STENCIL (1 << 0)
|
||||
#define VIRGL_BIND_RENDER_TARGET (1 << 1)
|
||||
#define VIRGL_BIND_SAMPLER_VIEW (1 << 3)
|
||||
#define VIRGL_BIND_VERTEX_BUFFER (1 << 4)
|
||||
#define VIRGL_BIND_INDEX_BUFFER (1 << 5)
|
||||
#define VIRGL_BIND_CONSTANT_BUFFER (1 << 6)
|
||||
#define VIRGL_BIND_DISPLAY_TARGET (1 << 7)
|
||||
#define VIRGL_BIND_COMMAND_ARGS (1 << 8)
|
||||
#define VIRGL_BIND_STREAM_OUTPUT (1 << 11)
|
||||
#define VIRGL_BIND_SHADER_BUFFER (1 << 14)
|
||||
#define VIRGL_BIND_QUERY_BUFFER (1 << 15)
|
||||
#define VIRGL_BIND_CURSOR (1 << 16)
|
||||
#define VIRGL_BIND_CUSTOM (1 << 17)
|
||||
#define VIRGL_BIND_SCANOUT (1 << 18)
|
||||
|
||||
namespace Kernel::Graphics::VirtIOGPU::Protocol {
|
||||
|
||||
// Specification equivalent: enum virtio_gpu_ctrl_type
|
||||
|
@ -32,6 +50,18 @@ enum class CommandType : u32 {
|
|||
VIRTIO_GPU_CMD_GET_CAPSET,
|
||||
VIRTIO_GPU_CMD_GET_EDID,
|
||||
|
||||
/* 3d commands */
|
||||
VIRTIO_GPU_CMD_CTX_CREATE = 0x0200,
|
||||
VIRTIO_GPU_CMD_CTX_DESTROY,
|
||||
VIRTIO_GPU_CMD_CTX_ATTACH_RESOURCE,
|
||||
VIRTIO_GPU_CMD_CTX_DETACH_RESOURCE,
|
||||
VIRTIO_GPU_CMD_RESOURCE_CREATE_3D,
|
||||
VIRTIO_GPU_CMD_TRANSFER_TO_HOST_3D,
|
||||
VIRTIO_GPU_CMD_TRANSFER_FROM_HOST_3D,
|
||||
VIRTIO_GPU_CMD_SUBMIT_3D,
|
||||
VIRTIO_GPU_CMD_RESOURCE_MAP_BLOB,
|
||||
VIRTIO_GPU_CMD_RESOURCE_UNMAP_BLOB,
|
||||
|
||||
/* cursor commands */
|
||||
VIRTIO_GPU_CMD_UPDATE_CURSOR = 0x0300,
|
||||
VIRTIO_GPU_CMD_MOVE_CURSOR,
|
||||
|
@ -52,6 +82,54 @@ enum class CommandType : u32 {
|
|||
VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER,
|
||||
};
|
||||
|
||||
enum class ObjectType : u32 {
|
||||
NONE,
|
||||
BLEND,
|
||||
RASTERIZER,
|
||||
DSA,
|
||||
SHADER,
|
||||
VERTEX_ELEMENTS,
|
||||
SAMPLER_VIEW,
|
||||
SAMPLER_STATE,
|
||||
SURFACE,
|
||||
QUERY,
|
||||
STREAMOUT_TARGET,
|
||||
MSAA_SURFACE,
|
||||
MAX_OBJECTS,
|
||||
};
|
||||
|
||||
enum class PipeTextureTarget : u32 {
|
||||
BUFFER = 0,
|
||||
TEXTURE_1D,
|
||||
TEXTURE_2D,
|
||||
TEXTURE_3D,
|
||||
TEXTURE_CUBE,
|
||||
TEXTURE_RECT,
|
||||
TEXTURE_1D_ARRAY,
|
||||
TEXTURE_2D_ARRAY,
|
||||
TEXTURE_CUBE_ARRAY,
|
||||
MAX
|
||||
};
|
||||
|
||||
enum class PipePrimitiveTypes : u32 {
|
||||
POINTS = 0,
|
||||
LINES,
|
||||
LINE_LOOP,
|
||||
LINE_STRIP,
|
||||
TRIANGLES,
|
||||
TRIANGLE_STRIP,
|
||||
TRIANGLE_FAN,
|
||||
QUADS,
|
||||
QUAD_STRIP,
|
||||
POLYGON,
|
||||
LINES_ADJACENCY,
|
||||
LINE_STRIP_ADJACENCY,
|
||||
TRIANGLES_ADJACENCY,
|
||||
TRIANGLE_STRIP_ADJACENCY,
|
||||
PATCHES,
|
||||
MAX
|
||||
};
|
||||
|
||||
// Specification equivalent: struct virtio_gpu_ctrl_hdr
|
||||
struct ControlHeader {
|
||||
u32 type;
|
||||
|
@ -103,6 +181,23 @@ struct ResourceCreate2D {
|
|||
u32 height;
|
||||
};
|
||||
|
||||
// Specification equivalent: struct virtio_gpu_resource_create_3d
|
||||
struct ResourceCreate3D {
|
||||
ControlHeader header;
|
||||
u32 resource_id;
|
||||
u32 target;
|
||||
u32 format;
|
||||
u32 bind;
|
||||
u32 width;
|
||||
u32 height;
|
||||
u32 depth;
|
||||
u32 array_size;
|
||||
u32 last_level;
|
||||
u32 nr_samples;
|
||||
u32 flags;
|
||||
u32 padding;
|
||||
};
|
||||
|
||||
// Specification equivalent: struct virtio_gpu_resource_unref
|
||||
struct ResourceUnref {
|
||||
ControlHeader header;
|
||||
|
@ -171,4 +266,68 @@ struct GetEDIDResponse {
|
|||
u8 edid[1024];
|
||||
};
|
||||
|
||||
// No equivalent in specification
|
||||
struct ContextCreate {
|
||||
ControlHeader header;
|
||||
u32 name_length;
|
||||
u32 padding;
|
||||
AK::Array<char, 64> debug_name;
|
||||
};
|
||||
|
||||
static_assert(sizeof(ContextCreate::debug_name) == 64);
|
||||
|
||||
// No equivalent in specification
|
||||
struct ContextAttachResource {
|
||||
ControlHeader header;
|
||||
u32 resource_id;
|
||||
u32 padding;
|
||||
};
|
||||
|
||||
// No equivalent in specification
|
||||
struct CommandSubmit {
|
||||
ControlHeader header;
|
||||
u32 size;
|
||||
u32 padding;
|
||||
};
|
||||
|
||||
namespace Gallium {
|
||||
|
||||
enum class PipeTextureTarget : u32 {
|
||||
BUFFER,
|
||||
TEXTURE_1D,
|
||||
TEXTURE_2D,
|
||||
TEXTURE_3D,
|
||||
TEXTURE_CUBE,
|
||||
TEXTURE_RECT,
|
||||
TEXTURE_1D_ARRAY,
|
||||
TEXTURE_2D_ARRAY,
|
||||
TEXTURE_CUBE_ARRAY,
|
||||
MAX_TEXTURE_TYPES,
|
||||
};
|
||||
|
||||
enum class ShaderType : u32 {
|
||||
SHADER_VERTEX = 0,
|
||||
SHADER_FRAGMENT,
|
||||
SHADER_GEOMETRY,
|
||||
SHADER_TESS_CTRL,
|
||||
SHADER_TESS_EVAL,
|
||||
SHADER_COMPUTE,
|
||||
SHADER_TYPES
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
struct Resource3DSpecification {
|
||||
Gallium::PipeTextureTarget target;
|
||||
u32 format;
|
||||
u32 bind;
|
||||
u32 width;
|
||||
u32 height;
|
||||
u32 depth;
|
||||
u32 array_size;
|
||||
u32 last_level;
|
||||
u32 nr_samples;
|
||||
u32 flags;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue