aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--render/egl.c85
-rw-r--r--render/gles2/texture.c12
-rw-r--r--types/wlr_linux_dmabuf.c64
-rw-r--r--types/wlr_surface.c3
4 files changed, 103 insertions, 61 deletions
diff --git a/render/egl.c b/render/egl.c
index b1bd4884..e582b6d3 100644
--- a/render/egl.c
+++ b/render/egl.c
@@ -325,15 +325,6 @@ 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];
- 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) {
@@ -342,25 +333,66 @@ 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;
- }
+ unsigned int atti = 0;
+ EGLint attribs[50];
+ 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;
- 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;
+ struct {
+ EGLint fd;
+ EGLint offset;
+ EGLint pitch;
+ EGLint mod_lo;
+ EGLint mod_hi;
+ } attr_names[WLR_LINUX_DMABUF_MAX_PLANES] = {
+ {
+ EGL_DMA_BUF_PLANE0_FD_EXT,
+ EGL_DMA_BUF_PLANE0_OFFSET_EXT,
+ EGL_DMA_BUF_PLANE0_PITCH_EXT,
+ EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT,
+ EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT
+ }, {
+ EGL_DMA_BUF_PLANE1_FD_EXT,
+ EGL_DMA_BUF_PLANE1_OFFSET_EXT,
+ EGL_DMA_BUF_PLANE1_PITCH_EXT,
+ EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT,
+ EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT
+ }, {
+ EGL_DMA_BUF_PLANE2_FD_EXT,
+ EGL_DMA_BUF_PLANE2_OFFSET_EXT,
+ EGL_DMA_BUF_PLANE2_PITCH_EXT,
+ EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT,
+ EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT
+ }, {
+ EGL_DMA_BUF_PLANE3_FD_EXT,
+ EGL_DMA_BUF_PLANE3_OFFSET_EXT,
+ EGL_DMA_BUF_PLANE3_PITCH_EXT,
+ EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT,
+ EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT
+ }
+ };
+
+ for (int i=0; i < attributes->n_planes; i++) {
+ attribs[atti++] = attr_names[i].fd;
+ attribs[atti++] = attributes->fd[i];
+ attribs[atti++] = attr_names[i].offset;
+ attribs[atti++] = attributes->offset[i];
+ attribs[atti++] = attr_names[i].pitch;
+ attribs[atti++] = attributes->stride[i];
+ if (has_modifier) {
+ attribs[atti++] = attr_names[i].mod_lo;
+ attribs[atti++] = attributes->modifier[i] & 0xFFFFFFFF;
+ attribs[atti++] = attr_names[i].mod_hi;
+ attribs[atti++] = attributes->modifier[i] >> 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);
}
@@ -371,7 +403,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 766c0b15..46193c78 100644
--- a/render/gles2/texture.c
+++ b/render/gles2/texture.c
@@ -275,9 +275,15 @@ static bool gles2_texture_upload_dmabuf(struct wlr_texture *wlr_texture,
wlr_texture->inverted_y = true;
}
- GLenum target = GL_TEXTURE_2D;
- const struct gles2_pixel_format *pf =
- gles2_format_from_wl(WL_SHM_FORMAT_ARGB8888);
+ GLenum target;
+ const struct gles2_pixel_format *pf;
+ if (dmabuf->attributes.n_planes > 1) {
+ target = GL_TEXTURE_EXTERNAL_OES;
+ pf = &external_pixel_format;
+ } else {
+ target = GL_TEXTURE_2D;
+ pf = gles2_format_from_wl(WL_SHM_FORMAT_ARGB8888);
+ }
GLES2_DEBUG_PUSH;
gles2_texture_ensure(tex, target);
glBindTexture(target, tex->tex_id);
diff --git a/types/wlr_linux_dmabuf.c b/types/wlr_linux_dmabuf.c
index 1883bc49..a61d0ea5 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;
}
}
diff --git a/types/wlr_surface.c b/types/wlr_surface.c
index b3e0dcd8..e700853a 100644
--- a/types/wlr_surface.c
+++ b/types/wlr_surface.c
@@ -325,8 +325,7 @@ static void wlr_surface_apply_damage(struct wlr_surface *surface,
surface->current->buffer)) {
wlr_texture_upload_drm(surface->texture, surface->current->buffer);
goto release;
- } else if (wlr_dmabuf_resource_is_buffer(
- surface->current->buffer)) {
+ } else if (wlr_dmabuf_resource_is_buffer(surface->current->buffer)) {
wlr_texture_upload_dmabuf(surface->texture, surface->current->buffer);
goto release;
} else {