* [PATCH 00/11] drm/vkms: improve color curve LUTs precision
@ 2026-08-04 20:33 Leandro Ribeiro
2026-08-04 20:33 ` [PATCH 01/11] drm/vkms: rename VKMS_LUT_SIZE to VKMS_GAMMA_LUT_SIZE Leandro Ribeiro
` (10 more replies)
0 siblings, 11 replies; 17+ messages in thread
From: Leandro Ribeiro @ 2026-08-04 20:33 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 was 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.
Leandro Ribeiro (11):
drm/vkms: rename VKMS_LUT_SIZE to VKMS_GAMMA_LUT_SIZE
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 | 561 +++++++
drivers/gpu/drm/vkms/tests/vkms_color_test.c | 46 +-
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 | 2 +-
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, 1383 insertions(+), 844 deletions(-)
create mode 100644 drivers/gpu/drm/vkms/scripts/color-curve-lut.py
--
2.55.0
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 01/11] drm/vkms: rename VKMS_LUT_SIZE to VKMS_GAMMA_LUT_SIZE
2026-08-04 20:33 [PATCH 00/11] drm/vkms: improve color curve LUTs precision Leandro Ribeiro
@ 2026-08-04 20:33 ` Leandro Ribeiro
2026-08-04 20:41 ` sashiko-bot
2026-08-04 20:33 ` [PATCH 02/11] drm/vkms: allow color curve LUTs to have different sizes Leandro Ribeiro
` (9 subsequent siblings)
10 siblings, 1 reply; 17+ messages in thread
From: Leandro Ribeiro @ 2026-08-04 20:33 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.
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 079abfba427d..54ebb112b3b3 100644
--- a/drivers/gpu/drm/vkms/vkms_crtc.c
+++ b/drivers/gpu/drm/vkms/vkms_crtc.c
@@ -220,13 +220,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 0933e4ce0ff0..1975843abe92 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.55.0
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH 02/11] drm/vkms: allow color curve LUTs to have different sizes
2026-08-04 20:33 [PATCH 00/11] drm/vkms: improve color curve LUTs precision Leandro Ribeiro
2026-08-04 20:33 ` [PATCH 01/11] drm/vkms: rename VKMS_LUT_SIZE to VKMS_GAMMA_LUT_SIZE Leandro Ribeiro
@ 2026-08-04 20:33 ` Leandro Ribeiro
2026-08-04 20:33 ` [PATCH 03/11] drm/vkms: remove TEST_LUT_SIZE Leandro Ribeiro
` (8 subsequent siblings)
10 siblings, 0 replies; 17+ messages in thread
From: Leandro Ribeiro @ 2026-08-04 20:33 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.
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.55.0
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH 03/11] drm/vkms: remove TEST_LUT_SIZE
2026-08-04 20:33 [PATCH 00/11] drm/vkms: improve color curve LUTs precision Leandro Ribeiro
2026-08-04 20:33 ` [PATCH 01/11] drm/vkms: rename VKMS_LUT_SIZE to VKMS_GAMMA_LUT_SIZE Leandro Ribeiro
2026-08-04 20:33 ` [PATCH 02/11] drm/vkms: allow color curve LUTs to have different sizes Leandro Ribeiro
@ 2026-08-04 20:33 ` Leandro Ribeiro
2026-08-04 20:33 ` [PATCH 04/11] drm/vkms: remove linear_eotf Leandro Ribeiro
` (7 subsequent siblings)
10 siblings, 0 replies; 17+ messages in thread
From: Leandro Ribeiro @ 2026-08-04 20:33 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.
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.55.0
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH 04/11] drm/vkms: remove linear_eotf
2026-08-04 20:33 [PATCH 00/11] drm/vkms: improve color curve LUTs precision Leandro Ribeiro
` (2 preceding siblings ...)
2026-08-04 20:33 ` [PATCH 03/11] drm/vkms: remove TEST_LUT_SIZE Leandro Ribeiro
@ 2026-08-04 20:33 ` Leandro Ribeiro
2026-08-04 20:42 ` sashiko-bot
2026-08-04 20:33 ` [PATCH 05/11] drm/vkms: improve the way in which we access LUT member Leandro Ribeiro
` (6 subsequent siblings)
10 siblings, 1 reply; 17+ messages in thread
From: Leandro Ribeiro @ 2026-08-04 20:33 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 achieve the same
using test_linear_lut, so let's drop it.
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 | 266 -------------------
drivers/gpu/drm/vkms/vkms_luts.h | 1 -
3 files changed, 2 insertions(+), 269 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..28614edb8eb1 100644
--- a/drivers/gpu/drm/vkms/tests/vkms_color_test.c
+++ b/drivers/gpu/drm/vkms/tests/vkms_color_test.c
@@ -126,8 +126,8 @@ 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 * 0x101, LUT_RED);
KUNIT_EXPECT_EQ(test, DIV_ROUND_CLOSEST(linear, 0x101), 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.55.0
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH 05/11] drm/vkms: improve the way in which we access LUT member
2026-08-04 20:33 [PATCH 00/11] drm/vkms: improve color curve LUTs precision Leandro Ribeiro
` (3 preceding siblings ...)
2026-08-04 20:33 ` [PATCH 04/11] drm/vkms: remove linear_eotf Leandro Ribeiro
@ 2026-08-04 20:33 ` Leandro Ribeiro
2026-08-04 20:33 ` [PATCH 06/11] drm/vkms: rename struct vkms_color_lut::base to y Leandro Ribeiro
` (5 subsequent siblings)
10 siblings, 0 replies; 17+ messages in thread
From: Leandro Ribeiro @ 2026-08-04 20:33 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.
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 83d217085ad0..bd539ee4c5be 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.55.0
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH 06/11] drm/vkms: rename struct vkms_color_lut::base to y
2026-08-04 20:33 [PATCH 00/11] drm/vkms: improve color curve LUTs precision Leandro Ribeiro
` (4 preceding siblings ...)
2026-08-04 20:33 ` [PATCH 05/11] drm/vkms: improve the way in which we access LUT member Leandro Ribeiro
@ 2026-08-04 20:33 ` Leandro Ribeiro
2026-08-04 20:52 ` sashiko-bot
2026-08-04 20:33 ` [PATCH 07/11] drm/vkms: rename get_lut_index() to get_uniform_lut_index() Leandro Ribeiro
` (4 subsequent siblings)
10 siblings, 1 reply; 17+ messages in thread
From: Leandro Ribeiro @ 2026-08-04 20:33 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.
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 28614edb8eb1..cfcd7e8e7640 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 bd539ee4c5be..a022554e4b1a 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)
@@ -641,7 +641,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);
@@ -649,7 +649,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 1975843abe92..55a3ea184e44 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.55.0
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH 07/11] drm/vkms: rename get_lut_index() to get_uniform_lut_index()
2026-08-04 20:33 [PATCH 00/11] drm/vkms: improve color curve LUTs precision Leandro Ribeiro
` (5 preceding siblings ...)
2026-08-04 20:33 ` [PATCH 06/11] drm/vkms: rename struct vkms_color_lut::base to y Leandro Ribeiro
@ 2026-08-04 20:33 ` Leandro Ribeiro
2026-08-04 20:47 ` sashiko-bot
2026-08-04 20:33 ` [PATCH 08/11] drm/vkms: add support to non-uniform LUT for internal color curves Leandro Ribeiro
` (3 subsequent siblings)
10 siblings, 1 reply; 17+ messages in thread
From: Leandro Ribeiro @ 2026-08-04 20:33 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.
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 cfcd7e8e7640..bb9d84377b97 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 a022554e4b1a..1a5e899e5b4a 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.55.0
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH 08/11] drm/vkms: add support to non-uniform LUT for internal color curves
2026-08-04 20:33 [PATCH 00/11] drm/vkms: improve color curve LUTs precision Leandro Ribeiro
` (6 preceding siblings ...)
2026-08-04 20:33 ` [PATCH 07/11] drm/vkms: rename get_lut_index() to get_uniform_lut_index() Leandro Ribeiro
@ 2026-08-04 20:33 ` Leandro Ribeiro
2026-08-04 20:33 ` [PATCH 09/11] drm/vkms: test sRGB and inverse sRGB LUTs using more samples Leandro Ribeiro
` (2 subsequent siblings)
10 siblings, 0 replies; 17+ messages in thread
From: Leandro Ribeiro @ 2026-08-04 20:33 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.
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 bb9d84377b97..571b1b579310 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 1a5e899e5b4a..4ae1ffd31406 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 55a3ea184e44..be81844dfd22 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.55.0
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH 09/11] drm/vkms: test sRGB and inverse sRGB LUTs using more samples
2026-08-04 20:33 [PATCH 00/11] drm/vkms: improve color curve LUTs precision Leandro Ribeiro
` (7 preceding siblings ...)
2026-08-04 20:33 ` [PATCH 08/11] drm/vkms: add support to non-uniform LUT for internal color curves Leandro Ribeiro
@ 2026-08-04 20:33 ` Leandro Ribeiro
2026-08-04 20:33 ` [PATCH 10/11] drm/vkms: add script to create optimized LUTs for color curves Leandro Ribeiro
2026-08-04 20:33 ` [PATCH 11/11] drm/vkms: replace uniform sRGB LUT and its inverse with optimal ones Leandro Ribeiro
10 siblings, 0 replies; 17+ messages in thread
From: Leandro Ribeiro @ 2026-08-04 20:33 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.
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 571b1b579310..78f67bba33b5 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.55.0
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH 10/11] drm/vkms: add script to create optimized LUTs for color curves
2026-08-04 20:33 [PATCH 00/11] drm/vkms: improve color curve LUTs precision Leandro Ribeiro
` (8 preceding siblings ...)
2026-08-04 20:33 ` [PATCH 09/11] drm/vkms: test sRGB and inverse sRGB LUTs using more samples Leandro Ribeiro
@ 2026-08-04 20:33 ` Leandro Ribeiro
2026-08-04 20:47 ` sashiko-bot
2026-08-04 20:33 ` [PATCH 11/11] drm/vkms: replace uniform sRGB LUT and its inverse with optimal ones Leandro Ribeiro
10 siblings, 1 reply; 17+ messages in thread
From: Leandro Ribeiro @ 2026-08-04 20:33 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.
Signed-off-by: Leandro Ribeiro <leandro.ribeiro@collabora.com>
---
.../gpu/drm/vkms/scripts/color-curve-lut.py | 561 ++++++++++++++++++
1 file changed, 561 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..f80e67120f5b
--- /dev/null
+++ b/drivers/gpu/drm/vkms/scripts/color-curve-lut.py
@@ -0,0 +1,561 @@
+# 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
+import matplotlib.pyplot as plt
+
+
+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>")
+ 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}")
+ print(" -h, --help Show this help message and exit")
+ sys.exit(1)
+
+
+def parse_cli_params(args, function_table):
+ """
+ Parse cli params from users
+ """
+ if len(args) != 3:
+ print_help_and_quit(function_table)
+
+ 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
+
+
+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 = 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)
+
+ # 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.55.0
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH 11/11] drm/vkms: replace uniform sRGB LUT and its inverse with optimal ones
2026-08-04 20:33 [PATCH 00/11] drm/vkms: improve color curve LUTs precision Leandro Ribeiro
` (9 preceding siblings ...)
2026-08-04 20:33 ` [PATCH 10/11] drm/vkms: add script to create optimized LUTs for color curves Leandro Ribeiro
@ 2026-08-04 20:33 ` Leandro Ribeiro
10 siblings, 0 replies; 17+ messages in thread
From: Leandro Ribeiro @ 2026-08-04 20:33 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.
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 78f67bba33b5..0b3a652d311b 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.55.0
^ permalink raw reply related [flat|nested] 17+ messages in thread
* Re: [PATCH 01/11] drm/vkms: rename VKMS_LUT_SIZE to VKMS_GAMMA_LUT_SIZE
2026-08-04 20:33 ` [PATCH 01/11] drm/vkms: rename VKMS_LUT_SIZE to VKMS_GAMMA_LUT_SIZE Leandro Ribeiro
@ 2026-08-04 20:41 ` sashiko-bot
0 siblings, 0 replies; 17+ messages in thread
From: sashiko-bot @ 2026-08-04 20:41 UTC (permalink / raw)
To: Leandro Ribeiro; +Cc: dri-devel
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] Incorrect size calculation for gamma_lut validation causes atomic commits to be rejected on 32-bit systems.
--
--- Patch [1]: [PATCH 01/11] drm/vkms: rename VKMS_LUT_SIZE to VKMS_GAMMA_LUT_SIZE ---
commit 2362b93c64416bccb5039e7ee169799f46cd254c
Author: Leandro Ribeiro <leandro.ribeiro@collabora.com>
drm/vkms: rename VKMS_LUT_SIZE to VKMS_GAMMA_LUT_SIZE
This commit renames VKMS_LUT_SIZE to VKMS_GAMMA_LUT_SIZE to clarify that it
represents the size of the CRTC gamma LUT.
> diff --git a/drivers/gpu/drm/vkms/vkms_drv.c b/drivers/gpu/drm/vkms/vkms_drv.c
> index 5a640b531d88f..86a8a95694fd7 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)
[Severity: High]
This is a pre-existing issue, but does this calculation incorrectly reject
atomic commits with valid gamma LUTs on 32-bit systems?
Looking at vkms_atomic_check() in drivers/gpu/drm/vkms/vkms_drv.c, it
divides the length by the size of a pointer (sizeof(struct drm_color_lut *))
rather than the actual struct size (sizeof(struct drm_color_lut)).
On 32-bit architectures, the pointer size is 4 bytes, while the struct itself
is 8 bytes. When userspace provides a valid 256-element LUT (2048 bytes), this
division calculates the length as 512 elements. This would exceed the
VKMS_GAMMA_LUT_SIZE of 256, causing the atomic check to incorrectly fail
with -EINVAL.
> return -EINVAL;
> }
>
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260804203351.148521-1-leandro.ribeiro@collabora.com?part=1
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 04/11] drm/vkms: remove linear_eotf
2026-08-04 20:33 ` [PATCH 04/11] drm/vkms: remove linear_eotf Leandro Ribeiro
@ 2026-08-04 20:42 ` sashiko-bot
0 siblings, 0 replies; 17+ messages in thread
From: sashiko-bot @ 2026-08-04 20:42 UTC (permalink / raw)
To: Leandro Ribeiro; +Cc: dri-devel
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] The `vkms_color_test_linear` KUnit test loop relies on a hardcoded multiplier of `0x101` that was designed for a 256-element LUT. The patch replaces `linear_eotf` (256 elements) with `test_linear_lut` (16 elements) without adjusting the multiplier. Since the loop now only executes 16 times (`i` from 0 to 15), the evaluated channel values only range from `0x0000` to `0x0F0F` (~5.8% of the 16-bit color space). The test fails to exercise the remaining 94% of the color range and leaves 14 out of the 16 elements of `test_linear_lut` completely untested. To restore proper test coverage over the `0x0000` to `0xFFFF` range, both instances of `0x101` should be updated to `0x1111` (since `15 * 0x1111 = 0xFFFF`).
--
--- Patch [4]: [PATCH 04/11] drm/vkms: remove linear_eotf ---
commit e4769cf1ca6d6dd3c89f50766f7a24a69c53cccb
Author: Leandro Ribeiro <leandro.ribeiro@collabora.com>
drm/vkms: remove linear_eotf
This patch removes the linear_eotf LUT, which was only used for testing,
and updates the kunit color tests to use test_linear_lut instead.
> diff --git a/drivers/gpu/drm/vkms/tests/vkms_color_test.c b/drivers/gpu/drm/vkms/tests/vkms_color_test.c
> index 3489513af3527..28614edb8eb18 100644
> --- a/drivers/gpu/drm/vkms/tests/vkms_color_test.c
> +++ b/drivers/gpu/drm/vkms/tests/vkms_color_test.c
> @@ -126,8 +126,8 @@ 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 * 0x101, LUT_RED);
[Severity: Medium]
Since the new test_linear_lut only has 16 elements (compared to the 256
elements in linear_eotf), does leaving the multiplier as 0x101 mean we
only test values up to 0x0f0f (~5.8% of the 16-bit color space)?
Should both instances of 0x101 in this loop be updated to 0x1111 so that
the final iteration (15 * 0x1111) reaches 0xffff, restoring coverage over
the full color range?
>
> - KUNIT_EXPECT_EQ(test, DIV_ROUND_CLOSEST(linear, 0x101), i);
> + KUNIT_EXPECT_EQ(test, DIV_ROUND_CLOSEST(linear, 0x101), i);
> }
[ ... ]
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260804203351.148521-1-leandro.ribeiro@collabora.com?part=4
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 10/11] drm/vkms: add script to create optimized LUTs for color curves
2026-08-04 20:33 ` [PATCH 10/11] drm/vkms: add script to create optimized LUTs for color curves Leandro Ribeiro
@ 2026-08-04 20:47 ` sashiko-bot
0 siblings, 0 replies; 17+ messages in thread
From: sashiko-bot @ 2026-08-04 20:47 UTC (permalink / raw)
To: Leandro Ribeiro; +Cc: dri-devel
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] Unconditional GUI plot generation and matplotlib import block script execution and break in headless environments.
--
--- Patch [10]: [PATCH 10/11] drm/vkms: add script to create optimized LUTs for color curves ---
commit eeb1a305fab717b385cfb6fdf6633f43f03c3b5f
Author: Leandro Ribeiro <leandro.ribeiro@collabora.com>
drm/vkms: add script to create optimized LUTs for color curves
This commit adds a Python script to generate u16 LUTs for VKMS color transfer
functions. The script compares different LUT generation strategies and outputs
the generated LUTs as C arrays formatted for vkms_luts.c.
> 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 0000000000000..f80e67120f5b3
> --- /dev/null
> +++ b/drivers/gpu/drm/vkms/scripts/color-curve-lut.py
> @@ -0,0 +1,561 @@
[ ... ]
> +import sys
> +import os
> +import time
> +import bisect
> +import math
> +import numpy as np
> +import matplotlib.pyplot as plt
[Severity: Medium]
Will this unconditional import of matplotlib crash the script in headless
environments or CI pipelines that lack a configured display backend?
[ ... ]
> +def main(args):
[ ... ]
> + # Save the greedy subdivision LUT as C arrays for VKMS
> + greedy_lut = luts[2]
> + emit_c_arrays(greedy_lut, func_str)
> +
> + # 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()
[Severity: Medium]
Does this plt.show() call block execution indefinitely until the GUI window is
manually closed?
If this script is run as part of an automated workflow, this could cause the
process to hang. Could the plotting functionality be made optional and put
behind a command-line flag?
> +
> +
> +if __name__ == "__main__":
> + main(sys.argv)
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260804203351.148521-1-leandro.ribeiro@collabora.com?part=10
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 07/11] drm/vkms: rename get_lut_index() to get_uniform_lut_index()
2026-08-04 20:33 ` [PATCH 07/11] drm/vkms: rename get_lut_index() to get_uniform_lut_index() Leandro Ribeiro
@ 2026-08-04 20:47 ` sashiko-bot
0 siblings, 0 replies; 17+ messages in thread
From: sashiko-bot @ 2026-08-04 20:47 UTC (permalink / raw)
To: Leandro Ribeiro; +Cc: dri-devel
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
New issues:
- [Medium] Test coverage for linear LUT interpolation was severely reduced due to a mismatched scaling factor.
Pre-existing issues:
- [High] Incorrect element size used for gamma LUT validation in atomic check rejects valid LUTs on 32-bit platforms.
--
--- Patch [7]: [PATCH 07/11] drm/vkms: rename get_lut_index() to get_uniform_lut_index() ---
commit e4d9729afe7e5d9d0339bd7d09cfdb05b9aad78b
Author: Leandro Ribeiro <leandro.ribeiro@collabora.com>
drm/vkms: rename get_lut_index() to get_uniform_lut_index()
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.
> diff --git a/drivers/gpu/drm/vkms/tests/vkms_color_test.c b/drivers/gpu/drm/vkms/tests/vkms_color_test.c
> index cfcd7e8e76407..bb9d84377b979 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
> };
[Severity: Medium]
In drivers/gpu/drm/vkms/tests/vkms_color_test.c:vkms_color_test_linear(), the
multiplier is set to 0x101:
for (int i = 0; i < test_linear_lut.lut_length; i++) {
int linear = apply_lut_to_channel_value(&test_linear_lut, i * 0x101, LUT_RED);
KUNIT_EXPECT_EQ(test, DIV_ROUND_CLOSEST(linear, 0x101), i);
}
Since the new 16-element LUT has a step size of 0x1111, do we need to update
the 0x101 multiplier to match?
Currently, the 16 test iterations only reach up to 15 * 0x101 = 0xF0F. Because
the first interval spans from 0x0 to 0x1111, all test iterations fall entirely
within the very first interpolation interval, leaving over 90% of the channel
range untested.
[ ... ]
[Severity: High]
This is a pre-existing issue and was not introduced by the patch under review,
but I noticed a potential problem in vkms_atomic_check() in
drivers/gpu/drm/vkms/vkms_drv.c:
if (new_crtc_state->gamma_lut->length / sizeof(struct drm_color_lut *)
> VKMS_GAMMA_LUT_SIZE)
return -EINVAL;
Does this calculation correctly determine the number of elements?
The blob length is divided by the size of a pointer
(sizeof(struct drm_color_lut *)) instead of the size of the structure itself
(sizeof(struct drm_color_lut)). On 32-bit architectures, this doubles the
calculated element count and causes valid atomic commits containing a full
gamma LUT to be rejected with -EINVAL.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260804203351.148521-1-leandro.ribeiro@collabora.com?part=7
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 06/11] drm/vkms: rename struct vkms_color_lut::base to y
2026-08-04 20:33 ` [PATCH 06/11] drm/vkms: rename struct vkms_color_lut::base to y Leandro Ribeiro
@ 2026-08-04 20:52 ` sashiko-bot
0 siblings, 0 replies; 17+ messages in thread
From: sashiko-bot @ 2026-08-04 20:52 UTC (permalink / raw)
To: Leandro Ribeiro; +Cc: dri-devel
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
Pre-existing issues:
- [Critical] vkms_composer_worker accesses the global crtc->state asynchronously, creating a Use-After-Free (UAF) vulnerability.
- [High] vkms_atomic_check incorrectly divides gamma_lut length by sizeof(pointer) instead of sizeof(struct) on 32-bit systems.
--
--- Patch [6]: [PATCH 06/11] drm/vkms: rename struct vkms_color_lut::base to y ---
commit 89753bc7023e7c4dac9293962b90fb28fe7958fd
Author: Leandro Ribeiro <leandro.ribeiro@collabora.com>
drm/vkms: rename struct vkms_color_lut::base to y
This patch renames the base field in struct vkms_color_lut to y to prepare
for the addition of an x field in future commits. It updates all usages of
the field across the driver's tests, composer, and LUT initialization code.
There is no intended functional change.
> diff --git a/drivers/gpu/drm/vkms/vkms_composer.c b/drivers/gpu/drm/vkms/vkms_composer.c
> --- a/drivers/gpu/drm/vkms/vkms_composer.c
> +++ b/drivers/gpu/drm/vkms/vkms_composer.c
[ ... ]
> @@ -641,7 +641,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;
[Severity: Critical]
This isn't a bug introduced by this patch, but does accessing the global
crtc->state asynchronously here create a use-after-free vulnerability?
If userspace submits rapid non-blocking atomic commits, crtc->state can be
swapped by drm_atomic_helper_commit() and its previous gamma_lut blob freed
while vkms_composer_worker() is still executing.
Could this lead to the worker dereferencing the freed gamma_lut->data pointer
later in apply_lut_to_channel_value()?
> 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);
[ ... ]
While reviewing the gamma LUT handling, I also noticed the following in
vkms_drv.c:vkms_atomic_check():
> if (new_crtc_state->gamma_lut->length / sizeof(struct drm_color_lut *)
> > VKMS_GAMMA_LUT_SIZE)
> return -EINVAL;
[Severity: High]
This is a pre-existing issue, but does vkms_atomic_check() incorrectly divide
by sizeof(struct drm_color_lut *) instead of sizeof(struct drm_color_lut)?
On 32-bit systems where pointers are 4 bytes, a 256-entry LUT evaluates to a
length of 512, which exceeds VKMS_GAMMA_LUT_SIZE (256) and rejects valid
atomic commits with -EINVAL.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260804203351.148521-1-leandro.ribeiro@collabora.com?part=6
^ permalink raw reply [flat|nested] 17+ messages in thread
end of thread, other threads:[~2026-08-04 20:52 UTC | newest]
Thread overview: 17+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-04 20:33 [PATCH 00/11] drm/vkms: improve color curve LUTs precision Leandro Ribeiro
2026-08-04 20:33 ` [PATCH 01/11] drm/vkms: rename VKMS_LUT_SIZE to VKMS_GAMMA_LUT_SIZE Leandro Ribeiro
2026-08-04 20:41 ` sashiko-bot
2026-08-04 20:33 ` [PATCH 02/11] drm/vkms: allow color curve LUTs to have different sizes Leandro Ribeiro
2026-08-04 20:33 ` [PATCH 03/11] drm/vkms: remove TEST_LUT_SIZE Leandro Ribeiro
2026-08-04 20:33 ` [PATCH 04/11] drm/vkms: remove linear_eotf Leandro Ribeiro
2026-08-04 20:42 ` sashiko-bot
2026-08-04 20:33 ` [PATCH 05/11] drm/vkms: improve the way in which we access LUT member Leandro Ribeiro
2026-08-04 20:33 ` [PATCH 06/11] drm/vkms: rename struct vkms_color_lut::base to y Leandro Ribeiro
2026-08-04 20:52 ` sashiko-bot
2026-08-04 20:33 ` [PATCH 07/11] drm/vkms: rename get_lut_index() to get_uniform_lut_index() Leandro Ribeiro
2026-08-04 20:47 ` sashiko-bot
2026-08-04 20:33 ` [PATCH 08/11] drm/vkms: add support to non-uniform LUT for internal color curves Leandro Ribeiro
2026-08-04 20:33 ` [PATCH 09/11] drm/vkms: test sRGB and inverse sRGB LUTs using more samples Leandro Ribeiro
2026-08-04 20:33 ` [PATCH 10/11] drm/vkms: add script to create optimized LUTs for color curves Leandro Ribeiro
2026-08-04 20:47 ` sashiko-bot
2026-08-04 20:33 ` [PATCH 11/11] 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