diff --git a/src/compositor.c b/src/compositor.c index 6eb0b8c3..44cd4a8d 100644 --- a/src/compositor.c +++ b/src/compositor.c @@ -245,6 +245,8 @@ weston_surface_create(struct weston_compositor *compositor) pixman_region32_init(&surface->texture_damage); surface->buffer = NULL; + surface->buffer_transform = WL_OUTPUT_TRANSFORM_NORMAL; + surface->pending.buffer_transform = surface->buffer_transform; surface->output = NULL; surface->plane = &compositor->primary_plane; @@ -653,6 +655,34 @@ weston_surface_is_mapped(struct weston_surface *surface) return 0; } +WL_EXPORT int32_t +weston_surface_buffer_width(struct weston_surface *surface) +{ + 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->height; + default: + return surface->buffer->width; + } +} + +WL_EXPORT int32_t +weston_surface_buffer_height(struct weston_surface *surface) +{ + 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->width; + default: + return surface->buffer->height; + } +} + WL_EXPORT uint32_t weston_compositor_get_time(void) { @@ -1237,6 +1267,31 @@ surface_set_input_region(struct wl_client *client, } } +static int +surface_pending_buffer_has_different_size(struct weston_surface *surface) +{ + int width, height; + + switch (surface->pending.buffer_transform) { + case WL_OUTPUT_TRANSFORM_90: + case WL_OUTPUT_TRANSFORM_270: + case WL_OUTPUT_TRANSFORM_FLIPPED_90: + case WL_OUTPUT_TRANSFORM_FLIPPED_270: + height = surface->pending.buffer->width; + width = surface->pending.buffer->height; + break; + default: + width = surface->pending.buffer->width; + height = surface->pending.buffer->height; + } + + if (width == surface->geometry.width && + height == surface->geometry.height) + return 0; + else + return 1; +} + static void surface_commit(struct wl_client *client, struct wl_resource *resource) { @@ -1245,10 +1300,12 @@ surface_commit(struct wl_client *client, struct wl_resource *resource) if (surface->pending.sx || surface->pending.sy || (surface->pending.buffer && - (surface->pending.buffer->width != surface->geometry.width || - surface->pending.buffer->height != surface->geometry.height))) + surface_pending_buffer_has_different_size(surface))) surface->geometry.dirty = 1; + /* wl_surface.set_buffer_rotation */ + surface->buffer_transform = surface->pending.buffer_transform; + /* wl_surface.attach */ if (surface->pending.buffer || surface->pending.remove_contents) weston_surface_attach(surface, surface->pending.buffer); @@ -1298,6 +1355,15 @@ surface_commit(struct wl_client *client, struct wl_resource *resource) weston_surface_schedule_repaint(surface); } +static void +surface_set_buffer_transform(struct wl_client *client, + struct wl_resource *resource, int transform) +{ + struct weston_surface *surface = resource->data; + + surface->pending.buffer_transform = transform; +} + static const struct wl_surface_interface surface_interface = { surface_destroy, surface_attach, @@ -1305,7 +1371,8 @@ static const struct wl_surface_interface surface_interface = { surface_frame, surface_set_opaque_region, surface_set_input_region, - surface_commit + surface_commit, + surface_set_buffer_transform }; static void diff --git a/src/compositor.h b/src/compositor.h index e770664e..9e6355d7 100644 --- a/src/compositor.h +++ b/src/compositor.h @@ -437,6 +437,7 @@ struct weston_surface { struct wl_buffer *buffer; struct wl_listener buffer_destroy_listener; + uint32_t buffer_transform; /* All the pending state, that wl_surface.commit will apply. */ struct { @@ -458,6 +459,9 @@ struct weston_surface { /* wl_surface.frame */ struct wl_list frame_callback_list; + + /* wl_surface.set_buffer_transform */ + uint32_t buffer_transform; } pending; /* @@ -495,6 +499,10 @@ void weston_surface_from_global_fixed(struct weston_surface *surface, wl_fixed_t x, wl_fixed_t y, wl_fixed_t *sx, wl_fixed_t *sy); +int32_t +weston_surface_buffer_width(struct weston_surface *surface); +int32_t +weston_surface_buffer_height(struct weston_surface *surface); void weston_spring_init(struct weston_spring *spring, diff --git a/src/gl-renderer.c b/src/gl-renderer.c index 10477d3e..c2fdaa33 100644 --- a/src/gl-renderer.c +++ b/src/gl-renderer.c @@ -517,6 +517,47 @@ calculate_edges(struct weston_surface *es, pixman_box32_t *rect, return n; } +static void +transform_texcoord(struct weston_surface *es, GLfloat sx, GLfloat sy, + GLfloat *tx, GLfloat *ty) +{ + switch(es->buffer_transform) { + case WL_OUTPUT_TRANSFORM_NORMAL: + default: + *tx = sx; + *ty = sy; + break; + case WL_OUTPUT_TRANSFORM_FLIPPED: + *tx = 1.0 - sx; + *ty = sy; + break; + case WL_OUTPUT_TRANSFORM_90: + *tx = 1.0 - sy; + *ty = sx; + break; + case WL_OUTPUT_TRANSFORM_FLIPPED_90: + *tx = 1.0 - sy; + *ty = 1.0 - sx; + break; + case WL_OUTPUT_TRANSFORM_180: + *tx = 1.0 - sx; + *ty = 1.0 - sy; + break; + case WL_OUTPUT_TRANSFORM_FLIPPED_180: + *tx = sx; + *ty = 1.0 - sy; + break; + case WL_OUTPUT_TRANSFORM_270: + *tx = sy; + *ty = 1.0 - sx; + break; + case WL_OUTPUT_TRANSFORM_FLIPPED_270: + *tx = sy; + *ty = sx; + break; + } +} + static int texture_region(struct weston_surface *es, pixman_region32_t *region, pixman_region32_t *surf_region) @@ -543,7 +584,7 @@ texture_region(struct weston_surface *es, pixman_region32_t *region, pixman_box32_t *rect = &rects[i]; for (j = 0; j < nsurf; j++) { pixman_box32_t *surf_rect = &surf_rects[j]; - GLfloat sx, sy; + GLfloat sx, sy, tx, ty; GLfloat ex[8], ey[8]; /* edge points in screen space */ int n; @@ -572,8 +613,12 @@ texture_region(struct weston_surface *es, pixman_region32_t *region, *(v++) = ex[k]; *(v++) = ey[k]; /* texcoord: */ - *(v++) = sx * inv_width; - *(v++) = sy * inv_height; + transform_texcoord(es, + sx * inv_width, + sy * inv_height, + &tx, &ty); + *(v++) = tx; + *(v++) = ty; } vtxcnt[nvtx++] = n; @@ -1183,7 +1228,16 @@ gl_renderer_attach(struct weston_surface *es, struct wl_buffer *buffer) gs->images[i]); } - es->pitch = buffer->width; + 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: + es->pitch = buffer->height; + break; + default: + es->pitch = buffer->width; + } } else { weston_log("unhandled buffer type!\n"); } diff --git a/src/shell.c b/src/shell.c index 6bd89ec1..89d76272 100644 --- a/src/shell.c +++ b/src/shell.c @@ -2129,7 +2129,8 @@ configure_static_surface(struct weston_surface *es, struct weston_layer *layer) } weston_surface_configure(es, es->output->x, es->output->y, - es->buffer->width, es->buffer->height); + weston_surface_buffer_width(es), + weston_surface_buffer_height(es)); if (wl_list_empty(&es->layer_link)) { wl_list_insert(&layer->surface_list, &es->layer_link); @@ -2815,12 +2816,14 @@ hide_input_panels(struct wl_listener *listener, void *data) static void center_on_output(struct weston_surface *surface, struct weston_output *output) { - float x = (output->width - surface->buffer->width) / 2; - float y = (output->height - surface->buffer->height) / 2; + int32_t width = weston_surface_buffer_width(surface); + int32_t height = weston_surface_buffer_height(surface); + float x, y; - weston_surface_configure(surface, output->x + x, output->y + y, - surface->buffer->width, - surface->buffer->height); + x = output->x + (output->width - width) / 2; + y = output->y + (output->height - height) / 2; + + weston_surface_configure(surface, x, y, width, height); } static void @@ -3029,6 +3032,8 @@ shell_surface_configure(struct weston_surface *es, int32_t sx, int32_t sy) { struct shell_surface *shsurf = get_shell_surface(es); struct desktop_shell *shell = shsurf->shell; + int32_t width = weston_surface_buffer_width(es); + int32_t height = weston_surface_buffer_height(es); int type_changed = 0; if (shsurf->next_type != SHELL_SURFACE_NONE && @@ -3038,10 +3043,10 @@ shell_surface_configure(struct weston_surface *es, int32_t sx, int32_t sy) } if (!weston_surface_is_mapped(es)) { - map(shell, es, es->buffer->width, es->buffer->height, sx, sy); + map(shell, es, width, height, sx, sy); } else if (type_changed || sx != 0 || sy != 0 || - es->geometry.width != es->buffer->width || - es->geometry.height != es->buffer->height) { + es->geometry.width != width || + es->geometry.height != height) { float from_x, from_y; float to_x, to_y; @@ -3050,7 +3055,7 @@ shell_surface_configure(struct weston_surface *es, int32_t sx, int32_t sy) configure(shell, es, es->geometry.x + to_x - from_x, es->geometry.y + to_y - from_y, - es->buffer->width, es->buffer->height); + width, height); } } @@ -3216,8 +3221,10 @@ static void input_panel_configure(struct weston_surface *surface, int32_t sx, int32_t sy) { struct weston_mode *mode = surface->output->current; - float x = (mode->width - surface->buffer->width) / 2; - float y = mode->height - surface->buffer->height; + int32_t width = weston_surface_buffer_width(surface); + int32_t height = weston_surface_buffer_height(surface); + float x = (mode->width - width) / 2; + float y = mode->height - height; /* Don't map the input panel here, wait for * show_input_panels signal. */ @@ -3225,8 +3232,7 @@ input_panel_configure(struct weston_surface *surface, int32_t sx, int32_t sy) weston_surface_configure(surface, surface->output->x + x, surface->output->y + y, - surface->buffer->width, - surface->buffer->height); + width, height); } static void