Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5488dc16 authored by Lionel Landwerlin's avatar Lionel Landwerlin Committed by Daniel Vetter
Browse files

drm: introduce pipe color correction properties



Patch based on a previous series by Shashank Sharma.

This introduces optional properties to enable color correction at the
pipe level. It relies on 3 transformations applied to every pixels
displayed. First a lookup into a degamma table, then a multiplication
of the rgb components by a 3x3 matrix and finally another lookup into
a gamma table.

The following properties can be added to a pipe :
  - DEGAMMA_LUT : blob containing degamma LUT
  - DEGAMMA_LUT_SIZE : number of elements in DEGAMMA_LUT
  - CTM : transformation matrix applied after the degamma LUT
  - GAMMA_LUT : blob containing gamma LUT
  - GAMMA_LUT_SIZE : number of elements in GAMMA_LUT

DEGAMMA_LUT_SIZE and GAMMA_LUT_SIZE are read only properties, set by
the driver to tell userspace applications what sizes should be the
lookup tables in DEGAMMA_LUT and GAMMA_LUT.

A helper is also provided so legacy gamma correction is redirected
through these new properties.

v2: Register LUT size properties as range

v3: Fix round in drm_color_lut_get_value() helper
    More docs on how degamma/gamma properties are used

v4: Update contributors

v5: Rename CTM_MATRIX property to CTM (Doh!)
    Add legacy gamma_set atomic helper
    Describe CTM/LUT acronyms in the kernel doc

v6: Fix missing blob unref in drm_atomic_helper_crtc_reset

Signed-off-by: default avatarShashank Sharma <shashank.sharma@intel.com>
Signed-off-by: default avatarKumar, Kiran S <kiran.s.kumar@intel.com>
Signed-off-by: default avatarKausal Malladi <kausalmalladi@gmail.com>
Signed-off-by: default avatarLionel Landwerlin <lionel.g.landwerlin@intel.com>
Reviewed-by: default avatarMatt Roper <matthew.d.roper@intel.com>
Acked-by: default avatarRob Bradford <robert.bradford@intel.com>
[danvet: CrOS maintainers are also happy with the userspacde side:
https://codereview.chromium.org/1182063002/

 ]
Reviewed-by: default avatarDaniel Stone <daniels@collabora.com>
Signed-off-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
Link: http://patchwork.freedesktop.org/patch/msgid/1456506302-640-4-git-send-email-lionel.g.landwerlin@intel.com
parent 9b8d1e53
Loading
Loading
Loading
Loading
+57 −2
Original line number Diff line number Diff line
@@ -1816,7 +1816,7 @@ void intel_crt_init(struct drm_device *dev)
	<td valign="top" >Description/Restrictions</td>
	</tr>
	<tr>
	<td rowspan="37" valign="top" >DRM</td>
	<td rowspan="42" valign="top" >DRM</td>
	<td valign="top" >Generic</td>
	<td valign="top" >“rotation”</td>
	<td valign="top" >BITMASK</td>
@@ -2068,7 +2068,7 @@ void intel_crt_init(struct drm_device *dev)
	<td valign="top" >property to suggest an Y offset for a connector</td>
	</tr>
	<tr>
	<td rowspan="3" valign="top" >Optional</td>
	<td rowspan="8" valign="top" >Optional</td>
	<td valign="top" >“scaling mode”</td>
	<td valign="top" >ENUM</td>
	<td valign="top" >{ "None", "Full", "Center", "Full aspect" }</td>
@@ -2092,6 +2092,61 @@ void intel_crt_init(struct drm_device *dev)
	<td valign="top" >TBD</td>
	</tr>
	<tr>
	<td valign="top" >“DEGAMMA_LUT”</td>
	<td valign="top" >BLOB</td>
	<td valign="top" >0</td>
	<td valign="top" >CRTC</td>
	<td valign="top" >DRM property to set the degamma lookup table
		(LUT) mapping pixel data from the framebuffer before it is
		given to the transformation matrix. The data is an interpreted
		as an array of struct drm_color_lut elements. Hardware might
		choose not to use the full precision of the LUT elements nor
		use all the elements of the LUT (for example the hardware
		might choose to interpolate between LUT[0] and LUT[4]). </td>
	</tr>
	<tr>
	<td valign="top" >“DEGAMMA_LUT_SIZE”</td>
	<td valign="top" >RANGE | IMMUTABLE</td>
	<td valign="top" >Min=0, Max=UINT_MAX</td>
	<td valign="top" >CRTC</td>
	<td valign="top" >DRM property to gives the size of the lookup
		table to be set on the DEGAMMA_LUT property (the size depends
		on the underlying hardware).</td>
	</tr>
	<tr>
	<td valign="top" >“CTM”</td>
	<td valign="top" >BLOB</td>
	<td valign="top" >0</td>
	<td valign="top" >CRTC</td>
	<td valign="top" >DRM property to set the current
		transformation matrix (CTM) apply to pixel data after the
		lookup through the degamma LUT and before the lookup through
		the gamma LUT. The data is an interpreted as a struct
		drm_color_ctm.</td>
	</tr>
	<tr>
	<td valign="top" >“GAMMA_LUT”</td>
	<td valign="top" >BLOB</td>
	<td valign="top" >0</td>
	<td valign="top" >CRTC</td>
	<td valign="top" >DRM property to set the gamma lookup table
		(LUT) mapping pixel data after to the transformation matrix to
		data sent to the connector. The data is an interpreted as an
		array of struct drm_color_lut elements. Hardware might choose
		not to use the full precision of the LUT elements nor use all
		the elements of the LUT (for example the hardware might choose
		to interpolate between LUT[0] and LUT[4]).</td>
	</tr>
	<tr>
	<td valign="top" >“GAMMA_LUT_SIZE”</td>
	<td valign="top" >RANGE | IMMUTABLE</td>
	<td valign="top" >Min=0, Max=UINT_MAX</td>
	<td valign="top" >CRTC</td>
	<td valign="top" >DRM property to gives the size of the lookup
		table to be set on the GAMMA_LUT property (the size depends on
		the underlying hardware).</td>
	</tr>
	<tr>
	<td rowspan="20" valign="top" >i915</td>
	<td rowspan="2" valign="top" >Generic</td>
	<td valign="top" >"Broadcast RGB"</td>
+86 −2
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@

#include <drm/drmP.h>
#include <drm/drm_atomic.h>
#include <drm/drm_mode.h>
#include <drm/drm_plane_helper.h>

/**
@@ -387,6 +388,59 @@ int drm_atomic_set_mode_prop_for_crtc(struct drm_crtc_state *state,
}
EXPORT_SYMBOL(drm_atomic_set_mode_prop_for_crtc);

/**
 * drm_atomic_replace_property_blob - replace a blob property
 * @blob: a pointer to the member blob to be replaced
 * @new_blob: the new blob to replace with
 * @expected_size: the expected size of the new blob
 * @replaced: whether the blob has been replaced
 *
 * RETURNS:
 * Zero on success, error code on failure
 */
static void
drm_atomic_replace_property_blob(struct drm_property_blob **blob,
				 struct drm_property_blob *new_blob,
				 bool *replaced)
{
	struct drm_property_blob *old_blob = *blob;

	if (old_blob == new_blob)
		return;

	if (old_blob)
		drm_property_unreference_blob(old_blob);
	if (new_blob)
		drm_property_reference_blob(new_blob);
	*blob = new_blob;
	*replaced = true;

	return;
}

static int
drm_atomic_replace_property_blob_from_id(struct drm_crtc *crtc,
					 struct drm_property_blob **blob,
					 uint64_t blob_id,
					 ssize_t expected_size,
					 bool *replaced)
{
	struct drm_device *dev = crtc->dev;
	struct drm_property_blob *new_blob = NULL;

	if (blob_id != 0) {
		new_blob = drm_property_lookup_blob(dev, blob_id);
		if (new_blob == NULL)
			return -EINVAL;
		if (expected_size > 0 && expected_size != new_blob->length)
			return -EINVAL;
	}

	drm_atomic_replace_property_blob(blob, new_blob, replaced);

	return 0;
}

/**
 * drm_atomic_crtc_set_property - set property on CRTC
 * @crtc: the drm CRTC to set a property on
@@ -409,6 +463,7 @@ int drm_atomic_crtc_set_property(struct drm_crtc *crtc,
{
	struct drm_device *dev = crtc->dev;
	struct drm_mode_config *config = &dev->mode_config;
	bool replaced = false;
	int ret;

	if (property == config->prop_active)
@@ -419,8 +474,31 @@ int drm_atomic_crtc_set_property(struct drm_crtc *crtc,
		ret = drm_atomic_set_mode_prop_for_crtc(state, mode);
		drm_property_unreference_blob(mode);
		return ret;
	}
	else if (crtc->funcs->atomic_set_property)
	} else if (property == config->degamma_lut_property) {
		ret = drm_atomic_replace_property_blob_from_id(crtc,
					&state->degamma_lut,
					val,
					-1,
					&replaced);
		state->color_mgmt_changed = replaced;
		return ret;
	} else if (property == config->ctm_property) {
		ret = drm_atomic_replace_property_blob_from_id(crtc,
					&state->ctm,
					val,
					sizeof(struct drm_color_ctm),
					&replaced);
		state->color_mgmt_changed = replaced;
		return ret;
	} else if (property == config->gamma_lut_property) {
		ret = drm_atomic_replace_property_blob_from_id(crtc,
					&state->gamma_lut,
					val,
					-1,
					&replaced);
		state->color_mgmt_changed = replaced;
		return ret;
	} else if (crtc->funcs->atomic_set_property)
		return crtc->funcs->atomic_set_property(crtc, state, property, val);
	else
		return -EINVAL;
@@ -456,6 +534,12 @@ drm_atomic_crtc_get_property(struct drm_crtc *crtc,
		*val = state->active;
	else if (property == config->prop_mode_id)
		*val = (state->mode_blob) ? state->mode_blob->base.id : 0;
	else if (property == config->degamma_lut_property)
		*val = (state->degamma_lut) ? state->degamma_lut->base.id : 0;
	else if (property == config->ctm_property)
		*val = (state->ctm) ? state->ctm->base.id : 0;
	else if (property == config->gamma_lut_property)
		*val = (state->gamma_lut) ? state->gamma_lut->base.id : 0;
	else if (crtc->funcs->atomic_get_property)
		return crtc->funcs->atomic_get_property(crtc, state, property, val);
	else
+109 −1
Original line number Diff line number Diff line
@@ -2495,8 +2495,12 @@ EXPORT_SYMBOL(drm_atomic_helper_connector_dpms);
 */
void drm_atomic_helper_crtc_reset(struct drm_crtc *crtc)
{
	if (crtc->state)
	if (crtc->state) {
		drm_property_unreference_blob(crtc->state->mode_blob);
		drm_property_unreference_blob(crtc->state->degamma_lut);
		drm_property_unreference_blob(crtc->state->ctm);
		drm_property_unreference_blob(crtc->state->gamma_lut);
	}
	kfree(crtc->state);
	crtc->state = kzalloc(sizeof(*crtc->state), GFP_KERNEL);

@@ -2520,10 +2524,17 @@ void __drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc,

	if (state->mode_blob)
		drm_property_reference_blob(state->mode_blob);
	if (state->degamma_lut)
		drm_property_reference_blob(state->degamma_lut);
	if (state->ctm)
		drm_property_reference_blob(state->ctm);
	if (state->gamma_lut)
		drm_property_reference_blob(state->gamma_lut);
	state->mode_changed = false;
	state->active_changed = false;
	state->planes_changed = false;
	state->connectors_changed = false;
	state->color_mgmt_changed = false;
	state->event = NULL;
}
EXPORT_SYMBOL(__drm_atomic_helper_crtc_duplicate_state);
@@ -2564,6 +2575,9 @@ void __drm_atomic_helper_crtc_destroy_state(struct drm_crtc *crtc,
					    struct drm_crtc_state *state)
{
	drm_property_unreference_blob(state->mode_blob);
	drm_property_unreference_blob(state->degamma_lut);
	drm_property_unreference_blob(state->ctm);
	drm_property_unreference_blob(state->gamma_lut);
}
EXPORT_SYMBOL(__drm_atomic_helper_crtc_destroy_state);

@@ -2877,3 +2891,97 @@ void drm_atomic_helper_connector_destroy_state(struct drm_connector *connector,
	kfree(state);
}
EXPORT_SYMBOL(drm_atomic_helper_connector_destroy_state);

/**
 * drm_atomic_helper_legacy_gamma_set - set the legacy gamma correction table
 * @crtc: CRTC object
 * @red: red correction table
 * @green: green correction table
 * @blue: green correction table
 * @start:
 * @size: size of the tables
 *
 * Implements support for legacy gamma correction table for drivers
 * that support color management through the DEGAMMA_LUT/GAMMA_LUT
 * properties.
 */
void drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc,
					u16 *red, u16 *green, u16 *blue,
					uint32_t start, uint32_t size)
{
	struct drm_device *dev = crtc->dev;
	struct drm_mode_config *config = &dev->mode_config;
	struct drm_atomic_state *state;
	struct drm_crtc_state *crtc_state;
	struct drm_property_blob *blob = NULL;
	struct drm_color_lut *blob_data;
	int i, ret = 0;

	state = drm_atomic_state_alloc(crtc->dev);
	if (!state)
		return;

	blob = drm_property_create_blob(dev,
					sizeof(struct drm_color_lut) * size,
					NULL);
	if (!blob) {
		ret = -ENOMEM;
		goto fail;
	}

	/* Prepare GAMMA_LUT with the legacy values. */
	blob_data = (struct drm_color_lut *) blob->data;
	for (i = 0; i < size; i++) {
		blob_data[i].red = red[i];
		blob_data[i].green = green[i];
		blob_data[i].blue = blue[i];
	}

	state->acquire_ctx = crtc->dev->mode_config.acquire_ctx;
retry:
	crtc_state = drm_atomic_get_crtc_state(state, crtc);
	if (IS_ERR(crtc_state)) {
		ret = PTR_ERR(crtc_state);
		goto fail;
	}

	/* Reset DEGAMMA_LUT and CTM properties. */
	ret = drm_atomic_crtc_set_property(crtc, crtc_state,
			config->degamma_lut_property, 0);
	if (ret)
		goto fail;

	ret = drm_atomic_crtc_set_property(crtc, crtc_state,
			config->ctm_property, 0);
	if (ret)
		goto fail;

	ret = drm_atomic_crtc_set_property(crtc, crtc_state,
			config->gamma_lut_property, blob->base.id);
	if (ret)
		goto fail;

	ret = drm_atomic_commit(state);
	if (ret)
		goto fail;

	/* Driver takes ownership of state on successful commit. */

	drm_property_unreference_blob(blob);

	return;
fail:
	if (ret == -EDEADLK)
		goto backoff;

	drm_atomic_state_free(state);
	drm_property_unreference_blob(blob);

	return;
backoff:
	drm_atomic_state_clear(state);
	drm_atomic_legacy_backoff(state);

	goto retry;
}
EXPORT_SYMBOL(drm_atomic_helper_legacy_gamma_set);
+35 −0
Original line number Diff line number Diff line
@@ -1563,6 +1563,41 @@ static int drm_mode_create_standard_properties(struct drm_device *dev)
		return -ENOMEM;
	dev->mode_config.prop_mode_id = prop;

	prop = drm_property_create(dev,
			DRM_MODE_PROP_BLOB,
			"DEGAMMA_LUT", 0);
	if (!prop)
		return -ENOMEM;
	dev->mode_config.degamma_lut_property = prop;

	prop = drm_property_create_range(dev,
			DRM_MODE_PROP_IMMUTABLE,
			"DEGAMMA_LUT_SIZE", 0, UINT_MAX);
	if (!prop)
		return -ENOMEM;
	dev->mode_config.degamma_lut_size_property = prop;

	prop = drm_property_create(dev,
			DRM_MODE_PROP_BLOB,
			"CTM", 0);
	if (!prop)
		return -ENOMEM;
	dev->mode_config.ctm_property = prop;

	prop = drm_property_create(dev,
			DRM_MODE_PROP_BLOB,
			"GAMMA_LUT", 0);
	if (!prop)
		return -ENOMEM;
	dev->mode_config.gamma_lut_property = prop;

	prop = drm_property_create_range(dev,
			DRM_MODE_PROP_IMMUTABLE,
			"GAMMA_LUT_SIZE", 0, UINT_MAX);
	if (!prop)
		return -ENOMEM;
	dev->mode_config.gamma_lut_size_property = prop;

	return 0;
}

+33 −0
Original line number Diff line number Diff line
@@ -1075,3 +1075,36 @@ int drm_helper_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
	return drm_plane_helper_commit(plane, plane_state, old_fb);
}
EXPORT_SYMBOL(drm_helper_crtc_mode_set_base);

/**
 * drm_helper_crtc_enable_color_mgmt - enable color management properties
 * @crtc: DRM CRTC
 * @degamma_lut_size: the size of the degamma lut (before CSC)
 * @gamma_lut_size: the size of the gamma lut (after CSC)
 *
 * This function lets the driver enable the color correction properties on a
 * CRTC. This includes 3 degamma, csc and gamma properties that userspace can
 * set and 2 size properties to inform the userspace of the lut sizes.
 */
void drm_helper_crtc_enable_color_mgmt(struct drm_crtc *crtc,
				       int degamma_lut_size,
				       int gamma_lut_size)
{
	struct drm_device *dev = crtc->dev;
	struct drm_mode_config *config = &dev->mode_config;

	drm_object_attach_property(&crtc->base,
				   config->degamma_lut_property, 0);
	drm_object_attach_property(&crtc->base,
				   config->ctm_property, 0);
	drm_object_attach_property(&crtc->base,
				   config->gamma_lut_property, 0);

	drm_object_attach_property(&crtc->base,
				   config->degamma_lut_size_property,
				   degamma_lut_size);
	drm_object_attach_property(&crtc->base,
				   config->gamma_lut_size_property,
				   gamma_lut_size);
}
EXPORT_SYMBOL(drm_helper_crtc_enable_color_mgmt);
Loading