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:
Guillaume Desmottes 2017-07-17 16:07:21 +02:00 committed by Nicolas Dufresne
parent f9379b51b6
commit 2d67189073

View File

@ -49,8 +49,6 @@ struct kms_bo
{ {
void *ptr; void *ptr;
size_t size; size_t size;
size_t offset;
size_t pitch;
unsigned handle; unsigned handle;
unsigned int refs; unsigned int refs;
}; };
@ -130,13 +128,39 @@ gst_kms_allocator_memory_reset (GstKMSAllocator * allocator, GstKMSMemory * mem)
mem->bo = NULL; 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 static gboolean
gst_kms_allocator_memory_create (GstKMSAllocator * allocator, gst_kms_allocator_memory_create (GstKMSAllocator * allocator,
GstKMSMemory * kmsmem, GstVideoInfo * vinfo) GstKMSMemory * kmsmem, GstVideoInfo * vinfo)
{ {
gint ret; gint i, ret, h;
struct drm_mode_create_dumb arg = { 0, }; struct drm_mode_create_dumb arg = { 0, };
guint32 fmt; guint32 fmt;
gint num_planes = GST_VIDEO_INFO_N_PLANES (vinfo);
gsize offs = 0;
if (kmsmem->bo) if (kmsmem->bo)
return TRUE; return TRUE;
@ -151,15 +175,51 @@ gst_kms_allocator_memory_create (GstKMSAllocator * allocator,
fmt = gst_drm_format_from_video (GST_VIDEO_INFO_FORMAT (vinfo)); fmt = gst_drm_format_from_video (GST_VIDEO_INFO_FORMAT (vinfo));
arg.bpp = gst_drm_bpp_from_drm (fmt); arg.bpp = gst_drm_bpp_from_drm (fmt);
arg.width = GST_VIDEO_INFO_WIDTH (vinfo); 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); ret = drmIoctl (allocator->priv->fd, DRM_IOCTL_MODE_CREATE_DUMB, &arg);
if (ret) if (ret)
goto create_failed; 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; kmsmem->bo->handle = arg.handle;
/* will be used a memory maxsize */
kmsmem->bo->size = arg.size; 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; return TRUE;
@ -359,13 +419,13 @@ gst_kms_allocator_new (int fd)
* which are relative to the GstBuffer start. */ * which are relative to the GstBuffer start. */
static gboolean static gboolean
gst_kms_allocator_add_fb (GstKMSAllocator * alloc, GstKMSMemory * kmsmem, 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); gint num_planes = GST_VIDEO_INFO_N_PLANES (vinfo);
guint32 w, h, fmt, pitch = 0, bo_handles[4] = { 0, }; guint32 w, h, fmt, bo_handles[4] = { 0, };
guint32 offsets[4] = { 0, };
guint32 pitches[4] = { 0, }; guint32 pitches[4] = { 0, };
guint32 offsets[4] = { 0, };
if (kmsmem->fb_id) if (kmsmem->fb_id)
return TRUE; return TRUE;
@ -374,35 +434,19 @@ gst_kms_allocator_add_fb (GstKMSAllocator * alloc, GstKMSMemory * kmsmem,
h = GST_VIDEO_INFO_HEIGHT (vinfo); h = GST_VIDEO_INFO_HEIGHT (vinfo);
fmt = gst_drm_format_from_video (GST_VIDEO_INFO_FORMAT (vinfo)); fmt = gst_drm_format_from_video (GST_VIDEO_INFO_FORMAT (vinfo));
if (kmsmem->bo) { for (i = 0; i < num_planes; i++) {
bo_handles[0] = kmsmem->bo->handle; if (kmsmem->bo)
for (i = 1; i < num_planes; i++) bo_handles[i] = kmsmem->bo->handle;
bo_handles[i] = bo_handles[0]; else
/* 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++)
bo_handles[i] = kmsmem->gem_handle[i]; 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], GST_DEBUG_OBJECT (alloc, "bo handles: %d, %d, %d, %d", bo_handles[0],
bo_handles[1], bo_handles[2], bo_handles[3]); 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, ret = drmModeAddFB2 (alloc->priv->fd, w, h, fmt, bo_handles, pitches,
offsets, &kmsmem->fb_id, 0); offsets, &kmsmem->fb_id, 0);
if (ret) { if (ret) {
@ -410,6 +454,7 @@ gst_kms_allocator_add_fb (GstKMSAllocator * alloc, GstKMSMemory * kmsmem,
strerror (-ret), ret); strerror (-ret), ret);
return FALSE; return FALSE;
} }
return TRUE; return TRUE;
} }
@ -427,11 +472,15 @@ gst_kms_allocator_bo_alloc (GstAllocator * allocator, GstVideoInfo * vinfo)
alloc = GST_KMS_ALLOCATOR (allocator); alloc = GST_KMS_ALLOCATOR (allocator);
mem = GST_MEMORY_CAST (kmsmem); 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)) if (!gst_kms_allocator_memory_create (alloc, kmsmem, vinfo)) {
goto fail; 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)) if (!gst_kms_allocator_add_fb (alloc, kmsmem, vinfo->offset, vinfo))
goto fail; goto fail;