diff mbox

[1/6] drm: Create Color Management DRM properties

Message ID 1450378678-24296-2-git-send-email-lionel.g.landwerlin@intel.com (mailing list archive)
State New, archived
Headers show

Commit Message

Lionel Landwerlin Dec. 17, 2015, 6:57 p.m. UTC
From: Shashank Sharma <shashank.sharma@intel.com>

Color Management is an extension to DRM framework to allow hardware color
correction and enhancement capabilities.

DRM color manager supports these color properties:
1. "ctm": Color transformation matrix property, where a
   color transformation matrix of 9 correction values gets
   applied as correction.
2. "palette_before_ctm": for corrections which get applied
   beore color transformation matrix correction.
3. "palette_after_ctm": for corrections which get applied
   after color transformation matrix correction.

These color correction capabilities may differ per platform, supporting
various different no. of correction coefficients. So DRM color manager
support few properties using which a user space can query the platform's
capability, and prepare color correction accordingly.
These query properties are:
1. cm_coeff_after_ctm_property
2. cm_coeff_before_ctm_property
  (CTM is fix to 9 coefficients across industry)

Signed-off-by: Shashank Sharma <shashank.sharma@intel.com>
Signed-off-by: Kausal Malladi <kausalmalladi@gmail.com>
---
 drivers/gpu/drm/drm_atomic.c        | 67 +++++++++++++++++++++++++++++++++++--
 drivers/gpu/drm/drm_atomic_helper.c |  9 +++++
 drivers/gpu/drm/drm_crtc.c          | 32 ++++++++++++++++++
 include/drm/drm_crtc.h              | 24 +++++++++++++
 include/uapi/drm/drm.h              | 30 +++++++++++++++++
 5 files changed, 160 insertions(+), 2 deletions(-)

Comments

kernel test robot Dec. 17, 2015, 9:40 p.m. UTC | #1
Hi Shashank,

[auto build test WARNING on drm-intel/for-linux-next]
[also build test WARNING on next-20151217]
[cannot apply to v4.4-rc5]

url:    https://github.com/0day-ci/linux/commits/Lionel-Landwerlin/Color-Management-for-DRM-framework-v10/20151218-025917
base:   git://anongit.freedesktop.org/drm-intel for-linux-next
reproduce: make htmldocs

All warnings (new ones prefixed by >>):

   drivers/gpu/drm/i915/i915_irq.c:2647: warning: No description found for parameter 'wedged'
   drivers/gpu/drm/i915/i915_irq.c:2647: warning: No description found for parameter 'fmt'
>> drivers/gpu/drm/drm_atomic.c:405: warning: No description found for parameter 'dev'
   include/drm/drm_crtc.h:324: warning: No description found for parameter 'mode_blob'
   include/drm/drm_crtc.h:751: warning: No description found for parameter 'tile_blob_ptr'
   include/drm/drm_crtc.h:790: warning: No description found for parameter 'rotation'
   include/drm/drm_crtc.h:886: warning: No description found for parameter 'mutex'
   include/drm/drm_crtc.h:886: warning: No description found for parameter 'helper_private'
   include/drm/drm_crtc.h:1185: warning: No description found for parameter 'tile_idr'
   include/drm/drm_crtc.h:1185: warning: No description found for parameter 'delayed_event'
   include/drm/drm_crtc.h:1185: warning: No description found for parameter 'edid_property'
   include/drm/drm_crtc.h:1185: warning: No description found for parameter 'dpms_property'
   include/drm/drm_crtc.h:1185: warning: No description found for parameter 'path_property'
   include/drm/drm_crtc.h:1185: warning: No description found for parameter 'tile_property'
   include/drm/drm_crtc.h:1185: warning: No description found for parameter 'plane_type_property'
   include/drm/drm_crtc.h:1185: warning: No description found for parameter 'rotation_property'
   include/drm/drm_crtc.h:1185: warning: No description found for parameter 'prop_src_x'
   include/drm/drm_crtc.h:1185: warning: No description found for parameter 'prop_src_y'
   include/drm/drm_crtc.h:1185: warning: No description found for parameter 'prop_src_w'
   include/drm/drm_crtc.h:1185: warning: No description found for parameter 'prop_src_h'
   include/drm/drm_crtc.h:1185: warning: No description found for parameter 'prop_crtc_x'
   include/drm/drm_crtc.h:1185: warning: No description found for parameter 'prop_crtc_y'
   include/drm/drm_crtc.h:1185: warning: No description found for parameter 'prop_crtc_w'
   include/drm/drm_crtc.h:1185: warning: No description found for parameter 'prop_crtc_h'
   include/drm/drm_crtc.h:1185: warning: No description found for parameter 'prop_fb_id'
   include/drm/drm_crtc.h:1185: warning: No description found for parameter 'prop_crtc_id'
   include/drm/drm_crtc.h:1185: warning: No description found for parameter 'prop_active'
   include/drm/drm_crtc.h:1185: warning: No description found for parameter 'prop_mode_id'
   include/drm/drm_crtc.h:1185: warning: No description found for parameter 'dvi_i_subconnector_property'
   include/drm/drm_crtc.h:1185: warning: No description found for parameter 'dvi_i_select_subconnector_property'
   include/drm/drm_crtc.h:1185: warning: No description found for parameter 'tv_subconnector_property'
   include/drm/drm_crtc.h:1185: warning: No description found for parameter 'tv_select_subconnector_property'
   include/drm/drm_crtc.h:1185: warning: No description found for parameter 'tv_mode_property'
   include/drm/drm_crtc.h:1185: warning: No description found for parameter 'tv_left_margin_property'
   include/drm/drm_crtc.h:1185: warning: No description found for parameter 'tv_right_margin_property'
   include/drm/drm_crtc.h:1185: warning: No description found for parameter 'tv_top_margin_property'
   include/drm/drm_crtc.h:1185: warning: No description found for parameter 'tv_bottom_margin_property'
   include/drm/drm_crtc.h:1185: warning: No description found for parameter 'tv_brightness_property'
   include/drm/drm_crtc.h:1185: warning: No description found for parameter 'tv_contrast_property'
   include/drm/drm_crtc.h:1185: warning: No description found for parameter 'tv_flicker_reduction_property'
   include/drm/drm_crtc.h:1185: warning: No description found for parameter 'tv_overscan_property'
   include/drm/drm_crtc.h:1185: warning: No description found for parameter 'tv_saturation_property'
   include/drm/drm_crtc.h:1185: warning: No description found for parameter 'tv_hue_property'
   include/drm/drm_crtc.h:1185: warning: No description found for parameter 'scaling_mode_property'
   include/drm/drm_crtc.h:1185: warning: No description found for parameter 'aspect_ratio_property'
   include/drm/drm_crtc.h:1185: warning: No description found for parameter 'dirty_info_property'
   include/drm/drm_crtc.h:1185: warning: No description found for parameter 'suggested_x_property'
   include/drm/drm_crtc.h:1185: warning: No description found for parameter 'suggested_y_property'
   include/drm/drm_crtc.h:1185: warning: No description found for parameter 'allow_fb_modifiers'
   include/drm/drm_fb_helper.h:148: warning: No description found for parameter 'connector_info'
   include/drm/drm_dp_helper.h:749: warning: No description found for parameter 'i2c_nack_count'
   include/drm/drm_dp_helper.h:749: warning: No description found for parameter 'i2c_defer_count'
   drivers/gpu/drm/drm_dp_mst_topology.c:2237: warning: No description found for parameter 'connector'
   include/drm/drm_dp_mst_helper.h:98: warning: No description found for parameter 'cached_edid'
   include/drm/drm_dp_mst_helper.h:98: warning: No description found for parameter 'has_audio'
   include/drm/drm_dp_mst_helper.h:473: warning: No description found for parameter 'max_dpcd_transaction_bytes'
   include/drm/drm_dp_mst_helper.h:473: warning: No description found for parameter 'sink_count'
   include/drm/drm_dp_mst_helper.h:473: warning: No description found for parameter 'total_slots'
   include/drm/drm_dp_mst_helper.h:473: warning: No description found for parameter 'avail_slots'
   include/drm/drm_dp_mst_helper.h:473: warning: No description found for parameter 'total_pbn'
   include/drm/drm_dp_mst_helper.h:473: warning: No description found for parameter 'qlock'
   include/drm/drm_dp_mst_helper.h:473: warning: No description found for parameter 'tx_msg_downq'
   include/drm/drm_dp_mst_helper.h:473: warning: No description found for parameter 'tx_msg_upq'
   include/drm/drm_dp_mst_helper.h:473: warning: No description found for parameter 'tx_down_in_progress'
   include/drm/drm_dp_mst_helper.h:473: warning: No description found for parameter 'tx_up_in_progress'
   include/drm/drm_dp_mst_helper.h:473: warning: No description found for parameter 'payload_lock'
   include/drm/drm_dp_mst_helper.h:473: warning: No description found for parameter 'proposed_vcpis'
   include/drm/drm_dp_mst_helper.h:473: warning: No description found for parameter 'payloads'
   include/drm/drm_dp_mst_helper.h:473: warning: No description found for parameter 'payload_mask'
   include/drm/drm_dp_mst_helper.h:473: warning: No description found for parameter 'vcpi_mask'
   include/drm/drm_dp_mst_helper.h:473: warning: No description found for parameter 'tx_waitq'
   include/drm/drm_dp_mst_helper.h:473: warning: No description found for parameter 'work'
   include/drm/drm_dp_mst_helper.h:473: warning: No description found for parameter 'tx_work'
   include/drm/drm_dp_mst_helper.h:473: warning: No description found for parameter 'destroy_connector_list'
   include/drm/drm_dp_mst_helper.h:473: warning: No description found for parameter 'destroy_connector_lock'
   include/drm/drm_dp_mst_helper.h:473: warning: No description found for parameter 'destroy_connector_work'
   drivers/gpu/drm/drm_dp_mst_topology.c:2237: warning: No description found for parameter 'connector'
   drivers/gpu/drm/drm_irq.c:173: warning: No description found for parameter 'flags'
   include/drm/drmP.h:168: warning: No description found for parameter 'fmt'
   include/drm/drmP.h:184: warning: No description found for parameter 'fmt'
   include/drm/drmP.h:202: warning: No description found for parameter 'fmt'
   include/drm/drmP.h:247: warning: No description found for parameter 'dev'
   include/drm/drmP.h:247: warning: No description found for parameter 'data'
   include/drm/drmP.h:247: warning: No description found for parameter 'file_priv'
   include/drm/drmP.h:280: warning: No description found for parameter 'ioctl'
   include/drm/drmP.h:280: warning: No description found for parameter '_func'
   include/drm/drmP.h:280: warning: No description found for parameter '_flags'
   include/drm/drmP.h:360: warning: cannot understand function prototype: 'struct drm_lock_data '
   include/drm/drmP.h:413: warning: cannot understand function prototype: 'struct drm_driver '
   include/drm/drmP.h:663: warning: cannot understand function prototype: 'struct drm_info_list '
   include/drm/drmP.h:673: warning: cannot understand function prototype: 'struct drm_info_node '
   include/drm/drmP.h:683: warning: cannot understand function prototype: 'struct drm_minor '
   include/drm/drmP.h:731: warning: cannot understand function prototype: 'struct drm_device '
   drivers/gpu/drm/i915/intel_runtime_pm.c:2180: warning: No description found for parameter 'resume'
   drivers/gpu/drm/i915/intel_runtime_pm.c:2180: warning: No description found for parameter 'resume'
   drivers/gpu/drm/i915/i915_irq.c:2647: warning: No description found for parameter 'wedged'
   drivers/gpu/drm/i915/i915_irq.c:2647: warning: No description found for parameter 'fmt'
   drivers/gpu/drm/i915/i915_irq.c:2647: warning: No description found for parameter 'wedged'
   drivers/gpu/drm/i915/i915_irq.c:2647: warning: No description found for parameter 'fmt'
   drivers/gpu/drm/i915/i915_irq.c:2647: warning: No description found for parameter 'wedged'
   drivers/gpu/drm/i915/i915_irq.c:2647: warning: No description found for parameter 'fmt'
   drivers/gpu/drm/i915/i915_irq.c:2647: warning: No description found for parameter 'wedged'
   drivers/gpu/drm/i915/i915_irq.c:2647: warning: No description found for parameter 'fmt'

vim +/dev +405 drivers/gpu/drm/drm_atomic.c

   389	
   390	/**
   391	 * drm_atomic_crtc_set_blob - find and set a blob
   392	 * @state_blob: reference pointer to the color blob in the crtc_state
   393	 * @blob_id: blob_id coming from set_property() call
   394	 *
   395	 * Set a color correction blob (originating from a set blob property) on the
   396	 * desired CRTC state. This function will take reference of the blob property
   397	 * in the CRTC state, finds the blob based on blob_id (which comes from
   398	 * set_property call) and set the blob at the proper place.
   399	 *
   400	 * RETURNS:
   401	 * Zero on success, error code on failure.
   402	 */
   403	static int drm_atomic_crtc_set_blob(struct drm_device *dev,
   404		struct drm_property_blob **state_blob, uint32_t blob_id)
 > 405	{
   406		struct drm_property_blob *blob;
   407	
   408		blob = drm_property_lookup_blob(dev, blob_id);
   409		if (!blob) {
   410			DRM_DEBUG_KMS("Invalid Blob ID\n");
   411			return -EINVAL;
   412		}
   413	

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
Daniel Stone Dec. 18, 2015, 4:53 p.m. UTC | #2
[Paging danvet to the bottom paragraphs re client-cap ...]

Hi Lionel,
I've still got quite a few concerns about the implementation as it
stands. Some are minor quibbles (e.g. can't unset blob IDs), some are
larger design issues, some are rehashed comments from previous series,
and some are new now I've looked at it afresh.

On 17 December 2015 at 18:57, Lionel Landwerlin
<lionel.g.landwerlin@intel.com> wrote:
> DRM color manager supports these color properties:
> 1. "ctm": Color transformation matrix property, where a
>    color transformation matrix of 9 correction values gets
>    applied as correction.
> 2. "palette_before_ctm": for corrections which get applied
>    beore color transformation matrix correction.
> 3. "palette_after_ctm": for corrections which get applied
>    after color transformation matrix correction.

These all appear to be pretty common, at least for the platforms I've
checked. So, sounds good. You might want to document that before and
after palettes are often referred to as degamma and gamma,
respectively, though.

>  /**
> + * drm_atomic_crtc_set_blob - find and set a blob
> + * @state_blob: reference pointer to the color blob in the crtc_state
> + * @blob_id: blob_id coming from set_property() call
> + *
> + * Set a color correction blob (originating from a set blob property) on the
> + * desired CRTC state. This function will take reference of the blob property
> + * in the CRTC state, finds the blob based on blob_id (which comes from
> + * set_property call) and set the blob at the proper place.
> + *
> + * RETURNS:
> + * Zero on success, error code on failure.
> + */
> +static int drm_atomic_crtc_set_blob(struct drm_device *dev,
> +       struct drm_property_blob **state_blob, uint32_t blob_id)
> +{
> +       struct drm_property_blob *blob;
> +
> +       blob = drm_property_lookup_blob(dev, blob_id);
> +       if (!blob) {
> +               DRM_DEBUG_KMS("Invalid Blob ID\n");
> +               return -EINVAL;
> +       }

This needs to handle blob_id == 0, to unset it. Initialising 'blob' to
NULL and wrapping the lookup_blob check in if (blob_id != 0) should do
it. While you're at it, a more helpful error message (e.g. actually
listing the blob ID) might be in order. And IGT.

Making crtc_state->MODE_ID use this helper, and kms_atomic not
breaking, would be a fairly good indication that you've got it right.
;)

> @@ -305,11 +305,15 @@ struct drm_plane_helper_funcs;
>   * @mode_changed: crtc_state->mode or crtc_state->enable has been changed
>   * @active_changed: crtc_state->active has been toggled.
>   * @connectors_changed: connectors to this crtc have been updated
> + * @color_correction_changed: color correction blob in this crtc got updated
>   * @plane_mask: bitmask of (1 << drm_plane_index(plane)) of attached planes
>   * @last_vblank_count: for helpers and drivers to capture the vblank of the
>   *     update to ensure framebuffer cleanup isn't done too early
>   * @adjusted_mode: for use by helpers and drivers to compute adjusted mode timings
>   * @mode: current mode timings
> + * @palette_before_ctm_blob: blob for color corrections to be applied after CTM
> + * @palette_after_ctm_blob: blob for color corrections to be applied before CTM
> + * @ctm_blob: blob for CTM color correction

For instance, documenting (de)gamma terminology here might be nice.

> @@ -2019,6 +2029,11 @@ struct drm_mode_config_funcs {
>   * @property_blob_list: list of all the blob property objects
>   * @blob_lock: mutex for blob property allocation and management
>   * @*_property: core property tracking
> + * @cm_palette_before_ctm_property: color corrections before CTM block
> + * @cm_palette_after_ctm_property: color corrections after CTM block
> + * @cm_ctm_property: color transformation matrix correction
> + * @cm_coeff_before_ctm_property: query no of correction coeffi before CTM
> + * @cm_coeff_after_ctm_property: query no of correction coeffi after CTM

'coeffi'? These also aren't sufficient either (see my descent into
madness in the BDW patch), I don't think.

> +struct drm_r32g32b32 {
> +       /*
> +        * Data is in U8.24 fixed point format.
> +        * All platforms support values within [0, 1.0] range,
> +        * for Red, Green and Blue colors.
> +        */
> +       __u32 r32;
> +       __u32 g32;
> +       __u32 b32;
> +       __u32 reserved;
> +};

Wait, it's U8.24 (i.e. 0 -> 255.09999999403953517), but the supported
range is [0..1.0]? What am I missing?

> +struct drm_palette {
> +       /*
> +        * Starting of palette LUT in R32G32B32 format.
> +        * Each of RGB value is in U8.24 fixed point format.
> +        */
> +       struct drm_r32g32b32 lut[0];
> +};

Why the indirection; can we just expose the member directly?

> +struct drm_ctm {
> +       /*
> +        * Each value is in S31.32 format.
> +        * This is 3x3 matrix in row major format.
> +        * Integer part will be clipped to nearest
> +        * max/min boundary as supported by the HW platform.
> +        */
> +       __s64 ctm_coeff[9];
> +};

Perhaps ditto, but this seems more valid. As a total bikeshed,
'ctm_coeff' is redundant in a structure named drm_ctm anyway. Having
these namespaced into something consistent (e.g. drm_color_ or
whatever) might be nice too.

All in all, I have to admit I'm fairly baffled as to how I'd actually
use this from generic userspace. Not being able to divine the correct
list length (see BDW) is a showstopper. Having repeated conflicting
comments on the range (8.24 or 0.24?) is greatly confusing. Sign
wraparound on CHV is confusing, as is the '8-bit' vs. '10-bit' modes
which appear to do exactly the same thing (but with one more entry).
Not supporting blob == NULL to disable is pretty much a non-starter.

I also don't have a good answer on how to support non-CM-aware
clients. Currently they'll just blindly carry around the correction
factors from previous clients, which is _really_ bad: imagine you have
Weston ported to use KMS/CM to correct perfectly, and then start
Mutter/GNOME which still corrects perfectly, but using lcms and
various client-side compensation rather than the CM engine. Your
output will now be double-corrected, i.e. wrong, because Mutter won't
know to reset the CM properties.

About the only thing I can think of is to add a
DRM_CLIENT_CAP_COLOR_MGMT, and modify drm_atomic_*_duplicate_state to
take client caps (passed in from file_priv with the atomic ioctl, or
explicitly set by other kernel code, according to its capabilities),
and if the CM cap is not set, clear out the blobs when duplicating
state.

All of this also needs to be backed up by a lot more extensive IGT,
including disabling (from _every_ mode, not just 12-bit mode on BDW)
via setting blob == NULL, testing the various depths (I still don't
understand the difference between 8 and 10-bit on CHV), legacy gamma
hooks when using CM, testing reset/dumb clients when the above
duplicate_state issue is resolved, and especially the boundary cases
in conversions (e.g. the sign wraparound on CHV). The documentation
also _really_ needs fixing to be consistent with the code, and
consistent with itself. When that's done, I think I'll be
better-placed to do a second pass review, because after however many
revisions, I still can't clearly see how it would be used from generic
userspace (as opposed to an Intel-specific colour manager).

Sorry this probably isn't quite the Christmas present you'd hoped for ...

Cheers,
Daniel
Daniel Vetter Dec. 21, 2015, 12:38 p.m. UTC | #3
On Fri, Dec 18, 2015 at 04:53:28PM +0000, Daniel Stone wrote:
> [Paging danvet to the bottom paragraphs re client-cap ...]
> 
> Hi Lionel,
> I've still got quite a few concerns about the implementation as it
> stands. Some are minor quibbles (e.g. can't unset blob IDs), some are
> larger design issues, some are rehashed comments from previous series,
> and some are new now I've looked at it afresh.
> 
> On 17 December 2015 at 18:57, Lionel Landwerlin
> <lionel.g.landwerlin@intel.com> wrote:
> > DRM color manager supports these color properties:
> > 1. "ctm": Color transformation matrix property, where a
> >    color transformation matrix of 9 correction values gets
> >    applied as correction.
> > 2. "palette_before_ctm": for corrections which get applied
> >    beore color transformation matrix correction.
> > 3. "palette_after_ctm": for corrections which get applied
> >    after color transformation matrix correction.
> 
> These all appear to be pretty common, at least for the platforms I've
> checked. So, sounds good. You might want to document that before and
> after palettes are often referred to as degamma and gamma,
> respectively, though.
> 
> >  /**
> > + * drm_atomic_crtc_set_blob - find and set a blob
> > + * @state_blob: reference pointer to the color blob in the crtc_state
> > + * @blob_id: blob_id coming from set_property() call
> > + *
> > + * Set a color correction blob (originating from a set blob property) on the
> > + * desired CRTC state. This function will take reference of the blob property
> > + * in the CRTC state, finds the blob based on blob_id (which comes from
> > + * set_property call) and set the blob at the proper place.
> > + *
> > + * RETURNS:
> > + * Zero on success, error code on failure.
> > + */
> > +static int drm_atomic_crtc_set_blob(struct drm_device *dev,
> > +       struct drm_property_blob **state_blob, uint32_t blob_id)
> > +{
> > +       struct drm_property_blob *blob;
> > +
> > +       blob = drm_property_lookup_blob(dev, blob_id);
> > +       if (!blob) {
> > +               DRM_DEBUG_KMS("Invalid Blob ID\n");
> > +               return -EINVAL;
> > +       }
> 
> This needs to handle blob_id == 0, to unset it. Initialising 'blob' to
> NULL and wrapping the lookup_blob check in if (blob_id != 0) should do
> it. While you're at it, a more helpful error message (e.g. actually
> listing the blob ID) might be in order. And IGT.
> 
> Making crtc_state->MODE_ID use this helper, and kms_atomic not
> breaking, would be a fairly good indication that you've got it right.
> ;)
> 
> > @@ -305,11 +305,15 @@ struct drm_plane_helper_funcs;
> >   * @mode_changed: crtc_state->mode or crtc_state->enable has been changed
> >   * @active_changed: crtc_state->active has been toggled.
> >   * @connectors_changed: connectors to this crtc have been updated
> > + * @color_correction_changed: color correction blob in this crtc got updated
> >   * @plane_mask: bitmask of (1 << drm_plane_index(plane)) of attached planes
> >   * @last_vblank_count: for helpers and drivers to capture the vblank of the
> >   *     update to ensure framebuffer cleanup isn't done too early
> >   * @adjusted_mode: for use by helpers and drivers to compute adjusted mode timings
> >   * @mode: current mode timings
> > + * @palette_before_ctm_blob: blob for color corrections to be applied after CTM
> > + * @palette_after_ctm_blob: blob for color corrections to be applied before CTM
> > + * @ctm_blob: blob for CTM color correction
> 
> For instance, documenting (de)gamma terminology here might be nice.
> 
> > @@ -2019,6 +2029,11 @@ struct drm_mode_config_funcs {
> >   * @property_blob_list: list of all the blob property objects
> >   * @blob_lock: mutex for blob property allocation and management
> >   * @*_property: core property tracking
> > + * @cm_palette_before_ctm_property: color corrections before CTM block
> > + * @cm_palette_after_ctm_property: color corrections after CTM block
> > + * @cm_ctm_property: color transformation matrix correction
> > + * @cm_coeff_before_ctm_property: query no of correction coeffi before CTM
> > + * @cm_coeff_after_ctm_property: query no of correction coeffi after CTM
> 
> 'coeffi'? These also aren't sufficient either (see my descent into
> madness in the BDW patch), I don't think.

Yeah there's a question about how to best document new atomic extensions.
Traditionally we haven't documented the properties themselves (hence the
*_property), and I think that makes sense since it's a very large pile.
Two options left:
- Extensively document all the properties for a new feature in the drm
  core function to attach the props to a plane/crtc.

- Document them in the drm_*_state structures. There we can even use the
  new per-member kerneldoc layout to go into great details.

Probably best to do both and link between the two places.
> 
> > +struct drm_r32g32b32 {
> > +       /*
> > +        * Data is in U8.24 fixed point format.
> > +        * All platforms support values within [0, 1.0] range,
> > +        * for Red, Green and Blue colors.
> > +        */
> > +       __u32 r32;
> > +       __u32 g32;
> > +       __u32 b32;
> > +       __u32 reserved;
> > +};
> 
> Wait, it's U8.24 (i.e. 0 -> 255.09999999403953517), but the supported
> range is [0..1.0]? What am I missing?

Probably means:
- all platforms MUST support [0.0, 1.0] range, inclusive
- platforms CAN support larger values (which can make sense in degamma
  tables if your CTM will shrink things down again).

> 
> > +struct drm_palette {
> > +       /*
> > +        * Starting of palette LUT in R32G32B32 format.
> > +        * Each of RGB value is in U8.24 fixed point format.
> > +        */
> > +       struct drm_r32g32b32 lut[0];
> > +};
> 
> Why the indirection; can we just expose the member directly?
> 
> > +struct drm_ctm {
> > +       /*
> > +        * Each value is in S31.32 format.
> > +        * This is 3x3 matrix in row major format.
> > +        * Integer part will be clipped to nearest
> > +        * max/min boundary as supported by the HW platform.
> > +        */
> > +       __s64 ctm_coeff[9];
> > +};
> 
> Perhaps ditto, but this seems more valid. As a total bikeshed,
> 'ctm_coeff' is redundant in a structure named drm_ctm anyway. Having
> these namespaced into something consistent (e.g. drm_color_ or
> whatever) might be nice too.
> 
> All in all, I have to admit I'm fairly baffled as to how I'd actually
> use this from generic userspace. Not being able to divine the correct
> list length (see BDW) is a showstopper. Having repeated conflicting
> comments on the range (8.24 or 0.24?) is greatly confusing. Sign
> wraparound on CHV is confusing, as is the '8-bit' vs. '10-bit' modes
> which appear to do exactly the same thing (but with one more entry).
> Not supporting blob == NULL to disable is pretty much a non-starter.
> 
> I also don't have a good answer on how to support non-CM-aware
> clients. Currently they'll just blindly carry around the correction
> factors from previous clients, which is _really_ bad: imagine you have
> Weston ported to use KMS/CM to correct perfectly, and then start
> Mutter/GNOME which still corrects perfectly, but using lcms and
> various client-side compensation rather than the CM engine. Your
> output will now be double-corrected, i.e. wrong, because Mutter won't
> know to reset the CM properties.

Hm yeah, I think legacy entry points should remap to atomic ones.
Otherwise things are massively inconsistent (and we have a problem
figuring out when/which table applies in the driver). One problem with
that approach is that the legacy table has the assumption of a fixed
256 entries (well we expose the size somewhere, but that's what everyone
uses). At least on some platforms, the full-blown table used by these
patches isn't even an integer multiple of that.

> About the only thing I can think of is to add a
> DRM_CLIENT_CAP_COLOR_MGMT, and modify drm_atomic_*_duplicate_state to
> take client caps (passed in from file_priv with the atomic ioctl, or
> explicitly set by other kernel code, according to its capabilities),
> and if the CM cap is not set, clear out the blobs when duplicating
> state.
> 
> All of this also needs to be backed up by a lot more extensive IGT,
> including disabling (from _every_ mode, not just 12-bit mode on BDW)
> via setting blob == NULL, testing the various depths (I still don't
> understand the difference between 8 and 10-bit on CHV), legacy gamma
> hooks when using CM, testing reset/dumb clients when the above
> duplicate_state issue is resolved, and especially the boundary cases
> in conversions (e.g. the sign wraparound on CHV). The documentation
> also _really_ needs fixing to be consistent with the code, and
> consistent with itself. When that's done, I think I'll be
> better-placed to do a second pass review, because after however many
> revisions, I still can't clearly see how it would be used from generic
> userspace (as opposed to an Intel-specific colour manager).

One bit I'm not sure (and which isn't documented here) is that there's
supposed to be a read-only hint property telling new generic userspace
what tables are expected. This might mean you're not always using the most
awesome configuration, but it should at least work. That part of the
design seems to be undocumented.
-Daniel
Daniel Vetter Dec. 21, 2015, 12:43 p.m. UTC | #4
On Thu, Dec 17, 2015 at 06:57:53PM +0000, Lionel Landwerlin wrote:
> From: Shashank Sharma <shashank.sharma@intel.com>
> 
> Color Management is an extension to DRM framework to allow hardware color
> correction and enhancement capabilities.
> 
> DRM color manager supports these color properties:
> 1. "ctm": Color transformation matrix property, where a
>    color transformation matrix of 9 correction values gets
>    applied as correction.
> 2. "palette_before_ctm": for corrections which get applied
>    beore color transformation matrix correction.
> 3. "palette_after_ctm": for corrections which get applied
>    after color transformation matrix correction.
> 
> These color correction capabilities may differ per platform, supporting
> various different no. of correction coefficients. So DRM color manager
> support few properties using which a user space can query the platform's
> capability, and prepare color correction accordingly.
> These query properties are:
> 1. cm_coeff_after_ctm_property
> 2. cm_coeff_before_ctm_property
>   (CTM is fix to 9 coefficients across industry)
> 
> Signed-off-by: Shashank Sharma <shashank.sharma@intel.com>
> Signed-off-by: Kausal Malladi <kausalmalladi@gmail.com>
> ---
>  drivers/gpu/drm/drm_atomic.c        | 67 +++++++++++++++++++++++++++++++++++--
>  drivers/gpu/drm/drm_atomic_helper.c |  9 +++++
>  drivers/gpu/drm/drm_crtc.c          | 32 ++++++++++++++++++
>  include/drm/drm_crtc.h              | 24 +++++++++++++
>  include/uapi/drm/drm.h              | 30 +++++++++++++++++
>  5 files changed, 160 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
> index 6a21e5c..ebdb98d 100644
> --- a/drivers/gpu/drm/drm_atomic.c
> +++ b/drivers/gpu/drm/drm_atomic.c
> @@ -388,6 +388,38 @@ int drm_atomic_set_mode_prop_for_crtc(struct drm_crtc_state *state,
>  EXPORT_SYMBOL(drm_atomic_set_mode_prop_for_crtc);
>  
>  /**
> + * drm_atomic_crtc_set_blob - find and set a blob
> + * @state_blob: reference pointer to the color blob in the crtc_state
> + * @blob_id: blob_id coming from set_property() call
> + *
> + * Set a color correction blob (originating from a set blob property) on the
> + * desired CRTC state. This function will take reference of the blob property
> + * in the CRTC state, finds the blob based on blob_id (which comes from
> + * set_property call) and set the blob at the proper place.
> + *
> + * RETURNS:
> + * Zero on success, error code on failure.
> + */
> +static int drm_atomic_crtc_set_blob(struct drm_device *dev,
> +	struct drm_property_blob **state_blob, uint32_t blob_id)

I think we need to at least split this into a ctm and gamma table variant
to be able to have a size check for the passed-in blob:
- ctm must exactly match the size we expect
- gamma table must be an integer multiple of the drm_r32g32b32 struct.
  Also we should probably have a little helper to compute the size of the
  gamma lut in entries (just the size/sizeof(drm_r32g32b32) division
  really).


The other bits that's missing here is a drm core function to attach these
properties to planes/crtc. We don't want every driver to roll their own
implementation, since it'll lead to fun divergence between different
implementations. Also, that main function could be used to place the ABI
rules someplace nice (like how generic userspace is supposed to interact
with color manager props).
-Daniel

> +{
> +	struct drm_property_blob *blob;
> +
> +	blob = drm_property_lookup_blob(dev, blob_id);
> +	if (!blob) {
> +		DRM_DEBUG_KMS("Invalid Blob ID\n");
> +		return -EINVAL;
> +	}
> +
> +	if (*state_blob)
> +		drm_property_unreference_blob(*state_blob);
> +
> +	/* Attach the blob to be committed in state */
> +	*state_blob = blob;
> +	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
> @@ -419,8 +451,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->cm_palette_after_ctm_property) {
> +		ret = drm_atomic_crtc_set_blob(dev,
> +				&state->palette_after_ctm_blob, val);
> +		if (ret)
> +			DRM_DEBUG_KMS("Failed to load blob palette_after_ctm\n");
> +		else
> +			state->color_correction_changed = true;
> +		return ret;
> +	} else if (property == config->cm_palette_before_ctm_property) {
> +		ret = drm_atomic_crtc_set_blob(dev,
> +				&state->palette_before_ctm_blob, val);
> +		if (ret)
> +			DRM_DEBUG_KMS("Failed to load blob palette_before_ctm\n");
> +		else
> +			state->color_correction_changed = true;
> +		return ret;
> +	} else if (property == config->cm_ctm_property) {
> +		ret = drm_atomic_crtc_set_blob(dev,
> +				&state->ctm_blob, val);
> +		if (ret)
> +			DRM_DEBUG_KMS("Failed to load blob ctm\n");
> +		else
> +			state->color_correction_changed = true;
> +		return ret;
> +	} else if (crtc->funcs->atomic_set_property)
>  		return crtc->funcs->atomic_set_property(crtc, state, property, val);
>  	else
>  		return -EINVAL;
> @@ -456,6 +511,14 @@ 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->cm_palette_after_ctm_property)
> +		*val = (state->palette_after_ctm_blob) ?
> +			state->palette_after_ctm_blob->base.id : 0;
> +	else if (property == config->cm_palette_before_ctm_property)
> +		*val = (state->palette_before_ctm_blob) ?
> +			state->palette_before_ctm_blob->base.id : 0;
> +	else if (property == config->cm_ctm_property)
> +		*val = (state->ctm_blob) ? state->ctm_blob->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 268d37f..bd325da 100644
> --- a/drivers/gpu/drm/drm_atomic_helper.c
> +++ b/drivers/gpu/drm/drm_atomic_helper.c
> @@ -2448,6 +2448,12 @@ void __drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc,
>  
>  	if (state->mode_blob)
>  		drm_property_reference_blob(state->mode_blob);
> +	if (state->ctm_blob)
> +		drm_property_reference_blob(state->ctm_blob);
> +	if (state->palette_after_ctm_blob)
> +		drm_property_reference_blob(state->palette_after_ctm_blob);
> +	if (state->palette_before_ctm_blob)
> +		drm_property_reference_blob(state->palette_before_ctm_blob);
>  	state->mode_changed = false;
>  	state->active_changed = false;
>  	state->planes_changed = false;
> @@ -2492,6 +2498,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->ctm_blob);
> +	drm_property_unreference_blob(state->palette_after_ctm_blob);
> +	drm_property_unreference_blob(state->palette_before_ctm_blob);
>  }
>  EXPORT_SYMBOL(__drm_atomic_helper_crtc_destroy_state);
>  
> diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
> index 62fa95f..2e02d0f 100644
> --- a/drivers/gpu/drm/drm_crtc.c
> +++ b/drivers/gpu/drm/drm_crtc.c
> @@ -1542,6 +1542,38 @@ static int drm_mode_create_standard_properties(struct drm_device *dev)
>  		return -ENOMEM;
>  	dev->mode_config.prop_mode_id = prop;
>  
> +	/* Color Management properties */
> +	prop = drm_property_create(dev,
> +			DRM_MODE_PROP_BLOB, "PALETTE_AFTER_CTM", 0);
> +	if (!prop)
> +		return -ENOMEM;
> +	dev->mode_config.cm_palette_after_ctm_property = prop;
> +
> +	prop = drm_property_create(dev,
> +			DRM_MODE_PROP_BLOB, "PALETTE_BEFORE_CTM", 0);
> +	if (!prop)
> +		return -ENOMEM;
> +	dev->mode_config.cm_palette_before_ctm_property = prop;
> +
> +	prop = drm_property_create(dev,
> +			DRM_MODE_PROP_BLOB, "CTM", 0);
> +	if (!prop)
> +		return -ENOMEM;
> +	dev->mode_config.cm_ctm_property = prop;
> +
> +	/* DRM properties to query color capabilities */
> +	prop = drm_property_create(dev, DRM_MODE_PROP_IMMUTABLE,
> +			"COEFFICIENTS_BEFORE_CTM", 0);
> +	if (!prop)
> +		return -ENOMEM;
> +	dev->mode_config.cm_coeff_before_ctm_property = prop;
> +
> +	prop = drm_property_create(dev, DRM_MODE_PROP_IMMUTABLE,
> +			"COEFFICIENTS_AFTER_CTM", 0);
> +	if (!prop)
> +		return -ENOMEM;
> +	dev->mode_config.cm_coeff_after_ctm_property = prop;
> +
>  	return 0;
>  }
>  
> diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
> index 3b040b3..8326765 100644
> --- a/include/drm/drm_crtc.h
> +++ b/include/drm/drm_crtc.h
> @@ -305,11 +305,15 @@ struct drm_plane_helper_funcs;
>   * @mode_changed: crtc_state->mode or crtc_state->enable has been changed
>   * @active_changed: crtc_state->active has been toggled.
>   * @connectors_changed: connectors to this crtc have been updated
> + * @color_correction_changed: color correction blob in this crtc got updated
>   * @plane_mask: bitmask of (1 << drm_plane_index(plane)) of attached planes
>   * @last_vblank_count: for helpers and drivers to capture the vblank of the
>   * 	update to ensure framebuffer cleanup isn't done too early
>   * @adjusted_mode: for use by helpers and drivers to compute adjusted mode timings
>   * @mode: current mode timings
> + * @palette_before_ctm_blob: blob for color corrections to be applied after CTM
> + * @palette_after_ctm_blob: blob for color corrections to be applied before CTM
> + * @ctm_blob: blob for CTM color correction
>   * @event: optional pointer to a DRM event to signal upon completion of the
>   * 	state update
>   * @state: backpointer to global drm_atomic_state
> @@ -331,6 +335,7 @@ struct drm_crtc_state {
>  	bool mode_changed : 1;
>  	bool active_changed : 1;
>  	bool connectors_changed : 1;
> +	bool color_correction_changed : 1;
>  
>  	/* attached planes bitmask:
>  	 * WARNING: transitional helpers do not maintain plane_mask so
> @@ -350,6 +355,11 @@ struct drm_crtc_state {
>  	/* blob property to expose current mode to atomic userspace */
>  	struct drm_property_blob *mode_blob;
>  
> +	/* Color management blobs */
> +	struct drm_property_blob *palette_before_ctm_blob;
> +	struct drm_property_blob *palette_after_ctm_blob;
> +	struct drm_property_blob *ctm_blob;
> +
>  	struct drm_pending_vblank_event *event;
>  
>  	struct drm_atomic_state *state;
> @@ -2019,6 +2029,11 @@ struct drm_mode_config_funcs {
>   * @property_blob_list: list of all the blob property objects
>   * @blob_lock: mutex for blob property allocation and management
>   * @*_property: core property tracking
> + * @cm_palette_before_ctm_property: color corrections before CTM block
> + * @cm_palette_after_ctm_property: color corrections after CTM block
> + * @cm_ctm_property: color transformation matrix correction
> + * @cm_coeff_before_ctm_property: query no of correction coeffi before CTM
> + * @cm_coeff_after_ctm_property: query no of correction coeffi after CTM
>   * @preferred_depth: preferred RBG pixel depth, used by fb helpers
>   * @prefer_shadow: hint to userspace to prefer shadow-fb rendering
>   * @async_page_flip: does this device support async flips on the primary plane?
> @@ -2124,6 +2139,15 @@ struct drm_mode_config {
>  	struct drm_property *suggested_x_property;
>  	struct drm_property *suggested_y_property;
>  
> +	/* Color correction properties */
> +	struct drm_property *cm_palette_before_ctm_property;
> +	struct drm_property *cm_palette_after_ctm_property;
> +	struct drm_property *cm_ctm_property;
> +
> +	/* Color correction query */
> +	struct drm_property *cm_coeff_before_ctm_property;
> +	struct drm_property *cm_coeff_after_ctm_property;
> +
>  	/* dumb ioctl parameters */
>  	uint32_t preferred_depth, prefer_shadow;
>  
> diff --git a/include/uapi/drm/drm.h b/include/uapi/drm/drm.h
> index b4e92eb..24e4520 100644
> --- a/include/uapi/drm/drm.h
> +++ b/include/uapi/drm/drm.h
> @@ -830,6 +830,36 @@ struct drm_event_vblank {
>  	__u32 reserved;
>  };
>  
> +struct drm_r32g32b32 {
> +	/*
> +	 * Data is in U8.24 fixed point format.
> +	 * All platforms support values within [0, 1.0] range,
> +	 * for Red, Green and Blue colors.
> +	 */
> +	__u32 r32;
> +	__u32 g32;
> +	__u32 b32;
> +	__u32 reserved;
> +};
> +
> +struct drm_palette {
> +	/*
> +	 * Starting of palette LUT in R32G32B32 format.
> +	 * Each of RGB value is in U8.24 fixed point format.
> +	 */
> +	struct drm_r32g32b32 lut[0];
> +};
> +
> +struct drm_ctm {
> +	/*
> +	 * Each value is in S31.32 format.
> +	 * This is 3x3 matrix in row major format.
> +	 * Integer part will be clipped to nearest
> +	 * max/min boundary as supported by the HW platform.
> +	 */
> +	__s64 ctm_coeff[9];
> +};
> +
>  /* typedef area */
>  #ifndef __KERNEL__
>  typedef struct drm_clip_rect drm_clip_rect_t;
> -- 
> 2.6.3
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx
Daniel Stone Dec. 23, 2015, 9:47 a.m. UTC | #5
Hi,

On 21 December 2015 at 12:38, Daniel Vetter <daniel@ffwll.ch> wrote:
> On Fri, Dec 18, 2015 at 04:53:28PM +0000, Daniel Stone wrote:
>> > +struct drm_r32g32b32 {
>> > +       /*
>> > +        * Data is in U8.24 fixed point format.
>> > +        * All platforms support values within [0, 1.0] range,
>> > +        * for Red, Green and Blue colors.
>> > +        */
>> > +       __u32 r32;
>> > +       __u32 g32;
>> > +       __u32 b32;
>> > +       __u32 reserved;
>> > +};
>>
>> Wait, it's U8.24 (i.e. 0 -> 255.09999999403953517), but the supported
>> range is [0..1.0]? What am I missing?
>
> Probably means:
> - all platforms MUST support [0.0, 1.0] range, inclusive
> - platforms CAN support larger values (which can make sense in degamma
>   tables if your CTM will shrink things down again).

Ah, makes sense.

>> I also don't have a good answer on how to support non-CM-aware
>> clients. Currently they'll just blindly carry around the correction
>> factors from previous clients, which is _really_ bad: imagine you have
>> Weston ported to use KMS/CM to correct perfectly, and then start
>> Mutter/GNOME which still corrects perfectly, but using lcms and
>> various client-side compensation rather than the CM engine. Your
>> output will now be double-corrected, i.e. wrong, because Mutter won't
>> know to reset the CM properties.
>
> Hm yeah, I think legacy entry points should remap to atomic ones.
> Otherwise things are massively inconsistent (and we have a problem
> figuring out when/which table applies in the driver). One problem with
> that approach is that the legacy table has the assumption of a fixed
> 256 entries (well we expose the size somewhere, but that's what everyone
> uses). At least on some platforms, the full-blown table used by these
> patches isn't even an integer multiple of that.

It's not even a legacy vs. atomic thing, this can happen in
pure-atomic as well. Same as the render-compression plane property
that I just replied to here as well.

- Weston starts and sets up palette/CTM properties
- VT switch to Mutter, which isn't aware of new properties
- Mutter atomically sets new plane state, containing framebuffer which
is already colour-corrected for the target
- result is now double-corrected as Mutter didn't know to unset the
old properties

IOW, in the current model, any user of CM has to explicitly unset it
before handover (not always actually possible), or any generic
userspace must unset every property it sees and doesn't know about,
hoping that setting to 0 will do the right thing.

Or we could add another client cap, which would prevent the CM
properties from ever being exposed to userspace which doesn't know how
to work with it. Passing the client caps through to
plane_duplicate_state also means that we can unset the CM properties
at this early point for unaware clients. This would mean that we
wouldn't have to have code to explicitly unset it in, e.g., every
legacy hook.

>> About the only thing I can think of is to add a
>> DRM_CLIENT_CAP_COLOR_MGMT, and modify drm_atomic_*_duplicate_state to
>> take client caps (passed in from file_priv with the atomic ioctl, or
>> explicitly set by other kernel code, according to its capabilities),
>> and if the CM cap is not set, clear out the blobs when duplicating
>> state.

(As here.)

>> All of this also needs to be backed up by a lot more extensive IGT,
>> including disabling (from _every_ mode, not just 12-bit mode on BDW)
>> via setting blob == NULL, testing the various depths (I still don't
>> understand the difference between 8 and 10-bit on CHV), legacy gamma
>> hooks when using CM, testing reset/dumb clients when the above
>> duplicate_state issue is resolved, and especially the boundary cases
>> in conversions (e.g. the sign wraparound on CHV). The documentation
>> also _really_ needs fixing to be consistent with the code, and
>> consistent with itself. When that's done, I think I'll be
>> better-placed to do a second pass review, because after however many
>> revisions, I still can't clearly see how it would be used from generic
>> userspace (as opposed to an Intel-specific colour manager).
>
> One bit I'm not sure (and which isn't documented here) is that there's
> supposed to be a read-only hint property telling new generic userspace
> what tables are expected. This might mean you're not always using the most
> awesome configuration, but it should at least work. That part of the
> design seems to be undocumented.

Yeah, there is a single 'length' property per table, but given the
dizzying array of options available, I'm not really sure if that's
sufficient.

Cheers,
Daniel
Daniel Vetter Jan. 5, 2016, 10:23 a.m. UTC | #6
On Wed, Dec 23, 2015 at 09:47:00AM +0000, Daniel Stone wrote:
> Hi,
> 
> On 21 December 2015 at 12:38, Daniel Vetter <daniel@ffwll.ch> wrote:
> > On Fri, Dec 18, 2015 at 04:53:28PM +0000, Daniel Stone wrote:
> >> > +struct drm_r32g32b32 {
> >> > +       /*
> >> > +        * Data is in U8.24 fixed point format.
> >> > +        * All platforms support values within [0, 1.0] range,
> >> > +        * for Red, Green and Blue colors.
> >> > +        */
> >> > +       __u32 r32;
> >> > +       __u32 g32;
> >> > +       __u32 b32;
> >> > +       __u32 reserved;
> >> > +};
> >>
> >> Wait, it's U8.24 (i.e. 0 -> 255.09999999403953517), but the supported
> >> range is [0..1.0]? What am I missing?
> >
> > Probably means:
> > - all platforms MUST support [0.0, 1.0] range, inclusive
> > - platforms CAN support larger values (which can make sense in degamma
> >   tables if your CTM will shrink things down again).
> 
> Ah, makes sense.
> 
> >> I also don't have a good answer on how to support non-CM-aware
> >> clients. Currently they'll just blindly carry around the correction
> >> factors from previous clients, which is _really_ bad: imagine you have
> >> Weston ported to use KMS/CM to correct perfectly, and then start
> >> Mutter/GNOME which still corrects perfectly, but using lcms and
> >> various client-side compensation rather than the CM engine. Your
> >> output will now be double-corrected, i.e. wrong, because Mutter won't
> >> know to reset the CM properties.
> >
> > Hm yeah, I think legacy entry points should remap to atomic ones.
> > Otherwise things are massively inconsistent (and we have a problem
> > figuring out when/which table applies in the driver). One problem with
> > that approach is that the legacy table has the assumption of a fixed
> > 256 entries (well we expose the size somewhere, but that's what everyone
> > uses). At least on some platforms, the full-blown table used by these
> > patches isn't even an integer multiple of that.
> 
> It's not even a legacy vs. atomic thing, this can happen in
> pure-atomic as well. Same as the render-compression plane property
> that I just replied to here as well.
> 
> - Weston starts and sets up palette/CTM properties
> - VT switch to Mutter, which isn't aware of new properties
> - Mutter atomically sets new plane state, containing framebuffer which
> is already colour-corrected for the target
> - result is now double-corrected as Mutter didn't know to unset the
> old properties
> 
> IOW, in the current model, any user of CM has to explicitly unset it
> before handover (not always actually possible), or any generic
> userspace must unset every property it sees and doesn't know about,
> hoping that setting to 0 will do the right thing.
> 
> Or we could add another client cap, which would prevent the CM
> properties from ever being exposed to userspace which doesn't know how
> to work with it. Passing the client caps through to
> plane_duplicate_state also means that we can unset the CM properties
> at this early point for unaware clients. This would mean that we
> wouldn't have to have code to explicitly unset it in, e.g., every
> legacy hook.

We don't have any support for unsetting anything really. Same argument you
make for CM here applies to rotation too. The only generic solution (if
you really care about this) would be for logind to once sample all atomic
state on boot-up, and force-restore that state when switching. Restoring
atomic state doesn't require userspace to understanding the semantics
really.

This kind of force-restoring is probably something we should implement in
the fbdev emulation, which would cover about 99% of all cases where
developers/users want to run different compositors. Or fbdev should simply
reset CM state, like it does for rotation already (that part is easy to
add, but indeed seems to be missing).

Trying to create an ad-hoc solution (using opt-in flags) to this problem
for every single feature seems pointless imo.

> >> About the only thing I can think of is to add a
> >> DRM_CLIENT_CAP_COLOR_MGMT, and modify drm_atomic_*_duplicate_state to
> >> take client caps (passed in from file_priv with the atomic ioctl, or
> >> explicitly set by other kernel code, according to its capabilities),
> >> and if the CM cap is not set, clear out the blobs when duplicating
> >> state.
> 
> (As here.)
> 
> >> All of this also needs to be backed up by a lot more extensive IGT,
> >> including disabling (from _every_ mode, not just 12-bit mode on BDW)
> >> via setting blob == NULL, testing the various depths (I still don't
> >> understand the difference between 8 and 10-bit on CHV), legacy gamma
> >> hooks when using CM, testing reset/dumb clients when the above
> >> duplicate_state issue is resolved, and especially the boundary cases
> >> in conversions (e.g. the sign wraparound on CHV). The documentation
> >> also _really_ needs fixing to be consistent with the code, and
> >> consistent with itself. When that's done, I think I'll be
> >> better-placed to do a second pass review, because after however many
> >> revisions, I still can't clearly see how it would be used from generic
> >> userspace (as opposed to an Intel-specific colour manager).
> >
> > One bit I'm not sure (and which isn't documented here) is that there's
> > supposed to be a read-only hint property telling new generic userspace
> > what tables are expected. This might mean you're not always using the most
> > awesome configuration, but it should at least work. That part of the
> > design seems to be undocumented.
> 
> Yeah, there is a single 'length' property per table, but given the
> dizzying array of options available, I'm not really sure if that's
> sufficient.

The idea is to just give a hint to generic userspace. Fancy userspace that
wants to exploit all the other options needs to have some baked-in
knowledge of the hardware it runs on. This is kinda similar to how you can
do dumb buffers, but for fancy ones userspace (at least currently) needs
to just know how to allocate stuff. Imo there's just plain limits to how
generic KMS can be. And it's not worth pushing beyond those.
-Daniel
Daniel Stone Jan. 11, 2016, 8:37 p.m. UTC | #7
Hi,

On 5 January 2016 at 10:23, Daniel Vetter <daniel@ffwll.ch> wrote:
> On Wed, Dec 23, 2015 at 09:47:00AM +0000, Daniel Stone wrote:
>> It's not even a legacy vs. atomic thing, this can happen in
>> pure-atomic as well. Same as the render-compression plane property
>> that I just replied to here as well.
>>
>> - Weston starts and sets up palette/CTM properties
>> - VT switch to Mutter, which isn't aware of new properties
>> - Mutter atomically sets new plane state, containing framebuffer which
>> is already colour-corrected for the target
>> - result is now double-corrected as Mutter didn't know to unset the
>> old properties
>>
>> IOW, in the current model, any user of CM has to explicitly unset it
>> before handover (not always actually possible), or any generic
>> userspace must unset every property it sees and doesn't know about,
>> hoping that setting to 0 will do the right thing.
>>
>> Or we could add another client cap, which would prevent the CM
>> properties from ever being exposed to userspace which doesn't know how
>> to work with it. Passing the client caps through to
>> plane_duplicate_state also means that we can unset the CM properties
>> at this early point for unaware clients. This would mean that we
>> wouldn't have to have code to explicitly unset it in, e.g., every
>> legacy hook.
>
> We don't have any support for unsetting anything really. Same argument you
> make for CM here applies to rotation too. The only generic solution (if
> you really care about this) would be for logind to once sample all atomic
> state on boot-up, and force-restore that state when switching. Restoring
> atomic state doesn't require userspace to understanding the semantics
> really.

Sure, but on the other hand, rotation has been around ~forever, and is
implemented in multiple places. Colour management is a lot less
obvious.

> This kind of force-restoring is probably something we should implement in
> the fbdev emulation, which would cover about 99% of all cases where
> developers/users want to run different compositors. Or fbdev should simply
> reset CM state, like it does for rotation already (that part is easy to
> add, but indeed seems to be missing).
>
> Trying to create an ad-hoc solution (using opt-in flags) to this problem
> for every single feature seems pointless imo.

Fair enough, I guess it could be more difficult, so how about a new
flag to the atomic ioctl which requests state be _reset_ to scratch
rather than duplicated? That way, clients could be really sure they
weren't going to get screwed by rotation / colour management / render
compression / whatever.

>> Yeah, there is a single 'length' property per table, but given the
>> dizzying array of options available, I'm not really sure if that's
>> sufficient.
>
> The idea is to just give a hint to generic userspace. Fancy userspace that
> wants to exploit all the other options needs to have some baked-in
> knowledge of the hardware it runs on. This is kinda similar to how you can
> do dumb buffers, but for fancy ones userspace (at least currently) needs
> to just know how to allocate stuff. Imo there's just plain limits to how
> generic KMS can be. And it's not worth pushing beyond those.

I get the point, but am really struggling to make sense of the options
presented, and how a halfway-sensible generic userspace would work.
Exposing length/depth tuples might not be the worst idea; it also
sounds like there's more to dig out in terms of index interpolation as
well. But these are much smaller objections than having unwitting
clients inherit the CM state ...

Cheers,
Daniel
Ville Syrjälä Jan. 12, 2016, 10:02 a.m. UTC | #8
On Mon, Jan 11, 2016 at 08:37:09PM +0000, Daniel Stone wrote:
> Hi,
> 
> On 5 January 2016 at 10:23, Daniel Vetter <daniel@ffwll.ch> wrote:
> > On Wed, Dec 23, 2015 at 09:47:00AM +0000, Daniel Stone wrote:
> >> It's not even a legacy vs. atomic thing, this can happen in
> >> pure-atomic as well. Same as the render-compression plane property
> >> that I just replied to here as well.
> >>
> >> - Weston starts and sets up palette/CTM properties
> >> - VT switch to Mutter, which isn't aware of new properties
> >> - Mutter atomically sets new plane state, containing framebuffer which
> >> is already colour-corrected for the target
> >> - result is now double-corrected as Mutter didn't know to unset the
> >> old properties
> >>
> >> IOW, in the current model, any user of CM has to explicitly unset it
> >> before handover (not always actually possible), or any generic
> >> userspace must unset every property it sees and doesn't know about,
> >> hoping that setting to 0 will do the right thing.
> >>
> >> Or we could add another client cap, which would prevent the CM
> >> properties from ever being exposed to userspace which doesn't know how
> >> to work with it. Passing the client caps through to
> >> plane_duplicate_state also means that we can unset the CM properties
> >> at this early point for unaware clients. This would mean that we
> >> wouldn't have to have code to explicitly unset it in, e.g., every
> >> legacy hook.
> >
> > We don't have any support for unsetting anything really. Same argument you
> > make for CM here applies to rotation too. The only generic solution (if
> > you really care about this) would be for logind to once sample all atomic
> > state on boot-up, and force-restore that state when switching. Restoring
> > atomic state doesn't require userspace to understanding the semantics
> > really.
> 
> Sure, but on the other hand, rotation has been around ~forever, and is
> implemented in multiple places. Colour management is a lot less
> obvious.
> 
> > This kind of force-restoring is probably something we should implement in
> > the fbdev emulation, which would cover about 99% of all cases where
> > developers/users want to run different compositors. Or fbdev should simply
> > reset CM state, like it does for rotation already (that part is easy to
> > add, but indeed seems to be missing).
> >
> > Trying to create an ad-hoc solution (using opt-in flags) to this problem
> > for every single feature seems pointless imo.
> 
> Fair enough, I guess it could be more difficult, so how about a new
> flag to the atomic ioctl which requests state be _reset_ to scratch
> rather than duplicated? That way, clients could be really sure they
> weren't going to get screwed by rotation / colour management / render
> compression / whatever.

One question is what exactly is scratch? Eg. I have BYT tablet here
which has the display mounted upside down so in theory the reset state
should be 180 degree rotated. I have a patch hiding in some branch
to make the fbdev helper take over the rotation from the BIOS. I suppose
I should also dig into the VBT to see if there's some rotation indicators
there for the cases when you boot with HDMI plugged in. But I digress.
diff mbox

Patch

diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index 6a21e5c..ebdb98d 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -388,6 +388,38 @@  int drm_atomic_set_mode_prop_for_crtc(struct drm_crtc_state *state,
 EXPORT_SYMBOL(drm_atomic_set_mode_prop_for_crtc);
 
 /**
+ * drm_atomic_crtc_set_blob - find and set a blob
+ * @state_blob: reference pointer to the color blob in the crtc_state
+ * @blob_id: blob_id coming from set_property() call
+ *
+ * Set a color correction blob (originating from a set blob property) on the
+ * desired CRTC state. This function will take reference of the blob property
+ * in the CRTC state, finds the blob based on blob_id (which comes from
+ * set_property call) and set the blob at the proper place.
+ *
+ * RETURNS:
+ * Zero on success, error code on failure.
+ */
+static int drm_atomic_crtc_set_blob(struct drm_device *dev,
+	struct drm_property_blob **state_blob, uint32_t blob_id)
+{
+	struct drm_property_blob *blob;
+
+	blob = drm_property_lookup_blob(dev, blob_id);
+	if (!blob) {
+		DRM_DEBUG_KMS("Invalid Blob ID\n");
+		return -EINVAL;
+	}
+
+	if (*state_blob)
+		drm_property_unreference_blob(*state_blob);
+
+	/* Attach the blob to be committed in state */
+	*state_blob = blob;
+	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
@@ -419,8 +451,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->cm_palette_after_ctm_property) {
+		ret = drm_atomic_crtc_set_blob(dev,
+				&state->palette_after_ctm_blob, val);
+		if (ret)
+			DRM_DEBUG_KMS("Failed to load blob palette_after_ctm\n");
+		else
+			state->color_correction_changed = true;
+		return ret;
+	} else if (property == config->cm_palette_before_ctm_property) {
+		ret = drm_atomic_crtc_set_blob(dev,
+				&state->palette_before_ctm_blob, val);
+		if (ret)
+			DRM_DEBUG_KMS("Failed to load blob palette_before_ctm\n");
+		else
+			state->color_correction_changed = true;
+		return ret;
+	} else if (property == config->cm_ctm_property) {
+		ret = drm_atomic_crtc_set_blob(dev,
+				&state->ctm_blob, val);
+		if (ret)
+			DRM_DEBUG_KMS("Failed to load blob ctm\n");
+		else
+			state->color_correction_changed = true;
+		return ret;
+	} else if (crtc->funcs->atomic_set_property)
 		return crtc->funcs->atomic_set_property(crtc, state, property, val);
 	else
 		return -EINVAL;
@@ -456,6 +511,14 @@  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->cm_palette_after_ctm_property)
+		*val = (state->palette_after_ctm_blob) ?
+			state->palette_after_ctm_blob->base.id : 0;
+	else if (property == config->cm_palette_before_ctm_property)
+		*val = (state->palette_before_ctm_blob) ?
+			state->palette_before_ctm_blob->base.id : 0;
+	else if (property == config->cm_ctm_property)
+		*val = (state->ctm_blob) ? state->ctm_blob->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 268d37f..bd325da 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -2448,6 +2448,12 @@  void __drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc,
 
 	if (state->mode_blob)
 		drm_property_reference_blob(state->mode_blob);
+	if (state->ctm_blob)
+		drm_property_reference_blob(state->ctm_blob);
+	if (state->palette_after_ctm_blob)
+		drm_property_reference_blob(state->palette_after_ctm_blob);
+	if (state->palette_before_ctm_blob)
+		drm_property_reference_blob(state->palette_before_ctm_blob);
 	state->mode_changed = false;
 	state->active_changed = false;
 	state->planes_changed = false;
@@ -2492,6 +2498,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->ctm_blob);
+	drm_property_unreference_blob(state->palette_after_ctm_blob);
+	drm_property_unreference_blob(state->palette_before_ctm_blob);
 }
 EXPORT_SYMBOL(__drm_atomic_helper_crtc_destroy_state);
 
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 62fa95f..2e02d0f 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -1542,6 +1542,38 @@  static int drm_mode_create_standard_properties(struct drm_device *dev)
 		return -ENOMEM;
 	dev->mode_config.prop_mode_id = prop;
 
+	/* Color Management properties */
+	prop = drm_property_create(dev,
+			DRM_MODE_PROP_BLOB, "PALETTE_AFTER_CTM", 0);
+	if (!prop)
+		return -ENOMEM;
+	dev->mode_config.cm_palette_after_ctm_property = prop;
+
+	prop = drm_property_create(dev,
+			DRM_MODE_PROP_BLOB, "PALETTE_BEFORE_CTM", 0);
+	if (!prop)
+		return -ENOMEM;
+	dev->mode_config.cm_palette_before_ctm_property = prop;
+
+	prop = drm_property_create(dev,
+			DRM_MODE_PROP_BLOB, "CTM", 0);
+	if (!prop)
+		return -ENOMEM;
+	dev->mode_config.cm_ctm_property = prop;
+
+	/* DRM properties to query color capabilities */
+	prop = drm_property_create(dev, DRM_MODE_PROP_IMMUTABLE,
+			"COEFFICIENTS_BEFORE_CTM", 0);
+	if (!prop)
+		return -ENOMEM;
+	dev->mode_config.cm_coeff_before_ctm_property = prop;
+
+	prop = drm_property_create(dev, DRM_MODE_PROP_IMMUTABLE,
+			"COEFFICIENTS_AFTER_CTM", 0);
+	if (!prop)
+		return -ENOMEM;
+	dev->mode_config.cm_coeff_after_ctm_property = prop;
+
 	return 0;
 }
 
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 3b040b3..8326765 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -305,11 +305,15 @@  struct drm_plane_helper_funcs;
  * @mode_changed: crtc_state->mode or crtc_state->enable has been changed
  * @active_changed: crtc_state->active has been toggled.
  * @connectors_changed: connectors to this crtc have been updated
+ * @color_correction_changed: color correction blob in this crtc got updated
  * @plane_mask: bitmask of (1 << drm_plane_index(plane)) of attached planes
  * @last_vblank_count: for helpers and drivers to capture the vblank of the
  * 	update to ensure framebuffer cleanup isn't done too early
  * @adjusted_mode: for use by helpers and drivers to compute adjusted mode timings
  * @mode: current mode timings
+ * @palette_before_ctm_blob: blob for color corrections to be applied after CTM
+ * @palette_after_ctm_blob: blob for color corrections to be applied before CTM
+ * @ctm_blob: blob for CTM color correction
  * @event: optional pointer to a DRM event to signal upon completion of the
  * 	state update
  * @state: backpointer to global drm_atomic_state
@@ -331,6 +335,7 @@  struct drm_crtc_state {
 	bool mode_changed : 1;
 	bool active_changed : 1;
 	bool connectors_changed : 1;
+	bool color_correction_changed : 1;
 
 	/* attached planes bitmask:
 	 * WARNING: transitional helpers do not maintain plane_mask so
@@ -350,6 +355,11 @@  struct drm_crtc_state {
 	/* blob property to expose current mode to atomic userspace */
 	struct drm_property_blob *mode_blob;
 
+	/* Color management blobs */
+	struct drm_property_blob *palette_before_ctm_blob;
+	struct drm_property_blob *palette_after_ctm_blob;
+	struct drm_property_blob *ctm_blob;
+
 	struct drm_pending_vblank_event *event;
 
 	struct drm_atomic_state *state;
@@ -2019,6 +2029,11 @@  struct drm_mode_config_funcs {
  * @property_blob_list: list of all the blob property objects
  * @blob_lock: mutex for blob property allocation and management
  * @*_property: core property tracking
+ * @cm_palette_before_ctm_property: color corrections before CTM block
+ * @cm_palette_after_ctm_property: color corrections after CTM block
+ * @cm_ctm_property: color transformation matrix correction
+ * @cm_coeff_before_ctm_property: query no of correction coeffi before CTM
+ * @cm_coeff_after_ctm_property: query no of correction coeffi after CTM
  * @preferred_depth: preferred RBG pixel depth, used by fb helpers
  * @prefer_shadow: hint to userspace to prefer shadow-fb rendering
  * @async_page_flip: does this device support async flips on the primary plane?
@@ -2124,6 +2139,15 @@  struct drm_mode_config {
 	struct drm_property *suggested_x_property;
 	struct drm_property *suggested_y_property;
 
+	/* Color correction properties */
+	struct drm_property *cm_palette_before_ctm_property;
+	struct drm_property *cm_palette_after_ctm_property;
+	struct drm_property *cm_ctm_property;
+
+	/* Color correction query */
+	struct drm_property *cm_coeff_before_ctm_property;
+	struct drm_property *cm_coeff_after_ctm_property;
+
 	/* dumb ioctl parameters */
 	uint32_t preferred_depth, prefer_shadow;
 
diff --git a/include/uapi/drm/drm.h b/include/uapi/drm/drm.h
index b4e92eb..24e4520 100644
--- a/include/uapi/drm/drm.h
+++ b/include/uapi/drm/drm.h
@@ -830,6 +830,36 @@  struct drm_event_vblank {
 	__u32 reserved;
 };
 
+struct drm_r32g32b32 {
+	/*
+	 * Data is in U8.24 fixed point format.
+	 * All platforms support values within [0, 1.0] range,
+	 * for Red, Green and Blue colors.
+	 */
+	__u32 r32;
+	__u32 g32;
+	__u32 b32;
+	__u32 reserved;
+};
+
+struct drm_palette {
+	/*
+	 * Starting of palette LUT in R32G32B32 format.
+	 * Each of RGB value is in U8.24 fixed point format.
+	 */
+	struct drm_r32g32b32 lut[0];
+};
+
+struct drm_ctm {
+	/*
+	 * Each value is in S31.32 format.
+	 * This is 3x3 matrix in row major format.
+	 * Integer part will be clipped to nearest
+	 * max/min boundary as supported by the HW platform.
+	 */
+	__s64 ctm_coeff[9];
+};
+
 /* typedef area */
 #ifndef __KERNEL__
 typedef struct drm_clip_rect drm_clip_rect_t;