backend/wayland: add support for direct scan-out

Closes: https://github.com/swaywm/wlroots/issues/1830
This commit is contained in:
Simon Ser 2019-09-24 15:33:15 +03:00 committed by Drew DeVault
parent cbb2781fed
commit 5bddb5a909
4 changed files with 134 additions and 4 deletions

View File

@ -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);

View File

@ -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;
}
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,

View File

@ -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;

View File

@ -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'],