diff options
author | Guido Günther <agx@sigxcpu.org> | 2019-04-08 10:58:18 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-04-08 10:58:18 +0200 |
commit | 9faea17c738d9bfcdd241de7bae0bbe7590c77bf (patch) | |
tree | 3af5beee400f81ae4d8ced171719558b7730d1cd | |
parent | 43bd1d807af533fa369ed3d5431ca2f4e776e9bf (diff) | |
parent | e42178d03fd34f9f5fba10feabfc4b35a71edd31 (diff) |
Merge pull request #1642 from emersion/format-set
Introduce wlr_format_set
-rw-r--r-- | include/wlr/render/drm_format_set.h | 27 | ||||
-rw-r--r-- | include/wlr/render/egl.h | 11 | ||||
-rw-r--r-- | include/wlr/render/interface.h | 5 | ||||
-rw-r--r-- | include/wlr/render/meson.build | 3 | ||||
-rw-r--r-- | include/wlr/render/wlr_renderer.h | 12 | ||||
-rw-r--r-- | render/drm_format_set.c | 105 | ||||
-rw-r--r-- | render/egl.c | 76 | ||||
-rw-r--r-- | render/gles2/renderer.c | 13 | ||||
-rw-r--r-- | render/meson.build | 3 | ||||
-rw-r--r-- | render/wlr_renderer.c | 16 | ||||
-rw-r--r-- | types/wlr_linux_dmabuf_v1.c | 41 |
11 files changed, 224 insertions, 88 deletions
diff --git a/include/wlr/render/drm_format_set.h b/include/wlr/render/drm_format_set.h new file mode 100644 index 00000000..588914ae --- /dev/null +++ b/include/wlr/render/drm_format_set.h @@ -0,0 +1,27 @@ +#ifndef WLR_RENDER_DRM_FORMAT_SET_H +#define WLR_RENDER_DRM_FORMAT_SET_H + +#include <stdbool.h> +#include <stddef.h> +#include <stdint.h> + +struct wlr_drm_format { + uint32_t format; + size_t len, cap; + uint64_t modifiers[]; +}; + +struct wlr_drm_format_set { + size_t len, cap; + struct wlr_drm_format **formats; +}; + +void wlr_drm_format_set_finish(struct wlr_drm_format_set *set); + +const struct wlr_drm_format *wlr_drm_format_set_get( + const struct wlr_drm_format_set *set, uint32_t format); + +bool wlr_drm_format_set_add(struct wlr_drm_format_set *set, uint32_t format, + uint64_t modifier); + +#endif diff --git a/include/wlr/render/egl.h b/include/wlr/render/egl.h index 269af7e2..fb473ba8 100644 --- a/include/wlr/render/egl.h +++ b/include/wlr/render/egl.h @@ -21,6 +21,7 @@ #include <stdbool.h> #include <wayland-server.h> #include <wlr/render/dmabuf.h> +#include <wlr/render/drm_format_set.h> struct wlr_egl { EGLenum platform; @@ -42,6 +43,8 @@ struct wlr_egl { } exts; struct wl_display *wl_display; + + struct wlr_drm_format_set dmabuf_formats; }; // TODO: Allocate and return a wlr_egl @@ -88,13 +91,7 @@ EGLImageKHR wlr_egl_create_image_from_dmabuf(struct wlr_egl *egl, /** * Get the available dmabuf formats */ -int wlr_egl_get_dmabuf_formats(struct wlr_egl *egl, int **formats); - -/** - * Get the available dmabuf modifiers for a given format - */ -int wlr_egl_get_dmabuf_modifiers(struct wlr_egl *egl, int format, - uint64_t **modifiers); +const struct wlr_drm_format_set *wlr_egl_get_dmabuf_formats(struct wlr_egl *egl); bool wlr_egl_export_image_to_dmabuf(struct wlr_egl *egl, EGLImageKHR image, int32_t width, int32_t height, uint32_t flags, diff --git a/include/wlr/render/interface.h b/include/wlr/render/interface.h index c98a7cda..088b1efa 100644 --- a/include/wlr/render/interface.h +++ b/include/wlr/render/interface.h @@ -46,9 +46,8 @@ struct wlr_renderer_impl { struct wl_resource *resource); void (*wl_drm_buffer_get_size)(struct wlr_renderer *renderer, struct wl_resource *buffer, int *width, int *height); - int (*get_dmabuf_formats)(struct wlr_renderer *renderer, int **formats); - int (*get_dmabuf_modifiers)(struct wlr_renderer *renderer, int format, - uint64_t **modifiers); + const struct wlr_drm_format_set *(*get_dmabuf_formats)( + struct wlr_renderer *renderer); enum wl_shm_format (*preferred_read_format)(struct wlr_renderer *renderer); bool (*read_pixels)(struct wlr_renderer *renderer, enum wl_shm_format fmt, uint32_t *flags, uint32_t stride, uint32_t width, uint32_t height, diff --git a/include/wlr/render/meson.build b/include/wlr/render/meson.build index 05127bb7..06ebcc37 100644 --- a/include/wlr/render/meson.build +++ b/include/wlr/render/meson.build @@ -1,9 +1,10 @@ install_headers( 'dmabuf.h', 'egl.h', + 'drm_format_set.h', 'gles2.h', 'interface.h', 'wlr_renderer.h', 'wlr_texture.h', - subdir: 'wlr/render' + subdir: 'wlr/render', ) diff --git a/include/wlr/render/wlr_renderer.h b/include/wlr/render/wlr_renderer.h index 9c031b7f..33f96b68 100644 --- a/include/wlr/render/wlr_renderer.h +++ b/include/wlr/render/wlr_renderer.h @@ -20,6 +20,7 @@ enum wlr_renderer_read_pixels_flags { }; struct wlr_renderer_impl; +struct wlr_drm_format_set; struct wlr_renderer { const struct wlr_renderer_impl *impl; @@ -87,15 +88,10 @@ bool wlr_renderer_resource_is_wl_drm_buffer(struct wlr_renderer *renderer, void wlr_renderer_wl_drm_buffer_get_size(struct wlr_renderer *renderer, struct wl_resource *buffer, int *width, int *height); /** - * Get the available dmabuf formats + * Get the available DMA-BUF formats. */ -int wlr_renderer_get_dmabuf_formats(struct wlr_renderer *renderer, - int **formats); -/** - * Get the available dmabuf modifiers for a given format - */ -int wlr_renderer_get_dmabuf_modifiers(struct wlr_renderer *renderer, int format, - uint64_t **modifiers); +const struct wlr_drm_format_set *wlr_renderer_get_dmabuf_formats( + struct wlr_renderer *renderer); /** * Reads out of pixels of the currently bound surface into data. `stride` is in * bytes. diff --git a/render/drm_format_set.c b/render/drm_format_set.c new file mode 100644 index 00000000..df683b6d --- /dev/null +++ b/render/drm_format_set.c @@ -0,0 +1,105 @@ +#include <drm_fourcc.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <wlr/render/drm_format_set.h> +#include <wlr/util/log.h> + +void wlr_drm_format_set_finish(struct wlr_drm_format_set *set) { + for (size_t i = 0; i < set->len; ++i) { + free(set->formats[i]); + } + free(set->formats); + + set->len = 0; + set->cap = 0; + set->formats = NULL; +} + +static struct wlr_drm_format **format_set_get_ref(struct wlr_drm_format_set *set, + uint32_t format) { + for (size_t i = 0; i < set->len; ++i) { + if (set->formats[i]->format == format) { + return &set->formats[i]; + } + } + + return NULL; +} + +const struct wlr_drm_format *wlr_drm_format_set_get( + const struct wlr_drm_format_set *set, uint32_t format) { + struct wlr_drm_format **ptr = + format_set_get_ref((struct wlr_drm_format_set *)set, format); + return ptr ? *ptr : NULL; +} + +bool wlr_drm_format_set_add(struct wlr_drm_format_set *set, uint32_t format, + uint64_t modifier) { + struct wlr_drm_format **ptr = format_set_get_ref(set, format); + + if (ptr) { + struct wlr_drm_format *fmt = *ptr; + + if (modifier == DRM_FORMAT_MOD_INVALID) { + return true; + } + + for (size_t i = 0; i < fmt->len; ++i) { + if (fmt->modifiers[i] == modifier) { + return true; + } + } + + if (fmt->len == fmt->cap) { + size_t cap = fmt->cap ? fmt->cap * 2 : 4; + + fmt = realloc(fmt, sizeof(*fmt) + sizeof(fmt->modifiers[0]) * cap); + if (!fmt) { + wlr_log_errno(WLR_ERROR, "Allocation failed"); + return false; + } + + fmt->cap = cap; + *ptr = fmt; + } + + fmt->modifiers[fmt->len++] = modifier; + return true; + } + + size_t cap = modifier != DRM_FORMAT_MOD_INVALID ? 4 : 0; + + struct wlr_drm_format *fmt = + calloc(1, sizeof(*fmt) + sizeof(fmt->modifiers[0]) * cap); + if (!fmt) { + wlr_log_errno(WLR_ERROR, "Allocation failed"); + return false; + } + + fmt->format = format; + if (cap) { + fmt->cap = cap; + fmt->len = 1; + fmt->modifiers[0] = modifier; + } + + if (set->len == set->cap) { + size_t new = set->cap ? set->cap * 2 : 4; + + struct wlr_drm_format **tmp = realloc(set->formats, + sizeof(*fmt) + sizeof(fmt->modifiers[0]) * new); + if (!tmp) { + wlr_log_errno(WLR_ERROR, "Allocation failed"); + free(fmt); + return false; + } + + set->cap = new; + set->formats = tmp; + } + + set->formats[set->len++] = fmt; + return true; +} diff --git a/render/egl.c b/render/egl.c index cc00dece..450f8fc7 100644 --- a/render/egl.c +++ b/render/egl.c @@ -1,7 +1,7 @@ -#include <assert.h> -#include <drm_fourcc.h> #include <EGL/egl.h> #include <EGL/eglext.h> +#include <assert.h> +#include <drm_fourcc.h> #include <stdio.h> #include <stdlib.h> #include <wlr/render/egl.h> @@ -77,24 +77,49 @@ static bool check_egl_ext(const char *exts, const char *ext) { return false; } -static void print_dmabuf_formats(struct wlr_egl *egl) { - /* Avoid log msg if extension is not present */ - if (!egl->exts.image_dmabuf_import_modifiers_ext) { - return; - } +static int get_egl_dmabuf_formats(struct wlr_egl *egl, int **formats); +static int get_egl_dmabuf_modifiers(struct wlr_egl *egl, int format, + uint64_t **modifiers); +static void init_dmabuf_formats(struct wlr_egl *egl) { int *formats; - int num = wlr_egl_get_dmabuf_formats(egl, &formats); - if (num < 0) { + int formats_len = get_egl_dmabuf_formats(egl, &formats); + if (formats_len < 0) { return; } - char str_formats[num * 5 + 1]; - for (int i = 0; i < num; i++) { - snprintf(&str_formats[i*5], (num - i) * 5 + 1, "%.4s ", + for (int i = 0; i < formats_len; i++) { + uint32_t fmt = formats[i]; + + uint64_t *modifiers; + int modifiers_len = get_egl_dmabuf_modifiers(egl, fmt, &modifiers); + if (modifiers_len < 0) { + continue; + } + + if (modifiers_len == 0) { + wlr_drm_format_set_add(&egl->dmabuf_formats, fmt, DRM_FORMAT_MOD_INVALID); + } + + for (int j = 0; j < modifiers_len; j++) { + wlr_drm_format_set_add(&egl->dmabuf_formats, fmt, modifiers[j]); + } + + free(modifiers); + } + + char *str_formats = malloc(formats_len * 5 + 1); + if (str_formats == NULL) { + goto out; + } + for (int i = 0; i < formats_len; i++) { + snprintf(&str_formats[i*5], (formats_len - i) * 5 + 1, "%.4s ", (char*)&formats[i]); } wlr_log(WLR_DEBUG, "Supported dmabuf buffer formats: %s", str_formats); + free(str_formats); + +out: free(formats); } @@ -173,7 +198,7 @@ bool wlr_egl_init(struct wlr_egl *egl, EGLenum platform, void *remote_display, check_egl_ext(egl->exts_str, "EGL_MESA_image_dma_buf_export") && eglExportDMABUFImageQueryMESA && eglExportDMABUFImageMESA; - print_dmabuf_formats(egl); + init_dmabuf_formats(egl); egl->exts.bind_wayland_display_wl = check_egl_ext(egl->exts_str, "EGL_WL_bind_wayland_display") @@ -242,6 +267,8 @@ void wlr_egl_finish(struct wlr_egl *egl) { return; } + wlr_drm_format_set_finish(&egl->dmabuf_formats); + eglMakeCurrent(egl->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); if (egl->wl_display) { assert(egl->exts.bind_wayland_display_wl); @@ -486,10 +513,9 @@ EGLImageKHR wlr_egl_create_image_from_dmabuf(struct wlr_egl *egl, EGL_LINUX_DMA_BUF_EXT, NULL, attribs); } -int wlr_egl_get_dmabuf_formats(struct wlr_egl *egl, - int **formats) { +static int get_egl_dmabuf_formats(struct wlr_egl *egl, int **formats) { if (!egl->exts.image_dmabuf_import_ext) { - wlr_log(WLR_DEBUG, "dmabuf import extension not present"); + wlr_log(WLR_DEBUG, "DMA-BUF import extension not present"); return -1; } @@ -518,7 +544,7 @@ int wlr_egl_get_dmabuf_formats(struct wlr_egl *egl, EGLint num; if (!eglQueryDmaBufFormatsEXT(egl->display, 0, NULL, &num)) { - wlr_log(WLR_ERROR, "failed to query number of dmabuf formats"); + wlr_log(WLR_ERROR, "Failed to query number of dmabuf formats"); return -1; } @@ -529,17 +555,17 @@ int wlr_egl_get_dmabuf_formats(struct wlr_egl *egl, } if (!eglQueryDmaBufFormatsEXT(egl->display, num, *formats, &num)) { - wlr_log(WLR_ERROR, "failed to query dmabuf format"); + wlr_log(WLR_ERROR, "Failed to query dmabuf format"); free(*formats); return -1; } return num; } -int wlr_egl_get_dmabuf_modifiers(struct wlr_egl *egl, - int format, uint64_t **modifiers) { +static int get_egl_dmabuf_modifiers(struct wlr_egl *egl, int format, + uint64_t **modifiers) { if (!egl->exts.image_dmabuf_import_ext) { - wlr_log(WLR_DEBUG, "dmabuf extension not present"); + wlr_log(WLR_DEBUG, "DMA-BUF extension not present"); return -1; } @@ -551,7 +577,7 @@ int wlr_egl_get_dmabuf_modifiers(struct wlr_egl *egl, EGLint num; if (!eglQueryDmaBufModifiersEXT(egl->display, format, 0, NULL, NULL, &num)) { - wlr_log(WLR_ERROR, "failed to query dmabuf number of modifiers"); + wlr_log(WLR_ERROR, "Failed to query dmabuf number of modifiers"); return -1; } @@ -563,13 +589,17 @@ int wlr_egl_get_dmabuf_modifiers(struct wlr_egl *egl, if (!eglQueryDmaBufModifiersEXT(egl->display, format, num, *modifiers, NULL, &num)) { - wlr_log(WLR_ERROR, "failed to query dmabuf modifiers"); + wlr_log(WLR_ERROR, "Failed to query dmabuf modifiers"); free(*modifiers); return -1; } return num; } +const struct wlr_drm_format_set *wlr_egl_get_dmabuf_formats(struct wlr_egl *egl) { + return &egl->dmabuf_formats; +} + bool wlr_egl_export_image_to_dmabuf(struct wlr_egl *egl, EGLImageKHR image, int32_t width, int32_t height, uint32_t flags, struct wlr_dmabuf_attributes *attribs) { diff --git a/render/gles2/renderer.c b/render/gles2/renderer.c index 3409d144..dce1f162 100644 --- a/render/gles2/renderer.c +++ b/render/gles2/renderer.c @@ -247,16 +247,10 @@ static void gles2_wl_drm_buffer_get_size(struct wlr_renderer *wlr_renderer, eglQueryWaylandBufferWL(renderer->egl->display, buffer, EGL_HEIGHT, height); } -static int gles2_get_dmabuf_formats(struct wlr_renderer *wlr_renderer, - int **formats) { - struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); - return wlr_egl_get_dmabuf_formats(renderer->egl, formats); -} - -static int gles2_get_dmabuf_modifiers(struct wlr_renderer *wlr_renderer, - int format, uint64_t **modifiers) { +static const struct wlr_drm_format_set *gles2_get_dmabuf_formats( + struct wlr_renderer *wlr_renderer) { struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); - return wlr_egl_get_dmabuf_modifiers(renderer->egl, format, modifiers); + return wlr_egl_get_dmabuf_formats(renderer->egl); } static enum wl_shm_format gles2_preferred_read_format( @@ -402,7 +396,6 @@ static const struct wlr_renderer_impl renderer_impl = { .resource_is_wl_drm_buffer = gles2_resource_is_wl_drm_buffer, .wl_drm_buffer_get_size = gles2_wl_drm_buffer_get_size, .get_dmabuf_formats = gles2_get_dmabuf_formats, - .get_dmabuf_modifiers = gles2_get_dmabuf_modifiers, .preferred_read_format = gles2_preferred_read_format, .read_pixels = gles2_read_pixels, .texture_from_pixels = gles2_texture_from_pixels, diff --git a/render/meson.build b/render/meson.build index e45ea90b..3f6bfdca 100644 --- a/render/meson.build +++ b/render/meson.build @@ -12,6 +12,7 @@ lib_wlr_render = static_library( files( 'dmabuf.c', 'egl.c', + 'drm_format_set.c', 'gles2/pixel_format.c', 'gles2/renderer.c', 'gles2/shaders.c', @@ -27,7 +28,7 @@ lib_wlr_render = static_library( drm.partial_dependency(compile_args: true), # <drm_fourcc.h> glesv2, pixman, - wayland_server + wayland_server, ], ) diff --git a/render/wlr_renderer.c b/render/wlr_renderer.c index 58731d7f..802cbdbd 100644 --- a/render/wlr_renderer.c +++ b/render/wlr_renderer.c @@ -123,20 +123,12 @@ void wlr_renderer_wl_drm_buffer_get_size(struct wlr_renderer *r, return r->impl->wl_drm_buffer_get_size(r, buffer, width, height); } -int wlr_renderer_get_dmabuf_formats(struct wlr_renderer *r, - int **formats) { +const struct wlr_drm_format_set *wlr_renderer_get_dmabuf_formats( + struct wlr_renderer *r) { if (!r->impl->get_dmabuf_formats) { - return -1; - } - return r->impl->get_dmabuf_formats(r, formats); -} - -int wlr_renderer_get_dmabuf_modifiers(struct wlr_renderer *r, int format, - uint64_t **modifiers) { - if (!r->impl->get_dmabuf_modifiers) { - return -1; + return NULL; } - return r->impl->get_dmabuf_modifiers(r, format, modifiers); + return r->impl->get_dmabuf_formats(r); } bool wlr_renderer_read_pixels(struct wlr_renderer *r, enum wl_shm_format fmt, diff --git a/types/wlr_linux_dmabuf_v1.c b/types/wlr_linux_dmabuf_v1.c index 179602e1..19eab3f1 100644 --- a/types/wlr_linux_dmabuf_v1.c +++ b/types/wlr_linux_dmabuf_v1.c @@ -4,6 +4,7 @@ #include <stdlib.h> #include <unistd.h> #include <wayland-server.h> +#include <wlr/render/drm_format_set.h> #include <wlr/render/wlr_renderer.h> #include <wlr/types/wlr_linux_dmabuf_v1.h> #include <wlr/util/log.h> @@ -386,45 +387,39 @@ struct wlr_linux_dmabuf_v1 *wlr_linux_dmabuf_v1_from_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; uint64_t modifier_invalid = DRM_FORMAT_MOD_INVALID; - int *formats = NULL; - int num_formats = wlr_renderer_get_dmabuf_formats(renderer, &formats); - if (num_formats < 0) { + const struct wlr_drm_format_set *formats = + wlr_renderer_get_dmabuf_formats(linux_dmabuf->renderer); + if (formats == NULL) { return; } - for (int i = 0; i < num_formats; i++) { - uint64_t *modifiers = NULL; - int num_modifiers = wlr_renderer_get_dmabuf_modifiers(renderer, - formats[i], &modifiers); - if (num_modifiers < 0) { - return; - } - /* send DRM_FORMAT_MOD_INVALID token when no modifiers are supported - * for this format */ - if (num_modifiers == 0) { - num_modifiers = 1; + for (size_t i = 0; i < formats->len; i++) { + struct wlr_drm_format *fmt = formats->formats[i]; + + size_t modifiers_len = fmt->len; + uint64_t *modifiers = fmt->modifiers; + + // Send DRM_FORMAT_MOD_INVALID token when no modifiers are supported + // for this format + if (modifiers_len == 0) { + modifiers_len = 1; modifiers = &modifier_invalid; } - for (int j = 0; j < num_modifiers; j++) { + for (size_t j = 0; j < modifiers_len; j++) { 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], + fmt->format, modifier_hi, modifier_lo); } else if (modifiers[j] == DRM_FORMAT_MOD_LINEAR || - modifiers == &modifier_invalid) { - zwp_linux_dmabuf_v1_send_format(resource, formats[i]); + modifiers == &modifier_invalid) { + zwp_linux_dmabuf_v1_send_format(resource, fmt->format); } } - if (modifiers != &modifier_invalid) { - free(modifiers); - } } - free(formats); } static void linux_dmabuf_resource_destroy(struct wl_resource *resource) { |