412 lines
13 KiB
Diff
412 lines
13 KiB
Diff
From d5807fc0840117a8472922d69df76ddebf633325 Mon Sep 17 00:00:00 2001
|
|
From: Colin Kinloch <colin.kinloch@collabora.com>
|
|
Date: Thu, 16 Feb 2023 16:21:33 -0500
|
|
Subject: [PATCH 11/17] wayladnsink: Add DRM Dumb allocator support
|
|
|
|
If the input is not a DMABuf, attempt to copy into a DRM Dumb
|
|
buffer and import it has a DMABuf. This will offload the
|
|
compositor from actually doing this copy (needed to handle SHM)
|
|
and may allow the software decoded stream to be rendered to
|
|
an HW layer, or even reach through some better accelerated
|
|
GL import path.
|
|
|
|
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3801>
|
|
---
|
|
ext/gtk/gstgtkwaylandsink.c | 121 ++++++++++++++++++++++++++++++++++-
|
|
ext/wayland/gstwaylandsink.c | 110 +++++++++++++++++++++++++++++++
|
|
ext/wayland/gstwaylandsink.h | 3 +
|
|
3 files changed, 233 insertions(+), 1 deletion(-)
|
|
|
|
diff --git a/ext/gtk/gstgtkwaylandsink.c b/ext/gtk/gstgtkwaylandsink.c
|
|
index c46207c..438294b 100644
|
|
--- a/ext/gtk/gstgtkwaylandsink.c
|
|
+++ b/ext/gtk/gstgtkwaylandsink.c
|
|
@@ -87,7 +87,8 @@ enum
|
|
PROP_0,
|
|
PROP_WIDGET,
|
|
PROP_DISPLAY,
|
|
- PROP_ROTATE_METHOD
|
|
+ PROP_ROTATE_METHOD,
|
|
+ PROP_DRM_DEVICE,
|
|
};
|
|
|
|
typedef struct _GstGtkWaylandSinkPrivate
|
|
@@ -119,6 +120,9 @@ typedef struct _GstGtkWaylandSinkPrivate
|
|
GstVideoOrientationMethod current_rotate_method;
|
|
|
|
struct wl_callback *callback;
|
|
+
|
|
+ gchar *drm_device;
|
|
+ gboolean skip_dumb_buffer_copy;
|
|
} GstGtkWaylandSinkPrivate;
|
|
|
|
#define gst_gtk_wayland_sink_parent_class parent_class
|
|
@@ -161,6 +165,17 @@ gst_gtk_wayland_sink_class_init (GstGtkWaylandSinkClass * klass)
|
|
GST_TYPE_VIDEO_ORIENTATION_METHOD, GST_VIDEO_ORIENTATION_IDENTITY,
|
|
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
|
|
|
+ /**
|
|
+ * GstGtkWaylandSink:drm-device:
|
|
+ *
|
|
+ * Since: 1.24
|
|
+ */
|
|
+ g_object_class_install_property (gobject_class, PROP_DRM_DEVICE,
|
|
+ g_param_spec_string ("drm-device", "DRM Device", "Path of the "
|
|
+ "DRM device to use for dumb buffer allocation",
|
|
+ NULL,
|
|
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY));
|
|
+
|
|
gstelement_class->change_state =
|
|
GST_DEBUG_FUNCPTR (gst_gtk_wayland_sink_change_state);
|
|
|
|
@@ -207,6 +222,8 @@ gst_gtk_wayland_sink_finalize (GObject * object)
|
|
g_clear_object (&priv->gtk_widget);
|
|
gst_clear_caps (&priv->caps);
|
|
|
|
+ g_free (priv->drm_device);
|
|
+
|
|
G_OBJECT_CLASS (parent_class)->finalize (object);
|
|
}
|
|
|
|
@@ -379,6 +396,11 @@ gst_gtk_wayland_sink_get_property (GObject * object, guint prop_id,
|
|
case PROP_ROTATE_METHOD:
|
|
g_value_set_enum (value, priv->current_rotate_method);
|
|
break;
|
|
+ case PROP_DRM_DEVICE:
|
|
+ GST_OBJECT_LOCK (self);
|
|
+ g_value_set_string (value, priv->drm_device);
|
|
+ GST_OBJECT_UNLOCK (self);
|
|
+ break;
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
break;
|
|
@@ -390,12 +412,19 @@ gst_gtk_wayland_sink_set_property (GObject * object, guint prop_id,
|
|
const GValue * value, GParamSpec * pspec)
|
|
{
|
|
GstGtkWaylandSink *self = GST_GTK_WAYLAND_SINK (object);
|
|
+ GstGtkWaylandSinkPrivate *priv =
|
|
+ gst_gtk_wayland_sink_get_instance_private (self);
|
|
|
|
switch (prop_id) {
|
|
case PROP_ROTATE_METHOD:
|
|
gst_gtk_wayland_sink_set_rotate_method (self, g_value_get_enum (value),
|
|
FALSE);
|
|
break;
|
|
+ case PROP_DRM_DEVICE:
|
|
+ GST_OBJECT_LOCK (self);
|
|
+ priv->drm_device = g_value_dup_string (value);
|
|
+ GST_OBJECT_UNLOCK (self);
|
|
+ break;
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
break;
|
|
@@ -710,6 +739,8 @@ gst_gtk_wayland_sink_change_state (GstElement * element,
|
|
|
|
switch (transition) {
|
|
case GST_STATE_CHANGE_READY_TO_NULL:
|
|
+ g_clear_object (&priv->pool);
|
|
+ /* fallthrough */
|
|
case GST_STATE_CHANGE_NULL_TO_NULL:
|
|
gst_gtk_invoke_on_main ((GThreadFunc)
|
|
gst_gtk_wayland_sink_stop_on_main, element);
|
|
@@ -860,6 +891,41 @@ gst_gtk_wayland_activate_shm_pool (GstGtkWaylandSink * self)
|
|
return TRUE;
|
|
}
|
|
|
|
+static gboolean
|
|
+gst_gtk_wayland_activate_drm_dumb_pool (GstGtkWaylandSink * self)
|
|
+{
|
|
+ GstGtkWaylandSinkPrivate *priv =
|
|
+ gst_gtk_wayland_sink_get_instance_private (self);
|
|
+ GstAllocator *alloc;
|
|
+
|
|
+ if (!priv->drm_device)
|
|
+ return FALSE;
|
|
+
|
|
+ if (priv->pool && gst_buffer_pool_is_active (priv->pool)) {
|
|
+ GstStructure *config = gst_buffer_pool_get_config (priv->pool);
|
|
+ gboolean ret = FALSE;
|
|
+ gboolean is_drm_dumb = FALSE;
|
|
+
|
|
+ ret = gst_buffer_pool_config_get_allocator (config, &alloc, NULL);
|
|
+ gst_structure_free (config);
|
|
+
|
|
+ if (ret && alloc)
|
|
+ is_drm_dumb = GST_IS_DRM_DUMB_ALLOCATOR (alloc);
|
|
+
|
|
+ if (is_drm_dumb)
|
|
+ return TRUE;
|
|
+ }
|
|
+
|
|
+ alloc = gst_drm_dumb_allocator_new_with_device_path (priv->drm_device);
|
|
+ if (!alloc)
|
|
+ return FALSE;
|
|
+
|
|
+ gst_gtk_wayland_update_pool (self, alloc);
|
|
+ gst_object_unref (alloc);
|
|
+
|
|
+ return TRUE;
|
|
+}
|
|
+
|
|
static gboolean
|
|
gst_gtk_wayland_sink_set_caps (GstBaseSink * bsink, GstCaps * caps)
|
|
{
|
|
@@ -877,6 +943,7 @@ gst_gtk_wayland_sink_set_caps (GstBaseSink * bsink, GstCaps * caps)
|
|
|
|
format = GST_VIDEO_INFO_FORMAT (&priv->video_info);
|
|
priv->video_info_changed = TRUE;
|
|
+ priv->skip_dumb_buffer_copy = FALSE;
|
|
|
|
/* free pooled buffer used with previous caps */
|
|
if (priv->pool) {
|
|
@@ -1086,8 +1153,60 @@ gst_gtk_wayland_sink_show_frame (GstVideoSink * vsink, GstBuffer * buffer)
|
|
if (nb_dmabuf && (nb_dmabuf == gst_buffer_n_memory (buffer)))
|
|
wbuf = gst_wl_linux_dmabuf_construct_wl_buffer (buffer, priv->display,
|
|
&priv->video_info);
|
|
+
|
|
+ /* DMABuf did not work, let try and make this a dmabuf, it does not matter
|
|
+ * if it was a SHM since the compositor needs to copy that anyway, and
|
|
+ * offloading the compositor from a copy helps maintaining a smoother
|
|
+ * desktop.
|
|
+ */
|
|
+ if (!priv->skip_dumb_buffer_copy) {
|
|
+ GstVideoFrame src, dst;
|
|
+
|
|
+ if (!gst_gtk_wayland_activate_drm_dumb_pool (self)) {
|
|
+ priv->skip_dumb_buffer_copy = TRUE;
|
|
+ goto handle_shm;
|
|
+ }
|
|
+
|
|
+ ret = gst_buffer_pool_acquire_buffer (priv->pool, &to_render, NULL);
|
|
+ if (ret != GST_FLOW_OK)
|
|
+ goto no_buffer;
|
|
+
|
|
+ wlbuffer = gst_buffer_get_wl_buffer (priv->display, to_render);
|
|
+
|
|
+ /* attach a wl_buffer if there isn't one yet */
|
|
+ if (G_UNLIKELY (!wlbuffer)) {
|
|
+ wbuf = gst_wl_linux_dmabuf_construct_wl_buffer (to_render,
|
|
+ priv->display, &priv->video_info);
|
|
+
|
|
+ if (G_UNLIKELY (!wbuf)) {
|
|
+ GST_WARNING_OBJECT (self, "failed to import DRM Dumb dmabuf");
|
|
+ gst_clear_buffer (&to_render);
|
|
+ priv->skip_dumb_buffer_copy = TRUE;
|
|
+ goto handle_shm;
|
|
+ }
|
|
+
|
|
+ wlbuffer = gst_buffer_add_wl_buffer (to_render, wbuf, priv->display);
|
|
+ }
|
|
+
|
|
+ if (!gst_video_frame_map (&dst, &priv->video_info, to_render,
|
|
+ GST_MAP_WRITE))
|
|
+ goto dst_map_failed;
|
|
+
|
|
+ if (!gst_video_frame_map (&src, &priv->video_info, buffer, GST_MAP_READ)) {
|
|
+ gst_video_frame_unmap (&dst);
|
|
+ goto src_map_failed;
|
|
+ }
|
|
+
|
|
+ gst_video_frame_copy (&dst, &src);
|
|
+
|
|
+ gst_video_frame_unmap (&src);
|
|
+ gst_video_frame_unmap (&dst);
|
|
+
|
|
+ goto render;
|
|
+ }
|
|
}
|
|
|
|
+handle_shm:
|
|
if (!wbuf && gst_wl_display_check_format_for_shm (priv->display, format)) {
|
|
if (gst_buffer_n_memory (buffer) == 1 && gst_is_fd_memory (mem))
|
|
wbuf = gst_wl_shm_memory_construct_wl_buffer (mem, priv->display,
|
|
diff --git a/ext/wayland/gstwaylandsink.c b/ext/wayland/gstwaylandsink.c
|
|
index aa39447..bb7fcff 100644
|
|
--- a/ext/wayland/gstwaylandsink.c
|
|
+++ b/ext/wayland/gstwaylandsink.c
|
|
@@ -61,6 +61,7 @@ enum
|
|
PROP_DISPLAY,
|
|
PROP_FULLSCREEN,
|
|
PROP_ROTATE_METHOD,
|
|
+ PROP_DRM_DEVICE,
|
|
PROP_LAST
|
|
};
|
|
|
|
@@ -177,6 +178,18 @@ gst_wayland_sink_class_init (GstWaylandSinkClass * klass)
|
|
GST_TYPE_VIDEO_ORIENTATION_METHOD, GST_VIDEO_ORIENTATION_IDENTITY,
|
|
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
|
|
|
+ /**
|
|
+ * waylandsink:drm-device:
|
|
+ *
|
|
+ * Since: 1.24
|
|
+ */
|
|
+ g_object_class_install_property (gobject_class, PROP_DRM_DEVICE,
|
|
+ g_param_spec_string ("drm-device", "DRM Device", "Path of the "
|
|
+ "DRM device to use for dumb buffer allocation",
|
|
+ NULL,
|
|
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY));
|
|
+
|
|
+
|
|
/**
|
|
* waylandsink:render-rectangle:
|
|
*
|
|
@@ -266,6 +279,11 @@ gst_wayland_sink_get_property (GObject * object,
|
|
g_value_set_enum (value, self->current_rotate_method);
|
|
GST_OBJECT_UNLOCK (self);
|
|
break;
|
|
+ case PROP_DRM_DEVICE:
|
|
+ GST_OBJECT_LOCK (self);
|
|
+ g_value_set_string (value, self->drm_device);
|
|
+ GST_OBJECT_UNLOCK (self);
|
|
+ break;
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
break;
|
|
@@ -293,6 +311,11 @@ gst_wayland_sink_set_property (GObject * object,
|
|
gst_wayland_sink_set_rotate_method (self, g_value_get_enum (value),
|
|
FALSE);
|
|
break;
|
|
+ case PROP_DRM_DEVICE:
|
|
+ GST_OBJECT_LOCK (self);
|
|
+ self->drm_device = g_value_dup_string (value);
|
|
+ GST_OBJECT_UNLOCK (self);
|
|
+ break;
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
break;
|
|
@@ -318,6 +341,7 @@ gst_wayland_sink_finalize (GObject * object)
|
|
gst_clear_caps (&self->caps);
|
|
|
|
g_free (self->display_name);
|
|
+ g_free (self->drm_device);
|
|
|
|
g_mutex_clear (&self->display_lock);
|
|
g_mutex_clear (&self->render_lock);
|
|
@@ -629,6 +653,39 @@ gst_wayland_activate_shm_pool (GstWaylandSink * self)
|
|
return TRUE;
|
|
}
|
|
|
|
+static gboolean
|
|
+gst_wayland_activate_drm_dumb_pool (GstWaylandSink * self)
|
|
+{
|
|
+ GstAllocator *alloc;
|
|
+
|
|
+ if (!self->drm_device)
|
|
+ return FALSE;
|
|
+
|
|
+ if (self->pool && gst_buffer_pool_is_active (self->pool)) {
|
|
+ GstStructure *config = gst_buffer_pool_get_config (self->pool);
|
|
+ gboolean ret = FALSE;
|
|
+ gboolean is_drm_dumb = FALSE;
|
|
+
|
|
+ ret = gst_buffer_pool_config_get_allocator (config, &alloc, NULL);
|
|
+ gst_structure_free (config);
|
|
+
|
|
+ if (ret && alloc)
|
|
+ is_drm_dumb = GST_IS_DRM_DUMB_ALLOCATOR (alloc);
|
|
+
|
|
+ if (is_drm_dumb)
|
|
+ return TRUE;
|
|
+ }
|
|
+
|
|
+ alloc = gst_drm_dumb_allocator_new_with_device_path (self->drm_device);
|
|
+ if (!alloc)
|
|
+ return FALSE;
|
|
+
|
|
+ gst_wayland_update_pool (self, alloc);
|
|
+ gst_object_unref (alloc);
|
|
+
|
|
+ return TRUE;
|
|
+}
|
|
+
|
|
static gboolean
|
|
gst_wayland_sink_set_caps (GstBaseSink * bsink, GstCaps * caps)
|
|
{
|
|
@@ -644,6 +701,7 @@ gst_wayland_sink_set_caps (GstBaseSink * bsink, GstCaps * caps)
|
|
|
|
format = GST_VIDEO_INFO_FORMAT (&self->video_info);
|
|
self->video_info_changed = TRUE;
|
|
+ self->skip_dumb_buffer_copy = FALSE;
|
|
|
|
/* free pooled buffer used with previous caps */
|
|
if (self->pool) {
|
|
@@ -848,8 +906,60 @@ gst_wayland_sink_show_frame (GstVideoSink * vsink, GstBuffer * buffer)
|
|
if (nb_dmabuf && (nb_dmabuf == gst_buffer_n_memory (buffer)))
|
|
wbuf = gst_wl_linux_dmabuf_construct_wl_buffer (buffer, self->display,
|
|
&self->video_info);
|
|
+
|
|
+ /* DMABuf did not work, let try and make this a dmabuf, it does not matter
|
|
+ * if it was a SHM since the compositor needs to copy that anyway, and
|
|
+ * offloading the compositor from a copy helps maintaining a smoother
|
|
+ * desktop.
|
|
+ */
|
|
+ if (!self->skip_dumb_buffer_copy) {
|
|
+ GstVideoFrame src, dst;
|
|
+
|
|
+ if (!gst_wayland_activate_drm_dumb_pool (self)) {
|
|
+ self->skip_dumb_buffer_copy = TRUE;
|
|
+ goto handle_shm;
|
|
+ }
|
|
+
|
|
+ ret = gst_buffer_pool_acquire_buffer (self->pool, &to_render, NULL);
|
|
+ if (ret != GST_FLOW_OK)
|
|
+ goto no_buffer;
|
|
+
|
|
+ wlbuffer = gst_buffer_get_wl_buffer (self->display, to_render);
|
|
+
|
|
+ /* attach a wl_buffer if there isn't one yet */
|
|
+ if (G_UNLIKELY (!wlbuffer)) {
|
|
+ wbuf = gst_wl_linux_dmabuf_construct_wl_buffer (to_render,
|
|
+ self->display, &self->video_info);
|
|
+
|
|
+ if (G_UNLIKELY (!wbuf)) {
|
|
+ GST_WARNING_OBJECT (self, "failed to import DRM Dumb dmabuf");
|
|
+ gst_clear_buffer (&to_render);
|
|
+ self->skip_dumb_buffer_copy = TRUE;
|
|
+ goto handle_shm;
|
|
+ }
|
|
+
|
|
+ wlbuffer = gst_buffer_add_wl_buffer (to_render, wbuf, self->display);
|
|
+ }
|
|
+
|
|
+ if (!gst_video_frame_map (&dst, &self->video_info, to_render,
|
|
+ GST_MAP_WRITE))
|
|
+ goto dst_map_failed;
|
|
+
|
|
+ if (!gst_video_frame_map (&src, &self->video_info, buffer, GST_MAP_READ)) {
|
|
+ gst_video_frame_unmap (&dst);
|
|
+ goto src_map_failed;
|
|
+ }
|
|
+
|
|
+ gst_video_frame_copy (&dst, &src);
|
|
+
|
|
+ gst_video_frame_unmap (&src);
|
|
+ gst_video_frame_unmap (&dst);
|
|
+
|
|
+ goto render;
|
|
+ }
|
|
}
|
|
|
|
+handle_shm:
|
|
if (!wbuf && gst_wl_display_check_format_for_shm (self->display, format)) {
|
|
if (gst_buffer_n_memory (buffer) == 1 && gst_is_fd_memory (mem))
|
|
wbuf = gst_wl_shm_memory_construct_wl_buffer (mem, self->display,
|
|
diff --git a/ext/wayland/gstwaylandsink.h b/ext/wayland/gstwaylandsink.h
|
|
index 1ff50d1..ca3400e 100644
|
|
--- a/ext/wayland/gstwaylandsink.h
|
|
+++ b/ext/wayland/gstwaylandsink.h
|
|
@@ -69,6 +69,9 @@ struct _GstWaylandSink
|
|
GstVideoOrientationMethod current_rotate_method;
|
|
|
|
struct wl_callback *callback;
|
|
+
|
|
+ gchar *drm_device;
|
|
+ gboolean skip_dumb_buffer_copy;
|
|
};
|
|
|
|
struct _GstWaylandSinkClass
|
|
--
|
|
2.25.1
|
|
|