On Tue, Oct 01, 2013 at 12:53:03PM +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.
Is this something you want in 1.3? We're the RC phase now and I hope to release 1.3 this Friday. However, for compositor-rpi.c I defer to you, Pekka and Daniel. We can apply this to master and ship with 1.3, but I can't test it or vouch for the quality, so it's up to you guys. Kristian > > Remaining issues: > > * The EGL side isn't sending sync messages from SwapBuffers while waiting > for buffer.release events, so it requires weston to post them inmediately. > It > has been tested with Neil's patch: > http://article.gmane.org/gmane.comp.freedesktop.wayland.devel/10769 > > * weston-subsurfaces doesn't work as expected because of the frame callbacks > starving the client's event loop: > http://thread.gmane.org/gmane.comp.freedesktop.wayland.devel/10959 > > src/rpi-renderer.c | 253 > +++++++++++++++++++++++++++++++++++++++++++++++------ > 1 file changed, 225 insertions(+), 28 deletions(-) > > diff --git a/src/rpi-renderer.c b/src/rpi-renderer.c > index 3ba5fc4..7a8558e 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); > > @@ -472,8 +504,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 +687,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 +725,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 +760,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 +778,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 +822,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 +913,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 +1234,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; > + } > > - /* XXX: need to check if in middle of update > - if (!buffer && !surface->single_buffer) > - rpi_resource_release(surface->back); */ > + renderer->query_buffer(renderer->egl_display, > + wl_resource, > + EGL_HEIGHT, &buffer->height); > > - /* XXX: cannot do this, if middle of an update > - if (surface->handle == DISPMANX_NO_HANDLE) > - rpi_resource_release(surface->front); */ > + surface->buffer_type = BUFFER_TYPE_EGL; > > - /* 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. > - */ > + if(surface->egl_back == NULL) > + surface->egl_back = calloc(1, sizeof > *surface->egl_back); > + > + 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 +1389,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 +1404,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 +1427,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 +1535,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 +1559,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 > [email protected] > http://lists.freedesktop.org/mailman/listinfo/wayland-devel _______________________________________________ wayland-devel mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/wayland-devel
