vulkan_test2

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