vulkan_test2

annotate src/wsys_x11.c @ 17:f8bd29f124a8

foo
author John Tsiombikas <nuclear@member.fsf.org>
date Wed, 27 Jun 2018 01:57:55 +0300
parents 9fb6c24691ea
children
rev   line source
nuclear@4 1 #include <stdio.h>
nuclear@4 2 #include <stdlib.h>
nuclear@4 3 #include <X11/Xlib.h>
nuclear@4 4 #include <X11/Xutil.h>
nuclear@4 5 #include "wsys.h"
nuclear@4 6 #include "vku.h"
nuclear@4 7
nuclear@4 8 struct callbacks {
nuclear@4 9 void (*display)(void);
nuclear@4 10 void (*reshape)(int, int);
nuclear@4 11 void (*keyboard)(int, int);
nuclear@4 12 void (*mouse)(int, int, int, int);
nuclear@4 13 void (*motion)(int, int);
nuclear@4 14 void (*passive)(int, int);
nuclear@4 15 };
nuclear@4 16
nuclear@4 17 enum {
nuclear@4 18 QUIT = 1,
nuclear@4 19 RESHAPE = 2,
nuclear@4 20 REDISPLAY = 4
nuclear@4 21 };
nuclear@4 22
nuclear@17 23 static int reshape(int x, int y);
nuclear@4 24 static void proc_event(XEvent *ev);
nuclear@4 25
nuclear@4 26 static Display *dpy;
nuclear@4 27 static Window win;
nuclear@5 28 static VkSurfaceKHR surf;
nuclear@5 29 static VkSwapchainKHR swapchain;
nuclear@4 30 static Atom xa_wm_delete;
nuclear@4 31 static int win_width, win_height;
nuclear@4 32 static int win_mapped;
nuclear@4 33 static unsigned int evmask = StructureNotifyMask | ExposureMask;
nuclear@4 34 static unsigned int pending;
nuclear@4 35 static struct callbacks cb;
nuclear@4 36
nuclear@4 37 int wsys_create_window(int xsz, int ysz)
nuclear@4 38 {
nuclear@4 39 int i, scr, num_visuals;
nuclear@4 40 Window root_win;
nuclear@4 41 Visual *vis = 0;
nuclear@4 42 XSetWindowAttributes xattr;
nuclear@4 43 unsigned int xattr_mask;
nuclear@4 44 XVisualInfo *vinf, vinf_match;
nuclear@4 45
nuclear@4 46 if(!(dpy = XOpenDisplay(0))) {
nuclear@4 47 fprintf(stderr, "failed to open connection to the X server\n");
nuclear@4 48 return -1;
nuclear@4 49 }
nuclear@4 50 scr = DefaultScreen(dpy);
nuclear@4 51 root_win = RootWindow(dpy, scr);
nuclear@4 52
nuclear@4 53 xa_wm_delete = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
nuclear@4 54
nuclear@4 55 vinf_match.screen = scr;
nuclear@4 56 vinf_match.depth = 24;
nuclear@4 57 vinf_match.class = TrueColor;
nuclear@4 58
nuclear@4 59 if(!(vinf = XGetVisualInfo(dpy, VisualScreenMask | VisualDepthMask | VisualClassMask, &vinf_match, &num_visuals))) {
nuclear@4 60 fprintf(stderr, "failed to retrieve matching visuals\n");
nuclear@4 61 XCloseDisplay(dpy);
nuclear@4 62 return -1;
nuclear@4 63 }
nuclear@4 64
nuclear@4 65 for(i=0; i<num_visuals; i++) {
nuclear@4 66 if(vku_xlib_usable_visual(dpy, vinf[i].visualid)) {
nuclear@4 67 vis = vinf[i].visual;
nuclear@4 68 break;
nuclear@4 69 }
nuclear@4 70 }
nuclear@4 71 if(!vis) {
nuclear@4 72 fprintf(stderr, "failed to find approprate visual\n");
nuclear@4 73 XFree(vinf);
nuclear@4 74 XCloseDisplay(dpy);
nuclear@4 75 return -1;
nuclear@4 76 }
nuclear@4 77
nuclear@4 78 xattr.background_pixel = xattr.border_pixel = BlackPixel(dpy, scr);
nuclear@4 79 xattr.colormap = XCreateColormap(dpy, root_win, vis, AllocNone);
nuclear@4 80 xattr_mask = CWBackPixel | CWBorderPixel | CWColormap;
nuclear@4 81
nuclear@4 82 if(!(win = XCreateWindow(dpy, root_win, 0, 0, xsz, ysz, 0, 24, InputOutput, vis, xattr_mask, &xattr))) {
nuclear@4 83 fprintf(stderr, "failed to create X window\n");
nuclear@4 84 XFree(vinf);
nuclear@4 85 XCloseDisplay(dpy);
nuclear@4 86 return -1;
nuclear@4 87 }
nuclear@4 88 XFree(vinf);
nuclear@4 89
nuclear@4 90 XSelectInput(dpy, win, evmask);
nuclear@4 91 XSetWMProtocols(dpy, win, &xa_wm_delete, 1);
nuclear@4 92
nuclear@5 93 if(!(surf = vku_xlib_create_surface(dpy, win))) {
nuclear@5 94 fprintf(stderr, "failed to create vulkan surface for the window\n");
nuclear@5 95 XDestroyWindow(dpy, win);
nuclear@5 96 XCloseDisplay(dpy);
nuclear@5 97 return -1;
nuclear@5 98 }
nuclear@5 99 /* swapchain gets created before the first reshape invocation */
nuclear@5 100
nuclear@4 101 wsys_set_window_title("X11 window");
nuclear@4 102 XMapWindow(dpy, win);
nuclear@4 103
nuclear@4 104 win_width = xsz;
nuclear@4 105 win_height = ysz;
nuclear@17 106
nuclear@17 107 if(reshape(xsz, ysz) == -1) {
nuclear@17 108 XDestroyWindow(dpy, win);
nuclear@17 109 XCloseDisplay(dpy);
nuclear@17 110 return -1;
nuclear@17 111 }
nuclear@17 112
nuclear@17 113 pending = REDISPLAY;
nuclear@4 114
nuclear@4 115 return 0;
nuclear@4 116 }
nuclear@4 117
nuclear@4 118 void wsys_destroy_window(void)
nuclear@4 119 {
nuclear@4 120 if(dpy) {
nuclear@4 121 if(win) {
nuclear@4 122 XDestroyWindow(dpy, win);
nuclear@4 123 win = 0;
nuclear@4 124 }
nuclear@4 125 XCloseDisplay(dpy);
nuclear@4 126 dpy = 0;
nuclear@4 127 }
nuclear@4 128 }
nuclear@4 129
nuclear@4 130 void wsys_get_window_size(int *xsz, int *ysz)
nuclear@4 131 {
nuclear@4 132 *xsz = win_width;
nuclear@4 133 *ysz = win_height;
nuclear@4 134 }
nuclear@4 135
nuclear@4 136 void wsys_set_window_title(const char *title)
nuclear@4 137 {
nuclear@4 138 XTextProperty text;
nuclear@4 139 XStringListToTextProperty((char**)&title, 1, &text);
nuclear@4 140 XSetWMName(dpy, win, &text);
nuclear@4 141 XSetWMIconName(dpy, win, &text);
nuclear@4 142 XFree(text.value);
nuclear@4 143 }
nuclear@4 144
nuclear@4 145 void wsys_display_callback(void (*func)(void))
nuclear@4 146 {
nuclear@4 147 cb.display = func;
nuclear@4 148 }
nuclear@4 149
nuclear@4 150 void wsys_reshape_callback(void (*func)(int, int))
nuclear@4 151 {
nuclear@4 152 cb.reshape = func;
nuclear@4 153 }
nuclear@4 154
nuclear@4 155 void wsys_keyboard_callback(void (*func)(int, int))
nuclear@4 156 {
nuclear@4 157 cb.keyboard = func;
nuclear@4 158 if(func) {
nuclear@4 159 evmask |= KeyPressMask | KeyReleaseMask;
nuclear@4 160 } else {
nuclear@4 161 evmask &= ~(KeyPressMask | KeyReleaseMask);
nuclear@4 162 }
nuclear@4 163 if(win) {
nuclear@4 164 XSelectInput(dpy, win, evmask);
nuclear@4 165 }
nuclear@4 166 }
nuclear@4 167
nuclear@4 168 void wsys_mouse_callback(void (*func)(int, int, int, int))
nuclear@4 169 {
nuclear@4 170 cb.mouse = func;
nuclear@4 171 if(func) {
nuclear@4 172 evmask |= ButtonPressMask | ButtonReleaseMask;
nuclear@4 173 } else {
nuclear@4 174 evmask &= ~(ButtonPressMask | ButtonReleaseMask);
nuclear@4 175 }
nuclear@4 176 if(win) {
nuclear@4 177 XSelectInput(dpy, win, evmask);
nuclear@4 178 }
nuclear@4 179 }
nuclear@4 180
nuclear@4 181 void wsys_motion_callback(void (*func)(int, int))
nuclear@4 182 {
nuclear@4 183 cb.motion = func;
nuclear@4 184 if(func) {
nuclear@4 185 evmask |= ButtonMotionMask;
nuclear@4 186 } else {
nuclear@4 187 evmask &= ~ButtonMotionMask;
nuclear@4 188 }
nuclear@4 189 if(win) {
nuclear@4 190 XSelectInput(dpy, win, evmask);
nuclear@4 191 }
nuclear@4 192 }
nuclear@4 193
nuclear@4 194 void wsys_passive_motion_callback(void (*func)(int, int))
nuclear@4 195 {
nuclear@4 196 cb.passive = func;
nuclear@4 197 if(func) {
nuclear@4 198 evmask |= PointerMotionMask;
nuclear@4 199 } else {
nuclear@4 200 evmask &= ~PointerMotionMask;
nuclear@4 201 }
nuclear@4 202 if(win) {
nuclear@4 203 XSelectInput(dpy, win, evmask);
nuclear@4 204 }
nuclear@4 205 }
nuclear@4 206
nuclear@17 207 void wsys_swap_buffers(VkSemaphore sem_wait)
nuclear@4 208 {
nuclear@17 209 vku_present(swapchain, next_swapchain_image, sem_wait);
nuclear@17 210 next_swapchain_image = vku_get_next_image(swapchain, swapchain_getimg_sem);
nuclear@4 211 }
nuclear@4 212
nuclear@4 213 void wsys_redisplay(void)
nuclear@4 214 {
nuclear@4 215 pending |= REDISPLAY;
nuclear@4 216 }
nuclear@4 217
nuclear@4 218 void wsys_quit(void)
nuclear@4 219 {
nuclear@4 220 pending |= QUIT;
nuclear@4 221 }
nuclear@4 222
nuclear@17 223 static int reshape(int x, int y)
nuclear@17 224 {
nuclear@17 225 int i;
nuclear@17 226 VkSwapchainKHR sc;
nuclear@17 227 VkFormat fmt = VK_FORMAT_B8G8R8A8_UNORM; /* TODO enumerate and choose */
nuclear@17 228
nuclear@17 229 printf("DBG reshape\n");
nuclear@17 230
nuclear@17 231 if(!vkrpass) {
nuclear@17 232 if(!(vkrpass = vku_create_renderpass(fmt, VK_FORMAT_UNDEFINED))) {
nuclear@17 233 abort();
nuclear@17 234 }
nuclear@17 235 }
nuclear@17 236
nuclear@17 237 if(!(sc = vku_create_swapchain(surf, x, y, 2, fmt,
nuclear@17 238 VK_PRESENT_MODE_FIFO_KHR, swapchain))) {
nuclear@17 239 fprintf(stderr, "Failed to create %dx%d double-buffered swapchain\n", x, y);
nuclear@17 240 return -1;
nuclear@17 241 }
nuclear@17 242 swapchain = sc;
nuclear@17 243
nuclear@17 244 free(swapchain_images);
nuclear@17 245 swapchain_size = 2;
nuclear@17 246 swapchain_images = vku_get_swapchain_images(sc, 0);
nuclear@17 247 next_swapchain_image = vku_get_next_image(swapchain, swapchain_getimg_sem);
nuclear@17 248
nuclear@17 249 if(!swapchain_views) {
nuclear@17 250 if(!(swapchain_views = calloc(swapchain_size, sizeof *swapchain_views))) {
nuclear@17 251 fprintf(stderr, "Failed to allocate image views\n");
nuclear@17 252 return -1;
nuclear@17 253 }
nuclear@17 254 }
nuclear@17 255
nuclear@17 256 for(i=0; i<swapchain_size; i++) {
nuclear@17 257 if(swapchain_views[i]) {
nuclear@17 258 vku_destroy_view(swapchain_views[i]);
nuclear@17 259 }
nuclear@17 260 swapchain_views[i] = vku_create_view(swapchain_images[i], fmt);
nuclear@17 261 }
nuclear@17 262
nuclear@17 263 if(!swapchain_framebuf) {
nuclear@17 264 if(!(swapchain_framebuf = calloc(swapchain_size, sizeof *swapchain_framebuf))) {
nuclear@17 265 fprintf(stderr, "Failed to allocate framebuffers\n");
nuclear@17 266 return -1;
nuclear@17 267 }
nuclear@17 268 }
nuclear@17 269
nuclear@17 270 for(i=0; i<swapchain_size; i++) {
nuclear@17 271 if(swapchain_framebuf[i]) {
nuclear@17 272 vku_destroy_framebuffer(swapchain_framebuf[i]);
nuclear@17 273 }
nuclear@17 274 swapchain_framebuf[i] = vku_create_framebuffer(swapchain_views[i], x, y, vkrpass);
nuclear@17 275 }
nuclear@17 276
nuclear@17 277 if(cb.reshape) {
nuclear@17 278 cb.reshape(x, y);
nuclear@17 279 }
nuclear@17 280 return 0;
nuclear@17 281 }
nuclear@17 282
nuclear@4 283 int wsys_process_events(int mode)
nuclear@4 284 {
nuclear@4 285 XEvent xev;
nuclear@4 286
nuclear@4 287 if(pending & RESHAPE) {
nuclear@17 288 if(reshape(win_width, win_height) == -1) {
nuclear@5 289 return -1;
nuclear@5 290 }
nuclear@4 291 pending &= ~RESHAPE;
nuclear@4 292 }
nuclear@4 293
nuclear@4 294 if(mode == WSYS_BLOCKING) {
nuclear@4 295 XNextEvent(dpy, &xev);
nuclear@4 296 proc_event(&xev);
nuclear@4 297 if(pending & QUIT) return -1;
nuclear@4 298 }
nuclear@4 299
nuclear@4 300 while(XPending(dpy)) {
nuclear@4 301 XNextEvent(dpy, &xev);
nuclear@4 302 proc_event(&xev);
nuclear@4 303 if(pending & QUIT) return -1;
nuclear@4 304 }
nuclear@4 305
nuclear@4 306 if(pending & REDISPLAY && win_mapped) {
nuclear@4 307 pending &= ~REDISPLAY;
nuclear@4 308 if(cb.display) {
nuclear@4 309 cb.display();
nuclear@4 310 }
nuclear@4 311 }
nuclear@4 312 return 0;
nuclear@4 313 }
nuclear@4 314
nuclear@4 315 static void proc_event(XEvent *ev)
nuclear@4 316 {
nuclear@4 317 switch(ev->type) {
nuclear@4 318 case MapNotify:
nuclear@4 319 win_mapped = 1;
nuclear@4 320 break;
nuclear@4 321
nuclear@4 322 case UnmapNotify:
nuclear@4 323 win_mapped = 0;
nuclear@4 324 break;
nuclear@4 325
nuclear@4 326 case ClientMessage:
nuclear@4 327 if(ev->xclient.data.l[0] == xa_wm_delete) {
nuclear@4 328 pending |= QUIT;
nuclear@4 329 }
nuclear@4 330 break;
nuclear@4 331
nuclear@4 332 case ConfigureNotify:
nuclear@4 333 if(ev->xconfigure.width != win_width || ev->xconfigure.height != win_height) {
nuclear@4 334 win_width = ev->xconfigure.width;
nuclear@4 335 win_height = ev->xconfigure.height;
nuclear@4 336 pending |= RESHAPE;
nuclear@4 337 }
nuclear@4 338 break;
nuclear@4 339
nuclear@4 340 case Expose:
nuclear@4 341 if(ev->xexpose.count == 0) {
nuclear@4 342 pending |= REDISPLAY;
nuclear@4 343 }
nuclear@4 344 break;
nuclear@4 345
nuclear@4 346 case KeyPress:
nuclear@4 347 case KeyRelease:
nuclear@4 348 if(cb.keyboard) {
nuclear@4 349 KeySym sym;
nuclear@4 350 char str[16];
nuclear@4 351 XLookupString(&ev->xkey, str, sizeof str, &sym, 0);
nuclear@4 352 cb.keyboard(sym & 0xff, ev->type == KeyPress ? 1 : 0);
nuclear@4 353 }
nuclear@4 354 break;
nuclear@4 355
nuclear@4 356 case ButtonPress:
nuclear@4 357 case ButtonRelease:
nuclear@4 358 if(cb.mouse) {
nuclear@4 359 int bn = ev->xbutton.button - Button1;
nuclear@4 360 int pressed = ev->type == ButtonPress ? 1 : 0;
nuclear@4 361 cb.mouse(bn, pressed, ev->xbutton.x, ev->xbutton.y);
nuclear@4 362 }
nuclear@4 363 break;
nuclear@4 364
nuclear@4 365 case MotionNotify:
nuclear@4 366 if(ev->xmotion.state & 0x1f00) {
nuclear@4 367 if(cb.motion) {
nuclear@4 368 cb.motion(ev->xmotion.x, ev->xmotion.y);
nuclear@4 369 }
nuclear@4 370 } else {
nuclear@4 371 if(cb.passive) {
nuclear@4 372 cb.passive(ev->xmotion.x, ev->xmotion.y);
nuclear@4 373 }
nuclear@4 374 }
nuclear@4 375 break;
nuclear@4 376 }
nuclear@4 377 }