vulkan_test2

view src/wsys_x11.c @ 6:1dd2c7398afc

swapchain images and other tales of woe
author John Tsiombikas <nuclear@member.fsf.org>
date Fri, 22 Sep 2017 18:13:03 +0300
parents cec4b0e7fce8
children 20eb42197ab8
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 void proc_event(XEvent *ev);
25 static Display *dpy;
26 static Window win;
27 static VkSurfaceKHR surf;
28 static VkSwapchainKHR swapchain;
29 static VkImage *swapchain_images;
30 static int next_swapchain_image;
31 static Atom xa_wm_delete;
32 static int win_width, win_height;
33 static int win_mapped;
34 static unsigned int evmask = StructureNotifyMask | ExposureMask;
35 static unsigned int pending;
36 static struct callbacks cb;
38 int wsys_create_window(int xsz, int ysz)
39 {
40 int i, scr, num_visuals;
41 Window root_win;
42 Visual *vis = 0;
43 XSetWindowAttributes xattr;
44 unsigned int xattr_mask;
45 XVisualInfo *vinf, vinf_match;
47 if(!(dpy = XOpenDisplay(0))) {
48 fprintf(stderr, "failed to open connection to the X server\n");
49 return -1;
50 }
51 scr = DefaultScreen(dpy);
52 root_win = RootWindow(dpy, scr);
54 xa_wm_delete = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
56 vinf_match.screen = scr;
57 vinf_match.depth = 24;
58 vinf_match.class = TrueColor;
60 if(!(vinf = XGetVisualInfo(dpy, VisualScreenMask | VisualDepthMask | VisualClassMask, &vinf_match, &num_visuals))) {
61 fprintf(stderr, "failed to retrieve matching visuals\n");
62 XCloseDisplay(dpy);
63 return -1;
64 }
66 for(i=0; i<num_visuals; i++) {
67 if(vku_xlib_usable_visual(dpy, vinf[i].visualid)) {
68 vis = vinf[i].visual;
69 break;
70 }
71 }
72 if(!vis) {
73 fprintf(stderr, "failed to find approprate visual\n");
74 XFree(vinf);
75 XCloseDisplay(dpy);
76 return -1;
77 }
79 xattr.background_pixel = xattr.border_pixel = BlackPixel(dpy, scr);
80 xattr.colormap = XCreateColormap(dpy, root_win, vis, AllocNone);
81 xattr_mask = CWBackPixel | CWBorderPixel | CWColormap;
83 if(!(win = XCreateWindow(dpy, root_win, 0, 0, xsz, ysz, 0, 24, InputOutput, vis, xattr_mask, &xattr))) {
84 fprintf(stderr, "failed to create X window\n");
85 XFree(vinf);
86 XCloseDisplay(dpy);
87 return -1;
88 }
89 XFree(vinf);
91 XSelectInput(dpy, win, evmask);
92 XSetWMProtocols(dpy, win, &xa_wm_delete, 1);
94 if(!(surf = vku_xlib_create_surface(dpy, win))) {
95 fprintf(stderr, "failed to create vulkan surface for the window\n");
96 XDestroyWindow(dpy, win);
97 XCloseDisplay(dpy);
98 return -1;
99 }
100 /* swapchain gets created before the first reshape invocation */
102 wsys_set_window_title("X11 window");
103 XMapWindow(dpy, win);
105 win_width = xsz;
106 win_height = ysz;
107 pending = RESHAPE | REDISPLAY;
109 return 0;
110 }
112 void wsys_destroy_window(void)
113 {
114 if(dpy) {
115 if(win) {
116 XDestroyWindow(dpy, win);
117 win = 0;
118 }
119 XCloseDisplay(dpy);
120 dpy = 0;
121 }
122 }
124 void wsys_get_window_size(int *xsz, int *ysz)
125 {
126 *xsz = win_width;
127 *ysz = win_height;
128 }
130 void wsys_set_window_title(const char *title)
131 {
132 XTextProperty text;
133 XStringListToTextProperty((char**)&title, 1, &text);
134 XSetWMName(dpy, win, &text);
135 XSetWMIconName(dpy, win, &text);
136 XFree(text.value);
137 }
139 void wsys_display_callback(void (*func)(void))
140 {
141 cb.display = func;
142 }
144 void wsys_reshape_callback(void (*func)(int, int))
145 {
146 cb.reshape = func;
147 }
149 void wsys_keyboard_callback(void (*func)(int, int))
150 {
151 cb.keyboard = func;
152 if(func) {
153 evmask |= KeyPressMask | KeyReleaseMask;
154 } else {
155 evmask &= ~(KeyPressMask | KeyReleaseMask);
156 }
157 if(win) {
158 XSelectInput(dpy, win, evmask);
159 }
160 }
162 void wsys_mouse_callback(void (*func)(int, int, int, int))
163 {
164 cb.mouse = func;
165 if(func) {
166 evmask |= ButtonPressMask | ButtonReleaseMask;
167 } else {
168 evmask &= ~(ButtonPressMask | ButtonReleaseMask);
169 }
170 if(win) {
171 XSelectInput(dpy, win, evmask);
172 }
173 }
175 void wsys_motion_callback(void (*func)(int, int))
176 {
177 cb.motion = func;
178 if(func) {
179 evmask |= ButtonMotionMask;
180 } else {
181 evmask &= ~ButtonMotionMask;
182 }
183 if(win) {
184 XSelectInput(dpy, win, evmask);
185 }
186 }
188 void wsys_passive_motion_callback(void (*func)(int, int))
189 {
190 cb.passive = func;
191 if(func) {
192 evmask |= PointerMotionMask;
193 } else {
194 evmask &= ~PointerMotionMask;
195 }
196 if(win) {
197 XSelectInput(dpy, win, evmask);
198 }
199 }
201 void wsys_swap_buffers(void)
202 {
203 vku_present(swapchain, next_swapchain_image);
204 next_swapchain_image = vku_get_next_image(swapchain);
205 }
207 void wsys_redisplay(void)
208 {
209 pending |= REDISPLAY;
210 }
212 void wsys_quit(void)
213 {
214 pending |= QUIT;
215 }
217 int wsys_process_events(int mode)
218 {
219 XEvent xev;
221 if(pending & RESHAPE) {
222 VkSwapchainKHR sc;
223 if(!(sc = vku_create_swapchain(surf, win_width, win_height, 2, VK_PRESENT_MODE_FIFO_KHR, swapchain))) {
224 fprintf(stderr, "Failed to create %dx%d double-buffered swapchain\n", win_width, win_height);
225 return -1;
226 }
227 swapchain = sc;
229 free(swapchain_images);
230 swapchain_images = vku_get_swapchain_images(sc, 0);
231 next_swapchain_image = vku_get_next_image(swapchain);
233 if(cb.reshape) {
234 cb.reshape(win_width, win_height);
235 }
236 pending &= ~RESHAPE;
237 }
239 if(mode == WSYS_BLOCKING) {
240 XNextEvent(dpy, &xev);
241 proc_event(&xev);
242 if(pending & QUIT) return -1;
243 }
245 while(XPending(dpy)) {
246 XNextEvent(dpy, &xev);
247 proc_event(&xev);
248 if(pending & QUIT) return -1;
249 }
251 if(pending & REDISPLAY && win_mapped) {
252 pending &= ~REDISPLAY;
253 if(cb.display) {
254 cb.display();
255 }
256 }
257 return 0;
258 }
260 static void proc_event(XEvent *ev)
261 {
262 switch(ev->type) {
263 case MapNotify:
264 win_mapped = 1;
265 break;
267 case UnmapNotify:
268 win_mapped = 0;
269 break;
271 case ClientMessage:
272 if(ev->xclient.data.l[0] == xa_wm_delete) {
273 pending |= QUIT;
274 }
275 break;
277 case ConfigureNotify:
278 if(ev->xconfigure.width != win_width || ev->xconfigure.height != win_height) {
279 win_width = ev->xconfigure.width;
280 win_height = ev->xconfigure.height;
281 pending |= RESHAPE;
282 }
283 break;
285 case Expose:
286 if(ev->xexpose.count == 0) {
287 pending |= REDISPLAY;
288 }
289 break;
291 case KeyPress:
292 case KeyRelease:
293 if(cb.keyboard) {
294 KeySym sym;
295 char str[16];
296 XLookupString(&ev->xkey, str, sizeof str, &sym, 0);
297 cb.keyboard(sym & 0xff, ev->type == KeyPress ? 1 : 0);
298 }
299 break;
301 case ButtonPress:
302 case ButtonRelease:
303 if(cb.mouse) {
304 int bn = ev->xbutton.button - Button1;
305 int pressed = ev->type == ButtonPress ? 1 : 0;
306 cb.mouse(bn, pressed, ev->xbutton.x, ev->xbutton.y);
307 }
308 break;
310 case MotionNotify:
311 if(ev->xmotion.state & 0x1f00) {
312 if(cb.motion) {
313 cb.motion(ev->xmotion.x, ev->xmotion.y);
314 }
315 } else {
316 if(cb.passive) {
317 cb.passive(ev->xmotion.x, ev->xmotion.y);
318 }
319 }
320 break;
321 }
322 }