1const std = @import("std");2const mem = std.mem;3const posix = std.posix;4const linux = std.os.linux;56const pixman = @import("pixman");7const wl = @import("wayland").client.wl;89const Buffer = @This();1011mmap: ?[]align(4096) u8 = null,12data: ?[]u32 = null,13buffer: ?*wl.Buffer = null,14pix: ?*pixman.Image = null,1516busy: bool = false,17width: u31 = 0,18height: u31 = 0,19size: u31 = 0,2021pub fn resize(self: *Buffer, shm: *wl.Shm, width: u31, height: u31) !void {22 if (width == 0 or height == 0) return;2324 self.busy = true;25 self.width = width;26 self.height = height;2728 const fd = try posix.memfd_create("creek-shm", linux.MFD.CLOEXEC);29 defer posix.close(fd);3031 const stride = width * 4;32 self.size = stride * height;33 try posix.ftruncate(fd, self.size);3435 self.mmap = try posix.mmap(null, self.size, posix.PROT.READ | posix.PROT.WRITE, .{ .TYPE = .SHARED }, fd, 0);36 self.data = mem.bytesAsSlice(u32, self.mmap.?);3738 const pool = try shm.createPool(fd, self.size);39 defer pool.destroy();4041 self.buffer = try pool.createBuffer(0, width, height, stride, .argb8888);42 errdefer self.buffer.?.destroy();43 self.buffer.?.setListener(*Buffer, listener, self);4445 self.pix = pixman.Image.createBitsNoClear(.a8r8g8b8, width, height, self.data.?.ptr, stride);46}4748pub fn deinit(self: *Buffer) void {49 if (self.pix) |pix| _ = pix.unref();50 if (self.buffer) |buf| buf.destroy();51 if (self.mmap) |mmap| posix.munmap(mmap);52}5354fn listener(_: *wl.Buffer, event: wl.Buffer.Event, buffer: *Buffer) void {55 switch (event) {56 .release => buffer.busy = false,57 }58}5960pub fn nextBuffer(pool: *[2]Buffer, shm: *wl.Shm, width: u16, height: u16) !*Buffer {61 if (pool[0].busy and pool[1].busy) {62 return error.NoAvailableBuffers;63 }64 const buffer = if (!pool[0].busy) &pool[0] else &pool[1];6566 if (buffer.width != width or buffer.height != height) {67 buffer.deinit();68 try buffer.resize(shm, width, height);69 }70 return buffer;71}