[igt-dev] [PATCH i-g-t 8/8] lib: Add support for rendering into packed YCbCr framebuffers
Ville Syrjala
ville.syrjala at linux.intel.com
Tue Feb 27 21:21:20 UTC 2018
From: Ville Syrjälä <ville.syrjala at linux.intel.com>
Reuse the __convert() cairo stuff to support packed YCbCr framebuffers.
Signed-off-by: Ville Syrjälä <ville.syrjala at linux.intel.com>
---
lib/igt_fb.c | 182 +++++++++++++++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 172 insertions(+), 10 deletions(-)
diff --git a/lib/igt_fb.c b/lib/igt_fb.c
index 56dcf6d38e7c..20c7788f5f5d 100644
--- a/lib/igt_fb.c
+++ b/lib/igt_fb.c
@@ -85,6 +85,22 @@ static struct format_desc_struct {
.cairo_id = CAIRO_FORMAT_RGB24,
.num_planes = 2, .plane_bpp = { 8, 16, },
},
+ { .name = "YUYV", .depth = -1, .drm_id = DRM_FORMAT_YUYV,
+ .cairo_id = CAIRO_FORMAT_RGB24,
+ .num_planes = 1, .plane_bpp = { 16, },
+ },
+ { .name = "YVYU", .depth = -1, .drm_id = DRM_FORMAT_YVYU,
+ .cairo_id = CAIRO_FORMAT_RGB24,
+ .num_planes = 1, .plane_bpp = { 16, },
+ },
+ { .name = "UYVY", .depth = -1, .drm_id = DRM_FORMAT_UYVY,
+ .cairo_id = CAIRO_FORMAT_RGB24,
+ .num_planes = 1, .plane_bpp = { 16, },
+ },
+ { .name = "VYUY", .depth = -1, .drm_id = DRM_FORMAT_VYUY,
+ .cairo_id = CAIRO_FORMAT_RGB24,
+ .num_planes = 1, .plane_bpp = { 16, },
+ },
};
#define for_each_format(f) \
for (f = format_desc; f - format_desc < ARRAY_SIZE(format_desc); f++)
@@ -1511,16 +1527,151 @@ static void convert_rgb24_to_nv12(struct igt_fb *fb, struct fb_convert_blit_uplo
}
}
+/* { Y0, U, Y1, V } */
+static const unsigned char swizzle_yuyv[] = { 0, 1, 2, 3 };
+static const unsigned char swizzle_yvyu[] = { 0, 3, 2, 1 };
+static const unsigned char swizzle_uyvy[] = { 1, 0, 3, 2 };
+static const unsigned char swizzle_vyuy[] = { 1, 2, 3, 0 };
+
+static const unsigned char *yuyv_swizzle(uint32_t format)
+{
+ switch (format) {
+ default:
+ case DRM_FORMAT_YUYV:
+ return swizzle_yuyv;
+ case DRM_FORMAT_YVYU:
+ return swizzle_yvyu;
+ case DRM_FORMAT_UYVY:
+ return swizzle_uyvy;
+ case DRM_FORMAT_VYUY:
+ return swizzle_vyuy;
+ }
+}
+
+static void convert_yuyv_to_rgb24(struct igt_fb *fb, struct fb_convert_blit_upload *blit,
+ const unsigned char swz[4])
+{
+ 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);
+ bool full_range = false; /* FIXME */
+ const struct igt_color_encoding *e = &igt_ycbcr_bt601; /* FIXME */
+ struct igt_mat4 m = igt_ycbcr_to_rgb_matrix(e, full_range);
+
+ igt_assert((fb->width & 1) == 0);
+
+ /*
+ * 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.
+ */
+ memcpy(buf, blit->linear.map, blit->linear.size);
+ yuyv = buf;
+
+ /* Convert from limited color range BT.601 */
+ for (i = 0; i < fb->height; i++) {
+ for (j = 0; j < fb->width / 2; j++) {
+ /* Convert 2x1 pixel blocks */
+ struct igt_vec4 yuv0, yuv1;
+ struct igt_vec4 rgb0, rgb1;
+
+ yuv0.d[0] = yuyv[j * 4 + swz[0]];
+ yuv1.d[0] = yuyv[j * 4 + swz[2]];
+ yuv0.d[1] = yuv1.d[1] = yuyv[j * 4 + swz[1]];
+ yuv0.d[2] = yuv1.d[2] = yuyv[j * 4 + swz[3]];
+ yuv0.d[3] = yuv1.d[3] = 1.0f;
+
+ rgb0 = igt_matrix_transform(&m, &yuv0);
+ rgb1 = igt_matrix_transform(&m, &yuv1);
+
+ rgb24[j * 8 + 2] = clamprgb(rgb0.d[0]);
+ rgb24[j * 8 + 1] = clamprgb(rgb0.d[1]);
+ rgb24[j * 8 + 0] = clamprgb(rgb0.d[2]);
+
+ rgb24[j * 8 + 4 + 2] = clamprgb(rgb1.d[0]);
+ rgb24[j * 8 + 4 + 1] = clamprgb(rgb1.d[1]);
+ rgb24[j * 8 + 4 + 0] = clamprgb(rgb1.d[2]);
+ }
+
+ rgb24 += rgb24_stride;
+ yuyv += yuyv_stride;
+ }
+
+ free(buf);
+}
+
+static void convert_rgb24_to_yuyv(struct igt_fb *fb, struct fb_convert_blit_upload *blit,
+ const unsigned char swz[4])
+{
+ 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;
+ bool full_range = false; /* FIXME */
+ const struct igt_color_encoding *e = &igt_ycbcr_bt601; /* FIXME */
+ struct igt_mat4 m = igt_rgb_to_ycbcr_matrix(e, full_range);
+
+ igt_assert((fb->width & 1) == 0);
+
+ 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,
+ "Conversion not implemented for !YUYV planar formats\n");
+
+ for (i = 0; i < fb->height; i++) {
+ for (j = 0; j < fb->width / 2; j++) {
+ /* Convert 2x1 pixel blocks */
+ struct igt_vec4 rgb0, rgb1;
+ struct igt_vec4 yuv0, yuv1;
+
+ rgb0.d[0] = rgb24[j * 8 + 2];
+ rgb0.d[1] = rgb24[j * 8 + 1];
+ rgb0.d[2] = rgb24[j * 8 + 0];
+ rgb0.d[3] = 1.0f;
+
+ rgb1.d[0] = rgb24[j * 8 + 4 + 2];
+ rgb1.d[1] = rgb24[j * 8 + 4 + 1];
+ rgb1.d[2] = rgb24[j * 8 + 4 + 0];
+ rgb1.d[3] = 1.0f;
+
+ yuv0 = igt_matrix_transform(&m, &rgb0);
+ yuv1 = igt_matrix_transform(&m, &rgb1);
+
+ yuyv[j * 4 + swz[0]] = yuv0.d[0];
+ yuyv[j * 4 + swz[2]] = yuv1.d[0];
+ yuyv[j * 4 + swz[1]] = (yuv0.d[1] + yuv1.d[1]) / 2.0f;
+ yuyv[j * 4 + swz[3]] = (yuv0.d[2] + yuv1.d[2]) / 2.0f;
+ }
+
+ rgb24 += rgb24_stride;
+ yuyv += yuyv_stride;
+ }
+}
+
static void destroy_cairo_surface__convert(void *arg)
{
struct fb_convert_blit_upload *blit = arg;
struct igt_fb *fb = blit->fb;
- /* Convert back to planar! */
- igt_assert_f(fb->drm_format == DRM_FORMAT_NV12,
- "Conversion not implemented for !NV12 planar formats\n");
-
- convert_rgb24_to_nv12(fb, blit);
+ /* 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, yuyv_swizzle(fb->drm_format));
+ break;
+ default:
+ igt_assert_f(false, "Conversion not implemented for formats 0x%x\n",
+ fb->drm_format);
+ }
munmap(blit->rgb24.map, blit->rgb24.size);
@@ -1559,10 +1710,21 @@ static void create_cairo_surface__convert(int fd, struct igt_fb *fb)
memcpy(blit->linear.offsets, fb->offsets, sizeof(fb->offsets));
}
- /* Convert to linear! */
- igt_assert_f(fb->drm_format == DRM_FORMAT_NV12,
- "Conversion not implemented for !NV12 planar formats\n");
- convert_nv12_to_rgb24(fb, blit);
+ /* 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, yuyv_swizzle(fb->drm_format));
+ break;
+ default:
+ igt_assert_f(false, "Conversion not implemented for formats 0x%x\n",
+ fb->drm_format);
+ }
fb->cairo_surface =
cairo_image_surface_create_for_data(blit->rgb24.map,
@@ -1589,7 +1751,7 @@ static void create_cairo_surface__convert(int fd, struct igt_fb *fb)
cairo_surface_t *igt_get_cairo_surface(int fd, struct igt_fb *fb)
{
if (fb->cairo_surface == NULL) {
- if (fb->num_planes > 1)
+ if (is_yuv(fb->drm_format))
create_cairo_surface__convert(fd, fb);
else if (fb->tiling == LOCAL_I915_FORMAT_MOD_Y_TILED ||
fb->tiling == LOCAL_I915_FORMAT_MOD_Yf_TILED)
--
2.13.6
More information about the igt-dev
mailing list