many changes: Makefile, util, fixed indent, fixes in swapchain
[vkrt] / src / vk.c
1 #include <assert.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5
6 #include "vk.h"
7
8 /* static variables */
9
10 static VkViewport viewport;
11 static VkRect2D scissor;
12 static bool enable_layers = true;
13
14 /* static functions */
15
16 static VkSampleCountFlagBits
17 get_num_samples(uint32_t num_samples)
18 {
19     switch(num_samples) {
20     case 64:
21         return VK_SAMPLE_COUNT_64_BIT;
22     case 32:
23         return VK_SAMPLE_COUNT_32_BIT;
24     case 16:
25         return VK_SAMPLE_COUNT_16_BIT;
26     case 8:
27         return VK_SAMPLE_COUNT_8_BIT;
28     case 4:
29         return VK_SAMPLE_COUNT_4_BIT;
30     case 2:
31         return VK_SAMPLE_COUNT_2_BIT;
32     case 1:
33         break;
34     default:
35         fprintf(stderr, "Invalid number of samples in VkSampleCountFlagBits. Using one sample.\n");
36         break;
37     }
38     return VK_SAMPLE_COUNT_1_BIT;
39 }
40
41 static VkAccessFlagBits
42 get_access_mask(const VkImageLayout layout)
43 {
44     /* dstAccessMask of barriers must be supported from the pipeline
45      * stage, see also access scopes and this table:
46      * https://www.khronos.org/registry/vulkan/specs/1.2-extensions/html/vkspec.html#synchronization-access-types-supported
47      */
48     switch (layout) {
49     case VK_IMAGE_LAYOUT_UNDEFINED:
50         return 0;
51     case VK_IMAGE_LAYOUT_GENERAL:
52         return VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT;
53     case VK_IMAGE_LAYOUT_PREINITIALIZED:
54         return VK_ACCESS_HOST_WRITE_BIT;
55     case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
56         return VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
57                VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
58     case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
59         return VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_INPUT_ATTACHMENT_READ_BIT;
60     case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
61         return VK_ACCESS_TRANSFER_READ_BIT;
62     case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
63         return VK_ACCESS_TRANSFER_WRITE_BIT;
64     case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR:
65         return 0;
66     default:
67         return 0;
68     };
69
70     return 0;
71 }
72
73 static void
74 enable_validation_layers(VkInstanceCreateInfo *info)
75 {
76     int i;
77     uint32_t num_layers;
78     VkLayerProperties *layers;
79     static const char *layer_names[] = {
80         "VK_LAYER_KHRONOS_validation",
81     };
82
83     vkEnumerateInstanceLayerProperties(&num_layers, 0);
84     layers = alloca(num_layers * sizeof *layers);
85     vkEnumerateInstanceLayerProperties(&num_layers, layers);
86
87     if (num_layers) {
88         printf("Available validation layers:\n");
89         for(i = 0; i < (int)num_layers; i++) {
90             printf(" %s\n", layers[i].layerName);
91         }
92
93         info->ppEnabledLayerNames = layer_names;
94         info->enabledLayerCount = sizeof layer_names / sizeof *layer_names;
95     } else {
96         fprintf(stderr, "Vulkan validation layers not found.\n");
97     }
98 }
99
100 static void
101 enable_extensions(VkInstanceCreateInfo *info)
102 {
103     static const char *ext_names[] = {
104         "VK_KHR_xcb_surface",
105         "VK_KHR_surface"
106     };
107
108     uint32_t num_extensions;
109     VkExtensionProperties *extensions;
110     int i;
111
112     vkEnumerateInstanceExtensionProperties(0, &num_extensions, 0);
113     if (!num_extensions) {
114         fprintf(stderr, "No instance extensions found.\n");
115         return;
116     }
117
118     extensions = alloca(num_extensions * sizeof *extensions);
119     vkEnumerateInstanceExtensionProperties(0, &num_extensions, extensions);
120
121     printf("Available extensions:\n");
122     for (i = 0; i < num_extensions; i++) {
123        printf(" %s\n", extensions[i].extensionName);
124     }
125
126     info->ppEnabledExtensionNames = ext_names;
127     info->enabledExtensionCount = ARRAY_SIZE(ext_names);
128 }
129
130 static VkInstance
131 create_instance(bool enable_layers)
132 {
133     VkApplicationInfo app_info;
134     VkInstanceCreateInfo inst_info;
135     VkInstance inst;
136
137     /* VkApplicationInfo */
138     memset(&app_info, 0, sizeof app_info);
139     app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
140     app_info.pApplicationName = "vktest";
141     app_info.apiVersion = VK_API_VERSION_1_1;
142
143     /* VkInstanceCreateInfo */
144     memset(&inst_info, 0, sizeof inst_info);
145     inst_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
146     inst_info.pApplicationInfo = &app_info;
147
148     enable_extensions(&inst_info);
149     if (enable_layers) {
150         enable_validation_layers(&inst_info);
151     }
152
153     if (vkCreateInstance(&inst_info, 0, &inst) != VK_SUCCESS)
154         return 0;
155
156     return inst;
157 }
158
159 static VkPhysicalDevice
160 select_physical_device(VkInstance inst)
161 {
162     VkResult res = VK_SUCCESS;
163     uint32_t dev_count = 0;
164     VkPhysicalDevice *pdevices;
165     VkPhysicalDevice pdevice0;
166
167     if ((res =
168          vkEnumeratePhysicalDevices(inst, &dev_count, 0)) != VK_SUCCESS)
169         return 0;
170
171     pdevices = malloc(dev_count * sizeof(VkPhysicalDevice));
172     if (vkEnumeratePhysicalDevices(inst, &dev_count, pdevices) !=
173         VK_SUCCESS)
174         return 0;
175
176     pdevice0 = pdevices[0];
177     free(pdevices);
178
179     return pdevice0;
180 }
181
182 static VkDevice
183 create_device(struct vk_ctx *ctx, VkPhysicalDevice pdev)
184 {
185     const char *deviceExtensions[] = { "VK_KHR_swapchain" };
186     VkDeviceQueueCreateInfo dev_queue_info;
187     VkDeviceCreateInfo dev_info;
188     VkDevice dev;
189     uint32_t prop_count;
190     VkQueueFamilyProperties *fam_props;
191     uint32_t i;
192     float qprio = 0;
193
194     ctx->qfam_idx = -1;
195     vkGetPhysicalDeviceQueueFamilyProperties(pdev, &prop_count, 0);
196     if (prop_count < 0) {
197         fprintf(stderr, "Invalid queue family properties.\n");
198         return 0;
199     }
200
201     fam_props = malloc(prop_count * sizeof *fam_props);
202     vkGetPhysicalDeviceQueueFamilyProperties(pdev, &prop_count, fam_props);
203
204     for (i = 0; i < prop_count; i++) {
205         if (fam_props[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
206             ctx->qfam_idx = i;
207             break;
208         }
209     }
210     free(fam_props);
211
212     memset(&dev_queue_info, 0, sizeof dev_queue_info);
213     dev_queue_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
214     dev_queue_info.queueFamilyIndex = ctx->qfam_idx;
215     dev_queue_info.queueCount = 1;
216     dev_queue_info.pQueuePriorities = &qprio;
217
218     memset(&dev_info, 0, sizeof dev_info);
219     dev_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
220     dev_info.queueCreateInfoCount = 1;
221     dev_info.pQueueCreateInfos = &dev_queue_info;
222     dev_info.enabledExtensionCount = ARRAY_SIZE(deviceExtensions);
223     dev_info.ppEnabledExtensionNames = deviceExtensions;
224
225     if (vkCreateDevice(pdev, &dev_info, 0, &dev) != VK_SUCCESS)
226         return 0;
227
228     return dev;
229 }
230
231 static void
232 fill_uuid(VkPhysicalDevice pdev, uint8_t *deviceUUID, uint8_t *driverUUID)
233 {
234     VkPhysicalDeviceIDProperties devProp;
235     VkPhysicalDeviceProperties2 prop2;
236
237     memset(&devProp, 0, sizeof devProp);
238     devProp.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES;
239
240     memset(&prop2, 0, sizeof prop2);
241     prop2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
242     prop2.pNext = &devProp;
243
244     vkGetPhysicalDeviceProperties2(pdev, &prop2);
245     memcpy(deviceUUID, devProp.deviceUUID, VK_UUID_SIZE);
246     memcpy(driverUUID, devProp.driverUUID, VK_UUID_SIZE);
247 }
248
249 static VkCommandPool
250 create_cmd_pool(struct vk_ctx *ctx)
251 {
252     VkCommandPoolCreateInfo cmd_pool_info;
253     VkCommandPool cmd_pool;
254     VkDevice dev = ctx->dev;
255
256     memset(&cmd_pool_info, 0, sizeof cmd_pool_info);
257     cmd_pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
258     cmd_pool_info.queueFamilyIndex = ctx->qfam_idx;
259     cmd_pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
260
261     if (vkCreateCommandPool(dev, &cmd_pool_info, 0, &cmd_pool) != VK_SUCCESS)
262         return 0;
263
264     return cmd_pool;
265 }
266
267 static VkRenderPass
268 create_renderpass(struct vk_ctx *ctx,
269                   struct vk_image_props *color_img_props,
270                   struct vk_image_props *depth_img_props)
271 {
272     uint32_t num_attachments = 2;
273     VkAttachmentDescription att_dsc[2];
274     VkAttachmentReference att_rfc[2];
275     VkSubpassDescription subpass_dsc[1];
276     VkRenderPassCreateInfo rpass_info;
277
278     /* VkAttachmentDescription */
279     memset(att_dsc, 0, num_attachments * sizeof att_dsc[0]);
280
281     att_dsc[0].samples = get_num_samples(color_img_props->num_samples);
282     att_dsc[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
283     att_dsc[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
284     att_dsc[0].initialLayout = color_img_props->in_layout;
285     att_dsc[0].finalLayout = color_img_props->end_layout;
286     att_dsc[0].format = color_img_props->format;
287     att_dsc[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
288     att_dsc[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
289
290     att_dsc[1].samples = get_num_samples(depth_img_props->num_samples);
291
292     /* We might want to reuse a depth buffer */
293     if (depth_img_props->in_layout != VK_IMAGE_LAYOUT_UNDEFINED) {
294         att_dsc[1].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
295         att_dsc[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
296     }
297     else {
298         att_dsc[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
299         att_dsc[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
300     }
301
302     att_dsc[1].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
303     att_dsc[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
304     att_dsc[1].initialLayout = depth_img_props->in_layout;
305     att_dsc[1].finalLayout = depth_img_props->end_layout;
306     att_dsc[1].format = depth_img_props->format;
307
308     /* VkAttachmentReference */
309     memset(att_rfc, 0, num_attachments * sizeof att_rfc[0]);
310
311     att_rfc[0].layout = color_img_props->tiling == VK_IMAGE_TILING_OPTIMAL ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_GENERAL;
312     att_rfc[0].attachment = 0;
313
314     att_rfc[1].layout = depth_img_props->tiling == VK_IMAGE_TILING_OPTIMAL ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_GENERAL;
315     att_rfc[1].attachment = 1;
316
317     /* VkSubpassDescription */
318     memset(&subpass_dsc, 0, sizeof subpass_dsc);
319     subpass_dsc[0].pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
320     subpass_dsc[0].colorAttachmentCount = 1;
321     subpass_dsc[0].pColorAttachments = &att_rfc[0];
322     subpass_dsc[0].pDepthStencilAttachment = &att_rfc[1];
323
324     /* VkRenderPassCreateInfo */
325     memset(&rpass_info, 0, sizeof rpass_info);
326     rpass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
327     rpass_info.attachmentCount = num_attachments;
328     rpass_info.pAttachments = att_dsc;
329     rpass_info.subpassCount = 1;
330     rpass_info.pSubpasses = subpass_dsc;
331
332     VkRenderPass rpass;
333     if (vkCreateRenderPass(ctx->dev, &rpass_info, 0, &rpass) != VK_SUCCESS) {
334         fprintf(stderr, "Failed to create renderpass.\n");
335         rpass = VK_NULL_HANDLE;
336     }
337
338     return rpass;
339 }
340
341 static inline VkImageType
342 get_image_type(uint32_t h, uint32_t d)
343 {
344     if (h == 1)
345         return VK_IMAGE_TYPE_1D;
346
347     if (d > 1)
348         return VK_IMAGE_TYPE_3D;
349
350     return VK_IMAGE_TYPE_2D;
351 }
352
353 static VkImageViewType
354 get_image_view_type(struct vk_image_props *props)
355 {
356     VkImageType type = get_image_type(props->h, props->depth);
357     switch(type) {
358         case VK_IMAGE_TYPE_1D:
359             return props->num_layers > 1 ?
360                 VK_IMAGE_VIEW_TYPE_1D_ARRAY :
361                 VK_IMAGE_VIEW_TYPE_1D;
362         case VK_IMAGE_TYPE_2D:
363             if (props->num_layers == 1)
364                 return VK_IMAGE_VIEW_TYPE_2D;
365             if (props->num_layers == 6)
366                 return VK_IMAGE_VIEW_TYPE_CUBE;
367             if (props->num_layers % 6 == 0)
368                 return VK_IMAGE_VIEW_TYPE_CUBE_ARRAY;
369             if (props->num_layers > 1)
370                 return VK_IMAGE_VIEW_TYPE_2D_ARRAY;
371         case VK_IMAGE_TYPE_3D:
372             if (props->num_layers == 1)
373                 return VK_IMAGE_VIEW_TYPE_3D;
374             if ((props->num_layers == 1) &&
375                 (props->num_levels == 1))
376                 return VK_IMAGE_VIEW_TYPE_2D;
377             if ((props->num_levels == 1) &&
378                 (props->num_layers > 1))
379                 return VK_IMAGE_VIEW_TYPE_2D_ARRAY;
380         default:
381             return VK_IMAGE_VIEW_TYPE_2D;
382     }
383 }
384
385 static VkImageAspectFlagBits
386 get_aspect_from_depth_format(VkFormat depth_format)
387 {
388     switch (depth_format) {
389     case VK_FORMAT_D16_UNORM:
390     case VK_FORMAT_X8_D24_UNORM_PACK32:
391     case VK_FORMAT_D32_SFLOAT:
392         return VK_IMAGE_ASPECT_DEPTH_BIT;
393     case VK_FORMAT_S8_UINT:
394         return VK_IMAGE_ASPECT_STENCIL_BIT;
395     case VK_FORMAT_D16_UNORM_S8_UINT:
396     case VK_FORMAT_D24_UNORM_S8_UINT:
397     case VK_FORMAT_D32_SFLOAT_S8_UINT:
398         return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
399     default:
400         break;
401     }
402     return 0;
403 }
404
405 static VkPipelineStageFlags
406 get_pipeline_stage_flags(const VkImageLayout layout)
407 {
408     switch (layout) {
409     case VK_IMAGE_LAYOUT_UNDEFINED:
410         return VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
411     case VK_IMAGE_LAYOUT_GENERAL:
412         return VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
413     case VK_IMAGE_LAYOUT_PREINITIALIZED:
414         return VK_PIPELINE_STAGE_HOST_BIT;
415     case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
416     case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
417         return VK_PIPELINE_STAGE_TRANSFER_BIT;
418     case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
419         return VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
420     case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
421         return VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
422                VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
423     case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR:
424         return VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
425     default:
426         break;
427     }
428     return 0;
429 }
430
431 static bool
432 create_image_view(struct vk_ctx *ctx,
433                   VkImage image,
434                   VkImageViewType view_type,
435                   VkFormat format,
436                   VkImageSubresourceRange sr,
437                   bool is_swapchain,
438                   VkImageView *image_view)
439 {
440     VkImageViewCreateInfo info;
441
442     memset(&info, 0, sizeof info);
443     info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
444     info.image = image;
445     info.viewType = view_type;
446     info.viewType = VK_IMAGE_VIEW_TYPE_2D;
447     info.format = format;
448     info.subresourceRange = sr;
449
450     if (is_swapchain) {
451         info.components.r = VK_COMPONENT_SWIZZLE_R;
452         info.components.g = VK_COMPONENT_SWIZZLE_G;
453         info.components.b = VK_COMPONENT_SWIZZLE_B;
454         info.components.a = VK_COMPONENT_SWIZZLE_A;
455     }
456
457     if (vkCreateImageView(ctx->dev, &info, 0, image_view) != VK_SUCCESS) {
458         fprintf(stderr, "Failed to create image view.\n");
459         image_view = VK_NULL_HANDLE;
460
461         return false;
462     }
463
464     return true;
465 }
466
467 static void
468 create_framebuffer(struct vk_ctx *ctx,
469                    struct vk_image_att *color_att,
470                    struct vk_image_att *depth_att,
471                    struct vk_renderer *renderer)
472 {
473     VkImageSubresourceRange sr;
474     VkFramebufferCreateInfo fb_info;
475     VkImageView atts[2];
476     VkImageViewType view_type = get_image_view_type(&color_att->props);
477
478     if (!color_att->obj.img || !depth_att->obj.img) {
479         fprintf(stderr, "Invalid framebuffer attachment image.\n");
480         goto fail;
481     }
482
483     /* create image views */
484
485     /* VKImageSubresourceRange */
486     memset(&sr, 0, sizeof sr);
487     sr.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
488     /* If an application wants to use all mip levels
489      * or layers in an image after the baseMipLevel
490      * or baseArrayLayer, it can set levelCount and
491      * layerCount to the special values
492      * VK_REMAINING_MIP_LEVELS and
493      * VK_REMAINING_ARRAY_LAYERS without knowing the
494      * exact number of mip levels or layers.
495      */
496     sr.baseMipLevel = 0;
497     sr.levelCount = color_att->props.num_levels;
498     sr.baseArrayLayer = 0;
499     sr.layerCount = color_att->props.num_layers;
500
501     /* color view */
502     if (!create_image_view(ctx, color_att->obj.img, view_type, color_att->props.format, sr, false, &color_att->obj.img_view)) {
503         fprintf(stderr, "Failed to create color image view for framebuffer.\n");
504         vk_destroy_image(ctx, &color_att->obj);
505         goto fail;
506     }
507
508     /* depth view */
509     memset(&sr, 0, sizeof sr);
510     sr.aspectMask = get_aspect_from_depth_format(depth_att->props.format);
511     sr.baseMipLevel = 0;
512     sr.levelCount = depth_att->props.num_levels ? depth_att->props.num_levels : 1;
513     sr.baseArrayLayer = 0;
514     sr.layerCount = depth_att->props.num_layers ? depth_att->props.num_layers : 1;
515
516     if (!create_image_view(ctx, depth_att->obj.img,
517                            depth_att->props.num_layers > 1 ?
518                            VK_IMAGE_VIEW_TYPE_2D_ARRAY :
519                            VK_IMAGE_VIEW_TYPE_2D,
520                            depth_att->props.format,
521                            sr,
522                            false,
523                            &depth_att->obj.img_view)) {
524         fprintf(stderr, "Failed to create depth image view for framebuffer.\n");
525         vk_destroy_image(ctx, &depth_att->obj);
526         goto fail;
527     }
528
529     atts[0] = color_att->obj.img_view;
530     atts[1] = depth_att->obj.img_view;
531
532     memset(&fb_info, 0, sizeof fb_info);
533     fb_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
534     fb_info.renderPass = renderer->renderpass;
535     fb_info.width = color_att->props.w;
536     fb_info.height = color_att->props.h;
537     fb_info.layers = color_att->props.num_layers ? color_att->props.num_layers : 1;
538     fb_info.attachmentCount = 2;
539     fb_info.pAttachments = atts;
540
541     if (vkCreateFramebuffer(ctx->dev, &fb_info, 0, &renderer->fb) != VK_SUCCESS)
542         goto fail;
543
544     return;
545
546 fail:
547     fprintf(stderr, "Failed to create framebuffer.\n");
548     renderer->fb = VK_NULL_HANDLE;
549 }
550
551 static VkShaderModule
552 create_shader_module(struct vk_ctx *ctx,
553              const char *src,
554              unsigned int size)
555 {
556     VkShaderModuleCreateInfo sm_info;
557     VkShaderModule sm;
558
559     /* VkShaderModuleCreateInfo */
560     memset(&sm_info, 0, sizeof sm_info);
561     sm_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
562     sm_info.codeSize = size;
563     sm_info.pCode = (void*)src;
564
565     if (vkCreateShaderModule(ctx->dev, &sm_info, 0, &sm) != VK_SUCCESS) {
566         fprintf(stderr, "Failed to create shader module.\n");
567         sm = VK_NULL_HANDLE;
568     }
569
570     return sm;
571 }
572
573 static void
574 create_pipeline(struct vk_ctx *ctx,
575                 uint32_t width,
576                 uint32_t height,
577                 uint32_t num_samples,
578                 bool enable_depth,
579                 bool enable_stencil,
580                 struct vk_renderer *renderer)
581 {
582     VkVertexInputBindingDescription vert_bind_dsc[1];
583     VkVertexInputAttributeDescription vert_att_dsc[1];
584
585     VkPipelineColorBlendAttachmentState cb_att_state[1];
586     VkPipelineVertexInputStateCreateInfo vert_input_info;
587     VkPipelineInputAssemblyStateCreateInfo asm_info;
588     VkPipelineViewportStateCreateInfo viewport_info;
589     VkPipelineRasterizationStateCreateInfo rs_info;
590     VkPipelineMultisampleStateCreateInfo ms_info;
591     VkPipelineDepthStencilStateCreateInfo ds_info;
592     VkPipelineColorBlendStateCreateInfo cb_info;
593     VkPipelineShaderStageCreateInfo sdr_stages[2];
594     VkPipelineLayoutCreateInfo layout_info;
595     VkGraphicsPipelineCreateInfo pipeline_info;
596     VkFormat format;
597     VkFormatProperties fmt_props;
598     VkPushConstantRange pc_range[1];
599
600     VkStencilOpState front;
601     VkStencilOpState back;
602     int i;
603     VkPipelineLayout pipeline_layout;
604     uint32_t stride;
605
606     /* format of vertex attributes:
607      * we have 2D vectors so we need a RG format:
608      * R for x, G for y
609      * the stride (distance between 2 consecutive elements)
610      * must be 8 because we use 32 bit floats and
611      * 32bits = 8bytes */
612     format = VK_FORMAT_R32G32_SFLOAT;
613     vkGetPhysicalDeviceFormatProperties(ctx->pdev, format, &fmt_props);
614     assert(fmt_props.bufferFeatures & VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT);
615     stride = 8;
616
617     /* VkVertexInputAttributeDescription */
618     memset(&vert_att_dsc, 0, sizeof vert_att_dsc);
619     vert_att_dsc[0].location = 0;
620     vert_att_dsc[0].binding = 0;
621     vert_att_dsc[0].format = format; /* see comment */
622     vert_att_dsc[0].offset = 0;
623
624     /* VkVertexInputBindingDescription */
625     memset(&vert_bind_dsc, 0, sizeof vert_bind_dsc);
626     vert_bind_dsc[0].binding = 0;
627     vert_bind_dsc[0].stride = stride;
628     vert_bind_dsc[0].inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
629
630     /* If using vbo, we have setup vertex_info in the renderer. */
631     bool use_vbo = renderer->vertex_info.num_verts > 0;
632
633     /* VkPipelineVertexInputStateCreateInfo */
634     memset(&vert_input_info, 0, sizeof vert_input_info);
635     vert_input_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
636     vert_input_info.vertexBindingDescriptionCount = use_vbo ? 1 : 0;
637     vert_input_info.pVertexBindingDescriptions = vert_bind_dsc;
638     vert_input_info.vertexAttributeDescriptionCount = use_vbo ? 1 : 0;
639     vert_input_info.pVertexAttributeDescriptions = vert_att_dsc;
640
641     /* VkPipelineInputAssemblyStateCreateInfo */
642     memset(&asm_info, 0, sizeof asm_info);
643     asm_info.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
644     asm_info.topology = renderer->vertex_info.topology ?
645                         renderer->vertex_info.topology
646                         : VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
647     asm_info.primitiveRestartEnable = false;
648
649     /* VkViewport */
650     viewport.x = viewport.y = 0;
651     viewport.width = width;
652     viewport.height = height;
653     viewport.minDepth = 0;
654     viewport.maxDepth = 1;
655
656     /* VkRect2D scissor */
657     scissor.offset.x = scissor.offset.y = 0;
658     scissor.extent.width = width;
659     scissor.extent.height = height;
660
661     /* VkPipelineViewportStateCreateInfo */
662     memset(&viewport_info, 0, sizeof viewport_info);
663     viewport_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
664     viewport_info.viewportCount = 1;
665     viewport_info.pViewports = &viewport;
666     viewport_info.scissorCount = 1;
667     viewport_info.pScissors = &scissor;
668
669     /* VkPipelineRasterizationStateCreateInfo */
670     memset(&rs_info, 0, sizeof rs_info);
671     rs_info.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
672     rs_info.polygonMode = VK_POLYGON_MODE_FILL;
673     rs_info.cullMode = VK_CULL_MODE_NONE;
674     rs_info.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
675     rs_info.lineWidth = 1.0;
676
677     /* VkPipelineMultisampleStateCreateInfo */
678     memset(&ms_info, 0, sizeof ms_info);
679     ms_info.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
680     ms_info.rasterizationSamples = num_samples;
681
682     /* VkStencilOpState */
683     /* The default values for ES are taken by Topi Pohjolainen's code */
684     /* defaults in OpenGL ES 3.1 */
685     memset(&front, 0, sizeof front);
686     front.compareMask = ~0;
687     front.writeMask = ~0;
688     front.reference = 0;
689
690     memset(&back, 0, sizeof back);
691     back.compareMask = ~0;
692     back.writeMask = ~0;
693     back.reference = 0;
694
695     /* VkPipelineDepthStencilStateCreateInfo */
696     memset(&ds_info, 0, sizeof ds_info);
697     ds_info.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
698     ds_info.front = front;
699     ds_info.back = back;
700     /* defaults in OpenGL ES 3.1 */
701     ds_info.minDepthBounds = 0;
702     ds_info.maxDepthBounds = 1;
703     /* z buffer, stencil buffer */
704     if (enable_depth) {
705         ds_info.depthTestEnable = VK_TRUE;
706         ds_info.depthWriteEnable = VK_TRUE;
707         ds_info.depthCompareOp = VK_COMPARE_OP_LESS;
708     }
709     if (enable_stencil) {
710         ds_info.stencilTestEnable = VK_TRUE;
711         ds_info.depthTestEnable = VK_FALSE;
712         ds_info.depthWriteEnable = VK_TRUE;
713     }
714
715     /* we only care about the passOp here */
716     ds_info.back.compareOp = VK_COMPARE_OP_ALWAYS;
717     ds_info.back.failOp = VK_STENCIL_OP_REPLACE;
718     ds_info.back.depthFailOp = VK_STENCIL_OP_REPLACE;
719     ds_info.back.passOp = VK_STENCIL_OP_REPLACE;
720     ds_info.back.compareMask = 0xffffffff;
721     ds_info.back.writeMask = 0xffffffff;
722     ds_info.back.reference = 1;
723     ds_info.front = ds_info.back;
724
725     /* VkPipelineColorBlendAttachmentState */
726     memset(&cb_att_state[0], 0, sizeof cb_att_state[0]);
727     cb_att_state[0].colorWriteMask = (VK_COLOR_COMPONENT_R_BIT |
728                                       VK_COLOR_COMPONENT_G_BIT |
729                                       VK_COLOR_COMPONENT_B_BIT |
730                                       VK_COLOR_COMPONENT_A_BIT);
731
732     /* VkPipelineColorBlendStateCreateInfo */
733     memset(&cb_info, 0, sizeof cb_info);
734     cb_info.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
735     cb_info.attachmentCount = 1;
736     cb_info.pAttachments = cb_att_state;
737     /* default in ES 3.1 */
738     for (i = 0; i < 4; i++) {
739         cb_info.blendConstants[i] = 0.0f;
740     }
741
742     /* VkPipelineShaderStageCreateInfo */
743     memset(sdr_stages, 0, 2 * sizeof sdr_stages[0]);
744
745     sdr_stages[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
746     sdr_stages[0].stage = VK_SHADER_STAGE_VERTEX_BIT;
747     sdr_stages[0].module = renderer->vs;
748     sdr_stages[0].pName = "main";
749
750     sdr_stages[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
751     sdr_stages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT;
752     sdr_stages[1].module = renderer->fs;
753     sdr_stages[1].pName = "main";
754
755     /* VkPushConstantRange */
756     memset(pc_range, 0, sizeof pc_range[0]);
757     pc_range[0].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
758     pc_range[0].size = sizeof (struct vk_dims); /* w, h */
759
760     /* VkPipelineLayoutCreateInfo */
761     memset(&layout_info, 0, sizeof layout_info);
762     layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
763     layout_info.pushConstantRangeCount = 1;
764     layout_info.pPushConstantRanges = pc_range;
765
766     if (vkCreatePipelineLayout(ctx->dev, &layout_info, 0, &pipeline_layout) != VK_SUCCESS) {
767         fprintf(stderr, "Failed to create pipeline layout\n");
768         renderer->pipeline = VK_NULL_HANDLE;
769         return;
770     }
771
772     renderer->pipeline_layout = pipeline_layout;
773
774     /* VkGraphicsPipelineCreateInfo */
775     memset(&pipeline_info, 0, sizeof pipeline_info);
776     pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
777     pipeline_info.layout = pipeline_layout;
778     pipeline_info.renderPass = renderer->renderpass;
779     pipeline_info.pVertexInputState = &vert_input_info;
780     pipeline_info.pInputAssemblyState = &asm_info;
781     pipeline_info.pViewportState = &viewport_info;
782     pipeline_info.pRasterizationState = &rs_info;
783     pipeline_info.pMultisampleState = &ms_info;
784     pipeline_info.pDepthStencilState = &ds_info;
785     pipeline_info.pColorBlendState = &cb_info;
786     pipeline_info.stageCount = 2;
787     pipeline_info.pStages = sdr_stages;
788
789     if (vkCreateGraphicsPipelines(ctx->dev, 0, 1,
790                                   &pipeline_info, 0,
791                                   &renderer->pipeline) != VK_SUCCESS) {
792         fprintf(stderr, "Failed to create graphics pipeline.\n");
793         renderer->pipeline = VK_NULL_HANDLE;
794     }
795 }
796
797 static VkCommandBuffer
798 create_cmd_buf(VkDevice dev, VkCommandPool cmd_pool)
799 {
800     VkCommandBuffer cmd_buf;
801     VkCommandBufferAllocateInfo alloc_info;
802
803     memset(&alloc_info, 0, sizeof alloc_info);
804     alloc_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
805     alloc_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
806     alloc_info.commandBufferCount = 1;
807     alloc_info.commandPool = cmd_pool;
808
809     if (vkAllocateCommandBuffers(dev, &alloc_info, &cmd_buf) != VK_SUCCESS)
810         return 0;
811
812     return cmd_buf;
813 }
814
815 static uint32_t
816 get_memory_type_idx(VkPhysicalDevice pdev,
817             const VkMemoryRequirements *mem_reqs,
818             VkMemoryPropertyFlagBits prop_flags)
819 {
820     VkPhysicalDeviceMemoryProperties pdev_mem_props;
821     uint32_t i;
822
823     vkGetPhysicalDeviceMemoryProperties(pdev, &pdev_mem_props);
824
825     for (i = 0; i < pdev_mem_props.memoryTypeCount; i++) {
826         const VkMemoryType *type = &pdev_mem_props.memoryTypes[i];
827
828         if ((mem_reqs->memoryTypeBits & (1 << i)) &&
829             (type->propertyFlags & prop_flags) == prop_flags) {
830             return i;
831             break;
832         }
833     }
834     return UINT32_MAX;
835 }
836
837 static VkDeviceMemory
838 alloc_memory(struct vk_ctx *ctx,
839              bool is_external,
840              const VkMemoryRequirements *mem_reqs,
841              VkImage image,
842              VkBuffer buffer,
843              VkMemoryPropertyFlagBits prop_flags)
844 {
845     VkExportMemoryAllocateInfo exp_mem_info;
846     VkMemoryAllocateInfo mem_alloc_info;
847     VkDeviceMemory mem;
848     VkMemoryDedicatedAllocateInfoKHR ded_info;
849
850     if (is_external) {
851         memset(&exp_mem_info, 0, sizeof exp_mem_info);
852         exp_mem_info.sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO;
853         exp_mem_info.handleTypes =
854             VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
855     }
856
857     memset(&mem_alloc_info, 0, sizeof mem_alloc_info);
858     mem_alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
859     mem_alloc_info.pNext = &exp_mem_info;
860     mem_alloc_info.allocationSize = mem_reqs->size;
861     mem_alloc_info.memoryTypeIndex =
862         get_memory_type_idx(ctx->pdev, mem_reqs, prop_flags);
863
864     if (mem_alloc_info.memoryTypeIndex == UINT32_MAX) {
865         fprintf(stderr, "No suitable memory type index found.\n");
866         return 0;
867     }
868
869     if (image || buffer) {
870         memset(&ded_info, 0, sizeof ded_info);
871         ded_info.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO;
872         ded_info.image = image;
873         ded_info.buffer = buffer;
874
875         exp_mem_info.pNext = &ded_info;
876     }
877
878     if (vkAllocateMemory(ctx->dev, &mem_alloc_info, 0, &mem) !=
879         VK_SUCCESS)
880         return 0;
881
882     return mem;
883 }
884
885 static bool
886 alloc_image_memory(struct vk_ctx *ctx, struct vk_image_obj *img_obj)
887 {
888     VkMemoryDedicatedRequirements ded_reqs;
889     VkImageMemoryRequirementsInfo2 req_info2;
890     VkMemoryRequirements2 mem_reqs2;
891
892     memset(&ded_reqs, 0, sizeof ded_reqs);
893     ded_reqs.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS;
894
895     /* VkImageMemoryRequirementsInfo2 */
896     memset(&req_info2, 0, sizeof req_info2);
897     req_info2.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2;
898     req_info2.image = img_obj->img;
899
900     /* VkMemoryRequirements2 */
901     memset(&mem_reqs2, 0, sizeof mem_reqs2);
902     mem_reqs2.sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2;
903     mem_reqs2.pNext = &ded_reqs;
904
905     vkGetImageMemoryRequirements2(ctx->dev, &req_info2, &mem_reqs2);
906     img_obj->mobj.mem = alloc_memory(ctx,
907                                      true, /* is_external = FIXME */
908                                      &mem_reqs2.memoryRequirements,
909                                      ded_reqs.requiresDedicatedAllocation ?
910                                         img_obj->img : VK_NULL_HANDLE,
911                                      VK_NULL_HANDLE,
912                                      mem_reqs2.memoryRequirements.memoryTypeBits &
913                                         VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
914
915     img_obj->mobj.mem_sz = mem_reqs2.memoryRequirements.size;
916     img_obj->mobj.dedicated = ded_reqs.requiresDedicatedAllocation;
917     if (img_obj->mobj.mem == VK_NULL_HANDLE) {
918         fprintf(stderr, "Failed to allocate image memory.\n");
919         return false;
920     }
921
922     if (vkBindImageMemory(ctx->dev, img_obj->img, img_obj->mobj.mem, 0) !=
923             VK_SUCCESS) {
924         fprintf(stderr, "Failed to bind image memory.\n");
925         return false;
926     }
927
928     return true;
929 }
930
931 static bool
932 are_props_supported(struct vk_ctx *ctx, struct vk_image_props *props)
933 {
934     VkPhysicalDeviceExternalImageFormatInfo ext_img_fmt_info;
935     VkExternalImageFormatProperties ext_img_fmt_props;
936
937     int i;
938     VkPhysicalDeviceImageFormatInfo2 img_fmt_info;
939     VkImageFormatProperties2 img_fmt_props;
940     VkImageUsageFlagBits all_flags[] = {
941         VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
942         VK_IMAGE_USAGE_TRANSFER_DST_BIT,
943         VK_IMAGE_USAGE_SAMPLED_BIT,
944         VK_IMAGE_USAGE_STORAGE_BIT,
945         VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
946         VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
947         VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT,
948         /* Shouldn't be used together with COLOR, DEPTH_STENCIL
949          * attachment bits:
950          * VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT,
951          * Provided by VK_EXT_fragment_density_map
952          * VK_IMAGE_USAGE_FRAGMENT_DENSITY_MAP_BIT_EXT,
953          * Provided by VK_NV_shading_rate_image
954          * VK_IMAGE_USAGE_SHADING_RATE_IMAGE_BIT_NV,
955          * Provided by VK_KHR_fragment_shading_rate
956          * VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR,
957          */
958     };
959     VkImageUsageFlagBits flags = 0;
960
961     VkExternalMemoryFeatureFlagBits export_feature_flags =
962         VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT;
963     VkExternalMemoryHandleTypeFlagBits handle_type =
964         VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;
965
966     memset(&ext_img_fmt_info, 0, sizeof ext_img_fmt_info);
967     ext_img_fmt_info.sType =
968         VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO;
969     ext_img_fmt_info.handleType = handle_type;
970
971     memset(&ext_img_fmt_props, 0, sizeof ext_img_fmt_props);
972     ext_img_fmt_props.sType =
973         VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES;
974
975     memset(&img_fmt_props, 0, sizeof img_fmt_props);
976     img_fmt_props.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2;
977     img_fmt_props.pNext = &ext_img_fmt_props;
978
979     memset(&img_fmt_info, 0, sizeof img_fmt_info);
980     img_fmt_info.sType =
981         VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2;
982     img_fmt_info.pNext = &ext_img_fmt_info;
983     img_fmt_info.format = props->format;
984     img_fmt_info.type = get_image_type(props->h, props->depth);
985     img_fmt_info.tiling = props->tiling;
986
987     for (i = 0; i < ARRAY_SIZE(all_flags); i++) {
988         img_fmt_info.usage = all_flags[i];
989         if (vkGetPhysicalDeviceImageFormatProperties2(ctx->pdev,
990                     &img_fmt_info,
991                     &img_fmt_props) == VK_SUCCESS) {
992             flags |= all_flags[i];
993         }
994     }
995
996     /* usage can't be null */
997     if (flags) {
998         img_fmt_info.usage = flags;
999     }
1000     else {
1001         fprintf(stderr, "Unsupported Vulkan format properties: usage.\n");
1002         return false;
1003     }
1004
1005     if (vkGetPhysicalDeviceImageFormatProperties2
1006         (ctx->pdev, &img_fmt_info, &img_fmt_props) != VK_SUCCESS) {
1007         fprintf(stderr,
1008             "Unsupported Vulkan format properties.\n");
1009         return false;
1010     }
1011     props->usage = flags;
1012
1013     if (props->need_export &&
1014         !(ext_img_fmt_props.externalMemoryProperties.externalMemoryFeatures
1015             & export_feature_flags)) {
1016         fprintf(stderr, "Unsupported Vulkan external memory features.\n");
1017         return false;
1018     }
1019
1020     return true;
1021 }
1022
1023 /* static swapchain / surf related functions */
1024
1025 static bool
1026 sc_validate_surface(struct vk_ctx *ctx,
1027                  VkSurfaceKHR surf)
1028 {
1029     VkBool32 supported;
1030     if (!surf) {
1031         fprintf(stderr, "No surface!\n");
1032         return false;
1033     }
1034
1035     if(vkGetPhysicalDeviceSurfaceSupportKHR(ctx->pdev, ctx->qfam_idx, surf, &supported) != VK_SUCCESS) {
1036         fprintf(stderr, "Failed to validate surface.\n");
1037         return false;
1038     }
1039
1040     if (!supported) {
1041         fprintf(stderr, "Invalid surface! Check if the surface with queue family index: %d supports presentation.\n", (int)ctx->qfam_idx);
1042         return false;
1043     }
1044
1045     return true;
1046 }
1047
1048 static bool
1049 sc_select_format(struct vk_ctx *ctx,
1050                  VkSurfaceKHR surf,
1051                  VkSwapchainCreateInfoKHR *s_info)
1052 {
1053     VkSurfaceFormatKHR *formats;
1054     uint32_t num_formats;
1055
1056     if (vkGetPhysicalDeviceSurfaceFormatsKHR(ctx->pdev, surf, &num_formats, 0) != VK_SUCCESS) {
1057         fprintf(stderr, "Failed to get the number of surface formats.\n");
1058         return false;
1059     }
1060
1061     if (!num_formats) {
1062         fprintf(stderr, "No surface formats found.\n");
1063         return false;
1064     }
1065
1066     formats = malloc(num_formats * sizeof *formats);
1067
1068     if (vkGetPhysicalDeviceSurfaceFormatsKHR(ctx->pdev, surf, &num_formats, formats) != VK_SUCCESS) {
1069         fprintf(stderr, "Failed to get the supported surface formats.\n");
1070         return false;
1071     }
1072
1073     if ((num_formats == 1) && (formats[0].format == VK_FORMAT_UNDEFINED)) {
1074         s_info->imageFormat = VK_FORMAT_B8G8R8A8_UNORM;
1075         s_info->imageColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
1076     } else {
1077         s_info->imageFormat = formats[0].format;
1078         s_info->imageColorSpace = formats[0].colorSpace;
1079     }
1080     free(formats);
1081
1082     return true;
1083 }
1084
1085 static bool
1086 sc_select_supported_present_modes(struct vk_ctx *ctx,
1087                                   VkSurfaceKHR surf,
1088                                   bool has_vsync,
1089                                   VkSwapchainCreateInfoKHR *s_info)
1090 {
1091     VkPresentModeKHR *present_modes;
1092     uint32_t num_present_modes;
1093     int i;
1094
1095     /* find supported present modes */
1096     if (vkGetPhysicalDeviceSurfacePresentModesKHR(ctx->pdev, surf, &num_present_modes, 0) != VK_SUCCESS || !num_present_modes) {
1097         fprintf(stderr, "Failed to get the number of the supported presentation modes.\n");
1098         return false;
1099     }
1100
1101     present_modes = malloc(num_present_modes * sizeof *present_modes);
1102     if (vkGetPhysicalDeviceSurfacePresentModesKHR(ctx->pdev, surf, &num_present_modes, present_modes) != VK_SUCCESS) {
1103         fprintf(stderr, "Failed to get the number of supported presentation modes.\n");
1104         return false;
1105     }
1106     if (vkGetPhysicalDeviceSurfacePresentModesKHR(ctx->pdev, surf, &num_present_modes,
1107                                                   present_modes) != VK_SUCCESS) {
1108         fprintf(stderr, "Failed to get the supported presentation modes.\n");
1109         return false;
1110     }
1111
1112     s_info->presentMode = VK_PRESENT_MODE_FIFO_KHR;
1113     if (!has_vsync) {
1114         for (i = 0; i < num_present_modes; i++) {
1115             if (present_modes[i] == VK_PRESENT_MODE_MAILBOX_KHR) {
1116                 s_info->presentMode = present_modes[i];
1117                 goto success;
1118             }
1119             if (present_modes[i] == VK_PRESENT_MODE_IMMEDIATE_KHR) {
1120                 s_info->presentMode = present_modes[i];
1121                 goto success;
1122             }
1123         }
1124     }
1125
1126 success:
1127     free(present_modes);
1128     return true;
1129 }
1130
1131 /* end of static functions */
1132
1133 /* exposed Vulkan functions */
1134
1135 bool
1136 vk_init_ctx(struct vk_ctx *ctx)
1137 {
1138     if ((ctx->inst = create_instance(enable_layers)) == VK_NULL_HANDLE) {
1139         fprintf(stderr, "Failed to create Vulkan instance.\n");
1140         goto fail;
1141     }
1142
1143     if ((ctx->pdev = select_physical_device(ctx->inst)) == VK_NULL_HANDLE) {
1144         fprintf(stderr, "Failed to find suitable physical device.\n");
1145         goto fail;
1146     }
1147
1148     if ((ctx->dev = create_device(ctx, ctx->pdev)) == VK_NULL_HANDLE) {
1149         fprintf(stderr, "Failed to create Vulkan device.\n");
1150         goto fail;
1151     }
1152
1153     fill_uuid(ctx->pdev, ctx->deviceUUID, ctx->driverUUID);
1154     return true;
1155
1156 fail:
1157     vk_cleanup_ctx(ctx);
1158     return false;
1159 }
1160
1161 bool
1162 vk_init_ctx_for_rendering(struct vk_ctx *ctx)
1163 {
1164     if (!vk_init_ctx(ctx)) {
1165         fprintf(stderr, "Failed to initialize Vulkan.\n");
1166         return false;
1167     }
1168
1169     if ((ctx->cmd_pool = create_cmd_pool(ctx)) == VK_NULL_HANDLE) {
1170         fprintf(stderr, "Failed to create command pool.\n");
1171         goto fail;
1172     }
1173
1174     if ((ctx->cmd_buf = create_cmd_buf(ctx->dev, ctx->cmd_pool)) ==
1175                                        VK_NULL_HANDLE) {
1176         fprintf(stderr, "Failed to create command buffer.\n");
1177         goto fail;
1178     }
1179
1180     vkGetDeviceQueue(ctx->dev, ctx->qfam_idx, 0, &ctx->queue);
1181     if (!ctx->queue) {
1182         fprintf(stderr, "Failed to get command queue.\n");
1183         goto fail;
1184     }
1185
1186     return true;
1187
1188 fail:
1189     vk_cleanup_ctx(ctx);
1190     return false;
1191 }
1192
1193 void
1194 vk_cleanup_ctx(struct vk_ctx *ctx)
1195 {
1196     if (enable_layers) {
1197         return;
1198     }
1199
1200     if (ctx->cmd_buf != VK_NULL_HANDLE) {
1201         vkResetCommandBuffer(ctx->cmd_buf,
1202                              VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT);
1203         vkFreeCommandBuffers(ctx->dev, ctx->cmd_pool, 1, &ctx->cmd_buf);
1204         ctx->cmd_buf = VK_NULL_HANDLE;
1205     }
1206
1207     if (ctx->cmd_pool != VK_NULL_HANDLE) {
1208         vkResetCommandPool(ctx->dev, ctx->cmd_pool,
1209                            VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT);
1210         vkDestroyCommandPool(ctx->dev, ctx->cmd_pool, 0);
1211         ctx->cmd_pool = VK_NULL_HANDLE;
1212     }
1213
1214     if (ctx->dev != VK_NULL_HANDLE) {
1215         vkDestroyDevice(ctx->dev, 0);
1216         ctx->dev = VK_NULL_HANDLE;
1217     }
1218
1219     if (ctx->inst != VK_NULL_HANDLE) {
1220         vkDestroyInstance(ctx->inst, 0);
1221         ctx->inst = VK_NULL_HANDLE;
1222     }
1223 }
1224
1225 bool
1226 vk_create_image(struct vk_ctx *ctx,
1227                 struct vk_image_props *props,
1228                 struct vk_image_obj *img)
1229 {
1230     VkImageCreateInfo img_info;
1231
1232     memset(&img_info, 0, sizeof img_info);
1233     img_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
1234     img_info.pNext = 0; /* do something if external */
1235     img_info.imageType = get_image_type(props->h, props->depth);
1236     img_info.format = props->format;
1237     img_info.extent.width = props->w;
1238     img_info.extent.height = props->h;
1239     img_info.extent.depth = props->depth;
1240     img_info.mipLevels = props->num_levels ? props->num_levels : 1;
1241     img_info.arrayLayers = props->num_layers ?
1242                            props->num_layers : VK_SAMPLE_COUNT_1_BIT;
1243     img_info.samples = get_num_samples(props->num_samples);
1244     img_info.tiling = props->tiling;
1245     img_info.usage = props->usage ?
1246                      props->usage : VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
1247     img_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
1248     img_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
1249
1250     if (vkCreateImage(ctx->dev, &img_info, 0, &img->img) != VK_SUCCESS)
1251         goto fail;
1252
1253     if(!alloc_image_memory(ctx, img))
1254         goto fail;
1255
1256     return true;
1257
1258 fail:
1259     fprintf(stderr, "Failed to create external image.\n");
1260     vk_destroy_image(ctx, img);
1261     img->img = VK_NULL_HANDLE;
1262     img->mobj.mem = VK_NULL_HANDLE;
1263     return false;
1264 }
1265
1266 void
1267 vk_destroy_image(struct vk_ctx *ctx, struct vk_image_obj *img_obj)
1268 {
1269     if (img_obj->img != VK_NULL_HANDLE) {
1270         vkDestroyImage(ctx->dev, img_obj->img, 0);
1271         img_obj->img = VK_NULL_HANDLE;
1272     }
1273
1274     if (img_obj->mobj.mem != VK_NULL_HANDLE) {
1275         vkFreeMemory(ctx->dev, img_obj->mobj.mem, 0);
1276         img_obj->mobj.mem = VK_NULL_HANDLE;
1277     }
1278 }
1279
1280 bool
1281 vk_create_ext_image(struct vk_ctx *ctx,
1282                     struct vk_image_props *props, struct vk_image_obj *img)
1283 {
1284     VkExternalMemoryImageCreateInfo ext_img_info;
1285     VkImageCreateInfo img_info;
1286
1287     memset(&ext_img_info, 0, sizeof ext_img_info);
1288     ext_img_info.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO;
1289     ext_img_info.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;
1290
1291     memset(&img_info, 0, sizeof img_info);
1292     img_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
1293     img_info.pNext = &ext_img_info;
1294     img_info.imageType = get_image_type(props->h, props->depth);
1295     img_info.format = props->format;
1296     img_info.extent.width = props->w;
1297     img_info.extent.height = props->h;
1298     img_info.extent.depth = props->depth;
1299     img_info.mipLevels = props->num_levels ? props->num_levels : 1;
1300     img_info.arrayLayers = props->num_layers ? props->num_layers : VK_SAMPLE_COUNT_1_BIT;
1301     img_info.samples = get_num_samples(props->num_samples);
1302     img_info.tiling = props->tiling;
1303     img_info.usage = props->usage;
1304     img_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
1305     img_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
1306     /* issue 17 of EXT_external_objects
1307      * Required in OpenGL implementations that support
1308      * ARB_texture_view, OES_texture_view, EXT_texture_view,
1309      * or OpenGL 4.3 and above.
1310      */
1311     img_info.flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
1312
1313     if (vkCreateImage(ctx->dev, &img_info, 0, &img->img) != VK_SUCCESS)
1314         goto fail;
1315
1316     if(!alloc_image_memory(ctx, img))
1317         goto fail;
1318
1319     return true;
1320
1321 fail:
1322     fprintf(stderr, "Failed to create external image.\n");
1323     vk_destroy_image(ctx, img);
1324     img->img = VK_NULL_HANDLE;
1325     img->mobj.mem = VK_NULL_HANDLE;
1326     return false;
1327 }
1328
1329 bool
1330 vk_fill_ext_image_props(struct vk_ctx *ctx,
1331                         uint32_t w,
1332                         uint32_t h,
1333                         uint32_t d,
1334                         uint32_t num_samples,
1335                         uint32_t num_levels,
1336                         uint32_t num_layers,
1337                         VkFormat format,
1338                         VkImageTiling tiling,
1339                         VkImageLayout in_layout,
1340                         VkImageLayout end_layout,
1341                         bool need_export,
1342                         struct vk_image_props *props)
1343 {
1344     props->w = w;
1345     props->h = h;
1346     props->depth = d;
1347
1348     props->num_samples = num_samples;
1349     props->num_levels = num_levels;
1350     props->num_layers = num_layers;
1351
1352     props->format = format;
1353     props->tiling = tiling;
1354
1355     props->in_layout = in_layout;
1356     props->end_layout = end_layout;
1357     props->need_export = need_export;
1358
1359     if (!are_props_supported(ctx, props))
1360         return false;
1361
1362     return true;
1363 }
1364
1365 bool
1366 vk_create_renderer(struct vk_ctx *ctx,
1367                    const char *vs_src,
1368                    unsigned int vs_size,
1369                    const char *fs_src,
1370                    unsigned int fs_size,
1371                    bool enable_depth,
1372                    bool enable_stencil,
1373                    struct vk_image_att *color_att,
1374                    struct vk_image_att *depth_att,
1375                    struct vk_vertex_info *vert_info,
1376                    struct vk_renderer *renderer)
1377 {
1378     memset(&renderer->vertex_info, 0, sizeof renderer->vertex_info);
1379     if (vert_info)
1380         renderer->vertex_info = *vert_info;
1381
1382     if (!color_att || depth_att) {
1383         fprintf(stderr, "Empty attachment.\n");
1384         goto fail;
1385     }
1386
1387     renderer->renderpass = create_renderpass(ctx, &color_att->props,
1388                                              &depth_att->props);
1389     if (renderer->renderpass == VK_NULL_HANDLE)
1390         goto fail;
1391
1392     create_framebuffer(ctx, color_att, depth_att, renderer);
1393     if (renderer->fb == VK_NULL_HANDLE)
1394         goto fail;
1395
1396     renderer->vs = create_shader_module(ctx, vs_src, vs_size);
1397     if (renderer->vs == VK_NULL_HANDLE)
1398         goto fail;
1399
1400     renderer->fs = create_shader_module(ctx, fs_src, fs_size);
1401     if (renderer->fs == VK_NULL_HANDLE)
1402         goto fail;
1403
1404     create_pipeline(ctx, color_att->props.w, color_att->props.h,
1405                     color_att->props.num_samples, enable_depth,
1406                     enable_stencil, renderer);
1407
1408     if (renderer->pipeline == VK_NULL_HANDLE)
1409         goto fail;
1410
1411     return true;
1412
1413 fail:
1414     fprintf(stderr, "Failed to create graphics pipeline.\n");
1415     vk_destroy_renderer(ctx, renderer);
1416     return false;
1417 }
1418
1419 void
1420 vk_destroy_renderer(struct vk_ctx *ctx,
1421                     struct vk_renderer *renderer)
1422 {
1423     if (renderer->renderpass != VK_NULL_HANDLE) {
1424         vkDestroyRenderPass(ctx->dev, renderer->renderpass, 0);
1425         renderer->renderpass = VK_NULL_HANDLE;
1426     }
1427
1428     if (renderer->vs != VK_NULL_HANDLE) {
1429         vkDestroyShaderModule(ctx->dev, renderer->vs, 0);
1430         renderer->vs = VK_NULL_HANDLE;
1431     }
1432
1433     if (renderer->fs != VK_NULL_HANDLE) {
1434         vkDestroyShaderModule(ctx->dev, renderer->fs, 0);
1435         renderer->fs = VK_NULL_HANDLE;
1436     }
1437
1438     if (renderer->fb != VK_NULL_HANDLE) {
1439         vkDestroyFramebuffer(ctx->dev, renderer->fb, 0);
1440         renderer->fb = VK_NULL_HANDLE;
1441     }
1442
1443     if (renderer->pipeline != VK_NULL_HANDLE) {
1444         vkDestroyPipeline(ctx->dev, renderer->pipeline, 0);
1445         renderer->pipeline = VK_NULL_HANDLE;
1446     }
1447
1448     if (renderer->pipeline_layout != VK_NULL_HANDLE) {
1449         vkDestroyPipelineLayout(ctx->dev, renderer->pipeline_layout, 0);
1450         renderer->pipeline_layout = VK_NULL_HANDLE;
1451     }
1452 }
1453
1454 bool
1455 vk_create_ext_buffer(struct vk_ctx *ctx,
1456                      uint32_t sz,
1457                      VkBufferUsageFlagBits usage,
1458                      struct vk_buf *bo)
1459 {
1460     VkExternalMemoryBufferCreateInfo ext_bo_info;
1461
1462     memset(&ext_bo_info, 0, sizeof ext_bo_info);
1463     ext_bo_info.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO;
1464     ext_bo_info.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;
1465
1466     if (!vk_create_buffer(ctx, true, sz, usage, &ext_bo_info, bo)) {
1467         fprintf(stderr, "Failed to allocate external buffer.\n");
1468         return false;
1469     }
1470
1471     return true;
1472 }
1473
1474 bool
1475 vk_create_buffer(struct vk_ctx *ctx,
1476                  bool is_external,
1477                  uint32_t sz,
1478                  VkBufferUsageFlagBits usage,
1479                  void *pnext,
1480                  struct vk_buf *bo)
1481 {
1482     VkBufferCreateInfo buf_info;
1483     VkMemoryRequirements mem_reqs;
1484
1485     bo->mobj.mem = VK_NULL_HANDLE;
1486     bo->buf = VK_NULL_HANDLE;
1487
1488     /* VkBufferCreateInfo */
1489     memset(&buf_info, 0, sizeof buf_info);
1490     buf_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
1491     buf_info.size = sz;
1492     buf_info.usage = usage;
1493     buf_info.pNext = pnext;
1494     buf_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
1495
1496     if (vkCreateBuffer(ctx->dev, &buf_info, 0, &bo->buf) != VK_SUCCESS)
1497         goto fail;
1498
1499     /* allocate buffer */
1500     vkGetBufferMemoryRequirements(ctx->dev, bo->buf, &mem_reqs);
1501     /* VK_MEMORY_PROPERTY_HOST_COHERENT_BIT bit specifies that the
1502      * host cache management commands vkFlushMappedMemoryRanges and
1503      * vkInvalidateMappedMemoryRanges are not needed to flush host
1504      * writes to the device or make device writes visible to the
1505      * host, respectively. */
1506     bo->mobj.mem = alloc_memory(ctx, is_external, &mem_reqs, VK_NULL_HANDLE,
1507                                 VK_NULL_HANDLE,
1508                                 VK_MEMORY_PROPERTY_HOST_COHERENT_BIT |
1509                                 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
1510
1511     if (bo->mobj.mem == VK_NULL_HANDLE)
1512         goto fail;
1513
1514     bo->mobj.mem_sz = sz;
1515
1516     if (vkBindBufferMemory(ctx->dev, bo->buf, bo->mobj.mem, 0) != VK_SUCCESS) {
1517         fprintf(stderr, "Failed to bind buffer memory.\n");
1518         goto fail;
1519     }
1520
1521     return true;
1522
1523 fail:
1524     fprintf(stderr, "Failed to allocate buffer.\n");
1525     vk_destroy_buffer(ctx, bo);
1526     return false;
1527 }
1528
1529 bool
1530 vk_update_buffer_data(struct vk_ctx *ctx,
1531                       void *data,
1532                       uint32_t data_sz,
1533                       struct vk_buf *bo)
1534 {
1535     void *map;
1536
1537     if (vkMapMemory(ctx->dev, bo->mobj.mem, 0, data_sz, 0, &map) != VK_SUCCESS) {
1538         fprintf(stderr, "Failed to map buffer memory.\n");
1539         goto fail;
1540     }
1541
1542     memcpy(map, data, data_sz);
1543
1544     vkUnmapMemory(ctx->dev, bo->mobj.mem);
1545     return true;
1546
1547 fail:
1548     fprintf(stderr, "Failed to update buffer data. Destroying the buffer.\n");
1549     vk_destroy_buffer(ctx, bo);
1550
1551     return false;
1552 }
1553
1554 void
1555 vk_destroy_buffer(struct vk_ctx *ctx,
1556           struct vk_buf *bo)
1557 {
1558     if (bo->buf != VK_NULL_HANDLE)
1559         vkDestroyBuffer(ctx->dev, bo->buf, 0);
1560
1561     if (bo->mobj.mem != VK_NULL_HANDLE)
1562         vkFreeMemory(ctx->dev, bo->mobj.mem, 0);
1563
1564     bo->mobj.mem_sz = 0;
1565     bo->buf = VK_NULL_HANDLE;
1566     bo->mobj.mem = VK_NULL_HANDLE;
1567 }
1568
1569 void
1570 vk_draw(struct vk_ctx *ctx,
1571         struct vk_buf *vbo,
1572         struct vk_renderer *renderer,
1573         float *vk_fb_color,
1574         uint32_t vk_fb_color_count,
1575         struct vk_semaphores *semaphores,
1576         struct vk_image_att *attachments,
1577         uint32_t n_attachments,
1578         float x, float y,
1579         float w, float h)
1580 {
1581     VkCommandBufferBeginInfo cmd_begin_info;
1582     VkRenderPassBeginInfo rp_begin_info;
1583     VkRect2D rp_area;
1584     VkClearValue clear_values[2];
1585     VkSubmitInfo submit_info;
1586     VkDeviceSize offsets[] = {0};
1587     VkPipelineStageFlagBits stage_flags;
1588     struct vk_dims img_size;
1589
1590     assert(vk_fb_color_count == 4);
1591
1592     /* VkCommandBufferBeginInfo */
1593     memset(&cmd_begin_info, 0, sizeof cmd_begin_info);
1594     cmd_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
1595     cmd_begin_info.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT;
1596
1597     /* VkRect2D render area */
1598     memset(&rp_area, 0, sizeof rp_area);
1599     rp_area.extent.width = (uint32_t)w;
1600     rp_area.extent.height = (uint32_t)h;
1601     rp_area.offset.x = x;
1602     rp_area.offset.y = y;
1603
1604     /* VkClearValue */
1605     memset(&clear_values[0], 0, sizeof clear_values[0]);
1606     clear_values[0].color.float32[0] = vk_fb_color[0]; /* red */
1607     clear_values[0].color.float32[1] = vk_fb_color[1]; /* green */
1608     clear_values[0].color.float32[2] = vk_fb_color[2]; /* blue */
1609     clear_values[0].color.float32[3] = vk_fb_color[3]; /* alpha */
1610
1611     memset(&clear_values[1], 0, sizeof clear_values[1]);
1612     clear_values[1].depthStencil.depth = 1.0;
1613     clear_values[1].depthStencil.stencil = 0;
1614
1615     /* VkRenderPassBeginInfo */
1616     memset(&rp_begin_info, 0, sizeof rp_begin_info);
1617     rp_begin_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
1618     rp_begin_info.renderPass = renderer->renderpass;
1619     rp_begin_info.framebuffer = renderer->fb;
1620     rp_begin_info.renderArea = rp_area;
1621     rp_begin_info.clearValueCount = 2;
1622     rp_begin_info.pClearValues = clear_values;
1623
1624     /* VkSubmitInfo */
1625     stage_flags = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT;
1626
1627     memset(&submit_info, 0, sizeof submit_info);
1628     submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
1629     submit_info.commandBufferCount = 1;
1630     submit_info.pCommandBuffers = &ctx->cmd_buf;
1631
1632     /* semaphores */
1633     if (semaphores) {
1634         assert(semaphores->frame_ready);
1635         assert(semaphores->frame_done);
1636
1637         submit_info.pWaitDstStageMask = &stage_flags;
1638         submit_info.waitSemaphoreCount = 1;
1639         submit_info.pWaitSemaphores = &semaphores->frame_done;
1640
1641         submit_info.signalSemaphoreCount = 1;
1642         submit_info.pSignalSemaphores = &semaphores->frame_ready;
1643     }
1644
1645     vkBeginCommandBuffer(ctx->cmd_buf, &cmd_begin_info);
1646     vkCmdBeginRenderPass(ctx->cmd_buf, &rp_begin_info, VK_SUBPASS_CONTENTS_INLINE);
1647
1648     viewport.x = x;
1649     viewport.y = y;
1650     viewport.width = w;
1651     viewport.height = h;
1652
1653     scissor.offset.x = x;
1654     scissor.offset.y = y;
1655     scissor.extent.width = w;
1656     scissor.extent.height = h;
1657
1658     vkCmdSetViewport(ctx->cmd_buf, 0, 1, &viewport);
1659     vkCmdSetScissor(ctx->cmd_buf, 0, 1, &scissor);
1660
1661     img_size.w = (float)w;
1662     img_size.h = (float)h;
1663     vkCmdPushConstants(ctx->cmd_buf,
1664                renderer->pipeline_layout,
1665                VK_SHADER_STAGE_FRAGMENT_BIT,
1666                0, sizeof (struct vk_dims),
1667                &img_size);
1668
1669     if (vbo) {
1670         vkCmdBindVertexBuffers(ctx->cmd_buf, 0, 1, &vbo->buf, offsets);
1671     }
1672     vkCmdBindPipeline(ctx->cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS, renderer->pipeline);
1673
1674     int num_vertices = vbo ? renderer->vertex_info.num_verts : 4;
1675     vkCmdDraw(ctx->cmd_buf, num_vertices, 1, 0, 0);
1676     vkCmdEndRenderPass(ctx->cmd_buf);
1677     if (attachments) {
1678         VkImageMemoryBarrier *barriers =
1679             calloc(n_attachments, sizeof(VkImageMemoryBarrier));
1680         VkImageMemoryBarrier *barrier = barriers;
1681         for (uint32_t n = 0; n < n_attachments; n++, barrier++) {
1682             struct vk_image_att *att = &attachments[n];
1683             VkImageAspectFlagBits depth_stencil_flags =
1684                 get_aspect_from_depth_format(att->props.format);
1685             bool is_depth = (depth_stencil_flags != 0);
1686
1687             /* Insert barrier to mark ownership transfer. */
1688             barrier->sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
1689             barrier->oldLayout = is_depth ?
1690                 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL :
1691                 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
1692             barrier->newLayout = VK_IMAGE_LAYOUT_GENERAL;
1693             barrier->srcAccessMask = get_access_mask(barrier->oldLayout);
1694             barrier->dstAccessMask = get_access_mask(barrier->newLayout);
1695             barrier->srcQueueFamilyIndex = ctx->qfam_idx;
1696             barrier->dstQueueFamilyIndex = VK_QUEUE_FAMILY_EXTERNAL;
1697             barrier->image = att->obj.img;
1698             barrier->subresourceRange.aspectMask = is_depth ?
1699                 depth_stencil_flags :
1700                 VK_IMAGE_ASPECT_COLOR_BIT;
1701             barrier->subresourceRange.baseMipLevel = 0;
1702             barrier->subresourceRange.levelCount = 1;
1703             barrier->subresourceRange.baseArrayLayer = 0;
1704             barrier->subresourceRange.layerCount = 1;
1705         }
1706
1707         vkCmdPipelineBarrier(ctx->cmd_buf,
1708                      VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
1709                      VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
1710                      0,
1711                      0, NULL,
1712                      0, NULL,
1713                      n_attachments, barriers);
1714         free(barriers);
1715     }
1716
1717     vkEndCommandBuffer(ctx->cmd_buf);
1718
1719     if (vkQueueSubmit(ctx->queue, 1, &submit_info, VK_NULL_HANDLE) != VK_SUCCESS) {
1720         fprintf(stderr, "Failed to submit queue.\n");
1721     }
1722
1723     if (!semaphores)
1724         vkQueueWaitIdle(ctx->queue);
1725 }
1726
1727 void
1728 vk_clear_color(struct vk_ctx *ctx,
1729                struct vk_buf *vbo,
1730                struct vk_renderer *renderer,
1731                float *vk_fb_color,
1732                uint32_t vk_fb_color_count,
1733                struct vk_semaphores *semaphores,
1734                bool has_wait, bool has_signal,
1735                struct vk_image_att *attachments,
1736                uint32_t n_attachments,
1737                float x, float y,
1738                float w, float h)
1739 {
1740     VkCommandBufferBeginInfo cmd_begin_info;
1741     VkRenderPassBeginInfo rp_begin_info;
1742     VkRect2D rp_area;
1743     VkClearValue clear_values[2];
1744     VkSubmitInfo submit_info;
1745     VkPipelineStageFlagBits stage_flags;
1746     VkImageSubresourceRange img_range;
1747
1748     assert(vk_fb_color_count == 4);
1749
1750     /* VkCommandBufferBeginInfo */
1751     memset(&cmd_begin_info, 0, sizeof cmd_begin_info);
1752     cmd_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
1753     cmd_begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
1754
1755     /* VkRect2D render area */
1756     memset(&rp_area, 0, sizeof rp_area);
1757     rp_area.extent.width = (uint32_t)w;
1758     rp_area.extent.height = (uint32_t)h;
1759     rp_area.offset.x = x;
1760     rp_area.offset.y = y;
1761
1762     /* VkClearValue */
1763     memset(&clear_values[0], 0, sizeof clear_values[0]);
1764     clear_values[0].color.float32[0] = vk_fb_color[0]; /* red */
1765     clear_values[0].color.float32[1] = vk_fb_color[1]; /* green */
1766     clear_values[0].color.float32[2] = vk_fb_color[2]; /* blue */
1767     clear_values[0].color.float32[3] = vk_fb_color[3]; /* alpha */
1768
1769     memset(&clear_values[1], 0, sizeof clear_values[1]);
1770     clear_values[1].depthStencil.depth = 1.0;
1771     clear_values[1].depthStencil.stencil = 0;
1772
1773     /* VkRenderPassBeginInfo */
1774     memset(&rp_begin_info, 0, sizeof rp_begin_info);
1775     rp_begin_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
1776     rp_begin_info.renderPass = renderer->renderpass;
1777     rp_begin_info.framebuffer = renderer->fb;
1778     rp_begin_info.renderArea = rp_area;
1779     rp_begin_info.clearValueCount = 2;
1780     rp_begin_info.pClearValues = clear_values;
1781
1782     /* VkSubmitInfo */
1783     stage_flags = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT;
1784
1785     memset(&submit_info, 0, sizeof submit_info);
1786     submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
1787     submit_info.commandBufferCount = 1;
1788     submit_info.pCommandBuffers = &ctx->cmd_buf;
1789
1790     /* FIXME */
1791     if (has_wait) {
1792         submit_info.pWaitDstStageMask = &stage_flags;
1793         submit_info.waitSemaphoreCount = 1;
1794         submit_info.pWaitSemaphores = &semaphores->frame_done;
1795     }
1796
1797     if (has_signal) {
1798         submit_info.signalSemaphoreCount = 1;
1799         submit_info.pSignalSemaphores = &semaphores->frame_ready;
1800     }
1801
1802     img_range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
1803     img_range.baseMipLevel = 0;
1804     img_range.levelCount = 1;
1805     img_range.baseArrayLayer = 0;
1806     img_range.layerCount = 1;
1807
1808     vkBeginCommandBuffer(ctx->cmd_buf, &cmd_begin_info);
1809     vk_transition_image_layout(&attachments[0],
1810                                ctx->cmd_buf,
1811                                VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
1812                                VK_IMAGE_LAYOUT_GENERAL,
1813                                VK_QUEUE_FAMILY_EXTERNAL,
1814                                ctx->qfam_idx);
1815     vkCmdClearColorImage(ctx->cmd_buf,
1816                          attachments[0].obj.img,
1817                          VK_IMAGE_LAYOUT_GENERAL,
1818                          &clear_values[0].color,
1819                          1,
1820                          &img_range);
1821
1822     vkCmdBeginRenderPass(ctx->cmd_buf, &rp_begin_info, VK_SUBPASS_CONTENTS_INLINE);
1823
1824     viewport.x = x;
1825     viewport.y = y;
1826     viewport.width = w;
1827     viewport.height = h;
1828
1829     scissor.offset.x = x;
1830     scissor.offset.y = y;
1831     scissor.extent.width = w;
1832     scissor.extent.height = h;
1833
1834     vkCmdSetViewport(ctx->cmd_buf, 0, 1, &viewport);
1835     vkCmdSetScissor(ctx->cmd_buf, 0, 1, &scissor);
1836
1837     vkCmdBindPipeline(ctx->cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS, renderer->pipeline);
1838
1839     vkCmdEndRenderPass(ctx->cmd_buf);
1840
1841     if (attachments) {
1842         VkImageMemoryBarrier *barriers =
1843             calloc(n_attachments, sizeof(VkImageMemoryBarrier));
1844         VkImageMemoryBarrier *barrier = barriers;
1845
1846         for (uint32_t n = 0; n < n_attachments; n++, barrier++) {
1847             struct vk_image_att *att = &attachments[n];
1848
1849             /* Insert barrier to mark ownership transfer. */
1850             barrier->sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
1851
1852             bool is_depth =
1853                 get_aspect_from_depth_format(att->props.format) != VK_NULL_HANDLE;
1854
1855             barrier->oldLayout = is_depth ?
1856                 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL :
1857                 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
1858             barrier->newLayout = VK_IMAGE_LAYOUT_GENERAL;
1859             barrier->srcAccessMask = get_access_mask(barrier->oldLayout);
1860             barrier->dstAccessMask = get_access_mask(barrier->newLayout);
1861             barrier->srcQueueFamilyIndex = ctx->qfam_idx;
1862             barrier->dstQueueFamilyIndex = VK_QUEUE_FAMILY_EXTERNAL;
1863             barrier->image = att->obj.img;
1864             barrier->subresourceRange.aspectMask = is_depth ?
1865                 VK_IMAGE_ASPECT_DEPTH_BIT :
1866                 VK_IMAGE_ASPECT_COLOR_BIT;
1867             barrier->subresourceRange.baseMipLevel = 0;
1868             barrier->subresourceRange.levelCount = 1;
1869             barrier->subresourceRange.baseArrayLayer = 0;
1870             barrier->subresourceRange.layerCount = 1;
1871         }
1872
1873         vkCmdPipelineBarrier(ctx->cmd_buf,
1874                      VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
1875                      VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
1876                      0,
1877                      0, NULL,
1878                      0, NULL,
1879                      n_attachments, barriers);
1880         free(barriers);
1881     }
1882
1883     vkEndCommandBuffer(ctx->cmd_buf);
1884
1885     if (vkQueueSubmit(ctx->queue, 1, &submit_info, VK_NULL_HANDLE) != VK_SUCCESS) {
1886         fprintf(stderr, "Failed to submit queue.\n");
1887     }
1888
1889     if (!semaphores && !has_wait && !has_signal)
1890         vkQueueWaitIdle(ctx->queue);
1891 }
1892
1893 bool
1894 vk_create_swapchain(struct vk_ctx *ctx,
1895                     int width, int height,
1896                     bool has_vsync,
1897                     VkSurfaceKHR surf,
1898                     struct vk_swapchain *old_swapchain,
1899                     struct vk_swapchain *swapchain)
1900 {
1901     VkSurfaceCapabilitiesKHR surf_cap;
1902     VkSwapchainCreateInfoKHR s_info;
1903     VkExtent2D extent;
1904     VkImageSubresourceRange sr;
1905     VkImage *s_images;
1906     int i;
1907
1908     if (!sc_validate_surface(ctx, surf)) {
1909         fprintf(stderr, "Failed to validate surface!\n");
1910         return false;
1911     }
1912
1913     /* get pdevice capabilities
1914      * will need that to determine the swapchain number of images
1915      */
1916     if (vkGetPhysicalDeviceSurfaceCapabilitiesKHR(ctx->pdev, surf, &surf_cap) != VK_SUCCESS) {
1917         fprintf(stderr, "Failed to query surface capabilities.\n");
1918         return false;
1919     }
1920
1921     /* allocate and init an empty struct vk_swapchain */
1922     swapchain = malloc(sizeof *swapchain);
1923     memset(swapchain, 0, sizeof *swapchain);
1924
1925     swapchain->surface = surf;
1926
1927     memset(&s_info, 0, sizeof s_info);
1928     s_info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
1929     s_info.flags = 0;
1930     /* surface format */
1931     if (!sc_select_format(ctx, surf, &s_info)) {
1932         fprintf(stderr, "Failed to determine the surface format.\n");
1933         return false;
1934     }
1935     s_info.surface = surf;
1936
1937     /* number of images */
1938     s_info.minImageCount = surf_cap.minImageCount;
1939     /* swapchain images dims */
1940     {
1941         extent.width = width;
1942         extent.height = height;
1943     }
1944     if (!sc_select_supported_present_modes(ctx, surf, has_vsync, &s_info)) {
1945         s_info.presentMode = VK_PRESENT_MODE_FIFO_KHR;
1946     }
1947     s_info.imageExtent = extent;
1948     s_info.imageArrayLayers = 1;
1949     /* enable color attachment bit and transfer src and transfer dst bits
1950      * too if they are supported */
1951     {
1952         s_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
1953         if (surf_cap.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_SRC_BIT)
1954             s_info.imageUsage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
1955         if (surf_cap.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_DST_BIT)
1956             s_info.imageUsage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
1957     }
1958     s_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
1959     s_info.queueFamilyIndexCount = ctx->qfam_idx;
1960
1961     /* we might want to use this function when we recreate the swapchain too */
1962     s_info.preTransform = surf_cap.supportedTransforms &
1963                             VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR ?
1964                             VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR :
1965                             surf_cap.currentTransform;
1966
1967     /* we could also write a sc_select_supported_composite_alpha
1968      * later but VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR is universally
1969      * supported */
1970     s_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
1971     s_info.clipped = VK_TRUE;
1972     s_info.oldSwapchain = old_swapchain ? old_swapchain->swapchain : 0;
1973
1974     if (vkCreateSwapchainKHR(ctx->dev, &s_info, 0,
1975                              &swapchain->swapchain) != VK_SUCCESS) {
1976         fprintf(stderr, "Failed to create a swapchain.\n");
1977         return false;
1978     }
1979
1980     /* if an existing swapchain is recreated we need to destroy
1981      * the old swapchain and clean up the images */
1982     if (old_swapchain) {
1983         for (i = 0; i < old_swapchain->num_images; i++) {
1984             vkDestroyImageView(ctx->dev, old_swapchain->images[i].image_view, 0);
1985         }
1986         vk_destroy_swapchain(ctx, old_swapchain);
1987     }
1988
1989     /* get the number of swapchain images and the swapchain images
1990      * and store the new swapchain images
1991      */
1992     vkGetSwapchainImagesKHR(ctx->dev, swapchain->swapchain, &swapchain->num_images, 0);
1993     printf("number of swapchain images: %d\n", swapchain->num_images);
1994
1995     /* create images */
1996     s_images = malloc(swapchain->num_images * sizeof(VkImage));
1997     vkGetSwapchainImagesKHR(ctx->dev, swapchain->swapchain, &swapchain->num_images, s_images);
1998
1999     swapchain->image_fmt = s_info.imageFormat;
2000     swapchain->images = malloc(swapchain->num_images * sizeof(struct vk_swap_image_obj));
2001
2002     memset(&sr, 0, sizeof sr);
2003     sr.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
2004     sr.levelCount = 1;
2005     sr.layerCount = 1;
2006
2007     for (i = 0; i < swapchain->num_images; i++) {
2008         swapchain->images[i].image = s_images[i];
2009         if (!(create_image_view(ctx,
2010                                 swapchain->images[i].image,
2011                                 VK_IMAGE_VIEW_TYPE_2D,
2012                                 swapchain->image_fmt,
2013                                 sr,
2014                                 true,
2015                                 &swapchain->images[i].image_view))) {
2016             fprintf(stderr, "Fail to create an image view from the swapchain image: i=%d\n", i);
2017             break;
2018         }
2019         if (i < swapchain->num_images - 1) {
2020             int j;
2021             for (j = 0; j < i; j++) {
2022                 vkDestroyImageView(ctx->dev, swapchain->images[i].image_view, 0);
2023             }
2024             return false;
2025         }
2026     }
2027
2028     free(s_images);
2029     return true;
2030 }
2031
2032 void
2033 vk_destroy_swapchain(struct vk_ctx *ctx,
2034                      struct vk_swapchain *swapchain)
2035 {
2036     vkDestroySwapchainKHR(ctx->dev, swapchain->swapchain, 0);
2037     vkDestroySurfaceKHR(ctx->inst, swapchain->surface, 0);
2038
2039     free(swapchain);
2040     swapchain = 0;
2041 }
2042
2043 void
2044 vk_copy_image_to_buffer(struct vk_ctx *ctx,
2045                         struct vk_image_att *src_img,
2046                         struct vk_buf *dst_bo,
2047                         float w, float h)
2048 {
2049     VkCommandBufferBeginInfo cmd_begin_info;
2050     VkSubmitInfo submit_info;
2051     VkImageAspectFlagBits aspect_mask = get_aspect_from_depth_format(src_img->props.format);
2052
2053     /* VkCommandBufferBeginInfo */
2054     memset(&cmd_begin_info, 0, sizeof cmd_begin_info);
2055     cmd_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
2056     cmd_begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
2057
2058     memset(&submit_info, 0, sizeof submit_info);
2059     submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
2060     submit_info.commandBufferCount = 1;
2061     submit_info.pCommandBuffers = &ctx->cmd_buf;
2062
2063     vkBeginCommandBuffer(ctx->cmd_buf, &cmd_begin_info);
2064     if (src_img->props.end_layout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL && dst_bo) {
2065         vk_transition_image_layout(src_img,
2066                                    ctx->cmd_buf,
2067                                    VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
2068                                    VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
2069                                    VK_QUEUE_FAMILY_EXTERNAL,
2070                                    ctx->qfam_idx);
2071
2072         /* copy image to buf */
2073         VkBufferImageCopy copy_region = {
2074             .bufferOffset = 0,
2075             .bufferRowLength = w,
2076             .bufferImageHeight = h,
2077             .imageSubresource = {
2078                 .aspectMask = aspect_mask ? aspect_mask
2079                               : VK_IMAGE_ASPECT_COLOR_BIT,
2080                 .mipLevel = 0,
2081                 .baseArrayLayer = 0,
2082                 .layerCount = 1,
2083             },
2084             .imageOffset = { 0, 0, 0 },
2085             .imageExtent = { w, h, 1 }
2086                 };
2087
2088         vkCmdCopyImageToBuffer(ctx->cmd_buf,
2089                                src_img->obj.img,
2090                                VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
2091                                dst_bo->buf, 1, &copy_region);
2092
2093         vk_transition_image_layout(src_img,
2094                                    ctx->cmd_buf,
2095                                    VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
2096                                    VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
2097                                    VK_QUEUE_FAMILY_EXTERNAL,
2098                                    ctx->qfam_idx);
2099
2100         VkBufferMemoryBarrier write_finish_buffer_memory_barrier = {
2101             .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
2102             .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
2103             .dstAccessMask = VK_ACCESS_HOST_READ_BIT,
2104             .srcQueueFamilyIndex = VK_QUEUE_FAMILY_EXTERNAL,
2105             .dstQueueFamilyIndex = ctx->qfam_idx,
2106             .buffer = dst_bo->buf,
2107             .offset = 0,
2108             .size = VK_WHOLE_SIZE
2109         };
2110
2111         vkCmdPipelineBarrier(ctx->cmd_buf,
2112                              VK_PIPELINE_STAGE_TRANSFER_BIT,
2113                              VK_PIPELINE_STAGE_HOST_BIT,
2114                              (VkDependencyFlags) 0, 0, NULL,
2115                              1, &write_finish_buffer_memory_barrier,
2116                              0, NULL);
2117     }
2118     vkEndCommandBuffer(ctx->cmd_buf);
2119
2120     if (vkQueueSubmit(ctx->queue, 1, &submit_info, VK_NULL_HANDLE) != VK_SUCCESS) {
2121         fprintf(stderr, "Failed to submit queue.\n");
2122     }
2123     vkQueueWaitIdle(ctx->queue);
2124 }
2125
2126 // FIXME: external
2127 bool
2128 vk_create_semaphores(struct vk_ctx *ctx,
2129                      bool is_external,
2130                      struct vk_semaphores *semaphores)
2131 {
2132     VkSemaphoreCreateInfo sema_info;
2133     VkExportSemaphoreCreateInfo exp_sema_info;
2134
2135     if (is_external) {
2136         /* VkExportSemaphoreCreateInfo */
2137         memset(&exp_sema_info, 0, sizeof exp_sema_info);
2138         exp_sema_info.sType = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO;
2139         exp_sema_info.handleTypes = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT;
2140     }
2141
2142     /* VkSemaphoreCreateInfo */
2143     memset(&sema_info, 0, sizeof sema_info);
2144     sema_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
2145     sema_info.pNext = is_external ? &exp_sema_info : 0;
2146
2147     if (vkCreateSemaphore(ctx->dev, &sema_info, 0, &semaphores->frame_ready) != VK_SUCCESS) {
2148         fprintf(stderr, "Failed to create semaphore frame_ready.\n");
2149         return false;
2150     }
2151
2152     if (vkCreateSemaphore(ctx->dev, &sema_info, 0, &semaphores->frame_done) != VK_SUCCESS) {
2153         fprintf(stderr, "Failed to create semaphore frame_done.\n");
2154         return false;
2155     }
2156
2157     return true;
2158 }
2159
2160 void
2161 vk_destroy_semaphores(struct vk_ctx *ctx,
2162                       struct vk_semaphores *semaphores)
2163 {
2164     if (semaphores->frame_ready)
2165         vkDestroySemaphore(ctx->dev, semaphores->frame_ready, 0);
2166     if (semaphores->frame_done)
2167         vkDestroySemaphore(ctx->dev, semaphores->frame_done, 0);
2168 }
2169
2170 void
2171 vk_transition_image_layout(struct vk_image_att *img_att,
2172                VkCommandBuffer cmd_buf,
2173                VkImageLayout old_layout,
2174                VkImageLayout new_layout,
2175                uint32_t src_queue_fam_idx,
2176                uint32_t dst_queue_fam_idx)
2177 {
2178     VkImageMemoryBarrier barrier;
2179     struct vk_image_props props = img_att->props;
2180     VkImageAspectFlagBits aspect_mask = get_aspect_from_depth_format(props.format);
2181
2182     memset(&barrier, 0, sizeof barrier);
2183     barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
2184     barrier.srcAccessMask = get_access_mask(old_layout);
2185     barrier.dstAccessMask = get_access_mask(new_layout);
2186     barrier.oldLayout = old_layout;
2187     barrier.newLayout = new_layout;
2188     barrier.srcQueueFamilyIndex = src_queue_fam_idx;
2189     barrier.dstQueueFamilyIndex = dst_queue_fam_idx;
2190     barrier.image = img_att->obj.img;
2191     barrier.subresourceRange.aspectMask = aspect_mask ? aspect_mask :
2192                                           VK_IMAGE_ASPECT_COLOR_BIT;
2193     barrier.subresourceRange.levelCount = 1;
2194     barrier.subresourceRange.layerCount = 1;
2195
2196     vkCmdPipelineBarrier(cmd_buf,
2197                          get_pipeline_stage_flags(old_layout),
2198                          get_pipeline_stage_flags(new_layout),
2199                          0, 0, VK_NULL_HANDLE, 0, VK_NULL_HANDLE, 1, &barrier);
2200 }