Re: [V7 08/45] Documentation/gpu: document drm_colorop

2025-02-21 Thread Harry Wentland



On 2025-02-21 11:42, Simon Ser wrote:
> On Friday, February 21st, 2025 at 17:18, Harry Wentland 
>  wrote:
> 
>> I did a brief survey of other enum properties and noticed
>> that this isn't well documented for others, such as the Content
>> Protection connector property, or the COLOR_RANGE and COLOR_ENCODING
>> plane properties.
> 
> Isn't the Content Protection property documented here?
> https://dri.freedesktop.org/docs/drm/gpu/drm-kms.html#standard-connector-properties
> 

Yes, but I don't see the actual strings. The doc mentions UNDESIRED,
DESIRED, and ENABLED but the strings are "Undesired", "Desired", and
"Enabled".

> COLOR_RANGE and COLOR_ENCODING are documented here, but indeed they
> are missing docs for enum entries:
> https://dri.freedesktop.org/docs/drm/gpu/drm-kms.html#color-management-properties
> 
> Would be nice to fix.
> 
>> On the IGT front, some tests set enum properties via enum strings,
>> and other set and get enum properties based on the prop uint64_t
>> prop_values[i] entry from the drmModeObjectPropertiesPtr.
>>
>> Do you know if there's a best practice for enum usage or is it mostly
>> a case of "use what works for you"?
> 
> It's an old debate. Some user-space uses enum integer values, some
> user-space uses enum name strings.
> 
> In theory, each KMS object could have a different name-value map for
> a given property. However, this is very theoretical and last time we've
> discussed this we haven't found any case where this would be desirable.
> 
> IMHO, strings make it painful for user-space because it needs to go
> through another level of indirection (to convert names to values right
> before setting a property) for no benefit. Strings are more annoying to
> handle in general (memory management, typos, etc).
> 
> Kernel has a no user-space regression policy anyways, so when user-space
> starts using values, the kernel won't be able to break these users.
> 

Makes sense and thanks for some background on previous discussions on this.

> Other people have argued that strings make it easier for user-space to
> start using a new KMS property without deploying new kernel uAPI headers.
> 

I don't understand this argument. You would either need to define the
strings or the ints in your user-space app. You could do either without
deploying new uAPI headers.

> In the end, it's up to user-space to use their preferred way to set
> properties.

Makes sense.

Harry


Re: [V7 08/45] Documentation/gpu: document drm_colorop

2025-02-21 Thread Harry Wentland



On 2025-02-15 09:40, Simon Ser wrote:
> On Monday, February 10th, 2025 at 23:03, Harry Wentland 
>  wrote:
> 
 + * DOC: overview
 + *
 + * A colorop represents a single color operation. Colorops are chained
 + * via the NEXT property and make up color pipelines. Color pipelines
 + * are advertised and selected via the COLOR_PIPELINE &drm_plane
 + * property.
 + *
 + * A colorop will be of a certain type, advertised by the read-only TYPE
 + * property. Each type of colorop will advertise a different set of
 + * properties and is programmed in a different manner. Types can be
 + * enumerated 1D curves, 1D LUTs, 3D LUTs, matrices, etc. See the
 + * &drm_colorop_type documentation for information on each type.
>>>
>>> It's not super nice to refer to internal kernel docs here, because AFAIU
>>> this section is mostly written towards user-space developers. User-space
>>> developers have no idea how internal kernel structs work.
>>>
>>> It would be nicer to have a list of colorop types here, without referring
>>> to kernel internals. For instance, we have a list of
>>
>> I'm not sure I follow. This is linking to the drm_colorop_type
>> (from drm_mode.h) enum documentation in drm-uapi.html.
>>
>> Duplicating it here would mean that sooner or later the two
>> docs will get out of sync.
> 
> Oh, I thought this was an internal kernel enum. I guess the only missing
> thing is the string exposed to user-space for each enum entry then?
> 

Good point. We'll add that to the enum drm_colorop_type docs.

I did a brief survey of other enum properties and noticed
that this isn't well documented for others, such as the Content
Protection connector property, or the COLOR_RANGE and COLOR_ENCODING
plane properties.

On the IGT front, some tests set enum properties via enum strings,
and other set and get enum properties based on the prop uint64_t
prop_values[i] entry from the drmModeObjectPropertiesPtr.

Do you know if there's a best practice for enum usage or is it mostly
a case of "use what works for you"?

Harry

> In any case, sounds good to me.
> 
>> I agree with the rest and we'll reflect that in v8.
> 
> Sweet!



Re: [V7 08/45] Documentation/gpu: document drm_colorop

2025-02-21 Thread Simon Ser
On Friday, February 21st, 2025 at 19:41, Harry Wentland 
 wrote:

> > Other people have argued that strings make it easier for user-space to
> > start using a new KMS property without deploying new kernel uAPI headers.
> 
> I don't understand this argument. You would either need to define the
> strings or the ints in your user-space app. You could do either without
> deploying new uAPI headers.

I suppose a string is less likely to be wrong/mixed up than a magic
number? I'm probably not the best person to explain this side of the
debate. :P

Looking at Weston, it seems to just re-define its own enums matching
the kernel strings:
https://gitlab.freedesktop.org/wayland/weston/-/blob/6d9c42a7d294a1435822541ab4b3e12a8998dabb/libweston/backend-drm/kms.c#L49

For reference, one of the previous discussions:
https://lists.freedesktop.org/archives/dri-devel/2020-April/thread.html#261055

I think there was another one, but can't find it back…


Re: [V7 34/45] drm/amd/display: add shaper and blend colorops for 1D Curve Custom LUT

2025-02-21 Thread Harry Wentland



On 2025-02-12 18:44, Leo Li wrote:
> 
> 
> On 2024-12-19 23:33, Alex Hung wrote:
>> This patch adds colorops for custom 1D LUTs in the SHAPER and
>> BLND HW blocks.
>>
>> With this change the following IGT tests pass:
>> kms_colorop --run plane-XR30-XR30-srgb_inv_eotf_lut
>> kms_colorop --run plane-XR30-XR30-srgb_inv_eotf_lut-srgb_eotf_lut
>>
>> The color pipeline now consists of the following colorops:
>> 1. 1D curve colorop
>> 2. 1D curve colorop
>> 3. 1D LUT
>> 4. 1D curve colorop
>> 5. 1D LUT
>>
>> The 1D curve colorops support sRGB, BT2020, and PQ scaled to 125.0.
>>
>> Signed-off-by: Alex Hung 
>> Signed-off-by: Harry Wentland 
>> ---
>> v7:
>>   - Initialize uint32_t blend_size = 0 by default (kernel test robot)
>>   - Modify state->size to colorop->lut_size
>>
>>   .../amd/display/amdgpu_dm/amdgpu_dm_color.c   | 166 ++
>>   .../amd/display/amdgpu_dm/amdgpu_dm_colorop.c |  32 
>>   2 files changed, 120 insertions(+), 78 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c 
>> b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
>> index 1765402bc122..0bea52eede39 100644
>> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
>> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
>> @@ -1211,38 +1211,6 @@ __set_dm_plane_colorop_degamma(struct drm_plane_state 
>> *plane_state,
>>   return __set_colorop_in_tf_1d_curve(dc_plane_state, colorop_state);
>>   }
>>   -static int
>> -__set_colorop_in_shaper_1d_curve(struct dc_plane_state *dc_plane_state,
>> -   struct drm_colorop_state *colorop_state)
>> -{
>> -    struct dc_transfer_func *tf = &dc_plane_state->in_shaper_func;
>> -    struct drm_colorop *colorop = colorop_state->colorop;
>> -    struct drm_device *drm = colorop->dev;
>> -
>> -    if (colorop->type != DRM_COLOROP_1D_CURVE)
>> -    return -EINVAL;
>> -
>> -    if (!(BIT(colorop_state->curve_1d_type) & 
>> amdgpu_dm_supported_shaper_tfs))
>> -    return -EINVAL;
>> -
>> -    if (colorop_state->bypass) {
>> -    tf->type = TF_TYPE_BYPASS;
>> -    tf->tf = TRANSFER_FUNCTION_LINEAR;
>> -    return 0;
>> -    }
>> -
>> -    drm_dbg(drm, "Shaper colorop with ID: %d\n", colorop->base.id);
>> -
>> -    if (colorop->type == DRM_COLOROP_1D_CURVE) {
>> -    tf->type = TF_TYPE_DISTRIBUTED_POINTS;
>> -    tf->tf = amdgpu_colorop_tf_to_dc_tf(colorop_state->curve_1d_type);
>> -    tf->sdr_ref_white_level = SDR_WHITE_LEVEL_INIT_VALUE;
>> -    return __set_output_tf(tf, 0, 0, false);
>> -    }
>> -
>> -    return -EINVAL;
>> -}
>> -
>>   static int
>>   __set_dm_plane_colorop_shaper(struct drm_plane_state *plane_state,
>>     struct dc_plane_state *dc_plane_state,
>> @@ -1251,64 +1219,61 @@ __set_dm_plane_colorop_shaper(struct drm_plane_state 
>> *plane_state,
>>   struct drm_colorop *old_colorop;
>>   struct drm_colorop_state *colorop_state = NULL, *new_colorop_state;
>>   struct drm_atomic_state *state = plane_state->state;
>> +    enum dc_transfer_func_predefined default_tf = TRANSFER_FUNCTION_LINEAR;
>> +    struct dc_transfer_func *tf = &dc_plane_state->in_shaper_func;
>> +    const struct drm_color_lut *shaper_lut;
>> +    struct drm_device *dev = colorop->dev;
>> +    uint32_t shaper_size;
>>   int i = 0;
>>   +    /* 1D Curve - SHAPER TF */
>>   old_colorop = colorop;
>> -
>> -    /* 2nd op: 1d curve - shaper */
>>   for_each_new_colorop_in_state(state, colorop, new_colorop_state, i) {
>>   if (new_colorop_state->colorop == old_colorop &&
>>   (BIT(new_colorop_state->curve_1d_type) & 
>> amdgpu_dm_supported_shaper_tfs)) {
>>   colorop_state = new_colorop_state;
>>   break;
>>   }
>> -
>> -    if (new_colorop_state->colorop == old_colorop) {
>> -    colorop_state = new_colorop_state;
>> -    break;
>> -    }
>>   }
>>   -    if (!colorop_state)
>> -    return -EINVAL;
>> -
>> -    return __set_colorop_in_shaper_1d_curve(dc_plane_state, colorop_state);
>> -}
>> -
>> -
>> -static int
>> -__set_colorop_1d_curve_blend_tf_lut(struct dc_plane_state *dc_plane_state,
>> -  struct drm_colorop_state *colorop_state)
>> -{
>> -
>> -    struct dc_transfer_func *tf = &dc_plane_state->blend_tf;
>> -    struct drm_colorop *colorop = colorop_state->colorop;
>> -    struct drm_device *drm = colorop->dev;
>> -    const struct drm_color_lut *blend_lut;
>> -    uint32_t blend_size = 0;
>> -
>> -    if (colorop->type != DRM_COLOROP_1D_CURVE)
>> -    return -EINVAL;
>> +    if (colorop_state && !colorop_state->bypass && colorop->type == 
>> DRM_COLOROP_1D_CURVE) {
>> +    drm_dbg(dev, "Shaper TF colorop with ID: %d\n", colorop->base.id);
>> +    tf->type = TF_TYPE_DISTRIBUTED_POINTS;
>> +    tf->tf = default_tf = 
>> amdgpu_colorop_tf_to_dc_tf(colorop_state->curve_1d_type);
>> +    tf->sdr_ref_white_level = SDR_WHITE_LEVEL_INIT_VALUE;
>> 

Re: [V7 08/45] Documentation/gpu: document drm_colorop

2025-02-21 Thread Simon Ser
On Friday, February 21st, 2025 at 17:18, Harry Wentland 
 wrote:

> I did a brief survey of other enum properties and noticed
> that this isn't well documented for others, such as the Content
> Protection connector property, or the COLOR_RANGE and COLOR_ENCODING
> plane properties.

Isn't the Content Protection property documented here?
https://dri.freedesktop.org/docs/drm/gpu/drm-kms.html#standard-connector-properties

COLOR_RANGE and COLOR_ENCODING are documented here, but indeed they
are missing docs for enum entries:
https://dri.freedesktop.org/docs/drm/gpu/drm-kms.html#color-management-properties

Would be nice to fix.

> On the IGT front, some tests set enum properties via enum strings,
> and other set and get enum properties based on the prop uint64_t
> prop_values[i] entry from the drmModeObjectPropertiesPtr.
> 
> Do you know if there's a best practice for enum usage or is it mostly
> a case of "use what works for you"?

It's an old debate. Some user-space uses enum integer values, some
user-space uses enum name strings.

In theory, each KMS object could have a different name-value map for
a given property. However, this is very theoretical and last time we've
discussed this we haven't found any case where this would be desirable.

IMHO, strings make it painful for user-space because it needs to go
through another level of indirection (to convert names to values right
before setting a property) for no benefit. Strings are more annoying to
handle in general (memory management, typos, etc).

Kernel has a no user-space regression policy anyways, so when user-space
starts using values, the kernel won't be able to break these users.

Other people have argued that strings make it easier for user-space to
start using a new KMS property without deploying new kernel uAPI headers.

In the end, it's up to user-space to use their preferred way to set
properties.


Re: [V7 42/45] drm/amd/display: add 3D LUT colorop

2025-02-21 Thread Harry Wentland



On 2025-02-13 13:21, Leo Li wrote:
> 
> 
> 
> On 2024-12-19 23:33, Alex Hung wrote:
>> This adds support for a 3D LUT.
>>
>> The color pipeline now consists of the following colorops:
>> 1. 1D curve colorop
>> 2. Multiplier
>> 3. 3x4 CTM
>> 4. 1D curve colorop
>> 5. 1D LUT
>> 6. 3D LUT
>> 7. 1D curve colorop
>> 8. 1D LUT
>>
>> Signed-off-by: Alex Hung 
>> ---
>> v7:
>>   - Simplify 3D LUT according to drm_colorop changes (Simon Ser)
>>
>>   .../amd/display/amdgpu_dm/amdgpu_dm_color.c   | 100 +-
>>   .../amd/display/amdgpu_dm/amdgpu_dm_colorop.c |  19 
>>   2 files changed, 116 insertions(+), 3 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c 
>> b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
>> index 54ec12c1352f..5e8c5c0657c4 100644
>> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
>> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
>> @@ -1282,7 +1282,8 @@ __set_dm_plane_colorop_multiplier(struct 
>> drm_plane_state *plane_state,
>>   static int
>>   __set_dm_plane_colorop_shaper(struct drm_plane_state *plane_state,
>>     struct dc_plane_state *dc_plane_state,
>> -  struct drm_colorop *colorop)
>> +  struct drm_colorop *colorop,
>> +  bool *enabled)
>>   {
>>   struct drm_colorop *old_colorop;
>>   struct drm_colorop_state *colorop_state = NULL, *new_colorop_state;
>> @@ -1310,6 +1311,7 @@ __set_dm_plane_colorop_shaper(struct drm_plane_state 
>> *plane_state,
>>   tf->tf = default_tf = 
>> amdgpu_colorop_tf_to_dc_tf(colorop_state->curve_1d_type);
>>   tf->sdr_ref_white_level = SDR_WHITE_LEVEL_INIT_VALUE;
>>   __set_output_tf(tf, 0, 0, false);
>> +    *enabled = true;
>>   }
>>     /* 1D LUT - SHAPER LUT */
>> @@ -1337,8 +1339,88 @@ __set_dm_plane_colorop_shaper(struct drm_plane_state 
>> *plane_state,
>>   shaper_size = shaper_lut != NULL ? shaper_size : 0;
>>     /* Custom LUT size must be the same as supported size */
>> -    if (shaper_size == colorop->lut_size)
>> +    if (shaper_size == colorop->lut_size) {
>>   __set_output_tf(tf, shaper_lut, shaper_size, false);
>> +    *enabled = true;
>> +    }
>> +    }
>> +
>> +    return 0;
>> +}
>> +
>> +/* __set_colorop_3dlut - set DRM 3D LUT to DC stream
>> + * @drm_lut3d: user 3D LUT
>> + * @drm_lut3d_size: size of 3D LUT
>> + * @lut3d: DC 3D LUT
>> + *
>> + * Map user 3D LUT data to DC 3D LUT and all necessary bits to program it
>> + * on DCN accordingly.
>> + */
>> +static void __set_colorop_3dlut(const struct drm_color_lut *drm_lut3d,
>> +    uint32_t drm_lut3d_size,
>> +    struct dc_3dlut *lut)
>> +{
>> +    if (!drm_lut3d_size)
>> +    return;
>> +
>> +    lut->state.bits.initialized = 0;
>> +

Shouldn't we clear this bit if !drm_lut3d_size? I.e.,

if (!drm_lut3d_size) {
lut->state.bits.initialized = 0;
return;
}

>> +    /* Only supports 17x17x17 3D LUT (12-bit) now */
>> +    lut->lut_3d.use_12bits = true;
>> +    lut->lut_3d.use_tetrahedral_9 = false;
>> +
>> +    lut->state.bits.initialized = 1;
>> +    __drm_3dlut_to_dc_3dlut(drm_lut3d, drm_lut3d_size, &lut->lut_3d,
>> +    lut->lut_3d.use_tetrahedral_9, 12);
>> +
>> +}
>> +
>> +static int
>> +__set_dm_plane_colorop_3dlut(struct drm_plane_state *plane_state,
>> + struct dc_plane_state *dc_plane_state,
>> + struct drm_colorop *colorop,
>> + bool shaper_enabled)
>> +{
>> +    struct drm_colorop *old_colorop;
>> +    struct drm_colorop_state *colorop_state = NULL, *new_colorop_state;
>> +    struct dc_transfer_func *tf = &dc_plane_state->in_shaper_func;
>> +    struct drm_atomic_state *state = plane_state->state;
>> +    const struct amdgpu_device *adev = drm_to_adev(colorop->dev);
>> +    const struct drm_device *dev = colorop->dev;
>> +    const struct drm_color_lut *lut3d;
>> +    uint32_t lut3d_size;
>> +    int i = 0;
>> +
>> +    /* 3D LUT */
>> +    old_colorop = colorop;
>> +    for_each_new_colorop_in_state(state, colorop, new_colorop_state, i) {
>> +    if (new_colorop_state->colorop == old_colorop &&
>> +    new_colorop_state->colorop->type == DRM_COLOROP_3D_LUT) {
>> +    colorop_state = new_colorop_state;
>> +    break;
>> +    }
>> +    }
>> +
>> +    if (colorop_state && !colorop_state->bypass && colorop->type == 
>> DRM_COLOROP_3D_LUT) {
>> +    if (!adev->dm.dc->caps.color.dpp.hw_3d_lut) {
>> +    drm_dbg(dev, "3D LUT is not supported by hardware\n");
>> +    return 0;
> 
> Should an error be returned instead?
> -Leo
> 
>> +    }
>> +
>> +    drm_dbg(dev, "3D LUT colorop with ID: %d\n", colorop->base.id);
>> +    lut3d = __extract_blob_lut(colorop_state->data, &lut3d_size);
>> +    lut3d_size = lut3d != NULL ? lut3d_size : 0;
>> +    __set_colorop_3dlut(l