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