]> www.infradead.org Git - users/hch/misc.git/commitdiff
drm/amd/display: Optimize custom brightness curve interpolation
authorMario Limonciello <mario.limonciello@amd.com>
Tue, 19 Aug 2025 16:29:05 +0000 (11:29 -0500)
committerAlex Deucher <alexander.deucher@amd.com>
Fri, 29 Aug 2025 14:13:58 +0000 (10:13 -0400)
[Why]
Custom brightness curve works by walking through all data points one
by one.  When the brightness value is at either extreme this is a lot
of data points to walk.  This is especially noticeable when moving a
brightness slider around how it can lag.

[How]
Bisect the data points to find the closest for interpolation.

Reviewed-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
Signed-off-by: Alex Hung <alex.hung@amd.com>
Tested-by: Dan Wheeler <daniel.wheeler@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c

index 12eb1a91a4e9fdf5ec640cfa1a8a2163420e417d..242f985642610918f1b22fd94c489c649cc3b570 100644 (file)
@@ -4817,8 +4817,8 @@ static void convert_custom_brightness(const struct amdgpu_dm_backlight_caps *cap
                                      uint32_t *user_brightness)
 {
        u32 brightness = scale_input_to_fw(min, max, *user_brightness);
-       u8 prev_signal = 0, prev_lum = 0;
-       int i = 0;
+       u8 lower_signal, upper_signal, upper_lum, lower_lum, lum;
+       int left, right;
 
        if (amdgpu_dc_debug_mask & DC_DISABLE_CUSTOM_BRIGHTNESS_CURVE)
                return;
@@ -4826,32 +4826,44 @@ static void convert_custom_brightness(const struct amdgpu_dm_backlight_caps *cap
        if (!caps->data_points)
                return;
 
-       /* choose start to run less interpolation steps */
-       if (caps->luminance_data[caps->data_points/2].input_signal > brightness)
-               i = caps->data_points/2;
-       do {
-               u8 signal = caps->luminance_data[i].input_signal;
-               u8 lum = caps->luminance_data[i].luminance;
+       left = 0;
+       right = caps->data_points - 1;
+       while (left <= right) {
+               int mid = left + (right - left) / 2;
+               u8 signal = caps->luminance_data[mid].input_signal;
 
-               /*
-                * brightness == signal: luminance is percent numerator
-                * brightness < signal: interpolate between previous and current luminance numerator
-                * brightness > signal: find next data point
-                */
-               if (brightness > signal) {
-                       prev_signal = signal;
-                       prev_lum = lum;
-                       i++;
-                       continue;
+               /* Exact match found */
+               if (signal == brightness) {
+                       lum = caps->luminance_data[mid].luminance;
+                       goto scale;
                }
-               if (brightness < signal)
-                       lum = prev_lum + DIV_ROUND_CLOSEST((lum - prev_lum) *
-                                                          (brightness - prev_signal),
-                                                          signal - prev_signal);
-               *user_brightness = scale_fw_to_input(min, max,
-                                                    DIV_ROUND_CLOSEST(lum * brightness, 101));
-               return;
-       } while (i < caps->data_points);
+
+               if (signal < brightness)
+                       left = mid + 1;
+               else
+                       right = mid - 1;
+       }
+
+       /* verify bound */
+       if (left >= caps->data_points)
+               left = caps->data_points - 1;
+
+       /* At this point, left > right */
+       lower_signal = caps->luminance_data[right].input_signal;
+       upper_signal = caps->luminance_data[left].input_signal;
+       lower_lum = caps->luminance_data[right].luminance;
+       upper_lum = caps->luminance_data[left].luminance;
+
+       /* interpolate */
+       if (right == left || !lower_lum)
+               lum = upper_lum;
+       else
+               lum = lower_lum + DIV_ROUND_CLOSEST((upper_lum - lower_lum) *
+                                                   (brightness - lower_signal),
+                                                   upper_signal - lower_signal);
+scale:
+       *user_brightness = scale_fw_to_input(min, max,
+                                            DIV_ROUND_CLOSEST(lum * brightness, 101));
 }
 
 static u32 convert_brightness_from_user(const struct amdgpu_dm_backlight_caps *caps,