summaryrefslogtreecommitdiff
path: root/sys/inteldrm/intelbufmgrpool.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/inteldrm/intelbufmgrpool.c')
-rw-r--r--sys/inteldrm/intelbufmgrpool.c222
1 files changed, 222 insertions, 0 deletions
diff --git a/sys/inteldrm/intelbufmgrpool.c b/sys/inteldrm/intelbufmgrpool.c
new file mode 100644
index 0000000..c380397
--- /dev/null
+++ b/sys/inteldrm/intelbufmgrpool.c
@@ -0,0 +1,222 @@
+/*
+ * GStreamer intel bufmgr upload element
+ *
+ * Copyright (C) 2014 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ */
+
+#include "intelbufmgrpool.h"
+
+#include <libdrm/i915_drm.h>
+
+GST_DEBUG_CATEGORY_EXTERN (gstinteldmabufupload_debug);
+#define GST_CAT_DEFAULT gstinteldmabufupload_debug
+
+#define parent_class gst_intel_bufmgr_pool_parent_class
+G_DEFINE_TYPE (GstIntelBufmgrPool, gst_intel_bufmgr_pool, GST_TYPE_BUFFER_POOL);
+
+static G_DEFINE_QUARK (GstIntelBufmgrBoQDataQuark, gst_intel_bufmgr_bo_qdata);
+
+static GstFlowReturn gst_intel_bufmgr_pool_alloc_buffer (GstBufferPool * pool,
+ GstBuffer ** buffer, GstBufferPoolAcquireParams * params);
+
+static gpointer
+gst_intel_bufmgr_mem_map (GstMemory * mem, gsize maxsize, GstMapFlags flags)
+{
+ drm_intel_bo *bo;
+
+ /* make memory sharing work, theoretically */
+ if (mem->parent)
+ return gst_intel_bufmgr_mem_map (mem->parent, maxsize, flags);
+
+ bo = gst_mini_object_get_qdata (GST_MINI_OBJECT (mem),
+ gst_intel_bufmgr_bo_qdata_quark ());
+
+ if (drm_intel_gem_bo_map_gtt (bo) != 0) {
+ GST_ERROR ("failed to map drm_intel_bo");
+ return NULL;
+ }
+
+ return bo->virtual;
+}
+
+static void
+gst_intel_bufmgr_mem_unmap (GstMemory * mem)
+{
+ drm_intel_bo *bo;
+
+ /* make memory sharing work, theoretically */
+ if (mem->parent) {
+ gst_intel_bufmgr_mem_unmap (mem->parent);
+ return;
+ }
+
+ bo = gst_mini_object_get_qdata (GST_MINI_OBJECT (mem),
+ gst_intel_bufmgr_bo_qdata_quark ());
+
+ drm_intel_gem_bo_unmap_gtt (bo);
+}
+
+static gboolean
+gst_intel_bufmgr_pool_set_config (GstBufferPool * pool, GstStructure * config)
+{
+ GstIntelBufmgrPool *self = GST_INTEL_BUFMGR_POOL (pool);
+ GstVideoInfo info;
+ GstCaps *caps;
+ GstBuffer *tmp;
+ guint size, min_bufs, max_bufs;
+ gboolean ret;
+
+ if (!gst_buffer_pool_config_get_params (config, &caps, &size, &min_bufs,
+ &max_bufs))
+ goto wrong_config;
+
+ if (caps == NULL)
+ goto no_caps;
+
+ /* now parse the caps from the config */
+ if (!gst_video_info_from_caps (&info, caps))
+ goto wrong_caps;
+
+ self->info = info;
+
+ /* Acquire a buffer and configure the size in the base class.
+ * This is necessary to allow buffers to be reused in GstBufferPool,
+ * because if the size does not match, GstBufferPool thinks that the
+ * buffer has been modified and it discards it instead of reusing it.
+ * Unfortunately, the size is determined by the downstream drm_intel_bo
+ * allocator and not by us, so we have to allocate a buffer to find
+ * out what its size ends up being.
+ */
+ if (gst_intel_bufmgr_pool_alloc_buffer (pool, &tmp, NULL) != GST_FLOW_OK)
+ return FALSE;
+
+ size = gst_buffer_get_size (tmp);
+ gst_buffer_pool_config_set_params (config, caps, size, min_bufs, max_bufs);
+
+ ret = GST_CALL_PARENT_WITH_DEFAULT
+ (GST_BUFFER_POOL_CLASS, set_config, (pool, config), TRUE);
+
+ gst_buffer_unref (tmp);
+
+ return ret;
+
+ /* ERRORS */
+wrong_config:
+ {
+ GST_WARNING_OBJECT (pool, "invalid config");
+ return FALSE;
+ }
+no_caps:
+ {
+ GST_WARNING_OBJECT (pool, "no caps in config");
+ return FALSE;
+ }
+wrong_caps:
+ {
+ GST_WARNING_OBJECT (pool,
+ "failed getting geometry from caps %" GST_PTR_FORMAT, caps);
+ return FALSE;
+ }
+}
+
+static GstFlowReturn
+gst_intel_bufmgr_pool_alloc_buffer (GstBufferPool * pool, GstBuffer ** buffer,
+ GstBufferPoolAcquireParams * params)
+{
+ GstIntelBufmgrPool *self = GST_INTEL_BUFMGR_POOL (pool);
+ GstMemory *mem;
+ drm_intel_bo *bo;
+ gint dmabuf_fd;
+ uint32_t tiling = I915_TILING_NONE;
+ gulong stride;
+
+ bo = drm_intel_bo_alloc_tiled (self->context->bufmgr, "gst", self->info.width,
+ self->info.height, self->info.finfo->pixel_stride[0], &tiling, &stride,
+ 0);
+
+ if (!bo) {
+ GST_ERROR_OBJECT (pool, "Allocating a drm_intel_bo failed");
+ return GST_FLOW_ERROR;
+ }
+
+ if (drm_intel_bo_gem_export_to_prime (bo, &dmabuf_fd) != 0) {
+ GST_ERROR_OBJECT (pool, "Failed to export drm_intel_bo to a dmabuf");
+ drm_intel_bo_unreference (bo);
+ return GST_FLOW_ERROR;
+ }
+
+ mem = gst_dmabuf_allocator_alloc (self->allocator, dmabuf_fd, bo->size);
+ gst_mini_object_set_qdata (GST_MINI_OBJECT (mem),
+ gst_intel_bufmgr_bo_qdata_quark (), bo,
+ (GDestroyNotify) drm_intel_bo_unreference);
+
+ *buffer = gst_buffer_new ();
+ gst_buffer_append_memory (*buffer, mem);
+
+ self->info.stride[0] = stride;
+ (void) gst_buffer_add_video_meta_full (*buffer, 0, self->info.finfo->format,
+ self->info.width, self->info.height, self->info.finfo->n_planes,
+ self->info.offset, self->info.stride);
+
+ GST_DEBUG_OBJECT (pool, "Allocated buffer. width %d, height %d, format %s, "
+ "stride %d", self->info.width, self->info.height,
+ gst_video_format_to_string (self->info.finfo->format),
+ self->info.stride[0]);
+
+ return GST_FLOW_OK;
+}
+
+static void
+gst_intel_bufmgr_pool_finalize (GObject * object)
+{
+ GstIntelBufmgrPool *self = GST_INTEL_BUFMGR_POOL (object);
+
+ g_object_unref (self->allocator);
+ gst_mini_object_unref ((GstMiniObject *) self->context);
+}
+
+static void
+gst_intel_bufmgr_pool_class_init (GstIntelBufmgrPoolClass * klass)
+{
+ GstBufferPoolClass *bpool_class = (GstBufferPoolClass *) klass;
+ GObjectClass *object_class = (GObjectClass *) klass;
+
+ bpool_class->set_config =
+ GST_DEBUG_FUNCPTR (gst_intel_bufmgr_pool_set_config);
+ bpool_class->alloc_buffer =
+ GST_DEBUG_FUNCPTR (gst_intel_bufmgr_pool_alloc_buffer);
+
+ object_class->finalize = GST_DEBUG_FUNCPTR (gst_intel_bufmgr_pool_finalize);
+}
+
+static void
+gst_intel_bufmgr_pool_init (GstIntelBufmgrPool * self)
+{
+ self->allocator = gst_dmabuf_allocator_new ();
+ self->allocator->mem_map = gst_intel_bufmgr_mem_map;
+ self->allocator->mem_unmap = gst_intel_bufmgr_mem_unmap;
+}
+
+GstBufferPool *
+gst_intel_bufmgr_pool_new (GstIntelBufmgrContext * context)
+{
+ GstIntelBufmgrPool *self = g_object_new (GST_TYPE_INTEL_BUFMGR_POOL, NULL);
+ self->context =
+ (GstIntelBufmgrContext *) gst_mini_object_ref ((GstMiniObject *) context);
+ return (GstBufferPool *) self;
+}