mirror of
https://gitlab.freedesktop.org/wayland/weston.git
synced 2026-05-08 18:18:09 +02:00
compositor-drm: Support output scaling
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.
This commit is contained in:
parent
80f9163ad6
commit
d9a7bb75d0
1 changed files with 59 additions and 28 deletions
|
|
@ -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[] = {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue