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

@ -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))