* [PATCH v2 00/12] drm/vkms: improve color curve LUTs precision
@ 2026-11-06 20:18 Leandro Ribeiro
2026-11-06 20:18 ` [PATCH v2 01/12] drm/vkms: rename VKMS_LUT_SIZE to VKMS_GAMMA_LUT_SIZE Leandro Ribeiro
` (11 more replies)
0 siblings, 12 replies; 13+ messages in thread
From: Leandro Ribeiro @ 2026-11-06 20:18 UTC (permalink / raw)
To: louis.chauvet
Cc: airlied, alex.hung, daniel, hamohammed.sa, harry.wentland,
maarten.lankhorst, melissa.srw, mripard, pekka.paalanen,
robert.mader, simona, tzimmermann, dri-devel, linux-kernel
Currently VKMS only supports uniform LUTs. Besides the userspace
provided LUTs, it also represents color curves with LUTs, as it can't
simply implement the continuous curve formulas (floating-point would be
required).
This adds support to represent color curves with non-uniform LUTs,
improving the precision significantly. It also provides a script
that can be used to create these LUTs.
The optimized LUTs use more samples in regions where the interpolation
and quantization errors are higher (usually in regions with a steeper
slope). The LUT generator script compares different strategies and uses
greedy subdivision, which outperformed the other methods, to generate
the optimized LUTs for VKMS.
For now, only the existing sRGB and inverse sRGB curves are replaced.
Support for more color curves will be added in future patchsets.
v2:
- Fixed a few minor issues spotted by Sashiko bot
- Added reviewed-by and tested-by tags
- Rebased
Leandro Ribeiro (12):
drm/vkms: rename VKMS_LUT_SIZE to VKMS_GAMMA_LUT_SIZE
vkms: properly compute gamma LUT size in vkms_atomic_check()
drm/vkms: allow color curve LUTs to have different sizes
drm/vkms: remove TEST_LUT_SIZE
drm/vkms: remove linear_eotf
drm/vkms: improve the way in which we access LUT member
drm/vkms: rename struct vkms_color_lut::base to y
drm/vkms: rename get_lut_index() to get_uniform_lut_index()
drm/vkms: add support to non-uniform LUT for internal color curves
drm/vkms: test sRGB and inverse sRGB LUTs using more samples
drm/vkms: add script to create optimized LUTs for color curves
drm/vkms: replace uniform sRGB LUT and its inverse with optimal ones
.../gpu/drm/vkms/scripts/color-curve-lut.py | 573 +++++++
drivers/gpu/drm/vkms/tests/vkms_color_test.c | 48 +-
drivers/gpu/drm/vkms/vkms_composer.c | 127 +-
drivers/gpu/drm/vkms/vkms_composer.h | 2 +-
drivers/gpu/drm/vkms/vkms_crtc.c | 4 +-
drivers/gpu/drm/vkms/vkms_drv.c | 4 +-
drivers/gpu/drm/vkms/vkms_drv.h | 13 +-
drivers/gpu/drm/vkms/vkms_luts.c | 1469 ++++++++---------
drivers/gpu/drm/vkms/vkms_luts.h | 3 -
9 files changed, 1397 insertions(+), 846 deletions(-)
create mode 100644 drivers/gpu/drm/vkms/scripts/color-curve-lut.py
--
2.56.0
^ permalink raw reply [flat|nested] 13+ messages in thread* [PATCH v2 01/12] drm/vkms: rename VKMS_LUT_SIZE to VKMS_GAMMA_LUT_SIZE 2026-11-06 20:18 [PATCH v2 00/12] drm/vkms: improve color curve LUTs precision Leandro Ribeiro @ 2026-11-06 20:18 ` Leandro Ribeiro 2026-11-06 20:18 ` [PATCH v2 02/12] vkms: properly compute gamma LUT size in vkms_atomic_check() Leandro Ribeiro ` (10 subsequent siblings) 11 siblings, 0 replies; 13+ messages in thread From: Leandro Ribeiro @ 2026-11-06 20:18 UTC (permalink / raw) To: louis.chauvet Cc: airlied, alex.hung, daniel, hamohammed.sa, harry.wentland, maarten.lankhorst, melissa.srw, mripard, pekka.paalanen, robert.mader, simona, tzimmermann, dri-devel, linux-kernel This is the size of the CRTC gamma LUT size. So let's specify this in the name. Reviewed-by: Robert Mader <robert.mader@collabora.com> Tested-by: Robert Mader <robert.mader@collabora.com> Signed-off-by: Leandro Ribeiro <leandro.ribeiro@collabora.com> --- drivers/gpu/drm/vkms/vkms_crtc.c | 4 ++-- drivers/gpu/drm/vkms/vkms_drv.c | 2 +- drivers/gpu/drm/vkms/vkms_drv.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/vkms/vkms_crtc.c b/drivers/gpu/drm/vkms/vkms_crtc.c index fe17f49305a9..019d7bc90cdc 100644 --- a/drivers/gpu/drm/vkms/vkms_crtc.c +++ b/drivers/gpu/drm/vkms/vkms_crtc.c @@ -222,13 +222,13 @@ struct vkms_output *vkms_crtc_init(struct drm_device *dev, struct drm_plane *pri drm_crtc_helper_add(crtc, &vkms_crtc_helper_funcs); - ret = drm_mode_crtc_set_gamma_size(crtc, VKMS_LUT_SIZE); + ret = drm_mode_crtc_set_gamma_size(crtc, VKMS_GAMMA_LUT_SIZE); if (ret) { DRM_ERROR("Failed to set gamma size\n"); return ERR_PTR(ret); } - drm_crtc_enable_color_mgmt(crtc, 0, false, VKMS_LUT_SIZE); + drm_crtc_enable_color_mgmt(crtc, 0, false, VKMS_GAMMA_LUT_SIZE); drm_crtc_attach_background_color_property(crtc); diff --git a/drivers/gpu/drm/vkms/vkms_drv.c b/drivers/gpu/drm/vkms/vkms_drv.c index 5a640b531d88..86a8a95694fd 100644 --- a/drivers/gpu/drm/vkms/vkms_drv.c +++ b/drivers/gpu/drm/vkms/vkms_drv.c @@ -113,7 +113,7 @@ static int vkms_atomic_check(struct drm_device *dev, struct drm_atomic_commit *s continue; if (new_crtc_state->gamma_lut->length / sizeof(struct drm_color_lut *) - > VKMS_LUT_SIZE) + > VKMS_GAMMA_LUT_SIZE) return -EINVAL; } diff --git a/drivers/gpu/drm/vkms/vkms_drv.h b/drivers/gpu/drm/vkms/vkms_drv.h index dea6cad3f1b9..34b855431af3 100644 --- a/drivers/gpu/drm/vkms/vkms_drv.h +++ b/drivers/gpu/drm/vkms/vkms_drv.h @@ -25,7 +25,7 @@ #define NUM_OVERLAY_PLANES 8 -#define VKMS_LUT_SIZE 256 +#define VKMS_GAMMA_LUT_SIZE 256 /** * struct vkms_frame_info - Structure to store the state of a frame -- 2.56.0 ^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH v2 02/12] vkms: properly compute gamma LUT size in vkms_atomic_check() 2026-11-06 20:18 [PATCH v2 00/12] drm/vkms: improve color curve LUTs precision Leandro Ribeiro 2026-11-06 20:18 ` [PATCH v2 01/12] drm/vkms: rename VKMS_LUT_SIZE to VKMS_GAMMA_LUT_SIZE Leandro Ribeiro @ 2026-11-06 20:18 ` Leandro Ribeiro 2026-11-06 20:18 ` [PATCH v2 03/12] drm/vkms: allow color curve LUTs to have different sizes Leandro Ribeiro ` (9 subsequent siblings) 11 siblings, 0 replies; 13+ messages in thread From: Leandro Ribeiro @ 2026-11-06 20:18 UTC (permalink / raw) To: louis.chauvet Cc: airlied, alex.hung, daniel, hamohammed.sa, harry.wentland, maarten.lankhorst, melissa.srw, mripard, pekka.paalanen, robert.mader, simona, tzimmermann, dri-devel, linux-kernel, Sashiko Gamma LUT size is being computed wrongly, dividing blob size by sizeof(struct drm_color_lut *). But the blob is an array of struct drm_color_lut. Replace sizeof(struct drm_color_lut *) with sizeof(struct drm_color_lut), properly validating the userspace gamma LUT size. Issue caught by Sashiko bot: https://sashiko.dev/#/patchset/20260804203351.148521-1-leandro.ribeiro@collabora.com?part=1 Reported-by: Sashiko <sashiko-bot@kernel.org> Reviewed-by: Robert Mader <robert.mader@collabora.com> Tested-by: Robert Mader <robert.mader@collabora.com> Signed-off-by: Leandro Ribeiro <leandro.ribeiro@collabora.com> --- drivers/gpu/drm/vkms/vkms_drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/vkms/vkms_drv.c b/drivers/gpu/drm/vkms/vkms_drv.c index 86a8a95694fd..28b99511f186 100644 --- a/drivers/gpu/drm/vkms/vkms_drv.c +++ b/drivers/gpu/drm/vkms/vkms_drv.c @@ -112,7 +112,7 @@ static int vkms_atomic_check(struct drm_device *dev, struct drm_atomic_commit *s if (!new_crtc_state->gamma_lut || !new_crtc_state->color_mgmt_changed) continue; - if (new_crtc_state->gamma_lut->length / sizeof(struct drm_color_lut *) + if (new_crtc_state->gamma_lut->length / sizeof(struct drm_color_lut) > VKMS_GAMMA_LUT_SIZE) return -EINVAL; } -- 2.56.0 ^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH v2 03/12] drm/vkms: allow color curve LUTs to have different sizes 2026-11-06 20:18 [PATCH v2 00/12] drm/vkms: improve color curve LUTs precision Leandro Ribeiro 2026-11-06 20:18 ` [PATCH v2 01/12] drm/vkms: rename VKMS_LUT_SIZE to VKMS_GAMMA_LUT_SIZE Leandro Ribeiro 2026-11-06 20:18 ` [PATCH v2 02/12] vkms: properly compute gamma LUT size in vkms_atomic_check() Leandro Ribeiro @ 2026-11-06 20:18 ` Leandro Ribeiro 2026-11-06 20:18 ` [PATCH v2 04/12] drm/vkms: remove TEST_LUT_SIZE Leandro Ribeiro ` (8 subsequent siblings) 11 siblings, 0 replies; 13+ messages in thread From: Leandro Ribeiro @ 2026-11-06 20:18 UTC (permalink / raw) To: louis.chauvet Cc: airlied, alex.hung, daniel, hamohammed.sa, harry.wentland, maarten.lankhorst, melissa.srw, mripard, pekka.paalanen, robert.mader, simona, tzimmermann, dri-devel, linux-kernel Instead of keeping a hardcoded size that all LUTs representing color curves must use, use ARRAY_SIZE() instead. Besides making the code clearer, this allows us to create optimal LUTs for each color curve, and each of them can naturally have a different size. In the next commits we introduce these optimal LUTs. Reviewed-by: Robert Mader <robert.mader@collabora.com> Tested-by: Robert Mader <robert.mader@collabora.com> Signed-off-by: Leandro Ribeiro <leandro.ribeiro@collabora.com> --- drivers/gpu/drm/vkms/tests/vkms_color_test.c | 4 ++-- drivers/gpu/drm/vkms/vkms_luts.c | 12 ++++++------ drivers/gpu/drm/vkms/vkms_luts.h | 2 -- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/vkms/tests/vkms_color_test.c b/drivers/gpu/drm/vkms/tests/vkms_color_test.c index 1a1c7cac2f15..18e73a8a5c31 100644 --- a/drivers/gpu/drm/vkms/tests/vkms_color_test.c +++ b/drivers/gpu/drm/vkms/tests/vkms_color_test.c @@ -128,7 +128,7 @@ static void vkms_color_test_lerp(struct kunit *test) static void vkms_color_test_linear(struct kunit *test) { - for (int i = 0; i < LUT_SIZE; i++) { + for (int i = 0; i < linear_eotf.lut_length; i++) { int linear = apply_lut_to_channel_value(&linear_eotf, i * 0x101, LUT_RED); KUNIT_EXPECT_EQ(test, DIV_ROUND_CLOSEST(linear, 0x101), i); @@ -139,7 +139,7 @@ static void vkms_color_srgb_inv_srgb(struct kunit *test) { u16 srgb, final; - for (int i = 0; i < LUT_SIZE; i++) { + for (int i = 0; i < srgb_eotf.lut_length; i++) { srgb = apply_lut_to_channel_value(&srgb_eotf, i * 0x101, LUT_RED); final = apply_lut_to_channel_value(&srgb_inv_eotf, srgb, LUT_RED); diff --git a/drivers/gpu/drm/vkms/vkms_luts.c b/drivers/gpu/drm/vkms/vkms_luts.c index 82cb792f10d8..6dcdef26bda8 100644 --- a/drivers/gpu/drm/vkms/vkms_luts.c +++ b/drivers/gpu/drm/vkms/vkms_luts.c @@ -12,7 +12,7 @@ * https://gitlab.freedesktop.org/hwentland/lutgen */ -static struct drm_color_lut linear_array[LUT_SIZE] = { +static struct drm_color_lut linear_array[] = { { 0x0, 0x0, 0x0, 0 }, { 0x101, 0x101, 0x101, 0 }, { 0x202, 0x202, 0x202, 0 }, @@ -273,12 +273,12 @@ static struct drm_color_lut linear_array[LUT_SIZE] = { const struct vkms_color_lut linear_eotf = { .base = linear_array, - .lut_length = LUT_SIZE, + .lut_length = ARRAY_SIZE(linear_array), .channel_value2index_ratio = 0xff00ffll }; EXPORT_SYMBOL(linear_eotf); -static struct drm_color_lut srgb_array[LUT_SIZE] = { +static struct drm_color_lut srgb_array[] = { { 0x0, 0x0, 0x0, 0 }, { 0x13, 0x13, 0x13, 0 }, { 0x27, 0x27, 0x27, 0 }, @@ -539,12 +539,12 @@ static struct drm_color_lut srgb_array[LUT_SIZE] = { const struct vkms_color_lut srgb_eotf = { .base = srgb_array, - .lut_length = LUT_SIZE, + .lut_length = ARRAY_SIZE(srgb_array), .channel_value2index_ratio = 0xff00ffll }; EXPORT_SYMBOL(srgb_eotf); -static struct drm_color_lut srgb_inv_array[LUT_SIZE] = { +static struct drm_color_lut srgb_inv_array[] = { { 0x0, 0x0, 0x0, 0 }, { 0xcc2, 0xcc2, 0xcc2, 0 }, { 0x15be, 0x15be, 0x15be, 0 }, @@ -805,7 +805,7 @@ static struct drm_color_lut srgb_inv_array[LUT_SIZE] = { const struct vkms_color_lut srgb_inv_eotf = { .base = srgb_inv_array, - .lut_length = LUT_SIZE, + .lut_length = ARRAY_SIZE(srgb_inv_array), .channel_value2index_ratio = 0xff00ffll }; EXPORT_SYMBOL(srgb_inv_eotf); diff --git a/drivers/gpu/drm/vkms/vkms_luts.h b/drivers/gpu/drm/vkms/vkms_luts.h index 925a4a7b84e2..8078ab33b83e 100644 --- a/drivers/gpu/drm/vkms/vkms_luts.h +++ b/drivers/gpu/drm/vkms/vkms_luts.h @@ -3,8 +3,6 @@ #ifndef _VKMS_LUTS_H_ #define _VKMS_LUTS_H_ -#define LUT_SIZE 256 - extern const struct vkms_color_lut linear_eotf; extern const struct vkms_color_lut srgb_eotf; extern const struct vkms_color_lut srgb_inv_eotf; -- 2.56.0 ^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH v2 04/12] drm/vkms: remove TEST_LUT_SIZE 2026-11-06 20:18 [PATCH v2 00/12] drm/vkms: improve color curve LUTs precision Leandro Ribeiro ` (2 preceding siblings ...) 2026-11-06 20:18 ` [PATCH v2 03/12] drm/vkms: allow color curve LUTs to have different sizes Leandro Ribeiro @ 2026-11-06 20:18 ` Leandro Ribeiro 2026-11-06 20:18 ` [PATCH v2 05/12] drm/vkms: remove linear_eotf Leandro Ribeiro ` (7 subsequent siblings) 11 siblings, 0 replies; 13+ messages in thread From: Leandro Ribeiro @ 2026-11-06 20:18 UTC (permalink / raw) To: louis.chauvet Cc: airlied, alex.hung, daniel, hamohammed.sa, harry.wentland, maarten.lankhorst, melissa.srw, mripard, pekka.paalanen, robert.mader, simona, tzimmermann, dri-devel, linux-kernel This can be replaced by ARRAY_SIZE(), so drop it. Reviewed-by: Robert Mader <robert.mader@collabora.com> Tested-by: Robert Mader <robert.mader@collabora.com> Signed-off-by: Leandro Ribeiro <leandro.ribeiro@collabora.com> --- drivers/gpu/drm/vkms/tests/vkms_color_test.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/vkms/tests/vkms_color_test.c b/drivers/gpu/drm/vkms/tests/vkms_color_test.c index 18e73a8a5c31..3489513af352 100644 --- a/drivers/gpu/drm/vkms/tests/vkms_color_test.c +++ b/drivers/gpu/drm/vkms/tests/vkms_color_test.c @@ -8,11 +8,9 @@ #include "../vkms_drv.h" #include "../vkms_luts.h" -#define TEST_LUT_SIZE 16 - MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING"); -static struct drm_color_lut test_linear_array[TEST_LUT_SIZE] = { +static struct drm_color_lut test_linear_array[] = { { 0x0, 0x0, 0x0, 0 }, { 0x1111, 0x1111, 0x1111, 0 }, { 0x2222, 0x2222, 0x2222, 0 }, @@ -84,7 +82,7 @@ static const struct vkms_color_test_lerp_params color_test_lerp_cases[] = { static const struct vkms_color_lut test_linear_lut = { .base = test_linear_array, - .lut_length = TEST_LUT_SIZE, + .lut_length = ARRAY_SIZE(test_linear_array), .channel_value2index_ratio = 0xf000fll }; @@ -96,7 +94,7 @@ static void vkms_color_test_get_lut_index(struct kunit *test) lut_index = get_lut_index(&test_linear_lut, test_linear_array[0].red); KUNIT_EXPECT_EQ(test, drm_fixp2int(lut_index), 0); - for (i = 0; i < TEST_LUT_SIZE; i++) { + for (i = 0; i < test_linear_lut.lut_length; i++) { lut_index = get_lut_index(&test_linear_lut, test_linear_array[i].red); KUNIT_EXPECT_EQ(test, drm_fixp2int_ceil(lut_index), i); } -- 2.56.0 ^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH v2 05/12] drm/vkms: remove linear_eotf 2026-11-06 20:18 [PATCH v2 00/12] drm/vkms: improve color curve LUTs precision Leandro Ribeiro ` (3 preceding siblings ...) 2026-11-06 20:18 ` [PATCH v2 04/12] drm/vkms: remove TEST_LUT_SIZE Leandro Ribeiro @ 2026-11-06 20:18 ` Leandro Ribeiro 2026-11-06 20:18 ` [PATCH v2 06/12] drm/vkms: improve the way in which we access LUT member Leandro Ribeiro ` (6 subsequent siblings) 11 siblings, 0 replies; 13+ messages in thread From: Leandro Ribeiro @ 2026-11-06 20:18 UTC (permalink / raw) To: louis.chauvet Cc: airlied, alex.hung, daniel, hamohammed.sa, harry.wentland, maarten.lankhorst, melissa.srw, mripard, pekka.paalanen, robert.mader, simona, tzimmermann, dri-devel, linux-kernel This is being used only for testing purposes. We can have a similar test using test_linear_lut, so let's drop it. test_linear_lut has fewer taps than linear_eotf (16 versus 256), but that is enough here because the test only evaluates values corresponding to LUT entries, so interpolation between LUT entries is not being exercised. In the next commits we change the tests to exercise apply_lut_to_channel_value() in a more relevant way. v2: - Address feedback from Sashiko bot: in the previous version, I forgot to update the multiplier. https://sashiko.dev/#/patchset/20260804203351.148521-1-leandro.ribeiro@collabora.com?part=4 Reviewed-by: Robert Mader <robert.mader@collabora.com> Tested-by: Robert Mader <robert.mader@collabora.com> Signed-off-by: Leandro Ribeiro <leandro.ribeiro@collabora.com> --- drivers/gpu/drm/vkms/tests/vkms_color_test.c | 6 +- drivers/gpu/drm/vkms/vkms_luts.c | 266 ------------------- drivers/gpu/drm/vkms/vkms_luts.h | 1 - 3 files changed, 3 insertions(+), 270 deletions(-) diff --git a/drivers/gpu/drm/vkms/tests/vkms_color_test.c b/drivers/gpu/drm/vkms/tests/vkms_color_test.c index 3489513af352..83ef2afcc819 100644 --- a/drivers/gpu/drm/vkms/tests/vkms_color_test.c +++ b/drivers/gpu/drm/vkms/tests/vkms_color_test.c @@ -126,10 +126,10 @@ static void vkms_color_test_lerp(struct kunit *test) static void vkms_color_test_linear(struct kunit *test) { - for (int i = 0; i < linear_eotf.lut_length; i++) { - int linear = apply_lut_to_channel_value(&linear_eotf, i * 0x101, LUT_RED); + for (int i = 0; i < test_linear_lut.lut_length; i++) { + int linear = apply_lut_to_channel_value(&test_linear_lut, i * 0x1111, LUT_RED); - KUNIT_EXPECT_EQ(test, DIV_ROUND_CLOSEST(linear, 0x101), i); + KUNIT_EXPECT_EQ(test, DIV_ROUND_CLOSEST(linear, 0x1111), i); } } diff --git a/drivers/gpu/drm/vkms/vkms_luts.c b/drivers/gpu/drm/vkms/vkms_luts.c index 6dcdef26bda8..d0e96df2c120 100644 --- a/drivers/gpu/drm/vkms/vkms_luts.c +++ b/drivers/gpu/drm/vkms/vkms_luts.c @@ -12,272 +12,6 @@ * https://gitlab.freedesktop.org/hwentland/lutgen */ -static struct drm_color_lut linear_array[] = { - { 0x0, 0x0, 0x0, 0 }, - { 0x101, 0x101, 0x101, 0 }, - { 0x202, 0x202, 0x202, 0 }, - { 0x303, 0x303, 0x303, 0 }, - { 0x404, 0x404, 0x404, 0 }, - { 0x505, 0x505, 0x505, 0 }, - { 0x606, 0x606, 0x606, 0 }, - { 0x707, 0x707, 0x707, 0 }, - { 0x808, 0x808, 0x808, 0 }, - { 0x909, 0x909, 0x909, 0 }, - { 0xa0a, 0xa0a, 0xa0a, 0 }, - { 0xb0b, 0xb0b, 0xb0b, 0 }, - { 0xc0c, 0xc0c, 0xc0c, 0 }, - { 0xd0d, 0xd0d, 0xd0d, 0 }, - { 0xe0e, 0xe0e, 0xe0e, 0 }, - { 0xf0f, 0xf0f, 0xf0f, 0 }, - { 0x1010, 0x1010, 0x1010, 0 }, - { 0x1111, 0x1111, 0x1111, 0 }, - { 0x1212, 0x1212, 0x1212, 0 }, - { 0x1313, 0x1313, 0x1313, 0 }, - { 0x1414, 0x1414, 0x1414, 0 }, - { 0x1515, 0x1515, 0x1515, 0 }, - { 0x1616, 0x1616, 0x1616, 0 }, - { 0x1717, 0x1717, 0x1717, 0 }, - { 0x1818, 0x1818, 0x1818, 0 }, - { 0x1919, 0x1919, 0x1919, 0 }, - { 0x1a1a, 0x1a1a, 0x1a1a, 0 }, - { 0x1b1b, 0x1b1b, 0x1b1b, 0 }, - { 0x1c1c, 0x1c1c, 0x1c1c, 0 }, - { 0x1d1d, 0x1d1d, 0x1d1d, 0 }, - { 0x1e1e, 0x1e1e, 0x1e1e, 0 }, - { 0x1f1f, 0x1f1f, 0x1f1f, 0 }, - { 0x2020, 0x2020, 0x2020, 0 }, - { 0x2121, 0x2121, 0x2121, 0 }, - { 0x2222, 0x2222, 0x2222, 0 }, - { 0x2323, 0x2323, 0x2323, 0 }, - { 0x2424, 0x2424, 0x2424, 0 }, - { 0x2525, 0x2525, 0x2525, 0 }, - { 0x2626, 0x2626, 0x2626, 0 }, - { 0x2727, 0x2727, 0x2727, 0 }, - { 0x2828, 0x2828, 0x2828, 0 }, - { 0x2929, 0x2929, 0x2929, 0 }, - { 0x2a2a, 0x2a2a, 0x2a2a, 0 }, - { 0x2b2b, 0x2b2b, 0x2b2b, 0 }, - { 0x2c2c, 0x2c2c, 0x2c2c, 0 }, - { 0x2d2d, 0x2d2d, 0x2d2d, 0 }, - { 0x2e2e, 0x2e2e, 0x2e2e, 0 }, - { 0x2f2f, 0x2f2f, 0x2f2f, 0 }, - { 0x3030, 0x3030, 0x3030, 0 }, - { 0x3131, 0x3131, 0x3131, 0 }, - { 0x3232, 0x3232, 0x3232, 0 }, - { 0x3333, 0x3333, 0x3333, 0 }, - { 0x3434, 0x3434, 0x3434, 0 }, - { 0x3535, 0x3535, 0x3535, 0 }, - { 0x3636, 0x3636, 0x3636, 0 }, - { 0x3737, 0x3737, 0x3737, 0 }, - { 0x3838, 0x3838, 0x3838, 0 }, - { 0x3939, 0x3939, 0x3939, 0 }, - { 0x3a3a, 0x3a3a, 0x3a3a, 0 }, - { 0x3b3b, 0x3b3b, 0x3b3b, 0 }, - { 0x3c3c, 0x3c3c, 0x3c3c, 0 }, - { 0x3d3d, 0x3d3d, 0x3d3d, 0 }, - { 0x3e3e, 0x3e3e, 0x3e3e, 0 }, - { 0x3f3f, 0x3f3f, 0x3f3f, 0 }, - { 0x4040, 0x4040, 0x4040, 0 }, - { 0x4141, 0x4141, 0x4141, 0 }, - { 0x4242, 0x4242, 0x4242, 0 }, - { 0x4343, 0x4343, 0x4343, 0 }, - { 0x4444, 0x4444, 0x4444, 0 }, - { 0x4545, 0x4545, 0x4545, 0 }, - { 0x4646, 0x4646, 0x4646, 0 }, - { 0x4747, 0x4747, 0x4747, 0 }, - { 0x4848, 0x4848, 0x4848, 0 }, - { 0x4949, 0x4949, 0x4949, 0 }, - { 0x4a4a, 0x4a4a, 0x4a4a, 0 }, - { 0x4b4b, 0x4b4b, 0x4b4b, 0 }, - { 0x4c4c, 0x4c4c, 0x4c4c, 0 }, - { 0x4d4d, 0x4d4d, 0x4d4d, 0 }, - { 0x4e4e, 0x4e4e, 0x4e4e, 0 }, - { 0x4f4f, 0x4f4f, 0x4f4f, 0 }, - { 0x5050, 0x5050, 0x5050, 0 }, - { 0x5151, 0x5151, 0x5151, 0 }, - { 0x5252, 0x5252, 0x5252, 0 }, - { 0x5353, 0x5353, 0x5353, 0 }, - { 0x5454, 0x5454, 0x5454, 0 }, - { 0x5555, 0x5555, 0x5555, 0 }, - { 0x5656, 0x5656, 0x5656, 0 }, - { 0x5757, 0x5757, 0x5757, 0 }, - { 0x5858, 0x5858, 0x5858, 0 }, - { 0x5959, 0x5959, 0x5959, 0 }, - { 0x5a5a, 0x5a5a, 0x5a5a, 0 }, - { 0x5b5b, 0x5b5b, 0x5b5b, 0 }, - { 0x5c5c, 0x5c5c, 0x5c5c, 0 }, - { 0x5d5d, 0x5d5d, 0x5d5d, 0 }, - { 0x5e5e, 0x5e5e, 0x5e5e, 0 }, - { 0x5f5f, 0x5f5f, 0x5f5f, 0 }, - { 0x6060, 0x6060, 0x6060, 0 }, - { 0x6161, 0x6161, 0x6161, 0 }, - { 0x6262, 0x6262, 0x6262, 0 }, - { 0x6363, 0x6363, 0x6363, 0 }, - { 0x6464, 0x6464, 0x6464, 0 }, - { 0x6565, 0x6565, 0x6565, 0 }, - { 0x6666, 0x6666, 0x6666, 0 }, - { 0x6767, 0x6767, 0x6767, 0 }, - { 0x6868, 0x6868, 0x6868, 0 }, - { 0x6969, 0x6969, 0x6969, 0 }, - { 0x6a6a, 0x6a6a, 0x6a6a, 0 }, - { 0x6b6b, 0x6b6b, 0x6b6b, 0 }, - { 0x6c6c, 0x6c6c, 0x6c6c, 0 }, - { 0x6d6d, 0x6d6d, 0x6d6d, 0 }, - { 0x6e6e, 0x6e6e, 0x6e6e, 0 }, - { 0x6f6f, 0x6f6f, 0x6f6f, 0 }, - { 0x7070, 0x7070, 0x7070, 0 }, - { 0x7171, 0x7171, 0x7171, 0 }, - { 0x7272, 0x7272, 0x7272, 0 }, - { 0x7373, 0x7373, 0x7373, 0 }, - { 0x7474, 0x7474, 0x7474, 0 }, - { 0x7575, 0x7575, 0x7575, 0 }, - { 0x7676, 0x7676, 0x7676, 0 }, - { 0x7777, 0x7777, 0x7777, 0 }, - { 0x7878, 0x7878, 0x7878, 0 }, - { 0x7979, 0x7979, 0x7979, 0 }, - { 0x7a7a, 0x7a7a, 0x7a7a, 0 }, - { 0x7b7b, 0x7b7b, 0x7b7b, 0 }, - { 0x7c7c, 0x7c7c, 0x7c7c, 0 }, - { 0x7d7d, 0x7d7d, 0x7d7d, 0 }, - { 0x7e7e, 0x7e7e, 0x7e7e, 0 }, - { 0x7f7f, 0x7f7f, 0x7f7f, 0 }, - { 0x8080, 0x8080, 0x8080, 0 }, - { 0x8181, 0x8181, 0x8181, 0 }, - { 0x8282, 0x8282, 0x8282, 0 }, - { 0x8383, 0x8383, 0x8383, 0 }, - { 0x8484, 0x8484, 0x8484, 0 }, - { 0x8585, 0x8585, 0x8585, 0 }, - { 0x8686, 0x8686, 0x8686, 0 }, - { 0x8787, 0x8787, 0x8787, 0 }, - { 0x8888, 0x8888, 0x8888, 0 }, - { 0x8989, 0x8989, 0x8989, 0 }, - { 0x8a8a, 0x8a8a, 0x8a8a, 0 }, - { 0x8b8b, 0x8b8b, 0x8b8b, 0 }, - { 0x8c8c, 0x8c8c, 0x8c8c, 0 }, - { 0x8d8d, 0x8d8d, 0x8d8d, 0 }, - { 0x8e8e, 0x8e8e, 0x8e8e, 0 }, - { 0x8f8f, 0x8f8f, 0x8f8f, 0 }, - { 0x9090, 0x9090, 0x9090, 0 }, - { 0x9191, 0x9191, 0x9191, 0 }, - { 0x9292, 0x9292, 0x9292, 0 }, - { 0x9393, 0x9393, 0x9393, 0 }, - { 0x9494, 0x9494, 0x9494, 0 }, - { 0x9595, 0x9595, 0x9595, 0 }, - { 0x9696, 0x9696, 0x9696, 0 }, - { 0x9797, 0x9797, 0x9797, 0 }, - { 0x9898, 0x9898, 0x9898, 0 }, - { 0x9999, 0x9999, 0x9999, 0 }, - { 0x9a9a, 0x9a9a, 0x9a9a, 0 }, - { 0x9b9b, 0x9b9b, 0x9b9b, 0 }, - { 0x9c9c, 0x9c9c, 0x9c9c, 0 }, - { 0x9d9d, 0x9d9d, 0x9d9d, 0 }, - { 0x9e9e, 0x9e9e, 0x9e9e, 0 }, - { 0x9f9f, 0x9f9f, 0x9f9f, 0 }, - { 0xa0a0, 0xa0a0, 0xa0a0, 0 }, - { 0xa1a1, 0xa1a1, 0xa1a1, 0 }, - { 0xa2a2, 0xa2a2, 0xa2a2, 0 }, - { 0xa3a3, 0xa3a3, 0xa3a3, 0 }, - { 0xa4a4, 0xa4a4, 0xa4a4, 0 }, - { 0xa5a5, 0xa5a5, 0xa5a5, 0 }, - { 0xa6a6, 0xa6a6, 0xa6a6, 0 }, - { 0xa7a7, 0xa7a7, 0xa7a7, 0 }, - { 0xa8a8, 0xa8a8, 0xa8a8, 0 }, - { 0xa9a9, 0xa9a9, 0xa9a9, 0 }, - { 0xaaaa, 0xaaaa, 0xaaaa, 0 }, - { 0xabab, 0xabab, 0xabab, 0 }, - { 0xacac, 0xacac, 0xacac, 0 }, - { 0xadad, 0xadad, 0xadad, 0 }, - { 0xaeae, 0xaeae, 0xaeae, 0 }, - { 0xafaf, 0xafaf, 0xafaf, 0 }, - { 0xb0b0, 0xb0b0, 0xb0b0, 0 }, - { 0xb1b1, 0xb1b1, 0xb1b1, 0 }, - { 0xb2b2, 0xb2b2, 0xb2b2, 0 }, - { 0xb3b3, 0xb3b3, 0xb3b3, 0 }, - { 0xb4b4, 0xb4b4, 0xb4b4, 0 }, - { 0xb5b5, 0xb5b5, 0xb5b5, 0 }, - { 0xb6b6, 0xb6b6, 0xb6b6, 0 }, - { 0xb7b7, 0xb7b7, 0xb7b7, 0 }, - { 0xb8b8, 0xb8b8, 0xb8b8, 0 }, - { 0xb9b9, 0xb9b9, 0xb9b9, 0 }, - { 0xbaba, 0xbaba, 0xbaba, 0 }, - { 0xbbbb, 0xbbbb, 0xbbbb, 0 }, - { 0xbcbc, 0xbcbc, 0xbcbc, 0 }, - { 0xbdbd, 0xbdbd, 0xbdbd, 0 }, - { 0xbebe, 0xbebe, 0xbebe, 0 }, - { 0xbfbf, 0xbfbf, 0xbfbf, 0 }, - { 0xc0c0, 0xc0c0, 0xc0c0, 0 }, - { 0xc1c1, 0xc1c1, 0xc1c1, 0 }, - { 0xc2c2, 0xc2c2, 0xc2c2, 0 }, - { 0xc3c3, 0xc3c3, 0xc3c3, 0 }, - { 0xc4c4, 0xc4c4, 0xc4c4, 0 }, - { 0xc5c5, 0xc5c5, 0xc5c5, 0 }, - { 0xc6c6, 0xc6c6, 0xc6c6, 0 }, - { 0xc7c7, 0xc7c7, 0xc7c7, 0 }, - { 0xc8c8, 0xc8c8, 0xc8c8, 0 }, - { 0xc9c9, 0xc9c9, 0xc9c9, 0 }, - { 0xcaca, 0xcaca, 0xcaca, 0 }, - { 0xcbcb, 0xcbcb, 0xcbcb, 0 }, - { 0xcccc, 0xcccc, 0xcccc, 0 }, - { 0xcdcd, 0xcdcd, 0xcdcd, 0 }, - { 0xcece, 0xcece, 0xcece, 0 }, - { 0xcfcf, 0xcfcf, 0xcfcf, 0 }, - { 0xd0d0, 0xd0d0, 0xd0d0, 0 }, - { 0xd1d1, 0xd1d1, 0xd1d1, 0 }, - { 0xd2d2, 0xd2d2, 0xd2d2, 0 }, - { 0xd3d3, 0xd3d3, 0xd3d3, 0 }, - { 0xd4d4, 0xd4d4, 0xd4d4, 0 }, - { 0xd5d5, 0xd5d5, 0xd5d5, 0 }, - { 0xd6d6, 0xd6d6, 0xd6d6, 0 }, - { 0xd7d7, 0xd7d7, 0xd7d7, 0 }, - { 0xd8d8, 0xd8d8, 0xd8d8, 0 }, - { 0xd9d9, 0xd9d9, 0xd9d9, 0 }, - { 0xdada, 0xdada, 0xdada, 0 }, - { 0xdbdb, 0xdbdb, 0xdbdb, 0 }, - { 0xdcdc, 0xdcdc, 0xdcdc, 0 }, - { 0xdddd, 0xdddd, 0xdddd, 0 }, - { 0xdede, 0xdede, 0xdede, 0 }, - { 0xdfdf, 0xdfdf, 0xdfdf, 0 }, - { 0xe0e0, 0xe0e0, 0xe0e0, 0 }, - { 0xe1e1, 0xe1e1, 0xe1e1, 0 }, - { 0xe2e2, 0xe2e2, 0xe2e2, 0 }, - { 0xe3e3, 0xe3e3, 0xe3e3, 0 }, - { 0xe4e4, 0xe4e4, 0xe4e4, 0 }, - { 0xe5e5, 0xe5e5, 0xe5e5, 0 }, - { 0xe6e6, 0xe6e6, 0xe6e6, 0 }, - { 0xe7e7, 0xe7e7, 0xe7e7, 0 }, - { 0xe8e8, 0xe8e8, 0xe8e8, 0 }, - { 0xe9e9, 0xe9e9, 0xe9e9, 0 }, - { 0xeaea, 0xeaea, 0xeaea, 0 }, - { 0xebeb, 0xebeb, 0xebeb, 0 }, - { 0xecec, 0xecec, 0xecec, 0 }, - { 0xeded, 0xeded, 0xeded, 0 }, - { 0xeeee, 0xeeee, 0xeeee, 0 }, - { 0xefef, 0xefef, 0xefef, 0 }, - { 0xf0f0, 0xf0f0, 0xf0f0, 0 }, - { 0xf1f1, 0xf1f1, 0xf1f1, 0 }, - { 0xf2f2, 0xf2f2, 0xf2f2, 0 }, - { 0xf3f3, 0xf3f3, 0xf3f3, 0 }, - { 0xf4f4, 0xf4f4, 0xf4f4, 0 }, - { 0xf5f5, 0xf5f5, 0xf5f5, 0 }, - { 0xf6f6, 0xf6f6, 0xf6f6, 0 }, - { 0xf7f7, 0xf7f7, 0xf7f7, 0 }, - { 0xf8f8, 0xf8f8, 0xf8f8, 0 }, - { 0xf9f9, 0xf9f9, 0xf9f9, 0 }, - { 0xfafa, 0xfafa, 0xfafa, 0 }, - { 0xfbfb, 0xfbfb, 0xfbfb, 0 }, - { 0xfcfc, 0xfcfc, 0xfcfc, 0 }, - { 0xfdfd, 0xfdfd, 0xfdfd, 0 }, - { 0xfefe, 0xfefe, 0xfefe, 0 }, - { 0xffff, 0xffff, 0xffff, 0 }, -}; - -const struct vkms_color_lut linear_eotf = { - .base = linear_array, - .lut_length = ARRAY_SIZE(linear_array), - .channel_value2index_ratio = 0xff00ffll -}; -EXPORT_SYMBOL(linear_eotf); - static struct drm_color_lut srgb_array[] = { { 0x0, 0x0, 0x0, 0 }, { 0x13, 0x13, 0x13, 0 }, diff --git a/drivers/gpu/drm/vkms/vkms_luts.h b/drivers/gpu/drm/vkms/vkms_luts.h index 8078ab33b83e..655e9553cd91 100644 --- a/drivers/gpu/drm/vkms/vkms_luts.h +++ b/drivers/gpu/drm/vkms/vkms_luts.h @@ -3,7 +3,6 @@ #ifndef _VKMS_LUTS_H_ #define _VKMS_LUTS_H_ -extern const struct vkms_color_lut linear_eotf; extern const struct vkms_color_lut srgb_eotf; extern const struct vkms_color_lut srgb_inv_eotf; -- 2.56.0 ^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH v2 06/12] drm/vkms: improve the way in which we access LUT member 2026-11-06 20:18 [PATCH v2 00/12] drm/vkms: improve color curve LUTs precision Leandro Ribeiro ` (4 preceding siblings ...) 2026-11-06 20:18 ` [PATCH v2 05/12] drm/vkms: remove linear_eotf Leandro Ribeiro @ 2026-11-06 20:18 ` Leandro Ribeiro 2026-11-06 20:18 ` [PATCH v2 07/12] drm/vkms: rename struct vkms_color_lut::base to y Leandro Ribeiro ` (5 subsequent siblings) 11 siblings, 0 replies; 13+ messages in thread From: Leandro Ribeiro @ 2026-11-06 20:18 UTC (permalink / raw) To: louis.chauvet Cc: airlied, alex.hung, daniel, hamohammed.sa, harry.wentland, maarten.lankhorst, melissa.srw, mripard, pekka.paalanen, robert.mader, simona, tzimmermann, dri-devel, linux-kernel apply_lut_to_channel_value() indexes a struct drm_color_lut array, and then cast to (__u16 *) and index with the channel (r -> index 0, g -> index 1, b -> index 2). This is a bit fragile and prone to issues. Instead, add a more robust helper lut_channel_value() such that, given a struct drm_color_lut and a color channel, it retrives the value. Reviewed-by: Robert Mader <robert.mader@collabora.com> Tested-by: Robert Mader <robert.mader@collabora.com> Signed-off-by: Leandro Ribeiro <leandro.ribeiro@collabora.com> --- drivers/gpu/drm/vkms/vkms_composer.c | 30 ++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/vkms/vkms_composer.c b/drivers/gpu/drm/vkms/vkms_composer.c index 0fc915a954ba..b4a433be1b2d 100644 --- a/drivers/gpu/drm/vkms/vkms_composer.c +++ b/drivers/gpu/drm/vkms/vkms_composer.c @@ -75,6 +75,24 @@ VISIBLE_IF_KUNIT u16 lerp_u16(u16 a, u16 b, s64 t) } EXPORT_SYMBOL_IF_KUNIT(lerp_u16); +static inline u16 lut_channel_value(const struct drm_color_lut *lut, + enum lut_channel channel) +{ + switch (channel) { + case LUT_RED: + return lut->red; + case LUT_BLUE: + return lut->blue; + case LUT_GREEN: + return lut->green; + case LUT_RESERVED: + DRM_DEBUG_DRIVER("LUT_RESERVED channel should not be accessed"); + return 0; + } + DRM_DEBUG_DRIVER("unknown LUT channel"); + return 0; +} + VISIBLE_IF_KUNIT s64 get_lut_index(const struct vkms_color_lut *lut, u16 channel_value) { s64 color_channel_fp = drm_int2fixp(channel_value); @@ -86,8 +104,8 @@ EXPORT_SYMBOL_IF_KUNIT(get_lut_index); VISIBLE_IF_KUNIT u16 apply_lut_to_channel_value(const struct vkms_color_lut *lut, u16 channel_value, enum lut_channel channel) { + const struct drm_color_lut *lut_y_floor, *lut_y_ceil; s64 lut_index = get_lut_index(lut, channel_value); - u16 *floor_lut_value, *ceil_lut_value; u16 floor_channel_value, ceil_channel_value; /* @@ -96,15 +114,15 @@ VISIBLE_IF_KUNIT u16 apply_lut_to_channel_value(const struct vkms_color_lut *lut */ static_assert(sizeof(struct drm_color_lut) == sizeof(__u16) * 4); - floor_lut_value = (__u16 *)&lut->base[drm_fixp2int(lut_index)]; + lut_y_floor = &lut->base[drm_fixp2int(lut_index)]; if (drm_fixp2int(lut_index) == (lut->lut_length - 1)) /* We're at the end of the LUT array, use same value for ceil and floor */ - ceil_lut_value = floor_lut_value; + lut_y_ceil = lut_y_floor; else - ceil_lut_value = (__u16 *)&lut->base[drm_fixp2int_ceil(lut_index)]; + lut_y_ceil = &lut->base[drm_fixp2int_ceil(lut_index)]; - floor_channel_value = floor_lut_value[channel]; - ceil_channel_value = ceil_lut_value[channel]; + floor_channel_value = lut_channel_value(lut_y_floor, channel); + ceil_channel_value = lut_channel_value(lut_y_ceil, channel); return lerp_u16(floor_channel_value, ceil_channel_value, lut_index & DRM_FIXED_DECIMAL_MASK); -- 2.56.0 ^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH v2 07/12] drm/vkms: rename struct vkms_color_lut::base to y 2026-11-06 20:18 [PATCH v2 00/12] drm/vkms: improve color curve LUTs precision Leandro Ribeiro ` (5 preceding siblings ...) 2026-11-06 20:18 ` [PATCH v2 06/12] drm/vkms: improve the way in which we access LUT member Leandro Ribeiro @ 2026-11-06 20:18 ` Leandro Ribeiro 2026-11-06 20:18 ` [PATCH v2 08/12] drm/vkms: rename get_lut_index() to get_uniform_lut_index() Leandro Ribeiro ` (4 subsequent siblings) 11 siblings, 0 replies; 13+ messages in thread From: Leandro Ribeiro @ 2026-11-06 20:18 UTC (permalink / raw) To: louis.chauvet Cc: airlied, alex.hung, daniel, hamohammed.sa, harry.wentland, maarten.lankhorst, melissa.srw, mripard, pekka.paalanen, robert.mader, simona, tzimmermann, dri-devel, linux-kernel No behavior change. In the following commits we'll add x, so y better matches that. Reviewed-by: Robert Mader <robert.mader@collabora.com> Tested-by: Robert Mader <robert.mader@collabora.com> Signed-off-by: Leandro Ribeiro <leandro.ribeiro@collabora.com> --- drivers/gpu/drm/vkms/tests/vkms_color_test.c | 2 +- drivers/gpu/drm/vkms/vkms_composer.c | 10 +++++----- drivers/gpu/drm/vkms/vkms_drv.h | 2 +- drivers/gpu/drm/vkms/vkms_luts.c | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/vkms/tests/vkms_color_test.c b/drivers/gpu/drm/vkms/tests/vkms_color_test.c index 83ef2afcc819..c223797a542a 100644 --- a/drivers/gpu/drm/vkms/tests/vkms_color_test.c +++ b/drivers/gpu/drm/vkms/tests/vkms_color_test.c @@ -81,7 +81,7 @@ static const struct vkms_color_test_lerp_params color_test_lerp_cases[] = { }; static const struct vkms_color_lut test_linear_lut = { - .base = test_linear_array, + .y = test_linear_array, .lut_length = ARRAY_SIZE(test_linear_array), .channel_value2index_ratio = 0xf000fll }; diff --git a/drivers/gpu/drm/vkms/vkms_composer.c b/drivers/gpu/drm/vkms/vkms_composer.c index b4a433be1b2d..640a1a03f06f 100644 --- a/drivers/gpu/drm/vkms/vkms_composer.c +++ b/drivers/gpu/drm/vkms/vkms_composer.c @@ -114,12 +114,12 @@ VISIBLE_IF_KUNIT u16 apply_lut_to_channel_value(const struct vkms_color_lut *lut */ static_assert(sizeof(struct drm_color_lut) == sizeof(__u16) * 4); - lut_y_floor = &lut->base[drm_fixp2int(lut_index)]; + lut_y_floor = &lut->y[drm_fixp2int(lut_index)]; if (drm_fixp2int(lut_index) == (lut->lut_length - 1)) /* We're at the end of the LUT array, use same value for ceil and floor */ lut_y_ceil = lut_y_floor; else - lut_y_ceil = &lut->base[drm_fixp2int_ceil(lut_index)]; + lut_y_ceil = &lut->y[drm_fixp2int_ceil(lut_index)]; floor_channel_value = lut_channel_value(lut_y_floor, channel); ceil_channel_value = lut_channel_value(lut_y_ceil, channel); @@ -132,7 +132,7 @@ EXPORT_SYMBOL_IF_KUNIT(apply_lut_to_channel_value); static void apply_lut(const struct vkms_crtc_state *crtc_state, struct line_buffer *output_buffer) { - if (!crtc_state->gamma_lut.base) + if (!crtc_state->gamma_lut.y) return; if (!crtc_state->gamma_lut.lut_length) @@ -647,7 +647,7 @@ void vkms_composer_worker(struct work_struct *work) s64 max_lut_index_fp; s64 u16_max_fp = drm_int2fixp(0xffff); - crtc_state->gamma_lut.base = (struct drm_color_lut *)crtc->state->gamma_lut->data; + crtc_state->gamma_lut.y = (struct drm_color_lut *)crtc->state->gamma_lut->data; crtc_state->gamma_lut.lut_length = crtc->state->gamma_lut->length / sizeof(struct drm_color_lut); max_lut_index_fp = drm_int2fixp(crtc_state->gamma_lut.lut_length - 1); @@ -655,7 +655,7 @@ void vkms_composer_worker(struct work_struct *work) u16_max_fp); } else { - crtc_state->gamma_lut.base = NULL; + crtc_state->gamma_lut.y = NULL; } spin_unlock_irq(&out->composer_lock); diff --git a/drivers/gpu/drm/vkms/vkms_drv.h b/drivers/gpu/drm/vkms/vkms_drv.h index 34b855431af3..cdcf7a79697b 100644 --- a/drivers/gpu/drm/vkms/vkms_drv.h +++ b/drivers/gpu/drm/vkms/vkms_drv.h @@ -159,7 +159,7 @@ struct vkms_plane { }; struct vkms_color_lut { - struct drm_color_lut *base; + struct drm_color_lut *y; size_t lut_length; s64 channel_value2index_ratio; }; diff --git a/drivers/gpu/drm/vkms/vkms_luts.c b/drivers/gpu/drm/vkms/vkms_luts.c index d0e96df2c120..7b0c8eaf83b8 100644 --- a/drivers/gpu/drm/vkms/vkms_luts.c +++ b/drivers/gpu/drm/vkms/vkms_luts.c @@ -272,7 +272,7 @@ static struct drm_color_lut srgb_array[] = { }; const struct vkms_color_lut srgb_eotf = { - .base = srgb_array, + .y = srgb_array, .lut_length = ARRAY_SIZE(srgb_array), .channel_value2index_ratio = 0xff00ffll }; @@ -538,7 +538,7 @@ static struct drm_color_lut srgb_inv_array[] = { }; const struct vkms_color_lut srgb_inv_eotf = { - .base = srgb_inv_array, + .y = srgb_inv_array, .lut_length = ARRAY_SIZE(srgb_inv_array), .channel_value2index_ratio = 0xff00ffll }; -- 2.56.0 ^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH v2 08/12] drm/vkms: rename get_lut_index() to get_uniform_lut_index() 2026-11-06 20:18 [PATCH v2 00/12] drm/vkms: improve color curve LUTs precision Leandro Ribeiro ` (6 preceding siblings ...) 2026-11-06 20:18 ` [PATCH v2 07/12] drm/vkms: rename struct vkms_color_lut::base to y Leandro Ribeiro @ 2026-11-06 20:18 ` Leandro Ribeiro 2026-11-06 20:18 ` [PATCH v2 09/12] drm/vkms: add support to non-uniform LUT for internal color curves Leandro Ribeiro ` (3 subsequent siblings) 11 siblings, 0 replies; 13+ messages in thread From: Leandro Ribeiro @ 2026-11-06 20:18 UTC (permalink / raw) To: louis.chauvet Cc: airlied, alex.hung, daniel, hamohammed.sa, harry.wentland, maarten.lankhorst, melissa.srw, mripard, pekka.paalanen, robert.mader, simona, tzimmermann, dri-devel, linux-kernel In the next commits we'll add non-uniform LUTs, and this function will be used exclusively by uniform LUTs. So rename it to make this clearer. Reviewed-by: Robert Mader <robert.mader@collabora.com> Tested-by: Robert Mader <robert.mader@collabora.com> Signed-off-by: Leandro Ribeiro <leandro.ribeiro@collabora.com> --- drivers/gpu/drm/vkms/tests/vkms_color_test.c | 28 ++++++++++---------- drivers/gpu/drm/vkms/vkms_composer.c | 6 ++--- drivers/gpu/drm/vkms/vkms_composer.h | 2 +- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/vkms/tests/vkms_color_test.c b/drivers/gpu/drm/vkms/tests/vkms_color_test.c index c223797a542a..06cec3591c5c 100644 --- a/drivers/gpu/drm/vkms/tests/vkms_color_test.c +++ b/drivers/gpu/drm/vkms/tests/vkms_color_test.c @@ -86,31 +86,31 @@ static const struct vkms_color_lut test_linear_lut = { .channel_value2index_ratio = 0xf000fll }; -static void vkms_color_test_get_lut_index(struct kunit *test) +static void vkms_color_test_get_uniform_lut_index(struct kunit *test) { s64 lut_index; int i; - lut_index = get_lut_index(&test_linear_lut, test_linear_array[0].red); + lut_index = get_uniform_lut_index(&test_linear_lut, test_linear_array[0].red); KUNIT_EXPECT_EQ(test, drm_fixp2int(lut_index), 0); for (i = 0; i < test_linear_lut.lut_length; i++) { - lut_index = get_lut_index(&test_linear_lut, test_linear_array[i].red); + lut_index = get_uniform_lut_index(&test_linear_lut, test_linear_array[i].red); KUNIT_EXPECT_EQ(test, drm_fixp2int_ceil(lut_index), i); } - KUNIT_EXPECT_EQ(test, drm_fixp2int(get_lut_index(&srgb_eotf, 0x0)), 0x0); - KUNIT_EXPECT_EQ(test, drm_fixp2int_ceil(get_lut_index(&srgb_eotf, 0x0)), 0x0); - KUNIT_EXPECT_EQ(test, drm_fixp2int_ceil(get_lut_index(&srgb_eotf, 0x101)), 0x1); - KUNIT_EXPECT_EQ(test, drm_fixp2int_ceil(get_lut_index(&srgb_eotf, 0x202)), 0x2); + KUNIT_EXPECT_EQ(test, drm_fixp2int(get_uniform_lut_index(&srgb_eotf, 0x0)), 0x0); + KUNIT_EXPECT_EQ(test, drm_fixp2int_ceil(get_uniform_lut_index(&srgb_eotf, 0x0)), 0x0); + KUNIT_EXPECT_EQ(test, drm_fixp2int_ceil(get_uniform_lut_index(&srgb_eotf, 0x101)), 0x1); + KUNIT_EXPECT_EQ(test, drm_fixp2int_ceil(get_uniform_lut_index(&srgb_eotf, 0x202)), 0x2); - KUNIT_EXPECT_EQ(test, drm_fixp2int(get_lut_index(&srgb_inv_eotf, 0x0)), 0x0); - KUNIT_EXPECT_EQ(test, drm_fixp2int_ceil(get_lut_index(&srgb_inv_eotf, 0x0)), 0x0); - KUNIT_EXPECT_EQ(test, drm_fixp2int_ceil(get_lut_index(&srgb_inv_eotf, 0x101)), 0x1); - KUNIT_EXPECT_EQ(test, drm_fixp2int_ceil(get_lut_index(&srgb_inv_eotf, 0x202)), 0x2); + KUNIT_EXPECT_EQ(test, drm_fixp2int(get_uniform_lut_index(&srgb_inv_eotf, 0x0)), 0x0); + KUNIT_EXPECT_EQ(test, drm_fixp2int_ceil(get_uniform_lut_index(&srgb_inv_eotf, 0x0)), 0x0); + KUNIT_EXPECT_EQ(test, drm_fixp2int_ceil(get_uniform_lut_index(&srgb_inv_eotf, 0x101)), 0x1); + KUNIT_EXPECT_EQ(test, drm_fixp2int_ceil(get_uniform_lut_index(&srgb_inv_eotf, 0x202)), 0x2); - KUNIT_EXPECT_EQ(test, drm_fixp2int_ceil(get_lut_index(&srgb_eotf, 0xfefe)), 0xfe); - KUNIT_EXPECT_EQ(test, drm_fixp2int_ceil(get_lut_index(&srgb_eotf, 0xffff)), 0xff); + KUNIT_EXPECT_EQ(test, drm_fixp2int_ceil(get_uniform_lut_index(&srgb_eotf, 0xfefe)), 0xfe); + KUNIT_EXPECT_EQ(test, drm_fixp2int_ceil(get_uniform_lut_index(&srgb_eotf, 0xffff)), 0xff); } static void vkms_color_test_lerp(struct kunit *test) @@ -392,7 +392,7 @@ static void vkms_color_ctm_3x4_bt709(struct kunit *test) } static struct kunit_case vkms_color_test_cases[] = { - KUNIT_CASE(vkms_color_test_get_lut_index), + KUNIT_CASE(vkms_color_test_get_uniform_lut_index), KUNIT_CASE(vkms_color_test_lerp), KUNIT_CASE(vkms_color_test_linear), KUNIT_CASE(vkms_color_srgb_inv_srgb), diff --git a/drivers/gpu/drm/vkms/vkms_composer.c b/drivers/gpu/drm/vkms/vkms_composer.c index 640a1a03f06f..faf4515f024c 100644 --- a/drivers/gpu/drm/vkms/vkms_composer.c +++ b/drivers/gpu/drm/vkms/vkms_composer.c @@ -93,19 +93,19 @@ static inline u16 lut_channel_value(const struct drm_color_lut *lut, return 0; } -VISIBLE_IF_KUNIT s64 get_lut_index(const struct vkms_color_lut *lut, u16 channel_value) +VISIBLE_IF_KUNIT s64 get_uniform_lut_index(const struct vkms_color_lut *lut, u16 channel_value) { s64 color_channel_fp = drm_int2fixp(channel_value); return drm_fixp_mul(color_channel_fp, lut->channel_value2index_ratio); } -EXPORT_SYMBOL_IF_KUNIT(get_lut_index); +EXPORT_SYMBOL_IF_KUNIT(get_uniform_lut_index); VISIBLE_IF_KUNIT u16 apply_lut_to_channel_value(const struct vkms_color_lut *lut, u16 channel_value, enum lut_channel channel) { const struct drm_color_lut *lut_y_floor, *lut_y_ceil; - s64 lut_index = get_lut_index(lut, channel_value); + s64 lut_index = get_uniform_lut_index(lut, channel_value); u16 floor_channel_value, ceil_channel_value; /* diff --git a/drivers/gpu/drm/vkms/vkms_composer.h b/drivers/gpu/drm/vkms/vkms_composer.h index 04dd5646f672..fa003af12f85 100644 --- a/drivers/gpu/drm/vkms/vkms_composer.h +++ b/drivers/gpu/drm/vkms/vkms_composer.h @@ -19,7 +19,7 @@ enum lut_channel { #if IS_ENABLED(CONFIG_KUNIT) u16 lerp_u16(u16 a, u16 b, s64 t); -s64 get_lut_index(const struct vkms_color_lut *lut, u16 channel_value); +s64 get_uniform_lut_index(const struct vkms_color_lut *lut, u16 channel_value); u16 apply_lut_to_channel_value(const struct vkms_color_lut *lut, u16 channel_value, enum lut_channel channel); void apply_3x4_matrix(struct pixel_argb_s32 *pixel, const struct drm_color_ctm_3x4 *matrix); -- 2.56.0 ^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH v2 09/12] drm/vkms: add support to non-uniform LUT for internal color curves 2026-11-06 20:18 [PATCH v2 00/12] drm/vkms: improve color curve LUTs precision Leandro Ribeiro ` (7 preceding siblings ...) 2026-11-06 20:18 ` [PATCH v2 08/12] drm/vkms: rename get_lut_index() to get_uniform_lut_index() Leandro Ribeiro @ 2026-11-06 20:18 ` Leandro Ribeiro 2026-11-06 20:18 ` [PATCH v2 10/12] drm/vkms: test sRGB and inverse sRGB LUTs using more samples Leandro Ribeiro ` (2 subsequent siblings) 11 siblings, 0 replies; 13+ messages in thread From: Leandro Ribeiro @ 2026-11-06 20:18 UTC (permalink / raw) To: louis.chauvet Cc: airlied, alex.hung, daniel, hamohammed.sa, harry.wentland, maarten.lankhorst, melissa.srw, mripard, pekka.paalanen, robert.mader, simona, tzimmermann, dri-devel, linux-kernel This extends VKMS internal LUT implementation, allowing it to represent non-uniform LUTs. Such LUTs have the X axis. LUTs that come from userspace (gamma LUT) are always uniform, so they don't have a X axis. Note: vkms_color_srgb_inv_srgb() error tolerance reduced from 1/255 to 119/65535 ~= 0.46/255. Before this patch, the test compared the results after quantizing them to 8-bit precision, while the updated test compares directly in 16-bit. The LUT precision does not change with this patch. Reviewed-by: Robert Mader <robert.mader@collabora.com> Tested-by: Robert Mader <robert.mader@collabora.com> Signed-off-by: Leandro Ribeiro <leandro.ribeiro@collabora.com> --- drivers/gpu/drm/vkms/tests/vkms_color_test.c | 20 +---- drivers/gpu/drm/vkms/vkms_composer.c | 85 ++++++++++++++++++-- drivers/gpu/drm/vkms/vkms_drv.h | 9 +++ drivers/gpu/drm/vkms/vkms_luts.c | 57 +++++++++++-- 4 files changed, 139 insertions(+), 32 deletions(-) diff --git a/drivers/gpu/drm/vkms/tests/vkms_color_test.c b/drivers/gpu/drm/vkms/tests/vkms_color_test.c index 06cec3591c5c..238f4d21ebc8 100644 --- a/drivers/gpu/drm/vkms/tests/vkms_color_test.c +++ b/drivers/gpu/drm/vkms/tests/vkms_color_test.c @@ -98,19 +98,6 @@ static void vkms_color_test_get_uniform_lut_index(struct kunit *test) lut_index = get_uniform_lut_index(&test_linear_lut, test_linear_array[i].red); KUNIT_EXPECT_EQ(test, drm_fixp2int_ceil(lut_index), i); } - - KUNIT_EXPECT_EQ(test, drm_fixp2int(get_uniform_lut_index(&srgb_eotf, 0x0)), 0x0); - KUNIT_EXPECT_EQ(test, drm_fixp2int_ceil(get_uniform_lut_index(&srgb_eotf, 0x0)), 0x0); - KUNIT_EXPECT_EQ(test, drm_fixp2int_ceil(get_uniform_lut_index(&srgb_eotf, 0x101)), 0x1); - KUNIT_EXPECT_EQ(test, drm_fixp2int_ceil(get_uniform_lut_index(&srgb_eotf, 0x202)), 0x2); - - KUNIT_EXPECT_EQ(test, drm_fixp2int(get_uniform_lut_index(&srgb_inv_eotf, 0x0)), 0x0); - KUNIT_EXPECT_EQ(test, drm_fixp2int_ceil(get_uniform_lut_index(&srgb_inv_eotf, 0x0)), 0x0); - KUNIT_EXPECT_EQ(test, drm_fixp2int_ceil(get_uniform_lut_index(&srgb_inv_eotf, 0x101)), 0x1); - KUNIT_EXPECT_EQ(test, drm_fixp2int_ceil(get_uniform_lut_index(&srgb_inv_eotf, 0x202)), 0x2); - - KUNIT_EXPECT_EQ(test, drm_fixp2int_ceil(get_uniform_lut_index(&srgb_eotf, 0xfefe)), 0xfe); - KUNIT_EXPECT_EQ(test, drm_fixp2int_ceil(get_uniform_lut_index(&srgb_eotf, 0xffff)), 0xff); } static void vkms_color_test_lerp(struct kunit *test) @@ -136,13 +123,14 @@ static void vkms_color_test_linear(struct kunit *test) static void vkms_color_srgb_inv_srgb(struct kunit *test) { u16 srgb, final; + u16 tolerance = 119; for (int i = 0; i < srgb_eotf.lut_length; i++) { - srgb = apply_lut_to_channel_value(&srgb_eotf, i * 0x101, LUT_RED); + srgb = apply_lut_to_channel_value(&srgb_eotf, srgb_eotf.x[i], LUT_RED); final = apply_lut_to_channel_value(&srgb_inv_eotf, srgb, LUT_RED); - KUNIT_EXPECT_GE(test, final / 0x101, i - 1); - KUNIT_EXPECT_LE(test, final / 0x101, i + 1); + KUNIT_EXPECT_GE(test, final, (int)srgb_eotf.x[i] - tolerance); + KUNIT_EXPECT_LE(test, final, (int)srgb_eotf.x[i] + tolerance); } } diff --git a/drivers/gpu/drm/vkms/vkms_composer.c b/drivers/gpu/drm/vkms/vkms_composer.c index faf4515f024c..7a6a7875520c 100644 --- a/drivers/gpu/drm/vkms/vkms_composer.c +++ b/drivers/gpu/drm/vkms/vkms_composer.c @@ -93,27 +93,81 @@ static inline u16 lut_channel_value(const struct drm_color_lut *lut, return 0; } +static u16 apply_non_uniform_lut(const struct vkms_color_lut *lut, + u16 channel_value, + enum lut_channel channel) +{ + const struct drm_color_lut *lut_y_lo, *lut_y_hi; + u16 y_lo, y_hi; + u16 x_lo, x_hi; + unsigned int lo, hi, mid; + s64 t; + + /* + * Handle values out of LUT domain. + */ + if (channel_value <= lut->x[0]) + return lut_channel_value(&lut->y[0], channel); + if (channel_value >= lut->x[lut->lut_length - 1]) + return lut_channel_value(&lut->y[lut->lut_length - 1], channel); + + /* + * Binary search to find the largest index lo such that + * x[lo] <= channel_value. + */ + lo = 0; + hi = lut->lut_length - 1; + while (lo < hi) { + mid = lo + (hi - lo + 1) / 2; + if (lut->x[mid] <= channel_value) + lo = mid; + else + hi = mid - 1; + } + lut_y_lo = &lut->y[lo]; + + /* + * As x[0] < channel_value < x[lut_length - 1] and + * x[lo] <= channel_value, lo + 1 is a valid index. + */ + lut_y_hi = &lut->y[lo + 1]; + + x_lo = lut->x[lo]; + x_hi = lut->x[lo + 1]; + y_lo = lut_channel_value(lut_y_lo, channel); + y_hi = lut_channel_value(lut_y_hi, channel); + + /* Avoid division by zero when two consecutive x values are equal. */ + if (x_hi == x_lo) + return y_lo; + + t = drm_fixp_div(drm_int2fixp(channel_value - x_lo), + drm_int2fixp(x_hi - x_lo)); + + return lerp_u16(y_lo, y_hi, t); +} + VISIBLE_IF_KUNIT s64 get_uniform_lut_index(const struct vkms_color_lut *lut, u16 channel_value) { s64 color_channel_fp = drm_int2fixp(channel_value); + if (lut->x) { + DRM_DEBUG_DRIVER("Non-uniform LUT should not use get_uniform_lut_index()"); + return 0; + } + return drm_fixp_mul(color_channel_fp, lut->channel_value2index_ratio); } EXPORT_SYMBOL_IF_KUNIT(get_uniform_lut_index); -VISIBLE_IF_KUNIT u16 apply_lut_to_channel_value(const struct vkms_color_lut *lut, u16 channel_value, - enum lut_channel channel) +static u16 apply_uniform_lut(const struct vkms_color_lut *lut, + u16 channel_value, + enum lut_channel channel) { const struct drm_color_lut *lut_y_floor, *lut_y_ceil; s64 lut_index = get_uniform_lut_index(lut, channel_value); u16 floor_channel_value, ceil_channel_value; - /* - * This checks if `struct drm_color_lut` has any gap added by the compiler - * between the struct fields. - */ - static_assert(sizeof(struct drm_color_lut) == sizeof(__u16) * 4); - lut_y_floor = &lut->y[drm_fixp2int(lut_index)]; if (drm_fixp2int(lut_index) == (lut->lut_length - 1)) /* We're at the end of the LUT array, use same value for ceil and floor */ @@ -127,6 +181,21 @@ VISIBLE_IF_KUNIT u16 apply_lut_to_channel_value(const struct vkms_color_lut *lut return lerp_u16(floor_channel_value, ceil_channel_value, lut_index & DRM_FIXED_DECIMAL_MASK); } + +VISIBLE_IF_KUNIT u16 apply_lut_to_channel_value(const struct vkms_color_lut *lut, u16 channel_value, + enum lut_channel channel) +{ + /* + * This checks if `struct drm_color_lut` has any gap added by the compiler + * between the struct fields. + */ + static_assert(sizeof(struct drm_color_lut) == sizeof(__u16) * 4); + + if (lut->x) + return apply_non_uniform_lut(lut, channel_value, channel); + + return apply_uniform_lut(lut, channel_value, channel); +} EXPORT_SYMBOL_IF_KUNIT(apply_lut_to_channel_value); diff --git a/drivers/gpu/drm/vkms/vkms_drv.h b/drivers/gpu/drm/vkms/vkms_drv.h index cdcf7a79697b..0098b551f324 100644 --- a/drivers/gpu/drm/vkms/vkms_drv.h +++ b/drivers/gpu/drm/vkms/vkms_drv.h @@ -158,7 +158,16 @@ struct vkms_plane { struct drm_plane base; }; +/** + * struct vkms_color_lut - Driver specific color LUT representation + * @x: LUT x-values, must be non-decreasing and may be non-uniformly spaced. + * Only required for non-uniform LUTs. + * @y: LUT y-values. + * @lut_length: The LUT length. + * @channel_value2index_ratio: helper for uniform LUTs (no x-values). + */ struct vkms_color_lut { + u16 *x; struct drm_color_lut *y; size_t lut_length; s64 channel_value2index_ratio; diff --git a/drivers/gpu/drm/vkms/vkms_luts.c b/drivers/gpu/drm/vkms/vkms_luts.c index 7b0c8eaf83b8..c2d5f9e502ae 100644 --- a/drivers/gpu/drm/vkms/vkms_luts.c +++ b/drivers/gpu/drm/vkms/vkms_luts.c @@ -12,7 +12,42 @@ * https://gitlab.freedesktop.org/hwentland/lutgen */ -static struct drm_color_lut srgb_array[] = { +static u16 linear_x[] = { + 0x0000, 0x0101, 0x0202, 0x0303, 0x0404, 0x0505, 0x0606, 0x0707, + 0x0808, 0x0909, 0x0a0a, 0x0b0b, 0x0c0c, 0x0d0d, 0x0e0e, 0x0f0f, + 0x1010, 0x1111, 0x1212, 0x1313, 0x1414, 0x1515, 0x1616, 0x1717, + 0x1818, 0x1919, 0x1a1a, 0x1b1b, 0x1c1c, 0x1d1d, 0x1e1e, 0x1f1f, + 0x2020, 0x2121, 0x2222, 0x2323, 0x2424, 0x2525, 0x2626, 0x2727, + 0x2828, 0x2929, 0x2a2a, 0x2b2b, 0x2c2c, 0x2d2d, 0x2e2e, 0x2f2f, + 0x3030, 0x3131, 0x3232, 0x3333, 0x3434, 0x3535, 0x3636, 0x3737, + 0x3838, 0x3939, 0x3a3a, 0x3b3b, 0x3c3c, 0x3d3d, 0x3e3e, 0x3f3f, + 0x4040, 0x4141, 0x4242, 0x4343, 0x4444, 0x4545, 0x4646, 0x4747, + 0x4848, 0x4949, 0x4a4a, 0x4b4b, 0x4c4c, 0x4d4d, 0x4e4e, 0x4f4f, + 0x5050, 0x5151, 0x5252, 0x5353, 0x5454, 0x5555, 0x5656, 0x5757, + 0x5858, 0x5959, 0x5a5a, 0x5b5b, 0x5c5c, 0x5d5d, 0x5e5e, 0x5f5f, + 0x6060, 0x6161, 0x6262, 0x6363, 0x6464, 0x6565, 0x6666, 0x6767, + 0x6868, 0x6969, 0x6a6a, 0x6b6b, 0x6c6c, 0x6d6d, 0x6e6e, 0x6f6f, + 0x7070, 0x7171, 0x7272, 0x7373, 0x7474, 0x7575, 0x7676, 0x7777, + 0x7878, 0x7979, 0x7a7a, 0x7b7b, 0x7c7c, 0x7d7d, 0x7e7e, 0x7f7f, + 0x8080, 0x8181, 0x8282, 0x8383, 0x8484, 0x8585, 0x8686, 0x8787, + 0x8888, 0x8989, 0x8a8a, 0x8b8b, 0x8c8c, 0x8d8d, 0x8e8e, 0x8f8f, + 0x9090, 0x9191, 0x9292, 0x9393, 0x9494, 0x9595, 0x9696, 0x9797, + 0x9898, 0x9999, 0x9a9a, 0x9b9b, 0x9c9c, 0x9d9d, 0x9e9e, 0x9f9f, + 0xa0a0, 0xa1a1, 0xa2a2, 0xa3a3, 0xa4a4, 0xa5a5, 0xa6a6, 0xa7a7, + 0xa8a8, 0xa9a9, 0xaaaa, 0xabab, 0xacac, 0xadad, 0xaeae, 0xafaf, + 0xb0b0, 0xb1b1, 0xb2b2, 0xb3b3, 0xb4b4, 0xb5b5, 0xb6b6, 0xb7b7, + 0xb8b8, 0xb9b9, 0xbaba, 0xbbbb, 0xbcbc, 0xbdbd, 0xbebe, 0xbfbf, + 0xc0c0, 0xc1c1, 0xc2c2, 0xc3c3, 0xc4c4, 0xc5c5, 0xc6c6, 0xc7c7, + 0xc8c8, 0xc9c9, 0xcaca, 0xcbcb, 0xcccc, 0xcdcd, 0xcece, 0xcfcf, + 0xd0d0, 0xd1d1, 0xd2d2, 0xd3d3, 0xd4d4, 0xd5d5, 0xd6d6, 0xd7d7, + 0xd8d8, 0xd9d9, 0xdada, 0xdbdb, 0xdcdc, 0xdddd, 0xdede, 0xdfdf, + 0xe0e0, 0xe1e1, 0xe2e2, 0xe3e3, 0xe4e4, 0xe5e5, 0xe6e6, 0xe7e7, + 0xe8e8, 0xe9e9, 0xeaea, 0xebeb, 0xecec, 0xeded, 0xeeee, 0xefef, + 0xf0f0, 0xf1f1, 0xf2f2, 0xf3f3, 0xf4f4, 0xf5f5, 0xf6f6, 0xf7f7, + 0xf8f8, 0xf9f9, 0xfafa, 0xfbfb, 0xfcfc, 0xfdfd, 0xfefe, 0xffff +}; + +static struct drm_color_lut srgb_y[] = { { 0x0, 0x0, 0x0, 0 }, { 0x13, 0x13, 0x13, 0 }, { 0x27, 0x27, 0x27, 0 }, @@ -271,14 +306,17 @@ static struct drm_color_lut srgb_array[] = { { 0xffff, 0xffff, 0xffff, 0 }, }; +static_assert(ARRAY_SIZE(linear_x) == ARRAY_SIZE(srgb_y), + "srgb x and y must have the same number of entries"); + const struct vkms_color_lut srgb_eotf = { - .y = srgb_array, - .lut_length = ARRAY_SIZE(srgb_array), - .channel_value2index_ratio = 0xff00ffll + .x = linear_x, + .y = srgb_y, + .lut_length = ARRAY_SIZE(srgb_y) }; EXPORT_SYMBOL(srgb_eotf); -static struct drm_color_lut srgb_inv_array[] = { +static struct drm_color_lut srgb_inv_y[] = { { 0x0, 0x0, 0x0, 0 }, { 0xcc2, 0xcc2, 0xcc2, 0 }, { 0x15be, 0x15be, 0x15be, 0 }, @@ -537,9 +575,12 @@ static struct drm_color_lut srgb_inv_array[] = { { 0xffff, 0xffff, 0xffff, 0 }, }; +static_assert(ARRAY_SIZE(linear_x) == ARRAY_SIZE(srgb_inv_y), + "srgb_inv x and y must have the same number of entries"); + const struct vkms_color_lut srgb_inv_eotf = { - .y = srgb_inv_array, - .lut_length = ARRAY_SIZE(srgb_inv_array), - .channel_value2index_ratio = 0xff00ffll + .x = linear_x, + .y = srgb_inv_y, + .lut_length = ARRAY_SIZE(srgb_inv_y) }; EXPORT_SYMBOL(srgb_inv_eotf); -- 2.56.0 ^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH v2 10/12] drm/vkms: test sRGB and inverse sRGB LUTs using more samples 2026-11-06 20:18 [PATCH v2 00/12] drm/vkms: improve color curve LUTs precision Leandro Ribeiro ` (8 preceding siblings ...) 2026-11-06 20:18 ` [PATCH v2 09/12] drm/vkms: add support to non-uniform LUT for internal color curves Leandro Ribeiro @ 2026-11-06 20:18 ` Leandro Ribeiro 2026-11-06 20:18 ` [PATCH v2 11/12] drm/vkms: add script to create optimized LUTs for color curves Leandro Ribeiro 2026-11-06 20:18 ` [PATCH v2 12/12] drm/vkms: replace uniform sRGB LUT and its inverse with optimal ones Leandro Ribeiro 11 siblings, 0 replies; 13+ messages in thread From: Leandro Ribeiro @ 2026-11-06 20:18 UTC (permalink / raw) To: louis.chauvet Cc: airlied, alex.hung, daniel, hamohammed.sa, harry.wentland, maarten.lankhorst, melissa.srw, mripard, pekka.paalanen, robert.mader, simona, tzimmermann, dri-devel, linux-kernel We're currently using srgb_eotf.lut_length samples in vkms_color_srgb_inv_srgb(). This does not exercise any points that are not in the forward sRGB LUT, although it exercises points that are not in its inverse. Let's test with more samples, to also exercise points that are not in the forward sRGB LUT. We chose 4096 samples. LUT inputs are u16, so we could have up to 65536 samples. LUT sizes are usually not higher than 512, so with 4096 we have at least 8 samples between each LUT point. We can see a minor error bump with this change. In the next commits we replace such LUTs with non-uniform optimal ones to reduce the error. Reviewed-by: Robert Mader <robert.mader@collabora.com> Tested-by: Robert Mader <robert.mader@collabora.com> Signed-off-by: Leandro Ribeiro <leandro.ribeiro@collabora.com> --- drivers/gpu/drm/vkms/tests/vkms_color_test.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/vkms/tests/vkms_color_test.c b/drivers/gpu/drm/vkms/tests/vkms_color_test.c index 238f4d21ebc8..86d9b14f847b 100644 --- a/drivers/gpu/drm/vkms/tests/vkms_color_test.c +++ b/drivers/gpu/drm/vkms/tests/vkms_color_test.c @@ -123,14 +123,16 @@ static void vkms_color_test_linear(struct kunit *test) static void vkms_color_srgb_inv_srgb(struct kunit *test) { u16 srgb, final; - u16 tolerance = 119; + u16 tolerance = 122; + u32 x; - for (int i = 0; i < srgb_eotf.lut_length; i++) { - srgb = apply_lut_to_channel_value(&srgb_eotf, srgb_eotf.x[i], LUT_RED); + for (u32 i = 0; i <= 4095; i++) { + x = i * U16_MAX / 4095; + srgb = apply_lut_to_channel_value(&srgb_eotf, x, LUT_RED); final = apply_lut_to_channel_value(&srgb_inv_eotf, srgb, LUT_RED); - KUNIT_EXPECT_GE(test, final, (int)srgb_eotf.x[i] - tolerance); - KUNIT_EXPECT_LE(test, final, (int)srgb_eotf.x[i] + tolerance); + KUNIT_EXPECT_GE(test, final, (int)x - tolerance); + KUNIT_EXPECT_LE(test, final, (int)x + tolerance); } } -- 2.56.0 ^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH v2 11/12] drm/vkms: add script to create optimized LUTs for color curves 2026-11-06 20:18 [PATCH v2 00/12] drm/vkms: improve color curve LUTs precision Leandro Ribeiro ` (9 preceding siblings ...) 2026-11-06 20:18 ` [PATCH v2 10/12] drm/vkms: test sRGB and inverse sRGB LUTs using more samples Leandro Ribeiro @ 2026-11-06 20:18 ` Leandro Ribeiro 2026-11-06 20:18 ` [PATCH v2 12/12] drm/vkms: replace uniform sRGB LUT and its inverse with optimal ones Leandro Ribeiro 11 siblings, 0 replies; 13+ messages in thread From: Leandro Ribeiro @ 2026-11-06 20:18 UTC (permalink / raw) To: louis.chauvet Cc: airlied, alex.hung, daniel, hamohammed.sa, harry.wentland, maarten.lankhorst, melissa.srw, mripard, pekka.paalanen, robert.mader, simona, tzimmermann, dri-devel, linux-kernel Add a Python script to generate u16 LUTs for VKMS color transfer functions while minimizing interpolation and quantization errors. The script compares different LUT generation strategies and uses greedy subdivision to generate optimized LUTs for the supported transfer functions. It also outputs the generated LUTs in a format ready to be added to vkms_luts.c. v2: - Address feedback from Sashiko bot: conditionally plot, to avoid issues on headless systems. https://sashiko.dev/#/patchset/20260804203351.148521-1-leandro.ribeiro@collabora.com?part=10 Reviewed-by: Robert Mader <robert.mader@collabora.com> Tested-by: Robert Mader <robert.mader@collabora.com> Signed-off-by: Leandro Ribeiro <leandro.ribeiro@collabora.com> --- .../gpu/drm/vkms/scripts/color-curve-lut.py | 573 ++++++++++++++++++ 1 file changed, 573 insertions(+) create mode 100644 drivers/gpu/drm/vkms/scripts/color-curve-lut.py diff --git a/drivers/gpu/drm/vkms/scripts/color-curve-lut.py b/drivers/gpu/drm/vkms/scripts/color-curve-lut.py new file mode 100644 index 000000000000..c8f13643bdb7 --- /dev/null +++ b/drivers/gpu/drm/vkms/scripts/color-curve-lut.py @@ -0,0 +1,573 @@ +# SPDX-License-Identifier: GPL-2.0+ + +""" +Context +======= + +VKMS uses u16 LUTs for color transfer functions. This script generates LUTs +while minimizing interpolation and quantization error without making them +unnecessarily large. + +Three LUT generation methods are compared with this script: + + 1. uniform: distribute points uniformly in the domain. + 2. inverse uniform: distribute points uniformly in the range. + 3. greedy subdivision: iteratively adds points where interpolation error is + highest. + +Since VKMS LUTs use u16 values, max_error is evaluated at all 65536 possible +input values, comparing to the original continuous curve. For each color curve, +the LUT size is chosen so the error is close to the u16 quantization step +(roughly 10^-5). Greedy subdivision performed best for all transfer functions of +interest, so this script generates the corresponding C arrays to be used by VKMS +(see vkms_luts.c). + +Error evaluation +================ + +To evaluate the LUTs, we compare the interpolated result against the original +continuous curve at all 65536 possible u16 input values. Sampling between u16 +values could report errors that VKMS cannot encounter, since its input is always +a u16 value, so there is no benefit in using more samples. + +We initially experimented with float LUTs, where more samples were useful, and +the results were similar: greedy subdivision outperformed the other methods. + +LUT size selection +================== + +u16 quantization step is roughly 10^-5 in normalized space. So for each curve we +target LUT interpolation error close to or below this (making errors negligible +in the pipeline), and select the minimum LUT size that satisfies this target. + +Inverse PQ requires a much higher LUT size than the other curves to satisfy this +error metric. This is expected, as it has a high slope near-zero. + +Results +======= + +As stated, greedy subdivision improves the results significantly. Besides +accounting for interpolation error, it also accounts for quantization error. +Uniform LUTs perform well for curves similar to power-law, while inverse uniform +LUTs perform well for curves similar to inverse power-law. Still, for u16 LUTs +greedy subdivision algorithm outperforms both. + +Here are the LUT sizes and errors at which the error converged to the target +error: + +Results using greedy subdivision u16 LUTs +---------------------------------------------- +Function LUT size Max error +---------------------------------------------- +pow 2.2 270 9.320331e-06 +inverse pow 2.2 370 1.056258e-05 +piece-wise sRGB 260 9.298192e-06 +inv piece-wise sRGB 330 1.001394e-05 +PQ 380 9.159226e-06 +inverse PQ 540 9.476497e-06 +BT.2020 OETF 270 9.762646e-06 +inv BT.2020 OETF 240 9.924004e-06 +---------------------------------------------- + +Note: inverse pow 2.2 and inverse piece-wise sRGB LUTs stopped improving with +fewer taps than inverse PQ, but their max_error didn't drop below 10^-5, even +with very large LUTs. This can be attributed to quantization error. +""" + +import sys +import os +import time +import bisect +import math +import numpy as np + + +def u16_to_float(u16_val): + """Convert u16 value to normalized float [0, 1]""" + return u16_val / 65535.0 + + +def float_to_u16(float_val): + """Convert normalized float [0, 1] to u16""" + return int(np.round(np.clip(float_val * 65535.0, 0, 65535))) + + +class LUT: + """ + Base class for all LUT. + """ + def __init__(self, name, function_pair, lut_size): + self.name = name + self.lut_size = lut_size + self.func = function_pair[0] + self.inverse_func = function_pair[1] + self.x = None + self.y = None + self.x_float = None # cached float x array for interpolation + self.y_float = None # cached float y array for interpolation + self.build_lut() + self.validate() + self.cache_float() + + def validate(self): + """Sanity-check the generated LUT arrays""" + errors = [] + + if self.lut_size < 2: + errors.append(f"LUT size ({self.lut_size}) < 2") + if len(self.x) != self.lut_size: + errors.append(f"x length ({len(self.x)}) != lut_size ({self.lut_size})") + if len(self.y) != self.lut_size: + errors.append(f"y length ({len(self.y)}) != lut_size ({self.lut_size})") + + # All curves start with (0, 0) and end with (1, 1) + if self.x[0] != 0: + errors.append(f"x[0] = {self.x[0]}, expected 0") + if self.x[-1] != 65535: + errors.append(f"x[-1] = {self.x[-1]}, expected 65535") + if self.y[0] != 0: + errors.append(f"y[0] = {self.y[0]}, expected 0") + if self.y[-1] != 65535: + errors.append(f"y[-1] = {self.y[-1]}, expected 65535") + + # X must be strictly increasing (no repeated points) + for i in range(1, self.lut_size): + if self.x[i] <= self.x[i - 1]: + errors.append(f"x not strictly increasing at index {i}: " + f"x[{i-1}]={self.x[i-1]}, x[{i}]={self.x[i]}") + break + + # Y must be non-decreasing (all supported TFs are increasing on [0,1], + # so the quantized output should never decrease) + for i in range(1, self.lut_size): + if self.y[i] < self.y[i - 1]: + errors.append(f"y decreases between index {i-1} and {i}: " + f"y[{i-1}]={self.y[i-1]}, y[{i}]={self.y[i]}") + break + + if errors: + print(f"\n[{self.name}] VALIDATION FAILED:") + for e in errors: + print(f" - {e}") + sys.exit(1) + + def cache_float(self): + """Cache u16 x and y arrays as float for interpolation""" + self.x_float = self.x / 65535.0 + self.y_float = self.y / 65535.0 + + @staticmethod + def lut_interp(x, x_array, y_array): + """ + Lookup with linear interpolation using binary search. + All inputs and output are floats in [0, 1]. + """ + if x <= x_array[0]: + return y_array[0] + if x >= x_array[-1]: + return y_array[-1] + + # Use bisect for Python lists, np.searchsorted for numpy arrays. This + # avoids type conversions that are extremely slow. + if isinstance(x_array, list): + i1 = bisect.bisect_left(x_array, x) + else: + i1 = np.searchsorted(x_array, x) + + i0 = i1 - 1 + + x0, y0 = x_array[i0], y_array[i0] + x1, y1 = x_array[i1], y_array[i1] + + return y0 + (x - x0) * (y1 - y0) / (x1 - x0) + + def build_lut(self): + raise NotImplementedError + + def compute_error(self, num_samples=65536): + """ + Compute average absolute error and max absolute error for this LUT. + Samples all 65536 possible u16 input values, interpolates using cached + float arrays, and compares to the continuous function. + """ + average_abs_error = 0 + max_abs_error = 0 + max_abs_error_x = 0 + for i in range(num_samples): + x = i / (num_samples - 1) + lut_res = self.lut_interp(x, self.x_float, self.y_float) + real_res = self.func(x) + error = abs(real_res - lut_res) + average_abs_error += error + if error > max_abs_error: + max_abs_error = error + max_abs_error_x = x + average_abs_error = average_abs_error / num_samples + + # Check if max_error occurs between two adjacent u16 x + i1 = np.searchsorted(self.x_float, max_abs_error_x) + i0 = i1 - 1 + if i0 >= 0 and i1 < self.lut_size: + x0_u16 = self.x[i0] + x1_u16 = self.x[i1] + if x1_u16 - x0_u16 == 1: + indent = " " * (len(self.name) + 3) + print(f"[{self.name}] Warning: max_error at x={max_abs_error_x:.6e}\n" + f"{indent}is between adjacent u16 x points ({x0_u16}, {x1_u16}).\n" + f"{indent}Increasing LUT size probably won't help.") + + return average_abs_error, max_abs_error + + +class LUT_uniform(LUT): + """ + Regular uniform LUT, equidistant points in the domain + """ + def __init__(self, function_pair, lut_size): + super().__init__("Uniform", function_pair, lut_size) + + def build_lut(self): + x_list = [] + y_list = [] + for i in range(self.lut_size): + # Generate x uniformly in u16 space [0, 65535] + x_u16 = min(65535, round(i * 65535 / (self.lut_size - 1))) + x_float = u16_to_float(x_u16) + y_float = self.func(x_float) + x_list.append(x_u16) + y_list.append(float_to_u16(y_float)) + + self.x = np.array(x_list, dtype=np.uint16) + self.y = np.array(y_list, dtype=np.uint16) + + +class LUT_inverse_uniform(LUT): + """ + Inverse uniform LUT: uniformly spaces y values and computes x = f_inv(y). + Similar to inverting x and y arrays from regular LUT. This naturally places + more points in regions where the function has high slope (e.g. near zero for + inverse power-law curves). + """ + def __init__(self, function_pair, lut_size): + super().__init__("Inverse uniform", function_pair, lut_size) + + def build_lut(self): + # Uniformly space points in the range, compute x = inverse_func(y) + x_list = [] + y_list = [] + for i in range(self.lut_size): + y_u16 = min(65535, round(i * 65535 / (self.lut_size - 1))) + x_u16 = float_to_u16(self.inverse_func(u16_to_float(y_u16))) + + # Ignore duplicates. + if x_list and x_u16 == x_list[-1]: + continue + + x_list.append(x_u16) + # As x_u16 may contain quantization error (it is the result of + # computing inverse_func(y) but rounded to closest quantization + # step), let's recompute y_u16 based on x_u16 using func(). This + # creates a more precise LUT. + y_list.append(float_to_u16(self.func(u16_to_float(x_u16)))) + + self.x = np.array(x_list, dtype=np.uint16) + self.y = np.array(y_list, dtype=np.uint16) + + # Update size, as we may have ignored duplicates + self.lut_size = len(x_list) + + +class LUT_greedy_subdivision(LUT): + """ + This greedily looks for domain points in which the interpolation error is + maximal, and keeps adding points in such regions to reduce the LUT error. + + The code here only samples the midpoint of each segment to compute error, + not the true maximum error point in the segment. This is an approximation, + and one would have to try several points in the segments to have even more + accurate results. But the midpoint heuristic is fast and accurate enough. + + Note: the optimal solution (optimal in terms of minimizing interpolation + error) for the approximation problem would be using the method of globally + optimal knot placement, but that's much more complex. This one is good + enough. + """ + def __init__(self, function_pair, lut_size): + super().__init__("Greedy subdivision", function_pair, lut_size) + + def build_lut(self): + # Use Python lists during construction, as it's much faster to + # dynamically change their size. + x_list = [0, 65535] + y_list = [float_to_u16(self.func(0.0)), float_to_u16(self.func(1.0))] + + # Maintain float lists for interpolation during construction + x_list_float = [0.0, 1.0] + y_list_float = [u16_to_float(y_list[0]), u16_to_float(y_list[1])] + + # Add points based on max error + while len(x_list) < self.lut_size: + max_error = 0.0 + width_cur = 0.0 + index = 0 + best_x_mid_u16 = None + + # Find segment with max error + for i in range(len(x_list) - 1): + x0_u16 = x_list[i] + x1_u16 = x_list[i + 1] + segment_width_u16 = x1_u16 - x0_u16 + + # Skip segments in which we can't add more points in between + if segment_width_u16 < 2: + continue + + # Calculate midpoint in u16 space + x_mid_u16 = (x0_u16 + x1_u16) // 2 + x_mid_float = u16_to_float(x_mid_u16) + + # Compute error at midpoint + y_sample = self.func(x_mid_float) + y_interp = self.lut_interp(x_mid_float, x_list_float, y_list_float) + segment_max_error = abs(y_sample - y_interp) + + # Prefer biggest segment to tie-break error == max_error. This + # avoids issues with e.g. linear segments. In these segments, + # the error is always zero, so we need to add points evenly + # spaced. + if (segment_max_error > max_error or + (math.isclose(segment_max_error, max_error, abs_tol=1e-6) and + segment_width_u16 > width_cur)): + max_error = segment_max_error + index = i + width_cur = segment_width_u16 + best_x_mid_u16 = x_mid_u16 + + # If no valid segment found, stop. Also update size as we may have + # converged without the LUT size given by end user. + if best_x_mid_u16 is None: + self.lut_size = len(x_list) + break + + x_mid_float = u16_to_float(best_x_mid_u16) + y_mid_float = self.func(x_mid_float) + y_mid_u16 = float_to_u16(y_mid_float) + + x_list.insert(index + 1, best_x_mid_u16) + y_list.insert(index + 1, y_mid_u16) + x_list_float.insert(index + 1, x_mid_float) + y_list_float.insert(index + 1, u16_to_float(y_mid_u16)) + + self.x = np.array(x_list, dtype=np.uint16) + self.y = np.array(y_list, dtype=np.uint16) + + +class Functions: + """ + Functions and their inverse + """ + @staticmethod + def pow22(x): + return pow(x, 2.2) + + @staticmethod + def inv_pow22(x): + return pow(x, 1.0 / 2.2) + + @staticmethod + def srgb(x): + if x <= 0.04045: + return x / 12.92 + return pow(((x + 0.055) / 1.055), 2.4) + + @staticmethod + def inv_srgb(x): + if x <= 0.0031308: + return 12.92 * x + return 1.055 * pow(x, (1.0 / 2.4)) - 0.055 + + @staticmethod + def pq(x): + m1_inv = 1.0 / 0.1593017578125 + m2_inv = 1.0 / 78.84375 + c1 = 0.8359375 + c2 = 18.8515625 + c3 = 18.6875 + aux = pow(x, m2_inv) + return pow(max(aux - c1, 0.0) / (c2 - c3 * aux), m1_inv) + + @staticmethod + def inv_pq(x): + m1 = 0.1593017578125 + m2 = 78.84375 + c1 = 0.8359375 + c2 = 18.8515625 + c3 = 18.6875 + aux = pow(x, m1) + return pow((c1 + c2 * aux) / (1.0 + c3 * aux), m2) + + @staticmethod + def bt2020_oetf(x): + a = 1.0993 + if x < 0.018: + return 4.5 * x + return a * (pow(x, 0.45)) - (a - 1.0) + + @staticmethod + def inv_bt2020_oetf(x): + a = 1.0993 + if x < 0.081: + return x / 4.5 + k = (x + a - 1.0) / a + return pow(k, 1.0 / 0.45) + + +def emit_c_arrays(lut, func_str): + """ + Write X and Y arrays in C format compatible with vkms_luts.c to a file. + """ + name = func_str + + output_file = f"{func_str}{lut.lut_size}.txt" + if os.path.isfile(output_file): + print(f" File {output_file} already exists, not overriding it") + return + + lines = [] + + # X array: format eight values per line. + lines.append(f"static u16 {name}_x[] = {{") + for i in range(0, lut.lut_size, 8): + chunk = lut.x[i:i+8] + vals = ", ".join(f"0x{int(v):04x}" for v in chunk) + comma = "," if i + 8 < lut.lut_size else "" + lines.append(f"\t{vals}{comma}") + lines.append("};") + lines.append("") + + # Y array: one struct drm_color_lut entry per line: { R = val, G = val, B = val, reserved = 0 } + lines.append(f"static struct drm_color_lut {name}_y[] = {{") + for i, y_val in enumerate(lut.y): + v = int(y_val) + comma = "," if i < lut.lut_size - 1 else "" + lines.append(f"\t{{ 0x{v:04x}, 0x{v:04x}, 0x{v:04x}, 0 }}{comma}") + lines.append("};") + + output = "\n".join(lines) + "\n" + + with open(output_file, 'w') as f: + f.write(output) + print(f" C arrays written to {output_file}") + + +def print_help_and_quit(function_table): + """ + Print usage message and quit + """ + print("Usage: python script.py <function> <LUT_size> [--plot]") + print(" -h, --help Show this help message and exit") + print(" --plot Display the LUT plots") + print("LUT size in range [2, 4096]") + print("LUTs based on greedy subdivision algorithm are printed to file <function><LUT_size>.txt") + print("Possible function names are:") + for func in function_table.keys(): + print(f" {func}") + print(f" inv_{func}") + sys.exit(1) + + +def parse_cli_params(args, function_table): + """ + Parse cli params from users + """ + if len(args) not in (3, 4): + print_help_and_quit(function_table) + + plot = False + if len(args) == 4: + if args[3] != "--plot": + print(f"Error: unknown option '{args[3]}'\n") + print_help_and_quit(function_table) + plot = True + + func_str = args[1] + use_inverse = func_str.startswith("inv_") + base_func_str = func_str[4:] if use_inverse else func_str + + func_pair = function_table.get(base_func_str) + if func_pair is None: + print(f"Error: unknown function '{func_str}'\n") + print_help_and_quit(function_table) + + if use_inverse: + func_pair = (func_pair[1], func_pair[0]) + + lut_size_str = args[2] + try: + lut_size = int(lut_size_str) + if lut_size < 2 or lut_size > 4096: + print(f"Error: LUT size '{lut_size}' not in valid range\n") + print_help_and_quit(function_table) + except ValueError: + print(f"Error: '{lut_size_str}' is not a valid LUT size\n") + print_help_and_quit(function_table) + + return func_str, func_pair, lut_size, plot + + +def main(args): + function_table = { + "srgb": (Functions.srgb, Functions.inv_srgb), + "pow22": (Functions.pow22, Functions.inv_pow22), + "pq": (Functions.pq, Functions.inv_pq), + "bt2020_oetf": (Functions.bt2020_oetf, Functions.inv_bt2020_oetf), + } + + func_str, func_pair, lut_size, plot = parse_cli_params(args, function_table) + + start_time = time.perf_counter() + + luts = [LUT_uniform(func_pair, lut_size), + LUT_inverse_uniform(func_pair, lut_size), + LUT_greedy_subdivision(func_pair, lut_size)] + + luts_error = [lut.compute_error() for lut in luts] + + print(f"\nFunction: {func_str}, LUT size (specified by user): {lut_size}\n") + print(f"{'LUT Type':<41} {'Average Error':>15} {'Max Error':>11}") + print("-" * 72) + + for i, lut in enumerate(luts): + avg_error, max_error = luts_error[i] + label = f"{lut.name:<20} (actual size: {lut.lut_size})" + print(f"{label:<40} {avg_error:>15.6e} {max_error:>15.6e}") + + end_time = time.perf_counter() + print(f"\nTime to compute LUTs and errors: {end_time - start_time:.4f} seconds") + + # Save the greedy subdivision LUT as C arrays for VKMS + greedy_lut = luts[2] + emit_c_arrays(greedy_lut, func_str) + + if not plot: + return + + import matplotlib.pyplot as plt + + # Plot the LUTs... kind of useless when we have a big LUT, but still good to + # visualize with fewer taps. + fig, axes = plt.subplots(1, len(luts), figsize=(15, 6)) + for i, lut in enumerate(luts): + ax = axes[i] + ax.set_title(f"{lut.name} - {func_str}, LUT size: {lut.lut_size}") + ax.set_xlabel('X') + ax.set_ylabel('Y') + ax.grid(True, linestyle='--') + ax.plot(lut.x, lut.y, 'o', color="blue") + ax.set_aspect('equal') + plt.tight_layout() + plt.show() + + +if __name__ == "__main__": + main(sys.argv) -- 2.56.0 ^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH v2 12/12] drm/vkms: replace uniform sRGB LUT and its inverse with optimal ones 2026-11-06 20:18 [PATCH v2 00/12] drm/vkms: improve color curve LUTs precision Leandro Ribeiro ` (10 preceding siblings ...) 2026-11-06 20:18 ` [PATCH v2 11/12] drm/vkms: add script to create optimized LUTs for color curves Leandro Ribeiro @ 2026-11-06 20:18 ` Leandro Ribeiro 11 siblings, 0 replies; 13+ messages in thread From: Leandro Ribeiro @ 2026-11-06 20:18 UTC (permalink / raw) To: louis.chauvet Cc: airlied, alex.hung, daniel, hamohammed.sa, harry.wentland, maarten.lankhorst, melissa.srw, mripard, pekka.paalanen, robert.mader, simona, tzimmermann, dri-devel, linux-kernel This uses the script added in "drm/vkms: add script to create optimized LUTs for color curves" to produce optimized LUTs for sRGB and its inverse. The LUTs are non-uniform and have more taps where it matters (areas with high slope), decreasing the error they produce. vkms_color_srgb_inv_srgb() error tolerance dropped from 122/65535 to 11/65535. Reviewed-by: Robert Mader <robert.mader@collabora.com> Tested-by: Robert Mader <robert.mader@collabora.com> Signed-off-by: Leandro Ribeiro <leandro.ribeiro@collabora.com> --- drivers/gpu/drm/vkms/tests/vkms_color_test.c | 2 +- drivers/gpu/drm/vkms/vkms_luts.c | 1228 ++++++++++-------- 2 files changed, 676 insertions(+), 554 deletions(-) diff --git a/drivers/gpu/drm/vkms/tests/vkms_color_test.c b/drivers/gpu/drm/vkms/tests/vkms_color_test.c index 86d9b14f847b..c3c61037cb71 100644 --- a/drivers/gpu/drm/vkms/tests/vkms_color_test.c +++ b/drivers/gpu/drm/vkms/tests/vkms_color_test.c @@ -123,7 +123,7 @@ static void vkms_color_test_linear(struct kunit *test) static void vkms_color_srgb_inv_srgb(struct kunit *test) { u16 srgb, final; - u16 tolerance = 122; + u16 tolerance = 11; u32 x; for (u32 i = 0; i <= 4095; i++) { diff --git a/drivers/gpu/drm/vkms/vkms_luts.c b/drivers/gpu/drm/vkms/vkms_luts.c index c2d5f9e502ae..4b766ae7c125 100644 --- a/drivers/gpu/drm/vkms/vkms_luts.c +++ b/drivers/gpu/drm/vkms/vkms_luts.c @@ -6,580 +6,702 @@ #include "vkms_luts.h" /* - * These luts were generated with a LUT generated based on - * skia's transfer function code. The LUT generator can be - * found at - * https://gitlab.freedesktop.org/hwentland/lutgen + * These LUTs were generated by scripts/color-curve-lut.py using greedy + * subdivision to minimize interpolation error. */ -static u16 linear_x[] = { - 0x0000, 0x0101, 0x0202, 0x0303, 0x0404, 0x0505, 0x0606, 0x0707, - 0x0808, 0x0909, 0x0a0a, 0x0b0b, 0x0c0c, 0x0d0d, 0x0e0e, 0x0f0f, - 0x1010, 0x1111, 0x1212, 0x1313, 0x1414, 0x1515, 0x1616, 0x1717, - 0x1818, 0x1919, 0x1a1a, 0x1b1b, 0x1c1c, 0x1d1d, 0x1e1e, 0x1f1f, - 0x2020, 0x2121, 0x2222, 0x2323, 0x2424, 0x2525, 0x2626, 0x2727, - 0x2828, 0x2929, 0x2a2a, 0x2b2b, 0x2c2c, 0x2d2d, 0x2e2e, 0x2f2f, - 0x3030, 0x3131, 0x3232, 0x3333, 0x3434, 0x3535, 0x3636, 0x3737, - 0x3838, 0x3939, 0x3a3a, 0x3b3b, 0x3c3c, 0x3d3d, 0x3e3e, 0x3f3f, - 0x4040, 0x4141, 0x4242, 0x4343, 0x4444, 0x4545, 0x4646, 0x4747, - 0x4848, 0x4949, 0x4a4a, 0x4b4b, 0x4c4c, 0x4d4d, 0x4e4e, 0x4f4f, - 0x5050, 0x5151, 0x5252, 0x5353, 0x5454, 0x5555, 0x5656, 0x5757, - 0x5858, 0x5959, 0x5a5a, 0x5b5b, 0x5c5c, 0x5d5d, 0x5e5e, 0x5f5f, - 0x6060, 0x6161, 0x6262, 0x6363, 0x6464, 0x6565, 0x6666, 0x6767, - 0x6868, 0x6969, 0x6a6a, 0x6b6b, 0x6c6c, 0x6d6d, 0x6e6e, 0x6f6f, - 0x7070, 0x7171, 0x7272, 0x7373, 0x7474, 0x7575, 0x7676, 0x7777, - 0x7878, 0x7979, 0x7a7a, 0x7b7b, 0x7c7c, 0x7d7d, 0x7e7e, 0x7f7f, - 0x8080, 0x8181, 0x8282, 0x8383, 0x8484, 0x8585, 0x8686, 0x8787, - 0x8888, 0x8989, 0x8a8a, 0x8b8b, 0x8c8c, 0x8d8d, 0x8e8e, 0x8f8f, - 0x9090, 0x9191, 0x9292, 0x9393, 0x9494, 0x9595, 0x9696, 0x9797, - 0x9898, 0x9999, 0x9a9a, 0x9b9b, 0x9c9c, 0x9d9d, 0x9e9e, 0x9f9f, - 0xa0a0, 0xa1a1, 0xa2a2, 0xa3a3, 0xa4a4, 0xa5a5, 0xa6a6, 0xa7a7, - 0xa8a8, 0xa9a9, 0xaaaa, 0xabab, 0xacac, 0xadad, 0xaeae, 0xafaf, - 0xb0b0, 0xb1b1, 0xb2b2, 0xb3b3, 0xb4b4, 0xb5b5, 0xb6b6, 0xb7b7, - 0xb8b8, 0xb9b9, 0xbaba, 0xbbbb, 0xbcbc, 0xbdbd, 0xbebe, 0xbfbf, - 0xc0c0, 0xc1c1, 0xc2c2, 0xc3c3, 0xc4c4, 0xc5c5, 0xc6c6, 0xc7c7, - 0xc8c8, 0xc9c9, 0xcaca, 0xcbcb, 0xcccc, 0xcdcd, 0xcece, 0xcfcf, - 0xd0d0, 0xd1d1, 0xd2d2, 0xd3d3, 0xd4d4, 0xd5d5, 0xd6d6, 0xd7d7, - 0xd8d8, 0xd9d9, 0xdada, 0xdbdb, 0xdcdc, 0xdddd, 0xdede, 0xdfdf, - 0xe0e0, 0xe1e1, 0xe2e2, 0xe3e3, 0xe4e4, 0xe5e5, 0xe6e6, 0xe7e7, - 0xe8e8, 0xe9e9, 0xeaea, 0xebeb, 0xecec, 0xeded, 0xeeee, 0xefef, - 0xf0f0, 0xf1f1, 0xf2f2, 0xf3f3, 0xf4f4, 0xf5f5, 0xf6f6, 0xf7f7, - 0xf8f8, 0xf9f9, 0xfafa, 0xfbfb, 0xfcfc, 0xfdfd, 0xfefe, 0xffff +static u16 srgb_x[] = { + 0x0000, 0x07ff, 0x09ff, 0x0aff, 0x0bff, 0x0dff, 0x0fff, 0x10ff, + 0x11ff, 0x12ff, 0x13ff, 0x14ff, 0x15ff, 0x16ff, 0x17ff, 0x18ff, + 0x19ff, 0x1aff, 0x1bff, 0x1dff, 0x1fff, 0x21ff, 0x23ff, 0x25ff, + 0x26ff, 0x27ff, 0x28ff, 0x29ff, 0x2aff, 0x2bff, 0x2cff, 0x2dff, + 0x2eff, 0x2fff, 0x30ff, 0x31ff, 0x32ff, 0x33ff, 0x34ff, 0x35ff, + 0x36ff, 0x37ff, 0x38ff, 0x39ff, 0x3aff, 0x3bff, 0x3c7f, 0x3cff, + 0x3d7f, 0x3dff, 0x3eff, 0x3fff, 0x40ff, 0x41ff, 0x427f, 0x42ff, + 0x437f, 0x43ff, 0x44ff, 0x45ff, 0x46ff, 0x47ff, 0x48ff, 0x49ff, + 0x4aff, 0x4bff, 0x4cff, 0x4dff, 0x4eff, 0x4fff, 0x50ff, 0x51ff, + 0x52ff, 0x53ff, 0x54ff, 0x55ff, 0x56ff, 0x57ff, 0x58ff, 0x59ff, + 0x5aff, 0x5bff, 0x5cff, 0x5dff, 0x5eff, 0x5fff, 0x607f, 0x60ff, + 0x61ff, 0x62ff, 0x637f, 0x63ff, 0x64ff, 0x65ff, 0x66ff, 0x67ff, + 0x68ff, 0x69ff, 0x6aff, 0x6bff, 0x6cff, 0x6dff, 0x6eff, 0x6fff, + 0x70ff, 0x71ff, 0x72ff, 0x73ff, 0x74ff, 0x75ff, 0x76ff, 0x77ff, + 0x78ff, 0x79ff, 0x7aff, 0x7bff, 0x7cff, 0x7dff, 0x7eff, 0x7fff, + 0x80ff, 0x81ff, 0x82ff, 0x83ff, 0x84ff, 0x85ff, 0x86ff, 0x87ff, + 0x887f, 0x88ff, 0x89ff, 0x8aff, 0x8bff, 0x8cff, 0x8d7f, 0x8dff, + 0x8eff, 0x8fff, 0x90ff, 0x91ff, 0x92ff, 0x93ff, 0x94ff, 0x95ff, + 0x96ff, 0x97ff, 0x987f, 0x98ff, 0x99ff, 0x9aff, 0x9bff, 0x9cff, + 0x9dff, 0x9eff, 0x9fff, 0xa0ff, 0xa1ff, 0xa2ff, 0xa3ff, 0xa4ff, + 0xa5ff, 0xa6ff, 0xa7ff, 0xa8ff, 0xa9ff, 0xaaff, 0xabff, 0xacff, + 0xadff, 0xaeff, 0xafff, 0xb0ff, 0xb1ff, 0xb2ff, 0xb3ff, 0xb4ff, + 0xb5ff, 0xb6ff, 0xb7ff, 0xb87f, 0xb8ff, 0xb97f, 0xb9ff, 0xbaff, + 0xbbff, 0xbcff, 0xbdff, 0xbeff, 0xbfff, 0xc0ff, 0xc1ff, 0xc2ff, + 0xc3ff, 0xc4ff, 0xc5ff, 0xc6ff, 0xc7ff, 0xc87f, 0xc8ff, 0xc9ff, + 0xcaff, 0xcbff, 0xccff, 0xcdff, 0xceff, 0xcfff, 0xd0ff, 0xd1ff, + 0xd2ff, 0xd3ff, 0xd4ff, 0xd5ff, 0xd67f, 0xd6ff, 0xd7ff, 0xd8ff, + 0xd9ff, 0xdaff, 0xdbff, 0xdcff, 0xddff, 0xdeff, 0xdfff, 0xe0ff, + 0xe1ff, 0xe2ff, 0xe3ff, 0xe4ff, 0xe5ff, 0xe6ff, 0xe7ff, 0xe8ff, + 0xe9ff, 0xeaff, 0xebff, 0xecff, 0xedff, 0xeeff, 0xefff, 0xf0ff, + 0xf17f, 0xf1ff, 0xf27f, 0xf2ff, 0xf37f, 0xf3ff, 0xf47f, 0xf4ff, + 0xf5ff, 0xf6ff, 0xf7ff, 0xf8ff, 0xf9ff, 0xfaff, 0xfb7f, 0xfbff, + 0xfcff, 0xfdff, 0xfeff, 0xffff }; static struct drm_color_lut srgb_y[] = { - { 0x0, 0x0, 0x0, 0 }, - { 0x13, 0x13, 0x13, 0 }, - { 0x27, 0x27, 0x27, 0 }, - { 0x3b, 0x3b, 0x3b, 0 }, - { 0x4f, 0x4f, 0x4f, 0 }, - { 0x63, 0x63, 0x63, 0 }, - { 0x77, 0x77, 0x77, 0 }, - { 0x8b, 0x8b, 0x8b, 0 }, - { 0x9f, 0x9f, 0x9f, 0 }, - { 0xb3, 0xb3, 0xb3, 0 }, - { 0xc6, 0xc6, 0xc6, 0 }, - { 0xdb, 0xdb, 0xdb, 0 }, - { 0xf0, 0xf0, 0xf0, 0 }, - { 0x107, 0x107, 0x107, 0 }, - { 0x11f, 0x11f, 0x11f, 0 }, - { 0x139, 0x139, 0x139, 0 }, - { 0x153, 0x153, 0x153, 0 }, - { 0x16f, 0x16f, 0x16f, 0 }, - { 0x18c, 0x18c, 0x18c, 0 }, - { 0x1aa, 0x1aa, 0x1aa, 0 }, - { 0x1ca, 0x1ca, 0x1ca, 0 }, - { 0x1eb, 0x1eb, 0x1eb, 0 }, - { 0x20d, 0x20d, 0x20d, 0 }, - { 0x231, 0x231, 0x231, 0 }, - { 0x256, 0x256, 0x256, 0 }, - { 0x27d, 0x27d, 0x27d, 0 }, - { 0x2a4, 0x2a4, 0x2a4, 0 }, - { 0x2ce, 0x2ce, 0x2ce, 0 }, - { 0x2f9, 0x2f9, 0x2f9, 0 }, - { 0x325, 0x325, 0x325, 0 }, - { 0x352, 0x352, 0x352, 0 }, - { 0x381, 0x381, 0x381, 0 }, - { 0x3b2, 0x3b2, 0x3b2, 0 }, - { 0x3e4, 0x3e4, 0x3e4, 0 }, - { 0x418, 0x418, 0x418, 0 }, - { 0x44d, 0x44d, 0x44d, 0 }, - { 0x484, 0x484, 0x484, 0 }, - { 0x4bc, 0x4bc, 0x4bc, 0 }, - { 0x4f6, 0x4f6, 0x4f6, 0 }, - { 0x531, 0x531, 0x531, 0 }, - { 0x56e, 0x56e, 0x56e, 0 }, - { 0x5ad, 0x5ad, 0x5ad, 0 }, - { 0x5ed, 0x5ed, 0x5ed, 0 }, - { 0x62f, 0x62f, 0x62f, 0 }, - { 0x672, 0x672, 0x672, 0 }, - { 0x6b7, 0x6b7, 0x6b7, 0 }, - { 0x6fe, 0x6fe, 0x6fe, 0 }, - { 0x746, 0x746, 0x746, 0 }, - { 0x791, 0x791, 0x791, 0 }, - { 0x7dc, 0x7dc, 0x7dc, 0 }, - { 0x82a, 0x82a, 0x82a, 0 }, - { 0x879, 0x879, 0x879, 0 }, - { 0x8ca, 0x8ca, 0x8ca, 0 }, - { 0x91d, 0x91d, 0x91d, 0 }, - { 0x971, 0x971, 0x971, 0 }, - { 0x9c7, 0x9c7, 0x9c7, 0 }, - { 0xa1f, 0xa1f, 0xa1f, 0 }, - { 0xa79, 0xa79, 0xa79, 0 }, - { 0xad4, 0xad4, 0xad4, 0 }, - { 0xb32, 0xb32, 0xb32, 0 }, - { 0xb91, 0xb91, 0xb91, 0 }, - { 0xbf2, 0xbf2, 0xbf2, 0 }, - { 0xc54, 0xc54, 0xc54, 0 }, - { 0xcb9, 0xcb9, 0xcb9, 0 }, - { 0xd1f, 0xd1f, 0xd1f, 0 }, - { 0xd88, 0xd88, 0xd88, 0 }, - { 0xdf2, 0xdf2, 0xdf2, 0 }, - { 0xe5e, 0xe5e, 0xe5e, 0 }, - { 0xecc, 0xecc, 0xecc, 0 }, - { 0xf3c, 0xf3c, 0xf3c, 0 }, - { 0xfad, 0xfad, 0xfad, 0 }, - { 0x1021, 0x1021, 0x1021, 0 }, - { 0x1096, 0x1096, 0x1096, 0 }, - { 0x110e, 0x110e, 0x110e, 0 }, - { 0x1187, 0x1187, 0x1187, 0 }, - { 0x1203, 0x1203, 0x1203, 0 }, - { 0x1280, 0x1280, 0x1280, 0 }, - { 0x12ff, 0x12ff, 0x12ff, 0 }, - { 0x1380, 0x1380, 0x1380, 0 }, - { 0x1404, 0x1404, 0x1404, 0 }, - { 0x1489, 0x1489, 0x1489, 0 }, - { 0x1510, 0x1510, 0x1510, 0 }, - { 0x1599, 0x1599, 0x1599, 0 }, - { 0x1624, 0x1624, 0x1624, 0 }, - { 0x16b2, 0x16b2, 0x16b2, 0 }, - { 0x1741, 0x1741, 0x1741, 0 }, - { 0x17d2, 0x17d2, 0x17d2, 0 }, - { 0x1865, 0x1865, 0x1865, 0 }, - { 0x18fb, 0x18fb, 0x18fb, 0 }, - { 0x1992, 0x1992, 0x1992, 0 }, - { 0x1a2c, 0x1a2c, 0x1a2c, 0 }, - { 0x1ac8, 0x1ac8, 0x1ac8, 0 }, - { 0x1b65, 0x1b65, 0x1b65, 0 }, - { 0x1c05, 0x1c05, 0x1c05, 0 }, - { 0x1ca7, 0x1ca7, 0x1ca7, 0 }, - { 0x1d4b, 0x1d4b, 0x1d4b, 0 }, - { 0x1df1, 0x1df1, 0x1df1, 0 }, - { 0x1e99, 0x1e99, 0x1e99, 0 }, - { 0x1f44, 0x1f44, 0x1f44, 0 }, - { 0x1ff0, 0x1ff0, 0x1ff0, 0 }, - { 0x209f, 0x209f, 0x209f, 0 }, - { 0x2150, 0x2150, 0x2150, 0 }, - { 0x2203, 0x2203, 0x2203, 0 }, - { 0x22b8, 0x22b8, 0x22b8, 0 }, - { 0x2370, 0x2370, 0x2370, 0 }, - { 0x2429, 0x2429, 0x2429, 0 }, - { 0x24e5, 0x24e5, 0x24e5, 0 }, - { 0x25a3, 0x25a3, 0x25a3, 0 }, - { 0x2663, 0x2663, 0x2663, 0 }, - { 0x2726, 0x2726, 0x2726, 0 }, - { 0x27ea, 0x27ea, 0x27ea, 0 }, - { 0x28b1, 0x28b1, 0x28b1, 0 }, - { 0x297a, 0x297a, 0x297a, 0 }, - { 0x2a45, 0x2a45, 0x2a45, 0 }, - { 0x2b13, 0x2b13, 0x2b13, 0 }, - { 0x2be3, 0x2be3, 0x2be3, 0 }, - { 0x2cb5, 0x2cb5, 0x2cb5, 0 }, - { 0x2d89, 0x2d89, 0x2d89, 0 }, - { 0x2e60, 0x2e60, 0x2e60, 0 }, - { 0x2f39, 0x2f39, 0x2f39, 0 }, - { 0x3014, 0x3014, 0x3014, 0 }, - { 0x30f2, 0x30f2, 0x30f2, 0 }, - { 0x31d2, 0x31d2, 0x31d2, 0 }, - { 0x32b4, 0x32b4, 0x32b4, 0 }, - { 0x3398, 0x3398, 0x3398, 0 }, - { 0x347f, 0x347f, 0x347f, 0 }, - { 0x3569, 0x3569, 0x3569, 0 }, - { 0x3654, 0x3654, 0x3654, 0 }, - { 0x3742, 0x3742, 0x3742, 0 }, - { 0x3832, 0x3832, 0x3832, 0 }, - { 0x3925, 0x3925, 0x3925, 0 }, - { 0x3a1a, 0x3a1a, 0x3a1a, 0 }, - { 0x3b11, 0x3b11, 0x3b11, 0 }, - { 0x3c0b, 0x3c0b, 0x3c0b, 0 }, - { 0x3d07, 0x3d07, 0x3d07, 0 }, - { 0x3e05, 0x3e05, 0x3e05, 0 }, - { 0x3f06, 0x3f06, 0x3f06, 0 }, - { 0x400a, 0x400a, 0x400a, 0 }, - { 0x410f, 0x410f, 0x410f, 0 }, - { 0x4218, 0x4218, 0x4218, 0 }, - { 0x4322, 0x4322, 0x4322, 0 }, - { 0x442f, 0x442f, 0x442f, 0 }, - { 0x453f, 0x453f, 0x453f, 0 }, - { 0x4650, 0x4650, 0x4650, 0 }, - { 0x4765, 0x4765, 0x4765, 0 }, - { 0x487c, 0x487c, 0x487c, 0 }, - { 0x4995, 0x4995, 0x4995, 0 }, - { 0x4ab1, 0x4ab1, 0x4ab1, 0 }, - { 0x4bcf, 0x4bcf, 0x4bcf, 0 }, - { 0x4cf0, 0x4cf0, 0x4cf0, 0 }, - { 0x4e13, 0x4e13, 0x4e13, 0 }, - { 0x4f39, 0x4f39, 0x4f39, 0 }, - { 0x5061, 0x5061, 0x5061, 0 }, - { 0x518b, 0x518b, 0x518b, 0 }, - { 0x52b9, 0x52b9, 0x52b9, 0 }, - { 0x53e8, 0x53e8, 0x53e8, 0 }, - { 0x551b, 0x551b, 0x551b, 0 }, - { 0x5650, 0x5650, 0x5650, 0 }, - { 0x5787, 0x5787, 0x5787, 0 }, - { 0x58c1, 0x58c1, 0x58c1, 0 }, - { 0x59fd, 0x59fd, 0x59fd, 0 }, - { 0x5b3c, 0x5b3c, 0x5b3c, 0 }, - { 0x5c7e, 0x5c7e, 0x5c7e, 0 }, - { 0x5dc2, 0x5dc2, 0x5dc2, 0 }, - { 0x5f09, 0x5f09, 0x5f09, 0 }, - { 0x6052, 0x6052, 0x6052, 0 }, - { 0x619e, 0x619e, 0x619e, 0 }, - { 0x62ec, 0x62ec, 0x62ec, 0 }, - { 0x643d, 0x643d, 0x643d, 0 }, - { 0x6591, 0x6591, 0x6591, 0 }, - { 0x66e7, 0x66e7, 0x66e7, 0 }, - { 0x6840, 0x6840, 0x6840, 0 }, - { 0x699b, 0x699b, 0x699b, 0 }, - { 0x6afa, 0x6afa, 0x6afa, 0 }, - { 0x6c5a, 0x6c5a, 0x6c5a, 0 }, - { 0x6dbe, 0x6dbe, 0x6dbe, 0 }, - { 0x6f24, 0x6f24, 0x6f24, 0 }, - { 0x708c, 0x708c, 0x708c, 0 }, - { 0x71f8, 0x71f8, 0x71f8, 0 }, - { 0x7366, 0x7366, 0x7366, 0 }, - { 0x74d6, 0x74d6, 0x74d6, 0 }, - { 0x764a, 0x764a, 0x764a, 0 }, - { 0x77c0, 0x77c0, 0x77c0, 0 }, - { 0x7938, 0x7938, 0x7938, 0 }, - { 0x7ab4, 0x7ab4, 0x7ab4, 0 }, - { 0x7c32, 0x7c32, 0x7c32, 0 }, - { 0x7db3, 0x7db3, 0x7db3, 0 }, - { 0x7f36, 0x7f36, 0x7f36, 0 }, - { 0x80bc, 0x80bc, 0x80bc, 0 }, - { 0x8245, 0x8245, 0x8245, 0 }, - { 0x83d1, 0x83d1, 0x83d1, 0 }, - { 0x855f, 0x855f, 0x855f, 0 }, - { 0x86f0, 0x86f0, 0x86f0, 0 }, - { 0x8884, 0x8884, 0x8884, 0 }, - { 0x8a1a, 0x8a1a, 0x8a1a, 0 }, - { 0x8bb4, 0x8bb4, 0x8bb4, 0 }, - { 0x8d50, 0x8d50, 0x8d50, 0 }, - { 0x8eee, 0x8eee, 0x8eee, 0 }, - { 0x9090, 0x9090, 0x9090, 0 }, - { 0x9234, 0x9234, 0x9234, 0 }, - { 0x93db, 0x93db, 0x93db, 0 }, - { 0x9585, 0x9585, 0x9585, 0 }, - { 0x9732, 0x9732, 0x9732, 0 }, - { 0x98e1, 0x98e1, 0x98e1, 0 }, - { 0x9a93, 0x9a93, 0x9a93, 0 }, - { 0x9c48, 0x9c48, 0x9c48, 0 }, - { 0x9e00, 0x9e00, 0x9e00, 0 }, - { 0x9fbb, 0x9fbb, 0x9fbb, 0 }, - { 0xa178, 0xa178, 0xa178, 0 }, - { 0xa338, 0xa338, 0xa338, 0 }, - { 0xa4fb, 0xa4fb, 0xa4fb, 0 }, - { 0xa6c1, 0xa6c1, 0xa6c1, 0 }, - { 0xa88a, 0xa88a, 0xa88a, 0 }, - { 0xaa56, 0xaa56, 0xaa56, 0 }, - { 0xac24, 0xac24, 0xac24, 0 }, - { 0xadf5, 0xadf5, 0xadf5, 0 }, - { 0xafc9, 0xafc9, 0xafc9, 0 }, - { 0xb1a0, 0xb1a0, 0xb1a0, 0 }, - { 0xb37a, 0xb37a, 0xb37a, 0 }, - { 0xb557, 0xb557, 0xb557, 0 }, - { 0xb736, 0xb736, 0xb736, 0 }, - { 0xb919, 0xb919, 0xb919, 0 }, - { 0xbafe, 0xbafe, 0xbafe, 0 }, - { 0xbce6, 0xbce6, 0xbce6, 0 }, - { 0xbed2, 0xbed2, 0xbed2, 0 }, - { 0xc0c0, 0xc0c0, 0xc0c0, 0 }, - { 0xc2b0, 0xc2b0, 0xc2b0, 0 }, - { 0xc4a4, 0xc4a4, 0xc4a4, 0 }, - { 0xc69b, 0xc69b, 0xc69b, 0 }, - { 0xc895, 0xc895, 0xc895, 0 }, - { 0xca91, 0xca91, 0xca91, 0 }, - { 0xcc91, 0xcc91, 0xcc91, 0 }, - { 0xce93, 0xce93, 0xce93, 0 }, - { 0xd098, 0xd098, 0xd098, 0 }, - { 0xd2a1, 0xd2a1, 0xd2a1, 0 }, - { 0xd4ac, 0xd4ac, 0xd4ac, 0 }, - { 0xd6ba, 0xd6ba, 0xd6ba, 0 }, - { 0xd8cb, 0xd8cb, 0xd8cb, 0 }, - { 0xdadf, 0xdadf, 0xdadf, 0 }, - { 0xdcf7, 0xdcf7, 0xdcf7, 0 }, - { 0xdf11, 0xdf11, 0xdf11, 0 }, - { 0xe12e, 0xe12e, 0xe12e, 0 }, - { 0xe34e, 0xe34e, 0xe34e, 0 }, - { 0xe571, 0xe571, 0xe571, 0 }, - { 0xe796, 0xe796, 0xe796, 0 }, - { 0xe9bf, 0xe9bf, 0xe9bf, 0 }, - { 0xebeb, 0xebeb, 0xebeb, 0 }, - { 0xee1a, 0xee1a, 0xee1a, 0 }, - { 0xf04c, 0xf04c, 0xf04c, 0 }, - { 0xf281, 0xf281, 0xf281, 0 }, - { 0xf4b9, 0xf4b9, 0xf4b9, 0 }, - { 0xf6f4, 0xf6f4, 0xf6f4, 0 }, - { 0xf932, 0xf932, 0xf932, 0 }, - { 0xfb73, 0xfb73, 0xfb73, 0 }, - { 0xfdb7, 0xfdb7, 0xfdb7, 0 }, - { 0xffff, 0xffff, 0xffff, 0 }, + { 0x0000, 0x0000, 0x0000, 0 }, + { 0x009e, 0x009e, 0x009e, 0 }, + { 0x00c6, 0x00c6, 0x00c6, 0 }, + { 0x00da, 0x00da, 0x00da, 0 }, + { 0x00f0, 0x00f0, 0x00f0, 0 }, + { 0x011e, 0x011e, 0x011e, 0 }, + { 0x0152, 0x0152, 0x0152, 0 }, + { 0x016d, 0x016d, 0x016d, 0 }, + { 0x018a, 0x018a, 0x018a, 0 }, + { 0x01a8, 0x01a8, 0x01a8, 0 }, + { 0x01c8, 0x01c8, 0x01c8, 0 }, + { 0x01e9, 0x01e9, 0x01e9, 0 }, + { 0x020b, 0x020b, 0x020b, 0 }, + { 0x022e, 0x022e, 0x022e, 0 }, + { 0x0253, 0x0253, 0x0253, 0 }, + { 0x0279, 0x0279, 0x0279, 0 }, + { 0x02a1, 0x02a1, 0x02a1, 0 }, + { 0x02ca, 0x02ca, 0x02ca, 0 }, + { 0x02f4, 0x02f4, 0x02f4, 0 }, + { 0x034d, 0x034d, 0x034d, 0 }, + { 0x03ac, 0x03ac, 0x03ac, 0 }, + { 0x0411, 0x0411, 0x0411, 0 }, + { 0x047c, 0x047c, 0x047c, 0 }, + { 0x04ed, 0x04ed, 0x04ed, 0 }, + { 0x0528, 0x0528, 0x0528, 0 }, + { 0x0565, 0x0565, 0x0565, 0 }, + { 0x05a3, 0x05a3, 0x05a3, 0 }, + { 0x05e3, 0x05e3, 0x05e3, 0 }, + { 0x0624, 0x0624, 0x0624, 0 }, + { 0x0667, 0x0667, 0x0667, 0 }, + { 0x06ab, 0x06ab, 0x06ab, 0 }, + { 0x06f1, 0x06f1, 0x06f1, 0 }, + { 0x0739, 0x0739, 0x0739, 0 }, + { 0x0783, 0x0783, 0x0783, 0 }, + { 0x07ce, 0x07ce, 0x07ce, 0 }, + { 0x081b, 0x081b, 0x081b, 0 }, + { 0x0869, 0x0869, 0x0869, 0 }, + { 0x08ba, 0x08ba, 0x08ba, 0 }, + { 0x090c, 0x090c, 0x090c, 0 }, + { 0x095f, 0x095f, 0x095f, 0 }, + { 0x09b5, 0x09b5, 0x09b5, 0 }, + { 0x0a0c, 0x0a0c, 0x0a0c, 0 }, + { 0x0a65, 0x0a65, 0x0a65, 0 }, + { 0x0ac0, 0x0ac0, 0x0ac0, 0 }, + { 0x0b1c, 0x0b1c, 0x0b1c, 0 }, + { 0x0b7b, 0x0b7b, 0x0b7b, 0 }, + { 0x0baa, 0x0baa, 0x0baa, 0 }, + { 0x0bdb, 0x0bdb, 0x0bdb, 0 }, + { 0x0c0b, 0x0c0b, 0x0c0b, 0 }, + { 0x0c3d, 0x0c3d, 0x0c3d, 0 }, + { 0x0ca0, 0x0ca0, 0x0ca0, 0 }, + { 0x0d06, 0x0d06, 0x0d06, 0 }, + { 0x0d6d, 0x0d6d, 0x0d6d, 0 }, + { 0x0dd7, 0x0dd7, 0x0dd7, 0 }, + { 0x0e0c, 0x0e0c, 0x0e0c, 0 }, + { 0x0e42, 0x0e42, 0x0e42, 0 }, + { 0x0e78, 0x0e78, 0x0e78, 0 }, + { 0x0eaf, 0x0eaf, 0x0eaf, 0 }, + { 0x0f1d, 0x0f1d, 0x0f1d, 0 }, + { 0x0f8e, 0x0f8e, 0x0f8e, 0 }, + { 0x1001, 0x1001, 0x1001, 0 }, + { 0x1075, 0x1075, 0x1075, 0 }, + { 0x10ec, 0x10ec, 0x10ec, 0 }, + { 0x1164, 0x1164, 0x1164, 0 }, + { 0x11de, 0x11de, 0x11de, 0 }, + { 0x125b, 0x125b, 0x125b, 0 }, + { 0x12d9, 0x12d9, 0x12d9, 0 }, + { 0x1359, 0x1359, 0x1359, 0 }, + { 0x13db, 0x13db, 0x13db, 0 }, + { 0x145f, 0x145f, 0x145f, 0 }, + { 0x14e5, 0x14e5, 0x14e5, 0 }, + { 0x156d, 0x156d, 0x156d, 0 }, + { 0x15f7, 0x15f7, 0x15f7, 0 }, + { 0x1683, 0x1683, 0x1683, 0 }, + { 0x1711, 0x1711, 0x1711, 0 }, + { 0x17a1, 0x17a1, 0x17a1, 0 }, + { 0x1833, 0x1833, 0x1833, 0 }, + { 0x18c7, 0x18c7, 0x18c7, 0 }, + { 0x195e, 0x195e, 0x195e, 0 }, + { 0x19f6, 0x19f6, 0x19f6, 0 }, + { 0x1a90, 0x1a90, 0x1a90, 0 }, + { 0x1b2c, 0x1b2c, 0x1b2c, 0 }, + { 0x1bcb, 0x1bcb, 0x1bcb, 0 }, + { 0x1c6b, 0x1c6b, 0x1c6b, 0 }, + { 0x1d0e, 0x1d0e, 0x1d0e, 0 }, + { 0x1db3, 0x1db3, 0x1db3, 0 }, + { 0x1e06, 0x1e06, 0x1e06, 0 }, + { 0x1e5a, 0x1e5a, 0x1e5a, 0 }, + { 0x1f02, 0x1f02, 0x1f02, 0 }, + { 0x1fae, 0x1fae, 0x1fae, 0 }, + { 0x2004, 0x2004, 0x2004, 0 }, + { 0x205b, 0x205b, 0x205b, 0 }, + { 0x210a, 0x210a, 0x210a, 0 }, + { 0x21bc, 0x21bc, 0x21bc, 0 }, + { 0x226f, 0x226f, 0x226f, 0 }, + { 0x2325, 0x2325, 0x2325, 0 }, + { 0x23dd, 0x23dd, 0x23dd, 0 }, + { 0x2497, 0x2497, 0x2497, 0 }, + { 0x2553, 0x2553, 0x2553, 0 }, + { 0x2612, 0x2612, 0x2612, 0 }, + { 0x26d3, 0x26d3, 0x26d3, 0 }, + { 0x2795, 0x2795, 0x2795, 0 }, + { 0x285b, 0x285b, 0x285b, 0 }, + { 0x2922, 0x2922, 0x2922, 0 }, + { 0x29eb, 0x29eb, 0x29eb, 0 }, + { 0x2ab7, 0x2ab7, 0x2ab7, 0 }, + { 0x2b85, 0x2b85, 0x2b85, 0 }, + { 0x2c56, 0x2c56, 0x2c56, 0 }, + { 0x2d28, 0x2d28, 0x2d28, 0 }, + { 0x2dfd, 0x2dfd, 0x2dfd, 0 }, + { 0x2ed4, 0x2ed4, 0x2ed4, 0 }, + { 0x2fad, 0x2fad, 0x2fad, 0 }, + { 0x3089, 0x3089, 0x3089, 0 }, + { 0x3167, 0x3167, 0x3167, 0 }, + { 0x3247, 0x3247, 0x3247, 0 }, + { 0x332a, 0x332a, 0x332a, 0 }, + { 0x340e, 0x340e, 0x340e, 0 }, + { 0x34f5, 0x34f5, 0x34f5, 0 }, + { 0x35df, 0x35df, 0x35df, 0 }, + { 0x36cb, 0x36cb, 0x36cb, 0 }, + { 0x37b9, 0x37b9, 0x37b9, 0 }, + { 0x38a9, 0x38a9, 0x38a9, 0 }, + { 0x399c, 0x399c, 0x399c, 0 }, + { 0x3a91, 0x3a91, 0x3a91, 0 }, + { 0x3b89, 0x3b89, 0x3b89, 0 }, + { 0x3c83, 0x3c83, 0x3c83, 0 }, + { 0x3d7f, 0x3d7f, 0x3d7f, 0 }, + { 0x3e7e, 0x3e7e, 0x3e7e, 0 }, + { 0x3efe, 0x3efe, 0x3efe, 0 }, + { 0x3f7f, 0x3f7f, 0x3f7f, 0 }, + { 0x4082, 0x4082, 0x4082, 0 }, + { 0x4188, 0x4188, 0x4188, 0 }, + { 0x4290, 0x4290, 0x4290, 0 }, + { 0x439b, 0x439b, 0x439b, 0 }, + { 0x4421, 0x4421, 0x4421, 0 }, + { 0x44a8, 0x44a8, 0x44a8, 0 }, + { 0x45b7, 0x45b7, 0x45b7, 0 }, + { 0x46c9, 0x46c9, 0x46c9, 0 }, + { 0x47dd, 0x47dd, 0x47dd, 0 }, + { 0x48f4, 0x48f4, 0x48f4, 0 }, + { 0x4a0d, 0x4a0d, 0x4a0d, 0 }, + { 0x4b29, 0x4b29, 0x4b29, 0 }, + { 0x4c47, 0x4c47, 0x4c47, 0 }, + { 0x4d68, 0x4d68, 0x4d68, 0 }, + { 0x4e8b, 0x4e8b, 0x4e8b, 0 }, + { 0x4fb1, 0x4fb1, 0x4fb1, 0 }, + { 0x5044, 0x5044, 0x5044, 0 }, + { 0x50d9, 0x50d9, 0x50d9, 0 }, + { 0x5203, 0x5203, 0x5203, 0 }, + { 0x5330, 0x5330, 0x5330, 0 }, + { 0x5460, 0x5460, 0x5460, 0 }, + { 0x5592, 0x5592, 0x5592, 0 }, + { 0x56c6, 0x56c6, 0x56c6, 0 }, + { 0x57fe, 0x57fe, 0x57fe, 0 }, + { 0x5937, 0x5937, 0x5937, 0 }, + { 0x5a73, 0x5a73, 0x5a73, 0 }, + { 0x5bb2, 0x5bb2, 0x5bb2, 0 }, + { 0x5cf3, 0x5cf3, 0x5cf3, 0 }, + { 0x5e37, 0x5e37, 0x5e37, 0 }, + { 0x5f7d, 0x5f7d, 0x5f7d, 0 }, + { 0x60c6, 0x60c6, 0x60c6, 0 }, + { 0x6212, 0x6212, 0x6212, 0 }, + { 0x6360, 0x6360, 0x6360, 0 }, + { 0x64b0, 0x64b0, 0x64b0, 0 }, + { 0x6604, 0x6604, 0x6604, 0 }, + { 0x6759, 0x6759, 0x6759, 0 }, + { 0x68b2, 0x68b2, 0x68b2, 0 }, + { 0x6a0d, 0x6a0d, 0x6a0d, 0 }, + { 0x6b6a, 0x6b6a, 0x6b6a, 0 }, + { 0x6ccb, 0x6ccb, 0x6ccb, 0 }, + { 0x6e2d, 0x6e2d, 0x6e2d, 0 }, + { 0x6f93, 0x6f93, 0x6f93, 0 }, + { 0x70fb, 0x70fb, 0x70fb, 0 }, + { 0x7266, 0x7266, 0x7266, 0 }, + { 0x73d3, 0x73d3, 0x73d3, 0 }, + { 0x7543, 0x7543, 0x7543, 0 }, + { 0x76b6, 0x76b6, 0x76b6, 0 }, + { 0x782b, 0x782b, 0x782b, 0 }, + { 0x79a3, 0x79a3, 0x79a3, 0 }, + { 0x7a60, 0x7a60, 0x7a60, 0 }, + { 0x7b1e, 0x7b1e, 0x7b1e, 0 }, + { 0x7bdc, 0x7bdc, 0x7bdc, 0 }, + { 0x7c9b, 0x7c9b, 0x7c9b, 0 }, + { 0x7e1b, 0x7e1b, 0x7e1b, 0 }, + { 0x7f9d, 0x7f9d, 0x7f9d, 0 }, + { 0x8123, 0x8123, 0x8123, 0 }, + { 0x82ab, 0x82ab, 0x82ab, 0 }, + { 0x8436, 0x8436, 0x8436, 0 }, + { 0x85c3, 0x85c3, 0x85c3, 0 }, + { 0x8753, 0x8753, 0x8753, 0 }, + { 0x88e6, 0x88e6, 0x88e6, 0 }, + { 0x8a7c, 0x8a7c, 0x8a7c, 0 }, + { 0x8c14, 0x8c14, 0x8c14, 0 }, + { 0x8daf, 0x8daf, 0x8daf, 0 }, + { 0x8f4d, 0x8f4d, 0x8f4d, 0 }, + { 0x90ed, 0x90ed, 0x90ed, 0 }, + { 0x9291, 0x9291, 0x9291, 0 }, + { 0x9363, 0x9363, 0x9363, 0 }, + { 0x9437, 0x9437, 0x9437, 0 }, + { 0x95df, 0x95df, 0x95df, 0 }, + { 0x978b, 0x978b, 0x978b, 0 }, + { 0x9939, 0x9939, 0x9939, 0 }, + { 0x9aea, 0x9aea, 0x9aea, 0 }, + { 0x9c9e, 0x9c9e, 0x9c9e, 0 }, + { 0x9e55, 0x9e55, 0x9e55, 0 }, + { 0xa00e, 0xa00e, 0xa00e, 0 }, + { 0xa1ca, 0xa1ca, 0xa1ca, 0 }, + { 0xa389, 0xa389, 0xa389, 0 }, + { 0xa54b, 0xa54b, 0xa54b, 0 }, + { 0xa710, 0xa710, 0xa710, 0 }, + { 0xa8d7, 0xa8d7, 0xa8d7, 0 }, + { 0xaaa2, 0xaaa2, 0xaaa2, 0 }, + { 0xab88, 0xab88, 0xab88, 0 }, + { 0xac6f, 0xac6f, 0xac6f, 0 }, + { 0xae3e, 0xae3e, 0xae3e, 0 }, + { 0xb011, 0xb011, 0xb011, 0 }, + { 0xb1e7, 0xb1e7, 0xb1e7, 0 }, + { 0xb3bf, 0xb3bf, 0xb3bf, 0 }, + { 0xb59a, 0xb59a, 0xb59a, 0 }, + { 0xb779, 0xb779, 0xb779, 0 }, + { 0xb959, 0xb959, 0xb959, 0 }, + { 0xbb3d, 0xbb3d, 0xbb3d, 0 }, + { 0xbd24, 0xbd24, 0xbd24, 0 }, + { 0xbf0d, 0xbf0d, 0xbf0d, 0 }, + { 0xc0fa, 0xc0fa, 0xc0fa, 0 }, + { 0xc2e9, 0xc2e9, 0xc2e9, 0 }, + { 0xc4db, 0xc4db, 0xc4db, 0 }, + { 0xc6d0, 0xc6d0, 0xc6d0, 0 }, + { 0xc8c8, 0xc8c8, 0xc8c8, 0 }, + { 0xcac3, 0xcac3, 0xcac3, 0 }, + { 0xccc1, 0xccc1, 0xccc1, 0 }, + { 0xcec2, 0xcec2, 0xcec2, 0 }, + { 0xd0c5, 0xd0c5, 0xd0c5, 0 }, + { 0xd2cc, 0xd2cc, 0xd2cc, 0 }, + { 0xd4d5, 0xd4d5, 0xd4d5, 0 }, + { 0xd6e2, 0xd6e2, 0xd6e2, 0 }, + { 0xd8f1, 0xd8f1, 0xd8f1, 0 }, + { 0xdb03, 0xdb03, 0xdb03, 0 }, + { 0xdd18, 0xdd18, 0xdd18, 0 }, + { 0xdf31, 0xdf31, 0xdf31, 0 }, + { 0xe03e, 0xe03e, 0xe03e, 0 }, + { 0xe14c, 0xe14c, 0xe14c, 0 }, + { 0xe25a, 0xe25a, 0xe25a, 0 }, + { 0xe36a, 0xe36a, 0xe36a, 0 }, + { 0xe47a, 0xe47a, 0xe47a, 0 }, + { 0xe58b, 0xe58b, 0xe58b, 0 }, + { 0xe69c, 0xe69c, 0xe69c, 0 }, + { 0xe7af, 0xe7af, 0xe7af, 0 }, + { 0xe9d5, 0xe9d5, 0xe9d5, 0 }, + { 0xebff, 0xebff, 0xebff, 0 }, + { 0xee2c, 0xee2c, 0xee2c, 0 }, + { 0xf05c, 0xf05c, 0xf05c, 0 }, + { 0xf28f, 0xf28f, 0xf28f, 0 }, + { 0xf4c5, 0xf4c5, 0xf4c5, 0 }, + { 0xf5e1, 0xf5e1, 0xf5e1, 0 }, + { 0xf6fe, 0xf6fe, 0xf6fe, 0 }, + { 0xf939, 0xf939, 0xf939, 0 }, + { 0xfb78, 0xfb78, 0xfb78, 0 }, + { 0xfdba, 0xfdba, 0xfdba, 0 }, + { 0xffff, 0xffff, 0xffff, 0 } }; -static_assert(ARRAY_SIZE(linear_x) == ARRAY_SIZE(srgb_y), +static_assert(ARRAY_SIZE(srgb_x) == ARRAY_SIZE(srgb_y), "srgb x and y must have the same number of entries"); const struct vkms_color_lut srgb_eotf = { - .x = linear_x, + .x = srgb_x, .y = srgb_y, .lut_length = ARRAY_SIZE(srgb_y) }; EXPORT_SYMBOL(srgb_eotf); +static u16 srgb_inv_x[] = { + 0x0000, 0x007f, 0x00bf, 0x00cf, 0x00d7, 0x00df, 0x00ef, 0x00ff, + 0x010f, 0x011f, 0x012f, 0x013f, 0x014f, 0x015f, 0x016f, 0x017f, + 0x018f, 0x019f, 0x01af, 0x01bf, 0x01cf, 0x01df, 0x01ef, 0x01ff, + 0x020f, 0x021f, 0x022f, 0x023f, 0x025f, 0x027f, 0x029f, 0x02af, + 0x02bf, 0x02df, 0x02ff, 0x030f, 0x031f, 0x032f, 0x033f, 0x034f, + 0x035f, 0x037f, 0x038f, 0x039f, 0x03af, 0x03bf, 0x03cf, 0x03df, + 0x03ff, 0x041f, 0x043f, 0x045f, 0x047f, 0x049f, 0x04bf, 0x04df, + 0x04ff, 0x051f, 0x053f, 0x055f, 0x057f, 0x059f, 0x05bf, 0x05ff, + 0x063f, 0x065f, 0x067f, 0x069f, 0x06bf, 0x06ff, 0x071f, 0x073f, + 0x075f, 0x077f, 0x07bf, 0x07ff, 0x083f, 0x087f, 0x08bf, 0x08ff, + 0x093f, 0x097f, 0x099f, 0x09bf, 0x09ff, 0x0a3f, 0x0a7f, 0x0abf, + 0x0aff, 0x0b3f, 0x0b7f, 0x0bbf, 0x0bff, 0x0c3f, 0x0c7f, 0x0cbf, + 0x0cff, 0x0d3f, 0x0d7f, 0x0dbf, 0x0dff, 0x0e3f, 0x0e7f, 0x0ebf, + 0x0eff, 0x0f3f, 0x0f7f, 0x0fbf, 0x0fff, 0x103f, 0x107f, 0x10bf, + 0x10ff, 0x117f, 0x11ff, 0x127f, 0x12ff, 0x133f, 0x137f, 0x13bf, + 0x13ff, 0x143f, 0x147f, 0x14bf, 0x14ff, 0x153f, 0x157f, 0x15ff, + 0x167f, 0x16ff, 0x177f, 0x17ff, 0x187f, 0x18ff, 0x193f, 0x197f, + 0x19bf, 0x19ff, 0x1a7f, 0x1aff, 0x1b7f, 0x1bff, 0x1c7f, 0x1cff, + 0x1d7f, 0x1dff, 0x1e7f, 0x1eff, 0x1f7f, 0x1fff, 0x207f, 0x20ff, + 0x217f, 0x21ff, 0x22ff, 0x237f, 0x23ff, 0x247f, 0x24ff, 0x25ff, + 0x26ff, 0x277f, 0x27ff, 0x287f, 0x28ff, 0x297f, 0x29ff, 0x2a7f, + 0x2aff, 0x2b7f, 0x2bff, 0x2c7f, 0x2cff, 0x2dff, 0x2eff, 0x2fff, + 0x30ff, 0x31ff, 0x32ff, 0x33ff, 0x347f, 0x34ff, 0x357f, 0x35ff, + 0x367f, 0x36ff, 0x377f, 0x37ff, 0x38ff, 0x39ff, 0x3aff, 0x3bff, + 0x3c7f, 0x3cff, 0x3d7f, 0x3dff, 0x3eff, 0x3fff, 0x40ff, 0x41ff, + 0x42ff, 0x43ff, 0x44ff, 0x45ff, 0x46ff, 0x47ff, 0x48ff, 0x49ff, + 0x4aff, 0x4bff, 0x4cff, 0x4dff, 0x4eff, 0x4fff, 0x50ff, 0x51ff, + 0x527f, 0x52ff, 0x53ff, 0x55ff, 0x56ff, 0x57ff, 0x58ff, 0x59ff, + 0x5aff, 0x5bff, 0x5dff, 0x5eff, 0x5fff, 0x60ff, 0x61ff, 0x62ff, + 0x63ff, 0x64ff, 0x65ff, 0x66ff, 0x677f, 0x67ff, 0x68ff, 0x69ff, + 0x6aff, 0x6bff, 0x6dff, 0x6fff, 0x71ff, 0x73ff, 0x75ff, 0x76ff, + 0x77ff, 0x78ff, 0x79ff, 0x7bff, 0x7dff, 0x7fff, 0x80ff, 0x81ff, + 0x83ff, 0x85ff, 0x86ff, 0x87ff, 0x88ff, 0x89ff, 0x8aff, 0x8bff, + 0x8dff, 0x8fff, 0x91ff, 0x92ff, 0x93ff, 0x94ff, 0x95ff, 0x97ff, + 0x99ff, 0x9bff, 0x9dff, 0x9fff, 0xa0ff, 0xa1ff, 0xa3ff, 0xa5ff, + 0xa7ff, 0xa9ff, 0xaaff, 0xabff, 0xadff, 0xafff, 0xb1ff, 0xb2ff, + 0xb3ff, 0xb5ff, 0xb7ff, 0xb9ff, 0xbbff, 0xbdff, 0xbfff, 0xc1ff, + 0xc3ff, 0xc5ff, 0xc7ff, 0xc9ff, 0xcbff, 0xcdff, 0xcfff, 0xd1ff, + 0xd3ff, 0xd5ff, 0xd7ff, 0xd9ff, 0xdbff, 0xddff, 0xdeff, 0xdfff, + 0xe1ff, 0xe3ff, 0xe4ff, 0xe5ff, 0xe6ff, 0xe7ff, 0xe87f, 0xe8ff, + 0xe9ff, 0xebff, 0xefff, 0xf3ff, 0xf5ff, 0xf7ff, 0xf9ff, 0xfbff, + 0xfdff, 0xffff +}; + static struct drm_color_lut srgb_inv_y[] = { - { 0x0, 0x0, 0x0, 0 }, - { 0xcc2, 0xcc2, 0xcc2, 0 }, - { 0x15be, 0x15be, 0x15be, 0 }, - { 0x1c56, 0x1c56, 0x1c56, 0 }, - { 0x21bd, 0x21bd, 0x21bd, 0 }, - { 0x2666, 0x2666, 0x2666, 0 }, - { 0x2a8a, 0x2a8a, 0x2a8a, 0 }, - { 0x2e4c, 0x2e4c, 0x2e4c, 0 }, - { 0x31c0, 0x31c0, 0x31c0, 0 }, - { 0x34f6, 0x34f6, 0x34f6, 0 }, - { 0x37f9, 0x37f9, 0x37f9, 0 }, - { 0x3acf, 0x3acf, 0x3acf, 0 }, - { 0x3d80, 0x3d80, 0x3d80, 0 }, - { 0x4010, 0x4010, 0x4010, 0 }, - { 0x4284, 0x4284, 0x4284, 0 }, - { 0x44dd, 0x44dd, 0x44dd, 0 }, - { 0x4720, 0x4720, 0x4720, 0 }, - { 0x494e, 0x494e, 0x494e, 0 }, - { 0x4b69, 0x4b69, 0x4b69, 0 }, - { 0x4d73, 0x4d73, 0x4d73, 0 }, - { 0x4f6e, 0x4f6e, 0x4f6e, 0 }, - { 0x5159, 0x5159, 0x5159, 0 }, - { 0x5337, 0x5337, 0x5337, 0 }, - { 0x5509, 0x5509, 0x5509, 0 }, - { 0x56cf, 0x56cf, 0x56cf, 0 }, - { 0x588a, 0x588a, 0x588a, 0 }, - { 0x5a3b, 0x5a3b, 0x5a3b, 0 }, - { 0x5be2, 0x5be2, 0x5be2, 0 }, - { 0x5d80, 0x5d80, 0x5d80, 0 }, - { 0x5f16, 0x5f16, 0x5f16, 0 }, - { 0x60a4, 0x60a4, 0x60a4, 0 }, - { 0x6229, 0x6229, 0x6229, 0 }, - { 0x63a8, 0x63a8, 0x63a8, 0 }, - { 0x6520, 0x6520, 0x6520, 0 }, - { 0x6691, 0x6691, 0x6691, 0 }, - { 0x67fc, 0x67fc, 0x67fc, 0 }, - { 0x6961, 0x6961, 0x6961, 0 }, - { 0x6ac0, 0x6ac0, 0x6ac0, 0 }, - { 0x6c19, 0x6c19, 0x6c19, 0 }, - { 0x6d6e, 0x6d6e, 0x6d6e, 0 }, - { 0x6ebd, 0x6ebd, 0x6ebd, 0 }, - { 0x7008, 0x7008, 0x7008, 0 }, - { 0x714d, 0x714d, 0x714d, 0 }, - { 0x728f, 0x728f, 0x728f, 0 }, - { 0x73cc, 0x73cc, 0x73cc, 0 }, - { 0x7504, 0x7504, 0x7504, 0 }, - { 0x7639, 0x7639, 0x7639, 0 }, - { 0x776a, 0x776a, 0x776a, 0 }, - { 0x7897, 0x7897, 0x7897, 0 }, - { 0x79c1, 0x79c1, 0x79c1, 0 }, - { 0x7ae7, 0x7ae7, 0x7ae7, 0 }, - { 0x7c09, 0x7c09, 0x7c09, 0 }, - { 0x7d28, 0x7d28, 0x7d28, 0 }, - { 0x7e44, 0x7e44, 0x7e44, 0 }, - { 0x7f5d, 0x7f5d, 0x7f5d, 0 }, - { 0x8073, 0x8073, 0x8073, 0 }, - { 0x8186, 0x8186, 0x8186, 0 }, - { 0x8296, 0x8296, 0x8296, 0 }, - { 0x83a4, 0x83a4, 0x83a4, 0 }, - { 0x84ae, 0x84ae, 0x84ae, 0 }, - { 0x85b6, 0x85b6, 0x85b6, 0 }, - { 0x86bc, 0x86bc, 0x86bc, 0 }, - { 0x87bf, 0x87bf, 0x87bf, 0 }, - { 0x88bf, 0x88bf, 0x88bf, 0 }, - { 0x89be, 0x89be, 0x89be, 0 }, - { 0x8ab9, 0x8ab9, 0x8ab9, 0 }, - { 0x8bb3, 0x8bb3, 0x8bb3, 0 }, - { 0x8cab, 0x8cab, 0x8cab, 0 }, - { 0x8da0, 0x8da0, 0x8da0, 0 }, - { 0x8e93, 0x8e93, 0x8e93, 0 }, - { 0x8f84, 0x8f84, 0x8f84, 0 }, - { 0x9073, 0x9073, 0x9073, 0 }, - { 0x9161, 0x9161, 0x9161, 0 }, - { 0x924c, 0x924c, 0x924c, 0 }, - { 0x9335, 0x9335, 0x9335, 0 }, - { 0x941d, 0x941d, 0x941d, 0 }, - { 0x9503, 0x9503, 0x9503, 0 }, - { 0x95e7, 0x95e7, 0x95e7, 0 }, - { 0x96c9, 0x96c9, 0x96c9, 0 }, - { 0x97aa, 0x97aa, 0x97aa, 0 }, - { 0x9889, 0x9889, 0x9889, 0 }, - { 0x9966, 0x9966, 0x9966, 0 }, - { 0x9a42, 0x9a42, 0x9a42, 0 }, - { 0x9b1c, 0x9b1c, 0x9b1c, 0 }, - { 0x9bf5, 0x9bf5, 0x9bf5, 0 }, - { 0x9ccc, 0x9ccc, 0x9ccc, 0 }, - { 0x9da1, 0x9da1, 0x9da1, 0 }, - { 0x9e76, 0x9e76, 0x9e76, 0 }, - { 0x9f49, 0x9f49, 0x9f49, 0 }, - { 0xa01a, 0xa01a, 0xa01a, 0 }, - { 0xa0ea, 0xa0ea, 0xa0ea, 0 }, - { 0xa1b9, 0xa1b9, 0xa1b9, 0 }, - { 0xa286, 0xa286, 0xa286, 0 }, - { 0xa352, 0xa352, 0xa352, 0 }, - { 0xa41d, 0xa41d, 0xa41d, 0 }, - { 0xa4e7, 0xa4e7, 0xa4e7, 0 }, - { 0xa5af, 0xa5af, 0xa5af, 0 }, - { 0xa676, 0xa676, 0xa676, 0 }, - { 0xa73c, 0xa73c, 0xa73c, 0 }, - { 0xa801, 0xa801, 0xa801, 0 }, - { 0xa8c5, 0xa8c5, 0xa8c5, 0 }, - { 0xa987, 0xa987, 0xa987, 0 }, - { 0xaa48, 0xaa48, 0xaa48, 0 }, - { 0xab09, 0xab09, 0xab09, 0 }, - { 0xabc8, 0xabc8, 0xabc8, 0 }, - { 0xac86, 0xac86, 0xac86, 0 }, - { 0xad43, 0xad43, 0xad43, 0 }, - { 0xadff, 0xadff, 0xadff, 0 }, - { 0xaeba, 0xaeba, 0xaeba, 0 }, - { 0xaf74, 0xaf74, 0xaf74, 0 }, - { 0xb02d, 0xb02d, 0xb02d, 0 }, - { 0xb0e5, 0xb0e5, 0xb0e5, 0 }, - { 0xb19c, 0xb19c, 0xb19c, 0 }, - { 0xb252, 0xb252, 0xb252, 0 }, - { 0xb307, 0xb307, 0xb307, 0 }, - { 0xb3bb, 0xb3bb, 0xb3bb, 0 }, - { 0xb46f, 0xb46f, 0xb46f, 0 }, - { 0xb521, 0xb521, 0xb521, 0 }, - { 0xb5d3, 0xb5d3, 0xb5d3, 0 }, - { 0xb683, 0xb683, 0xb683, 0 }, - { 0xb733, 0xb733, 0xb733, 0 }, - { 0xb7e2, 0xb7e2, 0xb7e2, 0 }, - { 0xb890, 0xb890, 0xb890, 0 }, - { 0xb93d, 0xb93d, 0xb93d, 0 }, - { 0xb9ea, 0xb9ea, 0xb9ea, 0 }, - { 0xba96, 0xba96, 0xba96, 0 }, - { 0xbb40, 0xbb40, 0xbb40, 0 }, - { 0xbbea, 0xbbea, 0xbbea, 0 }, - { 0xbc94, 0xbc94, 0xbc94, 0 }, - { 0xbd3c, 0xbd3c, 0xbd3c, 0 }, - { 0xbde4, 0xbde4, 0xbde4, 0 }, - { 0xbe8b, 0xbe8b, 0xbe8b, 0 }, - { 0xbf31, 0xbf31, 0xbf31, 0 }, - { 0xbfd7, 0xbfd7, 0xbfd7, 0 }, - { 0xc07b, 0xc07b, 0xc07b, 0 }, - { 0xc120, 0xc120, 0xc120, 0 }, - { 0xc1c3, 0xc1c3, 0xc1c3, 0 }, - { 0xc266, 0xc266, 0xc266, 0 }, - { 0xc308, 0xc308, 0xc308, 0 }, - { 0xc3a9, 0xc3a9, 0xc3a9, 0 }, - { 0xc449, 0xc449, 0xc449, 0 }, - { 0xc4e9, 0xc4e9, 0xc4e9, 0 }, - { 0xc589, 0xc589, 0xc589, 0 }, - { 0xc627, 0xc627, 0xc627, 0 }, - { 0xc6c5, 0xc6c5, 0xc6c5, 0 }, - { 0xc763, 0xc763, 0xc763, 0 }, - { 0xc7ff, 0xc7ff, 0xc7ff, 0 }, - { 0xc89b, 0xc89b, 0xc89b, 0 }, - { 0xc937, 0xc937, 0xc937, 0 }, - { 0xc9d2, 0xc9d2, 0xc9d2, 0 }, - { 0xca6c, 0xca6c, 0xca6c, 0 }, - { 0xcb06, 0xcb06, 0xcb06, 0 }, - { 0xcb9f, 0xcb9f, 0xcb9f, 0 }, - { 0xcc37, 0xcc37, 0xcc37, 0 }, - { 0xcccf, 0xcccf, 0xcccf, 0 }, - { 0xcd66, 0xcd66, 0xcd66, 0 }, - { 0xcdfd, 0xcdfd, 0xcdfd, 0 }, - { 0xce93, 0xce93, 0xce93, 0 }, - { 0xcf29, 0xcf29, 0xcf29, 0 }, - { 0xcfbe, 0xcfbe, 0xcfbe, 0 }, - { 0xd053, 0xd053, 0xd053, 0 }, - { 0xd0e7, 0xd0e7, 0xd0e7, 0 }, - { 0xd17a, 0xd17a, 0xd17a, 0 }, - { 0xd20d, 0xd20d, 0xd20d, 0 }, - { 0xd2a0, 0xd2a0, 0xd2a0, 0 }, - { 0xd331, 0xd331, 0xd331, 0 }, - { 0xd3c3, 0xd3c3, 0xd3c3, 0 }, - { 0xd454, 0xd454, 0xd454, 0 }, - { 0xd4e4, 0xd4e4, 0xd4e4, 0 }, - { 0xd574, 0xd574, 0xd574, 0 }, - { 0xd603, 0xd603, 0xd603, 0 }, - { 0xd692, 0xd692, 0xd692, 0 }, - { 0xd720, 0xd720, 0xd720, 0 }, - { 0xd7ae, 0xd7ae, 0xd7ae, 0 }, - { 0xd83c, 0xd83c, 0xd83c, 0 }, - { 0xd8c9, 0xd8c9, 0xd8c9, 0 }, - { 0xd955, 0xd955, 0xd955, 0 }, - { 0xd9e1, 0xd9e1, 0xd9e1, 0 }, - { 0xda6d, 0xda6d, 0xda6d, 0 }, - { 0xdaf8, 0xdaf8, 0xdaf8, 0 }, - { 0xdb83, 0xdb83, 0xdb83, 0 }, - { 0xdc0d, 0xdc0d, 0xdc0d, 0 }, - { 0xdc97, 0xdc97, 0xdc97, 0 }, - { 0xdd20, 0xdd20, 0xdd20, 0 }, - { 0xdda9, 0xdda9, 0xdda9, 0 }, - { 0xde31, 0xde31, 0xde31, 0 }, - { 0xdeb9, 0xdeb9, 0xdeb9, 0 }, - { 0xdf41, 0xdf41, 0xdf41, 0 }, - { 0xdfc8, 0xdfc8, 0xdfc8, 0 }, - { 0xe04f, 0xe04f, 0xe04f, 0 }, - { 0xe0d5, 0xe0d5, 0xe0d5, 0 }, - { 0xe15b, 0xe15b, 0xe15b, 0 }, - { 0xe1e0, 0xe1e0, 0xe1e0, 0 }, - { 0xe266, 0xe266, 0xe266, 0 }, - { 0xe2ea, 0xe2ea, 0xe2ea, 0 }, - { 0xe36f, 0xe36f, 0xe36f, 0 }, - { 0xe3f3, 0xe3f3, 0xe3f3, 0 }, - { 0xe476, 0xe476, 0xe476, 0 }, - { 0xe4f9, 0xe4f9, 0xe4f9, 0 }, - { 0xe57c, 0xe57c, 0xe57c, 0 }, - { 0xe5fe, 0xe5fe, 0xe5fe, 0 }, - { 0xe680, 0xe680, 0xe680, 0 }, - { 0xe702, 0xe702, 0xe702, 0 }, - { 0xe783, 0xe783, 0xe783, 0 }, - { 0xe804, 0xe804, 0xe804, 0 }, - { 0xe884, 0xe884, 0xe884, 0 }, - { 0xe905, 0xe905, 0xe905, 0 }, - { 0xe984, 0xe984, 0xe984, 0 }, - { 0xea04, 0xea04, 0xea04, 0 }, - { 0xea83, 0xea83, 0xea83, 0 }, - { 0xeb02, 0xeb02, 0xeb02, 0 }, - { 0xeb80, 0xeb80, 0xeb80, 0 }, - { 0xebfe, 0xebfe, 0xebfe, 0 }, - { 0xec7b, 0xec7b, 0xec7b, 0 }, - { 0xecf9, 0xecf9, 0xecf9, 0 }, - { 0xed76, 0xed76, 0xed76, 0 }, - { 0xedf2, 0xedf2, 0xedf2, 0 }, - { 0xee6f, 0xee6f, 0xee6f, 0 }, - { 0xeeeb, 0xeeeb, 0xeeeb, 0 }, - { 0xef66, 0xef66, 0xef66, 0 }, - { 0xefe2, 0xefe2, 0xefe2, 0 }, - { 0xf05d, 0xf05d, 0xf05d, 0 }, - { 0xf0d7, 0xf0d7, 0xf0d7, 0 }, - { 0xf152, 0xf152, 0xf152, 0 }, - { 0xf1cc, 0xf1cc, 0xf1cc, 0 }, - { 0xf245, 0xf245, 0xf245, 0 }, - { 0xf2bf, 0xf2bf, 0xf2bf, 0 }, - { 0xf338, 0xf338, 0xf338, 0 }, - { 0xf3b0, 0xf3b0, 0xf3b0, 0 }, - { 0xf429, 0xf429, 0xf429, 0 }, - { 0xf4a1, 0xf4a1, 0xf4a1, 0 }, - { 0xf519, 0xf519, 0xf519, 0 }, - { 0xf590, 0xf590, 0xf590, 0 }, - { 0xf608, 0xf608, 0xf608, 0 }, - { 0xf67e, 0xf67e, 0xf67e, 0 }, - { 0xf6f5, 0xf6f5, 0xf6f5, 0 }, - { 0xf76b, 0xf76b, 0xf76b, 0 }, - { 0xf7e1, 0xf7e1, 0xf7e1, 0 }, - { 0xf857, 0xf857, 0xf857, 0 }, - { 0xf8cd, 0xf8cd, 0xf8cd, 0 }, - { 0xf942, 0xf942, 0xf942, 0 }, - { 0xf9b7, 0xf9b7, 0xf9b7, 0 }, - { 0xfa2b, 0xfa2b, 0xfa2b, 0 }, - { 0xfaa0, 0xfaa0, 0xfaa0, 0 }, - { 0xfb14, 0xfb14, 0xfb14, 0 }, - { 0xfb88, 0xfb88, 0xfb88, 0 }, - { 0xfbfb, 0xfbfb, 0xfbfb, 0 }, - { 0xfc6e, 0xfc6e, 0xfc6e, 0 }, - { 0xfce1, 0xfce1, 0xfce1, 0 }, - { 0xfd54, 0xfd54, 0xfd54, 0 }, - { 0xfdc6, 0xfdc6, 0xfdc6, 0 }, - { 0xfe39, 0xfe39, 0xfe39, 0 }, - { 0xfeaa, 0xfeaa, 0xfeaa, 0 }, - { 0xff1c, 0xff1c, 0xff1c, 0 }, - { 0xff8d, 0xff8d, 0xff8d, 0 }, - { 0xffff, 0xffff, 0xffff, 0 }, + { 0x0000, 0x0000, 0x0000, 0 }, + { 0x0669, 0x0669, 0x0669, 0 }, + { 0x09a4, 0x09a4, 0x09a4, 0 }, + { 0x0a72, 0x0a72, 0x0a72, 0 }, + { 0x0ad6, 0x0ad6, 0x0ad6, 0 }, + { 0x0b38, 0x0b38, 0x0b38, 0 }, + { 0x0bf6, 0x0bf6, 0x0bf6, 0 }, + { 0x0cac, 0x0cac, 0x0cac, 0 }, + { 0x0d5c, 0x0d5c, 0x0d5c, 0 }, + { 0x0e06, 0x0e06, 0x0e06, 0 }, + { 0x0eaa, 0x0eaa, 0x0eaa, 0 }, + { 0x0f4a, 0x0f4a, 0x0f4a, 0 }, + { 0x0fe5, 0x0fe5, 0x0fe5, 0 }, + { 0x107b, 0x107b, 0x107b, 0 }, + { 0x110e, 0x110e, 0x110e, 0 }, + { 0x119d, 0x119d, 0x119d, 0 }, + { 0x1228, 0x1228, 0x1228, 0 }, + { 0x12b1, 0x12b1, 0x12b1, 0 }, + { 0x1336, 0x1336, 0x1336, 0 }, + { 0x13b8, 0x13b8, 0x13b8, 0 }, + { 0x1438, 0x1438, 0x1438, 0 }, + { 0x14b5, 0x14b5, 0x14b5, 0 }, + { 0x1530, 0x1530, 0x1530, 0 }, + { 0x15a9, 0x15a9, 0x15a9, 0 }, + { 0x161f, 0x161f, 0x161f, 0 }, + { 0x1693, 0x1693, 0x1693, 0 }, + { 0x1705, 0x1705, 0x1705, 0 }, + { 0x1776, 0x1776, 0x1776, 0 }, + { 0x1851, 0x1851, 0x1851, 0 }, + { 0x1926, 0x1926, 0x1926, 0 }, + { 0x19f4, 0x19f4, 0x19f4, 0 }, + { 0x1a59, 0x1a59, 0x1a59, 0 }, + { 0x1abd, 0x1abd, 0x1abd, 0 }, + { 0x1b81, 0x1b81, 0x1b81, 0 }, + { 0x1c3f, 0x1c3f, 0x1c3f, 0 }, + { 0x1c9d, 0x1c9d, 0x1c9d, 0 }, + { 0x1cf9, 0x1cf9, 0x1cf9, 0 }, + { 0x1d55, 0x1d55, 0x1d55, 0 }, + { 0x1daf, 0x1daf, 0x1daf, 0 }, + { 0x1e09, 0x1e09, 0x1e09, 0 }, + { 0x1e61, 0x1e61, 0x1e61, 0 }, + { 0x1f0f, 0x1f0f, 0x1f0f, 0 }, + { 0x1f65, 0x1f65, 0x1f65, 0 }, + { 0x1fb9, 0x1fb9, 0x1fb9, 0 }, + { 0x200d, 0x200d, 0x200d, 0 }, + { 0x2060, 0x2060, 0x2060, 0 }, + { 0x20b3, 0x20b3, 0x20b3, 0 }, + { 0x2104, 0x2104, 0x2104, 0 }, + { 0x21a5, 0x21a5, 0x21a5, 0 }, + { 0x2243, 0x2243, 0x2243, 0 }, + { 0x22de, 0x22de, 0x22de, 0 }, + { 0x2376, 0x2376, 0x2376, 0 }, + { 0x240c, 0x240c, 0x240c, 0 }, + { 0x24a0, 0x24a0, 0x24a0, 0 }, + { 0x2531, 0x2531, 0x2531, 0 }, + { 0x25c0, 0x25c0, 0x25c0, 0 }, + { 0x264c, 0x264c, 0x264c, 0 }, + { 0x26d7, 0x26d7, 0x26d7, 0 }, + { 0x2760, 0x2760, 0x2760, 0 }, + { 0x27e7, 0x27e7, 0x27e7, 0 }, + { 0x286c, 0x286c, 0x286c, 0 }, + { 0x28ef, 0x28ef, 0x28ef, 0 }, + { 0x2971, 0x2971, 0x2971, 0 }, + { 0x2a70, 0x2a70, 0x2a70, 0 }, + { 0x2b68, 0x2b68, 0x2b68, 0 }, + { 0x2be2, 0x2be2, 0x2be2, 0 }, + { 0x2c5a, 0x2c5a, 0x2c5a, 0 }, + { 0x2cd2, 0x2cd2, 0x2cd2, 0 }, + { 0x2d48, 0x2d48, 0x2d48, 0 }, + { 0x2e30, 0x2e30, 0x2e30, 0 }, + { 0x2ea2, 0x2ea2, 0x2ea2, 0 }, + { 0x2f13, 0x2f13, 0x2f13, 0 }, + { 0x2f83, 0x2f83, 0x2f83, 0 }, + { 0x2ff2, 0x2ff2, 0x2ff2, 0 }, + { 0x30cd, 0x30cd, 0x30cd, 0 }, + { 0x31a3, 0x31a3, 0x31a3, 0 }, + { 0x3276, 0x3276, 0x3276, 0 }, + { 0x3345, 0x3345, 0x3345, 0 }, + { 0x3410, 0x3410, 0x3410, 0 }, + { 0x34d8, 0x34d8, 0x34d8, 0 }, + { 0x359d, 0x359d, 0x359d, 0 }, + { 0x365e, 0x365e, 0x365e, 0 }, + { 0x36be, 0x36be, 0x36be, 0 }, + { 0x371d, 0x371d, 0x371d, 0 }, + { 0x37d9, 0x37d9, 0x37d9, 0 }, + { 0x3892, 0x3892, 0x3892, 0 }, + { 0x3949, 0x3949, 0x3949, 0 }, + { 0x39fd, 0x39fd, 0x39fd, 0 }, + { 0x3aaf, 0x3aaf, 0x3aaf, 0 }, + { 0x3b5e, 0x3b5e, 0x3b5e, 0 }, + { 0x3c0b, 0x3c0b, 0x3c0b, 0 }, + { 0x3cb6, 0x3cb6, 0x3cb6, 0 }, + { 0x3d5f, 0x3d5f, 0x3d5f, 0 }, + { 0x3e05, 0x3e05, 0x3e05, 0 }, + { 0x3eaa, 0x3eaa, 0x3eaa, 0 }, + { 0x3f4d, 0x3f4d, 0x3f4d, 0 }, + { 0x3fee, 0x3fee, 0x3fee, 0 }, + { 0x408d, 0x408d, 0x408d, 0 }, + { 0x412a, 0x412a, 0x412a, 0 }, + { 0x41c6, 0x41c6, 0x41c6, 0 }, + { 0x4260, 0x4260, 0x4260, 0 }, + { 0x42f9, 0x42f9, 0x42f9, 0 }, + { 0x4390, 0x4390, 0x4390, 0 }, + { 0x4425, 0x4425, 0x4425, 0 }, + { 0x44b9, 0x44b9, 0x44b9, 0 }, + { 0x454c, 0x454c, 0x454c, 0 }, + { 0x45dd, 0x45dd, 0x45dd, 0 }, + { 0x466d, 0x466d, 0x466d, 0 }, + { 0x46fb, 0x46fb, 0x46fb, 0 }, + { 0x4788, 0x4788, 0x4788, 0 }, + { 0x4814, 0x4814, 0x4814, 0 }, + { 0x489f, 0x489f, 0x489f, 0 }, + { 0x4928, 0x4928, 0x4928, 0 }, + { 0x4a38, 0x4a38, 0x4a38, 0 }, + { 0x4b43, 0x4b43, 0x4b43, 0 }, + { 0x4c49, 0x4c49, 0x4c49, 0 }, + { 0x4d4c, 0x4d4c, 0x4d4c, 0 }, + { 0x4dcc, 0x4dcc, 0x4dcc, 0 }, + { 0x4e4a, 0x4e4a, 0x4e4a, 0 }, + { 0x4ec8, 0x4ec8, 0x4ec8, 0 }, + { 0x4f45, 0x4f45, 0x4f45, 0 }, + { 0x4fc1, 0x4fc1, 0x4fc1, 0 }, + { 0x503c, 0x503c, 0x503c, 0 }, + { 0x50b7, 0x50b7, 0x50b7, 0 }, + { 0x5130, 0x5130, 0x5130, 0 }, + { 0x51a9, 0x51a9, 0x51a9, 0 }, + { 0x5220, 0x5220, 0x5220, 0 }, + { 0x530e, 0x530e, 0x530e, 0 }, + { 0x53f8, 0x53f8, 0x53f8, 0 }, + { 0x54df, 0x54df, 0x54df, 0 }, + { 0x55c3, 0x55c3, 0x55c3, 0 }, + { 0x56a4, 0x56a4, 0x56a4, 0 }, + { 0x5782, 0x5782, 0x5782, 0 }, + { 0x585e, 0x585e, 0x585e, 0 }, + { 0x58cb, 0x58cb, 0x58cb, 0 }, + { 0x5937, 0x5937, 0x5937, 0 }, + { 0x59a3, 0x59a3, 0x59a3, 0 }, + { 0x5a0e, 0x5a0e, 0x5a0e, 0 }, + { 0x5ae3, 0x5ae3, 0x5ae3, 0 }, + { 0x5bb5, 0x5bb5, 0x5bb5, 0 }, + { 0x5c85, 0x5c85, 0x5c85, 0 }, + { 0x5d52, 0x5d52, 0x5d52, 0 }, + { 0x5e1e, 0x5e1e, 0x5e1e, 0 }, + { 0x5ee8, 0x5ee8, 0x5ee8, 0 }, + { 0x5faf, 0x5faf, 0x5faf, 0 }, + { 0x6074, 0x6074, 0x6074, 0 }, + { 0x6138, 0x6138, 0x6138, 0 }, + { 0x61fa, 0x61fa, 0x61fa, 0 }, + { 0x62ba, 0x62ba, 0x62ba, 0 }, + { 0x6378, 0x6378, 0x6378, 0 }, + { 0x6434, 0x6434, 0x6434, 0 }, + { 0x64ef, 0x64ef, 0x64ef, 0 }, + { 0x65a8, 0x65a8, 0x65a8, 0 }, + { 0x6660, 0x6660, 0x6660, 0 }, + { 0x67ca, 0x67ca, 0x67ca, 0 }, + { 0x687d, 0x687d, 0x687d, 0 }, + { 0x692e, 0x692e, 0x692e, 0 }, + { 0x69de, 0x69de, 0x69de, 0 }, + { 0x6a8d, 0x6a8d, 0x6a8d, 0 }, + { 0x6be6, 0x6be6, 0x6be6, 0 }, + { 0x6d3a, 0x6d3a, 0x6d3a, 0 }, + { 0x6de2, 0x6de2, 0x6de2, 0 }, + { 0x6e88, 0x6e88, 0x6e88, 0 }, + { 0x6f2e, 0x6f2e, 0x6f2e, 0 }, + { 0x6fd2, 0x6fd2, 0x6fd2, 0 }, + { 0x7076, 0x7076, 0x7076, 0 }, + { 0x7118, 0x7118, 0x7118, 0 }, + { 0x71b9, 0x71b9, 0x71b9, 0 }, + { 0x7258, 0x7258, 0x7258, 0 }, + { 0x72f7, 0x72f7, 0x72f7, 0 }, + { 0x7395, 0x7395, 0x7395, 0 }, + { 0x7432, 0x7432, 0x7432, 0 }, + { 0x74cd, 0x74cd, 0x74cd, 0 }, + { 0x7602, 0x7602, 0x7602, 0 }, + { 0x7732, 0x7732, 0x7732, 0 }, + { 0x785f, 0x785f, 0x785f, 0 }, + { 0x7988, 0x7988, 0x7988, 0 }, + { 0x7aad, 0x7aad, 0x7aad, 0 }, + { 0x7bcf, 0x7bcf, 0x7bcf, 0 }, + { 0x7cee, 0x7cee, 0x7cee, 0 }, + { 0x7d7c, 0x7d7c, 0x7d7c, 0 }, + { 0x7e09, 0x7e09, 0x7e09, 0 }, + { 0x7e96, 0x7e96, 0x7e96, 0 }, + { 0x7f22, 0x7f22, 0x7f22, 0 }, + { 0x7fad, 0x7fad, 0x7fad, 0 }, + { 0x8037, 0x8037, 0x8037, 0 }, + { 0x80c1, 0x80c1, 0x80c1, 0 }, + { 0x814a, 0x814a, 0x814a, 0 }, + { 0x825a, 0x825a, 0x825a, 0 }, + { 0x8367, 0x8367, 0x8367, 0 }, + { 0x8471, 0x8471, 0x8471, 0 }, + { 0x8578, 0x8578, 0x8578, 0 }, + { 0x85fb, 0x85fb, 0x85fb, 0 }, + { 0x867d, 0x867d, 0x867d, 0 }, + { 0x86ff, 0x86ff, 0x86ff, 0 }, + { 0x8780, 0x8780, 0x8780, 0 }, + { 0x8880, 0x8880, 0x8880, 0 }, + { 0x897e, 0x897e, 0x897e, 0 }, + { 0x8a7a, 0x8a7a, 0x8a7a, 0 }, + { 0x8b73, 0x8b73, 0x8b73, 0 }, + { 0x8c6a, 0x8c6a, 0x8c6a, 0 }, + { 0x8d5f, 0x8d5f, 0x8d5f, 0 }, + { 0x8e52, 0x8e52, 0x8e52, 0 }, + { 0x8f42, 0x8f42, 0x8f42, 0 }, + { 0x9031, 0x9031, 0x9031, 0 }, + { 0x911e, 0x911e, 0x911e, 0 }, + { 0x9209, 0x9209, 0x9209, 0 }, + { 0x92f2, 0x92f2, 0x92f2, 0 }, + { 0x93d9, 0x93d9, 0x93d9, 0 }, + { 0x94bf, 0x94bf, 0x94bf, 0 }, + { 0x95a2, 0x95a2, 0x95a2, 0 }, + { 0x9684, 0x9684, 0x9684, 0 }, + { 0x9764, 0x9764, 0x9764, 0 }, + { 0x9843, 0x9843, 0x9843, 0 }, + { 0x9920, 0x9920, 0x9920, 0 }, + { 0x99fb, 0x99fb, 0x99fb, 0 }, + { 0x9a69, 0x9a69, 0x9a69, 0 }, + { 0x9ad5, 0x9ad5, 0x9ad5, 0 }, + { 0x9bae, 0x9bae, 0x9bae, 0 }, + { 0x9d5a, 0x9d5a, 0x9d5a, 0 }, + { 0x9e2e, 0x9e2e, 0x9e2e, 0 }, + { 0x9f00, 0x9f00, 0x9f00, 0 }, + { 0x9fd1, 0x9fd1, 0x9fd1, 0 }, + { 0xa0a1, 0xa0a1, 0xa0a1, 0 }, + { 0xa16f, 0xa16f, 0xa16f, 0 }, + { 0xa23d, 0xa23d, 0xa23d, 0 }, + { 0xa3d3, 0xa3d3, 0xa3d3, 0 }, + { 0xa49c, 0xa49c, 0xa49c, 0 }, + { 0xa564, 0xa564, 0xa564, 0 }, + { 0xa62b, 0xa62b, 0xa62b, 0 }, + { 0xa6f1, 0xa6f1, 0xa6f1, 0 }, + { 0xa7b5, 0xa7b5, 0xa7b5, 0 }, + { 0xa878, 0xa878, 0xa878, 0 }, + { 0xa93b, 0xa93b, 0xa93b, 0 }, + { 0xa9fc, 0xa9fc, 0xa9fc, 0 }, + { 0xaabb, 0xaabb, 0xaabb, 0 }, + { 0xab1b, 0xab1b, 0xab1b, 0 }, + { 0xab7a, 0xab7a, 0xab7a, 0 }, + { 0xac38, 0xac38, 0xac38, 0 }, + { 0xacf5, 0xacf5, 0xacf5, 0 }, + { 0xadb1, 0xadb1, 0xadb1, 0 }, + { 0xae6b, 0xae6b, 0xae6b, 0 }, + { 0xafde, 0xafde, 0xafde, 0 }, + { 0xb14c, 0xb14c, 0xb14c, 0 }, + { 0xb2b7, 0xb2b7, 0xb2b7, 0 }, + { 0xb41e, 0xb41e, 0xb41e, 0 }, + { 0xb581, 0xb581, 0xb581, 0 }, + { 0xb631, 0xb631, 0xb631, 0 }, + { 0xb6e1, 0xb6e1, 0xb6e1, 0 }, + { 0xb790, 0xb790, 0xb790, 0 }, + { 0xb83d, 0xb83d, 0xb83d, 0 }, + { 0xb997, 0xb997, 0xb997, 0 }, + { 0xbaed, 0xbaed, 0xbaed, 0 }, + { 0xbc3f, 0xbc3f, 0xbc3f, 0 }, + { 0xbce8, 0xbce8, 0xbce8, 0 }, + { 0xbd8f, 0xbd8f, 0xbd8f, 0 }, + { 0xbedc, 0xbedc, 0xbedc, 0 }, + { 0xc025, 0xc025, 0xc025, 0 }, + { 0xc0c9, 0xc0c9, 0xc0c9, 0 }, + { 0xc16c, 0xc16c, 0xc16c, 0 }, + { 0xc20f, 0xc20f, 0xc20f, 0 }, + { 0xc2b0, 0xc2b0, 0xc2b0, 0 }, + { 0xc352, 0xc352, 0xc352, 0 }, + { 0xc3f2, 0xc3f2, 0xc3f2, 0 }, + { 0xc531, 0xc531, 0xc531, 0 }, + { 0xc66d, 0xc66d, 0xc66d, 0 }, + { 0xc7a6, 0xc7a6, 0xc7a6, 0 }, + { 0xc842, 0xc842, 0xc842, 0 }, + { 0xc8dd, 0xc8dd, 0xc8dd, 0 }, + { 0xc978, 0xc978, 0xc978, 0 }, + { 0xca12, 0xca12, 0xca12, 0 }, + { 0xcb44, 0xcb44, 0xcb44, 0 }, + { 0xcc74, 0xcc74, 0xcc74, 0 }, + { 0xcda2, 0xcda2, 0xcda2, 0 }, + { 0xcecd, 0xcecd, 0xcecd, 0 }, + { 0xcff6, 0xcff6, 0xcff6, 0 }, + { 0xd08a, 0xd08a, 0xd08a, 0 }, + { 0xd11d, 0xd11d, 0xd11d, 0 }, + { 0xd242, 0xd242, 0xd242, 0 }, + { 0xd365, 0xd365, 0xd365, 0 }, + { 0xd486, 0xd486, 0xd486, 0 }, + { 0xd5a4, 0xd5a4, 0xd5a4, 0 }, + { 0xd633, 0xd633, 0xd633, 0 }, + { 0xd6c1, 0xd6c1, 0xd6c1, 0 }, + { 0xd7dc, 0xd7dc, 0xd7dc, 0 }, + { 0xd8f5, 0xd8f5, 0xd8f5, 0 }, + { 0xda0c, 0xda0c, 0xda0c, 0 }, + { 0xda97, 0xda97, 0xda97, 0 }, + { 0xdb21, 0xdb21, 0xdb21, 0 }, + { 0xdc35, 0xdc35, 0xdc35, 0 }, + { 0xdd47, 0xdd47, 0xdd47, 0 }, + { 0xde57, 0xde57, 0xde57, 0 }, + { 0xdf65, 0xdf65, 0xdf65, 0 }, + { 0xe072, 0xe072, 0xe072, 0 }, + { 0xe17d, 0xe17d, 0xe17d, 0 }, + { 0xe286, 0xe286, 0xe286, 0 }, + { 0xe38e, 0xe38e, 0xe38e, 0 }, + { 0xe494, 0xe494, 0xe494, 0 }, + { 0xe599, 0xe599, 0xe599, 0 }, + { 0xe69c, 0xe69c, 0xe69c, 0 }, + { 0xe79e, 0xe79e, 0xe79e, 0 }, + { 0xe89e, 0xe89e, 0xe89e, 0 }, + { 0xe99d, 0xe99d, 0xe99d, 0 }, + { 0xea9a, 0xea9a, 0xea9a, 0 }, + { 0xeb96, 0xeb96, 0xeb96, 0 }, + { 0xec90, 0xec90, 0xec90, 0 }, + { 0xed8a, 0xed8a, 0xed8a, 0 }, + { 0xee82, 0xee82, 0xee82, 0 }, + { 0xef78, 0xef78, 0xef78, 0 }, + { 0xf06d, 0xf06d, 0xf06d, 0 }, + { 0xf0e7, 0xf0e7, 0xf0e7, 0 }, + { 0xf161, 0xf161, 0xf161, 0 }, + { 0xf254, 0xf254, 0xf254, 0 }, + { 0xf345, 0xf345, 0xf345, 0 }, + { 0xf3be, 0xf3be, 0xf3be, 0 }, + { 0xf435, 0xf435, 0xf435, 0 }, + { 0xf4ad, 0xf4ad, 0xf4ad, 0 }, + { 0xf524, 0xf524, 0xf524, 0 }, + { 0xf560, 0xf560, 0xf560, 0 }, + { 0xf59b, 0xf59b, 0xf59b, 0 }, + { 0xf612, 0xf612, 0xf612, 0 }, + { 0xf6ff, 0xf6ff, 0xf6ff, 0 }, + { 0xf8d5, 0xf8d5, 0xf8d5, 0 }, + { 0xfaa6, 0xfaa6, 0xfaa6, 0 }, + { 0xfb8d, 0xfb8d, 0xfb8d, 0 }, + { 0xfc72, 0xfc72, 0xfc72, 0 }, + { 0xfd57, 0xfd57, 0xfd57, 0 }, + { 0xfe3b, 0xfe3b, 0xfe3b, 0 }, + { 0xff1d, 0xff1d, 0xff1d, 0 }, + { 0xffff, 0xffff, 0xffff, 0 } }; -static_assert(ARRAY_SIZE(linear_x) == ARRAY_SIZE(srgb_inv_y), +static_assert(ARRAY_SIZE(srgb_inv_x) == ARRAY_SIZE(srgb_inv_y), "srgb_inv x and y must have the same number of entries"); const struct vkms_color_lut srgb_inv_eotf = { - .x = linear_x, + .x = srgb_inv_x, .y = srgb_inv_y, .lut_length = ARRAY_SIZE(srgb_inv_y) }; -- 2.56.0 ^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2026-11-06 20:19 UTC | newest] Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2026-11-06 20:18 [PATCH v2 00/12] drm/vkms: improve color curve LUTs precision Leandro Ribeiro 2026-11-06 20:18 ` [PATCH v2 01/12] drm/vkms: rename VKMS_LUT_SIZE to VKMS_GAMMA_LUT_SIZE Leandro Ribeiro 2026-11-06 20:18 ` [PATCH v2 02/12] vkms: properly compute gamma LUT size in vkms_atomic_check() Leandro Ribeiro 2026-11-06 20:18 ` [PATCH v2 03/12] drm/vkms: allow color curve LUTs to have different sizes Leandro Ribeiro 2026-11-06 20:18 ` [PATCH v2 04/12] drm/vkms: remove TEST_LUT_SIZE Leandro Ribeiro 2026-11-06 20:18 ` [PATCH v2 05/12] drm/vkms: remove linear_eotf Leandro Ribeiro 2026-11-06 20:18 ` [PATCH v2 06/12] drm/vkms: improve the way in which we access LUT member Leandro Ribeiro 2026-11-06 20:18 ` [PATCH v2 07/12] drm/vkms: rename struct vkms_color_lut::base to y Leandro Ribeiro 2026-11-06 20:18 ` [PATCH v2 08/12] drm/vkms: rename get_lut_index() to get_uniform_lut_index() Leandro Ribeiro 2026-11-06 20:18 ` [PATCH v2 09/12] drm/vkms: add support to non-uniform LUT for internal color curves Leandro Ribeiro 2026-11-06 20:18 ` [PATCH v2 10/12] drm/vkms: test sRGB and inverse sRGB LUTs using more samples Leandro Ribeiro 2026-11-06 20:18 ` [PATCH v2 11/12] drm/vkms: add script to create optimized LUTs for color curves Leandro Ribeiro 2026-11-06 20:18 ` [PATCH v2 12/12] drm/vkms: replace uniform sRGB LUT and its inverse with optimal ones Leandro Ribeiro
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®