diff options
author | Simon Ser <contact@emersion.fr> | 2019-09-24 15:33:15 +0300 |
---|---|---|
committer | Drew DeVault <sir@cmpwn.com> | 2019-10-16 09:40:26 -0400 |
commit | 5bddb5a909f9cf768cfcdbdd2bb943eb01484961 (patch) | |
tree | f7f76f897f52defa3f497e66fae060fb450b1498 /backend | |
parent | cbb2781fed7944dae680a66a35443f5b1a678ec7 (diff) |
backend/wayland: add support for direct scan-out
Closes: https://github.com/swaywm/wlroots/issues/1830
Diffstat (limited to 'backend')
-rw-r--r-- | backend/wayland/backend.c | 38 | ||||
-rw-r--r-- | backend/wayland/output.c | 94 |
2 files changed, 128 insertions, 4 deletions
diff --git a/backend/wayland/backend.c b/backend/wayland/backend.c index 7afd5e7e..21dc8ca7 100644 --- a/backend/wayland/backend.c +++ b/backend/wayland/backend.c @@ -5,6 +5,7 @@ #include <wlr/config.h> +#include <drm_fourcc.h> #include <wayland-server-core.h> #include <wlr/backend/interface.h> @@ -16,8 +17,9 @@ #include "backend/wayland.h" #include "util/signal.h" -#include "xdg-decoration-unstable-v1-client-protocol.h" +#include "linux-dmabuf-unstable-v1-client-protocol.h" #include "pointer-gestures-unstable-v1-client-protocol.h" +#include "xdg-decoration-unstable-v1-client-protocol.h" #include "xdg-shell-client-protocol.h" #include "tablet-unstable-v2-client-protocol.h" @@ -59,6 +61,29 @@ static const struct xdg_wm_base_listener xdg_wm_base_listener = { xdg_wm_base_handle_ping, }; +static void linux_dmabuf_v1_handle_format(void *data, + struct zwp_linux_dmabuf_v1 *linux_dmabuf_v1, uint32_t format) { + // Note, this event is deprecated + struct wlr_wl_backend *wl = data; + + wlr_drm_format_set_add(&wl->linux_dmabuf_v1_formats, format, + DRM_FORMAT_MOD_INVALID); +} + +static void linux_dmabuf_v1_handle_modifier(void *data, + struct zwp_linux_dmabuf_v1 *linux_dmabuf_v1, uint32_t format, + uint32_t modifier_hi, uint32_t modifier_lo) { + struct wlr_wl_backend *wl = data; + + uint64_t modifier = ((uint64_t)modifier_hi << 32) | modifier_lo; + wlr_drm_format_set_add(&wl->linux_dmabuf_v1_formats, format, modifier); +} + +static const struct zwp_linux_dmabuf_v1_listener linux_dmabuf_v1_listener = { + .format = linux_dmabuf_v1_handle_format, + .modifier = linux_dmabuf_v1_handle_modifier, +}; + 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; @@ -85,6 +110,12 @@ static void registry_global(void *data, struct wl_registry *registry, } else if (strcmp(iface, zwp_tablet_manager_v2_interface.name) == 0) { wl->tablet_manager = wl_registry_bind(registry, name, &zwp_tablet_manager_v2_interface, 1); + } else if (strcmp(iface, zwp_linux_dmabuf_v1_interface.name) == 0 && + version >= 3) { + wl->zwp_linux_dmabuf_v1 = wl_registry_bind(registry, name, + &zwp_linux_dmabuf_v1_interface, 3); + zwp_linux_dmabuf_v1_add_listener(wl->zwp_linux_dmabuf_v1, + &linux_dmabuf_v1_listener, wl); } } @@ -153,6 +184,8 @@ static void backend_destroy(struct wlr_backend *backend) { wlr_renderer_destroy(wl->renderer); wlr_egl_finish(&wl->egl); + wlr_drm_format_set_finish(&wl->linux_dmabuf_v1_formats); + if (wl->pointer) { wl_pointer_destroy(wl->pointer); } @@ -165,6 +198,9 @@ static void backend_destroy(struct wlr_backend *backend) { if (wl->zwp_pointer_gestures_v1) { zwp_pointer_gestures_v1_destroy(wl->zwp_pointer_gestures_v1); } + if (wl->zwp_linux_dmabuf_v1) { + zwp_linux_dmabuf_v1_destroy(wl->zwp_linux_dmabuf_v1); + } xdg_wm_base_destroy(wl->xdg_wm_base); wl_compositor_destroy(wl->compositor); wl_registry_destroy(wl->registry); diff --git a/backend/wayland/output.c b/backend/wayland/output.c index 1d697d9a..7a13e041 100644 --- a/backend/wayland/output.c +++ b/backend/wayland/output.c @@ -16,6 +16,7 @@ #include "backend/wayland.h" #include "util/signal.h" +#include "linux-dmabuf-unstable-v1-client-protocol.h" #include "xdg-decoration-unstable-v1-client-protocol.h" #include "xdg-shell-client-protocol.h" @@ -59,6 +60,59 @@ static bool output_attach_render(struct wlr_output *wlr_output, buffer_age); } +static bool output_attach_buffer(struct wlr_output *wlr_output, + struct wlr_buffer *buffer) { + struct wlr_wl_output *output = + get_wl_output_from_output(wlr_output); + struct wlr_wl_backend *wl = output->backend; + + struct wlr_dmabuf_attributes attribs; + if (!wlr_buffer_get_dmabuf(buffer, &attribs)) { + return false; + } + + if (attribs.width != wlr_output->width || + attribs.height != wlr_output->height) { + return false; + } + + if (!wlr_drm_format_set_has(&wl->linux_dmabuf_v1_formats, + attribs.format, attribs.modifier)) { + return false; + } + + 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); + } + + 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 + + wl_surface_attach(output->surface, wl_buffer, 0, 0); + + if (output->pending_wl_buffer != NULL) { + wl_buffer_destroy(output->pending_wl_buffer); + } + output->pending_wl_buffer = wl_buffer; + return true; +} + static bool output_commit(struct wlr_output *wlr_output) { struct wlr_wl_output *output = get_wl_output_from_output(wlr_output); @@ -76,13 +130,46 @@ static bool output_commit(struct wlr_output *wlr_output) { damage = &wlr_output->pending.damage; } - if (!wlr_egl_swap_buffers(&output->backend->egl, - output->egl_surface, damage)) { - return false; + wlr_buffer_unref(output->current_buffer); + output->current_buffer = NULL; + if (output->current_wl_buffer != NULL) { + wl_buffer_destroy(output->current_wl_buffer); + output->current_wl_buffer = NULL; + } + + assert(wlr_output->pending.committed & WLR_OUTPUT_STATE_BUFFER); + switch (wlr_output->pending.buffer_type) { + case WLR_OUTPUT_STATE_BUFFER_RENDER: + if (!wlr_egl_swap_buffers(&output->backend->egl, + output->egl_surface, damage)) { + return false; + } + break; + case WLR_OUTPUT_STATE_BUFFER_SCANOUT: + if (damage == NULL) { + wl_surface_damage_buffer(output->surface, + 0, 0, INT32_MAX, INT32_MAX); + } else { + int rects_len; + pixman_box32_t *rects = + pixman_region32_rectangles(damage, &rects_len); + for (int i = 0; i < rects_len; i++) { + pixman_box32_t *r = &rects[i]; + wl_surface_damage_buffer(output->surface, r->x1, r->y1, + r->x2 - r->x1, r->y2 - r->y1); + } + } + wl_surface_commit(output->surface); + + output->current_buffer = wlr_buffer_ref(wlr_output->pending.buffer); + output->current_wl_buffer = output->pending_wl_buffer; + output->pending_wl_buffer = NULL; + break; } // TODO: if available, use the presentation-time protocol wlr_output_send_present(wlr_output, NULL); + return true; } @@ -222,6 +309,7 @@ static const struct wlr_output_impl output_impl = { .set_custom_mode = output_set_custom_mode, .destroy = output_destroy, .attach_render = output_attach_render, + .attach_buffer = output_attach_buffer, .commit = output_commit, .set_cursor = output_set_cursor, .move_cursor = output_move_cursor, |