wayland: wlbuffer: workaround for unaligned drm dumb frames not rendered
Describe your issue
$> gst-launch-1.0 videotestsrc ! video/x-raw, format=I420 ! waylandsink drm-device=/dev/dri/card0 ERROR: from element /GstPipeline:pipeline0/GstWaylandSink:waylandsink0: Video memory can not be written from userspace.
This is only affecting I420: NV12 or YUY2 runs fine.
Expected Behavior
No error observed and video test pattern rendered.
Observed Behavior
Exit on error
Setup
- STM32MP25-EV evaluation board or STM32MP157-DK discovery board
- GStreamer-1.22 + "Add DRM Dumb allocation support into Wayland Sinks" merge request: !3801 (commits)
How reproducible is the bug?
100%
Solutions you have tried
Tracing shows:
$> gst-launch-1.0 videotestsrc num-buffers=-1 ! video/x-raw, format=I420 ! waylandsink -v --gst-debug=*:9 2>&1 | grep -e trim -e written -e copy_plane -e wl_buffer | awk -F.c: '{ print $NF }' 159:buffer_release: GstWlBuffer@0xffff98002e10 [00m wl_buffer::release (GstBuffer: 0x1c998a20) ------------------------------------------------------------------------------------^^^^^^^^^^ 1703:gst_buffer_resize_range: trim 0x1c998a20 0-115200 size:138240 offs:0 max:138240 => resize 138240 to 115200 -----------------------------------^^^^^^^^^^ => map failed after this resize ! 1179:gst_wayland_sink_show_frame: Video memory can not be written from userspace buffer: 0x1c998a20 -----------------------------------------------------------------------------------------^^^^^^^^^^ 320x240 is aligned to 384x240 (size=138240 in I420) when allocating through DRM dumb allocator (STM dri card is aligning on 128bytes). Problematic code which leads to wrong resize of buffer is in gstbufferpool.c: default_reset_buffer (GstBufferPool * pool, GstBuffer * buffer) { <...> /* if the memory is intact reset the size to the full size */ if (!GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_TAG_MEMORY)) { gsize offset, maxsize; gst_buffer_get_sizes (buffer, &offset, &maxsize); /* check if we can resize to at least the pool configured size. If not, * then this will fail internally in gst_buffer_resize(). * default_release_buffer() will drop the buffer from the pool if the * sizes don't match */ if (maxsize >= pool->priv->size) { gst_buffer_resize (buffer, -offset, pool->priv->size); ======^^^^^^^^^^^^^^^^^ } else { GST_WARNING_OBJECT (pool, "Buffer %p without the memory tag has " "maxsize (%" G_GSIZE_FORMAT ") that is smaller than the " "configured buffer pool size (%u). The buffer will be not be " "reused. This is most likely a bug in this GstBufferPool subclass", buffer, maxsize, pool->priv->size); } }
Patch consist to force GST_BUFFER_FLAG_TAG_MEMORY right before unref so that we don't fall into the resize case later on:
diff --git a/gst-libs/gst/wayland/gstwlbuffer.c b/gst-libs/gst/wayland/gstwlbuffer.c index 6bf6778..3efe15f 100644 --- a/gst-libs/gst/wayland/gstwlbuffer.c +++ b/gst-libs/gst/wayland/gstwlbuffer.c @@ -161,6 +161,8 @@ buffer_release (void *data, struct wl_buffer *wl_buffer) priv->used_by_compositor = FALSE; priv->current_gstbuffer = NULL; + GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_TAG_MEMORY); + /* unref should be last, because it may end up destroying the GstWlBuffer */ gst_buffer_unref (buf); }
This is a workaround only, this needs a deeper analysis for a better patch...
Edited by Hugues Fruchet