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.
This commit is contained in:
Ander Conselvan de Oliveira 2012-11-27 17:03:42 +02:00 committed by Kristian Høgsberg
parent 864c784b5c
commit 012b4c78c9
4 changed files with 156 additions and 21 deletions

View file

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

View file

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

View file

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

View file

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