[igt-dev] [PATCH i-g-t 2/4] lib/igt_fb: Add support for P01x formats
Maarten Lankhorst
maarten.lankhorst at linux.intel.com
Fri Feb 1 11:15:42 UTC 2019
The P01x formats are planar 16 bits per component, with the unused lower bits set to 0.
This means they can all be converted the same way. Only the range is slightly different,
and this is handled in the color_encoding implementation.
This requires cairo 1.17.2 and pixman 0.36. This works but doesn't give extra precision.
For more than 8 bits precision a few more patches are required to pixman, pending review:
https://lists.freedesktop.org/archives/pixman/2019-January/004815.html
https://lists.freedesktop.org/archives/pixman/2019-January/004809.html
Once those are merged, we will require the next pixman release for better precision.
Signed-off-by: Maarten Lankhorst <maarten.lankhorst at linux.intel.com>
---
configure.ac | 4 +-
include/drm-uapi/drm_fourcc.h | 10 ++
lib/igt_color_encoding.c | 4 +
lib/igt_fb.c | 205 ++++++++++++++++++++++++++++++++--
lib/igt_fb.h | 6 +
meson.build | 4 +-
6 files changed, 218 insertions(+), 15 deletions(-)
diff --git a/configure.ac b/configure.ac
index b46f024f875a..336a05bb3f0d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -136,10 +136,10 @@ fi
PKG_CHECK_MODULES(XRANDR, xrandr >= 1.3, AC_DEFINE(HAVE_XRANDR, 1, [Have libXrandr]), [have_xrandr=no])
# for testdisplay
-PKG_CHECK_MODULES(CAIRO, [cairo >= 1.12.0])
+PKG_CHECK_MODULES(CAIRO, [cairo >= 1.17.2])
PKG_CHECK_MODULES(LIBUDEV, [libudev])
PKG_CHECK_MODULES(GLIB, [glib-2.0])
-PKG_CHECK_MODULES(PIXMAN, [pixman-1])
+PKG_CHECK_MODULES(PIXMAN, [pixman-1 >= 0.36])
PKG_CHECK_MODULES(GSL, [gsl], [gsl=yes], [gsl=no])
AM_CONDITIONAL(HAVE_GSL, [test "x$gsl" = xyes])
diff --git a/include/drm-uapi/drm_fourcc.h b/include/drm-uapi/drm_fourcc.h
index 4ddf754bab09..c9a5e5787031 100644
--- a/include/drm-uapi/drm_fourcc.h
+++ b/include/drm-uapi/drm_fourcc.h
@@ -195,6 +195,16 @@ extern "C" {
#define DRM_FORMAT_NV24 fourcc_code('N', 'V', '2', '4') /* non-subsampled Cr:Cb plane */
#define DRM_FORMAT_NV42 fourcc_code('N', 'V', '4', '2') /* non-subsampled Cb:Cr plane */
+/*
+ * 2 plane YCbCr
+ * index 0 = Y plane, [15:0] Y little endian where Pxxx indicate
+ * component xxx msb Y [xxx:16-xxx]
+ * index 1 = Cr:Cb plane, [31:0] Cr:Cb little endian [xxx:16-xxx:xxx:16-xxx]
+ */
+#define DRM_FORMAT_P010 fourcc_code('P', '0', '1', '0') /* 2x2 subsampled Cr:Cb plane, 10 bit per channel */
+#define DRM_FORMAT_P012 fourcc_code('P', '0', '1', '2') /* 2x2 subsampled Cr:Cb plane, 12 bit per channel */
+#define DRM_FORMAT_P016 fourcc_code('P', '0', '1', '6') /* 2x2 subsampled Cr:Cb plane, 16 bit per channel */
+
/*
* 3 plane YCbCr
* index 0: Y plane, [7:0] Y
diff --git a/lib/igt_color_encoding.c b/lib/igt_color_encoding.c
index 4cbe18e217e3..b7a12a1e07f7 100644
--- a/lib/igt_color_encoding.c
+++ b/lib/igt_color_encoding.c
@@ -135,11 +135,15 @@ static const struct color_encoding_format {
float ofs_y, max_y, ofs_cbcr, mid_cbcr, max_cbcr;
} formats[] = {
{ DRM_FORMAT_XRGB8888, 255.f, },
+ { IGT_FORMAT_FLOAT, 1.f, },
{ DRM_FORMAT_NV12, 255.f, 16.f, 235.f, 16.f, 128.f, 240.f },
{ DRM_FORMAT_YUYV, 255.f, 16.f, 235.f, 16.f, 128.f, 240.f },
{ DRM_FORMAT_YVYU, 255.f, 16.f, 235.f, 16.f, 128.f, 240.f },
{ DRM_FORMAT_UYVY, 255.f, 16.f, 235.f, 16.f, 128.f, 240.f },
{ DRM_FORMAT_VYUY, 255.f, 16.f, 235.f, 16.f, 128.f, 240.f },
+ { DRM_FORMAT_P010, 65472.f, 4096.f, 60160.f, 4096.f, 32768.f, 61440.f },
+ { DRM_FORMAT_P012, 65520.f, 4096.f, 60160.f, 4096.f, 32768.f, 61440.f },
+ { DRM_FORMAT_P016, 65535.f, 4096.f, 60160.f, 4096.f, 32768.f, 61440.f },
};
static const struct color_encoding_format *lookup_fourcc(uint32_t fourcc)
diff --git a/lib/igt_fb.c b/lib/igt_fb.c
index a971aebb36b3..8bd0420fc2e4 100644
--- a/lib/igt_fb.c
+++ b/lib/igt_fb.c
@@ -151,6 +151,22 @@ static const struct format_desc_struct {
.cairo_id = CAIRO_FORMAT_RGB24,
.num_planes = 1, .plane_bpp = { 16, },
},
+ { .name = "P010", .depth = -1, .drm_id = DRM_FORMAT_P010,
+ .cairo_id = CAIRO_FORMAT_RGB96F,
+ .num_planes = 2, .plane_bpp = { 16, 32 },
+ },
+ { .name = "P012", .depth = -1, .drm_id = DRM_FORMAT_P012,
+ .cairo_id = CAIRO_FORMAT_RGB96F,
+ .num_planes = 2, .plane_bpp = { 16, 32 },
+ },
+ { .name = "P016", .depth = -1, .drm_id = DRM_FORMAT_P016,
+ .cairo_id = CAIRO_FORMAT_RGB96F,
+ .num_planes = 2, .plane_bpp = { 16, 32 },
+ },
+ { .name = "IGT-FLOAT", .depth = -1, .drm_id = IGT_FORMAT_FLOAT,
+ .cairo_id = CAIRO_FORMAT_INVALID,
+ .num_planes = 1, .plane_bpp = { 128 },
+ },
};
#define for_each_format(f) \
for (f = format_desc; f - format_desc < ARRAY_SIZE(format_desc); f++)
@@ -239,10 +255,17 @@ void igt_get_fb_tile_size(int fd, uint64_t tiling, int fb_bpp,
static unsigned fb_plane_width(const struct igt_fb *fb, int plane)
{
- if (fb->drm_format == DRM_FORMAT_NV12 && plane == 1)
- return DIV_ROUND_UP(fb->width, 2);
-
- return fb->width;
+ switch (fb->drm_format) {
+ case DRM_FORMAT_P010:
+ case DRM_FORMAT_P012:
+ case DRM_FORMAT_P016:
+ case DRM_FORMAT_NV12:
+ if (plane == 1)
+ return DIV_ROUND_UP(fb->width, 2);
+ /* fall-thru */
+ default:
+ return fb->width;
+ }
}
static unsigned fb_plane_bpp(const struct igt_fb *fb, int plane)
@@ -254,10 +277,17 @@ static unsigned fb_plane_bpp(const struct igt_fb *fb, int plane)
static unsigned fb_plane_height(const struct igt_fb *fb, int plane)
{
- if (fb->drm_format == DRM_FORMAT_NV12 && plane == 1)
- return DIV_ROUND_UP(fb->height, 2);
-
- return fb->height;
+ switch (fb->drm_format) {
+ case DRM_FORMAT_P010:
+ case DRM_FORMAT_P012:
+ case DRM_FORMAT_P016:
+ case DRM_FORMAT_NV12:
+ if (plane == 1)
+ return DIV_ROUND_UP(fb->height, 2);
+ /* fall-thru */
+ default:
+ return fb->height;
+ }
}
static int fb_num_planes(const struct igt_fb *fb)
@@ -516,6 +546,13 @@ static int create_bo_for_fb(struct igt_fb *fb)
full_range ? 0x00800080 : 0x10801080,
fb->strides[0] * fb->plane_height[0] / sizeof(wchar_t));
break;
+ case DRM_FORMAT_P010:
+ case DRM_FORMAT_P012:
+ case DRM_FORMAT_P016:
+ wmemset(ptr, full_range ? 0 : 0x10001000,
+ fb->offsets[1] / sizeof(wchar_t));
+ wmemset(ptr + fb->offsets[1], 0x80008000,
+ DIV_ROUND_UP(fb->height,2) * fb->strides[1] / sizeof(wchar_t));
}
gem_munmap(ptr, fb->size);
@@ -1463,6 +1500,7 @@ struct fb_convert_blit_upload {
};
static void *igt_fb_create_cairo_shadow_buffer(int fd,
+ unsigned drm_format,
unsigned int width,
unsigned int height,
struct igt_fb *shadow)
@@ -1472,7 +1510,7 @@ static void *igt_fb_create_cairo_shadow_buffer(int fd,
igt_assert(shadow);
fb_init(shadow, fd, width, height,
- DRM_FORMAT_XRGB8888, LOCAL_DRM_FORMAT_MOD_NONE,
+ drm_format, LOCAL_DRM_FORMAT_MOD_NONE,
IGT_COLOR_YCBCR_BT709, IGT_COLOR_YCBCR_LIMITED_RANGE);
shadow->strides[0] = ALIGN(width * shadow->plane_bpp[0], 16);
@@ -1983,6 +2021,124 @@ static void convert_rgb24_to_yuyv(struct fb_convert *cvt)
}
}
+static void read_rgbf(struct igt_vec4 *rgb, const float *rgb24)
+{
+ rgb->d[0] = rgb24[0];
+ rgb->d[1] = rgb24[1];
+ rgb->d[2] = rgb24[2];
+ rgb->d[3] = 1.0f;
+}
+
+static void write_rgbf(float *rgb24, const struct igt_vec4 *rgb)
+{
+ rgb24[0] = rgb->d[0];
+ rgb24[1] = rgb->d[1];
+ rgb24[2] = rgb->d[2];
+}
+
+static void convert_p01X_to_float(struct fb_convert *cvt)
+{
+ int i, j;
+ struct igt_fb *fb_p01x = cvt->src.fb;
+ struct igt_fb *fb_float = cvt->dst.fb;
+ const uint16_t *y, *uv;
+ void *buf = convert_src_get(cvt);
+ float *ptr = cvt->dst.ptr + fb_float->offsets[0];
+ unsigned float_stride = fb_float->strides[0] / sizeof(*ptr);
+ unsigned planar_stride = fb_p01x->strides[0] / sizeof(*y);
+ struct igt_mat4 m = igt_ycbcr_to_rgb_matrix(fb_p01x->drm_format,
+ fb_float->drm_format,
+ fb_p01x->color_encoding,
+ fb_p01x->color_range);
+
+ y = buf + fb_p01x->offsets[0];
+ uv = buf + fb_p01x->offsets[1];
+
+ for (i = 0; i < fb_p01x->height / 2; i++) {
+ for (j = 0; j < fb_p01x->width / 2; j++) {
+ /* Convert 2x2 pixel blocks */
+ struct igt_vec4 yuv[4];
+ struct igt_vec4 rgb[4];
+
+ yuv[0].d[0] = y[j * 2 + 0];
+ yuv[1].d[0] = y[j * 2 + 1];
+ yuv[2].d[0] = y[j * 2 + 0 + planar_stride];
+ yuv[3].d[0] = y[j * 2 + 1 + planar_stride];
+
+ yuv[0].d[1] = yuv[1].d[1] = yuv[2].d[1] = yuv[3].d[1] = uv[j * 2 + 0];
+ yuv[0].d[2] = yuv[1].d[2] = yuv[2].d[2] = yuv[3].d[2] = uv[j * 2 + 1];
+ yuv[0].d[3] = yuv[1].d[3] = yuv[2].d[3] = yuv[3].d[3] = 1.0f;
+
+ rgb[0] = igt_matrix_transform(&m, &yuv[0]);
+ rgb[1] = igt_matrix_transform(&m, &yuv[1]);
+ rgb[2] = igt_matrix_transform(&m, &yuv[2]);
+ rgb[3] = igt_matrix_transform(&m, &yuv[3]);
+
+ write_rgbf(&ptr[j * 6 + 0], &rgb[0]);
+ write_rgbf(&ptr[j * 6 + 3], &rgb[1]);
+ write_rgbf(&ptr[j * 6 + 0 + float_stride], &rgb[2]);
+ write_rgbf(&ptr[j * 6 + 3 + float_stride], &rgb[3]);
+ }
+
+ ptr += 2 * float_stride;
+ y += 2 * planar_stride;
+ uv += planar_stride;
+ }
+
+ convert_src_put(cvt, buf);
+}
+
+static void convert_float_to_p01X(struct fb_convert *cvt)
+{
+ int i, j;
+ struct igt_fb *fb_float = cvt->src.fb;
+ struct igt_fb *fb_p01x = cvt->dst.fb;
+ uint16_t *y = cvt->dst.ptr + fb_p01x->offsets[0];
+ uint16_t *uv = cvt->dst.ptr + fb_p01x->offsets[1];
+ const float *ptr = cvt->src.ptr + fb_float->offsets[0];
+ unsigned float_stride = fb_float->strides[0] / sizeof(*ptr);
+ unsigned planar_stride = fb_p01x->strides[0] / sizeof(*y);
+ struct igt_mat4 m = igt_rgb_to_ycbcr_matrix(fb_float->drm_format,
+ fb_p01x->drm_format,
+ fb_p01x->color_encoding,
+ fb_p01x->color_range);
+
+ for (i = 0; i < fb_p01x->height / 2; i++) {
+ for (j = 0; j < fb_p01x->width / 2; j++) {
+ /* Convert 2x2 pixel blocks */
+ struct igt_vec4 rgb[4];
+ struct igt_vec4 yuv[4];
+
+ read_rgbf(&rgb[0], &ptr[j * 6 + 0]);
+ read_rgbf(&rgb[1], &ptr[j * 6 + 3]);
+ read_rgbf(&rgb[2], &ptr[j * 6 + 0 + float_stride]);
+ read_rgbf(&rgb[3], &ptr[j * 6 + 3 + float_stride]);
+
+ yuv[0] = igt_matrix_transform(&m, &rgb[0]);
+ yuv[1] = igt_matrix_transform(&m, &rgb[1]);
+ yuv[2] = igt_matrix_transform(&m, &rgb[2]);
+ yuv[3] = igt_matrix_transform(&m, &rgb[3]);
+
+ y[j * 2 + 0] = yuv[0].d[0];
+ y[j * 2 + 1] = yuv[1].d[0];
+ y[j * 2 + 0 + planar_stride] = yuv[2].d[0];
+ y[j * 2 + 1 + planar_stride] = yuv[3].d[0];
+
+ /*
+ * We assume the MPEG2 chroma siting convention, where
+ * pixel center for Cb'Cr' is between the left top and
+ * bottom pixel in a 2x2 block, so take the average.
+ */
+ uv[j * 2 + 0] = (yuv[0].d[1] + yuv[2].d[1]) / 2.0f;
+ uv[j * 2 + 1] = (yuv[0].d[2] + yuv[2].d[2]) / 2.0f;
+ }
+
+ ptr += 2 * float_stride;
+ y += 2 * planar_stride;
+ uv += planar_stride;
+ }
+}
+
static void convert_pixman(struct fb_convert *cvt)
{
pixman_format_code_t src_pixman = drm_format_to_pixman(cvt->src.fb->drm_format);
@@ -2058,6 +2214,22 @@ static void fb_convert(struct fb_convert *cvt)
convert_rgb24_to_yuyv(cvt);
return;
}
+ } else if (cvt->dst.fb->drm_format == IGT_FORMAT_FLOAT) {
+ switch (cvt->src.fb->drm_format) {
+ case DRM_FORMAT_P010:
+ case DRM_FORMAT_P012:
+ case DRM_FORMAT_P016:
+ convert_p01X_to_float(cvt);
+ return;
+ }
+ } else if (cvt->src.fb->drm_format == IGT_FORMAT_FLOAT) {
+ switch (cvt->dst.fb->drm_format) {
+ case DRM_FORMAT_P010:
+ case DRM_FORMAT_P012:
+ case DRM_FORMAT_P016:
+ convert_float_to_p01X(cvt);
+ return;
+ }
}
igt_assert_f(false,
@@ -2098,11 +2270,19 @@ 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 = { };
+ const struct format_desc_struct *f = lookup_drm_format(fb->drm_format);
+ unsigned drm_format;
+
+ if (f->cairo_id == CAIRO_FORMAT_RGB96F ||
+ f->cairo_id == CAIRO_FORMAT_RGBA128F)
+ drm_format = IGT_FORMAT_FLOAT;
+ else
+ drm_format = DRM_FORMAT_XRGB8888;
igt_assert(blit);
blit->base.fd = fd;
blit->base.fb = fb;
- blit->shadow_ptr = igt_fb_create_cairo_shadow_buffer(fd,
+ blit->shadow_ptr = igt_fb_create_cairo_shadow_buffer(fd, drm_format,
fb->width,
fb->height,
&blit->shadow_fb);
@@ -2129,7 +2309,7 @@ static void create_cairo_surface__convert(int fd, struct igt_fb *fb)
fb->cairo_surface =
cairo_image_surface_create_for_data(blit->shadow_ptr,
- CAIRO_FORMAT_RGB24,
+ f->cairo_id,
fb->width, fb->height,
blit->shadow_fb.strides[0]);
@@ -2400,6 +2580,9 @@ bool igt_format_is_yuv(uint32_t drm_format)
{
switch (drm_format) {
case DRM_FORMAT_NV12:
+ case DRM_FORMAT_P010:
+ case DRM_FORMAT_P012:
+ case DRM_FORMAT_P016:
case DRM_FORMAT_YUYV:
case DRM_FORMAT_YVYU:
case DRM_FORMAT_UYVY:
diff --git a/lib/igt_fb.h b/lib/igt_fb.h
index 9f027deba842..8c683db5e9ec 100644
--- a/lib/igt_fb.h
+++ b/lib/igt_fb.h
@@ -38,6 +38,12 @@
#include "igt_color_encoding.h"
+/*
+ * Internal format to denote a buffer compatible with pixman's
+ * floating point format. Range [0-1].
+ */
+#define IGT_FORMAT_FLOAT fourcc_code('I', 'G', 'F', 'x')
+
/**
* igt_fb_t:
* @fb_id: KMS ID of the framebuffer
diff --git a/meson.build b/meson.build
index b17e67ef7f05..4269f361823d 100644
--- a/meson.build
+++ b/meson.build
@@ -149,7 +149,7 @@ endif
build_info += 'With libunwind: ' + libunwindinfo
libdw = dependency('libdw', required : true)
-pixman = dependency('pixman-1', required : true)
+pixman = dependency('pixman-1', version : '>= 0.36', required : true)
valgrind = null_dep
valgrindinfo = 'No'
@@ -162,7 +162,7 @@ if with_valgrind != 'false'
endif
build_info += 'Valgrind annotations: ' + valgrindinfo
-cairo = dependency('cairo', version : '>1.12.0', required : true)
+cairo = dependency('cairo', version : '>=1.17.2', required : true)
libudev = dependency('libudev', required : true)
glib = dependency('glib-2.0', required : true)
--
2.20.1
More information about the igt-dev
mailing list