blob: b7e9487498f39b6cf2339027e97c2835ace447b5 [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;
139};
140
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300141struct rpir_output {
142 DISPMANX_DISPLAY_HANDLE_T display;
143
144 DISPMANX_UPDATE_HANDLE_T update;
145 struct weston_matrix matrix;
146
147 /* all Elements currently on screen */
Jason Ekstranda7af7042013-10-12 22:38:11 -0500148 struct wl_list view_list; /* struct rpir_surface::link */
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300149
150 /* Elements just removed, waiting for update completion */
Jason Ekstranda7af7042013-10-12 22:38:11 -0500151 struct wl_list view_cleanup_list; /* struct rpir_surface::link */
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300152
153 struct rpi_resource capture_buffer;
154 uint8_t *capture_data;
155};
156
157struct rpi_renderer {
158 struct weston_renderer base;
159
160 int single_buffer;
Tomeu Vizosob4659eb2013-10-07 11:02:20 +0200161
162#ifdef ENABLE_EGL
163 EGLDisplay egl_display;
164
165 PFNEGLBINDWAYLANDDISPLAYWL bind_display;
166 PFNEGLUNBINDWAYLANDDISPLAYWL unbind_display;
167 PFNEGLQUERYWAYLANDBUFFERWL query_buffer;
168#endif
169 int has_bind_display;
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300170};
171
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300172static int
173rpi_renderer_create_surface(struct weston_surface *base);
174
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300175static inline struct rpir_surface *
176to_rpir_surface(struct weston_surface *surface)
177{
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300178 if (!surface->renderer_state)
179 rpi_renderer_create_surface(surface);
180
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300181 return surface->renderer_state;
182}
183
Jason Ekstranda7af7042013-10-12 22:38:11 -0500184static inline struct rpir_view *
185to_rpir_view(struct weston_view *view)
186{
187 return view->renderer_state;
188}
189
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300190static inline struct rpir_output *
191to_rpir_output(struct weston_output *output)
192{
193 return output->renderer_state;
194}
195
196static inline struct rpi_renderer *
197to_rpi_renderer(struct weston_compositor *compositor)
198{
199 return container_of(compositor->renderer, struct rpi_renderer, base);
200}
201
202static inline int
203int_max(int a, int b)
204{
205 return a > b ? a : b;
206}
207
208static inline void
209int_swap(int *a, int *b)
210{
211 int tmp = *a;
212 *a = *b;
213 *b = tmp;
214}
215
216static uint8_t
217float2uint8(float f)
218{
219 int v = roundf(f * 255.0f);
220
221 return v < 0 ? 0 : (v > 255 ? 255 : v);
222}
223
224static void
225rpi_resource_init(struct rpi_resource *resource)
226{
227 resource->handle = DISPMANX_NO_HANDLE;
228}
229
230static void
231rpi_resource_release(struct rpi_resource *resource)
232{
233 if (resource->handle == DISPMANX_NO_HANDLE)
234 return;
235
236 vc_dispmanx_resource_delete(resource->handle);
237 DBG("resource %p release\n", resource);
238 resource->handle = DISPMANX_NO_HANDLE;
239}
240
241static int
242rpi_resource_realloc(struct rpi_resource *resource, VC_IMAGE_TYPE_T ifmt,
243 int width, int height, int stride, int buffer_height)
244{
245 uint32_t dummy;
246
247 if (resource->handle != DISPMANX_NO_HANDLE &&
248 resource->width == width &&
249 resource->height == height &&
250 resource->stride == stride &&
251 resource->buffer_height == buffer_height &&
252 resource->ifmt == ifmt)
253 return 0;
254
255 rpi_resource_release(resource);
256
257 /* NOTE: if stride is not a multiple of 16 pixels in bytes,
258 * the vc_image_* functions may break. Dispmanx elements
259 * should be fine, though. Buffer_height probably has similar
260 * constraints, too.
261 */
262 resource->handle =
263 vc_dispmanx_resource_create(ifmt,
264 width | (stride << 16),
265 height | (buffer_height << 16),
266 &dummy);
267 if (resource->handle == DISPMANX_NO_HANDLE)
268 return -1;
269
270 resource->width = width;
271 resource->height = height;
272 resource->stride = stride;
273 resource->buffer_height = buffer_height;
274 resource->ifmt = ifmt;
275 DBG("resource %p alloc\n", resource);
276 return 1;
277}
278
279/* A firmware workaround for broken ALPHA_PREMULT + ALPHA_MIX hardware. */
280#define PREMULT_ALPHA_FLAG (1 << 31)
281
282static VC_IMAGE_TYPE_T
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500283shm_buffer_get_vc_format(struct wl_shm_buffer *buffer)
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300284{
285 switch (wl_shm_buffer_get_format(buffer)) {
286 case WL_SHM_FORMAT_XRGB8888:
287 return VC_IMAGE_XRGB8888;
288 case WL_SHM_FORMAT_ARGB8888:
289 return VC_IMAGE_ARGB8888 | PREMULT_ALPHA_FLAG;
Tomeu Vizoso03681892013-08-06 20:05:57 +0200290 case WL_SHM_FORMAT_RGB565:
291 return VC_IMAGE_RGB565;
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300292 default:
293 /* invalid format */
294 return VC_IMAGE_MIN;
295 }
296}
297
298static int
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500299rpi_resource_update(struct rpi_resource *resource, struct weston_buffer *buffer,
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300300 pixman_region32_t *region)
301{
302 pixman_region32_t write_region;
303 pixman_box32_t *r;
304 VC_RECT_T rect;
305 VC_IMAGE_TYPE_T ifmt;
306 uint32_t *pixels;
307 int width;
308 int height;
309 int stride;
310 int ret;
311#ifdef HAVE_RESOURCE_WRITE_DATA_RECT
312 int n;
313#endif
314
315 if (!buffer)
316 return -1;
317
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500318 ifmt = shm_buffer_get_vc_format(buffer->shm_buffer);
319 width = wl_shm_buffer_get_width(buffer->shm_buffer);
320 height = wl_shm_buffer_get_height(buffer->shm_buffer);
321 stride = wl_shm_buffer_get_stride(buffer->shm_buffer);
322 pixels = wl_shm_buffer_get_data(buffer->shm_buffer);
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300323
324 ret = rpi_resource_realloc(resource, ifmt & ~PREMULT_ALPHA_FLAG,
325 width, height, stride, height);
326 if (ret < 0)
327 return -1;
328
329 pixman_region32_init_rect(&write_region, 0, 0, width, height);
330 if (ret == 0)
331 pixman_region32_intersect(&write_region,
332 &write_region, region);
333
334#ifdef HAVE_RESOURCE_WRITE_DATA_RECT
335 /* XXX: Can this do a format conversion, so that scanout does not have to? */
336 r = pixman_region32_rectangles(&write_region, &n);
337 while (n--) {
338 vc_dispmanx_rect_set(&rect, r[n].x1, r[n].y1,
339 r[n].x2 - r[n].x1, r[n].y2 - r[n].y1);
340
341 ret = vc_dispmanx_resource_write_data_rect(resource->handle,
342 ifmt, stride,
343 pixels, &rect,
344 rect.x, rect.y);
345 DBG("%s: %p %ux%u@%u,%u, ret %d\n", __func__, resource,
346 rect.width, rect.height, rect.x, rect.y, ret);
347 if (ret)
348 break;
349 }
350#else
351 /* vc_dispmanx_resource_write_data() ignores ifmt,
352 * rect.x, rect.width, and uses stride only for computing
353 * the size of the transfer as rect.height * stride.
354 * Therefore we can only write rows starting at x=0.
355 * To be able to write more than one scanline at a time,
356 * the resource must have been created with the same stride
357 * as used here, and we must write full scanlines.
358 */
359
360 r = pixman_region32_extents(&write_region);
361 vc_dispmanx_rect_set(&rect, 0, r->y1, width, r->y2 - r->y1);
362 ret = vc_dispmanx_resource_write_data(resource->handle,
363 ifmt, stride, pixels, &rect);
364 DBG("%s: %p %ux%u@%u,%u, ret %d\n", __func__, resource,
365 width, r->y2 - r->y1, 0, r->y1, ret);
366#endif
367
368 pixman_region32_fini(&write_region);
369
370 return ret ? -1 : 0;
371}
372
Tomeu Vizoso74987582013-10-25 10:34:38 +0200373static void
374rpir_egl_buffer_destroy(struct rpir_egl_buffer *egl_buffer)
375{
376 struct weston_buffer *buffer;
377
378 if (egl_buffer == NULL)
379 return;
380
381 buffer = egl_buffer->buffer_ref.buffer;
382 if (buffer == NULL) {
383 /* The client has already destroyed the wl_buffer, the
384 * compositor has the responsibility to delete the resource.
385 */
386 vc_dispmanx_resource_delete(egl_buffer->resource_handle);
387 } else {
388 vc_dispmanx_set_wl_buffer_in_use(buffer->resource, 0);
389 weston_buffer_reference(&egl_buffer->buffer_ref, NULL);
390 }
391
392 free(egl_buffer);
393}
394
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300395static struct rpir_surface *
396rpir_surface_create(struct rpi_renderer *renderer)
397{
398 struct rpir_surface *surface;
399
400 surface = calloc(1, sizeof *surface);
401 if (!surface)
402 return NULL;
403
Tomeu Vizoso5c3ea3b2013-10-24 15:38:30 +0200404 wl_list_init(&surface->views);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500405 surface->visible_views = 0;
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300406 surface->single_buffer = renderer->single_buffer;
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300407 rpi_resource_init(&surface->resources[0]);
408 rpi_resource_init(&surface->resources[1]);
409 surface->front = &surface->resources[0];
410 if (surface->single_buffer)
411 surface->back = &surface->resources[0];
412 else
413 surface->back = &surface->resources[1];
Tomeu Vizosob4659eb2013-10-07 11:02:20 +0200414 surface->buffer_type = BUFFER_TYPE_NULL;
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300415
416 pixman_region32_init(&surface->prev_damage);
417
418 return surface;
419}
420
421static void
422rpir_surface_destroy(struct rpir_surface *surface)
423{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500424 if (surface->visible_views)
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300425 weston_log("ERROR rpi: destroying on-screen element\n");
426
Jason Ekstranda7af7042013-10-12 22:38:11 -0500427 assert(wl_list_empty(&surface->views));
428
429 if (surface->surface)
430 surface->surface->renderer_state = NULL;
431
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300432 pixman_region32_fini(&surface->prev_damage);
433 rpi_resource_release(&surface->resources[0]);
434 rpi_resource_release(&surface->resources[1]);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500435 DBG("rpir_surface %p destroyed (%u)\n", surface, surface->visible_views);
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300436
Tomeu Vizoso74987582013-10-25 10:34:38 +0200437 rpir_egl_buffer_destroy(surface->egl_back);
438 rpir_egl_buffer_destroy(surface->egl_front);
439 rpir_egl_buffer_destroy(surface->egl_old_front);
Tomeu Vizosob4659eb2013-10-07 11:02:20 +0200440
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300441 free(surface);
442}
443
444static int
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500445rpir_surface_damage(struct rpir_surface *surface, struct weston_buffer *buffer,
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300446 pixman_region32_t *damage)
447{
448 pixman_region32_t upload;
449 int ret;
450
451 if (!pixman_region32_not_empty(damage))
452 return 0;
453
454 DBG("rpir_surface %p update resource %p\n", surface, surface->back);
455
456 /* XXX: todo: if no surface->handle, update front buffer directly
457 * to avoid creating a new back buffer */
458 if (surface->single_buffer) {
459 ret = rpi_resource_update(surface->front, buffer, damage);
460 } else {
461 pixman_region32_init(&upload);
462 pixman_region32_union(&upload, &surface->prev_damage, damage);
463 ret = rpi_resource_update(surface->back, buffer, &upload);
464 pixman_region32_fini(&upload);
465 }
466
467 pixman_region32_copy(&surface->prev_damage, damage);
468 surface->need_swap = 1;
469
470 return ret;
471}
472
Jason Ekstranda7af7042013-10-12 22:38:11 -0500473static struct rpir_view *
474rpir_view_create(struct rpir_surface *surface)
475{
476 struct rpir_view *view;
477
478 view = calloc(1, sizeof *view);
479 if (!view)
480 return NULL;
481
482 view->surface = surface;
483 wl_list_insert(&surface->views, &view->surface_link);
484
485 wl_list_init(&view->link);
486 view->handle = DISPMANX_NO_HANDLE;
487
488 return view;
489}
490
491static void
492rpir_view_destroy(struct rpir_view *view)
493{
494 wl_list_remove(&view->link);
495
496 if (view->handle != DISPMANX_NO_HANDLE) {
497 view->surface->visible_views--;
498 weston_log("ERROR rpi: destroying on-screen element\n");
499 }
500
501 if (view->view)
502 view->view->renderer_state = NULL;
503
504 wl_list_remove(&view->surface_link);
505 if (wl_list_empty(&view->surface->views) && view->surface->surface == NULL)
506 rpir_surface_destroy(view->surface);
507
508 DBG("rpir_view %p destroyed (%d)\n", view, view->handle);
509
510 free(view);
511}
512
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300513static void
514matrix_type_str(struct weston_matrix *matrix, char *buf, int len)
515{
516 static const char types[33] = "TSRO";
517 unsigned mask = matrix->type;
518 int i = 0;
519
520 while (mask && i < len - 1) {
521 if (mask & (1u << i))
522 *buf++ = types[i];
523 mask &= ~(1u << i);
524 i++;
525 }
526 *buf = '\0';
527}
528
529static void
530log_print_matrix(struct weston_matrix *matrix)
531{
532 char typestr[6];
533 float *d = matrix->d;
534
535 matrix_type_str(matrix, typestr, sizeof typestr);
536 weston_log_continue("%14.6e %14.6e %14.6e %14.6e\n",
537 d[0], d[4], d[8], d[12]);
538 weston_log_continue("%14.6e %14.6e %14.6e %14.6e\n",
539 d[1], d[5], d[9], d[13]);
540 weston_log_continue("%14.6e %14.6e %14.6e %14.6e\n",
541 d[2], d[6], d[10], d[14]);
542 weston_log_continue("%14.6e %14.6e %14.6e %14.6e type: %s\n",
543 d[3], d[7], d[11], d[15], typestr);
544}
545
546static void
547warn_bad_matrix(struct weston_matrix *total, struct weston_matrix *output,
548 struct weston_matrix *surface)
549{
550 static int n_warn;
551 char typestr[6];
552
553 if (n_warn++ == 10)
554 weston_log("%s: not showing more warnings\n", __func__);
555
556 if (n_warn > 10)
557 return;
558
559 weston_log("%s: warning: total transformation is not renderable:\n",
560 __func__);
561 log_print_matrix(total);
562
563 matrix_type_str(surface, typestr, sizeof typestr);
564 weston_log_continue("surface matrix type: %s\n", typestr);
565 matrix_type_str(output, typestr, sizeof typestr);
566 weston_log_continue("output matrix type: %s\n", typestr);
567}
568
569/*#define SURFACE_TRANSFORM */
570
571static int
Jason Ekstranda7af7042013-10-12 22:38:11 -0500572rpir_view_compute_rects(struct rpir_view *view,
573 VC_RECT_T *src_rect, VC_RECT_T *dst_rect,
574 VC_IMAGE_TRANSFORM_T *flipmask)
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300575{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500576 struct weston_output *output_base = view->view->surface->output;
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300577 struct rpir_output *output = to_rpir_output(output_base);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500578 struct weston_matrix matrix = view->view->transform.matrix;
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300579 VC_IMAGE_TRANSFORM_T flipt = 0;
580 int src_x, src_y;
581 int dst_x, dst_y;
582 int src_width, src_height;
583 int dst_width, dst_height;
584 struct weston_vector p1 = {{ 0.0f, 0.0f, 0.0f, 1.0f }};
585 struct weston_vector p2 = {{ 0.0f, 0.0f, 0.0f, 1.0f }};
586 int t;
587 int over;
588
589 /* XXX: take buffer transform into account */
590
591 /* src is in 16.16, dst is in 32.0 fixed point.
592 * Negative values are not allowed in VC_RECT_T.
593 * Clip size to output boundaries, firmware ignores
594 * huge elements like 8192x8192.
595 */
596
597 src_x = 0 << 16;
598 src_y = 0 << 16;
Tomeu Vizosob4659eb2013-10-07 11:02:20 +0200599
Jason Ekstranda7af7042013-10-12 22:38:11 -0500600 if (view->surface->buffer_type == BUFFER_TYPE_EGL) {
601 struct weston_buffer *buffer =
602 view->surface->egl_front->buffer_ref.buffer;
Tomeu Vizosob4659eb2013-10-07 11:02:20 +0200603
604 src_width = buffer->width << 16;
605 src_height = buffer->height << 16;
606 } else {
Jason Ekstranda7af7042013-10-12 22:38:11 -0500607 src_width = view->surface->front->width << 16;
608 src_height = view->surface->front->height << 16;
Tomeu Vizosob4659eb2013-10-07 11:02:20 +0200609 }
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300610
611 weston_matrix_multiply(&matrix, &output->matrix);
612
613#ifdef SURFACE_TRANSFORM
614 if (matrix.type >= WESTON_MATRIX_TRANSFORM_OTHER) {
615#else
616 if (matrix.type >= WESTON_MATRIX_TRANSFORM_ROTATE) {
617#endif
618 warn_bad_matrix(&matrix, &output->matrix,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500619 &view->view->transform.matrix);
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300620 } else {
621 if (matrix.type & WESTON_MATRIX_TRANSFORM_ROTATE) {
622 if (fabsf(matrix.d[0]) < 1e-4f &&
623 fabsf(matrix.d[5]) < 1e-4f) {
624 flipt |= TRANSFORM_TRANSPOSE;
625 } else if (fabsf(matrix.d[1]) < 1e-4 &&
626 fabsf(matrix.d[4]) < 1e-4) {
627 /* no transpose */
628 } else {
629 warn_bad_matrix(&matrix, &output->matrix,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500630 &view->view->transform.matrix);
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300631 }
632 }
633 }
634
Jason Ekstranda7af7042013-10-12 22:38:11 -0500635 p2.f[0] = view->view->geometry.width;
636 p2.f[1] = view->view->geometry.height;
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300637
638 /* transform top-left and bot-right corner into screen coordinates */
639 weston_matrix_transform(&matrix, &p1);
640 weston_matrix_transform(&matrix, &p2);
641
642 /* Compute the destination rectangle on screen, converting
643 * negative dimensions to flips.
644 */
645
646 dst_width = round(p2.f[0] - p1.f[0]);
647 if (dst_width < 0) {
648 dst_x = round(p2.f[0]);
649 dst_width = -dst_width;
650
651 if (!(flipt & TRANSFORM_TRANSPOSE))
652 flipt |= TRANSFORM_HFLIP;
653 else
654 flipt |= TRANSFORM_VFLIP;
655 } else {
656 dst_x = round(p1.f[0]);
657 }
658
659 dst_height = round(p2.f[1] - p1.f[1]);
660 if (dst_height < 0) {
661 dst_y = round(p2.f[1]);
662 dst_height = -dst_height;
663
664 if (!(flipt & TRANSFORM_TRANSPOSE))
665 flipt |= TRANSFORM_VFLIP;
666 else
667 flipt |= TRANSFORM_HFLIP;
668 } else {
669 dst_y = round(p1.f[1]);
670 }
671
672 if (dst_width == 0 || dst_height == 0) {
673 DBG("ignored, zero surface area before clipping\n");
674 return -1;
675 }
676
677#ifdef SURFACE_TRANSFORM
678 /* Dispmanx works as if you flipped the whole screen, when
679 * you flip an element. But, we want to flip an element in place.
680 * XXX: fixme
681 */
682 if (flipt & TRANSFORM_HFLIP)
683 dst_x = output_base->width - dst_x;
684 if (flipt & TRANSFORM_VFLIP)
685 dst_y = output_base->height - dst_y;
686 if (flipt & TRANSFORM_TRANSPOSE) {
687 int_swap(&dst_x, &dst_y);
688 int_swap(&dst_width, &dst_height);
689 }
690#else
691 switch (output_base->transform) {
692 case WL_OUTPUT_TRANSFORM_FLIPPED:
693 flipt = TRANSFORM_HFLIP;
694 break;
695 case WL_OUTPUT_TRANSFORM_NORMAL:
696 flipt = 0;
697 break;
698
699 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
700 flipt = TRANSFORM_HFLIP | TRANSFORM_VFLIP | TRANSFORM_TRANSPOSE;
701 break;
702 case WL_OUTPUT_TRANSFORM_90:
703 flipt = TRANSFORM_VFLIP | TRANSFORM_TRANSPOSE;
704 break;
705 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
706 flipt = TRANSFORM_VFLIP;
707 break;
708 case WL_OUTPUT_TRANSFORM_180:
709 flipt = TRANSFORM_HFLIP | TRANSFORM_VFLIP;
710 break;
711
712 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
713 flipt = TRANSFORM_TRANSPOSE;
714 break;
715 case WL_OUTPUT_TRANSFORM_270:
716 flipt = TRANSFORM_HFLIP | TRANSFORM_TRANSPOSE;
717 break;
718 default:
719 break;
720 }
721#endif
722
723 /* clip destination rectangle to screen dimensions */
724
725 if (dst_x < 0) {
726 t = (int64_t)dst_x * src_width / dst_width;
727 src_width += t;
728 dst_width += dst_x;
729 src_x -= t;
730 dst_x = 0;
731 }
732
733 if (dst_y < 0) {
734 t = (int64_t)dst_y * src_height / dst_height;
735 src_height += t;
736 dst_height += dst_y;
737 src_y -= t;
738 dst_y = 0;
739 }
740
741 over = dst_x + dst_width - output_base->width;
742 if (over > 0) {
743 t = (int64_t)over * src_width / dst_width;
744 src_width -= t;
745 dst_width -= over;
746 }
747
748 over = dst_y + dst_height - output_base->height;
749 if (over > 0) {
750 t = (int64_t)over * src_height / dst_height;
751 src_height -= t;
752 dst_height -= over;
753 }
754
755 src_width = int_max(src_width, 0);
756 src_height = int_max(src_height, 0);
757
Jason Ekstranda7af7042013-10-12 22:38:11 -0500758 DBG("rpir_view %p %dx%d: p1 %f, %f; p2 %f, %f\n", view,
759 view->view->geometry.width,
760 view->view->geometry.height,
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300761 p1.f[0], p1.f[1], p2.f[0], p2.f[1]);
762 DBG("src rect %d;%d, %d;%d, %d;%dx%d;%d\n",
763 src_x >> 16, src_x & 0xffff,
764 src_y >> 16, src_y & 0xffff,
765 src_width >> 16, src_width & 0xffff,
766 src_height >> 16, src_height & 0xffff);
767 DBG("dest rect %d, %d, %dx%d%s%s%s\n",
768 dst_x, dst_y, dst_width, dst_height,
769 (flipt & TRANSFORM_HFLIP) ? " hflip" : "",
770 (flipt & TRANSFORM_VFLIP) ? " vflip" : "",
771 (flipt & TRANSFORM_TRANSPOSE) ? " transp" : "");
772
773 assert(src_x >= 0);
774 assert(src_y >= 0);
775 assert(dst_x >= 0);
776 assert(dst_y >= 0);
777
778 if (dst_width < 1 || dst_height < 1) {
779 DBG("ignored, zero surface area after clipping\n");
780 return -1;
781 }
782
Tomeu Vizosob4659eb2013-10-07 11:02:20 +0200783 /* EGL buffers will be upside-down related to what DispmanX expects */
Jason Ekstranda7af7042013-10-12 22:38:11 -0500784 if (view->surface->buffer_type == BUFFER_TYPE_EGL)
Tomeu Vizosob4659eb2013-10-07 11:02:20 +0200785 flipt ^= TRANSFORM_VFLIP;
786
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300787 vc_dispmanx_rect_set(src_rect, src_x, src_y, src_width, src_height);
788 vc_dispmanx_rect_set(dst_rect, dst_x, dst_y, dst_width, dst_height);
789 *flipmask = flipt;
790
791 return 0;
792}
793
794static DISPMANX_TRANSFORM_T
795vc_image2dispmanx_transform(VC_IMAGE_TRANSFORM_T t)
796{
797 /* XXX: uhh, are these right? */
798 switch (t) {
799 case VC_IMAGE_ROT0:
800 return DISPMANX_NO_ROTATE;
801 case VC_IMAGE_MIRROR_ROT0:
802 return DISPMANX_FLIP_HRIZ;
803 case VC_IMAGE_MIRROR_ROT180:
804 return DISPMANX_FLIP_VERT;
805 case VC_IMAGE_ROT180:
806 return DISPMANX_ROTATE_180;
807 case VC_IMAGE_MIRROR_ROT90:
808 return DISPMANX_ROTATE_90 | DISPMANX_FLIP_HRIZ;
809 case VC_IMAGE_ROT270:
810 return DISPMANX_ROTATE_270;
811 case VC_IMAGE_ROT90:
812 return DISPMANX_ROTATE_90;
813 case VC_IMAGE_MIRROR_ROT270:
814 return DISPMANX_ROTATE_270 | DISPMANX_FLIP_VERT;
815 default:
816 assert(0 && "bad VC_IMAGE_TRANSFORM_T");
817 return DISPMANX_NO_ROTATE;
818 }
819}
820
Tomeu Vizosob4659eb2013-10-07 11:02:20 +0200821
822static DISPMANX_RESOURCE_HANDLE_T
823rpir_surface_get_resource(struct rpir_surface *surface)
824{
825 switch (surface->buffer_type) {
826 case BUFFER_TYPE_SHM:
827 case BUFFER_TYPE_NULL:
828 return surface->front->handle;
829 case BUFFER_TYPE_EGL:
830 if (surface->egl_front != NULL)
831 return surface->egl_front->resource_handle;
832 default:
833 return DISPMANX_NO_HANDLE;
834 }
835}
836
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300837static int
Jason Ekstranda7af7042013-10-12 22:38:11 -0500838rpir_view_dmx_add(struct rpir_view *view, struct rpir_output *output,
839 DISPMANX_UPDATE_HANDLE_T update, int layer)
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300840{
841 /* Do not use DISPMANX_FLAGS_ALPHA_PREMULT here.
842 * If you define PREMULT and ALPHA_MIX, the hardware will not
843 * multiply the source color with the element alpha, leading to
844 * bad colors. Instead, we define PREMULT during pixel data upload.
845 */
846 VC_DISPMANX_ALPHA_T alphasetup = {
847 DISPMANX_FLAGS_ALPHA_FROM_SOURCE |
848 DISPMANX_FLAGS_ALPHA_MIX,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500849 float2uint8(view->view->alpha), /* opacity 0-255 */
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300850 0 /* mask resource handle */
851 };
852 VC_RECT_T dst_rect;
853 VC_RECT_T src_rect;
854 VC_IMAGE_TRANSFORM_T flipmask;
855 int ret;
Tomeu Vizosob4659eb2013-10-07 11:02:20 +0200856 DISPMANX_RESOURCE_HANDLE_T resource_handle;
857
Jason Ekstranda7af7042013-10-12 22:38:11 -0500858 resource_handle = rpir_surface_get_resource(view->surface);
Tomeu Vizosob4659eb2013-10-07 11:02:20 +0200859 if (resource_handle == DISPMANX_NO_HANDLE) {
860 weston_log("%s: no buffer yet, aborting\n", __func__);
861 return 0;
862 }
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300863
Jason Ekstranda7af7042013-10-12 22:38:11 -0500864 ret = rpir_view_compute_rects(view, &src_rect, &dst_rect, &flipmask);
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300865 if (ret < 0)
866 return 0;
867
Jason Ekstranda7af7042013-10-12 22:38:11 -0500868 view->handle = vc_dispmanx_element_add(
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300869 update,
870 output->display,
871 layer,
872 &dst_rect,
Tomeu Vizosob4659eb2013-10-07 11:02:20 +0200873 resource_handle,
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300874 &src_rect,
875 DISPMANX_PROTECTION_NONE,
876 &alphasetup,
877 NULL /* clamp */,
878 vc_image2dispmanx_transform(flipmask));
Jason Ekstranda7af7042013-10-12 22:38:11 -0500879 DBG("rpir_surface %p add %u, alpha %f resource %d\n", view,
880 view->handle, view->view->alpha, resource_handle);
881
882 if (view->handle == DISPMANX_NO_HANDLE)
883 return -1;
884
885 view->surface->visible_views++;
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300886
887 return 1;
888}
889
890static void
Jason Ekstranda7af7042013-10-12 22:38:11 -0500891rpir_view_dmx_swap(struct rpir_view *view,
892 DISPMANX_UPDATE_HANDLE_T update)
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300893{
894 VC_RECT_T rect;
895 pixman_box32_t *r;
896
897 /* XXX: skip, iff resource was not reallocated, and single-buffering */
Jason Ekstranda7af7042013-10-12 22:38:11 -0500898 vc_dispmanx_element_change_source(update, view->handle,
899 view->surface->front->handle);
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300900
901 /* This is current damage now, after rpir_surface_damage() */
Jason Ekstranda7af7042013-10-12 22:38:11 -0500902 r = pixman_region32_extents(&view->surface->prev_damage);
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300903
904 vc_dispmanx_rect_set(&rect, r->x1, r->y1,
905 r->x2 - r->x1, r->y2 - r->y1);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500906 vc_dispmanx_element_modified(update, view->handle, &rect);
907 DBG("rpir_view %p swap\n", view);
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300908}
909
910static int
Jason Ekstranda7af7042013-10-12 22:38:11 -0500911rpir_view_dmx_move(struct rpir_view *view,
912 DISPMANX_UPDATE_HANDLE_T update, int layer)
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300913{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500914 uint8_t alpha = float2uint8(view->view->alpha);
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300915 VC_RECT_T dst_rect;
916 VC_RECT_T src_rect;
917 VC_IMAGE_TRANSFORM_T flipmask;
918 int ret;
919
920 /* XXX: return early, if all attributes stay the same */
921
Jason Ekstranda7af7042013-10-12 22:38:11 -0500922 if (view->surface->buffer_type == BUFFER_TYPE_EGL) {
Tomeu Vizosob4659eb2013-10-07 11:02:20 +0200923 DISPMANX_RESOURCE_HANDLE_T resource_handle;
924
Jason Ekstranda7af7042013-10-12 22:38:11 -0500925 resource_handle = rpir_surface_get_resource(view->surface);
Tomeu Vizosob4659eb2013-10-07 11:02:20 +0200926 if (resource_handle == DISPMANX_NO_HANDLE) {
927 weston_log("%s: no buffer yet, aborting\n", __func__);
928 return 0;
929 }
930
931 vc_dispmanx_element_change_source(update,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500932 view->handle,
Tomeu Vizosob4659eb2013-10-07 11:02:20 +0200933 resource_handle);
934 }
935
Jason Ekstranda7af7042013-10-12 22:38:11 -0500936 ret = rpir_view_compute_rects(view, &src_rect, &dst_rect, &flipmask);
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300937 if (ret < 0)
938 return 0;
939
940 ret = vc_dispmanx_element_change_attributes(
941 update,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500942 view->handle,
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300943 ELEMENT_CHANGE_LAYER |
944 ELEMENT_CHANGE_OPACITY |
945 ELEMENT_CHANGE_TRANSFORM |
946 ELEMENT_CHANGE_DEST_RECT |
947 ELEMENT_CHANGE_SRC_RECT,
948 layer,
949 alpha,
950 &dst_rect,
951 &src_rect,
952 DISPMANX_NO_HANDLE,
953 /* This really is DISPMANX_TRANSFORM_T, no matter
954 * what the header says. */
955 vc_image2dispmanx_transform(flipmask));
Jason Ekstranda7af7042013-10-12 22:38:11 -0500956 DBG("rpir_view %p move\n", view);
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300957
958 if (ret)
959 return -1;
960
961 return 1;
962}
963
964static void
Jason Ekstranda7af7042013-10-12 22:38:11 -0500965rpir_view_dmx_remove(struct rpir_view *view,
966 DISPMANX_UPDATE_HANDLE_T update)
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300967{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500968 if (view->handle == DISPMANX_NO_HANDLE)
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300969 return;
970
Jason Ekstranda7af7042013-10-12 22:38:11 -0500971 vc_dispmanx_element_remove(update, view->handle);
972 DBG("rpir_view %p remove %u\n", view, view->handle);
973 view->handle = DISPMANX_NO_HANDLE;
974 view->surface->visible_views--;
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300975}
976
977static void
978rpir_surface_swap_pointers(struct rpir_surface *surface)
979{
980 struct rpi_resource *tmp;
981
Tomeu Vizosob4659eb2013-10-07 11:02:20 +0200982 if (surface->buffer_type == BUFFER_TYPE_EGL) {
983 if (surface->egl_back != NULL) {
984 assert(surface->egl_old_front == NULL);
985 surface->egl_old_front = surface->egl_front;
986 surface->egl_front = surface->egl_back;
987 surface->egl_back = NULL;
Tomeu Vizoso15767812013-10-24 15:38:31 +0200988 DBG("new front %d\n", surface->egl_front->resource_handle);
Tomeu Vizosob4659eb2013-10-07 11:02:20 +0200989 }
Tomeu Vizosob4659eb2013-10-07 11:02:20 +0200990 } else {
Jason Ekstranda7af7042013-10-12 22:38:11 -0500991 tmp = surface->front;
992 surface->front = surface->back;
993 surface->back = tmp;
Tomeu Vizoso15767812013-10-24 15:38:31 +0200994 DBG("new back %p, new front %p\n", surface->back, surface->front);
Tomeu Vizosob4659eb2013-10-07 11:02:20 +0200995 }
Jason Ekstranda7af7042013-10-12 22:38:11 -0500996}
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300997
Jason Ekstranda7af7042013-10-12 22:38:11 -0500998static int
999is_view_not_visible(struct weston_view *view)
1000{
1001 /* Return true, if surface is guaranteed to be totally obscured. */
1002 int ret;
1003 pixman_region32_t unocc;
1004
1005 pixman_region32_init(&unocc);
1006 pixman_region32_subtract(&unocc, &view->transform.boundingbox,
1007 &view->clip);
1008 ret = !pixman_region32_not_empty(&unocc);
1009 pixman_region32_fini(&unocc);
1010
1011 return ret;
1012}
1013
1014static void
1015rpir_view_update(struct rpir_view *view, struct rpir_output *output,
1016 DISPMANX_UPDATE_HANDLE_T update, int layer)
1017{
1018 int ret;
1019 int obscured;
1020
Jason Ekstranda7af7042013-10-12 22:38:11 -05001021 obscured = is_view_not_visible(view->view);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001022 if (obscured) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05001023 DBG("rpir_view %p totally obscured.\n", view);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001024
Jason Ekstranda7af7042013-10-12 22:38:11 -05001025 wl_list_remove(&view->link);
1026 if (view->handle == DISPMANX_NO_HANDLE) {
1027 wl_list_init(&view->link);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001028 } else {
Jason Ekstranda7af7042013-10-12 22:38:11 -05001029 rpir_view_dmx_remove(view, update);
1030 wl_list_insert(&output->view_cleanup_list,
1031 &view->link);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001032 }
1033
1034 goto out;
1035 }
1036
Jason Ekstranda7af7042013-10-12 22:38:11 -05001037 if (view->handle == DISPMANX_NO_HANDLE) {
1038 ret = rpir_view_dmx_add(view, output, update, layer);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001039 if (ret == 0) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05001040 wl_list_remove(&view->link);
1041 wl_list_init(&view->link);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001042 } else if (ret < 0) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05001043 weston_log("ERROR rpir_view_dmx_add() failed.\n");
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001044 }
1045 } else {
Jason Ekstranda7af7042013-10-12 22:38:11 -05001046 if (view->surface->need_swap)
1047 rpir_view_dmx_swap(view, update);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001048
Jason Ekstranda7af7042013-10-12 22:38:11 -05001049 ret = rpir_view_dmx_move(view, update, layer);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001050 if (ret == 0) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05001051 rpir_view_dmx_remove(view, update);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001052
Jason Ekstranda7af7042013-10-12 22:38:11 -05001053 wl_list_remove(&view->link);
1054 wl_list_insert(&output->view_cleanup_list,
1055 &view->link);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001056 } else if (ret < 0) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05001057 weston_log("ERROR rpir_view_dmx_move() failed.\n");
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001058 }
1059 }
1060
1061out:
Jason Ekstranda7af7042013-10-12 22:38:11 -05001062 view->layer = layer;
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001063}
1064
1065static int
1066rpi_renderer_read_pixels(struct weston_output *base,
1067 pixman_format_code_t format, void *pixels,
1068 uint32_t x, uint32_t y,
1069 uint32_t width, uint32_t height)
1070{
1071 struct rpir_output *output = to_rpir_output(base);
1072 struct rpi_resource *buffer = &output->capture_buffer;
1073 VC_RECT_T rect;
1074 uint32_t fb_width, fb_height;
1075 uint32_t dst_pitch;
1076 uint32_t i;
1077 int ret;
1078
Hardeningff39efa2013-09-18 23:56:35 +02001079 fb_width = base->current_mode->width;
1080 fb_height = base->current_mode->height;
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001081
1082 DBG("%s(%u, %u, %u, %u), resource %p\n", __func__,
1083 x, y, width, height, buffer);
1084
1085 if (format != PIXMAN_a8r8g8b8) {
1086 weston_log("rpi-renderer error: bad read_format\n");
1087 return -1;
1088 }
1089
1090 dst_pitch = fb_width * 4;
1091
1092 if (buffer->handle == DISPMANX_NO_HANDLE) {
1093 free(output->capture_data);
1094 output->capture_data = NULL;
1095
1096 ret = rpi_resource_realloc(buffer, VC_IMAGE_ARGB8888,
1097 fb_width, fb_height,
1098 dst_pitch, fb_height);
1099 if (ret < 0) {
1100 weston_log("rpi-renderer error: "
1101 "allocating read buffer failed\n");
1102 return -1;
1103 }
1104
1105 ret = vc_dispmanx_snapshot(output->display, buffer->handle,
1106 VC_IMAGE_ROT0);
1107 if (ret) {
1108 weston_log("rpi-renderer error: "
1109 "vc_dispmanx_snapshot returned %d\n", ret);
1110 return -1;
1111 }
1112 DBG("%s: snapshot done.\n", __func__);
1113 }
1114
1115 /*
1116 * If vc_dispmanx_resource_read_data was able to read sub-rectangles,
1117 * we could read directly into 'pixels'. But it cannot, it does not
1118 * use rect.x or rect.width, and does this:
1119 * host_start = (uint8_t *)dst_address + (dst_pitch * p_rect->y);
1120 * In other words, it is only good for reading the full buffer in
1121 * one go.
1122 */
1123 vc_dispmanx_rect_set(&rect, 0, 0, fb_width, fb_height);
1124
1125 if (x == 0 && y == 0 && width == fb_width && height == fb_height) {
1126 ret = vc_dispmanx_resource_read_data(buffer->handle, &rect,
1127 pixels, dst_pitch);
1128 if (ret) {
1129 weston_log("rpi-renderer error: "
1130 "resource_read_data returned %d\n", ret);
1131 return -1;
1132 }
1133 DBG("%s: full frame done.\n", __func__);
1134 return 0;
1135 }
1136
1137 if (!output->capture_data) {
1138 output->capture_data = malloc(fb_height * dst_pitch);
1139 if (!output->capture_data) {
1140 weston_log("rpi-renderer error: "
1141 "out of memory\n");
1142 return -1;
1143 }
1144
1145 ret = vc_dispmanx_resource_read_data(buffer->handle, &rect,
1146 output->capture_data,
1147 dst_pitch);
1148 if (ret) {
1149 weston_log("rpi-renderer error: "
1150 "resource_read_data returned %d\n", ret);
1151 return -1;
1152 }
1153 }
1154
1155 for (i = 0; i < height; i++) {
1156 uint8_t *src = output->capture_data +
1157 (y + i) * dst_pitch + x * 4;
1158 uint8_t *dst = (uint8_t *)pixels + i * width * 4;
1159 memcpy(dst, src, width * 4);
1160 }
1161
1162 return 0;
1163}
1164
1165static void
1166rpir_output_dmx_remove_all(struct rpir_output *output,
1167 DISPMANX_UPDATE_HANDLE_T update)
1168{
Jason Ekstranda7af7042013-10-12 22:38:11 -05001169 struct rpir_view *view;
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001170
Jason Ekstranda7af7042013-10-12 22:38:11 -05001171 while (!wl_list_empty(&output->view_list)) {
1172 view = container_of(output->view_list.next,
1173 struct rpir_view, link);
1174 rpir_view_dmx_remove(view, update);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001175
Jason Ekstranda7af7042013-10-12 22:38:11 -05001176 wl_list_remove(&view->link);
1177 wl_list_insert(&output->view_cleanup_list, &view->link);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001178 }
1179}
1180
1181static void
1182output_compute_matrix(struct weston_output *base)
1183{
1184 struct rpir_output *output = to_rpir_output(base);
1185 struct weston_matrix *matrix = &output->matrix;
1186 const float half_w = 0.5f * base->width;
1187 const float half_h = 0.5f * base->height;
1188 float mag;
1189 float dx, dy;
1190
1191 weston_matrix_init(matrix);
1192 weston_matrix_translate(matrix, -base->x, -base->y, 0.0f);
1193
1194#ifdef SURFACE_TRANSFORM
1195 weston_matrix_translate(matrix, -half_w, -half_h, 0.0f);
1196 switch (base->transform) {
1197 case WL_OUTPUT_TRANSFORM_FLIPPED:
1198 weston_matrix_scale(matrix, -1.0f, 1.0f, 1.0f);
1199 case WL_OUTPUT_TRANSFORM_NORMAL:
1200 /* weston_matrix_rotate_xy(matrix, 1.0f, 0.0f); no-op */
1201 weston_matrix_translate(matrix, half_w, half_h, 0.0f);
1202 break;
1203
1204 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
1205 weston_matrix_scale(matrix, -1.0f, 1.0f, 1.0f);
1206 case WL_OUTPUT_TRANSFORM_90:
1207 weston_matrix_rotate_xy(matrix, 0.0f, 1.0f);
1208 weston_matrix_translate(matrix, half_h, half_w, 0.0f);
1209 break;
1210
1211 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
1212 weston_matrix_scale(matrix, -1.0f, 1.0f, 1.0f);
1213 case WL_OUTPUT_TRANSFORM_180:
1214 weston_matrix_rotate_xy(matrix, -1.0f, 0.0f);
1215 weston_matrix_translate(matrix, half_w, half_h, 0.0f);
1216 break;
1217
1218 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
1219 weston_matrix_scale(matrix, -1.0f, 1.0f, 1.0f);
1220 case WL_OUTPUT_TRANSFORM_270:
1221 weston_matrix_rotate_xy(matrix, 0.0f, -1.0f);
1222 weston_matrix_translate(matrix, half_h, half_w, 0.0f);
1223 break;
1224
1225 default:
1226 break;
1227 }
1228#endif
1229
1230 if (base->zoom.active) {
1231 /* The base->zoom stuff is in GL coordinate system */
1232 mag = 1.0f / (1.0f - base->zoom.spring_z.current);
1233 dx = -(base->zoom.trans_x + 1.0f) * half_w;
1234 dy = -(base->zoom.trans_y + 1.0f) * half_h;
1235 weston_matrix_translate(matrix, dx, dy, 0.0f);
1236 weston_matrix_scale(matrix, mag, mag, 1.0f);
1237 weston_matrix_translate(matrix, half_w, half_h, 0.0f);
1238 }
1239}
1240
1241/* Note: this won't work right for multiple outputs. A DispmanX Element
1242 * is tied to one DispmanX Display, i.e. output.
1243 */
1244static void
1245rpi_renderer_repaint_output(struct weston_output *base,
1246 pixman_region32_t *output_damage)
1247{
1248 struct weston_compositor *compositor = base->compositor;
1249 struct rpir_output *output = to_rpir_output(base);
Jason Ekstranda7af7042013-10-12 22:38:11 -05001250 struct weston_view *wv;
1251 struct rpir_view *view;
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001252 struct wl_list done_list;
1253 int layer = 1;
1254
1255 assert(output->update != DISPMANX_NO_HANDLE);
1256
1257 output_compute_matrix(base);
1258
1259 rpi_resource_release(&output->capture_buffer);
1260 free(output->capture_data);
1261 output->capture_data = NULL;
1262
Jason Ekstranda7af7042013-10-12 22:38:11 -05001263 /* Swap resources on surfaces as needed */
1264 wl_list_for_each_reverse(wv, &compositor->view_list, link)
1265 wv->surface->touched = 0;
1266
1267 wl_list_for_each_reverse(wv, &compositor->view_list, link) {
1268 view = to_rpir_view(wv);
1269
1270 if (!wv->surface->touched) {
1271 wv->surface->touched = 1;
1272
Tomeu Vizoso44247742013-10-24 15:38:32 +02001273 if (view->surface->buffer_type == BUFFER_TYPE_EGL ||
1274 view->surface->need_swap)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001275 rpir_surface_swap_pointers(view->surface);
1276 }
1277
Tomeu Vizoso74987582013-10-25 10:34:38 +02001278 if (view->surface->buffer_type == BUFFER_TYPE_EGL) {
1279 struct weston_buffer *buffer;
1280 buffer = view->surface->egl_front->buffer_ref.buffer;
1281 if (buffer != NULL) {
1282 vc_dispmanx_set_wl_buffer_in_use(buffer->resource, 1);
Jason Ekstranda7af7042013-10-12 22:38:11 -05001283 } else {
Tomeu Vizoso74987582013-10-25 10:34:38 +02001284 weston_log("warning: client destroyed current front buffer\n");
1285
1286 wl_list_remove(&view->link);
1287 if (view->handle == DISPMANX_NO_HANDLE) {
1288 wl_list_init(&view->link);
1289 } else {
1290 rpir_view_dmx_remove(view, output->update);
1291 wl_list_insert(&output->view_cleanup_list,
1292 &view->link);
1293 }
Jason Ekstranda7af7042013-10-12 22:38:11 -05001294 }
1295 }
1296 }
1297
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001298 /* update all renderable surfaces */
1299 wl_list_init(&done_list);
Jason Ekstranda7af7042013-10-12 22:38:11 -05001300 wl_list_for_each_reverse(wv, &compositor->view_list, link) {
1301 if (wv->plane != &compositor->primary_plane)
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001302 continue;
1303
Jason Ekstranda7af7042013-10-12 22:38:11 -05001304 view = to_rpir_view(wv);
1305 assert(!wl_list_empty(&view->link) ||
1306 view->handle == DISPMANX_NO_HANDLE);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001307
Jason Ekstranda7af7042013-10-12 22:38:11 -05001308 wl_list_remove(&view->link);
1309 wl_list_insert(&done_list, &view->link);
1310 rpir_view_update(view, output, output->update, layer++);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001311 }
1312
Jason Ekstranda7af7042013-10-12 22:38:11 -05001313 /* Mark all surfaces as swapped */
1314 wl_list_for_each_reverse(wv, &compositor->view_list, link)
1315 to_rpir_surface(wv->surface)->need_swap = 0;
1316
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001317 /* Remove all surfaces that are still on screen, but were
1318 * not rendered this time.
1319 */
1320 rpir_output_dmx_remove_all(output, output->update);
1321
Jason Ekstranda7af7042013-10-12 22:38:11 -05001322 wl_list_insert_list(&output->view_list, &done_list);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001323 output->update = DISPMANX_NO_HANDLE;
1324
1325 /* The frame_signal is emitted in rpi_renderer_finish_frame(),
1326 * so that the firmware can capture the up-to-date contents.
1327 */
1328}
1329
1330static void
1331rpi_renderer_flush_damage(struct weston_surface *base)
1332{
1333 /* Called for every surface just before repainting it, if
1334 * having an shm buffer.
1335 */
1336 struct rpir_surface *surface = to_rpir_surface(base);
Jason Ekstrand6bd62942013-06-20 20:38:23 -05001337 struct weston_buffer *buffer = surface->buffer_ref.buffer;
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001338 int ret;
1339
1340 assert(buffer);
Jason Ekstrand6bd62942013-06-20 20:38:23 -05001341 assert(wl_shm_buffer_get(buffer->resource));
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001342
1343 ret = rpir_surface_damage(surface, buffer, &base->damage);
1344 if (ret)
1345 weston_log("%s error: updating Dispmanx resource failed.\n",
1346 __func__);
1347
1348 weston_buffer_reference(&surface->buffer_ref, NULL);
1349}
1350
1351static void
Jason Ekstrand6bd62942013-06-20 20:38:23 -05001352rpi_renderer_attach(struct weston_surface *base, struct weston_buffer *buffer)
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001353{
1354 /* Called every time a client commits an attach. */
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001355 struct rpir_surface *surface = to_rpir_surface(base);
1356
1357 assert(surface);
1358 if (!surface)
1359 return;
1360
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001361 if (surface->buffer_type == BUFFER_TYPE_SHM) {
1362 if (!surface->single_buffer)
1363 /* XXX: need to check if in middle of update */
1364 rpi_resource_release(surface->back);
1365
Jason Ekstranda7af7042013-10-12 22:38:11 -05001366 if (!surface->visible_views)
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001367 /* XXX: cannot do this, if middle of an update */
1368 rpi_resource_release(surface->front);
1369
1370 weston_buffer_reference(&surface->buffer_ref, NULL);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001371 }
1372
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001373 /* If buffer is NULL, Weston core unmaps the surface, the surface
1374 * will not appear in repaint list, and so rpi_renderer_repaint_output
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001375 * will remove the DispmanX element. Later, for SHM, also the front
1376 * buffer will be released in the cleanup_list processing.
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001377 */
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001378 if (!buffer)
1379 return;
1380
1381 if (wl_shm_buffer_get(buffer->resource)) {
1382 surface->buffer_type = BUFFER_TYPE_SHM;
1383 buffer->shm_buffer = wl_shm_buffer_get(buffer->resource);
1384 buffer->width = wl_shm_buffer_get_width(buffer->shm_buffer);
1385 buffer->height = wl_shm_buffer_get_height(buffer->shm_buffer);
1386
1387 weston_buffer_reference(&surface->buffer_ref, buffer);
1388 } else {
1389#if ENABLE_EGL
1390 struct rpi_renderer *renderer = to_rpi_renderer(base->compositor);
Tomeu Vizosoa8e5f292013-10-09 11:29:45 +02001391 struct wl_resource *wl_resource = buffer->resource;
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001392
1393 if (!renderer->has_bind_display ||
1394 !renderer->query_buffer(renderer->egl_display,
1395 wl_resource,
1396 EGL_WIDTH, &buffer->width)) {
1397 weston_log("unhandled buffer type!\n");
1398 weston_buffer_reference(&surface->buffer_ref, NULL);
1399 surface->buffer_type = BUFFER_TYPE_NULL;
1400 }
1401
1402 renderer->query_buffer(renderer->egl_display,
1403 wl_resource,
1404 EGL_HEIGHT, &buffer->height);
1405
1406 surface->buffer_type = BUFFER_TYPE_EGL;
1407
1408 if(surface->egl_back == NULL)
1409 surface->egl_back = calloc(1, sizeof *surface->egl_back);
1410
1411 weston_buffer_reference(&surface->egl_back->buffer_ref, buffer);
1412 surface->egl_back->resource_handle =
1413 vc_dispmanx_get_handle_from_wl_buffer(wl_resource);
1414#else
1415 weston_log("unhandled buffer type!\n");
1416 weston_buffer_reference(&surface->buffer_ref, NULL);
1417 surface->buffer_type = BUFFER_TYPE_NULL;
1418#endif
1419 }
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001420}
1421
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +03001422static void
1423rpir_surface_handle_surface_destroy(struct wl_listener *listener, void *data)
1424{
1425 struct rpir_surface *surface;
1426 struct weston_surface *base = data;
1427
1428 surface = container_of(listener, struct rpir_surface,
1429 surface_destroy_listener);
1430
1431 assert(surface);
1432 assert(surface->surface == base);
1433 if (!surface)
1434 return;
1435
1436 surface->surface = NULL;
1437 base->renderer_state = NULL;
1438
1439 if (wl_list_empty(&surface->views))
1440 rpir_surface_destroy(surface);
1441}
1442
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001443static int
1444rpi_renderer_create_surface(struct weston_surface *base)
1445{
1446 struct rpi_renderer *renderer = to_rpi_renderer(base->compositor);
1447 struct rpir_surface *surface;
1448
1449 assert(base->renderer_state == NULL);
1450
1451 surface = rpir_surface_create(renderer);
1452 if (!surface)
1453 return -1;
1454
1455 surface->surface = base;
1456 base->renderer_state = surface;
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +03001457
1458 surface->surface_destroy_listener.notify =
1459 rpir_surface_handle_surface_destroy;
1460 wl_signal_add(&base->destroy_signal,
1461 &surface->surface_destroy_listener);
1462
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001463 return 0;
1464}
1465
Jason Ekstranda7af7042013-10-12 22:38:11 -05001466static int
1467rpi_renderer_create_view(struct weston_view *base)
1468{
1469 struct rpir_surface *surface = to_rpir_surface(base->surface);
1470 struct rpir_view *view;
1471
1472 assert(base->renderer_state == NULL);
1473
1474 view = rpir_view_create(surface);
1475 if (!view)
1476 return -1;
1477
1478 view->view = base;
1479 base->renderer_state = view;
1480 return 0;
1481}
1482
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001483static void
1484rpi_renderer_surface_set_color(struct weston_surface *base,
1485 float red, float green, float blue, float alpha)
1486{
1487 struct rpir_surface *surface = to_rpir_surface(base);
1488 uint8_t color[4];
1489 VC_RECT_T rect;
1490 int ret;
1491
1492 assert(surface);
1493
1494 ret = rpi_resource_realloc(surface->back, VC_IMAGE_ARGB8888,
1495 1, 1, 4, 1);
1496 if (ret < 0) {
1497 weston_log("Error: %s: rpi_resource_realloc failed.\n",
1498 __func__);
1499 return;
1500 }
1501
1502 color[0] = float2uint8(blue);
1503 color[1] = float2uint8(green);
1504 color[2] = float2uint8(red);
1505 color[3] = float2uint8(alpha);
1506
1507 vc_dispmanx_rect_set(&rect, 0, 0, 1, 1);
1508 ret = vc_dispmanx_resource_write_data(surface->back->handle,
1509 VC_IMAGE_ARGB8888,
1510 4, color, &rect);
1511 if (ret) {
1512 weston_log("Error: %s: resource_write_data failed.\n",
1513 __func__);
1514 return;
1515 }
1516
1517 DBG("%s: resource %p solid color BGRA %u,%u,%u,%u\n", __func__,
1518 surface->back, color[0], color[1], color[2], color[3]);
1519
1520 /*pixman_region32_copy(&surface->prev_damage, damage);*/
1521 surface->need_swap = 1;
1522}
1523
1524static void
Jason Ekstranda7af7042013-10-12 22:38:11 -05001525rpi_renderer_destroy_view(struct weston_view *base)
1526{
1527 struct rpir_view *view = to_rpir_view(base);
1528
1529 assert(view);
1530 assert(view->view == base);
1531 if (!view)
1532 return;
1533
Tomeu Vizoso34dad7d2013-10-25 10:34:37 +02001534 view->view = NULL;
1535
Jason Ekstranda7af7042013-10-12 22:38:11 -05001536 /* If guaranteed to not be on screen, just detroy it. */
1537 if (wl_list_empty(&view->link))
1538 rpir_view_destroy(view);
1539
1540 /* Otherwise, the view is either on screen and needs
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001541 * to be removed by a repaint update, or it is in the
Jason Ekstranda7af7042013-10-12 22:38:11 -05001542 * view_cleanup_list, and will be destroyed by
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001543 * rpi_renderer_finish_frame().
1544 */
1545}
1546
1547static void
1548rpi_renderer_destroy(struct weston_compositor *compositor)
1549{
1550 struct rpi_renderer *renderer = to_rpi_renderer(compositor);
1551
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001552#if ENABLE_EGL
1553 if (renderer->has_bind_display)
1554 renderer->unbind_display(renderer->egl_display,
1555 compositor->wl_display);
1556#endif
1557
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001558 free(renderer);
1559 compositor->renderer = NULL;
1560}
1561
1562WL_EXPORT int
1563rpi_renderer_create(struct weston_compositor *compositor,
1564 const struct rpi_renderer_parameters *params)
1565{
1566 struct rpi_renderer *renderer;
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001567#if ENABLE_EGL
1568 const char *extensions;
1569 EGLBoolean ret;
1570 EGLint major, minor;
1571#endif
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001572
1573 weston_log("Initializing the DispmanX compositing renderer\n");
1574
1575 renderer = calloc(1, sizeof *renderer);
1576 if (renderer == NULL)
1577 return -1;
1578
1579 renderer->single_buffer = params->single_buffer;
1580
1581 renderer->base.read_pixels = rpi_renderer_read_pixels;
1582 renderer->base.repaint_output = rpi_renderer_repaint_output;
1583 renderer->base.flush_damage = rpi_renderer_flush_damage;
1584 renderer->base.attach = rpi_renderer_attach;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001585 renderer->base.create_view = rpi_renderer_create_view;
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001586 renderer->base.surface_set_color = rpi_renderer_surface_set_color;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001587 renderer->base.destroy_view = rpi_renderer_destroy_view;
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001588 renderer->base.destroy = rpi_renderer_destroy;
1589
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001590#ifdef ENABLE_EGL
1591 renderer->egl_display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
1592 if (renderer->egl_display == EGL_NO_DISPLAY) {
1593 weston_log("failed to create EGL display\n");
1594 return -1;
1595 }
1596
1597 if (!eglInitialize(renderer->egl_display, &major, &minor)) {
1598 weston_log("failed to initialize EGL display\n");
1599 return -1;
1600 }
1601
1602 renderer->bind_display =
1603 (void *) eglGetProcAddress("eglBindWaylandDisplayWL");
1604 renderer->unbind_display =
1605 (void *) eglGetProcAddress("eglUnbindWaylandDisplayWL");
1606 renderer->query_buffer =
1607 (void *) eglGetProcAddress("eglQueryWaylandBufferWL");
1608
1609 extensions = (const char *) eglQueryString(renderer->egl_display,
1610 EGL_EXTENSIONS);
1611 if (!extensions) {
1612 weston_log("Retrieving EGL extension string failed.\n");
1613 return -1;
1614 }
1615
1616 if (strstr(extensions, "EGL_WL_bind_wayland_display"))
1617 renderer->has_bind_display = 1;
1618
1619 if (renderer->has_bind_display) {
1620 ret = renderer->bind_display(renderer->egl_display,
1621 compositor->wl_display);
1622 if (!ret)
1623 renderer->has_bind_display = 0;
1624 }
1625#endif
1626
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001627 compositor->renderer = &renderer->base;
1628 compositor->read_format = PIXMAN_a8r8g8b8;
1629 /* WESTON_CAP_ROTATION_ANY not supported */
1630
Tomeu Vizoso03681892013-08-06 20:05:57 +02001631 wl_display_add_shm_format(compositor->wl_display, WL_SHM_FORMAT_RGB565);
1632
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001633 return 0;
1634}
1635
1636WL_EXPORT int
1637rpi_renderer_output_create(struct weston_output *base,
1638 DISPMANX_DISPLAY_HANDLE_T display)
1639{
1640 struct rpir_output *output;
1641
1642 assert(base->renderer_state == NULL);
1643
1644 output = calloc(1, sizeof *output);
1645 if (!output)
1646 return -1;
1647
1648 output->display = display;
1649 output->update = DISPMANX_NO_HANDLE;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001650 wl_list_init(&output->view_list);
1651 wl_list_init(&output->view_cleanup_list);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001652 rpi_resource_init(&output->capture_buffer);
1653 base->renderer_state = output;
1654
1655 return 0;
1656}
1657
1658WL_EXPORT void
1659rpi_renderer_output_destroy(struct weston_output *base)
1660{
1661 struct rpir_output *output = to_rpir_output(base);
Jason Ekstranda7af7042013-10-12 22:38:11 -05001662 struct rpir_view *view;
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001663 DISPMANX_UPDATE_HANDLE_T update;
1664
1665 rpi_resource_release(&output->capture_buffer);
1666 free(output->capture_data);
1667 output->capture_data = NULL;
1668
1669 update = vc_dispmanx_update_start(0);
1670 rpir_output_dmx_remove_all(output, update);
1671 vc_dispmanx_update_submit_sync(update);
1672
Jason Ekstranda7af7042013-10-12 22:38:11 -05001673 while (!wl_list_empty(&output->view_cleanup_list)) {
1674 view = container_of(output->view_cleanup_list.next,
1675 struct rpir_view, link);
1676 rpir_view_destroy(view);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001677 }
1678
1679 free(output);
1680 base->renderer_state = NULL;
1681}
1682
1683WL_EXPORT void
1684rpi_renderer_set_update_handle(struct weston_output *base,
1685 DISPMANX_UPDATE_HANDLE_T handle)
1686{
1687 struct rpir_output *output = to_rpir_output(base);
1688
1689 output->update = handle;
1690}
1691
1692WL_EXPORT void
1693rpi_renderer_finish_frame(struct weston_output *base)
1694{
1695 struct rpir_output *output = to_rpir_output(base);
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001696 struct weston_compositor *compositor = base->compositor;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001697 struct weston_view *wv;
1698 struct rpir_view *view;
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001699
Jason Ekstranda7af7042013-10-12 22:38:11 -05001700 while (!wl_list_empty(&output->view_cleanup_list)) {
1701 view = container_of(output->view_cleanup_list.next,
1702 struct rpir_view, link);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001703
Jason Ekstranda7af7042013-10-12 22:38:11 -05001704 if (view->view) {
1705 /* The weston_view still exists, but is
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001706 * temporarily not visible, and hence its Element
1707 * was removed. The current front buffer contents
1708 * must be preserved.
1709 */
Jason Ekstranda7af7042013-10-12 22:38:11 -05001710 if (!view->surface->visible_views)
1711 rpi_resource_release(view->surface->back);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001712
Jason Ekstranda7af7042013-10-12 22:38:11 -05001713 wl_list_remove(&view->link);
1714 wl_list_init(&view->link);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001715 } else {
Jason Ekstranda7af7042013-10-12 22:38:11 -05001716 rpir_view_destroy(view);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001717 }
1718 }
1719
Jason Ekstranda7af7042013-10-12 22:38:11 -05001720 wl_list_for_each(wv, &compositor->view_list, link) {
1721 view = to_rpir_view(wv);
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001722
Jason Ekstranda7af7042013-10-12 22:38:11 -05001723 if (view->surface->buffer_type != BUFFER_TYPE_EGL)
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001724 continue;
1725
Tomeu Vizoso74987582013-10-25 10:34:38 +02001726 rpir_egl_buffer_destroy(view->surface->egl_old_front);
Jason Ekstranda7af7042013-10-12 22:38:11 -05001727 view->surface->egl_old_front = NULL;
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001728 }
1729
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001730 wl_signal_emit(&base->frame_signal, base);
1731}