1
0
Fork 0

Compare commits

...

40 commits

Author SHA1 Message Date
Gert-dev
2cdcc4b9cc
onscreen/native: Use EGLSyncs instead of cogl_framebuffer_finish
cogl_framebuffer_finish can result in a CPU-side stall because it waits for
the primary GPU to flush and execute all commands that were queued before
that. By using a GPU-side EGLSync we can let the primary GPU inform us when
it is done with the queued commands instead. We then create another EGLSync
on the secondary GPU using the same fd so the primary GPU effectively
signals the secondary GPU when it is done rendering, causing the latter
to wait for the former before copying part of the frames it needs for
monitors attached to it directly.

This solves the corruption that cogl_framebuffer_finish also solved, but
without needing a CPU-side stall.

Signed-off-by: Mingi Sung <sungmg@saltyming.net>
2024-09-15 13:59:55 +09:00
Michel Dänzer
1444e82cd8
onscreen/native: Set latest cogl sync_fd on KMS update
See previous commit log on the effects of this.

This means the deadline evasion needs to be added in both cases in
clutter_frame_clock_notify_presented.

v2:
* Use meta_kms_update_set_sync_fd. (Jonas Ådahl)

Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3958>
Signed-off-by: Mingi Sung <sungmg@saltyming.net>
2024-09-15 13:59:32 +09:00
Michel Dänzer
a9a221933e
kms/impl-device: Handle sync_fd in meta_kms_impl_device_handle_update
If the KMS thread is using the deadline timer, and a valid sync_file
descriptor is passed in:

1. The update is deferred, and the deadline timer is left armed, until
   the sync_fd signals (becomes readable).
2. Implicit synchronization is disabled for the KMS update.

This means cursor updates should no longer miss a display refresh
cycle due to mutter's compositing GPU work finishing too late.

v2:
* Use g_autoptr for GSource in meta_kms_impl_device_handle_update.
  (Sebastian Wick)
v3:
* Use meta_kms_update_get_sync_fd, don't track sync_fd in
  CrtcFrame::submitted_update. (Jonas Ådahl)
v4:
* Clean up CrtcFrame::submitted_update members in crtc_frame_free.
v5:
* Coding style cleanup in meta_kms_impl_device_handle_update.
  (Jonas Ådahl)

Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3958>
Signed-off-by: Mingi Sung <sungmg@saltyming.net>
2024-09-15 13:59:32 +09:00
Michel Dänzer
168839e317
kms/update: Add meta_kms_update_get/set_sync_fd
v2:
* Use g_steal_fd in meta_kms_update_merge_from. (Jonas Ådahl)

Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3958>
Signed-off-by: Mingi Sung <sungmg@saltyming.net>
2024-09-15 13:59:32 +09:00
Michel Dänzer
011b6f7c96
kms/plane: Rename META_KMS_ASSIGN_PLANE_FLAG_DIRECT_SCANOUT
To META_KMS_ASSIGN_PLANE_FLAG_DISABLE_IMPLICIT_SYNC. This describes the
effect of the flag, instead of the circumstances it's currently used
for.

Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3958>
Signed-off-by: Mingi Sung <sungmg@saltyming.net>
2024-09-15 13:59:32 +09:00
Michel Dänzer
a364e785f9
kms/crtc: Conditionally return 0 in meta_kms_crtc_get_deadline_evasion
If both crtc->shortterm_max_dispatch_duration_us and
crtc->deadline_evasion_us are 0, i.e. we're not using the deadline
timer.

v2:
* Fix coding style. (Jonas Ådahl)

Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3958>
Signed-off-by: Mingi Sung <sungmg@saltyming.net>
2024-09-15 13:59:31 +09:00
Michel Dänzer
e3bbee2630
kms/impl-device: Track dispatch duration in crtc_frame_deadline_dispatch
And take it into account in meta_kms_crtc_get_deadline_evasion.

This uses the same fundamental approach as clutter frame clock scheduling:

Measure the deadline timer dispatch duration, keep track of the longest
duration, and set the timer to fire such that the longest measured
dispatch duration would result in it completing shortly before start of
vblank.

Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/3612

v2:
* Move DEADLINE_EVASION_CONSTANT_US addition from
  meta_kms_crtc_determine_deadline to meta_kms_crtc_get_deadline_evasion.
* Calculate how long before start of vblank dispatch completed for
  debug output in crtc_frame_deadline_dispatch.
* Shorten over-long lines in crtc_frame_deadline_dispatch.

Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3934>
Signed-off-by: Mingi Sung <sungmg@saltyming.net>
(cherry picked from commit 88e7f353)
2024-09-15 13:58:58 +09:00
Michel Dänzer
b5dffcdc67
kms/impl-device: Use KMS_DEADLINE in crtc_page_flip_feedback_flipped
It's useful for this to match the debug topic in
crtc_frame_deadline_dispatch.

Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3934>
Signed-off-by: Mingi Sung <sungmg@saltyming.net>
2024-09-15 13:58:58 +09:00
Daniel van Vugt
0411de33b5
kms/impl-device: Add debug logging for deadline dispatch lateness
And also "completion" time to measure when the commit returned.

This is structured so as to measure all timestamps first before logging
anything. That way our results shouldn't be (don't seem to be) affected
by the logging itself.

Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3265>
Signed-off-by: Mingi Sung <sungmg@saltyming.net>
2024-09-15 13:58:58 +09:00
Daniel van Vugt
739ad5590b
kms/impl-device: Remember the expected deadline dispatch time
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3265>
Signed-off-by: Mingi Sung <sungmg@saltyming.net>
2024-09-15 13:58:58 +09:00
Daniel van Vugt
7f88fd419b
Add debug topic "kms-deadline"
Which will allow us to report on deadline timings without influencing
the CPU clock like the busy "kms" topic does.

Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3265>
Signed-off-by: Mingi Sung <sungmg@saltyming.net>
2024-09-15 13:58:58 +09:00
Jonas Ådahl
c9bb8a16a2
kms: Don't disarm deadline timer when compositing
If we finish compositing in time, the composited result will be
submitted prior to the deadline timer is triggered, and we'll be fine,
and if not, at least the cursor updates will be smooth, which makes it
appear smoother than not.

There is a risk that this can negatively impact composited updates when
moving the cursor, so make it possible to toggle a paint-debug flag for
now until this has been more tested.

This also mean we need to disarm the deadline timer after handling
update, as there might be a scheduled cursor update pending, but we
already handled it, so disarm the timer.

Here is an illustration of the difference.

In the following scenario, with disarming, the composited frame E, and
the cursor movement C gets presented. With this branch, only the cursor
movement C gets presented.
```
 * A: beginning of composited frame
 * B: begin notification reaches KMS thread
 * C: cursor moved
 * D: calculated deadline dispatch time (disabled with the branch)
 * E: KMS update posted
 * F: KMS update reaches KMS thread
 * G: actual deadline (and with branch and gets committed)
Compositor thread: --------A---------------E---------
                            \               \
                             \               \
KMS thread:        -----------B------C----D---F-G----
```

In the following scenario, by not disarming, the cursor update C will be
presented, and the would-be-delayed composited frame E would be delayed
anyway, i.e. fixing cursor stutter.
```
 * A: beginning of composited frame
 * B: begin notification reaches KMS thread
 * C: cursor moved
 * D: calculated deadline dispatch time (and with branch will be dispatched)
 * E: KMS update posted
 * F: actual deadline
 * G: KMS update reaches KMS thread (and with branch gets postponed)
Compositor thread: --------A---------------E---------
                            \               \
                             \               \
KMS thread:        -----------B------C----D-F-G------
```

Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3184>
Signed-off-by: Mingi Sung <sungmg@saltyming.net>
2024-09-15 13:58:58 +09:00
Jonas Ådahl
efadfc4a94
renderer-view/native: Update deadline evasion each frame
The deadline evasion depends on debug flags, but they are not trackable,
so update the deadline evasion each time we schedule an update.

Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3184>
Signed-off-by: Mingi Sung <sungmg@saltyming.net>
(cherry picked from commit 6ec1312384)
2024-09-15 13:58:57 +09:00
Jonas Ådahl
96ca767e22
clutter/frame-clock: Take deadline evasion into account
This is meant to be the amount of time before a CRTC deadline we're
usually dispatching at. It's not yet set by anything however.

Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3184>
Signed-off-by: Mingi Sung <sungmg@saltyming.net>
2024-09-15 13:58:57 +09:00
Daniel van Vugt
9e07b3be72
onscreen/native: Return GErrors from secondary GPU updates
And return early from `swap_buffers_with_damage` if the error would have
led to flipping a NULL buffer.

This is also the perfect time to remove the `egl_context_changed` parameter
and move `_cogl_winsys_egl_ensure_current` closer to the code that actually
needs it.

Related: https://bugs.launchpad.net/bugs/2069565
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3817>
Signed-off-by: Mingi Sung <sungmg@saltyming.net>
2024-09-15 13:58:34 +09:00
Daniel van Vugt
99bbd37b02
onscreen/native: Set frame result to IDLE on swap failure
So that swap failure messages are not also followed by:

meta_stage_native_redraw_view: runtime check failed: (!META_IS_CRTC_KMS (crtc))

Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3817>
Signed-off-by: Mingi Sung <sungmg@saltyming.net>
2024-09-15 13:58:34 +09:00
Daniel van Vugt
608f6d1223
onscreen/native: Unify the failure paths of swap_buffers_with_damage
They're both the same and a third one will be added soon.

Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3817>
Signed-off-by: Mingi Sung <sungmg@saltyming.net>
2024-09-15 13:58:34 +09:00
Daniel van Vugt
3214e92918
onscreen/native: Squash adjacent switch statements
Because we can. And it's now clearer that `buffer` is only used in
`META_RENDERER_NATIVE_MODE_GBM`.

Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3891>
Signed-off-by: Mingi Sung <sungmg@saltyming.net>
2024-09-15 13:58:34 +09:00
Daniel van Vugt
bc74aadcc2
onscreen/native: Move next_frame storage to later in the function
It won't be used until later when we flip, and in fact assigning
it early could have led to its own assertion failing on the next frame
in the unlikely event that we return with "Failed to ensure KMS FB ID...

Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3891>
Signed-off-by: Mingi Sung <sungmg@saltyming.net>
2024-09-15 13:58:33 +09:00
Daniel van Vugt
1815af679f
onscreen/native: Return the framebuffer by result, not parameters
`update_secondary_gpu_state_post_swap_buffers` decides what our front
buffer object will be. There is only one answer. So return it as the
function result instead of making the caller figure it out.

Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3830>
Signed-off-by: Mingi Sung <sungmg@saltyming.net>
2024-09-15 13:58:33 +09:00
Daniel van Vugt
e53f0e1463
onscreen/native: Remove frame parameter from flip_crtc
It's always equal to `onscreen_native->next_frame` and we can't eliminate
that copy so easily. Removing the parameter removes all ambiguity about
where the next frame will come from.

Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3829>
Signed-off-by: Mingi Sung <sungmg@saltyming.net>
2024-09-15 13:58:33 +09:00
Jonas Ådahl
f45d4c0c7f
onscreen/native: Track next and presenting buffers via ClutterFrame
Let the ClutterFrame (or rather MetaFrameNative) own both the scanout
object and the framebuffer object, and let the frame itself live for as
long as it's needed. This allows to place fields that is related to a
single frame together, aiming to help reasoning about the lifetime of
the fields that were previously directly stored in MetaOnscreenNative.

Also take the opportunity to rename "current" to "presenting", to make
it clearer that frame's buffer is what is currently presenting to the
user.

Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3799>
Signed-off-by: Mingi Sung <sungmg@saltyming.net>
2024-09-15 13:58:29 +09:00
Florian Müllner
f585134c11
Bump version to 46.5
Update NEWS.
2024-09-14 21:51:41 +02:00
José Expósito
0fab816982 onscreen/native: Return the correct number of EGL modifiers
g_array_sized_new() creates a new GArray with a preallocated size, but,
after creation, the array length is still zero [1].

Store the modifiers in a EGLuint64KHR array and use g_array_new_take()
to create a new GArray with the correct size.

Because no modifiers were returned, gbm_surface_create() was used
instead gbm_surface_create_with_modifiers() on multi-GPU setups.

[1] https://docs.gtk.org/glib/type_func.Array.sized_new.html

Fixes: aec85281ba ("native/renderer: Retrieve the right modifiers set for each GPU")
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3998>
(cherry picked from commit cf5508bdeb)
2024-09-14 21:27:57 +02:00
Peter Hutterer
4b622fbda8 wayland: Use the tool's current_tablet device instead of caching it
The tablet tool is initialized with a device but if that device is later
removed we never update tool->device. This eventually causes a crash
when we're passing that device into
meta_wayland_input_invalidate_focus().

The tool keeps track of the current tablet anyway so instead of caching
this pointer in the tool, use the current tablet's device.

Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/3642
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3959>
(cherry picked from commit e4004a7c4f)
2024-09-14 21:26:54 +02:00
Jonas Ådahl
3715012588 kms/impl-device: Disarm deadline timer when disabling
Otherwise we'll end up firing when not expected to, e.g. when the screen
is locked and monitors are all turned off.

Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/3629
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3982>
(cherry picked from commit 66a45809fa)
2024-09-14 21:23:56 +02:00
Jonas Ådahl
a8cc1739d3 kms/impl-device: Put deadline timer disarming in a helper
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3982>
(cherry picked from commit 1d87bcaab2)
2024-09-14 21:23:50 +02:00
Christian Hergert
ba06ba24ac compositor: Mark window drag actor invisible
If the window_drag->handle ClutterActor:visible property is FALSE,
then we avoid a full-framebuffer damage on the monitor when beginning
and ending a drag.

Testing with `mutter --wayland --display-server` still shows a full-
framebuffer damage on the first drag, but that appears to be unrelated
to this. Subsequent full-framebuffer damage which would occur on
drag-begin and drag-end have been elided.

Related: #3630
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3975>
(cherry picked from commit 030270ba3b)
2024-09-14 21:21:59 +02:00
Jonas Ådahl
abd2c95864 kms: Inhibit real time scheduling until initial mode set
We're already inhibiting real time scheduling when reading new KMS state
after hot plugs, as well as when during mode sets, due to the kernel not
being able to reliably handle these within the 250 ms limit. However, we
didn't do this during initial probing, which meant that occasionally
we'd run into these kind of issues during startup.

Handle this by always inhibiting real time scheduling up front, and
don't uninhibit until all initially discovered device have finished
processing their initial mode set.

Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/3628
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3960>
(cherry picked from commit d2be0b6950)
2024-09-14 21:20:59 +02:00
Peter Hutterer
e8d7640316 wayland: Set current tool surface to NULL on prox-out
If an application is maximised, clutter_stage_pick_and_update_device()
goes into the
        if ((flags & CLUTTER_DEVICE_UPDATE_IGNORE_CACHE) == 0)
condition and returns the current actor for the device. This means no
CLUTTER_LEAVE/ENTER events are generated and in turn means the focus is
never invalidated and updated.

This leads to tool->focus_surface always being NULL and all events are
discarded.

Notably, tool->current is set to the right surface but
that one never changes either so meta_wayland_tablet_tool_set_current_surface()
exits early too because surface == tool->current and we thus never call
meta_wayland_input_invalidate_focus().

Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/3616
Fixes: fb8ac5dff7 ("wayland: Track current tablet tool focus surface")
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3956>
(cherry picked from commit d866590b78)
2024-09-14 21:20:46 +02:00
Peter Hutterer
3a580e4bce wayland: Propagate a tablet's DEVICE_REMOVED to trigger the signals
Clutter's "device-removed" signal is sent in
clutter_seat_handle_event_post(). Our tablet code is set up to handle
that signal to then notify wayland clients of removed tablet devices.

However, returning CLUTTER_EVENT_STOP for a DEVICE_REMOVED event means
we never get to the point where we send out the signals and thus never
remove the tablets.

Fixes: a37fd34bbb ("wayland: Make MetaWaylandSeat in charge of its own tablet seat")

Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/3615
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3955>
(cherry picked from commit c03e64ef1d)
2024-09-14 21:20:16 +02:00
Carlos Garnacho
04b2b87959 wayland: Register touchpoint info on CLUTTER_ENTER
The first event happening for a new touch will be the CLUTTER_ENTER
event generated when picking it. Use this event for registration of
the touch info, so that MetaWaylandEventHandler.get_focus_surface may
get the right focus surface for the device/sequence on the first try.

Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3889>
(cherry picked from commit 2e82a2049f)
2024-09-14 21:17:04 +02:00
Carlos Garnacho
1c57f38daf wayland: Only cancel touch when a new event handler takes over
And notably, don't cancel touch when an event handler is being
removed. Touch events are largely unaffected by most Wayland
grabs (pointer constraints, popups), so we might be cancelling
input too early if one of these wayland grabs was effective when
touch interaction began, but stopped sometime between touch updates.

Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3889>
(cherry picked from commit 77b21ef8dc)
2024-09-14 21:16:56 +02:00
Carlos Garnacho
ac089a1710 wayland: Ignore touch events in seat default focus handler
Touch events are implicitly grabbed to the surface they began in,
and are not affected by the focus handler. However these events
will appear to come from the core pointer device, which might lead
to the wrong device being updated.

Ignore events with a sequence, since the default focus handler
does not intend to do anything with them.

Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3889>
(cherry picked from commit 08c903a359)
2024-09-14 21:16:53 +02:00
Bilal Elmoussaoui
fc1532efc4 Remove unused variables
Detected through codeql

Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3837>
(cherry picked from commit 6e1c761330)
2024-09-14 21:16:38 +02:00
Daniel van Vugt
34ee35a53a kms/impl-device: Add/remove deadline timer as required
On a hybrid machine with i915 primary and nvidia-drm (470) secondary,
`meta_render_device_egl_stream_initable_init` calls
`meta_kms_inhibit_kernel_thread` to change from the default 'kernel'
thread type to 'user'. And soon after that it would
`meta_render_device_egl_stream_finalize` because I'm not actually
using that GPU, and calls `meta_kms_uninhibit_kernel_thread`.

So during startup Mutter would default to a realtime kernel thread,
switch to a user thread (which doesn't support realtime), and then
switch back to a realtime kernel thread.

In the middle of all that, while the thread type was 'user' and
realtime disabled, something was invoking `ensure_crtc_frame` which
created a `CrtcFrame` without a deadline timer. Soon after that the
thread type changed back to 'kernel' with deadline timers expected, but
our existing `CrtcFrame` has no deadline timer associated with it. And
so it would never fire, causing the cursor to freeze whenever the primary
plane isn't changing. And the problem was permanent, not just the first
frame because each `CrtcFrame` gets repeatedly reused (maybe shouldn't
be called a "Frame"?).

Now we adapt to switching between kernel and user thread types by adding
and removing the deadline timer as required.

Close: https://gitlab.gnome.org/GNOME/mutter/-/issues/3464
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3950>
(cherry picked from commit c436e7cb17)
2024-09-14 21:13:11 +02:00
Daniel van Vugt
a6737a46c7 kms/update: Don't count trivial custom page flips as empty updates
This includes most frames when using EGL_DEVICE.

While it would be nice to skip all update processing in this case,
we can't go quite that far because EGL_DEVICE is still waiting on
page flip callbacks.

Fixes: 27ed069766 ("kms/impl-device: Add deadline based KMS commit scheduling")
Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/3196
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3939>
(cherry picked from commit 4c91616ff2)
2024-09-14 21:11:28 +02:00
Daniel van Vugt
7786482bd5 onscreen/native: Associate the kms_crtc with EGL_DEVICE updates
Although we track updates for EGL_DEVICE, they are often empty because
the primary plane has a custom page flip method. That means there's
no CRTC latched yet, but we do know exactly which CRTC is associated
with the flip. Set it so the update can still be processed.

Fixes: 27ed069766 ("kms/impl-device: Add deadline based KMS commit scheduling")
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3939>
(cherry picked from commit cfb2100d40)
2024-09-14 21:11:22 +02:00
Carlos Garnacho
3bb02538b9 wayland: Bypass popup grab focus if other handlers are in effect
If other handlers (e.g. DnD) are on top of the popup grab focus, we
may want it to move outside same-client surfaces as the popup grab
specifies.

Check that it is the current handler before making same-client checks,
so that these handlers on top have an opportunity to find other
surfaces, e.g. during DnD from a popup.

Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/1681
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3937>
(cherry picked from commit c179bebb70)
2024-09-14 21:09:59 +02:00
Carlos Garnacho
99808a3365 wayland: Track pressed mouse buttons for popup grabs through modifiers
Move away from tracking presses/releases directly, since there might be
other event handlers on top that might prevent the popup event handler
to fully track all events. The replacement is using event state modifiers,
which will use information set from the backend, and is enough to determine
there's no more pressed buttons without tracking prior event history.

This makes the popup event handler able to interact with other event
handlers that might be on top, and consume button release events for
themselves (e.g. DnD), no longer resulting in a stuck popup grab.

Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3937>
(cherry picked from commit 22362378ea)
2024-09-14 21:09:47 +02:00
57 changed files with 992 additions and 297 deletions

24
NEWS
View file

@ -1,3 +1,27 @@
46.5
====
* Fix drag and drop between X11 and wayland clients [Carlos; !3821]
* Fix drag and drop from grabbing popups [Carlos; !3937]
* Fix EGLDevice support [Daniel; !3939]
* Fix frozen cursor on some hybrid machines [Daniel; !3950]
* Fix touch window dragging with pointer lock enabled [Carlos; !3889]
* Fix propagating tablet device removals to clients [Peter; !3955]
* Fix tablet input in maximized windows [Peter; !3956]
* Reduce damage on window movement [Christian; !3975]
* Fix frozen cursor after suspend [Jonas; !3982]
* Fix using modifiers on multi-GPU setups [José; !3998]
* Fixed crashes [Marco, Jonas; !3978, !3960]
* Misc. bug fixes and cleanups [Daniel, Michel, Sebastian, Bilal, Peter;
#3597, !3946, !3903, !3914, !3954, !3912, !3837, !3959]
Contributors:
Jonas Ådahl, Michel Dänzer, Bilal Elmoussaoui, José Expósito, Carlos Garnacho,
Christian Hergert, Peter Hutterer, Marco Trevisan (Treviño), Daniel van Vugt,
Sebastian Wick
Translators:
Daniel Șerbănescu [ro], Vasil Pupkin [be]
46.4 46.4
==== ====
* Fix nested popovers on wayland [Carlos; !3874] * Fix nested popovers on wayland [Carlos; !3874]

View file

@ -137,6 +137,8 @@ struct _ClutterFrameClock
int64_t last_dispatch_interval_us; int64_t last_dispatch_interval_us;
int64_t deadline_evasion_us;
char *output_name; char *output_name;
}; };
@ -389,7 +391,8 @@ clutter_frame_clock_notify_presented (ClutterFrameClock *frame_clock,
frame_clock->shortterm_max_update_duration_us = frame_clock->shortterm_max_update_duration_us =
CLAMP (frame_clock->last_dispatch_lateness_us + dispatch_to_swap_us + CLAMP (frame_clock->last_dispatch_lateness_us + dispatch_to_swap_us +
MAX (swap_to_rendering_done_us, swap_to_flip_us), MAX (swap_to_rendering_done_us, swap_to_flip_us) +
frame_clock->deadline_evasion_us,
frame_clock->shortterm_max_update_duration_us, frame_clock->shortterm_max_update_duration_us,
frame_clock->refresh_interval_us); frame_clock->refresh_interval_us);
@ -1253,3 +1256,10 @@ clutter_frame_clock_class_init (ClutterFrameClockClass *klass)
G_TYPE_NONE, G_TYPE_NONE,
0); 0);
} }
void
clutter_frame_clock_set_deadline_evasion (ClutterFrameClock *frame_clock,
int64_t deadline_evasion_us)
{
frame_clock->deadline_evasion_us = deadline_evasion_us;
}

View file

@ -106,3 +106,7 @@ void clutter_frame_clock_record_flip_time (ClutterFrameClock *frame_clock,
int64_t flip_time_us); int64_t flip_time_us);
GString * clutter_frame_clock_get_max_render_time_debug_info (ClutterFrameClock *frame_clock); GString * clutter_frame_clock_get_max_render_time_debug_info (ClutterFrameClock *frame_clock);
CLUTTER_EXPORT
void clutter_frame_clock_set_deadline_evasion (ClutterFrameClock *frame_clock,
int64_t deadline_evasion_us);

View file

@ -740,6 +740,10 @@ clutter_stage_view_schedule_update (ClutterStageView *view)
{ {
ClutterStageViewPrivate *priv = ClutterStageViewPrivate *priv =
clutter_stage_view_get_instance_private (view); clutter_stage_view_get_instance_private (view);
ClutterStageViewClass *view_class = CLUTTER_STAGE_VIEW_GET_CLASS (view);
if (view_class->schedule_update)
view_class->schedule_update (view);
clutter_frame_clock_schedule_update (priv->frame_clock); clutter_frame_clock_schedule_update (priv->frame_clock);
} }

View file

@ -54,6 +54,8 @@ struct _ClutterStageViewClass
ClutterFrame * (* new_frame) (ClutterStageView *view); ClutterFrame * (* new_frame) (ClutterStageView *view);
ClutterPaintFlag (* get_default_paint_flags) (ClutterStageView *view); ClutterPaintFlag (* get_default_paint_flags) (ClutterStageView *view);
void (* schedule_update) (ClutterStageView *view);
}; };
CLUTTER_EXPORT CLUTTER_EXPORT

View file

@ -55,7 +55,6 @@ ensure_bits_initialized (CoglGlFramebufferBack *gl_framebuffer_back)
cogl_framebuffer_driver_get_framebuffer (driver); cogl_framebuffer_driver_get_framebuffer (driver);
CoglContext *ctx = cogl_framebuffer_get_context (framebuffer); CoglContext *ctx = cogl_framebuffer_get_context (framebuffer);
CoglFramebufferBits *bits = &gl_framebuffer_back->bits; CoglFramebufferBits *bits = &gl_framebuffer_back->bits;
g_autoptr (GError) error = NULL;
if (!gl_framebuffer_back->dirty_bitmasks) if (!gl_framebuffer_back->dirty_bitmasks)
return TRUE; return TRUE;

View file

@ -65,7 +65,6 @@ ensure_bits_initialized (CoglGlFramebufferFbo *gl_framebuffer_fbo)
cogl_framebuffer_driver_get_framebuffer (driver); cogl_framebuffer_driver_get_framebuffer (driver);
CoglContext *ctx = cogl_framebuffer_get_context (framebuffer); CoglContext *ctx = cogl_framebuffer_get_context (framebuffer);
CoglFramebufferBits *bits = &gl_framebuffer_fbo->bits; CoglFramebufferBits *bits = &gl_framebuffer_fbo->bits;
g_autoptr (GError) error = NULL;
if (!gl_framebuffer_fbo->dirty_bitmasks) if (!gl_framebuffer_fbo->dirty_bitmasks)
return TRUE; return TRUE;

View file

@ -1,5 +1,5 @@
project('mutter', 'c', project('mutter', 'c',
version: '46.4', version: '46.5',
meson_version: '>= 0.60.0', meson_version: '>= 0.60.0',
license: 'GPLv2+' license: 'GPLv2+'
) )

View file

@ -44,6 +44,11 @@ struct _MetaEgl
PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR; PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR;
PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR; PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR;
PFNEGLCREATESYNCPROC eglCreateSync;
PFNEGLDESTROYSYNCPROC eglDestroySync;
PFNEGLWAITSYNCPROC eglWaitSync;
PFNEGLDUPNATIVEFENCEFDANDROIDPROC eglDupNativeFenceFDANDROID;
PFNEGLBINDWAYLANDDISPLAYWL eglBindWaylandDisplayWL; PFNEGLBINDWAYLANDDISPLAYWL eglBindWaylandDisplayWL;
PFNEGLQUERYWAYLANDBUFFERWL eglQueryWaylandBufferWL; PFNEGLQUERYWAYLANDBUFFERWL eglQueryWaylandBufferWL;
@ -1162,6 +1167,90 @@ meta_egl_query_display_attrib (MetaEgl *egl,
return TRUE; return TRUE;
} }
gboolean
meta_egl_create_sync (MetaEgl *egl,
EGLDisplay display,
EGLenum type,
const EGLAttrib *attrib_list,
EGLSync *egl_sync,
GError **error)
{
if (!is_egl_proc_valid (egl->eglCreateSync, error))
return FALSE;
EGLSync sync;
sync = egl->eglCreateSync (display, type, attrib_list);
if (sync == EGL_NO_SYNC)
{
set_egl_error (error);
return FALSE;
}
*egl_sync = sync;
return TRUE;
}
gboolean
meta_egl_destroy_sync (MetaEgl *egl,
EGLDisplay display,
EGLSync sync,
GError **error)
{
if (!is_egl_proc_valid (egl->eglDestroySync, error))
return FALSE;
if (!egl->eglDestroySync (display, sync))
{
set_egl_error (error);
return FALSE;
}
return TRUE;
}
gboolean
meta_egl_wait_sync (MetaEgl *egl,
EGLDisplay display,
EGLSync sync,
EGLint flags,
GError **error)
{
if (!is_egl_proc_valid (egl->eglWaitSync, error))
return FALSE;
if (!egl->eglWaitSync (display, sync, flags))
{
set_egl_error (error);
return FALSE;
}
return TRUE;
}
EGLint
meta_egl_duplicate_native_fence_fd (MetaEgl *egl,
EGLDisplay display,
EGLSync sync,
GError **error)
{
if (!is_egl_proc_valid (egl->eglDupNativeFenceFDANDROID, error))
return EGL_NO_NATIVE_FENCE_FD_ANDROID;
EGLint fd = EGL_NO_NATIVE_FENCE_FD_ANDROID;
fd = egl->eglDupNativeFenceFDANDROID (display, sync);
if (fd == EGL_NO_NATIVE_FENCE_FD_ANDROID)
{
set_egl_error (error);
}
return fd;
}
#define GET_EGL_PROC_ADDR(proc) \ #define GET_EGL_PROC_ADDR(proc) \
egl->proc = (void *) eglGetProcAddress (#proc); egl->proc = (void *) eglGetProcAddress (#proc);
@ -1175,6 +1264,11 @@ meta_egl_constructed (GObject *object)
GET_EGL_PROC_ADDR (eglCreateImageKHR); GET_EGL_PROC_ADDR (eglCreateImageKHR);
GET_EGL_PROC_ADDR (eglDestroyImageKHR); GET_EGL_PROC_ADDR (eglDestroyImageKHR);
GET_EGL_PROC_ADDR (eglCreateSync);
GET_EGL_PROC_ADDR (eglDestroySync);
GET_EGL_PROC_ADDR (eglWaitSync);
GET_EGL_PROC_ADDR (eglDupNativeFenceFDANDROID);
GET_EGL_PROC_ADDR (eglBindWaylandDisplayWL); GET_EGL_PROC_ADDR (eglBindWaylandDisplayWL);
GET_EGL_PROC_ADDR (eglQueryWaylandBufferWL); GET_EGL_PROC_ADDR (eglQueryWaylandBufferWL);

View file

@ -276,3 +276,26 @@ gboolean meta_egl_query_display_attrib (MetaEgl *egl,
EGLint attribute, EGLint attribute,
EGLAttrib *value, EGLAttrib *value,
GError **error); GError **error);
gboolean meta_egl_create_sync (MetaEgl *egl,
EGLDisplay display,
EGLenum type,
const EGLAttrib *attrib_list,
EGLSync *egl_sync,
GError **error);
gboolean meta_egl_destroy_sync (MetaEgl *egl,
EGLDisplay display,
EGLSync sync,
GError **error);
gboolean meta_egl_wait_sync (MetaEgl *egl,
EGLDisplay display,
EGLSync sync,
EGLint flags,
GError **error);
EGLint meta_egl_duplicate_native_fence_fd (MetaEgl *egl,
EGLDisplay display,
EGLSync sync,
GError **error);

View file

@ -609,6 +609,7 @@ init_gpus (MetaBackendNative *native,
{ {
MetaBackend *backend = META_BACKEND (native); MetaBackend *backend = META_BACKEND (native);
MetaUdev *udev = meta_backend_native_get_udev (native); MetaUdev *udev = meta_backend_native_get_udev (native);
MetaKms *kms = meta_backend_native_get_kms (native);
g_autoptr (GError) local_error = NULL; g_autoptr (GError) local_error = NULL;
MetaUdevDeviceType device_type = 0; MetaUdevDeviceType device_type = 0;
GList *devices; GList *devices;
@ -669,6 +670,8 @@ init_gpus (MetaBackendNative *native,
g_list_free_full (devices, g_object_unref); g_list_free_full (devices, g_object_unref);
meta_kms_notify_probed (kms);
if (!meta_backend_is_headless (backend) && if (!meta_backend_is_headless (backend) &&
g_list_length (meta_backend_get_gpus (backend)) == 0) g_list_length (meta_backend_get_gpus (backend)) == 0)
{ {

View file

@ -348,6 +348,15 @@ meta_crtc_kms_is_hw_cursor_supported (MetaCrtcNative *crtc_native)
return meta_kms_device_has_cursor_plane_for (kms_device, kms_crtc); return meta_kms_device_has_cursor_plane_for (kms_device, kms_crtc);
} }
static int64_t
meta_crtc_kms_get_deadline_evasion (MetaCrtcNative *crtc_native)
{
MetaCrtcKms *crtc_kms = META_CRTC_KMS (crtc_native);
MetaKmsCrtc *kms_crtc = meta_crtc_kms_get_kms_crtc (crtc_kms);
return meta_kms_crtc_get_deadline_evasion (kms_crtc);
}
MetaKmsPlane * MetaKmsPlane *
meta_crtc_kms_get_assigned_cursor_plane (MetaCrtcKms *crtc_kms) meta_crtc_kms_get_assigned_cursor_plane (MetaCrtcKms *crtc_kms)
{ {
@ -479,6 +488,7 @@ meta_crtc_kms_class_init (MetaCrtcKmsClass *klass)
crtc_native_class->is_transform_handled = meta_crtc_kms_is_transform_handled; crtc_native_class->is_transform_handled = meta_crtc_kms_is_transform_handled;
crtc_native_class->is_hw_cursor_supported = meta_crtc_kms_is_hw_cursor_supported; crtc_native_class->is_hw_cursor_supported = meta_crtc_kms_is_hw_cursor_supported;
crtc_native_class->get_deadline_evasion = meta_crtc_kms_get_deadline_evasion;
signals[GAMMA_LUT_CHANGED] = signals[GAMMA_LUT_CHANGED] =
g_signal_new ("gamma-lut-changed", g_signal_new ("gamma-lut-changed",

View file

@ -39,6 +39,14 @@ meta_crtc_native_is_hw_cursor_supported (MetaCrtcNative *crtc_native)
return klass->is_hw_cursor_supported (crtc_native); return klass->is_hw_cursor_supported (crtc_native);
} }
int64_t
meta_crtc_native_get_deadline_evasion (MetaCrtcNative *crtc_native)
{
MetaCrtcNativeClass *klass = META_CRTC_NATIVE_GET_CLASS (crtc_native);
return klass->get_deadline_evasion (crtc_native);
}
static void static void
meta_crtc_native_init (MetaCrtcNative *crtc_native) meta_crtc_native_init (MetaCrtcNative *crtc_native)
{ {

View file

@ -31,9 +31,12 @@ struct _MetaCrtcNativeClass
gboolean (* is_transform_handled) (MetaCrtcNative *crtc_native, gboolean (* is_transform_handled) (MetaCrtcNative *crtc_native,
MetaMonitorTransform monitor_transform); MetaMonitorTransform monitor_transform);
gboolean (* is_hw_cursor_supported) (MetaCrtcNative *crtc_native); gboolean (* is_hw_cursor_supported) (MetaCrtcNative *crtc_native);
int64_t (* get_deadline_evasion) (MetaCrtcNative *crtc_native);
}; };
gboolean meta_crtc_native_is_transform_handled (MetaCrtcNative *crtc_native, gboolean meta_crtc_native_is_transform_handled (MetaCrtcNative *crtc_native,
MetaMonitorTransform transform); MetaMonitorTransform transform);
gboolean meta_crtc_native_is_hw_cursor_supported (MetaCrtcNative *crtc_native); gboolean meta_crtc_native_is_hw_cursor_supported (MetaCrtcNative *crtc_native);
int64_t meta_crtc_native_get_deadline_evasion (MetaCrtcNative *crtc_native);

View file

@ -70,6 +70,12 @@ meta_crtc_virtual_is_hw_cursor_supported (MetaCrtcNative *crtc_native)
return TRUE; return TRUE;
} }
static int64_t
meta_crtc_virtual_get_deadline_evasion (MetaCrtcNative *crtc_native)
{
return 0;
}
static void static void
meta_crtc_virtual_init (MetaCrtcVirtual *crtc_virtual) meta_crtc_virtual_init (MetaCrtcVirtual *crtc_virtual)
{ {
@ -89,4 +95,6 @@ meta_crtc_virtual_class_init (MetaCrtcVirtualClass *klass)
meta_crtc_virtual_is_transform_handled; meta_crtc_virtual_is_transform_handled;
crtc_native_class->is_hw_cursor_supported = crtc_native_class->is_hw_cursor_supported =
meta_crtc_virtual_is_hw_cursor_supported; meta_crtc_virtual_is_hw_cursor_supported;
crtc_native_class->get_deadline_evasion =
meta_crtc_virtual_get_deadline_evasion;
} }

View file

@ -27,6 +27,9 @@ struct _MetaFrameNative
{ {
ClutterFrame base; ClutterFrame base;
MetaDrmBuffer *buffer;
CoglScanout *scanout;
MetaKmsUpdate *kms_update; MetaKmsUpdate *kms_update;
}; };
@ -35,6 +38,9 @@ meta_frame_native_release (ClutterFrame *frame)
{ {
MetaFrameNative *frame_native = meta_frame_native_from_frame (frame); MetaFrameNative *frame_native = meta_frame_native_from_frame (frame);
g_clear_object (&frame_native->buffer);
g_clear_object (&frame_native->scanout);
g_return_if_fail (!frame_native->kms_update); g_return_if_fail (!frame_native->kms_update);
} }
@ -76,3 +82,29 @@ meta_frame_native_has_kms_update (MetaFrameNative *frame_native)
{ {
return !!frame_native->kms_update; return !!frame_native->kms_update;
} }
void
meta_frame_native_set_buffer (MetaFrameNative *frame_native,
MetaDrmBuffer *buffer)
{
g_set_object (&frame_native->buffer, buffer);
}
MetaDrmBuffer *
meta_frame_native_get_buffer (MetaFrameNative *frame_native)
{
return frame_native->buffer;
}
void
meta_frame_native_set_scanout (MetaFrameNative *frame_native,
CoglScanout *scanout)
{
g_set_object (&frame_native->scanout, scanout);
}
CoglScanout *
meta_frame_native_get_scanout (MetaFrameNative *frame_native)
{
return frame_native->scanout;
}

View file

@ -17,6 +17,7 @@
#pragma once #pragma once
#include "backends/native/meta-backend-native-types.h"
#include "backends/native/meta-kms-types.h" #include "backends/native/meta-kms-types.h"
#include "clutter/clutter.h" #include "clutter/clutter.h"
#include "core/util-private.h" #include "core/util-private.h"
@ -36,3 +37,13 @@ MetaKmsUpdate * meta_frame_native_steal_kms_update (MetaFrameNative *frame_nativ
META_EXPORT_TEST META_EXPORT_TEST
gboolean meta_frame_native_has_kms_update (MetaFrameNative *frame_native); gboolean meta_frame_native_has_kms_update (MetaFrameNative *frame_native);
void meta_frame_native_set_buffer (MetaFrameNative *frame_native,
MetaDrmBuffer *buffer);
MetaDrmBuffer * meta_frame_native_get_buffer (MetaFrameNative *frame_native);
void meta_frame_native_set_scanout (MetaFrameNative *frame_native,
CoglScanout *scanout);
CoglScanout * meta_frame_native_get_scanout (MetaFrameNative *frame_native);

View file

@ -28,8 +28,7 @@
#include "backends/native/meta-kms-update-private.h" #include "backends/native/meta-kms-update-private.h"
#include "backends/native/meta-kms-utils.h" #include "backends/native/meta-kms-utils.h"
#define DEADLINE_EVASION_US 800 #define DEADLINE_EVASION_CONSTANT_US 200
#define DEADLINE_EVASION_WITH_KMS_TOPIC_US 1000
#define MINIMUM_REFRESH_RATE 30.f #define MINIMUM_REFRESH_RATE 30.f
@ -50,6 +49,10 @@ struct _MetaKmsCrtc
MetaKmsCrtcState current_state; MetaKmsCrtcState current_state;
MetaKmsCrtcPropTable prop_table; MetaKmsCrtcPropTable prop_table;
int64_t shortterm_max_dispatch_duration_us;
int64_t deadline_evasion_us;
int64_t deadline_evasion_update_time_us;
}; };
G_DEFINE_TYPE (MetaKmsCrtc, meta_kms_crtc, G_TYPE_OBJECT) G_DEFINE_TYPE (MetaKmsCrtc, meta_kms_crtc, G_TYPE_OBJECT)
@ -543,6 +546,33 @@ get_crtc_type_bitmask (MetaKmsCrtc *crtc)
} }
} }
static void
maybe_update_deadline_evasion (MetaKmsCrtc *crtc,
int64_t next_presentation_time_us)
{
/* Do not update long-term max if there has been no measurement */
if (!crtc->shortterm_max_dispatch_duration_us)
return;
if (next_presentation_time_us - crtc->deadline_evasion_update_time_us <
G_USEC_PER_SEC)
return;
if (crtc->deadline_evasion_us > crtc->shortterm_max_dispatch_duration_us)
{
/* Exponential drop-off toward the clamped short-term max */
crtc->deadline_evasion_us -=
(crtc->deadline_evasion_us - crtc->shortterm_max_dispatch_duration_us) / 2;
}
else
{
crtc->deadline_evasion_us = crtc->shortterm_max_dispatch_duration_us;
}
crtc->shortterm_max_dispatch_duration_us = 0;
crtc->deadline_evasion_update_time_us = next_presentation_time_us;
}
gboolean gboolean
meta_kms_crtc_determine_deadline (MetaKmsCrtc *crtc, meta_kms_crtc_determine_deadline (MetaKmsCrtc *crtc,
int64_t *out_next_deadline_us, int64_t *out_next_deadline_us,
@ -610,10 +640,8 @@ meta_kms_crtc_determine_deadline (MetaKmsCrtc *crtc,
* *
*/ */
if (meta_is_topic_enabled (META_DEBUG_KMS)) deadline_evasion_us = meta_kms_crtc_get_deadline_evasion (crtc);
deadline_evasion_us = DEADLINE_EVASION_WITH_KMS_TOPIC_US; maybe_update_deadline_evasion (crtc, next_presentation_us);
else
deadline_evasion_us = DEADLINE_EVASION_US;
vblank_duration_us = meta_calculate_drm_mode_vblank_duration_us (drm_mode); vblank_duration_us = meta_calculate_drm_mode_vblank_duration_us (drm_mode);
next_deadline_us = next_presentation_us - (vblank_duration_us + next_deadline_us = next_presentation_us - (vblank_duration_us +
@ -625,3 +653,33 @@ meta_kms_crtc_determine_deadline (MetaKmsCrtc *crtc,
return TRUE; return TRUE;
} }
void
meta_kms_crtc_update_shortterm_max_dispatch_duration (MetaKmsCrtc *crtc,
int64_t duration_us)
{
int64_t refresh_interval_us;
if (duration_us <= crtc->shortterm_max_dispatch_duration_us)
return;
refresh_interval_us =
(int64_t) (0.5 + G_USEC_PER_SEC /
meta_calculate_drm_mode_refresh_rate (&crtc->current_state.drm_mode));
crtc->shortterm_max_dispatch_duration_us = MIN (duration_us, refresh_interval_us);
}
int64_t
meta_kms_crtc_get_deadline_evasion (MetaKmsCrtc *crtc)
{
int64_t deadline_evasion_us;
deadline_evasion_us =
MAX (crtc->shortterm_max_dispatch_duration_us, crtc->deadline_evasion_us);
if (!deadline_evasion_us)
return 0;
return deadline_evasion_us + DEADLINE_EVASION_CONSTANT_US;
}

View file

@ -65,3 +65,8 @@ int meta_kms_crtc_get_idx (MetaKmsCrtc *crtc);
META_EXPORT_TEST META_EXPORT_TEST
gboolean meta_kms_crtc_is_active (MetaKmsCrtc *crtc); gboolean meta_kms_crtc_is_active (MetaKmsCrtc *crtc);
void meta_kms_crtc_update_shortterm_max_dispatch_duration (MetaKmsCrtc *crtc,
int64_t duration_us);
int64_t meta_kms_crtc_get_deadline_evasion (MetaKmsCrtc *crtc);

View file

@ -643,7 +643,7 @@ process_plane_assignment (MetaKmsImplDevice *impl_device,
return FALSE; return FALSE;
} }
if (plane_assignment->flags & META_KMS_ASSIGN_PLANE_FLAG_DIRECT_SCANOUT) if (plane_assignment->flags & META_KMS_ASSIGN_PLANE_FLAG_DISABLE_IMPLICIT_SYNC)
{ {
int signaled_sync_file; int signaled_sync_file;

View file

@ -39,6 +39,7 @@
#include "backends/native/meta-kms-plane-private.h" #include "backends/native/meta-kms-plane-private.h"
#include "backends/native/meta-kms-plane.h" #include "backends/native/meta-kms-plane.h"
#include "backends/native/meta-kms-private.h" #include "backends/native/meta-kms-private.h"
#include "backends/native/meta-kms-utils.h"
#include "backends/native/meta-thread-private.h" #include "backends/native/meta-thread-private.h"
#include "meta-default-modes.h" #include "meta-default-modes.h"
@ -71,9 +72,17 @@ typedef struct _CrtcDeadline
GSource *source; GSource *source;
gboolean armed; gboolean armed;
gboolean is_deadline_page_flip; gboolean is_deadline_page_flip;
int64_t expected_deadline_time_us;
int64_t expected_presentation_time_us; int64_t expected_presentation_time_us;
gboolean has_expected_presentation_time; gboolean has_expected_presentation_time;
} deadline; } deadline;
struct {
MetaKmsUpdate *kms_update;
MetaKmsUpdateFlag flags;
MetaKmsCrtc *latch_crtc;
GSource *source;
} submitted_update;
} CrtcFrame; } CrtcFrame;
typedef enum _MetaDeadlineTimerState typedef enum _MetaDeadlineTimerState
@ -108,6 +117,8 @@ typedef struct _MetaKmsImplDevicePrivate
GHashTable *crtc_frames; GHashTable *crtc_frames;
gboolean realtime_inhibited_pending_mode_set;
MetaDeadlineTimerState deadline_timer_state; MetaDeadlineTimerState deadline_timer_state;
gboolean sync_file_retrieved; gboolean sync_file_retrieved;
@ -1165,6 +1176,7 @@ arm_crtc_frame_deadline_timer (CrtcFrame *crtc_frame,
timerfd_settime (crtc_frame->deadline.timer_fd, timerfd_settime (crtc_frame->deadline.timer_fd,
TFD_TIMER_ABSTIME, &its, NULL); TFD_TIMER_ABSTIME, &its, NULL);
crtc_frame->deadline.expected_deadline_time_us = next_deadline_us;
crtc_frame->deadline.expected_presentation_time_us = next_presentation_us; crtc_frame->deadline.expected_presentation_time_us = next_presentation_us;
crtc_frame->deadline.has_expected_presentation_time = next_presentation_us != 0; crtc_frame->deadline.has_expected_presentation_time = next_presentation_us != 0;
crtc_frame->deadline.armed = TRUE; crtc_frame->deadline.armed = TRUE;
@ -1197,7 +1209,7 @@ crtc_page_flip_feedback_flipped (MetaKmsCrtc *crtc,
CrtcFrame *crtc_frame = user_data; CrtcFrame *crtc_frame = user_data;
if (crtc_frame->deadline.is_deadline_page_flip && if (crtc_frame->deadline.is_deadline_page_flip &&
meta_is_topic_enabled (META_DEBUG_KMS)) meta_is_topic_enabled (META_DEBUG_KMS_DEADLINE))
{ {
struct timeval page_flip_timeval; struct timeval page_flip_timeval;
int64_t presentation_time_us; int64_t presentation_time_us;
@ -1210,7 +1222,7 @@ crtc_page_flip_feedback_flipped (MetaKmsCrtc *crtc,
if (crtc_frame->deadline.has_expected_presentation_time) if (crtc_frame->deadline.has_expected_presentation_time)
{ {
meta_topic (META_DEBUG_KMS, meta_topic (META_DEBUG_KMS_DEADLINE,
"Deadline page flip presentation time: %" G_GINT64_FORMAT " us, " "Deadline page flip presentation time: %" G_GINT64_FORMAT " us, "
"expected %" G_GINT64_FORMAT " us " "expected %" G_GINT64_FORMAT " us "
"(diff: %" G_GINT64_FORMAT ")", "(diff: %" G_GINT64_FORMAT ")",
@ -1221,7 +1233,7 @@ crtc_page_flip_feedback_flipped (MetaKmsCrtc *crtc,
} }
else else
{ {
meta_topic (META_DEBUG_KMS, meta_topic (META_DEBUG_KMS_DEADLINE,
"Deadline page flip presentation time: %" G_GINT64_FORMAT " us", "Deadline page flip presentation time: %" G_GINT64_FORMAT " us",
presentation_time_us); presentation_time_us);
} }
@ -1390,11 +1402,16 @@ crtc_frame_deadline_dispatch (MetaThreadImpl *thread_impl,
GError **error) GError **error)
{ {
CrtcFrame *crtc_frame = user_data; CrtcFrame *crtc_frame = user_data;
MetaKmsDevice *device = meta_kms_crtc_get_device (crtc_frame->crtc); MetaKmsCrtc *crtc = crtc_frame->crtc;
MetaKmsDevice *device = meta_kms_crtc_get_device (crtc);
MetaKmsImplDevice *impl_device = meta_kms_device_get_impl_device (device); MetaKmsImplDevice *impl_device = meta_kms_device_get_impl_device (device);
g_autoptr (MetaKmsFeedback) feedback = NULL; g_autoptr (MetaKmsFeedback) feedback = NULL;
uint64_t timer_value; uint64_t timer_value;
ssize_t ret; ssize_t ret;
int64_t dispatch_time_us = 0, update_done_time_us, interval_us;
if (meta_is_topic_enabled (META_DEBUG_KMS_DEADLINE))
dispatch_time_us = g_get_monotonic_time ();
ret = read (crtc_frame->deadline.timer_fd, ret = read (crtc_frame->deadline.timer_fd,
&timer_value, &timer_value,
@ -1416,6 +1433,36 @@ crtc_frame_deadline_dispatch (MetaThreadImpl *thread_impl,
crtc_frame->crtc, crtc_frame->crtc,
g_steal_pointer (&crtc_frame->pending_update), g_steal_pointer (&crtc_frame->pending_update),
META_KMS_UPDATE_FLAG_NONE); META_KMS_UPDATE_FLAG_NONE);
update_done_time_us = g_get_monotonic_time ();
/* Calculate how long after the planned start of deadline dispatch it finished */
interval_us = update_done_time_us - crtc_frame->deadline.expected_deadline_time_us;
if (meta_is_topic_enabled (META_DEBUG_KMS_DEADLINE))
{
int64_t deadline_evasion_us, lateness_us, duration_us, vblank_delta_us;
deadline_evasion_us = meta_kms_crtc_get_deadline_evasion (crtc);
lateness_us = dispatch_time_us -
crtc_frame->deadline.expected_deadline_time_us;
duration_us = update_done_time_us - dispatch_time_us;
vblank_delta_us = deadline_evasion_us - lateness_us - duration_us;
meta_topic (META_DEBUG_KMS_DEADLINE,
"Deadline evasion %3"G_GINT64_FORMAT "µs, "
"dispatch started %3"G_GINT64_FORMAT "µs %s and "
"completed %3"G_GINT64_FORMAT "µs after that, "
"%3"G_GINT64_FORMAT "µs %s start of vblank.",
deadline_evasion_us,
ABS (lateness_us),
lateness_us >= 0 ? "late" : "early",
duration_us,
ABS (vblank_delta_us),
vblank_delta_us >= 0 ? "before" : "after");
}
meta_kms_crtc_update_shortterm_max_dispatch_duration (crtc, interval_us);
if (meta_kms_feedback_did_pass (feedback)) if (meta_kms_feedback_did_pass (feedback))
crtc_frame->deadline.is_deadline_page_flip = TRUE; crtc_frame->deadline.is_deadline_page_flip = TRUE;
disarm_crtc_frame_deadline_timer (crtc_frame); disarm_crtc_frame_deadline_timer (crtc_frame);
@ -1429,6 +1476,8 @@ crtc_frame_free (CrtcFrame *crtc_frame)
g_clear_fd (&crtc_frame->deadline.timer_fd, NULL); g_clear_fd (&crtc_frame->deadline.timer_fd, NULL);
g_clear_pointer (&crtc_frame->deadline.source, g_source_destroy); g_clear_pointer (&crtc_frame->deadline.source, g_source_destroy);
g_clear_pointer (&crtc_frame->pending_update, meta_kms_update_free); g_clear_pointer (&crtc_frame->pending_update, meta_kms_update_free);
g_clear_pointer (&crtc_frame->submitted_update.kms_update, meta_kms_update_free);
g_clear_pointer (&crtc_frame->submitted_update.source, g_source_destroy);
g_free (crtc_frame); g_free (crtc_frame);
} }
@ -1470,18 +1519,22 @@ ensure_crtc_frame (MetaKmsImplDevice *impl_device,
MetaKmsImpl *impl = meta_kms_impl_device_get_impl (impl_device); MetaKmsImpl *impl = meta_kms_impl_device_get_impl (impl_device);
MetaThreadImpl *thread_impl = META_THREAD_IMPL (impl); MetaThreadImpl *thread_impl = META_THREAD_IMPL (impl);
CrtcFrame *crtc_frame; CrtcFrame *crtc_frame;
gboolean want_deadline_timer, have_deadline_timer;
crtc_frame = get_crtc_frame (impl_device, latch_crtc); crtc_frame = get_crtc_frame (impl_device, latch_crtc);
if (crtc_frame) if (!crtc_frame)
return crtc_frame; {
crtc_frame = g_new0 (CrtcFrame, 1);
crtc_frame->impl_device = impl_device;
crtc_frame->crtc = latch_crtc;
crtc_frame->deadline.timer_fd = -1;
crtc_frame->await_flush = TRUE;
g_hash_table_insert (priv->crtc_frames, latch_crtc, crtc_frame);
}
crtc_frame = g_new0 (CrtcFrame, 1); want_deadline_timer = is_using_deadline_timer (impl_device);
crtc_frame->impl_device = impl_device; have_deadline_timer = crtc_frame->deadline.timer_fd >= 0;
crtc_frame->crtc = latch_crtc; if (want_deadline_timer && !have_deadline_timer)
crtc_frame->deadline.timer_fd = -1;
crtc_frame->await_flush = TRUE;
if (is_using_deadline_timer (impl_device))
{ {
int timer_fd; int timer_fd;
GSource *source; GSource *source;
@ -1506,8 +1559,11 @@ ensure_crtc_frame (MetaKmsImplDevice *impl_device,
g_source_unref (source); g_source_unref (source);
} }
else if (!want_deadline_timer && have_deadline_timer)
g_hash_table_insert (priv->crtc_frames, latch_crtc, crtc_frame); {
g_clear_fd (&crtc_frame->deadline.timer_fd, NULL);
g_clear_pointer (&crtc_frame->deadline.source, g_source_destroy);
}
return crtc_frame; return crtc_frame;
} }
@ -1530,6 +1586,79 @@ queue_update (MetaKmsImplDevice *impl_device,
} }
} }
static gpointer
meta_kms_impl_device_update_ready (MetaThreadImpl *impl,
gpointer user_data,
GError **error)
{
CrtcFrame *crtc_frame = user_data;
MetaKmsDevice *device = meta_kms_crtc_get_device (crtc_frame->crtc);
MetaKmsImplDevice *impl_device = meta_kms_device_get_impl_device (device);
MetaKmsImplDevicePrivate *priv =
meta_kms_impl_device_get_instance_private (impl_device);
MetaKmsUpdate *update;
MetaKmsCrtc *latch_crtc;
MetaKmsFeedback *feedback;
meta_assert_in_kms_impl (meta_kms_impl_get_kms (priv->impl));
g_clear_pointer (&crtc_frame->submitted_update.source, g_source_destroy);
update = g_steal_pointer (&crtc_frame->submitted_update.kms_update);
meta_kms_update_realize (update, impl_device);
latch_crtc = g_steal_pointer (&crtc_frame->submitted_update.latch_crtc);
if (crtc_frame->pending_page_flip &&
!meta_kms_update_get_mode_sets (update))
{
g_assert (latch_crtc);
meta_topic (META_DEBUG_KMS,
"Queuing update on CRTC %u (%s): pending page flip",
meta_kms_crtc_get_id (latch_crtc),
priv->path);
queue_update (impl_device, crtc_frame, update);
return GINT_TO_POINTER (TRUE);
}
if (crtc_frame->pending_update)
{
meta_kms_update_merge_from (crtc_frame->pending_update, update);
meta_kms_update_free (update);
update = g_steal_pointer (&crtc_frame->pending_update);
disarm_crtc_frame_deadline_timer (crtc_frame);
}
meta_kms_device_handle_flush (priv->device, latch_crtc);
feedback = do_process (impl_device, latch_crtc, update, crtc_frame->submitted_update.flags);
if (meta_kms_feedback_did_pass (feedback) &&
crtc_frame->deadline.armed)
disarm_crtc_frame_deadline_timer (crtc_frame);
meta_kms_feedback_unref (feedback);
return GINT_TO_POINTER (TRUE);
}
static gboolean
is_fd_readable (int fd)
{
GPollFD poll_fd;
poll_fd.fd = fd;
poll_fd.events = G_IO_IN;
poll_fd.revents = 0;
if (!g_poll (&poll_fd, 1, 0))
return FALSE;
return (poll_fd.revents & (G_IO_IN | G_IO_NVAL)) != 0;
}
void void
meta_kms_impl_device_handle_update (MetaKmsImplDevice *impl_device, meta_kms_impl_device_handle_update (MetaKmsImplDevice *impl_device,
MetaKmsUpdate *update, MetaKmsUpdate *update,
@ -1537,10 +1666,15 @@ meta_kms_impl_device_handle_update (MetaKmsImplDevice *impl_device,
{ {
MetaKmsImplDevicePrivate *priv = MetaKmsImplDevicePrivate *priv =
meta_kms_impl_device_get_instance_private (impl_device); meta_kms_impl_device_get_instance_private (impl_device);
MetaKmsImpl *kms_impl = meta_kms_impl_device_get_impl (impl_device);
MetaThreadImpl *thread_impl = META_THREAD_IMPL (kms_impl);
g_autoptr (GError) error = NULL; g_autoptr (GError) error = NULL;
MetaKmsCrtc *latch_crtc; MetaKmsCrtc *latch_crtc;
CrtcFrame *crtc_frame; CrtcFrame *crtc_frame;
MetaKmsFeedback *feedback; MetaKmsFeedback *feedback;
g_autoptr (GSource) source = NULL;
g_autofree char *name = NULL;
int sync_fd = -1;
meta_assert_in_kms_impl (meta_kms_impl_get_kms (priv->impl)); meta_assert_in_kms_impl (meta_kms_impl_get_kms (priv->impl));
@ -1561,38 +1695,58 @@ meta_kms_impl_device_handle_update (MetaKmsImplDevice *impl_device,
if (!ensure_device_file (impl_device, &error)) if (!ensure_device_file (impl_device, &error))
goto err; goto err;
meta_kms_update_realize (update, impl_device);
crtc_frame = ensure_crtc_frame (impl_device, latch_crtc); crtc_frame = ensure_crtc_frame (impl_device, latch_crtc);
crtc_frame->await_flush = FALSE; if (crtc_frame->submitted_update.kms_update)
if (crtc_frame->pending_page_flip &&
!meta_kms_update_get_mode_sets (update))
{ {
g_assert (latch_crtc); g_set_error (&error, G_IO_ERROR, G_IO_ERROR_PENDING,
"Previously-submitted update wasn't ready yet");
goto err;
}
meta_topic (META_DEBUG_KMS, crtc_frame->await_flush = FALSE;
"Queuing update on CRTC %u (%s): pending page flip", crtc_frame->submitted_update.kms_update = update;
meta_kms_crtc_get_id (latch_crtc), crtc_frame->submitted_update.flags = flags;
priv->path); crtc_frame->submitted_update.latch_crtc = latch_crtc;
queue_update (impl_device, crtc_frame, update); if (is_using_deadline_timer (impl_device))
sync_fd = meta_kms_update_get_sync_fd (update);
if (sync_fd >= 0)
{
GList *l;
for (l = meta_kms_update_get_plane_assignments (update); l; l = l->next)
{
MetaKmsPlaneAssignment *assignment = l->data;
assignment->flags |= META_KMS_ASSIGN_PLANE_FLAG_DISABLE_IMPLICIT_SYNC;
}
}
if (sync_fd < 0 ||
is_fd_readable (sync_fd))
{
meta_kms_impl_device_update_ready (thread_impl,
crtc_frame,
NULL);
return; return;
} }
if (crtc_frame->pending_update) source = meta_thread_impl_register_fd (thread_impl,
{ sync_fd,
meta_kms_update_merge_from (crtc_frame->pending_update, update); meta_kms_impl_device_update_ready,
meta_kms_update_free (update); crtc_frame);
update = g_steal_pointer (&crtc_frame->pending_update);
disarm_crtc_frame_deadline_timer (crtc_frame);
}
meta_kms_device_handle_flush (priv->device, latch_crtc); name = g_strdup_printf ("[mutter] KMS update sync_fd (crtc: %u, %s)",
meta_kms_crtc_get_id (latch_crtc),
priv->path);
g_source_set_name (source, name);
g_source_set_priority (source, G_PRIORITY_HIGH + 1);
g_source_set_can_recurse (source, FALSE);
g_source_set_ready_time (source, -1);
feedback = do_process (impl_device, latch_crtc, update, flags); crtc_frame->submitted_update.source = source;
meta_kms_feedback_unref (feedback);
return; return;
err: err:
@ -1688,6 +1842,25 @@ needs_flush:
meta_kms_device_set_needs_flush (meta_kms_crtc_get_device (crtc), crtc); meta_kms_device_set_needs_flush (meta_kms_crtc_get_device (crtc), crtc);
} }
static void
disarm_all_deadline_timers (MetaKmsImplDevice *impl_device)
{
MetaKmsImplDevicePrivate *priv =
meta_kms_impl_device_get_instance_private (impl_device);
GHashTableIter iter;
CrtcFrame *crtc_frame;
g_hash_table_iter_init (&iter, priv->crtc_frames);
while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &crtc_frame))
{
crtc_frame->deadline.is_deadline_page_flip = FALSE;
crtc_frame->await_flush = FALSE;
crtc_frame->pending_page_flip = FALSE;
g_clear_pointer (&crtc_frame->pending_update, meta_kms_update_free);
disarm_crtc_frame_deadline_timer (crtc_frame);
}
}
static MetaKmsFeedback * static MetaKmsFeedback *
process_mode_set_update (MetaKmsImplDevice *impl_device, process_mode_set_update (MetaKmsImplDevice *impl_device,
MetaKmsUpdate *update, MetaKmsUpdate *update,
@ -1701,7 +1874,6 @@ process_mode_set_update (MetaKmsImplDevice *impl_device,
MetaKmsFeedback *feedback; MetaKmsFeedback *feedback;
CrtcFrame *crtc_frame; CrtcFrame *crtc_frame;
GList *l; GList *l;
GHashTableIter iter;
for (l = meta_kms_update_get_mode_sets (update); l; l = l->next) for (l = meta_kms_update_get_mode_sets (update); l; l = l->next)
{ {
@ -1720,20 +1892,18 @@ process_mode_set_update (MetaKmsImplDevice *impl_device,
update = g_steal_pointer (&crtc_frame->pending_update); update = g_steal_pointer (&crtc_frame->pending_update);
} }
g_hash_table_iter_init (&iter, priv->crtc_frames); disarm_all_deadline_timers (impl_device);
while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &crtc_frame))
{
crtc_frame->deadline.is_deadline_page_flip = FALSE;
crtc_frame->await_flush = FALSE;
crtc_frame->pending_page_flip = FALSE;
g_clear_pointer (&crtc_frame->pending_update, meta_kms_update_free);
disarm_crtc_frame_deadline_timer (crtc_frame);
}
meta_thread_inhibit_realtime_in_impl (thread); meta_thread_inhibit_realtime_in_impl (thread);
feedback = do_process (impl_device, NULL, update, flags); feedback = do_process (impl_device, NULL, update, flags);
meta_thread_uninhibit_realtime_in_impl (thread); meta_thread_uninhibit_realtime_in_impl (thread);
if (priv->realtime_inhibited_pending_mode_set)
{
priv->realtime_inhibited_pending_mode_set = FALSE;
meta_thread_uninhibit_realtime_in_impl (thread);
}
return feedback; return feedback;
} }
@ -1786,6 +1956,8 @@ meta_kms_impl_device_disable (MetaKmsImplDevice *impl_device)
if (!priv->device_file) if (!priv->device_file)
return; return;
disarm_all_deadline_timers (impl_device);
meta_kms_impl_device_hold_fd (impl_device); meta_kms_impl_device_hold_fd (impl_device);
meta_thread_inhibit_realtime_in_impl (thread); meta_thread_inhibit_realtime_in_impl (thread);
klass->disable (impl_device); klass->disable (impl_device);
@ -1924,6 +2096,15 @@ meta_kms_impl_device_finalize (GObject *object)
MetaKmsImplDevicePrivate *priv = MetaKmsImplDevicePrivate *priv =
meta_kms_impl_device_get_instance_private (impl_device); meta_kms_impl_device_get_instance_private (impl_device);
if (priv->realtime_inhibited_pending_mode_set)
{
MetaThreadImpl *thread_impl = META_THREAD_IMPL (priv->impl);
MetaThread *thread = meta_thread_impl_get_thread (thread_impl);
priv->realtime_inhibited_pending_mode_set = FALSE;
meta_thread_uninhibit_realtime_in_impl (thread);
}
meta_kms_impl_remove_impl_device (priv->impl, impl_device); meta_kms_impl_remove_impl_device (priv->impl, impl_device);
g_list_free_full (priv->planes, g_object_unref); g_list_free_full (priv->planes, g_object_unref);
@ -1973,6 +2154,16 @@ meta_kms_impl_device_init_mode_setting (MetaKmsImplDevice *impl_device,
update_connectors (impl_device, drm_resources, 0); update_connectors (impl_device, drm_resources, 0);
if (!priv->crtcs)
{
MetaThreadImpl *thread_impl = META_THREAD_IMPL (priv->impl);
MetaThread *thread = meta_thread_impl_get_thread (thread_impl);
g_warn_if_fail (priv->realtime_inhibited_pending_mode_set);
meta_thread_uninhibit_realtime_in_impl (thread);
priv->realtime_inhibited_pending_mode_set = FALSE;
}
drmModeFreeResources (drm_resources); drmModeFreeResources (drm_resources);
return TRUE; return TRUE;
@ -2050,6 +2241,8 @@ meta_kms_impl_device_initable_init (GInitable *initable,
MetaKmsImplDevice *impl_device = META_KMS_IMPL_DEVICE (initable); MetaKmsImplDevice *impl_device = META_KMS_IMPL_DEVICE (initable);
MetaKmsImplDevicePrivate *priv = MetaKmsImplDevicePrivate *priv =
meta_kms_impl_device_get_instance_private (impl_device); meta_kms_impl_device_get_instance_private (impl_device);
MetaThreadImpl *thread_impl = META_THREAD_IMPL (priv->impl);
MetaThread *thread = meta_thread_impl_get_thread (thread_impl);
int fd; int fd;
if (!ensure_device_file (impl_device, error)) if (!ensure_device_file (impl_device, error))
@ -2075,6 +2268,9 @@ meta_kms_impl_device_initable_init (GInitable *initable,
priv->sync_file = -1; priv->sync_file = -1;
meta_thread_inhibit_realtime_in_impl (thread);
priv->realtime_inhibited_pending_mode_set = TRUE;
return TRUE; return TRUE;
} }

View file

@ -172,12 +172,32 @@ meta_kms_impl_finalize (GObject *object)
G_OBJECT_CLASS (meta_kms_impl_parent_class)->finalize (object); G_OBJECT_CLASS (meta_kms_impl_parent_class)->finalize (object);
} }
static void
meta_kms_impl_setup (MetaThreadImpl *thread_impl)
{
MetaThread *thread = meta_thread_impl_get_thread (thread_impl);
meta_thread_inhibit_realtime_in_impl (thread);
}
void
meta_kms_impl_notify_probed (MetaKmsImpl *impl)
{
MetaThreadImpl *thread_impl = META_THREAD_IMPL (impl);
MetaThread *thread = meta_thread_impl_get_thread (thread_impl);
meta_thread_uninhibit_realtime_in_impl (thread);
}
static void static void
meta_kms_impl_class_init (MetaKmsImplClass *klass) meta_kms_impl_class_init (MetaKmsImplClass *klass)
{ {
GObjectClass *object_class = G_OBJECT_CLASS (klass); GObjectClass *object_class = G_OBJECT_CLASS (klass);
MetaThreadImplClass *thread_impl_class = META_THREAD_IMPL_CLASS (klass);
object_class->finalize = meta_kms_impl_finalize; object_class->finalize = meta_kms_impl_finalize;
thread_impl_class->setup = meta_kms_impl_setup;
} }
MetaKmsUpdateFilter * MetaKmsUpdateFilter *

View file

@ -53,6 +53,8 @@ void meta_kms_impl_notify_modes_set (MetaKmsImpl *impl);
MetaKmsImpl * meta_kms_impl_new (MetaKms *kms); MetaKmsImpl * meta_kms_impl_new (MetaKms *kms);
void meta_kms_impl_notify_probed (MetaKmsImpl *impl);
MetaKmsUpdateFilter * meta_kms_impl_add_update_filter (MetaKmsImpl *impl, MetaKmsUpdateFilter * meta_kms_impl_add_update_filter (MetaKmsImpl *impl,
MetaKmsUpdateFilterFunc func, MetaKmsUpdateFilterFunc func,
gpointer user_data); gpointer user_data);

View file

@ -20,6 +20,8 @@
#include "backends/native/meta-kms-update.h" #include "backends/native/meta-kms-update.h"
#include "backends/native/meta-kms-update-private.h" #include "backends/native/meta-kms-update-private.h"
#include <glib/gstdio.h>
#include "backends/meta-display-config-shared.h" #include "backends/meta-display-config-shared.h"
#include "backends/native/meta-kms-connector.h" #include "backends/native/meta-kms-connector.h"
#include "backends/native/meta-kms-crtc.h" #include "backends/native/meta-kms-crtc.h"
@ -51,6 +53,8 @@ struct _MetaKmsUpdate
gboolean needs_modeset; gboolean needs_modeset;
MetaKmsImplDevice *impl_device; MetaKmsImplDevice *impl_device;
int sync_fd;
}; };
void void
@ -1136,6 +1140,8 @@ meta_kms_update_merge_from (MetaKmsUpdate *update,
merge_custom_page_flip_from (update, other_update); merge_custom_page_flip_from (update, other_update);
merge_page_flip_listeners_from (update, other_update); merge_page_flip_listeners_from (update, other_update);
merge_result_listeners_from (update, other_update); merge_result_listeners_from (update, other_update);
meta_kms_update_set_sync_fd (update, g_steal_fd (&other_update->sync_fd));
} }
gboolean gboolean
@ -1152,6 +1158,7 @@ meta_kms_update_new (MetaKmsDevice *device)
update = g_new0 (MetaKmsUpdate, 1); update = g_new0 (MetaKmsUpdate, 1);
update->device = device; update->device = device;
update->is_latchable = TRUE; update->is_latchable = TRUE;
update->sync_fd = -1;
return update; return update;
} }
@ -1175,6 +1182,7 @@ meta_kms_update_free (MetaKmsUpdate *update)
g_list_free_full (update->crtc_color_updates, g_list_free_full (update->crtc_color_updates,
(GDestroyNotify) meta_kms_crtc_color_updates_free); (GDestroyNotify) meta_kms_crtc_color_updates_free);
g_clear_pointer (&update->custom_page_flip, meta_kms_custom_page_flip_free); g_clear_pointer (&update->custom_page_flip, meta_kms_custom_page_flip_free);
g_clear_fd (&update->sync_fd, NULL);
g_free (update); g_free (update);
} }
@ -1200,6 +1208,23 @@ meta_kms_update_get_latch_crtc (MetaKmsUpdate *update)
return update->latch_crtc; return update->latch_crtc;
} }
int
meta_kms_update_get_sync_fd (MetaKmsUpdate *update)
{
return update->sync_fd;
}
void
meta_kms_update_set_sync_fd (MetaKmsUpdate *update,
int sync_fd)
{
if (update->sync_fd == sync_fd)
return;
g_clear_fd (&update->sync_fd, NULL);
update->sync_fd = sync_fd;
}
gboolean gboolean
meta_kms_update_is_empty (MetaKmsUpdate *update) meta_kms_update_is_empty (MetaKmsUpdate *update)
{ {
@ -1207,5 +1232,6 @@ meta_kms_update_is_empty (MetaKmsUpdate *update)
!update->plane_assignments && !update->plane_assignments &&
!update->connector_updates && !update->connector_updates &&
!update->crtc_updates && !update->crtc_updates &&
!update->crtc_color_updates); !update->crtc_color_updates &&
!update->custom_page_flip);
} }

View file

@ -39,7 +39,7 @@ typedef enum _MetaKmsAssignPlaneFlag
META_KMS_ASSIGN_PLANE_FLAG_NONE = 0, META_KMS_ASSIGN_PLANE_FLAG_NONE = 0,
META_KMS_ASSIGN_PLANE_FLAG_FB_UNCHANGED = 1 << 0, META_KMS_ASSIGN_PLANE_FLAG_FB_UNCHANGED = 1 << 0,
META_KMS_ASSIGN_PLANE_FLAG_ALLOW_FAIL = 1 << 1, META_KMS_ASSIGN_PLANE_FLAG_ALLOW_FAIL = 1 << 1,
META_KMS_ASSIGN_PLANE_FLAG_DIRECT_SCANOUT = 1 << 2, META_KMS_ASSIGN_PLANE_FLAG_DISABLE_IMPLICIT_SYNC = 1 << 2,
} MetaKmsAssignPlaneFlag; } MetaKmsAssignPlaneFlag;
struct _MetaKmsPageFlipListenerVtable struct _MetaKmsPageFlipListenerVtable
@ -157,6 +157,13 @@ void meta_kms_update_set_crtc_gamma (MetaKmsUpdate *update,
MetaKmsCrtc *crtc, MetaKmsCrtc *crtc,
const MetaGammaLut *gamma); const MetaGammaLut *gamma);
int
meta_kms_update_get_sync_fd (MetaKmsUpdate *update);
void
meta_kms_update_set_sync_fd (MetaKmsUpdate *update,
int sync_fd);
void meta_kms_plane_assignment_set_fb_damage (MetaKmsPlaneAssignment *plane_assignment, void meta_kms_plane_assignment_set_fb_damage (MetaKmsPlaneAssignment *plane_assignment,
const int *rectangles, const int *rectangles,
int n_rectangles); int n_rectangles);

View file

@ -413,6 +413,23 @@ meta_kms_new (MetaBackend *backend,
return kms; return kms;
} }
static gpointer
notify_probed_in_impl (MetaThreadImpl *thread_impl,
gpointer user_data,
GError **error)
{
meta_kms_impl_notify_probed (META_KMS_IMPL (thread_impl));
return NULL;
}
void
meta_kms_notify_probed (MetaKms *kms)
{
meta_thread_post_impl_task (META_THREAD (kms),
notify_probed_in_impl,
NULL, NULL, NULL, NULL);
}
static void static void
meta_kms_finalize (GObject *object) meta_kms_finalize (GObject *object)
{ {

View file

@ -64,6 +64,8 @@ MetaKms * meta_kms_new (MetaBackend *backend,
MetaKmsFlags flags, MetaKmsFlags flags,
GError **error); GError **error);
void meta_kms_notify_probed (MetaKms *kms);
META_EXPORT_TEST META_EXPORT_TEST
void meta_kms_inhibit_kernel_thread (MetaKms *kms); void meta_kms_inhibit_kernel_thread (MetaKms *kms);

View file

@ -29,6 +29,7 @@
#include "backends/native/meta-onscreen-native.h" #include "backends/native/meta-onscreen-native.h"
#include <glib/gstdio.h>
#include <drm_fourcc.h> #include <drm_fourcc.h>
#include "backends/meta-egl-ext.h" #include "backends/meta-egl-ext.h"
@ -102,12 +103,11 @@ struct _MetaOnscreenNative
MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state; MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state;
ClutterFrame *presented_frame;
ClutterFrame *next_frame;
struct { struct {
struct gbm_surface *surface; struct gbm_surface *surface;
MetaDrmBuffer *current_fb;
MetaDrmBuffer *next_fb;
CoglScanout *current_scanout;
CoglScanout *next_scanout;
} gbm; } gbm;
#ifdef HAVE_EGL_DEVICE #ifdef HAVE_EGL_DEVICE
@ -144,30 +144,17 @@ init_secondary_gpu_state (MetaRendererNative *renderer_native,
CoglOnscreen *onscreen, CoglOnscreen *onscreen,
GError **error); GError **error);
static void
free_current_bo (CoglOnscreen *onscreen)
{
MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen);
g_clear_object (&onscreen_native->gbm.current_fb);
g_clear_object (&onscreen_native->gbm.current_scanout);
}
static void static void
meta_onscreen_native_swap_drm_fb (CoglOnscreen *onscreen) meta_onscreen_native_swap_drm_fb (CoglOnscreen *onscreen)
{ {
MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen); MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen);
if (!onscreen_native->gbm.next_fb) if (!onscreen_native->next_frame)
return; return;
free_current_bo (onscreen); g_clear_pointer (&onscreen_native->presented_frame, clutter_frame_unref);
onscreen_native->presented_frame =
g_set_object (&onscreen_native->gbm.current_fb, onscreen_native->gbm.next_fb); g_steal_pointer (&onscreen_native->next_frame);
g_clear_object (&onscreen_native->gbm.next_fb);
g_set_object (&onscreen_native->gbm.current_scanout,
onscreen_native->gbm.next_scanout);
g_clear_object (&onscreen_native->gbm.next_scanout);
} }
static void static void
@ -175,8 +162,7 @@ meta_onscreen_native_clear_next_fb (CoglOnscreen *onscreen)
{ {
MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen); MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen);
g_clear_object (&onscreen_native->gbm.next_fb); g_clear_pointer (&onscreen_native->next_frame, clutter_frame_unref);
g_clear_object (&onscreen_native->gbm.next_scanout);
} }
static void static void
@ -311,7 +297,7 @@ page_flip_feedback_ready (MetaKmsCrtc *kms_crtc,
frame_info = cogl_onscreen_peek_head_frame_info (onscreen); frame_info = cogl_onscreen_peek_head_frame_info (onscreen);
frame_info->flags |= COGL_FRAME_INFO_FLAG_SYMBOLIC; frame_info->flags |= COGL_FRAME_INFO_FLAG_SYMBOLIC;
g_warn_if_fail (!onscreen_native->gbm.next_fb); g_warn_if_fail (!onscreen_native->next_frame);
meta_onscreen_native_notify_frame_complete (onscreen); meta_onscreen_native_notify_frame_complete (onscreen);
} }
@ -528,12 +514,15 @@ meta_onscreen_native_flip_crtc (CoglOnscreen *onscreen,
{ {
MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen); MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen);
MetaRendererNative *renderer_native = onscreen_native->renderer_native; MetaRendererNative *renderer_native = onscreen_native->renderer_native;
ClutterFrame *frame = onscreen_native->next_frame;
MetaFrameNative *frame_native;
MetaGpuKms *render_gpu = onscreen_native->render_gpu; MetaGpuKms *render_gpu = onscreen_native->render_gpu;
MetaCrtcKms *crtc_kms = META_CRTC_KMS (crtc); MetaCrtcKms *crtc_kms = META_CRTC_KMS (crtc);
MetaKmsCrtc *kms_crtc = meta_crtc_kms_get_kms_crtc (crtc_kms); MetaKmsCrtc *kms_crtc = meta_crtc_kms_get_kms_crtc (crtc_kms);
MetaRendererNativeGpuData *renderer_gpu_data; MetaRendererNativeGpuData *renderer_gpu_data;
MetaGpuKms *gpu_kms; MetaGpuKms *gpu_kms;
MetaDrmBuffer *buffer; MetaDrmBuffer *buffer;
CoglScanout *scanout;
MetaKmsPlaneAssignment *plane_assignment; MetaKmsPlaneAssignment *plane_assignment;
graphene_rect_t src_rect; graphene_rect_t src_rect;
MtkRectangle dst_rect; MtkRectangle dst_rect;
@ -541,6 +530,8 @@ meta_onscreen_native_flip_crtc (CoglOnscreen *onscreen,
COGL_TRACE_BEGIN_SCOPED (MetaOnscreenNativeFlipCrtcs, COGL_TRACE_BEGIN_SCOPED (MetaOnscreenNativeFlipCrtcs,
"Meta::OnscreenNative::flip_crtc()"); "Meta::OnscreenNative::flip_crtc()");
g_return_if_fail (frame);
gpu_kms = META_GPU_KMS (meta_crtc_get_gpu (crtc)); gpu_kms = META_GPU_KMS (meta_crtc_get_gpu (crtc));
g_assert (meta_gpu_kms_is_crtc_active (gpu_kms, crtc)); g_assert (meta_gpu_kms_is_crtc_active (gpu_kms, crtc));
@ -550,14 +541,14 @@ meta_onscreen_native_flip_crtc (CoglOnscreen *onscreen,
switch (renderer_gpu_data->mode) switch (renderer_gpu_data->mode)
{ {
case META_RENDERER_NATIVE_MODE_GBM: case META_RENDERER_NATIVE_MODE_GBM:
buffer = onscreen_native->gbm.next_fb; frame_native = meta_frame_native_from_frame (frame);
buffer = meta_frame_native_get_buffer (frame_native);
scanout = meta_frame_native_get_scanout (frame_native);
if (onscreen_native->gbm.next_scanout) if (scanout)
{ {
cogl_scanout_get_src_rect (onscreen_native->gbm.next_scanout, cogl_scanout_get_src_rect (scanout, &src_rect);
&src_rect); cogl_scanout_get_dst_rect (scanout, &dst_rect);
cogl_scanout_get_dst_rect (onscreen_native->gbm.next_scanout,
&dst_rect);
} }
else else
{ {
@ -593,6 +584,7 @@ meta_onscreen_native_flip_crtc (CoglOnscreen *onscreen,
break; break;
#ifdef HAVE_EGL_DEVICE #ifdef HAVE_EGL_DEVICE
case META_RENDERER_NATIVE_MODE_EGL_DEVICE: case META_RENDERER_NATIVE_MODE_EGL_DEVICE:
meta_kms_update_set_flushing (kms_update, kms_crtc);
meta_kms_update_set_custom_page_flip (kms_update, meta_kms_update_set_custom_page_flip (kms_update,
custom_egl_stream_page_flip, custom_egl_stream_page_flip,
onscreen_native); onscreen_native);
@ -848,29 +840,63 @@ import_shared_framebuffer (CoglOnscreen *onscreen,
} }
static MetaDrmBuffer * static MetaDrmBuffer *
copy_shared_framebuffer_gpu (CoglOnscreen *onscreen, copy_shared_framebuffer_gpu (CoglOnscreen *onscreen,
MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state, MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state,
MetaRendererNativeGpuData *renderer_gpu_data, MetaRendererNativeGpuData *renderer_gpu_data,
gboolean *egl_context_changed, MetaDrmBuffer *primary_gpu_fb,
MetaDrmBuffer *primary_gpu_fb) GError **error)
{ {
MetaRendererNative *renderer_native = renderer_gpu_data->renderer_native; MetaRendererNative *renderer_native = renderer_gpu_data->renderer_native;
MetaEgl *egl = meta_renderer_native_get_egl (renderer_native); MetaEgl *egl = meta_renderer_native_get_egl (renderer_native);
MetaGles3 *gles3 = meta_renderer_native_get_gles3 (renderer_native); MetaGles3 *gles3 = meta_renderer_native_get_gles3 (renderer_native);
CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
CoglContext *cogl_context = cogl_framebuffer_get_context (framebuffer);
CoglDisplay *cogl_display = cogl_context_get_display (cogl_context);
CoglRendererEGL *cogl_renderer_egl = cogl_context->display->renderer->winsys;
MetaRenderDevice *render_device; MetaRenderDevice *render_device;
EGLDisplay egl_display; EGLDisplay egl_display = NULL;
GError *error = NULL;
gboolean use_modifiers; gboolean use_modifiers;
MetaDeviceFile *device_file; MetaDeviceFile *device_file;
MetaDrmBufferFlags flags; MetaDrmBufferFlags flags;
MetaDrmBufferGbm *buffer_gbm; MetaDrmBufferGbm *buffer_gbm = NULL;
struct gbm_bo *bo; struct gbm_bo *bo;
EGLSync primary_gpu_egl_sync = EGL_NO_SYNC;
EGLSync secondary_gpu_egl_sync = EGL_NO_SYNC;
g_autofd int primary_gpu_sync_fence = EGL_NO_NATIVE_FENCE_FD_ANDROID;
COGL_TRACE_BEGIN_SCOPED (CopySharedFramebufferSecondaryGpu, COGL_TRACE_BEGIN_SCOPED (CopySharedFramebufferSecondaryGpu,
"copy_shared_framebuffer_gpu()"); "copy_shared_framebuffer_gpu()");
if (renderer_gpu_data->secondary.needs_explicit_sync) if (renderer_gpu_data->secondary.needs_explicit_sync)
cogl_framebuffer_finish (COGL_FRAMEBUFFER (onscreen)); {
if (!meta_egl_create_sync (egl,
cogl_renderer_egl->edpy,
EGL_SYNC_NATIVE_FENCE_ANDROID,
NULL,
&primary_gpu_egl_sync,
error))
{
g_prefix_error (error, "Failed to create EGLSync on primary GPU: ");
return NULL;
}
// According to the EGL_KHR_fence_sync specification we must ensure
// the fence command is flushed in this context to be able to await it
// in another (secondary GPU context) or we risk waiting indefinitely.
cogl_framebuffer_flush (COGL_FRAMEBUFFER (onscreen));
primary_gpu_sync_fence =
meta_egl_duplicate_native_fence_fd (egl,
cogl_renderer_egl->edpy,
primary_gpu_egl_sync,
error);
if (primary_gpu_sync_fence == EGL_NO_NATIVE_FENCE_FD_ANDROID)
{
g_prefix_error (error, "Failed to duplicate EGLSync FD on primary GPU: ");
goto done;
}
}
render_device = renderer_gpu_data->render_device; render_device = renderer_gpu_data->render_device;
egl_display = meta_render_device_get_egl_display (render_device); egl_display = meta_render_device_get_egl_display (render_device);
@ -880,15 +906,45 @@ copy_shared_framebuffer_gpu (CoglOnscreen *onscreen,
secondary_gpu_state->egl_surface, secondary_gpu_state->egl_surface,
secondary_gpu_state->egl_surface, secondary_gpu_state->egl_surface,
renderer_gpu_data->secondary.egl_context, renderer_gpu_data->secondary.egl_context,
&error)) error))
{ {
g_warning ("Failed to make current: %s", error->message); g_prefix_error (error, "Failed to make current: ");
g_error_free (error); goto done;
return NULL;
} }
*egl_context_changed = TRUE; if (primary_gpu_sync_fence != EGL_NO_NATIVE_FENCE_FD_ANDROID)
{
EGLAttrib attribs[3];
attribs[0] = EGL_SYNC_NATIVE_FENCE_FD_ANDROID;
attribs[1] = primary_gpu_sync_fence;
attribs[2] = EGL_NONE;
if (!meta_egl_create_sync (egl,
egl_display,
EGL_SYNC_NATIVE_FENCE_ANDROID,
attribs,
&secondary_gpu_egl_sync,
error))
{
g_prefix_error (error, "Failed to create EGLSync on secondary GPU: ");
goto done;
}
// eglCreateSync takes ownership of an existing fd that is passed, so
// don't try to clean it up twice.
primary_gpu_sync_fence = EGL_NO_NATIVE_FENCE_FD_ANDROID;
if (!meta_egl_wait_sync (egl,
egl_display,
secondary_gpu_egl_sync,
0,
error))
{
g_prefix_error (error, "Failed to wait for EGLSync on secondary GPU: ");
goto done;
}
}
buffer_gbm = META_DRM_BUFFER_GBM (primary_gpu_fb); buffer_gbm = META_DRM_BUFFER_GBM (primary_gpu_fb);
bo = meta_drm_buffer_gbm_get_bo (buffer_gbm); bo = meta_drm_buffer_gbm_get_bo (buffer_gbm);
@ -898,21 +954,19 @@ copy_shared_framebuffer_gpu (CoglOnscreen *onscreen,
renderer_gpu_data->secondary.egl_context, renderer_gpu_data->secondary.egl_context,
secondary_gpu_state->egl_surface, secondary_gpu_state->egl_surface,
bo, bo,
&error)) error))
{ {
g_warning ("Failed to blit shared framebuffer: %s", error->message); g_prefix_error (error, "Failed to blit shared framebuffer: ");
g_error_free (error); goto done;
return NULL;
} }
if (!meta_egl_swap_buffers (egl, if (!meta_egl_swap_buffers (egl,
egl_display, egl_display,
secondary_gpu_state->egl_surface, secondary_gpu_state->egl_surface,
&error)) error))
{ {
g_warning ("Failed to swap buffers: %s", error->message); g_prefix_error (error, "Failed to swap buffers: ");
g_error_free (error); goto done;
return NULL;
} }
use_modifiers = meta_renderer_native_use_modifiers (renderer_native); use_modifiers = meta_renderer_native_use_modifiers (renderer_native);
@ -926,13 +980,11 @@ copy_shared_framebuffer_gpu (CoglOnscreen *onscreen,
meta_drm_buffer_gbm_new_lock_front (device_file, meta_drm_buffer_gbm_new_lock_front (device_file,
secondary_gpu_state->gbm.surface, secondary_gpu_state->gbm.surface,
flags, flags,
&error); error);
if (!buffer_gbm) if (!buffer_gbm)
{ {
g_warning ("meta_drm_buffer_gbm_new_lock_front failed: %s", g_prefix_error (error, "meta_drm_buffer_gbm_new_lock_front failed: ");
error->message); goto done;
g_error_free (error);
return NULL;
} }
g_object_set_qdata_full (G_OBJECT (buffer_gbm), g_object_set_qdata_full (G_OBJECT (buffer_gbm),
@ -940,7 +992,24 @@ copy_shared_framebuffer_gpu (CoglOnscreen *onscreen,
g_object_ref (primary_gpu_fb), g_object_ref (primary_gpu_fb),
g_object_unref); g_object_unref);
return META_DRM_BUFFER (buffer_gbm); done:
_cogl_winsys_egl_ensure_current (cogl_display);
if (primary_gpu_egl_sync != EGL_NO_SYNC &&
!meta_egl_destroy_sync (egl,
cogl_renderer_egl->edpy,
primary_gpu_egl_sync,
error))
g_prefix_error (error, "Failed to destroy primary GPU EGLSync: ");
if (secondary_gpu_egl_sync != EGL_NO_SYNC &&
!meta_egl_destroy_sync (egl,
egl_display,
secondary_gpu_egl_sync,
error))
g_prefix_error (error, "Failed to destroy secondary GPU EGLSync: ");
return buffer_gbm ? META_DRM_BUFFER (buffer_gbm) : NULL;
} }
static MetaDrmBufferDumb * static MetaDrmBufferDumb *
@ -1192,56 +1261,54 @@ update_secondary_gpu_state_pre_swap_buffers (CoglOnscreen *onscreen,
return copy; return copy;
} }
static void static MetaDrmBuffer *
update_secondary_gpu_state_post_swap_buffers (CoglOnscreen *onscreen, acquire_front_buffer (CoglOnscreen *onscreen,
gboolean *egl_context_changed, MetaDrmBuffer *primary_gpu_fb,
MetaDrmBuffer *primary_gpu_fb, MetaDrmBuffer *secondary_gpu_fb,
MetaDrmBuffer **secondary_gpu_fb) GError **error)
{ {
MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen); MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen);
MetaRendererNative *renderer_native = onscreen_native->renderer_native; MetaRendererNative *renderer_native = onscreen_native->renderer_native;
MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state; MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state;
MetaRendererNativeGpuData *renderer_gpu_data;
MetaDrmBuffer *imported_fb;
COGL_TRACE_BEGIN_SCOPED (MetaRendererNativeGpuStatePostSwapBuffers, COGL_TRACE_BEGIN_SCOPED (MetaRendererNativeGpuStatePostSwapBuffers,
"update_secondary_gpu_state_post_swap_buffers()"); "acquire_front_buffer()");
secondary_gpu_state = onscreen_native->secondary_gpu_state; secondary_gpu_state = onscreen_native->secondary_gpu_state;
if (secondary_gpu_state) if (!secondary_gpu_state)
{ return g_object_ref (primary_gpu_fb);
MetaRendererNativeGpuData *renderer_gpu_data;
g_autoptr (MetaDrmBuffer) next_fb = NULL;
renderer_gpu_data = renderer_gpu_data =
meta_renderer_native_get_gpu_data (renderer_native, meta_renderer_native_get_gpu_data (renderer_native,
secondary_gpu_state->gpu_kms); secondary_gpu_state->gpu_kms);
switch (renderer_gpu_data->secondary.copy_mode) switch (renderer_gpu_data->secondary.copy_mode)
{ {
case META_SHARED_FRAMEBUFFER_COPY_MODE_ZERO: case META_SHARED_FRAMEBUFFER_COPY_MODE_ZERO:
next_fb = import_shared_framebuffer (onscreen, imported_fb = import_shared_framebuffer (onscreen,
secondary_gpu_state, secondary_gpu_state,
primary_gpu_fb); primary_gpu_fb);
if (next_fb) if (imported_fb)
break; return imported_fb;
/* The fallback was prepared in pre_swap_buffers and is currently /* The fallback was prepared in pre_swap_buffers and is currently
* in secondary_gpu_fb. * in secondary_gpu_fb.
*/ */
renderer_gpu_data->secondary.copy_mode = renderer_gpu_data->secondary.copy_mode =
META_SHARED_FRAMEBUFFER_COPY_MODE_PRIMARY; META_SHARED_FRAMEBUFFER_COPY_MODE_PRIMARY;
G_GNUC_FALLTHROUGH; G_GNUC_FALLTHROUGH;
case META_SHARED_FRAMEBUFFER_COPY_MODE_PRIMARY: case META_SHARED_FRAMEBUFFER_COPY_MODE_PRIMARY:
next_fb = g_object_ref (*secondary_gpu_fb); return g_object_ref (secondary_gpu_fb);
break; case META_SHARED_FRAMEBUFFER_COPY_MODE_SECONDARY_GPU:
case META_SHARED_FRAMEBUFFER_COPY_MODE_SECONDARY_GPU: return copy_shared_framebuffer_gpu (onscreen,
next_fb = copy_shared_framebuffer_gpu (onscreen, secondary_gpu_state,
secondary_gpu_state, renderer_gpu_data,
renderer_gpu_data, primary_gpu_fb,
egl_context_changed, error);
primary_gpu_fb);
break;
}
g_set_object (secondary_gpu_fb, next_fb);
} }
g_assert_not_reached ();
return NULL;
} }
static void static void
@ -1303,7 +1370,6 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen,
{ {
CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen); CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
CoglContext *cogl_context = cogl_framebuffer_get_context (framebuffer); CoglContext *cogl_context = cogl_framebuffer_get_context (framebuffer);
CoglDisplay *cogl_display = cogl_context_get_display (cogl_context);
CoglRenderer *cogl_renderer = cogl_context->display->renderer; CoglRenderer *cogl_renderer = cogl_context->display->renderer;
CoglRendererEGL *cogl_renderer_egl = cogl_renderer->winsys; CoglRendererEGL *cogl_renderer_egl = cogl_renderer->winsys;
MetaRendererNativeGpuData *renderer_gpu_data = cogl_renderer_egl->platform; MetaRendererNativeGpuData *renderer_gpu_data = cogl_renderer_egl->platform;
@ -1321,15 +1387,18 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen,
MetaKmsUpdate *kms_update; MetaKmsUpdate *kms_update;
CoglOnscreenClass *parent_class; CoglOnscreenClass *parent_class;
gboolean create_timestamp_query = TRUE; gboolean create_timestamp_query = TRUE;
gboolean egl_context_changed = FALSE;
MetaPowerSave power_save_mode; MetaPowerSave power_save_mode;
g_autoptr (GError) error = NULL; g_autoptr (GError) error = NULL;
MetaDrmBufferFlags buffer_flags; MetaDrmBufferFlags buffer_flags;
MetaDrmBufferGbm *buffer_gbm; MetaDrmBufferGbm *buffer_gbm;
g_autoptr (MetaDrmBuffer) primary_gpu_fb = NULL; g_autoptr (MetaDrmBuffer) primary_gpu_fb = NULL;
g_autoptr (MetaDrmBuffer) secondary_gpu_fb = NULL; g_autoptr (MetaDrmBuffer) secondary_gpu_fb = NULL;
g_autoptr (MetaDrmBuffer) buffer = NULL;
MetaKmsCrtc *kms_crtc; MetaKmsCrtc *kms_crtc;
MetaKmsDevice *kms_device; MetaKmsDevice *kms_device;
int sync_fd;
COGL_TRACE_SCOPED_ANCHOR (MetaRendererNativePostKmsUpdate);
COGL_TRACE_BEGIN_SCOPED (MetaRendererNativeSwapBuffers, COGL_TRACE_BEGIN_SCOPED (MetaRendererNativeSwapBuffers,
"Meta::OnscreenNative::swap_buffers_with_damage()"); "Meta::OnscreenNative::swap_buffers_with_damage()");
@ -1383,46 +1452,28 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen,
g_warning ("Failed to lock front buffer on %s: %s", g_warning ("Failed to lock front buffer on %s: %s",
meta_device_file_get_path (render_device_file), meta_device_file_get_path (render_device_file),
error->message); error->message);
goto swap_failed;
frame_info->flags |= COGL_FRAME_INFO_FLAG_SYMBOLIC;
meta_onscreen_native_notify_frame_complete (onscreen);
return;
} }
primary_gpu_fb = META_DRM_BUFFER (g_steal_pointer (&buffer_gbm)); primary_gpu_fb = META_DRM_BUFFER (g_steal_pointer (&buffer_gbm));
break; buffer = acquire_front_buffer (onscreen,
case META_RENDERER_NATIVE_MODE_SURFACELESS: primary_gpu_fb,
g_assert_not_reached (); secondary_gpu_fb,
break; &error);
#ifdef HAVE_EGL_DEVICE if (buffer == NULL)
case META_RENDERER_NATIVE_MODE_EGL_DEVICE: {
break; g_warning ("Failed to acquire front buffer: %s", error->message);
#endif goto swap_failed;
} }
update_secondary_gpu_state_post_swap_buffers (onscreen, meta_frame_native_set_buffer (frame_native, buffer);
&egl_context_changed,
primary_gpu_fb,
&secondary_gpu_fb);
switch (renderer_gpu_data->mode) if (!meta_drm_buffer_ensure_fb_id (buffer, &error))
{
case META_RENDERER_NATIVE_MODE_GBM:
g_warn_if_fail (onscreen_native->gbm.next_fb == NULL);
if (onscreen_native->secondary_gpu_state)
g_set_object (&onscreen_native->gbm.next_fb, secondary_gpu_fb);
else
g_set_object (&onscreen_native->gbm.next_fb, primary_gpu_fb);
if (!meta_drm_buffer_ensure_fb_id (onscreen_native->gbm.next_fb, &error))
{ {
g_warning ("Failed to ensure KMS FB ID on %s: %s", g_warning ("Failed to ensure KMS FB ID on %s: %s",
meta_device_file_get_path (render_device_file), meta_device_file_get_path (render_device_file),
error->message); error->message);
goto swap_failed;
frame_info->flags |= COGL_FRAME_INFO_FLAG_SYMBOLIC;
meta_onscreen_native_notify_frame_complete (onscreen);
return;
} }
break; break;
case META_RENDERER_NATIVE_MODE_SURFACELESS: case META_RENDERER_NATIVE_MODE_SURFACELESS:
@ -1433,14 +1484,8 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen,
#endif #endif
} }
/* g_warn_if_fail (!onscreen_native->next_frame);
* If we changed EGL context, cogl will have the wrong idea about what is onscreen_native->next_frame = clutter_frame_ref (frame);
* current, making it fail to set it when it needs to. Avoid that by making
* EGL_NO_CONTEXT current now, making cogl eventually set the correct
* context.
*/
if (egl_context_changed)
_cogl_winsys_egl_ensure_current (cogl_display);
kms_crtc = meta_crtc_kms_get_kms_crtc (META_CRTC_KMS (onscreen_native->crtc)); kms_crtc = meta_crtc_kms_get_kms_crtc (META_CRTC_KMS (onscreen_native->crtc));
kms_device = meta_kms_crtc_get_device (kms_crtc); kms_device = meta_kms_crtc_get_device (kms_crtc);
@ -1474,8 +1519,8 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen,
return; return;
} }
COGL_TRACE_BEGIN_SCOPED (MetaRendererNativePostKmsUpdate, COGL_TRACE_BEGIN_ANCHORED (MetaRendererNativePostKmsUpdate,
"Meta::OnscreenNative::swap_buffers_with_damage#post_pending_update()"); "Meta::OnscreenNative::swap_buffers_with_damage#post_pending_update()");
switch (renderer_gpu_data->mode) switch (renderer_gpu_data->mode)
{ {
@ -1536,9 +1581,17 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen,
meta_kms_device_get_path (kms_device)); meta_kms_device_get_path (kms_device));
kms_update = meta_frame_native_steal_kms_update (frame_native); kms_update = meta_frame_native_steal_kms_update (frame_native);
sync_fd = cogl_context_get_latest_sync_fd (cogl_context);
meta_kms_update_set_sync_fd (kms_update, sync_fd);
meta_kms_device_post_update (kms_device, kms_update, meta_kms_device_post_update (kms_device, kms_update,
META_KMS_UPDATE_FLAG_NONE); META_KMS_UPDATE_FLAG_NONE);
clutter_frame_set_result (frame, CLUTTER_FRAME_RESULT_PENDING_PRESENTED); clutter_frame_set_result (frame, CLUTTER_FRAME_RESULT_PENDING_PRESENTED);
return;
swap_failed:
frame_info->flags |= COGL_FRAME_INFO_FLAG_SYMBOLIC;
meta_onscreen_native_notify_frame_complete (onscreen);
clutter_frame_set_result (frame, CLUTTER_FRAME_RESULT_IDLE);
} }
gboolean gboolean
@ -1571,7 +1624,7 @@ meta_onscreen_native_is_buffer_scanout_compatible (CoglOnscreen *onscreen,
assign_primary_plane (crtc_kms, assign_primary_plane (crtc_kms,
buffer, buffer,
test_update, test_update,
META_KMS_ASSIGN_PLANE_FLAG_DIRECT_SCANOUT, META_KMS_ASSIGN_PLANE_FLAG_DISABLE_IMPLICIT_SYNC,
&src_rect, &src_rect,
&dst_rect); &dst_rect);
@ -1606,11 +1659,15 @@ scanout_result_feedback (const MetaKmsFeedback *kms_feedback,
G_IO_ERROR_PERMISSION_DENIED)) G_IO_ERROR_PERMISSION_DENIED))
{ {
ClutterStageView *view = CLUTTER_STAGE_VIEW (onscreen_native->view); ClutterStageView *view = CLUTTER_STAGE_VIEW (onscreen_native->view);
ClutterFrame *next_frame = onscreen_native->next_frame;
MetaFrameNative *next_frame_native =
meta_frame_native_from_frame (next_frame);
CoglScanout *scanout =
meta_frame_native_get_scanout (next_frame_native);
g_warning ("Direct scanout page flip failed: %s", error->message); g_warning ("Direct scanout page flip failed: %s", error->message);
cogl_scanout_notify_failed (onscreen_native->gbm.next_scanout, cogl_scanout_notify_failed (scanout, onscreen);
onscreen);
clutter_stage_view_add_redraw_clip (view, NULL); clutter_stage_view_add_redraw_clip (view, NULL);
clutter_stage_view_schedule_update_now (view); clutter_stage_view_schedule_update_now (view);
} }
@ -1675,12 +1732,13 @@ meta_onscreen_native_direct_scanout (CoglOnscreen *onscreen,
render_gpu); render_gpu);
g_warn_if_fail (renderer_gpu_data->mode == META_RENDERER_NATIVE_MODE_GBM); g_warn_if_fail (renderer_gpu_data->mode == META_RENDERER_NATIVE_MODE_GBM);
g_warn_if_fail (!onscreen_native->gbm.next_fb);
g_warn_if_fail (!onscreen_native->gbm.next_scanout);
g_set_object (&onscreen_native->gbm.next_scanout, scanout); g_warn_if_fail (!onscreen_native->next_frame);
g_set_object (&onscreen_native->gbm.next_fb, onscreen_native->next_frame = clutter_frame_ref (frame);
META_DRM_BUFFER (cogl_scanout_get_buffer (scanout)));
meta_frame_native_set_scanout (frame_native, scanout);
meta_frame_native_set_buffer (frame_native,
META_DRM_BUFFER (cogl_scanout_get_buffer (scanout)));
frame_info->cpu_time_before_buffer_swap_us = g_get_monotonic_time (); frame_info->cpu_time_before_buffer_swap_us = g_get_monotonic_time ();
@ -1701,7 +1759,7 @@ meta_onscreen_native_direct_scanout (CoglOnscreen *onscreen,
onscreen_native->view, onscreen_native->view,
onscreen_native->crtc, onscreen_native->crtc,
kms_update, kms_update,
META_KMS_ASSIGN_PLANE_FLAG_DIRECT_SCANOUT, META_KMS_ASSIGN_PLANE_FLAG_DISABLE_IMPLICIT_SYNC,
NULL, NULL,
0); 0);
@ -1786,11 +1844,15 @@ meta_onscreen_native_before_redraw (CoglOnscreen *onscreen,
ClutterFrame *frame) ClutterFrame *frame)
{ {
MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen); MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen);
MetaCrtcKms *crtc_kms = META_CRTC_KMS (onscreen_native->crtc);
MetaKmsCrtc *kms_crtc = meta_crtc_kms_get_kms_crtc (crtc_kms);
meta_kms_device_await_flush (meta_kms_crtc_get_device (kms_crtc), if (meta_get_debug_paint_flags () & META_DEBUG_PAINT_SYNC_CURSOR_PRIMARY)
kms_crtc); {
MetaCrtcKms *crtc_kms = META_CRTC_KMS (onscreen_native->crtc);
MetaKmsCrtc *kms_crtc = meta_crtc_kms_get_kms_crtc (crtc_kms);
meta_kms_device_await_flush (meta_kms_crtc_get_device (kms_crtc), kms_crtc);
}
maybe_update_frame_sync (onscreen_native, frame); maybe_update_frame_sync (onscreen_native, frame);
} }
@ -2043,8 +2105,8 @@ get_supported_egl_modifiers (CoglOnscreen *onscreen,
MetaRenderDevice *render_device; MetaRenderDevice *render_device;
EGLDisplay egl_display; EGLDisplay egl_display;
EGLint num_modifiers; EGLint num_modifiers;
GArray *modifiers; g_autofree EGLuint64KHR *modifiers = NULL;
GError *error = NULL; g_autoptr (GError) error = NULL;
gboolean ret; gboolean ret;
gpu = meta_crtc_get_gpu (META_CRTC (crtc_kms)); gpu = meta_crtc_get_gpu (META_CRTC (crtc_kms));
@ -2064,22 +2126,20 @@ get_supported_egl_modifiers (CoglOnscreen *onscreen,
if (!ret || num_modifiers == 0) if (!ret || num_modifiers == 0)
return NULL; return NULL;
modifiers = g_array_sized_new (FALSE, FALSE, sizeof (uint64_t), modifiers = g_new (typeof (*modifiers), num_modifiers);
num_modifiers);
ret = meta_egl_query_dma_buf_modifiers (egl, egl_display, ret = meta_egl_query_dma_buf_modifiers (egl, egl_display,
format, num_modifiers, format, num_modifiers,
(EGLuint64KHR *) modifiers->data, NULL, modifiers, NULL,
&num_modifiers, &error); &num_modifiers, &error);
if (!ret) if (!ret)
{ {
g_warning ("Failed to query DMABUF modifiers: %s", error->message); g_warning ("Failed to query DMABUF modifiers: %s", error->message);
g_error_free (error);
g_array_free (modifiers, TRUE);
return NULL; return NULL;
} }
return modifiers; return g_array_new_take (g_steal_pointer (&modifiers), num_modifiers, FALSE,
sizeof (*modifiers));
} }
static GArray * static GArray *
@ -2126,7 +2186,6 @@ choose_onscreen_egl_config (CoglOnscreen *onscreen,
MetaCrtcKms *crtc_kms = META_CRTC_KMS (onscreen_native->crtc); MetaCrtcKms *crtc_kms = META_CRTC_KMS (onscreen_native->crtc);
MetaKmsPlane *kms_plane = meta_crtc_kms_get_assigned_primary_plane (crtc_kms); MetaKmsPlane *kms_plane = meta_crtc_kms_get_assigned_primary_plane (crtc_kms);
EGLint attrs[MAX_EGL_CONFIG_ATTRIBS]; EGLint attrs[MAX_EGL_CONFIG_ATTRIBS];
g_autoptr (GError) local_error = NULL;
static const uint32_t alphaless_10bpc_formats[] = { static const uint32_t alphaless_10bpc_formats[] = {
GBM_FORMAT_XRGB2101010, GBM_FORMAT_XRGB2101010,
GBM_FORMAT_XBGR2101010, GBM_FORMAT_XBGR2101010,
@ -2865,15 +2924,15 @@ meta_onscreen_native_dispose (GObject *object)
meta_onscreen_native_detach (onscreen_native); meta_onscreen_native_detach (onscreen_native);
g_clear_pointer (&onscreen_native->next_frame, clutter_frame_unref);
g_clear_pointer (&onscreen_native->presented_frame, clutter_frame_unref);
renderer_gpu_data = renderer_gpu_data =
meta_renderer_native_get_gpu_data (renderer_native, meta_renderer_native_get_gpu_data (renderer_native,
onscreen_native->render_gpu); onscreen_native->render_gpu);
switch (renderer_gpu_data->mode) switch (renderer_gpu_data->mode)
{ {
case META_RENDERER_NATIVE_MODE_GBM: case META_RENDERER_NATIVE_MODE_GBM:
g_clear_object (&onscreen_native->gbm.next_fb);
g_clear_object (&onscreen_native->gbm.next_scanout);
free_current_bo (onscreen);
break; break;
case META_RENDERER_NATIVE_MODE_SURFACELESS: case META_RENDERER_NATIVE_MODE_SURFACELESS:
g_assert_not_reached (); g_assert_not_reached ();

View file

@ -2172,7 +2172,6 @@ meta_renderer_native_unset_modes (MetaRendererNative *renderer_native)
MetaKmsDevice *kms_device = MetaKmsDevice *kms_device =
meta_gpu_kms_get_kms_device (META_GPU_KMS (gpu)); meta_gpu_kms_get_kms_device (META_GPU_KMS (gpu));
GList *k; GList *k;
g_autoptr (MetaKmsFeedback) kms_feedback = NULL;
MetaKmsUpdate *kms_update = NULL; MetaKmsUpdate *kms_update = NULL;
for (k = meta_gpu_get_crtcs (gpu); k; k = k->next) for (k = meta_gpu_get_crtcs (gpu); k; k = k->next)

View file

@ -24,6 +24,7 @@
#include "backends/native/meta-renderer-view-native.h" #include "backends/native/meta-renderer-view-native.h"
#include "backends/native/meta-crtc-native.h"
#include "backends/native/meta-frame-native.h" #include "backends/native/meta-frame-native.h"
struct _MetaRendererViewNative struct _MetaRendererViewNative
@ -34,18 +35,58 @@ struct _MetaRendererViewNative
G_DEFINE_TYPE (MetaRendererViewNative, meta_renderer_view_native, G_DEFINE_TYPE (MetaRendererViewNative, meta_renderer_view_native,
META_TYPE_RENDERER_VIEW) META_TYPE_RENDERER_VIEW)
static void
update_frame_clock_deadline_evasion (MetaRendererView *renderer_view)
{
ClutterStageView *stage_view = CLUTTER_STAGE_VIEW (renderer_view);
ClutterFrameClock *frame_clock;
MetaCrtc *crtc;
MetaCrtcNative *crtc_native;
int64_t deadline_evasion_us;
frame_clock = clutter_stage_view_get_frame_clock (stage_view);
crtc = meta_renderer_view_get_crtc (renderer_view);
crtc_native = META_CRTC_NATIVE (crtc);
deadline_evasion_us = meta_crtc_native_get_deadline_evasion (crtc_native);
clutter_frame_clock_set_deadline_evasion (frame_clock,
deadline_evasion_us);
}
static void
meta_renderer_view_native_constructed (GObject *object)
{
MetaRendererView *renderer_view = META_RENDERER_VIEW (object);
G_OBJECT_CLASS (meta_renderer_view_native_parent_class)->constructed (object);
update_frame_clock_deadline_evasion (renderer_view);
}
static ClutterFrame * static ClutterFrame *
meta_renderer_view_native_new_frame (ClutterStageView *stage_view) meta_renderer_view_native_new_frame (ClutterStageView *stage_view)
{ {
return (ClutterFrame *) meta_frame_native_new (); return (ClutterFrame *) meta_frame_native_new ();
} }
static void
meta_renderer_view_native_schedule_update (ClutterStageView *stage_view)
{
MetaRendererView *renderer_view = META_RENDERER_VIEW (stage_view);
update_frame_clock_deadline_evasion (renderer_view);
}
static void static void
meta_renderer_view_native_class_init (MetaRendererViewNativeClass *klass) meta_renderer_view_native_class_init (MetaRendererViewNativeClass *klass)
{ {
GObjectClass *object_class = G_OBJECT_CLASS (klass);
ClutterStageViewClass *stage_view_class = CLUTTER_STAGE_VIEW_CLASS (klass); ClutterStageViewClass *stage_view_class = CLUTTER_STAGE_VIEW_CLASS (klass);
object_class->constructed = meta_renderer_view_native_constructed;
stage_view_class->new_frame = meta_renderer_view_native_new_frame; stage_view_class->new_frame = meta_renderer_view_native_new_frame;
stage_view_class->schedule_update = meta_renderer_view_native_schedule_update;
} }
static void static void

View file

@ -568,6 +568,15 @@ meta_thread_impl_dispatch (MetaThreadImpl *thread_impl)
return 1; return 1;
} }
void
meta_thread_impl_setup (MetaThreadImpl *thread_impl)
{
MetaThreadImplClass *klass = META_THREAD_IMPL_GET_CLASS (thread_impl);
if (klass->setup)
klass->setup (thread_impl);
}
void void
meta_thread_impl_run (MetaThreadImpl *thread_impl, meta_thread_impl_run (MetaThreadImpl *thread_impl,
MetaThreadImplRunFlags flags) MetaThreadImplRunFlags flags)

View file

@ -38,6 +38,8 @@ G_DECLARE_DERIVABLE_TYPE (MetaThreadImpl, meta_thread_impl,
struct _MetaThreadImplClass struct _MetaThreadImplClass
{ {
GObjectClass parent_class; GObjectClass parent_class;
void (* setup) (MetaThreadImpl *thread_impl);
}; };
typedef enum _MetaThreadTaskFeedbackType typedef enum _MetaThreadTaskFeedbackType
@ -70,6 +72,8 @@ void meta_thread_impl_queue_task (MetaThreadImpl *thread_impl,
void meta_thread_impl_terminate (MetaThreadImpl *thread_impl); void meta_thread_impl_terminate (MetaThreadImpl *thread_impl);
void meta_thread_impl_setup (MetaThreadImpl *thread_impl);
void meta_thread_impl_run (MetaThreadImpl *thread_impl, void meta_thread_impl_run (MetaThreadImpl *thread_impl,
MetaThreadImplRunFlags flags); MetaThreadImplRunFlags flags);

View file

@ -333,22 +333,28 @@ request_normal_scheduling (MetaThread *thread,
} }
static gboolean static gboolean
should_use_realtime_scheduling_in_impl (MetaThread *thread) can_use_realtime_scheduling_in_impl (MetaThread *thread)
{ {
MetaThreadPrivate *priv = meta_thread_get_instance_private (thread); MetaThreadPrivate *priv = meta_thread_get_instance_private (thread);
gboolean should_use_realtime_scheduling = FALSE;
switch (priv->thread_type) switch (priv->thread_type)
{ {
case META_THREAD_TYPE_USER: case META_THREAD_TYPE_USER:
break; return FALSE;
case META_THREAD_TYPE_KERNEL: case META_THREAD_TYPE_KERNEL:
if (priv->wants_realtime && priv->kernel.realtime_inhibit_count == 0) return priv->wants_realtime;
should_use_realtime_scheduling = TRUE;
break;
} }
return should_use_realtime_scheduling; g_assert_not_reached ();
}
static gboolean
should_use_realtime_scheduling_in_impl (MetaThread *thread)
{
MetaThreadPrivate *priv = meta_thread_get_instance_private (thread);
return (can_use_realtime_scheduling_in_impl (thread) &&
priv->kernel.realtime_inhibit_count == 0);
} }
static void static void
@ -417,11 +423,13 @@ thread_impl_func (gpointer user_data)
priv->kernel.realtime_inhibit_count = 0; priv->kernel.realtime_inhibit_count = 0;
priv->kernel.is_realtime = FALSE; priv->kernel.is_realtime = FALSE;
meta_thread_impl_setup (impl);
sync_realtime_scheduling_in_impl (thread); sync_realtime_scheduling_in_impl (thread);
if (priv->kernel.is_realtime) if (can_use_realtime_scheduling_in_impl (thread))
{ {
g_message ("Made thread '%s' realtime scheduled", priv->name); g_message ("Thread '%s' will be using real time scheduling", priv->name);
run_flags |= META_THREAD_IMPL_RUN_FLAG_REALTIME; run_flags |= META_THREAD_IMPL_RUN_FLAG_REALTIME;
} }
@ -765,7 +773,6 @@ meta_thread_reset_thread_type (MetaThread *thread,
MetaThreadType thread_type) MetaThreadType thread_type)
{ {
MetaThreadPrivate *priv = meta_thread_get_instance_private (thread); MetaThreadPrivate *priv = meta_thread_get_instance_private (thread);
g_autoptr (GMainContext) thread_context = NULL;
if (priv->thread_type == thread_type) if (priv->thread_type == thread_type)
return; return;

View file

@ -1838,6 +1838,7 @@ meta_window_drag_begin (MetaWindowDrag *window_drag,
stage = meta_backend_get_stage (backend); stage = meta_backend_get_stage (backend);
window_drag->handler = clutter_actor_new (); window_drag->handler = clutter_actor_new ();
clutter_actor_hide (window_drag->handler);
clutter_actor_set_name (window_drag->handler, clutter_actor_set_name (window_drag->handler,
"Window drag helper"); "Window drag helper");
g_signal_connect_swapped (window_drag->handler, "event", g_signal_connect_swapped (window_drag->handler, "event",

View file

@ -69,6 +69,7 @@ static const GDebugKey meta_debug_keys[] = {
{ "color", META_DEBUG_COLOR }, { "color", META_DEBUG_COLOR },
{ "input-events", META_DEBUG_INPUT_EVENTS }, { "input-events", META_DEBUG_INPUT_EVENTS },
{ "eis", META_DEBUG_EIS }, { "eis", META_DEBUG_EIS },
{ "kms-deadline", META_DEBUG_KMS_DEADLINE },
}; };
static gint verbose_topics = 0; static gint verbose_topics = 0;
@ -326,6 +327,8 @@ meta_topic_to_string (MetaDebugTopic topic)
return "INPUT_EVENTS"; return "INPUT_EVENTS";
case META_DEBUG_EIS: case META_DEBUG_EIS:
return "EIS"; return "EIS";
case META_DEBUG_KMS_DEADLINE:
return "KMS_DEADLINE";
} }
return "WM"; return "WM";

View file

@ -6851,7 +6851,6 @@ meta_window_get_unit_cgroup (MetaWindow *window)
g_autofree char *contents = NULL; g_autofree char *contents = NULL;
g_autofree char *complete_path = NULL; g_autofree char *complete_path = NULL;
g_autofree char *unit_name = NULL; g_autofree char *unit_name = NULL;
g_autofree char *unit_path = NULL;
char *unit_end; char *unit_end;
pid_t pid; pid_t pid;

View file

@ -50,6 +50,7 @@
* @META_DEBUG_COLOR: color management * @META_DEBUG_COLOR: color management
* @META_DEBUG_INPUT_EVENTS: input events * @META_DEBUG_INPUT_EVENTS: input events
* @META_DEBUG_EIS: eis state * @META_DEBUG_EIS: eis state
* @META_DEBUG_KMS_DEADLINE: KMS deadline timers
*/ */
typedef enum typedef enum
{ {
@ -83,6 +84,7 @@ typedef enum
META_DEBUG_COLOR = 1 << 26, META_DEBUG_COLOR = 1 << 26,
META_DEBUG_INPUT_EVENTS = 1 << 27, META_DEBUG_INPUT_EVENTS = 1 << 27,
META_DEBUG_EIS = 1 << 28, META_DEBUG_EIS = 1 << 28,
META_DEBUG_KMS_DEADLINE = 1 << 29,
} MetaDebugTopic; } MetaDebugTopic;
META_EXPORT META_EXPORT

View file

@ -51,11 +51,14 @@ void meta_fatal (const char *format,
* MetaDebugPaintFlag: * MetaDebugPaintFlag:
* @META_DEBUG_PAINT_NONE: default * @META_DEBUG_PAINT_NONE: default
* @META_DEBUG_PAINT_OPAQUE_REGION: paint opaque regions * @META_DEBUG_PAINT_OPAQUE_REGION: paint opaque regions
* @META_DEBUG_PAINT_SYNC_CURSOR_PRIMARY: make cursor updates await compositing
* frames
*/ */
typedef enum typedef enum
{ {
META_DEBUG_PAINT_NONE = 0, META_DEBUG_PAINT_NONE = 0,
META_DEBUG_PAINT_OPAQUE_REGION = 1 << 0, META_DEBUG_PAINT_OPAQUE_REGION = 1 << 0,
META_DEBUG_PAINT_SYNC_CURSOR_PRIMARY = 1 << 1,
} MetaDebugPaintFlag; } MetaDebugPaintFlag;
META_EXPORT META_EXPORT

View file

@ -35,7 +35,6 @@ get_colord_mock_proxy (void)
{ {
GDBusProxy *proxy; GDBusProxy *proxy;
g_autoptr (GError) error = NULL; g_autoptr (GError) error = NULL;
g_autoptr (GVariant) ret = NULL;
proxy = proxy =
g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,

View file

@ -126,7 +126,6 @@ get_colord_mock_proxy (void)
{ {
GDBusProxy *proxy; GDBusProxy *proxy;
g_autoptr (GError) error = NULL; g_autoptr (GError) error = NULL;
g_autoptr (GVariant) ret = NULL;
proxy = proxy =
g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
@ -259,7 +258,6 @@ get_gsd_color_mock_proxy (void)
{ {
GDBusProxy *proxy; GDBusProxy *proxy;
g_autoptr (GError) error = NULL; g_autoptr (GError) error = NULL;
g_autoptr (GVariant) ret = NULL;
proxy = proxy =
g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION, g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,

View file

@ -318,7 +318,6 @@ meta_test_input_capture_clear_barriers (void)
MetaBackend *backend = meta_context_get_backend (test_context); MetaBackend *backend = meta_context_get_backend (test_context);
ClutterSeat *seat = meta_backend_get_default_seat (backend); ClutterSeat *seat = meta_backend_get_default_seat (backend);
g_autoptr (MetaVirtualMonitor) virtual_monitor1 = NULL; g_autoptr (MetaVirtualMonitor) virtual_monitor1 = NULL;
g_autoptr (MetaVirtualMonitor) virtual_monitor2 = NULL;
g_autoptr (ClutterVirtualInputDevice) virtual_pointer = NULL; g_autoptr (ClutterVirtualInputDevice) virtual_pointer = NULL;
InputCaptureTestClient *test_client; InputCaptureTestClient *test_client;
@ -436,7 +435,6 @@ meta_test_input_capture_events (void)
MetaBackend *backend = meta_context_get_backend (test_context); MetaBackend *backend = meta_context_get_backend (test_context);
ClutterSeat *seat = meta_backend_get_default_seat (backend); ClutterSeat *seat = meta_backend_get_default_seat (backend);
g_autoptr (MetaVirtualMonitor) virtual_monitor1 = NULL; g_autoptr (MetaVirtualMonitor) virtual_monitor1 = NULL;
g_autoptr (MetaVirtualMonitor) virtual_monitor2 = NULL;
g_autoptr (ClutterVirtualInputDevice) virtual_pointer = NULL; g_autoptr (ClutterVirtualInputDevice) virtual_pointer = NULL;
g_autoptr (ClutterVirtualInputDevice) virtual_keyboard = NULL; g_autoptr (ClutterVirtualInputDevice) virtual_keyboard = NULL;
InputCaptureTestClient *test_client; InputCaptureTestClient *test_client;
@ -595,7 +593,6 @@ main (int argc,
char **argv) char **argv)
{ {
g_autoptr (MetaContext) context = NULL; g_autoptr (MetaContext) context = NULL;
g_autoptr (GError) error = NULL;
g_assert_cmpstr (getenv ("GSETTINGS_BACKEND"), ==, "memory"); g_assert_cmpstr (getenv ("GSETTINGS_BACKEND"), ==, "memory");

View file

@ -100,7 +100,6 @@ meta_backend_test_add_test_device (MetaBackendTest *backend_test,
ClutterInputDeviceType device_type, ClutterInputDeviceType device_type,
int n_buttons) int n_buttons)
{ {
g_autoptr (GList) devices = NULL;
MetaBackend *backend = META_BACKEND (backend_test); MetaBackend *backend = META_BACKEND (backend_test);
ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend); ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
ClutterSeat *seat = clutter_backend_get_default_seat (clutter_backend); ClutterSeat *seat = clutter_backend_get_default_seat (clutter_backend);

View file

@ -517,6 +517,12 @@ meta_crtc_test_set_gamma_lut (MetaCrtc *crtc,
sizeof (uint16_t) * lut->size); sizeof (uint16_t) * lut->size);
} }
static int64_t
meta_crtc_test_get_deadline_evasion (MetaCrtcNative *crtc_native)
{
return 0;
}
static void static void
meta_crtc_test_finalize (GObject *object) meta_crtc_test_finalize (GObject *object)
{ {

View file

@ -1147,7 +1147,6 @@ assert_realtime (MetaThreadImpl *thread_impl,
GError **error) GError **error)
{ {
g_autoptr (GVariant) ret = NULL; g_autoptr (GVariant) ret = NULL;
g_autoptr (GVariant) priority_variant = NULL;
uint32_t priority = 0; uint32_t priority = 0;
g_assert_true (meta_thread_impl_is_realtime (thread_impl)); g_assert_true (meta_thread_impl_is_realtime (thread_impl));
@ -1196,7 +1195,6 @@ assert_no_realtime (MetaThreadImpl *thread_impl,
GError **error) GError **error)
{ {
g_autoptr (GVariant) ret = NULL; g_autoptr (GVariant) ret = NULL;
g_autoptr (GVariant) priority_variant = NULL;
uint32_t priority = UINT32_MAX; uint32_t priority = UINT32_MAX;
g_assert_false (meta_thread_impl_is_realtime (thread_impl)); g_assert_false (meta_thread_impl_is_realtime (thread_impl));

View file

@ -93,7 +93,6 @@ main (int argc,
char **argv) char **argv)
{ {
g_autoptr (MetaContext) context = NULL; g_autoptr (MetaContext) context = NULL;
g_autoptr (GError) error = NULL;
context = meta_create_test_context (META_CONTEXT_TEST_TYPE_HEADLESS, context = meta_create_test_context (META_CONTEXT_TEST_TYPE_HEADLESS,
META_CONTEXT_TEST_FLAG_NO_X11); META_CONTEXT_TEST_FLAG_NO_X11);

View file

@ -168,7 +168,6 @@ main (int argc,
char **argv) char **argv)
{ {
g_autoptr (MetaContext) context = NULL; g_autoptr (MetaContext) context = NULL;
g_autoptr (GError) error = NULL;
context = meta_create_test_context (META_CONTEXT_TEST_TYPE_HEADLESS, context = meta_create_test_context (META_CONTEXT_TEST_TYPE_HEADLESS,
META_CONTEXT_TEST_FLAG_NO_X11); META_CONTEXT_TEST_FLAG_NO_X11);

View file

@ -275,7 +275,6 @@ main (int argc,
char **argv) char **argv)
{ {
g_autoptr (MetaContext) context = NULL; g_autoptr (MetaContext) context = NULL;
g_autoptr (GError) error = NULL;
context = meta_create_test_context (META_CONTEXT_TEST_TYPE_HEADLESS, context = meta_create_test_context (META_CONTEXT_TEST_TYPE_HEADLESS,
META_CONTEXT_TEST_FLAG_TEST_CLIENT); META_CONTEXT_TEST_FLAG_TEST_CLIENT);

View file

@ -320,7 +320,6 @@ main (int argc,
char **argv) char **argv)
{ {
g_autoptr (MetaContext) context = NULL; g_autoptr (MetaContext) context = NULL;
g_autoptr (GError) error = NULL;
context = test_context = context = test_context =
meta_create_test_context (META_CONTEXT_TEST_TYPE_HEADLESS, meta_create_test_context (META_CONTEXT_TEST_TYPE_HEADLESS,

View file

@ -175,7 +175,6 @@ primary_device_set_selection (struct wl_client *client,
uint32_t serial) uint32_t serial)
{ {
MetaWaylandDataDevicePrimary *data_device = wl_resource_get_user_data (resource); MetaWaylandDataDevicePrimary *data_device = wl_resource_get_user_data (resource);
MetaWaylandSeat *seat = wl_container_of (data_device, seat, primary_data_device);
MetaWaylandDataSource *source = NULL; MetaWaylandDataSource *source = NULL;
if (source_resource) if (source_resource)
@ -343,7 +342,6 @@ void
meta_wayland_data_device_primary_set_focus (MetaWaylandDataDevicePrimary *data_device, meta_wayland_data_device_primary_set_focus (MetaWaylandDataDevicePrimary *data_device,
MetaWaylandSurface *surface) MetaWaylandSurface *surface)
{ {
MetaWaylandSeat *seat = wl_container_of (data_device, seat, primary_data_device);
struct wl_client *focus_client = NULL; struct wl_client *focus_client = NULL;
struct wl_resource *data_device_resource; struct wl_resource *data_device_resource;

View file

@ -1048,7 +1048,6 @@ data_device_set_selection (struct wl_client *client,
uint32_t serial) uint32_t serial)
{ {
MetaWaylandDataDevice *data_device = wl_resource_get_user_data (resource); MetaWaylandDataDevice *data_device = wl_resource_get_user_data (resource);
MetaWaylandSeat *seat = wl_container_of (data_device, seat, data_device);
MetaWaylandDataSource *source; MetaWaylandDataSource *source;
if (source_resource) if (source_resource)
@ -1250,7 +1249,6 @@ void
meta_wayland_data_device_set_focus (MetaWaylandDataDevice *data_device, meta_wayland_data_device_set_focus (MetaWaylandDataDevice *data_device,
MetaWaylandSurface *surface) MetaWaylandSurface *surface)
{ {
MetaWaylandSeat *seat = wl_container_of (data_device, seat, data_device);
struct wl_client *focus_client = NULL; struct wl_client *focus_client = NULL;
struct wl_resource *data_device_resource; struct wl_resource *data_device_resource;

View file

@ -48,6 +48,12 @@ struct _MetaWaylandInput
ClutterGrab *grab; ClutterGrab *grab;
}; };
typedef enum
{
INVALIDATE_FOCUS_FLAG_DEFAULT = 0,
INVALIDATE_FOCUS_FLAG_CANCEL_TOUCH = 1 << 0,
} InvalidateFocusFlag;
static void meta_wayland_input_sync_focus (MetaWaylandInput *input); static void meta_wayland_input_sync_focus (MetaWaylandInput *input);
G_DEFINE_FINAL_TYPE (MetaWaylandInput, meta_wayland_input, G_TYPE_OBJECT) G_DEFINE_FINAL_TYPE (MetaWaylandInput, meta_wayland_input, G_TYPE_OBJECT)
@ -137,7 +143,8 @@ meta_wayland_event_handler_invalidate_focus (MetaWaylandEventHandler *handler,
} }
static void static void
meta_wayland_input_invalidate_all_focus (MetaWaylandInput *input) meta_wayland_input_invalidate_all_focus (MetaWaylandInput *input,
InvalidateFocusFlag flags)
{ {
MetaWaylandEventHandler *handler; MetaWaylandEventHandler *handler;
MetaWaylandSeat *seat = input->seat; MetaWaylandSeat *seat = input->seat;
@ -161,7 +168,8 @@ meta_wayland_input_invalidate_all_focus (MetaWaylandInput *input)
meta_wayland_event_handler_invalidate_focus (handler, device, NULL); meta_wayland_event_handler_invalidate_focus (handler, device, NULL);
} }
if (meta_wayland_seat_has_touch (seat)) if (meta_wayland_seat_has_touch (seat) &&
(flags & INVALIDATE_FOCUS_FLAG_CANCEL_TOUCH) != 0)
meta_wayland_touch_cancel (seat->touch); meta_wayland_touch_cancel (seat->touch);
g_hash_table_iter_init (&iter, seat->tablet_seat->tablets); g_hash_table_iter_init (&iter, seat->tablet_seat->tablets);
@ -257,7 +265,8 @@ meta_wayland_input_sync_focus (MetaWaylandInput *input)
g_assert (!wl_list_empty (&input->event_handler_list)); g_assert (!wl_list_empty (&input->event_handler_list));
handler = wl_container_of (input->event_handler_list.next, handler, link); handler = wl_container_of (input->event_handler_list.next, handler, link);
meta_wayland_input_invalidate_all_focus (input); meta_wayland_input_invalidate_all_focus (input,
INVALIDATE_FOCUS_FLAG_CANCEL_TOUCH);
} }
static void static void
@ -310,7 +319,8 @@ meta_wayland_input_attach_event_handler (MetaWaylandInput *input,
input); input);
} }
meta_wayland_input_invalidate_all_focus (input); meta_wayland_input_invalidate_all_focus (input,
INVALIDATE_FOCUS_FLAG_DEFAULT);
return handler; return handler;
} }
@ -337,13 +347,8 @@ meta_wayland_input_detach_event_handler (MetaWaylandInput *input,
wl_list_remove (&handler->link); wl_list_remove (&handler->link);
if (handler_change && !wl_list_empty (&input->event_handler_list)) if (handler_change && !wl_list_empty (&input->event_handler_list))
{ meta_wayland_input_invalidate_all_focus (input,
MetaWaylandEventHandler *head = INVALIDATE_FOCUS_FLAG_DEFAULT);
wl_container_of (input->event_handler_list.next,
head, link);
meta_wayland_input_invalidate_all_focus (input);
}
if (input->grab && !should_be_grabbed (input)) if (input->grab && !should_be_grabbed (input))
{ {

View file

@ -56,8 +56,6 @@ struct _MetaWaylandPopupGrab
MetaWaylandSeat *seat; MetaWaylandSeat *seat;
MetaWaylandEventHandler *handler; MetaWaylandEventHandler *handler;
int press_count;
struct wl_client *grab_client; struct wl_client *grab_client;
struct wl_list all_popups; struct wl_list all_popups;
}; };
@ -118,12 +116,15 @@ popup_grab_get_focus_surface (MetaWaylandEventHandler *handler,
} }
else else
{ {
MetaWaylandInput *input = meta_wayland_seat_get_input (popup_grab->seat);
surface = meta_wayland_event_handler_chain_up_get_focus_surface (handler, surface = meta_wayland_event_handler_chain_up_get_focus_surface (handler,
device, device,
sequence); sequence);
if (surface && surface->resource && if (!meta_wayland_input_is_current_handler (input, handler) ||
wl_resource_get_client (surface->resource) == popup_grab->grab_client) (surface && surface->resource &&
wl_resource_get_client (surface->resource) == popup_grab->grab_client))
return surface; return surface;
} }
@ -140,18 +141,6 @@ popup_grab_focus (MetaWaylandEventHandler *handler,
meta_wayland_event_handler_chain_up_focus (handler, device, sequence, surface); meta_wayland_event_handler_chain_up_focus (handler, device, sequence, surface);
} }
static gboolean
popup_grab_press (MetaWaylandEventHandler *handler,
const ClutterEvent *event,
gpointer user_data)
{
MetaWaylandPopupGrab *popup_grab = user_data;
popup_grab->press_count++;
return CLUTTER_EVENT_PROPAGATE;
}
static gboolean static gboolean
popup_grab_release (MetaWaylandEventHandler *handler, popup_grab_release (MetaWaylandEventHandler *handler,
const ClutterEvent *event, const ClutterEvent *event,
@ -162,9 +151,12 @@ popup_grab_release (MetaWaylandEventHandler *handler,
ClutterEventSequence *sequence = clutter_event_get_event_sequence (event); ClutterEventSequence *sequence = clutter_event_get_event_sequence (event);
gboolean close_popup; gboolean close_popup;
close_popup = popup_grab->press_count == 1; close_popup = __builtin_popcount (clutter_event_get_state (event) &
(CLUTTER_BUTTON1_MASK |
popup_grab->press_count = MAX (0, popup_grab->press_count - 1); CLUTTER_BUTTON2_MASK |
CLUTTER_BUTTON3_MASK |
CLUTTER_BUTTON4_MASK |
CLUTTER_BUTTON5_MASK)) <= 1;
if (close_popup) if (close_popup)
{ {
@ -188,7 +180,7 @@ static MetaWaylandEventInterface popup_event_interface = {
popup_grab_get_focus_surface, popup_grab_get_focus_surface,
popup_grab_focus, popup_grab_focus,
NULL, /* motion */ NULL, /* motion */
popup_grab_press, NULL, /* press */
popup_grab_release, popup_grab_release,
}; };

View file

@ -215,6 +215,9 @@ default_focus (MetaWaylandEventHandler *handler,
MetaWaylandSeat *seat = user_data; MetaWaylandSeat *seat = user_data;
ClutterInputCapabilities caps; ClutterInputCapabilities caps;
if (sequence)
return;
caps = clutter_input_device_get_capabilities (device); caps = clutter_input_device_get_capabilities (device);
if (caps & if (caps &
@ -432,12 +435,24 @@ meta_wayland_seat_update (MetaWaylandSeat *seat,
switch (clutter_event_type (event)) switch (clutter_event_type (event))
{ {
case CLUTTER_ENTER:
case CLUTTER_LEAVE:
if (clutter_event_get_event_sequence (event))
{
if (meta_wayland_seat_has_touch (seat))
meta_wayland_touch_update (seat->touch, event);
}
else
{
if (meta_wayland_seat_has_pointer (seat))
meta_wayland_pointer_update (seat->pointer, event);
}
break;
case CLUTTER_MOTION: case CLUTTER_MOTION:
case CLUTTER_BUTTON_PRESS: case CLUTTER_BUTTON_PRESS:
case CLUTTER_BUTTON_RELEASE: case CLUTTER_BUTTON_RELEASE:
case CLUTTER_SCROLL: case CLUTTER_SCROLL:
case CLUTTER_ENTER:
case CLUTTER_LEAVE:
if (meta_wayland_seat_has_pointer (seat)) if (meta_wayland_seat_has_pointer (seat))
meta_wayland_pointer_update (seat->pointer, event); meta_wayland_pointer_update (seat->pointer, event);
break; break;

View file

@ -356,7 +356,6 @@ meta_wayland_tablet_seat_lookup_pad (MetaWaylandTabletSeat *tablet_seat,
static MetaWaylandTabletTool * static MetaWaylandTabletTool *
meta_wayland_tablet_seat_ensure_tool (MetaWaylandTabletSeat *tablet_seat, meta_wayland_tablet_seat_ensure_tool (MetaWaylandTabletSeat *tablet_seat,
ClutterInputDevice *device,
ClutterInputDeviceTool *device_tool) ClutterInputDeviceTool *device_tool)
{ {
MetaWaylandTabletTool *tool; MetaWaylandTabletTool *tool;
@ -365,7 +364,7 @@ meta_wayland_tablet_seat_ensure_tool (MetaWaylandTabletSeat *tablet_seat,
if (!tool) if (!tool)
{ {
tool = meta_wayland_tablet_tool_new (tablet_seat, device, device_tool); tool = meta_wayland_tablet_tool_new (tablet_seat, device_tool);
g_hash_table_insert (tablet_seat->tools, device_tool, tool); g_hash_table_insert (tablet_seat->tools, device_tool, tool);
} }
@ -393,7 +392,7 @@ meta_wayland_tablet_seat_update (MetaWaylandTabletSeat *tablet_seat,
device_tool = clutter_event_get_device_tool (event); device_tool = clutter_event_get_device_tool (event);
if (device && device_tool) if (device && device_tool)
tool = meta_wayland_tablet_seat_ensure_tool (tablet_seat, device, device_tool); tool = meta_wayland_tablet_seat_ensure_tool (tablet_seat, device_tool);
if (!tool) if (!tool)
return; return;
@ -448,6 +447,8 @@ meta_wayland_tablet_seat_handle_event (MetaWaylandTabletSeat *tablet_seat,
return CLUTTER_EVENT_PROPAGATE; return CLUTTER_EVENT_PROPAGATE;
return meta_wayland_tablet_pad_handle_event (pad, event); return meta_wayland_tablet_pad_handle_event (pad, event);
case CLUTTER_DEVICE_REMOVED:
return CLUTTER_EVENT_PROPAGATE;
default: default:
return CLUTTER_EVENT_STOP; return CLUTTER_EVENT_STOP;
} }

View file

@ -41,7 +41,6 @@
struct _MetaWaylandTabletTool struct _MetaWaylandTabletTool
{ {
MetaWaylandTabletSeat *seat; MetaWaylandTabletSeat *seat;
ClutterInputDevice *device;
ClutterInputDeviceTool *device_tool; ClutterInputDeviceTool *device_tool;
struct wl_list resource_list; struct wl_list resource_list;
struct wl_list focus_resource_list; struct wl_list focus_resource_list;
@ -424,7 +423,6 @@ tool_cursor_prepare_at (MetaCursorSpriteXcursor *sprite_xcursor,
MetaWaylandTabletTool * MetaWaylandTabletTool *
meta_wayland_tablet_tool_new (MetaWaylandTabletSeat *seat, meta_wayland_tablet_tool_new (MetaWaylandTabletSeat *seat,
ClutterInputDevice *device,
ClutterInputDeviceTool *device_tool) ClutterInputDeviceTool *device_tool)
{ {
MetaWaylandCompositor *compositor = MetaWaylandCompositor *compositor =
@ -436,7 +434,6 @@ meta_wayland_tablet_tool_new (MetaWaylandTabletSeat *seat,
tool = g_new0 (MetaWaylandTabletTool, 1); tool = g_new0 (MetaWaylandTabletTool, 1);
tool->seat = seat; tool->seat = seat;
tool->device = device;
tool->device_tool = device_tool; tool->device_tool = device_tool;
wl_list_init (&tool->resource_list); wl_list_init (&tool->resource_list);
wl_list_init (&tool->focus_resource_list); wl_list_init (&tool->focus_resource_list);
@ -635,7 +632,8 @@ meta_wayland_tablet_tool_set_current_surface (MetaWaylandTabletTool *tool,
tablet_seat = tool->seat; tablet_seat = tool->seat;
input = meta_wayland_seat_get_input (tablet_seat->seat); input = meta_wayland_seat_get_input (tablet_seat->seat);
meta_wayland_input_invalidate_focus (input, tool->device, NULL); if (tool->current_tablet)
meta_wayland_input_invalidate_focus (input, tool->current_tablet->device, NULL);
} }
static void static void
@ -920,6 +918,7 @@ meta_wayland_tablet_tool_update (MetaWaylandTabletTool *tool,
break; break;
case CLUTTER_PROXIMITY_OUT: case CLUTTER_PROXIMITY_OUT:
tool->current_tablet = NULL; tool->current_tablet = NULL;
meta_wayland_tablet_tool_set_current_surface (tool, NULL);
meta_wayland_tablet_tool_set_cursor_surface (tool, NULL); meta_wayland_tablet_tool_set_cursor_surface (tool, NULL);
meta_wayland_tablet_tool_update_cursor_surface (tool); meta_wayland_tablet_tool_update_cursor_surface (tool);
g_clear_object (&tool->cursor_renderer); g_clear_object (&tool->cursor_renderer);
@ -1002,7 +1001,7 @@ meta_wayland_tablet_tool_get_grab_info (MetaWaylandTabletTool *tool,
meta_wayland_tablet_tool_can_grab_surface (tool, surface, serial)) meta_wayland_tablet_tool_can_grab_surface (tool, surface, serial))
{ {
if (device_out) if (device_out)
*device_out = tool->device; *device_out = tool->current_tablet ? NULL : tool->current_tablet->device;
if (x) if (x)
*x = tool->grab_x; *x = tool->grab_x;

View file

@ -29,7 +29,6 @@
#include "wayland/meta-wayland-types.h" #include "wayland/meta-wayland-types.h"
MetaWaylandTabletTool * meta_wayland_tablet_tool_new (MetaWaylandTabletSeat *seat, MetaWaylandTabletTool * meta_wayland_tablet_tool_new (MetaWaylandTabletSeat *seat,
ClutterInputDevice *device,
ClutterInputDeviceTool *device_tool); ClutterInputDeviceTool *device_tool);
void meta_wayland_tablet_tool_free (MetaWaylandTabletTool *tool); void meta_wayland_tablet_tool_free (MetaWaylandTabletTool *tool);

View file

@ -226,7 +226,7 @@ meta_wayland_touch_update (MetaWaylandTouch *touch,
sequence = clutter_event_get_event_sequence (event); sequence = clutter_event_get_event_sequence (event);
event_type = clutter_event_type (event); event_type = clutter_event_type (event);
if (event_type == CLUTTER_TOUCH_BEGIN) if (event_type == CLUTTER_ENTER)
{ {
MetaWaylandSurface *surface = NULL; MetaWaylandSurface *surface = NULL;
MetaBackend *backend; MetaBackend *backend;
@ -256,7 +256,8 @@ meta_wayland_touch_update (MetaWaylandTouch *touch,
if (!touch_info) if (!touch_info)
return; return;
if (event_type != CLUTTER_TOUCH_BEGIN && if ((event_type == CLUTTER_TOUCH_UPDATE ||
event_type == CLUTTER_TOUCH_END) &&
!touch_info->begin_delivered) !touch_info->begin_delivered)
{ {
g_hash_table_remove (touch->touches, sequence); g_hash_table_remove (touch->touches, sequence);