diff --git a/libweston/libweston-internal.h b/libweston/libweston-internal.h index d92bf63d8..2053361cb 100644 --- a/libweston/libweston-internal.h +++ b/libweston/libweston-internal.h @@ -62,6 +62,12 @@ weston_renderbuffer_unref(struct weston_renderbuffer *renderbuffer); struct weston_renderer_options { }; +struct linux_dmabuf_memory { + struct dmabuf_attributes *attributes; + + void (*destroy)(struct linux_dmabuf_memory *dmabuf); +}; + struct weston_renderer { int (*read_pixels)(struct weston_output *output, const struct pixel_format_info *format, void *pixels, @@ -102,6 +108,40 @@ struct weston_renderer { void (*buffer_init)(struct weston_compositor *ec, struct weston_buffer *buffer); + /** + * Add DMABUF as renderbuffer to the output + * + * \param output The output to add the DMABUF renderbuffer for. + * \param dmabuf The description object of the DMABUF to import. + * \return A weston_renderbuffer on success, NULL on failure. + * + * This function imports the DMABUF memory as renderbuffer and adds + * it to the output. The returned weston_renderbuffer can be passed to + * repaint_output() to render into the DMABUF. + * + * The ownership of the linux_dmabuf_memory is transferred to the + * returned weston_renderbuffer. The linux_dmabuf_memory will be + * destroyed automatically when the weston_renderbuffer is destroyed. + */ + struct weston_renderbuffer * + (*create_renderbuffer_dmabuf)(struct weston_output *output, + struct linux_dmabuf_memory *dmabuf); + + /** + * Remove the DAMBUF renderbuffer from the output + * + * \param output The output to remove a DMABUF renderbuffer from. + * \param renderbuffer The weston_renderbuffer that shall be removed + * + * This function removes the DMABUF renderbuffer from the output. + * + * This allows the backend to signal the renderer that it will no longer + * use the renderbuffer for rendering and the renderer may free the + * resources of the renderbuffer. + */ + void (*remove_renderbuffer_dmabuf)(struct weston_output *output, + struct weston_renderbuffer *renderbuffer); + enum weston_renderer_type type; const struct gl_renderer_interface *gl; const struct pixman_renderer_interface *pixman; diff --git a/libweston/renderer-gl/gl-renderer-internal.h b/libweston/renderer-gl/gl-renderer-internal.h index 1e489e2f6..58c84d1af 100644 --- a/libweston/renderer-gl/gl-renderer-internal.h +++ b/libweston/renderer-gl/gl-renderer-internal.h @@ -193,6 +193,7 @@ struct gl_renderer { PFNGLEGLIMAGETARGETTEXTURE2DOESPROC image_target_texture_2d; PFNGLTEXIMAGE3DOESPROC tex_image_3d; + PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC image_target_renderbuffer_storage; PFNEGLCREATEIMAGEKHRPROC create_image; PFNEGLDESTROYIMAGEKHRPROC destroy_image; PFNEGLSWAPBUFFERSWITHDAMAGEEXTPROC swap_buffers_with_damage; diff --git a/libweston/renderer-gl/gl-renderer.c b/libweston/renderer-gl/gl-renderer.c index 803d26230..382f91266 100644 --- a/libweston/renderer-gl/gl-renderer.c +++ b/libweston/renderer-gl/gl-renderer.c @@ -148,6 +148,14 @@ struct gl_capture_task { int fd; }; +struct dmabuf_renderbuffer { + struct gl_renderbuffer base; + struct gl_renderer *gr; + /* The wrapped dmabuf memory */ + struct linux_dmabuf_memory *dmabuf; + EGLImageKHR image; +}; + struct dmabuf_format { uint32_t format; struct wl_list link; @@ -597,6 +605,12 @@ to_gl_renderbuffer(struct weston_renderbuffer *renderbuffer) return container_of(renderbuffer, struct gl_renderbuffer, base); } +static inline struct dmabuf_renderbuffer * +to_dmabuf_renderbuffer(struct gl_renderbuffer *renderbuffer) +{ + return container_of(renderbuffer, struct dmabuf_renderbuffer, base); +} + static void gl_renderer_renderbuffer_destroy(struct weston_renderbuffer *renderbuffer) { @@ -4157,6 +4171,100 @@ gl_renderer_output_fbo_create(struct weston_output *output, &options->fb_size, &options->area); } +static void +gl_renderer_dmabuf_renderbuffer_destroy(struct weston_renderbuffer *renderbuffer) +{ + struct gl_renderbuffer *gl_renderbuffer = to_gl_renderbuffer(renderbuffer); + struct dmabuf_renderbuffer *dmabuf_renderbuffer = to_dmabuf_renderbuffer(gl_renderbuffer); + struct gl_renderer *gr = dmabuf_renderbuffer->gr; + + glDeleteFramebuffers(1, &gl_renderbuffer->fbo); + glDeleteRenderbuffers(1, &gl_renderbuffer->rb); + pixman_region32_fini(&gl_renderbuffer->base.damage); + + gr->destroy_image(gr->egl_display, dmabuf_renderbuffer->image); + + /* Destroy the owned dmabuf */ + dmabuf_renderbuffer->dmabuf->destroy(dmabuf_renderbuffer->dmabuf); + + free(dmabuf_renderbuffer); +} + +static struct weston_renderbuffer * +gl_renderer_create_renderbuffer_dmabuf(struct weston_output *output, + struct linux_dmabuf_memory *dmabuf) +{ + struct gl_renderer *gr = get_renderer(output->compositor); + struct gl_output_state *go = get_output_state(output); + struct dmabuf_attributes *attributes = dmabuf->attributes; + struct dmabuf_renderbuffer *rb; + struct gl_renderbuffer *renderbuffer; + int fb_status; + + rb = xzalloc(sizeof(*rb)); + renderbuffer = &rb->base; + + rb->image = import_simple_dmabuf(gr, attributes); + if (rb->image == EGL_NO_IMAGE_KHR) { + weston_log("Failed to import dmabuf renderbuffer\n"); + free(rb); + return NULL; + } + + glGenFramebuffers(1, &renderbuffer->fbo); + glBindFramebuffer(GL_FRAMEBUFFER, renderbuffer->fbo); + + glGenRenderbuffers(1, &renderbuffer->rb); + glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer->rb); + gr->image_target_renderbuffer_storage(GL_RENDERBUFFER, rb->image); + if (glGetError() == GL_INVALID_OPERATION) { + weston_log("Failed to create renderbuffer\n"); + glBindRenderbuffer(GL_RENDERBUFFER, 0); + glDeleteRenderbuffers(1, &renderbuffer->rb); + gr->destroy_image(gr->egl_display, rb->image); + free(rb); + return NULL; + } + + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + GL_RENDERBUFFER, renderbuffer->rb); + + fb_status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glBindRenderbuffer(GL_RENDERBUFFER, 0); + if (fb_status != GL_FRAMEBUFFER_COMPLETE) { + weston_log("failed to bind renderbuffer to fbo\n"); + glDeleteFramebuffers(1, &renderbuffer->fbo); + glDeleteRenderbuffers(1, &renderbuffer->rb); + gr->destroy_image(gr->egl_display, rb->image); + free(rb); + return NULL; + } + + rb->gr = gr; + rb->dmabuf = dmabuf; + + pixman_region32_init(&rb->base.base.damage); + /* + * One reference is kept on the renderbuffer_list, + * the other is returned to the calling backend. + */ + rb->base.base.refcount = 2; + rb->base.base.destroy = gl_renderer_dmabuf_renderbuffer_destroy; + wl_list_insert(&go->renderbuffer_list, &rb->base.link); + + return &rb->base.base; +} + +static void +gl_renderer_remove_renderbuffer_dmabuf(struct weston_output *output, + struct weston_renderbuffer *renderbuffer) +{ + struct gl_renderbuffer *gl_renderbuffer = to_gl_renderbuffer(renderbuffer); + + gl_renderer_remove_renderbuffer(gl_renderbuffer); +} + static void gl_renderer_output_destroy(struct weston_output *output) { @@ -4366,6 +4474,8 @@ gl_renderer_display_create(struct weston_compositor *ec, if (gr->has_dmabuf_import) { gr->base.import_dmabuf = gl_renderer_import_dmabuf; gr->base.get_supported_formats = gl_renderer_get_supported_formats; + gr->base.create_renderbuffer_dmabuf = gl_renderer_create_renderbuffer_dmabuf; + gr->base.remove_renderbuffer_dmabuf = gl_renderer_remove_renderbuffer_dmabuf; ret = populate_supported_formats(ec, &gr->supported_formats); if (ret < 0) goto fail_terminate; @@ -4562,6 +4672,9 @@ gl_renderer_setup(struct weston_compositor *ec) gr->image_target_texture_2d = (void *) eglGetProcAddress("glEGLImageTargetTexture2DOES"); + gr->image_target_renderbuffer_storage = + (void *)eglGetProcAddress("glEGLImageTargetRenderbufferStorageOES"); + extensions = (const char *) glGetString(GL_EXTENSIONS); if (!extensions) { weston_log("Retrieving GL extension string failed.\n");