8ddea099f798d508de95fdd547121770493c2584
[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 /* static variables */
43 static Vec4 clear_color(1, 0.1, 0.1, 1.0);
44
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();
55
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);
65
66 bool init_vulkan()
67 {
68         if(!glfwInit()) {
69                 fprintf(stderr, "Failed to initialize GLFW.\n");
70                 return false;
71         }
72
73         if(!glfwVulkanSupported()) {
74                 fprintf(stderr, "No Vulkan support on the device.\n");
75                 return false;
76         }
77
78         //TODO: remove later
79         glfwSetErrorCallback(error_callback);
80
81         /* create device and command pool! */
82         if(!vku_create_device()) {
83                 fprintf(stderr, "Failed to initialize vulkan.\n");
84                 return false;
85         }
86
87         if(!glfwGetPhysicalDevicePresentationSupport(vk_instance, vk_physical, vk_qfamily)) {
88                 fprintf(stderr, "Presentation support not found.\n");
89                 return false;
90         }
91
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");
95                 return false;
96         }
97
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));
101                 return false;
102         }
103
104         if(!create_swapchain(&vk_swapchain)) {
105                 fprintf(stderr, "Failed to create swapchain.\n");
106                 return false;
107         }
108
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");
112                 return false;
113         }
114
115         if(!create_zbuffer()) {
116                 fprintf(stderr, "Failed to create depth buffer.\n");
117                 return false;
118         }
119
120         if(!create_renderpass()) {
121                 fprintf(stderr, "Failed to create the renderpass.\n");
122                 return false;
123         }
124
125         if(!create_framebuffers()) {
126                 fprintf(stderr, "Failed to create the framebuffer.\n");
127                 return false;
128         }
129
130         if(!end_init_command_buffer(&init_buf)) {
131                 fprintf(stderr, "Failed to end the command buffer.\n");
132                 return false;
133         }
134
135         /* rendering command buffers */
136         if(!allocate_rendering_command_buffers(rbufs)) {
137                 fprintf(stderr, "Failed to allocate rendering command buffers.\n");
138                 return false;
139         }
140
141         if(!begin_rendering_command_buffers(rbufs, 2)) {
142                 fprintf(stderr, "Failed to begin rendering command buffers.\n");
143                 return false;
144         }
145
146         gfx_clear = clear;
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;
154
155         return true;
156 }
157
158 static bool create_swapchain(VkSwapchainKHR *sc)
159 {
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");
164                 return false;
165         }
166
167         /* presentation modes */
168         uint32_t prmode_cnt;
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");
171                 return false;
172         }
173
174         if(prmode_cnt == 0) {
175                 fprintf(stderr, "Presentation modes not found.\n");
176                 return false;
177         }
178
179         VkPresentModeKHR scmode = VK_PRESENT_MODE_FIFO_KHR;
180         VkPresentModeKHR *modes = new VkPresentModeKHR[prmode_cnt];
181
182         if(vkGetPhysicalDeviceSurfacePresentModesKHR(vk_physical, vk_surface, &prmode_cnt, modes) != VK_SUCCESS) {
183                 fprintf(stderr, "Failed to get physical device presentation modes.\n");
184                 return false;
185         }
186
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;
190                         break;
191                 }
192                 if((scmode != VK_PRESENT_MODE_MAILBOX_KHR) && (modes[i] == VK_PRESENT_MODE_IMMEDIATE_KHR)) {
193                         //fallback
194                         scmode = VK_PRESENT_MODE_IMMEDIATE_KHR;
195                 }
196         }
197
198         /* swapchain extents */
199         VkExtent2D scextent;
200         if(scap.currentExtent.width == 0xffffffff || scap.currentExtent.height == 0xffffffff) {
201                 scextent.width = win_w;
202                 scextent.height = win_h;
203         }
204         else {
205                 scextent = scap.currentExtent;
206                 win_w = scextent.width;
207                 win_h = scextent.height;
208         }
209
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;
215
216         printf("num_images : %u\n", num_images);
217         assert(num_images > 0);
218
219         images = new VkImage[num_images];
220         iviews = new VkImageView[num_images];
221
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;
226
227         /* find suitable colorspace, format */
228         VkFormat format;
229         VkColorSpaceKHR colorspace;
230
231         VkSurfaceFormatKHR sformat;
232         if(!vku_get_surface_format(vk_physical, vk_surface, &sformat)) {
233                 return false;
234         }
235
236         format = sformat.format;
237         colorspace = sformat.colorSpace;
238
239         /* creating the swapchain */
240         VkSwapchainCreateInfoKHR sinfo;
241         memset(&sinfo, 0, sizeof sinfo);
242
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
257
258         if(vkCreateSwapchainKHR(vk_device, &sinfo, 0, sc) != VK_SUCCESS) {
259                 fprintf(stderr, "Failed to create swapchain.\n");
260                 return false;
261         }
262
263         if(vkGetSwapchainImagesKHR(vk_device, *sc, &num_images, 0) != VK_SUCCESS) {
264                 fprintf(stderr, "Failed to get the number of the swapchain images.\n");
265                 return false;
266         }
267
268         if(vkGetSwapchainImagesKHR(vk_device, *sc, &num_images, images) != VK_SUCCESS) {
269                 fprintf(stderr, "Failed to get the swapchain images.\n");
270                 return false;
271         }
272
273         VkImageViewCreateInfo ivinf;
274         memset(&ivinf, 0, sizeof ivinf);
275         ivinf.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
276         ivinf.format = format;
277         ivinf.components = {
278                 VK_COMPONENT_SWIZZLE_R,
279                 VK_COMPONENT_SWIZZLE_G,
280                 VK_COMPONENT_SWIZZLE_B,
281                 VK_COMPONENT_SWIZZLE_A
282         };
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;
287
288         for(uint32_t i=0; i<num_images; i++) {
289                 ivinf.image = images[i];
290
291                 VkResult res;
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));
294                         return false;
295                 }
296         }
297
298         return true;
299 }
300
301 static bool begin_init_command_buffer(VkCommandBuffer *cb)
302 {
303         if(*cb == VK_NULL_HANDLE) {
304                 *cb = vku_alloc_cmdbuf(vk_pool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
305
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;
312
313                 VkCommandBufferBeginInfo cbinf;
314                 memset(&cbinf, 0, sizeof cbinf);
315                 cbinf.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
316                 cbinf.pInheritanceInfo = &ciinf;
317
318                 if(vkBeginCommandBuffer(*cb, &cbinf) != VK_SUCCESS) {
319                         fprintf(stderr, "Failed to begin command buffer.\n");
320                         return false;
321                 }
322         }
323         return true;
324 }
325
326 static bool create_zbuffer()
327 {
328         VkImageCreateInfo dinfo;
329         memset(&dinfo, 0, sizeof dinfo);
330
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};
335         dinfo.mipLevels = 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;
340
341         if(vkCreateImage(vk_device, &dinfo, 0, &dimg) != VK_SUCCESS) {
342                 fprintf(stderr, "Failed to create depth buffer image.\n");
343                 return false;
344         }
345
346         VkMemoryRequirements dmem_reqs;
347         vkGetImageMemoryRequirements(vk_device, dimg, &dmem_reqs);
348
349         DevMemBlock block;
350         if(!vku_allocate(dmem_reqs.size, &block)) {
351                 fprintf(stderr, "Failed to allocate zbuffer image.\n");
352                 return false;
353         }
354
355         vkBindImageMemory(vk_device, dimg, block.dev_mem, 0);
356
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");
361                 return false;
362         }
363
364         VkImageViewCreateInfo div_inf;
365         memset(&div_inf, 0, sizeof div_inf);
366
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;
374
375         if(vkCreateImageView(vk_device, &div_inf, 0, &dview) != VK_SUCCESS) {
376                 fprintf(stderr, "Failed to create image view for depth buffer.\n");
377                 return false;
378         }
379
380         return true;
381 }
382
383 static bool create_renderpass()
384 {
385         VkSurfaceFormatKHR sformat;
386         if(!vku_get_surface_format(vk_physical, vk_surface, &sformat)) {
387                 fprintf(stderr, "Failed to get surface format.\n");
388                 return false;
389         }
390
391         VkAttachmentDescription att[2];
392         memset(&att, 0, (sizeof att[0]) * 2);
393
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;
402
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;
411
412         VkAttachmentReference cref;
413         memset(&cref, 0, sizeof cref);
414         cref.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
415
416         VkAttachmentReference dref;
417         memset(&dref, 0, sizeof dref);
418         dref.attachment = 1;
419         dref.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
420
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;
427
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;
435
436         if(vkCreateRenderPass(vk_device, &rinf, 0, &rpass) != VK_SUCCESS) {
437                 fprintf(stderr, "Failed to create rpass.\n");
438                 return false;
439         }
440
441         return true;
442 }
443
444 static bool create_framebuffers()
445 {
446         /* framebuffer attachments */
447         VkImageView fb_att[2];
448         fb_att[1] = dview;
449
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;
456         fbinf.width = win_w;
457         fbinf.height = win_h;
458         fbinf.layers = 1;
459
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);
464                         return false;
465                 }
466         }
467         return true;
468 }
469
470 static bool end_init_command_buffer(VkCommandBuffer *cb)
471 {
472         if(vkEndCommandBuffer(*cb) != VK_SUCCESS) {
473                 fprintf(stderr, "Failed to end command buffer.\n");
474                 return false;
475         }
476
477         VkSubmitInfo si;
478         memset(&si, 0, sizeof si);
479         si.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
480         si.commandBufferCount = 1;
481         si.pCommandBuffers = cb;
482
483         if(vkQueueSubmit(vk_queue, 1, &si, VK_NULL_HANDLE) != VK_SUCCESS) {
484                 fprintf(stderr, "Failed to submit null queue.\n");
485                 return false;
486         }
487
488         if(vkQueueWaitIdle(vk_queue) != VK_SUCCESS) {
489                 fprintf(stderr, "QueueWaitIdle failure!\n");
490                 return false;
491         }
492
493         vkFreeCommandBuffers(vk_device, vk_pool, 1, cb);
494         *cb = VK_NULL_HANDLE;
495
496         return true;
497 }
498
499 static bool allocate_rendering_command_buffers(VkCommandBuffer *bufs)
500 {
501         return vku_alloc_cmdbufs(vk_pool, VK_COMMAND_BUFFER_LEVEL_PRIMARY,
502                                  2, bufs);
503 }
504
505 static void free_rendering_command_buffers(VkCommandBuffer *bufs, int count)
506 {
507         for(int i=0; i<count; i++) {
508                 vku_free_cmdbuf(vk_pool, bufs[i]);
509         }
510 }
511
512 static bool begin_rendering_command_buffers(VkCommandBuffer *bufs, int count)
513 {
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;
519
520         VkCommandBufferBeginInfo binf;
521         memset(&binf, 0, sizeof binf);
522         binf.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
523         binf.pInheritanceInfo = &iinf;
524
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];
529         }
530         clvals[1].depthStencil = {1.0f, 0};
531
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);
536                         return false;
537                 }
538
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);
550
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;
560
561                 vkCmdBeginRenderPass(bufs[i], &rbinf, VK_SUBPASS_CONTENTS_INLINE);
562                 VkViewport viewport;
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);
568
569                 VkRect2D scissor;
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]);
575
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];
588
589                 vkCmdPipelineBarrier(bufs[i], VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, 0, 0, 0, 1, &ppb);
590
591                 if(vkEndCommandBuffer(bufs[i]) != VK_SUCCESS) {
592                         fprintf(stderr, "Failed to end command buffer: %d\n", i);
593                         return false;
594                 }
595         }
596         return true;
597 }
598
599 void cleanup_vulkan()
600 {
601         free_rendering_command_buffers(rbufs, 2);
602         if(win) {
603                 glfwDestroyWindow(win);
604         }
605         glfwTerminate();
606
607         //TODOs according to the book:
608         // 1- make sure all threads have been terminated (when I add threads)
609         vku_cleanup();
610 }
611
612 static void error_callback(int error, const char *description)
613 {
614         fprintf(stderr, "GLFW error %d: %s.\n", error, description);
615 }
616
617 static void reshape(int width, int height)
618 {
619 }
620
621 static void clear(float r, float g, float b)
622 {
623 }
624
625 static void viewport(int x, int y, int width, int height)
626 {
627 }
628
629 static void zbuffer(bool enable)
630 {
631 }
632
633 static void cull_face(Gfx_cull_face cf)
634 {
635 }
636
637 static void swapbuffers()
638 {
639 }
640
641 static void begin_drawing()
642 {
643         VkSemaphoreCreateInfo psinf;
644         memset(&psinf, 0, sizeof psinf);
645         psinf.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
646
647         VkResult res;
648         if((res = vkCreateSemaphore(vk_device, &psinf, 0, &psema)) != VK_SUCCESS) {
649                 fprintf(stderr, "Failed to create semaphore.\n");
650         }
651         assert(res == VK_SUCCESS);
652 }
653
654 static void end_drawing()
655 {
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");
660                 return;
661         }
662         assert(res == VK_SUCCESS);
663
664         VkSubmitInfo sinf;
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];
673
674         res = vkQueueSubmit(vk_queue, 1, &sinf, VK_NULL_HANDLE);
675         assert(res == VK_SUCCESS);
676
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;
683
684         res = vkQueuePresentKHR(vk_queue, &pinf);
685         if(res == VK_ERROR_OUT_OF_DATE_KHR) {
686                 fprintf(stderr, "Swapchain out of date.\n");
687         }
688         assert(res == VK_SUCCESS);
689
690         res = vkQueueWaitIdle(vk_queue);
691         assert(res == VK_SUCCESS);
692
693         vkDestroySemaphore(vk_device, psema, 0);
694 }