#include "dc_stream_priv.h"
#define DC_LOGGER dc->ctx->logger
+#define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
+#define MAX(x, y) ((x > y) ? x : y)
/*******************************************************************************
* Private functions
}
}
+/*
+ * Finds the greatest index in refresh_rate_hz that contains a value <= refresh
+ */
+static int dc_stream_get_nearest_smallest_index(struct dc_stream_state *stream, int refresh)
+{
+ for (int i = 0; i < (LUMINANCE_DATA_TABLE_SIZE - 1); ++i) {
+ if ((stream->lumin_data.refresh_rate_hz[i] <= refresh) && (refresh < stream->lumin_data.refresh_rate_hz[i + 1])) {
+ return i;
+ }
+ }
+ return 9;
+}
+
+/*
+ * Finds a corresponding brightness for a given refresh rate between 2 given indices, where index1 < index2
+ */
+static int dc_stream_get_brightness_millinits_linear_interpolation (struct dc_stream_state *stream,
+ int index1,
+ int index2,
+ int refresh_hz)
+{
+ int slope = 0;
+ if (stream->lumin_data.refresh_rate_hz[index2] != stream->lumin_data.refresh_rate_hz[index1]) {
+ slope = (stream->lumin_data.luminance_millinits[index2] - stream->lumin_data.luminance_millinits[index1]) /
+ (stream->lumin_data.refresh_rate_hz[index2] - stream->lumin_data.refresh_rate_hz[index1]);
+ }
+
+ int y_intercept = stream->lumin_data.luminance_millinits[index2] - slope * stream->lumin_data.refresh_rate_hz[index2];
+
+ return (y_intercept + refresh_hz * slope);
+}
+
+/*
+ * Finds a corresponding refresh rate for a given brightness between 2 given indices, where index1 < index2
+ */
+static int dc_stream_get_refresh_hz_linear_interpolation (struct dc_stream_state *stream,
+ int index1,
+ int index2,
+ int brightness_millinits)
+{
+ int slope = 1;
+ if (stream->lumin_data.refresh_rate_hz[index2] != stream->lumin_data.refresh_rate_hz[index1]) {
+ slope = (stream->lumin_data.luminance_millinits[index2] - stream->lumin_data.luminance_millinits[index1]) /
+ (stream->lumin_data.refresh_rate_hz[index2] - stream->lumin_data.refresh_rate_hz[index1]);
+ }
+
+ int y_intercept = stream->lumin_data.luminance_millinits[index2] - slope * stream->lumin_data.refresh_rate_hz[index2];
+
+ return ((brightness_millinits - y_intercept) / slope);
+}
+
+/*
+ * Finds the current brightness in millinits given a refresh rate
+ */
+static int dc_stream_get_brightness_millinits_from_refresh (struct dc_stream_state *stream, int refresh_hz)
+{
+ int nearest_smallest_index = dc_stream_get_nearest_smallest_index(stream, refresh_hz);
+ int nearest_smallest_value = stream->lumin_data.refresh_rate_hz[nearest_smallest_index];
+
+ if (nearest_smallest_value == refresh_hz)
+ return stream->lumin_data.luminance_millinits[nearest_smallest_index];
+
+ if (nearest_smallest_index >= 9)
+ return dc_stream_get_brightness_millinits_linear_interpolation(stream, nearest_smallest_index - 1, nearest_smallest_index, refresh_hz);
+
+ if (nearest_smallest_value == stream->lumin_data.refresh_rate_hz[nearest_smallest_index + 1])
+ return stream->lumin_data.luminance_millinits[nearest_smallest_index];
+
+ return dc_stream_get_brightness_millinits_linear_interpolation(stream, nearest_smallest_index, nearest_smallest_index + 1, refresh_hz);
+}
+
+/*
+ * Finds the lowest refresh rate that can be achieved
+ * from starting_refresh_hz while staying within flicker criteria
+ */
+static int dc_stream_calculate_flickerless_refresh_rate(struct dc_stream_state *stream,
+ int current_brightness,
+ int starting_refresh_hz,
+ bool is_gaming,
+ bool search_for_max_increase)
+{
+ int nearest_smallest_index = dc_stream_get_nearest_smallest_index(stream, starting_refresh_hz);
+
+ int flicker_criteria_millinits = is_gaming ?
+ stream->lumin_data.flicker_criteria_milli_nits_GAMING :
+ stream->lumin_data.flicker_criteria_milli_nits_STATIC;
+
+ int safe_upper_bound = current_brightness + flicker_criteria_millinits;
+ int safe_lower_bound = current_brightness - flicker_criteria_millinits;
+ int lumin_millinits_temp = 0;
+
+ int offset = -1;
+ if (search_for_max_increase) {
+ offset = 1;
+ }
+
+ /*
+ * Increments up or down by 1 depending on search_for_max_increase
+ */
+ for (int i = nearest_smallest_index; (i > 0 && !search_for_max_increase) || (i < (LUMINANCE_DATA_TABLE_SIZE - 1) && search_for_max_increase); i += offset) {
+
+ lumin_millinits_temp = stream->lumin_data.luminance_millinits[i + offset];
+
+ if ((lumin_millinits_temp >= safe_upper_bound) || (lumin_millinits_temp <= safe_lower_bound)) {
+
+ if (stream->lumin_data.refresh_rate_hz[i + offset] == stream->lumin_data.refresh_rate_hz[i])
+ return stream->lumin_data.refresh_rate_hz[i];
+
+ int target_brightness = (stream->lumin_data.luminance_millinits[i + offset] >= (current_brightness + flicker_criteria_millinits)) ?
+ current_brightness + flicker_criteria_millinits :
+ current_brightness - flicker_criteria_millinits;
+
+ int refresh = 0;
+
+ /*
+ * Need the second input to be < third input for dc_stream_get_refresh_hz_linear_interpolation
+ */
+ if (search_for_max_increase)
+ refresh = dc_stream_get_refresh_hz_linear_interpolation(stream, i, i + offset, target_brightness);
+ else
+ refresh = dc_stream_get_refresh_hz_linear_interpolation(stream, i + offset, i, target_brightness);
+
+ if (refresh == stream->lumin_data.refresh_rate_hz[i + offset])
+ return stream->lumin_data.refresh_rate_hz[i + offset];
+
+ return refresh;
+ }
+ }
+
+ if (search_for_max_increase)
+ return stream->lumin_data.refresh_rate_hz[LUMINANCE_DATA_TABLE_SIZE - 1];
+ else
+ return stream->lumin_data.refresh_rate_hz[0];
+}
+
+/*
+ * Gets the max delta luminance within a specified refresh range
+ */
+static int dc_stream_get_max_delta_lumin_millinits(struct dc_stream_state *stream, int hz1, int hz2, bool isGaming)
+{
+ int lower_refresh_brightness = dc_stream_get_brightness_millinits_from_refresh (stream, hz1);
+ int higher_refresh_brightness = dc_stream_get_brightness_millinits_from_refresh (stream, hz2);
+
+ int min = lower_refresh_brightness;
+ int max = higher_refresh_brightness;
+
+ /*
+ * Static screen, therefore no need to scan through array
+ */
+ if (!isGaming) {
+ if (lower_refresh_brightness >= higher_refresh_brightness) {
+ return lower_refresh_brightness - higher_refresh_brightness;
+ }
+ return higher_refresh_brightness - lower_refresh_brightness;
+ }
+
+ min = MIN(lower_refresh_brightness, higher_refresh_brightness);
+ max = MAX(lower_refresh_brightness, higher_refresh_brightness);
+
+ int nearest_smallest_index = dc_stream_get_nearest_smallest_index(stream, hz1);
+
+ for (; nearest_smallest_index < (LUMINANCE_DATA_TABLE_SIZE - 1) &&
+ stream->lumin_data.refresh_rate_hz[nearest_smallest_index + 1] <= hz2 ; nearest_smallest_index++) {
+ min = MIN(min, stream->lumin_data.luminance_millinits[nearest_smallest_index + 1]);
+ max = MAX(max, stream->lumin_data.luminance_millinits[nearest_smallest_index + 1]);
+ }
+
+ return (max - min);
+}
+
+/*
+ * Finds the highest refresh rate that can be achieved
+ * from starting_refresh_hz while staying within flicker criteria
+ */
+int dc_stream_calculate_max_flickerless_refresh_rate(struct dc_stream_state *stream, int starting_refresh_hz, bool is_gaming)
+{
+ if (!stream->lumin_data.is_valid)
+ return 0;
+
+ int current_brightness = dc_stream_get_brightness_millinits_from_refresh(stream, starting_refresh_hz);
+
+ return dc_stream_calculate_flickerless_refresh_rate(stream,
+ current_brightness,
+ starting_refresh_hz,
+ is_gaming,
+ true);
+}
+
+/*
+ * Finds the lowest refresh rate that can be achieved
+ * from starting_refresh_hz while staying within flicker criteria
+ */
+int dc_stream_calculate_min_flickerless_refresh_rate(struct dc_stream_state *stream, int starting_refresh_hz, bool is_gaming)
+{
+ if (!stream->lumin_data.is_valid)
+ return 0;
+
+ int current_brightness = dc_stream_get_brightness_millinits_from_refresh(stream, starting_refresh_hz);
+
+ return dc_stream_calculate_flickerless_refresh_rate(stream,
+ current_brightness,
+ starting_refresh_hz,
+ is_gaming,
+ false);
+}
+
+/*
+ * Determines if there will be a flicker when moving between 2 refresh rates
+ */
+bool dc_stream_is_refresh_rate_range_flickerless(struct dc_stream_state *stream, int hz1, int hz2, bool is_gaming)
+{
+
+ /*
+ * Assume that we wont flicker if there is invalid data
+ */
+ if (!stream->lumin_data.is_valid)
+ return false;
+
+ int dl = dc_stream_get_max_delta_lumin_millinits(stream, hz1, hz2, is_gaming);
+
+ int flicker_criteria_millinits = (is_gaming) ?
+ stream->lumin_data.flicker_criteria_milli_nits_GAMING :
+ stream->lumin_data.flicker_criteria_milli_nits_STATIC;
+
+ return (dl <= flicker_criteria_millinits);
+}