diff --git a/backend/wayland/backend.c b/backend/wayland/backend.c index 9b5876186..75bb2925c 100644 --- a/backend/wayland/backend.c +++ b/backend/wayland/backend.c @@ -20,6 +20,7 @@ #include "backend/wayland.h" #include "render/drm_format_set.h" #include "render/gbm_allocator.h" +#include "render/pixel_format.h" #include "render/wlr_renderer.h" #include "util/signal.h" @@ -190,6 +191,17 @@ static const struct wl_drm_listener legacy_drm_listener = { .capabilities = legacy_drm_handle_capabilities, }; +static void shm_handle_format(void *data, struct wl_shm *shm, + uint32_t shm_format) { + struct wlr_wl_backend *wl = data; + uint32_t drm_format = convert_wl_shm_format_to_drm(shm_format); + wlr_drm_format_set_add(&wl->shm_formats, drm_format, DRM_FORMAT_MOD_INVALID); +} + +static const struct wl_shm_listener shm_listener = { + .format = shm_handle_format, +}; + static void registry_global(void *data, struct wl_registry *registry, uint32_t name, const char *iface, uint32_t version) { struct wlr_wl_backend *wl = data; @@ -233,6 +245,9 @@ static void registry_global(void *data, struct wl_registry *registry, } else if (strcmp(iface, wl_drm_interface.name) == 0) { wl->legacy_drm = wl_registry_bind(registry, name, &wl_drm_interface, 1); wl_drm_add_listener(wl->legacy_drm, &legacy_drm_listener, wl); + } else if (strcmp(iface, wl_shm_interface.name) == 0) { + wl->shm = wl_registry_bind(registry, name, &wl_shm_interface, 1); + wl_shm_add_listener(wl->shm, &shm_listener, wl); } } @@ -302,6 +317,7 @@ static void backend_destroy(struct wlr_backend *backend) { wlr_allocator_destroy(wl->allocator); close(wl->drm_fd); + wlr_drm_format_set_finish(&wl->shm_formats); wlr_drm_format_set_finish(&wl->linux_dmabuf_v1_formats); struct wlr_wl_buffer *buffer, *tmp_buffer; @@ -322,6 +338,9 @@ static void backend_destroy(struct wlr_backend *backend) { if (wl->zwp_linux_dmabuf_v1) { zwp_linux_dmabuf_v1_destroy(wl->zwp_linux_dmabuf_v1); } + if (wl->shm) { + wl_shm_destroy(wl->shm); + } if (wl->zwp_relative_pointer_manager_v1) { zwp_relative_pointer_manager_v1_destroy(wl->zwp_relative_pointer_manager_v1); } diff --git a/backend/wayland/output.c b/backend/wayland/output.c index b36af17bd..3d5d2e316 100644 --- a/backend/wayland/output.c +++ b/backend/wayland/output.c @@ -7,6 +7,7 @@ #include #include +#include #include #include @@ -15,6 +16,7 @@ #include #include "backend/wayland.h" +#include "render/pixel_format.h" #include "render/swapchain.h" #include "render/wlr_renderer.h" #include "util/signal.h" @@ -161,17 +163,58 @@ static void buffer_handle_buffer_destroy(struct wl_listener *listener, static bool test_buffer(struct wlr_wl_backend *wl, struct wlr_buffer *wlr_buffer) { - struct wlr_dmabuf_attributes attribs; - if (!wlr_buffer_get_dmabuf(wlr_buffer, &attribs)) { + struct wlr_dmabuf_attributes dmabuf; + struct wlr_shm_attributes shm; + if (wlr_buffer_get_dmabuf(wlr_buffer, &dmabuf)) { + return wlr_drm_format_set_has(&wl->linux_dmabuf_v1_formats, + dmabuf.format, dmabuf.modifier); + } else if (wlr_buffer_get_shm(wlr_buffer, &shm)) { + return wlr_drm_format_set_has(&wl->shm_formats, shm.format, + DRM_FORMAT_MOD_INVALID); + } else { return false; } +} - if (!wlr_drm_format_set_has(&wl->linux_dmabuf_v1_formats, - attribs.format, attribs.modifier)) { - return false; +static struct wl_buffer *import_dmabuf(struct wlr_wl_backend *wl, + struct wlr_dmabuf_attributes *dmabuf) { + uint32_t modifier_hi = dmabuf->modifier >> 32; + uint32_t modifier_lo = (uint32_t)dmabuf->modifier; + struct zwp_linux_buffer_params_v1 *params = + zwp_linux_dmabuf_v1_create_params(wl->zwp_linux_dmabuf_v1); + for (int i = 0; i < dmabuf->n_planes; i++) { + zwp_linux_buffer_params_v1_add(params, dmabuf->fd[i], i, + dmabuf->offset[i], dmabuf->stride[i], modifier_hi, modifier_lo); } - return true; + uint32_t flags = 0; + if (dmabuf->flags & WLR_DMABUF_ATTRIBUTES_FLAGS_Y_INVERT) { + flags |= ZWP_LINUX_BUFFER_PARAMS_V1_FLAGS_Y_INVERT; + } + if (dmabuf->flags & WLR_DMABUF_ATTRIBUTES_FLAGS_INTERLACED) { + flags |= ZWP_LINUX_BUFFER_PARAMS_V1_FLAGS_INTERLACED; + } + if (dmabuf->flags & WLR_DMABUF_ATTRIBUTES_FLAGS_BOTTOM_FIRST) { + flags |= ZWP_LINUX_BUFFER_PARAMS_V1_FLAGS_BOTTOM_FIRST; + } + struct wl_buffer *wl_buffer = zwp_linux_buffer_params_v1_create_immed( + params, dmabuf->width, dmabuf->height, dmabuf->format, flags); + // TODO: handle create() errors + return wl_buffer; +} + +static struct wl_buffer *import_shm(struct wlr_wl_backend *wl, + struct wlr_shm_attributes *shm) { + enum wl_shm_format wl_shm_format = convert_drm_format_to_wl_shm(shm->format); + uint32_t size = shm->stride * shm->height; + struct wl_shm_pool *pool = wl_shm_create_pool(wl->shm, shm->fd, size); + if (pool == NULL) { + return NULL; + } + struct wl_buffer *wl_buffer = wl_shm_pool_create_buffer(pool, shm->offset, + shm->width, shm->height, shm->stride, wl_shm_format); + wl_shm_pool_destroy(pool); + return wl_buffer; } static struct wlr_wl_buffer *create_wl_buffer(struct wlr_wl_backend *wl, @@ -180,34 +223,20 @@ static struct wlr_wl_buffer *create_wl_buffer(struct wlr_wl_backend *wl, return NULL; } - struct wlr_dmabuf_attributes attribs; - if (!wlr_buffer_get_dmabuf(wlr_buffer, &attribs)) { + struct wlr_dmabuf_attributes dmabuf; + struct wlr_shm_attributes shm; + struct wl_buffer *wl_buffer; + if (wlr_buffer_get_dmabuf(wlr_buffer, &dmabuf)) { + wl_buffer = import_dmabuf(wl, &dmabuf); + } else if (wlr_buffer_get_shm(wlr_buffer, &shm)) { + wl_buffer = import_shm(wl, &shm); + } else { return NULL; } - - uint32_t modifier_hi = attribs.modifier >> 32; - uint32_t modifier_lo = (uint32_t)attribs.modifier; - struct zwp_linux_buffer_params_v1 *params = - zwp_linux_dmabuf_v1_create_params(wl->zwp_linux_dmabuf_v1); - for (int i = 0; i < attribs.n_planes; i++) { - zwp_linux_buffer_params_v1_add(params, attribs.fd[i], i, - attribs.offset[i], attribs.stride[i], modifier_hi, modifier_lo); + if (wl_buffer == NULL) { + return NULL; } - uint32_t flags = 0; - if (attribs.flags & WLR_DMABUF_ATTRIBUTES_FLAGS_Y_INVERT) { - flags |= ZWP_LINUX_BUFFER_PARAMS_V1_FLAGS_Y_INVERT; - } - if (attribs.flags & WLR_DMABUF_ATTRIBUTES_FLAGS_INTERLACED) { - flags |= ZWP_LINUX_BUFFER_PARAMS_V1_FLAGS_INTERLACED; - } - if (attribs.flags & WLR_DMABUF_ATTRIBUTES_FLAGS_BOTTOM_FIRST) { - flags |= ZWP_LINUX_BUFFER_PARAMS_V1_FLAGS_BOTTOM_FIRST; - } - struct wl_buffer *wl_buffer = zwp_linux_buffer_params_v1_create_immed( - params, attribs.width, attribs.height, attribs.format, flags); - // TODO: handle create() errors - struct wlr_wl_buffer *buffer = calloc(1, sizeof(struct wlr_wl_buffer)); if (buffer == NULL) { wl_buffer_destroy(wl_buffer); diff --git a/include/backend/wayland.h b/include/backend/wayland.h index d6bed2b61..ddaca335b 100644 --- a/include/backend/wayland.h +++ b/include/backend/wayland.h @@ -38,10 +38,12 @@ struct wlr_wl_backend { struct zxdg_decoration_manager_v1 *zxdg_decoration_manager_v1; struct zwp_pointer_gestures_v1 *zwp_pointer_gestures_v1; struct wp_presentation *presentation; + struct wl_shm *shm; struct zwp_linux_dmabuf_v1 *zwp_linux_dmabuf_v1; struct zwp_relative_pointer_manager_v1 *zwp_relative_pointer_manager_v1; struct wl_list seats; // wlr_wl_seat.link struct zwp_tablet_manager_v2 *tablet_manager; + struct wlr_drm_format_set shm_formats; struct wlr_drm_format_set linux_dmabuf_v1_formats; struct wl_drm *legacy_drm; char *drm_render_name;