a0f77514c47ed568dbf8793b9fde1ce1a7a9b8da
[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 create_zbuffer();
60 static bool create_renderpass();
61 static bool create_framebuffers();
62 static bool create_pipelines();
63 static bool begin_init_command_buffer(VkCommandBuffer *cb);
64 static bool end_init_command_buffer(VkCommandBuffer *cb);
65 static bool allocate_rendering_command_buffers(VkCommandBuffer *bufs);
66 static void free_rendering_command_buffers(VkCommandBuffer *bufs, int count);
67 static bool begin_rendering_command_buffers(VkCommandBuffer *bufs, int count);
68
69 bool init_vulkan()
70 {
71         if(!glfwInit()) {
72                 fprintf(stderr, "Failed to initialize GLFW.\n");
73                 return false;
74         }
75
76         if(!glfwVulkanSupported()) {
77                 fprintf(stderr, "No Vulkan support on the device.\n");
78                 return false;
79         }
80
81         //TODO: remove later
82         glfwSetErrorCallback(error_callback);
83
84         /* create device and command pool! */
85         if(!vku_create_device()) {
86                 fprintf(stderr, "Failed to initialize vulkan.\n");
87                 return false;
88         }
89
90         if(!glfwGetPhysicalDevicePresentationSupport(vkinst, vk_physical, vkqfamily)) {
91                 fprintf(stderr, "Presentation support not found.\n");
92                 return false;
93         }
94
95         glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
96         if(!(win = glfwCreateWindow(win_w, win_h, "vkcow", 0, 0))) {
97                 fprintf(stderr, "Failed to create window.\n");
98                 return false;
99         }
100
101         VkResult res = glfwCreateWindowSurface(vkinst, win, 0, &vk_surface);
102         if(res != VK_SUCCESS) {
103                 fprintf(stderr, "Failed to create KHR surface: %s\n", vku_get_vulkan_error_str(res));
104                 return false;
105         }
106
107         if(!create_swapchain(&vk_swapchain)) {
108                 fprintf(stderr, "Failed to create swapchain.\n");
109                 return false;
110         }
111
112         init_buf = VK_NULL_HANDLE;
113         if(!begin_init_command_buffer(&init_buf)) {
114                 fprintf(stderr, "Failed to start VK_NULL_HANDLE command buffer.\n");
115                 return false;
116         }
117
118         if(!create_zbuffer()) {
119                 fprintf(stderr, "Failed to create depth buffer.\n");
120                 return false;
121         }
122
123         if(!create_renderpass()) {
124                 fprintf(stderr, "Failed to create the renderpass.\n");
125                 return false;
126         }
127
128         if(!create_framebuffers()) {
129                 fprintf(stderr, "Failed to create the framebuffer.\n");
130                 return false;
131         }
132
133         if(!create_pipelines()) {
134                 fprintf(stderr, "Failed to create the pipelines.\n");
135                 return false;
136         }
137
138         if(!end_init_command_buffer(&init_buf)) {
139                 fprintf(stderr, "Failed to end the command buffer.\n");
140                 return false;
141         }
142
143         /* rendering command buffers */
144         if(!allocate_rendering_command_buffers(rbufs)) {
145                 fprintf(stderr, "Failed to allocate rendering command buffers.\n");
146                 return false;
147         }
148
149         if(!begin_rendering_command_buffers(rbufs, 2)) {
150                 fprintf(stderr, "Failed to begin rendering command buffers.\n");
151                 return false;
152         }
153
154         gfx_clear = clear;
155         gfx_viewport = viewport;
156         gfx_zbuffer = zbuffer;
157         gfx_cull_face = cull_face;
158         gfx_reshape = reshape;
159         gfx_swapbuffers = swapbuffers;
160         gfx_begin_drawing = begin_drawing;
161         gfx_end_drawing = end_drawing;
162
163         return true;
164 }
165
166 static bool create_swapchain(VkSwapchainKHR *sc)
167 {
168         /* surface capabilities */
169         VkSurfaceCapabilitiesKHR scap;
170         if(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(vk_physical, vk_surface, &scap) != VK_SUCCESS) {
171                 fprintf(stderr, "Failed to get physical device surface capabilities\n");
172                 return false;
173         }
174
175         /* presentation modes */
176         uint32_t prmode_cnt;
177         if(vkGetPhysicalDeviceSurfacePresentModesKHR(vk_physical, vk_surface, &prmode_cnt, 0) != VK_SUCCESS) {
178                 fprintf(stderr, "Failed to get physical device surface presentation modes count.\n");
179                 return false;
180         }
181
182         if(prmode_cnt == 0) {
183                 fprintf(stderr, "Presentation modes not found.\n");
184                 return false;
185         }
186
187         VkPresentModeKHR scmode = VK_PRESENT_MODE_FIFO_KHR;
188         VkPresentModeKHR *modes = new VkPresentModeKHR[prmode_cnt];
189
190         if(vkGetPhysicalDeviceSurfacePresentModesKHR(vk_physical, vk_surface, &prmode_cnt, modes) != VK_SUCCESS) {
191                 fprintf(stderr, "Failed to get physical device presentation modes.\n");
192                 return false;
193         }
194
195         for(uint32_t i=0; i<prmode_cnt; i++) {
196                 if(modes[i] == VK_PRESENT_MODE_MAILBOX_KHR) {
197                         scmode = VK_PRESENT_MODE_MAILBOX_KHR;
198                         break;
199                 }
200                 if((scmode != VK_PRESENT_MODE_MAILBOX_KHR) && (modes[i] == VK_PRESENT_MODE_IMMEDIATE_KHR)) {
201                         //fallback
202                         scmode = VK_PRESENT_MODE_IMMEDIATE_KHR;
203                 }
204         }
205
206         /* swapchain extents */
207         VkExtent2D scextent;
208         if(scap.currentExtent.width == 0xffffffff || scap.currentExtent.height == 0xffffffff) {
209                 scextent.width = win_w;
210                 scextent.height = win_h;
211         }
212         else {
213                 scextent = scap.currentExtent;
214                 win_w = scextent.width;
215                 win_h = scextent.height;
216         }
217
218         /* number of swapchain images (on intel that's 3: maybe should hardcode it to 2?) */
219         num_images = scap.minImageCount; //+ 1;
220         /* intel doesn't set the maxImageCount */
221         if(scap.maxImageCount > 0 && num_images > scap.maxImageCount)
222                 num_images = scap.maxImageCount;
223
224         printf("num_images : %u\n", num_images);
225         assert(num_images > 0);
226
227         images = new VkImage[num_images];
228         iviews = new VkImageView[num_images];
229
230         /* transform flags */
231         VkSurfaceTransformFlagBitsKHR pre_transf = scap.currentTransform;
232         if(scap.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR)
233                 pre_transf = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
234
235         /* find suitable colorspace, format */
236         VkFormat format;
237         VkColorSpaceKHR colorspace;
238
239         VkSurfaceFormatKHR sformat;
240         if(!vku_get_surface_format(vk_physical, vk_surface, &sformat)) {
241                 return false;
242         }
243
244         format = sformat.format;
245         colorspace = sformat.colorSpace;
246
247         /* creating the swapchain */
248         VkSwapchainCreateInfoKHR sinfo;
249         memset(&sinfo, 0, sizeof sinfo);
250
251         sinfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
252         sinfo.surface = vk_surface;
253         sinfo.minImageCount = num_images;
254         sinfo.imageFormat = format;
255         sinfo.imageColorSpace = colorspace;
256         sinfo.imageExtent = scextent;
257         sinfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
258         sinfo.preTransform = pre_transf;
259         sinfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
260         sinfo.imageArrayLayers = 1;
261         sinfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
262         sinfo.presentMode = scmode;
263         sinfo.oldSwapchain = VK_NULL_HANDLE; //TODO
264         sinfo.clipped = VK_TRUE; //TODO
265
266         if(vkCreateSwapchainKHR(vk_device, &sinfo, 0, sc) != VK_SUCCESS) {
267                 fprintf(stderr, "Failed to create swapchain.\n");
268                 return false;
269         }
270
271         if(vkGetSwapchainImagesKHR(vk_device, *sc, &num_images, 0) != VK_SUCCESS) {
272                 fprintf(stderr, "Failed to get the number of the swapchain images.\n");
273                 return false;
274         }
275
276         if(vkGetSwapchainImagesKHR(vk_device, *sc, &num_images, images) != VK_SUCCESS) {
277                 fprintf(stderr, "Failed to get the swapchain images.\n");
278                 return false;
279         }
280
281         VkImageViewCreateInfo ivinf;
282         memset(&ivinf, 0, sizeof ivinf);
283         ivinf.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
284         ivinf.format = format;
285         ivinf.components = {
286                 VK_COMPONENT_SWIZZLE_R,
287                 VK_COMPONENT_SWIZZLE_G,
288                 VK_COMPONENT_SWIZZLE_B,
289                 VK_COMPONENT_SWIZZLE_A
290         };
291         ivinf.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
292         ivinf.subresourceRange.levelCount = 1;
293         ivinf.subresourceRange.layerCount = 1;
294         ivinf.viewType = VK_IMAGE_VIEW_TYPE_2D;
295
296         for(uint32_t i=0; i<num_images; i++) {
297                 ivinf.image = images[i];
298
299                 VkResult res;
300                 if((res = vkCreateImageView(vk_device, &ivinf, 0, &iviews[i])) != VK_SUCCESS) {
301                         fprintf(stderr, "Failed to create image view %d: %s.\n", i, vku_get_vulkan_error_str(res));
302                         return false;
303                 }
304         }
305
306         return true;
307 }
308
309 static bool begin_init_command_buffer(VkCommandBuffer *cb)
310 {
311         if(*cb == VK_NULL_HANDLE) {
312                 *cb = vku_alloc_cmdbuf(vk_pool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
313
314                 VkCommandBufferInheritanceInfo ciinf;
315                 memset(&ciinf, 0, sizeof ciinf);
316                 ciinf.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
317                 ciinf.renderPass = VK_NULL_HANDLE;
318                 ciinf.framebuffer = VK_NULL_HANDLE;
319                 ciinf.occlusionQueryEnable = VK_FALSE;
320
321                 VkCommandBufferBeginInfo cbinf;
322                 memset(&cbinf, 0, sizeof cbinf);
323                 cbinf.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
324                 cbinf.pInheritanceInfo = &ciinf;
325
326                 if(vkBeginCommandBuffer(*cb, &cbinf) != VK_SUCCESS) {
327                         fprintf(stderr, "Failed to begin command buffer.\n");
328                         return false;
329                 }
330         }
331         return true;
332 }
333
334 static bool create_zbuffer()
335 {
336         VkImageCreateInfo dinfo;
337         memset(&dinfo, 0, sizeof dinfo);
338
339         dinfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
340         dinfo.imageType = VK_IMAGE_TYPE_2D;
341         dinfo.format = dformat;
342         dinfo.extent = {(uint32_t)win_w, (uint32_t)win_h, 1};
343         dinfo.mipLevels = 1;
344         dinfo.arrayLayers = 1;
345         dinfo.samples = VK_SAMPLE_COUNT_1_BIT;
346         dinfo.tiling = VK_IMAGE_TILING_OPTIMAL;
347         dinfo.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
348
349         if(vkCreateImage(vk_device, &dinfo, 0, &dimg) != VK_SUCCESS) {
350                 fprintf(stderr, "Failed to create depth buffer image.\n");
351                 return false;
352         }
353
354         VkMemoryRequirements dmem_reqs;
355         vkGetImageMemoryRequirements(vk_device, dimg, &dmem_reqs);
356
357         gpu_mem = vk_allocate(dmem_reqs.size);
358
359         if(!gpu_mem)
360                 return false;
361
362         vkBindImageMemory(vk_device, dimg, gpu_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         //TODO!!!
660         free_rendering_command_buffers(rbufs, 2);
661         if(win) {
662                 glfwDestroyWindow(win);
663         }
664         glfwTerminate();
665
666         //TODOs according to the book:
667         // 1- make sure all threads have been terminated (when I add threads)
668         vku_cleanup();
669 }
670
671 static void error_callback(int error, const char *description)
672 {
673         fprintf(stderr, "GLFW error %d: %s.\n", error, description);
674 }
675
676 static void reshape(int width, int height)
677 {
678 //      VkSwapchainKHR sc;
679 //      if(!(sc = vku_create_swapchain(vk_surface, width, height, 2, VK_PRESENT_MODE_FIFO_KHR,
680 //                                     vk_swapchain))) {
681 //              fprintf(stderr, "Failed to create %dx%d double-buffered swapchain\n", width, height);
682 //              return;
683 //      }
684 //      vk_swapchain = sc;
685 //
686 //      delete [] vkswapchain_images;
687 //      vkswapchain_images = vku_get_swapchain_images(sc, 0);
688 //      vk_curr_swapchain_image = vku_get_next_image(vk_swapchain);
689 }
690
691 static void clear(float r, float g, float b)
692 {
693 }
694
695 static void viewport(int x, int y, int width, int height)
696 {
697 }
698
699 static void zbuffer(bool enable)
700 {
701 }
702
703 static void cull_face(Gfx_cull_face cf)
704 {
705 }
706
707 static void swapbuffers()
708 {
709 }
710
711 static void begin_drawing()
712 {
713         VkSemaphoreCreateInfo psinf;
714         memset(&psinf, 0, sizeof psinf);
715         psinf.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
716
717         VkResult res;
718         if((res = vkCreateSemaphore(vk_device, &psinf, 0, &psema)) != VK_SUCCESS) {
719                 fprintf(stderr, "Failed to create semaphore.\n");
720         }
721         assert(res == VK_SUCCESS);
722 }
723
724 static void end_drawing()
725 {
726         VkResult res = vkAcquireNextImageKHR(vk_device, vk_swapchain,
727                                              UINT64_MAX, psema, VK_NULL_HANDLE, &curr_img);
728         if(res == VK_ERROR_OUT_OF_DATE_KHR) {
729                 fprintf(stderr, "Swapchain out of date.\n");
730                 return;
731         }
732         assert(res == VK_SUCCESS);
733
734         VkSubmitInfo sinf;
735         memset(&sinf, 0, sizeof sinf);
736         VkPipelineStageFlags psflags = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
737         sinf.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
738         sinf.waitSemaphoreCount = 1;
739         sinf.pWaitSemaphores = &psema;
740         sinf.pWaitDstStageMask = &psflags;
741         sinf.commandBufferCount = 1;
742         sinf.pCommandBuffers = &rbufs[curr_img];
743
744         res = vkQueueSubmit(vk_queue, 1, &sinf, VK_NULL_HANDLE);
745         assert(res == VK_SUCCESS);
746
747         VkPresentInfoKHR pinf;
748         memset(&pinf, 0, sizeof pinf);
749         pinf.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
750         pinf.swapchainCount = 1;
751         pinf.pSwapchains = &vk_swapchain;
752         pinf.pImageIndices = &curr_img;
753
754         res = vkQueuePresentKHR(vk_queue, &pinf);
755         if(res == VK_ERROR_OUT_OF_DATE_KHR) {
756                 fprintf(stderr, "Swapchain out of date.\n");
757         }
758         assert(res == VK_SUCCESS);
759
760         res = vkQueueWaitIdle(vk_queue);
761         assert(res == VK_SUCCESS);
762
763         vkDestroySemaphore(vk_device, psema, 0);
764 }