summaryrefslogtreecommitdiff
path: root/src/screen
diff options
context:
space:
mode:
Diffstat (limited to 'src/screen')
-rw-r--r--src/screen/drm/card.zig5
-rw-r--r--src/screen/drm/connector/mode.zig13
-rw-r--r--src/screen/drm/connector/root.zig1
-rw-r--r--src/screen/drm/crtc/root.zig52
-rw-r--r--src/screen/drm/frame-buffer/pixelformat.zig11
-rw-r--r--src/screen/drm/frame-buffer/root.zig147
-rw-r--r--src/screen/drm/request.zig6
-rw-r--r--src/screen/main.zig62
8 files changed, 288 insertions, 9 deletions
diff --git a/src/screen/drm/card.zig b/src/screen/drm/card.zig
index 411716a..d66a5f1 100644
--- a/src/screen/drm/card.zig
+++ b/src/screen/drm/card.zig
@@ -7,6 +7,7 @@ const Resources = @import("resources.zig").Resources;
const Connector = @import("connector/root.zig").Connector;
const Encoder = @import("encoder/root.zig").Encoder;
const Crtc = @import("crtc/root.zig").Crtc;
+const FrameBuffer = @import("frame-buffer/root.zig").FrameBuffer;
pub const Card = struct {
@@ -52,4 +53,8 @@ pub const Card = struct {
pub fn crtc(self: *Card, id: u32) !Crtc {
return Crtc.init(self, id);
}
+
+ pub fn create_frame_buffer(self: *Card, width: u32, height: u32, bpp: u32) !FrameBuffer {
+ return FrameBuffer.init(self, width, height, bpp);
+ }
};
diff --git a/src/screen/drm/connector/mode.zig b/src/screen/drm/connector/mode.zig
index 9f4dfc4..fb61b5b 100644
--- a/src/screen/drm/connector/mode.zig
+++ b/src/screen/drm/connector/mode.zig
@@ -9,6 +9,17 @@ pub const Mode = extern struct {
total: u16,
};
+ const Type = packed struct(u32) {
+ builtin: bool,
+ clock_c: bool,
+ crtc_c: bool,
+ preferred: bool,
+ default: bool,
+ userdef: bool,
+ driver: bool,
+ _padding: u25,
+ };
+
const Flags = packed struct(u32) {
phsync: bool,
nhsync: bool,
@@ -35,7 +46,7 @@ pub const Mode = extern struct {
vertical_refresh: u32,
flags: Flags,
- type: u32,
+ type: Type,
name: [32]u8,
pub fn frame_rate(self: *const Self) f32 {
diff --git a/src/screen/drm/connector/root.zig b/src/screen/drm/connector/root.zig
index 5766851..c104e84 100644
--- a/src/screen/drm/connector/root.zig
+++ b/src/screen/drm/connector/root.zig
@@ -2,6 +2,7 @@ const std = @import("std");
const os = std.os.linux;
const Drm = @import("../request.zig").Drm;
const Card = @import("../card.zig").Card;
+const FrameBuffer = @import("../frame-buffer/root.zig").FrameBuffer;
pub const Connection = @import("connection.zig").Connection;
pub const Mode = @import("mode.zig").Mode;
diff --git a/src/screen/drm/crtc/root.zig b/src/screen/drm/crtc/root.zig
index 7601732..3c9d6f9 100644
--- a/src/screen/drm/crtc/root.zig
+++ b/src/screen/drm/crtc/root.zig
@@ -2,9 +2,11 @@ const std = @import("std");
const Card = @import("../card.zig").Card;
const Drm = @import("../request.zig").Drm;
const Connector = @import("../connector/root.zig").Connector;
+const FrameBuffer = @import("../frame-buffer/root.zig").FrameBuffer;
+const Mode = @import("../connector/mode.zig").Mode;
pub const RawCrtc = extern struct {
- connectors: ?*Connector,
+ connector_ids: ?*u32,
count_connectors: u32,
id: u32,
buffer_id: u32,
@@ -12,15 +14,19 @@ pub const RawCrtc = extern struct {
y: u32,
gamma_size: u32,
mode_valid: u32,
+ mode: Mode,
};
pub const Crtc = struct {
const Self = @This();
+ connector_ids: ?*u32,
+ count_connectors: u32,
id: u32,
buffer_id: u32,
x: u32,
y: u32,
+ mode: Mode,
mode_valid: u32,
gamma_size: u32,
card: *Card,
@@ -29,17 +35,57 @@ pub const Crtc = struct {
var raw = std.mem.zeroInit(RawCrtc, .{ .id = id });
try Drm.get_crtc.request(card.file.handle, RawCrtc, &raw);
return .{
+ .connector_ids = raw.connector_ids,
+ .count_connectors = raw.count_connectors,
.id = raw.id,
.buffer_id = raw.buffer_id,
.x = raw.x,
.y = raw.y,
+ .mode = raw.mode,
.mode_valid = raw.mode_valid,
.gamma_size = raw.gamma_size,
.card = card,
};
}
- pub fn deinit(self: *Self) void {
- _ = self;
+ pub fn attach(self: *Self, frame_buffer: *FrameBuffer, connector: *Connector, mode: Mode) !void {
+ self.connector_ids = &connector.id;
+ self.count_connectors = 1;
+
+ var crtc = RawCrtc {
+ .id = self.id,
+ .x = self.x,
+ .y = self.y,
+ .buffer_id = frame_buffer.id,
+ .connector_ids = self.connector_ids,
+ .count_connectors = self.count_connectors,
+ .mode = mode,
+ .mode_valid = 1,
+ .gamma_size = self.gamma_size,
+ };
+
+ try Drm.set_crtc.request(self.card.file.handle, RawCrtc, &crtc);
+
+ std.debug.print("crtc = {any}\n", .{self});
+ }
+
+ pub fn detach(self: *Self) void {
+ var crtc = RawCrtc {
+ .id = self.id,
+ .x = self.x,
+ .y = self.y,
+ .buffer_id = self.buffer_id,
+ .connector_ids = self.connector_ids,
+ .count_connectors = self.count_connectors,
+ .mode = self.mode,
+ .mode_valid = self.mode_valid,
+ .gamma_size = self.gamma_size,
+ };
+
+ Drm.set_crtc.request(
+ self.card.file.handle,
+ RawCrtc,
+ &crtc
+ ) catch |err| std.debug.panic("set crtc failed on detach: {}", .{err});
}
};
diff --git a/src/screen/drm/frame-buffer/pixelformat.zig b/src/screen/drm/frame-buffer/pixelformat.zig
new file mode 100644
index 0000000..a4b3f9a
--- /dev/null
+++ b/src/screen/drm/frame-buffer/pixelformat.zig
@@ -0,0 +1,11 @@
+
+fn pixel_format_code(comptime a: u8, comptime b: u8, comptime c: u8, comptime d: u8) u32 {
+ return @as(u32, @intCast(a)) |
+ (@as(u32, @intCast(b)) << 8) |
+ (@as(u32, @intCast(c)) << 16) |
+ (@as(u32, @intCast(d)) << 24);
+}
+
+pub const PixelFormat = enum(u32) {
+ xrgb8888 = pixel_format_code('X', 'R', '2', '4'),
+};
diff --git a/src/screen/drm/frame-buffer/root.zig b/src/screen/drm/frame-buffer/root.zig
new file mode 100644
index 0000000..eb7b47b
--- /dev/null
+++ b/src/screen/drm/frame-buffer/root.zig
@@ -0,0 +1,147 @@
+const std = @import("std");
+const os = std.os.linux;
+const Card = @import("../card.zig").Card;
+const Drm = @import("../request.zig").Drm;
+const PixelFormat = @import("pixelformat.zig").PixelFormat;
+const cerror = @import("../../cerror.zig");
+
+const CreateDumb = extern struct {
+ height: u32,
+ width: u32,
+ bpp: u32,
+ flags: u32,
+ handle: u32,
+ pitch: u32,
+ size: u32,
+};
+
+const FrameBufferCmd2 = extern struct {
+ id: u32,
+ width: u32,
+ height: u32,
+ pixel_format: PixelFormat,
+ flags: u32,
+ handles: [4]u32,
+ pitches: [4]u32,
+ offsets: [4]u32,
+ modifier: [4]u32,
+};
+
+const MapDumb = extern struct {
+ handle: u32,
+ __padding: u32,
+ offset: i64,
+};
+
+pub const Pixel = packed struct(u32) {
+ blue: u8,
+ green: u8,
+ red: u8,
+ _padding: u8 = 0x0,
+};
+
+pub const FrameBuffer = struct {
+ const Self = @This();
+
+ card: *Card,
+ id: u32,
+ width: u32,
+ height: u32,
+ bpp: u32,
+ stride: u32,
+ data_size: u64,
+ canvas_size: u64,
+ handle: u32,
+ data: [*]volatile Pixel,
+
+ pub fn init(card: *Card, width: u32, height: u32, bpp: u32) !Self {
+ var create_dumb = std.mem.zeroInit(CreateDumb, .{
+ .width = width,
+ .height = height,
+ .bpp = bpp,
+ });
+ try Drm.create_dumb.request(
+ card.file.handle,
+ CreateDumb,
+ &create_dumb
+ );
+
+ var fb = Self {
+ .id = 0,
+ .width = create_dumb.width,
+ .height = create_dumb.height,
+ .bpp = create_dumb.bpp,
+ .stride = create_dumb.pitch,
+ .data_size = create_dumb.size,
+ .canvas_size = create_dumb.size / (bpp / 8),
+ .handle = create_dumb.handle,
+ .data = undefined,
+ .card = card,
+ };
+
+ var buffer_cmd = FrameBufferCmd2 {
+ .id = 0,
+ .width = fb.width,
+ .height = fb.height,
+ .pixel_format = PixelFormat.xrgb8888,
+ .flags = 0,
+ .handles = [_] u32 { fb.handle, 0, 0, 0 },
+ .pitches = [_] u32 { fb.stride, 0, 0, 0 },
+ .offsets = [_] u32 { 0, 0, 0, 0 },
+ .modifier = [_] u32 { 0, 0, 0, 0 },
+ };
+
+ try Drm.add_frame_buffer2.request(
+ card.file.handle,
+ FrameBufferCmd2,
+ &buffer_cmd
+ );
+
+ fb.id = buffer_cmd.id;
+
+ var map_dumb = std.mem.zeroInit(MapDumb, .{ .handle = fb.handle });
+
+ try Drm.map_dumb.request(
+ card.file.handle,
+ MapDumb,
+ &map_dumb
+ );
+
+ const address = os.mmap(
+ null,
+ fb.data_size,
+ os.PROT.READ | os.PROT.WRITE,
+ .{ .TYPE = os.MAP_TYPE.SHARED },
+ card.file.handle,
+ map_dumb.offset
+ );
+
+ try cerror.from_usize(address);
+
+ fb.data = @ptrFromInt(address);
+
+ return fb;
+ }
+
+ pub fn set(self: *Self, x: u32, y: u32, pixel: Pixel) void {
+ self.data[x + self.width * y] = pixel;
+ }
+
+ pub fn deinit(self: *Self) void {
+ cerror.from_usize(
+ os.munmap(@ptrCast(@volatileCast(self.data)), self.data_size)
+ ) catch |err| std.debug.panic("munmap failed in frame-buffer: {}", .{err});
+
+ Drm.remove_frame_buffer.request(
+ self.card.file.handle,
+ u32,
+ &self.id
+ ) catch @panic("failed to remove frame-buffer");
+
+ Drm.destroy_dumb.request(
+ self.card.file.handle,
+ u32,
+ &self.handle
+ ) catch @panic("failed to destroy dumb-buffer");
+ }
+};
diff --git a/src/screen/drm/request.zig b/src/screen/drm/request.zig
index f833c94..9e0a045 100644
--- a/src/screen/drm/request.zig
+++ b/src/screen/drm/request.zig
@@ -11,8 +11,14 @@ pub const Drm = enum(u8) {
get_resources = 0xa0,
get_crtc = 0xa1,
+ set_crtc = 0xa2,
get_encoder = 0xa6,
get_connector = 0xa7,
+ remove_frame_buffer = 0xaf,
+ create_dumb = 0xb2,
+ map_dumb = 0xb3,
+ destroy_dumb = 0xb4,
+ add_frame_buffer2 = 0xb8,
pub fn request(self: Self, fd: os.fd_t, T: type, arg: *T) !void {
const id = os.IOCTL.IOWR('d', @intFromEnum(self), T);
diff --git a/src/screen/main.zig b/src/screen/main.zig
index b0e5b2e..1a33fd0 100644
--- a/src/screen/main.zig
+++ b/src/screen/main.zig
@@ -5,16 +5,68 @@ pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
const allocator = gpa.allocator();
- var card = try drm.Card.open("card1", allocator);
+ var card = try drm.Card.open("card0", allocator);
defer card.close();
var resources = try card.resources();
defer resources.deinit();
- std.debug.print("id: {}\n", .{resources.crtc_ids[0]});
+ var connector = try card.connector(resources.connector_ids[0]);
+ defer connector.deinit();
- var crtc = try card.crtc(resources.crtc_ids[0]);
- defer crtc.deinit();
+ std.debug.print("connector = {}\n", .{ connector.id });
- std.debug.print("crtc: {any}\n", .{crtc});
+ const mode = connector.modes[0];
+
+ std.debug.print("mode = {s}@{d}Hz\n", .{ mode.name, mode.frame_rate() });
+
+ var crtc = try crtc: {
+ for (connector.encoder_ids) |encoder_id| {
+ var encoder = try card.encoder(encoder_id);
+ defer encoder.deinit();
+
+ for (resources.crtc_ids, 0..) |crtc_id, index| {
+ if ((encoder.possible_crtcs & (@as(u32, 1) << @intCast(index))) != 0) {
+ break :crtc card.crtc(crtc_id);
+ }
+ }
+ }
+
+ break :crtc error.CrtcNotFound;
+ };
+ defer crtc.detach();
+
+ std.debug.print("crtc = {}\n", .{ crtc.id });
+
+ var framebuffer = try card.create_frame_buffer(mode.horizontal.size, mode.vertical.size, 32);
+ defer framebuffer.deinit();
+
+ std.debug.print("framebuffer = {}, {}\n", .{ framebuffer.id, framebuffer.canvas_size });
+
+ try crtc.attach(&framebuffer, &connector, mode);
+
+ var frame: u24 = 0;
+
+ while (true) {
+ for (0..framebuffer.width) |x| {
+ for (0..framebuffer.height) |y| {
+ const raster_x = (frame + x) / 100 * 100;
+ const raster_y = y / 100 * 100;
+ const color = ((raster_x + raster_y) + 0x129453) * 0x329120;
+ framebuffer.set(@intCast(x), @intCast(y), .{
+ .red = @intCast(color & 0xff),
+ .green = @intCast((color >> 8) & 0xff),
+ .blue = @intCast((color >> 16) & 0xff),
+ });
+ }
+ }
+
+ frame, _ = @addWithOverflow(frame, 1);
+
+ try crtc.attach(&framebuffer, &connector, mode);
+
+ std.time.sleep(@intFromFloat(1000000000 / mode.frame_rate()));
+ }
+
+ while (true) { std.time.sleep(5000000000); }
}