gl-renderer: introduce a new struct dmabuf_image

This struct serves as renderer data for linux-dmabuf buffers, and can
contain multiple struct egl_image, simplifying this latter in the
common non-dmabuf case.

Signed-off-by: Emmanuel Gil Peyrot <emmanuel.peyrot@collabora.com>
Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk>
Reviewed-by: Daniel Stone <daniels@collabora.com>
Reviewed-by: Derek Foreman <derekf@osg.samsung.com>

Differential Revision: https://phabricator.freedesktop.org/D333
This commit is contained in:
Emmanuel Gil Peyrot 2016-01-11 19:04:34 +00:00 committed by Derek Foreman
parent c9626a38c4
commit b8053505f4

View File

@ -99,9 +99,12 @@ struct egl_image {
struct gl_renderer *renderer; struct gl_renderer *renderer;
EGLImageKHR image; EGLImageKHR image;
int refcount; int refcount;
};
/* Only used for dmabuf imported buffer */ struct dmabuf_image {
struct linux_dmabuf_buffer *dmabuf; struct linux_dmabuf_buffer *dmabuf;
int num_images;
struct egl_image *images[3];
struct wl_list link; struct wl_list link;
}; };
@ -191,6 +194,16 @@ struct gl_renderer {
static PFNEGLGETPLATFORMDISPLAYEXTPROC get_platform_display = NULL; static PFNEGLGETPLATFORMDISPLAYEXTPROC get_platform_display = NULL;
static inline const char *
dump_format(uint32_t format, char out[4])
{
#if BYTE_ORDER == BIG_ENDIAN
format = __builtin_bswap32(format);
#endif
memcpy(out, &format, 4);
return out;
}
static inline struct gl_output_state * static inline struct gl_output_state *
get_output_state(struct weston_output *output) get_output_state(struct weston_output *output)
{ {
@ -222,7 +235,6 @@ egl_image_create(struct gl_renderer *gr, EGLenum target,
struct egl_image *img; struct egl_image *img;
img = zalloc(sizeof *img); img = zalloc(sizeof *img);
wl_list_init(&img->link);
img->renderer = gr; img->renderer = gr;
img->refcount = 1; img->refcount = 1;
img->image = gr->create_image(gr->egl_display, EGL_NO_CONTEXT, img->image = gr->create_image(gr->egl_display, EGL_NO_CONTEXT,
@ -255,16 +267,37 @@ egl_image_unref(struct egl_image *image)
if (image->refcount > 0) if (image->refcount > 0)
return image->refcount; return image->refcount;
if (image->dmabuf)
linux_dmabuf_buffer_set_user_data(image->dmabuf, NULL, NULL);
gr->destroy_image(gr->egl_display, image->image); gr->destroy_image(gr->egl_display, image->image);
wl_list_remove(&image->link);
free(image); free(image);
return 0; return 0;
} }
static struct dmabuf_image*
dmabuf_image_create(void)
{
struct dmabuf_image *img;
img = zalloc(sizeof *img);
wl_list_init(&img->link);
return img;
}
static void
dmabuf_image_destroy(struct dmabuf_image *image)
{
int i;
for (i = 0; i < image->num_images; ++i)
egl_image_unref(image->images[i]);
if (image->dmabuf)
linux_dmabuf_buffer_set_user_data(image->dmabuf, NULL, NULL);
wl_list_remove(&image->link);
}
static const char * static const char *
egl_error_string(EGLint code) egl_error_string(EGLint code)
{ {
@ -1420,23 +1453,19 @@ gl_renderer_attach_egl(struct weston_surface *es, struct weston_buffer *buffer,
static void static void
gl_renderer_destroy_dmabuf(struct linux_dmabuf_buffer *dmabuf) gl_renderer_destroy_dmabuf(struct linux_dmabuf_buffer *dmabuf)
{ {
struct egl_image *image = dmabuf->user_data; struct dmabuf_image *image = dmabuf->user_data;
egl_image_unref(image); dmabuf_image_destroy(image);
} }
static struct egl_image * static struct egl_image *
import_dmabuf(struct gl_renderer *gr, import_simple_dmabuf(struct gl_renderer *gr,
struct linux_dmabuf_buffer *dmabuf) struct dmabuf_attributes *attributes)
{ {
struct egl_image *image; struct egl_image *image;
EGLint attribs[30]; EGLint attribs[30];
int atti = 0; int atti = 0;
image = linux_dmabuf_buffer_get_user_data(dmabuf);
if (image)
return egl_image_ref(image);
/* This requires the Mesa commit in /* This requires the Mesa commit in
* Mesa 10.3 (08264e5dad4df448e7718e782ad9077902089a07) or * Mesa 10.3 (08264e5dad4df448e7718e782ad9077902089a07) or
* Mesa 10.2.7 (55d28925e6109a4afd61f109e845a8a51bd17652). * Mesa 10.2.7 (55d28925e6109a4afd61f109e845a8a51bd17652).
@ -1446,38 +1475,38 @@ import_dmabuf(struct gl_renderer *gr,
*/ */
attribs[atti++] = EGL_WIDTH; attribs[atti++] = EGL_WIDTH;
attribs[atti++] = dmabuf->attributes.width; attribs[atti++] = attributes->width;
attribs[atti++] = EGL_HEIGHT; attribs[atti++] = EGL_HEIGHT;
attribs[atti++] = dmabuf->attributes.height; attribs[atti++] = attributes->height;
attribs[atti++] = EGL_LINUX_DRM_FOURCC_EXT; attribs[atti++] = EGL_LINUX_DRM_FOURCC_EXT;
attribs[atti++] = dmabuf->attributes.format; attribs[atti++] = attributes->format;
/* XXX: Add modifier here when supported */ /* XXX: Add modifier here when supported */
if (dmabuf->attributes.n_planes > 0) { if (attributes->n_planes > 0) {
attribs[atti++] = EGL_DMA_BUF_PLANE0_FD_EXT; attribs[atti++] = EGL_DMA_BUF_PLANE0_FD_EXT;
attribs[atti++] = dmabuf->attributes.fd[0]; attribs[atti++] = attributes->fd[0];
attribs[atti++] = EGL_DMA_BUF_PLANE0_OFFSET_EXT; attribs[atti++] = EGL_DMA_BUF_PLANE0_OFFSET_EXT;
attribs[atti++] = dmabuf->attributes.offset[0]; attribs[atti++] = attributes->offset[0];
attribs[atti++] = EGL_DMA_BUF_PLANE0_PITCH_EXT; attribs[atti++] = EGL_DMA_BUF_PLANE0_PITCH_EXT;
attribs[atti++] = dmabuf->attributes.stride[0]; attribs[atti++] = attributes->stride[0];
} }
if (dmabuf->attributes.n_planes > 1) { if (attributes->n_planes > 1) {
attribs[atti++] = EGL_DMA_BUF_PLANE1_FD_EXT; attribs[atti++] = EGL_DMA_BUF_PLANE1_FD_EXT;
attribs[atti++] = dmabuf->attributes.fd[1]; attribs[atti++] = attributes->fd[1];
attribs[atti++] = EGL_DMA_BUF_PLANE1_OFFSET_EXT; attribs[atti++] = EGL_DMA_BUF_PLANE1_OFFSET_EXT;
attribs[atti++] = dmabuf->attributes.offset[1]; attribs[atti++] = attributes->offset[1];
attribs[atti++] = EGL_DMA_BUF_PLANE1_PITCH_EXT; attribs[atti++] = EGL_DMA_BUF_PLANE1_PITCH_EXT;
attribs[atti++] = dmabuf->attributes.stride[1]; attribs[atti++] = attributes->stride[1];
} }
if (dmabuf->attributes.n_planes > 2) { if (attributes->n_planes > 2) {
attribs[atti++] = EGL_DMA_BUF_PLANE2_FD_EXT; attribs[atti++] = EGL_DMA_BUF_PLANE2_FD_EXT;
attribs[atti++] = dmabuf->attributes.fd[2]; attribs[atti++] = attributes->fd[2];
attribs[atti++] = EGL_DMA_BUF_PLANE2_OFFSET_EXT; attribs[atti++] = EGL_DMA_BUF_PLANE2_OFFSET_EXT;
attribs[atti++] = dmabuf->attributes.offset[2]; attribs[atti++] = attributes->offset[2];
attribs[atti++] = EGL_DMA_BUF_PLANE2_PITCH_EXT; attribs[atti++] = EGL_DMA_BUF_PLANE2_PITCH_EXT;
attribs[atti++] = dmabuf->attributes.stride[2]; attribs[atti++] = attributes->stride[2];
} }
attribs[atti++] = EGL_NONE; attribs[atti++] = EGL_NONE;
@ -1485,14 +1514,28 @@ import_dmabuf(struct gl_renderer *gr,
image = egl_image_create(gr, EGL_LINUX_DMA_BUF_EXT, NULL, image = egl_image_create(gr, EGL_LINUX_DMA_BUF_EXT, NULL,
attribs); attribs);
if (!image) return image;
return NULL; }
/* The cache owns one ref. The caller gets another. */ static struct dmabuf_image *
import_dmabuf(struct gl_renderer *gr,
struct linux_dmabuf_buffer *dmabuf)
{
struct egl_image *egl_image;
struct dmabuf_image *image;
char fmt[4];
egl_image = import_simple_dmabuf(gr, &dmabuf->attributes);
if (!egl_image) {
weston_log("Format %.4s unsupported by EGL, aborting\n",
dump_format(dmabuf->attributes.format, fmt));
return NULL;
}
image = dmabuf_image_create();
image->dmabuf = dmabuf; image->dmabuf = dmabuf;
wl_list_insert(&gr->dmabuf_images, &image->link); image->num_images = 1;
linux_dmabuf_buffer_set_user_data(dmabuf, egl_image_ref(image), image->images[0] = egl_image;
gl_renderer_destroy_dmabuf);
return image; return image;
} }
@ -1502,7 +1545,7 @@ gl_renderer_import_dmabuf(struct weston_compositor *ec,
struct linux_dmabuf_buffer *dmabuf) struct linux_dmabuf_buffer *dmabuf)
{ {
struct gl_renderer *gr = get_renderer(ec); struct gl_renderer *gr = get_renderer(ec);
struct egl_image *image; struct dmabuf_image *image;
int i; int i;
assert(gr->has_dmabuf_import); assert(gr->has_dmabuf_import);
@ -1521,8 +1564,9 @@ gl_renderer_import_dmabuf(struct weston_compositor *ec,
if (!image) if (!image)
return false; return false;
/* Cache retains a ref. */ wl_list_insert(&gr->dmabuf_images, &image->link);
egl_image_unref(image); linux_dmabuf_buffer_set_user_data(dmabuf, image,
gl_renderer_destroy_dmabuf);
return true; return true;
} }
@ -1552,7 +1596,9 @@ gl_renderer_attach_dmabuf(struct weston_surface *surface,
{ {
struct gl_renderer *gr = get_renderer(surface->compositor); struct gl_renderer *gr = get_renderer(surface->compositor);
struct gl_surface_state *gs = get_surface_state(surface); struct gl_surface_state *gs = get_surface_state(surface);
struct dmabuf_image *image;
int i; int i;
int ret;
if (!gr->has_dmabuf_import) { if (!gr->has_dmabuf_import) {
linux_dmabuf_buffer_send_server_error(dmabuf, linux_dmabuf_buffer_send_server_error(dmabuf,
@ -1586,27 +1632,40 @@ gl_renderer_attach_dmabuf(struct weston_surface *surface,
* *
* Here we release the cache reference which has to be final. * Here we release the cache reference which has to be final.
*/ */
gs->images[0] = linux_dmabuf_buffer_get_user_data(dmabuf); image = linux_dmabuf_buffer_get_user_data(dmabuf);
if (gs->images[0]) {
int ret;
ret = egl_image_unref(gs->images[0]); /* The dmabuf_image should have been created during the import */
assert(image != NULL);
for (i = 0; i < image->num_images; ++i) {
ret = egl_image_unref(image->images[i]);
assert(ret == 0); assert(ret == 0);
} }
gs->images[0] = import_dmabuf(gr, dmabuf); for (i = 0; i < image->num_images; ++i) {
if (!gs->images[0]) { image->images[i] = import_simple_dmabuf(gr, &image->dmabuf->attributes);
linux_dmabuf_buffer_send_server_error(dmabuf, if (!image->images[i]) {
"EGL dmabuf import failed"); image->num_images = 0;
return; while (i) {
ret = egl_image_unref(image->images[--i]);
assert(ret == 0);
}
linux_dmabuf_buffer_send_server_error(dmabuf,
"EGL dmabuf import failed");
return;
}
} }
gs->num_images = 1;
ensure_textures(gs, 1); gs->num_images = image->num_images;
for (i = 0; i < gs->num_images; ++i)
gs->images[i] = egl_image_ref(image->images[i]);
glActiveTexture(GL_TEXTURE0); ensure_textures(gs, gs->num_images);
glBindTexture(gs->target, gs->textures[0]); for (i = 0; i < gs->num_images; ++i) {
gr->image_target_texture_2d(gs->target, gs->images[0]->image); glActiveTexture(GL_TEXTURE0 + i);
glBindTexture(gs->target, gs->textures[i]);
gr->image_target_texture_2d(gs->target, gs->images[i]->image);
}
gs->pitch = buffer->width; gs->pitch = buffer->width;
gs->height = buffer->height; gs->height = buffer->height;
@ -2370,7 +2429,7 @@ static void
gl_renderer_destroy(struct weston_compositor *ec) gl_renderer_destroy(struct weston_compositor *ec)
{ {
struct gl_renderer *gr = get_renderer(ec); struct gl_renderer *gr = get_renderer(ec);
struct egl_image *image, *next; struct dmabuf_image *image, *next;
wl_signal_emit(&gr->destroy_signal, gr); wl_signal_emit(&gr->destroy_signal, gr);
@ -2383,12 +2442,8 @@ gl_renderer_destroy(struct weston_compositor *ec)
EGL_NO_CONTEXT); EGL_NO_CONTEXT);
wl_list_for_each_safe(image, next, &gr->dmabuf_images, link) { wl_list_for_each_safe(image, next, &gr->dmabuf_images, link)
int ret; dmabuf_image_destroy(image);
ret = egl_image_unref(image);
assert(ret == 0);
}
eglTerminate(gr->egl_display); eglTerminate(gr->egl_display);
eglReleaseThread(); eglReleaseThread();