diff --git a/render/egl.c b/render/egl.c index d60da2ab92..dc399e43c6 100644 --- a/render/egl.c +++ b/render/egl.c @@ -330,8 +330,8 @@ bool wlr_egl_swap_buffers(struct wlr_egl *egl, EGLSurface surface, EGLImage wlr_egl_create_image_from_dmabuf(struct wlr_egl *egl, struct wlr_dmabuf_buffer_attribs *attributes) { - int atti = 0; - EGLint attribs[20]; + unsigned int atti = 0; + EGLint attribs[50]; attribs[atti++] = EGL_WIDTH; attribs[atti++] = attributes->width; attribs[atti++] = EGL_HEIGHT; @@ -347,12 +347,6 @@ EGLImage wlr_egl_create_image_from_dmabuf(struct wlr_egl *egl, 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; @@ -365,7 +359,54 @@ EGLImage wlr_egl_create_image_from_dmabuf(struct wlr_egl *egl, attribs[atti++] = EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT; attribs[atti++] = attributes->modifier[0] >> 32; } + + if (attributes->n_planes > 1) { + attribs[atti++] = EGL_DMA_BUF_PLANE1_FD_EXT; + attribs[atti++] = attributes->fd[1]; + attribs[atti++] = EGL_DMA_BUF_PLANE1_OFFSET_EXT; + attribs[atti++] = attributes->offset[1]; + attribs[atti++] = EGL_DMA_BUF_PLANE1_PITCH_EXT; + attribs[atti++] = attributes->stride[1]; + if (has_modifier) { + attribs[atti++] = EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT; + attribs[atti++] = attributes->modifier[1] & 0xFFFFFFFF; + attribs[atti++] = EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT; + attribs[atti++] = attributes->modifier[1] >> 32; + } + } + + if (attributes->n_planes > 2) { + attribs[atti++] = EGL_DMA_BUF_PLANE2_FD_EXT; + attribs[atti++] = attributes->fd[2]; + attribs[atti++] = EGL_DMA_BUF_PLANE2_OFFSET_EXT; + attribs[atti++] = attributes->offset[2]; + attribs[atti++] = EGL_DMA_BUF_PLANE2_PITCH_EXT; + attribs[atti++] = attributes->stride[2]; + if (has_modifier) { + attribs[atti++] = EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT; + attribs[atti++] = attributes->modifier[2] & 0xFFFFFFFF; + attribs[atti++] = EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT; + attribs[atti++] = attributes->modifier[2] >> 32; + } + } + + if (attributes->n_planes > 3) { + attribs[atti++] = EGL_DMA_BUF_PLANE3_FD_EXT; + attribs[atti++] = attributes->fd[3]; + attribs[atti++] = EGL_DMA_BUF_PLANE3_OFFSET_EXT; + attribs[atti++] = attributes->offset[3]; + attribs[atti++] = EGL_DMA_BUF_PLANE3_PITCH_EXT; + attribs[atti++] = attributes->stride[3]; + if (has_modifier) { + attribs[atti++] = EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT; + attribs[atti++] = attributes->modifier[3] & 0xFFFFFFFF; + attribs[atti++] = EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT; + attribs[atti++] = attributes->modifier[3] >> 32; + } + } attribs[atti++] = EGL_NONE; + assert(atti < sizeof(attribs)/sizeof(attribs[0])); + return eglCreateImageKHR(egl->display, EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, NULL, attribs); } @@ -376,7 +417,8 @@ EGLImage wlr_egl_create_image_from_dmabuf(struct wlr_egl *egl, 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 */ + /* TODO: YUV based formats not yet supported, require multiple + * wlr_create_image_from_dmabuf */ case WL_SHM_FORMAT_YUYV: case WL_SHM_FORMAT_YVYU: case WL_SHM_FORMAT_UYVY: diff --git a/render/gles2/texture.c b/render/gles2/texture.c index 99f153b800..405f132112 100644 --- a/render/gles2/texture.c +++ b/render/gles2/texture.c @@ -252,9 +252,16 @@ static bool gles2_texture_upload_dmabuf(struct wlr_texture *_tex, _tex->inverted_y = true; } - GLenum target = GL_TEXTURE_2D; - const struct pixel_format *pf = - gl_format_for_wl_format(WL_SHM_FORMAT_ARGB8888); + GLenum target; + const struct pixel_format *pf; + if (dmabuf->attributes.n_planes > 1) { + target = GL_TEXTURE_EXTERNAL_OES; + pf = &external_pixel_format; + } else { + target = GL_TEXTURE_2D; + pf = gl_format_for_wl_format(WL_SHM_FORMAT_ARGB8888); + } + gles2_texture_ensure_texture(tex, target); GL_CALL(glBindTexture(target, tex->tex_id)); tex->image = wlr_egl_create_image_from_dmabuf(tex->egl, &dmabuf->attributes); diff --git a/types/wlr_linux_dmabuf.c b/types/wlr_linux_dmabuf.c index 1883bc4951..a61d0ea58a 100644 --- a/types/wlr_linux_dmabuf.c +++ b/types/wlr_linux_dmabuf.c @@ -139,19 +139,18 @@ static void params_create_common(struct wl_client *client, goto err_out; } - /* TODO: support more planes */ - if (buffer->attributes.n_planes != 1) { + if (buffer->attributes.fd[0] == -1) { wl_resource_post_error(params_resource, ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INCOMPLETE, - "only single plane buffers supported not %d", - buffer->attributes.n_planes); + "no dmabuf has been added for plane 0"); goto err_out; } - if (buffer->attributes.fd[0] == -1) { - wl_resource_post_error(params_resource, + if ((buffer->attributes.fd[3] >= 0 || buffer->attributes.fd[2] >= 0) && + (buffer->attributes.fd[2] == -1 || buffer->attributes.fd[1] == -1)) { + wl_resource_post_error (params_resource, ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INCOMPLETE, - "no dmabuf has been added for plane"); + "gap in dmabuf planes"); goto err_out; } @@ -167,43 +166,48 @@ static void params_create_common(struct wl_client *client, goto err_out; } - if ((uint64_t)buffer->attributes.offset[0] + buffer->attributes.stride[0] > UINT32_MAX) { - wl_resource_post_error(params_resource, - ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS, - "size overflow for plane"); - goto err_out; - } + for (int i = 0; i < buffer->attributes.n_planes; i++) { + if ((uint64_t)buffer->attributes.offset[i] + + buffer->attributes.stride[i] > UINT32_MAX) { + wl_resource_post_error(params_resource, + ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS, + "size overflow for plane %d", i); + goto err_out; + } - if ((uint64_t)buffer->attributes.offset[0] + - (uint64_t)buffer->attributes.stride[0] * height > UINT32_MAX) { - wl_resource_post_error(params_resource, - ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS, - "size overflow for plane"); - goto err_out; - } + if ((uint64_t)buffer->attributes.offset[i] + + (uint64_t)buffer->attributes.stride[i] * height > UINT32_MAX) { + wl_resource_post_error(params_resource, + ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS, + "size overflow for plane %d", i); + goto err_out; + } - off_t size = lseek(buffer->attributes.fd[0], 0, SEEK_END); - if (size != -1) { /* Skip checks if kernel does no support seek on buffer */ - if (buffer->attributes.offset[0] >= size) { + off_t size = lseek(buffer->attributes.fd[i], 0, SEEK_END); + if (size == -1) { /* Skip checks if kernel does no support seek on buffer */ + continue; + } + if (buffer->attributes.offset[i] >= size) { wl_resource_post_error(params_resource, ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS, - "invalid offset %i for plane", - buffer->attributes.offset[0]); + "invalid offset %i for plane %d", + buffer->attributes.offset[i], i); goto err_out; } - if (buffer->attributes.offset[0] + buffer->attributes.stride[0] > size) { + if (buffer->attributes.offset[i] + buffer->attributes.stride[i] > size) { wl_resource_post_error(params_resource, ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS, - "invalid stride %i for plane", - buffer->attributes.stride[0]); + "invalid stride %i for plane %d", + buffer->attributes.stride[i], i); goto err_out; } - if (buffer->attributes.offset[0] + buffer->attributes.stride[0] * height > size) { + if (i == 0 && /* planes > 0 might be subsampled according to fourcc format */ + buffer->attributes.offset[i] + buffer->attributes.stride[i] * height > size) { wl_resource_post_error(params_resource, ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS, - "invalid buffer stride or height for plane"); + "invalid buffer stride or height for plane %d", i); goto err_out; } }