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