blob: 4ba13778ff1987333ae4f204ab775fa367e7a718 [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>
Jussi Kukkonen649bbce2016-07-19 14:16:27 +030031#include <stdint.h>
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030032#include <stdlib.h>
Pekka Paalanenf75b6bb2015-03-04 16:12:04 +020033#include <assert.h>
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030034
35#include "pixman-renderer.h"
Jon Cruz867d50e2015-06-15 15:37:10 -070036#include "shared/helpers.h"
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030037
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +020038#include <linux/input.h>
39
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030040struct pixman_output_state {
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +020041 void *shadow_buffer;
42 pixman_image_t *shadow_image;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030043 pixman_image_t *hw_buffer;
44};
45
46struct pixman_surface_state {
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +030047 struct weston_surface *surface;
48
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030049 pixman_image_t *image;
50 struct weston_buffer_reference buffer_ref;
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +030051
Lubomir Rintelddc2b1e2013-12-12 12:57:56 +010052 struct wl_listener buffer_destroy_listener;
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +030053 struct wl_listener surface_destroy_listener;
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +030054 struct wl_listener renderer_destroy_listener;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030055};
56
57struct pixman_renderer {
58 struct weston_renderer base;
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +030059
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +020060 int repaint_debug;
61 pixman_image_t *debug_color;
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +030062 struct weston_binding *debug_binding;
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +030063
64 struct wl_signal destroy_signal;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030065};
66
67static inline struct pixman_output_state *
68get_output_state(struct weston_output *output)
69{
70 return (struct pixman_output_state *)output->renderer_state;
71}
72
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +030073static int
74pixman_renderer_create_surface(struct weston_surface *surface);
75
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030076static inline struct pixman_surface_state *
77get_surface_state(struct weston_surface *surface)
78{
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +030079 if (!surface->renderer_state)
80 pixman_renderer_create_surface(surface);
81
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030082 return (struct pixman_surface_state *)surface->renderer_state;
83}
84
85static inline struct pixman_renderer *
86get_renderer(struct weston_compositor *ec)
87{
88 return (struct pixman_renderer *)ec->renderer;
89}
90
91static int
92pixman_renderer_read_pixels(struct weston_output *output,
93 pixman_format_code_t format, void *pixels,
94 uint32_t x, uint32_t y,
95 uint32_t width, uint32_t height)
96{
97 struct pixman_output_state *po = get_output_state(output);
Alexander Larsson97af7922013-05-29 12:01:33 +020098 pixman_transform_t transform;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030099 pixman_image_t *out_buf;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300100
101 if (!po->hw_buffer) {
102 errno = ENODEV;
103 return -1;
104 }
105
106 out_buf = pixman_image_create_bits(format,
107 width,
108 height,
109 pixels,
110 (PIXMAN_FORMAT_BPP(format) / 8) * width);
111
Alexander Larsson97af7922013-05-29 12:01:33 +0200112 /* Caller expects vflipped source image */
113 pixman_transform_init_translate(&transform,
114 pixman_int_to_fixed (x),
115 pixman_int_to_fixed (y - pixman_image_get_height (po->hw_buffer)));
116 pixman_transform_scale(&transform, NULL,
117 pixman_fixed_1,
118 pixman_fixed_minus_1);
119 pixman_image_set_transform(po->hw_buffer, &transform);
120
121 pixman_image_composite32(PIXMAN_OP_SRC,
122 po->hw_buffer, /* src */
123 NULL /* mask */,
124 out_buf, /* dest */
125 0, 0, /* src_x, src_y */
126 0, 0, /* mask_x, mask_y */
127 0, 0, /* dest_x, dest_y */
128 pixman_image_get_width (po->hw_buffer), /* width */
129 pixman_image_get_height (po->hw_buffer) /* height */);
130 pixman_image_set_transform(po->hw_buffer, NULL);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300131
132 pixman_image_unref(out_buf);
133
134 return 0;
135}
136
Vasily Khoruzhick031fc872013-01-29 14:58:14 +0300137static void
Alexander Larsson1f206b42013-05-22 14:41:36 +0200138region_global_to_output(struct weston_output *output, pixman_region32_t *region)
139{
Jason Ekstrand52c476a2015-11-18 16:32:29 -0600140 if (output->zoom.active) {
141 weston_matrix_transform_region(region, &output->matrix, region);
142 } else {
143 pixman_region32_translate(region, -output->x, -output->y);
144 weston_transformed_region(output->width, output->height,
145 output->transform,
146 output->current_scale,
147 region, region);
148 }
Vasily Khoruzhick031fc872013-01-29 14:58:14 +0300149}
150
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300151#define D2F(v) pixman_double_to_fixed((double)v)
152
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300153static void
Jason Ekstrand8870a232014-05-20 15:53:19 -0500154weston_matrix_to_pixman_transform(pixman_transform_t *pt,
155 const struct weston_matrix *wm)
Pekka Paalanen0b4c5352014-03-14 14:38:17 +0200156{
Jason Ekstrand8870a232014-05-20 15:53:19 -0500157 /* Pixman supports only 2D transform matrix, but Weston uses 3D, *
158 * so we're omitting Z coordinate here. */
159 pt->matrix[0][0] = pixman_double_to_fixed(wm->d[0]);
160 pt->matrix[0][1] = pixman_double_to_fixed(wm->d[4]);
161 pt->matrix[0][2] = pixman_double_to_fixed(wm->d[12]);
162 pt->matrix[1][0] = pixman_double_to_fixed(wm->d[1]);
163 pt->matrix[1][1] = pixman_double_to_fixed(wm->d[5]);
164 pt->matrix[1][2] = pixman_double_to_fixed(wm->d[13]);
165 pt->matrix[2][0] = pixman_double_to_fixed(wm->d[3]);
166 pt->matrix[2][1] = pixman_double_to_fixed(wm->d[7]);
167 pt->matrix[2][2] = pixman_double_to_fixed(wm->d[15]);
Pekka Paalanen0b4c5352014-03-14 14:38:17 +0200168}
169
170static void
Pekka Paalanen6ea523b2015-03-04 14:18:39 +0200171pixman_renderer_compute_transform(pixman_transform_t *transform_out,
172 struct weston_view *ev,
173 struct weston_output *output)
174{
175 struct weston_matrix matrix;
176
177 /* Set up the source transformation based on the surface
178 position, the output position/transform/scale and the client
179 specified buffer transform/scale */
Derek Foremana5855ad2015-03-24 11:36:16 -0500180 matrix = output->inverse_matrix;
Pekka Paalanen6ea523b2015-03-04 14:18:39 +0200181
182 if (ev->transform.enabled) {
183 weston_matrix_multiply(&matrix, &ev->transform.inverse);
184 } else {
185 weston_matrix_translate(&matrix,
186 -ev->geometry.x, -ev->geometry.y, 0);
187 }
188
189 weston_matrix_multiply(&matrix, &ev->surface->surface_to_buffer_matrix);
190
191 weston_matrix_to_pixman_transform(transform_out, &matrix);
192}
193
Pekka Paalanen23d4af52015-03-04 16:18:26 +0200194static bool
195view_transformation_is_translation(struct weston_view *view)
196{
197 if (!view->transform.enabled)
198 return true;
199
200 if (view->transform.matrix.type <= WESTON_MATRIX_TRANSFORM_TRANSLATE)
201 return true;
202
203 return false;
204}
205
Pekka Paalanen6ea523b2015-03-04 14:18:39 +0200206static void
Pekka Paalanenf75b6bb2015-03-04 16:12:04 +0200207region_intersect_only_translation(pixman_region32_t *result_global,
208 pixman_region32_t *global,
209 pixman_region32_t *surf,
210 struct weston_view *view)
211{
212 float view_x, view_y;
213
214 assert(view_transformation_is_translation(view));
215
216 /* Convert from surface to global coordinates */
217 pixman_region32_copy(result_global, surf);
218 weston_view_to_global_float(view, 0, 0, &view_x, &view_y);
219 pixman_region32_translate(result_global, (int)view_x, (int)view_y);
220
221 pixman_region32_intersect(result_global, result_global, global);
222}
223
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200224static void
225composite_whole(pixman_op_t op,
226 pixman_image_t *src,
227 pixman_image_t *mask,
228 pixman_image_t *dest,
229 const pixman_transform_t *transform,
230 pixman_filter_t filter)
231{
232 int32_t dest_width;
233 int32_t dest_height;
234
235 dest_width = pixman_image_get_width(dest);
236 dest_height = pixman_image_get_height(dest);
237
238 pixman_image_set_transform(src, transform);
239 pixman_image_set_filter(src, filter, NULL, 0);
240
241 pixman_image_composite32(op, src, mask, dest,
242 0, 0, /* src_x, src_y */
243 0, 0, /* mask_x, mask_y */
244 0, 0, /* dest_x, dest_y */
245 dest_width, dest_height);
246}
247
248static void
249composite_clipped(pixman_image_t *src,
250 pixman_image_t *mask,
251 pixman_image_t *dest,
252 const pixman_transform_t *transform,
253 pixman_filter_t filter,
254 pixman_region32_t *src_clip)
255{
256 int n_box;
257 pixman_box32_t *boxes;
258 int32_t dest_width;
259 int32_t dest_height;
260 int src_stride;
261 int bitspp;
262 pixman_format_code_t src_format;
263 void *src_data;
264 int i;
265
266 /* Hardcoded to use PIXMAN_OP_OVER, because sampling outside of
267 * a Pixman image produces (0,0,0,0) instead of discarding the
268 * fragment.
269 */
270
271 dest_width = pixman_image_get_width(dest);
272 dest_height = pixman_image_get_height(dest);
273 src_format = pixman_image_get_format(src);
274 src_stride = pixman_image_get_stride(src);
275 bitspp = PIXMAN_FORMAT_BPP(src_format);
276 src_data = pixman_image_get_data(src);
277
278 assert(src_format);
279
280 /* This would be massive overdraw, except when n_box is 1. */
281 boxes = pixman_region32_rectangles(src_clip, &n_box);
282 for (i = 0; i < n_box; i++) {
283 uint8_t *ptr = src_data;
284 pixman_image_t *boximg;
285 pixman_transform_t adj = *transform;
286
287 ptr += boxes[i].y1 * src_stride;
288 ptr += boxes[i].x1 * bitspp / 8;
289 boximg = pixman_image_create_bits_no_clear(src_format,
290 boxes[i].x2 - boxes[i].x1,
291 boxes[i].y2 - boxes[i].y1,
292 (uint32_t *)ptr, src_stride);
293
294 pixman_transform_translate(&adj, NULL,
295 pixman_int_to_fixed(-boxes[i].x1),
296 pixman_int_to_fixed(-boxes[i].y1));
297 pixman_image_set_transform(boximg, &adj);
298
299 pixman_image_set_filter(boximg, filter, NULL, 0);
300 pixman_image_composite32(PIXMAN_OP_OVER, boximg, mask, dest,
301 0, 0, /* src_x, src_y */
302 0, 0, /* mask_x, mask_y */
303 0, 0, /* dest_x, dest_y */
304 dest_width, dest_height);
305
306 pixman_image_unref(boximg);
307 }
308
309 if (n_box > 1) {
310 static bool warned = false;
311
312 if (!warned)
313 weston_log("Pixman-renderer warning: %dx overdraw\n",
314 n_box);
315 warned = true;
316 }
317}
318
Pekka Paalanen11af0d92015-03-05 11:56:29 +0200319/** Paint an intersected region
320 *
321 * \param ev The view to be painted.
322 * \param output The output being painted.
323 * \param repaint_output The region to be painted in output coordinates.
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200324 * \param source_clip The region of the source image to use, in source image
325 * coordinates. If NULL, use the whole source image.
Pekka Paalanen11af0d92015-03-05 11:56:29 +0200326 * \param pixman_op Compositing operator, either SRC or OVER.
327 */
Pekka Paalanenf75b6bb2015-03-04 16:12:04 +0200328static void
Jason Ekstranda7af7042013-10-12 22:38:11 -0500329repaint_region(struct weston_view *ev, struct weston_output *output,
Pekka Paalanen11af0d92015-03-05 11:56:29 +0200330 pixman_region32_t *repaint_output,
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200331 pixman_region32_t *source_clip,
Alexander Larsson1f206b42013-05-22 14:41:36 +0200332 pixman_op_t pixman_op)
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300333{
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200334 struct pixman_renderer *pr =
335 (struct pixman_renderer *) output->compositor->renderer;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500336 struct pixman_surface_state *ps = get_surface_state(ev->surface);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300337 struct pixman_output_state *po = get_output_state(output);
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200338 struct weston_buffer_viewport *vp = &ev->surface->buffer_viewport;
Alexander Larsson1f206b42013-05-22 14:41:36 +0200339 pixman_transform_t transform;
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200340 pixman_filter_t filter;
Manuel Bachmann9c4ab662014-04-07 11:58:45 +0200341 pixman_image_t *mask_image;
342 pixman_color_t mask = { 0, };
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300343
Pekka Paalanen11af0d92015-03-05 11:56:29 +0200344 /* Clip rendering to the damaged output region */
345 pixman_image_set_clip_region32(po->shadow_image, repaint_output);
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200346
Pekka Paalanen6ea523b2015-03-04 14:18:39 +0200347 pixman_renderer_compute_transform(&transform, ev, output);
Alexander Larsson1f206b42013-05-22 14:41:36 +0200348
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200349 if (ev->transform.enabled || output->current_scale != vp->buffer.scale)
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200350 filter = PIXMAN_FILTER_BILINEAR;
Alexander Larsson1f206b42013-05-22 14:41:36 +0200351 else
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200352 filter = PIXMAN_FILTER_NEAREST;
Alexander Larsson1f206b42013-05-22 14:41:36 +0200353
Neil Robertse5051712013-11-13 15:44:06 +0000354 if (ps->buffer_ref.buffer)
355 wl_shm_buffer_begin_access(ps->buffer_ref.buffer->shm_buffer);
356
Manuel Bachmannb1fff412014-04-05 05:31:37 +0200357 if (ev->alpha < 1.0) {
Manuel Bachmann9c4ab662014-04-07 11:58:45 +0200358 mask.alpha = 0xffff * ev->alpha;
Manuel Bachmannb1fff412014-04-05 05:31:37 +0200359 mask_image = pixman_image_create_solid_fill(&mask);
Manuel Bachmann9c4ab662014-04-07 11:58:45 +0200360 } else {
Manuel Bachmannb1fff412014-04-05 05:31:37 +0200361 mask_image = NULL;
Manuel Bachmann9c4ab662014-04-07 11:58:45 +0200362 }
Manuel Bachmannb1fff412014-04-05 05:31:37 +0200363
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200364 if (source_clip)
365 composite_clipped(ps->image, mask_image, po->shadow_image,
366 &transform, filter, source_clip);
367 else
368 composite_whole(pixman_op, ps->image, mask_image,
369 po->shadow_image, &transform, filter);
Alexander Larsson1f206b42013-05-22 14:41:36 +0200370
Manuel Bachmann9c4ab662014-04-07 11:58:45 +0200371 if (mask_image)
372 pixman_image_unref(mask_image);
373
Neil Robertse5051712013-11-13 15:44:06 +0000374 if (ps->buffer_ref.buffer)
375 wl_shm_buffer_end_access(ps->buffer_ref.buffer->shm_buffer);
376
Alexander Larsson1f206b42013-05-22 14:41:36 +0200377 if (pr->repaint_debug)
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200378 pixman_image_composite32(PIXMAN_OP_OVER,
Alexander Larsson1f206b42013-05-22 14:41:36 +0200379 pr->debug_color, /* src */
380 NULL /* mask */,
381 po->shadow_image, /* dest */
382 0, 0, /* src_x, src_y */
383 0, 0, /* mask_x, mask_y */
384 0, 0, /* dest_x, dest_y */
385 pixman_image_get_width (po->shadow_image), /* width */
386 pixman_image_get_height (po->shadow_image) /* height */);
387
388 pixman_image_set_clip_region32 (po->shadow_image, NULL);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300389}
390
391static void
Pekka Paalanenccf99ce2015-03-05 12:57:35 +0200392draw_view_translated(struct weston_view *view, struct weston_output *output,
393 pixman_region32_t *repaint_global)
394{
395 struct weston_surface *surface = view->surface;
396 /* non-opaque region in surface coordinates: */
397 pixman_region32_t surface_blend;
398 /* region to be painted in output coordinates: */
399 pixman_region32_t repaint_output;
400
401 pixman_region32_init(&repaint_output);
402
403 /* Blended region is whole surface minus opaque region,
404 * unless surface alpha forces us to blend all.
405 */
406 pixman_region32_init_rect(&surface_blend, 0, 0,
407 surface->width, surface->height);
408
409 if (!(view->alpha < 1.0)) {
410 pixman_region32_subtract(&surface_blend, &surface_blend,
411 &surface->opaque);
412
413 if (pixman_region32_not_empty(&surface->opaque)) {
414 region_intersect_only_translation(&repaint_output,
415 repaint_global,
416 &surface->opaque,
417 view);
418 region_global_to_output(output, &repaint_output);
419
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200420 repaint_region(view, output, &repaint_output, NULL,
Pekka Paalanenccf99ce2015-03-05 12:57:35 +0200421 PIXMAN_OP_SRC);
422 }
423 }
424
425 if (pixman_region32_not_empty(&surface_blend)) {
426 region_intersect_only_translation(&repaint_output,
427 repaint_global,
428 &surface_blend, view);
429 region_global_to_output(output, &repaint_output);
430
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200431 repaint_region(view, output, &repaint_output, NULL,
Pekka Paalanenccf99ce2015-03-05 12:57:35 +0200432 PIXMAN_OP_OVER);
433 }
434
435 pixman_region32_fini(&surface_blend);
436 pixman_region32_fini(&repaint_output);
437}
438
439static void
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200440draw_view_source_clipped(struct weston_view *view,
441 struct weston_output *output,
442 pixman_region32_t *repaint_global)
443{
444 struct weston_surface *surface = view->surface;
445 pixman_region32_t surf_region;
446 pixman_region32_t buffer_region;
447 pixman_region32_t repaint_output;
448
449 /* Do not bother separating the opaque region from non-opaque.
450 * Source clipping requires PIXMAN_OP_OVER in all cases, so painting
451 * opaque separately has no benefit.
452 */
453
454 pixman_region32_init_rect(&surf_region, 0, 0,
455 surface->width, surface->height);
Pekka Paalanenc93782a2015-03-06 10:33:50 +0200456 if (view->geometry.scissor_enabled)
457 pixman_region32_intersect(&surf_region, &surf_region,
458 &view->geometry.scissor);
459
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200460 pixman_region32_init(&buffer_region);
461 weston_surface_to_buffer_region(surface, &surf_region, &buffer_region);
462
463 pixman_region32_init(&repaint_output);
464 pixman_region32_copy(&repaint_output, repaint_global);
465 region_global_to_output(output, &repaint_output);
466
467 repaint_region(view, output, &repaint_output, &buffer_region,
468 PIXMAN_OP_OVER);
469
470 pixman_region32_fini(&repaint_output);
471 pixman_region32_fini(&buffer_region);
472 pixman_region32_fini(&surf_region);
473}
474
475static void
Jason Ekstranda7af7042013-10-12 22:38:11 -0500476draw_view(struct weston_view *ev, struct weston_output *output,
477 pixman_region32_t *damage) /* in global coordinates */
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300478{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500479 struct pixman_surface_state *ps = get_surface_state(ev->surface);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300480 /* repaint bounding region in global coordinates: */
481 pixman_region32_t repaint;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300482
483 /* No buffer attached */
484 if (!ps->image)
485 return;
486
487 pixman_region32_init(&repaint);
488 pixman_region32_intersect(&repaint,
Pekka Paalanen25c0ca52015-02-19 11:15:33 +0200489 &ev->transform.boundingbox, damage);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500490 pixman_region32_subtract(&repaint, &repaint, &ev->clip);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300491
492 if (!pixman_region32_not_empty(&repaint))
493 goto out;
494
Pekka Paalanenccf99ce2015-03-05 12:57:35 +0200495 if (view_transformation_is_translation(ev)) {
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200496 /* The simple case: The surface regions opaque, non-opaque,
497 * etc. are convertible to global coordinate space.
498 * There is no need to use a source clip region.
499 * It is possible to paint opaque region as PIXMAN_OP_SRC.
Pekka Paalanenc93782a2015-03-06 10:33:50 +0200500 * Also the boundingbox is accurate rather than an
501 * approximation.
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200502 */
Pekka Paalanenccf99ce2015-03-05 12:57:35 +0200503 draw_view_translated(ev, output, &repaint);
504 } else {
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200505 /* The complex case: the view transformation does not allow
506 * converting opaque etc. regions into global coordinate space.
507 * Therefore we need source clipping to avoid sampling from
508 * unwanted source image areas, unless the source image is
509 * to be used whole. Source clipping does not work with
510 * PIXMAN_OP_SRC.
511 */
512 draw_view_source_clipped(ev, output, &repaint);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300513 }
514
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300515out:
516 pixman_region32_fini(&repaint);
517}
518static void
519repaint_surfaces(struct weston_output *output, pixman_region32_t *damage)
520{
521 struct weston_compositor *compositor = output->compositor;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500522 struct weston_view *view;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300523
Jason Ekstranda7af7042013-10-12 22:38:11 -0500524 wl_list_for_each_reverse(view, &compositor->view_list, link)
525 if (view->plane == &compositor->primary_plane)
526 draw_view(view, output, damage);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300527}
528
529static void
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200530copy_to_hw_buffer(struct weston_output *output, pixman_region32_t *region)
531{
532 struct pixman_output_state *po = get_output_state(output);
Alexander Larsson1f206b42013-05-22 14:41:36 +0200533 pixman_region32_t output_region;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200534
Alexander Larsson1f206b42013-05-22 14:41:36 +0200535 pixman_region32_init(&output_region);
536 pixman_region32_copy(&output_region, region);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200537
Alexander Larsson1f206b42013-05-22 14:41:36 +0200538 region_global_to_output(output, &output_region);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200539
Alexander Larsson1f206b42013-05-22 14:41:36 +0200540 pixman_image_set_clip_region32 (po->hw_buffer, &output_region);
Ryo Munakata389d2052014-09-04 01:56:53 +0900541 pixman_region32_fini(&output_region);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200542
Alexander Larsson1f206b42013-05-22 14:41:36 +0200543 pixman_image_composite32(PIXMAN_OP_SRC,
544 po->shadow_image, /* src */
545 NULL /* mask */,
546 po->hw_buffer, /* dest */
547 0, 0, /* src_x, src_y */
548 0, 0, /* mask_x, mask_y */
549 0, 0, /* dest_x, dest_y */
550 pixman_image_get_width (po->hw_buffer), /* width */
551 pixman_image_get_height (po->hw_buffer) /* height */);
552
553 pixman_image_set_clip_region32 (po->hw_buffer, NULL);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200554}
555
556static void
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300557pixman_renderer_repaint_output(struct weston_output *output,
558 pixman_region32_t *output_damage)
559{
560 struct pixman_output_state *po = get_output_state(output);
561
562 if (!po->hw_buffer)
563 return;
564
565 repaint_surfaces(output, output_damage);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200566 copy_to_hw_buffer(output, output_damage);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300567
568 pixman_region32_copy(&output->previous_damage, output_damage);
569 wl_signal_emit(&output->frame_signal, output);
570
571 /* Actual flip should be done by caller */
572}
573
574static void
575pixman_renderer_flush_damage(struct weston_surface *surface)
576{
577 /* No-op for pixman renderer */
578}
579
580static void
Lubomir Rintelddc2b1e2013-12-12 12:57:56 +0100581buffer_state_handle_buffer_destroy(struct wl_listener *listener, void *data)
582{
583 struct pixman_surface_state *ps;
584
585 ps = container_of(listener, struct pixman_surface_state,
586 buffer_destroy_listener);
587
588 if (ps->image) {
589 pixman_image_unref(ps->image);
590 ps->image = NULL;
591 }
592
593 ps->buffer_destroy_listener.notify = NULL;
594}
595
596static void
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500597pixman_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300598{
599 struct pixman_surface_state *ps = get_surface_state(es);
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500600 struct wl_shm_buffer *shm_buffer;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300601 pixman_format_code_t pixman_format;
602
603 weston_buffer_reference(&ps->buffer_ref, buffer);
604
Lubomir Rintelddc2b1e2013-12-12 12:57:56 +0100605 if (ps->buffer_destroy_listener.notify) {
606 wl_list_remove(&ps->buffer_destroy_listener.link);
607 ps->buffer_destroy_listener.notify = NULL;
608 }
609
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300610 if (ps->image) {
611 pixman_image_unref(ps->image);
612 ps->image = NULL;
613 }
614
615 if (!buffer)
616 return;
Jason Ekstrand52c476a2015-11-18 16:32:29 -0600617
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500618 shm_buffer = wl_shm_buffer_get(buffer->resource);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300619
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500620 if (! shm_buffer) {
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300621 weston_log("Pixman renderer supports only SHM buffers\n");
622 weston_buffer_reference(&ps->buffer_ref, NULL);
623 return;
624 }
625
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500626 switch (wl_shm_buffer_get_format(shm_buffer)) {
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300627 case WL_SHM_FORMAT_XRGB8888:
628 pixman_format = PIXMAN_x8r8g8b8;
629 break;
630 case WL_SHM_FORMAT_ARGB8888:
631 pixman_format = PIXMAN_a8r8g8b8;
632 break;
Tomeu Vizoso1c1fc292013-08-06 20:05:56 +0200633 case WL_SHM_FORMAT_RGB565:
634 pixman_format = PIXMAN_r5g6b5;
635 break;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300636 default:
637 weston_log("Unsupported SHM buffer format\n");
638 weston_buffer_reference(&ps->buffer_ref, NULL);
639 return;
640 break;
641 }
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500642
643 buffer->shm_buffer = shm_buffer;
644 buffer->width = wl_shm_buffer_get_width(shm_buffer);
645 buffer->height = wl_shm_buffer_get_height(shm_buffer);
646
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300647 ps->image = pixman_image_create_bits(pixman_format,
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500648 buffer->width, buffer->height,
649 wl_shm_buffer_get_data(shm_buffer),
650 wl_shm_buffer_get_stride(shm_buffer));
Lubomir Rintelddc2b1e2013-12-12 12:57:56 +0100651
652 ps->buffer_destroy_listener.notify =
653 buffer_state_handle_buffer_destroy;
654 wl_signal_add(&buffer->destroy_signal,
655 &ps->buffer_destroy_listener);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300656}
657
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300658static void
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300659pixman_renderer_surface_state_destroy(struct pixman_surface_state *ps)
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300660{
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300661 wl_list_remove(&ps->surface_destroy_listener.link);
662 wl_list_remove(&ps->renderer_destroy_listener.link);
Lubomir Rintelddc2b1e2013-12-12 12:57:56 +0100663 if (ps->buffer_destroy_listener.notify) {
664 wl_list_remove(&ps->buffer_destroy_listener.link);
665 ps->buffer_destroy_listener.notify = NULL;
666 }
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300667
668 ps->surface->renderer_state = NULL;
669
670 if (ps->image) {
671 pixman_image_unref(ps->image);
672 ps->image = NULL;
673 }
674 weston_buffer_reference(&ps->buffer_ref, NULL);
675 free(ps);
676}
677
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300678static void
679surface_state_handle_surface_destroy(struct wl_listener *listener, void *data)
680{
681 struct pixman_surface_state *ps;
682
683 ps = container_of(listener, struct pixman_surface_state,
684 surface_destroy_listener);
685
686 pixman_renderer_surface_state_destroy(ps);
687}
688
689static void
690surface_state_handle_renderer_destroy(struct wl_listener *listener, void *data)
691{
692 struct pixman_surface_state *ps;
693
694 ps = container_of(listener, struct pixman_surface_state,
695 renderer_destroy_listener);
696
697 pixman_renderer_surface_state_destroy(ps);
698}
699
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300700static int
701pixman_renderer_create_surface(struct weston_surface *surface)
702{
703 struct pixman_surface_state *ps;
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300704 struct pixman_renderer *pr = get_renderer(surface->compositor);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300705
Bryce Harringtonde16d892014-11-20 22:21:57 -0800706 ps = zalloc(sizeof *ps);
707 if (ps == NULL)
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300708 return -1;
709
710 surface->renderer_state = ps;
711
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300712 ps->surface = surface;
713
714 ps->surface_destroy_listener.notify =
715 surface_state_handle_surface_destroy;
716 wl_signal_add(&surface->destroy_signal,
717 &ps->surface_destroy_listener);
718
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300719 ps->renderer_destroy_listener.notify =
720 surface_state_handle_renderer_destroy;
721 wl_signal_add(&pr->destroy_signal,
722 &ps->renderer_destroy_listener);
723
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300724 return 0;
725}
726
727static void
728pixman_renderer_surface_set_color(struct weston_surface *es,
729 float red, float green, float blue, float alpha)
730{
731 struct pixman_surface_state *ps = get_surface_state(es);
732 pixman_color_t color;
733
734 color.red = red * 0xffff;
735 color.green = green * 0xffff;
736 color.blue = blue * 0xffff;
737 color.alpha = alpha * 0xffff;
Jason Ekstrand52c476a2015-11-18 16:32:29 -0600738
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300739 if (ps->image) {
740 pixman_image_unref(ps->image);
741 ps->image = NULL;
742 }
743
744 ps->image = pixman_image_create_solid_fill(&color);
745}
746
747static void
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300748pixman_renderer_destroy(struct weston_compositor *ec)
749{
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +0300750 struct pixman_renderer *pr = get_renderer(ec);
751
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300752 wl_signal_emit(&pr->destroy_signal, pr);
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +0300753 weston_binding_destroy(pr->debug_binding);
754 free(pr);
755
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300756 ec->renderer = NULL;
757}
758
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200759static void
Pekka Paalanen6764bbe2015-02-11 12:29:56 +0200760pixman_renderer_surface_get_content_size(struct weston_surface *surface,
761 int *width, int *height)
762{
763 struct pixman_surface_state *ps = get_surface_state(surface);
764
765 if (ps->image) {
766 *width = pixman_image_get_width(ps->image);
767 *height = pixman_image_get_height(ps->image);
768 } else {
769 *width = 0;
770 *height = 0;
771 }
772}
773
774static int
775pixman_renderer_surface_copy_content(struct weston_surface *surface,
776 void *target, size_t size,
777 int src_x, int src_y,
778 int width, int height)
779{
780 const pixman_format_code_t format = PIXMAN_a8b8g8r8;
781 const size_t bytespp = 4; /* PIXMAN_a8b8g8r8 */
782 struct pixman_surface_state *ps = get_surface_state(surface);
783 pixman_image_t *out_buf;
784
785 if (!ps->image)
786 return -1;
787
788 out_buf = pixman_image_create_bits(format, width, height,
789 target, width * bytespp);
790
791 pixman_image_set_transform(ps->image, NULL);
792 pixman_image_composite32(PIXMAN_OP_SRC,
793 ps->image, /* src */
794 NULL, /* mask */
795 out_buf, /* dest */
796 src_x, src_y, /* src_x, src_y */
797 0, 0, /* mask_x, mask_y */
798 0, 0, /* dest_x, dest_y */
799 width, height);
800
801 pixman_image_unref(out_buf);
802
803 return 0;
804}
805
806static void
Derek Foreman8ae2db52015-07-15 13:00:36 -0500807debug_binding(struct weston_keyboard *keyboard, uint32_t time, uint32_t key,
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200808 void *data)
809{
810 struct weston_compositor *ec = data;
811 struct pixman_renderer *pr = (struct pixman_renderer *) ec->renderer;
812
813 pr->repaint_debug ^= 1;
814
815 if (pr->repaint_debug) {
816 pixman_color_t red = {
817 0x3fff, 0x0000, 0x0000, 0x3fff
818 };
819
820 pr->debug_color = pixman_image_create_solid_fill(&red);
821 } else {
822 pixman_image_unref(pr->debug_color);
823 weston_compositor_damage_all(ec);
824 }
825}
826
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300827WL_EXPORT int
828pixman_renderer_init(struct weston_compositor *ec)
829{
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200830 struct pixman_renderer *renderer;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300831
Bryce Harringtonde16d892014-11-20 22:21:57 -0800832 renderer = zalloc(sizeof *renderer);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300833 if (renderer == NULL)
834 return -1;
835
Philipp Brüschweilerf3e39f92013-03-08 20:35:39 +0100836 renderer->repaint_debug = 0;
837 renderer->debug_color = NULL;
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200838 renderer->base.read_pixels = pixman_renderer_read_pixels;
839 renderer->base.repaint_output = pixman_renderer_repaint_output;
840 renderer->base.flush_damage = pixman_renderer_flush_damage;
841 renderer->base.attach = pixman_renderer_attach;
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200842 renderer->base.surface_set_color = pixman_renderer_surface_set_color;
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200843 renderer->base.destroy = pixman_renderer_destroy;
Pekka Paalanen6764bbe2015-02-11 12:29:56 +0200844 renderer->base.surface_get_content_size =
845 pixman_renderer_surface_get_content_size;
846 renderer->base.surface_copy_content =
847 pixman_renderer_surface_copy_content;
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200848 ec->renderer = &renderer->base;
Pekka Paalanen7bb65102013-05-22 18:03:04 +0300849 ec->capabilities |= WESTON_CAP_ROTATION_ANY;
Pekka Paalanen4fc5dd02013-05-22 18:03:05 +0300850 ec->capabilities |= WESTON_CAP_CAPTURE_YFLIP;
Pekka Paalanenc93782a2015-03-06 10:33:50 +0200851 ec->capabilities |= WESTON_CAP_VIEW_CLIP_MASK;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300852
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +0300853 renderer->debug_binding =
854 weston_compositor_add_debug_binding(ec, KEY_R,
855 debug_binding, ec);
Tomeu Vizoso1c1fc292013-08-06 20:05:56 +0200856
857 wl_display_add_shm_format(ec->wl_display, WL_SHM_FORMAT_RGB565);
858
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300859 wl_signal_init(&renderer->destroy_signal);
860
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300861 return 0;
862}
863
864WL_EXPORT void
865pixman_renderer_output_set_buffer(struct weston_output *output, pixman_image_t *buffer)
866{
867 struct pixman_output_state *po = get_output_state(output);
868
869 if (po->hw_buffer)
870 pixman_image_unref(po->hw_buffer);
871 po->hw_buffer = buffer;
872
873 if (po->hw_buffer) {
874 output->compositor->read_format = pixman_image_get_format(po->hw_buffer);
875 pixman_image_ref(po->hw_buffer);
876 }
877}
878
879WL_EXPORT int
880pixman_renderer_output_create(struct weston_output *output)
881{
Bryce Harringtonde16d892014-11-20 22:21:57 -0800882 struct pixman_output_state *po;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200883 int w, h;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300884
Bryce Harringtonde16d892014-11-20 22:21:57 -0800885 po = zalloc(sizeof *po);
886 if (po == NULL)
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300887 return -1;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200888
889 /* set shadow image transformation */
Hardeningff39efa2013-09-18 23:56:35 +0200890 w = output->current_mode->width;
891 h = output->current_mode->height;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200892
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200893 po->shadow_buffer = malloc(w * h * 4);
894
895 if (!po->shadow_buffer) {
896 free(po);
897 return -1;
898 }
899
900 po->shadow_image =
901 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
902 po->shadow_buffer, w * 4);
903
904 if (!po->shadow_image) {
905 free(po->shadow_buffer);
906 free(po);
907 return -1;
908 }
909
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300910 output->renderer_state = po;
911
912 return 0;
913}
914
915WL_EXPORT void
916pixman_renderer_output_destroy(struct weston_output *output)
917{
918 struct pixman_output_state *po = get_output_state(output);
919
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200920 pixman_image_unref(po->shadow_image);
Ander Conselvan de Oliveira23e72b82013-01-25 15:13:06 +0200921
922 if (po->hw_buffer)
923 pixman_image_unref(po->hw_buffer);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200924
Arnaud Vrac8e3fe082014-08-25 20:56:52 +0200925 free(po->shadow_buffer);
926
927 po->shadow_buffer = NULL;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200928 po->shadow_image = NULL;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300929 po->hw_buffer = NULL;
930
931 free(po);
932}