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).
This commit is contained in:
parent
3c16929a6a
commit
225ddf0a53
5 changed files with 27 additions and 18 deletions
|
|
@ -11,6 +11,7 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
These are in rough order of my priority, though no promises I do them in this order.
|
These are in rough order of my priority, though no promises I do them in this order.
|
||||||
|
|
||||||
- [ ] Switch all structs to idiomatic Zig init/deinit pattern (init returns value, caller decides stack/heap)
|
- [ ] Switch all structs to idiomatic Zig init/deinit pattern (init returns value, caller decides stack/heap)
|
||||||
|
- [ ] Implement runtime log levels
|
||||||
- [ ] Support per-host config using properties
|
- [ ] Support per-host config using properties
|
||||||
- [ ] Support a basic bar
|
- [ ] Support a basic bar
|
||||||
- [ ] Support starting programs at WM launch
|
- [ ] Support starting programs at WM launch
|
||||||
|
|
|
||||||
|
|
@ -61,6 +61,7 @@ fn findSuitableBuffer(buffer_pool: *BufferPool, wl_shm: *wl.Shm, width: u31, hei
|
||||||
const buffer: *Buffer = @fieldParentPtr("node", node);
|
const buffer: *Buffer = @fieldParentPtr("node", node);
|
||||||
if (buffer.busy) continue;
|
if (buffer.busy) continue;
|
||||||
if (buffer.width == width and buffer.height == height) {
|
if (buffer.width == width and buffer.height == height) {
|
||||||
|
buffer.busy = true;
|
||||||
return buffer;
|
return buffer;
|
||||||
} else {
|
} else {
|
||||||
first_unbusy_buffer = buffer;
|
first_unbusy_buffer = buffer;
|
||||||
|
|
@ -72,6 +73,7 @@ fn findSuitableBuffer(buffer_pool: *BufferPool, wl_shm: *wl.Shm, width: u31, hei
|
||||||
if (first_unbusy_buffer) |buffer| {
|
if (first_unbusy_buffer) |buffer| {
|
||||||
buffer.deinit();
|
buffer.deinit();
|
||||||
buffer.* = try Buffer.init(wl_shm, width, height);
|
buffer.* = try Buffer.init(wl_shm, width, height);
|
||||||
|
buffer.setListener();
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -223,7 +223,7 @@ pub fn initWallpaperLayerSurface(output: *Output) !void {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (output.wl_surface) |_| {
|
if (output.wl_surface) |_| {
|
||||||
log.debug("Skipping adding a second wallpaper surface to {s}", .{output.name orelse "some output"});
|
// This output already has a layer surface, we can exit early
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -344,15 +344,13 @@ pub fn renderWallpaper(output: *Output) !void {
|
||||||
|
|
||||||
const buffer: *Buffer = try context.buffer_pool.nextBuffer(context.wl_shm, width * scale, height * scale);
|
const buffer: *Buffer = try context.buffer_pool.nextBuffer(context.wl_shm, width * scale, height * scale);
|
||||||
|
|
||||||
const pix = pixman.Image.createBitsNoClear(image_format, image_width, image_height, image_data, image_stride);
|
const pix = pixman.Image.createBitsNoClear(image_format, image_width, image_height, image_data, image_stride) orelse {
|
||||||
if (pix == null) {
|
log.err("Failed to copy the wallpaper image for rendering", .{});
|
||||||
log.err("failed to copy the background image for rendering", .{});
|
|
||||||
return error.ImageCopyError;
|
return error.ImageCopyError;
|
||||||
}
|
};
|
||||||
defer _ = pix.?.unref();
|
defer _ = pix.unref();
|
||||||
|
|
||||||
// Get scale for our image compared to the monitor's scale
|
// Calculate image scale
|
||||||
// XXX: This sucks in Zig but also I'm sure there's a better way to write it
|
|
||||||
var sx: f64 = @as(f64, @floatFromInt(image_width)) / @as(f64, @floatFromInt(width * scale));
|
var sx: f64 = @as(f64, @floatFromInt(image_width)) / @as(f64, @floatFromInt(width * scale));
|
||||||
var sy: f64 = calculate_scale(image_height, height, scale);
|
var sy: f64 = calculate_scale(image_height, height, scale);
|
||||||
|
|
||||||
|
|
@ -360,19 +358,31 @@ pub fn renderWallpaper(output: *Output) !void {
|
||||||
sx = s;
|
sx = s;
|
||||||
sy = s;
|
sy = s;
|
||||||
|
|
||||||
|
// Calculate translation offsets to center the image on the output.
|
||||||
|
// If the scaled image is larger than the output, the offset crops equally from both sides.
|
||||||
const tx: f64 = calculate_transform(image_width, width, sx);
|
const tx: f64 = calculate_transform(image_width, width, sx);
|
||||||
const ty: f64 = calculate_transform(image_height, height, sy);
|
const ty: f64 = calculate_transform(image_height, height, sy);
|
||||||
|
|
||||||
|
// Build a combined source-to-destination transform matrix.
|
||||||
|
// Pixman transforms map destination pixels back to source pixels, so:
|
||||||
|
// t_scale: maps a destination pixel to the corresponding source pixel (scaling)
|
||||||
|
// t_trans: shifts the sampling point to center the image
|
||||||
|
// t = t_trans * t_scale: first scale, then translate (in source space)
|
||||||
|
var t_scale: pixman.FTransform = undefined;
|
||||||
|
var t_trans: pixman.FTransform = undefined;
|
||||||
var t: pixman.FTransform = undefined;
|
var t: pixman.FTransform = undefined;
|
||||||
|
// t2 is the fixed-point version of t, which is what pixman actually uses internally
|
||||||
var t2: pixman.Transform = undefined;
|
var t2: pixman.Transform = undefined;
|
||||||
|
|
||||||
pixman.FTransform.initTranslate(&t, tx, ty);
|
pixman.FTransform.initScale(&t_scale, sx, sy);
|
||||||
pixman.FTransform.initScale(&t, sx, sy);
|
pixman.FTransform.initTranslate(&t_trans, tx, ty);
|
||||||
|
pixman.FTransform.multiply(&t, &t_trans, &t_scale);
|
||||||
_ = pixman.Transform.fromFTransform(&t2, &t);
|
_ = pixman.Transform.fromFTransform(&t2, &t);
|
||||||
_ = pix.?.setTransform(&t2);
|
_ = pix.setTransform(&t2);
|
||||||
_ = pix.?.setFilter(.best, &[_]pixman.Fixed{}, 0);
|
_ = pix.setFilter(.best, &[_]pixman.Fixed{}, 0);
|
||||||
|
|
||||||
pixman.Image.composite32(.src, pix.?, null, buffer.pixman_image, 0, 0, 0, 0, 0, 0, width * scale, height * scale);
|
// Combine the transformed source image into the buffer.
|
||||||
|
pixman.Image.composite32(.src, pix, null, buffer.pixman_image, 0, 0, 0, 0, 0, 0, width * scale, height * scale);
|
||||||
|
|
||||||
log.info("render: {}x{} (scaled from {}x{})", .{ width * scale, height * scale, image_width, image_height });
|
log.info("render: {}x{} (scaled from {}x{})", .{ width * scale, height * scale, image_width, image_height });
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ pub fn create(image_path: []const u8) !*WallpaperImage {
|
||||||
const g: u32 = @intCast(pixels[i].g);
|
const g: u32 = @intCast(pixels[i].g);
|
||||||
const b: u32 = @intCast(pixels[i].b);
|
const b: u32 = @intCast(pixels[i].b);
|
||||||
const new_val: u32 = (a << 24) + (r << 16) + (g << 8) + b;
|
const new_val: u32 = (a << 24) + (r << 16) + (g << 8) + b;
|
||||||
try wallpaper_image.pixels.append(utils.allocator, new_val);
|
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;
|
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;
|
||||||
|
|
|
||||||
|
|
@ -134,10 +134,6 @@ fn registryListener(registry: *wl.Registry, event: wl.Registry.Event, globals: *
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const std_options = std.Options{
|
|
||||||
.log_level = .debug,
|
|
||||||
};
|
|
||||||
|
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const mem = std.mem;
|
const mem = std.mem;
|
||||||
const fatal = std.process.fatal;
|
const fatal = std.process.fatal;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue