Add support for scaled logical monitor framebuffers

This commit adds support for rendering onto enlarged per logical
monitor framebuffers, using the scaled clutter stage views, for HiDPI
enabled logical monitors.

This works by scaling the mode of the monitors in a logical monitors by
the scale, no longer relying on scaling the window actors and window
geometry for making windows have the correct size on HiDPI monitors.

It is disabled by default, as in automatically created configurations
will still use the old mode. This is partly because Xwayland clients
will not yet work good enough to make it feasible.

To enable, add the 'scale-monitor-framebuffer' keyword to the
org.gnome.mutter.experimental-features gsettings array.

It is still possible to specify the mode via the new D-Bus API, which
has been adapted.

The adaptations to the D-Bus API means the caller need to be aware of
how to position logical monitors on the stage grid. This depends on the
'layout-mode' property that is used (see the DisplayConfig D-Bus
documentation).

https://bugzilla.gnome.org/show_bug.cgi?id=777732
This commit is contained in:
Jonas Ådahl
2017-02-24 18:10:52 +08:00
parent 094e0356e8
commit 8163ca6821
26 changed files with 721 additions and 118 deletions

View File

@ -100,6 +100,7 @@ struct _MetaBackendClass
typedef enum _MetaExperimentalFeature
{
META_EXPERIMENTAL_FEATURE_NONE = 0,
META_EXPERIMENTAL_FEATURE_SCALE_MONITOR_FRAMEBUFFER = (1 << 0)
} MetaExperimentalFeature;
void meta_init_backend (GType backend_gtype);
@ -161,6 +162,8 @@ void meta_backend_enable_experimental_feature (MetaBackend *backend,
gboolean meta_is_stage_views_enabled (void);
gboolean meta_is_stage_views_scaled (void);
MetaInputSettings *meta_backend_get_input_settings (MetaBackend *backend);
#endif /* META_BACKEND_PRIVATE_H */

View File

@ -428,7 +428,10 @@ experimental_features_handler (GVariant *features_variant,
while (g_variant_iter_loop (&features_iter, "s", &feature))
{
/* So far no experimental features defined. */
g_info ("Unknown experimental feature '%s'\n", feature);
if (g_str_equal (feature, "scale-monitor-framebuffer"))
features |= META_EXPERIMENTAL_FEATURE_SCALE_MONITOR_FRAMEBUFFER;
else
g_info ("Unknown experimental feature '%s'\n", feature);
}
if (features != priv->experimental_features)
@ -968,6 +971,22 @@ meta_is_stage_views_enabled (void)
return !g_str_equal (mutter_stage_views, "0");
}
gboolean
meta_is_stage_views_scaled (void)
{
MetaBackend *backend = meta_get_backend ();
MetaMonitorManager *monitor_manager =
meta_backend_get_monitor_manager (backend);
MetaLogicalMonitorLayoutMode layout_mode;
if (!meta_is_stage_views_enabled ())
return FALSE;
layout_mode = monitor_manager->layout_mode;
return layout_mode == META_LOGICAL_MONITOR_LAYOUT_MODE_LOGICAL;
}
MetaInputSettings *
meta_backend_get_input_settings (MetaBackend *backend)
{

View File

@ -78,7 +78,7 @@ meta_logical_monitor_new (MetaMonitorManager *monitor_manager,
logical_monitor->number = monitor_number;
logical_monitor->winsys_id = main_output->winsys_id;
logical_monitor->scale = logical_monitor_config->scale,
logical_monitor->scale = logical_monitor_config->scale;
logical_monitor->in_fullscreen = -1;
logical_monitor->rect = logical_monitor_config->layout;

View File

@ -60,9 +60,9 @@ G_DECLARE_FINAL_TYPE (MetaLogicalMonitor, meta_logical_monitor,
META, LOGICAL_MONITOR,
GObject)
MetaLogicalMonitor * meta_logical_monitor_new (MetaMonitorManager *monitor_manager,
MetaLogicalMonitorConfig *logical_monitor_config,
int monitor_number);
MetaLogicalMonitor * meta_logical_monitor_new (MetaMonitorManager *monitor_manager,
MetaLogicalMonitorConfig *logical_monitor_config,
int monitor_number);
MetaLogicalMonitor * meta_logical_monitor_new_derived (MetaMonitorManager *monitor_manager,
MetaMonitor *monitor,

View File

@ -51,8 +51,8 @@ meta_monitor_config_manager_new (MetaMonitorManager *monitor_manager)
config_manager = g_object_new (META_TYPE_MONITOR_CONFIG_MANAGER, NULL);
config_manager->monitor_manager = monitor_manager;
config_manager->config_store = g_object_new (META_TYPE_MONITOR_CONFIG_STORE,
NULL);
config_manager->config_store =
meta_monitor_config_store_new (monitor_manager);
return config_manager;
}
@ -461,10 +461,11 @@ create_monitor_config (MetaMonitor *monitor,
}
static MetaLogicalMonitorConfig *
create_preferred_logical_monitor_config (MetaMonitorManager *monitor_manager,
MetaMonitor *monitor,
int x,
int y)
create_preferred_logical_monitor_config (MetaMonitorManager *monitor_manager,
MetaMonitor *monitor,
int x,
int y,
MetaLogicalMonitorLayoutMode layout_mode)
{
MetaMonitorMode *mode;
int width, height;
@ -478,6 +479,16 @@ create_preferred_logical_monitor_config (MetaMonitorManager *monitor_manager,
monitor,
mode);
switch (layout_mode)
{
case META_LOGICAL_MONITOR_LAYOUT_MODE_LOGICAL:
width /= scale;
height /= scale;
break;
case META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL:
break;
}
monitor_config = create_monitor_config (monitor, mode);
logical_monitor_config = g_new0 (MetaLogicalMonitorConfig, 1);
@ -501,6 +512,7 @@ meta_monitor_config_manager_create_linear (MetaMonitorConfigManager *config_mana
MetaMonitorManager *monitor_manager = config_manager->monitor_manager;
GList *logical_monitor_configs;
MetaMonitor *primary_monitor;
MetaLogicalMonitorLayoutMode layout_mode;
MetaLogicalMonitorConfig *primary_logical_monitor_config;
int x;
GList *monitors;
@ -510,10 +522,13 @@ meta_monitor_config_manager_create_linear (MetaMonitorConfigManager *config_mana
if (!primary_monitor)
return NULL;
layout_mode = meta_monitor_manager_get_default_layout_mode (monitor_manager);
primary_logical_monitor_config =
create_preferred_logical_monitor_config (monitor_manager,
primary_monitor,
0, 0);
0, 0,
layout_mode);
primary_logical_monitor_config->is_primary = TRUE;
logical_monitor_configs = g_list_append (NULL,
primary_logical_monitor_config);
@ -535,14 +550,15 @@ meta_monitor_config_manager_create_linear (MetaMonitorConfigManager *config_mana
logical_monitor_config =
create_preferred_logical_monitor_config (monitor_manager,
monitor,
x, 0);
x, 0,
layout_mode);
logical_monitor_configs = g_list_append (logical_monitor_configs,
logical_monitor_config);
x += logical_monitor_config->layout.width;
}
return meta_monitors_config_new (logical_monitor_configs);
return meta_monitors_config_new (logical_monitor_configs, layout_mode);
}
MetaMonitorsConfig *
@ -551,21 +567,25 @@ meta_monitor_config_manager_create_fallback (MetaMonitorConfigManager *config_ma
MetaMonitorManager *monitor_manager = config_manager->monitor_manager;
MetaMonitor *primary_monitor;
GList *logical_monitor_configs;
MetaLogicalMonitorLayoutMode layout_mode;
MetaLogicalMonitorConfig *primary_logical_monitor_config;
primary_monitor = find_primary_monitor (monitor_manager);
if (!primary_monitor)
return NULL;
layout_mode = meta_monitor_manager_get_default_layout_mode (monitor_manager);
primary_logical_monitor_config =
create_preferred_logical_monitor_config (monitor_manager,
primary_monitor,
0, 0);
0, 0,
layout_mode);
primary_logical_monitor_config->is_primary = TRUE;
logical_monitor_configs = g_list_append (NULL,
primary_logical_monitor_config);
return meta_monitors_config_new (logical_monitor_configs);
return meta_monitors_config_new (logical_monitor_configs, layout_mode);
}
MetaMonitorsConfig *
@ -574,6 +594,7 @@ meta_monitor_config_manager_create_suggested (MetaMonitorConfigManager *config_m
MetaMonitorManager *monitor_manager = config_manager->monitor_manager;
MetaLogicalMonitorConfig *primary_logical_monitor_config = NULL;
MetaMonitor *primary_monitor;
MetaLogicalMonitorLayoutMode layout_mode;
GList *logical_monitor_configs;
GList *region;
GList *monitors;
@ -583,6 +604,8 @@ meta_monitor_config_manager_create_suggested (MetaMonitorConfigManager *config_m
if (!primary_monitor)
return NULL;
layout_mode = meta_monitor_manager_get_default_layout_mode (monitor_manager);
logical_monitor_configs = NULL;
region = NULL;
monitors = meta_monitor_manager_get_monitors (monitor_manager);
@ -598,7 +621,8 @@ meta_monitor_config_manager_create_suggested (MetaMonitorConfigManager *config_m
logical_monitor_config =
create_preferred_logical_monitor_config (monitor_manager,
monitor,
x, y);
x, y,
layout_mode);
logical_monitor_configs = g_list_append (logical_monitor_configs,
logical_monitor_config);
@ -629,7 +653,7 @@ meta_monitor_config_manager_create_suggested (MetaMonitorConfigManager *config_m
primary_logical_monitor_config->is_primary = TRUE;
return meta_monitors_config_new (logical_monitor_configs);
return meta_monitors_config_new (logical_monitor_configs, layout_mode);
}
void
@ -774,13 +798,15 @@ meta_monitors_config_key_equal (gconstpointer data_a,
}
MetaMonitorsConfig *
meta_monitors_config_new (GList *logical_monitor_configs)
meta_monitors_config_new (GList *logical_monitor_configs,
MetaLogicalMonitorLayoutMode layout_mode)
{
MetaMonitorsConfig *config;
config = g_object_new (META_TYPE_MONITORS_CONFIG, NULL);
config->logical_monitor_configs = logical_monitor_configs;
config->key = meta_monitors_config_key_new (logical_monitor_configs);
config->layout_mode = layout_mode;
return config;
}
@ -862,12 +888,13 @@ meta_verify_monitor_config (MetaMonitorConfig *monitor_config,
}
gboolean
meta_verify_logical_monitor_config (MetaLogicalMonitorConfig *logical_monitor_config,
GError **error)
meta_verify_logical_monitor_config (MetaLogicalMonitorConfig *logical_monitor_config,
MetaLogicalMonitorLayoutMode layout_mode,
GError **error)
{
GList *l;
int layout_width;
int layout_height;
int expected_mode_width = 0;
int expected_mode_height = 0;
if (logical_monitor_config->scale < 1)
{
@ -894,14 +921,26 @@ meta_verify_logical_monitor_config (MetaLogicalMonitorConfig *logical_monitor_co
return FALSE;
}
layout_width = logical_monitor_config->layout.width;
layout_height = logical_monitor_config->layout.height;
switch (layout_mode)
{
case META_LOGICAL_MONITOR_LAYOUT_MODE_LOGICAL:
expected_mode_width = (logical_monitor_config->layout.width *
logical_monitor_config->scale);
expected_mode_height = (logical_monitor_config->layout.height *
logical_monitor_config->scale);
break;
case META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL:
expected_mode_width = logical_monitor_config->layout.width;
expected_mode_height = logical_monitor_config->layout.height;
break;
}
for (l = logical_monitor_config->monitor_configs; l; l = l->next)
{
MetaMonitorConfig *monitor_config = l->data;
if (monitor_config->mode_spec->width != layout_width ||
monitor_config->mode_spec->height != layout_height)
if (monitor_config->mode_spec->width != expected_mode_width ||
monitor_config->mode_spec->height != expected_mode_height)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Monitor modes in logical monitor conflict");

View File

@ -56,6 +56,8 @@ struct _MetaMonitorsConfig
MetaMonitorsConfigKey *key;
GList *logical_monitor_configs;
MetaLogicalMonitorLayoutMode layout_mode;
};
#define META_TYPE_MONITORS_CONFIG (meta_monitors_config_get_type ())
@ -85,7 +87,8 @@ void meta_monitor_config_manager_set_current (MetaMonitorConfigManager *config_m
MetaMonitorsConfig * meta_monitor_config_manager_get_current (MetaMonitorConfigManager *config_manager);
MetaMonitorsConfig * meta_monitors_config_new (GList *logical_monitor_configs);
MetaMonitorsConfig * meta_monitors_config_new (GList *logical_monitor_configs,
MetaLogicalMonitorLayoutMode layout_mode);
unsigned int meta_monitors_config_key_hash (gconstpointer config_key);
@ -107,8 +110,9 @@ gboolean meta_verify_monitor_spec (MetaMonitorSpec *monitor_spec,
gboolean meta_verify_monitor_config (MetaMonitorConfig *monitor_config,
GError **error);
gboolean meta_verify_logical_monitor_config (MetaLogicalMonitorConfig *logical_monitor_config,
GError **error);
gboolean meta_verify_logical_monitor_config (MetaLogicalMonitorConfig *logical_monitor_config,
MetaLogicalMonitorLayoutMode layout_mode,
GError **error);
gboolean meta_verify_monitors_config (MetaMonitorsConfig *config,
GError **error);

View File

@ -81,6 +81,8 @@ struct _MetaMonitorConfigStore
{
GObject parent;
MetaMonitorManager *monitor_manager;
GHashTable *configs;
};
@ -355,11 +357,13 @@ handle_start_element (GMarkupParseContext *context,
}
static gboolean
derive_logical_monitor_layout (MetaLogicalMonitorConfig *logical_monitor_config,
GError **error)
derive_logical_monitor_layout (MetaLogicalMonitorConfig *logical_monitor_config,
MetaLogicalMonitorLayoutMode layout_mode,
GError **error)
{
MetaMonitorConfig *monitor_config;
int mode_width, mode_height;
int width = 0, height = 0;
GList *l;
monitor_config = logical_monitor_config->monitor_configs->data;
@ -379,8 +383,19 @@ derive_logical_monitor_layout (MetaLogicalMonitorConfig *logical_monitor_config,
}
}
logical_monitor_config->layout.width = mode_width;
logical_monitor_config->layout.height = mode_height;
switch (layout_mode)
{
case META_LOGICAL_MONITOR_LAYOUT_MODE_LOGICAL:
width = mode_width / logical_monitor_config->scale;
height = mode_height / logical_monitor_config->scale;
break;
case META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL:
width = mode_width;
height = mode_height;
}
logical_monitor_config->layout.width = width;
logical_monitor_config->layout.height = height;
return TRUE;
}
@ -491,12 +506,6 @@ handle_end_element (GMarkupParseContext *context,
if (logical_monitor_config->scale == 0)
logical_monitor_config->scale = 1;
if (!derive_logical_monitor_layout (logical_monitor_config, error))
return;
if (!meta_verify_logical_monitor_config (logical_monitor_config, error))
return;
parser->current_logical_monitor_configs =
g_list_append (parser->current_logical_monitor_configs,
logical_monitor_config);
@ -508,12 +517,34 @@ handle_end_element (GMarkupParseContext *context,
case STATE_CONFIGURATION:
{
MetaMonitorConfigStore *store = parser->config_store;
MetaMonitorsConfig *config;
GList *l;
MetaLogicalMonitorLayoutMode layout_mode;
g_assert (g_str_equal (element_name, "configuration"));
layout_mode =
meta_monitor_manager_get_default_layout_mode (store->monitor_manager);
for (l = parser->current_logical_monitor_configs; l; l = l->next)
{
MetaLogicalMonitorConfig *logical_monitor_config = l->data;
if (!derive_logical_monitor_layout (logical_monitor_config,
layout_mode,
error))
return;
if (!meta_verify_logical_monitor_config (logical_monitor_config,
layout_mode,
error))
return;
}
config =
meta_monitors_config_new (parser->current_logical_monitor_configs);
meta_monitors_config_new (parser->current_logical_monitor_configs,
layout_mode);
if (!meta_verify_monitors_config (config, error))
{
@ -852,6 +883,17 @@ meta_monitor_config_store_get_config_count (MetaMonitorConfigStore *config_store
return (int) g_hash_table_size (config_store->configs);
}
MetaMonitorConfigStore *
meta_monitor_config_store_new (MetaMonitorManager *monitor_manager)
{
MetaMonitorConfigStore *store;
store = g_object_new (META_TYPE_MONITOR_CONFIG_STORE, NULL);
store->monitor_manager = monitor_manager;
return store;
}
static void
meta_monitor_config_store_dispose (GObject *object)
{

View File

@ -30,6 +30,8 @@
G_DECLARE_FINAL_TYPE (MetaMonitorConfigStore, meta_monitor_config_store,
META, MONITOR_CONFIG_STORE, GObject)
MetaMonitorConfigStore * meta_monitor_config_store_new (MetaMonitorManager *monitor_manager);
MetaMonitorsConfig * meta_monitor_config_store_lookup (MetaMonitorConfigStore *config_store,
MetaMonitorsConfigKey *key);

View File

@ -605,10 +605,30 @@ meta_monitor_manager_dummy_get_supported_scales (MetaMonitorManager *manager,
*n_scales = G_N_ELEMENTS (supported_scales_dummy);
}
static gboolean
is_monitor_framebuffers_scaled (void)
{
MetaBackend *backend = meta_get_backend ();
return meta_backend_is_experimental_feature_enabled (
backend,
META_EXPERIMENTAL_FEATURE_SCALE_MONITOR_FRAMEBUFFER);
}
static MetaMonitorManagerCapability
meta_monitor_manager_dummy_get_capabilities (MetaMonitorManager *manager)
{
return META_MONITOR_MANAGER_CAPABILITY_MIRRORING;
MetaMonitorManagerCapability capabilities =
META_MONITOR_MANAGER_CAPABILITY_NONE;
capabilities |= META_MONITOR_MANAGER_CAPABILITY_MIRRORING;
if (meta_backend_is_experimental_feature_enabled (
meta_get_backend (),
META_EXPERIMENTAL_FEATURE_SCALE_MONITOR_FRAMEBUFFER))
capabilities |= META_MONITOR_MANAGER_CAPABILITY_LAYOUT_MODE;
return capabilities;
}
static gboolean
@ -625,6 +645,18 @@ meta_monitor_manager_dummy_get_max_screen_size (MetaMonitorManager *manager,
return TRUE;
}
static MetaLogicalMonitorLayoutMode
meta_monitor_manager_dummy_get_default_layout_mode (MetaMonitorManager *manager)
{
if (!meta_is_stage_views_enabled ())
return META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL;
if (is_monitor_framebuffers_scaled ())
return META_LOGICAL_MONITOR_LAYOUT_MODE_LOGICAL;
else
return META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL;
}
static void
meta_monitor_manager_dummy_class_init (MetaMonitorManagerDummyClass *klass)
{
@ -639,6 +671,7 @@ meta_monitor_manager_dummy_class_init (MetaMonitorManagerDummyClass *klass)
manager_class->get_supported_scales = meta_monitor_manager_dummy_get_supported_scales;
manager_class->get_capabilities = meta_monitor_manager_dummy_get_capabilities;
manager_class->get_max_screen_size = meta_monitor_manager_dummy_get_max_screen_size;
manager_class->get_default_layout_mode = meta_monitor_manager_dummy_get_default_layout_mode;
}
static void

View File

@ -71,7 +71,8 @@ typedef struct _MetaTileInfo MetaTileInfo;
typedef enum _MetaMonitorManagerCapability
{
META_MONITOR_MANAGER_CAPABILITY_NONE = 0,
META_MONITOR_MANAGER_CAPABILITY_MIRRORING = (1 << 0)
META_MONITOR_MANAGER_CAPABILITY_MIRRORING = (1 << 0),
META_MONITOR_MANAGER_CAPABILITY_LAYOUT_MODE = (1 << 1)
} MetaMonitorManagerCapability;
/* Equivalent to the 'method' enum in org.gnome.Mutter.DisplayConfig */
@ -82,6 +83,13 @@ typedef enum _MetaMonitorsConfigMethod
META_MONITORS_CONFIG_METHOD_PERSISTENT = 2
} MetaMonitorsConfigMethod;
/* Equivalent to the 'layout-mode' enum in org.gnome.Mutter.DisplayConfig */
typedef enum _MetaLogicalMonitorLayoutMode
{
META_LOGICAL_MONITOR_LAYOUT_MODE_LOGICAL = 1,
META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL = 2
} MetaLogicalMonitorLayoutMode;
typedef enum
{
META_MONITOR_TRANSFORM_NORMAL,
@ -274,6 +282,8 @@ struct _MetaMonitorManager
MetaPowerSave power_save_mode;
MetaLogicalMonitorLayoutMode layout_mode;
int screen_width;
int screen_height;
@ -376,6 +386,8 @@ struct _MetaMonitorManagerClass
gboolean (*get_max_screen_size) (MetaMonitorManager *,
int *,
int *);
MetaLogicalMonitorLayoutMode (*get_default_layout_mode) (MetaMonitorManager *);
};
void meta_monitor_manager_rebuild (MetaMonitorManager *manager,
@ -479,6 +491,9 @@ gboolean meta_monitor_manager_get_max_screen_size (MetaMonitorManager
int *max_width,
int *max_height);
MetaLogicalMonitorLayoutMode
meta_monitor_manager_get_default_layout_mode (MetaMonitorManager *manager);
void meta_monitor_manager_clear_output (MetaOutput *output);
void meta_monitor_manager_clear_mode (MetaCrtcMode *mode);
void meta_monitor_manager_clear_crtc (MetaCrtc *crtc);

View File

@ -319,6 +319,16 @@ meta_monitor_manager_get_max_screen_size (MetaMonitorManager *manager,
return manager_class->get_max_screen_size (manager, max_width, max_height);
}
MetaLogicalMonitorLayoutMode
meta_monitor_manager_get_default_layout_mode (MetaMonitorManager *manager)
{
MetaMonitorManagerClass *manager_class =
META_MONITOR_MANAGER_GET_CLASS (manager);
return manager_class->get_default_layout_mode (manager);
}
static void
meta_monitor_manager_ensure_initial_config (MetaMonitorManager *manager)
{
@ -1397,6 +1407,13 @@ meta_monitor_manager_handle_get_current_state (MetaDBusDisplayConfig *skeleton,
g_variant_new_boolean (FALSE));
}
if (capabilities & META_MONITOR_MANAGER_CAPABILITY_LAYOUT_MODE)
{
g_variant_builder_add (&properties_builder, "{sv}",
"layout-mode",
g_variant_new_uint32 (manager->layout_mode));
}
if (meta_monitor_manager_get_max_screen_size (manager,
&max_screen_width,
&max_screen_height))
@ -1593,10 +1610,12 @@ create_monitor_config_from_variant (MetaMonitorManager *manager,
}
static gboolean
derive_logical_monitor_size (GList *monitor_configs,
int *width,
int *height,
GError **error)
derive_logical_monitor_size (GList *monitor_configs,
int *width,
int *height,
double scale,
MetaLogicalMonitorLayoutMode layout_mode,
GError **error)
{
MetaMonitorConfig *monitor_config;
@ -1608,16 +1627,27 @@ derive_logical_monitor_size (GList *monitor_configs,
}
monitor_config = monitor_configs->data;
*width = monitor_config->mode_spec->width;
*height = monitor_config->mode_spec->height;
return TRUE;
switch (layout_mode)
{
case META_LOGICAL_MONITOR_LAYOUT_MODE_LOGICAL:
*width = monitor_config->mode_spec->width / scale;
*height = monitor_config->mode_spec->height / scale;
return TRUE;
case META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL:
*width = monitor_config->mode_spec->width;
*height = monitor_config->mode_spec->height;
return TRUE;
}
g_assert_not_reached ();
}
static MetaLogicalMonitorConfig *
create_logical_monitor_config_from_variant (MetaMonitorManager *manager,
GVariant *logical_monitor_config_variant,
GError **error)
create_logical_monitor_config_from_variant (MetaMonitorManager *manager,
GVariant *logical_monitor_config_variant,
MetaLogicalMonitorLayoutMode layout_mode,
GError **error)
{
MetaLogicalMonitorConfig *logical_monitor_config;
int x, y, width, height;
@ -1658,7 +1688,8 @@ create_logical_monitor_config_from_variant (MetaMonitorManager *manager,
}
g_variant_iter_free (monitor_configs_iter);
if (!derive_logical_monitor_size (monitor_configs, &width, &height, error))
if (!derive_logical_monitor_size (monitor_configs, &width, &height,
scale, layout_mode, error))
goto err;
logical_monitor_config = g_new0 (MetaLogicalMonitorConfig, 1);
@ -1674,7 +1705,9 @@ create_logical_monitor_config_from_variant (MetaMonitorManager *manager,
.monitor_configs = monitor_configs
};
if (!meta_verify_logical_monitor_config (logical_monitor_config, error))
if (!meta_verify_logical_monitor_config (logical_monitor_config,
layout_mode,
error))
{
meta_logical_monitor_config_free (logical_monitor_config);
return NULL;
@ -1687,6 +1720,19 @@ err:
return NULL;
}
static gboolean
is_valid_layout_mode (MetaLogicalMonitorLayoutMode layout_mode)
{
switch (layout_mode)
{
case META_LOGICAL_MONITOR_LAYOUT_MODE_LOGICAL:
case META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL:
return TRUE;
}
return FALSE;
}
static gboolean
meta_monitor_manager_handle_apply_monitors_config (MetaDBusDisplayConfig *skeleton,
GDBusMethodInvocation *invocation,
@ -1696,6 +1742,9 @@ meta_monitor_manager_handle_apply_monitors_config (MetaDBusDisplayConfig *skelet
GVariant *properties_variant)
{
MetaMonitorManager *manager = META_MONITOR_MANAGER (skeleton);
MetaMonitorManagerCapability capabilities;
GVariant *layout_mode_variant = NULL;
MetaLogicalMonitorLayoutMode layout_mode;
GVariantIter logical_monitor_configs_iter;
MetaMonitorsConfig *config;
GList *logical_monitor_configs = NULL;
@ -1717,6 +1766,39 @@ meta_monitor_manager_handle_apply_monitors_config (MetaDBusDisplayConfig *skelet
return TRUE;
}
capabilities = meta_monitor_manager_get_capabilities (manager);
if (properties_variant)
layout_mode_variant = g_variant_lookup_value (properties_variant,
"layout-mode",
G_VARIANT_TYPE ("u"));
if (layout_mode_variant &&
capabilities & META_MONITOR_MANAGER_CAPABILITY_LAYOUT_MODE)
{
g_variant_get (layout_mode_variant, "u", &layout_mode);
}
else if (!layout_mode_variant)
{
layout_mode =
meta_monitor_manager_get_default_layout_mode (manager);
}
else
{
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
G_DBUS_ERROR_INVALID_ARGS,
"Can't set layout mode");
return TRUE;
}
if (!is_valid_layout_mode (layout_mode))
{
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
G_DBUS_ERROR_ACCESS_DENIED,
"Invalid layout mode specified");
return TRUE;
}
g_variant_iter_init (&logical_monitor_configs_iter,
logical_monitor_configs_variant);
while (TRUE)
@ -1731,6 +1813,7 @@ meta_monitor_manager_handle_apply_monitors_config (MetaDBusDisplayConfig *skelet
logical_monitor_config =
create_logical_monitor_config_from_variant (manager,
logical_monitor_config_variant,
layout_mode,
&error);
if (!logical_monitor_config)
{
@ -1747,7 +1830,7 @@ meta_monitor_manager_handle_apply_monitors_config (MetaDBusDisplayConfig *skelet
logical_monitor_config);
}
config = meta_monitors_config_new (logical_monitor_configs);
config = meta_monitors_config_new (logical_monitor_configs, layout_mode);
if (!meta_verify_monitors_config (config, &error))
{
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
@ -2416,6 +2499,12 @@ void
meta_monitor_manager_update_logical_state (MetaMonitorManager *manager,
MetaMonitorsConfig *config)
{
if (config)
manager->layout_mode = config->layout_mode;
else
manager->layout_mode =
meta_monitor_manager_get_default_layout_mode (manager);
meta_monitor_manager_rebuild_logical_monitors (manager, config);
}
@ -2455,6 +2544,8 @@ meta_monitor_manager_update_monitor_modes_derived (MetaMonitorManager *manager)
void
meta_monitor_manager_update_logical_state_derived (MetaMonitorManager *manager)
{
manager->layout_mode = META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL;
meta_monitor_manager_rebuild_logical_monitors_derived (manager);
}

View File

@ -35,6 +35,8 @@
#include <meta/meta-backend.h>
#include "backends/meta-backend-private.h"
#include "backends/meta-logical-monitor.h"
#include "backends/meta-monitor.h"
#include "backends/meta-monitor-manager-private.h"
#include "backends/native/meta-renderer-native.h"
#include "meta/boxes.h"
@ -214,50 +216,125 @@ set_crtc_cursor (MetaCursorRendererNative *native,
}
}
typedef struct
{
MetaCursorRendererNative *in_cursor_renderer_native;
MetaLogicalMonitor *in_logical_monitor;
MetaRectangle in_local_cursor_rect;
MetaCursorSprite *in_cursor_sprite;
gboolean out_painted;
} UpdateCrtcCursorData;
static gboolean
update_monitor_crtc_cursor (MetaMonitor *monitor,
MetaMonitorMode *monitor_mode,
MetaMonitorCrtcMode *monitor_crtc_mode,
gpointer user_data,
GError **error)
{
UpdateCrtcCursorData *data = user_data;
MetaCursorRendererNative *cursor_renderer_native =
data->in_cursor_renderer_native;
MetaCursorRendererNativePrivate *priv =
meta_cursor_renderer_native_get_instance_private (cursor_renderer_native);
MetaRectangle scaled_crtc_rect;
int scale;
if (meta_is_stage_views_scaled ())
scale = meta_logical_monitor_get_scale (data->in_logical_monitor);
else
scale = 1;
scaled_crtc_rect = (MetaRectangle) {
.x = monitor_crtc_mode->x / scale,
.y = monitor_crtc_mode->y / scale,
.width = monitor_crtc_mode->crtc_mode->width / scale,
.height = monitor_crtc_mode->crtc_mode->height / scale
};
if (priv->has_hw_cursor &&
meta_rectangle_overlap (&scaled_crtc_rect,
&data->in_local_cursor_rect))
{
int crtc_cursor_x, crtc_cursor_y;
set_crtc_cursor (data->in_cursor_renderer_native,
monitor_crtc_mode->output->crtc,
data->in_cursor_sprite);
crtc_cursor_x = (data->in_local_cursor_rect.x - scaled_crtc_rect.x) * scale;
crtc_cursor_y = (data->in_local_cursor_rect.y - scaled_crtc_rect.y) * scale;
drmModeMoveCursor (priv->drm_fd,
monitor_crtc_mode->output->crtc->crtc_id,
crtc_cursor_x,
crtc_cursor_y);
data->out_painted = data->out_painted || TRUE;
}
else
{
set_crtc_cursor (data->in_cursor_renderer_native,
monitor_crtc_mode->output->crtc, NULL);
}
return TRUE;
}
static void
update_hw_cursor (MetaCursorRendererNative *native,
MetaCursorSprite *cursor_sprite)
{
MetaCursorRendererNativePrivate *priv = meta_cursor_renderer_native_get_instance_private (native);
MetaCursorRenderer *renderer = META_CURSOR_RENDERER (native);
MetaMonitorManager *monitors;
MetaCrtc *crtcs;
unsigned int i, n_crtcs;
MetaBackend *backend = meta_get_backend ();
MetaMonitorManager *monitor_manager =
meta_backend_get_monitor_manager (backend);
GList *logical_monitors;
GList *l;
MetaRectangle rect;
gboolean painted = FALSE;
monitors = meta_monitor_manager_get ();
meta_monitor_manager_get_resources (monitors, NULL, NULL, &crtcs, &n_crtcs, NULL, NULL);
if (cursor_sprite)
rect = meta_cursor_renderer_calculate_rect (renderer, cursor_sprite);
else
rect = (MetaRectangle) { 0 };
for (i = 0; i < n_crtcs; i++)
logical_monitors =
meta_monitor_manager_get_logical_monitors (monitor_manager);
for (l = logical_monitors; l; l = l->next)
{
gboolean crtc_should_use_cursor;
MetaCursorSprite *crtc_cursor;
MetaRectangle *crtc_rect;
MetaLogicalMonitor *logical_monitor = l->data;
UpdateCrtcCursorData data;
GList *monitors;
GList *k;
crtc_rect = &crtcs[i].rect;
data = (UpdateCrtcCursorData) {
.in_cursor_renderer_native = native,
.in_logical_monitor = logical_monitor,
.in_local_cursor_rect = (MetaRectangle) {
.x = rect.x - logical_monitor->rect.x,
.y = rect.y - logical_monitor->rect.y,
.width = rect.width,
.height = rect.height
},
.in_cursor_sprite = cursor_sprite
};
crtc_should_use_cursor = (priv->has_hw_cursor &&
meta_rectangle_overlap (&rect, crtc_rect));
if (crtc_should_use_cursor)
crtc_cursor = cursor_sprite;
else
crtc_cursor = NULL;
set_crtc_cursor (native, &crtcs[i], crtc_cursor);
if (crtc_cursor)
monitors = meta_logical_monitor_get_monitors (logical_monitor);
for (k = monitors; k; k = k->next)
{
drmModeMoveCursor (priv->drm_fd, crtcs[i].crtc_id,
rect.x - crtc_rect->x,
rect.y - crtc_rect->y);
painted = TRUE;
MetaMonitor *monitor = k->data;
MetaMonitorMode *monitor_mode;
monitor_mode = meta_monitor_get_current_mode (monitor);
meta_monitor_mode_foreach_crtc (monitor, monitor_mode,
update_monitor_crtc_cursor,
&data,
NULL);
}
painted = painted || data.out_painted;
}
priv->hw_state_invalidated = FALSE;
@ -316,6 +393,55 @@ cursor_over_transformed_crtc (MetaCursorRenderer *renderer,
return FALSE;
}
static float
calculate_cursor_crtc_sprite_scale (MetaCursorSprite *cursor_sprite,
MetaLogicalMonitor *logical_monitor)
{
return (meta_logical_monitor_get_scale (logical_monitor) *
meta_cursor_sprite_get_texture_scale (cursor_sprite));
}
static gboolean
can_draw_cursor_unscaled (MetaCursorRenderer *renderer,
MetaCursorSprite *cursor_sprite)
{
MetaBackend *backend;
MetaMonitorManager *monitor_manager;
MetaRectangle cursor_rect;
GList *logical_monitors;
GList *l;
gboolean has_visible_crtc_sprite = FALSE;
if (!meta_is_stage_views_scaled ())
return meta_cursor_sprite_get_texture_scale (cursor_sprite) == 1.0;
backend = meta_get_backend ();
monitor_manager = meta_backend_get_monitor_manager (backend);
logical_monitors =
meta_monitor_manager_get_logical_monitors (monitor_manager);
if (!logical_monitors)
return FALSE;
cursor_rect = meta_cursor_renderer_calculate_rect (renderer, cursor_sprite);
for (l = logical_monitors; l; l = l->next)
{
MetaLogicalMonitor *logical_monitor = l->data;
if (!meta_rectangle_overlap (&cursor_rect, &logical_monitor->rect))
continue;
if (calculate_cursor_crtc_sprite_scale (cursor_sprite,
logical_monitor) != 1.0)
return FALSE;
has_visible_crtc_sprite = TRUE;
}
return has_visible_crtc_sprite;
}
static gboolean
should_have_hw_cursor (MetaCursorRenderer *renderer,
MetaCursorSprite *cursor_sprite)
@ -337,7 +463,7 @@ should_have_hw_cursor (MetaCursorRenderer *renderer,
if (!texture)
return FALSE;
if (meta_cursor_sprite_get_texture_scale (cursor_sprite) != 1)
if (!can_draw_cursor_unscaled (renderer, cursor_sprite))
return FALSE;
if (!has_valid_cursor_sprite_gbm_bo (cursor_sprite))

View File

@ -1937,6 +1937,11 @@ meta_monitor_manager_kms_get_capabilities (MetaMonitorManager *manager)
MetaMonitorManagerCapability capabilities =
META_MONITOR_MANAGER_CAPABILITY_NONE;
if (meta_backend_is_experimental_feature_enabled (
backend,
META_EXPERIMENTAL_FEATURE_SCALE_MONITOR_FRAMEBUFFER))
capabilities |= META_MONITOR_MANAGER_CAPABILITY_LAYOUT_MODE;
switch (meta_renderer_native_get_mode (renderer_native))
{
case META_RENDERER_NATIVE_MODE_GBM:
@ -1967,6 +1972,20 @@ meta_monitor_manager_kms_get_max_screen_size (MetaMonitorManager *manager,
return TRUE;
}
static MetaLogicalMonitorLayoutMode
meta_monitor_manager_kms_get_default_layout_mode (MetaMonitorManager *manager)
{
if (!meta_is_stage_views_enabled ())
return META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL;
if (meta_backend_is_experimental_feature_enabled (
meta_get_backend (),
META_EXPERIMENTAL_FEATURE_SCALE_MONITOR_FRAMEBUFFER))
return META_LOGICAL_MONITOR_LAYOUT_MODE_LOGICAL;
else
return META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL;
}
static void
meta_monitor_manager_kms_dispose (GObject *object)
{
@ -2011,4 +2030,5 @@ meta_monitor_manager_kms_class_init (MetaMonitorManagerKmsClass *klass)
manager_class->get_supported_scales = meta_monitor_manager_kms_get_supported_scales;
manager_class->get_capabilities = meta_monitor_manager_kms_get_capabilities;
manager_class->get_max_screen_size = meta_monitor_manager_kms_get_max_screen_size;
manager_class->get_default_layout_mode = meta_monitor_manager_kms_get_default_layout_mode;
}

View File

@ -1707,16 +1707,26 @@ meta_renderer_native_create_view (MetaRenderer *renderer,
MetaMonitorTransform view_transform;
CoglOnscreen *onscreen = NULL;
CoglOffscreen *offscreen = NULL;
int scale;
int width, height;
MetaRendererView *view;
GError *error = NULL;
view_transform = calculate_view_transform (monitor_manager, logical_monitor);
if (meta_is_stage_views_scaled ())
scale = logical_monitor->scale;
else
scale = 1;
width = logical_monitor->rect.width * scale;
height = logical_monitor->rect.height * scale;
onscreen = meta_renderer_native_create_onscreen (META_RENDERER_NATIVE (renderer),
cogl_context,
view_transform,
logical_monitor->rect.width,
logical_monitor->rect.height);
width,
height);
if (!onscreen)
meta_fatal ("Failed to allocate onscreen framebuffer\n");
@ -1725,14 +1735,15 @@ meta_renderer_native_create_view (MetaRenderer *renderer,
offscreen = meta_renderer_native_create_offscreen (META_RENDERER_NATIVE (renderer),
cogl_context,
view_transform,
logical_monitor->rect.width,
logical_monitor->rect.height);
width,
height);
if (!offscreen)
meta_fatal ("Failed to allocate back buffer texture\n");
}
view = g_object_new (META_TYPE_RENDERER_VIEW,
"layout", &logical_monitor->rect,
"scale", scale,
"framebuffer", onscreen,
"offscreen", offscreen,
"logical-monitor", logical_monitor,

View File

@ -1623,6 +1623,16 @@ meta_monitor_manager_xrandr_get_max_screen_size (MetaMonitorManager *manager,
return TRUE;
}
static MetaLogicalMonitorLayoutMode
meta_monitor_manager_xrandr_get_default_layout_mode (MetaMonitorManager *manager)
{
/*
* Under X11, we still use the 'logical' layout mode, but it is
* eqivalent to 'physical' as the scale is always 1.
*/
return META_LOGICAL_MONITOR_LAYOUT_MODE_LOGICAL;
}
static void
meta_monitor_manager_xrandr_init (MetaMonitorManagerXrandr *manager_xrandr)
{
@ -1703,6 +1713,7 @@ meta_monitor_manager_xrandr_class_init (MetaMonitorManagerXrandrClass *klass)
manager_class->get_supported_scales = meta_monitor_manager_xrandr_get_supported_scales;
manager_class->get_capabilities = meta_monitor_manager_xrandr_get_capabilities;
manager_class->get_max_screen_size = meta_monitor_manager_xrandr_get_max_screen_size;
manager_class->get_default_layout_mode = meta_monitor_manager_xrandr_get_default_layout_mode;
quark_meta_monitor_xrandr_data =
g_quark_from_static_string ("-meta-monitor-xrandr-data");

View File

@ -122,6 +122,7 @@ meta_renderer_x11_create_view (MetaRenderer *renderer,
ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
CoglContext *cogl_context = clutter_backend_get_cogl_context (clutter_backend);
MetaMonitorTransform view_transform;
int view_scale;
int width, height;
CoglTexture2D *texture_2d;
CoglOffscreen *fake_onscreen;
@ -130,11 +131,16 @@ meta_renderer_x11_create_view (MetaRenderer *renderer,
g_assert (meta_is_wayland_compositor ());
width = logical_monitor->rect.width;
height = logical_monitor->rect.height;
view_transform = calculate_view_transform (monitor_manager, logical_monitor);
if (meta_is_stage_views_scaled ())
view_scale = logical_monitor->scale;
else
view_scale = 1;
width = logical_monitor->rect.width * view_scale;
height = logical_monitor->rect.height * view_scale;
texture_2d = cogl_texture_2d_new_with_size (cogl_context, width, height);
fake_onscreen = cogl_offscreen_new_with_texture (COGL_TEXTURE (texture_2d));
@ -158,6 +164,7 @@ meta_renderer_x11_create_view (MetaRenderer *renderer,
"framebuffer", COGL_FRAMEBUFFER (fake_onscreen),
"offscreen", COGL_FRAMEBUFFER (offscreen),
"transform", view_transform,
"scale", view_scale,
NULL);
}