blob: c650d5561e1f3976a4d2090717d86ee8f6e2d927 [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>
Pekka Paalanenf75b6bb2015-03-04 16:12:04 +020029#include <assert.h>
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030030
31#include "pixman-renderer.h"
32
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +020033#include <linux/input.h>
34
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030035struct pixman_output_state {
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +020036 void *shadow_buffer;
37 pixman_image_t *shadow_image;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030038 pixman_image_t *hw_buffer;
39};
40
41struct pixman_surface_state {
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +030042 struct weston_surface *surface;
43
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030044 pixman_image_t *image;
45 struct weston_buffer_reference buffer_ref;
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +030046
Lubomir Rintelddc2b1e2013-12-12 12:57:56 +010047 struct wl_listener buffer_destroy_listener;
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +030048 struct wl_listener surface_destroy_listener;
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +030049 struct wl_listener renderer_destroy_listener;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030050};
51
52struct pixman_renderer {
53 struct weston_renderer base;
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +030054
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +020055 int repaint_debug;
56 pixman_image_t *debug_color;
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +030057 struct weston_binding *debug_binding;
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +030058
59 struct wl_signal destroy_signal;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030060};
61
62static inline struct pixman_output_state *
63get_output_state(struct weston_output *output)
64{
65 return (struct pixman_output_state *)output->renderer_state;
66}
67
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +030068static int
69pixman_renderer_create_surface(struct weston_surface *surface);
70
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030071static inline struct pixman_surface_state *
72get_surface_state(struct weston_surface *surface)
73{
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +030074 if (!surface->renderer_state)
75 pixman_renderer_create_surface(surface);
76
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030077 return (struct pixman_surface_state *)surface->renderer_state;
78}
79
80static inline struct pixman_renderer *
81get_renderer(struct weston_compositor *ec)
82{
83 return (struct pixman_renderer *)ec->renderer;
84}
85
86static int
87pixman_renderer_read_pixels(struct weston_output *output,
88 pixman_format_code_t format, void *pixels,
89 uint32_t x, uint32_t y,
90 uint32_t width, uint32_t height)
91{
92 struct pixman_output_state *po = get_output_state(output);
Alexander Larsson97af7922013-05-29 12:01:33 +020093 pixman_transform_t transform;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030094 pixman_image_t *out_buf;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030095
96 if (!po->hw_buffer) {
97 errno = ENODEV;
98 return -1;
99 }
100
101 out_buf = pixman_image_create_bits(format,
102 width,
103 height,
104 pixels,
105 (PIXMAN_FORMAT_BPP(format) / 8) * width);
106
Alexander Larsson97af7922013-05-29 12:01:33 +0200107 /* Caller expects vflipped source image */
108 pixman_transform_init_translate(&transform,
109 pixman_int_to_fixed (x),
110 pixman_int_to_fixed (y - pixman_image_get_height (po->hw_buffer)));
111 pixman_transform_scale(&transform, NULL,
112 pixman_fixed_1,
113 pixman_fixed_minus_1);
114 pixman_image_set_transform(po->hw_buffer, &transform);
115
116 pixman_image_composite32(PIXMAN_OP_SRC,
117 po->hw_buffer, /* src */
118 NULL /* mask */,
119 out_buf, /* dest */
120 0, 0, /* src_x, src_y */
121 0, 0, /* mask_x, mask_y */
122 0, 0, /* dest_x, dest_y */
123 pixman_image_get_width (po->hw_buffer), /* width */
124 pixman_image_get_height (po->hw_buffer) /* height */);
125 pixman_image_set_transform(po->hw_buffer, NULL);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300126
127 pixman_image_unref(out_buf);
128
129 return 0;
130}
131
Vasily Khoruzhick031fc872013-01-29 14:58:14 +0300132static void
Alexander Larsson1f206b42013-05-22 14:41:36 +0200133region_global_to_output(struct weston_output *output, pixman_region32_t *region)
134{
135 pixman_region32_translate(region, -output->x, -output->y);
Jason Ekstrand33ff6362013-10-27 22:25:01 -0500136 weston_transformed_region(output->width, output->height,
137 output->transform, output->current_scale,
138 region, region);
Vasily Khoruzhick031fc872013-01-29 14:58:14 +0300139}
140
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300141#define D2F(v) pixman_double_to_fixed((double)v)
142
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300143static void
Jason Ekstrand8870a232014-05-20 15:53:19 -0500144weston_matrix_to_pixman_transform(pixman_transform_t *pt,
145 const struct weston_matrix *wm)
Pekka Paalanen0b4c5352014-03-14 14:38:17 +0200146{
Jason Ekstrand8870a232014-05-20 15:53:19 -0500147 /* Pixman supports only 2D transform matrix, but Weston uses 3D, *
148 * so we're omitting Z coordinate here. */
149 pt->matrix[0][0] = pixman_double_to_fixed(wm->d[0]);
150 pt->matrix[0][1] = pixman_double_to_fixed(wm->d[4]);
151 pt->matrix[0][2] = pixman_double_to_fixed(wm->d[12]);
152 pt->matrix[1][0] = pixman_double_to_fixed(wm->d[1]);
153 pt->matrix[1][1] = pixman_double_to_fixed(wm->d[5]);
154 pt->matrix[1][2] = pixman_double_to_fixed(wm->d[13]);
155 pt->matrix[2][0] = pixman_double_to_fixed(wm->d[3]);
156 pt->matrix[2][1] = pixman_double_to_fixed(wm->d[7]);
157 pt->matrix[2][2] = pixman_double_to_fixed(wm->d[15]);
Pekka Paalanen0b4c5352014-03-14 14:38:17 +0200158}
159
160static void
Pekka Paalanen6ea523b2015-03-04 14:18:39 +0200161pixman_renderer_compute_transform(pixman_transform_t *transform_out,
162 struct weston_view *ev,
163 struct weston_output *output)
164{
165 struct weston_matrix matrix;
166
167 /* Set up the source transformation based on the surface
168 position, the output position/transform/scale and the client
169 specified buffer transform/scale */
Derek Foremana5855ad2015-03-24 11:36:16 -0500170 matrix = output->inverse_matrix;
Pekka Paalanen6ea523b2015-03-04 14:18:39 +0200171
172 if (ev->transform.enabled) {
173 weston_matrix_multiply(&matrix, &ev->transform.inverse);
174 } else {
175 weston_matrix_translate(&matrix,
176 -ev->geometry.x, -ev->geometry.y, 0);
177 }
178
179 weston_matrix_multiply(&matrix, &ev->surface->surface_to_buffer_matrix);
180
181 weston_matrix_to_pixman_transform(transform_out, &matrix);
182}
183
Pekka Paalanen23d4af52015-03-04 16:18:26 +0200184static bool
185view_transformation_is_translation(struct weston_view *view)
186{
187 if (!view->transform.enabled)
188 return true;
189
190 if (view->transform.matrix.type <= WESTON_MATRIX_TRANSFORM_TRANSLATE)
191 return true;
192
193 return false;
194}
195
Pekka Paalanen6ea523b2015-03-04 14:18:39 +0200196static void
Pekka Paalanenf75b6bb2015-03-04 16:12:04 +0200197region_intersect_only_translation(pixman_region32_t *result_global,
198 pixman_region32_t *global,
199 pixman_region32_t *surf,
200 struct weston_view *view)
201{
202 float view_x, view_y;
203
204 assert(view_transformation_is_translation(view));
205
206 /* Convert from surface to global coordinates */
207 pixman_region32_copy(result_global, surf);
208 weston_view_to_global_float(view, 0, 0, &view_x, &view_y);
209 pixman_region32_translate(result_global, (int)view_x, (int)view_y);
210
211 pixman_region32_intersect(result_global, result_global, global);
212}
213
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200214static void
215composite_whole(pixman_op_t op,
216 pixman_image_t *src,
217 pixman_image_t *mask,
218 pixman_image_t *dest,
219 const pixman_transform_t *transform,
220 pixman_filter_t filter)
221{
222 int32_t dest_width;
223 int32_t dest_height;
224
225 dest_width = pixman_image_get_width(dest);
226 dest_height = pixman_image_get_height(dest);
227
228 pixman_image_set_transform(src, transform);
229 pixman_image_set_filter(src, filter, NULL, 0);
230
231 pixman_image_composite32(op, src, mask, dest,
232 0, 0, /* src_x, src_y */
233 0, 0, /* mask_x, mask_y */
234 0, 0, /* dest_x, dest_y */
235 dest_width, dest_height);
236}
237
238static void
239composite_clipped(pixman_image_t *src,
240 pixman_image_t *mask,
241 pixman_image_t *dest,
242 const pixman_transform_t *transform,
243 pixman_filter_t filter,
244 pixman_region32_t *src_clip)
245{
246 int n_box;
247 pixman_box32_t *boxes;
248 int32_t dest_width;
249 int32_t dest_height;
250 int src_stride;
251 int bitspp;
252 pixman_format_code_t src_format;
253 void *src_data;
254 int i;
255
256 /* Hardcoded to use PIXMAN_OP_OVER, because sampling outside of
257 * a Pixman image produces (0,0,0,0) instead of discarding the
258 * fragment.
259 */
260
261 dest_width = pixman_image_get_width(dest);
262 dest_height = pixman_image_get_height(dest);
263 src_format = pixman_image_get_format(src);
264 src_stride = pixman_image_get_stride(src);
265 bitspp = PIXMAN_FORMAT_BPP(src_format);
266 src_data = pixman_image_get_data(src);
267
268 assert(src_format);
269
270 /* This would be massive overdraw, except when n_box is 1. */
271 boxes = pixman_region32_rectangles(src_clip, &n_box);
272 for (i = 0; i < n_box; i++) {
273 uint8_t *ptr = src_data;
274 pixman_image_t *boximg;
275 pixman_transform_t adj = *transform;
276
277 ptr += boxes[i].y1 * src_stride;
278 ptr += boxes[i].x1 * bitspp / 8;
279 boximg = pixman_image_create_bits_no_clear(src_format,
280 boxes[i].x2 - boxes[i].x1,
281 boxes[i].y2 - boxes[i].y1,
282 (uint32_t *)ptr, src_stride);
283
284 pixman_transform_translate(&adj, NULL,
285 pixman_int_to_fixed(-boxes[i].x1),
286 pixman_int_to_fixed(-boxes[i].y1));
287 pixman_image_set_transform(boximg, &adj);
288
289 pixman_image_set_filter(boximg, filter, NULL, 0);
290 pixman_image_composite32(PIXMAN_OP_OVER, boximg, mask, dest,
291 0, 0, /* src_x, src_y */
292 0, 0, /* mask_x, mask_y */
293 0, 0, /* dest_x, dest_y */
294 dest_width, dest_height);
295
296 pixman_image_unref(boximg);
297 }
298
299 if (n_box > 1) {
300 static bool warned = false;
301
302 if (!warned)
303 weston_log("Pixman-renderer warning: %dx overdraw\n",
304 n_box);
305 warned = true;
306 }
307}
308
Pekka Paalanen11af0d92015-03-05 11:56:29 +0200309/** Paint an intersected region
310 *
311 * \param ev The view to be painted.
312 * \param output The output being painted.
313 * \param repaint_output The region to be painted in output coordinates.
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200314 * \param source_clip The region of the source image to use, in source image
315 * coordinates. If NULL, use the whole source image.
Pekka Paalanen11af0d92015-03-05 11:56:29 +0200316 * \param pixman_op Compositing operator, either SRC or OVER.
317 */
Pekka Paalanenf75b6bb2015-03-04 16:12:04 +0200318static void
Jason Ekstranda7af7042013-10-12 22:38:11 -0500319repaint_region(struct weston_view *ev, struct weston_output *output,
Pekka Paalanen11af0d92015-03-05 11:56:29 +0200320 pixman_region32_t *repaint_output,
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200321 pixman_region32_t *source_clip,
Alexander Larsson1f206b42013-05-22 14:41:36 +0200322 pixman_op_t pixman_op)
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300323{
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200324 struct pixman_renderer *pr =
325 (struct pixman_renderer *) output->compositor->renderer;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500326 struct pixman_surface_state *ps = get_surface_state(ev->surface);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300327 struct pixman_output_state *po = get_output_state(output);
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200328 struct weston_buffer_viewport *vp = &ev->surface->buffer_viewport;
Alexander Larsson1f206b42013-05-22 14:41:36 +0200329 pixman_transform_t transform;
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200330 pixman_filter_t filter;
Manuel Bachmann9c4ab662014-04-07 11:58:45 +0200331 pixman_image_t *mask_image;
332 pixman_color_t mask = { 0, };
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300333
Pekka Paalanen11af0d92015-03-05 11:56:29 +0200334 /* Clip rendering to the damaged output region */
335 pixman_image_set_clip_region32(po->shadow_image, repaint_output);
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200336
Pekka Paalanen6ea523b2015-03-04 14:18:39 +0200337 pixman_renderer_compute_transform(&transform, ev, output);
Alexander Larsson1f206b42013-05-22 14:41:36 +0200338
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200339 if (ev->transform.enabled || output->current_scale != vp->buffer.scale)
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200340 filter = PIXMAN_FILTER_BILINEAR;
Alexander Larsson1f206b42013-05-22 14:41:36 +0200341 else
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200342 filter = PIXMAN_FILTER_NEAREST;
Alexander Larsson1f206b42013-05-22 14:41:36 +0200343
Neil Robertse5051712013-11-13 15:44:06 +0000344 if (ps->buffer_ref.buffer)
345 wl_shm_buffer_begin_access(ps->buffer_ref.buffer->shm_buffer);
346
Manuel Bachmannb1fff412014-04-05 05:31:37 +0200347 if (ev->alpha < 1.0) {
Manuel Bachmann9c4ab662014-04-07 11:58:45 +0200348 mask.alpha = 0xffff * ev->alpha;
Manuel Bachmannb1fff412014-04-05 05:31:37 +0200349 mask_image = pixman_image_create_solid_fill(&mask);
Manuel Bachmann9c4ab662014-04-07 11:58:45 +0200350 } else {
Manuel Bachmannb1fff412014-04-05 05:31:37 +0200351 mask_image = NULL;
Manuel Bachmann9c4ab662014-04-07 11:58:45 +0200352 }
Manuel Bachmannb1fff412014-04-05 05:31:37 +0200353
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200354 if (source_clip)
355 composite_clipped(ps->image, mask_image, po->shadow_image,
356 &transform, filter, source_clip);
357 else
358 composite_whole(pixman_op, ps->image, mask_image,
359 po->shadow_image, &transform, filter);
Alexander Larsson1f206b42013-05-22 14:41:36 +0200360
Manuel Bachmann9c4ab662014-04-07 11:58:45 +0200361 if (mask_image)
362 pixman_image_unref(mask_image);
363
Neil Robertse5051712013-11-13 15:44:06 +0000364 if (ps->buffer_ref.buffer)
365 wl_shm_buffer_end_access(ps->buffer_ref.buffer->shm_buffer);
366
Alexander Larsson1f206b42013-05-22 14:41:36 +0200367 if (pr->repaint_debug)
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200368 pixman_image_composite32(PIXMAN_OP_OVER,
Alexander Larsson1f206b42013-05-22 14:41:36 +0200369 pr->debug_color, /* src */
370 NULL /* mask */,
371 po->shadow_image, /* dest */
372 0, 0, /* src_x, src_y */
373 0, 0, /* mask_x, mask_y */
374 0, 0, /* dest_x, dest_y */
375 pixman_image_get_width (po->shadow_image), /* width */
376 pixman_image_get_height (po->shadow_image) /* height */);
377
378 pixman_image_set_clip_region32 (po->shadow_image, NULL);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300379}
380
381static void
Pekka Paalanenccf99ce2015-03-05 12:57:35 +0200382draw_view_translated(struct weston_view *view, struct weston_output *output,
383 pixman_region32_t *repaint_global)
384{
385 struct weston_surface *surface = view->surface;
386 /* non-opaque region in surface coordinates: */
387 pixman_region32_t surface_blend;
388 /* region to be painted in output coordinates: */
389 pixman_region32_t repaint_output;
390
391 pixman_region32_init(&repaint_output);
392
393 /* Blended region is whole surface minus opaque region,
394 * unless surface alpha forces us to blend all.
395 */
396 pixman_region32_init_rect(&surface_blend, 0, 0,
397 surface->width, surface->height);
398
399 if (!(view->alpha < 1.0)) {
400 pixman_region32_subtract(&surface_blend, &surface_blend,
401 &surface->opaque);
402
403 if (pixman_region32_not_empty(&surface->opaque)) {
404 region_intersect_only_translation(&repaint_output,
405 repaint_global,
406 &surface->opaque,
407 view);
408 region_global_to_output(output, &repaint_output);
409
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200410 repaint_region(view, output, &repaint_output, NULL,
Pekka Paalanenccf99ce2015-03-05 12:57:35 +0200411 PIXMAN_OP_SRC);
412 }
413 }
414
415 if (pixman_region32_not_empty(&surface_blend)) {
416 region_intersect_only_translation(&repaint_output,
417 repaint_global,
418 &surface_blend, view);
419 region_global_to_output(output, &repaint_output);
420
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200421 repaint_region(view, output, &repaint_output, NULL,
Pekka Paalanenccf99ce2015-03-05 12:57:35 +0200422 PIXMAN_OP_OVER);
423 }
424
425 pixman_region32_fini(&surface_blend);
426 pixman_region32_fini(&repaint_output);
427}
428
429static void
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200430draw_view_source_clipped(struct weston_view *view,
431 struct weston_output *output,
432 pixman_region32_t *repaint_global)
433{
434 struct weston_surface *surface = view->surface;
435 pixman_region32_t surf_region;
436 pixman_region32_t buffer_region;
437 pixman_region32_t repaint_output;
438
439 /* Do not bother separating the opaque region from non-opaque.
440 * Source clipping requires PIXMAN_OP_OVER in all cases, so painting
441 * opaque separately has no benefit.
442 */
443
444 pixman_region32_init_rect(&surf_region, 0, 0,
445 surface->width, surface->height);
Pekka Paalanenc93782a2015-03-06 10:33:50 +0200446 if (view->geometry.scissor_enabled)
447 pixman_region32_intersect(&surf_region, &surf_region,
448 &view->geometry.scissor);
449
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200450 pixman_region32_init(&buffer_region);
451 weston_surface_to_buffer_region(surface, &surf_region, &buffer_region);
452
453 pixman_region32_init(&repaint_output);
454 pixman_region32_copy(&repaint_output, repaint_global);
455 region_global_to_output(output, &repaint_output);
456
457 repaint_region(view, output, &repaint_output, &buffer_region,
458 PIXMAN_OP_OVER);
459
460 pixman_region32_fini(&repaint_output);
461 pixman_region32_fini(&buffer_region);
462 pixman_region32_fini(&surf_region);
463}
464
465static void
Jason Ekstranda7af7042013-10-12 22:38:11 -0500466draw_view(struct weston_view *ev, struct weston_output *output,
467 pixman_region32_t *damage) /* in global coordinates */
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300468{
Derek Foreman66951b72014-09-01 10:33:28 -0500469 static int zoom_logged = 0;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500470 struct pixman_surface_state *ps = get_surface_state(ev->surface);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300471 /* repaint bounding region in global coordinates: */
472 pixman_region32_t repaint;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300473
474 /* No buffer attached */
475 if (!ps->image)
476 return;
477
478 pixman_region32_init(&repaint);
479 pixman_region32_intersect(&repaint,
Pekka Paalanen25c0ca52015-02-19 11:15:33 +0200480 &ev->transform.boundingbox, damage);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500481 pixman_region32_subtract(&repaint, &repaint, &ev->clip);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300482
483 if (!pixman_region32_not_empty(&repaint))
484 goto out;
485
Derek Foreman66951b72014-09-01 10:33:28 -0500486 if (output->zoom.active && !zoom_logged) {
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300487 weston_log("pixman renderer does not support zoom\n");
Derek Foreman66951b72014-09-01 10:33:28 -0500488 zoom_logged = 1;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300489 }
490
Pekka Paalanenccf99ce2015-03-05 12:57:35 +0200491 if (view_transformation_is_translation(ev)) {
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200492 /* The simple case: The surface regions opaque, non-opaque,
493 * etc. are convertible to global coordinate space.
494 * There is no need to use a source clip region.
495 * It is possible to paint opaque region as PIXMAN_OP_SRC.
Pekka Paalanenc93782a2015-03-06 10:33:50 +0200496 * Also the boundingbox is accurate rather than an
497 * approximation.
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200498 */
Pekka Paalanenccf99ce2015-03-05 12:57:35 +0200499 draw_view_translated(ev, output, &repaint);
500 } else {
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200501 /* The complex case: the view transformation does not allow
502 * converting opaque etc. regions into global coordinate space.
503 * Therefore we need source clipping to avoid sampling from
504 * unwanted source image areas, unless the source image is
505 * to be used whole. Source clipping does not work with
506 * PIXMAN_OP_SRC.
507 */
508 draw_view_source_clipped(ev, output, &repaint);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300509 }
510
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300511out:
512 pixman_region32_fini(&repaint);
513}
514static void
515repaint_surfaces(struct weston_output *output, pixman_region32_t *damage)
516{
517 struct weston_compositor *compositor = output->compositor;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500518 struct weston_view *view;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300519
Jason Ekstranda7af7042013-10-12 22:38:11 -0500520 wl_list_for_each_reverse(view, &compositor->view_list, link)
521 if (view->plane == &compositor->primary_plane)
522 draw_view(view, output, damage);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300523}
524
525static void
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200526copy_to_hw_buffer(struct weston_output *output, pixman_region32_t *region)
527{
528 struct pixman_output_state *po = get_output_state(output);
Alexander Larsson1f206b42013-05-22 14:41:36 +0200529 pixman_region32_t output_region;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200530
Alexander Larsson1f206b42013-05-22 14:41:36 +0200531 pixman_region32_init(&output_region);
532 pixman_region32_copy(&output_region, region);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200533
Alexander Larsson1f206b42013-05-22 14:41:36 +0200534 region_global_to_output(output, &output_region);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200535
Alexander Larsson1f206b42013-05-22 14:41:36 +0200536 pixman_image_set_clip_region32 (po->hw_buffer, &output_region);
Ryo Munakata389d2052014-09-04 01:56:53 +0900537 pixman_region32_fini(&output_region);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200538
Alexander Larsson1f206b42013-05-22 14:41:36 +0200539 pixman_image_composite32(PIXMAN_OP_SRC,
540 po->shadow_image, /* src */
541 NULL /* mask */,
542 po->hw_buffer, /* dest */
543 0, 0, /* src_x, src_y */
544 0, 0, /* mask_x, mask_y */
545 0, 0, /* dest_x, dest_y */
546 pixman_image_get_width (po->hw_buffer), /* width */
547 pixman_image_get_height (po->hw_buffer) /* height */);
548
549 pixman_image_set_clip_region32 (po->hw_buffer, NULL);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200550}
551
552static void
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300553pixman_renderer_repaint_output(struct weston_output *output,
554 pixman_region32_t *output_damage)
555{
556 struct pixman_output_state *po = get_output_state(output);
557
558 if (!po->hw_buffer)
559 return;
560
561 repaint_surfaces(output, output_damage);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200562 copy_to_hw_buffer(output, output_damage);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300563
564 pixman_region32_copy(&output->previous_damage, output_damage);
565 wl_signal_emit(&output->frame_signal, output);
566
567 /* Actual flip should be done by caller */
568}
569
570static void
571pixman_renderer_flush_damage(struct weston_surface *surface)
572{
573 /* No-op for pixman renderer */
574}
575
576static void
Lubomir Rintelddc2b1e2013-12-12 12:57:56 +0100577buffer_state_handle_buffer_destroy(struct wl_listener *listener, void *data)
578{
579 struct pixman_surface_state *ps;
580
581 ps = container_of(listener, struct pixman_surface_state,
582 buffer_destroy_listener);
583
584 if (ps->image) {
585 pixman_image_unref(ps->image);
586 ps->image = NULL;
587 }
588
589 ps->buffer_destroy_listener.notify = NULL;
590}
591
592static void
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500593pixman_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300594{
595 struct pixman_surface_state *ps = get_surface_state(es);
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500596 struct wl_shm_buffer *shm_buffer;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300597 pixman_format_code_t pixman_format;
598
599 weston_buffer_reference(&ps->buffer_ref, buffer);
600
Lubomir Rintelddc2b1e2013-12-12 12:57:56 +0100601 if (ps->buffer_destroy_listener.notify) {
602 wl_list_remove(&ps->buffer_destroy_listener.link);
603 ps->buffer_destroy_listener.notify = NULL;
604 }
605
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300606 if (ps->image) {
607 pixman_image_unref(ps->image);
608 ps->image = NULL;
609 }
610
611 if (!buffer)
612 return;
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500613
614 shm_buffer = wl_shm_buffer_get(buffer->resource);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300615
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500616 if (! shm_buffer) {
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300617 weston_log("Pixman renderer supports only SHM buffers\n");
618 weston_buffer_reference(&ps->buffer_ref, NULL);
619 return;
620 }
621
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500622 switch (wl_shm_buffer_get_format(shm_buffer)) {
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300623 case WL_SHM_FORMAT_XRGB8888:
624 pixman_format = PIXMAN_x8r8g8b8;
625 break;
626 case WL_SHM_FORMAT_ARGB8888:
627 pixman_format = PIXMAN_a8r8g8b8;
628 break;
Tomeu Vizoso1c1fc292013-08-06 20:05:56 +0200629 case WL_SHM_FORMAT_RGB565:
630 pixman_format = PIXMAN_r5g6b5;
631 break;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300632 default:
633 weston_log("Unsupported SHM buffer format\n");
634 weston_buffer_reference(&ps->buffer_ref, NULL);
635 return;
636 break;
637 }
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500638
639 buffer->shm_buffer = shm_buffer;
640 buffer->width = wl_shm_buffer_get_width(shm_buffer);
641 buffer->height = wl_shm_buffer_get_height(shm_buffer);
642
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300643 ps->image = pixman_image_create_bits(pixman_format,
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500644 buffer->width, buffer->height,
645 wl_shm_buffer_get_data(shm_buffer),
646 wl_shm_buffer_get_stride(shm_buffer));
Lubomir Rintelddc2b1e2013-12-12 12:57:56 +0100647
648 ps->buffer_destroy_listener.notify =
649 buffer_state_handle_buffer_destroy;
650 wl_signal_add(&buffer->destroy_signal,
651 &ps->buffer_destroy_listener);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300652}
653
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300654static void
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300655pixman_renderer_surface_state_destroy(struct pixman_surface_state *ps)
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300656{
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300657 wl_list_remove(&ps->surface_destroy_listener.link);
658 wl_list_remove(&ps->renderer_destroy_listener.link);
Lubomir Rintelddc2b1e2013-12-12 12:57:56 +0100659 if (ps->buffer_destroy_listener.notify) {
660 wl_list_remove(&ps->buffer_destroy_listener.link);
661 ps->buffer_destroy_listener.notify = NULL;
662 }
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300663
664 ps->surface->renderer_state = NULL;
665
666 if (ps->image) {
667 pixman_image_unref(ps->image);
668 ps->image = NULL;
669 }
670 weston_buffer_reference(&ps->buffer_ref, NULL);
671 free(ps);
672}
673
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300674static void
675surface_state_handle_surface_destroy(struct wl_listener *listener, void *data)
676{
677 struct pixman_surface_state *ps;
678
679 ps = container_of(listener, struct pixman_surface_state,
680 surface_destroy_listener);
681
682 pixman_renderer_surface_state_destroy(ps);
683}
684
685static void
686surface_state_handle_renderer_destroy(struct wl_listener *listener, void *data)
687{
688 struct pixman_surface_state *ps;
689
690 ps = container_of(listener, struct pixman_surface_state,
691 renderer_destroy_listener);
692
693 pixman_renderer_surface_state_destroy(ps);
694}
695
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300696static int
697pixman_renderer_create_surface(struct weston_surface *surface)
698{
699 struct pixman_surface_state *ps;
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300700 struct pixman_renderer *pr = get_renderer(surface->compositor);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300701
Bryce Harringtonde16d892014-11-20 22:21:57 -0800702 ps = zalloc(sizeof *ps);
703 if (ps == NULL)
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300704 return -1;
705
706 surface->renderer_state = ps;
707
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300708 ps->surface = surface;
709
710 ps->surface_destroy_listener.notify =
711 surface_state_handle_surface_destroy;
712 wl_signal_add(&surface->destroy_signal,
713 &ps->surface_destroy_listener);
714
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300715 ps->renderer_destroy_listener.notify =
716 surface_state_handle_renderer_destroy;
717 wl_signal_add(&pr->destroy_signal,
718 &ps->renderer_destroy_listener);
719
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300720 return 0;
721}
722
723static void
724pixman_renderer_surface_set_color(struct weston_surface *es,
725 float red, float green, float blue, float alpha)
726{
727 struct pixman_surface_state *ps = get_surface_state(es);
728 pixman_color_t color;
729
730 color.red = red * 0xffff;
731 color.green = green * 0xffff;
732 color.blue = blue * 0xffff;
733 color.alpha = alpha * 0xffff;
734
735 if (ps->image) {
736 pixman_image_unref(ps->image);
737 ps->image = NULL;
738 }
739
740 ps->image = pixman_image_create_solid_fill(&color);
741}
742
743static void
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300744pixman_renderer_destroy(struct weston_compositor *ec)
745{
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +0300746 struct pixman_renderer *pr = get_renderer(ec);
747
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300748 wl_signal_emit(&pr->destroy_signal, pr);
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +0300749 weston_binding_destroy(pr->debug_binding);
750 free(pr);
751
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300752 ec->renderer = NULL;
753}
754
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200755static void
Pekka Paalanen6764bbe2015-02-11 12:29:56 +0200756pixman_renderer_surface_get_content_size(struct weston_surface *surface,
757 int *width, int *height)
758{
759 struct pixman_surface_state *ps = get_surface_state(surface);
760
761 if (ps->image) {
762 *width = pixman_image_get_width(ps->image);
763 *height = pixman_image_get_height(ps->image);
764 } else {
765 *width = 0;
766 *height = 0;
767 }
768}
769
770static int
771pixman_renderer_surface_copy_content(struct weston_surface *surface,
772 void *target, size_t size,
773 int src_x, int src_y,
774 int width, int height)
775{
776 const pixman_format_code_t format = PIXMAN_a8b8g8r8;
777 const size_t bytespp = 4; /* PIXMAN_a8b8g8r8 */
778 struct pixman_surface_state *ps = get_surface_state(surface);
779 pixman_image_t *out_buf;
780
781 if (!ps->image)
782 return -1;
783
784 out_buf = pixman_image_create_bits(format, width, height,
785 target, width * bytespp);
786
787 pixman_image_set_transform(ps->image, NULL);
788 pixman_image_composite32(PIXMAN_OP_SRC,
789 ps->image, /* src */
790 NULL, /* mask */
791 out_buf, /* dest */
792 src_x, src_y, /* src_x, src_y */
793 0, 0, /* mask_x, mask_y */
794 0, 0, /* dest_x, dest_y */
795 width, height);
796
797 pixman_image_unref(out_buf);
798
799 return 0;
800}
801
802static void
Kristian Høgsberge3148752013-05-06 23:19:49 -0400803debug_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200804 void *data)
805{
806 struct weston_compositor *ec = data;
807 struct pixman_renderer *pr = (struct pixman_renderer *) ec->renderer;
808
809 pr->repaint_debug ^= 1;
810
811 if (pr->repaint_debug) {
812 pixman_color_t red = {
813 0x3fff, 0x0000, 0x0000, 0x3fff
814 };
815
816 pr->debug_color = pixman_image_create_solid_fill(&red);
817 } else {
818 pixman_image_unref(pr->debug_color);
819 weston_compositor_damage_all(ec);
820 }
821}
822
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300823WL_EXPORT int
824pixman_renderer_init(struct weston_compositor *ec)
825{
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200826 struct pixman_renderer *renderer;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300827
Bryce Harringtonde16d892014-11-20 22:21:57 -0800828 renderer = zalloc(sizeof *renderer);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300829 if (renderer == NULL)
830 return -1;
831
Philipp Brüschweilerf3e39f92013-03-08 20:35:39 +0100832 renderer->repaint_debug = 0;
833 renderer->debug_color = NULL;
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200834 renderer->base.read_pixels = pixman_renderer_read_pixels;
835 renderer->base.repaint_output = pixman_renderer_repaint_output;
836 renderer->base.flush_damage = pixman_renderer_flush_damage;
837 renderer->base.attach = pixman_renderer_attach;
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200838 renderer->base.surface_set_color = pixman_renderer_surface_set_color;
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200839 renderer->base.destroy = pixman_renderer_destroy;
Pekka Paalanen6764bbe2015-02-11 12:29:56 +0200840 renderer->base.surface_get_content_size =
841 pixman_renderer_surface_get_content_size;
842 renderer->base.surface_copy_content =
843 pixman_renderer_surface_copy_content;
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200844 ec->renderer = &renderer->base;
Pekka Paalanen7bb65102013-05-22 18:03:04 +0300845 ec->capabilities |= WESTON_CAP_ROTATION_ANY;
Pekka Paalanen4fc5dd02013-05-22 18:03:05 +0300846 ec->capabilities |= WESTON_CAP_CAPTURE_YFLIP;
Pekka Paalanenc93782a2015-03-06 10:33:50 +0200847 ec->capabilities |= WESTON_CAP_VIEW_CLIP_MASK;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300848
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +0300849 renderer->debug_binding =
850 weston_compositor_add_debug_binding(ec, KEY_R,
851 debug_binding, ec);
Tomeu Vizoso1c1fc292013-08-06 20:05:56 +0200852
853 wl_display_add_shm_format(ec->wl_display, WL_SHM_FORMAT_RGB565);
854
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300855 wl_signal_init(&renderer->destroy_signal);
856
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300857 return 0;
858}
859
860WL_EXPORT void
861pixman_renderer_output_set_buffer(struct weston_output *output, pixman_image_t *buffer)
862{
863 struct pixman_output_state *po = get_output_state(output);
864
865 if (po->hw_buffer)
866 pixman_image_unref(po->hw_buffer);
867 po->hw_buffer = buffer;
868
869 if (po->hw_buffer) {
870 output->compositor->read_format = pixman_image_get_format(po->hw_buffer);
871 pixman_image_ref(po->hw_buffer);
872 }
873}
874
875WL_EXPORT int
876pixman_renderer_output_create(struct weston_output *output)
877{
Bryce Harringtonde16d892014-11-20 22:21:57 -0800878 struct pixman_output_state *po;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200879 int w, h;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300880
Bryce Harringtonde16d892014-11-20 22:21:57 -0800881 po = zalloc(sizeof *po);
882 if (po == NULL)
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300883 return -1;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200884
885 /* set shadow image transformation */
Hardeningff39efa2013-09-18 23:56:35 +0200886 w = output->current_mode->width;
887 h = output->current_mode->height;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200888
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200889 po->shadow_buffer = malloc(w * h * 4);
890
891 if (!po->shadow_buffer) {
892 free(po);
893 return -1;
894 }
895
896 po->shadow_image =
897 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
898 po->shadow_buffer, w * 4);
899
900 if (!po->shadow_image) {
901 free(po->shadow_buffer);
902 free(po);
903 return -1;
904 }
905
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300906 output->renderer_state = po;
907
908 return 0;
909}
910
911WL_EXPORT void
912pixman_renderer_output_destroy(struct weston_output *output)
913{
914 struct pixman_output_state *po = get_output_state(output);
915
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200916 pixman_image_unref(po->shadow_image);
Ander Conselvan de Oliveira23e72b82013-01-25 15:13:06 +0200917
918 if (po->hw_buffer)
919 pixman_image_unref(po->hw_buffer);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200920
Arnaud Vrac8e3fe082014-08-25 20:56:52 +0200921 free(po->shadow_buffer);
922
923 po->shadow_buffer = NULL;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200924 po->shadow_image = NULL;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300925 po->hw_buffer = NULL;
926
927 free(po);
928}