beansprout-custom/src/WallpaperImage.zig
Ben Buhse 225ddf0a53
Fix buffer pool race condition, pixman transform, and pixel conversion
Mark reused buffers as busy before returning from nextBuffer (before,
they only got marked busy on init).

Re-attach wl_buffer listener after re-initializing a buffer. This lets
the re-inited buffer still get a released event.

Combine scale and translate matrices with multiply instead of overwriting

Use appendAssumeCapacity for pixel conversion loop (since we already
initialized the list with the correct size).
2026-02-08 10:51:33 -06:00

60 lines
2.3 KiB
Zig

// SPDX-FileCopyrightText: 2026 Ben Buhse <me@benbuhse.email>
//
// SPDX-License-Identifier: GPL-3.0-or-later
const WallpaperImage = @This();
image: *pixman.Image,
pixels: std.ArrayList(u32),
// TODO: Make image_path nullable, if null, do a single color with a single_pixel_buffer instead(?)
pub fn create(image_path: []const u8) !*WallpaperImage {
var wallpaper_image = try utils.allocator.create(WallpaperImage);
errdefer utils.allocator.destroy(wallpaper_image);
var read_buf: [zigimg.io.DEFAULT_BUFFER_SIZE]u8 = undefined;
var image = try zigimg.Image.fromFilePath(utils.allocator, image_path, &read_buf);
defer image.deinit(utils.allocator);
// We don't want to deal with all the possible formats,
// so let's just convert to one we can use with pixman.
if (image.pixelFormat() != .rgba32) {
try image.convert(utils.allocator, .rgba32);
}
log.debug("image loaded ({}x{})", .{ image.width, image.height });
const pixels = image.pixels.rgba32;
// We have to manually convert to argb --
// It's only guaranteed that Wayland compositors will have xrgb and argb support but zigimg doesn't have either of those.
wallpaper_image.pixels = try std.ArrayList(u32).initCapacity(utils.allocator, pixels.len);
errdefer wallpaper_image.pixels.deinit(utils.allocator);
for (0..pixels.len) |i| {
const a: u32 = @intCast(pixels[i].a);
const r: u32 = @intCast(pixels[i].r);
const g: u32 = @intCast(pixels[i].g);
const b: u32 = @intCast(pixels[i].b);
const new_val: u32 = (a << 24) + (r << 16) + (g << 8) + b;
wallpaper_image.pixels.appendAssumeCapacity(new_val);
}
wallpaper_image.image = pixman.Image.createBits(.a8r8g8b8, @intCast(image.width), @intCast(image.height), @ptrCast(@alignCast(wallpaper_image.pixels.items.ptr)), @intCast(image.width * image.pixelFormat().pixelStride())) orelse return error.FailedToCreatePixmanImage;
return wallpaper_image;
}
pub fn destroy(wallpaper_image: *WallpaperImage) void {
_ = wallpaper_image.image.unref();
wallpaper_image.pixels.deinit(utils.allocator);
utils.allocator.destroy(wallpaper_image);
}
const std = @import("std");
const pixman = @import("pixman");
const zigimg = @import("zigimg");
const utils = @import("utils.zig");
const log = std.log.scoped(.WallpaperImage);