[PATCH 15/15] compositor-drm: Support output scaling
alexl at redhat.com
alexl at redhat.com
Wed May 22 05:41:39 PDT 2013
From: Alexander Larsson <alexl at redhat.com>
If you specify e.g. scale=2 in an output section in weston.ini
we scale all modes by that factor.
We also correctly scale cursor positioning, but ATM there is no
scaling of the cursor sprite itself.
---
src/compositor-drm.c | 87 +++++++++++++++++++++++++++++++++++-----------------
1 file changed, 59 insertions(+), 28 deletions(-)
diff --git a/src/compositor-drm.c b/src/compositor-drm.c
index 8b33256..1485c6c 100644
--- a/src/compositor-drm.c
+++ b/src/compositor-drm.c
@@ -61,6 +61,7 @@ static int option_current_mode = 0;
static char *output_name;
static char *output_mode;
static char *output_transform;
+static char *output_scale;
static struct wl_list configured_output_list;
enum output_config {
@@ -76,6 +77,7 @@ struct drm_configured_output {
char *name;
char *mode;
uint32_t transform;
+ int32_t scale;
int32_t width, height;
drmModeModeInfo crtc_mode;
enum output_config config;
@@ -463,6 +465,7 @@ drm_output_prepare_scanout_surface(struct weston_output *_output,
buffer->width != output->base.current->width ||
buffer->height != output->base.current->height ||
output->base.transform != es->buffer_transform ||
+ output->base.scale != es->buffer_scale ||
es->transform.enabled)
return NULL;
@@ -791,6 +794,9 @@ drm_output_prepare_overlay_surface(struct weston_output *output_base,
if (es->buffer_transform != output_base->transform)
return NULL;
+ if (es->buffer_scale != output_base->scale)
+ return NULL;
+
if (c->sprites_are_broken)
return NULL;
@@ -859,7 +865,8 @@ drm_output_prepare_overlay_surface(struct weston_output *output_base,
tbox = weston_transformed_rect(output_base->width,
output_base->height,
output_base->transform,
- 1, *box);
+ output_base->scale,
+ *box);
s->dest_x = tbox.x1;
s->dest_y = tbox.y1;
s->dest_w = tbox.x2 - tbox.x1;
@@ -896,7 +903,7 @@ drm_output_prepare_overlay_surface(struct weston_output *output_base,
tbox = weston_transformed_rect(wl_fixed_from_int(es->geometry.width),
wl_fixed_from_int(es->geometry.height),
- es->buffer_transform, 1, tbox);
+ es->buffer_transform, es->buffer_scale, tbox);
s->src_x = tbox.x1 << 8;
s->src_y = tbox.y1 << 8;
@@ -977,8 +984,8 @@ drm_output_set_cursor(struct drm_output *output)
}
}
- x = es->geometry.x - output->base.x;
- y = es->geometry.y - output->base.y;
+ x = (es->geometry.x - output->base.x) * output->base.scale;
+ y = (es->geometry.y - output->base.y) * output->base.scale;
if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
weston_log("failed to move cursor: %m\n");
@@ -1258,18 +1265,29 @@ init_pixman(struct drm_compositor *ec)
}
static struct drm_mode *
-drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
+drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info, struct drm_configured_output *config)
{
struct drm_mode *mode;
uint64_t refresh;
+ int scale;
mode = malloc(sizeof *mode);
if (mode == NULL)
return NULL;
+ scale = 1;
+ if (config)
+ scale = config->scale;
+
+ if (info->hdisplay % scale != 0 ||
+ info->vdisplay % scale) {
+ weston_log("Mode %dx%d not multiple of scale %d\n", info->hdisplay, info->vdisplay, scale);
+ return NULL;
+ }
+
mode->base.flags = 0;
- mode->base.width = info->hdisplay;
- mode->base.height = info->vdisplay;
+ mode->base.width = info->hdisplay / scale;
+ mode->base.height = info->vdisplay / scale;
/* Calculate higher precision (mHz) refresh rate */
refresh = (info->clock * 1000000LL / info->htotal +
@@ -1285,6 +1303,9 @@ drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
mode->base.refresh = refresh;
mode->mode_info = *info;
+ if (scale != 1)
+ mode->base.flags |= WL_OUTPUT_MODE_SCALED;
+
if (info->type & DRM_MODE_TYPE_PREFERRED)
mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
@@ -1446,8 +1467,8 @@ drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec)
int i, flags;
output->surface = gbm_surface_create(ec->gbm,
- output->base.current->width,
- output->base.current->height,
+ output->base.current->width * output->base.scale,
+ output->base.current->height * output->base.scale,
GBM_FORMAT_XRGB8888,
GBM_BO_USE_SCANOUT |
GBM_BO_USE_RENDERING);
@@ -1491,12 +1512,12 @@ drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c)
/* FIXME error checking */
for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
- output->dumb[i] = drm_fb_create_dumb(c, w, h);
+ output->dumb[i] = drm_fb_create_dumb(c, w * output->base.scale, h * output->base.scale);
if (!output->dumb[i])
goto err;
output->image[i] =
- pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
+ pixman_image_create_bits(PIXMAN_x8r8g8b8, w * output->base.scale, h * output->base.scale,
output->dumb[i]->map,
output->dumb[i]->stride);
if (!output->image[i])
@@ -1719,6 +1740,16 @@ create_output_for_connector(struct drm_compositor *ec,
snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
output->base.name = strdup(name);
+ wl_list_for_each(temp, &configured_output_list, link) {
+ if (strcmp(temp->name, output->base.name) == 0) {
+ if (temp->mode)
+ weston_log("%s mode \"%s\" in config\n",
+ temp->name, temp->mode);
+ o = temp;
+ break;
+ }
+ }
+
output->crtc_id = resources->crtcs[i];
output->pipe = i;
ec->crtc_allocator |= (1 << output->crtc_id);
@@ -1742,7 +1773,7 @@ create_output_for_connector(struct drm_compositor *ec,
}
for (i = 0; i < connector->count_modes; i++) {
- drm_mode = drm_output_add_mode(output, &connector->modes[i]);
+ drm_mode = drm_output_add_mode(output, &connector->modes[i], o);
if (!drm_mode)
goto err_free;
}
@@ -1751,16 +1782,6 @@ create_output_for_connector(struct drm_compositor *ec,
current = NULL;
configured = NULL;
- wl_list_for_each(temp, &configured_output_list, link) {
- if (strcmp(temp->name, output->base.name) == 0) {
- if (temp->mode)
- weston_log("%s mode \"%s\" in config\n",
- temp->name, temp->mode);
- o = temp;
- break;
- }
- }
-
if (o && o->config == OUTPUT_CONFIG_OFF) {
weston_log("Disabling output %s\n", o->name);
@@ -1771,8 +1792,8 @@ create_output_for_connector(struct drm_compositor *ec,
wl_list_for_each(drm_mode, &output->base.mode_list, base.link) {
if (o && o->config == OUTPUT_CONFIG_MODE &&
- o->width == drm_mode->base.width &&
- o->height == drm_mode->base.height)
+ o->width == drm_mode->base.width * o->scale &&
+ o->height == drm_mode->base.height * o->scale)
configured = drm_mode;
if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
current = drm_mode;
@@ -1781,14 +1802,14 @@ create_output_for_connector(struct drm_compositor *ec,
}
if (o && o->config == OUTPUT_CONFIG_MODELINE) {
- configured = drm_output_add_mode(output, &o->crtc_mode);
+ configured = drm_output_add_mode(output, &o->crtc_mode, 0);
if (!configured)
goto err_free;
current = configured;
}
if (current == NULL && crtc_mode.clock != 0) {
- current = drm_output_add_mode(output, &crtc_mode);
+ current = drm_output_add_mode(output, &crtc_mode, 0);
if (!current)
goto err_free;
}
@@ -1814,7 +1835,8 @@ create_output_for_connector(struct drm_compositor *ec,
weston_output_init(&output->base, &ec->base, x, y,
connector->mmWidth, connector->mmHeight,
- o ? o->transform : WL_OUTPUT_TRANSFORM_NORMAL, 1);
+ o ? o->transform : WL_OUTPUT_TRANSFORM_NORMAL,
+ o ? o->scale : 1);
if (ec->use_pixman) {
if (drm_output_init_pixman(output, ec) < 0) {
@@ -2622,14 +2644,16 @@ output_section_done(void *data)
output = malloc(sizeof *output);
if (!output || !output_name || (output_name[0] == 'X') ||
- (!output_mode && !output_transform)) {
+ (!output_mode && !output_transform && !output_scale)) {
free(output_name);
free(output_mode);
free(output_transform);
+ free(output_scale);
free(output);
output_name = NULL;
output_mode = NULL;
output_transform = NULL;
+ output_scale = NULL;
return;
}
@@ -2658,11 +2682,17 @@ output_section_done(void *data)
drm_output_set_transform(output);
+ if (!output_scale || sscanf(output_scale, "%d", &output->scale) != 1)
+ output->scale = 1;
+
wl_list_insert(&configured_output_list, &output->link);
if (output_transform)
free(output_transform);
output_transform = NULL;
+ if (output_scale)
+ free(output_scale);
+ output_scale = NULL;
}
WL_EXPORT struct weston_compositor *
@@ -2688,6 +2718,7 @@ backend_init(struct wl_display *display, int *argc, char *argv[],
{ "name", CONFIG_KEY_STRING, &output_name },
{ "mode", CONFIG_KEY_STRING, &output_mode },
{ "transform", CONFIG_KEY_STRING, &output_transform },
+ { "scale", CONFIG_KEY_STRING, &output_scale },
};
const struct config_section config_section[] = {
--
1.8.1.4
More information about the wayland-devel
mailing list