mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-02-22 14:06:23 +00:00
kmsallocator: add driver pitch support for planar formats
We used to to handle the driver pitch only for single plan video format. Add support for multi planes format by re-using the extrapolate function from the v4l2 element. Also use this pitch to calculate the proper offsets. Prevent DRM drivers to pick a slow path if the pitches/offsets don't match the ones it reported. https://bugzilla.gnome.org/show_bug.cgi?id=785029
This commit is contained in:
parent
f9379b51b6
commit
2d67189073
1 changed files with 85 additions and 36 deletions
|
@ -49,8 +49,6 @@ struct kms_bo
|
|||
{
|
||||
void *ptr;
|
||||
size_t size;
|
||||
size_t offset;
|
||||
size_t pitch;
|
||||
unsigned handle;
|
||||
unsigned int refs;
|
||||
};
|
||||
|
@ -130,13 +128,39 @@ gst_kms_allocator_memory_reset (GstKMSAllocator * allocator, GstKMSMemory * mem)
|
|||
mem->bo = NULL;
|
||||
}
|
||||
|
||||
/* Copied from gst_v4l2_object_extrapolate_stride() */
|
||||
static gint
|
||||
extrapolate_stride (const GstVideoFormatInfo * finfo, gint plane, gint stride)
|
||||
{
|
||||
gint estride;
|
||||
|
||||
switch (finfo->format) {
|
||||
case GST_VIDEO_FORMAT_NV12:
|
||||
case GST_VIDEO_FORMAT_NV12_64Z32:
|
||||
case GST_VIDEO_FORMAT_NV21:
|
||||
case GST_VIDEO_FORMAT_NV16:
|
||||
case GST_VIDEO_FORMAT_NV61:
|
||||
case GST_VIDEO_FORMAT_NV24:
|
||||
estride = (plane == 0 ? 1 : 2) *
|
||||
GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (finfo, plane, stride);
|
||||
break;
|
||||
default:
|
||||
estride = GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (finfo, plane, stride);
|
||||
break;
|
||||
}
|
||||
|
||||
return estride;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_kms_allocator_memory_create (GstKMSAllocator * allocator,
|
||||
GstKMSMemory * kmsmem, GstVideoInfo * vinfo)
|
||||
{
|
||||
gint ret;
|
||||
gint i, ret, h;
|
||||
struct drm_mode_create_dumb arg = { 0, };
|
||||
guint32 fmt;
|
||||
gint num_planes = GST_VIDEO_INFO_N_PLANES (vinfo);
|
||||
gsize offs = 0;
|
||||
|
||||
if (kmsmem->bo)
|
||||
return TRUE;
|
||||
|
@ -151,15 +175,51 @@ gst_kms_allocator_memory_create (GstKMSAllocator * allocator,
|
|||
fmt = gst_drm_format_from_video (GST_VIDEO_INFO_FORMAT (vinfo));
|
||||
arg.bpp = gst_drm_bpp_from_drm (fmt);
|
||||
arg.width = GST_VIDEO_INFO_WIDTH (vinfo);
|
||||
arg.height = gst_drm_height_from_drm (fmt, GST_VIDEO_INFO_HEIGHT (vinfo));
|
||||
h = GST_VIDEO_INFO_HEIGHT (vinfo);
|
||||
arg.height = gst_drm_height_from_drm (fmt, h);
|
||||
|
||||
ret = drmIoctl (allocator->priv->fd, DRM_IOCTL_MODE_CREATE_DUMB, &arg);
|
||||
if (ret)
|
||||
goto create_failed;
|
||||
|
||||
if (!arg.pitch)
|
||||
goto done;
|
||||
|
||||
for (i = 0; i < num_planes; i++) {
|
||||
guint32 pitch;
|
||||
|
||||
if (!arg.pitch)
|
||||
continue;
|
||||
|
||||
/* Overwrite the video info's stride and offset using the pitch calculcated
|
||||
* by the kms driver. */
|
||||
pitch = extrapolate_stride (vinfo->finfo, i, arg.pitch);
|
||||
GST_VIDEO_INFO_PLANE_STRIDE (vinfo, i) = pitch;
|
||||
GST_VIDEO_INFO_PLANE_OFFSET (vinfo, i) = offs;
|
||||
|
||||
/* Note that we cannot negotiate special padding betweem each planes,
|
||||
* hence using the display height here. */
|
||||
offs += pitch * GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (vinfo->finfo, i, h);
|
||||
|
||||
GST_DEBUG_OBJECT (allocator, "Created BO plane %i with stride %i and "
|
||||
"offset %" G_GSIZE_FORMAT, i,
|
||||
GST_VIDEO_INFO_PLANE_STRIDE (vinfo, i),
|
||||
GST_VIDEO_INFO_PLANE_OFFSET (vinfo, i));
|
||||
}
|
||||
|
||||
done:
|
||||
kmsmem->bo->handle = arg.handle;
|
||||
/* will be used a memory maxsize */
|
||||
kmsmem->bo->size = arg.size;
|
||||
kmsmem->bo->pitch = arg.pitch;
|
||||
|
||||
/* Validate the size to prevent overflow */
|
||||
if (kmsmem->bo->size < GST_VIDEO_INFO_SIZE (vinfo)) {
|
||||
GST_ERROR_OBJECT (allocator,
|
||||
"DUMB buffer has a size of %" G_GSIZE_FORMAT
|
||||
" but we require at least %" G_GSIZE_FORMAT " to hold a frame",
|
||||
kmsmem->bo->size, GST_VIDEO_INFO_SIZE (vinfo));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
|
||||
|
@ -359,13 +419,13 @@ gst_kms_allocator_new (int fd)
|
|||
* which are relative to the GstBuffer start. */
|
||||
static gboolean
|
||||
gst_kms_allocator_add_fb (GstKMSAllocator * alloc, GstKMSMemory * kmsmem,
|
||||
gsize mem_offsets[GST_VIDEO_MAX_PLANES], GstVideoInfo * vinfo)
|
||||
gsize in_offsets[GST_VIDEO_MAX_PLANES], GstVideoInfo * vinfo)
|
||||
{
|
||||
int i, ret;
|
||||
gint i, ret;
|
||||
gint num_planes = GST_VIDEO_INFO_N_PLANES (vinfo);
|
||||
guint32 w, h, fmt, pitch = 0, bo_handles[4] = { 0, };
|
||||
guint32 offsets[4] = { 0, };
|
||||
guint32 w, h, fmt, bo_handles[4] = { 0, };
|
||||
guint32 pitches[4] = { 0, };
|
||||
guint32 offsets[4] = { 0, };
|
||||
|
||||
if (kmsmem->fb_id)
|
||||
return TRUE;
|
||||
|
@ -374,35 +434,19 @@ gst_kms_allocator_add_fb (GstKMSAllocator * alloc, GstKMSMemory * kmsmem,
|
|||
h = GST_VIDEO_INFO_HEIGHT (vinfo);
|
||||
fmt = gst_drm_format_from_video (GST_VIDEO_INFO_FORMAT (vinfo));
|
||||
|
||||
if (kmsmem->bo) {
|
||||
bo_handles[0] = kmsmem->bo->handle;
|
||||
for (i = 1; i < num_planes; i++)
|
||||
bo_handles[i] = bo_handles[0];
|
||||
|
||||
/* Get the bo pitch calculated by the kms driver.
|
||||
* If it's defined, it will overwrite the video info's stride.
|
||||
* Since the API is completely undefined for planar formats,
|
||||
* only do this for interleaved formats.
|
||||
*/
|
||||
if (num_planes == 1)
|
||||
pitch = kmsmem->bo->pitch;
|
||||
} else {
|
||||
for (i = 0; i < num_planes; i++)
|
||||
for (i = 0; i < num_planes; i++) {
|
||||
if (kmsmem->bo)
|
||||
bo_handles[i] = kmsmem->bo->handle;
|
||||
else
|
||||
bo_handles[i] = kmsmem->gem_handle[i];
|
||||
|
||||
pitches[i] = GST_VIDEO_INFO_PLANE_STRIDE (vinfo, i);
|
||||
offsets[i] = in_offsets[i];
|
||||
}
|
||||
|
||||
GST_DEBUG_OBJECT (alloc, "bo handles: %d, %d, %d, %d", bo_handles[0],
|
||||
bo_handles[1], bo_handles[2], bo_handles[3]);
|
||||
|
||||
for (i = 0; i < num_planes; i++) {
|
||||
offsets[i] = mem_offsets[i];
|
||||
if (pitch)
|
||||
GST_VIDEO_INFO_PLANE_STRIDE (vinfo, i) = pitch;
|
||||
pitches[i] = GST_VIDEO_INFO_PLANE_STRIDE (vinfo, i);
|
||||
GST_DEBUG_OBJECT (alloc, "Create FB plane %i with stride %u and offset %u",
|
||||
i, pitches[i], offsets[i]);
|
||||
}
|
||||
|
||||
ret = drmModeAddFB2 (alloc->priv->fd, w, h, fmt, bo_handles, pitches,
|
||||
offsets, &kmsmem->fb_id, 0);
|
||||
if (ret) {
|
||||
|
@ -410,6 +454,7 @@ gst_kms_allocator_add_fb (GstKMSAllocator * alloc, GstKMSMemory * kmsmem,
|
|||
strerror (-ret), ret);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
@ -427,11 +472,15 @@ gst_kms_allocator_bo_alloc (GstAllocator * allocator, GstVideoInfo * vinfo)
|
|||
alloc = GST_KMS_ALLOCATOR (allocator);
|
||||
|
||||
mem = GST_MEMORY_CAST (kmsmem);
|
||||
gst_memory_init (mem, GST_MEMORY_FLAG_NO_SHARE, allocator, NULL,
|
||||
GST_VIDEO_INFO_SIZE (vinfo), 0, 0, GST_VIDEO_INFO_SIZE (vinfo));
|
||||
|
||||
if (!gst_kms_allocator_memory_create (alloc, kmsmem, vinfo))
|
||||
goto fail;
|
||||
if (!gst_kms_allocator_memory_create (alloc, kmsmem, vinfo)) {
|
||||
g_slice_free (GstKMSMemory, kmsmem);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gst_memory_init (mem, GST_MEMORY_FLAG_NO_SHARE, allocator, NULL,
|
||||
kmsmem->bo->size, 0, 0, GST_VIDEO_INFO_SIZE (vinfo));
|
||||
|
||||
if (!gst_kms_allocator_add_fb (alloc, kmsmem, vinfo->offset, vinfo))
|
||||
goto fail;
|
||||
|
||||
|
|
Loading…
Reference in a new issue