blob: 204802edd225956868de5c4f3f38a7cab4003c28 [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;
156 struct weston_matrix matrix;
157
158 /* all Elements currently on screen */
Jason Ekstranda7af7042013-10-12 22:38:11 -0500159 struct wl_list view_list; /* struct rpir_surface::link */
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300160
161 /* Elements just removed, waiting for update completion */
Jason Ekstranda7af7042013-10-12 22:38:11 -0500162 struct wl_list view_cleanup_list; /* struct rpir_surface::link */
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300163
164 struct rpi_resource capture_buffer;
165 uint8_t *capture_data;
166};
167
168struct rpi_renderer {
169 struct weston_renderer base;
170
171 int single_buffer;
Tomeu Vizosoe4f7b922013-12-02 17:18:58 +0100172 int enable_opaque_regions;
Tomeu Vizosob4659eb2013-10-07 11:02:20 +0200173
174#ifdef ENABLE_EGL
175 EGLDisplay egl_display;
176
177 PFNEGLBINDWAYLANDDISPLAYWL bind_display;
178 PFNEGLUNBINDWAYLANDDISPLAYWL unbind_display;
179 PFNEGLQUERYWAYLANDBUFFERWL query_buffer;
180#endif
181 int has_bind_display;
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300182};
183
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300184static int
185rpi_renderer_create_surface(struct weston_surface *base);
186
Tomeu Vizoso96dc9e42013-10-28 10:17:45 +0100187static int
188rpi_renderer_create_view(struct weston_view *base);
189
190static void
191rpir_view_handle_view_destroy(struct wl_listener *listener, void *data);
192
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300193static inline struct rpir_surface *
194to_rpir_surface(struct weston_surface *surface)
195{
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300196 if (!surface->renderer_state)
197 rpi_renderer_create_surface(surface);
198
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300199 return surface->renderer_state;
200}
201
Jason Ekstranda7af7042013-10-12 22:38:11 -0500202static inline struct rpir_view *
203to_rpir_view(struct weston_view *view)
204{
Tomeu Vizoso96dc9e42013-10-28 10:17:45 +0100205 if (!view->renderer_state)
206 rpi_renderer_create_view(view);
207
Jason Ekstranda7af7042013-10-12 22:38:11 -0500208 return view->renderer_state;
209}
210
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300211static inline struct rpir_output *
212to_rpir_output(struct weston_output *output)
213{
214 return output->renderer_state;
215}
216
217static inline struct rpi_renderer *
218to_rpi_renderer(struct weston_compositor *compositor)
219{
220 return container_of(compositor->renderer, struct rpi_renderer, base);
221}
222
223static inline int
224int_max(int a, int b)
225{
226 return a > b ? a : b;
227}
228
229static inline void
230int_swap(int *a, int *b)
231{
232 int tmp = *a;
233 *a = *b;
234 *b = tmp;
235}
236
237static uint8_t
238float2uint8(float f)
239{
240 int v = roundf(f * 255.0f);
241
242 return v < 0 ? 0 : (v > 255 ? 255 : v);
243}
244
245static void
246rpi_resource_init(struct rpi_resource *resource)
247{
248 resource->handle = DISPMANX_NO_HANDLE;
249}
250
251static void
252rpi_resource_release(struct rpi_resource *resource)
253{
254 if (resource->handle == DISPMANX_NO_HANDLE)
255 return;
256
257 vc_dispmanx_resource_delete(resource->handle);
258 DBG("resource %p release\n", resource);
259 resource->handle = DISPMANX_NO_HANDLE;
260}
261
262static int
263rpi_resource_realloc(struct rpi_resource *resource, VC_IMAGE_TYPE_T ifmt,
264 int width, int height, int stride, int buffer_height)
265{
266 uint32_t dummy;
267
268 if (resource->handle != DISPMANX_NO_HANDLE &&
269 resource->width == width &&
270 resource->height == height &&
271 resource->stride == stride &&
272 resource->buffer_height == buffer_height &&
273 resource->ifmt == ifmt)
274 return 0;
275
276 rpi_resource_release(resource);
277
278 /* NOTE: if stride is not a multiple of 16 pixels in bytes,
279 * the vc_image_* functions may break. Dispmanx elements
280 * should be fine, though. Buffer_height probably has similar
281 * constraints, too.
282 */
283 resource->handle =
284 vc_dispmanx_resource_create(ifmt,
285 width | (stride << 16),
286 height | (buffer_height << 16),
287 &dummy);
288 if (resource->handle == DISPMANX_NO_HANDLE)
289 return -1;
290
291 resource->width = width;
292 resource->height = height;
293 resource->stride = stride;
294 resource->buffer_height = buffer_height;
295 resource->ifmt = ifmt;
296 DBG("resource %p alloc\n", resource);
297 return 1;
298}
299
300/* A firmware workaround for broken ALPHA_PREMULT + ALPHA_MIX hardware. */
301#define PREMULT_ALPHA_FLAG (1 << 31)
302
303static VC_IMAGE_TYPE_T
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500304shm_buffer_get_vc_format(struct wl_shm_buffer *buffer)
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300305{
306 switch (wl_shm_buffer_get_format(buffer)) {
307 case WL_SHM_FORMAT_XRGB8888:
308 return VC_IMAGE_XRGB8888;
309 case WL_SHM_FORMAT_ARGB8888:
310 return VC_IMAGE_ARGB8888 | PREMULT_ALPHA_FLAG;
Tomeu Vizoso03681892013-08-06 20:05:57 +0200311 case WL_SHM_FORMAT_RGB565:
312 return VC_IMAGE_RGB565;
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300313 default:
314 /* invalid format */
315 return VC_IMAGE_MIN;
316 }
317}
318
Tomeu Vizosoe4f7b922013-12-02 17:18:58 +0100319#ifndef HAVE_ELEMENT_SET_OPAQUE_RECT
320static uint32_t *
321apply_opaque_region(struct wl_shm_buffer *buffer,
322 pixman_region32_t *opaque_region)
323{
324 uint32_t *src, *dst;
325 int width;
326 int height;
327 int stride;
328 int x, y;
329
330 width = wl_shm_buffer_get_width(buffer);
331 height = wl_shm_buffer_get_height(buffer);
332 stride = wl_shm_buffer_get_stride(buffer);
333 src = wl_shm_buffer_get_data(buffer);
334
335 dst = malloc(height * stride);
336 if (dst == NULL) {
337 weston_log("rpi-renderer error: out of memory\n");
338 return NULL;
339 }
340
341 for (y = 0; y < height; y++) {
342 for (x = 0; x < width; x++) {
343 int i = y * stride / 4 + x;
Derek Foremand5e21872014-11-21 12:31:04 -0600344 if (pixman_region32_contains_point (opaque_region, x, y, NULL)) {
Tomeu Vizosoe4f7b922013-12-02 17:18:58 +0100345 dst[i] = src[i] | 0xff000000;
346 } else {
347 dst[i] = src[i];
348 }
349 }
350 }
351
352 return dst;
353}
354#endif
355
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300356static int
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500357rpi_resource_update(struct rpi_resource *resource, struct weston_buffer *buffer,
Tomeu Vizosoe4f7b922013-12-02 17:18:58 +0100358 pixman_region32_t *region, pixman_region32_t *opaque_region)
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300359{
360 pixman_region32_t write_region;
361 pixman_box32_t *r;
362 VC_RECT_T rect;
363 VC_IMAGE_TYPE_T ifmt;
364 uint32_t *pixels;
365 int width;
366 int height;
367 int stride;
368 int ret;
U. Artie Eoff5e854bc2014-01-17 13:56:41 -0800369 int applied_opaque_region = 0;
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300370#ifdef HAVE_RESOURCE_WRITE_DATA_RECT
371 int n;
372#endif
373
374 if (!buffer)
375 return -1;
376
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500377 ifmt = shm_buffer_get_vc_format(buffer->shm_buffer);
378 width = wl_shm_buffer_get_width(buffer->shm_buffer);
379 height = wl_shm_buffer_get_height(buffer->shm_buffer);
380 stride = wl_shm_buffer_get_stride(buffer->shm_buffer);
381 pixels = wl_shm_buffer_get_data(buffer->shm_buffer);
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300382
Tomeu Vizosoe4f7b922013-12-02 17:18:58 +0100383#ifndef HAVE_ELEMENT_SET_OPAQUE_RECT
384 if (pixman_region32_not_empty(opaque_region) &&
385 wl_shm_buffer_get_format(buffer->shm_buffer) == WL_SHM_FORMAT_ARGB8888 &&
386 resource->enable_opaque_regions) {
387 pixels = apply_opaque_region(buffer->shm_buffer, opaque_region);
388
389 if (!pixels)
390 return -1;
U. Artie Eoff5e854bc2014-01-17 13:56:41 -0800391
392 applied_opaque_region = 1;
Tomeu Vizosoe4f7b922013-12-02 17:18:58 +0100393 }
394#endif
395
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300396 ret = rpi_resource_realloc(resource, ifmt & ~PREMULT_ALPHA_FLAG,
397 width, height, stride, height);
U. Artie Eoff5e854bc2014-01-17 13:56:41 -0800398 if (ret < 0) {
399 if (applied_opaque_region)
400 free(pixels);
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300401 return -1;
U. Artie Eoff5e854bc2014-01-17 13:56:41 -0800402 }
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300403
404 pixman_region32_init_rect(&write_region, 0, 0, width, height);
405 if (ret == 0)
406 pixman_region32_intersect(&write_region,
407 &write_region, region);
408
Neil Robertse5051712013-11-13 15:44:06 +0000409 wl_shm_buffer_begin_access(buffer->shm_buffer);
410
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300411#ifdef HAVE_RESOURCE_WRITE_DATA_RECT
412 /* XXX: Can this do a format conversion, so that scanout does not have to? */
413 r = pixman_region32_rectangles(&write_region, &n);
414 while (n--) {
415 vc_dispmanx_rect_set(&rect, r[n].x1, r[n].y1,
416 r[n].x2 - r[n].x1, r[n].y2 - r[n].y1);
417
418 ret = vc_dispmanx_resource_write_data_rect(resource->handle,
419 ifmt, stride,
420 pixels, &rect,
421 rect.x, rect.y);
422 DBG("%s: %p %ux%u@%u,%u, ret %d\n", __func__, resource,
423 rect.width, rect.height, rect.x, rect.y, ret);
424 if (ret)
425 break;
426 }
427#else
428 /* vc_dispmanx_resource_write_data() ignores ifmt,
429 * rect.x, rect.width, and uses stride only for computing
430 * the size of the transfer as rect.height * stride.
431 * Therefore we can only write rows starting at x=0.
432 * To be able to write more than one scanline at a time,
433 * the resource must have been created with the same stride
434 * as used here, and we must write full scanlines.
435 */
436
437 r = pixman_region32_extents(&write_region);
438 vc_dispmanx_rect_set(&rect, 0, r->y1, width, r->y2 - r->y1);
439 ret = vc_dispmanx_resource_write_data(resource->handle,
440 ifmt, stride, pixels, &rect);
441 DBG("%s: %p %ux%u@%u,%u, ret %d\n", __func__, resource,
442 width, r->y2 - r->y1, 0, r->y1, ret);
443#endif
444
Neil Robertse5051712013-11-13 15:44:06 +0000445 wl_shm_buffer_end_access(buffer->shm_buffer);
446
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300447 pixman_region32_fini(&write_region);
448
U. Artie Eoff5e854bc2014-01-17 13:56:41 -0800449 if (applied_opaque_region)
Tomeu Vizosoe4f7b922013-12-02 17:18:58 +0100450 free(pixels);
Tomeu Vizosoe4f7b922013-12-02 17:18:58 +0100451
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300452 return ret ? -1 : 0;
453}
454
Pekka Paalanend5fbfb22013-11-22 17:30:39 +0200455static inline void
456rpi_buffer_egl_lock(struct weston_buffer *buffer)
457{
458#ifdef ENABLE_EGL
459 vc_dispmanx_set_wl_buffer_in_use(buffer->resource, 1);
460#endif
461}
462
463static inline void
464rpi_buffer_egl_unlock(struct weston_buffer *buffer)
465{
466#ifdef ENABLE_EGL
467 vc_dispmanx_set_wl_buffer_in_use(buffer->resource, 0);
468#endif
469}
470
Tomeu Vizoso74987582013-10-25 10:34:38 +0200471static void
472rpir_egl_buffer_destroy(struct rpir_egl_buffer *egl_buffer)
473{
474 struct weston_buffer *buffer;
475
476 if (egl_buffer == NULL)
477 return;
478
479 buffer = egl_buffer->buffer_ref.buffer;
480 if (buffer == NULL) {
481 /* The client has already destroyed the wl_buffer, the
482 * compositor has the responsibility to delete the resource.
483 */
484 vc_dispmanx_resource_delete(egl_buffer->resource_handle);
485 } else {
Pekka Paalanend5fbfb22013-11-22 17:30:39 +0200486 rpi_buffer_egl_unlock(buffer);
Tomeu Vizoso74987582013-10-25 10:34:38 +0200487 weston_buffer_reference(&egl_buffer->buffer_ref, NULL);
488 }
489
490 free(egl_buffer);
491}
492
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300493static struct rpir_surface *
494rpir_surface_create(struct rpi_renderer *renderer)
495{
496 struct rpir_surface *surface;
497
Bryce Harringtonde16d892014-11-20 22:21:57 -0800498 surface = zalloc(sizeof *surface);
499 if (surface == NULL)
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300500 return NULL;
501
Tomeu Vizoso5c3ea3b2013-10-24 15:38:30 +0200502 wl_list_init(&surface->views);
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300503 surface->single_buffer = renderer->single_buffer;
Tomeu Vizosoe4f7b922013-12-02 17:18:58 +0100504 surface->enable_opaque_regions = renderer->enable_opaque_regions;
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300505 rpi_resource_init(&surface->resources[0]);
506 rpi_resource_init(&surface->resources[1]);
507 surface->front = &surface->resources[0];
508 if (surface->single_buffer)
509 surface->back = &surface->resources[0];
510 else
511 surface->back = &surface->resources[1];
Tomeu Vizosoe4f7b922013-12-02 17:18:58 +0100512
513 surface->front->enable_opaque_regions = renderer->enable_opaque_regions;
514 surface->back->enable_opaque_regions = renderer->enable_opaque_regions;
515
Tomeu Vizosob4659eb2013-10-07 11:02:20 +0200516 surface->buffer_type = BUFFER_TYPE_NULL;
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300517
518 pixman_region32_init(&surface->prev_damage);
519
520 return surface;
521}
522
523static void
524rpir_surface_destroy(struct rpir_surface *surface)
525{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500526 if (surface->visible_views)
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300527 weston_log("ERROR rpi: destroying on-screen element\n");
528
Jason Ekstranda7af7042013-10-12 22:38:11 -0500529 assert(wl_list_empty(&surface->views));
530
531 if (surface->surface)
532 surface->surface->renderer_state = NULL;
533
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300534 pixman_region32_fini(&surface->prev_damage);
535 rpi_resource_release(&surface->resources[0]);
536 rpi_resource_release(&surface->resources[1]);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500537 DBG("rpir_surface %p destroyed (%u)\n", surface, surface->visible_views);
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300538
Tomeu Vizoso74987582013-10-25 10:34:38 +0200539 rpir_egl_buffer_destroy(surface->egl_back);
540 rpir_egl_buffer_destroy(surface->egl_front);
541 rpir_egl_buffer_destroy(surface->egl_old_front);
Tomeu Vizosob4659eb2013-10-07 11:02:20 +0200542
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300543 free(surface);
544}
545
546static int
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500547rpir_surface_damage(struct rpir_surface *surface, struct weston_buffer *buffer,
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300548 pixman_region32_t *damage)
549{
550 pixman_region32_t upload;
551 int ret;
552
553 if (!pixman_region32_not_empty(damage))
554 return 0;
555
556 DBG("rpir_surface %p update resource %p\n", surface, surface->back);
557
558 /* XXX: todo: if no surface->handle, update front buffer directly
559 * to avoid creating a new back buffer */
560 if (surface->single_buffer) {
Tomeu Vizosoe4f7b922013-12-02 17:18:58 +0100561 ret = rpi_resource_update(surface->front, buffer, damage,
562 &surface->surface->opaque);
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300563 } else {
564 pixman_region32_init(&upload);
565 pixman_region32_union(&upload, &surface->prev_damage, damage);
Tomeu Vizosoe4f7b922013-12-02 17:18:58 +0100566 ret = rpi_resource_update(surface->back, buffer, &upload,
567 &surface->surface->opaque);
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300568 pixman_region32_fini(&upload);
569 }
570
571 pixman_region32_copy(&surface->prev_damage, damage);
572 surface->need_swap = 1;
573
574 return ret;
575}
576
Jason Ekstranda7af7042013-10-12 22:38:11 -0500577static struct rpir_view *
578rpir_view_create(struct rpir_surface *surface)
579{
580 struct rpir_view *view;
581
Bryce Harringtonde16d892014-11-20 22:21:57 -0800582 view = zalloc(sizeof *view);
583 if (view == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -0500584 return NULL;
585
586 view->surface = surface;
587 wl_list_insert(&surface->views, &view->surface_link);
588
589 wl_list_init(&view->link);
590 view->handle = DISPMANX_NO_HANDLE;
591
592 return view;
593}
594
595static void
596rpir_view_destroy(struct rpir_view *view)
597{
598 wl_list_remove(&view->link);
599
600 if (view->handle != DISPMANX_NO_HANDLE) {
601 view->surface->visible_views--;
602 weston_log("ERROR rpi: destroying on-screen element\n");
603 }
604
605 if (view->view)
606 view->view->renderer_state = NULL;
607
608 wl_list_remove(&view->surface_link);
609 if (wl_list_empty(&view->surface->views) && view->surface->surface == NULL)
610 rpir_surface_destroy(view->surface);
611
612 DBG("rpir_view %p destroyed (%d)\n", view, view->handle);
613
614 free(view);
615}
616
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300617static void
618matrix_type_str(struct weston_matrix *matrix, char *buf, int len)
619{
620 static const char types[33] = "TSRO";
621 unsigned mask = matrix->type;
622 int i = 0;
623
624 while (mask && i < len - 1) {
625 if (mask & (1u << i))
626 *buf++ = types[i];
627 mask &= ~(1u << i);
628 i++;
629 }
630 *buf = '\0';
631}
632
633static void
634log_print_matrix(struct weston_matrix *matrix)
635{
636 char typestr[6];
637 float *d = matrix->d;
638
639 matrix_type_str(matrix, typestr, sizeof typestr);
640 weston_log_continue("%14.6e %14.6e %14.6e %14.6e\n",
641 d[0], d[4], d[8], d[12]);
642 weston_log_continue("%14.6e %14.6e %14.6e %14.6e\n",
643 d[1], d[5], d[9], d[13]);
644 weston_log_continue("%14.6e %14.6e %14.6e %14.6e\n",
645 d[2], d[6], d[10], d[14]);
646 weston_log_continue("%14.6e %14.6e %14.6e %14.6e type: %s\n",
647 d[3], d[7], d[11], d[15], typestr);
648}
649
650static void
651warn_bad_matrix(struct weston_matrix *total, struct weston_matrix *output,
652 struct weston_matrix *surface)
653{
654 static int n_warn;
655 char typestr[6];
656
657 if (n_warn++ == 10)
658 weston_log("%s: not showing more warnings\n", __func__);
659
660 if (n_warn > 10)
661 return;
662
663 weston_log("%s: warning: total transformation is not renderable:\n",
664 __func__);
665 log_print_matrix(total);
666
667 matrix_type_str(surface, typestr, sizeof typestr);
668 weston_log_continue("surface matrix type: %s\n", typestr);
669 matrix_type_str(output, typestr, sizeof typestr);
670 weston_log_continue("output matrix type: %s\n", typestr);
671}
672
673/*#define SURFACE_TRANSFORM */
674
675static int
Jason Ekstranda7af7042013-10-12 22:38:11 -0500676rpir_view_compute_rects(struct rpir_view *view,
677 VC_RECT_T *src_rect, VC_RECT_T *dst_rect,
678 VC_IMAGE_TRANSFORM_T *flipmask)
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300679{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500680 struct weston_output *output_base = view->view->surface->output;
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300681 struct rpir_output *output = to_rpir_output(output_base);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500682 struct weston_matrix matrix = view->view->transform.matrix;
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300683 VC_IMAGE_TRANSFORM_T flipt = 0;
684 int src_x, src_y;
685 int dst_x, dst_y;
686 int src_width, src_height;
687 int dst_width, dst_height;
688 struct weston_vector p1 = {{ 0.0f, 0.0f, 0.0f, 1.0f }};
689 struct weston_vector p2 = {{ 0.0f, 0.0f, 0.0f, 1.0f }};
690 int t;
691 int over;
692
693 /* XXX: take buffer transform into account */
694
695 /* src is in 16.16, dst is in 32.0 fixed point.
696 * Negative values are not allowed in VC_RECT_T.
697 * Clip size to output boundaries, firmware ignores
698 * huge elements like 8192x8192.
699 */
700
701 src_x = 0 << 16;
702 src_y = 0 << 16;
Tomeu Vizosob4659eb2013-10-07 11:02:20 +0200703
Jason Ekstranda7af7042013-10-12 22:38:11 -0500704 if (view->surface->buffer_type == BUFFER_TYPE_EGL) {
705 struct weston_buffer *buffer =
706 view->surface->egl_front->buffer_ref.buffer;
Tomeu Vizosob4659eb2013-10-07 11:02:20 +0200707
708 src_width = buffer->width << 16;
709 src_height = buffer->height << 16;
710 } else {
Jason Ekstranda7af7042013-10-12 22:38:11 -0500711 src_width = view->surface->front->width << 16;
712 src_height = view->surface->front->height << 16;
Tomeu Vizosob4659eb2013-10-07 11:02:20 +0200713 }
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300714
715 weston_matrix_multiply(&matrix, &output->matrix);
716
717#ifdef SURFACE_TRANSFORM
718 if (matrix.type >= WESTON_MATRIX_TRANSFORM_OTHER) {
719#else
720 if (matrix.type >= WESTON_MATRIX_TRANSFORM_ROTATE) {
721#endif
722 warn_bad_matrix(&matrix, &output->matrix,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500723 &view->view->transform.matrix);
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300724 } else {
725 if (matrix.type & WESTON_MATRIX_TRANSFORM_ROTATE) {
726 if (fabsf(matrix.d[0]) < 1e-4f &&
727 fabsf(matrix.d[5]) < 1e-4f) {
728 flipt |= TRANSFORM_TRANSPOSE;
729 } else if (fabsf(matrix.d[1]) < 1e-4 &&
730 fabsf(matrix.d[4]) < 1e-4) {
731 /* no transpose */
732 } else {
733 warn_bad_matrix(&matrix, &output->matrix,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500734 &view->view->transform.matrix);
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300735 }
736 }
737 }
738
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600739 p2.f[0] = view->view->surface->width;
740 p2.f[1] = view->view->surface->height;
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300741
742 /* transform top-left and bot-right corner into screen coordinates */
743 weston_matrix_transform(&matrix, &p1);
744 weston_matrix_transform(&matrix, &p2);
745
746 /* Compute the destination rectangle on screen, converting
747 * negative dimensions to flips.
748 */
749
750 dst_width = round(p2.f[0] - p1.f[0]);
751 if (dst_width < 0) {
752 dst_x = round(p2.f[0]);
753 dst_width = -dst_width;
754
755 if (!(flipt & TRANSFORM_TRANSPOSE))
756 flipt |= TRANSFORM_HFLIP;
757 else
758 flipt |= TRANSFORM_VFLIP;
759 } else {
760 dst_x = round(p1.f[0]);
761 }
762
763 dst_height = round(p2.f[1] - p1.f[1]);
764 if (dst_height < 0) {
765 dst_y = round(p2.f[1]);
766 dst_height = -dst_height;
767
768 if (!(flipt & TRANSFORM_TRANSPOSE))
769 flipt |= TRANSFORM_VFLIP;
770 else
771 flipt |= TRANSFORM_HFLIP;
772 } else {
773 dst_y = round(p1.f[1]);
774 }
775
776 if (dst_width == 0 || dst_height == 0) {
777 DBG("ignored, zero surface area before clipping\n");
778 return -1;
779 }
780
781#ifdef SURFACE_TRANSFORM
782 /* Dispmanx works as if you flipped the whole screen, when
783 * you flip an element. But, we want to flip an element in place.
784 * XXX: fixme
785 */
786 if (flipt & TRANSFORM_HFLIP)
787 dst_x = output_base->width - dst_x;
788 if (flipt & TRANSFORM_VFLIP)
789 dst_y = output_base->height - dst_y;
790 if (flipt & TRANSFORM_TRANSPOSE) {
791 int_swap(&dst_x, &dst_y);
792 int_swap(&dst_width, &dst_height);
793 }
794#else
795 switch (output_base->transform) {
796 case WL_OUTPUT_TRANSFORM_FLIPPED:
797 flipt = TRANSFORM_HFLIP;
798 break;
799 case WL_OUTPUT_TRANSFORM_NORMAL:
800 flipt = 0;
801 break;
802
803 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
804 flipt = TRANSFORM_HFLIP | TRANSFORM_VFLIP | TRANSFORM_TRANSPOSE;
805 break;
806 case WL_OUTPUT_TRANSFORM_90:
807 flipt = TRANSFORM_VFLIP | TRANSFORM_TRANSPOSE;
808 break;
809 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
810 flipt = TRANSFORM_VFLIP;
811 break;
812 case WL_OUTPUT_TRANSFORM_180:
813 flipt = TRANSFORM_HFLIP | TRANSFORM_VFLIP;
814 break;
815
816 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
817 flipt = TRANSFORM_TRANSPOSE;
818 break;
819 case WL_OUTPUT_TRANSFORM_270:
820 flipt = TRANSFORM_HFLIP | TRANSFORM_TRANSPOSE;
821 break;
822 default:
823 break;
824 }
825#endif
826
827 /* clip destination rectangle to screen dimensions */
828
829 if (dst_x < 0) {
830 t = (int64_t)dst_x * src_width / dst_width;
831 src_width += t;
832 dst_width += dst_x;
833 src_x -= t;
834 dst_x = 0;
835 }
836
837 if (dst_y < 0) {
838 t = (int64_t)dst_y * src_height / dst_height;
839 src_height += t;
840 dst_height += dst_y;
841 src_y -= t;
842 dst_y = 0;
843 }
844
845 over = dst_x + dst_width - output_base->width;
846 if (over > 0) {
847 t = (int64_t)over * src_width / dst_width;
848 src_width -= t;
849 dst_width -= over;
850 }
851
852 over = dst_y + dst_height - output_base->height;
853 if (over > 0) {
854 t = (int64_t)over * src_height / dst_height;
855 src_height -= t;
856 dst_height -= over;
857 }
858
859 src_width = int_max(src_width, 0);
860 src_height = int_max(src_height, 0);
861
Jason Ekstranda7af7042013-10-12 22:38:11 -0500862 DBG("rpir_view %p %dx%d: p1 %f, %f; p2 %f, %f\n", view,
Pekka Paalanen2d0f8b72014-05-09 15:08:06 +0300863 view->view->surface->width,
864 view->view->surface->height,
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300865 p1.f[0], p1.f[1], p2.f[0], p2.f[1]);
866 DBG("src rect %d;%d, %d;%d, %d;%dx%d;%d\n",
867 src_x >> 16, src_x & 0xffff,
868 src_y >> 16, src_y & 0xffff,
869 src_width >> 16, src_width & 0xffff,
870 src_height >> 16, src_height & 0xffff);
871 DBG("dest rect %d, %d, %dx%d%s%s%s\n",
872 dst_x, dst_y, dst_width, dst_height,
873 (flipt & TRANSFORM_HFLIP) ? " hflip" : "",
874 (flipt & TRANSFORM_VFLIP) ? " vflip" : "",
875 (flipt & TRANSFORM_TRANSPOSE) ? " transp" : "");
876
877 assert(src_x >= 0);
878 assert(src_y >= 0);
879 assert(dst_x >= 0);
880 assert(dst_y >= 0);
881
882 if (dst_width < 1 || dst_height < 1) {
883 DBG("ignored, zero surface area after clipping\n");
884 return -1;
885 }
886
Tomeu Vizosob4659eb2013-10-07 11:02:20 +0200887 /* EGL buffers will be upside-down related to what DispmanX expects */
Jason Ekstranda7af7042013-10-12 22:38:11 -0500888 if (view->surface->buffer_type == BUFFER_TYPE_EGL)
Tomeu Vizosob4659eb2013-10-07 11:02:20 +0200889 flipt ^= TRANSFORM_VFLIP;
890
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300891 vc_dispmanx_rect_set(src_rect, src_x, src_y, src_width, src_height);
892 vc_dispmanx_rect_set(dst_rect, dst_x, dst_y, dst_width, dst_height);
893 *flipmask = flipt;
894
895 return 0;
896}
897
898static DISPMANX_TRANSFORM_T
899vc_image2dispmanx_transform(VC_IMAGE_TRANSFORM_T t)
900{
901 /* XXX: uhh, are these right? */
902 switch (t) {
903 case VC_IMAGE_ROT0:
904 return DISPMANX_NO_ROTATE;
905 case VC_IMAGE_MIRROR_ROT0:
906 return DISPMANX_FLIP_HRIZ;
907 case VC_IMAGE_MIRROR_ROT180:
908 return DISPMANX_FLIP_VERT;
909 case VC_IMAGE_ROT180:
910 return DISPMANX_ROTATE_180;
911 case VC_IMAGE_MIRROR_ROT90:
912 return DISPMANX_ROTATE_90 | DISPMANX_FLIP_HRIZ;
913 case VC_IMAGE_ROT270:
914 return DISPMANX_ROTATE_270;
915 case VC_IMAGE_ROT90:
916 return DISPMANX_ROTATE_90;
917 case VC_IMAGE_MIRROR_ROT270:
918 return DISPMANX_ROTATE_270 | DISPMANX_FLIP_VERT;
919 default:
920 assert(0 && "bad VC_IMAGE_TRANSFORM_T");
921 return DISPMANX_NO_ROTATE;
922 }
923}
924
Tomeu Vizosob4659eb2013-10-07 11:02:20 +0200925static DISPMANX_RESOURCE_HANDLE_T
926rpir_surface_get_resource(struct rpir_surface *surface)
927{
928 switch (surface->buffer_type) {
929 case BUFFER_TYPE_SHM:
930 case BUFFER_TYPE_NULL:
931 return surface->front->handle;
932 case BUFFER_TYPE_EGL:
933 if (surface->egl_front != NULL)
934 return surface->egl_front->resource_handle;
935 default:
936 return DISPMANX_NO_HANDLE;
937 }
938}
939
Tomeu Vizosoe4f7b922013-12-02 17:18:58 +0100940#ifdef HAVE_ELEMENT_SET_OPAQUE_RECT
941static int
942rpir_surface_set_opaque_rect(struct rpir_surface *surface,
943 DISPMANX_UPDATE_HANDLE_T update)
944{
945 int ret;
946
947 if (pixman_region32_not_empty(&surface->surface->opaque) &&
948 surface->opaque_regions) {
949 pixman_box32_t *box;
950 VC_RECT_T opaque_rect;
951
952 box = pixman_region32_extents(&surface->surface->opaque);
953 opaque_rect.x = box->x1;
954 opaque_rect.y = box->y1;
955 opaque_rect.width = box->x2 - box->x1;
956 opaque_rect.height = box->y2 - box->y1;
957
958 ret = vc_dispmanx_element_set_opaque_rect(update,
959 surface->handle,
960 &opaque_rect);
961 if (ret) {
962 weston_log("vc_dispmanx_element_set_opaque_rect failed\n");
963 return -1;
964 }
965 }
966
967 return 0;
968}
969#endif
970
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300971static int
Jason Ekstranda7af7042013-10-12 22:38:11 -0500972rpir_view_dmx_add(struct rpir_view *view, struct rpir_output *output,
973 DISPMANX_UPDATE_HANDLE_T update, int layer)
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300974{
975 /* Do not use DISPMANX_FLAGS_ALPHA_PREMULT here.
976 * If you define PREMULT and ALPHA_MIX, the hardware will not
977 * multiply the source color with the element alpha, leading to
978 * bad colors. Instead, we define PREMULT during pixel data upload.
979 */
980 VC_DISPMANX_ALPHA_T alphasetup = {
981 DISPMANX_FLAGS_ALPHA_FROM_SOURCE |
982 DISPMANX_FLAGS_ALPHA_MIX,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500983 float2uint8(view->view->alpha), /* opacity 0-255 */
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300984 0 /* mask resource handle */
985 };
986 VC_RECT_T dst_rect;
987 VC_RECT_T src_rect;
988 VC_IMAGE_TRANSFORM_T flipmask;
989 int ret;
Tomeu Vizosob4659eb2013-10-07 11:02:20 +0200990 DISPMANX_RESOURCE_HANDLE_T resource_handle;
991
Jason Ekstranda7af7042013-10-12 22:38:11 -0500992 resource_handle = rpir_surface_get_resource(view->surface);
Tomeu Vizosob4659eb2013-10-07 11:02:20 +0200993 if (resource_handle == DISPMANX_NO_HANDLE) {
994 weston_log("%s: no buffer yet, aborting\n", __func__);
995 return 0;
996 }
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300997
Jason Ekstranda7af7042013-10-12 22:38:11 -0500998 ret = rpir_view_compute_rects(view, &src_rect, &dst_rect, &flipmask);
Pekka Paalanend7265bc2013-05-22 18:03:06 +0300999 if (ret < 0)
1000 return 0;
1001
Jason Ekstranda7af7042013-10-12 22:38:11 -05001002 view->handle = vc_dispmanx_element_add(
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001003 update,
1004 output->display,
1005 layer,
1006 &dst_rect,
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001007 resource_handle,
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001008 &src_rect,
1009 DISPMANX_PROTECTION_NONE,
1010 &alphasetup,
1011 NULL /* clamp */,
1012 vc_image2dispmanx_transform(flipmask));
Jason Ekstranda7af7042013-10-12 22:38:11 -05001013 DBG("rpir_surface %p add %u, alpha %f resource %d\n", view,
1014 view->handle, view->view->alpha, resource_handle);
1015
1016 if (view->handle == DISPMANX_NO_HANDLE)
1017 return -1;
1018
Tomeu Vizosoe4f7b922013-12-02 17:18:58 +01001019#ifdef HAVE_ELEMENT_SET_OPAQUE_RECT
1020 ret = rpir_surface_set_opaque_rect(surface, update);
1021 if (ret < 0)
1022 return -1;
1023#endif
1024
Jason Ekstranda7af7042013-10-12 22:38:11 -05001025 view->surface->visible_views++;
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001026
1027 return 1;
1028}
1029
1030static void
Jason Ekstranda7af7042013-10-12 22:38:11 -05001031rpir_view_dmx_swap(struct rpir_view *view,
1032 DISPMANX_UPDATE_HANDLE_T update)
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001033{
1034 VC_RECT_T rect;
1035 pixman_box32_t *r;
1036
1037 /* XXX: skip, iff resource was not reallocated, and single-buffering */
Jason Ekstranda7af7042013-10-12 22:38:11 -05001038 vc_dispmanx_element_change_source(update, view->handle,
1039 view->surface->front->handle);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001040
1041 /* This is current damage now, after rpir_surface_damage() */
Jason Ekstranda7af7042013-10-12 22:38:11 -05001042 r = pixman_region32_extents(&view->surface->prev_damage);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001043
1044 vc_dispmanx_rect_set(&rect, r->x1, r->y1,
1045 r->x2 - r->x1, r->y2 - r->y1);
Jason Ekstranda7af7042013-10-12 22:38:11 -05001046 vc_dispmanx_element_modified(update, view->handle, &rect);
1047 DBG("rpir_view %p swap\n", view);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001048}
1049
1050static int
Jason Ekstranda7af7042013-10-12 22:38:11 -05001051rpir_view_dmx_move(struct rpir_view *view,
1052 DISPMANX_UPDATE_HANDLE_T update, int layer)
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001053{
Jason Ekstranda7af7042013-10-12 22:38:11 -05001054 uint8_t alpha = float2uint8(view->view->alpha);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001055 VC_RECT_T dst_rect;
1056 VC_RECT_T src_rect;
1057 VC_IMAGE_TRANSFORM_T flipmask;
1058 int ret;
1059
1060 /* XXX: return early, if all attributes stay the same */
1061
Jason Ekstranda7af7042013-10-12 22:38:11 -05001062 if (view->surface->buffer_type == BUFFER_TYPE_EGL) {
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001063 DISPMANX_RESOURCE_HANDLE_T resource_handle;
1064
Jason Ekstranda7af7042013-10-12 22:38:11 -05001065 resource_handle = rpir_surface_get_resource(view->surface);
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001066 if (resource_handle == DISPMANX_NO_HANDLE) {
1067 weston_log("%s: no buffer yet, aborting\n", __func__);
1068 return 0;
1069 }
1070
1071 vc_dispmanx_element_change_source(update,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001072 view->handle,
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001073 resource_handle);
1074 }
1075
Jason Ekstranda7af7042013-10-12 22:38:11 -05001076 ret = rpir_view_compute_rects(view, &src_rect, &dst_rect, &flipmask);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001077 if (ret < 0)
1078 return 0;
1079
1080 ret = vc_dispmanx_element_change_attributes(
1081 update,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001082 view->handle,
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001083 ELEMENT_CHANGE_LAYER |
1084 ELEMENT_CHANGE_OPACITY |
1085 ELEMENT_CHANGE_TRANSFORM |
1086 ELEMENT_CHANGE_DEST_RECT |
1087 ELEMENT_CHANGE_SRC_RECT,
1088 layer,
1089 alpha,
1090 &dst_rect,
1091 &src_rect,
1092 DISPMANX_NO_HANDLE,
1093 /* This really is DISPMANX_TRANSFORM_T, no matter
1094 * what the header says. */
1095 vc_image2dispmanx_transform(flipmask));
Jason Ekstranda7af7042013-10-12 22:38:11 -05001096 DBG("rpir_view %p move\n", view);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001097
1098 if (ret)
1099 return -1;
1100
Tomeu Vizosoe4f7b922013-12-02 17:18:58 +01001101#ifdef HAVE_ELEMENT_SET_OPAQUE_RECT
1102 ret = rpir_surface_set_opaque_rect(surface, update);
1103 if (ret < 0)
1104 return -1;
1105#endif
1106
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001107 return 1;
1108}
1109
1110static void
Jason Ekstranda7af7042013-10-12 22:38:11 -05001111rpir_view_dmx_remove(struct rpir_view *view,
1112 DISPMANX_UPDATE_HANDLE_T update)
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001113{
Jason Ekstranda7af7042013-10-12 22:38:11 -05001114 if (view->handle == DISPMANX_NO_HANDLE)
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001115 return;
1116
Jason Ekstranda7af7042013-10-12 22:38:11 -05001117 vc_dispmanx_element_remove(update, view->handle);
1118 DBG("rpir_view %p remove %u\n", view, view->handle);
1119 view->handle = DISPMANX_NO_HANDLE;
1120 view->surface->visible_views--;
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001121}
1122
1123static void
1124rpir_surface_swap_pointers(struct rpir_surface *surface)
1125{
1126 struct rpi_resource *tmp;
1127
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001128 if (surface->buffer_type == BUFFER_TYPE_EGL) {
1129 if (surface->egl_back != NULL) {
1130 assert(surface->egl_old_front == NULL);
1131 surface->egl_old_front = surface->egl_front;
1132 surface->egl_front = surface->egl_back;
1133 surface->egl_back = NULL;
Tomeu Vizoso15767812013-10-24 15:38:31 +02001134 DBG("new front %d\n", surface->egl_front->resource_handle);
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001135 }
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001136 } else {
Jason Ekstranda7af7042013-10-12 22:38:11 -05001137 tmp = surface->front;
1138 surface->front = surface->back;
1139 surface->back = tmp;
Tomeu Vizoso15767812013-10-24 15:38:31 +02001140 DBG("new back %p, new front %p\n", surface->back, surface->front);
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001141 }
Jason Ekstranda7af7042013-10-12 22:38:11 -05001142}
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001143
Jason Ekstranda7af7042013-10-12 22:38:11 -05001144static int
1145is_view_not_visible(struct weston_view *view)
1146{
1147 /* Return true, if surface is guaranteed to be totally obscured. */
1148 int ret;
1149 pixman_region32_t unocc;
1150
1151 pixman_region32_init(&unocc);
1152 pixman_region32_subtract(&unocc, &view->transform.boundingbox,
1153 &view->clip);
1154 ret = !pixman_region32_not_empty(&unocc);
1155 pixman_region32_fini(&unocc);
1156
1157 return ret;
1158}
1159
1160static void
1161rpir_view_update(struct rpir_view *view, struct rpir_output *output,
1162 DISPMANX_UPDATE_HANDLE_T update, int layer)
1163{
1164 int ret;
1165 int obscured;
1166
Jason Ekstranda7af7042013-10-12 22:38:11 -05001167 obscured = is_view_not_visible(view->view);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001168 if (obscured) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05001169 DBG("rpir_view %p totally obscured.\n", view);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001170
Jason Ekstranda7af7042013-10-12 22:38:11 -05001171 wl_list_remove(&view->link);
1172 if (view->handle == DISPMANX_NO_HANDLE) {
1173 wl_list_init(&view->link);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001174 } else {
Jason Ekstranda7af7042013-10-12 22:38:11 -05001175 rpir_view_dmx_remove(view, update);
1176 wl_list_insert(&output->view_cleanup_list,
1177 &view->link);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001178 }
1179
1180 goto out;
1181 }
1182
Jason Ekstranda7af7042013-10-12 22:38:11 -05001183 if (view->handle == DISPMANX_NO_HANDLE) {
1184 ret = rpir_view_dmx_add(view, output, update, layer);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001185 if (ret == 0) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05001186 wl_list_remove(&view->link);
1187 wl_list_init(&view->link);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001188 } else if (ret < 0) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05001189 weston_log("ERROR rpir_view_dmx_add() failed.\n");
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001190 }
1191 } else {
Jason Ekstranda7af7042013-10-12 22:38:11 -05001192 if (view->surface->need_swap)
1193 rpir_view_dmx_swap(view, update);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001194
Jason Ekstranda7af7042013-10-12 22:38:11 -05001195 ret = rpir_view_dmx_move(view, update, layer);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001196 if (ret == 0) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05001197 rpir_view_dmx_remove(view, update);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001198
Jason Ekstranda7af7042013-10-12 22:38:11 -05001199 wl_list_remove(&view->link);
1200 wl_list_insert(&output->view_cleanup_list,
1201 &view->link);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001202 } else if (ret < 0) {
Jason Ekstranda7af7042013-10-12 22:38:11 -05001203 weston_log("ERROR rpir_view_dmx_move() failed.\n");
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001204 }
1205 }
1206
1207out:
Jason Ekstranda7af7042013-10-12 22:38:11 -05001208 view->layer = layer;
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001209}
1210
1211static int
1212rpi_renderer_read_pixels(struct weston_output *base,
1213 pixman_format_code_t format, void *pixels,
1214 uint32_t x, uint32_t y,
1215 uint32_t width, uint32_t height)
1216{
1217 struct rpir_output *output = to_rpir_output(base);
1218 struct rpi_resource *buffer = &output->capture_buffer;
1219 VC_RECT_T rect;
1220 uint32_t fb_width, fb_height;
1221 uint32_t dst_pitch;
1222 uint32_t i;
1223 int ret;
1224
Hardeningff39efa2013-09-18 23:56:35 +02001225 fb_width = base->current_mode->width;
1226 fb_height = base->current_mode->height;
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001227
1228 DBG("%s(%u, %u, %u, %u), resource %p\n", __func__,
1229 x, y, width, height, buffer);
1230
1231 if (format != PIXMAN_a8r8g8b8) {
1232 weston_log("rpi-renderer error: bad read_format\n");
1233 return -1;
1234 }
1235
1236 dst_pitch = fb_width * 4;
1237
1238 if (buffer->handle == DISPMANX_NO_HANDLE) {
1239 free(output->capture_data);
1240 output->capture_data = NULL;
1241
1242 ret = rpi_resource_realloc(buffer, VC_IMAGE_ARGB8888,
1243 fb_width, fb_height,
1244 dst_pitch, fb_height);
1245 if (ret < 0) {
1246 weston_log("rpi-renderer error: "
1247 "allocating read buffer failed\n");
1248 return -1;
1249 }
1250
1251 ret = vc_dispmanx_snapshot(output->display, buffer->handle,
1252 VC_IMAGE_ROT0);
1253 if (ret) {
1254 weston_log("rpi-renderer error: "
1255 "vc_dispmanx_snapshot returned %d\n", ret);
1256 return -1;
1257 }
1258 DBG("%s: snapshot done.\n", __func__);
1259 }
1260
1261 /*
1262 * If vc_dispmanx_resource_read_data was able to read sub-rectangles,
1263 * we could read directly into 'pixels'. But it cannot, it does not
1264 * use rect.x or rect.width, and does this:
1265 * host_start = (uint8_t *)dst_address + (dst_pitch * p_rect->y);
1266 * In other words, it is only good for reading the full buffer in
1267 * one go.
1268 */
1269 vc_dispmanx_rect_set(&rect, 0, 0, fb_width, fb_height);
1270
1271 if (x == 0 && y == 0 && width == fb_width && height == fb_height) {
1272 ret = vc_dispmanx_resource_read_data(buffer->handle, &rect,
1273 pixels, dst_pitch);
1274 if (ret) {
1275 weston_log("rpi-renderer error: "
1276 "resource_read_data returned %d\n", ret);
1277 return -1;
1278 }
1279 DBG("%s: full frame done.\n", __func__);
1280 return 0;
1281 }
1282
1283 if (!output->capture_data) {
1284 output->capture_data = malloc(fb_height * dst_pitch);
1285 if (!output->capture_data) {
1286 weston_log("rpi-renderer error: "
1287 "out of memory\n");
1288 return -1;
1289 }
1290
1291 ret = vc_dispmanx_resource_read_data(buffer->handle, &rect,
1292 output->capture_data,
1293 dst_pitch);
1294 if (ret) {
1295 weston_log("rpi-renderer error: "
1296 "resource_read_data returned %d\n", ret);
1297 return -1;
1298 }
1299 }
1300
1301 for (i = 0; i < height; i++) {
1302 uint8_t *src = output->capture_data +
1303 (y + i) * dst_pitch + x * 4;
1304 uint8_t *dst = (uint8_t *)pixels + i * width * 4;
1305 memcpy(dst, src, width * 4);
1306 }
1307
1308 return 0;
1309}
1310
1311static void
1312rpir_output_dmx_remove_all(struct rpir_output *output,
1313 DISPMANX_UPDATE_HANDLE_T update)
1314{
Jason Ekstranda7af7042013-10-12 22:38:11 -05001315 struct rpir_view *view;
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001316
Jason Ekstranda7af7042013-10-12 22:38:11 -05001317 while (!wl_list_empty(&output->view_list)) {
1318 view = container_of(output->view_list.next,
1319 struct rpir_view, link);
1320 rpir_view_dmx_remove(view, update);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001321
Jason Ekstranda7af7042013-10-12 22:38:11 -05001322 wl_list_remove(&view->link);
1323 wl_list_insert(&output->view_cleanup_list, &view->link);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001324 }
1325}
1326
1327static void
1328output_compute_matrix(struct weston_output *base)
1329{
1330 struct rpir_output *output = to_rpir_output(base);
1331 struct weston_matrix *matrix = &output->matrix;
Pekka Paalanenc143df12015-03-10 12:52:14 +02001332#ifdef SURFACE_TRANSFORM
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001333 const float half_w = 0.5f * base->width;
1334 const float half_h = 0.5f * base->height;
Pekka Paalanenc143df12015-03-10 12:52:14 +02001335#endif
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001336 float mag;
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001337
1338 weston_matrix_init(matrix);
1339 weston_matrix_translate(matrix, -base->x, -base->y, 0.0f);
1340
1341#ifdef SURFACE_TRANSFORM
1342 weston_matrix_translate(matrix, -half_w, -half_h, 0.0f);
1343 switch (base->transform) {
1344 case WL_OUTPUT_TRANSFORM_FLIPPED:
1345 weston_matrix_scale(matrix, -1.0f, 1.0f, 1.0f);
1346 case WL_OUTPUT_TRANSFORM_NORMAL:
1347 /* weston_matrix_rotate_xy(matrix, 1.0f, 0.0f); no-op */
1348 weston_matrix_translate(matrix, half_w, half_h, 0.0f);
1349 break;
1350
1351 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
1352 weston_matrix_scale(matrix, -1.0f, 1.0f, 1.0f);
1353 case WL_OUTPUT_TRANSFORM_90:
1354 weston_matrix_rotate_xy(matrix, 0.0f, 1.0f);
1355 weston_matrix_translate(matrix, half_h, half_w, 0.0f);
1356 break;
1357
1358 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
1359 weston_matrix_scale(matrix, -1.0f, 1.0f, 1.0f);
1360 case WL_OUTPUT_TRANSFORM_180:
1361 weston_matrix_rotate_xy(matrix, -1.0f, 0.0f);
1362 weston_matrix_translate(matrix, half_w, half_h, 0.0f);
1363 break;
1364
1365 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
1366 weston_matrix_scale(matrix, -1.0f, 1.0f, 1.0f);
1367 case WL_OUTPUT_TRANSFORM_270:
1368 weston_matrix_rotate_xy(matrix, 0.0f, -1.0f);
1369 weston_matrix_translate(matrix, half_h, half_w, 0.0f);
1370 break;
1371
1372 default:
1373 break;
1374 }
1375#endif
1376
1377 if (base->zoom.active) {
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001378 mag = 1.0f / (1.0f - base->zoom.spring_z.current);
Pekka Paalanenc143df12015-03-10 12:52:14 +02001379 weston_matrix_translate(matrix, base->zoom.trans_x,
1380 base->zoom.trans_y, 0.0f);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001381 weston_matrix_scale(matrix, mag, mag, 1.0f);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001382 }
1383}
1384
1385/* Note: this won't work right for multiple outputs. A DispmanX Element
1386 * is tied to one DispmanX Display, i.e. output.
1387 */
1388static void
1389rpi_renderer_repaint_output(struct weston_output *base,
1390 pixman_region32_t *output_damage)
1391{
1392 struct weston_compositor *compositor = base->compositor;
1393 struct rpir_output *output = to_rpir_output(base);
Jason Ekstranda7af7042013-10-12 22:38:11 -05001394 struct weston_view *wv;
1395 struct rpir_view *view;
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001396 struct wl_list done_list;
1397 int layer = 1;
1398
1399 assert(output->update != DISPMANX_NO_HANDLE);
1400
1401 output_compute_matrix(base);
1402
1403 rpi_resource_release(&output->capture_buffer);
1404 free(output->capture_data);
1405 output->capture_data = NULL;
1406
Jason Ekstranda7af7042013-10-12 22:38:11 -05001407 /* Swap resources on surfaces as needed */
1408 wl_list_for_each_reverse(wv, &compositor->view_list, link)
1409 wv->surface->touched = 0;
1410
1411 wl_list_for_each_reverse(wv, &compositor->view_list, link) {
1412 view = to_rpir_view(wv);
1413
1414 if (!wv->surface->touched) {
1415 wv->surface->touched = 1;
1416
Tomeu Vizoso44247742013-10-24 15:38:32 +02001417 if (view->surface->buffer_type == BUFFER_TYPE_EGL ||
1418 view->surface->need_swap)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001419 rpir_surface_swap_pointers(view->surface);
1420 }
1421
Tomeu Vizoso74987582013-10-25 10:34:38 +02001422 if (view->surface->buffer_type == BUFFER_TYPE_EGL) {
1423 struct weston_buffer *buffer;
1424 buffer = view->surface->egl_front->buffer_ref.buffer;
1425 if (buffer != NULL) {
Pekka Paalanend5fbfb22013-11-22 17:30:39 +02001426 rpi_buffer_egl_lock(buffer);
Jason Ekstranda7af7042013-10-12 22:38:11 -05001427 } else {
Tomeu Vizoso74987582013-10-25 10:34:38 +02001428 weston_log("warning: client destroyed current front buffer\n");
1429
1430 wl_list_remove(&view->link);
1431 if (view->handle == DISPMANX_NO_HANDLE) {
1432 wl_list_init(&view->link);
1433 } else {
1434 rpir_view_dmx_remove(view, output->update);
1435 wl_list_insert(&output->view_cleanup_list,
1436 &view->link);
1437 }
Jason Ekstranda7af7042013-10-12 22:38:11 -05001438 }
1439 }
1440 }
1441
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001442 /* update all renderable surfaces */
1443 wl_list_init(&done_list);
Jason Ekstranda7af7042013-10-12 22:38:11 -05001444 wl_list_for_each_reverse(wv, &compositor->view_list, link) {
1445 if (wv->plane != &compositor->primary_plane)
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001446 continue;
1447
Jason Ekstranda7af7042013-10-12 22:38:11 -05001448 view = to_rpir_view(wv);
1449 assert(!wl_list_empty(&view->link) ||
1450 view->handle == DISPMANX_NO_HANDLE);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001451
Jason Ekstranda7af7042013-10-12 22:38:11 -05001452 wl_list_remove(&view->link);
1453 wl_list_insert(&done_list, &view->link);
1454 rpir_view_update(view, output, output->update, layer++);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001455 }
1456
Jason Ekstranda7af7042013-10-12 22:38:11 -05001457 /* Mark all surfaces as swapped */
1458 wl_list_for_each_reverse(wv, &compositor->view_list, link)
1459 to_rpir_surface(wv->surface)->need_swap = 0;
1460
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001461 /* Remove all surfaces that are still on screen, but were
1462 * not rendered this time.
1463 */
1464 rpir_output_dmx_remove_all(output, output->update);
1465
Jason Ekstranda7af7042013-10-12 22:38:11 -05001466 wl_list_insert_list(&output->view_list, &done_list);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001467 output->update = DISPMANX_NO_HANDLE;
1468
1469 /* The frame_signal is emitted in rpi_renderer_finish_frame(),
1470 * so that the firmware can capture the up-to-date contents.
1471 */
1472}
1473
1474static void
1475rpi_renderer_flush_damage(struct weston_surface *base)
1476{
1477 /* Called for every surface just before repainting it, if
1478 * having an shm buffer.
1479 */
1480 struct rpir_surface *surface = to_rpir_surface(base);
Jason Ekstrand6bd62942013-06-20 20:38:23 -05001481 struct weston_buffer *buffer = surface->buffer_ref.buffer;
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001482 int ret;
1483
1484 assert(buffer);
Jason Ekstrand6bd62942013-06-20 20:38:23 -05001485 assert(wl_shm_buffer_get(buffer->resource));
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001486
1487 ret = rpir_surface_damage(surface, buffer, &base->damage);
1488 if (ret)
1489 weston_log("%s error: updating Dispmanx resource failed.\n",
1490 __func__);
1491
1492 weston_buffer_reference(&surface->buffer_ref, NULL);
1493}
1494
1495static void
Jason Ekstrand6bd62942013-06-20 20:38:23 -05001496rpi_renderer_attach(struct weston_surface *base, struct weston_buffer *buffer)
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001497{
1498 /* Called every time a client commits an attach. */
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001499 struct rpir_surface *surface = to_rpir_surface(base);
1500
1501 assert(surface);
1502 if (!surface)
1503 return;
1504
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001505 if (surface->buffer_type == BUFFER_TYPE_SHM) {
1506 if (!surface->single_buffer)
1507 /* XXX: need to check if in middle of update */
1508 rpi_resource_release(surface->back);
1509
Jason Ekstranda7af7042013-10-12 22:38:11 -05001510 if (!surface->visible_views)
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001511 /* XXX: cannot do this, if middle of an update */
1512 rpi_resource_release(surface->front);
1513
1514 weston_buffer_reference(&surface->buffer_ref, NULL);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001515 }
1516
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001517 /* If buffer is NULL, Weston core unmaps the surface, the surface
1518 * will not appear in repaint list, and so rpi_renderer_repaint_output
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001519 * will remove the DispmanX element. Later, for SHM, also the front
1520 * buffer will be released in the cleanup_list processing.
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001521 */
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001522 if (!buffer)
1523 return;
1524
1525 if (wl_shm_buffer_get(buffer->resource)) {
1526 surface->buffer_type = BUFFER_TYPE_SHM;
1527 buffer->shm_buffer = wl_shm_buffer_get(buffer->resource);
1528 buffer->width = wl_shm_buffer_get_width(buffer->shm_buffer);
1529 buffer->height = wl_shm_buffer_get_height(buffer->shm_buffer);
1530
1531 weston_buffer_reference(&surface->buffer_ref, buffer);
1532 } else {
1533#if ENABLE_EGL
1534 struct rpi_renderer *renderer = to_rpi_renderer(base->compositor);
Tomeu Vizosoa8e5f292013-10-09 11:29:45 +02001535 struct wl_resource *wl_resource = buffer->resource;
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001536
1537 if (!renderer->has_bind_display ||
1538 !renderer->query_buffer(renderer->egl_display,
1539 wl_resource,
1540 EGL_WIDTH, &buffer->width)) {
1541 weston_log("unhandled buffer type!\n");
1542 weston_buffer_reference(&surface->buffer_ref, NULL);
1543 surface->buffer_type = BUFFER_TYPE_NULL;
1544 }
1545
1546 renderer->query_buffer(renderer->egl_display,
1547 wl_resource,
1548 EGL_HEIGHT, &buffer->height);
1549
1550 surface->buffer_type = BUFFER_TYPE_EGL;
1551
1552 if(surface->egl_back == NULL)
Bryce Harringtonde16d892014-11-20 22:21:57 -08001553 surface->egl_back = zalloc(sizeof *surface->egl_back);
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001554
1555 weston_buffer_reference(&surface->egl_back->buffer_ref, buffer);
1556 surface->egl_back->resource_handle =
1557 vc_dispmanx_get_handle_from_wl_buffer(wl_resource);
1558#else
1559 weston_log("unhandled buffer type!\n");
1560 weston_buffer_reference(&surface->buffer_ref, NULL);
1561 surface->buffer_type = BUFFER_TYPE_NULL;
1562#endif
1563 }
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001564}
1565
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +03001566static void
1567rpir_surface_handle_surface_destroy(struct wl_listener *listener, void *data)
1568{
1569 struct rpir_surface *surface;
1570 struct weston_surface *base = data;
1571
1572 surface = container_of(listener, struct rpir_surface,
1573 surface_destroy_listener);
1574
1575 assert(surface);
1576 assert(surface->surface == base);
1577 if (!surface)
1578 return;
1579
1580 surface->surface = NULL;
1581 base->renderer_state = NULL;
1582
1583 if (wl_list_empty(&surface->views))
1584 rpir_surface_destroy(surface);
1585}
1586
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001587static int
1588rpi_renderer_create_surface(struct weston_surface *base)
1589{
1590 struct rpi_renderer *renderer = to_rpi_renderer(base->compositor);
1591 struct rpir_surface *surface;
1592
1593 assert(base->renderer_state == NULL);
1594
1595 surface = rpir_surface_create(renderer);
1596 if (!surface)
1597 return -1;
1598
1599 surface->surface = base;
1600 base->renderer_state = surface;
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +03001601
1602 surface->surface_destroy_listener.notify =
1603 rpir_surface_handle_surface_destroy;
1604 wl_signal_add(&base->destroy_signal,
1605 &surface->surface_destroy_listener);
1606
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001607 return 0;
1608}
1609
Jason Ekstranda7af7042013-10-12 22:38:11 -05001610static int
1611rpi_renderer_create_view(struct weston_view *base)
1612{
1613 struct rpir_surface *surface = to_rpir_surface(base->surface);
1614 struct rpir_view *view;
1615
1616 assert(base->renderer_state == NULL);
1617
1618 view = rpir_view_create(surface);
1619 if (!view)
1620 return -1;
1621
1622 view->view = base;
1623 base->renderer_state = view;
Tomeu Vizoso96dc9e42013-10-28 10:17:45 +01001624
1625 view->view_destroy_listener.notify =
1626 rpir_view_handle_view_destroy;
1627 wl_signal_add(&base->destroy_signal,
1628 &view->view_destroy_listener);
1629
Jason Ekstranda7af7042013-10-12 22:38:11 -05001630 return 0;
1631}
1632
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001633static void
1634rpi_renderer_surface_set_color(struct weston_surface *base,
1635 float red, float green, float blue, float alpha)
1636{
1637 struct rpir_surface *surface = to_rpir_surface(base);
1638 uint8_t color[4];
1639 VC_RECT_T rect;
1640 int ret;
1641
1642 assert(surface);
1643
1644 ret = rpi_resource_realloc(surface->back, VC_IMAGE_ARGB8888,
1645 1, 1, 4, 1);
1646 if (ret < 0) {
1647 weston_log("Error: %s: rpi_resource_realloc failed.\n",
1648 __func__);
1649 return;
1650 }
1651
1652 color[0] = float2uint8(blue);
1653 color[1] = float2uint8(green);
1654 color[2] = float2uint8(red);
1655 color[3] = float2uint8(alpha);
1656
1657 vc_dispmanx_rect_set(&rect, 0, 0, 1, 1);
1658 ret = vc_dispmanx_resource_write_data(surface->back->handle,
1659 VC_IMAGE_ARGB8888,
1660 4, color, &rect);
1661 if (ret) {
1662 weston_log("Error: %s: resource_write_data failed.\n",
1663 __func__);
1664 return;
1665 }
1666
1667 DBG("%s: resource %p solid color BGRA %u,%u,%u,%u\n", __func__,
1668 surface->back, color[0], color[1], color[2], color[3]);
1669
1670 /*pixman_region32_copy(&surface->prev_damage, damage);*/
1671 surface->need_swap = 1;
1672}
1673
1674static void
Tomeu Vizoso96dc9e42013-10-28 10:17:45 +01001675rpir_view_handle_view_destroy(struct wl_listener *listener, void *data)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001676{
Tomeu Vizoso96dc9e42013-10-28 10:17:45 +01001677 struct rpir_view *view;
1678 struct weston_view *base = data;
1679
1680 view = container_of(listener, struct rpir_view, view_destroy_listener);
Jason Ekstranda7af7042013-10-12 22:38:11 -05001681
1682 assert(view);
1683 assert(view->view == base);
1684 if (!view)
1685 return;
1686
Tomeu Vizoso34dad7d2013-10-25 10:34:37 +02001687 view->view = NULL;
Tomeu Vizoso96dc9e42013-10-28 10:17:45 +01001688 base->renderer_state = NULL;
Tomeu Vizoso34dad7d2013-10-25 10:34:37 +02001689
Tomeu Vizoso96dc9e42013-10-28 10:17:45 +01001690 /* If guaranteed to not be on screen, just destroy it. */
Jason Ekstranda7af7042013-10-12 22:38:11 -05001691 if (wl_list_empty(&view->link))
1692 rpir_view_destroy(view);
1693
1694 /* Otherwise, the view is either on screen and needs
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001695 * to be removed by a repaint update, or it is in the
Jason Ekstranda7af7042013-10-12 22:38:11 -05001696 * view_cleanup_list, and will be destroyed by
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001697 * rpi_renderer_finish_frame().
1698 */
1699}
1700
1701static void
1702rpi_renderer_destroy(struct weston_compositor *compositor)
1703{
1704 struct rpi_renderer *renderer = to_rpi_renderer(compositor);
1705
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001706#if ENABLE_EGL
1707 if (renderer->has_bind_display)
1708 renderer->unbind_display(renderer->egl_display,
1709 compositor->wl_display);
1710#endif
1711
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001712 free(renderer);
1713 compositor->renderer = NULL;
1714}
1715
1716WL_EXPORT int
1717rpi_renderer_create(struct weston_compositor *compositor,
1718 const struct rpi_renderer_parameters *params)
1719{
1720 struct rpi_renderer *renderer;
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001721#if ENABLE_EGL
1722 const char *extensions;
1723 EGLBoolean ret;
1724 EGLint major, minor;
1725#endif
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001726
1727 weston_log("Initializing the DispmanX compositing renderer\n");
1728
Bryce Harringtonde16d892014-11-20 22:21:57 -08001729 renderer = zalloc(sizeof *renderer);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001730 if (renderer == NULL)
1731 return -1;
1732
1733 renderer->single_buffer = params->single_buffer;
Tomeu Vizosoe4f7b922013-12-02 17:18:58 +01001734 renderer->enable_opaque_regions = params->opaque_regions;
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001735
1736 renderer->base.read_pixels = rpi_renderer_read_pixels;
1737 renderer->base.repaint_output = rpi_renderer_repaint_output;
1738 renderer->base.flush_damage = rpi_renderer_flush_damage;
1739 renderer->base.attach = rpi_renderer_attach;
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001740 renderer->base.surface_set_color = rpi_renderer_surface_set_color;
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001741 renderer->base.destroy = rpi_renderer_destroy;
1742
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001743#ifdef ENABLE_EGL
1744 renderer->egl_display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
1745 if (renderer->egl_display == EGL_NO_DISPLAY) {
1746 weston_log("failed to create EGL display\n");
U. Artie Eoffe067b302014-01-17 14:00:18 -08001747 free(renderer);
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001748 return -1;
1749 }
1750
1751 if (!eglInitialize(renderer->egl_display, &major, &minor)) {
1752 weston_log("failed to initialize EGL display\n");
U. Artie Eoffe067b302014-01-17 14:00:18 -08001753 free(renderer);
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001754 return -1;
1755 }
1756
1757 renderer->bind_display =
1758 (void *) eglGetProcAddress("eglBindWaylandDisplayWL");
1759 renderer->unbind_display =
1760 (void *) eglGetProcAddress("eglUnbindWaylandDisplayWL");
1761 renderer->query_buffer =
1762 (void *) eglGetProcAddress("eglQueryWaylandBufferWL");
1763
1764 extensions = (const char *) eglQueryString(renderer->egl_display,
1765 EGL_EXTENSIONS);
1766 if (!extensions) {
1767 weston_log("Retrieving EGL extension string failed.\n");
U. Artie Eoffac9f35a2014-01-17 16:28:15 -08001768 eglTerminate(renderer->egl_display);
U. Artie Eoffe067b302014-01-17 14:00:18 -08001769 free(renderer);
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001770 return -1;
1771 }
1772
1773 if (strstr(extensions, "EGL_WL_bind_wayland_display"))
1774 renderer->has_bind_display = 1;
1775
1776 if (renderer->has_bind_display) {
1777 ret = renderer->bind_display(renderer->egl_display,
1778 compositor->wl_display);
1779 if (!ret)
1780 renderer->has_bind_display = 0;
1781 }
1782#endif
1783
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001784 compositor->renderer = &renderer->base;
1785 compositor->read_format = PIXMAN_a8r8g8b8;
1786 /* WESTON_CAP_ROTATION_ANY not supported */
1787
Tomeu Vizoso03681892013-08-06 20:05:57 +02001788 wl_display_add_shm_format(compositor->wl_display, WL_SHM_FORMAT_RGB565);
1789
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001790 return 0;
1791}
1792
1793WL_EXPORT int
1794rpi_renderer_output_create(struct weston_output *base,
1795 DISPMANX_DISPLAY_HANDLE_T display)
1796{
1797 struct rpir_output *output;
1798
1799 assert(base->renderer_state == NULL);
1800
Bryce Harringtonde16d892014-11-20 22:21:57 -08001801 output = zalloc(sizeof *output);
1802 if (output == NULL)
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001803 return -1;
1804
1805 output->display = display;
1806 output->update = DISPMANX_NO_HANDLE;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001807 wl_list_init(&output->view_list);
1808 wl_list_init(&output->view_cleanup_list);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001809 rpi_resource_init(&output->capture_buffer);
1810 base->renderer_state = output;
1811
1812 return 0;
1813}
1814
1815WL_EXPORT void
1816rpi_renderer_output_destroy(struct weston_output *base)
1817{
1818 struct rpir_output *output = to_rpir_output(base);
Jason Ekstranda7af7042013-10-12 22:38:11 -05001819 struct rpir_view *view;
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001820 DISPMANX_UPDATE_HANDLE_T update;
1821
1822 rpi_resource_release(&output->capture_buffer);
1823 free(output->capture_data);
1824 output->capture_data = NULL;
1825
1826 update = vc_dispmanx_update_start(0);
1827 rpir_output_dmx_remove_all(output, update);
1828 vc_dispmanx_update_submit_sync(update);
1829
Jason Ekstranda7af7042013-10-12 22:38:11 -05001830 while (!wl_list_empty(&output->view_cleanup_list)) {
1831 view = container_of(output->view_cleanup_list.next,
1832 struct rpir_view, link);
1833 rpir_view_destroy(view);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001834 }
1835
1836 free(output);
1837 base->renderer_state = NULL;
1838}
1839
1840WL_EXPORT void
1841rpi_renderer_set_update_handle(struct weston_output *base,
1842 DISPMANX_UPDATE_HANDLE_T handle)
1843{
1844 struct rpir_output *output = to_rpir_output(base);
1845
1846 output->update = handle;
1847}
1848
1849WL_EXPORT void
1850rpi_renderer_finish_frame(struct weston_output *base)
1851{
1852 struct rpir_output *output = to_rpir_output(base);
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001853 struct weston_compositor *compositor = base->compositor;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001854 struct weston_view *wv;
1855 struct rpir_view *view;
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001856
Jason Ekstranda7af7042013-10-12 22:38:11 -05001857 while (!wl_list_empty(&output->view_cleanup_list)) {
1858 view = container_of(output->view_cleanup_list.next,
1859 struct rpir_view, link);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001860
Jason Ekstranda7af7042013-10-12 22:38:11 -05001861 if (view->view) {
1862 /* The weston_view still exists, but is
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001863 * temporarily not visible, and hence its Element
1864 * was removed. The current front buffer contents
1865 * must be preserved.
1866 */
Jason Ekstranda7af7042013-10-12 22:38:11 -05001867 if (!view->surface->visible_views)
1868 rpi_resource_release(view->surface->back);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001869
Jason Ekstranda7af7042013-10-12 22:38:11 -05001870 wl_list_remove(&view->link);
1871 wl_list_init(&view->link);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001872 } else {
Jason Ekstranda7af7042013-10-12 22:38:11 -05001873 rpir_view_destroy(view);
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001874 }
1875 }
1876
Jason Ekstranda7af7042013-10-12 22:38:11 -05001877 wl_list_for_each(wv, &compositor->view_list, link) {
1878 view = to_rpir_view(wv);
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001879
Jason Ekstranda7af7042013-10-12 22:38:11 -05001880 if (view->surface->buffer_type != BUFFER_TYPE_EGL)
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001881 continue;
1882
Tomeu Vizoso74987582013-10-25 10:34:38 +02001883 rpir_egl_buffer_destroy(view->surface->egl_old_front);
Jason Ekstranda7af7042013-10-12 22:38:11 -05001884 view->surface->egl_old_front = NULL;
Tomeu Vizosob4659eb2013-10-07 11:02:20 +02001885 }
1886
Pekka Paalanend7265bc2013-05-22 18:03:06 +03001887 wl_signal_emit(&base->frame_signal, base);
1888}