drm/amd/display: Optimize custom brightness curve interpolation

[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>
This commit is contained in:
Mario Limonciello
2025-08-19 11:29:05 -05:00
committed by Alex Deucher
parent 002a612023
commit de63b05593

View 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,