blob: 23315b12f5b337b7a53f3fe69513aa551d1468ff [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 *
Bryce Harringtona0bbfea2015-06-11 15:35:43 -07006 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sublicense, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030013 *
Bryce Harringtona0bbfea2015-06-11 15:35:43 -070014 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial
16 * portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
22 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
23 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 * SOFTWARE.
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030026 */
27
Daniel Stonec228e232013-05-22 18:03:19 +030028#include "config.h"
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030029
30#include <errno.h>
31#include <stdlib.h>
Pekka Paalanenf75b6bb2015-03-04 16:12:04 +020032#include <assert.h>
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030033
34#include "pixman-renderer.h"
35
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +020036#include <linux/input.h>
37
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030038struct pixman_output_state {
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +020039 void *shadow_buffer;
40 pixman_image_t *shadow_image;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030041 pixman_image_t *hw_buffer;
42};
43
44struct pixman_surface_state {
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +030045 struct weston_surface *surface;
46
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030047 pixman_image_t *image;
48 struct weston_buffer_reference buffer_ref;
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +030049
Lubomir Rintelddc2b1e2013-12-12 12:57:56 +010050 struct wl_listener buffer_destroy_listener;
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +030051 struct wl_listener surface_destroy_listener;
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +030052 struct wl_listener renderer_destroy_listener;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030053};
54
55struct pixman_renderer {
56 struct weston_renderer base;
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +030057
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +020058 int repaint_debug;
59 pixman_image_t *debug_color;
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +030060 struct weston_binding *debug_binding;
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +030061
62 struct wl_signal destroy_signal;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030063};
64
65static inline struct pixman_output_state *
66get_output_state(struct weston_output *output)
67{
68 return (struct pixman_output_state *)output->renderer_state;
69}
70
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +030071static int
72pixman_renderer_create_surface(struct weston_surface *surface);
73
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030074static inline struct pixman_surface_state *
75get_surface_state(struct weston_surface *surface)
76{
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +030077 if (!surface->renderer_state)
78 pixman_renderer_create_surface(surface);
79
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030080 return (struct pixman_surface_state *)surface->renderer_state;
81}
82
83static inline struct pixman_renderer *
84get_renderer(struct weston_compositor *ec)
85{
86 return (struct pixman_renderer *)ec->renderer;
87}
88
89static int
90pixman_renderer_read_pixels(struct weston_output *output,
91 pixman_format_code_t format, void *pixels,
92 uint32_t x, uint32_t y,
93 uint32_t width, uint32_t height)
94{
95 struct pixman_output_state *po = get_output_state(output);
Alexander Larsson97af7922013-05-29 12:01:33 +020096 pixman_transform_t transform;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030097 pixman_image_t *out_buf;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030098
99 if (!po->hw_buffer) {
100 errno = ENODEV;
101 return -1;
102 }
103
104 out_buf = pixman_image_create_bits(format,
105 width,
106 height,
107 pixels,
108 (PIXMAN_FORMAT_BPP(format) / 8) * width);
109
Alexander Larsson97af7922013-05-29 12:01:33 +0200110 /* Caller expects vflipped source image */
111 pixman_transform_init_translate(&transform,
112 pixman_int_to_fixed (x),
113 pixman_int_to_fixed (y - pixman_image_get_height (po->hw_buffer)));
114 pixman_transform_scale(&transform, NULL,
115 pixman_fixed_1,
116 pixman_fixed_minus_1);
117 pixman_image_set_transform(po->hw_buffer, &transform);
118
119 pixman_image_composite32(PIXMAN_OP_SRC,
120 po->hw_buffer, /* src */
121 NULL /* mask */,
122 out_buf, /* dest */
123 0, 0, /* src_x, src_y */
124 0, 0, /* mask_x, mask_y */
125 0, 0, /* dest_x, dest_y */
126 pixman_image_get_width (po->hw_buffer), /* width */
127 pixman_image_get_height (po->hw_buffer) /* height */);
128 pixman_image_set_transform(po->hw_buffer, NULL);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300129
130 pixman_image_unref(out_buf);
131
132 return 0;
133}
134
Vasily Khoruzhick031fc872013-01-29 14:58:14 +0300135static void
Alexander Larsson1f206b42013-05-22 14:41:36 +0200136region_global_to_output(struct weston_output *output, pixman_region32_t *region)
137{
138 pixman_region32_translate(region, -output->x, -output->y);
Jason Ekstrand33ff6362013-10-27 22:25:01 -0500139 weston_transformed_region(output->width, output->height,
140 output->transform, output->current_scale,
141 region, region);
Vasily Khoruzhick031fc872013-01-29 14:58:14 +0300142}
143
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300144#define D2F(v) pixman_double_to_fixed((double)v)
145
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300146static void
Jason Ekstrand8870a232014-05-20 15:53:19 -0500147weston_matrix_to_pixman_transform(pixman_transform_t *pt,
148 const struct weston_matrix *wm)
Pekka Paalanen0b4c5352014-03-14 14:38:17 +0200149{
Jason Ekstrand8870a232014-05-20 15:53:19 -0500150 /* Pixman supports only 2D transform matrix, but Weston uses 3D, *
151 * so we're omitting Z coordinate here. */
152 pt->matrix[0][0] = pixman_double_to_fixed(wm->d[0]);
153 pt->matrix[0][1] = pixman_double_to_fixed(wm->d[4]);
154 pt->matrix[0][2] = pixman_double_to_fixed(wm->d[12]);
155 pt->matrix[1][0] = pixman_double_to_fixed(wm->d[1]);
156 pt->matrix[1][1] = pixman_double_to_fixed(wm->d[5]);
157 pt->matrix[1][2] = pixman_double_to_fixed(wm->d[13]);
158 pt->matrix[2][0] = pixman_double_to_fixed(wm->d[3]);
159 pt->matrix[2][1] = pixman_double_to_fixed(wm->d[7]);
160 pt->matrix[2][2] = pixman_double_to_fixed(wm->d[15]);
Pekka Paalanen0b4c5352014-03-14 14:38:17 +0200161}
162
163static void
Pekka Paalanen6ea523b2015-03-04 14:18:39 +0200164pixman_renderer_compute_transform(pixman_transform_t *transform_out,
165 struct weston_view *ev,
166 struct weston_output *output)
167{
168 struct weston_matrix matrix;
169
170 /* Set up the source transformation based on the surface
171 position, the output position/transform/scale and the client
172 specified buffer transform/scale */
Derek Foremana5855ad2015-03-24 11:36:16 -0500173 matrix = output->inverse_matrix;
Pekka Paalanen6ea523b2015-03-04 14:18:39 +0200174
175 if (ev->transform.enabled) {
176 weston_matrix_multiply(&matrix, &ev->transform.inverse);
177 } else {
178 weston_matrix_translate(&matrix,
179 -ev->geometry.x, -ev->geometry.y, 0);
180 }
181
182 weston_matrix_multiply(&matrix, &ev->surface->surface_to_buffer_matrix);
183
184 weston_matrix_to_pixman_transform(transform_out, &matrix);
185}
186
Pekka Paalanen23d4af52015-03-04 16:18:26 +0200187static bool
188view_transformation_is_translation(struct weston_view *view)
189{
190 if (!view->transform.enabled)
191 return true;
192
193 if (view->transform.matrix.type <= WESTON_MATRIX_TRANSFORM_TRANSLATE)
194 return true;
195
196 return false;
197}
198
Pekka Paalanen6ea523b2015-03-04 14:18:39 +0200199static void
Pekka Paalanenf75b6bb2015-03-04 16:12:04 +0200200region_intersect_only_translation(pixman_region32_t *result_global,
201 pixman_region32_t *global,
202 pixman_region32_t *surf,
203 struct weston_view *view)
204{
205 float view_x, view_y;
206
207 assert(view_transformation_is_translation(view));
208
209 /* Convert from surface to global coordinates */
210 pixman_region32_copy(result_global, surf);
211 weston_view_to_global_float(view, 0, 0, &view_x, &view_y);
212 pixman_region32_translate(result_global, (int)view_x, (int)view_y);
213
214 pixman_region32_intersect(result_global, result_global, global);
215}
216
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200217static void
218composite_whole(pixman_op_t op,
219 pixman_image_t *src,
220 pixman_image_t *mask,
221 pixman_image_t *dest,
222 const pixman_transform_t *transform,
223 pixman_filter_t filter)
224{
225 int32_t dest_width;
226 int32_t dest_height;
227
228 dest_width = pixman_image_get_width(dest);
229 dest_height = pixman_image_get_height(dest);
230
231 pixman_image_set_transform(src, transform);
232 pixman_image_set_filter(src, filter, NULL, 0);
233
234 pixman_image_composite32(op, src, mask, dest,
235 0, 0, /* src_x, src_y */
236 0, 0, /* mask_x, mask_y */
237 0, 0, /* dest_x, dest_y */
238 dest_width, dest_height);
239}
240
241static void
242composite_clipped(pixman_image_t *src,
243 pixman_image_t *mask,
244 pixman_image_t *dest,
245 const pixman_transform_t *transform,
246 pixman_filter_t filter,
247 pixman_region32_t *src_clip)
248{
249 int n_box;
250 pixman_box32_t *boxes;
251 int32_t dest_width;
252 int32_t dest_height;
253 int src_stride;
254 int bitspp;
255 pixman_format_code_t src_format;
256 void *src_data;
257 int i;
258
259 /* Hardcoded to use PIXMAN_OP_OVER, because sampling outside of
260 * a Pixman image produces (0,0,0,0) instead of discarding the
261 * fragment.
262 */
263
264 dest_width = pixman_image_get_width(dest);
265 dest_height = pixman_image_get_height(dest);
266 src_format = pixman_image_get_format(src);
267 src_stride = pixman_image_get_stride(src);
268 bitspp = PIXMAN_FORMAT_BPP(src_format);
269 src_data = pixman_image_get_data(src);
270
271 assert(src_format);
272
273 /* This would be massive overdraw, except when n_box is 1. */
274 boxes = pixman_region32_rectangles(src_clip, &n_box);
275 for (i = 0; i < n_box; i++) {
276 uint8_t *ptr = src_data;
277 pixman_image_t *boximg;
278 pixman_transform_t adj = *transform;
279
280 ptr += boxes[i].y1 * src_stride;
281 ptr += boxes[i].x1 * bitspp / 8;
282 boximg = pixman_image_create_bits_no_clear(src_format,
283 boxes[i].x2 - boxes[i].x1,
284 boxes[i].y2 - boxes[i].y1,
285 (uint32_t *)ptr, src_stride);
286
287 pixman_transform_translate(&adj, NULL,
288 pixman_int_to_fixed(-boxes[i].x1),
289 pixman_int_to_fixed(-boxes[i].y1));
290 pixman_image_set_transform(boximg, &adj);
291
292 pixman_image_set_filter(boximg, filter, NULL, 0);
293 pixman_image_composite32(PIXMAN_OP_OVER, boximg, mask, dest,
294 0, 0, /* src_x, src_y */
295 0, 0, /* mask_x, mask_y */
296 0, 0, /* dest_x, dest_y */
297 dest_width, dest_height);
298
299 pixman_image_unref(boximg);
300 }
301
302 if (n_box > 1) {
303 static bool warned = false;
304
305 if (!warned)
306 weston_log("Pixman-renderer warning: %dx overdraw\n",
307 n_box);
308 warned = true;
309 }
310}
311
Pekka Paalanen11af0d92015-03-05 11:56:29 +0200312/** Paint an intersected region
313 *
314 * \param ev The view to be painted.
315 * \param output The output being painted.
316 * \param repaint_output The region to be painted in output coordinates.
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200317 * \param source_clip The region of the source image to use, in source image
318 * coordinates. If NULL, use the whole source image.
Pekka Paalanen11af0d92015-03-05 11:56:29 +0200319 * \param pixman_op Compositing operator, either SRC or OVER.
320 */
Pekka Paalanenf75b6bb2015-03-04 16:12:04 +0200321static void
Jason Ekstranda7af7042013-10-12 22:38:11 -0500322repaint_region(struct weston_view *ev, struct weston_output *output,
Pekka Paalanen11af0d92015-03-05 11:56:29 +0200323 pixman_region32_t *repaint_output,
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200324 pixman_region32_t *source_clip,
Alexander Larsson1f206b42013-05-22 14:41:36 +0200325 pixman_op_t pixman_op)
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300326{
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200327 struct pixman_renderer *pr =
328 (struct pixman_renderer *) output->compositor->renderer;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500329 struct pixman_surface_state *ps = get_surface_state(ev->surface);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300330 struct pixman_output_state *po = get_output_state(output);
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200331 struct weston_buffer_viewport *vp = &ev->surface->buffer_viewport;
Alexander Larsson1f206b42013-05-22 14:41:36 +0200332 pixman_transform_t transform;
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200333 pixman_filter_t filter;
Manuel Bachmann9c4ab662014-04-07 11:58:45 +0200334 pixman_image_t *mask_image;
335 pixman_color_t mask = { 0, };
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300336
Pekka Paalanen11af0d92015-03-05 11:56:29 +0200337 /* Clip rendering to the damaged output region */
338 pixman_image_set_clip_region32(po->shadow_image, repaint_output);
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200339
Pekka Paalanen6ea523b2015-03-04 14:18:39 +0200340 pixman_renderer_compute_transform(&transform, ev, output);
Alexander Larsson1f206b42013-05-22 14:41:36 +0200341
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200342 if (ev->transform.enabled || output->current_scale != vp->buffer.scale)
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200343 filter = PIXMAN_FILTER_BILINEAR;
Alexander Larsson1f206b42013-05-22 14:41:36 +0200344 else
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200345 filter = PIXMAN_FILTER_NEAREST;
Alexander Larsson1f206b42013-05-22 14:41:36 +0200346
Neil Robertse5051712013-11-13 15:44:06 +0000347 if (ps->buffer_ref.buffer)
348 wl_shm_buffer_begin_access(ps->buffer_ref.buffer->shm_buffer);
349
Manuel Bachmannb1fff412014-04-05 05:31:37 +0200350 if (ev->alpha < 1.0) {
Manuel Bachmann9c4ab662014-04-07 11:58:45 +0200351 mask.alpha = 0xffff * ev->alpha;
Manuel Bachmannb1fff412014-04-05 05:31:37 +0200352 mask_image = pixman_image_create_solid_fill(&mask);
Manuel Bachmann9c4ab662014-04-07 11:58:45 +0200353 } else {
Manuel Bachmannb1fff412014-04-05 05:31:37 +0200354 mask_image = NULL;
Manuel Bachmann9c4ab662014-04-07 11:58:45 +0200355 }
Manuel Bachmannb1fff412014-04-05 05:31:37 +0200356
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200357 if (source_clip)
358 composite_clipped(ps->image, mask_image, po->shadow_image,
359 &transform, filter, source_clip);
360 else
361 composite_whole(pixman_op, ps->image, mask_image,
362 po->shadow_image, &transform, filter);
Alexander Larsson1f206b42013-05-22 14:41:36 +0200363
Manuel Bachmann9c4ab662014-04-07 11:58:45 +0200364 if (mask_image)
365 pixman_image_unref(mask_image);
366
Neil Robertse5051712013-11-13 15:44:06 +0000367 if (ps->buffer_ref.buffer)
368 wl_shm_buffer_end_access(ps->buffer_ref.buffer->shm_buffer);
369
Alexander Larsson1f206b42013-05-22 14:41:36 +0200370 if (pr->repaint_debug)
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200371 pixman_image_composite32(PIXMAN_OP_OVER,
Alexander Larsson1f206b42013-05-22 14:41:36 +0200372 pr->debug_color, /* src */
373 NULL /* mask */,
374 po->shadow_image, /* dest */
375 0, 0, /* src_x, src_y */
376 0, 0, /* mask_x, mask_y */
377 0, 0, /* dest_x, dest_y */
378 pixman_image_get_width (po->shadow_image), /* width */
379 pixman_image_get_height (po->shadow_image) /* height */);
380
381 pixman_image_set_clip_region32 (po->shadow_image, NULL);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300382}
383
384static void
Pekka Paalanenccf99ce2015-03-05 12:57:35 +0200385draw_view_translated(struct weston_view *view, struct weston_output *output,
386 pixman_region32_t *repaint_global)
387{
388 struct weston_surface *surface = view->surface;
389 /* non-opaque region in surface coordinates: */
390 pixman_region32_t surface_blend;
391 /* region to be painted in output coordinates: */
392 pixman_region32_t repaint_output;
393
394 pixman_region32_init(&repaint_output);
395
396 /* Blended region is whole surface minus opaque region,
397 * unless surface alpha forces us to blend all.
398 */
399 pixman_region32_init_rect(&surface_blend, 0, 0,
400 surface->width, surface->height);
401
402 if (!(view->alpha < 1.0)) {
403 pixman_region32_subtract(&surface_blend, &surface_blend,
404 &surface->opaque);
405
406 if (pixman_region32_not_empty(&surface->opaque)) {
407 region_intersect_only_translation(&repaint_output,
408 repaint_global,
409 &surface->opaque,
410 view);
411 region_global_to_output(output, &repaint_output);
412
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200413 repaint_region(view, output, &repaint_output, NULL,
Pekka Paalanenccf99ce2015-03-05 12:57:35 +0200414 PIXMAN_OP_SRC);
415 }
416 }
417
418 if (pixman_region32_not_empty(&surface_blend)) {
419 region_intersect_only_translation(&repaint_output,
420 repaint_global,
421 &surface_blend, view);
422 region_global_to_output(output, &repaint_output);
423
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200424 repaint_region(view, output, &repaint_output, NULL,
Pekka Paalanenccf99ce2015-03-05 12:57:35 +0200425 PIXMAN_OP_OVER);
426 }
427
428 pixman_region32_fini(&surface_blend);
429 pixman_region32_fini(&repaint_output);
430}
431
432static void
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200433draw_view_source_clipped(struct weston_view *view,
434 struct weston_output *output,
435 pixman_region32_t *repaint_global)
436{
437 struct weston_surface *surface = view->surface;
438 pixman_region32_t surf_region;
439 pixman_region32_t buffer_region;
440 pixman_region32_t repaint_output;
441
442 /* Do not bother separating the opaque region from non-opaque.
443 * Source clipping requires PIXMAN_OP_OVER in all cases, so painting
444 * opaque separately has no benefit.
445 */
446
447 pixman_region32_init_rect(&surf_region, 0, 0,
448 surface->width, surface->height);
Pekka Paalanenc93782a2015-03-06 10:33:50 +0200449 if (view->geometry.scissor_enabled)
450 pixman_region32_intersect(&surf_region, &surf_region,
451 &view->geometry.scissor);
452
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200453 pixman_region32_init(&buffer_region);
454 weston_surface_to_buffer_region(surface, &surf_region, &buffer_region);
455
456 pixman_region32_init(&repaint_output);
457 pixman_region32_copy(&repaint_output, repaint_global);
458 region_global_to_output(output, &repaint_output);
459
460 repaint_region(view, output, &repaint_output, &buffer_region,
461 PIXMAN_OP_OVER);
462
463 pixman_region32_fini(&repaint_output);
464 pixman_region32_fini(&buffer_region);
465 pixman_region32_fini(&surf_region);
466}
467
468static void
Jason Ekstranda7af7042013-10-12 22:38:11 -0500469draw_view(struct weston_view *ev, struct weston_output *output,
470 pixman_region32_t *damage) /* in global coordinates */
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300471{
Derek Foreman66951b72014-09-01 10:33:28 -0500472 static int zoom_logged = 0;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500473 struct pixman_surface_state *ps = get_surface_state(ev->surface);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300474 /* repaint bounding region in global coordinates: */
475 pixman_region32_t repaint;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300476
477 /* No buffer attached */
478 if (!ps->image)
479 return;
480
481 pixman_region32_init(&repaint);
482 pixman_region32_intersect(&repaint,
Pekka Paalanen25c0ca52015-02-19 11:15:33 +0200483 &ev->transform.boundingbox, damage);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500484 pixman_region32_subtract(&repaint, &repaint, &ev->clip);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300485
486 if (!pixman_region32_not_empty(&repaint))
487 goto out;
488
Derek Foreman66951b72014-09-01 10:33:28 -0500489 if (output->zoom.active && !zoom_logged) {
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300490 weston_log("pixman renderer does not support zoom\n");
Derek Foreman66951b72014-09-01 10:33:28 -0500491 zoom_logged = 1;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300492 }
493
Pekka Paalanenccf99ce2015-03-05 12:57:35 +0200494 if (view_transformation_is_translation(ev)) {
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200495 /* The simple case: The surface regions opaque, non-opaque,
496 * etc. are convertible to global coordinate space.
497 * There is no need to use a source clip region.
498 * It is possible to paint opaque region as PIXMAN_OP_SRC.
Pekka Paalanenc93782a2015-03-06 10:33:50 +0200499 * Also the boundingbox is accurate rather than an
500 * approximation.
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200501 */
Pekka Paalanenccf99ce2015-03-05 12:57:35 +0200502 draw_view_translated(ev, output, &repaint);
503 } else {
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200504 /* The complex case: the view transformation does not allow
505 * converting opaque etc. regions into global coordinate space.
506 * Therefore we need source clipping to avoid sampling from
507 * unwanted source image areas, unless the source image is
508 * to be used whole. Source clipping does not work with
509 * PIXMAN_OP_SRC.
510 */
511 draw_view_source_clipped(ev, output, &repaint);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300512 }
513
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300514out:
515 pixman_region32_fini(&repaint);
516}
517static void
518repaint_surfaces(struct weston_output *output, pixman_region32_t *damage)
519{
520 struct weston_compositor *compositor = output->compositor;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500521 struct weston_view *view;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300522
Jason Ekstranda7af7042013-10-12 22:38:11 -0500523 wl_list_for_each_reverse(view, &compositor->view_list, link)
524 if (view->plane == &compositor->primary_plane)
525 draw_view(view, output, damage);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300526}
527
528static void
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200529copy_to_hw_buffer(struct weston_output *output, pixman_region32_t *region)
530{
531 struct pixman_output_state *po = get_output_state(output);
Alexander Larsson1f206b42013-05-22 14:41:36 +0200532 pixman_region32_t output_region;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200533
Alexander Larsson1f206b42013-05-22 14:41:36 +0200534 pixman_region32_init(&output_region);
535 pixman_region32_copy(&output_region, region);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200536
Alexander Larsson1f206b42013-05-22 14:41:36 +0200537 region_global_to_output(output, &output_region);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200538
Alexander Larsson1f206b42013-05-22 14:41:36 +0200539 pixman_image_set_clip_region32 (po->hw_buffer, &output_region);
Ryo Munakata389d2052014-09-04 01:56:53 +0900540 pixman_region32_fini(&output_region);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200541
Alexander Larsson1f206b42013-05-22 14:41:36 +0200542 pixman_image_composite32(PIXMAN_OP_SRC,
543 po->shadow_image, /* src */
544 NULL /* mask */,
545 po->hw_buffer, /* dest */
546 0, 0, /* src_x, src_y */
547 0, 0, /* mask_x, mask_y */
548 0, 0, /* dest_x, dest_y */
549 pixman_image_get_width (po->hw_buffer), /* width */
550 pixman_image_get_height (po->hw_buffer) /* height */);
551
552 pixman_image_set_clip_region32 (po->hw_buffer, NULL);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200553}
554
555static void
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300556pixman_renderer_repaint_output(struct weston_output *output,
557 pixman_region32_t *output_damage)
558{
559 struct pixman_output_state *po = get_output_state(output);
560
561 if (!po->hw_buffer)
562 return;
563
564 repaint_surfaces(output, output_damage);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200565 copy_to_hw_buffer(output, output_damage);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300566
567 pixman_region32_copy(&output->previous_damage, output_damage);
568 wl_signal_emit(&output->frame_signal, output);
569
570 /* Actual flip should be done by caller */
571}
572
573static void
574pixman_renderer_flush_damage(struct weston_surface *surface)
575{
576 /* No-op for pixman renderer */
577}
578
579static void
Lubomir Rintelddc2b1e2013-12-12 12:57:56 +0100580buffer_state_handle_buffer_destroy(struct wl_listener *listener, void *data)
581{
582 struct pixman_surface_state *ps;
583
584 ps = container_of(listener, struct pixman_surface_state,
585 buffer_destroy_listener);
586
587 if (ps->image) {
588 pixman_image_unref(ps->image);
589 ps->image = NULL;
590 }
591
592 ps->buffer_destroy_listener.notify = NULL;
593}
594
595static void
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500596pixman_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300597{
598 struct pixman_surface_state *ps = get_surface_state(es);
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500599 struct wl_shm_buffer *shm_buffer;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300600 pixman_format_code_t pixman_format;
601
602 weston_buffer_reference(&ps->buffer_ref, buffer);
603
Lubomir Rintelddc2b1e2013-12-12 12:57:56 +0100604 if (ps->buffer_destroy_listener.notify) {
605 wl_list_remove(&ps->buffer_destroy_listener.link);
606 ps->buffer_destroy_listener.notify = NULL;
607 }
608
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300609 if (ps->image) {
610 pixman_image_unref(ps->image);
611 ps->image = NULL;
612 }
613
614 if (!buffer)
615 return;
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500616
617 shm_buffer = wl_shm_buffer_get(buffer->resource);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300618
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500619 if (! shm_buffer) {
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300620 weston_log("Pixman renderer supports only SHM buffers\n");
621 weston_buffer_reference(&ps->buffer_ref, NULL);
622 return;
623 }
624
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500625 switch (wl_shm_buffer_get_format(shm_buffer)) {
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300626 case WL_SHM_FORMAT_XRGB8888:
627 pixman_format = PIXMAN_x8r8g8b8;
628 break;
629 case WL_SHM_FORMAT_ARGB8888:
630 pixman_format = PIXMAN_a8r8g8b8;
631 break;
Tomeu Vizoso1c1fc292013-08-06 20:05:56 +0200632 case WL_SHM_FORMAT_RGB565:
633 pixman_format = PIXMAN_r5g6b5;
634 break;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300635 default:
636 weston_log("Unsupported SHM buffer format\n");
637 weston_buffer_reference(&ps->buffer_ref, NULL);
638 return;
639 break;
640 }
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500641
642 buffer->shm_buffer = shm_buffer;
643 buffer->width = wl_shm_buffer_get_width(shm_buffer);
644 buffer->height = wl_shm_buffer_get_height(shm_buffer);
645
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300646 ps->image = pixman_image_create_bits(pixman_format,
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500647 buffer->width, buffer->height,
648 wl_shm_buffer_get_data(shm_buffer),
649 wl_shm_buffer_get_stride(shm_buffer));
Lubomir Rintelddc2b1e2013-12-12 12:57:56 +0100650
651 ps->buffer_destroy_listener.notify =
652 buffer_state_handle_buffer_destroy;
653 wl_signal_add(&buffer->destroy_signal,
654 &ps->buffer_destroy_listener);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300655}
656
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300657static void
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300658pixman_renderer_surface_state_destroy(struct pixman_surface_state *ps)
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300659{
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300660 wl_list_remove(&ps->surface_destroy_listener.link);
661 wl_list_remove(&ps->renderer_destroy_listener.link);
Lubomir Rintelddc2b1e2013-12-12 12:57:56 +0100662 if (ps->buffer_destroy_listener.notify) {
663 wl_list_remove(&ps->buffer_destroy_listener.link);
664 ps->buffer_destroy_listener.notify = NULL;
665 }
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300666
667 ps->surface->renderer_state = NULL;
668
669 if (ps->image) {
670 pixman_image_unref(ps->image);
671 ps->image = NULL;
672 }
673 weston_buffer_reference(&ps->buffer_ref, NULL);
674 free(ps);
675}
676
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300677static void
678surface_state_handle_surface_destroy(struct wl_listener *listener, void *data)
679{
680 struct pixman_surface_state *ps;
681
682 ps = container_of(listener, struct pixman_surface_state,
683 surface_destroy_listener);
684
685 pixman_renderer_surface_state_destroy(ps);
686}
687
688static void
689surface_state_handle_renderer_destroy(struct wl_listener *listener, void *data)
690{
691 struct pixman_surface_state *ps;
692
693 ps = container_of(listener, struct pixman_surface_state,
694 renderer_destroy_listener);
695
696 pixman_renderer_surface_state_destroy(ps);
697}
698
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300699static int
700pixman_renderer_create_surface(struct weston_surface *surface)
701{
702 struct pixman_surface_state *ps;
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300703 struct pixman_renderer *pr = get_renderer(surface->compositor);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300704
Bryce Harringtonde16d892014-11-20 22:21:57 -0800705 ps = zalloc(sizeof *ps);
706 if (ps == NULL)
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300707 return -1;
708
709 surface->renderer_state = ps;
710
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300711 ps->surface = surface;
712
713 ps->surface_destroy_listener.notify =
714 surface_state_handle_surface_destroy;
715 wl_signal_add(&surface->destroy_signal,
716 &ps->surface_destroy_listener);
717
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300718 ps->renderer_destroy_listener.notify =
719 surface_state_handle_renderer_destroy;
720 wl_signal_add(&pr->destroy_signal,
721 &ps->renderer_destroy_listener);
722
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300723 return 0;
724}
725
726static void
727pixman_renderer_surface_set_color(struct weston_surface *es,
728 float red, float green, float blue, float alpha)
729{
730 struct pixman_surface_state *ps = get_surface_state(es);
731 pixman_color_t color;
732
733 color.red = red * 0xffff;
734 color.green = green * 0xffff;
735 color.blue = blue * 0xffff;
736 color.alpha = alpha * 0xffff;
737
738 if (ps->image) {
739 pixman_image_unref(ps->image);
740 ps->image = NULL;
741 }
742
743 ps->image = pixman_image_create_solid_fill(&color);
744}
745
746static void
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300747pixman_renderer_destroy(struct weston_compositor *ec)
748{
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +0300749 struct pixman_renderer *pr = get_renderer(ec);
750
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300751 wl_signal_emit(&pr->destroy_signal, pr);
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +0300752 weston_binding_destroy(pr->debug_binding);
753 free(pr);
754
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300755 ec->renderer = NULL;
756}
757
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200758static void
Pekka Paalanen6764bbe2015-02-11 12:29:56 +0200759pixman_renderer_surface_get_content_size(struct weston_surface *surface,
760 int *width, int *height)
761{
762 struct pixman_surface_state *ps = get_surface_state(surface);
763
764 if (ps->image) {
765 *width = pixman_image_get_width(ps->image);
766 *height = pixman_image_get_height(ps->image);
767 } else {
768 *width = 0;
769 *height = 0;
770 }
771}
772
773static int
774pixman_renderer_surface_copy_content(struct weston_surface *surface,
775 void *target, size_t size,
776 int src_x, int src_y,
777 int width, int height)
778{
779 const pixman_format_code_t format = PIXMAN_a8b8g8r8;
780 const size_t bytespp = 4; /* PIXMAN_a8b8g8r8 */
781 struct pixman_surface_state *ps = get_surface_state(surface);
782 pixman_image_t *out_buf;
783
784 if (!ps->image)
785 return -1;
786
787 out_buf = pixman_image_create_bits(format, width, height,
788 target, width * bytespp);
789
790 pixman_image_set_transform(ps->image, NULL);
791 pixman_image_composite32(PIXMAN_OP_SRC,
792 ps->image, /* src */
793 NULL, /* mask */
794 out_buf, /* dest */
795 src_x, src_y, /* src_x, src_y */
796 0, 0, /* mask_x, mask_y */
797 0, 0, /* dest_x, dest_y */
798 width, height);
799
800 pixman_image_unref(out_buf);
801
802 return 0;
803}
804
805static void
Kristian Høgsberge3148752013-05-06 23:19:49 -0400806debug_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200807 void *data)
808{
809 struct weston_compositor *ec = data;
810 struct pixman_renderer *pr = (struct pixman_renderer *) ec->renderer;
811
812 pr->repaint_debug ^= 1;
813
814 if (pr->repaint_debug) {
815 pixman_color_t red = {
816 0x3fff, 0x0000, 0x0000, 0x3fff
817 };
818
819 pr->debug_color = pixman_image_create_solid_fill(&red);
820 } else {
821 pixman_image_unref(pr->debug_color);
822 weston_compositor_damage_all(ec);
823 }
824}
825
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300826WL_EXPORT int
827pixman_renderer_init(struct weston_compositor *ec)
828{
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200829 struct pixman_renderer *renderer;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300830
Bryce Harringtonde16d892014-11-20 22:21:57 -0800831 renderer = zalloc(sizeof *renderer);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300832 if (renderer == NULL)
833 return -1;
834
Philipp Brüschweilerf3e39f92013-03-08 20:35:39 +0100835 renderer->repaint_debug = 0;
836 renderer->debug_color = NULL;
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200837 renderer->base.read_pixels = pixman_renderer_read_pixels;
838 renderer->base.repaint_output = pixman_renderer_repaint_output;
839 renderer->base.flush_damage = pixman_renderer_flush_damage;
840 renderer->base.attach = pixman_renderer_attach;
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200841 renderer->base.surface_set_color = pixman_renderer_surface_set_color;
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200842 renderer->base.destroy = pixman_renderer_destroy;
Pekka Paalanen6764bbe2015-02-11 12:29:56 +0200843 renderer->base.surface_get_content_size =
844 pixman_renderer_surface_get_content_size;
845 renderer->base.surface_copy_content =
846 pixman_renderer_surface_copy_content;
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200847 ec->renderer = &renderer->base;
Pekka Paalanen7bb65102013-05-22 18:03:04 +0300848 ec->capabilities |= WESTON_CAP_ROTATION_ANY;
Pekka Paalanen4fc5dd02013-05-22 18:03:05 +0300849 ec->capabilities |= WESTON_CAP_CAPTURE_YFLIP;
Pekka Paalanenc93782a2015-03-06 10:33:50 +0200850 ec->capabilities |= WESTON_CAP_VIEW_CLIP_MASK;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300851
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +0300852 renderer->debug_binding =
853 weston_compositor_add_debug_binding(ec, KEY_R,
854 debug_binding, ec);
Tomeu Vizoso1c1fc292013-08-06 20:05:56 +0200855
856 wl_display_add_shm_format(ec->wl_display, WL_SHM_FORMAT_RGB565);
857
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300858 wl_signal_init(&renderer->destroy_signal);
859
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300860 return 0;
861}
862
863WL_EXPORT void
864pixman_renderer_output_set_buffer(struct weston_output *output, pixman_image_t *buffer)
865{
866 struct pixman_output_state *po = get_output_state(output);
867
868 if (po->hw_buffer)
869 pixman_image_unref(po->hw_buffer);
870 po->hw_buffer = buffer;
871
872 if (po->hw_buffer) {
873 output->compositor->read_format = pixman_image_get_format(po->hw_buffer);
874 pixman_image_ref(po->hw_buffer);
875 }
876}
877
878WL_EXPORT int
879pixman_renderer_output_create(struct weston_output *output)
880{
Bryce Harringtonde16d892014-11-20 22:21:57 -0800881 struct pixman_output_state *po;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200882 int w, h;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300883
Bryce Harringtonde16d892014-11-20 22:21:57 -0800884 po = zalloc(sizeof *po);
885 if (po == NULL)
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300886 return -1;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200887
888 /* set shadow image transformation */
Hardeningff39efa2013-09-18 23:56:35 +0200889 w = output->current_mode->width;
890 h = output->current_mode->height;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200891
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200892 po->shadow_buffer = malloc(w * h * 4);
893
894 if (!po->shadow_buffer) {
895 free(po);
896 return -1;
897 }
898
899 po->shadow_image =
900 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
901 po->shadow_buffer, w * 4);
902
903 if (!po->shadow_image) {
904 free(po->shadow_buffer);
905 free(po);
906 return -1;
907 }
908
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300909 output->renderer_state = po;
910
911 return 0;
912}
913
914WL_EXPORT void
915pixman_renderer_output_destroy(struct weston_output *output)
916{
917 struct pixman_output_state *po = get_output_state(output);
918
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200919 pixman_image_unref(po->shadow_image);
Ander Conselvan de Oliveira23e72b82013-01-25 15:13:06 +0200920
921 if (po->hw_buffer)
922 pixman_image_unref(po->hw_buffer);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200923
Arnaud Vrac8e3fe082014-08-25 20:56:52 +0200924 free(po->shadow_buffer);
925
926 po->shadow_buffer = NULL;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200927 po->shadow_image = NULL;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300928 po->hw_buffer = NULL;
929
930 free(po);
931}