blob: be3b3e5825c84c4aa6367376b57767f7e5156eed [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 */
170 weston_matrix_invert(&matrix, &output->matrix);
171
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);
446 pixman_region32_init(&buffer_region);
447 weston_surface_to_buffer_region(surface, &surf_region, &buffer_region);
448
449 pixman_region32_init(&repaint_output);
450 pixman_region32_copy(&repaint_output, repaint_global);
451 region_global_to_output(output, &repaint_output);
452
453 repaint_region(view, output, &repaint_output, &buffer_region,
454 PIXMAN_OP_OVER);
455
456 pixman_region32_fini(&repaint_output);
457 pixman_region32_fini(&buffer_region);
458 pixman_region32_fini(&surf_region);
459}
460
461static void
Jason Ekstranda7af7042013-10-12 22:38:11 -0500462draw_view(struct weston_view *ev, struct weston_output *output,
463 pixman_region32_t *damage) /* in global coordinates */
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300464{
Derek Foreman66951b72014-09-01 10:33:28 -0500465 static int zoom_logged = 0;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500466 struct pixman_surface_state *ps = get_surface_state(ev->surface);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300467 /* repaint bounding region in global coordinates: */
468 pixman_region32_t repaint;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300469
470 /* No buffer attached */
471 if (!ps->image)
472 return;
473
474 pixman_region32_init(&repaint);
475 pixman_region32_intersect(&repaint,
Pekka Paalanen25c0ca52015-02-19 11:15:33 +0200476 &ev->transform.boundingbox, damage);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500477 pixman_region32_subtract(&repaint, &repaint, &ev->clip);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300478
479 if (!pixman_region32_not_empty(&repaint))
480 goto out;
481
Derek Foreman66951b72014-09-01 10:33:28 -0500482 if (output->zoom.active && !zoom_logged) {
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300483 weston_log("pixman renderer does not support zoom\n");
Derek Foreman66951b72014-09-01 10:33:28 -0500484 zoom_logged = 1;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300485 }
486
Pekka Paalanenccf99ce2015-03-05 12:57:35 +0200487 if (view_transformation_is_translation(ev)) {
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200488 /* The simple case: The surface regions opaque, non-opaque,
489 * etc. are convertible to global coordinate space.
490 * There is no need to use a source clip region.
491 * It is possible to paint opaque region as PIXMAN_OP_SRC.
492 */
Pekka Paalanenccf99ce2015-03-05 12:57:35 +0200493 draw_view_translated(ev, output, &repaint);
494 } else {
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200495 /* The complex case: the view transformation does not allow
496 * converting opaque etc. regions into global coordinate space.
497 * Therefore we need source clipping to avoid sampling from
498 * unwanted source image areas, unless the source image is
499 * to be used whole. Source clipping does not work with
500 * PIXMAN_OP_SRC.
501 */
502 draw_view_source_clipped(ev, output, &repaint);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300503 }
504
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300505out:
506 pixman_region32_fini(&repaint);
507}
508static void
509repaint_surfaces(struct weston_output *output, pixman_region32_t *damage)
510{
511 struct weston_compositor *compositor = output->compositor;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500512 struct weston_view *view;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300513
Jason Ekstranda7af7042013-10-12 22:38:11 -0500514 wl_list_for_each_reverse(view, &compositor->view_list, link)
515 if (view->plane == &compositor->primary_plane)
516 draw_view(view, output, damage);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300517}
518
519static void
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200520copy_to_hw_buffer(struct weston_output *output, pixman_region32_t *region)
521{
522 struct pixman_output_state *po = get_output_state(output);
Alexander Larsson1f206b42013-05-22 14:41:36 +0200523 pixman_region32_t output_region;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200524
Alexander Larsson1f206b42013-05-22 14:41:36 +0200525 pixman_region32_init(&output_region);
526 pixman_region32_copy(&output_region, region);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200527
Alexander Larsson1f206b42013-05-22 14:41:36 +0200528 region_global_to_output(output, &output_region);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200529
Alexander Larsson1f206b42013-05-22 14:41:36 +0200530 pixman_image_set_clip_region32 (po->hw_buffer, &output_region);
Ryo Munakata389d2052014-09-04 01:56:53 +0900531 pixman_region32_fini(&output_region);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200532
Alexander Larsson1f206b42013-05-22 14:41:36 +0200533 pixman_image_composite32(PIXMAN_OP_SRC,
534 po->shadow_image, /* src */
535 NULL /* mask */,
536 po->hw_buffer, /* dest */
537 0, 0, /* src_x, src_y */
538 0, 0, /* mask_x, mask_y */
539 0, 0, /* dest_x, dest_y */
540 pixman_image_get_width (po->hw_buffer), /* width */
541 pixman_image_get_height (po->hw_buffer) /* height */);
542
543 pixman_image_set_clip_region32 (po->hw_buffer, NULL);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200544}
545
546static void
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300547pixman_renderer_repaint_output(struct weston_output *output,
548 pixman_region32_t *output_damage)
549{
550 struct pixman_output_state *po = get_output_state(output);
551
552 if (!po->hw_buffer)
553 return;
554
555 repaint_surfaces(output, output_damage);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200556 copy_to_hw_buffer(output, output_damage);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300557
558 pixman_region32_copy(&output->previous_damage, output_damage);
559 wl_signal_emit(&output->frame_signal, output);
560
561 /* Actual flip should be done by caller */
562}
563
564static void
565pixman_renderer_flush_damage(struct weston_surface *surface)
566{
567 /* No-op for pixman renderer */
568}
569
570static void
Lubomir Rintelddc2b1e2013-12-12 12:57:56 +0100571buffer_state_handle_buffer_destroy(struct wl_listener *listener, void *data)
572{
573 struct pixman_surface_state *ps;
574
575 ps = container_of(listener, struct pixman_surface_state,
576 buffer_destroy_listener);
577
578 if (ps->image) {
579 pixman_image_unref(ps->image);
580 ps->image = NULL;
581 }
582
583 ps->buffer_destroy_listener.notify = NULL;
584}
585
586static void
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500587pixman_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300588{
589 struct pixman_surface_state *ps = get_surface_state(es);
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500590 struct wl_shm_buffer *shm_buffer;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300591 pixman_format_code_t pixman_format;
592
593 weston_buffer_reference(&ps->buffer_ref, buffer);
594
Lubomir Rintelddc2b1e2013-12-12 12:57:56 +0100595 if (ps->buffer_destroy_listener.notify) {
596 wl_list_remove(&ps->buffer_destroy_listener.link);
597 ps->buffer_destroy_listener.notify = NULL;
598 }
599
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300600 if (ps->image) {
601 pixman_image_unref(ps->image);
602 ps->image = NULL;
603 }
604
605 if (!buffer)
606 return;
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500607
608 shm_buffer = wl_shm_buffer_get(buffer->resource);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300609
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500610 if (! shm_buffer) {
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300611 weston_log("Pixman renderer supports only SHM buffers\n");
612 weston_buffer_reference(&ps->buffer_ref, NULL);
613 return;
614 }
615
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500616 switch (wl_shm_buffer_get_format(shm_buffer)) {
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300617 case WL_SHM_FORMAT_XRGB8888:
618 pixman_format = PIXMAN_x8r8g8b8;
619 break;
620 case WL_SHM_FORMAT_ARGB8888:
621 pixman_format = PIXMAN_a8r8g8b8;
622 break;
Tomeu Vizoso1c1fc292013-08-06 20:05:56 +0200623 case WL_SHM_FORMAT_RGB565:
624 pixman_format = PIXMAN_r5g6b5;
625 break;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300626 default:
627 weston_log("Unsupported SHM buffer format\n");
628 weston_buffer_reference(&ps->buffer_ref, NULL);
629 return;
630 break;
631 }
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500632
633 buffer->shm_buffer = shm_buffer;
634 buffer->width = wl_shm_buffer_get_width(shm_buffer);
635 buffer->height = wl_shm_buffer_get_height(shm_buffer);
636
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300637 ps->image = pixman_image_create_bits(pixman_format,
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500638 buffer->width, buffer->height,
639 wl_shm_buffer_get_data(shm_buffer),
640 wl_shm_buffer_get_stride(shm_buffer));
Lubomir Rintelddc2b1e2013-12-12 12:57:56 +0100641
642 ps->buffer_destroy_listener.notify =
643 buffer_state_handle_buffer_destroy;
644 wl_signal_add(&buffer->destroy_signal,
645 &ps->buffer_destroy_listener);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300646}
647
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300648static void
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300649pixman_renderer_surface_state_destroy(struct pixman_surface_state *ps)
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300650{
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300651 wl_list_remove(&ps->surface_destroy_listener.link);
652 wl_list_remove(&ps->renderer_destroy_listener.link);
Lubomir Rintelddc2b1e2013-12-12 12:57:56 +0100653 if (ps->buffer_destroy_listener.notify) {
654 wl_list_remove(&ps->buffer_destroy_listener.link);
655 ps->buffer_destroy_listener.notify = NULL;
656 }
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300657
658 ps->surface->renderer_state = NULL;
659
660 if (ps->image) {
661 pixman_image_unref(ps->image);
662 ps->image = NULL;
663 }
664 weston_buffer_reference(&ps->buffer_ref, NULL);
665 free(ps);
666}
667
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300668static void
669surface_state_handle_surface_destroy(struct wl_listener *listener, void *data)
670{
671 struct pixman_surface_state *ps;
672
673 ps = container_of(listener, struct pixman_surface_state,
674 surface_destroy_listener);
675
676 pixman_renderer_surface_state_destroy(ps);
677}
678
679static void
680surface_state_handle_renderer_destroy(struct wl_listener *listener, void *data)
681{
682 struct pixman_surface_state *ps;
683
684 ps = container_of(listener, struct pixman_surface_state,
685 renderer_destroy_listener);
686
687 pixman_renderer_surface_state_destroy(ps);
688}
689
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300690static int
691pixman_renderer_create_surface(struct weston_surface *surface)
692{
693 struct pixman_surface_state *ps;
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300694 struct pixman_renderer *pr = get_renderer(surface->compositor);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300695
Bryce Harringtonde16d892014-11-20 22:21:57 -0800696 ps = zalloc(sizeof *ps);
697 if (ps == NULL)
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300698 return -1;
699
700 surface->renderer_state = ps;
701
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300702 ps->surface = surface;
703
704 ps->surface_destroy_listener.notify =
705 surface_state_handle_surface_destroy;
706 wl_signal_add(&surface->destroy_signal,
707 &ps->surface_destroy_listener);
708
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300709 ps->renderer_destroy_listener.notify =
710 surface_state_handle_renderer_destroy;
711 wl_signal_add(&pr->destroy_signal,
712 &ps->renderer_destroy_listener);
713
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300714 return 0;
715}
716
717static void
718pixman_renderer_surface_set_color(struct weston_surface *es,
719 float red, float green, float blue, float alpha)
720{
721 struct pixman_surface_state *ps = get_surface_state(es);
722 pixman_color_t color;
723
724 color.red = red * 0xffff;
725 color.green = green * 0xffff;
726 color.blue = blue * 0xffff;
727 color.alpha = alpha * 0xffff;
728
729 if (ps->image) {
730 pixman_image_unref(ps->image);
731 ps->image = NULL;
732 }
733
734 ps->image = pixman_image_create_solid_fill(&color);
735}
736
737static void
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300738pixman_renderer_destroy(struct weston_compositor *ec)
739{
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +0300740 struct pixman_renderer *pr = get_renderer(ec);
741
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300742 wl_signal_emit(&pr->destroy_signal, pr);
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +0300743 weston_binding_destroy(pr->debug_binding);
744 free(pr);
745
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300746 ec->renderer = NULL;
747}
748
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200749static void
Pekka Paalanen6764bbe2015-02-11 12:29:56 +0200750pixman_renderer_surface_get_content_size(struct weston_surface *surface,
751 int *width, int *height)
752{
753 struct pixman_surface_state *ps = get_surface_state(surface);
754
755 if (ps->image) {
756 *width = pixman_image_get_width(ps->image);
757 *height = pixman_image_get_height(ps->image);
758 } else {
759 *width = 0;
760 *height = 0;
761 }
762}
763
764static int
765pixman_renderer_surface_copy_content(struct weston_surface *surface,
766 void *target, size_t size,
767 int src_x, int src_y,
768 int width, int height)
769{
770 const pixman_format_code_t format = PIXMAN_a8b8g8r8;
771 const size_t bytespp = 4; /* PIXMAN_a8b8g8r8 */
772 struct pixman_surface_state *ps = get_surface_state(surface);
773 pixman_image_t *out_buf;
774
775 if (!ps->image)
776 return -1;
777
778 out_buf = pixman_image_create_bits(format, width, height,
779 target, width * bytespp);
780
781 pixman_image_set_transform(ps->image, NULL);
782 pixman_image_composite32(PIXMAN_OP_SRC,
783 ps->image, /* src */
784 NULL, /* mask */
785 out_buf, /* dest */
786 src_x, src_y, /* src_x, src_y */
787 0, 0, /* mask_x, mask_y */
788 0, 0, /* dest_x, dest_y */
789 width, height);
790
791 pixman_image_unref(out_buf);
792
793 return 0;
794}
795
796static void
Kristian Høgsberge3148752013-05-06 23:19:49 -0400797debug_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200798 void *data)
799{
800 struct weston_compositor *ec = data;
801 struct pixman_renderer *pr = (struct pixman_renderer *) ec->renderer;
802
803 pr->repaint_debug ^= 1;
804
805 if (pr->repaint_debug) {
806 pixman_color_t red = {
807 0x3fff, 0x0000, 0x0000, 0x3fff
808 };
809
810 pr->debug_color = pixman_image_create_solid_fill(&red);
811 } else {
812 pixman_image_unref(pr->debug_color);
813 weston_compositor_damage_all(ec);
814 }
815}
816
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300817WL_EXPORT int
818pixman_renderer_init(struct weston_compositor *ec)
819{
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200820 struct pixman_renderer *renderer;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300821
Bryce Harringtonde16d892014-11-20 22:21:57 -0800822 renderer = zalloc(sizeof *renderer);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300823 if (renderer == NULL)
824 return -1;
825
Philipp Brüschweilerf3e39f92013-03-08 20:35:39 +0100826 renderer->repaint_debug = 0;
827 renderer->debug_color = NULL;
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200828 renderer->base.read_pixels = pixman_renderer_read_pixels;
829 renderer->base.repaint_output = pixman_renderer_repaint_output;
830 renderer->base.flush_damage = pixman_renderer_flush_damage;
831 renderer->base.attach = pixman_renderer_attach;
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200832 renderer->base.surface_set_color = pixman_renderer_surface_set_color;
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200833 renderer->base.destroy = pixman_renderer_destroy;
Pekka Paalanen6764bbe2015-02-11 12:29:56 +0200834 renderer->base.surface_get_content_size =
835 pixman_renderer_surface_get_content_size;
836 renderer->base.surface_copy_content =
837 pixman_renderer_surface_copy_content;
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200838 ec->renderer = &renderer->base;
Pekka Paalanen7bb65102013-05-22 18:03:04 +0300839 ec->capabilities |= WESTON_CAP_ROTATION_ANY;
Pekka Paalanen4fc5dd02013-05-22 18:03:05 +0300840 ec->capabilities |= WESTON_CAP_CAPTURE_YFLIP;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300841
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +0300842 renderer->debug_binding =
843 weston_compositor_add_debug_binding(ec, KEY_R,
844 debug_binding, ec);
Tomeu Vizoso1c1fc292013-08-06 20:05:56 +0200845
846 wl_display_add_shm_format(ec->wl_display, WL_SHM_FORMAT_RGB565);
847
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300848 wl_signal_init(&renderer->destroy_signal);
849
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300850 return 0;
851}
852
853WL_EXPORT void
854pixman_renderer_output_set_buffer(struct weston_output *output, pixman_image_t *buffer)
855{
856 struct pixman_output_state *po = get_output_state(output);
857
858 if (po->hw_buffer)
859 pixman_image_unref(po->hw_buffer);
860 po->hw_buffer = buffer;
861
862 if (po->hw_buffer) {
863 output->compositor->read_format = pixman_image_get_format(po->hw_buffer);
864 pixman_image_ref(po->hw_buffer);
865 }
866}
867
868WL_EXPORT int
869pixman_renderer_output_create(struct weston_output *output)
870{
Bryce Harringtonde16d892014-11-20 22:21:57 -0800871 struct pixman_output_state *po;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200872 int w, h;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300873
Bryce Harringtonde16d892014-11-20 22:21:57 -0800874 po = zalloc(sizeof *po);
875 if (po == NULL)
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300876 return -1;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200877
878 /* set shadow image transformation */
Hardeningff39efa2013-09-18 23:56:35 +0200879 w = output->current_mode->width;
880 h = output->current_mode->height;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200881
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200882 po->shadow_buffer = malloc(w * h * 4);
883
884 if (!po->shadow_buffer) {
885 free(po);
886 return -1;
887 }
888
889 po->shadow_image =
890 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
891 po->shadow_buffer, w * 4);
892
893 if (!po->shadow_image) {
894 free(po->shadow_buffer);
895 free(po);
896 return -1;
897 }
898
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300899 output->renderer_state = po;
900
901 return 0;
902}
903
904WL_EXPORT void
905pixman_renderer_output_destroy(struct weston_output *output)
906{
907 struct pixman_output_state *po = get_output_state(output);
908
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200909 pixman_image_unref(po->shadow_image);
Ander Conselvan de Oliveira23e72b82013-01-25 15:13:06 +0200910
911 if (po->hw_buffer)
912 pixman_image_unref(po->hw_buffer);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200913
Arnaud Vrac8e3fe082014-08-25 20:56:52 +0200914 free(po->shadow_buffer);
915
916 po->shadow_buffer = NULL;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200917 po->shadow_image = NULL;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300918 po->hw_buffer = NULL;
919
920 free(po);
921}