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 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24 
25 #include "gstfdmemory.h"
26 #include "gstdmabuf.h"
27 
28 /**
29  * SECTION:gstdmabuf
30  * @title: GstDmaBufAllocator
31  * @short_description: Memory wrapper for Linux dmabuf memory
32  * @see_also: #GstMemory
33  *
34  * Since: 1.2
35  */
36 
37 #ifdef HAVE_LINUX_DMA_BUF_H
38 #include <sys/ioctl.h>
39 #include <linux/dma-buf.h>
40 #endif
41 
42 GST_DEBUG_CATEGORY_STATIC (dmabuf_debug);
43 #define GST_CAT_DEFAULT dmabuf_debug
44 
45 G_DEFINE_TYPE (GstDmaBufAllocator, gst_dmabuf_allocator, GST_TYPE_FD_ALLOCATOR);
46 
47 static gpointer
gst_dmabuf_mem_map(GstMemory * gmem,GstMapInfo * info,gsize maxsize)48 gst_dmabuf_mem_map (GstMemory * gmem, GstMapInfo * info, gsize maxsize)
49 {
50   GstAllocator *allocator = gmem->allocator;
51   gpointer ret;
52 
53 #ifdef HAVE_LINUX_DMA_BUF_H
54   struct dma_buf_sync sync = { DMA_BUF_SYNC_START };
55 
56   if (info->flags & GST_MAP_READ)
57     sync.flags |= DMA_BUF_SYNC_READ;
58 
59   if (info->flags & GST_MAP_WRITE)
60     sync.flags |= DMA_BUF_SYNC_WRITE;
61 #endif
62 
63   ret = allocator->mem_map (gmem, maxsize, info->flags);
64 
65 #ifdef HAVE_LINUX_DMA_BUF_H
66   if (ret) {
67     if (ioctl (gst_fd_memory_get_fd (gmem), DMA_BUF_IOCTL_SYNC, &sync) < 0)
68       GST_WARNING_OBJECT (allocator, "Failed to synchronize DMABuf: %s (%i)",
69           g_strerror (errno), errno);
70   }
71 #endif
72 
73   return ret;
74 }
75 
76 static void
gst_dmabuf_mem_unmap(GstMemory * gmem,GstMapInfo * info)77 gst_dmabuf_mem_unmap (GstMemory * gmem, GstMapInfo * info)
78 {
79   GstAllocator *allocator = gmem->allocator;
80 #ifdef HAVE_LINUX_DMA_BUF_H
81   struct dma_buf_sync sync = { DMA_BUF_SYNC_END };
82 
83   if (info->flags & GST_MAP_READ)
84     sync.flags |= DMA_BUF_SYNC_READ;
85 
86   if (info->flags & GST_MAP_WRITE)
87     sync.flags |= DMA_BUF_SYNC_WRITE;
88 
89   if (ioctl (gst_fd_memory_get_fd (gmem), DMA_BUF_IOCTL_SYNC, &sync) < 0)
90     GST_WARNING_OBJECT (allocator, "Failed to synchronize DMABuf: %s (%i)",
91         g_strerror (errno), errno);
92 #else
93   GST_WARNING_OBJECT (allocator, "Using DMABuf without synchronization.");
94 #endif
95 
96   allocator->mem_unmap (gmem);
97 }
98 
99 static void
gst_dmabuf_allocator_class_init(GstDmaBufAllocatorClass * klass)100 gst_dmabuf_allocator_class_init (GstDmaBufAllocatorClass * klass)
101 {
102 }
103 
104 static void
gst_dmabuf_allocator_init(GstDmaBufAllocator * allocator)105 gst_dmabuf_allocator_init (GstDmaBufAllocator * allocator)
106 {
107   GstAllocator *alloc = GST_ALLOCATOR_CAST (allocator);
108 
109   alloc->mem_type = GST_ALLOCATOR_DMABUF;
110   alloc->mem_map_full = gst_dmabuf_mem_map;
111   alloc->mem_unmap_full = gst_dmabuf_mem_unmap;
112 }
113 
114 /**
115  * gst_dmabuf_allocator_new:
116  *
117  * Return a new dmabuf allocator.
118  *
119  * Returns: (transfer full): a new dmabuf allocator, or NULL if the allocator
120  *    isn't available. Use gst_object_unref() to release the allocator after
121  *    usage
122  *
123  * Since: 1.2
124  */
125 GstAllocator *
gst_dmabuf_allocator_new(void)126 gst_dmabuf_allocator_new (void)
127 {
128   GstAllocator *alloc;
129 
130   GST_DEBUG_CATEGORY_INIT (dmabuf_debug, "dmabuf", 0, "dmabuf memory");
131 
132   alloc = g_object_new (GST_TYPE_DMABUF_ALLOCATOR, NULL);
133   gst_object_ref_sink (alloc);
134 
135   return alloc;
136 }
137 
138 /**
139  * gst_dmabuf_allocator_alloc:
140  * @allocator: allocator to be used for this memory
141  * @fd: dmabuf file descriptor
142  * @size: memory size
143  *
144  * Return a %GstMemory that wraps a dmabuf file descriptor.
145  *
146  * Returns: (transfer full): a GstMemory based on @allocator.
147  * When the buffer will be released dmabuf allocator will close the @fd.
148  * The memory is only mmapped on gst_buffer_map() request.
149  *
150  * Since: 1.2
151  */
152 GstMemory *
gst_dmabuf_allocator_alloc(GstAllocator * allocator,gint fd,gsize size)153 gst_dmabuf_allocator_alloc (GstAllocator * allocator, gint fd, gsize size)
154 {
155   g_return_val_if_fail (GST_IS_DMABUF_ALLOCATOR (allocator), NULL);
156 
157   return gst_fd_allocator_alloc (allocator, fd, size, GST_FD_MEMORY_FLAG_NONE);
158 }
159 
160 /**
161  * gst_dmabuf_allocator_alloc_with_flags:
162  * @allocator: allocator to be used for this memory
163  * @fd: dmabuf file descriptor
164  * @size: memory size
165  * @flags: extra #GstFdMemoryFlags
166  *
167  * Return a %GstMemory that wraps a dmabuf file descriptor.
168  *
169  * Returns: (transfer full): a GstMemory based on @allocator.
170  *
171  * When the buffer will be released the allocator will close the @fd unless
172  * the %GST_FD_MEMORY_FLAG_DONT_CLOSE flag is specified.
173  * The memory is only mmapped on gst_buffer_mmap() request.
174  *
175  * Since: 1.16
176  */
177 GstMemory *
gst_dmabuf_allocator_alloc_with_flags(GstAllocator * allocator,gint fd,gsize size,GstFdMemoryFlags flags)178 gst_dmabuf_allocator_alloc_with_flags (GstAllocator * allocator, gint fd,
179     gsize size, GstFdMemoryFlags flags)
180 {
181   g_return_val_if_fail (GST_IS_DMABUF_ALLOCATOR (allocator), NULL);
182 
183   return gst_fd_allocator_alloc (allocator, fd, size, flags);
184 }
185 
186 /**
187  * gst_dmabuf_memory_get_fd:
188  * @mem: the memory to get the file descriptor
189  *
190  * Return the file descriptor associated with @mem.
191  *
192  * Returns: the file descriptor associated with the memory, or -1.  The file
193  *     descriptor is still owned by the GstMemory.  Use dup to take a copy
194  *     if you intend to use it beyond the lifetime of this GstMemory.
195  *
196  * Since: 1.2
197  */
198 gint
gst_dmabuf_memory_get_fd(GstMemory * mem)199 gst_dmabuf_memory_get_fd (GstMemory * mem)
200 {
201   g_return_val_if_fail (gst_is_dmabuf_memory (mem), -1);
202 
203   return gst_fd_memory_get_fd (mem);
204 }
205 
206 /**
207  * gst_is_dmabuf_memory:
208  * @mem: the memory to be check
209  *
210  * Check if @mem is dmabuf memory.
211  *
212  * Returns: %TRUE if @mem is dmabuf memory, otherwise %FALSE
213  *
214  * Since: 1.2
215  */
216 gboolean
gst_is_dmabuf_memory(GstMemory * mem)217 gst_is_dmabuf_memory (GstMemory * mem)
218 {
219   g_return_val_if_fail (mem != NULL, FALSE);
220 
221   return GST_IS_DMABUF_ALLOCATOR (mem->allocator);
222 }
223