It was completely wrong: according to the protocol, the effective
geometry is only updated on commit time if there pending state has
new state from xdg_surface.set_window_geometry or
xdg_surface.set_window_geometry has never been sent at all.
This commit adds wlr_xdg_surface.geometry which correctly matches the
effective window geometry and removes now-useless
wlr_xdg_surface_get_geometry().
It seems that some scene compositors want to avoid wlr_scene_output_commit
and use the lower lever wlr_scene_output_build_state. However, build
state does not early return if a frame is not needed so compositors will
implement the check themselves. Let's add a helper function that compositors
can use to implement the check.
Technically pending_commit_damage is a private interface, so this lets
compositors not interface with private interfaces to implement the check.
This fixes direct scanout VRR. As direct scanout buffers are not part
of the swapchain, we would mistakenly union instead of subtract the damage
meaning it will just accumulate indefinitely.
The reason for this existing in the first place is for compositors that
might want to sidestep scene and commit their own buffers to the output.
In this case, scene could theoretically acknowledge that and update the
damage. Except, this really didn't work because WLR_OUTPUT_STATE_DAMAGE
would need to be defined which is optional. This patch also properly
acknowledges commits without damage.
In the use case of a weird compositor that might want to sidestep scene,
they can just trash the damage ring themselves.
Fixes: #3871
There were two problems with the old implementation:
1. wlr_scene_output_commit would bail early if a frame wasn't requested
and there was no commit damage, however commit damage could never accumulate
until rendering happens. The check was subtly wrong as a result.
2. Previously, we would fill the pending commit damage based on the
current state of the damage ring. However, during direct scanout, the
damage would accumulate which would mean we would submit damage from
previous frames even if we didn't need to.
The old logic might not update the entire scene node when a node is
disabled. It would only consider the damage last time (the damage was
based on the visible region of the node).
It's important that we update the entire node region because xwayland
stacking will depend on this.
We were relying on the fact that we wouldn't paint anything on top
of the black background in the region of a black rect. However
when fractional scaling is used the repaint region might get
expanded to nearby pixels by scale_output_damage(). As a result
the neighbour scene nodes might leak into the skipped black rect's
region.
Avoid this by using this optimization for bottom-most black rects
only when fractional scaling is used.
References: https://github.com/swaywm/sway/issues/8233
If we need to apply a color transform to rendered content, we will not
be able to use direct scanout. Explicitly skip it to not accidentally
show frames lacking the color transform.
Clients may, for example, commit an exclusive zone larger than the
output dimensions. Compositors must handle this gracefully, which likely
requires more work on the compositor side but returning a usable area
with negative width or height in wlr_scene_layer_surface_v1_configure()
is nonsensical.
If we hit this case, we effectively failed to render something, this might
be because a texture failed to upload or the texture is momentarily
unavailable after a GPU reset. If we fail to render, we have to continue
to track damage for the next frame in hopes that the texture becomes
available then.
An alternative approach would be to fail the commit completely if we
find this case, but in the case of gpu resets, clients may not commit
a new buffer for a while, and a frozen display does not help.
This fixes damage tracking issues after a gpu reset.
We will soon support custom swapchains. In order to track output damage
we should instead use the damage_ring which will hold all the buffers
we are currently tracking anyway across an arbitrary amount of swapchains.
We would fail to call scene_node_update() which would then call output
events for us. We need to make sure to update the node when we first map
a buffer, as the comment explained.