10 static VkViewport viewport;
11 static VkRect2D scissor;
12 static bool enable_layers = true;
14 /* static functions */
16 static VkSampleCountFlagBits
17 get_num_samples(uint32_t num_samples)
21 return VK_SAMPLE_COUNT_64_BIT;
23 return VK_SAMPLE_COUNT_32_BIT;
25 return VK_SAMPLE_COUNT_16_BIT;
27 return VK_SAMPLE_COUNT_8_BIT;
29 return VK_SAMPLE_COUNT_4_BIT;
31 return VK_SAMPLE_COUNT_2_BIT;
35 fprintf(stderr, "Invalid number of samples in VkSampleCountFlagBits. Using one sample.\n");
38 return VK_SAMPLE_COUNT_1_BIT;
41 static VkAccessFlagBits
42 get_access_mask(const VkImageLayout layout)
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
49 case VK_IMAGE_LAYOUT_UNDEFINED:
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:
74 enable_validation_layers(VkInstanceCreateInfo *info)
78 VkLayerProperties *layers;
79 static const char *layer_names[] = {
80 "VK_LAYER_KHRONOS_validation",
83 vkEnumerateInstanceLayerProperties(&num_layers, 0);
84 layers = alloca(num_layers * sizeof *layers);
85 vkEnumerateInstanceLayerProperties(&num_layers, layers);
88 printf("Available validation layers:\n");
89 for(i = 0; i < (int)num_layers; i++) {
90 printf(" %s\n", layers[i].layerName);
93 info->ppEnabledLayerNames = layer_names;
94 info->enabledLayerCount = sizeof layer_names / sizeof *layer_names;
96 fprintf(stderr, "Vulkan validation layers not found.\n");
101 enable_extensions(VkInstanceCreateInfo *info)
103 static const char *ext_names[] = {
104 "VK_KHR_xcb_surface",
108 uint32_t num_extensions;
109 VkExtensionProperties *extensions;
112 vkEnumerateInstanceExtensionProperties(0, &num_extensions, 0);
113 if (!num_extensions) {
114 fprintf(stderr, "No instance extensions found.\n");
118 extensions = alloca(num_extensions * sizeof *extensions);
119 vkEnumerateInstanceExtensionProperties(0, &num_extensions, extensions);
121 printf("Available extensions:\n");
122 for (i = 0; i < num_extensions; i++) {
123 printf(" %s\n", extensions[i].extensionName);
126 info->ppEnabledExtensionNames = ext_names;
127 info->enabledExtensionCount = ARRAY_SIZE(ext_names);
131 create_instance(bool enable_layers)
133 VkApplicationInfo app_info;
134 VkInstanceCreateInfo inst_info;
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;
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;
148 enable_extensions(&inst_info);
150 enable_validation_layers(&inst_info);
153 if (vkCreateInstance(&inst_info, 0, &inst) != VK_SUCCESS)
159 static VkPhysicalDevice
160 select_physical_device(VkInstance inst)
162 VkResult res = VK_SUCCESS;
163 uint32_t dev_count = 0;
164 VkPhysicalDevice *pdevices;
165 VkPhysicalDevice pdevice0;
168 vkEnumeratePhysicalDevices(inst, &dev_count, 0)) != VK_SUCCESS)
171 pdevices = malloc(dev_count * sizeof(VkPhysicalDevice));
172 if (vkEnumeratePhysicalDevices(inst, &dev_count, pdevices) !=
176 pdevice0 = pdevices[0];
183 create_device(struct vk_ctx *ctx, VkPhysicalDevice pdev)
185 const char *deviceExtensions[] = { "VK_KHR_swapchain" };
186 VkDeviceQueueCreateInfo dev_queue_info;
187 VkDeviceCreateInfo dev_info;
190 VkQueueFamilyProperties *fam_props;
195 vkGetPhysicalDeviceQueueFamilyProperties(pdev, &prop_count, 0);
196 if (prop_count < 0) {
197 fprintf(stderr, "Invalid queue family properties.\n");
201 fam_props = malloc(prop_count * sizeof *fam_props);
202 vkGetPhysicalDeviceQueueFamilyProperties(pdev, &prop_count, fam_props);
204 for (i = 0; i < prop_count; i++) {
205 if (fam_props[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
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;
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;
225 if (vkCreateDevice(pdev, &dev_info, 0, &dev) != VK_SUCCESS)
232 fill_uuid(VkPhysicalDevice pdev, uint8_t *deviceUUID, uint8_t *driverUUID)
234 VkPhysicalDeviceIDProperties devProp;
235 VkPhysicalDeviceProperties2 prop2;
237 memset(&devProp, 0, sizeof devProp);
238 devProp.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES;
240 memset(&prop2, 0, sizeof prop2);
241 prop2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
242 prop2.pNext = &devProp;
244 vkGetPhysicalDeviceProperties2(pdev, &prop2);
245 memcpy(deviceUUID, devProp.deviceUUID, VK_UUID_SIZE);
246 memcpy(driverUUID, devProp.driverUUID, VK_UUID_SIZE);
250 create_cmd_pool(struct vk_ctx *ctx)
252 VkCommandPoolCreateInfo cmd_pool_info;
253 VkCommandPool cmd_pool;
254 VkDevice dev = ctx->dev;
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;
261 if (vkCreateCommandPool(dev, &cmd_pool_info, 0, &cmd_pool) != VK_SUCCESS)
268 create_renderpass(struct vk_ctx *ctx,
269 struct vk_image_props *color_img_props,
270 struct vk_image_props *depth_img_props)
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;
278 /* VkAttachmentDescription */
279 memset(att_dsc, 0, num_attachments * sizeof att_dsc[0]);
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;
290 att_dsc[1].samples = get_num_samples(depth_img_props->num_samples);
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;
298 att_dsc[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
299 att_dsc[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
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;
308 /* VkAttachmentReference */
309 memset(att_rfc, 0, num_attachments * sizeof att_rfc[0]);
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;
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;
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];
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;
333 if (vkCreateRenderPass(ctx->dev, &rpass_info, 0, &rpass) != VK_SUCCESS) {
334 fprintf(stderr, "Failed to create renderpass.\n");
335 rpass = VK_NULL_HANDLE;
341 static inline VkImageType
342 get_image_type(uint32_t h, uint32_t d)
345 return VK_IMAGE_TYPE_1D;
348 return VK_IMAGE_TYPE_3D;
350 return VK_IMAGE_TYPE_2D;
353 static VkImageViewType
354 get_image_view_type(struct vk_image_props *props)
356 VkImageType type = get_image_type(props->h, props->depth);
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;
381 return VK_IMAGE_VIEW_TYPE_2D;
385 static VkImageAspectFlagBits
386 get_aspect_from_depth_format(VkFormat depth_format)
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;
405 static VkPipelineStageFlags
406 get_pipeline_stage_flags(const VkImageLayout 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;
432 create_image_view(struct vk_ctx *ctx,
434 VkImageViewType view_type,
436 VkImageSubresourceRange sr,
438 VkImageView *image_view)
440 VkImageViewCreateInfo info;
442 memset(&info, 0, sizeof info);
443 info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
445 info.viewType = view_type;
446 info.viewType = VK_IMAGE_VIEW_TYPE_2D;
447 info.format = format;
448 info.subresourceRange = sr;
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;
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;
468 create_framebuffer(struct vk_ctx *ctx,
469 struct vk_image_attachment *color_att,
470 struct vk_image_attachment *depth_att,
471 struct vk_renderer *renderer)
473 VkImageSubresourceRange sr;
474 VkFramebufferCreateInfo fb_info;
476 VkImageViewType view_type = get_image_view_type(&color_att->props);
478 if (!color_att->obj.img || !depth_att->obj.img) {
479 fprintf(stderr, "Invalid framebuffer attachment image.\n");
483 /* create image views */
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.
497 sr.levelCount = color_att->props.num_levels;
498 sr.baseArrayLayer = 0;
499 sr.layerCount = color_att->props.num_layers;
502 if (!color_att->obj.img_view) {
503 if (!create_image_view(ctx, color_att->obj.img, view_type, color_att->props.format, sr, false, &color_att->obj.img_view)) {
504 fprintf(stderr, "Failed to create color image view for framebuffer.\n");
505 vk_destroy_image(ctx, &color_att->obj);
511 memset(&sr, 0, sizeof sr);
512 sr.aspectMask = get_aspect_from_depth_format(depth_att->props.format);
514 sr.levelCount = depth_att->props.num_levels ? depth_att->props.num_levels : 1;
515 sr.baseArrayLayer = 0;
516 sr.layerCount = depth_att->props.num_layers ? depth_att->props.num_layers : 1;
518 if (!depth_att->obj.img_view) {
519 if (!create_image_view(ctx, depth_att->obj.img,
520 depth_att->props.num_layers > 1 ?
521 VK_IMAGE_VIEW_TYPE_2D_ARRAY :
522 VK_IMAGE_VIEW_TYPE_2D,
523 depth_att->props.format,
526 &depth_att->obj.img_view)) {
527 fprintf(stderr, "Failed to create depth image view for framebuffer.\n");
528 vk_destroy_image(ctx, &depth_att->obj);
533 atts[0] = color_att->obj.img_view;
534 atts[1] = depth_att->obj.img_view;
536 memset(&fb_info, 0, sizeof fb_info);
537 fb_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
538 fb_info.renderPass = renderer->renderpass;
539 fb_info.width = color_att->props.w;
540 fb_info.height = color_att->props.h;
541 fb_info.layers = color_att->props.num_layers ? color_att->props.num_layers : 1;
542 fb_info.attachmentCount = 2;
543 fb_info.pAttachments = atts;
545 if (vkCreateFramebuffer(ctx->dev, &fb_info, 0, &renderer->fb) != VK_SUCCESS)
551 fprintf(stderr, "Failed to create framebuffer.\n");
552 renderer->fb = VK_NULL_HANDLE;
555 static VkShaderModule
556 create_shader_module(struct vk_ctx *ctx,
560 VkShaderModuleCreateInfo sm_info;
563 /* VkShaderModuleCreateInfo */
564 memset(&sm_info, 0, sizeof sm_info);
565 sm_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
566 sm_info.codeSize = size;
567 sm_info.pCode = (void*)src;
569 if (vkCreateShaderModule(ctx->dev, &sm_info, 0, &sm) != VK_SUCCESS) {
570 fprintf(stderr, "Failed to create shader module.\n");
578 create_pipeline(struct vk_ctx *ctx,
581 uint32_t num_samples,
584 struct vk_renderer *renderer)
586 VkVertexInputBindingDescription vert_bind_dsc[1];
587 VkVertexInputAttributeDescription vert_att_dsc[1];
589 VkPipelineColorBlendAttachmentState cb_att_state[1];
590 VkPipelineVertexInputStateCreateInfo vert_input_info;
591 VkPipelineInputAssemblyStateCreateInfo asm_info;
592 VkPipelineViewportStateCreateInfo viewport_info;
593 VkPipelineRasterizationStateCreateInfo rs_info;
594 VkPipelineMultisampleStateCreateInfo ms_info;
595 VkPipelineDepthStencilStateCreateInfo ds_info;
596 VkPipelineColorBlendStateCreateInfo cb_info;
597 VkPipelineShaderStageCreateInfo sdr_stages[2];
598 VkPipelineLayoutCreateInfo layout_info;
599 VkGraphicsPipelineCreateInfo pipeline_info;
601 VkFormatProperties fmt_props;
602 VkPushConstantRange pc_range[1];
604 VkStencilOpState front;
605 VkStencilOpState back;
607 VkPipelineLayout pipeline_layout;
610 /* format of vertex attributes:
611 * we have 2D vectors so we need a RG format:
613 * the stride (distance between 2 consecutive elements)
614 * must be 8 because we use 32 bit floats and
616 format = VK_FORMAT_R32G32_SFLOAT;
617 vkGetPhysicalDeviceFormatProperties(ctx->pdev, format, &fmt_props);
618 assert(fmt_props.bufferFeatures & VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT);
621 /* VkVertexInputAttributeDescription */
622 memset(&vert_att_dsc, 0, sizeof vert_att_dsc);
623 vert_att_dsc[0].location = 0;
624 vert_att_dsc[0].binding = 0;
625 vert_att_dsc[0].format = format; /* see comment */
626 vert_att_dsc[0].offset = 0;
628 /* VkVertexInputBindingDescription */
629 memset(&vert_bind_dsc, 0, sizeof vert_bind_dsc);
630 vert_bind_dsc[0].binding = 0;
631 vert_bind_dsc[0].stride = stride;
632 vert_bind_dsc[0].inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
634 /* If using vbo, we have setup vertex_info in the renderer. */
635 bool use_vbo = renderer->vertex_info.num_verts > 0;
637 /* VkPipelineVertexInputStateCreateInfo */
638 memset(&vert_input_info, 0, sizeof vert_input_info);
639 vert_input_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
640 vert_input_info.vertexBindingDescriptionCount = use_vbo ? 1 : 0;
641 vert_input_info.pVertexBindingDescriptions = vert_bind_dsc;
642 vert_input_info.vertexAttributeDescriptionCount = use_vbo ? 1 : 0;
643 vert_input_info.pVertexAttributeDescriptions = vert_att_dsc;
645 /* VkPipelineInputAssemblyStateCreateInfo */
646 memset(&asm_info, 0, sizeof asm_info);
647 asm_info.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
648 asm_info.topology = renderer->vertex_info.topology ?
649 renderer->vertex_info.topology
650 : VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
651 asm_info.primitiveRestartEnable = false;
654 viewport.x = viewport.y = 0;
655 viewport.width = width;
656 viewport.height = height;
657 viewport.minDepth = 0;
658 viewport.maxDepth = 1;
660 /* VkRect2D scissor */
661 scissor.offset.x = scissor.offset.y = 0;
662 scissor.extent.width = width;
663 scissor.extent.height = height;
665 /* VkPipelineViewportStateCreateInfo */
666 memset(&viewport_info, 0, sizeof viewport_info);
667 viewport_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
668 viewport_info.viewportCount = 1;
669 viewport_info.pViewports = &viewport;
670 viewport_info.scissorCount = 1;
671 viewport_info.pScissors = &scissor;
673 /* VkPipelineRasterizationStateCreateInfo */
674 memset(&rs_info, 0, sizeof rs_info);
675 rs_info.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
676 rs_info.polygonMode = VK_POLYGON_MODE_FILL;
677 rs_info.cullMode = VK_CULL_MODE_NONE;
678 rs_info.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
679 rs_info.lineWidth = 1.0;
681 /* VkPipelineMultisampleStateCreateInfo */
682 memset(&ms_info, 0, sizeof ms_info);
683 ms_info.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
684 ms_info.rasterizationSamples = num_samples;
686 /* VkStencilOpState */
687 /* The default values for ES are taken by Topi Pohjolainen's code */
688 /* defaults in OpenGL ES 3.1 */
689 memset(&front, 0, sizeof front);
690 front.compareMask = ~0;
691 front.writeMask = ~0;
694 memset(&back, 0, sizeof back);
695 back.compareMask = ~0;
699 /* VkPipelineDepthStencilStateCreateInfo */
700 memset(&ds_info, 0, sizeof ds_info);
701 ds_info.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
702 ds_info.front = front;
704 /* defaults in OpenGL ES 3.1 */
705 ds_info.minDepthBounds = 0;
706 ds_info.maxDepthBounds = 1;
707 /* z buffer, stencil buffer */
709 ds_info.depthTestEnable = VK_TRUE;
710 ds_info.depthWriteEnable = VK_TRUE;
711 ds_info.depthCompareOp = VK_COMPARE_OP_LESS;
713 if (enable_stencil) {
714 ds_info.stencilTestEnable = VK_TRUE;
715 ds_info.depthTestEnable = VK_FALSE;
716 ds_info.depthWriteEnable = VK_TRUE;
719 /* we only care about the passOp here */
720 ds_info.back.compareOp = VK_COMPARE_OP_ALWAYS;
721 ds_info.back.failOp = VK_STENCIL_OP_REPLACE;
722 ds_info.back.depthFailOp = VK_STENCIL_OP_REPLACE;
723 ds_info.back.passOp = VK_STENCIL_OP_REPLACE;
724 ds_info.back.compareMask = 0xffffffff;
725 ds_info.back.writeMask = 0xffffffff;
726 ds_info.back.reference = 1;
727 ds_info.front = ds_info.back;
729 /* VkPipelineColorBlendAttachmentState */
730 memset(&cb_att_state[0], 0, sizeof cb_att_state[0]);
731 cb_att_state[0].colorWriteMask = (VK_COLOR_COMPONENT_R_BIT |
732 VK_COLOR_COMPONENT_G_BIT |
733 VK_COLOR_COMPONENT_B_BIT |
734 VK_COLOR_COMPONENT_A_BIT);
736 /* VkPipelineColorBlendStateCreateInfo */
737 memset(&cb_info, 0, sizeof cb_info);
738 cb_info.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
739 cb_info.attachmentCount = 1;
740 cb_info.pAttachments = cb_att_state;
741 /* default in ES 3.1 */
742 for (i = 0; i < 4; i++) {
743 cb_info.blendConstants[i] = 0.0f;
746 /* VkPipelineShaderStageCreateInfo */
747 memset(sdr_stages, 0, 2 * sizeof sdr_stages[0]);
749 sdr_stages[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
750 sdr_stages[0].stage = VK_SHADER_STAGE_VERTEX_BIT;
751 sdr_stages[0].module = renderer->vs;
752 sdr_stages[0].pName = "main";
754 sdr_stages[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
755 sdr_stages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT;
756 sdr_stages[1].module = renderer->fs;
757 sdr_stages[1].pName = "main";
759 /* VkPushConstantRange */
760 memset(pc_range, 0, sizeof pc_range[0]);
761 pc_range[0].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
762 pc_range[0].size = sizeof (struct vk_dims); /* w, h */
764 /* VkPipelineLayoutCreateInfo */
765 memset(&layout_info, 0, sizeof layout_info);
766 layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
767 layout_info.pushConstantRangeCount = 1;
768 layout_info.pPushConstantRanges = pc_range;
770 if (vkCreatePipelineLayout(ctx->dev, &layout_info, 0, &pipeline_layout) != VK_SUCCESS) {
771 fprintf(stderr, "Failed to create pipeline layout\n");
772 renderer->pipeline = VK_NULL_HANDLE;
776 renderer->pipeline_layout = pipeline_layout;
778 /* VkGraphicsPipelineCreateInfo */
779 memset(&pipeline_info, 0, sizeof pipeline_info);
780 pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
781 pipeline_info.layout = pipeline_layout;
782 pipeline_info.renderPass = renderer->renderpass;
783 pipeline_info.pVertexInputState = &vert_input_info;
784 pipeline_info.pInputAssemblyState = &asm_info;
785 pipeline_info.pViewportState = &viewport_info;
786 pipeline_info.pRasterizationState = &rs_info;
787 pipeline_info.pMultisampleState = &ms_info;
788 pipeline_info.pDepthStencilState = &ds_info;
789 pipeline_info.pColorBlendState = &cb_info;
790 pipeline_info.stageCount = 2;
791 pipeline_info.pStages = sdr_stages;
793 if (vkCreateGraphicsPipelines(ctx->dev, 0, 1,
795 &renderer->pipeline) != VK_SUCCESS) {
796 fprintf(stderr, "Failed to create graphics pipeline.\n");
797 renderer->pipeline = VK_NULL_HANDLE;
801 static VkCommandBuffer
802 create_cmd_buf(VkDevice dev, VkCommandPool cmd_pool)
804 VkCommandBuffer cmd_buf;
805 VkCommandBufferAllocateInfo alloc_info;
807 memset(&alloc_info, 0, sizeof alloc_info);
808 alloc_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
809 alloc_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
810 alloc_info.commandBufferCount = 1;
811 alloc_info.commandPool = cmd_pool;
813 if (vkAllocateCommandBuffers(dev, &alloc_info, &cmd_buf) != VK_SUCCESS)
820 get_memory_type_idx(VkPhysicalDevice pdev,
821 const VkMemoryRequirements *mem_reqs,
822 VkMemoryPropertyFlagBits prop_flags)
824 VkPhysicalDeviceMemoryProperties pdev_mem_props;
827 vkGetPhysicalDeviceMemoryProperties(pdev, &pdev_mem_props);
829 for (i = 0; i < pdev_mem_props.memoryTypeCount; i++) {
830 const VkMemoryType *type = &pdev_mem_props.memoryTypes[i];
832 if ((mem_reqs->memoryTypeBits & (1 << i)) &&
833 (type->propertyFlags & prop_flags) == prop_flags) {
841 static VkDeviceMemory
842 alloc_memory(struct vk_ctx *ctx,
844 const VkMemoryRequirements *mem_reqs,
847 VkMemoryPropertyFlagBits prop_flags)
849 VkExportMemoryAllocateInfo exp_mem_info;
850 VkMemoryAllocateInfo mem_alloc_info;
852 VkMemoryDedicatedAllocateInfoKHR ded_info;
855 memset(&exp_mem_info, 0, sizeof exp_mem_info);
856 exp_mem_info.sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO;
857 exp_mem_info.handleTypes =
858 VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
861 memset(&mem_alloc_info, 0, sizeof mem_alloc_info);
862 mem_alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
863 mem_alloc_info.pNext = is_external ? &exp_mem_info : VK_NULL_HANDLE;
864 mem_alloc_info.allocationSize = mem_reqs->size;
865 mem_alloc_info.memoryTypeIndex =
866 get_memory_type_idx(ctx->pdev, mem_reqs, prop_flags);
868 if (mem_alloc_info.memoryTypeIndex == UINT32_MAX) {
869 fprintf(stderr, "No suitable memory type index found.\n");
873 if (image || buffer) {
874 memset(&ded_info, 0, sizeof ded_info);
875 ded_info.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO;
876 ded_info.image = image;
877 ded_info.buffer = buffer;
879 exp_mem_info.pNext = &ded_info;
882 if (vkAllocateMemory(ctx->dev, &mem_alloc_info, 0, &mem) !=
890 alloc_image_memory(struct vk_ctx *ctx, bool is_external, struct vk_image_obj *img_obj)
892 VkMemoryDedicatedRequirements ded_reqs;
893 VkImageMemoryRequirementsInfo2 req_info2;
894 VkMemoryRequirements2 mem_reqs2;
896 memset(&ded_reqs, 0, sizeof ded_reqs);
897 ded_reqs.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS;
899 /* VkImageMemoryRequirementsInfo2 */
900 memset(&req_info2, 0, sizeof req_info2);
901 req_info2.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2;
902 req_info2.image = img_obj->img;
904 /* VkMemoryRequirements2 */
905 memset(&mem_reqs2, 0, sizeof mem_reqs2);
906 mem_reqs2.sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2;
907 mem_reqs2.pNext = &ded_reqs;
909 vkGetImageMemoryRequirements2(ctx->dev, &req_info2, &mem_reqs2);
910 img_obj->mobj.mem = alloc_memory(ctx,
912 &mem_reqs2.memoryRequirements,
913 ded_reqs.requiresDedicatedAllocation ?
914 img_obj->img : VK_NULL_HANDLE,
916 mem_reqs2.memoryRequirements.memoryTypeBits &
917 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
919 img_obj->mobj.mem_sz = mem_reqs2.memoryRequirements.size;
920 img_obj->mobj.dedicated = ded_reqs.requiresDedicatedAllocation;
921 if (img_obj->mobj.mem == VK_NULL_HANDLE) {
922 fprintf(stderr, "Failed to allocate image memory.\n");
926 if (vkBindImageMemory(ctx->dev, img_obj->img, img_obj->mobj.mem, 0) !=
928 fprintf(stderr, "Failed to bind image memory.\n");
936 are_props_supported(struct vk_ctx *ctx, struct vk_image_props *props)
938 VkPhysicalDeviceExternalImageFormatInfo ext_img_fmt_info;
939 VkExternalImageFormatProperties ext_img_fmt_props;
942 VkPhysicalDeviceImageFormatInfo2 img_fmt_info;
943 VkImageFormatProperties2 img_fmt_props;
944 VkImageUsageFlagBits all_flags[] = {
945 VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
946 VK_IMAGE_USAGE_TRANSFER_DST_BIT,
947 VK_IMAGE_USAGE_SAMPLED_BIT,
948 VK_IMAGE_USAGE_STORAGE_BIT,
949 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
950 VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
951 VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT,
952 /* Shouldn't be used together with COLOR, DEPTH_STENCIL
954 * VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT,
955 * Provided by VK_EXT_fragment_density_map
956 * VK_IMAGE_USAGE_FRAGMENT_DENSITY_MAP_BIT_EXT,
957 * Provided by VK_NV_shading_rate_image
958 * VK_IMAGE_USAGE_SHADING_RATE_IMAGE_BIT_NV,
959 * Provided by VK_KHR_fragment_shading_rate
960 * VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR,
963 VkImageUsageFlagBits flags = 0;
965 VkExternalMemoryFeatureFlagBits export_feature_flags =
966 VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT;
967 VkExternalMemoryHandleTypeFlagBits handle_type =
968 VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;
970 memset(&ext_img_fmt_info, 0, sizeof ext_img_fmt_info);
971 ext_img_fmt_info.sType =
972 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO;
973 ext_img_fmt_info.handleType = handle_type;
975 memset(&ext_img_fmt_props, 0, sizeof ext_img_fmt_props);
976 ext_img_fmt_props.sType =
977 VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES;
979 memset(&img_fmt_props, 0, sizeof img_fmt_props);
980 img_fmt_props.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2;
981 img_fmt_props.pNext = &ext_img_fmt_props;
983 memset(&img_fmt_info, 0, sizeof img_fmt_info);
985 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2;
986 img_fmt_info.pNext = &ext_img_fmt_info;
987 img_fmt_info.format = props->format;
988 img_fmt_info.type = get_image_type(props->h, props->depth);
989 img_fmt_info.tiling = props->tiling;
991 for (i = 0; i < ARRAY_SIZE(all_flags); i++) {
992 img_fmt_info.usage = all_flags[i];
993 if (vkGetPhysicalDeviceImageFormatProperties2(ctx->pdev,
995 &img_fmt_props) == VK_SUCCESS) {
996 flags |= all_flags[i];
1000 /* usage can't be null */
1002 img_fmt_info.usage = flags;
1005 fprintf(stderr, "Unsupported Vulkan format properties: usage.\n");
1009 if (vkGetPhysicalDeviceImageFormatProperties2
1010 (ctx->pdev, &img_fmt_info, &img_fmt_props) != VK_SUCCESS) {
1012 "Unsupported Vulkan format properties.\n");
1015 props->usage = flags;
1017 if (props->need_export &&
1018 !(ext_img_fmt_props.externalMemoryProperties.externalMemoryFeatures
1019 & export_feature_flags)) {
1020 fprintf(stderr, "Unsupported Vulkan external memory features.\n");
1027 /* static swapchain / surf related functions */
1030 sc_validate_surface(struct vk_ctx *ctx,
1035 fprintf(stderr, "No surface!\n");
1039 if(vkGetPhysicalDeviceSurfaceSupportKHR(ctx->pdev, ctx->qfam_idx, surf, &supported) != VK_SUCCESS) {
1040 fprintf(stderr, "Failed to validate surface.\n");
1045 fprintf(stderr, "Invalid surface! Check if the surface with queue family index: %d supports presentation.\n", (int)ctx->qfam_idx);
1053 sc_select_format(struct vk_ctx *ctx,
1055 VkSwapchainCreateInfoKHR *s_info)
1057 VkSurfaceFormatKHR *formats;
1058 uint32_t num_formats;
1060 if (vkGetPhysicalDeviceSurfaceFormatsKHR(ctx->pdev, surf, &num_formats, 0) != VK_SUCCESS) {
1061 fprintf(stderr, "Failed to get the number of surface formats.\n");
1066 fprintf(stderr, "No surface formats found.\n");
1070 formats = malloc(num_formats * sizeof *formats);
1072 if (vkGetPhysicalDeviceSurfaceFormatsKHR(ctx->pdev, surf, &num_formats, formats) != VK_SUCCESS) {
1073 fprintf(stderr, "Failed to get the supported surface formats.\n");
1077 if ((num_formats == 1) && (formats[0].format == VK_FORMAT_UNDEFINED)) {
1078 s_info->imageFormat = VK_FORMAT_B8G8R8A8_UNORM;
1079 s_info->imageColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
1081 s_info->imageFormat = formats[0].format;
1082 s_info->imageColorSpace = formats[0].colorSpace;
1090 sc_select_supported_present_modes(struct vk_ctx *ctx,
1093 VkSwapchainCreateInfoKHR *s_info)
1095 VkPresentModeKHR *present_modes;
1096 uint32_t num_present_modes;
1099 /* find supported present modes */
1100 if (vkGetPhysicalDeviceSurfacePresentModesKHR(ctx->pdev, surf, &num_present_modes, 0) != VK_SUCCESS || !num_present_modes) {
1101 fprintf(stderr, "Failed to get the number of the supported presentation modes.\n");
1105 present_modes = malloc(num_present_modes * sizeof *present_modes);
1106 if (vkGetPhysicalDeviceSurfacePresentModesKHR(ctx->pdev, surf, &num_present_modes, present_modes) != VK_SUCCESS) {
1107 fprintf(stderr, "Failed to get the number of supported presentation modes.\n");
1110 if (vkGetPhysicalDeviceSurfacePresentModesKHR(ctx->pdev, surf, &num_present_modes,
1111 present_modes) != VK_SUCCESS) {
1112 fprintf(stderr, "Failed to get the supported presentation modes.\n");
1116 s_info->presentMode = VK_PRESENT_MODE_FIFO_KHR;
1118 for (i = 0; i < num_present_modes; i++) {
1119 if (present_modes[i] == VK_PRESENT_MODE_MAILBOX_KHR) {
1120 s_info->presentMode = present_modes[i];
1123 if (present_modes[i] == VK_PRESENT_MODE_IMMEDIATE_KHR) {
1124 s_info->presentMode = present_modes[i];
1131 free(present_modes);
1135 /* end of static functions */
1137 /* exposed Vulkan functions */
1140 vk_init_ctx(struct vk_ctx *ctx)
1142 if ((ctx->inst = create_instance(enable_layers)) == VK_NULL_HANDLE) {
1143 fprintf(stderr, "Failed to create Vulkan instance.\n");
1147 if ((ctx->pdev = select_physical_device(ctx->inst)) == VK_NULL_HANDLE) {
1148 fprintf(stderr, "Failed to find suitable physical device.\n");
1152 if ((ctx->dev = create_device(ctx, ctx->pdev)) == VK_NULL_HANDLE) {
1153 fprintf(stderr, "Failed to create Vulkan device.\n");
1157 fill_uuid(ctx->pdev, ctx->deviceUUID, ctx->driverUUID);
1161 vk_cleanup_ctx(ctx);
1166 vk_init_ctx_for_rendering(struct vk_ctx *ctx)
1168 if (!vk_init_ctx(ctx)) {
1169 fprintf(stderr, "Failed to initialize Vulkan.\n");
1173 if ((ctx->cmd_pool = create_cmd_pool(ctx)) == VK_NULL_HANDLE) {
1174 fprintf(stderr, "Failed to create command pool.\n");
1178 if ((ctx->cmd_buf = create_cmd_buf(ctx->dev, ctx->cmd_pool)) ==
1180 fprintf(stderr, "Failed to create command buffer.\n");
1184 vkGetDeviceQueue(ctx->dev, ctx->qfam_idx, 0, &ctx->queue);
1186 fprintf(stderr, "Failed to get command queue.\n");
1193 vk_cleanup_ctx(ctx);
1198 vk_cleanup_ctx(struct vk_ctx *ctx)
1200 if (enable_layers) {
1204 if (ctx->cmd_buf != VK_NULL_HANDLE) {
1205 vkResetCommandBuffer(ctx->cmd_buf,
1206 VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT);
1207 vkFreeCommandBuffers(ctx->dev, ctx->cmd_pool, 1, &ctx->cmd_buf);
1208 ctx->cmd_buf = VK_NULL_HANDLE;
1211 if (ctx->cmd_pool != VK_NULL_HANDLE) {
1212 vkResetCommandPool(ctx->dev, ctx->cmd_pool,
1213 VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT);
1214 vkDestroyCommandPool(ctx->dev, ctx->cmd_pool, 0);
1215 ctx->cmd_pool = VK_NULL_HANDLE;
1218 if (ctx->dev != VK_NULL_HANDLE) {
1219 vkDestroyDevice(ctx->dev, 0);
1220 ctx->dev = VK_NULL_HANDLE;
1223 if (ctx->inst != VK_NULL_HANDLE) {
1224 vkDestroyInstance(ctx->inst, 0);
1225 ctx->inst = VK_NULL_HANDLE;
1230 vk_create_image(struct vk_ctx *ctx,
1231 struct vk_image_props *props,
1232 struct vk_image_obj *img)
1234 VkImageCreateInfo img_info;
1236 memset(&img_info, 0, sizeof img_info);
1237 img_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
1238 img_info.pNext = 0; /* do something if external */
1239 img_info.imageType = get_image_type(props->h, props->depth);
1240 img_info.format = props->format;
1241 img_info.extent.width = props->w;
1242 img_info.extent.height = props->h;
1243 img_info.extent.depth = props->depth;
1244 img_info.mipLevels = props->num_levels ? props->num_levels : 1;
1245 img_info.arrayLayers = props->num_layers ?
1246 props->num_layers : VK_SAMPLE_COUNT_1_BIT;
1247 img_info.samples = get_num_samples(props->num_samples);
1248 img_info.tiling = props->tiling;
1249 img_info.usage = props->usage ?
1250 props->usage : VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
1251 img_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
1252 img_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
1254 if (vkCreateImage(ctx->dev, &img_info, 0, &img->img) != VK_SUCCESS)
1257 if(!alloc_image_memory(ctx, props->need_export, img))
1263 fprintf(stderr, "Failed to create external image.\n");
1264 vk_destroy_image(ctx, img);
1265 img->img = VK_NULL_HANDLE;
1266 img->mobj.mem = VK_NULL_HANDLE;
1271 vk_destroy_image(struct vk_ctx *ctx, struct vk_image_obj *img_obj)
1273 if (img_obj->img != VK_NULL_HANDLE) {
1274 vkDestroyImage(ctx->dev, img_obj->img, 0);
1275 img_obj->img = VK_NULL_HANDLE;
1278 if (img_obj->mobj.mem != VK_NULL_HANDLE) {
1279 vkFreeMemory(ctx->dev, img_obj->mobj.mem, 0);
1280 img_obj->mobj.mem = VK_NULL_HANDLE;
1285 vk_create_ext_image(struct vk_ctx *ctx,
1286 struct vk_image_props *props, struct vk_image_obj *img)
1288 VkExternalMemoryImageCreateInfo ext_img_info;
1289 VkImageCreateInfo img_info;
1291 memset(&ext_img_info, 0, sizeof ext_img_info);
1292 ext_img_info.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO;
1293 ext_img_info.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;
1295 memset(&img_info, 0, sizeof img_info);
1296 img_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
1297 img_info.pNext = &ext_img_info;
1298 img_info.imageType = get_image_type(props->h, props->depth);
1299 img_info.format = props->format;
1300 img_info.extent.width = props->w;
1301 img_info.extent.height = props->h;
1302 img_info.extent.depth = props->depth;
1303 img_info.mipLevels = props->num_levels ? props->num_levels : 1;
1304 img_info.arrayLayers = props->num_layers ? props->num_layers : VK_SAMPLE_COUNT_1_BIT;
1305 img_info.samples = get_num_samples(props->num_samples);
1306 img_info.tiling = props->tiling;
1307 img_info.usage = props->usage;
1308 img_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
1309 img_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
1310 /* issue 17 of EXT_external_objects
1311 * Required in OpenGL implementations that support
1312 * ARB_texture_view, OES_texture_view, EXT_texture_view,
1313 * or OpenGL 4.3 and above.
1315 img_info.flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
1317 if (vkCreateImage(ctx->dev, &img_info, 0, &img->img) != VK_SUCCESS)
1320 if(!alloc_image_memory(ctx, true, img))
1326 fprintf(stderr, "Failed to create external image.\n");
1327 vk_destroy_image(ctx, img);
1328 img->img = VK_NULL_HANDLE;
1329 img->mobj.mem = VK_NULL_HANDLE;
1334 vk_fill_image_props(struct vk_ctx *ctx,
1338 uint32_t num_samples,
1339 uint32_t num_levels,
1340 uint32_t num_layers,
1342 VkImageTiling tiling,
1343 VkImageLayout in_layout,
1344 VkImageLayout end_layout,
1346 struct vk_image_props *props)
1352 props->num_samples = num_samples;
1353 props->num_levels = num_levels;
1354 props->num_layers = num_layers;
1356 props->format = format;
1357 props->tiling = tiling;
1359 props->in_layout = in_layout;
1360 props->end_layout = end_layout;
1361 props->need_export = need_export;
1363 if (!are_props_supported(ctx, props))
1370 vk_create_renderer(struct vk_ctx *ctx,
1372 unsigned int vs_size,
1374 unsigned int fs_size,
1376 bool enable_stencil,
1377 struct vk_image_attachment *color_att,
1378 struct vk_image_attachment *depth_att,
1379 struct vk_vertex_info *vert_info,
1380 struct vk_renderer *renderer)
1382 memset(&renderer->vertex_info, 0, sizeof renderer->vertex_info);
1384 renderer->vertex_info = *vert_info;
1386 if (!color_att || depth_att) {
1387 fprintf(stderr, "Empty attachment.\n");
1391 renderer->renderpass = create_renderpass(ctx, &color_att->props,
1393 if (renderer->renderpass == VK_NULL_HANDLE)
1396 create_framebuffer(ctx, color_att, depth_att, renderer);
1397 if (renderer->fb == VK_NULL_HANDLE)
1400 renderer->vs = create_shader_module(ctx, vs_src, vs_size);
1401 if (renderer->vs == VK_NULL_HANDLE)
1404 renderer->fs = create_shader_module(ctx, fs_src, fs_size);
1405 if (renderer->fs == VK_NULL_HANDLE)
1408 create_pipeline(ctx, color_att->props.w, color_att->props.h,
1409 color_att->props.num_samples, enable_depth,
1410 enable_stencil, renderer);
1412 if (renderer->pipeline == VK_NULL_HANDLE)
1418 fprintf(stderr, "Failed to create graphics pipeline.\n");
1419 vk_destroy_renderer(ctx, renderer);
1424 vk_destroy_renderer(struct vk_ctx *ctx,
1425 struct vk_renderer *renderer)
1427 if (renderer->renderpass != VK_NULL_HANDLE) {
1428 vkDestroyRenderPass(ctx->dev, renderer->renderpass, 0);
1429 renderer->renderpass = VK_NULL_HANDLE;
1432 if (renderer->vs != VK_NULL_HANDLE) {
1433 vkDestroyShaderModule(ctx->dev, renderer->vs, 0);
1434 renderer->vs = VK_NULL_HANDLE;
1437 if (renderer->fs != VK_NULL_HANDLE) {
1438 vkDestroyShaderModule(ctx->dev, renderer->fs, 0);
1439 renderer->fs = VK_NULL_HANDLE;
1442 if (renderer->fb != VK_NULL_HANDLE) {
1443 vkDestroyFramebuffer(ctx->dev, renderer->fb, 0);
1444 renderer->fb = VK_NULL_HANDLE;
1447 if (renderer->pipeline != VK_NULL_HANDLE) {
1448 vkDestroyPipeline(ctx->dev, renderer->pipeline, 0);
1449 renderer->pipeline = VK_NULL_HANDLE;
1452 if (renderer->pipeline_layout != VK_NULL_HANDLE) {
1453 vkDestroyPipelineLayout(ctx->dev, renderer->pipeline_layout, 0);
1454 renderer->pipeline_layout = VK_NULL_HANDLE;
1459 vk_create_ext_buffer(struct vk_ctx *ctx,
1461 VkBufferUsageFlagBits usage,
1464 VkExternalMemoryBufferCreateInfo ext_bo_info;
1466 memset(&ext_bo_info, 0, sizeof ext_bo_info);
1467 ext_bo_info.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO;
1468 ext_bo_info.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;
1470 if (!vk_create_buffer(ctx, true, sz, usage, &ext_bo_info, bo)) {
1471 fprintf(stderr, "Failed to allocate external buffer.\n");
1479 vk_create_buffer(struct vk_ctx *ctx,
1482 VkBufferUsageFlagBits usage,
1486 VkBufferCreateInfo buf_info;
1487 VkMemoryRequirements mem_reqs;
1489 bo->mobj.mem = VK_NULL_HANDLE;
1490 bo->buf = VK_NULL_HANDLE;
1492 /* VkBufferCreateInfo */
1493 memset(&buf_info, 0, sizeof buf_info);
1494 buf_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
1496 buf_info.usage = usage;
1497 buf_info.pNext = pnext;
1498 buf_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
1500 if (vkCreateBuffer(ctx->dev, &buf_info, 0, &bo->buf) != VK_SUCCESS)
1503 /* allocate buffer */
1504 vkGetBufferMemoryRequirements(ctx->dev, bo->buf, &mem_reqs);
1505 /* VK_MEMORY_PROPERTY_HOST_COHERENT_BIT bit specifies that the
1506 * host cache management commands vkFlushMappedMemoryRanges and
1507 * vkInvalidateMappedMemoryRanges are not needed to flush host
1508 * writes to the device or make device writes visible to the
1509 * host, respectively. */
1510 bo->mobj.mem = alloc_memory(ctx, is_external, &mem_reqs, VK_NULL_HANDLE,
1512 VK_MEMORY_PROPERTY_HOST_COHERENT_BIT |
1513 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
1515 if (bo->mobj.mem == VK_NULL_HANDLE)
1518 bo->mobj.mem_sz = sz;
1520 if (vkBindBufferMemory(ctx->dev, bo->buf, bo->mobj.mem, 0) != VK_SUCCESS) {
1521 fprintf(stderr, "Failed to bind buffer memory.\n");
1528 fprintf(stderr, "Failed to allocate buffer.\n");
1529 vk_destroy_buffer(ctx, bo);
1534 vk_update_buffer_data(struct vk_ctx *ctx,
1541 if (vkMapMemory(ctx->dev, bo->mobj.mem, 0, data_sz, 0, &map) != VK_SUCCESS) {
1542 fprintf(stderr, "Failed to map buffer memory.\n");
1546 memcpy(map, data, data_sz);
1548 vkUnmapMemory(ctx->dev, bo->mobj.mem);
1552 fprintf(stderr, "Failed to update buffer data. Destroying the buffer.\n");
1553 vk_destroy_buffer(ctx, bo);
1559 vk_destroy_buffer(struct vk_ctx *ctx,
1562 if (bo->buf != VK_NULL_HANDLE)
1563 vkDestroyBuffer(ctx->dev, bo->buf, 0);
1565 if (bo->mobj.mem != VK_NULL_HANDLE)
1566 vkFreeMemory(ctx->dev, bo->mobj.mem, 0);
1568 bo->mobj.mem_sz = 0;
1569 bo->buf = VK_NULL_HANDLE;
1570 bo->mobj.mem = VK_NULL_HANDLE;
1574 vk_draw(struct vk_ctx *ctx,
1576 struct vk_renderer *renderer,
1578 uint32_t vk_fb_color_count,
1579 struct vk_semaphores *semaphores,
1580 struct vk_image_attachment *attachments,
1581 uint32_t n_attachments,
1585 VkCommandBufferBeginInfo cmd_begin_info;
1586 VkRenderPassBeginInfo rp_begin_info;
1588 VkClearValue clear_values[2];
1589 VkSubmitInfo submit_info;
1590 VkDeviceSize offsets[] = {0};
1591 VkPipelineStageFlagBits stage_flags;
1592 struct vk_dims img_size;
1594 assert(vk_fb_color_count == 4);
1596 /* VkCommandBufferBeginInfo */
1597 memset(&cmd_begin_info, 0, sizeof cmd_begin_info);
1598 cmd_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
1599 cmd_begin_info.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT;
1601 /* VkRect2D render area */
1602 memset(&rp_area, 0, sizeof rp_area);
1603 rp_area.extent.width = (uint32_t)w;
1604 rp_area.extent.height = (uint32_t)h;
1605 rp_area.offset.x = x;
1606 rp_area.offset.y = y;
1609 memset(&clear_values[0], 0, sizeof clear_values[0]);
1610 clear_values[0].color.float32[0] = vk_fb_color[0]; /* red */
1611 clear_values[0].color.float32[1] = vk_fb_color[1]; /* green */
1612 clear_values[0].color.float32[2] = vk_fb_color[2]; /* blue */
1613 clear_values[0].color.float32[3] = vk_fb_color[3]; /* alpha */
1615 memset(&clear_values[1], 0, sizeof clear_values[1]);
1616 clear_values[1].depthStencil.depth = 1.0;
1617 clear_values[1].depthStencil.stencil = 0;
1619 /* VkRenderPassBeginInfo */
1620 memset(&rp_begin_info, 0, sizeof rp_begin_info);
1621 rp_begin_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
1622 rp_begin_info.renderPass = renderer->renderpass;
1623 rp_begin_info.framebuffer = renderer->fb;
1624 rp_begin_info.renderArea = rp_area;
1625 rp_begin_info.clearValueCount = 2;
1626 rp_begin_info.pClearValues = clear_values;
1629 stage_flags = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT;
1631 memset(&submit_info, 0, sizeof submit_info);
1632 submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
1633 submit_info.commandBufferCount = 1;
1634 submit_info.pCommandBuffers = &ctx->cmd_buf;
1638 assert(semaphores->frame_ready);
1639 assert(semaphores->frame_done);
1641 submit_info.pWaitDstStageMask = &stage_flags;
1642 submit_info.waitSemaphoreCount = 1;
1643 submit_info.pWaitSemaphores = &semaphores->frame_done;
1645 submit_info.signalSemaphoreCount = 1;
1646 submit_info.pSignalSemaphores = &semaphores->frame_ready;
1649 vkBeginCommandBuffer(ctx->cmd_buf, &cmd_begin_info);
1650 vkCmdBeginRenderPass(ctx->cmd_buf, &rp_begin_info, VK_SUBPASS_CONTENTS_INLINE);
1655 viewport.height = h;
1657 scissor.offset.x = x;
1658 scissor.offset.y = y;
1659 scissor.extent.width = w;
1660 scissor.extent.height = h;
1662 vkCmdSetViewport(ctx->cmd_buf, 0, 1, &viewport);
1663 vkCmdSetScissor(ctx->cmd_buf, 0, 1, &scissor);
1665 img_size.w = (float)w;
1666 img_size.h = (float)h;
1667 vkCmdPushConstants(ctx->cmd_buf,
1668 renderer->pipeline_layout,
1669 VK_SHADER_STAGE_FRAGMENT_BIT,
1670 0, sizeof (struct vk_dims),
1674 vkCmdBindVertexBuffers(ctx->cmd_buf, 0, 1, &vbo->buf, offsets);
1676 vkCmdBindPipeline(ctx->cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS, renderer->pipeline);
1678 int num_vertices = vbo ? renderer->vertex_info.num_verts : 4;
1679 vkCmdDraw(ctx->cmd_buf, num_vertices, 1, 0, 0);
1680 vkCmdEndRenderPass(ctx->cmd_buf);
1682 VkImageMemoryBarrier *barriers =
1683 calloc(n_attachments, sizeof(VkImageMemoryBarrier));
1684 VkImageMemoryBarrier *barrier = barriers;
1685 for (uint32_t n = 0; n < n_attachments; n++, barrier++) {
1686 struct vk_image_attachment *att = &attachments[n];
1687 VkImageAspectFlagBits depth_stencil_flags =
1688 get_aspect_from_depth_format(att->props.format);
1689 bool is_depth = (depth_stencil_flags != 0);
1691 /* Insert barrier to mark ownership transfer. */
1692 barrier->sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
1693 barrier->oldLayout = is_depth ?
1694 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL :
1695 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
1696 barrier->newLayout = VK_IMAGE_LAYOUT_GENERAL;
1697 barrier->srcAccessMask = get_access_mask(barrier->oldLayout);
1698 barrier->dstAccessMask = get_access_mask(barrier->newLayout);
1699 barrier->srcQueueFamilyIndex = ctx->qfam_idx;
1700 barrier->dstQueueFamilyIndex = VK_QUEUE_FAMILY_EXTERNAL;
1701 barrier->image = att->obj.img;
1702 barrier->subresourceRange.aspectMask = is_depth ?
1703 depth_stencil_flags :
1704 VK_IMAGE_ASPECT_COLOR_BIT;
1705 barrier->subresourceRange.baseMipLevel = 0;
1706 barrier->subresourceRange.levelCount = 1;
1707 barrier->subresourceRange.baseArrayLayer = 0;
1708 barrier->subresourceRange.layerCount = 1;
1711 vkCmdPipelineBarrier(ctx->cmd_buf,
1712 VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
1713 VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
1717 n_attachments, barriers);
1721 vkEndCommandBuffer(ctx->cmd_buf);
1723 if (vkQueueSubmit(ctx->queue, 1, &submit_info, VK_NULL_HANDLE) != VK_SUCCESS) {
1724 fprintf(stderr, "Failed to submit queue.\n");
1728 vkQueueWaitIdle(ctx->queue);
1732 vk_clear_color(struct vk_ctx *ctx,
1734 struct vk_renderer *renderer,
1736 uint32_t vk_fb_color_count,
1737 struct vk_semaphores *semaphores,
1738 bool has_wait, bool has_signal,
1739 struct vk_image_attachment *attachments,
1740 uint32_t n_attachments,
1744 VkCommandBufferBeginInfo cmd_begin_info;
1745 VkRenderPassBeginInfo rp_begin_info;
1747 VkClearValue clear_values[2];
1748 VkSubmitInfo submit_info;
1749 VkPipelineStageFlagBits stage_flags;
1750 VkImageSubresourceRange img_range;
1752 assert(vk_fb_color_count == 4);
1754 /* VkCommandBufferBeginInfo */
1755 memset(&cmd_begin_info, 0, sizeof cmd_begin_info);
1756 cmd_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
1757 cmd_begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
1759 /* VkRect2D render area */
1760 memset(&rp_area, 0, sizeof rp_area);
1761 rp_area.extent.width = (uint32_t)w;
1762 rp_area.extent.height = (uint32_t)h;
1763 rp_area.offset.x = x;
1764 rp_area.offset.y = y;
1767 memset(&clear_values[0], 0, sizeof clear_values[0]);
1768 clear_values[0].color.float32[0] = vk_fb_color[0]; /* red */
1769 clear_values[0].color.float32[1] = vk_fb_color[1]; /* green */
1770 clear_values[0].color.float32[2] = vk_fb_color[2]; /* blue */
1771 clear_values[0].color.float32[3] = vk_fb_color[3]; /* alpha */
1773 memset(&clear_values[1], 0, sizeof clear_values[1]);
1774 clear_values[1].depthStencil.depth = 1.0;
1775 clear_values[1].depthStencil.stencil = 0;
1777 /* VkRenderPassBeginInfo */
1778 memset(&rp_begin_info, 0, sizeof rp_begin_info);
1779 rp_begin_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
1780 rp_begin_info.renderPass = renderer->renderpass;
1781 rp_begin_info.framebuffer = renderer->fb;
1782 rp_begin_info.renderArea = rp_area;
1783 rp_begin_info.clearValueCount = 2;
1784 rp_begin_info.pClearValues = clear_values;
1787 stage_flags = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT;
1789 memset(&submit_info, 0, sizeof submit_info);
1790 submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
1791 submit_info.commandBufferCount = 1;
1792 submit_info.pCommandBuffers = &ctx->cmd_buf;
1796 submit_info.pWaitDstStageMask = &stage_flags;
1797 submit_info.waitSemaphoreCount = 1;
1798 submit_info.pWaitSemaphores = &semaphores->frame_done;
1802 submit_info.signalSemaphoreCount = 1;
1803 submit_info.pSignalSemaphores = &semaphores->frame_ready;
1806 img_range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
1807 img_range.baseMipLevel = 0;
1808 img_range.levelCount = 1;
1809 img_range.baseArrayLayer = 0;
1810 img_range.layerCount = 1;
1812 vkBeginCommandBuffer(ctx->cmd_buf, &cmd_begin_info);
1813 vk_transition_image_layout(&attachments[0],
1815 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
1816 VK_IMAGE_LAYOUT_GENERAL,
1817 VK_QUEUE_FAMILY_EXTERNAL,
1819 vkCmdClearColorImage(ctx->cmd_buf,
1820 attachments[0].obj.img,
1821 VK_IMAGE_LAYOUT_GENERAL,
1822 &clear_values[0].color,
1826 vkCmdBeginRenderPass(ctx->cmd_buf, &rp_begin_info, VK_SUBPASS_CONTENTS_INLINE);
1831 viewport.height = h;
1833 scissor.offset.x = x;
1834 scissor.offset.y = y;
1835 scissor.extent.width = w;
1836 scissor.extent.height = h;
1838 vkCmdSetViewport(ctx->cmd_buf, 0, 1, &viewport);
1839 vkCmdSetScissor(ctx->cmd_buf, 0, 1, &scissor);
1841 vkCmdBindPipeline(ctx->cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS, renderer->pipeline);
1843 vkCmdEndRenderPass(ctx->cmd_buf);
1846 VkImageMemoryBarrier *barriers =
1847 calloc(n_attachments, sizeof(VkImageMemoryBarrier));
1848 VkImageMemoryBarrier *barrier = barriers;
1850 for (uint32_t n = 0; n < n_attachments; n++, barrier++) {
1851 struct vk_image_attachment *att = &attachments[n];
1853 /* Insert barrier to mark ownership transfer. */
1854 barrier->sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
1857 get_aspect_from_depth_format(att->props.format) != VK_NULL_HANDLE;
1859 barrier->oldLayout = is_depth ?
1860 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL :
1861 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
1862 barrier->newLayout = VK_IMAGE_LAYOUT_GENERAL;
1863 barrier->srcAccessMask = get_access_mask(barrier->oldLayout);
1864 barrier->dstAccessMask = get_access_mask(barrier->newLayout);
1865 barrier->srcQueueFamilyIndex = ctx->qfam_idx;
1866 barrier->dstQueueFamilyIndex = VK_QUEUE_FAMILY_EXTERNAL;
1867 barrier->image = att->obj.img;
1868 barrier->subresourceRange.aspectMask = is_depth ?
1869 VK_IMAGE_ASPECT_DEPTH_BIT :
1870 VK_IMAGE_ASPECT_COLOR_BIT;
1871 barrier->subresourceRange.baseMipLevel = 0;
1872 barrier->subresourceRange.levelCount = 1;
1873 barrier->subresourceRange.baseArrayLayer = 0;
1874 barrier->subresourceRange.layerCount = 1;
1877 vkCmdPipelineBarrier(ctx->cmd_buf,
1878 VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
1879 VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
1883 n_attachments, barriers);
1887 vkEndCommandBuffer(ctx->cmd_buf);
1889 if (vkQueueSubmit(ctx->queue, 1, &submit_info, VK_NULL_HANDLE) != VK_SUCCESS) {
1890 fprintf(stderr, "Failed to submit queue.\n");
1893 if (!semaphores && !has_wait && !has_signal)
1894 vkQueueWaitIdle(ctx->queue);
1898 vk_create_swapchain(struct vk_ctx *ctx,
1899 int width, int height,
1902 struct vk_swapchain *old_swapchain,
1903 struct vk_swapchain *swapchain)
1905 VkSurfaceCapabilitiesKHR surf_cap;
1906 VkSwapchainCreateInfoKHR s_info;
1908 VkImageSubresourceRange sr;
1912 if (!sc_validate_surface(ctx, surf)) {
1913 fprintf(stderr, "Failed to validate surface!\n");
1917 /* get pdevice capabilities
1918 * will need that to determine the swapchain number of images
1920 if (vkGetPhysicalDeviceSurfaceCapabilitiesKHR(ctx->pdev, surf, &surf_cap) != VK_SUCCESS) {
1921 fprintf(stderr, "Failed to query surface capabilities.\n");
1925 /* allocate and init an empty struct vk_swapchain */
1926 swapchain = malloc(sizeof *swapchain);
1927 memset(swapchain, 0, sizeof *swapchain);
1929 swapchain->surface = surf;
1931 memset(&s_info, 0, sizeof s_info);
1932 s_info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
1934 /* surface format */
1935 if (!sc_select_format(ctx, surf, &s_info)) {
1936 fprintf(stderr, "Failed to determine the surface format.\n");
1939 s_info.surface = surf;
1941 /* number of images */
1942 s_info.minImageCount = surf_cap.minImageCount;
1943 /* swapchain images dims */
1945 extent.width = width;
1946 extent.height = height;
1948 if (!sc_select_supported_present_modes(ctx, surf, has_vsync, &s_info)) {
1949 s_info.presentMode = VK_PRESENT_MODE_FIFO_KHR;
1951 s_info.imageExtent = extent;
1952 s_info.imageArrayLayers = 1;
1953 /* enable color attachment bit and transfer src and transfer dst bits
1954 * too if they are supported */
1956 s_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
1957 if (surf_cap.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_SRC_BIT)
1958 s_info.imageUsage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
1959 if (surf_cap.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_DST_BIT)
1960 s_info.imageUsage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
1962 s_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
1963 s_info.queueFamilyIndexCount = ctx->qfam_idx;
1965 /* we might want to use this function when we recreate the swapchain too */
1966 s_info.preTransform = surf_cap.supportedTransforms &
1967 VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR ?
1968 VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR :
1969 surf_cap.currentTransform;
1971 /* we could also write a sc_select_supported_composite_alpha
1972 * later but VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR is universally
1974 s_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
1975 s_info.clipped = VK_TRUE;
1976 s_info.oldSwapchain = old_swapchain ? old_swapchain->swapchain : 0;
1978 if (vkCreateSwapchainKHR(ctx->dev, &s_info, 0,
1979 &swapchain->swapchain) != VK_SUCCESS) {
1980 fprintf(stderr, "Failed to create a swapchain.\n");
1984 /* if an existing swapchain is recreated we need to destroy
1985 * the old swapchain and clean up the images */
1986 if (old_swapchain) {
1987 for (i = 0; i < old_swapchain->num_images; i++) {
1988 vkDestroyImageView(ctx->dev, old_swapchain->images[i].img_view, 0);
1990 vk_destroy_swapchain(ctx, old_swapchain);
1993 /* get the number of swapchain images and the swapchain images
1994 * and store the new swapchain images
1996 vkGetSwapchainImagesKHR(ctx->dev, swapchain->swapchain, &swapchain->num_images, 0);
1997 printf("number of swapchain images: %d\n", swapchain->num_images);
2000 s_images = malloc(swapchain->num_images * sizeof(VkImage));
2001 vkGetSwapchainImagesKHR(ctx->dev, swapchain->swapchain, &swapchain->num_images, s_images);
2003 swapchain->image_fmt = s_info.imageFormat;
2004 swapchain->images = malloc(swapchain->num_images * sizeof(struct vk_image_obj));
2006 memset(&sr, 0, sizeof sr);
2007 sr.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
2011 for (i = 0; i < swapchain->num_images; i++) {
2012 swapchain->images[i].img = s_images[i];
2013 if (!(create_image_view(ctx,
2014 swapchain->images[i].img,
2015 VK_IMAGE_VIEW_TYPE_2D,
2016 swapchain->image_fmt,
2019 &swapchain->images[i].img_view))) {
2020 fprintf(stderr, "Fail to create an image view from the swapchain image: i=%d\n", i);
2023 if (i < swapchain->num_images - 1) {
2025 for (j = 0; j < i; j++) {
2026 vkDestroyImageView(ctx->dev, swapchain->images[i].img_view, 0);
2031 memset(&swapchain->images[i].mobj, 0, sizeof swapchain->images[i].mobj);
2039 vk_destroy_swapchain(struct vk_ctx *ctx,
2040 struct vk_swapchain *swapchain)
2042 vkDestroySwapchainKHR(ctx->dev, swapchain->swapchain, 0);
2043 vkDestroySurfaceKHR(ctx->inst, swapchain->surface, 0);
2050 vk_copy_image_to_buffer(struct vk_ctx *ctx,
2051 struct vk_image_attachment *src_img,
2052 struct vk_buf *dst_bo,
2055 VkCommandBufferBeginInfo cmd_begin_info;
2056 VkSubmitInfo submit_info;
2057 VkImageAspectFlagBits aspect_mask = get_aspect_from_depth_format(src_img->props.format);
2059 /* VkCommandBufferBeginInfo */
2060 memset(&cmd_begin_info, 0, sizeof cmd_begin_info);
2061 cmd_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
2062 cmd_begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
2064 memset(&submit_info, 0, sizeof submit_info);
2065 submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
2066 submit_info.commandBufferCount = 1;
2067 submit_info.pCommandBuffers = &ctx->cmd_buf;
2069 vkBeginCommandBuffer(ctx->cmd_buf, &cmd_begin_info);
2070 if (src_img->props.end_layout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL && dst_bo) {
2071 vk_transition_image_layout(src_img,
2073 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
2074 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
2075 VK_QUEUE_FAMILY_EXTERNAL,
2078 /* copy image to buf */
2079 VkBufferImageCopy copy_region = {
2081 .bufferRowLength = w,
2082 .bufferImageHeight = h,
2083 .imageSubresource = {
2084 .aspectMask = aspect_mask ? aspect_mask
2085 : VK_IMAGE_ASPECT_COLOR_BIT,
2087 .baseArrayLayer = 0,
2090 .imageOffset = { 0, 0, 0 },
2091 .imageExtent = { w, h, 1 }
2094 vkCmdCopyImageToBuffer(ctx->cmd_buf,
2096 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
2097 dst_bo->buf, 1, ©_region);
2099 vk_transition_image_layout(src_img,
2101 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
2102 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
2103 VK_QUEUE_FAMILY_EXTERNAL,
2106 VkBufferMemoryBarrier write_finish_buffer_memory_barrier = {
2107 .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
2108 .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
2109 .dstAccessMask = VK_ACCESS_HOST_READ_BIT,
2110 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_EXTERNAL,
2111 .dstQueueFamilyIndex = ctx->qfam_idx,
2112 .buffer = dst_bo->buf,
2114 .size = VK_WHOLE_SIZE
2117 vkCmdPipelineBarrier(ctx->cmd_buf,
2118 VK_PIPELINE_STAGE_TRANSFER_BIT,
2119 VK_PIPELINE_STAGE_HOST_BIT,
2120 (VkDependencyFlags) 0, 0, NULL,
2121 1, &write_finish_buffer_memory_barrier,
2124 vkEndCommandBuffer(ctx->cmd_buf);
2126 if (vkQueueSubmit(ctx->queue, 1, &submit_info, VK_NULL_HANDLE) != VK_SUCCESS) {
2127 fprintf(stderr, "Failed to submit queue.\n");
2129 vkQueueWaitIdle(ctx->queue);
2133 vk_create_semaphores(struct vk_ctx *ctx,
2135 struct vk_semaphores *semaphores)
2137 VkSemaphoreCreateInfo sema_info;
2138 VkExportSemaphoreCreateInfo exp_sema_info;
2141 /* VkExportSemaphoreCreateInfo */
2142 memset(&exp_sema_info, 0, sizeof exp_sema_info);
2143 exp_sema_info.sType = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO;
2144 exp_sema_info.handleTypes = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT;
2147 /* VkSemaphoreCreateInfo */
2148 memset(&sema_info, 0, sizeof sema_info);
2149 sema_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
2150 sema_info.pNext = is_external ? &exp_sema_info : 0;
2152 if (vkCreateSemaphore(ctx->dev, &sema_info, 0, &semaphores->frame_ready) != VK_SUCCESS) {
2153 fprintf(stderr, "Failed to create semaphore frame_ready.\n");
2157 if (vkCreateSemaphore(ctx->dev, &sema_info, 0, &semaphores->frame_done) != VK_SUCCESS) {
2158 fprintf(stderr, "Failed to create semaphore frame_done.\n");
2166 vk_destroy_semaphores(struct vk_ctx *ctx,
2167 struct vk_semaphores *semaphores)
2169 if (semaphores->frame_ready)
2170 vkDestroySemaphore(ctx->dev, semaphores->frame_ready, 0);
2171 if (semaphores->frame_done)
2172 vkDestroySemaphore(ctx->dev, semaphores->frame_done, 0);
2176 vk_create_fences(struct vk_ctx *ctx,
2178 VkFenceCreateFlagBits flags,
2181 VkFenceCreateInfo f_info;
2184 memset(&f_info, 0, sizeof f_info);
2185 f_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
2186 f_info.flags = flags ? flags : VK_FENCE_CREATE_SIGNALED_BIT;
2189 fences = malloc(num_cmd_buf * sizeof(VkFence));
2190 for (i = 0; i < num_cmd_buf; i++) {
2191 if (vkCreateFence(ctx->dev, &f_info, 0, &fences[i]) != VK_SUCCESS) {
2192 fprintf(stderr, "Failed to create fence number: %d\n", (i + 1));
2199 for (i = 0; i < j; i++) {
2200 vkDestroyFence(ctx->dev, fences[i], 0);
2209 vk_destroy_fences(struct vk_ctx *ctx,
2214 for (i = 0; i < num_fences; i++) {
2215 vkDestroyFence(ctx->dev, fences[i], 0);
2220 vk_transition_image_layout(struct vk_image_attachment *img_att,
2221 VkCommandBuffer cmd_buf,
2222 VkImageLayout old_layout,
2223 VkImageLayout new_layout,
2224 uint32_t src_queue_fam_idx,
2225 uint32_t dst_queue_fam_idx)
2227 VkImageMemoryBarrier barrier;
2228 struct vk_image_props props = img_att->props;
2229 VkImageAspectFlagBits aspect_mask = get_aspect_from_depth_format(props.format);
2231 memset(&barrier, 0, sizeof barrier);
2232 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
2233 barrier.srcAccessMask = get_access_mask(old_layout);
2234 barrier.dstAccessMask = get_access_mask(new_layout);
2235 barrier.oldLayout = old_layout;
2236 barrier.newLayout = new_layout;
2237 barrier.srcQueueFamilyIndex = src_queue_fam_idx;
2238 barrier.dstQueueFamilyIndex = dst_queue_fam_idx;
2239 barrier.image = img_att->obj.img;
2240 barrier.subresourceRange.aspectMask = aspect_mask ? aspect_mask :
2241 VK_IMAGE_ASPECT_COLOR_BIT;
2242 barrier.subresourceRange.levelCount = 1;
2243 barrier.subresourceRange.layerCount = 1;
2245 vkCmdPipelineBarrier(cmd_buf,
2246 get_pipeline_stage_flags(old_layout),
2247 get_pipeline_stage_flags(new_layout),
2248 0, 0, VK_NULL_HANDLE, 0, VK_NULL_HANDLE, 1, &barrier);