From aaabc1b32d9e514b31257826f3c2fc60babe0e21 Mon Sep 17 00:00:00 2001 From: Tristan Ross Date: Thu, 15 May 2025 23:07:03 -0700 Subject: [PATCH] feat(gpu): adding linux-drm --- build.zig | 9 +++ build.zig.zon | 4 + lib/phantom/gpu.zig | 3 + lib/phantom/gpu/Device.zig | 4 +- lib/phantom/gpu/backend.zig | 9 +++ lib/phantom/gpu/backend/linux_drm.zig | 11 +++ .../gpu/backend/linux_drm/Connector.zig | 0 lib/phantom/gpu/backend/linux_drm/Device.zig | 58 +++++++++++++ .../gpu/backend/linux_drm/Provider.zig | 81 +++++++++++++++++++ 9 files changed, 177 insertions(+), 2 deletions(-) create mode 100644 lib/phantom/gpu/backend.zig create mode 100644 lib/phantom/gpu/backend/linux_drm.zig create mode 100644 lib/phantom/gpu/backend/linux_drm/Connector.zig create mode 100644 lib/phantom/gpu/backend/linux_drm/Device.zig create mode 100644 lib/phantom/gpu/backend/linux_drm/Provider.zig diff --git a/build.zig b/build.zig index 6b6e5d4..bd91b25 100644 --- a/build.zig +++ b/build.zig @@ -30,6 +30,15 @@ pub fn build(b: *std.Build) void { }, }); + if (target.result.os.tag == .linux) { + const libdrm = b.dependency("libdrm", .{ + .target = target, + .optimize = optimize, + }); + + module.addImport("libdrm", libdrm.module("libdrm")); + } + const autodoc_test = b.addObject(.{ .name = "phantom", .root_module = module, diff --git a/build.zig.zon b/build.zig.zon index cab7046..e592d89 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -15,6 +15,10 @@ .url = "https://codeberg.org/ifreund/zig-wayland/archive/f3c5d503e540ada8cbcb056420de240af0c094f7.tar.gz", .hash = "wayland-0.4.0-dev-lQa1kjfIAQCmhhQu3xF0KH-94-TzeMXOqfnP0-Dg6Wyy", }, + .libdrm = .{ + .url = "https://github.com/MidstallSoftware/libdrm.zig/archive/d020314c5fcd78d64bdeecda3a42d0e43522f9af.tar.gz", + .hash = "libdrm-0.1.0-iX14LQFJAQAEHpJCxO9os_WFkU-GVD1kuLKkWnGqQRxz", + }, }, .fingerprint = 0x6896f6aeaa10b7f9, } diff --git a/lib/phantom/gpu.zig b/lib/phantom/gpu.zig index 0534aaf..1a9a67f 100644 --- a/lib/phantom/gpu.zig +++ b/lib/phantom/gpu.zig @@ -1,9 +1,12 @@ +pub const backend = @import("gpu/backend.zig"); + pub const Connector = @import("gpu/Connector.zig"); pub const Device = @import("gpu/Device.zig"); pub const Provider = @import("gpu/Provider.zig"); pub const Texture = @import("gpu/Texture.zig"); test { + _ = backend; _ = Connector; _ = Device; _ = Provider; diff --git a/lib/phantom/gpu/Device.zig b/lib/phantom/gpu/Device.zig index 5e3cd01..4ce6111 100644 --- a/lib/phantom/gpu/Device.zig +++ b/lib/phantom/gpu/Device.zig @@ -3,14 +3,14 @@ const Connector = @import("Connector.zig"); const Self = @This(); pub const VTable = struct { - getConnectors: *const fn (*anyopaque) anyerror![]*Connector, + getConnectors: *const fn (*anyopaque) anyerror![]const *Connector, destroy: *const fn (*anyopaque) void, }; ptr: *anyopaque, vtable: *const VTable, -pub inline fn getConnectors(self: *Self) anyerror![]*Connector { +pub inline fn getConnectors(self: *Self) anyerror![]const *Connector { return self.vtable.getConnectors(self.ptr); } diff --git a/lib/phantom/gpu/backend.zig b/lib/phantom/gpu/backend.zig new file mode 100644 index 0000000..9daaa38 --- /dev/null +++ b/lib/phantom/gpu/backend.zig @@ -0,0 +1,9 @@ +const builtin = @import("builtin"); + +pub const linux_drm = @import("backend/linux_drm.zig"); + +test { + if (builtin.os.tag == .linux) { + _ = linux_drm; + } +} diff --git a/lib/phantom/gpu/backend/linux_drm.zig b/lib/phantom/gpu/backend/linux_drm.zig new file mode 100644 index 0000000..c6622ce --- /dev/null +++ b/lib/phantom/gpu/backend/linux_drm.zig @@ -0,0 +1,11 @@ +//! GPU backend for Linux using the Direct Rendering Manager subsystem. + +pub const Connector = @import("linux_drm/Connector.zig"); +pub const Device = @import("linux_drm/Device.zig"); +pub const Provider = @import("linux_drm/Provider.zig"); + +test { + _ = Connector; + _ = Device; + _ = Provider; +} diff --git a/lib/phantom/gpu/backend/linux_drm/Connector.zig b/lib/phantom/gpu/backend/linux_drm/Connector.zig new file mode 100644 index 0000000..e69de29 diff --git a/lib/phantom/gpu/backend/linux_drm/Device.zig b/lib/phantom/gpu/backend/linux_drm/Device.zig new file mode 100644 index 0000000..ed3ea15 --- /dev/null +++ b/lib/phantom/gpu/backend/linux_drm/Device.zig @@ -0,0 +1,58 @@ +const std = @import("std"); +const Allocator = std.mem.Allocator; +const libdrm = @import("libdrm"); +const Connector = @import("../../Connector.zig"); +const Device = @import("../../Device.zig"); +const Self = @This(); + +allocator: Allocator, +node: libdrm.Node, +base: Device, + +pub fn create(alloc: Allocator, node: libdrm.Node) !*Device { + const self = try alloc.create(Self); + errdefer alloc.destroy(self); + + self.* = .{ + .allocator = alloc, + .node = node, + .base = .{ + .ptr = self, + .vtable = &.{ + .getConnectors = impl_getConnectors, + .destroy = impl_destroy, + }, + }, + }; + return &self.base; +} + +pub fn getConnectors(self: *Self) ![]const *Connector { + var list = std.ArrayList(*Connector).init(self.allocator); + defer list.deinit(); + + const modeCardRes = try self.node.getModeCardRes(); + defer modeCardRes.deinit(self.allocator); + + if (modeCardRes.connectorIds()) |connectorIds| { + for (connectorIds) |connectorId| { + std.debug.print("{}\n", .{connectorId}); + } + } + return try list.toOwnedSlice(); +} + +pub fn destroy(self: *Self) void { + self.node.deinit(); + self.allocator.destroy(self); +} + +fn impl_getConnectors(ptr: *anyopaque) anyerror![]const *Connector { + const self: *Self = @alignCast(@ptrCast(ptr)); + return self.getConnectors(); +} + +fn impl_destroy(ptr: *anyopaque) void { + const self: *Self = @alignCast(@ptrCast(ptr)); + return self.destroy(); +} diff --git a/lib/phantom/gpu/backend/linux_drm/Provider.zig b/lib/phantom/gpu/backend/linux_drm/Provider.zig new file mode 100644 index 0000000..3d1d401 --- /dev/null +++ b/lib/phantom/gpu/backend/linux_drm/Provider.zig @@ -0,0 +1,81 @@ +const std = @import("std"); +const Allocator = std.mem.Allocator; +const libdrm = @import("libdrm"); +const Provider = @import("../../Provider.zig"); +const Device = @import("../../Device.zig"); +const LinuxDrmDevice = @import("Device.zig"); +const Self = @This(); + +allocator: Allocator, +base: Provider, + +pub fn create(alloc: Allocator) !*Provider { + const self = try alloc.create(Self); + errdefer alloc.destroy(self); + + self.* = .{ + .allocator = alloc, + .base = .{ + .ptr = self, + .vtable = &.{ + .getDevices = impl_getDevices, + .destroy = impl_destroy, + }, + }, + }; + return &self.base; +} + +pub fn getDevices(self: *Self) anyerror![]const *Device { + var list = std.ArrayList(*Device).init(self.allocator); + defer list.deinit(); + + var iter = libdrm.Node.Iterator.init(self.allocator, .primary); + while (iter.next()) |node| { + const device = try LinuxDrmDevice.create(self.allocator, node); + errdefer device.destroy(); + + try list.append(device); + } + + return try list.toOwnedSlice(); +} + +pub fn destroy(self: *Self) void { + self.allocator.destroy(self); +} + +fn impl_getDevices(ptr: *anyopaque) anyerror![]const *Device { + const self: *Self = @alignCast(@ptrCast(ptr)); + return self.getDevices(); +} + +fn impl_destroy(ptr: *anyopaque) void { + const self: *Self = @alignCast(@ptrCast(ptr)); + return self.destroy(); +} + +test { + const provider = try create(std.testing.allocator); + defer provider.destroy(); + + const devices = try provider.getDevices(); + defer { + for (devices) |dev| dev.destroy(); + std.testing.allocator.free(devices); + } + + if (devices.len == 0) return error.SkipZigTest; + + std.debug.print("{any}\n", .{devices}); + + for (devices) |dev| { + const connectors = dev.getConnectors() catch continue; + defer { + for (connectors) |conn| conn.destroy(); + std.testing.allocator.free(connectors); + } + + std.debug.print("{any}\n", .{connectors}); + } +}