
If a stage view uses an offscreen framebuffer exclusively for rotation and a Wayland client provides pre-rotated buffers, we should try to use scanout. This saves us one copy more than scanout in the onscreen case, i.e. two fullscreen copies in total. Offscreen rotation is notably used for all 90/270 degree rotations at the moment, as using display hardware for them is apparently more complex than for x-/y-flips and can even have detrimental effects on power consumption. This can be tested with `weston-simple-egl`. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2468>
226 lines
6.7 KiB
C
226 lines
6.7 KiB
C
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
|
|
|
/*
|
|
* Copyright (C) 2022 Dor Askayo
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License as
|
|
* published by the Free Software Foundation; either version 2 of the
|
|
* License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
|
* 02111-1307, USA.
|
|
*
|
|
* Written by:
|
|
* Dor Askayo <dor.askayo@gmail.com>
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#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_onscreen (stage_view);
|
|
if (!COGL_IS_ONSCREEN (framebuffer))
|
|
return FALSE;
|
|
|
|
if (clutter_stage_view_has_shadowfb (stage_view))
|
|
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)
|
|
{
|
|
g_assert (stage_view != NULL);
|
|
|
|
return g_object_new (META_TYPE_COMPOSITOR_VIEW_NATIVE,
|
|
"stage-view", 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
|
|
meta_compositor_view_native_init (MetaCompositorViewNative *view_native)
|
|
{
|
|
}
|