[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