[igt-dev] [PATCH v6 03/13] fb: Create common function to convert frame formats

Ville Syrjälä ville.syrjala at linux.intel.com
Fri Aug 31 13:41:10 UTC 2018


On Fri, Aug 31, 2018 at 03:12:12PM +0200, Maxime Ripard wrote:
> The current code to convert between two buffer formats is quite tied to the
> cairo surface infrastructure. Since we'll want to reuse it, make that
> function more generic by introducing a common structure that passes all the
> arguments and a common function that will call the right functions we
> needed.
> 
> Reviewed-by: Eric Anholt <eric at anholt.net>
> Signed-off-by: Maxime Ripard <maxime.ripard at bootlin.com>
> ---
>  lib/igt_fb.c | 243 ++++++++++++++++++++++++++++++++--------------------
>  1 file changed, 153 insertions(+), 90 deletions(-)
> 
> diff --git a/lib/igt_fb.c b/lib/igt_fb.c
> index 4061fedec0c1..1914233786a5 100644
> --- a/lib/igt_fb.c
> +++ b/lib/igt_fb.c
> @@ -1384,6 +1384,24 @@ struct fb_convert_blit_upload {
>  	struct fb_blit_linear linear;
>  };
>  
> +struct fb_convert_buf {
> +	void			*ptr;
> +	unsigned int		stride;
> +	unsigned int		size;
> +	uint32_t		fmt;
> +	enum igt_color_encoding	color_encoding;
> +	enum igt_color_range	color_range;
> +	uint32_t		offsets[4];
> +};

I wonder if we can just use igt_fb for that instead of duplicating most
of it?

I have a patch that did something like that for the fb_blit_upload
stuff: https://patchwork.freedesktop.org/patch/239832/

> +
> +struct fb_convert {
> +	unsigned int		width;
> +	unsigned int		height;
> +
> +	struct fb_convert_buf	dst;
> +	struct fb_convert_buf	src;
> +};
> +
>  static uint8_t clamprgb(float val)
>  {
>  	return clamp((int)(val + 0.5f), 0, 255);
> @@ -1404,27 +1422,28 @@ static void write_rgb(uint8_t *rgb24, const struct igt_vec4 *rgb)
>  	rgb24[0] = clamprgb(rgb->d[2]);
>  }
>  
> -static void convert_nv12_to_rgb24(struct igt_fb *fb, struct fb_convert_blit_upload *blit)
> +static void convert_nv12_to_rgb24(struct fb_convert *cvt)
>  {
>  	int i, j;
>  	const uint8_t *y, *uv;
> -	uint8_t *rgb24 = blit->rgb24.map;
> -	unsigned rgb24_stride = blit->rgb24.stride, planar_stride = blit->linear.stride;
> -	uint8_t *buf = malloc(blit->linear.size);
> -	struct igt_mat4 m = igt_ycbcr_to_rgb_matrix(fb->color_encoding,
> -						    fb->color_range);
> +	uint8_t *rgb24 = cvt->dst.ptr;
> +	unsigned int rgb24_stride = cvt->dst.stride;
> +	unsigned int planar_stride = cvt->src.stride;
> +	uint8_t *buf = malloc(cvt->src.size);
> +	struct igt_mat4 m = igt_ycbcr_to_rgb_matrix(cvt->src.color_encoding,
> +						    cvt->src.color_range);
>  
>  	/*
>  	 * Reading from the BO is awfully slow because of lack of read caching,
>  	 * it's faster to copy the whole BO to a temporary buffer and convert
>  	 * from there.
>  	 */
> -	igt_memcpy_from_wc(buf, blit->linear.map, blit->linear.size);
> -	y = &buf[blit->linear.offsets[0]];
> -	uv = &buf[blit->linear.offsets[1]];
> +	igt_memcpy_from_wc(buf, cvt->src.ptr, cvt->src.size);
> +	y = cvt->src.ptr + cvt->src.offsets[0];
> +	uv = cvt->src.ptr + cvt->src.offsets[1];
>  
> -	for (i = 0; i < fb->height / 2; i++) {
> -		for (j = 0; j < fb->width / 2; j++) {
> +	for (i = 0; i < cvt->height / 2; i++) {
> +		for (j = 0; j < cvt->width / 2; j++) {
>  			/* Convert 2x2 pixel blocks */
>  			struct igt_vec4 yuv[4];
>  			struct igt_vec4 rgb[4];
> @@ -1449,7 +1468,7 @@ static void convert_nv12_to_rgb24(struct igt_fb *fb, struct fb_convert_blit_uplo
>  			write_rgb(&rgb24[j * 8 + 4 + rgb24_stride], &rgb[3]);
>  		}
>  
> -		if (fb->width & 1) {
> +		if (cvt->width & 1) {
>  			/* Convert 1x2 pixel block */
>  			struct igt_vec4 yuv[2];
>  			struct igt_vec4 rgb[2];
> @@ -1473,9 +1492,9 @@ static void convert_nv12_to_rgb24(struct igt_fb *fb, struct fb_convert_blit_uplo
>  		uv += planar_stride;
>  	}
>  
> -	if (fb->height & 1) {
> +	if (cvt->height & 1) {
>  		/* Convert last row */
> -		for (j = 0; j < fb->width / 2; j++) {
> +		for (j = 0; j < cvt->width / 2; j++) {
>  			/* Convert 2x1 pixel blocks */
>  			struct igt_vec4 yuv[2];
>  			struct igt_vec4 rgb[2];
> @@ -1493,7 +1512,7 @@ static void convert_nv12_to_rgb24(struct igt_fb *fb, struct fb_convert_blit_uplo
>  			write_rgb(&rgb24[j * 8 + 4], &rgb[0]);
>  		}
>  
> -		if (fb->width & 1) {
> +		if (cvt->width & 1) {
>  			/* Convert single pixel */
>  			struct igt_vec4 yuv;
>  			struct igt_vec4 rgb;
> @@ -1512,22 +1531,22 @@ static void convert_nv12_to_rgb24(struct igt_fb *fb, struct fb_convert_blit_uplo
>  	free(buf);
>  }
>  
> -static void convert_rgb24_to_nv12(struct igt_fb *fb, struct fb_convert_blit_upload *blit)
> +static void convert_rgb24_to_nv12(struct fb_convert *cvt)
>  {
>  	int i, j;
> -	uint8_t *y = &blit->linear.map[blit->linear.offsets[0]];
> -	uint8_t *uv = &blit->linear.map[blit->linear.offsets[1]];
> -	const uint8_t *rgb24 = blit->rgb24.map;
> -	unsigned rgb24_stride = blit->rgb24.stride;
> -	unsigned planar_stride = blit->linear.stride;
> -	struct igt_mat4 m = igt_rgb_to_ycbcr_matrix(fb->color_encoding,
> -						    fb->color_range);
> -
> -	igt_assert_f(fb->drm_format == DRM_FORMAT_NV12,
> +	uint8_t *y = cvt->dst.ptr + cvt->dst.offsets[0];
> +	uint8_t *uv = cvt->dst.ptr + cvt->dst.offsets[1];
> +	const uint8_t *rgb24 = cvt->src.ptr;
> +	unsigned rgb24_stride = cvt->src.stride;
> +	unsigned planar_stride = cvt->dst.stride;
> +	struct igt_mat4 m = igt_rgb_to_ycbcr_matrix(cvt->dst.color_encoding,
> +						    cvt->dst.color_range);
> +
> +	igt_assert_f(cvt->dst.fmt == DRM_FORMAT_NV12,
>  		     "Conversion not implemented for !NV12 planar formats\n");
>  
> -	for (i = 0; i < fb->height / 2; i++) {
> -		for (j = 0; j < fb->width / 2; j++) {
> +	for (i = 0; i < cvt->height / 2; i++) {
> +		for (j = 0; j < cvt->width / 2; j++) {
>  			/* Convert 2x2 pixel blocks */
>  			struct igt_vec4 rgb[4];
>  			struct igt_vec4 yuv[4];
> @@ -1556,7 +1575,7 @@ static void convert_rgb24_to_nv12(struct igt_fb *fb, struct fb_convert_blit_uplo
>  			uv[j * 2 + 1] = (yuv[0].d[2] + yuv[2].d[2]) / 2.0f;
>  		}
>  
> -		if (fb->width & 1) {
> +		if (cvt->width & 1) {
>  			/* Convert 1x2 pixel block */
>  			struct igt_vec4 rgb[2];
>  			struct igt_vec4 yuv[2];
> @@ -1585,8 +1604,8 @@ static void convert_rgb24_to_nv12(struct igt_fb *fb, struct fb_convert_blit_uplo
>  	}
>  
>  	/* Last row cannot be interpolated between 2 pixels, take the single value */
> -	if (fb->height & 1) {
> -		for (j = 0; j < fb->width / 2; j++) {
> +	if (cvt->height & 1) {
> +		for (j = 0; j < cvt->width / 2; j++) {
>  			/* Convert 2x1 pixel blocks */
>  			struct igt_vec4 rgb[2];
>  			struct igt_vec4 yuv[2];
> @@ -1603,7 +1622,7 @@ static void convert_rgb24_to_nv12(struct igt_fb *fb, struct fb_convert_blit_uplo
>  			uv[j * 2 + 1] = yuv[0].d[2];
>  		}
>  
> -		if (fb->width & 1) {
> +		if (cvt->width & 1) {
>  			/* Convert single pixel */
>  			struct igt_vec4 rgb;
>  			struct igt_vec4 yuv;
> @@ -1640,27 +1659,28 @@ static const unsigned char *yuyv_swizzle(uint32_t format)
>  	}
>  }
>  
> -static void convert_yuyv_to_rgb24(struct igt_fb *fb, struct fb_convert_blit_upload *blit)
> +static void convert_yuyv_to_rgb24(struct fb_convert *cvt)
>  {
>  	int i, j;
>  	const uint8_t *yuyv;
> -	uint8_t *rgb24 = blit->rgb24.map;
> -	unsigned rgb24_stride = blit->rgb24.stride, yuyv_stride = blit->linear.stride;
> -	uint8_t *buf = malloc(blit->linear.size);
> -	struct igt_mat4 m = igt_ycbcr_to_rgb_matrix(fb->color_encoding,
> -						    fb->color_range);
> -	const unsigned char *swz = yuyv_swizzle(fb->drm_format);
> +	uint8_t *rgb24 = cvt->dst.ptr;
> +	unsigned int rgb24_stride = cvt->dst.stride;
> +	unsigned int yuyv_stride = cvt->src.stride;
> +	uint8_t *buf = malloc(cvt->src.size);
> +	struct igt_mat4 m = igt_ycbcr_to_rgb_matrix(cvt->src.color_encoding,
> +						    cvt->src.color_range);
> +	const unsigned char *swz = yuyv_swizzle(cvt->src.fmt);
>  
>  	/*
>  	 * Reading from the BO is awfully slow because of lack of read caching,
>  	 * it's faster to copy the whole BO to a temporary buffer and convert
>  	 * from there.
>  	 */
> -	igt_memcpy_from_wc(buf, blit->linear.map, blit->linear.size);
> +	igt_memcpy_from_wc(buf, cvt->src.ptr, cvt->src.size);
>  	yuyv = buf;
>  
> -	for (i = 0; i < fb->height; i++) {
> -		for (j = 0; j < fb->width / 2; j++) {
> +	for (i = 0; i < cvt->height; i++) {
> +		for (j = 0; j < cvt->width / 2; j++) {
>  			/* Convert 2x1 pixel blocks */
>  			struct igt_vec4 yuv[2];
>  			struct igt_vec4 rgb[2];
> @@ -1678,7 +1698,7 @@ static void convert_yuyv_to_rgb24(struct igt_fb *fb, struct fb_convert_blit_uplo
>  			write_rgb(&rgb24[j * 8 + 4], &rgb[1]);
>  		}
>  
> -		if (fb->width & 1) {
> +		if (cvt->width & 1) {
>  			struct igt_vec4 yuv;
>  			struct igt_vec4 rgb;
>  
> @@ -1699,25 +1719,25 @@ static void convert_yuyv_to_rgb24(struct igt_fb *fb, struct fb_convert_blit_uplo
>  	free(buf);
>  }
>  
> -static void convert_rgb24_to_yuyv(struct igt_fb *fb, struct fb_convert_blit_upload *blit)
> +static void convert_rgb24_to_yuyv(struct fb_convert *cvt)
>  {
>  	int i, j;
> -	uint8_t *yuyv = blit->linear.map;
> -	const uint8_t *rgb24 = blit->rgb24.map;
> -	unsigned rgb24_stride = blit->rgb24.stride;
> -	unsigned yuyv_stride = blit->linear.stride;
> -	struct igt_mat4 m = igt_rgb_to_ycbcr_matrix(fb->color_encoding,
> -						    fb->color_range);
> -	const unsigned char *swz = yuyv_swizzle(fb->drm_format);
> -
> -	igt_assert_f(fb->drm_format == DRM_FORMAT_YUYV ||
> -		     fb->drm_format == DRM_FORMAT_YVYU ||
> -		     fb->drm_format == DRM_FORMAT_UYVY ||
> -		     fb->drm_format == DRM_FORMAT_VYUY,
> +	uint8_t *yuyv = cvt->dst.ptr;
> +	const uint8_t *rgb24 = cvt->src.ptr;
> +	unsigned rgb24_stride = cvt->src.stride;
> +	unsigned yuyv_stride = cvt->dst.stride;
> +	struct igt_mat4 m = igt_rgb_to_ycbcr_matrix(cvt->dst.color_encoding,
> +						    cvt->dst.color_range);
> +	const unsigned char *swz = yuyv_swizzle(cvt->dst.fmt);
> +
> +	igt_assert_f(cvt->dst.fmt == DRM_FORMAT_YUYV ||
> +		     cvt->dst.fmt == DRM_FORMAT_YVYU ||
> +		     cvt->dst.fmt == DRM_FORMAT_UYVY ||
> +		     cvt->dst.fmt == DRM_FORMAT_VYUY,
>  		     "Conversion not implemented for !YUYV planar formats\n");
>  
> -	for (i = 0; i < fb->height; i++) {
> -		for (j = 0; j < fb->width / 2; j++) {
> +	for (i = 0; i < cvt->height; i++) {
> +		for (j = 0; j < cvt->width / 2; j++) {
>  			/* Convert 2x1 pixel blocks */
>  			struct igt_vec4 rgb[2];
>  			struct igt_vec4 yuv[2];
> @@ -1734,7 +1754,7 @@ static void convert_rgb24_to_yuyv(struct igt_fb *fb, struct fb_convert_blit_uplo
>  			yuyv[j * 4 + swz[3]] = (yuv[0].d[2] + yuv[1].d[2]) / 2.0f;
>  		}
>  
> -		if (fb->width & 1) {
> +		if (cvt->width & 1) {
>  			struct igt_vec4 rgb;
>  			struct igt_vec4 yuv;
>  
> @@ -1752,27 +1772,65 @@ static void convert_rgb24_to_yuyv(struct igt_fb *fb, struct fb_convert_blit_uplo
>  	}
>  }
>  
> +static void fb_convert(struct fb_convert *cvt)
> +{
> +	if (cvt->dst.fmt == DRM_FORMAT_RGB888) {
> +		switch (cvt->src.fmt) {
> +		case DRM_FORMAT_NV12:
> +			convert_nv12_to_rgb24(cvt);
> +			return;
> +		case DRM_FORMAT_YUYV:
> +		case DRM_FORMAT_YVYU:
> +		case DRM_FORMAT_UYVY:
> +		case DRM_FORMAT_VYUY:
> +			convert_yuyv_to_rgb24(cvt);
> +			return;
> +		}
> +	} else if (cvt->src.fmt == DRM_FORMAT_RGB888) {
> +		switch (cvt->dst.fmt) {
> +		case DRM_FORMAT_NV12:
> +			convert_rgb24_to_nv12(cvt);
> +			return;
> +		case DRM_FORMAT_YUYV:
> +		case DRM_FORMAT_YVYU:
> +		case DRM_FORMAT_UYVY:
> +		case DRM_FORMAT_VYUY:
> +			convert_rgb24_to_yuyv(cvt);
> +			return;
> +		}
> +	}
> +
> +	igt_assert_f(false,
> +		     "Conversion not implemented (from format 0x%x to 0x%x)\n",
> +		     cvt->src.fmt, cvt->dst.fmt);
> +}
> +
>  static void destroy_cairo_surface__convert(void *arg)
>  {
>  	struct fb_convert_blit_upload *blit = arg;
>  	struct igt_fb *fb = blit->fb;
> -
> -	/* Convert linear rgb back! */
> -	switch(fb->drm_format) {
> -	case DRM_FORMAT_NV12:
> -		convert_rgb24_to_nv12(fb, blit);
> -		break;
> -	case DRM_FORMAT_YUYV:
> -	case DRM_FORMAT_YVYU:
> -	case DRM_FORMAT_UYVY:
> -	case DRM_FORMAT_VYUY:
> -		convert_rgb24_to_yuyv(fb, blit);
> -		break;
> -	default:
> -		igt_assert_f(false, "Conversion not implemented for formats 0x%x\n",
> -			     fb->drm_format);
> -	}
> -
> +	struct fb_convert cvt = {
> +		.width	= fb->width,
> +		.height	= fb->height,
> +
> +		.dst	= {
> +			.ptr		= blit->linear.map,
> +			.fmt		= fb->drm_format,
> +			.stride		= blit->linear.stride,
> +			.size		= blit->linear.size,
> +			.color_encoding	= fb->color_encoding,
> +			.color_range	= fb->color_range,
> +		},
> +
> +		.src	= {
> +			.ptr		= blit->rgb24.map,
> +			.fmt		= DRM_FORMAT_RGB888,
> +			.stride		= blit->rgb24.stride,
> +			.size		= blit->rgb24.size,
> +		},
> +	};
> +
> +	fb_convert(&cvt);
>  	munmap(blit->rgb24.map, blit->rgb24.size);
>  
>  	if (blit->linear.handle)
> @@ -1788,6 +1846,8 @@ static void destroy_cairo_surface__convert(void *arg)
>  static void create_cairo_surface__convert(int fd, struct igt_fb *fb)
>  {
>  	struct fb_convert_blit_upload *blit = malloc(sizeof(*blit));
> +	struct fb_convert cvt = { 0 };
> +
>  	igt_assert(blit);
>  
>  	blit->fd = fd;
> @@ -1809,21 +1869,24 @@ static void create_cairo_surface__convert(int fd, struct igt_fb *fb)
>  		memcpy(blit->linear.offsets, fb->offsets, sizeof(fb->offsets));
>  	}
>  
> -	/* Convert to linear rgb! */
> -	switch(fb->drm_format) {
> -	case DRM_FORMAT_NV12:
> -		convert_nv12_to_rgb24(fb, blit);
> -		break;
> -	case DRM_FORMAT_YUYV:
> -	case DRM_FORMAT_YVYU:
> -	case DRM_FORMAT_UYVY:
> -	case DRM_FORMAT_VYUY:
> -		convert_yuyv_to_rgb24(fb, blit);
> -		break;
> -	default:
> -		igt_assert_f(false, "Conversion not implemented for formats 0x%x\n",
> -			     fb->drm_format);
> -	}
> +	cvt.width = fb->width;
> +	cvt.height = fb->height;
> +
> +	cvt.dst.ptr = blit->rgb24.map;
> +	cvt.dst.fmt = DRM_FORMAT_RGB888;
> +	cvt.dst.stride = blit->rgb24.stride;
> +	cvt.dst.size = blit->rgb24.size;
> +
> +	cvt.src.ptr = blit->linear.map;
> +	cvt.src.fmt = fb->drm_format;
> +	cvt.src.stride	= blit->linear.stride;
> +	cvt.src.size = blit->linear.size;
> +	cvt.src.color_encoding = fb->color_encoding;
> +	cvt.src.color_range = fb->color_range;
> +	memcpy(cvt.dst.offsets, blit->linear.offsets,
> +	       sizeof(blit->linear.offsets));
> +
> +	fb_convert(&cvt);
>  
>  	fb->cairo_surface =
>  		cairo_image_surface_create_for_data(blit->rgb24.map,
> -- 
> git-series 0.9.1

-- 
Ville Syrjälä
Intel


More information about the igt-dev mailing list