diff options
Diffstat (limited to 'render')
-rw-r--r-- | render/egl.c | 135 | ||||
-rw-r--r-- | render/glapi.txt | 2 | ||||
-rw-r--r-- | render/gles2/texture.c | 62 | ||||
-rw-r--r-- | render/wlr_texture.c | 5 |
4 files changed, 200 insertions, 4 deletions
diff --git a/render/egl.c b/render/egl.c index 0a68d6e5..55809983 100644 --- a/render/egl.c +++ b/render/egl.c @@ -167,6 +167,12 @@ bool wlr_egl_init(struct wlr_egl *egl, EGLenum platform, void *remote_display, check_egl_ext(egl->egl_exts_str, "EGL_EXT_swap_buffers_with_damage") || check_egl_ext(egl->egl_exts_str, "EGL_KHR_swap_buffers_with_damage"); + egl->egl_exts.dmabuf_import = + check_egl_ext(egl->egl_exts_str, "EGL_EXT_image_dma_buf_import"); + egl->egl_exts.dmabuf_import_modifiers = + check_egl_ext(egl->egl_exts_str, "EGL_EXT_image_dma_buf_import_modifiers") + && eglQueryDmaBufFormatsEXT && eglQueryDmaBufModifiersEXT; + return true; error: @@ -299,3 +305,132 @@ bool wlr_egl_swap_buffers(struct wlr_egl *egl, EGLSurface surface, } return true; } + +EGLImage wlr_egl_create_image_from_dmabuf(struct wlr_egl *egl, + struct wlr_dmabuf_buffer_attribs *attributes) { + int atti = 0; + EGLint attribs[20]; + attribs[atti++] = EGL_WIDTH; + attribs[atti++] = attributes->width; + attribs[atti++] = EGL_HEIGHT; + attribs[atti++] = attributes->height; + attribs[atti++] = EGL_LINUX_DRM_FOURCC_EXT; + attribs[atti++] = attributes->format; + + bool has_modifier = false; + if (attributes->modifier[0] != DRM_FORMAT_MOD_INVALID) { + if (!egl->egl_exts.dmabuf_import_modifiers) { + return NULL; + } + has_modifier = true; + } + + /* TODO: YUV planes have up four planes but we only support a + single EGLImage for now */ + if (attributes->n_planes > 1) { + return NULL; + } + + attribs[atti++] = EGL_DMA_BUF_PLANE0_FD_EXT; + attribs[atti++] = attributes->fd[0]; + attribs[atti++] = EGL_DMA_BUF_PLANE0_OFFSET_EXT; + attribs[atti++] = attributes->offset[0]; + attribs[atti++] = EGL_DMA_BUF_PLANE0_PITCH_EXT; + attribs[atti++] = attributes->stride[0]; + if (has_modifier) { + attribs[atti++] = EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT; + attribs[atti++] = attributes->modifier[0] & 0xFFFFFFFF; + attribs[atti++] = EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT; + attribs[atti++] = attributes->modifier[0] >> 32; + } + attribs[atti++] = EGL_NONE; + return eglCreateImageKHR(egl->display, EGL_NO_CONTEXT, + EGL_LINUX_DMA_BUF_EXT, NULL, attribs); +} + +#ifndef DRM_FORMAT_BIG_ENDIAN +# define DRM_FORMAT_BIG_ENDIAN 0x80000000 +#endif +bool wlr_egl_check_import_dmabuf(struct wlr_egl *egl, + struct wlr_dmabuf_buffer *dmabuf) { + switch (dmabuf->attributes.format & ~DRM_FORMAT_BIG_ENDIAN) { + /* YUV based formats not yet supported */ + case WL_SHM_FORMAT_YUYV: + case WL_SHM_FORMAT_YVYU: + case WL_SHM_FORMAT_UYVY: + case WL_SHM_FORMAT_VYUY: + case WL_SHM_FORMAT_AYUV: + return false; + default: + break; + } + + EGLImage egl_image = wlr_egl_create_image_from_dmabuf(egl, + &dmabuf->attributes); + if (egl_image) { + /* We can import the image, good. No need to keep it + since wlr_texture_upload_dmabuf will import it again */ + wlr_egl_destroy_image(egl, egl_image); + return true; + } + /* TODO: import yuv dmabufs */ + return false; +} + +int wlr_egl_get_dmabuf_formats(struct wlr_egl *egl, + int **formats) { + if (!egl->egl_exts.dmabuf_import || + !egl->egl_exts.dmabuf_import_modifiers) { + wlr_log(L_ERROR, "dmabuf extension not present"); + return -1; + } + + EGLint num; + if (!eglQueryDmaBufFormatsEXT(egl->display, 0, NULL, &num)) { + wlr_log(L_ERROR, "failed to query number of dmabuf formats"); + return -1; + } + + *formats = calloc(num, sizeof(int)); + if (*formats == NULL) { + wlr_log(L_ERROR, "Allocation failed: %s", strerror(errno)); + return -1; + } + + if (!eglQueryDmaBufFormatsEXT(egl->display, num, *formats, &num)) { + wlr_log(L_ERROR, "failed to query dmabuf format"); + free(*formats); + return -1; + } + return num; +} + +int wlr_egl_get_dmabuf_modifiers(struct wlr_egl *egl, + int format, uint64_t **modifiers) { + if (!egl->egl_exts.dmabuf_import || + !egl->egl_exts.dmabuf_import_modifiers) { + wlr_log(L_ERROR, "dmabuf extension not present"); + return -1; + } + + EGLint num; + if (!eglQueryDmaBufModifiersEXT(egl->display, format, 0, + NULL, NULL, &num)) { + wlr_log(L_ERROR, "failed to query dmabuf number of modifiers"); + return -1; + } + + *modifiers = calloc(num, sizeof(uint64_t)); + if (*modifiers == NULL) { + wlr_log(L_ERROR, "Allocation failed: %s", strerror(errno)); + return -1; + } + + if (!eglQueryDmaBufModifiersEXT(egl->display, format, num, + *modifiers, NULL, &num)) { + wlr_log(L_ERROR, "failed to query dmabuf modifiers"); + free(*modifiers); + return -1; + } + return num; +} diff --git a/render/glapi.txt b/render/glapi.txt index 0b0b452c..02ac7dd8 100644 --- a/render/glapi.txt +++ b/render/glapi.txt @@ -8,3 +8,5 @@ eglCreatePlatformWindowSurfaceEXT -glEGLImageTargetTexture2DOES -eglSwapBuffersWithDamageEXT -eglSwapBuffersWithDamageKHR +-eglQueryDmaBufFormatsEXT +-eglQueryDmaBufModifiersEXT diff --git a/render/gles2/texture.c b/render/gles2/texture.c index d25d1809..5e84890f 100644 --- a/render/gles2/texture.c +++ b/render/gles2/texture.c @@ -227,6 +227,42 @@ static bool gles2_texture_upload_eglimage(struct wlr_texture *wlr_tex, return true; } + +static bool gles2_texture_upload_dmabuf(struct wlr_texture *_tex, + struct wl_resource *dmabuf_resource) { + struct wlr_gles2_texture *tex = (struct wlr_gles2_texture *)_tex; + struct wlr_dmabuf_buffer *dmabuf = wlr_dmabuf_buffer_from_buffer_resource( + dmabuf_resource); + + if (!tex->egl->egl_exts.dmabuf_import) { + wlr_log(L_ERROR, "Want dmabuf but extension not present"); + return false; + } + + tex->wlr_texture.width = dmabuf->attributes.width; + tex->wlr_texture.height = dmabuf->attributes.height; + + if (tex->image) { + wlr_egl_destroy_image(tex->egl, tex->image); + } + + if (wlr_dmabuf_buffer_has_inverted_y(dmabuf)) { + _tex->inverted_y = true; + } + + GLenum target = GL_TEXTURE_2D; + const struct pixel_format *pf = + gl_format_for_wl_format(WL_SHM_FORMAT_ARGB8888); + gles2_texture_ensure_texture(tex); + GL_CALL(glBindTexture(target, tex->tex_id)); + tex->image = wlr_egl_create_image_from_dmabuf(tex->egl, &dmabuf->attributes); + GL_CALL(glActiveTexture(GL_TEXTURE0)); + GL_CALL(glEGLImageTargetTexture2DOES(target, tex->image)); + tex->pixel_format = pf; + tex->wlr_texture.valid = true; + return true; +} + static void gles2_texture_get_matrix(struct wlr_texture *_texture, float (*matrix)[16], const float (*projection)[16], int x, int y) { struct wlr_gles2_texture *texture = (struct wlr_gles2_texture *)_texture; @@ -240,6 +276,21 @@ static void gles2_texture_get_matrix(struct wlr_texture *_texture, wlr_matrix_mul(projection, matrix, matrix); } + +static bool gles2_texture_get_dmabuf_size(struct wlr_texture *texture, struct + wl_resource *resource, int *width, int *height) { + if (!wlr_dmabuf_resource_is_buffer(resource)) { + return false; + } + + struct wlr_dmabuf_buffer *dmabuf = wlr_dmabuf_buffer_from_buffer_resource( + resource); + *width = dmabuf->attributes.width; + *height = dmabuf->attributes.height; + return true; +} + + static void gles2_texture_get_buffer_size(struct wlr_texture *texture, struct wl_resource *resource, int *width, int *height) { struct wl_shm_buffer *buffer = wl_shm_buffer_get(resource); @@ -250,10 +301,12 @@ static void gles2_texture_get_buffer_size(struct wlr_texture *texture, struct } if (!wlr_egl_query_buffer(tex->egl, resource, EGL_WIDTH, (EGLint*)width)) { - wlr_log(L_ERROR, "could not get size of the buffer " - "(no buffer found)"); - return; - }; + if (!gles2_texture_get_dmabuf_size(texture, resource, + width, height)) { + wlr_log(L_ERROR, "could not get size of the buffer"); + return; + } + } wlr_egl_query_buffer(tex->egl, resource, EGL_HEIGHT, (EGLint*)height); @@ -292,6 +345,7 @@ static struct wlr_texture_impl wlr_texture_impl = { .upload_shm = gles2_texture_upload_shm, .update_shm = gles2_texture_update_shm, .upload_drm = gles2_texture_upload_drm, + .upload_dmabuf = gles2_texture_upload_dmabuf, .upload_eglimage = gles2_texture_upload_eglimage, .get_matrix = gles2_texture_get_matrix, .get_buffer_size = gles2_texture_get_buffer_size, diff --git a/render/wlr_texture.c b/render/wlr_texture.c index a82a16b2..e4e6b9ff 100644 --- a/render/wlr_texture.c +++ b/render/wlr_texture.c @@ -53,6 +53,11 @@ bool wlr_texture_upload_eglimage(struct wlr_texture *texture, return texture->impl->upload_eglimage(texture, image, width, height); } +bool wlr_texture_upload_dmabuf(struct wlr_texture *texture, + struct wl_resource *dmabuf_resource) { + return texture->impl->upload_dmabuf(texture, dmabuf_resource); +} + void wlr_texture_get_matrix(struct wlr_texture *texture, float (*matrix)[16], const float (*projection)[16], int x, int y) { texture->impl->get_matrix(texture, matrix, projection, x, y); |