9 static VkViewport viewport;
10 static VkRect2D scissor;
11 static bool enable_layers = true;
13 /* static functions */
15 static VkSampleCountFlagBits
16 get_num_samples(uint32_t num_samples)
20 return VK_SAMPLE_COUNT_64_BIT;
22 return VK_SAMPLE_COUNT_32_BIT;
24 return VK_SAMPLE_COUNT_16_BIT;
26 return VK_SAMPLE_COUNT_8_BIT;
28 return VK_SAMPLE_COUNT_4_BIT;
30 return VK_SAMPLE_COUNT_2_BIT;
34 fprintf(stderr, "Invalid number of samples in VkSampleCountFlagBits. Using one sample.\n");
37 return VK_SAMPLE_COUNT_1_BIT;
40 static VkAccessFlagBits
41 get_access_mask(const VkImageLayout layout)
43 /* dstAccessMask of barriers must be supported from the pipeline
44 * stage, see also access scopes and this table:
45 * https://www.khronos.org/registry/vulkan/specs/1.2-extensions/html/vkspec.html#synchronization-access-types-supported
48 case VK_IMAGE_LAYOUT_UNDEFINED:
50 case VK_IMAGE_LAYOUT_GENERAL:
51 return VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT;
52 case VK_IMAGE_LAYOUT_PREINITIALIZED:
53 return VK_ACCESS_HOST_WRITE_BIT;
54 case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
55 return VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
56 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
57 case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
58 return VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_INPUT_ATTACHMENT_READ_BIT;
59 case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
60 return VK_ACCESS_TRANSFER_READ_BIT;
61 case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
62 return VK_ACCESS_TRANSFER_WRITE_BIT;
63 case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR:
73 enable_validation_layers(VkInstanceCreateInfo *info)
77 VkLayerProperties *layers;
78 static const char *layer_names[] = {
79 "VK_LAYER_KHRONOS_validation",
82 vkEnumerateInstanceLayerProperties(&num_layers, 0);
83 layers = alloca(num_layers * sizeof *layers);
84 vkEnumerateInstanceLayerProperties(&num_layers, layers);
87 printf("Available validation layers:\n");
88 for(i = 0; i < (int)num_layers; i++) {
89 printf(" %s\n", layers[i].layerName);
92 info->ppEnabledLayerNames = layer_names;
93 info->enabledLayerCount = sizeof layer_names / sizeof *layer_names;
95 fprintf(stderr, "Vulkan validation layers not found.\n");
100 enable_extensions(VkInstanceCreateInfo *info)
102 static const char *ext_names[] = {
103 "VK_KHR_xcb_surface",
107 uint32_t num_extensions;
108 VkExtensionProperties *extensions;
111 vkEnumerateInstanceExtensionProperties(0, &num_extensions, 0);
112 if (!num_extensions) {
113 fprintf(stderr, "No instance extensions found.\n");
117 extensions = alloca(num_extensions * sizeof *extensions);
118 vkEnumerateInstanceExtensionProperties(0, &num_extensions, extensions);
120 printf("Available extensions:\n");
121 for (i = 0; i < num_extensions; i++) {
122 printf(" %s\n", extensions[i].extensionName);
125 info->ppEnabledExtensionNames = ext_names;
126 info->enabledExtensionCount = ARRAY_SIZE(ext_names);
130 create_instance(bool enable_layers)
132 VkApplicationInfo app_info;
133 VkInstanceCreateInfo inst_info;
136 /* VkApplicationInfo */
137 memset(&app_info, 0, sizeof app_info);
138 app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
139 app_info.pApplicationName = "vktest";
140 app_info.apiVersion = VK_API_VERSION_1_1;
142 /* VkInstanceCreateInfo */
143 memset(&inst_info, 0, sizeof inst_info);
144 inst_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
145 inst_info.pApplicationInfo = &app_info;
147 enable_extensions(&inst_info);
149 enable_validation_layers(&inst_info);
152 if (vkCreateInstance(&inst_info, 0, &inst) != VK_SUCCESS)
158 static VkPhysicalDevice
159 select_physical_device(VkInstance inst)
161 VkResult res = VK_SUCCESS;
162 uint32_t dev_count = 0;
163 VkPhysicalDevice *pdevices;
164 VkPhysicalDevice pdevice0;
167 vkEnumeratePhysicalDevices(inst, &dev_count, 0)) != VK_SUCCESS)
170 pdevices = malloc(dev_count * sizeof(VkPhysicalDevice));
171 if (vkEnumeratePhysicalDevices(inst, &dev_count, pdevices) !=
175 pdevice0 = pdevices[0];
182 create_device(struct vk_ctx *ctx, VkPhysicalDevice pdev)
184 const char *deviceExtensions[] = { "VK_KHR_swapchain" };
185 VkDeviceQueueCreateInfo dev_queue_info;
186 VkDeviceCreateInfo dev_info;
189 VkQueueFamilyProperties *fam_props;
194 vkGetPhysicalDeviceQueueFamilyProperties(pdev, &prop_count, 0);
195 if (prop_count < 0) {
196 fprintf(stderr, "Invalid queue family properties.\n");
200 fam_props = malloc(prop_count * sizeof *fam_props);
201 vkGetPhysicalDeviceQueueFamilyProperties(pdev, &prop_count, fam_props);
203 for (i = 0; i < prop_count; i++) {
204 if (fam_props[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
211 memset(&dev_queue_info, 0, sizeof dev_queue_info);
212 dev_queue_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
213 dev_queue_info.queueFamilyIndex = ctx->qfam_idx;
214 dev_queue_info.queueCount = 1;
215 dev_queue_info.pQueuePriorities = &qprio;
217 memset(&dev_info, 0, sizeof dev_info);
218 dev_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
219 dev_info.queueCreateInfoCount = 1;
220 dev_info.pQueueCreateInfos = &dev_queue_info;
221 dev_info.enabledExtensionCount = ARRAY_SIZE(deviceExtensions);
222 dev_info.ppEnabledExtensionNames = deviceExtensions;
224 if (vkCreateDevice(pdev, &dev_info, 0, &dev) != VK_SUCCESS)
231 fill_uuid(VkPhysicalDevice pdev, uint8_t *deviceUUID, uint8_t *driverUUID)
233 VkPhysicalDeviceIDProperties devProp;
234 VkPhysicalDeviceProperties2 prop2;
236 memset(&devProp, 0, sizeof devProp);
237 devProp.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES;
239 memset(&prop2, 0, sizeof prop2);
240 prop2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
241 prop2.pNext = &devProp;
243 vkGetPhysicalDeviceProperties2(pdev, &prop2);
244 memcpy(deviceUUID, devProp.deviceUUID, VK_UUID_SIZE);
245 memcpy(driverUUID, devProp.driverUUID, VK_UUID_SIZE);
249 create_cmd_pool(struct vk_ctx *ctx)
251 VkCommandPoolCreateInfo cmd_pool_info;
252 VkCommandPool cmd_pool;
253 VkDevice dev = ctx->dev;
255 memset(&cmd_pool_info, 0, sizeof cmd_pool_info);
256 cmd_pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
257 cmd_pool_info.queueFamilyIndex = ctx->qfam_idx;
258 cmd_pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
260 if (vkCreateCommandPool(dev, &cmd_pool_info, 0, &cmd_pool) != VK_SUCCESS)
267 create_renderpass(struct vk_ctx *ctx,
268 struct vk_image_props *color_img_props,
269 struct vk_image_props *depth_img_props)
271 uint32_t num_attachments = 2;
272 VkAttachmentDescription att_dsc[2];
273 VkAttachmentReference att_rfc[2];
274 VkSubpassDescription subpass_dsc[1];
275 VkRenderPassCreateInfo rpass_info;
277 /* VkAttachmentDescription */
278 memset(att_dsc, 0, num_attachments * sizeof att_dsc[0]);
280 att_dsc[0].samples = get_num_samples(color_img_props->num_samples);
281 att_dsc[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
282 att_dsc[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
283 att_dsc[0].initialLayout = color_img_props->in_layout;
284 att_dsc[0].finalLayout = color_img_props->end_layout;
285 att_dsc[0].format = color_img_props->format;
286 att_dsc[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
287 att_dsc[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
289 att_dsc[1].samples = get_num_samples(depth_img_props->num_samples);
291 /* We might want to reuse a depth buffer */
292 if (depth_img_props->in_layout != VK_IMAGE_LAYOUT_UNDEFINED) {
293 att_dsc[1].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
294 att_dsc[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
297 att_dsc[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
298 att_dsc[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
301 att_dsc[1].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
302 att_dsc[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
303 att_dsc[1].initialLayout = depth_img_props->in_layout;
304 att_dsc[1].finalLayout = depth_img_props->end_layout;
305 att_dsc[1].format = depth_img_props->format;
307 /* VkAttachmentReference */
308 memset(att_rfc, 0, num_attachments * sizeof att_rfc[0]);
310 att_rfc[0].layout = color_img_props->tiling == VK_IMAGE_TILING_OPTIMAL ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_GENERAL;
311 att_rfc[0].attachment = 0;
313 att_rfc[1].layout = depth_img_props->tiling == VK_IMAGE_TILING_OPTIMAL ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_GENERAL;
314 att_rfc[1].attachment = 1;
316 /* VkSubpassDescription */
317 memset(&subpass_dsc, 0, sizeof subpass_dsc);
318 subpass_dsc[0].pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
319 subpass_dsc[0].colorAttachmentCount = 1;
320 subpass_dsc[0].pColorAttachments = &att_rfc[0];
321 subpass_dsc[0].pDepthStencilAttachment = &att_rfc[1];
323 /* VkRenderPassCreateInfo */
324 memset(&rpass_info, 0, sizeof rpass_info);
325 rpass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
326 rpass_info.attachmentCount = num_attachments;
327 rpass_info.pAttachments = att_dsc;
328 rpass_info.subpassCount = 1;
329 rpass_info.pSubpasses = subpass_dsc;
332 if (vkCreateRenderPass(ctx->dev, &rpass_info, 0, &rpass) != VK_SUCCESS) {
333 fprintf(stderr, "Failed to create renderpass.\n");
334 rpass = VK_NULL_HANDLE;
340 static inline VkImageType
341 get_image_type(uint32_t h, uint32_t d)
344 return VK_IMAGE_TYPE_1D;
347 return VK_IMAGE_TYPE_3D;
349 return VK_IMAGE_TYPE_2D;
352 static VkImageViewType
353 get_image_view_type(struct vk_image_props *props)
355 VkImageType type = get_image_type(props->h, props->depth);
357 case VK_IMAGE_TYPE_1D:
358 return props->num_layers > 1 ?
359 VK_IMAGE_VIEW_TYPE_1D_ARRAY :
360 VK_IMAGE_VIEW_TYPE_1D;
361 case VK_IMAGE_TYPE_2D:
362 if (props->num_layers == 1)
363 return VK_IMAGE_VIEW_TYPE_2D;
364 if (props->num_layers == 6)
365 return VK_IMAGE_VIEW_TYPE_CUBE;
366 if (props->num_layers % 6 == 0)
367 return VK_IMAGE_VIEW_TYPE_CUBE_ARRAY;
368 if (props->num_layers > 1)
369 return VK_IMAGE_VIEW_TYPE_2D_ARRAY;
370 case VK_IMAGE_TYPE_3D:
371 if (props->num_layers == 1)
372 return VK_IMAGE_VIEW_TYPE_3D;
373 if ((props->num_layers == 1) &&
374 (props->num_levels == 1))
375 return VK_IMAGE_VIEW_TYPE_2D;
376 if ((props->num_levels == 1) &&
377 (props->num_layers > 1))
378 return VK_IMAGE_VIEW_TYPE_2D_ARRAY;
380 return VK_IMAGE_VIEW_TYPE_2D;
384 static VkImageAspectFlagBits
385 get_aspect_from_depth_format(VkFormat depth_format)
387 switch (depth_format) {
388 case VK_FORMAT_D16_UNORM:
389 case VK_FORMAT_X8_D24_UNORM_PACK32:
390 case VK_FORMAT_D32_SFLOAT:
391 return VK_IMAGE_ASPECT_DEPTH_BIT;
392 case VK_FORMAT_S8_UINT:
393 return VK_IMAGE_ASPECT_STENCIL_BIT;
394 case VK_FORMAT_D16_UNORM_S8_UINT:
395 case VK_FORMAT_D24_UNORM_S8_UINT:
396 case VK_FORMAT_D32_SFLOAT_S8_UINT:
397 return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
404 static VkPipelineStageFlags
405 get_pipeline_stage_flags(const VkImageLayout layout)
408 case VK_IMAGE_LAYOUT_UNDEFINED:
409 return VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
410 case VK_IMAGE_LAYOUT_GENERAL:
411 return VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
412 case VK_IMAGE_LAYOUT_PREINITIALIZED:
413 return VK_PIPELINE_STAGE_HOST_BIT;
414 case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
415 case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
416 return VK_PIPELINE_STAGE_TRANSFER_BIT;
417 case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
418 return VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
419 case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
420 return VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
421 VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
422 case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR:
423 return VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
431 create_framebuffer(struct vk_ctx *ctx,
432 struct vk_image_att *color_att,
433 struct vk_image_att *depth_att,
434 struct vk_renderer *renderer)
436 VkImageSubresourceRange sr;
437 VkImageViewCreateInfo color_info;
438 VkImageViewCreateInfo depth_info;
439 VkFramebufferCreateInfo fb_info;
441 VkImageViewType view_type = get_image_view_type(&color_att->props);
443 if (!color_att->obj.img || !depth_att->obj.img) {
444 fprintf(stderr, "Invalid framebuffer attachment image.\n");
448 /* create image views */
450 /* VKImageSubresourceRange */
451 memset(&sr, 0, sizeof sr);
452 sr.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
453 /* If an application wants to use all mip levels
454 * or layers in an image after the baseMipLevel
455 * or baseArrayLayer, it can set levelCount and
456 * layerCount to the special values
457 * VK_REMAINING_MIP_LEVELS and
458 * VK_REMAINING_ARRAY_LAYERS without knowing the
459 * exact number of mip levels or layers.
462 sr.levelCount = color_att->props.num_levels;
463 sr.baseArrayLayer = 0;
464 sr.layerCount = color_att->props.num_layers;
467 memset(&color_info, 0, sizeof color_info);
468 color_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
469 color_info.image = color_att->obj.img;
470 color_info.viewType = view_type;
471 color_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
472 color_info.format = color_att->props.format;
473 color_info.subresourceRange = sr;
475 if (vkCreateImageView(ctx->dev, &color_info, 0, &color_att->obj.img_view) != VK_SUCCESS) {
476 fprintf(stderr, "Failed to create color image view for framebuffer.\n");
477 vk_destroy_image(ctx, &color_att->obj);
482 memset(&sr, 0, sizeof sr);
483 sr.aspectMask = get_aspect_from_depth_format(depth_att->props.format);
485 sr.levelCount = depth_att->props.num_levels ? depth_att->props.num_levels : 1;
486 sr.baseArrayLayer = 0;
487 sr.layerCount = depth_att->props.num_layers ? depth_att->props.num_layers : 1;
489 memset(&depth_info, 0, sizeof depth_info);
490 depth_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
491 depth_info.image = depth_att->obj.img;
492 depth_info.viewType = depth_att->props.num_layers > 1 ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D;
493 depth_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
494 depth_info.format = depth_att->props.format;
495 depth_info.subresourceRange = sr;
497 if (vkCreateImageView(ctx->dev, &depth_info, 0, &depth_att->obj.img_view) != VK_SUCCESS) {
499 fprintf(stderr, "Failed to create depth image view for framebuffer.\n");
500 vk_destroy_image(ctx, &depth_att->obj);
504 atts[0] = color_att->obj.img_view;
505 atts[1] = depth_att->obj.img_view;
507 memset(&fb_info, 0, sizeof fb_info);
508 fb_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
509 fb_info.renderPass = renderer->renderpass;
510 fb_info.width = color_att->props.w;
511 fb_info.height = color_att->props.h;
512 fb_info.layers = color_att->props.num_layers ? color_att->props.num_layers : 1;
513 fb_info.attachmentCount = 2;
514 fb_info.pAttachments = atts;
516 if (vkCreateFramebuffer(ctx->dev, &fb_info, 0, &renderer->fb) != VK_SUCCESS)
522 fprintf(stderr, "Failed to create framebuffer.\n");
523 renderer->fb = VK_NULL_HANDLE;
526 static VkShaderModule
527 create_shader_module(struct vk_ctx *ctx,
531 VkShaderModuleCreateInfo sm_info;
534 /* VkShaderModuleCreateInfo */
535 memset(&sm_info, 0, sizeof sm_info);
536 sm_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
537 sm_info.codeSize = size;
538 sm_info.pCode = (void*)src;
540 if (vkCreateShaderModule(ctx->dev, &sm_info, 0, &sm) != VK_SUCCESS) {
541 fprintf(stderr, "Failed to create shader module.\n");
549 create_pipeline(struct vk_ctx *ctx,
552 uint32_t num_samples,
555 struct vk_renderer *renderer)
557 VkVertexInputBindingDescription vert_bind_dsc[1];
558 VkVertexInputAttributeDescription vert_att_dsc[1];
560 VkPipelineColorBlendAttachmentState cb_att_state[1];
561 VkPipelineVertexInputStateCreateInfo vert_input_info;
562 VkPipelineInputAssemblyStateCreateInfo asm_info;
563 VkPipelineViewportStateCreateInfo viewport_info;
564 VkPipelineRasterizationStateCreateInfo rs_info;
565 VkPipelineMultisampleStateCreateInfo ms_info;
566 VkPipelineDepthStencilStateCreateInfo ds_info;
567 VkPipelineColorBlendStateCreateInfo cb_info;
568 VkPipelineShaderStageCreateInfo sdr_stages[2];
569 VkPipelineLayoutCreateInfo layout_info;
570 VkGraphicsPipelineCreateInfo pipeline_info;
572 VkFormatProperties fmt_props;
573 VkPushConstantRange pc_range[1];
575 VkStencilOpState front;
576 VkStencilOpState back;
578 VkPipelineLayout pipeline_layout;
581 /* format of vertex attributes:
582 * we have 2D vectors so we need a RG format:
584 * the stride (distance between 2 consecutive elements)
585 * must be 8 because we use 32 bit floats and
587 format = VK_FORMAT_R32G32_SFLOAT;
588 vkGetPhysicalDeviceFormatProperties(ctx->pdev, format, &fmt_props);
589 assert(fmt_props.bufferFeatures & VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT);
592 /* VkVertexInputAttributeDescription */
593 memset(&vert_att_dsc, 0, sizeof vert_att_dsc);
594 vert_att_dsc[0].location = 0;
595 vert_att_dsc[0].binding = 0;
596 vert_att_dsc[0].format = format; /* see comment */
597 vert_att_dsc[0].offset = 0;
599 /* VkVertexInputBindingDescription */
600 memset(&vert_bind_dsc, 0, sizeof vert_bind_dsc);
601 vert_bind_dsc[0].binding = 0;
602 vert_bind_dsc[0].stride = stride;
603 vert_bind_dsc[0].inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
605 /* If using vbo, we have setup vertex_info in the renderer. */
606 bool use_vbo = renderer->vertex_info.num_verts > 0;
608 /* VkPipelineVertexInputStateCreateInfo */
609 memset(&vert_input_info, 0, sizeof vert_input_info);
610 vert_input_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
611 vert_input_info.vertexBindingDescriptionCount = use_vbo ? 1 : 0;
612 vert_input_info.pVertexBindingDescriptions = vert_bind_dsc;
613 vert_input_info.vertexAttributeDescriptionCount = use_vbo ? 1 : 0;
614 vert_input_info.pVertexAttributeDescriptions = vert_att_dsc;
616 /* VkPipelineInputAssemblyStateCreateInfo */
617 memset(&asm_info, 0, sizeof asm_info);
618 asm_info.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
619 asm_info.topology = renderer->vertex_info.topology ?
620 renderer->vertex_info.topology
621 : VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
622 asm_info.primitiveRestartEnable = false;
625 viewport.x = viewport.y = 0;
626 viewport.width = width;
627 viewport.height = height;
628 viewport.minDepth = 0;
629 viewport.maxDepth = 1;
631 /* VkRect2D scissor */
632 scissor.offset.x = scissor.offset.y = 0;
633 scissor.extent.width = width;
634 scissor.extent.height = height;
636 /* VkPipelineViewportStateCreateInfo */
637 memset(&viewport_info, 0, sizeof viewport_info);
638 viewport_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
639 viewport_info.viewportCount = 1;
640 viewport_info.pViewports = &viewport;
641 viewport_info.scissorCount = 1;
642 viewport_info.pScissors = &scissor;
644 /* VkPipelineRasterizationStateCreateInfo */
645 memset(&rs_info, 0, sizeof rs_info);
646 rs_info.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
647 rs_info.polygonMode = VK_POLYGON_MODE_FILL;
648 rs_info.cullMode = VK_CULL_MODE_NONE;
649 rs_info.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
650 rs_info.lineWidth = 1.0;
652 /* VkPipelineMultisampleStateCreateInfo */
653 memset(&ms_info, 0, sizeof ms_info);
654 ms_info.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
655 ms_info.rasterizationSamples = num_samples;
657 /* VkStencilOpState */
658 /* The default values for ES are taken by Topi Pohjolainen's code */
659 /* defaults in OpenGL ES 3.1 */
660 memset(&front, 0, sizeof front);
661 front.compareMask = ~0;
662 front.writeMask = ~0;
665 memset(&back, 0, sizeof back);
666 back.compareMask = ~0;
670 /* VkPipelineDepthStencilStateCreateInfo */
671 memset(&ds_info, 0, sizeof ds_info);
672 ds_info.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
673 ds_info.front = front;
675 /* defaults in OpenGL ES 3.1 */
676 ds_info.minDepthBounds = 0;
677 ds_info.maxDepthBounds = 1;
678 /* z buffer, stencil buffer */
680 ds_info.depthTestEnable = VK_TRUE;
681 ds_info.depthWriteEnable = VK_TRUE;
682 ds_info.depthCompareOp = VK_COMPARE_OP_LESS;
684 if (enable_stencil) {
685 ds_info.stencilTestEnable = VK_TRUE;
686 ds_info.depthTestEnable = VK_FALSE;
687 ds_info.depthWriteEnable = VK_TRUE;
690 /* we only care about the passOp here */
691 ds_info.back.compareOp = VK_COMPARE_OP_ALWAYS;
692 ds_info.back.failOp = VK_STENCIL_OP_REPLACE;
693 ds_info.back.depthFailOp = VK_STENCIL_OP_REPLACE;
694 ds_info.back.passOp = VK_STENCIL_OP_REPLACE;
695 ds_info.back.compareMask = 0xffffffff;
696 ds_info.back.writeMask = 0xffffffff;
697 ds_info.back.reference = 1;
698 ds_info.front = ds_info.back;
700 /* VkPipelineColorBlendAttachmentState */
701 memset(&cb_att_state[0], 0, sizeof cb_att_state[0]);
702 cb_att_state[0].colorWriteMask = (VK_COLOR_COMPONENT_R_BIT |
703 VK_COLOR_COMPONENT_G_BIT |
704 VK_COLOR_COMPONENT_B_BIT |
705 VK_COLOR_COMPONENT_A_BIT);
707 /* VkPipelineColorBlendStateCreateInfo */
708 memset(&cb_info, 0, sizeof cb_info);
709 cb_info.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
710 cb_info.attachmentCount = 1;
711 cb_info.pAttachments = cb_att_state;
712 /* default in ES 3.1 */
713 for (i = 0; i < 4; i++) {
714 cb_info.blendConstants[i] = 0.0f;
717 /* VkPipelineShaderStageCreateInfo */
718 memset(sdr_stages, 0, 2 * sizeof sdr_stages[0]);
720 sdr_stages[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
721 sdr_stages[0].stage = VK_SHADER_STAGE_VERTEX_BIT;
722 sdr_stages[0].module = renderer->vs;
723 sdr_stages[0].pName = "main";
725 sdr_stages[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
726 sdr_stages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT;
727 sdr_stages[1].module = renderer->fs;
728 sdr_stages[1].pName = "main";
730 /* VkPushConstantRange */
731 memset(pc_range, 0, sizeof pc_range[0]);
732 pc_range[0].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
733 pc_range[0].size = sizeof (struct vk_dims); /* w, h */
735 /* VkPipelineLayoutCreateInfo */
736 memset(&layout_info, 0, sizeof layout_info);
737 layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
738 layout_info.pushConstantRangeCount = 1;
739 layout_info.pPushConstantRanges = pc_range;
741 if (vkCreatePipelineLayout(ctx->dev, &layout_info, 0, &pipeline_layout) != VK_SUCCESS) {
742 fprintf(stderr, "Failed to create pipeline layout\n");
743 renderer->pipeline = VK_NULL_HANDLE;
747 renderer->pipeline_layout = pipeline_layout;
749 /* VkGraphicsPipelineCreateInfo */
750 memset(&pipeline_info, 0, sizeof pipeline_info);
751 pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
752 pipeline_info.layout = pipeline_layout;
753 pipeline_info.renderPass = renderer->renderpass;
754 pipeline_info.pVertexInputState = &vert_input_info;
755 pipeline_info.pInputAssemblyState = &asm_info;
756 pipeline_info.pViewportState = &viewport_info;
757 pipeline_info.pRasterizationState = &rs_info;
758 pipeline_info.pMultisampleState = &ms_info;
759 pipeline_info.pDepthStencilState = &ds_info;
760 pipeline_info.pColorBlendState = &cb_info;
761 pipeline_info.stageCount = 2;
762 pipeline_info.pStages = sdr_stages;
764 if (vkCreateGraphicsPipelines(ctx->dev, 0, 1,
766 &renderer->pipeline) != VK_SUCCESS) {
767 fprintf(stderr, "Failed to create graphics pipeline.\n");
768 renderer->pipeline = VK_NULL_HANDLE;
772 static VkCommandBuffer
773 create_cmd_buf(VkDevice dev, VkCommandPool cmd_pool)
775 VkCommandBuffer cmd_buf;
776 VkCommandBufferAllocateInfo alloc_info;
778 memset(&alloc_info, 0, sizeof alloc_info);
779 alloc_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
780 alloc_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
781 alloc_info.commandBufferCount = 1;
782 alloc_info.commandPool = cmd_pool;
784 if (vkAllocateCommandBuffers(dev, &alloc_info, &cmd_buf) != VK_SUCCESS)
791 get_memory_type_idx(VkPhysicalDevice pdev,
792 const VkMemoryRequirements *mem_reqs,
793 VkMemoryPropertyFlagBits prop_flags)
795 VkPhysicalDeviceMemoryProperties pdev_mem_props;
798 vkGetPhysicalDeviceMemoryProperties(pdev, &pdev_mem_props);
800 for (i = 0; i < pdev_mem_props.memoryTypeCount; i++) {
801 const VkMemoryType *type = &pdev_mem_props.memoryTypes[i];
803 if ((mem_reqs->memoryTypeBits & (1 << i)) &&
804 (type->propertyFlags & prop_flags) == prop_flags) {
812 static VkDeviceMemory
813 alloc_memory(struct vk_ctx *ctx,
815 const VkMemoryRequirements *mem_reqs,
818 VkMemoryPropertyFlagBits prop_flags)
820 VkExportMemoryAllocateInfo exp_mem_info;
821 VkMemoryAllocateInfo mem_alloc_info;
823 VkMemoryDedicatedAllocateInfoKHR ded_info;
826 memset(&exp_mem_info, 0, sizeof exp_mem_info);
827 exp_mem_info.sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO;
828 exp_mem_info.handleTypes =
829 VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
832 memset(&mem_alloc_info, 0, sizeof mem_alloc_info);
833 mem_alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
834 mem_alloc_info.pNext = &exp_mem_info;
835 mem_alloc_info.allocationSize = mem_reqs->size;
836 mem_alloc_info.memoryTypeIndex =
837 get_memory_type_idx(ctx->pdev, mem_reqs, prop_flags);
839 if (mem_alloc_info.memoryTypeIndex == UINT32_MAX) {
840 fprintf(stderr, "No suitable memory type index found.\n");
844 if (image || buffer) {
845 memset(&ded_info, 0, sizeof ded_info);
846 ded_info.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO;
847 ded_info.image = image;
848 ded_info.buffer = buffer;
850 exp_mem_info.pNext = &ded_info;
853 if (vkAllocateMemory(ctx->dev, &mem_alloc_info, 0, &mem) !=
861 alloc_image_memory(struct vk_ctx *ctx, struct vk_image_obj *img_obj)
863 VkMemoryDedicatedRequirements ded_reqs;
864 VkImageMemoryRequirementsInfo2 req_info2;
865 VkMemoryRequirements2 mem_reqs2;
867 memset(&ded_reqs, 0, sizeof ded_reqs);
868 ded_reqs.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS;
870 /* VkImageMemoryRequirementsInfo2 */
871 memset(&req_info2, 0, sizeof req_info2);
872 req_info2.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2;
873 req_info2.image = img_obj->img;
875 /* VkMemoryRequirements2 */
876 memset(&mem_reqs2, 0, sizeof mem_reqs2);
877 mem_reqs2.sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2;
878 mem_reqs2.pNext = &ded_reqs;
880 vkGetImageMemoryRequirements2(ctx->dev, &req_info2, &mem_reqs2);
881 img_obj->mobj.mem = alloc_memory(ctx,
882 true, /* is_external = FIXME */
883 &mem_reqs2.memoryRequirements,
884 ded_reqs.requiresDedicatedAllocation ?
885 img_obj->img : VK_NULL_HANDLE,
887 mem_reqs2.memoryRequirements.memoryTypeBits &
888 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
890 img_obj->mobj.mem_sz = mem_reqs2.memoryRequirements.size;
891 img_obj->mobj.dedicated = ded_reqs.requiresDedicatedAllocation;
892 if (img_obj->mobj.mem == VK_NULL_HANDLE) {
893 fprintf(stderr, "Failed to allocate image memory.\n");
897 if (vkBindImageMemory(ctx->dev, img_obj->img, img_obj->mobj.mem, 0) !=
899 fprintf(stderr, "Failed to bind image memory.\n");
907 are_props_supported(struct vk_ctx *ctx, struct vk_image_props *props)
909 VkPhysicalDeviceExternalImageFormatInfo ext_img_fmt_info;
910 VkExternalImageFormatProperties ext_img_fmt_props;
913 VkPhysicalDeviceImageFormatInfo2 img_fmt_info;
914 VkImageFormatProperties2 img_fmt_props;
915 VkImageUsageFlagBits all_flags[] = {
916 VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
917 VK_IMAGE_USAGE_TRANSFER_DST_BIT,
918 VK_IMAGE_USAGE_SAMPLED_BIT,
919 VK_IMAGE_USAGE_STORAGE_BIT,
920 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
921 VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
922 VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT,
923 /* Shouldn't be used together with COLOR, DEPTH_STENCIL
925 * VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT,
926 * Provided by VK_EXT_fragment_density_map
927 * VK_IMAGE_USAGE_FRAGMENT_DENSITY_MAP_BIT_EXT,
928 * Provided by VK_NV_shading_rate_image
929 * VK_IMAGE_USAGE_SHADING_RATE_IMAGE_BIT_NV,
930 * Provided by VK_KHR_fragment_shading_rate
931 * VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR,
934 VkImageUsageFlagBits flags = 0;
936 VkExternalMemoryFeatureFlagBits export_feature_flags =
937 VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT;
938 VkExternalMemoryHandleTypeFlagBits handle_type =
939 VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;
941 memset(&ext_img_fmt_info, 0, sizeof ext_img_fmt_info);
942 ext_img_fmt_info.sType =
943 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO;
944 ext_img_fmt_info.handleType = handle_type;
946 memset(&ext_img_fmt_props, 0, sizeof ext_img_fmt_props);
947 ext_img_fmt_props.sType =
948 VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES;
950 memset(&img_fmt_props, 0, sizeof img_fmt_props);
951 img_fmt_props.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2;
952 img_fmt_props.pNext = &ext_img_fmt_props;
954 memset(&img_fmt_info, 0, sizeof img_fmt_info);
956 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2;
957 img_fmt_info.pNext = &ext_img_fmt_info;
958 img_fmt_info.format = props->format;
959 img_fmt_info.type = get_image_type(props->h, props->depth);
960 img_fmt_info.tiling = props->tiling;
962 for (i = 0; i < ARRAY_SIZE(all_flags); i++) {
963 img_fmt_info.usage = all_flags[i];
964 if (vkGetPhysicalDeviceImageFormatProperties2(ctx->pdev,
966 &img_fmt_props) == VK_SUCCESS) {
967 flags |= all_flags[i];
971 /* usage can't be null */
973 img_fmt_info.usage = flags;
976 fprintf(stderr, "Unsupported Vulkan format properties: usage.\n");
980 if (vkGetPhysicalDeviceImageFormatProperties2
981 (ctx->pdev, &img_fmt_info, &img_fmt_props) != VK_SUCCESS) {
983 "Unsupported Vulkan format properties.\n");
986 props->usage = flags;
988 if (props->need_export &&
989 !(ext_img_fmt_props.externalMemoryProperties.externalMemoryFeatures
990 & export_feature_flags)) {
991 fprintf(stderr, "Unsupported Vulkan external memory features.\n");
998 /* exposed Vulkan functions */
1001 vk_init_ctx(struct vk_ctx *ctx)
1003 if ((ctx->inst = create_instance(enable_layers)) == VK_NULL_HANDLE) {
1004 fprintf(stderr, "Failed to create Vulkan instance.\n");
1008 if ((ctx->pdev = select_physical_device(ctx->inst)) == VK_NULL_HANDLE) {
1009 fprintf(stderr, "Failed to find suitable physical device.\n");
1013 if ((ctx->dev = create_device(ctx, ctx->pdev)) == VK_NULL_HANDLE) {
1014 fprintf(stderr, "Failed to create Vulkan device.\n");
1018 fill_uuid(ctx->pdev, ctx->deviceUUID, ctx->driverUUID);
1022 vk_cleanup_ctx(ctx);
1027 vk_init_ctx_for_rendering(struct vk_ctx *ctx)
1029 if (!vk_init_ctx(ctx)) {
1030 fprintf(stderr, "Failed to initialize Vulkan.\n");
1034 if ((ctx->cmd_pool = create_cmd_pool(ctx)) == VK_NULL_HANDLE) {
1035 fprintf(stderr, "Failed to create command pool.\n");
1039 if ((ctx->cmd_buf = create_cmd_buf(ctx->dev, ctx->cmd_pool)) ==
1041 fprintf(stderr, "Failed to create command buffer.\n");
1045 vkGetDeviceQueue(ctx->dev, ctx->qfam_idx, 0, &ctx->queue);
1047 fprintf(stderr, "Failed to get command queue.\n");
1054 vk_cleanup_ctx(ctx);
1059 vk_cleanup_ctx(struct vk_ctx *ctx)
1061 if (enable_layers) {
1065 if (ctx->cmd_buf != VK_NULL_HANDLE) {
1066 vkResetCommandBuffer(ctx->cmd_buf,
1067 VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT);
1068 vkFreeCommandBuffers(ctx->dev, ctx->cmd_pool, 1, &ctx->cmd_buf);
1069 ctx->cmd_buf = VK_NULL_HANDLE;
1072 if (ctx->cmd_pool != VK_NULL_HANDLE) {
1073 vkResetCommandPool(ctx->dev, ctx->cmd_pool,
1074 VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT);
1075 vkDestroyCommandPool(ctx->dev, ctx->cmd_pool, 0);
1076 ctx->cmd_pool = VK_NULL_HANDLE;
1079 if (ctx->dev != VK_NULL_HANDLE) {
1080 vkDestroyDevice(ctx->dev, 0);
1081 ctx->dev = VK_NULL_HANDLE;
1084 if (ctx->inst != VK_NULL_HANDLE) {
1085 vkDestroyInstance(ctx->inst, 0);
1086 ctx->inst = VK_NULL_HANDLE;
1091 vk_create_image(struct vk_ctx *ctx,
1092 struct vk_image_props *props,
1093 struct vk_image_obj *img)
1095 VkImageCreateInfo img_info;
1097 memset(&img_info, 0, sizeof img_info);
1098 img_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
1099 img_info.pNext = 0; /* do something if external */
1100 img_info.imageType = get_image_type(props->h, props->depth);
1101 img_info.format = props->format;
1102 img_info.extent.width = props->w;
1103 img_info.extent.height = props->h;
1104 img_info.extent.depth = props->depth;
1105 img_info.mipLevels = props->num_levels ? props->num_levels : 1;
1106 img_info.arrayLayers = props->num_layers ?
1107 props->num_layers : VK_SAMPLE_COUNT_1_BIT;
1108 img_info.samples = get_num_samples(props->num_samples);
1109 img_info.tiling = props->tiling;
1110 img_info.usage = props->usage ?
1111 props->usage : VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
1112 img_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
1113 img_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
1115 if (vkCreateImage(ctx->dev, &img_info, 0, &img->img) != VK_SUCCESS)
1118 if(!alloc_image_memory(ctx, img))
1124 fprintf(stderr, "Failed to create external image.\n");
1125 vk_destroy_image(ctx, img);
1126 img->img = VK_NULL_HANDLE;
1127 img->mobj.mem = VK_NULL_HANDLE;
1132 vk_destroy_image(struct vk_ctx *ctx, struct vk_image_obj *img_obj)
1134 if (img_obj->img != VK_NULL_HANDLE) {
1135 vkDestroyImage(ctx->dev, img_obj->img, 0);
1136 img_obj->img = VK_NULL_HANDLE;
1139 if (img_obj->mobj.mem != VK_NULL_HANDLE) {
1140 vkFreeMemory(ctx->dev, img_obj->mobj.mem, 0);
1141 img_obj->mobj.mem = VK_NULL_HANDLE;
1146 vk_create_ext_image(struct vk_ctx *ctx,
1147 struct vk_image_props *props, struct vk_image_obj *img)
1149 VkExternalMemoryImageCreateInfo ext_img_info;
1150 VkImageCreateInfo img_info;
1152 memset(&ext_img_info, 0, sizeof ext_img_info);
1153 ext_img_info.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO;
1154 ext_img_info.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;
1156 memset(&img_info, 0, sizeof img_info);
1157 img_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
1158 img_info.pNext = &ext_img_info;
1159 img_info.imageType = get_image_type(props->h, props->depth);
1160 img_info.format = props->format;
1161 img_info.extent.width = props->w;
1162 img_info.extent.height = props->h;
1163 img_info.extent.depth = props->depth;
1164 img_info.mipLevels = props->num_levels ? props->num_levels : 1;
1165 img_info.arrayLayers = props->num_layers ? props->num_layers : VK_SAMPLE_COUNT_1_BIT;
1166 img_info.samples = get_num_samples(props->num_samples);
1167 img_info.tiling = props->tiling;
1168 img_info.usage = props->usage;
1169 img_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
1170 img_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
1171 /* issue 17 of EXT_external_objects
1172 * Required in OpenGL implementations that support
1173 * ARB_texture_view, OES_texture_view, EXT_texture_view,
1174 * or OpenGL 4.3 and above.
1176 img_info.flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
1178 if (vkCreateImage(ctx->dev, &img_info, 0, &img->img) != VK_SUCCESS)
1181 if(!alloc_image_memory(ctx, img))
1187 fprintf(stderr, "Failed to create external image.\n");
1188 vk_destroy_image(ctx, img);
1189 img->img = VK_NULL_HANDLE;
1190 img->mobj.mem = VK_NULL_HANDLE;
1195 vk_fill_ext_image_props(struct vk_ctx *ctx,
1199 uint32_t num_samples,
1200 uint32_t num_levels,
1201 uint32_t num_layers,
1203 VkImageTiling tiling,
1204 VkImageLayout in_layout,
1205 VkImageLayout end_layout,
1207 struct vk_image_props *props)
1213 props->num_samples = num_samples;
1214 props->num_levels = num_levels;
1215 props->num_layers = num_layers;
1217 props->format = format;
1218 props->tiling = tiling;
1220 props->in_layout = in_layout;
1221 props->end_layout = end_layout;
1222 props->need_export = need_export;
1224 if (!are_props_supported(ctx, props))
1231 vk_create_renderer(struct vk_ctx *ctx,
1233 unsigned int vs_size,
1235 unsigned int fs_size,
1237 bool enable_stencil,
1238 struct vk_image_att *color_att,
1239 struct vk_image_att *depth_att,
1240 struct vk_vertex_info *vert_info,
1241 struct vk_renderer *renderer)
1243 memset(&renderer->vertex_info, 0, sizeof renderer->vertex_info);
1245 renderer->vertex_info = *vert_info;
1247 renderer->renderpass = create_renderpass(ctx, &color_att->props,
1249 if (renderer->renderpass == VK_NULL_HANDLE)
1252 create_framebuffer(ctx, color_att, depth_att, renderer);
1253 if (renderer->fb == VK_NULL_HANDLE)
1256 renderer->vs = create_shader_module(ctx, vs_src, vs_size);
1257 if (renderer->vs == VK_NULL_HANDLE)
1260 renderer->fs = create_shader_module(ctx, fs_src, fs_size);
1261 if (renderer->fs == VK_NULL_HANDLE)
1264 create_pipeline(ctx, color_att->props.w, color_att->props.h,
1265 color_att->props.num_samples, enable_depth,
1266 enable_stencil, renderer);
1268 if (renderer->pipeline == VK_NULL_HANDLE)
1274 fprintf(stderr, "Failed to create graphics pipeline.\n");
1275 vk_destroy_renderer(ctx, renderer);
1280 vk_destroy_renderer(struct vk_ctx *ctx,
1281 struct vk_renderer *renderer)
1283 if (renderer->renderpass != VK_NULL_HANDLE) {
1284 vkDestroyRenderPass(ctx->dev, renderer->renderpass, 0);
1285 renderer->renderpass = VK_NULL_HANDLE;
1288 if (renderer->vs != VK_NULL_HANDLE) {
1289 vkDestroyShaderModule(ctx->dev, renderer->vs, 0);
1290 renderer->vs = VK_NULL_HANDLE;
1293 if (renderer->fs != VK_NULL_HANDLE) {
1294 vkDestroyShaderModule(ctx->dev, renderer->fs, 0);
1295 renderer->fs = VK_NULL_HANDLE;
1298 if (renderer->fb != VK_NULL_HANDLE) {
1299 vkDestroyFramebuffer(ctx->dev, renderer->fb, 0);
1300 renderer->fb = VK_NULL_HANDLE;
1303 if (renderer->pipeline != VK_NULL_HANDLE) {
1304 vkDestroyPipeline(ctx->dev, renderer->pipeline, 0);
1305 renderer->pipeline = VK_NULL_HANDLE;
1308 if (renderer->pipeline_layout != VK_NULL_HANDLE) {
1309 vkDestroyPipelineLayout(ctx->dev, renderer->pipeline_layout, 0);
1310 renderer->pipeline_layout = VK_NULL_HANDLE;
1315 vk_create_ext_buffer(struct vk_ctx *ctx,
1317 VkBufferUsageFlagBits usage,
1320 VkExternalMemoryBufferCreateInfo ext_bo_info;
1322 memset(&ext_bo_info, 0, sizeof ext_bo_info);
1323 ext_bo_info.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO;
1324 ext_bo_info.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;
1326 if (!vk_create_buffer(ctx, true, sz, usage, &ext_bo_info, bo)) {
1327 fprintf(stderr, "Failed to allocate external buffer.\n");
1335 vk_create_buffer(struct vk_ctx *ctx,
1338 VkBufferUsageFlagBits usage,
1342 VkBufferCreateInfo buf_info;
1343 VkMemoryRequirements mem_reqs;
1345 bo->mobj.mem = VK_NULL_HANDLE;
1346 bo->buf = VK_NULL_HANDLE;
1348 /* VkBufferCreateInfo */
1349 memset(&buf_info, 0, sizeof buf_info);
1350 buf_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
1352 buf_info.usage = usage;
1353 buf_info.pNext = pnext;
1354 buf_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
1356 if (vkCreateBuffer(ctx->dev, &buf_info, 0, &bo->buf) != VK_SUCCESS)
1359 /* allocate buffer */
1360 vkGetBufferMemoryRequirements(ctx->dev, bo->buf, &mem_reqs);
1361 /* VK_MEMORY_PROPERTY_HOST_COHERENT_BIT bit specifies that the
1362 * host cache management commands vkFlushMappedMemoryRanges and
1363 * vkInvalidateMappedMemoryRanges are not needed to flush host
1364 * writes to the device or make device writes visible to the
1365 * host, respectively. */
1366 bo->mobj.mem = alloc_memory(ctx, is_external, &mem_reqs, VK_NULL_HANDLE,
1368 VK_MEMORY_PROPERTY_HOST_COHERENT_BIT |
1369 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
1371 if (bo->mobj.mem == VK_NULL_HANDLE)
1374 bo->mobj.mem_sz = sz;
1376 if (vkBindBufferMemory(ctx->dev, bo->buf, bo->mobj.mem, 0) != VK_SUCCESS) {
1377 fprintf(stderr, "Failed to bind buffer memory.\n");
1384 fprintf(stderr, "Failed to allocate buffer.\n");
1385 vk_destroy_buffer(ctx, bo);
1390 vk_update_buffer_data(struct vk_ctx *ctx,
1397 if (vkMapMemory(ctx->dev, bo->mobj.mem, 0, data_sz, 0, &map) != VK_SUCCESS) {
1398 fprintf(stderr, "Failed to map buffer memory.\n");
1402 memcpy(map, data, data_sz);
1404 vkUnmapMemory(ctx->dev, bo->mobj.mem);
1408 fprintf(stderr, "Failed to update buffer data. Destroying the buffer.\n");
1409 vk_destroy_buffer(ctx, bo);
1415 vk_destroy_buffer(struct vk_ctx *ctx,
1418 if (bo->buf != VK_NULL_HANDLE)
1419 vkDestroyBuffer(ctx->dev, bo->buf, 0);
1421 if (bo->mobj.mem != VK_NULL_HANDLE)
1422 vkFreeMemory(ctx->dev, bo->mobj.mem, 0);
1424 bo->mobj.mem_sz = 0;
1425 bo->buf = VK_NULL_HANDLE;
1426 bo->mobj.mem = VK_NULL_HANDLE;
1430 vk_draw(struct vk_ctx *ctx,
1432 struct vk_renderer *renderer,
1434 uint32_t vk_fb_color_count,
1435 struct vk_semaphores *semaphores,
1436 struct vk_image_att *attachments,
1437 uint32_t n_attachments,
1441 VkCommandBufferBeginInfo cmd_begin_info;
1442 VkRenderPassBeginInfo rp_begin_info;
1444 VkClearValue clear_values[2];
1445 VkSubmitInfo submit_info;
1446 VkDeviceSize offsets[] = {0};
1447 VkPipelineStageFlagBits stage_flags;
1448 struct vk_dims img_size;
1450 assert(vk_fb_color_count == 4);
1452 /* VkCommandBufferBeginInfo */
1453 memset(&cmd_begin_info, 0, sizeof cmd_begin_info);
1454 cmd_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
1455 cmd_begin_info.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT;
1457 /* VkRect2D render area */
1458 memset(&rp_area, 0, sizeof rp_area);
1459 rp_area.extent.width = (uint32_t)w;
1460 rp_area.extent.height = (uint32_t)h;
1461 rp_area.offset.x = x;
1462 rp_area.offset.y = y;
1465 memset(&clear_values[0], 0, sizeof clear_values[0]);
1466 clear_values[0].color.float32[0] = vk_fb_color[0]; /* red */
1467 clear_values[0].color.float32[1] = vk_fb_color[1]; /* green */
1468 clear_values[0].color.float32[2] = vk_fb_color[2]; /* blue */
1469 clear_values[0].color.float32[3] = vk_fb_color[3]; /* alpha */
1471 memset(&clear_values[1], 0, sizeof clear_values[1]);
1472 clear_values[1].depthStencil.depth = 1.0;
1473 clear_values[1].depthStencil.stencil = 0;
1475 /* VkRenderPassBeginInfo */
1476 memset(&rp_begin_info, 0, sizeof rp_begin_info);
1477 rp_begin_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
1478 rp_begin_info.renderPass = renderer->renderpass;
1479 rp_begin_info.framebuffer = renderer->fb;
1480 rp_begin_info.renderArea = rp_area;
1481 rp_begin_info.clearValueCount = 2;
1482 rp_begin_info.pClearValues = clear_values;
1485 stage_flags = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT;
1487 memset(&submit_info, 0, sizeof submit_info);
1488 submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
1489 submit_info.commandBufferCount = 1;
1490 submit_info.pCommandBuffers = &ctx->cmd_buf;
1494 assert(semaphores->frame_ready);
1495 assert(semaphores->frame_done);
1497 submit_info.pWaitDstStageMask = &stage_flags;
1498 submit_info.waitSemaphoreCount = 1;
1499 submit_info.pWaitSemaphores = &semaphores->frame_done;
1501 submit_info.signalSemaphoreCount = 1;
1502 submit_info.pSignalSemaphores = &semaphores->frame_ready;
1505 vkBeginCommandBuffer(ctx->cmd_buf, &cmd_begin_info);
1506 vkCmdBeginRenderPass(ctx->cmd_buf, &rp_begin_info, VK_SUBPASS_CONTENTS_INLINE);
1511 viewport.height = h;
1513 scissor.offset.x = x;
1514 scissor.offset.y = y;
1515 scissor.extent.width = w;
1516 scissor.extent.height = h;
1518 vkCmdSetViewport(ctx->cmd_buf, 0, 1, &viewport);
1519 vkCmdSetScissor(ctx->cmd_buf, 0, 1, &scissor);
1521 img_size.w = (float)w;
1522 img_size.h = (float)h;
1523 vkCmdPushConstants(ctx->cmd_buf,
1524 renderer->pipeline_layout,
1525 VK_SHADER_STAGE_FRAGMENT_BIT,
1526 0, sizeof (struct vk_dims),
1530 vkCmdBindVertexBuffers(ctx->cmd_buf, 0, 1, &vbo->buf, offsets);
1532 vkCmdBindPipeline(ctx->cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS, renderer->pipeline);
1534 int num_vertices = vbo ? renderer->vertex_info.num_verts : 4;
1535 vkCmdDraw(ctx->cmd_buf, num_vertices, 1, 0, 0);
1536 vkCmdEndRenderPass(ctx->cmd_buf);
1538 VkImageMemoryBarrier *barriers =
1539 calloc(n_attachments, sizeof(VkImageMemoryBarrier));
1540 VkImageMemoryBarrier *barrier = barriers;
1541 for (uint32_t n = 0; n < n_attachments; n++, barrier++) {
1542 struct vk_image_att *att = &attachments[n];
1543 VkImageAspectFlagBits depth_stencil_flags =
1544 get_aspect_from_depth_format(att->props.format);
1545 bool is_depth = (depth_stencil_flags != 0);
1547 /* Insert barrier to mark ownership transfer. */
1548 barrier->sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
1549 barrier->oldLayout = is_depth ?
1550 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL :
1551 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
1552 barrier->newLayout = VK_IMAGE_LAYOUT_GENERAL;
1553 barrier->srcAccessMask = get_access_mask(barrier->oldLayout);
1554 barrier->dstAccessMask = get_access_mask(barrier->newLayout);
1555 barrier->srcQueueFamilyIndex = ctx->qfam_idx;
1556 barrier->dstQueueFamilyIndex = VK_QUEUE_FAMILY_EXTERNAL;
1557 barrier->image = att->obj.img;
1558 barrier->subresourceRange.aspectMask = is_depth ?
1559 depth_stencil_flags :
1560 VK_IMAGE_ASPECT_COLOR_BIT;
1561 barrier->subresourceRange.baseMipLevel = 0;
1562 barrier->subresourceRange.levelCount = 1;
1563 barrier->subresourceRange.baseArrayLayer = 0;
1564 barrier->subresourceRange.layerCount = 1;
1567 vkCmdPipelineBarrier(ctx->cmd_buf,
1568 VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
1569 VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
1573 n_attachments, barriers);
1577 vkEndCommandBuffer(ctx->cmd_buf);
1579 if (vkQueueSubmit(ctx->queue, 1, &submit_info, VK_NULL_HANDLE) != VK_SUCCESS) {
1580 fprintf(stderr, "Failed to submit queue.\n");
1584 vkQueueWaitIdle(ctx->queue);
1588 vk_clear_color(struct vk_ctx *ctx,
1590 struct vk_renderer *renderer,
1592 uint32_t vk_fb_color_count,
1593 struct vk_semaphores *semaphores,
1594 bool has_wait, bool has_signal,
1595 struct vk_image_att *attachments,
1596 uint32_t n_attachments,
1600 VkCommandBufferBeginInfo cmd_begin_info;
1601 VkRenderPassBeginInfo rp_begin_info;
1603 VkClearValue clear_values[2];
1604 VkSubmitInfo submit_info;
1605 VkPipelineStageFlagBits stage_flags;
1606 VkImageSubresourceRange img_range;
1608 assert(vk_fb_color_count == 4);
1610 /* VkCommandBufferBeginInfo */
1611 memset(&cmd_begin_info, 0, sizeof cmd_begin_info);
1612 cmd_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
1613 cmd_begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
1615 /* VkRect2D render area */
1616 memset(&rp_area, 0, sizeof rp_area);
1617 rp_area.extent.width = (uint32_t)w;
1618 rp_area.extent.height = (uint32_t)h;
1619 rp_area.offset.x = x;
1620 rp_area.offset.y = y;
1623 memset(&clear_values[0], 0, sizeof clear_values[0]);
1624 clear_values[0].color.float32[0] = vk_fb_color[0]; /* red */
1625 clear_values[0].color.float32[1] = vk_fb_color[1]; /* green */
1626 clear_values[0].color.float32[2] = vk_fb_color[2]; /* blue */
1627 clear_values[0].color.float32[3] = vk_fb_color[3]; /* alpha */
1629 memset(&clear_values[1], 0, sizeof clear_values[1]);
1630 clear_values[1].depthStencil.depth = 1.0;
1631 clear_values[1].depthStencil.stencil = 0;
1633 /* VkRenderPassBeginInfo */
1634 memset(&rp_begin_info, 0, sizeof rp_begin_info);
1635 rp_begin_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
1636 rp_begin_info.renderPass = renderer->renderpass;
1637 rp_begin_info.framebuffer = renderer->fb;
1638 rp_begin_info.renderArea = rp_area;
1639 rp_begin_info.clearValueCount = 2;
1640 rp_begin_info.pClearValues = clear_values;
1643 stage_flags = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT;
1645 memset(&submit_info, 0, sizeof submit_info);
1646 submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
1647 submit_info.commandBufferCount = 1;
1648 submit_info.pCommandBuffers = &ctx->cmd_buf;
1652 submit_info.pWaitDstStageMask = &stage_flags;
1653 submit_info.waitSemaphoreCount = 1;
1654 submit_info.pWaitSemaphores = &semaphores->frame_done;
1658 submit_info.signalSemaphoreCount = 1;
1659 submit_info.pSignalSemaphores = &semaphores->frame_ready;
1662 img_range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
1663 img_range.baseMipLevel = 0;
1664 img_range.levelCount = 1;
1665 img_range.baseArrayLayer = 0;
1666 img_range.layerCount = 1;
1668 vkBeginCommandBuffer(ctx->cmd_buf, &cmd_begin_info);
1669 vk_transition_image_layout(&attachments[0],
1671 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
1672 VK_IMAGE_LAYOUT_GENERAL,
1673 VK_QUEUE_FAMILY_EXTERNAL,
1675 vkCmdClearColorImage(ctx->cmd_buf,
1676 attachments[0].obj.img,
1677 VK_IMAGE_LAYOUT_GENERAL,
1678 &clear_values[0].color,
1682 vkCmdBeginRenderPass(ctx->cmd_buf, &rp_begin_info, VK_SUBPASS_CONTENTS_INLINE);
1687 viewport.height = h;
1689 scissor.offset.x = x;
1690 scissor.offset.y = y;
1691 scissor.extent.width = w;
1692 scissor.extent.height = h;
1694 vkCmdSetViewport(ctx->cmd_buf, 0, 1, &viewport);
1695 vkCmdSetScissor(ctx->cmd_buf, 0, 1, &scissor);
1697 vkCmdBindPipeline(ctx->cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS, renderer->pipeline);
1699 vkCmdEndRenderPass(ctx->cmd_buf);
1702 VkImageMemoryBarrier *barriers =
1703 calloc(n_attachments, sizeof(VkImageMemoryBarrier));
1704 VkImageMemoryBarrier *barrier = barriers;
1706 for (uint32_t n = 0; n < n_attachments; n++, barrier++) {
1707 struct vk_image_att *att = &attachments[n];
1709 /* Insert barrier to mark ownership transfer. */
1710 barrier->sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
1713 get_aspect_from_depth_format(att->props.format) != VK_NULL_HANDLE;
1715 barrier->oldLayout = is_depth ?
1716 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL :
1717 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
1718 barrier->newLayout = VK_IMAGE_LAYOUT_GENERAL;
1719 barrier->srcAccessMask = get_access_mask(barrier->oldLayout);
1720 barrier->dstAccessMask = get_access_mask(barrier->newLayout);
1721 barrier->srcQueueFamilyIndex = ctx->qfam_idx;
1722 barrier->dstQueueFamilyIndex = VK_QUEUE_FAMILY_EXTERNAL;
1723 barrier->image = att->obj.img;
1724 barrier->subresourceRange.aspectMask = is_depth ?
1725 VK_IMAGE_ASPECT_DEPTH_BIT :
1726 VK_IMAGE_ASPECT_COLOR_BIT;
1727 barrier->subresourceRange.baseMipLevel = 0;
1728 barrier->subresourceRange.levelCount = 1;
1729 barrier->subresourceRange.baseArrayLayer = 0;
1730 barrier->subresourceRange.layerCount = 1;
1733 vkCmdPipelineBarrier(ctx->cmd_buf,
1734 VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
1735 VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
1739 n_attachments, barriers);
1743 vkEndCommandBuffer(ctx->cmd_buf);
1745 if (vkQueueSubmit(ctx->queue, 1, &submit_info, VK_NULL_HANDLE) != VK_SUCCESS) {
1746 fprintf(stderr, "Failed to submit queue.\n");
1749 if (!semaphores && !has_wait && !has_signal)
1750 vkQueueWaitIdle(ctx->queue);
1754 vk_copy_image_to_buffer(struct vk_ctx *ctx,
1755 struct vk_image_att *src_img,
1756 struct vk_buf *dst_bo,
1759 VkCommandBufferBeginInfo cmd_begin_info;
1760 VkSubmitInfo submit_info;
1761 VkImageAspectFlagBits aspect_mask = get_aspect_from_depth_format(src_img->props.format);
1763 /* VkCommandBufferBeginInfo */
1764 memset(&cmd_begin_info, 0, sizeof cmd_begin_info);
1765 cmd_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
1766 cmd_begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
1768 memset(&submit_info, 0, sizeof submit_info);
1769 submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
1770 submit_info.commandBufferCount = 1;
1771 submit_info.pCommandBuffers = &ctx->cmd_buf;
1773 vkBeginCommandBuffer(ctx->cmd_buf, &cmd_begin_info);
1774 if (src_img->props.end_layout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL && dst_bo) {
1775 vk_transition_image_layout(src_img,
1777 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
1778 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
1779 VK_QUEUE_FAMILY_EXTERNAL,
1782 /* copy image to buf */
1783 VkBufferImageCopy copy_region = {
1785 .bufferRowLength = w,
1786 .bufferImageHeight = h,
1787 .imageSubresource = {
1788 .aspectMask = aspect_mask ? aspect_mask
1789 : VK_IMAGE_ASPECT_COLOR_BIT,
1791 .baseArrayLayer = 0,
1794 .imageOffset = { 0, 0, 0 },
1795 .imageExtent = { w, h, 1 }
1798 vkCmdCopyImageToBuffer(ctx->cmd_buf,
1800 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
1801 dst_bo->buf, 1, ©_region);
1803 vk_transition_image_layout(src_img,
1805 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
1806 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
1807 VK_QUEUE_FAMILY_EXTERNAL,
1810 VkBufferMemoryBarrier write_finish_buffer_memory_barrier = {
1811 .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
1812 .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
1813 .dstAccessMask = VK_ACCESS_HOST_READ_BIT,
1814 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_EXTERNAL,
1815 .dstQueueFamilyIndex = ctx->qfam_idx,
1816 .buffer = dst_bo->buf,
1818 .size = VK_WHOLE_SIZE
1821 vkCmdPipelineBarrier(ctx->cmd_buf,
1822 VK_PIPELINE_STAGE_TRANSFER_BIT,
1823 VK_PIPELINE_STAGE_HOST_BIT,
1824 (VkDependencyFlags) 0, 0, NULL,
1825 1, &write_finish_buffer_memory_barrier,
1828 vkEndCommandBuffer(ctx->cmd_buf);
1830 if (vkQueueSubmit(ctx->queue, 1, &submit_info, VK_NULL_HANDLE) != VK_SUCCESS) {
1831 fprintf(stderr, "Failed to submit queue.\n");
1833 vkQueueWaitIdle(ctx->queue);
1838 vk_create_semaphores(struct vk_ctx *ctx,
1839 struct vk_semaphores *semaphores)
1841 VkSemaphoreCreateInfo sema_info;
1842 VkExportSemaphoreCreateInfo exp_sema_info;
1844 /* VkExportSemaphoreCreateInfo */
1845 memset(&exp_sema_info, 0, sizeof exp_sema_info);
1846 exp_sema_info.sType = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO;
1847 exp_sema_info.handleTypes = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT;
1849 /* VkSemaphoreCreateInfo */
1850 memset(&sema_info, 0, sizeof sema_info);
1851 sema_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
1852 sema_info.pNext = &exp_sema_info;
1854 if (vkCreateSemaphore(ctx->dev, &sema_info, 0, &semaphores->frame_ready) != VK_SUCCESS) {
1855 fprintf(stderr, "Failed to create semaphore frame_ready.\n");
1859 if (vkCreateSemaphore(ctx->dev, &sema_info, 0, &semaphores->frame_done) != VK_SUCCESS) {
1860 fprintf(stderr, "Failed to create semaphore frame_done.\n");
1868 vk_destroy_semaphores(struct vk_ctx *ctx,
1869 struct vk_semaphores *semaphores)
1871 if (semaphores->frame_ready)
1872 vkDestroySemaphore(ctx->dev, semaphores->frame_ready, 0);
1873 if (semaphores->frame_done)
1874 vkDestroySemaphore(ctx->dev, semaphores->frame_done, 0);
1878 vk_transition_image_layout(struct vk_image_att *img_att,
1879 VkCommandBuffer cmd_buf,
1880 VkImageLayout old_layout,
1881 VkImageLayout new_layout,
1882 uint32_t src_queue_fam_idx,
1883 uint32_t dst_queue_fam_idx)
1885 VkImageMemoryBarrier barrier;
1886 struct vk_image_props props = img_att->props;
1887 VkImageAspectFlagBits aspect_mask = get_aspect_from_depth_format(props.format);
1889 memset(&barrier, 0, sizeof barrier);
1890 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
1891 barrier.srcAccessMask = get_access_mask(old_layout);
1892 barrier.dstAccessMask = get_access_mask(new_layout);
1893 barrier.oldLayout = old_layout;
1894 barrier.newLayout = new_layout;
1895 barrier.srcQueueFamilyIndex = src_queue_fam_idx;
1896 barrier.dstQueueFamilyIndex = dst_queue_fam_idx;
1897 barrier.image = img_att->obj.img;
1898 barrier.subresourceRange.aspectMask = aspect_mask ? aspect_mask :
1899 VK_IMAGE_ASPECT_COLOR_BIT;
1900 barrier.subresourceRange.levelCount = 1;
1901 barrier.subresourceRange.layerCount = 1;
1903 vkCmdPipelineBarrier(cmd_buf,
1904 get_pipeline_stage_flags(old_layout),
1905 get_pipeline_stage_flags(new_layout),
1906 0, 0, VK_NULL_HANDLE, 0, VK_NULL_HANDLE, 1, &barrier);