blob: 98a910ceb21efc557d10a626fd2e3d0251bee827 [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
45 struct wl_listener surface_destroy_listener;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030046};
47
48struct pixman_renderer {
49 struct weston_renderer base;
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +030050
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +020051 int repaint_debug;
52 pixman_image_t *debug_color;
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +030053 struct weston_binding *debug_binding;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030054};
55
56static inline struct pixman_output_state *
57get_output_state(struct weston_output *output)
58{
59 return (struct pixman_output_state *)output->renderer_state;
60}
61
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +030062static int
63pixman_renderer_create_surface(struct weston_surface *surface);
64
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030065static inline struct pixman_surface_state *
66get_surface_state(struct weston_surface *surface)
67{
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +030068 if (!surface->renderer_state)
69 pixman_renderer_create_surface(surface);
70
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030071 return (struct pixman_surface_state *)surface->renderer_state;
72}
73
74static inline struct pixman_renderer *
75get_renderer(struct weston_compositor *ec)
76{
77 return (struct pixman_renderer *)ec->renderer;
78}
79
80static int
81pixman_renderer_read_pixels(struct weston_output *output,
82 pixman_format_code_t format, void *pixels,
83 uint32_t x, uint32_t y,
84 uint32_t width, uint32_t height)
85{
86 struct pixman_output_state *po = get_output_state(output);
Alexander Larsson97af7922013-05-29 12:01:33 +020087 pixman_transform_t transform;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030088 pixman_image_t *out_buf;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030089
90 if (!po->hw_buffer) {
91 errno = ENODEV;
92 return -1;
93 }
94
95 out_buf = pixman_image_create_bits(format,
96 width,
97 height,
98 pixels,
99 (PIXMAN_FORMAT_BPP(format) / 8) * width);
100
Alexander Larsson97af7922013-05-29 12:01:33 +0200101 /* Caller expects vflipped source image */
102 pixman_transform_init_translate(&transform,
103 pixman_int_to_fixed (x),
104 pixman_int_to_fixed (y - pixman_image_get_height (po->hw_buffer)));
105 pixman_transform_scale(&transform, NULL,
106 pixman_fixed_1,
107 pixman_fixed_minus_1);
108 pixman_image_set_transform(po->hw_buffer, &transform);
109
110 pixman_image_composite32(PIXMAN_OP_SRC,
111 po->hw_buffer, /* src */
112 NULL /* mask */,
113 out_buf, /* dest */
114 0, 0, /* src_x, src_y */
115 0, 0, /* mask_x, mask_y */
116 0, 0, /* dest_x, dest_y */
117 pixman_image_get_width (po->hw_buffer), /* width */
118 pixman_image_get_height (po->hw_buffer) /* height */);
119 pixman_image_set_transform(po->hw_buffer, NULL);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300120
121 pixman_image_unref(out_buf);
122
123 return 0;
124}
125
Vasily Khoruzhick031fc872013-01-29 14:58:14 +0300126static void
Alexander Larsson4ea95522013-05-22 14:41:37 +0200127box_scale(pixman_box32_t *dst, int scale)
128{
129 dst->x1 *= scale;
130 dst->x2 *= scale;
131 dst->y1 *= scale;
132 dst->y2 *= scale;
133}
134
135static void
136scale_region (pixman_region32_t *region, int scale)
137{
138 pixman_box32_t *rects, *scaled_rects;
139 int nrects, i;
140
141 if (scale != 1) {
142 rects = pixman_region32_rectangles(region, &nrects);
143 scaled_rects = calloc(nrects, sizeof(pixman_box32_t));
144
145 for (i = 0; i < nrects; i++) {
146 scaled_rects[i] = rects[i];
147 box_scale(&scaled_rects[i], scale);
148 }
149 pixman_region32_clear(region);
150
151 pixman_region32_init_rects (region, scaled_rects, nrects);
152 free (scaled_rects);
153 }
154}
155
156static void
Alexander Larsson1f206b42013-05-22 14:41:36 +0200157transform_region (pixman_region32_t *region, int width, int height, enum wl_output_transform transform)
Vasily Khoruzhick031fc872013-01-29 14:58:14 +0300158{
Alexander Larsson1f206b42013-05-22 14:41:36 +0200159 pixman_box32_t *rects, *transformed_rects;
160 int nrects, i;
161
162 if (transform == WL_OUTPUT_TRANSFORM_NORMAL)
163 return;
164
165 rects = pixman_region32_rectangles(region, &nrects);
166 transformed_rects = calloc(nrects, sizeof(pixman_box32_t));
167
168 for (i = 0; i < nrects; i++) {
169 switch (transform) {
170 default:
171 case WL_OUTPUT_TRANSFORM_NORMAL:
172 transformed_rects[i].x1 = rects[i].x1;
173 transformed_rects[i].y1 = rects[i].y1;
174 transformed_rects[i].x2 = rects[i].x2;
175 transformed_rects[i].y2 = rects[i].y2;
176 break;
177 case WL_OUTPUT_TRANSFORM_90:
178 transformed_rects[i].x1 = height - rects[i].y2;
179 transformed_rects[i].y1 = rects[i].x1;
180 transformed_rects[i].x2 = height - rects[i].y1;
181 transformed_rects[i].y2 = rects[i].x2;
182 break;
183 case WL_OUTPUT_TRANSFORM_180:
184 transformed_rects[i].x1 = width - rects[i].x2;
185 transformed_rects[i].y1 = height - rects[i].y2;
186 transformed_rects[i].x2 = width - rects[i].x1;
187 transformed_rects[i].y2 = height - rects[i].y1;
188 break;
189 case WL_OUTPUT_TRANSFORM_270:
190 transformed_rects[i].x1 = rects[i].y1;
191 transformed_rects[i].y1 = width - rects[i].x2;
192 transformed_rects[i].x2 = rects[i].y2;
193 transformed_rects[i].y2 = width - rects[i].x1;
194 break;
195 case WL_OUTPUT_TRANSFORM_FLIPPED:
196 transformed_rects[i].x1 = width - rects[i].x2;
197 transformed_rects[i].y1 = rects[i].y1;
198 transformed_rects[i].x2 = width - rects[i].x1;
199 transformed_rects[i].y2 = rects[i].y2;
200 break;
201 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
202 transformed_rects[i].x1 = height - rects[i].y2;
203 transformed_rects[i].y1 = width - rects[i].x2;
204 transformed_rects[i].x2 = height - rects[i].y1;
205 transformed_rects[i].y2 = width - rects[i].x1;
206 break;
207 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
208 transformed_rects[i].x1 = rects[i].x1;
209 transformed_rects[i].y1 = height - rects[i].y2;
210 transformed_rects[i].x2 = rects[i].x2;
211 transformed_rects[i].y2 = height - rects[i].y1;
212 break;
213 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
214 transformed_rects[i].x1 = rects[i].y1;
215 transformed_rects[i].y1 = rects[i].x1;
216 transformed_rects[i].x2 = rects[i].y2;
217 transformed_rects[i].y2 = rects[i].x2;
218 break;
219 }
220 }
221 pixman_region32_clear(region);
222
223 pixman_region32_init_rects (region, transformed_rects, nrects);
224 free (transformed_rects);
225}
226
227static void
228region_global_to_output(struct weston_output *output, pixman_region32_t *region)
229{
230 pixman_region32_translate(region, -output->x, -output->y);
231 transform_region (region, output->width, output->height, output->transform);
Hardeningff39efa2013-09-18 23:56:35 +0200232 scale_region (region, output->current_scale);
Vasily Khoruzhick031fc872013-01-29 14:58:14 +0300233}
234
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300235#define D2F(v) pixman_double_to_fixed((double)v)
236
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300237static void
Jason Ekstranda7af7042013-10-12 22:38:11 -0500238repaint_region(struct weston_view *ev, struct weston_output *output,
Alexander Larsson1f206b42013-05-22 14:41:36 +0200239 pixman_region32_t *region, pixman_region32_t *surf_region,
240 pixman_op_t pixman_op)
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300241{
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200242 struct pixman_renderer *pr =
243 (struct pixman_renderer *) output->compositor->renderer;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500244 struct pixman_surface_state *ps = get_surface_state(ev->surface);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300245 struct pixman_output_state *po = get_output_state(output);
246 pixman_region32_t final_region;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500247 float view_x, view_y;
Alexander Larsson1f206b42013-05-22 14:41:36 +0200248 pixman_transform_t transform;
249 pixman_fixed_t fw, fh;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300250
251 /* The final region to be painted is the intersection of
252 * 'region' and 'surf_region'. However, 'region' is in the global
253 * coordinates, and 'surf_region' is in the surface-local
254 * coordinates
255 */
256 pixman_region32_init(&final_region);
Alexander Larsson1f206b42013-05-22 14:41:36 +0200257 if (surf_region) {
258 pixman_region32_copy(&final_region, surf_region);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300259
Alexander Larsson1f206b42013-05-22 14:41:36 +0200260 /* Convert from surface to global coordinates */
Jason Ekstranda7af7042013-10-12 22:38:11 -0500261 if (!ev->transform.enabled) {
262 pixman_region32_translate(&final_region, ev->geometry.x, ev->geometry.y);
Alexander Larsson1f206b42013-05-22 14:41:36 +0200263 } else {
Jason Ekstranda7af7042013-10-12 22:38:11 -0500264 weston_view_to_global_float(ev, 0, 0, &view_x, &view_y);
265 pixman_region32_translate(&final_region, (int)view_x, (int)view_y);
Alexander Larsson1f206b42013-05-22 14:41:36 +0200266 }
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300267
Alexander Larsson1f206b42013-05-22 14:41:36 +0200268 /* We need to paint the intersection */
269 pixman_region32_intersect(&final_region, &final_region, region);
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300270 } else {
Alexander Larsson1f206b42013-05-22 14:41:36 +0200271 /* If there is no surface region, just use the global region */
272 pixman_region32_copy(&final_region, region);
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300273 }
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300274
Alexander Larsson1f206b42013-05-22 14:41:36 +0200275 /* Convert from global to output coord */
276 region_global_to_output(output, &final_region);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300277
Alexander Larsson1f206b42013-05-22 14:41:36 +0200278 /* And clip to it */
279 pixman_image_set_clip_region32 (po->shadow_image, &final_region);
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200280
Alexander Larsson1f206b42013-05-22 14:41:36 +0200281 /* Set up the source transformation based on the surface
Alexander Larsson4ea95522013-05-22 14:41:37 +0200282 position, the output position/transform/scale and the client
283 specified buffer transform/scale */
Alexander Larsson1f206b42013-05-22 14:41:36 +0200284 pixman_transform_init_identity(&transform);
Alexander Larsson4ea95522013-05-22 14:41:37 +0200285 pixman_transform_scale(&transform, NULL,
Hardeningff39efa2013-09-18 23:56:35 +0200286 pixman_double_to_fixed ((double)1.0/output->current_scale),
287 pixman_double_to_fixed ((double)1.0/output->current_scale));
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200288
Alexander Larsson1f206b42013-05-22 14:41:36 +0200289 fw = pixman_int_to_fixed(output->width);
290 fh = pixman_int_to_fixed(output->height);
291 switch (output->transform) {
292 default:
293 case WL_OUTPUT_TRANSFORM_NORMAL:
294 case WL_OUTPUT_TRANSFORM_FLIPPED:
295 break;
296 case WL_OUTPUT_TRANSFORM_90:
297 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
298 pixman_transform_rotate(&transform, NULL, 0, -pixman_fixed_1);
299 pixman_transform_translate(&transform, NULL, 0, fh);
300 break;
301 case WL_OUTPUT_TRANSFORM_180:
302 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
303 pixman_transform_rotate(&transform, NULL, -pixman_fixed_1, 0);
304 pixman_transform_translate(&transform, NULL, fw, fh);
305 break;
306 case WL_OUTPUT_TRANSFORM_270:
307 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
308 pixman_transform_rotate(&transform, NULL, 0, pixman_fixed_1);
309 pixman_transform_translate(&transform, NULL, fw, 0);
310 break;
311 }
312
313 switch (output->transform) {
314 case WL_OUTPUT_TRANSFORM_FLIPPED:
315 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
316 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
317 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
318 pixman_transform_scale(&transform, NULL,
319 pixman_int_to_fixed (-1),
320 pixman_int_to_fixed (1));
321 pixman_transform_translate(&transform, NULL, fw, 0);
322 break;
323 }
324
325 pixman_transform_translate(&transform, NULL,
326 pixman_double_to_fixed (output->x),
327 pixman_double_to_fixed (output->y));
328
Jason Ekstranda7af7042013-10-12 22:38:11 -0500329 if (ev->transform.enabled) {
Alexander Larsson1f206b42013-05-22 14:41:36 +0200330 /* Pixman supports only 2D transform matrix, but Weston uses 3D,
331 * so we're omitting Z coordinate here
332 */
333 pixman_transform_t surface_transform = {{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500334 { D2F(ev->transform.matrix.d[0]),
335 D2F(ev->transform.matrix.d[4]),
336 D2F(ev->transform.matrix.d[12]),
Alexander Larsson1f206b42013-05-22 14:41:36 +0200337 },
Jason Ekstranda7af7042013-10-12 22:38:11 -0500338 { D2F(ev->transform.matrix.d[1]),
339 D2F(ev->transform.matrix.d[5]),
340 D2F(ev->transform.matrix.d[13]),
Alexander Larsson1f206b42013-05-22 14:41:36 +0200341 },
Jason Ekstranda7af7042013-10-12 22:38:11 -0500342 { D2F(ev->transform.matrix.d[3]),
343 D2F(ev->transform.matrix.d[7]),
344 D2F(ev->transform.matrix.d[15]),
Alexander Larsson1f206b42013-05-22 14:41:36 +0200345 }
346 }};
347
348 pixman_transform_invert(&surface_transform, &surface_transform);
349 pixman_transform_multiply (&transform, &surface_transform, &transform);
350 } else {
351 pixman_transform_translate(&transform, NULL,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500352 pixman_double_to_fixed ((double)-ev->geometry.x),
353 pixman_double_to_fixed ((double)-ev->geometry.y));
Alexander Larsson1f206b42013-05-22 14:41:36 +0200354 }
355
356
Jason Ekstranda7af7042013-10-12 22:38:11 -0500357 fw = pixman_int_to_fixed(ev->geometry.width);
358 fh = pixman_int_to_fixed(ev->geometry.height);
Alexander Larsson1f206b42013-05-22 14:41:36 +0200359
Jason Ekstranda7af7042013-10-12 22:38:11 -0500360 switch (ev->surface->buffer_transform) {
Alexander Larsson1f206b42013-05-22 14:41:36 +0200361 case WL_OUTPUT_TRANSFORM_FLIPPED:
362 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
363 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
364 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
365 pixman_transform_scale(&transform, NULL,
366 pixman_int_to_fixed (-1),
367 pixman_int_to_fixed (1));
368 pixman_transform_translate(&transform, NULL, fw, 0);
369 break;
370 }
371
Jason Ekstranda7af7042013-10-12 22:38:11 -0500372 switch (ev->surface->buffer_transform) {
Alexander Larsson1f206b42013-05-22 14:41:36 +0200373 default:
374 case WL_OUTPUT_TRANSFORM_NORMAL:
375 case WL_OUTPUT_TRANSFORM_FLIPPED:
376 break;
377 case WL_OUTPUT_TRANSFORM_90:
378 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
379 pixman_transform_rotate(&transform, NULL, 0, pixman_fixed_1);
380 pixman_transform_translate(&transform, NULL, fh, 0);
381 break;
382 case WL_OUTPUT_TRANSFORM_180:
383 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
384 pixman_transform_rotate(&transform, NULL, -pixman_fixed_1, 0);
385 pixman_transform_translate(&transform, NULL, fw, fh);
386 break;
387 case WL_OUTPUT_TRANSFORM_270:
388 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
389 pixman_transform_rotate(&transform, NULL, 0, -pixman_fixed_1);
390 pixman_transform_translate(&transform, NULL, 0, fw);
391 break;
392 }
393
Alexander Larsson4ea95522013-05-22 14:41:37 +0200394 pixman_transform_scale(&transform, NULL,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500395 pixman_double_to_fixed ((double)ev->surface->buffer_scale),
396 pixman_double_to_fixed ((double)ev->surface->buffer_scale));
Alexander Larsson4ea95522013-05-22 14:41:37 +0200397
Alexander Larsson1f206b42013-05-22 14:41:36 +0200398 pixman_image_set_transform(ps->image, &transform);
399
Jason Ekstranda7af7042013-10-12 22:38:11 -0500400 if (ev->transform.enabled || output->current_scale != ev->surface->buffer_scale)
Alexander Larsson1f206b42013-05-22 14:41:36 +0200401 pixman_image_set_filter(ps->image, PIXMAN_FILTER_BILINEAR, NULL, 0);
402 else
403 pixman_image_set_filter(ps->image, PIXMAN_FILTER_NEAREST, NULL, 0);
404
405 pixman_image_composite32(pixman_op,
406 ps->image, /* src */
407 NULL /* mask */,
408 po->shadow_image, /* dest */
409 0, 0, /* src_x, src_y */
410 0, 0, /* mask_x, mask_y */
411 0, 0, /* dest_x, dest_y */
412 pixman_image_get_width (po->shadow_image), /* width */
413 pixman_image_get_height (po->shadow_image) /* height */);
414
415 if (pr->repaint_debug)
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200416 pixman_image_composite32(PIXMAN_OP_OVER,
Alexander Larsson1f206b42013-05-22 14:41:36 +0200417 pr->debug_color, /* src */
418 NULL /* mask */,
419 po->shadow_image, /* dest */
420 0, 0, /* src_x, src_y */
421 0, 0, /* mask_x, mask_y */
422 0, 0, /* dest_x, dest_y */
423 pixman_image_get_width (po->shadow_image), /* width */
424 pixman_image_get_height (po->shadow_image) /* height */);
425
426 pixman_image_set_clip_region32 (po->shadow_image, NULL);
427
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300428 pixman_region32_fini(&final_region);
429}
430
431static void
Jason Ekstranda7af7042013-10-12 22:38:11 -0500432draw_view(struct weston_view *ev, struct weston_output *output,
433 pixman_region32_t *damage) /* in global coordinates */
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300434{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500435 struct pixman_surface_state *ps = get_surface_state(ev->surface);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300436 /* repaint bounding region in global coordinates: */
437 pixman_region32_t repaint;
438 /* non-opaque region in surface coordinates: */
439 pixman_region32_t surface_blend;
440
441 /* No buffer attached */
442 if (!ps->image)
443 return;
444
445 pixman_region32_init(&repaint);
446 pixman_region32_intersect(&repaint,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500447 &ev->transform.boundingbox, damage);
448 pixman_region32_subtract(&repaint, &repaint, &ev->clip);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300449
450 if (!pixman_region32_not_empty(&repaint))
451 goto out;
452
453 if (output->zoom.active) {
454 weston_log("pixman renderer does not support zoom\n");
455 goto out;
456 }
457
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300458 /* TODO: Implement repaint_region_complex() using pixman_composite_trapezoids() */
Jason Ekstranda7af7042013-10-12 22:38:11 -0500459 if (ev->transform.enabled &&
460 ev->transform.matrix.type != WESTON_MATRIX_TRANSFORM_TRANSLATE) {
461 repaint_region(ev, output, &repaint, NULL, PIXMAN_OP_OVER);
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300462 } else {
463 /* blended region is whole surface minus opaque region: */
464 pixman_region32_init_rect(&surface_blend, 0, 0,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500465 ev->geometry.width, ev->geometry.height);
466 pixman_region32_subtract(&surface_blend, &surface_blend, &ev->surface->opaque);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300467
Jason Ekstranda7af7042013-10-12 22:38:11 -0500468 if (pixman_region32_not_empty(&ev->surface->opaque)) {
469 repaint_region(ev, output, &repaint, &ev->surface->opaque, PIXMAN_OP_SRC);
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300470 }
471
472 if (pixman_region32_not_empty(&surface_blend)) {
Jason Ekstranda7af7042013-10-12 22:38:11 -0500473 repaint_region(ev, output, &repaint, &surface_blend, PIXMAN_OP_OVER);
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300474 }
475 pixman_region32_fini(&surface_blend);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300476 }
477
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300478
479out:
480 pixman_region32_fini(&repaint);
481}
482static void
483repaint_surfaces(struct weston_output *output, pixman_region32_t *damage)
484{
485 struct weston_compositor *compositor = output->compositor;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500486 struct weston_view *view;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300487
Jason Ekstranda7af7042013-10-12 22:38:11 -0500488 wl_list_for_each_reverse(view, &compositor->view_list, link)
489 if (view->plane == &compositor->primary_plane)
490 draw_view(view, output, damage);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300491}
492
493static void
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200494copy_to_hw_buffer(struct weston_output *output, pixman_region32_t *region)
495{
496 struct pixman_output_state *po = get_output_state(output);
Alexander Larsson1f206b42013-05-22 14:41:36 +0200497 pixman_region32_t output_region;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200498
Alexander Larsson1f206b42013-05-22 14:41:36 +0200499 pixman_region32_init(&output_region);
500 pixman_region32_copy(&output_region, region);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200501
Alexander Larsson1f206b42013-05-22 14:41:36 +0200502 region_global_to_output(output, &output_region);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200503
Alexander Larsson1f206b42013-05-22 14:41:36 +0200504 pixman_image_set_clip_region32 (po->hw_buffer, &output_region);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200505
Alexander Larsson1f206b42013-05-22 14:41:36 +0200506 pixman_image_composite32(PIXMAN_OP_SRC,
507 po->shadow_image, /* src */
508 NULL /* mask */,
509 po->hw_buffer, /* dest */
510 0, 0, /* src_x, src_y */
511 0, 0, /* mask_x, mask_y */
512 0, 0, /* dest_x, dest_y */
513 pixman_image_get_width (po->hw_buffer), /* width */
514 pixman_image_get_height (po->hw_buffer) /* height */);
515
516 pixman_image_set_clip_region32 (po->hw_buffer, NULL);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200517}
518
519static void
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300520pixman_renderer_repaint_output(struct weston_output *output,
521 pixman_region32_t *output_damage)
522{
523 struct pixman_output_state *po = get_output_state(output);
524
525 if (!po->hw_buffer)
526 return;
527
528 repaint_surfaces(output, output_damage);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200529 copy_to_hw_buffer(output, output_damage);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300530
531 pixman_region32_copy(&output->previous_damage, output_damage);
532 wl_signal_emit(&output->frame_signal, output);
533
534 /* Actual flip should be done by caller */
535}
536
537static void
538pixman_renderer_flush_damage(struct weston_surface *surface)
539{
540 /* No-op for pixman renderer */
541}
542
543static void
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500544pixman_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300545{
546 struct pixman_surface_state *ps = get_surface_state(es);
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500547 struct wl_shm_buffer *shm_buffer;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300548 pixman_format_code_t pixman_format;
549
550 weston_buffer_reference(&ps->buffer_ref, buffer);
551
552 if (ps->image) {
553 pixman_image_unref(ps->image);
554 ps->image = NULL;
555 }
556
557 if (!buffer)
558 return;
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500559
560 shm_buffer = wl_shm_buffer_get(buffer->resource);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300561
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500562 if (! shm_buffer) {
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300563 weston_log("Pixman renderer supports only SHM buffers\n");
564 weston_buffer_reference(&ps->buffer_ref, NULL);
565 return;
566 }
567
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500568 switch (wl_shm_buffer_get_format(shm_buffer)) {
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300569 case WL_SHM_FORMAT_XRGB8888:
570 pixman_format = PIXMAN_x8r8g8b8;
571 break;
572 case WL_SHM_FORMAT_ARGB8888:
573 pixman_format = PIXMAN_a8r8g8b8;
574 break;
Tomeu Vizoso1c1fc292013-08-06 20:05:56 +0200575 case WL_SHM_FORMAT_RGB565:
576 pixman_format = PIXMAN_r5g6b5;
577 break;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300578 default:
579 weston_log("Unsupported SHM buffer format\n");
580 weston_buffer_reference(&ps->buffer_ref, NULL);
581 return;
582 break;
583 }
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500584
585 buffer->shm_buffer = shm_buffer;
586 buffer->width = wl_shm_buffer_get_width(shm_buffer);
587 buffer->height = wl_shm_buffer_get_height(shm_buffer);
588
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300589 ps->image = pixman_image_create_bits(pixman_format,
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500590 buffer->width, buffer->height,
591 wl_shm_buffer_get_data(shm_buffer),
592 wl_shm_buffer_get_stride(shm_buffer));
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300593}
594
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300595static void
596surface_state_handle_surface_destroy(struct wl_listener *listener, void *data)
597{
598 struct pixman_surface_state *ps;
599
600 ps = container_of(listener, struct pixman_surface_state,
601 surface_destroy_listener);
602
603 ps->surface->renderer_state = NULL;
604
605 if (ps->image) {
606 pixman_image_unref(ps->image);
607 ps->image = NULL;
608 }
609 weston_buffer_reference(&ps->buffer_ref, NULL);
610 free(ps);
611}
612
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300613static int
614pixman_renderer_create_surface(struct weston_surface *surface)
615{
616 struct pixman_surface_state *ps;
617
618 ps = calloc(1, sizeof *ps);
619 if (!ps)
620 return -1;
621
622 surface->renderer_state = ps;
623
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300624 ps->surface = surface;
625
626 ps->surface_destroy_listener.notify =
627 surface_state_handle_surface_destroy;
628 wl_signal_add(&surface->destroy_signal,
629 &ps->surface_destroy_listener);
630
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300631 return 0;
632}
633
634static void
635pixman_renderer_surface_set_color(struct weston_surface *es,
636 float red, float green, float blue, float alpha)
637{
638 struct pixman_surface_state *ps = get_surface_state(es);
639 pixman_color_t color;
640
641 color.red = red * 0xffff;
642 color.green = green * 0xffff;
643 color.blue = blue * 0xffff;
644 color.alpha = alpha * 0xffff;
645
646 if (ps->image) {
647 pixman_image_unref(ps->image);
648 ps->image = NULL;
649 }
650
651 ps->image = pixman_image_create_solid_fill(&color);
652}
653
654static void
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300655pixman_renderer_destroy(struct weston_compositor *ec)
656{
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +0300657 struct pixman_renderer *pr = get_renderer(ec);
658
659 weston_binding_destroy(pr->debug_binding);
660 free(pr);
661
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300662 ec->renderer = NULL;
663}
664
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200665static void
Kristian Høgsberge3148752013-05-06 23:19:49 -0400666debug_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200667 void *data)
668{
669 struct weston_compositor *ec = data;
670 struct pixman_renderer *pr = (struct pixman_renderer *) ec->renderer;
671
672 pr->repaint_debug ^= 1;
673
674 if (pr->repaint_debug) {
675 pixman_color_t red = {
676 0x3fff, 0x0000, 0x0000, 0x3fff
677 };
678
679 pr->debug_color = pixman_image_create_solid_fill(&red);
680 } else {
681 pixman_image_unref(pr->debug_color);
682 weston_compositor_damage_all(ec);
683 }
684}
685
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300686WL_EXPORT int
687pixman_renderer_init(struct weston_compositor *ec)
688{
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200689 struct pixman_renderer *renderer;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300690
Ander Conselvan de Oliveirac68b1082013-10-25 16:26:31 +0300691 renderer = calloc(1, sizeof *renderer);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300692 if (renderer == NULL)
693 return -1;
694
Philipp Brüschweilerf3e39f92013-03-08 20:35:39 +0100695 renderer->repaint_debug = 0;
696 renderer->debug_color = NULL;
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200697 renderer->base.read_pixels = pixman_renderer_read_pixels;
698 renderer->base.repaint_output = pixman_renderer_repaint_output;
699 renderer->base.flush_damage = pixman_renderer_flush_damage;
700 renderer->base.attach = pixman_renderer_attach;
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200701 renderer->base.surface_set_color = pixman_renderer_surface_set_color;
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200702 renderer->base.destroy = pixman_renderer_destroy;
703 ec->renderer = &renderer->base;
Pekka Paalanen7bb65102013-05-22 18:03:04 +0300704 ec->capabilities |= WESTON_CAP_ROTATION_ANY;
Pekka Paalanen4fc5dd02013-05-22 18:03:05 +0300705 ec->capabilities |= WESTON_CAP_CAPTURE_YFLIP;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300706
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +0300707 renderer->debug_binding =
708 weston_compositor_add_debug_binding(ec, KEY_R,
709 debug_binding, ec);
Tomeu Vizoso1c1fc292013-08-06 20:05:56 +0200710
711 wl_display_add_shm_format(ec->wl_display, WL_SHM_FORMAT_RGB565);
712
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300713 return 0;
714}
715
716WL_EXPORT void
717pixman_renderer_output_set_buffer(struct weston_output *output, pixman_image_t *buffer)
718{
719 struct pixman_output_state *po = get_output_state(output);
720
721 if (po->hw_buffer)
722 pixman_image_unref(po->hw_buffer);
723 po->hw_buffer = buffer;
724
725 if (po->hw_buffer) {
726 output->compositor->read_format = pixman_image_get_format(po->hw_buffer);
727 pixman_image_ref(po->hw_buffer);
728 }
729}
730
731WL_EXPORT int
732pixman_renderer_output_create(struct weston_output *output)
733{
734 struct pixman_output_state *po = calloc(1, sizeof *po);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200735 int w, h;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300736
737 if (!po)
738 return -1;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200739
740 /* set shadow image transformation */
Hardeningff39efa2013-09-18 23:56:35 +0200741 w = output->current_mode->width;
742 h = output->current_mode->height;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200743
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200744 po->shadow_buffer = malloc(w * h * 4);
745
746 if (!po->shadow_buffer) {
747 free(po);
748 return -1;
749 }
750
751 po->shadow_image =
752 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
753 po->shadow_buffer, w * 4);
754
755 if (!po->shadow_image) {
756 free(po->shadow_buffer);
757 free(po);
758 return -1;
759 }
760
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300761 output->renderer_state = po;
762
763 return 0;
764}
765
766WL_EXPORT void
767pixman_renderer_output_destroy(struct weston_output *output)
768{
769 struct pixman_output_state *po = get_output_state(output);
770
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200771 pixman_image_unref(po->shadow_image);
Ander Conselvan de Oliveira23e72b82013-01-25 15:13:06 +0200772
773 if (po->hw_buffer)
774 pixman_image_unref(po->hw_buffer);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200775
776 po->shadow_image = NULL;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300777 po->hw_buffer = NULL;
778
779 free(po);
780}