output->mode = &conn->connector->modes[0];
output->base = pepper_compositor_add_output(drm->compositor, &drm_output_backend,
- conn->name, output);
+ conn->name, output, WL_OUTPUT_TRANSFORM_NORMAL, 1);
PEPPER_CHECK(output->base, goto error, "pepper_compositor_add_output() failed.\n");
if (render_env && strcmp(render_env, "gl") == 0)
}
output->base = pepper_compositor_add_output(output->fbdev->compositor,
- &fbdev_output_backend, "fbdev", output);
+ &fbdev_output_backend, "fbdev", output,
+ WL_OUTPUT_TRANSFORM_NORMAL, 1);
if (!output->base)
{
PEPPER_ERROR("Failed to add output to compositor in %s\n", __FUNCTION__);
utils-log.c \
utils-vt.c \
subcompositor.c \
- subsurface.c
+ subsurface.c \
+ misc.c
--- /dev/null
+/*
+* Copyright © 2008-2012 Kristian Høgsberg
+* Copyright © 2010-2012 Intel Corporation
+* Copyright © 2011 Benjamin Franzke
+* Copyright © 2012 Collabora, Ltd.
+* Copyright © 2015 S-Core Corporation
+* Copyright © 2015-2016 Samsung Electronics co., Ltd. All Rights Reserved.
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice (including the next
+* paragraph) shall be included in all copies or substantial portions of the
+* Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+* DEALINGS IN THE SOFTWARE.
+*/
+
+#include "pepper-internal.h"
+
+void
+pepper_pixman_region_global_to_output(pixman_region32_t *region, pepper_output_t *output)
+{
+ pixman_box32_t *box, b;
+ int num_rects, i;
+ int32_t scale = output->scale;
+ int32_t w = output->geometry.w;
+ int32_t h = output->geometry.h;
+
+ /* Transform into output geometry origin. */
+ pixman_region32_translate(region, output->geometry.x, output->geometry.y);
+
+ if (output->geometry.transform == WL_OUTPUT_TRANSFORM_NORMAL && scale == 1)
+ return;
+
+ box = pixman_region32_rectangles(region, &num_rects);
+
+ switch (output->geometry.transform)
+ {
+ case WL_OUTPUT_TRANSFORM_NORMAL:
+ break;
+ case WL_OUTPUT_TRANSFORM_90:
+ for (i = 0; i < num_rects; i++)
+ {
+ b.x1 = h - box[i].y2;
+ b.y1 = box[i].x1;
+ b.x2 = h - box[i].y1;
+ b.y2 = box[i].x2;
+
+ box[i] = b;
+ }
+ break;
+ case WL_OUTPUT_TRANSFORM_180:
+ for (i = 0; i < num_rects; i++)
+ {
+ b.x1 = w - box[i].x2;
+ b.y1 = h - box[i].y2;
+ b.x2 = w - box[i].x1;
+ b.y2 = h - box[i].y1;
+
+ box[i] = b;
+ }
+ break;
+ case WL_OUTPUT_TRANSFORM_270:
+ for (i = 0; i < num_rects; i++)
+ {
+ b.x1 = box[i].y1;
+ b.y1 = w - box[i].x2;
+ b.x2 = box[i].y2;
+ b.y2 = w - box[i].x1;
+
+ box[i] = b;
+ }
+ break;
+ case WL_OUTPUT_TRANSFORM_FLIPPED:
+ for (i = 0; i < num_rects; i++)
+ {
+ b.x1 = w - box[i].x2;
+ b.y1 = box[i].y1;
+ b.x2 = w - box[i].x1;
+ b.y2 = box[i].y2;
+
+ box[i] = b;
+ }
+ break;
+ case WL_OUTPUT_TRANSFORM_FLIPPED_90:
+ for (i = 0; i < num_rects; i++)
+ {
+ b.x1 = h - box[i].y2;
+ b.y1 = w - box[i].x2;
+ b.x2 = h - box[i].y1;
+ b.y2 = w - box[i].x1;
+
+ box[i] = b;
+ }
+ break;
+ case WL_OUTPUT_TRANSFORM_FLIPPED_180:
+ for (i = 0; i < num_rects; i++)
+ {
+ b.x1 = box[i].x1;
+ b.y1 = h - box[i].y2;
+ b.x2 = box[i].x2;
+ b.y2 = h - box[i].y1;
+
+ box[i] = b;
+ }
+ break;
+ case WL_OUTPUT_TRANSFORM_FLIPPED_270:
+ for (i = 0; i < num_rects; i++)
+ {
+ b.x1 = box[i].y1;
+ b.y1 = box[i].x1;
+ b.x2 = box[i].y2;
+ b.y2 = box[i].x2;
+
+ box[i] = b;
+ }
+ break;
+ }
+
+ if (scale != 1)
+ {
+ for (i = 0; i < num_rects; i++)
+ {
+ box[i].x1 *= scale;
+ box[i].y1 *= scale;
+ box[i].x2 *= scale;
+ box[i].y2 *= scale;
+ }
+ }
+}
+
+/* Calculate a matrix which transforms vertices into the output local space,
+ * so that output backends can simply use the matrix to transform a view
+ * into the frame buffer space.
+ *
+ * view space -> global space -> output space
+ *
+ * global to output space.
+ *
+ * 1. Translate to output geometry origin. (denote T)
+ * 2. Apply output transform. (denote X)
+ * 3. Apply output scale. (denote S)
+ *
+ * P' = S * X * T * G * P
+ *
+ * Given a global matrix G, we should calculate matrix M where
+ * M = S * X * T * G
+ *
+ * S can be represented as a single scale term.
+ * X can be represented using 6 values (a, b, c, d, e, f) where
+ * x' = a * x + b * y + e;
+ * y' = c * x + b * y + f;
+ * T can be represented using 2 translation term (x, y)
+ */
+static inline void
+make_output_transform(pepper_mat4_t *mat,
+ double s, /* scale */
+ double a, double b, double c, double d, double e, double f, /* transform */
+ double x, double y /* translate */)
+{
+ double *m = &mat->m[0];
+
+ m[ 0] = s * a;
+ m[ 1] = s * c;
+ m[ 4] = s * b;
+ m[ 5] = s * d;
+ m[12] = s * (a * x + b * y + e);
+ m[13] = s * (c * x + d * y + f);
+
+ if (s != 1.0)
+ mat->flags |= PEPPER_MATRIX_SCALE;
+
+ if (x != 0.0 || y != 0.0)
+ mat->flags |= PEPPER_MATRIX_TRANSLATE;
+
+ if (a != 1.0 || d != 1.0)
+ mat->flags |= PEPPER_MATRIX_ROTATE;
+}
+
+void
+pepper_transform_global_to_output(pepper_mat4_t *transform, pepper_output_t *output)
+{
+ pepper_mat4_t mat;
+ double x = output->geometry.x;
+ double y = output->geometry.y;
+ double w = output->geometry.w;
+ double h = output->geometry.h;
+
+ pepper_mat4_init_identity(&mat);
+
+ switch (output->geometry.transform)
+ {
+ default:
+ case WL_OUTPUT_TRANSFORM_NORMAL:
+ make_output_transform(&mat, (double)output->scale, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, x, y);
+ break;
+ case WL_OUTPUT_TRANSFORM_FLIPPED:
+ make_output_transform(&mat, (double)output->scale, -1.0, 0.0, 0.0, 1.0, w, 0.0, x, y);
+ break;
+ case WL_OUTPUT_TRANSFORM_90:
+ make_output_transform(&mat, (double)output->scale, 0.0, -1.0, 1.0, 0.0, h, 0.0, x, y);
+ break;
+ case WL_OUTPUT_TRANSFORM_FLIPPED_90:
+ make_output_transform(&mat, (double)output->scale, 0.0, -1.0, -1.0, 0.0, h, w, x, y);
+ break;
+ case WL_OUTPUT_TRANSFORM_180:
+ make_output_transform(&mat, (double)output->scale, -1.0, 0.0, 0.0, -1.0, w, h, x, y);
+ break;
+ case WL_OUTPUT_TRANSFORM_FLIPPED_180:
+ make_output_transform(&mat, (double)output->scale, 1.0, 0.0, 0.0, -1.0, 0.0, h, x, y);
+ break;
+ case WL_OUTPUT_TRANSFORM_270:
+ make_output_transform(&mat, (double)output->scale, 0.0, 1.0, -1.0, 0.0, 0.0, w, x, y);
+ break;
+ case WL_OUTPUT_TRANSFORM_FLIPPED_270:
+ make_output_transform(&mat, (double)output->scale, 0.0, 1.0, 1.0, 0.0, 0.0, 0.0, x, y);
+ break;
+ }
+
+ pepper_mat4_multiply(transform, &mat, transform);
+}
}
static void
-output_accumulate_damage(pepper_output_t *output)
+output_update_planes(pepper_output_t *output)
{
pepper_plane_t *plane;
pixman_region32_t clip;
pixman_region32_init(&clip);
pepper_list_for_each_reverse(plane, &output->plane_list, link)
- pepper_plane_accumulate_damage(plane, &clip);
+ pepper_plane_update(plane, &output->view_list, &clip);
pixman_region32_fini(&clip);
}
output_repaint(pepper_output_t *output)
{
pepper_view_t *view;
- pepper_plane_t *plane;
pepper_list_for_each(view, &output->compositor->view_list, compositor_link)
pepper_view_update(view);
}
output->backend->assign_planes(output->data, &output->view_list);
-
- pepper_list_for_each(plane, &output->plane_list, link)
- pepper_plane_update(plane, &output->view_list);
-
- output_accumulate_damage(output);
+ output_update_planes(output);
output->backend->repaint(output->data, &output->plane_list);
output->frame.pending = PEPPER_TRUE;
PEPPER_API pepper_output_t *
pepper_compositor_add_output(pepper_compositor_t *compositor,
- const pepper_output_backend_t *backend, const char *name, void *data)
+ const pepper_output_backend_t *backend, const char *name, void *data,
+ int transform, int scale)
{
pepper_output_t *output;
uint32_t id;
/* Initialize output modes. */
output_update_mode(output);
- /* TODO: Set scale value according to the config or something. */
- output->scale = 1;
-
- /* Initialize geometry. TODO: Calculate position and size of the output. */
- output->geometry.transform = WL_OUTPUT_TRANSFORM_NORMAL;
+ /* Initialize geometry. */
+ output->geometry.transform = transform;
+ output->scale = scale;
output->geometry.subpixel = backend->get_subpixel_order(data);
output->geometry.maker = backend->get_maker_name(data);
output->geometry.model = backend->get_model_name(data);
output->geometry.x = 0;
output->geometry.y = 0;
- output->geometry.w = output->current_mode.w;
- output->geometry.h = output->current_mode.h;
+
+ switch (transform)
+ {
+ case WL_OUTPUT_TRANSFORM_90:
+ case WL_OUTPUT_TRANSFORM_FLIPPED_90:
+ case WL_OUTPUT_TRANSFORM_270:
+ case WL_OUTPUT_TRANSFORM_FLIPPED_270:
+ output->geometry.w = output->current_mode.h / scale;
+ output->geometry.h = output->current_mode.w / scale;
+ break;
+ default:
+ output->geometry.w = output->current_mode.w / scale;
+ output->geometry.h = output->current_mode.h / scale;
+ break;
+ }
pepper_list_insert(&compositor->output_list, &output->link);
pepper_list_init(&output->plane_list);
pepper_plane_t *plane;
pepper_bool_t need_damage;
+ pepper_bool_t need_transform_update;
pepper_list_t link;
};
pepper_plane_add_damage_region(pepper_plane_t *plane, pixman_region32_t *region);
void
-pepper_plane_accumulate_damage(pepper_plane_t *plane, pixman_region32_t *clip);
+pepper_plane_update(pepper_plane_t *plane, const pepper_list_t *view_list, pixman_region32_t *clip);
void
-pepper_plane_update(pepper_plane_t *plane, const pepper_list_t *view_list);
+pepper_surface_flush_damage(pepper_surface_t *surface);
+/* Misc. */
void
-pepper_surface_flush_damage(pepper_surface_t *surface);
+pepper_pixman_region_global_to_output(pixman_region32_t *region, pepper_output_t *output);
+
+void
+pepper_transform_global_to_output(pepper_mat4_t *transform, pepper_output_t *output);
#endif /* PEPPER_INTERNAL_H */
PEPPER_API pepper_output_t *
pepper_compositor_add_output(pepper_compositor_t *compositor,
- const pepper_output_backend_t *backend, const char *name, void *data);
+ const pepper_output_backend_t *backend, const char *name, void *data,
+ int transform, int scale);
struct pepper_render_item
{
#include "pepper-internal.h"
void
-pepper_plane_update(pepper_plane_t *plane, const pepper_list_t *view_list)
+pepper_plane_update(pepper_plane_t *plane, const pepper_list_t *view_list, pixman_region32_t *clip)
{
- pepper_view_t *view;
- double output_x = plane->output->geometry.x;
- double output_y = plane->output->geometry.y;
+ int x = plane->output->geometry.x;
+ int y = plane->output->geometry.y;
+ int w = plane->output->geometry.w;
+ int h = plane->output->geometry.h;
+ pixman_region32_t plane_clip;
+ pepper_view_t *view;
+ pixman_region32_init(&plane_clip);
pepper_list_init(&plane->entry_list);
pepper_list_for_each(view, view_list, link)
{
- pepper_plane_entry_t *entry = &view->plane_entries[plane->output->id];
+ pepper_plane_entry_t *entry = &view->plane_entries[plane->output->id];
if (entry->plane == plane)
{
pepper_list_insert(plane->entry_list.prev, &entry->link);
- /* Calculate view transform on output local coordinate space. */
- pepper_mat4_init_translate(&entry->base.transform, -output_x, -output_y, 0.0);
- pepper_mat4_multiply(&entry->base.transform,
- &entry->base.transform, &view->global_transform);
- }
- }
-}
-
-void
-pepper_plane_accumulate_damage(pepper_plane_t *plane, pixman_region32_t *clip)
-{
- int x = plane->output->geometry.x;
- int y = plane->output->geometry.y;
- int w = plane->output->geometry.w;
- int h = plane->output->geometry.h;
- pepper_plane_entry_t *entry;
- pixman_region32_t plane_clip;
-
- pixman_region32_init(&plane_clip);
-
- pepper_list_for_each(entry, &plane->entry_list, link)
- {
- pepper_view_t *view = (pepper_view_t *)entry->base.view;
-
- pixman_region32_subtract(&entry->base.visible_region, &view->bounding_region, &plane_clip);
- pixman_region32_translate(&entry->base.visible_region, -x, -y);
- pixman_region32_intersect_rect(&entry->base.visible_region,
- &entry->base.visible_region, 0, 0, w, h);
-
- /* Accumulate opaque region of this plane on plane_clip. */
- pixman_region32_union(&plane_clip, &plane_clip, &view->opaque_region);
-
- if (entry->need_damage)
- {
- pepper_plane_add_damage_region(plane, &entry->base.visible_region);
- entry->need_damage = PEPPER_FALSE;
+ if (entry->need_transform_update)
+ {
+ entry->base.transform = view->global_transform;
+ pepper_transform_global_to_output(&entry->base.transform, plane->output);
+ entry->need_transform_update = PEPPER_FALSE;
+ }
+
+ /* Calculate visible region (output space). */
+ pixman_region32_subtract(&entry->base.visible_region,
+ &view->bounding_region, &plane_clip);
+ pixman_region32_intersect_rect(&entry->base.visible_region,
+ &entry->base.visible_region, x, y, w, h);
+ pepper_pixman_region_global_to_output(&entry->base.visible_region, plane->output);
+
+ /* Accumulate opaque region of this view (global space). */
+ pixman_region32_union(&plane_clip, &plane_clip, &view->opaque_region);
+
+ /* Add damage for the new visible region. */
+ if (entry->need_damage)
+ {
+ pepper_plane_add_damage_region(plane, &entry->base.visible_region);
+ entry->need_damage = PEPPER_FALSE;
+ }
+
+ /* Flush surface damage. (eg. texture upload) */
+ if (view->surface)
+ pepper_surface_flush_damage(view->surface);
}
-
- if (view->surface)
- pepper_surface_flush_damage(view->surface);
}
- /* Transform plane_clip to output local coordinate space. */
- pixman_region32_translate(&plane_clip, -x, -y);
- pixman_region32_intersect_rect(&plane_clip, &plane_clip, 0, 0, w, h);
-
- /* Copy accumulated clip region obsecured by opaque regions of views in front of this plane. */
+ /* Copy clip region of this plane. */
pixman_region32_copy(&plane->clip_region, clip);
- /* Accumulate clip region for the below plane. */
+ /* Accumulate clip region obsecured by this plane. */
+ pepper_pixman_region_global_to_output(&plane_clip, plane->output);
pixman_region32_union(clip, clip, &plane_clip);
pixman_region32_fini(&plane_clip);
}
void
pepper_view_mark_dirty(pepper_view_t *view, uint32_t flag)
{
- pepper_view_t *child;
+ pepper_view_t *child;
+ int i;
if (view->dirty & flag)
return;
{
pepper_list_for_each(child, &view->children_list, parent_link)
pepper_view_mark_dirty(child, PEPPER_VIEW_GEOMETRY_DIRTY);
+
+ for (i = 0; i < PEPPER_MAX_OUTPUT_COUNT; i++)
+ view->plane_entries[i].need_transform_update = PEPPER_TRUE;
}
/* Mark entire subtree's active as dirty. */
}
else
{
- pepper_mat4_inverse(&node->transform, &node->transform); /* FIXME */
pixman_transform_from_pepper_mat4(&trans, &node->transform);
+ pixman_transform_invert(&trans, &trans);
filter = PIXMAN_FILTER_BILINEAR;
}
/* Add compositor base class output object for this output. */
output->base = pepper_compositor_add_output(conn->pepper, &wayland_output_backend,
- output->name, output);
+ output->name, output, WL_OUTPUT_TRANSFORM_NORMAL, 1);
if (!output->base)
{
wayland_output_destroy(output);
pepper_x11_destroy(pepper_x11_connection_t *conn);
PEPPER_API pepper_output_t *
-pepper_x11_output_create(pepper_x11_connection_t *connection, int32_t w, int32_t h,
+pepper_x11_output_create(pepper_x11_connection_t *connection,
+ int x, int y, int w, int h, int transform, int scale,
const char *renderer);
PEPPER_API pepper_bool_t
int32_t x, y;
int32_t w, h;
uint32_t subpixel;
- uint32_t scale;
uint8_t depth;
uint8_t bpp;
/* set hints for window */
memset(&hints, 0, sizeof(hints));
hints.flags = WM_NORMAL_HINTS_MAX_SIZE | WM_NORMAL_HINTS_MIN_SIZE;
- hints.min_width = hints.max_width = output->w*output->scale;
- hints.min_height = hints.max_height = output->h*output->scale;
+ hints.min_width = hints.max_width = output->w;
+ hints.min_height = hints.max_height = output->h;
xcb_change_property(conn,
XCB_PROP_MODE_REPLACE,
output->window,
cookie = xcb_shm_put_image_checked(output->connection->xcb_connection,
output->window,
output->gc,
- output->w * output->scale, /* total_width */
- output->h * output->scale, /* total_height */
+ output->w,
+ output->h,
0, /* src_x */
0, /* src_y */
output->shm.w, /* src_w */
PEPPER_API pepper_output_t *
pepper_x11_output_create(pepper_x11_connection_t *connection,
- int32_t w,
- int32_t h,
+ int w, int h, int transform, int scale,
const char *renderer)
{
static const char *window_name = "PePPer Compositor";
/* Hard-Coded: subpixel order to horizontal RGB. */
output->subpixel = WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
- /* Hard-Coded: scale value to 1. */
- output->scale = 1;
-
/* Create X11 window */
{
uint32_t mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
XCB_COPY_FROM_PARENT,
output->window,
connection->screen->root,
- 0, /* X position of top-left corner of window */
- 0, /* Y position of top-left corner of window */
- w*output->scale,
- h*output->scale,
- 0, /* width of windows' border */
+ 0, 0, w, h, 0,
XCB_WINDOW_CLASS_INPUT_OUTPUT,
connection->screen->root_visual,
mask,
/* cannot resize */
memset(&hints, 0, sizeof(hints));
hints.flags = WM_NORMAL_HINTS_MAX_SIZE | WM_NORMAL_HINTS_MIN_SIZE;
- hints.min_width = hints.max_width = w*output->scale;
- hints.min_height = hints.max_height = h*output->scale;
+ hints.min_width = hints.max_width = w;
+ hints.min_height = hints.max_height = h;
xcb_change_property(connection->xcb_connection,
XCB_PROP_MODE_REPLACE,
output->window,
/* Register output object */
snprintf(&output->name[0], 32, "x11-%p", output);
base = pepper_compositor_add_output(connection->compositor,
- &x11_output_backend, output->name, output);
+ &x11_output_backend, output->name, output,
+ transform, scale);
if (!base)
{
PEPPER_ERROR("pepper_compositor_add_output failed\n");
conn = pepper_x11_connect(compositor, NULL);
PEPPER_ASSERT(conn);
- output = pepper_x11_output_create(conn, 1024, 768, renderer);
+ output = pepper_x11_output_create(conn, 0, 0, 1024, 768,
+ WL_OUTPUT_TRANSFORM_90, 1, renderer);
PEPPER_ASSERT(output);
if (!pepper_x11_input_create(conn))