kms: Export DMABuf from Dumb buffer when possible

https://bugzilla.gnome.org/show_bug.cgi?id=787593
This commit is contained in:
Nicolas Dufresne 2017-09-12 12:07:13 -04:00
parent 9d5a524547
commit 922031b0f9
5 changed files with 86 additions and 2 deletions

View file

@ -27,6 +27,7 @@
#include "config.h"
#endif
#include <fcntl.h>
#include <xf86drm.h>
#include <xf86drmMode.h>
#include <stdlib.h>
@ -37,6 +38,8 @@
/* it needs to be below because is internal to libdrm */
#include <drm.h>
#include <gst/allocators/gstdmabuf.h>
#include "gstkmsallocator.h"
#include "gstkmsutils.h"
@ -58,6 +61,7 @@ struct _GstKMSAllocatorPrivate
int fd;
/* protected by GstKMSAllocator object lock */
GList *mem_cache;
GstAllocator *dmabuf_alloc;
};
#define parent_class gst_kms_allocator_parent_class
@ -297,6 +301,9 @@ gst_kms_allocator_finalize (GObject * obj)
gst_kms_allocator_clear_cache (GST_ALLOCATOR (alloc));
if (alloc->priv->dmabuf_alloc)
gst_object_unref (alloc->priv->dmabuf_alloc);
if (check_fd (alloc))
close (alloc->priv->fd);
@ -555,6 +562,48 @@ failed:
}
}
GstMemory *
gst_kms_allocator_dmabuf_export (GstAllocator * allocator, GstMemory * _kmsmem)
{
GstKMSMemory *kmsmem = (GstKMSMemory *) _kmsmem;
GstKMSAllocator *alloc = GST_KMS_ALLOCATOR (allocator);
GstMemory *mem;
gint ret;
gint prime_fd;
/* We can only export DUMB buffers */
g_return_val_if_fail (kmsmem->bo, NULL);
ret = drmPrimeHandleToFD (alloc->priv->fd, kmsmem->bo->handle,
DRM_CLOEXEC | DRM_RDWR, &prime_fd);
if (ret)
goto export_fd_failed;
if (G_UNLIKELY (alloc->priv->dmabuf_alloc == NULL))
alloc->priv->dmabuf_alloc = gst_dmabuf_allocator_new ();
mem = gst_dmabuf_allocator_alloc (alloc->priv->dmabuf_alloc, prime_fd,
gst_memory_get_sizes (_kmsmem, NULL, NULL));
/* Populate the cache so KMSSink can find the kmsmem back when it receives
* one of these DMABuf. This call takes ownership of the kmsmem. */
gst_kms_allocator_cache (allocator, mem, _kmsmem);
GST_DEBUG_OBJECT (alloc, "Exported bo handle %d as %d", kmsmem->bo->handle,
prime_fd);
return mem;
/* ERRORS */
export_fd_failed:
{
GST_ERROR_OBJECT (alloc, "Failed to export bo handle %d: %s (%d)",
kmsmem->bo->handle, g_strerror (errno), ret);
return NULL;
}
}
/* FIXME, using gdata for caching on upstream memory is not tee safe */
GstMemory *
gst_kms_allocator_get_cached (GstMemory * mem)

View file

@ -86,6 +86,9 @@ GstKMSMemory* gst_kms_allocator_dmabuf_import (GstAllocator *allocator,
gsize offsets[GST_VIDEO_MAX_PLANES],
GstVideoInfo *vinfo);
GstMemory* gst_kms_allocator_dmabuf_export (GstAllocator *allocator,
GstMemory *kmsmem);
GstMemory * gst_kms_allocator_get_cached (GstMemory * mem);
void gst_kms_allocator_clear_cache (GstAllocator * allocator);

View file

@ -40,6 +40,7 @@ struct _GstKMSBufferPoolPrivate
GstVideoInfo vinfo;
GstAllocator *allocator;
gboolean add_videometa;
gboolean has_prime_export;
};
#define parent_class gst_kms_buffer_pool_parent_class
@ -52,7 +53,9 @@ static const gchar **
gst_kms_buffer_pool_get_options (GstBufferPool * pool)
{
static const gchar *options[] = { GST_BUFFER_POOL_OPTION_VIDEO_META,
GST_BUFFER_POOL_OPTION_KMS_BUFFER, NULL
GST_BUFFER_POOL_OPTION_KMS_BUFFER,
GST_BUFFER_POOL_OPTION_KMS_PRIME_EXPORT,
NULL
};
return options;
}
@ -97,6 +100,8 @@ gst_kms_buffer_pool_set_config (GstBufferPool * pool, GstStructure * config)
/* enable metadata based on config of the pool */
priv->add_videometa = gst_buffer_pool_config_has_option (config,
GST_BUFFER_POOL_OPTION_VIDEO_META);
priv->has_prime_export = gst_buffer_pool_config_has_option (config,
GST_BUFFER_POOL_OPTION_KMS_PRIME_EXPORT);
return GST_BUFFER_POOL_CLASS (parent_class)->set_config (pool, config);
@ -141,6 +146,16 @@ gst_kms_buffer_pool_alloc_buffer (GstBufferPool * pool, GstBuffer ** buffer,
if (!mem)
goto no_memory;
if (vpool->priv->has_prime_export) {
GstMemory *dmabufmem;
dmabufmem = gst_kms_allocator_dmabuf_export (priv->allocator, mem);
if (dmabufmem)
mem = dmabufmem;
else
GST_WARNING_OBJECT (pool, "Failed to export DMABuf from Dumb buffer.");
}
*buffer = gst_buffer_new ();
gst_buffer_append_memory (*buffer, mem);

View file

@ -37,10 +37,19 @@ G_BEGIN_DECLS
* GST_BUFFER_POOL_OPTION_KMS_BUFFER:
*
* An option that can be activated on buffer pool to request KMS
* buffers.
* buffers. NOT IMPLEMENTED
*/
#define GST_BUFFER_POOL_OPTION_KMS_BUFFER "GstBufferPoolOptionKMSBuffer"
/**
* GST_BUFFER_POOL_OPTION_KMS_PRIME_EXPORT:
*
* An option that can be activated on buffer pool to request DMABuf
* buffers. Callers are responsible to check if this is supported. Dumb buffers
* will be returned if not supported.
*/
#define GST_BUFFER_POOL_OPTION_KMS_PRIME_EXPORT "GstBufferPoolOptionKMSPrimeExport"
/* video bufferpool */
typedef struct _GstKMSBufferPool GstKMSBufferPool;
typedef struct _GstKMSBufferPoolClass GstKMSBufferPoolClass;

View file

@ -932,6 +932,14 @@ gst_kms_sink_propose_allocation (GstBaseSink * bsink, GstQuery * query)
pool = gst_kms_sink_create_pool (self, caps, size, 0);
if (!pool)
goto no_pool;
/* Only export for pool used upstream */
if (self->has_prime_export) {
GstStructure *config = gst_buffer_pool_get_config (pool);
gst_buffer_pool_config_add_option (config,
GST_BUFFER_POOL_OPTION_KMS_PRIME_EXPORT);
gst_buffer_pool_set_config (pool, config);
}
}
/* we need at least 2 buffer because we hold on to the last one */