[mutter] wayland: Move buffer use count to MetaWaylandSurface
- From: Jonas Ådahl <jadahl src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [mutter] wayland: Move buffer use count to MetaWaylandSurface
- Date: Tue, 29 Mar 2016 10:32:36 +0000 (UTC)
commit 10a01148561879f398f2b0a02e3416e6ca4f5fa9
Author: Jonas Ådahl <jadahl gmail com>
Date: Wed Mar 16 14:47:53 2016 +0800
wayland: Move buffer use count to MetaWaylandSurface
Each wl_surface.commit with a newly attached buffer should result in
one wl_buffer.release for the attached buffer. For example attaching
the same buffer to two different surfaces must always result in two
wl_buffer.release events being emitted by the server. The client is
responsible for counting the wl_buffer.release events and be sure to
have received as many release events as it has attached and committed
the buffer, before reusing it.
https://bugzilla.gnome.org/show_bug.cgi?id=762828
src/compositor/meta-surface-actor-wayland.c | 3 +-
src/core/window.c | 4 +-
src/wayland/meta-wayland-buffer.c | 22 ----
src/wayland/meta-wayland-buffer.h | 3 -
src/wayland/meta-wayland-pointer.c | 15 ++--
src/wayland/meta-wayland-surface.c | 152 ++++++++++++++++-----------
src/wayland/meta-wayland-surface.h | 17 +++-
7 files changed, 117 insertions(+), 99 deletions(-)
---
diff --git a/src/compositor/meta-surface-actor-wayland.c b/src/compositor/meta-surface-actor-wayland.c
index bb8bed2..6b6655e 100644
--- a/src/compositor/meta-surface-actor-wayland.c
+++ b/src/compositor/meta-surface-actor-wayland.c
@@ -136,7 +136,8 @@ meta_surface_actor_wayland_get_subsurface_rect (MetaSurfaceActorWayland *self,
MetaRectangle *rect)
{
MetaWaylandSurface *surface = meta_surface_actor_wayland_get_surface (self);
- CoglTexture *texture = surface->buffer->texture;
+ MetaWaylandBuffer *buffer = meta_wayland_surface_get_buffer (surface);
+ CoglTexture *texture = buffer->texture;
MetaWindow *toplevel_window;
int monitor_scale;
float x, y;
diff --git a/src/core/window.c b/src/core/window.c
index 45cfcf4..bc481dc 100644
--- a/src/core/window.c
+++ b/src/core/window.c
@@ -726,7 +726,7 @@ client_window_should_be_mapped (MetaWindow *window)
{
#ifdef HAVE_WAYLAND
if (window->client_type == META_WINDOW_CLIENT_TYPE_WAYLAND &&
- !window->surface->buffer)
+ !meta_wayland_surface_get_buffer (window->surface))
return FALSE;
#endif
@@ -1554,7 +1554,7 @@ meta_window_should_be_showing (MetaWindow *window)
{
#ifdef HAVE_WAYLAND
if (window->client_type == META_WINDOW_CLIENT_TYPE_WAYLAND &&
- !window->surface->buffer)
+ !meta_wayland_surface_get_buffer (window->surface))
return FALSE;
#endif
diff --git a/src/wayland/meta-wayland-buffer.c b/src/wayland/meta-wayland-buffer.c
index b59fd30..775bd67 100644
--- a/src/wayland/meta-wayland-buffer.c
+++ b/src/wayland/meta-wayland-buffer.c
@@ -53,25 +53,6 @@ meta_wayland_buffer_destroy_handler (struct wl_listener *listener,
g_object_unref (buffer);
}
-void
-meta_wayland_buffer_ref_use_count (MetaWaylandBuffer *buffer)
-{
- g_warn_if_fail (buffer->resource);
-
- buffer->use_count++;
-}
-
-void
-meta_wayland_buffer_unref_use_count (MetaWaylandBuffer *buffer)
-{
- g_return_if_fail (buffer->use_count != 0);
-
- buffer->use_count--;
-
- if (buffer->use_count == 0 && buffer->resource)
- wl_resource_queue_event (buffer->resource, WL_BUFFER_RELEASE);
-}
-
MetaWaylandBuffer *
meta_wayland_buffer_from_resource (struct wl_resource *resource)
{
@@ -106,7 +87,6 @@ meta_wayland_buffer_ensure_texture (MetaWaylandBuffer *buffer)
CoglTexture *texture;
struct wl_shm_buffer *shm_buffer;
- g_return_val_if_fail (buffer->use_count != 0, NULL);
g_return_val_if_fail (buffer->resource, NULL);
if (buffer->texture)
@@ -142,8 +122,6 @@ meta_wayland_buffer_process_damage (MetaWaylandBuffer *buffer,
{
struct wl_shm_buffer *shm_buffer;
- g_return_if_fail (buffer->use_count != 0);
-
shm_buffer = wl_shm_buffer_get (buffer->resource);
if (shm_buffer)
diff --git a/src/wayland/meta-wayland-buffer.h b/src/wayland/meta-wayland-buffer.h
index dcfef2d..977892b 100644
--- a/src/wayland/meta-wayland-buffer.h
+++ b/src/wayland/meta-wayland-buffer.h
@@ -39,7 +39,6 @@ struct _MetaWaylandBuffer
struct wl_listener destroy_listener;
CoglTexture *texture;
- uint32_t use_count;
};
#define META_TYPE_WAYLAND_BUFFER (meta_wayland_buffer_get_type ())
@@ -47,8 +46,6 @@ G_DECLARE_FINAL_TYPE (MetaWaylandBuffer, meta_wayland_buffer,
META, WAYLAND_BUFFER, GObject);
MetaWaylandBuffer * meta_wayland_buffer_from_resource (struct wl_resource *resource);
-void meta_wayland_buffer_ref_use_count (MetaWaylandBuffer *buffer);
-void meta_wayland_buffer_unref_use_count (MetaWaylandBuffer *buffer);
CoglTexture * meta_wayland_buffer_ensure_texture (MetaWaylandBuffer *buffer);
void meta_wayland_buffer_process_damage (MetaWaylandBuffer *buffer,
cairo_region_t *region);
diff --git a/src/wayland/meta-wayland-pointer.c b/src/wayland/meta-wayland-pointer.c
index f7106c6..173d7d0 100644
--- a/src/wayland/meta-wayland-pointer.c
+++ b/src/wayland/meta-wayland-pointer.c
@@ -966,24 +966,25 @@ update_cursor_sprite_texture (MetaWaylandSurface *surface)
MetaWaylandSurfaceRoleCursor *cursor_role =
META_WAYLAND_SURFACE_ROLE_CURSOR (surface->role);
MetaCursorSprite *cursor_sprite = cursor_role->cursor_sprite;
+ MetaWaylandBuffer *buffer = meta_wayland_surface_get_buffer (surface);
- g_return_if_fail (!surface->buffer || surface->buffer->texture);
+ g_return_if_fail (!buffer || buffer->texture);
- if (surface->buffer)
+ if (buffer)
{
meta_cursor_sprite_set_texture (cursor_sprite,
- surface->buffer->texture,
+ buffer->texture,
cursor_role->hot_x * surface->scale,
cursor_role->hot_y * surface->scale);
- if (surface->using_buffer)
+ if (surface->buffer_ref.use_count > 0)
{
- struct wl_resource *buffer;
+ struct wl_resource *buffer_resource;
- buffer = surface->buffer->resource;
+ buffer_resource = buffer->resource;
meta_cursor_renderer_realize_cursor_from_wl_buffer (cursor_renderer,
cursor_sprite,
- buffer);
+ buffer_resource);
}
}
else
diff --git a/src/wayland/meta-wayland-surface.c b/src/wayland/meta-wayland-surface.c
index 5e92e13..7e1fb01 100644
--- a/src/wayland/meta-wayland-surface.c
+++ b/src/wayland/meta-wayland-surface.c
@@ -176,55 +176,28 @@ meta_wayland_surface_assign_role (MetaWaylandSurface *surface,
}
static void
-surface_use_buffer (MetaWaylandSurface *surface)
-{
- g_return_if_fail (!surface->using_buffer);
-
- meta_wayland_buffer_ref_use_count (surface->buffer);
- surface->using_buffer = TRUE;
-}
-
-static void
-surface_stop_using_buffer (MetaWaylandSurface *surface)
-{
- if (!surface->using_buffer)
- return;
-
- meta_wayland_buffer_unref_use_count (surface->buffer);
- surface->using_buffer = FALSE;
-}
-
-static void
-surface_set_buffer (MetaWaylandSurface *surface,
- MetaWaylandBuffer *buffer)
-{
- if (surface->buffer == buffer)
- return;
-
- if (surface->buffer)
- surface_stop_using_buffer (surface);
-
- g_set_object (&surface->buffer, buffer);
-}
-
-static void
surface_process_damage (MetaWaylandSurface *surface,
cairo_region_t *region)
{
+ MetaWaylandBuffer *buffer = surface->buffer_ref.buffer;
unsigned int buffer_width;
unsigned int buffer_height;
cairo_rectangle_int_t surface_rect;
cairo_region_t *scaled_region;
int i, n_rectangles;
- if (!surface->buffer)
+ /* 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;
/* 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). */
- buffer_width = cogl_texture_get_width (surface->buffer->texture);
- buffer_height = cogl_texture_get_height (surface->buffer->texture);
+ buffer_width = cogl_texture_get_width (buffer->texture);
+ buffer_height = cogl_texture_get_height (buffer->texture);
surface_rect = (cairo_rectangle_int_t) {
.width = buffer_width / surface->scale,
.height = buffer_height / surface->scale,
@@ -236,7 +209,7 @@ surface_process_damage (MetaWaylandSurface *surface,
scaled_region = meta_region_scale (region, surface->scale);
/* First update the buffer. */
- meta_wayland_buffer_process_damage (surface->buffer, scaled_region);
+ meta_wayland_buffer_process_damage (buffer, scaled_region);
/* Now damage the actor. The actor expects damage in the unscaled texture
* coordinate space, i.e. same as the buffer. */
@@ -290,7 +263,7 @@ calculate_surface_window_geometry (MetaWaylandSurface *surface,
if (!CLUTTER_ACTOR_IS_VISIBLE (CLUTTER_ACTOR (surface_actor)))
return;
- if (!surface->buffer)
+ if (!surface->buffer_ref.buffer)
return;
meta_surface_actor_wayland_get_subsurface_rect (surface_actor,
@@ -326,6 +299,36 @@ destroy_window (MetaWaylandSurface *surface)
g_assert (surface->window == NULL);
}
+MetaWaylandBuffer *
+meta_wayland_surface_get_buffer (MetaWaylandSurface *surface)
+{
+ return surface->buffer_ref.buffer;
+}
+
+void
+meta_wayland_surface_ref_buffer_use_count (MetaWaylandSurface *surface)
+{
+ g_return_if_fail (surface->buffer_ref.buffer);
+ g_warn_if_fail (surface->buffer_ref.buffer->resource);
+
+ surface->buffer_ref.use_count++;
+}
+
+void
+meta_wayland_surface_unref_buffer_use_count (MetaWaylandSurface *surface)
+{
+ MetaWaylandBuffer *buffer = surface->buffer_ref.buffer;
+
+ g_return_if_fail (surface->buffer_ref.use_count != 0);
+
+ surface->buffer_ref.use_count--;
+
+ g_return_if_fail (buffer);
+
+ if (surface->buffer_ref.use_count == 0 && buffer->resource)
+ wl_resource_queue_event (buffer->resource, WL_BUFFER_RELEASE);
+}
+
static void
queue_surface_actor_frame_callbacks (MetaWaylandSurface *surface,
MetaWaylandPendingState *pending)
@@ -344,6 +347,7 @@ toplevel_surface_commit (MetaWaylandSurfaceRole *surface_role,
{
MetaWaylandSurface *surface =
meta_wayland_surface_role_get_surface (surface_role);
+ MetaWaylandBuffer *buffer = surface->buffer_ref.buffer;
MetaWindow *window = surface->window;
queue_surface_actor_frame_callbacks (surface, pending);
@@ -359,12 +363,12 @@ toplevel_surface_commit (MetaWaylandSurfaceRole *surface_role,
/* For wl_shell, it's equivalent to an unmap. Semantics
* are poorly defined, so we can choose some that are
* convenient for us. */
- if (surface->buffer && !window)
+ if (buffer && !window)
{
window = meta_window_wayland_new (meta_get_display (), surface);
meta_wayland_surface_set_window (surface, window);
}
- else if (surface->buffer == NULL && window)
+ else if (buffer == NULL && window)
{
destroy_window (surface);
return;
@@ -372,7 +376,7 @@ toplevel_surface_commit (MetaWaylandSurfaceRole *surface_role,
}
else
{
- if (surface->buffer == NULL)
+ if (buffer == NULL)
{
/* XDG surfaces can't commit NULL buffers */
wl_resource_post_error (surface->resource,
@@ -390,7 +394,7 @@ toplevel_surface_commit (MetaWaylandSurfaceRole *surface_role,
{
MetaRectangle geom = { 0 };
- CoglTexture *texture = surface->buffer->texture;
+ CoglTexture *texture = buffer->texture;
/* Update the buffer rect immediately. */
window->buffer_rect.width = cogl_texture_get_width (texture);
window->buffer_rect.height = cogl_texture_get_height (texture);
@@ -559,7 +563,7 @@ subsurface_surface_commit (MetaWaylandSurfaceRole *surface_role,
queue_surface_actor_frame_callbacks (surface, pending);
- if (surface->buffer != NULL)
+ if (surface->buffer_ref.buffer != NULL)
clutter_actor_show (CLUTTER_ACTOR (surface_actor));
else
clutter_actor_hide (CLUTTER_ACTOR (surface_actor));
@@ -656,28 +660,46 @@ static void
apply_pending_state (MetaWaylandSurface *surface,
MetaWaylandPendingState *pending)
{
- gboolean release_new_buffer = FALSE;
+ MetaSurfaceActorWayland *surface_actor_wayland =
+ META_SURFACE_ACTOR_WAYLAND (surface->surface_actor);
if (pending->newly_attached)
{
- if (!surface->buffer && surface->window)
+ gboolean switched_buffer;
+
+ if (!surface->buffer_ref.buffer && surface->window)
meta_window_queue (surface->window, META_QUEUE_CALC_SHOWING);
- surface_set_buffer (surface, pending->buffer);
+ /* 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)
+ meta_wayland_surface_unref_buffer_use_count (surface);
+
+ switched_buffer = g_set_object (&surface->buffer_ref.buffer,
+ pending->buffer);
- if (pending->buffer && !surface->using_buffer)
- {
- struct wl_shm_buffer *shm_buffer = wl_shm_buffer_get (pending->buffer->resource);
+ if (pending->buffer)
+ meta_wayland_surface_ref_buffer_use_count (surface);
- surface_use_buffer (surface);
- CoglTexture *texture = meta_wayland_buffer_ensure_texture (pending->buffer);
- meta_surface_actor_wayland_set_texture (META_SURFACE_ACTOR_WAYLAND (surface->surface_actor),
texture);
+ if (switched_buffer && pending->buffer)
+ {
+ CoglTexture *texture;
- /* Release the buffer as soon as possible, so the client can reuse it
- */
- if (shm_buffer)
- release_new_buffer = TRUE;
+ texture = meta_wayland_buffer_ensure_texture (pending->buffer);
+ meta_surface_actor_wayland_set_texture (surface_actor_wayland,
+ 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 = (pending->buffer &&
+ !wl_shm_buffer_get (pending->buffer->resource));
}
if (pending->scale > 0)
@@ -686,8 +708,12 @@ apply_pending_state (MetaWaylandSurface *surface,
if (!cairo_region_is_empty (pending->damage))
surface_process_damage (surface, pending->damage);
- if (release_new_buffer)
- surface_stop_using_buffer (surface);
+ /* If we have a buffer that we are not using, decrease the use count so it may
+ * be released if no-one else has a use-reference to it.
+ */
+ if (pending->newly_attached &&
+ !surface->buffer_held && surface->buffer_ref.buffer)
+ meta_wayland_surface_unref_buffer_use_count (surface);
surface->offset_x += pending->dx;
surface->offset_y += pending->dy;
@@ -732,8 +758,7 @@ apply_pending_state (MetaWaylandSurface *surface,
pending_state_signals[PENDING_STATE_SIGNAL_APPLIED],
0);
- meta_surface_actor_wayland_sync_state (
- META_SURFACE_ACTOR_WAYLAND (surface->surface_actor));
+ meta_surface_actor_wayland_sync_state (surface_actor_wayland);
pending_state_reset (pending);
@@ -1122,7 +1147,10 @@ wl_surface_destructor (struct wl_resource *resource)
if (surface->window)
destroy_window (surface);
- surface_set_buffer (surface, NULL);
+ if (surface->buffer_held)
+ meta_wayland_surface_unref_buffer_use_count (surface);
+ g_clear_object (&surface->buffer_ref.buffer);
+
g_clear_object (&surface->pending);
if (surface->opaque_region)
@@ -2771,10 +2799,10 @@ meta_wayland_surface_calculate_input_region (MetaWaylandSurface *surface)
cairo_rectangle_int_t buffer_rect;
CoglTexture *texture;
- if (!surface->buffer)
+ if (!surface->buffer_ref.buffer)
return NULL;
- texture = surface->buffer->texture;
+ texture = surface->buffer_ref.buffer->texture;
buffer_rect = (cairo_rectangle_int_t) {
.width = cogl_texture_get_width (texture) / surface->scale,
.height = cogl_texture_get_height (texture) / surface->scale,
diff --git a/src/wayland/meta-wayland-surface.h b/src/wayland/meta-wayland-surface.h
index 806903e..e7523d8 100644
--- a/src/wayland/meta-wayland-surface.h
+++ b/src/wayland/meta-wayland-surface.h
@@ -151,8 +151,6 @@ struct _MetaWaylandSurface
MetaSurfaceActor *surface_actor;
MetaWaylandSurfaceRole *role;
MetaWindow *window;
- MetaWaylandBuffer *buffer;
- gboolean using_buffer;
cairo_region_t *input_region;
cairo_region_t *opaque_region;
int scale;
@@ -160,6 +158,15 @@ struct _MetaWaylandSurface
GList *subsurfaces;
GHashTable *outputs_to_destroy_notify_id;
+ /* Buffer reference state. */
+ struct {
+ MetaWaylandBuffer *buffer;
+ unsigned int use_count;
+ } buffer_ref;
+
+ /* Buffer renderer state. */
+ gboolean buffer_held;
+
/* List of pending frame callbacks that needs to stay queued longer than one
* commit sequence, such as when it has not yet been assigned a role.
*/
@@ -230,6 +237,12 @@ MetaWaylandSurface *meta_wayland_surface_create (MetaWaylandCompositor *composit
gboolean meta_wayland_surface_assign_role (MetaWaylandSurface *surface,
GType role_type);
+MetaWaylandBuffer *meta_wayland_surface_get_buffer (MetaWaylandSurface *surface);
+
+void meta_wayland_surface_ref_buffer_use_count (MetaWaylandSurface *surface);
+
+void meta_wayland_surface_unref_buffer_use_count (MetaWaylandSurface *surface);
+
void meta_wayland_surface_set_window (MetaWaylandSurface *surface,
MetaWindow *window);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]