diff --git a/girs/GstGL-1.0.gir b/girs/GstGL-1.0.gir index c80acfc37c..b61d2f91dd 100644 --- a/girs/GstGL-1.0.gir +++ b/girs/GstGL-1.0.gir @@ -10526,6 +10526,20 @@ you are writing to OpenGL. Conversely, combining #GST_MAP_GL with + + See gst_buffer_pool_config_set_gl_min_free_queue_size(). + + + then number of buffers configured the free queue + + + + + a buffer pool config + + + + Sets @params on @config @@ -10543,6 +10557,33 @@ you are writing to OpenGL. Conversely, combining #GST_MAP_GL with + + Instructs the #GstGLBufferPool to keep @queue_size amount of buffers around +before allowing them for reuse. + +This is helpful to allow GPU processing to complete before the CPU +operations on the same buffer could start. Particularly useful when +uploading or downloading data to/from the GPU. + +A value of 0 disabled this functionality. + +This value must be less than the configured maximum amount of buffers for +this @config. + + + + + + + a buffer pool config + + + + the number of buffers + + + + diff --git a/subprojects/gst-plugins-base/ext/gl/gstgldownloadelement.c b/subprojects/gst-plugins-base/ext/gl/gstgldownloadelement.c index 1d3ee1adba..ee92ed4163 100644 --- a/subprojects/gst-plugins-base/ext/gl/gstgldownloadelement.c +++ b/subprojects/gst-plugins-base/ext/gl/gstgldownloadelement.c @@ -1453,6 +1453,7 @@ gst_gl_download_element_propose_allocation (GstBaseTransform * bt, /* the normal size of a frame */ size = info.size; gst_buffer_pool_config_set_params (config, caps, size, 0, 0); + gst_buffer_pool_config_set_gl_min_free_queue_size (config, 1); gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_GL_SYNC_META); diff --git a/subprojects/gst-plugins-base/gst-libs/gst/gl/gstglbufferpool.c b/subprojects/gst-plugins-base/gst-libs/gst/gl/gstglbufferpool.c index 168d483bd8..757fc6a07b 100644 --- a/subprojects/gst-plugins-base/gst-libs/gst/gl/gstglbufferpool.c +++ b/subprojects/gst-plugins-base/gst-libs/gst/gl/gstglbufferpool.c @@ -28,6 +28,8 @@ #include "gstglsyncmeta.h" #include "gstglutils.h" +#define DEFAULT_FREE_QUEUE_MIN_DEPTH 0 + /** * SECTION:gstglbufferpool * @title: GstGLBufferPool @@ -52,6 +54,11 @@ struct _GstGLBufferPoolPrivate GstCaps *caps; gboolean add_videometa; gboolean add_glsyncmeta; + + gsize free_queue_min_depth; + /* work around the GPU still potentially executing a buffer after it has been + * freed by keeping N buffers before being able to reuse them */ + GQueue *free_cache_buffers; }; static void gst_gl_buffer_pool_finalize (GObject * object); @@ -114,6 +121,18 @@ gst_gl_buffer_pool_set_config (GstBufferPool * pool, GstStructure * config) if (!gst_buffer_pool_config_get_allocator (config, &allocator, &alloc_params)) goto wrong_config; + { + guint min_free_queue_size = + gst_buffer_pool_config_get_gl_min_free_queue_size (config); + if (min_buffers < min_free_queue_size) { + min_buffers = MAX (min_buffers, min_free_queue_size); + } + if (max_buffers != 0 && max_buffers < min_buffers) + goto wrong_buffer_count; + + priv->free_queue_min_depth = min_free_queue_size; + } + gst_caps_replace (&priv->caps, caps); if (priv->allocator) @@ -255,6 +274,11 @@ wrong_allocator: GST_WARNING_OBJECT (pool, "Incorrect allocator type for this pool"); return FALSE; } +wrong_buffer_count: + { + GST_WARNING_OBJECT (pool, "Cannot achieve minimum buffer requirements"); + return FALSE; + } } static gboolean @@ -263,6 +287,20 @@ gst_gl_buffer_pool_start (GstBufferPool * pool) return GST_BUFFER_POOL_CLASS (parent_class)->start (pool); } +static gboolean +gst_gl_buffer_pool_stop (GstBufferPool * pool) +{ + GstGLBufferPool *glpool = GST_GL_BUFFER_POOL_CAST (pool); + GstGLBufferPoolPrivate *priv = glpool->priv; + GstBuffer *buffer; + + while ((buffer = g_queue_pop_head (priv->free_cache_buffers))) { + GST_BUFFER_POOL_CLASS (parent_class)->release_buffer (pool, buffer); + } + + return GST_BUFFER_POOL_CLASS (parent_class)->stop (pool); +} + /* This function handles GstBuffer creation */ static GstFlowReturn gst_gl_buffer_pool_alloc (GstBufferPool * pool, GstBuffer ** buffer, @@ -301,6 +339,27 @@ mem_create_failed: } } +static void +gst_gl_buffer_pool_release_buffer (GstBufferPool * pool, GstBuffer * buffer) +{ + GstGLBufferPool *glpool = GST_GL_BUFFER_POOL_CAST (pool); + GstGLBufferPoolPrivate *priv = glpool->priv; + + if (priv->free_queue_min_depth == 0 + && g_queue_get_length (priv->free_cache_buffers) == 0) { + GST_BUFFER_POOL_CLASS (parent_class)->release_buffer (pool, buffer); + } else { + g_queue_push_tail (priv->free_cache_buffers, buffer); + + while (g_queue_get_length (priv->free_cache_buffers) > + priv->free_queue_min_depth) { + GstBuffer *release_buffer = g_queue_pop_head (priv->free_cache_buffers); + GST_BUFFER_POOL_CLASS (parent_class)->release_buffer (pool, + release_buffer); + } + } +} + /** * gst_gl_buffer_pool_new: * @context: the #GstGLContext to use @@ -333,7 +392,9 @@ gst_gl_buffer_pool_class_init (GstGLBufferPoolClass * klass) gstbufferpool_class->get_options = gst_gl_buffer_pool_get_options; gstbufferpool_class->set_config = gst_gl_buffer_pool_set_config; gstbufferpool_class->alloc_buffer = gst_gl_buffer_pool_alloc; + gstbufferpool_class->release_buffer = gst_gl_buffer_pool_release_buffer; gstbufferpool_class->start = gst_gl_buffer_pool_start; + gstbufferpool_class->stop = gst_gl_buffer_pool_stop; } static void @@ -348,6 +409,8 @@ gst_gl_buffer_pool_init (GstGLBufferPool * pool) priv->caps = NULL; priv->add_videometa = TRUE; priv->add_glsyncmeta = FALSE; + priv->free_queue_min_depth = DEFAULT_FREE_QUEUE_MIN_DEPTH; + priv->free_cache_buffers = g_queue_new (); } static void @@ -361,6 +424,8 @@ gst_gl_buffer_pool_finalize (GObject * object) if (priv->caps) gst_caps_unref (priv->caps); + g_clear_pointer (&priv->free_cache_buffers, g_queue_free); + G_OBJECT_CLASS (gst_gl_buffer_pool_parent_class)->finalize (object); /* only release the context once all our memory have been deleted */ @@ -439,3 +504,56 @@ gst_buffer_pool_config_set_gl_allocation_params (GstStructure * config, gst_structure_set (config, "gl-allocation-params", GST_TYPE_GL_ALLOCATION_PARAMS, params, NULL); } + +/** + * gst_buffer_pool_config_set_gl_min_free_queue_size: + * @config: a buffer pool config + * @queue_size: the number of buffers + * + * Instructs the #GstGLBufferPool to keep @queue_size amount of buffers around + * before allowing them for reuse. + * + * This is helpful to allow GPU processing to complete before the CPU + * operations on the same buffer could start. Particularly useful when + * uploading or downloading data to/from the GPU. + * + * A value of 0 disabled this functionality. + * + * This value must be less than the configured maximum amount of buffers for + * this @config. + * + * Since: 1.24 + */ +void +gst_buffer_pool_config_set_gl_min_free_queue_size (GstStructure * config, + guint queue_size) +{ + g_return_if_fail (config != NULL); + + gst_structure_set (config, "gl-min-free-queue-size", + G_TYPE_UINT, queue_size, NULL); +} + +/** + * gst_buffer_pool_config_get_gl_min_free_queue_size: + * @config: a buffer pool config + * + * See gst_buffer_pool_config_set_gl_min_free_queue_size(). + * + * Returns: then number of buffers configured the free queue + * + * Since: 1.24 + */ +guint +gst_buffer_pool_config_get_gl_min_free_queue_size (GstStructure * config) +{ + guint queue_size = 0; + + g_return_val_if_fail (config != NULL, 0); + + if (!gst_structure_get (config, "gl-min-free-queue-size", + G_TYPE_UINT, &queue_size, NULL)) + queue_size = 0; + + return queue_size; +} diff --git a/subprojects/gst-plugins-base/gst-libs/gst/gl/gstglbufferpool.h b/subprojects/gst-plugins-base/gst-libs/gst/gl/gstglbufferpool.h index 595eed53ad..77c918f6cb 100644 --- a/subprojects/gst-plugins-base/gst-libs/gst/gl/gstglbufferpool.h +++ b/subprojects/gst-plugins-base/gst-libs/gst/gl/gstglbufferpool.h @@ -77,6 +77,11 @@ GstGLAllocationParams * gst_buffer_pool_config_get_gl_allocation_params (GstS GST_GL_API void gst_buffer_pool_config_set_gl_allocation_params (GstStructure * config, const GstGLAllocationParams * params); +GST_GL_API +guint gst_buffer_pool_config_get_gl_min_free_queue_size (GstStructure * config); +GST_GL_API +void gst_buffer_pool_config_set_gl_min_free_queue_size (GstStructure * config, + guint queue_size); G_END_DECLS diff --git a/subprojects/gst-plugins-base/gst-libs/gst/gl/gstglupload.c b/subprojects/gst-plugins-base/gst-libs/gst/gl/gstglupload.c index 1a4f13b5a0..878cc16ce7 100644 --- a/subprojects/gst-plugins-base/gst-libs/gst/gl/gstglupload.c +++ b/subprojects/gst-plugins-base/gst-libs/gst/gl/gstglupload.c @@ -458,7 +458,6 @@ _gl_memory_upload_propose_allocation (gpointer impl, GstQuery * decide_query, GstVideoInfo info; gsize size; - if (!gst_video_info_from_caps (&info, caps)) goto invalid_caps; @@ -468,6 +467,8 @@ _gl_memory_upload_propose_allocation (gpointer impl, GstQuery * decide_query, /* the normal size of a frame */ size = info.size; gst_buffer_pool_config_set_params (config, caps, size, 0, 0); + /* keep one buffer around before allowing acquire */ + gst_buffer_pool_config_set_gl_min_free_queue_size (config, 1); gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_GL_SYNC_META); if (upload->upload->priv->out_caps) { diff --git a/subprojects/gst-plugins-base/tests/check/elements/glimagesink.c b/subprojects/gst-plugins-base/tests/check/elements/glimagesink.c index 67a67c7db5..1f6fcbf576 100644 --- a/subprojects/gst-plugins-base/tests/check/elements/glimagesink.c +++ b/subprojects/gst-plugins-base/tests/check/elements/glimagesink.c @@ -29,6 +29,7 @@ #include #include #include +#include static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, @@ -181,6 +182,7 @@ GST_START_TEST (test_query_drain) config = gst_buffer_pool_get_config (originpool); gst_buffer_pool_config_set_params (config, caps, size, maxbuffers, maxbuffers); + gst_buffer_pool_config_set_gl_min_free_queue_size (config, 0); fail_unless (gst_buffer_pool_set_config (originpool, config)); /* The gl pool is setup and ready to be activated. */