aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIsaac Freund <mail@isaacfreund.com>2023-01-06 18:51:40 +0100
committerIsaac Freund <mail@isaacfreund.com>2023-01-06 18:51:40 +0100
commitdf2fc30238fe445cf04aaf64d0b906195129f726 (patch)
tree95d4b6890e2f1bd72bbf2b27b0a6c2bc55d5ef33
parentc479525ab8f54cbaf5f63e83267ca6d1ef23296f (diff)
downloadriver-df2fc30238fe445cf04aaf64d0b906195129f726.tar.gz
river-df2fc30238fe445cf04aaf64d0b906195129f726.tar.xz
session-lock: wait for present before locking
Currently we send the locked event after rendering and commit of blank or lock surfaces buffers on all outputs. However, this is technically not enough to ensure that the buffers have been presented. Instead, listen to the wlr_output present event to ensure that no normal, "unlocked" content is possibly visible.
-rw-r--r--river/LockManager.zig2
-rw-r--r--river/Output.zig41
-rw-r--r--river/render.zig7
3 files changed, 46 insertions, 4 deletions
diff --git a/river/LockManager.zig b/river/LockManager.zig
index cc4b56a..6723bd4 100644
--- a/river/LockManager.zig
+++ b/river/LockManager.zig
@@ -149,7 +149,7 @@ pub fn maybeLock(manager: *LockManager) void {
while (it) |node| : (it = node.next) {
const output = &node.data;
switch (output.lock_render_state) {
- .unlocked => {
+ .unlocked, .pending_blank, .pending_lock_surface => {
all_outputs_blanked = false;
all_outputs_rendered_lock_surface = false;
},
diff --git a/river/Output.zig b/river/Output.zig
index d1469d9..0d5a541 100644
--- a/river/Output.zig
+++ b/river/Output.zig
@@ -70,8 +70,17 @@ views: ViewStack(View) = .{},
lock_surface: ?*LockSurface = null,
lock_render_state: enum {
+ /// Normal, "unlocked" content may be visible.
unlocked,
+ /// Submitted a blank buffer but the buffer has not yet been presented.
+ /// Normal, "unlocked" content may be visible.
+ pending_blank,
+ /// A blank buffer has been presented.
blanked,
+ /// Submitted the lock surface buffer but the buffer has not yet been presented.
+ /// Normal, "unlocked" content may be visible.
+ pending_lock_surface,
+ /// The lock surface buffer has been presented.
lock_surface,
} = .unlocked,
@@ -102,6 +111,7 @@ status_trackers: std.SinglyLinkedList(OutputStatus) = .{},
destroy: wl.Listener(*wlr.Output) = wl.Listener(*wlr.Output).init(handleDestroy),
enable: wl.Listener(*wlr.Output) = wl.Listener(*wlr.Output).init(handleEnable),
mode: wl.Listener(*wlr.Output) = wl.Listener(*wlr.Output).init(handleMode),
+present: wl.Listener(*wlr.Output.event.Present) = wl.Listener(*wlr.Output.event.Present).init(handlePresent),
frame: wl.Listener(*wlr.OutputDamage) = wl.Listener(*wlr.OutputDamage).init(handleFrame),
damage_destroy: wl.Listener(*wlr.OutputDamage) = wl.Listener(*wlr.OutputDamage).init(handleDamageDestroy),
@@ -140,6 +150,7 @@ pub fn init(self: *Self, wlr_output: *wlr.Output) !void {
wlr_output.events.destroy.add(&self.destroy);
wlr_output.events.enable.add(&self.enable);
wlr_output.events.mode.add(&self.mode);
+ wlr_output.events.present.add(&self.present);
self.damage.?.events.frame.add(&self.frame);
self.damage.?.events.destroy.add(&self.damage_destroy);
@@ -478,6 +489,7 @@ fn handleDestroy(listener: *wl.Listener(*wlr.Output), _: *wlr.Output) void {
self.enable.link.remove();
self.frame.link.remove();
self.mode.link.remove();
+ self.present.link.remove();
// Free all memory and clean up the wlr.Output
if (self.layout_demand) |demand| demand.deinit();
@@ -511,6 +523,35 @@ fn handleMode(listener: *wl.Listener(*wlr.Output), _: *wlr.Output) void {
server.root.startTransaction();
}
+fn handlePresent(
+ listener: *wl.Listener(*wlr.Output.event.Present),
+ event: *wlr.Output.event.Present,
+) void {
+ const self = @fieldParentPtr(Self, "present", listener);
+
+ switch (self.lock_render_state) {
+ .unlocked => return,
+ .pending_blank, .pending_lock_surface => {
+ if (!event.presented) {
+ self.lock_render_state = .unlocked;
+ self.damage.?.addWhole();
+ return;
+ }
+
+ self.lock_render_state = switch (self.lock_render_state) {
+ .pending_blank => .blanked,
+ .pending_lock_surface => .lock_surface,
+ .unlocked, .blanked, .lock_surface => unreachable,
+ };
+
+ if (server.lock_manager.state != .locked) {
+ server.lock_manager.maybeLock();
+ }
+ },
+ .blanked, .lock_surface => unreachable,
+ }
+}
+
fn setTitle(self: Self) void {
const title = fmt.allocPrintZ(util.gpa, "river - {s}", .{self.wlr_output.name}) catch return;
defer util.gpa.free(title);
diff --git a/river/render.zig b/river/render.zig
index adef939..a238cd9 100644
--- a/river/render.zig
+++ b/river/render.zig
@@ -98,9 +98,10 @@ pub fn renderOutput(output: *Output) void {
return;
};
- output.lock_render_state = if (output.lock_surface != null) .lock_surface else .blanked;
- if (server.lock_manager.state != .locked) {
- server.lock_manager.maybeLock();
+ if (output.lock_surface == null) {
+ output.lock_render_state = .pending_blank;
+ } else {
+ output.lock_render_state = .pending_lock_surface;
}
return;