mirror of
https://github.com/linux-msm/laptops-kernel.git
synced 2026-08-13 14:19:53 -07:00
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:
committed by
Simon Ser
parent
08b651cad2
commit
c1e578bd08
@@ -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/
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
@@ -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_ */
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user