xref: /OK3568_Linux_fs/external/gstreamer-rockchip/gst/rockchipmpp/gstmppallocator.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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