3 #define GLFW_INCLUDE_VULKAN
4 #include <GLFW/glfw3.h>
12 #include <gmath/gmath.h>
14 /* extern "C": vulkan framework */
23 #define FENCE_TIMEOUT 100000000000
25 /**************************/
26 /* static glfw callbacks */
27 /**************************/
30 clb_key(GLFWwindow *win, int key, int scancode, int action, int mods);
33 clb_reshape(GLFWwindow *win, int width, int height);
36 clb_motion(GLFWwindow *win, double x, double y);
39 clb_mouse(GLFWwindow *win, int button, int action, int mods);
41 /**************************/
42 /* static functions */
43 /**************************/
45 /* init, cleanup, display */
64 /***************************/
65 /* static/global variables */
66 /***************************/
68 static GLFWwindow *win;
69 /* static bool redraw_pending; */
70 static bool move_camera;
73 static float cam_phi = 25;
74 static float cam_theta = 0;
75 static float cam_dist = 16;
78 static OrbitCamera *camera;
84 static int win_w = 800;
85 static int win_h = 600;
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;
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;
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 };
104 /* empty for as long as we hardcode the vertices in the vertex shader */
105 static struct vk_vertex_info vk_vert_info;
107 int main(int argc, char** argv)
112 fprintf(stderr, "Failed to initialize GLFW.\n");
121 glfwGetWindowSize(win, &win_w, &win_h);
122 clb_reshape(win, win_w, win_h);
125 while(!glfwWindowShouldClose(win)) {
129 vkDeviceWaitIdle(vk_core.dev);
134 /* static functions */
139 if (glfwVulkanSupported() != GLFW_TRUE) {
140 fprintf(stderr, "Vulkan is not supported on this device.\n");
146 glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
147 win = glfwCreateWindow(win_w, win_h, "helloworld rt", 0, 0);
150 fprintf(stderr, "Failed to create GLFW window\n");
154 glfwSetKeyCallback(win, clb_key);
156 /* initialize Vulkan context (instance) */
158 if (!vk_init_ctx_for_rendering(&vk_core, true, vk_enable_layers)) {
159 fprintf(stderr, "Failed to initialize Vulkan context.\n");
163 /* create (Xcb) surface */
165 glfwGetFramebufferSize(win, &win_h, &win_h);
166 if (glfwCreateWindowSurface(vk_core.inst, win, 0, &vk_surf)
168 fprintf(stderr, "Failed to create XCB surface.\n");
174 char *vsdr = sdr_load("data/main.vert.spv", &vsz);
175 char *fsdr = sdr_load("data/main.frag.spv", &fsz);
177 /* create semaphores */
178 if (!vk_create_semaphores(&vk_core, false, &vk_sema)) {
179 fprintf(stderr, "No semaphores were created.\n");
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");
189 if (vk_chain.swapchain == VK_NULL_HANDLE) {
190 fprintf(stderr, "Invalid swapchain handle.\n");
194 /* FIXME: this part is going to be part of each object's functions */
196 /* create depth attachment (for the moment we are going to use this
198 if (!vk_fill_image_props(&vk_core,
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,
206 &vk_depth_att.props)) {
207 fprintf(stderr, "Unsupported depth image properties\n");
210 if (!vk_create_image(&vk_core, &vk_depth_att.props, &vk_depth_att.obj)) {
211 fprintf(stderr, "Failed to create depth attachment.\n");
215 /* create renderer */
216 if (!vk_create_renderer(&vk_core,
217 vsdr, vsz, fsdr, fsz,
220 vk_chain.num_atts, vk_chain.atts, &vk_depth_att,
221 &vk_vert_info, &vk_rnd)) {
225 /* create cmd buffers */
226 for (size_t i = 0; i < vk_chain.num_atts; i++) {
227 VkCommandBuffer cmd_buf;
229 if(!(vk_create_fence(&vk_core, &fence))) {
230 fprintf(stderr, "Failed to create fence: %d.\n", (int)i);
233 vk_wait_fences.push_back(fence);
235 if (!(cmd_buf = vk_create_cmd_buffer(&vk_core))) {
236 fprintf(stderr, "Failed to create command buffer: %d.\n", (int)i);
240 /* record cmd buffer FIXME:
241 * part of each objects draw? loop for each
243 if (!vk_record_cmd_buffer(&vk_core, cmd_buf,
246 vk_chain.num_atts + 1, 0,
247 0, 0, win_w, win_h)) {
248 fprintf(stderr, "Failed to record command buffer.\n");
252 vk_cmd_buffers.push_back(cmd_buf);
255 vkResetFences(vk_core.dev, vk_wait_fences.size(), vk_wait_fences.data());
260 /* set GLFW callbacks */
262 glfwSetWindowSizeCallback(win, clb_reshape);
264 glfwSetCursorPosCallback(win, clb_motion);
265 glfwSetMouseButtonCallback(win, clb_mouse);
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());
273 vk_wait_fences.clear();
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());
278 vk_cmd_buffers.clear();
280 if (vk_depth_att.obj.img != VK_NULL_HANDLE) {
281 vk_destroy_image(&vk_core, &vk_depth_att.obj);
294 fprintf(stderr, "Failed to initialize Vulkan structs.\n");
298 camera = new OrbitCamera;
314 /* each object should have a command buffer renderpass etc? */
316 VkPipelineStageFlags wait_stages = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
318 vkAcquireNextImageKHR(vk_core.dev, vk_chain.swapchain,
319 UINT64_MAX, vk_sema.frame_ready, 0, &vk_chain_idx);
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;
331 if (vkQueueSubmit(vk_core.queue, 1, &sinfo, vk_wait_fences[vk_chain_idx]) != 0) {
332 fprintf(stderr, "Failed to submit draw commands.\n");
336 if (vkQueueWaitIdle(vk_core.queue) != VK_SUCCESS) {
337 fprintf(stderr, "Failed to wait idle.\n");
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);
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;
357 if (!vk_queue_present(&vk_chain, vk_core.queue, vk_chain_idx, vk_sema.frame_done)) {
360 vkResetFences(vk_core.dev, 1, &vk_wait_fences[vk_chain_idx]);
362 printf("display %d\n", count++);
368 vkQueueWaitIdle(vk_core.queue);
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);
374 glfwDestroyWindow(win);
376 if (vk_chain.swapchain) {
377 vk_destroy_swapchain(&vk_core, &vk_chain);
378 vkDestroySurfaceKHR(vk_core.inst, vk_surf, 0);
381 if (vk_enable_layers)
384 vk_destroy_cmd_buffers(&vk_core, vk_cmd_buffers.size(), vk_cmd_buffers.data());
387 vk_cleanup_ctx(&vk_core);
393 clb_reshape(GLFWwindow *win,
397 aspect = (float)width / (float)height;
398 mproj = calc_projection_matrix(45, aspect, 0.5, 1000.0f);
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);
408 clb_key(GLFWwindow *win, int key, int scancode,
409 int action, int mods)
411 if (action == GLFW_REPEAT) return;
413 if (action == GLFW_PRESS) {
415 case GLFW_KEY_ESCAPE:
416 glfwSetWindowShouldClose(win, GLFW_TRUE);
419 move_camera = !move_camera;
427 static double prev_x, prev_y;
428 static bool button[8];
431 clb_motion(GLFWwindow *win,
435 double dx = x - prev_x;
436 double dy = y - prev_y;
442 cam_theta += dx * 0.5;
452 cam_dist += dy * 0.1;
460 clb_mouse(GLFWwindow *win,