1 From 6136bc631e5e875ed6b75d994564dd5fd09c7bf3 Mon Sep 17 00:00:00 2001
2 From: Carlos Rafael Giani <dv@pseudoterminal.org>
3 Date: Wed, 7 Jun 2017 18:23:52 +0200
4 Subject: [PATCH] gstgl: Add direct DMABUF uploader [WIP]
6 This is the first, work-in-progress version of a new "direct" DMABUF
7 uploader. The idea is that some GPUs (like the Vivante series) can actually
8 perform the YUV->RGB conversion internally, so no custom conversion shaders
9 are needed. To make use of this feature, we need an additional uploader
10 that can import DMABUF FDs and also directly pass the pixel format,
11 relying on the GPU to do the conversion.
13 This patch is incomplete for these reasons:
14 - It is currently unknown how to determine if the GPU can handle these
16 - Currently it is not possible to probe for what EGLImage DMABUF input
17 formats the GPU can handle
18 - The EGLImage cache is there, but cannot be used, because some drivers
19 like etnaviv keep a cached copy of the texture inside, and it is
20 currently not clear how to let etnaviv know that the cache has to be
21 flushed once the associated DMABUF gets a new video frame
23 gst-libs/gst/gl/gstglupload.c | 290 +++++++++++++++++++++++++++++++++++++-----
24 1 file changed, 256 insertions(+), 34 deletions(-)
26 diff --git a/gst-libs/gst/gl/gstglupload.c b/gst-libs/gst/gl/gstglupload.c
27 index feaf2f68e..28abc898d 100644
28 --- a/gst-libs/gst/gl/gstglupload.c
29 +++ b/gst-libs/gst/gl/gstglupload.c
32 #if GST_GL_HAVE_DMABUF
33 #include <gst/allocators/gstdmabuf.h>
34 +#include <libdrm/drm_fourcc.h>
37 #if GST_GL_HAVE_VIV_DIRECTVIV
38 @@ -480,7 +481,256 @@ static const UploadMethod _gl_memory_upload = {
39 &_gl_memory_upload_free
43 #if GST_GL_HAVE_DMABUF
47 +_eglimage_quark (gint plane)
49 + static GQuark quark[4] = { 0 };
50 + static const gchar *quark_str[] = {
51 + "GstGLDMABufEGLImage0",
52 + "GstGLDMABufEGLImage1",
53 + "GstGLDMABufEGLImage2",
54 + "GstGLDMABufEGLImage3",
58 + quark[plane] = g_quark_from_static_string (quark_str[plane]);
60 + return quark[plane];
64 +_get_cached_eglimage (GstMiniObject * mobj, gint plane)
66 + return gst_mini_object_get_qdata (mobj, _eglimage_quark (plane));
70 +_set_cached_eglimage (GstMiniObject * mobj, GstEGLImage * eglimage, gint plane)
72 + return gst_mini_object_set_qdata (mobj,
73 + _eglimage_quark (plane), eglimage, (GDestroyNotify) gst_egl_image_unref);
76 +/* TODO: the normal and direct dmabuf uploader share a lot of code.
77 + * Perhaps they can be merged. */
78 +struct DirectDmabufUpload
80 + GstGLUpload *upload;
82 + GstEGLImage *eglimage;
84 + GstGLVideoAllocationParams *params;
87 +/* TODO add format probing (requires EGL_EXT_image_dma_buf_import_modifiers)
88 + * Currently this list is just hardcoded */
89 +#define GST_GL_DIRECT_DMABUF_FORMAT "{YUY2, NV12, I420}"
91 +static GstStaticCaps _direct_dma_buf_upload_caps =
92 +GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE (GST_GL_DIRECT_DMABUF_FORMAT));
95 +_direct_dma_buf_upload_new (GstGLUpload * upload)
97 + struct DirectDmabufUpload *dmabuf = g_new0 (struct DirectDmabufUpload, 1);
98 + dmabuf->upload = upload;
103 +_direct_dma_buf_upload_transform_caps (gpointer impl, GstGLContext * context,
104 + GstPadDirection direction, GstCaps * caps)
106 + GstCapsFeatures *passthrough =
107 + gst_caps_features_from_string
108 + (GST_CAPS_FEATURE_META_GST_VIDEO_OVERLAY_COMPOSITION);
111 + if (direction == GST_PAD_SINK) {
115 + _set_caps_features_with_passthrough (caps,
116 + GST_CAPS_FEATURE_MEMORY_GL_MEMORY, passthrough);
118 + gst_caps_set_simple (ret, "format", G_TYPE_STRING, "RGBA", NULL);
119 + tmp = _caps_intersect_texture_target (ret, 1 << GST_GL_TEXTURE_TARGET_2D);
120 + gst_caps_unref (ret);
124 + tmp = gst_caps_from_string (GST_VIDEO_CAPS_MAKE_WITH_FEATURES
125 + (GST_CAPS_FEATURE_MEMORY_SYSTEM_MEMORY, GST_GL_DIRECT_DMABUF_FORMAT));
127 + _set_caps_features_with_passthrough (tmp,
128 + GST_CAPS_FEATURE_MEMORY_SYSTEM_MEMORY, passthrough);
129 + gst_caps_unref (tmp);
132 + gst_caps_features_free (passthrough);
137 +_direct_dma_buf_upload_accept (gpointer impl, GstBuffer * buffer,
138 + GstCaps * in_caps, GstCaps * out_caps)
140 + struct DirectDmabufUpload *dmabuf = impl;
141 + GstVideoInfo *in_info = &dmabuf->upload->priv->in_info;
142 + guint n_planes = GST_VIDEO_INFO_N_PLANES (in_info);
143 + GstVideoMeta *meta;
147 + n_mem = gst_buffer_n_memory (buffer);
148 + meta = gst_buffer_get_video_meta (buffer);
150 + /* dmabuf upload is only supported with EGL contexts. */
151 + if (gst_gl_context_get_gl_platform (dmabuf->upload->context) !=
152 + GST_GL_PLATFORM_EGL)
155 + if (!gst_gl_context_check_feature (dmabuf->upload->context,
156 + "EGL_KHR_image_base"))
159 + /* This will eliminate most non-dmabuf out there */
160 + if (!gst_is_dmabuf_memory (gst_buffer_peek_memory (buffer, 0)))
163 + /* We cannot have multiple dmabuf per plane */
164 + if (n_mem > n_planes)
167 + /* Update video info based on video meta */
169 + in_info->width = meta->width;
170 + in_info->height = meta->height;
172 + for (i = 0; i < meta->n_planes; i++) {
173 + in_info->offset[i] = meta->offset[i];
174 + in_info->stride[i] = meta->stride[i];
178 + if (dmabuf->params)
179 + gst_gl_allocation_params_free ((GstGLAllocationParams *) dmabuf->params);
180 + if (!(dmabuf->params =
181 + gst_gl_video_allocation_params_new_wrapped_gl_handle (dmabuf->
182 + upload->context, NULL, &dmabuf->upload->priv->out_info, -1, NULL,
183 + GST_GL_TEXTURE_TARGET_2D, GST_VIDEO_GL_TEXTURE_TYPE_RGBA, NULL,
187 + /* Now create an EGLImage for each dmabufs */
189 + /* check if one is cached */
190 + dmabuf->eglimage = _get_cached_eglimage (GST_MINI_OBJECT (buffer), 0);
191 + /* TODO: This is a hack that effectively disables caching.
192 + * Currently it is not possible to inform some GPU drivers (like etnaviv)
193 + * that they should invalidate whatever texture-related cache they have,
194 + * so even if the associated dmabuf changes, the texture doesn't.. So, as
195 + * a workaround, were disable caching here and force the reinitialization
196 + * of EGLImages. Fix the texture cache updates and then remove the #if
199 + dmabuf->eglimage = NULL;
202 + if (!dmabuf->eglimage) {
203 + /* otherwise create one and cache it */
206 + gst_egl_image_from_dmabuf_direct (dmabuf->upload->context,
209 + if (!dmabuf->eglimage)
212 + _set_cached_eglimage (GST_MINI_OBJECT (buffer), dmabuf->eglimage, 0);
215 + GST_TRACE ("Got GstEGLImage %p", (gpointer) (dmabuf->eglimage));
222 +_direct_dma_buf_upload_propose_allocation (gpointer impl,
223 + GstQuery * decide_query, GstQuery * query)
225 + /* nothing to do for now. */
229 +_direct_dma_buf_upload_perform_gl_thread (GstGLContext * context,
230 + struct DirectDmabufUpload *dmabuf)
232 + GstGLMemoryAllocator *allocator;
236 + GST_GL_MEMORY_ALLOCATOR (gst_allocator_find
237 + (GST_GL_MEMORY_EGL_ALLOCATOR_NAME));
239 + /* FIXME: buffer pool */
240 + dmabuf->outbuf = gst_buffer_new ();
241 + ptr = (gpointer *) dmabuf->eglimage;
242 + gst_gl_memory_setup_buffer (allocator, dmabuf->outbuf, dmabuf->params, NULL,
244 + gst_object_unref (allocator);
247 +static GstGLUploadReturn
248 +_direct_dma_buf_upload_perform (gpointer impl, GstBuffer * buffer,
249 + GstBuffer ** outbuf)
251 + struct DirectDmabufUpload *dmabuf = impl;
253 + gst_gl_context_thread_add (dmabuf->upload->context,
254 + (GstGLContextThreadFunc) _direct_dma_buf_upload_perform_gl_thread,
257 + if (!dmabuf->outbuf)
258 + return GST_GL_UPLOAD_ERROR;
260 + gst_buffer_add_parent_buffer_meta (dmabuf->outbuf, buffer);
262 + *outbuf = dmabuf->outbuf;
263 + dmabuf->outbuf = NULL;
265 + return GST_GL_UPLOAD_DONE;
269 +_direct_dma_buf_upload_free (gpointer impl)
271 + struct DirectDmabufUpload *dmabuf = impl;
273 + if (dmabuf->params)
274 + gst_gl_allocation_params_free ((GstGLAllocationParams *) dmabuf->params);
279 +static const UploadMethod _direct_dma_buf_upload = {
282 + &_direct_dma_buf_upload_caps,
283 + &_direct_dma_buf_upload_new,
284 + &_direct_dma_buf_upload_transform_caps,
285 + &_direct_dma_buf_upload_accept,
286 + &_direct_dma_buf_upload_propose_allocation,
287 + &_direct_dma_buf_upload_perform,
288 + &_direct_dma_buf_upload_free
295 @@ -543,37 +793,6 @@ _dma_buf_upload_transform_caps (gpointer impl, GstGLContext * context,
300 -_eglimage_quark (gint plane)
302 - static GQuark quark[4] = { 0 };
303 - static const gchar *quark_str[] = {
304 - "GstGLDMABufEGLImage0",
305 - "GstGLDMABufEGLImage1",
306 - "GstGLDMABufEGLImage2",
307 - "GstGLDMABufEGLImage3",
311 - quark[plane] = g_quark_from_static_string (quark_str[plane]);
313 - return quark[plane];
316 -static GstEGLImage *
317 -_get_cached_eglimage (GstMemory * mem, gint plane)
319 - return gst_mini_object_get_qdata (GST_MINI_OBJECT (mem),
320 - _eglimage_quark (plane));
324 -_set_cached_eglimage (GstMemory * mem, GstEGLImage * eglimage, gint plane)
326 - return gst_mini_object_set_qdata (GST_MINI_OBJECT (mem),
327 - _eglimage_quark (plane), eglimage, (GDestroyNotify) gst_egl_image_unref);
331 _dma_buf_upload_accept (gpointer impl, GstBuffer * buffer, GstCaps * in_caps,
333 @@ -652,20 +871,20 @@ _dma_buf_upload_accept (gpointer impl, GstBuffer * buffer, GstCaps * in_caps,
334 /* Now create an EGLImage for each dmabufs */
335 for (i = 0; i < n_planes; i++) {
336 /* check if one is cached */
337 - dmabuf->eglimage[i] = _get_cached_eglimage (mems[i], i);
338 + dmabuf->eglimage[i] = _get_cached_eglimage (GST_MINI_OBJECT (mems[i]), i);
339 if (dmabuf->eglimage[i])
342 /* otherwise create one and cache it */
343 dmabuf->eglimage[i] =
344 - gst_egl_image_from_dmabuf (dmabuf->upload->context,
345 + gst_egl_image_from_dmabuf_as_rgba_plane (dmabuf->upload->context,
346 gst_dmabuf_memory_get_fd (mems[i]), in_info, i,
347 mems[i]->offset + mems_skip[i]);
349 if (!dmabuf->eglimage[i])
352 - _set_cached_eglimage (mems[i], dmabuf->eglimage[i], i);
353 + _set_cached_eglimage (GST_MINI_OBJECT (mems[i]), dmabuf->eglimage[i], i);
357 @@ -737,8 +956,10 @@ static const UploadMethod _dma_buf_upload = {
358 &_dma_buf_upload_free
362 #endif /* GST_GL_HAVE_DMABUF */
368 @@ -1523,6 +1744,7 @@ static const UploadMethod _directviv_upload = {
370 static const UploadMethod *upload_methods[] = { &_gl_memory_upload,
371 #if GST_GL_HAVE_DMABUF
372 + &_direct_dma_buf_upload,
375 #if GST_GL_HAVE_VIV_DIRECTVIV