drm/vkms: Add enumerated 1D curve colorop

This patch introduces a VKMS color pipeline that includes two
drm_colorops for named transfer functions. For now the only ones
supported are sRGB EOTF, sRGB Inverse EOTF, and a Linear TF.
We will expand this in the future but I don't want to do so
without accompanying IGT tests.

We introduce a new vkms_luts.c file that hard-codes sRGB EOTF,
sRGB Inverse EOTF, and a linear EOTF LUT. These have been
generated with 256 entries each as IGT is currently testing
only 8 bpc surfaces. We will likely need higher precision
but I'm reluctant to make that change without clear indication
that we need it. We'll revisit and, if necessary, regenerate
the LUTs when we have IGT tests for higher precision buffers.

Signed-off-by: Harry Wentland <harry.wentland@amd.com>
Signed-off-by: Alex Hung <alex.hung@amd.com>
Reviewed-by: Daniel Stone <daniels@collabora.com>
Reviewed-by: Louis Chauvet <louis.chauvet@bootlin.com>
Signed-off-by: Simon Ser <contact@emersion.fr>
Link: https://patch.msgid.link/20251115000237.3561250-16-alex.hung@amd.com
This commit is contained in:
Harry Wentland
2025-11-26 23:03:33 +01:00
committed by Simon Ser
parent 08b651cad2
commit c1e578bd08
8 changed files with 968 additions and 2 deletions
+3 -1
View File
@@ -9,7 +9,9 @@ vkms-y := \
vkms_writeback.o \
vkms_connector.o \
vkms_config.o \
vkms_configfs.o
vkms_configfs.o \
vkms_colorop.o \
vkms_luts.o
obj-$(CONFIG_DRM_VKMS) += vkms.o
obj-$(CONFIG_DRM_VKMS_KUNIT_TEST) += tests/
+86
View File
@@ -0,0 +1,86 @@
// SPDX-License-Identifier: GPL-2.0+
#include <linux/slab.h>
#include <drm/drm_colorop.h>
#include <drm/drm_print.h>
#include <drm/drm_property.h>
#include <drm/drm_plane.h>
#include "vkms_drv.h"
static const u64 supported_tfs =
BIT(DRM_COLOROP_1D_CURVE_SRGB_EOTF) |
BIT(DRM_COLOROP_1D_CURVE_SRGB_INV_EOTF);
#define MAX_COLOR_PIPELINE_OPS 2
static int vkms_initialize_color_pipeline(struct drm_plane *plane, struct drm_prop_enum_list *list)
{
struct drm_colorop *ops[MAX_COLOR_PIPELINE_OPS];
struct drm_device *dev = plane->dev;
int ret;
int i = 0, j = 0;
memset(ops, 0, sizeof(ops));
/* 1st op: 1d curve */
ops[i] = kzalloc(sizeof(*ops[i]), GFP_KERNEL);
if (!ops[i]) {
drm_err(dev, "KMS: Failed to allocate colorop\n");
ret = -ENOMEM;
goto cleanup;
}
ret = drm_plane_colorop_curve_1d_init(dev, ops[i], plane, supported_tfs);
if (ret)
goto cleanup;
list->type = ops[i]->base.id;
list->name = kasprintf(GFP_KERNEL, "Color Pipeline %d", ops[i]->base.id);
i++;
/* 2nd op: 1d curve */
ops[i] = kzalloc(sizeof(*ops[i]), GFP_KERNEL);
if (!ops[i]) {
drm_err(dev, "KMS: Failed to allocate colorop\n");
ret = -ENOMEM;
goto cleanup;
}
ret = drm_plane_colorop_curve_1d_init(dev, ops[i], plane, supported_tfs);
if (ret)
goto cleanup;
drm_colorop_set_next_property(ops[i - 1], ops[i]);
return 0;
cleanup:
for (j = 0; j < i; j++) {
if (ops[j]) {
drm_colorop_cleanup(ops[j]);
kfree(ops[j]);
}
}
return ret;
}
int vkms_initialize_colorops(struct drm_plane *plane)
{
struct drm_prop_enum_list pipeline;
int ret;
/* Add color pipeline */
ret = vkms_initialize_color_pipeline(plane, &pipeline);
if (ret)
return ret;
/* Create COLOR_PIPELINE property and attach */
ret = drm_plane_create_color_pipeline_property(plane, &pipeline, 1);
if (ret)
return ret;
return 0;
}
+50 -1
View File
@@ -14,6 +14,7 @@
#include <kunit/visibility.h>
#include "vkms_composer.h"
#include "vkms_luts.h"
static u16 pre_mul_blend_channel(u16 src, u16 dst, u16 alpha)
{
@@ -136,6 +137,54 @@ static void apply_lut(const struct vkms_crtc_state *crtc_state, struct line_buff
}
}
static void apply_colorop(struct pixel_argb_u16 *pixel, struct drm_colorop *colorop)
{
struct drm_colorop_state *colorop_state = colorop->state;
struct drm_device *dev = colorop->dev;
if (colorop->type == DRM_COLOROP_1D_CURVE) {
switch (colorop_state->curve_1d_type) {
case DRM_COLOROP_1D_CURVE_SRGB_INV_EOTF:
pixel->r = apply_lut_to_channel_value(&srgb_inv_eotf, pixel->r, LUT_RED);
pixel->g = apply_lut_to_channel_value(&srgb_inv_eotf, pixel->g, LUT_GREEN);
pixel->b = apply_lut_to_channel_value(&srgb_inv_eotf, pixel->b, LUT_BLUE);
break;
case DRM_COLOROP_1D_CURVE_SRGB_EOTF:
pixel->r = apply_lut_to_channel_value(&srgb_eotf, pixel->r, LUT_RED);
pixel->g = apply_lut_to_channel_value(&srgb_eotf, pixel->g, LUT_GREEN);
pixel->b = apply_lut_to_channel_value(&srgb_eotf, pixel->b, LUT_BLUE);
break;
default:
drm_WARN_ONCE(dev, true,
"unknown colorop 1D curve type %d\n",
colorop_state->curve_1d_type);
break;
}
}
}
static void pre_blend_color_transform(const struct vkms_plane_state *plane_state,
struct line_buffer *output_buffer)
{
for (size_t x = 0; x < output_buffer->n_pixels; x++) {
struct drm_colorop *colorop = plane_state->base.base.color_pipeline;
while (colorop) {
struct drm_colorop_state *colorop_state;
colorop_state = colorop->state;
if (!colorop_state)
return;
if (!colorop_state->bypass)
apply_colorop(&output_buffer->pixels[x], colorop);
colorop = colorop->next;
}
}
}
/**
* direction_for_rotation() - Get the correct reading direction for a given rotation
*
@@ -351,7 +400,7 @@ static void blend_line(struct vkms_plane_state *current_plane, int y,
*/
current_plane->pixel_read_line(current_plane, src_x_start, src_y_start, direction,
pixel_count, &stage_buffer->pixels[dst_x_start]);
pre_blend_color_transform(current_plane, stage_buffer);
pre_mul_alpha_blend(stage_buffer, output_buffer,
dst_x_start, pixel_count);
}
+1
View File
@@ -253,6 +253,7 @@ void vkms_destroy(struct vkms_config *config)
fdev = config->dev->faux_dev;
drm_colorop_pipeline_destroy(&config->dev->drm);
drm_dev_unregister(&config->dev->drm);
drm_atomic_helper_shutdown(&config->dev->drm);
devres_release_group(&fdev->dev, NULL);
+3
View File
@@ -319,4 +319,7 @@ void vkms_writeback_row(struct vkms_writeback_job *wb, const struct line_buffer
/* Writeback */
int vkms_enable_writeback_connector(struct vkms_device *vkmsdev, struct vkms_output *vkms_out);
/* Colorops */
int vkms_initialize_colorops(struct drm_plane *plane);
#endif /* _VKMS_DRV_H_ */
File diff suppressed because it is too large Load Diff
+12
View File
@@ -0,0 +1,12 @@
/* SPDX-License-Identifier: GPL-2.0+ */
#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;
#endif /* _VKMS_LUTS_H_ */
+2
View File
@@ -246,5 +246,7 @@ struct vkms_plane *vkms_plane_init(struct vkms_device *vkmsdev,
DRM_COLOR_YCBCR_BT601,
DRM_COLOR_YCBCR_FULL_RANGE);
vkms_initialize_colorops(&plane->base);
return plane;
}