28#include <vulkan/vulkan.h>
29#include <vulkan/vulkan_wayland.h>
34#include <wayland-client.h>
35#include "xdg-shell-client-protocol.h"
36#include "xdg-decoration-client-protocol.h"
37#include <xkbcommon/xkbcommon.h>
38#include <linux/input-event-codes.h>
44template <
class T,
class... Args>
46 std::function<T(Args...)>
func;
50 return funcwrap->
func(std::forward<Args>(args)...);
65int32_t GPUDisplayFrontendWayland::GetKey(uint32_t
key, uint32_t state)
69 xkb_keysym_t sym = xkb_state_key_get_one_sym(mXKBstate,
key + 8);
72 }
else if (sym == 65451) {
74 }
else if (sym == XKB_KEY_Shift_L || sym == XKB_KEY_Shift_R) {
76 }
else if (sym == XKB_KEY_Alt_L) {
78 }
else if (sym == XKB_KEY_ISO_Level3_Shift || sym == XKB_KEY_Alt_R) {
80 }
else if (sym == XKB_KEY_Control_L) {
82 }
else if (sym == XKB_KEY_Control_R) {
84 }
else if (sym == XKB_KEY_Up) {
86 }
else if (sym == XKB_KEY_Down) {
88 }
else if (sym == XKB_KEY_Left) {
90 }
else if (sym == XKB_KEY_Right) {
92 }
else if (sym == XKB_KEY_Page_Up) {
94 }
else if (sym == XKB_KEY_Page_Down) {
96 }
else if (sym == XKB_KEY_Escape) {
98 }
else if (sym == XKB_KEY_Return) {
100 }
else if (sym == XKB_KEY_End) {
102 }
else if (sym == XKB_KEY_Home) {
104 }
else if (sym == XKB_KEY_Insert) {
106 }
else if (sym == XKB_KEY_F1) {
108 }
else if (sym == XKB_KEY_F2) {
110 }
else if (sym == XKB_KEY_F3) {
112 }
else if (sym == XKB_KEY_F4) {
114 }
else if (sym == XKB_KEY_F5) {
116 }
else if (sym == XKB_KEY_F6) {
118 }
else if (sym == XKB_KEY_F7) {
120 }
else if (sym == XKB_KEY_F8) {
122 }
else if (sym == XKB_KEY_F9) {
124 }
else if (sym == XKB_KEY_F10) {
126 }
else if (sym == XKB_KEY_F11) {
128 }
else if (sym == XKB_KEY_F12) {
130 }
else if (sym == 32) {
132 }
else if (sym > 255) {
135 retVal = xkb_keysym_to_utf32(sym);
144void GPUDisplayFrontendWayland::createBuffer(uint32_t
width, uint32_t
height)
148 if (ftruncate(mFd,
size) < 0) {
149 throw std::runtime_error(
"Error setting waysland shm file size");
151 void* shm_data = mmap(
nullptr,
size, PROT_READ | PROT_WRITE, MAP_SHARED, mFd, 0);
152 if (shm_data == MAP_FAILED) {
153 throw std::runtime_error(
"wayland mmap failed");
155 memset(shm_data, 0,
size);
156 munmap(shm_data,
size);
158 mPool = wl_shm_create_pool(mShm, mFd,
size);
159 mBuffer = wl_shm_pool_create_buffer(mPool, 0,
width,
height,
stride, WL_SHM_FORMAT_XRGB8888);
162 wl_surface_attach(mSurface, mBuffer, 0, 0);
163 wl_surface_commit(mSurface);
166void GPUDisplayFrontendWayland::recreateBuffer(uint32_t
width, uint32_t
height)
168 wl_surface_attach(mSurface,
nullptr, 0, 0);
169 wl_surface_commit(mSurface);
170 wl_buffer_destroy(mBuffer);
171 wl_shm_pool_destroy(mPool);
175int32_t GPUDisplayFrontendWayland::FrontendMain()
178 fprintf(stderr,
"Only Vulkan backend supported\n");
182 mXKBcontext = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
183 if (mXKBcontext ==
nullptr) {
184 throw std::runtime_error(
"Error initializing xkb context");
187 mWayland = wl_display_connect(
nullptr);
188 if (mWayland ==
nullptr) {
189 throw std::runtime_error(
"Could not connect to wayland display");
191 mRegistry = wl_display_get_registry(mWayland);
192 if (mRegistry ==
nullptr) {
193 throw std::runtime_error(
"Could not create wayland registry");
196 mFd = memfd_create(
"/tmp/ca-gpu-display-wayland-memfile", 0);
198 throw std::runtime_error(
"Error creating wayland shm segment file descriptor");
201 auto pointer_enter = [](
void*
data, wl_pointer* wl_pointer, uint32_t serial, wl_surface* surface, wl_fixed_t surface_x, wl_fixed_t surface_y) {
203 auto pointer_leave = [](
void*
data, wl_pointer* wl_pointer, uint32_t serial, wl_surface* wl_surface) {
205 auto pointer_motion = [](
void*
data, wl_pointer* wl_pointer, uint32_t
time, wl_fixed_t surface_x, wl_fixed_t surface_y) {
207 me->mMouseMvX = wl_fixed_to_double(surface_x);
208 me->mMouseMvY = wl_fixed_to_double(surface_y);
210 auto pointer_button = [](
void*
data, wl_pointer* wl_pointer, uint32_t serial, uint32_t
time, uint32_t button, uint32_t
state) {
212 if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
213 if (button == BTN_RIGHT) {
214 me->mMouseDnR =
true;
215 }
else if (button == BTN_LEFT) {
218 me->mMouseDnX =
me->mMouseMvX;
219 me->mMouseDnY =
me->mMouseMvY;
220 }
else if (state == WL_POINTER_BUTTON_STATE_RELEASED) {
221 if (button == BTN_RIGHT) {
222 me->mMouseDnR =
false;
223 }
else if (button == BTN_LEFT) {
224 me->mMouseDn =
false;
228 auto pointer_axis = [](
void*
data, wl_pointer* wl_pointer, uint32_t
time, uint32_t axis, wl_fixed_t
value) {
233#pragma GCC diagnostic push
234#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
235 const wl_pointer_listener pointer_listener = {.enter = pointer_enter, .leave = pointer_leave, .motion = pointer_motion, .button = pointer_button, .axis = pointer_axis, .frame =
nullptr, .axis_source =
nullptr, .axis_stop =
nullptr, .axis_discrete =
nullptr};
236#pragma GCC diagnostic pop
238 auto keyboard_keymap = [](
void*
data, wl_keyboard* wl_keyboard, uint32_t
format, int32_t fd, uint32_t
size) {
240 if (
me->mXKBkeymap) {
241 xkb_state_unref(
me->mXKBstate);
242 xkb_keymap_unref(
me->mXKBkeymap);
244 char* keymap_string = (
char*)mmap(
nullptr,
size, PROT_READ, MAP_SHARED, fd, 0);
245 me->mXKBkeymap = xkb_keymap_new_from_string(
me->mXKBcontext, keymap_string, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS);
246 me->mXKBstate = xkb_state_new(
me->mXKBkeymap);
247 munmap(keymap_string,
size);
250 auto keyboard_enter = [](
void*
data, wl_keyboard* wl_keyboard, uint32_t serial, wl_surface* surface, wl_array* keys) {};
251 auto keyboard_leave = [](
void*
data, wl_keyboard* wl_keyboard, uint32_t serial, wl_surface* surface) {};
252 auto keyboard_key = [](
void*
data, wl_keyboard* wl_keyboard, uint32_t serial, uint32_t
time, uint32_t
key, uint32_t
state) {
254 int32_t symbol =
me->GetKey(
key, state);
255 int32_t keyPress = (symbol >=
'a' && symbol <=
'z') ? symbol +
'A' -
'a' : symbol;
256 if (state == XKB_KEY_DOWN) {
257 me->mKeys[keyPress] =
true;
259 me->HandleKey(symbol);
261 me->mKeys[keyPress] =
false;
262 me->mKeysShift[keyPress] =
false;
265 auto keyboard_modifiers = [](
void*
data, wl_keyboard* wl_keyboard, uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t
group) {
267 xkb_state_update_mask(
me->mXKBstate, mods_depressed, mods_latched, mods_locked, 0, 0,
group);
269 auto keyboard_repat = [](
void*
data, wl_keyboard* wl_keyboard, int32_t
rate, int32_t delay) {};
270 const wl_keyboard_listener keyboard_listener = {.keymap = keyboard_keymap, .enter = keyboard_enter, .leave = keyboard_leave, .key = keyboard_key, .modifiers = keyboard_modifiers, .repeat_info = keyboard_repat};
272 auto xdg_wm_base_ping = [](
void*
data,
struct xdg_wm_base* xdg_wm_base, uint32_t serial) {
273 xdg_wm_base_pong(xdg_wm_base, serial);
275 const xdg_wm_base_listener xdg_wm_base_listener = {
276 .ping = xdg_wm_base_ping,
279 auto seat_capabilities = [&](
struct wl_seat* seat, uint32_t capabilities) {
280 if (capabilities & WL_SEAT_CAPABILITY_POINTER) {
281 mPointer = wl_seat_get_pointer(mSeat);
282 wl_pointer_add_listener(mPointer, &pointer_listener,
this);
284 if (capabilities & WL_SEAT_CAPABILITY_POINTER) {
285 mKeyboard = wl_seat_get_keyboard(mSeat);
286 wl_keyboard_add_listener(mKeyboard, &keyboard_listener,
this);
291 auto seat_name = [](
void*
data,
struct wl_seat* seat,
const char*
name) {
293 GPUInfo(
"Wayland seat: %s",
name);
296 const wl_seat_listener seat_listener = {
297 .capabilities = seat_capabilities_c.callback,
301 auto registry_global = [&](wl_registry* registry, uint32_t
name,
const char* interface, uint32_t
version) {
303 GPUInfo(
"Available interface %s", interface);
305 if (strcmp(interface, wl_output_interface.name) == 0) {
306 mOutput = (wl_output*)wl_registry_bind(registry,
name, &wl_output_interface, 1);
308 }
else if (strcmp(interface, wl_compositor_interface.name) == 0) {
309 mCompositor = (wl_compositor*)wl_registry_bind(registry,
name, &wl_compositor_interface, 1);
310 }
else if (strcmp(interface, wl_shm_interface.name) == 0) {
311 mShm = (wl_shm*)wl_registry_bind(registry,
name, &wl_shm_interface, 1);
312 }
else if (strcmp(interface, xdg_wm_base_interface.name) == 0) {
313 mXdgBase = (xdg_wm_base*)wl_registry_bind(registry,
name, &xdg_wm_base_interface, 1);
314 xdg_wm_base_add_listener(mXdgBase, &xdg_wm_base_listener,
this);
315 }
else if (strcmp(interface, wl_seat_interface.name) == 0) {
316 mSeat = (wl_seat*)wl_registry_bind(registry,
name, &wl_seat_interface, 1);
317 wl_seat_add_listener(mSeat, &seat_listener, &seat_capabilities_c);
318 }
else if (strcmp(interface, zxdg_toplevel_decoration_v1_interface.name) == 0) {
319 mDecManager = (zxdg_decoration_manager_v1*)wl_registry_bind(registry,
name, &zxdg_toplevel_decoration_v1_interface, 1);
323 auto registry_global_c =
internal::CCallWrapper<void, wl_registry*, uint32_t, const char*, uint32_t>{[registry_global](wl_registry* registry, uint32_t
name,
const char* interface, uint32_t
version) { registry_global(registry,
name, interface,
version); }};
324 auto registry_global_remove = [](
void*
a, wl_registry*
b, uint32_t
c) {};
325 const wl_registry_listener registry_listener = {.global = ®istry_global_c.callback, .global_remove = registry_global_remove};
327 wl_registry_add_listener(mRegistry, ®istry_listener, ®istry_global_c);
328 wl_display_roundtrip(mWayland);
330 if (mCompositor ==
nullptr || mShm ==
nullptr || mXdgBase ==
nullptr || mSeat ==
nullptr || mOutput ==
nullptr) {
331 throw std::runtime_error(
"Error getting wayland objects");
334 mSurface = wl_compositor_create_surface(mCompositor);
335 if (mSurface ==
nullptr) {
336 throw std::runtime_error(
"Error creating wayland surface");
338 mXdgSurface = xdg_wm_base_get_xdg_surface(mXdgBase, mSurface);
339 if (mXdgSurface ==
nullptr) {
340 throw std::runtime_error(
"Error creating wayland xdg surface");
342 mXdgToplevel = xdg_surface_get_toplevel(mXdgSurface);
344 auto xdg_toplevel_handle_configure = [](
void*
data, xdg_toplevel* toplevel, int32_t
width, int32_t
height, wl_array*
states) {
346 if (
me->mDisplay->param()->par.debugLevel >= 3) {
347 GPUInfo(
"Wayland surface resized to %d %d",
width,
height);
353 auto xdg_surface_handle_configure = [](
void*
data, xdg_surface* surface, uint32_t serial) {
355 xdg_surface_ack_configure(
me->mXdgSurface, serial);
356 if (
me->mWidthRequested &&
me->mHeightRequested && (
me->mWidthRequested !=
me->mDisplayWidth ||
me->mHeightRequested !=
me->mDisplayHeight)) {
357 me->recreateBuffer(
me->mWidthRequested,
me->mHeightRequested);
358 me->ResizeScene(
me->mDisplayWidth,
me->mDisplayHeight);
362 me->mWidthRequested =
me->mHeightRequested = 0;
365 auto xdg_toplevel_handle_close = [](
void*
data, xdg_toplevel* toplevel) {
369#pragma GCC diagnostic push
370#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
371 const xdg_surface_listener xdg_surface_listener = {
372 .configure = xdg_surface_handle_configure,
375 const xdg_toplevel_listener xdg_toplevel_listener = {
376 .configure = xdg_toplevel_handle_configure,
377 .close = xdg_toplevel_handle_close,
378 .configure_bounds =
nullptr};
379#pragma GCC diagnostic pop
381 xdg_surface_add_listener(mXdgSurface, &xdg_surface_listener,
this);
382 xdg_toplevel_add_listener(mXdgToplevel, &xdg_toplevel_listener,
this);
387 printf(
"Enabling decoration\n");
390 wl_surface_commit(mSurface);
391 wl_display_roundtrip(mWayland);
409 xkb_state_unref(mXKBstate);
410 xkb_keymap_unref(mXKBkeymap);
411 mXKBkeymap =
nullptr;
413 xkb_context_unref(mXKBcontext);
415 pthread_mutex_lock(&mSemLockExit);
416 mDisplayRunning =
true;
417 pthread_mutex_unlock(&mSemLockExit);
419 pthread_mutex_lock(&mSemLockExit);
420 mDisplayRunning =
false;
421 pthread_mutex_unlock(&mSemLockExit);
424 wl_pointer_release(mPointer);
428 wl_keyboard_release(mKeyboard);
431 xdg_toplevel_destroy(mXdgToplevel);
432 xdg_surface_destroy(mXdgSurface);
433 wl_surface_destroy(mSurface);
434 wl_buffer_destroy(mBuffer);
435 wl_shm_pool_destroy(mPool);
436 wl_registry_destroy(mRegistry);
437 wl_display_disconnect(mWayland);
445 pthread_mutex_lock(&mSemLockExit);
446 if (mDisplayRunning) {
449 pthread_mutex_unlock(&mSemLockExit);
450 while (mDisplayRunning) {
458 xdg_toplevel_set_fullscreen(mXdgToplevel, mOutput);
460 xdg_toplevel_unset_fullscreen(mXdgToplevel);
467 xdg_toplevel_set_maximized(mXdgToplevel);
469 xdg_toplevel_unset_maximized(mXdgToplevel);
481 GPUError(
"Coult not Create frontend Thread...");
495 VkWaylandSurfaceCreateInfoKHR info{};
496 info.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR;
498 info.display = mWayland;
499 info.surface = mSurface;
500 return vkCreateWaylandSurfaceKHR(*(VkInstance*)instance, &info,
nullptr, (VkSurfaceKHR*)surface) != VK_SUCCESS;
505 static const char* exts[] = {
"VK_KHR_surface",
"VK_KHR_wayland_surface"};
void ToggleMaximized(bool set) override
void SwitchFullscreen(bool set) override
int32_t getVulkanSurface(void *instance, void *surface) override
int32_t StartDisplay() override
void getSize(int32_t &width, int32_t &height) override
void DisplayExit() override
void OpenGLPrint(const char *s, float x, float y, float r, float g, float b, float a, bool fromBotton=true) override
GPUDisplayFrontendWayland()
uint32_t getReqVulkanExtensions(const char **&p) override
void SetVSync(bool enable) override
static constexpr int32_t KEY_F9
const char * mFrontendName
static constexpr int32_t KEY_F2
static void * FrontendThreadWrapper(void *)
static constexpr int32_t KEY_ALT
static constexpr int32_t KEY_F12
static constexpr int32_t KEY_F7
static constexpr int32_t KEY_END
static constexpr int32_t KEY_PAGEDOWN
static constexpr int32_t KEY_RALT
volatile int32_t mDisplayControl
static constexpr int32_t KEY_F10
static constexpr int32_t KEY_F4
static constexpr int32_t KEY_LEFT
static constexpr int32_t KEY_ENTER
static constexpr int32_t KEY_F6
static constexpr int32_t KEY_CTRL
static constexpr int32_t KEY_F1
static constexpr const char * DISPLAY_WINDOW_NAME
static constexpr int32_t INIT_WIDTH
frontendTypes mFrontendType
static constexpr int32_t KEY_SHIFT
static constexpr int32_t KEY_F3
static constexpr int32_t KEY_INSERT
static constexpr int32_t KEY_F11
static constexpr int32_t KEY_SPACE
static constexpr int32_t KEY_F5
static constexpr int32_t KEY_PAGEUP
static constexpr int32_t KEY_HOME
int32_t InitDisplay(bool initFailure=false)
GPUDisplayBackend * backend()
static constexpr int32_t KEY_UP
static constexpr int32_t KEY_DOWN
static constexpr int32_t KEY_F8
static constexpr int32_t INIT_HEIGHT
static constexpr int32_t KEY_RIGHT
static constexpr int32_t KEY_RCTRL
static constexpr int32_t KEY_ESCAPE
GLuint const GLchar * name
GLint GLsizei GLsizei height
GLboolean GLboolean GLboolean b
GLsizei const GLfloat * value
GLint GLenum GLboolean GLsizei stride
GLboolean GLboolean GLboolean GLboolean a
GLint GLint GLsizei GLint GLenum format
Polygon< T > close(Polygon< T > polygon)
std::function< T(Args...)> func
static T callback(void *context, Args... args)
std::vector< std::byte > createBuffer(gsl::span< std::string > data, uint32_t orbit=12345, uint16_t bc=678)