Commit db971856 authored by Alex Hung's avatar Alex Hung Committed by Simon Ser
Browse files

drm/colorop: Add 3D LUT support to color pipeline



It is to be used to enable HDR by allowing userpace to create and pass
3D LUTs to kernel and hardware.

new drm_colorop_type: DRM_COLOROP_3D_LUT.

Reviewed-by: default avatarSimon Ser <contact@emersion.fr>
Signed-off-by: default avatarAlex Hung <alex.hung@amd.com>
Reviewed-by: default avatarDaniel Stone <daniels@collabora.com>
Reviewed-by: default avatarMelissa Wen <mwen@igalia.com>
Reviewed-by: default avatarSebastian Wick <sebastian.wick@redhat.com>
Signed-off-by: default avatarSimon Ser <contact@emersion.fr>
Link: https://patch.msgid.link/20251115000237.3561250-46-alex.hung@amd.com
parent 24689634
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -807,6 +807,12 @@ static void drm_atomic_colorop_print_state(struct drm_printer *p,
	case DRM_COLOROP_MULTIPLIER:
		drm_printf(p, "\tmultiplier=%llu\n", state->multiplier);
		break;
	case DRM_COLOROP_3D_LUT:
		drm_printf(p, "\tsize=%d\n", colorop->size);
		drm_printf(p, "\tinterpolation=%s\n",
			   drm_get_colorop_lut3d_interpolation_name(colorop->lut3d_interpolation));
		drm_printf(p, "\tdata blob id=%d\n", state->data ? state->data->base.id : 0);
		break;
	default:
		break;
	}
+8 −0
Original line number Diff line number Diff line
@@ -705,6 +705,10 @@ static int drm_atomic_color_set_data_property(struct drm_colorop *colorop,
	case DRM_COLOROP_CTM_3X4:
		size = sizeof(struct drm_color_ctm_3x4);
		break;
	case DRM_COLOROP_3D_LUT:
		size = colorop->size * colorop->size * colorop->size *
		       sizeof(struct drm_color_lut32);
		break;
	default:
		/* should never get here */
		return -EINVAL;
@@ -732,6 +736,8 @@ static int drm_atomic_colorop_set_property(struct drm_colorop *colorop,
		state->curve_1d_type = val;
	} else if (property == colorop->multiplier_property) {
		state->multiplier = val;
	} else if (property == colorop->lut3d_interpolation_property) {
		colorop->lut3d_interpolation = val;
	} else if (property == colorop->data_property) {
		return drm_atomic_color_set_data_property(colorop, state,
							  property, val);
@@ -763,6 +769,8 @@ drm_atomic_colorop_get_property(struct drm_colorop *colorop,
		*val = state->multiplier;
	else if (property == colorop->size_property)
		*val = colorop->size;
	else if (property == colorop->lut3d_interpolation_property)
		*val = colorop->lut3d_interpolation;
	else if (property == colorop->data_property)
		*val = (state->data) ? state->data->base.id : 0;
	else
+72 −0
Original line number Diff line number Diff line
@@ -67,6 +67,7 @@ static const struct drm_prop_enum_list drm_colorop_type_enum_list[] = {
	{ DRM_COLOROP_1D_LUT, "1D LUT" },
	{ DRM_COLOROP_CTM_3X4, "3x4 Matrix"},
	{ DRM_COLOROP_MULTIPLIER, "Multiplier"},
	{ DRM_COLOROP_3D_LUT, "3D LUT"},
};

static const char * const colorop_curve_1d_type_names[] = {
@@ -82,6 +83,11 @@ static const struct drm_prop_enum_list drm_colorop_lut1d_interpolation_list[] =
	{ DRM_COLOROP_LUT1D_INTERPOLATION_LINEAR, "Linear" },
};


static const struct drm_prop_enum_list drm_colorop_lut3d_interpolation_list[] = {
	{ DRM_COLOROP_LUT3D_INTERPOLATION_TETRAHEDRAL, "Tetrahedral" },
};

/* Init Helpers */

static int drm_plane_colorop_init(struct drm_device *dev, struct drm_colorop *colorop,
@@ -381,6 +387,51 @@ int drm_plane_colorop_mult_init(struct drm_device *dev, struct drm_colorop *colo
}
EXPORT_SYMBOL(drm_plane_colorop_mult_init);

int drm_plane_colorop_3dlut_init(struct drm_device *dev, struct drm_colorop *colorop,
				 struct drm_plane *plane,
				 uint32_t lut_size,
				 enum drm_colorop_lut3d_interpolation_type interpolation,
				 uint32_t flags)
{
	struct drm_property *prop;
	int ret;

	ret = drm_plane_colorop_init(dev, colorop, plane, DRM_COLOROP_3D_LUT, flags);
	if (ret)
		return ret;

	/* LUT size */
	prop = drm_property_create_range(dev, DRM_MODE_PROP_IMMUTABLE  | DRM_MODE_PROP_ATOMIC,
					 "SIZE", 0, UINT_MAX);
	if (!prop)
		return -ENOMEM;

	colorop->size_property = prop;
	drm_object_attach_property(&colorop->base, colorop->size_property, lut_size);
	colorop->size = lut_size;

	/* interpolation */
	prop = drm_property_create_enum(dev, 0, "LUT3D_INTERPOLATION",
					drm_colorop_lut3d_interpolation_list,
					ARRAY_SIZE(drm_colorop_lut3d_interpolation_list));
	if (!prop)
		return -ENOMEM;

	colorop->lut3d_interpolation_property = prop;
	drm_object_attach_property(&colorop->base, prop, interpolation);
	colorop->lut3d_interpolation = interpolation;

	/* data */
	ret = drm_colorop_create_data_prop(dev, colorop);
	if (ret)
		return ret;

	drm_colorop_reset(colorop);

	return 0;
}
EXPORT_SYMBOL(drm_plane_colorop_3dlut_init);

static void __drm_atomic_helper_colorop_duplicate_state(struct drm_colorop *colorop,
							struct drm_colorop_state *state)
{
@@ -472,7 +523,13 @@ static const char * const colorop_type_name[] = {
	[DRM_COLOROP_1D_LUT] = "1D LUT",
	[DRM_COLOROP_CTM_3X4] = "3x4 Matrix",
	[DRM_COLOROP_MULTIPLIER] = "Multiplier",
	[DRM_COLOROP_3D_LUT] = "3D LUT",
};

static const char * const colorop_lu3d_interpolation_name[] = {
	[DRM_COLOROP_LUT3D_INTERPOLATION_TETRAHEDRAL] = "Tetrahedral",
};

static const char * const colorop_lut1d_interpolation_name[] = {
	[DRM_COLOROP_LUT1D_INTERPOLATION_LINEAR] = "Linear",
};
@@ -508,6 +565,21 @@ const char *drm_get_colorop_lut1d_interpolation_name(enum drm_colorop_lut1d_inte
	return colorop_lut1d_interpolation_name[type];
}

/**
 * drm_get_colorop_lut3d_interpolation_name - return a string for interpolation type
 * @type: interpolation type to compute name of
 *
 * In contrast to the other drm_get_*_name functions this one here returns a
 * const pointer and hence is threadsafe.
 */
const char *drm_get_colorop_lut3d_interpolation_name(enum drm_colorop_lut3d_interpolation_type type)
{
	if (WARN_ON(type >= ARRAY_SIZE(colorop_lu3d_interpolation_name)))
		return "unknown";

	return colorop_lu3d_interpolation_name[type];
}

/**
 * drm_colorop_set_next_property - sets the next pointer
 * @colorop: drm colorop
+23 −0
Original line number Diff line number Diff line
@@ -283,6 +283,14 @@ struct drm_colorop {
	 */
	enum drm_colorop_lut1d_interpolation_type lut1d_interpolation;

	/**
	 * @lut3d_interpolation:
	 *
	 * Read-only
	 * Interpolation for DRM_COLOROP_3D_LUT
	 */
	enum drm_colorop_lut3d_interpolation_type lut3d_interpolation;

	/**
	 * @lut1d_interpolation_property:
	 *
@@ -311,6 +319,13 @@ struct drm_colorop {
	 */
	struct drm_property *size_property;

	/**
	 * @lut3d_interpolation_property:
	 *
	 * Read-only property for DRM_COLOROP_3D_LUT interpolation
	 */
	struct drm_property *lut3d_interpolation_property;

	/**
	 * @data_property:
	 *
@@ -366,6 +381,11 @@ int drm_plane_colorop_ctm_3x4_init(struct drm_device *dev, struct drm_colorop *c
				   struct drm_plane *plane, uint32_t flags);
int drm_plane_colorop_mult_init(struct drm_device *dev, struct drm_colorop *colorop,
				struct drm_plane *plane, uint32_t flags);
int drm_plane_colorop_3dlut_init(struct drm_device *dev, struct drm_colorop *colorop,
				 struct drm_plane *plane,
				 uint32_t lut_size,
				 enum drm_colorop_lut3d_interpolation_type interpolation,
				 uint32_t flags);

struct drm_colorop_state *
drm_atomic_helper_colorop_duplicate_state(struct drm_colorop *colorop);
@@ -418,6 +438,9 @@ const char *drm_get_colorop_curve_1d_type_name(enum drm_colorop_curve_1d_type ty
const char *
drm_get_colorop_lut1d_interpolation_name(enum drm_colorop_lut1d_interpolation_type type);

const char *
drm_get_colorop_lut3d_interpolation_name(enum drm_colorop_lut3d_interpolation_type type);

void drm_colorop_set_next_property(struct drm_colorop *colorop, struct drm_colorop *next);

#endif /* __DRM_COLOROP_H__ */
+34 −0
Original line number Diff line number Diff line
@@ -942,6 +942,40 @@ enum drm_colorop_type {
	 * property.
	 */
	DRM_COLOROP_MULTIPLIER,

	/**
	 * @DRM_COLOROP_3D_LUT:
	 *
	 * enum string "3D LUT"
	 *
	 * A 3D LUT of &drm_color_lut32 entries,
	 * packed into a blob via the DATA property. The driver's expected
	 * LUT size is advertised via the SIZE property, i.e., a 3D LUT with
	 * 17x17x17 entries will have SIZE set to 17.
	 *
	 * The DATA blob is a 3D array of struct drm_color_lut32 with dimension
	 * length of "size".
	 * The LUT elements are traversed like so:
	 *
	 *   for B in range 0..n
	 *     for G in range 0..n
	 *       for R in range 0..n
	 *        index = R + n * (G + n * B)
	 *         color = lut3d[index]
	 */
	DRM_COLOROP_3D_LUT,
};

/**
 * enum drm_colorop_lut3d_interpolation_type - type of 3DLUT interpolation
 */
enum drm_colorop_lut3d_interpolation_type {
	/**
	 * @DRM_COLOROP_LUT3D_INTERPOLATION_TETRAHEDRAL:
	 *
	 * Tetrahedral 3DLUT interpolation
	 */
	DRM_COLOROP_LUT3D_INTERPOLATION_TETRAHEDRAL,
};

/**