bind buf memory
[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 //command buffers
25 static VkCommandBuffer init_buf;
26 static VkCommandBuffer rbufs[2];
27 //depth buffer
28 static VkImage dimg;
29 static VkImageView dview;
30 static const VkFormat dformat = VK_FORMAT_D32_SFLOAT_S8_UINT;
31 //swapchain
32 static VkImage *images;
33 static VkImageView *iviews;
34 static uint32_t num_images;
35 //renderpass
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;
41
42
43 /* static variables */
44 static Vec4 clear_color(1, 0.1, 0.1, 1.0);
45
46 /* static functions */
47 static void error_callback(int error, const char *descr);
48 static void clear(float r, float g, float b);
49 static void viewport(int x, int y, int width, int height);
50 static void zbuffer(bool enable);
51 static void cull_face(Gfx_cull_face cf);
52 static void reshape(int width, int height);
53 static void swapbuffers();
54 static void begin_drawing();
55 static void end_drawing();
56
57 static bool create_swapchain(VkSwapchainKHR *sc);
58 static bool create_zbuffer();
59 static bool create_renderpass();
60 static bool create_framebuffers();
61 static bool create_pipelines();
62 static bool begin_init_command_buffer(VkCommandBuffer *cb);
63 static bool end_init_command_buffer(VkCommandBuffer *cb);
64 static bool allocate_rendering_command_buffers(VkCommandBuffer *bufs);
65 static void free_rendering_command_buffers(VkCommandBuffer *bufs, int count);
66 static bool begin_rendering_command_buffers(VkCommandBuffer *bufs, int count);
67
68 bool init_vulkan()
69 {
70         if(!glfwInit()) {
71                 fprintf(stderr, "Failed to initialize GLFW.\n");
72                 return false;
73         }
74
75         if(!glfwVulkanSupported()) {
76                 fprintf(stderr, "No Vulkan support on the device.\n");
77                 return false;
78         }
79
80         //TODO: remove later
81         glfwSetErrorCallback(error_callback);
82
83         /* create device and command pool! */
84         if(!vku_create_device()) {
85                 fprintf(stderr, "Failed to initialize vulkan.\n");
86                 return false;
87         }
88
89         if(!glfwGetPhysicalDevicePresentationSupport(vkinst, vk_physical, vkqfamily)) {
90                 fprintf(stderr, "Presentation support not found.\n");
91                 return false;
92         }
93
94         glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
95         if(!(win = glfwCreateWindow(win_w, win_h, "vkcow", 0, 0))) {
96                 fprintf(stderr, "Failed to create window.\n");
97                 return false;
98         }
99
100         VkResult res = glfwCreateWindowSurface(vkinst, win, 0, &vk_surface);
101         if(res != VK_SUCCESS) {
102                 fprintf(stderr, "Failed to create KHR surface: %s\n", vku_get_vulkan_error_str(res));
103                 return false;
104         }
105
106         if(!create_swapchain(&vk_swapchain)) {
107                 fprintf(stderr, "Failed to create swapchain.\n");
108                 return false;
109         }
110
111         init_buf = VK_NULL_HANDLE;
112         if(!begin_init_command_buffer(&init_buf)) {
113                 fprintf(stderr, "Failed to start VK_NULL_HANDLE command buffer.\n");
114                 return false;
115         }
116
117         if(!create_zbuffer()) {
118                 fprintf(stderr, "Failed to create depth buffer.\n");
119                 return false;
120         }
121
122         if(!create_renderpass()) {
123                 fprintf(stderr, "Failed to create the renderpass.\n");
124                 return false;
125         }
126
127         if(!create_framebuffers()) {
128                 fprintf(stderr, "Failed to create the framebuffer.\n");
129                 return false;
130         }
131
132         if(!create_pipelines()) {
133                 fprintf(stderr, "Failed to create the pipelines.\n");
134                 return false;
135         }
136
137         if(!end_init_command_buffer(&init_buf)) {
138                 fprintf(stderr, "Failed to end the command buffer.\n");
139                 return false;
140         }
141
142         /* rendering command buffers */
143         if(!allocate_rendering_command_buffers(rbufs)) {
144                 fprintf(stderr, "Failed to allocate rendering command buffers.\n");
145                 return false;
146         }
147
148         if(!begin_rendering_command_buffers(rbufs, 2)) {
149                 fprintf(stderr, "Failed to begin rendering command buffers.\n");
150                 return false;
151         }
152
153         gfx_clear = clear;
154         gfx_viewport = viewport;
155         gfx_zbuffer = zbuffer;
156         gfx_cull_face = cull_face;
157         gfx_reshape = reshape;
158         gfx_swapbuffers = swapbuffers;
159         gfx_begin_drawing = begin_drawing;
160         gfx_end_drawing = end_drawing;
161
162         return true;
163 }
164
165 static bool create_swapchain(VkSwapchainKHR *sc)
166 {
167         /* surface capabilities */
168         VkSurfaceCapabilitiesKHR scap;
169         if(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(vk_physical, vk_surface, &scap) != VK_SUCCESS) {
170                 fprintf(stderr, "Failed to get physical device surface capabilities\n");
171                 return false;
172         }
173
174         /* presentation modes */
175         uint32_t prmode_cnt;
176         if(vkGetPhysicalDeviceSurfacePresentModesKHR(vk_physical, vk_surface, &prmode_cnt, 0) != VK_SUCCESS) {
177                 fprintf(stderr, "Failed to get physical device surface presentation modes count.\n");
178                 return false;
179         }
180
181         if(prmode_cnt == 0) {
182                 fprintf(stderr, "Presentation modes not found.\n");
183                 return false;
184         }
185
186         VkPresentModeKHR scmode = VK_PRESENT_MODE_FIFO_KHR;
187         VkPresentModeKHR *modes = new VkPresentModeKHR[prmode_cnt];
188
189         if(vkGetPhysicalDeviceSurfacePresentModesKHR(vk_physical, vk_surface, &prmode_cnt, modes) != VK_SUCCESS) {
190                 fprintf(stderr, "Failed to get physical device presentation modes.\n");
191                 return false;
192         }
193
194         for(uint32_t i=0; i<prmode_cnt; i++) {
195                 if(modes[i] == VK_PRESENT_MODE_MAILBOX_KHR) {
196                         scmode = VK_PRESENT_MODE_MAILBOX_KHR;
197                         break;
198                 }
199                 if((scmode != VK_PRESENT_MODE_MAILBOX_KHR) && (modes[i] == VK_PRESENT_MODE_IMMEDIATE_KHR)) {
200                         //fallback
201                         scmode = VK_PRESENT_MODE_IMMEDIATE_KHR;
202                 }
203         }
204
205         /* swapchain extents */
206         VkExtent2D scextent;
207         if(scap.currentExtent.width == 0xffffffff || scap.currentExtent.height == 0xffffffff) {
208                 scextent.width = win_w;
209                 scextent.height = win_h;
210         }
211         else {
212                 scextent = scap.currentExtent;
213                 win_w = scextent.width;
214                 win_h = scextent.height;
215         }
216
217         /* number of swapchain images (on intel that's 3: maybe should hardcode it to 2?) */
218         num_images = scap.minImageCount; //+ 1;
219         /* intel doesn't set the maxImageCount */
220         if(scap.maxImageCount > 0 && num_images > scap.maxImageCount)
221                 num_images = scap.maxImageCount;
222
223         printf("num_images : %u\n", num_images);
224         assert(num_images > 0);
225
226         images = new VkImage[num_images];
227         iviews = new VkImageView[num_images];
228
229         /* transform flags */
230         VkSurfaceTransformFlagBitsKHR pre_transf = scap.currentTransform;
231         if(scap.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR)
232                 pre_transf = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
233
234         /* find suitable colorspace, format */
235         VkFormat format;
236         VkColorSpaceKHR colorspace;
237
238         VkSurfaceFormatKHR sformat;
239         if(!vku_get_surface_format(vk_physical, vk_surface, &sformat)) {
240                 return false;
241         }
242
243         format = sformat.format;
244         colorspace = sformat.colorSpace;
245
246         /* creating the swapchain */
247         VkSwapchainCreateInfoKHR sinfo;
248         memset(&sinfo, 0, sizeof sinfo);
249
250         sinfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
251         sinfo.surface = vk_surface;
252         sinfo.minImageCount = num_images;
253         sinfo.imageFormat = format;
254         sinfo.imageColorSpace = colorspace;
255         sinfo.imageExtent = scextent;
256         sinfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
257         sinfo.preTransform = pre_transf;
258         sinfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
259         sinfo.imageArrayLayers = 1;
260         sinfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
261         sinfo.presentMode = scmode;
262         sinfo.oldSwapchain = VK_NULL_HANDLE; //TODO
263         sinfo.clipped = VK_TRUE; //TODO
264
265         if(vkCreateSwapchainKHR(vk_device, &sinfo, 0, sc) != VK_SUCCESS) {
266                 fprintf(stderr, "Failed to create swapchain.\n");
267                 return false;
268         }
269
270         if(vkGetSwapchainImagesKHR(vk_device, *sc, &num_images, 0) != VK_SUCCESS) {
271                 fprintf(stderr, "Failed to get the number of the swapchain images.\n");
272                 return false;
273         }
274
275         if(vkGetSwapchainImagesKHR(vk_device, *sc, &num_images, images) != VK_SUCCESS) {
276                 fprintf(stderr, "Failed to get the swapchain images.\n");
277                 return false;
278         }
279
280         VkImageViewCreateInfo ivinf;
281         memset(&ivinf, 0, sizeof ivinf);
282         ivinf.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
283         ivinf.format = format;
284         ivinf.components = {
285                 VK_COMPONENT_SWIZZLE_R,
286                 VK_COMPONENT_SWIZZLE_G,
287                 VK_COMPONENT_SWIZZLE_B,
288                 VK_COMPONENT_SWIZZLE_A
289         };
290         ivinf.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
291         ivinf.subresourceRange.levelCount = 1;
292         ivinf.subresourceRange.layerCount = 1;
293         ivinf.viewType = VK_IMAGE_VIEW_TYPE_2D;
294
295         for(uint32_t i=0; i<num_images; i++) {
296                 ivinf.image = images[i];
297
298                 VkResult res;
299                 if((res = vkCreateImageView(vk_device, &ivinf, 0, &iviews[i])) != VK_SUCCESS) {
300                         fprintf(stderr, "Failed to create image view %d: %s.\n", i, vku_get_vulkan_error_str(res));
301                         return false;
302                 }
303         }
304
305         return true;
306 }
307
308 static bool begin_init_command_buffer(VkCommandBuffer *cb)
309 {
310         if(*cb == VK_NULL_HANDLE) {
311                 *cb = vku_alloc_cmdbuf(vk_pool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
312
313                 VkCommandBufferInheritanceInfo ciinf;
314                 memset(&ciinf, 0, sizeof ciinf);
315                 ciinf.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
316                 ciinf.renderPass = VK_NULL_HANDLE;
317                 ciinf.framebuffer = VK_NULL_HANDLE;
318                 ciinf.occlusionQueryEnable = VK_FALSE;
319
320                 VkCommandBufferBeginInfo cbinf;
321                 memset(&cbinf, 0, sizeof cbinf);
322                 cbinf.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
323                 cbinf.pInheritanceInfo = &ciinf;
324
325                 if(vkBeginCommandBuffer(*cb, &cbinf) != VK_SUCCESS) {
326                         fprintf(stderr, "Failed to begin command buffer.\n");
327                         return false;
328                 }
329         }
330         return true;
331 }
332
333 static bool create_zbuffer()
334 {
335         VkImageCreateInfo dinfo;
336         memset(&dinfo, 0, sizeof dinfo);
337
338         dinfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
339         dinfo.imageType = VK_IMAGE_TYPE_2D;
340         dinfo.format = dformat;
341         dinfo.extent = {(uint32_t)win_w, (uint32_t)win_h, 1};
342         dinfo.mipLevels = 1;
343         dinfo.arrayLayers = 1;
344         dinfo.samples = VK_SAMPLE_COUNT_1_BIT;
345         dinfo.tiling = VK_IMAGE_TILING_OPTIMAL;
346         dinfo.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
347
348         if(vkCreateImage(vk_device, &dinfo, 0, &dimg) != VK_SUCCESS) {
349                 fprintf(stderr, "Failed to create depth buffer image.\n");
350                 return false;
351         }
352
353         VkMemoryRequirements dmem_reqs;
354         vkGetImageMemoryRequirements(vk_device, dimg, &dmem_reqs);
355
356         DevMemBlock block;
357         if(!vku_allocate(dmem_reqs.size, &block)) {
358                 fprintf(stderr, "Failed to allocate zbuffer image.\n");
359                 return false;
360         }
361
362         vkBindImageMemory(vk_device, dimg, block.dev_mem, 0);
363
364         if(!vk_image_set_layout(init_buf, dimg, VK_IMAGE_ASPECT_DEPTH_BIT,
365                                 VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
366                                 (VkAccessFlagBits)0)) {
367                 fprintf(stderr, "Failed to set depth buffer layout.\n");
368                 return false;
369         }
370
371         VkImageViewCreateInfo div_inf;
372         memset(&div_inf, 0, sizeof div_inf);
373
374         div_inf.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
375         div_inf.image = dimg;
376         div_inf.format = dformat;
377         div_inf.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
378         div_inf.subresourceRange.levelCount = 1;
379         div_inf.subresourceRange.layerCount = 1;
380         div_inf.viewType = VK_IMAGE_VIEW_TYPE_2D;
381
382         if(vkCreateImageView(vk_device, &div_inf, 0, &dview) != VK_SUCCESS) {
383                 fprintf(stderr, "Failed to create image view for depth buffer.\n");
384                 return false;
385         }
386
387         return true;
388 }
389
390 static bool create_renderpass()
391 {
392         VkSurfaceFormatKHR sformat;
393         if(!vku_get_surface_format(vk_physical, vk_surface, &sformat)) {
394                 fprintf(stderr, "Failed to get surface format.\n");
395                 return false;
396         }
397
398         VkAttachmentDescription att[2];
399         memset(&att, 0, (sizeof att[0]) * 2);
400
401         att[0].format = sformat.format;
402         att[0].samples = VK_SAMPLE_COUNT_1_BIT;
403         att[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
404         att[0].storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
405         att[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
406         att[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
407         att[0].initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
408         att[0].finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
409
410         att[1].format = dformat;
411         att[1].samples = VK_SAMPLE_COUNT_1_BIT;
412         att[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
413         att[1].storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
414         att[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
415         att[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
416         att[1].initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
417         att[1].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
418
419         VkAttachmentReference cref;
420         memset(&cref, 0, sizeof cref);
421         cref.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
422
423         VkAttachmentReference dref;
424         memset(&dref, 0, sizeof dref);
425         dref.attachment = 1;
426         dref.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
427
428         VkSubpassDescription sd;
429         memset(&sd, 0, sizeof sd);
430         sd.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
431         sd.colorAttachmentCount = 1;
432         sd.pColorAttachments = &cref;
433         sd.pDepthStencilAttachment = &dref;
434
435         VkRenderPassCreateInfo rinf;
436         memset(&rinf, 0, sizeof rinf);
437         rinf.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
438         rinf.attachmentCount = 2;
439         rinf.pAttachments = att;
440         rinf.subpassCount = 1;
441         rinf.pSubpasses = &sd;
442
443         if(vkCreateRenderPass(vk_device, &rinf, 0, &rpass) != VK_SUCCESS) {
444                 fprintf(stderr, "Failed to create rpass.\n");
445                 return false;
446         }
447
448         return true;
449 }
450
451 static bool create_framebuffers()
452 {
453         /* framebuffer attachments */
454         VkImageView fb_att[2];
455         fb_att[1] = dview;
456
457         VkFramebufferCreateInfo fbinf;
458         memset(&fbinf, 0, sizeof fbinf);
459         fbinf.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
460         fbinf.renderPass = rpass;
461         fbinf.attachmentCount = 2;
462         fbinf.pAttachments = fb_att;
463         fbinf.width = win_w;
464         fbinf.height = win_h;
465         fbinf.layers = 1;
466
467         for(int i=0; i<2; i++) {
468                 fb_att[0] = iviews[i];
469                 if(vkCreateFramebuffer(vk_device, &fbinf, 0, &fbs[i]) != VK_SUCCESS) {
470                         fprintf(stderr, "Failed to create framebuffer %i\n", i);
471                         return false;
472                 }
473         }
474         return true;
475 }
476
477 static bool create_pipelines()
478 {
479         VkDescriptorSetLayoutBinding dslb[1];
480         memset(&dslb[0], 0, sizeof dslb[0]);
481         dslb[0].binding = 0;
482         dslb[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
483         dslb[0].descriptorCount = 1;
484         dslb[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
485
486         VkDescriptorSetLayoutCreateInfo dslinf;
487         memset(&dslinf, 0, sizeof dslinf);
488         dslinf.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
489         dslinf.bindingCount = 1; //dslb.size();
490         dslinf.pBindings = dslb;
491
492         VkDescriptorSetLayout dsl;
493         if(vkCreateDescriptorSetLayout(vk_device, &dslinf, 0, &dsl) != VK_SUCCESS) {
494                 fprintf(stderr, "Failed to create descriptor set layout.\n");
495                 return false;
496         }
497
498         VkPipelineLayoutCreateInfo pinf;
499         memset(&pinf, 0, sizeof pinf);
500         pinf.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
501         pinf.setLayoutCount = 1;
502         pinf.pSetLayouts = &dsl;
503
504         VkPipelineLayout pl;
505         if(vkCreatePipelineLayout(vk_device, &pinf, 0, &pl) != VK_SUCCESS) {
506                 fprintf(stderr, "Failed to create pipeline layout.\n");
507                 return false;
508         }
509
510         VkPipelineCacheCreateInfo pcinf;
511         memset(&pcinf, 0, sizeof pcinf);
512         pcinf.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;
513
514         VkPipelineCache pcache;
515         if(vkCreatePipelineCache(vk_device, &pcinf, 0, &pcache) != VK_SUCCESS) {
516                 fprintf(stderr, "Failed to create pipeline cache.\n");
517                 return false;
518         }
519
520         VkGraphicsPipelineCreateInfo ginf;
521         memset(&ginf, 0, sizeof ginf);
522         ginf.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
523         ginf.stageCount = 2;
524
525         return true;
526 }
527
528 static bool end_init_command_buffer(VkCommandBuffer *cb)
529 {
530         if(vkEndCommandBuffer(*cb) != VK_SUCCESS) {
531                 fprintf(stderr, "Failed to end command buffer.\n");
532                 return false;
533         }
534
535         VkSubmitInfo si;
536         memset(&si, 0, sizeof si);
537         si.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
538         si.commandBufferCount = 1;
539         si.pCommandBuffers = cb;
540
541         if(vkQueueSubmit(vk_queue, 1, &si, VK_NULL_HANDLE) != VK_SUCCESS) {
542                 fprintf(stderr, "Failed to submit null queue.\n");
543                 return false;
544         }
545
546         if(vkQueueWaitIdle(vk_queue) != VK_SUCCESS) {
547                 fprintf(stderr, "QueueWaitIdle failure!\n");
548                 return false;
549         }
550
551         vkFreeCommandBuffers(vk_device, vk_pool, 1, cb);
552         *cb = VK_NULL_HANDLE;
553
554         return true;
555 }
556
557 static bool allocate_rendering_command_buffers(VkCommandBuffer *bufs)
558 {
559         return vku_alloc_cmdbufs(vk_pool, VK_COMMAND_BUFFER_LEVEL_PRIMARY,
560                                  2, bufs);
561 }
562
563 static void free_rendering_command_buffers(VkCommandBuffer *bufs, int count)
564 {
565         for(int i=0; i<count; i++) {
566                 vku_free_cmdbuf(vk_pool, bufs[i]);
567         }
568 }
569
570 static bool begin_rendering_command_buffers(VkCommandBuffer *bufs, int count)
571 {
572         VkCommandBufferInheritanceInfo iinf;
573         memset(&iinf, 0, sizeof iinf);
574         iinf.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
575         iinf.renderPass = VK_NULL_HANDLE;
576         iinf.framebuffer = VK_NULL_HANDLE;
577
578         VkCommandBufferBeginInfo binf;
579         memset(&binf, 0, sizeof binf);
580         binf.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
581         binf.pInheritanceInfo = &iinf;
582
583         // setting clear values
584         VkClearValue clvals[2];
585         for(int i=0; i<4; i++) {
586                 clvals[0].color.float32[i] = clear_color[i];
587         }
588         clvals[1].depthStencil = {1.0f, 0};
589
590         //build drawing command buffers
591         for(int i=0; i<count; i++) {
592                 if(vkBeginCommandBuffer(bufs[i], &binf) != VK_SUCCESS) {
593                         fprintf(stderr, "Failed to begin command buffer: %d\n", i);
594                         return false;
595                 }
596
597                 VkImageMemoryBarrier imbarr;
598                 memset(&imbarr, 0, sizeof imbarr);
599                 imbarr.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
600                 imbarr.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
601                 imbarr.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
602                 imbarr.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
603                 imbarr.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
604                 imbarr.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
605                 imbarr.image = images[i];
606                 imbarr.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
607                 vkCmdPipelineBarrier(bufs[i], VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, 0, 0, 0, 1, &imbarr);
608
609                 VkRenderPassBeginInfo rbinf;
610                 memset(&rbinf, 0, sizeof rbinf);
611                 rbinf.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
612                 rbinf.renderPass = rpass;
613                 rbinf.framebuffer = fbs[i];
614                 rbinf.renderArea.extent.width = win_w;
615                 rbinf.renderArea.extent.height = win_h;
616                 rbinf.clearValueCount = count;
617                 rbinf.pClearValues = clvals;
618
619                 vkCmdBeginRenderPass(bufs[i], &rbinf, VK_SUBPASS_CONTENTS_INLINE);
620                 VkViewport viewport;
621                 memset(&viewport, 0, sizeof viewport);
622                 viewport.width = (float)win_w;
623                 viewport.height = (float)win_h;
624                 viewport.maxDepth = 1.0f;
625                 vkCmdSetViewport(bufs[i], 0, 1, &viewport);
626
627                 VkRect2D scissor;
628                 memset(&scissor, 0, sizeof scissor);
629                 scissor.extent.width = win_w;
630                 scissor.extent.height = win_h;
631                 vkCmdSetScissor(bufs[i], 0, 1, &scissor);
632                 vkCmdEndRenderPass(bufs[i]);
633
634                 /* pre-present barrier */
635                 VkImageMemoryBarrier ppb;
636                 memset(&ppb, 0, sizeof ppb);
637                 ppb.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
638                 ppb.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
639                 ppb.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT;
640                 ppb.oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
641                 ppb.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
642                 ppb.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
643                 ppb.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
644                 ppb.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
645                 ppb.image = images[i];
646
647                 vkCmdPipelineBarrier(bufs[i], VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, 0, 0, 0, 1, &ppb);
648
649                 if(vkEndCommandBuffer(bufs[i]) != VK_SUCCESS) {
650                         fprintf(stderr, "Failed to end command buffer: %d\n", i);
651                         return false;
652                 }
653         }
654         return true;
655 }
656
657 void cleanup_vulkan()
658 {
659         free_rendering_command_buffers(rbufs, 2);
660         if(win) {
661                 glfwDestroyWindow(win);
662         }
663         glfwTerminate();
664
665         //TODOs according to the book:
666         // 1- make sure all threads have been terminated (when I add threads)
667         vku_cleanup();
668 }
669
670 static void error_callback(int error, const char *description)
671 {
672         fprintf(stderr, "GLFW error %d: %s.\n", error, description);
673 }
674
675 static void reshape(int width, int height)
676 {
677 }
678
679 static void clear(float r, float g, float b)
680 {
681 }
682
683 static void viewport(int x, int y, int width, int height)
684 {
685 }
686
687 static void zbuffer(bool enable)
688 {
689 }
690
691 static void cull_face(Gfx_cull_face cf)
692 {
693 }
694
695 static void swapbuffers()
696 {
697 }
698
699 static void begin_drawing()
700 {
701         VkSemaphoreCreateInfo psinf;
702         memset(&psinf, 0, sizeof psinf);
703         psinf.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
704
705         VkResult res;
706         if((res = vkCreateSemaphore(vk_device, &psinf, 0, &psema)) != VK_SUCCESS) {
707                 fprintf(stderr, "Failed to create semaphore.\n");
708         }
709         assert(res == VK_SUCCESS);
710 }
711
712 static void end_drawing()
713 {
714         VkResult res = vkAcquireNextImageKHR(vk_device, vk_swapchain,
715                                              UINT64_MAX, psema, VK_NULL_HANDLE, &curr_img);
716         if(res == VK_ERROR_OUT_OF_DATE_KHR) {
717                 fprintf(stderr, "Swapchain out of date.\n");
718                 return;
719         }
720         assert(res == VK_SUCCESS);
721
722         VkSubmitInfo sinf;
723         memset(&sinf, 0, sizeof sinf);
724         VkPipelineStageFlags psflags = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
725         sinf.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
726         sinf.waitSemaphoreCount = 1;
727         sinf.pWaitSemaphores = &psema;
728         sinf.pWaitDstStageMask = &psflags;
729         sinf.commandBufferCount = 1;
730         sinf.pCommandBuffers = &rbufs[curr_img];
731
732         res = vkQueueSubmit(vk_queue, 1, &sinf, VK_NULL_HANDLE);
733         assert(res == VK_SUCCESS);
734
735         VkPresentInfoKHR pinf;
736         memset(&pinf, 0, sizeof pinf);
737         pinf.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
738         pinf.swapchainCount = 1;
739         pinf.pSwapchains = &vk_swapchain;
740         pinf.pImageIndices = &curr_img;
741
742         res = vkQueuePresentKHR(vk_queue, &pinf);
743         if(res == VK_ERROR_OUT_OF_DATE_KHR) {
744                 fprintf(stderr, "Swapchain out of date.\n");
745         }
746         assert(res == VK_SUCCESS);
747
748         res = vkQueueWaitIdle(vk_queue);
749         assert(res == VK_SUCCESS);
750
751         vkDestroySemaphore(vk_device, psema, 0);
752 }