blob: 7cbb4e837bd0dcbd8eeaae081058ebe505455048 [file] [log] [blame]
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001/*
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
Daniel Stonec228e232013-05-22 18:03:19 +030023#include "config.h"
24
Pekka Paalanend7265bc2013-05-22 18:03:06 +030025#include <stdlib.h>
26#include <assert.h>
27#include <string.h>
28
Pekka Paalanend7265bc2013-05-22 18:03:06 +030029#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
Tomeu Vizosob4659eb2013-10-07 11:02:20 +020038#ifdef ENABLE_EGL
39#include <EGL/egl.h>
40#include <EGL/eglext.h>
41#include "weston-egl-ext.h"
42#endif
43
Pekka Paalanend7265bc2013-05-22 18:03:06 +030044/*
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
82struct 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
91struct rpir_output;
92
Tomeu Vizosob4659eb2013-10-07 11:02:20 +020093struct rpir_egl_buffer {
94 struct weston_buffer_reference buffer_ref;
95 DISPMANX_RESOURCE_HANDLE_T resource_handle;
96};
97
98enum buffer_type {
99 BUFFER_TYPE_NULL,
100 BUFFER_TYPE_SHM,
101 BUFFER_TYPE_EGL
102};
103
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300104struct rpir_surface {
105 struct weston_surface *surface;
106
Jason Ekstranda7af7042013-10-12 22:38:11 -0500107 struct wl_list views;
108 int visible_views;
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300109 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
Tomeu Vizosob4659eb2013-10-07 11:02:20 +0200117 struct rpir_egl_buffer *egl_front;
118 struct rpir_egl_buffer *egl_back;
119 struct rpir_egl_buffer *egl_old_front;
120
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300121 struct weston_buffer_reference buffer_ref;
Tomeu Vizosob4659eb2013-10-07 11:02:20 +0200122 enum buffer_type buffer_type;
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300123};
124
Jason Ekstranda7af7042013-10-12 22:38:11 -0500125struct rpir_view {
126 struct rpir_surface *surface;
127 struct wl_list surface_link;
128 struct weston_view *view;
129
130 /* If link is empty, the view is guaranteed to not be on screen,
131 * i.e. updates removing Elements have completed.
132 */
133 struct wl_list link;
134
135 DISPMANX_ELEMENT_HANDLE_T handle;
136 int layer;
137};
138
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300139struct rpir_output {
140 DISPMANX_DISPLAY_HANDLE_T display;
141
142 DISPMANX_UPDATE_HANDLE_T update;
143 struct weston_matrix matrix;
144
145 /* all Elements currently on screen */
Jason Ekstranda7af7042013-10-12 22:38:11 -0500146 struct wl_list view_list; /* struct rpir_surface::link */
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300147
148 /* Elements just removed, waiting for update completion */
Jason Ekstranda7af7042013-10-12 22:38:11 -0500149 struct wl_list view_cleanup_list; /* struct rpir_surface::link */
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300150
151 struct rpi_resource capture_buffer;
152 uint8_t *capture_data;
153};
154
155struct rpi_renderer {
156 struct weston_renderer base;
157
158 int single_buffer;
Tomeu Vizosob4659eb2013-10-07 11:02:20 +0200159
160#ifdef ENABLE_EGL
161 EGLDisplay egl_display;
162
163 PFNEGLBINDWAYLANDDISPLAYWL bind_display;
164 PFNEGLUNBINDWAYLANDDISPLAYWL unbind_display;
165 PFNEGLQUERYWAYLANDBUFFERWL query_buffer;
166#endif
167 int has_bind_display;
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300168};
169
170static inline struct rpir_surface *
171to_rpir_surface(struct weston_surface *surface)
172{
173 return surface->renderer_state;
174}
175
Jason Ekstranda7af7042013-10-12 22:38:11 -0500176static inline struct rpir_view *
177to_rpir_view(struct weston_view *view)
178{
179 return view->renderer_state;
180}
181
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300182static inline struct rpir_output *
183to_rpir_output(struct weston_output *output)
184{
185 return output->renderer_state;
186}
187
188static inline struct rpi_renderer *
189to_rpi_renderer(struct weston_compositor *compositor)
190{
191 return container_of(compositor->renderer, struct rpi_renderer, base);
192}
193
194static inline int
195int_max(int a, int b)
196{
197 return a > b ? a : b;
198}
199
200static inline void
201int_swap(int *a, int *b)
202{
203 int tmp = *a;
204 *a = *b;
205 *b = tmp;
206}
207
208static uint8_t
209float2uint8(float f)
210{
211 int v = roundf(f * 255.0f);
212
213 return v < 0 ? 0 : (v > 255 ? 255 : v);
214}
215
216static void
217rpi_resource_init(struct rpi_resource *resource)
218{
219 resource->handle = DISPMANX_NO_HANDLE;
220}
221
222static void
223rpi_resource_release(struct rpi_resource *resource)
224{
225 if (resource->handle == DISPMANX_NO_HANDLE)
226 return;
227
228 vc_dispmanx_resource_delete(resource->handle);
229 DBG("resource %p release\n", resource);
230 resource->handle = DISPMANX_NO_HANDLE;
231}
232
233static int
234rpi_resource_realloc(struct rpi_resource *resource, VC_IMAGE_TYPE_T ifmt,
235 int width, int height, int stride, int buffer_height)
236{
237 uint32_t dummy;
238
239 if (resource->handle != DISPMANX_NO_HANDLE &&
240 resource->width == width &&
241 resource->height == height &&
242 resource->stride == stride &&
243 resource->buffer_height == buffer_height &&
244 resource->ifmt == ifmt)
245 return 0;
246
247 rpi_resource_release(resource);
248
249 /* NOTE: if stride is not a multiple of 16 pixels in bytes,
250 * the vc_image_* functions may break. Dispmanx elements
251 * should be fine, though. Buffer_height probably has similar
252 * constraints, too.
253 */
254 resource->handle =
255 vc_dispmanx_resource_create(ifmt,
256 width | (stride << 16),
257 height | (buffer_height << 16),
258 &dummy);
259 if (resource->handle == DISPMANX_NO_HANDLE)
260 return -1;
261
262 resource->width = width;
263 resource->height = height;
264 resource->stride = stride;
265 resource->buffer_height = buffer_height;
266 resource->ifmt = ifmt;
267 DBG("resource %p alloc\n", resource);
268 return 1;
269}
270
271/* A firmware workaround for broken ALPHA_PREMULT + ALPHA_MIX hardware. */
272#define PREMULT_ALPHA_FLAG (1 << 31)
273
274static VC_IMAGE_TYPE_T
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500275shm_buffer_get_vc_format(struct wl_shm_buffer *buffer)
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300276{
277 switch (wl_shm_buffer_get_format(buffer)) {
278 case WL_SHM_FORMAT_XRGB8888:
279 return VC_IMAGE_XRGB8888;
280 case WL_SHM_FORMAT_ARGB8888:
281 return VC_IMAGE_ARGB8888 | PREMULT_ALPHA_FLAG;
Tomeu Vizoso03681892013-08-06 20:05:57 +0200282 case WL_SHM_FORMAT_RGB565:
283 return VC_IMAGE_RGB565;
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300284 default:
285 /* invalid format */
286 return VC_IMAGE_MIN;
287 }
288}
289
290static int
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500291rpi_resource_update(struct rpi_resource *resource, struct weston_buffer *buffer,
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300292 pixman_region32_t *region)
293{
294 pixman_region32_t write_region;
295 pixman_box32_t *r;
296 VC_RECT_T rect;
297 VC_IMAGE_TYPE_T ifmt;
298 uint32_t *pixels;
299 int width;
300 int height;
301 int stride;
302 int ret;
303#ifdef HAVE_RESOURCE_WRITE_DATA_RECT
304 int n;
305#endif
306
307 if (!buffer)
308 return -1;
309
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500310 ifmt = shm_buffer_get_vc_format(buffer->shm_buffer);
311 width = wl_shm_buffer_get_width(buffer->shm_buffer);
312 height = wl_shm_buffer_get_height(buffer->shm_buffer);
313 stride = wl_shm_buffer_get_stride(buffer->shm_buffer);
314 pixels = wl_shm_buffer_get_data(buffer->shm_buffer);
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300315
316 ret = rpi_resource_realloc(resource, ifmt & ~PREMULT_ALPHA_FLAG,
317 width, height, stride, height);
318 if (ret < 0)
319 return -1;
320
321 pixman_region32_init_rect(&write_region, 0, 0, width, height);
322 if (ret == 0)
323 pixman_region32_intersect(&write_region,
324 &write_region, region);
325
326#ifdef HAVE_RESOURCE_WRITE_DATA_RECT
327 /* XXX: Can this do a format conversion, so that scanout does not have to? */
328 r = pixman_region32_rectangles(&write_region, &n);
329 while (n--) {
330 vc_dispmanx_rect_set(&rect, r[n].x1, r[n].y1,
331 r[n].x2 - r[n].x1, r[n].y2 - r[n].y1);
332
333 ret = vc_dispmanx_resource_write_data_rect(resource->handle,
334 ifmt, stride,
335 pixels, &rect,
336 rect.x, rect.y);
337 DBG("%s: %p %ux%u@%u,%u, ret %d\n", __func__, resource,
338 rect.width, rect.height, rect.x, rect.y, ret);
339 if (ret)
340 break;
341 }
342#else
343 /* vc_dispmanx_resource_write_data() ignores ifmt,
344 * rect.x, rect.width, and uses stride only for computing
345 * the size of the transfer as rect.height * stride.
346 * Therefore we can only write rows starting at x=0.
347 * To be able to write more than one scanline at a time,
348 * the resource must have been created with the same stride
349 * as used here, and we must write full scanlines.
350 */
351
352 r = pixman_region32_extents(&write_region);
353 vc_dispmanx_rect_set(&rect, 0, r->y1, width, r->y2 - r->y1);
354 ret = vc_dispmanx_resource_write_data(resource->handle,
355 ifmt, stride, pixels, &rect);
356 DBG("%s: %p %ux%u@%u,%u, ret %d\n", __func__, resource,
357 width, r->y2 - r->y1, 0, r->y1, ret);
358#endif
359
360 pixman_region32_fini(&write_region);
361
362 return ret ? -1 : 0;
363}
364
Tomeu Vizoso74987582013-10-25 10:34:38 +0200365static void
366rpir_egl_buffer_destroy(struct rpir_egl_buffer *egl_buffer)
367{
368 struct weston_buffer *buffer;
369
370 if (egl_buffer == NULL)
371 return;
372
373 buffer = egl_buffer->buffer_ref.buffer;
374 if (buffer == NULL) {
375 /* The client has already destroyed the wl_buffer, the
376 * compositor has the responsibility to delete the resource.
377 */
378 vc_dispmanx_resource_delete(egl_buffer->resource_handle);
379 } else {
380 vc_dispmanx_set_wl_buffer_in_use(buffer->resource, 0);
381 weston_buffer_reference(&egl_buffer->buffer_ref, NULL);
382 }
383
384 free(egl_buffer);
385}
386
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300387static struct rpir_surface *
388rpir_surface_create(struct rpi_renderer *renderer)
389{
390 struct rpir_surface *surface;
391
392 surface = calloc(1, sizeof *surface);
393 if (!surface)
394 return NULL;
395
Tomeu Vizoso5c3ea3b2013-10-24 15:38:30 +0200396 wl_list_init(&surface->views);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500397 surface->visible_views = 0;
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300398 surface->single_buffer = renderer->single_buffer;
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300399 rpi_resource_init(&surface->resources[0]);
400 rpi_resource_init(&surface->resources[1]);
401 surface->front = &surface->resources[0];
402 if (surface->single_buffer)
403 surface->back = &surface->resources[0];
404 else
405 surface->back = &surface->resources[1];
Tomeu Vizosob4659eb2013-10-07 11:02:20 +0200406 surface->buffer_type = BUFFER_TYPE_NULL;
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300407
408 pixman_region32_init(&surface->prev_damage);
409
410 return surface;
411}
412
413static void
414rpir_surface_destroy(struct rpir_surface *surface)
415{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500416 if (surface->visible_views)
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300417 weston_log("ERROR rpi: destroying on-screen element\n");
418
Jason Ekstranda7af7042013-10-12 22:38:11 -0500419 assert(wl_list_empty(&surface->views));
420
421 if (surface->surface)
422 surface->surface->renderer_state = NULL;
423
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300424 pixman_region32_fini(&surface->prev_damage);
425 rpi_resource_release(&surface->resources[0]);
426 rpi_resource_release(&surface->resources[1]);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500427 DBG("rpir_surface %p destroyed (%u)\n", surface, surface->visible_views);
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300428
Tomeu Vizoso74987582013-10-25 10:34:38 +0200429 rpir_egl_buffer_destroy(surface->egl_back);
430 rpir_egl_buffer_destroy(surface->egl_front);
431 rpir_egl_buffer_destroy(surface->egl_old_front);
Tomeu Vizosob4659eb2013-10-07 11:02:20 +0200432
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300433 free(surface);
434}
435
436static int
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500437rpir_surface_damage(struct rpir_surface *surface, struct weston_buffer *buffer,
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300438 pixman_region32_t *damage)
439{
440 pixman_region32_t upload;
441 int ret;
442
443 if (!pixman_region32_not_empty(damage))
444 return 0;
445
446 DBG("rpir_surface %p update resource %p\n", surface, surface->back);
447
448 /* XXX: todo: if no surface->handle, update front buffer directly
449 * to avoid creating a new back buffer */
450 if (surface->single_buffer) {
451 ret = rpi_resource_update(surface->front, buffer, damage);
452 } else {
453 pixman_region32_init(&upload);
454 pixman_region32_union(&upload, &surface->prev_damage, damage);
455 ret = rpi_resource_update(surface->back, buffer, &upload);
456 pixman_region32_fini(&upload);
457 }
458
459 pixman_region32_copy(&surface->prev_damage, damage);
460 surface->need_swap = 1;
461
462 return ret;
463}
464
Jason Ekstranda7af7042013-10-12 22:38:11 -0500465static struct rpir_view *
466rpir_view_create(struct rpir_surface *surface)
467{
468 struct rpir_view *view;
469
470 view = calloc(1, sizeof *view);
471 if (!view)
472 return NULL;
473
474 view->surface = surface;
475 wl_list_insert(&surface->views, &view->surface_link);
476
477 wl_list_init(&view->link);
478 view->handle = DISPMANX_NO_HANDLE;
479
480 return view;
481}
482
483static void
484rpir_view_destroy(struct rpir_view *view)
485{
486 wl_list_remove(&view->link);
487
488 if (view->handle != DISPMANX_NO_HANDLE) {
489 view->surface->visible_views--;
490 weston_log("ERROR rpi: destroying on-screen element\n");
491 }
492
493 if (view->view)
494 view->view->renderer_state = NULL;
495
496 wl_list_remove(&view->surface_link);
497 if (wl_list_empty(&view->surface->views) && view->surface->surface == NULL)
498 rpir_surface_destroy(view->surface);
499
500 DBG("rpir_view %p destroyed (%d)\n", view, view->handle);
501
502 free(view);
503}
504
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300505static void
506matrix_type_str(struct weston_matrix *matrix, char *buf, int len)
507{
508 static const char types[33] = "TSRO";
509 unsigned mask = matrix->type;
510 int i = 0;
511
512 while (mask && i < len - 1) {
513 if (mask & (1u << i))
514 *buf++ = types[i];
515 mask &= ~(1u << i);
516 i++;
517 }
518 *buf = '\0';
519}
520
521static void
522log_print_matrix(struct weston_matrix *matrix)
523{
524 char typestr[6];
525 float *d = matrix->d;
526
527 matrix_type_str(matrix, typestr, sizeof typestr);
528 weston_log_continue("%14.6e %14.6e %14.6e %14.6e\n",
529 d[0], d[4], d[8], d[12]);
530 weston_log_continue("%14.6e %14.6e %14.6e %14.6e\n",
531 d[1], d[5], d[9], d[13]);
532 weston_log_continue("%14.6e %14.6e %14.6e %14.6e\n",
533 d[2], d[6], d[10], d[14]);
534 weston_log_continue("%14.6e %14.6e %14.6e %14.6e type: %s\n",
535 d[3], d[7], d[11], d[15], typestr);
536}
537
538static void
539warn_bad_matrix(struct weston_matrix *total, struct weston_matrix *output,
540 struct weston_matrix *surface)
541{
542 static int n_warn;
543 char typestr[6];
544
545 if (n_warn++ == 10)
546 weston_log("%s: not showing more warnings\n", __func__);
547
548 if (n_warn > 10)
549 return;
550
551 weston_log("%s: warning: total transformation is not renderable:\n",
552 __func__);
553 log_print_matrix(total);
554
555 matrix_type_str(surface, typestr, sizeof typestr);
556 weston_log_continue("surface matrix type: %s\n", typestr);
557 matrix_type_str(output, typestr, sizeof typestr);
558 weston_log_continue("output matrix type: %s\n", typestr);
559}
560
561/*#define SURFACE_TRANSFORM */
562
563static int
Jason Ekstranda7af7042013-10-12 22:38:11 -0500564rpir_view_compute_rects(struct rpir_view *view,
565 VC_RECT_T *src_rect, VC_RECT_T *dst_rect,
566 VC_IMAGE_TRANSFORM_T *flipmask)
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300567{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500568 struct weston_output *output_base = view->view->surface->output;
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300569 struct rpir_output *output = to_rpir_output(output_base);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500570 struct weston_matrix matrix = view->view->transform.matrix;
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300571 VC_IMAGE_TRANSFORM_T flipt = 0;
572 int src_x, src_y;
573 int dst_x, dst_y;
574 int src_width, src_height;
575 int dst_width, dst_height;
576 struct weston_vector p1 = {{ 0.0f, 0.0f, 0.0f, 1.0f }};
577 struct weston_vector p2 = {{ 0.0f, 0.0f, 0.0f, 1.0f }};
578 int t;
579 int over;
580
581 /* XXX: take buffer transform into account */
582
583 /* src is in 16.16, dst is in 32.0 fixed point.
584 * Negative values are not allowed in VC_RECT_T.
585 * Clip size to output boundaries, firmware ignores
586 * huge elements like 8192x8192.
587 */
588
589 src_x = 0 << 16;
590 src_y = 0 << 16;
Tomeu Vizosob4659eb2013-10-07 11:02:20 +0200591
Jason Ekstranda7af7042013-10-12 22:38:11 -0500592 if (view->surface->buffer_type == BUFFER_TYPE_EGL) {
593 struct weston_buffer *buffer =
594 view->surface->egl_front->buffer_ref.buffer;
Tomeu Vizosob4659eb2013-10-07 11:02:20 +0200595
596 src_width = buffer->width << 16;
597 src_height = buffer->height << 16;
598 } else {
Jason Ekstranda7af7042013-10-12 22:38:11 -0500599 src_width = view->surface->front->width << 16;
600 src_height = view->surface->front->height << 16;
Tomeu Vizosob4659eb2013-10-07 11:02:20 +0200601 }
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300602
603 weston_matrix_multiply(&matrix, &output->matrix);
604
605#ifdef SURFACE_TRANSFORM
606 if (matrix.type >= WESTON_MATRIX_TRANSFORM_OTHER) {
607#else
608 if (matrix.type >= WESTON_MATRIX_TRANSFORM_ROTATE) {
609#endif
610 warn_bad_matrix(&matrix, &output->matrix,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500611 &view->view->transform.matrix);
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300612 } else {
613 if (matrix.type & WESTON_MATRIX_TRANSFORM_ROTATE) {
614 if (fabsf(matrix.d[0]) < 1e-4f &&
615 fabsf(matrix.d[5]) < 1e-4f) {
616 flipt |= TRANSFORM_TRANSPOSE;
617 } else if (fabsf(matrix.d[1]) < 1e-4 &&
618 fabsf(matrix.d[4]) < 1e-4) {
619 /* no transpose */
620 } else {
621 warn_bad_matrix(&matrix, &output->matrix,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500622 &view->view->transform.matrix);
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300623 }
624 }
625 }
626
Jason Ekstranda7af7042013-10-12 22:38:11 -0500627 p2.f[0] = view->view->geometry.width;
628 p2.f[1] = view->view->geometry.height;
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300629
630 /* transform top-left and bot-right corner into screen coordinates */
631 weston_matrix_transform(&matrix, &p1);
632 weston_matrix_transform(&matrix, &p2);
633
634 /* Compute the destination rectangle on screen, converting
635 * negative dimensions to flips.
636 */
637
638 dst_width = round(p2.f[0] - p1.f[0]);
639 if (dst_width < 0) {
640 dst_x = round(p2.f[0]);
641 dst_width = -dst_width;
642
643 if (!(flipt & TRANSFORM_TRANSPOSE))
644 flipt |= TRANSFORM_HFLIP;
645 else
646 flipt |= TRANSFORM_VFLIP;
647 } else {
648 dst_x = round(p1.f[0]);
649 }
650
651 dst_height = round(p2.f[1] - p1.f[1]);
652 if (dst_height < 0) {
653 dst_y = round(p2.f[1]);
654 dst_height = -dst_height;
655
656 if (!(flipt & TRANSFORM_TRANSPOSE))
657 flipt |= TRANSFORM_VFLIP;
658 else
659 flipt |= TRANSFORM_HFLIP;
660 } else {
661 dst_y = round(p1.f[1]);
662 }
663
664 if (dst_width == 0 || dst_height == 0) {
665 DBG("ignored, zero surface area before clipping\n");
666 return -1;
667 }
668
669#ifdef SURFACE_TRANSFORM
670 /* Dispmanx works as if you flipped the whole screen, when
671 * you flip an element. But, we want to flip an element in place.
672 * XXX: fixme
673 */
674 if (flipt & TRANSFORM_HFLIP)
675 dst_x = output_base->width - dst_x;
676 if (flipt & TRANSFORM_VFLIP)
677 dst_y = output_base->height - dst_y;
678 if (flipt & TRANSFORM_TRANSPOSE) {
679 int_swap(&dst_x, &dst_y);
680 int_swap(&dst_width, &dst_height);
681 }
682#else
683 switch (output_base->transform) {
684 case WL_OUTPUT_TRANSFORM_FLIPPED:
685 flipt = TRANSFORM_HFLIP;
686 break;
687 case WL_OUTPUT_TRANSFORM_NORMAL:
688 flipt = 0;
689 break;
690
691 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
692 flipt = TRANSFORM_HFLIP | TRANSFORM_VFLIP | TRANSFORM_TRANSPOSE;
693 break;
694 case WL_OUTPUT_TRANSFORM_90:
695 flipt = TRANSFORM_VFLIP | TRANSFORM_TRANSPOSE;
696 break;
697 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
698 flipt = TRANSFORM_VFLIP;
699 break;
700 case WL_OUTPUT_TRANSFORM_180:
701 flipt = TRANSFORM_HFLIP | TRANSFORM_VFLIP;
702 break;
703
704 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
705 flipt = TRANSFORM_TRANSPOSE;
706 break;
707 case WL_OUTPUT_TRANSFORM_270:
708 flipt = TRANSFORM_HFLIP | TRANSFORM_TRANSPOSE;
709 break;
710 default:
711 break;
712 }
713#endif
714
715 /* clip destination rectangle to screen dimensions */
716
717 if (dst_x < 0) {
718 t = (int64_t)dst_x * src_width / dst_width;
719 src_width += t;
720 dst_width += dst_x;
721 src_x -= t;
722 dst_x = 0;
723 }
724
725 if (dst_y < 0) {
726 t = (int64_t)dst_y * src_height / dst_height;
727 src_height += t;
728 dst_height += dst_y;
729 src_y -= t;
730 dst_y = 0;
731 }
732
733 over = dst_x + dst_width - output_base->width;
734 if (over > 0) {
735 t = (int64_t)over * src_width / dst_width;
736 src_width -= t;
737 dst_width -= over;
738 }
739
740 over = dst_y + dst_height - output_base->height;
741 if (over > 0) {
742 t = (int64_t)over * src_height / dst_height;
743 src_height -= t;
744 dst_height -= over;
745 }
746
747 src_width = int_max(src_width, 0);
748 src_height = int_max(src_height, 0);
749
Jason Ekstranda7af7042013-10-12 22:38:11 -0500750 DBG("rpir_view %p %dx%d: p1 %f, %f; p2 %f, %f\n", view,
751 view->view->geometry.width,
752 view->view->geometry.height,
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300753 p1.f[0], p1.f[1], p2.f[0], p2.f[1]);
754 DBG("src rect %d;%d, %d;%d, %d;%dx%d;%d\n",
755 src_x >> 16, src_x & 0xffff,
756 src_y >> 16, src_y & 0xffff,
757 src_width >> 16, src_width & 0xffff,
758 src_height >> 16, src_height & 0xffff);
759 DBG("dest rect %d, %d, %dx%d%s%s%s\n",
760 dst_x, dst_y, dst_width, dst_height,
761 (flipt & TRANSFORM_HFLIP) ? " hflip" : "",
762 (flipt & TRANSFORM_VFLIP) ? " vflip" : "",
763 (flipt & TRANSFORM_TRANSPOSE) ? " transp" : "");
764
765 assert(src_x >= 0);
766 assert(src_y >= 0);
767 assert(dst_x >= 0);
768 assert(dst_y >= 0);
769
770 if (dst_width < 1 || dst_height < 1) {
771 DBG("ignored, zero surface area after clipping\n");
772 return -1;
773 }
774
Tomeu Vizosob4659eb2013-10-07 11:02:20 +0200775 /* EGL buffers will be upside-down related to what DispmanX expects */
Jason Ekstranda7af7042013-10-12 22:38:11 -0500776 if (view->surface->buffer_type == BUFFER_TYPE_EGL)
Tomeu Vizosob4659eb2013-10-07 11:02:20 +0200777 flipt ^= TRANSFORM_VFLIP;
778
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300779 vc_dispmanx_rect_set(src_rect, src_x, src_y, src_width, src_height);
780 vc_dispmanx_rect_set(dst_rect, dst_x, dst_y, dst_width, dst_height);
781 *flipmask = flipt;
782
783 return 0;
784}
785
786static DISPMANX_TRANSFORM_T
787vc_image2dispmanx_transform(VC_IMAGE_TRANSFORM_T t)
788{
789 /* XXX: uhh, are these right? */
790 switch (t) {
791 case VC_IMAGE_ROT0:
792 return DISPMANX_NO_ROTATE;
793 case VC_IMAGE_MIRROR_ROT0:
794 return DISPMANX_FLIP_HRIZ;
795 case VC_IMAGE_MIRROR_ROT180:
796 return DISPMANX_FLIP_VERT;
797 case VC_IMAGE_ROT180:
798 return DISPMANX_ROTATE_180;
799 case VC_IMAGE_MIRROR_ROT90:
800 return DISPMANX_ROTATE_90 | DISPMANX_FLIP_HRIZ;
801 case VC_IMAGE_ROT270:
802 return DISPMANX_ROTATE_270;
803 case VC_IMAGE_ROT90:
804 return DISPMANX_ROTATE_90;
805 case VC_IMAGE_MIRROR_ROT270:
806 return DISPMANX_ROTATE_270 | DISPMANX_FLIP_VERT;
807 default:
808 assert(0 && "bad VC_IMAGE_TRANSFORM_T");
809 return DISPMANX_NO_ROTATE;
810 }
811}
812
Tomeu Vizosob4659eb2013-10-07 11:02:20 +0200813
814static DISPMANX_RESOURCE_HANDLE_T
815rpir_surface_get_resource(struct rpir_surface *surface)
816{
817 switch (surface->buffer_type) {
818 case BUFFER_TYPE_SHM:
819 case BUFFER_TYPE_NULL:
820 return surface->front->handle;
821 case BUFFER_TYPE_EGL:
822 if (surface->egl_front != NULL)
823 return surface->egl_front->resource_handle;
824 default:
825 return DISPMANX_NO_HANDLE;
826 }
827}
828
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300829static int
Jason Ekstranda7af7042013-10-12 22:38:11 -0500830rpir_view_dmx_add(struct rpir_view *view, struct rpir_output *output,
831 DISPMANX_UPDATE_HANDLE_T update, int layer)
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300832{
833 /* Do not use DISPMANX_FLAGS_ALPHA_PREMULT here.
834 * If you define PREMULT and ALPHA_MIX, the hardware will not
835 * multiply the source color with the element alpha, leading to
836 * bad colors. Instead, we define PREMULT during pixel data upload.
837 */
838 VC_DISPMANX_ALPHA_T alphasetup = {
839 DISPMANX_FLAGS_ALPHA_FROM_SOURCE |
840 DISPMANX_FLAGS_ALPHA_MIX,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500841 float2uint8(view->view->alpha), /* opacity 0-255 */
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300842 0 /* mask resource handle */
843 };
844 VC_RECT_T dst_rect;
845 VC_RECT_T src_rect;
846 VC_IMAGE_TRANSFORM_T flipmask;
847 int ret;
Tomeu Vizosob4659eb2013-10-07 11:02:20 +0200848 DISPMANX_RESOURCE_HANDLE_T resource_handle;
849
Jason Ekstranda7af7042013-10-12 22:38:11 -0500850 resource_handle = rpir_surface_get_resource(view->surface);
Tomeu Vizosob4659eb2013-10-07 11:02:20 +0200851 if (resource_handle == DISPMANX_NO_HANDLE) {
852 weston_log("%s: no buffer yet, aborting\n", __func__);
853 return 0;
854 }
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300855
Jason Ekstranda7af7042013-10-12 22:38:11 -0500856 ret = rpir_view_compute_rects(view, &src_rect, &dst_rect, &flipmask);
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300857 if (ret < 0)
858 return 0;
859
Jason Ekstranda7af7042013-10-12 22:38:11 -0500860 view->handle = vc_dispmanx_element_add(
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300861 update,
862 output->display,
863 layer,
864 &dst_rect,
Tomeu Vizosob4659eb2013-10-07 11:02:20 +0200865 resource_handle,
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300866 &src_rect,
867 DISPMANX_PROTECTION_NONE,
868 &alphasetup,
869 NULL /* clamp */,
870 vc_image2dispmanx_transform(flipmask));
Jason Ekstranda7af7042013-10-12 22:38:11 -0500871 DBG("rpir_surface %p add %u, alpha %f resource %d\n", view,
872 view->handle, view->view->alpha, resource_handle);
873
874 if (view->handle == DISPMANX_NO_HANDLE)
875 return -1;
876
877 view->surface->visible_views++;
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300878
879 return 1;
880}
881
882static void
Jason Ekstranda7af7042013-10-12 22:38:11 -0500883rpir_view_dmx_swap(struct rpir_view *view,
884 DISPMANX_UPDATE_HANDLE_T update)
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300885{
886 VC_RECT_T rect;
887 pixman_box32_t *r;
888
889 /* XXX: skip, iff resource was not reallocated, and single-buffering */
Jason Ekstranda7af7042013-10-12 22:38:11 -0500890 vc_dispmanx_element_change_source(update, view->handle,
891 view->surface->front->handle);
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300892
893 /* This is current damage now, after rpir_surface_damage() */
Jason Ekstranda7af7042013-10-12 22:38:11 -0500894 r = pixman_region32_extents(&view->surface->prev_damage);
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300895
896 vc_dispmanx_rect_set(&rect, r->x1, r->y1,
897 r->x2 - r->x1, r->y2 - r->y1);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500898 vc_dispmanx_element_modified(update, view->handle, &rect);
899 DBG("rpir_view %p swap\n", view);
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300900}
901
902static int
Jason Ekstranda7af7042013-10-12 22:38:11 -0500903rpir_view_dmx_move(struct rpir_view *view,
904 DISPMANX_UPDATE_HANDLE_T update, int layer)
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300905{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500906 uint8_t alpha = float2uint8(view->view->alpha);
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300907 VC_RECT_T dst_rect;
908 VC_RECT_T src_rect;
909 VC_IMAGE_TRANSFORM_T flipmask;
910 int ret;
911
912 /* XXX: return early, if all attributes stay the same */
913
Jason Ekstranda7af7042013-10-12 22:38:11 -0500914 if (view->surface->buffer_type == BUFFER_TYPE_EGL) {
Tomeu Vizosob4659eb2013-10-07 11:02:20 +0200915 DISPMANX_RESOURCE_HANDLE_T resource_handle;
916
Jason Ekstranda7af7042013-10-12 22:38:11 -0500917 resource_handle = rpir_surface_get_resource(view->surface);
Tomeu Vizosob4659eb2013-10-07 11:02:20 +0200918 if (resource_handle == DISPMANX_NO_HANDLE) {
919 weston_log("%s: no buffer yet, aborting\n", __func__);
920 return 0;
921 }
922
923 vc_dispmanx_element_change_source(update,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500924 view->handle,
Tomeu Vizosob4659eb2013-10-07 11:02:20 +0200925 resource_handle);
926 }
927
Jason Ekstranda7af7042013-10-12 22:38:11 -0500928 ret = rpir_view_compute_rects(view, &src_rect, &dst_rect, &flipmask);
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300929 if (ret < 0)
930 return 0;
931
932 ret = vc_dispmanx_element_change_attributes(
933 update,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500934 view->handle,
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300935 ELEMENT_CHANGE_LAYER |
936 ELEMENT_CHANGE_OPACITY |
937 ELEMENT_CHANGE_TRANSFORM |
938 ELEMENT_CHANGE_DEST_RECT |
939 ELEMENT_CHANGE_SRC_RECT,
940 layer,
941 alpha,
942 &dst_rect,
943 &src_rect,
944 DISPMANX_NO_HANDLE,
945 /* This really is DISPMANX_TRANSFORM_T, no matter
946 * what the header says. */
947 vc_image2dispmanx_transform(flipmask));
Jason Ekstranda7af7042013-10-12 22:38:11 -0500948 DBG("rpir_view %p move\n", view);
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300949
950 if (ret)
951 return -1;
952
953 return 1;
954}
955
956static void
Jason Ekstranda7af7042013-10-12 22:38:11 -0500957rpir_view_dmx_remove(struct rpir_view *view,
958 DISPMANX_UPDATE_HANDLE_T update)
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300959{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500960 if (view->handle == DISPMANX_NO_HANDLE)
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300961 return;
962
Jason Ekstranda7af7042013-10-12 22:38:11 -0500963 vc_dispmanx_element_remove(update, view->handle);
964 DBG("rpir_view %p remove %u\n", view, view->handle);
965 view->handle = DISPMANX_NO_HANDLE;
966 view->surface->visible_views--;
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300967}
968
969static void
970rpir_surface_swap_pointers(struct rpir_surface *surface)
971{
972 struct rpi_resource *tmp;
973
Tomeu Vizosob4659eb2013-10-07 11:02:20 +0200974 if (surface->buffer_type == BUFFER_TYPE_EGL) {
975 if (surface->egl_back != NULL) {
976 assert(surface->egl_old_front == NULL);
977 surface->egl_old_front = surface->egl_front;
978 surface->egl_front = surface->egl_back;
979 surface->egl_back = NULL;
Tomeu Vizoso15767812013-10-24 15:38:31 +0200980 DBG("new front %d\n", surface->egl_front->resource_handle);
Tomeu Vizosob4659eb2013-10-07 11:02:20 +0200981 }
Tomeu Vizosob4659eb2013-10-07 11:02:20 +0200982 } else {
Jason Ekstranda7af7042013-10-12 22:38:11 -0500983 tmp = surface->front;
984 surface->front = surface->back;
985 surface->back = tmp;
Tomeu Vizoso15767812013-10-24 15:38:31 +0200986 DBG("new back %p, new front %p\n", surface->back, surface->front);
Tomeu Vizosob4659eb2013-10-07 11:02:20 +0200987 }
Jason Ekstranda7af7042013-10-12 22:38:11 -0500988}
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300989
Jason Ekstranda7af7042013-10-12 22:38:11 -0500990static int
991is_view_not_visible(struct weston_view *view)
992{
993 /* Return true, if surface is guaranteed to be totally obscured. */
994 int ret;
995 pixman_region32_t unocc;
996
997 pixman_region32_init(&unocc);
998 pixman_region32_subtract(&unocc, &view->transform.boundingbox,
999 &view->clip);
1000 ret = !pixman_region32_not_empty(&unocc);
1001 pixman_region32_fini(&unocc);
1002
1003 return ret;
1004}
1005
1006static void
1007rpir_view_update(struct rpir_view *view, struct rpir_output *output,
1008 DISPMANX_UPDATE_HANDLE_T update, int layer)
1009{
1010 int ret;
1011 int obscured;
1012
Jason Ekstranda7af7042013-10-12 22:38:11 -05001013 obscured = is_view_not_visible(view->view);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001014 if (obscured) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05001015 DBG("rpir_view %p totally obscured.\n", view);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001016
Jason Ekstranda7af7042013-10-12 22:38:11 -05001017 wl_list_remove(&view->link);
1018 if (view->handle == DISPMANX_NO_HANDLE) {
1019 wl_list_init(&view->link);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001020 } else {
Jason Ekstranda7af7042013-10-12 22:38:11 -05001021 rpir_view_dmx_remove(view, update);
1022 wl_list_insert(&output->view_cleanup_list,
1023 &view->link);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001024 }
1025
1026 goto out;
1027 }
1028
Jason Ekstranda7af7042013-10-12 22:38:11 -05001029 if (view->handle == DISPMANX_NO_HANDLE) {
1030 ret = rpir_view_dmx_add(view, output, update, layer);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001031 if (ret == 0) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05001032 wl_list_remove(&view->link);
1033 wl_list_init(&view->link);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001034 } else if (ret < 0) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05001035 weston_log("ERROR rpir_view_dmx_add() failed.\n");
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001036 }
1037 } else {
Jason Ekstranda7af7042013-10-12 22:38:11 -05001038 if (view->surface->need_swap)
1039 rpir_view_dmx_swap(view, update);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001040
Jason Ekstranda7af7042013-10-12 22:38:11 -05001041 ret = rpir_view_dmx_move(view, update, layer);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001042 if (ret == 0) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05001043 rpir_view_dmx_remove(view, update);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001044
Jason Ekstranda7af7042013-10-12 22:38:11 -05001045 wl_list_remove(&view->link);
1046 wl_list_insert(&output->view_cleanup_list,
1047 &view->link);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001048 } else if (ret < 0) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05001049 weston_log("ERROR rpir_view_dmx_move() failed.\n");
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001050 }
1051 }
1052
1053out:
Jason Ekstranda7af7042013-10-12 22:38:11 -05001054 view->layer = layer;
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001055}
1056
1057static int
1058rpi_renderer_read_pixels(struct weston_output *base,
1059 pixman_format_code_t format, void *pixels,
1060 uint32_t x, uint32_t y,
1061 uint32_t width, uint32_t height)
1062{
1063 struct rpir_output *output = to_rpir_output(base);
1064 struct rpi_resource *buffer = &output->capture_buffer;
1065 VC_RECT_T rect;
1066 uint32_t fb_width, fb_height;
1067 uint32_t dst_pitch;
1068 uint32_t i;
1069 int ret;
1070
Hardeningff39efa2013-09-18 23:56:35 +02001071 fb_width = base->current_mode->width;
1072 fb_height = base->current_mode->height;
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001073
1074 DBG("%s(%u, %u, %u, %u), resource %p\n", __func__,
1075 x, y, width, height, buffer);
1076
1077 if (format != PIXMAN_a8r8g8b8) {
1078 weston_log("rpi-renderer error: bad read_format\n");
1079 return -1;
1080 }
1081
1082 dst_pitch = fb_width * 4;
1083
1084 if (buffer->handle == DISPMANX_NO_HANDLE) {
1085 free(output->capture_data);
1086 output->capture_data = NULL;
1087
1088 ret = rpi_resource_realloc(buffer, VC_IMAGE_ARGB8888,
1089 fb_width, fb_height,
1090 dst_pitch, fb_height);
1091 if (ret < 0) {
1092 weston_log("rpi-renderer error: "
1093 "allocating read buffer failed\n");
1094 return -1;
1095 }
1096
1097 ret = vc_dispmanx_snapshot(output->display, buffer->handle,
1098 VC_IMAGE_ROT0);
1099 if (ret) {
1100 weston_log("rpi-renderer error: "
1101 "vc_dispmanx_snapshot returned %d\n", ret);
1102 return -1;
1103 }
1104 DBG("%s: snapshot done.\n", __func__);
1105 }
1106
1107 /*
1108 * If vc_dispmanx_resource_read_data was able to read sub-rectangles,
1109 * we could read directly into 'pixels'. But it cannot, it does not
1110 * use rect.x or rect.width, and does this:
1111 * host_start = (uint8_t *)dst_address + (dst_pitch * p_rect->y);
1112 * In other words, it is only good for reading the full buffer in
1113 * one go.
1114 */
1115 vc_dispmanx_rect_set(&rect, 0, 0, fb_width, fb_height);
1116
1117 if (x == 0 && y == 0 && width == fb_width && height == fb_height) {
1118 ret = vc_dispmanx_resource_read_data(buffer->handle, &rect,
1119 pixels, dst_pitch);
1120 if (ret) {
1121 weston_log("rpi-renderer error: "
1122 "resource_read_data returned %d\n", ret);
1123 return -1;
1124 }
1125 DBG("%s: full frame done.\n", __func__);
1126 return 0;
1127 }
1128
1129 if (!output->capture_data) {
1130 output->capture_data = malloc(fb_height * dst_pitch);
1131 if (!output->capture_data) {
1132 weston_log("rpi-renderer error: "
1133 "out of memory\n");
1134 return -1;
1135 }
1136
1137 ret = vc_dispmanx_resource_read_data(buffer->handle, &rect,
1138 output->capture_data,
1139 dst_pitch);
1140 if (ret) {
1141 weston_log("rpi-renderer error: "
1142 "resource_read_data returned %d\n", ret);
1143 return -1;
1144 }
1145 }
1146
1147 for (i = 0; i < height; i++) {
1148 uint8_t *src = output->capture_data +
1149 (y + i) * dst_pitch + x * 4;
1150 uint8_t *dst = (uint8_t *)pixels + i * width * 4;
1151 memcpy(dst, src, width * 4);
1152 }
1153
1154 return 0;
1155}
1156
1157static void
1158rpir_output_dmx_remove_all(struct rpir_output *output,
1159 DISPMANX_UPDATE_HANDLE_T update)
1160{
Jason Ekstranda7af7042013-10-12 22:38:11 -05001161 struct rpir_view *view;
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001162
Jason Ekstranda7af7042013-10-12 22:38:11 -05001163 while (!wl_list_empty(&output->view_list)) {
1164 view = container_of(output->view_list.next,
1165 struct rpir_view, link);
1166 rpir_view_dmx_remove(view, update);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001167
Jason Ekstranda7af7042013-10-12 22:38:11 -05001168 wl_list_remove(&view->link);
1169 wl_list_insert(&output->view_cleanup_list, &view->link);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001170 }
1171}
1172
1173static void
1174output_compute_matrix(struct weston_output *base)
1175{
1176 struct rpir_output *output = to_rpir_output(base);
1177 struct weston_matrix *matrix = &output->matrix;
1178 const float half_w = 0.5f * base->width;
1179 const float half_h = 0.5f * base->height;
1180 float mag;
1181 float dx, dy;
1182
1183 weston_matrix_init(matrix);
1184 weston_matrix_translate(matrix, -base->x, -base->y, 0.0f);
1185
1186#ifdef SURFACE_TRANSFORM
1187 weston_matrix_translate(matrix, -half_w, -half_h, 0.0f);
1188 switch (base->transform) {
1189 case WL_OUTPUT_TRANSFORM_FLIPPED:
1190 weston_matrix_scale(matrix, -1.0f, 1.0f, 1.0f);
1191 case WL_OUTPUT_TRANSFORM_NORMAL:
1192 /* weston_matrix_rotate_xy(matrix, 1.0f, 0.0f); no-op */
1193 weston_matrix_translate(matrix, half_w, half_h, 0.0f);
1194 break;
1195
1196 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
1197 weston_matrix_scale(matrix, -1.0f, 1.0f, 1.0f);
1198 case WL_OUTPUT_TRANSFORM_90:
1199 weston_matrix_rotate_xy(matrix, 0.0f, 1.0f);
1200 weston_matrix_translate(matrix, half_h, half_w, 0.0f);
1201 break;
1202
1203 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
1204 weston_matrix_scale(matrix, -1.0f, 1.0f, 1.0f);
1205 case WL_OUTPUT_TRANSFORM_180:
1206 weston_matrix_rotate_xy(matrix, -1.0f, 0.0f);
1207 weston_matrix_translate(matrix, half_w, half_h, 0.0f);
1208 break;
1209
1210 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
1211 weston_matrix_scale(matrix, -1.0f, 1.0f, 1.0f);
1212 case WL_OUTPUT_TRANSFORM_270:
1213 weston_matrix_rotate_xy(matrix, 0.0f, -1.0f);
1214 weston_matrix_translate(matrix, half_h, half_w, 0.0f);
1215 break;
1216
1217 default:
1218 break;
1219 }
1220#endif
1221
1222 if (base->zoom.active) {
1223 /* The base->zoom stuff is in GL coordinate system */
1224 mag = 1.0f / (1.0f - base->zoom.spring_z.current);
1225 dx = -(base->zoom.trans_x + 1.0f) * half_w;
1226 dy = -(base->zoom.trans_y + 1.0f) * half_h;
1227 weston_matrix_translate(matrix, dx, dy, 0.0f);
1228 weston_matrix_scale(matrix, mag, mag, 1.0f);
1229 weston_matrix_translate(matrix, half_w, half_h, 0.0f);
1230 }
1231}
1232
1233/* Note: this won't work right for multiple outputs. A DispmanX Element
1234 * is tied to one DispmanX Display, i.e. output.
1235 */
1236static void
1237rpi_renderer_repaint_output(struct weston_output *base,
1238 pixman_region32_t *output_damage)
1239{
1240 struct weston_compositor *compositor = base->compositor;
1241 struct rpir_output *output = to_rpir_output(base);
Jason Ekstranda7af7042013-10-12 22:38:11 -05001242 struct weston_view *wv;
1243 struct rpir_view *view;
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001244 struct wl_list done_list;
1245 int layer = 1;
1246
1247 assert(output->update != DISPMANX_NO_HANDLE);
1248
1249 output_compute_matrix(base);
1250
1251 rpi_resource_release(&output->capture_buffer);
1252 free(output->capture_data);
1253 output->capture_data = NULL;
1254
Jason Ekstranda7af7042013-10-12 22:38:11 -05001255 /* Swap resources on surfaces as needed */
1256 wl_list_for_each_reverse(wv, &compositor->view_list, link)
1257 wv->surface->touched = 0;
1258
1259 wl_list_for_each_reverse(wv, &compositor->view_list, link) {
1260 view = to_rpir_view(wv);
1261
1262 if (!wv->surface->touched) {
1263 wv->surface->touched = 1;
1264
Tomeu Vizoso44247742013-10-24 15:38:32 +02001265 if (view->surface->buffer_type == BUFFER_TYPE_EGL ||
1266 view->surface->need_swap)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001267 rpir_surface_swap_pointers(view->surface);
1268 }
1269
Tomeu Vizoso74987582013-10-25 10:34:38 +02001270 if (view->surface->buffer_type == BUFFER_TYPE_EGL) {
1271 struct weston_buffer *buffer;
1272 buffer = view->surface->egl_front->buffer_ref.buffer;
1273 if (buffer != NULL) {
1274 vc_dispmanx_set_wl_buffer_in_use(buffer->resource, 1);
Jason Ekstranda7af7042013-10-12 22:38:11 -05001275 } else {
Tomeu Vizoso74987582013-10-25 10:34:38 +02001276 weston_log("warning: client destroyed current front buffer\n");
1277
1278 wl_list_remove(&view->link);
1279 if (view->handle == DISPMANX_NO_HANDLE) {
1280 wl_list_init(&view->link);
1281 } else {
1282 rpir_view_dmx_remove(view, output->update);
1283 wl_list_insert(&output->view_cleanup_list,
1284 &view->link);
1285 }
Jason Ekstranda7af7042013-10-12 22:38:11 -05001286 }
1287 }
1288 }
1289
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001290 /* update all renderable surfaces */
1291 wl_list_init(&done_list);
Jason Ekstranda7af7042013-10-12 22:38:11 -05001292 wl_list_for_each_reverse(wv, &compositor->view_list, link) {
1293 if (wv->plane != &compositor->primary_plane)
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001294 continue;
1295
Jason Ekstranda7af7042013-10-12 22:38:11 -05001296 view = to_rpir_view(wv);
1297 assert(!wl_list_empty(&view->link) ||
1298 view->handle == DISPMANX_NO_HANDLE);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001299
Jason Ekstranda7af7042013-10-12 22:38:11 -05001300 wl_list_remove(&view->link);
1301 wl_list_insert(&done_list, &view->link);
1302 rpir_view_update(view, output, output->update, layer++);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001303 }
1304
Jason Ekstranda7af7042013-10-12 22:38:11 -05001305 /* Mark all surfaces as swapped */
1306 wl_list_for_each_reverse(wv, &compositor->view_list, link)
1307 to_rpir_surface(wv->surface)->need_swap = 0;
1308
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001309 /* Remove all surfaces that are still on screen, but were
1310 * not rendered this time.
1311 */
1312 rpir_output_dmx_remove_all(output, output->update);
1313
Jason Ekstranda7af7042013-10-12 22:38:11 -05001314 wl_list_insert_list(&output->view_list, &done_list);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001315 output->update = DISPMANX_NO_HANDLE;
1316
1317 /* The frame_signal is emitted in rpi_renderer_finish_frame(),
1318 * so that the firmware can capture the up-to-date contents.
1319 */
1320}
1321
1322static void
1323rpi_renderer_flush_damage(struct weston_surface *base)
1324{
1325 /* Called for every surface just before repainting it, if
1326 * having an shm buffer.
1327 */
1328 struct rpir_surface *surface = to_rpir_surface(base);
Jason Ekstrand6bd62942013-06-20 20:38:23 -05001329 struct weston_buffer *buffer = surface->buffer_ref.buffer;
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001330 int ret;
1331
1332 assert(buffer);
Jason Ekstrand6bd62942013-06-20 20:38:23 -05001333 assert(wl_shm_buffer_get(buffer->resource));
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001334
1335 ret = rpir_surface_damage(surface, buffer, &base->damage);
1336 if (ret)
1337 weston_log("%s error: updating Dispmanx resource failed.\n",
1338 __func__);
1339
1340 weston_buffer_reference(&surface->buffer_ref, NULL);
1341}
1342
1343static void
Jason Ekstrand6bd62942013-06-20 20:38:23 -05001344rpi_renderer_attach(struct weston_surface *base, struct weston_buffer *buffer)
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001345{
1346 /* Called every time a client commits an attach. */
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001347 struct rpir_surface *surface = to_rpir_surface(base);
1348
1349 assert(surface);
1350 if (!surface)
1351 return;
1352
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001353 if (surface->buffer_type == BUFFER_TYPE_SHM) {
1354 if (!surface->single_buffer)
1355 /* XXX: need to check if in middle of update */
1356 rpi_resource_release(surface->back);
1357
Jason Ekstranda7af7042013-10-12 22:38:11 -05001358 if (!surface->visible_views)
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001359 /* XXX: cannot do this, if middle of an update */
1360 rpi_resource_release(surface->front);
1361
1362 weston_buffer_reference(&surface->buffer_ref, NULL);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001363 }
1364
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001365 /* If buffer is NULL, Weston core unmaps the surface, the surface
1366 * will not appear in repaint list, and so rpi_renderer_repaint_output
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001367 * will remove the DispmanX element. Later, for SHM, also the front
1368 * buffer will be released in the cleanup_list processing.
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001369 */
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001370 if (!buffer)
1371 return;
1372
1373 if (wl_shm_buffer_get(buffer->resource)) {
1374 surface->buffer_type = BUFFER_TYPE_SHM;
1375 buffer->shm_buffer = wl_shm_buffer_get(buffer->resource);
1376 buffer->width = wl_shm_buffer_get_width(buffer->shm_buffer);
1377 buffer->height = wl_shm_buffer_get_height(buffer->shm_buffer);
1378
1379 weston_buffer_reference(&surface->buffer_ref, buffer);
1380 } else {
1381#if ENABLE_EGL
1382 struct rpi_renderer *renderer = to_rpi_renderer(base->compositor);
Tomeu Vizosoa8e5f292013-10-09 11:29:45 +02001383 struct wl_resource *wl_resource = buffer->resource;
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001384
1385 if (!renderer->has_bind_display ||
1386 !renderer->query_buffer(renderer->egl_display,
1387 wl_resource,
1388 EGL_WIDTH, &buffer->width)) {
1389 weston_log("unhandled buffer type!\n");
1390 weston_buffer_reference(&surface->buffer_ref, NULL);
1391 surface->buffer_type = BUFFER_TYPE_NULL;
1392 }
1393
1394 renderer->query_buffer(renderer->egl_display,
1395 wl_resource,
1396 EGL_HEIGHT, &buffer->height);
1397
1398 surface->buffer_type = BUFFER_TYPE_EGL;
1399
1400 if(surface->egl_back == NULL)
1401 surface->egl_back = calloc(1, sizeof *surface->egl_back);
1402
1403 weston_buffer_reference(&surface->egl_back->buffer_ref, buffer);
1404 surface->egl_back->resource_handle =
1405 vc_dispmanx_get_handle_from_wl_buffer(wl_resource);
1406#else
1407 weston_log("unhandled buffer type!\n");
1408 weston_buffer_reference(&surface->buffer_ref, NULL);
1409 surface->buffer_type = BUFFER_TYPE_NULL;
1410#endif
1411 }
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001412}
1413
1414static int
1415rpi_renderer_create_surface(struct weston_surface *base)
1416{
1417 struct rpi_renderer *renderer = to_rpi_renderer(base->compositor);
1418 struct rpir_surface *surface;
1419
1420 assert(base->renderer_state == NULL);
1421
1422 surface = rpir_surface_create(renderer);
1423 if (!surface)
1424 return -1;
1425
1426 surface->surface = base;
1427 base->renderer_state = surface;
1428 return 0;
1429}
1430
Jason Ekstranda7af7042013-10-12 22:38:11 -05001431static int
1432rpi_renderer_create_view(struct weston_view *base)
1433{
1434 struct rpir_surface *surface = to_rpir_surface(base->surface);
1435 struct rpir_view *view;
1436
1437 assert(base->renderer_state == NULL);
1438
1439 view = rpir_view_create(surface);
1440 if (!view)
1441 return -1;
1442
1443 view->view = base;
1444 base->renderer_state = view;
1445 return 0;
1446}
1447
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001448static void
1449rpi_renderer_surface_set_color(struct weston_surface *base,
1450 float red, float green, float blue, float alpha)
1451{
1452 struct rpir_surface *surface = to_rpir_surface(base);
1453 uint8_t color[4];
1454 VC_RECT_T rect;
1455 int ret;
1456
1457 assert(surface);
1458
1459 ret = rpi_resource_realloc(surface->back, VC_IMAGE_ARGB8888,
1460 1, 1, 4, 1);
1461 if (ret < 0) {
1462 weston_log("Error: %s: rpi_resource_realloc failed.\n",
1463 __func__);
1464 return;
1465 }
1466
1467 color[0] = float2uint8(blue);
1468 color[1] = float2uint8(green);
1469 color[2] = float2uint8(red);
1470 color[3] = float2uint8(alpha);
1471
1472 vc_dispmanx_rect_set(&rect, 0, 0, 1, 1);
1473 ret = vc_dispmanx_resource_write_data(surface->back->handle,
1474 VC_IMAGE_ARGB8888,
1475 4, color, &rect);
1476 if (ret) {
1477 weston_log("Error: %s: resource_write_data failed.\n",
1478 __func__);
1479 return;
1480 }
1481
1482 DBG("%s: resource %p solid color BGRA %u,%u,%u,%u\n", __func__,
1483 surface->back, color[0], color[1], color[2], color[3]);
1484
1485 /*pixman_region32_copy(&surface->prev_damage, damage);*/
1486 surface->need_swap = 1;
1487}
1488
1489static void
1490rpi_renderer_destroy_surface(struct weston_surface *base)
1491{
1492 struct rpir_surface *surface = to_rpir_surface(base);
1493
1494 assert(surface);
1495 assert(surface->surface == base);
1496 if (!surface)
1497 return;
1498
1499 surface->surface = NULL;
1500 base->renderer_state = NULL;
1501
Jason Ekstranda7af7042013-10-12 22:38:11 -05001502 if (wl_list_empty(&surface->views))
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001503 rpir_surface_destroy(surface);
Jason Ekstranda7af7042013-10-12 22:38:11 -05001504}
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001505
Jason Ekstranda7af7042013-10-12 22:38:11 -05001506static void
1507rpi_renderer_destroy_view(struct weston_view *base)
1508{
1509 struct rpir_view *view = to_rpir_view(base);
1510
1511 assert(view);
1512 assert(view->view == base);
1513 if (!view)
1514 return;
1515
Tomeu Vizoso34dad7d2013-10-25 10:34:37 +02001516 view->view = NULL;
1517
Jason Ekstranda7af7042013-10-12 22:38:11 -05001518 /* If guaranteed to not be on screen, just detroy it. */
1519 if (wl_list_empty(&view->link))
1520 rpir_view_destroy(view);
1521
1522 /* Otherwise, the view is either on screen and needs
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001523 * to be removed by a repaint update, or it is in the
Jason Ekstranda7af7042013-10-12 22:38:11 -05001524 * view_cleanup_list, and will be destroyed by
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001525 * rpi_renderer_finish_frame().
1526 */
1527}
1528
1529static void
1530rpi_renderer_destroy(struct weston_compositor *compositor)
1531{
1532 struct rpi_renderer *renderer = to_rpi_renderer(compositor);
1533
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001534#if ENABLE_EGL
1535 if (renderer->has_bind_display)
1536 renderer->unbind_display(renderer->egl_display,
1537 compositor->wl_display);
1538#endif
1539
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001540 free(renderer);
1541 compositor->renderer = NULL;
1542}
1543
1544WL_EXPORT int
1545rpi_renderer_create(struct weston_compositor *compositor,
1546 const struct rpi_renderer_parameters *params)
1547{
1548 struct rpi_renderer *renderer;
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001549#if ENABLE_EGL
1550 const char *extensions;
1551 EGLBoolean ret;
1552 EGLint major, minor;
1553#endif
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001554
1555 weston_log("Initializing the DispmanX compositing renderer\n");
1556
1557 renderer = calloc(1, sizeof *renderer);
1558 if (renderer == NULL)
1559 return -1;
1560
1561 renderer->single_buffer = params->single_buffer;
1562
1563 renderer->base.read_pixels = rpi_renderer_read_pixels;
1564 renderer->base.repaint_output = rpi_renderer_repaint_output;
1565 renderer->base.flush_damage = rpi_renderer_flush_damage;
1566 renderer->base.attach = rpi_renderer_attach;
1567 renderer->base.create_surface = rpi_renderer_create_surface;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001568 renderer->base.create_view = rpi_renderer_create_view;
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001569 renderer->base.surface_set_color = rpi_renderer_surface_set_color;
1570 renderer->base.destroy_surface = rpi_renderer_destroy_surface;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001571 renderer->base.destroy_view = rpi_renderer_destroy_view;
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001572 renderer->base.destroy = rpi_renderer_destroy;
1573
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001574#ifdef ENABLE_EGL
1575 renderer->egl_display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
1576 if (renderer->egl_display == EGL_NO_DISPLAY) {
1577 weston_log("failed to create EGL display\n");
1578 return -1;
1579 }
1580
1581 if (!eglInitialize(renderer->egl_display, &major, &minor)) {
1582 weston_log("failed to initialize EGL display\n");
1583 return -1;
1584 }
1585
1586 renderer->bind_display =
1587 (void *) eglGetProcAddress("eglBindWaylandDisplayWL");
1588 renderer->unbind_display =
1589 (void *) eglGetProcAddress("eglUnbindWaylandDisplayWL");
1590 renderer->query_buffer =
1591 (void *) eglGetProcAddress("eglQueryWaylandBufferWL");
1592
1593 extensions = (const char *) eglQueryString(renderer->egl_display,
1594 EGL_EXTENSIONS);
1595 if (!extensions) {
1596 weston_log("Retrieving EGL extension string failed.\n");
1597 return -1;
1598 }
1599
1600 if (strstr(extensions, "EGL_WL_bind_wayland_display"))
1601 renderer->has_bind_display = 1;
1602
1603 if (renderer->has_bind_display) {
1604 ret = renderer->bind_display(renderer->egl_display,
1605 compositor->wl_display);
1606 if (!ret)
1607 renderer->has_bind_display = 0;
1608 }
1609#endif
1610
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001611 compositor->renderer = &renderer->base;
1612 compositor->read_format = PIXMAN_a8r8g8b8;
1613 /* WESTON_CAP_ROTATION_ANY not supported */
1614
Tomeu Vizoso03681892013-08-06 20:05:57 +02001615 wl_display_add_shm_format(compositor->wl_display, WL_SHM_FORMAT_RGB565);
1616
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001617 return 0;
1618}
1619
1620WL_EXPORT int
1621rpi_renderer_output_create(struct weston_output *base,
1622 DISPMANX_DISPLAY_HANDLE_T display)
1623{
1624 struct rpir_output *output;
1625
1626 assert(base->renderer_state == NULL);
1627
1628 output = calloc(1, sizeof *output);
1629 if (!output)
1630 return -1;
1631
1632 output->display = display;
1633 output->update = DISPMANX_NO_HANDLE;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001634 wl_list_init(&output->view_list);
1635 wl_list_init(&output->view_cleanup_list);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001636 rpi_resource_init(&output->capture_buffer);
1637 base->renderer_state = output;
1638
1639 return 0;
1640}
1641
1642WL_EXPORT void
1643rpi_renderer_output_destroy(struct weston_output *base)
1644{
1645 struct rpir_output *output = to_rpir_output(base);
Jason Ekstranda7af7042013-10-12 22:38:11 -05001646 struct rpir_view *view;
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001647 DISPMANX_UPDATE_HANDLE_T update;
1648
1649 rpi_resource_release(&output->capture_buffer);
1650 free(output->capture_data);
1651 output->capture_data = NULL;
1652
1653 update = vc_dispmanx_update_start(0);
1654 rpir_output_dmx_remove_all(output, update);
1655 vc_dispmanx_update_submit_sync(update);
1656
Jason Ekstranda7af7042013-10-12 22:38:11 -05001657 while (!wl_list_empty(&output->view_cleanup_list)) {
1658 view = container_of(output->view_cleanup_list.next,
1659 struct rpir_view, link);
1660 rpir_view_destroy(view);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001661 }
1662
1663 free(output);
1664 base->renderer_state = NULL;
1665}
1666
1667WL_EXPORT void
1668rpi_renderer_set_update_handle(struct weston_output *base,
1669 DISPMANX_UPDATE_HANDLE_T handle)
1670{
1671 struct rpir_output *output = to_rpir_output(base);
1672
1673 output->update = handle;
1674}
1675
1676WL_EXPORT void
1677rpi_renderer_finish_frame(struct weston_output *base)
1678{
1679 struct rpir_output *output = to_rpir_output(base);
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001680 struct weston_compositor *compositor = base->compositor;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001681 struct weston_view *wv;
1682 struct rpir_view *view;
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001683
Jason Ekstranda7af7042013-10-12 22:38:11 -05001684 while (!wl_list_empty(&output->view_cleanup_list)) {
1685 view = container_of(output->view_cleanup_list.next,
1686 struct rpir_view, link);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001687
Jason Ekstranda7af7042013-10-12 22:38:11 -05001688 if (view->view) {
1689 /* The weston_view still exists, but is
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001690 * temporarily not visible, and hence its Element
1691 * was removed. The current front buffer contents
1692 * must be preserved.
1693 */
Jason Ekstranda7af7042013-10-12 22:38:11 -05001694 if (!view->surface->visible_views)
1695 rpi_resource_release(view->surface->back);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001696
Jason Ekstranda7af7042013-10-12 22:38:11 -05001697 wl_list_remove(&view->link);
1698 wl_list_init(&view->link);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001699 } else {
Jason Ekstranda7af7042013-10-12 22:38:11 -05001700 rpir_view_destroy(view);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001701 }
1702 }
1703
Jason Ekstranda7af7042013-10-12 22:38:11 -05001704 wl_list_for_each(wv, &compositor->view_list, link) {
1705 view = to_rpir_view(wv);
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001706
Jason Ekstranda7af7042013-10-12 22:38:11 -05001707 if (view->surface->buffer_type != BUFFER_TYPE_EGL)
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001708 continue;
1709
Tomeu Vizoso74987582013-10-25 10:34:38 +02001710 rpir_egl_buffer_destroy(view->surface->egl_old_front);
Jason Ekstranda7af7042013-10-12 22:38:11 -05001711 view->surface->egl_old_front = NULL;
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001712 }
1713
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001714 wl_signal_emit(&base->frame_signal, base);
1715}