diff --git a/src/compositor-drm.c b/src/compositor-drm.c index 35019e06..8b332569 100644 --- a/src/compositor-drm.c +++ b/src/compositor-drm.c @@ -858,7 +858,8 @@ drm_output_prepare_overlay_surface(struct weston_output *output_base, box = pixman_region32_extents(&dest_rect); tbox = weston_transformed_rect(output_base->width, output_base->height, - output_base->transform, *box); + output_base->transform, + 1, *box); s->dest_x = tbox.x1; s->dest_y = tbox.y1; s->dest_w = tbox.x2 - tbox.x1; @@ -895,7 +896,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, tbox); + es->buffer_transform, 1, tbox); s->src_x = tbox.x1 << 8; s->src_y = tbox.y1 << 8; @@ -1813,7 +1814,7 @@ 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); + o ? o->transform : WL_OUTPUT_TRANSFORM_NORMAL, 1); if (ec->use_pixman) { if (drm_output_init_pixman(output, ec) < 0) { diff --git a/src/compositor-fbdev.c b/src/compositor-fbdev.c index 21028a51..c643c236 100644 --- a/src/compositor-fbdev.c +++ b/src/compositor-fbdev.c @@ -537,7 +537,8 @@ fbdev_output_create(struct fbdev_compositor *compositor, weston_output_init(&output->base, &compositor->base, 0, 0, output->fb_info.width_mm, output->fb_info.height_mm, - WL_OUTPUT_TRANSFORM_NORMAL); + WL_OUTPUT_TRANSFORM_NORMAL, + 1); width = output->fb_info.x_resolution; height = output->fb_info.y_resolution; diff --git a/src/compositor-headless.c b/src/compositor-headless.c index 0df0f7db..e4bd1bea 100644 --- a/src/compositor-headless.c +++ b/src/compositor-headless.c @@ -112,7 +112,7 @@ headless_compositor_create_output(struct headless_compositor *c, output->base.current = &output->mode; weston_output_init(&output->base, &c->base, 0, 0, width, height, - WL_OUTPUT_TRANSFORM_NORMAL); + WL_OUTPUT_TRANSFORM_NORMAL, 1); output->base.make = "weston"; output->base.model = "headless"; diff --git a/src/compositor-rpi.c b/src/compositor-rpi.c index 3cb2b56e..226c5ce4 100644 --- a/src/compositor-rpi.c +++ b/src/compositor-rpi.c @@ -1080,7 +1080,8 @@ rpi_output_create(struct rpi_compositor *compositor) weston_output_init(&output->base, &compositor->base, 0, 0, round(mm_width), round(mm_height), - WL_OUTPUT_TRANSFORM_NORMAL); + WL_OUTPUT_TRANSFORM_NORMAL, + 1); if (gl_renderer_output_create(&output->base, (EGLNativeWindowType)&output->egl_window) < 0) diff --git a/src/compositor-wayland.c b/src/compositor-wayland.c index 4112401f..511a12da 100644 --- a/src/compositor-wayland.c +++ b/src/compositor-wayland.c @@ -267,7 +267,7 @@ wayland_compositor_create_output(struct wayland_compositor *c, output->base.current = &output->mode; weston_output_init(&output->base, &c->base, 0, 0, width, height, - WL_OUTPUT_TRANSFORM_NORMAL); + WL_OUTPUT_TRANSFORM_NORMAL, 1); output->base.make = "waywayland"; output->base.model = "none"; diff --git a/src/compositor-x11.c b/src/compositor-x11.c index ea0d4b9e..58ccc162 100644 --- a/src/compositor-x11.c +++ b/src/compositor-x11.c @@ -59,6 +59,7 @@ static char *output_name; static char *output_mode; static char *output_transform; +static char *output_scale; static int option_width; static int option_height; static int option_count; @@ -68,6 +69,7 @@ struct x11_configured_output { char *name; int width, height; uint32_t transform; + unsigned int scale; struct wl_list link; }; @@ -125,6 +127,7 @@ struct x11_output { int shm_id; void *buf; uint8_t depth; + uint32_t scale; }; static struct xkb_keymap * @@ -534,8 +537,12 @@ x11_output_wait_for_map(struct x11_compositor *c, struct x11_output *output) configure_notify = (xcb_configure_notify_event_t *) event; - output->mode.width = configure_notify->width; - output->mode.height = configure_notify->height; + + if (configure_notify->width % output->scale != 0 || + configure_notify->height % output->scale != 0) + weston_log("Resolution is not a multiple of screen size, rounding\n"); + output->mode.width = configure_notify->width / output->scale; + output->mode.height = configure_notify->height / output->scale; configured = 1; break; } @@ -677,7 +684,7 @@ static struct x11_output * x11_compositor_create_output(struct x11_compositor *c, int x, int y, int width, int height, int fullscreen, int no_input, char *configured_name, - uint32_t transform) + uint32_t transform, uint32_t scale) { static const char name[] = "Weston Compositor"; static const char class[] = "weston-1\0Weston Compositor"; @@ -686,6 +693,7 @@ x11_compositor_create_output(struct x11_compositor *c, int x, int y, xcb_screen_iterator_t iter; struct wm_normal_hints normal_hints; struct wl_event_loop *loop; + int output_width, output_height; uint32_t mask = XCB_CW_EVENT_MASK | XCB_CW_CURSOR; xcb_atom_t atom_list[1]; uint32_t values[2] = { @@ -694,6 +702,9 @@ x11_compositor_create_output(struct x11_compositor *c, int x, int y, 0 }; + output_width = width * scale; + output_height = height * scale; + if (configured_name) sprintf(title, "%s - %s", name, configured_name); else @@ -719,9 +730,13 @@ x11_compositor_create_output(struct x11_compositor *c, int x, int y, output->mode.flags = WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED; + if (output->scale != 1) + output->mode.flags |= WL_OUTPUT_MODE_SCALED; + output->mode.width = width; output->mode.height = height; output->mode.refresh = 60000; + output->scale = scale; wl_list_init(&output->base.mode_list); wl_list_insert(&output->base.mode_list, &output->mode.link); @@ -733,7 +748,7 @@ x11_compositor_create_output(struct x11_compositor *c, int x, int y, output->window, iter.data->root, 0, 0, - width, height, + output_width, output_height, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, iter.data->root_visual, @@ -751,10 +766,10 @@ x11_compositor_create_output(struct x11_compositor *c, int x, int y, memset(&normal_hints, 0, sizeof normal_hints); normal_hints.flags = WM_NORMAL_HINTS_MAX_SIZE | WM_NORMAL_HINTS_MIN_SIZE; - normal_hints.min_width = width; - normal_hints.min_height = height; - normal_hints.max_width = width; - normal_hints.max_height = height; + normal_hints.min_width = output_width; + normal_hints.min_height = output_height; + normal_hints.max_width = output_width; + normal_hints.max_height = output_height; xcb_change_property(c->conn, XCB_PROP_MODE_REPLACE, output->window, c->atom.wm_normal_hints, c->atom.wm_size_hints, 32, @@ -794,10 +809,10 @@ x11_compositor_create_output(struct x11_compositor *c, int x, int y, output->base.make = "xwayland"; output->base.model = "none"; weston_output_init(&output->base, &c->base, - x, y, width, height, transform); + x, y, width, height, transform, scale); if (c->use_pixman) { - if (x11_output_init_shm(c, output, width, height) < 0) + if (x11_output_init_shm(c, output, output_width, output_height) < 0) return NULL; if (pixman_renderer_output_create(&output->base) < 0) { x11_output_deinit_shm(c, output); @@ -960,8 +975,8 @@ x11_output_transform_coordinate(struct x11_output *x11_output, { struct weston_output *output = &x11_output->base; wl_fixed_t tx, ty; - wl_fixed_t width = wl_fixed_from_int(output->width - 1); - wl_fixed_t height = wl_fixed_from_int(output->height - 1); + wl_fixed_t width = wl_fixed_from_int(output->width * output->scale - 1); + wl_fixed_t height = wl_fixed_from_int(output->height * output->scale - 1); switch(output->transform) { case WL_OUTPUT_TRANSFORM_NORMAL: @@ -999,6 +1014,9 @@ x11_output_transform_coordinate(struct x11_output *x11_output, break; } + tx /= output->scale; + ty /= output->scale; + tx += wl_fixed_from_int(output->x); ty += wl_fixed_from_int(output->y); @@ -1457,7 +1475,7 @@ x11_compositor_create(struct wl_display *display, option_height ? height : o->height, fullscreen, no_input, - o->name, o->transform); + o->name, o->transform, o->scale); if (output == NULL) goto err_x11_input; @@ -1471,7 +1489,7 @@ x11_compositor_create(struct wl_display *display, for (i = output_count; i < count; i++) { output = x11_compositor_create_output(c, x, 0, width, height, fullscreen, no_input, NULL, - WL_OUTPUT_TRANSFORM_NORMAL); + WL_OUTPUT_TRANSFORM_NORMAL, wl_fixed_from_int(1)); if (output == NULL) goto err_x11_input; x = pixman_region32_extents(&output->base.region)->x2; @@ -1536,7 +1554,7 @@ 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)) { if (output_name) free(output_name); output_name = NULL; @@ -1559,6 +1577,16 @@ output_section_done(void *data) output->height = 640; } + output->scale = 1; + if (output_scale) { + if (sscanf(output_scale, "%d", &output->scale) != 1) { + weston_log("Invalid scale \"%s\" for output %s\n", + output_scale, output_name); + x11_free_configured_output(output); + goto err_free; + } + } + x11_output_set_transform(output); wl_list_insert(configured_output_list.prev, &output->link); @@ -1570,6 +1598,7 @@ err_free: free(output_transform); output_mode = NULL; output_transform = NULL; + output_scale = NULL; } WL_EXPORT struct weston_compositor * @@ -1597,6 +1626,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[] = { diff --git a/src/compositor.c b/src/compositor.c index f67028e3..99fff6d9 100644 --- a/src/compositor.c +++ b/src/compositor.c @@ -93,6 +93,8 @@ sigchld_handler(int signal_number, void *data) static void weston_output_transform_init(struct weston_output *output, uint32_t transform); +static void +weston_output_scale_init(struct weston_output *output, uint32_t scale); WL_EXPORT int weston_output_switch_mode(struct weston_output *output, struct weston_mode *mode) @@ -113,6 +115,7 @@ weston_output_switch_mode(struct weston_output *output, struct weston_mode *mode /* Update output region and transformation matrix */ weston_output_transform_init(output, output->transform); + weston_output_scale_init(output, output->scale); pixman_region32_init(&output->previous_damage); pixman_region32_init_rect(&output->region, output->x, output->y, @@ -291,7 +294,9 @@ weston_surface_create(struct weston_compositor *compositor) } surface->buffer_transform = WL_OUTPUT_TRANSFORM_NORMAL; + surface->buffer_scale = 1; surface->pending.buffer_transform = surface->buffer_transform; + surface->pending.buffer_scale = surface->buffer_scale; surface->output = NULL; surface->plane = &compositor->primary_plane; surface->pending.newly_attached = 0; @@ -360,6 +365,7 @@ weston_surface_to_global_float(struct weston_surface *surface, WL_EXPORT void weston_transformed_coord(int width, int height, enum wl_output_transform transform, + uint32_t scale, float sx, float sy, float *bx, float *by) { switch (transform) { @@ -397,20 +403,24 @@ weston_transformed_coord(int width, int height, *by = sx; break; } + + *bx *= scale; + *by *= scale; } WL_EXPORT pixman_box32_t weston_transformed_rect(int width, int height, enum wl_output_transform transform, + uint32_t scale, pixman_box32_t rect) { float x1, x2, y1, y2; pixman_box32_t ret; - weston_transformed_coord(width, height, transform, + weston_transformed_coord(width, height, transform, scale, rect.x1, rect.y1, &x1, &y1); - weston_transformed_coord(width, height, transform, + weston_transformed_coord(width, height, transform, scale, rect.x2, rect.y2, &x2, &y2); if (x1 <= x2) { @@ -439,16 +449,34 @@ weston_surface_to_buffer_float(struct weston_surface *surface, weston_transformed_coord(surface->geometry.width, surface->geometry.height, surface->buffer_transform, + surface->buffer_scale, sx, sy, bx, by); } +WL_EXPORT void +weston_surface_to_buffer(struct weston_surface *surface, + int sx, int sy, int *bx, int *by) +{ + float bxf, byf; + + weston_transformed_coord(surface->geometry.width, + surface->geometry.height, + surface->buffer_transform, + surface->buffer_scale, + sx, sy, &bxf, &byf); + *bx = floorf(bxf); + *by = floorf(byf); +} + WL_EXPORT pixman_box32_t weston_surface_to_buffer_rect(struct weston_surface *surface, pixman_box32_t rect) { return weston_transformed_rect(surface->geometry.width, surface->geometry.height, - surface->buffer_transform, rect); + surface->buffer_transform, + surface->buffer_scale, + rect); } WL_EXPORT void @@ -877,29 +905,37 @@ weston_surface_is_mapped(struct weston_surface *surface) WL_EXPORT int32_t weston_surface_buffer_width(struct weston_surface *surface) { + int32_t width; switch (surface->buffer_transform) { case WL_OUTPUT_TRANSFORM_90: case WL_OUTPUT_TRANSFORM_270: case WL_OUTPUT_TRANSFORM_FLIPPED_90: case WL_OUTPUT_TRANSFORM_FLIPPED_270: - return surface->buffer_ref.buffer->height; + width = surface->buffer_ref.buffer->height; + break; default: - return surface->buffer_ref.buffer->width; + width = surface->buffer_ref.buffer->width; + break; } + return width / surface->buffer_scale; } WL_EXPORT int32_t weston_surface_buffer_height(struct weston_surface *surface) { + int32_t height; switch (surface->buffer_transform) { case WL_OUTPUT_TRANSFORM_90: case WL_OUTPUT_TRANSFORM_270: case WL_OUTPUT_TRANSFORM_FLIPPED_90: case WL_OUTPUT_TRANSFORM_FLIPPED_270: - return surface->buffer_ref.buffer->width; + height = surface->buffer_ref.buffer->width; + break; default: - return surface->buffer_ref.buffer->height; + height = surface->buffer_ref.buffer->height; + break; } + return height / surface->buffer_scale; } WL_EXPORT uint32_t @@ -1485,25 +1521,28 @@ static void weston_surface_commit(struct weston_surface *surface) { pixman_region32_t opaque; - int buffer_width = 0; - int buffer_height = 0; + int surface_width = 0; + int surface_height = 0; - /* wl_surface.set_buffer_rotation */ + /* wl_surface.set_buffer_transform */ surface->buffer_transform = surface->pending.buffer_transform; + /* wl_surface.set_buffer_scale */ + surface->buffer_scale = surface->pending.buffer_scale; + /* wl_surface.attach */ if (surface->pending.buffer || surface->pending.newly_attached) weston_surface_attach(surface, surface->pending.buffer); if (surface->buffer_ref.buffer) { - buffer_width = weston_surface_buffer_width(surface); - buffer_height = weston_surface_buffer_height(surface); + surface_width = weston_surface_buffer_width(surface); + surface_height = weston_surface_buffer_height(surface); } if (surface->configure && surface->pending.newly_attached) surface->configure(surface, surface->pending.sx, surface->pending.sy, - buffer_width, buffer_height); + surface_width, surface_height); if (surface->pending.buffer) wl_list_remove(&surface->pending.buffer_destroy_listener.link); @@ -1588,6 +1627,16 @@ surface_set_buffer_transform(struct wl_client *client, surface->pending.buffer_transform = transform; } +static void +surface_set_buffer_scale(struct wl_client *client, + struct wl_resource *resource, + uint32_t scale) +{ + struct weston_surface *surface = resource->data; + + surface->pending.buffer_scale = scale; +} + static const struct wl_surface_interface surface_interface = { surface_destroy, surface_attach, @@ -1596,7 +1645,8 @@ static const struct wl_surface_interface surface_interface = { surface_set_opaque_region, surface_set_input_region, surface_commit, - surface_set_buffer_transform + surface_set_buffer_transform, + surface_set_buffer_scale }; static void @@ -1702,25 +1752,28 @@ weston_subsurface_commit_from_cache(struct weston_subsurface *sub) { struct weston_surface *surface = sub->surface; pixman_region32_t opaque; - int buffer_width = 0; - int buffer_height = 0; + int surface_width = 0; + int surface_height = 0; - /* wl_surface.set_buffer_rotation */ + /* wl_surface.set_buffer_transform */ surface->buffer_transform = sub->cached.buffer_transform; + /* wl_surface.set_buffer_scale */ + surface->buffer_scale = sub->cached.buffer_scale; + /* wl_surface.attach */ if (sub->cached.buffer_ref.buffer || sub->cached.newly_attached) weston_surface_attach(surface, sub->cached.buffer_ref.buffer); weston_buffer_reference(&sub->cached.buffer_ref, NULL); if (surface->buffer_ref.buffer) { - buffer_width = weston_surface_buffer_width(surface); - buffer_height = weston_surface_buffer_height(surface); + surface_width = weston_surface_buffer_width(surface); + surface_height = weston_surface_buffer_height(surface); } if (surface->configure && sub->cached.newly_attached) surface->configure(surface, sub->cached.sx, sub->cached.sy, - buffer_width, buffer_height); + surface_width, surface_height); sub->cached.sx = 0; sub->cached.sy = 0; sub->cached.newly_attached = 0; @@ -1797,6 +1850,7 @@ weston_subsurface_commit_to_cache(struct weston_subsurface *sub) surface->pending.newly_attached = 0; sub->cached.buffer_transform = surface->pending.buffer_transform; + sub->cached.buffer_scale = surface->pending.buffer_scale; pixman_region32_copy(&sub->cached.opaque, &surface->pending.opaque); @@ -2466,6 +2520,9 @@ bind_output(struct wl_client *client, output->subpixel, output->make, output->model, output->transform); + if (version >= 2) + wl_output_send_scale(resource, + output->scale); wl_list_for_each (mode, &output->mode_list, link) { wl_output_send_mode(resource, @@ -2474,6 +2531,9 @@ bind_output(struct wl_client *client, mode->height, mode->refresh); } + + if (version >= 2) + wl_output_send_done(resource); } WL_EXPORT void @@ -2608,6 +2668,12 @@ weston_output_transform_init(struct weston_output *output, uint32_t transform) } } +static void +weston_output_scale_init(struct weston_output *output, uint32_t scale) +{ + output->scale = scale; +} + WL_EXPORT void weston_output_move(struct weston_output *output, int x, int y) { @@ -2622,7 +2688,8 @@ weston_output_move(struct weston_output *output, int x, int y) WL_EXPORT void weston_output_init(struct weston_output *output, struct weston_compositor *c, - int x, int y, int width, int height, uint32_t transform) + int x, int y, int width, int height, uint32_t transform, + uint32_t scale) { output->compositor = c; output->x = x; @@ -2636,6 +2703,7 @@ weston_output_init(struct weston_output *output, struct weston_compositor *c, output->dirty = 1; weston_output_transform_init(output, transform); + weston_output_scale_init(output, scale); weston_output_init_zoom(output); weston_output_move(output, x, y); diff --git a/src/compositor.h b/src/compositor.h index 318fc0d3..9a16ab6c 100644 --- a/src/compositor.h +++ b/src/compositor.h @@ -183,7 +183,8 @@ struct weston_output { char *make, *model, *serial_number; uint32_t subpixel; uint32_t transform; - + uint32_t scale; + struct weston_mode *current; struct weston_mode *origin; struct wl_list mode_list; @@ -601,6 +602,9 @@ struct weston_subsurface { /* wl_surface.set_buffer_transform */ uint32_t buffer_transform; + + /* wl_surface.set_buffer_scale */ + uint32_t buffer_scale; } cached; int synchronized; @@ -704,6 +708,7 @@ struct weston_surface { struct weston_buffer_reference buffer_ref; uint32_t buffer_transform; + uint32_t buffer_scale; int keep_buffer; /* bool for backends to prevent early release */ /* All the pending state, that wl_surface.commit will apply. */ @@ -729,6 +734,9 @@ struct weston_surface { /* wl_surface.set_buffer_transform */ uint32_t buffer_transform; + + /* wl_surface.set_scaling_factor */ + uint32_t buffer_scale; } pending; /* @@ -787,6 +795,10 @@ weston_surface_buffer_height(struct weston_surface *surface); WL_EXPORT void weston_surface_to_buffer_float(struct weston_surface *surface, float x, float y, float *bx, float *by); +WL_EXPORT void +weston_surface_to_buffer(struct weston_surface *surface, + int sx, int sy, int *bx, int *by); + pixman_box32_t weston_surface_to_buffer_rect(struct weston_surface *surface, pixman_box32_t rect); @@ -1005,7 +1017,7 @@ void weston_output_move(struct weston_output *output, int x, int y); void weston_output_init(struct weston_output *output, struct weston_compositor *c, - int x, int y, int width, int height, uint32_t transform); + int x, int y, int width, int height, uint32_t transform, uint32_t scale); void weston_output_destroy(struct weston_output *output); @@ -1136,10 +1148,12 @@ module_init(struct weston_compositor *compositor, void weston_transformed_coord(int width, int height, enum wl_output_transform transform, + uint32_t scale, float sx, float sy, float *bx, float *by); pixman_box32_t weston_transformed_rect(int width, int height, enum wl_output_transform transform, + uint32_t scale, pixman_box32_t rect); #ifdef __cplusplus diff --git a/src/gl-renderer.c b/src/gl-renderer.c index be74eba3..52d15e08 100644 --- a/src/gl-renderer.c +++ b/src/gl-renderer.c @@ -68,6 +68,7 @@ struct gl_surface_state { struct weston_buffer_reference buffer_ref; int pitch; /* in pixels */ + int height; /* in pixels */ }; struct gl_renderer { @@ -552,17 +553,7 @@ texture_region(struct weston_surface *es, pixman_region32_t *region, vtxcnt = wl_array_add(&gr->vtxcnt, nrects * nsurf * sizeof *vtxcnt); inv_width = 1.0 / gs->pitch; - - switch (es->buffer_transform) { - case WL_OUTPUT_TRANSFORM_90: - case WL_OUTPUT_TRANSFORM_270: - case WL_OUTPUT_TRANSFORM_FLIPPED_90: - case WL_OUTPUT_TRANSFORM_FLIPPED_270: - inv_height = 1.0 / es->geometry.width; - break; - default: - inv_height = 1.0 / es->geometry.height; - } + inv_height = 1.0 / gs->height; for (i = 0; i < nrects; i++) { pixman_box32_t *rect = &rects[i]; @@ -791,7 +782,7 @@ draw_surface(struct weston_surface *es, struct weston_output *output, use_shader(gr, gs->shader); shader_uniforms(gs->shader, es, output); - if (es->transform.enabled || output->zoom.active) + if (es->transform.enabled || output->zoom.active || output->scale != es->buffer_scale) filter = GL_LINEAR; else filter = GL_NEAREST; @@ -1023,9 +1014,9 @@ gl_renderer_repaint_output(struct weston_output *output, int32_t width, height; pixman_region32_t buffer_damage, total_damage; - width = output->current->width + + width = output->current->width * output->scale + output->border.left + output->border.right; - height = output->current->height + + height = output->current->height * output->scale + output->border.top + output->border.bottom; glViewport(0, 0, width, height); @@ -1214,6 +1205,7 @@ gl_renderer_attach(struct weston_surface *es, struct wl_buffer *buffer) if (wl_buffer_is_shm(buffer)) { gs->pitch = wl_shm_buffer_get_stride(buffer) / 4; + gs->height = wl_shm_buffer_get_height(buffer); gs->target = GL_TEXTURE_2D; ensure_textures(gs, 1); @@ -1279,6 +1271,7 @@ gl_renderer_attach(struct weston_surface *es, struct wl_buffer *buffer) } gs->pitch = buffer->width; + gs->height = buffer->height; } else { weston_log("unhandled buffer type!\n"); weston_buffer_reference(&gs->buffer_ref, NULL); diff --git a/src/pixman-renderer.c b/src/pixman-renderer.c index 92c6bb39..b1bbcd6a 100644 --- a/src/pixman-renderer.c +++ b/src/pixman-renderer.c @@ -104,6 +104,36 @@ pixman_renderer_read_pixels(struct weston_output *output, return 0; } +static void +box_scale(pixman_box32_t *dst, int scale) +{ + dst->x1 *= scale; + dst->x2 *= scale; + dst->y1 *= scale; + dst->y2 *= scale; +} + +static void +scale_region (pixman_region32_t *region, int scale) +{ + pixman_box32_t *rects, *scaled_rects; + int nrects, i; + + if (scale != 1) { + rects = pixman_region32_rectangles(region, &nrects); + scaled_rects = calloc(nrects, sizeof(pixman_box32_t)); + + for (i = 0; i < nrects; i++) { + scaled_rects[i] = rects[i]; + box_scale(&scaled_rects[i], scale); + } + pixman_region32_clear(region); + + pixman_region32_init_rects (region, scaled_rects, nrects); + free (scaled_rects); + } +} + static void transform_region (pixman_region32_t *region, int width, int height, enum wl_output_transform transform) { @@ -180,6 +210,7 @@ region_global_to_output(struct weston_output *output, pixman_region32_t *region) { pixman_region32_translate(region, -output->x, -output->y); transform_region (region, output->width, output->height, output->transform); + scale_region (region, output->scale); } #define D2F(v) pixman_double_to_fixed((double)v) @@ -229,9 +260,12 @@ repaint_region(struct weston_surface *es, struct weston_output *output, pixman_image_set_clip_region32 (po->shadow_image, &final_region); /* Set up the source transformation based on the surface - position, the output position/transform and the client - specified buffer transform */ + position, the output position/transform/scale and the client + specified buffer transform/scale */ pixman_transform_init_identity(&transform); + pixman_transform_scale(&transform, NULL, + pixman_double_to_fixed ((double)1.0/output->scale), + pixman_double_to_fixed ((double)1.0/output->scale)); fw = pixman_int_to_fixed(output->width); fh = pixman_int_to_fixed(output->height); @@ -338,9 +372,13 @@ repaint_region(struct weston_surface *es, struct weston_output *output, break; } + pixman_transform_scale(&transform, NULL, + pixman_double_to_fixed ((double)es->buffer_scale), + pixman_double_to_fixed ((double)es->buffer_scale)); + pixman_image_set_transform(ps->image, &transform); - if (es->transform.enabled) + if (es->transform.enabled || output->scale != es->buffer_scale) pixman_image_set_filter(ps->image, PIXMAN_FILTER_BILINEAR, NULL, 0); else pixman_image_set_filter(ps->image, PIXMAN_FILTER_NEAREST, NULL, 0); @@ -651,8 +689,8 @@ pixman_renderer_output_create(struct weston_output *output) return -1; /* set shadow image transformation */ - w = output->current->width; - h = output->current->height; + w = output->current->width * output->scale; + h = output->current->height * output->scale; po->shadow_buffer = malloc(w * h * 4);