[PATCH V10 27/30] tests/kms_colorop: Add a 3D LUT subtest
Aurabindo Pillai
aurabindo.pillai at amd.com
Fri Aug 22 21:35:19 UTC 2025
On 8/15/25 12:06 AM, Alex Hung wrote:
> This includes a subtests 3dlut_17_12_rgb.
>
> Signed-off-by: Alex Hung <alex.hung at amd.com>
> ---
> include/drm-uapi/drm_mode.h | 18 +
> lib/igt_color.c | 186 ++
> lib/igt_color.h | 10 +
> lib/igt_color_lut.h | 4946 +++++++++++++++++++++++++++++++++++
> lib/igt_kms.c | 2 +
> lib/igt_kms.h | 2 +
> tests/kms_colorop.c | 35 +-
> tests/kms_colorop.h | 19 +
> 8 files changed, 5217 insertions(+), 1 deletion(-)
> create mode 100644 lib/igt_color_lut.h
>
> diff --git a/include/drm-uapi/drm_mode.h b/include/drm-uapi/drm_mode.h
> index fe3e98e20..009bb3e7f 100644
> --- a/include/drm-uapi/drm_mode.h
> +++ b/include/drm-uapi/drm_mode.h
> @@ -891,6 +891,24 @@ enum drm_colorop_type {
> DRM_COLOROP_1D_LUT,
> DRM_COLOROP_CTM_3X4,
> DRM_COLOROP_MULTIPLIER,
> + DRM_COLOROP_3D_LUT,
> +};
> +
> +enum drm_colorop_interpolation_type {
> + DRM_COLOROP_TETRAHEDRAL,
> +};
> +
> +/**
> + * enum drm_colorop_lut3d_interpolation_type - type of 3DLUT interpolation
> + *
> + */
> +enum drm_colorop_lut3d_interpolation_type {
> + /**
> + * @DRM_COLOROP_LUT3D_INTERPOLATION_TETRAHEDRAL:
> + *
> + * Tetrahedral 3DLUT interpolation
> + */
> + DRM_COLOROP_LUT3D_INTERPOLATION_TETRAHEDRAL,
> };
>
> /**
> diff --git a/lib/igt_color.c b/lib/igt_color.c
> index aa65eac20..6a306bda2 100644
> --- a/lib/igt_color.c
> +++ b/lib/igt_color.c
> @@ -213,6 +213,184 @@ void igt_color_multiply_inv_125(igt_pixel_t *pixel)
> igt_color_multiply(pixel, 1 / 125.0f);
> }
>
> +static int
> +igt_get_lut3d_index_blue_fast(int r, int g, int b, long dim, int components)
> +{
> + return components * (b + (int)dim * (g + (int)dim * r));
> +}
> +
> +/* algorithm from https://github.com/AcademySoftwareFoundation/OpenColorIO/blob/main/src/OpenColorIO/ops/lut3d/Lut3DOpCPU.cpp#L422 */
> +static void igt_color_3dlut_tetrahedral(igt_pixel_t *pixel, igt_3dlut_t *lut3d, long m_dim)
> +{
> + int n000, n100, n010, n001, n110, n101, n011, n111;
> + float m_step = (float) m_dim - 1.0f;
> + const float dimMinusOne = (float) m_dim - 1.f;
> + float *m_optLut = (float *) lut3d->lut;
> + float idx[3];
> + float out[3];
> + int indexLow[3];
> + int indexHigh[3];
> + float fx, fy, fz;
> +
> + idx[0] = pixel->b * m_step;
> + idx[1] = pixel->g * m_step;
> + idx[2] = pixel->r * m_step;
> +
> + // NaNs become 0.
> + idx[0] = clamp(idx[0], 0.f, dimMinusOne);
> + idx[1] = clamp(idx[1], 0.f, dimMinusOne);
> + idx[2] = clamp(idx[2], 0.f, dimMinusOne);
> +
> + indexLow[0] = floor(idx[0]);
> + indexLow[1] = floor(idx[1]);
> + indexLow[2] = floor(idx[2]);
> +
> + // When the idx is exactly equal to an index (e.g. 0,1,2...)
> + // then the computation of highIdx is wrong. However,
> + // the delta is then equal to zero (e.g. idx-lowIdx),
> + // so the highIdx has no impact.
> + indexHigh[0] = ceil(idx[0]);
> + indexHigh[1] = ceil(idx[1]);
> + indexHigh[2] = ceil(idx[2]);
> +
> + fx = idx[0] - (float) indexLow[0];
> + fy = idx[1] - (float) indexLow[1];
> + fz = idx[2] - (float) indexLow[2];
> +
> + // Compute index into LUT for surrounding corners
> + n000 = igt_get_lut3d_index_blue_fast(indexLow[0], indexLow[1], indexLow[2], m_dim, 3);
> + n100 = igt_get_lut3d_index_blue_fast(indexHigh[0], indexLow[1], indexLow[2], m_dim, 3);
> + n010 = igt_get_lut3d_index_blue_fast(indexLow[0], indexHigh[1], indexLow[2], m_dim, 3);
> + n001 = igt_get_lut3d_index_blue_fast(indexLow[0], indexLow[1], indexHigh[2], m_dim, 3);
> + n110 = igt_get_lut3d_index_blue_fast(indexHigh[0], indexHigh[1], indexLow[2], m_dim, 3);
> + n101 = igt_get_lut3d_index_blue_fast(indexHigh[0], indexLow[1], indexHigh[2], m_dim, 3);
> + n011 = igt_get_lut3d_index_blue_fast(indexLow[0], indexHigh[1], indexHigh[2], m_dim, 3);
> + n111 = igt_get_lut3d_index_blue_fast(indexHigh[0], indexHigh[1], indexHigh[2], m_dim, 3);
> +
> + if (fx > fy) {
> + if (fy > fz) {
> + out[0] =
> + (1 - fx) * m_optLut[n000] +
> + (fx - fy) * m_optLut[n100] +
> + (fy - fz) * m_optLut[n110] +
> + (fz) * m_optLut[n111];
> +
> + out[1] =
> + (1 - fx) * m_optLut[n000 + 1] +
> + (fx - fy) * m_optLut[n100 + 1] +
> + (fy - fz) * m_optLut[n110 + 1] +
> + (fz) * m_optLut[n111 + 1];
> +
> + out[2] =
> + (1 - fx) * m_optLut[n000 + 2] +
> + (fx - fy) * m_optLut[n100 + 2] +
> + (fy - fz) * m_optLut[n110 + 2] +
> + (fz) * m_optLut[n111 + 2];
> + } else if (fx > fz) {
> + out[0] =
> + (1 - fx) * m_optLut[n000] +
> + (fx - fz) * m_optLut[n100] +
> + (fz - fy) * m_optLut[n101] +
> + (fy) * m_optLut[n111];
> +
> + out[1] =
> + (1 - fx) * m_optLut[n000 + 1] +
> + (fx - fz) * m_optLut[n100 + 1] +
> + (fz - fy) * m_optLut[n101 + 1] +
> + (fy) * m_optLut[n111 + 1];
> +
> + out[2] =
> + (1 - fx) * m_optLut[n000 + 2] +
> + (fx - fz) * m_optLut[n100 + 2] +
> + (fz - fy) * m_optLut[n101 + 2] +
> + (fy) * m_optLut[n111 + 2];
> + } else {
> + out[0] =
> + (1 - fz) * m_optLut[n000] +
> + (fz - fx) * m_optLut[n001] +
> + (fx - fy) * m_optLut[n101] +
> + (fy) * m_optLut[n111];
> +
> + out[1] =
> + (1 - fz) * m_optLut[n000 + 1] +
> + (fz - fx) * m_optLut[n001 + 1] +
> + (fx - fy) * m_optLut[n101 + 1] +
> + (fy) * m_optLut[n111 + 1];
> +
> + out[2] =
> + (1 - fz) * m_optLut[n000 + 2] +
> + (fz - fx) * m_optLut[n001 + 2] +
> + (fx - fy) * m_optLut[n101 + 2] +
> + (fy) * m_optLut[n111 + 2];
> + }
> + } else {
> + if (fz > fy) {
> + out[0] =
> + (1 - fz) * m_optLut[n000] +
> + (fz - fy) * m_optLut[n001] +
> + (fy - fx) * m_optLut[n011] +
> + (fx) * m_optLut[n111];
> +
> + out[1] =
> + (1 - fz) * m_optLut[n000 + 1] +
> + (fz - fy) * m_optLut[n001 + 1] +
> + (fy - fx) * m_optLut[n011 + 1] +
> + (fx) * m_optLut[n111 + 1];
> +
> + out[2] =
> + (1 - fz) * m_optLut[n000 + 2] +
> + (fz - fy) * m_optLut[n001 + 2] +
> + (fy - fx) * m_optLut[n011 + 2] +
> + (fx) * m_optLut[n111 + 2];
> + } else if (fz > fx) {
> + out[0] =
> + (1 - fy) * m_optLut[n000] +
> + (fy - fz) * m_optLut[n010] +
> + (fz - fx) * m_optLut[n011] +
> + (fx) * m_optLut[n111];
> +
> + out[1] =
> + (1 - fy) * m_optLut[n000 + 1] +
> + (fy - fz) * m_optLut[n010 + 1] +
> + (fz - fx) * m_optLut[n011 + 1] +
> + (fx) * m_optLut[n111 + 1];
> +
> + out[2] =
> + (1 - fy) * m_optLut[n000 + 2] +
> + (fy - fz) * m_optLut[n010 + 2] +
> + (fz - fx) * m_optLut[n011 + 2] +
> + (fx) * m_optLut[n111 + 2];
> + } else {
> + out[0] =
> + (1 - fy) * m_optLut[n000] +
> + (fy - fx) * m_optLut[n010] +
> + (fx - fz) * m_optLut[n110] +
> + (fz) * m_optLut[n111];
> +
> + out[1] =
> + (1 - fy) * m_optLut[n000 + 1] +
> + (fy - fx) * m_optLut[n010 + 1] +
> + (fx - fz) * m_optLut[n110 + 1] +
> + (fz) * m_optLut[n111 + 1];
> +
> + out[2] =
> + (1 - fy) * m_optLut[n000 + 2] +
> + (fy - fx) * m_optLut[n010 + 2] +
> + (fx - fz) * m_optLut[n110 + 2] +
> + (fz) * m_optLut[n111 + 2];
> + }
> + }
> +
> + pixel->r = out[0];
> + pixel->g = out[1];
> + pixel->b = out[2];
> +}
> +
> +void igt_color_3dlut_17_12_rgb(igt_pixel_t *pixel)
> +{
> + igt_color_3dlut_tetrahedral(pixel, &igt_3dlut_17_rgb, 17);
> +}
> +
> static void
> igt_color_fourcc_to_pixel(uint32_t raw_pixel, uint32_t drm_format, igt_pixel_t *pixel)
> {
> @@ -446,3 +624,11 @@ void igt_colorop_set_custom_1dlut(igt_display_t *display,
> {
> igt_colorop_replace_prop_blob(colorop, IGT_COLOROP_DATA, lut1d, lut_size);
> }
> +
> +void igt_colorop_set_3dlut(igt_display_t *display,
> + igt_colorop_t *colorop,
> + const igt_3dlut_norm_t *lut3d,
> + const size_t lut_size)
> +{
> + igt_colorop_replace_prop_blob(colorop, IGT_COLOROP_DATA, lut3d, lut_size);
> +}
> diff --git a/lib/igt_color.h b/lib/igt_color.h
> index 761dd2f95..0e1dc84e2 100644
> --- a/lib/igt_color.h
> +++ b/lib/igt_color.h
> @@ -16,6 +16,7 @@
>
> #include "igt_fb.h"
> #include "igt_kms.h"
> +#include "igt_color_lut.h"
>
> #define MAX_COLOR_LUT_ENTRIES 4096
>
> @@ -112,6 +113,12 @@ void igt_colorop_set_custom_1dlut(igt_display_t *display,
> const igt_1dlut_t *lut1d,
> const size_t lut_size);
>
> +void igt_colorop_set_3dlut(igt_display_t *display,
> + igt_colorop_t *colorop,
> + const igt_3dlut_norm_t *lut3d,
> + const size_t lut_size);
> +
> +
> /* transformations */
>
> void igt_color_srgb_inv_eotf(igt_pixel_t *pixel);
> @@ -136,4 +143,7 @@ void igt_color_ctm_3x4_bt709_enc(igt_pixel_t *pixel);
>
> void igt_color_multiply_125(igt_pixel_t *pixel);
> void igt_color_multiply_inv_125(igt_pixel_t *pixel);
> +void igt_color_3dlut_17_12_rgb(igt_pixel_t *pixel);
> +void igt_color_3dlut_17_12_bgr(igt_pixel_t *pixel);
> +
> #endif
> diff --git a/lib/igt_color_lut.h b/lib/igt_color_lut.h
> new file mode 100644
> index 000000000..b5c149c3d
> --- /dev/null
> +++ b/lib/igt_color_lut.h
> @@ -0,0 +1,4946 @@
> +/* SPDX-License-Identifier: MIT */
> +/*
> + * Copyright 2024 Advanced Micro Devices, Inc.
> + *
> + */
> +
> +#ifndef __IGT_COLOR_LUT_H__
> +#define __IGT_COLOR_LUT_H__
> +
> +#include "drm_mode.h"
> +
> +typedef struct igt_3dlut_norm {
> + struct drm_color_lut32 lut[4913];
> +} igt_3dlut_norm_t;
> +
> +struct igt_color_lut_float {
> + float red;
> + float green;
> + float blue;
> +};
> +
> +typedef struct igt_3dlut {
> + struct igt_color_lut_float lut[4913];
> +} igt_3dlut_t;
> +
> +/*
> + * A 3D LUT table with 17x17x17 entries for Traversal order RGB.
> + * It can be generated by scripts/convert_3dlut.py
> + */
> +igt_3dlut_t igt_3dlut_17_rgb = { {
This is pretty big, and assuming this doesn't need to be changed,
perhaps make it const so that it goes to .rodata
> + { .red = 0.000000, .green = 0.000000, .blue = 0.000000 },
> + { .red = 0.175580, .green = 0.003419, .blue = 0.006838 },
> + { .red = 0.338706, .green = 0.015140, .blue = 0.012454 },
> + { .red = 0.492552, .green = 0.015629, .blue = 0.012454 },
> + { .red = 0.641026, .green = 0.023687, .blue = 0.013187 },
> + { .red = 0.734310, .green = 0.049817, .blue = 0.013675 },
> + { .red = 0.809035, .green = 0.063736, .blue = 0.006105 },
> + { .red = 0.884982, .green = 0.063492, .blue = 0.019048 },
> + { .red = 0.963370, .green = 0.056899, .blue = 0.028571 },
> + { .red = 0.993407, .green = 0.080586, .blue = 0.044689 },
> + { .red = 0.999267, .green = 0.099145, .blue = 0.054457 },
> + { .red = 0.999267, .green = 0.110623, .blue = 0.060317 },
> + { .red = 0.999267, .green = 0.116972, .blue = 0.064225 },
> + { .red = 0.999267, .green = 0.121612, .blue = 0.066422 },
< snip >
More information about the igt-dev
mailing list