summaryrefslogtreecommitdiff
path: root/src/screen/drm
diff options
context:
space:
mode:
authorNathan Reiner <nathan@nathanreiner.xyz>2025-02-02 16:00:15 +0100
committerNathan Reiner <nathan@nathanreiner.xyz>2025-02-02 16:00:15 +0100
commit8d062a90b1ffbe9e00334fa3e9e939406bd32141 (patch)
tree20951bba89bbcdc3090e24d99eb9f91c0043f28e /src/screen/drm
parent0b6ee849722002a8bc7cc5374e3136bee4be2ccd (diff)
screen: add vsync and double buffering
Diffstat (limited to 'src/screen/drm')
-rw-r--r--src/screen/drm/card.zig26
-rw-r--r--src/screen/drm/crtc/root.zig32
-rw-r--r--src/screen/drm/event.zig31
-rw-r--r--src/screen/drm/frame-buffer/page-flip.zig8
-rw-r--r--src/screen/drm/frame-buffer/root.zig41
-rw-r--r--src/screen/drm/request.zig2
6 files changed, 135 insertions, 5 deletions
diff --git a/src/screen/drm/card.zig b/src/screen/drm/card.zig
index d66a5f1..6147cf2 100644
--- a/src/screen/drm/card.zig
+++ b/src/screen/drm/card.zig
@@ -7,7 +7,8 @@ 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;
+const DoubleBuffer = @import("frame-buffer/root.zig").DoubleBuffer;
+const Event = @import("event.zig").Event;
pub const Card = struct {
@@ -25,6 +26,7 @@ pub const Card = struct {
.mode = .read_write,
.lock_nonblocking = true,
}),
+
.allocator = allocator,
};
}
@@ -54,7 +56,25 @@ pub const Card = struct {
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);
+ pub fn create_double_buffer(self: *Card, width: u32, height: u32, bpp: u32) !DoubleBuffer {
+ return DoubleBuffer.init(self, width, height, bpp);
+ }
+
+ pub fn poll_event(self: *Card, timeout: i32) !?Event {
+ var pollfd = os.pollfd {
+ .fd = self.file.handle,
+ .events = os.POLL.IN,
+ .revents = 0
+ };
+
+ try cerror.from_usize(os.poll(@ptrCast(&pollfd), 1, timeout));
+
+ if ((pollfd.revents & os.POLL.IN) != 0) {
+ var event = std.mem.zeroes(Event);
+ try cerror.from_usize(os.read(self.file.handle, @ptrCast(&event), @sizeOf(Event)));
+ return event;
+ }
+
+ return null;
}
};
diff --git a/src/screen/drm/crtc/root.zig b/src/screen/drm/crtc/root.zig
index 3c9d6f9..f1f1d5c 100644
--- a/src/screen/drm/crtc/root.zig
+++ b/src/screen/drm/crtc/root.zig
@@ -2,7 +2,9 @@ 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 fb = @import("../frame-buffer/root.zig");
+const FrameBuffer = fb.FrameBuffer;
+const DoubleBuffer = fb.DoubleBuffer;
const Mode = @import("../connector/mode.zig").Mode;
pub const RawCrtc = extern struct {
@@ -17,6 +19,22 @@ pub const RawCrtc = extern struct {
mode: Mode,
};
+const PageFlipEvent = packed struct(u32) {
+ event: bool,
+ is_async: bool,
+ absolute: bool,
+ relative: bool,
+ __padding: u28,
+};
+
+const PageFlip = extern struct {
+ crtc_id: u32,
+ buffer_id: u32,
+ flags: PageFlipEvent,
+ __reserved: u32,
+ user_data: u64,
+};
+
pub const Crtc = struct {
const Self = @This();
@@ -65,8 +83,18 @@ pub const Crtc = struct {
};
try Drm.set_crtc.request(self.card.file.handle, RawCrtc, &crtc);
+ }
+
+ pub fn page_flip(self: *Self, double_buffer: *DoubleBuffer) !void {
+ double_buffer.swap();
+
+ var flip = std.mem.zeroInit(PageFlip, .{
+ .buffer_id = double_buffer.crtc_buffer().id,
+ .crtc_id = self.id,
+ .flags = std.mem.zeroInit(PageFlipEvent, .{ .event = true }),
+ });
- std.debug.print("crtc = {any}\n", .{self});
+ try Drm.page_flip.request(self.card.file.handle, PageFlip, &flip);
}
pub fn detach(self: *Self) void {
diff --git a/src/screen/drm/event.zig b/src/screen/drm/event.zig
new file mode 100644
index 0000000..201ced3
--- /dev/null
+++ b/src/screen/drm/event.zig
@@ -0,0 +1,31 @@
+
+pub const EventType = enum(u32) {
+ vblank = 1,
+ page_flip_complete = 2,
+ crtc_sequence = 3,
+};
+
+pub const VBlankEvent = extern struct {
+ user_data: u64,
+ tv_sec: u32,
+ tv_usec: u32,
+ sequence: u32,
+ crtc_id: u32,
+};
+
+pub const CrtcSequenceEvent = extern struct {
+ user_data: u64,
+ time_ns: i64,
+ sequence: u64,
+};
+
+pub const EventPayload = extern union {
+ vblank: VBlankEvent,
+ crtc_sequence: CrtcSequenceEvent,
+};
+
+pub const Event = extern struct {
+ type: EventType,
+ length: u32,
+ payload: EventPayload,
+};
diff --git a/src/screen/drm/frame-buffer/page-flip.zig b/src/screen/drm/frame-buffer/page-flip.zig
new file mode 100644
index 0000000..2e41e61
--- /dev/null
+++ b/src/screen/drm/frame-buffer/page-flip.zig
@@ -0,0 +1,8 @@
+
+pub const PageFlip = packed struct(u32) {
+ event: bool,
+ is_async: bool,
+ absolute: bool,
+ relative: bool,
+ _padding: u28,
+}
diff --git a/src/screen/drm/frame-buffer/root.zig b/src/screen/drm/frame-buffer/root.zig
index eb7b47b..0083711 100644
--- a/src/screen/drm/frame-buffer/root.zig
+++ b/src/screen/drm/frame-buffer/root.zig
@@ -33,6 +33,43 @@ const MapDumb = extern struct {
offset: i64,
};
+pub const DoubleBuffer = struct {
+ const Self = @This();
+
+ back: FrameBuffer,
+ front: FrameBuffer,
+
+ pub fn init(card: *Card, width: u32, height: u32, bpp: u32) !Self {
+ return .{
+ .back = try FrameBuffer.init(card, width, height, bpp),
+ .front = try FrameBuffer.init(card, width, height, bpp),
+ };
+ }
+
+ pub fn swap(self: *Self) void {
+ const back_data = self.back.data;
+ self.back.data = self.front.data;
+ self.front.data = back_data;
+
+ const back_id = self.back.id;
+ self.back.id = self.front.id;
+ self.front.id = back_id;
+ }
+
+ pub fn deinit(self: *Self) void {
+ self.back.deinit();
+ self.front.deinit();
+ }
+
+ pub fn buffer(self: *Self) *FrameBuffer {
+ return &self.back;
+ }
+
+ pub fn crtc_buffer(self: *Self) *FrameBuffer {
+ return &self.front;
+ }
+};
+
pub const Pixel = packed struct(u32) {
blue: u8,
green: u8,
@@ -127,6 +164,10 @@ pub const FrameBuffer = struct {
self.data[x + self.width * y] = pixel;
}
+ pub fn fill(self: *Self, pixel: Pixel) void {
+ @memset(self.data[0..self.canvas_size], pixel);
+ }
+
pub fn deinit(self: *Self) void {
cerror.from_usize(
os.munmap(@ptrCast(@volatileCast(self.data)), self.data_size)
diff --git a/src/screen/drm/request.zig b/src/screen/drm/request.zig
index 9e0a045..5daf92f 100644
--- a/src/screen/drm/request.zig
+++ b/src/screen/drm/request.zig
@@ -15,6 +15,8 @@ pub const Drm = enum(u8) {
get_encoder = 0xa6,
get_connector = 0xa7,
remove_frame_buffer = 0xaf,
+ page_flip = 0xb0,
+ dirty_frame_buffer = 0xb1,
create_dumb = 0xb2,
map_dumb = 0xb3,
destroy_dumb = 0xb4,