diff options
| author | Isaac Freund <mail@isaacfreund.com> | 2023-01-06 18:51:40 +0100 |
|---|---|---|
| committer | Isaac Freund <mail@isaacfreund.com> | 2023-01-06 18:51:40 +0100 |
| commit | df2fc30238fe445cf04aaf64d0b906195129f726 (patch) | |
| tree | 95d4b6890e2f1bd72bbf2b27b0a6c2bc55d5ef33 | |
| parent | c479525ab8f54cbaf5f63e83267ca6d1ef23296f (diff) | |
| download | river-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.zig | 2 | ||||
| -rw-r--r-- | river/Output.zig | 41 | ||||
| -rw-r--r-- | river/render.zig | 7 |
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; |
