1 /*
2 * Copyright © 2012 Intel Corporation
3 * Copyright © 2013 Vasily Khoruzhick <anarsoul@gmail.com>
4 * Copyright © 2015 Collabora, Ltd.
5 *
6 * 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:
13 *
14 * 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.
26 */
27
28 #include "config.h"
29
30 #include <errno.h>
31 #include <stdint.h>
32 #include <stdlib.h>
33 #include <assert.h>
34
35 #include "pixman-renderer.h"
36 #include "shared/helpers.h"
37
38 #include <linux/input.h>
39
40 struct pixman_output_state {
41 void *shadow_buffer;
42 pixman_image_t *shadow_image;
43 pixman_image_t *hw_buffer;
44 pixman_region32_t *hw_extra_damage;
45 };
46
47 struct pixman_surface_state {
48 struct weston_surface *surface;
49
50 pixman_image_t *image;
51 struct weston_buffer_reference buffer_ref;
52 struct weston_buffer_release_reference buffer_release_ref;
53
54 struct wl_listener buffer_destroy_listener;
55 struct wl_listener surface_destroy_listener;
56 struct wl_listener renderer_destroy_listener;
57 };
58
59 struct pixman_renderer {
60 struct weston_renderer base;
61
62 int repaint_debug;
63 pixman_image_t *debug_color;
64 struct weston_binding *debug_binding;
65
66 struct wl_signal destroy_signal;
67 };
68
69 static inline struct pixman_output_state *
get_output_state(struct weston_output * output)70 get_output_state(struct weston_output *output)
71 {
72 return (struct pixman_output_state *)output->renderer_state;
73 }
74
75 static int
76 pixman_renderer_create_surface(struct weston_surface *surface);
77
78 static inline struct pixman_surface_state *
get_surface_state(struct weston_surface * surface)79 get_surface_state(struct weston_surface *surface)
80 {
81 if (!surface->renderer_state)
82 pixman_renderer_create_surface(surface);
83
84 return (struct pixman_surface_state *)surface->renderer_state;
85 }
86
87 static inline struct pixman_renderer *
get_renderer(struct weston_compositor * ec)88 get_renderer(struct weston_compositor *ec)
89 {
90 return (struct pixman_renderer *)ec->renderer;
91 }
92
93 static int
pixman_renderer_read_pixels(struct weston_output * output,pixman_format_code_t format,void * pixels,uint32_t x,uint32_t y,uint32_t width,uint32_t height)94 pixman_renderer_read_pixels(struct weston_output *output,
95 pixman_format_code_t format, void *pixels,
96 uint32_t x, uint32_t y,
97 uint32_t width, uint32_t height)
98 {
99 struct pixman_output_state *po = get_output_state(output);
100 pixman_transform_t transform;
101 pixman_image_t *out_buf;
102
103 if (!po->hw_buffer) {
104 errno = ENODEV;
105 return -1;
106 }
107
108 out_buf = pixman_image_create_bits(format,
109 width,
110 height,
111 pixels,
112 (PIXMAN_FORMAT_BPP(format) / 8) * width);
113
114 /* Caller expects vflipped source image */
115 pixman_transform_init_translate(&transform,
116 pixman_int_to_fixed (x),
117 pixman_int_to_fixed (y - pixman_image_get_height (po->hw_buffer)));
118 pixman_transform_scale(&transform, NULL,
119 pixman_fixed_1,
120 pixman_fixed_minus_1);
121 pixman_image_set_transform(po->hw_buffer, &transform);
122
123 pixman_image_composite32(PIXMAN_OP_SRC,
124 po->hw_buffer, /* src */
125 NULL /* mask */,
126 out_buf, /* dest */
127 0, 0, /* src_x, src_y */
128 0, 0, /* mask_x, mask_y */
129 0, 0, /* dest_x, dest_y */
130 pixman_image_get_width (po->hw_buffer), /* width */
131 pixman_image_get_height (po->hw_buffer) /* height */);
132 pixman_image_set_transform(po->hw_buffer, NULL);
133
134 pixman_image_unref(out_buf);
135
136 return 0;
137 }
138
139 static void
region_global_to_output(struct weston_output * output,pixman_region32_t * region)140 region_global_to_output(struct weston_output *output, pixman_region32_t *region)
141 {
142 if (output->zoom.active) {
143 weston_matrix_transform_region(region, &output->matrix, region);
144 } else {
145 pixman_region32_translate(region, -output->x, -output->y);
146 weston_transformed_region(output->width, output->height,
147 output->transform,
148 output->current_scale,
149 region, region);
150 }
151 }
152
153 #define D2F(v) pixman_double_to_fixed((double)v)
154
155 static void
weston_matrix_to_pixman_transform(pixman_transform_t * pt,const struct weston_matrix * wm)156 weston_matrix_to_pixman_transform(pixman_transform_t *pt,
157 const struct weston_matrix *wm)
158 {
159 /* Pixman supports only 2D transform matrix, but Weston uses 3D, *
160 * so we're omitting Z coordinate here. */
161 pt->matrix[0][0] = pixman_double_to_fixed(wm->d[0]);
162 pt->matrix[0][1] = pixman_double_to_fixed(wm->d[4]);
163 pt->matrix[0][2] = pixman_double_to_fixed(wm->d[12]);
164 pt->matrix[1][0] = pixman_double_to_fixed(wm->d[1]);
165 pt->matrix[1][1] = pixman_double_to_fixed(wm->d[5]);
166 pt->matrix[1][2] = pixman_double_to_fixed(wm->d[13]);
167 pt->matrix[2][0] = pixman_double_to_fixed(wm->d[3]);
168 pt->matrix[2][1] = pixman_double_to_fixed(wm->d[7]);
169 pt->matrix[2][2] = pixman_double_to_fixed(wm->d[15]);
170 }
171
172 static void
pixman_renderer_compute_transform(pixman_transform_t * transform_out,struct weston_view * ev,struct weston_output * output)173 pixman_renderer_compute_transform(pixman_transform_t *transform_out,
174 struct weston_view *ev,
175 struct weston_output *output)
176 {
177 struct weston_matrix matrix;
178
179 /* Set up the source transformation based on the surface
180 position, the output position/transform/scale and the client
181 specified buffer transform/scale */
182 matrix = output->inverse_matrix;
183
184 if (ev->transform.enabled) {
185 weston_matrix_multiply(&matrix, &ev->transform.inverse);
186 } else {
187 weston_matrix_translate(&matrix,
188 -ev->geometry.x, -ev->geometry.y, 0);
189 }
190
191 weston_matrix_multiply(&matrix, &ev->surface->surface_to_buffer_matrix);
192
193 weston_matrix_to_pixman_transform(transform_out, &matrix);
194 }
195
196 static bool
view_transformation_is_translation(struct weston_view * view)197 view_transformation_is_translation(struct weston_view *view)
198 {
199 if (!view->transform.enabled)
200 return true;
201
202 if (view->transform.matrix.type <= WESTON_MATRIX_TRANSFORM_TRANSLATE)
203 return true;
204
205 return false;
206 }
207
208 static void
region_intersect_only_translation(pixman_region32_t * result_global,pixman_region32_t * global,pixman_region32_t * surf,struct weston_view * view)209 region_intersect_only_translation(pixman_region32_t *result_global,
210 pixman_region32_t *global,
211 pixman_region32_t *surf,
212 struct weston_view *view)
213 {
214 float view_x, view_y;
215
216 assert(view_transformation_is_translation(view));
217
218 /* Convert from surface to global coordinates */
219 pixman_region32_copy(result_global, surf);
220 weston_view_to_global_float(view, 0, 0, &view_x, &view_y);
221 pixman_region32_translate(result_global, (int)view_x, (int)view_y);
222
223 pixman_region32_intersect(result_global, result_global, global);
224 }
225
226 static void
composite_whole(pixman_op_t op,pixman_image_t * src,pixman_image_t * mask,pixman_image_t * dest,const pixman_transform_t * transform,pixman_filter_t filter)227 composite_whole(pixman_op_t op,
228 pixman_image_t *src,
229 pixman_image_t *mask,
230 pixman_image_t *dest,
231 const pixman_transform_t *transform,
232 pixman_filter_t filter)
233 {
234 int32_t dest_width;
235 int32_t dest_height;
236
237 dest_width = pixman_image_get_width(dest);
238 dest_height = pixman_image_get_height(dest);
239
240 pixman_image_set_transform(src, transform);
241 pixman_image_set_filter(src, filter, NULL, 0);
242
243 pixman_image_composite32(op, src, mask, dest,
244 0, 0, /* src_x, src_y */
245 0, 0, /* mask_x, mask_y */
246 0, 0, /* dest_x, dest_y */
247 dest_width, dest_height);
248 }
249
250 static void
composite_clipped(pixman_image_t * src,pixman_image_t * mask,pixman_image_t * dest,const pixman_transform_t * transform,pixman_filter_t filter,pixman_region32_t * src_clip)251 composite_clipped(pixman_image_t *src,
252 pixman_image_t *mask,
253 pixman_image_t *dest,
254 const pixman_transform_t *transform,
255 pixman_filter_t filter,
256 pixman_region32_t *src_clip)
257 {
258 int n_box;
259 pixman_box32_t *boxes;
260 int32_t dest_width;
261 int32_t dest_height;
262 int src_stride;
263 int bitspp;
264 pixman_format_code_t src_format;
265 void *src_data;
266 int i;
267
268 /* Hardcoded to use PIXMAN_OP_OVER, because sampling outside of
269 * a Pixman image produces (0,0,0,0) instead of discarding the
270 * fragment.
271 */
272
273 dest_width = pixman_image_get_width(dest);
274 dest_height = pixman_image_get_height(dest);
275 src_format = pixman_image_get_format(src);
276 src_stride = pixman_image_get_stride(src);
277 bitspp = PIXMAN_FORMAT_BPP(src_format);
278 src_data = pixman_image_get_data(src);
279
280 assert(src_format);
281
282 /* This would be massive overdraw, except when n_box is 1. */
283 boxes = pixman_region32_rectangles(src_clip, &n_box);
284 for (i = 0; i < n_box; i++) {
285 uint8_t *ptr = src_data;
286 pixman_image_t *boximg;
287 pixman_transform_t adj = *transform;
288
289 ptr += boxes[i].y1 * src_stride;
290 ptr += boxes[i].x1 * bitspp / 8;
291 boximg = pixman_image_create_bits_no_clear(src_format,
292 boxes[i].x2 - boxes[i].x1,
293 boxes[i].y2 - boxes[i].y1,
294 (uint32_t *)ptr, src_stride);
295
296 pixman_transform_translate(&adj, NULL,
297 pixman_int_to_fixed(-boxes[i].x1),
298 pixman_int_to_fixed(-boxes[i].y1));
299 pixman_image_set_transform(boximg, &adj);
300
301 pixman_image_set_filter(boximg, filter, NULL, 0);
302 pixman_image_composite32(PIXMAN_OP_OVER, boximg, mask, dest,
303 0, 0, /* src_x, src_y */
304 0, 0, /* mask_x, mask_y */
305 0, 0, /* dest_x, dest_y */
306 dest_width, dest_height);
307
308 pixman_image_unref(boximg);
309 }
310
311 if (n_box > 1) {
312 static bool warned = false;
313
314 if (!warned)
315 weston_log("Pixman-renderer warning: %dx overdraw\n",
316 n_box);
317 warned = true;
318 }
319 }
320
321 /** Paint an intersected region
322 *
323 * \param ev The view to be painted.
324 * \param output The output being painted.
325 * \param repaint_output The region to be painted in output coordinates.
326 * \param source_clip The region of the source image to use, in source image
327 * coordinates. If NULL, use the whole source image.
328 * \param pixman_op Compositing operator, either SRC or OVER.
329 */
330 static void
repaint_region(struct weston_view * ev,struct weston_output * output,pixman_region32_t * repaint_output,pixman_region32_t * source_clip,pixman_op_t pixman_op)331 repaint_region(struct weston_view *ev, struct weston_output *output,
332 pixman_region32_t *repaint_output,
333 pixman_region32_t *source_clip,
334 pixman_op_t pixman_op)
335 {
336 struct pixman_renderer *pr =
337 (struct pixman_renderer *) output->compositor->renderer;
338 struct pixman_surface_state *ps = get_surface_state(ev->surface);
339 struct pixman_output_state *po = get_output_state(output);
340 struct weston_buffer_viewport *vp = &ev->surface->buffer_viewport;
341 pixman_image_t *target_image;
342 pixman_transform_t transform;
343 pixman_filter_t filter;
344 pixman_image_t *mask_image;
345 pixman_color_t mask = { 0, };
346
347 if (po->shadow_image)
348 target_image = po->shadow_image;
349 else
350 target_image = po->hw_buffer;
351
352 /* Clip rendering to the damaged output region */
353 pixman_image_set_clip_region32(target_image, repaint_output);
354
355 pixman_renderer_compute_transform(&transform, ev, output);
356
357 if (ev->transform.enabled || output->current_scale != vp->buffer.scale)
358 filter = PIXMAN_FILTER_BILINEAR;
359 else
360 filter = PIXMAN_FILTER_NEAREST;
361
362 if (ps->buffer_ref.buffer)
363 wl_shm_buffer_begin_access(ps->buffer_ref.buffer->shm_buffer);
364
365 if (ev->alpha < 1.0) {
366 mask.alpha = 0xffff * ev->alpha;
367 mask_image = pixman_image_create_solid_fill(&mask);
368 } else {
369 mask_image = NULL;
370 }
371
372 if (source_clip)
373 composite_clipped(ps->image, mask_image, target_image,
374 &transform, filter, source_clip);
375 else
376 composite_whole(pixman_op, ps->image, mask_image,
377 target_image, &transform, filter);
378
379 if (mask_image)
380 pixman_image_unref(mask_image);
381
382 if (ps->buffer_ref.buffer)
383 wl_shm_buffer_end_access(ps->buffer_ref.buffer->shm_buffer);
384
385 if (pr->repaint_debug)
386 pixman_image_composite32(PIXMAN_OP_OVER,
387 pr->debug_color, /* src */
388 NULL /* mask */,
389 target_image, /* dest */
390 0, 0, /* src_x, src_y */
391 0, 0, /* mask_x, mask_y */
392 0, 0, /* dest_x, dest_y */
393 pixman_image_get_width (target_image), /* width */
394 pixman_image_get_height (target_image) /* height */);
395
396 pixman_image_set_clip_region32(target_image, NULL);
397 }
398
399 static void
draw_view_translated(struct weston_view * view,struct weston_output * output,pixman_region32_t * repaint_global)400 draw_view_translated(struct weston_view *view, struct weston_output *output,
401 pixman_region32_t *repaint_global)
402 {
403 struct weston_surface *surface = view->surface;
404 /* non-opaque region in surface coordinates: */
405 pixman_region32_t surface_blend;
406 /* region to be painted in output coordinates: */
407 pixman_region32_t repaint_output;
408
409 pixman_region32_init(&repaint_output);
410
411 /* Blended region is whole surface minus opaque region,
412 * unless surface alpha forces us to blend all.
413 */
414 pixman_region32_init_rect(&surface_blend, 0, 0,
415 surface->width, surface->height);
416
417 if (!(view->alpha < 1.0)) {
418 pixman_region32_subtract(&surface_blend, &surface_blend,
419 &surface->opaque);
420
421 if (pixman_region32_not_empty(&surface->opaque)) {
422 region_intersect_only_translation(&repaint_output,
423 repaint_global,
424 &surface->opaque,
425 view);
426 region_global_to_output(output, &repaint_output);
427
428 repaint_region(view, output, &repaint_output, NULL,
429 PIXMAN_OP_SRC);
430 }
431 }
432
433 if (pixman_region32_not_empty(&surface_blend)) {
434 region_intersect_only_translation(&repaint_output,
435 repaint_global,
436 &surface_blend, view);
437 region_global_to_output(output, &repaint_output);
438
439 repaint_region(view, output, &repaint_output, NULL,
440 PIXMAN_OP_OVER);
441 }
442
443 pixman_region32_fini(&surface_blend);
444 pixman_region32_fini(&repaint_output);
445 }
446
447 static void
draw_view_source_clipped(struct weston_view * view,struct weston_output * output,pixman_region32_t * repaint_global)448 draw_view_source_clipped(struct weston_view *view,
449 struct weston_output *output,
450 pixman_region32_t *repaint_global)
451 {
452 struct weston_surface *surface = view->surface;
453 pixman_region32_t surf_region;
454 pixman_region32_t buffer_region;
455 pixman_region32_t repaint_output;
456
457 /* Do not bother separating the opaque region from non-opaque.
458 * Source clipping requires PIXMAN_OP_OVER in all cases, so painting
459 * opaque separately has no benefit.
460 */
461
462 pixman_region32_init_rect(&surf_region, 0, 0,
463 surface->width, surface->height);
464 if (view->geometry.scissor_enabled)
465 pixman_region32_intersect(&surf_region, &surf_region,
466 &view->geometry.scissor);
467
468 pixman_region32_init(&buffer_region);
469 weston_surface_to_buffer_region(surface, &surf_region, &buffer_region);
470
471 pixman_region32_init(&repaint_output);
472 pixman_region32_copy(&repaint_output, repaint_global);
473 region_global_to_output(output, &repaint_output);
474
475 repaint_region(view, output, &repaint_output, &buffer_region,
476 PIXMAN_OP_OVER);
477
478 pixman_region32_fini(&repaint_output);
479 pixman_region32_fini(&buffer_region);
480 pixman_region32_fini(&surf_region);
481 }
482
483 static void
draw_view(struct weston_view * ev,struct weston_output * output,pixman_region32_t * damage)484 draw_view(struct weston_view *ev, struct weston_output *output,
485 pixman_region32_t *damage) /* in global coordinates */
486 {
487 struct pixman_surface_state *ps = get_surface_state(ev->surface);
488 /* repaint bounding region in global coordinates: */
489 pixman_region32_t repaint;
490
491 /* No buffer attached */
492 if (!ps->image)
493 return;
494
495 pixman_region32_init(&repaint);
496 pixman_region32_intersect(&repaint,
497 &ev->transform.boundingbox, damage);
498 pixman_region32_subtract(&repaint, &repaint, &ev->clip);
499
500 if (!pixman_region32_not_empty(&repaint))
501 goto out;
502
503 if (view_transformation_is_translation(ev)) {
504 /* The simple case: The surface regions opaque, non-opaque,
505 * etc. are convertible to global coordinate space.
506 * There is no need to use a source clip region.
507 * It is possible to paint opaque region as PIXMAN_OP_SRC.
508 * Also the boundingbox is accurate rather than an
509 * approximation.
510 */
511 draw_view_translated(ev, output, &repaint);
512 } else {
513 /* The complex case: the view transformation does not allow
514 * converting opaque etc. regions into global coordinate space.
515 * Therefore we need source clipping to avoid sampling from
516 * unwanted source image areas, unless the source image is
517 * to be used whole. Source clipping does not work with
518 * PIXMAN_OP_SRC.
519 */
520 draw_view_source_clipped(ev, output, &repaint);
521 }
522
523 out:
524 pixman_region32_fini(&repaint);
525 }
526 static void
repaint_surfaces(struct weston_output * output,pixman_region32_t * damage)527 repaint_surfaces(struct weston_output *output, pixman_region32_t *damage)
528 {
529 struct weston_compositor *compositor = output->compositor;
530 struct weston_view *view;
531
532 wl_list_for_each_reverse(view, &compositor->view_list, link)
533 if (view->plane == &compositor->primary_plane)
534 draw_view(view, output, damage);
535 }
536
537 static void
copy_to_hw_buffer(struct weston_output * output,pixman_region32_t * region)538 copy_to_hw_buffer(struct weston_output *output, pixman_region32_t *region)
539 {
540 struct pixman_output_state *po = get_output_state(output);
541 pixman_region32_t output_region;
542
543 pixman_region32_init(&output_region);
544 pixman_region32_copy(&output_region, region);
545
546 region_global_to_output(output, &output_region);
547
548 pixman_image_set_clip_region32 (po->hw_buffer, &output_region);
549 pixman_region32_fini(&output_region);
550
551 pixman_image_composite32(PIXMAN_OP_SRC,
552 po->shadow_image, /* src */
553 NULL /* mask */,
554 po->hw_buffer, /* dest */
555 0, 0, /* src_x, src_y */
556 0, 0, /* mask_x, mask_y */
557 0, 0, /* dest_x, dest_y */
558 pixman_image_get_width (po->hw_buffer), /* width */
559 pixman_image_get_height (po->hw_buffer) /* height */);
560
561 pixman_image_set_clip_region32 (po->hw_buffer, NULL);
562 }
563
564 static void
pixman_renderer_repaint_output(struct weston_output * output,pixman_region32_t * output_damage)565 pixman_renderer_repaint_output(struct weston_output *output,
566 pixman_region32_t *output_damage)
567 {
568 struct pixman_output_state *po = get_output_state(output);
569 pixman_region32_t hw_damage;
570
571 if (!po->hw_buffer) {
572 po->hw_extra_damage = NULL;
573 return;
574 }
575
576 pixman_region32_init(&hw_damage);
577 if (po->hw_extra_damage) {
578 pixman_region32_union(&hw_damage,
579 po->hw_extra_damage, output_damage);
580 po->hw_extra_damage = NULL;
581 } else {
582 pixman_region32_copy(&hw_damage, output_damage);
583 }
584
585 if (po->shadow_image) {
586 repaint_surfaces(output, output_damage);
587 copy_to_hw_buffer(output, &hw_damage);
588 } else {
589 repaint_surfaces(output, &hw_damage);
590 }
591 pixman_region32_fini(&hw_damage);
592
593 pixman_region32_copy(&output->previous_damage, output_damage);
594 wl_signal_emit(&output->frame_signal, output);
595
596 /* Actual flip should be done by caller */
597 }
598
599 static void
pixman_renderer_flush_damage(struct weston_surface * surface)600 pixman_renderer_flush_damage(struct weston_surface *surface)
601 {
602 /* No-op for pixman renderer */
603 }
604
605 static void
buffer_state_handle_buffer_destroy(struct wl_listener * listener,void * data)606 buffer_state_handle_buffer_destroy(struct wl_listener *listener, void *data)
607 {
608 struct pixman_surface_state *ps;
609
610 ps = container_of(listener, struct pixman_surface_state,
611 buffer_destroy_listener);
612
613 if (ps->image) {
614 pixman_image_unref(ps->image);
615 ps->image = NULL;
616 }
617
618 ps->buffer_destroy_listener.notify = NULL;
619 }
620
621 static void
pixman_renderer_attach(struct weston_surface * es,struct weston_buffer * buffer)622 pixman_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
623 {
624 struct pixman_surface_state *ps = get_surface_state(es);
625 struct wl_shm_buffer *shm_buffer;
626 pixman_format_code_t pixman_format;
627
628 weston_buffer_reference(&ps->buffer_ref, buffer);
629 weston_buffer_release_reference(&ps->buffer_release_ref,
630 es->buffer_release_ref.buffer_release);
631
632 if (ps->buffer_destroy_listener.notify) {
633 wl_list_remove(&ps->buffer_destroy_listener.link);
634 ps->buffer_destroy_listener.notify = NULL;
635 }
636
637 if (ps->image) {
638 pixman_image_unref(ps->image);
639 ps->image = NULL;
640 }
641
642 if (!buffer)
643 return;
644
645 shm_buffer = wl_shm_buffer_get(buffer->resource);
646
647 if (! shm_buffer) {
648 weston_log("Pixman renderer supports only SHM buffers\n");
649 weston_buffer_reference(&ps->buffer_ref, NULL);
650 weston_buffer_release_reference(&ps->buffer_release_ref, NULL);
651 return;
652 }
653
654 switch (wl_shm_buffer_get_format(shm_buffer)) {
655 case WL_SHM_FORMAT_XRGB8888:
656 pixman_format = PIXMAN_x8r8g8b8;
657 es->is_opaque = true;
658 break;
659 case WL_SHM_FORMAT_ARGB8888:
660 pixman_format = PIXMAN_a8r8g8b8;
661 es->is_opaque = false;
662 break;
663 case WL_SHM_FORMAT_RGB565:
664 pixman_format = PIXMAN_r5g6b5;
665 es->is_opaque = true;
666 break;
667 default:
668 weston_log("Unsupported SHM buffer format 0x%x\n",
669 wl_shm_buffer_get_format(shm_buffer));
670 weston_buffer_reference(&ps->buffer_ref, NULL);
671 weston_buffer_release_reference(&ps->buffer_release_ref, NULL);
672 weston_buffer_send_server_error(buffer,
673 "disconnecting due to unhandled buffer type");
674 return;
675 break;
676 }
677
678 buffer->shm_buffer = shm_buffer;
679 buffer->width = wl_shm_buffer_get_width(shm_buffer);
680 buffer->height = wl_shm_buffer_get_height(shm_buffer);
681
682 ps->image = pixman_image_create_bits(pixman_format,
683 buffer->width, buffer->height,
684 wl_shm_buffer_get_data(shm_buffer),
685 wl_shm_buffer_get_stride(shm_buffer));
686
687 ps->buffer_destroy_listener.notify =
688 buffer_state_handle_buffer_destroy;
689 wl_signal_add(&buffer->destroy_signal,
690 &ps->buffer_destroy_listener);
691 }
692
693 static void
pixman_renderer_surface_state_destroy(struct pixman_surface_state * ps)694 pixman_renderer_surface_state_destroy(struct pixman_surface_state *ps)
695 {
696 wl_list_remove(&ps->surface_destroy_listener.link);
697 wl_list_remove(&ps->renderer_destroy_listener.link);
698 if (ps->buffer_destroy_listener.notify) {
699 wl_list_remove(&ps->buffer_destroy_listener.link);
700 ps->buffer_destroy_listener.notify = NULL;
701 }
702
703 ps->surface->renderer_state = NULL;
704
705 if (ps->image) {
706 pixman_image_unref(ps->image);
707 ps->image = NULL;
708 }
709 weston_buffer_reference(&ps->buffer_ref, NULL);
710 weston_buffer_release_reference(&ps->buffer_release_ref, NULL);
711 free(ps);
712 }
713
714 static void
surface_state_handle_surface_destroy(struct wl_listener * listener,void * data)715 surface_state_handle_surface_destroy(struct wl_listener *listener, void *data)
716 {
717 struct pixman_surface_state *ps;
718
719 ps = container_of(listener, struct pixman_surface_state,
720 surface_destroy_listener);
721
722 pixman_renderer_surface_state_destroy(ps);
723 }
724
725 static void
surface_state_handle_renderer_destroy(struct wl_listener * listener,void * data)726 surface_state_handle_renderer_destroy(struct wl_listener *listener, void *data)
727 {
728 struct pixman_surface_state *ps;
729
730 ps = container_of(listener, struct pixman_surface_state,
731 renderer_destroy_listener);
732
733 pixman_renderer_surface_state_destroy(ps);
734 }
735
736 static int
pixman_renderer_create_surface(struct weston_surface * surface)737 pixman_renderer_create_surface(struct weston_surface *surface)
738 {
739 struct pixman_surface_state *ps;
740 struct pixman_renderer *pr = get_renderer(surface->compositor);
741
742 ps = zalloc(sizeof *ps);
743 if (ps == NULL)
744 return -1;
745
746 surface->renderer_state = ps;
747
748 ps->surface = surface;
749
750 ps->surface_destroy_listener.notify =
751 surface_state_handle_surface_destroy;
752 wl_signal_add(&surface->destroy_signal,
753 &ps->surface_destroy_listener);
754
755 ps->renderer_destroy_listener.notify =
756 surface_state_handle_renderer_destroy;
757 wl_signal_add(&pr->destroy_signal,
758 &ps->renderer_destroy_listener);
759
760 return 0;
761 }
762
763 static void
pixman_renderer_surface_set_color(struct weston_surface * es,float red,float green,float blue,float alpha)764 pixman_renderer_surface_set_color(struct weston_surface *es,
765 float red, float green, float blue, float alpha)
766 {
767 struct pixman_surface_state *ps = get_surface_state(es);
768 pixman_color_t color;
769
770 color.red = red * 0xffff;
771 color.green = green * 0xffff;
772 color.blue = blue * 0xffff;
773 color.alpha = alpha * 0xffff;
774
775 if (ps->image) {
776 pixman_image_unref(ps->image);
777 ps->image = NULL;
778 }
779
780 ps->image = pixman_image_create_solid_fill(&color);
781 }
782
783 static void
pixman_renderer_destroy(struct weston_compositor * ec)784 pixman_renderer_destroy(struct weston_compositor *ec)
785 {
786 struct pixman_renderer *pr = get_renderer(ec);
787
788 wl_signal_emit(&pr->destroy_signal, pr);
789 weston_binding_destroy(pr->debug_binding);
790 free(pr);
791
792 ec->renderer = NULL;
793 }
794
795 static void
pixman_renderer_surface_get_content_size(struct weston_surface * surface,int * width,int * height)796 pixman_renderer_surface_get_content_size(struct weston_surface *surface,
797 int *width, int *height)
798 {
799 struct pixman_surface_state *ps = get_surface_state(surface);
800
801 if (ps->image) {
802 *width = pixman_image_get_width(ps->image);
803 *height = pixman_image_get_height(ps->image);
804 } else {
805 *width = 0;
806 *height = 0;
807 }
808 }
809
810 static int
pixman_renderer_surface_copy_content(struct weston_surface * surface,void * target,size_t size,int src_x,int src_y,int width,int height)811 pixman_renderer_surface_copy_content(struct weston_surface *surface,
812 void *target, size_t size,
813 int src_x, int src_y,
814 int width, int height)
815 {
816 const pixman_format_code_t format = PIXMAN_a8b8g8r8;
817 const size_t bytespp = 4; /* PIXMAN_a8b8g8r8 */
818 struct pixman_surface_state *ps = get_surface_state(surface);
819 pixman_image_t *out_buf;
820
821 if (!ps->image)
822 return -1;
823
824 out_buf = pixman_image_create_bits(format, width, height,
825 target, width * bytespp);
826
827 pixman_image_set_transform(ps->image, NULL);
828 pixman_image_composite32(PIXMAN_OP_SRC,
829 ps->image, /* src */
830 NULL, /* mask */
831 out_buf, /* dest */
832 src_x, src_y, /* src_x, src_y */
833 0, 0, /* mask_x, mask_y */
834 0, 0, /* dest_x, dest_y */
835 width, height);
836
837 pixman_image_unref(out_buf);
838
839 return 0;
840 }
841
842 static void
debug_binding(struct weston_keyboard * keyboard,const struct timespec * time,uint32_t key,void * data)843 debug_binding(struct weston_keyboard *keyboard, const struct timespec *time,
844 uint32_t key, void *data)
845 {
846 struct weston_compositor *ec = data;
847 struct pixman_renderer *pr = (struct pixman_renderer *) ec->renderer;
848
849 pr->repaint_debug ^= 1;
850
851 if (pr->repaint_debug) {
852 pixman_color_t red = {
853 0x3fff, 0x0000, 0x0000, 0x3fff
854 };
855
856 pr->debug_color = pixman_image_create_solid_fill(&red);
857 } else {
858 pixman_image_unref(pr->debug_color);
859 weston_compositor_damage_all(ec);
860 }
861 }
862
863 WL_EXPORT int
pixman_renderer_init(struct weston_compositor * ec)864 pixman_renderer_init(struct weston_compositor *ec)
865 {
866 struct pixman_renderer *renderer;
867
868 renderer = zalloc(sizeof *renderer);
869 if (renderer == NULL)
870 return -1;
871
872 renderer->repaint_debug = 0;
873 renderer->debug_color = NULL;
874 renderer->base.read_pixels = pixman_renderer_read_pixels;
875 renderer->base.repaint_output = pixman_renderer_repaint_output;
876 renderer->base.flush_damage = pixman_renderer_flush_damage;
877 renderer->base.attach = pixman_renderer_attach;
878 renderer->base.surface_set_color = pixman_renderer_surface_set_color;
879 renderer->base.destroy = pixman_renderer_destroy;
880 renderer->base.surface_get_content_size =
881 pixman_renderer_surface_get_content_size;
882 renderer->base.surface_copy_content =
883 pixman_renderer_surface_copy_content;
884 ec->renderer = &renderer->base;
885 ec->capabilities |= WESTON_CAP_ROTATION_ANY;
886 ec->capabilities |= WESTON_CAP_CAPTURE_YFLIP;
887 ec->capabilities |= WESTON_CAP_VIEW_CLIP_MASK;
888
889 renderer->debug_binding =
890 weston_compositor_add_debug_binding(ec, KEY_R,
891 debug_binding, ec);
892
893 wl_display_add_shm_format(ec->wl_display, WL_SHM_FORMAT_RGB565);
894
895 wl_signal_init(&renderer->destroy_signal);
896
897 return 0;
898 }
899
900 WL_EXPORT void
pixman_renderer_output_set_buffer(struct weston_output * output,pixman_image_t * buffer)901 pixman_renderer_output_set_buffer(struct weston_output *output,
902 pixman_image_t *buffer)
903 {
904 struct pixman_output_state *po = get_output_state(output);
905
906 if (po->hw_buffer)
907 pixman_image_unref(po->hw_buffer);
908 po->hw_buffer = buffer;
909
910 if (po->hw_buffer) {
911 output->compositor->read_format = pixman_image_get_format(po->hw_buffer);
912 pixman_image_ref(po->hw_buffer);
913 }
914 }
915
916 WL_EXPORT void
pixman_renderer_output_set_hw_extra_damage(struct weston_output * output,pixman_region32_t * extra_damage)917 pixman_renderer_output_set_hw_extra_damage(struct weston_output *output,
918 pixman_region32_t *extra_damage)
919 {
920 struct pixman_output_state *po = get_output_state(output);
921
922 po->hw_extra_damage = extra_damage;
923 }
924
925 WL_EXPORT int
pixman_renderer_output_create(struct weston_output * output,uint32_t flags)926 pixman_renderer_output_create(struct weston_output *output, uint32_t flags)
927 {
928 struct pixman_output_state *po;
929 int w, h;
930
931 po = zalloc(sizeof *po);
932 if (po == NULL)
933 return -1;
934
935 if (flags & PIXMAN_RENDERER_OUTPUT_USE_SHADOW) {
936 /* set shadow image transformation */
937 w = output->current_mode->width;
938 h = output->current_mode->height;
939
940 po->shadow_buffer = malloc(w * h * 4);
941
942 if (!po->shadow_buffer) {
943 free(po);
944 return -1;
945 }
946
947 po->shadow_image =
948 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
949 po->shadow_buffer, w * 4);
950
951 if (!po->shadow_image) {
952 free(po->shadow_buffer);
953 free(po);
954 return -1;
955 }
956 }
957
958 output->renderer_state = po;
959
960 return 0;
961 }
962
963 WL_EXPORT void
pixman_renderer_output_destroy(struct weston_output * output)964 pixman_renderer_output_destroy(struct weston_output *output)
965 {
966 struct pixman_output_state *po = get_output_state(output);
967
968 if (po->shadow_image)
969 pixman_image_unref(po->shadow_image);
970
971 if (po->hw_buffer)
972 pixman_image_unref(po->hw_buffer);
973
974 free(po->shadow_buffer);
975
976 po->shadow_buffer = NULL;
977 po->shadow_image = NULL;
978 po->hw_buffer = NULL;
979
980 free(po);
981 }
982