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

Linux-dmabuf with n_planes > 1 #724

Merged
merged 2 commits into from Mar 23, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
85 changes: 59 additions & 26 deletions render/egl.c
Expand Up @@ -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) {
Expand All @@ -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);
}
Expand All @@ -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:
Expand Down
12 changes: 9 additions & 3 deletions render/gles2/texture.c
Expand Up @@ -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);
Expand Down
64 changes: 34 additions & 30 deletions types/wlr_linux_dmabuf.c
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
3 changes: 1 addition & 2 deletions types/wlr_surface.c
Expand Up @@ -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 {
Expand Down