compositor: Implement buffer transformation

Implement the wl_surface.set_buffer_transform request. This includes
tracking the double-buffered buffer transformation parameter and making
the gl renderer able to handle transformed buffers.
Ander Conselvan de Oliveira 12 years ago committed by Kristian Høgsberg
parent 864c784b5c
commit 012b4c78c9
  1. 73
      src/compositor.c
  2. 8
      src/compositor.h
  3. 62
      src/gl-renderer.c
  4. 34
      src/shell.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

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

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

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

Loading…
Cancel
Save