Commit de63b055 authored by Mario Limonciello's avatar Mario Limonciello Committed by Alex Deucher
Browse files

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: default avatarAlex Hung <alex.hung@amd.com>
Signed-off-by: default avatarMario Limonciello <mario.limonciello@amd.com>
Signed-off-by: default avatarAlex Hung <alex.hung@amd.com>
Tested-by: default avatarDan Wheeler <daniel.wheeler@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 002a6120
Loading
Loading
Loading
Loading
+38 −26
Original line number Diff line number Diff line
@@ -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 (signal < brightness)
			left = mid + 1;
		else
			right = mid - 1;
	}
		if (brightness < signal)
			lum = prev_lum + DIV_ROUND_CLOSEST((lum - prev_lum) *
							   (brightness - prev_signal),
							   signal - prev_signal);

	/* 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));
		return;
	} while (i < caps->data_points);
}

static u32 convert_brightness_from_user(const struct amdgpu_dm_backlight_caps *caps,