1const std = @import("std");2const Io = std.Io;3const mem = std.mem;4const posix = std.posix;5const linux = std.os.linux;67const pixman = @import("pixman");8const wl = @import("wayland").client.wl;910const Buffer = @This();1112const state = &@import("root").state;1314mmap: ?Io.File.MemoryMap = null,15data: ?[]u32 = null,16buffer: ?*wl.Buffer = null,17pix: ?*pixman.Image = null,1819busy: bool = false,20width: u31 = 0,21height: u31 = 0,22size: u31 = 0,2324pub fn resize(self: *Buffer, shm: *wl.Shm, width: u31, height: u31) !void {25 if (width == 0 or height == 0) return;2627 self.busy = true;28 self.width = width;29 self.height = height;3031 // There doesn't seem to be a way to memfd through a File abstraction, as of Zig 0.1632 const fd = try posix.memfd_create("creek-shm", linux.MFD.CLOEXEC);33 const file = Io.File{ .handle = fd, .flags = .{ .nonblocking = false } };34 defer file.close(state.io);3536 const stride = width * 4;37 self.size = stride * height;38 try file.setLength(state.io, self.size);3940 self.mmap = try file.createMemoryMap(state.io, .{ .len = self.size });41 self.data = mem.bytesAsSlice(u32, self.mmap.?.memory);4243 const pool = try shm.createPool(fd, self.size);44 defer pool.destroy();4546 self.buffer = try pool.createBuffer(0, width, height, stride, .argb8888);47 errdefer self.buffer.?.destroy();48 self.buffer.?.setListener(*Buffer, listener, self);4950 self.pix = pixman.Image.createBitsNoClear(.a8r8g8b8, width, height, self.data.?.ptr, stride);51}5253pub fn deinit(self: *Buffer) void {54 if (self.pix) |pix| _ = pix.unref();55 if (self.buffer) |buf| buf.destroy();56 if (self.mmap) |*mmap| mmap.destroy(state.io);57}5859fn listener(_: *wl.Buffer, event: wl.Buffer.Event, buffer: *Buffer) void {60 switch (event) {61 .release => buffer.busy = false,62 }63}6465pub fn nextBuffer(pool: *[2]Buffer, shm: *wl.Shm, width: u16, height: u16) !*Buffer {66 if (pool[0].busy and pool[1].busy) {67 return error.NoAvailableBuffers;68 }69 const buffer = if (!pool[0].busy) &pool[0] else &pool[1];7071 if (buffer.width != width or buffer.height != height) {72 buffer.deinit();73 try buffer.resize(shm, width, height);74 }75 return buffer;76}