10 static VkViewport viewport;
11 static VkRect2D scissor;
12 static VkPipelineCache pipeline_cache;
14 /* when I extend the program to use more than one buffers
15 * I might need to store them in this list and access it
16 * using multiple threads
21 static VkCommandBuffer *command_buffers;
22 static uint32_t num_command_buffers;
25 /* static functions */
27 static VkSampleCountFlagBits
28 get_num_samples(uint32_t num_samples)
32 return VK_SAMPLE_COUNT_64_BIT;
34 return VK_SAMPLE_COUNT_32_BIT;
36 return VK_SAMPLE_COUNT_16_BIT;
38 return VK_SAMPLE_COUNT_8_BIT;
40 return VK_SAMPLE_COUNT_4_BIT;
42 return VK_SAMPLE_COUNT_2_BIT;
46 fprintf(stderr, "Invalid number of samples in VkSampleCountFlagBits. Using one sample.\n");
49 return VK_SAMPLE_COUNT_1_BIT;
52 static VkAccessFlagBits
53 get_access_mask(const VkImageLayout layout)
55 /* dstAccessMask of barriers must be supported from the pipeline
56 * stage, see also access scopes and this table:
57 * https://www.khronos.org/registry/vulkan/specs/1.2-extensions/html/vkspec.html#synchronization-access-types-supported
60 case VK_IMAGE_LAYOUT_UNDEFINED:
62 case VK_IMAGE_LAYOUT_GENERAL:
63 return VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT;
64 case VK_IMAGE_LAYOUT_PREINITIALIZED:
65 return VK_ACCESS_HOST_WRITE_BIT;
66 case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
67 return VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
68 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
69 case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
70 return VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_INPUT_ATTACHMENT_READ_BIT;
71 case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
72 return VK_ACCESS_TRANSFER_READ_BIT;
73 case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
74 return VK_ACCESS_TRANSFER_WRITE_BIT;
75 case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR:
85 enable_validation_layers(VkInstanceCreateInfo *info)
89 VkLayerProperties *layers;
90 static const char *layer_names[] = {
91 "VK_LAYER_KHRONOS_validation",
94 vkEnumerateInstanceLayerProperties(&num_layers, 0);
95 layers = alloca(num_layers * sizeof *layers);
96 vkEnumerateInstanceLayerProperties(&num_layers, layers);
99 printf("Available validation layers:\n");
100 for(i = 0; i < (int)num_layers; i++) {
101 printf(" %s\n", layers[i].layerName);
104 info->ppEnabledLayerNames = layer_names;
105 info->enabledLayerCount = sizeof layer_names / sizeof *layer_names;
107 fprintf(stderr, "Vulkan validation layers not found.\n");
112 enable_extensions(VkInstanceCreateInfo *info)
114 static const char *ext_names[] = {
115 "VK_KHR_xcb_surface",
119 uint32_t num_extensions;
120 VkExtensionProperties *extensions;
123 vkEnumerateInstanceExtensionProperties(0, &num_extensions, 0);
124 if (!num_extensions) {
125 fprintf(stderr, "No instance extensions found.\n");
129 extensions = alloca(num_extensions * sizeof *extensions);
130 vkEnumerateInstanceExtensionProperties(0, &num_extensions, extensions);
132 printf("Available extensions:\n");
133 for (i = 0; i < num_extensions; i++) {
134 printf(" %s\n", extensions[i].extensionName);
137 info->ppEnabledExtensionNames = ext_names;
138 info->enabledExtensionCount = ARRAY_SIZE(ext_names);
142 create_instance(bool enable_layers)
144 VkApplicationInfo app_info;
145 VkInstanceCreateInfo inst_info;
148 /* VkApplicationInfo */
149 memset(&app_info, 0, sizeof app_info);
150 app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
151 app_info.pApplicationName = "vktest";
152 app_info.apiVersion = VK_API_VERSION_1_1;
154 /* VkInstanceCreateInfo */
155 memset(&inst_info, 0, sizeof inst_info);
156 inst_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
157 inst_info.pApplicationInfo = &app_info;
159 enable_extensions(&inst_info);
161 enable_validation_layers(&inst_info);
164 if (vkCreateInstance(&inst_info, 0, &inst) != VK_SUCCESS)
170 static VkPhysicalDevice
171 select_physical_device(VkInstance inst)
173 VkResult res = VK_SUCCESS;
174 uint32_t dev_count = 0;
175 VkPhysicalDevice *pdevices;
176 VkPhysicalDevice pdevice0;
179 vkEnumeratePhysicalDevices(inst, &dev_count, 0)) != VK_SUCCESS)
182 pdevices = malloc(dev_count * sizeof(VkPhysicalDevice));
183 if (vkEnumeratePhysicalDevices(inst, &dev_count, pdevices) !=
187 pdevice0 = pdevices[0];
194 create_device(struct vk_ctx *ctx, VkPhysicalDevice pdev)
196 const char *deviceExtensions[] = { "VK_KHR_swapchain" };
197 VkDeviceQueueCreateInfo dev_queue_info;
198 VkDeviceCreateInfo dev_info;
201 VkQueueFamilyProperties *fam_props;
206 vkGetPhysicalDeviceQueueFamilyProperties(pdev, &prop_count, 0);
207 if (prop_count < 0) {
208 fprintf(stderr, "Invalid queue family properties.\n");
212 fam_props = malloc(prop_count * sizeof *fam_props);
213 vkGetPhysicalDeviceQueueFamilyProperties(pdev, &prop_count, fam_props);
215 for (i = 0; i < prop_count; i++) {
216 if (fam_props[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
223 memset(&dev_queue_info, 0, sizeof dev_queue_info);
224 dev_queue_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
225 dev_queue_info.queueFamilyIndex = ctx->qfam_idx;
226 dev_queue_info.queueCount = 1;
227 dev_queue_info.pQueuePriorities = &qprio;
229 memset(&dev_info, 0, sizeof dev_info);
230 dev_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
231 dev_info.queueCreateInfoCount = 1;
232 dev_info.pQueueCreateInfos = &dev_queue_info;
233 dev_info.enabledExtensionCount = ARRAY_SIZE(deviceExtensions);
234 dev_info.ppEnabledExtensionNames = deviceExtensions;
236 if (vkCreateDevice(pdev, &dev_info, 0, &dev) != VK_SUCCESS)
243 fill_uuid(VkPhysicalDevice pdev, uint8_t *deviceUUID, uint8_t *driverUUID)
245 VkPhysicalDeviceIDProperties devProp;
246 VkPhysicalDeviceProperties2 prop2;
248 memset(&devProp, 0, sizeof devProp);
249 devProp.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES;
251 memset(&prop2, 0, sizeof prop2);
252 prop2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
253 prop2.pNext = &devProp;
255 vkGetPhysicalDeviceProperties2(pdev, &prop2);
256 memcpy(deviceUUID, devProp.deviceUUID, VK_UUID_SIZE);
257 memcpy(driverUUID, devProp.driverUUID, VK_UUID_SIZE);
261 create_cmd_pool(struct vk_ctx *ctx)
263 VkCommandPoolCreateInfo cmd_pool_info;
264 VkCommandPool cmd_pool;
266 memset(&cmd_pool_info, 0, sizeof cmd_pool_info);
267 cmd_pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
268 cmd_pool_info.queueFamilyIndex = ctx->qfam_idx;
269 cmd_pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
271 if (vkCreateCommandPool(ctx->dev, &cmd_pool_info, 0, &cmd_pool) != VK_SUCCESS)
277 static VkPipelineCache
278 create_pipeline_cache(struct vk_ctx *ctx)
280 VkPipelineCacheCreateInfo pc_info;
281 VkPipelineCache pcache;
283 memset(&pc_info, 0, sizeof pc_info);
284 pc_info.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;
286 if (vkCreatePipelineCache(ctx->dev, &pc_info, 0, &pcache) != VK_SUCCESS) {
287 fprintf(stderr, "Failed to create a pipeline cache.\n");
288 return VK_NULL_HANDLE;
295 create_renderpass(struct vk_ctx *ctx,
296 uint32_t num_color_atts,
297 struct vk_attachment *color_atts,
298 struct vk_attachment *depth_att)
300 VkAttachmentDescription *att_dsc;
301 VkAttachmentReference *att_rfc;
303 /* one subpass for the moment: */
304 VkSubpassDescription subpass_dsc[1];
305 VkRenderPassCreateInfo rpass_info;
308 uint32_t num_atts = num_color_atts + 1;
309 bool has_layout = depth_att->props.in_layout !=
310 VK_IMAGE_LAYOUT_UNDEFINED;
312 att_dsc = malloc(num_atts * sizeof att_dsc[0]);
313 att_rfc = malloc(num_atts * sizeof att_rfc[0]);
315 memset(att_dsc, 0, num_atts * sizeof att_dsc[0]);
316 memset(att_rfc, 0, num_atts * sizeof att_rfc[0]);
318 /* color attachments description (we can have many) */
319 for (i = 0; i < num_color_atts; i++) {
320 att_dsc[i].samples = get_num_samples(color_atts[i].props.num_samples);
321 att_dsc[i].initialLayout = color_atts[i].props.in_layout;
322 att_dsc[i].finalLayout = color_atts[i].props.end_layout;
323 att_dsc[i].format = color_atts[i].props.format;
325 att_dsc[i].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
326 att_dsc[i].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
327 att_dsc[i].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
328 att_dsc[i].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
330 att_rfc[i].attachment = i;
331 att_rfc[i].layout = color_atts[i].props.tiling != VK_IMAGE_TILING_OPTIMAL ?
332 VK_IMAGE_LAYOUT_GENERAL :
333 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
337 /* depth attachment description (we can have only one) */
338 att_dsc[num_color_atts].samples = get_num_samples(depth_att->props.num_samples);
339 att_dsc[num_color_atts].initialLayout = depth_att->props.in_layout;
340 att_dsc[num_color_atts].finalLayout = depth_att->props.end_layout;
341 att_dsc[num_color_atts].format = depth_att->props.format;
342 /* we might want to reuse the depth buffer when it's filled */
343 att_dsc[num_color_atts].loadOp = has_layout ?
344 VK_ATTACHMENT_LOAD_OP_LOAD :
345 VK_ATTACHMENT_LOAD_OP_CLEAR;
346 att_dsc[num_color_atts].stencilLoadOp = has_layout ?
347 VK_ATTACHMENT_LOAD_OP_LOAD :
348 VK_ATTACHMENT_LOAD_OP_CLEAR;
349 att_dsc[num_color_atts].stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
350 att_rfc[num_color_atts].layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
351 att_rfc[num_color_atts].attachment = num_color_atts;
353 /* VkSubpassDescription */
354 memset(&subpass_dsc, 0, sizeof subpass_dsc);
355 subpass_dsc[0].pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
356 subpass_dsc[0].colorAttachmentCount = num_color_atts;
357 subpass_dsc[0].pColorAttachments = &att_rfc[0];
358 subpass_dsc[0].pDepthStencilAttachment = &att_rfc[num_color_atts];
360 /* VkRenderPassCreateInfo */
361 memset(&rpass_info, 0, sizeof rpass_info);
362 rpass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
363 rpass_info.attachmentCount = num_atts;
364 rpass_info.pAttachments = att_dsc;
365 rpass_info.subpassCount = 1;
366 rpass_info.pSubpasses = subpass_dsc;
369 if (vkCreateRenderPass(ctx->dev, &rpass_info, 0, &rpass) != VK_SUCCESS) {
370 fprintf(stderr, "Failed to create renderpass.\n");
371 rpass = VK_NULL_HANDLE;
380 static inline VkImageType
381 get_image_type(uint32_t h, uint32_t d)
384 return VK_IMAGE_TYPE_1D;
387 return VK_IMAGE_TYPE_3D;
389 return VK_IMAGE_TYPE_2D;
393 static VkImageViewType
394 get_image_view_type(struct vk_att_props *props)
396 VkImageType type = get_image_type(props->h, props->depth);
398 case VK_IMAGE_TYPE_1D:
399 return props->num_layers > 1 ?
400 VK_IMAGE_VIEW_TYPE_1D_ARRAY :
401 VK_IMAGE_VIEW_TYPE_1D;
402 case VK_IMAGE_TYPE_2D:
403 if (props->num_layers == 1)
404 return VK_IMAGE_VIEW_TYPE_2D;
405 if (props->num_layers == 6)
406 return VK_IMAGE_VIEW_TYPE_CUBE;
407 if (props->num_layers % 6 == 0)
408 return VK_IMAGE_VIEW_TYPE_CUBE_ARRAY;
409 if (props->num_layers > 1)
410 return VK_IMAGE_VIEW_TYPE_2D_ARRAY;
411 case VK_IMAGE_TYPE_3D:
412 if (props->num_layers == 1)
413 return VK_IMAGE_VIEW_TYPE_3D;
414 if ((props->num_layers == 1) &&
415 (props->num_levels == 1))
416 return VK_IMAGE_VIEW_TYPE_2D;
417 if ((props->num_levels == 1) &&
418 (props->num_layers > 1))
419 return VK_IMAGE_VIEW_TYPE_2D_ARRAY;
421 return VK_IMAGE_VIEW_TYPE_2D;
426 static VkImageAspectFlagBits
427 get_aspect_from_depth_format(VkFormat depth_format)
429 switch (depth_format) {
430 case VK_FORMAT_D16_UNORM:
431 case VK_FORMAT_X8_D24_UNORM_PACK32:
432 case VK_FORMAT_D32_SFLOAT:
433 return VK_IMAGE_ASPECT_DEPTH_BIT;
434 case VK_FORMAT_S8_UINT:
435 return VK_IMAGE_ASPECT_STENCIL_BIT;
436 case VK_FORMAT_D16_UNORM_S8_UINT:
437 case VK_FORMAT_D24_UNORM_S8_UINT:
438 case VK_FORMAT_D32_SFLOAT_S8_UINT:
439 return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
446 static VkPipelineStageFlags
447 get_pipeline_stage_flags(const VkImageLayout layout)
450 case VK_IMAGE_LAYOUT_UNDEFINED:
451 return VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
452 case VK_IMAGE_LAYOUT_GENERAL:
453 return VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
454 case VK_IMAGE_LAYOUT_PREINITIALIZED:
455 return VK_PIPELINE_STAGE_HOST_BIT;
456 case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
457 case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
458 return VK_PIPELINE_STAGE_TRANSFER_BIT;
459 case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
460 return VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
461 case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
462 return VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
463 VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
464 case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR:
465 return VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
473 create_image_view(struct vk_ctx *ctx,
475 VkImageViewType view_type,
477 VkImageSubresourceRange sr,
479 VkImageView *image_view)
481 VkImageViewCreateInfo info;
483 memset(&info, 0, sizeof info);
484 info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
486 info.viewType = view_type;
487 info.viewType = VK_IMAGE_VIEW_TYPE_2D;
488 info.format = format;
489 info.subresourceRange = sr;
492 info.components.r = VK_COMPONENT_SWIZZLE_R;
493 info.components.g = VK_COMPONENT_SWIZZLE_G;
494 info.components.b = VK_COMPONENT_SWIZZLE_B;
495 info.components.a = VK_COMPONENT_SWIZZLE_A;
498 if (vkCreateImageView(ctx->dev, &info, 0, image_view) != VK_SUCCESS) {
499 fprintf(stderr, "Failed to create image view.\n");
500 image_view = VK_NULL_HANDLE;
509 create_attachment_views(struct vk_ctx *ctx, int num_color_att,
510 struct vk_attachment *color_att,
511 struct vk_attachment *depth_att)
513 VkImageSubresourceRange sr;
516 /* depth attachments */
517 memset(&sr, 0, sizeof sr);
518 sr.aspectMask = get_aspect_from_depth_format(depth_att->props.format);
521 sr.baseArrayLayer = 0;
524 create_image_view(ctx, depth_att->obj.img, VK_IMAGE_VIEW_TYPE_2D,
525 depth_att->props.format, sr, false,
526 &depth_att->obj.img_view);
528 memset(&sr, 0, sizeof sr);
529 sr.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
531 for (i = 0; i < num_color_att; i++) {
532 /* FIXME: in case of mipmaps */
534 sr.levelCount = color_att[i].props.num_levels;
535 sr.baseArrayLayer = 0;
536 sr.layerCount = color_att[i].props.num_layers;
538 create_image_view(ctx, color_att[i].obj.img, VK_IMAGE_VIEW_TYPE_2D,
539 color_att[i].props.format, sr, color_att[i].props.is_swapchain,
540 &color_att[i].obj.img_view);
547 create_framebuffer(struct vk_ctx *ctx,
548 int width, int height,
550 struct vk_attachment *color_att,
551 struct vk_attachment *depth_att,
552 struct vk_renderer *renderer)
554 VkFramebufferCreateInfo fb_info;
557 int num_atts = num_color_atts + 1;
559 atts = malloc(num_atts * sizeof atts[0]);
561 for (i = 0; i < num_color_atts; i++) {
562 atts[i] = color_att[i].obj.img_view;
564 atts[num_color_atts] = depth_att->obj.img_view;
566 memset(&fb_info, 0, sizeof fb_info);
567 fb_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
568 fb_info.renderPass = renderer->renderpass;
569 fb_info.width = width;
570 fb_info.height = height;
572 fb_info.attachmentCount = num_atts;
573 fb_info.pAttachments = atts;
575 if (vkCreateFramebuffer(ctx->dev, &fb_info, 0, &renderer->fb) != VK_SUCCESS)
582 fprintf(stderr, "Failed to create framebuffer.\n");
584 renderer->fb = VK_NULL_HANDLE;
587 static VkShaderModule
588 create_shader_module(struct vk_ctx *ctx,
592 VkShaderModuleCreateInfo sm_info;
595 /* VkShaderModuleCreateInfo */
596 memset(&sm_info, 0, sizeof sm_info);
597 sm_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
598 sm_info.codeSize = size;
599 sm_info.pCode = (void*)src;
601 if (vkCreateShaderModule(ctx->dev, &sm_info, 0, &sm) != VK_SUCCESS) {
602 fprintf(stderr, "Failed to create shader module.\n");
610 create_graphics_pipeline(struct vk_ctx *ctx,
613 uint32_t num_samples,
614 uint32_t num_color_atts,
617 struct vk_renderer *renderer)
619 VkVertexInputBindingDescription vert_bind_dsc[1];
620 VkVertexInputAttributeDescription vert_att_dsc[1];
622 VkPipelineColorBlendAttachmentState *cb_att_state;
623 VkPipelineVertexInputStateCreateInfo vert_input_info;
624 VkPipelineInputAssemblyStateCreateInfo asm_info;
625 VkPipelineViewportStateCreateInfo viewport_info;
626 VkPipelineRasterizationStateCreateInfo rs_info;
627 VkPipelineMultisampleStateCreateInfo ms_info;
628 VkPipelineDepthStencilStateCreateInfo ds_info;
629 VkPipelineColorBlendStateCreateInfo cb_info;
630 VkPipelineShaderStageCreateInfo sdr_stages[2];
631 VkPipelineLayoutCreateInfo layout_info;
632 VkGraphicsPipelineCreateInfo pipeline_info;
634 VkFormatProperties fmt_props;
635 VkPushConstantRange pc_range[1];
637 VkStencilOpState front;
638 VkStencilOpState back;
640 VkPipelineLayout pipeline_layout;
643 /* format of vertex attributes:
644 * we have 2D vectors so we need a RG format:
646 * the stride (distance between 2 consecutive elements)
647 * must be 8 because we use 32 bit floats and
649 format = VK_FORMAT_R32G32_SFLOAT;
650 vkGetPhysicalDeviceFormatProperties(ctx->pdev, format, &fmt_props);
651 assert(fmt_props.bufferFeatures & VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT);
654 /* VkVertexInputAttributeDescription */
655 memset(&vert_att_dsc, 0, sizeof vert_att_dsc);
656 vert_att_dsc[0].location = 0;
657 vert_att_dsc[0].binding = 0;
658 vert_att_dsc[0].format = format; /* see comment */
659 vert_att_dsc[0].offset = 0;
661 /* VkVertexInputBindingDescription */
662 memset(&vert_bind_dsc, 0, sizeof vert_bind_dsc);
663 vert_bind_dsc[0].binding = 0;
664 vert_bind_dsc[0].stride = stride;
665 vert_bind_dsc[0].inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
667 /* If using vbo, we have setup vertex_info in the renderer. */
668 bool use_vbo = renderer->vertex_info.num_verts > 0;
670 /* VkPipelineVertexInputStateCreateInfo */
671 memset(&vert_input_info, 0, sizeof vert_input_info);
672 vert_input_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
673 vert_input_info.vertexBindingDescriptionCount = use_vbo ? 1 : 0;
674 vert_input_info.pVertexBindingDescriptions = vert_bind_dsc;
675 vert_input_info.vertexAttributeDescriptionCount = use_vbo ? 1 : 0;
676 vert_input_info.pVertexAttributeDescriptions = vert_att_dsc;
678 /* VkPipelineInputAssemblyStateCreateInfo */
679 memset(&asm_info, 0, sizeof asm_info);
680 asm_info.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
681 asm_info.topology = renderer->vertex_info.topology ?
682 renderer->vertex_info.topology
683 : VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
684 asm_info.primitiveRestartEnable = false;
687 viewport.x = viewport.y = 0;
688 viewport.width = width;
689 viewport.height = height;
690 viewport.minDepth = 0;
691 viewport.maxDepth = 1;
693 /* VkRect2D scissor */
694 scissor.offset.x = scissor.offset.y = 0;
695 scissor.extent.width = width;
696 scissor.extent.height = height;
698 /* VkPipelineViewportStateCreateInfo */
699 memset(&viewport_info, 0, sizeof viewport_info);
700 viewport_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
701 viewport_info.viewportCount = 1;
702 viewport_info.pViewports = &viewport;
703 viewport_info.scissorCount = 1;
704 viewport_info.pScissors = &scissor;
706 /* VkPipelineRasterizationStateCreateInfo */
707 memset(&rs_info, 0, sizeof rs_info);
708 rs_info.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
709 rs_info.polygonMode = VK_POLYGON_MODE_FILL;
710 rs_info.cullMode = VK_CULL_MODE_NONE;
711 rs_info.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
712 rs_info.lineWidth = 1.0;
714 /* VkPipelineMultisampleStateCreateInfo */
715 memset(&ms_info, 0, sizeof ms_info);
716 ms_info.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
717 ms_info.rasterizationSamples = get_num_samples(num_samples);
719 /* VkStencilOpState */
720 /* The default values for ES are taken by Topi Pohjolainen's code */
721 /* defaults in OpenGL ES 3.1 */
722 memset(&front, 0, sizeof front);
723 front.compareMask = ~0;
724 front.writeMask = ~0;
727 memset(&back, 0, sizeof back);
728 back.compareMask = ~0;
732 /* VkPipelineDepthStencilStateCreateInfo */
733 memset(&ds_info, 0, sizeof ds_info);
734 ds_info.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
735 ds_info.front = front;
737 /* defaults in OpenGL ES 3.1 */
738 ds_info.minDepthBounds = 0;
739 ds_info.maxDepthBounds = 1;
740 /* z buffer, stencil buffer */
742 ds_info.depthTestEnable = VK_TRUE;
743 ds_info.depthWriteEnable = VK_TRUE;
744 ds_info.depthCompareOp = VK_COMPARE_OP_LESS;
746 if (enable_stencil) {
747 ds_info.stencilTestEnable = VK_TRUE;
748 ds_info.depthTestEnable = VK_FALSE;
749 ds_info.depthWriteEnable = VK_TRUE;
752 /* we only care about the passOp here */
753 ds_info.back.compareOp = VK_COMPARE_OP_ALWAYS;
754 ds_info.back.failOp = VK_STENCIL_OP_REPLACE;
755 ds_info.back.depthFailOp = VK_STENCIL_OP_REPLACE;
756 ds_info.back.passOp = VK_STENCIL_OP_REPLACE;
757 ds_info.back.compareMask = 0xffffffff;
758 ds_info.back.writeMask = 0xffffffff;
759 ds_info.back.reference = 1;
760 ds_info.front = ds_info.back;
762 /* VkPipelineColorBlendAttachmentState */
763 cb_att_state = malloc(num_color_atts * sizeof cb_att_state[0]);
765 fprintf(stderr, "Failed to allocate color blend attachment state for each attachment.\n");
768 memset(cb_att_state, 0, num_color_atts * sizeof cb_att_state[0]);
769 for (i = 0; i < num_color_atts; i++) {
770 cb_att_state[i].colorWriteMask = (VK_COLOR_COMPONENT_R_BIT |
771 VK_COLOR_COMPONENT_G_BIT |
772 VK_COLOR_COMPONENT_B_BIT |
773 VK_COLOR_COMPONENT_A_BIT);
776 /* VkPipelineColorBlendStateCreateInfo */
777 memset(&cb_info, 0, sizeof cb_info);
778 cb_info.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
779 cb_info.attachmentCount = num_color_atts;
780 cb_info.pAttachments = cb_att_state;
781 /* default in ES 3.1 */
782 for (i = 0; i < 4; i++) {
783 cb_info.blendConstants[i] = 0.0f;
786 /* VkPipelineShaderStageCreateInfo */
787 memset(sdr_stages, 0, 2 * sizeof sdr_stages[0]);
789 sdr_stages[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
790 sdr_stages[0].stage = VK_SHADER_STAGE_VERTEX_BIT;
791 sdr_stages[0].module = renderer->vs;
792 sdr_stages[0].pName = "main";
794 sdr_stages[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
795 sdr_stages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT;
796 sdr_stages[1].module = renderer->fs;
797 sdr_stages[1].pName = "main";
799 /* VkPushConstantRange */
800 memset(pc_range, 0, sizeof pc_range[0]);
801 pc_range[0].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
802 pc_range[0].size = sizeof (struct vk_dims); /* w, h */
804 /* VkPipelineLayoutCreateInfo */
805 memset(&layout_info, 0, sizeof layout_info);
806 layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
807 layout_info.pushConstantRangeCount = 1;
808 layout_info.pPushConstantRanges = pc_range;
810 if (vkCreatePipelineLayout(ctx->dev, &layout_info, 0, &pipeline_layout) != VK_SUCCESS) {
811 fprintf(stderr, "Failed to create pipeline layout\n");
812 renderer->pipeline = VK_NULL_HANDLE;
816 renderer->pipeline_layout = pipeline_layout;
818 /* VkGraphicsPipelineCreateInfo */
819 memset(&pipeline_info, 0, sizeof pipeline_info);
820 pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
821 pipeline_info.layout = pipeline_layout;
822 pipeline_info.renderPass = renderer->renderpass;
823 pipeline_info.pVertexInputState = &vert_input_info;
824 pipeline_info.pInputAssemblyState = &asm_info;
825 pipeline_info.pViewportState = &viewport_info;
826 pipeline_info.pRasterizationState = &rs_info;
827 pipeline_info.pMultisampleState = &ms_info;
828 pipeline_info.pDepthStencilState = &ds_info;
829 pipeline_info.pColorBlendState = &cb_info;
830 pipeline_info.stageCount = 2;
831 pipeline_info.pStages = sdr_stages;
833 if (vkCreateGraphicsPipelines(ctx->dev, 0, 1,
835 &renderer->pipeline) != VK_SUCCESS) {
836 fprintf(stderr, "Failed to create graphics pipeline.\n");
837 renderer->pipeline = VK_NULL_HANDLE;
850 get_memory_type_idx(VkPhysicalDevice pdev,
851 const VkMemoryRequirements *mem_reqs,
852 VkMemoryPropertyFlagBits prop_flags)
854 VkPhysicalDeviceMemoryProperties pdev_mem_props;
857 vkGetPhysicalDeviceMemoryProperties(pdev, &pdev_mem_props);
859 for (i = 0; i < pdev_mem_props.memoryTypeCount; i++) {
860 const VkMemoryType *type = &pdev_mem_props.memoryTypes[i];
862 if ((mem_reqs->memoryTypeBits & (1 << i)) &&
863 (type->propertyFlags & prop_flags) == prop_flags) {
871 static VkDeviceMemory
872 alloc_memory(struct vk_ctx *ctx,
874 const VkMemoryRequirements *mem_reqs,
877 VkMemoryPropertyFlagBits prop_flags)
879 VkExportMemoryAllocateInfo exp_mem_info;
880 VkMemoryAllocateInfo mem_alloc_info;
882 VkMemoryDedicatedAllocateInfoKHR ded_info;
885 memset(&exp_mem_info, 0, sizeof exp_mem_info);
886 exp_mem_info.sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO;
887 exp_mem_info.handleTypes =
888 VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
891 memset(&mem_alloc_info, 0, sizeof mem_alloc_info);
892 mem_alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
893 mem_alloc_info.pNext = is_external ? &exp_mem_info : VK_NULL_HANDLE;
894 mem_alloc_info.allocationSize = mem_reqs->size;
895 mem_alloc_info.memoryTypeIndex = get_memory_type_idx(ctx->pdev,
899 if (mem_alloc_info.memoryTypeIndex == UINT32_MAX) {
900 fprintf(stderr, "No suitable memory type index found.\n");
904 if (image || buffer) {
905 memset(&ded_info, 0, sizeof ded_info);
906 ded_info.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO;
907 ded_info.image = image;
908 ded_info.buffer = buffer;
910 exp_mem_info.pNext = &ded_info;
913 if (vkAllocateMemory(ctx->dev, &mem_alloc_info, 0, &mem) !=
921 alloc_image_memory(struct vk_ctx *ctx,
923 struct vk_image_obj *img_obj)
925 VkMemoryDedicatedRequirements ded_reqs;
926 VkImageMemoryRequirementsInfo2 req_info2;
927 VkMemoryRequirements2 mem_reqs2;
929 memset(&ded_reqs, 0, sizeof ded_reqs);
930 ded_reqs.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS;
932 /* VkImageMemoryRequirementsInfo2 */
933 memset(&req_info2, 0, sizeof req_info2);
934 req_info2.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2;
935 req_info2.image = img_obj->img;
937 /* VkMemoryRequirements2 */
938 memset(&mem_reqs2, 0, sizeof mem_reqs2);
939 mem_reqs2.sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2;
940 mem_reqs2.pNext = &ded_reqs;
942 vkGetImageMemoryRequirements2(ctx->dev, &req_info2, &mem_reqs2);
943 img_obj->mobj.mem = alloc_memory(ctx,
945 &mem_reqs2.memoryRequirements,
946 ded_reqs.requiresDedicatedAllocation ?
947 img_obj->img : VK_NULL_HANDLE,
949 mem_reqs2.memoryRequirements.memoryTypeBits &
950 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
952 img_obj->mobj.mem_sz = mem_reqs2.memoryRequirements.size;
953 img_obj->mobj.dedicated = ded_reqs.requiresDedicatedAllocation;
954 if (img_obj->mobj.mem == VK_NULL_HANDLE) {
955 fprintf(stderr, "Failed to allocate image memory.\n");
959 if (vkBindImageMemory(ctx->dev, img_obj->img, img_obj->mobj.mem, 0) !=
961 fprintf(stderr, "Failed to bind image memory.\n");
969 are_props_supported(struct vk_ctx *ctx, struct vk_att_props *props)
971 VkPhysicalDeviceExternalImageFormatInfo ext_img_fmt_info;
972 VkExternalImageFormatProperties ext_img_fmt_props;
975 VkPhysicalDeviceImageFormatInfo2 img_fmt_info;
976 VkImageFormatProperties2 img_fmt_props;
978 VkImageUsageFlagBits all_flags[] = {
979 VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
980 VK_IMAGE_USAGE_TRANSFER_DST_BIT,
981 VK_IMAGE_USAGE_SAMPLED_BIT,
982 VK_IMAGE_USAGE_STORAGE_BIT,
983 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
984 VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
985 VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT,
986 /* Shouldn't be used together with COLOR, DEPTH_STENCIL
988 * VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT,
989 * Provided by VK_EXT_fragment_density_map
990 * VK_IMAGE_USAGE_FRAGMENT_DENSITY_MAP_BIT_EXT,
991 * Provided by VK_NV_shading_rate_image
992 * VK_IMAGE_USAGE_SHADING_RATE_IMAGE_BIT_NV,
993 * Provided by VK_KHR_fragment_shading_rate
994 * VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR,
997 VkImageUsageFlagBits flags = 0;
999 VkExternalMemoryFeatureFlagBits export_feature_flags = props->need_export ?
1000 VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT : 0;
1001 VkExternalMemoryHandleTypeFlagBits handle_type = props->need_export ?
1002 VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR : 0;
1004 if (props->need_export) {
1005 memset(&ext_img_fmt_info, 0, sizeof ext_img_fmt_info);
1006 ext_img_fmt_info.sType =
1007 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO;
1008 ext_img_fmt_info.handleType = handle_type;
1010 memset(&ext_img_fmt_props, 0, sizeof ext_img_fmt_props);
1011 ext_img_fmt_props.sType =
1012 VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES;
1015 memset(&img_fmt_props, 0, sizeof img_fmt_props);
1016 img_fmt_props.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2;
1017 img_fmt_props.pNext = props->need_export ? &ext_img_fmt_props : 0;
1019 memset(&img_fmt_info, 0, sizeof img_fmt_info);
1020 img_fmt_info.sType =
1021 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2;
1022 img_fmt_info.pNext = props->need_export ? &ext_img_fmt_info : 0;
1023 img_fmt_info.format = props->format;
1024 img_fmt_info.type = VK_IMAGE_TYPE_2D;
1025 img_fmt_info.tiling = props->tiling;
1027 for (i = 0; i < ARRAY_SIZE(all_flags); i++) {
1028 img_fmt_info.usage = all_flags[i];
1029 if (vkGetPhysicalDeviceImageFormatProperties2(ctx->pdev,
1031 &img_fmt_props) == VK_SUCCESS) {
1032 flags |= all_flags[i];
1036 /* usage can't be null */
1038 img_fmt_info.usage = flags;
1040 if (!props->is_swapchain) {
1041 fprintf(stderr, "Unsupported Vulkan format properties: usage.\n");
1044 img_fmt_info.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
1047 if (vkGetPhysicalDeviceImageFormatProperties2
1048 (ctx->pdev, &img_fmt_info, &img_fmt_props) != VK_SUCCESS) {
1050 "Unsupported Vulkan format properties.\n");
1053 props->usage = flags;
1055 if (props->need_export &&
1056 !(ext_img_fmt_props.externalMemoryProperties.externalMemoryFeatures
1057 & export_feature_flags)) {
1058 fprintf(stderr, "Unsupported Vulkan external memory features.\n");
1065 /* static swapchain / surf related functions */
1068 sc_validate_surface(struct vk_ctx *ctx,
1073 fprintf(stderr, "No surface!\n");
1077 if(vkGetPhysicalDeviceSurfaceSupportKHR(ctx->pdev, ctx->qfam_idx, surf, &supported) != VK_SUCCESS) {
1078 fprintf(stderr, "Failed to validate surface.\n");
1083 fprintf(stderr, "Invalid surface! Check if the surface with queue family index: %d supports presentation.\n", (int)ctx->qfam_idx);
1091 sc_select_format(struct vk_ctx *ctx,
1093 VkSwapchainCreateInfoKHR *s_info)
1095 VkSurfaceFormatKHR *formats;
1096 uint32_t num_formats;
1098 if (vkGetPhysicalDeviceSurfaceFormatsKHR(ctx->pdev, surf, &num_formats, 0) != VK_SUCCESS) {
1099 fprintf(stderr, "Failed to get the number of surface formats.\n");
1104 fprintf(stderr, "No surface formats found.\n");
1108 formats = malloc(num_formats * sizeof *formats);
1110 if (vkGetPhysicalDeviceSurfaceFormatsKHR(ctx->pdev, surf, &num_formats, formats) != VK_SUCCESS) {
1111 fprintf(stderr, "Failed to get the supported surface formats.\n");
1115 if ((num_formats == 1) && (formats[0].format == VK_FORMAT_UNDEFINED)) {
1116 s_info->imageFormat = VK_FORMAT_B8G8R8A8_UNORM;
1117 s_info->imageColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
1119 s_info->imageFormat = formats[0].format;
1120 s_info->imageColorSpace = formats[0].colorSpace;
1128 sc_select_supported_present_modes(struct vk_ctx *ctx,
1131 VkSwapchainCreateInfoKHR *s_info)
1133 VkPresentModeKHR *present_modes;
1134 uint32_t num_present_modes;
1136 /* find supported present modes */
1137 if (vkGetPhysicalDeviceSurfacePresentModesKHR(ctx->pdev, surf, &num_present_modes, 0) != VK_SUCCESS || !num_present_modes) {
1138 fprintf(stderr, "Failed to get the number of the supported presentation modes.\n");
1142 present_modes = malloc(num_present_modes * sizeof *present_modes);
1143 if (vkGetPhysicalDeviceSurfacePresentModesKHR(ctx->pdev, surf, &num_present_modes, present_modes) != VK_SUCCESS) {
1144 fprintf(stderr, "Failed to get the number of supported presentation modes.\n");
1147 if (vkGetPhysicalDeviceSurfacePresentModesKHR(ctx->pdev, surf, &num_present_modes,
1148 present_modes) != VK_SUCCESS) {
1149 fprintf(stderr, "Failed to get the supported presentation modes.\n");
1153 s_info->presentMode = VK_PRESENT_MODE_FIFO_KHR;
1156 for (i = 0; i < num_present_modes; i++) {
1157 if (present_modes[i] == VK_PRESENT_MODE_MAILBOX_KHR) {
1158 s_info->presentMode = present_modes[i];
1161 if (present_modes[i] == VK_PRESENT_MODE_IMMEDIATE_KHR) {
1162 s_info->presentMode = present_modes[i];
1169 free(present_modes);
1173 /* end of static functions */
1175 /* exposed Vulkan functions */
1178 vk_init_ctx(struct vk_ctx *ctx,
1181 if ((ctx->inst = create_instance(enable_layers)) == VK_NULL_HANDLE) {
1182 fprintf(stderr, "Failed to create Vulkan instance.\n");
1186 if ((ctx->pdev = select_physical_device(ctx->inst)) == VK_NULL_HANDLE) {
1187 fprintf(stderr, "Failed to find suitable physical device.\n");
1191 if ((ctx->dev = create_device(ctx, ctx->pdev)) == VK_NULL_HANDLE) {
1192 fprintf(stderr, "Failed to create Vulkan device.\n");
1196 fill_uuid(ctx->pdev, ctx->deviceUUID, ctx->driverUUID);
1200 vk_cleanup_ctx(ctx);
1205 vk_init_ctx_for_rendering(struct vk_ctx *ctx,
1209 if (!vk_init_ctx(ctx, enable_layers)) {
1210 fprintf(stderr, "Failed to initialize Vulkan.\n");
1214 if ((ctx->cmd_pool = create_cmd_pool(ctx)) == VK_NULL_HANDLE) {
1215 fprintf(stderr, "Failed to create command pool.\n");
1219 vkGetDeviceQueue(ctx->dev, ctx->qfam_idx, 0, &ctx->queue);
1221 fprintf(stderr, "Failed to get command queue.\n");
1226 if (!(pipeline_cache = create_pipeline_cache(ctx))) {
1227 fprintf(stderr, "Failed to create pipeline cache.\n");
1235 vk_cleanup_ctx(ctx);
1240 vk_destroy_cmd_buffers(struct vk_ctx *ctx,
1241 uint32_t num_buffers,
1242 VkCommandBuffer *buffers)
1245 for (i = 0; i < num_buffers; i++) {
1246 vkResetCommandBuffer(buffers[i],
1247 VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT);
1249 vkFreeCommandBuffers(ctx->dev, ctx->cmd_pool, num_buffers, buffers);
1253 vk_cleanup_ctx(struct vk_ctx *ctx)
1255 if (ctx->cmd_pool != VK_NULL_HANDLE) {
1256 vkResetCommandPool(ctx->dev, ctx->cmd_pool,
1257 VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT);
1258 vkDestroyCommandPool(ctx->dev, ctx->cmd_pool, 0);
1259 ctx->cmd_pool = VK_NULL_HANDLE;
1262 if (pipeline_cache != VK_NULL_HANDLE) {
1263 vkDestroyPipelineCache(ctx->dev, pipeline_cache, 0);
1264 pipeline_cache = VK_NULL_HANDLE;
1267 if (ctx->dev != VK_NULL_HANDLE) {
1268 vkDestroyDevice(ctx->dev, 0);
1269 ctx->dev = VK_NULL_HANDLE;
1272 if (ctx->inst != VK_NULL_HANDLE) {
1273 vkDestroyInstance(ctx->inst, 0);
1274 ctx->inst = VK_NULL_HANDLE;
1279 vk_create_image(struct vk_ctx *ctx,
1280 struct vk_att_props *props,
1281 struct vk_image_obj *img)
1283 VkImageCreateInfo img_info;
1285 memset(&img_info, 0, sizeof img_info);
1286 img_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
1287 img_info.pNext = 0; /* do something if external */
1288 img_info.imageType = get_image_type(props->h, props->depth);
1289 img_info.format = props->format;
1290 img_info.extent.width = props->w;
1291 img_info.extent.height = props->h;
1292 img_info.extent.depth = props->depth;
1293 img_info.mipLevels = props->num_levels ? props->num_levels : 1;
1294 img_info.arrayLayers = props->num_layers ?
1295 props->num_layers : VK_SAMPLE_COUNT_1_BIT;
1296 img_info.samples = get_num_samples(props->num_samples);
1297 img_info.tiling = props->tiling;
1298 img_info.usage = props->usage ?
1299 props->usage : VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
1300 img_info.initialLayout = props->in_layout;
1301 img_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
1303 if (vkCreateImage(ctx->dev, &img_info, 0, &img->img) != VK_SUCCESS)
1306 if(!alloc_image_memory(ctx, props->need_export, img))
1312 fprintf(stderr, "Failed to create external image.\n");
1313 vk_destroy_image(ctx, img);
1314 img->img = VK_NULL_HANDLE;
1315 img->mobj.mem = VK_NULL_HANDLE;
1320 vk_destroy_image(struct vk_ctx *ctx, struct vk_image_obj *img_obj)
1322 if (img_obj->img != VK_NULL_HANDLE) {
1323 vkDestroyImage(ctx->dev, img_obj->img, 0);
1324 img_obj->img = VK_NULL_HANDLE;
1327 if (img_obj->mobj.mem != VK_NULL_HANDLE) {
1328 vkFreeMemory(ctx->dev, img_obj->mobj.mem, 0);
1329 img_obj->mobj.mem = VK_NULL_HANDLE;
1334 vk_create_ext_image(struct vk_ctx *ctx,
1335 struct vk_att_props *props, struct vk_image_obj *img)
1337 VkExternalMemoryImageCreateInfo ext_img_info;
1338 VkImageCreateInfo img_info;
1340 memset(&ext_img_info, 0, sizeof ext_img_info);
1341 ext_img_info.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO;
1342 ext_img_info.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;
1344 memset(&img_info, 0, sizeof img_info);
1345 img_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
1346 img_info.pNext = &ext_img_info;
1347 img_info.imageType = get_image_type(props->h, props->depth);
1348 img_info.format = props->format;
1349 img_info.extent.width = props->w;
1350 img_info.extent.height = props->h;
1351 img_info.extent.depth = props->depth;
1352 img_info.mipLevels = props->num_levels ? props->num_levels : 1;
1353 img_info.arrayLayers = props->num_layers ? props->num_layers : VK_SAMPLE_COUNT_1_BIT;
1354 img_info.samples = get_num_samples(props->num_samples);
1355 img_info.tiling = props->tiling;
1356 img_info.usage = props->usage;
1357 img_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
1358 img_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
1359 /* issue 17 of EXT_external_objects
1360 * Required in OpenGL implementations that support
1361 * ARB_texture_view, OES_texture_view, EXT_texture_view,
1362 * or OpenGL 4.3 and above.
1364 img_info.flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
1366 if (vkCreateImage(ctx->dev, &img_info, 0, &img->img) != VK_SUCCESS)
1369 if(!alloc_image_memory(ctx, true, img))
1375 fprintf(stderr, "Failed to create external image.\n");
1376 vk_destroy_image(ctx, img);
1377 img->img = VK_NULL_HANDLE;
1378 img->mobj.mem = VK_NULL_HANDLE;
1383 vk_fill_image_props(struct vk_ctx *ctx,
1387 uint32_t num_samples,
1388 uint32_t num_levels,
1389 uint32_t num_layers,
1391 VkImageTiling tiling,
1392 VkImageLayout in_layout,
1393 VkImageLayout end_layout,
1397 struct vk_att_props *props)
1403 props->num_samples = num_samples;
1404 props->num_levels = num_levels;
1405 props->num_layers = num_layers;
1407 props->format = format;
1408 props->tiling = tiling;
1410 props->in_layout = in_layout;
1411 props->end_layout = end_layout;
1413 props->is_swapchain = is_swapchain;
1414 props->is_depth = is_depth;
1415 props->need_export = need_export;
1417 if (!are_props_supported(ctx, props))
1424 vk_create_renderer(struct vk_ctx *ctx,
1426 unsigned int vs_size,
1428 unsigned int fs_size,
1430 uint32_t num_samples,
1432 bool enable_stencil,
1434 struct vk_attachment *color_att,
1435 struct vk_attachment *depth_att,
1436 struct vk_vertex_info *vert_info,
1437 struct vk_renderer *renderer)
1439 memset(&renderer->vertex_info, 0, sizeof renderer->vertex_info);
1441 renderer->vertex_info = *vert_info;
1443 /* create image views for each attachment */
1444 if (!create_attachment_views(ctx, num_color_att, color_att, depth_att))
1447 renderer->renderpass = create_renderpass(ctx,
1452 if (renderer->renderpass == VK_NULL_HANDLE)
1455 create_framebuffer(ctx,
1457 num_color_att, color_att,
1458 depth_att, renderer);
1459 if (renderer->fb == VK_NULL_HANDLE)
1462 renderer->vs = create_shader_module(ctx, vs_src, vs_size);
1463 if (renderer->vs == VK_NULL_HANDLE)
1466 renderer->fs = create_shader_module(ctx, fs_src, fs_size);
1467 if (renderer->fs == VK_NULL_HANDLE)
1470 /* FIXME this is only for graphics atm */
1471 if(!create_graphics_pipeline(ctx, w, h,
1475 enable_stencil, renderer))
1478 if (renderer->pipeline == VK_NULL_HANDLE)
1484 fprintf(stderr, "Failed to create renderer.\n");
1485 vk_destroy_renderer(ctx, renderer);
1490 vk_destroy_renderer(struct vk_ctx *ctx,
1491 struct vk_renderer *renderer)
1493 if (renderer->renderpass != VK_NULL_HANDLE) {
1494 vkDestroyRenderPass(ctx->dev, renderer->renderpass, 0);
1495 renderer->renderpass = VK_NULL_HANDLE;
1498 if (renderer->vs != VK_NULL_HANDLE) {
1499 vkDestroyShaderModule(ctx->dev, renderer->vs, 0);
1500 renderer->vs = VK_NULL_HANDLE;
1503 if (renderer->fs != VK_NULL_HANDLE) {
1504 vkDestroyShaderModule(ctx->dev, renderer->fs, 0);
1505 renderer->fs = VK_NULL_HANDLE;
1508 if (renderer->fb != VK_NULL_HANDLE) {
1509 vkDestroyFramebuffer(ctx->dev, renderer->fb, 0);
1510 renderer->fb = VK_NULL_HANDLE;
1513 if (renderer->pipeline != VK_NULL_HANDLE) {
1514 vkDestroyPipeline(ctx->dev, renderer->pipeline, 0);
1515 renderer->pipeline = VK_NULL_HANDLE;
1518 if (renderer->pipeline_layout != VK_NULL_HANDLE) {
1519 vkDestroyPipelineLayout(ctx->dev, renderer->pipeline_layout, 0);
1520 renderer->pipeline_layout = VK_NULL_HANDLE;
1525 vk_create_ext_buffer(struct vk_ctx *ctx,
1527 VkBufferUsageFlagBits usage,
1530 VkExternalMemoryBufferCreateInfo ext_bo_info;
1532 memset(&ext_bo_info, 0, sizeof ext_bo_info);
1533 ext_bo_info.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO;
1534 ext_bo_info.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;
1536 if (!vk_create_buffer(ctx, true, sz, usage, &ext_bo_info, bo)) {
1537 fprintf(stderr, "Failed to allocate external buffer.\n");
1545 vk_create_buffer(struct vk_ctx *ctx,
1548 VkBufferUsageFlagBits usage,
1552 VkBufferCreateInfo buf_info;
1553 VkMemoryRequirements mem_reqs;
1555 bo->mobj.mem = VK_NULL_HANDLE;
1556 bo->buf = VK_NULL_HANDLE;
1558 /* VkBufferCreateInfo */
1559 memset(&buf_info, 0, sizeof buf_info);
1560 buf_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
1562 buf_info.usage = usage;
1563 buf_info.pNext = pnext;
1564 buf_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
1566 if (vkCreateBuffer(ctx->dev, &buf_info, 0, &bo->buf) != VK_SUCCESS)
1569 /* allocate buffer */
1570 vkGetBufferMemoryRequirements(ctx->dev, bo->buf, &mem_reqs);
1571 /* VK_MEMORY_PROPERTY_HOST_COHERENT_BIT bit specifies that the
1572 * host cache management commands vkFlushMappedMemoryRanges and
1573 * vkInvalidateMappedMemoryRanges are not needed to flush host
1574 * writes to the device or make device writes visible to the
1575 * host, respectively. */
1576 bo->mobj.mem = alloc_memory(ctx, is_external, &mem_reqs, VK_NULL_HANDLE,
1578 VK_MEMORY_PROPERTY_HOST_COHERENT_BIT |
1579 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
1581 if (bo->mobj.mem == VK_NULL_HANDLE)
1584 bo->mobj.mem_sz = sz;
1586 if (vkBindBufferMemory(ctx->dev, bo->buf, bo->mobj.mem, 0) != VK_SUCCESS) {
1587 fprintf(stderr, "Failed to bind buffer memory.\n");
1594 fprintf(stderr, "Failed to allocate buffer.\n");
1595 vk_destroy_buffer(ctx, bo);
1600 vk_update_buffer_data(struct vk_ctx *ctx,
1607 if (vkMapMemory(ctx->dev, bo->mobj.mem, 0, data_sz, 0, &map) != VK_SUCCESS) {
1608 fprintf(stderr, "Failed to map buffer memory.\n");
1612 memcpy(map, data, data_sz);
1614 vkUnmapMemory(ctx->dev, bo->mobj.mem);
1618 fprintf(stderr, "Failed to update buffer data. Destroying the buffer.\n");
1619 vk_destroy_buffer(ctx, bo);
1625 vk_destroy_buffer(struct vk_ctx *ctx,
1628 if (bo->buf != VK_NULL_HANDLE)
1629 vkDestroyBuffer(ctx->dev, bo->buf, 0);
1631 if (bo->mobj.mem != VK_NULL_HANDLE)
1632 vkFreeMemory(ctx->dev, bo->mobj.mem, 0);
1634 bo->mobj.mem_sz = 0;
1635 bo->buf = VK_NULL_HANDLE;
1636 bo->mobj.mem = VK_NULL_HANDLE;
1640 vk_create_fence(struct vk_ctx *ctx,
1643 VkFenceCreateInfo finfo;
1645 memset(&finfo, 0, sizeof finfo);
1646 finfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
1647 finfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
1649 if (vkCreateFence(ctx->dev, &finfo, 0, fence) != VK_SUCCESS) {
1650 fprintf(stderr, "Failed to create fence.\n");
1659 vk_create_cmd_buffer(struct vk_ctx *ctx)
1661 VkCommandBuffer cmd_buf;
1662 VkCommandBufferAllocateInfo alloc_info;
1664 memset(&alloc_info, 0, sizeof alloc_info);
1665 alloc_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
1666 alloc_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
1667 alloc_info.commandBufferCount = 1;
1668 alloc_info.commandPool = ctx->cmd_pool;
1670 if (vkAllocateCommandBuffers(ctx->dev, &alloc_info, &cmd_buf) != VK_SUCCESS)
1677 vk_record_cmd_buffer(struct vk_ctx *ctx,
1678 VkCommandBuffer cmd_buf,
1679 struct vk_renderer *renderer,
1681 uint32_t vk_fb_color_count,
1684 struct vk_attachment *atts,
1688 VkCommandBufferBeginInfo cmd_begin_info;
1689 VkRenderPassBeginInfo rp_begin_info;
1691 VkClearValue *clear_values; int i;
1692 VkDeviceSize offsets[] = {0};
1694 struct vk_dims img_size;
1695 bool create_cmd_buf = false;
1697 assert(vk_fb_color_count == 4);
1699 /* if cmd_buf is null create it */
1701 if ((cmd_buf = vk_create_cmd_buffer(ctx)) ==
1703 fprintf(stderr, "Failed to create command buffer.\n");
1706 create_cmd_buf = true;
1709 /* VkCommandBufferBeginInfo */
1710 memset(&cmd_begin_info, 0, sizeof cmd_begin_info);
1711 cmd_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
1712 cmd_begin_info.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT;
1714 /* VkRect2D render area */
1715 memset(&rp_area, 0, sizeof rp_area);
1716 rp_area.extent.width = (uint32_t)w;
1717 rp_area.extent.height = (uint32_t)h;
1718 rp_area.offset.x = x;
1719 rp_area.offset.y = y;
1722 clear_values = malloc(num_atts * sizeof clear_values[0]);
1723 memset(clear_values, 0, num_atts * sizeof clear_values[0]);
1725 for (i = 0; i < num_atts - 1; i++) {
1726 clear_values[i].color.float32[0] = vk_fb_color[0];
1727 clear_values[i].color.float32[1] = vk_fb_color[1];
1728 clear_values[i].color.float32[2] = vk_fb_color[2];
1729 clear_values[i].color.float32[3] = vk_fb_color[3];
1731 clear_values[num_atts - 1].depthStencil.depth = 1.0f;
1732 clear_values[num_atts - 1].depthStencil.stencil = 0;
1734 /* VkRenderPassBeginInfo */
1735 memset(&rp_begin_info, 0, sizeof rp_begin_info);
1736 rp_begin_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
1737 rp_begin_info.renderPass = renderer->renderpass;
1738 rp_begin_info.framebuffer = renderer->fb;
1739 rp_begin_info.renderArea = rp_area;
1740 rp_begin_info.clearValueCount = num_atts;
1741 rp_begin_info.pClearValues = clear_values;
1743 vkBeginCommandBuffer(cmd_buf, &cmd_begin_info);
1744 vkCmdBeginRenderPass(cmd_buf, &rp_begin_info, VK_SUBPASS_CONTENTS_INLINE);
1749 viewport.height = h;
1751 scissor.offset.x = x;
1752 scissor.offset.y = y;
1753 scissor.extent.width = w;
1754 scissor.extent.height = h;
1756 vkCmdSetViewport(cmd_buf, 0, 1, &viewport);
1757 vkCmdSetScissor(cmd_buf, 0, 1, &scissor);
1759 img_size.w = (float)w;
1760 img_size.h = (float)h;
1761 vkCmdPushConstants(cmd_buf,
1762 renderer->pipeline_layout,
1763 VK_SHADER_STAGE_FRAGMENT_BIT,
1764 0, sizeof (struct vk_dims),
1768 vkCmdBindVertexBuffers(cmd_buf, 0, 1, &vbo->buf, offsets);
1771 vkCmdBindPipeline(cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS, renderer->pipeline);
1773 num_vertices = vbo ? renderer->vertex_info.num_verts : 4;
1774 vkCmdDraw(cmd_buf, num_vertices, 1, 0, 0);
1775 vkCmdEndRenderPass(cmd_buf);
1780 VkImageMemoryBarrier *barriers =
1781 calloc(num_atts, sizeof(VkImageMemoryBarrier));
1782 VkImageMemoryBarrier *barrier = barriers;
1783 for (uint32_t n = 0; n < num_atts; n++, barrier++) {
1784 struct vk_attachment *att = &atts[n];
1785 VkImageAspectFlagBits depth_stencil_flags =
1786 get_aspect_from_depth_format(att->props.format);
1787 bool is_depth = (depth_stencil_flags != 0);
1789 /* Insert barrier to mark ownership transfer. */
1790 barrier->sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
1791 barrier->oldLayout = is_depth ?
1792 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL :
1793 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
1794 barrier->newLayout = VK_IMAGE_LAYOUT_GENERAL;
1795 barrier->srcAccessMask = get_access_mask(barrier->oldLayout);
1796 barrier->dstAccessMask = get_access_mask(barrier->newLayout);
1797 barrier->srcQueueFamilyIndex = ctx->qfam_idx;
1798 barrier->dstQueueFamilyIndex = VK_QUEUE_FAMILY_EXTERNAL;
1799 barrier->image = att->obj.img;
1800 barrier->subresourceRange.aspectMask = is_depth ?
1801 depth_stencil_flags :
1802 VK_IMAGE_ASPECT_COLOR_BIT;
1803 barrier->subresourceRange.baseMipLevel = 0;
1804 barrier->subresourceRange.levelCount = 1;
1805 barrier->subresourceRange.baseArrayLayer = 0;
1806 barrier->subresourceRange.layerCount = 1;
1809 vkCmdPipelineBarrier(cmd_buf,
1810 VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
1811 VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
1815 num_atts, barriers);
1820 vkEndCommandBuffer(cmd_buf);
1821 if (create_cmd_buf) {
1822 vk_destroy_cmd_buffers(ctx, 1, &cmd_buf);
1828 vk_draw(struct vk_ctx *ctx,
1829 struct vk_semaphores *semaphores,
1830 uint32_t num_buffers,
1831 VkCommandBuffer *cmd_buf)
1833 VkSubmitInfo submit_info;
1834 VkPipelineStageFlagBits stage_flags;
1836 stage_flags = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT;
1839 memset(&submit_info, 0, sizeof submit_info);
1840 submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
1841 submit_info.commandBufferCount = num_buffers;
1842 submit_info.pCommandBuffers = cmd_buf;
1846 assert(semaphores->frame_ready);
1847 assert(semaphores->frame_done);
1849 submit_info.pWaitDstStageMask = &stage_flags;
1850 submit_info.waitSemaphoreCount = 1;
1851 submit_info.pWaitSemaphores = &semaphores->frame_done;
1853 submit_info.signalSemaphoreCount = 1;
1854 submit_info.pSignalSemaphores = &semaphores->frame_ready;
1858 if (vkQueueSubmit(ctx->queue, 1, &submit_info, VK_NULL_HANDLE) != VK_SUCCESS) {
1859 fprintf(stderr, "Failed to submit queue.\n");
1863 if (vkQueueWaitIdle(ctx->queue) != VK_SUCCESS) {
1864 fprintf(stderr, "Failed to wait idle.\n");
1870 vk_clear_color(struct vk_ctx *ctx,
1871 VkCommandBuffer cmd_buf,
1873 struct vk_renderer *renderer,
1875 uint32_t vk_fb_color_count,
1876 struct vk_semaphores *semaphores,
1877 bool has_wait, bool has_signal,
1878 struct vk_attachment *attachments,
1879 uint32_t n_attachments,
1883 VkCommandBufferBeginInfo cmd_begin_info;
1884 VkRenderPassBeginInfo rp_begin_info;
1886 VkClearValue clear_values[2];
1887 VkSubmitInfo submit_info;
1888 VkPipelineStageFlagBits stage_flags;
1889 VkImageSubresourceRange img_range;
1891 assert(vk_fb_color_count == 4);
1893 /* VkCommandBufferBeginInfo */
1894 memset(&cmd_begin_info, 0, sizeof cmd_begin_info);
1895 cmd_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
1896 cmd_begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
1898 /* VkRect2D render area */
1899 memset(&rp_area, 0, sizeof rp_area);
1900 rp_area.extent.width = (uint32_t)w;
1901 rp_area.extent.height = (uint32_t)h;
1902 rp_area.offset.x = x;
1903 rp_area.offset.y = y;
1906 memset(&clear_values[0], 0, sizeof clear_values[0]);
1907 clear_values[0].color.float32[0] = vk_fb_color[0]; /* red */
1908 clear_values[0].color.float32[1] = vk_fb_color[1]; /* green */
1909 clear_values[0].color.float32[2] = vk_fb_color[2]; /* blue */
1910 clear_values[0].color.float32[3] = vk_fb_color[3]; /* alpha */
1912 memset(&clear_values[1], 0, sizeof clear_values[1]);
1913 clear_values[1].depthStencil.depth = 1.0;
1914 clear_values[1].depthStencil.stencil = 0;
1916 /* VkRenderPassBeginInfo */
1917 memset(&rp_begin_info, 0, sizeof rp_begin_info);
1918 rp_begin_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
1919 rp_begin_info.renderPass = renderer->renderpass;
1920 rp_begin_info.framebuffer = renderer->fb;
1921 rp_begin_info.renderArea = rp_area;
1922 rp_begin_info.clearValueCount = 2;
1923 rp_begin_info.pClearValues = clear_values;
1926 stage_flags = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT;
1928 memset(&submit_info, 0, sizeof submit_info);
1929 submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
1930 submit_info.commandBufferCount = 1;
1931 submit_info.pCommandBuffers = &cmd_buf;
1935 submit_info.pWaitDstStageMask = &stage_flags;
1936 submit_info.waitSemaphoreCount = 1;
1937 submit_info.pWaitSemaphores = &semaphores->frame_done;
1941 submit_info.signalSemaphoreCount = 1;
1942 submit_info.pSignalSemaphores = &semaphores->frame_ready;
1945 img_range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
1946 img_range.baseMipLevel = 0;
1947 img_range.levelCount = 1;
1948 img_range.baseArrayLayer = 0;
1949 img_range.layerCount = 1;
1951 vkBeginCommandBuffer(cmd_buf, &cmd_begin_info);
1952 vk_transition_image_layout(&attachments[0],
1954 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
1955 VK_IMAGE_LAYOUT_GENERAL,
1956 VK_QUEUE_FAMILY_EXTERNAL,
1958 vkCmdClearColorImage(cmd_buf,
1959 attachments[0].obj.img,
1960 VK_IMAGE_LAYOUT_GENERAL,
1961 &clear_values[0].color,
1965 vkCmdBeginRenderPass(cmd_buf, &rp_begin_info, VK_SUBPASS_CONTENTS_INLINE);
1970 viewport.height = h;
1972 scissor.offset.x = x;
1973 scissor.offset.y = y;
1974 scissor.extent.width = w;
1975 scissor.extent.height = h;
1977 vkCmdSetViewport(cmd_buf, 0, 1, &viewport);
1978 vkCmdSetScissor(cmd_buf, 0, 1, &scissor);
1980 vkCmdBindPipeline(cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS, renderer->pipeline);
1982 vkCmdEndRenderPass(cmd_buf);
1985 VkImageMemoryBarrier *barriers =
1986 calloc(n_attachments, sizeof(VkImageMemoryBarrier));
1987 VkImageMemoryBarrier *barrier = barriers;
1989 for (uint32_t n = 0; n < n_attachments; n++, barrier++) {
1990 struct vk_attachment *att = &attachments[n];
1992 /* Insert barrier to mark ownership transfer. */
1993 barrier->sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
1996 get_aspect_from_depth_format(att->props.format) != VK_NULL_HANDLE;
1998 barrier->oldLayout = is_depth ?
1999 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL :
2000 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
2001 barrier->newLayout = VK_IMAGE_LAYOUT_GENERAL;
2002 barrier->srcAccessMask = get_access_mask(barrier->oldLayout);
2003 barrier->dstAccessMask = get_access_mask(barrier->newLayout);
2004 barrier->srcQueueFamilyIndex = ctx->qfam_idx;
2005 barrier->dstQueueFamilyIndex = VK_QUEUE_FAMILY_EXTERNAL;
2006 barrier->image = att->obj.img;
2007 barrier->subresourceRange.aspectMask = is_depth ?
2008 VK_IMAGE_ASPECT_DEPTH_BIT :
2009 VK_IMAGE_ASPECT_COLOR_BIT;
2010 barrier->subresourceRange.baseMipLevel = 0;
2011 barrier->subresourceRange.levelCount = 1;
2012 barrier->subresourceRange.baseArrayLayer = 0;
2013 barrier->subresourceRange.layerCount = 1;
2016 vkCmdPipelineBarrier(cmd_buf,
2017 VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
2018 VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
2022 n_attachments, barriers);
2026 vkEndCommandBuffer(cmd_buf);
2028 if (vkQueueSubmit(ctx->queue, 1, &submit_info, VK_NULL_HANDLE) != VK_SUCCESS) {
2029 fprintf(stderr, "Failed to submit queue.\n");
2032 if (!semaphores && !has_wait && !has_signal)
2033 vkQueueWaitIdle(ctx->queue);
2037 vk_set_viewport(struct vk_ctx *ctx,
2038 VkCommandBuffer cmd_buf,
2041 float near, float far)
2043 VkCommandBufferBeginInfo binfo;
2044 VkViewport viewport;
2046 memset(&viewport, 0, sizeof viewport);
2050 viewport.height = h;
2051 viewport.minDepth = near;
2052 viewport.maxDepth = far;
2054 memset(&binfo, 0, sizeof binfo);
2055 binfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
2056 binfo.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT;
2058 vkBeginCommandBuffer(cmd_buf, &binfo);
2059 vkCmdSetViewport(cmd_buf, 0, 1, &viewport);
2060 vkEndCommandBuffer(cmd_buf);
2064 vk_create_swapchain(struct vk_ctx *ctx,
2065 int width, int height,
2068 struct vk_swapchain *old_swapchain,
2069 struct vk_swapchain *swapchain)
2071 VkSurfaceCapabilitiesKHR surf_cap;
2072 VkSwapchainCreateInfoKHR s_info;
2074 VkImageSubresourceRange sr;
2078 if (!sc_validate_surface(ctx, surf)) {
2079 fprintf(stderr, "Failed to validate surface!\n");
2083 /* get pdevice capabilities
2084 * will need that to determine the swapchain number of images
2086 if (vkGetPhysicalDeviceSurfaceCapabilitiesKHR(ctx->pdev, surf, &surf_cap) != VK_SUCCESS) {
2087 fprintf(stderr, "Failed to query surface capabilities.\n");
2091 memset(swapchain, 0, sizeof *swapchain);
2093 memset(&s_info, 0, sizeof s_info);
2094 s_info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
2096 if (!sc_select_format(ctx, surf, &s_info)) {
2097 fprintf(stderr, "Failed to determine the surface format.\n");
2100 s_info.surface = surf;
2101 s_info.minImageCount = surf_cap.minImageCount;
2103 extent.width = width;
2104 extent.height = height;
2106 if (!sc_select_supported_present_modes(ctx, surf, has_vsync, &s_info)) {
2107 s_info.presentMode = VK_PRESENT_MODE_FIFO_KHR;
2109 s_info.imageExtent = extent;
2110 s_info.imageArrayLayers = 1;
2112 s_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
2113 if (surf_cap.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_SRC_BIT)
2114 s_info.imageUsage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
2115 if (surf_cap.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_DST_BIT)
2116 s_info.imageUsage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
2118 s_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
2119 s_info.queueFamilyIndexCount = ctx->qfam_idx;
2121 /* we might want to use this function when we recreate the swapchain too */
2122 s_info.preTransform = surf_cap.supportedTransforms &
2123 VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR ?
2124 VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR :
2125 surf_cap.currentTransform;
2127 /* we could also write a sc_select_supported_composite_alpha
2128 * later but VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR is universally
2130 s_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
2131 s_info.clipped = VK_TRUE;
2133 if (vkCreateSwapchainKHR(ctx->dev, &s_info, 0,
2134 &swapchain->swapchain) != VK_SUCCESS) {
2135 fprintf(stderr, "Failed to create a swapchain.\n");
2139 if (!swapchain->swapchain) {
2140 fprintf(stderr, "The swapchain seems null\n");
2144 /* get the number of swapchain images and the swapchain images
2145 * and store the new swapchain images
2147 vkGetSwapchainImagesKHR(ctx->dev, swapchain->swapchain, &swapchain->num_atts, 0);
2148 printf("number of swapchain images: %d\n", swapchain->num_atts);
2151 s_images = malloc(swapchain->num_atts * sizeof(VkImage));
2153 fprintf(stderr, "Failed to allocate swapchain images.\n");
2157 vkGetSwapchainImagesKHR(ctx->dev, swapchain->swapchain, &swapchain->num_atts, s_images);
2159 swapchain->image_fmt = s_info.imageFormat;
2160 swapchain->atts = malloc(swapchain->num_atts * sizeof swapchain->atts[0]);
2161 if (!swapchain->atts) {
2162 fprintf(stderr, "Failed to allocate swapchain images.\n");
2165 memset(swapchain->atts, 0, sizeof swapchain->atts[0]);
2167 memset(&sr, 0, sizeof sr);
2168 sr.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
2172 for (i = 0; i < swapchain->num_atts; i++) {
2173 /* we store the image */
2174 swapchain->atts[i].obj.img = s_images[i];
2176 /* filling attachment properties here where that info
2179 vk_fill_image_props(ctx, width, height, 1,
2183 VK_IMAGE_LAYOUT_UNDEFINED,
2184 VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
2186 &swapchain->atts[i].props);
2187 swapchain->atts[i].props.usage = s_info.imageUsage;
2189 if (!create_image_view(ctx, s_images[i],
2190 VK_IMAGE_VIEW_TYPE_2D,
2191 s_info.imageFormat, sr, true,
2192 &swapchain->atts[i].obj.img_view)) {
2193 fprintf(stderr, "Failed to create image view for image: %d\n", i);
2207 vk_destroy_swapchain(struct vk_ctx *ctx,
2208 struct vk_swapchain *swapchain)
2210 vkDestroySwapchainKHR(ctx->dev, swapchain->swapchain, 0);
2214 vk_queue_present(struct vk_swapchain *swapchain,
2217 VkSemaphore wait_sema)
2219 VkPresentInfoKHR pinfo;
2221 memset(&pinfo, 0, sizeof pinfo);
2222 pinfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
2223 pinfo.swapchainCount = 1;
2224 pinfo.pSwapchains = &swapchain->swapchain;
2225 pinfo.pImageIndices = &image_idx;
2227 pinfo.pWaitSemaphores = &wait_sema;
2228 pinfo.waitSemaphoreCount = 1;
2230 if (vkQueuePresentKHR(queue, &pinfo) != VK_SUCCESS) {
2231 fprintf(stderr, "Failed to present queue.\n");
2239 vk_copy_image_to_buffer(struct vk_ctx *ctx,
2240 VkCommandBuffer cmd_buf,
2241 struct vk_attachment *src_img,
2242 struct vk_buf *dst_bo,
2245 VkCommandBufferBeginInfo cmd_begin_info;
2246 VkSubmitInfo submit_info;
2247 VkImageAspectFlagBits aspect_mask = get_aspect_from_depth_format(src_img->props.format);
2249 /* VkCommandBufferBeginInfo */
2250 memset(&cmd_begin_info, 0, sizeof cmd_begin_info);
2251 cmd_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
2252 cmd_begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
2254 memset(&submit_info, 0, sizeof submit_info);
2255 submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
2256 submit_info.commandBufferCount = 1;
2257 submit_info.pCommandBuffers = &cmd_buf;
2259 vkBeginCommandBuffer(cmd_buf, &cmd_begin_info);
2260 if (src_img->props.end_layout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL && dst_bo) {
2261 vk_transition_image_layout(src_img,
2263 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
2264 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
2265 VK_QUEUE_FAMILY_EXTERNAL,
2268 /* copy image to buf */
2269 VkBufferImageCopy copy_region = {
2271 .bufferRowLength = w,
2272 .bufferImageHeight = h,
2273 .imageSubresource = {
2274 .aspectMask = aspect_mask ? aspect_mask
2275 : VK_IMAGE_ASPECT_COLOR_BIT,
2277 .baseArrayLayer = 0,
2280 .imageOffset = { 0, 0, 0 },
2281 .imageExtent = { w, h, 1 }
2284 vkCmdCopyImageToBuffer(cmd_buf,
2286 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
2287 dst_bo->buf, 1, ©_region);
2289 vk_transition_image_layout(src_img,
2291 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
2292 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
2293 VK_QUEUE_FAMILY_EXTERNAL,
2296 VkBufferMemoryBarrier write_finish_buffer_memory_barrier = {
2297 .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
2298 .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
2299 .dstAccessMask = VK_ACCESS_HOST_READ_BIT,
2300 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_EXTERNAL,
2301 .dstQueueFamilyIndex = ctx->qfam_idx,
2302 .buffer = dst_bo->buf,
2304 .size = VK_WHOLE_SIZE
2307 vkCmdPipelineBarrier(cmd_buf,
2308 VK_PIPELINE_STAGE_TRANSFER_BIT,
2309 VK_PIPELINE_STAGE_HOST_BIT,
2310 (VkDependencyFlags) 0, 0, NULL,
2311 1, &write_finish_buffer_memory_barrier,
2314 vkEndCommandBuffer(cmd_buf);
2316 if (vkQueueSubmit(ctx->queue, 1, &submit_info, VK_NULL_HANDLE) != VK_SUCCESS) {
2317 fprintf(stderr, "Failed to submit queue.\n");
2319 vkQueueWaitIdle(ctx->queue);
2323 vk_create_semaphores(struct vk_ctx *ctx,
2325 struct vk_semaphores *semaphores)
2327 VkSemaphoreCreateInfo sema_info;
2328 VkExportSemaphoreCreateInfo exp_sema_info;
2331 /* VkExportSemaphoreCreateInfo */
2332 memset(&exp_sema_info, 0, sizeof exp_sema_info);
2333 exp_sema_info.sType = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO;
2334 exp_sema_info.handleTypes = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT;
2337 /* VkSemaphoreCreateInfo */
2338 memset(&sema_info, 0, sizeof sema_info);
2339 sema_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
2340 sema_info.pNext = is_external ? &exp_sema_info : 0;
2342 if (vkCreateSemaphore(ctx->dev, &sema_info, 0, &semaphores->frame_ready) != VK_SUCCESS) {
2343 fprintf(stderr, "Failed to create semaphore frame_ready.\n");
2347 if (vkCreateSemaphore(ctx->dev, &sema_info, 0, &semaphores->frame_done) != VK_SUCCESS) {
2348 fprintf(stderr, "Failed to create semaphore frame_done.\n");
2356 vk_destroy_semaphores(struct vk_ctx *ctx,
2357 struct vk_semaphores *semaphores)
2359 if (semaphores->frame_ready)
2360 vkDestroySemaphore(ctx->dev, semaphores->frame_ready, 0);
2361 if (semaphores->frame_done)
2362 vkDestroySemaphore(ctx->dev, semaphores->frame_done, 0);
2366 vk_create_fences(struct vk_ctx *ctx,
2368 VkFenceCreateFlagBits flags,
2371 VkFenceCreateInfo f_info;
2374 memset(&f_info, 0, sizeof f_info);
2375 f_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
2376 f_info.flags = flags ? flags : VK_FENCE_CREATE_SIGNALED_BIT;
2379 fences = malloc(num_cmd_buf * sizeof(VkFence));
2380 for (i = 0; i < num_cmd_buf; i++) {
2381 if (vkCreateFence(ctx->dev, &f_info, 0, &fences[i]) != VK_SUCCESS) {
2382 fprintf(stderr, "Failed to create fence number: %d\n", (i + 1));
2389 for (i = 0; i < j; i++) {
2390 vkDestroyFence(ctx->dev, fences[i], 0);
2399 vk_destroy_fences(struct vk_ctx *ctx,
2404 for (i = 0; i < num_fences; i++) {
2405 vkDestroyFence(ctx->dev, fences[i], 0);
2410 vk_transition_image_layout(struct vk_attachment *img_att,
2411 VkCommandBuffer cmd_buf,
2412 VkImageLayout old_layout,
2413 VkImageLayout new_layout,
2414 uint32_t src_queue_fam_idx,
2415 uint32_t dst_queue_fam_idx)
2417 VkImageMemoryBarrier barrier;
2418 struct vk_att_props props = img_att->props;
2419 VkImageAspectFlagBits aspect_mask = get_aspect_from_depth_format(props.format);
2421 memset(&barrier, 0, sizeof barrier);
2422 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
2423 barrier.srcAccessMask = get_access_mask(old_layout);
2424 barrier.dstAccessMask = get_access_mask(new_layout);
2425 barrier.oldLayout = old_layout;
2426 barrier.newLayout = new_layout;
2427 barrier.srcQueueFamilyIndex = src_queue_fam_idx;
2428 barrier.dstQueueFamilyIndex = dst_queue_fam_idx;
2429 barrier.image = img_att->obj.img;
2430 barrier.subresourceRange.aspectMask = aspect_mask ? aspect_mask :
2431 VK_IMAGE_ASPECT_COLOR_BIT;
2432 barrier.subresourceRange.levelCount = 1;
2433 barrier.subresourceRange.layerCount = 1;
2435 vkCmdPipelineBarrier(cmd_buf,
2436 get_pipeline_stage_flags(old_layout),
2437 get_pipeline_stage_flags(new_layout),
2438 0, 0, VK_NULL_HANDLE, 0, VK_NULL_HANDLE, 1, &barrier);