blob: 09e8c0ee7daa9afa6a522ed6d1a4d30a5d377b32 [file] [log] [blame]
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +03001/*
2 * Copyright © 2012 Intel Corporation
3 * Copyright © 2013 Vasily Khoruzhick <anarsoul@gmail.com>
Pekka Paalanen6764bbe2015-02-11 12:29:56 +02004 * Copyright © 2015 Collabora, Ltd.
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +03005 *
6 * Permission to use, copy, modify, distribute, and sell this software and
7 * its documentation for any purpose is hereby granted without fee, provided
8 * that the above copyright notice appear in all copies and that both that
9 * copyright notice and this permission notice appear in supporting
10 * documentation, and that the name of the copyright holders not be used in
11 * advertising or publicity pertaining to distribution of the software
12 * without specific, written prior permission. The copyright holders make
13 * no representations about the suitability of this software for any
14 * purpose. It is provided "as is" without express or implied warranty.
15 *
16 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
17 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
18 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
19 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
20 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
21 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
22 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 */
24
Daniel Stonec228e232013-05-22 18:03:19 +030025#include "config.h"
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030026
27#include <errno.h>
28#include <stdlib.h>
29
30#include "pixman-renderer.h"
31
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +020032#include <linux/input.h>
33
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030034struct pixman_output_state {
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +020035 void *shadow_buffer;
36 pixman_image_t *shadow_image;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030037 pixman_image_t *hw_buffer;
38};
39
40struct pixman_surface_state {
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +030041 struct weston_surface *surface;
42
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030043 pixman_image_t *image;
44 struct weston_buffer_reference buffer_ref;
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +030045
Lubomir Rintelddc2b1e2013-12-12 12:57:56 +010046 struct wl_listener buffer_destroy_listener;
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +030047 struct wl_listener surface_destroy_listener;
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +030048 struct wl_listener renderer_destroy_listener;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030049};
50
51struct pixman_renderer {
52 struct weston_renderer base;
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +030053
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +020054 int repaint_debug;
55 pixman_image_t *debug_color;
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +030056 struct weston_binding *debug_binding;
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +030057
58 struct wl_signal destroy_signal;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030059};
60
61static inline struct pixman_output_state *
62get_output_state(struct weston_output *output)
63{
64 return (struct pixman_output_state *)output->renderer_state;
65}
66
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +030067static int
68pixman_renderer_create_surface(struct weston_surface *surface);
69
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030070static inline struct pixman_surface_state *
71get_surface_state(struct weston_surface *surface)
72{
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +030073 if (!surface->renderer_state)
74 pixman_renderer_create_surface(surface);
75
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030076 return (struct pixman_surface_state *)surface->renderer_state;
77}
78
79static inline struct pixman_renderer *
80get_renderer(struct weston_compositor *ec)
81{
82 return (struct pixman_renderer *)ec->renderer;
83}
84
85static int
86pixman_renderer_read_pixels(struct weston_output *output,
87 pixman_format_code_t format, void *pixels,
88 uint32_t x, uint32_t y,
89 uint32_t width, uint32_t height)
90{
91 struct pixman_output_state *po = get_output_state(output);
Alexander Larsson97af7922013-05-29 12:01:33 +020092 pixman_transform_t transform;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030093 pixman_image_t *out_buf;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030094
95 if (!po->hw_buffer) {
96 errno = ENODEV;
97 return -1;
98 }
99
100 out_buf = pixman_image_create_bits(format,
101 width,
102 height,
103 pixels,
104 (PIXMAN_FORMAT_BPP(format) / 8) * width);
105
Alexander Larsson97af7922013-05-29 12:01:33 +0200106 /* Caller expects vflipped source image */
107 pixman_transform_init_translate(&transform,
108 pixman_int_to_fixed (x),
109 pixman_int_to_fixed (y - pixman_image_get_height (po->hw_buffer)));
110 pixman_transform_scale(&transform, NULL,
111 pixman_fixed_1,
112 pixman_fixed_minus_1);
113 pixman_image_set_transform(po->hw_buffer, &transform);
114
115 pixman_image_composite32(PIXMAN_OP_SRC,
116 po->hw_buffer, /* src */
117 NULL /* mask */,
118 out_buf, /* dest */
119 0, 0, /* src_x, src_y */
120 0, 0, /* mask_x, mask_y */
121 0, 0, /* dest_x, dest_y */
122 pixman_image_get_width (po->hw_buffer), /* width */
123 pixman_image_get_height (po->hw_buffer) /* height */);
124 pixman_image_set_transform(po->hw_buffer, NULL);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300125
126 pixman_image_unref(out_buf);
127
128 return 0;
129}
130
Vasily Khoruzhick031fc872013-01-29 14:58:14 +0300131static void
Alexander Larsson1f206b42013-05-22 14:41:36 +0200132region_global_to_output(struct weston_output *output, pixman_region32_t *region)
133{
134 pixman_region32_translate(region, -output->x, -output->y);
Jason Ekstrand33ff6362013-10-27 22:25:01 -0500135 weston_transformed_region(output->width, output->height,
136 output->transform, output->current_scale,
137 region, region);
Vasily Khoruzhick031fc872013-01-29 14:58:14 +0300138}
139
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300140#define D2F(v) pixman_double_to_fixed((double)v)
141
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300142static void
Pekka Paalanen0b4c5352014-03-14 14:38:17 +0200143transform_apply_viewport(pixman_transform_t *transform,
144 struct weston_surface *surface)
145{
146 struct weston_buffer_viewport *vp = &surface->buffer_viewport;
147 double src_width, src_height;
148 double src_x, src_y;
149
150 if (vp->buffer.src_width == wl_fixed_from_int(-1)) {
151 if (vp->surface.width == -1)
152 return;
153
154 src_x = 0.0;
155 src_y = 0.0;
156 src_width = surface->width_from_buffer;
157 src_height = surface->height_from_buffer;
158 } else {
159 src_x = wl_fixed_to_double(vp->buffer.src_x);
160 src_y = wl_fixed_to_double(vp->buffer.src_y);
161 src_width = wl_fixed_to_double(vp->buffer.src_width);
162 src_height = wl_fixed_to_double(vp->buffer.src_height);
163 }
164
165 pixman_transform_scale(transform, NULL,
166 D2F(src_width / surface->width),
167 D2F(src_height / surface->height));
168 pixman_transform_translate(transform, NULL, D2F(src_x), D2F(src_y));
169}
170
171static void
Jason Ekstranda7af7042013-10-12 22:38:11 -0500172repaint_region(struct weston_view *ev, struct weston_output *output,
Alexander Larsson1f206b42013-05-22 14:41:36 +0200173 pixman_region32_t *region, pixman_region32_t *surf_region,
174 pixman_op_t pixman_op)
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300175{
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200176 struct pixman_renderer *pr =
177 (struct pixman_renderer *) output->compositor->renderer;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500178 struct pixman_surface_state *ps = get_surface_state(ev->surface);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300179 struct pixman_output_state *po = get_output_state(output);
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200180 struct weston_buffer_viewport *vp = &ev->surface->buffer_viewport;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300181 pixman_region32_t final_region;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500182 float view_x, view_y;
Alexander Larsson1f206b42013-05-22 14:41:36 +0200183 pixman_transform_t transform;
184 pixman_fixed_t fw, fh;
Manuel Bachmann9c4ab662014-04-07 11:58:45 +0200185 pixman_image_t *mask_image;
186 pixman_color_t mask = { 0, };
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300187
188 /* The final region to be painted is the intersection of
189 * 'region' and 'surf_region'. However, 'region' is in the global
190 * coordinates, and 'surf_region' is in the surface-local
191 * coordinates
192 */
193 pixman_region32_init(&final_region);
Alexander Larsson1f206b42013-05-22 14:41:36 +0200194 if (surf_region) {
195 pixman_region32_copy(&final_region, surf_region);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300196
Alexander Larsson1f206b42013-05-22 14:41:36 +0200197 /* Convert from surface to global coordinates */
Jason Ekstranda7af7042013-10-12 22:38:11 -0500198 if (!ev->transform.enabled) {
199 pixman_region32_translate(&final_region, ev->geometry.x, ev->geometry.y);
Alexander Larsson1f206b42013-05-22 14:41:36 +0200200 } else {
Jason Ekstranda7af7042013-10-12 22:38:11 -0500201 weston_view_to_global_float(ev, 0, 0, &view_x, &view_y);
202 pixman_region32_translate(&final_region, (int)view_x, (int)view_y);
Alexander Larsson1f206b42013-05-22 14:41:36 +0200203 }
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300204
Alexander Larsson1f206b42013-05-22 14:41:36 +0200205 /* We need to paint the intersection */
206 pixman_region32_intersect(&final_region, &final_region, region);
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300207 } else {
Alexander Larsson1f206b42013-05-22 14:41:36 +0200208 /* If there is no surface region, just use the global region */
209 pixman_region32_copy(&final_region, region);
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300210 }
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300211
Alexander Larsson1f206b42013-05-22 14:41:36 +0200212 /* Convert from global to output coord */
213 region_global_to_output(output, &final_region);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300214
Alexander Larsson1f206b42013-05-22 14:41:36 +0200215 /* And clip to it */
216 pixman_image_set_clip_region32 (po->shadow_image, &final_region);
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200217
Alexander Larsson1f206b42013-05-22 14:41:36 +0200218 /* Set up the source transformation based on the surface
Alexander Larsson4ea95522013-05-22 14:41:37 +0200219 position, the output position/transform/scale and the client
220 specified buffer transform/scale */
Alexander Larsson1f206b42013-05-22 14:41:36 +0200221 pixman_transform_init_identity(&transform);
Alexander Larsson4ea95522013-05-22 14:41:37 +0200222 pixman_transform_scale(&transform, NULL,
Hardeningff39efa2013-09-18 23:56:35 +0200223 pixman_double_to_fixed ((double)1.0/output->current_scale),
224 pixman_double_to_fixed ((double)1.0/output->current_scale));
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200225
Alexander Larsson1f206b42013-05-22 14:41:36 +0200226 fw = pixman_int_to_fixed(output->width);
227 fh = pixman_int_to_fixed(output->height);
228 switch (output->transform) {
229 default:
230 case WL_OUTPUT_TRANSFORM_NORMAL:
231 case WL_OUTPUT_TRANSFORM_FLIPPED:
232 break;
233 case WL_OUTPUT_TRANSFORM_90:
234 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
235 pixman_transform_rotate(&transform, NULL, 0, -pixman_fixed_1);
236 pixman_transform_translate(&transform, NULL, 0, fh);
237 break;
238 case WL_OUTPUT_TRANSFORM_180:
239 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
240 pixman_transform_rotate(&transform, NULL, -pixman_fixed_1, 0);
241 pixman_transform_translate(&transform, NULL, fw, fh);
242 break;
243 case WL_OUTPUT_TRANSFORM_270:
244 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
245 pixman_transform_rotate(&transform, NULL, 0, pixman_fixed_1);
246 pixman_transform_translate(&transform, NULL, fw, 0);
247 break;
248 }
249
250 switch (output->transform) {
251 case WL_OUTPUT_TRANSFORM_FLIPPED:
252 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
253 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
254 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
255 pixman_transform_scale(&transform, NULL,
256 pixman_int_to_fixed (-1),
257 pixman_int_to_fixed (1));
258 pixman_transform_translate(&transform, NULL, fw, 0);
259 break;
260 }
261
262 pixman_transform_translate(&transform, NULL,
263 pixman_double_to_fixed (output->x),
264 pixman_double_to_fixed (output->y));
265
Jason Ekstranda7af7042013-10-12 22:38:11 -0500266 if (ev->transform.enabled) {
Alexander Larsson1f206b42013-05-22 14:41:36 +0200267 /* Pixman supports only 2D transform matrix, but Weston uses 3D,
268 * so we're omitting Z coordinate here
269 */
270 pixman_transform_t surface_transform = {{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500271 { D2F(ev->transform.matrix.d[0]),
272 D2F(ev->transform.matrix.d[4]),
273 D2F(ev->transform.matrix.d[12]),
Alexander Larsson1f206b42013-05-22 14:41:36 +0200274 },
Jason Ekstranda7af7042013-10-12 22:38:11 -0500275 { D2F(ev->transform.matrix.d[1]),
276 D2F(ev->transform.matrix.d[5]),
277 D2F(ev->transform.matrix.d[13]),
Alexander Larsson1f206b42013-05-22 14:41:36 +0200278 },
Jason Ekstranda7af7042013-10-12 22:38:11 -0500279 { D2F(ev->transform.matrix.d[3]),
280 D2F(ev->transform.matrix.d[7]),
281 D2F(ev->transform.matrix.d[15]),
Alexander Larsson1f206b42013-05-22 14:41:36 +0200282 }
283 }};
284
285 pixman_transform_invert(&surface_transform, &surface_transform);
286 pixman_transform_multiply (&transform, &surface_transform, &transform);
287 } else {
288 pixman_transform_translate(&transform, NULL,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500289 pixman_double_to_fixed ((double)-ev->geometry.x),
290 pixman_double_to_fixed ((double)-ev->geometry.y));
Alexander Larsson1f206b42013-05-22 14:41:36 +0200291 }
292
Pekka Paalanen0b4c5352014-03-14 14:38:17 +0200293 transform_apply_viewport(&transform, ev->surface);
Jonny Lambfa1b3052013-11-26 18:19:47 +0100294
Jason Ekstrand42833702014-04-21 21:04:42 -0500295 fw = pixman_int_to_fixed(ev->surface->width_from_buffer);
296 fh = pixman_int_to_fixed(ev->surface->height_from_buffer);
Alexander Larsson1f206b42013-05-22 14:41:36 +0200297
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200298 switch (vp->buffer.transform) {
Alexander Larsson1f206b42013-05-22 14:41:36 +0200299 case WL_OUTPUT_TRANSFORM_FLIPPED:
300 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
301 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
302 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
303 pixman_transform_scale(&transform, NULL,
304 pixman_int_to_fixed (-1),
305 pixman_int_to_fixed (1));
306 pixman_transform_translate(&transform, NULL, fw, 0);
307 break;
308 }
309
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200310 switch (vp->buffer.transform) {
Alexander Larsson1f206b42013-05-22 14:41:36 +0200311 default:
312 case WL_OUTPUT_TRANSFORM_NORMAL:
313 case WL_OUTPUT_TRANSFORM_FLIPPED:
314 break;
315 case WL_OUTPUT_TRANSFORM_90:
316 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
317 pixman_transform_rotate(&transform, NULL, 0, pixman_fixed_1);
318 pixman_transform_translate(&transform, NULL, fh, 0);
319 break;
320 case WL_OUTPUT_TRANSFORM_180:
321 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
322 pixman_transform_rotate(&transform, NULL, -pixman_fixed_1, 0);
323 pixman_transform_translate(&transform, NULL, fw, fh);
324 break;
325 case WL_OUTPUT_TRANSFORM_270:
326 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
327 pixman_transform_rotate(&transform, NULL, 0, -pixman_fixed_1);
328 pixman_transform_translate(&transform, NULL, 0, fw);
329 break;
330 }
331
Jason Ekstrand50fba972014-02-25 21:54:59 -0600332 pixman_transform_scale(&transform, NULL,
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200333 pixman_double_to_fixed(vp->buffer.scale),
334 pixman_double_to_fixed(vp->buffer.scale));
Jason Ekstrand50fba972014-02-25 21:54:59 -0600335
Alexander Larsson1f206b42013-05-22 14:41:36 +0200336 pixman_image_set_transform(ps->image, &transform);
337
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200338 if (ev->transform.enabled || output->current_scale != vp->buffer.scale)
Alexander Larsson1f206b42013-05-22 14:41:36 +0200339 pixman_image_set_filter(ps->image, PIXMAN_FILTER_BILINEAR, NULL, 0);
340 else
341 pixman_image_set_filter(ps->image, PIXMAN_FILTER_NEAREST, NULL, 0);
342
Neil Robertse5051712013-11-13 15:44:06 +0000343 if (ps->buffer_ref.buffer)
344 wl_shm_buffer_begin_access(ps->buffer_ref.buffer->shm_buffer);
345
Manuel Bachmannb1fff412014-04-05 05:31:37 +0200346 if (ev->alpha < 1.0) {
Manuel Bachmann9c4ab662014-04-07 11:58:45 +0200347 mask.alpha = 0xffff * ev->alpha;
Manuel Bachmannb1fff412014-04-05 05:31:37 +0200348 mask_image = pixman_image_create_solid_fill(&mask);
Manuel Bachmann9c4ab662014-04-07 11:58:45 +0200349 } else {
Manuel Bachmannb1fff412014-04-05 05:31:37 +0200350 mask_image = NULL;
Manuel Bachmann9c4ab662014-04-07 11:58:45 +0200351 }
Manuel Bachmannb1fff412014-04-05 05:31:37 +0200352
Alexander Larsson1f206b42013-05-22 14:41:36 +0200353 pixman_image_composite32(pixman_op,
354 ps->image, /* src */
Manuel Bachmannb1fff412014-04-05 05:31:37 +0200355 mask_image, /* mask */
Alexander Larsson1f206b42013-05-22 14:41:36 +0200356 po->shadow_image, /* dest */
357 0, 0, /* src_x, src_y */
358 0, 0, /* mask_x, mask_y */
359 0, 0, /* dest_x, dest_y */
360 pixman_image_get_width (po->shadow_image), /* width */
361 pixman_image_get_height (po->shadow_image) /* height */);
362
Manuel Bachmann9c4ab662014-04-07 11:58:45 +0200363 if (mask_image)
364 pixman_image_unref(mask_image);
365
Neil Robertse5051712013-11-13 15:44:06 +0000366 if (ps->buffer_ref.buffer)
367 wl_shm_buffer_end_access(ps->buffer_ref.buffer->shm_buffer);
368
Alexander Larsson1f206b42013-05-22 14:41:36 +0200369 if (pr->repaint_debug)
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200370 pixman_image_composite32(PIXMAN_OP_OVER,
Alexander Larsson1f206b42013-05-22 14:41:36 +0200371 pr->debug_color, /* src */
372 NULL /* mask */,
373 po->shadow_image, /* dest */
374 0, 0, /* src_x, src_y */
375 0, 0, /* mask_x, mask_y */
376 0, 0, /* dest_x, dest_y */
377 pixman_image_get_width (po->shadow_image), /* width */
378 pixman_image_get_height (po->shadow_image) /* height */);
379
380 pixman_image_set_clip_region32 (po->shadow_image, NULL);
381
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300382 pixman_region32_fini(&final_region);
383}
384
385static void
Jason Ekstranda7af7042013-10-12 22:38:11 -0500386draw_view(struct weston_view *ev, struct weston_output *output,
387 pixman_region32_t *damage) /* in global coordinates */
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300388{
Derek Foreman66951b72014-09-01 10:33:28 -0500389 static int zoom_logged = 0;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500390 struct pixman_surface_state *ps = get_surface_state(ev->surface);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300391 /* repaint bounding region in global coordinates: */
392 pixman_region32_t repaint;
393 /* non-opaque region in surface coordinates: */
394 pixman_region32_t surface_blend;
395
396 /* No buffer attached */
397 if (!ps->image)
398 return;
399
400 pixman_region32_init(&repaint);
401 pixman_region32_intersect(&repaint,
Pekka Paalanen25c0ca52015-02-19 11:15:33 +0200402 &ev->transform.boundingbox, damage);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500403 pixman_region32_subtract(&repaint, &repaint, &ev->clip);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300404
405 if (!pixman_region32_not_empty(&repaint))
406 goto out;
407
Derek Foreman66951b72014-09-01 10:33:28 -0500408 if (output->zoom.active && !zoom_logged) {
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300409 weston_log("pixman renderer does not support zoom\n");
Derek Foreman66951b72014-09-01 10:33:28 -0500410 zoom_logged = 1;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300411 }
412
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300413 /* TODO: Implement repaint_region_complex() using pixman_composite_trapezoids() */
Manuel Bachmann9c4ab662014-04-07 11:58:45 +0200414 if (ev->alpha != 1.0 ||
415 (ev->transform.enabled &&
416 ev->transform.matrix.type != WESTON_MATRIX_TRANSFORM_TRANSLATE)) {
Jason Ekstranda7af7042013-10-12 22:38:11 -0500417 repaint_region(ev, output, &repaint, NULL, PIXMAN_OP_OVER);
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300418 } else {
419 /* blended region is whole surface minus opaque region: */
420 pixman_region32_init_rect(&surface_blend, 0, 0,
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600421 ev->surface->width, ev->surface->height);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500422 pixman_region32_subtract(&surface_blend, &surface_blend, &ev->surface->opaque);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300423
Jason Ekstranda7af7042013-10-12 22:38:11 -0500424 if (pixman_region32_not_empty(&ev->surface->opaque)) {
425 repaint_region(ev, output, &repaint, &ev->surface->opaque, PIXMAN_OP_SRC);
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300426 }
427
428 if (pixman_region32_not_empty(&surface_blend)) {
Jason Ekstranda7af7042013-10-12 22:38:11 -0500429 repaint_region(ev, output, &repaint, &surface_blend, PIXMAN_OP_OVER);
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300430 }
431 pixman_region32_fini(&surface_blend);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300432 }
433
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300434
435out:
436 pixman_region32_fini(&repaint);
437}
438static void
439repaint_surfaces(struct weston_output *output, pixman_region32_t *damage)
440{
441 struct weston_compositor *compositor = output->compositor;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500442 struct weston_view *view;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300443
Jason Ekstranda7af7042013-10-12 22:38:11 -0500444 wl_list_for_each_reverse(view, &compositor->view_list, link)
445 if (view->plane == &compositor->primary_plane)
446 draw_view(view, output, damage);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300447}
448
449static void
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200450copy_to_hw_buffer(struct weston_output *output, pixman_region32_t *region)
451{
452 struct pixman_output_state *po = get_output_state(output);
Alexander Larsson1f206b42013-05-22 14:41:36 +0200453 pixman_region32_t output_region;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200454
Alexander Larsson1f206b42013-05-22 14:41:36 +0200455 pixman_region32_init(&output_region);
456 pixman_region32_copy(&output_region, region);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200457
Alexander Larsson1f206b42013-05-22 14:41:36 +0200458 region_global_to_output(output, &output_region);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200459
Alexander Larsson1f206b42013-05-22 14:41:36 +0200460 pixman_image_set_clip_region32 (po->hw_buffer, &output_region);
Ryo Munakata389d2052014-09-04 01:56:53 +0900461 pixman_region32_fini(&output_region);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200462
Alexander Larsson1f206b42013-05-22 14:41:36 +0200463 pixman_image_composite32(PIXMAN_OP_SRC,
464 po->shadow_image, /* src */
465 NULL /* mask */,
466 po->hw_buffer, /* dest */
467 0, 0, /* src_x, src_y */
468 0, 0, /* mask_x, mask_y */
469 0, 0, /* dest_x, dest_y */
470 pixman_image_get_width (po->hw_buffer), /* width */
471 pixman_image_get_height (po->hw_buffer) /* height */);
472
473 pixman_image_set_clip_region32 (po->hw_buffer, NULL);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200474}
475
476static void
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300477pixman_renderer_repaint_output(struct weston_output *output,
478 pixman_region32_t *output_damage)
479{
480 struct pixman_output_state *po = get_output_state(output);
481
482 if (!po->hw_buffer)
483 return;
484
485 repaint_surfaces(output, output_damage);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200486 copy_to_hw_buffer(output, output_damage);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300487
488 pixman_region32_copy(&output->previous_damage, output_damage);
489 wl_signal_emit(&output->frame_signal, output);
490
491 /* Actual flip should be done by caller */
492}
493
494static void
495pixman_renderer_flush_damage(struct weston_surface *surface)
496{
497 /* No-op for pixman renderer */
498}
499
500static void
Lubomir Rintelddc2b1e2013-12-12 12:57:56 +0100501buffer_state_handle_buffer_destroy(struct wl_listener *listener, void *data)
502{
503 struct pixman_surface_state *ps;
504
505 ps = container_of(listener, struct pixman_surface_state,
506 buffer_destroy_listener);
507
508 if (ps->image) {
509 pixman_image_unref(ps->image);
510 ps->image = NULL;
511 }
512
513 ps->buffer_destroy_listener.notify = NULL;
514}
515
516static void
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500517pixman_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300518{
519 struct pixman_surface_state *ps = get_surface_state(es);
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500520 struct wl_shm_buffer *shm_buffer;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300521 pixman_format_code_t pixman_format;
522
523 weston_buffer_reference(&ps->buffer_ref, buffer);
524
Lubomir Rintelddc2b1e2013-12-12 12:57:56 +0100525 if (ps->buffer_destroy_listener.notify) {
526 wl_list_remove(&ps->buffer_destroy_listener.link);
527 ps->buffer_destroy_listener.notify = NULL;
528 }
529
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300530 if (ps->image) {
531 pixman_image_unref(ps->image);
532 ps->image = NULL;
533 }
534
535 if (!buffer)
536 return;
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500537
538 shm_buffer = wl_shm_buffer_get(buffer->resource);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300539
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500540 if (! shm_buffer) {
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300541 weston_log("Pixman renderer supports only SHM buffers\n");
542 weston_buffer_reference(&ps->buffer_ref, NULL);
543 return;
544 }
545
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500546 switch (wl_shm_buffer_get_format(shm_buffer)) {
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300547 case WL_SHM_FORMAT_XRGB8888:
548 pixman_format = PIXMAN_x8r8g8b8;
549 break;
550 case WL_SHM_FORMAT_ARGB8888:
551 pixman_format = PIXMAN_a8r8g8b8;
552 break;
Tomeu Vizoso1c1fc292013-08-06 20:05:56 +0200553 case WL_SHM_FORMAT_RGB565:
554 pixman_format = PIXMAN_r5g6b5;
555 break;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300556 default:
557 weston_log("Unsupported SHM buffer format\n");
558 weston_buffer_reference(&ps->buffer_ref, NULL);
559 return;
560 break;
561 }
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500562
563 buffer->shm_buffer = shm_buffer;
564 buffer->width = wl_shm_buffer_get_width(shm_buffer);
565 buffer->height = wl_shm_buffer_get_height(shm_buffer);
566
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300567 ps->image = pixman_image_create_bits(pixman_format,
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500568 buffer->width, buffer->height,
569 wl_shm_buffer_get_data(shm_buffer),
570 wl_shm_buffer_get_stride(shm_buffer));
Lubomir Rintelddc2b1e2013-12-12 12:57:56 +0100571
572 ps->buffer_destroy_listener.notify =
573 buffer_state_handle_buffer_destroy;
574 wl_signal_add(&buffer->destroy_signal,
575 &ps->buffer_destroy_listener);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300576}
577
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300578static void
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300579pixman_renderer_surface_state_destroy(struct pixman_surface_state *ps)
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300580{
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300581 wl_list_remove(&ps->surface_destroy_listener.link);
582 wl_list_remove(&ps->renderer_destroy_listener.link);
Lubomir Rintelddc2b1e2013-12-12 12:57:56 +0100583 if (ps->buffer_destroy_listener.notify) {
584 wl_list_remove(&ps->buffer_destroy_listener.link);
585 ps->buffer_destroy_listener.notify = NULL;
586 }
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300587
588 ps->surface->renderer_state = NULL;
589
590 if (ps->image) {
591 pixman_image_unref(ps->image);
592 ps->image = NULL;
593 }
594 weston_buffer_reference(&ps->buffer_ref, NULL);
595 free(ps);
596}
597
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300598static void
599surface_state_handle_surface_destroy(struct wl_listener *listener, void *data)
600{
601 struct pixman_surface_state *ps;
602
603 ps = container_of(listener, struct pixman_surface_state,
604 surface_destroy_listener);
605
606 pixman_renderer_surface_state_destroy(ps);
607}
608
609static void
610surface_state_handle_renderer_destroy(struct wl_listener *listener, void *data)
611{
612 struct pixman_surface_state *ps;
613
614 ps = container_of(listener, struct pixman_surface_state,
615 renderer_destroy_listener);
616
617 pixman_renderer_surface_state_destroy(ps);
618}
619
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300620static int
621pixman_renderer_create_surface(struct weston_surface *surface)
622{
623 struct pixman_surface_state *ps;
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300624 struct pixman_renderer *pr = get_renderer(surface->compositor);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300625
Bryce Harringtonde16d892014-11-20 22:21:57 -0800626 ps = zalloc(sizeof *ps);
627 if (ps == NULL)
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300628 return -1;
629
630 surface->renderer_state = ps;
631
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300632 ps->surface = surface;
633
634 ps->surface_destroy_listener.notify =
635 surface_state_handle_surface_destroy;
636 wl_signal_add(&surface->destroy_signal,
637 &ps->surface_destroy_listener);
638
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300639 ps->renderer_destroy_listener.notify =
640 surface_state_handle_renderer_destroy;
641 wl_signal_add(&pr->destroy_signal,
642 &ps->renderer_destroy_listener);
643
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300644 return 0;
645}
646
647static void
648pixman_renderer_surface_set_color(struct weston_surface *es,
649 float red, float green, float blue, float alpha)
650{
651 struct pixman_surface_state *ps = get_surface_state(es);
652 pixman_color_t color;
653
654 color.red = red * 0xffff;
655 color.green = green * 0xffff;
656 color.blue = blue * 0xffff;
657 color.alpha = alpha * 0xffff;
658
659 if (ps->image) {
660 pixman_image_unref(ps->image);
661 ps->image = NULL;
662 }
663
664 ps->image = pixman_image_create_solid_fill(&color);
665}
666
667static void
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300668pixman_renderer_destroy(struct weston_compositor *ec)
669{
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +0300670 struct pixman_renderer *pr = get_renderer(ec);
671
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300672 wl_signal_emit(&pr->destroy_signal, pr);
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +0300673 weston_binding_destroy(pr->debug_binding);
674 free(pr);
675
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300676 ec->renderer = NULL;
677}
678
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200679static void
Pekka Paalanen6764bbe2015-02-11 12:29:56 +0200680pixman_renderer_surface_get_content_size(struct weston_surface *surface,
681 int *width, int *height)
682{
683 struct pixman_surface_state *ps = get_surface_state(surface);
684
685 if (ps->image) {
686 *width = pixman_image_get_width(ps->image);
687 *height = pixman_image_get_height(ps->image);
688 } else {
689 *width = 0;
690 *height = 0;
691 }
692}
693
694static int
695pixman_renderer_surface_copy_content(struct weston_surface *surface,
696 void *target, size_t size,
697 int src_x, int src_y,
698 int width, int height)
699{
700 const pixman_format_code_t format = PIXMAN_a8b8g8r8;
701 const size_t bytespp = 4; /* PIXMAN_a8b8g8r8 */
702 struct pixman_surface_state *ps = get_surface_state(surface);
703 pixman_image_t *out_buf;
704
705 if (!ps->image)
706 return -1;
707
708 out_buf = pixman_image_create_bits(format, width, height,
709 target, width * bytespp);
710
711 pixman_image_set_transform(ps->image, NULL);
712 pixman_image_composite32(PIXMAN_OP_SRC,
713 ps->image, /* src */
714 NULL, /* mask */
715 out_buf, /* dest */
716 src_x, src_y, /* src_x, src_y */
717 0, 0, /* mask_x, mask_y */
718 0, 0, /* dest_x, dest_y */
719 width, height);
720
721 pixman_image_unref(out_buf);
722
723 return 0;
724}
725
726static void
Kristian Høgsberge3148752013-05-06 23:19:49 -0400727debug_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200728 void *data)
729{
730 struct weston_compositor *ec = data;
731 struct pixman_renderer *pr = (struct pixman_renderer *) ec->renderer;
732
733 pr->repaint_debug ^= 1;
734
735 if (pr->repaint_debug) {
736 pixman_color_t red = {
737 0x3fff, 0x0000, 0x0000, 0x3fff
738 };
739
740 pr->debug_color = pixman_image_create_solid_fill(&red);
741 } else {
742 pixman_image_unref(pr->debug_color);
743 weston_compositor_damage_all(ec);
744 }
745}
746
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300747WL_EXPORT int
748pixman_renderer_init(struct weston_compositor *ec)
749{
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200750 struct pixman_renderer *renderer;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300751
Bryce Harringtonde16d892014-11-20 22:21:57 -0800752 renderer = zalloc(sizeof *renderer);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300753 if (renderer == NULL)
754 return -1;
755
Philipp Brüschweilerf3e39f92013-03-08 20:35:39 +0100756 renderer->repaint_debug = 0;
757 renderer->debug_color = NULL;
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200758 renderer->base.read_pixels = pixman_renderer_read_pixels;
759 renderer->base.repaint_output = pixman_renderer_repaint_output;
760 renderer->base.flush_damage = pixman_renderer_flush_damage;
761 renderer->base.attach = pixman_renderer_attach;
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200762 renderer->base.surface_set_color = pixman_renderer_surface_set_color;
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200763 renderer->base.destroy = pixman_renderer_destroy;
Pekka Paalanen6764bbe2015-02-11 12:29:56 +0200764 renderer->base.surface_get_content_size =
765 pixman_renderer_surface_get_content_size;
766 renderer->base.surface_copy_content =
767 pixman_renderer_surface_copy_content;
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200768 ec->renderer = &renderer->base;
Pekka Paalanen7bb65102013-05-22 18:03:04 +0300769 ec->capabilities |= WESTON_CAP_ROTATION_ANY;
Pekka Paalanen4fc5dd02013-05-22 18:03:05 +0300770 ec->capabilities |= WESTON_CAP_CAPTURE_YFLIP;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300771
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +0300772 renderer->debug_binding =
773 weston_compositor_add_debug_binding(ec, KEY_R,
774 debug_binding, ec);
Tomeu Vizoso1c1fc292013-08-06 20:05:56 +0200775
776 wl_display_add_shm_format(ec->wl_display, WL_SHM_FORMAT_RGB565);
777
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300778 wl_signal_init(&renderer->destroy_signal);
779
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300780 return 0;
781}
782
783WL_EXPORT void
784pixman_renderer_output_set_buffer(struct weston_output *output, pixman_image_t *buffer)
785{
786 struct pixman_output_state *po = get_output_state(output);
787
788 if (po->hw_buffer)
789 pixman_image_unref(po->hw_buffer);
790 po->hw_buffer = buffer;
791
792 if (po->hw_buffer) {
793 output->compositor->read_format = pixman_image_get_format(po->hw_buffer);
794 pixman_image_ref(po->hw_buffer);
795 }
796}
797
798WL_EXPORT int
799pixman_renderer_output_create(struct weston_output *output)
800{
Bryce Harringtonde16d892014-11-20 22:21:57 -0800801 struct pixman_output_state *po;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200802 int w, h;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300803
Bryce Harringtonde16d892014-11-20 22:21:57 -0800804 po = zalloc(sizeof *po);
805 if (po == NULL)
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300806 return -1;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200807
808 /* set shadow image transformation */
Hardeningff39efa2013-09-18 23:56:35 +0200809 w = output->current_mode->width;
810 h = output->current_mode->height;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200811
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200812 po->shadow_buffer = malloc(w * h * 4);
813
814 if (!po->shadow_buffer) {
815 free(po);
816 return -1;
817 }
818
819 po->shadow_image =
820 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
821 po->shadow_buffer, w * 4);
822
823 if (!po->shadow_image) {
824 free(po->shadow_buffer);
825 free(po);
826 return -1;
827 }
828
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300829 output->renderer_state = po;
830
831 return 0;
832}
833
834WL_EXPORT void
835pixman_renderer_output_destroy(struct weston_output *output)
836{
837 struct pixman_output_state *po = get_output_state(output);
838
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200839 pixman_image_unref(po->shadow_image);
Ander Conselvan de Oliveira23e72b82013-01-25 15:13:06 +0200840
841 if (po->hw_buffer)
842 pixman_image_unref(po->hw_buffer);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200843
Arnaud Vrac8e3fe082014-08-25 20:56:52 +0200844 free(po->shadow_buffer);
845
846 po->shadow_buffer = NULL;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200847 po->shadow_image = NULL;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300848 po->hw_buffer = NULL;
849
850 free(po);
851}