From c024c5e3bfb4f671b9bc5af267053bb9ebb85c5c Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Mon, 29 Jul 2024 10:41:42 +0200 Subject: [PATCH] gstgldmabufbufferpool: use gsteglimagecache Store the imported GstEGLImage in a GstEGLImageCache. Since this passes ownership to the cache, stop unreffing the images from the GstMemory. Free the cache when the buffer pool is stopped. Part-of: --- .../ext/gl/gstgldmabufbufferpool.c | 125 +++++++++--------- 1 file changed, 60 insertions(+), 65 deletions(-) diff --git a/subprojects/gst-plugins-base/ext/gl/gstgldmabufbufferpool.c b/subprojects/gst-plugins-base/ext/gl/gstgldmabufbufferpool.c index c625daf880..4718dca777 100644 --- a/subprojects/gst-plugins-base/ext/gl/gstgldmabufbufferpool.c +++ b/subprojects/gst-plugins-base/ext/gl/gstgldmabufbufferpool.c @@ -30,16 +30,16 @@ #include #include #include - -#define GST_GL_DMABUF_EGLIMAGE "gst.gl.dmabuf.eglimage" +#include +#include typedef struct _GstGLDMABufBufferPoolPrivate { GstBufferPool *dmabuf_pool; GstCaps *dmabuf_caps; - GstGLMemoryAllocator *allocator; GstGLVideoAllocationParams *glparams; GstVideoInfoDmaDrm drm_info; + GstEGLImageCache *eglimage_cache; gboolean add_glsyncmeta; } GstGLDMABufBufferPoolPrivate; @@ -78,19 +78,8 @@ gst_gl_dmabuf_buffer_pool_set_config (GstBufferPool * pool, goto wrong_config; } - gst_clear_object (&self->priv->allocator); - - if (allocator) { - if (!GST_IS_GL_MEMORY_ALLOCATOR (allocator)) { - gst_clear_object (&allocator); - goto wrong_allocator; - } else { - self->priv->allocator = gst_object_ref (allocator); - } - } else { - self->priv->allocator = - gst_gl_memory_allocator_get_default (GST_GL_BUFFER_POOL - (pool)->context); + if (allocator && !GST_IS_GL_MEMORY_EGL_ALLOCATOR (allocator)) { + goto wrong_allocator; } /* @@ -193,6 +182,11 @@ gst_gl_dmabuf_buffer_pool_start (GstBufferPool * pool) return FALSE; } + if (self->priv->eglimage_cache) { + gst_egl_image_cache_unref (self->priv->eglimage_cache); + } + self->priv->eglimage_cache = gst_egl_image_cache_new (); + return GST_BUFFER_POOL_CLASS (parent_class)->start (pool); } @@ -205,33 +199,34 @@ gst_gl_dmabuf_buffer_pool_stop (GstBufferPool * pool) return FALSE; } + if (self->priv->eglimage_cache) { + gst_egl_image_cache_unref (self->priv->eglimage_cache); + } + return GST_BUFFER_POOL_CLASS (parent_class)->stop (pool); } typedef struct { GstEGLImage *eglimage[GST_VIDEO_MAX_PLANES]; - gpointer gpuhandle[GST_VIDEO_MAX_PLANES]; - guint n_planes; -} WrapDMABufData; + GstGLVideoAllocationParams *glparams; + GstBuffer *outbuf; +} BufferSetupData; static void -_wrap_dmabuf_eglimage (GstGLContext * context, gpointer data) +_setup_buffer_gl_thread (GstGLContext * context, BufferSetupData * d) { - WrapDMABufData *d = data; - const GstGLFuncs *gl = context->gl_vtable; - GLuint tex_ids[GST_VIDEO_MAX_PLANES]; - guint i; + GstGLMemoryAllocator *allocator = + GST_GL_MEMORY_ALLOCATOR (gst_allocator_find + (GST_GL_MEMORY_EGL_ALLOCATOR_NAME)); - gl->GenTextures (d->n_planes, tex_ids); - - for (i = 0; i < d->n_planes; ++i) { - gl->BindTexture (GL_TEXTURE_2D, tex_ids[i]); - gl->EGLImageTargetTexture2D (GL_TEXTURE_2D, - gst_egl_image_get_image (d->eglimage[i])); - - d->gpuhandle[i] = GUINT_TO_POINTER (tex_ids[i]); + if (!gst_gl_memory_setup_buffer (allocator, d->outbuf, d->glparams, NULL, + (gpointer *) d->eglimage, + GST_VIDEO_INFO_N_PLANES (d->glparams->v_info))) { + gst_clear_buffer (&d->outbuf); } + + gst_clear_object (&allocator); } static GstFlowReturn @@ -274,8 +269,9 @@ gst_gl_dmabuf_buffer_pool_acquire_buffer (GstBufferPool * pool, GstVideoMeta *vmeta; GstFlowReturn ret; GstBuffer *dmabuf; - GstBuffer *buf; - WrapDMABufData data; + GstMemory *previous_mem = NULL; + GstEGLImageCacheEntry *cache_entry = NULL; + BufferSetupData data; guint i; ret = gst_buffer_pool_acquire_buffer (self->priv->dmabuf_pool, &dmabuf, NULL); @@ -286,9 +282,7 @@ gst_gl_dmabuf_buffer_pool_acquire_buffer (GstBufferPool * pool, vmeta = gst_buffer_get_video_meta (dmabuf); g_return_val_if_fail (vmeta, GST_FLOW_ERROR); - data.n_planes = GST_VIDEO_INFO_N_PLANES (v_info); - - for (i = 0; i < data.n_planes; ++i) { + for (i = 0; i < GST_VIDEO_INFO_N_PLANES (v_info); ++i) { guint mem_idx, length; gsize skip; GstMemory *dmabufmem; @@ -306,6 +300,16 @@ gst_gl_dmabuf_buffer_pool_acquire_buffer (GstBufferPool * pool, g_assert (gst_is_dmabuf_memory (dmabufmem)); + /* + * Check if an EGLImage is cached. Remember the previous memory and cache + * entry to avoid repeated lookups if all dmabufmem point to the same + * memory. Otherwise create one and cache it. + */ + data.eglimage[i] = gst_egl_image_cache_lookup (self->priv->eglimage_cache, + dmabufmem, i, &previous_mem, &cache_entry); + if (data.eglimage[i]) + continue; + /* Anything that is not using GLMemory format RGBA is using indirect * dmabuf importation with linear modifiers */ if (GST_VIDEO_INFO_FORMAT (v_info) != GST_VIDEO_FORMAT_RGBA) { @@ -317,49 +321,48 @@ gst_gl_dmabuf_buffer_pool_acquire_buffer (GstBufferPool * pool, gst_egl_image_from_dmabuf_direct_target_with_dma_drm (glpool->context, 1, &fd, &skip, &self->priv->drm_info, GL_TEXTURE_2D); } + + gst_egl_image_cache_store (self->priv->eglimage_cache, dmabufmem, i, + data.eglimage[i], &cache_entry); } - gst_gl_context_thread_add (glpool->context, _wrap_dmabuf_eglimage, &data); + data.glparams = self->priv->glparams; - ret = GST_BUFFER_POOL_CLASS (parent_class)->acquire_buffer (pool, &buf, + ret = + GST_BUFFER_POOL_CLASS (parent_class)->acquire_buffer (pool, &data.outbuf, params); if (ret != GST_FLOW_OK) { - return GST_FLOW_ERROR; + ret = GST_FLOW_ERROR; + goto out; } - if (!gst_gl_memory_setup_buffer (self->priv->allocator, buf, - self->priv->glparams, NULL, data.gpuhandle, data.n_planes)) { + gst_gl_context_thread_add (glpool->context, + (GstGLContextThreadFunc) _setup_buffer_gl_thread, &data); + if (!data.outbuf) { goto mem_create_failed; } - for (i = 0; i < data.n_planes; ++i) { - GstMemory *mem = gst_buffer_peek_memory (buf, i); + gst_buffer_add_parent_buffer_meta (data.outbuf, dmabuf); - /* Unset wrapped flag, we want the texture be freed with the memory. */ - GST_GL_MEMORY_CAST (mem)->texture_wrapped = FALSE; + *buffer = data.outbuf; - gst_mini_object_set_qdata (GST_MINI_OBJECT (mem), - g_quark_from_static_string (GST_GL_DMABUF_EGLIMAGE), - data.eglimage[i], (GDestroyNotify) gst_egl_image_unref); - } - - gst_buffer_add_parent_buffer_meta (buf, dmabuf); +out: gst_clear_buffer (&dmabuf); - *buffer = buf; - - return GST_FLOW_OK; + return ret; /* ERROR */ no_buffer: { GST_WARNING_OBJECT (self, "Could not create DMABuf buffer"); - return GST_FLOW_ERROR; + ret = GST_FLOW_ERROR; + goto out; } mem_create_failed: { GST_WARNING_OBJECT (self, "Could not create GL Memory"); - return GST_FLOW_ERROR; + ret = GST_FLOW_ERROR; + goto out; } } @@ -381,19 +384,11 @@ gst_is_gl_dmabuf_buffer (GstBuffer * buffer) GstBuffer * gst_gl_dmabuf_buffer_unwrap (GstBuffer * buffer) { - GstGLDMABufBufferPool *pool; GstParentBufferMeta *meta; GstBuffer *wrapped_dmabuf = NULL; g_return_val_if_fail (gst_is_gl_dmabuf_buffer (buffer), NULL); - pool = GST_GL_DMABUF_BUFFER_POOL (buffer->pool); - - if (gst_buffer_peek_memory (buffer, 0)->allocator != - GST_ALLOCATOR (pool->priv->allocator)) { - return NULL; - } - meta = gst_buffer_get_parent_buffer_meta (buffer); if (meta && meta->buffer) {