transactions: save and render subsurface buffers

This commit is contained in:
Isaac Freund 2020-06-09 23:13:14 +02:00
parent 052c8e1dcb
commit 48ea771310
No known key found for this signature in database
GPG key ID: 86DED400DDFD7A11
3 changed files with 76 additions and 50 deletions

View file

@ -132,6 +132,7 @@ fn startTransaction(self: *Self) void {
var view_it = ViewStack(View).iterator(output.views.first, std.math.maxInt(u32)); var view_it = ViewStack(View).iterator(output.views.first, std.math.maxInt(u32));
while (view_it.next()) |view_node| { while (view_it.next()) |view_node| {
const view = &view_node.view; const view = &view_node.view;
// Clear the serial in case this transaction is interrupting a prior one. // Clear the serial in case this transaction is interrupting a prior one.
view.pending_serial = null; view.pending_serial = null;
@ -145,10 +146,10 @@ fn startTransaction(self: *Self) void {
view.sendFrameDone(); view.sendFrameDone();
} }
// If there is a saved buffer present, then this transaction is interrupting // If there are saved buffers present, then this transaction is interrupting
// a previous transaction and we should keep the old buffer. // a previous transaction and we should keep the old buffers.
if (view.stashed_buffer == null) { if (view.saved_buffers.items.len == 0) {
view.stashBuffer(); view.saveBuffers();
} }
} }
} }
@ -239,7 +240,7 @@ fn commitTransaction(self: *Self) void {
view_tags_changed = true; view_tags_changed = true;
} }
view.dropStashedBuffer(); view.dropSavedBuffers();
} }
if (view_tags_changed) output.sendViewTags(); if (view_tags_changed) output.sendViewTags();

View file

@ -38,6 +38,11 @@ const Impl = union(enum) {
xwayland_view: XwaylandView, xwayland_view: XwaylandView,
}; };
const SavedBuffer = struct {
wlr_buffer: *c.wlr_buffer,
box: Box,
};
/// The implementation of this view /// The implementation of this view
impl: Impl, impl: Impl,
@ -66,8 +71,8 @@ pending_tags: ?u32,
pending_serial: ?u32, pending_serial: ?u32,
// This is what we render while a transaction is in progress /// These are what we render while a transaction is in progress
stashed_buffer: ?*c.wlr_buffer, saved_buffers: std.ArrayList(SavedBuffer),
pub fn init( pub fn init(
self: *Self, self: *Self,
@ -94,7 +99,7 @@ pub fn init(
self.pending_serial = null; self.pending_serial = null;
self.stashed_buffer = null; self.saved_buffers = std.ArrayList(SavedBuffer).init(output.root.server.allocator);
if (@TypeOf(surface) == *c.wlr_xdg_surface) { if (@TypeOf(surface) == *c.wlr_xdg_surface) {
self.impl = .{ .xdg_toplevel = undefined }; self.impl = .{ .xdg_toplevel = undefined };
@ -106,9 +111,8 @@ pub fn init(
} }
pub fn deinit(self: Self) void { pub fn deinit(self: Self) void {
if (self.stashed_buffer) |buffer| { for (self.saved_buffers.items) |buffer| c.wlr_buffer_unref(buffer.wlr_buffer);
c.wlr_buffer_unref(buffer); self.saved_buffers.deinit();
}
} }
pub fn needsConfigure(self: Self) bool { pub fn needsConfigure(self: Self) bool {
@ -135,20 +139,42 @@ pub fn sendFrameDone(self: Self) void {
c.wlr_surface_send_frame_done(self.wlr_surface.?, &now); c.wlr_surface_send_frame_done(self.wlr_surface.?, &now);
} }
pub fn dropStashedBuffer(self: *Self) void { pub fn dropSavedBuffers(self: *Self) void {
// TODO: log debug error for (self.saved_buffers.items) |buffer| c.wlr_buffer_unref(buffer.wlr_buffer);
if (self.stashed_buffer) |buffer| { self.saved_buffers.items.len = 0;
c.wlr_buffer_unref(buffer);
self.stashed_buffer = null;
}
} }
pub fn stashBuffer(self: *Self) void { pub fn saveBuffers(self: *Self) void {
// TODO: log debug error if there is already a saved buffer if (self.saved_buffers.items.len > 0) {
if (self.wlr_surface) |wlr_surface| { Log.Error.log("view already has buffers saved, overwriting", .{});
if (c.wlr_surface_has_buffer(wlr_surface)) { self.saved_buffers.items.len = 0;
_ = c.wlr_buffer_ref(wlr_surface.buffer); }
self.stashed_buffer = wlr_surface.buffer;
self.forEachSurface(saveBuffersIterator, &self.saved_buffers);
}
fn saveBuffersIterator(
wlr_surface: ?*c.wlr_surface,
surface_x: c_int,
surface_y: c_int,
data: ?*c_void,
) callconv(.C) void {
const saved_buffers = @ptrCast(
*std.ArrayList(SavedBuffer),
@alignCast(@alignOf(*std.ArrayList(SavedBuffer)), data),
);
if (wlr_surface) |surface| {
if (c.wlr_surface_has_buffer(surface)) {
saved_buffers.append(.{
.wlr_buffer = surface.buffer,
.box = Box{
.x = surface_x,
.y = surface_y,
.width = @intCast(u32, surface.current.width),
.height = @intCast(u32, surface.current.height),
},
}) catch return;
_ = c.wlr_buffer_ref(surface.buffer);
} }
} }
} }

View file

@ -136,36 +136,35 @@ fn renderLayer(output: Output, layer: std.TailQueue(LayerSurface), now: *c.times
} }
fn renderView(output: Output, view: *View, now: *c.timespec) void { fn renderView(output: Output, view: *View, now: *c.timespec) void {
// If we have a stashed buffer, we are in the middle of a transaction // If we have saved buffers, we are in the middle of a transaction
// and need to render that buffer until the transaction is complete. // and need to render those buffers until the transaction is complete.
if (view.stashed_buffer) |buffer| { if (view.saved_buffers.items.len != 0) {
var box = c.wlr_box{ for (view.saved_buffers.items) |saved_buffer| {
.x = view.current_box.x, var box = saved_buffer.box.toWlrBox();
.y = view.current_box.y, box.x += view.current_box.x;
.width = @intCast(c_int, view.current_box.width), box.y += view.current_box.y;
.height = @intCast(c_int, view.current_box.height),
};
// Scale the box to the output's current scaling factor // Scale the box to the output's current scaling factor
scaleBox(&box, output.wlr_output.scale); scaleBox(&box, output.wlr_output.scale);
var matrix: [9]f32 = undefined; var matrix: [9]f32 = undefined;
c.wlr_matrix_project_box( c.wlr_matrix_project_box(
&matrix, &matrix,
&box, &box,
.WL_OUTPUT_TRANSFORM_NORMAL, .WL_OUTPUT_TRANSFORM_NORMAL,
0.0, 0.0,
&output.wlr_output.transform_matrix, &output.wlr_output.transform_matrix,
); );
// This takes our matrix, the texture, and an alpha, and performs the actual // This takes our matrix, the texture, and an alpha, and performs the actual
// rendering on the GPU. // rendering on the GPU.
_ = c.wlr_render_texture_with_matrix( _ = c.wlr_render_texture_with_matrix(
output.getRenderer(), output.getRenderer(),
buffer.texture, saved_buffer.wlr_buffer.texture,
&matrix, &matrix,
1.0, 1.0,
); );
}
} else { } else {
// Since there is no stashed buffer, we are not in the middle of // Since there is no stashed buffer, we are not in the middle of
// a transaction and may simply render each toplevel surface. // a transaction and may simply render each toplevel surface.