Will be used to trace a lot more, and with more details, and thus may
have a larger impact on what is actually measured. This potential impact
is the reason for enabling only when needed.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1700>
The failure to allocate was not properly handled, causing crashes later
on due to the offscreen being NULL.
#0 cogl_gl_framebuffer_bind (target=36160, gl_framebuffer=0x0)
#1 _cogl_driver_gl_flush_framebuffer_state (...)
#2 cogl_context_flush_framebuffer_state (read_buffer=0x55f48f386780, draw_buffer=0x55f48f386780, ...)
#3 cogl_framebuffer_clear4f (framebuffer=0x55f48f386780, ...)
#4 clutter_layer_node_pre_draw (...)
#5 clutter_paint_node_paint (...)
...
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1942>
We only listen to it for 2 settings (drag threshold, double click
time), and we already have the stock ClutterSettings object tracking
the source of these. This code is redundant.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1862>
Not sure how to update the damage or redraw clip or something; at least
this works properly when under a constantly-redrawing window, which is
ok for debugging purposes.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1762>
Max render time shows how early the frame clock needs to be dispatched
to make it to the predicted next presentation time. Before this commit
it was set to refresh interval minus 2 ms. This means Mutter would
always start compositing 14.7 ms before a display refresh on a 60 Hz
screen or 4.9 ms before a display refresh on a 144 Hz screen. However,
Mutter frequently does not need as much time to finish compositing and
submit buffer to KMS:
max render time
/------------\
---|---------------|---------------|---> presentations
D----S D--S
D - frame clock dispatch
S - buffer submission
This commit aims to automatically compute a shorter max render time to
make Mutter start compositing as late as possible (but still making it
in time for the presentation):
max render time
/-----\
---|---------------|---------------|---> presentations
D----S D--S
Why is this better? First of all, Mutter gets application contents to
draw at the time when compositing starts. If new application buffer
arrives after the compositing has started, but before the next
presentation, it won't make it on screen:
---|---------------|---------------|---> presentations
D----S D--S
A-------------X----------->
^ doesn't make it for this presentation
A - application buffer commit
X - application buffer sampled by Mutter
Here the application committed just a few ms too late and didn't make on
screen until the next presentation. If compositing starts later in the
frame cycle, applications can commit buffers closer to the presentation.
These buffers will be more up-to-date thereby reducing input latency.
---|---------------|---------------|---> presentations
D----S D--S
A----X---->
^ made it!
Moreover, applications are recommended to render their frames on frame
callbacks, which Mutter sends right after compositing is done. Since
this commit delays the compositing, it also reduces the latency for
applications drawing on frame callbacks. Compare:
---|---------------|---------------|---> presentations
D----S D--S
F--A-------X----------->
\____________________/
latency
---|---------------|---------------|---> presentations
D----S D--S
F--A-------X---->
\_____________/
less latency
F - frame callback received, application starts rendering
So how do we actually estimate max render time? We want it to be as low
as possible, but still large enough so as not to miss any frames by
accident:
max render time
/-----\
---|---------------|---------------|---> presentations
D------S------------->
oops, took a little too long
For a successful presentation, the frame needs to be submitted to KMS
and the GPU work must be completed before the vblank. This deadline can
be computed by subtracting the vblank duration (calculated from display
mode) from the predicted next presentation time.
We don't know how long compositing will take, and we also don't know how
long the GPU work will take, since clients can submit buffers with
unfinished GPU work. So we measure and estimate these values.
The frame clock dispatch can be split into two phases:
1. From start of the dispatch to all GPU commands being submitted (but
not finished)—until the call to eglSwapBuffers().
2. From eglSwapBuffers() to submitting the buffer to KMS and to GPU
work completing. These happen in parallel, and we want the latest of
the two to be done before the vblank.
We measure these three durations and store them for the last 16 frames.
The estimate for each duration is a maximum of these last 16 durations.
Usually even taking just the last frame's durations as the estimates
works well enough, but I found that screen-capturing with OBS Studio
increases duration variability enough to cause frequent missed frames
when using that method. Taking a maximum of the last 16 frames smoothes
out this variability.
The durations are naturally quite variable and the estimates aren't
perfect. To take this into account, an additional constant 2 ms is added
to the max render time.
How does it perform in practice? On my desktop with 144 Hz monitors I
get a max render time of 4–5 ms instead of the default 4.9 ms (I had
1 ms manually configured in sway) and on my laptop with a 60 Hz screen I
get a max render time of 4.8–5.5 ms instead of the default 14.7 ms (I
had 5–6 ms manually configured in sway). Weston [1] went with a 7 ms
default.
The main downside is that if there's a sudden heavy batch of work in the
compositing, which would've made it in default 14.7 ms, but doesn't make
it in reduced 6 ms, there is a delayed frame which would otherwise not
be there. Arguably, this happens rarely enough to be a good trade-off
for reduced latency. One possible solution is a "next frame is expected
to be heavy" function which manually increases max render time for the
next frame. This would avoid this single dropped frame at the start of
complex animations.
[1]: https://www.collabora.com/about-us/blog/2015/02/12/weston-repaint-scheduling/
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1762>
This fixes a warning/error:
In function 'parse_settings',
inlined from 'read_settings' at ../clutter/clutter/x11/xsettings/xsettings-client.c:398:25:
../clutter/clutter/x11/xsettings/xsettings-client.c:202:13: error: 'buffer.byte_order' may be used uninitialized [-Werror=maybe-uninitialized]
202 | if (buffer.byte_order != MSBFirst &&
| ~~~~~~^~~~~~~~~~~
This is needed to bump the CI image from F33 to F34, which includes a
upgraded compiler.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1865>
A simply wrapper around `CoglTexture`, making it easy to reuse
content without roundtrip from GPU to CPU memory and back.
It optionally takes a clip rectangle which is implemented by
creating a `CoglSubTexture`. A limitation here is that floating
point clips are not supported.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1888>
When using `CLUTTER_PAINT=damage-region` highlighting was conspicuously
absent during fullscreen animations like entering or leaving the
overview. That was because `queued_redraw_clip` was empty, because it
had been initialized from `redraw_clip == NULL` (full stage redraw).
Now we paint the damage region as the full view (which it is) instead
of nothing at all.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1890>
This commit adds scaling support to clutter_stage_capture_into, which
is currently used when screencasting monitors. This is supposed to
fix graphical issues that arise when using fractional scaling.
Fixes#1131
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1855>
All pointer a11y is a fabrication of Clutter backend-independent
code, with the help of a ClutterVirtualInputDevice and with some
UI on top.
On the other hand, MetaInputSettings is a backend implementation
detail, this has 2 gotchas:
- In the native backend, the MetaInputSettings (and pointer a11y
with it) are initialized early, before the ClutterSeat core
pointer is set up.
- Doing this from the MetaInputSettings also means another dubious
access from the input thread into main thread territory.
Move the pointer a11y into ClutterSettings, making this effectively
backend-independent business, invariably done from the main thread
and ensured to happen after seat initialization.
Fixes: https://gitlab.gnome.org/GNOME/mutter/-/issues/1765
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1849>
Since commit d2f8a30625 we use Graphene to union paint volumes, it
turns out a quite severe issue snuck in during review of that MR though:
Unioned paint volumes (so paint volumes of any actors with children) now
have negative heights. Once projected to 2d coordinates they luckily are
correct again, which is why everything is still working.
The problem is that obvious once looking closer: For the y coordinates
of the unioned paint volume we confused the maximum and the minimum
points and simply used the wrong coordinates to create the unioned paint
volume.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1827>
The graphene functions used by clutter for picking assume that boxes are
inclusive in both there start and end coordinates, so picking at y
coordinate 32 for an actor with the height 32 placed at y coordinate 0
would still be considered a hit. This however is wrong as 32 is the
first position that is not in the actor anymore.
Usually this would not be much of a problem, because motion events are
rarely ever at exactly these borders and even if they are there will be
another motion event soon after. But since actors in gnome-shell usually
are aligned with the pixel grid and on X11 enter/leave events are
generated by the X server at integer coordinates, this case is much
more likely for those.
This can cause issues with Firefox which when using client side
decorations, still requests MWM_DECOR_BORDER via _MOTIF_WM_HINTS to have
mutter draw a border + shadow. This means that the Firefox window even
when using CSD is still reparented. For such windows we receive among
others XI_RawMotion and XI_Enter events, but no XI_Motion events. And
the raw motion events are discarded after an enter event, because that
sets has_pointer_focus to TRUE in MetaSeatX11. So when moving the cursor
from the panel to a maximized Firefox window the last event clutter
receives is the enter event at exactly integer coordinates. Since the
panel is 32px tall and the generated enter event is at y position 32,
the picking code will pick a panel actor and the focus will remain on it
as long as the cursor does not leave the Firefox window.
Fix this by excluding the bottom and right border of a box when picking.
Fixes https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/4041
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1842>
Turns out ClutterClones need a bit of extra handling as always, there's
currently nothing that invalidates a clones paint volume when the source
actors paint volume changes.
Since ClutterClones get_paint_volume() implementation simply takes the
source actors paint volume and returns that, we should make sure they
are kept in sync and invalidate the clones paint volume as soon as the
source actor gets its PV invalidated.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1829>
Updating the last_paint_volume while painting has proven itself to be
quite prone to issues: First we had to make sure actors painted by
offscreen effects get their last_paint_volumes updated correctly (see
0320649a1c), and now a new issue turned up
where we don't update the paint volumes while a fullscreen unredirect is
happening.
To stop those issues from happening and to lay the foundation for using
the last_paint_volume for other things, update the last_paint_volume in
a separate step before painting instead of doing it in
clutter_actor_paint().
To save some resources, avoid introducing another traversal of the
scenegraph and add that step into the existing step of updating the
stage_views lists of actors. To properly update the paint volumes, we
need to do that after finishing the queued redraws, which is why we move
clutter_stage_maybe_finish_queue_redraws() to happen before the new
clutter_stage_finish_layout().
Fixes https://gitlab.gnome.org/GNOME/mutter/-/issues/1699
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1773>
The priv->paint_volume field of ClutterActor stores the cached paint
volume in the actors local coordinate system. It consist of the actors
paint volume itself and the union of all children paint volumes.
We want to invalidate those cached paint volumes according to the
following rules:
- If an actors transformation matrix changes, all paint volumes of the
parent-tree need to be invalidated (that's because the parent-volumes
have unioned the actors paint volume). Our own paint volume does not
need invalidation since the transformation matrix is not applied to it.
- If an actors allocation-size changes, its own paint volume and all the
volumes of the parent-tree need to be invalidated. That's because the
allocation-size is used as the size of the paint volume.
- If a clip gets set or clip_to_allocation gets enabled for an actor,
its own paint volume and all the volumes of the parent-tree need to be
invalidated. That's because the clip is factored in when creating the
paint volume.
So far we did this invalidation in various places and the invalidation
up the parent-tree happened inside clutter_actor_real_queue_relayout().
We did not invalidate on changes to the actors transformation matrices
and the invalidation in clutter_actor_real_queue_relayout() was more
like a "big hammer" that probably invalidated unnecessarily a few times.
So introduce proper infrastructure to invalidate those cached paint
volumes of actors only in the cases where they actually need to be
invalidated. To do that, we reuse the transform_changed() function and
introduce a new function queue_update_paint_volume() that invalidates
the paint volumes up the actor tree.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1773>
ClutterActors can override the get_paint_volume() vfunc in case they
draw outside the allocation. That's used by a bunch of actors, for
example ClutterText or StViewport in gnome-shell.
In case of StViewport, the paint volume returned depends on the value of
the StAdjustment, which means when we start to cache paint volumes more
agressively in ClutterActor, we'll need to add API that allows
StViewport to invalidate the paint volume. So introduce
clutter_actor_invalidate_paint_volume() to invalidate the cached paint
volume.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1773>
The action might not have been triggered yet, as per its trigger
threshold. This doesn't mean we shouldn't reset the point(s) accumulated
so far.
This fixes those touchpoints persisting after disable/enable, thus
making gesture recognition fail from there on.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1791>
We might want to perform distance/threshold checks in the ::prepare
vfunc, but we didn't record the last motion event yet. This used to
give a delta of 0/0 between the press and last motion coordinates,
despite the ClutterGestureAction having a trigger threshold. This
happens no longer.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1791>
The usage of clutter_actor_get_preferred_width/height() for building the
pick box can trigger Clutters size negotiation machinery in case the
allocation of the actor is invalidated, with commit 82f3bdd1 we worked
around that by excluding actors with invalidated allocations from
picking.
There's no need to do that though, when picking we always want to
operate on the last known allocation of the actor, since that is what's
actually painted on the screen.
So instead of not picking at all when an actors allocation is
invalidated, just use the size of the last allocation. We still have to
factor in one extra case, that's when an actor hasn't gotten any
allocation yet: In that case we want to exclude the actor from picking
since the actor is not on the screen yet.
This fixes a regression introduced by the commit mentioned above where
picking wouldn't work on windows that have just been resized.
https://gitlab.gnome.org/GNOME/mutter/-/issues/1674
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1784>
As documented in g_once_init_enter(): "While @location has a volatile qualifier,
this is a historical artifact and the pointer passed to it should not be
volatile.". And effectively this now warns with modern glibc.
Drop the "volatile" qualifier from these static variables as it's expected.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1785>
Some events such as the proximity one requires a device to be set before
we process them, so ensure we process the event details after we've
added the device to the seat.
This may lead to handle a device-removed signal before the clutter event
but it's anyways not different from what we did before commit 012c0a18
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1779>
The CallyStage objects lifetime is tied to the stage, so if we add a
weak pointer to it, we won't be able to remove it, as we would try to do
so not until the stage itself is being disposed, at which point removing
it fails. However, not removing it will make the stage try to clean up
the weak refs, and since it does this more or less directly after
freeing the cally stage, it ends up writing NULL to freed memory,
causing memory corruption.
Fix this by avoiding adding the weak pointer when that pointer is to the
stage.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1775>
This adds a test framework that makes it possible to compare the result
of painting a view against a reference image. Test reference as PNG
images are stored in src/tests/ref-tests/.
Reference images needs to be created for testing to be able to succeed.
Adding a test reference image is done using the
`MUTTER_REF_TEST_UPDATE` environment variable. See meta-ref-test.c for
details.
The image comparison code is largely based on the reference image test
framework in weston; see meta-ref-test.c for details.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1698>
Since commit 2ceac4a device-related X11 events aren't processed anymore,
causing the input settings not to handle the devices.
This is due to the fact that we may never call clutter_seat_handle_event_post()
for such events.
While this is always happening for the native backend, it doesn't happen in
X11 because the events are removed from the queue as part of
meta_x11_handle_event(), and thus no event was queued to the stage by the
backend events source.
This also makes sure that the event post handler is called after the
event is actually processed, and not before an event is queued.
Fixes: https://gitlab.gnome.org/GNOME/mutter/-/issues/1564
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1769>
To make the double buffered shadow buffer damaged tiles detection
feasable, a new EGL extension is needed for creating FBO's backed by
a custom CPU memory buffer, instead of DMA buffers, as DMA buffers can
be very slow to read, much slower than just painting the shadow buffer
directly.
Leave the code there, since such an EGL extension is intended to be
added, but hide it behind an env var so that it isn't enabled by
accident.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1724>
Regarding the sequence = 0 fallback: in some cases (moving a cursor
plane on atomic amdgpu) we get sequence = 0 in the page flip callback.
This seems like an amdgpu bug, so work around it by assuming a sequence
delta of 1 (it is equal to 1 because of the sequence != 0 check above).
Sequence can also legitimately be 0 if we're lucky during the 32-bit
overflow, in which case assuming a delta of 1 will give more or less
reasonable values on this and next presentation, after which it'll be
back to normal.
Sequence is also 0 on mode set fallback and when running nested, in
which case assuming a delta of 1 every frame is the best we can do.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1484>
This concerns only the cases when the presentation timestamp is received
directly from the device (from KMS or from GLX). In the majority of
cases this timestamp is already MONOTONIC. When it isn't, after this
commit, the current value of the MONOTONIC clock is sampled instead.
The alternative is to store the clock id alongside the timestamp, with
possible values of MONOTONIC, REALTIME (from KMS) and GETTIMEOFDAY (from
GLX; this might be the same as REALTIME, I'm not sure), and then
"convert" the timestamp to MONOTONIC when needed. An example of such a
conversion was done in compositor.c (removed in this commit). It would
also be needed for the presentation-time Wayland protocol. However, it
seems that the vast majority of up-to-date systems are using MONOTONIC
anyway, making this effort not justified.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1484>
KMS and GLX device timestamps have microsecond precision, and whenever
we sample the time ourselves it's not the real presentation time anyway,
so nanosecond precision for that case is unnecessary.
The presentation timestamp in ClutterFrameInfo is in microseconds, too,
so this commit makes them have the same precision.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1484>
A flag indicating whether the presentation timestamp was provided by
the display hardware (rather than sampled in user space).
It will be used for the presentation-time Wayland protocol.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1484>
ClutterText has a bit of a mess around its signalling of changes to the
cursor position: There's the position (deprecated) and cursor-position
property, and there's the cursor-changed and cursor-event (deprecated)
signal. The two properties are supposed to be notified when the cursor
position changes, and the two signals are notified when the cursor
position or size changes.
Now the properties notifications and the signals get fired in two very
different places: The two properties are notified in
clutter_text_set_cursor_position(), while the signals are fired during
the paint cycle when we figured out the final cursor position. The
latter is a pretty bad idea, nobody expects such a signal to be fired
during painting, and also changes to the text that are done in the
signal handler will only be applied on the next paint.
Now StEntry listens to cursor position changes via cursor-changed and
invalidates its text shadow, but since the signal is only notified
during the paint, the old text shadow will still get applied. To fix
this, also emit the cursor-changed signal when we notify the
cursor-position property.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1757>
This removes the responsibility of tracking these from the backend to
the base object. The backends are instead responsible for calling the
function to update the values.
For the native backend, it's important that this happens on the correct
thread, so each time either of these states may change, post a idle
callback on the main thread that sets the, at the time of queuing said
callback, up to date state. This means that things on the main thread
will always be able to get a "new enough but not too new" state when
listening on the 'notify::' signals and getting the property value
after.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1739>
In an x11 session, we don't receive motion events from X when the
pointer is above a window. Since commit 734a1859 we only do picking on
motion events though, which means when clicking the mouse to focus a
window, we don't repick and might still think the pointer is hovering
above another window or actor, ending up not focussing the window.
Fix this by always repicking on BUTTON_PRESS events. While this is not
necessary in the wayland session, button presses happen rarely compared
to motion events, so it's not a performance regression to do it in
Wayland sessions, too.
Fixes https://gitlab.gnome.org/GNOME/mutter/-/issues/1660
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1752>
ClutterText allows setting a custom PangoAttrList, and St uses that to
set the text style it's reading from CSS. One style St enforces using
this mechanism is the text color and setting the text color should
obviously not affect the size of the layout. ClutterText does queue a
relayout in that case though because it unconditionally queues a
relayout when updating the PangoAttrList.
We can avoid this relayout by reusing an optimization ClutterText has:
clutter_text_queue_redraw_or_relayout() will only queue a relayout if
the requested size of the layout changed.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1750>
With 734a185915 an optimization was
introduced to only pick on events which can actually cause the pointer
to move. In case of touch events, the first event (TOUCH_BEGIN) will
already move the touchpoint though, and we'll send our crossing
CLUTTER_ENTER event to the actor this TOUCH_BEGIN happened on.
So fix this embarrassing bug that caused touch input to break by also
picking to find an event-actor on TOUCH_BEGIN events.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1733>
Aside from ENTER/LEAVE, there are only two kinds of events that can move
the pointer, motion events and touch update events. Everything else
keeps the pointer at it's current position.
The reason we pick inside _clutter_process_event_details() is that we
want to set the event actor. Now if an event can't move the pointer, it
also can't change the event actor (well, it can subsequently by
triggering changes to the scenegraph, but that's handled elsewhere), so
there's no need to pick a new event actor when we get those events.
Instead, simply reuse the actor that's already associated with the
current input device as the event actor for non MOTION/TOUCH_UPDATE
events.
Events where a device or a touchpoint goes away (like DEVICE_REMOVED or
TOUCH_END/CANCEL) also affect picking, they don't need a repick, but
instead the actor associated with the device/touchpoint needs to be
unassociated. This is ensured by invoking remove_device_for_event() on
those events and will not be affected by this change.
This should improve performance while scrolling quite a bit, since
scroll events come in unthrottled and we now no longer do a repick on
each one of those.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1729>
We might have a stage view listener attached to the stage itself if the
actor didn't have a suitable frame clock when the actor was associated
with the timeline. We'd then listen to stage-views-changed signals on
the stage itself to be able to attach to a frame clock when one
appeared.
What went wrong is that if an actor that didn't have a frameclock was
associated with a timeline, but then destroyed, the timeline would
disassociate itself from the actor, but it'd still listen on the
stage-views-changed signal on the stage. This would be in itself
harmless, until the timeline itself is destroyed, as at this point, it
wouldn't clean up the stage-views-changed listener on the stage, as it's
assumed to only be valid when there is an actor attached.
Fix this issue by cleaning up the stage's stage-views-changed listener
when the actor is destroyed, as we wouldn't be able to make use of it by
then anyway.
Closes: https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/3323
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1719>
Before this commit, next presentation time could end up behind now_us or
ahead of now_us depending on how presentation times happened to be
aligned relative to integer multiples of refresh_interval_us. It's not
clear whether this was originally intended because even if it the next
presentation time ends up behind now_us, it is moved ahead by a while
loop down below in this function.
Even though this difference in behavior didn't really matter, it made
reasoning about the subsequent branches more complex. It would also
potentially introduce bugs if the logic was to be modified. So this
commit makes it so next presentation time is always ahead of now_us.
It also adds a comment with a graph detailing the computations, and
adjusts the variable names to drop unfortunate terminology mistakes.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1707>
Last presentation time is mainly used to make sure predicted
presentation time is aligned with display refreshes. Even if it went
back in time, there will be no issue as next presentation time takes
current time into account. Synthetic presentation time is not exactly
aligned with display refreshes, so using it would only result in
inconsistent animations.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1707>
When a transfer request is done to the MetaSelectionSourceRemote source,
it's translated to a SelectionTransfer signal, which the remote desktop
server is supposed to respond to with SelectionWrite.
A timeout (set to 15 seconds) is added to handle too long timeouts,
which cancels the transfer request.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1552>
Previously we were setting the FBO's viewport to be the same dimensions as
the stage itself for compatibility. This works for most cases, but not if
the actor is larger than the stage. In that case it could cause excessive
clipping if the actor's transformed screen position was negative, which
is seen in https://gitlab.gnome.org/GNOME/gnome-shell/issues/2087
Also if a small actor paints to its negative dimensions (like a box-shadow)
then we might be missing those pixels on the left or top, even though
they're inside the paint volume.
Now we set the viewport dimensions to match the area we're actually
rendering so the FBO contents are never over or under clipped.
Fixes: https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/3068
Although if you try using shadows larger than that (like in
gnome-shell#1090) then you will also need gnome-shell!1417.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1053>
We had been doing it backwards as far back as e3966882e8 which meant
that we were translating by `fbo_offset / resource_scale` stage units
instead of just `fbo_offset`.
Because `fbo_offset` is in stage units already, it's not scaled and so
needs to be applied after the unscaling from texels to stage units.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1053>
We've inherited, and still keep in place, code that reads ini files
at ~/.config/clutter-1.0/settings.ini and /etc/clutter-1.0/settings.ini
to tweak different aspects of Clutter.
Some of these should use GSettings instead, some others are exposed
nowadays differently for our purposes (e.g. envvars, looking glass, ...).
Overall seems like an unexpected entry point nowadays, so remove the
parsing of these .ini files altogether.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1693>
If we are about to replace `redraw_clip` with a clamped version of itself
then we may as well do the same for `queued_redraw_clip`, so you can see
more precisely what the damage of the current frame is.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1554>
Initially we generate the new part of fb_clip_region from the new part
of redraw_clip, scale it up and clamp. But the clamping means the new
part of fb_clip_region might now represent a slightly larger area than
the new part of redraw_clip, by one pixel.
In some rare cases where a foreground actor honours redraw_clip, but
the background actor does not (meaning it might fill all fb_clip_region),
you could find 1px rendering glitches in that gap as the background
actor paints there but the foreground actor does not.
To ensure such glitches can never happen we now regenerate the final
redraw_clip as a clamped superset of the final fb_clip_region. That's
the minimum area we must paint to ensure no gaps appear inside
fb_clip_region.
Although the fix here sounds like the intent of the old code, the old
code forgot to include the new part of fb_clip_region in the clamping
of the final redraw_clip. So the new part of redraw_clip was sometimes
kept too small for the new part of fb_clip_region.
We also move the code to the main path because technically it's also
needed when `has_buffer_age == FALSE`.
Fixes: https://gitlab.gnome.org/GNOME/mutter/-/issues/1500
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1554>
Before each frame is maybe redrawn, push any new cursor KMS state to the
pending update. It'll then either be posted during the next page flip,
or when the same frame finishes, in case nothing was redrawn.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1488>
This makes it possible to post a symbolic page flip and frame callback,
meant to be used by immediate symbolic page flip reply when emulating
cursor plane changes using legacy drmMode* functions.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1488>
Just as with the frame clock, add an API to communicate that a frame did
not result in a presentation. This can't happen yet but will when we
emulate atomic cursor plane changes using legacy drmMode API.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1488>
In constrast to notify_presented(), notify_ready() also returns the
state machine to the idle state, but without providing new frame
information, as no frame was actually presented.
This will happen for example with the simple KMS impl backend will do a
cursor movement, which will trigger a symbolic "page flip" reply in
order to emulate atomic KMS behavior. When this happen, we should just
try to reschedule again.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1488>
Don't mode set each CRTC in separate KMS updates, as reconfiguring one
CRTC might cause other CRTCs to be implicitly reset thus as well,
causing KMS return EBUSY if using atomic modesetting.
Prepare for this by compositing each CRTC first including adding steps
to the KMS update, but wait until all views has rendered at least once
before posting the initial update. After this each CRTC is posted
separately.
Using EGLStreams instead of normal page flipping seems to fail when
doing this though, so handle that the old way for the EGLStream case,
i.e. eglSwapBuffers() -> mode set with dumb buffer -> eglStream
"acquire" (resulting in page flip under the hood).
For this we also introduce a new error code so that we don't use client
buffers when doing mode sets, which could accidentally configure the
CRTC in a way that is incompatible with the primary plane buffers.
Do the same also when we're in power save mode, to only have one special
case path for this scenario in the regular swap-buffer path.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1488>
Instead of setting the frame result in the most generic layer, have the
backends do it themselves. This is necessary to communicate that a
swap-buffer call didn't really succeed completely to present the swapped
buffer, e.g. errors from KMS.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1488>
This argument is intended to be used by clutter to be able to
communicate with the onscreen backend, that happens to be the native
backend. It will be used to pass a ClutterFrame pointer, where the
result of page flips, mode sets etc can be communicated whenever it is
available.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1488>
ClutterFrame aims to carry information valid during dispatching a frame.
A frame may or may not include redrawing, but will always end with a
result.
A asynchronous page flip, for example, will result in a
CLUTTER_FRAME_RESULT_PENDING_PRESENTED, while a frame that only
dispatched events etc will result in CLUTTER_FRAME_RESULT_IDLE. Instead
of this being implicit, make the ClutterStageWindow implementation
handle this itself.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1488>
ClutterClickEvent currently doesn't check if button press and release
happen within the drag threshold, which can be surprising sometimes.
Only emit the "clicked" signal if the button press and release happen
within the area of drag threshold.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1667>
In clutter_timeline_set_actor() we currently always unset the
priv->frame_clock pointer of the old actor when a new actor gets set.
The priv->frame_clock pointer takes a reference on the ClutterFrameClock
though, so we leak ClutterFrameClocks here.
To fix it, simply rely on update_frame_clock(), which will call
set_frame_clock_internal() unconditionally to update the
priv->frame_clock pointer for us.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1632>
Some effects such as the BrightnessContrastEffect try to skip rendering
by returning early with a FALSE return value in pre_paint() in cases
where the effect would not change the rendering. This stopped working
when effects were ported to paint nodes.
In the case of OffscreenEffects, like BrightnessContrastEffect,
pre_paint() is responsible for setting up the offscreen buffer which is
then used in paint_node(). However if pre_paint() fails, this buffer is
not created and attempting to use it will result in several error
messages and broken rendering.
Instead of trying to call paint_node() of the effect if pre_paint()
failed, just draw the actor.
Fixes https://gitlab.gnome.org/GNOME/mutter/-/issues/1576
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1658>
When using alt-tab to switch between windows, on a key handler we
undo the compositor grab, which triggers a repick, which generates
crossing events, which are handled in place, and trigger these
reentrancy checks.
On one hand, we do intend these crossings to take effect in place,
rather than being queued (possibly after a number of already queued
events). On the other hand, we now outright discourage generating
events from random places (and hope to make it just not possible,
eventually) thus we can afford not to protect against reentrancy
caused by API misuse.
So just drop these checks, and let these crossing events be
properly handled.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1657>
This is the very same code than meta_wayland_pointer_repick(),
made part of Clutter, so triggering repicks on the same pointer
coordinates is made easy.
The intention is to remove meta_wayland_pointer_repick() in favor
of this call.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1654>
Updating the state before emitting the CLUTTER_LEAVE event allows its
handlers to query the pointer actor, and avoid getting the same actor
again. Conceptually, this makes picking more "atomic", and the events a
notification of the change.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1654>
Turns out GObject implicitly notifies all properties by default as soon
as a property setter is called, no matter if the property actually
changed or not. One can opt-out of this behavior by setting the
G_PARAM_EXPLICIT_NOTIFY flag.
So since almost all our properties get notified explicitely (well,
except ClutterActors deprecated show-on-set-parent property), set this
flag for all properties of ClutterActor and ClutterStage now. This
significantly reduces the number of notify:: signals emitted on
ClutterActors, because in gnome-shell javascript we usually set GObject
properties directly, not by going through the extra setter method.
More cleanups can be done in the future, since this flag is suitable for
almost every property in Clutter and even Mutter.
This fixes a crash where we'd hit a newly introduced assertion in
on_device_actor_reactive_changed() of ClutterStage because
notify::reactive got emitted multiple times.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1651>
Due to a few reasons currently the updating of input devices after stage
relayouts isn't working right now. Since we now have a list of pointer
devices in ClutterStage, we can simply use that list and can avoid
asking the input thread. Also we no longer need to check whether the
devices are pointer devices, since our list only consists of pointer
devices.
So switch to ClutterStages private list of pointer devices, which also
includes the core pointer (as opposed to the list returned by
clutter_seat_peek_devices()). This fixes picking after relayouts.
Note that this doesn't catch every possible change that might need a
repick, actors might also need a repick after transformation changes or
in case their custom clip has been changed.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1634>
As planned and prepared with the last commits, let ClutterStage take
care of tracking input devices and their respective actors. This means
we now can remove the old infrastructure for this from
ClutterInputDevice.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1633>
We're moving keeping track of input devices and their associated actors
out of ClutterInputDevice, this commit basically adds replacements for
clutter_input_device_update() and clutter_input_device_set_actor() to
clutter-main and shuffles the internals of those functions around a bit
for clarity.
clutter_stage_update_device() is made available in clutter-mutter.h
because we need to update the actor of input devices not only from
ClutterStage (when repicking after relayout), but also from
MetaWaylandPointer (inside meta_wayland_pointer_repick()).
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1633>
With the introduction of the input thread, we want to avoid modifying
ClutterInputDevices from the main thread, since they're owned and
updated by the thread.
There's one part of ClutterInputDevice that's still modified from the
main thread though, that is device-actors of pointer devices, and we're
going to move that state-tracking into ClutterStage instead.
So start that by adding the infrastructure to ClutterStage to keep track
of those things. It consists of two hashtables which associate devices
and touch sequences with actors, those hashtables get updated using
clutter_stage_update_device_entry() and
clutter_stage_remove_device_entry(), they can be queried by calling
clutter_stage_get_device_actor(), which will replace
clutter_input_device_get_actor().
clutter_stage_get_device_coords() is added and made available in
clutter-mutter.h because we need to get the coordinates when repicking
in meta_wayland_pointer_repick().
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1633>
The n_steps variable corresponds to the number of *pairs* of
texture lookups that the blur shader does. For example, when
n_steps = 1, the for-loop reads 1 pixel before and 1 pixel
after the current one.
Our blur shader is heavily inspired in WebRender's blur shader,
the biggest difference being that we calculate the gaussian
samples in the fragment shader itself, and not in the vertex
shader. (This could be an improvement in performance for the
future though!)
WebRender's blur shader calculates n_steps differently than what
we currently do, though. It calculates n_step in such a way that
at least 2 steps are performed for evey non-zero sigma value.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1646>
The shader already operates on floating point sigma, and
there's just no reason for us to force it to be an unsigned
integer. It's still important that sigma must be positive
though.
Make sigma a float, and make sure it's a positive number.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1646>
Yet another way to reduce the instruction count of the fragment
shader. Passing a pair of floats once is virtually free, compared
to computing horizontal and vertical on each fragment run.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1646>
New entries indirectly added to `pending_queue_redraw` during the loop
would make our iterator invalid and cause `g_hash_table_iter_next` to
fail without having visited all elements. That was seen as assertion
failures but also likely resulted in incomplete paint clips.
Now we steal the iterator's entry before such corruption can happen,
free it manually, and reset the iterator to the beginning on every
iteration. This is actually safe and efficient because we're removing each
entry we visit. So no time is wasted in resuming from the (new) beginning
of the hash table.
Fixes: https://gitlab.gnome.org/GNOME/mutter/-/issues/1557
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1615>
Add a new pair of APIs corresponding to CoglFramebuffer's draw_rectangles()
and draw_textured_rectangles(). They're generally more performance compared
to adding multiple single-rect operations. These variants are heavily used
by GNOME Shell's CSS implementation.
The op array is built to match cogl_framebuffer_draw_textured_rectangles()
always, which means it's a series of 8 floats composed (x1 y1 x2 y2) and
(s1 t1 s2 t2). To avoid adding new struct fields to ClutterPaintOperation,
which is a performance and memory sensitive structure, simply divide the
array length by 8 (which is guaranteed to be correct).
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1637>
Setting an ortho projection gives us pretty much the same result as
manually calculating the projection matrix. The ortho projection is
actually more "complete" than the custom projection we've been using,
as it also considers z-near and z-far, but in practice the generated
pixels are exactly equal.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1642>
In the purely paint node based rendering future, ClutterEffects
simply add more paint nodes to the tree when painting the actor.
This is the leap to achieve that future.
Add paint nodes to pre_paint, paint, and post_paint, and move the
ClutterEffectNode creation to _clutter_effect_paint().
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1355>
The paint node tree that ClutterOffscreenEffect generates is
simple:
Root
|------------+
| |
Layer Pipeline
|
Actor
Right now, both pre-paint and ClutterLayerNode push the offscreen
to the framebuffer stack. That's harmless, and will go away soon
anyway.
The actor node is created and added in a separate function because
it'll be reused by the next commit.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1355>
Add a new ClutterPaintNode parameter to the paint_target() vfunc.
For now, create a temporary ClutterEffectNode that is passed to
paint_target() and immediately painted; next commits will move
this to upper layers.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1355>
The blur pipeline is still cached on ClutterBlurEffect, and we
simply update the uniforms when asked to create the pipeline.
Now that ClutterOffscreenEffect will use the blur pipeline, it
doesn't need to override the paint_target() vfunc anymore.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1355>
The most annoying aspect of ClutterOffscreenEffect right now, and
the reason for all its subclasses to override pre-paint, is that
the pipeline creation isn't under subclasses' control. That means
all subclasses must ask ClutterOffscreenEffect to run pre-paint
and create the pipeline, then they all create their own pipelines
to paint.
To reduce this complexity, add a new create_pipeline() vfunc to
ClutterOffscreenEffect. Next commits will port effects to use this
new vfunc.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1355>
ClutterLayerNode currently skips pushing the offscreen framebuffer when
no operations are set. This was added at the time because pushing and
popping was a synchronization point in Cogl, slow enough to force the
layer node to have this protective measure. Nowadays, pushing and
popping on the paint context is free.
Make ClutterLayerNode always push and pop in pre and post paint.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1355>
ClutterBlurNode is a paint node based on ClutterLayerNode
that draws all children in an offscreen framebuffer, blurs
this framebuffer, and finally paints the blurred contents
according the the paint operations added.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1627>