blob: 41738a6b2abf9a8e8adfedde2e023238001c5084 [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
Jason Ekstranda7af7042013-10-12 22:38:11 -0500142repaint_region(struct weston_view *ev, struct weston_output *output,
Alexander Larsson1f206b42013-05-22 14:41:36 +0200143 pixman_region32_t *region, pixman_region32_t *surf_region,
144 pixman_op_t pixman_op)
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300145{
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200146 struct pixman_renderer *pr =
147 (struct pixman_renderer *) output->compositor->renderer;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500148 struct pixman_surface_state *ps = get_surface_state(ev->surface);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300149 struct pixman_output_state *po = get_output_state(output);
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200150 struct weston_buffer_viewport *vp = &ev->surface->buffer_viewport;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300151 pixman_region32_t final_region;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500152 float view_x, view_y;
Alexander Larsson1f206b42013-05-22 14:41:36 +0200153 pixman_transform_t transform;
154 pixman_fixed_t fw, fh;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300155
156 /* The final region to be painted is the intersection of
157 * 'region' and 'surf_region'. However, 'region' is in the global
158 * coordinates, and 'surf_region' is in the surface-local
159 * coordinates
160 */
161 pixman_region32_init(&final_region);
Alexander Larsson1f206b42013-05-22 14:41:36 +0200162 if (surf_region) {
163 pixman_region32_copy(&final_region, surf_region);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300164
Alexander Larsson1f206b42013-05-22 14:41:36 +0200165 /* Convert from surface to global coordinates */
Jason Ekstranda7af7042013-10-12 22:38:11 -0500166 if (!ev->transform.enabled) {
167 pixman_region32_translate(&final_region, ev->geometry.x, ev->geometry.y);
Alexander Larsson1f206b42013-05-22 14:41:36 +0200168 } else {
Jason Ekstranda7af7042013-10-12 22:38:11 -0500169 weston_view_to_global_float(ev, 0, 0, &view_x, &view_y);
170 pixman_region32_translate(&final_region, (int)view_x, (int)view_y);
Alexander Larsson1f206b42013-05-22 14:41:36 +0200171 }
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300172
Alexander Larsson1f206b42013-05-22 14:41:36 +0200173 /* We need to paint the intersection */
174 pixman_region32_intersect(&final_region, &final_region, region);
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300175 } else {
Alexander Larsson1f206b42013-05-22 14:41:36 +0200176 /* If there is no surface region, just use the global region */
177 pixman_region32_copy(&final_region, region);
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300178 }
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300179
Alexander Larsson1f206b42013-05-22 14:41:36 +0200180 /* Convert from global to output coord */
181 region_global_to_output(output, &final_region);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300182
Alexander Larsson1f206b42013-05-22 14:41:36 +0200183 /* And clip to it */
184 pixman_image_set_clip_region32 (po->shadow_image, &final_region);
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200185
Alexander Larsson1f206b42013-05-22 14:41:36 +0200186 /* Set up the source transformation based on the surface
Alexander Larsson4ea95522013-05-22 14:41:37 +0200187 position, the output position/transform/scale and the client
188 specified buffer transform/scale */
Alexander Larsson1f206b42013-05-22 14:41:36 +0200189 pixman_transform_init_identity(&transform);
Alexander Larsson4ea95522013-05-22 14:41:37 +0200190 pixman_transform_scale(&transform, NULL,
Hardeningff39efa2013-09-18 23:56:35 +0200191 pixman_double_to_fixed ((double)1.0/output->current_scale),
192 pixman_double_to_fixed ((double)1.0/output->current_scale));
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200193
Alexander Larsson1f206b42013-05-22 14:41:36 +0200194 fw = pixman_int_to_fixed(output->width);
195 fh = pixman_int_to_fixed(output->height);
196 switch (output->transform) {
197 default:
198 case WL_OUTPUT_TRANSFORM_NORMAL:
199 case WL_OUTPUT_TRANSFORM_FLIPPED:
200 break;
201 case WL_OUTPUT_TRANSFORM_90:
202 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
203 pixman_transform_rotate(&transform, NULL, 0, -pixman_fixed_1);
204 pixman_transform_translate(&transform, NULL, 0, fh);
205 break;
206 case WL_OUTPUT_TRANSFORM_180:
207 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
208 pixman_transform_rotate(&transform, NULL, -pixman_fixed_1, 0);
209 pixman_transform_translate(&transform, NULL, fw, fh);
210 break;
211 case WL_OUTPUT_TRANSFORM_270:
212 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
213 pixman_transform_rotate(&transform, NULL, 0, pixman_fixed_1);
214 pixman_transform_translate(&transform, NULL, fw, 0);
215 break;
216 }
217
218 switch (output->transform) {
219 case WL_OUTPUT_TRANSFORM_FLIPPED:
220 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
221 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
222 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
223 pixman_transform_scale(&transform, NULL,
224 pixman_int_to_fixed (-1),
225 pixman_int_to_fixed (1));
226 pixman_transform_translate(&transform, NULL, fw, 0);
227 break;
228 }
229
230 pixman_transform_translate(&transform, NULL,
231 pixman_double_to_fixed (output->x),
232 pixman_double_to_fixed (output->y));
233
Jason Ekstranda7af7042013-10-12 22:38:11 -0500234 if (ev->transform.enabled) {
Alexander Larsson1f206b42013-05-22 14:41:36 +0200235 /* Pixman supports only 2D transform matrix, but Weston uses 3D,
236 * so we're omitting Z coordinate here
237 */
238 pixman_transform_t surface_transform = {{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500239 { D2F(ev->transform.matrix.d[0]),
240 D2F(ev->transform.matrix.d[4]),
241 D2F(ev->transform.matrix.d[12]),
Alexander Larsson1f206b42013-05-22 14:41:36 +0200242 },
Jason Ekstranda7af7042013-10-12 22:38:11 -0500243 { D2F(ev->transform.matrix.d[1]),
244 D2F(ev->transform.matrix.d[5]),
245 D2F(ev->transform.matrix.d[13]),
Alexander Larsson1f206b42013-05-22 14:41:36 +0200246 },
Jason Ekstranda7af7042013-10-12 22:38:11 -0500247 { D2F(ev->transform.matrix.d[3]),
248 D2F(ev->transform.matrix.d[7]),
249 D2F(ev->transform.matrix.d[15]),
Alexander Larsson1f206b42013-05-22 14:41:36 +0200250 }
251 }};
252
253 pixman_transform_invert(&surface_transform, &surface_transform);
254 pixman_transform_multiply (&transform, &surface_transform, &transform);
255 } else {
256 pixman_transform_translate(&transform, NULL,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500257 pixman_double_to_fixed ((double)-ev->geometry.x),
258 pixman_double_to_fixed ((double)-ev->geometry.y));
Alexander Larsson1f206b42013-05-22 14:41:36 +0200259 }
260
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200261 if (vp->buffer.viewport_set) {
Pekka Paalanenb0420ae2014-01-08 15:39:17 +0200262 double viewport_x, viewport_y, viewport_width, viewport_height;
Jonny Lambfa1b3052013-11-26 18:19:47 +0100263 double ratio_x, ratio_y;
Alexander Larsson1f206b42013-05-22 14:41:36 +0200264
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200265 viewport_x = wl_fixed_to_double(vp->buffer.src_x);
266 viewport_y = wl_fixed_to_double(vp->buffer.src_y);
267 viewport_width = wl_fixed_to_double(vp->buffer.src_width);
268 viewport_height = wl_fixed_to_double(vp->buffer.src_height);
Jonny Lambfa1b3052013-11-26 18:19:47 +0100269
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200270 ratio_x = viewport_width / vp->surface.width;
271 ratio_y = viewport_height / vp->surface.height;
Jonny Lambfa1b3052013-11-26 18:19:47 +0100272
273 pixman_transform_scale(&transform, NULL,
274 pixman_double_to_fixed(ratio_x),
275 pixman_double_to_fixed(ratio_y));
Pekka Paalanenb0420ae2014-01-08 15:39:17 +0200276 pixman_transform_translate(&transform, NULL, pixman_double_to_fixed(viewport_x),
277 pixman_double_to_fixed(viewport_y));
Jonny Lambfa1b3052013-11-26 18:19:47 +0100278 }
279
Jason Ekstrand50fba972014-02-25 21:54:59 -0600280 fw = pixman_int_to_fixed(ev->surface->width);
281 fh = pixman_int_to_fixed(ev->surface->height);
Alexander Larsson1f206b42013-05-22 14:41:36 +0200282
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200283 switch (vp->buffer.transform) {
Alexander Larsson1f206b42013-05-22 14:41:36 +0200284 case WL_OUTPUT_TRANSFORM_FLIPPED:
285 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
286 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
287 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
288 pixman_transform_scale(&transform, NULL,
289 pixman_int_to_fixed (-1),
290 pixman_int_to_fixed (1));
291 pixman_transform_translate(&transform, NULL, fw, 0);
292 break;
293 }
294
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200295 switch (vp->buffer.transform) {
Alexander Larsson1f206b42013-05-22 14:41:36 +0200296 default:
297 case WL_OUTPUT_TRANSFORM_NORMAL:
298 case WL_OUTPUT_TRANSFORM_FLIPPED:
299 break;
300 case WL_OUTPUT_TRANSFORM_90:
301 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
302 pixman_transform_rotate(&transform, NULL, 0, pixman_fixed_1);
303 pixman_transform_translate(&transform, NULL, fh, 0);
304 break;
305 case WL_OUTPUT_TRANSFORM_180:
306 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
307 pixman_transform_rotate(&transform, NULL, -pixman_fixed_1, 0);
308 pixman_transform_translate(&transform, NULL, fw, fh);
309 break;
310 case WL_OUTPUT_TRANSFORM_270:
311 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
312 pixman_transform_rotate(&transform, NULL, 0, -pixman_fixed_1);
313 pixman_transform_translate(&transform, NULL, 0, fw);
314 break;
315 }
316
Jason Ekstrand50fba972014-02-25 21:54:59 -0600317 pixman_transform_scale(&transform, NULL,
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200318 pixman_double_to_fixed(vp->buffer.scale),
319 pixman_double_to_fixed(vp->buffer.scale));
Jason Ekstrand50fba972014-02-25 21:54:59 -0600320
Alexander Larsson1f206b42013-05-22 14:41:36 +0200321 pixman_image_set_transform(ps->image, &transform);
322
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200323 if (ev->transform.enabled || output->current_scale != vp->buffer.scale)
Alexander Larsson1f206b42013-05-22 14:41:36 +0200324 pixman_image_set_filter(ps->image, PIXMAN_FILTER_BILINEAR, NULL, 0);
325 else
326 pixman_image_set_filter(ps->image, PIXMAN_FILTER_NEAREST, NULL, 0);
327
Neil Robertse5051712013-11-13 15:44:06 +0000328 if (ps->buffer_ref.buffer)
329 wl_shm_buffer_begin_access(ps->buffer_ref.buffer->shm_buffer);
330
Alexander Larsson1f206b42013-05-22 14:41:36 +0200331 pixman_image_composite32(pixman_op,
332 ps->image, /* src */
333 NULL /* mask */,
334 po->shadow_image, /* dest */
335 0, 0, /* src_x, src_y */
336 0, 0, /* mask_x, mask_y */
337 0, 0, /* dest_x, dest_y */
338 pixman_image_get_width (po->shadow_image), /* width */
339 pixman_image_get_height (po->shadow_image) /* height */);
340
Neil Robertse5051712013-11-13 15:44:06 +0000341 if (ps->buffer_ref.buffer)
342 wl_shm_buffer_end_access(ps->buffer_ref.buffer->shm_buffer);
343
Alexander Larsson1f206b42013-05-22 14:41:36 +0200344 if (pr->repaint_debug)
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200345 pixman_image_composite32(PIXMAN_OP_OVER,
Alexander Larsson1f206b42013-05-22 14:41:36 +0200346 pr->debug_color, /* src */
347 NULL /* mask */,
348 po->shadow_image, /* dest */
349 0, 0, /* src_x, src_y */
350 0, 0, /* mask_x, mask_y */
351 0, 0, /* dest_x, dest_y */
352 pixman_image_get_width (po->shadow_image), /* width */
353 pixman_image_get_height (po->shadow_image) /* height */);
354
355 pixman_image_set_clip_region32 (po->shadow_image, NULL);
356
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300357 pixman_region32_fini(&final_region);
358}
359
360static void
Jason Ekstranda7af7042013-10-12 22:38:11 -0500361draw_view(struct weston_view *ev, struct weston_output *output,
362 pixman_region32_t *damage) /* in global coordinates */
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300363{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500364 struct pixman_surface_state *ps = get_surface_state(ev->surface);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300365 /* repaint bounding region in global coordinates: */
366 pixman_region32_t repaint;
367 /* non-opaque region in surface coordinates: */
368 pixman_region32_t surface_blend;
369
370 /* No buffer attached */
371 if (!ps->image)
372 return;
373
374 pixman_region32_init(&repaint);
375 pixman_region32_intersect(&repaint,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500376 &ev->transform.boundingbox, damage);
377 pixman_region32_subtract(&repaint, &repaint, &ev->clip);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300378
379 if (!pixman_region32_not_empty(&repaint))
380 goto out;
381
382 if (output->zoom.active) {
383 weston_log("pixman renderer does not support zoom\n");
384 goto out;
385 }
386
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300387 /* TODO: Implement repaint_region_complex() using pixman_composite_trapezoids() */
Jason Ekstranda7af7042013-10-12 22:38:11 -0500388 if (ev->transform.enabled &&
389 ev->transform.matrix.type != WESTON_MATRIX_TRANSFORM_TRANSLATE) {
390 repaint_region(ev, output, &repaint, NULL, PIXMAN_OP_OVER);
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300391 } else {
392 /* blended region is whole surface minus opaque region: */
393 pixman_region32_init_rect(&surface_blend, 0, 0,
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600394 ev->surface->width, ev->surface->height);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500395 pixman_region32_subtract(&surface_blend, &surface_blend, &ev->surface->opaque);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300396
Jason Ekstranda7af7042013-10-12 22:38:11 -0500397 if (pixman_region32_not_empty(&ev->surface->opaque)) {
398 repaint_region(ev, output, &repaint, &ev->surface->opaque, PIXMAN_OP_SRC);
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300399 }
400
401 if (pixman_region32_not_empty(&surface_blend)) {
Jason Ekstranda7af7042013-10-12 22:38:11 -0500402 repaint_region(ev, output, &repaint, &surface_blend, PIXMAN_OP_OVER);
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300403 }
404 pixman_region32_fini(&surface_blend);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300405 }
406
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300407
408out:
409 pixman_region32_fini(&repaint);
410}
411static void
412repaint_surfaces(struct weston_output *output, pixman_region32_t *damage)
413{
414 struct weston_compositor *compositor = output->compositor;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500415 struct weston_view *view;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300416
Jason Ekstranda7af7042013-10-12 22:38:11 -0500417 wl_list_for_each_reverse(view, &compositor->view_list, link)
418 if (view->plane == &compositor->primary_plane)
419 draw_view(view, output, damage);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300420}
421
422static void
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200423copy_to_hw_buffer(struct weston_output *output, pixman_region32_t *region)
424{
425 struct pixman_output_state *po = get_output_state(output);
Alexander Larsson1f206b42013-05-22 14:41:36 +0200426 pixman_region32_t output_region;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200427
Alexander Larsson1f206b42013-05-22 14:41:36 +0200428 pixman_region32_init(&output_region);
429 pixman_region32_copy(&output_region, region);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200430
Alexander Larsson1f206b42013-05-22 14:41:36 +0200431 region_global_to_output(output, &output_region);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200432
Alexander Larsson1f206b42013-05-22 14:41:36 +0200433 pixman_image_set_clip_region32 (po->hw_buffer, &output_region);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200434
Alexander Larsson1f206b42013-05-22 14:41:36 +0200435 pixman_image_composite32(PIXMAN_OP_SRC,
436 po->shadow_image, /* src */
437 NULL /* mask */,
438 po->hw_buffer, /* dest */
439 0, 0, /* src_x, src_y */
440 0, 0, /* mask_x, mask_y */
441 0, 0, /* dest_x, dest_y */
442 pixman_image_get_width (po->hw_buffer), /* width */
443 pixman_image_get_height (po->hw_buffer) /* height */);
444
445 pixman_image_set_clip_region32 (po->hw_buffer, NULL);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200446}
447
448static void
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300449pixman_renderer_repaint_output(struct weston_output *output,
450 pixman_region32_t *output_damage)
451{
452 struct pixman_output_state *po = get_output_state(output);
453
454 if (!po->hw_buffer)
455 return;
456
457 repaint_surfaces(output, output_damage);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200458 copy_to_hw_buffer(output, output_damage);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300459
460 pixman_region32_copy(&output->previous_damage, output_damage);
461 wl_signal_emit(&output->frame_signal, output);
462
463 /* Actual flip should be done by caller */
464}
465
466static void
467pixman_renderer_flush_damage(struct weston_surface *surface)
468{
469 /* No-op for pixman renderer */
470}
471
472static void
Lubomir Rintelddc2b1e2013-12-12 12:57:56 +0100473buffer_state_handle_buffer_destroy(struct wl_listener *listener, void *data)
474{
475 struct pixman_surface_state *ps;
476
477 ps = container_of(listener, struct pixman_surface_state,
478 buffer_destroy_listener);
479
480 if (ps->image) {
481 pixman_image_unref(ps->image);
482 ps->image = NULL;
483 }
484
485 ps->buffer_destroy_listener.notify = NULL;
486}
487
488static void
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500489pixman_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300490{
491 struct pixman_surface_state *ps = get_surface_state(es);
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500492 struct wl_shm_buffer *shm_buffer;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300493 pixman_format_code_t pixman_format;
494
495 weston_buffer_reference(&ps->buffer_ref, buffer);
496
Lubomir Rintelddc2b1e2013-12-12 12:57:56 +0100497 if (ps->buffer_destroy_listener.notify) {
498 wl_list_remove(&ps->buffer_destroy_listener.link);
499 ps->buffer_destroy_listener.notify = NULL;
500 }
501
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300502 if (ps->image) {
503 pixman_image_unref(ps->image);
504 ps->image = NULL;
505 }
506
507 if (!buffer)
508 return;
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500509
510 shm_buffer = wl_shm_buffer_get(buffer->resource);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300511
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500512 if (! shm_buffer) {
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300513 weston_log("Pixman renderer supports only SHM buffers\n");
514 weston_buffer_reference(&ps->buffer_ref, NULL);
515 return;
516 }
517
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500518 switch (wl_shm_buffer_get_format(shm_buffer)) {
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300519 case WL_SHM_FORMAT_XRGB8888:
520 pixman_format = PIXMAN_x8r8g8b8;
521 break;
522 case WL_SHM_FORMAT_ARGB8888:
523 pixman_format = PIXMAN_a8r8g8b8;
524 break;
Tomeu Vizoso1c1fc292013-08-06 20:05:56 +0200525 case WL_SHM_FORMAT_RGB565:
526 pixman_format = PIXMAN_r5g6b5;
527 break;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300528 default:
529 weston_log("Unsupported SHM buffer format\n");
530 weston_buffer_reference(&ps->buffer_ref, NULL);
531 return;
532 break;
533 }
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500534
535 buffer->shm_buffer = shm_buffer;
536 buffer->width = wl_shm_buffer_get_width(shm_buffer);
537 buffer->height = wl_shm_buffer_get_height(shm_buffer);
538
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300539 ps->image = pixman_image_create_bits(pixman_format,
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500540 buffer->width, buffer->height,
541 wl_shm_buffer_get_data(shm_buffer),
542 wl_shm_buffer_get_stride(shm_buffer));
Lubomir Rintelddc2b1e2013-12-12 12:57:56 +0100543
544 ps->buffer_destroy_listener.notify =
545 buffer_state_handle_buffer_destroy;
546 wl_signal_add(&buffer->destroy_signal,
547 &ps->buffer_destroy_listener);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300548}
549
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300550static void
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300551pixman_renderer_surface_state_destroy(struct pixman_surface_state *ps)
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300552{
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300553 wl_list_remove(&ps->surface_destroy_listener.link);
554 wl_list_remove(&ps->renderer_destroy_listener.link);
Lubomir Rintelddc2b1e2013-12-12 12:57:56 +0100555 if (ps->buffer_destroy_listener.notify) {
556 wl_list_remove(&ps->buffer_destroy_listener.link);
557 ps->buffer_destroy_listener.notify = NULL;
558 }
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300559
560 ps->surface->renderer_state = NULL;
561
562 if (ps->image) {
563 pixman_image_unref(ps->image);
564 ps->image = NULL;
565 }
566 weston_buffer_reference(&ps->buffer_ref, NULL);
567 free(ps);
568}
569
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300570static void
571surface_state_handle_surface_destroy(struct wl_listener *listener, void *data)
572{
573 struct pixman_surface_state *ps;
574
575 ps = container_of(listener, struct pixman_surface_state,
576 surface_destroy_listener);
577
578 pixman_renderer_surface_state_destroy(ps);
579}
580
581static void
582surface_state_handle_renderer_destroy(struct wl_listener *listener, void *data)
583{
584 struct pixman_surface_state *ps;
585
586 ps = container_of(listener, struct pixman_surface_state,
587 renderer_destroy_listener);
588
589 pixman_renderer_surface_state_destroy(ps);
590}
591
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300592static int
593pixman_renderer_create_surface(struct weston_surface *surface)
594{
595 struct pixman_surface_state *ps;
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300596 struct pixman_renderer *pr = get_renderer(surface->compositor);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300597
598 ps = calloc(1, sizeof *ps);
599 if (!ps)
600 return -1;
601
602 surface->renderer_state = ps;
603
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300604 ps->surface = surface;
605
606 ps->surface_destroy_listener.notify =
607 surface_state_handle_surface_destroy;
608 wl_signal_add(&surface->destroy_signal,
609 &ps->surface_destroy_listener);
610
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300611 ps->renderer_destroy_listener.notify =
612 surface_state_handle_renderer_destroy;
613 wl_signal_add(&pr->destroy_signal,
614 &ps->renderer_destroy_listener);
615
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300616 return 0;
617}
618
619static void
620pixman_renderer_surface_set_color(struct weston_surface *es,
621 float red, float green, float blue, float alpha)
622{
623 struct pixman_surface_state *ps = get_surface_state(es);
624 pixman_color_t color;
625
626 color.red = red * 0xffff;
627 color.green = green * 0xffff;
628 color.blue = blue * 0xffff;
629 color.alpha = alpha * 0xffff;
630
631 if (ps->image) {
632 pixman_image_unref(ps->image);
633 ps->image = NULL;
634 }
635
636 ps->image = pixman_image_create_solid_fill(&color);
637}
638
639static void
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300640pixman_renderer_destroy(struct weston_compositor *ec)
641{
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +0300642 struct pixman_renderer *pr = get_renderer(ec);
643
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300644 wl_signal_emit(&pr->destroy_signal, pr);
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +0300645 weston_binding_destroy(pr->debug_binding);
646 free(pr);
647
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300648 ec->renderer = NULL;
649}
650
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200651static void
Kristian Høgsberge3148752013-05-06 23:19:49 -0400652debug_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200653 void *data)
654{
655 struct weston_compositor *ec = data;
656 struct pixman_renderer *pr = (struct pixman_renderer *) ec->renderer;
657
658 pr->repaint_debug ^= 1;
659
660 if (pr->repaint_debug) {
661 pixman_color_t red = {
662 0x3fff, 0x0000, 0x0000, 0x3fff
663 };
664
665 pr->debug_color = pixman_image_create_solid_fill(&red);
666 } else {
667 pixman_image_unref(pr->debug_color);
668 weston_compositor_damage_all(ec);
669 }
670}
671
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300672WL_EXPORT int
673pixman_renderer_init(struct weston_compositor *ec)
674{
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200675 struct pixman_renderer *renderer;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300676
Ander Conselvan de Oliveirac68b1082013-10-25 16:26:31 +0300677 renderer = calloc(1, sizeof *renderer);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300678 if (renderer == NULL)
679 return -1;
680
Philipp Brüschweilerf3e39f92013-03-08 20:35:39 +0100681 renderer->repaint_debug = 0;
682 renderer->debug_color = NULL;
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200683 renderer->base.read_pixels = pixman_renderer_read_pixels;
684 renderer->base.repaint_output = pixman_renderer_repaint_output;
685 renderer->base.flush_damage = pixman_renderer_flush_damage;
686 renderer->base.attach = pixman_renderer_attach;
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200687 renderer->base.surface_set_color = pixman_renderer_surface_set_color;
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200688 renderer->base.destroy = pixman_renderer_destroy;
689 ec->renderer = &renderer->base;
Pekka Paalanen7bb65102013-05-22 18:03:04 +0300690 ec->capabilities |= WESTON_CAP_ROTATION_ANY;
Pekka Paalanen4fc5dd02013-05-22 18:03:05 +0300691 ec->capabilities |= WESTON_CAP_CAPTURE_YFLIP;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300692
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +0300693 renderer->debug_binding =
694 weston_compositor_add_debug_binding(ec, KEY_R,
695 debug_binding, ec);
Tomeu Vizoso1c1fc292013-08-06 20:05:56 +0200696
697 wl_display_add_shm_format(ec->wl_display, WL_SHM_FORMAT_RGB565);
698
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300699 wl_signal_init(&renderer->destroy_signal);
700
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300701 return 0;
702}
703
704WL_EXPORT void
705pixman_renderer_output_set_buffer(struct weston_output *output, pixman_image_t *buffer)
706{
707 struct pixman_output_state *po = get_output_state(output);
708
709 if (po->hw_buffer)
710 pixman_image_unref(po->hw_buffer);
711 po->hw_buffer = buffer;
712
713 if (po->hw_buffer) {
714 output->compositor->read_format = pixman_image_get_format(po->hw_buffer);
715 pixman_image_ref(po->hw_buffer);
716 }
717}
718
719WL_EXPORT int
720pixman_renderer_output_create(struct weston_output *output)
721{
722 struct pixman_output_state *po = calloc(1, sizeof *po);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200723 int w, h;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300724
725 if (!po)
726 return -1;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200727
728 /* set shadow image transformation */
Hardeningff39efa2013-09-18 23:56:35 +0200729 w = output->current_mode->width;
730 h = output->current_mode->height;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200731
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200732 po->shadow_buffer = malloc(w * h * 4);
733
734 if (!po->shadow_buffer) {
735 free(po);
736 return -1;
737 }
738
739 po->shadow_image =
740 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
741 po->shadow_buffer, w * 4);
742
743 if (!po->shadow_image) {
744 free(po->shadow_buffer);
745 free(po);
746 return -1;
747 }
748
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300749 output->renderer_state = po;
750
751 return 0;
752}
753
754WL_EXPORT void
755pixman_renderer_output_destroy(struct weston_output *output)
756{
757 struct pixman_output_state *po = get_output_state(output);
758
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200759 pixman_image_unref(po->shadow_image);
Ander Conselvan de Oliveira23e72b82013-01-25 15:13:06 +0200760
761 if (po->hw_buffer)
762 pixman_image_unref(po->hw_buffer);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200763
764 po->shadow_image = NULL;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300765 po->hw_buffer = NULL;
766
767 free(po);
768}