2 * Copyright © 2012-2013 Raspberry Pi Foundation
4 * Permission to use, copy, modify, distribute, and sell this software and
5 * its documentation for any purpose is hereby granted without fee, provided
6 * that the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation, and that the name of the copyright holders not be used in
9 * advertising or publicity pertaining to distribution of the software
10 * without specific, written prior permission. The copyright holders make
11 * no representations about the suitability of this software for any
12 * purpose. It is provided "as is" without express or implied warranty.
14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
15 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
16 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
17 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
18 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
19 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
20 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
30 # include <bcm_host.h>
32 # include "rpi-bcm-stubs.h"
35 #include "compositor.h"
36 #include "rpi-renderer.h"
40 #include <EGL/eglext.h>
41 #include "weston-egl-ext.h"
45 * Dispmanx API offers alpha-blended overlays for hardware compositing.
46 * The final composite consists of dispmanx elements, and their contents:
47 * the dispmanx resource assigned to the element. The elements may be
48 * scanned out directly, or composited to a temporary surface, depending on
49 * how the firmware decides to handle the scene. Updates to multiple elements
50 * may be queued in a single dispmanx update object, resulting in atomic and
51 * vblank synchronized display updates.
53 * To avoid tearing and display artifacts, the current dispmanx resource in a
54 * dispmanx element must not be touched. Therefore each element must be
55 * double-buffered, using two resources, the front and the back. While a
56 * dispmanx update is running, the both resources must be considered in use.
58 * A resource may be destroyed only, when the update removing the element has
59 * completed. Otherwise you risk showing an incomplete composition.
62 #ifndef ELEMENT_CHANGE_LAYER
63 /* copied from interface/vmcs_host/vc_vchi_dispmanx.h of userland.git */
64 #define ELEMENT_CHANGE_LAYER (1<<0)
65 #define ELEMENT_CHANGE_OPACITY (1<<1)
66 #define ELEMENT_CHANGE_DEST_RECT (1<<2)
67 #define ELEMENT_CHANGE_SRC_RECT (1<<3)
68 #define ELEMENT_CHANGE_MASK_RESOURCE (1<<4)
69 #define ELEMENT_CHANGE_TRANSFORM (1<<5)
74 weston_log(__VA_ARGS__)
76 #define DBG(...) do {} while (0)
79 /* If we had a fully featured vc_dispmanx_resource_write_data()... */
80 /*#define HAVE_RESOURCE_WRITE_DATA_RECT 1*/
82 /* If we had a vc_dispmanx_element_set_opaque_rect()... */
83 /*#define HAVE_ELEMENT_SET_OPAQUE_RECT 1*/
86 DISPMANX_RESOURCE_HANDLE_T handle;
88 int height; /* height of the image (valid pixel data) */
89 int stride; /* bytes */
90 int buffer_height; /* height of the buffer */
91 int enable_opaque_regions;
97 struct rpir_egl_buffer {
98 struct weston_buffer_reference buffer_ref;
99 DISPMANX_RESOURCE_HANDLE_T resource_handle;
108 struct rpir_surface {
109 struct weston_surface *surface;
111 struct wl_list views;
115 int enable_opaque_regions;
117 struct rpi_resource resources[2];
118 struct rpi_resource *front;
119 struct rpi_resource *back;
120 pixman_region32_t prev_damage;
122 struct rpir_egl_buffer *egl_front;
123 struct rpir_egl_buffer *egl_back;
124 struct rpir_egl_buffer *egl_old_front;
126 struct weston_buffer_reference buffer_ref;
127 enum buffer_type buffer_type;
129 struct wl_listener surface_destroy_listener;
133 struct rpir_surface *surface;
134 struct wl_list surface_link;
135 struct weston_view *view;
137 /* If link is empty, the view is guaranteed to not be on screen,
138 * i.e. updates removing Elements have completed.
142 DISPMANX_ELEMENT_HANDLE_T handle;
145 struct wl_listener view_destroy_listener;
149 DISPMANX_DISPLAY_HANDLE_T display;
151 DISPMANX_UPDATE_HANDLE_T update;
152 struct weston_matrix matrix;
154 /* all Elements currently on screen */
155 struct wl_list view_list; /* struct rpir_surface::link */
157 /* Elements just removed, waiting for update completion */
158 struct wl_list view_cleanup_list; /* struct rpir_surface::link */
160 struct rpi_resource capture_buffer;
161 uint8_t *capture_data;
164 struct rpi_renderer {
165 struct weston_renderer base;
168 int enable_opaque_regions;
171 EGLDisplay egl_display;
173 PFNEGLBINDWAYLANDDISPLAYWL bind_display;
174 PFNEGLUNBINDWAYLANDDISPLAYWL unbind_display;
175 PFNEGLQUERYWAYLANDBUFFERWL query_buffer;
177 int has_bind_display;
181 rpi_renderer_create_surface(struct weston_surface *base);
184 rpi_renderer_create_view(struct weston_view *base);
187 rpir_view_handle_view_destroy(struct wl_listener *listener, void *data);
189 static inline struct rpir_surface *
190 to_rpir_surface(struct weston_surface *surface)
192 if (!surface->renderer_state)
193 rpi_renderer_create_surface(surface);
195 return surface->renderer_state;
198 static inline struct rpir_view *
199 to_rpir_view(struct weston_view *view)
201 if (!view->renderer_state)
202 rpi_renderer_create_view(view);
204 return view->renderer_state;
207 static inline struct rpir_output *
208 to_rpir_output(struct weston_output *output)
210 return output->renderer_state;
213 static inline struct rpi_renderer *
214 to_rpi_renderer(struct weston_compositor *compositor)
216 return container_of(compositor->renderer, struct rpi_renderer, base);
220 int_max(int a, int b)
222 return a > b ? a : b;
226 int_swap(int *a, int *b)
236 int v = roundf(f * 255.0f);
238 return v < 0 ? 0 : (v > 255 ? 255 : v);
242 rpi_resource_init(struct rpi_resource *resource)
244 resource->handle = DISPMANX_NO_HANDLE;
248 rpi_resource_release(struct rpi_resource *resource)
250 if (resource->handle == DISPMANX_NO_HANDLE)
253 vc_dispmanx_resource_delete(resource->handle);
254 DBG("resource %p release\n", resource);
255 resource->handle = DISPMANX_NO_HANDLE;
259 rpi_resource_realloc(struct rpi_resource *resource, VC_IMAGE_TYPE_T ifmt,
260 int width, int height, int stride, int buffer_height)
264 if (resource->handle != DISPMANX_NO_HANDLE &&
265 resource->width == width &&
266 resource->height == height &&
267 resource->stride == stride &&
268 resource->buffer_height == buffer_height &&
269 resource->ifmt == ifmt)
272 rpi_resource_release(resource);
274 /* NOTE: if stride is not a multiple of 16 pixels in bytes,
275 * the vc_image_* functions may break. Dispmanx elements
276 * should be fine, though. Buffer_height probably has similar
280 vc_dispmanx_resource_create(ifmt,
281 width | (stride << 16),
282 height | (buffer_height << 16),
284 if (resource->handle == DISPMANX_NO_HANDLE)
287 resource->width = width;
288 resource->height = height;
289 resource->stride = stride;
290 resource->buffer_height = buffer_height;
291 resource->ifmt = ifmt;
292 DBG("resource %p alloc\n", resource);
296 /* A firmware workaround for broken ALPHA_PREMULT + ALPHA_MIX hardware. */
297 #define PREMULT_ALPHA_FLAG (1 << 31)
299 static VC_IMAGE_TYPE_T
300 shm_buffer_get_vc_format(struct wl_shm_buffer *buffer)
302 switch (wl_shm_buffer_get_format(buffer)) {
303 case WL_SHM_FORMAT_XRGB8888:
304 return VC_IMAGE_XRGB8888;
305 case WL_SHM_FORMAT_ARGB8888:
306 return VC_IMAGE_ARGB8888 | PREMULT_ALPHA_FLAG;
307 case WL_SHM_FORMAT_RGB565:
308 return VC_IMAGE_RGB565;
315 #ifndef HAVE_ELEMENT_SET_OPAQUE_RECT
317 apply_opaque_region(struct wl_shm_buffer *buffer,
318 pixman_region32_t *opaque_region)
326 width = wl_shm_buffer_get_width(buffer);
327 height = wl_shm_buffer_get_height(buffer);
328 stride = wl_shm_buffer_get_stride(buffer);
329 src = wl_shm_buffer_get_data(buffer);
331 dst = malloc(height * stride);
333 weston_log("rpi-renderer error: out of memory\n");
337 for (y = 0; y < height; y++) {
338 for (x = 0; x < width; x++) {
339 int i = y * stride / 4 + x;
341 if (pixman_region32_contains_point (opaque_region, x, y, &box)) {
342 dst[i] = src[i] | 0xff000000;
354 rpi_resource_update(struct rpi_resource *resource, struct weston_buffer *buffer,
355 pixman_region32_t *region, pixman_region32_t *opaque_region)
357 pixman_region32_t write_region;
360 VC_IMAGE_TYPE_T ifmt;
366 int applied_opaque_region = 0;
367 #ifdef HAVE_RESOURCE_WRITE_DATA_RECT
374 ifmt = shm_buffer_get_vc_format(buffer->shm_buffer);
375 width = wl_shm_buffer_get_width(buffer->shm_buffer);
376 height = wl_shm_buffer_get_height(buffer->shm_buffer);
377 stride = wl_shm_buffer_get_stride(buffer->shm_buffer);
378 pixels = wl_shm_buffer_get_data(buffer->shm_buffer);
380 #ifndef HAVE_ELEMENT_SET_OPAQUE_RECT
381 if (pixman_region32_not_empty(opaque_region) &&
382 wl_shm_buffer_get_format(buffer->shm_buffer) == WL_SHM_FORMAT_ARGB8888 &&
383 resource->enable_opaque_regions) {
384 pixels = apply_opaque_region(buffer->shm_buffer, opaque_region);
389 applied_opaque_region = 1;
393 ret = rpi_resource_realloc(resource, ifmt & ~PREMULT_ALPHA_FLAG,
394 width, height, stride, height);
396 if (applied_opaque_region)
401 pixman_region32_init_rect(&write_region, 0, 0, width, height);
403 pixman_region32_intersect(&write_region,
404 &write_region, region);
406 wl_shm_buffer_begin_access(buffer->shm_buffer);
408 #ifdef HAVE_RESOURCE_WRITE_DATA_RECT
409 /* XXX: Can this do a format conversion, so that scanout does not have to? */
410 r = pixman_region32_rectangles(&write_region, &n);
412 vc_dispmanx_rect_set(&rect, r[n].x1, r[n].y1,
413 r[n].x2 - r[n].x1, r[n].y2 - r[n].y1);
415 ret = vc_dispmanx_resource_write_data_rect(resource->handle,
419 DBG("%s: %p %ux%u@%u,%u, ret %d\n", __func__, resource,
420 rect.width, rect.height, rect.x, rect.y, ret);
425 /* vc_dispmanx_resource_write_data() ignores ifmt,
426 * rect.x, rect.width, and uses stride only for computing
427 * the size of the transfer as rect.height * stride.
428 * Therefore we can only write rows starting at x=0.
429 * To be able to write more than one scanline at a time,
430 * the resource must have been created with the same stride
431 * as used here, and we must write full scanlines.
434 r = pixman_region32_extents(&write_region);
435 vc_dispmanx_rect_set(&rect, 0, r->y1, width, r->y2 - r->y1);
436 ret = vc_dispmanx_resource_write_data(resource->handle,
437 ifmt, stride, pixels, &rect);
438 DBG("%s: %p %ux%u@%u,%u, ret %d\n", __func__, resource,
439 width, r->y2 - r->y1, 0, r->y1, ret);
442 wl_shm_buffer_end_access(buffer->shm_buffer);
444 pixman_region32_fini(&write_region);
446 if (applied_opaque_region)
453 rpi_buffer_egl_lock(struct weston_buffer *buffer)
456 vc_dispmanx_set_wl_buffer_in_use(buffer->resource, 1);
461 rpi_buffer_egl_unlock(struct weston_buffer *buffer)
464 vc_dispmanx_set_wl_buffer_in_use(buffer->resource, 0);
469 rpir_egl_buffer_destroy(struct rpir_egl_buffer *egl_buffer)
471 struct weston_buffer *buffer;
473 if (egl_buffer == NULL)
476 buffer = egl_buffer->buffer_ref.buffer;
477 if (buffer == NULL) {
478 /* The client has already destroyed the wl_buffer, the
479 * compositor has the responsibility to delete the resource.
481 vc_dispmanx_resource_delete(egl_buffer->resource_handle);
483 rpi_buffer_egl_unlock(buffer);
484 weston_buffer_reference(&egl_buffer->buffer_ref, NULL);
490 static struct rpir_surface *
491 rpir_surface_create(struct rpi_renderer *renderer)
493 struct rpir_surface *surface;
495 surface = calloc(1, sizeof *surface);
499 wl_list_init(&surface->views);
500 surface->visible_views = 0;
501 surface->single_buffer = renderer->single_buffer;
502 surface->enable_opaque_regions = renderer->enable_opaque_regions;
503 rpi_resource_init(&surface->resources[0]);
504 rpi_resource_init(&surface->resources[1]);
505 surface->front = &surface->resources[0];
506 if (surface->single_buffer)
507 surface->back = &surface->resources[0];
509 surface->back = &surface->resources[1];
511 surface->front->enable_opaque_regions = renderer->enable_opaque_regions;
512 surface->back->enable_opaque_regions = renderer->enable_opaque_regions;
514 surface->buffer_type = BUFFER_TYPE_NULL;
516 pixman_region32_init(&surface->prev_damage);
522 rpir_surface_destroy(struct rpir_surface *surface)
524 if (surface->visible_views)
525 weston_log("ERROR rpi: destroying on-screen element\n");
527 assert(wl_list_empty(&surface->views));
529 if (surface->surface)
530 surface->surface->renderer_state = NULL;
532 pixman_region32_fini(&surface->prev_damage);
533 rpi_resource_release(&surface->resources[0]);
534 rpi_resource_release(&surface->resources[1]);
535 DBG("rpir_surface %p destroyed (%u)\n", surface, surface->visible_views);
537 rpir_egl_buffer_destroy(surface->egl_back);
538 rpir_egl_buffer_destroy(surface->egl_front);
539 rpir_egl_buffer_destroy(surface->egl_old_front);
545 rpir_surface_damage(struct rpir_surface *surface, struct weston_buffer *buffer,
546 pixman_region32_t *damage)
548 pixman_region32_t upload;
551 if (!pixman_region32_not_empty(damage))
554 DBG("rpir_surface %p update resource %p\n", surface, surface->back);
556 /* XXX: todo: if no surface->handle, update front buffer directly
557 * to avoid creating a new back buffer */
558 if (surface->single_buffer) {
559 ret = rpi_resource_update(surface->front, buffer, damage,
560 &surface->surface->opaque);
562 pixman_region32_init(&upload);
563 pixman_region32_union(&upload, &surface->prev_damage, damage);
564 ret = rpi_resource_update(surface->back, buffer, &upload,
565 &surface->surface->opaque);
566 pixman_region32_fini(&upload);
569 pixman_region32_copy(&surface->prev_damage, damage);
570 surface->need_swap = 1;
575 static struct rpir_view *
576 rpir_view_create(struct rpir_surface *surface)
578 struct rpir_view *view;
580 view = calloc(1, sizeof *view);
584 view->surface = surface;
585 wl_list_insert(&surface->views, &view->surface_link);
587 wl_list_init(&view->link);
588 view->handle = DISPMANX_NO_HANDLE;
594 rpir_view_destroy(struct rpir_view *view)
596 wl_list_remove(&view->link);
598 if (view->handle != DISPMANX_NO_HANDLE) {
599 view->surface->visible_views--;
600 weston_log("ERROR rpi: destroying on-screen element\n");
604 view->view->renderer_state = NULL;
606 wl_list_remove(&view->surface_link);
607 if (wl_list_empty(&view->surface->views) && view->surface->surface == NULL)
608 rpir_surface_destroy(view->surface);
610 DBG("rpir_view %p destroyed (%d)\n", view, view->handle);
616 matrix_type_str(struct weston_matrix *matrix, char *buf, int len)
618 static const char types[33] = "TSRO";
619 unsigned mask = matrix->type;
622 while (mask && i < len - 1) {
623 if (mask & (1u << i))
632 log_print_matrix(struct weston_matrix *matrix)
635 float *d = matrix->d;
637 matrix_type_str(matrix, typestr, sizeof typestr);
638 weston_log_continue("%14.6e %14.6e %14.6e %14.6e\n",
639 d[0], d[4], d[8], d[12]);
640 weston_log_continue("%14.6e %14.6e %14.6e %14.6e\n",
641 d[1], d[5], d[9], d[13]);
642 weston_log_continue("%14.6e %14.6e %14.6e %14.6e\n",
643 d[2], d[6], d[10], d[14]);
644 weston_log_continue("%14.6e %14.6e %14.6e %14.6e type: %s\n",
645 d[3], d[7], d[11], d[15], typestr);
649 warn_bad_matrix(struct weston_matrix *total, struct weston_matrix *output,
650 struct weston_matrix *surface)
656 weston_log("%s: not showing more warnings\n", __func__);
661 weston_log("%s: warning: total transformation is not renderable:\n",
663 log_print_matrix(total);
665 matrix_type_str(surface, typestr, sizeof typestr);
666 weston_log_continue("surface matrix type: %s\n", typestr);
667 matrix_type_str(output, typestr, sizeof typestr);
668 weston_log_continue("output matrix type: %s\n", typestr);
671 /*#define SURFACE_TRANSFORM */
674 rpir_view_compute_rects(struct rpir_view *view,
675 VC_RECT_T *src_rect, VC_RECT_T *dst_rect,
676 VC_IMAGE_TRANSFORM_T *flipmask)
678 struct weston_output *output_base = view->view->surface->output;
679 struct rpir_output *output = to_rpir_output(output_base);
680 struct weston_matrix matrix = view->view->transform.matrix;
681 VC_IMAGE_TRANSFORM_T flipt = 0;
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 }};
691 /* XXX: take buffer transform into account */
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.
702 if (view->surface->buffer_type == BUFFER_TYPE_EGL) {
703 struct weston_buffer *buffer =
704 view->surface->egl_front->buffer_ref.buffer;
706 src_width = buffer->width << 16;
707 src_height = buffer->height << 16;
709 src_width = view->surface->front->width << 16;
710 src_height = view->surface->front->height << 16;
713 weston_matrix_multiply(&matrix, &output->matrix);
715 #ifdef SURFACE_TRANSFORM
716 if (matrix.type >= WESTON_MATRIX_TRANSFORM_OTHER) {
718 if (matrix.type >= WESTON_MATRIX_TRANSFORM_ROTATE) {
720 warn_bad_matrix(&matrix, &output->matrix,
721 &view->view->transform.matrix);
723 if (matrix.type & WESTON_MATRIX_TRANSFORM_ROTATE) {
724 if (fabsf(matrix.d[0]) < 1e-4f &&
725 fabsf(matrix.d[5]) < 1e-4f) {
726 flipt |= TRANSFORM_TRANSPOSE;
727 } else if (fabsf(matrix.d[1]) < 1e-4 &&
728 fabsf(matrix.d[4]) < 1e-4) {
731 warn_bad_matrix(&matrix, &output->matrix,
732 &view->view->transform.matrix);
737 p2.f[0] = view->view->surface->width;
738 p2.f[1] = view->view->surface->height;
740 /* transform top-left and bot-right corner into screen coordinates */
741 weston_matrix_transform(&matrix, &p1);
742 weston_matrix_transform(&matrix, &p2);
744 /* Compute the destination rectangle on screen, converting
745 * negative dimensions to flips.
748 dst_width = round(p2.f[0] - p1.f[0]);
750 dst_x = round(p2.f[0]);
751 dst_width = -dst_width;
753 if (!(flipt & TRANSFORM_TRANSPOSE))
754 flipt |= TRANSFORM_HFLIP;
756 flipt |= TRANSFORM_VFLIP;
758 dst_x = round(p1.f[0]);
761 dst_height = round(p2.f[1] - p1.f[1]);
762 if (dst_height < 0) {
763 dst_y = round(p2.f[1]);
764 dst_height = -dst_height;
766 if (!(flipt & TRANSFORM_TRANSPOSE))
767 flipt |= TRANSFORM_VFLIP;
769 flipt |= TRANSFORM_HFLIP;
771 dst_y = round(p1.f[1]);
774 if (dst_width == 0 || dst_height == 0) {
775 DBG("ignored, zero surface area before clipping\n");
779 #ifdef SURFACE_TRANSFORM
780 /* Dispmanx works as if you flipped the whole screen, when
781 * you flip an element. But, we want to flip an element in place.
784 if (flipt & TRANSFORM_HFLIP)
785 dst_x = output_base->width - dst_x;
786 if (flipt & TRANSFORM_VFLIP)
787 dst_y = output_base->height - dst_y;
788 if (flipt & TRANSFORM_TRANSPOSE) {
789 int_swap(&dst_x, &dst_y);
790 int_swap(&dst_width, &dst_height);
793 switch (output_base->transform) {
794 case WL_OUTPUT_TRANSFORM_FLIPPED:
795 flipt = TRANSFORM_HFLIP;
797 case WL_OUTPUT_TRANSFORM_NORMAL:
801 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
802 flipt = TRANSFORM_HFLIP | TRANSFORM_VFLIP | TRANSFORM_TRANSPOSE;
804 case WL_OUTPUT_TRANSFORM_90:
805 flipt = TRANSFORM_VFLIP | TRANSFORM_TRANSPOSE;
807 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
808 flipt = TRANSFORM_VFLIP;
810 case WL_OUTPUT_TRANSFORM_180:
811 flipt = TRANSFORM_HFLIP | TRANSFORM_VFLIP;
814 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
815 flipt = TRANSFORM_TRANSPOSE;
817 case WL_OUTPUT_TRANSFORM_270:
818 flipt = TRANSFORM_HFLIP | TRANSFORM_TRANSPOSE;
825 /* clip destination rectangle to screen dimensions */
828 t = (int64_t)dst_x * src_width / dst_width;
836 t = (int64_t)dst_y * src_height / dst_height;
843 over = dst_x + dst_width - output_base->width;
845 t = (int64_t)over * src_width / dst_width;
850 over = dst_y + dst_height - output_base->height;
852 t = (int64_t)over * src_height / dst_height;
857 src_width = int_max(src_width, 0);
858 src_height = int_max(src_height, 0);
860 DBG("rpir_view %p %dx%d: p1 %f, %f; p2 %f, %f\n", view,
861 view->view->surface->width,
862 view->view->surface->height,
863 p1.f[0], p1.f[1], p2.f[0], p2.f[1]);
864 DBG("src rect %d;%d, %d;%d, %d;%dx%d;%d\n",
865 src_x >> 16, src_x & 0xffff,
866 src_y >> 16, src_y & 0xffff,
867 src_width >> 16, src_width & 0xffff,
868 src_height >> 16, src_height & 0xffff);
869 DBG("dest rect %d, %d, %dx%d%s%s%s\n",
870 dst_x, dst_y, dst_width, dst_height,
871 (flipt & TRANSFORM_HFLIP) ? " hflip" : "",
872 (flipt & TRANSFORM_VFLIP) ? " vflip" : "",
873 (flipt & TRANSFORM_TRANSPOSE) ? " transp" : "");
880 if (dst_width < 1 || dst_height < 1) {
881 DBG("ignored, zero surface area after clipping\n");
885 /* EGL buffers will be upside-down related to what DispmanX expects */
886 if (view->surface->buffer_type == BUFFER_TYPE_EGL)
887 flipt ^= TRANSFORM_VFLIP;
889 vc_dispmanx_rect_set(src_rect, src_x, src_y, src_width, src_height);
890 vc_dispmanx_rect_set(dst_rect, dst_x, dst_y, dst_width, dst_height);
896 static DISPMANX_TRANSFORM_T
897 vc_image2dispmanx_transform(VC_IMAGE_TRANSFORM_T t)
899 /* XXX: uhh, are these right? */
902 return DISPMANX_NO_ROTATE;
903 case VC_IMAGE_MIRROR_ROT0:
904 return DISPMANX_FLIP_HRIZ;
905 case VC_IMAGE_MIRROR_ROT180:
906 return DISPMANX_FLIP_VERT;
907 case VC_IMAGE_ROT180:
908 return DISPMANX_ROTATE_180;
909 case VC_IMAGE_MIRROR_ROT90:
910 return DISPMANX_ROTATE_90 | DISPMANX_FLIP_HRIZ;
911 case VC_IMAGE_ROT270:
912 return DISPMANX_ROTATE_270;
914 return DISPMANX_ROTATE_90;
915 case VC_IMAGE_MIRROR_ROT270:
916 return DISPMANX_ROTATE_270 | DISPMANX_FLIP_VERT;
918 assert(0 && "bad VC_IMAGE_TRANSFORM_T");
919 return DISPMANX_NO_ROTATE;
923 static DISPMANX_RESOURCE_HANDLE_T
924 rpir_surface_get_resource(struct rpir_surface *surface)
926 switch (surface->buffer_type) {
927 case BUFFER_TYPE_SHM:
928 case BUFFER_TYPE_NULL:
929 return surface->front->handle;
930 case BUFFER_TYPE_EGL:
931 if (surface->egl_front != NULL)
932 return surface->egl_front->resource_handle;
934 return DISPMANX_NO_HANDLE;
938 #ifdef HAVE_ELEMENT_SET_OPAQUE_RECT
940 rpir_surface_set_opaque_rect(struct rpir_surface *surface,
941 DISPMANX_UPDATE_HANDLE_T update)
945 if (pixman_region32_not_empty(&surface->surface->opaque) &&
946 surface->opaque_regions) {
948 VC_RECT_T opaque_rect;
950 box = pixman_region32_extents(&surface->surface->opaque);
951 opaque_rect.x = box->x1;
952 opaque_rect.y = box->y1;
953 opaque_rect.width = box->x2 - box->x1;
954 opaque_rect.height = box->y2 - box->y1;
956 ret = vc_dispmanx_element_set_opaque_rect(update,
960 weston_log("vc_dispmanx_element_set_opaque_rect failed\n");
970 rpir_view_dmx_add(struct rpir_view *view, struct rpir_output *output,
971 DISPMANX_UPDATE_HANDLE_T update, int layer)
973 /* Do not use DISPMANX_FLAGS_ALPHA_PREMULT here.
974 * If you define PREMULT and ALPHA_MIX, the hardware will not
975 * multiply the source color with the element alpha, leading to
976 * bad colors. Instead, we define PREMULT during pixel data upload.
978 VC_DISPMANX_ALPHA_T alphasetup = {
979 DISPMANX_FLAGS_ALPHA_FROM_SOURCE |
980 DISPMANX_FLAGS_ALPHA_MIX,
981 float2uint8(view->view->alpha), /* opacity 0-255 */
982 0 /* mask resource handle */
986 VC_IMAGE_TRANSFORM_T flipmask;
988 DISPMANX_RESOURCE_HANDLE_T resource_handle;
990 resource_handle = rpir_surface_get_resource(view->surface);
991 if (resource_handle == DISPMANX_NO_HANDLE) {
992 weston_log("%s: no buffer yet, aborting\n", __func__);
996 ret = rpir_view_compute_rects(view, &src_rect, &dst_rect, &flipmask);
1000 view->handle = vc_dispmanx_element_add(
1007 DISPMANX_PROTECTION_NONE,
1010 vc_image2dispmanx_transform(flipmask));
1011 DBG("rpir_surface %p add %u, alpha %f resource %d\n", view,
1012 view->handle, view->view->alpha, resource_handle);
1014 if (view->handle == DISPMANX_NO_HANDLE)
1017 #ifdef HAVE_ELEMENT_SET_OPAQUE_RECT
1018 ret = rpir_surface_set_opaque_rect(surface, update);
1023 view->surface->visible_views++;
1029 rpir_view_dmx_swap(struct rpir_view *view,
1030 DISPMANX_UPDATE_HANDLE_T update)
1035 /* XXX: skip, iff resource was not reallocated, and single-buffering */
1036 vc_dispmanx_element_change_source(update, view->handle,
1037 view->surface->front->handle);
1039 /* This is current damage now, after rpir_surface_damage() */
1040 r = pixman_region32_extents(&view->surface->prev_damage);
1042 vc_dispmanx_rect_set(&rect, r->x1, r->y1,
1043 r->x2 - r->x1, r->y2 - r->y1);
1044 vc_dispmanx_element_modified(update, view->handle, &rect);
1045 DBG("rpir_view %p swap\n", view);
1049 rpir_view_dmx_move(struct rpir_view *view,
1050 DISPMANX_UPDATE_HANDLE_T update, int layer)
1052 uint8_t alpha = float2uint8(view->view->alpha);
1055 VC_IMAGE_TRANSFORM_T flipmask;
1058 /* XXX: return early, if all attributes stay the same */
1060 if (view->surface->buffer_type == BUFFER_TYPE_EGL) {
1061 DISPMANX_RESOURCE_HANDLE_T resource_handle;
1063 resource_handle = rpir_surface_get_resource(view->surface);
1064 if (resource_handle == DISPMANX_NO_HANDLE) {
1065 weston_log("%s: no buffer yet, aborting\n", __func__);
1069 vc_dispmanx_element_change_source(update,
1074 ret = rpir_view_compute_rects(view, &src_rect, &dst_rect, &flipmask);
1078 ret = vc_dispmanx_element_change_attributes(
1081 ELEMENT_CHANGE_LAYER |
1082 ELEMENT_CHANGE_OPACITY |
1083 ELEMENT_CHANGE_TRANSFORM |
1084 ELEMENT_CHANGE_DEST_RECT |
1085 ELEMENT_CHANGE_SRC_RECT,
1091 /* This really is DISPMANX_TRANSFORM_T, no matter
1092 * what the header says. */
1093 vc_image2dispmanx_transform(flipmask));
1094 DBG("rpir_view %p move\n", view);
1099 #ifdef HAVE_ELEMENT_SET_OPAQUE_RECT
1100 ret = rpir_surface_set_opaque_rect(surface, update);
1109 rpir_view_dmx_remove(struct rpir_view *view,
1110 DISPMANX_UPDATE_HANDLE_T update)
1112 if (view->handle == DISPMANX_NO_HANDLE)
1115 vc_dispmanx_element_remove(update, view->handle);
1116 DBG("rpir_view %p remove %u\n", view, view->handle);
1117 view->handle = DISPMANX_NO_HANDLE;
1118 view->surface->visible_views--;
1122 rpir_surface_swap_pointers(struct rpir_surface *surface)
1124 struct rpi_resource *tmp;
1126 if (surface->buffer_type == BUFFER_TYPE_EGL) {
1127 if (surface->egl_back != NULL) {
1128 assert(surface->egl_old_front == NULL);
1129 surface->egl_old_front = surface->egl_front;
1130 surface->egl_front = surface->egl_back;
1131 surface->egl_back = NULL;
1132 DBG("new front %d\n", surface->egl_front->resource_handle);
1135 tmp = surface->front;
1136 surface->front = surface->back;
1137 surface->back = tmp;
1138 DBG("new back %p, new front %p\n", surface->back, surface->front);
1143 is_view_not_visible(struct weston_view *view)
1145 /* Return true, if surface is guaranteed to be totally obscured. */
1147 pixman_region32_t unocc;
1149 pixman_region32_init(&unocc);
1150 pixman_region32_subtract(&unocc, &view->transform.boundingbox,
1152 ret = !pixman_region32_not_empty(&unocc);
1153 pixman_region32_fini(&unocc);
1159 rpir_view_update(struct rpir_view *view, struct rpir_output *output,
1160 DISPMANX_UPDATE_HANDLE_T update, int layer)
1165 obscured = is_view_not_visible(view->view);
1167 DBG("rpir_view %p totally obscured.\n", view);
1169 wl_list_remove(&view->link);
1170 if (view->handle == DISPMANX_NO_HANDLE) {
1171 wl_list_init(&view->link);
1173 rpir_view_dmx_remove(view, update);
1174 wl_list_insert(&output->view_cleanup_list,
1181 if (view->handle == DISPMANX_NO_HANDLE) {
1182 ret = rpir_view_dmx_add(view, output, update, layer);
1184 wl_list_remove(&view->link);
1185 wl_list_init(&view->link);
1186 } else if (ret < 0) {
1187 weston_log("ERROR rpir_view_dmx_add() failed.\n");
1190 if (view->surface->need_swap)
1191 rpir_view_dmx_swap(view, update);
1193 ret = rpir_view_dmx_move(view, update, layer);
1195 rpir_view_dmx_remove(view, update);
1197 wl_list_remove(&view->link);
1198 wl_list_insert(&output->view_cleanup_list,
1200 } else if (ret < 0) {
1201 weston_log("ERROR rpir_view_dmx_move() failed.\n");
1206 view->layer = layer;
1210 rpi_renderer_read_pixels(struct weston_output *base,
1211 pixman_format_code_t format, void *pixels,
1212 uint32_t x, uint32_t y,
1213 uint32_t width, uint32_t height)
1215 struct rpir_output *output = to_rpir_output(base);
1216 struct rpi_resource *buffer = &output->capture_buffer;
1218 uint32_t fb_width, fb_height;
1223 fb_width = base->current_mode->width;
1224 fb_height = base->current_mode->height;
1226 DBG("%s(%u, %u, %u, %u), resource %p\n", __func__,
1227 x, y, width, height, buffer);
1229 if (format != PIXMAN_a8r8g8b8) {
1230 weston_log("rpi-renderer error: bad read_format\n");
1234 dst_pitch = fb_width * 4;
1236 if (buffer->handle == DISPMANX_NO_HANDLE) {
1237 free(output->capture_data);
1238 output->capture_data = NULL;
1240 ret = rpi_resource_realloc(buffer, VC_IMAGE_ARGB8888,
1241 fb_width, fb_height,
1242 dst_pitch, fb_height);
1244 weston_log("rpi-renderer error: "
1245 "allocating read buffer failed\n");
1249 ret = vc_dispmanx_snapshot(output->display, buffer->handle,
1252 weston_log("rpi-renderer error: "
1253 "vc_dispmanx_snapshot returned %d\n", ret);
1256 DBG("%s: snapshot done.\n", __func__);
1260 * If vc_dispmanx_resource_read_data was able to read sub-rectangles,
1261 * we could read directly into 'pixels'. But it cannot, it does not
1262 * use rect.x or rect.width, and does this:
1263 * host_start = (uint8_t *)dst_address + (dst_pitch * p_rect->y);
1264 * In other words, it is only good for reading the full buffer in
1267 vc_dispmanx_rect_set(&rect, 0, 0, fb_width, fb_height);
1269 if (x == 0 && y == 0 && width == fb_width && height == fb_height) {
1270 ret = vc_dispmanx_resource_read_data(buffer->handle, &rect,
1273 weston_log("rpi-renderer error: "
1274 "resource_read_data returned %d\n", ret);
1277 DBG("%s: full frame done.\n", __func__);
1281 if (!output->capture_data) {
1282 output->capture_data = malloc(fb_height * dst_pitch);
1283 if (!output->capture_data) {
1284 weston_log("rpi-renderer error: "
1289 ret = vc_dispmanx_resource_read_data(buffer->handle, &rect,
1290 output->capture_data,
1293 weston_log("rpi-renderer error: "
1294 "resource_read_data returned %d\n", ret);
1299 for (i = 0; i < height; i++) {
1300 uint8_t *src = output->capture_data +
1301 (y + i) * dst_pitch + x * 4;
1302 uint8_t *dst = (uint8_t *)pixels + i * width * 4;
1303 memcpy(dst, src, width * 4);
1310 rpir_output_dmx_remove_all(struct rpir_output *output,
1311 DISPMANX_UPDATE_HANDLE_T update)
1313 struct rpir_view *view;
1315 while (!wl_list_empty(&output->view_list)) {
1316 view = container_of(output->view_list.next,
1317 struct rpir_view, link);
1318 rpir_view_dmx_remove(view, update);
1320 wl_list_remove(&view->link);
1321 wl_list_insert(&output->view_cleanup_list, &view->link);
1326 output_compute_matrix(struct weston_output *base)
1328 struct rpir_output *output = to_rpir_output(base);
1329 struct weston_matrix *matrix = &output->matrix;
1330 const float half_w = 0.5f * base->width;
1331 const float half_h = 0.5f * base->height;
1335 weston_matrix_init(matrix);
1336 weston_matrix_translate(matrix, -base->x, -base->y, 0.0f);
1338 #ifdef SURFACE_TRANSFORM
1339 weston_matrix_translate(matrix, -half_w, -half_h, 0.0f);
1340 switch (base->transform) {
1341 case WL_OUTPUT_TRANSFORM_FLIPPED:
1342 weston_matrix_scale(matrix, -1.0f, 1.0f, 1.0f);
1343 case WL_OUTPUT_TRANSFORM_NORMAL:
1344 /* weston_matrix_rotate_xy(matrix, 1.0f, 0.0f); no-op */
1345 weston_matrix_translate(matrix, half_w, half_h, 0.0f);
1348 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
1349 weston_matrix_scale(matrix, -1.0f, 1.0f, 1.0f);
1350 case WL_OUTPUT_TRANSFORM_90:
1351 weston_matrix_rotate_xy(matrix, 0.0f, 1.0f);
1352 weston_matrix_translate(matrix, half_h, half_w, 0.0f);
1355 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
1356 weston_matrix_scale(matrix, -1.0f, 1.0f, 1.0f);
1357 case WL_OUTPUT_TRANSFORM_180:
1358 weston_matrix_rotate_xy(matrix, -1.0f, 0.0f);
1359 weston_matrix_translate(matrix, half_w, half_h, 0.0f);
1362 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
1363 weston_matrix_scale(matrix, -1.0f, 1.0f, 1.0f);
1364 case WL_OUTPUT_TRANSFORM_270:
1365 weston_matrix_rotate_xy(matrix, 0.0f, -1.0f);
1366 weston_matrix_translate(matrix, half_h, half_w, 0.0f);
1374 if (base->zoom.active) {
1375 /* The base->zoom stuff is in GL coordinate system */
1376 mag = 1.0f / (1.0f - base->zoom.spring_z.current);
1377 dx = -(base->zoom.trans_x + 1.0f) * half_w;
1378 dy = -(base->zoom.trans_y + 1.0f) * half_h;
1379 weston_matrix_translate(matrix, dx, dy, 0.0f);
1380 weston_matrix_scale(matrix, mag, mag, 1.0f);
1381 weston_matrix_translate(matrix, half_w, half_h, 0.0f);
1385 /* Note: this won't work right for multiple outputs. A DispmanX Element
1386 * is tied to one DispmanX Display, i.e. output.
1389 rpi_renderer_repaint_output(struct weston_output *base,
1390 pixman_region32_t *output_damage)
1392 struct weston_compositor *compositor = base->compositor;
1393 struct rpir_output *output = to_rpir_output(base);
1394 struct weston_view *wv;
1395 struct rpir_view *view;
1396 struct wl_list done_list;
1399 assert(output->update != DISPMANX_NO_HANDLE);
1401 output_compute_matrix(base);
1403 rpi_resource_release(&output->capture_buffer);
1404 free(output->capture_data);
1405 output->capture_data = NULL;
1407 /* Swap resources on surfaces as needed */
1408 wl_list_for_each_reverse(wv, &compositor->view_list, link)
1409 wv->surface->touched = 0;
1411 wl_list_for_each_reverse(wv, &compositor->view_list, link) {
1412 view = to_rpir_view(wv);
1414 if (!wv->surface->touched) {
1415 wv->surface->touched = 1;
1417 if (view->surface->buffer_type == BUFFER_TYPE_EGL ||
1418 view->surface->need_swap)
1419 rpir_surface_swap_pointers(view->surface);
1422 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) {
1426 rpi_buffer_egl_lock(buffer);
1428 weston_log("warning: client destroyed current front buffer\n");
1430 wl_list_remove(&view->link);
1431 if (view->handle == DISPMANX_NO_HANDLE) {
1432 wl_list_init(&view->link);
1434 rpir_view_dmx_remove(view, output->update);
1435 wl_list_insert(&output->view_cleanup_list,
1442 /* update all renderable surfaces */
1443 wl_list_init(&done_list);
1444 wl_list_for_each_reverse(wv, &compositor->view_list, link) {
1445 if (wv->plane != &compositor->primary_plane)
1448 view = to_rpir_view(wv);
1449 assert(!wl_list_empty(&view->link) ||
1450 view->handle == DISPMANX_NO_HANDLE);
1452 wl_list_remove(&view->link);
1453 wl_list_insert(&done_list, &view->link);
1454 rpir_view_update(view, output, output->update, layer++);
1457 /* 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;
1461 /* Remove all surfaces that are still on screen, but were
1462 * not rendered this time.
1464 rpir_output_dmx_remove_all(output, output->update);
1466 wl_list_insert_list(&output->view_list, &done_list);
1467 output->update = DISPMANX_NO_HANDLE;
1469 /* The frame_signal is emitted in rpi_renderer_finish_frame(),
1470 * so that the firmware can capture the up-to-date contents.
1475 rpi_renderer_flush_damage(struct weston_surface *base)
1477 /* Called for every surface just before repainting it, if
1478 * having an shm buffer.
1480 struct rpir_surface *surface = to_rpir_surface(base);
1481 struct weston_buffer *buffer = surface->buffer_ref.buffer;
1485 assert(wl_shm_buffer_get(buffer->resource));
1487 ret = rpir_surface_damage(surface, buffer, &base->damage);
1489 weston_log("%s error: updating Dispmanx resource failed.\n",
1492 weston_buffer_reference(&surface->buffer_ref, NULL);
1496 rpi_renderer_attach(struct weston_surface *base, struct weston_buffer *buffer)
1498 /* Called every time a client commits an attach. */
1499 struct rpir_surface *surface = to_rpir_surface(base);
1505 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);
1510 if (!surface->visible_views)
1511 /* XXX: cannot do this, if middle of an update */
1512 rpi_resource_release(surface->front);
1514 weston_buffer_reference(&surface->buffer_ref, NULL);
1517 /* If buffer is NULL, Weston core unmaps the surface, the surface
1518 * will not appear in repaint list, and so rpi_renderer_repaint_output
1519 * will remove the DispmanX element. Later, for SHM, also the front
1520 * buffer will be released in the cleanup_list processing.
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);
1531 weston_buffer_reference(&surface->buffer_ref, buffer);
1534 struct rpi_renderer *renderer = to_rpi_renderer(base->compositor);
1535 struct wl_resource *wl_resource = buffer->resource;
1537 if (!renderer->has_bind_display ||
1538 !renderer->query_buffer(renderer->egl_display,
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;
1546 renderer->query_buffer(renderer->egl_display,
1548 EGL_HEIGHT, &buffer->height);
1550 surface->buffer_type = BUFFER_TYPE_EGL;
1552 if(surface->egl_back == NULL)
1553 surface->egl_back = calloc(1, sizeof *surface->egl_back);
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);
1559 weston_log("unhandled buffer type!\n");
1560 weston_buffer_reference(&surface->buffer_ref, NULL);
1561 surface->buffer_type = BUFFER_TYPE_NULL;
1567 rpir_surface_handle_surface_destroy(struct wl_listener *listener, void *data)
1569 struct rpir_surface *surface;
1570 struct weston_surface *base = data;
1572 surface = container_of(listener, struct rpir_surface,
1573 surface_destroy_listener);
1576 assert(surface->surface == base);
1580 surface->surface = NULL;
1581 base->renderer_state = NULL;
1583 if (wl_list_empty(&surface->views))
1584 rpir_surface_destroy(surface);
1588 rpi_renderer_create_surface(struct weston_surface *base)
1590 struct rpi_renderer *renderer = to_rpi_renderer(base->compositor);
1591 struct rpir_surface *surface;
1593 assert(base->renderer_state == NULL);
1595 surface = rpir_surface_create(renderer);
1599 surface->surface = base;
1600 base->renderer_state = surface;
1602 surface->surface_destroy_listener.notify =
1603 rpir_surface_handle_surface_destroy;
1604 wl_signal_add(&base->destroy_signal,
1605 &surface->surface_destroy_listener);
1611 rpi_renderer_create_view(struct weston_view *base)
1613 struct rpir_surface *surface = to_rpir_surface(base->surface);
1614 struct rpir_view *view;
1616 assert(base->renderer_state == NULL);
1618 view = rpir_view_create(surface);
1623 base->renderer_state = view;
1625 view->view_destroy_listener.notify =
1626 rpir_view_handle_view_destroy;
1627 wl_signal_add(&base->destroy_signal,
1628 &view->view_destroy_listener);
1634 rpi_renderer_surface_set_color(struct weston_surface *base,
1635 float red, float green, float blue, float alpha)
1637 struct rpir_surface *surface = to_rpir_surface(base);
1644 ret = rpi_resource_realloc(surface->back, VC_IMAGE_ARGB8888,
1647 weston_log("Error: %s: rpi_resource_realloc failed.\n",
1652 color[0] = float2uint8(blue);
1653 color[1] = float2uint8(green);
1654 color[2] = float2uint8(red);
1655 color[3] = float2uint8(alpha);
1657 vc_dispmanx_rect_set(&rect, 0, 0, 1, 1);
1658 ret = vc_dispmanx_resource_write_data(surface->back->handle,
1662 weston_log("Error: %s: resource_write_data failed.\n",
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]);
1670 /*pixman_region32_copy(&surface->prev_damage, damage);*/
1671 surface->need_swap = 1;
1675 rpir_view_handle_view_destroy(struct wl_listener *listener, void *data)
1677 struct rpir_view *view;
1678 struct weston_view *base = data;
1680 view = container_of(listener, struct rpir_view, view_destroy_listener);
1683 assert(view->view == base);
1688 base->renderer_state = NULL;
1690 /* If guaranteed to not be on screen, just destroy it. */
1691 if (wl_list_empty(&view->link))
1692 rpir_view_destroy(view);
1694 /* Otherwise, the view is either on screen and needs
1695 * to be removed by a repaint update, or it is in the
1696 * view_cleanup_list, and will be destroyed by
1697 * rpi_renderer_finish_frame().
1702 rpi_renderer_destroy(struct weston_compositor *compositor)
1704 struct rpi_renderer *renderer = to_rpi_renderer(compositor);
1707 if (renderer->has_bind_display)
1708 renderer->unbind_display(renderer->egl_display,
1709 compositor->wl_display);
1713 compositor->renderer = NULL;
1717 rpi_renderer_create(struct weston_compositor *compositor,
1718 const struct rpi_renderer_parameters *params)
1720 struct rpi_renderer *renderer;
1722 const char *extensions;
1724 EGLint major, minor;
1727 weston_log("Initializing the DispmanX compositing renderer\n");
1729 renderer = calloc(1, sizeof *renderer);
1730 if (renderer == NULL)
1733 renderer->single_buffer = params->single_buffer;
1734 renderer->enable_opaque_regions = params->opaque_regions;
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;
1740 renderer->base.surface_set_color = rpi_renderer_surface_set_color;
1741 renderer->base.destroy = rpi_renderer_destroy;
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");
1751 if (!eglInitialize(renderer->egl_display, &major, &minor)) {
1752 weston_log("failed to initialize EGL display\n");
1757 renderer->bind_display =
1758 (void *) eglGetProcAddress("eglBindWaylandDisplayWL");
1759 renderer->unbind_display =
1760 (void *) eglGetProcAddress("eglUnbindWaylandDisplayWL");
1761 renderer->query_buffer =
1762 (void *) eglGetProcAddress("eglQueryWaylandBufferWL");
1764 extensions = (const char *) eglQueryString(renderer->egl_display,
1767 weston_log("Retrieving EGL extension string failed.\n");
1768 eglTerminate(renderer->egl_display);
1773 if (strstr(extensions, "EGL_WL_bind_wayland_display"))
1774 renderer->has_bind_display = 1;
1776 if (renderer->has_bind_display) {
1777 ret = renderer->bind_display(renderer->egl_display,
1778 compositor->wl_display);
1780 renderer->has_bind_display = 0;
1784 compositor->renderer = &renderer->base;
1785 compositor->read_format = PIXMAN_a8r8g8b8;
1786 /* WESTON_CAP_ROTATION_ANY not supported */
1788 wl_display_add_shm_format(compositor->wl_display, WL_SHM_FORMAT_RGB565);
1794 rpi_renderer_output_create(struct weston_output *base,
1795 DISPMANX_DISPLAY_HANDLE_T display)
1797 struct rpir_output *output;
1799 assert(base->renderer_state == NULL);
1801 output = calloc(1, sizeof *output);
1805 output->display = display;
1806 output->update = DISPMANX_NO_HANDLE;
1807 wl_list_init(&output->view_list);
1808 wl_list_init(&output->view_cleanup_list);
1809 rpi_resource_init(&output->capture_buffer);
1810 base->renderer_state = output;
1816 rpi_renderer_output_destroy(struct weston_output *base)
1818 struct rpir_output *output = to_rpir_output(base);
1819 struct rpir_view *view;
1820 DISPMANX_UPDATE_HANDLE_T update;
1822 rpi_resource_release(&output->capture_buffer);
1823 free(output->capture_data);
1824 output->capture_data = NULL;
1826 update = vc_dispmanx_update_start(0);
1827 rpir_output_dmx_remove_all(output, update);
1828 vc_dispmanx_update_submit_sync(update);
1830 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);
1837 base->renderer_state = NULL;
1841 rpi_renderer_set_update_handle(struct weston_output *base,
1842 DISPMANX_UPDATE_HANDLE_T handle)
1844 struct rpir_output *output = to_rpir_output(base);
1846 output->update = handle;
1850 rpi_renderer_finish_frame(struct weston_output *base)
1852 struct rpir_output *output = to_rpir_output(base);
1853 struct weston_compositor *compositor = base->compositor;
1854 struct weston_view *wv;
1855 struct rpir_view *view;
1857 while (!wl_list_empty(&output->view_cleanup_list)) {
1858 view = container_of(output->view_cleanup_list.next,
1859 struct rpir_view, link);
1862 /* The weston_view still exists, but is
1863 * temporarily not visible, and hence its Element
1864 * was removed. The current front buffer contents
1865 * must be preserved.
1867 if (!view->surface->visible_views)
1868 rpi_resource_release(view->surface->back);
1870 wl_list_remove(&view->link);
1871 wl_list_init(&view->link);
1873 rpir_view_destroy(view);
1877 wl_list_for_each(wv, &compositor->view_list, link) {
1878 view = to_rpir_view(wv);
1880 if (view->surface->buffer_type != BUFFER_TYPE_EGL)
1883 rpir_egl_buffer_destroy(view->surface->egl_old_front);
1884 view->surface->egl_old_front = NULL;
1887 wl_signal_emit(&base->frame_signal, base);