monitor: Do not overlap when checking for applicable scaling values

With some resolutions (such as 4096x2160) we may compute duplicated
scale factors because we used a too wide threshold to check for an
applicable value.

In fact, while when we're at the first and last values it's fine to
search applicable values up to SCALE_FACTORS_STEP, on intermediate ones
we should stop in the middle of it, or we're end up overlapping the
previous scaling value domain.

In the said example in fact we were returning 2.666667 both when
looking to a scaling value close to 2.75 and 3.00 as the upper bound of
2.75 (3.0) was overlapping with the lower bound of 3.0 (2.75).
With the current code, the lower and upper bounds will be instead 2.875.

Adapt test to this, and this allows to also ensure that we're always
returning a sorted and unique list of scales (which is useful as also
g-c-c can ensure that this is true).

Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1878>
This commit is contained in:
Marco Trevisan (Treviño) 2021-05-28 19:45:42 +02:00
parent c86a1e00c0
commit 3e1e2cb91f
3 changed files with 23 additions and 7 deletions

View File

@ -1767,7 +1767,8 @@ meta_monitor_mode_should_be_advertised (MetaMonitorMode *monitor_mode)
static float static float
get_closest_scale_factor_for_resolution (float width, get_closest_scale_factor_for_resolution (float width,
float height, float height,
float scale) float scale,
float threshold)
{ {
unsigned int i, j; unsigned int i, j;
float scaled_h; float scaled_h;
@ -1799,8 +1800,8 @@ get_closest_scale_factor_for_resolution (float width,
current_scale = width / scaled_w; current_scale = width / scaled_w;
scaled_h = height / current_scale; scaled_h = height / current_scale;
if (current_scale >= scale + SCALE_FACTORS_STEPS || if (current_scale >= scale + threshold ||
current_scale <= scale - SCALE_FACTORS_STEPS || current_scale <= scale - threshold ||
current_scale < MINIMUM_SCALE_FACTOR || current_scale < MINIMUM_SCALE_FACTOR ||
current_scale > MAXIMUM_SCALE_FACTOR) current_scale > MAXIMUM_SCALE_FACTOR)
{ {
@ -1851,14 +1852,22 @@ meta_monitor_calculate_supported_scales (MetaMonitor *monitor,
} }
else else
{ {
float max_bound;
if (i == floorf (MINIMUM_SCALE_FACTOR) ||
i == ceilf (MAXIMUM_SCALE_FACTOR))
max_bound = SCALE_FACTORS_STEPS;
else
max_bound = SCALE_FACTORS_STEPS / 2.0;
for (j = 0; j < SCALE_FACTORS_PER_INTEGER; j++) for (j = 0; j < SCALE_FACTORS_PER_INTEGER; j++)
{ {
float scale; float scale;
float scale_value = i + j * SCALE_FACTORS_STEPS; float scale_value = i + j * SCALE_FACTORS_STEPS;
scale = get_closest_scale_factor_for_resolution (width, height, scale = get_closest_scale_factor_for_resolution (width, height,
scale_value); scale_value,
max_bound);
if (scale > 0.0) if (scale > 0.0)
g_array_append_val (supported_scales, scale); g_array_append_val (supported_scales, scale);
} }

View File

@ -811,6 +811,13 @@ check_expected_scales (MetaMonitor *monitor,
g_assert_cmpfloat (fmodf (width / scales[i], 1.0), ==, 0.0); g_assert_cmpfloat (fmodf (width / scales[i], 1.0), ==, 0.0);
g_assert_cmpfloat (fmodf (height / scales[i], 1.0), ==, 0.0); g_assert_cmpfloat (fmodf (height / scales[i], 1.0), ==, 0.0);
} }
if (i > 0)
{
/* And that scales are sorted and unique */
g_assert_cmpfloat (scales[i], >, scales[i-1]);
g_assert_false (G_APPROX_VALUE (scales[i], scales[i-1], 0.000001));
}
} }
} }

View File

@ -6273,9 +6273,9 @@ meta_test_monitor_supported_fractional_scales (void)
{ {
.width = 4096, .width = 4096,
.height = 2160, .height = 2160,
.n_scales = 10, .n_scales = 8,
.scales = { 1.000000, 1.333333, 1.454545, 1.777778, 2.000000, .scales = { 1.000000, 1.333333, 1.454545, 1.777778, 2.000000,
2.666667, 2.666667, 3.200000, 3.200000, 4.000000 2.666667, 3.200000, 4.000000
} }
}, },
{ {