blob: 530e2ed487035c2bccf2778d2217774d55d5e857 [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;
Manuel Bachmann9c4ab662014-04-07 11:58:45 +0200184 pixman_image_t *mask_image;
185 pixman_color_t mask = { 0, };
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300186
187 /* The final region to be painted is the intersection of
188 * 'region' and 'surf_region'. However, 'region' is in the global
189 * coordinates, and 'surf_region' is in the surface-local
190 * coordinates
191 */
192 pixman_region32_init(&final_region);
Alexander Larsson1f206b42013-05-22 14:41:36 +0200193 if (surf_region) {
194 pixman_region32_copy(&final_region, surf_region);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300195
Alexander Larsson1f206b42013-05-22 14:41:36 +0200196 /* Convert from surface to global coordinates */
Jason Ekstranda7af7042013-10-12 22:38:11 -0500197 if (!ev->transform.enabled) {
198 pixman_region32_translate(&final_region, ev->geometry.x, ev->geometry.y);
Alexander Larsson1f206b42013-05-22 14:41:36 +0200199 } else {
Jason Ekstranda7af7042013-10-12 22:38:11 -0500200 weston_view_to_global_float(ev, 0, 0, &view_x, &view_y);
201 pixman_region32_translate(&final_region, (int)view_x, (int)view_y);
Alexander Larsson1f206b42013-05-22 14:41:36 +0200202 }
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300203
Alexander Larsson1f206b42013-05-22 14:41:36 +0200204 /* We need to paint the intersection */
205 pixman_region32_intersect(&final_region, &final_region, region);
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300206 } else {
Alexander Larsson1f206b42013-05-22 14:41:36 +0200207 /* If there is no surface region, just use the global region */
208 pixman_region32_copy(&final_region, region);
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300209 }
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300210
Alexander Larsson1f206b42013-05-22 14:41:36 +0200211 /* Convert from global to output coord */
212 region_global_to_output(output, &final_region);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300213
Alexander Larsson1f206b42013-05-22 14:41:36 +0200214 /* And clip to it */
215 pixman_image_set_clip_region32 (po->shadow_image, &final_region);
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200216
Alexander Larsson1f206b42013-05-22 14:41:36 +0200217 /* Set up the source transformation based on the surface
Alexander Larsson4ea95522013-05-22 14:41:37 +0200218 position, the output position/transform/scale and the client
219 specified buffer transform/scale */
Alexander Larsson1f206b42013-05-22 14:41:36 +0200220 pixman_transform_init_identity(&transform);
Alexander Larsson4ea95522013-05-22 14:41:37 +0200221 pixman_transform_scale(&transform, NULL,
Hardeningff39efa2013-09-18 23:56:35 +0200222 pixman_double_to_fixed ((double)1.0/output->current_scale),
223 pixman_double_to_fixed ((double)1.0/output->current_scale));
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200224
Alexander Larsson1f206b42013-05-22 14:41:36 +0200225 fw = pixman_int_to_fixed(output->width);
226 fh = pixman_int_to_fixed(output->height);
227 switch (output->transform) {
228 default:
229 case WL_OUTPUT_TRANSFORM_NORMAL:
230 case WL_OUTPUT_TRANSFORM_FLIPPED:
231 break;
232 case WL_OUTPUT_TRANSFORM_90:
233 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
234 pixman_transform_rotate(&transform, NULL, 0, -pixman_fixed_1);
235 pixman_transform_translate(&transform, NULL, 0, fh);
236 break;
237 case WL_OUTPUT_TRANSFORM_180:
238 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
239 pixman_transform_rotate(&transform, NULL, -pixman_fixed_1, 0);
240 pixman_transform_translate(&transform, NULL, fw, fh);
241 break;
242 case WL_OUTPUT_TRANSFORM_270:
243 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
244 pixman_transform_rotate(&transform, NULL, 0, pixman_fixed_1);
245 pixman_transform_translate(&transform, NULL, fw, 0);
246 break;
247 }
248
249 switch (output->transform) {
250 case WL_OUTPUT_TRANSFORM_FLIPPED:
251 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
252 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
253 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
254 pixman_transform_scale(&transform, NULL,
255 pixman_int_to_fixed (-1),
256 pixman_int_to_fixed (1));
257 pixman_transform_translate(&transform, NULL, fw, 0);
258 break;
259 }
260
261 pixman_transform_translate(&transform, NULL,
262 pixman_double_to_fixed (output->x),
263 pixman_double_to_fixed (output->y));
264
Jason Ekstranda7af7042013-10-12 22:38:11 -0500265 if (ev->transform.enabled) {
Alexander Larsson1f206b42013-05-22 14:41:36 +0200266 /* Pixman supports only 2D transform matrix, but Weston uses 3D,
267 * so we're omitting Z coordinate here
268 */
269 pixman_transform_t surface_transform = {{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500270 { D2F(ev->transform.matrix.d[0]),
271 D2F(ev->transform.matrix.d[4]),
272 D2F(ev->transform.matrix.d[12]),
Alexander Larsson1f206b42013-05-22 14:41:36 +0200273 },
Jason Ekstranda7af7042013-10-12 22:38:11 -0500274 { D2F(ev->transform.matrix.d[1]),
275 D2F(ev->transform.matrix.d[5]),
276 D2F(ev->transform.matrix.d[13]),
Alexander Larsson1f206b42013-05-22 14:41:36 +0200277 },
Jason Ekstranda7af7042013-10-12 22:38:11 -0500278 { D2F(ev->transform.matrix.d[3]),
279 D2F(ev->transform.matrix.d[7]),
280 D2F(ev->transform.matrix.d[15]),
Alexander Larsson1f206b42013-05-22 14:41:36 +0200281 }
282 }};
283
284 pixman_transform_invert(&surface_transform, &surface_transform);
285 pixman_transform_multiply (&transform, &surface_transform, &transform);
286 } else {
287 pixman_transform_translate(&transform, NULL,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500288 pixman_double_to_fixed ((double)-ev->geometry.x),
289 pixman_double_to_fixed ((double)-ev->geometry.y));
Alexander Larsson1f206b42013-05-22 14:41:36 +0200290 }
291
Pekka Paalanen0b4c5352014-03-14 14:38:17 +0200292 transform_apply_viewport(&transform, ev->surface);
Jonny Lambfa1b3052013-11-26 18:19:47 +0100293
Jason Ekstrand42833702014-04-21 21:04:42 -0500294 fw = pixman_int_to_fixed(ev->surface->width_from_buffer);
295 fh = pixman_int_to_fixed(ev->surface->height_from_buffer);
Alexander Larsson1f206b42013-05-22 14:41:36 +0200296
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200297 switch (vp->buffer.transform) {
Alexander Larsson1f206b42013-05-22 14:41:36 +0200298 case WL_OUTPUT_TRANSFORM_FLIPPED:
299 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
300 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
301 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
302 pixman_transform_scale(&transform, NULL,
303 pixman_int_to_fixed (-1),
304 pixman_int_to_fixed (1));
305 pixman_transform_translate(&transform, NULL, fw, 0);
306 break;
307 }
308
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200309 switch (vp->buffer.transform) {
Alexander Larsson1f206b42013-05-22 14:41:36 +0200310 default:
311 case WL_OUTPUT_TRANSFORM_NORMAL:
312 case WL_OUTPUT_TRANSFORM_FLIPPED:
313 break;
314 case WL_OUTPUT_TRANSFORM_90:
315 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
316 pixman_transform_rotate(&transform, NULL, 0, pixman_fixed_1);
317 pixman_transform_translate(&transform, NULL, fh, 0);
318 break;
319 case WL_OUTPUT_TRANSFORM_180:
320 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
321 pixman_transform_rotate(&transform, NULL, -pixman_fixed_1, 0);
322 pixman_transform_translate(&transform, NULL, fw, fh);
323 break;
324 case WL_OUTPUT_TRANSFORM_270:
325 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
326 pixman_transform_rotate(&transform, NULL, 0, -pixman_fixed_1);
327 pixman_transform_translate(&transform, NULL, 0, fw);
328 break;
329 }
330
Jason Ekstrand50fba972014-02-25 21:54:59 -0600331 pixman_transform_scale(&transform, NULL,
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200332 pixman_double_to_fixed(vp->buffer.scale),
333 pixman_double_to_fixed(vp->buffer.scale));
Jason Ekstrand50fba972014-02-25 21:54:59 -0600334
Alexander Larsson1f206b42013-05-22 14:41:36 +0200335 pixman_image_set_transform(ps->image, &transform);
336
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200337 if (ev->transform.enabled || output->current_scale != vp->buffer.scale)
Alexander Larsson1f206b42013-05-22 14:41:36 +0200338 pixman_image_set_filter(ps->image, PIXMAN_FILTER_BILINEAR, NULL, 0);
339 else
340 pixman_image_set_filter(ps->image, PIXMAN_FILTER_NEAREST, NULL, 0);
341
Neil Robertse5051712013-11-13 15:44:06 +0000342 if (ps->buffer_ref.buffer)
343 wl_shm_buffer_begin_access(ps->buffer_ref.buffer->shm_buffer);
344
Manuel Bachmannb1fff412014-04-05 05:31:37 +0200345 if (ev->alpha < 1.0) {
Manuel Bachmann9c4ab662014-04-07 11:58:45 +0200346 mask.alpha = 0xffff * ev->alpha;
Manuel Bachmannb1fff412014-04-05 05:31:37 +0200347 mask_image = pixman_image_create_solid_fill(&mask);
Manuel Bachmann9c4ab662014-04-07 11:58:45 +0200348 } else {
Manuel Bachmannb1fff412014-04-05 05:31:37 +0200349 mask_image = NULL;
Manuel Bachmann9c4ab662014-04-07 11:58:45 +0200350 }
Manuel Bachmannb1fff412014-04-05 05:31:37 +0200351
Alexander Larsson1f206b42013-05-22 14:41:36 +0200352 pixman_image_composite32(pixman_op,
353 ps->image, /* src */
Manuel Bachmannb1fff412014-04-05 05:31:37 +0200354 mask_image, /* mask */
Alexander Larsson1f206b42013-05-22 14:41:36 +0200355 po->shadow_image, /* dest */
356 0, 0, /* src_x, src_y */
357 0, 0, /* mask_x, mask_y */
358 0, 0, /* dest_x, dest_y */
359 pixman_image_get_width (po->shadow_image), /* width */
360 pixman_image_get_height (po->shadow_image) /* height */);
361
Manuel Bachmann9c4ab662014-04-07 11:58:45 +0200362 if (mask_image)
363 pixman_image_unref(mask_image);
364
Neil Robertse5051712013-11-13 15:44:06 +0000365 if (ps->buffer_ref.buffer)
366 wl_shm_buffer_end_access(ps->buffer_ref.buffer->shm_buffer);
367
Alexander Larsson1f206b42013-05-22 14:41:36 +0200368 if (pr->repaint_debug)
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200369 pixman_image_composite32(PIXMAN_OP_OVER,
Alexander Larsson1f206b42013-05-22 14:41:36 +0200370 pr->debug_color, /* src */
371 NULL /* mask */,
372 po->shadow_image, /* dest */
373 0, 0, /* src_x, src_y */
374 0, 0, /* mask_x, mask_y */
375 0, 0, /* dest_x, dest_y */
376 pixman_image_get_width (po->shadow_image), /* width */
377 pixman_image_get_height (po->shadow_image) /* height */);
378
379 pixman_image_set_clip_region32 (po->shadow_image, NULL);
380
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300381 pixman_region32_fini(&final_region);
382}
383
384static void
Jason Ekstranda7af7042013-10-12 22:38:11 -0500385draw_view(struct weston_view *ev, struct weston_output *output,
386 pixman_region32_t *damage) /* in global coordinates */
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300387{
Derek Foreman66951b72014-09-01 10:33:28 -0500388 static int zoom_logged = 0;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500389 struct pixman_surface_state *ps = get_surface_state(ev->surface);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300390 /* repaint bounding region in global coordinates: */
391 pixman_region32_t repaint;
392 /* non-opaque region in surface coordinates: */
393 pixman_region32_t surface_blend;
394
395 /* No buffer attached */
396 if (!ps->image)
397 return;
398
399 pixman_region32_init(&repaint);
400 pixman_region32_intersect(&repaint,
Giulio Camuffo95ec0f92014-07-09 22:12:57 +0300401 &ev->transform.masked_boundingbox, damage);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500402 pixman_region32_subtract(&repaint, &repaint, &ev->clip);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300403
404 if (!pixman_region32_not_empty(&repaint))
405 goto out;
406
Derek Foreman66951b72014-09-01 10:33:28 -0500407 if (output->zoom.active && !zoom_logged) {
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300408 weston_log("pixman renderer does not support zoom\n");
Derek Foreman66951b72014-09-01 10:33:28 -0500409 zoom_logged = 1;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300410 }
411
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300412 /* TODO: Implement repaint_region_complex() using pixman_composite_trapezoids() */
Manuel Bachmann9c4ab662014-04-07 11:58:45 +0200413 if (ev->alpha != 1.0 ||
414 (ev->transform.enabled &&
415 ev->transform.matrix.type != WESTON_MATRIX_TRANSFORM_TRANSLATE)) {
Jason Ekstranda7af7042013-10-12 22:38:11 -0500416 repaint_region(ev, output, &repaint, NULL, PIXMAN_OP_OVER);
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300417 } else {
418 /* blended region is whole surface minus opaque region: */
419 pixman_region32_init_rect(&surface_blend, 0, 0,
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600420 ev->surface->width, ev->surface->height);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500421 pixman_region32_subtract(&surface_blend, &surface_blend, &ev->surface->opaque);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300422
Jason Ekstranda7af7042013-10-12 22:38:11 -0500423 if (pixman_region32_not_empty(&ev->surface->opaque)) {
424 repaint_region(ev, output, &repaint, &ev->surface->opaque, PIXMAN_OP_SRC);
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300425 }
426
427 if (pixman_region32_not_empty(&surface_blend)) {
Jason Ekstranda7af7042013-10-12 22:38:11 -0500428 repaint_region(ev, output, &repaint, &surface_blend, PIXMAN_OP_OVER);
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300429 }
430 pixman_region32_fini(&surface_blend);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300431 }
432
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300433
434out:
435 pixman_region32_fini(&repaint);
436}
437static void
438repaint_surfaces(struct weston_output *output, pixman_region32_t *damage)
439{
440 struct weston_compositor *compositor = output->compositor;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500441 struct weston_view *view;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300442
Jason Ekstranda7af7042013-10-12 22:38:11 -0500443 wl_list_for_each_reverse(view, &compositor->view_list, link)
444 if (view->plane == &compositor->primary_plane)
445 draw_view(view, output, damage);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300446}
447
448static void
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200449copy_to_hw_buffer(struct weston_output *output, pixman_region32_t *region)
450{
451 struct pixman_output_state *po = get_output_state(output);
Alexander Larsson1f206b42013-05-22 14:41:36 +0200452 pixman_region32_t output_region;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200453
Alexander Larsson1f206b42013-05-22 14:41:36 +0200454 pixman_region32_init(&output_region);
455 pixman_region32_copy(&output_region, region);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200456
Alexander Larsson1f206b42013-05-22 14:41:36 +0200457 region_global_to_output(output, &output_region);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200458
Alexander Larsson1f206b42013-05-22 14:41:36 +0200459 pixman_image_set_clip_region32 (po->hw_buffer, &output_region);
Ryo Munakata389d2052014-09-04 01:56:53 +0900460 pixman_region32_fini(&output_region);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200461
Alexander Larsson1f206b42013-05-22 14:41:36 +0200462 pixman_image_composite32(PIXMAN_OP_SRC,
463 po->shadow_image, /* src */
464 NULL /* mask */,
465 po->hw_buffer, /* dest */
466 0, 0, /* src_x, src_y */
467 0, 0, /* mask_x, mask_y */
468 0, 0, /* dest_x, dest_y */
469 pixman_image_get_width (po->hw_buffer), /* width */
470 pixman_image_get_height (po->hw_buffer) /* height */);
471
472 pixman_image_set_clip_region32 (po->hw_buffer, NULL);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200473}
474
475static void
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300476pixman_renderer_repaint_output(struct weston_output *output,
477 pixman_region32_t *output_damage)
478{
479 struct pixman_output_state *po = get_output_state(output);
480
481 if (!po->hw_buffer)
482 return;
483
484 repaint_surfaces(output, output_damage);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200485 copy_to_hw_buffer(output, output_damage);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300486
487 pixman_region32_copy(&output->previous_damage, output_damage);
488 wl_signal_emit(&output->frame_signal, output);
489
490 /* Actual flip should be done by caller */
491}
492
493static void
494pixman_renderer_flush_damage(struct weston_surface *surface)
495{
496 /* No-op for pixman renderer */
497}
498
499static void
Lubomir Rintelddc2b1e2013-12-12 12:57:56 +0100500buffer_state_handle_buffer_destroy(struct wl_listener *listener, void *data)
501{
502 struct pixman_surface_state *ps;
503
504 ps = container_of(listener, struct pixman_surface_state,
505 buffer_destroy_listener);
506
507 if (ps->image) {
508 pixman_image_unref(ps->image);
509 ps->image = NULL;
510 }
511
512 ps->buffer_destroy_listener.notify = NULL;
513}
514
515static void
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500516pixman_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300517{
518 struct pixman_surface_state *ps = get_surface_state(es);
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500519 struct wl_shm_buffer *shm_buffer;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300520 pixman_format_code_t pixman_format;
521
522 weston_buffer_reference(&ps->buffer_ref, buffer);
523
Lubomir Rintelddc2b1e2013-12-12 12:57:56 +0100524 if (ps->buffer_destroy_listener.notify) {
525 wl_list_remove(&ps->buffer_destroy_listener.link);
526 ps->buffer_destroy_listener.notify = NULL;
527 }
528
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300529 if (ps->image) {
530 pixman_image_unref(ps->image);
531 ps->image = NULL;
532 }
533
534 if (!buffer)
535 return;
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500536
537 shm_buffer = wl_shm_buffer_get(buffer->resource);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300538
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500539 if (! shm_buffer) {
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300540 weston_log("Pixman renderer supports only SHM buffers\n");
541 weston_buffer_reference(&ps->buffer_ref, NULL);
542 return;
543 }
544
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500545 switch (wl_shm_buffer_get_format(shm_buffer)) {
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300546 case WL_SHM_FORMAT_XRGB8888:
547 pixman_format = PIXMAN_x8r8g8b8;
548 break;
549 case WL_SHM_FORMAT_ARGB8888:
550 pixman_format = PIXMAN_a8r8g8b8;
551 break;
Tomeu Vizoso1c1fc292013-08-06 20:05:56 +0200552 case WL_SHM_FORMAT_RGB565:
553 pixman_format = PIXMAN_r5g6b5;
554 break;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300555 default:
556 weston_log("Unsupported SHM buffer format\n");
557 weston_buffer_reference(&ps->buffer_ref, NULL);
558 return;
559 break;
560 }
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500561
562 buffer->shm_buffer = shm_buffer;
563 buffer->width = wl_shm_buffer_get_width(shm_buffer);
564 buffer->height = wl_shm_buffer_get_height(shm_buffer);
565
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300566 ps->image = pixman_image_create_bits(pixman_format,
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500567 buffer->width, buffer->height,
568 wl_shm_buffer_get_data(shm_buffer),
569 wl_shm_buffer_get_stride(shm_buffer));
Lubomir Rintelddc2b1e2013-12-12 12:57:56 +0100570
571 ps->buffer_destroy_listener.notify =
572 buffer_state_handle_buffer_destroy;
573 wl_signal_add(&buffer->destroy_signal,
574 &ps->buffer_destroy_listener);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300575}
576
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300577static void
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300578pixman_renderer_surface_state_destroy(struct pixman_surface_state *ps)
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300579{
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300580 wl_list_remove(&ps->surface_destroy_listener.link);
581 wl_list_remove(&ps->renderer_destroy_listener.link);
Lubomir Rintelddc2b1e2013-12-12 12:57:56 +0100582 if (ps->buffer_destroy_listener.notify) {
583 wl_list_remove(&ps->buffer_destroy_listener.link);
584 ps->buffer_destroy_listener.notify = NULL;
585 }
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300586
587 ps->surface->renderer_state = NULL;
588
589 if (ps->image) {
590 pixman_image_unref(ps->image);
591 ps->image = NULL;
592 }
593 weston_buffer_reference(&ps->buffer_ref, NULL);
594 free(ps);
595}
596
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300597static void
598surface_state_handle_surface_destroy(struct wl_listener *listener, void *data)
599{
600 struct pixman_surface_state *ps;
601
602 ps = container_of(listener, struct pixman_surface_state,
603 surface_destroy_listener);
604
605 pixman_renderer_surface_state_destroy(ps);
606}
607
608static void
609surface_state_handle_renderer_destroy(struct wl_listener *listener, void *data)
610{
611 struct pixman_surface_state *ps;
612
613 ps = container_of(listener, struct pixman_surface_state,
614 renderer_destroy_listener);
615
616 pixman_renderer_surface_state_destroy(ps);
617}
618
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300619static int
620pixman_renderer_create_surface(struct weston_surface *surface)
621{
622 struct pixman_surface_state *ps;
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300623 struct pixman_renderer *pr = get_renderer(surface->compositor);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300624
Bryce Harringtonde16d892014-11-20 22:21:57 -0800625 ps = zalloc(sizeof *ps);
626 if (ps == NULL)
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300627 return -1;
628
629 surface->renderer_state = ps;
630
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300631 ps->surface = surface;
632
633 ps->surface_destroy_listener.notify =
634 surface_state_handle_surface_destroy;
635 wl_signal_add(&surface->destroy_signal,
636 &ps->surface_destroy_listener);
637
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300638 ps->renderer_destroy_listener.notify =
639 surface_state_handle_renderer_destroy;
640 wl_signal_add(&pr->destroy_signal,
641 &ps->renderer_destroy_listener);
642
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300643 return 0;
644}
645
646static void
647pixman_renderer_surface_set_color(struct weston_surface *es,
648 float red, float green, float blue, float alpha)
649{
650 struct pixman_surface_state *ps = get_surface_state(es);
651 pixman_color_t color;
652
653 color.red = red * 0xffff;
654 color.green = green * 0xffff;
655 color.blue = blue * 0xffff;
656 color.alpha = alpha * 0xffff;
657
658 if (ps->image) {
659 pixman_image_unref(ps->image);
660 ps->image = NULL;
661 }
662
663 ps->image = pixman_image_create_solid_fill(&color);
664}
665
666static void
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300667pixman_renderer_destroy(struct weston_compositor *ec)
668{
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +0300669 struct pixman_renderer *pr = get_renderer(ec);
670
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300671 wl_signal_emit(&pr->destroy_signal, pr);
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +0300672 weston_binding_destroy(pr->debug_binding);
673 free(pr);
674
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300675 ec->renderer = NULL;
676}
677
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200678static void
Kristian Høgsberge3148752013-05-06 23:19:49 -0400679debug_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200680 void *data)
681{
682 struct weston_compositor *ec = data;
683 struct pixman_renderer *pr = (struct pixman_renderer *) ec->renderer;
684
685 pr->repaint_debug ^= 1;
686
687 if (pr->repaint_debug) {
688 pixman_color_t red = {
689 0x3fff, 0x0000, 0x0000, 0x3fff
690 };
691
692 pr->debug_color = pixman_image_create_solid_fill(&red);
693 } else {
694 pixman_image_unref(pr->debug_color);
695 weston_compositor_damage_all(ec);
696 }
697}
698
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300699WL_EXPORT int
700pixman_renderer_init(struct weston_compositor *ec)
701{
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200702 struct pixman_renderer *renderer;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300703
Bryce Harringtonde16d892014-11-20 22:21:57 -0800704 renderer = zalloc(sizeof *renderer);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300705 if (renderer == NULL)
706 return -1;
707
Philipp Brüschweilerf3e39f92013-03-08 20:35:39 +0100708 renderer->repaint_debug = 0;
709 renderer->debug_color = NULL;
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200710 renderer->base.read_pixels = pixman_renderer_read_pixels;
711 renderer->base.repaint_output = pixman_renderer_repaint_output;
712 renderer->base.flush_damage = pixman_renderer_flush_damage;
713 renderer->base.attach = pixman_renderer_attach;
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200714 renderer->base.surface_set_color = pixman_renderer_surface_set_color;
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200715 renderer->base.destroy = pixman_renderer_destroy;
716 ec->renderer = &renderer->base;
Pekka Paalanen7bb65102013-05-22 18:03:04 +0300717 ec->capabilities |= WESTON_CAP_ROTATION_ANY;
Pekka Paalanen4fc5dd02013-05-22 18:03:05 +0300718 ec->capabilities |= WESTON_CAP_CAPTURE_YFLIP;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300719
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +0300720 renderer->debug_binding =
721 weston_compositor_add_debug_binding(ec, KEY_R,
722 debug_binding, ec);
Tomeu Vizoso1c1fc292013-08-06 20:05:56 +0200723
724 wl_display_add_shm_format(ec->wl_display, WL_SHM_FORMAT_RGB565);
725
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300726 wl_signal_init(&renderer->destroy_signal);
727
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300728 return 0;
729}
730
731WL_EXPORT void
732pixman_renderer_output_set_buffer(struct weston_output *output, pixman_image_t *buffer)
733{
734 struct pixman_output_state *po = get_output_state(output);
735
736 if (po->hw_buffer)
737 pixman_image_unref(po->hw_buffer);
738 po->hw_buffer = buffer;
739
740 if (po->hw_buffer) {
741 output->compositor->read_format = pixman_image_get_format(po->hw_buffer);
742 pixman_image_ref(po->hw_buffer);
743 }
744}
745
746WL_EXPORT int
747pixman_renderer_output_create(struct weston_output *output)
748{
Bryce Harringtonde16d892014-11-20 22:21:57 -0800749 struct pixman_output_state *po;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200750 int w, h;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300751
Bryce Harringtonde16d892014-11-20 22:21:57 -0800752 po = zalloc(sizeof *po);
753 if (po == NULL)
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300754 return -1;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200755
756 /* set shadow image transformation */
Hardeningff39efa2013-09-18 23:56:35 +0200757 w = output->current_mode->width;
758 h = output->current_mode->height;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200759
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200760 po->shadow_buffer = malloc(w * h * 4);
761
762 if (!po->shadow_buffer) {
763 free(po);
764 return -1;
765 }
766
767 po->shadow_image =
768 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
769 po->shadow_buffer, w * 4);
770
771 if (!po->shadow_image) {
772 free(po->shadow_buffer);
773 free(po);
774 return -1;
775 }
776
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300777 output->renderer_state = po;
778
779 return 0;
780}
781
782WL_EXPORT void
783pixman_renderer_output_destroy(struct weston_output *output)
784{
785 struct pixman_output_state *po = get_output_state(output);
786
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200787 pixman_image_unref(po->shadow_image);
Ander Conselvan de Oliveira23e72b82013-01-25 15:13:06 +0200788
789 if (po->hw_buffer)
790 pixman_image_unref(po->hw_buffer);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200791
Arnaud Vrac8e3fe082014-08-25 20:56:52 +0200792 free(po->shadow_buffer);
793
794 po->shadow_buffer = NULL;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200795 po->shadow_image = NULL;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300796 po->hw_buffer = NULL;
797
798 free(po);
799}