blob: 85fcd4c2a4408baee3b1e9ea8b875fa2efaad4b5 [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 {
40 pixman_image_t *image;
41 struct weston_buffer_reference buffer_ref;
42};
43
44struct pixman_renderer {
45 struct weston_renderer base;
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +020046 int repaint_debug;
47 pixman_image_t *debug_color;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030048};
49
50static inline struct pixman_output_state *
51get_output_state(struct weston_output *output)
52{
53 return (struct pixman_output_state *)output->renderer_state;
54}
55
56static inline struct pixman_surface_state *
57get_surface_state(struct weston_surface *surface)
58{
59 return (struct pixman_surface_state *)surface->renderer_state;
60}
61
62static inline struct pixman_renderer *
63get_renderer(struct weston_compositor *ec)
64{
65 return (struct pixman_renderer *)ec->renderer;
66}
67
68static int
69pixman_renderer_read_pixels(struct weston_output *output,
70 pixman_format_code_t format, void *pixels,
71 uint32_t x, uint32_t y,
72 uint32_t width, uint32_t height)
73{
74 struct pixman_output_state *po = get_output_state(output);
Alexander Larsson97af7922013-05-29 12:01:33 +020075 pixman_transform_t transform;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030076 pixman_image_t *out_buf;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030077
78 if (!po->hw_buffer) {
79 errno = ENODEV;
80 return -1;
81 }
82
83 out_buf = pixman_image_create_bits(format,
84 width,
85 height,
86 pixels,
87 (PIXMAN_FORMAT_BPP(format) / 8) * width);
88
Alexander Larsson97af7922013-05-29 12:01:33 +020089 /* Caller expects vflipped source image */
90 pixman_transform_init_translate(&transform,
91 pixman_int_to_fixed (x),
92 pixman_int_to_fixed (y - pixman_image_get_height (po->hw_buffer)));
93 pixman_transform_scale(&transform, NULL,
94 pixman_fixed_1,
95 pixman_fixed_minus_1);
96 pixman_image_set_transform(po->hw_buffer, &transform);
97
98 pixman_image_composite32(PIXMAN_OP_SRC,
99 po->hw_buffer, /* src */
100 NULL /* mask */,
101 out_buf, /* dest */
102 0, 0, /* src_x, src_y */
103 0, 0, /* mask_x, mask_y */
104 0, 0, /* dest_x, dest_y */
105 pixman_image_get_width (po->hw_buffer), /* width */
106 pixman_image_get_height (po->hw_buffer) /* height */);
107 pixman_image_set_transform(po->hw_buffer, NULL);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300108
109 pixman_image_unref(out_buf);
110
111 return 0;
112}
113
Vasily Khoruzhick031fc872013-01-29 14:58:14 +0300114static void
Alexander Larsson4ea95522013-05-22 14:41:37 +0200115box_scale(pixman_box32_t *dst, int scale)
116{
117 dst->x1 *= scale;
118 dst->x2 *= scale;
119 dst->y1 *= scale;
120 dst->y2 *= scale;
121}
122
123static void
124scale_region (pixman_region32_t *region, int scale)
125{
126 pixman_box32_t *rects, *scaled_rects;
127 int nrects, i;
128
129 if (scale != 1) {
130 rects = pixman_region32_rectangles(region, &nrects);
131 scaled_rects = calloc(nrects, sizeof(pixman_box32_t));
132
133 for (i = 0; i < nrects; i++) {
134 scaled_rects[i] = rects[i];
135 box_scale(&scaled_rects[i], scale);
136 }
137 pixman_region32_clear(region);
138
139 pixman_region32_init_rects (region, scaled_rects, nrects);
140 free (scaled_rects);
141 }
142}
143
144static void
Alexander Larsson1f206b42013-05-22 14:41:36 +0200145transform_region (pixman_region32_t *region, int width, int height, enum wl_output_transform transform)
Vasily Khoruzhick031fc872013-01-29 14:58:14 +0300146{
Alexander Larsson1f206b42013-05-22 14:41:36 +0200147 pixman_box32_t *rects, *transformed_rects;
148 int nrects, i;
149
150 if (transform == WL_OUTPUT_TRANSFORM_NORMAL)
151 return;
152
153 rects = pixman_region32_rectangles(region, &nrects);
154 transformed_rects = calloc(nrects, sizeof(pixman_box32_t));
155
156 for (i = 0; i < nrects; i++) {
157 switch (transform) {
158 default:
159 case WL_OUTPUT_TRANSFORM_NORMAL:
160 transformed_rects[i].x1 = rects[i].x1;
161 transformed_rects[i].y1 = rects[i].y1;
162 transformed_rects[i].x2 = rects[i].x2;
163 transformed_rects[i].y2 = rects[i].y2;
164 break;
165 case WL_OUTPUT_TRANSFORM_90:
166 transformed_rects[i].x1 = height - rects[i].y2;
167 transformed_rects[i].y1 = rects[i].x1;
168 transformed_rects[i].x2 = height - rects[i].y1;
169 transformed_rects[i].y2 = rects[i].x2;
170 break;
171 case WL_OUTPUT_TRANSFORM_180:
172 transformed_rects[i].x1 = width - rects[i].x2;
173 transformed_rects[i].y1 = height - rects[i].y2;
174 transformed_rects[i].x2 = width - rects[i].x1;
175 transformed_rects[i].y2 = height - rects[i].y1;
176 break;
177 case WL_OUTPUT_TRANSFORM_270:
178 transformed_rects[i].x1 = rects[i].y1;
179 transformed_rects[i].y1 = width - rects[i].x2;
180 transformed_rects[i].x2 = rects[i].y2;
181 transformed_rects[i].y2 = width - rects[i].x1;
182 break;
183 case WL_OUTPUT_TRANSFORM_FLIPPED:
184 transformed_rects[i].x1 = width - rects[i].x2;
185 transformed_rects[i].y1 = rects[i].y1;
186 transformed_rects[i].x2 = width - rects[i].x1;
187 transformed_rects[i].y2 = rects[i].y2;
188 break;
189 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
190 transformed_rects[i].x1 = height - rects[i].y2;
191 transformed_rects[i].y1 = width - rects[i].x2;
192 transformed_rects[i].x2 = height - rects[i].y1;
193 transformed_rects[i].y2 = width - rects[i].x1;
194 break;
195 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
196 transformed_rects[i].x1 = rects[i].x1;
197 transformed_rects[i].y1 = height - rects[i].y2;
198 transformed_rects[i].x2 = rects[i].x2;
199 transformed_rects[i].y2 = height - rects[i].y1;
200 break;
201 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
202 transformed_rects[i].x1 = rects[i].y1;
203 transformed_rects[i].y1 = rects[i].x1;
204 transformed_rects[i].x2 = rects[i].y2;
205 transformed_rects[i].y2 = rects[i].x2;
206 break;
207 }
208 }
209 pixman_region32_clear(region);
210
211 pixman_region32_init_rects (region, transformed_rects, nrects);
212 free (transformed_rects);
213}
214
215static void
216region_global_to_output(struct weston_output *output, pixman_region32_t *region)
217{
218 pixman_region32_translate(region, -output->x, -output->y);
219 transform_region (region, output->width, output->height, output->transform);
Hardeningff39efa2013-09-18 23:56:35 +0200220 scale_region (region, output->current_scale);
Vasily Khoruzhick031fc872013-01-29 14:58:14 +0300221}
222
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300223#define D2F(v) pixman_double_to_fixed((double)v)
224
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300225static void
Jason Ekstranda7af7042013-10-12 22:38:11 -0500226repaint_region(struct weston_view *ev, struct weston_output *output,
Alexander Larsson1f206b42013-05-22 14:41:36 +0200227 pixman_region32_t *region, pixman_region32_t *surf_region,
228 pixman_op_t pixman_op)
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300229{
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200230 struct pixman_renderer *pr =
231 (struct pixman_renderer *) output->compositor->renderer;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500232 struct pixman_surface_state *ps = get_surface_state(ev->surface);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300233 struct pixman_output_state *po = get_output_state(output);
234 pixman_region32_t final_region;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500235 float view_x, view_y;
Alexander Larsson1f206b42013-05-22 14:41:36 +0200236 pixman_transform_t transform;
237 pixman_fixed_t fw, fh;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300238
239 /* The final region to be painted is the intersection of
240 * 'region' and 'surf_region'. However, 'region' is in the global
241 * coordinates, and 'surf_region' is in the surface-local
242 * coordinates
243 */
244 pixman_region32_init(&final_region);
Alexander Larsson1f206b42013-05-22 14:41:36 +0200245 if (surf_region) {
246 pixman_region32_copy(&final_region, surf_region);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300247
Alexander Larsson1f206b42013-05-22 14:41:36 +0200248 /* Convert from surface to global coordinates */
Jason Ekstranda7af7042013-10-12 22:38:11 -0500249 if (!ev->transform.enabled) {
250 pixman_region32_translate(&final_region, ev->geometry.x, ev->geometry.y);
Alexander Larsson1f206b42013-05-22 14:41:36 +0200251 } else {
Jason Ekstranda7af7042013-10-12 22:38:11 -0500252 weston_view_to_global_float(ev, 0, 0, &view_x, &view_y);
253 pixman_region32_translate(&final_region, (int)view_x, (int)view_y);
Alexander Larsson1f206b42013-05-22 14:41:36 +0200254 }
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300255
Alexander Larsson1f206b42013-05-22 14:41:36 +0200256 /* We need to paint the intersection */
257 pixman_region32_intersect(&final_region, &final_region, region);
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300258 } else {
Alexander Larsson1f206b42013-05-22 14:41:36 +0200259 /* If there is no surface region, just use the global region */
260 pixman_region32_copy(&final_region, region);
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300261 }
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300262
Alexander Larsson1f206b42013-05-22 14:41:36 +0200263 /* Convert from global to output coord */
264 region_global_to_output(output, &final_region);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300265
Alexander Larsson1f206b42013-05-22 14:41:36 +0200266 /* And clip to it */
267 pixman_image_set_clip_region32 (po->shadow_image, &final_region);
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200268
Alexander Larsson1f206b42013-05-22 14:41:36 +0200269 /* Set up the source transformation based on the surface
Alexander Larsson4ea95522013-05-22 14:41:37 +0200270 position, the output position/transform/scale and the client
271 specified buffer transform/scale */
Alexander Larsson1f206b42013-05-22 14:41:36 +0200272 pixman_transform_init_identity(&transform);
Alexander Larsson4ea95522013-05-22 14:41:37 +0200273 pixman_transform_scale(&transform, NULL,
Hardeningff39efa2013-09-18 23:56:35 +0200274 pixman_double_to_fixed ((double)1.0/output->current_scale),
275 pixman_double_to_fixed ((double)1.0/output->current_scale));
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200276
Alexander Larsson1f206b42013-05-22 14:41:36 +0200277 fw = pixman_int_to_fixed(output->width);
278 fh = pixman_int_to_fixed(output->height);
279 switch (output->transform) {
280 default:
281 case WL_OUTPUT_TRANSFORM_NORMAL:
282 case WL_OUTPUT_TRANSFORM_FLIPPED:
283 break;
284 case WL_OUTPUT_TRANSFORM_90:
285 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
286 pixman_transform_rotate(&transform, NULL, 0, -pixman_fixed_1);
287 pixman_transform_translate(&transform, NULL, 0, fh);
288 break;
289 case WL_OUTPUT_TRANSFORM_180:
290 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
291 pixman_transform_rotate(&transform, NULL, -pixman_fixed_1, 0);
292 pixman_transform_translate(&transform, NULL, fw, fh);
293 break;
294 case WL_OUTPUT_TRANSFORM_270:
295 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
296 pixman_transform_rotate(&transform, NULL, 0, pixman_fixed_1);
297 pixman_transform_translate(&transform, NULL, fw, 0);
298 break;
299 }
300
301 switch (output->transform) {
302 case WL_OUTPUT_TRANSFORM_FLIPPED:
303 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
304 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
305 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
306 pixman_transform_scale(&transform, NULL,
307 pixman_int_to_fixed (-1),
308 pixman_int_to_fixed (1));
309 pixman_transform_translate(&transform, NULL, fw, 0);
310 break;
311 }
312
313 pixman_transform_translate(&transform, NULL,
314 pixman_double_to_fixed (output->x),
315 pixman_double_to_fixed (output->y));
316
Jason Ekstranda7af7042013-10-12 22:38:11 -0500317 if (ev->transform.enabled) {
Alexander Larsson1f206b42013-05-22 14:41:36 +0200318 /* Pixman supports only 2D transform matrix, but Weston uses 3D,
319 * so we're omitting Z coordinate here
320 */
321 pixman_transform_t surface_transform = {{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500322 { D2F(ev->transform.matrix.d[0]),
323 D2F(ev->transform.matrix.d[4]),
324 D2F(ev->transform.matrix.d[12]),
Alexander Larsson1f206b42013-05-22 14:41:36 +0200325 },
Jason Ekstranda7af7042013-10-12 22:38:11 -0500326 { D2F(ev->transform.matrix.d[1]),
327 D2F(ev->transform.matrix.d[5]),
328 D2F(ev->transform.matrix.d[13]),
Alexander Larsson1f206b42013-05-22 14:41:36 +0200329 },
Jason Ekstranda7af7042013-10-12 22:38:11 -0500330 { D2F(ev->transform.matrix.d[3]),
331 D2F(ev->transform.matrix.d[7]),
332 D2F(ev->transform.matrix.d[15]),
Alexander Larsson1f206b42013-05-22 14:41:36 +0200333 }
334 }};
335
336 pixman_transform_invert(&surface_transform, &surface_transform);
337 pixman_transform_multiply (&transform, &surface_transform, &transform);
338 } else {
339 pixman_transform_translate(&transform, NULL,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500340 pixman_double_to_fixed ((double)-ev->geometry.x),
341 pixman_double_to_fixed ((double)-ev->geometry.y));
Alexander Larsson1f206b42013-05-22 14:41:36 +0200342 }
343
344
Jason Ekstranda7af7042013-10-12 22:38:11 -0500345 fw = pixman_int_to_fixed(ev->geometry.width);
346 fh = pixman_int_to_fixed(ev->geometry.height);
Alexander Larsson1f206b42013-05-22 14:41:36 +0200347
Jason Ekstranda7af7042013-10-12 22:38:11 -0500348 switch (ev->surface->buffer_transform) {
Alexander Larsson1f206b42013-05-22 14:41:36 +0200349 case WL_OUTPUT_TRANSFORM_FLIPPED:
350 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
351 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
352 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
353 pixman_transform_scale(&transform, NULL,
354 pixman_int_to_fixed (-1),
355 pixman_int_to_fixed (1));
356 pixman_transform_translate(&transform, NULL, fw, 0);
357 break;
358 }
359
Jason Ekstranda7af7042013-10-12 22:38:11 -0500360 switch (ev->surface->buffer_transform) {
Alexander Larsson1f206b42013-05-22 14:41:36 +0200361 default:
362 case WL_OUTPUT_TRANSFORM_NORMAL:
363 case WL_OUTPUT_TRANSFORM_FLIPPED:
364 break;
365 case WL_OUTPUT_TRANSFORM_90:
366 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
367 pixman_transform_rotate(&transform, NULL, 0, pixman_fixed_1);
368 pixman_transform_translate(&transform, NULL, fh, 0);
369 break;
370 case WL_OUTPUT_TRANSFORM_180:
371 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
372 pixman_transform_rotate(&transform, NULL, -pixman_fixed_1, 0);
373 pixman_transform_translate(&transform, NULL, fw, fh);
374 break;
375 case WL_OUTPUT_TRANSFORM_270:
376 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
377 pixman_transform_rotate(&transform, NULL, 0, -pixman_fixed_1);
378 pixman_transform_translate(&transform, NULL, 0, fw);
379 break;
380 }
381
Alexander Larsson4ea95522013-05-22 14:41:37 +0200382 pixman_transform_scale(&transform, NULL,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500383 pixman_double_to_fixed ((double)ev->surface->buffer_scale),
384 pixman_double_to_fixed ((double)ev->surface->buffer_scale));
Alexander Larsson4ea95522013-05-22 14:41:37 +0200385
Alexander Larsson1f206b42013-05-22 14:41:36 +0200386 pixman_image_set_transform(ps->image, &transform);
387
Jason Ekstranda7af7042013-10-12 22:38:11 -0500388 if (ev->transform.enabled || output->current_scale != ev->surface->buffer_scale)
Alexander Larsson1f206b42013-05-22 14:41:36 +0200389 pixman_image_set_filter(ps->image, PIXMAN_FILTER_BILINEAR, NULL, 0);
390 else
391 pixman_image_set_filter(ps->image, PIXMAN_FILTER_NEAREST, NULL, 0);
392
393 pixman_image_composite32(pixman_op,
394 ps->image, /* src */
395 NULL /* mask */,
396 po->shadow_image, /* dest */
397 0, 0, /* src_x, src_y */
398 0, 0, /* mask_x, mask_y */
399 0, 0, /* dest_x, dest_y */
400 pixman_image_get_width (po->shadow_image), /* width */
401 pixman_image_get_height (po->shadow_image) /* height */);
402
403 if (pr->repaint_debug)
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200404 pixman_image_composite32(PIXMAN_OP_OVER,
Alexander Larsson1f206b42013-05-22 14:41:36 +0200405 pr->debug_color, /* src */
406 NULL /* mask */,
407 po->shadow_image, /* dest */
408 0, 0, /* src_x, src_y */
409 0, 0, /* mask_x, mask_y */
410 0, 0, /* dest_x, dest_y */
411 pixman_image_get_width (po->shadow_image), /* width */
412 pixman_image_get_height (po->shadow_image) /* height */);
413
414 pixman_image_set_clip_region32 (po->shadow_image, NULL);
415
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300416 pixman_region32_fini(&final_region);
417}
418
419static void
Jason Ekstranda7af7042013-10-12 22:38:11 -0500420draw_view(struct weston_view *ev, struct weston_output *output,
421 pixman_region32_t *damage) /* in global coordinates */
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300422{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500423 struct pixman_surface_state *ps = get_surface_state(ev->surface);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300424 /* repaint bounding region in global coordinates: */
425 pixman_region32_t repaint;
426 /* non-opaque region in surface coordinates: */
427 pixman_region32_t surface_blend;
428
429 /* No buffer attached */
430 if (!ps->image)
431 return;
432
433 pixman_region32_init(&repaint);
434 pixman_region32_intersect(&repaint,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500435 &ev->transform.boundingbox, damage);
436 pixman_region32_subtract(&repaint, &repaint, &ev->clip);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300437
438 if (!pixman_region32_not_empty(&repaint))
439 goto out;
440
441 if (output->zoom.active) {
442 weston_log("pixman renderer does not support zoom\n");
443 goto out;
444 }
445
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300446 /* TODO: Implement repaint_region_complex() using pixman_composite_trapezoids() */
Jason Ekstranda7af7042013-10-12 22:38:11 -0500447 if (ev->transform.enabled &&
448 ev->transform.matrix.type != WESTON_MATRIX_TRANSFORM_TRANSLATE) {
449 repaint_region(ev, output, &repaint, NULL, PIXMAN_OP_OVER);
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300450 } else {
451 /* blended region is whole surface minus opaque region: */
452 pixman_region32_init_rect(&surface_blend, 0, 0,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500453 ev->geometry.width, ev->geometry.height);
454 pixman_region32_subtract(&surface_blend, &surface_blend, &ev->surface->opaque);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300455
Jason Ekstranda7af7042013-10-12 22:38:11 -0500456 if (pixman_region32_not_empty(&ev->surface->opaque)) {
457 repaint_region(ev, output, &repaint, &ev->surface->opaque, PIXMAN_OP_SRC);
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300458 }
459
460 if (pixman_region32_not_empty(&surface_blend)) {
Jason Ekstranda7af7042013-10-12 22:38:11 -0500461 repaint_region(ev, output, &repaint, &surface_blend, PIXMAN_OP_OVER);
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300462 }
463 pixman_region32_fini(&surface_blend);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300464 }
465
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300466
467out:
468 pixman_region32_fini(&repaint);
469}
470static void
471repaint_surfaces(struct weston_output *output, pixman_region32_t *damage)
472{
473 struct weston_compositor *compositor = output->compositor;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500474 struct weston_view *view;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300475
Jason Ekstranda7af7042013-10-12 22:38:11 -0500476 wl_list_for_each_reverse(view, &compositor->view_list, link)
477 if (view->plane == &compositor->primary_plane)
478 draw_view(view, output, damage);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300479}
480
481static void
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200482copy_to_hw_buffer(struct weston_output *output, pixman_region32_t *region)
483{
484 struct pixman_output_state *po = get_output_state(output);
Alexander Larsson1f206b42013-05-22 14:41:36 +0200485 pixman_region32_t output_region;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200486
Alexander Larsson1f206b42013-05-22 14:41:36 +0200487 pixman_region32_init(&output_region);
488 pixman_region32_copy(&output_region, region);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200489
Alexander Larsson1f206b42013-05-22 14:41:36 +0200490 region_global_to_output(output, &output_region);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200491
Alexander Larsson1f206b42013-05-22 14:41:36 +0200492 pixman_image_set_clip_region32 (po->hw_buffer, &output_region);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200493
Alexander Larsson1f206b42013-05-22 14:41:36 +0200494 pixman_image_composite32(PIXMAN_OP_SRC,
495 po->shadow_image, /* src */
496 NULL /* mask */,
497 po->hw_buffer, /* dest */
498 0, 0, /* src_x, src_y */
499 0, 0, /* mask_x, mask_y */
500 0, 0, /* dest_x, dest_y */
501 pixman_image_get_width (po->hw_buffer), /* width */
502 pixman_image_get_height (po->hw_buffer) /* height */);
503
504 pixman_image_set_clip_region32 (po->hw_buffer, NULL);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200505}
506
507static void
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300508pixman_renderer_repaint_output(struct weston_output *output,
509 pixman_region32_t *output_damage)
510{
511 struct pixman_output_state *po = get_output_state(output);
512
513 if (!po->hw_buffer)
514 return;
515
516 repaint_surfaces(output, output_damage);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200517 copy_to_hw_buffer(output, output_damage);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300518
519 pixman_region32_copy(&output->previous_damage, output_damage);
520 wl_signal_emit(&output->frame_signal, output);
521
522 /* Actual flip should be done by caller */
523}
524
525static void
526pixman_renderer_flush_damage(struct weston_surface *surface)
527{
528 /* No-op for pixman renderer */
529}
530
531static void
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500532pixman_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300533{
534 struct pixman_surface_state *ps = get_surface_state(es);
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500535 struct wl_shm_buffer *shm_buffer;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300536 pixman_format_code_t pixman_format;
537
538 weston_buffer_reference(&ps->buffer_ref, buffer);
539
540 if (ps->image) {
541 pixman_image_unref(ps->image);
542 ps->image = NULL;
543 }
544
545 if (!buffer)
546 return;
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500547
548 shm_buffer = wl_shm_buffer_get(buffer->resource);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300549
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500550 if (! shm_buffer) {
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300551 weston_log("Pixman renderer supports only SHM buffers\n");
552 weston_buffer_reference(&ps->buffer_ref, NULL);
553 return;
554 }
555
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500556 switch (wl_shm_buffer_get_format(shm_buffer)) {
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300557 case WL_SHM_FORMAT_XRGB8888:
558 pixman_format = PIXMAN_x8r8g8b8;
559 break;
560 case WL_SHM_FORMAT_ARGB8888:
561 pixman_format = PIXMAN_a8r8g8b8;
562 break;
Tomeu Vizoso1c1fc292013-08-06 20:05:56 +0200563 case WL_SHM_FORMAT_RGB565:
564 pixman_format = PIXMAN_r5g6b5;
565 break;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300566 default:
567 weston_log("Unsupported SHM buffer format\n");
568 weston_buffer_reference(&ps->buffer_ref, NULL);
569 return;
570 break;
571 }
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500572
573 buffer->shm_buffer = shm_buffer;
574 buffer->width = wl_shm_buffer_get_width(shm_buffer);
575 buffer->height = wl_shm_buffer_get_height(shm_buffer);
576
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300577 ps->image = pixman_image_create_bits(pixman_format,
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500578 buffer->width, buffer->height,
579 wl_shm_buffer_get_data(shm_buffer),
580 wl_shm_buffer_get_stride(shm_buffer));
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300581}
582
583static int
584pixman_renderer_create_surface(struct weston_surface *surface)
585{
586 struct pixman_surface_state *ps;
587
588 ps = calloc(1, sizeof *ps);
589 if (!ps)
590 return -1;
591
592 surface->renderer_state = ps;
593
594 return 0;
595}
596
597static void
598pixman_renderer_surface_set_color(struct weston_surface *es,
599 float red, float green, float blue, float alpha)
600{
601 struct pixman_surface_state *ps = get_surface_state(es);
602 pixman_color_t color;
603
604 color.red = red * 0xffff;
605 color.green = green * 0xffff;
606 color.blue = blue * 0xffff;
607 color.alpha = alpha * 0xffff;
608
609 if (ps->image) {
610 pixman_image_unref(ps->image);
611 ps->image = NULL;
612 }
613
614 ps->image = pixman_image_create_solid_fill(&color);
615}
616
617static void
618pixman_renderer_destroy_surface(struct weston_surface *surface)
619{
620 struct pixman_surface_state *ps = get_surface_state(surface);
621
622 if (ps->image) {
623 pixman_image_unref(ps->image);
624 ps->image = NULL;
625 }
626 weston_buffer_reference(&ps->buffer_ref, NULL);
627 free(ps);
628}
629
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +0300630static void
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300631pixman_renderer_destroy(struct weston_compositor *ec)
632{
633 free(ec->renderer);
634 ec->renderer = NULL;
635}
636
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200637static void
Kristian Høgsberge3148752013-05-06 23:19:49 -0400638debug_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200639 void *data)
640{
641 struct weston_compositor *ec = data;
642 struct pixman_renderer *pr = (struct pixman_renderer *) ec->renderer;
643
644 pr->repaint_debug ^= 1;
645
646 if (pr->repaint_debug) {
647 pixman_color_t red = {
648 0x3fff, 0x0000, 0x0000, 0x3fff
649 };
650
651 pr->debug_color = pixman_image_create_solid_fill(&red);
652 } else {
653 pixman_image_unref(pr->debug_color);
654 weston_compositor_damage_all(ec);
655 }
656}
657
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300658WL_EXPORT int
659pixman_renderer_init(struct weston_compositor *ec)
660{
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200661 struct pixman_renderer *renderer;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300662
663 renderer = malloc(sizeof *renderer);
664 if (renderer == NULL)
665 return -1;
666
Philipp Brüschweilerf3e39f92013-03-08 20:35:39 +0100667 renderer->repaint_debug = 0;
668 renderer->debug_color = NULL;
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200669 renderer->base.read_pixels = pixman_renderer_read_pixels;
670 renderer->base.repaint_output = pixman_renderer_repaint_output;
671 renderer->base.flush_damage = pixman_renderer_flush_damage;
672 renderer->base.attach = pixman_renderer_attach;
673 renderer->base.create_surface = pixman_renderer_create_surface;
674 renderer->base.surface_set_color = pixman_renderer_surface_set_color;
675 renderer->base.destroy_surface = pixman_renderer_destroy_surface;
676 renderer->base.destroy = pixman_renderer_destroy;
677 ec->renderer = &renderer->base;
Pekka Paalanen7bb65102013-05-22 18:03:04 +0300678 ec->capabilities |= WESTON_CAP_ROTATION_ANY;
Pekka Paalanen4fc5dd02013-05-22 18:03:05 +0300679 ec->capabilities |= WESTON_CAP_CAPTURE_YFLIP;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300680
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200681 weston_compositor_add_debug_binding(ec, KEY_R,
682 debug_binding, ec);
Tomeu Vizoso1c1fc292013-08-06 20:05:56 +0200683
684 wl_display_add_shm_format(ec->wl_display, WL_SHM_FORMAT_RGB565);
685
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300686 return 0;
687}
688
689WL_EXPORT void
690pixman_renderer_output_set_buffer(struct weston_output *output, pixman_image_t *buffer)
691{
692 struct pixman_output_state *po = get_output_state(output);
693
694 if (po->hw_buffer)
695 pixman_image_unref(po->hw_buffer);
696 po->hw_buffer = buffer;
697
698 if (po->hw_buffer) {
699 output->compositor->read_format = pixman_image_get_format(po->hw_buffer);
700 pixman_image_ref(po->hw_buffer);
701 }
702}
703
704WL_EXPORT int
705pixman_renderer_output_create(struct weston_output *output)
706{
707 struct pixman_output_state *po = calloc(1, sizeof *po);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200708 int w, h;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300709
710 if (!po)
711 return -1;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200712
713 /* set shadow image transformation */
Hardeningff39efa2013-09-18 23:56:35 +0200714 w = output->current_mode->width;
715 h = output->current_mode->height;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200716
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200717 po->shadow_buffer = malloc(w * h * 4);
718
719 if (!po->shadow_buffer) {
720 free(po);
721 return -1;
722 }
723
724 po->shadow_image =
725 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
726 po->shadow_buffer, w * 4);
727
728 if (!po->shadow_image) {
729 free(po->shadow_buffer);
730 free(po);
731 return -1;
732 }
733
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300734 output->renderer_state = po;
735
736 return 0;
737}
738
739WL_EXPORT void
740pixman_renderer_output_destroy(struct weston_output *output)
741{
742 struct pixman_output_state *po = get_output_state(output);
743
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200744 pixman_image_unref(po->shadow_image);
Ander Conselvan de Oliveira23e72b82013-01-25 15:13:06 +0200745
746 if (po->hw_buffer)
747 pixman_image_unref(po->hw_buffer);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200748
749 po->shadow_image = NULL;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300750 po->hw_buffer = NULL;
751
752 free(po);
753}