libv4l-rockchip_v2: Adjust height for I420 to fit DMA alignment
Chromium sometimes uses USERPTR buffers to pass raw frames to the
encoder. USERPTR requires the size of the buffer fit cache alignment
for reliable DMA, which on ARM64 happens to be 128.
Normally we would adjust sizeimage to fit the alignment, but Chromium
currently ignores sizeimage passed back by V4L2, and only uses width
and height to compute a buffer size. To work around this, have the
libv4l plugin round up the height of the output format before it is
passed to the kernel, such that it fits the DMA alignment.
BUG=b:250800750
BUG=chromium:1362996
TEST=Screen share on Kevin should use hardware encoder
Change-Id: I3e4c63bb45b7bc9d50216371b0f7dcaf384c04a7
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/libv4lplugins/+/3933923
Reviewed-by: Brian Norris <[email protected]>
Reviewed-by: Hirokazu Honda <[email protected]>
Tested-by: Hirokazu Honda <[email protected]>
Commit-Queue: Chen-Yu Tsai <[email protected]>
diff --git a/libv4l-rockchip_v2/libv4l-encplugin-rockchip.c b/libv4l-rockchip_v2/libv4l-encplugin-rockchip.c
index af75efb..93e086c 100644
--- a/libv4l-rockchip_v2/libv4l-encplugin-rockchip.c
+++ b/libv4l-rockchip_v2/libv4l-encplugin-rockchip.c
@@ -48,6 +48,7 @@
#define DEFAULT_BITRATE 1000000
#define PENDING_BUFFER_QUEUE_SIZE VIDEO_MAX_FRAME
#define round_down(x, y) ((x) - ((x) % (y)))
+#define round_up(x, y) ((((x) + ((y) - 1)) / (y)) * (y))
/*
* struct pending_buffer - A v4l2 buffer pending for QBUF.
@@ -616,11 +617,26 @@
return SYS_IOCTL(fd, VIDIOC_S_PARM, parms);
}
+#define DMA_ALIGNMENT 128
+#define MB_DIM 16
+
static int ioctl_s_fmt_locked(struct encoder_context *ctx, int fd,
struct v4l2_format *format)
{
uint32_t width = format->fmt.pix_mp.width;
uint32_t height = format->fmt.pix_mp.height;
+
+ /* b/251326397 handle sizeimage in Chromium
+ * Align plane size to full cache line by adjusting the height.
+ * Considering the I420 format, the height and width are multiple
+ * of MB_DIM, and the size of uv plane is 1/2 of y plane in both
+ * dimensions. The height should be multiple of (cache * 4 / MB_DIM)
+ */
+ if (V4L2_TYPE_IS_OUTPUT(format->type) &&
+ format->fmt.pix_mp.pixelformat == V4L2_PIX_FMT_YUV420M)
+ format->fmt.pix_mp.height = height =
+ round_up(height, DMA_ALIGNMENT * 4 / MB_DIM);
+
int ret = SYS_IOCTL(fd, VIDIOC_S_FMT, format);
if (ret)
return ret;