blob: c7f3a9f33afc352b41f0307f5dcf547b5a1d0db4 [file] [log] [blame]
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +03001/*
2 * Copyright © 2012 Intel Corporation
3 * Copyright © 2013 Vasily Khoruzhick <anarsoul@gmail.com>
Pekka Paalanen6764bbe2015-02-11 12:29:56 +02004 * Copyright © 2015 Collabora, Ltd.
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +03005 *
6 * Permission to use, copy, modify, distribute, and sell this software and
7 * its documentation for any purpose is hereby granted without fee, provided
8 * that the above copyright notice appear in all copies and that both that
9 * copyright notice and this permission notice appear in supporting
10 * documentation, and that the name of the copyright holders not be used in
11 * advertising or publicity pertaining to distribution of the software
12 * without specific, written prior permission. The copyright holders make
13 * no representations about the suitability of this software for any
14 * purpose. It is provided "as is" without express or implied warranty.
15 *
16 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
17 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
18 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
19 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
20 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
21 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
22 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 */
24
Daniel Stonec228e232013-05-22 18:03:19 +030025#include "config.h"
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030026
27#include <errno.h>
28#include <stdlib.h>
29
30#include "pixman-renderer.h"
31
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +020032#include <linux/input.h>
33
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030034struct pixman_output_state {
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +020035 void *shadow_buffer;
36 pixman_image_t *shadow_image;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030037 pixman_image_t *hw_buffer;
38};
39
40struct pixman_surface_state {
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +030041 struct weston_surface *surface;
42
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030043 pixman_image_t *image;
44 struct weston_buffer_reference buffer_ref;
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +030045
Lubomir Rintelddc2b1e2013-12-12 12:57:56 +010046 struct wl_listener buffer_destroy_listener;
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +030047 struct wl_listener surface_destroy_listener;
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +030048 struct wl_listener renderer_destroy_listener;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030049};
50
51struct pixman_renderer {
52 struct weston_renderer base;
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +030053
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +020054 int repaint_debug;
55 pixman_image_t *debug_color;
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +030056 struct weston_binding *debug_binding;
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +030057
58 struct wl_signal destroy_signal;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030059};
60
61static inline struct pixman_output_state *
62get_output_state(struct weston_output *output)
63{
64 return (struct pixman_output_state *)output->renderer_state;
65}
66
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +030067static int
68pixman_renderer_create_surface(struct weston_surface *surface);
69
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030070static inline struct pixman_surface_state *
71get_surface_state(struct weston_surface *surface)
72{
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +030073 if (!surface->renderer_state)
74 pixman_renderer_create_surface(surface);
75
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030076 return (struct pixman_surface_state *)surface->renderer_state;
77}
78
79static inline struct pixman_renderer *
80get_renderer(struct weston_compositor *ec)
81{
82 return (struct pixman_renderer *)ec->renderer;
83}
84
85static int
86pixman_renderer_read_pixels(struct weston_output *output,
87 pixman_format_code_t format, void *pixels,
88 uint32_t x, uint32_t y,
89 uint32_t width, uint32_t height)
90{
91 struct pixman_output_state *po = get_output_state(output);
Alexander Larsson97af7922013-05-29 12:01:33 +020092 pixman_transform_t transform;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030093 pixman_image_t *out_buf;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030094
95 if (!po->hw_buffer) {
96 errno = ENODEV;
97 return -1;
98 }
99
100 out_buf = pixman_image_create_bits(format,
101 width,
102 height,
103 pixels,
104 (PIXMAN_FORMAT_BPP(format) / 8) * width);
105
Alexander Larsson97af7922013-05-29 12:01:33 +0200106 /* Caller expects vflipped source image */
107 pixman_transform_init_translate(&transform,
108 pixman_int_to_fixed (x),
109 pixman_int_to_fixed (y - pixman_image_get_height (po->hw_buffer)));
110 pixman_transform_scale(&transform, NULL,
111 pixman_fixed_1,
112 pixman_fixed_minus_1);
113 pixman_image_set_transform(po->hw_buffer, &transform);
114
115 pixman_image_composite32(PIXMAN_OP_SRC,
116 po->hw_buffer, /* src */
117 NULL /* mask */,
118 out_buf, /* dest */
119 0, 0, /* src_x, src_y */
120 0, 0, /* mask_x, mask_y */
121 0, 0, /* dest_x, dest_y */
122 pixman_image_get_width (po->hw_buffer), /* width */
123 pixman_image_get_height (po->hw_buffer) /* height */);
124 pixman_image_set_transform(po->hw_buffer, NULL);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300125
126 pixman_image_unref(out_buf);
127
128 return 0;
129}
130
Vasily Khoruzhick031fc872013-01-29 14:58:14 +0300131static void
Alexander Larsson1f206b42013-05-22 14:41:36 +0200132region_global_to_output(struct weston_output *output, pixman_region32_t *region)
133{
134 pixman_region32_translate(region, -output->x, -output->y);
Jason Ekstrand33ff6362013-10-27 22:25:01 -0500135 weston_transformed_region(output->width, output->height,
136 output->transform, output->current_scale,
137 region, region);
Vasily Khoruzhick031fc872013-01-29 14:58:14 +0300138}
139
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300140#define D2F(v) pixman_double_to_fixed((double)v)
141
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300142static void
Jason Ekstrand8870a232014-05-20 15:53:19 -0500143weston_matrix_to_pixman_transform(pixman_transform_t *pt,
144 const struct weston_matrix *wm)
Pekka Paalanen0b4c5352014-03-14 14:38:17 +0200145{
Jason Ekstrand8870a232014-05-20 15:53:19 -0500146 /* Pixman supports only 2D transform matrix, but Weston uses 3D, *
147 * so we're omitting Z coordinate here. */
148 pt->matrix[0][0] = pixman_double_to_fixed(wm->d[0]);
149 pt->matrix[0][1] = pixman_double_to_fixed(wm->d[4]);
150 pt->matrix[0][2] = pixman_double_to_fixed(wm->d[12]);
151 pt->matrix[1][0] = pixman_double_to_fixed(wm->d[1]);
152 pt->matrix[1][1] = pixman_double_to_fixed(wm->d[5]);
153 pt->matrix[1][2] = pixman_double_to_fixed(wm->d[13]);
154 pt->matrix[2][0] = pixman_double_to_fixed(wm->d[3]);
155 pt->matrix[2][1] = pixman_double_to_fixed(wm->d[7]);
156 pt->matrix[2][2] = pixman_double_to_fixed(wm->d[15]);
Pekka Paalanen0b4c5352014-03-14 14:38:17 +0200157}
158
159static void
Jason Ekstranda7af7042013-10-12 22:38:11 -0500160repaint_region(struct weston_view *ev, struct weston_output *output,
Alexander Larsson1f206b42013-05-22 14:41:36 +0200161 pixman_region32_t *region, pixman_region32_t *surf_region,
162 pixman_op_t pixman_op)
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300163{
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200164 struct pixman_renderer *pr =
165 (struct pixman_renderer *) output->compositor->renderer;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500166 struct pixman_surface_state *ps = get_surface_state(ev->surface);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300167 struct pixman_output_state *po = get_output_state(output);
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200168 struct weston_buffer_viewport *vp = &ev->surface->buffer_viewport;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300169 pixman_region32_t final_region;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500170 float view_x, view_y;
Alexander Larsson1f206b42013-05-22 14:41:36 +0200171 pixman_transform_t transform;
Jason Ekstrand8870a232014-05-20 15:53:19 -0500172 struct weston_matrix matrix;
Manuel Bachmann9c4ab662014-04-07 11:58:45 +0200173 pixman_image_t *mask_image;
174 pixman_color_t mask = { 0, };
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300175
176 /* The final region to be painted is the intersection of
177 * 'region' and 'surf_region'. However, 'region' is in the global
178 * coordinates, and 'surf_region' is in the surface-local
179 * coordinates
180 */
181 pixman_region32_init(&final_region);
Alexander Larsson1f206b42013-05-22 14:41:36 +0200182 if (surf_region) {
183 pixman_region32_copy(&final_region, surf_region);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300184
Alexander Larsson1f206b42013-05-22 14:41:36 +0200185 /* Convert from surface to global coordinates */
Jason Ekstranda7af7042013-10-12 22:38:11 -0500186 if (!ev->transform.enabled) {
187 pixman_region32_translate(&final_region, ev->geometry.x, ev->geometry.y);
Alexander Larsson1f206b42013-05-22 14:41:36 +0200188 } else {
Jason Ekstranda7af7042013-10-12 22:38:11 -0500189 weston_view_to_global_float(ev, 0, 0, &view_x, &view_y);
190 pixman_region32_translate(&final_region, (int)view_x, (int)view_y);
Alexander Larsson1f206b42013-05-22 14:41:36 +0200191 }
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300192
Alexander Larsson1f206b42013-05-22 14:41:36 +0200193 /* We need to paint the intersection */
194 pixman_region32_intersect(&final_region, &final_region, region);
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300195 } else {
Alexander Larsson1f206b42013-05-22 14:41:36 +0200196 /* If there is no surface region, just use the global region */
197 pixman_region32_copy(&final_region, region);
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300198 }
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300199
Alexander Larsson1f206b42013-05-22 14:41:36 +0200200 /* Convert from global to output coord */
201 region_global_to_output(output, &final_region);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300202
Alexander Larsson1f206b42013-05-22 14:41:36 +0200203 /* And clip to it */
204 pixman_image_set_clip_region32 (po->shadow_image, &final_region);
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200205
Alexander Larsson1f206b42013-05-22 14:41:36 +0200206 /* Set up the source transformation based on the surface
Alexander Larsson4ea95522013-05-22 14:41:37 +0200207 position, the output position/transform/scale and the client
208 specified buffer transform/scale */
Jason Ekstrand8870a232014-05-20 15:53:19 -0500209 weston_matrix_invert(&matrix, &output->matrix);
Alexander Larsson1f206b42013-05-22 14:41:36 +0200210
Jason Ekstranda7af7042013-10-12 22:38:11 -0500211 if (ev->transform.enabled) {
Jason Ekstrand8870a232014-05-20 15:53:19 -0500212 weston_matrix_multiply(&matrix, &ev->transform.inverse);
Alexander Larsson1f206b42013-05-22 14:41:36 +0200213 } else {
Jason Ekstrand8870a232014-05-20 15:53:19 -0500214 weston_matrix_translate(&matrix,
215 -ev->geometry.x, -ev->geometry.y, 0);
Alexander Larsson1f206b42013-05-22 14:41:36 +0200216 }
217
Jason Ekstrand8870a232014-05-20 15:53:19 -0500218 weston_matrix_multiply(&matrix, &ev->surface->surface_to_buffer_matrix);
Jonny Lambfa1b3052013-11-26 18:19:47 +0100219
Jason Ekstrand8870a232014-05-20 15:53:19 -0500220 weston_matrix_to_pixman_transform(&transform, &matrix);
Alexander Larsson1f206b42013-05-22 14:41:36 +0200221 pixman_image_set_transform(ps->image, &transform);
222
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200223 if (ev->transform.enabled || output->current_scale != vp->buffer.scale)
Alexander Larsson1f206b42013-05-22 14:41:36 +0200224 pixman_image_set_filter(ps->image, PIXMAN_FILTER_BILINEAR, NULL, 0);
225 else
226 pixman_image_set_filter(ps->image, PIXMAN_FILTER_NEAREST, NULL, 0);
227
Neil Robertse5051712013-11-13 15:44:06 +0000228 if (ps->buffer_ref.buffer)
229 wl_shm_buffer_begin_access(ps->buffer_ref.buffer->shm_buffer);
230
Manuel Bachmannb1fff412014-04-05 05:31:37 +0200231 if (ev->alpha < 1.0) {
Manuel Bachmann9c4ab662014-04-07 11:58:45 +0200232 mask.alpha = 0xffff * ev->alpha;
Manuel Bachmannb1fff412014-04-05 05:31:37 +0200233 mask_image = pixman_image_create_solid_fill(&mask);
Manuel Bachmann9c4ab662014-04-07 11:58:45 +0200234 } else {
Manuel Bachmannb1fff412014-04-05 05:31:37 +0200235 mask_image = NULL;
Manuel Bachmann9c4ab662014-04-07 11:58:45 +0200236 }
Manuel Bachmannb1fff412014-04-05 05:31:37 +0200237
Alexander Larsson1f206b42013-05-22 14:41:36 +0200238 pixman_image_composite32(pixman_op,
239 ps->image, /* src */
Manuel Bachmannb1fff412014-04-05 05:31:37 +0200240 mask_image, /* mask */
Alexander Larsson1f206b42013-05-22 14:41:36 +0200241 po->shadow_image, /* dest */
242 0, 0, /* src_x, src_y */
243 0, 0, /* mask_x, mask_y */
244 0, 0, /* dest_x, dest_y */
245 pixman_image_get_width (po->shadow_image), /* width */
246 pixman_image_get_height (po->shadow_image) /* height */);
247
Manuel Bachmann9c4ab662014-04-07 11:58:45 +0200248 if (mask_image)
249 pixman_image_unref(mask_image);
250
Neil Robertse5051712013-11-13 15:44:06 +0000251 if (ps->buffer_ref.buffer)
252 wl_shm_buffer_end_access(ps->buffer_ref.buffer->shm_buffer);
253
Alexander Larsson1f206b42013-05-22 14:41:36 +0200254 if (pr->repaint_debug)
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200255 pixman_image_composite32(PIXMAN_OP_OVER,
Alexander Larsson1f206b42013-05-22 14:41:36 +0200256 pr->debug_color, /* src */
257 NULL /* mask */,
258 po->shadow_image, /* dest */
259 0, 0, /* src_x, src_y */
260 0, 0, /* mask_x, mask_y */
261 0, 0, /* dest_x, dest_y */
262 pixman_image_get_width (po->shadow_image), /* width */
263 pixman_image_get_height (po->shadow_image) /* height */);
264
265 pixman_image_set_clip_region32 (po->shadow_image, NULL);
266
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300267 pixman_region32_fini(&final_region);
268}
269
270static void
Jason Ekstranda7af7042013-10-12 22:38:11 -0500271draw_view(struct weston_view *ev, struct weston_output *output,
272 pixman_region32_t *damage) /* in global coordinates */
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300273{
Derek Foreman66951b72014-09-01 10:33:28 -0500274 static int zoom_logged = 0;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500275 struct pixman_surface_state *ps = get_surface_state(ev->surface);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300276 /* repaint bounding region in global coordinates: */
277 pixman_region32_t repaint;
278 /* non-opaque region in surface coordinates: */
279 pixman_region32_t surface_blend;
280
281 /* No buffer attached */
282 if (!ps->image)
283 return;
284
285 pixman_region32_init(&repaint);
286 pixman_region32_intersect(&repaint,
Pekka Paalanen25c0ca52015-02-19 11:15:33 +0200287 &ev->transform.boundingbox, damage);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500288 pixman_region32_subtract(&repaint, &repaint, &ev->clip);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300289
290 if (!pixman_region32_not_empty(&repaint))
291 goto out;
292
Derek Foreman66951b72014-09-01 10:33:28 -0500293 if (output->zoom.active && !zoom_logged) {
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300294 weston_log("pixman renderer does not support zoom\n");
Derek Foreman66951b72014-09-01 10:33:28 -0500295 zoom_logged = 1;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300296 }
297
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300298 /* TODO: Implement repaint_region_complex() using pixman_composite_trapezoids() */
Manuel Bachmann9c4ab662014-04-07 11:58:45 +0200299 if (ev->alpha != 1.0 ||
300 (ev->transform.enabled &&
301 ev->transform.matrix.type != WESTON_MATRIX_TRANSFORM_TRANSLATE)) {
Jason Ekstranda7af7042013-10-12 22:38:11 -0500302 repaint_region(ev, output, &repaint, NULL, PIXMAN_OP_OVER);
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300303 } else {
304 /* blended region is whole surface minus opaque region: */
305 pixman_region32_init_rect(&surface_blend, 0, 0,
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600306 ev->surface->width, ev->surface->height);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500307 pixman_region32_subtract(&surface_blend, &surface_blend, &ev->surface->opaque);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300308
Jason Ekstranda7af7042013-10-12 22:38:11 -0500309 if (pixman_region32_not_empty(&ev->surface->opaque)) {
310 repaint_region(ev, output, &repaint, &ev->surface->opaque, PIXMAN_OP_SRC);
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300311 }
312
313 if (pixman_region32_not_empty(&surface_blend)) {
Jason Ekstranda7af7042013-10-12 22:38:11 -0500314 repaint_region(ev, output, &repaint, &surface_blend, PIXMAN_OP_OVER);
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300315 }
316 pixman_region32_fini(&surface_blend);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300317 }
318
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300319
320out:
321 pixman_region32_fini(&repaint);
322}
323static void
324repaint_surfaces(struct weston_output *output, pixman_region32_t *damage)
325{
326 struct weston_compositor *compositor = output->compositor;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500327 struct weston_view *view;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300328
Jason Ekstranda7af7042013-10-12 22:38:11 -0500329 wl_list_for_each_reverse(view, &compositor->view_list, link)
330 if (view->plane == &compositor->primary_plane)
331 draw_view(view, output, damage);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300332}
333
334static void
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200335copy_to_hw_buffer(struct weston_output *output, pixman_region32_t *region)
336{
337 struct pixman_output_state *po = get_output_state(output);
Alexander Larsson1f206b42013-05-22 14:41:36 +0200338 pixman_region32_t output_region;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200339
Alexander Larsson1f206b42013-05-22 14:41:36 +0200340 pixman_region32_init(&output_region);
341 pixman_region32_copy(&output_region, region);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200342
Alexander Larsson1f206b42013-05-22 14:41:36 +0200343 region_global_to_output(output, &output_region);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200344
Alexander Larsson1f206b42013-05-22 14:41:36 +0200345 pixman_image_set_clip_region32 (po->hw_buffer, &output_region);
Ryo Munakata389d2052014-09-04 01:56:53 +0900346 pixman_region32_fini(&output_region);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200347
Alexander Larsson1f206b42013-05-22 14:41:36 +0200348 pixman_image_composite32(PIXMAN_OP_SRC,
349 po->shadow_image, /* src */
350 NULL /* mask */,
351 po->hw_buffer, /* dest */
352 0, 0, /* src_x, src_y */
353 0, 0, /* mask_x, mask_y */
354 0, 0, /* dest_x, dest_y */
355 pixman_image_get_width (po->hw_buffer), /* width */
356 pixman_image_get_height (po->hw_buffer) /* height */);
357
358 pixman_image_set_clip_region32 (po->hw_buffer, NULL);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200359}
360
361static void
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300362pixman_renderer_repaint_output(struct weston_output *output,
363 pixman_region32_t *output_damage)
364{
365 struct pixman_output_state *po = get_output_state(output);
366
367 if (!po->hw_buffer)
368 return;
369
370 repaint_surfaces(output, output_damage);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200371 copy_to_hw_buffer(output, output_damage);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300372
373 pixman_region32_copy(&output->previous_damage, output_damage);
374 wl_signal_emit(&output->frame_signal, output);
375
376 /* Actual flip should be done by caller */
377}
378
379static void
380pixman_renderer_flush_damage(struct weston_surface *surface)
381{
382 /* No-op for pixman renderer */
383}
384
385static void
Lubomir Rintelddc2b1e2013-12-12 12:57:56 +0100386buffer_state_handle_buffer_destroy(struct wl_listener *listener, void *data)
387{
388 struct pixman_surface_state *ps;
389
390 ps = container_of(listener, struct pixman_surface_state,
391 buffer_destroy_listener);
392
393 if (ps->image) {
394 pixman_image_unref(ps->image);
395 ps->image = NULL;
396 }
397
398 ps->buffer_destroy_listener.notify = NULL;
399}
400
401static void
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500402pixman_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300403{
404 struct pixman_surface_state *ps = get_surface_state(es);
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500405 struct wl_shm_buffer *shm_buffer;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300406 pixman_format_code_t pixman_format;
407
408 weston_buffer_reference(&ps->buffer_ref, buffer);
409
Lubomir Rintelddc2b1e2013-12-12 12:57:56 +0100410 if (ps->buffer_destroy_listener.notify) {
411 wl_list_remove(&ps->buffer_destroy_listener.link);
412 ps->buffer_destroy_listener.notify = NULL;
413 }
414
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300415 if (ps->image) {
416 pixman_image_unref(ps->image);
417 ps->image = NULL;
418 }
419
420 if (!buffer)
421 return;
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500422
423 shm_buffer = wl_shm_buffer_get(buffer->resource);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300424
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500425 if (! shm_buffer) {
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300426 weston_log("Pixman renderer supports only SHM buffers\n");
427 weston_buffer_reference(&ps->buffer_ref, NULL);
428 return;
429 }
430
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500431 switch (wl_shm_buffer_get_format(shm_buffer)) {
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300432 case WL_SHM_FORMAT_XRGB8888:
433 pixman_format = PIXMAN_x8r8g8b8;
434 break;
435 case WL_SHM_FORMAT_ARGB8888:
436 pixman_format = PIXMAN_a8r8g8b8;
437 break;
Tomeu Vizoso1c1fc292013-08-06 20:05:56 +0200438 case WL_SHM_FORMAT_RGB565:
439 pixman_format = PIXMAN_r5g6b5;
440 break;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300441 default:
442 weston_log("Unsupported SHM buffer format\n");
443 weston_buffer_reference(&ps->buffer_ref, NULL);
444 return;
445 break;
446 }
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500447
448 buffer->shm_buffer = shm_buffer;
449 buffer->width = wl_shm_buffer_get_width(shm_buffer);
450 buffer->height = wl_shm_buffer_get_height(shm_buffer);
451
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300452 ps->image = pixman_image_create_bits(pixman_format,
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500453 buffer->width, buffer->height,
454 wl_shm_buffer_get_data(shm_buffer),
455 wl_shm_buffer_get_stride(shm_buffer));
Lubomir Rintelddc2b1e2013-12-12 12:57:56 +0100456
457 ps->buffer_destroy_listener.notify =
458 buffer_state_handle_buffer_destroy;
459 wl_signal_add(&buffer->destroy_signal,
460 &ps->buffer_destroy_listener);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300461}
462
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300463static void
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300464pixman_renderer_surface_state_destroy(struct pixman_surface_state *ps)
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300465{
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300466 wl_list_remove(&ps->surface_destroy_listener.link);
467 wl_list_remove(&ps->renderer_destroy_listener.link);
Lubomir Rintelddc2b1e2013-12-12 12:57:56 +0100468 if (ps->buffer_destroy_listener.notify) {
469 wl_list_remove(&ps->buffer_destroy_listener.link);
470 ps->buffer_destroy_listener.notify = NULL;
471 }
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300472
473 ps->surface->renderer_state = NULL;
474
475 if (ps->image) {
476 pixman_image_unref(ps->image);
477 ps->image = NULL;
478 }
479 weston_buffer_reference(&ps->buffer_ref, NULL);
480 free(ps);
481}
482
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300483static void
484surface_state_handle_surface_destroy(struct wl_listener *listener, void *data)
485{
486 struct pixman_surface_state *ps;
487
488 ps = container_of(listener, struct pixman_surface_state,
489 surface_destroy_listener);
490
491 pixman_renderer_surface_state_destroy(ps);
492}
493
494static void
495surface_state_handle_renderer_destroy(struct wl_listener *listener, void *data)
496{
497 struct pixman_surface_state *ps;
498
499 ps = container_of(listener, struct pixman_surface_state,
500 renderer_destroy_listener);
501
502 pixman_renderer_surface_state_destroy(ps);
503}
504
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300505static int
506pixman_renderer_create_surface(struct weston_surface *surface)
507{
508 struct pixman_surface_state *ps;
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300509 struct pixman_renderer *pr = get_renderer(surface->compositor);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300510
Bryce Harringtonde16d892014-11-20 22:21:57 -0800511 ps = zalloc(sizeof *ps);
512 if (ps == NULL)
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300513 return -1;
514
515 surface->renderer_state = ps;
516
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300517 ps->surface = surface;
518
519 ps->surface_destroy_listener.notify =
520 surface_state_handle_surface_destroy;
521 wl_signal_add(&surface->destroy_signal,
522 &ps->surface_destroy_listener);
523
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300524 ps->renderer_destroy_listener.notify =
525 surface_state_handle_renderer_destroy;
526 wl_signal_add(&pr->destroy_signal,
527 &ps->renderer_destroy_listener);
528
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300529 return 0;
530}
531
532static void
533pixman_renderer_surface_set_color(struct weston_surface *es,
534 float red, float green, float blue, float alpha)
535{
536 struct pixman_surface_state *ps = get_surface_state(es);
537 pixman_color_t color;
538
539 color.red = red * 0xffff;
540 color.green = green * 0xffff;
541 color.blue = blue * 0xffff;
542 color.alpha = alpha * 0xffff;
543
544 if (ps->image) {
545 pixman_image_unref(ps->image);
546 ps->image = NULL;
547 }
548
549 ps->image = pixman_image_create_solid_fill(&color);
550}
551
552static void
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300553pixman_renderer_destroy(struct weston_compositor *ec)
554{
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +0300555 struct pixman_renderer *pr = get_renderer(ec);
556
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300557 wl_signal_emit(&pr->destroy_signal, pr);
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +0300558 weston_binding_destroy(pr->debug_binding);
559 free(pr);
560
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300561 ec->renderer = NULL;
562}
563
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200564static void
Pekka Paalanen6764bbe2015-02-11 12:29:56 +0200565pixman_renderer_surface_get_content_size(struct weston_surface *surface,
566 int *width, int *height)
567{
568 struct pixman_surface_state *ps = get_surface_state(surface);
569
570 if (ps->image) {
571 *width = pixman_image_get_width(ps->image);
572 *height = pixman_image_get_height(ps->image);
573 } else {
574 *width = 0;
575 *height = 0;
576 }
577}
578
579static int
580pixman_renderer_surface_copy_content(struct weston_surface *surface,
581 void *target, size_t size,
582 int src_x, int src_y,
583 int width, int height)
584{
585 const pixman_format_code_t format = PIXMAN_a8b8g8r8;
586 const size_t bytespp = 4; /* PIXMAN_a8b8g8r8 */
587 struct pixman_surface_state *ps = get_surface_state(surface);
588 pixman_image_t *out_buf;
589
590 if (!ps->image)
591 return -1;
592
593 out_buf = pixman_image_create_bits(format, width, height,
594 target, width * bytespp);
595
596 pixman_image_set_transform(ps->image, NULL);
597 pixman_image_composite32(PIXMAN_OP_SRC,
598 ps->image, /* src */
599 NULL, /* mask */
600 out_buf, /* dest */
601 src_x, src_y, /* src_x, src_y */
602 0, 0, /* mask_x, mask_y */
603 0, 0, /* dest_x, dest_y */
604 width, height);
605
606 pixman_image_unref(out_buf);
607
608 return 0;
609}
610
611static void
Kristian Høgsberge3148752013-05-06 23:19:49 -0400612debug_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200613 void *data)
614{
615 struct weston_compositor *ec = data;
616 struct pixman_renderer *pr = (struct pixman_renderer *) ec->renderer;
617
618 pr->repaint_debug ^= 1;
619
620 if (pr->repaint_debug) {
621 pixman_color_t red = {
622 0x3fff, 0x0000, 0x0000, 0x3fff
623 };
624
625 pr->debug_color = pixman_image_create_solid_fill(&red);
626 } else {
627 pixman_image_unref(pr->debug_color);
628 weston_compositor_damage_all(ec);
629 }
630}
631
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300632WL_EXPORT int
633pixman_renderer_init(struct weston_compositor *ec)
634{
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200635 struct pixman_renderer *renderer;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300636
Bryce Harringtonde16d892014-11-20 22:21:57 -0800637 renderer = zalloc(sizeof *renderer);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300638 if (renderer == NULL)
639 return -1;
640
Philipp Brüschweilerf3e39f92013-03-08 20:35:39 +0100641 renderer->repaint_debug = 0;
642 renderer->debug_color = NULL;
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200643 renderer->base.read_pixels = pixman_renderer_read_pixels;
644 renderer->base.repaint_output = pixman_renderer_repaint_output;
645 renderer->base.flush_damage = pixman_renderer_flush_damage;
646 renderer->base.attach = pixman_renderer_attach;
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200647 renderer->base.surface_set_color = pixman_renderer_surface_set_color;
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200648 renderer->base.destroy = pixman_renderer_destroy;
Pekka Paalanen6764bbe2015-02-11 12:29:56 +0200649 renderer->base.surface_get_content_size =
650 pixman_renderer_surface_get_content_size;
651 renderer->base.surface_copy_content =
652 pixman_renderer_surface_copy_content;
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200653 ec->renderer = &renderer->base;
Pekka Paalanen7bb65102013-05-22 18:03:04 +0300654 ec->capabilities |= WESTON_CAP_ROTATION_ANY;
Pekka Paalanen4fc5dd02013-05-22 18:03:05 +0300655 ec->capabilities |= WESTON_CAP_CAPTURE_YFLIP;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300656
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +0300657 renderer->debug_binding =
658 weston_compositor_add_debug_binding(ec, KEY_R,
659 debug_binding, ec);
Tomeu Vizoso1c1fc292013-08-06 20:05:56 +0200660
661 wl_display_add_shm_format(ec->wl_display, WL_SHM_FORMAT_RGB565);
662
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300663 wl_signal_init(&renderer->destroy_signal);
664
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300665 return 0;
666}
667
668WL_EXPORT void
669pixman_renderer_output_set_buffer(struct weston_output *output, pixman_image_t *buffer)
670{
671 struct pixman_output_state *po = get_output_state(output);
672
673 if (po->hw_buffer)
674 pixman_image_unref(po->hw_buffer);
675 po->hw_buffer = buffer;
676
677 if (po->hw_buffer) {
678 output->compositor->read_format = pixman_image_get_format(po->hw_buffer);
679 pixman_image_ref(po->hw_buffer);
680 }
681}
682
683WL_EXPORT int
684pixman_renderer_output_create(struct weston_output *output)
685{
Bryce Harringtonde16d892014-11-20 22:21:57 -0800686 struct pixman_output_state *po;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200687 int w, h;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300688
Bryce Harringtonde16d892014-11-20 22:21:57 -0800689 po = zalloc(sizeof *po);
690 if (po == NULL)
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300691 return -1;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200692
693 /* set shadow image transformation */
Hardeningff39efa2013-09-18 23:56:35 +0200694 w = output->current_mode->width;
695 h = output->current_mode->height;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200696
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200697 po->shadow_buffer = malloc(w * h * 4);
698
699 if (!po->shadow_buffer) {
700 free(po);
701 return -1;
702 }
703
704 po->shadow_image =
705 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
706 po->shadow_buffer, w * 4);
707
708 if (!po->shadow_image) {
709 free(po->shadow_buffer);
710 free(po);
711 return -1;
712 }
713
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300714 output->renderer_state = po;
715
716 return 0;
717}
718
719WL_EXPORT void
720pixman_renderer_output_destroy(struct weston_output *output)
721{
722 struct pixman_output_state *po = get_output_state(output);
723
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200724 pixman_image_unref(po->shadow_image);
Ander Conselvan de Oliveira23e72b82013-01-25 15:13:06 +0200725
726 if (po->hw_buffer)
727 pixman_image_unref(po->hw_buffer);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200728
Arnaud Vrac8e3fe082014-08-25 20:56:52 +0200729 free(po->shadow_buffer);
730
731 po->shadow_buffer = NULL;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200732 po->shadow_image = NULL;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300733 po->hw_buffer = NULL;
734
735 free(po);
736}