backend/wayland: add support for direct scan-out
Closes: https://github.com/swaywm/wlroots/issues/1830
This commit is contained in:
parent
cbb2781fed
commit
5bddb5a909
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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'],
|
||||
|
|
Loading…
Reference in New Issue