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