1 #define GLFW_INCLUDE_VULKAN
2 #include <GLFW/glfw3.h>
11 #include <gmath/gmath.h>
13 #include "allocator.h"
19 /* global variables */
20 extern GLFWwindow *win;
25 static VkCommandBuffer init_buf;
26 static VkCommandBuffer rbufs[2];
29 static VkImageView dview;
30 static const VkFormat dformat = VK_FORMAT_D32_SFLOAT_S8_UINT;
32 static VkImage *images;
33 static VkImageView *iviews;
34 static uint32_t num_images;
35 static VkFramebuffer fbs[2];
36 //semaphores-drawing-presentation
37 static uint32_t curr_img; // current sc image
38 static VkSemaphore psema;
40 /* static variables */
41 static Vec4 clear_color(1, 0.1, 0.1, 1.0);
43 /* static functions */
44 static void error_callback(int error, const char *descr);
45 static void clear(float r, float g, float b);
46 static void viewport(int x, int y, int width, int height);
47 static void zbuffer(bool enable);
48 static void cull_face(Gfx_cull_face cf);
49 static void reshape(int width, int height);
50 static void swapbuffers();
51 static void begin_drawing();
52 static void end_drawing();
54 static bool create_swapchain(VkSwapchainKHR *sc);
55 static bool create_zbuffer();
56 static bool create_renderpass();
57 static bool create_framebuffers();
58 static bool begin_init_command_buffer(VkCommandBuffer *cb);
59 static bool end_init_command_buffer(VkCommandBuffer *cb);
60 static bool allocate_rendering_command_buffers(VkCommandBuffer *bufs);
61 static void free_rendering_command_buffers(VkCommandBuffer *bufs, int count);
62 static bool begin_rendering_command_buffers(VkCommandBuffer *bufs, int count);
67 fprintf(stderr, "Failed to initialize GLFW.\n");
71 if(!glfwVulkanSupported()) {
72 fprintf(stderr, "No Vulkan support on the device.\n");
77 glfwSetErrorCallback(error_callback);
79 /* create device and command pool! */
80 if(!vku_create_device()) {
81 fprintf(stderr, "Failed to initialize vulkan.\n");
85 if(!glfwGetPhysicalDevicePresentationSupport(vk_instance, vk_physical, vk_qfamily)) {
86 fprintf(stderr, "Presentation support not found.\n");
90 glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
91 if(!(win = glfwCreateWindow(win_w, win_h, "vkcow", 0, 0))) {
92 fprintf(stderr, "Failed to create window.\n");
96 VkResult res = glfwCreateWindowSurface(vk_instance, win, 0, &vk_surface);
97 if(res != VK_SUCCESS) {
98 fprintf(stderr, "Failed to create KHR surface: %s\n", vku_get_vulkan_error_str(res));
102 if(!create_swapchain(&vk_swapchain)) {
103 fprintf(stderr, "Failed to create swapchain.\n");
107 init_buf = VK_NULL_HANDLE;
108 if(!begin_init_command_buffer(&init_buf)) {
109 fprintf(stderr, "Failed to start VK_NULL_HANDLE command buffer.\n");
113 if(!create_zbuffer()) {
114 fprintf(stderr, "Failed to create depth buffer.\n");
118 if(!create_renderpass()) {
119 fprintf(stderr, "Failed to create the renderpass.\n");
123 if(!create_framebuffers()) {
124 fprintf(stderr, "Failed to create the framebuffer.\n");
128 if(!end_init_command_buffer(&init_buf)) {
129 fprintf(stderr, "Failed to end the command buffer.\n");
133 /* rendering command buffers */
134 if(!allocate_rendering_command_buffers(rbufs)) {
135 fprintf(stderr, "Failed to allocate rendering command buffers.\n");
139 if(!begin_rendering_command_buffers(rbufs, 2)) {
140 fprintf(stderr, "Failed to begin rendering command buffers.\n");
145 gfx_viewport = viewport;
146 gfx_zbuffer = zbuffer;
147 gfx_cull_face = cull_face;
148 gfx_reshape = reshape;
149 gfx_swapbuffers = swapbuffers;
150 gfx_begin_drawing = begin_drawing;
151 gfx_end_drawing = end_drawing;
156 static bool create_swapchain(VkSwapchainKHR *sc)
158 /* surface capabilities */
159 VkSurfaceCapabilitiesKHR scap;
160 if(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(vk_physical, vk_surface, &scap) != VK_SUCCESS) {
161 fprintf(stderr, "Failed to get physical device surface capabilities\n");
165 /* presentation modes */
167 if(vkGetPhysicalDeviceSurfacePresentModesKHR(vk_physical, vk_surface, &prmode_cnt, 0) != VK_SUCCESS) {
168 fprintf(stderr, "Failed to get physical device surface presentation modes count.\n");
172 if(prmode_cnt == 0) {
173 fprintf(stderr, "Presentation modes not found.\n");
177 VkPresentModeKHR scmode = VK_PRESENT_MODE_FIFO_KHR;
178 VkPresentModeKHR *modes = new VkPresentModeKHR[prmode_cnt];
180 if(vkGetPhysicalDeviceSurfacePresentModesKHR(vk_physical, vk_surface, &prmode_cnt, modes) != VK_SUCCESS) {
181 fprintf(stderr, "Failed to get physical device presentation modes.\n");
185 for(uint32_t i=0; i<prmode_cnt; i++) {
186 if(modes[i] == VK_PRESENT_MODE_MAILBOX_KHR) {
187 scmode = VK_PRESENT_MODE_MAILBOX_KHR;
190 if((scmode != VK_PRESENT_MODE_MAILBOX_KHR) && (modes[i] == VK_PRESENT_MODE_IMMEDIATE_KHR)) {
192 scmode = VK_PRESENT_MODE_IMMEDIATE_KHR;
196 /* swapchain extents */
198 if(scap.currentExtent.width == 0xffffffff || scap.currentExtent.height == 0xffffffff) {
199 scextent.width = win_w;
200 scextent.height = win_h;
203 scextent = scap.currentExtent;
204 win_w = scextent.width;
205 win_h = scextent.height;
208 /* number of swapchain images (on intel that's 3: maybe should hardcode it to 2?) */
209 num_images = scap.minImageCount; //+ 1;
210 /* intel doesn't set the maxImageCount */
211 if(scap.maxImageCount > 0 && num_images > scap.maxImageCount)
212 num_images = scap.maxImageCount;
214 printf("num_images : %u\n", num_images);
215 assert(num_images > 0);
217 images = new VkImage[num_images];
218 iviews = new VkImageView[num_images];
220 /* transform flags */
221 VkSurfaceTransformFlagBitsKHR pre_transf = scap.currentTransform;
222 if(scap.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR)
223 pre_transf = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
225 /* find suitable colorspace, format */
227 VkColorSpaceKHR colorspace;
229 VkSurfaceFormatKHR sformat;
230 if(!vku_get_surface_format(vk_physical, vk_surface, &sformat)) {
234 format = sformat.format;
235 colorspace = sformat.colorSpace;
237 /* creating the swapchain */
238 VkSwapchainCreateInfoKHR sinfo;
239 memset(&sinfo, 0, sizeof sinfo);
241 sinfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
242 sinfo.surface = vk_surface;
243 sinfo.minImageCount = num_images;
244 sinfo.imageFormat = format;
245 sinfo.imageColorSpace = colorspace;
246 sinfo.imageExtent = scextent;
247 sinfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
248 sinfo.preTransform = pre_transf;
249 sinfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
250 sinfo.imageArrayLayers = 1;
251 sinfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
252 sinfo.presentMode = scmode;
253 sinfo.oldSwapchain = VK_NULL_HANDLE; //TODO
254 sinfo.clipped = VK_TRUE; //TODO
256 if(vkCreateSwapchainKHR(vk_device, &sinfo, 0, sc) != VK_SUCCESS) {
257 fprintf(stderr, "Failed to create swapchain.\n");
261 if(vkGetSwapchainImagesKHR(vk_device, *sc, &num_images, 0) != VK_SUCCESS) {
262 fprintf(stderr, "Failed to get the number of the swapchain images.\n");
266 if(vkGetSwapchainImagesKHR(vk_device, *sc, &num_images, images) != VK_SUCCESS) {
267 fprintf(stderr, "Failed to get the swapchain images.\n");
271 VkImageViewCreateInfo ivinf;
272 memset(&ivinf, 0, sizeof ivinf);
273 ivinf.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
274 ivinf.format = format;
276 VK_COMPONENT_SWIZZLE_R,
277 VK_COMPONENT_SWIZZLE_G,
278 VK_COMPONENT_SWIZZLE_B,
279 VK_COMPONENT_SWIZZLE_A
281 ivinf.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
282 ivinf.subresourceRange.levelCount = 1;
283 ivinf.subresourceRange.layerCount = 1;
284 ivinf.viewType = VK_IMAGE_VIEW_TYPE_2D;
286 for(uint32_t i=0; i<num_images; i++) {
287 ivinf.image = images[i];
290 if((res = vkCreateImageView(vk_device, &ivinf, 0, &iviews[i])) != VK_SUCCESS) {
291 fprintf(stderr, "Failed to create image view %d: %s.\n", i, vku_get_vulkan_error_str(res));
299 static bool begin_init_command_buffer(VkCommandBuffer *cb)
301 if(*cb == VK_NULL_HANDLE) {
302 *cb = vku_alloc_cmdbuf(vk_pool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
304 VkCommandBufferInheritanceInfo ciinf;
305 memset(&ciinf, 0, sizeof ciinf);
306 ciinf.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
307 ciinf.renderPass = VK_NULL_HANDLE;
308 ciinf.framebuffer = VK_NULL_HANDLE;
309 ciinf.occlusionQueryEnable = VK_FALSE;
311 VkCommandBufferBeginInfo cbinf;
312 memset(&cbinf, 0, sizeof cbinf);
313 cbinf.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
314 cbinf.pInheritanceInfo = &ciinf;
316 if(vkBeginCommandBuffer(*cb, &cbinf) != VK_SUCCESS) {
317 fprintf(stderr, "Failed to begin command buffer.\n");
324 static bool create_zbuffer()
326 VkImageCreateInfo dinfo;
327 memset(&dinfo, 0, sizeof dinfo);
329 dinfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
330 dinfo.imageType = VK_IMAGE_TYPE_2D;
331 dinfo.format = dformat;
332 dinfo.extent = {(uint32_t)win_w, (uint32_t)win_h, 1};
334 dinfo.arrayLayers = 1;
335 dinfo.samples = VK_SAMPLE_COUNT_1_BIT;
336 dinfo.tiling = VK_IMAGE_TILING_OPTIMAL;
337 dinfo.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
339 if(vkCreateImage(vk_device, &dinfo, 0, &dimg) != VK_SUCCESS) {
340 fprintf(stderr, "Failed to create depth buffer image.\n");
344 VkMemoryRequirements dmem_reqs;
345 vkGetImageMemoryRequirements(vk_device, dimg, &dmem_reqs);
348 if(!vku_allocate(dmem_reqs.size, &block)) {
349 fprintf(stderr, "Failed to allocate zbuffer image.\n");
353 vkBindImageMemory(vk_device, dimg, block.dev_mem, 0);
355 if(!vk_image_set_layout(init_buf, dimg, VK_IMAGE_ASPECT_DEPTH_BIT,
356 VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
357 (VkAccessFlagBits)0)) {
358 fprintf(stderr, "Failed to set depth buffer layout.\n");
362 VkImageViewCreateInfo div_inf;
363 memset(&div_inf, 0, sizeof div_inf);
365 div_inf.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
366 div_inf.image = dimg;
367 div_inf.format = dformat;
368 div_inf.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
369 div_inf.subresourceRange.levelCount = 1;
370 div_inf.subresourceRange.layerCount = 1;
371 div_inf.viewType = VK_IMAGE_VIEW_TYPE_2D;
373 if(vkCreateImageView(vk_device, &div_inf, 0, &dview) != VK_SUCCESS) {
374 fprintf(stderr, "Failed to create image view for depth buffer.\n");
381 static bool create_renderpass()
383 VkSurfaceFormatKHR sformat;
384 if(!vku_get_surface_format(vk_physical, vk_surface, &sformat)) {
385 fprintf(stderr, "Failed to get surface format.\n");
389 VkAttachmentDescription att[2];
390 memset(&att, 0, (sizeof att[0]) * 2);
392 att[0].format = sformat.format;
393 att[0].samples = VK_SAMPLE_COUNT_1_BIT;
394 att[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
395 att[0].storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
396 att[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
397 att[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
398 att[0].initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
399 att[0].finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
401 att[1].format = dformat;
402 att[1].samples = VK_SAMPLE_COUNT_1_BIT;
403 att[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
404 att[1].storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
405 att[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
406 att[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
407 att[1].initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
408 att[1].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
410 VkAttachmentReference cref;
411 memset(&cref, 0, sizeof cref);
412 cref.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
414 VkAttachmentReference dref;
415 memset(&dref, 0, sizeof dref);
417 dref.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
419 VkSubpassDescription sd;
420 memset(&sd, 0, sizeof sd);
421 sd.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
422 sd.colorAttachmentCount = 1;
423 sd.pColorAttachments = &cref;
424 sd.pDepthStencilAttachment = &dref;
426 VkRenderPassCreateInfo rinf;
427 memset(&rinf, 0, sizeof rinf);
428 rinf.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
429 rinf.attachmentCount = 2;
430 rinf.pAttachments = att;
431 rinf.subpassCount = 1;
432 rinf.pSubpasses = &sd;
434 if(vkCreateRenderPass(vk_device, &rinf, 0, &vk_renderpass) != VK_SUCCESS) {
435 fprintf(stderr, "Failed to create render pass.\n");
442 static bool create_framebuffers()
444 /* framebuffer attachments */
445 VkImageView fb_att[2];
448 VkFramebufferCreateInfo fbinf;
449 memset(&fbinf, 0, sizeof fbinf);
450 fbinf.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
451 fbinf.renderPass = vk_renderpass;
452 fbinf.attachmentCount = 2;
453 fbinf.pAttachments = fb_att;
455 fbinf.height = win_h;
458 for(int i=0; i<2; i++) {
459 fb_att[0] = iviews[i];
460 if(vkCreateFramebuffer(vk_device, &fbinf, 0, &fbs[i]) != VK_SUCCESS) {
461 fprintf(stderr, "Failed to create framebuffer %i\n", i);
468 static bool end_init_command_buffer(VkCommandBuffer *cb)
470 if(vkEndCommandBuffer(*cb) != VK_SUCCESS) {
471 fprintf(stderr, "Failed to end command buffer.\n");
476 memset(&si, 0, sizeof si);
477 si.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
478 si.commandBufferCount = 1;
479 si.pCommandBuffers = cb;
481 if(vkQueueSubmit(vk_queue, 1, &si, VK_NULL_HANDLE) != VK_SUCCESS) {
482 fprintf(stderr, "Failed to submit null queue.\n");
486 if(vkQueueWaitIdle(vk_queue) != VK_SUCCESS) {
487 fprintf(stderr, "QueueWaitIdle failure!\n");
491 vkFreeCommandBuffers(vk_device, vk_pool, 1, cb);
492 *cb = VK_NULL_HANDLE;
497 static bool allocate_rendering_command_buffers(VkCommandBuffer *bufs)
499 return vku_alloc_cmdbufs(vk_pool, VK_COMMAND_BUFFER_LEVEL_PRIMARY,
503 static void free_rendering_command_buffers(VkCommandBuffer *bufs, int count)
505 for(int i=0; i<count; i++) {
506 vku_free_cmdbuf(vk_pool, bufs[i]);
510 static bool begin_rendering_command_buffers(VkCommandBuffer *bufs, int count)
512 VkCommandBufferInheritanceInfo iinf;
513 memset(&iinf, 0, sizeof iinf);
514 iinf.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
515 iinf.renderPass = VK_NULL_HANDLE;
516 iinf.framebuffer = VK_NULL_HANDLE;
518 VkCommandBufferBeginInfo binf;
519 memset(&binf, 0, sizeof binf);
520 binf.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
521 binf.pInheritanceInfo = &iinf;
523 // setting clear values
524 VkClearValue clvals[2];
525 for(int i=0; i<4; i++) {
526 clvals[0].color.float32[i] = clear_color[i];
528 clvals[1].depthStencil = {1.0f, 0};
530 //build drawing command buffers
531 for(int i=0; i<count; i++) {
532 if(vkBeginCommandBuffer(bufs[i], &binf) != VK_SUCCESS) {
533 fprintf(stderr, "Failed to begin command buffer: %d\n", i);
537 VkImageMemoryBarrier imbarr;
538 memset(&imbarr, 0, sizeof imbarr);
539 imbarr.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
540 imbarr.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
541 imbarr.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
542 imbarr.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
543 imbarr.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
544 imbarr.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
545 imbarr.image = images[i];
546 imbarr.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
547 vkCmdPipelineBarrier(bufs[i], VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, 0, 0, 0, 1, &imbarr);
549 VkRenderPassBeginInfo rbinf;
550 memset(&rbinf, 0, sizeof rbinf);
551 rbinf.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
552 rbinf.renderPass = vk_renderpass;
553 rbinf.framebuffer = fbs[i];
554 rbinf.renderArea.extent.width = win_w;
555 rbinf.renderArea.extent.height = win_h;
556 rbinf.clearValueCount = count;
557 rbinf.pClearValues = clvals;
559 vkCmdBeginRenderPass(bufs[i], &rbinf, VK_SUBPASS_CONTENTS_INLINE);
561 memset(&viewport, 0, sizeof viewport);
562 viewport.width = (float)win_w;
563 viewport.height = (float)win_h;
564 viewport.maxDepth = 1.0f;
565 vkCmdSetViewport(bufs[i], 0, 1, &viewport);
568 memset(&scissor, 0, sizeof scissor);
569 scissor.extent.width = win_w;
570 scissor.extent.height = win_h;
571 vkCmdSetScissor(bufs[i], 0, 1, &scissor);
572 vkCmdEndRenderPass(bufs[i]);
574 /* pre-present barrier */
575 VkImageMemoryBarrier ppb;
576 memset(&ppb, 0, sizeof ppb);
577 ppb.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
578 ppb.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
579 ppb.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT;
580 ppb.oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
581 ppb.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
582 ppb.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
583 ppb.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
584 ppb.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
585 ppb.image = images[i];
587 vkCmdPipelineBarrier(bufs[i], VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, 0, 0, 0, 1, &ppb);
589 if(vkEndCommandBuffer(bufs[i]) != VK_SUCCESS) {
590 fprintf(stderr, "Failed to end command buffer: %d\n", i);
597 void cleanup_vulkan()
599 free_rendering_command_buffers(rbufs, 2);
601 glfwDestroyWindow(win);
605 //TODOs according to the book:
606 // 1- make sure all threads have been terminated (when I add threads)
610 static void error_callback(int error, const char *description)
612 fprintf(stderr, "GLFW error %d: %s.\n", error, description);
615 static void reshape(int width, int height)
619 static void clear(float r, float g, float b)
623 static void viewport(int x, int y, int width, int height)
627 static void zbuffer(bool enable)
631 static void cull_face(Gfx_cull_face cf)
635 static void swapbuffers()
639 static void begin_drawing()
641 VkSemaphoreCreateInfo psinf;
642 memset(&psinf, 0, sizeof psinf);
643 psinf.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
646 if((res = vkCreateSemaphore(vk_device, &psinf, 0, &psema)) != VK_SUCCESS) {
647 fprintf(stderr, "Failed to create semaphore.\n");
649 assert(res == VK_SUCCESS);
652 static void end_drawing()
654 VkResult res = vkAcquireNextImageKHR(vk_device, vk_swapchain,
655 UINT64_MAX, psema, VK_NULL_HANDLE, &curr_img);
656 if(res == VK_ERROR_OUT_OF_DATE_KHR) {
657 fprintf(stderr, "Swapchain out of date.\n");
660 assert(res == VK_SUCCESS);
663 memset(&sinf, 0, sizeof sinf);
664 VkPipelineStageFlags psflags = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
665 sinf.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
666 sinf.waitSemaphoreCount = 1;
667 sinf.pWaitSemaphores = &psema;
668 sinf.pWaitDstStageMask = &psflags;
669 sinf.commandBufferCount = 1;
670 sinf.pCommandBuffers = &rbufs[curr_img];
672 res = vkQueueSubmit(vk_queue, 1, &sinf, VK_NULL_HANDLE);
673 assert(res == VK_SUCCESS);
675 VkPresentInfoKHR pinf;
676 memset(&pinf, 0, sizeof pinf);
677 pinf.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
678 pinf.swapchainCount = 1;
679 pinf.pSwapchains = &vk_swapchain;
680 pinf.pImageIndices = &curr_img;
682 res = vkQueuePresentKHR(vk_queue, &pinf);
683 if(res == VK_ERROR_OUT_OF_DATE_KHR) {
684 fprintf(stderr, "Swapchain out of date.\n");
686 assert(res == VK_SUCCESS);
688 res = vkQueueWaitIdle(vk_queue);
689 assert(res == VK_SUCCESS);
691 vkDestroySemaphore(vk_device, psema, 0);