compositor-drm: Work around page flip not setting tiling mode on BYT
[platform/upstream/weston.git] / src / pixman-renderer.c
1 /*
2  * Copyright © 2012 Intel Corporation
3  * Copyright © 2013 Vasily Khoruzhick <anarsoul@gmail.com>
4  *
5  * Permission to use, copy, modify, distribute, and sell this software and
6  * its documentation for any purpose is hereby granted without fee, provided
7  * that the above copyright notice appear in all copies and that both that
8  * copyright notice and this permission notice appear in supporting
9  * documentation, and that the name of the copyright holders not be used in
10  * advertising or publicity pertaining to distribution of the software
11  * without specific, written prior permission.  The copyright holders make
12  * no representations about the suitability of this software for any
13  * purpose.  It is provided "as is" without express or implied warranty.
14  *
15  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
16  * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17  * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
18  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
19  * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
20  * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22  */
23
24 #include "config.h"
25
26 #include <errno.h>
27 #include <stdlib.h>
28
29 #include "pixman-renderer.h"
30
31 #include <linux/input.h>
32
33 struct pixman_output_state {
34         void *shadow_buffer;
35         pixman_image_t *shadow_image;
36         pixman_image_t *hw_buffer;
37 };
38
39 struct pixman_surface_state {
40         struct weston_surface *surface;
41
42         pixman_image_t *image;
43         struct weston_buffer_reference buffer_ref;
44
45         struct wl_listener buffer_destroy_listener;
46         struct wl_listener surface_destroy_listener;
47         struct wl_listener renderer_destroy_listener;
48 };
49
50 struct pixman_renderer {
51         struct weston_renderer base;
52
53         int repaint_debug;
54         pixman_image_t *debug_color;
55         struct weston_binding *debug_binding;
56
57         struct wl_signal destroy_signal;
58 };
59
60 static inline struct pixman_output_state *
61 get_output_state(struct weston_output *output)
62 {
63         return (struct pixman_output_state *)output->renderer_state;
64 }
65
66 static int
67 pixman_renderer_create_surface(struct weston_surface *surface);
68
69 static inline struct pixman_surface_state *
70 get_surface_state(struct weston_surface *surface)
71 {
72         if (!surface->renderer_state)
73                 pixman_renderer_create_surface(surface);
74
75         return (struct pixman_surface_state *)surface->renderer_state;
76 }
77
78 static inline struct pixman_renderer *
79 get_renderer(struct weston_compositor *ec)
80 {
81         return (struct pixman_renderer *)ec->renderer;
82 }
83
84 static int
85 pixman_renderer_read_pixels(struct weston_output *output,
86                                pixman_format_code_t format, void *pixels,
87                                uint32_t x, uint32_t y,
88                                uint32_t width, uint32_t height)
89 {
90         struct pixman_output_state *po = get_output_state(output);
91         pixman_transform_t transform;
92         pixman_image_t *out_buf;
93
94         if (!po->hw_buffer) {
95                 errno = ENODEV;
96                 return -1;
97         }
98
99         out_buf = pixman_image_create_bits(format,
100                 width,
101                 height,
102                 pixels,
103                 (PIXMAN_FORMAT_BPP(format) / 8) * width);
104
105         /* Caller expects vflipped source image */
106         pixman_transform_init_translate(&transform,
107                                         pixman_int_to_fixed (x),
108                                         pixman_int_to_fixed (y - pixman_image_get_height (po->hw_buffer)));
109         pixman_transform_scale(&transform, NULL,
110                                pixman_fixed_1,
111                                pixman_fixed_minus_1);
112         pixman_image_set_transform(po->hw_buffer, &transform);
113
114         pixman_image_composite32(PIXMAN_OP_SRC,
115                                  po->hw_buffer, /* src */
116                                  NULL /* mask */,
117                                  out_buf, /* dest */
118                                  0, 0, /* src_x, src_y */
119                                  0, 0, /* mask_x, mask_y */
120                                  0, 0, /* dest_x, dest_y */
121                                  pixman_image_get_width (po->hw_buffer), /* width */
122                                  pixman_image_get_height (po->hw_buffer) /* height */);
123         pixman_image_set_transform(po->hw_buffer, NULL);
124
125         pixman_image_unref(out_buf);
126
127         return 0;
128 }
129
130 static void
131 region_global_to_output(struct weston_output *output, pixman_region32_t *region)
132 {
133         pixman_region32_translate(region, -output->x, -output->y);
134         weston_transformed_region(output->width, output->height,
135                                   output->transform, output->current_scale,
136                                   region, region);
137 }
138
139 #define D2F(v) pixman_double_to_fixed((double)v)
140
141 static void
142 transform_apply_viewport(pixman_transform_t *transform,
143                          struct weston_surface *surface)
144 {
145         struct weston_buffer_viewport *vp = &surface->buffer_viewport;
146         double src_width, src_height;
147         double src_x, src_y;
148
149         if (vp->buffer.src_width == wl_fixed_from_int(-1)) {
150                 if (vp->surface.width == -1)
151                         return;
152
153                 src_x = 0.0;
154                 src_y = 0.0;
155                 src_width = surface->width_from_buffer;
156                 src_height = surface->height_from_buffer;
157         } else {
158                 src_x = wl_fixed_to_double(vp->buffer.src_x);
159                 src_y = wl_fixed_to_double(vp->buffer.src_y);
160                 src_width = wl_fixed_to_double(vp->buffer.src_width);
161                 src_height = wl_fixed_to_double(vp->buffer.src_height);
162         }
163
164         pixman_transform_scale(transform, NULL,
165                                D2F(src_width / surface->width),
166                                D2F(src_height / surface->height));
167         pixman_transform_translate(transform, NULL, D2F(src_x), D2F(src_y));
168 }
169
170 static void
171 repaint_region(struct weston_view *ev, struct weston_output *output,
172                pixman_region32_t *region, pixman_region32_t *surf_region,
173                pixman_op_t pixman_op)
174 {
175         struct pixman_renderer *pr =
176                 (struct pixman_renderer *) output->compositor->renderer;
177         struct pixman_surface_state *ps = get_surface_state(ev->surface);
178         struct pixman_output_state *po = get_output_state(output);
179         struct weston_buffer_viewport *vp = &ev->surface->buffer_viewport;
180         pixman_region32_t final_region;
181         float view_x, view_y;
182         pixman_transform_t transform;
183         pixman_fixed_t fw, fh;
184         pixman_image_t *mask_image;
185         pixman_color_t mask = { 0, };
186
187         /* The final region to be painted is the intersection of
188          * 'region' and 'surf_region'. However, 'region' is in the global
189          * coordinates, and 'surf_region' is in the surface-local
190          * coordinates
191          */
192         pixman_region32_init(&final_region);
193         if (surf_region) {
194                 pixman_region32_copy(&final_region, surf_region);
195
196                 /* Convert from surface to global coordinates */
197                 if (!ev->transform.enabled) {
198                         pixman_region32_translate(&final_region, ev->geometry.x, ev->geometry.y);
199                 } else {
200                         weston_view_to_global_float(ev, 0, 0, &view_x, &view_y);
201                         pixman_region32_translate(&final_region, (int)view_x, (int)view_y);
202                 }
203
204                 /* We need to paint the intersection */
205                 pixman_region32_intersect(&final_region, &final_region, region);
206         } else {
207                 /* If there is no surface region, just use the global region */
208                 pixman_region32_copy(&final_region, region);
209         }
210
211         /* Convert from global to output coord */
212         region_global_to_output(output, &final_region);
213
214         /* And clip to it */
215         pixman_image_set_clip_region32 (po->shadow_image, &final_region);
216
217         /* Set up the source transformation based on the surface
218            position, the output position/transform/scale and the client
219            specified buffer transform/scale */
220         pixman_transform_init_identity(&transform);
221         pixman_transform_scale(&transform, NULL,
222                                pixman_double_to_fixed ((double)1.0/output->current_scale),
223                                pixman_double_to_fixed ((double)1.0/output->current_scale));
224
225         fw = pixman_int_to_fixed(output->width);
226         fh = pixman_int_to_fixed(output->height);
227         switch (output->transform) {
228         default:
229         case WL_OUTPUT_TRANSFORM_NORMAL:
230         case WL_OUTPUT_TRANSFORM_FLIPPED:
231                 break;
232         case WL_OUTPUT_TRANSFORM_90:
233         case WL_OUTPUT_TRANSFORM_FLIPPED_90:
234                 pixman_transform_rotate(&transform, NULL, 0, -pixman_fixed_1);
235                 pixman_transform_translate(&transform, NULL, 0, fh);
236                 break;
237         case WL_OUTPUT_TRANSFORM_180:
238         case WL_OUTPUT_TRANSFORM_FLIPPED_180:
239                 pixman_transform_rotate(&transform, NULL, -pixman_fixed_1, 0);
240                 pixman_transform_translate(&transform, NULL, fw, fh);
241                 break;
242         case WL_OUTPUT_TRANSFORM_270:
243         case WL_OUTPUT_TRANSFORM_FLIPPED_270:
244                 pixman_transform_rotate(&transform, NULL, 0, pixman_fixed_1);
245                 pixman_transform_translate(&transform, NULL, fw, 0);
246                 break;
247         }
248
249         switch (output->transform) {
250         case WL_OUTPUT_TRANSFORM_FLIPPED:
251         case WL_OUTPUT_TRANSFORM_FLIPPED_90:
252         case WL_OUTPUT_TRANSFORM_FLIPPED_180:
253         case WL_OUTPUT_TRANSFORM_FLIPPED_270:
254                 pixman_transform_scale(&transform, NULL,
255                                        pixman_int_to_fixed (-1),
256                                        pixman_int_to_fixed (1));
257                 pixman_transform_translate(&transform, NULL, fw, 0);
258                 break;
259         }
260
261         pixman_transform_translate(&transform, NULL,
262                                    pixman_double_to_fixed (output->x),
263                                    pixman_double_to_fixed (output->y));
264
265         if (ev->transform.enabled) {
266                 /* Pixman supports only 2D transform matrix, but Weston uses 3D,
267                  * so we're omitting Z coordinate here
268                  */
269                 pixman_transform_t surface_transform = {{
270                                 { D2F(ev->transform.matrix.d[0]),
271                                   D2F(ev->transform.matrix.d[4]),
272                                   D2F(ev->transform.matrix.d[12]),
273                                 },
274                                 { D2F(ev->transform.matrix.d[1]),
275                                   D2F(ev->transform.matrix.d[5]),
276                                   D2F(ev->transform.matrix.d[13]),
277                                 },
278                                 { D2F(ev->transform.matrix.d[3]),
279                                   D2F(ev->transform.matrix.d[7]),
280                                   D2F(ev->transform.matrix.d[15]),
281                                 }
282                         }};
283
284                 pixman_transform_invert(&surface_transform, &surface_transform);
285                 pixman_transform_multiply (&transform, &surface_transform, &transform);
286         } else {
287                 pixman_transform_translate(&transform, NULL,
288                                            pixman_double_to_fixed ((double)-ev->geometry.x),
289                                            pixman_double_to_fixed ((double)-ev->geometry.y));
290         }
291
292         transform_apply_viewport(&transform, ev->surface);
293
294         fw = pixman_int_to_fixed(ev->surface->width_from_buffer);
295         fh = pixman_int_to_fixed(ev->surface->height_from_buffer);
296
297         switch (vp->buffer.transform) {
298         case WL_OUTPUT_TRANSFORM_FLIPPED:
299         case WL_OUTPUT_TRANSFORM_FLIPPED_90:
300         case WL_OUTPUT_TRANSFORM_FLIPPED_180:
301         case WL_OUTPUT_TRANSFORM_FLIPPED_270:
302                 pixman_transform_scale(&transform, NULL,
303                                        pixman_int_to_fixed (-1),
304                                        pixman_int_to_fixed (1));
305                 pixman_transform_translate(&transform, NULL, fw, 0);
306                 break;
307         }
308
309         switch (vp->buffer.transform) {
310         default:
311         case WL_OUTPUT_TRANSFORM_NORMAL:
312         case WL_OUTPUT_TRANSFORM_FLIPPED:
313                 break;
314         case WL_OUTPUT_TRANSFORM_90:
315         case WL_OUTPUT_TRANSFORM_FLIPPED_90:
316                 pixman_transform_rotate(&transform, NULL, 0, pixman_fixed_1);
317                 pixman_transform_translate(&transform, NULL, fh, 0);
318                 break;
319         case WL_OUTPUT_TRANSFORM_180:
320         case WL_OUTPUT_TRANSFORM_FLIPPED_180:
321                 pixman_transform_rotate(&transform, NULL, -pixman_fixed_1, 0);
322                 pixman_transform_translate(&transform, NULL, fw, fh);
323                 break;
324         case WL_OUTPUT_TRANSFORM_270:
325         case WL_OUTPUT_TRANSFORM_FLIPPED_270:
326                 pixman_transform_rotate(&transform, NULL, 0, -pixman_fixed_1);
327                 pixman_transform_translate(&transform, NULL, 0, fw);
328                 break;
329         }
330
331         pixman_transform_scale(&transform, NULL,
332                                pixman_double_to_fixed(vp->buffer.scale),
333                                pixman_double_to_fixed(vp->buffer.scale));
334
335         pixman_image_set_transform(ps->image, &transform);
336
337         if (ev->transform.enabled || output->current_scale != vp->buffer.scale)
338                 pixman_image_set_filter(ps->image, PIXMAN_FILTER_BILINEAR, NULL, 0);
339         else
340                 pixman_image_set_filter(ps->image, PIXMAN_FILTER_NEAREST, NULL, 0);
341
342         if (ps->buffer_ref.buffer)
343                 wl_shm_buffer_begin_access(ps->buffer_ref.buffer->shm_buffer);
344
345         if (ev->alpha < 1.0) {
346                 mask.alpha = 0xffff * ev->alpha;
347                 mask_image = pixman_image_create_solid_fill(&mask);
348         } else {
349                 mask_image = NULL;
350         }
351
352         pixman_image_composite32(pixman_op,
353                                  ps->image, /* src */
354                                  mask_image, /* mask */
355                                  po->shadow_image, /* dest */
356                                  0, 0, /* src_x, src_y */
357                                  0, 0, /* mask_x, mask_y */
358                                  0, 0, /* dest_x, dest_y */
359                                  pixman_image_get_width (po->shadow_image), /* width */
360                                  pixman_image_get_height (po->shadow_image) /* height */);
361
362         if (mask_image)
363                 pixman_image_unref(mask_image);
364
365         if (ps->buffer_ref.buffer)
366                 wl_shm_buffer_end_access(ps->buffer_ref.buffer->shm_buffer);
367
368         if (pr->repaint_debug)
369                 pixman_image_composite32(PIXMAN_OP_OVER,
370                                          pr->debug_color, /* src */
371                                          NULL /* mask */,
372                                          po->shadow_image, /* dest */
373                                          0, 0, /* src_x, src_y */
374                                          0, 0, /* mask_x, mask_y */
375                                          0, 0, /* dest_x, dest_y */
376                                          pixman_image_get_width (po->shadow_image), /* width */
377                                          pixman_image_get_height (po->shadow_image) /* height */);
378
379         pixman_image_set_clip_region32 (po->shadow_image, NULL);
380
381         pixman_region32_fini(&final_region);
382 }
383
384 static void
385 draw_view(struct weston_view *ev, struct weston_output *output,
386           pixman_region32_t *damage) /* in global coordinates */
387 {
388         static int zoom_logged = 0;
389         struct pixman_surface_state *ps = get_surface_state(ev->surface);
390         /* repaint bounding region in global coordinates: */
391         pixman_region32_t repaint;
392         /* non-opaque region in surface coordinates: */
393         pixman_region32_t surface_blend;
394
395         /* No buffer attached */
396         if (!ps->image)
397                 return;
398
399         pixman_region32_init(&repaint);
400         pixman_region32_intersect(&repaint,
401                                   &ev->transform.masked_boundingbox, damage);
402         pixman_region32_subtract(&repaint, &repaint, &ev->clip);
403
404         if (!pixman_region32_not_empty(&repaint))
405                 goto out;
406
407         if (output->zoom.active && !zoom_logged) {
408                 weston_log("pixman renderer does not support zoom\n");
409                 zoom_logged = 1;
410         }
411
412         /* TODO: Implement repaint_region_complex() using pixman_composite_trapezoids() */
413         if (ev->alpha != 1.0 ||
414             (ev->transform.enabled &&
415              ev->transform.matrix.type != WESTON_MATRIX_TRANSFORM_TRANSLATE)) {
416                 repaint_region(ev, output, &repaint, NULL, PIXMAN_OP_OVER);
417         } else {
418                 /* blended region is whole surface minus opaque region: */
419                 pixman_region32_init_rect(&surface_blend, 0, 0,
420                                           ev->surface->width, ev->surface->height);
421                 pixman_region32_subtract(&surface_blend, &surface_blend, &ev->surface->opaque);
422
423                 if (pixman_region32_not_empty(&ev->surface->opaque)) {
424                         repaint_region(ev, output, &repaint, &ev->surface->opaque, PIXMAN_OP_SRC);
425                 }
426
427                 if (pixman_region32_not_empty(&surface_blend)) {
428                         repaint_region(ev, output, &repaint, &surface_blend, PIXMAN_OP_OVER);
429                 }
430                 pixman_region32_fini(&surface_blend);
431         }
432
433
434 out:
435         pixman_region32_fini(&repaint);
436 }
437 static void
438 repaint_surfaces(struct weston_output *output, pixman_region32_t *damage)
439 {
440         struct weston_compositor *compositor = output->compositor;
441         struct weston_view *view;
442
443         wl_list_for_each_reverse(view, &compositor->view_list, link)
444                 if (view->plane == &compositor->primary_plane)
445                         draw_view(view, output, damage);
446 }
447
448 static void
449 copy_to_hw_buffer(struct weston_output *output, pixman_region32_t *region)
450 {
451         struct pixman_output_state *po = get_output_state(output);
452         pixman_region32_t output_region;
453
454         pixman_region32_init(&output_region);
455         pixman_region32_copy(&output_region, region);
456
457         region_global_to_output(output, &output_region);
458
459         pixman_image_set_clip_region32 (po->hw_buffer, &output_region);
460         pixman_region32_fini(&output_region);
461
462         pixman_image_composite32(PIXMAN_OP_SRC,
463                                  po->shadow_image, /* src */
464                                  NULL /* mask */,
465                                  po->hw_buffer, /* dest */
466                                  0, 0, /* src_x, src_y */
467                                  0, 0, /* mask_x, mask_y */
468                                  0, 0, /* dest_x, dest_y */
469                                  pixman_image_get_width (po->hw_buffer), /* width */
470                                  pixman_image_get_height (po->hw_buffer) /* height */);
471
472         pixman_image_set_clip_region32 (po->hw_buffer, NULL);
473 }
474
475 static void
476 pixman_renderer_repaint_output(struct weston_output *output,
477                              pixman_region32_t *output_damage)
478 {
479         struct pixman_output_state *po = get_output_state(output);
480
481         if (!po->hw_buffer)
482                 return;
483
484         repaint_surfaces(output, output_damage);
485         copy_to_hw_buffer(output, output_damage);
486
487         pixman_region32_copy(&output->previous_damage, output_damage);
488         wl_signal_emit(&output->frame_signal, output);
489
490         /* Actual flip should be done by caller */
491 }
492
493 static void
494 pixman_renderer_flush_damage(struct weston_surface *surface)
495 {
496         /* No-op for pixman renderer */
497 }
498
499 static void
500 buffer_state_handle_buffer_destroy(struct wl_listener *listener, void *data)
501 {
502         struct pixman_surface_state *ps;
503
504         ps = container_of(listener, struct pixman_surface_state,
505                           buffer_destroy_listener);
506
507         if (ps->image) {
508                 pixman_image_unref(ps->image);
509                 ps->image = NULL;
510         }
511
512         ps->buffer_destroy_listener.notify = NULL;
513 }
514
515 static void
516 pixman_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
517 {
518         struct pixman_surface_state *ps = get_surface_state(es);
519         struct wl_shm_buffer *shm_buffer;
520         pixman_format_code_t pixman_format;
521
522         weston_buffer_reference(&ps->buffer_ref, buffer);
523
524         if (ps->buffer_destroy_listener.notify) {
525                 wl_list_remove(&ps->buffer_destroy_listener.link);
526                 ps->buffer_destroy_listener.notify = NULL;
527         }
528
529         if (ps->image) {
530                 pixman_image_unref(ps->image);
531                 ps->image = NULL;
532         }
533
534         if (!buffer)
535                 return;
536         
537         shm_buffer = wl_shm_buffer_get(buffer->resource);
538
539         if (! shm_buffer) {
540                 weston_log("Pixman renderer supports only SHM buffers\n");
541                 weston_buffer_reference(&ps->buffer_ref, NULL);
542                 return;
543         }
544
545         switch (wl_shm_buffer_get_format(shm_buffer)) {
546         case WL_SHM_FORMAT_XRGB8888:
547                 pixman_format = PIXMAN_x8r8g8b8;
548                 break;
549         case WL_SHM_FORMAT_ARGB8888:
550                 pixman_format = PIXMAN_a8r8g8b8;
551                 break;
552         case WL_SHM_FORMAT_RGB565:
553                 pixman_format = PIXMAN_r5g6b5;
554                 break;
555         default:
556                 weston_log("Unsupported SHM buffer format\n");
557                 weston_buffer_reference(&ps->buffer_ref, NULL);
558                 return;
559         break;
560         }
561
562         buffer->shm_buffer = shm_buffer;
563         buffer->width = wl_shm_buffer_get_width(shm_buffer);
564         buffer->height = wl_shm_buffer_get_height(shm_buffer);
565
566         ps->image = pixman_image_create_bits(pixman_format,
567                 buffer->width, buffer->height,
568                 wl_shm_buffer_get_data(shm_buffer),
569                 wl_shm_buffer_get_stride(shm_buffer));
570
571         ps->buffer_destroy_listener.notify =
572                 buffer_state_handle_buffer_destroy;
573         wl_signal_add(&buffer->destroy_signal,
574                       &ps->buffer_destroy_listener);
575 }
576
577 static void
578 pixman_renderer_surface_state_destroy(struct pixman_surface_state *ps)
579 {
580         wl_list_remove(&ps->surface_destroy_listener.link);
581         wl_list_remove(&ps->renderer_destroy_listener.link);
582         if (ps->buffer_destroy_listener.notify) {
583                 wl_list_remove(&ps->buffer_destroy_listener.link);
584                 ps->buffer_destroy_listener.notify = NULL;
585         }
586
587         ps->surface->renderer_state = NULL;
588
589         if (ps->image) {
590                 pixman_image_unref(ps->image);
591                 ps->image = NULL;
592         }
593         weston_buffer_reference(&ps->buffer_ref, NULL);
594         free(ps);
595 }
596
597 static void
598 surface_state_handle_surface_destroy(struct wl_listener *listener, void *data)
599 {
600         struct pixman_surface_state *ps;
601
602         ps = container_of(listener, struct pixman_surface_state,
603                           surface_destroy_listener);
604
605         pixman_renderer_surface_state_destroy(ps);
606 }
607
608 static void
609 surface_state_handle_renderer_destroy(struct wl_listener *listener, void *data)
610 {
611         struct pixman_surface_state *ps;
612
613         ps = container_of(listener, struct pixman_surface_state,
614                           renderer_destroy_listener);
615
616         pixman_renderer_surface_state_destroy(ps);
617 }
618
619 static int
620 pixman_renderer_create_surface(struct weston_surface *surface)
621 {
622         struct pixman_surface_state *ps;
623         struct pixman_renderer *pr = get_renderer(surface->compositor);
624
625         ps = calloc(1, sizeof *ps);
626         if (!ps)
627                 return -1;
628
629         surface->renderer_state = ps;
630
631         ps->surface = surface;
632
633         ps->surface_destroy_listener.notify =
634                 surface_state_handle_surface_destroy;
635         wl_signal_add(&surface->destroy_signal,
636                       &ps->surface_destroy_listener);
637
638         ps->renderer_destroy_listener.notify =
639                 surface_state_handle_renderer_destroy;
640         wl_signal_add(&pr->destroy_signal,
641                       &ps->renderer_destroy_listener);
642
643         return 0;
644 }
645
646 static void
647 pixman_renderer_surface_set_color(struct weston_surface *es,
648                  float red, float green, float blue, float alpha)
649 {
650         struct pixman_surface_state *ps = get_surface_state(es);
651         pixman_color_t color;
652
653         color.red = red * 0xffff;
654         color.green = green * 0xffff;
655         color.blue = blue * 0xffff;
656         color.alpha = alpha * 0xffff;
657         
658         if (ps->image) {
659                 pixman_image_unref(ps->image);
660                 ps->image = NULL;
661         }
662
663         ps->image = pixman_image_create_solid_fill(&color);
664 }
665
666 static void
667 pixman_renderer_destroy(struct weston_compositor *ec)
668 {
669         struct pixman_renderer *pr = get_renderer(ec);
670
671         wl_signal_emit(&pr->destroy_signal, pr);
672         weston_binding_destroy(pr->debug_binding);
673         free(pr);
674
675         ec->renderer = NULL;
676 }
677
678 static void
679 debug_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
680               void *data)
681 {
682         struct weston_compositor *ec = data;
683         struct pixman_renderer *pr = (struct pixman_renderer *) ec->renderer;
684
685         pr->repaint_debug ^= 1;
686
687         if (pr->repaint_debug) {
688                 pixman_color_t red = {
689                         0x3fff, 0x0000, 0x0000, 0x3fff
690                 };
691
692                 pr->debug_color = pixman_image_create_solid_fill(&red);
693         } else {
694                 pixman_image_unref(pr->debug_color);
695                 weston_compositor_damage_all(ec);
696         }
697 }
698
699 WL_EXPORT int
700 pixman_renderer_init(struct weston_compositor *ec)
701 {
702         struct pixman_renderer *renderer;
703
704         renderer = calloc(1, sizeof *renderer);
705         if (renderer == NULL)
706                 return -1;
707
708         renderer->repaint_debug = 0;
709         renderer->debug_color = NULL;
710         renderer->base.read_pixels = pixman_renderer_read_pixels;
711         renderer->base.repaint_output = pixman_renderer_repaint_output;
712         renderer->base.flush_damage = pixman_renderer_flush_damage;
713         renderer->base.attach = pixman_renderer_attach;
714         renderer->base.surface_set_color = pixman_renderer_surface_set_color;
715         renderer->base.destroy = pixman_renderer_destroy;
716         ec->renderer = &renderer->base;
717         ec->capabilities |= WESTON_CAP_ROTATION_ANY;
718         ec->capabilities |= WESTON_CAP_CAPTURE_YFLIP;
719
720         renderer->debug_binding =
721                 weston_compositor_add_debug_binding(ec, KEY_R,
722                                                     debug_binding, ec);
723
724         wl_display_add_shm_format(ec->wl_display, WL_SHM_FORMAT_RGB565);
725
726         wl_signal_init(&renderer->destroy_signal);
727
728         return 0;
729 }
730
731 WL_EXPORT void
732 pixman_renderer_output_set_buffer(struct weston_output *output, pixman_image_t *buffer)
733 {
734         struct pixman_output_state *po = get_output_state(output);
735
736         if (po->hw_buffer)
737                 pixman_image_unref(po->hw_buffer);
738         po->hw_buffer = buffer;
739
740         if (po->hw_buffer) {
741                 output->compositor->read_format = pixman_image_get_format(po->hw_buffer);
742                 pixman_image_ref(po->hw_buffer);
743         }
744 }
745
746 WL_EXPORT int
747 pixman_renderer_output_create(struct weston_output *output)
748 {
749         struct pixman_output_state *po = calloc(1, sizeof *po);
750         int w, h;
751
752         if (!po)
753                 return -1;
754
755         /* set shadow image transformation */
756         w = output->current_mode->width;
757         h = output->current_mode->height;
758
759         po->shadow_buffer = malloc(w * h * 4);
760
761         if (!po->shadow_buffer) {
762                 free(po);
763                 return -1;
764         }
765
766         po->shadow_image =
767                 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
768                                          po->shadow_buffer, w * 4);
769
770         if (!po->shadow_image) {
771                 free(po->shadow_buffer);
772                 free(po);
773                 return -1;
774         }
775
776         output->renderer_state = po;
777
778         return 0;
779 }
780
781 WL_EXPORT void
782 pixman_renderer_output_destroy(struct weston_output *output)
783 {
784         struct pixman_output_state *po = get_output_state(output);
785
786         pixman_image_unref(po->shadow_image);
787
788         if (po->hw_buffer)
789                 pixman_image_unref(po->hw_buffer);
790
791         free(po->shadow_buffer);
792
793         po->shadow_buffer = NULL;
794         po->shadow_image = NULL;
795         po->hw_buffer = NULL;
796
797         free(po);
798 }