rewriting swapchain/image/allocation parts
[demo] / src / vulkan / vk.cc
1 #define GLFW_INCLUDE_VULKAN
2 #include <GLFW/glfw3.h>
3
4 #include <alloca.h>
5 #include <assert.h>
6 #include <stdio.h>
7 #include <string.h>
8 #include <string>
9 #include <vector>
10
11 #include <gmath/gmath.h>
12
13 #include "allocator.h"
14 #include "gfxapi.h"
15 #include "image.h"
16 #include "vkutil.h"
17 #include "vk.h"
18
19 /* global variables */
20 extern GLFWwindow *win;
21 extern int win_w;
22 extern int win_h;
23
24 static VkCommandBuffer cmd_buf; // command buffer used at zbuffer creation
25 //depth buffer
26 static VkImage dimg;
27 static VkImageView dview;
28 //swapchain
29 static VkImage *images;
30 static VkImageView *iviews;
31 static uint32_t num_images;
32
33 /* static variables */
34 static VkDeviceMemory gpu_mem; // to be replaced when I fix the allocator
35 // zbuffer image, view:
36
37 VkCommandBuffer *swapchain_cmd_bufs;
38
39 /* static functions */
40 static void error_callback(int error, const char *descr);
41 static void clear(float r, float g, float b);
42 static void viewport(int x, int y, int width, int height);
43 static void zbuffer(bool enable);
44 static void cull_face(Gfx_cull_face cf);
45 static void reshape(int width, int height);
46 static void swapbuffers();
47 static void begin_drawing();
48 static void end_drawing();
49
50 static bool create_swapchain();
51 static bool begin_command_buffer();
52 static bool create_swapchain_image_views(VkFormat format);
53 static bool create_zbuffer();
54
55 static bool create_swapchain_cmd_bufs(VkCommandPool vk_pool);
56 static bool record_cmd_clear(float r, float g, float b);
57
58 bool init_vulkan()
59 {
60         if(!glfwInit()) {
61                 fprintf(stderr, "Failed to initialize GLFW.\n");
62                 return false;
63         }
64
65         if(!glfwVulkanSupported()) {
66                 fprintf(stderr, "No Vulkan support on the device.\n");
67                 return false;
68         }
69
70         //TODO: remove later
71         glfwSetErrorCallback(error_callback);
72
73         /* create device and command pool! */
74         if(!vku_create_device()) {
75                 fprintf(stderr, "Failed to initialize vulkan.\n");
76                 return false;
77         }
78
79         if(!glfwGetPhysicalDevicePresentationSupport(vkinst, vk_physical, vkqfamily)) {
80                 fprintf(stderr, "Presentation support not found.\n");
81                 return false;
82         }
83
84         glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
85         if(!(win = glfwCreateWindow(win_w, win_h, "vkcow", 0, 0))) {
86                 fprintf(stderr, "Failed to create window.\n");
87                 return false;
88         }
89
90         VkResult res = glfwCreateWindowSurface(vkinst, win, 0, &vk_surface);
91         if(res != VK_SUCCESS) {
92                 fprintf(stderr, "Failed to create KHR surface: %s\n", vku_get_vulkan_error_str(res));
93                 return false;
94         }
95
96         if(!create_swapchain()) {
97                 fprintf(stderr, "Failed to create swapchain.\n");
98                 return false;
99         }
100
101         cmd_buf = VK_NULL_HANDLE;
102         if(!begin_command_buffer()) {
103                 fprintf(stderr, "Failed to start VK_NULL_HANDLE command buffer.\n");
104                 return false;
105         }
106
107         if(!create_zbuffer()) {
108                 fprintf(stderr, "Failed to create depth buffer.\n");
109                 return false;
110         }
111
112         gfx_clear = clear;
113         gfx_viewport = viewport;
114         gfx_zbuffer = zbuffer;
115         gfx_cull_face = cull_face;
116         gfx_reshape = reshape;
117         gfx_swapbuffers = swapbuffers;
118         gfx_begin_drawing = begin_drawing;
119         gfx_end_drawing = end_drawing;
120
121
122 /*
123         if(!vku_create_semaphores())
124                 return false;
125
126         if(!(vk_swapchain = vku_create_swapchain(vk_surface, win_w, win_h, 2,
127                                                 VK_PRESENT_MODE_IMMEDIATE_KHR, 0))) {
128                 fprintf(stderr, "Failed to create swapchain.\n");
129                 return false;
130         }
131
132         vkswapchain_images = vku_get_swapchain_images(vk_swapchain, &vknum_swapchain_images);
133         if(!vkswapchain_images) {
134                 fprintf(stderr, "Failed to get swapchain images.\n");
135                 return false;
136         }
137
138 //              vkswapchain_views = vku_create_image_views(vkswapchain_images, vknum_swapchain_images);
139 //              if(!vkswapchain_views) {
140 //                      fprintf(stderr, "Failed to create swapchain image views.\n");
141 //                      delete [] vkswapchain_images;
142 //                      return false;
143 //              }
144
145         if(!create_swapchain_cmd_bufs(vk_pool)) {
146                 return false;
147         }
148
149         if(!record_cmd_clear(1.0, 0.1, 0.1))
150                 return false;
151         */
152
153         return true;
154 }
155
156 static bool create_swapchain()
157 {
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");
162                 return false;
163         }
164
165         /* presentation modes */
166         uint32_t prmode_cnt;
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");
169                 return false;
170         }
171
172         if(prmode_cnt == 0) {
173                 fprintf(stderr, "Presentation modes not found.\n");
174                 return false;
175         }
176
177         VkPresentModeKHR scmode = VK_PRESENT_MODE_FIFO_KHR;
178         VkPresentModeKHR *modes = new VkPresentModeKHR[prmode_cnt];
179
180         if(vkGetPhysicalDeviceSurfacePresentModesKHR(vk_physical, vk_surface, &prmode_cnt, modes) != VK_SUCCESS) {
181                 fprintf(stderr, "Failed to get physical device presentation modes.\n");
182                 return false;
183         }
184
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;
188                         break;
189                 }
190                 if((scmode != VK_PRESENT_MODE_MAILBOX_KHR) && (modes[i] == VK_PRESENT_MODE_IMMEDIATE_KHR)) {
191                                 //fallback
192                                 scmode = VK_PRESENT_MODE_IMMEDIATE_KHR;
193                 }
194         }
195
196         /* swapchain extents */
197         VkExtent2D scextent;
198         if(scap.currentExtent.width == 0xffffffff || scap.currentExtent.height == 0xffffffff) {
199                 scextent.width = win_w;
200                 scextent.height = win_h;
201         }
202         else {
203                 scextent = scap.currentExtent;
204                 win_w = scextent.width;
205                 win_h = scextent.height;
206         }
207
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;
213
214         printf("num_images : %u\n", num_images);
215         assert(num_images > 0);
216
217         /* transform flags */
218         VkSurfaceTransformFlagBitsKHR pre_transf = scap.currentTransform;
219         if(scap.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR)
220                 pre_transf = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
221
222         /* find suitable colorspace, format */
223         uint32_t fcount;
224         if(vkGetPhysicalDeviceSurfaceFormatsKHR(vk_physical, vk_surface, &fcount, 0) != VK_SUCCESS) {
225                 fprintf(stderr, "Failed to get format count for physical device.\n");
226                 return false;
227         }
228         if(fcount == 0) {
229                 fprintf(stderr, "No color formats were found.\n");
230                 return false;
231         }
232
233         VkFormat format;
234         VkColorSpaceKHR colorspace;
235
236         VkSurfaceFormatKHR *formats = new VkSurfaceFormatKHR[fcount];
237         if(vkGetPhysicalDeviceSurfaceFormatsKHR(vk_physical, vk_surface, &fcount, formats) != VK_SUCCESS) {
238                 fprintf(stderr, "Failed to get surface formats.\n");
239                 return false;
240         }
241         if((fcount == 1) && (formats[0].format == VK_FORMAT_UNDEFINED)) {
242                 format = VK_FORMAT_B8G8R8_UNORM;
243         } else {
244                 format = formats[0].format;
245         }
246         colorspace = formats[0].colorSpace;
247
248         /* creating the swapchain */
249         VkSwapchainCreateInfoKHR sinfo;
250         memset(&sinfo, 0, sizeof sinfo);
251
252         sinfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
253         sinfo.surface = vk_surface;
254         sinfo.minImageCount = num_images;
255         sinfo.imageFormat = format;
256         sinfo.imageColorSpace = colorspace;
257         sinfo.imageExtent = scextent;
258         sinfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
259         sinfo.preTransform = pre_transf;
260         sinfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
261         sinfo.imageArrayLayers = 1;
262         sinfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
263         sinfo.presentMode = scmode;
264         sinfo.oldSwapchain = VK_NULL_HANDLE; //TODO
265         sinfo.clipped = VK_TRUE; //TODO
266
267         if(vkCreateSwapchainKHR(vk_device, &sinfo, 0, &vk_swapchain) != VK_SUCCESS) {
268                 fprintf(stderr, "Failed to create swapchain.\n");
269                 return false;
270         }
271
272         if(vkGetSwapchainImagesKHR(vk_device, vk_swapchain, &num_images, 0) != VK_SUCCESS) {
273                 fprintf(stderr, "Failed to get the number of the swapchain images.\n");
274                 return false;
275         }
276
277         images = new VkImage[num_images];
278         if(vkGetSwapchainImagesKHR(vk_device, vk_swapchain, &num_images, images) != VK_SUCCESS) {
279                 fprintf(stderr, "Failed to get the swapchain images.\n");
280                 return false;
281         }
282         assert(images);
283
284         if(!create_swapchain_image_views(format)) {
285                 fprintf(stderr, "Failed to create image views for the swapchain images.\n");
286                 return false;
287         }
288
289         // create renderpass
290
291
292         return true;
293 }
294
295 static bool create_swapchain_image_views(VkFormat format)
296 {
297         VkImageViewCreateInfo ivinf;
298         memset(&ivinf, 0, sizeof ivinf);
299
300         ivinf.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
301         ivinf.format = format;
302         ivinf.components = {
303                 VK_COMPONENT_SWIZZLE_R,
304                 VK_COMPONENT_SWIZZLE_G,
305                 VK_COMPONENT_SWIZZLE_B,
306                 VK_COMPONENT_SWIZZLE_A
307         };
308         ivinf.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
309         ivinf.subresourceRange.levelCount = 1;
310         ivinf.subresourceRange.layerCount = 1;
311         ivinf.viewType = VK_IMAGE_VIEW_TYPE_2D;
312
313         iviews = new VkImageView[num_images];
314         for(uint32_t i=0; i<num_images; i++) {
315                 ivinf.image = images[i];
316                 if(vkCreateImageView(vk_device, &ivinf, 0, &iviews[i]) != VK_SUCCESS) {
317                         fprintf(stderr, "Failed to create view for the swapchain image: %d.\n", i);
318                         return false;
319                 }
320         }
321         return true;
322 }
323
324 static bool begin_command_buffer()
325 {
326         if(cmd_buf == VK_NULL_HANDLE) {
327                 cmd_buf = vku_alloc_cmdbuf(vk_pool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
328
329                 VkCommandBufferInheritanceInfo ciinf;
330                 memset(&ciinf, 0, sizeof ciinf);
331                 ciinf.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
332                 ciinf.renderPass = VK_NULL_HANDLE;
333                 ciinf.framebuffer = VK_NULL_HANDLE;
334                 ciinf.occlusionQueryEnable = VK_FALSE;
335
336                 VkCommandBufferBeginInfo cbinf;
337                 memset(&cbinf, 0, sizeof cbinf);
338                 cbinf.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
339                 cbinf.pInheritanceInfo = &ciinf;
340
341                 if(vkBeginCommandBuffer(cmd_buf, &cbinf) != VK_SUCCESS) {
342                         fprintf(stderr, "Failed to begin command buffer.\n");
343                         return false;
344                 }
345         }
346         return true;
347 }
348
349 static bool create_zbuffer()
350 {
351         VkFormat dformat = VK_FORMAT_D32_SFLOAT_S8_UINT;
352
353         VkImageCreateInfo dinfo;
354         memset(&dinfo, 0, sizeof dinfo);
355
356         dinfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
357         dinfo.imageType = VK_IMAGE_TYPE_2D;
358         dinfo.format = dformat;
359         dinfo.extent = {win_w, win_h, 1};
360         dinfo.mipLevels = 1;
361         dinfo.arrayLayers = 1;
362         dinfo.samples = VK_SAMPLE_COUNT_1_BIT;
363         dinfo.tiling = VK_IMAGE_TILING_OPTIMAL;
364         dinfo.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
365
366         if(vkCreateImage(vk_device, &dinfo, 0, &dimg) != VK_SUCCESS) {
367                 fprintf(stderr, "Failed to create depth buffer image.\n");
368                 return false;
369         }
370
371         VkMemoryRequirements dmem_reqs;
372         vkGetImageMemoryRequirements(vk_device, dimg, &dmem_reqs);
373
374         gpu_mem = vk_allocate(dmem_reqs.size);
375
376         if(!gpu_mem)
377                 return false;
378
379         vkBindImageMemory(vk_device, dimg, gpu_mem, 0);
380
381         // XXX set image layout
382         if(!vk_image_set_layout(cmd_buf, dimg, VK_IMAGE_ASPECT_DEPTH_BIT,
383                         VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
384                         (VkAccessFlagBits)0)) {
385                 fprintf(stderr, "Failed to set depth buffer layout.\n");
386                 return false;
387         }
388
389         VkImageViewCreateInfo div_inf;
390         memset(&div_inf, 0, sizeof div_inf);
391
392         div_inf.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
393         div_inf.image = dimg;
394         div_inf.format = dformat;
395         div_inf.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
396         div_inf.subresourceRange.levelCount = 1;
397         div_inf.subresourceRange.layerCount = 1;
398         div_inf.viewType = VK_IMAGE_VIEW_TYPE_2D;
399
400         if(vkCreateImageView(vk_device, &div_inf, 0, &dview) != VK_SUCCESS) {
401                 fprintf(stderr, "Failed to create image view for depth buffer.\n");
402         }
403
404         return true;
405 }
406
407 void cleanup_vulkan()
408 {
409         vkFreeCommandBuffers(vk_device, vk_pool, vknum_swapchain_images, swapchain_cmd_bufs);
410         if(win) {
411                 glfwDestroyWindow(win);
412         }
413         glfwTerminate();
414
415         //TODOs according to the book:
416         // 1- make sure all threads have been terminated (when I add threads)
417         vku_cleanup();
418 }
419
420 static void error_callback(int error, const char *description)
421 {
422         fprintf(stderr, "GLFW error %d: %s.\n", error, description);
423 }
424
425 static void reshape(int width, int height)
426 {
427         VkSwapchainKHR sc;
428         if(!(sc = vku_create_swapchain(vk_surface, width, height, 2, VK_PRESENT_MODE_FIFO_KHR,
429                                        vk_swapchain))) {
430                 fprintf(stderr, "Failed to create %dx%d double-buffered swapchain\n", width, height);
431                 return;
432         }
433         vk_swapchain = sc;
434
435         delete [] vkswapchain_images;
436         vkswapchain_images = vku_get_swapchain_images(sc, 0);
437         vk_curr_swapchain_image = vku_get_next_image(vk_swapchain);
438 }
439
440 static void clear(float r, float g, float b)
441 {
442 }
443
444 static void viewport(int x, int y, int width, int height)
445 {
446 }
447
448 static void zbuffer(bool enable)
449 {
450 }
451
452 static void cull_face(Gfx_cull_face cf)
453 {
454 }
455
456 static void swapbuffers()
457 {
458 }
459
460 static void begin_drawing()
461 {
462         // if((vk_curr_swapchain_image = vku_get_next_image(vk_swapchain)) == -1) {
463         //      fprintf(stderr, "Failed to get swapchain image. Exiting.\n");
464         //      exit(1);
465         // }
466 }
467
468 static void end_drawing()
469 {
470         /* submit queue */
471
472         // VkSubmitInfo sinf;
473         // memset(&sinf, 0, sizeof sinf);
474         // sinf.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
475         // sinf.waitSemaphoreCount = 1;
476         // sinf.pWaitSemaphores = &vk_img_avail_sema;
477         // sinf.signalSemaphoreCount = 1;
478         // sinf.pSignalSemaphores = &vk_rend_done_sema;
479
480         // // the queue should wait on the semaphore
481
482         // VkPipelineStageFlags wait_flags = VK_PIPELINE_STAGE_TRANSFER_BIT;
483         // sinf.pWaitDstStageMask = &wait_flags;
484         // sinf.commandBufferCount = 1;
485         // sinf.pCommandBuffers = &swapchain_cmd_bufs[vk_curr_swapchain_image];
486
487         // if(vkQueueSubmit(vk_queue, 1, &sinf, VK_NULL_HANDLE) != VK_SUCCESS) {
488         //      fprintf(stderr, "Failed to submit drawing command buffer\n");
489         //      exit(1);
490         // }
491
492         // /* present drawn image */
493         // VkPresentInfoKHR pinf;
494         // memset(&pinf, 0, sizeof pinf);
495         // pinf.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
496         // pinf.waitSemaphoreCount = 1;
497         // pinf.pWaitSemaphores = &vk_rend_done_sema;
498         // pinf.swapchainCount = 1;
499         // pinf.pSwapchains = &vk_swapchain;
500         // pinf.pImageIndices = (uint32_t *)&vk_curr_swapchain_image;
501
502         // if(vkQueuePresentKHR(vk_queue, &pinf) != VK_SUCCESS) {
503         //      fprintf(stderr, "Failed to submit presentation command buffer.\n");
504         //      exit(1);
505         // }
506 }
507
508 static bool record_cmd_clear(float r, float g, float b)
509 {
510 //      VkCommandBufferBeginInfo binf;
511 //      binf.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
512 //      binf.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT;
513
514 //      /* this function must be called outside a renderpass instance */
515 //      const VkClearColorValue pcolor[4] = {r, g, b, 1.0};
516
517 //      VkImageSubresourceRange range;
518 //      memset(&range, 0, sizeof range);
519 //      range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
520 //      range.baseMipLevel = 0;
521 //      range.baseArrayLayer = 0;
522 //      range.layerCount = 1;
523
524 //      for(int i=0; i<vknum_swapchain_images; i++) {
525 //              /* layout for clearing */
526 //              VkImageMemoryBarrier cb;
527 //              memset(&cb, 0, sizeof cb);
528 //              cb.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
529 //              cb.srcAccessMask = VK_ACCESS_MEMORY_READ_BIT;
530 //              cb.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
531 //              cb.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
532 //              cb.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
533 //              cb.srcQueueFamilyIndex = vkqfamily;
534 //              cb.dstQueueFamilyIndex = vkqfamily;
535 //              cb.image = vkswapchain_images[i];
536 //              cb.subresourceRange = range;
537
538 //              /* layout for presenting */
539 //              VkImageMemoryBarrier pb;
540 //              memset(&pb, 0, sizeof pb);
541 //              pb.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
542 //              pb.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
543 //              pb.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT;
544 //              pb.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
545 //              pb.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
546 //              pb.srcQueueFamilyIndex = vkqfamily;
547 //              pb.dstQueueFamilyIndex = vkqfamily;
548 //              pb.image = vkswapchain_images[i];
549 //              pb.subresourceRange = range;
550
551 //              vkBeginCommandBuffer(swapchain_cmd_bufs[i], &binf);
552 //              vkCmdPipelineBarrier(swapchain_cmd_bufs[i], VK_PIPELINE_STAGE_TRANSFER_BIT,
553 //                                   VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, 0, 0, 0, 1, &pb);
554
555 //              vkCmdClearColorImage(swapchain_cmd_bufs[i], vkswapchain_images[vk_curr_swapchain_image], VK_IMAGE_LAYOUT_GENERAL,
556 //                                   pcolor, 1, &range);
557
558 //              vkCmdPipelineBarrier(swapchain_cmd_bufs[i], VK_PIPELINE_STAGE_TRANSFER_BIT,
559 //                                   VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, 0, 0, 0, 1, &cb);
560
561 //              if(vkEndCommandBuffer(swapchain_cmd_bufs[i]) != VK_SUCCESS) {
562 //                      fprintf(stderr, "Failed to record command buffer.\n");
563 //                      return false;
564 //              }
565 //      }
566 //      return true;
567 // }
568
569 // static bool create_swapchain_cmd_bufs(VkCommandPool cpool)
570 // {
571 //      swapchain_cmd_bufs = new VkCommandBuffer[vknum_swapchain_images];
572
573 //      VkCommandBufferAllocateInfo ainf;
574 //      memset(&ainf, 0, sizeof ainf);
575
576 //      ainf.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
577 //      ainf.commandPool = cpool;
578 //      ainf.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
579 //      ainf.commandBufferCount = (uint32_t)vknum_swapchain_images;
580
581 //      if(vkAllocateCommandBuffers(vk_device, &ainf, swapchain_cmd_bufs) != VK_SUCCESS) {
582 //              fprintf(stderr, "Failed to allocate the swapchain command buffers.\n");
583 //              return false;
584 //      }
585
586         return true;
587 }