gl-renderer: add dmabuf renderbuffer support
Support importing dmabuf buffers as renderbuffers and binding them to FBOs. These can then be rendered to directly, or they can be blitted into from the shadow render buffer. How to best create those dmabuf buffers in the backend is an open question and may vary depending on what external API the backend is interfacing with. Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
This commit is contained in:
parent
c9c4549064
commit
5a779b7804
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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");
|
||||
|
|
Loading…
Reference in New Issue