mirror of
https://gitlab.freedesktop.org/wlroots/wlroots.git
synced 2025-12-14 08:56:26 -05:00
Add initial linux_dmabuf protocol support
Tested with
./weston-simple-dmabuf-drm
./weston-simple-dmabuf-drm --import-immediate=1
./weston-simple-dmabuf-drm --y-inverted=1
(and combinations)
Supports only single plane XRGB dmabufs for now.
This commit is contained in:
parent
2d0db16942
commit
14cdb6153f
12 changed files with 787 additions and 4 deletions
135
render/egl.c
135
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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,3 +8,5 @@ eglCreatePlatformWindowSurfaceEXT
|
|||
-glEGLImageTargetTexture2DOES
|
||||
-eglSwapBuffersWithDamageEXT
|
||||
-eglSwapBuffersWithDamageKHR
|
||||
-eglQueryDmaBufFormatsEXT
|
||||
-eglQueryDmaBufModifiersEXT
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue