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