From affbfb6a28cfb2a5385e8a2e0417137599f06fa0 Mon Sep 17 00:00:00 2001 From: nyorain Date: Fri, 12 Oct 2018 22:04:12 +0200 Subject: [PATCH] Support older wlr_linux_dmabuf_v1 clients If a client uses an older version of the dmabuf protocol, use the `formats` event instead of `modifiers` (since that didn't exist in older versions). With a bit of necessary guessing, support dmabuf importing even when EGL_EXT_image_dma_buf_import_modifiers isn't present instead of failing up front. --- include/wlr/render/dmabuf.h | 4 +++ render/egl.c | 49 +++++++++++++++++++++++++++++++------ types/wlr_linux_dmabuf_v1.c | 29 +++++++++++----------- 3 files changed, 61 insertions(+), 21 deletions(-) diff --git a/include/wlr/render/dmabuf.h b/include/wlr/render/dmabuf.h index 33c3a129..32cfe874 100644 --- a/include/wlr/render/dmabuf.h +++ b/include/wlr/render/dmabuf.h @@ -16,6 +16,10 @@ #define DRM_FORMAT_MOD_INVALID ((1ULL<<56) - 1) #endif +#ifndef DRM_FORMAT_MOD_LINEAR +#define DRM_FORMAT_MOD_LINEAR 0 +#endif + #define WLR_DMABUF_MAX_PLANES 4 enum wlr_dmabuf_attributes_flags { diff --git a/render/egl.c b/render/egl.c index 96e48c06..585baaeb 100644 --- a/render/egl.c +++ b/render/egl.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include "glapi.h" @@ -382,13 +383,21 @@ EGLImageKHR wlr_egl_create_image_from_wl_drm(struct wlr_egl *egl, EGLImageKHR wlr_egl_create_image_from_dmabuf(struct wlr_egl *egl, struct wlr_dmabuf_attributes *attributes) { - if (!egl->exts.image_base_khr) { + if (!egl->exts.image_base_khr || !egl->exts.image_dmabuf_import_ext) { + wlr_log(WLR_ERROR, "dmabuf import extension not present"); return NULL; } bool has_modifier = false; - if (attributes->modifier != DRM_FORMAT_MOD_INVALID) { + + // we assume the same way we assumed formats without the import_modifiers + // extension that mod_linear is supported. The special mod mod_invalid + // is sometimes used to signal modifier unawareness which is what we + // have here + if (attributes->modifier != DRM_FORMAT_MOD_INVALID && + attributes->modifier != DRM_FORMAT_MOD_LINEAR) { if (!egl->exts.image_dmabuf_import_modifiers_ext) { + wlr_log(WLR_ERROR, "dmabuf modifiers extension not present"); return NULL; } has_modifier = true; @@ -460,12 +469,34 @@ EGLImageKHR wlr_egl_create_image_from_dmabuf(struct wlr_egl *egl, int wlr_egl_get_dmabuf_formats(struct wlr_egl *egl, int **formats) { - if (!egl->exts.image_dmabuf_import_ext || - !egl->exts.image_dmabuf_import_modifiers_ext) { - wlr_log(WLR_DEBUG, "dmabuf extension not present"); + if (!egl->exts.image_dmabuf_import_ext) { + wlr_log(WLR_DEBUG, "dmabuf import extension not present"); return -1; } + // when we only have the image_dmabuf_import extension we can't query + // which formats are supported. These two are on almost always + // supported; it's the intended way to just try to create buffers. + // Just a guess but better than not supporting dmabufs at all, + // given that the modifiers extension isn't supported everywhere. + if (!egl->exts.image_dmabuf_import_modifiers_ext) { + static const int fallback_formats[] = { + DRM_FORMAT_ARGB8888, + DRM_FORMAT_XRGB8888, + }; + static unsigned num = sizeof(fallback_formats) / + sizeof(fallback_formats[0]); + + *formats = calloc(num, sizeof(int)); + if (!*formats) { + wlr_log_errno(WLR_ERROR, "Allocation failed"); + return -1; + } + + memcpy(*formats, fallback_formats, num * sizeof(**formats)); + return num; + } + EGLint num; if (!eglQueryDmaBufFormatsEXT(egl->display, 0, NULL, &num)) { wlr_log(WLR_ERROR, "failed to query number of dmabuf formats"); @@ -488,12 +519,16 @@ int wlr_egl_get_dmabuf_formats(struct wlr_egl *egl, int wlr_egl_get_dmabuf_modifiers(struct wlr_egl *egl, int format, uint64_t **modifiers) { - if (!egl->exts.image_dmabuf_import_ext || - !egl->exts.image_dmabuf_import_modifiers_ext) { + if (!egl->exts.image_dmabuf_import_ext) { wlr_log(WLR_DEBUG, "dmabuf extension not present"); return -1; } + if(!egl->exts.image_dmabuf_import_modifiers_ext) { + *modifiers = NULL; + return 0; + } + EGLint num; if (!eglQueryDmaBufModifiersEXT(egl->display, format, 0, NULL, NULL, &num)) { diff --git a/types/wlr_linux_dmabuf_v1.c b/types/wlr_linux_dmabuf_v1.c index f72e7c07..eb7b2f9e 100644 --- a/types/wlr_linux_dmabuf_v1.c +++ b/types/wlr_linux_dmabuf_v1.c @@ -103,6 +103,7 @@ static void params_add(struct wl_client *client, close(fd); return; } + buffer->attributes.modifier = modifier; buffer->has_modifier = true; @@ -382,13 +383,9 @@ struct wlr_linux_dmabuf_v1 *wlr_linux_dmabuf_v1_from_resource( return dmabuf; } -static void linux_dmabuf_send_modifiers(struct wlr_linux_dmabuf_v1 *linux_dmabuf, - struct wl_resource *resource) { +static void linux_dmabuf_send_formats(struct wlr_linux_dmabuf_v1 *linux_dmabuf, + struct wl_resource *resource, uint32_t version) { struct wlr_renderer *renderer = linux_dmabuf->renderer; - /* - * Use EGL_EXT_image_dma_buf_import_modifiers to query and advertise - * format/modifier codes. - */ uint64_t modifier_invalid = DRM_FORMAT_MOD_INVALID; int *formats = NULL; int num_formats = wlr_renderer_get_dmabuf_formats(renderer, &formats); @@ -410,10 +407,17 @@ static void linux_dmabuf_send_modifiers(struct wlr_linux_dmabuf_v1 *linux_dmabuf modifiers = &modifier_invalid; } for (int j = 0; j < num_modifiers; j++) { - uint32_t modifier_lo = modifiers[j] & 0xFFFFFFFF; - uint32_t modifier_hi = modifiers[j] >> 32; - zwp_linux_dmabuf_v1_send_modifier(resource, formats[i], - modifier_hi, modifier_lo); + if (version >= ZWP_LINUX_DMABUF_V1_MODIFIER_SINCE_VERSION) { + uint32_t modifier_lo = modifiers[j] & 0xFFFFFFFF; + uint32_t modifier_hi = modifiers[j] >> 32; + zwp_linux_dmabuf_v1_send_modifier(resource, + formats[i], + modifier_hi, + modifier_lo); + } else if (modifiers[j] == DRM_FORMAT_MOD_LINEAR || + modifiers == &modifier_invalid) { + zwp_linux_dmabuf_v1_send_format(resource, formats[i]); + } } if (modifiers != &modifier_invalid) { free(modifiers); @@ -439,10 +443,7 @@ static void linux_dmabuf_bind(struct wl_client *client, void *data, wl_resource_set_implementation(resource, &linux_dmabuf_impl, linux_dmabuf, linux_dmabuf_resource_destroy); wl_list_insert(&linux_dmabuf->resources, wl_resource_get_link(resource)); - - if (version >= ZWP_LINUX_DMABUF_V1_MODIFIER_SINCE_VERSION) { - linux_dmabuf_send_modifiers(linux_dmabuf, resource); - } + linux_dmabuf_send_formats(linux_dmabuf, resource, version); } void wlr_linux_dmabuf_v1_destroy(struct wlr_linux_dmabuf_v1 *linux_dmabuf) {