aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Ser <contact@emersion.fr>2019-09-24 15:33:15 +0300
committerDrew DeVault <sir@cmpwn.com>2019-10-16 09:40:26 -0400
commit5bddb5a909f9cf768cfcdbdd2bb943eb01484961 (patch)
treef7f76f897f52defa3f497e66fae060fb450b1498
parentcbb2781fed7944dae680a66a35443f5b1a678ec7 (diff)
backend/wayland: add support for direct scan-out
Closes: https://github.com/swaywm/wlroots/issues/1830
-rw-r--r--backend/wayland/backend.c38
-rw-r--r--backend/wayland/output.c94
-rw-r--r--include/backend/wayland.h5
-rw-r--r--protocol/meson.build1
4 files changed, 134 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,
diff --git a/include/backend/wayland.h b/include/backend/wayland.h
index a237ced7..886aea9f 100644
--- a/include/backend/wayland.h
+++ b/include/backend/wayland.h
@@ -12,6 +12,7 @@
#include <wlr/render/egl.h>
#include <wlr/render/wlr_renderer.h>
#include <wlr/types/wlr_box.h>
+#include <wlr/render/drm_format_set.h>
struct wlr_wl_backend {
struct wlr_backend backend;
@@ -34,12 +35,14 @@ struct wlr_wl_backend {
struct xdg_wm_base *xdg_wm_base;
struct zxdg_decoration_manager_v1 *zxdg_decoration_manager_v1;
struct zwp_pointer_gestures_v1 *zwp_pointer_gestures_v1;
+ struct zwp_linux_dmabuf_v1 *zwp_linux_dmabuf_v1;
struct wl_seat *seat;
struct wl_pointer *pointer;
struct wl_keyboard *keyboard;
struct wlr_wl_pointer *current_pointer;
struct zwp_tablet_manager_v2 *tablet_manager;
char *seat_name;
+ struct wlr_drm_format_set linux_dmabuf_v1_formats;
};
struct wlr_wl_output {
@@ -55,6 +58,8 @@ struct wlr_wl_output {
struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1;
struct wl_egl_window *egl_window;
EGLSurface egl_surface;
+ struct wl_buffer *pending_wl_buffer, *current_wl_buffer;
+ struct wlr_buffer *current_buffer;
uint32_t enter_serial;
diff --git a/protocol/meson.build b/protocol/meson.build
index 25694010..13dfaefb 100644
--- a/protocol/meson.build
+++ b/protocol/meson.build
@@ -43,6 +43,7 @@ protocols = [
client_protocols = [
[wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'],
[wl_protocol_dir, 'unstable/idle-inhibit/idle-inhibit-unstable-v1.xml'],
+ [wl_protocol_dir, 'unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml'],
[wl_protocol_dir, 'unstable/pointer-constraints/pointer-constraints-unstable-v1.xml'],
[wl_protocol_dir, 'unstable/pointer-gestures/pointer-gestures-unstable-v1.xml'],
[wl_protocol_dir, 'unstable/relative-pointer/relative-pointer-unstable-v1.xml'],