From: Harry Wentland <harry.wentland@amd.com>
To: <igt-dev@lists.freedesktop.org>
Cc: Harry Wentland <harry.wentland@amd.com>
Subject: [PATCH v5 10/37] igt/color: Add SW color transform functionality
Date: Mon, 19 Aug 2024 16:57:56 -0400 [thread overview]
Message-ID: <20240819205823.316656-11-harry.wentland@amd.com> (raw)
In-Reply-To: <20240819205823.316656-1-harry.wentland@amd.com>
In order to test color we want to compare a HW (KMS) transform
with a SW transform. This introduces color transform for an
sRGB EOTF but this can be extended to other transforms. Code is
borrowed from Skia.
v4:
- Rename srgb_tf to srgb_eotf
v3:
- Use SPDX style license identifier (Kamil)
- Replace large copy-paste of Skia license with copyright note
in file header. Skia is BSD licensed, which is compatible with
MIT.
v2:
- Add inverse sRGB TF
- Make TF functions available to tests
- Modify tranform_pixels function to take multple transforms
Signed-off-by: Harry Wentland <harry.wentland@amd.com>
---
lib/igt_color.c | 258 ++++++++++++++++++++++++++++++++++++++++++++++++
lib/igt_color.h | 43 ++++++++
lib/igt_fb.c | 6 +-
lib/igt_fb.h | 2 +
lib/meson.build | 1 +
5 files changed, 307 insertions(+), 3 deletions(-)
create mode 100644 lib/igt_color.c
create mode 100644 lib/igt_color.h
diff --git a/lib/igt_color.c b/lib/igt_color.c
new file mode 100644
index 000000000000..6349f2b15a47
--- /dev/null
+++ b/lib/igt_color.c
@@ -0,0 +1,258 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright 2023 Advanced Micro Devices, Inc.
+ *
+ * This file contains code adapted from Skia, which is
+ * Copyright (c) 2011 Google Inc. All rights reserved.
+ */
+
+#include <errno.h>
+#include <math.h>
+
+#include "igt_color.h"
+#include "igt_core.h"
+#include "igt_x86.h"
+
+
+static float clamp(float val, float min, float max)
+{
+ return ((val < min) ? min : ((val > max) ? max : val));
+}
+
+static float igt_color_tf_eval_unclamped(const struct igt_color_tf *fn, float x)
+{
+ if (x < fn->d)
+ return fn->c * x + fn->f;
+ return pow(fn->a * x + fn->b, fn->g) + fn->e;
+}
+
+static float igt_color_tf_eval(const struct igt_color_tf *fn, float x)
+{
+ float fn_at_x_unclamped = igt_color_tf_eval_unclamped(fn, x);
+ return clamp(fn_at_x_unclamped, 0.0f, 1.0f);
+}
+
+static void tf_inverse(const struct igt_color_tf *fn, struct igt_color_tf *inv) {
+ memset(inv, 0, sizeof(struct igt_color_tf));
+
+ if (fn->a > 0 && fn->g > 0) {
+ double a_to_the_g = pow(fn->a, fn->g);
+ inv->a = 1.f / a_to_the_g;
+ inv->b = -fn->e / a_to_the_g;
+ inv->g = 1.f / fn->g;
+ }
+
+ inv->d = fn->c * fn->d + fn->f;
+ inv->e = -fn->b / fn->a;
+ if (fn->c != 0) {
+ inv->c = 1.f / fn->c;
+ inv->f = -fn->f / fn->c;
+ }
+}
+
+void igt_color_srgb_inv_eotf(igt_pixel_t *pixel)
+{
+ struct igt_color_tf inv;
+
+ tf_inverse(&srgb_eotf, &inv);
+
+ pixel->r = igt_color_tf_eval(&inv, pixel->r);
+ pixel->g = igt_color_tf_eval(&inv, pixel->g);
+ pixel->b = igt_color_tf_eval(&inv, pixel->b);
+}
+
+
+
+void igt_color_srgb_eotf(igt_pixel_t *pixel)
+{
+ pixel->r = igt_color_tf_eval(&srgb_eotf, pixel->r);
+ pixel->g = igt_color_tf_eval(&srgb_eotf, pixel->g);
+ pixel->b = igt_color_tf_eval(&srgb_eotf, pixel->b);
+}
+
+int igt_color_transform_pixels(igt_fb_t *fb, igt_pixel_transform transforms[], int num_transforms)
+{
+ uint32_t *line = NULL;
+ void *map;
+ char *ptr;
+ int x, y, cpp = igt_drm_format_to_bpp(fb->drm_format) / 8;
+ uint32_t stride = igt_fb_calc_plane_stride(fb, 0);
+
+ if (fb->num_planes != 1)
+ return -EINVAL;
+
+ /* TODO expand for other formats */
+ if (fb->drm_format != DRM_FORMAT_XRGB8888)
+ return -EINVAL;
+
+ ptr = igt_fb_map_buffer(fb->fd, fb);
+ igt_assert(ptr);
+ map = ptr;
+
+ /*
+ * Framebuffers are often uncached, which can make byte-wise accesses
+ * very slow. We copy each line of the FB into a local buffer to speed
+ * up the hashing.
+ */
+ line = malloc(stride);
+ if (!line) {
+ munmap(map, fb->size);
+ return -ENOMEM;
+ }
+
+ for (y = 0; y < fb->height; y++, ptr += stride) {
+
+ /* get line from buffer */
+ igt_memcpy_from_wc(line, ptr, fb->width * cpp);
+
+ for (x = 0; x < fb->width; x++) {
+ uint32_t raw_pixel = le32_to_cpu(line[x]);
+ igt_pixel_t pixel;
+ int i;
+
+ raw_pixel &= 0x00ffffff;
+
+ /*
+ * unpack pixel into igt_pixel_t
+ *
+ * only for XRGB8888 for now
+ *
+ * TODO add "generic" mechanism for unpacking
+ * other FB formats
+ */
+ pixel.r = (raw_pixel & 0x00ff0000) >> 16;
+ pixel.g = (raw_pixel & 0x0000ff00) >> 8;
+ pixel.b = (raw_pixel & 0x000000ff);
+
+ /* normalize for 8-bit */
+ pixel.r /= (0xff);
+ pixel.g /= (0xff);
+ pixel.b /= (0xff);
+
+ /* TODO use read_rgb from igt_fb? */
+
+ /* run transform on pixel */
+
+ for (i = 0; i < num_transforms; i++)
+ transforms[i](&pixel);
+
+ /* de-normalize back to 8-bit */
+ pixel.r *= (0xff);
+ pixel.g *= (0xff);
+ pixel.b *= (0xff);
+
+ /* re-pack pixel into FB*/
+ raw_pixel = 0x0;
+ raw_pixel |= ((uint8_t) (lround(pixel.r) & 0xff)) << 16;
+ raw_pixel |= ((uint8_t) (lround(pixel.g) & 0xff)) << 8;
+ raw_pixel |= ((uint8_t) (lround(pixel.b) & 0xff));
+ /* TODO use write_rgb from igt_fb? */
+
+ /* write back to line */
+ line[x] = cpu_to_le32(raw_pixel);
+ }
+
+ /* copy line back to fb buffer */
+ igt_memcpy_from_wc(ptr, line, fb->width * cpp);
+ }
+
+ free(line);
+ igt_fb_unmap_buffer(fb, map);
+
+ return 0;
+
+ /* for each pixel */
+
+ /* convert to float and create igt_pixel */
+
+ /* call transform */
+
+ /* convert back to fb format from igt_pixel */
+
+
+}
+
+bool igt_cmp_fb_component(uint16_t comp1, uint16_t comp2, uint8_t up, uint8_t down)
+{
+ int16_t diff = comp2 - comp1;
+
+ if ((diff < -down) || (diff > up)) {
+ printf("comp1 %x comp2 %x diff %d down %d, up %d\n", comp1, comp2, diff, -down, up);
+ return false;
+ }
+
+ return true;
+}
+
+bool igt_cmp_fb_pixels(igt_fb_t *fb1, igt_fb_t *fb2, uint8_t up, uint8_t down)
+{
+ uint32_t *ptr1, *ptr2;
+ uint32_t pixel1, pixel2, i, j;
+ bool matched = true;
+
+
+ ptr1 = igt_fb_map_buffer(fb1->fd, fb1);
+ ptr2 = igt_fb_map_buffer(fb2->fd, fb2);
+
+ igt_assert(fb1->drm_format == fb2->drm_format);
+ igt_assert(fb1->size == fb2->size);
+
+ for (i = 0; i < fb1->size / sizeof(uint32_t); i++) {
+ uint16_t mask = 0xff;
+ uint16_t shift = 8;
+
+ if (fb1->drm_format == DRM_FORMAT_XRGB2101010) {
+ /* ignore alpha */
+ pixel1 = ptr1[i] & ~0xc0000000;
+ pixel2 = ptr2[i] & ~0xc0000000;
+
+ mask = 0x3ff;
+ shift = 10;
+
+
+ } else if (fb1->drm_format == DRM_FORMAT_XRGB8888) {
+ /* ignore alpha */
+ pixel1 = ptr1[i] & ~0xff000000;
+ pixel2 = ptr2[i] & ~0xff000000;
+
+ mask = 0xff;
+ shift = 8;
+
+ } else {
+ pixel1 = ptr1[i];
+ pixel2 = ptr2[i];
+ }
+
+ for (j = 0; j < 3; j++) {
+ uint16_t comp1 = (pixel1 >> (shift*j)) & mask;
+ uint16_t comp2 = (pixel2 >> (shift*j)) & mask;
+
+ if (!igt_cmp_fb_component(comp1, comp2, up, down)) {
+ /* TODO use proper log*/
+ printf("i %d j %d shift %d mask %x comp1 %x comp2 %x, pixel1 %x pixel2 %x\n",
+ i, j, shift, mask, comp1, comp2, pixel1, pixel2);
+ return false;
+ }
+ }
+ }
+
+ igt_fb_unmap_buffer(fb1, ptr1);
+ igt_fb_unmap_buffer(fb2, ptr2);
+
+ return matched;
+}
+
+
+void igt_dump_fb(igt_display_t *display, igt_fb_t *fb,
+ const char *path_name, const char *file_name)
+{
+ char filepath_out[PATH_MAX];
+ cairo_surface_t *fb_surface_out;
+ cairo_status_t status;
+
+ snprintf(filepath_out, PATH_MAX, "%s/%s.png", path_name, file_name);
+ fb_surface_out = igt_get_cairo_surface(display->drm_fd, fb);
+ status = cairo_surface_write_to_png(fb_surface_out, filepath_out);
+ igt_assert_eq(status, CAIRO_STATUS_SUCCESS);
+ cairo_surface_destroy(fb_surface_out);
+}
\ No newline at end of file
diff --git a/lib/igt_color.h b/lib/igt_color.h
new file mode 100644
index 000000000000..fa9f6cf42991
--- /dev/null
+++ b/lib/igt_color.h
@@ -0,0 +1,43 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright 2023 Advanced Micro Devices, Inc.
+ *
+ * This file contains code adapted from Skia, which is
+ * Copyright (c) 2011 Google Inc. All rights reserved.
+ */
+
+
+#ifndef __IGT_COLOR_H__
+#define __IGT_COLOR_H__
+
+#include <limits.h>
+
+#include "igt_fb.h"
+#include "igt_kms.h"
+
+struct igt_color_tf {
+ float g, a,b,c,d,e,f;
+};
+
+const struct igt_color_tf srgb_eotf = {2.4f, (float)(1/1.055), (float)(0.055/1.055), (float)(1/12.92), 0.04045f, 0, 0};
+
+typedef struct igt_pixel {
+ float r;
+ float g;
+ float b;
+} igt_pixel_t;
+
+bool igt_cmp_fb_component(uint16_t comp1, uint16_t comp2, uint8_t up, uint8_t down);
+bool igt_cmp_fb_pixels(igt_fb_t *fb1, igt_fb_t *fb2, uint8_t up, uint8_t down);
+
+void igt_dump_fb(igt_display_t *display, igt_fb_t *fb, const char *path_name, const char *file_name);
+
+/* TODO also allow 64-bit pixels, or other weird sizes */
+typedef void (*igt_pixel_transform)(igt_pixel_t *pixel);
+
+int igt_color_transform_pixels(igt_fb_t *fb, igt_pixel_transform transforms[], int num_transforms);
+
+void igt_color_srgb_inv_eotf(igt_pixel_t *pixel);
+void igt_color_srgb_eotf(igt_pixel_t *pixel);
+
+#endif
\ No newline at end of file
diff --git a/lib/igt_fb.c b/lib/igt_fb.c
index addff2cfba3b..abee42918def 100644
--- a/lib/igt_fb.c
+++ b/lib/igt_fb.c
@@ -762,7 +762,7 @@ void igt_init_fb(struct igt_fb *fb, int fd, int width, int height,
}
}
-static uint32_t calc_plane_stride(struct igt_fb *fb, int plane)
+uint32_t igt_fb_calc_plane_stride(struct igt_fb *fb, int plane)
{
uint32_t min_stride = fb->plane_width[plane] *
(fb->plane_bpp[plane] / 8);
@@ -944,7 +944,7 @@ static uint64_t calc_fb_size(struct igt_fb *fb)
/* respect the stride requested by the caller */
if (!fb->strides[plane])
- fb->strides[plane] = calc_plane_stride(fb, plane);
+ fb->strides[plane] = igt_fb_calc_plane_stride(fb, plane);
align = get_plane_alignment(fb, plane);
if (align)
@@ -4814,7 +4814,7 @@ int igt_fb_get_fnv1a_crc(struct igt_fb *fb, igt_crc_t *crc)
void *map;
char *ptr;
int x, y, cpp = igt_drm_format_to_bpp(fb->drm_format) / 8;
- uint32_t stride = calc_plane_stride(fb, 0);
+ uint32_t stride = igt_fb_calc_plane_stride(fb, 0);
if (fb->num_planes != 1)
return -EINVAL;
diff --git a/lib/igt_fb.h b/lib/igt_fb.h
index 834aaef54dea..d2751c0bb772 100644
--- a/lib/igt_fb.h
+++ b/lib/igt_fb.h
@@ -170,6 +170,8 @@ int igt_dirty_fb(int fd, struct igt_fb *fb);
void *igt_fb_map_buffer(int fd, struct igt_fb *fb);
void igt_fb_unmap_buffer(struct igt_fb *fb, void *buffer);
+uint32_t igt_fb_calc_plane_stride(struct igt_fb *fb, int plane);
+
void igt_create_bo_for_fb(int fd, int width, int height,
uint32_t format, uint64_t modifier,
struct igt_fb *fb);
diff --git a/lib/meson.build b/lib/meson.build
index f711e60a736a..15fe5f5c2a18 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -107,6 +107,7 @@ lib_sources = [
'igt_edid.c',
'igt_eld.c',
'igt_infoframe.c',
+ 'igt_color.c',
'veboxcopy_gen12.c',
'igt_msm.c',
'igt_dsc.c',
--
2.46.0
next prev parent reply other threads:[~2024-08-19 20:58 UTC|newest]
Thread overview: 41+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-08-19 20:57 [PATCH v5 00/37] IGT tests for the KMS Color Pipeline API Harry Wentland
2024-08-19 20:57 ` [PATCH v5 01/37] lib/drmtest: Add is_vkms_device() Harry Wentland
2024-08-19 20:57 ` [PATCH v5 02/37] tests/kms_writeback: Fix kms_writeback for VKMS Harry Wentland
2024-08-19 20:57 ` [PATCH v5 03/37] lib/igt_kms: Move get_writeback_formats_blob to lib Harry Wentland
2024-08-19 20:57 ` [PATCH v5 04/37] lib/igt_kms: Introduce DRM_CLIENT_CAP_PLANE_COLOR_PIPELINE Harry Wentland
2024-08-19 20:57 ` [PATCH v5 05/37] include/drm-uapi: Add COLOROP object Harry Wentland
2024-08-19 20:57 ` [PATCH v5 06/37] drm-uapi: Add 3x4 CTM Harry Wentland
2024-08-19 20:57 ` [PATCH v5 07/37] drm-uapi: Add 1D LUT drm_colorop_type Harry Wentland
2024-08-19 20:57 ` [PATCH v5 08/37] lib/igt_kms: Introduce drm_colorop and COLOR_PIPELINE Harry Wentland
2024-08-19 20:57 ` [PATCH v5 09/37] tests/kms_properties: Add colorop properties test Harry Wentland
2024-08-19 20:57 ` Harry Wentland [this message]
2024-08-19 20:57 ` [PATCH v5 11/37] lib/igt_fb: Add copy_fb function Harry Wentland
2024-08-19 20:57 ` [PATCH v5 12/37] tests/kms_colorop: Add kms_colorop tests Harry Wentland
2024-08-19 20:57 ` [PATCH v5 13/37] lib/igt_kms: Add support for DATA colorop property Harry Wentland
2024-08-19 20:58 ` [PATCH v5 14/37] lib/igt_color: Add support for 3x4 matrices Harry Wentland
2024-08-19 20:58 ` [PATCH v5 15/37] tests/kms_colorop: Add 3x4 CTM tests Harry Wentland
2024-08-19 20:58 ` [PATCH v5 16/37] tests/kms_colorop: Add bypass test Harry Wentland
2024-08-19 20:58 ` [PATCH v5 17/37] tests/kms_colorop: Parametrize the buffer format Harry Wentland
2024-08-19 20:58 ` [PATCH v5 18/37] tests/kms_colorop: Add 10bpc test and skip if format not supported Harry Wentland
2024-08-19 20:58 ` [PATCH v5 19/37] tests/kms_colorop: Skip if writeback does not support fourcc Harry Wentland
2024-08-19 20:58 ` [PATCH v5 20/37] lib/igt_fb: Allow any non-planar format for igt_copy_fb Harry Wentland
2024-08-19 20:58 ` [PATCH v5 21/37] kms/colorop: Do proper setup and cleanup Harry Wentland
2024-08-19 20:58 ` [PATCH v5 22/37] lib/igt_color: Support color transform for XRGB2101010 Harry Wentland
2024-08-19 20:58 ` [PATCH v5 23/37] tests/kms_colorop: Set wide [13, 13] bracket for comparison on amdgpu Harry Wentland
2024-08-19 20:58 ` [PATCH v5 24/37] lib/igt_color: Add PQ variants for 0-1 and 0-125 range Harry Wentland
2024-08-19 20:58 ` [PATCH v5 25/37] tests/kms_colorop: Add tests for PQ variants Harry Wentland
2024-08-19 20:58 ` [PATCH v5 26/37] lib/igt_kms: increase MAX_NUM_COLOROPS to 128 Harry Wentland
2024-08-19 20:58 ` [PATCH v5 27/37] tests/kms_colorop: Add a sRGB test for EOTF -> Inverse EOTF -> EOTF Harry Wentland
2024-08-19 20:58 ` [PATCH v5 28/37] lib/igt_color: add BT2020/BT709 transfer functions Harry Wentland
2024-08-19 20:58 ` [PATCH v5 29/37] tests/kms_colorop: Add tests for BT2020/BT709 TFs Harry Wentland
2024-08-19 20:58 ` [PATCH v5 30/37] lib/igt_color: Add 1D LUT color transformation support Harry Wentland
2024-08-19 20:58 ` [PATCH v5 31/37] test/kms_colorop: Add tests that exercise the 1D LUT colorops Harry Wentland
2024-08-19 20:58 ` [PATCH v5 32/37] tests/kms_colorop: Add multiplier tests Harry Wentland
2024-08-19 20:58 ` [PATCH v5 33/37] lib/igt_color: Point license header at skia license Harry Wentland
2024-08-19 20:58 ` [PATCH v5 34/37] scripts/convert_3dlut.py Convert a 3D LUT to igt_3dlut_t array for 3D LUT API Harry Wentland
2024-08-19 20:58 ` [PATCH v5 35/37] tests/kms_colorop: Add 3D LUT subtests Harry Wentland
2024-08-19 20:58 ` [PATCH v5 36/37] drm-uapi: Update kernel doc for drm_colorop_type Harry Wentland
2024-08-19 20:58 ` [PATCH v5 37/37] drm-uapi: Sync up definition with kernel colorop implementation Harry Wentland
2024-08-19 23:30 ` ✓ CI.xeBAT: success for IGT tests for the KMS Color Pipeline API (rev6) Patchwork
2024-08-19 23:46 ` ✗ Fi.CI.BAT: failure " Patchwork
2024-08-20 7:49 ` ✗ CI.xeFULL: " Patchwork
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20240819205823.316656-11-harry.wentland@amd.com \
--to=harry.wentland@amd.com \
--cc=igt-dev@lists.freedesktop.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox