ea7071534a2822b04486f1e0d85ab22be47e07bb
[vkrt] / src / main.cc
1 #include <stdio.h>
2
3 #define GLFW_INCLUDE_VULKAN
4 #include <GLFW/glfw3.h>
5
6 #include <assert.h>
7 #include <stdlib.h>
8 #include <string.h>
9
10 #include <vector>
11
12 #include <gmath/gmath.h>
13
14 /* extern "C": vulkan framework */
15 #include "vk.h"
16 #include "util.h"
17
18 /* C++ */
19 #include "camera.h"
20
21 /* defines */
22
23 #define FENCE_TIMEOUT 100000000000
24
25 /**************************/
26 /* static glfw callbacks */
27 /**************************/
28
29 static void
30 clb_key(GLFWwindow *win, int key, int scancode, int action, int mods);
31
32 static void
33 clb_reshape(GLFWwindow *win, int width, int height);
34
35 static void
36 clb_motion(GLFWwindow *win, double x, double y);
37
38 static void
39 clb_mouse(GLFWwindow *win, int button, int action, int mods);
40
41 /**************************/
42 /* static functions */
43 /**************************/
44
45 /* init, cleanup, display */
46
47 static bool
48 init();
49
50 static void
51 cleanup();
52
53 static void
54 display();
55
56 /* vulkan, glfw */
57
58 static bool
59 vk_init();
60
61 static void
62 vk_cleanup();
63
64 /***************************/
65 /* static/global variables */
66 /***************************/
67
68 static GLFWwindow *win;
69 /* static bool redraw_pending; */
70 static bool move_camera;
71
72 /* camera */
73 static float cam_phi = 25;
74 static float cam_theta = 0;
75 static float cam_dist = 16;
76 static Vec3 cam_pos;
77
78 static OrbitCamera *camera;
79
80 static float aspect;
81 static Mat4 mproj;
82
83 /* win etc */
84 static int win_w = 800;
85 static int win_h = 600;
86
87 /* vulkan */
88 static bool vk_enable_layers = true;
89 static struct vk_ctx vk_core;
90 static VkSurfaceKHR vk_surf;
91 static struct vk_swapchain vk_chain;
92 static uint32_t vk_chain_idx;
93 static struct vk_semaphores vk_sema;
94
95 /* for the moment: one cmd buffer per swapchain image */
96 static std::vector<VkCommandBuffer>vk_cmd_buffers;
97 static std::vector<VkFence>vk_wait_fences;
98
99 /* FIXME make them part of each object's functions/params */
100 static struct vk_renderer vk_rnd;
101 static struct vk_attachment vk_depth_att;
102 static float vk_fb_color[4] = { 0.0, 0.0, 0.5, 1.0 };
103
104 /* empty for as long as we hardcode the vertices in the vertex shader */
105 static struct vk_vertex_info vk_vert_info;
106
107 int main(int argc, char** argv)
108 {
109     atexit(cleanup);
110
111     if (!glfwInit()) {
112         fprintf(stderr, "Failed to initialize GLFW.\n");
113         return 1;
114     }
115
116     if (!init()) {
117         return 1;
118     }
119
120 #if 0
121     glfwGetWindowSize(win, &win_w, &win_h);
122     clb_reshape(win, win_w, win_h);
123 #endif
124
125         while(!glfwWindowShouldClose(win)) {
126                 glfwPollEvents();
127                 display();
128         }
129     vkDeviceWaitIdle(vk_core.dev);
130
131     return 0;
132 }
133
134 /* static functions */
135
136 static bool
137 vk_init()
138 {
139     if (glfwVulkanSupported() != GLFW_TRUE) {
140         fprintf(stderr, "Vulkan is not supported on this device.\n");
141         return false;
142     }
143
144     /* create window */
145
146     glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
147     win = glfwCreateWindow(win_w, win_h, "helloworld rt", 0, 0);
148
149     if (!win) {
150         fprintf(stderr, "Failed to create GLFW window\n");
151         return false;
152     }
153
154     glfwSetKeyCallback(win, clb_key);
155
156     /* initialize Vulkan context (instance) */
157
158     if (!vk_init_ctx_for_rendering(&vk_core, true, vk_enable_layers)) {
159         fprintf(stderr, "Failed to initialize Vulkan context.\n");
160         return false;
161     }
162
163     /* create (Xcb) surface */
164
165     glfwGetFramebufferSize(win, &win_h, &win_h);
166     if (glfwCreateWindowSurface(vk_core.inst, win, 0, &vk_surf)
167             != VK_SUCCESS) {
168         fprintf(stderr, "Failed to create XCB surface.\n");
169         return false;
170     }
171
172     /* load shaders */
173     int vsz, fsz;
174     char *vsdr = sdr_load("data/main.vert.spv", &vsz);
175     char *fsdr = sdr_load("data/main.frag.spv", &fsz);
176
177     /* create semaphores */
178     if (!vk_create_semaphores(&vk_core, false, &vk_sema)) {
179         fprintf(stderr, "No semaphores were created.\n");
180         goto fail;
181     }
182
183     /* create swapchain */
184     if (!vk_create_swapchain(&vk_core, win_w, win_h, false, vk_surf, 0, &vk_chain)) {
185         fprintf(stderr, "No swapchain was created.\n");
186         goto fail;
187     }
188
189     if (vk_chain.swapchain == VK_NULL_HANDLE) {
190         fprintf(stderr, "Invalid swapchain handle.\n");
191         goto fail;
192     }
193
194     /* FIXME: this part is going to be part of each object's functions */
195
196     /* create depth attachment (for the moment we are going to use this
197      * for all images */
198     if (!vk_fill_image_props(&vk_core,
199                              win_w, win_h, 1,
200                              1, 1, 1,
201                              VK_FORMAT_D32_SFLOAT_S8_UINT,
202                              VK_IMAGE_TILING_OPTIMAL,
203                              VK_IMAGE_LAYOUT_UNDEFINED,
204                              VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
205                              false, true, false,
206                              &vk_depth_att.props)) {
207         fprintf(stderr, "Unsupported depth image properties\n");
208         return false;
209     }
210     if (!vk_create_image(&vk_core, &vk_depth_att.props, &vk_depth_att.obj)) {
211         fprintf(stderr, "Failed to create depth attachment.\n");
212         goto fail;
213     }
214
215     /* create renderer */
216     if (!vk_create_renderer(&vk_core,
217                             vsdr, vsz, fsdr, fsz,
218                             win_w, win_h, 1,
219                             false, false,
220                             vk_chain.num_atts, vk_chain.atts, &vk_depth_att,
221                             &vk_vert_info, &vk_rnd)) {
222         goto fail;
223     }
224
225     /* create cmd buffers */
226     for (size_t i = 0; i < vk_chain.num_atts; i++) {
227         VkCommandBuffer cmd_buf;
228         VkFence fence;
229         if(!(vk_create_fence(&vk_core, &fence))) {
230             fprintf(stderr, "Failed to create fence: %d.\n", (int)i);
231             goto fail;
232         }
233         vk_wait_fences.push_back(fence);
234
235         if (!(cmd_buf = vk_create_cmd_buffer(&vk_core))) {
236             fprintf(stderr, "Failed to create command buffer: %d.\n", (int)i);
237             goto fail;
238         }
239
240         /* record cmd buffer FIXME:
241          * part of each objects draw? loop for each
242          * renderer */
243         if (!vk_record_cmd_buffer(&vk_core, cmd_buf,
244                                   &vk_rnd, 0,
245                                   4, vk_fb_color,
246                                   vk_chain.num_atts + 1, 0,
247                                   0, 0, win_w, win_h)) {
248             fprintf(stderr, "Failed to record command buffer.\n");
249             goto fail;
250         }
251
252         vk_cmd_buffers.push_back(cmd_buf);
253     }
254
255     vkResetFences(vk_core.dev, vk_wait_fences.size(), vk_wait_fences.data());
256
257     free(vsdr);
258     free(fsdr);
259
260     /* set GLFW callbacks */
261
262     glfwSetWindowSizeCallback(win, clb_reshape);
263
264     glfwSetCursorPosCallback(win, clb_motion);
265     glfwSetMouseButtonCallback(win, clb_mouse);
266
267     return true;
268
269 fail:
270     for (size_t i = 0; i < vk_wait_fences.size(); i++) {
271         vk_destroy_fences(&vk_core, vk_wait_fences.size(), vk_wait_fences.data());
272     }
273     vk_wait_fences.clear();
274
275     for (size_t i = 0; i < vk_cmd_buffers.size(); i++) {
276         vk_destroy_cmd_buffers(&vk_core, vk_cmd_buffers.size(), vk_cmd_buffers.data());
277     }
278     vk_cmd_buffers.clear();
279
280     if (vk_depth_att.obj.img != VK_NULL_HANDLE) {
281         vk_destroy_image(&vk_core, &vk_depth_att.obj);
282     }
283
284     free(vsdr);
285     free(fsdr);
286
287     return false;
288 }
289
290 static bool
291 init()
292 {
293     if (!vk_init()) {
294         fprintf(stderr, "Failed to initialize Vulkan structs.\n");
295         return false;
296     }
297
298     camera = new OrbitCamera;
299     return true;
300 }
301
302 static void
303 cleanup()
304 {
305     delete camera;
306
307     vk_cleanup();
308 }
309
310 static int count;
311 static void
312 display()
313 {
314     /* each object should have a command buffer renderpass etc? */
315     VkSubmitInfo sinfo;
316     VkPipelineStageFlags wait_stages = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
317
318     vkAcquireNextImageKHR(vk_core.dev, vk_chain.swapchain,
319                           UINT64_MAX, vk_sema.frame_ready, 0, &vk_chain_idx);
320
321     memset(&sinfo, 0, sizeof sinfo);
322     sinfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
323     sinfo.waitSemaphoreCount = 1;
324     sinfo.pWaitSemaphores = &vk_sema.frame_ready;
325     sinfo.pWaitDstStageMask = &wait_stages;
326     sinfo.commandBufferCount = 1;
327     sinfo.pCommandBuffers = &vk_cmd_buffers[vk_chain_idx];
328     sinfo.signalSemaphoreCount = 1;
329         sinfo.pSignalSemaphores = &vk_sema.frame_done;
330
331     if (vkQueueSubmit(vk_core.queue, 1, &sinfo, vk_wait_fences[vk_chain_idx]) != 0) {
332         fprintf(stderr, "Failed to submit draw commands.\n");
333         abort();
334     }
335
336     if (vkQueueWaitIdle(vk_core.queue) != VK_SUCCESS) {
337         fprintf(stderr, "Failed to wait idle.\n");
338         abort();
339     }
340
341     if (vkWaitForFences(vk_core.dev, 1, &vk_wait_fences[vk_chain_idx],
342                         VK_TRUE, FENCE_TIMEOUT) != VK_SUCCESS) {
343         fprintf(stderr, "Waiting for fence: %u failed.\n", vk_chain_idx);
344         abort();
345     }
346
347 #if 0
348     memset(&pinfo, 0, sizeof pinfo);
349     pinfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
350     pinfo.waitSemaphoreCount = 1;
351     pinfo.pWaitSemaphores = &vk_sema.frame_done;
352     pinfo.swapchainCount = 1;
353     pinfo.pSwapchains = &vk_chain.swapchain;
354     pinfo.pImageIndices = &vk_chain_idx;
355 #endif
356
357     if (!vk_queue_present(&vk_chain, vk_core.queue, vk_chain_idx, vk_sema.frame_done)) {
358         abort();
359     }
360     vkResetFences(vk_core.dev, 1, &vk_wait_fences[vk_chain_idx]);
361
362     printf("display %d\n", count++);
363 }
364
365 static void
366 vk_cleanup()
367 {
368     vkQueueWaitIdle(vk_core.queue);
369
370     vk_destroy_image(&vk_core, &vk_depth_att.obj);
371     vk_destroy_renderer(&vk_core, &vk_rnd);
372     vk_destroy_semaphores(&vk_core, &vk_sema);
373
374     glfwDestroyWindow(win);
375
376     if (vk_chain.swapchain) {
377         vk_destroy_swapchain(&vk_core, &vk_chain);
378         vkDestroySurfaceKHR(vk_core.inst, vk_surf, 0);
379     }
380
381     if (vk_enable_layers)
382         return;
383
384     vk_destroy_cmd_buffers(&vk_core, vk_cmd_buffers.size(), vk_cmd_buffers.data());
385     glfwTerminate();
386
387     vk_cleanup_ctx(&vk_core);
388 }
389
390 /* glfw callbacks */
391
392 static void
393 clb_reshape(GLFWwindow *win,
394             int width,
395             int height)
396 {
397     aspect = (float)width / (float)height;
398     mproj = calc_projection_matrix(45, aspect, 0.5, 1000.0f);
399
400     /* FIXME near and far clipping planes */
401     vk_set_viewport(&vk_core, vk_cmd_buffers[vk_chain_idx],
402                     0, 0, win_w, win_h, 0.0f, 1.0f);
403     win_w = width;
404     win_h = height;
405 }
406
407 static void
408 clb_key(GLFWwindow *win, int key, int scancode,
409         int action, int mods)
410 {
411     if (action == GLFW_REPEAT) return;
412
413     if (action == GLFW_PRESS) {
414         switch(key) {
415         case GLFW_KEY_ESCAPE:
416             glfwSetWindowShouldClose(win, GLFW_TRUE);
417             exit(0);
418         case ' ':
419             move_camera = !move_camera;
420             break;
421         default:
422             break;
423         }
424     }
425 }
426
427 static double prev_x, prev_y;
428 static bool button[8];
429
430 static void
431 clb_motion(GLFWwindow *win,
432            double x,
433            double y)
434 {
435         double dx = x - prev_x;
436         double dy = y - prev_y;
437
438         prev_x = x;
439         prev_y = y;
440
441         if(button[0]) {
442                 cam_theta += dx * 0.5;
443                 cam_phi += dy * 0.5;
444
445                 if(cam_phi < 0)
446                         cam_phi = 0;
447                 if(cam_phi > 90)
448                         cam_phi = 90;
449         }
450
451         if(button[1]) {
452                 cam_dist += dy * 0.1;
453                 if(cam_dist < 0.0) {
454                         cam_dist = 0.0;
455                 }
456         }
457 }
458
459 static void
460 clb_mouse(GLFWwindow *win,
461           int button,
462           int action,
463           int mods)
464 {
465 }