compositor/native: Add support for direct scanout per view

This uses MetaCompositorViewNative to find a candidate surface for
scanout and to keep track of it separately for each view, effectively
allowing each CRTC to use a different buffer for direct scanout.

There are three parts for potentially assigning a buffer for direct
scanout at the compositor level:
  1. Finding a candidate surface actor on the view (if any)
  2. Attempting to assign the candidate's buffer for direct scanout
  3. Updating references relating to the scanout candidate as needed

The three parts were moved in their entirety from being handled by the
MetaCompositorNative to being handled by the MetaCompositorViewNative.
As part of this transition, the logic was also slightly refactored so
that each of the three parts is handled by its own helper function.
This allowed to avoid the use of "goto" statements and hopefully make
the logic easier to read and follow.

The first part mentioned above was changed in this commit to make use
of the new meta_compositor_view_get_top_window_actor () API to get the
top window actor in the view instead of the top window actor on all
views.

The second part and third parts mentioned above weren't changed other
than being done in the context of a view instead of globally.

Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2526>
This commit is contained in:
Dor Askayo 2022-07-12 11:35:33 +03:00 committed by Marge Bot
parent ad0e19a034
commit 4736f873f2
3 changed files with 177 additions and 141 deletions

View File

@ -22,151 +22,27 @@
#include "compositor/meta-compositor-native.h"
#include "backends/meta-logical-monitor.h"
#include "backends/native/meta-crtc-kms.h"
#include "compositor/meta-compositor-view-native.h"
#include "compositor/meta-surface-actor-wayland.h"
struct _MetaCompositorNative
{
MetaCompositorServer parent;
MetaWaylandSurface *current_scanout_candidate;
};
G_DEFINE_TYPE (MetaCompositorNative, meta_compositor_native,
META_TYPE_COMPOSITOR_SERVER)
#ifdef HAVE_WAYLAND
static MetaRendererView *
get_window_view (MetaRenderer *renderer,
MetaWindow *window)
{
GList *l;
MetaRendererView *view_found = NULL;
for (l = meta_renderer_get_views (renderer); l; l = l->next)
{
ClutterStageView *stage_view = l->data;
MetaRectangle view_layout;
clutter_stage_view_get_layout (stage_view, &view_layout);
if (meta_rectangle_equal (&window->buffer_rect,
&view_layout))
{
if (view_found)
return NULL;
view_found = META_RENDERER_VIEW (stage_view);
}
}
return view_found;
}
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;
int geometry_scale;
MetaWaylandSurface *old_candidate =
compositor_native->current_scanout_candidate;
MetaWaylandSurface *new_candidate = NULL;
g_autoptr (CoglScanout) scanout = NULL;
if (meta_compositor_is_unredirect_inhibited (compositor))
goto done;
window_actor = meta_compositor_get_top_window_actor (compositor);
if (!window_actor)
goto done;
if (meta_window_actor_effect_in_progress (window_actor))
goto done;
if (clutter_actor_has_transitions (CLUTTER_ACTOR (window_actor)))
goto done;
window = meta_window_actor_get_meta_window (window_actor);
if (!window)
goto done;
view = get_window_view (renderer, window);
if (!view)
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))
goto done;
surface_actor = meta_window_actor_get_scanout_candidate (window_actor);
if (!surface_actor)
goto done;
if (meta_surface_actor_is_obscured (surface_actor))
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;
geometry_scale = meta_window_actor_get_geometry_scale (window_actor);
if (!meta_wayland_surface_can_scanout_untransformed (surface, view,
geometry_scale))
goto done;
new_candidate = surface;
onscreen = COGL_ONSCREEN (framebuffer);
scanout = meta_wayland_surface_try_acquire_scanout (surface,
onscreen);
if (!scanout)
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);
}
}
#endif /* HAVE_WAYLAND */
static void
meta_compositor_native_before_paint (MetaCompositor *compositor,
MetaCompositorView *compositor_view)
{
MetaCompositorViewNative *compositor_view_native =
META_COMPOSITOR_VIEW_NATIVE (compositor_view);
MetaCompositorClass *parent_class;
#ifdef HAVE_WAYLAND
maybe_assign_primary_plane (compositor);
meta_compositor_view_native_maybe_assign_scanout (compositor_view_native,
compositor);
#endif
parent_class = META_COMPOSITOR_CLASS (meta_compositor_native_parent_class);
@ -194,16 +70,6 @@ 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)
{
@ -212,11 +78,8 @@ 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;
compositor_class->create_view = meta_compositor_native_create_view;
}

View File

@ -26,14 +26,166 @@
#include "compositor/meta-compositor-view-native.h"
#include "backends/meta-crtc.h"
#include "backends/native/meta-crtc-kms.h"
#include "compositor/compositor-private.h"
#include "compositor/meta-window-actor-private.h"
#ifdef HAVE_WAYLAND
#include "compositor/meta-surface-actor-wayland.h"
#include "wayland/meta-wayland-surface.h"
#endif /* HAVE_WAYLAND */
struct _MetaCompositorViewNative
{
MetaCompositorView parent;
#ifdef HAVE_WAYLAND
MetaWaylandSurface *scanout_candidate;
#endif /* HAVE_WAYLAND */
};
G_DEFINE_TYPE (MetaCompositorViewNative, meta_compositor_view_native,
META_TYPE_COMPOSITOR_VIEW)
#ifdef HAVE_WAYLAND
static void
update_scanout_candidate (MetaCompositorViewNative *view_native,
MetaWaylandSurface *surface,
MetaCrtc *crtc)
{
if (view_native->scanout_candidate &&
view_native->scanout_candidate != surface)
{
meta_wayland_surface_set_scanout_candidate (view_native->scanout_candidate,
NULL);
g_clear_weak_pointer (&view_native->scanout_candidate);
}
if (surface)
{
meta_wayland_surface_set_scanout_candidate (surface, crtc);
g_set_weak_pointer (&view_native->scanout_candidate,
surface);
}
}
static gboolean
find_scanout_candidate (MetaCompositorView *compositor_view,
MetaCompositor *compositor,
MetaCrtc **crtc_out,
CoglOnscreen **onscreen_out,
MetaWaylandSurface **surface_out)
{
ClutterStageView *stage_view;
MetaRendererView *renderer_view;
MetaCrtc *crtc;
CoglFramebuffer *framebuffer;
MetaWindowActor *window_actor;
MetaWindow *window;
MetaSurfaceActor *surface_actor;
MetaSurfaceActorWayland *surface_actor_wayland;
MetaWaylandSurface *surface;
int geometry_scale;
if (meta_compositor_is_unredirect_inhibited (compositor))
return FALSE;
stage_view = meta_compositor_view_get_stage_view (compositor_view);
renderer_view = META_RENDERER_VIEW (stage_view);
crtc = meta_renderer_view_get_crtc (renderer_view);
if (!META_IS_CRTC_KMS (crtc))
return FALSE;
framebuffer = clutter_stage_view_get_framebuffer (stage_view);
if (!COGL_IS_ONSCREEN (framebuffer))
return FALSE;
window_actor = meta_compositor_view_get_top_window_actor (compositor_view);
if (!window_actor)
return FALSE;
if (meta_window_actor_effect_in_progress (window_actor))
return FALSE;
if (clutter_actor_has_transitions (CLUTTER_ACTOR (window_actor)))
return FALSE;
window = meta_window_actor_get_meta_window (window_actor);
if (!window)
return FALSE;
surface_actor = meta_window_actor_get_scanout_candidate (window_actor);
if (!surface_actor)
return FALSE;
if (meta_surface_actor_is_obscured (surface_actor))
return FALSE;
surface_actor_wayland = META_SURFACE_ACTOR_WAYLAND (surface_actor);
surface = meta_surface_actor_wayland_get_surface (surface_actor_wayland);
if (!surface)
return FALSE;
geometry_scale = meta_window_actor_get_geometry_scale (window_actor);
if (!meta_wayland_surface_can_scanout_untransformed (surface,
renderer_view,
geometry_scale))
return FALSE;
*crtc_out = crtc;
*onscreen_out = COGL_ONSCREEN (framebuffer);
*surface_out = surface;
return TRUE;
}
static void
try_assign_next_scanout (MetaCompositorView *compositor_view,
CoglOnscreen *onscreen,
MetaWaylandSurface *surface)
{
ClutterStageView *stage_view;
g_autoptr (CoglScanout) scanout = NULL;
scanout = meta_wayland_surface_try_acquire_scanout (surface,
onscreen);
if (!scanout)
return;
stage_view = meta_compositor_view_get_stage_view (compositor_view);
clutter_stage_view_assign_next_scanout (stage_view, scanout);
}
void
meta_compositor_view_native_maybe_assign_scanout (MetaCompositorViewNative *view_native,
MetaCompositor *compositor)
{
MetaCompositorView *compositor_view = META_COMPOSITOR_VIEW (view_native);
MetaCrtc *crtc = NULL;
CoglOnscreen *onscreen = NULL;
MetaWaylandSurface *surface = NULL;
gboolean candidate_found;
candidate_found = find_scanout_candidate (compositor_view,
compositor,
&crtc,
&onscreen,
&surface);
if (candidate_found)
{
try_assign_next_scanout (compositor_view,
onscreen,
surface);
}
update_scanout_candidate (view_native, surface, crtc);
}
#endif /* HAVE_WAYLAND */
MetaCompositorViewNative *
meta_compositor_view_native_new (ClutterStageView *stage_view)
{
@ -44,9 +196,24 @@ meta_compositor_view_native_new (ClutterStageView *stage_view)
NULL);
}
static void
meta_compositor_view_native_finalize (GObject *object)
{
#ifdef HAVE_WAYLAND
MetaCompositorViewNative *view_native = META_COMPOSITOR_VIEW_NATIVE (object);
g_clear_weak_pointer (&view_native->scanout_candidate);
#endif /* HAVE_WAYLAND */
G_OBJECT_CLASS (meta_compositor_view_native_parent_class)->finalize (object);
}
static void
meta_compositor_view_native_class_init (MetaCompositorViewNativeClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = meta_compositor_view_native_finalize;
}
static void

View File

@ -27,6 +27,7 @@
#include "clutter/clutter-mutter.h"
#include "compositor/meta-compositor-view.h"
#include "meta/compositor.h"
#define META_TYPE_COMPOSITOR_VIEW_NATIVE (meta_compositor_view_native_get_type ())
G_DECLARE_FINAL_TYPE (MetaCompositorViewNative, meta_compositor_view_native,
@ -34,4 +35,9 @@ G_DECLARE_FINAL_TYPE (MetaCompositorViewNative, meta_compositor_view_native,
MetaCompositorViewNative *meta_compositor_view_native_new (ClutterStageView *stage_view);
#ifdef HAVE_WAYLAND
void meta_compositor_view_native_maybe_assign_scanout (MetaCompositorViewNative *view_native,
MetaCompositor *compositor);
#endif /* HAVE_WAYLAND */
#endif /* META_COMPOSITOR_VIEW_NATIVE_H */