blob: 33eb67cc2daeaef8ac0bce169f5121f16b591528 [file] [log] [blame]
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001/*
2 * Copyright © 2012-2013 Raspberry Pi Foundation
3 *
Bryce Harringtona0bbfea2015-06-11 15:35:43 -07004 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files (the
6 * "Software"), to deal in the Software without restriction, including
7 * without limitation the rights to use, copy, modify, merge, publish,
8 * distribute, sublicense, and/or sell copies of the Software, and to
9 * permit persons to whom the Software is furnished to do so, subject to
10 * the following conditions:
Pekka Paalanend7265bc2013-05-22 18:03:06 +030011 *
Bryce Harringtona0bbfea2015-06-11 15:35:43 -070012 * The above copyright notice and this permission notice (including the
13 * next paragraph) shall be included in all copies or substantial
14 * portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
20 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 * SOFTWARE.
Pekka Paalanend7265bc2013-05-22 18:03:06 +030024 */
25
Daniel Stonec228e232013-05-22 18:03:19 +030026#include "config.h"
27
Pekka Paalanend7265bc2013-05-22 18:03:06 +030028#include <stdlib.h>
29#include <assert.h>
30#include <string.h>
31
Pekka Paalanend7265bc2013-05-22 18:03:06 +030032#ifdef HAVE_BCM_HOST
33# include <bcm_host.h>
34#else
35# include "rpi-bcm-stubs.h"
36#endif
37
38#include "compositor.h"
39#include "rpi-renderer.h"
Jon Cruz867d50e2015-06-15 15:37:10 -070040#include "shared/helpers.h"
Pekka Paalanend7265bc2013-05-22 18:03:06 +030041
Tomeu Vizosob4659eb2013-10-07 11:02:20 +020042#ifdef ENABLE_EGL
43#include <EGL/egl.h>
44#include <EGL/eglext.h>
45#include "weston-egl-ext.h"
46#endif
47
Pekka Paalanend7265bc2013-05-22 18:03:06 +030048/*
49 * Dispmanx API offers alpha-blended overlays for hardware compositing.
50 * The final composite consists of dispmanx elements, and their contents:
51 * the dispmanx resource assigned to the element. The elements may be
52 * scanned out directly, or composited to a temporary surface, depending on
53 * how the firmware decides to handle the scene. Updates to multiple elements
54 * may be queued in a single dispmanx update object, resulting in atomic and
55 * vblank synchronized display updates.
56 *
57 * To avoid tearing and display artifacts, the current dispmanx resource in a
58 * dispmanx element must not be touched. Therefore each element must be
59 * double-buffered, using two resources, the front and the back. While a
60 * dispmanx update is running, the both resources must be considered in use.
61 *
62 * A resource may be destroyed only, when the update removing the element has
63 * completed. Otherwise you risk showing an incomplete composition.
64 */
65
66#ifndef ELEMENT_CHANGE_LAYER
67/* copied from interface/vmcs_host/vc_vchi_dispmanx.h of userland.git */
68#define ELEMENT_CHANGE_LAYER (1<<0)
69#define ELEMENT_CHANGE_OPACITY (1<<1)
70#define ELEMENT_CHANGE_DEST_RECT (1<<2)
71#define ELEMENT_CHANGE_SRC_RECT (1<<3)
72#define ELEMENT_CHANGE_MASK_RESOURCE (1<<4)
73#define ELEMENT_CHANGE_TRANSFORM (1<<5)
74#endif
75
76#if 0
77#define DBG(...) \
78 weston_log(__VA_ARGS__)
79#else
80#define DBG(...) do {} while (0)
81#endif
82
83/* If we had a fully featured vc_dispmanx_resource_write_data()... */
84/*#define HAVE_RESOURCE_WRITE_DATA_RECT 1*/
85
Tomeu Vizosoe4f7b922013-12-02 17:18:58 +010086/* If we had a vc_dispmanx_element_set_opaque_rect()... */
87/*#define HAVE_ELEMENT_SET_OPAQUE_RECT 1*/
88
Pekka Paalanend7265bc2013-05-22 18:03:06 +030089struct rpi_resource {
90 DISPMANX_RESOURCE_HANDLE_T handle;
91 int width;
92 int height; /* height of the image (valid pixel data) */
93 int stride; /* bytes */
94 int buffer_height; /* height of the buffer */
Tomeu Vizosoe4f7b922013-12-02 17:18:58 +010095 int enable_opaque_regions;
Pekka Paalanend7265bc2013-05-22 18:03:06 +030096 VC_IMAGE_TYPE_T ifmt;
97};
98
99struct rpir_output;
100
Tomeu Vizosob4659eb2013-10-07 11:02:20 +0200101struct rpir_egl_buffer {
102 struct weston_buffer_reference buffer_ref;
103 DISPMANX_RESOURCE_HANDLE_T resource_handle;
104};
105
106enum buffer_type {
107 BUFFER_TYPE_NULL,
108 BUFFER_TYPE_SHM,
109 BUFFER_TYPE_EGL
110};
111
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300112struct rpir_surface {
113 struct weston_surface *surface;
114
Jason Ekstranda7af7042013-10-12 22:38:11 -0500115 struct wl_list views;
116 int visible_views;
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300117 int need_swap;
118 int single_buffer;
Tomeu Vizosoe4f7b922013-12-02 17:18:58 +0100119 int enable_opaque_regions;
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300120
121 struct rpi_resource resources[2];
122 struct rpi_resource *front;
123 struct rpi_resource *back;
124 pixman_region32_t prev_damage;
125
Tomeu Vizosob4659eb2013-10-07 11:02:20 +0200126 struct rpir_egl_buffer *egl_front;
127 struct rpir_egl_buffer *egl_back;
128 struct rpir_egl_buffer *egl_old_front;
129
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300130 struct weston_buffer_reference buffer_ref;
Tomeu Vizosob4659eb2013-10-07 11:02:20 +0200131 enum buffer_type buffer_type;
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300132
133 struct wl_listener surface_destroy_listener;
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300134};
135
Jason Ekstranda7af7042013-10-12 22:38:11 -0500136struct rpir_view {
137 struct rpir_surface *surface;
138 struct wl_list surface_link;
139 struct weston_view *view;
140
141 /* If link is empty, the view is guaranteed to not be on screen,
142 * i.e. updates removing Elements have completed.
143 */
144 struct wl_list link;
145
146 DISPMANX_ELEMENT_HANDLE_T handle;
147 int layer;
Tomeu Vizoso96dc9e42013-10-28 10:17:45 +0100148
149 struct wl_listener view_destroy_listener;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500150};
151
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300152struct rpir_output {
153 DISPMANX_DISPLAY_HANDLE_T display;
154
155 DISPMANX_UPDATE_HANDLE_T update;
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300156
157 /* all Elements currently on screen */
Jason Ekstranda7af7042013-10-12 22:38:11 -0500158 struct wl_list view_list; /* struct rpir_surface::link */
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300159
160 /* Elements just removed, waiting for update completion */
Jason Ekstranda7af7042013-10-12 22:38:11 -0500161 struct wl_list view_cleanup_list; /* struct rpir_surface::link */
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300162
163 struct rpi_resource capture_buffer;
164 uint8_t *capture_data;
165};
166
167struct rpi_renderer {
168 struct weston_renderer base;
169
170 int single_buffer;
Tomeu Vizosoe4f7b922013-12-02 17:18:58 +0100171 int enable_opaque_regions;
Tomeu Vizosob4659eb2013-10-07 11:02:20 +0200172
173#ifdef ENABLE_EGL
174 EGLDisplay egl_display;
175
176 PFNEGLBINDWAYLANDDISPLAYWL bind_display;
177 PFNEGLUNBINDWAYLANDDISPLAYWL unbind_display;
178 PFNEGLQUERYWAYLANDBUFFERWL query_buffer;
179#endif
180 int has_bind_display;
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300181};
182
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300183static int
184rpi_renderer_create_surface(struct weston_surface *base);
185
Tomeu Vizoso96dc9e42013-10-28 10:17:45 +0100186static int
187rpi_renderer_create_view(struct weston_view *base);
188
189static void
190rpir_view_handle_view_destroy(struct wl_listener *listener, void *data);
191
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300192static inline struct rpir_surface *
193to_rpir_surface(struct weston_surface *surface)
194{
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300195 if (!surface->renderer_state)
196 rpi_renderer_create_surface(surface);
197
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300198 return surface->renderer_state;
199}
200
Jason Ekstranda7af7042013-10-12 22:38:11 -0500201static inline struct rpir_view *
202to_rpir_view(struct weston_view *view)
203{
Tomeu Vizoso96dc9e42013-10-28 10:17:45 +0100204 if (!view->renderer_state)
205 rpi_renderer_create_view(view);
206
Jason Ekstranda7af7042013-10-12 22:38:11 -0500207 return view->renderer_state;
208}
209
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300210static inline struct rpir_output *
211to_rpir_output(struct weston_output *output)
212{
213 return output->renderer_state;
214}
215
216static inline struct rpi_renderer *
217to_rpi_renderer(struct weston_compositor *compositor)
218{
219 return container_of(compositor->renderer, struct rpi_renderer, base);
220}
221
222static inline int
223int_max(int a, int b)
224{
225 return a > b ? a : b;
226}
227
228static inline void
229int_swap(int *a, int *b)
230{
231 int tmp = *a;
232 *a = *b;
233 *b = tmp;
234}
235
236static uint8_t
237float2uint8(float f)
238{
239 int v = roundf(f * 255.0f);
240
241 return v < 0 ? 0 : (v > 255 ? 255 : v);
242}
243
244static void
245rpi_resource_init(struct rpi_resource *resource)
246{
247 resource->handle = DISPMANX_NO_HANDLE;
248}
249
250static void
251rpi_resource_release(struct rpi_resource *resource)
252{
253 if (resource->handle == DISPMANX_NO_HANDLE)
254 return;
255
256 vc_dispmanx_resource_delete(resource->handle);
257 DBG("resource %p release\n", resource);
258 resource->handle = DISPMANX_NO_HANDLE;
259}
260
261static int
262rpi_resource_realloc(struct rpi_resource *resource, VC_IMAGE_TYPE_T ifmt,
263 int width, int height, int stride, int buffer_height)
264{
265 uint32_t dummy;
266
267 if (resource->handle != DISPMANX_NO_HANDLE &&
268 resource->width == width &&
269 resource->height == height &&
270 resource->stride == stride &&
271 resource->buffer_height == buffer_height &&
272 resource->ifmt == ifmt)
273 return 0;
274
275 rpi_resource_release(resource);
276
277 /* NOTE: if stride is not a multiple of 16 pixels in bytes,
278 * the vc_image_* functions may break. Dispmanx elements
279 * should be fine, though. Buffer_height probably has similar
280 * constraints, too.
281 */
282 resource->handle =
283 vc_dispmanx_resource_create(ifmt,
284 width | (stride << 16),
285 height | (buffer_height << 16),
286 &dummy);
287 if (resource->handle == DISPMANX_NO_HANDLE)
288 return -1;
289
290 resource->width = width;
291 resource->height = height;
292 resource->stride = stride;
293 resource->buffer_height = buffer_height;
294 resource->ifmt = ifmt;
295 DBG("resource %p alloc\n", resource);
296 return 1;
297}
298
299/* A firmware workaround for broken ALPHA_PREMULT + ALPHA_MIX hardware. */
300#define PREMULT_ALPHA_FLAG (1 << 31)
301
302static VC_IMAGE_TYPE_T
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500303shm_buffer_get_vc_format(struct wl_shm_buffer *buffer)
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300304{
305 switch (wl_shm_buffer_get_format(buffer)) {
306 case WL_SHM_FORMAT_XRGB8888:
307 return VC_IMAGE_XRGB8888;
308 case WL_SHM_FORMAT_ARGB8888:
309 return VC_IMAGE_ARGB8888 | PREMULT_ALPHA_FLAG;
Tomeu Vizoso03681892013-08-06 20:05:57 +0200310 case WL_SHM_FORMAT_RGB565:
311 return VC_IMAGE_RGB565;
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300312 default:
313 /* invalid format */
314 return VC_IMAGE_MIN;
315 }
316}
317
Tomeu Vizosoe4f7b922013-12-02 17:18:58 +0100318#ifndef HAVE_ELEMENT_SET_OPAQUE_RECT
319static uint32_t *
320apply_opaque_region(struct wl_shm_buffer *buffer,
321 pixman_region32_t *opaque_region)
322{
323 uint32_t *src, *dst;
324 int width;
325 int height;
326 int stride;
327 int x, y;
328
329 width = wl_shm_buffer_get_width(buffer);
330 height = wl_shm_buffer_get_height(buffer);
331 stride = wl_shm_buffer_get_stride(buffer);
332 src = wl_shm_buffer_get_data(buffer);
333
334 dst = malloc(height * stride);
335 if (dst == NULL) {
336 weston_log("rpi-renderer error: out of memory\n");
337 return NULL;
338 }
339
340 for (y = 0; y < height; y++) {
341 for (x = 0; x < width; x++) {
342 int i = y * stride / 4 + x;
Derek Foremand5e21872014-11-21 12:31:04 -0600343 if (pixman_region32_contains_point (opaque_region, x, y, NULL)) {
Tomeu Vizosoe4f7b922013-12-02 17:18:58 +0100344 dst[i] = src[i] | 0xff000000;
345 } else {
346 dst[i] = src[i];
347 }
348 }
349 }
350
351 return dst;
352}
353#endif
354
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300355static int
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500356rpi_resource_update(struct rpi_resource *resource, struct weston_buffer *buffer,
Tomeu Vizosoe4f7b922013-12-02 17:18:58 +0100357 pixman_region32_t *region, pixman_region32_t *opaque_region)
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300358{
359 pixman_region32_t write_region;
360 pixman_box32_t *r;
361 VC_RECT_T rect;
362 VC_IMAGE_TYPE_T ifmt;
363 uint32_t *pixels;
364 int width;
365 int height;
366 int stride;
367 int ret;
U. Artie Eoff5e854bc2014-01-17 13:56:41 -0800368 int applied_opaque_region = 0;
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300369#ifdef HAVE_RESOURCE_WRITE_DATA_RECT
370 int n;
371#endif
372
373 if (!buffer)
374 return -1;
375
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500376 ifmt = shm_buffer_get_vc_format(buffer->shm_buffer);
377 width = wl_shm_buffer_get_width(buffer->shm_buffer);
378 height = wl_shm_buffer_get_height(buffer->shm_buffer);
379 stride = wl_shm_buffer_get_stride(buffer->shm_buffer);
380 pixels = wl_shm_buffer_get_data(buffer->shm_buffer);
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300381
Tomeu Vizosoe4f7b922013-12-02 17:18:58 +0100382#ifndef HAVE_ELEMENT_SET_OPAQUE_RECT
383 if (pixman_region32_not_empty(opaque_region) &&
384 wl_shm_buffer_get_format(buffer->shm_buffer) == WL_SHM_FORMAT_ARGB8888 &&
385 resource->enable_opaque_regions) {
386 pixels = apply_opaque_region(buffer->shm_buffer, opaque_region);
387
388 if (!pixels)
389 return -1;
U. Artie Eoff5e854bc2014-01-17 13:56:41 -0800390
391 applied_opaque_region = 1;
Tomeu Vizosoe4f7b922013-12-02 17:18:58 +0100392 }
393#endif
394
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300395 ret = rpi_resource_realloc(resource, ifmt & ~PREMULT_ALPHA_FLAG,
396 width, height, stride, height);
U. Artie Eoff5e854bc2014-01-17 13:56:41 -0800397 if (ret < 0) {
398 if (applied_opaque_region)
399 free(pixels);
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300400 return -1;
U. Artie Eoff5e854bc2014-01-17 13:56:41 -0800401 }
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300402
403 pixman_region32_init_rect(&write_region, 0, 0, width, height);
404 if (ret == 0)
405 pixman_region32_intersect(&write_region,
406 &write_region, region);
407
Neil Robertse5051712013-11-13 15:44:06 +0000408 wl_shm_buffer_begin_access(buffer->shm_buffer);
409
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300410#ifdef HAVE_RESOURCE_WRITE_DATA_RECT
411 /* XXX: Can this do a format conversion, so that scanout does not have to? */
412 r = pixman_region32_rectangles(&write_region, &n);
413 while (n--) {
414 vc_dispmanx_rect_set(&rect, r[n].x1, r[n].y1,
415 r[n].x2 - r[n].x1, r[n].y2 - r[n].y1);
416
417 ret = vc_dispmanx_resource_write_data_rect(resource->handle,
418 ifmt, stride,
419 pixels, &rect,
420 rect.x, rect.y);
421 DBG("%s: %p %ux%u@%u,%u, ret %d\n", __func__, resource,
422 rect.width, rect.height, rect.x, rect.y, ret);
423 if (ret)
424 break;
425 }
426#else
427 /* vc_dispmanx_resource_write_data() ignores ifmt,
428 * rect.x, rect.width, and uses stride only for computing
429 * the size of the transfer as rect.height * stride.
430 * Therefore we can only write rows starting at x=0.
431 * To be able to write more than one scanline at a time,
432 * the resource must have been created with the same stride
433 * as used here, and we must write full scanlines.
434 */
435
436 r = pixman_region32_extents(&write_region);
437 vc_dispmanx_rect_set(&rect, 0, r->y1, width, r->y2 - r->y1);
438 ret = vc_dispmanx_resource_write_data(resource->handle,
439 ifmt, stride, pixels, &rect);
440 DBG("%s: %p %ux%u@%u,%u, ret %d\n", __func__, resource,
441 width, r->y2 - r->y1, 0, r->y1, ret);
442#endif
443
Neil Robertse5051712013-11-13 15:44:06 +0000444 wl_shm_buffer_end_access(buffer->shm_buffer);
445
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300446 pixman_region32_fini(&write_region);
447
U. Artie Eoff5e854bc2014-01-17 13:56:41 -0800448 if (applied_opaque_region)
Tomeu Vizosoe4f7b922013-12-02 17:18:58 +0100449 free(pixels);
Tomeu Vizosoe4f7b922013-12-02 17:18:58 +0100450
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300451 return ret ? -1 : 0;
452}
453
Pekka Paalanend5fbfb22013-11-22 17:30:39 +0200454static inline void
455rpi_buffer_egl_lock(struct weston_buffer *buffer)
456{
457#ifdef ENABLE_EGL
458 vc_dispmanx_set_wl_buffer_in_use(buffer->resource, 1);
459#endif
460}
461
462static inline void
463rpi_buffer_egl_unlock(struct weston_buffer *buffer)
464{
465#ifdef ENABLE_EGL
466 vc_dispmanx_set_wl_buffer_in_use(buffer->resource, 0);
467#endif
468}
469
Tomeu Vizoso74987582013-10-25 10:34:38 +0200470static void
471rpir_egl_buffer_destroy(struct rpir_egl_buffer *egl_buffer)
472{
473 struct weston_buffer *buffer;
474
475 if (egl_buffer == NULL)
476 return;
477
478 buffer = egl_buffer->buffer_ref.buffer;
479 if (buffer == NULL) {
480 /* The client has already destroyed the wl_buffer, the
481 * compositor has the responsibility to delete the resource.
482 */
483 vc_dispmanx_resource_delete(egl_buffer->resource_handle);
484 } else {
Pekka Paalanend5fbfb22013-11-22 17:30:39 +0200485 rpi_buffer_egl_unlock(buffer);
Tomeu Vizoso74987582013-10-25 10:34:38 +0200486 weston_buffer_reference(&egl_buffer->buffer_ref, NULL);
487 }
488
489 free(egl_buffer);
490}
491
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300492static struct rpir_surface *
493rpir_surface_create(struct rpi_renderer *renderer)
494{
495 struct rpir_surface *surface;
496
Bryce Harringtonde16d892014-11-20 22:21:57 -0800497 surface = zalloc(sizeof *surface);
498 if (surface == NULL)
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300499 return NULL;
500
Tomeu Vizoso5c3ea3b2013-10-24 15:38:30 +0200501 wl_list_init(&surface->views);
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300502 surface->single_buffer = renderer->single_buffer;
Tomeu Vizosoe4f7b922013-12-02 17:18:58 +0100503 surface->enable_opaque_regions = renderer->enable_opaque_regions;
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300504 rpi_resource_init(&surface->resources[0]);
505 rpi_resource_init(&surface->resources[1]);
506 surface->front = &surface->resources[0];
507 if (surface->single_buffer)
508 surface->back = &surface->resources[0];
509 else
510 surface->back = &surface->resources[1];
Tomeu Vizosoe4f7b922013-12-02 17:18:58 +0100511
512 surface->front->enable_opaque_regions = renderer->enable_opaque_regions;
513 surface->back->enable_opaque_regions = renderer->enable_opaque_regions;
514
Tomeu Vizosob4659eb2013-10-07 11:02:20 +0200515 surface->buffer_type = BUFFER_TYPE_NULL;
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300516
517 pixman_region32_init(&surface->prev_damage);
518
519 return surface;
520}
521
522static void
523rpir_surface_destroy(struct rpir_surface *surface)
524{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500525 if (surface->visible_views)
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300526 weston_log("ERROR rpi: destroying on-screen element\n");
527
Jason Ekstranda7af7042013-10-12 22:38:11 -0500528 assert(wl_list_empty(&surface->views));
529
530 if (surface->surface)
531 surface->surface->renderer_state = NULL;
532
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300533 pixman_region32_fini(&surface->prev_damage);
534 rpi_resource_release(&surface->resources[0]);
535 rpi_resource_release(&surface->resources[1]);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500536 DBG("rpir_surface %p destroyed (%u)\n", surface, surface->visible_views);
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300537
Tomeu Vizoso74987582013-10-25 10:34:38 +0200538 rpir_egl_buffer_destroy(surface->egl_back);
539 rpir_egl_buffer_destroy(surface->egl_front);
540 rpir_egl_buffer_destroy(surface->egl_old_front);
Tomeu Vizosob4659eb2013-10-07 11:02:20 +0200541
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300542 free(surface);
543}
544
545static int
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500546rpir_surface_damage(struct rpir_surface *surface, struct weston_buffer *buffer,
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300547 pixman_region32_t *damage)
548{
549 pixman_region32_t upload;
550 int ret;
551
552 if (!pixman_region32_not_empty(damage))
553 return 0;
554
555 DBG("rpir_surface %p update resource %p\n", surface, surface->back);
556
557 /* XXX: todo: if no surface->handle, update front buffer directly
558 * to avoid creating a new back buffer */
559 if (surface->single_buffer) {
Tomeu Vizosoe4f7b922013-12-02 17:18:58 +0100560 ret = rpi_resource_update(surface->front, buffer, damage,
561 &surface->surface->opaque);
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300562 } else {
563 pixman_region32_init(&upload);
564 pixman_region32_union(&upload, &surface->prev_damage, damage);
Tomeu Vizosoe4f7b922013-12-02 17:18:58 +0100565 ret = rpi_resource_update(surface->back, buffer, &upload,
566 &surface->surface->opaque);
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300567 pixman_region32_fini(&upload);
568 }
569
570 pixman_region32_copy(&surface->prev_damage, damage);
571 surface->need_swap = 1;
572
573 return ret;
574}
575
Jason Ekstranda7af7042013-10-12 22:38:11 -0500576static struct rpir_view *
577rpir_view_create(struct rpir_surface *surface)
578{
579 struct rpir_view *view;
580
Bryce Harringtonde16d892014-11-20 22:21:57 -0800581 view = zalloc(sizeof *view);
582 if (view == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -0500583 return NULL;
584
585 view->surface = surface;
586 wl_list_insert(&surface->views, &view->surface_link);
587
588 wl_list_init(&view->link);
589 view->handle = DISPMANX_NO_HANDLE;
590
591 return view;
592}
593
594static void
595rpir_view_destroy(struct rpir_view *view)
596{
597 wl_list_remove(&view->link);
598
599 if (view->handle != DISPMANX_NO_HANDLE) {
600 view->surface->visible_views--;
601 weston_log("ERROR rpi: destroying on-screen element\n");
602 }
603
604 if (view->view)
605 view->view->renderer_state = NULL;
606
607 wl_list_remove(&view->surface_link);
608 if (wl_list_empty(&view->surface->views) && view->surface->surface == NULL)
609 rpir_surface_destroy(view->surface);
610
611 DBG("rpir_view %p destroyed (%d)\n", view, view->handle);
612
613 free(view);
614}
615
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300616static void
617matrix_type_str(struct weston_matrix *matrix, char *buf, int len)
618{
619 static const char types[33] = "TSRO";
620 unsigned mask = matrix->type;
621 int i = 0;
622
623 while (mask && i < len - 1) {
624 if (mask & (1u << i))
625 *buf++ = types[i];
626 mask &= ~(1u << i);
627 i++;
628 }
629 *buf = '\0';
630}
631
632static void
633log_print_matrix(struct weston_matrix *matrix)
634{
635 char typestr[6];
636 float *d = matrix->d;
637
638 matrix_type_str(matrix, typestr, sizeof typestr);
639 weston_log_continue("%14.6e %14.6e %14.6e %14.6e\n",
640 d[0], d[4], d[8], d[12]);
641 weston_log_continue("%14.6e %14.6e %14.6e %14.6e\n",
642 d[1], d[5], d[9], d[13]);
643 weston_log_continue("%14.6e %14.6e %14.6e %14.6e\n",
644 d[2], d[6], d[10], d[14]);
645 weston_log_continue("%14.6e %14.6e %14.6e %14.6e type: %s\n",
646 d[3], d[7], d[11], d[15], typestr);
647}
648
649static void
650warn_bad_matrix(struct weston_matrix *total, struct weston_matrix *output,
651 struct weston_matrix *surface)
652{
653 static int n_warn;
654 char typestr[6];
655
656 if (n_warn++ == 10)
657 weston_log("%s: not showing more warnings\n", __func__);
658
659 if (n_warn > 10)
660 return;
661
662 weston_log("%s: warning: total transformation is not renderable:\n",
663 __func__);
664 log_print_matrix(total);
665
666 matrix_type_str(surface, typestr, sizeof typestr);
667 weston_log_continue("surface matrix type: %s\n", typestr);
668 matrix_type_str(output, typestr, sizeof typestr);
669 weston_log_continue("output matrix type: %s\n", typestr);
670}
671
672/*#define SURFACE_TRANSFORM */
673
674static int
Jason Ekstranda7af7042013-10-12 22:38:11 -0500675rpir_view_compute_rects(struct rpir_view *view,
676 VC_RECT_T *src_rect, VC_RECT_T *dst_rect,
677 VC_IMAGE_TRANSFORM_T *flipmask)
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300678{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500679 struct weston_output *output_base = view->view->surface->output;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500680 struct weston_matrix matrix = view->view->transform.matrix;
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300681 VC_IMAGE_TRANSFORM_T flipt = 0;
682 int src_x, src_y;
683 int dst_x, dst_y;
684 int src_width, src_height;
685 int dst_width, dst_height;
686 struct weston_vector p1 = {{ 0.0f, 0.0f, 0.0f, 1.0f }};
687 struct weston_vector p2 = {{ 0.0f, 0.0f, 0.0f, 1.0f }};
688 int t;
689 int over;
690
691 /* XXX: take buffer transform into account */
692
693 /* src is in 16.16, dst is in 32.0 fixed point.
694 * Negative values are not allowed in VC_RECT_T.
695 * Clip size to output boundaries, firmware ignores
696 * huge elements like 8192x8192.
697 */
698
699 src_x = 0 << 16;
700 src_y = 0 << 16;
Tomeu Vizosob4659eb2013-10-07 11:02:20 +0200701
Jason Ekstranda7af7042013-10-12 22:38:11 -0500702 if (view->surface->buffer_type == BUFFER_TYPE_EGL) {
703 struct weston_buffer *buffer =
704 view->surface->egl_front->buffer_ref.buffer;
Tomeu Vizosob4659eb2013-10-07 11:02:20 +0200705
John Sadler960b5eb2015-09-05 15:01:39 +0100706 if (!buffer)
707 return -1;
708
Tomeu Vizosob4659eb2013-10-07 11:02:20 +0200709 src_width = buffer->width << 16;
710 src_height = buffer->height << 16;
711 } else {
Jason Ekstranda7af7042013-10-12 22:38:11 -0500712 src_width = view->surface->front->width << 16;
713 src_height = view->surface->front->height << 16;
Tomeu Vizosob4659eb2013-10-07 11:02:20 +0200714 }
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300715
Derek Foreman75ead052015-05-07 11:54:18 -0500716 weston_matrix_multiply(&matrix, &output_base->matrix);
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300717
718#ifdef SURFACE_TRANSFORM
719 if (matrix.type >= WESTON_MATRIX_TRANSFORM_OTHER) {
720#else
721 if (matrix.type >= WESTON_MATRIX_TRANSFORM_ROTATE) {
722#endif
Derek Foreman75ead052015-05-07 11:54:18 -0500723 warn_bad_matrix(&matrix, &output_base->matrix,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500724 &view->view->transform.matrix);
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300725 } else {
726 if (matrix.type & WESTON_MATRIX_TRANSFORM_ROTATE) {
727 if (fabsf(matrix.d[0]) < 1e-4f &&
728 fabsf(matrix.d[5]) < 1e-4f) {
729 flipt |= TRANSFORM_TRANSPOSE;
730 } else if (fabsf(matrix.d[1]) < 1e-4 &&
731 fabsf(matrix.d[4]) < 1e-4) {
732 /* no transpose */
733 } else {
Derek Foreman75ead052015-05-07 11:54:18 -0500734 warn_bad_matrix(&matrix, &output_base->matrix,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500735 &view->view->transform.matrix);
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300736 }
737 }
738 }
739
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600740 p2.f[0] = view->view->surface->width;
741 p2.f[1] = view->view->surface->height;
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300742
743 /* transform top-left and bot-right corner into screen coordinates */
744 weston_matrix_transform(&matrix, &p1);
745 weston_matrix_transform(&matrix, &p2);
746
747 /* Compute the destination rectangle on screen, converting
748 * negative dimensions to flips.
749 */
750
751 dst_width = round(p2.f[0] - p1.f[0]);
752 if (dst_width < 0) {
753 dst_x = round(p2.f[0]);
754 dst_width = -dst_width;
755
756 if (!(flipt & TRANSFORM_TRANSPOSE))
757 flipt |= TRANSFORM_HFLIP;
758 else
759 flipt |= TRANSFORM_VFLIP;
760 } else {
761 dst_x = round(p1.f[0]);
762 }
763
764 dst_height = round(p2.f[1] - p1.f[1]);
765 if (dst_height < 0) {
766 dst_y = round(p2.f[1]);
767 dst_height = -dst_height;
768
769 if (!(flipt & TRANSFORM_TRANSPOSE))
770 flipt |= TRANSFORM_VFLIP;
771 else
772 flipt |= TRANSFORM_HFLIP;
773 } else {
774 dst_y = round(p1.f[1]);
775 }
776
777 if (dst_width == 0 || dst_height == 0) {
778 DBG("ignored, zero surface area before clipping\n");
779 return -1;
780 }
781
782#ifdef SURFACE_TRANSFORM
783 /* Dispmanx works as if you flipped the whole screen, when
784 * you flip an element. But, we want to flip an element in place.
785 * XXX: fixme
786 */
787 if (flipt & TRANSFORM_HFLIP)
788 dst_x = output_base->width - dst_x;
789 if (flipt & TRANSFORM_VFLIP)
790 dst_y = output_base->height - dst_y;
791 if (flipt & TRANSFORM_TRANSPOSE) {
792 int_swap(&dst_x, &dst_y);
793 int_swap(&dst_width, &dst_height);
794 }
795#else
796 switch (output_base->transform) {
797 case WL_OUTPUT_TRANSFORM_FLIPPED:
798 flipt = TRANSFORM_HFLIP;
799 break;
800 case WL_OUTPUT_TRANSFORM_NORMAL:
801 flipt = 0;
802 break;
803
804 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
805 flipt = TRANSFORM_HFLIP | TRANSFORM_VFLIP | TRANSFORM_TRANSPOSE;
806 break;
807 case WL_OUTPUT_TRANSFORM_90:
808 flipt = TRANSFORM_VFLIP | TRANSFORM_TRANSPOSE;
809 break;
810 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
811 flipt = TRANSFORM_VFLIP;
812 break;
813 case WL_OUTPUT_TRANSFORM_180:
814 flipt = TRANSFORM_HFLIP | TRANSFORM_VFLIP;
815 break;
816
817 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
818 flipt = TRANSFORM_TRANSPOSE;
819 break;
820 case WL_OUTPUT_TRANSFORM_270:
821 flipt = TRANSFORM_HFLIP | TRANSFORM_TRANSPOSE;
822 break;
823 default:
824 break;
825 }
826#endif
827
828 /* clip destination rectangle to screen dimensions */
829
830 if (dst_x < 0) {
831 t = (int64_t)dst_x * src_width / dst_width;
832 src_width += t;
833 dst_width += dst_x;
834 src_x -= t;
835 dst_x = 0;
836 }
837
838 if (dst_y < 0) {
839 t = (int64_t)dst_y * src_height / dst_height;
840 src_height += t;
841 dst_height += dst_y;
842 src_y -= t;
843 dst_y = 0;
844 }
845
846 over = dst_x + dst_width - output_base->width;
847 if (over > 0) {
848 t = (int64_t)over * src_width / dst_width;
849 src_width -= t;
850 dst_width -= over;
851 }
852
853 over = dst_y + dst_height - output_base->height;
854 if (over > 0) {
855 t = (int64_t)over * src_height / dst_height;
856 src_height -= t;
857 dst_height -= over;
858 }
859
860 src_width = int_max(src_width, 0);
861 src_height = int_max(src_height, 0);
862
Jason Ekstranda7af7042013-10-12 22:38:11 -0500863 DBG("rpir_view %p %dx%d: p1 %f, %f; p2 %f, %f\n", view,
Pekka Paalanen2d0f8b72014-05-09 15:08:06 +0300864 view->view->surface->width,
865 view->view->surface->height,
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300866 p1.f[0], p1.f[1], p2.f[0], p2.f[1]);
867 DBG("src rect %d;%d, %d;%d, %d;%dx%d;%d\n",
868 src_x >> 16, src_x & 0xffff,
869 src_y >> 16, src_y & 0xffff,
870 src_width >> 16, src_width & 0xffff,
871 src_height >> 16, src_height & 0xffff);
872 DBG("dest rect %d, %d, %dx%d%s%s%s\n",
873 dst_x, dst_y, dst_width, dst_height,
874 (flipt & TRANSFORM_HFLIP) ? " hflip" : "",
875 (flipt & TRANSFORM_VFLIP) ? " vflip" : "",
876 (flipt & TRANSFORM_TRANSPOSE) ? " transp" : "");
877
878 assert(src_x >= 0);
879 assert(src_y >= 0);
880 assert(dst_x >= 0);
881 assert(dst_y >= 0);
882
883 if (dst_width < 1 || dst_height < 1) {
884 DBG("ignored, zero surface area after clipping\n");
885 return -1;
886 }
887
Tomeu Vizosob4659eb2013-10-07 11:02:20 +0200888 /* EGL buffers will be upside-down related to what DispmanX expects */
Jason Ekstranda7af7042013-10-12 22:38:11 -0500889 if (view->surface->buffer_type == BUFFER_TYPE_EGL)
Tomeu Vizosob4659eb2013-10-07 11:02:20 +0200890 flipt ^= TRANSFORM_VFLIP;
891
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300892 vc_dispmanx_rect_set(src_rect, src_x, src_y, src_width, src_height);
893 vc_dispmanx_rect_set(dst_rect, dst_x, dst_y, dst_width, dst_height);
894 *flipmask = flipt;
895
896 return 0;
897}
898
899static DISPMANX_TRANSFORM_T
900vc_image2dispmanx_transform(VC_IMAGE_TRANSFORM_T t)
901{
902 /* XXX: uhh, are these right? */
903 switch (t) {
904 case VC_IMAGE_ROT0:
905 return DISPMANX_NO_ROTATE;
906 case VC_IMAGE_MIRROR_ROT0:
907 return DISPMANX_FLIP_HRIZ;
908 case VC_IMAGE_MIRROR_ROT180:
909 return DISPMANX_FLIP_VERT;
910 case VC_IMAGE_ROT180:
911 return DISPMANX_ROTATE_180;
912 case VC_IMAGE_MIRROR_ROT90:
913 return DISPMANX_ROTATE_90 | DISPMANX_FLIP_HRIZ;
914 case VC_IMAGE_ROT270:
915 return DISPMANX_ROTATE_270;
916 case VC_IMAGE_ROT90:
917 return DISPMANX_ROTATE_90;
918 case VC_IMAGE_MIRROR_ROT270:
919 return DISPMANX_ROTATE_270 | DISPMANX_FLIP_VERT;
920 default:
921 assert(0 && "bad VC_IMAGE_TRANSFORM_T");
922 return DISPMANX_NO_ROTATE;
923 }
924}
925
Tomeu Vizosob4659eb2013-10-07 11:02:20 +0200926static DISPMANX_RESOURCE_HANDLE_T
927rpir_surface_get_resource(struct rpir_surface *surface)
928{
929 switch (surface->buffer_type) {
930 case BUFFER_TYPE_SHM:
931 case BUFFER_TYPE_NULL:
932 return surface->front->handle;
933 case BUFFER_TYPE_EGL:
934 if (surface->egl_front != NULL)
935 return surface->egl_front->resource_handle;
936 default:
937 return DISPMANX_NO_HANDLE;
938 }
939}
940
Tomeu Vizosoe4f7b922013-12-02 17:18:58 +0100941#ifdef HAVE_ELEMENT_SET_OPAQUE_RECT
942static int
943rpir_surface_set_opaque_rect(struct rpir_surface *surface,
944 DISPMANX_UPDATE_HANDLE_T update)
945{
946 int ret;
947
948 if (pixman_region32_not_empty(&surface->surface->opaque) &&
949 surface->opaque_regions) {
950 pixman_box32_t *box;
951 VC_RECT_T opaque_rect;
952
953 box = pixman_region32_extents(&surface->surface->opaque);
954 opaque_rect.x = box->x1;
955 opaque_rect.y = box->y1;
956 opaque_rect.width = box->x2 - box->x1;
957 opaque_rect.height = box->y2 - box->y1;
958
959 ret = vc_dispmanx_element_set_opaque_rect(update,
960 surface->handle,
961 &opaque_rect);
962 if (ret) {
963 weston_log("vc_dispmanx_element_set_opaque_rect failed\n");
964 return -1;
965 }
966 }
967
968 return 0;
969}
970#endif
971
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300972static int
Jason Ekstranda7af7042013-10-12 22:38:11 -0500973rpir_view_dmx_add(struct rpir_view *view, struct rpir_output *output,
974 DISPMANX_UPDATE_HANDLE_T update, int layer)
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300975{
976 /* Do not use DISPMANX_FLAGS_ALPHA_PREMULT here.
977 * If you define PREMULT and ALPHA_MIX, the hardware will not
978 * multiply the source color with the element alpha, leading to
979 * bad colors. Instead, we define PREMULT during pixel data upload.
980 */
981 VC_DISPMANX_ALPHA_T alphasetup = {
982 DISPMANX_FLAGS_ALPHA_FROM_SOURCE |
983 DISPMANX_FLAGS_ALPHA_MIX,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500984 float2uint8(view->view->alpha), /* opacity 0-255 */
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300985 0 /* mask resource handle */
986 };
987 VC_RECT_T dst_rect;
988 VC_RECT_T src_rect;
989 VC_IMAGE_TRANSFORM_T flipmask;
990 int ret;
Tomeu Vizosob4659eb2013-10-07 11:02:20 +0200991 DISPMANX_RESOURCE_HANDLE_T resource_handle;
992
Jason Ekstranda7af7042013-10-12 22:38:11 -0500993 resource_handle = rpir_surface_get_resource(view->surface);
Tomeu Vizosob4659eb2013-10-07 11:02:20 +0200994 if (resource_handle == DISPMANX_NO_HANDLE) {
995 weston_log("%s: no buffer yet, aborting\n", __func__);
996 return 0;
997 }
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300998
Jason Ekstranda7af7042013-10-12 22:38:11 -0500999 ret = rpir_view_compute_rects(view, &src_rect, &dst_rect, &flipmask);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001000 if (ret < 0)
1001 return 0;
1002
Jason Ekstranda7af7042013-10-12 22:38:11 -05001003 view->handle = vc_dispmanx_element_add(
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001004 update,
1005 output->display,
1006 layer,
1007 &dst_rect,
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001008 resource_handle,
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001009 &src_rect,
1010 DISPMANX_PROTECTION_NONE,
1011 &alphasetup,
1012 NULL /* clamp */,
1013 vc_image2dispmanx_transform(flipmask));
Jason Ekstranda7af7042013-10-12 22:38:11 -05001014 DBG("rpir_surface %p add %u, alpha %f resource %d\n", view,
1015 view->handle, view->view->alpha, resource_handle);
1016
1017 if (view->handle == DISPMANX_NO_HANDLE)
1018 return -1;
1019
Tomeu Vizosoe4f7b922013-12-02 17:18:58 +01001020#ifdef HAVE_ELEMENT_SET_OPAQUE_RECT
1021 ret = rpir_surface_set_opaque_rect(surface, update);
1022 if (ret < 0)
1023 return -1;
1024#endif
1025
Jason Ekstranda7af7042013-10-12 22:38:11 -05001026 view->surface->visible_views++;
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001027
1028 return 1;
1029}
1030
1031static void
Jason Ekstranda7af7042013-10-12 22:38:11 -05001032rpir_view_dmx_swap(struct rpir_view *view,
1033 DISPMANX_UPDATE_HANDLE_T update)
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001034{
1035 VC_RECT_T rect;
1036 pixman_box32_t *r;
1037
1038 /* XXX: skip, iff resource was not reallocated, and single-buffering */
Jason Ekstranda7af7042013-10-12 22:38:11 -05001039 vc_dispmanx_element_change_source(update, view->handle,
1040 view->surface->front->handle);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001041
1042 /* This is current damage now, after rpir_surface_damage() */
Jason Ekstranda7af7042013-10-12 22:38:11 -05001043 r = pixman_region32_extents(&view->surface->prev_damage);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001044
1045 vc_dispmanx_rect_set(&rect, r->x1, r->y1,
1046 r->x2 - r->x1, r->y2 - r->y1);
Jason Ekstranda7af7042013-10-12 22:38:11 -05001047 vc_dispmanx_element_modified(update, view->handle, &rect);
1048 DBG("rpir_view %p swap\n", view);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001049}
1050
1051static int
Jason Ekstranda7af7042013-10-12 22:38:11 -05001052rpir_view_dmx_move(struct rpir_view *view,
1053 DISPMANX_UPDATE_HANDLE_T update, int layer)
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001054{
Jason Ekstranda7af7042013-10-12 22:38:11 -05001055 uint8_t alpha = float2uint8(view->view->alpha);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001056 VC_RECT_T dst_rect;
1057 VC_RECT_T src_rect;
1058 VC_IMAGE_TRANSFORM_T flipmask;
1059 int ret;
1060
1061 /* XXX: return early, if all attributes stay the same */
1062
Jason Ekstranda7af7042013-10-12 22:38:11 -05001063 if (view->surface->buffer_type == BUFFER_TYPE_EGL) {
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001064 DISPMANX_RESOURCE_HANDLE_T resource_handle;
1065
Jason Ekstranda7af7042013-10-12 22:38:11 -05001066 resource_handle = rpir_surface_get_resource(view->surface);
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001067 if (resource_handle == DISPMANX_NO_HANDLE) {
1068 weston_log("%s: no buffer yet, aborting\n", __func__);
1069 return 0;
1070 }
1071
1072 vc_dispmanx_element_change_source(update,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001073 view->handle,
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001074 resource_handle);
1075 }
1076
Jason Ekstranda7af7042013-10-12 22:38:11 -05001077 ret = rpir_view_compute_rects(view, &src_rect, &dst_rect, &flipmask);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001078 if (ret < 0)
1079 return 0;
1080
1081 ret = vc_dispmanx_element_change_attributes(
1082 update,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001083 view->handle,
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001084 ELEMENT_CHANGE_LAYER |
1085 ELEMENT_CHANGE_OPACITY |
1086 ELEMENT_CHANGE_TRANSFORM |
1087 ELEMENT_CHANGE_DEST_RECT |
1088 ELEMENT_CHANGE_SRC_RECT,
1089 layer,
1090 alpha,
1091 &dst_rect,
1092 &src_rect,
1093 DISPMANX_NO_HANDLE,
1094 /* This really is DISPMANX_TRANSFORM_T, no matter
1095 * what the header says. */
1096 vc_image2dispmanx_transform(flipmask));
Jason Ekstranda7af7042013-10-12 22:38:11 -05001097 DBG("rpir_view %p move\n", view);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001098
1099 if (ret)
1100 return -1;
1101
Tomeu Vizosoe4f7b922013-12-02 17:18:58 +01001102#ifdef HAVE_ELEMENT_SET_OPAQUE_RECT
1103 ret = rpir_surface_set_opaque_rect(surface, update);
1104 if (ret < 0)
1105 return -1;
1106#endif
1107
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001108 return 1;
1109}
1110
1111static void
Jason Ekstranda7af7042013-10-12 22:38:11 -05001112rpir_view_dmx_remove(struct rpir_view *view,
1113 DISPMANX_UPDATE_HANDLE_T update)
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001114{
Jason Ekstranda7af7042013-10-12 22:38:11 -05001115 if (view->handle == DISPMANX_NO_HANDLE)
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001116 return;
1117
Jason Ekstranda7af7042013-10-12 22:38:11 -05001118 vc_dispmanx_element_remove(update, view->handle);
1119 DBG("rpir_view %p remove %u\n", view, view->handle);
1120 view->handle = DISPMANX_NO_HANDLE;
1121 view->surface->visible_views--;
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001122}
1123
1124static void
1125rpir_surface_swap_pointers(struct rpir_surface *surface)
1126{
1127 struct rpi_resource *tmp;
1128
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001129 if (surface->buffer_type == BUFFER_TYPE_EGL) {
1130 if (surface->egl_back != NULL) {
1131 assert(surface->egl_old_front == NULL);
1132 surface->egl_old_front = surface->egl_front;
1133 surface->egl_front = surface->egl_back;
1134 surface->egl_back = NULL;
Tomeu Vizoso15767812013-10-24 15:38:31 +02001135 DBG("new front %d\n", surface->egl_front->resource_handle);
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001136 }
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001137 } else {
Jason Ekstranda7af7042013-10-12 22:38:11 -05001138 tmp = surface->front;
1139 surface->front = surface->back;
1140 surface->back = tmp;
Tomeu Vizoso15767812013-10-24 15:38:31 +02001141 DBG("new back %p, new front %p\n", surface->back, surface->front);
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001142 }
Jason Ekstranda7af7042013-10-12 22:38:11 -05001143}
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001144
Jason Ekstranda7af7042013-10-12 22:38:11 -05001145static int
1146is_view_not_visible(struct weston_view *view)
1147{
1148 /* Return true, if surface is guaranteed to be totally obscured. */
1149 int ret;
1150 pixman_region32_t unocc;
1151
1152 pixman_region32_init(&unocc);
1153 pixman_region32_subtract(&unocc, &view->transform.boundingbox,
1154 &view->clip);
1155 ret = !pixman_region32_not_empty(&unocc);
1156 pixman_region32_fini(&unocc);
1157
1158 return ret;
1159}
1160
1161static void
1162rpir_view_update(struct rpir_view *view, struct rpir_output *output,
1163 DISPMANX_UPDATE_HANDLE_T update, int layer)
1164{
1165 int ret;
1166 int obscured;
1167
Jason Ekstranda7af7042013-10-12 22:38:11 -05001168 obscured = is_view_not_visible(view->view);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001169 if (obscured) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05001170 DBG("rpir_view %p totally obscured.\n", view);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001171
Jason Ekstranda7af7042013-10-12 22:38:11 -05001172 wl_list_remove(&view->link);
1173 if (view->handle == DISPMANX_NO_HANDLE) {
1174 wl_list_init(&view->link);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001175 } else {
Jason Ekstranda7af7042013-10-12 22:38:11 -05001176 rpir_view_dmx_remove(view, update);
1177 wl_list_insert(&output->view_cleanup_list,
1178 &view->link);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001179 }
1180
1181 goto out;
1182 }
1183
Jason Ekstranda7af7042013-10-12 22:38:11 -05001184 if (view->handle == DISPMANX_NO_HANDLE) {
1185 ret = rpir_view_dmx_add(view, output, update, layer);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001186 if (ret == 0) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05001187 wl_list_remove(&view->link);
1188 wl_list_init(&view->link);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001189 } else if (ret < 0) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05001190 weston_log("ERROR rpir_view_dmx_add() failed.\n");
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001191 }
1192 } else {
Jason Ekstranda7af7042013-10-12 22:38:11 -05001193 if (view->surface->need_swap)
1194 rpir_view_dmx_swap(view, update);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001195
Jason Ekstranda7af7042013-10-12 22:38:11 -05001196 ret = rpir_view_dmx_move(view, update, layer);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001197 if (ret == 0) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05001198 rpir_view_dmx_remove(view, update);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001199
Jason Ekstranda7af7042013-10-12 22:38:11 -05001200 wl_list_remove(&view->link);
1201 wl_list_insert(&output->view_cleanup_list,
1202 &view->link);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001203 } else if (ret < 0) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05001204 weston_log("ERROR rpir_view_dmx_move() failed.\n");
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001205 }
1206 }
1207
1208out:
Jason Ekstranda7af7042013-10-12 22:38:11 -05001209 view->layer = layer;
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001210}
1211
1212static int
1213rpi_renderer_read_pixels(struct weston_output *base,
1214 pixman_format_code_t format, void *pixels,
1215 uint32_t x, uint32_t y,
1216 uint32_t width, uint32_t height)
1217{
1218 struct rpir_output *output = to_rpir_output(base);
1219 struct rpi_resource *buffer = &output->capture_buffer;
1220 VC_RECT_T rect;
1221 uint32_t fb_width, fb_height;
1222 uint32_t dst_pitch;
1223 uint32_t i;
1224 int ret;
1225
Hardeningff39efa2013-09-18 23:56:35 +02001226 fb_width = base->current_mode->width;
1227 fb_height = base->current_mode->height;
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001228
1229 DBG("%s(%u, %u, %u, %u), resource %p\n", __func__,
1230 x, y, width, height, buffer);
1231
1232 if (format != PIXMAN_a8r8g8b8) {
1233 weston_log("rpi-renderer error: bad read_format\n");
1234 return -1;
1235 }
1236
1237 dst_pitch = fb_width * 4;
1238
1239 if (buffer->handle == DISPMANX_NO_HANDLE) {
1240 free(output->capture_data);
1241 output->capture_data = NULL;
1242
1243 ret = rpi_resource_realloc(buffer, VC_IMAGE_ARGB8888,
1244 fb_width, fb_height,
1245 dst_pitch, fb_height);
1246 if (ret < 0) {
1247 weston_log("rpi-renderer error: "
1248 "allocating read buffer failed\n");
1249 return -1;
1250 }
1251
1252 ret = vc_dispmanx_snapshot(output->display, buffer->handle,
1253 VC_IMAGE_ROT0);
1254 if (ret) {
1255 weston_log("rpi-renderer error: "
1256 "vc_dispmanx_snapshot returned %d\n", ret);
1257 return -1;
1258 }
1259 DBG("%s: snapshot done.\n", __func__);
1260 }
1261
1262 /*
1263 * If vc_dispmanx_resource_read_data was able to read sub-rectangles,
1264 * we could read directly into 'pixels'. But it cannot, it does not
1265 * use rect.x or rect.width, and does this:
1266 * host_start = (uint8_t *)dst_address + (dst_pitch * p_rect->y);
1267 * In other words, it is only good for reading the full buffer in
1268 * one go.
1269 */
1270 vc_dispmanx_rect_set(&rect, 0, 0, fb_width, fb_height);
1271
1272 if (x == 0 && y == 0 && width == fb_width && height == fb_height) {
1273 ret = vc_dispmanx_resource_read_data(buffer->handle, &rect,
1274 pixels, dst_pitch);
1275 if (ret) {
1276 weston_log("rpi-renderer error: "
1277 "resource_read_data returned %d\n", ret);
1278 return -1;
1279 }
1280 DBG("%s: full frame done.\n", __func__);
1281 return 0;
1282 }
1283
1284 if (!output->capture_data) {
1285 output->capture_data = malloc(fb_height * dst_pitch);
1286 if (!output->capture_data) {
1287 weston_log("rpi-renderer error: "
1288 "out of memory\n");
1289 return -1;
1290 }
1291
1292 ret = vc_dispmanx_resource_read_data(buffer->handle, &rect,
1293 output->capture_data,
1294 dst_pitch);
1295 if (ret) {
1296 weston_log("rpi-renderer error: "
1297 "resource_read_data returned %d\n", ret);
1298 return -1;
1299 }
1300 }
1301
1302 for (i = 0; i < height; i++) {
1303 uint8_t *src = output->capture_data +
1304 (y + i) * dst_pitch + x * 4;
1305 uint8_t *dst = (uint8_t *)pixels + i * width * 4;
1306 memcpy(dst, src, width * 4);
1307 }
1308
1309 return 0;
1310}
1311
1312static void
1313rpir_output_dmx_remove_all(struct rpir_output *output,
1314 DISPMANX_UPDATE_HANDLE_T update)
1315{
Jason Ekstranda7af7042013-10-12 22:38:11 -05001316 struct rpir_view *view;
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001317
Jason Ekstranda7af7042013-10-12 22:38:11 -05001318 while (!wl_list_empty(&output->view_list)) {
1319 view = container_of(output->view_list.next,
1320 struct rpir_view, link);
1321 rpir_view_dmx_remove(view, update);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001322
Jason Ekstranda7af7042013-10-12 22:38:11 -05001323 wl_list_remove(&view->link);
1324 wl_list_insert(&output->view_cleanup_list, &view->link);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001325 }
1326}
1327
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001328/* Note: this won't work right for multiple outputs. A DispmanX Element
1329 * is tied to one DispmanX Display, i.e. output.
1330 */
1331static void
1332rpi_renderer_repaint_output(struct weston_output *base,
1333 pixman_region32_t *output_damage)
1334{
1335 struct weston_compositor *compositor = base->compositor;
1336 struct rpir_output *output = to_rpir_output(base);
Jason Ekstranda7af7042013-10-12 22:38:11 -05001337 struct weston_view *wv;
1338 struct rpir_view *view;
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001339 struct wl_list done_list;
1340 int layer = 1;
1341
1342 assert(output->update != DISPMANX_NO_HANDLE);
1343
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001344 rpi_resource_release(&output->capture_buffer);
1345 free(output->capture_data);
1346 output->capture_data = NULL;
1347
Jason Ekstranda7af7042013-10-12 22:38:11 -05001348 /* Swap resources on surfaces as needed */
1349 wl_list_for_each_reverse(wv, &compositor->view_list, link)
Derek Foreman060cf112015-11-18 16:32:26 -06001350 wv->surface->touched = false;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001351
1352 wl_list_for_each_reverse(wv, &compositor->view_list, link) {
1353 view = to_rpir_view(wv);
1354
1355 if (!wv->surface->touched) {
Derek Foreman060cf112015-11-18 16:32:26 -06001356 wv->surface->touched = true;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001357
Tomeu Vizoso44247742013-10-24 15:38:32 +02001358 if (view->surface->buffer_type == BUFFER_TYPE_EGL ||
1359 view->surface->need_swap)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001360 rpir_surface_swap_pointers(view->surface);
1361 }
1362
Tomeu Vizoso74987582013-10-25 10:34:38 +02001363 if (view->surface->buffer_type == BUFFER_TYPE_EGL) {
1364 struct weston_buffer *buffer;
1365 buffer = view->surface->egl_front->buffer_ref.buffer;
1366 if (buffer != NULL) {
Pekka Paalanend5fbfb22013-11-22 17:30:39 +02001367 rpi_buffer_egl_lock(buffer);
Jason Ekstranda7af7042013-10-12 22:38:11 -05001368 } else {
Tomeu Vizoso74987582013-10-25 10:34:38 +02001369 weston_log("warning: client destroyed current front buffer\n");
1370
1371 wl_list_remove(&view->link);
1372 if (view->handle == DISPMANX_NO_HANDLE) {
1373 wl_list_init(&view->link);
1374 } else {
1375 rpir_view_dmx_remove(view, output->update);
1376 wl_list_insert(&output->view_cleanup_list,
1377 &view->link);
1378 }
Jason Ekstranda7af7042013-10-12 22:38:11 -05001379 }
1380 }
1381 }
1382
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001383 /* update all renderable surfaces */
1384 wl_list_init(&done_list);
Jason Ekstranda7af7042013-10-12 22:38:11 -05001385 wl_list_for_each_reverse(wv, &compositor->view_list, link) {
1386 if (wv->plane != &compositor->primary_plane)
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001387 continue;
1388
Jason Ekstranda7af7042013-10-12 22:38:11 -05001389 view = to_rpir_view(wv);
1390 assert(!wl_list_empty(&view->link) ||
1391 view->handle == DISPMANX_NO_HANDLE);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001392
Jason Ekstranda7af7042013-10-12 22:38:11 -05001393 wl_list_remove(&view->link);
1394 wl_list_insert(&done_list, &view->link);
1395 rpir_view_update(view, output, output->update, layer++);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001396 }
1397
Jason Ekstranda7af7042013-10-12 22:38:11 -05001398 /* Mark all surfaces as swapped */
1399 wl_list_for_each_reverse(wv, &compositor->view_list, link)
1400 to_rpir_surface(wv->surface)->need_swap = 0;
1401
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001402 /* Remove all surfaces that are still on screen, but were
1403 * not rendered this time.
1404 */
1405 rpir_output_dmx_remove_all(output, output->update);
1406
Jason Ekstranda7af7042013-10-12 22:38:11 -05001407 wl_list_insert_list(&output->view_list, &done_list);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001408 output->update = DISPMANX_NO_HANDLE;
1409
1410 /* The frame_signal is emitted in rpi_renderer_finish_frame(),
1411 * so that the firmware can capture the up-to-date contents.
1412 */
Shinya Saito2071f1f2015-10-22 11:44:49 +09001413 pixman_region32_copy(&base->previous_damage, output_damage);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001414}
1415
1416static void
1417rpi_renderer_flush_damage(struct weston_surface *base)
1418{
1419 /* Called for every surface just before repainting it, if
1420 * having an shm buffer.
1421 */
1422 struct rpir_surface *surface = to_rpir_surface(base);
Jason Ekstrand6bd62942013-06-20 20:38:23 -05001423 struct weston_buffer *buffer = surface->buffer_ref.buffer;
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001424 int ret;
1425
1426 assert(buffer);
Jason Ekstrand6bd62942013-06-20 20:38:23 -05001427 assert(wl_shm_buffer_get(buffer->resource));
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001428
1429 ret = rpir_surface_damage(surface, buffer, &base->damage);
1430 if (ret)
1431 weston_log("%s error: updating Dispmanx resource failed.\n",
1432 __func__);
1433
1434 weston_buffer_reference(&surface->buffer_ref, NULL);
1435}
1436
1437static void
Jason Ekstrand6bd62942013-06-20 20:38:23 -05001438rpi_renderer_attach(struct weston_surface *base, struct weston_buffer *buffer)
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001439{
1440 /* Called every time a client commits an attach. */
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001441 struct rpir_surface *surface = to_rpir_surface(base);
1442
1443 assert(surface);
1444 if (!surface)
1445 return;
1446
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001447 if (surface->buffer_type == BUFFER_TYPE_SHM) {
1448 if (!surface->single_buffer)
1449 /* XXX: need to check if in middle of update */
1450 rpi_resource_release(surface->back);
1451
Jason Ekstranda7af7042013-10-12 22:38:11 -05001452 if (!surface->visible_views)
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001453 /* XXX: cannot do this, if middle of an update */
1454 rpi_resource_release(surface->front);
1455
1456 weston_buffer_reference(&surface->buffer_ref, NULL);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001457 }
1458
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001459 /* If buffer is NULL, Weston core unmaps the surface, the surface
1460 * will not appear in repaint list, and so rpi_renderer_repaint_output
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001461 * will remove the DispmanX element. Later, for SHM, also the front
1462 * buffer will be released in the cleanup_list processing.
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001463 */
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001464 if (!buffer)
1465 return;
1466
1467 if (wl_shm_buffer_get(buffer->resource)) {
1468 surface->buffer_type = BUFFER_TYPE_SHM;
1469 buffer->shm_buffer = wl_shm_buffer_get(buffer->resource);
1470 buffer->width = wl_shm_buffer_get_width(buffer->shm_buffer);
1471 buffer->height = wl_shm_buffer_get_height(buffer->shm_buffer);
1472
1473 weston_buffer_reference(&surface->buffer_ref, buffer);
1474 } else {
1475#if ENABLE_EGL
1476 struct rpi_renderer *renderer = to_rpi_renderer(base->compositor);
Tomeu Vizosoa8e5f292013-10-09 11:29:45 +02001477 struct wl_resource *wl_resource = buffer->resource;
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001478
1479 if (!renderer->has_bind_display ||
1480 !renderer->query_buffer(renderer->egl_display,
1481 wl_resource,
1482 EGL_WIDTH, &buffer->width)) {
1483 weston_log("unhandled buffer type!\n");
1484 weston_buffer_reference(&surface->buffer_ref, NULL);
1485 surface->buffer_type = BUFFER_TYPE_NULL;
1486 }
1487
1488 renderer->query_buffer(renderer->egl_display,
1489 wl_resource,
1490 EGL_HEIGHT, &buffer->height);
1491
1492 surface->buffer_type = BUFFER_TYPE_EGL;
1493
Dawid Gajownik74a635b2015-08-06 17:12:19 -03001494 if (surface->egl_back == NULL)
Bryce Harringtonde16d892014-11-20 22:21:57 -08001495 surface->egl_back = zalloc(sizeof *surface->egl_back);
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001496
1497 weston_buffer_reference(&surface->egl_back->buffer_ref, buffer);
1498 surface->egl_back->resource_handle =
1499 vc_dispmanx_get_handle_from_wl_buffer(wl_resource);
1500#else
1501 weston_log("unhandled buffer type!\n");
1502 weston_buffer_reference(&surface->buffer_ref, NULL);
1503 surface->buffer_type = BUFFER_TYPE_NULL;
1504#endif
1505 }
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001506}
1507
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +03001508static void
1509rpir_surface_handle_surface_destroy(struct wl_listener *listener, void *data)
1510{
1511 struct rpir_surface *surface;
1512 struct weston_surface *base = data;
1513
1514 surface = container_of(listener, struct rpir_surface,
1515 surface_destroy_listener);
1516
1517 assert(surface);
1518 assert(surface->surface == base);
1519 if (!surface)
1520 return;
1521
1522 surface->surface = NULL;
1523 base->renderer_state = NULL;
1524
1525 if (wl_list_empty(&surface->views))
1526 rpir_surface_destroy(surface);
1527}
1528
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001529static int
1530rpi_renderer_create_surface(struct weston_surface *base)
1531{
1532 struct rpi_renderer *renderer = to_rpi_renderer(base->compositor);
1533 struct rpir_surface *surface;
1534
1535 assert(base->renderer_state == NULL);
1536
1537 surface = rpir_surface_create(renderer);
1538 if (!surface)
1539 return -1;
1540
1541 surface->surface = base;
1542 base->renderer_state = surface;
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +03001543
1544 surface->surface_destroy_listener.notify =
1545 rpir_surface_handle_surface_destroy;
1546 wl_signal_add(&base->destroy_signal,
1547 &surface->surface_destroy_listener);
1548
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001549 return 0;
1550}
1551
Jason Ekstranda7af7042013-10-12 22:38:11 -05001552static int
1553rpi_renderer_create_view(struct weston_view *base)
1554{
1555 struct rpir_surface *surface = to_rpir_surface(base->surface);
1556 struct rpir_view *view;
1557
1558 assert(base->renderer_state == NULL);
1559
1560 view = rpir_view_create(surface);
1561 if (!view)
1562 return -1;
1563
1564 view->view = base;
1565 base->renderer_state = view;
Tomeu Vizoso96dc9e42013-10-28 10:17:45 +01001566
1567 view->view_destroy_listener.notify =
1568 rpir_view_handle_view_destroy;
1569 wl_signal_add(&base->destroy_signal,
1570 &view->view_destroy_listener);
1571
Jason Ekstranda7af7042013-10-12 22:38:11 -05001572 return 0;
1573}
1574
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001575static void
1576rpi_renderer_surface_set_color(struct weston_surface *base,
1577 float red, float green, float blue, float alpha)
1578{
1579 struct rpir_surface *surface = to_rpir_surface(base);
1580 uint8_t color[4];
1581 VC_RECT_T rect;
1582 int ret;
1583
1584 assert(surface);
1585
1586 ret = rpi_resource_realloc(surface->back, VC_IMAGE_ARGB8888,
1587 1, 1, 4, 1);
1588 if (ret < 0) {
1589 weston_log("Error: %s: rpi_resource_realloc failed.\n",
1590 __func__);
1591 return;
1592 }
1593
1594 color[0] = float2uint8(blue);
1595 color[1] = float2uint8(green);
1596 color[2] = float2uint8(red);
1597 color[3] = float2uint8(alpha);
1598
1599 vc_dispmanx_rect_set(&rect, 0, 0, 1, 1);
1600 ret = vc_dispmanx_resource_write_data(surface->back->handle,
1601 VC_IMAGE_ARGB8888,
1602 4, color, &rect);
1603 if (ret) {
1604 weston_log("Error: %s: resource_write_data failed.\n",
1605 __func__);
1606 return;
1607 }
1608
1609 DBG("%s: resource %p solid color BGRA %u,%u,%u,%u\n", __func__,
1610 surface->back, color[0], color[1], color[2], color[3]);
1611
1612 /*pixman_region32_copy(&surface->prev_damage, damage);*/
1613 surface->need_swap = 1;
1614}
1615
1616static void
Tomeu Vizoso96dc9e42013-10-28 10:17:45 +01001617rpir_view_handle_view_destroy(struct wl_listener *listener, void *data)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001618{
Tomeu Vizoso96dc9e42013-10-28 10:17:45 +01001619 struct rpir_view *view;
1620 struct weston_view *base = data;
1621
1622 view = container_of(listener, struct rpir_view, view_destroy_listener);
Jason Ekstranda7af7042013-10-12 22:38:11 -05001623
1624 assert(view);
1625 assert(view->view == base);
1626 if (!view)
1627 return;
1628
Tomeu Vizoso34dad7d2013-10-25 10:34:37 +02001629 view->view = NULL;
Tomeu Vizoso96dc9e42013-10-28 10:17:45 +01001630 base->renderer_state = NULL;
Tomeu Vizoso34dad7d2013-10-25 10:34:37 +02001631
Tomeu Vizoso96dc9e42013-10-28 10:17:45 +01001632 /* If guaranteed to not be on screen, just destroy it. */
Jason Ekstranda7af7042013-10-12 22:38:11 -05001633 if (wl_list_empty(&view->link))
1634 rpir_view_destroy(view);
1635
1636 /* Otherwise, the view is either on screen and needs
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001637 * to be removed by a repaint update, or it is in the
Jason Ekstranda7af7042013-10-12 22:38:11 -05001638 * view_cleanup_list, and will be destroyed by
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001639 * rpi_renderer_finish_frame().
1640 */
1641}
1642
1643static void
1644rpi_renderer_destroy(struct weston_compositor *compositor)
1645{
1646 struct rpi_renderer *renderer = to_rpi_renderer(compositor);
1647
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001648#if ENABLE_EGL
1649 if (renderer->has_bind_display)
1650 renderer->unbind_display(renderer->egl_display,
1651 compositor->wl_display);
1652#endif
1653
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001654 free(renderer);
1655 compositor->renderer = NULL;
1656}
1657
1658WL_EXPORT int
1659rpi_renderer_create(struct weston_compositor *compositor,
1660 const struct rpi_renderer_parameters *params)
1661{
1662 struct rpi_renderer *renderer;
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001663#if ENABLE_EGL
1664 const char *extensions;
1665 EGLBoolean ret;
1666 EGLint major, minor;
1667#endif
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001668
1669 weston_log("Initializing the DispmanX compositing renderer\n");
1670
Bryce Harringtonde16d892014-11-20 22:21:57 -08001671 renderer = zalloc(sizeof *renderer);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001672 if (renderer == NULL)
1673 return -1;
1674
1675 renderer->single_buffer = params->single_buffer;
Tomeu Vizosoe4f7b922013-12-02 17:18:58 +01001676 renderer->enable_opaque_regions = params->opaque_regions;
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001677
1678 renderer->base.read_pixels = rpi_renderer_read_pixels;
1679 renderer->base.repaint_output = rpi_renderer_repaint_output;
1680 renderer->base.flush_damage = rpi_renderer_flush_damage;
1681 renderer->base.attach = rpi_renderer_attach;
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001682 renderer->base.surface_set_color = rpi_renderer_surface_set_color;
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001683 renderer->base.destroy = rpi_renderer_destroy;
1684
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001685#ifdef ENABLE_EGL
1686 renderer->egl_display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
1687 if (renderer->egl_display == EGL_NO_DISPLAY) {
1688 weston_log("failed to create EGL display\n");
U. Artie Eoffe067b302014-01-17 14:00:18 -08001689 free(renderer);
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001690 return -1;
1691 }
1692
1693 if (!eglInitialize(renderer->egl_display, &major, &minor)) {
1694 weston_log("failed to initialize EGL display\n");
U. Artie Eoffe067b302014-01-17 14:00:18 -08001695 free(renderer);
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001696 return -1;
1697 }
1698
1699 renderer->bind_display =
1700 (void *) eglGetProcAddress("eglBindWaylandDisplayWL");
1701 renderer->unbind_display =
1702 (void *) eglGetProcAddress("eglUnbindWaylandDisplayWL");
1703 renderer->query_buffer =
1704 (void *) eglGetProcAddress("eglQueryWaylandBufferWL");
1705
1706 extensions = (const char *) eglQueryString(renderer->egl_display,
1707 EGL_EXTENSIONS);
1708 if (!extensions) {
1709 weston_log("Retrieving EGL extension string failed.\n");
U. Artie Eoffac9f35a2014-01-17 16:28:15 -08001710 eglTerminate(renderer->egl_display);
U. Artie Eoffe067b302014-01-17 14:00:18 -08001711 free(renderer);
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001712 return -1;
1713 }
1714
1715 if (strstr(extensions, "EGL_WL_bind_wayland_display"))
1716 renderer->has_bind_display = 1;
1717
1718 if (renderer->has_bind_display) {
1719 ret = renderer->bind_display(renderer->egl_display,
1720 compositor->wl_display);
1721 if (!ret)
1722 renderer->has_bind_display = 0;
1723 }
1724#endif
1725
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001726 compositor->renderer = &renderer->base;
1727 compositor->read_format = PIXMAN_a8r8g8b8;
1728 /* WESTON_CAP_ROTATION_ANY not supported */
1729
Tomeu Vizoso03681892013-08-06 20:05:57 +02001730 wl_display_add_shm_format(compositor->wl_display, WL_SHM_FORMAT_RGB565);
1731
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001732 return 0;
1733}
1734
1735WL_EXPORT int
1736rpi_renderer_output_create(struct weston_output *base,
1737 DISPMANX_DISPLAY_HANDLE_T display)
1738{
1739 struct rpir_output *output;
1740
1741 assert(base->renderer_state == NULL);
1742
Bryce Harringtonde16d892014-11-20 22:21:57 -08001743 output = zalloc(sizeof *output);
1744 if (output == NULL)
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001745 return -1;
1746
1747 output->display = display;
1748 output->update = DISPMANX_NO_HANDLE;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001749 wl_list_init(&output->view_list);
1750 wl_list_init(&output->view_cleanup_list);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001751 rpi_resource_init(&output->capture_buffer);
1752 base->renderer_state = output;
1753
1754 return 0;
1755}
1756
1757WL_EXPORT void
1758rpi_renderer_output_destroy(struct weston_output *base)
1759{
1760 struct rpir_output *output = to_rpir_output(base);
Jason Ekstranda7af7042013-10-12 22:38:11 -05001761 struct rpir_view *view;
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001762 DISPMANX_UPDATE_HANDLE_T update;
1763
1764 rpi_resource_release(&output->capture_buffer);
1765 free(output->capture_data);
1766 output->capture_data = NULL;
1767
1768 update = vc_dispmanx_update_start(0);
1769 rpir_output_dmx_remove_all(output, update);
1770 vc_dispmanx_update_submit_sync(update);
1771
Jason Ekstranda7af7042013-10-12 22:38:11 -05001772 while (!wl_list_empty(&output->view_cleanup_list)) {
1773 view = container_of(output->view_cleanup_list.next,
1774 struct rpir_view, link);
1775 rpir_view_destroy(view);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001776 }
1777
1778 free(output);
1779 base->renderer_state = NULL;
1780}
1781
1782WL_EXPORT void
1783rpi_renderer_set_update_handle(struct weston_output *base,
1784 DISPMANX_UPDATE_HANDLE_T handle)
1785{
1786 struct rpir_output *output = to_rpir_output(base);
1787
1788 output->update = handle;
1789}
1790
1791WL_EXPORT void
1792rpi_renderer_finish_frame(struct weston_output *base)
1793{
1794 struct rpir_output *output = to_rpir_output(base);
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001795 struct weston_compositor *compositor = base->compositor;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001796 struct weston_view *wv;
1797 struct rpir_view *view;
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001798
Jason Ekstranda7af7042013-10-12 22:38:11 -05001799 while (!wl_list_empty(&output->view_cleanup_list)) {
1800 view = container_of(output->view_cleanup_list.next,
1801 struct rpir_view, link);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001802
Jason Ekstranda7af7042013-10-12 22:38:11 -05001803 if (view->view) {
1804 /* The weston_view still exists, but is
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001805 * temporarily not visible, and hence its Element
1806 * was removed. The current front buffer contents
1807 * must be preserved.
1808 */
Jason Ekstranda7af7042013-10-12 22:38:11 -05001809 if (!view->surface->visible_views)
1810 rpi_resource_release(view->surface->back);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001811
Jason Ekstranda7af7042013-10-12 22:38:11 -05001812 wl_list_remove(&view->link);
1813 wl_list_init(&view->link);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001814 } else {
Jason Ekstranda7af7042013-10-12 22:38:11 -05001815 rpir_view_destroy(view);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001816 }
1817 }
1818
Jason Ekstranda7af7042013-10-12 22:38:11 -05001819 wl_list_for_each(wv, &compositor->view_list, link) {
1820 view = to_rpir_view(wv);
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001821
Jason Ekstranda7af7042013-10-12 22:38:11 -05001822 if (view->surface->buffer_type != BUFFER_TYPE_EGL)
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001823 continue;
1824
Tomeu Vizoso74987582013-10-25 10:34:38 +02001825 rpir_egl_buffer_destroy(view->surface->egl_old_front);
Jason Ekstranda7af7042013-10-12 22:38:11 -05001826 view->surface->egl_old_front = NULL;
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001827 }
1828
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001829 wl_signal_emit(&base->frame_signal, base);
1830}