mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-22 16:26:39 +00:00
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>
This commit is contained in:
parent
755bd9143e
commit
ed60843c1e
3 changed files with 233 additions and 1 deletions
|
@ -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,
|
||||
|
|
|
@ -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) {
|
||||
|
@ -845,8 +903,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,
|
||||
|
|
|
@ -69,6 +69,9 @@ struct _GstWaylandSink
|
|||
GstVideoOrientationMethod current_rotate_method;
|
||||
|
||||
struct wl_callback *callback;
|
||||
|
||||
gchar *drm_device;
|
||||
gboolean skip_dumb_buffer_copy;
|
||||
};
|
||||
|
||||
struct _GstWaylandSinkClass
|
||||
|
|
Loading…
Reference in a new issue