compositor: Support output/buffer scaling

If you specify e.g. scale=2 in weston.ini an output section for the
X11 backend we automatically upscale all normal surfaces by this
amount. Additionally we respect a buffer_scale set on the buffer to
mean that the buffer is already in a scaled form.

This works with both the gl and the pixman renderer. The non-X
backends compile and work, but don't support changing the output
scale (they do downscale as needed due to buffer_scale though).

This also sends the new "scale" and "done" events on wl_output,
making clients aware of the scale.
Alexander Larsson 12 years ago committed by Kristian Høgsberg
parent 1f206b4ce4
commit 4ea9552d05
  1. 7
      src/compositor-drm.c
  2. 3
      src/compositor-fbdev.c
  3. 2
      src/compositor-headless.c
  4. 3
      src/compositor-rpi.c
  5. 2
      src/compositor-wayland.c
  6. 60
      src/compositor-x11.c
  7. 110
      src/compositor.c
  8. 18
      src/compositor.h
  9. 21
      src/gl-renderer.c
  10. 48
      src/pixman-renderer.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) {

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

@ -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";

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

@ -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";

@ -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[] = {

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

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

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

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

Loading…
Cancel
Save