Re: [igt-dev] [PATCH i-g-t 2/4] lib/igt_fb: Add support for P01x formats

Maarten Lankhorst
2019-02-04T17:06:24Z

Op 04-02-2019 om 14:22 schreef Sharma, Swati2:
>
> On 01-Feb-19 4:45 PM, Maarten Lankhorst wrote:
>> 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@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,
>
> Hi Maarten,
>
> With this change f->cairo_id, for pixel format AB24 whose cairo_id=CAIRO_FORMAT_INVALID and pixman_id!=invalid, when cairo will try to create surface it will return non-zero value i.e. 16 (CAIRO_STATUS_INVALID_FORMAT).  May be some change required in igt_get_cairo_surface if condition or need to assign cairo format for pixel format having invalid cairo like it was earlier :/

Thanks, will make sure that INVALID_FORMAT is caught. :)

~Maarten