Now, it is checked whether an output pixel corresponds to an integer
number of buffer pixels; if it doesn't, the region is altered to take
this into account.
This allows the backend to have access to the frame damage, as
reported by the scanned-out client. Some KMS drivers can make use
of it (e.g. for PSR, or optimized USB transfers in the GUD driver),
and the Wayland/X11 backends forward it to the parent compositor.
The concept of a persistent accumulated surface offset is wrong
from a protocol point-of-view. wl_surface.offset is tied to a
commit, its interpretation depends on the surface role.
For example, with the following sequence:
wl_surface@1.offset(1, 1)
wl_surface@1.commit()
wl_pointer@2.set_cursor(wl_surface@1, 42, 42)
The final cursor hotspot is (42, 42): the commit which happened
before the set_cursor request has no impact on the hotspot
computation.
The wlr_output_cursor logic already uses wlr_surface.current.{dx,dy}.
wlr_scene's drag icon doesn't, update it accordingly.
If a new buffer is set for a buffer node, we must update the entire
node unconditionally if the buffer size changes, or the buffer is given
a buffer where it was previously NULL.
While we're here, let's avoid calling scene_node_update on just damage
updates. If the caller hasn't given us a damage region we just assume
the whole buffer.
If the area calculations for output overlap overflow a signed int, we
may not consider it to be a primary output. Turn this into an unsigned
type so this happens less frequently.
Additionally, it is possible the overflow would produce 0, we can handle
this by simply changing the comparison to more than or equal.
While we're here, let's assert that we always assign a primary output
if there are any intersecting outputs.
Originally, I thought that we could safely subtract opaque regions
from the background even if the black rect optimization was kicking in.
This is wrong because a scene node that isn't fully occluded will still
appear in the render list even if its partially under a black rect. We
need to make sure that while culling the background, we only consider
opaque regions that are also visible. This will fix the black rect
optimization with the background.
We don't need to worry about the black rect optimization here (that
always assumes that there will be a black background) because the
background is culled based on the render list. That means if a black rect
is removed, the visibility will reach all the way to the bottom forcing
the renderer to clear the area not breaking the assumption.
If culling is not enabled, there is no longer any guarantee that the
elements behind the rect won't be rendered. We must render the black rect
in all circumstances to cover up anything rendered.
This fixes the WLR_SCENE_DISABLE_VISIBILTY option.
This has a few benefits one of them crucial for proper operation:
- The primary output will be based on the largest area that is actually
visible to the user. Presentation and frame done events are based on
this state. This is important to do since we cull frame done events.
If we happen to be in a situation where a surface sits mostly on output
A and some on output B but is completely obstructed by for instance a
fullscreen surface on output A we will erroneously send frame_done
events based on output A. If we base things as they are in reality
(visibility) the primary output will instead be output B and things will
work properly.
- The primary output will be NULL if the surface is completely hidden.
Due to quirks with wayland, on a surface commit, frame done events are
required to be sent. Therefore, a new frame will be submitted for rendering
on the primary output. We can improve adaptive sync on completely hidden
but enabled surfaces if we null out the primary output in this state.
- The client will be more likely to choose better metadata to use
for rendering to an output's optimal rendering characteristics.
We can also get rid of the intersection checks in the rendering functions
because we are guaranteed to already be in the node do to the prior
intersection checking of the node visibility.
Simplify damage handling by using our cached visibility state.
Damaging can happen in one step because since we can use the old visibility
state which represent what portions of the screen the scene node was. This
way we can damage everything in one step after the fact.