We need this hint whether direct scanout succeeds or fails because it's
the mechanism by which we will tell the clock to enforce double buffering,
thus making direct scanout possible on future frames. Triple buffering
will be disabled until such time that direct scanout is not being attempted.
Because the buffer queue may grow by an extra frame in triple buffering,
we need measurements exceeding one frame to indicate when and by how much
the scaling is necessary.
Chronologically they already overlap in time as presentation may
complete in the middle of the dispatch function, otherwise they are
contiguous in time. And most switch statements treated the two states
the same already so they're easy to merge into a single `DISPATCHED`
state.
Having fewer states now will make life easier when we add more states
later.
Error diffusion was introduced in 0555a5bbc1 for Nvidia where last
presentation time is always unknown (zero). Dispatch times would drift
apart always being a fraction of a frame late, and accumulated to cause
periodic frame skips. So error diffusion corrected that precisely and
avoided the skips.
That works great with double buffering but less great with triple
buffering. It's certainly still needed with triple buffering but
correcting for a lateness of many milliseconds isn't a good idea. That's
because a dispatch being that late is not due to main loop jitter but due
to Nvidia's swap buffers blocking when the queue is full. So scheduling
the next frame even earlier using last_dispatch_lateness_us would just
perpetuate the problem of swap buffers blocking for too long.
So now we lower the threshold of when error diffusion gets disabled. It's
still high enough to fix the original smoothness problem it was for, but
now low enough to detect Nvidia's occasionally blocking swaps and backs
off in that case.
Since the average duration of a blocking swap is half a frame interval
and we want to distinguish between that and sub-millisecond jitter, the
logical threshold is halfway again: refresh_interval_us/4.
While it was correct for double buffering, the test was wrong for
triple buffering and would lead to accidentally staying in triple
buffering for too long.
Fixes: 8f27ebf87e
It's analogous to discard_pending_page_flips but represents swaps that
might become flips after the next frame notification callbacks, thanks
to triple buffering. Since the views are being rebuilt and their onscreens
are about to be destroyed, turning those swaps into more flips/posts would
just lead to unexpected behaviour (like trying to flip on a half-destroyed
inactive CRTC).
Otherwise we could get:
meta_kms_prepare_shutdown ->
flush_callbacks ->
... ->
try_post_latest_swap ->
post and queue more callbacks
So later in shutdown those callbacks would trigger an assertion failure
in meta_kms_impl_device_atomic_finalize:
g_hash_table_size (impl_device_atomic->page_flip_datas) == 0
And when the number of pending posts decreases we know it's safe to submit
a new one. Since KMS generally only supports one outstanding post right now,
"decreases" means equal to zero.
This will allow us to keep track of up to two buffers that have been
swapped but not yet scanning out, for triple buffering.
This commit replaces mutter!1968.
In the unlikely event that swap_buffers_with_damage drops the previous swap
it was forgetting to notify about the discarded frame. That could lead to
frame clock freezes.
All paths out of `meta_onscreen_native_swap_buffers_with_damage` from
here onward would set the same `CLUTTER_FRAME_RESULT_PENDING_PRESENTED`
(or terminate with `g_assert_not_reached`).
Even failed posts set this result because they will do a
`meta_onscreen_native_notify_frame_complete` in
`page_flip_feedback_discarded`.
Because it soon won't be the maximum. But we do want to verify that the
frame info queue is not empty, to avoid NULL dereferencing and catch logic
errors.
This is a case that triple buffering will encounter. We don't want it
to queue the same onscreen multiple times because that would represent
multiple flips occurring simultaneously.
It's a linear search but the list length is typically only 1 or 2 so
no need for anything fancier yet.
Simply to make it clear that the renamed function is specific to a
particular X11 initialization mode (mandatory Xwayland), put that in the
name, so that it's easier to understand when this function is relevant.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3329>
This means that for X11 sessions we'll do it before any windows are
mapped, and before any plugin implementation is started. Doing it before
a plugin is started is important, because things that the plugin does
during startup can have consequences on how compositing on Xorg works.
For the Xwayland case, we'll do it relatively in the setup phase. It
appears to have been harmless to do it later in the post-opened signal,
but there is no harm in doing it as one of the earlier steps.
Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/3089
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3329>
This gives greater control to the callers on the place where a grab is being
activated, this may make a difference in the handling of crossing events
triggered through it, e.g. by having callers rely on having already obtained
a ClutterGrab prior to handling the resulting effects.
The "input only" grab has also been turned inactive by default, in order to
to have the ClutterGrab pointer available for checks at the MetaWaylandEventHandler
focus changing methods triggered through grab activation.
(cherry-picked from commit 8e5f3a1f83)
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3874>
When cloning an actor we were applying a global scale to it, based on
the size of the clone itself and of the cloned actor.
This implied that the transformed size of the clone was not the one that
was set, but it was taking taking in account the actor scaling too.
So in practice we were scaling it twice.
While this had no visual implications it indeed was causing troubles
when a ClutterClone was reactive because in such case only the scaled
area of the scaled clone was considered reactive.
Assume you had an actor of 100x100 pixels, scaling it to a clone of
50x50 pixels:
- The scale applied to the clone was 0.5
- The transformed size of the clone was: 25x25 pixels
- The clone was reactive only in that sub-area
To avoid this, never touch the clone transformation matrix, but only
transform it at paint time.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2959>
(cherry picked from commit 44c0c311ba)
The two dialog creation virtual functions returned by these functions have to
be unreferenced by the caller (and are actually unreferenced in other places in
the code).
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3790>
(cherry picked from commit 4134d12789)
If the titlebar of a window has been moved above the screen by a user
via an unconstrained move, then any constrained user resize following
this move will cause the window to jump below the top of the screen or
cause other glitchy behavior.
This commit removes the constraint that the titlebar of a window must be
below the top of the screen for any resize that is both (1) triggered by
a user and (2) is a resize that affects only the left, right, or bottom
edges of the window. This allows users to move a window partially above
the screen and then resize the window to be wider or resize the bottom
edge of the window to make it taller or shorter.
Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/1206
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3764>
(cherry picked from commit 5ba364a947)
Right now the unmapped signal doesn't always fire which means we didn't
see a surface that's being unmapped in these code paths before. In
particular the resource, window and role can be gone. Handle those
cases.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3783>
(cherry picked from commit 3e7b1d9cbd)
When mutter creates a dma-buf buffer for screencasting, the buffers
stride will, among other attributes, also be defined.
However, mutter currently only sets the buffer stride, when actually
recording a frame, but not when adding it.
This behaviour disallows screencast consumers (clients) to already
import the respective buffer (i.e. for Vulkan creating a VkImage for the
dma-buf image), as the stride is not yet communicated to the client.
Since the stride won't change after adding the respective buffer,
directly set the buffer stride, when adding the PipeWire buffer. This
allows screencast consumers (clients) to do optimizations in their
encoding paths.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3827>
(cherry picked from commit 0dd4080509)