blob: eff720151367436fe77d5a7a226df6127db04c94 [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
Lubomir Rintelddc2b1e2013-12-12 12:57:56 +010045 struct wl_listener buffer_destroy_listener;
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +030046 struct wl_listener surface_destroy_listener;
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +030047 struct wl_listener renderer_destroy_listener;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030048};
49
50struct pixman_renderer {
51 struct weston_renderer base;
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +030052
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +020053 int repaint_debug;
54 pixman_image_t *debug_color;
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +030055 struct weston_binding *debug_binding;
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +030056
57 struct wl_signal destroy_signal;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030058};
59
60static inline struct pixman_output_state *
61get_output_state(struct weston_output *output)
62{
63 return (struct pixman_output_state *)output->renderer_state;
64}
65
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +030066static int
67pixman_renderer_create_surface(struct weston_surface *surface);
68
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030069static inline struct pixman_surface_state *
70get_surface_state(struct weston_surface *surface)
71{
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +030072 if (!surface->renderer_state)
73 pixman_renderer_create_surface(surface);
74
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030075 return (struct pixman_surface_state *)surface->renderer_state;
76}
77
78static inline struct pixman_renderer *
79get_renderer(struct weston_compositor *ec)
80{
81 return (struct pixman_renderer *)ec->renderer;
82}
83
84static int
85pixman_renderer_read_pixels(struct weston_output *output,
86 pixman_format_code_t format, void *pixels,
87 uint32_t x, uint32_t y,
88 uint32_t width, uint32_t height)
89{
90 struct pixman_output_state *po = get_output_state(output);
Alexander Larsson97af7922013-05-29 12:01:33 +020091 pixman_transform_t transform;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030092 pixman_image_t *out_buf;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030093
94 if (!po->hw_buffer) {
95 errno = ENODEV;
96 return -1;
97 }
98
99 out_buf = pixman_image_create_bits(format,
100 width,
101 height,
102 pixels,
103 (PIXMAN_FORMAT_BPP(format) / 8) * width);
104
Alexander Larsson97af7922013-05-29 12:01:33 +0200105 /* Caller expects vflipped source image */
106 pixman_transform_init_translate(&transform,
107 pixman_int_to_fixed (x),
108 pixman_int_to_fixed (y - pixman_image_get_height (po->hw_buffer)));
109 pixman_transform_scale(&transform, NULL,
110 pixman_fixed_1,
111 pixman_fixed_minus_1);
112 pixman_image_set_transform(po->hw_buffer, &transform);
113
114 pixman_image_composite32(PIXMAN_OP_SRC,
115 po->hw_buffer, /* src */
116 NULL /* mask */,
117 out_buf, /* dest */
118 0, 0, /* src_x, src_y */
119 0, 0, /* mask_x, mask_y */
120 0, 0, /* dest_x, dest_y */
121 pixman_image_get_width (po->hw_buffer), /* width */
122 pixman_image_get_height (po->hw_buffer) /* height */);
123 pixman_image_set_transform(po->hw_buffer, NULL);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300124
125 pixman_image_unref(out_buf);
126
127 return 0;
128}
129
Vasily Khoruzhick031fc872013-01-29 14:58:14 +0300130static void
Alexander Larsson1f206b42013-05-22 14:41:36 +0200131region_global_to_output(struct weston_output *output, pixman_region32_t *region)
132{
133 pixman_region32_translate(region, -output->x, -output->y);
Jason Ekstrand33ff6362013-10-27 22:25:01 -0500134 weston_transformed_region(output->width, output->height,
135 output->transform, output->current_scale,
136 region, region);
Vasily Khoruzhick031fc872013-01-29 14:58:14 +0300137}
138
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300139#define D2F(v) pixman_double_to_fixed((double)v)
140
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300141static void
Pekka Paalanen0b4c5352014-03-14 14:38:17 +0200142transform_apply_viewport(pixman_transform_t *transform,
143 struct weston_surface *surface)
144{
145 struct weston_buffer_viewport *vp = &surface->buffer_viewport;
146 double src_width, src_height;
147 double src_x, src_y;
148
149 if (vp->buffer.src_width == wl_fixed_from_int(-1)) {
150 if (vp->surface.width == -1)
151 return;
152
153 src_x = 0.0;
154 src_y = 0.0;
155 src_width = surface->width_from_buffer;
156 src_height = surface->height_from_buffer;
157 } else {
158 src_x = wl_fixed_to_double(vp->buffer.src_x);
159 src_y = wl_fixed_to_double(vp->buffer.src_y);
160 src_width = wl_fixed_to_double(vp->buffer.src_width);
161 src_height = wl_fixed_to_double(vp->buffer.src_height);
162 }
163
164 pixman_transform_scale(transform, NULL,
165 D2F(src_width / surface->width),
166 D2F(src_height / surface->height));
167 pixman_transform_translate(transform, NULL, D2F(src_x), D2F(src_y));
168}
169
170static void
Jason Ekstranda7af7042013-10-12 22:38:11 -0500171repaint_region(struct weston_view *ev, struct weston_output *output,
Alexander Larsson1f206b42013-05-22 14:41:36 +0200172 pixman_region32_t *region, pixman_region32_t *surf_region,
173 pixman_op_t pixman_op)
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300174{
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200175 struct pixman_renderer *pr =
176 (struct pixman_renderer *) output->compositor->renderer;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500177 struct pixman_surface_state *ps = get_surface_state(ev->surface);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300178 struct pixman_output_state *po = get_output_state(output);
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200179 struct weston_buffer_viewport *vp = &ev->surface->buffer_viewport;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300180 pixman_region32_t final_region;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500181 float view_x, view_y;
Alexander Larsson1f206b42013-05-22 14:41:36 +0200182 pixman_transform_t transform;
183 pixman_fixed_t fw, fh;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300184
185 /* The final region to be painted is the intersection of
186 * 'region' and 'surf_region'. However, 'region' is in the global
187 * coordinates, and 'surf_region' is in the surface-local
188 * coordinates
189 */
190 pixman_region32_init(&final_region);
Alexander Larsson1f206b42013-05-22 14:41:36 +0200191 if (surf_region) {
192 pixman_region32_copy(&final_region, surf_region);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300193
Alexander Larsson1f206b42013-05-22 14:41:36 +0200194 /* Convert from surface to global coordinates */
Jason Ekstranda7af7042013-10-12 22:38:11 -0500195 if (!ev->transform.enabled) {
196 pixman_region32_translate(&final_region, ev->geometry.x, ev->geometry.y);
Alexander Larsson1f206b42013-05-22 14:41:36 +0200197 } else {
Jason Ekstranda7af7042013-10-12 22:38:11 -0500198 weston_view_to_global_float(ev, 0, 0, &view_x, &view_y);
199 pixman_region32_translate(&final_region, (int)view_x, (int)view_y);
Alexander Larsson1f206b42013-05-22 14:41:36 +0200200 }
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300201
Alexander Larsson1f206b42013-05-22 14:41:36 +0200202 /* We need to paint the intersection */
203 pixman_region32_intersect(&final_region, &final_region, region);
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300204 } else {
Alexander Larsson1f206b42013-05-22 14:41:36 +0200205 /* If there is no surface region, just use the global region */
206 pixman_region32_copy(&final_region, region);
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300207 }
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300208
Alexander Larsson1f206b42013-05-22 14:41:36 +0200209 /* Convert from global to output coord */
210 region_global_to_output(output, &final_region);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300211
Alexander Larsson1f206b42013-05-22 14:41:36 +0200212 /* And clip to it */
213 pixman_image_set_clip_region32 (po->shadow_image, &final_region);
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200214
Alexander Larsson1f206b42013-05-22 14:41:36 +0200215 /* Set up the source transformation based on the surface
Alexander Larsson4ea95522013-05-22 14:41:37 +0200216 position, the output position/transform/scale and the client
217 specified buffer transform/scale */
Alexander Larsson1f206b42013-05-22 14:41:36 +0200218 pixman_transform_init_identity(&transform);
Alexander Larsson4ea95522013-05-22 14:41:37 +0200219 pixman_transform_scale(&transform, NULL,
Hardeningff39efa2013-09-18 23:56:35 +0200220 pixman_double_to_fixed ((double)1.0/output->current_scale),
221 pixman_double_to_fixed ((double)1.0/output->current_scale));
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200222
Alexander Larsson1f206b42013-05-22 14:41:36 +0200223 fw = pixman_int_to_fixed(output->width);
224 fh = pixman_int_to_fixed(output->height);
225 switch (output->transform) {
226 default:
227 case WL_OUTPUT_TRANSFORM_NORMAL:
228 case WL_OUTPUT_TRANSFORM_FLIPPED:
229 break;
230 case WL_OUTPUT_TRANSFORM_90:
231 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
232 pixman_transform_rotate(&transform, NULL, 0, -pixman_fixed_1);
233 pixman_transform_translate(&transform, NULL, 0, fh);
234 break;
235 case WL_OUTPUT_TRANSFORM_180:
236 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
237 pixman_transform_rotate(&transform, NULL, -pixman_fixed_1, 0);
238 pixman_transform_translate(&transform, NULL, fw, fh);
239 break;
240 case WL_OUTPUT_TRANSFORM_270:
241 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
242 pixman_transform_rotate(&transform, NULL, 0, pixman_fixed_1);
243 pixman_transform_translate(&transform, NULL, fw, 0);
244 break;
245 }
246
247 switch (output->transform) {
248 case WL_OUTPUT_TRANSFORM_FLIPPED:
249 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
250 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
251 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
252 pixman_transform_scale(&transform, NULL,
253 pixman_int_to_fixed (-1),
254 pixman_int_to_fixed (1));
255 pixman_transform_translate(&transform, NULL, fw, 0);
256 break;
257 }
258
259 pixman_transform_translate(&transform, NULL,
260 pixman_double_to_fixed (output->x),
261 pixman_double_to_fixed (output->y));
262
Jason Ekstranda7af7042013-10-12 22:38:11 -0500263 if (ev->transform.enabled) {
Alexander Larsson1f206b42013-05-22 14:41:36 +0200264 /* Pixman supports only 2D transform matrix, but Weston uses 3D,
265 * so we're omitting Z coordinate here
266 */
267 pixman_transform_t surface_transform = {{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500268 { D2F(ev->transform.matrix.d[0]),
269 D2F(ev->transform.matrix.d[4]),
270 D2F(ev->transform.matrix.d[12]),
Alexander Larsson1f206b42013-05-22 14:41:36 +0200271 },
Jason Ekstranda7af7042013-10-12 22:38:11 -0500272 { D2F(ev->transform.matrix.d[1]),
273 D2F(ev->transform.matrix.d[5]),
274 D2F(ev->transform.matrix.d[13]),
Alexander Larsson1f206b42013-05-22 14:41:36 +0200275 },
Jason Ekstranda7af7042013-10-12 22:38:11 -0500276 { D2F(ev->transform.matrix.d[3]),
277 D2F(ev->transform.matrix.d[7]),
278 D2F(ev->transform.matrix.d[15]),
Alexander Larsson1f206b42013-05-22 14:41:36 +0200279 }
280 }};
281
282 pixman_transform_invert(&surface_transform, &surface_transform);
283 pixman_transform_multiply (&transform, &surface_transform, &transform);
284 } else {
285 pixman_transform_translate(&transform, NULL,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500286 pixman_double_to_fixed ((double)-ev->geometry.x),
287 pixman_double_to_fixed ((double)-ev->geometry.y));
Alexander Larsson1f206b42013-05-22 14:41:36 +0200288 }
289
Pekka Paalanen0b4c5352014-03-14 14:38:17 +0200290 transform_apply_viewport(&transform, ev->surface);
Jonny Lambfa1b3052013-11-26 18:19:47 +0100291
Jason Ekstrand50fba972014-02-25 21:54:59 -0600292 fw = pixman_int_to_fixed(ev->surface->width);
293 fh = pixman_int_to_fixed(ev->surface->height);
Alexander Larsson1f206b42013-05-22 14:41:36 +0200294
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200295 switch (vp->buffer.transform) {
Alexander Larsson1f206b42013-05-22 14:41:36 +0200296 case WL_OUTPUT_TRANSFORM_FLIPPED:
297 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
298 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
299 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
300 pixman_transform_scale(&transform, NULL,
301 pixman_int_to_fixed (-1),
302 pixman_int_to_fixed (1));
303 pixman_transform_translate(&transform, NULL, fw, 0);
304 break;
305 }
306
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200307 switch (vp->buffer.transform) {
Alexander Larsson1f206b42013-05-22 14:41:36 +0200308 default:
309 case WL_OUTPUT_TRANSFORM_NORMAL:
310 case WL_OUTPUT_TRANSFORM_FLIPPED:
311 break;
312 case WL_OUTPUT_TRANSFORM_90:
313 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
314 pixman_transform_rotate(&transform, NULL, 0, pixman_fixed_1);
315 pixman_transform_translate(&transform, NULL, fh, 0);
316 break;
317 case WL_OUTPUT_TRANSFORM_180:
318 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
319 pixman_transform_rotate(&transform, NULL, -pixman_fixed_1, 0);
320 pixman_transform_translate(&transform, NULL, fw, fh);
321 break;
322 case WL_OUTPUT_TRANSFORM_270:
323 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
324 pixman_transform_rotate(&transform, NULL, 0, -pixman_fixed_1);
325 pixman_transform_translate(&transform, NULL, 0, fw);
326 break;
327 }
328
Jason Ekstrand50fba972014-02-25 21:54:59 -0600329 pixman_transform_scale(&transform, NULL,
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200330 pixman_double_to_fixed(vp->buffer.scale),
331 pixman_double_to_fixed(vp->buffer.scale));
Jason Ekstrand50fba972014-02-25 21:54:59 -0600332
Alexander Larsson1f206b42013-05-22 14:41:36 +0200333 pixman_image_set_transform(ps->image, &transform);
334
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200335 if (ev->transform.enabled || output->current_scale != vp->buffer.scale)
Alexander Larsson1f206b42013-05-22 14:41:36 +0200336 pixman_image_set_filter(ps->image, PIXMAN_FILTER_BILINEAR, NULL, 0);
337 else
338 pixman_image_set_filter(ps->image, PIXMAN_FILTER_NEAREST, NULL, 0);
339
Neil Robertse5051712013-11-13 15:44:06 +0000340 if (ps->buffer_ref.buffer)
341 wl_shm_buffer_begin_access(ps->buffer_ref.buffer->shm_buffer);
342
Manuel Bachmannb1fff412014-04-05 05:31:37 +0200343 pixman_image_t *mask_image;
344 if (ev->alpha < 1.0) {
345 pixman_color_t mask = { 0x0000, 0x0000, 0x0000, 0xffff*ev->alpha };
346 mask_image = pixman_image_create_solid_fill(&mask);
347 } else
348 mask_image = NULL;
349
Alexander Larsson1f206b42013-05-22 14:41:36 +0200350 pixman_image_composite32(pixman_op,
351 ps->image, /* src */
Manuel Bachmannb1fff412014-04-05 05:31:37 +0200352 mask_image, /* mask */
Alexander Larsson1f206b42013-05-22 14:41:36 +0200353 po->shadow_image, /* dest */
354 0, 0, /* src_x, src_y */
355 0, 0, /* mask_x, mask_y */
356 0, 0, /* dest_x, dest_y */
357 pixman_image_get_width (po->shadow_image), /* width */
358 pixman_image_get_height (po->shadow_image) /* height */);
359
Neil Robertse5051712013-11-13 15:44:06 +0000360 if (ps->buffer_ref.buffer)
361 wl_shm_buffer_end_access(ps->buffer_ref.buffer->shm_buffer);
362
Alexander Larsson1f206b42013-05-22 14:41:36 +0200363 if (pr->repaint_debug)
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200364 pixman_image_composite32(PIXMAN_OP_OVER,
Alexander Larsson1f206b42013-05-22 14:41:36 +0200365 pr->debug_color, /* src */
366 NULL /* mask */,
367 po->shadow_image, /* dest */
368 0, 0, /* src_x, src_y */
369 0, 0, /* mask_x, mask_y */
370 0, 0, /* dest_x, dest_y */
371 pixman_image_get_width (po->shadow_image), /* width */
372 pixman_image_get_height (po->shadow_image) /* height */);
373
374 pixman_image_set_clip_region32 (po->shadow_image, NULL);
375
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300376 pixman_region32_fini(&final_region);
377}
378
379static void
Jason Ekstranda7af7042013-10-12 22:38:11 -0500380draw_view(struct weston_view *ev, struct weston_output *output,
381 pixman_region32_t *damage) /* in global coordinates */
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300382{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500383 struct pixman_surface_state *ps = get_surface_state(ev->surface);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300384 /* repaint bounding region in global coordinates: */
385 pixman_region32_t repaint;
386 /* non-opaque region in surface coordinates: */
387 pixman_region32_t surface_blend;
388
389 /* No buffer attached */
390 if (!ps->image)
391 return;
392
393 pixman_region32_init(&repaint);
394 pixman_region32_intersect(&repaint,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500395 &ev->transform.boundingbox, damage);
396 pixman_region32_subtract(&repaint, &repaint, &ev->clip);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300397
398 if (!pixman_region32_not_empty(&repaint))
399 goto out;
400
401 if (output->zoom.active) {
402 weston_log("pixman renderer does not support zoom\n");
403 goto out;
404 }
405
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300406 /* TODO: Implement repaint_region_complex() using pixman_composite_trapezoids() */
Jason Ekstranda7af7042013-10-12 22:38:11 -0500407 if (ev->transform.enabled &&
408 ev->transform.matrix.type != WESTON_MATRIX_TRANSFORM_TRANSLATE) {
409 repaint_region(ev, output, &repaint, NULL, PIXMAN_OP_OVER);
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300410 } else {
411 /* blended region is whole surface minus opaque region: */
412 pixman_region32_init_rect(&surface_blend, 0, 0,
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600413 ev->surface->width, ev->surface->height);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500414 pixman_region32_subtract(&surface_blend, &surface_blend, &ev->surface->opaque);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300415
Jason Ekstranda7af7042013-10-12 22:38:11 -0500416 if (pixman_region32_not_empty(&ev->surface->opaque)) {
417 repaint_region(ev, output, &repaint, &ev->surface->opaque, PIXMAN_OP_SRC);
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300418 }
419
420 if (pixman_region32_not_empty(&surface_blend)) {
Jason Ekstranda7af7042013-10-12 22:38:11 -0500421 repaint_region(ev, output, &repaint, &surface_blend, PIXMAN_OP_OVER);
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300422 }
423 pixman_region32_fini(&surface_blend);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300424 }
425
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300426
427out:
428 pixman_region32_fini(&repaint);
429}
430static void
431repaint_surfaces(struct weston_output *output, pixman_region32_t *damage)
432{
433 struct weston_compositor *compositor = output->compositor;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500434 struct weston_view *view;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300435
Jason Ekstranda7af7042013-10-12 22:38:11 -0500436 wl_list_for_each_reverse(view, &compositor->view_list, link)
437 if (view->plane == &compositor->primary_plane)
438 draw_view(view, output, damage);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300439}
440
441static void
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200442copy_to_hw_buffer(struct weston_output *output, pixman_region32_t *region)
443{
444 struct pixman_output_state *po = get_output_state(output);
Alexander Larsson1f206b42013-05-22 14:41:36 +0200445 pixman_region32_t output_region;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200446
Alexander Larsson1f206b42013-05-22 14:41:36 +0200447 pixman_region32_init(&output_region);
448 pixman_region32_copy(&output_region, region);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200449
Alexander Larsson1f206b42013-05-22 14:41:36 +0200450 region_global_to_output(output, &output_region);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200451
Alexander Larsson1f206b42013-05-22 14:41:36 +0200452 pixman_image_set_clip_region32 (po->hw_buffer, &output_region);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200453
Alexander Larsson1f206b42013-05-22 14:41:36 +0200454 pixman_image_composite32(PIXMAN_OP_SRC,
455 po->shadow_image, /* src */
456 NULL /* mask */,
457 po->hw_buffer, /* dest */
458 0, 0, /* src_x, src_y */
459 0, 0, /* mask_x, mask_y */
460 0, 0, /* dest_x, dest_y */
461 pixman_image_get_width (po->hw_buffer), /* width */
462 pixman_image_get_height (po->hw_buffer) /* height */);
463
464 pixman_image_set_clip_region32 (po->hw_buffer, NULL);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200465}
466
467static void
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300468pixman_renderer_repaint_output(struct weston_output *output,
469 pixman_region32_t *output_damage)
470{
471 struct pixman_output_state *po = get_output_state(output);
472
473 if (!po->hw_buffer)
474 return;
475
476 repaint_surfaces(output, output_damage);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200477 copy_to_hw_buffer(output, output_damage);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300478
479 pixman_region32_copy(&output->previous_damage, output_damage);
480 wl_signal_emit(&output->frame_signal, output);
481
482 /* Actual flip should be done by caller */
483}
484
485static void
486pixman_renderer_flush_damage(struct weston_surface *surface)
487{
488 /* No-op for pixman renderer */
489}
490
491static void
Lubomir Rintelddc2b1e2013-12-12 12:57:56 +0100492buffer_state_handle_buffer_destroy(struct wl_listener *listener, void *data)
493{
494 struct pixman_surface_state *ps;
495
496 ps = container_of(listener, struct pixman_surface_state,
497 buffer_destroy_listener);
498
499 if (ps->image) {
500 pixman_image_unref(ps->image);
501 ps->image = NULL;
502 }
503
504 ps->buffer_destroy_listener.notify = NULL;
505}
506
507static void
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500508pixman_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300509{
510 struct pixman_surface_state *ps = get_surface_state(es);
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500511 struct wl_shm_buffer *shm_buffer;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300512 pixman_format_code_t pixman_format;
513
514 weston_buffer_reference(&ps->buffer_ref, buffer);
515
Lubomir Rintelddc2b1e2013-12-12 12:57:56 +0100516 if (ps->buffer_destroy_listener.notify) {
517 wl_list_remove(&ps->buffer_destroy_listener.link);
518 ps->buffer_destroy_listener.notify = NULL;
519 }
520
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300521 if (ps->image) {
522 pixman_image_unref(ps->image);
523 ps->image = NULL;
524 }
525
526 if (!buffer)
527 return;
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500528
529 shm_buffer = wl_shm_buffer_get(buffer->resource);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300530
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500531 if (! shm_buffer) {
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300532 weston_log("Pixman renderer supports only SHM buffers\n");
533 weston_buffer_reference(&ps->buffer_ref, NULL);
534 return;
535 }
536
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500537 switch (wl_shm_buffer_get_format(shm_buffer)) {
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300538 case WL_SHM_FORMAT_XRGB8888:
539 pixman_format = PIXMAN_x8r8g8b8;
540 break;
541 case WL_SHM_FORMAT_ARGB8888:
542 pixman_format = PIXMAN_a8r8g8b8;
543 break;
Tomeu Vizoso1c1fc292013-08-06 20:05:56 +0200544 case WL_SHM_FORMAT_RGB565:
545 pixman_format = PIXMAN_r5g6b5;
546 break;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300547 default:
548 weston_log("Unsupported SHM buffer format\n");
549 weston_buffer_reference(&ps->buffer_ref, NULL);
550 return;
551 break;
552 }
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500553
554 buffer->shm_buffer = shm_buffer;
555 buffer->width = wl_shm_buffer_get_width(shm_buffer);
556 buffer->height = wl_shm_buffer_get_height(shm_buffer);
557
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300558 ps->image = pixman_image_create_bits(pixman_format,
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500559 buffer->width, buffer->height,
560 wl_shm_buffer_get_data(shm_buffer),
561 wl_shm_buffer_get_stride(shm_buffer));
Lubomir Rintelddc2b1e2013-12-12 12:57:56 +0100562
563 ps->buffer_destroy_listener.notify =
564 buffer_state_handle_buffer_destroy;
565 wl_signal_add(&buffer->destroy_signal,
566 &ps->buffer_destroy_listener);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300567}
568
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300569static void
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300570pixman_renderer_surface_state_destroy(struct pixman_surface_state *ps)
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300571{
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300572 wl_list_remove(&ps->surface_destroy_listener.link);
573 wl_list_remove(&ps->renderer_destroy_listener.link);
Lubomir Rintelddc2b1e2013-12-12 12:57:56 +0100574 if (ps->buffer_destroy_listener.notify) {
575 wl_list_remove(&ps->buffer_destroy_listener.link);
576 ps->buffer_destroy_listener.notify = NULL;
577 }
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300578
579 ps->surface->renderer_state = NULL;
580
581 if (ps->image) {
582 pixman_image_unref(ps->image);
583 ps->image = NULL;
584 }
585 weston_buffer_reference(&ps->buffer_ref, NULL);
586 free(ps);
587}
588
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300589static void
590surface_state_handle_surface_destroy(struct wl_listener *listener, void *data)
591{
592 struct pixman_surface_state *ps;
593
594 ps = container_of(listener, struct pixman_surface_state,
595 surface_destroy_listener);
596
597 pixman_renderer_surface_state_destroy(ps);
598}
599
600static void
601surface_state_handle_renderer_destroy(struct wl_listener *listener, void *data)
602{
603 struct pixman_surface_state *ps;
604
605 ps = container_of(listener, struct pixman_surface_state,
606 renderer_destroy_listener);
607
608 pixman_renderer_surface_state_destroy(ps);
609}
610
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300611static int
612pixman_renderer_create_surface(struct weston_surface *surface)
613{
614 struct pixman_surface_state *ps;
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300615 struct pixman_renderer *pr = get_renderer(surface->compositor);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300616
617 ps = calloc(1, sizeof *ps);
618 if (!ps)
619 return -1;
620
621 surface->renderer_state = ps;
622
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300623 ps->surface = surface;
624
625 ps->surface_destroy_listener.notify =
626 surface_state_handle_surface_destroy;
627 wl_signal_add(&surface->destroy_signal,
628 &ps->surface_destroy_listener);
629
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300630 ps->renderer_destroy_listener.notify =
631 surface_state_handle_renderer_destroy;
632 wl_signal_add(&pr->destroy_signal,
633 &ps->renderer_destroy_listener);
634
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300635 return 0;
636}
637
638static void
639pixman_renderer_surface_set_color(struct weston_surface *es,
640 float red, float green, float blue, float alpha)
641{
642 struct pixman_surface_state *ps = get_surface_state(es);
643 pixman_color_t color;
644
645 color.red = red * 0xffff;
646 color.green = green * 0xffff;
647 color.blue = blue * 0xffff;
648 color.alpha = alpha * 0xffff;
649
650 if (ps->image) {
651 pixman_image_unref(ps->image);
652 ps->image = NULL;
653 }
654
655 ps->image = pixman_image_create_solid_fill(&color);
656}
657
658static void
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300659pixman_renderer_destroy(struct weston_compositor *ec)
660{
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +0300661 struct pixman_renderer *pr = get_renderer(ec);
662
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300663 wl_signal_emit(&pr->destroy_signal, pr);
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +0300664 weston_binding_destroy(pr->debug_binding);
665 free(pr);
666
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300667 ec->renderer = NULL;
668}
669
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200670static void
Kristian Høgsberge3148752013-05-06 23:19:49 -0400671debug_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200672 void *data)
673{
674 struct weston_compositor *ec = data;
675 struct pixman_renderer *pr = (struct pixman_renderer *) ec->renderer;
676
677 pr->repaint_debug ^= 1;
678
679 if (pr->repaint_debug) {
680 pixman_color_t red = {
681 0x3fff, 0x0000, 0x0000, 0x3fff
682 };
683
684 pr->debug_color = pixman_image_create_solid_fill(&red);
685 } else {
686 pixman_image_unref(pr->debug_color);
687 weston_compositor_damage_all(ec);
688 }
689}
690
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300691WL_EXPORT int
692pixman_renderer_init(struct weston_compositor *ec)
693{
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200694 struct pixman_renderer *renderer;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300695
Ander Conselvan de Oliveirac68b1082013-10-25 16:26:31 +0300696 renderer = calloc(1, sizeof *renderer);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300697 if (renderer == NULL)
698 return -1;
699
Philipp Brüschweilerf3e39f92013-03-08 20:35:39 +0100700 renderer->repaint_debug = 0;
701 renderer->debug_color = NULL;
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200702 renderer->base.read_pixels = pixman_renderer_read_pixels;
703 renderer->base.repaint_output = pixman_renderer_repaint_output;
704 renderer->base.flush_damage = pixman_renderer_flush_damage;
705 renderer->base.attach = pixman_renderer_attach;
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200706 renderer->base.surface_set_color = pixman_renderer_surface_set_color;
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200707 renderer->base.destroy = pixman_renderer_destroy;
708 ec->renderer = &renderer->base;
Pekka Paalanen7bb65102013-05-22 18:03:04 +0300709 ec->capabilities |= WESTON_CAP_ROTATION_ANY;
Pekka Paalanen4fc5dd02013-05-22 18:03:05 +0300710 ec->capabilities |= WESTON_CAP_CAPTURE_YFLIP;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300711
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +0300712 renderer->debug_binding =
713 weston_compositor_add_debug_binding(ec, KEY_R,
714 debug_binding, ec);
Tomeu Vizoso1c1fc292013-08-06 20:05:56 +0200715
716 wl_display_add_shm_format(ec->wl_display, WL_SHM_FORMAT_RGB565);
717
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300718 wl_signal_init(&renderer->destroy_signal);
719
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300720 return 0;
721}
722
723WL_EXPORT void
724pixman_renderer_output_set_buffer(struct weston_output *output, pixman_image_t *buffer)
725{
726 struct pixman_output_state *po = get_output_state(output);
727
728 if (po->hw_buffer)
729 pixman_image_unref(po->hw_buffer);
730 po->hw_buffer = buffer;
731
732 if (po->hw_buffer) {
733 output->compositor->read_format = pixman_image_get_format(po->hw_buffer);
734 pixman_image_ref(po->hw_buffer);
735 }
736}
737
738WL_EXPORT int
739pixman_renderer_output_create(struct weston_output *output)
740{
741 struct pixman_output_state *po = calloc(1, sizeof *po);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200742 int w, h;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300743
744 if (!po)
745 return -1;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200746
747 /* set shadow image transformation */
Hardeningff39efa2013-09-18 23:56:35 +0200748 w = output->current_mode->width;
749 h = output->current_mode->height;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200750
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200751 po->shadow_buffer = malloc(w * h * 4);
752
753 if (!po->shadow_buffer) {
754 free(po);
755 return -1;
756 }
757
758 po->shadow_image =
759 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
760 po->shadow_buffer, w * 4);
761
762 if (!po->shadow_image) {
763 free(po->shadow_buffer);
764 free(po);
765 return -1;
766 }
767
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300768 output->renderer_state = po;
769
770 return 0;
771}
772
773WL_EXPORT void
774pixman_renderer_output_destroy(struct weston_output *output)
775{
776 struct pixman_output_state *po = get_output_state(output);
777
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200778 pixman_image_unref(po->shadow_image);
Ander Conselvan de Oliveira23e72b82013-01-25 15:13:06 +0200779
780 if (po->hw_buffer)
781 pixman_image_unref(po->hw_buffer);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200782
783 po->shadow_image = NULL;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300784 po->hw_buffer = NULL;
785
786 free(po);
787}