mutter/src/wayland/meta-wayland-surface.c

2314 lines
72 KiB
C
Raw Normal View History

/*
* Wayland Support
*
* Copyright (C) 2012,2013 Intel Corporation
* Copyright (C) 2013-2017 Red Hat, Inc.
*
* 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.
*/
2014-10-07 22:59:01 -04:00
#include "config.h"
#include "wayland/meta-wayland-surface.h"
#include <gobject/gvaluecollector.h>
#include <wayland-server.h>
#include "backends/meta-cursor-tracker-private.h"
#include "clutter/clutter.h"
#include "cogl/cogl.h"
#include "compositor/meta-surface-actor-wayland.h"
#include "compositor/meta-surface-actor.h"
#include "compositor/meta-window-actor-private.h"
#include "compositor/region-utils.h"
#include "core/display-private.h"
#include "core/window-private.h"
#include "wayland/meta-wayland-actor-surface.h"
#include "wayland/meta-wayland-buffer.h"
#include "wayland/meta-wayland-data-device.h"
#include "wayland/meta-wayland-gtk-shell.h"
#include "wayland/meta-wayland-keyboard.h"
#include "wayland/meta-wayland-outputs.h"
#include "wayland/meta-wayland-pointer.h"
#include "wayland/meta-wayland-presentation-time-private.h"
#include "wayland/meta-wayland-private.h"
#include "wayland/meta-wayland-region.h"
#include "wayland/meta-wayland-seat.h"
#include "wayland/meta-wayland-subsurface.h"
#include "wayland/meta-wayland-transaction.h"
#include "wayland/meta-wayland-viewporter.h"
#include "wayland/meta-wayland-xdg-shell.h"
#include "wayland/meta-window-wayland.h"
#include "wayland/meta-xwayland-private.h"
#include "wayland/meta-xwayland-private.h"
window-actor: Split into two subclasses of MetaSurfaceActor The rendering logic before was somewhat complex. We had three independent cases to take into account when doing rendering: * X11 compositor. In this case, we're a traditional X11 compositor, not a Wayland compositor. We use XCompositeNameWindowPixmap to get the backing pixmap for the window, and deal with the COMPOSITE extension messiness. In this case, meta_is_wayland_compositor() is FALSE. * Wayland clients. In this case, we're a Wayland compositor managing Wayland surfaces. The rendering for this is fairly straightforward, as Cogl handles most of the complexity with EGL and SHM buffers... Wayland clients give us the input and opaque regions through wl_surface. In this case, meta_is_wayland_compositor() is TRUE and priv->window->client_type == META_WINDOW_CLIENT_TYPE_WAYLAND. * XWayland clients. In this case, we're a Wayland compositor, like above, and XWayland hands us Wayland surfaces. XWayland handles the COMPOSITE extension messiness for us, and hands us a buffer like any other Wayland client. We have to fetch the input and opaque regions from the X11 window ourselves. In this case, meta_is_wayland_compositor() is TRUE and priv->window->client_type == META_WINDOW_CLIENT_TYPE_X11. We now split the rendering logic into two subclasses, which are: * MetaSurfaceActorX11, which handles the X11 compositor case, in that it uses XCompositeNameWindowPixmap to get the backing pixmap, and deal with all the COMPOSITE extension messiness. * MetaSurfaceActorWayland, which handles the Wayland compositor case for both native Wayland clients and XWayland clients. XWayland handles COMPOSITE for us, and handles pushing a surface over through the xf86-video-wayland DDX. Frame sync is still in MetaWindowActor, as it needs to work for both the X11 compositor and XWayland client cases. When Wayland's video display protocol lands, this will need to be significantly overhauled, as it would have to work for any wl_surface, including subsurfaces, so we would need surface-level discretion. https://bugzilla.gnome.org/show_bug.cgi?id=720631
2014-02-01 17:21:11 -05:00
enum
{
SURFACE_STATE_SIGNAL_APPLIED,
SURFACE_STATE_SIGNAL_N_SIGNALS
};
enum
{
SURFACE_ROLE_PROP_0,
SURFACE_ROLE_PROP_SURFACE,
};
static guint surface_state_signals[SURFACE_STATE_SIGNAL_N_SIGNALS];
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,
meta_wayland_surface_role,
G_TYPE_OBJECT)
G_DEFINE_TYPE (MetaWaylandSurfaceState,
meta_wayland_surface_state,
G_TYPE_OBJECT)
enum
{
SURFACE_DESTROY,
SURFACE_UNMAPPED,
SURFACE_CONFIGURE,
SURFACE_SHORTCUTS_INHIBITED,
SURFACE_SHORTCUTS_RESTORED,
SURFACE_GEOMETRY_CHANGED,
SURFACE_PRE_STATE_APPLIED,
N_SURFACE_SIGNALS
};
guint surface_signals[N_SURFACE_SIGNALS] = { 0 };
static void
meta_wayland_surface_role_assigned (MetaWaylandSurfaceRole *surface_role);
static void
meta_wayland_surface_role_commit_state (MetaWaylandSurfaceRole *surface_role,
MetaWaylandTransaction *transaction,
MetaWaylandSurfaceState *pending);
static void
meta_wayland_surface_role_pre_apply_state (MetaWaylandSurfaceRole *surface_role,
MetaWaylandSurfaceState *pending);
static void
meta_wayland_surface_role_apply_state (MetaWaylandSurfaceRole *surface_role,
MetaWaylandSurfaceState *pending);
static void
meta_wayland_surface_role_post_apply_state (MetaWaylandSurfaceRole *surface_role,
MetaWaylandSurfaceState *pending);
static gboolean
meta_wayland_surface_role_is_on_logical_monitor (MetaWaylandSurfaceRole *surface_role,
MetaLogicalMonitor *logical_monitor);
static MetaWaylandSurface *
meta_wayland_surface_role_get_toplevel (MetaWaylandSurfaceRole *surface_role);
static void
set_surface_is_on_output (MetaWaylandSurface *surface,
MetaWaylandOutput *wayland_output,
gboolean is_on_output);
static void
role_assignment_valist_to_properties (GType role_type,
const char *first_property_name,
va_list var_args,
GArray *names,
GArray *values)
{
GObjectClass *object_class;
const char *property_name = first_property_name;
object_class = g_type_class_ref (role_type);
while (property_name)
{
GValue value = G_VALUE_INIT;
GParamSpec *pspec;
GType ptype;
gchar *error = NULL;
pspec = g_object_class_find_property (object_class,
property_name);
g_assert (pspec);
ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
G_VALUE_COLLECT_INIT (&value, ptype, var_args, 0, &error);
g_assert (!error);
g_array_append_val (names, property_name);
g_array_append_val (values, value);
property_name = va_arg (var_args, const char *);
}
g_type_class_unref (object_class);
}
gboolean
meta_wayland_surface_assign_role (MetaWaylandSurface *surface,
GType role_type,
const char *first_property_name,
...)
{
va_list var_args;
if (!surface->role)
{
if (first_property_name)
{
GArray *names;
GArray *values;
const char *surface_prop_name;
GValue surface_value = G_VALUE_INIT;
GObject *role_object;
names = g_array_new (FALSE, FALSE, sizeof (const char *));
values = g_array_new (FALSE, FALSE, sizeof (GValue));
g_array_set_clear_func (values, (GDestroyNotify) g_value_unset);
va_start (var_args, first_property_name);
role_assignment_valist_to_properties (role_type,
first_property_name,
var_args,
names,
values);
va_end (var_args);
surface_prop_name = "surface";
g_value_init (&surface_value, META_TYPE_WAYLAND_SURFACE);
g_value_set_object (&surface_value, surface);
g_array_append_val (names, surface_prop_name);
g_array_append_val (values, surface_value);
role_object =
g_object_new_with_properties (role_type,
values->len,
(const char **) names->data,
(const GValue *) values->data);
surface->role = META_WAYLAND_SURFACE_ROLE (role_object);
g_array_free (names, TRUE);
g_array_free (values, TRUE);
}
else
{
surface->role = g_object_new (role_type, "surface", surface, NULL);
}
meta_wayland_surface_role_assigned (surface->role);
/* Release the use count held on behalf of the just assigned role. */
if (surface->unassigned.buffer)
{
wayland/surface: Overhaul handling of buffer use count Move the use count from a separate MetaWaylandBufferRef struct to the MetaWaylandBuffer class, and remove the former. The buffer use count is now incremented already in meta_wayland_surface_commit, since the Wayland protocol defines the buffer to be in use by the compositor at that point. If the buffer attachment ends up being dropped again before it is applied to the surface state (e.g. because another buffer is committed to a synchronized sub-surface before the parent surface is committed), the use count is now decremented, and a buffer release event is sent if the use count drops to 0. Buffer release events were previously incorrectly not sent under these circumstances. Test case: Run the weston-subsurfaces demo with the -r1 and/or -t1 command line parameter. Resize the window. Before this change, weston-subsurfaces would freeze or abort after a few resize operations, because mutter failed to send release events and the client ran out of usable buffers. v2: * Handle NULL priv->buffer_ref in meta_wayland_cursor_surface_apply_state. v3: * Remove MetaWaylandBufferRef altogether, move the use count tracking to MetaWaylandBuffer itself. Much simpler, and doesn't run into lifetime issues when mutter shuts down. v4: * Warn if use count isn't 0 in meta_wayland_buffer_finalize. * Keep pending_buffer_resource_destroyed for attached but not yet committed buffers. If the client attaches a buffer and then destroys it before commit, we ignore the buffer attachement, same as before this MR. v5: * Rebase on top of new commit which splits up surface->texture. * MetaWaylandSurfaceState::buffer can only be non-NULL if ::newly_attached is TRUE, simplify accordingly. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1880>
2022-06-22 12:43:11 -04:00
meta_wayland_buffer_dec_use_count (surface->unassigned.buffer);
g_clear_object (&surface->unassigned.buffer);
}
return TRUE;
}
else if (G_OBJECT_TYPE (surface->role) != role_type)
{
return FALSE;
}
else
{
va_start (var_args, first_property_name);
g_object_set_valist (G_OBJECT (surface->role),
first_property_name, var_args);
va_end (var_args);
meta_wayland_surface_role_assigned (surface->role);
return TRUE;
}
}
static int
get_buffer_width (MetaWaylandSurface *surface)
{
MetaWaylandBuffer *buffer = meta_wayland_surface_get_buffer (surface);
if (buffer)
return cogl_texture_get_width (surface->output_state.texture);
else
return 0;
}
static int
get_buffer_height (MetaWaylandSurface *surface)
{
MetaWaylandBuffer *buffer = meta_wayland_surface_get_buffer (surface);
if (buffer)
return cogl_texture_get_height (surface->output_state.texture);
else
return 0;
}
static void
surface_process_damage (MetaWaylandSurface *surface,
cairo_region_t *surface_region,
cairo_region_t *buffer_region)
{
MetaWaylandBuffer *buffer = meta_wayland_surface_get_buffer (surface);
cairo_rectangle_int_t buffer_rect;
MetaSurfaceActor *actor;
/* If the client destroyed the buffer it attached before committing, but
* still posted damage, or posted damage without any buffer, don't try to
* process it on the non-existing buffer.
*/
if (!buffer)
return;
buffer_rect = (cairo_rectangle_int_t) {
.width = get_buffer_width (surface),
.height = get_buffer_height (surface),
};
if (!cairo_region_is_empty (surface_region))
{
cairo_rectangle_int_t surface_rect;
cairo_region_t *scaled_region;
cairo_region_t *transformed_region;
cairo_region_t *viewport_region;
graphene_rect_t src_rect;
/* Intersect the damage region with the surface region before scaling in
* order to avoid integer overflow when scaling a damage region is too
* large (for example INT32_MAX which mesa passes). */
surface_rect = (cairo_rectangle_int_t) {
.width = meta_wayland_surface_get_width (surface),
.height = meta_wayland_surface_get_height (surface),
};
cairo_region_intersect_rectangle (surface_region, &surface_rect);
/* The damage region must be in the same coordinate space as the buffer,
* i.e. scaled with surface->scale. */
if (surface->viewport.has_src_rect)
{
src_rect = (graphene_rect_t) {
.origin.x = surface->viewport.src_rect.origin.x,
.origin.y = surface->viewport.src_rect.origin.y,
.size.width = surface->viewport.src_rect.size.width,
.size.height = surface->viewport.src_rect.size.height
};
}
else
{
int width, height;
if (meta_monitor_transform_is_rotated (surface->buffer_transform))
{
width = get_buffer_height (surface);
height = get_buffer_width (surface);
}
else
{
width = get_buffer_width (surface);
height = get_buffer_height (surface);
}
src_rect = (graphene_rect_t) {
.size.width = width / surface->scale,
.size.height = height / surface->scale
};
}
viewport_region = meta_region_crop_and_scale (surface_region,
&src_rect,
surface_rect.width,
surface_rect.height);
scaled_region = meta_region_scale (viewport_region, surface->scale);
transformed_region = meta_region_transform (scaled_region,
surface->buffer_transform,
buffer_rect.width,
buffer_rect.height);
/* Now add the scaled, cropped and transformed damage region to the
* buffer damage. Buffer damage is already in the correct coordinate
* space. */
cairo_region_union (buffer_region, transformed_region);
cairo_region_destroy (viewport_region);
cairo_region_destroy (scaled_region);
cairo_region_destroy (transformed_region);
}
cairo_region_intersect_rectangle (buffer_region, &buffer_rect);
meta_wayland_buffer_process_damage (buffer, surface->output_state.texture,
buffer_region);
actor = meta_wayland_surface_get_actor (surface);
if (actor)
{
int i, n_rectangles;
n_rectangles = cairo_region_num_rectangles (buffer_region);
for (i = 0; i < n_rectangles; i++)
{
cairo_rectangle_int_t rect;
cairo_region_get_rectangle (buffer_region, i, &rect);
meta_surface_actor_process_damage (actor,
rect.x, rect.y,
rect.width, rect.height);
}
}
}
MetaWaylandBuffer *
meta_wayland_surface_get_buffer (MetaWaylandSurface *surface)
{
wayland/surface: Overhaul handling of buffer use count Move the use count from a separate MetaWaylandBufferRef struct to the MetaWaylandBuffer class, and remove the former. The buffer use count is now incremented already in meta_wayland_surface_commit, since the Wayland protocol defines the buffer to be in use by the compositor at that point. If the buffer attachment ends up being dropped again before it is applied to the surface state (e.g. because another buffer is committed to a synchronized sub-surface before the parent surface is committed), the use count is now decremented, and a buffer release event is sent if the use count drops to 0. Buffer release events were previously incorrectly not sent under these circumstances. Test case: Run the weston-subsurfaces demo with the -r1 and/or -t1 command line parameter. Resize the window. Before this change, weston-subsurfaces would freeze or abort after a few resize operations, because mutter failed to send release events and the client ran out of usable buffers. v2: * Handle NULL priv->buffer_ref in meta_wayland_cursor_surface_apply_state. v3: * Remove MetaWaylandBufferRef altogether, move the use count tracking to MetaWaylandBuffer itself. Much simpler, and doesn't run into lifetime issues when mutter shuts down. v4: * Warn if use count isn't 0 in meta_wayland_buffer_finalize. * Keep pending_buffer_resource_destroyed for attached but not yet committed buffers. If the client attaches a buffer and then destroys it before commit, we ignore the buffer attachement, same as before this MR. v5: * Rebase on top of new commit which splits up surface->texture. * MetaWaylandSurfaceState::buffer can only be non-NULL if ::newly_attached is TRUE, simplify accordingly. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1880>
2022-06-22 12:43:11 -04:00
return surface->buffer;
}
static void
pending_buffer_resource_destroyed (MetaWaylandBuffer *buffer,
MetaWaylandSurfaceState *pending)
{
g_clear_signal_handler (&pending->buffer_destroy_handler_id, buffer);
pending->buffer = NULL;
}
static void
meta_wayland_surface_state_set_default (MetaWaylandSurfaceState *state)
{
state->newly_attached = FALSE;
state->buffer = NULL;
state->texture = NULL;
state->buffer_destroy_handler_id = 0;
state->dx = 0;
state->dy = 0;
state->scale = 0;
state->input_region = NULL;
state->input_region_set = FALSE;
state->opaque_region = NULL;
state->opaque_region_set = FALSE;
state->surface_damage = cairo_region_create ();
state->buffer_damage = cairo_region_create ();
wl_list_init (&state->frame_callback_list);
state->has_new_geometry = FALSE;
state->has_acked_configure_serial = FALSE;
state->has_new_min_size = FALSE;
state->has_new_max_size = FALSE;
state->has_new_buffer_transform = FALSE;
state->has_new_viewport_src_rect = FALSE;
state->has_new_viewport_dst_size = FALSE;
state->subsurface_placement_ops = NULL;
wl_list_init (&state->presentation_feedback_list);
state->xdg_popup_reposition_token = 0;
}
static void
meta_wayland_surface_state_discard_presentation_feedback (MetaWaylandSurfaceState *state)
{
while (!wl_list_empty (&state->presentation_feedback_list))
{
MetaWaylandPresentationFeedback *feedback =
wl_container_of (state->presentation_feedback_list.next, feedback, link);
meta_wayland_presentation_feedback_discard (feedback);
}
}
static void
meta_wayland_surface_state_clear (MetaWaylandSurfaceState *state)
{
MetaWaylandFrameCallback *cb, *next;
cogl_clear_object (&state->texture);
g_clear_pointer (&state->surface_damage, cairo_region_destroy);
g_clear_pointer (&state->buffer_damage, cairo_region_destroy);
g_clear_pointer (&state->input_region, cairo_region_destroy);
g_clear_pointer (&state->opaque_region, cairo_region_destroy);
g_clear_pointer (&state->xdg_positioner, g_free);
wayland/surface: Overhaul handling of buffer use count Move the use count from a separate MetaWaylandBufferRef struct to the MetaWaylandBuffer class, and remove the former. The buffer use count is now incremented already in meta_wayland_surface_commit, since the Wayland protocol defines the buffer to be in use by the compositor at that point. If the buffer attachment ends up being dropped again before it is applied to the surface state (e.g. because another buffer is committed to a synchronized sub-surface before the parent surface is committed), the use count is now decremented, and a buffer release event is sent if the use count drops to 0. Buffer release events were previously incorrectly not sent under these circumstances. Test case: Run the weston-subsurfaces demo with the -r1 and/or -t1 command line parameter. Resize the window. Before this change, weston-subsurfaces would freeze or abort after a few resize operations, because mutter failed to send release events and the client ran out of usable buffers. v2: * Handle NULL priv->buffer_ref in meta_wayland_cursor_surface_apply_state. v3: * Remove MetaWaylandBufferRef altogether, move the use count tracking to MetaWaylandBuffer itself. Much simpler, and doesn't run into lifetime issues when mutter shuts down. v4: * Warn if use count isn't 0 in meta_wayland_buffer_finalize. * Keep pending_buffer_resource_destroyed for attached but not yet committed buffers. If the client attaches a buffer and then destroys it before commit, we ignore the buffer attachement, same as before this MR. v5: * Rebase on top of new commit which splits up surface->texture. * MetaWaylandSurfaceState::buffer can only be non-NULL if ::newly_attached is TRUE, simplify accordingly. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1880>
2022-06-22 12:43:11 -04:00
if (state->buffer_destroy_handler_id)
{
g_clear_signal_handler (&state->buffer_destroy_handler_id, state->buffer);
state->buffer = NULL;
}
else
{
g_clear_object (&state->buffer);
}
wl_list_for_each_safe (cb, next, &state->frame_callback_list, link)
wl_resource_destroy (cb->resource);
if (state->subsurface_placement_ops)
wayland/surface: Use transactions for all sub-surface hierarchy changes And keep track of the hierarchy separately for the Wayland protocol and for output. Protocol state is updated immediately as protocol requests are processed, output state only when the corresponding transaction is applied (which may be deferred until the next commit of the parent surface). v2: * Directly add placement ops to a transaction, instead of going via pending_state. * Use transaction entry for the sub-surface instead of that for its parent surface. v3: * Use transaction entry for the parent surface again, to ensure proper ordering of placement ops, and call meta_wayland_surface_notify_subsurface_state_changed only once per parent surface. * Drop all use of wl_resource_add_destroy_listener, transactions are keeping surfaces alive as long as needed. v4: * Rebase on https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2501 * Drop ClutterActor code from meta_wayland_surface_apply_placement_ops. (Robert Mader) v5: * Rename MetaWaylandSubSurfaceState to MetaWaylandSurfaceSubState, since the next commit adds not sub-surface specific state to it. v6: * Move include of meta-wayland-subsurface.h from meta-wayland-transaction.c to .h, since the latter references MetaWaylandSubsurfacePlacementOp. v7: * Drop superfluous !entry check from meta_wayland_transaction_apply. v8: * Rename output/protocol fields to output/protocol_state. (Jonas Ådahl) v9: * Use meta_wayland_surface_state_new in meta_wayland_transaction_add_placement_op. v10: * Fix a few style issues per check-style.py. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1880>
2021-07-23 10:01:37 -04:00
g_slist_free_full (state->subsurface_placement_ops, g_free);
meta_wayland_surface_state_discard_presentation_feedback (state);
}
void
meta_wayland_surface_state_reset (MetaWaylandSurfaceState *state)
{
meta_wayland_surface_state_clear (state);
meta_wayland_surface_state_set_default (state);
}
void
meta_wayland_surface_state_merge_into (MetaWaylandSurfaceState *from,
MetaWaylandSurfaceState *to)
{
if (from->newly_attached)
{
if (to->buffer)
wayland/surface: Overhaul handling of buffer use count Move the use count from a separate MetaWaylandBufferRef struct to the MetaWaylandBuffer class, and remove the former. The buffer use count is now incremented already in meta_wayland_surface_commit, since the Wayland protocol defines the buffer to be in use by the compositor at that point. If the buffer attachment ends up being dropped again before it is applied to the surface state (e.g. because another buffer is committed to a synchronized sub-surface before the parent surface is committed), the use count is now decremented, and a buffer release event is sent if the use count drops to 0. Buffer release events were previously incorrectly not sent under these circumstances. Test case: Run the weston-subsurfaces demo with the -r1 and/or -t1 command line parameter. Resize the window. Before this change, weston-subsurfaces would freeze or abort after a few resize operations, because mutter failed to send release events and the client ran out of usable buffers. v2: * Handle NULL priv->buffer_ref in meta_wayland_cursor_surface_apply_state. v3: * Remove MetaWaylandBufferRef altogether, move the use count tracking to MetaWaylandBuffer itself. Much simpler, and doesn't run into lifetime issues when mutter shuts down. v4: * Warn if use count isn't 0 in meta_wayland_buffer_finalize. * Keep pending_buffer_resource_destroyed for attached but not yet committed buffers. If the client attaches a buffer and then destroys it before commit, we ignore the buffer attachement, same as before this MR. v5: * Rebase on top of new commit which splits up surface->texture. * MetaWaylandSurfaceState::buffer can only be non-NULL if ::newly_attached is TRUE, simplify accordingly. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1880>
2022-06-22 12:43:11 -04:00
{
g_warn_if_fail (to->buffer_destroy_handler_id == 0);
meta_wayland_buffer_dec_use_count (to->buffer);
g_object_unref (to->buffer);
}
to->newly_attached = TRUE;
wayland/surface: Overhaul handling of buffer use count Move the use count from a separate MetaWaylandBufferRef struct to the MetaWaylandBuffer class, and remove the former. The buffer use count is now incremented already in meta_wayland_surface_commit, since the Wayland protocol defines the buffer to be in use by the compositor at that point. If the buffer attachment ends up being dropped again before it is applied to the surface state (e.g. because another buffer is committed to a synchronized sub-surface before the parent surface is committed), the use count is now decremented, and a buffer release event is sent if the use count drops to 0. Buffer release events were previously incorrectly not sent under these circumstances. Test case: Run the weston-subsurfaces demo with the -r1 and/or -t1 command line parameter. Resize the window. Before this change, weston-subsurfaces would freeze or abort after a few resize operations, because mutter failed to send release events and the client ran out of usable buffers. v2: * Handle NULL priv->buffer_ref in meta_wayland_cursor_surface_apply_state. v3: * Remove MetaWaylandBufferRef altogether, move the use count tracking to MetaWaylandBuffer itself. Much simpler, and doesn't run into lifetime issues when mutter shuts down. v4: * Warn if use count isn't 0 in meta_wayland_buffer_finalize. * Keep pending_buffer_resource_destroyed for attached but not yet committed buffers. If the client attaches a buffer and then destroys it before commit, we ignore the buffer attachement, same as before this MR. v5: * Rebase on top of new commit which splits up surface->texture. * MetaWaylandSurfaceState::buffer can only be non-NULL if ::newly_attached is TRUE, simplify accordingly. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1880>
2022-06-22 12:43:11 -04:00
to->buffer = g_steal_pointer (&from->buffer);
cogl_clear_object (&to->texture);
to->texture = g_steal_pointer (&from->texture);
}
to->dx += from->dx;
to->dy += from->dy;
wl_list_insert_list (&to->frame_callback_list, &from->frame_callback_list);
wl_list_init (&from->frame_callback_list);
cairo_region_union (to->surface_damage, from->surface_damage);
cairo_region_union (to->buffer_damage, from->buffer_damage);
if (from->input_region_set)
{
if (to->input_region)
cairo_region_union (to->input_region, from->input_region);
else
to->input_region = cairo_region_reference (from->input_region);
to->input_region_set = TRUE;
}
if (from->opaque_region_set)
{
if (to->opaque_region)
cairo_region_union (to->opaque_region, from->opaque_region);
else
to->opaque_region = cairo_region_reference (from->opaque_region);
to->opaque_region_set = TRUE;
}
if (from->has_new_geometry)
{
to->new_geometry = from->new_geometry;
to->has_new_geometry = TRUE;
}
if (from->has_acked_configure_serial)
{
to->acked_configure_serial = from->acked_configure_serial;
to->has_acked_configure_serial = TRUE;
}
if (from->has_new_min_size)
{
to->new_min_width = from->new_min_width;
to->new_min_height = from->new_min_height;
to->has_new_min_size = TRUE;
}
if (from->has_new_max_size)
{
to->new_max_width = from->new_max_width;
to->new_max_height = from->new_max_height;
to->has_new_max_size = TRUE;
}
if (from->scale > 0)
to->scale = from->scale;
if (from->has_new_buffer_transform)
{
to->buffer_transform = from->buffer_transform;
to->has_new_buffer_transform = TRUE;
}
if (from->has_new_viewport_src_rect)
{
to->viewport_src_rect.origin.x = from->viewport_src_rect.origin.x;
to->viewport_src_rect.origin.y = from->viewport_src_rect.origin.y;
to->viewport_src_rect.size.width = from->viewport_src_rect.size.width;
to->viewport_src_rect.size.height = from->viewport_src_rect.size.height;
to->has_new_viewport_src_rect = TRUE;
}
if (from->has_new_viewport_dst_size)
{
to->viewport_dst_width = from->viewport_dst_width;
to->viewport_dst_height = from->viewport_dst_height;
to->has_new_viewport_dst_size = TRUE;
}
if (from->subsurface_placement_ops != NULL)
{
if (to->subsurface_placement_ops != NULL)
{
to->subsurface_placement_ops =
g_slist_concat (to->subsurface_placement_ops,
from->subsurface_placement_ops);
}
else
{
to->subsurface_placement_ops = from->subsurface_placement_ops;
}
from->subsurface_placement_ops = NULL;
}
/*
* A new commit indicates a new content update, so any previous
* content update did not go on screen and needs to be discarded.
*/
meta_wayland_surface_state_discard_presentation_feedback (to);
wl_list_insert_list (&to->presentation_feedback_list,
&from->presentation_feedback_list);
wl_list_init (&from->presentation_feedback_list);
if (from->xdg_positioner)
{
g_clear_pointer (&to->xdg_positioner, g_free);
to->xdg_positioner = g_steal_pointer (&from->xdg_positioner);
to->xdg_popup_reposition_token = from->xdg_popup_reposition_token;
}
}
static void
meta_wayland_surface_state_finalize (GObject *object)
{
MetaWaylandSurfaceState *state = META_WAYLAND_SURFACE_STATE (object);
meta_wayland_surface_state_clear (state);
G_OBJECT_CLASS (meta_wayland_surface_state_parent_class)->finalize (object);
}
static void
meta_wayland_surface_state_init (MetaWaylandSurfaceState *state)
{
meta_wayland_surface_state_set_default (state);
}
static void
meta_wayland_surface_state_class_init (MetaWaylandSurfaceStateClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = meta_wayland_surface_state_finalize;
surface_state_signals[SURFACE_STATE_SIGNAL_APPLIED] =
g_signal_new ("applied",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
0,
NULL, NULL, NULL,
G_TYPE_NONE, 0);
}
static void
meta_wayland_surface_discard_presentation_feedback (MetaWaylandSurface *surface)
{
while (!wl_list_empty (&surface->presentation_time.feedback_list))
{
MetaWaylandPresentationFeedback *feedback =
wl_container_of (surface->presentation_time.feedback_list.next,
feedback, link);
meta_wayland_presentation_feedback_discard (feedback);
}
}
wayland/surface: Use transactions for all sub-surface hierarchy changes And keep track of the hierarchy separately for the Wayland protocol and for output. Protocol state is updated immediately as protocol requests are processed, output state only when the corresponding transaction is applied (which may be deferred until the next commit of the parent surface). v2: * Directly add placement ops to a transaction, instead of going via pending_state. * Use transaction entry for the sub-surface instead of that for its parent surface. v3: * Use transaction entry for the parent surface again, to ensure proper ordering of placement ops, and call meta_wayland_surface_notify_subsurface_state_changed only once per parent surface. * Drop all use of wl_resource_add_destroy_listener, transactions are keeping surfaces alive as long as needed. v4: * Rebase on https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2501 * Drop ClutterActor code from meta_wayland_surface_apply_placement_ops. (Robert Mader) v5: * Rename MetaWaylandSubSurfaceState to MetaWaylandSurfaceSubState, since the next commit adds not sub-surface specific state to it. v6: * Move include of meta-wayland-subsurface.h from meta-wayland-transaction.c to .h, since the latter references MetaWaylandSubsurfacePlacementOp. v7: * Drop superfluous !entry check from meta_wayland_transaction_apply. v8: * Rename output/protocol fields to output/protocol_state. (Jonas Ådahl) v9: * Use meta_wayland_surface_state_new in meta_wayland_transaction_add_placement_op. v10: * Fix a few style issues per check-style.py. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1880>
2021-07-23 10:01:37 -04:00
void
meta_wayland_surface_apply_placement_ops (MetaWaylandSurface *parent,
MetaWaylandSurfaceState *state)
{
GSList *l;
for (l = state->subsurface_placement_ops; l; l = l->next)
{
MetaWaylandSubsurfacePlacementOp *op = l->data;
MetaWaylandSurface *surface = op->surface;
GNode *sibling_node;
g_node_unlink (surface->output_state.subsurface_branch_node);
if (!op->sibling)
{
surface->output_state.parent = NULL;
continue;
}
surface->output_state.parent = parent;
if (op->sibling == parent)
sibling_node = parent->output_state.subsurface_leaf_node;
else
sibling_node = op->sibling->output_state.subsurface_branch_node;
switch (op->placement)
{
case META_WAYLAND_SUBSURFACE_PLACEMENT_ABOVE:
g_node_insert_after (parent->output_state.subsurface_branch_node,
sibling_node,
surface->output_state.subsurface_branch_node);
break;
case META_WAYLAND_SUBSURFACE_PLACEMENT_BELOW:
g_node_insert_before (parent->output_state.subsurface_branch_node,
sibling_node,
surface->output_state.subsurface_branch_node);
break;
}
}
}
void
meta_wayland_surface_apply_state (MetaWaylandSurface *surface,
MetaWaylandSurfaceState *state)
{
gboolean had_damage = FALSE;
int old_width, old_height;
old_width = meta_wayland_surface_get_width (surface);
old_height = meta_wayland_surface_get_height (surface);
g_signal_emit (surface, surface_signals[SURFACE_PRE_STATE_APPLIED], 0);
if (surface->role)
{
meta_wayland_surface_role_pre_apply_state (surface->role, state);
}
else
{
if (state->newly_attached && surface->unassigned.buffer)
{
wayland/surface: Overhaul handling of buffer use count Move the use count from a separate MetaWaylandBufferRef struct to the MetaWaylandBuffer class, and remove the former. The buffer use count is now incremented already in meta_wayland_surface_commit, since the Wayland protocol defines the buffer to be in use by the compositor at that point. If the buffer attachment ends up being dropped again before it is applied to the surface state (e.g. because another buffer is committed to a synchronized sub-surface before the parent surface is committed), the use count is now decremented, and a buffer release event is sent if the use count drops to 0. Buffer release events were previously incorrectly not sent under these circumstances. Test case: Run the weston-subsurfaces demo with the -r1 and/or -t1 command line parameter. Resize the window. Before this change, weston-subsurfaces would freeze or abort after a few resize operations, because mutter failed to send release events and the client ran out of usable buffers. v2: * Handle NULL priv->buffer_ref in meta_wayland_cursor_surface_apply_state. v3: * Remove MetaWaylandBufferRef altogether, move the use count tracking to MetaWaylandBuffer itself. Much simpler, and doesn't run into lifetime issues when mutter shuts down. v4: * Warn if use count isn't 0 in meta_wayland_buffer_finalize. * Keep pending_buffer_resource_destroyed for attached but not yet committed buffers. If the client attaches a buffer and then destroys it before commit, we ignore the buffer attachement, same as before this MR. v5: * Rebase on top of new commit which splits up surface->texture. * MetaWaylandSurfaceState::buffer can only be non-NULL if ::newly_attached is TRUE, simplify accordingly. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1880>
2022-06-22 12:43:11 -04:00
meta_wayland_buffer_dec_use_count (surface->unassigned.buffer);
g_clear_object (&surface->unassigned.buffer);
}
}
if (state->newly_attached)
{
/* Always release any previously held buffer. If the buffer held is same
* as the newly attached buffer, we still need to release it here, because
* wl_surface.attach+commit and wl_buffer.release on the attached buffer
* is symmetric.
*/
if (surface->buffer_held)
wayland/surface: Overhaul handling of buffer use count Move the use count from a separate MetaWaylandBufferRef struct to the MetaWaylandBuffer class, and remove the former. The buffer use count is now incremented already in meta_wayland_surface_commit, since the Wayland protocol defines the buffer to be in use by the compositor at that point. If the buffer attachment ends up being dropped again before it is applied to the surface state (e.g. because another buffer is committed to a synchronized sub-surface before the parent surface is committed), the use count is now decremented, and a buffer release event is sent if the use count drops to 0. Buffer release events were previously incorrectly not sent under these circumstances. Test case: Run the weston-subsurfaces demo with the -r1 and/or -t1 command line parameter. Resize the window. Before this change, weston-subsurfaces would freeze or abort after a few resize operations, because mutter failed to send release events and the client ran out of usable buffers. v2: * Handle NULL priv->buffer_ref in meta_wayland_cursor_surface_apply_state. v3: * Remove MetaWaylandBufferRef altogether, move the use count tracking to MetaWaylandBuffer itself. Much simpler, and doesn't run into lifetime issues when mutter shuts down. v4: * Warn if use count isn't 0 in meta_wayland_buffer_finalize. * Keep pending_buffer_resource_destroyed for attached but not yet committed buffers. If the client attaches a buffer and then destroys it before commit, we ignore the buffer attachement, same as before this MR. v5: * Rebase on top of new commit which splits up surface->texture. * MetaWaylandSurfaceState::buffer can only be non-NULL if ::newly_attached is TRUE, simplify accordingly. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1880>
2022-06-22 12:43:11 -04:00
meta_wayland_buffer_dec_use_count (surface->buffer);
wayland/surface: Overhaul handling of buffer use count Move the use count from a separate MetaWaylandBufferRef struct to the MetaWaylandBuffer class, and remove the former. The buffer use count is now incremented already in meta_wayland_surface_commit, since the Wayland protocol defines the buffer to be in use by the compositor at that point. If the buffer attachment ends up being dropped again before it is applied to the surface state (e.g. because another buffer is committed to a synchronized sub-surface before the parent surface is committed), the use count is now decremented, and a buffer release event is sent if the use count drops to 0. Buffer release events were previously incorrectly not sent under these circumstances. Test case: Run the weston-subsurfaces demo with the -r1 and/or -t1 command line parameter. Resize the window. Before this change, weston-subsurfaces would freeze or abort after a few resize operations, because mutter failed to send release events and the client ran out of usable buffers. v2: * Handle NULL priv->buffer_ref in meta_wayland_cursor_surface_apply_state. v3: * Remove MetaWaylandBufferRef altogether, move the use count tracking to MetaWaylandBuffer itself. Much simpler, and doesn't run into lifetime issues when mutter shuts down. v4: * Warn if use count isn't 0 in meta_wayland_buffer_finalize. * Keep pending_buffer_resource_destroyed for attached but not yet committed buffers. If the client attaches a buffer and then destroys it before commit, we ignore the buffer attachement, same as before this MR. v5: * Rebase on top of new commit which splits up surface->texture. * MetaWaylandSurfaceState::buffer can only be non-NULL if ::newly_attached is TRUE, simplify accordingly. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1880>
2022-06-22 12:43:11 -04:00
g_set_object (&surface->buffer, state->buffer);
cogl_clear_object (&surface->output_state.texture);
surface->output_state.texture = g_steal_pointer (&state->texture);
/* If the newly attached buffer is going to be accessed directly without
* making a copy, such as an EGL buffer, mark it as in-use don't release
* it until is replaced by a subsequent wl_surface.commit or when the
* wl_surface is destroyed.
*/
surface->buffer_held =
(state->buffer &&
(state->buffer->type != META_WAYLAND_BUFFER_TYPE_SHM &&
state->buffer->type != META_WAYLAND_BUFFER_TYPE_SINGLE_PIXEL));
}
if (state->scale > 0)
surface->scale = state->scale;
if ((get_buffer_width (surface) % surface->scale != 0) ||
(get_buffer_height (surface) % surface->scale != 0))
{
struct wl_resource *resource = surface->resource;
pid_t pid;
wl_client_get_credentials (wl_resource_get_client (resource), &pid, NULL,
NULL);
g_warning ("Bug in client with pid %ld: Buffer size (%dx%d) is not an"
"integer multiple of the buffer_scale (%d).", (long) pid,
get_buffer_width (surface), get_buffer_height (surface),
surface->scale);
}
if (state->has_new_buffer_transform)
surface->buffer_transform = state->buffer_transform;
if (state->has_new_viewport_src_rect)
{
surface->viewport.src_rect.origin.x = state->viewport_src_rect.origin.x;
surface->viewport.src_rect.origin.y = state->viewport_src_rect.origin.y;
surface->viewport.src_rect.size.width = state->viewport_src_rect.size.width;
surface->viewport.src_rect.size.height = state->viewport_src_rect.size.height;
surface->viewport.has_src_rect = surface->viewport.src_rect.size.width > 0;
}
if (state->has_new_viewport_dst_size)
{
surface->viewport.dst_width = state->viewport_dst_width;
surface->viewport.dst_height = state->viewport_dst_height;
surface->viewport.has_dst_size = surface->viewport.dst_width > 0;
}
state->derived.surface_size_changed =
meta_wayland_surface_get_width (surface) != old_width ||
meta_wayland_surface_get_height (surface) != old_height;
if (!cairo_region_is_empty (state->surface_damage) ||
!cairo_region_is_empty (state->buffer_damage))
{
surface_process_damage (surface,
state->surface_damage,
state->buffer_damage);
had_damage = TRUE;
}
surface->offset_x += state->dx;
surface->offset_y += state->dy;
if (state->opaque_region_set)
{
if (surface->opaque_region)
cairo_region_destroy (surface->opaque_region);
if (state->opaque_region)
surface->opaque_region = cairo_region_reference (state->opaque_region);
else
surface->opaque_region = NULL;
}
if (state->input_region_set)
{
if (surface->input_region)
cairo_region_destroy (surface->input_region);
if (state->input_region)
surface->input_region = cairo_region_reference (state->input_region);
else
surface->input_region = NULL;
}
/*
* A new commit indicates a new content update, so any previous
* content update did not go on screen and needs to be discarded.
*/
meta_wayland_surface_discard_presentation_feedback (surface);
wl_list_insert_list (&surface->presentation_time.feedback_list,
&state->presentation_feedback_list);
wl_list_init (&state->presentation_feedback_list);
if (!wl_list_empty (&surface->presentation_time.feedback_list))
meta_wayland_compositor_add_presentation_feedback_surface (surface->compositor,
surface);
if (surface->role)
{
meta_wayland_surface_role_apply_state (surface->role, state);
g_assert (wl_list_empty (&state->frame_callback_list));
}
else
{
wl_list_insert_list (surface->unassigned.pending_frame_callback_list.prev,
&state->frame_callback_list);
wl_list_init (&state->frame_callback_list);
wayland/surface: Overhaul handling of buffer use count Move the use count from a separate MetaWaylandBufferRef struct to the MetaWaylandBuffer class, and remove the former. The buffer use count is now incremented already in meta_wayland_surface_commit, since the Wayland protocol defines the buffer to be in use by the compositor at that point. If the buffer attachment ends up being dropped again before it is applied to the surface state (e.g. because another buffer is committed to a synchronized sub-surface before the parent surface is committed), the use count is now decremented, and a buffer release event is sent if the use count drops to 0. Buffer release events were previously incorrectly not sent under these circumstances. Test case: Run the weston-subsurfaces demo with the -r1 and/or -t1 command line parameter. Resize the window. Before this change, weston-subsurfaces would freeze or abort after a few resize operations, because mutter failed to send release events and the client ran out of usable buffers. v2: * Handle NULL priv->buffer_ref in meta_wayland_cursor_surface_apply_state. v3: * Remove MetaWaylandBufferRef altogether, move the use count tracking to MetaWaylandBuffer itself. Much simpler, and doesn't run into lifetime issues when mutter shuts down. v4: * Warn if use count isn't 0 in meta_wayland_buffer_finalize. * Keep pending_buffer_resource_destroyed for attached but not yet committed buffers. If the client attaches a buffer and then destroys it before commit, we ignore the buffer attachement, same as before this MR. v5: * Rebase on top of new commit which splits up surface->texture. * MetaWaylandSurfaceState::buffer can only be non-NULL if ::newly_attached is TRUE, simplify accordingly. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1880>
2022-06-22 12:43:11 -04:00
if (state->buffer)
{
/* The need to keep the wl_buffer from being released depends on what
* role the surface is given. That means we need to also keep a use
* count for wl_buffer's that are used by unassigned wl_surface's.
*/
wayland/surface: Overhaul handling of buffer use count Move the use count from a separate MetaWaylandBufferRef struct to the MetaWaylandBuffer class, and remove the former. The buffer use count is now incremented already in meta_wayland_surface_commit, since the Wayland protocol defines the buffer to be in use by the compositor at that point. If the buffer attachment ends up being dropped again before it is applied to the surface state (e.g. because another buffer is committed to a synchronized sub-surface before the parent surface is committed), the use count is now decremented, and a buffer release event is sent if the use count drops to 0. Buffer release events were previously incorrectly not sent under these circumstances. Test case: Run the weston-subsurfaces demo with the -r1 and/or -t1 command line parameter. Resize the window. Before this change, weston-subsurfaces would freeze or abort after a few resize operations, because mutter failed to send release events and the client ran out of usable buffers. v2: * Handle NULL priv->buffer_ref in meta_wayland_cursor_surface_apply_state. v3: * Remove MetaWaylandBufferRef altogether, move the use count tracking to MetaWaylandBuffer itself. Much simpler, and doesn't run into lifetime issues when mutter shuts down. v4: * Warn if use count isn't 0 in meta_wayland_buffer_finalize. * Keep pending_buffer_resource_destroyed for attached but not yet committed buffers. If the client attaches a buffer and then destroys it before commit, we ignore the buffer attachement, same as before this MR. v5: * Rebase on top of new commit which splits up surface->texture. * MetaWaylandSurfaceState::buffer can only be non-NULL if ::newly_attached is TRUE, simplify accordingly. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1880>
2022-06-22 12:43:11 -04:00
surface->unassigned.buffer = g_object_ref (state->buffer);
meta_wayland_buffer_inc_use_count (surface->unassigned.buffer);
}
}
if (state->subsurface_placement_ops)
wayland/surface: Use transactions for all sub-surface hierarchy changes And keep track of the hierarchy separately for the Wayland protocol and for output. Protocol state is updated immediately as protocol requests are processed, output state only when the corresponding transaction is applied (which may be deferred until the next commit of the parent surface). v2: * Directly add placement ops to a transaction, instead of going via pending_state. * Use transaction entry for the sub-surface instead of that for its parent surface. v3: * Use transaction entry for the parent surface again, to ensure proper ordering of placement ops, and call meta_wayland_surface_notify_subsurface_state_changed only once per parent surface. * Drop all use of wl_resource_add_destroy_listener, transactions are keeping surfaces alive as long as needed. v4: * Rebase on https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2501 * Drop ClutterActor code from meta_wayland_surface_apply_placement_ops. (Robert Mader) v5: * Rename MetaWaylandSubSurfaceState to MetaWaylandSurfaceSubState, since the next commit adds not sub-surface specific state to it. v6: * Move include of meta-wayland-subsurface.h from meta-wayland-transaction.c to .h, since the latter references MetaWaylandSubsurfacePlacementOp. v7: * Drop superfluous !entry check from meta_wayland_transaction_apply. v8: * Rename output/protocol fields to output/protocol_state. (Jonas Ådahl) v9: * Use meta_wayland_surface_state_new in meta_wayland_transaction_add_placement_op. v10: * Fix a few style issues per check-style.py. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1880>
2021-07-23 10:01:37 -04:00
meta_wayland_surface_notify_subsurface_state_changed (surface);
wayland/surface: Overhaul handling of buffer use count Move the use count from a separate MetaWaylandBufferRef struct to the MetaWaylandBuffer class, and remove the former. The buffer use count is now incremented already in meta_wayland_surface_commit, since the Wayland protocol defines the buffer to be in use by the compositor at that point. If the buffer attachment ends up being dropped again before it is applied to the surface state (e.g. because another buffer is committed to a synchronized sub-surface before the parent surface is committed), the use count is now decremented, and a buffer release event is sent if the use count drops to 0. Buffer release events were previously incorrectly not sent under these circumstances. Test case: Run the weston-subsurfaces demo with the -r1 and/or -t1 command line parameter. Resize the window. Before this change, weston-subsurfaces would freeze or abort after a few resize operations, because mutter failed to send release events and the client ran out of usable buffers. v2: * Handle NULL priv->buffer_ref in meta_wayland_cursor_surface_apply_state. v3: * Remove MetaWaylandBufferRef altogether, move the use count tracking to MetaWaylandBuffer itself. Much simpler, and doesn't run into lifetime issues when mutter shuts down. v4: * Warn if use count isn't 0 in meta_wayland_buffer_finalize. * Keep pending_buffer_resource_destroyed for attached but not yet committed buffers. If the client attaches a buffer and then destroys it before commit, we ignore the buffer attachement, same as before this MR. v5: * Rebase on top of new commit which splits up surface->texture. * MetaWaylandSurfaceState::buffer can only be non-NULL if ::newly_attached is TRUE, simplify accordingly. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1880>
2022-06-22 12:43:11 -04:00
/* If we need to hold the newly attached buffer, drop its reference from the
* state, to prevent meta_wayland_transaction_entry_destroy from decreasing
* the use count.
*/
wayland/surface: Overhaul handling of buffer use count Move the use count from a separate MetaWaylandBufferRef struct to the MetaWaylandBuffer class, and remove the former. The buffer use count is now incremented already in meta_wayland_surface_commit, since the Wayland protocol defines the buffer to be in use by the compositor at that point. If the buffer attachment ends up being dropped again before it is applied to the surface state (e.g. because another buffer is committed to a synchronized sub-surface before the parent surface is committed), the use count is now decremented, and a buffer release event is sent if the use count drops to 0. Buffer release events were previously incorrectly not sent under these circumstances. Test case: Run the weston-subsurfaces demo with the -r1 and/or -t1 command line parameter. Resize the window. Before this change, weston-subsurfaces would freeze or abort after a few resize operations, because mutter failed to send release events and the client ran out of usable buffers. v2: * Handle NULL priv->buffer_ref in meta_wayland_cursor_surface_apply_state. v3: * Remove MetaWaylandBufferRef altogether, move the use count tracking to MetaWaylandBuffer itself. Much simpler, and doesn't run into lifetime issues when mutter shuts down. v4: * Warn if use count isn't 0 in meta_wayland_buffer_finalize. * Keep pending_buffer_resource_destroyed for attached but not yet committed buffers. If the client attaches a buffer and then destroys it before commit, we ignore the buffer attachement, same as before this MR. v5: * Rebase on top of new commit which splits up surface->texture. * MetaWaylandSurfaceState::buffer can only be non-NULL if ::newly_attached is TRUE, simplify accordingly. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1880>
2022-06-22 12:43:11 -04:00
if (state->newly_attached && surface->buffer_held)
g_clear_object (&state->buffer);
g_signal_emit (state,
surface_state_signals[SURFACE_STATE_SIGNAL_APPLIED],
0);
if (had_damage)
{
MetaWindow *toplevel_window;
toplevel_window = meta_wayland_surface_get_toplevel_window (surface);
if (toplevel_window)
{
MetaWindowActor *toplevel_window_actor;
toplevel_window_actor =
meta_window_actor_from_window (toplevel_window);
if (toplevel_window_actor)
meta_window_actor_notify_damaged (toplevel_window_actor);
}
}
if (surface->role)
meta_wayland_surface_role_post_apply_state (surface->role, state);
}
MetaWaylandSurfaceState *
meta_wayland_surface_get_pending_state (MetaWaylandSurface *surface)
{
return surface->pending_state;
}
MetaWaylandTransaction *
meta_wayland_surface_ensure_transaction (MetaWaylandSurface *surface)
{
if (!surface->sub.transaction)
surface->sub.transaction = meta_wayland_transaction_new (surface->compositor);
return surface->sub.transaction;
}
static void
meta_wayland_surface_commit (MetaWaylandSurface *surface)
{
MetaWaylandSurfaceState *pending = surface->pending_state;
MetaWaylandBuffer *buffer = pending->buffer;
MetaWaylandTransaction *transaction;
MetaWaylandSurface *subsurface_surface;
COGL_TRACE_BEGIN_SCOPED (MetaWaylandSurfaceCommit,
"WaylandSurface (commit)");
if (buffer)
{
g_autoptr (GError) error = NULL;
wayland/surface: Overhaul handling of buffer use count Move the use count from a separate MetaWaylandBufferRef struct to the MetaWaylandBuffer class, and remove the former. The buffer use count is now incremented already in meta_wayland_surface_commit, since the Wayland protocol defines the buffer to be in use by the compositor at that point. If the buffer attachment ends up being dropped again before it is applied to the surface state (e.g. because another buffer is committed to a synchronized sub-surface before the parent surface is committed), the use count is now decremented, and a buffer release event is sent if the use count drops to 0. Buffer release events were previously incorrectly not sent under these circumstances. Test case: Run the weston-subsurfaces demo with the -r1 and/or -t1 command line parameter. Resize the window. Before this change, weston-subsurfaces would freeze or abort after a few resize operations, because mutter failed to send release events and the client ran out of usable buffers. v2: * Handle NULL priv->buffer_ref in meta_wayland_cursor_surface_apply_state. v3: * Remove MetaWaylandBufferRef altogether, move the use count tracking to MetaWaylandBuffer itself. Much simpler, and doesn't run into lifetime issues when mutter shuts down. v4: * Warn if use count isn't 0 in meta_wayland_buffer_finalize. * Keep pending_buffer_resource_destroyed for attached but not yet committed buffers. If the client attaches a buffer and then destroys it before commit, we ignore the buffer attachement, same as before this MR. v5: * Rebase on top of new commit which splits up surface->texture. * MetaWaylandSurfaceState::buffer can only be non-NULL if ::newly_attached is TRUE, simplify accordingly. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1880>
2022-06-22 12:43:11 -04:00
g_clear_signal_handler (&pending->buffer_destroy_handler_id,
buffer);
if (!meta_wayland_buffer_is_realized (buffer))
meta_wayland_buffer_realize (buffer);
if (!meta_wayland_buffer_attach (buffer,
&surface->protocol_state.texture,
&error))
{
g_warning ("Could not import pending buffer: %s", error->message);
wl_resource_post_error (surface->resource, WL_DISPLAY_ERROR_NO_MEMORY,
"Failed to attach buffer to surface %i: %s",
wl_resource_get_id (surface->resource),
error->message);
return;
}
pending->texture = cogl_object_ref (surface->protocol_state.texture);
wayland/surface: Overhaul handling of buffer use count Move the use count from a separate MetaWaylandBufferRef struct to the MetaWaylandBuffer class, and remove the former. The buffer use count is now incremented already in meta_wayland_surface_commit, since the Wayland protocol defines the buffer to be in use by the compositor at that point. If the buffer attachment ends up being dropped again before it is applied to the surface state (e.g. because another buffer is committed to a synchronized sub-surface before the parent surface is committed), the use count is now decremented, and a buffer release event is sent if the use count drops to 0. Buffer release events were previously incorrectly not sent under these circumstances. Test case: Run the weston-subsurfaces demo with the -r1 and/or -t1 command line parameter. Resize the window. Before this change, weston-subsurfaces would freeze or abort after a few resize operations, because mutter failed to send release events and the client ran out of usable buffers. v2: * Handle NULL priv->buffer_ref in meta_wayland_cursor_surface_apply_state. v3: * Remove MetaWaylandBufferRef altogether, move the use count tracking to MetaWaylandBuffer itself. Much simpler, and doesn't run into lifetime issues when mutter shuts down. v4: * Warn if use count isn't 0 in meta_wayland_buffer_finalize. * Keep pending_buffer_resource_destroyed for attached but not yet committed buffers. If the client attaches a buffer and then destroys it before commit, we ignore the buffer attachement, same as before this MR. v5: * Rebase on top of new commit which splits up surface->texture. * MetaWaylandSurfaceState::buffer can only be non-NULL if ::newly_attached is TRUE, simplify accordingly. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1880>
2022-06-22 12:43:11 -04:00
g_object_ref (buffer);
meta_wayland_buffer_inc_use_count (buffer);
}
else if (pending->newly_attached)
{
cogl_clear_object (&surface->protocol_state.texture);
}
if (meta_wayland_surface_is_synchronized (surface))
transaction = meta_wayland_surface_ensure_transaction (surface);
else
transaction = meta_wayland_transaction_new (surface->compositor);
if (surface->role)
meta_wayland_surface_role_commit_state (surface->role, transaction, pending);
meta_wayland_transaction_merge_pending_state (transaction, surface);
wayland/surface: Use transactions for all sub-surface hierarchy changes And keep track of the hierarchy separately for the Wayland protocol and for output. Protocol state is updated immediately as protocol requests are processed, output state only when the corresponding transaction is applied (which may be deferred until the next commit of the parent surface). v2: * Directly add placement ops to a transaction, instead of going via pending_state. * Use transaction entry for the sub-surface instead of that for its parent surface. v3: * Use transaction entry for the parent surface again, to ensure proper ordering of placement ops, and call meta_wayland_surface_notify_subsurface_state_changed only once per parent surface. * Drop all use of wl_resource_add_destroy_listener, transactions are keeping surfaces alive as long as needed. v4: * Rebase on https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2501 * Drop ClutterActor code from meta_wayland_surface_apply_placement_ops. (Robert Mader) v5: * Rename MetaWaylandSubSurfaceState to MetaWaylandSurfaceSubState, since the next commit adds not sub-surface specific state to it. v6: * Move include of meta-wayland-subsurface.h from meta-wayland-transaction.c to .h, since the latter references MetaWaylandSubsurfacePlacementOp. v7: * Drop superfluous !entry check from meta_wayland_transaction_apply. v8: * Rename output/protocol fields to output/protocol_state. (Jonas Ådahl) v9: * Use meta_wayland_surface_state_new in meta_wayland_transaction_add_placement_op. v10: * Fix a few style issues per check-style.py. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1880>
2021-07-23 10:01:37 -04:00
META_WAYLAND_SURFACE_FOREACH_SUBSURFACE (&surface->protocol_state,
subsurface_surface)
{
if (!subsurface_surface->sub.transaction)
continue;
meta_wayland_transaction_merge_into (subsurface_surface->sub.transaction,
transaction);
subsurface_surface->sub.transaction = NULL;
}
/*
* If this is a sub-surface and it is in effective synchronous mode, only
* cache the pending surface state until either one of the following two
* scenarios happens:
* 1) Its parent surface gets its state applied.
* 2) Its mode changes from synchronized to desynchronized and its parent
* surface is in effective desynchronized mode.
*/
if (!meta_wayland_surface_is_synchronized (surface))
meta_wayland_transaction_commit (transaction);
}
static void
wl_surface_destroy (struct wl_client *client,
struct wl_resource *resource)
{
wl_resource_destroy (resource);
}
static void
wl_surface_attach (struct wl_client *client,
struct wl_resource *surface_resource,
struct wl_resource *buffer_resource,
int32_t dx,
int32_t dy)
{
MetaWaylandSurface *surface =
wl_resource_get_user_data (surface_resource);
MetaWaylandCompositor *compositor = surface->compositor;
MetaWaylandSurfaceState *pending = surface->pending_state;
MetaWaylandBuffer *buffer;
if (buffer_resource)
buffer = meta_wayland_buffer_from_resource (compositor, buffer_resource);
else
buffer = NULL;
if (surface->pending_state->buffer)
{
g_clear_signal_handler (&pending->buffer_destroy_handler_id,
pending->buffer);
}
if (wl_resource_get_version (surface_resource) >=
WL_SURFACE_OFFSET_SINCE_VERSION &&
(dx != 0 || dy != 0))
{
wl_resource_post_error (surface_resource,
WL_SURFACE_ERROR_INVALID_OFFSET,
"Attaching with an offset is no longer allowed");
return;
}
pending->newly_attached = TRUE;
pending->buffer = buffer;
pending->dx = dx;
pending->dy = dy;
if (buffer)
{
pending->buffer_destroy_handler_id =
g_signal_connect (buffer, "resource-destroyed",
G_CALLBACK (pending_buffer_resource_destroyed),
pending);
}
}
static void
wl_surface_damage (struct wl_client *client,
struct wl_resource *surface_resource,
int32_t x,
int32_t y,
int32_t width,
int32_t height)
{
MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource);
MetaWaylandSurfaceState *pending = surface->pending_state;
cairo_rectangle_int_t rectangle;
rectangle = (cairo_rectangle_int_t) {
.x = x,
.y = y,
.width = width,
.height = height
};
cairo_region_union_rectangle (pending->surface_damage, &rectangle);
}
static void
destroy_frame_callback (struct wl_resource *callback_resource)
{
MetaWaylandFrameCallback *callback =
wl_resource_get_user_data (callback_resource);
wl_list_remove (&callback->link);
g_free (callback);
}
static void
wl_surface_frame (struct wl_client *client,
struct wl_resource *surface_resource,
uint32_t callback_id)
{
MetaWaylandFrameCallback *callback;
MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource);
MetaWaylandSurfaceState *pending = surface->pending_state;
callback = g_new0 (MetaWaylandFrameCallback, 1);
callback->surface = surface;
callback->resource = wl_resource_create (client,
&wl_callback_interface,
META_WL_CALLBACK_VERSION,
callback_id);
wl_resource_set_implementation (callback->resource, NULL, callback,
destroy_frame_callback);
wl_list_insert (pending->frame_callback_list.prev, &callback->link);
}
static void
wl_surface_set_opaque_region (struct wl_client *client,
struct wl_resource *surface_resource,
struct wl_resource *region_resource)
{
MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource);
MetaWaylandSurfaceState *pending = surface->pending_state;
g_clear_pointer (&pending->opaque_region, cairo_region_destroy);
if (region_resource)
{
MetaWaylandRegion *region = wl_resource_get_user_data (region_resource);
cairo_region_t *cr_region = meta_wayland_region_peek_cairo_region (region);
pending->opaque_region = cairo_region_copy (cr_region);
}
pending->opaque_region_set = TRUE;
}
static void
wl_surface_set_input_region (struct wl_client *client,
struct wl_resource *surface_resource,
struct wl_resource *region_resource)
{
MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource);
MetaWaylandSurfaceState *pending = surface->pending_state;
g_clear_pointer (&pending->input_region, cairo_region_destroy);
if (region_resource)
{
MetaWaylandRegion *region = wl_resource_get_user_data (region_resource);
cairo_region_t *cr_region = meta_wayland_region_peek_cairo_region (region);
pending->input_region = cairo_region_copy (cr_region);
}
pending->input_region_set = TRUE;
}
static void
wl_surface_commit (struct wl_client *client,
struct wl_resource *resource)
{
MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
meta_wayland_surface_commit (surface);
}
static MetaMonitorTransform
transform_from_wl_output_transform (int32_t transform_value)
{
enum wl_output_transform transform = transform_value;
switch (transform)
{
case WL_OUTPUT_TRANSFORM_NORMAL:
return META_MONITOR_TRANSFORM_NORMAL;
case WL_OUTPUT_TRANSFORM_90:
return META_MONITOR_TRANSFORM_90;
case WL_OUTPUT_TRANSFORM_180:
return META_MONITOR_TRANSFORM_180;
case WL_OUTPUT_TRANSFORM_270:
return META_MONITOR_TRANSFORM_270;
case WL_OUTPUT_TRANSFORM_FLIPPED:
return META_MONITOR_TRANSFORM_FLIPPED;
case WL_OUTPUT_TRANSFORM_FLIPPED_90:
return META_MONITOR_TRANSFORM_FLIPPED_90;
case WL_OUTPUT_TRANSFORM_FLIPPED_180:
return META_MONITOR_TRANSFORM_FLIPPED_180;
case WL_OUTPUT_TRANSFORM_FLIPPED_270:
return META_MONITOR_TRANSFORM_FLIPPED_270;
default:
return -1;
}
}
static void
wl_surface_set_buffer_transform (struct wl_client *client,
struct wl_resource *resource,
int32_t transform)
{
MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
MetaWaylandSurfaceState *pending = surface->pending_state;
MetaMonitorTransform buffer_transform;
buffer_transform = transform_from_wl_output_transform (transform);
if (buffer_transform == -1)
{
wl_resource_post_error (resource,
WL_SURFACE_ERROR_INVALID_TRANSFORM,
"Trying to set invalid buffer_transform of %d",
transform);
return;
}
pending->buffer_transform = buffer_transform;
pending->has_new_buffer_transform = TRUE;
}
static void
wl_surface_set_buffer_scale (struct wl_client *client,
struct wl_resource *resource,
int scale)
{
MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
MetaWaylandSurfaceState *pending = surface->pending_state;
if (scale <= 0)
{
wl_resource_post_error (resource,
WL_SURFACE_ERROR_INVALID_SCALE,
"Trying to set invalid buffer_scale of %d",
scale);
return;
}
pending->scale = scale;
}
static void
wl_surface_damage_buffer (struct wl_client *client,
struct wl_resource *surface_resource,
int32_t x,
int32_t y,
int32_t width,
int32_t height)
{
MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource);
MetaWaylandSurfaceState *pending = surface->pending_state;
cairo_rectangle_int_t rectangle;
rectangle = (cairo_rectangle_int_t) {
.x = x,
.y = y,
.width = width,
.height = height
};
cairo_region_union_rectangle (pending->buffer_damage, &rectangle);
}
static void
wl_surface_offset (struct wl_client *client,
struct wl_resource *surface_resource,
int32_t dx,
int32_t dy)
{
MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource);
MetaWaylandSurfaceState *pending = surface->pending_state;
pending->dx = dx;
pending->dy = dy;
}
static const struct wl_surface_interface meta_wayland_wl_surface_interface = {
wl_surface_destroy,
wl_surface_attach,
wl_surface_damage,
wl_surface_frame,
wl_surface_set_opaque_region,
wl_surface_set_input_region,
wl_surface_commit,
wl_surface_set_buffer_transform,
wl_surface_set_buffer_scale,
wl_surface_damage_buffer,
wl_surface_offset,
};
static void
handle_output_destroyed (MetaWaylandOutput *wayland_output,
MetaWaylandSurface *surface)
{
set_surface_is_on_output (surface, wayland_output, FALSE);
}
static void
handle_output_bound (MetaWaylandOutput *wayland_output,
struct wl_resource *output_resource,
MetaWaylandSurface *surface)
{
if (wl_resource_get_client (output_resource) ==
wl_resource_get_client (surface->resource))
wl_surface_send_enter (surface->resource, output_resource);
}
static void
surface_entered_output (MetaWaylandSurface *surface,
MetaWaylandOutput *wayland_output)
{
g_signal_connect (wayland_output, "output-destroyed",
G_CALLBACK (handle_output_destroyed),
surface);
if (surface->resource)
{
const GList *l;
for (l = meta_wayland_output_get_resources (wayland_output); l; l = l->next)
{
struct wl_resource *resource = l->data;
if (wl_resource_get_client (resource) !=
wl_resource_get_client (surface->resource))
continue;
wl_surface_send_enter (surface->resource, resource);
}
}
g_signal_connect (wayland_output, "output-bound",
G_CALLBACK (handle_output_bound),
surface);
}
static void
surface_left_output (MetaWaylandSurface *surface,
MetaWaylandOutput *wayland_output)
{
const GList *l;
g_signal_handlers_disconnect_by_func (wayland_output,
G_CALLBACK (handle_output_destroyed),
surface);
g_signal_handlers_disconnect_by_func (wayland_output,
G_CALLBACK (handle_output_bound),
surface);
if (!surface->resource)
return;
for (l = meta_wayland_output_get_resources (wayland_output); l; l = l->next)
{
struct wl_resource *resource = l->data;
if (wl_resource_get_client (resource) !=
wl_resource_get_client (surface->resource))
continue;
wl_surface_send_leave (surface->resource, resource);
}
}
static void
set_surface_is_on_output (MetaWaylandSurface *surface,
MetaWaylandOutput *wayland_output,
gboolean is_on_output)
{
gboolean was_on_output;
was_on_output = g_hash_table_contains (surface->outputs, wayland_output);
if (!was_on_output && is_on_output)
{
g_hash_table_add (surface->outputs, wayland_output);
surface_entered_output (surface, wayland_output);
}
else if (was_on_output && !is_on_output)
{
g_hash_table_remove (surface->outputs, wayland_output);
surface_left_output (surface, wayland_output);
}
}
static void
update_surface_output_state (gpointer key, gpointer value, gpointer user_data)
{
MetaWaylandOutput *wayland_output = value;
MetaWaylandSurface *surface = user_data;
MetaLogicalMonitor *logical_monitor;
gboolean is_on_logical_monitor;
g_assert (surface->role);
logical_monitor = meta_wayland_output_get_logical_monitor (wayland_output);
if (!logical_monitor)
{
set_surface_is_on_output (surface, wayland_output, FALSE);
return;
}
is_on_logical_monitor =
meta_wayland_surface_role_is_on_logical_monitor (surface->role,
logical_monitor);
set_surface_is_on_output (surface, wayland_output, is_on_logical_monitor);
}
static void
surface_output_disconnect_signals (gpointer key,
gpointer value,
gpointer user_data)
{
MetaWaylandOutput *wayland_output = key;
MetaWaylandSurface *surface = user_data;
g_signal_handlers_disconnect_by_func (wayland_output,
G_CALLBACK (handle_output_destroyed),
surface);
g_signal_handlers_disconnect_by_func (wayland_output,
G_CALLBACK (handle_output_bound),
surface);
}
void
meta_wayland_surface_update_outputs (MetaWaylandSurface *surface)
{
if (!surface->compositor)
return;
g_hash_table_foreach (surface->compositor->outputs,
update_surface_output_state,
surface);
}
void
meta_wayland_surface_notify_unmapped (MetaWaylandSurface *surface)
{
g_signal_emit (surface, surface_signals[SURFACE_UNMAPPED], 0);
}
static void
meta_wayland_surface_finalize (GObject *object)
{
MetaWaylandSurface *surface = META_WAYLAND_SURFACE (object);
MetaWaylandCompositor *compositor = surface->compositor;
MetaWaylandFrameCallback *cb, *next;
g_clear_object (&surface->scanout_candidate);
g_clear_object (&surface->role);
if (surface->unassigned.buffer)
{
wayland/surface: Overhaul handling of buffer use count Move the use count from a separate MetaWaylandBufferRef struct to the MetaWaylandBuffer class, and remove the former. The buffer use count is now incremented already in meta_wayland_surface_commit, since the Wayland protocol defines the buffer to be in use by the compositor at that point. If the buffer attachment ends up being dropped again before it is applied to the surface state (e.g. because another buffer is committed to a synchronized sub-surface before the parent surface is committed), the use count is now decremented, and a buffer release event is sent if the use count drops to 0. Buffer release events were previously incorrectly not sent under these circumstances. Test case: Run the weston-subsurfaces demo with the -r1 and/or -t1 command line parameter. Resize the window. Before this change, weston-subsurfaces would freeze or abort after a few resize operations, because mutter failed to send release events and the client ran out of usable buffers. v2: * Handle NULL priv->buffer_ref in meta_wayland_cursor_surface_apply_state. v3: * Remove MetaWaylandBufferRef altogether, move the use count tracking to MetaWaylandBuffer itself. Much simpler, and doesn't run into lifetime issues when mutter shuts down. v4: * Warn if use count isn't 0 in meta_wayland_buffer_finalize. * Keep pending_buffer_resource_destroyed for attached but not yet committed buffers. If the client attaches a buffer and then destroys it before commit, we ignore the buffer attachement, same as before this MR. v5: * Rebase on top of new commit which splits up surface->texture. * MetaWaylandSurfaceState::buffer can only be non-NULL if ::newly_attached is TRUE, simplify accordingly. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1880>
2022-06-22 12:43:11 -04:00
meta_wayland_buffer_dec_use_count (surface->unassigned.buffer);
g_clear_object (&surface->unassigned.buffer);
}
if (surface->buffer_held)
wayland/surface: Overhaul handling of buffer use count Move the use count from a separate MetaWaylandBufferRef struct to the MetaWaylandBuffer class, and remove the former. The buffer use count is now incremented already in meta_wayland_surface_commit, since the Wayland protocol defines the buffer to be in use by the compositor at that point. If the buffer attachment ends up being dropped again before it is applied to the surface state (e.g. because another buffer is committed to a synchronized sub-surface before the parent surface is committed), the use count is now decremented, and a buffer release event is sent if the use count drops to 0. Buffer release events were previously incorrectly not sent under these circumstances. Test case: Run the weston-subsurfaces demo with the -r1 and/or -t1 command line parameter. Resize the window. Before this change, weston-subsurfaces would freeze or abort after a few resize operations, because mutter failed to send release events and the client ran out of usable buffers. v2: * Handle NULL priv->buffer_ref in meta_wayland_cursor_surface_apply_state. v3: * Remove MetaWaylandBufferRef altogether, move the use count tracking to MetaWaylandBuffer itself. Much simpler, and doesn't run into lifetime issues when mutter shuts down. v4: * Warn if use count isn't 0 in meta_wayland_buffer_finalize. * Keep pending_buffer_resource_destroyed for attached but not yet committed buffers. If the client attaches a buffer and then destroys it before commit, we ignore the buffer attachement, same as before this MR. v5: * Rebase on top of new commit which splits up surface->texture. * MetaWaylandSurfaceState::buffer can only be non-NULL if ::newly_attached is TRUE, simplify accordingly. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1880>
2022-06-22 12:43:11 -04:00
meta_wayland_buffer_dec_use_count (surface->buffer);
g_clear_pointer (&surface->output_state.texture, cogl_object_unref);
wayland/surface: Overhaul handling of buffer use count Move the use count from a separate MetaWaylandBufferRef struct to the MetaWaylandBuffer class, and remove the former. The buffer use count is now incremented already in meta_wayland_surface_commit, since the Wayland protocol defines the buffer to be in use by the compositor at that point. If the buffer attachment ends up being dropped again before it is applied to the surface state (e.g. because another buffer is committed to a synchronized sub-surface before the parent surface is committed), the use count is now decremented, and a buffer release event is sent if the use count drops to 0. Buffer release events were previously incorrectly not sent under these circumstances. Test case: Run the weston-subsurfaces demo with the -r1 and/or -t1 command line parameter. Resize the window. Before this change, weston-subsurfaces would freeze or abort after a few resize operations, because mutter failed to send release events and the client ran out of usable buffers. v2: * Handle NULL priv->buffer_ref in meta_wayland_cursor_surface_apply_state. v3: * Remove MetaWaylandBufferRef altogether, move the use count tracking to MetaWaylandBuffer itself. Much simpler, and doesn't run into lifetime issues when mutter shuts down. v4: * Warn if use count isn't 0 in meta_wayland_buffer_finalize. * Keep pending_buffer_resource_destroyed for attached but not yet committed buffers. If the client attaches a buffer and then destroys it before commit, we ignore the buffer attachement, same as before this MR. v5: * Rebase on top of new commit which splits up surface->texture. * MetaWaylandSurfaceState::buffer can only be non-NULL if ::newly_attached is TRUE, simplify accordingly. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1880>
2022-06-22 12:43:11 -04:00
g_clear_object (&surface->buffer);
if (surface->opaque_region)
cairo_region_destroy (surface->opaque_region);
if (surface->input_region)
cairo_region_destroy (surface->input_region);
meta_wayland_compositor_remove_frame_callback_surface (compositor, surface);
meta_wayland_compositor_remove_presentation_feedback_surface (compositor,
surface);
g_hash_table_foreach (surface->outputs,
surface_output_disconnect_signals,
surface);
g_hash_table_destroy (surface->outputs);
wl_list_for_each_safe (cb, next,
&surface->unassigned.pending_frame_callback_list,
link)
wl_resource_destroy (cb->resource);
meta_wayland_surface_discard_presentation_feedback (surface);
wayland/surface: Use transactions for all sub-surface hierarchy changes And keep track of the hierarchy separately for the Wayland protocol and for output. Protocol state is updated immediately as protocol requests are processed, output state only when the corresponding transaction is applied (which may be deferred until the next commit of the parent surface). v2: * Directly add placement ops to a transaction, instead of going via pending_state. * Use transaction entry for the sub-surface instead of that for its parent surface. v3: * Use transaction entry for the parent surface again, to ensure proper ordering of placement ops, and call meta_wayland_surface_notify_subsurface_state_changed only once per parent surface. * Drop all use of wl_resource_add_destroy_listener, transactions are keeping surfaces alive as long as needed. v4: * Rebase on https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2501 * Drop ClutterActor code from meta_wayland_surface_apply_placement_ops. (Robert Mader) v5: * Rename MetaWaylandSubSurfaceState to MetaWaylandSurfaceSubState, since the next commit adds not sub-surface specific state to it. v6: * Move include of meta-wayland-subsurface.h from meta-wayland-transaction.c to .h, since the latter references MetaWaylandSubsurfacePlacementOp. v7: * Drop superfluous !entry check from meta_wayland_transaction_apply. v8: * Rename output/protocol fields to output/protocol_state. (Jonas Ådahl) v9: * Use meta_wayland_surface_state_new in meta_wayland_transaction_add_placement_op. v10: * Fix a few style issues per check-style.py. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1880>
2021-07-23 10:01:37 -04:00
g_clear_pointer (&surface->output_state.subsurface_branch_node, g_node_destroy);
g_hash_table_destroy (surface->shortcut_inhibited_seats);
G_OBJECT_CLASS (meta_wayland_surface_parent_class)->finalize (object);
}
static void
wl_surface_destructor (struct wl_resource *resource)
{
MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
wayland/surface: Use transactions for all sub-surface hierarchy changes And keep track of the hierarchy separately for the Wayland protocol and for output. Protocol state is updated immediately as protocol requests are processed, output state only when the corresponding transaction is applied (which may be deferred until the next commit of the parent surface). v2: * Directly add placement ops to a transaction, instead of going via pending_state. * Use transaction entry for the sub-surface instead of that for its parent surface. v3: * Use transaction entry for the parent surface again, to ensure proper ordering of placement ops, and call meta_wayland_surface_notify_subsurface_state_changed only once per parent surface. * Drop all use of wl_resource_add_destroy_listener, transactions are keeping surfaces alive as long as needed. v4: * Rebase on https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2501 * Drop ClutterActor code from meta_wayland_surface_apply_placement_ops. (Robert Mader) v5: * Rename MetaWaylandSubSurfaceState to MetaWaylandSurfaceSubState, since the next commit adds not sub-surface specific state to it. v6: * Move include of meta-wayland-subsurface.h from meta-wayland-transaction.c to .h, since the latter references MetaWaylandSubsurfacePlacementOp. v7: * Drop superfluous !entry check from meta_wayland_transaction_apply. v8: * Rename output/protocol fields to output/protocol_state. (Jonas Ådahl) v9: * Use meta_wayland_surface_state_new in meta_wayland_transaction_add_placement_op. v10: * Fix a few style issues per check-style.py. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1880>
2021-07-23 10:01:37 -04:00
MetaWaylandSurface *subsurface_surface;
g_signal_emit (surface, surface_signals[SURFACE_DESTROY], 0);
g_clear_object (&surface->pending_state);
g_clear_pointer (&surface->sub.transaction, meta_wayland_transaction_free);
if (surface->resource)
wl_resource_set_user_data (g_steal_pointer (&surface->resource), NULL);
wayland/surface: Use transactions for all sub-surface hierarchy changes And keep track of the hierarchy separately for the Wayland protocol and for output. Protocol state is updated immediately as protocol requests are processed, output state only when the corresponding transaction is applied (which may be deferred until the next commit of the parent surface). v2: * Directly add placement ops to a transaction, instead of going via pending_state. * Use transaction entry for the sub-surface instead of that for its parent surface. v3: * Use transaction entry for the parent surface again, to ensure proper ordering of placement ops, and call meta_wayland_surface_notify_subsurface_state_changed only once per parent surface. * Drop all use of wl_resource_add_destroy_listener, transactions are keeping surfaces alive as long as needed. v4: * Rebase on https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2501 * Drop ClutterActor code from meta_wayland_surface_apply_placement_ops. (Robert Mader) v5: * Rename MetaWaylandSubSurfaceState to MetaWaylandSurfaceSubState, since the next commit adds not sub-surface specific state to it. v6: * Move include of meta-wayland-subsurface.h from meta-wayland-transaction.c to .h, since the latter references MetaWaylandSubsurfacePlacementOp. v7: * Drop superfluous !entry check from meta_wayland_transaction_apply. v8: * Rename output/protocol fields to output/protocol_state. (Jonas Ådahl) v9: * Use meta_wayland_surface_state_new in meta_wayland_transaction_add_placement_op. v10: * Fix a few style issues per check-style.py. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1880>
2021-07-23 10:01:37 -04:00
META_WAYLAND_SURFACE_FOREACH_SUBSURFACE (&surface->protocol_state,
subsurface_surface)
meta_wayland_subsurface_parent_destroyed (subsurface_surface);
g_clear_pointer (&surface->wl_subsurface, wl_resource_destroy);
wayland/surface: Use transactions for all sub-surface hierarchy changes And keep track of the hierarchy separately for the Wayland protocol and for output. Protocol state is updated immediately as protocol requests are processed, output state only when the corresponding transaction is applied (which may be deferred until the next commit of the parent surface). v2: * Directly add placement ops to a transaction, instead of going via pending_state. * Use transaction entry for the sub-surface instead of that for its parent surface. v3: * Use transaction entry for the parent surface again, to ensure proper ordering of placement ops, and call meta_wayland_surface_notify_subsurface_state_changed only once per parent surface. * Drop all use of wl_resource_add_destroy_listener, transactions are keeping surfaces alive as long as needed. v4: * Rebase on https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2501 * Drop ClutterActor code from meta_wayland_surface_apply_placement_ops. (Robert Mader) v5: * Rename MetaWaylandSubSurfaceState to MetaWaylandSurfaceSubState, since the next commit adds not sub-surface specific state to it. v6: * Move include of meta-wayland-subsurface.h from meta-wayland-transaction.c to .h, since the latter references MetaWaylandSubsurfacePlacementOp. v7: * Drop superfluous !entry check from meta_wayland_transaction_apply. v8: * Rename output/protocol fields to output/protocol_state. (Jonas Ådahl) v9: * Use meta_wayland_surface_state_new in meta_wayland_transaction_add_placement_op. v10: * Fix a few style issues per check-style.py. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1880>
2021-07-23 10:01:37 -04:00
g_clear_pointer (&surface->protocol_state.subsurface_branch_node, g_node_destroy);
cogl_clear_object (&surface->protocol_state.texture);
/*
* Any transactions referencing this surface will keep it alive until they get
* applied/destroyed. The last reference will be dropped in
* meta_wayland_transaction_free.
*/
g_object_unref (surface);
}
MetaWaylandSurface *
meta_wayland_surface_create (MetaWaylandCompositor *compositor,
2014-04-22 18:22:13 -04:00
struct wl_client *client,
struct wl_resource *compositor_resource,
guint32 id)
{
MetaWaylandSurface *surface = g_object_new (META_TYPE_WAYLAND_SURFACE, NULL);
int surface_version;
surface->compositor = compositor;
surface->scale = 1;
surface_version = wl_resource_get_version (compositor_resource);
surface->resource = wl_resource_create (client,
&wl_surface_interface,
surface_version,
id);
wl_resource_set_implementation (surface->resource,
&meta_wayland_wl_surface_interface,
surface,
wl_surface_destructor);
wl_list_init (&surface->unassigned.pending_frame_callback_list);
surface->outputs = g_hash_table_new (NULL, NULL);
surface->shortcut_inhibited_seats = g_hash_table_new (NULL, NULL);
wl_list_init (&surface->presentation_time.feedback_list);
meta_wayland_compositor_notify_surface_id (compositor, id, surface);
return surface;
}
gboolean
meta_wayland_surface_begin_grab_op (MetaWaylandSurface *surface,
MetaWaylandSeat *seat,
MetaGrabOp grab_op,
gfloat x,
gfloat y)
{
MetaWindow *window = meta_wayland_surface_get_window (surface);
if (grab_op == META_GRAB_OP_NONE)
return FALSE;
/* This is an input driven operation so we set frame_action to
constrain it in the same way as it would be if the window was
being moved/resized via a SSD event. */
return meta_display_begin_grab_op (window->display,
window,
grab_op,
TRUE, /* pointer_already_grabbed */
TRUE, /* frame_action */
1, /* button. XXX? */
0, /* modmask */
meta_display_get_current_time_roundtrip (window->display),
x, y);
}
/**
* meta_wayland_shell_init:
* @compositor: The #MetaWaylandCompositor object
*
* Initializes the Wayland interfaces providing features that deal with
* desktop-specific conundrums, like XDG shell, etc.
*/
void
meta_wayland_shell_init (MetaWaylandCompositor *compositor)
{
meta_wayland_xdg_shell_init (compositor);
meta_wayland_init_gtk_shell (compositor);
meta_wayland_init_viewporter (compositor);
}
void
meta_wayland_surface_configure_notify (MetaWaylandSurface *surface,
MetaWaylandWindowConfiguration *configuration)
{
MetaWaylandShellSurface *shell_surface =
META_WAYLAND_SHELL_SURFACE (surface->role);
g_signal_emit (surface, surface_signals[SURFACE_CONFIGURE], 0);
meta_wayland_shell_surface_configure (shell_surface, configuration);
}
void
meta_wayland_surface_ping (MetaWaylandSurface *surface,
guint32 serial)
{
MetaWaylandShellSurface *shell_surface =
META_WAYLAND_SHELL_SURFACE (surface->role);
meta_wayland_shell_surface_ping (shell_surface, serial);
}
void
meta_wayland_surface_delete (MetaWaylandSurface *surface)
{
MetaWaylandShellSurface *shell_surface =
META_WAYLAND_SHELL_SURFACE (surface->role);
meta_wayland_shell_surface_close (shell_surface);
}
2014-02-28 00:18:42 -05:00
void
meta_wayland_surface_window_managed (MetaWaylandSurface *surface,
MetaWindow *window)
{
MetaWaylandShellSurface *shell_surface =
META_WAYLAND_SHELL_SURFACE (surface->role);
meta_wayland_shell_surface_managed (shell_surface, window);
}
void
meta_wayland_surface_drag_dest_focus_in (MetaWaylandSurface *surface,
MetaWaylandDataOffer *offer)
{
MetaWaylandCompositor *compositor = surface->compositor;
MetaWaylandDataDevice *data_device = &compositor->seat->data_device;
surface->dnd.funcs->focus_in (data_device, surface, offer);
}
void
meta_wayland_surface_drag_dest_motion (MetaWaylandSurface *surface,
const ClutterEvent *event)
{
MetaWaylandCompositor *compositor = surface->compositor;
MetaWaylandDataDevice *data_device = &compositor->seat->data_device;
surface->dnd.funcs->motion (data_device, surface, event);
}
void
meta_wayland_surface_drag_dest_focus_out (MetaWaylandSurface *surface)
{
MetaWaylandCompositor *compositor = surface->compositor;
MetaWaylandDataDevice *data_device = &compositor->seat->data_device;
surface->dnd.funcs->focus_out (data_device, surface);
}
void
meta_wayland_surface_drag_dest_drop (MetaWaylandSurface *surface)
{
MetaWaylandCompositor *compositor = surface->compositor;
MetaWaylandDataDevice *data_device = &compositor->seat->data_device;
surface->dnd.funcs->drop (data_device, surface);
}
void
meta_wayland_surface_drag_dest_update (MetaWaylandSurface *surface)
{
MetaWaylandCompositor *compositor = surface->compositor;
MetaWaylandDataDevice *data_device = &compositor->seat->data_device;
surface->dnd.funcs->update (data_device, surface);
}
MetaWaylandSurface *
meta_wayland_surface_get_toplevel (MetaWaylandSurface *surface)
{
if (surface->role)
return meta_wayland_surface_role_get_toplevel (surface->role);
else
return NULL;
}
MetaWindow *
meta_wayland_surface_get_toplevel_window (MetaWaylandSurface *surface)
{
MetaWaylandSurface *toplevel;
toplevel = meta_wayland_surface_get_toplevel (surface);
if (toplevel)
return meta_wayland_surface_get_window (toplevel);
else
return NULL;
}
void
meta_wayland_surface_get_relative_coordinates (MetaWaylandSurface *surface,
float abs_x,
float abs_y,
float *sx,
float *sy)
{
MetaWaylandSurfaceRoleClass *surface_role_class =
META_WAYLAND_SURFACE_ROLE_GET_CLASS (surface->role);
surface_role_class->get_relative_coordinates (surface->role,
abs_x, abs_y,
sx, sy);
}
void
meta_wayland_surface_get_absolute_coordinates (MetaWaylandSurface *surface,
float sx,
float sy,
float *x,
float *y)
{
ClutterActor *actor =
CLUTTER_ACTOR (meta_wayland_surface_get_actor (surface));
graphene_point3d_t sv = {
.x = sx,
.y = sy,
};
graphene_point3d_t v = { 0 };
clutter_actor_apply_relative_transform_to_point (actor, NULL, &sv, &v);
*x = v.x;
*y = v.y;
}
static void
meta_wayland_surface_init (MetaWaylandSurface *surface)
{
surface->pending_state = meta_wayland_surface_state_new ();
wayland/surface: Use transactions for all sub-surface hierarchy changes And keep track of the hierarchy separately for the Wayland protocol and for output. Protocol state is updated immediately as protocol requests are processed, output state only when the corresponding transaction is applied (which may be deferred until the next commit of the parent surface). v2: * Directly add placement ops to a transaction, instead of going via pending_state. * Use transaction entry for the sub-surface instead of that for its parent surface. v3: * Use transaction entry for the parent surface again, to ensure proper ordering of placement ops, and call meta_wayland_surface_notify_subsurface_state_changed only once per parent surface. * Drop all use of wl_resource_add_destroy_listener, transactions are keeping surfaces alive as long as needed. v4: * Rebase on https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2501 * Drop ClutterActor code from meta_wayland_surface_apply_placement_ops. (Robert Mader) v5: * Rename MetaWaylandSubSurfaceState to MetaWaylandSurfaceSubState, since the next commit adds not sub-surface specific state to it. v6: * Move include of meta-wayland-subsurface.h from meta-wayland-transaction.c to .h, since the latter references MetaWaylandSubsurfacePlacementOp. v7: * Drop superfluous !entry check from meta_wayland_transaction_apply. v8: * Rename output/protocol fields to output/protocol_state. (Jonas Ådahl) v9: * Use meta_wayland_surface_state_new in meta_wayland_transaction_add_placement_op. v10: * Fix a few style issues per check-style.py. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1880>
2021-07-23 10:01:37 -04:00
surface->output_state.subsurface_branch_node = g_node_new (surface);
surface->output_state.subsurface_leaf_node =
g_node_prepend_data (surface->output_state.subsurface_branch_node, surface);
surface->protocol_state.subsurface_branch_node = g_node_new (surface);
surface->protocol_state.subsurface_leaf_node =
g_node_prepend_data (surface->protocol_state.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->finalize = meta_wayland_surface_finalize;
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),
G_SIGNAL_RUN_LAST,
0, NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
surface_signals[SURFACE_UNMAPPED] =
g_signal_new ("unmapped",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
0, NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
surface_signals[SURFACE_CONFIGURE] =
g_signal_new ("configure",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
0, NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
surface_signals[SURFACE_SHORTCUTS_INHIBITED] =
g_signal_new ("shortcuts-inhibited",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
0, NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
surface_signals[SURFACE_SHORTCUTS_RESTORED] =
g_signal_new ("shortcuts-restored",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
0, NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
surface_signals[SURFACE_GEOMETRY_CHANGED] =
g_signal_new ("geometry-changed",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
0, NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
surface_signals[SURFACE_PRE_STATE_APPLIED] =
g_signal_new ("pre-state-applied",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
0, NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
}
static void
meta_wayland_surface_role_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
MetaWaylandSurfaceRole *surface_role = META_WAYLAND_SURFACE_ROLE (object);
MetaWaylandSurfaceRolePrivate *priv =
meta_wayland_surface_role_get_instance_private (surface_role);
switch (prop_id)
{
case SURFACE_ROLE_PROP_SURFACE:
priv->surface = g_value_get_object (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
meta_wayland_surface_role_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
MetaWaylandSurfaceRole *surface_role = META_WAYLAND_SURFACE_ROLE (object);
MetaWaylandSurfaceRolePrivate *priv =
meta_wayland_surface_role_get_instance_private (surface_role);
switch (prop_id)
{
case SURFACE_ROLE_PROP_SURFACE:
g_value_set_object (value, priv->surface);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
meta_wayland_surface_role_init (MetaWaylandSurfaceRole *role)
{
}
static void
meta_wayland_surface_role_class_init (MetaWaylandSurfaceRoleClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->set_property = meta_wayland_surface_role_set_property;
object_class->get_property = meta_wayland_surface_role_get_property;
g_object_class_install_property (object_class,
SURFACE_ROLE_PROP_SURFACE,
g_param_spec_object ("surface",
"MetaWaylandSurface",
"The MetaWaylandSurface instance",
META_TYPE_WAYLAND_SURFACE,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS));
}
static void
meta_wayland_surface_role_assigned (MetaWaylandSurfaceRole *surface_role)
{
META_WAYLAND_SURFACE_ROLE_GET_CLASS (surface_role)->assigned (surface_role);
}
static void
meta_wayland_surface_role_commit_state (MetaWaylandSurfaceRole *surface_role,
MetaWaylandTransaction *transaction,
MetaWaylandSurfaceState *pending)
{
MetaWaylandSurfaceRoleClass *klass;
klass = META_WAYLAND_SURFACE_ROLE_GET_CLASS (surface_role);
if (klass->commit_state)
klass->commit_state (surface_role, transaction, pending);
}
static void
meta_wayland_surface_role_pre_apply_state (MetaWaylandSurfaceRole *surface_role,
MetaWaylandSurfaceState *pending)
{
MetaWaylandSurfaceRoleClass *klass;
klass = META_WAYLAND_SURFACE_ROLE_GET_CLASS (surface_role);
if (klass->pre_apply_state)
klass->pre_apply_state (surface_role, pending);
}
static void
meta_wayland_surface_role_post_apply_state (MetaWaylandSurfaceRole *surface_role,
MetaWaylandSurfaceState *pending)
{
MetaWaylandSurfaceRoleClass *klass;
klass = META_WAYLAND_SURFACE_ROLE_GET_CLASS (surface_role);
if (klass->post_apply_state)
klass->post_apply_state (surface_role, pending);
}
static void
meta_wayland_surface_role_apply_state (MetaWaylandSurfaceRole *surface_role,
MetaWaylandSurfaceState *pending)
{
META_WAYLAND_SURFACE_ROLE_GET_CLASS (surface_role)->apply_state (surface_role,
pending);
}
static gboolean
meta_wayland_surface_role_is_on_logical_monitor (MetaWaylandSurfaceRole *surface_role,
MetaLogicalMonitor *logical_monitor)
{
MetaWaylandSurfaceRoleClass *klass;
klass = META_WAYLAND_SURFACE_ROLE_GET_CLASS (surface_role);
if (klass->is_on_logical_monitor)
return klass->is_on_logical_monitor (surface_role, logical_monitor);
else
return FALSE;
}
static MetaWaylandSurface *
meta_wayland_surface_role_get_toplevel (MetaWaylandSurfaceRole *surface_role)
{
MetaWaylandSurfaceRoleClass *klass;
klass = META_WAYLAND_SURFACE_ROLE_GET_CLASS (surface_role);
if (klass->get_toplevel)
return klass->get_toplevel (surface_role);
else
return NULL;
}
static MetaWindow *
meta_wayland_surface_role_get_window (MetaWaylandSurfaceRole *surface_role)
{
MetaWaylandSurfaceRoleClass *klass;
klass = META_WAYLAND_SURFACE_ROLE_GET_CLASS (surface_role);
if (klass->get_window)
return klass->get_window (surface_role);
else
return NULL;
}
MetaWindow *
meta_wayland_surface_get_window (MetaWaylandSurface *surface)
{
if (!surface->role)
return NULL;
return meta_wayland_surface_role_get_window (surface->role);
}
static gboolean
meta_wayland_surface_role_is_synchronized (MetaWaylandSurfaceRole *surface_role)
{
MetaWaylandSurfaceRoleClass *klass;
klass = META_WAYLAND_SURFACE_ROLE_GET_CLASS (surface_role);
if (klass->is_synchronized)
return klass->is_synchronized (surface_role);
else
return FALSE;
}
gboolean
meta_wayland_surface_is_synchronized (MetaWaylandSurface *surface)
{
if (!surface->role)
return FALSE;
return meta_wayland_surface_role_is_synchronized (surface->role);
}
static void
meta_wayland_surface_role_notify_subsurface_state_changed (MetaWaylandSurfaceRole *surface_role)
{
MetaWaylandSurfaceRoleClass *klass;
klass = META_WAYLAND_SURFACE_ROLE_GET_CLASS (surface_role);
g_return_if_fail (klass->notify_subsurface_state_changed);
klass->notify_subsurface_state_changed (surface_role);
}
void
meta_wayland_surface_notify_subsurface_state_changed (MetaWaylandSurface *surface)
{
if (surface->role)
meta_wayland_surface_role_notify_subsurface_state_changed (surface->role);
}
MetaWaylandSurface *
meta_wayland_surface_role_get_surface (MetaWaylandSurfaceRole *role)
{
MetaWaylandSurfaceRolePrivate *priv =
meta_wayland_surface_role_get_instance_private (role);
return priv->surface;
}
cairo_region_t *
meta_wayland_surface_calculate_input_region (MetaWaylandSurface *surface)
{
cairo_region_t *region;
cairo_rectangle_int_t buffer_rect;
wayland/surface: Overhaul handling of buffer use count Move the use count from a separate MetaWaylandBufferRef struct to the MetaWaylandBuffer class, and remove the former. The buffer use count is now incremented already in meta_wayland_surface_commit, since the Wayland protocol defines the buffer to be in use by the compositor at that point. If the buffer attachment ends up being dropped again before it is applied to the surface state (e.g. because another buffer is committed to a synchronized sub-surface before the parent surface is committed), the use count is now decremented, and a buffer release event is sent if the use count drops to 0. Buffer release events were previously incorrectly not sent under these circumstances. Test case: Run the weston-subsurfaces demo with the -r1 and/or -t1 command line parameter. Resize the window. Before this change, weston-subsurfaces would freeze or abort after a few resize operations, because mutter failed to send release events and the client ran out of usable buffers. v2: * Handle NULL priv->buffer_ref in meta_wayland_cursor_surface_apply_state. v3: * Remove MetaWaylandBufferRef altogether, move the use count tracking to MetaWaylandBuffer itself. Much simpler, and doesn't run into lifetime issues when mutter shuts down. v4: * Warn if use count isn't 0 in meta_wayland_buffer_finalize. * Keep pending_buffer_resource_destroyed for attached but not yet committed buffers. If the client attaches a buffer and then destroys it before commit, we ignore the buffer attachement, same as before this MR. v5: * Rebase on top of new commit which splits up surface->texture. * MetaWaylandSurfaceState::buffer can only be non-NULL if ::newly_attached is TRUE, simplify accordingly. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1880>
2022-06-22 12:43:11 -04:00
if (!surface->buffer)
return NULL;
buffer_rect = (cairo_rectangle_int_t) {
.width = meta_wayland_surface_get_width (surface),
.height = meta_wayland_surface_get_height (surface),
};
region = cairo_region_create_rectangle (&buffer_rect);
if (surface->input_region)
cairo_region_intersect (region, surface->input_region);
return region;
}
void
meta_wayland_surface_inhibit_shortcuts (MetaWaylandSurface *surface,
MetaWaylandSeat *seat)
{
g_hash_table_add (surface->shortcut_inhibited_seats, seat);
g_signal_emit (surface, surface_signals[SURFACE_SHORTCUTS_INHIBITED], 0);
}
void
meta_wayland_surface_restore_shortcuts (MetaWaylandSurface *surface,
MetaWaylandSeat *seat)
{
g_signal_emit (surface, surface_signals[SURFACE_SHORTCUTS_RESTORED], 0);
g_hash_table_remove (surface->shortcut_inhibited_seats, seat);
}
gboolean
meta_wayland_surface_is_shortcuts_inhibited (MetaWaylandSurface *surface,
MetaWaylandSeat *seat)
{
if (surface->shortcut_inhibited_seats == NULL)
return FALSE;
return g_hash_table_contains (surface->shortcut_inhibited_seats, seat);
}
CoglTexture *
meta_wayland_surface_get_texture (MetaWaylandSurface *surface)
{
return surface->output_state.texture;
}
MetaSurfaceActor *
meta_wayland_surface_get_actor (MetaWaylandSurface *surface)
{
if (!surface->role || !META_IS_WAYLAND_ACTOR_SURFACE (surface->role))
return NULL;
return meta_wayland_actor_surface_get_actor (META_WAYLAND_ACTOR_SURFACE (surface->role));
}
void
meta_wayland_surface_notify_geometry_changed (MetaWaylandSurface *surface)
{
g_signal_emit (surface, surface_signals[SURFACE_GEOMETRY_CHANGED], 0);
}
int
meta_wayland_surface_get_width (MetaWaylandSurface *surface)
{
if (surface->viewport.has_dst_size)
{
return surface->viewport.dst_width;
}
else if (surface->viewport.has_src_rect)
{
return ceilf (surface->viewport.src_rect.size.width);
}
else
{
int width;
if (meta_monitor_transform_is_rotated (surface->buffer_transform))
width = get_buffer_height (surface);
else
width = get_buffer_width (surface);
return width / surface->scale;
}
}
int
meta_wayland_surface_get_height (MetaWaylandSurface *surface)
{
if (surface->viewport.has_dst_size)
{
return surface->viewport.dst_height;
}
else if (surface->viewport.has_src_rect)
{
return ceilf (surface->viewport.src_rect.size.height);
}
else
{
int height;
if (meta_monitor_transform_is_rotated (surface->buffer_transform))
height = get_buffer_width (surface);
else
height = get_buffer_height (surface);
return height / surface->scale;
}
}
static void
scanout_destroyed (gpointer data,
GObject *where_the_object_was)
{
wayland/surface: Overhaul handling of buffer use count Move the use count from a separate MetaWaylandBufferRef struct to the MetaWaylandBuffer class, and remove the former. The buffer use count is now incremented already in meta_wayland_surface_commit, since the Wayland protocol defines the buffer to be in use by the compositor at that point. If the buffer attachment ends up being dropped again before it is applied to the surface state (e.g. because another buffer is committed to a synchronized sub-surface before the parent surface is committed), the use count is now decremented, and a buffer release event is sent if the use count drops to 0. Buffer release events were previously incorrectly not sent under these circumstances. Test case: Run the weston-subsurfaces demo with the -r1 and/or -t1 command line parameter. Resize the window. Before this change, weston-subsurfaces would freeze or abort after a few resize operations, because mutter failed to send release events and the client ran out of usable buffers. v2: * Handle NULL priv->buffer_ref in meta_wayland_cursor_surface_apply_state. v3: * Remove MetaWaylandBufferRef altogether, move the use count tracking to MetaWaylandBuffer itself. Much simpler, and doesn't run into lifetime issues when mutter shuts down. v4: * Warn if use count isn't 0 in meta_wayland_buffer_finalize. * Keep pending_buffer_resource_destroyed for attached but not yet committed buffers. If the client attaches a buffer and then destroys it before commit, we ignore the buffer attachement, same as before this MR. v5: * Rebase on top of new commit which splits up surface->texture. * MetaWaylandSurfaceState::buffer can only be non-NULL if ::newly_attached is TRUE, simplify accordingly. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1880>
2022-06-22 12:43:11 -04:00
MetaWaylandBuffer *buffer = data;
wayland/surface: Overhaul handling of buffer use count Move the use count from a separate MetaWaylandBufferRef struct to the MetaWaylandBuffer class, and remove the former. The buffer use count is now incremented already in meta_wayland_surface_commit, since the Wayland protocol defines the buffer to be in use by the compositor at that point. If the buffer attachment ends up being dropped again before it is applied to the surface state (e.g. because another buffer is committed to a synchronized sub-surface before the parent surface is committed), the use count is now decremented, and a buffer release event is sent if the use count drops to 0. Buffer release events were previously incorrectly not sent under these circumstances. Test case: Run the weston-subsurfaces demo with the -r1 and/or -t1 command line parameter. Resize the window. Before this change, weston-subsurfaces would freeze or abort after a few resize operations, because mutter failed to send release events and the client ran out of usable buffers. v2: * Handle NULL priv->buffer_ref in meta_wayland_cursor_surface_apply_state. v3: * Remove MetaWaylandBufferRef altogether, move the use count tracking to MetaWaylandBuffer itself. Much simpler, and doesn't run into lifetime issues when mutter shuts down. v4: * Warn if use count isn't 0 in meta_wayland_buffer_finalize. * Keep pending_buffer_resource_destroyed for attached but not yet committed buffers. If the client attaches a buffer and then destroys it before commit, we ignore the buffer attachement, same as before this MR. v5: * Rebase on top of new commit which splits up surface->texture. * MetaWaylandSurfaceState::buffer can only be non-NULL if ::newly_attached is TRUE, simplify accordingly. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1880>
2022-06-22 12:43:11 -04:00
meta_wayland_buffer_dec_use_count (buffer);
g_object_unref (buffer);
}
CoglScanout *
meta_wayland_surface_try_acquire_scanout (MetaWaylandSurface *surface,
CoglOnscreen *onscreen)
{
CoglScanout *scanout;
wayland/surface: Overhaul handling of buffer use count Move the use count from a separate MetaWaylandBufferRef struct to the MetaWaylandBuffer class, and remove the former. The buffer use count is now incremented already in meta_wayland_surface_commit, since the Wayland protocol defines the buffer to be in use by the compositor at that point. If the buffer attachment ends up being dropped again before it is applied to the surface state (e.g. because another buffer is committed to a synchronized sub-surface before the parent surface is committed), the use count is now decremented, and a buffer release event is sent if the use count drops to 0. Buffer release events were previously incorrectly not sent under these circumstances. Test case: Run the weston-subsurfaces demo with the -r1 and/or -t1 command line parameter. Resize the window. Before this change, weston-subsurfaces would freeze or abort after a few resize operations, because mutter failed to send release events and the client ran out of usable buffers. v2: * Handle NULL priv->buffer_ref in meta_wayland_cursor_surface_apply_state. v3: * Remove MetaWaylandBufferRef altogether, move the use count tracking to MetaWaylandBuffer itself. Much simpler, and doesn't run into lifetime issues when mutter shuts down. v4: * Warn if use count isn't 0 in meta_wayland_buffer_finalize. * Keep pending_buffer_resource_destroyed for attached but not yet committed buffers. If the client attaches a buffer and then destroys it before commit, we ignore the buffer attachement, same as before this MR. v5: * Rebase on top of new commit which splits up surface->texture. * MetaWaylandSurfaceState::buffer can only be non-NULL if ::newly_attached is TRUE, simplify accordingly. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1880>
2022-06-22 12:43:11 -04:00
MetaWaylandBuffer *buffer;
wayland/surface: Overhaul handling of buffer use count Move the use count from a separate MetaWaylandBufferRef struct to the MetaWaylandBuffer class, and remove the former. The buffer use count is now incremented already in meta_wayland_surface_commit, since the Wayland protocol defines the buffer to be in use by the compositor at that point. If the buffer attachment ends up being dropped again before it is applied to the surface state (e.g. because another buffer is committed to a synchronized sub-surface before the parent surface is committed), the use count is now decremented, and a buffer release event is sent if the use count drops to 0. Buffer release events were previously incorrectly not sent under these circumstances. Test case: Run the weston-subsurfaces demo with the -r1 and/or -t1 command line parameter. Resize the window. Before this change, weston-subsurfaces would freeze or abort after a few resize operations, because mutter failed to send release events and the client ran out of usable buffers. v2: * Handle NULL priv->buffer_ref in meta_wayland_cursor_surface_apply_state. v3: * Remove MetaWaylandBufferRef altogether, move the use count tracking to MetaWaylandBuffer itself. Much simpler, and doesn't run into lifetime issues when mutter shuts down. v4: * Warn if use count isn't 0 in meta_wayland_buffer_finalize. * Keep pending_buffer_resource_destroyed for attached but not yet committed buffers. If the client attaches a buffer and then destroys it before commit, we ignore the buffer attachement, same as before this MR. v5: * Rebase on top of new commit which splits up surface->texture. * MetaWaylandSurfaceState::buffer can only be non-NULL if ::newly_attached is TRUE, simplify accordingly. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1880>
2022-06-22 12:43:11 -04:00
if (!surface->buffer)
return NULL;
wayland/surface: Overhaul handling of buffer use count Move the use count from a separate MetaWaylandBufferRef struct to the MetaWaylandBuffer class, and remove the former. The buffer use count is now incremented already in meta_wayland_surface_commit, since the Wayland protocol defines the buffer to be in use by the compositor at that point. If the buffer attachment ends up being dropped again before it is applied to the surface state (e.g. because another buffer is committed to a synchronized sub-surface before the parent surface is committed), the use count is now decremented, and a buffer release event is sent if the use count drops to 0. Buffer release events were previously incorrectly not sent under these circumstances. Test case: Run the weston-subsurfaces demo with the -r1 and/or -t1 command line parameter. Resize the window. Before this change, weston-subsurfaces would freeze or abort after a few resize operations, because mutter failed to send release events and the client ran out of usable buffers. v2: * Handle NULL priv->buffer_ref in meta_wayland_cursor_surface_apply_state. v3: * Remove MetaWaylandBufferRef altogether, move the use count tracking to MetaWaylandBuffer itself. Much simpler, and doesn't run into lifetime issues when mutter shuts down. v4: * Warn if use count isn't 0 in meta_wayland_buffer_finalize. * Keep pending_buffer_resource_destroyed for attached but not yet committed buffers. If the client attaches a buffer and then destroys it before commit, we ignore the buffer attachement, same as before this MR. v5: * Rebase on top of new commit which splits up surface->texture. * MetaWaylandSurfaceState::buffer can only be non-NULL if ::newly_attached is TRUE, simplify accordingly. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1880>
2022-06-22 12:43:11 -04:00
if (surface->buffer->use_count == 0)
return NULL;
wayland/surface: Overhaul handling of buffer use count Move the use count from a separate MetaWaylandBufferRef struct to the MetaWaylandBuffer class, and remove the former. The buffer use count is now incremented already in meta_wayland_surface_commit, since the Wayland protocol defines the buffer to be in use by the compositor at that point. If the buffer attachment ends up being dropped again before it is applied to the surface state (e.g. because another buffer is committed to a synchronized sub-surface before the parent surface is committed), the use count is now decremented, and a buffer release event is sent if the use count drops to 0. Buffer release events were previously incorrectly not sent under these circumstances. Test case: Run the weston-subsurfaces demo with the -r1 and/or -t1 command line parameter. Resize the window. Before this change, weston-subsurfaces would freeze or abort after a few resize operations, because mutter failed to send release events and the client ran out of usable buffers. v2: * Handle NULL priv->buffer_ref in meta_wayland_cursor_surface_apply_state. v3: * Remove MetaWaylandBufferRef altogether, move the use count tracking to MetaWaylandBuffer itself. Much simpler, and doesn't run into lifetime issues when mutter shuts down. v4: * Warn if use count isn't 0 in meta_wayland_buffer_finalize. * Keep pending_buffer_resource_destroyed for attached but not yet committed buffers. If the client attaches a buffer and then destroys it before commit, we ignore the buffer attachement, same as before this MR. v5: * Rebase on top of new commit which splits up surface->texture. * MetaWaylandSurfaceState::buffer can only be non-NULL if ::newly_attached is TRUE, simplify accordingly. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1880>
2022-06-22 12:43:11 -04:00
scanout = meta_wayland_buffer_try_acquire_scanout (surface->buffer,
onscreen);
if (!scanout)
return NULL;
wayland/surface: Overhaul handling of buffer use count Move the use count from a separate MetaWaylandBufferRef struct to the MetaWaylandBuffer class, and remove the former. The buffer use count is now incremented already in meta_wayland_surface_commit, since the Wayland protocol defines the buffer to be in use by the compositor at that point. If the buffer attachment ends up being dropped again before it is applied to the surface state (e.g. because another buffer is committed to a synchronized sub-surface before the parent surface is committed), the use count is now decremented, and a buffer release event is sent if the use count drops to 0. Buffer release events were previously incorrectly not sent under these circumstances. Test case: Run the weston-subsurfaces demo with the -r1 and/or -t1 command line parameter. Resize the window. Before this change, weston-subsurfaces would freeze or abort after a few resize operations, because mutter failed to send release events and the client ran out of usable buffers. v2: * Handle NULL priv->buffer_ref in meta_wayland_cursor_surface_apply_state. v3: * Remove MetaWaylandBufferRef altogether, move the use count tracking to MetaWaylandBuffer itself. Much simpler, and doesn't run into lifetime issues when mutter shuts down. v4: * Warn if use count isn't 0 in meta_wayland_buffer_finalize. * Keep pending_buffer_resource_destroyed for attached but not yet committed buffers. If the client attaches a buffer and then destroys it before commit, we ignore the buffer attachement, same as before this MR. v5: * Rebase on top of new commit which splits up surface->texture. * MetaWaylandSurfaceState::buffer can only be non-NULL if ::newly_attached is TRUE, simplify accordingly. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1880>
2022-06-22 12:43:11 -04:00
buffer = g_object_ref (surface->buffer);
meta_wayland_buffer_inc_use_count (buffer);
g_object_weak_ref (G_OBJECT (scanout), scanout_destroyed, buffer);
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]);
}
gboolean
meta_wayland_surface_can_scanout_untransformed (MetaWaylandSurface *surface,
MetaRendererView *view,
int geometry_scale)
{
if (meta_renderer_view_get_transform (view) != surface->buffer_transform)
{
meta_topic (META_DEBUG_RENDER,
"Surface can not be scanned out untransformed: buffer "
"transform does not match renderer-view transform");
return FALSE;
}
if (surface->viewport.has_dst_size)
{
MetaRectangle view_layout;
float view_scale;
clutter_stage_view_get_layout (CLUTTER_STAGE_VIEW (view), &view_layout);
view_scale = clutter_stage_view_get_scale (CLUTTER_STAGE_VIEW (view));
if (!G_APPROX_VALUE (view_layout.width, surface->viewport.dst_width,
FLT_EPSILON) ||
!G_APPROX_VALUE (view_layout.height, surface->viewport.dst_height,
FLT_EPSILON) ||
!G_APPROX_VALUE (view_layout.width * view_scale,
get_buffer_width (surface),
FLT_EPSILON) ||
!G_APPROX_VALUE (view_layout.height * view_scale,
get_buffer_height (surface),
FLT_EPSILON))
{
meta_topic (META_DEBUG_RENDER,
"Surface can not be scanned out untransformed: viewport "
"destination size does not match stage-view layout");
return FALSE;
}
}
else
{
MetaContext *context =
meta_wayland_compositor_get_context (surface->compositor);
MetaBackend *backend = meta_context_get_backend (context);
if (meta_backend_is_stage_views_scaled (backend))
{
float view_scale;
view_scale = clutter_stage_view_get_scale (CLUTTER_STAGE_VIEW (view));
if (!G_APPROX_VALUE (view_scale, surface->scale, FLT_EPSILON))
{
meta_topic (META_DEBUG_RENDER,
"Surface can not be scanned out untransformed: "
"buffer scale does not match stage-view scale");
return FALSE;
}
}
else
{
if (geometry_scale != surface->scale)
{
meta_topic (META_DEBUG_RENDER,
"Surface can not be scanned out untransformed: "
"buffer scale does not match actor geometry scale");
return FALSE;
}
}
}
if (surface->viewport.has_src_rect)
{
if (!G_APPROX_VALUE (surface->viewport.src_rect.origin.x, 0.0,
FLT_EPSILON) ||
!G_APPROX_VALUE (surface->viewport.src_rect.origin.y, 0.0,
FLT_EPSILON) ||
!G_APPROX_VALUE (surface->viewport.src_rect.size.width *
surface->scale,
get_buffer_width (surface),
FLT_EPSILON) ||
!G_APPROX_VALUE (surface->viewport.src_rect.size.height *
surface->scale,
get_buffer_height (surface),
FLT_EPSILON))
{
meta_topic (META_DEBUG_RENDER,
"Surface can not be scanned out untransformed: viewport "
"source rect does not cover the whole buffer");
return FALSE;
}
}
return TRUE;
}
int
meta_wayland_surface_get_geometry_scale (MetaWaylandSurface *surface)
{
MetaWaylandActorSurface *actor_surface;
g_return_val_if_fail (META_IS_WAYLAND_ACTOR_SURFACE (surface->role), 1);
actor_surface = META_WAYLAND_ACTOR_SURFACE (surface->role);
return meta_wayland_actor_surface_get_geometry_scale (actor_surface);
}