allocators: add some since markers and misc other doc clean-ups
[platform/upstream/gstreamer.git] / gst-libs / gst / allocators / gstdmabuf.c
1 /* GStreamer dmabuf allocator
2  * Copyright (C) 2013 Linaro SA
3  * Author: Benjamin Gaignard <benjamin.gaignard@linaro.org> for Linaro.
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 mordetails.
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
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20
21 #include "gstdmabuf.h"
22
23 /**
24  * SECTION:gstdmabuf
25  * @short_description: Memory wrapper for Linux dmabuf memory
26  * @see_also: #GstMemory
27  *
28  * Since: 1.2
29  */
30
31 #ifdef HAVE_MMAP
32 #include <sys/mman.h>
33 #include <unistd.h>
34
35 /*
36  * GstDmaBufMemory
37  * @fd: the file descriptor associated this memory
38  * @data: mmapped address
39  * @mmapping_flags: mmapping flags
40  * @mmap_count: mmapping counter
41  * @lock: a mutex to make mmapping thread safe
42  */
43 typedef struct
44 {
45   GstMemory mem;
46
47   gint fd;
48   gpointer data;
49   gint mmapping_flags;
50   gint mmap_count;
51   GMutex lock;
52 } GstDmaBufMemory;
53
54 #define ALLOCATOR_NAME "dmabuf"
55
56 GST_DEBUG_CATEGORY_STATIC (dmabuf_debug);
57 #define GST_CAT_DEFAULT dmabuf_debug
58
59 static GstMemory *
60 _dmabuf_alloc (GstAllocator * allocator, gsize size,
61     GstAllocationParams * params)
62 {
63   g_warning ("Use dmabuf_mem_alloc() to allocate from this allocator");
64
65   return NULL;
66 }
67
68 static void
69 _dmabuf_free (GstAllocator * allocator, GstMemory * mem)
70 {
71   GstDmaBufMemory *dbmem = (GstDmaBufMemory *) mem;
72
73   if (dbmem->data)
74     g_warning ("Freeing memory still mapped");
75
76   close (dbmem->fd);
77   g_mutex_clear (&dbmem->lock);
78   g_slice_free (GstDmaBufMemory, dbmem);
79   GST_DEBUG ("%p: freed", dbmem);
80 }
81
82 static gpointer
83 _dmabuf_mem_map (GstDmaBufMemory * mem, gsize maxsize, GstMapFlags flags)
84 {
85   gint prot;
86   gpointer ret = NULL;
87
88   g_mutex_lock (&mem->lock);
89
90   prot = flags & GST_MAP_READ ? PROT_READ : 0;
91   prot |= flags & GST_MAP_WRITE ? PROT_WRITE : 0;
92
93   /* do not mmap twice the buffer */
94   if (mem->data) {
95     /* only return address if mapping flags are a subset
96      * of the previous flags */
97     if (mem->mmapping_flags & prot)
98       ret = mem->data;
99
100     goto out;
101   }
102
103   if (mem->fd != -1)
104     mem->data = mmap (0, maxsize, prot, MAP_SHARED, mem->fd, 0);
105
106   GST_DEBUG ("%p: fd %d: mapped %p", mem, mem->fd, mem->data);
107
108   if (mem->data) {
109     mem->mmapping_flags = prot;
110     mem->mem.size = maxsize;
111     mem->mmap_count++;
112     ret = mem->data;
113   }
114
115 out:
116   g_mutex_unlock (&mem->lock);
117   return ret;
118 }
119
120 static gboolean
121 _dmabuf_mem_unmap (GstDmaBufMemory * mem)
122 {
123   g_mutex_lock (&mem->lock);
124
125   if (mem->data && !(--mem->mmap_count)) {
126     munmap ((void *) mem->data, mem->mem.size);
127     mem->data = NULL;
128     mem->mem.size = 0;
129     mem->mmapping_flags = 0;
130     GST_DEBUG ("%p: fd %d unmapped", mem, mem->fd);
131   }
132   g_mutex_unlock (&mem->lock);
133   return TRUE;
134 }
135
136 static GstDmaBufMemory *
137 _dmabuf_mem_share (GstDmaBufMemory * mem, gssize offset, gsize size)
138 {
139   GstDmaBufMemory *sub;
140   GstMemory *parent;
141   GST_DEBUG ("%p: share %" G_GSSIZE_FORMAT " %" G_GSIZE_FORMAT, mem, offset,
142       size);
143
144   /* find the real parent */
145   if ((parent = mem->mem.parent) == NULL)
146     parent = (GstMemory *) mem;
147
148   if (size == -1)
149     size = mem->mem.size - offset;
150
151   sub = g_slice_new (GstDmaBufMemory);
152   /* the shared memory is always readonly */
153   gst_memory_init (GST_MEMORY_CAST (sub), GST_MINI_OBJECT_FLAGS (parent) |
154       GST_MINI_OBJECT_FLAG_LOCK_READONLY, mem->mem.allocator, parent,
155       mem->mem.maxsize, mem->mem.align, mem->mem.offset + offset, size);
156
157   return sub;
158 }
159
160 static GstDmaBufMemory *
161 _dmabuf_mem_copy (GstDmaBufMemory * mem, gssize offset, gsize size)
162 {
163   gint newfd = dup (mem->fd);
164
165   if (newfd == -1) {
166     GST_WARNING ("Can't duplicate dmabuf file descriptor");
167     return NULL;
168   }
169
170   GST_DEBUG ("%p: copy %" G_GSSIZE_FORMAT " %" G_GSIZE_FORMAT, mem, offset,
171       size);
172   return (GstDmaBufMemory *) gst_dmabuf_allocator_alloc (mem->mem.allocator,
173       newfd, size);
174 }
175
176 typedef struct
177 {
178   GstAllocator parent;
179 } dmabuf_mem_Allocator;
180
181 typedef struct
182 {
183   GstAllocatorClass parent_class;
184 } dmabuf_mem_AllocatorClass;
185
186 GType dmabuf_mem_allocator_get_type (void);
187 G_DEFINE_TYPE (dmabuf_mem_Allocator, dmabuf_mem_allocator, GST_TYPE_ALLOCATOR);
188
189 #define GST_TYPE_DMABUF_ALLOCATOR   (dmabuf_mem_allocator_get_type())
190 #define GST_IS_DMABUF_ALLOCATOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_DMABUF_ALLOCATOR))
191
192 static void
193 dmabuf_mem_allocator_class_init (dmabuf_mem_AllocatorClass * klass)
194 {
195   GstAllocatorClass *allocator_class;
196
197   allocator_class = (GstAllocatorClass *) klass;
198
199   allocator_class->alloc = _dmabuf_alloc;
200   allocator_class->free = _dmabuf_free;
201 }
202
203 static void
204 dmabuf_mem_allocator_init (dmabuf_mem_Allocator * allocator)
205 {
206   GstAllocator *alloc = GST_ALLOCATOR_CAST (allocator);
207
208   alloc->mem_type = ALLOCATOR_NAME;
209   alloc->mem_map = (GstMemoryMapFunction) _dmabuf_mem_map;
210   alloc->mem_unmap = (GstMemoryUnmapFunction) _dmabuf_mem_unmap;
211   alloc->mem_share = (GstMemoryShareFunction) _dmabuf_mem_share;
212   alloc->mem_copy = (GstMemoryCopyFunction) _dmabuf_mem_copy;
213 }
214
215 static void
216 _dmabuf_mem_init (void)
217 {
218   GstAllocator *allocator =
219       g_object_new (dmabuf_mem_allocator_get_type (), NULL);
220   gst_allocator_register (ALLOCATOR_NAME, allocator);
221
222   GST_DEBUG_CATEGORY_INIT (dmabuf_debug, "dmabuf", 0, "dmabuf memory");
223 }
224
225 /**
226  * gst_dmabuf_allocator_obtain:
227  *
228  * Return a dmabuf allocator.
229  *
230  * Returns: (transfer full): a dmabuf allocator, or NULL if the allocator
231  *    isn't available. Use gst_object_unref() to release the allocator after
232  *    usage
233  *
234  * Since: 1.2
235  */
236 GstAllocator *
237 gst_dmabuf_allocator_obtain (void)
238 {
239   static GOnce dmabuf_allocator_once = G_ONCE_INIT;
240   GstAllocator *allocator;
241
242   g_once (&dmabuf_allocator_once, (GThreadFunc) _dmabuf_mem_init, NULL);
243
244   allocator = gst_allocator_find (ALLOCATOR_NAME);
245   if (!allocator)
246     GST_WARNING ("No allocator named %s found", ALLOCATOR_NAME);
247   return allocator;
248 }
249
250 /**
251  * gst_dmabuf_allocator_alloc:
252  * @allocator: allocator to be used for this memory
253  * @fd: dmabuf file descriptor
254  * @size: memory size
255  *
256  * Return a %GstMemory that wraps a dmabuf file descriptor.
257  *
258  * Returns: (transfer full): a GstMemory based on @allocator.
259  * When the buffer will be released dmabuf allocator will close the @fd.
260  * The memory is only mmapped on gst_buffer_mmap() request.
261  *
262  * Since: 1.2
263  */
264 GstMemory *
265 gst_dmabuf_allocator_alloc (GstAllocator * allocator, gint fd, gsize size)
266 {
267   GstDmaBufMemory *mem;
268
269   if (!allocator) {
270     allocator = gst_dmabuf_allocator_obtain ();
271   }
272
273   if (!GST_IS_DMABUF_ALLOCATOR (allocator)) {
274     GST_WARNING ("it isn't the correct allocator for dmabuf");
275     return NULL;
276   }
277
278   GST_DEBUG ("alloc from allocator %p", allocator);
279
280   mem = g_slice_new (GstDmaBufMemory);
281
282   gst_memory_init (GST_MEMORY_CAST (mem), 0, allocator, NULL, size, 0, 0, 0);
283
284   mem->fd = fd;
285   mem->data = NULL;
286   mem->mmapping_flags = 0;
287   mem->mmap_count = 0;
288   g_mutex_init (&mem->lock);
289
290   GST_DEBUG ("%p: fd: %d size %d", mem, mem->fd, mem->mem.maxsize);
291
292   return (GstMemory *) mem;
293 }
294
295 /**
296  * gst_dmabuf_memory_get_fd:
297  * @mem: the memory to get the file descriptor
298  *
299  * Return the file descriptor associated with @mem.
300  *
301  * Returns: the file descriptor associated with the memory, or -1
302  *
303  * Since: 1.2
304  */
305 gint
306 gst_dmabuf_memory_get_fd (GstMemory * mem)
307 {
308   GstDmaBufMemory *dbmem = (GstDmaBufMemory *) mem;
309
310   g_return_val_if_fail (gst_is_dmabuf_memory (mem), -1);
311
312   return dbmem->fd;
313 }
314
315 /**
316  * gst_is_dmabuf_memory:
317  * @mem: the memory to be check
318  *
319  * Check if @mem is dmabuf memory.
320  *
321  * Returns: %TRUE if @mem is dmabuf memory, otherwise %FALSE
322  *
323  * Since: 1.2
324  */
325 gboolean
326 gst_is_dmabuf_memory (GstMemory * mem)
327 {
328   return g_strcmp0 (mem->allocator->mem_type, ALLOCATOR_NAME) == 0;
329 }
330
331 #else /* !HAVE_MMAP */
332
333 GstAllocator *
334 gst_dmabuf_allocator_obtain (void)
335 {
336   return NULL;
337 }
338
339 GstMemory *
340 gst_dmabuf_allocator_alloc (GstAllocator * allocator, gint fd, gsize size)
341 {
342   return NULL;
343 }
344
345 gint
346 gst_dmabuf_memory_get_fd (GstMemory * mem)
347 {
348   return -1;
349 }
350
351 gboolean
352 gst_is_dmabuf_memory (GstMemory * mem)
353 {
354   return FALSE;
355 }
356
357 #endif /* HAVE_MMAP */