buffer allocation
[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         DevMemBlock block;
358         if(!vku_allocate(dmem_reqs.size, &block)) {
359                 fprintf(stderr, "Failed to allocate zbuffer image.\n");
360                 return false;
361         }
362
363         vkBindImageMemory(vk_device, dimg, block.dev_mem, 0);
364
365         if(!vk_image_set_layout(init_buf, dimg, VK_IMAGE_ASPECT_DEPTH_BIT,
366                                 VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
367                                 (VkAccessFlagBits)0)) {
368                 fprintf(stderr, "Failed to set depth buffer layout.\n");
369                 return false;
370         }
371
372         VkImageViewCreateInfo div_inf;
373         memset(&div_inf, 0, sizeof div_inf);
374
375         div_inf.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
376         div_inf.image = dimg;
377         div_inf.format = dformat;
378         div_inf.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
379         div_inf.subresourceRange.levelCount = 1;
380         div_inf.subresourceRange.layerCount = 1;
381         div_inf.viewType = VK_IMAGE_VIEW_TYPE_2D;
382
383         if(vkCreateImageView(vk_device, &div_inf, 0, &dview) != VK_SUCCESS) {
384                 fprintf(stderr, "Failed to create image view for depth buffer.\n");
385                 return false;
386         }
387
388         return true;
389 }
390
391 static bool create_renderpass()
392 {
393         VkSurfaceFormatKHR sformat;
394         if(!vku_get_surface_format(vk_physical, vk_surface, &sformat)) {
395                 fprintf(stderr, "Failed to get surface format.\n");
396                 return false;
397         }
398
399         VkAttachmentDescription att[2];
400         memset(&att, 0, (sizeof att[0]) * 2);
401
402         att[0].format = sformat.format;
403         att[0].samples = VK_SAMPLE_COUNT_1_BIT;
404         att[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
405         att[0].storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
406         att[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
407         att[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
408         att[0].initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
409         att[0].finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
410
411         att[1].format = dformat;
412         att[1].samples = VK_SAMPLE_COUNT_1_BIT;
413         att[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
414         att[1].storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
415         att[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
416         att[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
417         att[1].initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
418         att[1].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
419
420         VkAttachmentReference cref;
421         memset(&cref, 0, sizeof cref);
422         cref.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
423
424         VkAttachmentReference dref;
425         memset(&dref, 0, sizeof dref);
426         dref.attachment = 1;
427         dref.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
428
429         VkSubpassDescription sd;
430         memset(&sd, 0, sizeof sd);
431         sd.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
432         sd.colorAttachmentCount = 1;
433         sd.pColorAttachments = &cref;
434         sd.pDepthStencilAttachment = &dref;
435
436         VkRenderPassCreateInfo rinf;
437         memset(&rinf, 0, sizeof rinf);
438         rinf.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
439         rinf.attachmentCount = 2;
440         rinf.pAttachments = att;
441         rinf.subpassCount = 1;
442         rinf.pSubpasses = &sd;
443
444         if(vkCreateRenderPass(vk_device, &rinf, 0, &rpass) != VK_SUCCESS) {
445                 fprintf(stderr, "Failed to create rpass.\n");
446                 return false;
447         }
448
449         return true;
450 }
451
452 static bool create_framebuffers()
453 {
454         /* framebuffer attachments */
455         VkImageView fb_att[2];
456         fb_att[1] = dview;
457
458         VkFramebufferCreateInfo fbinf;
459         memset(&fbinf, 0, sizeof fbinf);
460         fbinf.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
461         fbinf.renderPass = rpass;
462         fbinf.attachmentCount = 2;
463         fbinf.pAttachments = fb_att;
464         fbinf.width = win_w;
465         fbinf.height = win_h;
466         fbinf.layers = 1;
467
468         for(int i=0; i<2; i++) {
469                 fb_att[0] = iviews[i];
470                 if(vkCreateFramebuffer(vk_device, &fbinf, 0, &fbs[i]) != VK_SUCCESS) {
471                         fprintf(stderr, "Failed to create framebuffer %i\n", i);
472                         return false;
473                 }
474         }
475         return true;
476 }
477
478 static bool create_pipelines()
479 {
480         VkDescriptorSetLayoutBinding dslb[1];
481         memset(&dslb[0], 0, sizeof dslb[0]);
482         dslb[0].binding = 0;
483         dslb[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
484         dslb[0].descriptorCount = 1;
485         dslb[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
486
487         VkDescriptorSetLayoutCreateInfo dslinf;
488         memset(&dslinf, 0, sizeof dslinf);
489         dslinf.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
490         dslinf.bindingCount = 1; //dslb.size();
491         dslinf.pBindings = dslb;
492
493         VkDescriptorSetLayout dsl;
494         if(vkCreateDescriptorSetLayout(vk_device, &dslinf, 0, &dsl) != VK_SUCCESS) {
495                 fprintf(stderr, "Failed to create descriptor set layout.\n");
496                 return false;
497         }
498
499         VkPipelineLayoutCreateInfo pinf;
500         memset(&pinf, 0, sizeof pinf);
501         pinf.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
502         pinf.setLayoutCount = 1;
503         pinf.pSetLayouts = &dsl;
504
505         VkPipelineLayout pl;
506         if(vkCreatePipelineLayout(vk_device, &pinf, 0, &pl) != VK_SUCCESS) {
507                 fprintf(stderr, "Failed to create pipeline layout.\n");
508                 return false;
509         }
510
511         VkPipelineCacheCreateInfo pcinf;
512         memset(&pcinf, 0, sizeof pcinf);
513         pcinf.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;
514
515         VkPipelineCache pcache;
516         if(vkCreatePipelineCache(vk_device, &pcinf, 0, &pcache) != VK_SUCCESS) {
517                 fprintf(stderr, "Failed to create pipeline cache.\n");
518                 return false;
519         }
520
521         VkGraphicsPipelineCreateInfo ginf;
522         memset(&ginf, 0, sizeof ginf);
523         ginf.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
524         ginf.stageCount = 2;
525
526         return true;
527 }
528
529 static bool end_init_command_buffer(VkCommandBuffer *cb)
530 {
531         if(vkEndCommandBuffer(*cb) != VK_SUCCESS) {
532                 fprintf(stderr, "Failed to end command buffer.\n");
533                 return false;
534         }
535
536         VkSubmitInfo si;
537         memset(&si, 0, sizeof si);
538         si.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
539         si.commandBufferCount = 1;
540         si.pCommandBuffers = cb;
541
542         if(vkQueueSubmit(vk_queue, 1, &si, VK_NULL_HANDLE) != VK_SUCCESS) {
543                 fprintf(stderr, "Failed to submit null queue.\n");
544                 return false;
545         }
546
547         if(vkQueueWaitIdle(vk_queue) != VK_SUCCESS) {
548                 fprintf(stderr, "QueueWaitIdle failure!\n");
549                 return false;
550         }
551
552         vkFreeCommandBuffers(vk_device, vk_pool, 1, cb);
553         *cb = VK_NULL_HANDLE;
554
555         return true;
556 }
557
558 static bool allocate_rendering_command_buffers(VkCommandBuffer *bufs)
559 {
560         return vku_alloc_cmdbufs(vk_pool, VK_COMMAND_BUFFER_LEVEL_PRIMARY,
561                                  2, bufs);
562 }
563
564 static void free_rendering_command_buffers(VkCommandBuffer *bufs, int count)
565 {
566         for(int i=0; i<count; i++) {
567                 vku_free_cmdbuf(vk_pool, bufs[i]);
568         }
569 }
570
571 static bool begin_rendering_command_buffers(VkCommandBuffer *bufs, int count)
572 {
573         VkCommandBufferInheritanceInfo iinf;
574         memset(&iinf, 0, sizeof iinf);
575         iinf.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
576         iinf.renderPass = VK_NULL_HANDLE;
577         iinf.framebuffer = VK_NULL_HANDLE;
578
579         VkCommandBufferBeginInfo binf;
580         memset(&binf, 0, sizeof binf);
581         binf.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
582         binf.pInheritanceInfo = &iinf;
583
584         // setting clear values
585         VkClearValue clvals[2];
586         for(int i=0; i<4; i++) {
587                 clvals[0].color.float32[i] = clear_color[i];
588         }
589         clvals[1].depthStencil = {1.0f, 0};
590
591         //build drawing command buffers
592         for(int i=0; i<count; i++) {
593                 if(vkBeginCommandBuffer(bufs[i], &binf) != VK_SUCCESS) {
594                         fprintf(stderr, "Failed to begin command buffer: %d\n", i);
595                         return false;
596                 }
597
598                 VkImageMemoryBarrier imbarr;
599                 memset(&imbarr, 0, sizeof imbarr);
600                 imbarr.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
601                 imbarr.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
602                 imbarr.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
603                 imbarr.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
604                 imbarr.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
605                 imbarr.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
606                 imbarr.image = images[i];
607                 imbarr.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
608                 vkCmdPipelineBarrier(bufs[i], VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, 0, 0, 0, 1, &imbarr);
609
610                 VkRenderPassBeginInfo rbinf;
611                 memset(&rbinf, 0, sizeof rbinf);
612                 rbinf.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
613                 rbinf.renderPass = rpass;
614                 rbinf.framebuffer = fbs[i];
615                 rbinf.renderArea.extent.width = win_w;
616                 rbinf.renderArea.extent.height = win_h;
617                 rbinf.clearValueCount = count;
618                 rbinf.pClearValues = clvals;
619
620                 vkCmdBeginRenderPass(bufs[i], &rbinf, VK_SUBPASS_CONTENTS_INLINE);
621                 VkViewport viewport;
622                 memset(&viewport, 0, sizeof viewport);
623                 viewport.width = (float)win_w;
624                 viewport.height = (float)win_h;
625                 viewport.maxDepth = 1.0f;
626                 vkCmdSetViewport(bufs[i], 0, 1, &viewport);
627
628                 VkRect2D scissor;
629                 memset(&scissor, 0, sizeof scissor);
630                 scissor.extent.width = win_w;
631                 scissor.extent.height = win_h;
632                 vkCmdSetScissor(bufs[i], 0, 1, &scissor);
633                 vkCmdEndRenderPass(bufs[i]);
634
635                 /* pre-present barrier */
636                 VkImageMemoryBarrier ppb;
637                 memset(&ppb, 0, sizeof ppb);
638                 ppb.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
639                 ppb.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
640                 ppb.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT;
641                 ppb.oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
642                 ppb.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
643                 ppb.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
644                 ppb.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
645                 ppb.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
646                 ppb.image = images[i];
647
648                 vkCmdPipelineBarrier(bufs[i], VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, 0, 0, 0, 1, &ppb);
649
650                 if(vkEndCommandBuffer(bufs[i]) != VK_SUCCESS) {
651                         fprintf(stderr, "Failed to end command buffer: %d\n", i);
652                         return false;
653                 }
654         }
655         return true;
656 }
657
658 void cleanup_vulkan()
659 {
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 }
679
680 static void clear(float r, float g, float b)
681 {
682 }
683
684 static void viewport(int x, int y, int width, int height)
685 {
686 }
687
688 static void zbuffer(bool enable)
689 {
690 }
691
692 static void cull_face(Gfx_cull_face cf)
693 {
694 }
695
696 static void swapbuffers()
697 {
698 }
699
700 static void begin_drawing()
701 {
702         VkSemaphoreCreateInfo psinf;
703         memset(&psinf, 0, sizeof psinf);
704         psinf.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
705
706         VkResult res;
707         if((res = vkCreateSemaphore(vk_device, &psinf, 0, &psema)) != VK_SUCCESS) {
708                 fprintf(stderr, "Failed to create semaphore.\n");
709         }
710         assert(res == VK_SUCCESS);
711 }
712
713 static void end_drawing()
714 {
715         VkResult res = vkAcquireNextImageKHR(vk_device, vk_swapchain,
716                                              UINT64_MAX, psema, VK_NULL_HANDLE, &curr_img);
717         if(res == VK_ERROR_OUT_OF_DATE_KHR) {
718                 fprintf(stderr, "Swapchain out of date.\n");
719                 return;
720         }
721         assert(res == VK_SUCCESS);
722
723         VkSubmitInfo sinf;
724         memset(&sinf, 0, sizeof sinf);
725         VkPipelineStageFlags psflags = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
726         sinf.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
727         sinf.waitSemaphoreCount = 1;
728         sinf.pWaitSemaphores = &psema;
729         sinf.pWaitDstStageMask = &psflags;
730         sinf.commandBufferCount = 1;
731         sinf.pCommandBuffers = &rbufs[curr_img];
732
733         res = vkQueueSubmit(vk_queue, 1, &sinf, VK_NULL_HANDLE);
734         assert(res == VK_SUCCESS);
735
736         VkPresentInfoKHR pinf;
737         memset(&pinf, 0, sizeof pinf);
738         pinf.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
739         pinf.swapchainCount = 1;
740         pinf.pSwapchains = &vk_swapchain;
741         pinf.pImageIndices = &curr_img;
742
743         res = vkQueuePresentKHR(vk_queue, &pinf);
744         if(res == VK_ERROR_OUT_OF_DATE_KHR) {
745                 fprintf(stderr, "Swapchain out of date.\n");
746         }
747         assert(res == VK_SUCCESS);
748
749         res = vkQueueWaitIdle(vk_queue);
750         assert(res == VK_SUCCESS);
751
752         vkDestroySemaphore(vk_device, psema, 0);
753 }