Skip to content

Commit 120ade8

Browse files
authored
[Wayland] Direct scanout (#744)
* wayland/surface: Put buffer reference on heap Currently a buffer use count always reaches zero before it is replaced. This is due to the fact that at the point a new buffer is attached, the last potential user releases it (the stage) since the currently displayed frame has a composited copy of the buffer. This may however change, if a buffer is scanned out directly, meaning it should not be released until the page flip callback is invoked. Prepare for this by making the buffer reference a heap allocated struct, enabling us to keep a pointer to it longer than the buffer is attached. Original Mutter commit: https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/798/diffs?commit_id=47002bf0cd9983cb5e45121d566d203baef71103 * drm-buffer/gbm: Support both surface and standalone buffers Surface buffers are created with meta_drm_buffer_new_acquire(), taking a gbm_surface acquiring the gbm itself, and meta_drm_buffer_new_take() that takes over ownership of a passed gbm_bo. Original Mutter commit: https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/798/diffs?commit_id=282aada13a5d744dd29eedf3255b6a9f6d0e370c * window/x11: Use G_DECLARE_DERIVABLE_TYPE() This removes the MetaWindowX11::priv pointer. It is replaced with a meta_window_x11_get_private() helper function, and another method to get the client rect without going through MetaWindowX11Private. * surface-actor-x11: Move window related unredirect logic to MetaWindowX11 Better to have the relevant object figure out whether it is a good position to be unredirectable other than the actor, which should be responsible for being composited. Original Mutter commit: https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/798/diffs?commit_id=5dad87cfb9058a0be96d9ec1a530e09a6d418a6e * clutter/actor: Add semi-private API to check for transitions Transitions are used for animating actors when e.g. going from/to fullscreen, and the like. We need to know such things when deciding whether to avoid compositing a window actor, so make add API visible to mutter that checks whether there are any transitions active. Original Mutter commit: https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/798/diffs?commit_id=bc178b711ffbd8db0b7cfecefb6f67edf4e0254f * wayland: Make MetaWaylandBufferRef reference counted So that we can have a more dynamic ownership. Original Mutter commit: https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/798/diffs?commit_id=f36120757f4de3eead9245335bc497c596ed88df * wayland/buffer-ref: Add helpers for use count tracking Original Mutter commit: https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/798/diffs?commit_id=f8ee974628504e5ca917cf03a9effdd810629332 * cogl/onscreen: Add API to scanout a buffer directly Instead of always swapping buffers and flipping the back buffer, make it possible to scan out a provided buffer directly without swapping any EGL buffers. A buffer is passed as an object implementing the empty CoglScanout interface. It is only possible to do this in the native backend; and the interface is implemented by MetaDrmBufferGbm. When directly scanned out, instead of calling gbm_surface_lock_front_buffer() to get the gbm_bo and fbid, get it directly from the MetaDrmBufferGbm, and use that to create the page flip KMS update. Original Mutter commit: https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/798/diffs?commit_id=3da8c1bfdc1fa486111c1e1dff363fb931612468 * clutter/view: Make it possible to assign a temporary direct scanout Make it possible to cause the next frame to scan out directly from the passed CoglScannout. This makes it possible to completely bypass compositing for the following frame. Original Mutter commit: https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/798/diffs?commit_id=753066598ff83fa9bdbd1be23d1e22663ae59297 * renderer/native: Add API to get primary GPU Will be used when acquiring scanouts from Wayland buffers. Original Mutter commit: https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/798/diffs?commit_id=3dd8861fbf51183fd69106f55095d444cd37cc34 * onscreen/native: Add API to check whether buffer is scanout compatible While this is fairly incomplete, as to check things fully we need to use TEST_ONLY in atomic to try out a complete assignment on the device, but this works well enough for legacy non-modifier cases. Original Mutter commit: https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/798/diffs?commit_id=b9fe9c736a3b7ef298bda5f785938275805a47f0 * wayland/dma-buf: Don't advertise modifier support by default Advertising support for modifiers means we will most likely not not be able to scan out client buffers directly, meaning it just as likely that we won't be able to scan out even fullscreen windows without atomic KMS. When we have atomic support, we should advertise support for modifiers if atomic is used to drive the CRTCs, as we by then can check whether we can scan out directly, place in an overlay plane, etc. Original Mutter commit: https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/798/diffs?commit_id=cb05b164140dc6934ff5a00cb4354a5dbf4593ef * wayland/dma-buf: Handle getting dma-buf from detached buffer handle We might still have a MetaWaylandBuffer for a wl_buffer that was destroyed. Handle trying to fetch the MetaWaylandDmaBufBuffer from such a buffer gracefully. Original Mutter commit: https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/798/diffs?commit_id=4b1805c3065eea293aefb1e3d1dc0ba685bcc1fc * wayland: Add API to acquire a CoglScanout from a surface This will check whether the current backing buffer is compatible with the primary plane of the passed CoglOnscreen. Since this will extend the time before a buffer is released, the MetaWaylandBufferRef is swapped and orphaned if a new buffer is committed before the previous one was released. It'll eventually be released, usually by the next page flip callback. Currently implemented for EGLImage and DMA-BUF buffer types. Original Mutter commit: https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/798/diffs?commit_id=ff7a42b8bc25c24d3e0fc0a277b1d628f5ea599a * util: Move MetaLater to its own file While at it, fix some style inconsistencies, for now use a single singleton struct instead of multiple static variables, and other non-functional cleanups. Semantically, there is no changes introduced. Original Mutter commit: https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/798/diffs?commit_id=d682cdb078f281b03084e3e0d7ab40d3ea382c1f * display: Initialize MetaCompositor in two steps MetaCompositor is the place in muffin that manages the higher level state of compositing, such as handling what happens before and after paint. In order for other units that depend on having a compositor instance active, but should be initialized before the X11 implementation of MetaCompositor registers as a X11 compositing manager, split the initialization of compositing into two steps: 1) Instantiate the object - only construct the instance, making it possible for users to start listening to signals etc 2) Manage - this e.g. establishes the compositor as the X11 compositing manager and similar things. This will enable us to put compositing dependent scattered global variables into a MetaCompositor owned object. For now, compositor management is internally done by calling a new `meta_compositor_do_manage()`, as right now we can't change the API of `meta_compositor_manage()` as it is public. For the next version, manual management of compositing will removed from the public API, and only managed internally. Original Mutter commit: https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/798/diffs?commit_id=dc4fe780f790c8fbd3624a7e75fd25c9a3918d0b * later: Make MetaCompositor the owner of the MetaLaters state Since the order of destruction during MetaDisplay tear down is a bit unordered, there are pieces that try to destruct its compositing dependent pieces (i.e. queued MetaLater callbacks) after MetaCompositor has been cleaned up, meaning we need to put some slightly awkward NULL checks to avoid crashing. Original Mutter commit: https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/798/diffs?commit_id=2e7d02f1ce8cb8eba15968c7facd815a7ce43080 * later: Listen to MetaCompositor signal instead of clutter We need to coordinate with MetaCompositor during pre-paint so that we have control over whether MetaLater callbacks happen first, or the MetaCompositor pre-paint logic. In order to do so, make MetaLater listen to a new signal "pre-paint" on MetaCompositor, that is called MetaCompositors own pre-paint handling. This fixes an issue where the top window actor was calculated after the MetaCompositor pre-paint handling, meaning the top actor being painted was out-of-date. Original Mutter commit: https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/798/diffs?commit_id=b51c468c0facc3be5df597a6fe0c8c35b95a1fff * compositor: Add support for direct scanout of Wayland surfaces Try to bypass compositing if there is a fullscreen toplevel window with a buffer compatible with the primary plane of the monitor it is fullscreen on. Only non-mirrored is currently supported; as well as fullscreened on a single monitor. It should be possible to extend with more cases, but this starts small. It does this by introducing a new MetaCompositor sub type MetaCompositorNative specific to the native backend, which derives from MetaCompositorServer, containing functionality only relevant for when running on top of the native backend. Original Mutter commit: https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/798/diffs?commit_id=65a6c4c361b7dad10b19f9bcabdcf7b576d7daa0 * debian: update symbols for libmuffin0 * Fix build * Fix build * wayland/dma-buf: Handle failing to import scanout DMA buffer * Use custom page flip function when retrying failed flips When using its EGLStream-based presentation path with the proprietary NVIDIA driver, mutter will use a different function to process page flips - custom_egl_stream_page_flip. If that fails due to an EBUSY error, it will attempt to retry the flip. However, when retrying, it unconditionally uses the libdrm-based path. In practice, this causes a segfault when attempting to access plane_assignments->fb_id, since plane_assignments will be NULL in the EGLStream case. This patch has muffin also use the custom page flip function when retrying the failed flip. * backends: force enable modifiers on tagged devices Some devices can't scanout to linear buffers directly as the hw is not capable of eg rendering into a linear depth buffer. Add code to force kms-modifiers on udev taged devices. * add missing systemd-dev dependency * compositor/native: fix parent class
1 parent 0ef3a81 commit 120ade8

68 files changed

Lines changed: 1772 additions & 587 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

clutter/clutter/clutter-actor.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20020,6 +20020,23 @@ clutter_actor_get_transition (ClutterActor *self,
2002020020
return clos->transition;
2002120021
}
2002220022

20023+
/**
20024+
* clutter_actor_has_transitions: (skip)
20025+
*/
20026+
gboolean
20027+
clutter_actor_has_transitions (ClutterActor *self)
20028+
{
20029+
const ClutterAnimationInfo *info;
20030+
20031+
g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
20032+
20033+
info = _clutter_actor_get_animation_info_or_defaults (self);
20034+
if (info->transitions == NULL)
20035+
return FALSE;
20036+
20037+
return g_hash_table_size (info->transitions) > 0;
20038+
}
20039+
2002320040
/**
2002420041
* clutter_actor_save_easing_state:
2002520042
* @self: a #ClutterActor

clutter/clutter/clutter-muffin.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,10 @@ void clutter_stage_thaw_updates (ClutterStage *stage);
7575
CLUTTER_EXPORT
7676
void clutter_stage_update_resource_scales (ClutterStage *stage);
7777

78+
CLUTTER_EXPORT
79+
void clutter_stage_view_assign_next_scanout (ClutterStageView *stage_view,
80+
CoglScanout *scanout);
81+
7882
CLUTTER_EXPORT
7983
gboolean clutter_actor_has_damage (ClutterActor *actor);
8084

@@ -83,6 +87,10 @@ void clutter_stage_get_device_coords (ClutterStage *stage,
8387
ClutterInputDevice *device,
8488
ClutterEventSequence *sequence,
8589
graphene_point_t *coords);
90+
91+
CLUTTER_EXPORT
92+
gboolean clutter_actor_has_transitions (ClutterActor *actor);
93+
8694
#undef __CLUTTER_H_INSIDE__
8795

8896
#endif /* __CLUTTER_MUFFIN_H__ */

clutter/clutter/clutter-stage-view-private.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,11 +54,12 @@ const cairo_region_t * clutter_stage_view_peek_redraw_clip (ClutterStageView *vi
5454

5555
cairo_region_t * clutter_stage_view_take_redraw_clip (ClutterStageView *view);
5656

57-
5857
void clutter_stage_view_transform_rect_to_onscreen (ClutterStageView *view,
5958
const cairo_rectangle_int_t *src_rect,
6059
int dst_width,
6160
int dst_height,
6261
cairo_rectangle_int_t *dst_rect);
6362

63+
CoglScanout * clutter_stage_view_take_scanout (ClutterStageView *view);
64+
6465
#endif /* __CLUTTER_STAGE_VIEW_PRIVATE_H__ */

clutter/clutter/clutter-stage-view.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525

2626
#include "clutter/clutter-damage-history.h"
2727
#include "clutter/clutter-private.h"
28+
#include "clutter/clutter-muffin.h"
29+
#include "cogl/cogl.h"
2830

2931
enum
3032
{
@@ -64,6 +66,8 @@ typedef struct _ClutterStageViewPrivate
6466
CoglOffscreen *framebuffer;
6567
} shadow;
6668

69+
CoglScanout *next_scanout;
70+
6771
gboolean has_redraw_clip;
6872
cairo_region_t *redraw_clip;
6973

@@ -923,6 +927,25 @@ clutter_stage_default_get_offscreen_transformation_matrix (ClutterStageView *vie
923927
cogl_matrix_init_identity (matrix);
924928
}
925929

930+
void
931+
clutter_stage_view_assign_next_scanout (ClutterStageView *view,
932+
CoglScanout *scanout)
933+
{
934+
ClutterStageViewPrivate *priv =
935+
clutter_stage_view_get_instance_private (view);
936+
937+
g_set_object (&priv->next_scanout, scanout);
938+
}
939+
940+
CoglScanout *
941+
clutter_stage_view_take_scanout (ClutterStageView *view)
942+
{
943+
ClutterStageViewPrivate *priv =
944+
clutter_stage_view_get_instance_private (view);
945+
946+
return g_steal_pointer (&priv->next_scanout);
947+
}
948+
926949
static void
927950
clutter_stage_view_get_property (GObject *object,
928951
guint prop_id,

clutter/clutter/cogl/clutter-stage-cogl.c

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -793,6 +793,20 @@ clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window,
793793
return res;
794794
}
795795

796+
static void
797+
clutter_stage_cogl_scanout_view (ClutterStageCogl *stage_cogl,
798+
ClutterStageView *view,
799+
CoglScanout *scanout)
800+
{
801+
CoglFramebuffer *framebuffer = clutter_stage_view_get_framebuffer (view);
802+
CoglOnscreen *onscreen;
803+
804+
g_return_if_fail (cogl_is_onscreen (framebuffer));
805+
806+
onscreen = COGL_ONSCREEN (framebuffer);
807+
cogl_onscreen_direct_scanout (onscreen, scanout);
808+
}
809+
796810
static void
797811
clutter_stage_cogl_redraw (ClutterStageWindow *stage_window)
798812
{
@@ -820,11 +834,23 @@ clutter_stage_cogl_redraw (ClutterStageWindow *stage_window)
820834
for (l = _clutter_stage_window_get_views (stage_window); l; l = l->next)
821835
{
822836
ClutterStageView *view = l->data;
837+
g_autoptr (CoglScanout) scanout = NULL;
823838

824839
if (!clutter_stage_view_has_redraw_clip (view))
825840
continue;
826841

827-
swap_event |= clutter_stage_cogl_redraw_view (stage_window, view);
842+
scanout = clutter_stage_view_take_scanout (view);
843+
if (scanout)
844+
{
845+
clutter_stage_cogl_scanout_view (stage_cogl,
846+
view,
847+
scanout);
848+
swap_event = TRUE;
849+
}
850+
else
851+
{
852+
swap_event |= clutter_stage_cogl_redraw_view (stage_window, view);
853+
}
828854
}
829855

830856
if (has_redraw_clip)

cogl/cogl/cogl-onscreen.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,27 @@ cogl_onscreen_get_buffer_age (CoglOnscreen *onscreen)
405405
return winsys->onscreen_get_buffer_age (onscreen);
406406
}
407407

408+
void
409+
cogl_onscreen_direct_scanout (CoglOnscreen *onscreen,
410+
CoglScanout *scanout)
411+
{
412+
CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
413+
const CoglWinsysVtable *winsys;
414+
CoglFrameInfo *info;
415+
416+
g_return_if_fail (framebuffer->type == COGL_FRAMEBUFFER_TYPE_ONSCREEN);
417+
g_return_if_fail (_cogl_winsys_has_feature (COGL_WINSYS_FEATURE_SYNC_AND_COMPLETE_EVENT));
418+
419+
info = _cogl_frame_info_new ();
420+
info->frame_counter = onscreen->frame_counter;
421+
g_queue_push_tail (&onscreen->pending_frame_infos, info);
422+
423+
winsys = _cogl_framebuffer_get_winsys (framebuffer);
424+
winsys->onscreen_direct_scanout (onscreen, scanout);
425+
426+
onscreen->frame_counter++;
427+
}
428+
408429
#ifdef COGL_HAS_X11_SUPPORT
409430
uint32_t
410431
cogl_x11_onscreen_get_window_xid (CoglOnscreen *onscreen)

cogl/cogl/cogl-onscreen.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ G_BEGIN_DECLS
5050
typedef struct _CoglOnscreen CoglOnscreen;
5151
#define COGL_ONSCREEN(X) ((CoglOnscreen *)(X))
5252

53+
typedef struct _CoglScanout CoglScanout;
54+
5355
/**
5456
* cogl_onscreen_get_gtype:
5557
*
@@ -284,6 +286,13 @@ cogl_onscreen_swap_buffers_with_damage (CoglOnscreen *onscreen,
284286
const int *rectangles,
285287
int n_rectangles);
286288

289+
/**
290+
* cogl_onscreen_direct_scanout: (skip)
291+
*/
292+
COGL_EXPORT void
293+
cogl_onscreen_direct_scanout (CoglOnscreen *onscreen,
294+
CoglScanout *scanout);
295+
287296
/**
288297
* cogl_onscreen_swap_region:
289298
* @onscreen: A #CoglOnscreen framebuffer

cogl/cogl/cogl-scanout.c

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
* Copyright (C) 2019 Red Hat Inc.
3+
*
4+
* This library is free software; you can redistribute it and/or
5+
* modify it under the terms of the GNU Lesser General Public
6+
* License as published by the Free Software Foundation; either
7+
* version 2 of the License, or (at your option) any later version.
8+
*
9+
* This library is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12+
* Lesser General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU Lesser General Public
15+
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
16+
*/
17+
18+
#include "cogl-config.h"
19+
20+
#include "cogl-scanout.h"
21+
22+
G_DEFINE_INTERFACE (CoglScanout, cogl_scanout, G_TYPE_OBJECT)
23+
24+
static void
25+
cogl_scanout_default_init (CoglScanoutInterface *iface)
26+
{
27+
}

cogl/cogl/cogl-scanout.h

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
* Copyright (C) 2019 Red Hat Inc.
3+
*
4+
* This library is free software; you can redistribute it and/or
5+
* modify it under the terms of the GNU Lesser General Public
6+
* License as published by the Free Software Foundation; either
7+
* version 2 of the License, or (at your option) any later version.
8+
*
9+
* This library is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12+
* Lesser General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU Lesser General Public
15+
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
16+
*/
17+
18+
#ifndef COGL_SCANOUT_H
19+
#define COGL_SCANOUT_H
20+
21+
#include "cogl/cogl-types.h"
22+
23+
#include <glib-object.h>
24+
25+
#define COGL_TYPE_SCANOUT (cogl_scanout_get_type ())
26+
COGL_EXPORT
27+
G_DECLARE_INTERFACE (CoglScanout, cogl_scanout,
28+
COGL, SCANOUT, GObject)
29+
30+
struct _CoglScanoutInterface
31+
{
32+
GTypeInterface parent_iface;
33+
};
34+
35+
#endif /* COGL_SCANOUT_H */

cogl/cogl/cogl.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@
122122
#include <cogl/cogl-fence.h>
123123
#include <cogl/cogl-glib-source.h>
124124
#include <cogl/cogl-trace.h>
125+
#include <cogl/cogl-scanout.h>
125126
/* XXX: This will definitly go away once all the Clutter winsys
126127
* code has been migrated down into Cogl! */
127128
#include <cogl/deprecated/cogl-clutter.h>

0 commit comments

Comments
 (0)