transactions: save transform, refactor rendering

This commit is contained in:
Isaac Freund 2020-06-10 00:06:26 +02:00
parent 48ea771310
commit ddc7da0f16
No known key found for this signature in database
GPG key ID: 86DED400DDFD7A11
2 changed files with 44 additions and 55 deletions

View file

@ -41,6 +41,7 @@ const Impl = union(enum) {
const SavedBuffer = struct { const SavedBuffer = struct {
wlr_buffer: *c.wlr_buffer, wlr_buffer: *c.wlr_buffer,
box: Box, box: Box,
transform: c.wl_output_transform,
}; };
/// The implementation of this view /// The implementation of this view
@ -173,6 +174,7 @@ fn saveBuffersIterator(
.width = @intCast(u32, surface.current.width), .width = @intCast(u32, surface.current.width),
.height = @intCast(u32, surface.current.height), .height = @intCast(u32, surface.current.height),
}, },
.transform = surface.current.transform,
}) catch return; }) catch return;
_ = c.wlr_buffer_ref(surface.buffer); _ = c.wlr_buffer_ref(surface.buffer);
} }

View file

@ -129,7 +129,7 @@ fn renderLayer(output: Output, layer: std.TailQueue(LayerSurface), now: *c.times
}; };
c.wlr_layer_surface_v1_for_each_surface( c.wlr_layer_surface_v1_for_each_surface(
layer_surface.wlr_layer_surface, layer_surface.wlr_layer_surface,
renderSurface, renderSurfaceIterator,
&rdata, &rdata,
); );
} }
@ -139,32 +139,18 @@ fn renderView(output: Output, view: *View, now: *c.timespec) void {
// If we have saved buffers, 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 those buffers until the transaction is complete. // and need to render those buffers until the transaction is complete.
if (view.saved_buffers.items.len != 0) { if (view.saved_buffers.items.len != 0) {
for (view.saved_buffers.items) |saved_buffer| { for (view.saved_buffers.items) |saved_buffer|
var box = saved_buffer.box.toWlrBox(); renderTexture(
box.x += view.current_box.x; output,
box.y += view.current_box.y;
// Scale the box to the output's current scaling factor
scaleBox(&box, output.wlr_output.scale);
var matrix: [9]f32 = undefined;
c.wlr_matrix_project_box(
&matrix,
&box,
.WL_OUTPUT_TRANSFORM_NORMAL,
0.0,
&output.wlr_output.transform_matrix,
);
// This takes our matrix, the texture, and an alpha, and performs the actual
// rendering on the GPU.
_ = c.wlr_render_texture_with_matrix(
output.getRenderer(),
saved_buffer.wlr_buffer.texture, saved_buffer.wlr_buffer.texture,
&matrix, .{
1.0, .x = saved_buffer.box.x + view.current_box.x,
.y = saved_buffer.box.y + view.current_box.y,
.width = @intCast(c_int, saved_buffer.box.width),
.height = @intCast(c_int, saved_buffer.box.height),
},
saved_buffer.transform,
); );
}
} 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.
@ -175,7 +161,7 @@ fn renderView(output: Output, view: *View, now: *c.timespec) void {
.when = now, .when = now,
}; };
view.forEachSurface(renderSurface, &rdata); view.forEachSurface(renderSurfaceIterator, &rdata);
} }
} }
@ -197,58 +183,59 @@ fn renderXwaylandUnmanaged(output: Output, now: *c.timespec) void {
.output_y = wlr_xwayland_surface.y - output_box.y, .output_y = wlr_xwayland_surface.y - output_box.y,
.when = now, .when = now,
}; };
c.wlr_surface_for_each_surface(wlr_xwayland_surface.surface, renderSurface, &rdata); c.wlr_surface_for_each_surface(wlr_xwayland_surface.surface, renderSurfaceIterator, &rdata);
} }
} }
/// This function is passed to wlroots to render each surface during iteration /// This function is passed to wlroots to render each surface during iteration
fn renderSurface( fn renderSurfaceIterator(
_surface: ?*c.wlr_surface, surface: ?*c.wlr_surface,
surface_x: c_int, surface_x: c_int,
surface_y: c_int, surface_y: c_int,
data: ?*c_void, data: ?*c_void,
) callconv(.C) void { ) callconv(.C) void {
// wlroots says this will never be null
const surface = _surface.?;
const rdata = @ptrCast(*SurfaceRenderData, @alignCast(@alignOf(SurfaceRenderData), data)); const rdata = @ptrCast(*SurfaceRenderData, @alignCast(@alignOf(SurfaceRenderData), data));
const output = rdata.output;
const wlr_output = output.wlr_output;
// We first obtain a wlr_texture, which is a GPU resource. wlroots renderTexture(
// automatically handles negotiating these with the client. The underlying rdata.output.*,
// resource could be an opaque handle passed from the client, or the client c.wlr_surface_get_texture(surface),
// could have sent a pixel buffer which we copied to the GPU, or a few other .{
// means. You don't have to worry about this, wlroots takes care of it. .x = rdata.output_x + surface_x,
const texture = c.wlr_surface_get_texture(surface); .y = rdata.output_y + surface_y,
if (texture == null) { .width = surface.?.current.width,
return; .height = surface.?.current.height,
} },
surface.?.current.transform,
);
var box = c.wlr_box{ c.wlr_surface_send_frame_done(surface, rdata.when);
.x = rdata.output_x + surface_x, }
.y = rdata.output_y + surface_y,
.width = surface.current.width, /// Render the given texture at the given box, taking the scale and transform
.height = surface.current.height, /// of the output into account.
}; fn renderTexture(
output: Output,
wlr_texture: ?*c.wlr_texture,
wlr_box: c.wlr_box,
transform: c.wl_output_transform,
) void {
const texture = wlr_texture orelse return;
var box = wlr_box;
// Scale the box to the output's current scaling factor // Scale the box to the output's current scaling factor
scaleBox(&box, wlr_output.scale); scaleBox(&box, output.wlr_output.scale);
// wlr_matrix_project_box is a helper which takes a box with a desired // wlr_matrix_project_box is a helper which takes a box with a desired
// x, y coordinates, width and height, and an output geometry, then // x, y coordinates, width and height, and an output geometry, then
// prepares an orthographic projection and multiplies the necessary // prepares an orthographic projection and multiplies the necessary
// transforms to produce a model-view-projection matrix. // transforms to produce a model-view-projection matrix.
var matrix: [9]f32 = undefined; var matrix: [9]f32 = undefined;
const transform = c.wlr_output_transform_invert(surface.current.transform); const inverted = c.wlr_output_transform_invert(transform);
c.wlr_matrix_project_box(&matrix, &box, transform, 0.0, &wlr_output.transform_matrix); c.wlr_matrix_project_box(&matrix, &box, inverted, 0.0, &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(output.getRenderer(), texture, &matrix, 1.0); _ = c.wlr_render_texture_with_matrix(output.getRenderer(), texture, &matrix, 1.0);
// This lets the client know that we've displayed that frame and it can
// prepare another one now if it likes.
c.wlr_surface_send_frame_done(surface, rdata.when);
} }
fn renderBorders(output: Output, view: *View, now: *c.timespec) void { fn renderBorders(output: Output, view: *View, now: *c.timespec) void {