summaryrefslogtreecommitdiff
path: root/Kernel/Graphics
diff options
context:
space:
mode:
authorSahan Fernando <sahan.h.fernando@gmail.com>2022-02-13 16:45:30 +1100
committerAli Mohammad Pur <Ali.mpfard@gmail.com>2022-03-09 14:58:48 +0330
commitfd6a536c60d1bedae92cf2e6e1e1b203980317c2 (patch)
tree4c37ac6600f1ed03216d6e84665c8fcc0de4df0a /Kernel/Graphics
parent966989afe8ec95283cde5145e8306aa3ff9d708c (diff)
downloadserenity-fd6a536c60d1bedae92cf2e6e1e1b203980317c2.zip
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.
Diffstat (limited to 'Kernel/Graphics')
-rw-r--r--Kernel/Graphics/VirtIOGPU/FramebufferDevice.cpp6
-rw-r--r--Kernel/Graphics/VirtIOGPU/GPU3DDevice.cpp97
-rw-r--r--Kernel/Graphics/VirtIOGPU/GPU3DDevice.h111
-rw-r--r--Kernel/Graphics/VirtIOGPU/GraphicsAdapter.cpp119
-rw-r--r--Kernel/Graphics/VirtIOGPU/GraphicsAdapter.h18
-rw-r--r--Kernel/Graphics/VirtIOGPU/Protocol.h159
6 files changed, 502 insertions, 8 deletions
diff --git a/Kernel/Graphics/VirtIOGPU/FramebufferDevice.cpp b/Kernel/Graphics/VirtIOGPU/FramebufferDevice.cpp
index 9e4d3a9c01..74c4bef463 100644
--- a/Kernel/Graphics/VirtIOGPU/FramebufferDevice.cpp
+++ b/Kernel/Graphics/VirtIOGPU/FramebufferDevice.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;
diff --git a/Kernel/Graphics/VirtIOGPU/GPU3DDevice.cpp b/Kernel/Graphics/VirtIOGPU/GPU3DDevice.cpp
new file mode 100644
index 0000000000..7114216da5
--- /dev/null
+++ b/Kernel/Graphics/VirtIOGPU/GPU3DDevice.cpp
@@ -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;
+}
+
+}
diff --git a/Kernel/Graphics/VirtIOGPU/GPU3DDevice.h b/Kernel/Graphics/VirtIOGPU/GPU3DDevice.h
new file mode 100644
index 0000000000..2e41e9ef79
--- /dev/null
+++ b/Kernel/Graphics/VirtIOGPU/GPU3DDevice.h
@@ -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;
+};
+
+}
diff --git a/Kernel/Graphics/VirtIOGPU/GraphicsAdapter.cpp b/Kernel/Graphics/VirtIOGPU/GraphicsAdapter.cpp
index 6580a9a2cf..62e3c0e714 100644
--- a/Kernel/Graphics/VirtIOGPU/GraphicsAdapter.cpp
+++ b/Kernel/Graphics/VirtIOGPU/GraphicsAdapter.cpp
@@ -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));
+}
+
}
diff --git a/Kernel/Graphics/VirtIOGPU/GraphicsAdapter.h b/Kernel/Graphics/VirtIOGPU/GraphicsAdapter.h
index a04e241d59..579aafb69c 100644
--- a/Kernel/Graphics/VirtIOGPU/GraphicsAdapter.h
+++ b/Kernel/Graphics/VirtIOGPU/GraphicsAdapter.h
@@ -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;
};
}
diff --git a/Kernel/Graphics/VirtIOGPU/Protocol.h b/Kernel/Graphics/VirtIOGPU/Protocol.h
index 704f565352..e8c3483185 100644
--- a/Kernel/Graphics/VirtIOGPU/Protocol.h
+++ b/Kernel/Graphics/VirtIOGPU/Protocol.h
@@ -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;
+};
+
}