wlbuffer.c 8.53 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
/* GStreamer Wayland video sink
 *
 * Copyright (C) 2014 Collabora Ltd.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301 USA.
 */

/* GstWlBuffer wraps wl_buffer and provides a mechanism for preventing
 * buffers from being re-used while the compositor is using them. This
 * is achieved by adding a reference to the GstBuffer as soon as its
 * associated wl_buffer is sent to the compositor and by removing this
 * reference as soon as the compositor sends a wl_buffer::release message.
 *
 * This mechanism is a bit complicated, though, because it adds cyclic
 * references that can be dangerous. The reference cycles looks like:
 *
 *   ----------------
31 32 33 34 35 36 37 38
 *   | GstWlDisplay | ---------------------------->
 *   ----------------                              |
 *                                                 |
 *                                                 V
 *   -----------------     -------------     ---------------
 *   | GstBufferPool | --> | GstBuffer | ==> | GstWlBuffer |
 *   |               | <-- |           | <-- |             |
 *   -----------------     -------------     ---------------
39 40 41 42 43 44 45 46 47 48 49 50
 *
 * A GstBufferPool normally holds references to its GstBuffers and each buffer
 * holds a reference to a GstWlBuffer (saved in the GstMiniObject qdata).
 * When a GstBuffer is in use, it holds a reference back to the pool and the
 * pool doesn't hold a reference to the GstBuffer. When the GstBuffer is unrefed
 * externally, it returns back to the pool and the pool holds again a reference
 * to the buffer.
 *
 * Now when the compositor is using a buffer, the GstWlBuffer also holds a ref
 * to the GstBuffer, which prevents it from returning to the pool. When the
 * last GstWlBuffer receives a release event and unrefs the last GstBuffer,
 * the GstBufferPool will be able to stop and if no-one is holding a strong
51 52
 * ref to it, it will be destroyed. This will destroy the pool's GstBuffers and
 * also the GstWlBuffers. This will all happen in the same context of the last
53 54
 * gst_buffer_unref, which will be called from the buffer_release() callback.
 *
55 56 57 58 59 60
 * The problem here lies in the fact that buffer_release() will be called
 * from the event loop thread of GstWlDisplay, so it's as if the display
 * holds a reference to the GstWlBuffer, but without having an actual reference.
 * When we kill the display, there is no way for the GstWlBuffer, the associated
 * GstBuffer and the GstBufferPool to get destroyed, so we are going to leak a
 * fair ammount of memory.
61
 *
62 63
 * Normally, this rarely happens, because the compositor releases buffers
 * almost immediately and when waylandsink stops, they are already released.
64 65
 *
 * However, we want to be absolutely certain, so a solution is introduced
66
 * by registering all the GstWlBuffers with the display and explicitly
67 68 69 70 71 72 73 74 75 76
 * releasing all the buffer references as soon as the display is destroyed.
 *
 * When the GstWlDisplay is finalized, it takes a reference to all the
 * registered GstWlBuffers and then calls gst_wl_buffer_force_release_and_unref,
 * which releases the potential reference to the GstBuffer, destroys the
 * underlying wl_buffer and removes the reference that GstWlDisplay is holding.
 * At that point, either the GstBuffer is alive somewhere and still holds a ref
 * to the GstWlBuffer, which it will release when it gets destroyed, or the
 * GstBuffer was destroyed in the meantime and the GstWlBuffer gets destroyed
 * as soon as we remove the reference that GstWlDisplay holds.
77 78 79 80 81 82 83 84 85 86 87 88
 */

#include "wlbuffer.h"

GST_DEBUG_CATEGORY_EXTERN (gstwayland_debug);
#define GST_CAT_DEFAULT gstwayland_debug

G_DEFINE_TYPE (GstWlBuffer, gst_wl_buffer, G_TYPE_OBJECT);

static G_DEFINE_QUARK (GstWlBufferQDataQuark, gst_wl_buffer_qdata);

static void
89
gst_wl_buffer_dispose (GObject * gobject)
90 91 92
{
  GstWlBuffer *self = GST_WL_BUFFER (gobject);

93 94 95 96 97 98
  GST_TRACE_OBJECT (self, "dispose");

  /* if the display is shutting down and we are trying to dipose
   * the GstWlBuffer from another thread, unregister_buffer() will
   * block and in the end the display will increase the refcount
   * of this GstWlBuffer, so it will not be finalized */
99 100
  if (self->display)
    gst_wl_display_unregister_buffer (self->display, self);
101 102 103 104 105 106 107 108 109 110 111 112 113

  G_OBJECT_CLASS (gst_wl_buffer_parent_class)->dispose (gobject);
}

static void
gst_wl_buffer_finalize (GObject * gobject)
{
  GstWlBuffer *self = GST_WL_BUFFER (gobject);

  GST_TRACE_OBJECT (self, "finalize");

  if (self->wlbuffer)
    wl_buffer_destroy (self->wlbuffer);
114 115 116 117 118 119 120 121 122

  G_OBJECT_CLASS (gst_wl_buffer_parent_class)->finalize (gobject);
}

static void
gst_wl_buffer_class_init (GstWlBufferClass * klass)
{
  GObjectClass *object_class = (GObjectClass *) klass;

123
  object_class->dispose = gst_wl_buffer_dispose;
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
  object_class->finalize = gst_wl_buffer_finalize;
}

static void
gst_wl_buffer_init (GstWlBuffer * self)
{
}

static void
buffer_release (void *data, struct wl_buffer *wl_buffer)
{
  GstWlBuffer *self = data;

  GST_LOG_OBJECT (self, "wl_buffer::release (GstBuffer: %p)", self->gstbuffer);

  self->used_by_compositor = FALSE;

  /* unref should be last, because it may end up destroying the GstWlBuffer */
  gst_buffer_unref (self->gstbuffer);
}

static const struct wl_buffer_listener buffer_listener = {
  buffer_release
};

149 150 151 152 153 154 155 156 157 158 159 160 161
static void
gstbuffer_disposed (GstWlBuffer * self)
{
  g_assert (!self->used_by_compositor);
  self->gstbuffer = NULL;

  GST_TRACE_OBJECT (self, "owning GstBuffer was finalized");

  /* this will normally destroy the GstWlBuffer, unless the display is
   * finalizing and it has taken an additional reference to it */
  g_object_unref (self);
}

162
GstWlBuffer *
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
gst_buffer_add_wl_buffer (GstBuffer * gstbuffer, struct wl_buffer *wlbuffer,
    GstWlDisplay * display)
{
  GstWlBuffer *self;

  self = g_object_new (GST_TYPE_WL_BUFFER, NULL);
  self->gstbuffer = gstbuffer;
  self->wlbuffer = wlbuffer;
  self->display = display;

  gst_wl_display_register_buffer (self->display, self);

  wl_buffer_add_listener (self->wlbuffer, &buffer_listener, self);

  gst_mini_object_set_qdata ((GstMiniObject *) gstbuffer,
178
      gst_wl_buffer_qdata_quark (), self, (GDestroyNotify) gstbuffer_disposed);
179 180

  return self;
181 182 183 184 185 186 187 188 189 190 191 192
}

GstWlBuffer *
gst_buffer_get_wl_buffer (GstBuffer * gstbuffer)
{
  return gst_mini_object_get_qdata ((GstMiniObject *) gstbuffer,
      gst_wl_buffer_qdata_quark ());
}

void
gst_wl_buffer_force_release_and_unref (GstWlBuffer * self)
{
193 194
  /* Force a buffer release.
   * At this point, the GstWlDisplay has killed its event loop,
195 196 197 198 199 200
   * so we don't need to worry about buffer_release() being called
   * at the same time from the event loop thread */
  if (self->used_by_compositor) {
    GST_DEBUG_OBJECT (self, "forcing wl_buffer::release (GstBuffer: %p)",
        self->gstbuffer);
    self->used_by_compositor = FALSE;
201
    gst_buffer_unref (self->gstbuffer);
202 203
  }

204 205 206 207 208 209 210 211 212 213
  /* Finalize this GstWlBuffer early.
   * This method has been called as a result of the display shutting down,
   * so we need to stop using any wayland resources and disconnect from
   * the display. The GstWlBuffer stays alive, though, to avoid race
   * conditions with the GstBuffer being destroyed from another thread.
   * The last reference is either owned by the GstBuffer or by us and
   * it will be released at the end of this function. */
  GST_TRACE_OBJECT (self, "finalizing early");
  wl_buffer_destroy (self->wlbuffer);
  self->wlbuffer = NULL;
214
  self->display = NULL;
215 216

  /* remove the reference that the caller (GstWlDisplay) owns */
217 218 219 220
  g_object_unref (self);
}

void
221
gst_wl_buffer_attach (GstWlBuffer * self, struct wl_surface *surface)
222
{
223 224 225 226
  if (self->used_by_compositor) {
    GST_DEBUG_OBJECT (self, "buffer used by compositor %p", self->gstbuffer);
    return;
  }
227

228
  wl_surface_attach (surface, self->wlbuffer, 0, 0);
229 230 231 232 233 234 235

  /* Add a reference to the buffer. This represents the fact that
   * the compositor is using the buffer and it should not return
   * back to the pool and be re-used until the compositor releases it. */
  gst_buffer_ref (self->gstbuffer);
  self->used_by_compositor = TRUE;
}