Commit c1e578bd authored by Harry Wentland's avatar Harry Wentland Committed by Simon Ser
Browse files

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: default avatarHarry Wentland <harry.wentland@amd.com>
Signed-off-by: default avatarAlex Hung <alex.hung@amd.com>
Reviewed-by: default avatarDaniel Stone <daniels@collabora.com>
Reviewed-by: default avatarLouis Chauvet <louis.chauvet@bootlin.com>
Signed-off-by: default avatarSimon Ser <contact@emersion.fr>
Link: https://patch.msgid.link/20251115000237.3561250-16-alex.hung@amd.com
parent 08b651ca
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -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 −0
Original line number Diff line number Diff line
// 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
Original line number Diff line number Diff line
@@ -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 −0
Original line number Diff line number Diff line
@@ -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 −0
Original line number Diff line number Diff line
@@ -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_ */
Loading