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;
36 static VkRenderPass rpass;
37 static VkFramebuffer fbs[2];
38 //semaphores-drawing-presentation
39 static uint32_t curr_img; // current sc image
40 static VkSemaphore psema;
42 /* static variables */
43 static Vec4 clear_color(1, 0.1, 0.1, 1.0);
45 /* static functions */
46 static void error_callback(int error, const char *descr);
47 static void clear(float r, float g, float b);
48 static void viewport(int x, int y, int width, int height);
49 static void zbuffer(bool enable);
50 static void cull_face(Gfx_cull_face cf);
51 static void reshape(int width, int height);
52 static void swapbuffers();
53 static void begin_drawing();
54 static void end_drawing();
56 static bool create_swapchain(VkSwapchainKHR *sc);
57 static bool create_zbuffer();
58 static bool create_renderpass();
59 static bool create_framebuffers();
60 static bool begin_init_command_buffer(VkCommandBuffer *cb);
61 static bool end_init_command_buffer(VkCommandBuffer *cb);
62 static bool allocate_rendering_command_buffers(VkCommandBuffer *bufs);
63 static void free_rendering_command_buffers(VkCommandBuffer *bufs, int count);
64 static bool begin_rendering_command_buffers(VkCommandBuffer *bufs, int count);
69 fprintf(stderr, "Failed to initialize GLFW.\n");
73 if(!glfwVulkanSupported()) {
74 fprintf(stderr, "No Vulkan support on the device.\n");
79 glfwSetErrorCallback(error_callback);
81 /* create device and command pool! */
82 if(!vku_create_device()) {
83 fprintf(stderr, "Failed to initialize vulkan.\n");
87 if(!glfwGetPhysicalDevicePresentationSupport(vk_instance, vk_physical, vk_qfamily)) {
88 fprintf(stderr, "Presentation support not found.\n");
92 glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
93 if(!(win = glfwCreateWindow(win_w, win_h, "vkcow", 0, 0))) {
94 fprintf(stderr, "Failed to create window.\n");
98 VkResult res = glfwCreateWindowSurface(vk_instance, win, 0, &vk_surface);
99 if(res != VK_SUCCESS) {
100 fprintf(stderr, "Failed to create KHR surface: %s\n", vku_get_vulkan_error_str(res));
104 if(!create_swapchain(&vk_swapchain)) {
105 fprintf(stderr, "Failed to create swapchain.\n");
109 init_buf = VK_NULL_HANDLE;
110 if(!begin_init_command_buffer(&init_buf)) {
111 fprintf(stderr, "Failed to start VK_NULL_HANDLE command buffer.\n");
115 if(!create_zbuffer()) {
116 fprintf(stderr, "Failed to create depth buffer.\n");
120 if(!create_renderpass()) {
121 fprintf(stderr, "Failed to create the renderpass.\n");
125 if(!create_framebuffers()) {
126 fprintf(stderr, "Failed to create the framebuffer.\n");
130 if(!end_init_command_buffer(&init_buf)) {
131 fprintf(stderr, "Failed to end the command buffer.\n");
135 /* rendering command buffers */
136 if(!allocate_rendering_command_buffers(rbufs)) {
137 fprintf(stderr, "Failed to allocate rendering command buffers.\n");
141 if(!begin_rendering_command_buffers(rbufs, 2)) {
142 fprintf(stderr, "Failed to begin rendering command buffers.\n");
147 gfx_viewport = viewport;
148 gfx_zbuffer = zbuffer;
149 gfx_cull_face = cull_face;
150 gfx_reshape = reshape;
151 gfx_swapbuffers = swapbuffers;
152 gfx_begin_drawing = begin_drawing;
153 gfx_end_drawing = end_drawing;
158 static bool create_swapchain(VkSwapchainKHR *sc)
160 /* surface capabilities */
161 VkSurfaceCapabilitiesKHR scap;
162 if(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(vk_physical, vk_surface, &scap) != VK_SUCCESS) {
163 fprintf(stderr, "Failed to get physical device surface capabilities\n");
167 /* presentation modes */
169 if(vkGetPhysicalDeviceSurfacePresentModesKHR(vk_physical, vk_surface, &prmode_cnt, 0) != VK_SUCCESS) {
170 fprintf(stderr, "Failed to get physical device surface presentation modes count.\n");
174 if(prmode_cnt == 0) {
175 fprintf(stderr, "Presentation modes not found.\n");
179 VkPresentModeKHR scmode = VK_PRESENT_MODE_FIFO_KHR;
180 VkPresentModeKHR *modes = new VkPresentModeKHR[prmode_cnt];
182 if(vkGetPhysicalDeviceSurfacePresentModesKHR(vk_physical, vk_surface, &prmode_cnt, modes) != VK_SUCCESS) {
183 fprintf(stderr, "Failed to get physical device presentation modes.\n");
187 for(uint32_t i=0; i<prmode_cnt; i++) {
188 if(modes[i] == VK_PRESENT_MODE_MAILBOX_KHR) {
189 scmode = VK_PRESENT_MODE_MAILBOX_KHR;
192 if((scmode != VK_PRESENT_MODE_MAILBOX_KHR) && (modes[i] == VK_PRESENT_MODE_IMMEDIATE_KHR)) {
194 scmode = VK_PRESENT_MODE_IMMEDIATE_KHR;
198 /* swapchain extents */
200 if(scap.currentExtent.width == 0xffffffff || scap.currentExtent.height == 0xffffffff) {
201 scextent.width = win_w;
202 scextent.height = win_h;
205 scextent = scap.currentExtent;
206 win_w = scextent.width;
207 win_h = scextent.height;
210 /* number of swapchain images (on intel that's 3: maybe should hardcode it to 2?) */
211 num_images = scap.minImageCount; //+ 1;
212 /* intel doesn't set the maxImageCount */
213 if(scap.maxImageCount > 0 && num_images > scap.maxImageCount)
214 num_images = scap.maxImageCount;
216 printf("num_images : %u\n", num_images);
217 assert(num_images > 0);
219 images = new VkImage[num_images];
220 iviews = new VkImageView[num_images];
222 /* transform flags */
223 VkSurfaceTransformFlagBitsKHR pre_transf = scap.currentTransform;
224 if(scap.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR)
225 pre_transf = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
227 /* find suitable colorspace, format */
229 VkColorSpaceKHR colorspace;
231 VkSurfaceFormatKHR sformat;
232 if(!vku_get_surface_format(vk_physical, vk_surface, &sformat)) {
236 format = sformat.format;
237 colorspace = sformat.colorSpace;
239 /* creating the swapchain */
240 VkSwapchainCreateInfoKHR sinfo;
241 memset(&sinfo, 0, sizeof sinfo);
243 sinfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
244 sinfo.surface = vk_surface;
245 sinfo.minImageCount = num_images;
246 sinfo.imageFormat = format;
247 sinfo.imageColorSpace = colorspace;
248 sinfo.imageExtent = scextent;
249 sinfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
250 sinfo.preTransform = pre_transf;
251 sinfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
252 sinfo.imageArrayLayers = 1;
253 sinfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
254 sinfo.presentMode = scmode;
255 sinfo.oldSwapchain = VK_NULL_HANDLE; //TODO
256 sinfo.clipped = VK_TRUE; //TODO
258 if(vkCreateSwapchainKHR(vk_device, &sinfo, 0, sc) != VK_SUCCESS) {
259 fprintf(stderr, "Failed to create swapchain.\n");
263 if(vkGetSwapchainImagesKHR(vk_device, *sc, &num_images, 0) != VK_SUCCESS) {
264 fprintf(stderr, "Failed to get the number of the swapchain images.\n");
268 if(vkGetSwapchainImagesKHR(vk_device, *sc, &num_images, images) != VK_SUCCESS) {
269 fprintf(stderr, "Failed to get the swapchain images.\n");
273 VkImageViewCreateInfo ivinf;
274 memset(&ivinf, 0, sizeof ivinf);
275 ivinf.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
276 ivinf.format = format;
278 VK_COMPONENT_SWIZZLE_R,
279 VK_COMPONENT_SWIZZLE_G,
280 VK_COMPONENT_SWIZZLE_B,
281 VK_COMPONENT_SWIZZLE_A
283 ivinf.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
284 ivinf.subresourceRange.levelCount = 1;
285 ivinf.subresourceRange.layerCount = 1;
286 ivinf.viewType = VK_IMAGE_VIEW_TYPE_2D;
288 for(uint32_t i=0; i<num_images; i++) {
289 ivinf.image = images[i];
292 if((res = vkCreateImageView(vk_device, &ivinf, 0, &iviews[i])) != VK_SUCCESS) {
293 fprintf(stderr, "Failed to create image view %d: %s.\n", i, vku_get_vulkan_error_str(res));
301 static bool begin_init_command_buffer(VkCommandBuffer *cb)
303 if(*cb == VK_NULL_HANDLE) {
304 *cb = vku_alloc_cmdbuf(vk_pool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
306 VkCommandBufferInheritanceInfo ciinf;
307 memset(&ciinf, 0, sizeof ciinf);
308 ciinf.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
309 ciinf.renderPass = VK_NULL_HANDLE;
310 ciinf.framebuffer = VK_NULL_HANDLE;
311 ciinf.occlusionQueryEnable = VK_FALSE;
313 VkCommandBufferBeginInfo cbinf;
314 memset(&cbinf, 0, sizeof cbinf);
315 cbinf.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
316 cbinf.pInheritanceInfo = &ciinf;
318 if(vkBeginCommandBuffer(*cb, &cbinf) != VK_SUCCESS) {
319 fprintf(stderr, "Failed to begin command buffer.\n");
326 static bool create_zbuffer()
328 VkImageCreateInfo dinfo;
329 memset(&dinfo, 0, sizeof dinfo);
331 dinfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
332 dinfo.imageType = VK_IMAGE_TYPE_2D;
333 dinfo.format = dformat;
334 dinfo.extent = {(uint32_t)win_w, (uint32_t)win_h, 1};
336 dinfo.arrayLayers = 1;
337 dinfo.samples = VK_SAMPLE_COUNT_1_BIT;
338 dinfo.tiling = VK_IMAGE_TILING_OPTIMAL;
339 dinfo.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
341 if(vkCreateImage(vk_device, &dinfo, 0, &dimg) != VK_SUCCESS) {
342 fprintf(stderr, "Failed to create depth buffer image.\n");
346 VkMemoryRequirements dmem_reqs;
347 vkGetImageMemoryRequirements(vk_device, dimg, &dmem_reqs);
350 if(!vku_allocate(dmem_reqs.size, &block)) {
351 fprintf(stderr, "Failed to allocate zbuffer image.\n");
355 vkBindImageMemory(vk_device, dimg, block.dev_mem, 0);
357 if(!vk_image_set_layout(init_buf, dimg, VK_IMAGE_ASPECT_DEPTH_BIT,
358 VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
359 (VkAccessFlagBits)0)) {
360 fprintf(stderr, "Failed to set depth buffer layout.\n");
364 VkImageViewCreateInfo div_inf;
365 memset(&div_inf, 0, sizeof div_inf);
367 div_inf.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
368 div_inf.image = dimg;
369 div_inf.format = dformat;
370 div_inf.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
371 div_inf.subresourceRange.levelCount = 1;
372 div_inf.subresourceRange.layerCount = 1;
373 div_inf.viewType = VK_IMAGE_VIEW_TYPE_2D;
375 if(vkCreateImageView(vk_device, &div_inf, 0, &dview) != VK_SUCCESS) {
376 fprintf(stderr, "Failed to create image view for depth buffer.\n");
383 static bool create_renderpass()
385 VkSurfaceFormatKHR sformat;
386 if(!vku_get_surface_format(vk_physical, vk_surface, &sformat)) {
387 fprintf(stderr, "Failed to get surface format.\n");
391 VkAttachmentDescription att[2];
392 memset(&att, 0, (sizeof att[0]) * 2);
394 att[0].format = sformat.format;
395 att[0].samples = VK_SAMPLE_COUNT_1_BIT;
396 att[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
397 att[0].storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
398 att[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
399 att[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
400 att[0].initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
401 att[0].finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
403 att[1].format = dformat;
404 att[1].samples = VK_SAMPLE_COUNT_1_BIT;
405 att[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
406 att[1].storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
407 att[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
408 att[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
409 att[1].initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
410 att[1].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
412 VkAttachmentReference cref;
413 memset(&cref, 0, sizeof cref);
414 cref.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
416 VkAttachmentReference dref;
417 memset(&dref, 0, sizeof dref);
419 dref.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
421 VkSubpassDescription sd;
422 memset(&sd, 0, sizeof sd);
423 sd.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
424 sd.colorAttachmentCount = 1;
425 sd.pColorAttachments = &cref;
426 sd.pDepthStencilAttachment = &dref;
428 VkRenderPassCreateInfo rinf;
429 memset(&rinf, 0, sizeof rinf);
430 rinf.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
431 rinf.attachmentCount = 2;
432 rinf.pAttachments = att;
433 rinf.subpassCount = 1;
434 rinf.pSubpasses = &sd;
436 if(vkCreateRenderPass(vk_device, &rinf, 0, &rpass) != VK_SUCCESS) {
437 fprintf(stderr, "Failed to create rpass.\n");
444 static bool create_framebuffers()
446 /* framebuffer attachments */
447 VkImageView fb_att[2];
450 VkFramebufferCreateInfo fbinf;
451 memset(&fbinf, 0, sizeof fbinf);
452 fbinf.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
453 fbinf.renderPass = rpass;
454 fbinf.attachmentCount = 2;
455 fbinf.pAttachments = fb_att;
457 fbinf.height = win_h;
460 for(int i=0; i<2; i++) {
461 fb_att[0] = iviews[i];
462 if(vkCreateFramebuffer(vk_device, &fbinf, 0, &fbs[i]) != VK_SUCCESS) {
463 fprintf(stderr, "Failed to create framebuffer %i\n", i);
470 static bool end_init_command_buffer(VkCommandBuffer *cb)
472 if(vkEndCommandBuffer(*cb) != VK_SUCCESS) {
473 fprintf(stderr, "Failed to end command buffer.\n");
478 memset(&si, 0, sizeof si);
479 si.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
480 si.commandBufferCount = 1;
481 si.pCommandBuffers = cb;
483 if(vkQueueSubmit(vk_queue, 1, &si, VK_NULL_HANDLE) != VK_SUCCESS) {
484 fprintf(stderr, "Failed to submit null queue.\n");
488 if(vkQueueWaitIdle(vk_queue) != VK_SUCCESS) {
489 fprintf(stderr, "QueueWaitIdle failure!\n");
493 vkFreeCommandBuffers(vk_device, vk_pool, 1, cb);
494 *cb = VK_NULL_HANDLE;
499 static bool allocate_rendering_command_buffers(VkCommandBuffer *bufs)
501 return vku_alloc_cmdbufs(vk_pool, VK_COMMAND_BUFFER_LEVEL_PRIMARY,
505 static void free_rendering_command_buffers(VkCommandBuffer *bufs, int count)
507 for(int i=0; i<count; i++) {
508 vku_free_cmdbuf(vk_pool, bufs[i]);
512 static bool begin_rendering_command_buffers(VkCommandBuffer *bufs, int count)
514 VkCommandBufferInheritanceInfo iinf;
515 memset(&iinf, 0, sizeof iinf);
516 iinf.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
517 iinf.renderPass = VK_NULL_HANDLE;
518 iinf.framebuffer = VK_NULL_HANDLE;
520 VkCommandBufferBeginInfo binf;
521 memset(&binf, 0, sizeof binf);
522 binf.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
523 binf.pInheritanceInfo = &iinf;
525 // setting clear values
526 VkClearValue clvals[2];
527 for(int i=0; i<4; i++) {
528 clvals[0].color.float32[i] = clear_color[i];
530 clvals[1].depthStencil = {1.0f, 0};
532 //build drawing command buffers
533 for(int i=0; i<count; i++) {
534 if(vkBeginCommandBuffer(bufs[i], &binf) != VK_SUCCESS) {
535 fprintf(stderr, "Failed to begin command buffer: %d\n", i);
539 VkImageMemoryBarrier imbarr;
540 memset(&imbarr, 0, sizeof imbarr);
541 imbarr.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
542 imbarr.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
543 imbarr.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
544 imbarr.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
545 imbarr.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
546 imbarr.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
547 imbarr.image = images[i];
548 imbarr.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
549 vkCmdPipelineBarrier(bufs[i], VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, 0, 0, 0, 1, &imbarr);
551 VkRenderPassBeginInfo rbinf;
552 memset(&rbinf, 0, sizeof rbinf);
553 rbinf.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
554 rbinf.renderPass = rpass;
555 rbinf.framebuffer = fbs[i];
556 rbinf.renderArea.extent.width = win_w;
557 rbinf.renderArea.extent.height = win_h;
558 rbinf.clearValueCount = count;
559 rbinf.pClearValues = clvals;
561 vkCmdBeginRenderPass(bufs[i], &rbinf, VK_SUBPASS_CONTENTS_INLINE);
563 memset(&viewport, 0, sizeof viewport);
564 viewport.width = (float)win_w;
565 viewport.height = (float)win_h;
566 viewport.maxDepth = 1.0f;
567 vkCmdSetViewport(bufs[i], 0, 1, &viewport);
570 memset(&scissor, 0, sizeof scissor);
571 scissor.extent.width = win_w;
572 scissor.extent.height = win_h;
573 vkCmdSetScissor(bufs[i], 0, 1, &scissor);
574 vkCmdEndRenderPass(bufs[i]);
576 /* pre-present barrier */
577 VkImageMemoryBarrier ppb;
578 memset(&ppb, 0, sizeof ppb);
579 ppb.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
580 ppb.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
581 ppb.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT;
582 ppb.oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
583 ppb.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
584 ppb.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
585 ppb.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
586 ppb.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
587 ppb.image = images[i];
589 vkCmdPipelineBarrier(bufs[i], VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, 0, 0, 0, 1, &ppb);
591 if(vkEndCommandBuffer(bufs[i]) != VK_SUCCESS) {
592 fprintf(stderr, "Failed to end command buffer: %d\n", i);
599 void cleanup_vulkan()
601 free_rendering_command_buffers(rbufs, 2);
603 glfwDestroyWindow(win);
607 //TODOs according to the book:
608 // 1- make sure all threads have been terminated (when I add threads)
612 static void error_callback(int error, const char *description)
614 fprintf(stderr, "GLFW error %d: %s.\n", error, description);
617 static void reshape(int width, int height)
621 static void clear(float r, float g, float b)
625 static void viewport(int x, int y, int width, int height)
629 static void zbuffer(bool enable)
633 static void cull_face(Gfx_cull_face cf)
637 static void swapbuffers()
641 static void begin_drawing()
643 VkSemaphoreCreateInfo psinf;
644 memset(&psinf, 0, sizeof psinf);
645 psinf.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
648 if((res = vkCreateSemaphore(vk_device, &psinf, 0, &psema)) != VK_SUCCESS) {
649 fprintf(stderr, "Failed to create semaphore.\n");
651 assert(res == VK_SUCCESS);
654 static void end_drawing()
656 VkResult res = vkAcquireNextImageKHR(vk_device, vk_swapchain,
657 UINT64_MAX, psema, VK_NULL_HANDLE, &curr_img);
658 if(res == VK_ERROR_OUT_OF_DATE_KHR) {
659 fprintf(stderr, "Swapchain out of date.\n");
662 assert(res == VK_SUCCESS);
665 memset(&sinf, 0, sizeof sinf);
666 VkPipelineStageFlags psflags = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
667 sinf.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
668 sinf.waitSemaphoreCount = 1;
669 sinf.pWaitSemaphores = &psema;
670 sinf.pWaitDstStageMask = &psflags;
671 sinf.commandBufferCount = 1;
672 sinf.pCommandBuffers = &rbufs[curr_img];
674 res = vkQueueSubmit(vk_queue, 1, &sinf, VK_NULL_HANDLE);
675 assert(res == VK_SUCCESS);
677 VkPresentInfoKHR pinf;
678 memset(&pinf, 0, sizeof pinf);
679 pinf.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
680 pinf.swapchainCount = 1;
681 pinf.pSwapchains = &vk_swapchain;
682 pinf.pImageIndices = &curr_img;
684 res = vkQueuePresentKHR(vk_queue, &pinf);
685 if(res == VK_ERROR_OUT_OF_DATE_KHR) {
686 fprintf(stderr, "Swapchain out of date.\n");
688 assert(res == VK_SUCCESS);
690 res = vkQueueWaitIdle(vk_queue);
691 assert(res == VK_SUCCESS);
693 vkDestroySemaphore(vk_device, psema, 0);