@@ -786,6 +786,9 @@ static void drm_atomic_colorop_print_state(struct drm_printer *p,
const struct drm_colorop_state *state)
{
struct drm_colorop *colorop = state->colorop;
+ struct drm_property_blob *modes = state->lut_3d_modes;
+ struct drm_mode_3dlut_mode *mode_3dlut;
+ int i;
drm_printf(p, "colorop[%u]:\n", colorop->base.id);
drm_printf(p, "\ttype=%s\n", drm_get_colorop_type_name(colorop->type));
@@ -808,6 +811,24 @@ 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:
+ mode_3dlut = (struct drm_mode_3dlut_mode *) modes->data;
+
+ drm_printf(p, "\tlut_3d_modes blob id=%d\n", modes ? modes->base.id : 0);
+ for (i = 0; i < modes->length / sizeof(struct drm_mode_3dlut_mode); i++) {
+ drm_printf(p, "\t lut_size=%d\n", mode_3dlut[i].lut_size);
+ drm_printf(p, "\t lut_strides=%d %d %d\n", mode_3dlut[i].lut_stride[0],
+ mode_3dlut[i].lut_stride[1],
+ mode_3dlut[i].lut_stride[2]);
+ drm_printf(p, "\t interpolation=%s\n",
+ drm_get_colorop_lut3d_interpolation_name(mode_3dlut[i].interpolation));
+ drm_printf(p, "\t color_depth=%d\n", mode_3dlut[i].color_depth);
+ drm_printf(p, "\t color_format=%X\n", mode_3dlut[i].color_format);
+ drm_printf(p, "\t traversal_order=%X\n", mode_3dlut[i].traversal_order);
+ }
+ drm_printf(p, "\tlut_3d_mode_index=%d\n", state->lut_3d_mode_index);
+ drm_printf(p, "\tdata blob id=%d\n", state->data ? state->data->base.id : 0);
+ break;
default:
break;
}
@@ -695,9 +695,11 @@ static int drm_atomic_color_set_data_property(struct drm_colorop *colorop,
struct drm_colorop_state *state,
struct drm_property *property, uint64_t val)
{
+ struct drm_mode_3dlut_mode *modes;
ssize_t elem_size = -1;
ssize_t size = -1;
bool replaced = false;
+ uint32_t index;
switch (colorop->type) {
case DRM_COLOROP_1D_LUT:
@@ -706,6 +708,15 @@ 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:
+ index = state->lut_3d_mode_index;
+ if (index >= (state->lut_3d_modes->length / sizeof(struct drm_mode_3dlut_mode)))
+ return -EINVAL;
+
+ modes = (struct drm_mode_3dlut_mode *) state->lut_3d_modes->data;
+ size = modes[index].lut_stride[0] * modes[index].lut_stride[1] * modes[index].lut_stride[2] *
+ sizeof(struct drm_color_lut);
+ break;
default:
/* should never get here */
return -EINVAL;
@@ -729,6 +740,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->lut_3d_mode_index_property) {
+ state->lut_3d_mode_index = val;
} else if (property == colorop->data_property) {
return drm_atomic_color_set_data_property(colorop,
state, property, val);
@@ -756,6 +769,10 @@ drm_atomic_colorop_get_property(struct drm_colorop *colorop,
*val = state->curve_1d_type;
} else if (property == colorop->multiplier_property) {
*val = state->multiplier;
+ } else if (property == colorop->lut_3d_modes_property) {
+ *val = (state->lut_3d_modes) ? state->lut_3d_modes->base.id : 0;
+ } else if (property == colorop->lut_3d_mode_index_property) {
+ *val = state->lut_3d_mode_index;
} else if (property == colorop->size_property) {
*val = state->size;
} else if (property == colorop->data_property) {
@@ -66,6 +66,7 @@ static const struct drm_prop_enum_list drm_colorop_type_enum_list[] = {
{ DRM_COLOROP_1D_LUT, "1D Curve Custom 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[] = {
@@ -348,6 +349,53 @@ int drm_colorop_mult_init(struct drm_device *dev, struct drm_colorop *colorop,
}
EXPORT_SYMBOL(drm_colorop_mult_init);
+int drm_colorop_3dlut_init(struct drm_device *dev, struct drm_colorop *colorop,
+ struct drm_plane *plane, struct drm_mode_3dlut_mode *mode_3dlut,
+ size_t num, bool allow_bypass)
+{
+ struct drm_property_blob *blob;
+ struct drm_property *prop;
+ int ret;
+
+ ret = drm_colorop_init(dev, colorop, plane, DRM_COLOROP_3D_LUT, allow_bypass);
+ if (ret)
+ return ret;
+
+ /* lut_3d_modes */
+ prop = drm_property_create(dev, DRM_MODE_PROP_BLOB | DRM_MODE_PROP_IMMUTABLE, "3DLUT_MODES", 0);
+ if (!prop)
+ return -ENOMEM;
+
+ colorop->lut_3d_modes_property = prop;
+
+
+ blob = drm_property_create_blob(colorop->dev, num * sizeof(struct drm_mode_3dlut_mode),
+ mode_3dlut);
+ if (IS_ERR(blob))
+ return PTR_ERR(blob);
+
+ drm_object_attach_property(&colorop->base, colorop->lut_3d_modes_property, blob ? blob->base.id : 0);
+ drm_colorop_reset(colorop);
+
+ drm_property_replace_blob(&colorop->state->lut_3d_modes, blob);
+
+ /* lut_3d_modes index */
+ prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, "3DLUT_MODE_INDEX", 0, num - 1);
+ if (!prop)
+ return -ENOMEM;
+
+ colorop->lut_3d_mode_index_property = prop;
+ drm_object_attach_property(&colorop->base, colorop->lut_3d_mode_index_property, 0);
+
+ /* data */
+ ret = drm_colorop_create_data_prop(dev, colorop);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+EXPORT_SYMBOL(drm_colorop_3dlut_init);
+
static void __drm_atomic_helper_colorop_duplicate_state(struct drm_colorop *colorop,
struct drm_colorop_state *state)
{
@@ -437,7 +485,13 @@ static const char * const colorop_type_name[] = {
[DRM_COLOROP_1D_LUT] = "1D Curve Custom 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",
};
@@ -473,6 +527,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
@@ -139,6 +139,29 @@ struct drm_colorop_state {
*/
uint32_t size;
+ /**
+ * @lut_3d_modes:
+ *
+ * Mode blob for displaying a list of supported 3dlut modes.
+ *
+ * To setup a 3D LUT, lut_3d_modes, lut_3d_modes and data are expected
+ * to be used in the following sequence:
+ *
+ * 1. device driver sets a list of supported drm_mode_3dlut_mode in "lut_3d_modes".
+ * 2. userspace reads "lut_3d_modes" to determines an appropriate mode.
+ * 3. userspace sets "lut_3d_mode_index" pointing the selected mode.
+ * 4. userspace passes a 3D LUT via "data"
+ * 5. usersapce commits to device driver
+ */
+ struct drm_property_blob *lut_3d_modes;
+
+ /**
+ * @lut_3d_mode_index:
+ *
+ * A zero-based index pointing to current lut_3d_mode.
+ */
+ uint16_t lut_3d_mode_index;
+
/**
* @data:
*
@@ -274,6 +297,21 @@ struct drm_colorop {
*/
struct drm_property *size_property;
+ /**
+ * @lut_3d_modes_property:
+ *
+ * 3DLUT mode property used to convert the framebuffer's colors
+ * to non-linear gamma.
+ */
+ struct drm_property *lut_3d_modes_property;
+
+ /**
+ * @lut_3d_mode_index_property:
+ *
+ * 3DLUT mode index property for choosing 3D LUT mode.
+ */
+ struct drm_property *lut_3d_mode_index_property;
+
/**
* @data_property:
*
@@ -329,6 +367,9 @@ int drm_colorop_ctm_3x4_init(struct drm_device *dev, struct drm_colorop *colorop
struct drm_plane *plane, bool allow_bypass);
int drm_colorop_mult_init(struct drm_device *dev, struct drm_colorop *colorop,
struct drm_plane *plane, bool allow_bypass);
+int drm_colorop_3dlut_init(struct drm_device *dev, struct drm_colorop *colorop,
+ struct drm_plane *plane, struct drm_mode_3dlut_mode *mode_3dlut,
+ size_t num, bool allow_bypass);
struct drm_colorop_state *
drm_atomic_helper_colorop_duplicate_state(struct drm_colorop *colorop);
@@ -379,6 +420,7 @@ const char *drm_get_colorop_type_name(enum drm_colorop_type type);
*/
const char *drm_get_colorop_curve_1d_type_name(enum drm_colorop_curve_1d_type type);
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);
@@ -914,6 +914,90 @@ enum drm_colorop_type {
* property.
*/
DRM_COLOROP_MULTIPLIER,
+ /**
+ * @DRM_COLOROP_3D_LUT:
+ *
+ * A 3D LUT of &drm_color_lut entries,
+ * packed into a blob via the DATA property. The driver's expected
+ * LUT size is advertised via the SIZE property.
+ */
+ 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,
+};
+
+/**
+ * enum drm_colorop_lut3d_traversal_order - traversal order of the 3D LUT
+ *
+ * This enum describes the order of traversal of 3DLUT elements.
+ */
+enum drm_colorop_lut3d_traversal_order {
+ /**
+ * @DRM_COLOROP_LUT3D_TRAVERSAL_RGB:
+ *
+ * the LUT elements are traversed like so:
+ * for R in range 0..n
+ * for G in range 0..n
+ * for B in range 0..n
+ * color = lut3d[R][G][B]
+ */
+ DRM_COLOROP_LUT3D_TRAVERSAL_RGB,
+ /**
+ * @DRM_COLOROP_LUT3D_TRAVERSAL_BGR:
+ *
+ * the LUT elements are traversed like so:
+ * for R in range 0..n
+ * for G in range 0..n
+ * for B in range 0..n
+ * color = lut3d[B][G][R]
+ */
+ DRM_COLOROP_LUT3D_TRAVERSAL_BGR,
+};
+
+/**
+ * struct drm_mode_3dlut_mode - 3D LUT mode
+ *
+ * The mode describes the supported and selected format of a 3DLUT.
+ */
+struct drm_mode_3dlut_mode {
+ /**
+ * @lut_size: 3D LUT size - can be 9, 17 or 33
+ */
+ __u16 lut_size;
+ /**
+ * @lut_stride: dimensions of 3D LUT. Must be larger than lut_size
+ */
+ __u16 lut_stride[3];
+ /**
+ * @interpolation: interpolation algorithm for 3D LUT. See drm_colorop_lut3d_interpolation_type
+ */
+ __u16 interpolation;
+ /**
+ * @color_depth: color depth - can be 8, 10 or 12
+ */
+ __u16 color_depth;
+ /**
+ * @color_format: color format specified by fourcc values
+ * ex. DRM_FORMAT_XRGB16161616 - color in order of RGB, each is 16bit.
+ */
+ __u32 color_format;
+ /**
+ * @traversal_order:
+ *
+ * Traversal order when parsing/writing the 3D LUT. See enum drm_colorop_lut3d_traversal_order
+ */
+ __u16 traversal_order;
};
/**