diff options
author | Lionel Landwerlin <lionel.g.landwerlin@intel.com> | 2016-02-26 20:05:00 +0300 |
---|---|---|
committer | Daniel Vetter <daniel.vetter@ffwll.ch> | 2016-03-08 15:57:32 +0300 |
commit | 5488dc16fde74595a40c5d20ae52d978313f0b4e (patch) | |
tree | 555cde44405cfb8a773346f5673fe826f925a1a7 /drivers | |
parent | 9b8d1e53f6da63920ba569405b8d57ddbb42a988 (diff) | |
download | linux-5488dc16fde74595a40c5d20ae52d978313f0b4e.tar.xz |
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: Shashank Sharma <shashank.sharma@intel.com>
Signed-off-by: Kumar, Kiran S <kiran.s.kumar@intel.com>
Signed-off-by: Kausal Malladi <kausalmalladi@gmail.com>
Signed-off-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
Reviewed-by: Matt Roper <matthew.d.roper@intel.com>
Acked-by: Rob Bradford <robert.bradford@intel.com>
[danvet: CrOS maintainers are also happy with the userspacde side:
https://codereview.chromium.org/1182063002/ ]
Reviewed-by: Daniel Stone <daniels@collabora.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Link: http://patchwork.freedesktop.org/patch/msgid/1456506302-640-4-git-send-email-lionel.g.landwerlin@intel.com
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/gpu/drm/drm_atomic.c | 88 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_atomic_helper.c | 110 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_crtc.c | 35 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_crtc_helper.c | 33 |
4 files changed, 263 insertions, 3 deletions
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 8fb469c4e4b8..c7e7a955bb1e 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -28,6 +28,7 @@ #include <drm/drmP.h> #include <drm/drm_atomic.h> +#include <drm/drm_mode.h> #include <drm/drm_plane_helper.h> /** @@ -388,6 +389,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 * @state: the state object to update with the new property value @@ -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 diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 7a034b231792..3e49a0993191 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -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); diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 579505c0a498..49781a9f8a94 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -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; } diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index 7539eea4ccbc..79555d2b1b87 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -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); |