linux-dmabuf: Support multi plane formats like NV12
This commit is contained in:
parent
805039457a
commit
b1852096c5
83
render/egl.c
83
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,
|
EGLImage wlr_egl_create_image_from_dmabuf(struct wlr_egl *egl,
|
||||||
struct wlr_dmabuf_buffer_attribs *attributes) {
|
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;
|
bool has_modifier = false;
|
||||||
if (attributes->modifier[0] != DRM_FORMAT_MOD_INVALID) {
|
if (attributes->modifier[0] != DRM_FORMAT_MOD_INVALID) {
|
||||||
if (!egl->egl_exts.dmabuf_import_modifiers) {
|
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;
|
has_modifier = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: YUV planes have up four planes but we only support a
|
unsigned int atti = 0;
|
||||||
single EGLImage for now */
|
EGLint attribs[50];
|
||||||
if (attributes->n_planes > 1) {
|
attribs[atti++] = EGL_WIDTH;
|
||||||
return NULL;
|
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;
|
struct {
|
||||||
attribs[atti++] = attributes->fd[0];
|
EGLint fd;
|
||||||
attribs[atti++] = EGL_DMA_BUF_PLANE0_OFFSET_EXT;
|
EGLint offset;
|
||||||
attribs[atti++] = attributes->offset[0];
|
EGLint pitch;
|
||||||
attribs[atti++] = EGL_DMA_BUF_PLANE0_PITCH_EXT;
|
EGLint mod_lo;
|
||||||
attribs[atti++] = attributes->stride[0];
|
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) {
|
if (has_modifier) {
|
||||||
attribs[atti++] = EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT;
|
attribs[atti++] = attr_names[i].mod_lo;
|
||||||
attribs[atti++] = attributes->modifier[0] & 0xFFFFFFFF;
|
attribs[atti++] = attributes->modifier[i] & 0xFFFFFFFF;
|
||||||
attribs[atti++] = EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT;
|
attribs[atti++] = attr_names[i].mod_hi;
|
||||||
attribs[atti++] = attributes->modifier[0] >> 32;
|
attribs[atti++] = attributes->modifier[i] >> 32;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
attribs[atti++] = EGL_NONE;
|
attribs[atti++] = EGL_NONE;
|
||||||
|
assert(atti < sizeof(attribs)/sizeof(attribs[0]));
|
||||||
|
|
||||||
return eglCreateImageKHR(egl->display, EGL_NO_CONTEXT,
|
return eglCreateImageKHR(egl->display, EGL_NO_CONTEXT,
|
||||||
EGL_LINUX_DMA_BUF_EXT, NULL, attribs);
|
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,
|
bool wlr_egl_check_import_dmabuf(struct wlr_egl *egl,
|
||||||
struct wlr_dmabuf_buffer *dmabuf) {
|
struct wlr_dmabuf_buffer *dmabuf) {
|
||||||
switch (dmabuf->attributes.format & ~DRM_FORMAT_BIG_ENDIAN) {
|
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_YUYV:
|
||||||
case WL_SHM_FORMAT_YVYU:
|
case WL_SHM_FORMAT_YVYU:
|
||||||
case WL_SHM_FORMAT_UYVY:
|
case WL_SHM_FORMAT_UYVY:
|
||||||
|
|
|
@ -275,9 +275,15 @@ static bool gles2_texture_upload_dmabuf(struct wlr_texture *wlr_texture,
|
||||||
wlr_texture->inverted_y = true;
|
wlr_texture->inverted_y = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
GLenum target = GL_TEXTURE_2D;
|
GLenum target;
|
||||||
const struct gles2_pixel_format *pf =
|
const struct gles2_pixel_format *pf;
|
||||||
gles2_format_from_wl(WL_SHM_FORMAT_ARGB8888);
|
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_DEBUG_PUSH;
|
||||||
gles2_texture_ensure(tex, target);
|
gles2_texture_ensure(tex, target);
|
||||||
glBindTexture(target, tex->tex_id);
|
glBindTexture(target, tex->tex_id);
|
||||||
|
|
|
@ -139,19 +139,18 @@ static void params_create_common(struct wl_client *client,
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: support more planes */
|
|
||||||
if (buffer->attributes.n_planes != 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);
|
|
||||||
goto err_out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (buffer->attributes.fd[0] == -1) {
|
if (buffer->attributes.fd[0] == -1) {
|
||||||
wl_resource_post_error(params_resource,
|
wl_resource_post_error(params_resource,
|
||||||
ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INCOMPLETE,
|
ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INCOMPLETE,
|
||||||
"no dmabuf has been added for plane");
|
"no dmabuf has been added for plane 0");
|
||||||
|
goto err_out;
|
||||||
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
"gap in dmabuf planes");
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,43 +166,48 @@ static void params_create_common(struct wl_client *client,
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((uint64_t)buffer->attributes.offset[0] + buffer->attributes.stride[0] > UINT32_MAX) {
|
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,
|
wl_resource_post_error(params_resource,
|
||||||
ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
|
ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
|
||||||
"size overflow for plane");
|
"size overflow for plane %d", i);
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((uint64_t)buffer->attributes.offset[0] +
|
if ((uint64_t)buffer->attributes.offset[i]
|
||||||
(uint64_t)buffer->attributes.stride[0] * height > UINT32_MAX) {
|
+ (uint64_t)buffer->attributes.stride[i] * height > UINT32_MAX) {
|
||||||
wl_resource_post_error(params_resource,
|
wl_resource_post_error(params_resource,
|
||||||
ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
|
ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
|
||||||
"size overflow for plane");
|
"size overflow for plane %d", i);
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
|
|
||||||
off_t size = lseek(buffer->attributes.fd[0], 0, SEEK_END);
|
off_t size = lseek(buffer->attributes.fd[i], 0, SEEK_END);
|
||||||
if (size != -1) { /* Skip checks if kernel does no support seek on buffer */
|
if (size == -1) { /* Skip checks if kernel does no support seek on buffer */
|
||||||
if (buffer->attributes.offset[0] >= size) {
|
continue;
|
||||||
|
}
|
||||||
|
if (buffer->attributes.offset[i] >= size) {
|
||||||
wl_resource_post_error(params_resource,
|
wl_resource_post_error(params_resource,
|
||||||
ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
|
ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
|
||||||
"invalid offset %i for plane",
|
"invalid offset %i for plane %d",
|
||||||
buffer->attributes.offset[0]);
|
buffer->attributes.offset[i], i);
|
||||||
goto err_out;
|
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,
|
wl_resource_post_error(params_resource,
|
||||||
ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
|
ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
|
||||||
"invalid stride %i for plane",
|
"invalid stride %i for plane %d",
|
||||||
buffer->attributes.stride[0]);
|
buffer->attributes.stride[i], i);
|
||||||
goto err_out;
|
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,
|
wl_resource_post_error(params_resource,
|
||||||
ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
|
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;
|
goto err_out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue