mirror of
https://github.com/brl/mutter.git
synced 2025-02-20 06:54:10 +00:00

This check was originally added because `window` was actually used. While technically correct, there's no reason to keep it around. Fixes: 4736f873f2 ("compositor/native: Add support for direct scanout per view") Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3177>
324 lines
10 KiB
C
324 lines
10 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, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
* 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-private.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 =
|
|
meta_compositor_view_get_stage_view (compositor_view);
|
|
MetaStageView *view = META_STAGE_VIEW (stage_view);
|
|
MetaRendererView *renderer_view = META_RENDERER_VIEW (stage_view);
|
|
MetaBackend *backend = meta_compositor_get_backend (compositor);
|
|
MetaCursorTracker *cursor_tracker =
|
|
meta_backend_get_cursor_tracker (backend);
|
|
CoglTexture *cursor_sprite;
|
|
MetaCrtc *crtc;
|
|
CoglFramebuffer *framebuffer;
|
|
MetaWindowActor *window_actor;
|
|
MtkRectangle view_rect;
|
|
ClutterActorBox actor_box;
|
|
MetaSurfaceActor *surface_actor;
|
|
MetaSurfaceActorWayland *surface_actor_wayland;
|
|
MetaWaylandSurface *surface;
|
|
|
|
if (meta_compositor_is_unredirect_inhibited (compositor))
|
|
{
|
|
meta_topic (META_DEBUG_RENDER,
|
|
"No direct scanout candidate: unredirect inhibited");
|
|
return FALSE;
|
|
}
|
|
|
|
clutter_stage_view_get_layout (stage_view, &view_rect);
|
|
|
|
cursor_sprite = meta_cursor_tracker_get_sprite (cursor_tracker);
|
|
if (cursor_sprite &&
|
|
meta_cursor_tracker_get_pointer_visible (cursor_tracker) &&
|
|
!meta_stage_view_is_cursor_overlay_inhibited (view))
|
|
{
|
|
graphene_rect_t graphene_view_rect;
|
|
graphene_rect_t cursor_rect;
|
|
graphene_point_t position;
|
|
float scale;
|
|
int hotspot_x;
|
|
int hotspot_y;
|
|
|
|
meta_cursor_tracker_get_pointer (cursor_tracker, &position, NULL);
|
|
meta_cursor_tracker_get_hot (cursor_tracker, &hotspot_x, &hotspot_y);
|
|
|
|
scale = (clutter_stage_view_get_scale (stage_view) *
|
|
meta_cursor_tracker_get_scale (cursor_tracker));
|
|
|
|
graphene_rect_init (&cursor_rect,
|
|
position.x - (hotspot_x * scale),
|
|
position.y - (hotspot_y * scale),
|
|
cogl_texture_get_width (cursor_sprite) * scale,
|
|
cogl_texture_get_height (cursor_sprite) * scale);
|
|
|
|
graphene_view_rect = mtk_rectangle_to_graphene_rect (&view_rect);
|
|
if (graphene_rect_intersection (&graphene_view_rect,
|
|
&cursor_rect,
|
|
NULL))
|
|
{
|
|
meta_topic (META_DEBUG_RENDER,
|
|
"No direct scanout candidate: using software cursor");
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
crtc = meta_renderer_view_get_crtc (renderer_view);
|
|
if (!META_IS_CRTC_KMS (crtc))
|
|
{
|
|
meta_topic (META_DEBUG_RENDER,
|
|
"No direct scanout candidate: no KMS CRTC");
|
|
return FALSE;
|
|
}
|
|
|
|
framebuffer = clutter_stage_view_get_onscreen (stage_view);
|
|
if (!COGL_IS_ONSCREEN (framebuffer))
|
|
{
|
|
meta_topic (META_DEBUG_RENDER,
|
|
"No direct scanout candidate: no onscreen framebuffer");
|
|
return FALSE;
|
|
}
|
|
|
|
if (clutter_stage_view_has_shadowfb (stage_view))
|
|
{
|
|
meta_topic (META_DEBUG_RENDER,
|
|
"No direct scanout candidate: stage-view has shadowfb");
|
|
return FALSE;
|
|
}
|
|
|
|
window_actor = meta_compositor_view_get_top_window_actor (compositor_view);
|
|
if (!window_actor)
|
|
{
|
|
meta_topic (META_DEBUG_RENDER,
|
|
"No direct scanout candidate: no top window actor");
|
|
return FALSE;
|
|
}
|
|
|
|
if (meta_window_actor_effect_in_progress (window_actor))
|
|
{
|
|
meta_topic (META_DEBUG_RENDER,
|
|
"No direct scanout candidate: window-actor effects in progress");
|
|
return FALSE;
|
|
}
|
|
|
|
if (clutter_actor_has_transitions (CLUTTER_ACTOR (window_actor)))
|
|
{
|
|
meta_topic (META_DEBUG_RENDER,
|
|
"No direct scanout candidate: window-actor has transition");
|
|
return FALSE;
|
|
}
|
|
|
|
if (!clutter_actor_get_paint_box (CLUTTER_ACTOR (window_actor),
|
|
&actor_box))
|
|
{
|
|
meta_topic (META_DEBUG_RENDER,
|
|
"No direct scanout candidate: no window actor paint-box");
|
|
return FALSE;
|
|
}
|
|
|
|
if (!G_APPROX_VALUE (actor_box.x1, view_rect.x,
|
|
CLUTTER_COORDINATE_EPSILON) ||
|
|
!G_APPROX_VALUE (actor_box.y1, view_rect.y,
|
|
CLUTTER_COORDINATE_EPSILON) ||
|
|
!G_APPROX_VALUE (actor_box.x2, view_rect.x + view_rect.width,
|
|
CLUTTER_COORDINATE_EPSILON) ||
|
|
!G_APPROX_VALUE (actor_box.y2, view_rect.y + view_rect.height,
|
|
CLUTTER_COORDINATE_EPSILON))
|
|
{
|
|
meta_topic (META_DEBUG_RENDER,
|
|
"No direct scanout candidate: paint-box (%f,%f,%f,%f) does "
|
|
"not match stage-view layout (%d,%d,%d,%d)",
|
|
actor_box.x1, actor_box.y1,
|
|
actor_box.x2 - actor_box.x1, actor_box.y2 - actor_box.y1,
|
|
view_rect.x, view_rect.y, view_rect.width, view_rect.height);
|
|
return FALSE;
|
|
}
|
|
|
|
surface_actor = meta_window_actor_get_scanout_candidate (window_actor);
|
|
if (!surface_actor)
|
|
{
|
|
meta_topic (META_DEBUG_RENDER,
|
|
"No direct scanout candidate: window-actor has no scanout "
|
|
"candidate");
|
|
return FALSE;
|
|
}
|
|
|
|
if (meta_surface_actor_is_effectively_obscured (surface_actor))
|
|
{
|
|
meta_topic (META_DEBUG_RENDER,
|
|
"No direct scanout candidate: surface-actor is obscured");
|
|
return FALSE;
|
|
}
|
|
|
|
surface_actor_wayland = META_SURFACE_ACTOR_WAYLAND (surface_actor);
|
|
surface = meta_surface_actor_wayland_get_surface (surface_actor_wayland);
|
|
if (!surface)
|
|
{
|
|
meta_topic (META_DEBUG_RENDER,
|
|
"No direct scanout candidate: no surface");
|
|
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;
|
|
|
|
stage_view = meta_compositor_view_get_stage_view (compositor_view);
|
|
scanout = meta_wayland_surface_try_acquire_scanout (surface,
|
|
onscreen,
|
|
stage_view);
|
|
if (!scanout)
|
|
{
|
|
meta_topic (META_DEBUG_RENDER,
|
|
"Could not acquire scanout");
|
|
return;
|
|
}
|
|
|
|
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)
|
|
{
|
|
}
|