[PATCH 13/15] compositor: Support output/buffer scaling
alexl at redhat.com
alexl at redhat.com
Wed May 22 05:41:37 PDT 2013
From: Alexander Larsson <alexl at redhat.com>
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.
---
src/compositor-drm.c | 7 +--
src/compositor-fbdev.c | 3 +-
src/compositor-headless.c | 2 +-
src/compositor-rpi.c | 3 +-
src/compositor-wayland.c | 2 +-
src/compositor-x11.c | 60 ++++++++++++++++++-------
src/compositor.c | 110 +++++++++++++++++++++++++++++++++++++---------
src/compositor.h | 18 +++++++-
src/gl-renderer.c | 21 +++------
src/pixman-renderer.c | 48 +++++++++++++++++---
10 files changed, 210 insertions(+), 64 deletions(-)
diff --git a/src/compositor-drm.c b/src/compositor-drm.c
index 35019e0..8b33256 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 21028a5..c643c23 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 0df0f7d..e4bd1be 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 3cb2b56..226c5ce 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 4112401..511a12d 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 ea0d4b9..58ccc16 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 f67028e..99fff6d 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 318fc0d..9a16ab6 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 be74eba..52d15e0 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 92c6bb3..b1bbcd6 100644
--- a/src/pixman-renderer.c
+++ b/src/pixman-renderer.c
@@ -105,6 +105,36 @@ pixman_renderer_read_pixels(struct weston_output *output,
}
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)
{
pixman_box32_t *rects, *transformed_rects;
@@ -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);
--
1.8.1.4
More information about the wayland-devel
mailing list