Commit 5861153b authored by Guido Gunther's avatar Guido Gunther
Browse files

monitor-manager: Support fractional scale DisplayConfig



This allows to set fractional scale in Settings too. The actual
calculation is based on what mutter does.

Closes: #479
Signed-off-by: Guido Gunther's avatarGuido Günther <guido.gunther@puri.sm>
parent 738f62df
......@@ -568,7 +568,7 @@ phosh_monitor_manager_handle_get_current_state (PhoshDBusDisplayConfig *skeleton
for (int k = 0; k < head->modes->len; k++) {
PhoshHeadMode *mode = g_ptr_array_index (head->modes, k);
g_autofree int *scales = NULL;
g_autofree float *scales = NULL;
if (!mode->name) {
g_warning ("Skipping unnamend mode %p", mode);
continue;
......@@ -576,7 +576,7 @@ phosh_monitor_manager_handle_get_current_state (PhoshDBusDisplayConfig *skeleton
g_variant_builder_init (&supported_scales_builder,
G_VARIANT_TYPE ("ad"));
scales = phosh_head_calculate_supported_mode_scales (head, mode, &n);
scales = phosh_head_calculate_supported_mode_scales (head, mode, &n, TRUE);
for (int l = 0; l < n; l++) {
g_variant_builder_add (&supported_scales_builder, "d",
(double)scales[l]);
......
......@@ -38,8 +38,10 @@ static GParamSpec *props[PHOSH_HEAD_PROP_LAST_PROP];
#define MINIMUM_LOGICAL_AREA_LANDSCAPE (800 * 480)
#define MINIMUM_LOGICAL_AREA_PORTRAIT (360 * 720)
#define MINIMUM_SCALE_FACTOR 1
#define MAXIMUM_SCALE_FACTOR 4
#define MINIMUM_SCALE_FACTOR 1.0f
#define MAXIMUM_SCALE_FACTOR 4.0f
#define SCALE_FACTORS_PER_INTEGER 4
#define SCALE_FACTORS_STEPS (1.0 / (float) SCALE_FACTORS_PER_INTEGER)
G_DEFINE_TYPE (PhoshHead, phosh_head, G_TYPE_OBJECT);
......@@ -71,29 +73,24 @@ mode_name (PhoshHeadMode *mode)
static gboolean
is_logical_size_large_enough (int width, int height)
is_logical_size_large_enough (float width, float height)
{
if (width > height)
return width * height >= MINIMUM_LOGICAL_AREA_LANDSCAPE;
else
return width * height >= MINIMUM_LOGICAL_AREA_PORTRAIT;
int area = (width > height) ? MINIMUM_LOGICAL_AREA_LANDSCAPE : MINIMUM_LOGICAL_AREA_PORTRAIT;
return width * height >= area;
}
static gboolean
is_valid_scale (int width, int height, int scale)
is_valid_scale (float width, float height, float scale)
{
int scaled_h = height / scale;
int scaled_w = width / scale;
float scaled_h = height / scale;
float scaled_w = width / scale;
if (scale < MINIMUM_SCALE_FACTOR || scale > MAXIMUM_SCALE_FACTOR ||
!is_logical_size_large_enough (scaled_w, scaled_h))
if (scale < MINIMUM_SCALE_FACTOR || scale > MAXIMUM_SCALE_FACTOR)
return FALSE;
if (width % scale == 0 && height % scale == 0)
return TRUE;
return FALSE;
return is_logical_size_large_enough (floorf (scaled_w), floorf(scaled_h));
}
......@@ -586,28 +583,108 @@ phosh_head_find_mode_by_name (PhoshHead *self, const char *name)
}
int *
static float
get_closest_scale_factor_for_resolution (float width, float height, float scale, float threshold)
{
unsigned int i;
float scaled_h;
float scaled_w;
float best_scale;
int base_scaled_w;
gboolean found_one;
best_scale = 0;
if (!is_valid_scale (width, height, scale))
return 0.0;
if ((int)fmodf (width, scale) == 0 && (int)fmodf (height, scale) == 0)
return scale;
i = 0;
found_one = FALSE;
base_scaled_w = floorf (width / scale);
do {
for (int j = 0; j < 2; j++) {
float current_scale;
int offset = i * (j ? 1 : -1);
scaled_w = base_scaled_w + offset;
current_scale = width / scaled_w;
scaled_h = height / current_scale;
if (current_scale >= scale + threshold ||
current_scale <= scale - threshold ||
current_scale < MINIMUM_SCALE_FACTOR ||
current_scale > MAXIMUM_SCALE_FACTOR) {
return best_scale;
}
#pragma GCC diagnostic ignored "-Wfloat-equal"
if (floorf (scaled_h) == scaled_h) {
#pragma GCC diagnostic error "-Wfloat-equal"
found_one = TRUE;
if (fabsf (current_scale - scale) < fabsf (best_scale - scale))
best_scale = current_scale;
}
}
i++;
} while (!found_one);
return best_scale;
}
float *
phosh_head_calculate_supported_mode_scales (PhoshHead *head,
PhoshHeadMode *mode,
int *n_supported_scales)
int *n_supported_scales,
gboolean fractional)
{
unsigned int i;
GArray *supported_scales;
supported_scales = g_array_new (FALSE, FALSE, sizeof (int));
for (i = MINIMUM_SCALE_FACTOR; i <= MAXIMUM_SCALE_FACTOR; i++) {
if (is_valid_scale (mode->width, mode->height, i))
g_array_append_val (supported_scales, i);
supported_scales = g_array_new (FALSE, FALSE, sizeof (float));
if (fractional) {
for (int i = floorf (MINIMUM_SCALE_FACTOR); i <= ceilf (MAXIMUM_SCALE_FACTOR); i++) {
float max_bound;
#pragma GCC diagnostic ignored "-Wfloat-equal"
if (i == floorf (MINIMUM_SCALE_FACTOR) || i == ceilf (MAXIMUM_SCALE_FACTOR)) {
#pragma GCC diagnostic error "-Wfloat-equal"
max_bound = SCALE_FACTORS_STEPS;
} else {
max_bound = SCALE_FACTORS_STEPS / 2.0;
}
for (int j = 0; j < SCALE_FACTORS_PER_INTEGER; j++) {
float scale;
float scale_value = i + j * SCALE_FACTORS_STEPS;
scale = get_closest_scale_factor_for_resolution (mode->width, mode->height,
scale_value,
max_bound);
if (scale > 0.0)
g_array_append_val (supported_scales, scale);
}
}
} else {
for (float f = floorf (MINIMUM_SCALE_FACTOR); f <= ceilf (MAXIMUM_SCALE_FACTOR); f++) {
if (is_valid_scale (mode->width, mode->height, f)) {
g_array_append_val (supported_scales, f);
}
}
}
if (supported_scales->len == 0) {
int fallback_scale = 1;
float fallback_scale = 1.0;
g_array_append_val (supported_scales, fallback_scale);
}
*n_supported_scales = supported_scales->len;
return (int *) g_array_free (supported_scales, FALSE);
return (float *) g_array_free (supported_scales, FALSE);
}
/**
......
......@@ -71,9 +71,10 @@ gboolean phosh_head_get_enabled (PhoshHead *self);
PhoshHeadMode *phosh_head_get_preferred_mode (PhoshHead *self);
gboolean phosh_head_is_builtin (PhoshHead *self);
PhoshHeadMode *phosh_head_find_mode_by_name (PhoshHead *self, const char *name);
int * phosh_head_calculate_supported_mode_scales (PhoshHead *head,
float * phosh_head_calculate_supported_mode_scales (PhoshHead *head,
PhoshHeadMode *mode,
int *n);
int *n,
gboolean fractional);
void phosh_head_clear_pending (PhoshHead *self);
G_END_DECLS
......@@ -13,7 +13,7 @@ static void
test_phosh_head_scale_integer (void)
{
int num;
g_autofree int *scales;
g_autofree float *scales;
PhoshHeadMode phone_mode = {
.width = 720,
......@@ -25,13 +25,13 @@ test_phosh_head_scale_integer (void)
.height = 2160,
};
scales = phosh_head_calculate_supported_mode_scales (NULL, &phone_mode, &num);
scales = phosh_head_calculate_supported_mode_scales (NULL, &phone_mode, &num, FALSE);
g_assert_cmpint (num, ==, 2);
g_assert_cmpint (scales[0], ==, 1);
g_assert_cmpint (scales[1], ==, 2);
g_clear_pointer (&scales, g_free);
scales = phosh_head_calculate_supported_mode_scales (NULL, &fourk_mode, &num);
scales = phosh_head_calculate_supported_mode_scales (NULL, &fourk_mode, &num, FALSE);
g_assert_cmpint (num, ==, 4);
g_assert_cmpint (scales[0], ==, 1);
g_assert_cmpint (scales[1], ==, 2);
......@@ -40,6 +40,45 @@ test_phosh_head_scale_integer (void)
}
static void
test_phosh_head_scale_fractional (void)
{
int num;
g_autofree float *scales;
PhoshHeadMode mode = {
.width = 720,
.height = 1440,
};
PhoshHeadMode fourk_mode = {
.width = 3840,
.height = 2160,
};
scales = phosh_head_calculate_supported_mode_scales (NULL, &mode, &num, TRUE);
g_assert_cmpint (num, ==, 5);
#pragma GCC diagnostic ignored "-Wfloat-equal"
g_assert_cmpfloat (scales[0], ==, 1.0);
g_assert_cmpfloat (scales[1], ==, 1.25);
g_assert_cmpfloat (scales[2], ==, 1.5);
g_assert_cmpfloat (scales[3], >=, 1.75);
g_assert_cmpfloat (scales[3], <=, 1.76);
g_assert_cmpfloat (scales[4], ==, 2.0);
g_clear_pointer (&scales, g_free);
scales = phosh_head_calculate_supported_mode_scales (NULL, &fourk_mode, &num, TRUE);
g_assert_cmpint (num, ==, 13);
g_assert_cmpfloat (scales[0], ==, 1.0);
g_assert_cmpfloat (scales[1], ==, 1.25);
/* ... */
g_assert_cmpfloat (scales[11], ==, 3.75);
g_assert_cmpfloat (scales[12], ==, 4);
#pragma GCC diagnostic error "-Wfloat-equal"
}
int
main (int argc,
char *argv[])
......@@ -47,6 +86,7 @@ main (int argc,
g_test_init (&argc, &argv, NULL);
g_test_add_func("/phosh/head/scale/integer", test_phosh_head_scale_integer);
g_test_add_func("/phosh/head/scale/fractional", test_phosh_head_scale_fractional);
return g_test_run();
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment