Skip to content
This repository has been archived by the owner on Nov 1, 2021. It is now read-only.

Commit

Permalink
linux-dmabuf: Support multi plane formats like NV12
Browse files Browse the repository at this point in the history
  • Loading branch information
agx committed Mar 21, 2018
1 parent 19bfcfb commit 0a9ee09
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 42 deletions.
60 changes: 51 additions & 9 deletions render/egl.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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);
}
Expand All @@ -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:
Expand Down
13 changes: 10 additions & 3 deletions render/gles2/texture.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
64 changes: 34 additions & 30 deletions types/wlr_linux_dmabuf.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand All @@ -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;
}
}
Expand Down

0 comments on commit 0a9ee09

Please sign in to comment.