Re: [RFC PATCH v4 00/42] Color Pipeline API w/ VKMS

2024-06-11 Thread Harry Wentland



On 2024-06-05 06:04, Melissa Wen wrote:
> On 02/26, Harry Wentland wrote:
>> This is an RFC set for a color pipeline API, along with a sample
>> implementation in VKMS. All the key API bits are here. VKMS now
>> supports two named transfer function colorops and two matrix
>> colorops. We have IGT tests that check all four of these colorops
>> with a pixel-by-pixel comparison that checks that these colorops
>> do what we expect them to do with a +/- 1 8 bpc code point margin.
>>
>> The big new change with v4 is the addition of an amdgpu color
>> pipeline, for all AMD GPUs with DCN 3 and newer. Amdgpu now support
>> the following:
>>
>> 1. 1D Curve EOTF
>> 2. 3x4 CTM
>> 3. Multiplier
>> 4. 1D Curve Inverse EOTF
>> 5. 1D LUT
>> 6. 1D Curve EOTF
>> 7. 1D LUT
>>
>> The supported curves for the 1D Curve type are:
>> - sRGB EOTF and its inverse
>> - PQ EOTF, scaled to [0.0, 125.0] and its inverse
>> - BT.2020/BT.709 OETF and its inverse
> 
> So, as we talked in the 2024 Linux Display Next Hackfest, I hacked
> `drm_info` to show the KMS color pipeline properties. You can find the
> experimental-and-ugly code here:
> - https://gitlab.freedesktop.org/mwen/drm_info/-/merge_requests/1
> It depends on updating libdrm [1] and you will only see something if you
> use a custom kernel with this series applied.
> 

Thanks. That's very useful.

> After checking the output, I missed a kind of Default or "Identity"
> curve for the `CURVE_1D_TYPE` enum. I understand that if the color
> operation is set bypass, we can ignore all property values, but I didn't
> find a similar approach on plane properties, so it looks weird to me:
> 
> └───"CURVE_1D_TYPE" (atomic): enum {sRGB Inverse EOTF, BT.2020 OETF, PQ 125 
> Inverse EOTF} = invalid (0)
> 

Good catch. That's where drm_info is useful. We shouldn't be reporting
"invalid (0)" but default to any other value. I'll fix that.

While your suggestion would work for AMD I'm a bit reluctant to add an
Identity element. It doesn't add value over "BYPASS". But more importantly
we discussed that there might be some HW that doesn't support HW on
colorops. It would be better if we avoid assumptions about the availability
of identity or bypass.

> Another thing that caught my attention was the size property for 1D
> Curve Custom LUT, that I expected a similar setup to CRTC 1D LUTs:
> 
> └───"GAMMA_LUT_SIZE" (immutable): range [0, UINT32_MAX] = 4096
> 
> But I got:
> 
> ├───"SIZE" (atomic): range [4096, 4096] = 4096
> 
> Any thoughts?

We should stick with same behavior as GAMMA_LUT_SIZE. I'll change
that.

> 
> Anyway, see below an example of `drm_info` output on AMD DCN301 for a
> given Overlay/Primary plane without userspace usage of the properties:
> 
> │   └───"COLOR_PIPELINE" (atomic): enum {Bypass, Color Pipeline 265} 
> = Bypass
> │   ├───Bypass
> │   └───Color Pipeline 265
> │   ├───Color Operation 265
> │   │   ├───"TYPE" (immutable): enum {1D Curve, 1D Curve 
> Custom LUT, 3x4 Matrix, Multiplier} = 1D Curve
> │   │   ├───"BYPASS" (atomic): range [0, 1] = 1
> │   │   └───"CURVE_1D_TYPE" (atomic): enum {sRGB EOTF, 
> BT.2020 Inverse OETF, PQ 125 EOTF} = sRGB EOTF
> │   ├───Color Operation 270
> │   │   ├───"TYPE" (immutable): enum {1D Curve, 1D Curve 
> Custom LUT, 3x4 Matrix, Multiplier} = 3x4 Matrix
> │   │   ├───"BYPASS" (atomic): range [0, 1] = 1
> │   │   └───"DATA" (atomic): blob = 0
> │   ├───Color Operation 275
> │   │   ├───"TYPE" (immutable): enum {1D Curve, 1D Curve 
> Custom LUT, 3x4 Matrix, Multiplier} = Multiplier
> │   │   ├───"BYPASS" (atomic): range [0, 1] = 1
> │   │   └───"MULTIPLIER" (atomic): range [0, UINT64_MAX] = 0
> │   ├───Color Operation 280
> │   │   ├───"TYPE" (immutable): enum {1D Curve, 1D Curve 
> Custom LUT, 3x4 Matrix, Multiplier} = 1D Curve
> │   │   ├───"BYPASS" (atomic): range [0, 1] = 1
> │   │   └───"CURVE_1D_TYPE" (atomic): enum {sRGB Inverse 
> EOTF, BT.2020 OETF, PQ 125 Inverse EOTF} = invalid (0)
> │   ├───Color Operation 285
> │   │   ├───"TYPE" (immutable): enum {1D Curve, 1D Curve 
> Custom LUT, 3x4 Matrix, Multiplier} = 1D Curve Custom LUT
> │   │   ├───"BYPASS" (atomic): range 

Re: [PATCH v2] drm/amd/display: Enable colorspace property for MST connectors

2024-05-23 Thread Harry Wentland

On 2024-05-08 17:45, Mario Limonciello wrote:

MST colorspace property support was disabled due to a series of warnings
that came up when the device was plugged in since the properties weren't
made at device creation. Create the properties in advance instead.

Suggested-by: Ville Syrjälä 
Fixes: 69a959610229 ("drm/amd/display: Temporary Disable MST DP Colorspace 
Property").
Reported-and-tested-by: Tyler Schneider 
Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/3353
Signed-off-by: Mario Limonciello 


Reviewed-by: Harry Wentland 

Harry


---
  drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c | 3 +++
  1 file changed, 3 insertions(+)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
index 941e96f100f4..12b036d511d0 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
@@ -613,6 +613,9 @@ dm_dp_add_mst_connector(struct drm_dp_mst_topology_mgr *mgr,
>base,
dev->mode_config.tile_property,
0);
+   connector->colorspace_property = master->base.colorspace_property;
+   if (connector->colorspace_property)
+   drm_connector_attach_colorspace_property(connector);
  
  	drm_connector_set_path_property(connector, pathprop);
  


Re: [PATCH v2] drm/amd/display: re-indent dc_power_down_on_boot()

2024-04-30 Thread Harry Wentland



On 2024-04-25 07:21, Dan Carpenter wrote:
> These lines are indented too far.  Clean the whitespace.
> 

Thanks.

Reviewed-by: Harry Wentland 

In the process of merging it into amd-staging-drm-next.

Harry

> Signed-off-by: Dan Carpenter 
> ---
> v2: Delete another blank line (checkpatch.pl --strict).
> 
>  drivers/gpu/drm/amd/display/dc/core/dc.c | 8 +++-
>  1 file changed, 3 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c 
> b/drivers/gpu/drm/amd/display/dc/core/dc.c
> index 3e16041bf4f9..5a0835f884a8 100644
> --- a/drivers/gpu/drm/amd/display/dc/core/dc.c
> +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c
> @@ -5192,11 +5192,9 @@ void dc_interrupt_ack(struct dc *dc, enum 
> dc_irq_source src)
>  void dc_power_down_on_boot(struct dc *dc)
>  {
>   if (dc->ctx->dce_environment != DCE_ENV_VIRTUAL_HW &&
> - dc->hwss.power_down_on_boot) {
> -
> - if (dc->caps.ips_support)
> - dc_exit_ips_for_hw_access(dc);
> -
> + dc->hwss.power_down_on_boot) {
> + if (dc->caps.ips_support)
> + dc_exit_ips_for_hw_access(dc);
>   dc->hwss.power_down_on_boot(dc);
>   }
>  }



Re: [PATCH][next] drm/amd/display: Fix spelling various spelling mistakes

2024-04-30 Thread Harry Wentland



On 2024-04-24 12:28, Colin Ian King wrote:
> There are various spelling mistakes in dml2_printf messages, fix them.
> 

Thanks.

Reviewed-by: Harry Wentland 

In the process of merging it into amd-staging-drm-next.

Harry

> Signed-off-by: Colin Ian King 
> ---
>  .../dc/dml2/dml21/src/dml2_core/dml2_core_dcn4_calcs.c  | 6 +++---
>  .../display/dc/dml2/dml21/src/dml2_core/dml2_core_shared.c  | 6 +++---
>  2 files changed, 6 insertions(+), 6 deletions(-)
> 
> diff --git 
> a/drivers/gpu/drm/amd/display/dc/dml2/dml21/src/dml2_core/dml2_core_dcn4_calcs.c
>  
> b/drivers/gpu/drm/amd/display/dc/dml2/dml21/src/dml2_core/dml2_core_dcn4_calcs.c
> index 846b0ae48596..2dea5965d02f 100644
> --- 
> a/drivers/gpu/drm/amd/display/dc/dml2/dml21/src/dml2_core/dml2_core_dcn4_calcs.c
> +++ 
> b/drivers/gpu/drm/amd/display/dc/dml2/dml21/src/dml2_core/dml2_core_dcn4_calcs.c
> @@ -5566,7 +5566,7 @@ static bool CalculatePrefetchSchedule(struct 
> dml2_core_internal_scratch *scratch
>   dml2_printf("DML: Tvm: %fus - time to fetch vm\n", 
> s->TimeForFetchingVM);
>   dml2_printf("DML: Tr0: %fus - time to fetch first row of data 
> pagetables\n", s->TimeForFetchingRowInVBlank);
>   dml2_printf("DML: Tsw: %fus = time to fetch enough pixel data 
> and cursor data to feed the scalers init position and detile\n", 
> (double)s->LinesToRequestPrefetchPixelData * s->LineTime);
> - dml2_printf("DML: To: %fus - time for propogation from scaler 
> to optc\n", (*p->DSTYAfterScaler + ((double)(*p->DSTXAfterScaler) / 
> (double)p->myPipe->HTotal)) * s->LineTime);
> + dml2_printf("DML: To: %fus - time for propagation from scaler 
> to optc\n", (*p->DSTYAfterScaler + ((double)(*p->DSTXAfterScaler) / 
> (double)p->myPipe->HTotal)) * s->LineTime);
>   dml2_printf("DML: Tvstartup - TSetup - Tcalc - TWait - Tpre - 
> To > 0\n");
>   dml2_printf("DML: Tslack(pre): %fus - time left over in 
> schedule\n", p->VStartup * s->LineTime - s->TimeForFetchingVM - 2 * 
> s->TimeForFetchingRowInVBlank - (*p->DSTYAfterScaler + 
> ((double)(*p->DSTXAfterScaler) / (double)p->myPipe->HTotal)) * s->LineTime - 
> p->TWait - p->TCalc - *p->TSetup);
>   dml2_printf("DML: row_bytes = dpte_row_bytes (per_pipe) = 
> PixelPTEBytesPerRow = : %u\n", p->PixelPTEBytesPerRow);
> @@ -7825,7 +7825,7 @@ static bool dml_core_mode_support(struct 
> dml2_core_calcs_mode_support_ex *in_out
>   dml2_printf("DML::%s: mode_lib->ms.FabricClock = %f\n", __func__, 
> mode_lib->ms.FabricClock);
>   dml2_printf("DML::%s: mode_lib->ms.uclk_freq_mhz = %f\n", __func__, 
> mode_lib->ms.uclk_freq_mhz);
>   dml2_printf("DML::%s: max_urgent_latency_us = %f\n", __func__, 
> mode_lib->ms.support.max_urgent_latency_us);
> - dml2_printf("DML::%s: urgent latency tolarance = %f\n", __func__, 
> ((mode_lib->ip.rob_buffer_size_kbytes - mode_lib->ip.pixel_chunk_size_kbytes) 
> * 1024 / (mode_lib->ms.DCFCLK * mode_lib->soc.return_bus_width_bytes)));
> + dml2_printf("DML::%s: urgent latency tolerance = %f\n", __func__, 
> ((mode_lib->ip.rob_buffer_size_kbytes - mode_lib->ip.pixel_chunk_size_kbytes) 
> * 1024 / (mode_lib->ms.DCFCLK * mode_lib->soc.return_bus_width_bytes)));
>   dml2_printf("DML::%s: ROBSupport = %u\n", __func__, 
> mode_lib->ms.support.ROBSupport);
>  #endif
>  
> @@ -10603,7 +10603,7 @@ static bool dml_core_mode_programming(struct 
> dml2_core_calcs_mode_programming_ex
>   if 
> (display_cfg->plane_descriptors[k].immediate_flip && 
> mode_lib->mp.ImmediateFlipSupportedForPipe[k] == false) {
>   mode_lib->mp.ImmediateFlipSupported = 
> false;
>  #ifdef __DML_VBA_DEBUG__
> - dml2_printf("DML::%s: Pipe %0d not 
> supporing iflip!\n", __func__, k);
> + dml2_printf("DML::%s: Pipe %0d not 
> supporting iflip!\n", __func__, k);
>  #endif
>   }
>   }
> diff --git 
> a/drivers/gpu/drm/amd/display/dc/dml2/dml21/src/dml2_core/dml2_core_shared.c 
> b/drivers/gpu/drm/amd/display/dc/dml2/dml21/src/dml2_core/dml2_core_shared.c
> index 0ef77a89d984..d1d4fe062d4e 100644
> --- 
> a/drivers/gpu/drm/amd/display/dc/dml2/dml21/src/dml2_core/dml2_core_shared.c
> +++ 
> b/drivers/gpu/drm/amd/display/dc/dml2/dml21/src/dml2_core/dml2_core_shared.c
> @@ -2023,7

Re: [PATCH] drm/amd/display: Avoid -Wenum-float-conversion in add_margin_and_round_to_dfs_grainularity()

2024-04-30 Thread Harry Wentland



On 2024-04-24 12:14, Nathan Chancellor wrote:
> When building with clang 19 or newer (which strengthened some of the
> enum conversion warnings for C), there is a warning (or error with
> CONFIG_WERROR=y) around doing arithmetic with an enumerated type and a
> floating point expression.
> 
>   
> drivers/gpu/drm/amd/amdgpu/../display/dc/dml2/dml21/src/dml2_dpmm/dml2_dpmm_dcn4.c:181:58:
>  error: arithmetic between enumeration type 'enum dentist_divider_range' and 
> floating-point type 'double' [-Werror,-Wenum-float-conversion]
> 181 | divider = (unsigned int)(DFS_DIVIDER_RANGE_SCALE_FACTOR * 
> (vco_freq_khz / clock_khz));
> |  ~~ ^ 
> ~~
>   1 error generated.
> 
> This conversion is expected due to the nature of the enumerated value
> and definition, so silence the warning by casting the enumeration to an
> integer explicitly to make it clear to the compiler.
> 
> Fixes: 3df48ddedee4 ("drm/amd/display: Add new DCN401 sources")

Thanks.

Reviewed-by: Harry Wentland 

In the process of merging it into amd-staging-drm-next.

Harry

> Signed-off-by: Nathan Chancellor 
> ---
> Alternatively, perhaps the potential truncation could happen before the
> multiplication?
> 
>   divider = DFS_DIVIDER_RANGE_SCALE_FACTOR * (unsigned int)(vco_freq_khz / 
> clock_khz);
> 
> I suspect the result of the division is probably not very large
> (certainly not within UINT_MAX / 4), so I would not expect the
> multiplication to overflow, but I was not sure so I decided to take the
> safer, NFC change. I am happy to respin as necessary.
> ---
>  .../gpu/drm/amd/display/dc/dml2/dml21/src/dml2_dpmm/dml2_dpmm_dcn4.c| 2 
> +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git 
> a/drivers/gpu/drm/amd/display/dc/dml2/dml21/src/dml2_dpmm/dml2_dpmm_dcn4.c 
> b/drivers/gpu/drm/amd/display/dc/dml2/dml21/src/dml2_dpmm/dml2_dpmm_dcn4.c
> index e6698ee65843..65eb0187e965 100644
> --- a/drivers/gpu/drm/amd/display/dc/dml2/dml21/src/dml2_dpmm/dml2_dpmm_dcn4.c
> +++ b/drivers/gpu/drm/amd/display/dc/dml2/dml21/src/dml2_dpmm/dml2_dpmm_dcn4.c
> @@ -178,7 +178,7 @@ static bool 
> add_margin_and_round_to_dfs_grainularity(double clock_khz, double ma
>  
>   clock_khz *= 1.0 + margin;
>  
> - divider = (unsigned int)(DFS_DIVIDER_RANGE_SCALE_FACTOR * (vco_freq_khz 
> / clock_khz));
> + divider = (unsigned int)((int)DFS_DIVIDER_RANGE_SCALE_FACTOR * 
> (vco_freq_khz / clock_khz));
>  
>   /* we want to floor here to get higher clock than required rather than 
> lower */
>   if (divider < DFS_DIVIDER_RANGE_2_START) {
> 
> ---
> base-commit: d60dc4dd72412d5d9566fdf391e4202b05f88912
> change-id: 20240424-amdgpu-display-dcn401-enum-float-conversion-c09cc1826ea2
> 
> Best regards,



Re: [PATCH] drm/uapi: Move drm_color_ctm_3x4 out from drm_mode.h

2024-04-30 Thread Harry Wentland



On 2024-04-22 04:58, Ville Syrjala wrote:
> From: Ville Syrjälä 
> 
> drm_color_ctm_3x4 is some undocumented amgdpu private
> uapi and thus has no business being in drm_mode.h.
> At least move it to some amdgpu specific header, albeit
> with the wrong namespace as maybe something somewhere
> is using this already?
> 
> Cc: Harry Wentland 
> Cc: Joshua Ashton 
> Cc: Alex Deucher 
> Fixes: 6872a189be50 ("drm/amd/display: Add 3x4 CTM support for plane CTM")
> Signed-off-by: Ville Syrjälä 

We'll bring this back with the color pipeline stuff but for now it doesn't
need to sit in drm_mode.h and probably shouldn't.

Reviewed-by: Harry Wentland 

Harry

> ---
>  include/uapi/drm/amdgpu_drm.h | 9 +
>  include/uapi/drm/drm_mode.h   | 8 
>  2 files changed, 9 insertions(+), 8 deletions(-)
> 
> diff --git a/include/uapi/drm/amdgpu_drm.h b/include/uapi/drm/amdgpu_drm.h
> index 96e32dafd4f0..d5ebafacdd70 100644
> --- a/include/uapi/drm/amdgpu_drm.h
> +++ b/include/uapi/drm/amdgpu_drm.h
> @@ -1269,6 +1269,15 @@ struct drm_amdgpu_info_gpuvm_fault {
>  #define AMDGPU_FAMILY_GC_10_3_7  151 /* GC 10.3.7 */
>  #define AMDGPU_FAMILY_GC_11_5_0  150 /* GC 11.5.0 */
>  
> +/* FIXME wrong namespace! */
> +struct drm_color_ctm_3x4 {
> + /*
> +  * Conversion matrix with 3x4 dimensions in S31.32 sign-magnitude
> +  * (not two's complement!) format.
> +  */
> + __u64 matrix[12];
> +};
> +
>  #if defined(__cplusplus)
>  }
>  #endif
> diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h
> index 1ca5c7e418fd..d390011b89b4 100644
> --- a/include/uapi/drm/drm_mode.h
> +++ b/include/uapi/drm/drm_mode.h
> @@ -846,14 +846,6 @@ struct drm_color_ctm {
>   __u64 matrix[9];
>  };
>  
> -struct drm_color_ctm_3x4 {
> - /*
> -  * Conversion matrix with 3x4 dimensions in S31.32 sign-magnitude
> -  * (not two's complement!) format.
> -  */
> - __u64 matrix[12];
> -};
> -
>  struct drm_color_lut {
>   /*
>* Values are mapped linearly to 0.0 - 1.0 range, with 0x0 == 0.0 and



Re: [PATCH] drm/mst: Fix NULL pointer dereference at drm_dp_add_payload_part2

2024-04-18 Thread Harry Wentland



On 2024-03-07 01:29, Wayne Lin wrote:
> [Why]
> Commit:
> - commit 5aa1dfcdf0a4 ("drm/mst: Refactor the flow for payload 
> allocation/removement")
> accidently overwrite the commit
> - commit 54d217406afe ("drm: use mgr->dev in drm_dbg_kms in 
> drm_dp_add_payload_part2")
> which cause regression.
> 
> [How]
> Recover the original NULL fix and remove the unnecessary input parameter 
> 'state' for
> drm_dp_add_payload_part2().
> 
> Fixes: 5aa1dfcdf0a4 ("drm/mst: Refactor the flow for payload 
> allocation/removement")
> Reported-by: Leon Weiß 
> Link: 
> https://lore.kernel.org/r/38c253ea42072cc825dc969ac4e6b9b600371cc8.ca...@ruhr-uni-bochum.de/
> Cc: ly...@redhat.com
> Cc: imre.d...@intel.com
> Cc: sta...@vger.kernel.org
> Cc: regressi...@lists.linux.dev
> Signed-off-by: Wayne Lin 

I haven't been deep in MST code in a while but this all looks
pretty straightforward and good.

Reviewed-by: Harry Wentland 

Harry

> ---
>  drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c | 2 +-
>  drivers/gpu/drm/display/drm_dp_mst_topology.c | 4 +---
>  drivers/gpu/drm/i915/display/intel_dp_mst.c   | 2 +-
>  drivers/gpu/drm/nouveau/dispnv50/disp.c   | 2 +-
>  include/drm/display/drm_dp_mst_helper.h   | 1 -
>  5 files changed, 4 insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c 
> b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
> index c27063305a13..2c36f3d00ca2 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
> @@ -363,7 +363,7 @@ void dm_helpers_dp_mst_send_payload_allocation(
>   mst_state = to_drm_dp_mst_topology_state(mst_mgr->base.state);
>   new_payload = drm_atomic_get_mst_payload_state(mst_state, 
> aconnector->mst_output_port);
>  
> - ret = drm_dp_add_payload_part2(mst_mgr, mst_state->base.state, 
> new_payload);
> + ret = drm_dp_add_payload_part2(mst_mgr, new_payload);
>  
>   if (ret) {
>   amdgpu_dm_set_mst_status(>mst_status,
> diff --git a/drivers/gpu/drm/display/drm_dp_mst_topology.c 
> b/drivers/gpu/drm/display/drm_dp_mst_topology.c
> index 03d528209426..95fd18f24e94 100644
> --- a/drivers/gpu/drm/display/drm_dp_mst_topology.c
> +++ b/drivers/gpu/drm/display/drm_dp_mst_topology.c
> @@ -3421,7 +3421,6 @@ EXPORT_SYMBOL(drm_dp_remove_payload_part2);
>  /**
>   * drm_dp_add_payload_part2() - Execute payload update part 2
>   * @mgr: Manager to use.
> - * @state: The global atomic state
>   * @payload: The payload to update
>   *
>   * If @payload was successfully assigned a starting time slot by 
> drm_dp_add_payload_part1(), this
> @@ -3430,14 +3429,13 @@ EXPORT_SYMBOL(drm_dp_remove_payload_part2);
>   * Returns: 0 on success, negative error code on failure.
>   */
>  int drm_dp_add_payload_part2(struct drm_dp_mst_topology_mgr *mgr,
> -  struct drm_atomic_state *state,
>struct drm_dp_mst_atomic_payload *payload)
>  {
>   int ret = 0;
>  
>   /* Skip failed payloads */
>   if (payload->payload_allocation_status != 
> DRM_DP_MST_PAYLOAD_ALLOCATION_DFP) {
> - drm_dbg_kms(state->dev, "Part 1 of payload creation for %s 
> failed, skipping part 2\n",
> + drm_dbg_kms(mgr->dev, "Part 1 of payload creation for %s 
> failed, skipping part 2\n",
>   payload->port->connector->name);
>   return -EIO;
>   }
> diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c 
> b/drivers/gpu/drm/i915/display/intel_dp_mst.c
> index 53aec023ce92..2fba66aec038 100644
> --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c
> +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c
> @@ -1160,7 +1160,7 @@ static void intel_mst_enable_dp(struct 
> intel_atomic_state *state,
>   if (first_mst_stream)
>   intel_ddi_wait_for_fec_status(encoder, pipe_config, true);
>  
> - drm_dp_add_payload_part2(_dp->mst_mgr, >base,
> + drm_dp_add_payload_part2(_dp->mst_mgr,
>drm_atomic_get_mst_payload_state(mst_state, 
> connector->port));
>  
>   if (DISPLAY_VER(dev_priv) >= 12)
> diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c 
> b/drivers/gpu/drm/nouveau/dispnv50/disp.c
> index 0c3d88ad0b0e..88728a0b2c25 100644
> --- a/drivers/gpu/drm/nouveau/dispnv50/disp.c
> +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c
> @@ -915,7 +915,7 @@ nv50_msto_cleanup(struct drm_atomic_state *state,
>   msto->disabled = fals

Re: [PATCH v2 1/4] drm/amd/display: Remove unnecessary SIGNAL_TYPE_HDMI_TYPE_A check

2024-04-17 Thread Harry Wentland



On 2024-01-15 11:05, Andri Yngvason wrote:
> From: Werner Sembach 
> 
> Remove unnecessary SIGNAL_TYPE_HDMI_TYPE_A check that was performed in the
> drm_mode_is_420_only() case, but not in the drm_mode_is_420_also() &&
> force_yuv420_output case.
> 
> Without further knowledge if YCbCr 4:2:0 is supported outside of HDMI,
> there is no reason to use RGB when the display
> reports drm_mode_is_420_only() even on a non HDMI connection.
> 
> This patch also moves both checks in the same if-case. This  eliminates an
> extra else-if-case.
> 
> Signed-off-by: Werner Sembach 
> Signed-off-by: Andri Yngvason 
> Tested-by: Andri Yngvason 
> ---
>  drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 6 +-
>  1 file changed, 1 insertion(+), 5 deletions(-)
> 
> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 
> b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> index f6575d7dee971..cc4d1f7f97b98 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> @@ -5575,11 +5575,7 @@ static void 
> fill_stream_properties_from_drm_display_mode(
>   timing_out->v_border_bottom = 0;
>   /* TODO: un-hardcode */
>   if (drm_mode_is_420_only(info, mode_in)
> - && stream->signal == SIGNAL_TYPE_HDMI_TYPE_A)
> - timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR420;
> - else if (drm_mode_is_420_also(info, mode_in)
> - && aconnector
> - && aconnector->force_yuv420_output)
> + || (drm_mode_is_420_also(info, mode_in) && 
> aconnector->force_yuv420_output))

We need to keep the && aconnector NULL check here, otherwise
writeback connectors will blow up.

Harry

>   timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR420;
>   else if ((connector->display_info.color_formats & 
> DRM_COLOR_FORMAT_YCBCR444)
>   && stream->signal == SIGNAL_TYPE_HDMI_TYPE_A)



Re: [PATCH v2 2/4] drm/uAPI: Add "force color format" drm property as setting for userspace

2024-04-17 Thread Harry Wentland
I'm a bit late to the game but I don't think this is merged
yet.

On 2024-01-15 11:05, Andri Yngvason wrote:
> From: Werner Sembach 
> 
> Add a new general drm property "force color format" which can be used
> by userspace to tell the graphics driver which color format to use.
> 
> Possible options are:
> - auto (default/current behaviour)
> - rgb
> - ycbcr444
> - ycbcr422 (supported by neither amdgpu or i915)

If no driver uses this should we expose this now? I would
prefer to leave ycbcr422 out of this until we have a driver
that actually uses it.

I've seen too many properties with ever possible value defined
but they're not used by any (open) userspace and then become
the object of intense discussion on how they should work. I
doubt that this would happen here, but I still feel a slight
aversion to defining things that no open userspace can use at
this point.

I agree with all of Sebastian and Pekka's comments elsewhere in
this thread, in particular with Sebastian's comments to not
advertise color formats that a driver can't support. See this
patch for how I implemented something similar for Colorspace
c265f340eaa8 ("drm/connector: Allow drivers to pass list of supported 
colorspaces")

Harry

> - ycbcr420
> 
> In theory the auto option should choose the best available option for the
> current setup, but because of bad internal conversion some monitors look
> better with rgb and some with ycbcr444.
> 
> Also, because of bad shielded connectors and/or cables, it might be
> preferable to use the less bandwidth heavy ycbcr422 and ycbcr420 formats
> for a signal that is less susceptible to interference.
> 
> In the future, automatic color calibration for screens might also depend on
> this option being available.
> 
> Signed-off-by: Werner Sembach 
> Signed-off-by: Andri Yngvason 
> Tested-by: Andri Yngvason 
> ---
> 
> Changes in v2:
>  - Renamed to "force color format" from "preferred color format"
>  - Removed Reported-by pointing to invalid email address
> 
> ---
>  drivers/gpu/drm/drm_atomic_helper.c |  4 +++
>  drivers/gpu/drm/drm_atomic_uapi.c   |  4 +++
>  drivers/gpu/drm/drm_connector.c | 48 +
>  include/drm/drm_connector.h | 16 ++
>  4 files changed, 72 insertions(+)
> 
> diff --git a/drivers/gpu/drm/drm_atomic_helper.c 
> b/drivers/gpu/drm/drm_atomic_helper.c
> index 39ef0a6addeba..1dabd164c4f09 100644
> --- a/drivers/gpu/drm/drm_atomic_helper.c
> +++ b/drivers/gpu/drm/drm_atomic_helper.c
> @@ -707,6 +707,10 @@ drm_atomic_helper_check_modeset(struct drm_device *dev,
>   if (old_connector_state->max_requested_bpc !=
>   new_connector_state->max_requested_bpc)
>   new_crtc_state->connectors_changed = true;
> +
> + if (old_connector_state->force_color_format !=
> + new_connector_state->force_color_format)
> + new_crtc_state->connectors_changed = true;
>   }
>  
>   if (funcs->atomic_check)
> diff --git a/drivers/gpu/drm/drm_atomic_uapi.c 
> b/drivers/gpu/drm/drm_atomic_uapi.c
> index 29d4940188d49..e45949bf4615f 100644
> --- a/drivers/gpu/drm/drm_atomic_uapi.c
> +++ b/drivers/gpu/drm/drm_atomic_uapi.c
> @@ -776,6 +776,8 @@ static int drm_atomic_connector_set_property(struct 
> drm_connector *connector,
>   state->max_requested_bpc = val;
>   } else if (property == connector->privacy_screen_sw_state_property) {
>   state->privacy_screen_sw_state = val;
> + } else if (property == connector->force_color_format_property) {
> + state->force_color_format = val;
>   } else if (connector->funcs->atomic_set_property) {
>   return connector->funcs->atomic_set_property(connector,
>   state, property, val);
> @@ -859,6 +861,8 @@ drm_atomic_connector_get_property(struct drm_connector 
> *connector,
>   *val = state->max_requested_bpc;
>   } else if (property == connector->privacy_screen_sw_state_property) {
>   *val = state->privacy_screen_sw_state;
> + } else if (property == connector->force_color_format_property) {
> + *val = state->force_color_format;
>   } else if (connector->funcs->atomic_get_property) {
>   return connector->funcs->atomic_get_property(connector,
>   state, property, val);
> diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
> index b0516505f7ae9..e0535e58b4535 100644
> --- a/drivers/gpu/drm/drm_connector.c
> +++ b/drivers/gpu/drm/drm_connector.c
> @@ -1061,6 +1061,14 @@ static const struct drm_prop_enum_list 
> drm_dp_subconnector_enum_list[] = {
>   { DRM_MODE_SUBCONNECTOR_Native,  "Native"}, /* DP */
>  };
>  
> +static const struct drm_prop_enum_list drm_force_color_format_enum_list[] = {
> + { 0, "auto" },
> + { 

Re: [PATCH 0/2] drm/amdgpu/display: Make multi-plane configurations more flexible

2024-04-16 Thread Harry Wentland



On 2024-04-16 04:01, Pekka Paalanen wrote:
> On Mon, 15 Apr 2024 18:33:39 -0400
> Leo Li  wrote:
> 
>> On 2024-04-15 04:19, Pekka Paalanen wrote:
>>> On Fri, 12 Apr 2024 16:14:28 -0400
>>> Leo Li  wrote:
>>>   
 On 2024-04-12 11:31, Alex Deucher wrote:  
> On Fri, Apr 12, 2024 at 11:08 AM Pekka Paalanen
>  wrote:  
>>
>> On Fri, 12 Apr 2024 10:28:52 -0400
>> Leo Li  wrote:
>> 
>>> On 2024-04-12 04:03, Pekka Paalanen wrote:  
 On Thu, 11 Apr 2024 16:33:57 -0400
 Leo Li  wrote:
 
>>
>> ...
>> 
> That begs the question of what can be nailed down and what can left to
> independent implementation. I guess things like which plane should be 
> enabled
> first (PRIMARY), and how zpos should be interpreted (overlay, 
> underlay, mixed)
> can be defined. How to handle atomic test failures could be as well.  

 What room is there for the interpretation of zpos values?

 I thought they are unambiguous already: only the relative numerical
 order matters, and that uniquely defines the KMS plane ordering.  
>>>
>>> The zpos value of the PRIMARY plane relative to OVERLAYS, for example, 
>>> as a way
>>> for vendors to communicate overlay, underlay, or mixed-arrangement 
>>> support. I
>>> don't think allowing OVERLAYs to be placed under the PRIMARY is 
>>> currently
>>> documented as a way to support underlay.  
>>
>> I always thought it's obvious that the zpos numbers dictate the plane
>> order without any other rules. After all, we have the universal planes
>> concept, where the plane type is only informational to aid heuristics
>> rather than defining anything.
>>
>> Only if the zpos property does not exist, the plane types would come
>> into play.
>>
>> Of course, if there actually exists userspace that fails if zpos allows
>> an overlay type plane to be placed below primary, or fails if primary
>> zpos is not zero, then DRM needs a new client cap.  

 Right, it wasn't immediately clear to me that the API allowed placement of
 things beneath the PRIMARY. But reading the docs for 
 drm_plane_create_zpos*,
 there's nothing that forbids it.
  
>> 
>>> libliftoff for example, assumes that the PRIMARY has the lowest zpos. So
>>> underlay arrangements will use an OVERLAY for the scanout plane, and 
>>> the PRIMARY
>>> for the underlay view.  
>>
>> That's totally ok. It works, right? Plane type does not matter if the
>> KMS driver accepts the configuration.
>>
>> What is a "scanout plane"? Aren't all KMS planes by definition scanout
>> planes?  

 Pardon my terminology, I thought the scanout plane was where weston 
 rendered
 non-offloadable surfaces to. I guess it's more correct to call it the 
 "render
 plane". On weston, it seems to be always assigned to the PRIMARY.
  
>>>
>>> The assignment restriction is just technical design debt. It is
>>> limiting. There is no other good reason for it, than when lighting
>>> up a CRTC for the first time, Weston should do it with the renderer FB
>>> only, on the plane that is most likely to succeed i.e. PRIMARY. After
>>> the CRTC is lit, there should be no built-in limitations in what can go
>>> where.
>>>
>>> The reason for this is that if a CRTC can be activated, it must always
>>> be able to show the renderer FB without incurring a modeset. This is
>>> important for ensuring that the fallback compositing (renderer) is
>>> always possible. So we start with that configuration, and everything
>>> else is optional bonus.  
>>
>> Genuinely curious - What exactly is limiting with keeping the renderer FB on
>> PRIMARY? IOW, what is the additional benefit of placing the renderer FB on
>> something other than PRIMARY?
> 
> The limitations come from a combination of hardware limitations.
> Perhaps zpos is not mutable, or maybe other planes cannot arbitrarily
> move between above and below the primary. This reduces the number of
> possible configurations, which might cause off-loading to fail.
> 
> I think older hardware has more of these arbitrary restrictions.
> 

 For libliftoff, using OVERLAYs as the render plane and PRIMARY as the 
 underlay
 plane would work. But I think keeping the render plane on PRIMARY (a la 
 weston)
 makes underlay arrangements easier to allocate, and would be nice to 
 incorporate
 into a shared algorithm.  
>>>
>>> If zpos exists, I don't think such limitation is a good idea. It will
>>> just limit the possible configurations for no reason.
>>>
>>> With zpos, the KMS plane type should be irrelevant for their
>>> z-ordering. Underlay vs. overlay completely loses its meaning at the
>>> KMS level.  
>>
>> Right, the plane types loose their meanings. But at least with the way
>> 

Re: [PATCH 0/2] drm/amdgpu/display: Make multi-plane configurations more flexible

2024-04-04 Thread Harry Wentland
on plane
>> arrangement algorithm. I think libliftoff is the most obvious candidate 
>> here. It
>> only handles overlay arrangements currently, but mixed-mode arrangements is
>> something I've been trying to look at.
>>
>> Taking the driver's reported zpos into account could narrow down the search
>> space for mixed arrangements. We could tell whether underlay, or overlay, or
>> both, is supported by looking at the allowed zpos ranges.
>>
>> I also wonder if it'll make underlay assignments easier. libliftoff has an
>> assumption that the PRIMARY plane has the lowest zpos (which now I realize, 
>> is
>> not always true). Therefore, the underlay buffer has to be placed on the
>> PRIMARY, with the render buffer on a higher OVERLAY. Swapping buffers between
>> planes when testing mixed-arrangements is kind of awkward, and simply setting
>> the OVERLAY's zpos to be lower or higher than the PRIMARY's sounds simpler.
>>
>> Currently only gamescope makes use of libliftoff, but I'm curious if patches
>> hooking it up to Weston would be welcomed? If there are other ways to have a
>> common arrangement algorithm, I'd be happy to hear that as well.
> 
> A natural thing would be to document such an algorithm with the KMS
> UAPI.
> 
> I don't know libliftoff well enough to say how welcome it would be in
> Weston. I have no fundamental or policy reason to keep an independent
> implementation in Weston though, so it's plausible at least.
> 
> It would need investigation, and perhaps also extending Weston test
> suite a lot more towards VKMS to verify plane assignments. Currently
> all plane assignment testing is manual on real hardware.
> 

It looks like VKMS doesn't have explicit zpos yet, so someone would
probably need to add that.

https://drmdb.emersion.fr/properties/4008636142/zpos

Harry

>> Note that libliftoff's algorithm is more complex than weston, since it 
>> searches
>> harder, and suffers from that permutational explosion. But it solves that by
>> trying high benefit arrangements first (offloading surfaces that update
>> frequently), and bailing out once the search reaches a hard-coded deadline.
>> Since it's currently overlay-only, the goal could be to "simply" have no
>> regressions.
> 
> Ensuring no regressions would indeed need to be taken care of by
> extending the VKMS-based automated testing.
> 
> 
> Thanks,
> pq
> 
>>>   
>>>> Some links to provide context and details:
>>>> * What is underlay?: 
>>>> https://gitlab.freedesktop.org/emersion/libliftoff/-/issues/76
>>>> * Discussion on how to implement underlay on Weston: 
>>>> https://gitlab.freedesktop.org/wayland/weston/-/merge_requests/1258#note_2325164
>>>>
>>>> Cc: Joshua Ashton 
>>>> Cc: Michel Dänzer 
>>>> Cc: Chao Guo 
>>>> Cc: Xaver Hugl 
>>>> Cc: Vikas Korjani 
>>>> Cc: Robert Mader 
>>>> Cc: Pekka Paalanen 
>>>> Cc: Sean Paul 
>>>> Cc: Simon Ser 
>>>> Cc: Shashank Sharma 
>>>> Cc: Harry Wentland 
>>>> Cc: Sebastian Wick 
>>>>
>>>> Leo Li (2):
>>>>drm/amd/display: Introduce overlay cursor mode
>>>>drm/amd/display: Move PRIMARY plane zpos higher
>>>>
>>>>   .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 405 --
>>>>   .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h |   7 +
>>>>   .../amd/display/amdgpu_dm/amdgpu_dm_crtc.c|   1 +
>>>>   .../amd/display/amdgpu_dm/amdgpu_dm_plane.c   |  28 +-
>>>>   4 files changed, 391 insertions(+), 50 deletions(-)
>>>>  
>>>   
> 



Re: [PATCH 1/2] drm/amd/display: Introduce overlay cursor mode

2024-03-28 Thread Harry Wentland




On 2024-03-28 11:48, Robert Mader wrote:

Hi,

On 15.03.24 18:09, sunpeng...@amd.com wrote:

From: Leo Li 

[Why]

DCN is the display hardware for amdgpu. DRM planes are backed by DCN
hardware pipes, which carry pixel data from one end (memory), to the
other (output encoder).

Each DCN pipe has the ability to blend in a cursor early on in the
pipeline. In other words, there are no dedicated cursor planes in DCN,
which makes cursor behavior somewhat unintuitive for compositors.

For example, if the cursor is in RGB format, but the top-most DRM plane
is in YUV format, DCN will not be able to blend them. Because of this,
amdgpu_dm rejects all configurations where a cursor needs to be enabled
on top of a YUV formatted plane.

 From a compositor's perspective, when computing an allocation for
hardware plane offloading, this cursor-on-yuv configuration result in an
atomic test failure. Since the failure reason is not obvious at all,
compositors will likely fall back to full rendering, which is not ideal.

Instead, amdgpu_dm can try to accommodate the cursor-on-yuv
configuration by opportunistically reserving a separate DCN pipe just
for the cursor. We can refer to this as "overlay cursor mode". It is
contrasted with "native cursor mode", where the native DCN per-pipe
cursor is used.

[How]

On each crtc, compute whether the cursor plane should be enabled in
overlay mode (which currently, is iff the immediate plane below has a
YUV format). If it is, mark the CRTC as requesting overlay cursor mode.


iff -> if

IIRC another case where this would be needed is when the scale of the 
plane below doesn't match the cursor scale. This is especially common 
for videos and thus implicitly covered by the YUV check in most cases, 
but should probably be made explicit. Michel Dänzer might be able to 
comment here.


Another possible case that could be covered here is when some area is 
not covered by any plane and just shows a black background. This happens 
e.g. if a compositor puts a YUV surface on the primary plane that has a 
different width/high ratio than the display. The compositor can add 
black bars by just leaving the area uncovered and thus require only a 
single hardware plane for video playback ("Unless explicitly specified 
(..), the active area of a CRTC will be black by default." 
https://dri.freedesktop.org/docs/drm/gpu/drm-kms.html#plane-abstraction). If the cursor is visible over this black bars, AMD currently refuses the commit IIUC (see also Michel Dänzers comment at https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3177#note_1924544)




Thanks for mentioning both of these scenarios. I agree it would be
good if we can expand the use of the overlay cursor to these cases.

Harry


Thanks,

Robert Mader



During DC validation, attempt to enable a separate DCN pipe for the
cursor if it's in overlay mode. If that fails, or if no overlay mode is
requested, then fallback to native mode.

Signed-off-by: Leo Li 
---
  .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 309 +++---
  .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h |   7 +
  .../amd/display/amdgpu_dm/amdgpu_dm_crtc.c    |   1 +
  .../amd/display/amdgpu_dm/amdgpu_dm_plane.c   |  13 +-
  4 files changed, 288 insertions(+), 42 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c

index 21a61454c878..09ab330aed17 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -8359,8 +8359,19 @@ static void amdgpu_dm_commit_planes(struct 
drm_atomic_state *state,

   * Disable the cursor first if we're disabling all the planes.
   * It'll remain on the screen after the planes are re-enabled
   * if we don't.
+ *
+ * If the cursor is transitioning from native to overlay mode, the
+ * native cursor needs to be disabled first.
   */
-    if (acrtc_state->active_planes == 0)
+    if (acrtc_state->cursor_mode == DM_CURSOR_OVERLAY_MODE &&
+    dm_old_crtc_state->cursor_mode == DM_CURSOR_NATIVE_MODE) {
+    struct dc_cursor_position cursor_position = {0};
+    dc_stream_set_cursor_position(acrtc_state->stream,
+  _position);
+    }
+
+    if (acrtc_state->active_planes == 0 &&
+    dm_old_crtc_state->cursor_mode == DM_CURSOR_NATIVE_MODE)
  amdgpu_dm_commit_cursors(state);
  /* update planes when needed */
@@ -8374,7 +8385,8 @@ static void amdgpu_dm_commit_planes(struct 
drm_atomic_state *state,
  struct dm_plane_state *dm_new_plane_state = 
to_dm_plane_state(new_plane_state);

  /* Cursor plane is handled after stream updates */
-    if (plane->type == DRM_PLANE_TYPE_CURSOR) {
+    if (plane->type == DRM_PLANE_TYPE_CURSOR &&
+    acrtc_state->cursor_mode == DM_CURSOR_NATIVE_MODE) {
  if ((fb && crtc == pcrtc) ||
  (old_plane_state->fb && old_plane_state->crtc == 
pcrtc))

 

Re: [PATCH 1/2] drm/amd/display: Introduce overlay cursor mode

2024-03-21 Thread Harry Wentland



On 2024-03-15 13:09, sunpeng...@amd.com wrote:
> From: Leo Li 
> 
> [Why]
> 
> DCN is the display hardware for amdgpu. DRM planes are backed by DCN
> hardware pipes, which carry pixel data from one end (memory), to the
> other (output encoder).
> 
> Each DCN pipe has the ability to blend in a cursor early on in the
> pipeline. In other words, there are no dedicated cursor planes in DCN,
> which makes cursor behavior somewhat unintuitive for compositors.
> 
> For example, if the cursor is in RGB format, but the top-most DRM plane
> is in YUV format, DCN will not be able to blend them. Because of this,
> amdgpu_dm rejects all configurations where a cursor needs to be enabled
> on top of a YUV formatted plane.
> 
> From a compositor's perspective, when computing an allocation for
> hardware plane offloading, this cursor-on-yuv configuration result in an
> atomic test failure. Since the failure reason is not obvious at all,
> compositors will likely fall back to full rendering, which is not ideal.
> 
> Instead, amdgpu_dm can try to accommodate the cursor-on-yuv
> configuration by opportunistically reserving a separate DCN pipe just
> for the cursor. We can refer to this as "overlay cursor mode". It is
> contrasted with "native cursor mode", where the native DCN per-pipe
> cursor is used.
> 
> [How]
> 
> On each crtc, compute whether the cursor plane should be enabled in
> overlay mode (which currently, is iff the immediate plane below has a
> YUV format). If it is, mark the CRTC as requesting overlay cursor mode.
> 
> During DC validation, attempt to enable a separate DCN pipe for the
> cursor if it's in overlay mode. If that fails, or if no overlay mode is
> requested, then fallback to native mode.
> 
> Signed-off-by: Leo Li 

We should run this through our usual testing cycle, and I need to go over
it a bit more closely than I have, but I like it, so it's
Acked-by: Harry Wentland 

Harry

> ---
>  .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 309 +++---
>  .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h |   7 +
>  .../amd/display/amdgpu_dm/amdgpu_dm_crtc.c|   1 +
>  .../amd/display/amdgpu_dm/amdgpu_dm_plane.c   |  13 +-
>  4 files changed, 288 insertions(+), 42 deletions(-)
> 
> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 
> b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> index 21a61454c878..09ab330aed17 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> @@ -8359,8 +8359,19 @@ static void amdgpu_dm_commit_planes(struct 
> drm_atomic_state *state,
>* Disable the cursor first if we're disabling all the planes.
>* It'll remain on the screen after the planes are re-enabled
>* if we don't.
> +  *
> +  * If the cursor is transitioning from native to overlay mode, the
> +  * native cursor needs to be disabled first.
>*/
> - if (acrtc_state->active_planes == 0)
> + if (acrtc_state->cursor_mode == DM_CURSOR_OVERLAY_MODE &&
> + dm_old_crtc_state->cursor_mode == DM_CURSOR_NATIVE_MODE) {
> + struct dc_cursor_position cursor_position = {0};
> + dc_stream_set_cursor_position(acrtc_state->stream,
> +   _position);
> + }
> +
> + if (acrtc_state->active_planes == 0 &&
> + dm_old_crtc_state->cursor_mode == DM_CURSOR_NATIVE_MODE)
>   amdgpu_dm_commit_cursors(state);
>  
>   /* update planes when needed */
> @@ -8374,7 +8385,8 @@ static void amdgpu_dm_commit_planes(struct 
> drm_atomic_state *state,
>   struct dm_plane_state *dm_new_plane_state = 
> to_dm_plane_state(new_plane_state);
>  
>   /* Cursor plane is handled after stream updates */
> - if (plane->type == DRM_PLANE_TYPE_CURSOR) {
> + if (plane->type == DRM_PLANE_TYPE_CURSOR &&
> + acrtc_state->cursor_mode == DM_CURSOR_NATIVE_MODE) {
>   if ((fb && crtc == pcrtc) ||
>   (old_plane_state->fb && old_plane_state->crtc == 
> pcrtc))
>   cursor_update = true;
> @@ -8727,7 +8739,8 @@ static void amdgpu_dm_commit_planes(struct 
> drm_atomic_state *state,
>* This avoids redundant programming in the case where we're going
>* to be disabling a single plane - those pipes are being disabled.
>*/
> - if (acrtc_state->active_planes)
> + if (acrtc_state->active_planes &&
> + acrtc_state->cursor_mode == DM_CURSOR_NATIVE_MODE)
>   amdgpu_dm

Re: [PATCH 2/2] drm/amd/display: Move PRIMARY plane zpos higher

2024-03-21 Thread Harry Wentland



On 2024-03-15 13:09, sunpeng...@amd.com wrote:
> From: Leo Li 
> 
> [Why]
> 
> Compositors have different ways of assigning surfaces to DRM planes for
> render offloading. It may decide between various strategies: overlay,
> underlay, or a mix of both
> 
> One way for compositors to implement the underlay strategy is to assign
> a higher zpos to the DRM_PRIMARY plane than the DRM_OVERLAY planes,
> effectively turning the DRM_OVERLAY plane into an underlay plane.
> 
> Today, amdgpu attaches an immutable zpos of 0 to the DRM_PRIMARY plane.
> This however, is an arbitrary restriction. DCN pipes are general
> purpose, and can be arranged in any z-order. To support compositors
> using this allocation scheme, we can set a non-zero immutable zpos for
> the PRIMARY, allowing the placement of OVERLAYS (mutable zpos range
> 0-254) beneath the PRIMARY.
> 
> [How]
> 
> Assign a zpos = #no of OVERLAY planes to the PRIMARY plane. Then, clean
> up any assumptions in the driver of PRIMARY plane having the lowest
> zpos.
> 
> Signed-off-by: Leo Li 

With the typo mentioned below fixes this is
Reviewed-by: Harry Wentland 

Before merging we should run a full promotion test (especially the IGT
tests) on it as this could break things in subtle ways.

Harry

> ---
>  .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 96 ++-
>  .../amd/display/amdgpu_dm/amdgpu_dm_plane.c   | 17 +++-
>  2 files changed, 104 insertions(+), 9 deletions(-)
> 
> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 
> b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> index 09ab330aed17..01b00f587701 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> @@ -80,6 +80,7 @@
>  #include 
>  #include 
>  #include 
> +#include 
>  
>  #include 
>  #include 
> @@ -369,6 +370,20 @@ static inline void reverse_planes_order(struct 
> dc_surface_update *array_of_surfa
>   swap(array_of_surface_update[i], array_of_surface_update[j]);
>  }
>  
> +/*
> + * DC will program planes with their z-order determined by their ordering
> + * in the dc_surface_updates array. This comparator is used to sort them
> + * by descending zpos.
> + */
> +static int dm_plane_layer_index_cmp(const void *a, const void *b)
> +{
> + const struct dc_surface_update *sa = (struct dc_surface_update *)a;
> + const struct dc_surface_update *sb = (struct dc_surface_update *)b;
> +
> + /* Sort by descending dc_plane layer_index (i.e. normalized_zpos) */
> + return sb->surface->layer_index - sa->surface->layer_index;
> +}
> +
>  /**
>   * update_planes_and_stream_adapter() - Send planes to be updated in DC
>   *
> @@ -393,7 +408,8 @@ static inline bool 
> update_planes_and_stream_adapter(struct dc *dc,
>   struct dc_stream_update 
> *stream_update,
>   struct dc_surface_update 
> *array_of_surface_update)
>  {
> - reverse_planes_order(array_of_surface_update, planes_count);
> + sort(array_of_surface_update, planes_count,
> +  sizeof(*array_of_surface_update), dm_plane_layer_index_cmp, NULL);
>  
>   /*
>* Previous frame finished and HW is ready for optimization.
> @@ -9363,6 +9379,8 @@ static void amdgpu_dm_atomic_commit_tail(struct 
> drm_atomic_state *state)
>   for (j = 0; j < status->plane_count; j++)
>   dummy_updates[j].surface = status->plane_states[0];
>  
> + sort(dummy_updates, status->plane_count,
> +  sizeof(*dummy_updates), dm_plane_layer_index_cmp, NULL);
>  
>   mutex_lock(>dc_lock);
>   dc_update_planes_and_stream(dm->dc,
> @@ -10097,6 +10115,17 @@ static bool should_reset_plane(struct 
> drm_atomic_state *state,
>   if (new_crtc_state->color_mgmt_changed)
>   return true;
>  
> + /*
> +  * On zpos change, planes need to be reordered by removing and re-adding
> +  * them one by one to the dc state, in order of descending zpos.
> +  *
> +  * TODO: We can likely skip bandwidth validation if the only thing that
> +  * changed about the plane was it'z z-ordering.
> +  */
> + if (new_crtc_state->zpos_changed) {
> + return true;
> + }
> +
>   if (drm_atomic_crtc_needs_modeset(new_crtc_state))
>   return true;
>  
> @@ -10509,6 +10538,65 @@ dm_get_plane_scale(struct drm_plane_state 
> *plane_state,
>   *out_plane_scale_h = plane_state->crtc_h * 1000 / plane_src_h;
>  }
>  
> +/*
> + * The normalized

Re: [PATCH 1/7] drm: Fix drm_fixp2int_round() making it add 0.5

2024-03-14 Thread Harry Wentland



On 2024-03-14 09:31, Melissa Wen wrote:
> On 03/14, Melissa Wen wrote:
>> On 03/13, Arthur Grillo wrote:
>>>
>>>
>>> On 12/03/24 15:27, Melissa Wen wrote:
 On 03/06, Arthur Grillo wrote:
> As well noted by Pekka[1], the rounding of drm_fixp2int_round is wrong.
> To round a number, you need to add 0.5 to the number and floor that,
> drm_fixp2int_round() is adding 0.076. Make it add 0.5.
>
> [1]: 
> https://lore.kernel.org/all/20240301135327.22efe0dd.pekka.paala...@collabora.com/
>
 Hi Arthur,

 thanks for addressing this issue.

 Please, add a fix tag to the commit that you are fixing, so we can
 easily backport. Might be this commit:
 https://cgit.freedesktop.org/drm/drm-misc/commit/drivers/gpu/drm/vkms?id=ab87f558dcfb2562c3497e89600dec798a446665
> Suggested-by: Pekka Paalanen 
> Signed-off-by: Arthur Grillo 
> ---
>  include/drm/drm_fixed.h | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/include/drm/drm_fixed.h b/include/drm/drm_fixed.h
> index 0c9f917a4d4b..de3a79909ac9 100644
> --- a/include/drm/drm_fixed.h
> +++ b/include/drm/drm_fixed.h
> @@ -90,7 +90,7 @@ static inline int drm_fixp2int(s64 a)
>  
>  static inline int drm_fixp2int_round(s64 a)
>  {
> - return drm_fixp2int(a + (1 << (DRM_FIXED_POINT_HALF - 1)));
 Also, this is the only usage of DRM_FIXED_POINT_HALF. Can you also
 remove it as it won't be used anymore?

> + return drm_fixp2int(a + DRM_FIXED_ONE / 2);
 Would this division be equivalent to just shifting 1ULL by 31 instead of
 32 as done in DRM_FIXED_ONE?
>>>
>>> Yes, but I think the division makes it easier to understand what is
>>> going on.
>>
>> Right. I was thinking about slightly better performance, but I don't
>> have any data. We can go with this since you consider more readable,
>> anyway.
> 
> Just checked that Harry proposed in another patch[1] this:
> `#define DRM_FIXED_HALF   0x8000ll` for the 0.5 const
> 
> Doesn't it sounds better?
> 

I tend to agree with Arthur and Pekka. DRM_FIXED_ONE / 2 makes it
really clear what's happening here. And I'd imagine compilers would
optimize it out anyways.

Obviously not opposed to a define but if it's only used in one place
I don't think it matters much.

Harry

> [1] 
> https://lore.kernel.org/dri-devel/20240226211100.100108-4-harry.wentl...@amd.com/
>>
>> Can you send another version addressing the other comments? Then I can
>> cherry-pick and already apply the fix.
>>
>> Thanks,
>>
>> Melissa
>>
>>>
>>> Best Regards,
>>> ~Arthur Grillo
>>>

 Melissa

>  }
>  
>  static inline int drm_fixp2int_ceil(s64 a)
>
> -- 
> 2.43.0
>



Re: [PATCH 1/7] drm: Fix drm_fixp2int_round() making it add 0.5

2024-03-08 Thread Harry Wentland

On 2024-03-06 15:03, Arthur Grillo wrote:

As well noted by Pekka[1], the rounding of drm_fixp2int_round is wrong.
To round a number, you need to add 0.5 to the number and floor that,
drm_fixp2int_round() is adding 0.076. Make it add 0.5.

[1]: 
https://lore.kernel.org/all/20240301135327.22efe0dd.pekka.paala...@collabora.com/

Suggested-by: Pekka Paalanen 
Signed-off-by: Arthur Grillo 


Reviewed-by: Harry Wentland 

I had a different jab at this [1], but your patch is cleaner.

https://patchwork.freedesktop.org/patch/579978/?series=123446=4

Harry


---
  include/drm/drm_fixed.h | 2 +-
  1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/include/drm/drm_fixed.h b/include/drm/drm_fixed.h
index 0c9f917a4d4b..de3a79909ac9 100644
--- a/include/drm/drm_fixed.h
+++ b/include/drm/drm_fixed.h
@@ -90,7 +90,7 @@ static inline int drm_fixp2int(s64 a)
  
  static inline int drm_fixp2int_round(s64 a)

  {
-   return drm_fixp2int(a + (1 << (DRM_FIXED_POINT_HALF - 1)));
+   return drm_fixp2int(a + DRM_FIXED_ONE / 2);
  }
  
  static inline int drm_fixp2int_ceil(s64 a)




Re: [PATCH] drm/amd: Drop abm_level property

2024-03-06 Thread Harry Wentland



On 2024-03-06 13:02, Mario Limonciello wrote:
> On 3/6/2024 12:00, Xaver Hugl wrote:
>> Am Mi., 6. März 2024 um 18:19 Uhr schrieb Mario Limonciello
>> :
>>> So the idea being if the compositor isn't using it we let
>>> power-profiles-daemon (or any other software) take control via sysfs and
>>> if the compositor does want to control it then it then it writes a DRM
>>> cap and we destroy the sysfs file?
>>
>> Yes. That way still only one party controls it at a given time, and we
>> can get both good default behavior for display servers that don't care
>> (like Xorg or compositors without color management support), and
>> compositors that want to put in the effort can do more specific things
>> with it.
> 
> I think that's a very good solution.
> 
> Harry, Hamza, what do you guys think?

In theory I like it. But how will this look in practice? Is PPD or compositor
on the scene first? Would it be possible to yank the sysfs away from PPD?

DRM client caps are set by the client when the client interacts with DRM.
At driver creation there is no client. How will the driver set things up?

A user might switch between DRM clients (login manager, to desktop compositor,
maybe to another VT with a different compositor). I know everything but the
login manager to desktop compositor hand-off is today considered exotic, but
what if someone starts building a use-case for it? I've done a bunch of 
gamescope
or IGT work in a different VT while I've had Plasma running on its default
VT.

If someone can sketch this out, with answers to all the questions above and
any other questions you can come up (be creative), I'd be happy to review.
Alternatively we can discuss this at the hackfest and maybe arrive at a
solution.

Harry




Re: [RFC PATCH v4 06/42] drm/vkms: Add kunit tests for VKMS LUT handling

2024-02-27 Thread Harry Wentland



On 2024-02-27 07:14, Arthur Grillo wrote:
> 
> 
> On 26/02/24 18:10, Harry Wentland wrote:
>> Debugging LUT math is much easier when we can unit test
>> it. Add kunit functionality to VKMS and add tests for
>>  - get_lut_index
>>  - lerp_u16
>>
>> v4:
>>  - Test the critical points of the lerp function (Pekka)
>>
>> v3:
>>  - Use include way of testing static functions (Arthur)
>>
>> Signed-off-by: Harry Wentland 
>> Cc: Arthur Grillo 
>> ---
>>  drivers/gpu/drm/vkms/Kconfig  |   5 +
>>  drivers/gpu/drm/vkms/tests/.kunitconfig   |   4 +
>>  drivers/gpu/drm/vkms/tests/vkms_color_tests.c | 163 ++
>>  drivers/gpu/drm/vkms/vkms_composer.c  |   8 +-
>>  4 files changed, 178 insertions(+), 2 deletions(-)
>>  create mode 100644 drivers/gpu/drm/vkms/tests/.kunitconfig
>>  create mode 100644 drivers/gpu/drm/vkms/tests/vkms_color_tests.c
>>
>> diff --git a/drivers/gpu/drm/vkms/Kconfig b/drivers/gpu/drm/vkms/Kconfig
>> index b9ecdebecb0b..c1f8b343ff0e 100644
>> --- a/drivers/gpu/drm/vkms/Kconfig
>> +++ b/drivers/gpu/drm/vkms/Kconfig
>> @@ -13,3 +13,8 @@ config DRM_VKMS
>>a VKMS.
>>  
>>If M is selected the module will be called vkms.
>> +
>> +config DRM_VKMS_KUNIT_TESTS
>> +tristate "Tests for VKMS" if !KUNIT_ALL_TESTS
>> +depends on DRM_VKMS && KUNIT
>> +default KUNIT_ALL_TESTS
>> diff --git a/drivers/gpu/drm/vkms/tests/.kunitconfig 
>> b/drivers/gpu/drm/vkms/tests/.kunitconfig
>> new file mode 100644
>> index ..70e378228cbd
>> --- /dev/null
>> +++ b/drivers/gpu/drm/vkms/tests/.kunitconfig
>> @@ -0,0 +1,4 @@
>> +CONFIG_KUNIT=y
>> +CONFIG_DRM=y
>> +CONFIG_DRM_VKMS=y
>> +CONFIG_DRM_VKMS_KUNIT_TESTS=y
>> diff --git a/drivers/gpu/drm/vkms/tests/vkms_color_tests.c 
>> b/drivers/gpu/drm/vkms/tests/vkms_color_tests.c
>> new file mode 100644
>> index ..fc73e48aa57c
>> --- /dev/null
>> +++ b/drivers/gpu/drm/vkms/tests/vkms_color_tests.c
>> @@ -0,0 +1,163 @@
>> +/* SPDX-License-Identifier: GPL-2.0+ */
>> +
>> +#include 
>> +
>> +#include 
>> +
>> +#define TEST_LUT_SIZE 16
>> +
>> +static struct drm_color_lut test_linear_array[TEST_LUT_SIZE] = {
>> +{ 0x0, 0x0, 0x0, 0 },
>> +{ 0x, 0x, 0x, 0 },
>> +{ 0x, 0x, 0x, 0 },
>> +{ 0x, 0x, 0x, 0 },
>> +{ 0x, 0x, 0x, 0 },
>> +{ 0x, 0x, 0x, 0 },
>> +{ 0x, 0x, 0x, 0 },
>> +{ 0x, 0x, 0x, 0 },
>> +{ 0x, 0x, 0x, 0 },
>> +{ 0x, 0x, 0x, 0 },
>> +{ 0x, 0x, 0x, 0 },
>> +{ 0x, 0x, 0x, 0 },
>> +{ 0x, 0x, 0x, 0 },
>> +{ 0x, 0x, 0x, 0 },
>> +{ 0x, 0x, 0x, 0 },
>> +{ 0x, 0x, 0x, 0 },
>> +};
>> +
>> +const struct vkms_color_lut test_linear_lut = {
>> +.base = test_linear_array,
>> +.lut_length = TEST_LUT_SIZE,
>> +.channel_value2index_ratio = 0xf000fll
>> +};
>> +
>> +
>> +static void vkms_color_test_get_lut_index(struct kunit *test)
>> +{
>> +int i;
>> +
>> +KUNIT_EXPECT_EQ(test, drm_fixp2int(get_lut_index(_linear_lut, 
>> test_linear_array[0].red)), 0);
>> +
>> +for (i = 0; i < TEST_LUT_SIZE; i++)
>> +KUNIT_EXPECT_EQ(test, 
>> drm_fixp2int_ceil(get_lut_index(_linear_lut, 
>> test_linear_array[i].red)), i);
>> +}
>> +
>> +static void vkms_color_test_lerp(struct kunit *test)
>> +{
>> +/*** half-way round down ***/
>> +s64 t = 0x8000 - 1;
>> +KUNIT_EXPECT_EQ(test, lerp_u16(0x0, 0x10, t), 0x8);
>> +
>> +/* odd a */
>> +KUNIT_EXPECT_EQ(test, lerp_u16(0x1, 0x10, t), 0x8);
>> +
>> +/* odd b */
>> +KUNIT_EXPECT_EQ(test, lerp_u16(0x1, 0xf, t), 0x8);
>> +
>> +/* b = a */
>> +KUNIT_EXPECT_EQ(test, lerp_u16(0x10, 0x10, t), 0x10);
>> +
>> +/* b = a + 1 */
>> +KUNIT_EXPECT_EQ(test, lerp_u16(0x10, 0x11, t), 0x10);
>> +
>> +
>> +/*** half-way round up ***/
>> +t = 0x8000;
>> +KUNIT_EXPECT_EQ(test, lerp_u16(0x0, 0x10, t), 0x8);
>> +
>> +/* odd a */
>> +KUNIT_EXPECT_EQ(test, lerp_u16(0x1, 0x10, t), 0x9);
>> +
>> +/* odd b */
>> +KUNIT_EXPECT_EQ(test, lerp_u16(0x1, 0xf, t), 0x8);
>&

Re: [RFC PATCH v4 00/42] Color Pipeline API w/ VKMS

2024-02-27 Thread Harry Wentland



On 2024-02-27 05:26, Joshua Ashton wrote:
> 
> 
> On 2/26/24 21:10, Harry Wentland wrote:
>> This is an RFC set for a color pipeline API, along with a sample
>> implementation in VKMS. All the key API bits are here. VKMS now
>> supports two named transfer function colorops and two matrix
>> colorops. We have IGT tests that check all four of these colorops
>> with a pixel-by-pixel comparison that checks that these colorops
>> do what we expect them to do with a +/- 1 8 bpc code point margin.
>>
>> The big new change with v4 is the addition of an amdgpu color
>> pipeline, for all AMD GPUs with DCN 3 and newer. Amdgpu now support
>> the following:
>>
>> 1. 1D Curve EOTF
>> 2. 3x4 CTM
>> 3. Multiplier
>> 4. 1D Curve Inverse EOTF
>> 5. 1D LUT
>> 6. 1D Curve EOTF
>> 7. 1D LUT
>>
>> The supported curves for the 1D Curve type are:
>> - sRGB EOTF and its inverse
>> - PQ EOTF, scaled to [0.0, 125.0] and its inverse
>> - BT.2020/BT.709 OETF and its inverse
>>
>> Note that the 1st and 5th colorops take the EOTF or Inverse
>> OETF while the 3rd colorop takes the Inverse EOTF or OETF.
>>
>> We are working on two more ops for amdgpu, the HDR multiplier
>> and the 3DLUT, which will give us this:
>>
>> 1. 1D Curve EOTF
>> 2. 3x4 CTM
>> 3. HDR Multiplier
>> 4. 1D Curve Inverse EOTF
>> 5. 1D LUT
>> 6. 3D LUT
>> 7. 1D Curve EOTF
>> 8. 1D LUT
>>
>> This, essentially mirrors the color pipeline used by gamescope
>> and presented by Melissa Wen, with the exception of the DEGAM
>> LUT, which is not currently used. See
>> [1] 
>> https://indico.freedesktop.org/event/4/contributions/186/attachments/138/218/xdc2023-TheRainbowTreasureMap-MelissaWen.pdf
>>
>> After this we'd like to also add the following ops:
>> - Scaler (Informational only)
> 
> Why informational only? Having NEAREST and in general custom taps should be 
> possible on AMDGPU right?
> 
> We don't have to solve this now, but I just want to make sure that we aren't 
> locking this to info only.
> 

No, this isn't locking it to information only. We could allow for NEAREST or
even custom taps in the future. Just don't want to open that debate now if
we don't have a good reason to.

Harry

> Thanks
> 
> - Joshie ✨
> 
>> - Color Encoding, to replace drm_plane's COLOR_ENCODING
>> - Color Range, to replace drm_plane's COLOR_RANGE
>>
>> This patchset is grouped as follows:
>>   - Patches 1-3: couple general patches/fixes
>>   - Patches 4-7: introduce kunit to VKMS
>>   - Patch 7: description of motivation and details behind the
>>  Color Pipeline API. If you're reading nothing else
>>  but are interested in the topic I highly recommend
>>  you take a look at this.
>>   - Patches 7-27: DRM core and VKMS changes for color pipeline API
>>   - Patches 28-40: DRM core and amdgpu changes for color pipeline API
>>
>> VKMS patches could still be improved in a few ways, though the
>> payoff might be limited and I would rather focus on other work
>> at the moment. The most obvious thing to improve would be to
>> eliminate the hard-coded LUTs for identity, and sRGB, and replace
>> them with fixed-point math instead.
>>
>> There are plenty of things that I would like to see here but
>> haven't had a chance to look at. These will (hopefully) be
>> addressed in future iterations, either in VKMS or amdgpu:
>>   - Clear documentation for each drm_colorop_type
>>   - Add custom LUT colorops to VKMS
>>   - Add pre-blending 3DLUT
>>   - How to support HW which can't bypass entire pipeline?
>>   - Add ability to create colorops that don't have BYPASS
>>   - Can we do a LOAD / COMMIT model for LUTs (and other properties)?
>>   - read-only scaling colorop which defines scaling taps and position
>>   - read-only color format colorop to define supported color formats
>>     for a pipeline
>>   - named matrices, for things like converting YUV to RGB
>>
>> IGT tests can be found at
>> https://gitlab.freedesktop.org/hwentland/igt-gpu-tools/-/merge_requests/1
>>
>> IGT patches are also being sent to the igt-dev mailing list.
>>
>> If you prefer a gitlab MR for review you can find it at
>> https://gitlab.freedesktop.org/hwentland/linux/-/merge_requests/5
>>
>> v4:
>>   - Add amdgpu color pipeline (WIP)
>>   - Don't block setting of deprecated properties, instead pass client cap
>>     to atomic check so drivers can ignore these props
>>   - Drop IOCTL definitions (Pekka)
>&

[RFC PATCH v4 32/42] drm/amd/display: Add support for sRGB Inverse EOTF in SHAPER block

2024-02-26 Thread Harry Wentland
From: Alex Hung 

Expose a 2nd curve colorop with support for
DRM_COLOROP_1D_CURVE_SRGB_INV_EOTF and program HW to
perform the sRGB Inverse EOTF on the shaper block
when the colorop is not in bypass.

With this change the follow IGT tests pass:
kms_colorop --run plane-XR30-XR30-srgb_inv_eotf
kms_colorop --run plane-XR30-XR30-srgb_eotf-srgb_inv_eotf

The color pipeline now consists of the following colorops:
1. 1D curve colorop w/ sRGB EOTF support
2. 1D curve colorop w/ sRGB Inverse EOTF support

Signed-off-by: Alex Hung 
Signed-off-by: Harry Wentland 
Co-developed-by: Harry Wentland 
---
 .../amd/display/amdgpu_dm/amdgpu_dm_color.c   | 76 +++
 .../amd/display/amdgpu_dm/amdgpu_dm_colorop.c | 20 -
 .../amd/display/amdgpu_dm/amdgpu_dm_colorop.h |  1 +
 3 files changed, 96 insertions(+), 1 deletion(-)

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 3ec759934669..8788cfd26abd 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
@@ -1203,6 +1203,70 @@ __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;
+   const struct drm_color_lut *shaper_lut;
+   uint32_t shaper_size;
+
+   if (colorop->type != DRM_COLOROP_1D_CURVE &&
+   colorop_state->curve_1d_type != DRM_COLOROP_1D_CURVE_SRGB_INV_EOTF)
+   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, shaper_lut, shaper_size, false);
+   }
+
+   return -EINVAL;
+}
+
+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 *old_colorop;
+   struct drm_colorop_state *colorop_state = NULL, *new_colorop_state;
+   struct drm_atomic_state *state = plane_state->state;
+   int i = 0;
+
+   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 &&
+   new_colorop_state->curve_1d_type == 
DRM_COLOROP_1D_CURVE_SRGB_INV_EOTF) {
+   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
 amdgpu_dm_plane_set_color_properties(struct drm_plane_state *plane_state,
 struct dc_plane_state *dc_plane_state)
@@ -1258,6 +1322,7 @@ amdgpu_dm_plane_set_colorop_properties(struct 
drm_plane_state *plane_state,
   struct dc_plane_state *dc_plane_state)
 {
struct drm_colorop *colorop = plane_state->color_pipeline;
+   struct drm_device *dev = plane_state->plane->dev;
int ret;
 
/* 1D Curve - DEGAM TF */
@@ -1269,6 +1334,17 @@ amdgpu_dm_plane_set_colorop_properties(struct 
drm_plane_state *plane_state,
if (ret)
return ret;
 
+   /* 1D Curve - SHAPER TF */
+   colorop = colorop->next;
+   if (!colorop) {
+   drm_dbg(dev, "no Shaper TF colorop found\n");
+   return -EINVAL;
+   }
+
+   ret = __set_dm_plane_colorop_shaper(plane_state, dc_plane_state, 
colorop);
+   if (ret)
+   return ret;
+
return 0;
 }
 
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_colorop.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_colorop.c
index e8b7fc8bb0f1..0d1626abf577 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_c

[RFC PATCH v4 31/42] drm/amd/display: Add support for sRGB EOTF in DEGAM block

2024-02-26 Thread Harry Wentland
From: Alex Hung 

Expose one 1D curve colorop with support for
DRM_COLOROP_1D_CURVE_SRGB_EOTF and program HW to perform
the sRGB transform when the colorop is not in bypass.

With this change the following IGT test passes:
kms_colorop --run plane-XR30-XR30-srgb_eotf

The color pipeline now consists of a single colorop:
1. 1D curve colorop w/ sRGB EOTF

Signed-off-by: Alex Hung 
Signed-off-by: Harry Wentland 
Co-developed-by: Harry Wentland 
---
 .../gpu/drm/amd/display/amdgpu_dm/Makefile|  3 +-
 .../amd/display/amdgpu_dm/amdgpu_dm_color.c   | 88 +++
 .../amd/display/amdgpu_dm/amdgpu_dm_colorop.c | 58 
 .../amd/display/amdgpu_dm/amdgpu_dm_colorop.h | 34 +++
 .../amd/display/amdgpu_dm/amdgpu_dm_plane.c   | 10 +++
 5 files changed, 192 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_colorop.c
 create mode 100644 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_colorop.h

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile 
b/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile
index ab2a97e354da..46158d67ab12 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile
@@ -38,7 +38,8 @@ AMDGPUDM = \
amdgpu_dm_pp_smu.o \
amdgpu_dm_psr.o \
amdgpu_dm_replay.o \
-   amdgpu_dm_wb.o
+   amdgpu_dm_wb.o \
+   amdgpu_dm_colorop.o
 
 ifdef CONFIG_DRM_AMD_DC_FP
 AMDGPUDM += dc_fpu.o
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 9b527bffe11a..3ec759934669 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
@@ -668,6 +668,19 @@ amdgpu_tf_to_dc_tf(enum amdgpu_transfer_function tf)
}
 }
 
+static enum dc_transfer_func_predefined
+amdgpu_colorop_tf_to_dc_tf(enum drm_colorop_curve_1d_type tf)
+{
+   switch (tf)
+   {
+   case DRM_COLOROP_1D_CURVE_SRGB_EOTF:
+   case DRM_COLOROP_1D_CURVE_SRGB_INV_EOTF:
+   return TRANSFER_FUNCTION_SRGB;
+   default:
+   return TRANSFER_FUNCTION_LINEAR;;
+   }
+}
+
 static void __to_dc_lut3d_color(struct dc_rgb *rgb,
const struct drm_color_lut lut,
int bit_precision)
@@ -1137,6 +1150,59 @@ __set_dm_plane_degamma(struct drm_plane_state 
*plane_state,
return 0;
 }
 
+static int
+__set_colorop_in_tf_1d_curve(struct dc_plane_state *dc_plane_state,
+  struct drm_colorop_state *colorop_state)
+{
+   struct dc_transfer_func *tf = dc_plane_state->in_transfer_func;
+   struct drm_colorop *colorop = colorop_state->colorop;
+   struct drm_device *drm = colorop->dev;
+
+   if (colorop->type != DRM_COLOROP_1D_CURVE &&
+   colorop_state->curve_1d_type != DRM_COLOROP_1D_CURVE_SRGB_EOTF)
+   return -EINVAL;
+
+   if (colorop_state->bypass) {
+   tf->type = TF_TYPE_BYPASS;
+   tf->tf = TRANSFER_FUNCTION_LINEAR;
+   return 0;
+   }
+
+   drm_dbg(drm, "Degamma colorop with ID: %d\n", colorop->base.id);
+
+   tf->type = TF_TYPE_PREDEFINED;
+   tf->tf = amdgpu_colorop_tf_to_dc_tf(colorop_state->curve_1d_type);
+
+   return 0;
+}
+
+static int
+__set_dm_plane_colorop_degamma(struct drm_plane_state *plane_state,
+  struct dc_plane_state *dc_plane_state,
+  struct drm_colorop *colorop)
+{
+   struct drm_colorop *old_colorop;
+   struct drm_colorop_state *colorop_state = NULL, *new_colorop_state;
+   struct drm_atomic_state *state = plane_state->state;
+   int i = 0;
+
+   old_colorop = colorop;
+
+   /* 1st op: 1d curve - degamma */
+   for_each_new_colorop_in_state(state, colorop, new_colorop_state, i) {
+   if (new_colorop_state->colorop == old_colorop &&
+   new_colorop_state->curve_1d_type == 
DRM_COLOROP_1D_CURVE_SRGB_EOTF) {
+   colorop_state = new_colorop_state;
+   break;
+   }
+   }
+
+   if (!colorop_state)
+   return -EINVAL;
+
+   return __set_colorop_in_tf_1d_curve(dc_plane_state, colorop_state);
+}
+
 static int
 amdgpu_dm_plane_set_color_properties(struct drm_plane_state *plane_state,
 struct dc_plane_state *dc_plane_state)
@@ -1187,6 +1253,25 @@ amdgpu_dm_plane_set_color_properties(struct 
drm_plane_state *plane_state,
return 0;
 }
 
+static int
+amdgpu_dm_plane_set_colorop_properties(struct drm_plane_state *plane_state,
+  struct dc_plane_state *dc_plane_state)
+{
+   struct drm_colorop *colorop = plane_state->color_pipeline;
+   int ret;
+
+   /* 1D Curve - DEGAM TF */
+

[RFC PATCH v4 41/42] drm/colorop: Add mutliplier type

2024-02-26 Thread Harry Wentland
From: Alex Hung 

This introduces a new drm_colorop_type: DRM_COLOROP_MULTIPLIER.

It's a simple multiplier to all pixel values. The value is
specified via a S31.32 fixed point provided via the
"MULTIPLIER" property.

Signed-off-by: Alex Hung 
---
 drivers/gpu/drm/drm_atomic.c  |  3 +++
 drivers/gpu/drm/drm_atomic_uapi.c |  4 
 drivers/gpu/drm/drm_colorop.c | 29 +++--
 include/drm/drm_colorop.h | 16 
 include/uapi/drm/drm_mode.h   |  1 +
 5 files changed, 51 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index f7d51839ca03..af0b6338a55c 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -806,6 +806,9 @@ static void drm_atomic_colorop_print_state(struct 
drm_printer *p,
case DRM_COLOROP_CTM_3X4:
drm_printf(p, "\tdata blob id=%d\n", state->data ? 
state->data->base.id : 0);
break;
+   case DRM_COLOROP_MULTIPLIER:
+   drm_printf(p, "\tmultiplier=%u\n", state->multiplier);
+   break;
default:
break;
}
diff --git a/drivers/gpu/drm/drm_atomic_uapi.c 
b/drivers/gpu/drm/drm_atomic_uapi.c
index 6bfe857720cd..b4ecda563728 100644
--- a/drivers/gpu/drm/drm_atomic_uapi.c
+++ b/drivers/gpu/drm/drm_atomic_uapi.c
@@ -727,6 +727,8 @@ static int drm_atomic_colorop_set_property(struct 
drm_colorop *colorop,
state->bypass = val;
} else if (property == colorop->curve_1d_type_property) {
state->curve_1d_type = val;
+   } else if (property == colorop->multiplier_property) {
+   state->multiplier = val;
} else if (property == colorop->data_property) {
return drm_atomic_color_set_data_property(colorop,
state, property, val);
@@ -752,6 +754,8 @@ drm_atomic_colorop_get_property(struct drm_colorop *colorop,
*val = state->bypass;
} else if (property == colorop->curve_1d_type_property) {
*val = state->curve_1d_type;
+   } else if (property == colorop->multiplier_property) {
+   *val = state->multiplier;
} else if (property == colorop->size_property) {
*val = state->size;
} else if (property == colorop->data_property) {
diff --git a/drivers/gpu/drm/drm_colorop.c b/drivers/gpu/drm/drm_colorop.c
index 4452eaeeb242..c6cdd743de51 100644
--- a/drivers/gpu/drm/drm_colorop.c
+++ b/drivers/gpu/drm/drm_colorop.c
@@ -35,7 +35,8 @@
 static const struct drm_prop_enum_list drm_colorop_type_enum_list[] = {
{ DRM_COLOROP_1D_CURVE, "1D Curve" },
{ DRM_COLOROP_1D_LUT, "1D Curve Custom LUT" },
-   { DRM_COLOROP_CTM_3X4, "3x4 Matrix"}
+   { DRM_COLOROP_CTM_3X4, "3x4 Matrix"},
+   { DRM_COLOROP_MULTIPLIER, "Multiplier"},
 };
 
 static const char * const colorop_curve_1d_type_names[] = {
@@ -231,6 +232,29 @@ int drm_colorop_ctm_3x4_init(struct drm_device *dev, 
struct drm_colorop *colorop
 }
 EXPORT_SYMBOL(drm_colorop_ctm_3x4_init);
 
+int drm_colorop_mult_init(struct drm_device *dev, struct drm_colorop *colorop,
+ struct drm_plane *plane)
+{
+   struct drm_property *prop;
+   int ret;
+
+   ret = drm_colorop_init(dev, colorop, plane, DRM_COLOROP_MULTIPLIER);
+   if (ret)
+   return ret;
+
+   prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, 
"MULTIPLIER", 0, U64_MAX);
+   if (!prop)
+   return -ENOMEM;
+
+   colorop->multiplier_property = prop;
+   drm_object_attach_property(>base, 
colorop->multiplier_property, 0);
+
+   drm_colorop_reset(colorop);
+
+   return 0;
+}
+EXPORT_SYMBOL(drm_colorop_mult_init);
+
 static void __drm_atomic_helper_colorop_duplicate_state(struct drm_colorop 
*colorop,
struct 
drm_colorop_state *state)
 {
@@ -333,7 +357,8 @@ EXPORT_SYMBOL(drm_colorop_reset);
 static const char * const colorop_type_name[] = {
[DRM_COLOROP_1D_CURVE] = "1D Curve",
[DRM_COLOROP_1D_LUT] = "1D Curve Custom LUT",
-   [DRM_COLOROP_CTM_3X4] = "3x4 Matrix"
+   [DRM_COLOROP_CTM_3X4] = "3x4 Matrix",
+   [DRM_COLOROP_MULTIPLIER] = "Multiplier",
 };
 
 /**
diff --git a/include/drm/drm_colorop.h b/include/drm/drm_colorop.h
index 8adc7ece3bd1..f9f83644cc9f 100644
--- a/include/drm/drm_colorop.h
+++ b/include/drm/drm_colorop.h
@@ -64,6 +64,13 @@ struct drm_colorop_state {
 */
enum drm_colorop_curve_1d_type curve_1d_type;
 
+   /**
+* @multiplier:
+*
+* Multiplier to 'gain' the plane. Format is S31.32 sign-magnitude.
+*/
+   uint64_t multiplier;
+
/**
 * @size:
 *
@@ -186,6 +193,13 @@ struct drm_colorop {
 */
struct drm_property *curve_1d_type_property;
 
+   /**
+* @multiplier_property:
+*

[RFC PATCH v4 40/42] drm/amd/display: add 3x4 matrix colorop

2024-02-26 Thread Harry Wentland
From: Alex Hung 

This adds support for a 3x4 color transformation matrix.

With this change the following IGT tests pass:
kms_colorop --run plane-XR30-XR30-ctm_3x4_50_desat
kms_colorop --run plane-XR30-XR30-ctm_3x4_overdrive
kms_colorop --run plane-XR30-XR30-ctm_3x4_oversaturate
kms_colorop --run plane-XR30-XR30-ctm_3x4_bt709_enc
kms_colorop --run plane-XR30-XR30-ctm_3x4_bt709_dec

The color pipeline now consists of the following colorops:
1. 1D curve colorop
2. 3x4 CTM
3. 1D curve colorop
4. 1D LUT
5. 1D curve colorop
6. 1D LUT

Signed-off-by: Alex Hung 
Signed-off-by: Harry Wentland 
---
 .../amd/display/amdgpu_dm/amdgpu_dm_color.c   | 50 +++
 .../amd/display/amdgpu_dm/amdgpu_dm_colorop.c | 15 ++
 2 files changed, 65 insertions(+)

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 e7b51b29cc04..ef50640b362b 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
@@ -1212,6 +1212,45 @@ __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_dm_plane_colorop_3x4_matrix(struct drm_plane_state *plane_state,
+ struct dc_plane_state *dc_plane_state,
+ struct drm_colorop *colorop)
+{
+   struct drm_colorop *old_colorop;
+   struct drm_colorop_state *colorop_state = NULL, *new_colorop_state;
+   struct drm_atomic_state *state = plane_state->state;
+   const struct drm_device *dev = colorop->dev;
+   const struct drm_property_blob *blob;
+   struct drm_color_ctm_3x4 *ctm = NULL;
+   int i = 0;
+
+   /* 3x4 matrix */
+   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_CTM_3X4) {
+   colorop_state = new_colorop_state;
+   break;
+   }
+   }
+
+   if (colorop_state && !colorop_state->bypass && colorop->type == 
DRM_COLOROP_CTM_3X4) {
+   drm_dbg(dev, "3x4 matrix colorop with ID: %d\n", 
colorop->base.id);
+   blob = colorop_state->data;
+   if (blob->length == sizeof(struct drm_color_ctm_3x4)) {
+   ctm = blob ? (struct drm_color_ctm_3x4 *) blob->data : 
NULL;
+   __drm_ctm_3x4_to_dc_matrix(ctm, 
dc_plane_state->gamut_remap_matrix.matrix);
+   dc_plane_state->gamut_remap_matrix.enable_remap = true;
+   
dc_plane_state->input_csc_color_matrix.enable_adjustment = false;
+   } else
+   drm_warn(dev, "blob->length (%ld) isn't equal to 
drm_color_ctm_3x4 (%ld)\n",
+blob->length, sizeof(struct 
drm_color_ctm_3x4));
+   }
+
+   return 0;
+}
+
 static int
 __set_dm_plane_colorop_shaper(struct drm_plane_state *plane_state,
  struct dc_plane_state *dc_plane_state,
@@ -1411,6 +1450,17 @@ amdgpu_dm_plane_set_colorop_properties(struct 
drm_plane_state *plane_state,
if (ret)
return ret;
 
+   /* 3x4 matrix */
+   colorop = colorop->next;
+   if (!colorop) {
+   drm_dbg(dev, "no 3x4 matrix colorop found\n");
+   return -EINVAL;
+   }
+
+   ret = __set_dm_plane_colorop_3x4_matrix(plane_state, dc_plane_state, 
colorop);
+   if (ret)
+   return ret;
+
/* 1D Curve & LUT - SHAPER TF & LUT */
colorop = colorop->next;
if (!colorop) {
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_colorop.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_colorop.c
index 08480bf61dc5..ba42f1f6b620 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_colorop.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_colorop.c
@@ -69,6 +69,21 @@ int amdgpu_dm_initialize_default_pipeline(struct drm_plane 
*plane, struct drm_pr
 
prev_op = op;
 
+   /* 3x4 matrix */
+   op = kzalloc(sizeof(struct drm_colorop), GFP_KERNEL);
+   if (!op) {
+   DRM_ERROR("KMS: Failed to allocate colorop\n");
+   return -ENOMEM;
+   }
+
+   ret = drm_colorop_ctm_3x4_init(dev, op, plane);
+   if (ret)
+   return ret;
+
+   drm_colorop_set_next_property(prev_op, op);
+
+   prev_op = op;
+
/* 1D curve - SHAPER TF */
op = kzalloc(sizeof(struct drm_colorop), GFP_KERNEL);
if (!op) {
-- 
2.44.0



[RFC PATCH v4 33/42] drm/amd/display: Add support for sRGB EOTF in BLND block

2024-02-26 Thread Harry Wentland
From: Alex Hung 

Expose a 3rd 1D curve colorop, with support for
DRM_COLOROP_1D_CURVE_SRGB_EOTF and program the BLND block
to perform the sRGB transform when the colorop is not in
bypass

With this change the following IGT test passes:
kms_colorop --run plane-XR30-XR30-srgb_eotf-srgb_inv_eotf-srgb_eotf

The color pipeline now consists of the following colorops:
1. 1D curve colorop w/ sRGB EOTF support
2. 1D curve colorop w/ sRGB Inverse EOTF support
3. 1D curve colorop w/ sRGB EOTF support

Signed-off-by: Alex Hung 
Signed-off-by: Harry Wentland 
Co-developed-by: Harry Wentland 
---
 .../amd/display/amdgpu_dm/amdgpu_dm_color.c   | 77 +++
 .../amd/display/amdgpu_dm/amdgpu_dm_colorop.c | 18 +
 .../amd/display/amdgpu_dm/amdgpu_dm_colorop.h |  1 +
 3 files changed, 96 insertions(+)

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 8788cfd26abd..3e3ae2b58b06 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
@@ -1267,6 +1267,72 @@ __set_dm_plane_colorop_shaper(struct drm_plane_state 
*plane_state,
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;
+
+   if (colorop->type != DRM_COLOROP_1D_CURVE &&
+   colorop_state->curve_1d_type != DRM_COLOROP_1D_CURVE_SRGB_EOTF)
+   return -EINVAL;
+
+   if (colorop_state->bypass) {
+   tf->type = TF_TYPE_BYPASS;
+   tf->tf = TRANSFER_FUNCTION_LINEAR;
+   return 0;
+   }
+
+   drm_dbg(drm, "Blend 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_input_tf(NULL, tf, blend_lut, blend_size);
+   }
+
+   return -EINVAL;
+}
+
+static int
+__set_dm_plane_colorop_blend(struct drm_plane_state *plane_state,
+struct dc_plane_state *dc_plane_state,
+struct drm_colorop *colorop)
+{
+   struct drm_colorop *old_colorop;
+   struct drm_colorop_state *colorop_state = NULL, *new_colorop_state;
+   struct drm_atomic_state *state = plane_state->state;
+   int i = 0;
+
+   old_colorop = colorop;
+
+   /* 3nd op: 1d curve - blend */
+   for_each_new_colorop_in_state(state, colorop, new_colorop_state, i) {
+   if (new_colorop_state->colorop == old_colorop &&
+   new_colorop_state->curve_1d_type == 
DRM_COLOROP_1D_CURVE_SRGB_EOTF) {
+   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_1d_curve_blend_tf_lut(dc_plane_state, 
colorop_state);
+}
+
 static int
 amdgpu_dm_plane_set_color_properties(struct drm_plane_state *plane_state,
 struct dc_plane_state *dc_plane_state)
@@ -1345,6 +1411,17 @@ amdgpu_dm_plane_set_colorop_properties(struct 
drm_plane_state *plane_state,
if (ret)
return ret;
 
+   /* 1D Curve - BLND TF */
+   colorop = colorop->next;
+   if (!colorop) {
+   drm_dbg(dev, "no Blend TF colorop found\n");
+   return -EINVAL;
+   }
+
+   ret = __set_dm_plane_colorop_blend(plane_state, dc_plane_state, 
colorop);
+   if (ret)
+   return ret;
+
return 0;
 }
 
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_colorop.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_colorop.c
index 0d1626abf577..449a2ad6a184 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_colorop.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_colorop.c
@@ -37,6 +37,9 @@ const u64 amdgpu_dm_supported_degam_tfs =
  const u64 amdgpu_dm_supported_shaper_tfs =
BIT(DRM_COLOROP_1D_CURVE_SRGB_INV_EOTF);
 
+const u64 amdgpu_dm_supported_blnd_tfs =
+   BIT(DRM_COLOROP_1D_CURVE_SRGB_EOTF);
+
 int amdgpu_dm_initialize_default_pipeline(struct drm_plane *p

[RFC PATCH v4 42/42] drm/amd/display: add multiplier colorop

2024-02-26 Thread Harry Wentland
From: Alex Hung 

This adds support for a multiplier. This multiplier is
programmed via the HDR Multiplier in DCN.

With this change the following IGT tests pass:
kms_colorop --run plane-XR30-XR30-multiply_125
kms_colorop --run plane-XR30-XR30-multiply_inv_125

The color pipeline now consists of the following colorops:
1. 1D curve colorop
2. 3x4 CTM
3. Multiplier
4. 1D curve colorop
5. 1D LUT
6. 1D curve colorop
7. 1D LUT

Signed-off-by: Alex Hung 
---
 .../amd/display/amdgpu_dm/amdgpu_dm_color.c   | 40 +++
 .../amd/display/amdgpu_dm/amdgpu_dm_colorop.c | 15 +++
 2 files changed, 55 insertions(+)

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 ef50640b362b..b05e4fea8a08 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
@@ -1251,6 +1251,35 @@ __set_dm_plane_colorop_3x4_matrix(struct drm_plane_state 
*plane_state,
return 0;
 }
 
+static int
+__set_dm_plane_colorop_multiplier(struct drm_plane_state *plane_state,
+ struct dc_plane_state *dc_plane_state,
+ struct drm_colorop *colorop)
+{
+   struct drm_colorop *old_colorop;
+   struct drm_colorop_state *colorop_state = NULL, *new_colorop_state;
+   struct drm_atomic_state *state = plane_state->state;
+   const struct drm_device *dev = colorop->dev;
+   int i = 0;
+
+   /* Multiplier */
+   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_MULTIPLIER) 
{
+   colorop_state = new_colorop_state;
+   break;
+   }
+   }
+
+   if (colorop_state && !colorop_state->bypass && colorop->type == 
DRM_COLOROP_MULTIPLIER) {
+   drm_dbg(dev, "Multiplier colorop with ID: %d\n", 
colorop->base.id);
+   dc_plane_state->hdr_mult = 
amdgpu_dm_fixpt_from_s3132(colorop_state->multiplier);
+   }
+
+   return 0;
+}
+
 static int
 __set_dm_plane_colorop_shaper(struct drm_plane_state *plane_state,
  struct dc_plane_state *dc_plane_state,
@@ -1461,6 +1490,17 @@ amdgpu_dm_plane_set_colorop_properties(struct 
drm_plane_state *plane_state,
if (ret)
return ret;
 
+   /* Multiplier */
+   colorop = colorop->next;
+   if (!colorop) {
+   drm_dbg(dev, "no multiplier colorop found\n");
+   return -EINVAL;
+   }
+
+   ret = __set_dm_plane_colorop_multiplier(plane_state, dc_plane_state, 
colorop);
+   if (ret)
+   return ret;
+
/* 1D Curve & LUT - SHAPER TF & LUT */
colorop = colorop->next;
if (!colorop) {
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_colorop.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_colorop.c
index ba42f1f6b620..b739d6cb3e6b 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_colorop.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_colorop.c
@@ -84,6 +84,21 @@ int amdgpu_dm_initialize_default_pipeline(struct drm_plane 
*plane, struct drm_pr
 
prev_op = op;
 
+   /* Multiplier */
+   op = kzalloc(sizeof(struct drm_colorop), GFP_KERNEL);
+   if (!op) {
+   DRM_ERROR("KMS: Failed to allocate colorop\n");
+   return -ENOMEM;
+   }
+
+   ret = drm_colorop_mult_init(dev, op, plane);
+   if (ret)
+   return ret;
+
+   drm_colorop_set_next_property(prev_op, op);
+
+   prev_op = op;
+
/* 1D curve - SHAPER TF */
op = kzalloc(sizeof(struct drm_colorop), GFP_KERNEL);
if (!op) {
-- 
2.44.0



[RFC PATCH v4 08/42] drm/doc/rfc: Describe why prescriptive color pipeline is needed

2024-02-26 Thread Harry Wentland
v4:
 - Drop IOCTL docs since we dropped the IOCTLs (Pekka)
 - Clarify reading and setting of COLOR_PIPELINE prop (Pekka)
 - Add blurb about not requiring to reject a pipeline due to
   incompatible ops, as long as op can be bypassed (Pekka)
 - Dropped informational strings (such as input CSC) as they're
   not actually intended to be advertised (Pekka)

v3:
 - Describe DRM_CLIENT_CAP_PLANE_COLOR_PIPELINE (Sebastian)
 - Ask for clear documentation of colorop behavior (Sebastian)

v2:
 - Update colorop visualizations to match reality (Sebastian, Alex Hung)
 - Updated wording (Pekka)
 - Change BYPASS wording to make it non-mandatory (Sebastian)
 - Drop cover-letter-like paragraph from COLOR_PIPELINE Plane Property
   section (Pekka)
 - Use PQ EOTF instead of its inverse in Pipeline Programming example (Melissa)
 - Add "Driver Implementer's Guide" section (Pekka)
 - Add "Driver Forward/Backward Compatibility" section (Sebastian, Pekka)

Signed-off-by: Harry Wentland 
---
 Documentation/gpu/rfc/color_pipeline.rst | 360 +++
 1 file changed, 360 insertions(+)
 create mode 100644 Documentation/gpu/rfc/color_pipeline.rst

diff --git a/Documentation/gpu/rfc/color_pipeline.rst 
b/Documentation/gpu/rfc/color_pipeline.rst
new file mode 100644
index ..6c653e17054a
--- /dev/null
+++ b/Documentation/gpu/rfc/color_pipeline.rst
@@ -0,0 +1,360 @@
+
+Linux Color Pipeline API
+
+
+What problem are we solving?
+
+
+We would like to support pre-, and post-blending complex color
+transformations in display controller hardware in order to allow for
+HW-supported HDR use-cases, as well as to provide support to
+color-managed applications, such as video or image editors.
+
+It is possible to support an HDR output on HW supporting the Colorspace
+and HDR Metadata drm_connector properties, but that requires the
+compositor or application to render and compose the content into one
+final buffer intended for display. Doing so is costly.
+
+Most modern display HW offers various 1D LUTs, 3D LUTs, matrices, and other
+operations to support color transformations. These operations are often
+implemented in fixed-function HW and therefore much more power efficient than
+performing similar operations via shaders or CPU.
+
+We would like to make use of this HW functionality to support complex color
+transformations with no, or minimal CPU or shader load.
+
+
+How are other OSes solving this problem?
+
+
+The most widely supported use-cases regard HDR content, whether video or
+gaming.
+
+Most OSes will specify the source content format (color gamut, encoding 
transfer
+function, and other metadata, such as max and average light levels) to a 
driver.
+Drivers will then program their fixed-function HW accordingly to map from a
+source content buffer's space to a display's space.
+
+When fixed-function HW is not available the compositor will assemble a shader 
to
+ask the GPU to perform the transformation from the source content format to the
+display's format.
+
+A compositor's mapping function and a driver's mapping function are usually
+entirely separate concepts. On OSes where a HW vendor has no insight into
+closed-source compositor code such a vendor will tune their color management
+code to visually match the compositor's. On other OSes, where both mapping
+functions are open to an implementer they will ensure both mappings match.
+
+This results in mapping algorithm lock-in, meaning that no-one alone can
+experiment with or introduce new mapping algorithms and achieve
+consistent results regardless of which implementation path is taken.
+
+Why is Linux different?
+===
+
+Unlike other OSes, where there is one compositor for one or more drivers, on
+Linux we have a many-to-many relationship. Many compositors; many drivers.
+In addition each compositor vendor or community has their own view of how
+color management should be done. This is what makes Linux so beautiful.
+
+This means that a HW vendor can now no longer tune their driver to one
+compositor, as tuning it to one could make it look fairly different from
+another compositor's color mapping.
+
+We need a better solution.
+
+
+Descriptive API
+===
+
+An API that describes the source and destination colorspaces is a descriptive
+API. It describes the input and output color spaces but does not describe
+how precisely they should be mapped. Such a mapping includes many minute
+design decision that can greatly affect the look of the final result.
+
+It is not feasible to describe such mapping with enough detail to ensure the
+same result from each implementation. In fact, these mappings are a very active
+research area.
+
+
+Prescriptive API
+
+
+A prescriptive API describes not the source and destination colorspaces. It
+instead prescribes a recipe for how to manipulate pi

[RFC PATCH v4 20/42] drm/colorop: Add 3x4 CTM type

2024-02-26 Thread Harry Wentland
This type is used to support a 3x4 matrix in colorops. A 3x4
matrix uses the last column as a "bias" column. Some HW exposes
support for 3x4. The calculation looks like:

 out   matrixin
 |R|   |0  1  2  3 |   | R |
 |G| = |4  5  6  7 | x | G |
 |B|   |8  9  10 11|   | B |
   |1.0|

This is also the first colorop where we need a blob property to
program the property. For that we'll introduce a new DATA
property that can be used by all colorop TYPEs requiring a
blob. The way a DATA blob is read depends on the TYPE of
the colorop.

We only create the DATA property for property types that
need it.

v4:
 - Create helper function for creating 3x4 CTM colorop
 - Fix CTM indexes in comment (Pekka)

Signed-off-by: Harry Wentland 
---
 drivers/gpu/drm/drm_atomic.c  | 14 ++-
 drivers/gpu/drm/drm_atomic_uapi.c | 29 ++
 drivers/gpu/drm/drm_colorop.c | 40 +++
 include/drm/drm_colorop.h | 19 +++
 include/uapi/drm/drm_mode.h   |  9 ++-
 5 files changed, 109 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index d82858dabf06..6e736ffa6d7c 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -793,7 +793,19 @@ static void drm_atomic_colorop_print_state(struct 
drm_printer *p,
drm_printf(p, "colorop[%u]:\n", colorop->base.id);
drm_printf(p, "\ttype=%s\n", drm_get_colorop_type_name(colorop->type));
drm_printf(p, "\tbypass=%u\n", state->bypass);
-   drm_printf(p, "\tcurve_1d_type=%s\n", 
drm_get_colorop_curve_1d_type_name(state->curve_1d_type));
+
+   switch (colorop->type) {
+   case DRM_COLOROP_1D_CURVE:
+   drm_printf(p, "\tcurve_1d_type=%s\n",
+  
drm_get_colorop_curve_1d_type_name(state->curve_1d_type));
+   break;
+   case DRM_COLOROP_CTM_3X4:
+   drm_printf(p, "\tdata blob id=%d\n", state->data ? 
state->data->base.id : 0);
+   break;
+   default:
+   break;
+   }
+
drm_printf(p, "\tnext=%d\n", colorop->next ? colorop->next->base.id : 
0);
 }
 
diff --git a/drivers/gpu/drm/drm_atomic_uapi.c 
b/drivers/gpu/drm/drm_atomic_uapi.c
index ff258b34544e..23b248987a7c 100644
--- a/drivers/gpu/drm/drm_atomic_uapi.c
+++ b/drivers/gpu/drm/drm_atomic_uapi.c
@@ -691,6 +691,30 @@ drm_atomic_plane_get_property(struct drm_plane *plane,
return 0;
 }
 
+static int drm_atomic_color_set_data_property(struct drm_colorop *colorop,
+   struct drm_colorop_state *state,
+   struct drm_property *property, uint64_t val)
+{
+   ssize_t elem_size = -1;
+   ssize_t size = -1;
+   bool replaced = false;
+
+   switch (colorop->type) {
+   case DRM_COLOROP_CTM_3X4:
+   size = sizeof(struct drm_color_ctm_3x4);
+   break;
+   default:
+   /* should never get here */
+   return -EINVAL;
+   }
+
+   return drm_property_replace_blob_from_id(colorop->dev,
+   >data,
+   val,
+   size,
+   elem_size,
+   );
+}
 
 static int drm_atomic_colorop_set_property(struct drm_colorop *colorop,
struct drm_colorop_state *state, struct drm_file *file_priv,
@@ -700,6 +724,9 @@ static int drm_atomic_colorop_set_property(struct 
drm_colorop *colorop,
state->bypass = val;
} else if (property == colorop->curve_1d_type_property) {
state->curve_1d_type = val;
+   } else if (property == colorop->data_property) {
+   return drm_atomic_color_set_data_property(colorop,
+   state, property, val);
} else {
drm_dbg_atomic(colorop->dev,
   "[COLOROP:%d:%d] unknown property 
[PROP:%d:%s]]\n",
@@ -722,6 +749,8 @@ drm_atomic_colorop_get_property(struct drm_colorop *colorop,
*val = state->bypass;
} else if (property == colorop->curve_1d_type_property) {
*val = state->curve_1d_type;
+   } else if (property == colorop->data_property) {
+   *val = (state->data) ? state->data->base.id : 0;
} else {
return -EINVAL;
}
diff --git a/drivers/gpu/drm/drm_colorop.c b/drivers/gpu/drm/drm_colorop.c
index 71c2286333a1..7baa1eba 100644
--- a/drivers/gpu/drm/drm_colorop.c
+++ b/drivers/gpu/drm/drm_colorop.c
@@ -34,6 +34,7 @@
 
 static const struct drm_prop_enum_list drm_colorop_type_enum_list[] = {
{ DRM_COLOROP_1D_CURVE, "1D Curve" },
+   { DRM

[RFC PATCH v4 39/42] drm/amd/display: add shaper and blend colorops for 1D Curve Custom LUT

2024-02-26 Thread Harry Wentland
From: Alex Hung 

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 
---
 .../amd/display/amdgpu_dm/amdgpu_dm_color.c   | 170 +-
 .../amd/display/amdgpu_dm/amdgpu_dm_colorop.c |  30 
 2 files changed, 119 insertions(+), 81 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 d5d356cf9fc6..e7b51b29cc04 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
@@ -1212,40 +1212,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;
-   const struct drm_color_lut *shaper_lut;
-   uint32_t shaper_size;
-
-   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, shaper_lut, shaper_size, false);
-   }
-
-   return -EINVAL;
-}
-
 static int
 __set_dm_plane_colorop_shaper(struct drm_plane_state *plane_state,
  struct dc_plane_state *dc_plane_state,
@@ -1254,64 +1220,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) {
+   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;
+   __set_output_tf(tf, shaper_lut, shaper_size, false);
+   }
+
+   /* 1D LUT - SHAPER LUT */
+   colorop = old_colorop->next;
+   if (!colorop) {
+   drm_dbg(dev, "no Shaper LUT colorop found\n");
+   return -EINVAL;
+   }
+
+   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_1D_LUT) {
colorop_state = new_colorop_state;
break;
}
}
 
-   if (!colorop_state)
-   return -EINVAL;
-
-   re

[RFC PATCH v4 36/42] drm/colorop: add BT2020/BT709 OETF and Inverse OETF

2024-02-26 Thread Harry Wentland
The BT.709 and BT.2020 OETFs are the same, the only difference
being that the BT.2020 variant is defined with more precision
for 10 and 12-bit per color encodings.

Both are used as encoding functions for video content, and are
therefore defined as OETF (opto-electronic transfer function)
instead of as EOTF (electro-optical transfer function).

Signed-off-by: Harry Wentland 
---
 drivers/gpu/drm/drm_colorop.c | 2 ++
 include/drm/drm_colorop.h | 2 ++
 2 files changed, 4 insertions(+)

diff --git a/drivers/gpu/drm/drm_colorop.c b/drivers/gpu/drm/drm_colorop.c
index 781947e42b02..b10cad5a7208 100644
--- a/drivers/gpu/drm/drm_colorop.c
+++ b/drivers/gpu/drm/drm_colorop.c
@@ -40,6 +40,8 @@ static const struct drm_prop_enum_list 
drm_colorop_type_enum_list[] = {
 static const char * const colorop_curve_1d_type_names[] = {
[DRM_COLOROP_1D_CURVE_SRGB_EOTF] = "sRGB EOTF",
[DRM_COLOROP_1D_CURVE_SRGB_INV_EOTF] = "sRGB Inverse EOTF",
+   [DRM_COLOROP_1D_CURVE_BT2020_INV_OETF] = "BT.2020 Inverse OETF",
+   [DRM_COLOROP_1D_CURVE_BT2020_OETF] = "BT.2020 OETF",
[DRM_COLOROP_1D_CURVE_PQ_125_EOTF] = "PQ 125 EOTF",
[DRM_COLOROP_1D_CURVE_PQ_125_INV_EOTF] = "PQ 125 Inverse EOTF",
 };
diff --git a/include/drm/drm_colorop.h b/include/drm/drm_colorop.h
index e06d9ea28efd..28b3136dabad 100644
--- a/include/drm/drm_colorop.h
+++ b/include/drm/drm_colorop.h
@@ -33,6 +33,8 @@
 enum drm_colorop_curve_1d_type {
DRM_COLOROP_1D_CURVE_SRGB_EOTF,
DRM_COLOROP_1D_CURVE_SRGB_INV_EOTF,
+   DRM_COLOROP_1D_CURVE_BT2020_INV_OETF,
+   DRM_COLOROP_1D_CURVE_BT2020_OETF,
DRM_COLOROP_1D_CURVE_PQ_125_EOTF,
DRM_COLOROP_1D_CURVE_PQ_125_INV_EOTF,
DRM_COLOROP_1D_CURVE_COUNT
-- 
2.44.0



[RFC PATCH v4 30/42] drm/amd/display: Skip color pipeline initialization for cursor plane

2024-02-26 Thread Harry Wentland
From: Alex Hung 

Signed-off-by: Alex Hung 
---
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
index c5c07b4cd6c9..d3f64f586243 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
@@ -1659,6 +1659,9 @@ dm_plane_init_colorops(struct drm_plane *plane)
struct drm_prop_enum_list pipelines[MAX_COLOR_PIPELINES];
int len = 0;
 
+   if (plane->type == DRM_PLANE_TYPE_CURSOR)
+   return 0;
+
/* Create COLOR_PIPELINE property and attach */
drm_plane_create_color_pipeline_property(plane, pipelines, len);
 
-- 
2.44.0



[RFC PATCH v4 38/42] drm/colorop: Add 1D Curve Custom LUT type

2024-02-26 Thread Harry Wentland
From: Alex Hung 

We've previously introduced DRM_COLOROP_1D_CURVE for
pre-defined 1D curves. But we also have HW that supports
custom curves and userspace needs the ability to pass
custom curves, aka LUTs.

This patch introduces a new colorop type, called
DRM_COLOROP_1D_LUT that provides a SIZE property which
is used by a driver to advertise the supported SIZE
of the LUT, as well as a DATA property which userspace
uses to set the LUT.

DATA and size function in the same way as current drm_crtc
GAMMA and DEGAMMA LUTs.

Signed-off-by: Alex Hung 
Signed-off-by: Harry Wentland 
Co-developed-by: Harry Wentland 
---
 drivers/gpu/drm/drm_atomic.c  |  4 
 drivers/gpu/drm/drm_atomic_uapi.c |  5 +
 drivers/gpu/drm/drm_colorop.c | 36 +--
 include/drm/drm_colorop.h | 16 ++
 include/uapi/drm/drm_mode.h   |  1 +
 5 files changed, 60 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index 6e736ffa6d7c..f7d51839ca03 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -799,6 +799,10 @@ static void drm_atomic_colorop_print_state(struct 
drm_printer *p,
drm_printf(p, "\tcurve_1d_type=%s\n",
   
drm_get_colorop_curve_1d_type_name(state->curve_1d_type));
break;
+   case DRM_COLOROP_1D_LUT:
+   drm_printf(p, "\tsize=%d\n", state->size);
+   drm_printf(p, "\tdata blob id=%d\n", state->data ? 
state->data->base.id : 0);
+   break;
case DRM_COLOROP_CTM_3X4:
drm_printf(p, "\tdata blob id=%d\n", state->data ? 
state->data->base.id : 0);
break;
diff --git a/drivers/gpu/drm/drm_atomic_uapi.c 
b/drivers/gpu/drm/drm_atomic_uapi.c
index c7c1c614b0d9..6bfe857720cd 100644
--- a/drivers/gpu/drm/drm_atomic_uapi.c
+++ b/drivers/gpu/drm/drm_atomic_uapi.c
@@ -700,6 +700,9 @@ static int drm_atomic_color_set_data_property(struct 
drm_colorop *colorop,
bool replaced = false;
 
switch (colorop->type) {
+   case DRM_COLOROP_1D_LUT:
+   size = state->size * sizeof(struct drm_color_lut);
+   break;
case DRM_COLOROP_CTM_3X4:
size = sizeof(struct drm_color_ctm_3x4);
break;
@@ -749,6 +752,8 @@ drm_atomic_colorop_get_property(struct drm_colorop *colorop,
*val = state->bypass;
} else if (property == colorop->curve_1d_type_property) {
*val = state->curve_1d_type;
+   } else if (property == colorop->size_property) {
+   *val = state->size;
} else if (property == colorop->data_property) {
*val = (state->data) ? state->data->base.id : 0;
} else {
diff --git a/drivers/gpu/drm/drm_colorop.c b/drivers/gpu/drm/drm_colorop.c
index b10cad5a7208..4452eaeeb242 100644
--- a/drivers/gpu/drm/drm_colorop.c
+++ b/drivers/gpu/drm/drm_colorop.c
@@ -34,6 +34,7 @@
 
 static const struct drm_prop_enum_list drm_colorop_type_enum_list[] = {
{ DRM_COLOROP_1D_CURVE, "1D Curve" },
+   { DRM_COLOROP_1D_LUT, "1D Curve Custom LUT" },
{ DRM_COLOROP_CTM_3X4, "3x4 Matrix"}
 };
 
@@ -175,11 +176,41 @@ static int drm_colorop_create_data_prop(struct drm_device 
*dev, struct drm_color
 
colorop->data_property = prop;
drm_object_attach_property(>base,
-   colorop->data_property,
-   0);
+  colorop->data_property,
+  0);
 
return 0;
 }
+int drm_colorop_curve_1d_lut_init(struct drm_device *dev, struct drm_colorop 
*colorop,
+ struct drm_plane *plane, uint32_t lut_size)
+{
+   struct drm_property *prop;
+   int ret;
+
+   ret = drm_colorop_init(dev, colorop, plane, DRM_COLOROP_1D_LUT);
+   if (ret)
+   return ret;
+
+   /* initialize 1D LUT only attribute */
+   /* LUT size */
+   prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, "SIZE", 
lut_size, lut_size);
+   if (!prop)
+   return -ENOMEM;
+
+   colorop->size_property = prop;
+   drm_object_attach_property(>base, colorop->size_property, 0);
+
+   /* data */
+   ret = drm_colorop_create_data_prop(dev, colorop);
+   if (ret)
+   return ret;
+
+   drm_colorop_reset(colorop);
+   colorop->state->size = lut_size;
+
+   return 0;
+}
+EXPORT_SYMBOL(drm_colorop_curve_1d_lut_init);
 
 int drm_colorop_ctm_3x4_init(struct drm_device *dev, struct drm_colorop 
*colorop,
 struct drm_plane *plane)
@@ -301,6 +332,7 @@ EXPORT_SYMBOL(drm_colorop_reset);
 
 static const char * const colorop_type_name[] 

[RFC PATCH v4 34/42] drm/colorop: Add PQ 125 EOTF and its inverse

2024-02-26 Thread Harry Wentland
The PQ function defines a mapping of code values to nits (cd/m^2).
The max code value maps to 10,000 nits.

Windows DWM's canonical composition color space (CCCS)  defaults
to composing SDR contents to 80 nits and uses a float value of
1.0 to represent this. For this reason AMD HW hard-codes a PQ
function that is scaled by 125, yielding 80 nit PQ values for
1.0 and 10,000 nits at 125.0.

This patch introduces this scaled PQ EOTF and its inverse as
1D curve types.

Signed-off-by: Harry Wentland 
---
 drivers/gpu/drm/drm_colorop.c | 2 ++
 include/drm/drm_colorop.h | 2 ++
 2 files changed, 4 insertions(+)

diff --git a/drivers/gpu/drm/drm_colorop.c b/drivers/gpu/drm/drm_colorop.c
index 7baa1eba..781947e42b02 100644
--- a/drivers/gpu/drm/drm_colorop.c
+++ b/drivers/gpu/drm/drm_colorop.c
@@ -40,6 +40,8 @@ static const struct drm_prop_enum_list 
drm_colorop_type_enum_list[] = {
 static const char * const colorop_curve_1d_type_names[] = {
[DRM_COLOROP_1D_CURVE_SRGB_EOTF] = "sRGB EOTF",
[DRM_COLOROP_1D_CURVE_SRGB_INV_EOTF] = "sRGB Inverse EOTF",
+   [DRM_COLOROP_1D_CURVE_PQ_125_EOTF] = "PQ 125 EOTF",
+   [DRM_COLOROP_1D_CURVE_PQ_125_INV_EOTF] = "PQ 125 Inverse EOTF",
 };
 
 
diff --git a/include/drm/drm_colorop.h b/include/drm/drm_colorop.h
index 8710e550790c..e06d9ea28efd 100644
--- a/include/drm/drm_colorop.h
+++ b/include/drm/drm_colorop.h
@@ -33,6 +33,8 @@
 enum drm_colorop_curve_1d_type {
DRM_COLOROP_1D_CURVE_SRGB_EOTF,
DRM_COLOROP_1D_CURVE_SRGB_INV_EOTF,
+   DRM_COLOROP_1D_CURVE_PQ_125_EOTF,
+   DRM_COLOROP_1D_CURVE_PQ_125_INV_EOTF,
DRM_COLOROP_1D_CURVE_COUNT
 };
 
-- 
2.44.0



[RFC PATCH v4 02/42] drm: Add helper for conversion from signed-magnitude

2024-02-26 Thread Harry Wentland
CTM values are defined as signed-magnitude values. Add
a helper that converts from CTM signed-magnitude fixed
point value to the twos-complement value used by
drm_fixed.

Signed-off-by: Harry Wentland 
---
 include/drm/drm_fixed.h | 18 ++
 1 file changed, 18 insertions(+)

diff --git a/include/drm/drm_fixed.h b/include/drm/drm_fixed.h
index 0c9f917a4d4b..cb842ba80ddd 100644
--- a/include/drm/drm_fixed.h
+++ b/include/drm/drm_fixed.h
@@ -78,6 +78,24 @@ static inline u32 dfixed_div(fixed20_12 A, fixed20_12 B)
 #define DRM_FIXED_EPSILON  1LL
 #define DRM_FIXED_ALMOST_ONE   (DRM_FIXED_ONE - DRM_FIXED_EPSILON)
 
+/**
+ * @drm_sm2fixp
+ *
+ * Convert a 1.31.32 signed-magnitude fixed point to 32.32
+ * 2s-complement fixed point
+ *
+ * @return s64 2s-complement fixed point
+ */
+static inline s64 drm_sm2fixp(__u64 a)
+{
+   if ((a & (1LL << 63))) {
+   return -(a & 0x7fffll);
+   } else {
+   return a;
+   }
+
+}
+
 static inline s64 drm_int2fixp(int a)
 {
return ((s64)a) << DRM_FIXED_POINT;
-- 
2.44.0



[RFC PATCH v4 29/42] drm/amd/display: Add bypass COLOR PIPELINE

2024-02-26 Thread Harry Wentland
Add the default Bypass pipeline and ensure it passes the
kms_colorop test plane-XR30-XR30-bypass.

Signed-off-by: Harry Wentland 
---
 .../amd/display/amdgpu_dm/amdgpu_dm_plane.c   | 19 +++
 1 file changed, 19 insertions(+)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
index 8a4c40b4c27e..c5c07b4cd6c9 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
@@ -1651,6 +1651,20 @@ dm_atomic_plane_get_property(struct drm_plane *plane,
 }
 #endif
 
+#define MAX_COLOR_PIPELINES 5
+
+static int
+dm_plane_init_colorops(struct drm_plane *plane)
+{
+   struct drm_prop_enum_list pipelines[MAX_COLOR_PIPELINES];
+   int len = 0;
+
+   /* Create COLOR_PIPELINE property and attach */
+   drm_plane_create_color_pipeline_property(plane, pipelines, len);
+
+   return 0;
+}
+
 static const struct drm_plane_funcs dm_plane_funcs = {
.update_plane   = drm_atomic_helper_update_plane,
.disable_plane  = drm_atomic_helper_disable_plane,
@@ -1744,7 +1758,12 @@ int amdgpu_dm_plane_init(struct amdgpu_display_manager 
*dm,
 
 #ifdef AMD_PRIVATE_COLOR
dm_atomic_plane_attach_color_mgmt_properties(dm, plane);
+#else
+   res = dm_plane_init_colorops(plane);
+   if (res)
+   return res;
 #endif
+
/* Create (reset) the plane state */
if (plane->funcs->reset)
plane->funcs->reset(plane);
-- 
2.44.0



[RFC PATCH v4 37/42] drm/amd/display: Add support for BT.709 and BT.2020 TFs

2024-02-26 Thread Harry Wentland
This adds support for the BT.709/BT.2020 transfer functions
on all current 1D curve plane colorops, i.e., on DEGAM, SHAPER,
and BLND blocks.

With this change the following IGT subtests pass:
kms_colorop --run plane-XR30-XR30-bt2020_inv_oetf
kms_colorop --run plane-XR30-XR30-bt2020_oetf

Signed-off-by: Harry Wentland 
---
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c   | 11 ---
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_colorop.c | 10 +++---
 2 files changed, 15 insertions(+), 6 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 20b7eb47388c..d5d356cf9fc6 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
@@ -677,6 +677,9 @@ amdgpu_colorop_tf_to_dc_tf(enum drm_colorop_curve_1d_type 
tf)
case DRM_COLOROP_1D_CURVE_SRGB_EOTF:
case DRM_COLOROP_1D_CURVE_SRGB_INV_EOTF:
return TRANSFER_FUNCTION_SRGB;
+   case DRM_COLOROP_1D_CURVE_BT2020_INV_OETF:
+   case DRM_COLOROP_1D_CURVE_BT2020_OETF:
+   return TRANSFER_FUNCTION_BT709;
case DRM_COLOROP_1D_CURVE_PQ_125_EOTF:
case DRM_COLOROP_1D_CURVE_PQ_125_INV_EOTF:
return TRANSFER_FUNCTION_PQ;
@@ -1287,8 +1290,10 @@ __set_colorop_1d_curve_blend_tf_lut(struct 
dc_plane_state *dc_plane_state,
const struct drm_color_lut *blend_lut;
uint32_t blend_size;
 
-   if (colorop->type != DRM_COLOROP_1D_CURVE &&
-   colorop_state->curve_1d_type != DRM_COLOROP_1D_CURVE_SRGB_EOTF)
+   if (colorop->type != DRM_COLOROP_1D_CURVE)
+   return -EINVAL;
+
+   if (!(BIT(colorop_state->curve_1d_type) & amdgpu_dm_supported_blnd_tfs))
return -EINVAL;
 
if (colorop_state->bypass) {
@@ -1324,7 +1329,7 @@ __set_dm_plane_colorop_blend(struct drm_plane_state 
*plane_state,
/* 3nd op: 1d curve - blend */
for_each_new_colorop_in_state(state, colorop, new_colorop_state, i) {
if (new_colorop_state->colorop == old_colorop &&
-   new_colorop_state->curve_1d_type == 
DRM_COLOROP_1D_CURVE_SRGB_EOTF) {
+   (BIT(new_colorop_state->curve_1d_type) & 
amdgpu_dm_supported_blnd_tfs)) {
colorop_state = new_colorop_state;
break;
}
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_colorop.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_colorop.c
index f99d8e09d89b..bc66bd4f9fdd 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_colorop.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_colorop.c
@@ -33,14 +33,18 @@
 
 const u64 amdgpu_dm_supported_degam_tfs =
BIT(DRM_COLOROP_1D_CURVE_SRGB_EOTF) |
-   BIT(DRM_COLOROP_1D_CURVE_PQ_125_EOTF);
+   BIT(DRM_COLOROP_1D_CURVE_PQ_125_EOTF) |
+   BIT(DRM_COLOROP_1D_CURVE_BT2020_INV_OETF);
 
 const u64 amdgpu_dm_supported_shaper_tfs =
BIT(DRM_COLOROP_1D_CURVE_SRGB_INV_EOTF) |
-   BIT(DRM_COLOROP_1D_CURVE_PQ_125_INV_EOTF);
+   BIT(DRM_COLOROP_1D_CURVE_PQ_125_INV_EOTF) |
+   BIT(DRM_COLOROP_1D_CURVE_BT2020_OETF);
 
 const u64 amdgpu_dm_supported_blnd_tfs =
-   BIT(DRM_COLOROP_1D_CURVE_SRGB_EOTF);
+   BIT(DRM_COLOROP_1D_CURVE_SRGB_EOTF) |
+   BIT(DRM_COLOROP_1D_CURVE_PQ_125_EOTF) |
+   BIT(DRM_COLOROP_1D_CURVE_BT2020_INV_OETF);
 
 int amdgpu_dm_initialize_default_pipeline(struct drm_plane *plane, struct 
drm_prop_enum_list *list)
 {
-- 
2.44.0



[RFC PATCH v4 11/42] drm/colorop: Add 1D Curve subtype

2024-02-26 Thread Harry Wentland
v4:
 - Use drm_colorop_curve_1d_type_enum_list to get name (Pekka)
 - Create separate init function for 1D curve
 - Pass supported TFs into 1D curve init function

Signed-off-by: Harry Wentland 
Signed-off-by: Alex Hung 
Co-developed-by: Alex Hung 
---
 drivers/gpu/drm/drm_atomic_uapi.c | 18 +---
 drivers/gpu/drm/drm_colorop.c | 71 +++
 include/drm/drm_colorop.h | 24 +++
 3 files changed, 108 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/drm_atomic_uapi.c 
b/drivers/gpu/drm/drm_atomic_uapi.c
index e3067c095c72..fdd540cfe24f 100644
--- a/drivers/gpu/drm/drm_atomic_uapi.c
+++ b/drivers/gpu/drm/drm_atomic_uapi.c
@@ -648,11 +648,17 @@ static int drm_atomic_colorop_set_property(struct 
drm_colorop *colorop,
struct drm_colorop_state *state, struct drm_file *file_priv,
struct drm_property *property, uint64_t val)
 {
-   drm_dbg_atomic(colorop->dev,
-   "[COLOROP:%d] unknown property [PROP:%d:%s]]\n",
-   colorop->base.id,
-   property->base.id, property->name);
-   return -EINVAL;
+   if (property == colorop->curve_1d_type_property) {
+   state->curve_1d_type = val;
+   } else {
+   drm_dbg_atomic(colorop->dev,
+  "[COLOROP:%d:%d] unknown property 
[PROP:%d:%s]]\n",
+  colorop->base.id, colorop->type,
+  property->base.id, property->name);
+   return -EINVAL;
+   }
+
+   return 0;
 }
 
 static int
@@ -662,6 +668,8 @@ drm_atomic_colorop_get_property(struct drm_colorop *colorop,
 {
if (property == colorop->type_property) {
*val = colorop->type;
+   } else if (property == colorop->curve_1d_type_property) {
+   *val = state->curve_1d_type;
} else {
return -EINVAL;
}
diff --git a/drivers/gpu/drm/drm_colorop.c b/drivers/gpu/drm/drm_colorop.c
index 3a07a8fe2842..f4740b6115d1 100644
--- a/drivers/gpu/drm/drm_colorop.c
+++ b/drivers/gpu/drm/drm_colorop.c
@@ -36,6 +36,12 @@ static const struct drm_prop_enum_list 
drm_colorop_type_enum_list[] = {
{ DRM_COLOROP_1D_CURVE, "1D Curve" },
 };
 
+static const char * const colorop_curve_1d_type_names[] = {
+   [DRM_COLOROP_1D_CURVE_SRGB_EOTF] = "sRGB EOTF",
+   [DRM_COLOROP_1D_CURVE_SRGB_INV_EOTF] = "sRGB Inverse EOTF",
+};
+
+
 /* Init Helpers */
 
 int drm_colorop_init(struct drm_device *dev, struct drm_colorop *colorop,
@@ -78,6 +84,56 @@ int drm_colorop_init(struct drm_device *dev, struct 
drm_colorop *colorop,
 }
 EXPORT_SYMBOL(drm_colorop_init);
 
+int drm_colorop_curve_1d_init(struct drm_device *dev, struct drm_colorop 
*colorop,
+ struct drm_plane *plane, u64 supported_tfs)
+{
+   struct drm_prop_enum_list enum_list[DRM_COLOROP_1D_CURVE_COUNT];
+   int i, len;
+
+   struct drm_property *prop;
+   int ret;
+
+   if (!supported_tfs) {
+   drm_err(dev,
+   "No supported TFs for new 1D curve colorop on 
[PLANE:%d:%s]\n",
+   plane->base.id, plane->name);
+   return -EINVAL;
+   }
+
+   if ((supported_tfs & -BIT(DRM_COLOROP_1D_CURVE_COUNT)) != 0) {
+   drm_err(dev, "Unknown TF provided on [PLANE:%d:%s]\n",
+   plane->base.id, plane->name);
+   return -EINVAL;
+   }
+
+   ret = drm_colorop_init(dev, colorop, plane, DRM_COLOROP_1D_CURVE);
+   if (ret)
+   return ret;
+
+   len = 0;
+   for (i = 0; i < DRM_COLOROP_1D_CURVE_COUNT; i++) {
+   if ((supported_tfs & BIT(i)) == 0)
+   continue;
+
+   enum_list[len].type = i;
+   enum_list[len].name = colorop_curve_1d_type_names[i];
+   len++;
+   }
+
+   /* initialize 1D curve only attribute */
+   prop = drm_property_create_enum(dev, DRM_MODE_PROP_ATOMIC, 
"CURVE_1D_TYPE",
+   enum_list, len);
+   if (!prop)
+   return -ENOMEM;
+
+   colorop->curve_1d_type_property = prop;
+   drm_object_attach_property(>base, 
colorop->curve_1d_type_property, 0);
+   drm_colorop_reset(colorop);
+
+   return 0;
+}
+EXPORT_SYMBOL(drm_colorop_curve_1d_init);
+
 static void __drm_atomic_helper_colorop_duplicate_state(struct drm_colorop 
*colorop,
struct 
drm_colorop_state *state)
 {
@@ -192,3 +248,18 @@ const char *drm_get_colorop_type_name(enum 
drm_colorop_type type)
 
return colorop_type_name[type];
 }
+
+/**
+ * drm_get_colorop_curve_1d_type_name - return a string for 1D curve type
+ * @range: 1d curve type to 

[RFC PATCH v4 16/42] drm/colorop: Add NEXT to colorop state print

2024-02-26 Thread Harry Wentland
v3:
 - Read NEXT ID from drm_colorop's next pointer

Signed-off-by: Harry Wentland 
---
 drivers/gpu/drm/drm_atomic.c | 1 +
 include/drm/drm_colorop.h| 2 ++
 2 files changed, 3 insertions(+)

diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index 27a8805c5fa1..d82858dabf06 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -794,6 +794,7 @@ static void drm_atomic_colorop_print_state(struct 
drm_printer *p,
drm_printf(p, "\ttype=%s\n", drm_get_colorop_type_name(colorop->type));
drm_printf(p, "\tbypass=%u\n", state->bypass);
drm_printf(p, "\tcurve_1d_type=%s\n", 
drm_get_colorop_curve_1d_type_name(state->curve_1d_type));
+   drm_printf(p, "\tnext=%d\n", colorop->next ? colorop->next->base.id : 
0);
 }
 
 static void drm_atomic_plane_print_state(struct drm_printer *p,
diff --git a/include/drm/drm_colorop.h b/include/drm/drm_colorop.h
index fc9a28d138b8..e85ed5aa68d0 100644
--- a/include/drm/drm_colorop.h
+++ b/include/drm/drm_colorop.h
@@ -237,6 +237,8 @@ const char *drm_get_colorop_type_name(enum drm_colorop_type 
type);
 const char *drm_get_colorop_curve_1d_type_name(enum drm_colorop_curve_1d_type 
type);
 
 void drm_colorop_set_next_property(struct drm_colorop *colorop, struct 
drm_colorop *next);
+uint32_t drm_colorop_get_next_property(struct drm_colorop *colorop);
+struct drm_colorop *drm_colorop_get_next(struct drm_colorop *colorop);
 
 
 #endif /* __DRM_COLOROP_H__ */
-- 
2.44.0



[RFC PATCH v4 19/42] drm/colorop: Introduce DRM_CLIENT_CAP_PLANE_COLOR_PIPELINE

2024-02-26 Thread Harry Wentland
With the introduction of the pre-blending color pipeline we
can no longer have color operations that don't have a clear
position in the color pipeline. We deprecate all existing
plane properties. For upstream drivers those are:
 - COLOR_ENCODING
 - COLOR_RANGE

Drivers are expected to ignore these properties when
programming the HW.

Setting of the COLOR_PIPELINE plane property or drm_colorop
properties is only allowed for userspace that sets this
client cap.

v4:
 - Don't block setting of COLOR_RANGE and COLOR_ENCODING
   when client cap is set

Signed-off-by: Harry Wentland 
---
 drivers/gpu/drm/drm_atomic_uapi.c | 13 -
 drivers/gpu/drm/drm_ioctl.c   |  7 +++
 include/drm/drm_file.h|  7 +++
 include/uapi/drm/drm.h| 16 
 4 files changed, 42 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/drm_atomic_uapi.c 
b/drivers/gpu/drm/drm_atomic_uapi.c
index 86f77a9aa3a8..ff258b34544e 100644
--- a/drivers/gpu/drm/drm_atomic_uapi.c
+++ b/drivers/gpu/drm/drm_atomic_uapi.c
@@ -570,6 +570,12 @@ static int drm_atomic_plane_set_property(struct drm_plane 
*plane,
} else if (property == plane->color_range_property) {
state->color_range = val;
} else if (property == plane->color_pipeline_property) {
+   if (!file_priv->plane_color_pipeline) {
+   drm_dbg_atomic(dev,
+  "Setting COLOR_PIPELINE plane property 
not permitted unless DRM_CLIENT_CAP_PLANE_COLOR_PIPELINE is set\n");
+   return -EINVAL;
+   }
+
/* find DRM colorop object */
struct drm_colorop *colorop = NULL;
colorop = drm_colorop_find(dev, file_priv, val);
@@ -1179,6 +1185,12 @@ int drm_atomic_set_property(struct drm_atomic_state 
*state,
break;
}
case DRM_MODE_OBJECT_COLOROP: {
+   if (!file_priv->plane_color_pipeline) {
+   drm_dbg_atomic(prop->dev,
+  "[OBJECT:%d] is a colorop but 
DRM_CLIENT_CAP_PLANE_COLOR_PIPELINE not set\n",
+  obj->id);
+   ret = -EINVAL;
+   }
struct drm_colorop *colorop = obj_to_colorop(obj);
struct drm_colorop_state *colorop_state;
 
@@ -1191,7 +1203,6 @@ int drm_atomic_set_property(struct drm_atomic_state 
*state,
ret = drm_atomic_colorop_set_property(colorop,
colorop_state, file_priv,
prop, prop_value);
-
break;
}
default:
diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c
index e368fc084c77..da59e37ae228 100644
--- a/drivers/gpu/drm/drm_ioctl.c
+++ b/drivers/gpu/drm/drm_ioctl.c
@@ -373,6 +373,13 @@ drm_setclientcap(struct drm_device *dev, void *data, 
struct drm_file *file_priv)
return -EINVAL;
file_priv->supports_virtualized_cursor_plane = req->value;
break;
+   case DRM_CLIENT_CAP_PLANE_COLOR_PIPELINE:
+   if (!file_priv->atomic)
+   return -EINVAL;
+   if (req->value > 1)
+   return -EINVAL;
+   file_priv->plane_color_pipeline = req->value;
+   break;
default:
return -EINVAL;
}
diff --git a/include/drm/drm_file.h b/include/drm/drm_file.h
index ab230d3af138..63c1d29b8520 100644
--- a/include/drm/drm_file.h
+++ b/include/drm/drm_file.h
@@ -204,6 +204,13 @@ struct drm_file {
 */
bool writeback_connectors;
 
+   /**
+* @plane_color_pipeline:
+*
+* True if client understands plane color pipelines
+*/
+   bool plane_color_pipeline;
+
/**
 * @was_master:
 *
diff --git a/include/uapi/drm/drm.h b/include/uapi/drm/drm.h
index 16122819edfe..2d74c49274ee 100644
--- a/include/uapi/drm/drm.h
+++ b/include/uapi/drm/drm.h
@@ -875,6 +875,22 @@ struct drm_get_cap {
  */
 #define DRM_CLIENT_CAP_CURSOR_PLANE_HOTSPOT6
 
+/**
+ * DRM_CLIENT_CAP_PLANE_COLOR_PIPELINE
+ *
+ * If set to 1
+ * - the DRM core will allow setting of plane the COLOR_PIPELINE
+ *   property, as well as drm_colorop properties.
+ * - Drivers will ignore these properties
+ *   - COLOR_ENCODING
+ *   - COLOR_RANGE
+ *
+ * The client must enable _CLIENT_CAP_ATOMIC first.
+ *
+ * This capability is currently in development.
+ */
+#define DRM_CLIENT_CAP_PLANE_COLOR_PIPELINE7
+
 /* DRM_IOCTL_SET_CLIENT_CAP ioctl argument type */
 struct drm_set_client_cap {
__u64 capability;
-- 
2.44.0



[RFC PATCH v4 23/42] drm/vkms: add 3x4 matrix in color pipeline

2024-02-26 Thread Harry Wentland
We add two 3x4 matrices into the VKMS color pipeline. The reason
we're adding matrices is so that we can test that application
of a matrix and its inverse yields an output equal to the input
image.

One complication with the matrix implementation has to do with
the fact that the matrix entries are in signed-magnitude fixed
point, whereas the drm_fixed.h implementation uses 2s-complement.
The latter one is the one that we want for easy addition and
subtraction, so we convert all entries to 2s-complement.

Signed-off-by: Harry Wentland 
---
 drivers/gpu/drm/vkms/vkms_colorop.c  | 32 +++-
 drivers/gpu/drm/vkms/vkms_composer.c | 27 +++
 include/drm/drm_colorop.h|  2 ++
 3 files changed, 60 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/vkms/vkms_colorop.c 
b/drivers/gpu/drm/vkms/vkms_colorop.c
index d2db366da6d3..a0e54b2c1f7a 100644
--- a/drivers/gpu/drm/vkms/vkms_colorop.c
+++ b/drivers/gpu/drm/vkms/vkms_colorop.c
@@ -35,7 +35,37 @@ const int vkms_initialize_color_pipeline(struct drm_plane 
*plane, struct drm_pro
 
prev_op = op;
 
-   /* 2nd op: 1d curve */
+   /* 2nd op: 3x4 matrix */
+   op = kzalloc(sizeof(struct drm_colorop), GFP_KERNEL);
+   if (!op) {
+   DRM_ERROR("KMS: Failed to allocate colorop\n");
+   return -ENOMEM;
+   }
+
+   ret = drm_colorop_ctm_3x4_init(dev, op, plane);
+   if (ret)
+   return ret;
+
+   drm_colorop_set_next_property(prev_op, op);
+
+   prev_op = op;
+
+   /* 3rd op: 3x4 matrix */
+   op = kzalloc(sizeof(struct drm_colorop), GFP_KERNEL);
+   if (!op) {
+   DRM_ERROR("KMS: Failed to allocate colorop\n");
+   return -ENOMEM;
+   }
+
+   ret = drm_colorop_ctm_3x4_init(dev, op, plane);
+   if (ret)
+   return ret;
+
+   drm_colorop_set_next_property(prev_op, op);
+
+   prev_op = op;
+
+   /* 4th op: 1d curve */
op = kzalloc(sizeof(struct drm_colorop), GFP_KERNEL);
if (!op) {
DRM_ERROR("KMS: Failed to allocate colorop\n");
diff --git a/drivers/gpu/drm/vkms/vkms_composer.c 
b/drivers/gpu/drm/vkms/vkms_composer.c
index d2101fa55aa3..8bbfce651526 100644
--- a/drivers/gpu/drm/vkms/vkms_composer.c
+++ b/drivers/gpu/drm/vkms/vkms_composer.c
@@ -164,6 +164,30 @@ static void apply_lut(const struct vkms_crtc_state 
*crtc_state, struct line_buff
}
 }
 
+static void apply_3x4_matrix(struct pixel_argb_s32 *pixel, const struct 
drm_color_ctm_3x4 *matrix)
+{
+   s64 rf, gf, bf;
+
+   rf = drm_fixp_mul(drm_sm2fixp(matrix->matrix[0]), 
drm_int2fixp(pixel->r)) +
+drm_fixp_mul(drm_sm2fixp(matrix->matrix[1]), 
drm_int2fixp(pixel->g)) +
+drm_fixp_mul(drm_sm2fixp(matrix->matrix[2]), 
drm_int2fixp(pixel->b)) +
+drm_sm2fixp(matrix->matrix[3]);
+
+   gf = drm_fixp_mul(drm_sm2fixp(matrix->matrix[4]), 
drm_int2fixp(pixel->r)) +
+drm_fixp_mul(drm_sm2fixp(matrix->matrix[5]), 
drm_int2fixp(pixel->g)) +
+drm_fixp_mul(drm_sm2fixp(matrix->matrix[6]), 
drm_int2fixp(pixel->b)) +
+drm_sm2fixp(matrix->matrix[7]);
+
+   bf = drm_fixp_mul(drm_sm2fixp(matrix->matrix[8]), 
drm_int2fixp(pixel->r)) +
+drm_fixp_mul(drm_sm2fixp(matrix->matrix[9]), 
drm_int2fixp(pixel->g)) +
+drm_fixp_mul(drm_sm2fixp(matrix->matrix[10]), 
drm_int2fixp(pixel->b)) +
+drm_sm2fixp(matrix->matrix[11]);
+
+   pixel->r = drm_fixp2int(rf);
+   pixel->g = drm_fixp2int(gf);
+   pixel->b = drm_fixp2int(bf);
+}
+
 static void apply_colorop(struct pixel_argb_s32 *pixel, struct drm_colorop 
*colorop)
 {
/* TODO is this right? */
@@ -185,6 +209,9 @@ static void apply_colorop(struct pixel_argb_s32 *pixel, 
struct drm_colorop *colo
DRM_DEBUG_DRIVER("unkown colorop 1D curve type 
%d\n", colorop_state->curve_1d_type);
break;
}
+   } else if (colorop->type == DRM_COLOROP_CTM_3X4) {
+   if (colorop_state->data)
+   apply_3x4_matrix(pixel, (struct drm_color_ctm_3x4 *) 
colorop_state->data->data);
}
 
 }
diff --git a/include/drm/drm_colorop.h b/include/drm/drm_colorop.h
index 4aee29e161d6..8710e550790c 100644
--- a/include/drm/drm_colorop.h
+++ b/include/drm/drm_colorop.h
@@ -224,6 +224,8 @@ int drm_colorop_init(struct drm_device *dev, struct 
drm_colorop *colorop,
 
 int drm_colorop_curve_1d_init(struct drm_device *dev, struct drm_colorop 
*colorop,
  struct drm_plane *plane, u64 supported_tfs);
+int drm_colorop_ctm_3x4_init(struct drm_device *dev, struct drm_colorop 
*colorop,
+struct drm_plane *plane);
 
 struct drm_colorop_state *
 drm_atomic_helper_colorop_duplicate_state(struct drm_colorop *colorop);
-- 
2.44.0



[RFC PATCH v4 25/42] drm/vkms: Add tests for CTM handling

2024-02-26 Thread Harry Wentland
A whole slew of tests for CTM handling that greatly helped in
debugging the CTM code. The extent of tests might seem a bit
silly but they're fast and might someday help save someone
else's day when debugging this.

v4:
 - Comment on origin of bt709_enc matrix (Pekka)
 - Use full opaque alpha (Pekka)
 - Add additional check for Y < 0x (Pekka)
 - Remove unused code (Pekka)
 - Rename red, green, blue to Y, U, V where applicable

Signed-off-by: Harry Wentland 
---
 drivers/gpu/drm/vkms/tests/vkms_color_tests.c | 251 ++
 drivers/gpu/drm/vkms/vkms_composer.c  |   2 +-
 2 files changed, 252 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/vkms/tests/vkms_color_tests.c 
b/drivers/gpu/drm/vkms/tests/vkms_color_tests.c
index e6ac01dee830..83d07f7bae37 100644
--- a/drivers/gpu/drm/vkms/tests/vkms_color_tests.c
+++ b/drivers/gpu/drm/vkms/tests/vkms_color_tests.c
@@ -3,6 +3,7 @@
 #include 
 
 #include 
+#include 
 
 #define TEST_LUT_SIZE 16
 
@@ -181,11 +182,261 @@ static void vkms_color_srgb_inv_srgb(struct kunit *test)
}
 }
 
+#define FIXPT_HALF(DRM_FIXED_ONE >> 1)
+#define FIXPT_QUARTER (DRM_FIXED_ONE >> 2)
+
+const struct drm_color_ctm_3x4 test_matrix_3x4_50_desat = { {
+   FIXPT_HALF, FIXPT_QUARTER, FIXPT_QUARTER, 0,
+   FIXPT_QUARTER, FIXPT_HALF, FIXPT_QUARTER, 0,
+   FIXPT_QUARTER, FIXPT_QUARTER, FIXPT_HALF, 0
+} };
+
+static void vkms_color_ctm_3x4_50_desat(struct kunit *test)
+{
+   struct pixel_argb_s32 ref, out;
+
+   /* full white */
+   ref.a = 0x;
+   ref.r = 0x;
+   ref.g = 0x;
+   ref.b = 0x;
+
+   memcpy(, , sizeof(out));
+   apply_3x4_matrix(, _matrix_3x4_50_desat);
+
+   KUNIT_EXPECT_MEMEQ(test, , , sizeof(out));
+
+   /* full black */
+   ref.a = 0x;
+   ref.r = 0x0;
+   ref.g = 0x0;
+   ref.b = 0x0;
+
+   memcpy(, , sizeof(out));
+   apply_3x4_matrix(, _matrix_3x4_50_desat);
+
+   KUNIT_EXPECT_MEMEQ(test, , , sizeof(out));
+
+   /* 50% grey */
+   ref.a = 0x;
+   ref.r = 0x8000;
+   ref.g = 0x8000;
+   ref.b = 0x8000;
+
+   memcpy(, , sizeof(out));
+   apply_3x4_matrix(, _matrix_3x4_50_desat);
+
+   KUNIT_EXPECT_MEMEQ(test, , , sizeof(out));
+
+   /* full red to 50% desat */
+   ref.a = 0x;
+   ref.r = 0x7fff;
+   ref.g = 0x3fff;
+   ref.b = 0x3fff;
+
+   out.a = 0x;
+   out.r = 0x;
+   out.g = 0x0;
+   out.b = 0x0;
+
+   apply_3x4_matrix(, _matrix_3x4_50_desat);
+
+   KUNIT_EXPECT_MEMEQ(test, , , sizeof(out));
+}
+
+/*
+ * BT.709 encoding matrix
+ *
+ * Values printed from within IGT when converting
+ * igt_matrix_3x4_bt709_enc to the fixed-point format expected
+ * by DRM/KMS.
+ */
+const struct drm_color_ctm_3x4 test_matrix_3x4_bt709_enc = { {
+   0x366cf400ull, 0xb7175900ull, 0x000127bb300ull, 0,
+   0x80001993b3a0ull, 0x80005609fe80ull, 0x6f9db200ull, 0,
+   0x9d70a400ull, 0x80008f011100ull, 0x8e6f9330ull, 0
+} };
+
+static void vkms_color_ctm_3x4_bt709(struct kunit *test)
+{
+   struct pixel_argb_s32 out;
+
+   /* full white to bt709 */
+   out.a = 0x;
+   out.r = 0x;
+   out.g = 0x;
+   out.b = 0x;
+
+   apply_3x4_matrix(, _matrix_3x4_bt709_enc);
+
+   /* Y 255 */
+   KUNIT_EXPECT_GT(test, out.r, 0xfe00);
+   KUNIT_EXPECT_LT(test, out.r, 0x1);
+
+   /* U 0 */
+   KUNIT_EXPECT_LT(test, out.g, 0x0100);
+
+   /* V 0 */
+   KUNIT_EXPECT_LT(test, out.b, 0x0100);
+
+   /* full black to bt709 */
+   out.a = 0x;
+   out.r = 0x0;
+   out.g = 0x0;
+   out.b = 0x0;
+
+   apply_3x4_matrix(, _matrix_3x4_bt709_enc);
+
+   /* Y 0 */
+   KUNIT_EXPECT_LT(test, out.r, 0x100);
+
+   /* U 0 */
+   KUNIT_EXPECT_LT(test, out.g, 0x0100);
+
+   /* V 0 */
+   KUNIT_EXPECT_LT(test, out.b, 0x0100);
+
+   /* gray to bt709 */
+   out.a = 0x;
+   out.r = 0x7fff;
+   out.g = 0x7fff;
+   out.b = 0x7fff;
+
+   apply_3x4_matrix(, _matrix_3x4_bt709_enc);
+
+   /* Y 127 */
+   KUNIT_EXPECT_GT(test, out.r, 0x7e00);
+   KUNIT_EXPECT_LT(test, out.r, 0x8000);
+
+   /* U 0 */
+   KUNIT_EXPECT_LT(test, out.g, 0x0100);
+
+   /* V 0 */
+   KUNIT_EXPECT_LT(test, out.b, 0x0100);
+
+   /* == red 255 - bt709 enc == */
+   out.a = 0x;
+   out.r = 0x;
+   out.g = 0x0;
+   out.b = 0x0;
+
+   apply_3x4_matrix(, _matrix_3x4_bt709_enc);
+
+   /* Y 54 */
+   KUNIT_EXPECT_GT(test, out.r, 0x3500);
+   KUNIT_EXPECT_LT(test, out.r, 0x3700);
+
+   /* U 0 */
+   KUNIT_EXPECT_LT(test, out.g, 0x0100);
+
+   /* V 157 */
+   KUNIT_EXPECT_GT(test, out.b, 0x9C00);
+   KUNIT_EXPECT_LT(test, out.b, 0x9E00);
+
+
+   /* == green 255 - bt709 enc == */
+   out.a = 0x;
+   

[RFC PATCH v4 26/42] drm/colorop: pass plane_color_pipeline client cap to atomic check

2024-02-26 Thread Harry Wentland
Drivers will need to know whether an atomic check/commit
originated from a client with DRM_CLIENT_CAP_PLANE_COLOR_PIPELINE
so they can ignore deprecated properties, like COLOR_ENCODING
and COLOR_RANGE.

Pass the plane_color_pipeline bit to drm_atomic_state.

Signed-off-by: Harry Wentland 
---
 drivers/gpu/drm/drm_atomic_uapi.c |  1 +
 include/drm/drm_atomic.h  | 17 +
 2 files changed, 18 insertions(+)

diff --git a/drivers/gpu/drm/drm_atomic_uapi.c 
b/drivers/gpu/drm/drm_atomic_uapi.c
index 23b248987a7c..c7c1c614b0d9 100644
--- a/drivers/gpu/drm/drm_atomic_uapi.c
+++ b/drivers/gpu/drm/drm_atomic_uapi.c
@@ -1571,6 +1571,7 @@ int drm_mode_atomic_ioctl(struct drm_device *dev,
drm_modeset_acquire_init(, DRM_MODESET_ACQUIRE_INTERRUPTIBLE);
state->acquire_ctx = 
state->allow_modeset = !!(arg->flags & DRM_MODE_ATOMIC_ALLOW_MODESET);
+   state->plane_color_pipeline = file_priv->plane_color_pipeline;
 
 retry:
copied_objs = 0;
diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
index 2346f19eda9f..61e6b5553eec 100644
--- a/include/drm/drm_atomic.h
+++ b/include/drm/drm_atomic.h
@@ -404,6 +404,23 @@ struct drm_atomic_state {
 * states.
 */
bool duplicated : 1;
+
+   /**
+* @plane_color_pipeline : 1
+*
+* Indicates whether this atomic state originated with a client that
+* set the DRM_CLIENT_CAP_PLANE_COLOR_PIPELINE.
+*
+* Drivers and helper functions should use this to ignore legacy
+* properties that are incompatible with the drm_plane COLOR_PIPELINE
+* behavior, such as
+*  - COLOR_RANGE
+*  - COLOR_ENCODING
+* or any other driver-specific properties that might affect pixel
+* values.
+*/
+   bool plane_color_pipeline : 1;
+
struct __drm_colorops_state *colorops;
struct __drm_planes_state *planes;
struct __drm_crtcs_state *crtcs;
-- 
2.44.0



[RFC PATCH v4 35/42] drm/amd/display: Enable support for PQ 125 EOTF and Inverse

2024-02-26 Thread Harry Wentland
This patchset enables support for the PQ_125 EOTF and its inverse
on all existing plane 1D curve colorops, i.e., on DEGAM, SHAPER,
and BLND blocks.

With this patchset the following IGT subtests are passing:
kms_colorop --run plane-XR30-XR30-pq_125_eotf
kms_colorop --run plane-XR30-XR30-pq_125_inv_eotf
kms_colorop --run plane-XR30-XR30-pq_125_eotf-pq_125_inv_eotf
kms_colorop --run plane-XR30-XR30-pq_125_eotf-pq_125_inv_eotf-pq_125_eotf

Signed-off-by: Harry Wentland 
---
 .../amd/display/amdgpu_dm/amdgpu_dm_color.c   | 20 +--
 .../amd/display/amdgpu_dm/amdgpu_dm_colorop.c |  8 +---
 2 files changed, 19 insertions(+), 9 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 3e3ae2b58b06..20b7eb47388c 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
@@ -25,6 +25,7 @@
 #include "amdgpu.h"
 #include "amdgpu_mode.h"
 #include "amdgpu_dm.h"
+#include "amdgpu_dm_colorop.h"
 #include "dc.h"
 #include "modules/color/color_gamma.h"
 #include "basics/conversion.h"
@@ -676,6 +677,9 @@ amdgpu_colorop_tf_to_dc_tf(enum drm_colorop_curve_1d_type 
tf)
case DRM_COLOROP_1D_CURVE_SRGB_EOTF:
case DRM_COLOROP_1D_CURVE_SRGB_INV_EOTF:
return TRANSFER_FUNCTION_SRGB;
+   case DRM_COLOROP_1D_CURVE_PQ_125_EOTF:
+   case DRM_COLOROP_1D_CURVE_PQ_125_INV_EOTF:
+   return TRANSFER_FUNCTION_PQ;
default:
return TRANSFER_FUNCTION_LINEAR;;
}
@@ -1158,8 +1162,10 @@ __set_colorop_in_tf_1d_curve(struct dc_plane_state 
*dc_plane_state,
struct drm_colorop *colorop = colorop_state->colorop;
struct drm_device *drm = colorop->dev;
 
-   if (colorop->type != DRM_COLOROP_1D_CURVE &&
-   colorop_state->curve_1d_type != DRM_COLOROP_1D_CURVE_SRGB_EOTF)
+   if (colorop->type != DRM_COLOROP_1D_CURVE)
+   return -EINVAL;
+
+   if (!(BIT(colorop_state->curve_1d_type) & 
amdgpu_dm_supported_degam_tfs))
return -EINVAL;
 
if (colorop_state->bypass) {
@@ -1191,7 +1197,7 @@ __set_dm_plane_colorop_degamma(struct drm_plane_state 
*plane_state,
/* 1st op: 1d curve - degamma */
for_each_new_colorop_in_state(state, colorop, new_colorop_state, i) {
if (new_colorop_state->colorop == old_colorop &&
-   new_colorop_state->curve_1d_type == 
DRM_COLOROP_1D_CURVE_SRGB_EOTF) {
+   (BIT(new_colorop_state->curve_1d_type) & 
amdgpu_dm_supported_degam_tfs)) {
colorop_state = new_colorop_state;
break;
}
@@ -1213,8 +1219,10 @@ __set_colorop_in_shaper_1d_curve(struct dc_plane_state 
*dc_plane_state,
const struct drm_color_lut *shaper_lut;
uint32_t shaper_size;
 
-   if (colorop->type != DRM_COLOROP_1D_CURVE &&
-   colorop_state->curve_1d_type != DRM_COLOROP_1D_CURVE_SRGB_INV_EOTF)
+   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) {
@@ -1250,7 +1258,7 @@ __set_dm_plane_colorop_shaper(struct drm_plane_state 
*plane_state,
/* 2nd op: 1d curve - shaper */
for_each_new_colorop_in_state(state, colorop, new_colorop_state, i) {
if (new_colorop_state->colorop == old_colorop &&
-   new_colorop_state->curve_1d_type == 
DRM_COLOROP_1D_CURVE_SRGB_INV_EOTF) {
+   (BIT(new_colorop_state->curve_1d_type) & 
amdgpu_dm_supported_shaper_tfs)) {
colorop_state = new_colorop_state;
break;
}
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_colorop.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_colorop.c
index 449a2ad6a184..f99d8e09d89b 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_colorop.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_colorop.c
@@ -32,10 +32,12 @@
 #include "amdgpu_dm_colorop.h"
 
 const u64 amdgpu_dm_supported_degam_tfs =
-   BIT(DRM_COLOROP_1D_CURVE_SRGB_EOTF);
+   BIT(DRM_COLOROP_1D_CURVE_SRGB_EOTF) |
+   BIT(DRM_COLOROP_1D_CURVE_PQ_125_EOTF);
 
- const u64 amdgpu_dm_supported_shaper_tfs =
-   BIT(DRM_COLOROP_1D_CURVE_SRGB_INV_EOTF);
+const u64 amdgpu_dm_supported_shaper_tfs =
+   BIT(DRM_COLOROP_1D_CURVE_SRGB_INV_EOTF) |
+   BIT(DRM_COLOROP_1D_CURVE_PQ_125_INV_EOTF);
 
 const u64 amdgpu_dm_supported_blnd_tfs =
BIT(DRM_COLOROP_1D_CURVE_SRGB_EOTF);
-- 
2.44.0



[RFC PATCH v4 28/42] drm/amd/display: Ignore deprecated props when plane_color_pipeline set

2024-02-26 Thread Harry Wentland
When the plane_color_pipeline bit is set we should ignore
deprecated properties, such as COLOR_RANGE and COLOR_ENCODING.

Signed-off-by: Harry Wentland 
---
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 4 
 1 file changed, 4 insertions(+)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index f6575d7dee97..47c6fd33fd60 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -4948,6 +4948,10 @@ fill_plane_color_attributes(const struct drm_plane_state 
*plane_state,
 
*color_space = COLOR_SPACE_SRGB;
 
+   /* Ignore properties when DRM_CLIENT_CAP_PLANE_COLOR_PIPELINE is set */
+   if (plane_state->state && plane_state->state->plane_color_pipeline)
+   return 0;
+
/* DRM color properties only affect non-RGB formats. */
if (format < SURFACE_PIXEL_FORMAT_VIDEO_BEGIN)
return 0;
-- 
2.44.0



[RFC PATCH v4 17/42] drm/vkms: Add enumerated 1D curve colorop

2024-02-26 Thread Harry Wentland
This patch introduces a VKMS color pipeline that includes two
drm_colorops for named transfer functions. For now the only ones
supported are sRGB EOTF, sRGB Inverse EOTF, and a Linear TF.
We will expand this in the future but I don't want to do so
without accompanying IGT tests.

We introduce a new vkms_luts.c file that hard-codes sRGB EOTF,
sRGB Inverse EOTF, and a linear EOTF LUT. These have been
generated with 256 entries each as IGT is currently testing
only 8 bpc surfaces. We will likely need higher precision
but I'm reluctant to make that change without clear indication
that we need it. We'll revisit and, if necessary, regenerate
the LUTs when we have IGT tests for higher precision buffers.

v4:
 - Drop _tf_ from color_pipeline init function
 - Pass supported TFs into colorop init
 - Create bypass pipeline in DRM helper (Pekka)

v2:
 - Add commit description
 - Fix sRGB EOTF LUT definition
 - Add linear and sRGB inverse EOTF LUTs

Signed-off-by: Harry Wentland 
Signed-off-by: Alex Hung 
---
 drivers/gpu/drm/vkms/Makefile|   4 +-
 drivers/gpu/drm/vkms/vkms_colorop.c  |  70 +++
 drivers/gpu/drm/vkms/vkms_composer.c |  45 ++
 drivers/gpu/drm/vkms/vkms_drv.h  |   4 +
 drivers/gpu/drm/vkms/vkms_luts.c | 802 +++
 drivers/gpu/drm/vkms/vkms_luts.h |  12 +
 drivers/gpu/drm/vkms/vkms_plane.c|   2 +
 7 files changed, 938 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/vkms/vkms_colorop.c
 create mode 100644 drivers/gpu/drm/vkms/vkms_luts.c
 create mode 100644 drivers/gpu/drm/vkms/vkms_luts.h

diff --git a/drivers/gpu/drm/vkms/Makefile b/drivers/gpu/drm/vkms/Makefile
index 1b28a6a32948..c38455c46be4 100644
--- a/drivers/gpu/drm/vkms/Makefile
+++ b/drivers/gpu/drm/vkms/Makefile
@@ -6,6 +6,8 @@ vkms-y := \
vkms_formats.o \
vkms_crtc.o \
vkms_composer.o \
-   vkms_writeback.o
+   vkms_writeback.o \
+   vkms_colorop.o \
+   vkms_luts.o
 
 obj-$(CONFIG_DRM_VKMS) += vkms.o
diff --git a/drivers/gpu/drm/vkms/vkms_colorop.c 
b/drivers/gpu/drm/vkms/vkms_colorop.c
new file mode 100644
index ..d2db366da6d3
--- /dev/null
+++ b/drivers/gpu/drm/vkms/vkms_colorop.c
@@ -0,0 +1,70 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#define MAX_COLOR_PIPELINES 5
+
+static const u64 supported_tfs =
+   BIT(DRM_COLOROP_1D_CURVE_SRGB_EOTF) |
+   BIT(DRM_COLOROP_1D_CURVE_SRGB_INV_EOTF);
+
+const int vkms_initialize_color_pipeline(struct drm_plane *plane, struct 
drm_prop_enum_list *list)
+{
+
+   struct drm_colorop *op, *prev_op;
+   struct drm_device *dev = plane->dev;
+   int ret;
+
+   /* 1st op: 1d curve */
+   op = kzalloc(sizeof(struct drm_colorop), GFP_KERNEL);
+   if (!op) {
+   DRM_ERROR("KMS: Failed to allocate colorop\n");
+   return -ENOMEM;
+   }
+
+   ret = drm_colorop_curve_1d_init(dev, op, plane, supported_tfs);
+   if (ret)
+   return ret;
+
+   list->type = op->base.id;
+   list->name = kasprintf(GFP_KERNEL, "Color Pipeline %d", op->base.id);
+
+   prev_op = op;
+
+   /* 2nd op: 1d curve */
+   op = kzalloc(sizeof(struct drm_colorop), GFP_KERNEL);
+   if (!op) {
+   DRM_ERROR("KMS: Failed to allocate colorop\n");
+   return -ENOMEM;
+   }
+
+   ret = drm_colorop_curve_1d_init(dev, op, plane, supported_tfs);
+   if (ret)
+   return ret;
+
+   drm_colorop_set_next_property(prev_op, op);
+
+   return 0;
+}
+
+int vkms_initialize_colorops(struct drm_plane *plane)
+{
+   struct drm_prop_enum_list pipelines[MAX_COLOR_PIPELINES];
+   int len = 0;
+   int ret;
+
+   /* Add color pipeline */
+   ret = vkms_initialize_color_pipeline(plane, &(pipelines[len]));
+   if (ret)
+   return ret;
+   len++;
+
+   /* Create COLOR_PIPELINE property and attach */
+   drm_plane_create_color_pipeline_property(plane, pipelines, len);
+
+   return 0;
+}
diff --git a/drivers/gpu/drm/vkms/vkms_composer.c 
b/drivers/gpu/drm/vkms/vkms_composer.c
index b90e446d5954..9493bdb1ba3f 100644
--- a/drivers/gpu/drm/vkms/vkms_composer.c
+++ b/drivers/gpu/drm/vkms/vkms_composer.c
@@ -12,6 +12,7 @@
 #include 
 
 #include "vkms_drv.h"
+#include "vkms_luts.h"
 
 static u16 pre_mul_blend_channel(u16 src, u16 dst, u16 alpha)
 {
@@ -163,6 +164,47 @@ static void apply_lut(const struct vkms_crtc_state 
*crtc_state, struct line_buff
}
 }
 
+static void pre_blend_color_transform(const struct vkms_plane_state 
*plane_state, struct line_buffer *output_buffer)
+{
+   struct drm_colorop *colorop = plane_state->base.base.color_pipeline;
+
+   while (colorop) {
+   struct drm_colorop_state *colorop_state;
+
+   if (!colorop)
+   return;
+
+   /* TODO 

[RFC PATCH v4 27/42] drm/colorop: define a new macro for_each_new_colorop_in_state

2024-02-26 Thread Harry Wentland
From: Alex Hung 

Create a new macro for_each_new_colorop_in_state to access new
drm_colorop_state updated from uapi.

Signed-off-by: Alex Hung 
---
 include/drm/drm_atomic.h | 20 
 1 file changed, 20 insertions(+)

diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
index 61e6b5553eec..a4c5ff99a515 100644
--- a/include/drm/drm_atomic.h
+++ b/include/drm/drm_atomic.h
@@ -979,6 +979,26 @@ void drm_state_dump(struct drm_device *dev, struct 
drm_printer *p);
  (new_colorop_state) = 
(__state)->colorops[__i].new_state, 1))
 
 
+/**
+ * for_each_new_colorop_in_state - iterate over all colorops in an atomic 
update
+ * @__state:  drm_atomic_state pointer
+ * @colorop:  drm_colorop iteration cursor
+ * @new_colorop_state:  drm_colorop_state iteration cursor for the new 
state
+ * @__i: int iteration cursor, for macro-internal use
+ *
+ * This iterates over all colorops in an atomic update, tracking new state. 
This is
+ * useful is useful in places where the state delta needs to be considered, for
+ * example in atomic check functions.
+ */
+#define for_each_new_colorop_in_state(__state, colorop, new_colorop_state, 
__i) \
+   for ((__i) = 0; \
+(__i) < (__state)->dev->mode_config.num_colorop;   \
+(__i)++)   \
+   for_each_if ((__state)->colorops[__i].ptr &&\
+((colorop) = (__state)->colorops[__i].ptr, \
+ (void)(colorop) /* Only to avoid 
unused-but-set-variable warning */, \
+ (new_colorop_state) = 
(__state)->colorops[__i].new_state, 1))
+
 /**
  * for_each_oldnew_plane_in_state - iterate over all planes in an atomic update
  * @__state:  drm_atomic_state pointer
-- 
2.44.0



[RFC PATCH v4 24/42] drm/tests: Add a few tests around drm_fixed.h

2024-02-26 Thread Harry Wentland
While working on the CTM implementation of VKMS I had to ascertain
myself of a few assumptions. One of those is whether drm_fixed.h
treats its numbers using signed-magnitude or twos-complement. It is
twos-complement.

In order to make someone else's day easier I am adding the
drm_test_int2fixp test that validates the above assumption.

I am also adding a test for the new sm2fixp function that converts
from a signed-magnitude fixed point to the twos-complement fixed
point.

Signed-off-by: Harry Wentland 
---
 drivers/gpu/drm/tests/Makefile|  3 +-
 drivers/gpu/drm/tests/drm_fixp_test.c | 69 +++
 2 files changed, 71 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/tests/drm_fixp_test.c

diff --git a/drivers/gpu/drm/tests/Makefile b/drivers/gpu/drm/tests/Makefile
index d6183b3d7688..98468f7908dd 100644
--- a/drivers/gpu/drm/tests/Makefile
+++ b/drivers/gpu/drm/tests/Makefile
@@ -19,6 +19,7 @@ obj-$(CONFIG_DRM_KUNIT_TEST) += \
drm_modes_test.o \
drm_plane_helper_test.o \
drm_probe_helper_test.o \
-   drm_rect_test.o
+   drm_rect_test.o \
+   drm_fixp_test.o
 
 CFLAGS_drm_mm_test.o := $(DISABLE_STRUCTLEAK_PLUGIN)
diff --git a/drivers/gpu/drm/tests/drm_fixp_test.c 
b/drivers/gpu/drm/tests/drm_fixp_test.c
new file mode 100644
index ..f420f173ff66
--- /dev/null
+++ b/drivers/gpu/drm/tests/drm_fixp_test.c
@@ -0,0 +1,69 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ */
+
+#include 
+#include 
+
+static void drm_test_sm2fixp(struct kunit *test)
+{
+   KUNIT_EXPECT_EQ(test, 0x7fffll, ((1LL << 63) - 1));
+
+   /* 1 */
+   KUNIT_EXPECT_EQ(test, drm_int2fixp(1), drm_sm2fixp(1ull << 
DRM_FIXED_POINT));
+
+   /* -1 */
+   KUNIT_EXPECT_EQ(test, drm_int2fixp(-1), drm_sm2fixp((1ull << 63) | 
(1ull << DRM_FIXED_POINT)));
+
+   /* 0.5 */
+   KUNIT_EXPECT_EQ(test, drm_fixp_from_fraction(1, 2), drm_sm2fixp(1ull << 
(DRM_FIXED_POINT - 1)));
+
+   /* -0.5 */
+   KUNIT_EXPECT_EQ(test, drm_fixp_from_fraction(-1, 2), drm_sm2fixp((1ull 
<< 63) | (1ull << (DRM_FIXED_POINT - 1;
+
+}
+
+static void drm_test_int2fixp(struct kunit *test)
+{
+   /* 1 */
+   KUNIT_EXPECT_EQ(test, 1ll << 32, drm_int2fixp(1));
+
+   /* -1 */
+   KUNIT_EXPECT_EQ(test, -(1ll << 32), drm_int2fixp(-1));
+
+   /* 1 + (-1) = 0 */
+   KUNIT_EXPECT_EQ(test, 0, drm_int2fixp(1) + drm_int2fixp(-1));
+
+   /* 1 / 2 */
+   KUNIT_EXPECT_EQ(test, 1ll << 31, drm_fixp_from_fraction(1, 2));
+
+   /* -0.5 */
+   KUNIT_EXPECT_EQ(test, -(1ll << 31), drm_fixp_from_fraction(-1, 2));
+
+   /* (1 / 2) + (-1) = 0.5 */
+   KUNIT_EXPECT_EQ(test, 1ll << 31, drm_fixp_from_fraction(-1, 2) + 
drm_int2fixp(1));
+
+   /* (1 / 2) - 1) = 0.5 */
+   KUNIT_EXPECT_EQ(test, -(1ll << 31), drm_fixp_from_fraction(1, 2) + 
drm_int2fixp(-1));
+
+   /* (1 / 2) - 1) = 0.5 */
+   KUNIT_EXPECT_EQ(test, -(1ll << 31), drm_fixp_from_fraction(1, 2) - 
drm_int2fixp(1));
+
+}
+
+static struct kunit_case drm_fixp_tests[] = {
+   KUNIT_CASE(drm_test_int2fixp),
+   KUNIT_CASE(drm_test_sm2fixp),
+   { }
+};
+
+static struct kunit_suite drm_rect_test_suite = {
+   .name = "drm_fixp",
+   .test_cases = drm_fixp_tests,
+};
+
+kunit_test_suite(drm_rect_test_suite);
+
+MODULE_AUTHOR("AMD");
+MODULE_LICENSE("GPL and additional rights");
\ No newline at end of file
-- 
2.44.0



[RFC PATCH v4 09/42] drm/colorop: Introduce new drm_colorop mode object

2024-02-26 Thread Harry Wentland
This patches introduces a new drm_colorop mode object. This
object represents color transformations and can be used to
define color pipelines.

We also introduce the drm_colorop_state here, as well as
various helpers and state tracking bits.

v4:
 - Drop IOCTL definitions (Pekka)
 - add missing declaration (Chaitanya Kumar Borah)

v3:
 - Drop TODO for lock (it's handled in drm_modeset_drop_locks)
   (Melissa)
 - Don't get plane state when getting colorop state
 - Make some functions static (kernel test robot)

Signed-off-by: Harry Wentland 
---
 drivers/gpu/drm/Makefile|   1 +
 drivers/gpu/drm/drm_atomic.c|  70 
 drivers/gpu/drm/drm_atomic_helper.c |  12 +++
 drivers/gpu/drm/drm_atomic_uapi.c   |  48 +
 drivers/gpu/drm/drm_colorop.c   | 152 ++
 drivers/gpu/drm/drm_mode_config.c   |   7 ++
 include/drm/drm_atomic.h|  82 +++
 include/drm/drm_atomic_uapi.h   |   1 +
 include/drm/drm_colorop.h   | 158 
 include/drm/drm_mode_config.h   |  18 
 include/drm/drm_plane.h |   2 +
 include/uapi/drm/drm_mode.h |   1 +
 12 files changed, 552 insertions(+)
 create mode 100644 drivers/gpu/drm/drm_colorop.c
 create mode 100644 include/drm/drm_colorop.h

diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 104b42df2e95..4b14dcbb6117 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -16,6 +16,7 @@ drm-y := \
drm_client.o \
drm_client_modeset.o \
drm_color_mgmt.o \
+   drm_colorop.o \
drm_connector.o \
drm_crtc.o \
drm_displayid.o \
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index a91737adf8e7..62e87e6a9653 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -42,6 +42,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include "drm_crtc_internal.h"
 #include "drm_internal.h"
@@ -108,6 +109,7 @@ void drm_atomic_state_default_release(struct 
drm_atomic_state *state)
kfree(state->connectors);
kfree(state->crtcs);
kfree(state->planes);
+   kfree(state->colorops);
kfree(state->private_objs);
 }
 EXPORT_SYMBOL(drm_atomic_state_default_release);
@@ -139,6 +141,10 @@ drm_atomic_state_init(struct drm_device *dev, struct 
drm_atomic_state *state)
sizeof(*state->planes), GFP_KERNEL);
if (!state->planes)
goto fail;
+   state->colorops = kcalloc(dev->mode_config.num_colorop,
+ sizeof(*state->colorops), GFP_KERNEL);
+   if (!state->colorops)
+   goto fail;
 
/*
 * Because drm_atomic_state can be committed asynchronously we need our
@@ -250,6 +256,20 @@ void drm_atomic_state_default_clear(struct 
drm_atomic_state *state)
state->planes[i].new_state = NULL;
}
 
+   for (i = 0; i < config->num_colorop; i++) {
+   struct drm_colorop *colorop = state->colorops[i].ptr;
+
+   if (!colorop)
+   continue;
+
+   drm_colorop_atomic_destroy_state(colorop,
+state->colorops[i].state);
+   state->colorops[i].ptr = NULL;
+   state->colorops[i].state = NULL;
+   state->colorops[i].old_state = NULL;
+   state->colorops[i].new_state = NULL;
+   }
+
for (i = 0; i < state->num_private_objs; i++) {
struct drm_private_obj *obj = state->private_objs[i].ptr;
 
@@ -571,6 +591,56 @@ drm_atomic_get_plane_state(struct drm_atomic_state *state,
 }
 EXPORT_SYMBOL(drm_atomic_get_plane_state);
 
+
+/**
+ * drm_atomic_get_colorop_state - get colorop state
+ * @state: global atomic state object
+ * @colorop: colorop to get state object for
+ *
+ * This function returns the colorop state for the given colorop, allocating it
+ * if needed. It will also grab the relevant plane lock to make sure that the
+ * state is consistent.
+ *
+ * Returns:
+ *
+ * Either the allocated state or the error code encoded into the pointer. When
+ * the error is EDEADLK then the w/w mutex code has detected a deadlock and the
+ * entire atomic sequence must be restarted. All other errors are fatal.
+ */
+struct drm_colorop_state *
+drm_atomic_get_colorop_state(struct drm_atomic_state *state,
+struct drm_colorop *colorop)
+{
+   int ret, index = drm_colorop_index(colorop);
+   struct drm_colorop_state *colorop_state;
+
+   WARN_ON(!state->acquire_ctx);
+
+   colorop_state = drm_atomic_get_existing_colorop_state(state, colorop);
+   if (colorop_state)
+   return colorop_state;
+
+   ret = drm_modeset_lock(>plane->mutex, state->acquire_ctx);
+   if (ret)
+  

[RFC PATCH v4 15/42] drm/plane: Add COLOR PIPELINE property

2024-02-26 Thread Harry Wentland
We're adding a new enum COLOR PIPELINE property. This
property will have entries for each COLOR PIPELINE by
referencing the DRM object ID of the first drm_colorop
of the pipeline. 0 disables the entire COLOR PIPELINE.

Userspace can use this to discover the available color
pipelines, as well as set the desired one. The color
pipelines are programmed via properties on the actual
drm_colorop objects.

v4:
 - Add pipeline property creation helper (Pekka)
 - Fix function comment for
   drm_atomic_set_colorop_for_plane (Pekka)
 - Always create Bypass pipeline (Pekka)
 - Add missing function declaration (Chaitanya Kumar Borah)

Signed-off-by: Harry Wentland 
---
 drivers/gpu/drm/drm_atomic.c  | 46 
 drivers/gpu/drm/drm_atomic_state_helper.c |  5 +++
 drivers/gpu/drm/drm_atomic_uapi.c | 42 ++
 drivers/gpu/drm/drm_plane.c   | 52 +++
 include/drm/drm_atomic.h  |  3 ++
 include/drm/drm_atomic_uapi.h |  2 +
 include/drm/drm_plane.h   | 11 +
 7 files changed, 161 insertions(+)

diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index 3645c36d63b3..27a8805c5fa1 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -1458,6 +1458,52 @@ drm_atomic_add_affected_planes(struct drm_atomic_state 
*state,
 }
 EXPORT_SYMBOL(drm_atomic_add_affected_planes);
 
+/**
+ * drm_atomic_add_affected_colorops - add colorops for plane
+ * @state: atomic state
+ * @plane: DRM plane
+ *
+ * This function walks the current configuration and adds all colorops
+ * currently used by @plane to the atomic configuration @state. This is useful
+ * when an atomic commit also needs to check all currently enabled colorop on
+ * @plane, e.g. when changing the mode. It's also useful when re-enabling a 
plane
+ * to avoid special code to force-enable all colorops.
+ *
+ * Since acquiring a colorop state will always also acquire the w/w mutex of 
the
+ * current plane for that colorop (if there is any) adding all the colorop 
states for
+ * a plane will not reduce parallelism of atomic updates.
+ *
+ * Returns:
+ * 0 on success or can fail with -EDEADLK or -ENOMEM. When the error is EDEADLK
+ * then the w/w mutex code has detected a deadlock and the entire atomic
+ * sequence must be restarted. All other errors are fatal.
+ */
+int
+drm_atomic_add_affected_colorops(struct drm_atomic_state *state,
+struct drm_plane *plane)
+{
+   struct drm_colorop *colorop;
+   struct drm_colorop_state *colorop_state;
+
+   WARN_ON(!drm_atomic_get_new_plane_state(state, plane));
+
+   drm_dbg_atomic(plane->dev,
+  "Adding all current colorops for [plane:%d:%s] to %p\n",
+  plane->base.id, plane->name, state);
+
+   drm_for_each_colorop(colorop, plane->dev) {
+   if (colorop->plane != plane)
+   continue;
+
+   colorop_state = drm_atomic_get_colorop_state(state, colorop);
+   if (IS_ERR(colorop_state))
+   return PTR_ERR(colorop_state);
+   }
+
+   return 0;
+}
+EXPORT_SYMBOL(drm_atomic_add_affected_colorops);
+
 /**
  * drm_atomic_check_only - check whether a given config would work
  * @state: atomic configuration to check
diff --git a/drivers/gpu/drm/drm_atomic_state_helper.c 
b/drivers/gpu/drm/drm_atomic_state_helper.c
index 519228eb1095..d1dd082b1286 100644
--- a/drivers/gpu/drm/drm_atomic_state_helper.c
+++ b/drivers/gpu/drm/drm_atomic_state_helper.c
@@ -267,6 +267,11 @@ void __drm_atomic_helper_plane_state_reset(struct 
drm_plane_state *plane_state,
plane_state->color_range = val;
}
 
+   if (plane->color_pipeline_property) {
+   /* default is always NULL, i.e., bypass */
+   plane_state->color_pipeline = NULL;
+   }
+
if (plane->zpos_property) {
if (!drm_object_property_get_default_value(>base,
   plane->zpos_property,
diff --git a/drivers/gpu/drm/drm_atomic_uapi.c 
b/drivers/gpu/drm/drm_atomic_uapi.c
index 87f00131be11..86f77a9aa3a8 100644
--- a/drivers/gpu/drm/drm_atomic_uapi.c
+++ b/drivers/gpu/drm/drm_atomic_uapi.c
@@ -256,6 +256,36 @@ drm_atomic_set_fb_for_plane(struct drm_plane_state 
*plane_state,
 }
 EXPORT_SYMBOL(drm_atomic_set_fb_for_plane);
 
+
+/**
+ * drm_atomic_set_colorop_for_plane - set colorop for plane
+ * @plane_state: atomic state object for the plane
+ * @colorop: colorop to use for the plane
+ *
+ * Helper function to select the color pipeline on a plane by setting
+ * it to the first drm_colorop element of the pipeline.
+ */
+void
+drm_atomic_set_colorop_for_plane(struct drm_plane_state *plane_state,
+struct drm_colorop *colorop)
+{
+   struct drm_plane *plane 

[RFC PATCH v4 22/42] drm/vkms: Use s32 for internal color pipeline precision

2024-02-26 Thread Harry Wentland
Certain operations require us to preserve values below 0.0 and
above 1.0 (0x0 and 0x respectively in 16 bpc unorm). One
such operation is a BT709 encoding operation followed by its
decoding operation, or the reverse.

We'll use s32 values as intermediate in and outputs of our
color operations, for the operations where it matters.

For now this won't apply to LUT operations. We might want to
update those to work on s32 as well, but it's unclear how
that should work for unorm LUT definitions. We'll revisit
that once we add LUT + CTM tests.

In order to allow for this we'll also invert the nesting of our
colorop processing loops. We now use the pixel iteration loop
on the outside and the colorop iteration on the inside.

v4:
 - Clarify that we're packing 16-bit UNORM into s32, not
   converting values to a different representation (Pekka)

v3:
 - Use new colorop->next pointer

Signed-off-by: Harry Wentland 
---
 drivers/gpu/drm/vkms/vkms_composer.c | 57 +---
 drivers/gpu/drm/vkms/vkms_drv.h  |  4 ++
 2 files changed, 48 insertions(+), 13 deletions(-)

diff --git a/drivers/gpu/drm/vkms/vkms_composer.c 
b/drivers/gpu/drm/vkms/vkms_composer.c
index 25b786b49db0..d2101fa55aa3 100644
--- a/drivers/gpu/drm/vkms/vkms_composer.c
+++ b/drivers/gpu/drm/vkms/vkms_composer.c
@@ -164,7 +164,7 @@ static void apply_lut(const struct vkms_crtc_state 
*crtc_state, struct line_buff
}
 }
 
-static void apply_colorop(struct pixel_argb_u16 *pixel, struct drm_colorop 
*colorop)
+static void apply_colorop(struct pixel_argb_s32 *pixel, struct drm_colorop 
*colorop)
 {
/* TODO is this right? */
struct drm_colorop_state *colorop_state = colorop->state;
@@ -191,25 +191,56 @@ static void apply_colorop(struct pixel_argb_u16 *pixel, 
struct drm_colorop *colo
 
 static void pre_blend_color_transform(const struct vkms_plane_state 
*plane_state, struct line_buffer *output_buffer)
 {
-   struct drm_colorop *colorop = plane_state->base.base.color_pipeline;
+   struct drm_colorop *colorop;
+   struct pixel_argb_s32 pixel;
 
-   while (colorop) {
-   struct drm_colorop_state *colorop_state;
+   for (size_t x = 0; x < output_buffer->n_pixels; x++) {
 
-   if (!colorop)
-   return;
+   /*
+* Some operations, such as applying a BT709 encoding matrix,
+* followed by a decoding matrix, require that we preserve
+* values above 1.0 and below 0.0 until the end of the pipeline.
+*
+* Pack the 16-bit UNORM values into s32 to give us head-room to
+* avoid clipping until we're at the end of the pipeline. Clip
+* intentionally at the end of the pipeline before packing
+* UNORM values back into u16.
+*/
+   pixel.a = output_buffer->pixels[x].a;
+   pixel.r = output_buffer->pixels[x].r;
+   pixel.g = output_buffer->pixels[x].g;
+   pixel.b = output_buffer->pixels[x].b;
 
-   /* TODO this is probably wrong */
-   colorop_state = colorop->state;
+   colorop = plane_state->base.base.color_pipeline;
+   while (colorop) {
+   struct drm_colorop_state *colorop_state;
 
-   if (!colorop_state)
-   return;
+   if (!colorop)
+   return;
+
+   /* TODO this is probably wrong */
+   colorop_state = colorop->state;
+
+   if (!colorop_state)
+   return;
 
-   for (size_t x = 0; x < output_buffer->n_pixels; x++)
if (!colorop_state->bypass)
-   apply_colorop(_buffer->pixels[x], 
colorop);
+   apply_colorop(, colorop);
 
-   colorop = colorop->next;
+   colorop = colorop->next;
+   }
+
+   /* clamp pixel */
+   pixel.a = max(min(pixel.a, 0x), 0x0);
+   pixel.r = max(min(pixel.r, 0x), 0x0);
+   pixel.g = max(min(pixel.g, 0x), 0x0);
+   pixel.b = max(min(pixel.b, 0x), 0x0);
+
+   /* put back to output_buffer */
+   output_buffer->pixels[x].a = pixel.a;
+   output_buffer->pixels[x].r = pixel.r;
+   output_buffer->pixels[x].g = pixel.g;
+   output_buffer->pixels[x].b = pixel.b;
}
 }
 
diff --git a/drivers/gpu/drm/vkms/vkms_drv.h b/drivers/gpu/drm/vkms/vkms_drv.h
index 2bcc24c196a2..fadb7685a360 100644
--- a/drivers/gpu/drm/vkms/vkms_drv.h
+++ b/drivers/gpu/drm/vkms/vkms_drv.h
@@ -36,6 +36,10 @@ struct vkms_frame_info {
unsigned int cpp;
 };
 
+struct pixel_argb_s32 {
+   s32

[RFC PATCH v4 21/42] drm/vkms: Pull apply_colorop out of pre_blend_color_transform

2024-02-26 Thread Harry Wentland
The if/switch statement is bound to grow with more types and
subtypes. Pull this out into its own funcion to make things more
manageable and readable.

Signed-off-by: Harry Wentland 
---
 drivers/gpu/drm/vkms/vkms_composer.c | 48 
 1 file changed, 28 insertions(+), 20 deletions(-)

diff --git a/drivers/gpu/drm/vkms/vkms_composer.c 
b/drivers/gpu/drm/vkms/vkms_composer.c
index 9493bdb1ba3f..25b786b49db0 100644
--- a/drivers/gpu/drm/vkms/vkms_composer.c
+++ b/drivers/gpu/drm/vkms/vkms_composer.c
@@ -164,6 +164,31 @@ static void apply_lut(const struct vkms_crtc_state 
*crtc_state, struct line_buff
}
 }
 
+static void apply_colorop(struct pixel_argb_u16 *pixel, struct drm_colorop 
*colorop)
+{
+   /* TODO is this right? */
+   struct drm_colorop_state *colorop_state = colorop->state;
+
+   if (colorop->type == DRM_COLOROP_1D_CURVE) {
+   switch (colorop_state->curve_1d_type) {
+   case DRM_COLOROP_1D_CURVE_SRGB_INV_EOTF:
+   pixel->r = 
apply_lut_to_channel_value(_inv_eotf, pixel->r, LUT_RED);
+   pixel->g = 
apply_lut_to_channel_value(_inv_eotf, pixel->g, LUT_GREEN);
+   pixel->b = 
apply_lut_to_channel_value(_inv_eotf, pixel->b, LUT_BLUE);
+   break;
+   case DRM_COLOROP_1D_CURVE_SRGB_EOTF:
+   pixel->r = 
apply_lut_to_channel_value(_eotf, pixel->r, LUT_RED);
+   pixel->g = 
apply_lut_to_channel_value(_eotf, pixel->g, LUT_GREEN);
+   pixel->b = 
apply_lut_to_channel_value(_eotf, pixel->b, LUT_BLUE);
+   break;
+   default:
+   DRM_DEBUG_DRIVER("unkown colorop 1D curve type 
%d\n", colorop_state->curve_1d_type);
+   break;
+   }
+   }
+
+}
+
 static void pre_blend_color_transform(const struct vkms_plane_state 
*plane_state, struct line_buffer *output_buffer)
 {
struct drm_colorop *colorop = plane_state->base.base.color_pipeline;
@@ -180,26 +205,9 @@ static void pre_blend_color_transform(const struct 
vkms_plane_state *plane_state
if (!colorop_state)
return;
 
-   for (size_t x = 0; x < output_buffer->n_pixels; x++) {
-   struct pixel_argb_u16 *pixel = 
_buffer->pixels[x];
-
-   if (colorop->type == DRM_COLOROP_1D_CURVE &&
-   colorop_state->bypass == false) {
-   switch (colorop_state->curve_1d_type) {
-   case DRM_COLOROP_1D_CURVE_SRGB_INV_EOTF:
-   pixel->r = 
apply_lut_to_channel_value(_inv_eotf, pixel->r, LUT_RED);
-   pixel->g = 
apply_lut_to_channel_value(_inv_eotf, pixel->g, LUT_GREEN);
-   pixel->b = 
apply_lut_to_channel_value(_inv_eotf, pixel->b, LUT_BLUE);
-   break;
-   case DRM_COLOROP_1D_CURVE_SRGB_EOTF:
-   default:
-   pixel->r = 
apply_lut_to_channel_value(_eotf, pixel->r, LUT_RED);
-   pixel->g = 
apply_lut_to_channel_value(_eotf, pixel->g, LUT_GREEN);
-   pixel->b = 
apply_lut_to_channel_value(_eotf, pixel->b, LUT_BLUE);
-   break;
-   }
-   }
-   }
+   for (size_t x = 0; x < output_buffer->n_pixels; x++)
+   if (!colorop_state->bypass)
+   apply_colorop(_buffer->pixels[x], 
colorop);
 
colorop = colorop->next;
}
-- 
2.44.0



[RFC PATCH v4 01/42] drm: Don't treat 0 as -1 in drm_fixp2int_ceil

2024-02-26 Thread Harry Wentland
Unit testing this in VKMS shows that passing 0 into
this function returns -1, which is highly counter-
intuitive. Fix it by checking whether the input is
>= 0 instead of > 0.

Fixes: 64566b5e767f9 ("drm: Add drm_fixp_from_fraction and drm_fixp2int_ceil")
Signed-off-by: Harry Wentland 
Reviewed-by: Simon Ser 
Reviewed-by: Melissa Wen 
---
 include/drm/drm_fixed.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/include/drm/drm_fixed.h b/include/drm/drm_fixed.h
index 6ea339d5de08..0c9f917a4d4b 100644
--- a/include/drm/drm_fixed.h
+++ b/include/drm/drm_fixed.h
@@ -95,7 +95,7 @@ static inline int drm_fixp2int_round(s64 a)
 
 static inline int drm_fixp2int_ceil(s64 a)
 {
-   if (a > 0)
+   if (a >= 0)
return drm_fixp2int(a + DRM_FIXED_ALMOST_ONE);
else
return drm_fixp2int(a - DRM_FIXED_ALMOST_ONE);
-- 
2.44.0



[RFC PATCH v4 04/42] drm/vkms: Round fixp2int conversion in lerp_u16

2024-02-26 Thread Harry Wentland
fixp2int always rounds down, fixp2int_ceil rounds up. We need
the new fixp2int_round.

Signed-off-by: Harry Wentland 
---
 drivers/gpu/drm/vkms/vkms_composer.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/vkms/vkms_composer.c 
b/drivers/gpu/drm/vkms/vkms_composer.c
index 3c99fb8b54e2..e70cd473e3be 100644
--- a/drivers/gpu/drm/vkms/vkms_composer.c
+++ b/drivers/gpu/drm/vkms/vkms_composer.c
@@ -98,7 +98,7 @@ static u16 lerp_u16(u16 a, u16 b, s64 t)
 
s64 delta = drm_fixp_mul(b_fp - a_fp,  t);
 
-   return drm_fixp2int(a_fp + delta);
+   return drm_fixp2int_round(a_fp + delta);
 }
 
 static s64 get_lut_index(const struct vkms_color_lut *lut, u16 channel_value)
-- 
2.44.0



[RFC PATCH v4 13/42] drm/colorop: Add NEXT property

2024-02-26 Thread Harry Wentland
We'll construct color pipelines out of drm_colorop by
chaining them via the NEXT pointer. NEXT will point to
the next drm_colorop in the pipeline, or by 0 if we're
at the end of the pipeline.

v4:
 - Allow setting of NEXT property to NULL (Chaitanya Kumar Borah)

v3:
 - Add next pointer to colorop to be used by drivers
   and in DRM core

Signed-off-by: Harry Wentland 
---
 drivers/gpu/drm/drm_colorop.c | 29 +
 include/drm/drm_colorop.h | 20 
 2 files changed, 49 insertions(+)

diff --git a/drivers/gpu/drm/drm_colorop.c b/drivers/gpu/drm/drm_colorop.c
index 29979816a2d1..71c2286333a1 100644
--- a/drivers/gpu/drm/drm_colorop.c
+++ b/drivers/gpu/drm/drm_colorop.c
@@ -59,6 +59,7 @@ int drm_colorop_init(struct drm_device *dev, struct 
drm_colorop *colorop,
colorop->dev = dev;
colorop->type = type;
colorop->plane = plane;
+   colorop->next = NULL;
 
list_add_tail(>head, >colorop_list);
colorop->index = config->num_colorop++;
@@ -92,6 +93,15 @@ int drm_colorop_init(struct drm_device *dev, struct 
drm_colorop *colorop,
   colorop->bypass_property,
   1);
 
+   prop = drm_property_create_object(dev, DRM_MODE_PROP_IMMUTABLE | 
DRM_MODE_PROP_ATOMIC,
+ "NEXT", DRM_MODE_OBJECT_COLOROP);
+   if (!prop)
+   return -ENOMEM;
+   colorop->next_property = prop;
+   drm_object_attach_property(>base,
+  colorop->next_property,
+  0);
+
return ret;
 }
 EXPORT_SYMBOL(drm_colorop_init);
@@ -279,3 +289,22 @@ const char *drm_get_colorop_curve_1d_type_name(enum 
drm_colorop_curve_1d_type ty
 
return colorop_curve_1d_type_names[type];
 }
+
+/**
+ * drm_colorop_set_next_property - sets the next pointer
+ * @colorop: drm colorop
+ * @next: next colorop
+ *
+ * Should be used when constructing the color pipeline
+ */
+void drm_colorop_set_next_property(struct drm_colorop *colorop, struct 
drm_colorop *next)
+{
+   if (!colorop->next_property)
+   return;
+
+   drm_object_property_set_value(>base,
+ colorop->next_property,
+ next ? next->base.id : 0);
+   colorop->next = next;
+}
+EXPORT_SYMBOL(drm_colorop_set_next_property);
diff --git a/include/drm/drm_colorop.h b/include/drm/drm_colorop.h
index 28aa5c1c309e..8060988b5892 100644
--- a/include/drm/drm_colorop.h
+++ b/include/drm/drm_colorop.h
@@ -132,6 +132,14 @@ struct drm_colorop {
 */
enum drm_colorop_type type;
 
+   /**
+* @next:
+*
+* Read-only
+* Pointer to next drm_colorop in pipeline
+*/
+   struct drm_colorop *next;
+
/**
 * @type_property:
 *
@@ -159,10 +167,20 @@ struct drm_colorop {
 */
struct drm_property *curve_1d_type_property;
 
+   /**
+* @next_property
+*
+* Read-only property to next colorop in the pipeline
+*/
+   struct drm_property *next_property;
+
 };
 
 #define obj_to_colorop(x) container_of(x, struct drm_colorop, base)
 
+
+
+
 /**
  * drm_crtc_find - look up a Colorop object from its ID
  * @dev: DRM device
@@ -213,5 +231,7 @@ static inline unsigned int drm_colorop_index(const struct 
drm_colorop *colorop)
 #define drm_for_each_colorop(colorop, dev) \
list_for_each_entry(colorop, &(dev)->mode_config.colorop_list, head)
 
+void drm_colorop_set_next_property(struct drm_colorop *colorop, struct 
drm_colorop *next);
+
 
 #endif /* __DRM_COLOROP_H__ */
-- 
2.44.0



[RFC PATCH v4 14/42] drm/colorop: Add atomic state print for drm_colorop

2024-02-26 Thread Harry Wentland
Signed-off-by: Harry Wentland 
---
 drivers/gpu/drm/drm_atomic.c | 25 -
 include/drm/drm_colorop.h|  5 +
 2 files changed, 29 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index b400e32c9d39..3645c36d63b3 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -783,6 +783,19 @@ static int drm_atomic_plane_check(const struct 
drm_plane_state *old_plane_state,
return 0;
 }
 
+
+
+static void drm_atomic_colorop_print_state(struct drm_printer *p,
+   const struct drm_colorop_state *state)
+{
+   struct drm_colorop *colorop = state->colorop;
+
+   drm_printf(p, "colorop[%u]:\n", colorop->base.id);
+   drm_printf(p, "\ttype=%s\n", drm_get_colorop_type_name(colorop->type));
+   drm_printf(p, "\tbypass=%u\n", state->bypass);
+   drm_printf(p, "\tcurve_1d_type=%s\n", 
drm_get_colorop_curve_1d_type_name(state->curve_1d_type));
+}
+
 static void drm_atomic_plane_print_state(struct drm_printer *p,
const struct drm_plane_state *state)
 {
@@ -804,7 +817,8 @@ static void drm_atomic_plane_print_state(struct drm_printer 
*p,
drm_printf(p, "\tcolor-range=%s\n",
   drm_get_color_range_name(state->color_range));
drm_printf(p, "\tcolor_mgmt_changed=%d\n", state->color_mgmt_changed);
-
+   drm_printf(p, "\tcolor-pipeline=%d\n",
+  state->color_pipeline ? state->color_pipeline->base.id : 0);
if (plane->funcs->atomic_print_state)
plane->funcs->atomic_print_state(p, state);
 }
@@ -1840,6 +1854,7 @@ static void __drm_state_dump(struct drm_device *dev, 
struct drm_printer *p,
 bool take_locks)
 {
struct drm_mode_config *config = >mode_config;
+   struct drm_colorop *colorop;
struct drm_plane *plane;
struct drm_crtc *crtc;
struct drm_connector *connector;
@@ -1849,6 +1864,14 @@ static void __drm_state_dump(struct drm_device *dev, 
struct drm_printer *p,
if (!drm_drv_uses_atomic_modeset(dev))
return;
 
+   list_for_each_entry(colorop, >colorop_list, head) {
+   if (take_locks)
+   drm_modeset_lock(>plane->mutex, NULL);
+   drm_atomic_colorop_print_state(p, colorop->state);
+   if (take_locks)
+   drm_modeset_unlock(>plane->mutex);
+   }
+
list_for_each_entry(plane, >plane_list, head) {
if (take_locks)
drm_modeset_lock(>mutex, NULL);
diff --git a/include/drm/drm_colorop.h b/include/drm/drm_colorop.h
index 8060988b5892..fc9a28d138b8 100644
--- a/include/drm/drm_colorop.h
+++ b/include/drm/drm_colorop.h
@@ -231,6 +231,11 @@ static inline unsigned int drm_colorop_index(const struct 
drm_colorop *colorop)
 #define drm_for_each_colorop(colorop, dev) \
list_for_each_entry(colorop, &(dev)->mode_config.colorop_list, head)
 
+const char *drm_get_color_pipeline_name(struct drm_colorop *colorop);
+
+const char *drm_get_colorop_type_name(enum drm_colorop_type type);
+const char *drm_get_colorop_curve_1d_type_name(enum drm_colorop_curve_1d_type 
type);
+
 void drm_colorop_set_next_property(struct drm_colorop *colorop, struct 
drm_colorop *next);
 
 
-- 
2.44.0



[RFC PATCH v4 10/42] drm/colorop: Add TYPE property

2024-02-26 Thread Harry Wentland
Add a read-only TYPE property. The TYPE specifies the colorop
type, such as enumerated curve, 1D LUT, CTM, 3D LUT, PWL LUT,
etc.

v4:
 - Use enum property for TYPE (Pekka)

v3:
 - Make TYPE a range property
 - Move enum drm_colorop_type to uapi header
 - Fix drm_get_colorop_type_name description

For now we're only introducing an enumerated 1D LUT type to
illustrate the concept.

Signed-off-by: Harry Wentland 
---
 drivers/gpu/drm/drm_atomic.c  |  4 +--
 drivers/gpu/drm/drm_atomic_uapi.c |  8 +-
 drivers/gpu/drm/drm_colorop.c | 44 ++-
 include/drm/drm_colorop.h | 17 +++-
 include/uapi/drm/drm_mode.h   |  4 +++
 5 files changed, 72 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index 62e87e6a9653..b400e32c9d39 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -634,8 +634,8 @@ drm_atomic_get_colorop_state(struct drm_atomic_state *state,
state->colorops[index].new_state = colorop_state;
colorop_state->state = state;
 
-   drm_dbg_atomic(colorop->dev, "Added [COLOROP:%d] %p state to %p\n",
-  colorop->base.id, colorop_state, state);
+   drm_dbg_atomic(colorop->dev, "Added [COLOROP:%d:%d] %p state to %p\n",
+  colorop->base.id, colorop->type, colorop_state, state);
 
return colorop_state;
 }
diff --git a/drivers/gpu/drm/drm_atomic_uapi.c 
b/drivers/gpu/drm/drm_atomic_uapi.c
index 1f9b6dfa8ca7..e3067c095c72 100644
--- a/drivers/gpu/drm/drm_atomic_uapi.c
+++ b/drivers/gpu/drm/drm_atomic_uapi.c
@@ -660,7 +660,13 @@ drm_atomic_colorop_get_property(struct drm_colorop 
*colorop,
const struct drm_colorop_state *state,
struct drm_property *property, uint64_t *val)
 {
-   return -EINVAL;
+   if (property == colorop->type_property) {
+   *val = colorop->type;
+   } else {
+   return -EINVAL;
+   }
+
+   return 0;
 }
 
 static int drm_atomic_set_writeback_fb_for_connector(
diff --git a/drivers/gpu/drm/drm_colorop.c b/drivers/gpu/drm/drm_colorop.c
index a295ab96aee1..3a07a8fe2842 100644
--- a/drivers/gpu/drm/drm_colorop.c
+++ b/drivers/gpu/drm/drm_colorop.c
@@ -32,12 +32,17 @@
 
 /* TODO big colorop doc, including properties, etc. */
 
+static const struct drm_prop_enum_list drm_colorop_type_enum_list[] = {
+   { DRM_COLOROP_1D_CURVE, "1D Curve" },
+};
+
 /* Init Helpers */
 
 int drm_colorop_init(struct drm_device *dev, struct drm_colorop *colorop,
-struct drm_plane *plane)
+struct drm_plane *plane, enum drm_colorop_type type)
 {
struct drm_mode_config *config = >mode_config;
+   struct drm_property *prop;
int ret = 0;
 
ret = drm_mode_object_add(dev, >base, DRM_MODE_OBJECT_COLOROP);
@@ -46,12 +51,29 @@ int drm_colorop_init(struct drm_device *dev, struct 
drm_colorop *colorop,
 
colorop->base.properties = >properties;
colorop->dev = dev;
+   colorop->type = type;
colorop->plane = plane;
 
list_add_tail(>head, >colorop_list);
colorop->index = config->num_colorop++;
 
/* add properties */
+
+   /* type */
+   prop = drm_property_create_enum(dev,
+   DRM_MODE_PROP_IMMUTABLE,
+   "TYPE", drm_colorop_type_enum_list,
+   ARRAY_SIZE(drm_colorop_type_enum_list));
+
+   if (!prop)
+   return -ENOMEM;
+
+   colorop->type_property = prop;
+
+   drm_object_attach_property(>base,
+  colorop->type_property,
+  colorop->type);
+
return ret;
 }
 EXPORT_SYMBOL(drm_colorop_init);
@@ -150,3 +172,23 @@ void drm_colorop_reset(struct drm_colorop *colorop)
__drm_colorop_reset(colorop, colorop->state);
 }
 EXPORT_SYMBOL(drm_colorop_reset);
+
+
+static const char * const colorop_type_name[] = {
+   [DRM_COLOROP_1D_CURVE] = "1D Curve",
+};
+
+/**
+ * drm_get_colorop_type_name - return a string for colorop type
+ * @type: colorop type to compute name of
+ *
+ * In contrast to the other drm_get_*_name functions this one here returns a
+ * const pointer and hence is threadsafe.
+ */
+const char *drm_get_colorop_type_name(enum drm_colorop_type type)
+{
+   if (WARN_ON(type >= ARRAY_SIZE(colorop_type_name)))
+   return "unknown";
+
+   return colorop_type_name[type];
+}
diff --git a/include/drm/drm_colorop.h b/include/drm/drm_colorop.h
index e611f830f986..cb98c55f8387 100644
--- a/include/drm/drm_colorop.h
+++ b/include/drm/drm_colorop.h
@@ -103,6 +103,21 @@ struct drm_colorop {
/** @properties: property tracking for this plane */
s

[RFC PATCH v4 12/42] drm/colorop: Add BYPASS property

2024-02-26 Thread Harry Wentland
We want to be able to bypass each colorop at all times.
Introduce a new BYPASS boolean property for this.

Signed-off-by: Harry Wentland 
---
 drivers/gpu/drm/drm_atomic_uapi.c |  6 +-
 drivers/gpu/drm/drm_colorop.c | 16 
 include/drm/drm_colorop.h | 20 
 3 files changed, 41 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/drm_atomic_uapi.c 
b/drivers/gpu/drm/drm_atomic_uapi.c
index fdd540cfe24f..87f00131be11 100644
--- a/drivers/gpu/drm/drm_atomic_uapi.c
+++ b/drivers/gpu/drm/drm_atomic_uapi.c
@@ -648,7 +648,9 @@ static int drm_atomic_colorop_set_property(struct 
drm_colorop *colorop,
struct drm_colorop_state *state, struct drm_file *file_priv,
struct drm_property *property, uint64_t val)
 {
-   if (property == colorop->curve_1d_type_property) {
+   if (property == colorop->bypass_property) {
+   state->bypass = val;
+   } else if (property == colorop->curve_1d_type_property) {
state->curve_1d_type = val;
} else {
drm_dbg_atomic(colorop->dev,
@@ -668,6 +670,8 @@ drm_atomic_colorop_get_property(struct drm_colorop *colorop,
 {
if (property == colorop->type_property) {
*val = colorop->type;
+   } else if (property == colorop->bypass_property) {
+   *val = state->bypass;
} else if (property == colorop->curve_1d_type_property) {
*val = state->curve_1d_type;
} else {
diff --git a/drivers/gpu/drm/drm_colorop.c b/drivers/gpu/drm/drm_colorop.c
index f4740b6115d1..29979816a2d1 100644
--- a/drivers/gpu/drm/drm_colorop.c
+++ b/drivers/gpu/drm/drm_colorop.c
@@ -80,6 +80,18 @@ int drm_colorop_init(struct drm_device *dev, struct 
drm_colorop *colorop,
   colorop->type_property,
   colorop->type);
 
+   /* bypass */
+   /* TODO can we reuse the mode_config->active_prop? */
+   prop = drm_property_create_bool(dev, DRM_MODE_PROP_ATOMIC,
+   "BYPASS");
+   if (!prop)
+   return -ENOMEM;
+
+   colorop->bypass_property = prop;
+   drm_object_attach_property(>base,
+  colorop->bypass_property,
+  1);
+
return ret;
 }
 EXPORT_SYMBOL(drm_colorop_init);
@@ -123,6 +135,7 @@ int drm_colorop_curve_1d_init(struct drm_device *dev, 
struct drm_colorop *coloro
/* initialize 1D curve only attribute */
prop = drm_property_create_enum(dev, DRM_MODE_PROP_ATOMIC, 
"CURVE_1D_TYPE",
enum_list, len);
+
if (!prop)
return -ENOMEM;
 
@@ -138,6 +151,8 @@ static void 
__drm_atomic_helper_colorop_duplicate_state(struct drm_colorop *colo
struct 
drm_colorop_state *state)
 {
memcpy(state, colorop->state, sizeof(*state));
+
+   state->bypass = true;
 }
 
 struct drm_colorop_state *
@@ -189,6 +204,7 @@ static void __drm_colorop_state_reset(struct 
drm_colorop_state *colorop_state,
  struct drm_colorop *colorop)
 {
colorop_state->colorop = colorop;
+   colorop_state->bypass = true;
 }
 
 /**
diff --git a/include/drm/drm_colorop.h b/include/drm/drm_colorop.h
index 539db900f16f..28aa5c1c309e 100644
--- a/include/drm/drm_colorop.h
+++ b/include/drm/drm_colorop.h
@@ -45,6 +45,14 @@ struct drm_colorop_state {
 
/* colorop properties */
 
+   /**
+* @bypass:
+*
+* True if colorop shall be bypassed. False if colorop is
+* enabled.
+*/
+   bool bypass;
+
/**
 * @curve_1d_type:
 *
@@ -132,6 +140,18 @@ struct drm_colorop {
 */
struct drm_property *type_property;
 
+   /**
+* @bypass_property:
+*
+* Boolean property to control enablement of the color
+* operation. Setting bypass to "true" shall always be supported
+* in order to allow compositors to quickly fall back to
+* alternate methods of color processing. This is important
+* since setting color operations can fail due to unique
+* HW constraints.
+*/
+   struct drm_property *bypass_property;
+
/**
 * @curve_1d_type:
 *
-- 
2.44.0



[RFC PATCH v4 05/42] drm/vkms: Create separate Kconfig file for VKMS

2024-02-26 Thread Harry Wentland
This aligns with most other DRM drivers and will allow
us to add new VKMS config options without polluting
the DRM Kconfig.

v3:
 - Change SPDX to GPL-2.0-only to match DRM KConfig
   SPDX (Simon)

Signed-off-by: Harry Wentland 
Reviewed-by: Simon Ser 
---
 drivers/gpu/drm/Kconfig  | 14 +-
 drivers/gpu/drm/vkms/Kconfig | 15 +++
 2 files changed, 16 insertions(+), 13 deletions(-)
 create mode 100644 drivers/gpu/drm/vkms/Kconfig

diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index 2520db0b776e..e3ea8793cb8a 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -289,19 +289,7 @@ config DRM_VGEM
  as used by Mesa's software renderer for enhanced performance.
  If M is selected the module will be called vgem.
 
-config DRM_VKMS
-   tristate "Virtual KMS (EXPERIMENTAL)"
-   depends on DRM && MMU
-   select DRM_KMS_HELPER
-   select DRM_GEM_SHMEM_HELPER
-   select CRC32
-   default n
-   help
- Virtual Kernel Mode-Setting (VKMS) is used for testing or for
- running GPU in a headless machines. Choose this option to get
- a VKMS.
-
- If M is selected the module will be called vkms.
+source "drivers/gpu/drm/vkms/Kconfig"
 
 source "drivers/gpu/drm/exynos/Kconfig"
 
diff --git a/drivers/gpu/drm/vkms/Kconfig b/drivers/gpu/drm/vkms/Kconfig
new file mode 100644
index ..b9ecdebecb0b
--- /dev/null
+++ b/drivers/gpu/drm/vkms/Kconfig
@@ -0,0 +1,15 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+config DRM_VKMS
+   tristate "Virtual KMS (EXPERIMENTAL)"
+   depends on DRM && MMU
+   select DRM_KMS_HELPER
+   select DRM_GEM_SHMEM_HELPER
+   select CRC32
+   default n
+   help
+ Virtual Kernel Mode-Setting (VKMS) is used for testing or for
+ running GPU in a headless machines. Choose this option to get
+ a VKMS.
+
+ If M is selected the module will be called vkms.
-- 
2.44.0



[RFC PATCH v4 18/42] drm/vkms: Add kunit tests for linear and sRGB LUTs

2024-02-26 Thread Harry Wentland
Signed-off-by: Harry Wentland 
---
 drivers/gpu/drm/vkms/tests/vkms_color_tests.c | 37 ++-
 1 file changed, 36 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/vkms/tests/vkms_color_tests.c 
b/drivers/gpu/drm/vkms/tests/vkms_color_tests.c
index fc73e48aa57c..e6ac01dee830 100644
--- a/drivers/gpu/drm/vkms/tests/vkms_color_tests.c
+++ b/drivers/gpu/drm/vkms/tests/vkms_color_tests.c
@@ -31,7 +31,6 @@ const struct vkms_color_lut test_linear_lut = {
.channel_value2index_ratio = 0xf000fll
 };
 
-
 static void vkms_color_test_get_lut_index(struct kunit *test)
 {
int i;
@@ -40,6 +39,19 @@ static void vkms_color_test_get_lut_index(struct kunit *test)
 
for (i = 0; i < TEST_LUT_SIZE; i++)
KUNIT_EXPECT_EQ(test, 
drm_fixp2int_ceil(get_lut_index(_linear_lut, test_linear_array[i].red)), 
i);
+
+   KUNIT_EXPECT_EQ(test, drm_fixp2int(get_lut_index(_eotf, 0x0)), 
0x0);
+   KUNIT_EXPECT_EQ(test, drm_fixp2int_ceil(get_lut_index(_eotf, 
0x0)), 0x0);
+   KUNIT_EXPECT_EQ(test, drm_fixp2int_ceil(get_lut_index(_eotf, 
0x101)), 0x1);
+   KUNIT_EXPECT_EQ(test, drm_fixp2int_ceil(get_lut_index(_eotf, 
0x202)), 0x2);
+
+   KUNIT_EXPECT_EQ(test, drm_fixp2int(get_lut_index(_inv_eotf, 0x0)), 
0x0);
+   KUNIT_EXPECT_EQ(test, drm_fixp2int_ceil(get_lut_index(_inv_eotf, 
0x0)), 0x0);
+   KUNIT_EXPECT_EQ(test, drm_fixp2int_ceil(get_lut_index(_inv_eotf, 
0x101)), 0x1);
+   KUNIT_EXPECT_EQ(test, drm_fixp2int_ceil(get_lut_index(_inv_eotf, 
0x202)), 0x2);
+
+   KUNIT_EXPECT_EQ(test, drm_fixp2int_ceil(get_lut_index(_eotf, 
0xfefe)), 0xfe);
+   KUNIT_EXPECT_EQ(test, drm_fixp2int_ceil(get_lut_index(_eotf, 
0x)), 0xff);
 }
 
 static void vkms_color_test_lerp(struct kunit *test)
@@ -148,9 +160,32 @@ static void vkms_color_test_lerp(struct kunit *test)
KUNIT_EXPECT_EQ(test, lerp_u16(0x0, 0x1, 0x8000), 0x1);
 }
 
+static void vkms_color_test_linear(struct kunit *test)
+{
+   for (int i = 0; i < LUT_SIZE; i++) {
+   int linear = apply_lut_to_channel_value(_eotf, i * 
0x101, LUT_RED);
+   KUNIT_EXPECT_EQ(test, DIV_ROUND_CLOSEST(linear, 0x101), i);
+   }
+}
+
+static void vkms_color_srgb_inv_srgb(struct kunit *test)
+{
+   u16 srgb, final;
+
+   for (int i = 0; i < LUT_SIZE; i++) {
+   srgb = apply_lut_to_channel_value(_eotf, i * 0x101, 
LUT_RED);
+   final = apply_lut_to_channel_value(_inv_eotf, srgb, 
LUT_RED);
+
+   KUNIT_EXPECT_GE(test, final / 0x101, i-1);
+   KUNIT_EXPECT_LE(test, final / 0x101, i+1);
+   }
+}
+
 static struct kunit_case vkms_color_test_cases[] = {
KUNIT_CASE(vkms_color_test_get_lut_index),
KUNIT_CASE(vkms_color_test_lerp),
+   KUNIT_CASE(vkms_color_test_linear),
+   KUNIT_CASE(vkms_color_srgb_inv_srgb),
{}
 };
 
-- 
2.44.0



[RFC PATCH v4 07/42] drm/vkms: Avoid reading beyond LUT array

2024-02-26 Thread Harry Wentland
When the floor LUT index (drm_fixp2int(lut_index) is the last
index of the array the ceil LUT index will point to an entry
beyond the array. Make sure we guard against it and use the
value of the floor LUT index.

v3:
 - Drop bits from commit description that didn't contribute
   anything of value

Fixes: db1f254f2cfaf ("drm/vkms: Add support to 1D gamma LUT")
Signed-off-by: Harry Wentland 
Cc: Arthur Grillo 
Reviewed-by: Melissa Wen 
---
 drivers/gpu/drm/vkms/vkms_composer.c | 14 ++
 1 file changed, 10 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/vkms/vkms_composer.c 
b/drivers/gpu/drm/vkms/vkms_composer.c
index d178f2a400f6..b90e446d5954 100644
--- a/drivers/gpu/drm/vkms/vkms_composer.c
+++ b/drivers/gpu/drm/vkms/vkms_composer.c
@@ -123,6 +123,8 @@ static u16 apply_lut_to_channel_value(const struct 
vkms_color_lut *lut, u16 chan
  enum lut_channel channel)
 {
s64 lut_index = get_lut_index(lut, channel_value);
+   u16 *floor_lut_value, *ceil_lut_value;
+   u16 floor_channel_value, ceil_channel_value;
 
/*
 * This checks if `struct drm_color_lut` has any gap added by the 
compiler
@@ -130,11 +132,15 @@ static u16 apply_lut_to_channel_value(const struct 
vkms_color_lut *lut, u16 chan
 */
static_assert(sizeof(struct drm_color_lut) == sizeof(__u16) * 4);
 
-   u16 *floor_lut_value = (__u16 *)>base[drm_fixp2int(lut_index)];
-   u16 *ceil_lut_value = (__u16 *)>base[drm_fixp2int_ceil(lut_index)];
+   floor_lut_value = (__u16 *)>base[drm_fixp2int(lut_index)];
+   if (drm_fixp2int(lut_index) == (lut->lut_length - 1))
+   /* We're at the end of the LUT array, use same value for ceil 
and floor */
+   ceil_lut_value = floor_lut_value;
+   else
+   ceil_lut_value = (__u16 
*)>base[drm_fixp2int_ceil(lut_index)];
 
-   u16 floor_channel_value = floor_lut_value[channel];
-   u16 ceil_channel_value = ceil_lut_value[channel];
+   floor_channel_value = floor_lut_value[channel];
+   ceil_channel_value = ceil_lut_value[channel];
 
return lerp_u16(floor_channel_value, ceil_channel_value,
lut_index & DRM_FIXED_DECIMAL_MASK);
-- 
2.44.0



[RFC PATCH v4 06/42] drm/vkms: Add kunit tests for VKMS LUT handling

2024-02-26 Thread Harry Wentland
Debugging LUT math is much easier when we can unit test
it. Add kunit functionality to VKMS and add tests for
 - get_lut_index
 - lerp_u16

v4:
 - Test the critical points of the lerp function (Pekka)

v3:
 - Use include way of testing static functions (Arthur)

Signed-off-by: Harry Wentland 
Cc: Arthur Grillo 
---
 drivers/gpu/drm/vkms/Kconfig  |   5 +
 drivers/gpu/drm/vkms/tests/.kunitconfig   |   4 +
 drivers/gpu/drm/vkms/tests/vkms_color_tests.c | 163 ++
 drivers/gpu/drm/vkms/vkms_composer.c  |   8 +-
 4 files changed, 178 insertions(+), 2 deletions(-)
 create mode 100644 drivers/gpu/drm/vkms/tests/.kunitconfig
 create mode 100644 drivers/gpu/drm/vkms/tests/vkms_color_tests.c

diff --git a/drivers/gpu/drm/vkms/Kconfig b/drivers/gpu/drm/vkms/Kconfig
index b9ecdebecb0b..c1f8b343ff0e 100644
--- a/drivers/gpu/drm/vkms/Kconfig
+++ b/drivers/gpu/drm/vkms/Kconfig
@@ -13,3 +13,8 @@ config DRM_VKMS
  a VKMS.
 
  If M is selected the module will be called vkms.
+
+config DRM_VKMS_KUNIT_TESTS
+   tristate "Tests for VKMS" if !KUNIT_ALL_TESTS
+   depends on DRM_VKMS && KUNIT
+   default KUNIT_ALL_TESTS
diff --git a/drivers/gpu/drm/vkms/tests/.kunitconfig 
b/drivers/gpu/drm/vkms/tests/.kunitconfig
new file mode 100644
index ..70e378228cbd
--- /dev/null
+++ b/drivers/gpu/drm/vkms/tests/.kunitconfig
@@ -0,0 +1,4 @@
+CONFIG_KUNIT=y
+CONFIG_DRM=y
+CONFIG_DRM_VKMS=y
+CONFIG_DRM_VKMS_KUNIT_TESTS=y
diff --git a/drivers/gpu/drm/vkms/tests/vkms_color_tests.c 
b/drivers/gpu/drm/vkms/tests/vkms_color_tests.c
new file mode 100644
index ..fc73e48aa57c
--- /dev/null
+++ b/drivers/gpu/drm/vkms/tests/vkms_color_tests.c
@@ -0,0 +1,163 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+
+#include 
+
+#include 
+
+#define TEST_LUT_SIZE 16
+
+static struct drm_color_lut test_linear_array[TEST_LUT_SIZE] = {
+   { 0x0, 0x0, 0x0, 0 },
+   { 0x, 0x, 0x, 0 },
+   { 0x, 0x, 0x, 0 },
+   { 0x, 0x, 0x, 0 },
+   { 0x, 0x, 0x, 0 },
+   { 0x, 0x, 0x, 0 },
+   { 0x, 0x, 0x, 0 },
+   { 0x, 0x, 0x, 0 },
+   { 0x, 0x, 0x, 0 },
+   { 0x, 0x, 0x, 0 },
+   { 0x, 0x, 0x, 0 },
+   { 0x, 0x, 0x, 0 },
+   { 0x, 0x, 0x, 0 },
+   { 0x, 0x, 0x, 0 },
+   { 0x, 0x, 0x, 0 },
+   { 0x, 0x, 0x, 0 },
+};
+
+const struct vkms_color_lut test_linear_lut = {
+   .base = test_linear_array,
+   .lut_length = TEST_LUT_SIZE,
+   .channel_value2index_ratio = 0xf000fll
+};
+
+
+static void vkms_color_test_get_lut_index(struct kunit *test)
+{
+   int i;
+
+   KUNIT_EXPECT_EQ(test, drm_fixp2int(get_lut_index(_linear_lut, 
test_linear_array[0].red)), 0);
+
+   for (i = 0; i < TEST_LUT_SIZE; i++)
+   KUNIT_EXPECT_EQ(test, 
drm_fixp2int_ceil(get_lut_index(_linear_lut, test_linear_array[i].red)), 
i);
+}
+
+static void vkms_color_test_lerp(struct kunit *test)
+{
+   /*** half-way round down ***/
+   s64 t = 0x8000 - 1;
+   KUNIT_EXPECT_EQ(test, lerp_u16(0x0, 0x10, t), 0x8);
+
+   /* odd a */
+   KUNIT_EXPECT_EQ(test, lerp_u16(0x1, 0x10, t), 0x8);
+
+   /* odd b */
+   KUNIT_EXPECT_EQ(test, lerp_u16(0x1, 0xf, t), 0x8);
+
+   /* b = a */
+   KUNIT_EXPECT_EQ(test, lerp_u16(0x10, 0x10, t), 0x10);
+
+   /* b = a + 1 */
+   KUNIT_EXPECT_EQ(test, lerp_u16(0x10, 0x11, t), 0x10);
+
+
+   /*** half-way round up ***/
+   t = 0x8000;
+   KUNIT_EXPECT_EQ(test, lerp_u16(0x0, 0x10, t), 0x8);
+
+   /* odd a */
+   KUNIT_EXPECT_EQ(test, lerp_u16(0x1, 0x10, t), 0x9);
+
+   /* odd b */
+   KUNIT_EXPECT_EQ(test, lerp_u16(0x1, 0xf, t), 0x8);
+
+   /* b = a */
+   KUNIT_EXPECT_EQ(test, lerp_u16(0x10, 0x10, t), 0x10);
+
+   /* b = a + 1 */
+   KUNIT_EXPECT_EQ(test, lerp_u16(0x10, 0x11, t), 0x11);
+
+   /*** t = 0.0 ***/
+   t = 0x0;
+   KUNIT_EXPECT_EQ(test, lerp_u16(0x0, 0x10, t), 0x0);
+
+   /* odd a */
+   KUNIT_EXPECT_EQ(test, lerp_u16(0x1, 0x10, t), 0x1);
+
+   /* odd b */
+   KUNIT_EXPECT_EQ(test, lerp_u16(0x1, 0xf, t), 0x1);
+
+   /* b = a */
+   KUNIT_EXPECT_EQ(test, lerp_u16(0x10, 0x10, t), 0x10);
+
+   /* b = a + 1 */
+   KUNIT_EXPECT_EQ(test, lerp_u16(0x10, 0x11, t), 0x10);
+
+   /*** t = 1.0 ***/
+   t = 0x1;
+   KUNIT_EXPECT_EQ(test, lerp_u16(0x0, 0x10, t), 0x10);
+
+   /* odd a */
+   KUNIT_EXPECT_EQ(test, lerp_u16(0x1, 0x10, t), 0x10);
+
+   /* odd b */
+   KUNIT_EXPECT_EQ(test, lerp_u16(0x1, 0xf, t), 0xf);
+
+   /* b = a */
+   KUNIT_EXPECT_EQ(test, lerp_u16(0x10, 0x10, t), 0x10);
+
+   /* b = a + 1 */
+   KUNIT_EXPECT_EQ(test, lerp_u16(0x10, 0x11, t), 0x11);
+
+
+   /*** t = 0.0 + 1 ***

[RFC PATCH v4 03/42] drm: Correctly round for fixp2int_round

2024-02-26 Thread Harry Wentland
A value of 0x8000 and higher should round up, and
below should round down. VKMS Kunit tests for lerp_u16
showed that this is not the case. Fix it.

1 << (DRM_FIXED_POINT_HALF - 1) =
1 << 15 = 0x8000

This is not 0.5, but 0.0762939453125.

Instead of some smart math use a simple if/else to
round up or down. This helps people like me to understand
what the function does.

Signed-off-by: Harry Wentland 
---
 include/drm/drm_fixed.h | 15 ++-
 1 file changed, 10 insertions(+), 5 deletions(-)

diff --git a/include/drm/drm_fixed.h b/include/drm/drm_fixed.h
index cb842ba80ddd..8ee549f68537 100644
--- a/include/drm/drm_fixed.h
+++ b/include/drm/drm_fixed.h
@@ -77,6 +77,8 @@ static inline u32 dfixed_div(fixed20_12 A, fixed20_12 B)
 #define DRM_FIXED_DIGITS_MASK  (~DRM_FIXED_DECIMAL_MASK)
 #define DRM_FIXED_EPSILON  1LL
 #define DRM_FIXED_ALMOST_ONE   (DRM_FIXED_ONE - DRM_FIXED_EPSILON)
+#define DRM_FIXED_FRACTIONAL   0xll
+#define DRM_FIXED_HALF 0x8000ll
 
 /**
  * @drm_sm2fixp
@@ -106,11 +108,6 @@ static inline int drm_fixp2int(s64 a)
return ((s64)a) >> DRM_FIXED_POINT;
 }
 
-static inline int drm_fixp2int_round(s64 a)
-{
-   return drm_fixp2int(a + (1 << (DRM_FIXED_POINT_HALF - 1)));
-}
-
 static inline int drm_fixp2int_ceil(s64 a)
 {
if (a >= 0)
@@ -119,6 +116,14 @@ static inline int drm_fixp2int_ceil(s64 a)
return drm_fixp2int(a - DRM_FIXED_ALMOST_ONE);
 }
 
+static inline int drm_fixp2int_round(s64 a)
+{
+   if ((a & DRM_FIXED_FRACTIONAL) < DRM_FIXED_HALF)
+   return drm_fixp2int(a);
+   else
+   return drm_fixp2int_ceil(a);
+}
+
 static inline unsigned drm_fixp_msbset(s64 a)
 {
unsigned shift, sign = (a >> 63) & 1;
-- 
2.44.0



[RFC PATCH v4 00/42] Color Pipeline API w/ VKMS

2024-02-26 Thread Harry Wentland
This is an RFC set for a color pipeline API, along with a sample
implementation in VKMS. All the key API bits are here. VKMS now
supports two named transfer function colorops and two matrix
colorops. We have IGT tests that check all four of these colorops
with a pixel-by-pixel comparison that checks that these colorops
do what we expect them to do with a +/- 1 8 bpc code point margin.

The big new change with v4 is the addition of an amdgpu color
pipeline, for all AMD GPUs with DCN 3 and newer. Amdgpu now support
the following:

1. 1D Curve EOTF
2. 3x4 CTM
3. Multiplier
4. 1D Curve Inverse EOTF
5. 1D LUT
6. 1D Curve EOTF
7. 1D LUT

The supported curves for the 1D Curve type are:
- sRGB EOTF and its inverse
- PQ EOTF, scaled to [0.0, 125.0] and its inverse
- BT.2020/BT.709 OETF and its inverse

Note that the 1st and 5th colorops take the EOTF or Inverse
OETF while the 3rd colorop takes the Inverse EOTF or OETF.

We are working on two more ops for amdgpu, the HDR multiplier
and the 3DLUT, which will give us this:

1. 1D Curve EOTF
2. 3x4 CTM
3. HDR Multiplier
4. 1D Curve Inverse EOTF
5. 1D LUT
6. 3D LUT
7. 1D Curve EOTF
8. 1D LUT

This, essentially mirrors the color pipeline used by gamescope
and presented by Melissa Wen, with the exception of the DEGAM
LUT, which is not currently used. See
[1] 
https://indico.freedesktop.org/event/4/contributions/186/attachments/138/218/xdc2023-TheRainbowTreasureMap-MelissaWen.pdf

After this we'd like to also add the following ops:
- Scaler (Informational only)
- Color Encoding, to replace drm_plane's COLOR_ENCODING
- Color Range, to replace drm_plane's COLOR_RANGE

This patchset is grouped as follows:
 - Patches 1-3: couple general patches/fixes
 - Patches 4-7: introduce kunit to VKMS
 - Patch 7: description of motivation and details behind the
Color Pipeline API. If you're reading nothing else
but are interested in the topic I highly recommend
you take a look at this.
 - Patches 7-27: DRM core and VKMS changes for color pipeline API
 - Patches 28-40: DRM core and amdgpu changes for color pipeline API

VKMS patches could still be improved in a few ways, though the
payoff might be limited and I would rather focus on other work
at the moment. The most obvious thing to improve would be to
eliminate the hard-coded LUTs for identity, and sRGB, and replace
them with fixed-point math instead.

There are plenty of things that I would like to see here but
haven't had a chance to look at. These will (hopefully) be
addressed in future iterations, either in VKMS or amdgpu:
 - Clear documentation for each drm_colorop_type
 - Add custom LUT colorops to VKMS
 - Add pre-blending 3DLUT
 - How to support HW which can't bypass entire pipeline?
 - Add ability to create colorops that don't have BYPASS
 - Can we do a LOAD / COMMIT model for LUTs (and other properties)?
 - read-only scaling colorop which defines scaling taps and position
 - read-only color format colorop to define supported color formats
   for a pipeline
 - named matrices, for things like converting YUV to RGB

IGT tests can be found at
https://gitlab.freedesktop.org/hwentland/igt-gpu-tools/-/merge_requests/1

IGT patches are also being sent to the igt-dev mailing list.

If you prefer a gitlab MR for review you can find it at
https://gitlab.freedesktop.org/hwentland/linux/-/merge_requests/5

v4:
 - Add amdgpu color pipeline (WIP)
 - Don't block setting of deprecated properties, instead pass client cap
   to atomic check so drivers can ignore these props
 - Drop IOCTL definitions (Pekka)
 - Use enum property for colorop TYPE (Pekka)
 - A few cleanups to the docs (Pekka)
 - Rework the TYPE enum to name relation to avoid code duplication (Pekka)
 - Add missing function declarations (Chaitanya Kumar Borah)
 - Allow setting of NEXT property to NULL in _set_ function (Chaitanya Kumar 
Borah)
 - Add helper for creation of pipeline drm_plane property (Pekka)
 - Always create Bypass pipeline (Pekka)
 - A bunch of changes to VKMS kunit tests (Pekka)
 - Fix index in CTM doc (Pekka)

v3:
 - Abandon IOCTLs and discover colorops as clients iterate the pipeline
 - Remove need for libdrm
 - Add color_pipeline client cap and make mutually exclusive with
   COLOR_RANGE and COLOR_ENCODING properties
 - add CTM colorop to VKMS
 - Use include way for kunit testing static functions (Arthur)
 - Make TYPE a range property
 - Move enum drm_colorop_type to uapi header
 - and a bunch of smaller bits that are highlighted in the relevant commit
   description

v2:
 - Rebased on drm-misc-next
 - Introduce a VKMS Kunit so we can test LUT functionality in vkms_composer
 - Incorporate feedback in color_pipeline.rst doc
 - Add support for sRGB inverse EOTF
 - Add 2nd enumerated TF colorop to VKMS
 - Fix LUTs and some issues with applying LUTs in VKMS

Cc: Ville Syrjala 
Cc: Pekka Paalanen 
Cc: Simon Ser 
Cc: Harry Wentland 
Cc: Melissa Wen 
Cc: Jonas Ådahl 
Cc: Sebastian Wick 
Cc: Shashank Sharma 
Cc: Alexander Goins 
Cc

Re: UAPI Re: [PATCH 1/3] drm: Add DRM_MODE_TV_MODE_MONOCHROME

2024-02-21 Thread Harry Wentland



On 2024-02-21 04:07, Pekka Paalanen wrote:
> On Fri, 16 Feb 2024 18:48:55 +
> Dave Stevenson  wrote:
> 
>> From: Nick Hollinghurst 
>>
>> Add this as a value for enum_drm_connector_tv_mode, represented
>> by the string "Mono", to generate video with no colour encoding
>> or bursts. Define it to have no pedestal (since only NTSC-M calls
>> for a pedestal).
>>
>> Change default mode creation to acommodate the new tv_mode value
>> which comprises both 525-line and 625-line formats.
>>
>> Signed-off-by: Nick Hollinghurst 
>> Signed-off-by: Dave Stevenson 
> 
> Hi Dave and Nick,
> 
> since no-one else commented yet, I'd like to remind of the new UAPI
> requirements:
> https://dri.freedesktop.org/docs/drm/gpu/drm-uapi.html#open-source-userspace-requirements
> 
> AFAIU, adding a new value to an existing enum still counts as new UAPI.
> 

I tend to agree with Pekka. I'm getting tired of seeing new DRM properties
without knowing which canonical upstream user-space project uses it.

Can someone describe this for the "TV mode" property?

Harry

> Maybe there is no need for the full treatment here, or maybe there is,
> I'm not sure. I think you should make some statement about how the new
> UAPI requirements have been addressed.
> 
> Btw. no-one has submitted a record with "TV mode" to
> https://drmdb.emersion.fr/
> It only lists the radeon-specific "tv standard" property. I first
> thought you had mistaken the property name in the cover letter.
> 
> 
> Thanks,
> pq
> 
>> ---
>>  drivers/gpu/drm/drm_connector.c| 7 +++
>>  drivers/gpu/drm/drm_modes.c| 5 -
>>  drivers/gpu/drm/drm_probe_helper.c | 5 +++--
>>  include/drm/drm_connector.h| 7 +++
>>  4 files changed, 21 insertions(+), 3 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/drm_connector.c 
>> b/drivers/gpu/drm/drm_connector.c
>> index b0516505f7ae..fe05d27f3404 100644
>> --- a/drivers/gpu/drm/drm_connector.c
>> +++ b/drivers/gpu/drm/drm_connector.c
>> @@ -1005,6 +1005,7 @@ static const struct drm_prop_enum_list 
>> drm_tv_mode_enum_list[] = {
>>  { DRM_MODE_TV_MODE_PAL_M, "PAL-M" },
>>  { DRM_MODE_TV_MODE_PAL_N, "PAL-N" },
>>  { DRM_MODE_TV_MODE_SECAM, "SECAM" },
>> +{ DRM_MODE_TV_MODE_MONOCHROME, "Mono" },
>>  };
>>  DRM_ENUM_NAME_FN(drm_get_tv_mode_name, drm_tv_mode_enum_list)
>>  
>> @@ -1697,6 +1698,12 @@ 
>> EXPORT_SYMBOL(drm_connector_attach_dp_subconnector_property);
>>   *  TV Mode is CCIR System B (aka 625-lines) together with
>>   *  the SECAM Color Encoding.
>>   *
>> + *  Mono:
>> + *
>> + *  Use timings appropriate to the DRM mode, including
>> + *  equalizing pulses for a 525-line or 625-line mode,
>> + *  with no pedestal or color encoding.
>> + *
>>   *  Drivers can set up this property by calling
>>   *  drm_mode_create_tv_properties().
>>   */
>> diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
>> index c4f88c3a93b7..d274e7b00b79 100644
>> --- a/drivers/gpu/drm/drm_modes.c
>> +++ b/drivers/gpu/drm/drm_modes.c
>> @@ -530,7 +530,8 @@ static int fill_analog_mode(struct drm_device *dev,
>>   * @interlace: whether to compute an interlaced mode
>>   *
>>   * This function creates a struct drm_display_mode instance suited for
>> - * an analog TV output, for one of the usual analog TV mode.
>> + * an analog TV output, for one of the usual analog TV modes. Where
>> + * this is DRM_MODE_TV_MODE_MONOCHROME, a 625-line mode will be created.
>>   *
>>   * Note that @hdisplay is larger than the usual constraints for the PAL
>>   * and NTSC timings, and we'll choose to ignore most timings constraints
>> @@ -568,6 +569,8 @@ struct drm_display_mode *drm_analog_tv_mode(struct 
>> drm_device *dev,
>>  case DRM_MODE_TV_MODE_PAL_N:
>>  fallthrough;
>>  case DRM_MODE_TV_MODE_SECAM:
>> +fallthrough;
>> +case DRM_MODE_TV_MODE_MONOCHROME:
>>  analog = DRM_MODE_ANALOG_PAL;
>>  break;
>>  
>> diff --git a/drivers/gpu/drm/drm_probe_helper.c 
>> b/drivers/gpu/drm/drm_probe_helper.c
>> index d1e1ade66f81..9254dc2af873 100644
>> --- a/drivers/gpu/drm/drm_probe_helper.c
>> +++ b/drivers/gpu/drm/drm_probe_helper.c
>> @@ -1211,8 +1211,9 @@ int drm_connector_helper_tv_get_modes(struct 
>> drm_connector *connector)
>>  for (i = 0; i < tv_mode_property->num_values; i++)
>>  supported_tv_modes |= BIT(tv_mode_property->values[i]);
>>  
>> -if ((supported_tv_modes & ntsc_modes) &&
>> -(supported_tv_modes & pal_modes)) {
>> +if (((supported_tv_modes & ntsc_modes) &&
>> + (supported_tv_modes & pal_modes)) ||
>> +(supported_tv_modes & BIT(DRM_MODE_TV_MODE_MONOCHROME))) {
>>  uint64_t default_mode;
>>  
>>  if (drm_object_property_get_default_value(>base,
>> diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
>> index fe88d7fc6b8f..90fd0ea0ca09 100644
>> --- a/include/drm/drm_connector.h
>> +++ b/include/drm/drm_connector.h

Re: [PATCH 00/28] Plane Color Pipeline support for Intel platforms

2024-02-16 Thread Harry Wentland



On 2024-02-13 01:48, Uma Shankar wrote:
> This series intends to add support for Plane Color Management for
> Intel platforms. This is based on the design which has been agreed
> upon by the community. Series implementing the design for generic
> DRM core has been sent out by Harry Wentland and is under review
> below:
> https://patchwork.freedesktop.org/series/123446/
> 
> The base work of above series is squashed under 1 patch and support
> for Intel platform is added on top of it.
> Any reviews on the original core design is expected to be done in 
> Harry's series to avoid any forking of the discussion.
> 
> We have added some changes/fixes to the Harry's core DRM changes,
> being put up as separate patches on top of squashed patch. These are
> expected to get included in the main series from Harry once agreed upon.
> 
> Changes added on core design:
> 1. Below patches implement some fixes on original series
> drm: Add missing function declarations
> drm: handle NULL next colorop in drm_colorop_set_next_property
> drm: Fix error logging in set Color Pipeline
> 
> 2. Implemented a HW capability property to expose segmented luts.
> drm: Add Color lut range attributes
> drm: Add Color ops capability property
> drm: Define helper to create color ops capability property
> drm: Define helper for adding capability property for 1D LUT
> 
> This helps in generically defining the hardware lut capabilities,
> lut distribution, precision, segmented or PWL LUTS.
> 
> 3. Added support for enhanced prescision, 3x3 matrix and 1d LUT:
> drm: Add Enhanced LUT precision structure
> drm: Add support for 3x3 CTM
> drm: Add 1D LUT color op
> 
> On top of this base work for DRM core plane color pipeline design,
> implementation is done for Intel hardware platforms. Below patches
> include the same:
> 
> drm/i915: Add identifiers for intel color blocks
> drm/i915: Add intel_color_op
> drm/i915/color: Add helper to allocate intel colorop
> drm/i915/color: Add helper to create intel colorop
> drm/i915/color: Create a transfer function color pipeline
> drm/i915/color: Add and attach COLORPIPELINE plane property
> drm/i915/color: Add framework to set colorop
> drm/i915/color: Add callbacks to set plane CTM
> drm/i915/color: Add framework to program PRE/POST CSC LUT
> FIXME: force disable legacy plane color properties for TGL and beyond
> drm/i915/color: Enable Plane Color Pipelines
> drm/i915: Define segmented Lut and add capabilities to colorop
> drm/i915/color: Add plane CTM callback for TGL and beyond
> drm/i915: Add register definitions for Plane Degamma
> drm/i915: Add register definitions for Plane Post CSC
> drm/i915/color: Program Pre-CSC registers
> drm/i915/xelpd: Program Plane Post CSC Registers
> 
> Bhanu from Intel will be sending out the igt changes to help test the
> color pipeline implementation based on the current igt changes sent out
> by Harry.
> https://patchwork.freedesktop.org/series/123448/
> 
> Planned Next Steps:
> 1. Work with Harry and community and get DRM core changes for color
> pipeline merged.

We'll need a userspace to implement support before merging, but we're
working to enabling all color properties gamescope currently uses for
the SteamDeck color management to the Color Pipeline API, which should
help us get there. It's still a journey but I think the path is clear.

I'll send a new version of my patch series next week, including some AMD
implementation (not the entire AMD pipeline yet).

We're also adding a 1D_LUT type that's much simpler, basically a copy
of what the drm_crtc currently uses. One option is to keep both types,
another is to see if AMD's LUT can be expressed using the caps that you
define. I think it should be possible to express it as a single segment.

There might be another few changes in the core that might help you. Like
seeing the value of the client cap in the driver.

It's really good to see your work. With that we'll have three driver
implementations: VKMS, Intel, AMD,, which shows broad usability of this
approach.

Harry

> 2. Implement pipe color management (post blending) based on the current
> color pipeline design.
> 3. Work with compositor maintainers to get color processing implemented
> using display hardware, thereby avoid any GL or GPU shaders.
> 
> Thanks to all the community maintainers and contributors who have helped
> to get this support in upstream Linux. Looking forward to collaborate,
> work together and get this merged.
> 
> Cc: Ville Syrjala 
> Cc: Pekka Paalanen 
> Cc: Simon Ser 
> Cc: Harry Wentland 
> Cc: Melissa Wen 
> Cc: Jonas Ådahl 
> Cc: Sebastian Wick 
> Cc: Shashank Sharma 
> Cc: Alexander Goins 
> Cc: Joshua Ashton 
> Cc: Michel Dänzer 
> Cc: Aleix Pol 
> Cc: Xaver Hugl

Re: [PATCH] drm/amd: Drop abm_level property

2024-02-16 Thread Harry Wentland



On 2024-02-16 10:33, Mario Limonciello wrote:
> This vendor specific property has never been used by userspace
> software and conflicts with the panel_power_savings sysfs file.
> That is a compositor and user could fight over the same data.
> 
> Fixes: f97e4303da16 ("drm/amd/display: add panel_power_savings sysfs entry to 
> eDP connectors")
> Suggested-by: Harry Wentland 
> Signed-off-by: Mario Limonciello 
> --
> Cc: Hamza Mahfooz 
> Cc: Sun peng (Leo) Li 

Reviewed-by: Harry Wentland 

Harry

> ---
>  drivers/gpu/drm/amd/amdgpu/amdgpu_display.c   |  8 
>  drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h  |  2 --
>  drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 14 --
>  3 files changed, 24 deletions(-)
> 
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c 
> b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c
> index b8fbe97efe1d..3ecc7ef95172 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c
> @@ -1350,14 +1350,6 @@ int amdgpu_display_modeset_create_props(struct 
> amdgpu_device *adev)
>"dither",
>amdgpu_dither_enum_list, sz);
>  
> - if (adev->dc_enabled) {
> - adev->mode_info.abm_level_property =
> - drm_property_create_range(adev_to_drm(adev), 0,
> -   "abm level", 0, 4);
> - if (!adev->mode_info.abm_level_property)
> - return -ENOMEM;
> - }
> -
>   return 0;
>  }
>  
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h 
> b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
> index 2e4911050cc5..1fe21a70ddd0 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
> @@ -324,8 +324,6 @@ struct amdgpu_mode_info {
>   struct drm_property *audio_property;
>   /* FMT dithering */
>   struct drm_property *dither_property;
> - /* Adaptive Backlight Modulation (power feature) */
> - struct drm_property *abm_level_property;
>   /* hardcoded DFP edid from BIOS */
>   struct edid *bios_hardcoded_edid;
>   int bios_hardcoded_edid_size;
> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 
> b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> index b9ac3d2f8029..e3b32ffba85a 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> @@ -6388,9 +6388,6 @@ int amdgpu_dm_connector_atomic_set_property(struct 
> drm_connector *connector,
>   } else if (property == adev->mode_info.underscan_property) {
>   dm_new_state->underscan_enable = val;
>   ret = 0;
> - } else if (property == adev->mode_info.abm_level_property) {
> - dm_new_state->abm_level = val ?: ABM_LEVEL_IMMEDIATE_DISABLE;
> - ret = 0;
>   }
>  
>   return ret;
> @@ -6433,10 +6430,6 @@ int amdgpu_dm_connector_atomic_get_property(struct 
> drm_connector *connector,
>   } else if (property == adev->mode_info.underscan_property) {
>   *val = dm_state->underscan_enable;
>   ret = 0;
> - } else if (property == adev->mode_info.abm_level_property) {
> - *val = (dm_state->abm_level != ABM_LEVEL_IMMEDIATE_DISABLE) ?
> - dm_state->abm_level : 0;
> - ret = 0;
>   }
>  
>   return ret;
> @@ -7652,13 +7645,6 @@ void amdgpu_dm_connector_init_helper(struct 
> amdgpu_display_manager *dm,
>   aconnector->base.state->max_bpc = 16;
>   aconnector->base.state->max_requested_bpc = 
> aconnector->base.state->max_bpc;
>  
> - if (connector_type == DRM_MODE_CONNECTOR_eDP &&
> - (dc_is_dmcu_initialized(adev->dm.dc) ||
> -  adev->dm.dc->ctx->dmub_srv) && amdgpu_dm_abm_level < 0) {
> - drm_object_attach_property(>base.base,
> - adev->mode_info.abm_level_property, 0);
> - }
> -
>   if (connector_type == DRM_MODE_CONNECTOR_HDMIA) {
>   /* Content Type is currently only implemented for HDMI. */
>   drm_connector_attach_content_type_property(>base);



Re: [PATCH v2] drm/amd/display: add panel_power_savings sysfs entry to eDP connectors

2024-02-16 Thread Harry Wentland



On 2024-02-16 11:11, Harry Wentland wrote:
> 
> 
> On 2024-02-16 10:42, Pekka Paalanen wrote:
>> On Fri, 16 Feb 2024 09:33:47 -0500
>> Harry Wentland  wrote:
>>
>>> On 2024-02-16 03:19, Pekka Paalanen wrote:
>>>> On Fri, 2 Feb 2024 10:28:35 -0500
>>>> Hamza Mahfooz  wrote:
>>>>   
>>>>> We want programs besides the compositor to be able to enable or disable
>>>>> panel power saving features.  
>>>>
>>>> Could you also explain why, in the commit message, please?
>>>>
>>>> It is unexpected for arbitrary programs to be able to override the KMS
>>>> client, and certainly new ways to do so should not be added without an
>>>> excellent justification.
>>>>
>>>> Maybe debugfs would be more appropriate if the purpose is only testing
>>>> rather than production environments?
>>>>   
>>>>> However, since they are currently only
>>>>> configurable through DRM properties, that isn't possible. So, to remedy
>>>>> that issue introduce a new "panel_power_savings" sysfs attribute.  
>>>>
>>>> When the DRM property was added, what was used as the userspace to
>>>> prove its workings?
>>>>   
>>>
>>> I don't think there ever was a userspace implementation and doubt any
>>> exists today. Part of that is on me. In hindsight, the KMS prop should
>>> have never gone upstream.
>>>
>>> I suggest we drop the KMS prop entirely.
>>
>> Sounds good. What about the sysfs thing? Should it be a debugfs thing
>> instead, assuming the below question will be resolved?
>>
> 
> 
> It's intended to be used by the power profiles daemon (PPD). I don't think
> debugfs is the right choice. See
> https://gitlab.freedesktop.org/upower/power-profiles-daemon/-/commit/41ed5d33a82b0ceb7b6d473551eb2aa62cade6bc
> 
>>> As for the color accuracy topic, I think it is important that compositors
>>> can have full control over that if needed, while it's also important
>>> for HW vendors to optimize for power when absolute color accuracy is not
>>> needed. An average end-user writing code or working on their slides
>>> would rather have a longer battery life than a perfectly color-accurate
>>> display. We should probably think of a solution that can support both
>>> use-cases.
>>
>> I agree. Maybe this pondering should start from "how would it work from
>> end user perspective"?
>>
>> "Automatically" is probably be most desirable answer. Some kind of
> 
> I agree
> 
>> desktop settings with options like "save power at the expense of image
>> quality":
>> - always
>> - not if watching movies/gaming
>> - on battery
>> - on battery, unless I'm watching movies/gaming
>> - never
>>
> 
> It's interesting that you split out movies/gaming, specifically. AMD's
> ABM algorithm seems to have considered movies in particular when
> evaluating the power/fidelity trade-off.
> 
> I wouldn't think consumer media is very particular about a specific
> color fidelity (despite what HDR specs try to make you believe). Where
> color fidelity would matter to me is when I'd want to edit pictures or
> video.
> 
> The "abm_level" property that we expose is really just that, a setting
> for the strength of the power-savings effect, with 0 being off and 4 being
> maximum strength and power saving, at the expense of fidelity.
> 
> Mario's work is to let the PPD control it and set the ABM levels based on
> the selected power profile:
> 0 - Performance
> 1 - Balance
> 3 - Power
> 
> And I believe we've looked at disabling ABM (setting it to 0) automatically
> if we know we're on AC power.
> 
>> Or maybe there already is something like that, and it only needs to be
>> plumbed through?
>>
>> Which would point towards KMS clients needing to control it, which
>> means a generic KMS prop rather than vendor specific?
>>
>> Or should the desktop compositor be talking to some daemon instead of
>> KMS for this? Maybe they already are?
>>
> 
> I think the intention is for the PPD to be that daemon. Mario can elaborate.
> 

Some more details and screenshots on how the PPD is expected to work and look:
https://linuxconfig.org/how-to-manage-power-profiles-over-d-bus-with-power-profiles-daemon-on-linux

Harry

> Harry
> 
>>
>> Thanks,
>> pq
> 



Re: [PATCH v2] drm/amd/display: add panel_power_savings sysfs entry to eDP connectors

2024-02-16 Thread Harry Wentland



On 2024-02-16 10:42, Pekka Paalanen wrote:
> On Fri, 16 Feb 2024 09:33:47 -0500
> Harry Wentland  wrote:
> 
>> On 2024-02-16 03:19, Pekka Paalanen wrote:
>>> On Fri, 2 Feb 2024 10:28:35 -0500
>>> Hamza Mahfooz  wrote:
>>>   
>>>> We want programs besides the compositor to be able to enable or disable
>>>> panel power saving features.  
>>>
>>> Could you also explain why, in the commit message, please?
>>>
>>> It is unexpected for arbitrary programs to be able to override the KMS
>>> client, and certainly new ways to do so should not be added without an
>>> excellent justification.
>>>
>>> Maybe debugfs would be more appropriate if the purpose is only testing
>>> rather than production environments?
>>>   
>>>> However, since they are currently only
>>>> configurable through DRM properties, that isn't possible. So, to remedy
>>>> that issue introduce a new "panel_power_savings" sysfs attribute.  
>>>
>>> When the DRM property was added, what was used as the userspace to
>>> prove its workings?
>>>   
>>
>> I don't think there ever was a userspace implementation and doubt any
>> exists today. Part of that is on me. In hindsight, the KMS prop should
>> have never gone upstream.
>>
>> I suggest we drop the KMS prop entirely.
> 
> Sounds good. What about the sysfs thing? Should it be a debugfs thing
> instead, assuming the below question will be resolved?
> 


It's intended to be used by the power profiles daemon (PPD). I don't think
debugfs is the right choice. See
https://gitlab.freedesktop.org/upower/power-profiles-daemon/-/commit/41ed5d33a82b0ceb7b6d473551eb2aa62cade6bc

>> As for the color accuracy topic, I think it is important that compositors
>> can have full control over that if needed, while it's also important
>> for HW vendors to optimize for power when absolute color accuracy is not
>> needed. An average end-user writing code or working on their slides
>> would rather have a longer battery life than a perfectly color-accurate
>> display. We should probably think of a solution that can support both
>> use-cases.
> 
> I agree. Maybe this pondering should start from "how would it work from
> end user perspective"?
> 
> "Automatically" is probably be most desirable answer. Some kind of

I agree

> desktop settings with options like "save power at the expense of image
> quality":
> - always
> - not if watching movies/gaming
> - on battery
> - on battery, unless I'm watching movies/gaming
> - never
> 

It's interesting that you split out movies/gaming, specifically. AMD's
ABM algorithm seems to have considered movies in particular when
evaluating the power/fidelity trade-off.

I wouldn't think consumer media is very particular about a specific
color fidelity (despite what HDR specs try to make you believe). Where
color fidelity would matter to me is when I'd want to edit pictures or
video.

The "abm_level" property that we expose is really just that, a setting
for the strength of the power-savings effect, with 0 being off and 4 being
maximum strength and power saving, at the expense of fidelity.

Mario's work is to let the PPD control it and set the ABM levels based on
the selected power profile:
0 - Performance
1 - Balance
3 - Power

And I believe we've looked at disabling ABM (setting it to 0) automatically
if we know we're on AC power.

> Or maybe there already is something like that, and it only needs to be
> plumbed through?
> 
> Which would point towards KMS clients needing to control it, which
> means a generic KMS prop rather than vendor specific?
> 
> Or should the desktop compositor be talking to some daemon instead of
> KMS for this? Maybe they already are?
> 

I think the intention is for the PPD to be that daemon. Mario can elaborate.

Harry

> 
> Thanks,
> pq



Re: [PATCH] drm/amd: Only allow one entity to control ABM

2024-02-16 Thread Harry Wentland



On 2024-02-16 09:47, Christian König wrote:
> Am 16.02.24 um 15:42 schrieb Mario Limonciello:
>> On 2/16/2024 08:38, Christian König wrote:
>>> Am 16.02.24 um 15:07 schrieb Mario Limonciello:
>>>> By exporting ABM to sysfs it's possible that DRM master and software
>>>> controlling the sysfs file fight over the value programmed for ABM.
>>>>
>>>> Adjust the module parameter behavior to control who control ABM:
>>>> -2: DRM
>>>> -1: sysfs (IE via software like power-profiles-daemon)
>>>
>>> Well that sounds extremely awkward. Why should a power-profiles-deamon has 
>>> control over the panel power saving features?
>>>
>>> I mean we are talking about things like reducing backlight level when the 
>>> is inactivity, don't we?
>>
>> We're talking about activating the ABM algorithm when the system is in power 
>> saving mode; not from inactivity.  This allows the user to squeeze out some 
>> extra power "just" in that situation.
>>
>> But given the comments on the other patch, I tend to agree with Harry's 
>> proposal instead that we just drop the DRM property entirely as there are no 
>> consumers of it.
> 
> Yeah, but even then the design to let this be controlled by an userspace 
> deamon is questionable. Stuff like that is handled inside the kernel and not 
> exposed to userspace usually.
> 

I think we'll need a bit in our kernel docs describing ABM. Assumptions around 
what it is and does seem to lead to confusion.

The thing is that ABM has a visual impact that not all users like. It would 
make sense for users to be able to change the ABM level as desired, and/or 
configure their power profiles to select a certain ABM level.

ABM will reduce the backlight and compensate by adjusting brightness and 
contrast of the image. It has 5 levels: 0, 1, 2, 3, 4. 0 means off. 4 means 
maximum backlight reduction. IMO, 1 and 2 look okay. 3 and 4 can be quite 
impactful, both to power and visual fidelity.

Harry

> Regards,
> Christian.
> 
>>
>>>
>>> Regards,
>>> Christian.
>>>
>>>> 0-4: User via command line
>>>>
>>>> Also introduce a Kconfig option that allows distributions to choose
>>>> the default policy that is appropriate for them.
>>>>
>>>> Fixes: f97e4303da16 ("drm/amd/display: add panel_power_savings sysfs entry 
>>>> to eDP connectors")
>>>> Signed-off-by: Mario Limonciello 
>>>> ---
>>>> Cc: Hamza Mahfooz 
>>>> Cc: Harry Wentland 
>>>> Cc: Sun peng (Leo) Li 
>>>>   drivers/gpu/drm/amd/amdgpu/Kconfig    | 72 +++
>>>>   drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c   | 23 +++---
>>>>   .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c |  6 +-
>>>>   3 files changed, 90 insertions(+), 11 deletions(-)
>>>>
>>>> diff --git a/drivers/gpu/drm/amd/amdgpu/Kconfig 
>>>> b/drivers/gpu/drm/amd/amdgpu/Kconfig
>>>> index 22d88f8ef527..2ab57ccf6f21 100644
>>>> --- a/drivers/gpu/drm/amd/amdgpu/Kconfig
>>>> +++ b/drivers/gpu/drm/amd/amdgpu/Kconfig
>>>> @@ -80,6 +80,78 @@ config DRM_AMDGPU_WERROR
>>>>     Add -Werror to the build flags for amdgpu.ko.
>>>>     Only enable this if you are warning code for amdgpu.ko.
>>>> +choice
>>>> +    prompt "Amdgpu panel power Savings"
>>>> +    default AMDGPU_SYSFS_ABM
>>>> +    help
>>>> +    Control the default behavior for adaptive panel power savings.
>>>> +
>>>> +    Panel power savings features will sacrifice color accuracy
>>>> +    in exchange for power savings.
>>>> +
>>>> +    This can be configured for:
>>>> +    - dynamic control by the DRM master
>>>> +    - dynamic control by sysfs nodes
>>>> +    - statically by the user at kernel compile time
>>>> +
>>>> +    This value can also be overridden by the amdgpu.abmlevel
>>>> +    module parameter.
>>>> +
>>>> +config AMDGPU_DRM_ABM
>>>> +    bool "DRM Master control"
>>>> +    help
>>>> +    Export a property called 'abm_level' that can be
>>>> +    manipulated by the DRM master for supported hardware.
>>>> +
>>>> +config AMDGPU_SYSFS_ABM
>>>> +    bool "sysfs control"
>>>> +    help
>>>> +    Export a sysfs file 'panel_power_savin

Re: [PATCH v2] drm/amd/display: add panel_power_savings sysfs entry to eDP connectors

2024-02-16 Thread Harry Wentland



On 2024-02-16 03:19, Pekka Paalanen wrote:
> On Fri, 2 Feb 2024 10:28:35 -0500
> Hamza Mahfooz  wrote:
> 
>> We want programs besides the compositor to be able to enable or disable
>> panel power saving features.
> 
> Could you also explain why, in the commit message, please?
> 
> It is unexpected for arbitrary programs to be able to override the KMS
> client, and certainly new ways to do so should not be added without an
> excellent justification.
> 
> Maybe debugfs would be more appropriate if the purpose is only testing
> rather than production environments?
> 
>> However, since they are currently only
>> configurable through DRM properties, that isn't possible. So, to remedy
>> that issue introduce a new "panel_power_savings" sysfs attribute.
> 
> When the DRM property was added, what was used as the userspace to
> prove its workings?
> 

I don't think there ever was a userspace implementation and doubt any
exists today. Part of that is on me. In hindsight, the KMS prop should
have never gone upstream.

I suggest we drop the KMS prop entirely.

As for the color accuracy topic, I think it is important that compositors
can have full control over that if needed, while it's also important
for HW vendors to optimize for power when absolute color accuracy is not
needed. An average end-user writing code or working on their slides
would rather have a longer battery life than a perfectly color-accurate
display. We should probably think of a solution that can support both
use-cases.

Harry

> 
> Thanks,
> pq
> 
>>
>> Cc: Mario Limonciello 
>> Signed-off-by: Hamza Mahfooz 
>> ---
>> v2: hide ABM_LEVEL_IMMEDIATE_DISABLE in the read case, force an atomic
>> commit when setting the value, call sysfs_remove_group() in
>> amdgpu_dm_connector_unregister() and add some documentation.
>> ---
>>  .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 76 +++
>>  1 file changed, 76 insertions(+)
>>
>> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 
>> b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
>> index 8590c9f1dda6..3c62489d03dc 100644
>> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
>> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
>> @@ -6436,10 +6436,79 @@ int amdgpu_dm_connector_atomic_get_property(struct 
>> drm_connector *connector,
>>  return ret;
>>  }
>>  
>> +/**
>> + * DOC: panel power savings
>> + *
>> + * The display manager allows you to set your desired **panel power 
>> savings**
>> + * level (between 0-4, with 0 representing off), e.g. using the following::
>> + *
>> + *   # echo 3 > /sys/class/drm/card0-eDP-1/amdgpu/panel_power_savings
>> + *
>> + * Modifying this value can have implications on color accuracy, so tread
>> + * carefully.
>> + */
>> +
>> +static ssize_t panel_power_savings_show(struct device *device,
>> +struct device_attribute *attr,
>> +char *buf)
>> +{
>> +struct drm_connector *connector = dev_get_drvdata(device);
>> +struct drm_device *dev = connector->dev;
>> +u8 val;
>> +
>> +drm_modeset_lock(>mode_config.connection_mutex, NULL);
>> +val = to_dm_connector_state(connector->state)->abm_level ==
>> +ABM_LEVEL_IMMEDIATE_DISABLE ? 0 :
>> +to_dm_connector_state(connector->state)->abm_level;
>> +drm_modeset_unlock(>mode_config.connection_mutex);
>> +
>> +return sysfs_emit(buf, "%u\n", val);
>> +}
>> +
>> +static ssize_t panel_power_savings_store(struct device *device,
>> + struct device_attribute *attr,
>> + const char *buf, size_t count)
>> +{
>> +struct drm_connector *connector = dev_get_drvdata(device);
>> +struct drm_device *dev = connector->dev;
>> +long val;
>> +int ret;
>> +
>> +ret = kstrtol(buf, 0, );
>> +
>> +if (ret)
>> +return ret;
>> +
>> +if (val < 0 || val > 4)
>> +return -EINVAL;
>> +
>> +drm_modeset_lock(>mode_config.connection_mutex, NULL);
>> +to_dm_connector_state(connector->state)->abm_level = val ?:
>> +ABM_LEVEL_IMMEDIATE_DISABLE;
>> +drm_modeset_unlock(>mode_config.connection_mutex);
>> +
>> +drm_kms_helper_hotplug_event(dev);
>> +
>> +return count;
>> +}
>> +
>> +static DEVICE_ATTR_RW(panel_power_savings);
>> +
>> +static struct attribute *amdgpu_attrs[] = {
>> +_attr_panel_power_savings.attr,
>> +NULL
>> +};
>> +
>> +static const struct attribute_group amdgpu_group = {
>> +.name = "amdgpu",
>> +.attrs = amdgpu_attrs
>> +};
>> +
>>  static void amdgpu_dm_connector_unregister(struct drm_connector *connector)
>>  {
>>  struct amdgpu_dm_connector *amdgpu_dm_connector = 
>> to_amdgpu_dm_connector(connector);
>>  
>> +sysfs_remove_group(>kdev->kobj, _group);
>>  drm_dp_aux_unregister(_dm_connector->dm_dp_aux.aux);
>>  }
>>  
>> @@ -6541,6 +6610,13 @@ amdgpu_dm_connector_late_register(struct 
>> 

Re: [PATCH v2] drm/amd/display: add panel_power_savings sysfs entry to eDP connectors

2024-02-15 Thread Harry Wentland
On 2024-02-02 11:20, Mario Limonciello wrote:
> On 2/2/2024 09:28, Hamza Mahfooz wrote:
>> We want programs besides the compositor to be able to enable or disable
>> panel power saving features. However, since they are currently only
>> configurable through DRM properties, that isn't possible. So, to remedy
>> that issue introduce a new "panel_power_savings" sysfs attribute.
>>

I've been trying to avoid looking at this too closely, partly because
I want ABM enablement by default, with control for users. But the
more I think about this the more uncomfortable I get. The key for my
discomfort is that we're going around the back of DRM master to set
a DRM property. This is apt to create lots of weird behaviors,
especially if compositors also decide to implement support for the
abm_level property and then potentially fight PPD, or other users
of this sysfs.

I'm also not sure a new sysfs is a good candidate for drm-fixes.

Harry

>> Cc: Mario Limonciello 
>> Signed-off-by: Hamza Mahfooz 
> 
> Reviewed-by: Mario Limonciello 
> Tested-by: Mario Limonciello 
> 
>> ---
>> v2: hide ABM_LEVEL_IMMEDIATE_DISABLE in the read case, force an atomic
>>  commit when setting the value, call sysfs_remove_group() in
>>  amdgpu_dm_connector_unregister() and add some documentation.
>> ---
>>   .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 76 +++
>>   1 file changed, 76 insertions(+)
>>
>> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 
>> b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
>> index 8590c9f1dda6..3c62489d03dc 100644
>> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
>> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
>> @@ -6436,10 +6436,79 @@ int amdgpu_dm_connector_atomic_get_property(struct 
>> drm_connector *connector,
>>   return ret;
>>   }
>>   +/**
>> + * DOC: panel power savings
>> + *
>> + * The display manager allows you to set your desired **panel power 
>> savings**
>> + * level (between 0-4, with 0 representing off), e.g. using the following::
>> + *
>> + *   # echo 3 > /sys/class/drm/card0-eDP-1/amdgpu/panel_power_savings
>> + *
>> + * Modifying this value can have implications on color accuracy, so tread
>> + * carefully.
>> + */
>> +
>> +static ssize_t panel_power_savings_show(struct device *device,
>> +    struct device_attribute *attr,
>> +    char *buf)
>> +{
>> +    struct drm_connector *connector = dev_get_drvdata(device);
>> +    struct drm_device *dev = connector->dev;
>> +    u8 val;
>> +
>> +    drm_modeset_lock(>mode_config.connection_mutex, NULL);
>> +    val = to_dm_connector_state(connector->state)->abm_level ==
>> +    ABM_LEVEL_IMMEDIATE_DISABLE ? 0 :
>> +    to_dm_connector_state(connector->state)->abm_level;
>> +    drm_modeset_unlock(>mode_config.connection_mutex);
>> +
>> +    return sysfs_emit(buf, "%u\n", val);
>> +}
>> +
>> +static ssize_t panel_power_savings_store(struct device *device,
>> + struct device_attribute *attr,
>> + const char *buf, size_t count)
>> +{
>> +    struct drm_connector *connector = dev_get_drvdata(device);
>> +    struct drm_device *dev = connector->dev;
>> +    long val;
>> +    int ret;
>> +
>> +    ret = kstrtol(buf, 0, );
>> +
>> +    if (ret)
>> +    return ret;
>> +
>> +    if (val < 0 || val > 4)
>> +    return -EINVAL;
>> +
>> +    drm_modeset_lock(>mode_config.connection_mutex, NULL);
>> +    to_dm_connector_state(connector->state)->abm_level = val ?:
>> +    ABM_LEVEL_IMMEDIATE_DISABLE;
>> +    drm_modeset_unlock(>mode_config.connection_mutex);
>> +
>> +    drm_kms_helper_hotplug_event(dev);
>> +
>> +    return count;
>> +}
>> +
>> +static DEVICE_ATTR_RW(panel_power_savings);
>> +
>> +static struct attribute *amdgpu_attrs[] = {
>> +    _attr_panel_power_savings.attr,
>> +    NULL
>> +};
>> +
>> +static const struct attribute_group amdgpu_group = {
>> +    .name = "amdgpu",
>> +    .attrs = amdgpu_attrs
>> +};
>> +
>>   static void amdgpu_dm_connector_unregister(struct drm_connector *connector)
>>   {
>>   struct amdgpu_dm_connector *amdgpu_dm_connector = 
>> to_amdgpu_dm_connector(connector);
>>   +    sysfs_remove_group(>kdev->kobj, _group);
>>   drm_dp_aux_unregister(_dm_connector->dm_dp_aux.aux);
>>   }
>>   @@ -6541,6 +6610,13 @@ amdgpu_dm_connector_late_register(struct 
>> drm_connector *connector)
>>   to_amdgpu_dm_connector(connector);
>>   int r;
>>   +    if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) {
>> +    r = sysfs_create_group(>kdev->kobj,
>> +   _group);
>> +    if (r)
>> +    return r;
>> +    }
>> +
>>   amdgpu_dm_register_backlight_device(amdgpu_dm_connector);
>>     if ((connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort) ||
> 



Re: [RFC 0/5] Introduce drm sharpening property

2024-02-15 Thread Harry Wentland
Adding a couple of compositor devs as they might be interested in this.

On 2024-02-14 06:24, Nemesa Garg wrote:
>   Many a times images are blurred or upscaled content is also not as
> crisp as original rendered image. Traditional sharpening techniques often
> apply a uniform level of enhancement across entire image, which sometimes
> result in over-sharpening of some areas and potential loss of natural 
> details. 
> 
> Intel has come up with Display Engine based adaptive sharpening filter 
> with minimal power and performance impact. From LNL onwards, the Display
> hardware can use one of the pipe scaler for adaptive sharpness filter.
> This can be used for both gaming and non-gaming use cases like photos,
> image viewing. It works on a region of pixels depending on the tap size.
> 
> This RFC is an attempt to introduce an adaptive sharpness solution which
> helps in improving the image quality. For this new CRTC property is added.

I don't think CRTC is the right place for this. Scaling tends to be more
of a plane thing. Planes can be scaled independently, or is that not the
case for Intel? Or does Intel HW do this sharpening operation independent
of any scaling, on the entire output?

> The user can set this property with desired sharpness strength value with
> 0-255. A value of 1 representing minimum sharpening strength and 255
> representing maximum sharpness strength. A strength value of 0 means no
> sharpening or sharpening feature disabled.
> It works on a region of pixels depending on the tap size. The coefficients
> are used to generate an alpha value which is used to blend the sharpened
> image to original image.
>  
> Userspace implementation for sharpening feature and IGT implementation
> is in progress.

It would be very helpful to have an idea how this looks in userspace, and
which compositors will implement this.

Harry

> 
> Nemesa Garg (5):
>   drm: Introduce sharpeness mode property
>   drm/i915/display/: Compute the scaler filter coefficients
>   drm/i915/dispaly/: Enable the second scaler
>   drm/i915/display/: Add registers and compute the strength
>   drm/i915/display: Load the lut values and enable sharpness
> 
>  drivers/gpu/drm/drm_atomic_uapi.c |   4 +
>  drivers/gpu/drm/drm_crtc.c|  17 ++
>  drivers/gpu/drm/i915/Makefile |   1 +
>  drivers/gpu/drm/i915/display/intel_crtc.c |   3 +
>  drivers/gpu/drm/i915/display/intel_display.c  |  20 +-
>  .../drm/i915/display/intel_display_types.h|  11 +
>  .../drm/i915/display/intel_modeset_verify.c   |   1 +
>  .../drm/i915/display/intel_sharpen_filter.c   | 214 ++
>  .../drm/i915/display/intel_sharpen_filter.h   |  31 +++
>  drivers/gpu/drm/i915/display/skl_scaler.c |  86 ++-
>  drivers/gpu/drm/i915/display/skl_scaler.h |   1 +
>  drivers/gpu/drm/i915/i915_reg.h   |  19 ++
>  drivers/gpu/drm/xe/Makefile   |   1 +
>  include/drm/drm_crtc.h|  17 ++
>  14 files changed, 416 insertions(+), 10 deletions(-)
>  create mode 100644 drivers/gpu/drm/i915/display/intel_sharpen_filter.c
>  create mode 100644 drivers/gpu/drm/i915/display/intel_sharpen_filter.h
> 



Re: [PATCH v2 2/2] drm/amdgpu: Implement check_async_props for planes

2024-01-23 Thread Harry Wentland



On 2024-01-23 13:02, Xaver Hugl wrote:
> Am Mo., 22. Jan. 2024 um 16:50 Uhr schrieb Harry Wentland
> :
>>
>>
>>
>> On 2024-01-19 13:25, Ville Syrjälä wrote:
>>> On Fri, Jan 19, 2024 at 03:12:35PM -0300, André Almeida wrote:
>>>> AMD GPUs can do async flips with changes on more properties than just
>>>> the FB ID, so implement a custom check_async_props for AMD planes.
>>>>
>>>> Allow amdgpu to do async flips with IN_FENCE_ID and FB_DAMAGE_CLIPS
>>>> properties. For userspace to check if a driver support this two
>>>> properties, the strategy for now is to use TEST_ONLY commits.
>>>>
>>>> Signed-off-by: André Almeida 
>>>> ---
>>>> v2: Drop overlay plane option for now
>>>>
>>>>   .../amd/display/amdgpu_dm/amdgpu_dm_plane.c   | 29 +++
>>>>   1 file changed, 29 insertions(+)
>>>>
>>>> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c 
>>>> b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
>>>> index 116121e647ca..7afe8c1b62d4 100644
>>>> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
>>>> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
>>>> @@ -25,6 +25,7 @@
>>>>*/
>>>>
>>>>   #include 
>>>> +#include 
>>>>   #include 
>>>>   #include 
>>>>   #include 
>>>> @@ -1430,6 +1431,33 @@ static void 
>>>> amdgpu_dm_plane_drm_plane_destroy_state(struct drm_plane *plane,
>>>>  drm_atomic_helper_plane_destroy_state(plane, state);
>>>>   }
>>>>
>>>> +static int amdgpu_dm_plane_check_async_props(struct drm_property *prop,
>>>> +  struct drm_plane *plane,
>>>> +  struct drm_plane_state *plane_state,
>>>> +  struct drm_mode_object *obj,
>>>> +  u64 prop_value, u64 old_val)
>>>> +{
>>>> +struct drm_mode_config *config = >dev->mode_config;
>>>> +int ret;
>>>> +
>>>> +if (prop != config->prop_fb_id &&
>>>> +prop != config->prop_in_fence_fd &&
>>>
>>> IN_FENCE should just be allowed always.
>>>
>>>> +prop != config->prop_fb_damage_clips) {
>>>
>>> This seems a bit dubious to me. How is amdgpu using the damage
>>> information during async flips?
>>
>> Yeah, I'm also not sure this is right. Has anyone tested this
>> with a PSR SU panel?
>>
>> Harry
> 
> I attempted to, but according to
> /sys/kernel/debug/dri/1/eDP-1/psr_state, PSR never kicks in on my
> laptop at all. The only reason I wanted this property though is to
> reduce the number of special cases for async pageflips compositors
> have to implement; as it's not necessary for any functionality I think
> it's also fine to leave it out.
> 

Yeah, PSR panels aren't super common. PSR SU (Selective Update) panels
even less so.

I'd prefer to keep the damage clips out of async for now unless we
can actually test it with a PSR SU panel.

Harry

>>>> +ret = drm_atomic_plane_get_property(plane, plane_state,
>>>> +prop, _val);
>>>> +return drm_atomic_check_prop_changes(ret, old_val, 
>>>> prop_value, prop);
>>>> +}
>>>> +
>>>> +if (plane_state->plane->type != DRM_PLANE_TYPE_PRIMARY) {
>>>> +drm_dbg_atomic(prop->dev,
>>>> +   "[OBJECT:%d] Only primary planes can be 
>>>> changed during async flip\n",
>>>> +   obj->id);
>>>> +return -EINVAL;
>>>> +}
>>>> +
>>>> +return 0;
>>>> +}
>>>> +
>>>>   static const struct drm_plane_funcs dm_plane_funcs = {
>>>>  .update_plane   = drm_atomic_helper_update_plane,
>>>>  .disable_plane  = drm_atomic_helper_disable_plane,
>>>> @@ -1438,6 +1466,7 @@ static const struct drm_plane_funcs dm_plane_funcs = 
>>>> {
>>>>  .atomic_duplicate_state = amdgpu_dm_plane_drm_plane_duplicate_state,
>>>>  .atomic_destroy_state = amdgpu_dm_plane_drm_plane_destroy_state,
>>>>  .format_mod_supported = amdgpu_dm_plane_format_mod_supported,
>>>> +.check_async_props = amdgpu_dm_plane_check_async_props,
>>>>   };
>>>>
>>>>   int amdgpu_dm_plane_init(struct amdgpu_display_manager *dm,
>>>> --
>>>> 2.43.0
>>>



Re: [PATCH v2 2/2] drm/amdgpu: Implement check_async_props for planes

2024-01-22 Thread Harry Wentland




On 2024-01-19 13:25, Ville Syrjälä wrote:

On Fri, Jan 19, 2024 at 03:12:35PM -0300, André Almeida wrote:

AMD GPUs can do async flips with changes on more properties than just
the FB ID, so implement a custom check_async_props for AMD planes.

Allow amdgpu to do async flips with IN_FENCE_ID and FB_DAMAGE_CLIPS
properties. For userspace to check if a driver support this two
properties, the strategy for now is to use TEST_ONLY commits.

Signed-off-by: André Almeida 
---
v2: Drop overlay plane option for now

  .../amd/display/amdgpu_dm/amdgpu_dm_plane.c   | 29 +++
  1 file changed, 29 insertions(+)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
index 116121e647ca..7afe8c1b62d4 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
@@ -25,6 +25,7 @@
   */
  
  #include 

+#include 
  #include 
  #include 
  #include 
@@ -1430,6 +1431,33 @@ static void 
amdgpu_dm_plane_drm_plane_destroy_state(struct drm_plane *plane,
drm_atomic_helper_plane_destroy_state(plane, state);
  }
  
+static int amdgpu_dm_plane_check_async_props(struct drm_property *prop,

+ struct drm_plane *plane,
+ struct drm_plane_state *plane_state,
+ struct drm_mode_object *obj,
+ u64 prop_value, u64 old_val)
+{
+   struct drm_mode_config *config = >dev->mode_config;
+   int ret;
+
+   if (prop != config->prop_fb_id &&
+   prop != config->prop_in_fence_fd &&


IN_FENCE should just be allowed always.


+   prop != config->prop_fb_damage_clips) {


This seems a bit dubious to me. How is amdgpu using the damage
information during async flips?


Yeah, I'm also not sure this is right. Has anyone tested this
with a PSR SU panel?

Harry




+   ret = drm_atomic_plane_get_property(plane, plane_state,
+   prop, _val);
+   return drm_atomic_check_prop_changes(ret, old_val, prop_value, 
prop);
+   }
+
+   if (plane_state->plane->type != DRM_PLANE_TYPE_PRIMARY) {
+   drm_dbg_atomic(prop->dev,
+  "[OBJECT:%d] Only primary planes can be changed 
during async flip\n",
+  obj->id);
+   return -EINVAL;
+   }
+
+   return 0;
+}
+
  static const struct drm_plane_funcs dm_plane_funcs = {
.update_plane   = drm_atomic_helper_update_plane,
.disable_plane  = drm_atomic_helper_disable_plane,
@@ -1438,6 +1466,7 @@ static const struct drm_plane_funcs dm_plane_funcs = {
.atomic_duplicate_state = amdgpu_dm_plane_drm_plane_duplicate_state,
.atomic_destroy_state = amdgpu_dm_plane_drm_plane_destroy_state,
.format_mod_supported = amdgpu_dm_plane_format_mod_supported,
+   .check_async_props = amdgpu_dm_plane_check_async_props,
  };
  
  int amdgpu_dm_plane_init(struct amdgpu_display_manager *dm,

--
2.43.0




Re: [PATCH v3 0/9] drm/amd/display: improve DTN color state log

2024-01-19 Thread Harry Wentland
000 4294967296 00
> [ 3]:Bypass   Bypass  Bypass   12-bit   9x9x9 
> BypassSW  4294967296 00 00 00 00 
> 4294967296 00 00 00 00 4294967296 00
> 
> DPP Color Caps: input_lut_shared:0  icsc:1  dgam_ram:1  dgam_rom: 
> srgb:1,bt2020:1,gamma2_2:0,pq:0,hlg:0  post_csc:0  gamcor:0  
> dgam_rom_for_yuv:1  3d_lut:1  blnd_lut:1  oscs:0
> 
> MPCC:  OPP  DPP  MPCCBOT  MODE  ALPHA_MODE  PREMULT  OVERLAP_ONLY  IDLE  OGAM 
> mode
> [ 0]:   0h   0h   3h 3   20 0 0  
> RAM A
> [ 3]:   0h   3h   fh 2   20 0 0 
> Bypass
> 
> MPC Color Caps: gamut_remap:0, 3dlut:0, ogam_ram:1, ocsc:1
> 
> ===
> 
> Let me know your thoughts.
> 

Thanks for improving this.

The series is
Reviewed-by: Harry Wentland 

I'll merge it over the next day or two (depending on how
well our CI cooperates).

Harry

> Melissa
> 
> [1] https://lore.kernel.org/amd-gfx/20230913164329.123687-1-m...@igalia.com/
> [2] https://lore.kernel.org/amd-gfx/20231116195812.906115-1-m...@igalia.com/
> [3] 
> https://github.com/ValveSoftware/gamescope/blob/master/src/docs/Steam%20Deck%20Display%20Pipeline.png
> 
> 
> Harry Wentland (1):
>   drm/amd/display: Add dpp_get_gamut_remap functions
> 
> Melissa Wen (8):
>   drm/amd/display: decouple color state from hw state log
>   drm/amd/display: read gamut remap matrix in fixed-point 31.32 format
>   drm/amd/display: fill up DCN3 DPP color state
>   drm/amd/display: add get_gamut_remap helper for MPC3
>   drm/amd/display: create DCN3-specific log for MPC state
>   drm/amd/display: hook up DCN30 color blocks data to DTN log
>   drm/amd/display: add DPP and MPC color caps to DTN log
>   drm/amd/display: hook up DCN20 color blocks data to DTN log
> 
>  .../drm/amd/display/dc/basics/conversion.c|  34 
>  .../drm/amd/display/dc/basics/conversion.h|   4 +
>  .../amd/display/dc/dcn10/dcn10_cm_common.c|  20 +++
>  .../amd/display/dc/dcn10/dcn10_cm_common.h|   4 +-
>  .../gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c  |   3 +-
>  .../gpu/drm/amd/display/dc/dcn10/dcn10_dpp.h  |   3 +
>  .../drm/amd/display/dc/dcn10/dcn10_dpp_cm.c   |  70 +++-
>  .../gpu/drm/amd/display/dc/dcn20/dcn20_dpp.c  |  31 ++--
>  .../gpu/drm/amd/display/dc/dcn20/dcn20_dpp.h  |   3 +
>  .../drm/amd/display/dc/dcn20/dcn20_dpp_cm.c   |  55 +++
>  .../gpu/drm/amd/display/dc/dcn20/dcn20_init.c |   1 +
>  .../gpu/drm/amd/display/dc/dcn20/dcn20_mpc.c  |  24 ++-
>  .../drm/amd/display/dc/dcn201/dcn201_dpp.c|   1 +
>  .../gpu/drm/amd/display/dc/dcn21/dcn21_init.c |   1 +
>  .../gpu/drm/amd/display/dc/dcn30/dcn30_dpp.c  |  38 -
>  .../gpu/drm/amd/display/dc/dcn30/dcn30_dpp.h  |   2 +
>  .../drm/amd/display/dc/dcn30/dcn30_dpp_cm.c   |  54 +++
>  .../gpu/drm/amd/display/dc/dcn30/dcn30_init.c |   1 +
>  .../gpu/drm/amd/display/dc/dcn30/dcn30_mpc.c  | 106 -
>  .../gpu/drm/amd/display/dc/dcn30/dcn30_mpc.h  |   4 +
>  .../drm/amd/display/dc/dcn301/dcn301_init.c   |   1 +
>  .../gpu/drm/amd/display/dc/dcn31/dcn31_init.c |   1 +
>  .../drm/amd/display/dc/dcn314/dcn314_init.c   |   1 +
>  .../gpu/drm/amd/display/dc/dcn32/dcn32_dpp.c  |   1 +
>  .../amd/display/dc/hwss/dcn10/dcn10_hwseq.c   |  90 ---
>  .../amd/display/dc/hwss/dcn20/dcn20_hwseq.c   | 106 +
>  .../amd/display/dc/hwss/dcn20/dcn20_hwseq.h   |   2 +
>  .../amd/display/dc/hwss/dcn30/dcn30_hwseq.c   | 149 ++
>  .../amd/display/dc/hwss/dcn30/dcn30_hwseq.h   |   3 +
>  .../drm/amd/display/dc/hwss/hw_sequencer.h|   2 +
>  drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h   |  14 ++
>  drivers/gpu/drm/amd/display/dc/inc/hw/mpc.h   |   7 +
>  32 files changed, 795 insertions(+), 41 deletions(-)
> 



Re: [RFC PATCH v3 21/23] drm/vkms: add 3x4 matrix in color pipeline

2024-01-04 Thread Harry Wentland



On 2023-12-08 08:11, Pekka Paalanen wrote:
> On Wed, 8 Nov 2023 11:36:40 -0500
> Harry Wentland  wrote:
> 
>> We add two 3x4 matrices into the VKMS color pipeline. The reason
>> we're adding matrices is so that we can test that application
>> of a matrix and its inverse yields an output equal to the input
>> image.
> 
> Would it not be better to mimic what a hardware driver might likely
> have? Or maybe that will be just a few more pipelines?
> 
> People testing their compositors would likely expect a more usual
> pipeline arrangement.
> 

True, but my focus with VKMS was to get the interface and core
code off the ground and make sure it's all (mostly) sane. For
more realistic testing we're currently focussing on creating the
AMD color pipeline in amdgpu.

There's definitely value in mimicing real HW with VKMS but it's
also a non-trivial task and somewhat lower in priority for me.
I think at this point there is higher value in getting a real HW
implementation off the ground.

Harry

>> One complication with the matrix implementation has to do with
>> the fact that the matrix entries are in signed-magnitude fixed
>> point, whereas the drm_fixed.h implementation uses 2s-complement.
>> The latter one is the one that we want for easy addition and
>> subtraction, so we convert all entries to 2s-complement.
>>
>> Signed-off-by: Harry Wentland 
>> ---
>>  drivers/gpu/drm/vkms/vkms_colorop.c  | 32 +++-
>>  drivers/gpu/drm/vkms/vkms_composer.c | 27 +++
>>  2 files changed, 58 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/gpu/drm/vkms/vkms_colorop.c 
>> b/drivers/gpu/drm/vkms/vkms_colorop.c
>> index 9a26b9fdc4a2..4e37e805c443 100644
>> --- a/drivers/gpu/drm/vkms/vkms_colorop.c
>> +++ b/drivers/gpu/drm/vkms/vkms_colorop.c
>> @@ -31,7 +31,37 @@ const int vkms_initialize_tf_pipeline(struct drm_plane 
>> *plane, struct drm_prop_e
>>  
>>  prev_op = op;
>>  
>> -/* 2nd op: 1d curve */
>> +/* 2nd op: 3x4 matrix */
>> +op = kzalloc(sizeof(struct drm_colorop), GFP_KERNEL);
>> +if (!op) {
>> +DRM_ERROR("KMS: Failed to allocate colorop\n");
>> +return -ENOMEM;
>> +}
>> +
>> +ret = drm_colorop_init(dev, op, plane, DRM_COLOROP_CTM_3X4);
>> +if (ret)
>> +return ret;
>> +
>> +drm_colorop_set_next_property(prev_op, op);
>> +
>> +prev_op = op;
>> +
>> +/* 3rd op: 3x4 matrix */
>> +op = kzalloc(sizeof(struct drm_colorop), GFP_KERNEL);
>> +if (!op) {
>> +DRM_ERROR("KMS: Failed to allocate colorop\n");
>> +return -ENOMEM;
>> +}
>> +
>> +ret = drm_colorop_init(dev, op, plane, DRM_COLOROP_CTM_3X4);
>> +if (ret)
>> +return ret;
>> +
>> +drm_colorop_set_next_property(prev_op, op);
>> +
>> +prev_op = op;
>> +
>> +/* 4th op: 1d curve */
>>  op = kzalloc(sizeof(struct drm_colorop), GFP_KERNEL);
>>  if (!op) {
>>  DRM_ERROR("KMS: Failed to allocate colorop\n");
>> diff --git a/drivers/gpu/drm/vkms/vkms_composer.c 
>> b/drivers/gpu/drm/vkms/vkms_composer.c
>> index d04a235b9fcd..c278fb223188 100644
>> --- a/drivers/gpu/drm/vkms/vkms_composer.c
>> +++ b/drivers/gpu/drm/vkms/vkms_composer.c
>> @@ -164,6 +164,30 @@ static void apply_lut(const struct vkms_crtc_state 
>> *crtc_state, struct line_buff
>>  }
>>  }
>>  
>> +static void apply_3x4_matrix(struct pixel_argb_s32 *pixel, const struct 
>> drm_color_ctm_3x4 *matrix)
>> +{
>> +s64 rf, gf, bf;
>> +
>> +rf = drm_fixp_mul(drm_sm2fixp(matrix->matrix[0]), 
>> drm_int2fixp(pixel->r)) +
>> + drm_fixp_mul(drm_sm2fixp(matrix->matrix[1]), 
>> drm_int2fixp(pixel->g)) +
>> + drm_fixp_mul(drm_sm2fixp(matrix->matrix[2]), 
>> drm_int2fixp(pixel->b)) +
>> + drm_sm2fixp(matrix->matrix[3]);
> 
> Again, if you went for performance, you'd make a copy of the matrix in
> fixp format in advance, to avoid having to convert the same thing for
> every processed pixel.
> 
>> +
>> +gf = drm_fixp_mul(drm_sm2fixp(matrix->matrix[4]), 
>> drm_int2fixp(pixel->r)) +
>> + drm_fixp_mul(drm_sm2fixp(matrix->matrix[5]), 
>> drm_int2fixp(pixel->g)) +
>> + drm_fixp_mul(drm_sm2fixp(matrix->matrix[6]), 
>> drm_int2fixp(pixel->b)) +
>> + drm_sm2fixp(matrix->matrix[7]);
>> +
>> +bf = d

Re: [RFC PATCH v3 23/23] drm/vkms: Add tests for CTM handling

2024-01-04 Thread Harry Wentland



On 2023-12-08 08:32, Pekka Paalanen wrote:
> On Wed, 8 Nov 2023 11:36:42 -0500
> Harry Wentland  wrote:
> 
>> A whole slew of tests for CTM handling that greatly helped in
>> debugging the CTM code. The extent of tests might seem a bit
>> silly but they're fast and might someday help save someone
>> else's day when debugging this.
> 
> To be honest, this looks pretty limited testing. I guess the more
> exhaustive tests are in IGT though, would be nice to mention that in
> the commit message.
> 
> There is not a single case for out of [0.0, 1.0] input nor output.
> 
> The offset part is always zero.
> 

It is very limited testing, mostly intended for sanity checking.
If I find time I might expand on these but it's pretty low
priority at the moment. The core of the testing is intended to
be done via IGT.

Harry

>> Signed-off-by: Harry Wentland 
>> ---
>>  drivers/gpu/drm/vkms/tests/vkms_color_tests.c | 258 ++
>>  drivers/gpu/drm/vkms/vkms_composer.c  |   2 +-
>>  2 files changed, 259 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/gpu/drm/vkms/tests/vkms_color_tests.c 
>> b/drivers/gpu/drm/vkms/tests/vkms_color_tests.c
>> index ad4c2f72fd1e..3eaa2233afbb 100644
>> --- a/drivers/gpu/drm/vkms/tests/vkms_color_tests.c
>> +++ b/drivers/gpu/drm/vkms/tests/vkms_color_tests.c
>> @@ -3,6 +3,7 @@
>>  #include 
>>  
>>  #include 
>> +#include 
>>  
>>  #define TEST_LUT_SIZE 16
>>  
>> @@ -80,11 +81,268 @@ static void vkms_color_srgb_inv_srgb(struct kunit *test)
>>  }
>>  }
>>  
>> +#define FIXPT_HALF(DRM_FIXED_ONE >> 1)
>> +#define FIXPT_QUARTER (DRM_FIXED_ONE >> 2)
>> +
>> +const struct drm_color_ctm_3x4 test_matrix_3x4_50_desat = { {
>> +FIXPT_HALF, FIXPT_QUARTER, FIXPT_QUARTER, 0,
>> +FIXPT_QUARTER, FIXPT_HALF, FIXPT_QUARTER, 0,
>> +FIXPT_QUARTER, FIXPT_QUARTER, FIXPT_HALF, 0
>> +} };
>> +
>> +static void vkms_color_ctm_3x4_50_desat(struct kunit *test)
>> +{
>> +struct pixel_argb_s32 ref, out;
>> +
>> +/* full white */
>> +ref.a = 0x0;
>> +ref.r = 0x;
>> +ref.g = 0x;
>> +ref.b = 0x;
>> +
>> +memcpy(, , sizeof(out));
>> +apply_3x4_matrix(, _matrix_3x4_50_desat);
>> +
>> +KUNIT_EXPECT_MEMEQ(test, , , sizeof(out));
>> +
>> +/* full black */
>> +ref.a = 0x0;
> 
> This is transparent, btw.
> 
>> +ref.r = 0x0;
>> +ref.g = 0x0;
>> +ref.b = 0x0;
>> +
>> +memcpy(, , sizeof(out));
>> +apply_3x4_matrix(, _matrix_3x4_50_desat);
>> +
>> +KUNIT_EXPECT_MEMEQ(test, , , sizeof(out));
>> +
>> +/* 50% grey */
>> +ref.a = 0x0;
>> +ref.r = 0x8000;
>> +ref.g = 0x8000;
>> +ref.b = 0x8000;
>> +
>> +memcpy(, , sizeof(out));
>> +apply_3x4_matrix(, _matrix_3x4_50_desat);
>> +
>> +KUNIT_EXPECT_MEMEQ(test, , , sizeof(out));
>> +
>> +/* full red to 50% desat */
>> +ref.a = 0x0;
>> +ref.r = 0x7fff;
>> +ref.g = 0x3fff;
>> +ref.b = 0x3fff;
>> +
>> +out.a = 0x0;
>> +out.r = 0x;
>> +out.g = 0x0;
>> +out.b = 0x0;
>> +
>> +apply_3x4_matrix(, _matrix_3x4_50_desat);
>> +
>> +KUNIT_EXPECT_MEMEQ(test, , , sizeof(out));
>> +}
>> +
>> +const struct drm_color_ctm_3x4 test_matrix_3x4_bt709_enc = { {
>> +0x366cf400ull, 0xb7175900ull, 0x000127bb300ull, 0,
>> +0x80001993b3a0ull, 0x80005609fe80ull, 0x6f9db200ull, 0,
>> +0x9d70a400ull, 0x80008f011100ull, 0x8e6f9330ull, 0
>> +} };
> 
> Would be nice to have a comment explaining where these values came
> from, like a snippet of Python printing these. The conversion from real
> numbers to this representation is the interesting part.
> 
>> +
>> +static void vkms_color_ctm_3x4_bt709(struct kunit *test)
>> +{
>> +struct pixel_argb_s32 ref, out;
>> +
>> +/* full white to bt709 */
>> +ref.a = 0x0;
>> +ref.r = 0xfffe; /* off by one in 16bpc not a big deal */
>> +ref.g = 0x0;
>> +ref.b = 0x0;
>> +
>> +out.a = 0x0;
>> +out.r = 0x;
>> +out.g = 0x;
>> +out.b = 0x;
>> +
>> +apply_3x4_matrix(, _matrix_3x4_bt709_enc);
>> +
>> +/* red 255 */
>> +KUNIT_EXPECT_GT(test, out.r, 0xfe00);
> 
> This allows result grossly gre

Re: DRM TTM stack trace dump on ancient hardware

2024-01-04 Thread Harry Wentland
Oland is DCE 6 and won't default to DC.

Harry

On 2024-01-04 10:51, Christian König wrote:
> Hi Olliver,
>
> well as long as you don't explicitly disable the support for the older hw 
> generations the R7 250 is still supported and should still work perfectly 
> fine.
>
> What you see here is basically some reference counting issue, most likely in 
> the display code.
>
> Question to Alex and Harry is CIK already using DC or the classic display 
> code? If it's DC then it looks like we either miss unpinning a BO or grabbing 
> a reference to a BO.
>
> Regards,
> Christian.
>
> Am 04.01.24 um 16:38 schrieb Olliver Schinagl:
>> Sorry for just dumping this here, but for those that think this is 
>> important, just rebooted after a weird btrfs crash (remounted r/o, no 
>> dataloss it seems), probably a new kernel, and got duped with the following. 
>> Things 'seem' to work fine however. I don't even know how or where to google 
>> for this one.
>>
>>
>> My graphics card is I think the R7 250, or some old beast like that, and I 
>> also know i'm probably shouldn't be using amdgpu on this oldtimer?
>>
>> Linux 6.6.9-arch1-1 #1 SMP PREEMPT_DYNAMIC Tue, 02 Jan 2024 02:28:28 + 
>> x86_64 GNU/Linux
>> 01:00.0 VGA compatible controller: Advanced Micro Devices, Inc. [AMD/ATI] 
>> Oland XT [Radeon HD 8670 / R5 340X OEM / R7 250/350/350X OEM]
>> model name    : AMD FX(tm)-8350 Eight-Core Processor
>>
>> [    0.00] Command line: BOOT_IMAGE=/arch_root/boot/vmlinuz-linux 
>> root=UUID=d rw rootflags=subvol=arch_root radeon.audio=1 radeon.si_support=0 
>> radeon.cik_support=0 amdgpu.si_support=1 amdgpu.cik_support=1 
>> LANG=en_US.UTF-8 ivrs_ioapic=9@:00:14.0 ivrs_ioapic=10@:00:00.2 
>> noibrs noibpb nopti mitigations=off
>> [    0.091847] Kernel command line: BOOT_IMAGE=/arch_root/boot/vmlinuz-linux 
>> root=UUID=d rw rootflags=subvol=arch_root radeon.audio=1 radeon.si_support=0 
>> radeon.cik_support=0 amdgpu.si_support=1 amdgpu.cik_support=1 
>> LANG=en_US.UTF-8 ivrs_ioapic=9@:00:14.0 ivrs_ioapic=10@:00:00.2 
>> noibrs noibpb nopti mitigations=off
>> [    1.490484] [drm] radeon kernel modesetting enabled.
>> [    1.490565] radeon :01:00.0: SI support disabled by module param
>> [    4.627771] [drm] amdgpu kernel modesetting enabled.
>> [    4.627955] amdgpu: Virtual CRAT table created for CPU
>> [    4.627967] amdgpu: Topology: Add CPU node
>> [    4.650039] amdgpu :01:00.0: amdgpu: Fetched VBIOS from ROM BAR
>> [    4.650042] amdgpu: ATOM BIOS: 113-C6620600-S01
>> [    4.650054] kfd kfd: amdgpu: OLAND  not supported in kfd
>> [    4.678004] amdgpu :01:00.0: vgaarb: deactivate vga console
>> [    4.678007] amdgpu :01:00.0: amdgpu: Trusted Memory Zone (TMZ) 
>> feature not supported
>> [    4.678010] amdgpu :01:00.0: amdgpu: PCIE atomic ops is not supported
>> [    4.678715] amdgpu :01:00.0: amdgpu: VRAM: 2048M 0x00F4 - 
>> 0x00F47FFF (2048M used)
>> [    4.678718] amdgpu :01:00.0: amdgpu: GART: 1024M 0x00FF - 
>> 0x00FF3FFF
>> [    4.678878] [drm] amdgpu: 2048M of VRAM memory ready
>> [    4.678880] [drm] amdgpu: 11487M of GTT memory ready.
>> [    4.679218] amdgpu :01:00.0: amdgpu: PCIE GART of 1024M enabled 
>> (table at 0x00F40040).
>> [    4.680506] [drm] amdgpu: dpm initialized
>> [    4.680527] [drm] AMDGPU Display Connectors
>> [    5.209956] amdgpu :01:00.0: amdgpu: SE 1, SH per SE 1, CU per SH 6, 
>> active_cu_number 6
>> [    5.521572] [drm] Initialized amdgpu 3.54.0 20150101 for :01:00.0 on 
>> minor 1
>> [    5.670853] fbcon: amdgpudrmfb (fb0) is primary device
>> [    5.731643] amdgpu :01:00.0: [drm] fb0: amdgpudrmfb frame buffer 
>> device
>>
>> But kernel dumps like this are usually not a good thing (tm).
>>
>> [   32.161704] [ cut here ]
>> [   32.161708] WARNING: CPU: 0 PID: 603 at drivers/gpu/drm/ttm/ttm_bo.c:326 
>> ttm_bo_release+0x292/0x2e0 [ttm]
>> [   32.161726] Modules linked in: xt_conntrack xt_MASQUERADE 
>> nf_conntrack_netlink iptable_nat nf_nat nf_conntrack nf_defrag_ipv6 
>> nf_defrag_ipv4 xt_addrtype iptable_filter br_netfilter bridge rfcomm 
>> snd_seq_dummy snd_hrtimer snd_seq snd_seq_device overlay 8021q garp mrp stp 
>> llc cmac algif_hash algif_skcipher af_alg bnep it87 hwmon_vid edac_mce_amd 
>> kvm_amd ccp snd_hda_codec_realtek kvm snd_hda_codec_generic 
>> snd_hda_codec_hdmi snd_hda_intel btusb irqbypass snd_intel_dspcfg btrtl 
>> crct10dif_pclmul snd_intel_sdw_acpi btintel crc32_pclmul btbcm 
>> polyval_clmulni snd_hda_codec eeepc_wmi btmtk polyval_generic gf128mul 
>> asus_wmi bluetooth snd_hda_core ledtrig_audio ghash_clmulni_intel r8169 
>> sparse_keymap sha512_ssse3 snd_hwdep sha1_ssse3 platform_profile snd_pcm 
>> i8042 ecdh_generic aesni_intel serio realtek sp5100_tco snd_timer 
>> crypto_simd mdio_devres wmi_bmof rfkill cryptd pcspkr acpi_cpufreq k10temp 
>> fam15h_power i2c_piix4 snd crc16 soundcore libphy joydev mousedev mac_hid 
>> 

Re: [RFC PATCH v3 04/23] drm/vkms: Add kunit tests for VKMS LUT handling

2023-12-19 Thread Harry Wentland



On 2023-12-07 09:30, Pekka Paalanen wrote:
> On Wed, 8 Nov 2023 11:36:23 -0500
> Harry Wentland  wrote:
> 
>> Debugging LUT math is much easier when we can unit test
>> it. Add kunit functionality to VKMS and add tests for
>>  - get_lut_index
>>  - lerp_u16
>>
>> v3:
>>  - Use include way of testing static functions (Arthur)
>>
>> Signed-off-by: Harry Wentland 
>> Cc: Arthur Grillo 
>> ---
>>  drivers/gpu/drm/vkms/Kconfig  |  5 ++
>>  drivers/gpu/drm/vkms/tests/.kunitconfig   |  4 ++
>>  drivers/gpu/drm/vkms/tests/vkms_color_tests.c | 62 +++
>>  drivers/gpu/drm/vkms/vkms_composer.c  |  8 ++-
>>  4 files changed, 77 insertions(+), 2 deletions(-)
>>  create mode 100644 drivers/gpu/drm/vkms/tests/.kunitconfig
>>  create mode 100644 drivers/gpu/drm/vkms/tests/vkms_color_tests.c
>>
>> diff --git a/drivers/gpu/drm/vkms/Kconfig b/drivers/gpu/drm/vkms/Kconfig
>> index b9ecdebecb0b..c1f8b343ff0e 100644
>> --- a/drivers/gpu/drm/vkms/Kconfig
>> +++ b/drivers/gpu/drm/vkms/Kconfig
>> @@ -13,3 +13,8 @@ config DRM_VKMS
>>a VKMS.
>>  
>>If M is selected the module will be called vkms.
>> +
>> +config DRM_VKMS_KUNIT_TESTS
>> +tristate "Tests for VKMS" if !KUNIT_ALL_TESTS
>> +depends on DRM_VKMS && KUNIT
>> +default KUNIT_ALL_TESTS
>> diff --git a/drivers/gpu/drm/vkms/tests/.kunitconfig 
>> b/drivers/gpu/drm/vkms/tests/.kunitconfig
>> new file mode 100644
>> index ..70e378228cbd
>> --- /dev/null
>> +++ b/drivers/gpu/drm/vkms/tests/.kunitconfig
>> @@ -0,0 +1,4 @@
>> +CONFIG_KUNIT=y
>> +CONFIG_DRM=y
>> +CONFIG_DRM_VKMS=y
>> +CONFIG_DRM_VKMS_KUNIT_TESTS=y
>> diff --git a/drivers/gpu/drm/vkms/tests/vkms_color_tests.c 
>> b/drivers/gpu/drm/vkms/tests/vkms_color_tests.c
>> new file mode 100644
>> index ..b995114cf6b8
>> --- /dev/null
>> +++ b/drivers/gpu/drm/vkms/tests/vkms_color_tests.c
>> @@ -0,0 +1,62 @@
>> +/* SPDX-License-Identifier: GPL-2.0+ */
>> +
>> +#include 
>> +
>> +#include 
>> +
>> +#define TEST_LUT_SIZE 16
>> +
>> +static struct drm_color_lut test_linear_array[TEST_LUT_SIZE] = {
>> +{ 0x0, 0x0, 0x0, 0 },
>> +{ 0x, 0x, 0x, 0 },
>> +{ 0x, 0x, 0x, 0 },
>> +{ 0x, 0x, 0x, 0 },
>> +{ 0x, 0x, 0x, 0 },
>> +{ 0x, 0x, 0x, 0 },
>> +{ 0x, 0x, 0x, 0 },
>> +{ 0x, 0x, 0x, 0 },
>> +{ 0x, 0x, 0x, 0 },
>> +{ 0x, 0x, 0x, 0 },
>> +{ 0x, 0x, 0x, 0 },
>> +{ 0x, 0x, 0x, 0 },
>> +{ 0x, 0x, 0x, 0 },
>> +{ 0x, 0x, 0x, 0 },
>> +{ 0x, 0x, 0x, 0 },
>> +{ 0x, 0x, 0x, 0 },
>> +};
>> +
>> +const struct vkms_color_lut test_linear_lut = {
>> +.base = test_linear_array,
>> +.lut_length = TEST_LUT_SIZE,
>> +.channel_value2index_ratio = 0xf000fll
>> +};
>> +
>> +
>> +static void vkms_color_test_get_lut_index(struct kunit *test)
>> +{
>> +int i;
>> +
>> +KUNIT_EXPECT_EQ(test, drm_fixp2int(get_lut_index(_linear_lut, 
>> test_linear_array[0].red)), 0);
>> +
>> +for (i = 0; i < TEST_LUT_SIZE; i++)
>> +KUNIT_EXPECT_EQ(test, 
>> drm_fixp2int_ceil(get_lut_index(_linear_lut, 
>> test_linear_array[i].red)), i);
> 
> Hi,
> 
> what about testing with values not directly hitting a LUT element?
> 
>> +}
>> +
>> +static void vkms_color_test_lerp(struct kunit *test)
>> +{
>> +KUNIT_EXPECT_EQ(test, lerp_u16(0x0, 0x10, 0x8000), 0x8);
> 
> It would raise much more confidence in lerp_u16() if there were more cases:
> - odd a
> - odd b
> - odd b-a
> - b = a
> - b = a + 1
> 
> For each of the above:
> - t = 0.0
> - t = 1.0
> - t = 0.0 + 1
> - t = 1.0 - 1
> - t chosen so that result must round/truncate
> - t chosen to verify the flipping point of result a (or b) to a+1 (or b-1)
> 
> I think those are the fragile points in a lerp implementation.
> 

Good point. Adding the "t = 1.0 - 1" test actually showed a problem
with the lerp_u16 function. I have a fix for it.

Harry

> 
> Thanks,
> pq
> 
>> +}
>> +
>> +static struct kunit_case vkms_color_test_cases[] = {
>> +KUNIT_CASE(vkms_color_test_get_lut_index),
>> +KUNIT_CASE(vkms_color_test_lerp),
>

Re: [PATCH] drm/amd/display: fix cursor-plane-only atomic commits not triggering pageflips

2023-12-07 Thread Harry Wentland




On 2023-12-07 14:30, Xaver Hugl wrote:

Sorry, it looks like I sent this too soon. I tested the patch on a
second PC and it doesn't fix the issue there.



Ah, too bad. Won't merge it then.

Harry



Am Do., 7. Dez. 2023 um 19:25 Uhr schrieb Xaver Hugl :


With VRR, every atomic commit affecting a given display must trigger
a new scanout cycle, so that userspace is able to control the refresh
rate of the display. Before this commit, this was not the case for
atomic commits that only contain cursor plane properties.

Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/3034
Cc: sta...@vger.kernel.org

Signed-off-by: Xaver Hugl 
---
  drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 10 --
  1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index b452796fc6d3..b379c859fbef 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -8149,9 +8149,15 @@ static void amdgpu_dm_commit_planes(struct 
drm_atomic_state *state,
 /* Cursor plane is handled after stream updates */
 if (plane->type == DRM_PLANE_TYPE_CURSOR) {
 if ((fb && crtc == pcrtc) ||
-   (old_plane_state->fb && old_plane_state->crtc == 
pcrtc))
+   (old_plane_state->fb && old_plane_state->crtc == 
pcrtc)) {
 cursor_update = true;
-
+   /*
+* With atomic modesetting, cursor changes must
+* also trigger a new refresh period with vrr
+*/
+   if (!state->legacy_cursor_update)
+   pflip_present = true;
+   }
 continue;
 }

--
2.43.0



Re: [PATCH] drm/amd/display: fix cursor-plane-only atomic commits not triggering pageflips

2023-12-07 Thread Harry Wentland

On 2023-12-07 13:25, Xaver Hugl wrote:

With VRR, every atomic commit affecting a given display must trigger
a new scanout cycle, so that userspace is able to control the refresh
rate of the display. Before this commit, this was not the case for
atomic commits that only contain cursor plane properties.

Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/3034
Cc: sta...@vger.kernel.org

Signed-off-by: Xaver Hugl 


Reviewed-by: Harry Wentland 

Harry


---
  drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 10 --
  1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index b452796fc6d3..b379c859fbef 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -8149,9 +8149,15 @@ static void amdgpu_dm_commit_planes(struct 
drm_atomic_state *state,
/* Cursor plane is handled after stream updates */
if (plane->type == DRM_PLANE_TYPE_CURSOR) {
if ((fb && crtc == pcrtc) ||
-   (old_plane_state->fb && old_plane_state->crtc == 
pcrtc))
+   (old_plane_state->fb && old_plane_state->crtc == 
pcrtc)) {
cursor_update = true;
-
+   /*
+* With atomic modesetting, cursor changes must
+* also trigger a new refresh period with vrr
+*/
+   if (!state->legacy_cursor_update)
+   pflip_present = true;
+   }
continue;
}
  


Re: [PATCH v2 2/8] drm/amdgpu: Do not include

2023-12-05 Thread Harry Wentland
On 2023-12-04 04:07, Thomas Zimmermann wrote:
> Remove unnecessary include statements for .
> The file contains helpers for non-atomic code and should not be
> required by most drivers. No functional changes.
> 
> Signed-off-by: Thomas Zimmermann 

Reviewed-by: Harry Wentland 

Harry

> ---
>  drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 1 -
>  1 file changed, 1 deletion(-)
> 
> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 
> b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> index aa43f1761acd3..b8c3a9b104a41 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> @@ -92,7 +92,6 @@
>  #include 
>  #include 
>  #include 
> -#include 
>  
>  #include 
>  



Re: [PATCH v5 00/32] drm/amd/display: add AMD driver-specific properties for color mgmt

2023-12-01 Thread Harry Wentland



On 2023-11-30 06:34, Daniel Vetter wrote:
> On Tue, 28 Nov 2023 at 23:11, Harry Wentland  wrote:
>>
>> On 2023-11-16 14:57, Melissa Wen wrote:
>>> Hello,
>>>
>>> This series extends the current KMS color management API with AMD
>>> driver-specific properties to enhance the color management support on
>>> AMD Steam Deck. The key additions to the color pipeline include:
>>>
>>
>> snip
>>
>>> Melissa Wen (18):
>>>   drm/drm_mode_object: increase max objects to accommodate new color
>>> props
>>>   drm/drm_property: make replace_property_blob_from_id a DRM helper
>>>   drm/drm_plane: track color mgmt changes per plane
>>
>> If all patches are merged through amd-staging-drm-next I worry that
>> conflicts creep in if any code around replace_property_blob_from_id
>> changes in DRM.
>>
>> My plan is to merge DRM patches through drm-misc-next, as well
>> as include them in the amd-staging-drm-next merge. They should then
>> fall out at the next amd-staging-drm-next pull and (hopefully)
>> ensure that there is no conflict.
>>
>> If no objections I'll go ahead with that later this week.
> 
> Double-merging tends to be the worst because git doesn't realize the
> commits match, which actually makes the conflicts worse when they
> happen (because the 3-way merge diff gets absolute confused by all the
> changed context and misplaces everything to the max). So please don't,
> _only_ every cherry-pick when a patch in -next is also needed in
> -fixes, and we didn't put it into the right tree. But even that is a
> bit tricky and should only be done by maintainers (using dim
> cherry-pick if it's drm-misc) because the conflicts tend to be bad and
> need to be sorted out with backmerges sooner than later.
> 
> For this case merge everything through one tree with the right acks,
> pull to drm-next asap and then backmerge into the other tree. Here
> probably amdgpu-next with drm-misc maintainer acks for the 3 core
> patches. Or if amdgpu-next pull won't come for a while, put them into
> drm-misc-next and just wait a week until it's in drm-next, then
> forward amdgpu-next.
> 

Maxime, Maarten, Thomas, could I get an ACK from you for the three
DRM core patches and an ACK for pulling them through the AMD tree?

Thanks,
Harry

> Cheers, Sima
> 
>> Harry
>>
>>>   drm/amd/display: add driver-specific property for plane degamma LUT
>>>   drm/amd/display: explicitly define EOTF and inverse EOTF
>>>   drm/amd/display: document AMDGPU pre-defined transfer functions
>>>   drm/amd/display: add plane 3D LUT driver-specific properties
>>>   drm/amd/display: add plane shaper LUT and TF driver-specific
>>> properties
>>>   drm/amd/display: add CRTC gamma TF driver-specific property
>>>   drm/amd/display: add comments to describe DM crtc color mgmt behavior
>>>   drm/amd/display: encapsulate atomic regamma operation
>>>   drm/amd/display: decouple steps for mapping CRTC degamma to DC plane
>>>   drm/amd/display: reject atomic commit if setting both plane and CRTC
>>> degamma
>>>   drm/amd/display: add plane shaper LUT support
>>>   drm/amd/display: add plane shaper TF support
>>>   drm/amd/display: add plane 3D LUT support
>>>   drm/amd/display: add plane CTM driver-specific property
>>>   drm/amd/display: add plane CTM support
>>>
>>>  drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h  |  91 ++
>>>  .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c |  34 +-
>>>  .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 108 +++
>>>  .../amd/display/amdgpu_dm/amdgpu_dm_color.c   | 818 --
>>>  .../amd/display/amdgpu_dm/amdgpu_dm_crtc.c|  72 ++
>>>  .../amd/display/amdgpu_dm/amdgpu_dm_plane.c   | 232 -
>>>  .../gpu/drm/amd/display/include/fixed31_32.h  |  12 +
>>>  drivers/gpu/drm/arm/malidp_crtc.c |   2 +-
>>>  drivers/gpu/drm/drm_atomic.c  |   1 +
>>>  drivers/gpu/drm/drm_atomic_state_helper.c |   1 +
>>>  drivers/gpu/drm/drm_atomic_uapi.c |  43 +-
>>>  drivers/gpu/drm/drm_property.c|  49 ++
>>>  include/drm/drm_mode_object.h |   2 +-
>>>  include/drm/drm_plane.h   |   7 +
>>>  include/drm/drm_property.h|   6 +
>>>  include/uapi/drm/drm_mode.h   |   8 +
>>>  16 files changed, 1377 insertions(+), 109 deletions(-)
>>>
>>
> 
> 



Re: [PATCH v5 00/32] drm/amd/display: add AMD driver-specific properties for color mgmt

2023-11-28 Thread Harry Wentland
On 2023-11-16 14:57, Melissa Wen wrote:
> Hello,
> 
> This series extends the current KMS color management API with AMD
> driver-specific properties to enhance the color management support on
> AMD Steam Deck. The key additions to the color pipeline include:
> 

snip

> Melissa Wen (18):
>   drm/drm_mode_object: increase max objects to accommodate new color
> props
>   drm/drm_property: make replace_property_blob_from_id a DRM helper
>   drm/drm_plane: track color mgmt changes per plane

If all patches are merged through amd-staging-drm-next I worry that
conflicts creep in if any code around replace_property_blob_from_id
changes in DRM.

My plan is to merge DRM patches through drm-misc-next, as well
as include them in the amd-staging-drm-next merge. They should then
fall out at the next amd-staging-drm-next pull and (hopefully)
ensure that there is no conflict.

If no objections I'll go ahead with that later this week.

Harry

>   drm/amd/display: add driver-specific property for plane degamma LUT
>   drm/amd/display: explicitly define EOTF and inverse EOTF
>   drm/amd/display: document AMDGPU pre-defined transfer functions
>   drm/amd/display: add plane 3D LUT driver-specific properties
>   drm/amd/display: add plane shaper LUT and TF driver-specific
> properties
>   drm/amd/display: add CRTC gamma TF driver-specific property
>   drm/amd/display: add comments to describe DM crtc color mgmt behavior
>   drm/amd/display: encapsulate atomic regamma operation
>   drm/amd/display: decouple steps for mapping CRTC degamma to DC plane
>   drm/amd/display: reject atomic commit if setting both plane and CRTC
> degamma
>   drm/amd/display: add plane shaper LUT support
>   drm/amd/display: add plane shaper TF support
>   drm/amd/display: add plane 3D LUT support
>   drm/amd/display: add plane CTM driver-specific property
>   drm/amd/display: add plane CTM support
> 
>  drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h  |  91 ++
>  .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c |  34 +-
>  .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 108 +++
>  .../amd/display/amdgpu_dm/amdgpu_dm_color.c   | 818 --
>  .../amd/display/amdgpu_dm/amdgpu_dm_crtc.c|  72 ++
>  .../amd/display/amdgpu_dm/amdgpu_dm_plane.c   | 232 -
>  .../gpu/drm/amd/display/include/fixed31_32.h  |  12 +
>  drivers/gpu/drm/arm/malidp_crtc.c |   2 +-
>  drivers/gpu/drm/drm_atomic.c  |   1 +
>  drivers/gpu/drm/drm_atomic_state_helper.c |   1 +
>  drivers/gpu/drm/drm_atomic_uapi.c |  43 +-
>  drivers/gpu/drm/drm_property.c|  49 ++
>  include/drm/drm_mode_object.h |   2 +-
>  include/drm/drm_plane.h   |   7 +
>  include/drm/drm_property.h|   6 +
>  include/uapi/drm/drm_mode.h   |   8 +
>  16 files changed, 1377 insertions(+), 109 deletions(-)
> 



Re: [PATCH v5 09/32] drm/amd/display: add plane 3D LUT driver-specific properties

2023-11-17 Thread Harry Wentland

On 2023-11-16 14:57, Melissa Wen wrote:

Add 3D LUT property for plane color transformations using a 3D lookup
table. 3D LUT allows for highly accurate and complex color
transformations and is suitable to adjust the balance between color
channels. It's also more complex to manage and require more
computational resources.

Since a 3D LUT has a limited number of entries in each dimension we want
to use them in an optimal fashion. This means using the 3D LUT in a
colorspace that is optimized for human vision, such as sRGB, PQ, or
another non-linear space. Therefore, userpace may need one 1D LUT
(shaper) before it to delinearize content and another 1D LUT after 3D
LUT (blend) to linearize content again for blending. The next patches
add these 1D LUTs to the plane color mgmt pipeline.

v3:
- improve commit message about 3D LUT
- describe the 3D LUT entries and size (Harry)

v4:
- advertise 3D LUT max size as the size of a single-dimension

v5:
- get lut3d blob correctly (Joshua)
- fix doc about 3d-lut dimension size (Sebastian)

Signed-off-by: Melissa Wen 


Reviewed-by: Harry Wentland 

We'll run this series through our testing. If that doesn't show
problems and if I don't see any new comments on the series I'm
planning to merge it through amd-staging-drm-next.

Harry



---
  drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h  | 18 ++
  .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h |  9 +++
  .../amd/display/amdgpu_dm/amdgpu_dm_color.c   | 14 +++
  .../amd/display/amdgpu_dm/amdgpu_dm_plane.c   | 24 +++
  4 files changed, 65 insertions(+)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
index ee67c5adf0f1..57822477408f 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
@@ -364,6 +364,24 @@ struct amdgpu_mode_info {
 * @plane_hdr_mult_property:
 */
struct drm_property *plane_hdr_mult_property;
+   /**
+* @plane_lut3d_property: Plane property for color transformation using
+* a 3D LUT (pre-blending), a three-dimensional array where each
+* element is an RGB triplet. Each dimension has the size of
+* lut3d_size. The array contains samples from the approximated
+* function. On AMD, values between samples are estimated by
+* tetrahedral interpolation. The array is accessed with three indices,
+* one for each input dimension (color channel), blue being the
+* outermost dimension, red the innermost.
+*/
+   struct drm_property *plane_lut3d_property;
+   /**
+* @plane_degamma_lut_size_property: Plane property to define the max
+* size of 3D LUT as supported by the driver (read-only). The max size
+* is the max size of one dimension and, therefore, the max number of
+* entries for 3D LUT array is the 3D LUT size cubed;
+*/
+   struct drm_property *plane_lut3d_size_property;
  };
  
  #define AMDGPU_MAX_BL_LEVEL 0xFF

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
index 38163b7084fa..03b48b331b7c 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -776,6 +776,11 @@ struct dm_plane_state {
 * TF is needed for any subsequent linear-to-non-linear transforms.
 */
__u64 hdr_mult;
+   /**
+* @lut3d: 3D lookup table blob. The blob (if not NULL) is an array of
+*  drm_color_lut.
+*/
+   struct drm_property_blob *lut3d;
  };
  
  struct dm_crtc_state {

@@ -861,6 +866,10 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector 
*connector,
  
  void amdgpu_dm_trigger_timing_sync(struct drm_device *dev);
  
+/* 3D LUT max size is 17x17x17 (4913 entries) */

+#define MAX_COLOR_3DLUT_SIZE 17
+#define MAX_COLOR_3DLUT_BITDEPTH 12
+/* 1D LUT size */
  #define MAX_COLOR_LUT_ENTRIES 4096
  /* Legacy gamm LUT users such as X doesn't like large LUT sizes */
  #define MAX_COLOR_LEGACY_LUT_ENTRIES 256
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 b5b34a9209e4..a3b4f6a4c4a8 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
@@ -231,6 +231,20 @@ amdgpu_dm_create_color_properties(struct amdgpu_device 
*adev)
return -ENOMEM;
adev->mode_info.plane_hdr_mult_property = prop;
  
+	prop = drm_property_create(adev_to_drm(adev),

+  DRM_MODE_PROP_BLOB,
+  "AMD_PLANE_LUT3D", 0);
+   if (!prop)
+   return -ENOMEM;
+   adev->mode_info.plane_lut3d_property = prop;
+
+   prop = drm_property_create_range(adev_to_drm(adev),
+DRM_MOD

Re: [PATCH v4 12/32] drm/amd/display: add CRTC gamma TF driver-specific property

2023-11-15 Thread Harry Wentland



On 2023-10-05 13:15, Melissa Wen wrote:
> Add AMD pre-defined transfer function property to default DRM CRTC gamma
> to convert to wire encoding with or without a user gamma LUT. There is
> no post-blending regamma ROM for pre-defined TF. When setting Gamma TF
> (!= Identity) and LUT at the same time, the color module will combine
> the pre-defined TF and the custom LUT values into the LUT that's
> actually programmed.
> 
> v2:
> - enable CRTC prop in the end of driver-specific prop sequence
> - define inverse EOTFs as supported regamma TFs
> - reword driver-specific function doc to remove shaper/3D LUT
> 
> v3:
> - spell out TF+LUT behavior in the commit and comments (Harry)
> 
> Co-developed-by: Joshua Ashton 
> Signed-off-by: Joshua Ashton 
> Signed-off-by: Melissa Wen 

Reviewed-by: Harry Wentland 

Harry

> ---
>  drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h  |  7 ++
>  .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h |  8 +++
>  .../amd/display/amdgpu_dm/amdgpu_dm_color.c   |  7 ++
>  .../amd/display/amdgpu_dm/amdgpu_dm_crtc.c| 72 +++
>  4 files changed, 94 insertions(+)
> 
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h 
> b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
> index dee35d208493..071cc10bfd90 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
> @@ -424,6 +424,13 @@ struct amdgpu_mode_info {
>* from a combination of pre-defined TF and the custom 1D LUT).
>*/
>   struct drm_property *plane_blend_tf_property;
> + /* @regamma_tf_property: Transfer function for CRTC regamma
> +  * (post-blending). Possible values are defined by `enum
> +  * amdgpu_transfer_function`. There is no regamma ROM, but we can use
> +  * AMD color modules to program LUT parameters from predefined TF (or
> +  * from a combination of pre-defined TF and the custom 1D LUT).
> +  */
> + struct drm_property *regamma_tf_property;
>  };
>  
>  #define AMDGPU_MAX_BL_LEVEL 0xFF
> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h 
> b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
> index 1b96c742d747..c138457ff12e 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
> @@ -836,6 +836,14 @@ struct dm_crtc_state {
>   struct dc_info_packet vrr_infopacket;
>  
>   int abm_level;
> +
> +/**
> +  * @regamma_tf:
> +  *
> +  * Pre-defined transfer function for converting internal FB -> wire
> +  * encoding.
> +  */
> + enum amdgpu_transfer_function regamma_tf;
>  };
>  
>  #define to_dm_crtc_state(x) container_of(x, struct dm_crtc_state, base)
> 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 82c554662faa..2ecfa0e886e8 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
> @@ -294,6 +294,13 @@ amdgpu_dm_create_color_properties(struct amdgpu_device 
> *adev)
>   return -ENOMEM;
>   adev->mode_info.plane_blend_tf_property = prop;
>  
> + prop = amdgpu_create_tf_property(adev_to_drm(adev),
> +  "AMD_CRTC_REGAMMA_TF",
> +  amdgpu_inv_eotf);
> + if (!prop)
> + return -ENOMEM;
> + adev->mode_info.regamma_tf_property = prop;
> +
>   return 0;
>  }
>  #endif
> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c 
> b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c
> index 440fc0869a34..d746f0aa0f11 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c
> @@ -253,6 +253,7 @@ static struct drm_crtc_state 
> *dm_crtc_duplicate_state(struct drm_crtc *crtc)
>   state->freesync_config = cur->freesync_config;
>   state->cm_has_degamma = cur->cm_has_degamma;
>   state->cm_is_degamma_srgb = cur->cm_is_degamma_srgb;
> + state->regamma_tf = cur->regamma_tf;
>   state->crc_skip_count = cur->crc_skip_count;
>   state->mpo_requested = cur->mpo_requested;
>   /* TODO Duplicate dc_stream after objects are stream object is 
> flattened */
> @@ -289,6 +290,70 @@ static int amdgpu_dm_crtc_late_register(struct drm_crtc 
> *crtc)
>  }
>  #endif
>  
> +#ifdef AMD_PRIVATE_COLOR
> +/**
> + * drm_crtc_additional_color_mgmt - enable additional color properties
> + * @crtc: DRM CRTC
> + *
> + * This function lets the driver enable 

Re: [PATCH v4 11/32] drm/amd/display: add plane blend LUT and TF driver-specific properties

2023-11-15 Thread Harry Wentland



On 2023-10-05 13:15, Melissa Wen wrote:
> From: Joshua Ashton 
> 
> Blend 1D LUT or a pre-defined transfer function (TF) can be set to
> linearize content before blending, so that it's positioned just before
> blending planes in the AMD color mgmt pipeline, and after 3D LUT
> (non-linear space). Shaper and Blend LUTs are 1D LUTs that sandwich 3D
> LUT. Drivers should advertize blend properties according to HW caps.
> 
> There is no blend ROM for pre-defined TF. When setting blend TF (!=
> Identity) and LUT at the same time, the color module will combine the
> pre-defined TF and the custom LUT values into the LUT that's actually
> programmed.
> 
> v3:
> - spell out TF+LUT behavior in the commit and comments (Harry)
> 
> Signed-off-by: Joshua Ashton 
> Signed-off-by: Melissa Wen 

Reviewed-by: Harry Wentland 

Harry

> ---
>  drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h  | 22 
>  .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 12 +++
>  .../amd/display/amdgpu_dm/amdgpu_dm_color.c   | 21 +++
>  .../amd/display/amdgpu_dm/amdgpu_dm_plane.c   | 36 +++
>  4 files changed, 91 insertions(+)
> 
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h 
> b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
> index af70db4f6b4b..dee35d208493 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
> @@ -402,6 +402,28 @@ struct amdgpu_mode_info {
>* entries for 3D LUT array is the 3D LUT size cubed;
>*/
>   struct drm_property *plane_lut3d_size_property;
> + /**
> +  * @plane_blend_lut_property: Plane property for output gamma before
> +  * blending. Userspace set a blend LUT to convert colors after 3D LUT
> +  * conversion. It works as a post-3DLUT 1D LUT. With shaper LUT, they
> +  * are sandwiching 3D LUT with two 1D LUT. If plane_blend_tf_property
> +  * != Identity TF, AMD color module will combine the user LUT values
> +  * with pre-defined TF into the LUT parameters to be programmed.
> +  */
> + struct drm_property *plane_blend_lut_property;
> + /**
> +  * @plane_blend_lut_size_property: Plane property to define the max
> +  * size of blend LUT as supported by the driver (read-only).
> +  */
> + struct drm_property *plane_blend_lut_size_property;
> + /**
> +  * @plane_blend_tf_property: Plane property to set a predefined
> +  * transfer function for pre-blending blend/out_gamma (after applying
> +  * 3D LUT) with or without LUT. There is no blend ROM, but we can use
> +  * AMD color modules to program LUT parameters from predefined TF (or
> +  * from a combination of pre-defined TF and the custom 1D LUT).
> +  */
> + struct drm_property *plane_blend_tf_property;
>  };
>  
>  #define AMDGPU_MAX_BL_LEVEL 0xFF
> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h 
> b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
> index 0e2a04a3caf3..1b96c742d747 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
> @@ -800,6 +800,18 @@ struct dm_plane_state {
>*  drm_color_lut.
>*/
>   struct drm_property_blob *lut3d;
> + /**
> +  * @blend_lut: blend lut lookup table blob. The blob (if not NULL) is an
> +  * array of  drm_color_lut.
> +  */
> + struct drm_property_blob *blend_lut;
> + /**
> +  * @blend_tf:
> +  *
> +  * Pre-defined transfer function for converting plane pixel data before
> +  * applying blend LUT.
> +  */
> + enum amdgpu_transfer_function blend_tf;
>  };
>  
>  struct dm_crtc_state {
> 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 d3c7f9a13a61..82c554662faa 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
> @@ -273,6 +273,27 @@ amdgpu_dm_create_color_properties(struct amdgpu_device 
> *adev)
>   return -ENOMEM;
>   adev->mode_info.plane_lut3d_size_property = prop;
>  
> + prop = drm_property_create(adev_to_drm(adev),
> +DRM_MODE_PROP_BLOB,
> +"AMD_PLANE_BLEND_LUT", 0);
> + if (!prop)
> + return -ENOMEM;
> + adev->mode_info.plane_blend_lut_property = prop;
> +
> + prop = drm_property_create_range(adev_to_drm(adev),
> +  DRM_MODE_PROP_IMMUTABLE,
> +  "AMD_PLANE_BLEND_LUT_SIZE", 0, 
> UINT_MAX)

Re: [PATCH v4 10/32] drm/amd/display: add plane shaper LUT and TF driver-specific properties

2023-11-15 Thread Harry Wentland



On 2023-10-05 13:15, Melissa Wen wrote:
> On AMD HW, 3D LUT always assumes a preceding shaper 1D LUT used for
> delinearizing and/or normalizing the color space before applying a 3D
> LUT. Add pre-defined transfer function to enable delinearizing content
> with or without shaper LUT, where AMD color module calculates the
> resulted shaper curve. We apply an inverse EOTF to go from linear
> values to encoded values. If we are already in a non-linear space and/or
> don't need to normalize values, we can bypass shaper LUT with a linear
> transfer function that is also the default TF value.
> 
> There is no shaper ROM. When setting shaper TF (!= Identity) and LUT at
> the same time, the color module will combine the pre-defined TF and the
> custom LUT values into the LUT that's actually programmed.
> 
> v2:
> - squash commits for shaper LUT and shaper TF
> - define inverse EOTF as supported shaper TFs
> 
> v3:
> - spell out TF+LUT behavior in the commit and comments (Harry)
> - replace BT709 EOTF by inv OETF
> 
> Signed-off-by: Melissa Wen 

Reviewed-by: Harry Wentland 

Harry

> ---
>  drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h  | 21 
>  .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 11 +++
>  .../amd/display/amdgpu_dm/amdgpu_dm_color.c   | 29 +
>  .../amd/display/amdgpu_dm/amdgpu_dm_plane.c   | 32 +++
>  4 files changed, 93 insertions(+)
> 
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h 
> b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
> index f7adaa52c23f..af70db4f6b4b 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
> @@ -363,6 +363,27 @@ struct amdgpu_mode_info {
>* @plane_hdr_mult_property:
>*/
>   struct drm_property *plane_hdr_mult_property;
> + /**
> +  * @shaper_lut_property: Plane property to set pre-blending shaper LUT
> +  * that converts color content before 3D LUT. If
> +  * plane_shaper_tf_property != Identity TF, AMD color module will
> +  * combine the user LUT values with pre-defined TF into the LUT
> +  * parameters to be programmed.
> +  */
> + struct drm_property *plane_shaper_lut_property;
> + /**
> +  * @shaper_lut_size_property: Plane property for the size of
> +  * pre-blending shaper LUT as supported by the driver (read-only).
> +  */
> + struct drm_property *plane_shaper_lut_size_property;
> + /**
> +  * @plane_shaper_tf_property: Plane property to set a predefined
> +  * transfer function for pre-blending shaper (before applying 3D LUT)
> +  * with or without LUT. There is no shaper ROM, but we can use AMD
> +  * color modules to program LUT parameters from predefined TF (or
> +  * from a combination of pre-defined TF and the custom 1D LUT).
> +  */
> + struct drm_property *plane_shaper_tf_property;
>   /**
>* @plane_lut3d_property: Plane property for color transformation using
>* a 3D LUT (pre-blending), a three-dimensional array where each
> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h 
> b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
> index 7a2350c62cf1..0e2a04a3caf3 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
> @@ -784,6 +784,17 @@ struct dm_plane_state {
>* TF is needed for any subsequent linear-to-non-linear transforms.
>*/
>   __u64 hdr_mult;
> + /**
> +  * @shaper_lut: shaper lookup table blob. The blob (if not NULL) is an
> +  * array of  drm_color_lut.
> +  */
> + struct drm_property_blob *shaper_lut;
> + /**
> +  * @shaper_tf:
> +  *
> +  * Predefined transfer function to delinearize color space.
> +  */
> + enum amdgpu_transfer_function shaper_tf;
>   /**
>* @lut3d: 3D lookup table blob. The blob (if not NULL) is an array of
>*  drm_color_lut.
> 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 011f2f9ec890..d3c7f9a13a61 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
> @@ -173,6 +173,14 @@ static const u32 amdgpu_eotf =
>   BIT(AMDGPU_TRANSFER_FUNCTION_GAMMA24_EOTF) |
>   BIT(AMDGPU_TRANSFER_FUNCTION_GAMMA26_EOTF);
>  
> +static const u32 amdgpu_inv_eotf =
> + BIT(AMDGPU_TRANSFER_FUNCTION_SRGB_INV_EOTF) |
> + BIT(AMDGPU_TRANSFER_FUNCTION_BT709_OETF) |
> + BIT(AMDGPU_TRANSFER_FUNCTION_PQ_INV_EOTF) |
> + BIT(AMDGPU_TRANSFER_FUNCTION_GAMMA22_INV_EOTF) |
> + B

Re: [PATCH v4 08/32] drm/amd/display: add plane HDR multiplier driver-specific property

2023-11-15 Thread Harry Wentland



On 2023-10-05 13:15, Melissa Wen wrote:
> From: Joshua Ashton 
> 
> Multiplier to 'gain' the plane. When PQ is decoded using the fixed func
> transfer function to the internal FP16 fb, 1.0 -> 80 nits (on AMD at
> least) When sRGB is decoded, 1.0 -> 1.0.  Therefore, 1.0 multiplier = 80
> nits for SDR content. So if you want, 203 nits for SDR content, pass in
> (203.0 / 80.0).
> 
> v4:
> - comment about the PQ TF need for L-to-NL (from Harry's review)
> 
> Signed-off-by: Joshua Ashton 
> Co-developed-by: Melissa Wen 
> Signed-off-by: Melissa Wen 

Reviewed-by: Harry Wentland 

Harry

> ---
>  drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h|  4 
>  .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h   | 17 +
>  .../drm/amd/display/amdgpu_dm/amdgpu_dm_color.c |  6 ++
>  .../drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c | 13 +
>  4 files changed, 40 insertions(+)
> 
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h 
> b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
> index 9b6fab86c6c3..62044d41da75 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
> @@ -359,6 +359,10 @@ struct amdgpu_mode_info {
>* to go from scanout/encoded values to linear values.
>*/
>   struct drm_property *plane_degamma_tf_property;
> + /**
> +  * @plane_hdr_mult_property:
> +  */
> + struct drm_property *plane_hdr_mult_property;
>  };
>  
>  #define AMDGPU_MAX_BL_LEVEL 0xFF
> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h 
> b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
> index fc4f188d397e..bb2ce843369d 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
> @@ -55,6 +55,9 @@
>  #define HDMI_AMD_VENDOR_SPECIFIC_DATA_BLOCK_IEEE_REGISTRATION_ID 0x1A
>  #define AMD_VSDB_VERSION_3_FEATURECAP_REPLAYMODE 0x40
>  #define HDMI_AMD_VENDOR_SPECIFIC_DATA_BLOCK_VERSION_3 0x3
> +
> +#define AMDGPU_HDR_MULT_DEFAULT (0x1LL)
> +
>  /*
>  #include "include/amdgpu_dal_power_if.h"
>  #include "amdgpu_dm_irq.h"
> @@ -767,6 +770,20 @@ struct dm_plane_state {
>* linearize.
>*/
>   enum amdgpu_transfer_function degamma_tf;
> + /**
> +  * @hdr_mult:
> +  *
> +  * Multiplier to 'gain' the plane.  When PQ is decoded using the fixed
> +  * func transfer function to the internal FP16 fb, 1.0 -> 80 nits (on
> +  * AMD at least). When sRGB is decoded, 1.0 -> 1.0, obviously.
> +  * Therefore, 1.0 multiplier = 80 nits for SDR content.  So if you
> +  * want, 203 nits for SDR content, pass in (203.0 / 80.0).  Format is
> +  * S31.32 sign-magnitude.
> +  *
> +  * HDR multiplier can wide range beyond [0.0, 1.0]. This means that PQ
> +  * TF is needed for any subsequent linear-to-non-linear transforms.
> +  */
> + __u64 hdr_mult;
>  };
>  
>  struct dm_crtc_state {
> 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 d5dbd20a6766..caf49a044ab4 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
> @@ -224,6 +224,12 @@ amdgpu_dm_create_color_properties(struct amdgpu_device 
> *adev)
>   return -ENOMEM;
>   adev->mode_info.plane_degamma_tf_property = prop;
>  
> + prop = drm_property_create_range(adev_to_drm(adev),
> +  0, "AMD_PLANE_HDR_MULT", 0, U64_MAX);
> + if (!prop)
> + return -ENOMEM;
> + adev->mode_info.plane_hdr_mult_property = prop;
> +
>   return 0;
>  }
>  #endif
> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c 
> b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
> index 04af6db8cffd..ae64d4b73360 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
> @@ -1337,6 +1337,7 @@ static void dm_drm_plane_reset(struct drm_plane *plane)
>  
>   __drm_atomic_helper_plane_reset(plane, _state->base);
>   amdgpu_state->degamma_tf = AMDGPU_TRANSFER_FUNCTION_DEFAULT;
> + amdgpu_state->hdr_mult = AMDGPU_HDR_MULT_DEFAULT;
>  }
>  
>  static struct drm_plane_state *
> @@ -1360,6 +1361,7 @@ dm_drm_plane_duplicate_state(struct drm_plane *plane)
>   drm_property_blob_get(dm_plane_state->degamma_lut);
>  
>   dm_plane_state->degamma_tf = old_dm_plane_state->degamma_tf;
> + dm_plane_state->hdr_mult = old

Re: [PATCH v4 07/32] drm/amd/display: document AMDGPU pre-defined transfer functions

2023-11-15 Thread Harry Wentland



On 2023-10-05 13:15, Melissa Wen wrote:
> Brief documentation about pre-defined transfer function usage on AMD
> display driver and standardized EOTFs and inverse EOTFs.
> 
> v3:
> - Document BT709 OETF (Pekka)
> - Fix description of sRGB and pure power funcs (Pekka)
> 
> v4:
> - Add description of linear and non-linear forms (Harry)
> 
> Co-developed-by: Harry Wentland 
> Signed-off-by: Harry Wentland 
> Signed-off-by: Melissa Wen 

Reviewed-by: Harry Wentland 

Harry

> ---
>  .../amd/display/amdgpu_dm/amdgpu_dm_color.c   | 62 +++
>  1 file changed, 62 insertions(+)
> 
> 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 d03bdb010e8b..d5dbd20a6766 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
> @@ -85,6 +85,68 @@ void amdgpu_dm_init_color_mod(void)
>  }
>  
>  #ifdef AMD_PRIVATE_COLOR
> +/* Pre-defined Transfer Functions (TF)
> + *
> + * AMD driver supports pre-defined mathematical functions for transferring
> + * between encoded values and optical/linear space. Depending on HW color 
> caps,
> + * ROMs and curves built by the AMD color module support these transforms.
> + *
> + * The driver-specific color implementation exposes properties for 
> pre-blending
> + * degamma TF, shaper TF (before 3D LUT), and blend(dpp.ogam) TF and
> + * post-blending regamma (mpc.ogam) TF. However, only pre-blending degamma
> + * supports ROM curves. AMD color module uses pre-defined coefficients to 
> build
> + * curves for the other blocks. What can be done by each color block is
> + * described by struct dpp_color_capsand struct mpc_color_caps.
> + *
> + * AMD driver-specific color API exposes the following pre-defined transfer
> + * functions:
> + *
> + * - Identity: linear/identity relationship between pixel value and
> + *   luminance value;
> + * - Gamma 2.2, Gamma 2.4, Gamma 2.6: pure power functions;
> + * - sRGB: 2.4: The piece-wise transfer function from IEC 61966-2-1:1999;
> + * - BT.709: has a linear segment in the bottom part and then a power 
> function
> + *   with a 0.45 (~1/2.22) gamma for the rest of the range; standardized by
> + *   ITU-R BT.709-6;
> + * - PQ (Perceptual Quantizer): used for HDR display, allows luminance range
> + *   capability of 0 to 10,000 nits; standardized by SMPTE ST 2084.
> + *
> + * The AMD color model is designed with an assumption that SDR (sRGB, BT.709,
> + * Gamma 2.2, etc.) peak white maps (normalized to 1.0 FP) to 80 nits in the 
> PQ
> + * system. This has the implication that PQ EOTF (non-linear to linear) maps 
> to
> + * [0.0..125.0] where 125.0 = 10,000 nits / 80 nits.
> + *
> + * Non-linear and linear forms are described in the table below:
> + *
> + * ┌───┬─┬──┐
> + * │   │ Non-linear  │   Linear │
> + * ├───┼─┼──┤
> + * │  sRGB │ UNORM or [0.0, 1.0] │ [0.0, 1.0]   │
> + * ├───┼─┼──┤
> + * │ BT709 │ UNORM or [0.0, 1.0] │ [0.0, 1.0]   │
> + * ├───┼─┼──┤
> + * │ Gamma 2.x │ UNORM or [0.0, 1.0] │ [0.0, 1.0]   │
> + * ├───┼─┼──┤
> + * │PQ │ UNORM or FP16 CCCS* │ [0.0, 125.0] │
> + * ├───┼─┼──┤
> + * │  Identity │ UNORM or FP16 CCCS* │ [0.0, 1.0] or CCCS** │
> + * └───┴─┴──┘
> + * * CCCS: Windows canonical composition color space
> + * ** Respectively
> + *
> + * In the driver-specific API, color block names attached to TF properties
> + * suggest the intention regarding non-linear encoding pixel's luminance
> + * values. As some newer encodings don't use gamma curve, we make encoding 
> and
> + * decoding explicit by defining an enum list of transfer functions supported
> + * in terms of EOTF and inverse EOTF, where:
> + *
> + * - EOTF (electro-optical transfer function): is the transfer function to go
> + *   from the encoded value to an optical (linear) value. De-gamma functions
> + *   traditionally do this.
> + * - Inverse EOTF (simply the inverse of the EOTF): is usually intended to go
> + *   from an optical/linear space (which might have been used for blending)
> + *   back to the encoded values. Gamma functions traditionally do this.
> + */
>  static const char * const
>  amdgpu_transfer_function_names[] = {
>   [AMDGPU_TRANSFER_FUNCTION_DEFAULT]  = "Default",



Re: [PATCH v4 06/32] drm/amd/display: explicitly define EOTF and inverse EOTF

2023-11-15 Thread Harry Wentland



On 2023-10-05 13:15, Melissa Wen wrote:
> Instead of relying on color block names to get the transfer function
> intention regarding encoding pixel's luminance, define supported
> Electro-Optical Transfer Functions (EOTFs) and inverse EOTFs, that
> includes pure gamma or standardized transfer functions.
> 
> v3:
> - squash linear and unity TFs to identity (Pekka)
> - define the right TFs for BT.709 (Pekka and Harry)
> - add comment about AMD TF coefficients
> 
> Suggested-by: Harry Wentland 
> Signed-off-by: Melissa Wen 

Reviewed-by: Harry Wentland 

Harry

> ---
>  .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 27 +---
>  .../amd/display/amdgpu_dm/amdgpu_dm_color.c   | 67 ++-
>  2 files changed, 71 insertions(+), 23 deletions(-)
> 
> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h 
> b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
> index 4c4cdf7fc6be..fc4f188d397e 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
> @@ -724,16 +724,27 @@ struct amdgpu_dm_wb_connector {
>  
>  extern const struct amdgpu_ip_block_version dm_ip_block;
>  
> +/* enum amdgpu_transfer_function: pre-defined transfer function supported by 
> AMD.
> + *
> + * It includes standardized transfer functions and pure power functions. The
> + * transfer function coefficients are available at 
> modules/color/color_gamma.c
> + */
>  enum amdgpu_transfer_function {
>   AMDGPU_TRANSFER_FUNCTION_DEFAULT,
> - AMDGPU_TRANSFER_FUNCTION_SRGB,
> - AMDGPU_TRANSFER_FUNCTION_BT709,
> - AMDGPU_TRANSFER_FUNCTION_PQ,
> - AMDGPU_TRANSFER_FUNCTION_LINEAR,
> - AMDGPU_TRANSFER_FUNCTION_UNITY,
> - AMDGPU_TRANSFER_FUNCTION_GAMMA22,
> - AMDGPU_TRANSFER_FUNCTION_GAMMA24,
> - AMDGPU_TRANSFER_FUNCTION_GAMMA26,
> + AMDGPU_TRANSFER_FUNCTION_SRGB_EOTF,
> + AMDGPU_TRANSFER_FUNCTION_BT709_INV_OETF,
> + AMDGPU_TRANSFER_FUNCTION_PQ_EOTF,
> + AMDGPU_TRANSFER_FUNCTION_IDENTITY,
> + AMDGPU_TRANSFER_FUNCTION_GAMMA22_EOTF,
> + AMDGPU_TRANSFER_FUNCTION_GAMMA24_EOTF,
> + AMDGPU_TRANSFER_FUNCTION_GAMMA26_EOTF,
> + AMDGPU_TRANSFER_FUNCTION_SRGB_INV_EOTF,
> + AMDGPU_TRANSFER_FUNCTION_BT709_OETF,
> + AMDGPU_TRANSFER_FUNCTION_PQ_INV_EOTF,
> + AMDGPU_TRANSFER_FUNCTION_GAMMA22_INV_EOTF,
> + AMDGPU_TRANSFER_FUNCTION_GAMMA24_INV_EOTF,
> + AMDGPU_TRANSFER_FUNCTION_GAMMA26_INV_EOTF,
> +AMDGPU_TRANSFER_FUNCTION_COUNT
>  };
>  
>  struct dm_plane_state {
> 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 56ce008b9095..d03bdb010e8b 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
> @@ -85,18 +85,57 @@ void amdgpu_dm_init_color_mod(void)
>  }
>  
>  #ifdef AMD_PRIVATE_COLOR
> -static const struct drm_prop_enum_list amdgpu_transfer_function_enum_list[] 
> = {
> - { AMDGPU_TRANSFER_FUNCTION_DEFAULT, "Default" },
> - { AMDGPU_TRANSFER_FUNCTION_SRGB, "sRGB" },
> - { AMDGPU_TRANSFER_FUNCTION_BT709, "BT.709" },
> - { AMDGPU_TRANSFER_FUNCTION_PQ, "PQ (Perceptual Quantizer)" },
> - { AMDGPU_TRANSFER_FUNCTION_LINEAR, "Linear" },
> - { AMDGPU_TRANSFER_FUNCTION_UNITY, "Unity" },
> - { AMDGPU_TRANSFER_FUNCTION_GAMMA22, "Gamma 2.2" },
> - { AMDGPU_TRANSFER_FUNCTION_GAMMA24, "Gamma 2.4" },
> - { AMDGPU_TRANSFER_FUNCTION_GAMMA26, "Gamma 2.6" },
> +static const char * const
> +amdgpu_transfer_function_names[] = {
> + [AMDGPU_TRANSFER_FUNCTION_DEFAULT]  = "Default",
> + [AMDGPU_TRANSFER_FUNCTION_IDENTITY] = "Identity",
> + [AMDGPU_TRANSFER_FUNCTION_SRGB_EOTF]= "sRGB EOTF",
> + [AMDGPU_TRANSFER_FUNCTION_BT709_INV_OETF]   = "BT.709 inv_OETF",
> + [AMDGPU_TRANSFER_FUNCTION_PQ_EOTF]  = "PQ EOTF",
> + [AMDGPU_TRANSFER_FUNCTION_GAMMA22_EOTF] = "Gamma 2.2 EOTF",
> + [AMDGPU_TRANSFER_FUNCTION_GAMMA24_EOTF] = "Gamma 2.4 EOTF",
> + [AMDGPU_TRANSFER_FUNCTION_GAMMA26_EOTF] = "Gamma 2.6 EOTF",
> + [AMDGPU_TRANSFER_FUNCTION_SRGB_INV_EOTF]= "sRGB inv_EOTF",
> + [AMDGPU_TRANSFER_FUNCTION_BT709_OETF]   = "BT.709 OETF",
> + [AMDGPU_TRANSFER_FUNCTION_PQ_INV_EOTF]  = "PQ inv_EOTF",
> + [AMDGPU_TRANSFER_FUNCTION_GAMMA22_INV_EOTF] = "Gamma 2.2 inv_EOTF",
> + [AMDGPU_T

Re: [PATCH 03/20] drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c: remove I2C_CLASS_DDC support

2023-11-13 Thread Harry Wentland
Please just use "drm/amd/display:" as tag in the commit subject.

With that fixed, this is
Acked-by: Harry Wentland 

Harry

On 2023-11-13 06:23, Heiner Kallweit wrote:
> After removal of the legacy EEPROM driver and I2C_CLASS_DDC support in
> olpc_dcon there's no i2c client driver left supporting I2C_CLASS_DDC.
> Class-based device auto-detection is a legacy mechanism and shouldn't
> be used in new code. So we can remove this class completely now.
> 
> Preferably this series should be applied via the i2c tree.
> 
> Signed-off-by: Heiner Kallweit 
> 
> ---
>  drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c |1 -
>  1 file changed, 1 deletion(-)
> 
> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 
> b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> index 6f99f6754..ae1edc6ab 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> @@ -7529,7 +7529,6 @@ create_i2c(struct ddc_service *ddc_service,
>   if (!i2c)
>   return NULL;
>   i2c->base.owner = THIS_MODULE;
> - i2c->base.class = I2C_CLASS_DDC;
>   i2c->base.dev.parent = >pdev->dev;
>   i2c->base.algo = _dm_i2c_algo;
>   snprintf(i2c->base.name, sizeof(i2c->base.name), "AMDGPU DM i2c hw bus 
> %d", link_index);
> 



Re: [RFC PATCH 01/10] drm/doc/rfc: Describe why prescriptive color pipeline is needed

2023-11-10 Thread Harry Wentland




On 2023-11-09 04:20, Pekka Paalanen wrote:

On Wed, 8 Nov 2023 11:27:35 -0500
Harry Wentland  wrote:


On 2023-11-08 11:19, Pekka Paalanen wrote:

On Wed, 8 Nov 2023 09:31:17 -0500
Harry Wentland  wrote:
   

On 2023-11-08 06:40, Sebastian Wick wrote:

On Wed, Nov 8, 2023 at 11:16 AM Pekka Paalanen  wrote:


...


An incremental UAPI development approach is fine by me, meaning that
pipelines might not be complete at first, but I believe that requires
telling userspace whether the driver developers consider the pipeline
complete (no undescribed operations that would significantly change
results from the expected results given the UAPI exposed pipeline).

The prime example of what I would like to know is that if a FB
contains PQ-encoded image and I use a color pipeline to scale that
image up, will the interpolation happen before or after the non-linear
colorop that decodes PQ. That is a significant difference as pointed
out by Joshua.



That's fair and I want to give that to you. My concern stems from
the sentiment that I hear that any pipeline that doesn't explicitly
advertise this is useless. I don't agree there. Let's not let perfect
be the enemy of good.


It's up to the use case. The policy of what is sufficient should reside
in userspace.

What about matching compositor shader composition with KMS?

Can we use that as a rough precision threshold? If userspace implements
the exact same color pipeline as the KMS UAPI describes, then that and
the KMS composited result should be indistinguishable in side-by-side
or alternating visual inspection on any monitor in isolation.

Did this whole effort not start from wanting to off-load things to
display hardware but still maintain visual equivalence to software/GPU
composition?
   


I agree with you and I want all that as well.

All I'm saying is that every userspace won't have the same policy of
what is sufficient. Just because Weston has a very high threshold
doesn't mean we can't move forward with a workable solution for other
userspace, as long as we don't do something that prevents us from
doing the perfect solution eventually.

And yes, I do want a solution that works for Weston and hear your
comments on what that requires.


I totally agree.

How will that be reflected in the UAPI? If some pipelines are different
from others in correctness/strictness perspective, how will userspace
tell them apart?

Is the current proposal along the lines of: userspace creates a
software pipeline first, and if it cannot map all operations on it to
KMS color pipeline colorops, then the KMS pipeline is not sufficient?

The gist being, if the software pipeline is scaling the image for
example, then it must find a scaling colorop in the KMS pipeline if it
cares about the scaling correctness.



With a simplified model of an imaginary color pipeline I expect this
to look like this:

Color Pipeline 1:
  EOTF Curve - CTM

Color Pipeline 2:
  EOTF Curve - scale - CTM

Realistically both would most likely map to the same HW blocks.

Assuming userspace A and B do the following:
  EOTF Curve - scale - CTM

Userspace A doesn't care about scaling and would only look for:
  EOTF Curve - CTM

and find a match with Color Pipeline 1.

Userspace B cares about scaling and would look for
  EOTF Curve - scale - CTM

and find a match with Color Pipeline 2.

If Color Pipeline 2 is not exposed in the first iteration of the
driver's implementation userspace A would still be able to make
use of it, but userspace B would not, since it requires a defined
scale operation. If the driver then exposes Color Pipeline 2 in a
second iteration userspace B can find a match for what it needs
and make use of it.

Realistically userspace B would not attempt to implement a DRM/KMS
color pipeline implementation unless it knows that there's a driver
that can do what it needs.


Another example is YUV pixel format on an FB that magically turns into
some kind of RGB when sampled, but there is no colorop to tell what
happens. I suppose userspace cannot assume that the lack of colorop
there means an identity YUV->RGB matrix either? How to model
that? I guess the already mentioned pixel format requirements on a
pipeline would help, making it impossible to use a pipeline without a
YUV->RGB colorop on a YUV FB unless the lack of colorop does indeed
mean an identity matrix.



I agree.


The same with sub-sampled YUV which probably needs to always(?) be
expanded into fully sampled at the beginning of a pipeline? Chroma
siting.

This is in addition to the previously discussed userspace policy that
if a KMS color pipeline contains colorops the userspace does not
recognise, userspace probably should not pick that pipeline under any
conditions, because it might do something completely unexpected.



Unless those colorops can be put into bypass.


I think the above could work, but I feel it requires documenting several
examples like scaling that might not exist in the colorop definitions
at first. Oth

[RFC PATCH v3 17/23] drm/colorop: Introduce DRM_CLIENT_CAP_PLANE_COLOR_PIPELINE

2023-11-08 Thread Harry Wentland
With the introduction of the pre-blending color pipeline we
can no longer have color operations that don't have a clear
position in the color pipeline. We deprecate all existing
plane properties. For upstream drivers those are:
 - COLOR_ENCODING
 - COLOR_RANGE

Userspace that registers with the
DRM_CLIENT_CAP_PLANE_COLOR_PIPELINE will be permitted to set
the COLOR_PIPELINE plane property and drm_colorop properties.
But it won't be allowed to set COLOR_ENCODING and
COLOR_RANGE. Userspace that does not set this client cap
will not be permitted to touch the color pipeline.

Signed-off-by: Harry Wentland 
---
 drivers/gpu/drm/drm_atomic_uapi.c | 23 ++-
 drivers/gpu/drm/drm_ioctl.c   |  7 +++
 include/drm/drm_file.h|  7 +++
 include/uapi/drm/drm.h| 15 +++
 4 files changed, 51 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/drm_atomic_uapi.c 
b/drivers/gpu/drm/drm_atomic_uapi.c
index c6629fdaa114..69c56982e2d0 100644
--- a/drivers/gpu/drm/drm_atomic_uapi.c
+++ b/drivers/gpu/drm/drm_atomic_uapi.c
@@ -610,10 +610,26 @@ static int drm_atomic_plane_set_property(struct drm_plane 
*plane,
} else if (property == plane->zpos_property) {
state->zpos = val;
} else if (property == plane->color_encoding_property) {
+   if (file_priv->plane_color_pipeline) {
+   drm_dbg_atomic(dev,
+  "Setting COLOR_PIPELINE plane property 
not permitted when DRM_CLIENT_CAP_PLANE_COLOR_PIPELINE is set\n");
+   return -EINVAL;
+   }
state->color_encoding = val;
} else if (property == plane->color_range_property) {
+   if (file_priv->plane_color_pipeline) {
+   drm_dbg_atomic(dev,
+  "Setting COLOR_PIPELINE plane property 
not permitted when DRM_CLIENT_CAP_PLANE_COLOR_PIPELINE is set\n");
+   return -EINVAL;
+   }
state->color_range = val;
} else if (property == plane->color_pipeline_property) {
+   if (!file_priv->plane_color_pipeline) {
+   drm_dbg_atomic(dev,
+  "Setting COLOR_PIPELINE plane property 
not permitted unless DRM_CLIENT_CAP_PLANE_COLOR_PIPELINE is set\n");
+   return -EINVAL;
+   }
+
/* find DRM colorop object */
struct drm_colorop *colorop = NULL;
colorop = drm_colorop_find(dev, file_priv, val);
@@ -1158,6 +1174,12 @@ int drm_atomic_set_property(struct drm_atomic_state 
*state,
break;
}
case DRM_MODE_OBJECT_COLOROP: {
+   if (!file_priv->plane_color_pipeline) {
+   drm_dbg_atomic(prop->dev,
+  "[OBJECT:%d] is a colorop but 
DRM_CLIENT_CAP_PLANE_COLOR_PIPELINE not set\n",
+  obj->id);
+   ret = -EINVAL;
+   }
struct drm_colorop *colorop = obj_to_colorop(obj);
struct drm_colorop_state *colorop_state;
 
@@ -1170,7 +1192,6 @@ int drm_atomic_set_property(struct drm_atomic_state 
*state,
ret = drm_atomic_colorop_set_property(colorop,
colorop_state, file_priv,
prop, prop_value);
-
break;
}
default:
diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c
index 44fda68c28ae..0d869658e13e 100644
--- a/drivers/gpu/drm/drm_ioctl.c
+++ b/drivers/gpu/drm/drm_ioctl.c
@@ -361,6 +361,13 @@ drm_setclientcap(struct drm_device *dev, void *data, 
struct drm_file *file_priv)
return -EINVAL;
file_priv->writeback_connectors = req->value;
break;
+   case DRM_CLIENT_CAP_PLANE_COLOR_PIPELINE:
+   if (!file_priv->atomic)
+   return -EINVAL;
+   if (req->value > 1)
+   return -EINVAL;
+   file_priv->plane_color_pipeline = req->value;
+   break;
default:
return -EINVAL;
}
diff --git a/include/drm/drm_file.h b/include/drm/drm_file.h
index e1b5b4282f75..bf11b646c898 100644
--- a/include/drm/drm_file.h
+++ b/include/drm/drm_file.h
@@ -204,6 +204,13 @@ struct drm_file {
 */
bool writeback_connectors;
 
+   /**
+* @plane_color_pipeline:
+*
+* True if client understands plane color pipelines
+*/
+   bool plane_color_pipeline;
+
/**
 * @was_master:
 *
diff --git a/include/uapi/drm/drm.h b/include/uapi/drm/drm.h
index 841d393fb84e..2576b170e8d0 100644
--- a/include

[RFC PATCH v3 19/23] drm/vkms: Pull apply_colorop out of pre_blend_color_transform

2023-11-08 Thread Harry Wentland
The if/switch statement is bound to grow with more types and
subtypes. Pull this out into its own funcion to make things more
manageable and readable.

Signed-off-by: Harry Wentland 
---
 drivers/gpu/drm/vkms/vkms_composer.c | 48 
 1 file changed, 28 insertions(+), 20 deletions(-)

diff --git a/drivers/gpu/drm/vkms/vkms_composer.c 
b/drivers/gpu/drm/vkms/vkms_composer.c
index be42756e300a..9010415e4bd6 100644
--- a/drivers/gpu/drm/vkms/vkms_composer.c
+++ b/drivers/gpu/drm/vkms/vkms_composer.c
@@ -164,6 +164,31 @@ static void apply_lut(const struct vkms_crtc_state 
*crtc_state, struct line_buff
}
 }
 
+static void apply_colorop(struct pixel_argb_u16 *pixel, struct drm_colorop 
*colorop)
+{
+   /* TODO is this right? */
+   struct drm_colorop_state *colorop_state = colorop->state;
+
+   if (colorop->type == DRM_COLOROP_1D_CURVE) {
+   switch (colorop_state->curve_1d_type) {
+   case DRM_COLOROP_1D_CURVE_SRGB_INV_EOTF:
+   pixel->r = 
apply_lut_to_channel_value(_inv_eotf, pixel->r, LUT_RED);
+   pixel->g = 
apply_lut_to_channel_value(_inv_eotf, pixel->g, LUT_GREEN);
+   pixel->b = 
apply_lut_to_channel_value(_inv_eotf, pixel->b, LUT_BLUE);
+   break;
+   case DRM_COLOROP_1D_CURVE_SRGB_EOTF:
+   pixel->r = 
apply_lut_to_channel_value(_eotf, pixel->r, LUT_RED);
+   pixel->g = 
apply_lut_to_channel_value(_eotf, pixel->g, LUT_GREEN);
+   pixel->b = 
apply_lut_to_channel_value(_eotf, pixel->b, LUT_BLUE);
+   break;
+   default:
+   DRM_DEBUG_DRIVER("unkown colorop 1D curve type 
%d\n", colorop_state->curve_1d_type);
+   break;
+   }
+   }
+
+}
+
 static void pre_blend_color_transform(const struct vkms_plane_state 
*plane_state, struct line_buffer *output_buffer)
 {
struct drm_colorop *colorop = plane_state->base.base.color_pipeline;
@@ -180,26 +205,9 @@ static void pre_blend_color_transform(const struct 
vkms_plane_state *plane_state
if (!colorop_state)
return;
 
-   for (size_t x = 0; x < output_buffer->n_pixels; x++) {
-   struct pixel_argb_u16 *pixel = 
_buffer->pixels[x];
-
-   if (colorop->type == DRM_COLOROP_1D_CURVE &&
-   colorop_state->bypass == false) {
-   switch (colorop_state->curve_1d_type) {
-   case DRM_COLOROP_1D_CURVE_SRGB_INV_EOTF:
-   pixel->r = 
apply_lut_to_channel_value(_inv_eotf, pixel->r, LUT_RED);
-   pixel->g = 
apply_lut_to_channel_value(_inv_eotf, pixel->g, LUT_GREEN);
-   pixel->b = 
apply_lut_to_channel_value(_inv_eotf, pixel->b, LUT_BLUE);
-   break;
-   case DRM_COLOROP_1D_CURVE_SRGB_EOTF:
-   default:
-   pixel->r = 
apply_lut_to_channel_value(_eotf, pixel->r, LUT_RED);
-   pixel->g = 
apply_lut_to_channel_value(_eotf, pixel->g, LUT_GREEN);
-   pixel->b = 
apply_lut_to_channel_value(_eotf, pixel->b, LUT_BLUE);
-   break;
-   }
-   }
-   }
+   for (size_t x = 0; x < output_buffer->n_pixels; x++)
+   if (!colorop_state->bypass)
+   apply_colorop(_buffer->pixels[x], 
colorop);
 
colorop = colorop->next;
}
-- 
2.42.1



[RFC PATCH v3 08/23] drm/colorop: Add TYPE property

2023-11-08 Thread Harry Wentland
Add a read-only TYPE property. The TYPE specifies the colorop
type, such as enumerated curve, 1D LUT, CTM, 3D LUT, PWL LUT,
etc.

v3:
 - Make TYPE a range property
 - Move enum drm_colorop_type to uapi header
 - Fix drm_get_colorop_type_name description

For now we're only introducing an enumerated 1D LUT type to
illustrate the concept.

Signed-off-by: Harry Wentland 
---
 drivers/gpu/drm/drm_atomic.c  |  4 +--
 drivers/gpu/drm/drm_atomic_uapi.c |  8 +-
 drivers/gpu/drm/drm_colorop.c | 43 ++-
 include/drm/drm_colorop.h | 17 +++-
 include/uapi/drm/drm_mode.h   |  4 +++
 5 files changed, 71 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index 6390443f1819..59e1797d1ca8 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -634,8 +634,8 @@ drm_atomic_get_colorop_state(struct drm_atomic_state *state,
state->colorops[index].new_state = colorop_state;
colorop_state->state = state;
 
-   drm_dbg_atomic(colorop->dev, "Added [COLOROP:%d] %p state to %p\n",
-  colorop->base.id, colorop_state, state);
+   drm_dbg_atomic(colorop->dev, "Added [COLOROP:%d:%d] %p state to %p\n",
+  colorop->base.id, colorop->type, colorop_state, state);
 
return colorop_state;
 }
diff --git a/drivers/gpu/drm/drm_atomic_uapi.c 
b/drivers/gpu/drm/drm_atomic_uapi.c
index 21da1b327ee9..f22bd8671236 100644
--- a/drivers/gpu/drm/drm_atomic_uapi.c
+++ b/drivers/gpu/drm/drm_atomic_uapi.c
@@ -682,7 +682,13 @@ drm_atomic_colorop_get_property(struct drm_colorop 
*colorop,
const struct drm_colorop_state *state,
struct drm_property *property, uint64_t *val)
 {
-   return -EINVAL;
+   if (property == colorop->type_property) {
+   *val = colorop->type;
+   } else {
+   return -EINVAL;
+   }
+
+   return 0;
 }
 
 static int drm_atomic_set_writeback_fb_for_connector(
diff --git a/drivers/gpu/drm/drm_colorop.c b/drivers/gpu/drm/drm_colorop.c
index a295ab96aee1..902b13e300fd 100644
--- a/drivers/gpu/drm/drm_colorop.c
+++ b/drivers/gpu/drm/drm_colorop.c
@@ -32,12 +32,17 @@
 
 /* TODO big colorop doc, including properties, etc. */
 
+static const struct drm_prop_enum_list drm_colorop_type_enum_list[] = {
+   { DRM_COLOROP_1D_CURVE, "1D Curve" },
+};
+
 /* Init Helpers */
 
 int drm_colorop_init(struct drm_device *dev, struct drm_colorop *colorop,
-struct drm_plane *plane)
+struct drm_plane *plane, enum drm_colorop_type type)
 {
struct drm_mode_config *config = >mode_config;
+   struct drm_property *prop;
int ret = 0;
 
ret = drm_mode_object_add(dev, >base, DRM_MODE_OBJECT_COLOROP);
@@ -46,12 +51,28 @@ int drm_colorop_init(struct drm_device *dev, struct 
drm_colorop *colorop,
 
colorop->base.properties = >properties;
colorop->dev = dev;
+   colorop->type = type;
colorop->plane = plane;
 
list_add_tail(>head, >colorop_list);
colorop->index = config->num_colorop++;
 
/* add properties */
+
+   /* type */
+   prop = drm_property_create_range(dev,
+   DRM_MODE_PROP_IMMUTABLE,
+   "TYPE", type, type);
+
+   if (!prop)
+   return -ENOMEM;
+
+   colorop->type_property = prop;
+
+   drm_object_attach_property(>base,
+  colorop->type_property,
+  colorop->type);
+
return ret;
 }
 EXPORT_SYMBOL(drm_colorop_init);
@@ -150,3 +171,23 @@ void drm_colorop_reset(struct drm_colorop *colorop)
__drm_colorop_reset(colorop, colorop->state);
 }
 EXPORT_SYMBOL(drm_colorop_reset);
+
+
+static const char * const colorop_type_name[] = {
+   [DRM_COLOROP_1D_CURVE] = "1D Curve",
+};
+
+/**
+ * drm_get_colorop_type_name - return a string for colorop type
+ * @type: colorop type to compute name of
+ *
+ * In contrast to the other drm_get_*_name functions this one here returns a
+ * const pointer and hence is threadsafe.
+ */
+const char *drm_get_colorop_type_name(enum drm_colorop_type type)
+{
+   if (WARN_ON(type >= ARRAY_SIZE(colorop_type_name)))
+   return "unknown";
+
+   return colorop_type_name[type];
+}
diff --git a/include/drm/drm_colorop.h b/include/drm/drm_colorop.h
index 3dd169b0317d..0386440afe40 100644
--- a/include/drm/drm_colorop.h
+++ b/include/drm/drm_colorop.h
@@ -103,6 +103,21 @@ struct drm_colorop {
/** @properties: property tracking for this plane */
struct drm_object_properties properties;
 
+   /**
+* @type:
+*
+* Read-only
+* Type of color operatio

[RFC PATCH v3 20/23] drm/vkms: Use s32 for internal color pipeline precision

2023-11-08 Thread Harry Wentland
Certain operations require us to preserve values below 0.0 and
above 1.0 (0x0 and 0x respectively in 16 bpc unorm). One
such operation is a BT709 encoding operation followed by its
decoding operation, or the reverse.

We'll use s32 values as intermediate in and outputs of our
color operations, for the operations where it matters.

For now this won't apply to LUT operations. We might want to
update those to work on s32 as well, but it's unclear how
that should work for unorm LUT definitions. We'll revisit
that once we add LUT + CTM tests.

In order to allow for this we'll also invert the nesting of our
colorop processing loops. We now use the pixel iteration loop
on the outside and the colorop iteration on the inside.

v3:
 - Use new colorop->next pointer

Signed-off-by: Harry Wentland 
---
 drivers/gpu/drm/vkms/vkms_composer.c | 55 +---
 drivers/gpu/drm/vkms/vkms_drv.h  |  4 ++
 2 files changed, 46 insertions(+), 13 deletions(-)

diff --git a/drivers/gpu/drm/vkms/vkms_composer.c 
b/drivers/gpu/drm/vkms/vkms_composer.c
index 9010415e4bd6..d04a235b9fcd 100644
--- a/drivers/gpu/drm/vkms/vkms_composer.c
+++ b/drivers/gpu/drm/vkms/vkms_composer.c
@@ -164,7 +164,7 @@ static void apply_lut(const struct vkms_crtc_state 
*crtc_state, struct line_buff
}
 }
 
-static void apply_colorop(struct pixel_argb_u16 *pixel, struct drm_colorop 
*colorop)
+static void apply_colorop(struct pixel_argb_s32 *pixel, struct drm_colorop 
*colorop)
 {
/* TODO is this right? */
struct drm_colorop_state *colorop_state = colorop->state;
@@ -191,25 +191,54 @@ static void apply_colorop(struct pixel_argb_u16 *pixel, 
struct drm_colorop *colo
 
 static void pre_blend_color_transform(const struct vkms_plane_state 
*plane_state, struct line_buffer *output_buffer)
 {
-   struct drm_colorop *colorop = plane_state->base.base.color_pipeline;
+   struct drm_colorop *colorop;
+   struct pixel_argb_s32 pixel;
 
-   while (colorop) {
-   struct drm_colorop_state *colorop_state;
+   for (size_t x = 0; x < output_buffer->n_pixels; x++) {
+
+   /*
+* Some operations, such as applying a BT709 encoding matrix,
+* followed by a decoding matrix, require that we preserve
+* values above 1.0 and below 0.0 until the end of the pipeline.
+*
+* Convert values to s32 for our internal pipeline and go back
+* to u16 values at the end.
+*/
+   pixel.a = output_buffer->pixels[x].a;
+   pixel.r = output_buffer->pixels[x].r;
+   pixel.g = output_buffer->pixels[x].g;
+   pixel.b = output_buffer->pixels[x].b;
+
+   colorop = plane_state->base.base.color_pipeline;
+   while (colorop) {
+   struct drm_colorop_state *colorop_state;
 
-   if (!colorop)
-   return;
+   if (!colorop)
+   return;
 
-   /* TODO this is probably wrong */
-   colorop_state = colorop->state;
+   /* TODO this is probably wrong */
+   colorop_state = colorop->state;
 
-   if (!colorop_state)
-   return;
+   if (!colorop_state)
+   return;
 
-   for (size_t x = 0; x < output_buffer->n_pixels; x++)
if (!colorop_state->bypass)
-   apply_colorop(_buffer->pixels[x], 
colorop);
+   apply_colorop(, colorop);
+
+   colorop = colorop->next;
+   }
 
-   colorop = colorop->next;
+   /* clamp pixel */
+   pixel.a = max(min(pixel.a, 0x), 0x0);
+   pixel.r = max(min(pixel.r, 0x), 0x0);
+   pixel.g = max(min(pixel.g, 0x), 0x0);
+   pixel.b = max(min(pixel.b, 0x), 0x0);
+
+   /* put back to output_buffer */
+   output_buffer->pixels[x].a = pixel.a;
+   output_buffer->pixels[x].r = pixel.r;
+   output_buffer->pixels[x].g = pixel.g;
+   output_buffer->pixels[x].b = pixel.b;
}
 }
 
diff --git a/drivers/gpu/drm/vkms/vkms_drv.h b/drivers/gpu/drm/vkms/vkms_drv.h
index 2bcc24c196a2..fadb7685a360 100644
--- a/drivers/gpu/drm/vkms/vkms_drv.h
+++ b/drivers/gpu/drm/vkms/vkms_drv.h
@@ -36,6 +36,10 @@ struct vkms_frame_info {
unsigned int cpp;
 };
 
+struct pixel_argb_s32 {
+   s32 a, r, g, b;
+};
+
 struct pixel_argb_u16 {
u16 a, r, g, b;
 };
-- 
2.42.1



[RFC PATCH v3 22/23] drm/tests: Add a few tests around drm_fixed.h

2023-11-08 Thread Harry Wentland
While working on the CTM implementation of VKMS I had to ascertain
myself of a few assumptions. One of those is whether drm_fixed.h
treats its numbers using signed-magnitude or twos-complement. It is
twos-complement.

In order to make someone else's day easier I am adding the
drm_test_int2fixp test that validates the above assumption.

I am also adding a test for the new sm2fixp function that converts
from a signed-magnitude fixed point to the twos-complement fixed
point.

Signed-off-by: Harry Wentland 
---
 drivers/gpu/drm/tests/Makefile|  3 +-
 drivers/gpu/drm/tests/drm_fixp_test.c | 69 +++
 2 files changed, 71 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/tests/drm_fixp_test.c

diff --git a/drivers/gpu/drm/tests/Makefile b/drivers/gpu/drm/tests/Makefile
index ba7baa622675..61f44ad0e862 100644
--- a/drivers/gpu/drm/tests/Makefile
+++ b/drivers/gpu/drm/tests/Makefile
@@ -18,6 +18,7 @@ obj-$(CONFIG_DRM_KUNIT_TEST) += \
drm_plane_helper_test.o \
drm_probe_helper_test.o \
drm_rect_test.o \
-   drm_exec_test.o
+   drm_exec_test.o \
+   drm_fixp_test.o
 
 CFLAGS_drm_mm_test.o := $(DISABLE_STRUCTLEAK_PLUGIN)
diff --git a/drivers/gpu/drm/tests/drm_fixp_test.c 
b/drivers/gpu/drm/tests/drm_fixp_test.c
new file mode 100644
index ..f420f173ff66
--- /dev/null
+++ b/drivers/gpu/drm/tests/drm_fixp_test.c
@@ -0,0 +1,69 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ */
+
+#include 
+#include 
+
+static void drm_test_sm2fixp(struct kunit *test)
+{
+   KUNIT_EXPECT_EQ(test, 0x7fffll, ((1LL << 63) - 1));
+
+   /* 1 */
+   KUNIT_EXPECT_EQ(test, drm_int2fixp(1), drm_sm2fixp(1ull << 
DRM_FIXED_POINT));
+
+   /* -1 */
+   KUNIT_EXPECT_EQ(test, drm_int2fixp(-1), drm_sm2fixp((1ull << 63) | 
(1ull << DRM_FIXED_POINT)));
+
+   /* 0.5 */
+   KUNIT_EXPECT_EQ(test, drm_fixp_from_fraction(1, 2), drm_sm2fixp(1ull << 
(DRM_FIXED_POINT - 1)));
+
+   /* -0.5 */
+   KUNIT_EXPECT_EQ(test, drm_fixp_from_fraction(-1, 2), drm_sm2fixp((1ull 
<< 63) | (1ull << (DRM_FIXED_POINT - 1;
+
+}
+
+static void drm_test_int2fixp(struct kunit *test)
+{
+   /* 1 */
+   KUNIT_EXPECT_EQ(test, 1ll << 32, drm_int2fixp(1));
+
+   /* -1 */
+   KUNIT_EXPECT_EQ(test, -(1ll << 32), drm_int2fixp(-1));
+
+   /* 1 + (-1) = 0 */
+   KUNIT_EXPECT_EQ(test, 0, drm_int2fixp(1) + drm_int2fixp(-1));
+
+   /* 1 / 2 */
+   KUNIT_EXPECT_EQ(test, 1ll << 31, drm_fixp_from_fraction(1, 2));
+
+   /* -0.5 */
+   KUNIT_EXPECT_EQ(test, -(1ll << 31), drm_fixp_from_fraction(-1, 2));
+
+   /* (1 / 2) + (-1) = 0.5 */
+   KUNIT_EXPECT_EQ(test, 1ll << 31, drm_fixp_from_fraction(-1, 2) + 
drm_int2fixp(1));
+
+   /* (1 / 2) - 1) = 0.5 */
+   KUNIT_EXPECT_EQ(test, -(1ll << 31), drm_fixp_from_fraction(1, 2) + 
drm_int2fixp(-1));
+
+   /* (1 / 2) - 1) = 0.5 */
+   KUNIT_EXPECT_EQ(test, -(1ll << 31), drm_fixp_from_fraction(1, 2) - 
drm_int2fixp(1));
+
+}
+
+static struct kunit_case drm_fixp_tests[] = {
+   KUNIT_CASE(drm_test_int2fixp),
+   KUNIT_CASE(drm_test_sm2fixp),
+   { }
+};
+
+static struct kunit_suite drm_rect_test_suite = {
+   .name = "drm_fixp",
+   .test_cases = drm_fixp_tests,
+};
+
+kunit_test_suite(drm_rect_test_suite);
+
+MODULE_AUTHOR("AMD");
+MODULE_LICENSE("GPL and additional rights");
\ No newline at end of file
-- 
2.42.1



[RFC PATCH v3 07/23] drm/colorop: Introduce new drm_colorop mode object

2023-11-08 Thread Harry Wentland
This patches introduces a new drm_colorop mode object. This
object represents color transformations and can be used to
define color pipelines.

We also introduce the drm_colorop_state here, as well as
various helpers and state tracking bits.

v3:
 - Drop TODO for lock (it's handled in drm_modeset_drop_locks)
   (Melissa)
 - Don't get plane state when getting colorop state
 - Make some functions static (kernel test robot)

Signed-off-by: Harry Wentland 
---
 drivers/gpu/drm/Makefile|   1 +
 drivers/gpu/drm/drm_atomic.c|  70 +
 drivers/gpu/drm/drm_atomic_helper.c |  12 +++
 drivers/gpu/drm/drm_atomic_uapi.c   |  48 +
 drivers/gpu/drm/drm_colorop.c   | 152 +++
 drivers/gpu/drm/drm_mode_config.c   |   7 ++
 drivers/gpu/drm/drm_plane_helper.c  |   2 +-
 include/drm/drm_atomic.h|  82 +++
 include/drm/drm_atomic_uapi.h   |   1 +
 include/drm/drm_colorop.h   | 157 
 include/drm/drm_mode_config.h   |  18 
 include/drm/drm_plane.h |   2 +
 include/uapi/drm/drm.h  |   3 +
 include/uapi/drm/drm_mode.h |   1 +
 14 files changed, 555 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/drm_colorop.c
 create mode 100644 include/drm/drm_colorop.h

diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 8e1bde059170..7ba67f9775e7 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -16,6 +16,7 @@ drm-y := \
drm_client.o \
drm_client_modeset.o \
drm_color_mgmt.o \
+   drm_colorop.o \
drm_connector.o \
drm_crtc.o \
drm_displayid.o \
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index f1a503aafe5a..6390443f1819 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -42,6 +42,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include "drm_crtc_internal.h"
 #include "drm_internal.h"
@@ -108,6 +109,7 @@ void drm_atomic_state_default_release(struct 
drm_atomic_state *state)
kfree(state->connectors);
kfree(state->crtcs);
kfree(state->planes);
+   kfree(state->colorops);
kfree(state->private_objs);
 }
 EXPORT_SYMBOL(drm_atomic_state_default_release);
@@ -139,6 +141,10 @@ drm_atomic_state_init(struct drm_device *dev, struct 
drm_atomic_state *state)
sizeof(*state->planes), GFP_KERNEL);
if (!state->planes)
goto fail;
+   state->colorops = kcalloc(dev->mode_config.num_colorop,
+ sizeof(*state->colorops), GFP_KERNEL);
+   if (!state->colorops)
+   goto fail;
 
/*
 * Because drm_atomic_state can be committed asynchronously we need our
@@ -250,6 +256,20 @@ void drm_atomic_state_default_clear(struct 
drm_atomic_state *state)
state->planes[i].new_state = NULL;
}
 
+   for (i = 0; i < config->num_colorop; i++) {
+   struct drm_colorop *colorop = state->colorops[i].ptr;
+
+   if (!colorop)
+   continue;
+
+   drm_colorop_atomic_destroy_state(colorop,
+state->colorops[i].state);
+   state->colorops[i].ptr = NULL;
+   state->colorops[i].state = NULL;
+   state->colorops[i].old_state = NULL;
+   state->colorops[i].new_state = NULL;
+   }
+
for (i = 0; i < state->num_private_objs; i++) {
struct drm_private_obj *obj = state->private_objs[i].ptr;
 
@@ -571,6 +591,56 @@ drm_atomic_get_plane_state(struct drm_atomic_state *state,
 }
 EXPORT_SYMBOL(drm_atomic_get_plane_state);
 
+
+/**
+ * drm_atomic_get_colorop_state - get colorop state
+ * @state: global atomic state object
+ * @colorop: colorop to get state object for
+ *
+ * This function returns the colorop state for the given colorop, allocating it
+ * if needed. It will also grab the relevant plane lock to make sure that the
+ * state is consistent.
+ *
+ * Returns:
+ *
+ * Either the allocated state or the error code encoded into the pointer. When
+ * the error is EDEADLK then the w/w mutex code has detected a deadlock and the
+ * entire atomic sequence must be restarted. All other errors are fatal.
+ */
+struct drm_colorop_state *
+drm_atomic_get_colorop_state(struct drm_atomic_state *state,
+struct drm_colorop *colorop)
+{
+   int ret, index = drm_colorop_index(colorop);
+   struct drm_colorop_state *colorop_state;
+
+   WARN_ON(!state->acquire_ctx);
+
+   colorop_state = drm_atomic_get_existing_colorop_state(state, colorop);
+   if (colorop_state)
+   return colorop_state;
+
+   ret = drm_modeset_lock(>plane->mutex, 

[RFC PATCH v3 13/23] drm/plane: Add COLOR PIPELINE property

2023-11-08 Thread Harry Wentland
We're adding a new enum COLOR PIPELINE property. This
property will have entries for each COLOR PIPELINE by
referencing the DRM object ID of the first drm_colorop
of the pipeline. 0 disables the entire COLOR PIPELINE.

Userspace can use this to discover the available color
pipelines, as well as set the desired one. The color
pipelines are programmed via properties on the actual
drm_colorop objects.

Signed-off-by: Harry Wentland 
---
 drivers/gpu/drm/drm_atomic.c  | 46 +++
 drivers/gpu/drm/drm_atomic_state_helper.c |  5 +++
 drivers/gpu/drm/drm_atomic_uapi.c | 44 ++
 include/drm/drm_atomic_uapi.h |  2 +
 include/drm/drm_plane.h   |  8 
 5 files changed, 105 insertions(+)

diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index ccf26b034433..cf3cb6d1239f 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -1463,6 +1463,52 @@ drm_atomic_add_affected_planes(struct drm_atomic_state 
*state,
 }
 EXPORT_SYMBOL(drm_atomic_add_affected_planes);
 
+/**
+ * drm_atomic_add_affected_colorops - add colorops for plane
+ * @state: atomic state
+ * @plane: DRM plane
+ *
+ * This function walks the current configuration and adds all colorops
+ * currently used by @plane to the atomic configuration @state. This is useful
+ * when an atomic commit also needs to check all currently enabled colorop on
+ * @plane, e.g. when changing the mode. It's also useful when re-enabling a 
plane
+ * to avoid special code to force-enable all colorops.
+ *
+ * Since acquiring a colorop state will always also acquire the w/w mutex of 
the
+ * current plane for that colorop (if there is any) adding all the colorop 
states for
+ * a plane will not reduce parallelism of atomic updates.
+ *
+ * Returns:
+ * 0 on success or can fail with -EDEADLK or -ENOMEM. When the error is EDEADLK
+ * then the w/w mutex code has detected a deadlock and the entire atomic
+ * sequence must be restarted. All other errors are fatal.
+ */
+int
+drm_atomic_add_affected_colorops(struct drm_atomic_state *state,
+struct drm_plane *plane)
+{
+   struct drm_colorop *colorop;
+   struct drm_colorop_state *colorop_state;
+
+   WARN_ON(!drm_atomic_get_new_plane_state(state, plane));
+
+   drm_dbg_atomic(plane->dev,
+  "Adding all current colorops for [plane:%d:%s] to %p\n",
+  plane->base.id, plane->name, state);
+
+   drm_for_each_colorop(colorop, plane->dev) {
+   if (colorop->plane != plane)
+   continue;
+
+   colorop_state = drm_atomic_get_colorop_state(state, colorop);
+   if (IS_ERR(colorop_state))
+   return PTR_ERR(colorop_state);
+   }
+
+   return 0;
+}
+EXPORT_SYMBOL(drm_atomic_add_affected_colorops);
+
 /**
  * drm_atomic_check_only - check whether a given config would work
  * @state: atomic configuration to check
diff --git a/drivers/gpu/drm/drm_atomic_state_helper.c 
b/drivers/gpu/drm/drm_atomic_state_helper.c
index 784e63d70a42..3c5f2c8e33d0 100644
--- a/drivers/gpu/drm/drm_atomic_state_helper.c
+++ b/drivers/gpu/drm/drm_atomic_state_helper.c
@@ -267,6 +267,11 @@ void __drm_atomic_helper_plane_state_reset(struct 
drm_plane_state *plane_state,
plane_state->color_range = val;
}
 
+   if (plane->color_pipeline_property) {
+   /* default is always NULL, i.e., bypass */
+   plane_state->color_pipeline = NULL;
+   }
+
if (plane->zpos_property) {
if (!drm_object_property_get_default_value(>base,
   plane->zpos_property,
diff --git a/drivers/gpu/drm/drm_atomic_uapi.c 
b/drivers/gpu/drm/drm_atomic_uapi.c
index a8f7a8a6639a..c6629fdaa114 100644
--- a/drivers/gpu/drm/drm_atomic_uapi.c
+++ b/drivers/gpu/drm/drm_atomic_uapi.c
@@ -256,6 +256,38 @@ drm_atomic_set_fb_for_plane(struct drm_plane_state 
*plane_state,
 }
 EXPORT_SYMBOL(drm_atomic_set_fb_for_plane);
 
+
+/**
+ * drm_atomic_set_colorop_for_plane - set colorop for plane
+ * @plane_state: atomic state object for the plane
+ * @colorop: colorop to use for the plane
+ *
+ * Changing the assigned framebuffer for a plane requires us to grab a 
reference
+ * to the new fb and drop the reference to the old fb, if there is one. This
+ * function takes care of all these details besides updating the pointer in the
+ * state object itself.
+ */
+void
+drm_atomic_set_colorop_for_plane(struct drm_plane_state *plane_state,
+struct drm_colorop *colorop)
+{
+   struct drm_plane *plane = plane_state->plane;
+
+   if (colorop)
+   drm_dbg_atomic(plane->dev,
+  "Set [COLOROP:%d] for [PLANE:%d:%s] state %p\n",
+

[RFC PATCH v3 18/23] drm/colorop: Add 3x4 CTM type

2023-11-08 Thread Harry Wentland
This type is used to support a 3x4 matrix in colorops. A 3x4
matrix uses the last column as a "bias" column. Some HW exposes
support for 3x4. The calculation looks like:

 out   matrixin
 |R|   |0  1  2  3 |   | R |
 |G| = |4  5  6  7 | x | G |
 |B|   |8  9  10 12|   | B |
   |1.0|

This is also the first colorop where we need a blob property to
program the property. For that we'll introduce a new DATA
property that can be used by all colorop TYPEs requiring a
blob. The way a DATA blob is read depends on the TYPE of
the colorop.

We only create the DATA property for property types that
need it.

Signed-off-by: Harry Wentland 
---
 drivers/gpu/drm/drm_atomic_uapi.c | 30 ++
 drivers/gpu/drm/drm_colorop.c | 16 
 include/drm/drm_colorop.h | 19 +++
 include/uapi/drm/drm_mode.h   | 19 ++-
 4 files changed, 83 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/drm_atomic_uapi.c 
b/drivers/gpu/drm/drm_atomic_uapi.c
index 69c56982e2d0..564bca68f652 100644
--- a/drivers/gpu/drm/drm_atomic_uapi.c
+++ b/drivers/gpu/drm/drm_atomic_uapi.c
@@ -725,6 +725,31 @@ drm_atomic_plane_get_property(struct drm_plane *plane,
return 0;
 }
 
+static int drm_atomic_color_set_data_property(struct drm_colorop *colorop,
+   struct drm_colorop_state *state,
+   struct drm_property *property, uint64_t val)
+{
+   ssize_t elem_size = -1;
+   ssize_t size = -1;
+   bool replaced;
+
+
+   switch (colorop->type) {
+   case DRM_COLOROP_CTM_3X4:
+   size = sizeof(struct drm_color_ctm_3x4);
+   break;
+   default:
+   /* should never get here */
+   return -EINVAL;
+   }
+
+   return drm_atomic_replace_property_blob_from_id(colorop->dev,
+   >data,
+   val,
+   size,
+   elem_size,
+   );
+}
 
 static int drm_atomic_colorop_set_property(struct drm_colorop *colorop,
struct drm_colorop_state *state, struct drm_file *file_priv,
@@ -734,6 +759,9 @@ static int drm_atomic_colorop_set_property(struct 
drm_colorop *colorop,
state->bypass = val;
} else if (property == colorop->curve_1d_type_property) {
state->curve_1d_type = val;
+   } else if (property == colorop->data_property) {
+   return drm_atomic_color_set_data_property(colorop,
+   state, property, val);
} else {
drm_dbg_atomic(colorop->dev,
   "[COLOROP:%d:%d] unknown property 
[PROP:%d:%s]]\n",
@@ -756,6 +784,8 @@ drm_atomic_colorop_get_property(struct drm_colorop *colorop,
*val = state->bypass;
} else if (property == colorop->curve_1d_type_property) {
*val = state->curve_1d_type;
+   } else if (property == colorop->data_property) {
+   *val = (state->data) ? state->data->base.id : 0;
} else {
return -EINVAL;
}
diff --git a/drivers/gpu/drm/drm_colorop.c b/drivers/gpu/drm/drm_colorop.c
index e62acf68bf9e..67e6efc90803 100644
--- a/drivers/gpu/drm/drm_colorop.c
+++ b/drivers/gpu/drm/drm_colorop.c
@@ -34,6 +34,7 @@
 
 static const struct drm_prop_enum_list drm_colorop_type_enum_list[] = {
{ DRM_COLOROP_1D_CURVE, "1D Curve" },
+   { DRM_COLOROP_CTM_3X4, "3x4 Matrix"}
 };
 
 static const struct drm_prop_enum_list drm_colorop_curve_1d_type_enum_list[] = 
{
@@ -105,6 +106,20 @@ int drm_colorop_init(struct drm_device *dev, struct 
drm_colorop *colorop,
   colorop->curve_1d_type_property,
   0);
 
+   /* data */
+   if (type == DRM_COLOROP_CTM_3X4) {
+   prop = drm_property_create(dev, DRM_MODE_PROP_ATOMIC | 
DRM_MODE_PROP_BLOB,
+  "DATA", 0);
+   if (!prop)
+   return -ENOMEM;
+
+   colorop->data_property = prop;
+   drm_object_attach_property(>base,
+  colorop->data_property,
+  0);
+   }
+
+   /* next */
prop = drm_property_create_object(dev, DRM_MODE_PROP_IMMUTABLE | 
DRM_MODE_PROP_ATOMIC,
"NEXT", DRM_MODE_OBJECT_COLOROP);
if (!prop)
@@ -219,6 +234,7 @@ EXPORT_SYMBOL(drm_colorop_reset);
 
 static const char * const colorop_type_name[] = {
[DRM_COLOROP_1D_CURVE] = "1D Curve",
+   [DRM_COLOROP_CTM_3X4] = "3x4 Matrix"
 };
 
 static const char * const colorop_curve_1d_type_name[] = {
diff --

  1   2   3   4   5   6   7   8   9   10   >