[PATCH 3/5] drm: introduce pipe color correction properties

Emil Velikov emil.l.velikov at gmail.com
Fri Feb 26 00:36:12 UTC 2016


Hi Lionel,

A bunch of suggestions - feel free to take or ignore them :-)

On 25 February 2016 at 10:58, Lionel Landwerlin
<lionel.g.landwerlin at intel.com> wrote:
> 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
>
> Signed-off-by: Shashank Sharma <shashank.sharma at intel.com>
> Signed-off-by: Lionel Landwerlin <lionel.g.landwerlin at intel.com>
> Signed-off-by: Kumar, Kiran S <kiran.s.kumar at intel.com>
> Signed-off-by: Kausal Malladi <kausalmalladi at gmail.com>
The above should be kept in the order of which people worked on them.

> Reviewed-by: Matt Roper <matthew.d.roper at intel.com>

> --- a/drivers/gpu/drm/drm_atomic.c
> +++ b/drivers/gpu/drm/drm_atomic.c

> @@ -376,6 +377,57 @@ 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 int
> +drm_atomic_replace_property_blob(struct drm_property_blob **blob,
> +                                struct drm_property_blob *new_blob,
> +                                bool *replaced)
"Replaced" here and though the rest of the patch is used as "changed".
Worth naming it that way ?

> +{
> +       struct drm_property_blob *old_blob = *blob;
> +
> +       if (old_blob == new_blob)
> +               return 0;
> +
> +       if (old_blob)
> +               drm_property_unreference_blob(old_blob);
> +       if (new_blob)
> +               drm_property_reference_blob(new_blob);
> +       *blob = new_blob;
> +       *replaced = true;
> +
> +       return 0;
The function always succeeds - drop the return value ?

> +}
> +
> +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;
> +       }
> +
Having a look at drm_atomic_set_mode_prop_for_crtc() I think I can
spot a bug - it shouldn't drop/unref the old blob in case of an error.
A case you handle nicely here. Perhaps it's worth using the
drm_atomic_replace_property_blob() in there ?


> @@ -397,6 +449,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)
> @@ -407,8 +460,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->gamma_lut_property) {
> +               ret = drm_atomic_replace_property_blob_from_id(crtc,
> +                                       &state->gamma_lut,
> +                                       val,
> +                                       -1,
Wondering if these "-1" shouldn't be derived/replaced with the
contents of the respective _size properly ?


> @@ -444,6 +520,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 4da4f2a..7ab8040 100644
> --- a/drivers/gpu/drm/drm_atomic_helper.c
> +++ b/drivers/gpu/drm/drm_atomic_helper.c

> @@ -2557,6 +2564,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);
Might want to keep the dtor in reverse order comparing to the ctor -
duplicate_state()


> @@ -2870,3 +2880,96 @@ 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);
> +
To keep the bringup/teardown simpler (and complete):
Move create_blob() before to state_alloc() and null check blob
immediately. One would need to add unref_blob() when state_alloc()
fails.

> +       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;
Add new blank line please.

> +       ret = drm_atomic_crtc_set_property(crtc, crtc_state,
> +                       config->ctm_property, 0);
> +       if (ret)
> +               goto fail;
> +
> +       /* Set GAMMA_LUT with legacy values. */
> +       if (blob == NULL) {
> +               ret = -ENOMEM;
> +               goto fail;
> +       }
> +
> +       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];
> +       }
> +
Move this loop after create_blob()

> +       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 != 0)
Please check in a consistent way. Currently we have ret != 0 vs ret
and foo == NULL vs !foo.

> +               goto fail;
> +
> +       drm_property_unreference_blob(blob);
> +
> +       /* Driver takes ownership of state on successful commit. */
Move the comment before unreference_blob(), so that it's closer to
atomic_commit() ?


> --- a/drivers/gpu/drm/drm_crtc.c
> +++ b/drivers/gpu/drm/drm_crtc.c
> @@ -1554,6 +1554,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);

Just wondering -  don't we want this and the remaining properties to
be atomic only ? I doubt we have userspace that [will be updated to]
handle these, yet lacks atomic.


> --- 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);
Wondering if we cannot have these listed like elsewhere in the patch.
I.e. have the _size property just after its respective counterpart.

Regards,
Emil


More information about the dri-devel mailing list