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