• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* GStreamer Wayland video sink
2  *
3  * Copyright (C) 2014 Collabora Ltd.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the Free
17  * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  * Boston, MA 02110-1301 USA.
19  */
20 
21 /* GstWlBuffer wraps wl_buffer and provides a mechanism for preventing
22  * buffers from being re-used while the compositor is using them. This
23  * is achieved by adding a reference to the GstBuffer as soon as its
24  * associated wl_buffer is sent to the compositor and by removing this
25  * reference as soon as the compositor sends a wl_buffer::release message.
26  *
27  * This mechanism is a bit complicated, though, because it adds cyclic
28  * references that can be dangerous. The reference cycles looks like:
29  *
30  *   ----------------
31  *   | GstWlDisplay | ---------------------------->
32  *   ----------------                              |
33  *                                                 |
34  *                                                 V
35  *   -----------------     -------------     ---------------
36  *   | GstBufferPool | --> | GstBuffer | ==> | GstWlBuffer |
37  *   |               | <-- |           | <-- |             |
38  *   -----------------     -------------     ---------------
39  *
40  * A GstBufferPool normally holds references to its GstBuffers and each buffer
41  * holds a reference to a GstWlBuffer (saved in the GstMiniObject weak ref data).
42  * When a GstBuffer is in use, it holds a reference back to the pool and the
43  * pool doesn't hold a reference to the GstBuffer. When the GstBuffer is unrefed
44  * externally, it returns back to the pool and the pool holds again a reference
45  * to the buffer.
46  *
47  * Now when the compositor is using a buffer, the GstWlBuffer also holds a ref
48  * to the GstBuffer, which prevents it from returning to the pool. When the
49  * last GstWlBuffer receives a release event and unrefs the last GstBuffer,
50  * the GstBufferPool will be able to stop and if no-one is holding a strong
51  * ref to it, it will be destroyed. This will destroy the pool's GstBuffers and
52  * also the GstWlBuffers. This will all happen in the same context of the last
53  * gst_buffer_unref, which will be called from the buffer_release() callback.
54  *
55  * The problem here lies in the fact that buffer_release() will be called
56  * from the event loop thread of GstWlDisplay, so it's as if the display
57  * holds a reference to the GstWlBuffer, but without having an actual reference.
58  * When we kill the display, there is no way for the GstWlBuffer, the associated
59  * GstBuffer and the GstBufferPool to get destroyed, so we are going to leak a
60  * fair amount of memory.
61  *
62  * Normally, this rarely happens, because the compositor releases buffers
63  * 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  * releasing all the buffer references as soon as the display is destroyed.
68  *
69  * When the GstWlDisplay is finalized, it takes a reference to all the
70  * registered GstWlBuffers and then calls gst_wl_buffer_force_release_and_unref,
71  * which releases the potential reference to the GstBuffer, destroys the
72  * underlying wl_buffer and removes the reference that GstWlDisplay is holding.
73  * At that point, either the GstBuffer is alive somewhere and still holds a ref
74  * to the GstWlBuffer, which it will release when it gets destroyed, or the
75  * GstBuffer was destroyed in the meantime and the GstWlBuffer gets destroyed
76  * as soon as we remove the reference that GstWlDisplay holds.
77  */
78 
79 #include "wlbuffer.h"
80 
81 GST_DEBUG_CATEGORY_EXTERN (gstwayland_debug);
82 #define GST_CAT_DEFAULT gstwayland_debug
83 
84 G_DEFINE_TYPE (GstWlBuffer, gst_wl_buffer, G_TYPE_OBJECT);
85 
86 static void
gst_wl_buffer_dispose(GObject * gobject)87 gst_wl_buffer_dispose (GObject * gobject)
88 {
89   GstWlBuffer *self = GST_WL_BUFFER (gobject);
90 
91   GST_TRACE_OBJECT (self, "dispose");
92 
93   /* if the display is shutting down and we are trying to dipose
94    * the GstWlBuffer from another thread, unregister_buffer() will
95    * block and in the end the display will increase the refcount
96    * of this GstWlBuffer, so it will not be finalized */
97   if (self->display) {
98     gst_wl_display_unregister_buffer (self->display, self->gstmem);
99   }
100 
101   G_OBJECT_CLASS (gst_wl_buffer_parent_class)->dispose (gobject);
102 }
103 
104 static void
gst_wl_buffer_finalize(GObject * gobject)105 gst_wl_buffer_finalize (GObject * gobject)
106 {
107   GstWlBuffer *self = GST_WL_BUFFER (gobject);
108 
109   GST_TRACE_OBJECT (self, "finalize");
110 
111   if (self->wlbuffer)
112     wl_buffer_destroy (self->wlbuffer);
113 
114   G_OBJECT_CLASS (gst_wl_buffer_parent_class)->finalize (gobject);
115 }
116 
117 static void
gst_wl_buffer_class_init(GstWlBufferClass * klass)118 gst_wl_buffer_class_init (GstWlBufferClass * klass)
119 {
120   GObjectClass *object_class = (GObjectClass *) klass;
121 
122   object_class->dispose = gst_wl_buffer_dispose;
123   object_class->finalize = gst_wl_buffer_finalize;
124 }
125 
126 static void
gst_wl_buffer_init(GstWlBuffer * self)127 gst_wl_buffer_init (GstWlBuffer * self)
128 {
129 }
130 
131 static void
buffer_release(void * data,struct wl_buffer * wl_buffer)132 buffer_release (void *data, struct wl_buffer *wl_buffer)
133 {
134   GstWlBuffer *self = data;
135   GstBuffer *buf = self->current_gstbuffer;
136 
137   GST_LOG_OBJECT (self, "wl_buffer::release (GstBuffer: %p)", buf);
138 
139   self->used_by_compositor = FALSE;
140   self->current_gstbuffer = NULL;
141 
142   /* unref should be last, because it may end up destroying the GstWlBuffer */
143   gst_buffer_unref (buf);
144 }
145 
146 static const struct wl_buffer_listener buffer_listener = {
147   buffer_release
148 };
149 
150 static void
gstmemory_disposed(GstWlBuffer * self)151 gstmemory_disposed (GstWlBuffer * self)
152 {
153   g_assert (!self->used_by_compositor);
154 
155   GST_TRACE_OBJECT (self, "owning GstMemory was finalized");
156 
157   /* this will normally destroy the GstWlBuffer, unless the display is
158    * finalizing and it has taken an additional reference to it */
159   g_object_unref (self);
160 }
161 
162 GstWlBuffer *
gst_buffer_add_wl_buffer(GstBuffer * gstbuffer,struct wl_buffer * wlbuffer,GstWlDisplay * display)163 gst_buffer_add_wl_buffer (GstBuffer * gstbuffer, struct wl_buffer *wlbuffer,
164     GstWlDisplay * display)
165 {
166   GstWlBuffer *self;
167 
168   self = g_object_new (GST_TYPE_WL_BUFFER, NULL);
169   self->current_gstbuffer = gstbuffer;
170   self->wlbuffer = wlbuffer;
171   self->display = display;
172   self->gstmem = gst_buffer_peek_memory (gstbuffer, 0);
173 
174   gst_wl_display_register_buffer (self->display, self->gstmem, self);
175 
176   wl_buffer_add_listener (self->wlbuffer, &buffer_listener, self);
177 
178   gst_mini_object_weak_ref (GST_MINI_OBJECT (self->gstmem),
179       (GstMiniObjectNotify) gstmemory_disposed, self);
180 
181 
182   return self;
183 }
184 
185 GstWlBuffer *
gst_buffer_get_wl_buffer(GstWlDisplay * display,GstBuffer * gstbuffer)186 gst_buffer_get_wl_buffer (GstWlDisplay * display, GstBuffer * gstbuffer)
187 {
188   GstMemory *mem0;
189   GstWlBuffer *wlbuf;
190 
191   if (!gstbuffer)
192     return NULL;
193 
194   mem0 = gst_buffer_peek_memory (gstbuffer, 0);
195 
196   wlbuf = gst_wl_display_lookup_buffer (display, mem0);
197   if (wlbuf)
198     wlbuf->current_gstbuffer = gstbuffer;
199 
200   return wlbuf;
201 }
202 
203 void
gst_wl_buffer_force_release_and_unref(GstBuffer * buf,GstWlBuffer * self)204 gst_wl_buffer_force_release_and_unref (GstBuffer * buf, GstWlBuffer * self)
205 {
206   /* Force a buffer release.
207    * At this point, the GstWlDisplay has killed its event loop,
208    * so we don't need to worry about buffer_release() being called
209    * at the same time from the event loop thread */
210   if (self->used_by_compositor) {
211     GST_DEBUG_OBJECT (self, "forcing wl_buffer::release (GstBuffer: %p)",
212         self->current_gstbuffer);
213     self->used_by_compositor = FALSE;
214     gst_buffer_unref (self->current_gstbuffer);
215   }
216 
217   /* Finalize this GstWlBuffer early.
218    * This method has been called as a result of the display shutting down,
219    * so we need to stop using any wayland resources and disconnect from
220    * the display. The GstWlBuffer stays alive, though, to avoid race
221    * conditions with the GstBuffer being destroyed from another thread.
222    * The last reference is either owned by the GstBuffer or by us and
223    * it will be released at the end of this function. */
224   GST_TRACE_OBJECT (self, "finalizing early");
225   wl_buffer_destroy (self->wlbuffer);
226   self->wlbuffer = NULL;
227   self->display = NULL;
228   self->current_gstbuffer = NULL;
229 
230   /* remove the reference that the caller (GstWlDisplay) owns */
231   g_object_unref (self);
232 }
233 
234 void
gst_wl_buffer_attach(GstWlBuffer * self,struct wl_surface * surface)235 gst_wl_buffer_attach (GstWlBuffer * self, struct wl_surface *surface)
236 {
237   if (self->used_by_compositor) {
238     GST_DEBUG_OBJECT (self, "buffer used by compositor %p",
239         self->current_gstbuffer);
240     return;
241   }
242 
243   wl_surface_attach (surface, self->wlbuffer, 0, 0);
244 
245   /* Add a reference to the buffer. This represents the fact that
246    * the compositor is using the buffer and it should not return
247    * back to the pool and be re-used until the compositor releases it. */
248   gst_buffer_ref (self->current_gstbuffer);
249   self->used_by_compositor = TRUE;
250 }
251