1940db7105c40090bd181d8bab9097977e3dccac
[profile/ivi/weston-ivi-shell.git] / src / rpi-renderer.c
1 /*
2  * Copyright © 2012-2013 Raspberry Pi Foundation
3  *
4  * Permission to use, copy, modify, distribute, and sell this software and
5  * its documentation for any purpose is hereby granted without fee, provided
6  * that the above copyright notice appear in all copies and that both that
7  * copyright notice and this permission notice appear in supporting
8  * documentation, and that the name of the copyright holders not be used in
9  * advertising or publicity pertaining to distribution of the software
10  * without specific, written prior permission.  The copyright holders make
11  * no representations about the suitability of this software for any
12  * purpose.  It is provided "as is" without express or implied warranty.
13  *
14  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
15  * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
16  * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
17  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
18  * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
19  * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
20  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21  */
22
23 #include "config.h"
24
25 #include <stdlib.h>
26 #include <assert.h>
27 #include <string.h>
28
29 #ifdef HAVE_BCM_HOST
30 #  include <bcm_host.h>
31 #else
32 #  include "rpi-bcm-stubs.h"
33 #endif
34
35 #include "compositor.h"
36 #include "rpi-renderer.h"
37
38 #ifdef ENABLE_EGL
39 #include <EGL/egl.h>
40 #include <EGL/eglext.h>
41 #include "weston-egl-ext.h"
42 #endif
43
44 /*
45  * Dispmanx API offers alpha-blended overlays for hardware compositing.
46  * The final composite consists of dispmanx elements, and their contents:
47  * the dispmanx resource assigned to the element. The elements may be
48  * scanned out directly, or composited to a temporary surface, depending on
49  * how the firmware decides to handle the scene. Updates to multiple elements
50  * may be queued in a single dispmanx update object, resulting in atomic and
51  * vblank synchronized display updates.
52  *
53  * To avoid tearing and display artifacts, the current dispmanx resource in a
54  * dispmanx element must not be touched. Therefore each element must be
55  * double-buffered, using two resources, the front and the back. While a
56  * dispmanx update is running, the both resources must be considered in use.
57  *
58  * A resource may be destroyed only, when the update removing the element has
59  * completed. Otherwise you risk showing an incomplete composition.
60  */
61
62 #ifndef ELEMENT_CHANGE_LAYER
63 /* copied from interface/vmcs_host/vc_vchi_dispmanx.h of userland.git */
64 #define ELEMENT_CHANGE_LAYER          (1<<0)
65 #define ELEMENT_CHANGE_OPACITY        (1<<1)
66 #define ELEMENT_CHANGE_DEST_RECT      (1<<2)
67 #define ELEMENT_CHANGE_SRC_RECT       (1<<3)
68 #define ELEMENT_CHANGE_MASK_RESOURCE  (1<<4)
69 #define ELEMENT_CHANGE_TRANSFORM      (1<<5)
70 #endif
71
72 #if 0
73 #define DBG(...) \
74         weston_log(__VA_ARGS__)
75 #else
76 #define DBG(...) do {} while (0)
77 #endif
78
79 /* If we had a fully featured vc_dispmanx_resource_write_data()... */
80 /*#define HAVE_RESOURCE_WRITE_DATA_RECT 1*/
81
82 struct rpi_resource {
83         DISPMANX_RESOURCE_HANDLE_T handle;
84         int width;
85         int height; /* height of the image (valid pixel data) */
86         int stride; /* bytes */
87         int buffer_height; /* height of the buffer */
88         VC_IMAGE_TYPE_T ifmt;
89 };
90
91 struct rpir_output;
92
93 struct rpir_egl_buffer {
94         struct weston_buffer_reference buffer_ref;
95         DISPMANX_RESOURCE_HANDLE_T resource_handle;
96 };
97
98 enum buffer_type {
99         BUFFER_TYPE_NULL,
100         BUFFER_TYPE_SHM,
101         BUFFER_TYPE_EGL
102 };
103
104 struct rpir_surface {
105         struct weston_surface *surface;
106
107         struct wl_list views;
108         int visible_views;
109         int need_swap;
110         int single_buffer;
111
112         struct rpi_resource resources[2];
113         struct rpi_resource *front;
114         struct rpi_resource *back;
115         pixman_region32_t prev_damage;
116
117         struct rpir_egl_buffer *egl_front;
118         struct rpir_egl_buffer *egl_back;
119         struct rpir_egl_buffer *egl_old_front;
120
121         struct weston_buffer_reference buffer_ref;
122         enum buffer_type buffer_type;
123
124         struct wl_listener surface_destroy_listener;
125 };
126
127 struct rpir_view {
128         struct rpir_surface *surface;
129         struct wl_list surface_link;
130         struct weston_view *view;
131
132         /* If link is empty, the view is guaranteed to not be on screen,
133          * i.e. updates removing Elements have completed.
134          */
135         struct wl_list link;
136
137         DISPMANX_ELEMENT_HANDLE_T handle;
138         int layer;
139
140         struct wl_listener view_destroy_listener;
141 };
142
143 struct rpir_output {
144         DISPMANX_DISPLAY_HANDLE_T display;
145
146         DISPMANX_UPDATE_HANDLE_T update;
147         struct weston_matrix matrix;
148
149         /* all Elements currently on screen */
150         struct wl_list view_list; /* struct rpir_surface::link */
151
152         /* Elements just removed, waiting for update completion */
153         struct wl_list view_cleanup_list; /* struct rpir_surface::link */
154
155         struct rpi_resource capture_buffer;
156         uint8_t *capture_data;
157 };
158
159 struct rpi_renderer {
160         struct weston_renderer base;
161
162         int single_buffer;
163
164 #ifdef ENABLE_EGL
165         EGLDisplay egl_display;
166
167         PFNEGLBINDWAYLANDDISPLAYWL bind_display;
168         PFNEGLUNBINDWAYLANDDISPLAYWL unbind_display;
169         PFNEGLQUERYWAYLANDBUFFERWL query_buffer;
170 #endif
171         int has_bind_display;
172 };
173
174 static int
175 rpi_renderer_create_surface(struct weston_surface *base);
176
177 static int
178 rpi_renderer_create_view(struct weston_view *base);
179
180 static void
181 rpir_view_handle_view_destroy(struct wl_listener *listener, void *data);
182
183 static inline struct rpir_surface *
184 to_rpir_surface(struct weston_surface *surface)
185 {
186         if (!surface->renderer_state)
187                 rpi_renderer_create_surface(surface);
188
189         return surface->renderer_state;
190 }
191
192 static inline struct rpir_view *
193 to_rpir_view(struct weston_view *view)
194 {
195         if (!view->renderer_state)
196                 rpi_renderer_create_view(view);
197
198         return view->renderer_state;
199 }
200
201 static inline struct rpir_output *
202 to_rpir_output(struct weston_output *output)
203 {
204         return output->renderer_state;
205 }
206
207 static inline struct rpi_renderer *
208 to_rpi_renderer(struct weston_compositor *compositor)
209 {
210         return container_of(compositor->renderer, struct rpi_renderer, base);
211 }
212
213 static inline int
214 int_max(int a, int b)
215 {
216         return a > b ? a : b;
217 }
218
219 static inline void
220 int_swap(int *a, int *b)
221 {
222         int tmp = *a;
223         *a = *b;
224         *b = tmp;
225 }
226
227 static uint8_t
228 float2uint8(float f)
229 {
230         int v = roundf(f * 255.0f);
231
232         return v < 0 ? 0 : (v > 255 ? 255 : v);
233 }
234
235 static void
236 rpi_resource_init(struct rpi_resource *resource)
237 {
238         resource->handle = DISPMANX_NO_HANDLE;
239 }
240
241 static void
242 rpi_resource_release(struct rpi_resource *resource)
243 {
244         if (resource->handle == DISPMANX_NO_HANDLE)
245                 return;
246
247         vc_dispmanx_resource_delete(resource->handle);
248         DBG("resource %p release\n", resource);
249         resource->handle = DISPMANX_NO_HANDLE;
250 }
251
252 static int
253 rpi_resource_realloc(struct rpi_resource *resource, VC_IMAGE_TYPE_T ifmt,
254                      int width, int height, int stride, int buffer_height)
255 {
256         uint32_t dummy;
257
258         if (resource->handle != DISPMANX_NO_HANDLE &&
259             resource->width == width &&
260             resource->height == height &&
261             resource->stride == stride &&
262             resource->buffer_height == buffer_height &&
263             resource->ifmt == ifmt)
264                 return 0;
265
266         rpi_resource_release(resource);
267
268         /* NOTE: if stride is not a multiple of 16 pixels in bytes,
269          * the vc_image_* functions may break. Dispmanx elements
270          * should be fine, though. Buffer_height probably has similar
271          * constraints, too.
272          */
273         resource->handle =
274                 vc_dispmanx_resource_create(ifmt,
275                                             width | (stride << 16),
276                                             height | (buffer_height << 16),
277                                             &dummy);
278         if (resource->handle == DISPMANX_NO_HANDLE)
279                 return -1;
280
281         resource->width = width;
282         resource->height = height;
283         resource->stride = stride;
284         resource->buffer_height = buffer_height;
285         resource->ifmt = ifmt;
286         DBG("resource %p alloc\n", resource);
287         return 1;
288 }
289
290 /* A firmware workaround for broken ALPHA_PREMULT + ALPHA_MIX hardware. */
291 #define PREMULT_ALPHA_FLAG (1 << 31)
292
293 static VC_IMAGE_TYPE_T
294 shm_buffer_get_vc_format(struct wl_shm_buffer *buffer)
295 {
296         switch (wl_shm_buffer_get_format(buffer)) {
297         case WL_SHM_FORMAT_XRGB8888:
298                 return VC_IMAGE_XRGB8888;
299         case WL_SHM_FORMAT_ARGB8888:
300                 return VC_IMAGE_ARGB8888 | PREMULT_ALPHA_FLAG;
301         case WL_SHM_FORMAT_RGB565:
302                 return VC_IMAGE_RGB565;
303         default:
304                 /* invalid format */
305                 return VC_IMAGE_MIN;
306         }
307 }
308
309 static int
310 rpi_resource_update(struct rpi_resource *resource, struct weston_buffer *buffer,
311                     pixman_region32_t *region)
312 {
313         pixman_region32_t write_region;
314         pixman_box32_t *r;
315         VC_RECT_T rect;
316         VC_IMAGE_TYPE_T ifmt;
317         uint32_t *pixels;
318         int width;
319         int height;
320         int stride;
321         int ret;
322 #ifdef HAVE_RESOURCE_WRITE_DATA_RECT
323         int n;
324 #endif
325
326         if (!buffer)
327                 return -1;
328
329         ifmt = shm_buffer_get_vc_format(buffer->shm_buffer);
330         width = wl_shm_buffer_get_width(buffer->shm_buffer);
331         height = wl_shm_buffer_get_height(buffer->shm_buffer);
332         stride = wl_shm_buffer_get_stride(buffer->shm_buffer);
333         pixels = wl_shm_buffer_get_data(buffer->shm_buffer);
334
335         ret = rpi_resource_realloc(resource, ifmt & ~PREMULT_ALPHA_FLAG,
336                                    width, height, stride, height);
337         if (ret < 0)
338                 return -1;
339
340         pixman_region32_init_rect(&write_region, 0, 0, width, height);
341         if (ret == 0)
342                 pixman_region32_intersect(&write_region,
343                                           &write_region, region);
344
345         wl_shm_buffer_begin_access(buffer->shm_buffer);
346
347 #ifdef HAVE_RESOURCE_WRITE_DATA_RECT
348         /* XXX: Can this do a format conversion, so that scanout does not have to? */
349         r = pixman_region32_rectangles(&write_region, &n);
350         while (n--) {
351                 vc_dispmanx_rect_set(&rect, r[n].x1, r[n].y1,
352                                      r[n].x2 - r[n].x1, r[n].y2 - r[n].y1);
353
354                 ret = vc_dispmanx_resource_write_data_rect(resource->handle,
355                                                            ifmt, stride,
356                                                            pixels, &rect,
357                                                            rect.x, rect.y);
358                 DBG("%s: %p %ux%u@%u,%u, ret %d\n", __func__, resource,
359                     rect.width, rect.height, rect.x, rect.y, ret);
360                 if (ret)
361                         break;
362         }
363 #else
364         /* vc_dispmanx_resource_write_data() ignores ifmt,
365          * rect.x, rect.width, and uses stride only for computing
366          * the size of the transfer as rect.height * stride.
367          * Therefore we can only write rows starting at x=0.
368          * To be able to write more than one scanline at a time,
369          * the resource must have been created with the same stride
370          * as used here, and we must write full scanlines.
371          */
372
373         r = pixman_region32_extents(&write_region);
374         vc_dispmanx_rect_set(&rect, 0, r->y1, width, r->y2 - r->y1);
375         ret = vc_dispmanx_resource_write_data(resource->handle,
376                                               ifmt, stride, pixels, &rect);
377         DBG("%s: %p %ux%u@%u,%u, ret %d\n", __func__, resource,
378             width, r->y2 - r->y1, 0, r->y1, ret);
379 #endif
380
381         wl_shm_buffer_end_access(buffer->shm_buffer);
382
383         pixman_region32_fini(&write_region);
384
385         return ret ? -1 : 0;
386 }
387
388 static void
389 rpir_egl_buffer_destroy(struct rpir_egl_buffer *egl_buffer)
390 {
391         struct weston_buffer *buffer;
392
393         if (egl_buffer == NULL)
394                 return;
395
396         buffer = egl_buffer->buffer_ref.buffer;
397         if (buffer == NULL) {
398                 /* The client has already destroyed the wl_buffer, the
399                  * compositor has the responsibility to delete the resource.
400                  */
401                 vc_dispmanx_resource_delete(egl_buffer->resource_handle);
402         } else {
403                 vc_dispmanx_set_wl_buffer_in_use(buffer->resource, 0);
404                 weston_buffer_reference(&egl_buffer->buffer_ref, NULL);
405         }
406
407         free(egl_buffer);
408 }
409
410 static struct rpir_surface *
411 rpir_surface_create(struct rpi_renderer *renderer)
412 {
413         struct rpir_surface *surface;
414
415         surface = calloc(1, sizeof *surface);
416         if (!surface)
417                 return NULL;
418
419         wl_list_init(&surface->views);
420         surface->visible_views = 0;
421         surface->single_buffer = renderer->single_buffer;
422         rpi_resource_init(&surface->resources[0]);
423         rpi_resource_init(&surface->resources[1]);
424         surface->front = &surface->resources[0];
425         if (surface->single_buffer)
426                 surface->back = &surface->resources[0];
427         else
428                 surface->back = &surface->resources[1];
429         surface->buffer_type = BUFFER_TYPE_NULL;
430
431         pixman_region32_init(&surface->prev_damage);
432
433         return surface;
434 }
435
436 static void
437 rpir_surface_destroy(struct rpir_surface *surface)
438 {
439         if (surface->visible_views)
440                 weston_log("ERROR rpi: destroying on-screen element\n");
441
442         assert(wl_list_empty(&surface->views));
443
444         if (surface->surface)
445                 surface->surface->renderer_state = NULL;
446
447         pixman_region32_fini(&surface->prev_damage);
448         rpi_resource_release(&surface->resources[0]);
449         rpi_resource_release(&surface->resources[1]);
450         DBG("rpir_surface %p destroyed (%u)\n", surface, surface->visible_views);
451
452         rpir_egl_buffer_destroy(surface->egl_back);
453         rpir_egl_buffer_destroy(surface->egl_front);
454         rpir_egl_buffer_destroy(surface->egl_old_front);
455
456         free(surface);
457 }
458
459 static int
460 rpir_surface_damage(struct rpir_surface *surface, struct weston_buffer *buffer,
461                     pixman_region32_t *damage)
462 {
463         pixman_region32_t upload;
464         int ret;
465
466         if (!pixman_region32_not_empty(damage))
467                 return 0;
468
469         DBG("rpir_surface %p update resource %p\n", surface, surface->back);
470
471         /* XXX: todo: if no surface->handle, update front buffer directly
472          * to avoid creating a new back buffer */
473         if (surface->single_buffer) {
474                 ret = rpi_resource_update(surface->front, buffer, damage);
475         } else {
476                 pixman_region32_init(&upload);
477                 pixman_region32_union(&upload, &surface->prev_damage, damage);
478                 ret = rpi_resource_update(surface->back, buffer, &upload);
479                 pixman_region32_fini(&upload);
480         }
481
482         pixman_region32_copy(&surface->prev_damage, damage);
483         surface->need_swap = 1;
484
485         return ret;
486 }
487
488 static struct rpir_view *
489 rpir_view_create(struct rpir_surface *surface)
490 {
491         struct rpir_view *view;
492
493         view = calloc(1, sizeof *view);
494         if (!view)
495                 return NULL;
496
497         view->surface = surface;
498         wl_list_insert(&surface->views, &view->surface_link);
499
500         wl_list_init(&view->link);
501         view->handle = DISPMANX_NO_HANDLE;
502
503         return view;
504 }
505
506 static void
507 rpir_view_destroy(struct rpir_view *view)
508 {
509         wl_list_remove(&view->link);
510
511         if (view->handle != DISPMANX_NO_HANDLE) {
512                 view->surface->visible_views--;
513                 weston_log("ERROR rpi: destroying on-screen element\n");
514         }
515
516         if (view->view)
517                 view->view->renderer_state = NULL;
518
519         wl_list_remove(&view->surface_link);
520         if (wl_list_empty(&view->surface->views) && view->surface->surface == NULL)
521                 rpir_surface_destroy(view->surface);
522
523         DBG("rpir_view %p destroyed (%d)\n", view, view->handle);
524
525         free(view);
526 }
527
528 static void
529 matrix_type_str(struct weston_matrix *matrix, char *buf, int len)
530 {
531         static const char types[33] = "TSRO";
532         unsigned mask = matrix->type;
533         int i = 0;
534
535         while (mask && i < len - 1) {
536                 if (mask & (1u << i))
537                         *buf++ = types[i];
538                 mask &= ~(1u << i);
539                 i++;
540         }
541         *buf = '\0';
542 }
543
544 static void
545 log_print_matrix(struct weston_matrix *matrix)
546 {
547         char typestr[6];
548         float *d = matrix->d;
549
550         matrix_type_str(matrix, typestr, sizeof typestr);
551         weston_log_continue("%14.6e %14.6e %14.6e %14.6e\n",
552                             d[0], d[4], d[8], d[12]);
553         weston_log_continue("%14.6e %14.6e %14.6e %14.6e\n",
554                             d[1], d[5], d[9], d[13]);
555         weston_log_continue("%14.6e %14.6e %14.6e %14.6e\n",
556                             d[2], d[6], d[10], d[14]);
557         weston_log_continue("%14.6e %14.6e %14.6e %14.6e type: %s\n",
558                             d[3], d[7], d[11], d[15], typestr);
559 }
560
561 static void
562 warn_bad_matrix(struct weston_matrix *total, struct weston_matrix *output,
563                 struct weston_matrix *surface)
564 {
565         static int n_warn;
566         char typestr[6];
567
568         if (n_warn++ == 10)
569                 weston_log("%s: not showing more warnings\n", __func__);
570
571         if (n_warn > 10)
572                 return;
573
574         weston_log("%s: warning: total transformation is not renderable:\n",
575                    __func__);
576         log_print_matrix(total);
577
578         matrix_type_str(surface, typestr, sizeof typestr);
579         weston_log_continue("surface matrix type: %s\n", typestr);
580         matrix_type_str(output, typestr, sizeof typestr);
581         weston_log_continue("output matrix type: %s\n", typestr);
582 }
583
584 /*#define SURFACE_TRANSFORM */
585
586 static int
587 rpir_view_compute_rects(struct rpir_view *view,
588                         VC_RECT_T *src_rect, VC_RECT_T *dst_rect,
589                         VC_IMAGE_TRANSFORM_T *flipmask)
590 {
591         struct weston_output *output_base = view->view->surface->output;
592         struct rpir_output *output = to_rpir_output(output_base);
593         struct weston_matrix matrix = view->view->transform.matrix;
594         VC_IMAGE_TRANSFORM_T flipt = 0;
595         int src_x, src_y;
596         int dst_x, dst_y;
597         int src_width, src_height;
598         int dst_width, dst_height;
599         struct weston_vector p1 = {{ 0.0f, 0.0f, 0.0f, 1.0f }};
600         struct weston_vector p2 = {{ 0.0f, 0.0f, 0.0f, 1.0f }};
601         int t;
602         int over;
603
604         /* XXX: take buffer transform into account */
605
606         /* src is in 16.16, dst is in 32.0 fixed point.
607          * Negative values are not allowed in VC_RECT_T.
608          * Clip size to output boundaries, firmware ignores
609          * huge elements like 8192x8192.
610          */
611
612         src_x = 0 << 16;
613         src_y = 0 << 16;
614
615         if (view->surface->buffer_type == BUFFER_TYPE_EGL) {
616                 struct weston_buffer *buffer =
617                         view->surface->egl_front->buffer_ref.buffer;
618
619                 src_width = buffer->width << 16;
620                 src_height = buffer->height << 16;
621         } else {
622                 src_width = view->surface->front->width << 16;
623                 src_height = view->surface->front->height << 16;
624         }
625
626         weston_matrix_multiply(&matrix, &output->matrix);
627
628 #ifdef SURFACE_TRANSFORM
629         if (matrix.type >= WESTON_MATRIX_TRANSFORM_OTHER) {
630 #else
631         if (matrix.type >= WESTON_MATRIX_TRANSFORM_ROTATE) {
632 #endif
633                 warn_bad_matrix(&matrix, &output->matrix,
634                                 &view->view->transform.matrix);
635         } else {
636                 if (matrix.type & WESTON_MATRIX_TRANSFORM_ROTATE) {
637                         if (fabsf(matrix.d[0]) < 1e-4f &&
638                             fabsf(matrix.d[5]) < 1e-4f) {
639                                 flipt |= TRANSFORM_TRANSPOSE;
640                         } else if (fabsf(matrix.d[1]) < 1e-4 &&
641                                    fabsf(matrix.d[4]) < 1e-4) {
642                                 /* no transpose */
643                         } else {
644                                 warn_bad_matrix(&matrix, &output->matrix,
645                                         &view->view->transform.matrix);
646                         }
647                 }
648         }
649
650         p2.f[0] = view->view->geometry.width;
651         p2.f[1] = view->view->geometry.height;
652
653         /* transform top-left and bot-right corner into screen coordinates */
654         weston_matrix_transform(&matrix, &p1);
655         weston_matrix_transform(&matrix, &p2);
656
657         /* Compute the destination rectangle on screen, converting
658          * negative dimensions to flips.
659          */
660
661         dst_width = round(p2.f[0] - p1.f[0]);
662         if (dst_width < 0) {
663                 dst_x = round(p2.f[0]);
664                 dst_width = -dst_width;
665
666                 if (!(flipt & TRANSFORM_TRANSPOSE))
667                         flipt |= TRANSFORM_HFLIP;
668                 else
669                         flipt |= TRANSFORM_VFLIP;
670         } else {
671                 dst_x = round(p1.f[0]);
672         }
673
674         dst_height = round(p2.f[1] - p1.f[1]);
675         if (dst_height < 0) {
676                 dst_y = round(p2.f[1]);
677                 dst_height = -dst_height;
678
679                 if (!(flipt & TRANSFORM_TRANSPOSE))
680                         flipt |= TRANSFORM_VFLIP;
681                 else
682                         flipt |= TRANSFORM_HFLIP;
683         } else {
684                 dst_y = round(p1.f[1]);
685         }
686
687         if (dst_width == 0 || dst_height == 0) {
688                 DBG("ignored, zero surface area before clipping\n");
689                 return -1;
690         }
691
692 #ifdef SURFACE_TRANSFORM
693         /* Dispmanx works as if you flipped the whole screen, when
694          * you flip an element. But, we want to flip an element in place.
695          * XXX: fixme
696          */
697         if (flipt & TRANSFORM_HFLIP)
698                 dst_x = output_base->width - dst_x;
699         if (flipt & TRANSFORM_VFLIP)
700                 dst_y = output_base->height - dst_y;
701         if (flipt & TRANSFORM_TRANSPOSE) {
702                 int_swap(&dst_x, &dst_y);
703                 int_swap(&dst_width, &dst_height);
704         }
705 #else
706         switch (output_base->transform) {
707         case WL_OUTPUT_TRANSFORM_FLIPPED:
708                 flipt = TRANSFORM_HFLIP;
709                 break;
710         case WL_OUTPUT_TRANSFORM_NORMAL:
711                 flipt = 0;
712                 break;
713
714         case WL_OUTPUT_TRANSFORM_FLIPPED_90:
715                 flipt = TRANSFORM_HFLIP | TRANSFORM_VFLIP | TRANSFORM_TRANSPOSE;
716                 break;
717         case WL_OUTPUT_TRANSFORM_90:
718                 flipt = TRANSFORM_VFLIP | TRANSFORM_TRANSPOSE;
719                 break;
720         case WL_OUTPUT_TRANSFORM_FLIPPED_180:
721                 flipt = TRANSFORM_VFLIP;
722                 break;
723         case WL_OUTPUT_TRANSFORM_180:
724                 flipt = TRANSFORM_HFLIP | TRANSFORM_VFLIP;
725                 break;
726
727         case WL_OUTPUT_TRANSFORM_FLIPPED_270:
728                 flipt = TRANSFORM_TRANSPOSE;
729                 break;
730         case WL_OUTPUT_TRANSFORM_270:
731                 flipt = TRANSFORM_HFLIP | TRANSFORM_TRANSPOSE;
732                 break;
733         default:
734                 break;
735         }
736 #endif
737
738         /* clip destination rectangle to screen dimensions */
739
740         if (dst_x < 0) {
741                 t = (int64_t)dst_x * src_width / dst_width;
742                 src_width += t;
743                 dst_width += dst_x;
744                 src_x -= t;
745                 dst_x = 0;
746         }
747
748         if (dst_y < 0) {
749                 t = (int64_t)dst_y * src_height / dst_height;
750                 src_height += t;
751                 dst_height += dst_y;
752                 src_y -= t;
753                 dst_y = 0;
754         }
755
756         over = dst_x + dst_width - output_base->width;
757         if (over > 0) {
758                 t = (int64_t)over * src_width / dst_width;
759                 src_width -= t;
760                 dst_width -= over;
761         }
762
763         over = dst_y + dst_height - output_base->height;
764         if (over > 0) {
765                 t = (int64_t)over * src_height / dst_height;
766                 src_height -= t;
767                 dst_height -= over;
768         }
769
770         src_width = int_max(src_width, 0);
771         src_height = int_max(src_height, 0);
772
773         DBG("rpir_view %p %dx%d: p1 %f, %f; p2 %f, %f\n", view,
774             view->view->geometry.width,
775             view->view->geometry.height,
776             p1.f[0], p1.f[1], p2.f[0], p2.f[1]);
777         DBG("src rect %d;%d, %d;%d, %d;%dx%d;%d\n",
778             src_x >> 16, src_x & 0xffff,
779             src_y >> 16, src_y & 0xffff,
780             src_width >> 16, src_width & 0xffff,
781             src_height >> 16, src_height & 0xffff);
782         DBG("dest rect %d, %d, %dx%d%s%s%s\n",
783             dst_x, dst_y, dst_width, dst_height,
784             (flipt & TRANSFORM_HFLIP) ? " hflip" : "",
785             (flipt & TRANSFORM_VFLIP) ? " vflip" : "",
786             (flipt & TRANSFORM_TRANSPOSE) ? " transp" : "");
787
788         assert(src_x >= 0);
789         assert(src_y >= 0);
790         assert(dst_x >= 0);
791         assert(dst_y >= 0);
792
793         if (dst_width < 1 || dst_height < 1) {
794                 DBG("ignored, zero surface area after clipping\n");
795                 return -1;
796         }
797
798         /* EGL buffers will be upside-down related to what DispmanX expects */
799         if (view->surface->buffer_type == BUFFER_TYPE_EGL)
800                 flipt ^= TRANSFORM_VFLIP;
801
802         vc_dispmanx_rect_set(src_rect, src_x, src_y, src_width, src_height);
803         vc_dispmanx_rect_set(dst_rect, dst_x, dst_y, dst_width, dst_height);
804         *flipmask = flipt;
805
806         return 0;
807 }
808
809 static DISPMANX_TRANSFORM_T
810 vc_image2dispmanx_transform(VC_IMAGE_TRANSFORM_T t)
811 {
812         /* XXX: uhh, are these right? */
813         switch (t) {
814         case VC_IMAGE_ROT0:
815                 return DISPMANX_NO_ROTATE;
816         case VC_IMAGE_MIRROR_ROT0:
817                 return DISPMANX_FLIP_HRIZ;
818         case VC_IMAGE_MIRROR_ROT180:
819                 return DISPMANX_FLIP_VERT;
820         case VC_IMAGE_ROT180:
821                 return DISPMANX_ROTATE_180;
822         case VC_IMAGE_MIRROR_ROT90:
823                 return DISPMANX_ROTATE_90 | DISPMANX_FLIP_HRIZ;
824         case VC_IMAGE_ROT270:
825                 return DISPMANX_ROTATE_270;
826         case VC_IMAGE_ROT90:
827                 return DISPMANX_ROTATE_90;
828         case VC_IMAGE_MIRROR_ROT270:
829                 return DISPMANX_ROTATE_270 | DISPMANX_FLIP_VERT;
830         default:
831                 assert(0 && "bad VC_IMAGE_TRANSFORM_T");
832                 return DISPMANX_NO_ROTATE;
833         }
834 }
835
836
837 static DISPMANX_RESOURCE_HANDLE_T
838 rpir_surface_get_resource(struct rpir_surface *surface)
839 {
840         switch (surface->buffer_type) {
841         case BUFFER_TYPE_SHM:
842         case BUFFER_TYPE_NULL:
843                 return surface->front->handle;
844         case BUFFER_TYPE_EGL:
845                 if (surface->egl_front != NULL)
846                         return surface->egl_front->resource_handle;
847         default:
848                 return DISPMANX_NO_HANDLE;
849         }
850 }
851
852 static int
853 rpir_view_dmx_add(struct rpir_view *view, struct rpir_output *output,
854                   DISPMANX_UPDATE_HANDLE_T update, int layer)
855 {
856         /* Do not use DISPMANX_FLAGS_ALPHA_PREMULT here.
857          * If you define PREMULT and ALPHA_MIX, the hardware will not
858          * multiply the source color with the element alpha, leading to
859          * bad colors. Instead, we define PREMULT during pixel data upload.
860          */
861         VC_DISPMANX_ALPHA_T alphasetup = {
862                 DISPMANX_FLAGS_ALPHA_FROM_SOURCE |
863                 DISPMANX_FLAGS_ALPHA_MIX,
864                 float2uint8(view->view->alpha), /* opacity 0-255 */
865                 0 /* mask resource handle */
866         };
867         VC_RECT_T dst_rect;
868         VC_RECT_T src_rect;
869         VC_IMAGE_TRANSFORM_T flipmask;
870         int ret;
871         DISPMANX_RESOURCE_HANDLE_T resource_handle;
872
873         resource_handle = rpir_surface_get_resource(view->surface);
874         if (resource_handle == DISPMANX_NO_HANDLE) {
875                 weston_log("%s: no buffer yet, aborting\n", __func__);
876                 return 0;
877         }
878
879         ret = rpir_view_compute_rects(view, &src_rect, &dst_rect, &flipmask);
880         if (ret < 0)
881                 return 0;
882
883         view->handle = vc_dispmanx_element_add(
884                 update,
885                 output->display,
886                 layer,
887                 &dst_rect,
888                 resource_handle,
889                 &src_rect,
890                 DISPMANX_PROTECTION_NONE,
891                 &alphasetup,
892                 NULL /* clamp */,
893                 vc_image2dispmanx_transform(flipmask));
894         DBG("rpir_surface %p add %u, alpha %f resource %d\n", view,
895             view->handle, view->view->alpha, resource_handle);
896
897         if (view->handle == DISPMANX_NO_HANDLE)
898                 return -1;
899
900         view->surface->visible_views++;
901
902         return 1;
903 }
904
905 static void
906 rpir_view_dmx_swap(struct rpir_view *view,
907                    DISPMANX_UPDATE_HANDLE_T update)
908 {
909         VC_RECT_T rect;
910         pixman_box32_t *r;
911
912         /* XXX: skip, iff resource was not reallocated, and single-buffering */
913         vc_dispmanx_element_change_source(update, view->handle,
914                                           view->surface->front->handle);
915
916         /* This is current damage now, after rpir_surface_damage() */
917         r = pixman_region32_extents(&view->surface->prev_damage);
918
919         vc_dispmanx_rect_set(&rect, r->x1, r->y1,
920                              r->x2 - r->x1, r->y2 - r->y1);
921         vc_dispmanx_element_modified(update, view->handle, &rect);
922         DBG("rpir_view %p swap\n", view);
923 }
924
925 static int
926 rpir_view_dmx_move(struct rpir_view *view,
927                    DISPMANX_UPDATE_HANDLE_T update, int layer)
928 {
929         uint8_t alpha = float2uint8(view->view->alpha);
930         VC_RECT_T dst_rect;
931         VC_RECT_T src_rect;
932         VC_IMAGE_TRANSFORM_T flipmask;
933         int ret;
934
935         /* XXX: return early, if all attributes stay the same */
936
937         if (view->surface->buffer_type == BUFFER_TYPE_EGL) {
938                 DISPMANX_RESOURCE_HANDLE_T resource_handle;
939
940                 resource_handle = rpir_surface_get_resource(view->surface);
941                 if (resource_handle == DISPMANX_NO_HANDLE) {
942                         weston_log("%s: no buffer yet, aborting\n", __func__);
943                         return 0;
944                 }
945
946                 vc_dispmanx_element_change_source(update,
947                                                   view->handle,
948                                                   resource_handle);
949         }
950
951         ret = rpir_view_compute_rects(view, &src_rect, &dst_rect, &flipmask);
952         if (ret < 0)
953                 return 0;
954
955         ret = vc_dispmanx_element_change_attributes(
956                 update,
957                 view->handle,
958                 ELEMENT_CHANGE_LAYER |
959                         ELEMENT_CHANGE_OPACITY |
960                         ELEMENT_CHANGE_TRANSFORM |
961                         ELEMENT_CHANGE_DEST_RECT |
962                         ELEMENT_CHANGE_SRC_RECT,
963                 layer,
964                 alpha,
965                 &dst_rect,
966                 &src_rect,
967                 DISPMANX_NO_HANDLE,
968                 /* This really is DISPMANX_TRANSFORM_T, no matter
969                  * what the header says. */
970                 vc_image2dispmanx_transform(flipmask));
971         DBG("rpir_view %p move\n", view);
972
973         if (ret)
974                 return -1;
975
976         return 1;
977 }
978
979 static void
980 rpir_view_dmx_remove(struct rpir_view *view,
981                      DISPMANX_UPDATE_HANDLE_T update)
982 {
983         if (view->handle == DISPMANX_NO_HANDLE)
984                 return;
985
986         vc_dispmanx_element_remove(update, view->handle);
987         DBG("rpir_view %p remove %u\n", view, view->handle);
988         view->handle = DISPMANX_NO_HANDLE;
989         view->surface->visible_views--;
990 }
991
992 static void
993 rpir_surface_swap_pointers(struct rpir_surface *surface)
994 {
995         struct rpi_resource *tmp;
996
997         if (surface->buffer_type == BUFFER_TYPE_EGL) {
998                 if (surface->egl_back != NULL) {
999                         assert(surface->egl_old_front == NULL);
1000                         surface->egl_old_front = surface->egl_front;
1001                         surface->egl_front = surface->egl_back;
1002                         surface->egl_back = NULL;
1003                         DBG("new front %d\n", surface->egl_front->resource_handle);
1004                 }
1005         } else {
1006                 tmp = surface->front;
1007                 surface->front = surface->back;
1008                 surface->back = tmp;
1009                 DBG("new back %p, new front %p\n", surface->back, surface->front);
1010         }
1011 }
1012
1013 static int
1014 is_view_not_visible(struct weston_view *view)
1015 {
1016         /* Return true, if surface is guaranteed to be totally obscured. */
1017         int ret;
1018         pixman_region32_t unocc;
1019
1020         pixman_region32_init(&unocc);
1021         pixman_region32_subtract(&unocc, &view->transform.boundingbox,
1022                                  &view->clip);
1023         ret = !pixman_region32_not_empty(&unocc);
1024         pixman_region32_fini(&unocc);
1025
1026         return ret;
1027 }
1028
1029 static void
1030 rpir_view_update(struct rpir_view *view, struct rpir_output *output,
1031                  DISPMANX_UPDATE_HANDLE_T update, int layer)
1032 {
1033         int ret;
1034         int obscured;
1035
1036         obscured = is_view_not_visible(view->view);
1037         if (obscured) {
1038                 DBG("rpir_view %p totally obscured.\n", view);
1039
1040                 wl_list_remove(&view->link);
1041                 if (view->handle == DISPMANX_NO_HANDLE) {
1042                         wl_list_init(&view->link);
1043                 } else {
1044                         rpir_view_dmx_remove(view, update);
1045                         wl_list_insert(&output->view_cleanup_list,
1046                                        &view->link);
1047                 }
1048
1049                 goto out;
1050         }
1051
1052         if (view->handle == DISPMANX_NO_HANDLE) {
1053                 ret = rpir_view_dmx_add(view, output, update, layer);
1054                 if (ret == 0) {
1055                         wl_list_remove(&view->link);
1056                         wl_list_init(&view->link);
1057                 } else if (ret < 0) {
1058                         weston_log("ERROR rpir_view_dmx_add() failed.\n");
1059                 }
1060         } else {
1061                 if (view->surface->need_swap)
1062                         rpir_view_dmx_swap(view, update);
1063
1064                 ret = rpir_view_dmx_move(view, update, layer);
1065                 if (ret == 0) {
1066                         rpir_view_dmx_remove(view, update);
1067
1068                         wl_list_remove(&view->link);
1069                         wl_list_insert(&output->view_cleanup_list,
1070                                        &view->link);
1071                 } else if (ret < 0) {
1072                         weston_log("ERROR rpir_view_dmx_move() failed.\n");
1073                 }
1074         }
1075
1076 out:
1077         view->layer = layer;
1078 }
1079
1080 static int
1081 rpi_renderer_read_pixels(struct weston_output *base,
1082                          pixman_format_code_t format, void *pixels,
1083                          uint32_t x, uint32_t y,
1084                          uint32_t width, uint32_t height)
1085 {
1086         struct rpir_output *output = to_rpir_output(base);
1087         struct rpi_resource *buffer = &output->capture_buffer;
1088         VC_RECT_T rect;
1089         uint32_t fb_width, fb_height;
1090         uint32_t dst_pitch;
1091         uint32_t i;
1092         int ret;
1093
1094         fb_width = base->current_mode->width;
1095         fb_height = base->current_mode->height;
1096
1097         DBG("%s(%u, %u, %u, %u), resource %p\n", __func__,
1098             x, y, width, height, buffer);
1099
1100         if (format != PIXMAN_a8r8g8b8) {
1101                 weston_log("rpi-renderer error: bad read_format\n");
1102                 return -1;
1103         }
1104
1105         dst_pitch = fb_width * 4;
1106
1107         if (buffer->handle == DISPMANX_NO_HANDLE) {
1108                 free(output->capture_data);
1109                 output->capture_data = NULL;
1110
1111                 ret = rpi_resource_realloc(buffer, VC_IMAGE_ARGB8888,
1112                                            fb_width, fb_height,
1113                                            dst_pitch, fb_height);
1114                 if (ret < 0) {
1115                         weston_log("rpi-renderer error: "
1116                                    "allocating read buffer failed\n");
1117                         return -1;
1118                 }
1119
1120                 ret = vc_dispmanx_snapshot(output->display, buffer->handle,
1121                                            VC_IMAGE_ROT0);
1122                 if (ret) {
1123                         weston_log("rpi-renderer error: "
1124                                    "vc_dispmanx_snapshot returned %d\n", ret);
1125                         return -1;
1126                 }
1127                 DBG("%s: snapshot done.\n", __func__);
1128         }
1129
1130         /*
1131          * If vc_dispmanx_resource_read_data was able to read sub-rectangles,
1132          * we could read directly into 'pixels'. But it cannot, it does not
1133          * use rect.x or rect.width, and does this:
1134          * host_start = (uint8_t *)dst_address + (dst_pitch * p_rect->y);
1135          * In other words, it is only good for reading the full buffer in
1136          * one go.
1137          */
1138         vc_dispmanx_rect_set(&rect, 0, 0, fb_width, fb_height);
1139
1140         if (x == 0 && y == 0 && width == fb_width && height == fb_height) {
1141                 ret = vc_dispmanx_resource_read_data(buffer->handle, &rect,
1142                                                      pixels, dst_pitch);
1143                 if (ret) {
1144                         weston_log("rpi-renderer error: "
1145                                    "resource_read_data returned %d\n", ret);
1146                         return -1;
1147                 }
1148                 DBG("%s: full frame done.\n", __func__);
1149                 return 0;
1150         }
1151
1152         if (!output->capture_data) {
1153                 output->capture_data = malloc(fb_height * dst_pitch);
1154                 if (!output->capture_data) {
1155                         weston_log("rpi-renderer error: "
1156                                    "out of memory\n");
1157                         return -1;
1158                 }
1159
1160                 ret = vc_dispmanx_resource_read_data(buffer->handle, &rect,
1161                                                      output->capture_data,
1162                                                      dst_pitch);
1163                 if (ret) {
1164                         weston_log("rpi-renderer error: "
1165                                    "resource_read_data returned %d\n", ret);
1166                         return -1;
1167                 }
1168         }
1169
1170         for (i = 0; i < height; i++) {
1171                 uint8_t *src = output->capture_data +
1172                                 (y + i) * dst_pitch + x * 4;
1173                 uint8_t *dst = (uint8_t *)pixels + i * width * 4;
1174                 memcpy(dst, src, width * 4);
1175         }
1176
1177         return 0;
1178 }
1179
1180 static void
1181 rpir_output_dmx_remove_all(struct rpir_output *output,
1182                            DISPMANX_UPDATE_HANDLE_T update)
1183 {
1184         struct rpir_view *view;
1185
1186         while (!wl_list_empty(&output->view_list)) {
1187                 view = container_of(output->view_list.next,
1188                                     struct rpir_view, link);
1189                 rpir_view_dmx_remove(view, update);
1190
1191                 wl_list_remove(&view->link);
1192                 wl_list_insert(&output->view_cleanup_list, &view->link);
1193         }
1194 }
1195
1196 static void
1197 output_compute_matrix(struct weston_output *base)
1198 {
1199         struct rpir_output *output = to_rpir_output(base);
1200         struct weston_matrix *matrix = &output->matrix;
1201         const float half_w = 0.5f * base->width;
1202         const float half_h = 0.5f * base->height;
1203         float mag;
1204         float dx, dy;
1205
1206         weston_matrix_init(matrix);
1207         weston_matrix_translate(matrix, -base->x, -base->y, 0.0f);
1208
1209 #ifdef SURFACE_TRANSFORM
1210         weston_matrix_translate(matrix, -half_w, -half_h, 0.0f);
1211         switch (base->transform) {
1212         case WL_OUTPUT_TRANSFORM_FLIPPED:
1213                 weston_matrix_scale(matrix, -1.0f, 1.0f, 1.0f);
1214         case WL_OUTPUT_TRANSFORM_NORMAL:
1215                 /* weston_matrix_rotate_xy(matrix, 1.0f, 0.0f); no-op */
1216                 weston_matrix_translate(matrix, half_w, half_h, 0.0f);
1217                 break;
1218
1219         case WL_OUTPUT_TRANSFORM_FLIPPED_90:
1220                 weston_matrix_scale(matrix, -1.0f, 1.0f, 1.0f);
1221         case WL_OUTPUT_TRANSFORM_90:
1222                 weston_matrix_rotate_xy(matrix, 0.0f, 1.0f);
1223                 weston_matrix_translate(matrix, half_h, half_w, 0.0f);
1224                 break;
1225
1226         case WL_OUTPUT_TRANSFORM_FLIPPED_180:
1227                 weston_matrix_scale(matrix, -1.0f, 1.0f, 1.0f);
1228         case WL_OUTPUT_TRANSFORM_180:
1229                 weston_matrix_rotate_xy(matrix, -1.0f, 0.0f);
1230                 weston_matrix_translate(matrix, half_w, half_h, 0.0f);
1231                 break;
1232
1233         case WL_OUTPUT_TRANSFORM_FLIPPED_270:
1234                 weston_matrix_scale(matrix, -1.0f, 1.0f, 1.0f);
1235         case WL_OUTPUT_TRANSFORM_270:
1236                 weston_matrix_rotate_xy(matrix, 0.0f, -1.0f);
1237                 weston_matrix_translate(matrix, half_h, half_w, 0.0f);
1238                 break;
1239
1240         default:
1241                 break;
1242         }
1243 #endif
1244
1245         if (base->zoom.active) {
1246                 /* The base->zoom stuff is in GL coordinate system */
1247                 mag = 1.0f / (1.0f - base->zoom.spring_z.current);
1248                 dx = -(base->zoom.trans_x + 1.0f) * half_w;
1249                 dy = -(base->zoom.trans_y + 1.0f) * half_h;
1250                 weston_matrix_translate(matrix, dx, dy, 0.0f);
1251                 weston_matrix_scale(matrix, mag, mag, 1.0f);
1252                 weston_matrix_translate(matrix, half_w, half_h, 0.0f);
1253         }
1254 }
1255
1256 /* Note: this won't work right for multiple outputs. A DispmanX Element
1257  * is tied to one DispmanX Display, i.e. output.
1258  */
1259 static void
1260 rpi_renderer_repaint_output(struct weston_output *base,
1261                             pixman_region32_t *output_damage)
1262 {
1263         struct weston_compositor *compositor = base->compositor;
1264         struct rpir_output *output = to_rpir_output(base);
1265         struct weston_view *wv;
1266         struct rpir_view *view;
1267         struct wl_list done_list;
1268         int layer = 1;
1269
1270         assert(output->update != DISPMANX_NO_HANDLE);
1271
1272         output_compute_matrix(base);
1273
1274         rpi_resource_release(&output->capture_buffer);
1275         free(output->capture_data);
1276         output->capture_data = NULL;
1277
1278         /* Swap resources on surfaces as needed */
1279         wl_list_for_each_reverse(wv, &compositor->view_list, link)
1280                 wv->surface->touched = 0;
1281
1282         wl_list_for_each_reverse(wv, &compositor->view_list, link) {
1283                 view = to_rpir_view(wv);
1284
1285                 if (!wv->surface->touched) {
1286                         wv->surface->touched = 1;
1287
1288                         if (view->surface->buffer_type == BUFFER_TYPE_EGL ||
1289                             view->surface->need_swap)
1290                                 rpir_surface_swap_pointers(view->surface);
1291                 }
1292
1293                 if (view->surface->buffer_type == BUFFER_TYPE_EGL) {
1294                         struct weston_buffer *buffer;
1295                         buffer = view->surface->egl_front->buffer_ref.buffer;
1296                         if (buffer != NULL) {
1297                                 vc_dispmanx_set_wl_buffer_in_use(buffer->resource, 1);
1298                         } else {
1299                                 weston_log("warning: client destroyed current front buffer\n");
1300
1301                                 wl_list_remove(&view->link);
1302                                 if (view->handle == DISPMANX_NO_HANDLE) {
1303                                         wl_list_init(&view->link);
1304                                 } else {
1305                                         rpir_view_dmx_remove(view, output->update);
1306                                         wl_list_insert(&output->view_cleanup_list,
1307                                                        &view->link);
1308                                 }
1309                         }
1310                 }
1311         }
1312
1313         /* update all renderable surfaces */
1314         wl_list_init(&done_list);
1315         wl_list_for_each_reverse(wv, &compositor->view_list, link) {
1316                 if (wv->plane != &compositor->primary_plane)
1317                         continue;
1318
1319                 view = to_rpir_view(wv);
1320                 assert(!wl_list_empty(&view->link) ||
1321                        view->handle == DISPMANX_NO_HANDLE);
1322
1323                 wl_list_remove(&view->link);
1324                 wl_list_insert(&done_list, &view->link);
1325                 rpir_view_update(view, output, output->update, layer++);
1326         }
1327
1328         /* Mark all surfaces as swapped */
1329         wl_list_for_each_reverse(wv, &compositor->view_list, link)
1330                 to_rpir_surface(wv->surface)->need_swap = 0;
1331
1332         /* Remove all surfaces that are still on screen, but were
1333          * not rendered this time.
1334          */
1335         rpir_output_dmx_remove_all(output, output->update);
1336
1337         wl_list_insert_list(&output->view_list, &done_list);
1338         output->update = DISPMANX_NO_HANDLE;
1339
1340         /* The frame_signal is emitted in rpi_renderer_finish_frame(),
1341          * so that the firmware can capture the up-to-date contents.
1342          */
1343 }
1344
1345 static void
1346 rpi_renderer_flush_damage(struct weston_surface *base)
1347 {
1348         /* Called for every surface just before repainting it, if
1349          * having an shm buffer.
1350          */
1351         struct rpir_surface *surface = to_rpir_surface(base);
1352         struct weston_buffer *buffer = surface->buffer_ref.buffer;
1353         int ret;
1354
1355         assert(buffer);
1356         assert(wl_shm_buffer_get(buffer->resource));
1357
1358         ret = rpir_surface_damage(surface, buffer, &base->damage);
1359         if (ret)
1360                 weston_log("%s error: updating Dispmanx resource failed.\n",
1361                            __func__);
1362
1363         weston_buffer_reference(&surface->buffer_ref, NULL);
1364 }
1365
1366 static void
1367 rpi_renderer_attach(struct weston_surface *base, struct weston_buffer *buffer)
1368 {
1369         /* Called every time a client commits an attach. */
1370         struct rpir_surface *surface = to_rpir_surface(base);
1371
1372         assert(surface);
1373         if (!surface)
1374                 return;
1375
1376         if (surface->buffer_type == BUFFER_TYPE_SHM) {
1377                 if (!surface->single_buffer)
1378                         /* XXX: need to check if in middle of update */
1379                         rpi_resource_release(surface->back);
1380
1381                 if (!surface->visible_views)
1382                         /* XXX: cannot do this, if middle of an update */
1383                         rpi_resource_release(surface->front);
1384
1385                 weston_buffer_reference(&surface->buffer_ref, NULL);
1386         }
1387
1388         /* If buffer is NULL, Weston core unmaps the surface, the surface
1389          * will not appear in repaint list, and so rpi_renderer_repaint_output
1390          * will remove the DispmanX element. Later, for SHM, also the front
1391          * buffer will be released in the cleanup_list processing.
1392          */
1393         if (!buffer)
1394                 return;
1395
1396         if (wl_shm_buffer_get(buffer->resource)) {
1397                 surface->buffer_type = BUFFER_TYPE_SHM;
1398                 buffer->shm_buffer = wl_shm_buffer_get(buffer->resource);
1399                 buffer->width = wl_shm_buffer_get_width(buffer->shm_buffer);
1400                 buffer->height = wl_shm_buffer_get_height(buffer->shm_buffer);
1401
1402                 weston_buffer_reference(&surface->buffer_ref, buffer);
1403         } else {
1404 #if ENABLE_EGL
1405                 struct rpi_renderer *renderer = to_rpi_renderer(base->compositor);
1406                 struct wl_resource *wl_resource = buffer->resource;
1407
1408                 if (!renderer->has_bind_display ||
1409                     !renderer->query_buffer(renderer->egl_display,
1410                                             wl_resource,
1411                                             EGL_WIDTH, &buffer->width)) {
1412                         weston_log("unhandled buffer type!\n");
1413                         weston_buffer_reference(&surface->buffer_ref, NULL);
1414                         surface->buffer_type = BUFFER_TYPE_NULL;
1415                 }
1416
1417                 renderer->query_buffer(renderer->egl_display,
1418                                        wl_resource,
1419                                        EGL_HEIGHT, &buffer->height);
1420
1421                 surface->buffer_type = BUFFER_TYPE_EGL;
1422
1423                 if(surface->egl_back == NULL)
1424                         surface->egl_back = calloc(1, sizeof *surface->egl_back);
1425
1426                 weston_buffer_reference(&surface->egl_back->buffer_ref, buffer);
1427                 surface->egl_back->resource_handle =
1428                         vc_dispmanx_get_handle_from_wl_buffer(wl_resource);
1429 #else
1430                 weston_log("unhandled buffer type!\n");
1431                 weston_buffer_reference(&surface->buffer_ref, NULL);
1432                 surface->buffer_type = BUFFER_TYPE_NULL;
1433 #endif
1434         }
1435 }
1436
1437 static void
1438 rpir_surface_handle_surface_destroy(struct wl_listener *listener, void *data)
1439 {
1440         struct rpir_surface *surface;
1441         struct weston_surface *base = data;
1442
1443         surface = container_of(listener, struct rpir_surface,
1444                                surface_destroy_listener);
1445
1446         assert(surface);
1447         assert(surface->surface == base);
1448         if (!surface)
1449                 return;
1450
1451         surface->surface = NULL;
1452         base->renderer_state = NULL;
1453
1454         if (wl_list_empty(&surface->views))
1455                 rpir_surface_destroy(surface);
1456 }
1457
1458 static int
1459 rpi_renderer_create_surface(struct weston_surface *base)
1460 {
1461         struct rpi_renderer *renderer = to_rpi_renderer(base->compositor);
1462         struct rpir_surface *surface;
1463
1464         assert(base->renderer_state == NULL);
1465
1466         surface = rpir_surface_create(renderer);
1467         if (!surface)
1468                 return -1;
1469
1470         surface->surface = base;
1471         base->renderer_state = surface;
1472
1473         surface->surface_destroy_listener.notify =
1474                 rpir_surface_handle_surface_destroy;
1475         wl_signal_add(&base->destroy_signal,
1476                       &surface->surface_destroy_listener);
1477
1478         return 0;
1479 }
1480
1481 static int
1482 rpi_renderer_create_view(struct weston_view *base)
1483 {
1484         struct rpir_surface *surface = to_rpir_surface(base->surface);
1485         struct rpir_view *view;
1486
1487         assert(base->renderer_state == NULL);
1488
1489         view = rpir_view_create(surface);
1490         if (!view)
1491                 return -1;
1492
1493         view->view = base;
1494         base->renderer_state = view;
1495
1496         view->view_destroy_listener.notify =
1497                 rpir_view_handle_view_destroy;
1498         wl_signal_add(&base->destroy_signal,
1499                       &view->view_destroy_listener);
1500
1501         return 0;
1502 }
1503
1504 static void
1505 rpi_renderer_surface_set_color(struct weston_surface *base,
1506                                float red, float green, float blue, float alpha)
1507 {
1508         struct rpir_surface *surface = to_rpir_surface(base);
1509         uint8_t color[4];
1510         VC_RECT_T rect;
1511         int ret;
1512
1513         assert(surface);
1514
1515         ret = rpi_resource_realloc(surface->back, VC_IMAGE_ARGB8888,
1516                                    1, 1, 4, 1);
1517         if (ret < 0) {
1518                 weston_log("Error: %s: rpi_resource_realloc failed.\n",
1519                            __func__);
1520                 return;
1521         }
1522
1523         color[0] = float2uint8(blue);
1524         color[1] = float2uint8(green);
1525         color[2] = float2uint8(red);
1526         color[3] = float2uint8(alpha);
1527
1528         vc_dispmanx_rect_set(&rect, 0, 0, 1, 1);
1529         ret = vc_dispmanx_resource_write_data(surface->back->handle,
1530                                               VC_IMAGE_ARGB8888,
1531                                               4, color, &rect);
1532         if (ret) {
1533                 weston_log("Error: %s: resource_write_data failed.\n",
1534                            __func__);
1535                 return;
1536         }
1537
1538         DBG("%s: resource %p solid color BGRA %u,%u,%u,%u\n", __func__,
1539             surface->back, color[0], color[1], color[2], color[3]);
1540
1541         /*pixman_region32_copy(&surface->prev_damage, damage);*/
1542         surface->need_swap = 1;
1543 }
1544
1545 static void
1546 rpir_view_handle_view_destroy(struct wl_listener *listener, void *data)
1547 {
1548         struct rpir_view *view;
1549         struct weston_view *base = data;
1550
1551         view = container_of(listener, struct rpir_view, view_destroy_listener);
1552
1553         assert(view);
1554         assert(view->view == base);
1555         if (!view)
1556                 return;
1557
1558         view->view = NULL;
1559         base->renderer_state = NULL;
1560
1561         /* If guaranteed to not be on screen, just destroy it. */
1562         if (wl_list_empty(&view->link))
1563                 rpir_view_destroy(view);
1564
1565         /* Otherwise, the view is either on screen and needs
1566          * to be removed by a repaint update, or it is in the
1567          * view_cleanup_list, and will be destroyed by
1568          * rpi_renderer_finish_frame().
1569          */
1570 }
1571
1572 static void
1573 rpi_renderer_destroy(struct weston_compositor *compositor)
1574 {
1575         struct rpi_renderer *renderer = to_rpi_renderer(compositor);
1576
1577 #if ENABLE_EGL
1578         if (renderer->has_bind_display)
1579                 renderer->unbind_display(renderer->egl_display,
1580                                          compositor->wl_display);
1581 #endif
1582
1583         free(renderer);
1584         compositor->renderer = NULL;
1585 }
1586
1587 WL_EXPORT int
1588 rpi_renderer_create(struct weston_compositor *compositor,
1589                     const struct rpi_renderer_parameters *params)
1590 {
1591         struct rpi_renderer *renderer;
1592 #if ENABLE_EGL
1593         const char *extensions;
1594         EGLBoolean ret;
1595         EGLint major, minor;
1596 #endif
1597
1598         weston_log("Initializing the DispmanX compositing renderer\n");
1599
1600         renderer = calloc(1, sizeof *renderer);
1601         if (renderer == NULL)
1602                 return -1;
1603
1604         renderer->single_buffer = params->single_buffer;
1605
1606         renderer->base.read_pixels = rpi_renderer_read_pixels;
1607         renderer->base.repaint_output = rpi_renderer_repaint_output;
1608         renderer->base.flush_damage = rpi_renderer_flush_damage;
1609         renderer->base.attach = rpi_renderer_attach;
1610         renderer->base.surface_set_color = rpi_renderer_surface_set_color;
1611         renderer->base.destroy = rpi_renderer_destroy;
1612
1613 #ifdef ENABLE_EGL
1614         renderer->egl_display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
1615         if (renderer->egl_display == EGL_NO_DISPLAY) {
1616                 weston_log("failed to create EGL display\n");
1617                 return -1;
1618         }
1619
1620         if (!eglInitialize(renderer->egl_display, &major, &minor)) {
1621                 weston_log("failed to initialize EGL display\n");
1622                 return -1;
1623         }
1624
1625         renderer->bind_display =
1626                 (void *) eglGetProcAddress("eglBindWaylandDisplayWL");
1627         renderer->unbind_display =
1628                 (void *) eglGetProcAddress("eglUnbindWaylandDisplayWL");
1629         renderer->query_buffer =
1630                 (void *) eglGetProcAddress("eglQueryWaylandBufferWL");
1631
1632         extensions = (const char *) eglQueryString(renderer->egl_display,
1633                                                    EGL_EXTENSIONS);
1634         if (!extensions) {
1635                 weston_log("Retrieving EGL extension string failed.\n");
1636                 return -1;
1637         }
1638
1639         if (strstr(extensions, "EGL_WL_bind_wayland_display"))
1640                 renderer->has_bind_display = 1;
1641
1642         if (renderer->has_bind_display) {
1643                 ret = renderer->bind_display(renderer->egl_display,
1644                                              compositor->wl_display);
1645                 if (!ret)
1646                         renderer->has_bind_display = 0;
1647         }
1648 #endif
1649
1650         compositor->renderer = &renderer->base;
1651         compositor->read_format = PIXMAN_a8r8g8b8;
1652         /* WESTON_CAP_ROTATION_ANY not supported */
1653
1654         wl_display_add_shm_format(compositor->wl_display, WL_SHM_FORMAT_RGB565);
1655
1656         return 0;
1657 }
1658
1659 WL_EXPORT int
1660 rpi_renderer_output_create(struct weston_output *base,
1661                            DISPMANX_DISPLAY_HANDLE_T display)
1662 {
1663         struct rpir_output *output;
1664
1665         assert(base->renderer_state == NULL);
1666
1667         output = calloc(1, sizeof *output);
1668         if (!output)
1669                 return -1;
1670
1671         output->display = display;
1672         output->update = DISPMANX_NO_HANDLE;
1673         wl_list_init(&output->view_list);
1674         wl_list_init(&output->view_cleanup_list);
1675         rpi_resource_init(&output->capture_buffer);
1676         base->renderer_state = output;
1677
1678         return 0;
1679 }
1680
1681 WL_EXPORT void
1682 rpi_renderer_output_destroy(struct weston_output *base)
1683 {
1684         struct rpir_output *output = to_rpir_output(base);
1685         struct rpir_view *view;
1686         DISPMANX_UPDATE_HANDLE_T update;
1687
1688         rpi_resource_release(&output->capture_buffer);
1689         free(output->capture_data);
1690         output->capture_data = NULL;
1691
1692         update = vc_dispmanx_update_start(0);
1693         rpir_output_dmx_remove_all(output, update);
1694         vc_dispmanx_update_submit_sync(update);
1695
1696         while (!wl_list_empty(&output->view_cleanup_list)) {
1697                 view = container_of(output->view_cleanup_list.next,
1698                                     struct rpir_view, link);
1699                 rpir_view_destroy(view);
1700         }
1701
1702         free(output);
1703         base->renderer_state = NULL;
1704 }
1705
1706 WL_EXPORT void
1707 rpi_renderer_set_update_handle(struct weston_output *base,
1708                                DISPMANX_UPDATE_HANDLE_T handle)
1709 {
1710         struct rpir_output *output = to_rpir_output(base);
1711
1712         output->update = handle;
1713 }
1714
1715 WL_EXPORT void
1716 rpi_renderer_finish_frame(struct weston_output *base)
1717 {
1718         struct rpir_output *output = to_rpir_output(base);
1719         struct weston_compositor *compositor = base->compositor;
1720         struct weston_view *wv;
1721         struct rpir_view *view;
1722
1723         while (!wl_list_empty(&output->view_cleanup_list)) {
1724                 view = container_of(output->view_cleanup_list.next,
1725                                     struct rpir_view, link);
1726
1727                 if (view->view) {
1728                         /* The weston_view still exists, but is
1729                          * temporarily not visible, and hence its Element
1730                          * was removed. The current front buffer contents
1731                          * must be preserved.
1732                          */
1733                         if (!view->surface->visible_views)
1734                                 rpi_resource_release(view->surface->back);
1735
1736                         wl_list_remove(&view->link);
1737                         wl_list_init(&view->link);
1738                 } else {
1739                         rpir_view_destroy(view);
1740                 }
1741         }
1742
1743         wl_list_for_each(wv, &compositor->view_list, link) {
1744                 view = to_rpir_view(wv);
1745
1746                 if (view->surface->buffer_type != BUFFER_TYPE_EGL)
1747                         continue;
1748
1749                 rpir_egl_buffer_destroy(view->surface->egl_old_front);
1750                 view->surface->egl_old_front = NULL;
1751         }
1752
1753         wl_signal_emit(&base->frame_signal, base);
1754 }