mirror of
https://gitlab.freedesktop.org/monado/monado.git
synced 2025-02-05 13:28:16 +00:00
compositor: overhaul Wayland backend
This simplifies the Wayland backend, fixes the build configuration for it, ports it to xdg-shell stable, and reworks some false assumptions from the original port.
This commit is contained in:
parent
55cbd03a81
commit
9bcfa56f2f
12
meson.build
12
meson.build
|
@ -59,7 +59,17 @@ endif
|
|||
x11 = dependency('x11', required: false)
|
||||
xcb = dependency('xcb', required: false)
|
||||
xcb_randr = dependency('xcb-randr', required: false)
|
||||
wayland = dependency('wayland-client', required: false)
|
||||
|
||||
wayland = dependency('wayland-client', required: false)
|
||||
wayland_protos = dependency('wayland-protocols', required: false)
|
||||
wayland_scanner = dependency('wayland-scanner', required: false)
|
||||
|
||||
if wayland_scanner.found()
|
||||
wayland_scanner = find_program(
|
||||
wayland_scanner.get_pkgconfig_variable('wayland_scanner'),
|
||||
native: true,
|
||||
)
|
||||
endif
|
||||
|
||||
hidapi_required = false
|
||||
openhmd_required = false
|
||||
|
|
|
@ -37,7 +37,6 @@ set(GL_SOURCE_FILES
|
|||
main/comp_swapchain.c
|
||||
main/comp_window.h
|
||||
main/comp_window_direct_mode.cpp
|
||||
main/comp_window_wayland.cpp
|
||||
main/comp_window_xcb.cpp
|
||||
)
|
||||
|
||||
|
|
|
@ -535,6 +535,12 @@ compositor_init_window_pre_vulkan(struct comp_compositor *c)
|
|||
|
||||
switch (c->settings.window_type) {
|
||||
case WINDOW_AUTO:
|
||||
#ifdef VK_USE_PLATFORM_WAYLAND_KHR
|
||||
if (compositor_try_window(c, comp_window_wayland_create(c))) {
|
||||
c->settings.window_type = WINDOW_WAYLAND;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
|
||||
if (compositor_try_window(c, comp_window_direct_create(c))) {
|
||||
c->settings.window_type = WINDOW_DIRECT_RANDR;
|
||||
|
@ -546,12 +552,6 @@ compositor_init_window_pre_vulkan(struct comp_compositor *c)
|
|||
c->settings.window_type = WINDOW_XCB;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
#ifdef VK_USE_PLATFORM_WAYLAND_KHR
|
||||
if (compositor_try_window(c, comp_window_wayland_create(c))) {
|
||||
c->settings.window_type = WINDOW_WAYLAND;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
COMP_ERROR(c, "Failed to auto detect window support!");
|
||||
break;
|
||||
|
|
|
@ -30,7 +30,6 @@ comp_settings_init(struct comp_settings *s, struct xrt_device *xdev)
|
|||
}
|
||||
|
||||
s->display = -1;
|
||||
s->mode = -1;
|
||||
s->color_format = VK_FORMAT_B8G8R8A8_UNORM;
|
||||
s->color_space = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
|
||||
s->present_mode = VK_PRESENT_MODE_FIFO_KHR;
|
||||
|
|
|
@ -53,7 +53,6 @@ enum window_type
|
|||
struct comp_settings
|
||||
{
|
||||
int display;
|
||||
int mode;
|
||||
|
||||
VkFormat color_format;
|
||||
VkColorSpaceKHR color_space;
|
||||
|
|
368
src/xrt/compositor/main/comp_window_wayland.c
Normal file
368
src/xrt/compositor/main/comp_window_wayland.c
Normal file
|
@ -0,0 +1,368 @@
|
|||
// Copyright 2019, Collabora, Ltd.
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
/*!
|
||||
* @file
|
||||
* @brief Wayland window code.
|
||||
* @author Lubosz Sarnecki <lubosz.sarnecki@collabora.com>
|
||||
* @author Jakob Bornecrantz <jakob@collabora.com>
|
||||
* @ingroup comp
|
||||
*/
|
||||
|
||||
#ifdef VK_USE_PLATFORM_WAYLAND_KHR
|
||||
|
||||
#include <errno.h>
|
||||
#include <linux/input.h>
|
||||
#include <poll.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wayland-client.h>
|
||||
|
||||
#include "xdg-shell-client-protocol.h"
|
||||
#include "xrt/xrt_compiler.h"
|
||||
#include "main/comp_window.h"
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Private structs.
|
||||
*
|
||||
*/
|
||||
|
||||
/*!
|
||||
* A Wayland connection and window.
|
||||
*/
|
||||
struct comp_window_wayland
|
||||
{
|
||||
struct comp_window base;
|
||||
|
||||
struct wl_display *display;
|
||||
struct wl_compositor *compositor;
|
||||
struct wl_surface *surface;
|
||||
|
||||
struct xdg_wm_base *wm_base;
|
||||
struct xdg_surface *xdg_surface;
|
||||
struct xdg_toplevel *xdg_toplevel;
|
||||
|
||||
bool fullscreen_requested;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Pre declare functions.
|
||||
*
|
||||
*/
|
||||
|
||||
static void
|
||||
comp_window_wayland_destroy(struct comp_window *w);
|
||||
|
||||
static bool
|
||||
comp_window_wayland_init(struct comp_window *w);
|
||||
|
||||
static void
|
||||
comp_window_wayland_update_window_title(struct comp_window *w,
|
||||
const char *title);
|
||||
|
||||
static void
|
||||
comp_window_wayland_registry_global(struct comp_window_wayland *w,
|
||||
struct wl_registry *registry,
|
||||
uint32_t name,
|
||||
const char *interface);
|
||||
|
||||
static void
|
||||
comp_window_wayland_fullscreen(struct comp_window_wayland *w);
|
||||
|
||||
static bool
|
||||
comp_window_wayland_init_swapchain(struct comp_window *w,
|
||||
uint32_t width,
|
||||
uint32_t height);
|
||||
|
||||
static VkResult
|
||||
comp_window_wayland_create_surface(struct comp_window_wayland *w,
|
||||
VkSurfaceKHR *vk_surface);
|
||||
|
||||
static void
|
||||
comp_window_wayland_flush(struct comp_window *w);
|
||||
|
||||
static void
|
||||
comp_window_wayland_configure(struct comp_window_wayland *w,
|
||||
int32_t width,
|
||||
int32_t height);
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Functions.
|
||||
*
|
||||
*/
|
||||
|
||||
struct comp_window *
|
||||
comp_window_wayland_create(struct comp_compositor *c)
|
||||
{
|
||||
struct comp_window_wayland *w =
|
||||
calloc(1, sizeof(struct comp_window_wayland));
|
||||
|
||||
w->base.name = "wayland";
|
||||
w->base.destroy = comp_window_wayland_destroy;
|
||||
w->base.flush = comp_window_wayland_flush;
|
||||
w->base.init = comp_window_wayland_init;
|
||||
w->base.init_swapchain = comp_window_wayland_init_swapchain;
|
||||
w->base.update_window_title = comp_window_wayland_update_window_title;
|
||||
w->base.c = c;
|
||||
|
||||
return &w->base;
|
||||
}
|
||||
|
||||
static void
|
||||
comp_window_wayland_destroy(struct comp_window *w)
|
||||
{
|
||||
struct comp_window_wayland *w_wayland = (struct comp_window_wayland *)w;
|
||||
|
||||
if (w_wayland->surface) {
|
||||
wl_surface_destroy(w_wayland->surface);
|
||||
w_wayland->surface = NULL;
|
||||
}
|
||||
if (w_wayland->compositor) {
|
||||
wl_compositor_destroy(w_wayland->compositor);
|
||||
w_wayland->compositor = NULL;
|
||||
}
|
||||
if (w_wayland->display) {
|
||||
wl_display_disconnect(w_wayland->display);
|
||||
w_wayland->display = NULL;
|
||||
}
|
||||
|
||||
free(w);
|
||||
}
|
||||
|
||||
static void
|
||||
comp_window_wayland_update_window_title(struct comp_window *w,
|
||||
const char *title)
|
||||
{
|
||||
struct comp_window_wayland *w_wayland = (struct comp_window_wayland *)w;
|
||||
xdg_toplevel_set_title(w_wayland->xdg_toplevel, title);
|
||||
}
|
||||
|
||||
static void
|
||||
comp_window_wayland_fullscreen(struct comp_window_wayland *w)
|
||||
{
|
||||
xdg_toplevel_set_fullscreen(w->xdg_toplevel, NULL);
|
||||
wl_surface_commit(w->surface);
|
||||
}
|
||||
|
||||
static void
|
||||
_xdg_surface_configure_cb(void *data,
|
||||
struct xdg_surface *surface,
|
||||
uint32_t serial)
|
||||
{
|
||||
xdg_surface_ack_configure(surface, serial);
|
||||
}
|
||||
|
||||
static void
|
||||
_xdg_toplevel_configure_cb(void *data,
|
||||
struct xdg_toplevel *toplevel,
|
||||
int32_t width,
|
||||
int32_t height,
|
||||
struct wl_array *states)
|
||||
{
|
||||
struct comp_window_wayland *w = (struct comp_window_wayland *)data;
|
||||
comp_window_wayland_configure(w, width, height);
|
||||
}
|
||||
|
||||
static const struct xdg_surface_listener xdg_surface_listener = {
|
||||
_xdg_surface_configure_cb,
|
||||
};
|
||||
|
||||
static void
|
||||
_xdg_toplevel_close_cb(void *data, struct xdg_toplevel *toplevel)
|
||||
{}
|
||||
|
||||
static const struct xdg_toplevel_listener xdg_toplevel_listener = {
|
||||
_xdg_toplevel_configure_cb,
|
||||
_xdg_toplevel_close_cb,
|
||||
};
|
||||
|
||||
static void
|
||||
_xdg_wm_base_ping_cb(void *data, struct xdg_wm_base *wm_base, uint32_t serial)
|
||||
{
|
||||
xdg_wm_base_pong(wm_base, serial);
|
||||
}
|
||||
|
||||
static const struct xdg_wm_base_listener xdg_wm_base_listener = {
|
||||
_xdg_wm_base_ping_cb,
|
||||
};
|
||||
|
||||
static bool
|
||||
comp_window_wayland_init_swapchain(struct comp_window *w,
|
||||
uint32_t width,
|
||||
uint32_t height)
|
||||
{
|
||||
struct comp_window_wayland *w_wayland = (struct comp_window_wayland *)w;
|
||||
VkResult ret;
|
||||
|
||||
ret = comp_window_wayland_create_surface(w_wayland,
|
||||
&w->swapchain.surface);
|
||||
if (ret != VK_SUCCESS) {
|
||||
COMP_ERROR(w->c, "Failed to create surface!");
|
||||
return false;
|
||||
}
|
||||
|
||||
vk_swapchain_create(
|
||||
&w->swapchain, width, height, w->c->settings.color_format,
|
||||
w->c->settings.color_space, w->c->settings.present_mode);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static VkResult
|
||||
comp_window_wayland_create_surface(struct comp_window_wayland *w,
|
||||
VkSurfaceKHR *vk_surface)
|
||||
{
|
||||
struct vk_bundle *vk = w->base.swapchain.vk;
|
||||
VkResult ret;
|
||||
|
||||
VkWaylandSurfaceCreateInfoKHR surface_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR,
|
||||
.pNext = NULL,
|
||||
.flags = 0,
|
||||
.display = w->display,
|
||||
.surface = w->surface,
|
||||
};
|
||||
|
||||
ret = vk->vkCreateWaylandSurfaceKHR(vk->instance, &surface_info, NULL,
|
||||
vk_surface);
|
||||
if (ret != VK_SUCCESS) {
|
||||
COMP_ERROR(w->base.c, "vkCreateWaylandSurfaceKHR: %s",
|
||||
vk_result_string(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
static void
|
||||
comp_window_wayland_flush(struct comp_window *w)
|
||||
{
|
||||
struct comp_window_wayland *w_wayland = (struct comp_window_wayland *)w;
|
||||
|
||||
while (wl_display_prepare_read(w_wayland->display) != 0)
|
||||
wl_display_dispatch_pending(w_wayland->display);
|
||||
if (wl_display_flush(w_wayland->display) < 0 && errno != EAGAIN) {
|
||||
wl_display_cancel_read(w_wayland->display);
|
||||
return;
|
||||
}
|
||||
|
||||
struct pollfd fds[] = {
|
||||
{
|
||||
.fd = wl_display_get_fd(w_wayland->display),
|
||||
.events = POLLIN,
|
||||
.revents = 0,
|
||||
},
|
||||
};
|
||||
|
||||
if (poll(fds, 1, 0) > 0) {
|
||||
wl_display_read_events(w_wayland->display);
|
||||
wl_display_dispatch_pending(w_wayland->display);
|
||||
} else {
|
||||
wl_display_cancel_read(w_wayland->display);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_registry_global_remove_cb(void *data,
|
||||
struct wl_registry *registry,
|
||||
uint32_t name)
|
||||
{}
|
||||
|
||||
static void
|
||||
_registry_global_cb(void *data,
|
||||
struct wl_registry *registry,
|
||||
uint32_t name,
|
||||
const char *interface,
|
||||
uint32_t version)
|
||||
{
|
||||
struct comp_window_wayland *w = (struct comp_window_wayland *)data;
|
||||
// vik_log_d("Interface: %s Version %d", interface, version);
|
||||
comp_window_wayland_registry_global(w, registry, name, interface);
|
||||
}
|
||||
|
||||
static const struct wl_registry_listener registry_listener = {
|
||||
_registry_global_cb,
|
||||
_registry_global_remove_cb,
|
||||
};
|
||||
|
||||
static void
|
||||
comp_window_wayland_registry_global(struct comp_window_wayland *w,
|
||||
struct wl_registry *registry,
|
||||
uint32_t name,
|
||||
const char *interface)
|
||||
{
|
||||
if (strcmp(interface, "wl_compositor") == 0) {
|
||||
w->compositor = (struct wl_compositor *)wl_registry_bind(
|
||||
registry, name, &wl_compositor_interface, 4);
|
||||
} else if (strcmp(interface, "xdg_wm_base") == 0) {
|
||||
w->wm_base = (struct xdg_wm_base *)wl_registry_bind(
|
||||
registry, name, &xdg_wm_base_interface, 1);
|
||||
xdg_wm_base_add_listener(w->wm_base, &xdg_wm_base_listener, w);
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
comp_window_wayland_init(struct comp_window *w)
|
||||
{
|
||||
struct comp_window_wayland *w_wayland = (struct comp_window_wayland *)w;
|
||||
|
||||
w_wayland->display = wl_display_connect(NULL);
|
||||
if (!w_wayland->display) {
|
||||
return false;
|
||||
}
|
||||
|
||||
struct wl_registry *registry =
|
||||
wl_display_get_registry(w_wayland->display);
|
||||
wl_registry_add_listener(registry, ®istry_listener, w_wayland);
|
||||
|
||||
wl_display_roundtrip(w_wayland->display);
|
||||
|
||||
wl_registry_destroy(registry);
|
||||
|
||||
w_wayland->surface =
|
||||
wl_compositor_create_surface(w_wayland->compositor);
|
||||
|
||||
if (!w_wayland->wm_base) {
|
||||
COMP_ERROR(w->c, "Compositor is missing xdg-shell support");
|
||||
}
|
||||
|
||||
w_wayland->xdg_surface =
|
||||
xdg_wm_base_get_xdg_surface(w_wayland->wm_base, w_wayland->surface);
|
||||
|
||||
xdg_surface_add_listener(w_wayland->xdg_surface, &xdg_surface_listener,
|
||||
w_wayland);
|
||||
|
||||
w_wayland->xdg_toplevel =
|
||||
xdg_surface_get_toplevel(w_wayland->xdg_surface);
|
||||
|
||||
xdg_toplevel_add_listener(w_wayland->xdg_toplevel,
|
||||
&xdg_toplevel_listener, w_wayland);
|
||||
/* Sane defaults */
|
||||
xdg_toplevel_set_app_id(w_wayland->xdg_toplevel, "openxr");
|
||||
xdg_toplevel_set_title(w_wayland->xdg_toplevel, "OpenXR application");
|
||||
|
||||
wl_surface_commit(w_wayland->surface);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
comp_window_wayland_configure(struct comp_window_wayland *w,
|
||||
int32_t width,
|
||||
int32_t height)
|
||||
{
|
||||
if (w->base.c->settings.fullscreen && !w->fullscreen_requested) {
|
||||
COMP_DEBUG(w->base.c, "Setting full screen");
|
||||
comp_window_wayland_fullscreen(w);
|
||||
w->fullscreen_requested = true;
|
||||
}
|
||||
// TODO: resize cb
|
||||
// resize_cb(m->size.first, m->size.second);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,629 +0,0 @@
|
|||
// Copyright 2019, Collabora, Ltd.
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
/*!
|
||||
* @file
|
||||
* @brief Wayland window code.
|
||||
* @author Lubosz Sarnecki <lubosz.sarnecki@collabora.com>
|
||||
* @author Jakob Bornecrantz <jakob@collabora.com>
|
||||
* @ingroup comp
|
||||
*/
|
||||
|
||||
#ifdef VK_USE_PLATFORM_WAYLAND_KHR
|
||||
|
||||
#include <poll.h>
|
||||
#include <linux/input.h>
|
||||
#include <wayland-client.h>
|
||||
#include "xdg-shell-unstable-v6.h"
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <cstring>
|
||||
|
||||
#include "xrt/xrt_compiler.h"
|
||||
#include "main/comp_window.h"
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Private structs.
|
||||
*
|
||||
*/
|
||||
|
||||
/*!
|
||||
* Wayland display mode.
|
||||
*/
|
||||
struct comp_window_wayland_mode
|
||||
{
|
||||
std::pair<int, int> size;
|
||||
int refresh;
|
||||
};
|
||||
|
||||
/*!
|
||||
* A single Wayland display.
|
||||
*/
|
||||
struct comp_window_wayland_display
|
||||
{
|
||||
wl_output *output;
|
||||
std::string make;
|
||||
std::string model;
|
||||
std::vector<comp_window_wayland_mode> modes;
|
||||
std::pair<int, int> physical_size_mm;
|
||||
std::pair<int, int> position;
|
||||
};
|
||||
|
||||
/*!
|
||||
* A Wayland connection and window.
|
||||
*/
|
||||
struct comp_window_wayland
|
||||
{
|
||||
struct comp_window base = comp_window();
|
||||
|
||||
wl_display *display = nullptr;
|
||||
wl_compositor *compositor = nullptr;
|
||||
wl_surface *surface = nullptr;
|
||||
|
||||
zxdg_shell_v6 *shell = nullptr;
|
||||
zxdg_surface_v6 *xdg_surface = nullptr;
|
||||
zxdg_toplevel_v6 *xdg_toplevel = nullptr;
|
||||
|
||||
std::vector<comp_window_wayland_display> displays = {};
|
||||
|
||||
bool is_configured = false;
|
||||
bool first_configure = true;
|
||||
bool fullscreen_requested = false;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Pre declare functions.
|
||||
*
|
||||
*/
|
||||
|
||||
static void
|
||||
comp_window_wayland_destroy(struct comp_window *w);
|
||||
|
||||
static bool
|
||||
comp_window_wayland_init(struct comp_window *w);
|
||||
|
||||
static void
|
||||
comp_window_wayland_update_window_title(struct comp_window *w,
|
||||
const char *title);
|
||||
|
||||
static void
|
||||
comp_window_wayland_registry_global(struct comp_window_wayland *w,
|
||||
wl_registry *registry,
|
||||
uint32_t name,
|
||||
const char *interface);
|
||||
|
||||
static void
|
||||
comp_window_wayland_fullscreen(struct comp_window_wayland *w);
|
||||
|
||||
static void
|
||||
comp_window_wayland_fullscreen(struct comp_window_wayland *w,
|
||||
wl_output *output);
|
||||
|
||||
static bool
|
||||
comp_window_wayland_init_swapchain(struct comp_window *w,
|
||||
uint32_t width,
|
||||
uint32_t height);
|
||||
|
||||
static VkResult
|
||||
comp_window_wayland_create_surface(struct comp_window_wayland *w,
|
||||
VkSurfaceKHR *vk_surface);
|
||||
|
||||
static void
|
||||
comp_window_wayland_flush(struct comp_window *w);
|
||||
|
||||
static void
|
||||
comp_window_wayland_output_mode(struct comp_window_wayland *w,
|
||||
wl_output *output,
|
||||
unsigned int flags,
|
||||
int width,
|
||||
int height,
|
||||
int refresh);
|
||||
|
||||
static comp_window_wayland_display *
|
||||
comp_window_wayland_get_display_from_output(struct comp_window_wayland *w,
|
||||
wl_output *output);
|
||||
|
||||
XRT_MAYBE_UNUSED static void
|
||||
comp_window_wayland_print_displays(struct comp_window_wayland *w);
|
||||
|
||||
static comp_window_wayland_display *
|
||||
comp_window_wayland_current_display(struct comp_window_wayland *w);
|
||||
|
||||
static comp_window_wayland_mode *
|
||||
comp_window_wayland_current_mode(struct comp_window_wayland *w);
|
||||
|
||||
static std::string
|
||||
mode_to_string(comp_window_wayland_mode *m);
|
||||
|
||||
static void
|
||||
comp_window_wayland_validate_display(struct comp_window_wayland *w);
|
||||
|
||||
static void
|
||||
validate_mode(struct comp_window_wayland *w);
|
||||
|
||||
static void
|
||||
comp_window_wayland_configure(struct comp_window_wayland *w,
|
||||
int32_t width,
|
||||
int32_t height);
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Functions.
|
||||
*
|
||||
*/
|
||||
|
||||
extern "C" struct comp_window *
|
||||
comp_window_wayland_create(struct comp_compositor *c)
|
||||
{
|
||||
auto w = new comp_window_wayland();
|
||||
|
||||
w->base.name = "wayland";
|
||||
w->base.destroy = comp_window_wayland_destroy;
|
||||
w->base.flush = comp_window_wayland_flush;
|
||||
w->base.init = comp_window_wayland_init;
|
||||
w->base.init_swapchain = comp_window_wayland_init_swapchain;
|
||||
w->base.update_window_title = comp_window_wayland_update_window_title;
|
||||
w->base.c = c;
|
||||
|
||||
return &w->base;
|
||||
}
|
||||
|
||||
static void
|
||||
comp_window_wayland_destroy(struct comp_window *w)
|
||||
{
|
||||
struct comp_window_wayland *w_wayland = (struct comp_window_wayland *)w;
|
||||
|
||||
if (w_wayland->surface) {
|
||||
wl_surface_destroy(w_wayland->surface);
|
||||
w_wayland->surface = nullptr;
|
||||
}
|
||||
if (w_wayland->compositor) {
|
||||
wl_compositor_destroy(w_wayland->compositor);
|
||||
w_wayland->compositor = nullptr;
|
||||
}
|
||||
if (w_wayland->display) {
|
||||
wl_display_disconnect(w_wayland->display);
|
||||
w_wayland->display = nullptr;
|
||||
}
|
||||
|
||||
delete w;
|
||||
}
|
||||
|
||||
static void
|
||||
comp_window_wayland_update_window_title(struct comp_window *w,
|
||||
const char *title)
|
||||
{
|
||||
struct comp_window_wayland *w_wayland = (struct comp_window_wayland *)w;
|
||||
zxdg_toplevel_v6_set_title(w_wayland->xdg_toplevel, title);
|
||||
}
|
||||
|
||||
static void
|
||||
comp_window_wayland_fullscreen(struct comp_window_wayland *w)
|
||||
{
|
||||
comp_window_wayland_fullscreen(
|
||||
w, comp_window_wayland_current_display(w)->output);
|
||||
}
|
||||
|
||||
static void
|
||||
comp_window_wayland_fullscreen(struct comp_window_wayland *w, wl_output *output)
|
||||
{
|
||||
zxdg_toplevel_v6_set_fullscreen(w->xdg_toplevel, output);
|
||||
wl_surface_commit(w->surface);
|
||||
}
|
||||
|
||||
static void
|
||||
_xdg_surface_configure_cb(void *data, zxdg_surface_v6 *surface, uint32_t serial)
|
||||
{
|
||||
zxdg_surface_v6_ack_configure(surface, serial);
|
||||
}
|
||||
|
||||
static void
|
||||
_xdg_toplevel_configure_cb(void *data,
|
||||
zxdg_toplevel_v6 *toplevel,
|
||||
int32_t width,
|
||||
int32_t height,
|
||||
struct wl_array *states)
|
||||
{
|
||||
comp_window_wayland *w = (comp_window_wayland *)data;
|
||||
comp_window_wayland_configure(w, width, height);
|
||||
}
|
||||
|
||||
static const zxdg_surface_v6_listener xdg_surface_listener = {
|
||||
_xdg_surface_configure_cb,
|
||||
};
|
||||
|
||||
static void
|
||||
_xdg_toplevel_close_cb(void *data, zxdg_toplevel_v6 *toplevel)
|
||||
{}
|
||||
|
||||
static const zxdg_toplevel_v6_listener xdg_toplevel_listener = {
|
||||
_xdg_toplevel_configure_cb,
|
||||
_xdg_toplevel_close_cb,
|
||||
};
|
||||
|
||||
static void
|
||||
_xdg_shell_ping_cb(void *data, zxdg_shell_v6 *shell, uint32_t serial)
|
||||
{
|
||||
zxdg_shell_v6_pong(shell, serial);
|
||||
}
|
||||
|
||||
const zxdg_shell_v6_listener xdg_shell_listener = {
|
||||
_xdg_shell_ping_cb,
|
||||
};
|
||||
|
||||
static bool
|
||||
comp_window_wayland_init_swapchain(struct comp_window *w,
|
||||
uint32_t width,
|
||||
uint32_t height)
|
||||
{
|
||||
struct comp_window_wayland *w_wayland = (struct comp_window_wayland *)w;
|
||||
VkResult ret;
|
||||
|
||||
ret = comp_window_wayland_create_surface(w_wayland,
|
||||
&w->swapchain.surface);
|
||||
if (ret != VK_SUCCESS) {
|
||||
COMP_ERROR(w->c, "Failed to create surface!");
|
||||
return false;
|
||||
}
|
||||
|
||||
vk_swapchain_create(
|
||||
&w->swapchain, width, height, w->c->settings.color_format,
|
||||
w->c->settings.color_space, w->c->settings.present_mode);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static VkResult
|
||||
comp_window_wayland_create_surface(struct comp_window_wayland *w,
|
||||
VkSurfaceKHR *vk_surface)
|
||||
{
|
||||
struct vk_bundle *vk = w->base.swapchain.vk;
|
||||
VkResult ret;
|
||||
|
||||
VkWaylandSurfaceCreateInfoKHR surface_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR,
|
||||
.pNext = nullptr,
|
||||
.flags = 0,
|
||||
.display = w->display,
|
||||
.surface = w->surface,
|
||||
};
|
||||
|
||||
ret = vk->vkCreateWaylandSurfaceKHR(vk->instance, &surface_info, NULL,
|
||||
vk_surface);
|
||||
if (ret != VK_SUCCESS) {
|
||||
COMP_ERROR(w->base.c, "vkCreateWaylandSurfaceKHR: %s",
|
||||
vk_result_string(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
static void
|
||||
comp_window_wayland_flush(struct comp_window *w)
|
||||
{
|
||||
struct comp_window_wayland *w_wayland = (struct comp_window_wayland *)w;
|
||||
|
||||
while (wl_display_prepare_read(w_wayland->display) != 0)
|
||||
wl_display_dispatch_pending(w_wayland->display);
|
||||
if (wl_display_flush(w_wayland->display) < 0 && errno != EAGAIN) {
|
||||
wl_display_cancel_read(w_wayland->display);
|
||||
return;
|
||||
}
|
||||
|
||||
struct pollfd fds[] = {
|
||||
{
|
||||
.fd = wl_display_get_fd(w_wayland->display),
|
||||
.events = POLLIN,
|
||||
.revents = 0,
|
||||
},
|
||||
};
|
||||
|
||||
if (poll(fds, 1, 0) > 0) {
|
||||
wl_display_read_events(w_wayland->display);
|
||||
wl_display_dispatch_pending(w_wayland->display);
|
||||
} else {
|
||||
wl_display_cancel_read(w_wayland->display);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
comp_window_wayland_output_mode(struct comp_window_wayland *w,
|
||||
wl_output *output,
|
||||
unsigned int flags,
|
||||
int width,
|
||||
int height,
|
||||
int refresh)
|
||||
{
|
||||
comp_window_wayland_mode m = {};
|
||||
m.size = {width, height};
|
||||
m.refresh = refresh;
|
||||
|
||||
comp_window_wayland_display *d =
|
||||
comp_window_wayland_get_display_from_output(w, output);
|
||||
if (d == nullptr) {
|
||||
COMP_ERROR(w->base.c, "Output mode callback before geomentry!");
|
||||
return;
|
||||
}
|
||||
|
||||
d->modes.push_back(m);
|
||||
}
|
||||
|
||||
static void
|
||||
_output_done_cb(void *data, wl_output *output)
|
||||
{}
|
||||
|
||||
static void
|
||||
_output_scale_cb(void *data, wl_output *output, int scale)
|
||||
{}
|
||||
|
||||
static void
|
||||
_registry_global_remove_cb(void *data, wl_registry *registry, uint32_t name)
|
||||
{}
|
||||
|
||||
static void
|
||||
_registry_global_cb(void *data,
|
||||
wl_registry *registry,
|
||||
uint32_t name,
|
||||
const char *interface,
|
||||
uint32_t version)
|
||||
{
|
||||
comp_window_wayland *w = (comp_window_wayland *)data;
|
||||
// vik_log_d("Interface: %s Version %d", interface, version);
|
||||
comp_window_wayland_registry_global(w, registry, name, interface);
|
||||
}
|
||||
|
||||
static void
|
||||
_output_mode_cb(void *data,
|
||||
wl_output *output,
|
||||
unsigned int flags,
|
||||
int width,
|
||||
int height,
|
||||
int refresh)
|
||||
{
|
||||
comp_window_wayland *w = (comp_window_wayland *)data;
|
||||
comp_window_wayland_output_mode(w, output, flags, width, height,
|
||||
refresh);
|
||||
}
|
||||
|
||||
static void
|
||||
_output_geometry_cb(void *data,
|
||||
wl_output *output,
|
||||
int x,
|
||||
int y,
|
||||
int w,
|
||||
int h,
|
||||
int subpixel,
|
||||
const char *make,
|
||||
const char *model,
|
||||
int transform)
|
||||
{
|
||||
comp_window_wayland_display d = {};
|
||||
d.output = output;
|
||||
d.make = std::string(make);
|
||||
d.model = std::string(model);
|
||||
d.physical_size_mm = {w, h};
|
||||
d.position = {x, y};
|
||||
|
||||
comp_window_wayland *self = (comp_window_wayland *)data;
|
||||
self->displays.push_back(d);
|
||||
}
|
||||
|
||||
// listeners
|
||||
static const wl_registry_listener registry_listener = {
|
||||
_registry_global_cb,
|
||||
_registry_global_remove_cb,
|
||||
};
|
||||
|
||||
static const wl_output_listener output_listener = {
|
||||
_output_geometry_cb,
|
||||
_output_mode_cb,
|
||||
_output_done_cb,
|
||||
_output_scale_cb,
|
||||
};
|
||||
|
||||
static void
|
||||
comp_window_wayland_registry_global(struct comp_window_wayland *w,
|
||||
wl_registry *registry,
|
||||
uint32_t name,
|
||||
const char *interface)
|
||||
{
|
||||
if (strcmp(interface, "wl_compositor") == 0) {
|
||||
w->compositor = (wl_compositor *)wl_registry_bind(
|
||||
registry, name, &wl_compositor_interface, 4);
|
||||
} else if (strcmp(interface, "zxdg_shell_v6") == 0) {
|
||||
w->shell = (zxdg_shell_v6 *)wl_registry_bind(
|
||||
registry, name, &zxdg_shell_v6_interface, 1);
|
||||
zxdg_shell_v6_add_listener(w->shell, &xdg_shell_listener, w);
|
||||
} else if (strcmp(interface, "wl_output") == 0) {
|
||||
wl_output *_output = (wl_output *)wl_registry_bind(
|
||||
registry, name, &wl_output_interface, 2);
|
||||
wl_output_add_listener(_output, &output_listener, w);
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
comp_window_wayland_init(struct comp_window *w)
|
||||
{
|
||||
struct comp_window_wayland *w_wayland = (struct comp_window_wayland *)w;
|
||||
|
||||
w_wayland->display = wl_display_connect(NULL);
|
||||
if (!w_wayland->display) {
|
||||
return false;
|
||||
}
|
||||
|
||||
wl_registry *registry = wl_display_get_registry(w_wayland->display);
|
||||
wl_registry_add_listener(registry, ®istry_listener, w_wayland);
|
||||
|
||||
wl_display_roundtrip(w_wayland->display);
|
||||
|
||||
wl_registry_destroy(registry);
|
||||
|
||||
w_wayland->surface =
|
||||
wl_compositor_create_surface(w_wayland->compositor);
|
||||
|
||||
if (!w_wayland->shell) {
|
||||
COMP_ERROR(
|
||||
w->c,
|
||||
"Compositor is missing unstable zxdg_shell_v6 support");
|
||||
}
|
||||
|
||||
w_wayland->xdg_surface =
|
||||
zxdg_shell_v6_get_xdg_surface(w_wayland->shell, w_wayland->surface);
|
||||
|
||||
zxdg_surface_v6_add_listener(w_wayland->xdg_surface,
|
||||
&xdg_surface_listener, w_wayland);
|
||||
|
||||
w_wayland->xdg_toplevel =
|
||||
zxdg_surface_v6_get_toplevel(w_wayland->xdg_surface);
|
||||
|
||||
zxdg_toplevel_v6_add_listener(w_wayland->xdg_toplevel,
|
||||
&xdg_toplevel_listener, w_wayland);
|
||||
|
||||
wl_surface_commit(w_wayland->surface);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static comp_window_wayland_display *
|
||||
comp_window_wayland_get_display_from_output(struct comp_window_wayland *w,
|
||||
wl_output *output)
|
||||
{
|
||||
for (int i = 0; i < (int)w->displays.size(); i++) {
|
||||
if (w->displays[i].output == output)
|
||||
return &w->displays[i];
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
XRT_MAYBE_UNUSED static void
|
||||
comp_window_wayland_print_displays(struct comp_window_wayland *w)
|
||||
{
|
||||
int i_d = 0;
|
||||
COMP_DEBUG(w->base.c, "Available displays:");
|
||||
for (auto d : w->displays) {
|
||||
COMP_DEBUG(w->base.c, "%d: %s %s [%d, %d] %dx%dmm (%d Modes)",
|
||||
i_d, d.make.c_str(), d.model.c_str(),
|
||||
d.position.first, d.position.second,
|
||||
d.physical_size_mm.first, d.physical_size_mm.second,
|
||||
(int)d.modes.size());
|
||||
|
||||
int i_m = 0;
|
||||
for (auto m : d.modes) {
|
||||
COMP_DEBUG(w->base.c, "\t%d: %s", i_m,
|
||||
mode_to_string(&m).c_str());
|
||||
i_m++;
|
||||
}
|
||||
i_d++;
|
||||
}
|
||||
}
|
||||
|
||||
static comp_window_wayland_display *
|
||||
comp_window_wayland_current_display(struct comp_window_wayland *w)
|
||||
{
|
||||
return &w->displays[w->base.c->settings.display];
|
||||
}
|
||||
|
||||
static comp_window_wayland_mode *
|
||||
comp_window_wayland_current_mode(struct comp_window_wayland *w)
|
||||
{
|
||||
return &comp_window_wayland_current_display(w)
|
||||
->modes[w->base.c->settings.mode];
|
||||
}
|
||||
|
||||
static std::string
|
||||
mode_to_string(comp_window_wayland_mode *m)
|
||||
{
|
||||
auto size = std::snprintf(nullptr, 0, "%d x %d @ %.2fHz", m->size.first,
|
||||
m->size.second, (float)m->refresh / 1000.0);
|
||||
std::string output(size + 1, '\0');
|
||||
std::snprintf(&output[0], size, "%d x %d @ %.2fHz", m->size.first,
|
||||
m->size.second, (float)m->refresh / 1000.0);
|
||||
return std::string(output);
|
||||
}
|
||||
|
||||
static void
|
||||
comp_window_wayland_validate_display(struct comp_window_wayland *w)
|
||||
{
|
||||
comp_window_wayland_display *d;
|
||||
|
||||
if (w->base.c->settings.display < 0)
|
||||
w->base.c->settings.display = 0;
|
||||
|
||||
if (w->base.c->settings.display > (int)w->displays.size()) {
|
||||
COMP_DEBUG(w->base.c,
|
||||
"Requested display %d, but only %d displays are "
|
||||
"available.",
|
||||
w->base.c->settings.display,
|
||||
(int)w->displays.size());
|
||||
|
||||
w->base.c->settings.display = 0;
|
||||
d = comp_window_wayland_current_display(w);
|
||||
COMP_DEBUG(w->base.c, "Selecting '%s %s' instead.",
|
||||
d->make.c_str(), d->model.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
validate_mode(struct comp_window_wayland *w)
|
||||
{
|
||||
comp_window_wayland_display *d = comp_window_wayland_current_display(w);
|
||||
|
||||
if (w->base.c->settings.mode < 0)
|
||||
w->base.c->settings.mode = 0;
|
||||
|
||||
if (w->base.c->settings.mode > (int)d->modes.size()) {
|
||||
COMP_DEBUG(w->base.c,
|
||||
"Requested mode %d, but only %d modes"
|
||||
" are available on display %d.",
|
||||
w->base.c->settings.mode, (int)d->modes.size(),
|
||||
w->base.c->settings.display);
|
||||
w->base.c->settings.mode = 0;
|
||||
COMP_DEBUG(w->base.c, "Selecting '%s' instead",
|
||||
mode_to_string(comp_window_wayland_current_mode(w))
|
||||
.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
comp_window_wayland_configure(struct comp_window_wayland *w,
|
||||
int32_t width,
|
||||
int32_t height)
|
||||
{
|
||||
if (w->first_configure) {
|
||||
comp_window_wayland_validate_display(w);
|
||||
validate_mode(w);
|
||||
w->first_configure = false;
|
||||
}
|
||||
|
||||
comp_window_wayland_mode *m = comp_window_wayland_current_mode(w);
|
||||
if (w->fullscreen_requested &&
|
||||
(m->size.first != width || m->size.second != height)) {
|
||||
COMP_DEBUG(w->base.c,
|
||||
"Received mode %dx%d does not match requested Mode "
|
||||
"%dx%d. "
|
||||
"Compositor bug? Requesting again.",
|
||||
width, height, m->size.first, m->size.second);
|
||||
w->fullscreen_requested = false;
|
||||
}
|
||||
|
||||
m = comp_window_wayland_current_mode(w);
|
||||
if (w->base.c->settings.fullscreen && !w->fullscreen_requested) {
|
||||
COMP_DEBUG(
|
||||
w->base.c, "Setting full screen on Display %d Mode %s",
|
||||
w->base.c->settings.display, mode_to_string(m).c_str());
|
||||
comp_window_wayland_fullscreen(w);
|
||||
w->fullscreen_requested = true;
|
||||
// TODO: resize cb
|
||||
// resize_cb(m->size.first, m->size.second);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -49,12 +49,46 @@ if xcb_randr.found()
|
|||
compositor_deps += [xcb_randr]
|
||||
endif
|
||||
|
||||
# TODO: This backend is straight-up broken
|
||||
#if wayland.found()
|
||||
# compile_args += ['-DVK_USE_PLATFORM_WAYLAND_KHR']
|
||||
# compositor_srcs += ['main/comp_window_wayland.cpp']
|
||||
# compositor_deps += [wayland]
|
||||
#endif
|
||||
if wayland.found() and wayland_protos.found() and wayland_scanner.found()
|
||||
wl_protos_src = []
|
||||
wl_protos_headers = []
|
||||
wl_protocol_dir = wayland_protos.get_pkgconfig_variable('pkgdatadir')
|
||||
|
||||
protocols = [
|
||||
[wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'],
|
||||
]
|
||||
|
||||
foreach p : protocols
|
||||
xml = join_paths(p)
|
||||
wl_protos_src += custom_target(
|
||||
xml.underscorify() + '_c',
|
||||
input: xml,
|
||||
output: '@BASENAME@-protocol.c',
|
||||
command: [wayland_scanner, 'private-code', '@INPUT@', '@OUTPUT@'],
|
||||
)
|
||||
wl_protos_headers += custom_target(
|
||||
xml.underscorify() + '_client_h',
|
||||
input: xml,
|
||||
output: '@BASENAME@-client-protocol.h',
|
||||
command: [wayland_scanner, 'client-header', '@INPUT@', '@OUTPUT@'],
|
||||
)
|
||||
endforeach
|
||||
|
||||
lib_wl_protos = static_library(
|
||||
'wl_protos',
|
||||
wl_protos_src + wl_protos_headers,
|
||||
dependencies: wayland.partial_dependency(compile_args: true),
|
||||
)
|
||||
|
||||
wl_protos = declare_dependency(
|
||||
link_with: lib_wl_protos,
|
||||
sources: wl_protos_headers,
|
||||
)
|
||||
|
||||
compile_args += ['-DVK_USE_PLATFORM_WAYLAND_KHR']
|
||||
compositor_srcs += ['main/comp_window_wayland.c']
|
||||
compositor_deps += [wayland, wl_protos]
|
||||
endif
|
||||
|
||||
if get_option('vulkan-validation')
|
||||
compile_args += ['-DXRT_ENABLE_VK_VALIDATION']
|
||||
|
|
Loading…
Reference in a new issue