[PATCH weston v3] rpi: Add support for EGL buffers

Tomeu Vizoso tomeu at tomeuvizoso.net
Wed Oct 9 10:19:37 CEST 2013


On 8 October 2013 20:33, Kristian Høgsberg <hoegsberg at gmail.com> wrote:
> On Mon, Oct 07, 2013 at 11:02:20AM +0200, Tomeu Vizoso wrote:
>> The EGL implementation on the RPi allocates a front and a back
>> DispmanX resources for each EGLSurface, which we composite along
>> the others.
>> ---
>>
>> v2: Added a stub for vc_dispmanx_get_handle_from_wl_buffer
>> v3: Release any wl_buffers when their surface is destroyed
>
> Thanks Tomeu, committed and pushed this.  I get a couple of warnings
> when compiling:
>
> rpi-renderer.c:1297:10: note: expected 'struct wl_buffer *' but argument is of type 'struct wl_resource *'
> rpi-renderer.c:1305:12: warning: passing argument 2 of 'renderer->query_buffer' from incompatible pointer type [enabled by default]
>             EGL_HEIGHT, &buffer->height);
>             ^
> rpi-renderer.c:1305:12: note: expected 'struct wl_buffer *' but argument is of type 'struct wl_resource *'

Not sure what can still have wl_buffer in PFNEGLQUERYWAYLANDBUFFERWL,
maybe Mesa? I have checked and the three definitions I have of it on
my machine have wl_resource now.

Regards,

Tomeu

> Kristian
>
>>  src/rpi-bcm-stubs.h |   7 ++
>>  src/rpi-renderer.c  | 271 ++++++++++++++++++++++++++++++++++++++++++++++------
>>  2 files changed, 250 insertions(+), 28 deletions(-)
>>
>> diff --git a/src/rpi-bcm-stubs.h b/src/rpi-bcm-stubs.h
>> index d3ffd4b..703cd77 100644
>> --- a/src/rpi-bcm-stubs.h
>> +++ b/src/rpi-bcm-stubs.h
>> @@ -296,6 +296,13 @@ vc_dispmanx_snapshot(DISPMANX_DISPLAY_HANDLE_T display,
>>       return -1;
>>  }
>>
>> +struct wl_resource;
>> +static inline DISPMANX_RESOURCE_HANDLE_T
>> +vc_dispmanx_get_handle_from_wl_buffer(struct wl_resource *_buffer)
>> +{
>> +     return DISPMANX_NO_HANDLE;
>> +}
>> +
>>  /* from /opt/vc/include/EGL/eglplatform.h */
>>
>>  typedef struct {
>> diff --git a/src/rpi-renderer.c b/src/rpi-renderer.c
>> index 3ba5fc4..2660031 100644
>> --- a/src/rpi-renderer.c
>> +++ b/src/rpi-renderer.c
>> @@ -35,6 +35,12 @@
>>  #include "compositor.h"
>>  #include "rpi-renderer.h"
>>
>> +#ifdef ENABLE_EGL
>> +#include <EGL/egl.h>
>> +#include <EGL/eglext.h>
>> +#include "weston-egl-ext.h"
>> +#endif
>> +
>>  /*
>>   * Dispmanx API offers alpha-blended overlays for hardware compositing.
>>   * The final composite consists of dispmanx elements, and their contents:
>> @@ -84,6 +90,17 @@ struct rpi_resource {
>>
>>  struct rpir_output;
>>
>> +struct rpir_egl_buffer {
>> +     struct weston_buffer_reference buffer_ref;
>> +     DISPMANX_RESOURCE_HANDLE_T resource_handle;
>> +};
>> +
>> +enum buffer_type {
>> +     BUFFER_TYPE_NULL,
>> +     BUFFER_TYPE_SHM,
>> +     BUFFER_TYPE_EGL
>> +};
>> +
>>  struct rpir_surface {
>>       struct weston_surface *surface;
>>
>> @@ -102,7 +119,12 @@ struct rpir_surface {
>>       struct rpi_resource *back;
>>       pixman_region32_t prev_damage;
>>
>> +     struct rpir_egl_buffer *egl_front;
>> +     struct rpir_egl_buffer *egl_back;
>> +     struct rpir_egl_buffer *egl_old_front;
>> +
>>       struct weston_buffer_reference buffer_ref;
>> +     enum buffer_type buffer_type;
>>  };
>>
>>  struct rpir_output {
>> @@ -125,6 +147,15 @@ struct rpi_renderer {
>>       struct weston_renderer base;
>>
>>       int single_buffer;
>> +
>> +#ifdef ENABLE_EGL
>> +     EGLDisplay egl_display;
>> +
>> +     PFNEGLBINDWAYLANDDISPLAYWL bind_display;
>> +     PFNEGLUNBINDWAYLANDDISPLAYWL unbind_display;
>> +     PFNEGLQUERYWAYLANDBUFFERWL query_buffer;
>> +#endif
>> +     int has_bind_display;
>>  };
>>
>>  static inline struct rpir_surface *
>> @@ -335,6 +366,7 @@ rpir_surface_create(struct rpi_renderer *renderer)
>>               surface->back = &surface->resources[0];
>>       else
>>               surface->back = &surface->resources[1];
>> +     surface->buffer_type = BUFFER_TYPE_NULL;
>>
>>       pixman_region32_init(&surface->prev_damage);
>>
>> @@ -354,6 +386,24 @@ rpir_surface_destroy(struct rpir_surface *surface)
>>       rpi_resource_release(&surface->resources[1]);
>>       DBG("rpir_surface %p destroyed (%u)\n", surface, surface->handle);
>>
>> +     if (surface->egl_back != NULL) {
>> +             weston_buffer_reference(&surface->egl_back->buffer_ref, NULL);
>> +             free(surface->egl_back);
>> +             surface->egl_back = NULL;
>> +     }
>> +
>> +     if (surface->egl_front != NULL) {
>> +             weston_buffer_reference(&surface->egl_front->buffer_ref, NULL);
>> +             free(surface->egl_front);
>> +             surface->egl_front = NULL;
>> +     }
>> +
>> +     if (surface->egl_old_front != NULL) {
>> +             weston_buffer_reference(&surface->egl_old_front->buffer_ref, NULL);
>> +             free(surface->egl_old_front);
>> +             surface->egl_old_front = NULL;
>> +     }
>> +
>>       free(surface);
>>  }
>>
>> @@ -472,8 +522,16 @@ rpir_surface_compute_rects(struct rpir_surface *surface,
>>
>>       src_x = 0 << 16;
>>       src_y = 0 << 16;
>> -     src_width = surface->front->width << 16;
>> -     src_height = surface->front->height << 16;
>> +
>> +     if (surface->buffer_type == BUFFER_TYPE_EGL) {
>> +             struct weston_buffer *buffer = surface->egl_front->buffer_ref.buffer;
>> +
>> +             src_width = buffer->width << 16;
>> +             src_height = buffer->height << 16;
>> +     } else {
>> +             src_width = surface->front->width << 16;
>> +             src_height = surface->front->height << 16;
>> +     }
>>
>>       weston_matrix_multiply(&matrix, &output->matrix);
>>
>> @@ -647,6 +705,10 @@ rpir_surface_compute_rects(struct rpir_surface *surface,
>>               return -1;
>>       }
>>
>> +     /* EGL buffers will be upside-down related to what DispmanX expects */
>> +     if (surface->buffer_type == BUFFER_TYPE_EGL)
>> +             flipt ^= TRANSFORM_VFLIP;
>> +
>>       vc_dispmanx_rect_set(src_rect, src_x, src_y, src_width, src_height);
>>       vc_dispmanx_rect_set(dst_rect, dst_x, dst_y, dst_width, dst_height);
>>       *flipmask = flipt;
>> @@ -681,6 +743,22 @@ vc_image2dispmanx_transform(VC_IMAGE_TRANSFORM_T t)
>>       }
>>  }
>>
>> +
>> +static DISPMANX_RESOURCE_HANDLE_T
>> +rpir_surface_get_resource(struct rpir_surface *surface)
>> +{
>> +     switch (surface->buffer_type) {
>> +     case BUFFER_TYPE_SHM:
>> +     case BUFFER_TYPE_NULL:
>> +             return surface->front->handle;
>> +     case BUFFER_TYPE_EGL:
>> +             if (surface->egl_front != NULL)
>> +                     return surface->egl_front->resource_handle;
>> +     default:
>> +             return DISPMANX_NO_HANDLE;
>> +     }
>> +}
>> +
>>  static int
>>  rpir_surface_dmx_add(struct rpir_surface *surface, struct rpir_output *output,
>>                   DISPMANX_UPDATE_HANDLE_T update, int layer)
>> @@ -700,6 +778,13 @@ rpir_surface_dmx_add(struct rpir_surface *surface, struct rpir_output *output,
>>       VC_RECT_T src_rect;
>>       VC_IMAGE_TRANSFORM_T flipmask;
>>       int ret;
>> +     DISPMANX_RESOURCE_HANDLE_T resource_handle;
>> +
>> +     resource_handle = rpir_surface_get_resource(surface);
>> +     if (resource_handle == DISPMANX_NO_HANDLE) {
>> +             weston_log("%s: no buffer yet, aborting\n", __func__);
>> +             return 0;
>> +     }
>>
>>       ret = rpir_surface_compute_rects(surface, &src_rect, &dst_rect,
>>                                        &flipmask);
>> @@ -711,17 +796,14 @@ rpir_surface_dmx_add(struct rpir_surface *surface, struct rpir_output *output,
>>               output->display,
>>               layer,
>>               &dst_rect,
>> -             surface->front->handle,
>> +             resource_handle,
>>               &src_rect,
>>               DISPMANX_PROTECTION_NONE,
>>               &alphasetup,
>>               NULL /* clamp */,
>>               vc_image2dispmanx_transform(flipmask));
>> -     DBG("rpir_surface %p add %u, alpha %f\n", surface, surface->handle,
>> -         surface->surface->alpha);
>> -
>> -     if (surface->handle == DISPMANX_NO_HANDLE)
>> -             return -1;
>> +     DBG("rpir_surface %p add %u, alpha %f resource %d\n", surface,
>> +         surface->handle, surface->surface->alpha, resource_handle);
>>
>>       return 1;
>>  }
>> @@ -758,6 +840,20 @@ rpir_surface_dmx_move(struct rpir_surface *surface,
>>
>>       /* XXX: return early, if all attributes stay the same */
>>
>> +     if (surface->buffer_type == BUFFER_TYPE_EGL) {
>> +             DISPMANX_RESOURCE_HANDLE_T resource_handle;
>> +
>> +             resource_handle = rpir_surface_get_resource(surface);
>> +             if (resource_handle == DISPMANX_NO_HANDLE) {
>> +                     weston_log("%s: no buffer yet, aborting\n", __func__);
>> +                     return 0;
>> +             }
>> +
>> +             vc_dispmanx_element_change_source(update,
>> +                                               surface->handle,
>> +                                               resource_handle);
>> +     }
>> +
>>       ret = rpir_surface_compute_rects(surface, &src_rect, &dst_rect,
>>                                        &flipmask);
>>       if (ret < 0)
>> @@ -835,8 +931,31 @@ rpir_surface_update(struct rpir_surface *surface, struct rpir_output *output,
>>       int ret;
>>       int obscured;
>>
>> -     if (need_swap)
>> -             rpir_surface_swap_pointers(surface);
>> +     if (surface->buffer_type == BUFFER_TYPE_EGL) {
>> +             if (surface->egl_back != NULL) {
>> +                     assert(surface->egl_old_front == NULL);
>> +                     surface->egl_old_front = surface->egl_front;
>> +                     surface->egl_front = surface->egl_back;
>> +                     surface->egl_back = NULL;
>> +             }
>> +             if (surface->egl_front->buffer_ref.buffer == NULL) {
>> +                     weston_log("warning: client unreffed current front buffer\n");
>> +
>> +                     wl_list_remove(&surface->link);
>> +                     if (surface->handle == DISPMANX_NO_HANDLE) {
>> +                             wl_list_init(&surface->link);
>> +                     } else {
>> +                             rpir_surface_dmx_remove(surface, update);
>> +                             wl_list_insert(&output->surface_cleanup_list,
>> +                                                &surface->link);
>> +                     }
>> +
>> +                     goto out;
>> +             }
>> +     } else {
>> +             if (need_swap)
>> +                     rpir_surface_swap_pointers(surface);
>> +     }
>>
>>       obscured = is_surface_not_visible(surface->surface);
>>       if (obscured) {
>> @@ -1133,40 +1252,72 @@ static void
>>  rpi_renderer_attach(struct weston_surface *base, struct weston_buffer *buffer)
>>  {
>>       /* Called every time a client commits an attach. */
>> -     static int warned;
>>       struct rpir_surface *surface = to_rpir_surface(base);
>>
>>       assert(surface);
>>       if (!surface)
>>               return;
>>
>> -     if (buffer && !wl_shm_buffer_get(buffer->resource) && !warned) {
>> -             weston_log("Error: non-wl_shm buffers not supported.\n");
>> -             warned = 1;
>> -             return;
>> +     if (surface->buffer_type == BUFFER_TYPE_SHM) {
>> +             if (!surface->single_buffer)
>> +                     /* XXX: need to check if in middle of update */
>> +                     rpi_resource_release(surface->back);
>> +
>> +             if (surface->handle == DISPMANX_NO_HANDLE)
>> +                     /* XXX: cannot do this, if middle of an update */
>> +                     rpi_resource_release(surface->front);
>> +
>> +             weston_buffer_reference(&surface->buffer_ref, NULL);
>>       }
>>
>> +     /* If buffer is NULL, Weston core unmaps the surface, the surface
>> +      * will not appear in repaint list, and so rpi_renderer_repaint_output
>> +      * will remove the DispmanX element. Later, for SHM, also the front
>> +      * buffer will be released in the cleanup_list processing.
>> +      */
>> +     if (!buffer)
>> +             return;
>> +
>>       if (wl_shm_buffer_get(buffer->resource)) {
>> +             surface->buffer_type = BUFFER_TYPE_SHM;
>>               buffer->shm_buffer = wl_shm_buffer_get(buffer->resource);
>>               buffer->width = wl_shm_buffer_get_width(buffer->shm_buffer);
>>               buffer->height = wl_shm_buffer_get_height(buffer->shm_buffer);
>> -     }
>>
>> -     weston_buffer_reference(&surface->buffer_ref, buffer);
>> +             weston_buffer_reference(&surface->buffer_ref, buffer);
>> +     } else {
>> +#if ENABLE_EGL
>> +             struct rpi_renderer *renderer = to_rpi_renderer(base->compositor);
>> +             struct wl_resource *wl_resource =
>> +                     (struct wl_resource *)buffer->resource;
>> +
>> +             if (!renderer->has_bind_display ||
>> +                 !renderer->query_buffer(renderer->egl_display,
>> +                                         wl_resource,
>> +                                         EGL_WIDTH, &buffer->width)) {
>> +                     weston_log("unhandled buffer type!\n");
>> +                     weston_buffer_reference(&surface->buffer_ref, NULL);
>> +                     surface->buffer_type = BUFFER_TYPE_NULL;
>> +             }
>> +
>> +             renderer->query_buffer(renderer->egl_display,
>> +                                    wl_resource,
>> +                                    EGL_HEIGHT, &buffer->height);
>>
>> -     /* XXX: need to check if in middle of update
>> -     if (!buffer && !surface->single_buffer)
>> -             rpi_resource_release(surface->back); */
>> +             surface->buffer_type = BUFFER_TYPE_EGL;
>>
>> -     /* XXX: cannot do this, if middle of an update
>> -     if (surface->handle == DISPMANX_NO_HANDLE)
>> -             rpi_resource_release(surface->front); */
>> +             if(surface->egl_back == NULL)
>> +                     surface->egl_back = calloc(1, sizeof *surface->egl_back);
>>
>> -     /* If buffer is NULL, Weston core unmaps the surface, the surface
>> -      * will not appear in repaint list, and so rpi_renderer_repaint_output
>> -      * will remove the DispmanX element. Later, also the front buffer
>> -      * will be released in the cleanup_list processing.
>> -      */
>> +             weston_buffer_reference(&surface->egl_back->buffer_ref, buffer);
>> +             surface->egl_back->resource_handle =
>> +                     vc_dispmanx_get_handle_from_wl_buffer(wl_resource);
>> +#else
>> +             weston_log("unhandled buffer type!\n");
>> +             weston_buffer_reference(&surface->buffer_ref, NULL);
>> +             surface->buffer_type = BUFFER_TYPE_NULL;
>> +#endif
>> +     }
>>  }
>>
>>  static int
>> @@ -1256,6 +1407,12 @@ rpi_renderer_destroy(struct weston_compositor *compositor)
>>  {
>>       struct rpi_renderer *renderer = to_rpi_renderer(compositor);
>>
>> +#if ENABLE_EGL
>> +     if (renderer->has_bind_display)
>> +             renderer->unbind_display(renderer->egl_display,
>> +                                      compositor->wl_display);
>> +#endif
>> +
>>       free(renderer);
>>       compositor->renderer = NULL;
>>  }
>> @@ -1265,6 +1422,11 @@ rpi_renderer_create(struct weston_compositor *compositor,
>>                   const struct rpi_renderer_parameters *params)
>>  {
>>       struct rpi_renderer *renderer;
>> +#if ENABLE_EGL
>> +     const char *extensions;
>> +     EGLBoolean ret;
>> +     EGLint major, minor;
>> +#endif
>>
>>       weston_log("Initializing the DispmanX compositing renderer\n");
>>
>> @@ -1283,6 +1445,43 @@ rpi_renderer_create(struct weston_compositor *compositor,
>>       renderer->base.destroy_surface = rpi_renderer_destroy_surface;
>>       renderer->base.destroy = rpi_renderer_destroy;
>>
>> +#ifdef ENABLE_EGL
>> +     renderer->egl_display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
>> +     if (renderer->egl_display == EGL_NO_DISPLAY) {
>> +             weston_log("failed to create EGL display\n");
>> +             return -1;
>> +     }
>> +
>> +     if (!eglInitialize(renderer->egl_display, &major, &minor)) {
>> +             weston_log("failed to initialize EGL display\n");
>> +             return -1;
>> +     }
>> +
>> +     renderer->bind_display =
>> +             (void *) eglGetProcAddress("eglBindWaylandDisplayWL");
>> +     renderer->unbind_display =
>> +             (void *) eglGetProcAddress("eglUnbindWaylandDisplayWL");
>> +     renderer->query_buffer =
>> +             (void *) eglGetProcAddress("eglQueryWaylandBufferWL");
>> +
>> +     extensions = (const char *) eglQueryString(renderer->egl_display,
>> +                                                EGL_EXTENSIONS);
>> +     if (!extensions) {
>> +             weston_log("Retrieving EGL extension string failed.\n");
>> +             return -1;
>> +     }
>> +
>> +     if (strstr(extensions, "EGL_WL_bind_wayland_display"))
>> +             renderer->has_bind_display = 1;
>> +
>> +     if (renderer->has_bind_display) {
>> +             ret = renderer->bind_display(renderer->egl_display,
>> +                                          compositor->wl_display);
>> +             if (!ret)
>> +                     renderer->has_bind_display = 0;
>> +     }
>> +#endif
>> +
>>       compositor->renderer = &renderer->base;
>>       compositor->read_format = PIXMAN_a8r8g8b8;
>>       /* WESTON_CAP_ROTATION_ANY not supported */
>> @@ -1354,6 +1553,8 @@ WL_EXPORT void
>>  rpi_renderer_finish_frame(struct weston_output *base)
>>  {
>>       struct rpir_output *output = to_rpir_output(base);
>> +     struct weston_compositor *compositor = base->compositor;
>> +     struct weston_surface *ws;
>>       struct rpir_surface *surface;
>>
>>       while (!wl_list_empty(&output->surface_cleanup_list)) {
>> @@ -1376,5 +1577,19 @@ rpi_renderer_finish_frame(struct weston_output *base)
>>               }
>>       }
>>
>> +     wl_list_for_each(ws, &compositor->surface_list, link) {
>> +             surface = to_rpir_surface(ws);
>> +
>> +             if (surface->buffer_type != BUFFER_TYPE_EGL)
>> +                     continue;
>> +
>> +             if(surface->egl_old_front == NULL)
>> +                     continue;
>> +
>> +             weston_buffer_reference(&surface->egl_old_front->buffer_ref, NULL);
>> +             free(surface->egl_old_front);
>> +             surface->egl_old_front = NULL;
>> +     }
>> +
>>       wl_signal_emit(&base->frame_signal, base);
>>  }
>> --
>> 1.8.3.1
>>
>> _______________________________________________
>> wayland-devel mailing list
>> wayland-devel at lists.freedesktop.org
>> http://lists.freedesktop.org/mailman/listinfo/wayland-devel


More information about the wayland-devel mailing list