1 /*
2 * Copyright 2021 Rockchip Electronics Co., Ltd
3 * Author: Jeffy Chen <jeffy.chen@rock-chips.com>
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
17 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 *
20 */
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include <unistd.h>
27
28 #include <gst/allocators/gstdmabuf.h>
29
30 #include "gstmppallocator.h"
31
32 #define GST_TYPE_MPP_ALLOCATOR (gst_mpp_allocator_get_type())
33 G_DECLARE_FINAL_TYPE (GstMppAllocator, gst_mpp_allocator, GST,
34 MPP_ALLOCATOR, GstDmaBufAllocator);
35
36 #define GST_MPP_ALLOCATOR(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \
37 GST_TYPE_MPP_ALLOCATOR, GstMppAllocator))
38
39 #define GST_CAT_DEFAULT mppallocator_debug
40 GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
41
42 #define GST_ALLOCATOR_MPP "mpp"
43
44 struct _GstMppAllocator
45 {
46 GstDmaBufAllocator parent;
47
48 /* group for buffer-alloc */
49 MppBufferGroup group;
50
51 /* group for buffer-import */
52 MppBufferGroup ext_group;
53
54 /* unique group ID */
55 gint index;
56
57 /* cache buffers */
58 gboolean cacheable;
59 };
60
61 #define gst_mpp_allocator_parent_class parent_class
62 G_DEFINE_TYPE (GstMppAllocator, gst_mpp_allocator, GST_TYPE_DMABUF_ALLOCATOR);
63
64 static GQuark
gst_mpp_buffer_quark(void)65 gst_mpp_buffer_quark (void)
66 {
67 static GQuark quark = 0;
68 if (quark == 0)
69 quark = g_quark_from_string ("mpp-buf");
70
71 return quark;
72 }
73
74 static GQuark
gst_mpp_ext_buffer_quark(void)75 gst_mpp_ext_buffer_quark (void)
76 {
77 static GQuark quark = 0;
78 if (quark == 0)
79 quark = g_quark_from_string ("mpp-ext-buf");
80
81 return quark;
82 }
83
84 void
gst_mpp_allocator_set_cacheable(GstAllocator * allocator,gboolean cacheable)85 gst_mpp_allocator_set_cacheable (GstAllocator * allocator, gboolean cacheable)
86 {
87 GstMppAllocator *self = GST_MPP_ALLOCATOR (allocator);
88 self->cacheable = cacheable;
89
90 /* Clear cached buffers */
91 if (!cacheable)
92 mpp_buffer_group_clear (self->group);
93 }
94
95 gint
gst_mpp_allocator_get_index(GstAllocator * allocator)96 gst_mpp_allocator_get_index (GstAllocator * allocator)
97 {
98 GstMppAllocator *self = GST_MPP_ALLOCATOR (allocator);
99 return self->index;
100 }
101
102 MppBufferGroup
gst_mpp_allocator_get_mpp_group(GstAllocator * allocator)103 gst_mpp_allocator_get_mpp_group (GstAllocator * allocator)
104 {
105 GstMppAllocator *self = GST_MPP_ALLOCATOR (allocator);
106 return self->group;
107 }
108
109 MppBuffer
gst_mpp_mpp_buffer_from_gst_memory(GstMemory * mem)110 gst_mpp_mpp_buffer_from_gst_memory (GstMemory * mem)
111 {
112 if (mem->parent)
113 return gst_mpp_mpp_buffer_from_gst_memory (mem->parent);
114
115 return gst_mini_object_get_qdata (GST_MINI_OBJECT (mem),
116 gst_mpp_buffer_quark ());
117 }
118
119 static void
gst_mpp_mem_destroy(gpointer ptr)120 gst_mpp_mem_destroy (gpointer ptr)
121 {
122 MppBuffer mbuf = ptr;
123
124 mpp_buffer_put (mbuf);
125 }
126
127 static GstMemory *
gst_mpp_allocator_import_dmafd(GstAllocator * allocator,gint fd,guint size)128 gst_mpp_allocator_import_dmafd (GstAllocator * allocator, gint fd, guint size)
129 {
130 GstMppAllocator *self = GST_MPP_ALLOCATOR (allocator);
131 GstMemory *mem;
132 MppBufferInfo info = { 0, };
133 MppBuffer mbuf = NULL;
134
135 GST_DEBUG_OBJECT (self, "import dmafd: %d (%d)", fd, size);
136
137 info.type = MPP_BUFFER_TYPE_DRM;
138 info.size = size;
139 info.fd = fd;
140
141 mpp_buffer_import_with_tag (self->ext_group, &info, &mbuf, NULL, __func__);
142 if (!mbuf)
143 return NULL;
144
145 mpp_buffer_set_index (mbuf, self->index);
146
147 mem = gst_mpp_allocator_import_mppbuf (allocator, mbuf);
148 mpp_buffer_put (mbuf);
149
150 return mem;
151 }
152
153 GstMemory *
gst_mpp_allocator_import_mppbuf(GstAllocator * allocator,MppBuffer mbuf)154 gst_mpp_allocator_import_mppbuf (GstAllocator * allocator, MppBuffer mbuf)
155 {
156 GstMppAllocator *self = GST_MPP_ALLOCATOR (allocator);
157 GstMemory *mem;
158 GQuark quark;
159 guint size;
160 gint fd;
161
162 GST_DEBUG_OBJECT (self, "import MPP buffer");
163
164 fd = mpp_buffer_get_fd (mbuf);
165 if (fd < 0) {
166 GST_ERROR_OBJECT (self, "failed to get dmafd");
167 return NULL;
168 }
169
170 /* HACK: DRM buffers are actually aligned to 4096 (page) */
171 size = GST_ROUND_UP_N (mpp_buffer_get_size (mbuf), 4096);
172
173 if (mpp_buffer_get_index (mbuf) != self->index) {
174 GST_DEBUG_OBJECT (self, "import from other group");
175 mem = gst_mpp_allocator_import_dmafd (allocator, fd, size);
176 quark = gst_mpp_ext_buffer_quark ();
177 } else {
178 mem = gst_fd_allocator_alloc (allocator, dup (fd), size,
179 GST_FD_MEMORY_FLAG_KEEP_MAPPED);
180 quark = gst_mpp_buffer_quark ();
181 }
182
183 mpp_buffer_inc_ref (mbuf);
184 gst_mini_object_set_qdata (GST_MINI_OBJECT (mem), quark, mbuf,
185 gst_mpp_mem_destroy);
186
187 return mem;
188 }
189
190 GstMemory *
gst_mpp_allocator_import_gst_memory(GstAllocator * allocator,GstMemory * mem)191 gst_mpp_allocator_import_gst_memory (GstAllocator * allocator, GstMemory * mem)
192 {
193 GstMppAllocator *self = GST_MPP_ALLOCATOR (allocator);
194 MppBuffer mbuf;
195 gsize offset;
196 guint size;
197 gint fd;
198
199 GST_DEBUG_OBJECT (self, "import gst memory");
200
201 if (!gst_is_dmabuf_memory (mem))
202 return NULL;
203
204 mbuf = gst_mpp_mpp_buffer_from_gst_memory (mem);
205 if (mbuf)
206 return gst_mpp_allocator_import_mppbuf (allocator, mbuf);
207
208 fd = gst_dmabuf_memory_get_fd (mem);
209 if (fd < 0) {
210 GST_ERROR_OBJECT (self, "failed to get dmafd");
211 return NULL;
212 }
213
214 size = gst_memory_get_sizes (mem, &offset, NULL);
215 if (offset)
216 return NULL;
217
218 return gst_mpp_allocator_import_dmafd (allocator, fd, size);
219 }
220
221 MppBuffer
gst_mpp_allocator_alloc_mppbuf(GstAllocator * allocator,gsize size)222 gst_mpp_allocator_alloc_mppbuf (GstAllocator * allocator, gsize size)
223 {
224 GstMppAllocator *self = GST_MPP_ALLOCATOR (allocator);
225 MppBuffer mbuf = NULL;
226
227 mpp_buffer_get (self->group, &mbuf, size);
228 mpp_buffer_set_index (mbuf, self->index);
229
230 return mbuf;
231 }
232
233 static GstMemory *
gst_mpp_allocator_alloc(GstAllocator * allocator,gsize size,GstAllocationParams * params UNUSED)234 gst_mpp_allocator_alloc (GstAllocator * allocator, gsize size,
235 GstAllocationParams * params UNUSED)
236 {
237 GstMemory *mem;
238 MppBuffer mbuf;
239
240 mbuf = gst_mpp_allocator_alloc_mppbuf (allocator, size);
241 if (!mbuf)
242 return NULL;
243
244 mem = gst_mpp_allocator_import_mppbuf (allocator, mbuf);
245 mpp_buffer_put (mbuf);
246
247 gst_memory_resize (mem, 0, size);
248 return mem;
249 }
250
251 static gpointer
gst_mpp_mem_map_full(GstMemory * mem,GstMapInfo * info,gsize size)252 gst_mpp_mem_map_full (GstMemory * mem, GstMapInfo * info, gsize size)
253 {
254 if (mem->parent)
255 return gst_mpp_mem_map_full (mem->parent, info, size);
256
257 if (GST_MEMORY_IS_NOT_MAPPABLE (mem))
258 return NULL;
259
260 return mem->allocator->mem_map (mem, size, info->flags);
261 }
262
263 static void
gst_mpp_allocator_free(GstAllocator * allocator,GstMemory * gmem)264 gst_mpp_allocator_free (GstAllocator * allocator, GstMemory * gmem)
265 {
266 GstMppAllocator *self = GST_MPP_ALLOCATOR (allocator);
267
268 /* Avoid caching external buffers */
269 mpp_buffer_group_clear (self->ext_group);
270
271 /* Clear cached buffers */
272 if (!self->cacheable)
273 mpp_buffer_group_clear (self->group);
274
275 GST_ALLOCATOR_CLASS (parent_class)->free (allocator, gmem);
276 }
277
278 GstAllocator *
gst_mpp_allocator_new(void)279 gst_mpp_allocator_new (void)
280 {
281 GstMppAllocator *alloc;
282 MppBufferGroup group, ext_group;
283
284 static gint num_mpp_alloc = 0;
285
286 if (mpp_buffer_group_get_internal (&group, MPP_BUFFER_TYPE_DRM))
287 return FALSE;
288
289 if (mpp_buffer_group_get_external (&ext_group, MPP_BUFFER_TYPE_DRM)) {
290 mpp_buffer_group_put (group);
291 return FALSE;
292 }
293
294 alloc = g_object_new (GST_TYPE_MPP_ALLOCATOR, NULL);
295 gst_object_ref_sink (alloc);
296
297 alloc->group = group;
298 alloc->ext_group = ext_group;
299 alloc->index = num_mpp_alloc++;
300 alloc->cacheable = TRUE;
301
302 return GST_ALLOCATOR_CAST (alloc);
303 }
304
305 static void
gst_mpp_allocator_finalize(GObject * obj)306 gst_mpp_allocator_finalize (GObject * obj)
307 {
308 GstMppAllocator *self = GST_MPP_ALLOCATOR (obj);
309
310 mpp_buffer_group_put (self->group);
311 mpp_buffer_group_put (self->ext_group);
312
313 G_OBJECT_CLASS (parent_class)->finalize (obj);
314 }
315
316 static void
gst_mpp_allocator_class_init(GstMppAllocatorClass * klass)317 gst_mpp_allocator_class_init (GstMppAllocatorClass * klass)
318 {
319 GstAllocatorClass *allocator_class = GST_ALLOCATOR_CLASS (klass);
320 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
321
322 GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "mppallocator", 0, "MPP allocator");
323
324 allocator_class->alloc = GST_DEBUG_FUNCPTR (gst_mpp_allocator_alloc);
325 allocator_class->free = GST_DEBUG_FUNCPTR (gst_mpp_allocator_free);
326
327 gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_mpp_allocator_finalize);
328 }
329
330 static void
gst_mpp_allocator_init(GstMppAllocator * allocator)331 gst_mpp_allocator_init (GstMppAllocator * allocator)
332 {
333 GstAllocator *alloc = GST_ALLOCATOR_CAST (allocator);
334
335 alloc->mem_type = GST_ALLOCATOR_MPP;
336 alloc->mem_map_full = GST_DEBUG_FUNCPTR (gst_mpp_mem_map_full);
337
338 GST_OBJECT_FLAG_SET (allocator, GST_ALLOCATOR_FLAG_CUSTOM_ALLOC);
339 }
340