diff --git a/src/compositor/meta-compositor-native.c b/src/compositor/meta-compositor-native.c index 00f66b70d..7822789a3 100644 --- a/src/compositor/meta-compositor-native.c +++ b/src/compositor/meta-compositor-native.c @@ -23,11 +23,14 @@ #include "compositor/meta-compositor-native.h" #include "backends/meta-logical-monitor.h" +#include "backends/native/meta-crtc-kms.h" #include "compositor/meta-surface-actor-wayland.h" struct _MetaCompositorNative { MetaCompositorServer parent; + + MetaWaylandSurface *current_scanout_candidate; }; G_DEFINE_TYPE (MetaCompositorNative, meta_compositor_native, @@ -62,57 +65,88 @@ get_window_view (MetaRenderer *renderer, static void maybe_assign_primary_plane (MetaCompositor *compositor) { + MetaCompositorNative *compositor_native = META_COMPOSITOR_NATIVE (compositor); MetaBackend *backend = meta_get_backend (); MetaRenderer *renderer = meta_backend_get_renderer (backend); MetaWindowActor *window_actor; MetaWindow *window; MetaRendererView *view; + MetaCrtc *crtc; CoglFramebuffer *framebuffer; CoglOnscreen *onscreen; MetaSurfaceActor *surface_actor; MetaSurfaceActorWayland *surface_actor_wayland; + MetaWaylandSurface *surface; + MetaWaylandSurface *old_candidate = + compositor_native->current_scanout_candidate; + MetaWaylandSurface *new_candidate = NULL; g_autoptr (CoglScanout) scanout = NULL; if (meta_compositor_is_unredirect_inhibited (compositor)) - return; + goto done; window_actor = meta_compositor_get_top_window_actor (compositor); if (!window_actor) - return; + goto done; if (meta_window_actor_effect_in_progress (window_actor)) - return; + goto done; if (clutter_actor_has_transitions (CLUTTER_ACTOR (window_actor))) - return; + goto done; if (clutter_actor_get_n_children (CLUTTER_ACTOR (window_actor)) != 1) - return; + goto done; window = meta_window_actor_get_meta_window (window_actor); if (!window) - return; + goto done; view = get_window_view (renderer, window); if (!view) - return; + goto done; + + crtc = meta_renderer_view_get_crtc (META_RENDERER_VIEW (view)); + if (!META_IS_CRTC_KMS (crtc)) + goto done; framebuffer = clutter_stage_view_get_framebuffer (CLUTTER_STAGE_VIEW (view)); if (!COGL_IS_ONSCREEN (framebuffer)) - return; + goto done; surface_actor = meta_window_actor_get_surface (window_actor); if (!META_IS_SURFACE_ACTOR_WAYLAND (surface_actor)) - return; - + goto done; surface_actor_wayland = META_SURFACE_ACTOR_WAYLAND (surface_actor); + + surface = meta_surface_actor_wayland_get_surface (surface_actor_wayland); + if (!surface) + goto done; + + new_candidate = surface; + onscreen = COGL_ONSCREEN (framebuffer); scanout = meta_surface_actor_wayland_try_acquire_scanout (surface_actor_wayland, onscreen); if (!scanout) - return; + goto done; clutter_stage_view_assign_next_scanout (CLUTTER_STAGE_VIEW (view), scanout); + +done: + + if (old_candidate && old_candidate != new_candidate) + { + meta_wayland_surface_set_scanout_candidate (old_candidate, NULL); + g_clear_weak_pointer (&compositor_native->current_scanout_candidate); + } + + if (new_candidate) + { + meta_wayland_surface_set_scanout_candidate (surface, crtc); + g_set_weak_pointer (&compositor_native->current_scanout_candidate, + surface); + } } static void @@ -137,6 +171,16 @@ meta_compositor_native_new (MetaDisplay *display, NULL); } +static void +meta_compositor_native_finalize (GObject *object) +{ + MetaCompositorNative *compositor_native = META_COMPOSITOR_NATIVE (object); + + g_clear_weak_pointer (&compositor_native->current_scanout_candidate); + + G_OBJECT_CLASS (meta_compositor_native_parent_class)->finalize (object); +} + static void meta_compositor_native_init (MetaCompositorNative *compositor_native) { @@ -145,7 +189,10 @@ meta_compositor_native_init (MetaCompositorNative *compositor_native) static void meta_compositor_native_class_init (MetaCompositorNativeClass *klass) { + GObjectClass *object_class = G_OBJECT_CLASS (klass); MetaCompositorClass *compositor_class = META_COMPOSITOR_CLASS (klass); + object_class->finalize = meta_compositor_native_finalize; + compositor_class->before_paint = meta_compositor_native_before_paint; } diff --git a/src/compositor/meta-surface-actor-wayland.c b/src/compositor/meta-surface-actor-wayland.c index 3fce4b3da..1dad50cd7 100644 --- a/src/compositor/meta-surface-actor-wayland.c +++ b/src/compositor/meta-surface-actor-wayland.c @@ -79,8 +79,7 @@ meta_surface_actor_wayland_try_acquire_scanout (MetaSurfaceActorWayland *self, return NULL; surface = meta_surface_actor_wayland_get_surface (self); - if (!surface) - return NULL; + g_return_val_if_fail (surface, NULL); scanout = meta_wayland_surface_try_acquire_scanout (surface, onscreen); if (!scanout) diff --git a/src/wayland/meta-wayland-surface.c b/src/wayland/meta-wayland-surface.c index 320df11ed..58e9f9bde 100644 --- a/src/wayland/meta-wayland-surface.c +++ b/src/wayland/meta-wayland-surface.c @@ -77,6 +77,17 @@ typedef struct _MetaWaylandSurfaceRolePrivate MetaWaylandSurface *surface; } MetaWaylandSurfaceRolePrivate; +enum +{ + PROP_0, + + PROP_SCANOUT_CANDIDATE, + + N_PROPS +}; + +static GParamSpec *obj_props[N_PROPS]; + G_DEFINE_TYPE (MetaWaylandSurface, meta_wayland_surface, G_TYPE_OBJECT); G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (MetaWaylandSurfaceRole, @@ -1412,6 +1423,7 @@ wl_surface_destructor (struct wl_resource *resource) g_signal_emit (surface, surface_signals[SURFACE_DESTROY], 0); + g_clear_object (&surface->scanout_candidate); g_clear_object (&surface->role); if (surface->unassigned.buffer) @@ -1693,11 +1705,41 @@ meta_wayland_surface_init (MetaWaylandSurface *surface) g_node_prepend_data (surface->subsurface_branch_node, surface); } +static void +meta_wayland_surface_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + MetaWaylandSurface *surface = META_WAYLAND_SURFACE (object); + + switch (prop_id) + { + case PROP_SCANOUT_CANDIDATE: + g_value_set_object (value, surface->scanout_candidate); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + static void meta_wayland_surface_class_init (MetaWaylandSurfaceClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); + object_class->get_property = meta_wayland_surface_get_property; + + obj_props[PROP_SCANOUT_CANDIDATE] = + g_param_spec_object ("scanout-candidate", + "scanout-candidate", + "Scanout candidate for given CRTC", + META_TYPE_CRTC, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS); + g_object_class_install_properties (object_class, N_PROPS, obj_props); + surface_signals[SURFACE_DESTROY] = g_signal_new ("destroy", G_TYPE_FROM_CLASS (object_class), @@ -2100,3 +2142,21 @@ meta_wayland_surface_try_acquire_scanout (MetaWaylandSurface *surface, return scanout; } + +MetaCrtc * +meta_wayland_surface_get_scanout_candidate (MetaWaylandSurface *surface) +{ + return surface->scanout_candidate; +} + +void +meta_wayland_surface_set_scanout_candidate (MetaWaylandSurface *surface, + MetaCrtc *crtc) +{ + if (surface->scanout_candidate == crtc) + return; + + g_set_object (&surface->scanout_candidate, crtc); + g_object_notify_by_pspec (G_OBJECT (surface), + obj_props[PROP_SCANOUT_CANDIDATE]); +} diff --git a/src/wayland/meta-wayland-surface.h b/src/wayland/meta-wayland-surface.h index cfe5976a5..25b619977 100644 --- a/src/wayland/meta-wayland-surface.h +++ b/src/wayland/meta-wayland-surface.h @@ -247,6 +247,9 @@ struct _MetaWaylandSurface */ uint64_t sequence; } presentation_time; + + /* dma-buf feedback */ + MetaCrtc *scanout_candidate; }; void meta_wayland_shell_init (MetaWaylandCompositor *compositor); @@ -363,6 +366,11 @@ int meta_wayland_surface_get_height (MetaWaylandSurface *surface CoglScanout * meta_wayland_surface_try_acquire_scanout (MetaWaylandSurface *surface, CoglOnscreen *onscreen); +MetaCrtc * meta_wayland_surface_get_scanout_candidate (MetaWaylandSurface *surface); + +void meta_wayland_surface_set_scanout_candidate (MetaWaylandSurface *surface, + MetaCrtc *crtc); + static inline GNode * meta_get_next_subsurface_sibling (GNode *n) {