blob: 2b6d12c9465cffd4f41a0e440ca74427e5c819af [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;
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300123
124 struct wl_listener surface_destroy_listener;
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300125};
126
Jason Ekstranda7af7042013-10-12 22:38:11 -0500127struct rpir_view {
128 struct rpir_surface *surface;
129 struct wl_list surface_link;
130 struct weston_view *view;
131
132 /* If link is empty, the view is guaranteed to not be on screen,
133 * i.e. updates removing Elements have completed.
134 */
135 struct wl_list link;
136
137 DISPMANX_ELEMENT_HANDLE_T handle;
138 int layer;
Tomeu Vizoso96dc9e42013-10-28 10:17:45 +0100139
140 struct wl_listener view_destroy_listener;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500141};
142
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300143struct rpir_output {
144 DISPMANX_DISPLAY_HANDLE_T display;
145
146 DISPMANX_UPDATE_HANDLE_T update;
147 struct weston_matrix matrix;
148
149 /* all Elements currently on screen */
Jason Ekstranda7af7042013-10-12 22:38:11 -0500150 struct wl_list view_list; /* struct rpir_surface::link */
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300151
152 /* Elements just removed, waiting for update completion */
Jason Ekstranda7af7042013-10-12 22:38:11 -0500153 struct wl_list view_cleanup_list; /* struct rpir_surface::link */
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300154
155 struct rpi_resource capture_buffer;
156 uint8_t *capture_data;
157};
158
159struct rpi_renderer {
160 struct weston_renderer base;
161
162 int single_buffer;
Tomeu Vizosob4659eb2013-10-07 11:02:20 +0200163
164#ifdef ENABLE_EGL
165 EGLDisplay egl_display;
166
167 PFNEGLBINDWAYLANDDISPLAYWL bind_display;
168 PFNEGLUNBINDWAYLANDDISPLAYWL unbind_display;
169 PFNEGLQUERYWAYLANDBUFFERWL query_buffer;
170#endif
171 int has_bind_display;
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300172};
173
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300174static int
175rpi_renderer_create_surface(struct weston_surface *base);
176
Tomeu Vizoso96dc9e42013-10-28 10:17:45 +0100177static int
178rpi_renderer_create_view(struct weston_view *base);
179
180static void
181rpir_view_handle_view_destroy(struct wl_listener *listener, void *data);
182
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300183static inline struct rpir_surface *
184to_rpir_surface(struct weston_surface *surface)
185{
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300186 if (!surface->renderer_state)
187 rpi_renderer_create_surface(surface);
188
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300189 return surface->renderer_state;
190}
191
Jason Ekstranda7af7042013-10-12 22:38:11 -0500192static inline struct rpir_view *
193to_rpir_view(struct weston_view *view)
194{
Tomeu Vizoso96dc9e42013-10-28 10:17:45 +0100195 if (!view->renderer_state)
196 rpi_renderer_create_view(view);
197
Jason Ekstranda7af7042013-10-12 22:38:11 -0500198 return view->renderer_state;
199}
200
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300201static inline struct rpir_output *
202to_rpir_output(struct weston_output *output)
203{
204 return output->renderer_state;
205}
206
207static inline struct rpi_renderer *
208to_rpi_renderer(struct weston_compositor *compositor)
209{
210 return container_of(compositor->renderer, struct rpi_renderer, base);
211}
212
213static inline int
214int_max(int a, int b)
215{
216 return a > b ? a : b;
217}
218
219static inline void
220int_swap(int *a, int *b)
221{
222 int tmp = *a;
223 *a = *b;
224 *b = tmp;
225}
226
227static uint8_t
228float2uint8(float f)
229{
230 int v = roundf(f * 255.0f);
231
232 return v < 0 ? 0 : (v > 255 ? 255 : v);
233}
234
235static void
236rpi_resource_init(struct rpi_resource *resource)
237{
238 resource->handle = DISPMANX_NO_HANDLE;
239}
240
241static void
242rpi_resource_release(struct rpi_resource *resource)
243{
244 if (resource->handle == DISPMANX_NO_HANDLE)
245 return;
246
247 vc_dispmanx_resource_delete(resource->handle);
248 DBG("resource %p release\n", resource);
249 resource->handle = DISPMANX_NO_HANDLE;
250}
251
252static int
253rpi_resource_realloc(struct rpi_resource *resource, VC_IMAGE_TYPE_T ifmt,
254 int width, int height, int stride, int buffer_height)
255{
256 uint32_t dummy;
257
258 if (resource->handle != DISPMANX_NO_HANDLE &&
259 resource->width == width &&
260 resource->height == height &&
261 resource->stride == stride &&
262 resource->buffer_height == buffer_height &&
263 resource->ifmt == ifmt)
264 return 0;
265
266 rpi_resource_release(resource);
267
268 /* NOTE: if stride is not a multiple of 16 pixels in bytes,
269 * the vc_image_* functions may break. Dispmanx elements
270 * should be fine, though. Buffer_height probably has similar
271 * constraints, too.
272 */
273 resource->handle =
274 vc_dispmanx_resource_create(ifmt,
275 width | (stride << 16),
276 height | (buffer_height << 16),
277 &dummy);
278 if (resource->handle == DISPMANX_NO_HANDLE)
279 return -1;
280
281 resource->width = width;
282 resource->height = height;
283 resource->stride = stride;
284 resource->buffer_height = buffer_height;
285 resource->ifmt = ifmt;
286 DBG("resource %p alloc\n", resource);
287 return 1;
288}
289
290/* A firmware workaround for broken ALPHA_PREMULT + ALPHA_MIX hardware. */
291#define PREMULT_ALPHA_FLAG (1 << 31)
292
293static VC_IMAGE_TYPE_T
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500294shm_buffer_get_vc_format(struct wl_shm_buffer *buffer)
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300295{
296 switch (wl_shm_buffer_get_format(buffer)) {
297 case WL_SHM_FORMAT_XRGB8888:
298 return VC_IMAGE_XRGB8888;
299 case WL_SHM_FORMAT_ARGB8888:
300 return VC_IMAGE_ARGB8888 | PREMULT_ALPHA_FLAG;
Tomeu Vizoso03681892013-08-06 20:05:57 +0200301 case WL_SHM_FORMAT_RGB565:
302 return VC_IMAGE_RGB565;
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300303 default:
304 /* invalid format */
305 return VC_IMAGE_MIN;
306 }
307}
308
309static int
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500310rpi_resource_update(struct rpi_resource *resource, struct weston_buffer *buffer,
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300311 pixman_region32_t *region)
312{
313 pixman_region32_t write_region;
314 pixman_box32_t *r;
315 VC_RECT_T rect;
316 VC_IMAGE_TYPE_T ifmt;
317 uint32_t *pixels;
318 int width;
319 int height;
320 int stride;
321 int ret;
322#ifdef HAVE_RESOURCE_WRITE_DATA_RECT
323 int n;
324#endif
325
326 if (!buffer)
327 return -1;
328
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500329 ifmt = shm_buffer_get_vc_format(buffer->shm_buffer);
330 width = wl_shm_buffer_get_width(buffer->shm_buffer);
331 height = wl_shm_buffer_get_height(buffer->shm_buffer);
332 stride = wl_shm_buffer_get_stride(buffer->shm_buffer);
333 pixels = wl_shm_buffer_get_data(buffer->shm_buffer);
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300334
335 ret = rpi_resource_realloc(resource, ifmt & ~PREMULT_ALPHA_FLAG,
336 width, height, stride, height);
337 if (ret < 0)
338 return -1;
339
340 pixman_region32_init_rect(&write_region, 0, 0, width, height);
341 if (ret == 0)
342 pixman_region32_intersect(&write_region,
343 &write_region, region);
344
Neil Robertse5051712013-11-13 15:44:06 +0000345 wl_shm_buffer_begin_access(buffer->shm_buffer);
346
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300347#ifdef HAVE_RESOURCE_WRITE_DATA_RECT
348 /* XXX: Can this do a format conversion, so that scanout does not have to? */
349 r = pixman_region32_rectangles(&write_region, &n);
350 while (n--) {
351 vc_dispmanx_rect_set(&rect, r[n].x1, r[n].y1,
352 r[n].x2 - r[n].x1, r[n].y2 - r[n].y1);
353
354 ret = vc_dispmanx_resource_write_data_rect(resource->handle,
355 ifmt, stride,
356 pixels, &rect,
357 rect.x, rect.y);
358 DBG("%s: %p %ux%u@%u,%u, ret %d\n", __func__, resource,
359 rect.width, rect.height, rect.x, rect.y, ret);
360 if (ret)
361 break;
362 }
363#else
364 /* vc_dispmanx_resource_write_data() ignores ifmt,
365 * rect.x, rect.width, and uses stride only for computing
366 * the size of the transfer as rect.height * stride.
367 * Therefore we can only write rows starting at x=0.
368 * To be able to write more than one scanline at a time,
369 * the resource must have been created with the same stride
370 * as used here, and we must write full scanlines.
371 */
372
373 r = pixman_region32_extents(&write_region);
374 vc_dispmanx_rect_set(&rect, 0, r->y1, width, r->y2 - r->y1);
375 ret = vc_dispmanx_resource_write_data(resource->handle,
376 ifmt, stride, pixels, &rect);
377 DBG("%s: %p %ux%u@%u,%u, ret %d\n", __func__, resource,
378 width, r->y2 - r->y1, 0, r->y1, ret);
379#endif
380
Neil Robertse5051712013-11-13 15:44:06 +0000381 wl_shm_buffer_end_access(buffer->shm_buffer);
382
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300383 pixman_region32_fini(&write_region);
384
385 return ret ? -1 : 0;
386}
387
Pekka Paalanend5fbfb22013-11-22 17:30:39 +0200388static inline void
389rpi_buffer_egl_lock(struct weston_buffer *buffer)
390{
391#ifdef ENABLE_EGL
392 vc_dispmanx_set_wl_buffer_in_use(buffer->resource, 1);
393#endif
394}
395
396static inline void
397rpi_buffer_egl_unlock(struct weston_buffer *buffer)
398{
399#ifdef ENABLE_EGL
400 vc_dispmanx_set_wl_buffer_in_use(buffer->resource, 0);
401#endif
402}
403
Tomeu Vizoso74987582013-10-25 10:34:38 +0200404static void
405rpir_egl_buffer_destroy(struct rpir_egl_buffer *egl_buffer)
406{
407 struct weston_buffer *buffer;
408
409 if (egl_buffer == NULL)
410 return;
411
412 buffer = egl_buffer->buffer_ref.buffer;
413 if (buffer == NULL) {
414 /* The client has already destroyed the wl_buffer, the
415 * compositor has the responsibility to delete the resource.
416 */
417 vc_dispmanx_resource_delete(egl_buffer->resource_handle);
418 } else {
Pekka Paalanend5fbfb22013-11-22 17:30:39 +0200419 rpi_buffer_egl_unlock(buffer);
Tomeu Vizoso74987582013-10-25 10:34:38 +0200420 weston_buffer_reference(&egl_buffer->buffer_ref, NULL);
421 }
422
423 free(egl_buffer);
424}
425
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300426static struct rpir_surface *
427rpir_surface_create(struct rpi_renderer *renderer)
428{
429 struct rpir_surface *surface;
430
431 surface = calloc(1, sizeof *surface);
432 if (!surface)
433 return NULL;
434
Tomeu Vizoso5c3ea3b2013-10-24 15:38:30 +0200435 wl_list_init(&surface->views);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500436 surface->visible_views = 0;
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300437 surface->single_buffer = renderer->single_buffer;
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300438 rpi_resource_init(&surface->resources[0]);
439 rpi_resource_init(&surface->resources[1]);
440 surface->front = &surface->resources[0];
441 if (surface->single_buffer)
442 surface->back = &surface->resources[0];
443 else
444 surface->back = &surface->resources[1];
Tomeu Vizosob4659eb2013-10-07 11:02:20 +0200445 surface->buffer_type = BUFFER_TYPE_NULL;
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300446
447 pixman_region32_init(&surface->prev_damage);
448
449 return surface;
450}
451
452static void
453rpir_surface_destroy(struct rpir_surface *surface)
454{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500455 if (surface->visible_views)
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300456 weston_log("ERROR rpi: destroying on-screen element\n");
457
Jason Ekstranda7af7042013-10-12 22:38:11 -0500458 assert(wl_list_empty(&surface->views));
459
460 if (surface->surface)
461 surface->surface->renderer_state = NULL;
462
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300463 pixman_region32_fini(&surface->prev_damage);
464 rpi_resource_release(&surface->resources[0]);
465 rpi_resource_release(&surface->resources[1]);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500466 DBG("rpir_surface %p destroyed (%u)\n", surface, surface->visible_views);
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300467
Tomeu Vizoso74987582013-10-25 10:34:38 +0200468 rpir_egl_buffer_destroy(surface->egl_back);
469 rpir_egl_buffer_destroy(surface->egl_front);
470 rpir_egl_buffer_destroy(surface->egl_old_front);
Tomeu Vizosob4659eb2013-10-07 11:02:20 +0200471
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300472 free(surface);
473}
474
475static int
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500476rpir_surface_damage(struct rpir_surface *surface, struct weston_buffer *buffer,
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300477 pixman_region32_t *damage)
478{
479 pixman_region32_t upload;
480 int ret;
481
482 if (!pixman_region32_not_empty(damage))
483 return 0;
484
485 DBG("rpir_surface %p update resource %p\n", surface, surface->back);
486
487 /* XXX: todo: if no surface->handle, update front buffer directly
488 * to avoid creating a new back buffer */
489 if (surface->single_buffer) {
490 ret = rpi_resource_update(surface->front, buffer, damage);
491 } else {
492 pixman_region32_init(&upload);
493 pixman_region32_union(&upload, &surface->prev_damage, damage);
494 ret = rpi_resource_update(surface->back, buffer, &upload);
495 pixman_region32_fini(&upload);
496 }
497
498 pixman_region32_copy(&surface->prev_damage, damage);
499 surface->need_swap = 1;
500
501 return ret;
502}
503
Jason Ekstranda7af7042013-10-12 22:38:11 -0500504static struct rpir_view *
505rpir_view_create(struct rpir_surface *surface)
506{
507 struct rpir_view *view;
508
509 view = calloc(1, sizeof *view);
510 if (!view)
511 return NULL;
512
513 view->surface = surface;
514 wl_list_insert(&surface->views, &view->surface_link);
515
516 wl_list_init(&view->link);
517 view->handle = DISPMANX_NO_HANDLE;
518
519 return view;
520}
521
522static void
523rpir_view_destroy(struct rpir_view *view)
524{
525 wl_list_remove(&view->link);
526
527 if (view->handle != DISPMANX_NO_HANDLE) {
528 view->surface->visible_views--;
529 weston_log("ERROR rpi: destroying on-screen element\n");
530 }
531
532 if (view->view)
533 view->view->renderer_state = NULL;
534
535 wl_list_remove(&view->surface_link);
536 if (wl_list_empty(&view->surface->views) && view->surface->surface == NULL)
537 rpir_surface_destroy(view->surface);
538
539 DBG("rpir_view %p destroyed (%d)\n", view, view->handle);
540
541 free(view);
542}
543
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300544static void
545matrix_type_str(struct weston_matrix *matrix, char *buf, int len)
546{
547 static const char types[33] = "TSRO";
548 unsigned mask = matrix->type;
549 int i = 0;
550
551 while (mask && i < len - 1) {
552 if (mask & (1u << i))
553 *buf++ = types[i];
554 mask &= ~(1u << i);
555 i++;
556 }
557 *buf = '\0';
558}
559
560static void
561log_print_matrix(struct weston_matrix *matrix)
562{
563 char typestr[6];
564 float *d = matrix->d;
565
566 matrix_type_str(matrix, typestr, sizeof typestr);
567 weston_log_continue("%14.6e %14.6e %14.6e %14.6e\n",
568 d[0], d[4], d[8], d[12]);
569 weston_log_continue("%14.6e %14.6e %14.6e %14.6e\n",
570 d[1], d[5], d[9], d[13]);
571 weston_log_continue("%14.6e %14.6e %14.6e %14.6e\n",
572 d[2], d[6], d[10], d[14]);
573 weston_log_continue("%14.6e %14.6e %14.6e %14.6e type: %s\n",
574 d[3], d[7], d[11], d[15], typestr);
575}
576
577static void
578warn_bad_matrix(struct weston_matrix *total, struct weston_matrix *output,
579 struct weston_matrix *surface)
580{
581 static int n_warn;
582 char typestr[6];
583
584 if (n_warn++ == 10)
585 weston_log("%s: not showing more warnings\n", __func__);
586
587 if (n_warn > 10)
588 return;
589
590 weston_log("%s: warning: total transformation is not renderable:\n",
591 __func__);
592 log_print_matrix(total);
593
594 matrix_type_str(surface, typestr, sizeof typestr);
595 weston_log_continue("surface matrix type: %s\n", typestr);
596 matrix_type_str(output, typestr, sizeof typestr);
597 weston_log_continue("output matrix type: %s\n", typestr);
598}
599
600/*#define SURFACE_TRANSFORM */
601
602static int
Jason Ekstranda7af7042013-10-12 22:38:11 -0500603rpir_view_compute_rects(struct rpir_view *view,
604 VC_RECT_T *src_rect, VC_RECT_T *dst_rect,
605 VC_IMAGE_TRANSFORM_T *flipmask)
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300606{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500607 struct weston_output *output_base = view->view->surface->output;
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300608 struct rpir_output *output = to_rpir_output(output_base);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500609 struct weston_matrix matrix = view->view->transform.matrix;
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300610 VC_IMAGE_TRANSFORM_T flipt = 0;
611 int src_x, src_y;
612 int dst_x, dst_y;
613 int src_width, src_height;
614 int dst_width, dst_height;
615 struct weston_vector p1 = {{ 0.0f, 0.0f, 0.0f, 1.0f }};
616 struct weston_vector p2 = {{ 0.0f, 0.0f, 0.0f, 1.0f }};
617 int t;
618 int over;
619
620 /* XXX: take buffer transform into account */
621
622 /* src is in 16.16, dst is in 32.0 fixed point.
623 * Negative values are not allowed in VC_RECT_T.
624 * Clip size to output boundaries, firmware ignores
625 * huge elements like 8192x8192.
626 */
627
628 src_x = 0 << 16;
629 src_y = 0 << 16;
Tomeu Vizosob4659eb2013-10-07 11:02:20 +0200630
Jason Ekstranda7af7042013-10-12 22:38:11 -0500631 if (view->surface->buffer_type == BUFFER_TYPE_EGL) {
632 struct weston_buffer *buffer =
633 view->surface->egl_front->buffer_ref.buffer;
Tomeu Vizosob4659eb2013-10-07 11:02:20 +0200634
635 src_width = buffer->width << 16;
636 src_height = buffer->height << 16;
637 } else {
Jason Ekstranda7af7042013-10-12 22:38:11 -0500638 src_width = view->surface->front->width << 16;
639 src_height = view->surface->front->height << 16;
Tomeu Vizosob4659eb2013-10-07 11:02:20 +0200640 }
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300641
642 weston_matrix_multiply(&matrix, &output->matrix);
643
644#ifdef SURFACE_TRANSFORM
645 if (matrix.type >= WESTON_MATRIX_TRANSFORM_OTHER) {
646#else
647 if (matrix.type >= WESTON_MATRIX_TRANSFORM_ROTATE) {
648#endif
649 warn_bad_matrix(&matrix, &output->matrix,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500650 &view->view->transform.matrix);
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300651 } else {
652 if (matrix.type & WESTON_MATRIX_TRANSFORM_ROTATE) {
653 if (fabsf(matrix.d[0]) < 1e-4f &&
654 fabsf(matrix.d[5]) < 1e-4f) {
655 flipt |= TRANSFORM_TRANSPOSE;
656 } else if (fabsf(matrix.d[1]) < 1e-4 &&
657 fabsf(matrix.d[4]) < 1e-4) {
658 /* no transpose */
659 } else {
660 warn_bad_matrix(&matrix, &output->matrix,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500661 &view->view->transform.matrix);
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300662 }
663 }
664 }
665
Jason Ekstranda7af7042013-10-12 22:38:11 -0500666 p2.f[0] = view->view->geometry.width;
667 p2.f[1] = view->view->geometry.height;
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300668
669 /* transform top-left and bot-right corner into screen coordinates */
670 weston_matrix_transform(&matrix, &p1);
671 weston_matrix_transform(&matrix, &p2);
672
673 /* Compute the destination rectangle on screen, converting
674 * negative dimensions to flips.
675 */
676
677 dst_width = round(p2.f[0] - p1.f[0]);
678 if (dst_width < 0) {
679 dst_x = round(p2.f[0]);
680 dst_width = -dst_width;
681
682 if (!(flipt & TRANSFORM_TRANSPOSE))
683 flipt |= TRANSFORM_HFLIP;
684 else
685 flipt |= TRANSFORM_VFLIP;
686 } else {
687 dst_x = round(p1.f[0]);
688 }
689
690 dst_height = round(p2.f[1] - p1.f[1]);
691 if (dst_height < 0) {
692 dst_y = round(p2.f[1]);
693 dst_height = -dst_height;
694
695 if (!(flipt & TRANSFORM_TRANSPOSE))
696 flipt |= TRANSFORM_VFLIP;
697 else
698 flipt |= TRANSFORM_HFLIP;
699 } else {
700 dst_y = round(p1.f[1]);
701 }
702
703 if (dst_width == 0 || dst_height == 0) {
704 DBG("ignored, zero surface area before clipping\n");
705 return -1;
706 }
707
708#ifdef SURFACE_TRANSFORM
709 /* Dispmanx works as if you flipped the whole screen, when
710 * you flip an element. But, we want to flip an element in place.
711 * XXX: fixme
712 */
713 if (flipt & TRANSFORM_HFLIP)
714 dst_x = output_base->width - dst_x;
715 if (flipt & TRANSFORM_VFLIP)
716 dst_y = output_base->height - dst_y;
717 if (flipt & TRANSFORM_TRANSPOSE) {
718 int_swap(&dst_x, &dst_y);
719 int_swap(&dst_width, &dst_height);
720 }
721#else
722 switch (output_base->transform) {
723 case WL_OUTPUT_TRANSFORM_FLIPPED:
724 flipt = TRANSFORM_HFLIP;
725 break;
726 case WL_OUTPUT_TRANSFORM_NORMAL:
727 flipt = 0;
728 break;
729
730 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
731 flipt = TRANSFORM_HFLIP | TRANSFORM_VFLIP | TRANSFORM_TRANSPOSE;
732 break;
733 case WL_OUTPUT_TRANSFORM_90:
734 flipt = TRANSFORM_VFLIP | TRANSFORM_TRANSPOSE;
735 break;
736 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
737 flipt = TRANSFORM_VFLIP;
738 break;
739 case WL_OUTPUT_TRANSFORM_180:
740 flipt = TRANSFORM_HFLIP | TRANSFORM_VFLIP;
741 break;
742
743 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
744 flipt = TRANSFORM_TRANSPOSE;
745 break;
746 case WL_OUTPUT_TRANSFORM_270:
747 flipt = TRANSFORM_HFLIP | TRANSFORM_TRANSPOSE;
748 break;
749 default:
750 break;
751 }
752#endif
753
754 /* clip destination rectangle to screen dimensions */
755
756 if (dst_x < 0) {
757 t = (int64_t)dst_x * src_width / dst_width;
758 src_width += t;
759 dst_width += dst_x;
760 src_x -= t;
761 dst_x = 0;
762 }
763
764 if (dst_y < 0) {
765 t = (int64_t)dst_y * src_height / dst_height;
766 src_height += t;
767 dst_height += dst_y;
768 src_y -= t;
769 dst_y = 0;
770 }
771
772 over = dst_x + dst_width - output_base->width;
773 if (over > 0) {
774 t = (int64_t)over * src_width / dst_width;
775 src_width -= t;
776 dst_width -= over;
777 }
778
779 over = dst_y + dst_height - output_base->height;
780 if (over > 0) {
781 t = (int64_t)over * src_height / dst_height;
782 src_height -= t;
783 dst_height -= over;
784 }
785
786 src_width = int_max(src_width, 0);
787 src_height = int_max(src_height, 0);
788
Jason Ekstranda7af7042013-10-12 22:38:11 -0500789 DBG("rpir_view %p %dx%d: p1 %f, %f; p2 %f, %f\n", view,
790 view->view->geometry.width,
791 view->view->geometry.height,
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300792 p1.f[0], p1.f[1], p2.f[0], p2.f[1]);
793 DBG("src rect %d;%d, %d;%d, %d;%dx%d;%d\n",
794 src_x >> 16, src_x & 0xffff,
795 src_y >> 16, src_y & 0xffff,
796 src_width >> 16, src_width & 0xffff,
797 src_height >> 16, src_height & 0xffff);
798 DBG("dest rect %d, %d, %dx%d%s%s%s\n",
799 dst_x, dst_y, dst_width, dst_height,
800 (flipt & TRANSFORM_HFLIP) ? " hflip" : "",
801 (flipt & TRANSFORM_VFLIP) ? " vflip" : "",
802 (flipt & TRANSFORM_TRANSPOSE) ? " transp" : "");
803
804 assert(src_x >= 0);
805 assert(src_y >= 0);
806 assert(dst_x >= 0);
807 assert(dst_y >= 0);
808
809 if (dst_width < 1 || dst_height < 1) {
810 DBG("ignored, zero surface area after clipping\n");
811 return -1;
812 }
813
Tomeu Vizosob4659eb2013-10-07 11:02:20 +0200814 /* EGL buffers will be upside-down related to what DispmanX expects */
Jason Ekstranda7af7042013-10-12 22:38:11 -0500815 if (view->surface->buffer_type == BUFFER_TYPE_EGL)
Tomeu Vizosob4659eb2013-10-07 11:02:20 +0200816 flipt ^= TRANSFORM_VFLIP;
817
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300818 vc_dispmanx_rect_set(src_rect, src_x, src_y, src_width, src_height);
819 vc_dispmanx_rect_set(dst_rect, dst_x, dst_y, dst_width, dst_height);
820 *flipmask = flipt;
821
822 return 0;
823}
824
825static DISPMANX_TRANSFORM_T
826vc_image2dispmanx_transform(VC_IMAGE_TRANSFORM_T t)
827{
828 /* XXX: uhh, are these right? */
829 switch (t) {
830 case VC_IMAGE_ROT0:
831 return DISPMANX_NO_ROTATE;
832 case VC_IMAGE_MIRROR_ROT0:
833 return DISPMANX_FLIP_HRIZ;
834 case VC_IMAGE_MIRROR_ROT180:
835 return DISPMANX_FLIP_VERT;
836 case VC_IMAGE_ROT180:
837 return DISPMANX_ROTATE_180;
838 case VC_IMAGE_MIRROR_ROT90:
839 return DISPMANX_ROTATE_90 | DISPMANX_FLIP_HRIZ;
840 case VC_IMAGE_ROT270:
841 return DISPMANX_ROTATE_270;
842 case VC_IMAGE_ROT90:
843 return DISPMANX_ROTATE_90;
844 case VC_IMAGE_MIRROR_ROT270:
845 return DISPMANX_ROTATE_270 | DISPMANX_FLIP_VERT;
846 default:
847 assert(0 && "bad VC_IMAGE_TRANSFORM_T");
848 return DISPMANX_NO_ROTATE;
849 }
850}
851
Tomeu Vizosob4659eb2013-10-07 11:02:20 +0200852
853static DISPMANX_RESOURCE_HANDLE_T
854rpir_surface_get_resource(struct rpir_surface *surface)
855{
856 switch (surface->buffer_type) {
857 case BUFFER_TYPE_SHM:
858 case BUFFER_TYPE_NULL:
859 return surface->front->handle;
860 case BUFFER_TYPE_EGL:
861 if (surface->egl_front != NULL)
862 return surface->egl_front->resource_handle;
863 default:
864 return DISPMANX_NO_HANDLE;
865 }
866}
867
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300868static int
Jason Ekstranda7af7042013-10-12 22:38:11 -0500869rpir_view_dmx_add(struct rpir_view *view, struct rpir_output *output,
870 DISPMANX_UPDATE_HANDLE_T update, int layer)
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300871{
872 /* Do not use DISPMANX_FLAGS_ALPHA_PREMULT here.
873 * If you define PREMULT and ALPHA_MIX, the hardware will not
874 * multiply the source color with the element alpha, leading to
875 * bad colors. Instead, we define PREMULT during pixel data upload.
876 */
877 VC_DISPMANX_ALPHA_T alphasetup = {
878 DISPMANX_FLAGS_ALPHA_FROM_SOURCE |
879 DISPMANX_FLAGS_ALPHA_MIX,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500880 float2uint8(view->view->alpha), /* opacity 0-255 */
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300881 0 /* mask resource handle */
882 };
883 VC_RECT_T dst_rect;
884 VC_RECT_T src_rect;
885 VC_IMAGE_TRANSFORM_T flipmask;
886 int ret;
Tomeu Vizosob4659eb2013-10-07 11:02:20 +0200887 DISPMANX_RESOURCE_HANDLE_T resource_handle;
888
Jason Ekstranda7af7042013-10-12 22:38:11 -0500889 resource_handle = rpir_surface_get_resource(view->surface);
Tomeu Vizosob4659eb2013-10-07 11:02:20 +0200890 if (resource_handle == DISPMANX_NO_HANDLE) {
891 weston_log("%s: no buffer yet, aborting\n", __func__);
892 return 0;
893 }
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300894
Jason Ekstranda7af7042013-10-12 22:38:11 -0500895 ret = rpir_view_compute_rects(view, &src_rect, &dst_rect, &flipmask);
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300896 if (ret < 0)
897 return 0;
898
Jason Ekstranda7af7042013-10-12 22:38:11 -0500899 view->handle = vc_dispmanx_element_add(
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300900 update,
901 output->display,
902 layer,
903 &dst_rect,
Tomeu Vizosob4659eb2013-10-07 11:02:20 +0200904 resource_handle,
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300905 &src_rect,
906 DISPMANX_PROTECTION_NONE,
907 &alphasetup,
908 NULL /* clamp */,
909 vc_image2dispmanx_transform(flipmask));
Jason Ekstranda7af7042013-10-12 22:38:11 -0500910 DBG("rpir_surface %p add %u, alpha %f resource %d\n", view,
911 view->handle, view->view->alpha, resource_handle);
912
913 if (view->handle == DISPMANX_NO_HANDLE)
914 return -1;
915
916 view->surface->visible_views++;
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300917
918 return 1;
919}
920
921static void
Jason Ekstranda7af7042013-10-12 22:38:11 -0500922rpir_view_dmx_swap(struct rpir_view *view,
923 DISPMANX_UPDATE_HANDLE_T update)
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300924{
925 VC_RECT_T rect;
926 pixman_box32_t *r;
927
928 /* XXX: skip, iff resource was not reallocated, and single-buffering */
Jason Ekstranda7af7042013-10-12 22:38:11 -0500929 vc_dispmanx_element_change_source(update, view->handle,
930 view->surface->front->handle);
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300931
932 /* This is current damage now, after rpir_surface_damage() */
Jason Ekstranda7af7042013-10-12 22:38:11 -0500933 r = pixman_region32_extents(&view->surface->prev_damage);
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300934
935 vc_dispmanx_rect_set(&rect, r->x1, r->y1,
936 r->x2 - r->x1, r->y2 - r->y1);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500937 vc_dispmanx_element_modified(update, view->handle, &rect);
938 DBG("rpir_view %p swap\n", view);
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300939}
940
941static int
Jason Ekstranda7af7042013-10-12 22:38:11 -0500942rpir_view_dmx_move(struct rpir_view *view,
943 DISPMANX_UPDATE_HANDLE_T update, int layer)
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300944{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500945 uint8_t alpha = float2uint8(view->view->alpha);
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300946 VC_RECT_T dst_rect;
947 VC_RECT_T src_rect;
948 VC_IMAGE_TRANSFORM_T flipmask;
949 int ret;
950
951 /* XXX: return early, if all attributes stay the same */
952
Jason Ekstranda7af7042013-10-12 22:38:11 -0500953 if (view->surface->buffer_type == BUFFER_TYPE_EGL) {
Tomeu Vizosob4659eb2013-10-07 11:02:20 +0200954 DISPMANX_RESOURCE_HANDLE_T resource_handle;
955
Jason Ekstranda7af7042013-10-12 22:38:11 -0500956 resource_handle = rpir_surface_get_resource(view->surface);
Tomeu Vizosob4659eb2013-10-07 11:02:20 +0200957 if (resource_handle == DISPMANX_NO_HANDLE) {
958 weston_log("%s: no buffer yet, aborting\n", __func__);
959 return 0;
960 }
961
962 vc_dispmanx_element_change_source(update,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500963 view->handle,
Tomeu Vizosob4659eb2013-10-07 11:02:20 +0200964 resource_handle);
965 }
966
Jason Ekstranda7af7042013-10-12 22:38:11 -0500967 ret = rpir_view_compute_rects(view, &src_rect, &dst_rect, &flipmask);
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300968 if (ret < 0)
969 return 0;
970
971 ret = vc_dispmanx_element_change_attributes(
972 update,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500973 view->handle,
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300974 ELEMENT_CHANGE_LAYER |
975 ELEMENT_CHANGE_OPACITY |
976 ELEMENT_CHANGE_TRANSFORM |
977 ELEMENT_CHANGE_DEST_RECT |
978 ELEMENT_CHANGE_SRC_RECT,
979 layer,
980 alpha,
981 &dst_rect,
982 &src_rect,
983 DISPMANX_NO_HANDLE,
984 /* This really is DISPMANX_TRANSFORM_T, no matter
985 * what the header says. */
986 vc_image2dispmanx_transform(flipmask));
Jason Ekstranda7af7042013-10-12 22:38:11 -0500987 DBG("rpir_view %p move\n", view);
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300988
989 if (ret)
990 return -1;
991
992 return 1;
993}
994
995static void
Jason Ekstranda7af7042013-10-12 22:38:11 -0500996rpir_view_dmx_remove(struct rpir_view *view,
997 DISPMANX_UPDATE_HANDLE_T update)
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300998{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500999 if (view->handle == DISPMANX_NO_HANDLE)
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001000 return;
1001
Jason Ekstranda7af7042013-10-12 22:38:11 -05001002 vc_dispmanx_element_remove(update, view->handle);
1003 DBG("rpir_view %p remove %u\n", view, view->handle);
1004 view->handle = DISPMANX_NO_HANDLE;
1005 view->surface->visible_views--;
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001006}
1007
1008static void
1009rpir_surface_swap_pointers(struct rpir_surface *surface)
1010{
1011 struct rpi_resource *tmp;
1012
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001013 if (surface->buffer_type == BUFFER_TYPE_EGL) {
1014 if (surface->egl_back != NULL) {
1015 assert(surface->egl_old_front == NULL);
1016 surface->egl_old_front = surface->egl_front;
1017 surface->egl_front = surface->egl_back;
1018 surface->egl_back = NULL;
Tomeu Vizoso15767812013-10-24 15:38:31 +02001019 DBG("new front %d\n", surface->egl_front->resource_handle);
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001020 }
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001021 } else {
Jason Ekstranda7af7042013-10-12 22:38:11 -05001022 tmp = surface->front;
1023 surface->front = surface->back;
1024 surface->back = tmp;
Tomeu Vizoso15767812013-10-24 15:38:31 +02001025 DBG("new back %p, new front %p\n", surface->back, surface->front);
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001026 }
Jason Ekstranda7af7042013-10-12 22:38:11 -05001027}
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001028
Jason Ekstranda7af7042013-10-12 22:38:11 -05001029static int
1030is_view_not_visible(struct weston_view *view)
1031{
1032 /* Return true, if surface is guaranteed to be totally obscured. */
1033 int ret;
1034 pixman_region32_t unocc;
1035
1036 pixman_region32_init(&unocc);
1037 pixman_region32_subtract(&unocc, &view->transform.boundingbox,
1038 &view->clip);
1039 ret = !pixman_region32_not_empty(&unocc);
1040 pixman_region32_fini(&unocc);
1041
1042 return ret;
1043}
1044
1045static void
1046rpir_view_update(struct rpir_view *view, struct rpir_output *output,
1047 DISPMANX_UPDATE_HANDLE_T update, int layer)
1048{
1049 int ret;
1050 int obscured;
1051
Jason Ekstranda7af7042013-10-12 22:38:11 -05001052 obscured = is_view_not_visible(view->view);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001053 if (obscured) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05001054 DBG("rpir_view %p totally obscured.\n", view);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001055
Jason Ekstranda7af7042013-10-12 22:38:11 -05001056 wl_list_remove(&view->link);
1057 if (view->handle == DISPMANX_NO_HANDLE) {
1058 wl_list_init(&view->link);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001059 } else {
Jason Ekstranda7af7042013-10-12 22:38:11 -05001060 rpir_view_dmx_remove(view, update);
1061 wl_list_insert(&output->view_cleanup_list,
1062 &view->link);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001063 }
1064
1065 goto out;
1066 }
1067
Jason Ekstranda7af7042013-10-12 22:38:11 -05001068 if (view->handle == DISPMANX_NO_HANDLE) {
1069 ret = rpir_view_dmx_add(view, output, update, layer);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001070 if (ret == 0) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05001071 wl_list_remove(&view->link);
1072 wl_list_init(&view->link);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001073 } else if (ret < 0) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05001074 weston_log("ERROR rpir_view_dmx_add() failed.\n");
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001075 }
1076 } else {
Jason Ekstranda7af7042013-10-12 22:38:11 -05001077 if (view->surface->need_swap)
1078 rpir_view_dmx_swap(view, update);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001079
Jason Ekstranda7af7042013-10-12 22:38:11 -05001080 ret = rpir_view_dmx_move(view, update, layer);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001081 if (ret == 0) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05001082 rpir_view_dmx_remove(view, update);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001083
Jason Ekstranda7af7042013-10-12 22:38:11 -05001084 wl_list_remove(&view->link);
1085 wl_list_insert(&output->view_cleanup_list,
1086 &view->link);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001087 } else if (ret < 0) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05001088 weston_log("ERROR rpir_view_dmx_move() failed.\n");
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001089 }
1090 }
1091
1092out:
Jason Ekstranda7af7042013-10-12 22:38:11 -05001093 view->layer = layer;
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001094}
1095
1096static int
1097rpi_renderer_read_pixels(struct weston_output *base,
1098 pixman_format_code_t format, void *pixels,
1099 uint32_t x, uint32_t y,
1100 uint32_t width, uint32_t height)
1101{
1102 struct rpir_output *output = to_rpir_output(base);
1103 struct rpi_resource *buffer = &output->capture_buffer;
1104 VC_RECT_T rect;
1105 uint32_t fb_width, fb_height;
1106 uint32_t dst_pitch;
1107 uint32_t i;
1108 int ret;
1109
Hardeningff39efa2013-09-18 23:56:35 +02001110 fb_width = base->current_mode->width;
1111 fb_height = base->current_mode->height;
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001112
1113 DBG("%s(%u, %u, %u, %u), resource %p\n", __func__,
1114 x, y, width, height, buffer);
1115
1116 if (format != PIXMAN_a8r8g8b8) {
1117 weston_log("rpi-renderer error: bad read_format\n");
1118 return -1;
1119 }
1120
1121 dst_pitch = fb_width * 4;
1122
1123 if (buffer->handle == DISPMANX_NO_HANDLE) {
1124 free(output->capture_data);
1125 output->capture_data = NULL;
1126
1127 ret = rpi_resource_realloc(buffer, VC_IMAGE_ARGB8888,
1128 fb_width, fb_height,
1129 dst_pitch, fb_height);
1130 if (ret < 0) {
1131 weston_log("rpi-renderer error: "
1132 "allocating read buffer failed\n");
1133 return -1;
1134 }
1135
1136 ret = vc_dispmanx_snapshot(output->display, buffer->handle,
1137 VC_IMAGE_ROT0);
1138 if (ret) {
1139 weston_log("rpi-renderer error: "
1140 "vc_dispmanx_snapshot returned %d\n", ret);
1141 return -1;
1142 }
1143 DBG("%s: snapshot done.\n", __func__);
1144 }
1145
1146 /*
1147 * If vc_dispmanx_resource_read_data was able to read sub-rectangles,
1148 * we could read directly into 'pixels'. But it cannot, it does not
1149 * use rect.x or rect.width, and does this:
1150 * host_start = (uint8_t *)dst_address + (dst_pitch * p_rect->y);
1151 * In other words, it is only good for reading the full buffer in
1152 * one go.
1153 */
1154 vc_dispmanx_rect_set(&rect, 0, 0, fb_width, fb_height);
1155
1156 if (x == 0 && y == 0 && width == fb_width && height == fb_height) {
1157 ret = vc_dispmanx_resource_read_data(buffer->handle, &rect,
1158 pixels, dst_pitch);
1159 if (ret) {
1160 weston_log("rpi-renderer error: "
1161 "resource_read_data returned %d\n", ret);
1162 return -1;
1163 }
1164 DBG("%s: full frame done.\n", __func__);
1165 return 0;
1166 }
1167
1168 if (!output->capture_data) {
1169 output->capture_data = malloc(fb_height * dst_pitch);
1170 if (!output->capture_data) {
1171 weston_log("rpi-renderer error: "
1172 "out of memory\n");
1173 return -1;
1174 }
1175
1176 ret = vc_dispmanx_resource_read_data(buffer->handle, &rect,
1177 output->capture_data,
1178 dst_pitch);
1179 if (ret) {
1180 weston_log("rpi-renderer error: "
1181 "resource_read_data returned %d\n", ret);
1182 return -1;
1183 }
1184 }
1185
1186 for (i = 0; i < height; i++) {
1187 uint8_t *src = output->capture_data +
1188 (y + i) * dst_pitch + x * 4;
1189 uint8_t *dst = (uint8_t *)pixels + i * width * 4;
1190 memcpy(dst, src, width * 4);
1191 }
1192
1193 return 0;
1194}
1195
1196static void
1197rpir_output_dmx_remove_all(struct rpir_output *output,
1198 DISPMANX_UPDATE_HANDLE_T update)
1199{
Jason Ekstranda7af7042013-10-12 22:38:11 -05001200 struct rpir_view *view;
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001201
Jason Ekstranda7af7042013-10-12 22:38:11 -05001202 while (!wl_list_empty(&output->view_list)) {
1203 view = container_of(output->view_list.next,
1204 struct rpir_view, link);
1205 rpir_view_dmx_remove(view, update);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001206
Jason Ekstranda7af7042013-10-12 22:38:11 -05001207 wl_list_remove(&view->link);
1208 wl_list_insert(&output->view_cleanup_list, &view->link);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001209 }
1210}
1211
1212static void
1213output_compute_matrix(struct weston_output *base)
1214{
1215 struct rpir_output *output = to_rpir_output(base);
1216 struct weston_matrix *matrix = &output->matrix;
1217 const float half_w = 0.5f * base->width;
1218 const float half_h = 0.5f * base->height;
1219 float mag;
1220 float dx, dy;
1221
1222 weston_matrix_init(matrix);
1223 weston_matrix_translate(matrix, -base->x, -base->y, 0.0f);
1224
1225#ifdef SURFACE_TRANSFORM
1226 weston_matrix_translate(matrix, -half_w, -half_h, 0.0f);
1227 switch (base->transform) {
1228 case WL_OUTPUT_TRANSFORM_FLIPPED:
1229 weston_matrix_scale(matrix, -1.0f, 1.0f, 1.0f);
1230 case WL_OUTPUT_TRANSFORM_NORMAL:
1231 /* weston_matrix_rotate_xy(matrix, 1.0f, 0.0f); no-op */
1232 weston_matrix_translate(matrix, half_w, half_h, 0.0f);
1233 break;
1234
1235 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
1236 weston_matrix_scale(matrix, -1.0f, 1.0f, 1.0f);
1237 case WL_OUTPUT_TRANSFORM_90:
1238 weston_matrix_rotate_xy(matrix, 0.0f, 1.0f);
1239 weston_matrix_translate(matrix, half_h, half_w, 0.0f);
1240 break;
1241
1242 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
1243 weston_matrix_scale(matrix, -1.0f, 1.0f, 1.0f);
1244 case WL_OUTPUT_TRANSFORM_180:
1245 weston_matrix_rotate_xy(matrix, -1.0f, 0.0f);
1246 weston_matrix_translate(matrix, half_w, half_h, 0.0f);
1247 break;
1248
1249 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
1250 weston_matrix_scale(matrix, -1.0f, 1.0f, 1.0f);
1251 case WL_OUTPUT_TRANSFORM_270:
1252 weston_matrix_rotate_xy(matrix, 0.0f, -1.0f);
1253 weston_matrix_translate(matrix, half_h, half_w, 0.0f);
1254 break;
1255
1256 default:
1257 break;
1258 }
1259#endif
1260
1261 if (base->zoom.active) {
1262 /* The base->zoom stuff is in GL coordinate system */
1263 mag = 1.0f / (1.0f - base->zoom.spring_z.current);
1264 dx = -(base->zoom.trans_x + 1.0f) * half_w;
1265 dy = -(base->zoom.trans_y + 1.0f) * half_h;
1266 weston_matrix_translate(matrix, dx, dy, 0.0f);
1267 weston_matrix_scale(matrix, mag, mag, 1.0f);
1268 weston_matrix_translate(matrix, half_w, half_h, 0.0f);
1269 }
1270}
1271
1272/* Note: this won't work right for multiple outputs. A DispmanX Element
1273 * is tied to one DispmanX Display, i.e. output.
1274 */
1275static void
1276rpi_renderer_repaint_output(struct weston_output *base,
1277 pixman_region32_t *output_damage)
1278{
1279 struct weston_compositor *compositor = base->compositor;
1280 struct rpir_output *output = to_rpir_output(base);
Jason Ekstranda7af7042013-10-12 22:38:11 -05001281 struct weston_view *wv;
1282 struct rpir_view *view;
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001283 struct wl_list done_list;
1284 int layer = 1;
1285
1286 assert(output->update != DISPMANX_NO_HANDLE);
1287
1288 output_compute_matrix(base);
1289
1290 rpi_resource_release(&output->capture_buffer);
1291 free(output->capture_data);
1292 output->capture_data = NULL;
1293
Jason Ekstranda7af7042013-10-12 22:38:11 -05001294 /* Swap resources on surfaces as needed */
1295 wl_list_for_each_reverse(wv, &compositor->view_list, link)
1296 wv->surface->touched = 0;
1297
1298 wl_list_for_each_reverse(wv, &compositor->view_list, link) {
1299 view = to_rpir_view(wv);
1300
1301 if (!wv->surface->touched) {
1302 wv->surface->touched = 1;
1303
Tomeu Vizoso44247742013-10-24 15:38:32 +02001304 if (view->surface->buffer_type == BUFFER_TYPE_EGL ||
1305 view->surface->need_swap)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001306 rpir_surface_swap_pointers(view->surface);
1307 }
1308
Tomeu Vizoso74987582013-10-25 10:34:38 +02001309 if (view->surface->buffer_type == BUFFER_TYPE_EGL) {
1310 struct weston_buffer *buffer;
1311 buffer = view->surface->egl_front->buffer_ref.buffer;
1312 if (buffer != NULL) {
Pekka Paalanend5fbfb22013-11-22 17:30:39 +02001313 rpi_buffer_egl_lock(buffer);
Jason Ekstranda7af7042013-10-12 22:38:11 -05001314 } else {
Tomeu Vizoso74987582013-10-25 10:34:38 +02001315 weston_log("warning: client destroyed current front buffer\n");
1316
1317 wl_list_remove(&view->link);
1318 if (view->handle == DISPMANX_NO_HANDLE) {
1319 wl_list_init(&view->link);
1320 } else {
1321 rpir_view_dmx_remove(view, output->update);
1322 wl_list_insert(&output->view_cleanup_list,
1323 &view->link);
1324 }
Jason Ekstranda7af7042013-10-12 22:38:11 -05001325 }
1326 }
1327 }
1328
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001329 /* update all renderable surfaces */
1330 wl_list_init(&done_list);
Jason Ekstranda7af7042013-10-12 22:38:11 -05001331 wl_list_for_each_reverse(wv, &compositor->view_list, link) {
1332 if (wv->plane != &compositor->primary_plane)
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001333 continue;
1334
Jason Ekstranda7af7042013-10-12 22:38:11 -05001335 view = to_rpir_view(wv);
1336 assert(!wl_list_empty(&view->link) ||
1337 view->handle == DISPMANX_NO_HANDLE);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001338
Jason Ekstranda7af7042013-10-12 22:38:11 -05001339 wl_list_remove(&view->link);
1340 wl_list_insert(&done_list, &view->link);
1341 rpir_view_update(view, output, output->update, layer++);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001342 }
1343
Jason Ekstranda7af7042013-10-12 22:38:11 -05001344 /* Mark all surfaces as swapped */
1345 wl_list_for_each_reverse(wv, &compositor->view_list, link)
1346 to_rpir_surface(wv->surface)->need_swap = 0;
1347
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001348 /* Remove all surfaces that are still on screen, but were
1349 * not rendered this time.
1350 */
1351 rpir_output_dmx_remove_all(output, output->update);
1352
Jason Ekstranda7af7042013-10-12 22:38:11 -05001353 wl_list_insert_list(&output->view_list, &done_list);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001354 output->update = DISPMANX_NO_HANDLE;
1355
1356 /* The frame_signal is emitted in rpi_renderer_finish_frame(),
1357 * so that the firmware can capture the up-to-date contents.
1358 */
1359}
1360
1361static void
1362rpi_renderer_flush_damage(struct weston_surface *base)
1363{
1364 /* Called for every surface just before repainting it, if
1365 * having an shm buffer.
1366 */
1367 struct rpir_surface *surface = to_rpir_surface(base);
Jason Ekstrand6bd62942013-06-20 20:38:23 -05001368 struct weston_buffer *buffer = surface->buffer_ref.buffer;
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001369 int ret;
1370
1371 assert(buffer);
Jason Ekstrand6bd62942013-06-20 20:38:23 -05001372 assert(wl_shm_buffer_get(buffer->resource));
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001373
1374 ret = rpir_surface_damage(surface, buffer, &base->damage);
1375 if (ret)
1376 weston_log("%s error: updating Dispmanx resource failed.\n",
1377 __func__);
1378
1379 weston_buffer_reference(&surface->buffer_ref, NULL);
1380}
1381
1382static void
Jason Ekstrand6bd62942013-06-20 20:38:23 -05001383rpi_renderer_attach(struct weston_surface *base, struct weston_buffer *buffer)
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001384{
1385 /* Called every time a client commits an attach. */
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001386 struct rpir_surface *surface = to_rpir_surface(base);
1387
1388 assert(surface);
1389 if (!surface)
1390 return;
1391
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001392 if (surface->buffer_type == BUFFER_TYPE_SHM) {
1393 if (!surface->single_buffer)
1394 /* XXX: need to check if in middle of update */
1395 rpi_resource_release(surface->back);
1396
Jason Ekstranda7af7042013-10-12 22:38:11 -05001397 if (!surface->visible_views)
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001398 /* XXX: cannot do this, if middle of an update */
1399 rpi_resource_release(surface->front);
1400
1401 weston_buffer_reference(&surface->buffer_ref, NULL);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001402 }
1403
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001404 /* If buffer is NULL, Weston core unmaps the surface, the surface
1405 * will not appear in repaint list, and so rpi_renderer_repaint_output
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001406 * will remove the DispmanX element. Later, for SHM, also the front
1407 * buffer will be released in the cleanup_list processing.
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001408 */
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001409 if (!buffer)
1410 return;
1411
1412 if (wl_shm_buffer_get(buffer->resource)) {
1413 surface->buffer_type = BUFFER_TYPE_SHM;
1414 buffer->shm_buffer = wl_shm_buffer_get(buffer->resource);
1415 buffer->width = wl_shm_buffer_get_width(buffer->shm_buffer);
1416 buffer->height = wl_shm_buffer_get_height(buffer->shm_buffer);
1417
1418 weston_buffer_reference(&surface->buffer_ref, buffer);
1419 } else {
1420#if ENABLE_EGL
1421 struct rpi_renderer *renderer = to_rpi_renderer(base->compositor);
Tomeu Vizosoa8e5f292013-10-09 11:29:45 +02001422 struct wl_resource *wl_resource = buffer->resource;
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001423
1424 if (!renderer->has_bind_display ||
1425 !renderer->query_buffer(renderer->egl_display,
1426 wl_resource,
1427 EGL_WIDTH, &buffer->width)) {
1428 weston_log("unhandled buffer type!\n");
1429 weston_buffer_reference(&surface->buffer_ref, NULL);
1430 surface->buffer_type = BUFFER_TYPE_NULL;
1431 }
1432
1433 renderer->query_buffer(renderer->egl_display,
1434 wl_resource,
1435 EGL_HEIGHT, &buffer->height);
1436
1437 surface->buffer_type = BUFFER_TYPE_EGL;
1438
1439 if(surface->egl_back == NULL)
1440 surface->egl_back = calloc(1, sizeof *surface->egl_back);
1441
1442 weston_buffer_reference(&surface->egl_back->buffer_ref, buffer);
1443 surface->egl_back->resource_handle =
1444 vc_dispmanx_get_handle_from_wl_buffer(wl_resource);
1445#else
1446 weston_log("unhandled buffer type!\n");
1447 weston_buffer_reference(&surface->buffer_ref, NULL);
1448 surface->buffer_type = BUFFER_TYPE_NULL;
1449#endif
1450 }
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001451}
1452
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +03001453static void
1454rpir_surface_handle_surface_destroy(struct wl_listener *listener, void *data)
1455{
1456 struct rpir_surface *surface;
1457 struct weston_surface *base = data;
1458
1459 surface = container_of(listener, struct rpir_surface,
1460 surface_destroy_listener);
1461
1462 assert(surface);
1463 assert(surface->surface == base);
1464 if (!surface)
1465 return;
1466
1467 surface->surface = NULL;
1468 base->renderer_state = NULL;
1469
1470 if (wl_list_empty(&surface->views))
1471 rpir_surface_destroy(surface);
1472}
1473
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001474static int
1475rpi_renderer_create_surface(struct weston_surface *base)
1476{
1477 struct rpi_renderer *renderer = to_rpi_renderer(base->compositor);
1478 struct rpir_surface *surface;
1479
1480 assert(base->renderer_state == NULL);
1481
1482 surface = rpir_surface_create(renderer);
1483 if (!surface)
1484 return -1;
1485
1486 surface->surface = base;
1487 base->renderer_state = surface;
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +03001488
1489 surface->surface_destroy_listener.notify =
1490 rpir_surface_handle_surface_destroy;
1491 wl_signal_add(&base->destroy_signal,
1492 &surface->surface_destroy_listener);
1493
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001494 return 0;
1495}
1496
Jason Ekstranda7af7042013-10-12 22:38:11 -05001497static int
1498rpi_renderer_create_view(struct weston_view *base)
1499{
1500 struct rpir_surface *surface = to_rpir_surface(base->surface);
1501 struct rpir_view *view;
1502
1503 assert(base->renderer_state == NULL);
1504
1505 view = rpir_view_create(surface);
1506 if (!view)
1507 return -1;
1508
1509 view->view = base;
1510 base->renderer_state = view;
Tomeu Vizoso96dc9e42013-10-28 10:17:45 +01001511
1512 view->view_destroy_listener.notify =
1513 rpir_view_handle_view_destroy;
1514 wl_signal_add(&base->destroy_signal,
1515 &view->view_destroy_listener);
1516
Jason Ekstranda7af7042013-10-12 22:38:11 -05001517 return 0;
1518}
1519
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001520static void
1521rpi_renderer_surface_set_color(struct weston_surface *base,
1522 float red, float green, float blue, float alpha)
1523{
1524 struct rpir_surface *surface = to_rpir_surface(base);
1525 uint8_t color[4];
1526 VC_RECT_T rect;
1527 int ret;
1528
1529 assert(surface);
1530
1531 ret = rpi_resource_realloc(surface->back, VC_IMAGE_ARGB8888,
1532 1, 1, 4, 1);
1533 if (ret < 0) {
1534 weston_log("Error: %s: rpi_resource_realloc failed.\n",
1535 __func__);
1536 return;
1537 }
1538
1539 color[0] = float2uint8(blue);
1540 color[1] = float2uint8(green);
1541 color[2] = float2uint8(red);
1542 color[3] = float2uint8(alpha);
1543
1544 vc_dispmanx_rect_set(&rect, 0, 0, 1, 1);
1545 ret = vc_dispmanx_resource_write_data(surface->back->handle,
1546 VC_IMAGE_ARGB8888,
1547 4, color, &rect);
1548 if (ret) {
1549 weston_log("Error: %s: resource_write_data failed.\n",
1550 __func__);
1551 return;
1552 }
1553
1554 DBG("%s: resource %p solid color BGRA %u,%u,%u,%u\n", __func__,
1555 surface->back, color[0], color[1], color[2], color[3]);
1556
1557 /*pixman_region32_copy(&surface->prev_damage, damage);*/
1558 surface->need_swap = 1;
1559}
1560
1561static void
Tomeu Vizoso96dc9e42013-10-28 10:17:45 +01001562rpir_view_handle_view_destroy(struct wl_listener *listener, void *data)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001563{
Tomeu Vizoso96dc9e42013-10-28 10:17:45 +01001564 struct rpir_view *view;
1565 struct weston_view *base = data;
1566
1567 view = container_of(listener, struct rpir_view, view_destroy_listener);
Jason Ekstranda7af7042013-10-12 22:38:11 -05001568
1569 assert(view);
1570 assert(view->view == base);
1571 if (!view)
1572 return;
1573
Tomeu Vizoso34dad7d2013-10-25 10:34:37 +02001574 view->view = NULL;
Tomeu Vizoso96dc9e42013-10-28 10:17:45 +01001575 base->renderer_state = NULL;
Tomeu Vizoso34dad7d2013-10-25 10:34:37 +02001576
Tomeu Vizoso96dc9e42013-10-28 10:17:45 +01001577 /* If guaranteed to not be on screen, just destroy it. */
Jason Ekstranda7af7042013-10-12 22:38:11 -05001578 if (wl_list_empty(&view->link))
1579 rpir_view_destroy(view);
1580
1581 /* Otherwise, the view is either on screen and needs
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001582 * to be removed by a repaint update, or it is in the
Jason Ekstranda7af7042013-10-12 22:38:11 -05001583 * view_cleanup_list, and will be destroyed by
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001584 * rpi_renderer_finish_frame().
1585 */
1586}
1587
1588static void
1589rpi_renderer_destroy(struct weston_compositor *compositor)
1590{
1591 struct rpi_renderer *renderer = to_rpi_renderer(compositor);
1592
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001593#if ENABLE_EGL
1594 if (renderer->has_bind_display)
1595 renderer->unbind_display(renderer->egl_display,
1596 compositor->wl_display);
1597#endif
1598
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001599 free(renderer);
1600 compositor->renderer = NULL;
1601}
1602
1603WL_EXPORT int
1604rpi_renderer_create(struct weston_compositor *compositor,
1605 const struct rpi_renderer_parameters *params)
1606{
1607 struct rpi_renderer *renderer;
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001608#if ENABLE_EGL
1609 const char *extensions;
1610 EGLBoolean ret;
1611 EGLint major, minor;
1612#endif
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001613
1614 weston_log("Initializing the DispmanX compositing renderer\n");
1615
1616 renderer = calloc(1, sizeof *renderer);
1617 if (renderer == NULL)
1618 return -1;
1619
1620 renderer->single_buffer = params->single_buffer;
1621
1622 renderer->base.read_pixels = rpi_renderer_read_pixels;
1623 renderer->base.repaint_output = rpi_renderer_repaint_output;
1624 renderer->base.flush_damage = rpi_renderer_flush_damage;
1625 renderer->base.attach = rpi_renderer_attach;
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001626 renderer->base.surface_set_color = rpi_renderer_surface_set_color;
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001627 renderer->base.destroy = rpi_renderer_destroy;
1628
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001629#ifdef ENABLE_EGL
1630 renderer->egl_display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
1631 if (renderer->egl_display == EGL_NO_DISPLAY) {
1632 weston_log("failed to create EGL display\n");
1633 return -1;
1634 }
1635
1636 if (!eglInitialize(renderer->egl_display, &major, &minor)) {
1637 weston_log("failed to initialize EGL display\n");
1638 return -1;
1639 }
1640
1641 renderer->bind_display =
1642 (void *) eglGetProcAddress("eglBindWaylandDisplayWL");
1643 renderer->unbind_display =
1644 (void *) eglGetProcAddress("eglUnbindWaylandDisplayWL");
1645 renderer->query_buffer =
1646 (void *) eglGetProcAddress("eglQueryWaylandBufferWL");
1647
1648 extensions = (const char *) eglQueryString(renderer->egl_display,
1649 EGL_EXTENSIONS);
1650 if (!extensions) {
1651 weston_log("Retrieving EGL extension string failed.\n");
1652 return -1;
1653 }
1654
1655 if (strstr(extensions, "EGL_WL_bind_wayland_display"))
1656 renderer->has_bind_display = 1;
1657
1658 if (renderer->has_bind_display) {
1659 ret = renderer->bind_display(renderer->egl_display,
1660 compositor->wl_display);
1661 if (!ret)
1662 renderer->has_bind_display = 0;
1663 }
1664#endif
1665
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001666 compositor->renderer = &renderer->base;
1667 compositor->read_format = PIXMAN_a8r8g8b8;
1668 /* WESTON_CAP_ROTATION_ANY not supported */
1669
Tomeu Vizoso03681892013-08-06 20:05:57 +02001670 wl_display_add_shm_format(compositor->wl_display, WL_SHM_FORMAT_RGB565);
1671
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001672 return 0;
1673}
1674
1675WL_EXPORT int
1676rpi_renderer_output_create(struct weston_output *base,
1677 DISPMANX_DISPLAY_HANDLE_T display)
1678{
1679 struct rpir_output *output;
1680
1681 assert(base->renderer_state == NULL);
1682
1683 output = calloc(1, sizeof *output);
1684 if (!output)
1685 return -1;
1686
1687 output->display = display;
1688 output->update = DISPMANX_NO_HANDLE;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001689 wl_list_init(&output->view_list);
1690 wl_list_init(&output->view_cleanup_list);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001691 rpi_resource_init(&output->capture_buffer);
1692 base->renderer_state = output;
1693
1694 return 0;
1695}
1696
1697WL_EXPORT void
1698rpi_renderer_output_destroy(struct weston_output *base)
1699{
1700 struct rpir_output *output = to_rpir_output(base);
Jason Ekstranda7af7042013-10-12 22:38:11 -05001701 struct rpir_view *view;
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001702 DISPMANX_UPDATE_HANDLE_T update;
1703
1704 rpi_resource_release(&output->capture_buffer);
1705 free(output->capture_data);
1706 output->capture_data = NULL;
1707
1708 update = vc_dispmanx_update_start(0);
1709 rpir_output_dmx_remove_all(output, update);
1710 vc_dispmanx_update_submit_sync(update);
1711
Jason Ekstranda7af7042013-10-12 22:38:11 -05001712 while (!wl_list_empty(&output->view_cleanup_list)) {
1713 view = container_of(output->view_cleanup_list.next,
1714 struct rpir_view, link);
1715 rpir_view_destroy(view);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001716 }
1717
1718 free(output);
1719 base->renderer_state = NULL;
1720}
1721
1722WL_EXPORT void
1723rpi_renderer_set_update_handle(struct weston_output *base,
1724 DISPMANX_UPDATE_HANDLE_T handle)
1725{
1726 struct rpir_output *output = to_rpir_output(base);
1727
1728 output->update = handle;
1729}
1730
1731WL_EXPORT void
1732rpi_renderer_finish_frame(struct weston_output *base)
1733{
1734 struct rpir_output *output = to_rpir_output(base);
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001735 struct weston_compositor *compositor = base->compositor;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001736 struct weston_view *wv;
1737 struct rpir_view *view;
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001738
Jason Ekstranda7af7042013-10-12 22:38:11 -05001739 while (!wl_list_empty(&output->view_cleanup_list)) {
1740 view = container_of(output->view_cleanup_list.next,
1741 struct rpir_view, link);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001742
Jason Ekstranda7af7042013-10-12 22:38:11 -05001743 if (view->view) {
1744 /* The weston_view still exists, but is
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001745 * temporarily not visible, and hence its Element
1746 * was removed. The current front buffer contents
1747 * must be preserved.
1748 */
Jason Ekstranda7af7042013-10-12 22:38:11 -05001749 if (!view->surface->visible_views)
1750 rpi_resource_release(view->surface->back);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001751
Jason Ekstranda7af7042013-10-12 22:38:11 -05001752 wl_list_remove(&view->link);
1753 wl_list_init(&view->link);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001754 } else {
Jason Ekstranda7af7042013-10-12 22:38:11 -05001755 rpir_view_destroy(view);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001756 }
1757 }
1758
Jason Ekstranda7af7042013-10-12 22:38:11 -05001759 wl_list_for_each(wv, &compositor->view_list, link) {
1760 view = to_rpir_view(wv);
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001761
Jason Ekstranda7af7042013-10-12 22:38:11 -05001762 if (view->surface->buffer_type != BUFFER_TYPE_EGL)
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001763 continue;
1764
Tomeu Vizoso74987582013-10-25 10:34:38 +02001765 rpir_egl_buffer_destroy(view->surface->egl_old_front);
Jason Ekstranda7af7042013-10-12 22:38:11 -05001766 view->surface->egl_old_front = NULL;
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001767 }
1768
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001769 wl_signal_emit(&base->frame_signal, base);
1770}