Introduce a new paint_node vfunc that, if implemented, allows
the effect to add nodes to a transient paint node that is
immediately painted. This is a transitional step until we
have fully delegated paint node rendering.
The most basic implementation of a ClutterEffect.paint_node
vfunc, and also the default implementation, is with an actor
node, as follows:
```
static void
foo_bar_paint_node (ClutterEffect *effect,
ClutterPaintNode *node,
ClutterPaintContext *paint_context,
ClutterEffectPaintFlags flags)
{
g_autoptr (ClutterPaintNode) actor_node = NULL;
actor_node = clutter_actor_node_new (effect->actor);
clutter_paint_node_add_child (node, actor_node);
}
```
This example gives the exact same behavior of simply calling
clutter_actor_continue_paint(). In the future, the paint node
itself will be a parameter of clutter_actor_continue_paint()
and we'll be able to simplify it event more.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1340>
ClutterEffectNode is a private ClutterPaintNode implementation
that does effectively nothing, but helps organizing the paint
node tree. It also helps debugging, since it can output the
effect class and name to the JSON debugging routines.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1340>
The idea of having a paint node tree is that we don't really need
to retrieve the framebuffer from ClutterPaintContext. For example,
ClutterLayerNode draws into an offscreen framebuffer; if any child
of a layer node needs to retrieve a framebuffer to draw, the layer
node's offscreen framebuffer should be used.
However, clutter_paint_node_get_framebuffer() goes straight to the
root node of the tree, skipping any potential paint nodes with a
custom framebuffer.
Modify clutter_paint_node_get_framebuffer() to walk up the paint
node tree until a node with a custom framebuffer appears. In many
cases, this will end up either in dummy or layer node's custom
framebuffer implementations.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1340>
Fixes a compiler warning with -Wmaybe-uninitialized enabled:
../../../../Source/gnome/mutter/clutter/clutter/clutter-actor.c: In function ‘clutter_actor_paint’:
../../../../Source/gnome/mutter/clutter/clutter/clutter-actor.c:3808:50: warning: ‘result’ may be used uninitialized in this function [-Wmaybe-uninitialized]
3808 | else if (result == CLUTTER_CULL_RESULT_OUT && success)
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~
Which might presumably happen in the unlikely case that there's no clip
frusta.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1624>
Instead of going through the event queue, stage handling code, and
back to the input device via a vmethod call, do this directly in the
MetaSeatImpl. This is not too different from X11, where everything
happens inside the backend.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403>
All that is left in the "public" struct is all state that ClutterStage
delegates on ClutterInputDevice. That should move somewhere else, but
not here, not now.
All private fields belong to construct-only properties, with only getter
API, and idempotent vmethods (except keyboard a11y, atm). This should
be enough to make ClutterInputDevice obviously thread safe, outside the
backend.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403>
Depending on the backend, we want to integrate this object at different
levels. It will sit close to the MetaBackendX11/MetaSeatX11 in X11, but
it will be put deep down with MetaSeatImpl in the native backend, in a
separate thread.
Since we can't depend on a single object type, nor are able to track
ClutterSeat signals neatly, make this API something to be called
explicitly by backends.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403>
This will query a device state; position and modifiers.
Note that ClutterSeat subclasses don't implement the vmethod yet,
so calling clutter_seat_query_state() may crash ATM.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403>
Testing points and rays against boxes is substantially cheaper - in
fact, almost trivial - compared to triangles. Check if the actor's
paint volume doesn't intersect with the current pick point / ray,
and skip recursing altogether in those cases.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1520>
The cached pick mode never actually cached anything, since it is
always, unconditionally reset when painting. Furthermore, next
commits will cull out actors during pick, which makes the pick
stack uncacheable.
Remove the cached pick mode.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1520>
Users of Debian arm64 (aarch64) report that on at least some GPUs
or screens, after time-based screen blanking has occurred, it is not
possible to unlock the screen. Bisection indicates that this regressed
in commit 209b1ba3, so presumably this is because a refresh rate of 0
is reported while the screen is blanked, leading to the frame clock
pausing forever.
Fixes: 209b1ba3 "clutter/frame-clock: Adapt refresh rate from to frame info"
Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/1536
Bug-Debian: https://bugs.debian.org/974172
Signed-off-by: Simon McVittie <smcv@debian.org>
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1601>
It's currently possible that some last_paint_volumes don't get updated
during a paint cycle, this can happen when a ClutterOffscreenEffect is
used: The offscreen effect might skip painting the content and the
children of an actor because it uses its own offscreened texture
instead. This means the offscreen effect doesn't call
clutter_actor_continue_paint(), and thus the the last_paint_volumes of
the children won't be updated.
Now one might think that isn't a problem, because as soon as a child
changes it's size or position, the offscreened texture would get
invalidated and clutter_actor_continue_paint() would get called. It's
not that easy though: Because the last_paint_volume includes all the
transformation matrices up to eye-coordinates, it has to be updated on
any changes to matrices, which includes position/transformation changes
to any actor up the hierarchy.
Now that's where get into problems with the offscreen effect: In case of
transformation changes to the offscreened actor or an actor up the
hierarchy, the offscreened texture won't get invalidated (that makes
sense, we can simply paint it transformed) and the last_paint_volumes
won't get updated even though they should.
This leaves us around with outdated last_paint_volumes where
last_paint_volume_valid is still set to TRUE. It can cause issues with
culling and clipped redraws.
So fix that by ensuring that all children that would get painted by
Clutter get their last_paint_volumes updated in case a ClutterEffect
decided not to call clutter_actor_continue_paint().
This ignores the case where a paint() vfunc override does the same and
doesn't call clutter_actor_paint() on children. Let's ignore this case
for now, there shouldn't be any implementation which does that and
ideally in a world that's painted solely by ClutterContent, we can get
rid of that vfunc in the future.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1591>
The first comment isn't really needed anymore since
the is_full_stage_redraw_queued() underneath is quite self-explaining.
Also rephrase the second comment a bit, including that
_clutter_paint_volume_get_stage_paint_box() does the aligning to the
pixel grid.
Finally, the last comment also looks out of date since we do that
rounding inside _clutter_paint_volume_get_stage_paint_box(), so remove
it.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1511>
We currently pass actors a reference to their associated
ClutterStageQueueRedrawEntry when queueing a redraw. This "splitting" of
the ownership of the entry has introduced quite a few bugs in the past
and is hard to follow.
So give up the "splitting" of the ownership and exclusively handle those
entries inside ClutterStage. To still allow removing the entry when an
actor gets unrealized introduce clutter_stage_dequeue_actor_redraw()
similar to what we already have for relayouts.
To be able to efficiently find entries when actors queue redraws, make
pending_queue_redraws a GHashTable, which fits quite nicely and also
allows removing the QueueRedrawEntries actor pointer in favour of the
key of the hashtable.
Since the struct is now private to ClutterStage, we can also rename it
to QueueRedrawEntry.
While at it, also sneak in the removal of the leading underscore from
clutter_stage_queue_actor_redraw().
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1511>
The "queue-redraw" signal is not used anywhere in Clutter and we now
also removed the vfunc implementation of the stage. So stop emitting it
and remove it, but keep the propagate_queue_redraw infrastructure to
make sure clones still get their redraws queued.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1511>
Since we now decoupled the "queue-redraw" signal from creating the stage
clip, we can move signal emission into
_clutter_actor_queue_redraw_full() and emit the signal right away when
queueing a redraw on an actor. With that we now no longer have to
accommodate for the stage pending_queue_redraws list changing while
iterating over it.
To ensure we don't emit the signal too often when multiple redraws are
queued on one actor, use the propagated_one_redraw flag to limit the
number of emissions to a single one for every update cycle.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1511>
Putting together the redraw clip of the stage never really fitted nicely
with the "queue-redraw" signal emission, it forces us to emit the
signals in a batch and we also use a weird trick to get the old paint
volume that's already on-screen into the final redraw clip (we call
_clutter_actor_propagate_queue_redraw() on the stage).
So start breaking up this association by making the stage explicitely
request the redraw clip from the actor and removing the
ClutterPaintVolume argument from _clutter_actor_finish_queue_redraw().
This is done by adding a private function
clutter_actor_get_redraw_clip() which returns our old (currently
visible) paint volume and the new paint volume.
This also allows removing the check whether a full stage redraw has been
queued in clutter_actor_real_queue_redraw() and we can now just stop the
signal emission if a propagation happened at least once.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1511>
The most common case for Clutter is 2D axis-aligned actors, which
maintain these properties even after projecting to eye coordinates.
In those cases, we can use a simpler hit test by checking against
boxes.
Not only this is simpler, but this maintains an important aspect
of picking that is a requirement for Clutter: watertightness. Even
though the triangles checks do work on x86_64, they do not guarantee
watertightness. This breaks tests on ARM.
Use graphene_box_t to hit-test axis-aligned 2D actors.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1599>