blob: 79c1d5b1aedec2c0acb75ce18b702ff91ae604bf [file] [log] [blame]
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +03001/*
2 * Copyright © 2012 Intel Corporation
3 * Copyright © 2013 Vasily Khoruzhick <anarsoul@gmail.com>
4 *
5 * Permission to use, copy, modify, distribute, and sell this software and
6 * its documentation for any purpose is hereby granted without fee, provided
7 * that the above copyright notice appear in all copies and that both that
8 * copyright notice and this permission notice appear in supporting
9 * documentation, and that the name of the copyright holders not be used in
10 * advertising or publicity pertaining to distribution of the software
11 * without specific, written prior permission. The copyright holders make
12 * no representations about the suitability of this software for any
13 * purpose. It is provided "as is" without express or implied warranty.
14 *
15 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
16 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
18 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
19 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
20 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 */
23
Daniel Stonec228e232013-05-22 18:03:19 +030024#include "config.h"
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030025
26#include <errno.h>
27#include <stdlib.h>
28
29#include "pixman-renderer.h"
30
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +020031#include <linux/input.h>
32
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030033struct pixman_output_state {
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +020034 void *shadow_buffer;
35 pixman_image_t *shadow_image;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030036 pixman_image_t *hw_buffer;
37};
38
39struct pixman_surface_state {
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +030040 struct weston_surface *surface;
41
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030042 pixman_image_t *image;
43 struct weston_buffer_reference buffer_ref;
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +030044
45 struct wl_listener surface_destroy_listener;
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +030046 struct wl_listener renderer_destroy_listener;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030047};
48
49struct pixman_renderer {
50 struct weston_renderer base;
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +030051
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +020052 int repaint_debug;
53 pixman_image_t *debug_color;
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +030054 struct weston_binding *debug_binding;
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +030055
56 struct wl_signal destroy_signal;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030057};
58
59static inline struct pixman_output_state *
60get_output_state(struct weston_output *output)
61{
62 return (struct pixman_output_state *)output->renderer_state;
63}
64
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +030065static int
66pixman_renderer_create_surface(struct weston_surface *surface);
67
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030068static inline struct pixman_surface_state *
69get_surface_state(struct weston_surface *surface)
70{
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +030071 if (!surface->renderer_state)
72 pixman_renderer_create_surface(surface);
73
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030074 return (struct pixman_surface_state *)surface->renderer_state;
75}
76
77static inline struct pixman_renderer *
78get_renderer(struct weston_compositor *ec)
79{
80 return (struct pixman_renderer *)ec->renderer;
81}
82
83static int
84pixman_renderer_read_pixels(struct weston_output *output,
85 pixman_format_code_t format, void *pixels,
86 uint32_t x, uint32_t y,
87 uint32_t width, uint32_t height)
88{
89 struct pixman_output_state *po = get_output_state(output);
Alexander Larsson97af7922013-05-29 12:01:33 +020090 pixman_transform_t transform;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030091 pixman_image_t *out_buf;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030092
93 if (!po->hw_buffer) {
94 errno = ENODEV;
95 return -1;
96 }
97
98 out_buf = pixman_image_create_bits(format,
99 width,
100 height,
101 pixels,
102 (PIXMAN_FORMAT_BPP(format) / 8) * width);
103
Alexander Larsson97af7922013-05-29 12:01:33 +0200104 /* Caller expects vflipped source image */
105 pixman_transform_init_translate(&transform,
106 pixman_int_to_fixed (x),
107 pixman_int_to_fixed (y - pixman_image_get_height (po->hw_buffer)));
108 pixman_transform_scale(&transform, NULL,
109 pixman_fixed_1,
110 pixman_fixed_minus_1);
111 pixman_image_set_transform(po->hw_buffer, &transform);
112
113 pixman_image_composite32(PIXMAN_OP_SRC,
114 po->hw_buffer, /* src */
115 NULL /* mask */,
116 out_buf, /* dest */
117 0, 0, /* src_x, src_y */
118 0, 0, /* mask_x, mask_y */
119 0, 0, /* dest_x, dest_y */
120 pixman_image_get_width (po->hw_buffer), /* width */
121 pixman_image_get_height (po->hw_buffer) /* height */);
122 pixman_image_set_transform(po->hw_buffer, NULL);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300123
124 pixman_image_unref(out_buf);
125
126 return 0;
127}
128
Vasily Khoruzhick031fc872013-01-29 14:58:14 +0300129static void
Alexander Larsson4ea95522013-05-22 14:41:37 +0200130box_scale(pixman_box32_t *dst, int scale)
131{
132 dst->x1 *= scale;
133 dst->x2 *= scale;
134 dst->y1 *= scale;
135 dst->y2 *= scale;
136}
137
138static void
139scale_region (pixman_region32_t *region, int scale)
140{
141 pixman_box32_t *rects, *scaled_rects;
142 int nrects, i;
143
144 if (scale != 1) {
145 rects = pixman_region32_rectangles(region, &nrects);
146 scaled_rects = calloc(nrects, sizeof(pixman_box32_t));
147
148 for (i = 0; i < nrects; i++) {
149 scaled_rects[i] = rects[i];
150 box_scale(&scaled_rects[i], scale);
151 }
152 pixman_region32_clear(region);
153
154 pixman_region32_init_rects (region, scaled_rects, nrects);
155 free (scaled_rects);
156 }
157}
158
159static void
Alexander Larsson1f206b42013-05-22 14:41:36 +0200160transform_region (pixman_region32_t *region, int width, int height, enum wl_output_transform transform)
Vasily Khoruzhick031fc872013-01-29 14:58:14 +0300161{
Alexander Larsson1f206b42013-05-22 14:41:36 +0200162 pixman_box32_t *rects, *transformed_rects;
163 int nrects, i;
164
165 if (transform == WL_OUTPUT_TRANSFORM_NORMAL)
166 return;
167
168 rects = pixman_region32_rectangles(region, &nrects);
169 transformed_rects = calloc(nrects, sizeof(pixman_box32_t));
170
171 for (i = 0; i < nrects; i++) {
172 switch (transform) {
173 default:
174 case WL_OUTPUT_TRANSFORM_NORMAL:
175 transformed_rects[i].x1 = rects[i].x1;
176 transformed_rects[i].y1 = rects[i].y1;
177 transformed_rects[i].x2 = rects[i].x2;
178 transformed_rects[i].y2 = rects[i].y2;
179 break;
180 case WL_OUTPUT_TRANSFORM_90:
181 transformed_rects[i].x1 = height - rects[i].y2;
182 transformed_rects[i].y1 = rects[i].x1;
183 transformed_rects[i].x2 = height - rects[i].y1;
184 transformed_rects[i].y2 = rects[i].x2;
185 break;
186 case WL_OUTPUT_TRANSFORM_180:
187 transformed_rects[i].x1 = width - rects[i].x2;
188 transformed_rects[i].y1 = height - rects[i].y2;
189 transformed_rects[i].x2 = width - rects[i].x1;
190 transformed_rects[i].y2 = height - rects[i].y1;
191 break;
192 case WL_OUTPUT_TRANSFORM_270:
193 transformed_rects[i].x1 = rects[i].y1;
194 transformed_rects[i].y1 = width - rects[i].x2;
195 transformed_rects[i].x2 = rects[i].y2;
196 transformed_rects[i].y2 = width - rects[i].x1;
197 break;
198 case WL_OUTPUT_TRANSFORM_FLIPPED:
199 transformed_rects[i].x1 = width - rects[i].x2;
200 transformed_rects[i].y1 = rects[i].y1;
201 transformed_rects[i].x2 = width - rects[i].x1;
202 transformed_rects[i].y2 = rects[i].y2;
203 break;
204 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
205 transformed_rects[i].x1 = height - rects[i].y2;
206 transformed_rects[i].y1 = width - rects[i].x2;
207 transformed_rects[i].x2 = height - rects[i].y1;
208 transformed_rects[i].y2 = width - rects[i].x1;
209 break;
210 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
211 transformed_rects[i].x1 = rects[i].x1;
212 transformed_rects[i].y1 = height - rects[i].y2;
213 transformed_rects[i].x2 = rects[i].x2;
214 transformed_rects[i].y2 = height - rects[i].y1;
215 break;
216 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
217 transformed_rects[i].x1 = rects[i].y1;
218 transformed_rects[i].y1 = rects[i].x1;
219 transformed_rects[i].x2 = rects[i].y2;
220 transformed_rects[i].y2 = rects[i].x2;
221 break;
222 }
223 }
224 pixman_region32_clear(region);
225
226 pixman_region32_init_rects (region, transformed_rects, nrects);
227 free (transformed_rects);
228}
229
230static void
231region_global_to_output(struct weston_output *output, pixman_region32_t *region)
232{
233 pixman_region32_translate(region, -output->x, -output->y);
234 transform_region (region, output->width, output->height, output->transform);
Hardeningff39efa2013-09-18 23:56:35 +0200235 scale_region (region, output->current_scale);
Vasily Khoruzhick031fc872013-01-29 14:58:14 +0300236}
237
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300238#define D2F(v) pixman_double_to_fixed((double)v)
239
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300240static void
Jason Ekstranda7af7042013-10-12 22:38:11 -0500241repaint_region(struct weston_view *ev, struct weston_output *output,
Alexander Larsson1f206b42013-05-22 14:41:36 +0200242 pixman_region32_t *region, pixman_region32_t *surf_region,
243 pixman_op_t pixman_op)
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300244{
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200245 struct pixman_renderer *pr =
246 (struct pixman_renderer *) output->compositor->renderer;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500247 struct pixman_surface_state *ps = get_surface_state(ev->surface);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300248 struct pixman_output_state *po = get_output_state(output);
249 pixman_region32_t final_region;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500250 float view_x, view_y;
Alexander Larsson1f206b42013-05-22 14:41:36 +0200251 pixman_transform_t transform;
252 pixman_fixed_t fw, fh;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300253
254 /* The final region to be painted is the intersection of
255 * 'region' and 'surf_region'. However, 'region' is in the global
256 * coordinates, and 'surf_region' is in the surface-local
257 * coordinates
258 */
259 pixman_region32_init(&final_region);
Alexander Larsson1f206b42013-05-22 14:41:36 +0200260 if (surf_region) {
261 pixman_region32_copy(&final_region, surf_region);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300262
Alexander Larsson1f206b42013-05-22 14:41:36 +0200263 /* Convert from surface to global coordinates */
Jason Ekstranda7af7042013-10-12 22:38:11 -0500264 if (!ev->transform.enabled) {
265 pixman_region32_translate(&final_region, ev->geometry.x, ev->geometry.y);
Alexander Larsson1f206b42013-05-22 14:41:36 +0200266 } else {
Jason Ekstranda7af7042013-10-12 22:38:11 -0500267 weston_view_to_global_float(ev, 0, 0, &view_x, &view_y);
268 pixman_region32_translate(&final_region, (int)view_x, (int)view_y);
Alexander Larsson1f206b42013-05-22 14:41:36 +0200269 }
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300270
Alexander Larsson1f206b42013-05-22 14:41:36 +0200271 /* We need to paint the intersection */
272 pixman_region32_intersect(&final_region, &final_region, region);
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300273 } else {
Alexander Larsson1f206b42013-05-22 14:41:36 +0200274 /* If there is no surface region, just use the global region */
275 pixman_region32_copy(&final_region, region);
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300276 }
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300277
Alexander Larsson1f206b42013-05-22 14:41:36 +0200278 /* Convert from global to output coord */
279 region_global_to_output(output, &final_region);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300280
Alexander Larsson1f206b42013-05-22 14:41:36 +0200281 /* And clip to it */
282 pixman_image_set_clip_region32 (po->shadow_image, &final_region);
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200283
Alexander Larsson1f206b42013-05-22 14:41:36 +0200284 /* Set up the source transformation based on the surface
Alexander Larsson4ea95522013-05-22 14:41:37 +0200285 position, the output position/transform/scale and the client
286 specified buffer transform/scale */
Alexander Larsson1f206b42013-05-22 14:41:36 +0200287 pixman_transform_init_identity(&transform);
Alexander Larsson4ea95522013-05-22 14:41:37 +0200288 pixman_transform_scale(&transform, NULL,
Hardeningff39efa2013-09-18 23:56:35 +0200289 pixman_double_to_fixed ((double)1.0/output->current_scale),
290 pixman_double_to_fixed ((double)1.0/output->current_scale));
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200291
Alexander Larsson1f206b42013-05-22 14:41:36 +0200292 fw = pixman_int_to_fixed(output->width);
293 fh = pixman_int_to_fixed(output->height);
294 switch (output->transform) {
295 default:
296 case WL_OUTPUT_TRANSFORM_NORMAL:
297 case WL_OUTPUT_TRANSFORM_FLIPPED:
298 break;
299 case WL_OUTPUT_TRANSFORM_90:
300 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
301 pixman_transform_rotate(&transform, NULL, 0, -pixman_fixed_1);
302 pixman_transform_translate(&transform, NULL, 0, fh);
303 break;
304 case WL_OUTPUT_TRANSFORM_180:
305 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
306 pixman_transform_rotate(&transform, NULL, -pixman_fixed_1, 0);
307 pixman_transform_translate(&transform, NULL, fw, fh);
308 break;
309 case WL_OUTPUT_TRANSFORM_270:
310 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
311 pixman_transform_rotate(&transform, NULL, 0, pixman_fixed_1);
312 pixman_transform_translate(&transform, NULL, fw, 0);
313 break;
314 }
315
316 switch (output->transform) {
317 case WL_OUTPUT_TRANSFORM_FLIPPED:
318 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
319 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
320 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
321 pixman_transform_scale(&transform, NULL,
322 pixman_int_to_fixed (-1),
323 pixman_int_to_fixed (1));
324 pixman_transform_translate(&transform, NULL, fw, 0);
325 break;
326 }
327
328 pixman_transform_translate(&transform, NULL,
329 pixman_double_to_fixed (output->x),
330 pixman_double_to_fixed (output->y));
331
Jason Ekstranda7af7042013-10-12 22:38:11 -0500332 if (ev->transform.enabled) {
Alexander Larsson1f206b42013-05-22 14:41:36 +0200333 /* Pixman supports only 2D transform matrix, but Weston uses 3D,
334 * so we're omitting Z coordinate here
335 */
336 pixman_transform_t surface_transform = {{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500337 { D2F(ev->transform.matrix.d[0]),
338 D2F(ev->transform.matrix.d[4]),
339 D2F(ev->transform.matrix.d[12]),
Alexander Larsson1f206b42013-05-22 14:41:36 +0200340 },
Jason Ekstranda7af7042013-10-12 22:38:11 -0500341 { D2F(ev->transform.matrix.d[1]),
342 D2F(ev->transform.matrix.d[5]),
343 D2F(ev->transform.matrix.d[13]),
Alexander Larsson1f206b42013-05-22 14:41:36 +0200344 },
Jason Ekstranda7af7042013-10-12 22:38:11 -0500345 { D2F(ev->transform.matrix.d[3]),
346 D2F(ev->transform.matrix.d[7]),
347 D2F(ev->transform.matrix.d[15]),
Alexander Larsson1f206b42013-05-22 14:41:36 +0200348 }
349 }};
350
351 pixman_transform_invert(&surface_transform, &surface_transform);
352 pixman_transform_multiply (&transform, &surface_transform, &transform);
353 } else {
354 pixman_transform_translate(&transform, NULL,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500355 pixman_double_to_fixed ((double)-ev->geometry.x),
356 pixman_double_to_fixed ((double)-ev->geometry.y));
Alexander Larsson1f206b42013-05-22 14:41:36 +0200357 }
358
359
Jason Ekstranda7af7042013-10-12 22:38:11 -0500360 fw = pixman_int_to_fixed(ev->geometry.width);
361 fh = pixman_int_to_fixed(ev->geometry.height);
Alexander Larsson1f206b42013-05-22 14:41:36 +0200362
Jason Ekstranda7af7042013-10-12 22:38:11 -0500363 switch (ev->surface->buffer_transform) {
Alexander Larsson1f206b42013-05-22 14:41:36 +0200364 case WL_OUTPUT_TRANSFORM_FLIPPED:
365 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
366 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
367 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
368 pixman_transform_scale(&transform, NULL,
369 pixman_int_to_fixed (-1),
370 pixman_int_to_fixed (1));
371 pixman_transform_translate(&transform, NULL, fw, 0);
372 break;
373 }
374
Jason Ekstranda7af7042013-10-12 22:38:11 -0500375 switch (ev->surface->buffer_transform) {
Alexander Larsson1f206b42013-05-22 14:41:36 +0200376 default:
377 case WL_OUTPUT_TRANSFORM_NORMAL:
378 case WL_OUTPUT_TRANSFORM_FLIPPED:
379 break;
380 case WL_OUTPUT_TRANSFORM_90:
381 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
382 pixman_transform_rotate(&transform, NULL, 0, pixman_fixed_1);
383 pixman_transform_translate(&transform, NULL, fh, 0);
384 break;
385 case WL_OUTPUT_TRANSFORM_180:
386 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
387 pixman_transform_rotate(&transform, NULL, -pixman_fixed_1, 0);
388 pixman_transform_translate(&transform, NULL, fw, fh);
389 break;
390 case WL_OUTPUT_TRANSFORM_270:
391 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
392 pixman_transform_rotate(&transform, NULL, 0, -pixman_fixed_1);
393 pixman_transform_translate(&transform, NULL, 0, fw);
394 break;
395 }
396
Alexander Larsson4ea95522013-05-22 14:41:37 +0200397 pixman_transform_scale(&transform, NULL,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500398 pixman_double_to_fixed ((double)ev->surface->buffer_scale),
399 pixman_double_to_fixed ((double)ev->surface->buffer_scale));
Alexander Larsson4ea95522013-05-22 14:41:37 +0200400
Alexander Larsson1f206b42013-05-22 14:41:36 +0200401 pixman_image_set_transform(ps->image, &transform);
402
Jason Ekstranda7af7042013-10-12 22:38:11 -0500403 if (ev->transform.enabled || output->current_scale != ev->surface->buffer_scale)
Alexander Larsson1f206b42013-05-22 14:41:36 +0200404 pixman_image_set_filter(ps->image, PIXMAN_FILTER_BILINEAR, NULL, 0);
405 else
406 pixman_image_set_filter(ps->image, PIXMAN_FILTER_NEAREST, NULL, 0);
407
408 pixman_image_composite32(pixman_op,
409 ps->image, /* src */
410 NULL /* mask */,
411 po->shadow_image, /* dest */
412 0, 0, /* src_x, src_y */
413 0, 0, /* mask_x, mask_y */
414 0, 0, /* dest_x, dest_y */
415 pixman_image_get_width (po->shadow_image), /* width */
416 pixman_image_get_height (po->shadow_image) /* height */);
417
418 if (pr->repaint_debug)
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200419 pixman_image_composite32(PIXMAN_OP_OVER,
Alexander Larsson1f206b42013-05-22 14:41:36 +0200420 pr->debug_color, /* src */
421 NULL /* mask */,
422 po->shadow_image, /* dest */
423 0, 0, /* src_x, src_y */
424 0, 0, /* mask_x, mask_y */
425 0, 0, /* dest_x, dest_y */
426 pixman_image_get_width (po->shadow_image), /* width */
427 pixman_image_get_height (po->shadow_image) /* height */);
428
429 pixman_image_set_clip_region32 (po->shadow_image, NULL);
430
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300431 pixman_region32_fini(&final_region);
432}
433
434static void
Jason Ekstranda7af7042013-10-12 22:38:11 -0500435draw_view(struct weston_view *ev, struct weston_output *output,
436 pixman_region32_t *damage) /* in global coordinates */
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300437{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500438 struct pixman_surface_state *ps = get_surface_state(ev->surface);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300439 /* repaint bounding region in global coordinates: */
440 pixman_region32_t repaint;
441 /* non-opaque region in surface coordinates: */
442 pixman_region32_t surface_blend;
443
444 /* No buffer attached */
445 if (!ps->image)
446 return;
447
448 pixman_region32_init(&repaint);
449 pixman_region32_intersect(&repaint,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500450 &ev->transform.boundingbox, damage);
451 pixman_region32_subtract(&repaint, &repaint, &ev->clip);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300452
453 if (!pixman_region32_not_empty(&repaint))
454 goto out;
455
456 if (output->zoom.active) {
457 weston_log("pixman renderer does not support zoom\n");
458 goto out;
459 }
460
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300461 /* TODO: Implement repaint_region_complex() using pixman_composite_trapezoids() */
Jason Ekstranda7af7042013-10-12 22:38:11 -0500462 if (ev->transform.enabled &&
463 ev->transform.matrix.type != WESTON_MATRIX_TRANSFORM_TRANSLATE) {
464 repaint_region(ev, output, &repaint, NULL, PIXMAN_OP_OVER);
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300465 } else {
466 /* blended region is whole surface minus opaque region: */
467 pixman_region32_init_rect(&surface_blend, 0, 0,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500468 ev->geometry.width, ev->geometry.height);
469 pixman_region32_subtract(&surface_blend, &surface_blend, &ev->surface->opaque);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300470
Jason Ekstranda7af7042013-10-12 22:38:11 -0500471 if (pixman_region32_not_empty(&ev->surface->opaque)) {
472 repaint_region(ev, output, &repaint, &ev->surface->opaque, PIXMAN_OP_SRC);
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300473 }
474
475 if (pixman_region32_not_empty(&surface_blend)) {
Jason Ekstranda7af7042013-10-12 22:38:11 -0500476 repaint_region(ev, output, &repaint, &surface_blend, PIXMAN_OP_OVER);
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300477 }
478 pixman_region32_fini(&surface_blend);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300479 }
480
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300481
482out:
483 pixman_region32_fini(&repaint);
484}
485static void
486repaint_surfaces(struct weston_output *output, pixman_region32_t *damage)
487{
488 struct weston_compositor *compositor = output->compositor;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500489 struct weston_view *view;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300490
Jason Ekstranda7af7042013-10-12 22:38:11 -0500491 wl_list_for_each_reverse(view, &compositor->view_list, link)
492 if (view->plane == &compositor->primary_plane)
493 draw_view(view, output, damage);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300494}
495
496static void
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200497copy_to_hw_buffer(struct weston_output *output, pixman_region32_t *region)
498{
499 struct pixman_output_state *po = get_output_state(output);
Alexander Larsson1f206b42013-05-22 14:41:36 +0200500 pixman_region32_t output_region;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200501
Alexander Larsson1f206b42013-05-22 14:41:36 +0200502 pixman_region32_init(&output_region);
503 pixman_region32_copy(&output_region, region);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200504
Alexander Larsson1f206b42013-05-22 14:41:36 +0200505 region_global_to_output(output, &output_region);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200506
Alexander Larsson1f206b42013-05-22 14:41:36 +0200507 pixman_image_set_clip_region32 (po->hw_buffer, &output_region);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200508
Alexander Larsson1f206b42013-05-22 14:41:36 +0200509 pixman_image_composite32(PIXMAN_OP_SRC,
510 po->shadow_image, /* src */
511 NULL /* mask */,
512 po->hw_buffer, /* dest */
513 0, 0, /* src_x, src_y */
514 0, 0, /* mask_x, mask_y */
515 0, 0, /* dest_x, dest_y */
516 pixman_image_get_width (po->hw_buffer), /* width */
517 pixman_image_get_height (po->hw_buffer) /* height */);
518
519 pixman_image_set_clip_region32 (po->hw_buffer, NULL);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200520}
521
522static void
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300523pixman_renderer_repaint_output(struct weston_output *output,
524 pixman_region32_t *output_damage)
525{
526 struct pixman_output_state *po = get_output_state(output);
527
528 if (!po->hw_buffer)
529 return;
530
531 repaint_surfaces(output, output_damage);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200532 copy_to_hw_buffer(output, output_damage);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300533
534 pixman_region32_copy(&output->previous_damage, output_damage);
535 wl_signal_emit(&output->frame_signal, output);
536
537 /* Actual flip should be done by caller */
538}
539
540static void
541pixman_renderer_flush_damage(struct weston_surface *surface)
542{
543 /* No-op for pixman renderer */
544}
545
546static void
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500547pixman_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300548{
549 struct pixman_surface_state *ps = get_surface_state(es);
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500550 struct wl_shm_buffer *shm_buffer;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300551 pixman_format_code_t pixman_format;
552
553 weston_buffer_reference(&ps->buffer_ref, buffer);
554
555 if (ps->image) {
556 pixman_image_unref(ps->image);
557 ps->image = NULL;
558 }
559
560 if (!buffer)
561 return;
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500562
563 shm_buffer = wl_shm_buffer_get(buffer->resource);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300564
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500565 if (! shm_buffer) {
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300566 weston_log("Pixman renderer supports only SHM buffers\n");
567 weston_buffer_reference(&ps->buffer_ref, NULL);
568 return;
569 }
570
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500571 switch (wl_shm_buffer_get_format(shm_buffer)) {
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300572 case WL_SHM_FORMAT_XRGB8888:
573 pixman_format = PIXMAN_x8r8g8b8;
574 break;
575 case WL_SHM_FORMAT_ARGB8888:
576 pixman_format = PIXMAN_a8r8g8b8;
577 break;
Tomeu Vizoso1c1fc292013-08-06 20:05:56 +0200578 case WL_SHM_FORMAT_RGB565:
579 pixman_format = PIXMAN_r5g6b5;
580 break;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300581 default:
582 weston_log("Unsupported SHM buffer format\n");
583 weston_buffer_reference(&ps->buffer_ref, NULL);
584 return;
585 break;
586 }
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500587
588 buffer->shm_buffer = shm_buffer;
589 buffer->width = wl_shm_buffer_get_width(shm_buffer);
590 buffer->height = wl_shm_buffer_get_height(shm_buffer);
591
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300592 ps->image = pixman_image_create_bits(pixman_format,
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500593 buffer->width, buffer->height,
594 wl_shm_buffer_get_data(shm_buffer),
595 wl_shm_buffer_get_stride(shm_buffer));
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300596}
597
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300598static void
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300599pixman_renderer_surface_state_destroy(struct pixman_surface_state *ps)
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300600{
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300601 wl_list_remove(&ps->surface_destroy_listener.link);
602 wl_list_remove(&ps->renderer_destroy_listener.link);
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300603
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300604
605 ps->surface->renderer_state = NULL;
606
607 if (ps->image) {
608 pixman_image_unref(ps->image);
609 ps->image = NULL;
610 }
611 weston_buffer_reference(&ps->buffer_ref, NULL);
612 free(ps);
613}
614
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300615static void
616surface_state_handle_surface_destroy(struct wl_listener *listener, void *data)
617{
618 struct pixman_surface_state *ps;
619
620 ps = container_of(listener, struct pixman_surface_state,
621 surface_destroy_listener);
622
623 pixman_renderer_surface_state_destroy(ps);
624}
625
626static void
627surface_state_handle_renderer_destroy(struct wl_listener *listener, void *data)
628{
629 struct pixman_surface_state *ps;
630
631 ps = container_of(listener, struct pixman_surface_state,
632 renderer_destroy_listener);
633
634 pixman_renderer_surface_state_destroy(ps);
635}
636
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300637static int
638pixman_renderer_create_surface(struct weston_surface *surface)
639{
640 struct pixman_surface_state *ps;
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300641 struct pixman_renderer *pr = get_renderer(surface->compositor);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300642
643 ps = calloc(1, sizeof *ps);
644 if (!ps)
645 return -1;
646
647 surface->renderer_state = ps;
648
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300649 ps->surface = surface;
650
651 ps->surface_destroy_listener.notify =
652 surface_state_handle_surface_destroy;
653 wl_signal_add(&surface->destroy_signal,
654 &ps->surface_destroy_listener);
655
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300656 ps->renderer_destroy_listener.notify =
657 surface_state_handle_renderer_destroy;
658 wl_signal_add(&pr->destroy_signal,
659 &ps->renderer_destroy_listener);
660
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300661 return 0;
662}
663
664static void
665pixman_renderer_surface_set_color(struct weston_surface *es,
666 float red, float green, float blue, float alpha)
667{
668 struct pixman_surface_state *ps = get_surface_state(es);
669 pixman_color_t color;
670
671 color.red = red * 0xffff;
672 color.green = green * 0xffff;
673 color.blue = blue * 0xffff;
674 color.alpha = alpha * 0xffff;
675
676 if (ps->image) {
677 pixman_image_unref(ps->image);
678 ps->image = NULL;
679 }
680
681 ps->image = pixman_image_create_solid_fill(&color);
682}
683
684static void
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300685pixman_renderer_destroy(struct weston_compositor *ec)
686{
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +0300687 struct pixman_renderer *pr = get_renderer(ec);
688
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300689 wl_signal_emit(&pr->destroy_signal, pr);
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +0300690 weston_binding_destroy(pr->debug_binding);
691 free(pr);
692
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300693 ec->renderer = NULL;
694}
695
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200696static void
Kristian Høgsberge3148752013-05-06 23:19:49 -0400697debug_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200698 void *data)
699{
700 struct weston_compositor *ec = data;
701 struct pixman_renderer *pr = (struct pixman_renderer *) ec->renderer;
702
703 pr->repaint_debug ^= 1;
704
705 if (pr->repaint_debug) {
706 pixman_color_t red = {
707 0x3fff, 0x0000, 0x0000, 0x3fff
708 };
709
710 pr->debug_color = pixman_image_create_solid_fill(&red);
711 } else {
712 pixman_image_unref(pr->debug_color);
713 weston_compositor_damage_all(ec);
714 }
715}
716
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300717WL_EXPORT int
718pixman_renderer_init(struct weston_compositor *ec)
719{
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200720 struct pixman_renderer *renderer;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300721
Ander Conselvan de Oliveirac68b1082013-10-25 16:26:31 +0300722 renderer = calloc(1, sizeof *renderer);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300723 if (renderer == NULL)
724 return -1;
725
Philipp Brüschweilerf3e39f92013-03-08 20:35:39 +0100726 renderer->repaint_debug = 0;
727 renderer->debug_color = NULL;
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200728 renderer->base.read_pixels = pixman_renderer_read_pixels;
729 renderer->base.repaint_output = pixman_renderer_repaint_output;
730 renderer->base.flush_damage = pixman_renderer_flush_damage;
731 renderer->base.attach = pixman_renderer_attach;
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200732 renderer->base.surface_set_color = pixman_renderer_surface_set_color;
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200733 renderer->base.destroy = pixman_renderer_destroy;
734 ec->renderer = &renderer->base;
Pekka Paalanen7bb65102013-05-22 18:03:04 +0300735 ec->capabilities |= WESTON_CAP_ROTATION_ANY;
Pekka Paalanen4fc5dd02013-05-22 18:03:05 +0300736 ec->capabilities |= WESTON_CAP_CAPTURE_YFLIP;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300737
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +0300738 renderer->debug_binding =
739 weston_compositor_add_debug_binding(ec, KEY_R,
740 debug_binding, ec);
Tomeu Vizoso1c1fc292013-08-06 20:05:56 +0200741
742 wl_display_add_shm_format(ec->wl_display, WL_SHM_FORMAT_RGB565);
743
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300744 wl_signal_init(&renderer->destroy_signal);
745
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300746 return 0;
747}
748
749WL_EXPORT void
750pixman_renderer_output_set_buffer(struct weston_output *output, pixman_image_t *buffer)
751{
752 struct pixman_output_state *po = get_output_state(output);
753
754 if (po->hw_buffer)
755 pixman_image_unref(po->hw_buffer);
756 po->hw_buffer = buffer;
757
758 if (po->hw_buffer) {
759 output->compositor->read_format = pixman_image_get_format(po->hw_buffer);
760 pixman_image_ref(po->hw_buffer);
761 }
762}
763
764WL_EXPORT int
765pixman_renderer_output_create(struct weston_output *output)
766{
767 struct pixman_output_state *po = calloc(1, sizeof *po);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200768 int w, h;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300769
770 if (!po)
771 return -1;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200772
773 /* set shadow image transformation */
Hardeningff39efa2013-09-18 23:56:35 +0200774 w = output->current_mode->width;
775 h = output->current_mode->height;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200776
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200777 po->shadow_buffer = malloc(w * h * 4);
778
779 if (!po->shadow_buffer) {
780 free(po);
781 return -1;
782 }
783
784 po->shadow_image =
785 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
786 po->shadow_buffer, w * 4);
787
788 if (!po->shadow_image) {
789 free(po->shadow_buffer);
790 free(po);
791 return -1;
792 }
793
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300794 output->renderer_state = po;
795
796 return 0;
797}
798
799WL_EXPORT void
800pixman_renderer_output_destroy(struct weston_output *output)
801{
802 struct pixman_output_state *po = get_output_state(output);
803
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200804 pixman_image_unref(po->shadow_image);
Ander Conselvan de Oliveira23e72b82013-01-25 15:13:06 +0200805
806 if (po->hw_buffer)
807 pixman_image_unref(po->hw_buffer);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200808
809 po->shadow_image = NULL;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300810 po->hw_buffer = NULL;
811
812 free(po);
813}