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 = "hikikornd";
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 vk_create_renderpass(struct vk_ctx *ctx,
296 uint32_t num_color_atts,
297 struct vk_att_props *color_props,
298 struct vk_att_props *depth_props,
299 VkRenderPass *renderpass)
301 VkAttachmentDescription *att_dsc;
302 VkAttachmentReference *att_rfc;
304 /* one subpass for the moment: */
305 VkSubpassDescription subpass_dsc[1];
306 VkSubpassDependency subpass_dep;
308 VkRenderPassCreateInfo rpass_info;
311 uint32_t num_atts = num_color_atts + 1;
312 bool has_layout = depth_props->in_layout != VK_IMAGE_LAYOUT_UNDEFINED;
314 att_dsc = malloc(num_atts * sizeof att_dsc[0]);
315 att_rfc = malloc(num_atts * sizeof att_rfc[0]);
317 memset(att_dsc, 0, num_atts * sizeof att_dsc[0]);
318 memset(att_rfc, 0, num_atts * sizeof att_rfc[0]);
320 /* color attachments description (we can have many) */
321 for (i = 0; i < num_color_atts; i++) {
322 att_dsc[i].samples = get_num_samples(color_props[i].num_samples);
323 att_dsc[i].initialLayout = color_props[i].in_layout;
324 att_dsc[i].finalLayout = color_props[i].end_layout;
325 att_dsc[i].format = color_props[i].format;
327 att_dsc[i].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
328 att_dsc[i].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
329 att_dsc[i].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
330 att_dsc[i].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
332 att_rfc[i].attachment = i;
333 att_rfc[i].layout = color_props[i].tiling != VK_IMAGE_TILING_OPTIMAL ?
334 VK_IMAGE_LAYOUT_GENERAL :
335 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
339 /* depth attachment description (we can have only one) */
340 att_dsc[num_color_atts].samples = get_num_samples(depth_props->num_samples);
341 att_dsc[num_color_atts].initialLayout = depth_props->in_layout;
342 att_dsc[num_color_atts].finalLayout = depth_props->end_layout;
343 att_dsc[num_color_atts].format = depth_props->format;
344 /* we might want to reuse the depth buffer when it's filled */
345 att_dsc[num_color_atts].loadOp = has_layout ?
346 VK_ATTACHMENT_LOAD_OP_LOAD :
347 VK_ATTACHMENT_LOAD_OP_CLEAR;
348 att_dsc[num_color_atts].stencilLoadOp = has_layout ?
349 VK_ATTACHMENT_LOAD_OP_LOAD :
350 VK_ATTACHMENT_LOAD_OP_CLEAR;
351 att_dsc[num_color_atts].stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
352 att_rfc[num_color_atts].layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
353 att_rfc[num_color_atts].attachment = num_color_atts;
355 /* VkSubpassDescription */
356 memset(&subpass_dsc, 0, sizeof subpass_dsc);
357 subpass_dsc[0].pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
358 subpass_dsc[0].colorAttachmentCount = num_color_atts;
359 subpass_dsc[0].pColorAttachments = &att_rfc[0];
360 subpass_dsc[0].pDepthStencilAttachment = &att_rfc[num_color_atts];
362 /* The subpasses in a render pass automatically take care of
363 * image layout transitions. These transitions are controlled
364 * by subpass dependencies, which specify memory and execution
365 * dependencies between subpasses. We have only a single subpass
366 * right now, but the operations right before and right after
367 * this subpass also count as implicit "subpasses". There are two
368 * built-in dependencies that take care of the transition at the
369 * start of the render pass and at the end of the render pass,
370 * but the former does not occur at the right time. It assumes
371 * that the transition occurs at the start of the pipeline,
372 * but we haven't acquired the image yet at that point! There are
373 * two ways to deal with this problem.
375 * We could change the waitStages for the frame_ready semaphore
376 * to VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT to ensure that the render
377 * passes don't begin until the image is available, or we can make
378 * the render pass wait for the
379 * VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT stage.
382 /* VkSubpassDependency */
383 memset(&subpass_dep, 0, sizeof subpass_dep);
384 subpass_dep.srcSubpass = VK_SUBPASS_EXTERNAL;
385 subpass_dep.dstSubpass = 0;
386 subpass_dep.srcStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
387 subpass_dep.srcAccessMask = 0;
388 subpass_dep.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
389 subpass_dep.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
391 /* VkRenderPassCreateInfo */
392 memset(&rpass_info, 0, sizeof rpass_info);
393 rpass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
394 rpass_info.attachmentCount = num_atts;
395 rpass_info.pAttachments = att_dsc;
396 rpass_info.subpassCount = 1;
397 rpass_info.pSubpasses = subpass_dsc;
398 rpass_info.dependencyCount = 1;
399 rpass_info.pDependencies = &subpass_dep;
401 if (vkCreateRenderPass(ctx->dev, &rpass_info, 0, renderpass) != VK_SUCCESS) {
402 fprintf(stderr, "Failed to create renderpass.\n");
403 *renderpass = VK_NULL_HANDLE;
417 static inline VkImageType
418 get_image_type(uint32_t h, uint32_t d)
421 return VK_IMAGE_TYPE_1D;
424 return VK_IMAGE_TYPE_3D;
426 return VK_IMAGE_TYPE_2D;
430 static VkImageViewType
431 get_image_view_type(struct vk_att_props *props)
433 VkImageType type = get_image_type(props->h, props->depth);
435 case VK_IMAGE_TYPE_1D:
436 return props->num_layers > 1 ?
437 VK_IMAGE_VIEW_TYPE_1D_ARRAY :
438 VK_IMAGE_VIEW_TYPE_1D;
439 case VK_IMAGE_TYPE_2D:
440 if (props->num_layers == 1)
441 return VK_IMAGE_VIEW_TYPE_2D;
442 if (props->num_layers == 6)
443 return VK_IMAGE_VIEW_TYPE_CUBE;
444 if (props->num_layers % 6 == 0)
445 return VK_IMAGE_VIEW_TYPE_CUBE_ARRAY;
446 if (props->num_layers > 1)
447 return VK_IMAGE_VIEW_TYPE_2D_ARRAY;
448 case VK_IMAGE_TYPE_3D:
449 if (props->num_layers == 1)
450 return VK_IMAGE_VIEW_TYPE_3D;
451 if ((props->num_layers == 1) &&
452 (props->num_levels == 1))
453 return VK_IMAGE_VIEW_TYPE_2D;
454 if ((props->num_levels == 1) &&
455 (props->num_layers > 1))
456 return VK_IMAGE_VIEW_TYPE_2D_ARRAY;
458 return VK_IMAGE_VIEW_TYPE_2D;
463 static VkImageAspectFlagBits
464 get_aspect_from_depth_format(VkFormat depth_format)
466 switch (depth_format) {
467 case VK_FORMAT_D16_UNORM:
468 case VK_FORMAT_X8_D24_UNORM_PACK32:
469 case VK_FORMAT_D32_SFLOAT:
470 return VK_IMAGE_ASPECT_DEPTH_BIT;
471 case VK_FORMAT_S8_UINT:
472 return VK_IMAGE_ASPECT_STENCIL_BIT;
473 case VK_FORMAT_D16_UNORM_S8_UINT:
474 case VK_FORMAT_D24_UNORM_S8_UINT:
475 case VK_FORMAT_D32_SFLOAT_S8_UINT:
476 return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
483 static VkPipelineStageFlags
484 get_pipeline_stage_flags(const VkImageLayout layout)
487 case VK_IMAGE_LAYOUT_UNDEFINED:
488 return VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
489 case VK_IMAGE_LAYOUT_GENERAL:
490 return VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
491 case VK_IMAGE_LAYOUT_PREINITIALIZED:
492 return VK_PIPELINE_STAGE_HOST_BIT;
493 case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
494 case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
495 return VK_PIPELINE_STAGE_TRANSFER_BIT;
496 case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
497 return VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
498 case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
499 return VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
500 VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
501 case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR:
502 return VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
511 create_attachment_views(struct vk_ctx *ctx, int num_color_att,
512 struct vk_attachment *color_att,
513 struct vk_attachment *depth_att)
515 VkImageSubresourceRange sr;
518 vk_create_image_view(ctx, depth_att->obj.img, VK_IMAGE_VIEW_TYPE_2D,
519 depth_att->props.format, false,
520 &depth_att->obj.img_view);
522 memset(&sr, 0, sizeof sr);
523 sr.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
525 for (i = 0; i < num_color_att; i++) {
526 vk_create_image_view(ctx, color_att[i].obj.img, VK_IMAGE_VIEW_TYPE_2D,
527 color_att[i].props.format,
528 color_att[i].props.is_swapchain,
529 &color_att[i].obj.img_view);
536 create_framebuffer_from_attachments(struct vk_ctx *ctx,
537 int width, int height,
539 struct vk_attachment *color_att,
540 struct vk_attachment *depth_att,
541 struct vk_renderer *renderer)
543 VkFramebufferCreateInfo fb_info;
546 int num_atts = num_color_atts + 1;
548 atts = malloc(num_atts * sizeof atts[0]);
550 for (i = 0; i < num_color_atts; i++) {
551 atts[i] = color_att[i].obj.img_view;
553 atts[num_color_atts] = depth_att->obj.img_view;
555 memset(&fb_info, 0, sizeof fb_info);
556 fb_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
557 fb_info.renderPass = renderer->renderpass;
558 fb_info.width = width;
559 fb_info.height = height;
561 fb_info.attachmentCount = num_atts;
562 fb_info.pAttachments = atts;
564 if (vkCreateFramebuffer(ctx->dev, &fb_info, 0, &renderer->fb) != VK_SUCCESS) {
565 fprintf(stderr, "Failed to create framebuffer.\n");
567 renderer->fb = VK_NULL_HANDLE;
577 static VkShaderModule
578 create_shader_module(struct vk_ctx *ctx,
582 VkShaderModuleCreateInfo sm_info;
585 /* VkShaderModuleCreateInfo */
586 memset(&sm_info, 0, sizeof sm_info);
587 sm_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
588 sm_info.codeSize = size;
589 sm_info.pCode = (void*)src;
591 if (vkCreateShaderModule(ctx->dev, &sm_info, 0, &sm) != VK_SUCCESS) {
592 fprintf(stderr, "Failed to create shader module.\n");
600 create_vertex_descriptions(struct vk_ctx *ctx,
601 struct vk_geometry *geometry,
603 VkVertexInputBindingDescription *bind_dsc,
605 VkVertexInputAttributeDescription *att_dsc)
608 VkFormatProperties fmt_props;
611 assert(num_bind_dsc == num_att_dsc);
613 memset(bind_dsc, 0, num_bind_dsc * sizeof bind_dsc[0]);
614 memset(att_dsc, 0, num_att_dsc * sizeof att_dsc[0]);
616 /* FIXME!!! format and stride!!
617 * We have 3D Vectors so we need an RGB format:
618 * R for x, G for y, B for z
619 * If we need to set the w we need an RGBA format!
620 * the stride (distance between 2 consecutive elements
621 * must be 8 as we use 32bits floats and 32bits = 8bytes
623 format = VK_FORMAT_R32G32B32_SFLOAT;
624 vkGetPhysicalDeviceFormatProperties(ctx->pdev, format, &fmt_props);
625 assert(fmt_props.bufferFeatures & VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT);
635 if (geometry->vertices.num_vertices) {
636 att_dsc[0].location = VERTEX_LOC;
637 att_dsc[0].binding = VERTEX_BIND;
638 att_dsc[0].format = format;
639 att_dsc[0].offset = 0;
641 bind_dsc[0].binding = VERTEX_BIND;
642 bind_dsc[0].stride = stride;
643 bind_dsc[0].inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
646 if (geometry->indices.num_vertices) {
649 if (geometry->normals.num_vertices) {
652 if (geometry->tangents.num_vertices) {
657 create_graphics_pipeline(struct vk_ctx *ctx,
660 uint32_t num_samples,
661 uint32_t num_color_atts,
664 struct vk_renderer *renderer)
666 VkVertexInputBindingDescription vert_bind_dsc[4];
667 VkVertexInputAttributeDescription vert_att_dsc[4];
669 VkPipelineColorBlendAttachmentState *cb_att_state;
670 VkPipelineVertexInputStateCreateInfo vert_input_info;
671 VkPipelineInputAssemblyStateCreateInfo asm_info;
672 VkPipelineViewportStateCreateInfo viewport_info;
673 VkPipelineRasterizationStateCreateInfo rs_info;
674 VkPipelineMultisampleStateCreateInfo ms_info;
675 VkPipelineDepthStencilStateCreateInfo ds_info;
676 VkPipelineColorBlendStateCreateInfo cb_info;
677 VkPipelineShaderStageCreateInfo sdr_stages[2];
678 VkPipelineLayoutCreateInfo layout_info;
679 VkGraphicsPipelineCreateInfo pipeline_info;
681 VkFormatProperties fmt_props;
682 VkPushConstantRange pc_range[1];
684 VkStencilOpState front;
685 VkStencilOpState back;
687 VkPipelineLayout pipeline_layout;
691 /* format of vertex attributes:
692 * we have 2D vectors so we need a RG format:
694 * the stride (distance between 2 consecutive elements)
695 * must be 8 because we use 32 bit floats and
697 format = VK_FORMAT_R32G32_SFLOAT;
698 vkGetPhysicalDeviceFormatProperties(ctx->pdev, format, &fmt_props);
699 assert(fmt_props.bufferFeatures & VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT);
702 // create_vertex_descriptions(ctx, renderer->geometry, 1, vert_bind_dsc, 1, vert_att_dsc);
703 memset(vert_att_dsc, 0, 4 * sizeof vert_att_dsc[0]);
704 memset(vert_bind_dsc, 0, 4 * sizeof vert_bind_dsc[0]);
706 /* VkVertexInputAttributeDescription */
707 vert_att_dsc[0].location = 0;
708 vert_att_dsc[0].binding = 0;
709 vert_att_dsc[0].format = format; /* see comment */
710 vert_att_dsc[0].offset = 0;
712 /* VkVertexInputBindingDescription */
713 vert_bind_dsc[0].binding = 0;
714 vert_bind_dsc[0].stride = stride;
715 vert_bind_dsc[0].inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
717 /* If using vbo, we have setup vertex_info in the renderer. */
718 bool has_geometry = renderer->geometry;
720 /* VkPipelineVertexInputStateCreateInfo */
721 memset(&vert_input_info, 0, sizeof vert_input_info);
722 vert_input_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
723 vert_input_info.vertexBindingDescriptionCount = renderer->geometry ? 1 : 0;
724 vert_input_info.pVertexBindingDescriptions = vert_bind_dsc;
725 vert_input_info.vertexAttributeDescriptionCount = renderer->geometry ? 1 : 0;
726 vert_input_info.pVertexAttributeDescriptions = vert_att_dsc;
728 /* VkPipelineInputAssemblyStateCreateInfo */
729 memset(&asm_info, 0, sizeof asm_info);
730 asm_info.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
731 asm_info.topology = has_geometry ?
732 renderer->geometry->topo
733 : VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
734 asm_info.primitiveRestartEnable = false;
737 viewport.x = viewport.y = 0;
738 viewport.width = width;
739 viewport.height = height;
740 viewport.minDepth = 0;
741 viewport.maxDepth = 1;
743 /* VkRect2D scissor */
744 scissor.offset.x = scissor.offset.y = 0;
745 scissor.extent.width = width;
746 scissor.extent.height = height;
748 /* VkPipelineViewportStateCreateInfo */
749 memset(&viewport_info, 0, sizeof viewport_info);
750 viewport_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
751 viewport_info.viewportCount = 1;
752 viewport_info.pViewports = &viewport;
753 viewport_info.scissorCount = 1;
754 viewport_info.pScissors = &scissor;
756 /* VkPipelineRasterizationStateCreateInfo */
757 memset(&rs_info, 0, sizeof rs_info);
758 rs_info.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
759 rs_info.polygonMode = VK_POLYGON_MODE_FILL;
760 rs_info.cullMode = VK_CULL_MODE_NONE;
761 rs_info.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
762 rs_info.lineWidth = 1.0;
764 /* VkPipelineMultisampleStateCreateInfo */
765 memset(&ms_info, 0, sizeof ms_info);
766 ms_info.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
767 ms_info.rasterizationSamples = get_num_samples(num_samples);
769 /* VkStencilOpState */
770 /* The default values for ES are taken by Topi Pohjolainen's code */
771 /* defaults in OpenGL ES 3.1 */
772 memset(&front, 0, sizeof front);
773 front.compareMask = ~0;
774 front.writeMask = ~0;
777 memset(&back, 0, sizeof back);
778 back.compareMask = ~0;
782 /* VkPipelineDepthStencilStateCreateInfo */
783 memset(&ds_info, 0, sizeof ds_info);
784 ds_info.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
785 ds_info.front = front;
787 /* defaults in OpenGL ES 3.1 */
788 ds_info.minDepthBounds = 0;
789 ds_info.maxDepthBounds = 1;
790 /* z buffer, stencil buffer */
792 ds_info.depthTestEnable = VK_TRUE;
793 ds_info.depthWriteEnable = VK_TRUE;
794 ds_info.depthCompareOp = VK_COMPARE_OP_LESS;
796 if (enable_stencil) {
797 ds_info.stencilTestEnable = VK_TRUE;
798 ds_info.depthTestEnable = VK_FALSE;
799 ds_info.depthWriteEnable = VK_TRUE;
802 /* we only care about the passOp here */
803 ds_info.back.compareOp = VK_COMPARE_OP_ALWAYS;
804 ds_info.back.failOp = VK_STENCIL_OP_REPLACE;
805 ds_info.back.depthFailOp = VK_STENCIL_OP_REPLACE;
806 ds_info.back.passOp = VK_STENCIL_OP_REPLACE;
807 ds_info.back.compareMask = 0xffffffff;
808 ds_info.back.writeMask = 0xffffffff;
809 ds_info.back.reference = 1;
810 ds_info.front = ds_info.back;
812 /* VkPipelineColorBlendAttachmentState */
813 cb_att_state = malloc(num_color_atts * sizeof cb_att_state[0]);
815 fprintf(stderr, "Failed to allocate color blend attachment state for each attachment.\n");
818 memset(cb_att_state, 0, num_color_atts * sizeof cb_att_state[0]);
819 for (i = 0; i < num_color_atts; i++) {
820 cb_att_state[i].colorWriteMask = (VK_COLOR_COMPONENT_R_BIT |
821 VK_COLOR_COMPONENT_G_BIT |
822 VK_COLOR_COMPONENT_B_BIT |
823 VK_COLOR_COMPONENT_A_BIT);
826 /* VkPipelineColorBlendStateCreateInfo */
827 memset(&cb_info, 0, sizeof cb_info);
828 cb_info.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
829 cb_info.attachmentCount = num_color_atts;
830 cb_info.pAttachments = cb_att_state;
831 /* default in ES 3.1 */
832 for (i = 0; i < 4; i++) {
833 cb_info.blendConstants[i] = 0.0f;
836 /* VkPipelineShaderStageCreateInfo */
837 memset(sdr_stages, 0, 2 * sizeof sdr_stages[0]);
839 sdr_stages[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
840 sdr_stages[0].stage = VK_SHADER_STAGE_VERTEX_BIT;
841 sdr_stages[0].module = renderer->vs;
842 sdr_stages[0].pName = "main";
844 sdr_stages[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
845 sdr_stages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT;
846 sdr_stages[1].module = renderer->fs;
847 sdr_stages[1].pName = "main";
849 /* VkPushConstantRange */
850 memset(pc_range, 0, sizeof pc_range[0]);
851 pc_range[0].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
852 pc_range[0].size = sizeof (struct vk_dims); /* w, h */
854 /* VkPipelineLayoutCreateInfo */
855 memset(&layout_info, 0, sizeof layout_info);
856 layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
857 layout_info.pushConstantRangeCount = 1;
858 layout_info.pPushConstantRanges = pc_range;
860 if (vkCreatePipelineLayout(ctx->dev, &layout_info,
861 0, &pipeline_layout) != VK_SUCCESS) {
862 fprintf(stderr, "Failed to create pipeline layout\n");
863 renderer->pipeline = VK_NULL_HANDLE;
867 renderer->pipeline_layout = pipeline_layout;
869 /* VkGraphicsPipelineCreateInfo */
870 memset(&pipeline_info, 0, sizeof pipeline_info);
871 pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
872 pipeline_info.layout = pipeline_layout;
873 pipeline_info.renderPass = renderer->renderpass;
874 pipeline_info.pVertexInputState = &vert_input_info;
875 pipeline_info.pInputAssemblyState = &asm_info;
876 pipeline_info.pViewportState = &viewport_info;
877 pipeline_info.pRasterizationState = &rs_info;
878 pipeline_info.pMultisampleState = &ms_info;
879 pipeline_info.pDepthStencilState = &ds_info;
880 pipeline_info.pColorBlendState = &cb_info;
881 pipeline_info.stageCount = 2;
882 pipeline_info.pStages = sdr_stages;
884 if (vkCreateGraphicsPipelines(ctx->dev, 0, 1,
886 &renderer->pipeline) != VK_SUCCESS) {
887 fprintf(stderr, "Failed to create graphics pipeline.\n");
888 renderer->pipeline = VK_NULL_HANDLE;
901 get_memory_type_idx(VkPhysicalDevice pdev,
902 const VkMemoryRequirements *mem_reqs,
903 VkMemoryPropertyFlagBits prop_flags)
905 VkPhysicalDeviceMemoryProperties pdev_mem_props;
908 vkGetPhysicalDeviceMemoryProperties(pdev, &pdev_mem_props);
910 for (i = 0; i < pdev_mem_props.memoryTypeCount; i++) {
911 const VkMemoryType *type = &pdev_mem_props.memoryTypes[i];
913 if ((mem_reqs->memoryTypeBits & (1 << i)) &&
914 (type->propertyFlags & prop_flags) == prop_flags) {
922 static VkDeviceMemory
923 alloc_memory(struct vk_ctx *ctx,
925 const VkMemoryRequirements *mem_reqs,
928 VkMemoryPropertyFlagBits prop_flags)
930 VkExportMemoryAllocateInfo exp_mem_info;
931 VkMemoryAllocateInfo mem_alloc_info;
933 VkMemoryDedicatedAllocateInfoKHR ded_info;
936 memset(&exp_mem_info, 0, sizeof exp_mem_info);
937 exp_mem_info.sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO;
938 exp_mem_info.handleTypes =
939 VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
942 memset(&mem_alloc_info, 0, sizeof mem_alloc_info);
943 mem_alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
944 mem_alloc_info.pNext = is_external ? &exp_mem_info : VK_NULL_HANDLE;
945 mem_alloc_info.allocationSize = mem_reqs->size;
946 mem_alloc_info.memoryTypeIndex = get_memory_type_idx(ctx->pdev,
950 if (mem_alloc_info.memoryTypeIndex == UINT32_MAX) {
951 fprintf(stderr, "No suitable memory type index found.\n");
955 if (image || buffer) {
956 memset(&ded_info, 0, sizeof ded_info);
957 ded_info.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO;
958 ded_info.image = image;
959 ded_info.buffer = buffer;
961 exp_mem_info.pNext = &ded_info;
964 if (vkAllocateMemory(ctx->dev, &mem_alloc_info, 0, &mem) !=
972 alloc_image_memory(struct vk_ctx *ctx,
974 struct vk_image_obj *img_obj)
976 VkMemoryDedicatedRequirements ded_reqs;
977 VkImageMemoryRequirementsInfo2 req_info2;
978 VkMemoryRequirements2 mem_reqs2;
980 memset(&ded_reqs, 0, sizeof ded_reqs);
981 ded_reqs.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS;
983 /* VkImageMemoryRequirementsInfo2 */
984 memset(&req_info2, 0, sizeof req_info2);
985 req_info2.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2;
986 req_info2.image = img_obj->img;
988 /* VkMemoryRequirements2 */
989 memset(&mem_reqs2, 0, sizeof mem_reqs2);
990 mem_reqs2.sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2;
991 mem_reqs2.pNext = &ded_reqs;
993 vkGetImageMemoryRequirements2(ctx->dev, &req_info2, &mem_reqs2);
994 img_obj->mobj.mem = alloc_memory(ctx,
996 &mem_reqs2.memoryRequirements,
997 ded_reqs.requiresDedicatedAllocation ?
998 img_obj->img : VK_NULL_HANDLE,
1000 mem_reqs2.memoryRequirements.memoryTypeBits &
1001 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
1003 img_obj->mobj.mem_sz = mem_reqs2.memoryRequirements.size;
1004 img_obj->mobj.dedicated = ded_reqs.requiresDedicatedAllocation;
1005 if (img_obj->mobj.mem == VK_NULL_HANDLE) {
1006 fprintf(stderr, "Failed to allocate image memory.\n");
1010 if (vkBindImageMemory(ctx->dev, img_obj->img, img_obj->mobj.mem, 0) !=
1012 fprintf(stderr, "Failed to bind image memory.\n");
1020 are_props_supported(struct vk_ctx *ctx, struct vk_att_props *props)
1022 VkPhysicalDeviceExternalImageFormatInfo ext_img_fmt_info;
1023 VkExternalImageFormatProperties ext_img_fmt_props;
1026 VkPhysicalDeviceImageFormatInfo2 img_fmt_info;
1027 VkImageFormatProperties2 img_fmt_props;
1029 VkImageUsageFlagBits all_flags[] = {
1030 VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
1031 VK_IMAGE_USAGE_TRANSFER_DST_BIT,
1032 VK_IMAGE_USAGE_SAMPLED_BIT,
1033 VK_IMAGE_USAGE_STORAGE_BIT,
1034 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
1035 VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
1036 VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT,
1037 /* Shouldn't be used together with COLOR, DEPTH_STENCIL
1039 * VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT,
1040 * Provided by VK_EXT_fragment_density_map
1041 * VK_IMAGE_USAGE_FRAGMENT_DENSITY_MAP_BIT_EXT,
1042 * Provided by VK_NV_shading_rate_image
1043 * VK_IMAGE_USAGE_SHADING_RATE_IMAGE_BIT_NV,
1044 * Provided by VK_KHR_fragment_shading_rate
1045 * VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR,
1048 VkImageUsageFlagBits flags = 0;
1050 VkExternalMemoryFeatureFlagBits export_feature_flags = props->need_export ?
1051 VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT : 0;
1052 VkExternalMemoryHandleTypeFlagBits handle_type = props->need_export ?
1053 VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR : 0;
1055 if (props->need_export) {
1056 memset(&ext_img_fmt_info, 0, sizeof ext_img_fmt_info);
1057 ext_img_fmt_info.sType =
1058 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO;
1059 ext_img_fmt_info.handleType = handle_type;
1061 memset(&ext_img_fmt_props, 0, sizeof ext_img_fmt_props);
1062 ext_img_fmt_props.sType =
1063 VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES;
1066 memset(&img_fmt_props, 0, sizeof img_fmt_props);
1067 img_fmt_props.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2;
1068 img_fmt_props.pNext = props->need_export ? &ext_img_fmt_props : 0;
1070 memset(&img_fmt_info, 0, sizeof img_fmt_info);
1071 img_fmt_info.sType =
1072 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2;
1073 img_fmt_info.pNext = props->need_export ? &ext_img_fmt_info : 0;
1074 img_fmt_info.format = props->format;
1075 img_fmt_info.type = VK_IMAGE_TYPE_2D;
1076 img_fmt_info.tiling = props->tiling;
1078 for (i = 0; i < ARRAY_SIZE(all_flags); i++) {
1079 img_fmt_info.usage = all_flags[i];
1080 if (vkGetPhysicalDeviceImageFormatProperties2(ctx->pdev,
1082 &img_fmt_props) == VK_SUCCESS) {
1083 flags |= all_flags[i];
1087 /* usage can't be null */
1089 img_fmt_info.usage = flags;
1091 if (!props->is_swapchain) {
1092 fprintf(stderr, "Unsupported Vulkan format properties: usage.\n");
1095 img_fmt_info.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
1098 if (vkGetPhysicalDeviceImageFormatProperties2
1099 (ctx->pdev, &img_fmt_info, &img_fmt_props) != VK_SUCCESS) {
1101 "Unsupported Vulkan format properties.\n");
1104 props->usage = flags;
1106 if (props->need_export &&
1107 !(ext_img_fmt_props.externalMemoryProperties.externalMemoryFeatures
1108 & export_feature_flags)) {
1109 fprintf(stderr, "Unsupported Vulkan external memory features.\n");
1116 /* static swapchain / surf related functions */
1119 sc_validate_surface(struct vk_ctx *ctx,
1124 fprintf(stderr, "No surface!\n");
1128 if(vkGetPhysicalDeviceSurfaceSupportKHR(ctx->pdev, ctx->qfam_idx,
1129 surf, &supported) != VK_SUCCESS) {
1130 fprintf(stderr, "Failed to validate surface.\n");
1135 fprintf(stderr, "Invalid surface! Check if the surface with queue family index: %d supports presentation.\n", (int)ctx->qfam_idx);
1143 sc_select_format(struct vk_ctx *ctx,
1145 VkSwapchainCreateInfoKHR *s_info)
1147 VkSurfaceFormatKHR *formats;
1148 uint32_t num_formats;
1150 if (vkGetPhysicalDeviceSurfaceFormatsKHR(ctx->pdev,
1152 &num_formats, 0) != VK_SUCCESS) {
1153 fprintf(stderr, "Failed to get the number of surface formats.\n");
1158 fprintf(stderr, "No surface formats found.\n");
1162 formats = malloc(num_formats * sizeof *formats);
1164 if (vkGetPhysicalDeviceSurfaceFormatsKHR(ctx->pdev, surf, &num_formats,
1165 formats) != VK_SUCCESS) {
1166 fprintf(stderr, "Failed to get the supported surface formats.\n");
1170 if ((num_formats == 1) && (formats[0].format == VK_FORMAT_UNDEFINED)) {
1171 s_info->imageFormat = VK_FORMAT_B8G8R8A8_UNORM;
1172 s_info->imageColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
1174 s_info->imageFormat = formats[0].format;
1175 s_info->imageColorSpace = formats[0].colorSpace;
1183 sc_select_supported_present_modes(struct vk_ctx *ctx,
1186 VkSwapchainCreateInfoKHR *s_info)
1188 VkPresentModeKHR *present_modes;
1189 uint32_t num_present_modes;
1191 /* find supported present modes */
1192 if (vkGetPhysicalDeviceSurfacePresentModesKHR(ctx->pdev, surf,
1193 &num_present_modes, 0) != VK_SUCCESS || !num_present_modes) {
1194 fprintf(stderr, "Failed to get the number of the supported presentation modes.\n");
1198 present_modes = malloc(num_present_modes * sizeof *present_modes);
1199 if (vkGetPhysicalDeviceSurfacePresentModesKHR(ctx->pdev, surf,
1201 present_modes) != VK_SUCCESS) {
1202 fprintf(stderr, "Failed to get the number of supported presentation modes.\n");
1205 if (vkGetPhysicalDeviceSurfacePresentModesKHR(ctx->pdev, surf,
1207 present_modes) != VK_SUCCESS) {
1208 fprintf(stderr, "Failed to get the supported presentation modes.\n");
1212 s_info->presentMode = VK_PRESENT_MODE_FIFO_KHR;
1215 for (i = 0; i < num_present_modes; i++) {
1216 if (present_modes[i] == VK_PRESENT_MODE_MAILBOX_KHR) {
1217 s_info->presentMode = present_modes[i];
1220 if (present_modes[i] == VK_PRESENT_MODE_IMMEDIATE_KHR) {
1221 s_info->presentMode = present_modes[i];
1228 free(present_modes);
1232 /* end of static functions */
1234 /* exposed Vulkan functions */
1237 vk_init_ctx(struct vk_ctx *ctx,
1240 if ((ctx->inst = create_instance(enable_layers)) == VK_NULL_HANDLE) {
1241 fprintf(stderr, "Failed to create Vulkan instance.\n");
1245 if ((ctx->pdev = select_physical_device(ctx->inst)) == VK_NULL_HANDLE) {
1246 fprintf(stderr, "Failed to find suitable physical device.\n");
1250 if ((ctx->dev = create_device(ctx, ctx->pdev)) == VK_NULL_HANDLE) {
1251 fprintf(stderr, "Failed to create Vulkan device.\n");
1255 fill_uuid(ctx->pdev, ctx->deviceUUID, ctx->driverUUID);
1259 vk_cleanup_ctx(ctx);
1264 vk_init_ctx_for_rendering(struct vk_ctx *ctx,
1268 if (!vk_init_ctx(ctx, enable_layers)) {
1269 fprintf(stderr, "Failed to initialize Vulkan.\n");
1273 if ((ctx->cmd_pool = create_cmd_pool(ctx)) == VK_NULL_HANDLE) {
1274 fprintf(stderr, "Failed to create command pool.\n");
1278 vkGetDeviceQueue(ctx->dev, ctx->qfam_idx, 0, &ctx->queue);
1280 fprintf(stderr, "Failed to get command queue.\n");
1285 if (!(pipeline_cache = create_pipeline_cache(ctx))) {
1286 fprintf(stderr, "Failed to create pipeline cache.\n");
1294 vk_cleanup_ctx(ctx);
1299 vk_destroy_cmd_buffers(struct vk_ctx *ctx,
1300 uint32_t num_buffers,
1301 VkCommandBuffer *buffers)
1304 for (i = 0; i < num_buffers; i++) {
1305 vkResetCommandBuffer(buffers[i],
1306 VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT);
1308 vkFreeCommandBuffers(ctx->dev, ctx->cmd_pool, num_buffers, buffers);
1312 vk_cleanup_ctx(struct vk_ctx *ctx)
1314 if (ctx->cmd_pool != VK_NULL_HANDLE) {
1315 vkResetCommandPool(ctx->dev, ctx->cmd_pool,
1316 VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT);
1317 vkDestroyCommandPool(ctx->dev, ctx->cmd_pool, 0);
1318 ctx->cmd_pool = VK_NULL_HANDLE;
1321 if (pipeline_cache != VK_NULL_HANDLE) {
1322 vkDestroyPipelineCache(ctx->dev, pipeline_cache, 0);
1323 pipeline_cache = VK_NULL_HANDLE;
1326 if (ctx->dev != VK_NULL_HANDLE) {
1327 vkDestroyDevice(ctx->dev, 0);
1328 ctx->dev = VK_NULL_HANDLE;
1331 if (ctx->inst != VK_NULL_HANDLE) {
1332 vkDestroyInstance(ctx->inst, 0);
1333 ctx->inst = VK_NULL_HANDLE;
1338 vk_create_ext_image(struct vk_ctx *ctx,
1339 struct vk_att_props *props,
1340 struct vk_image_obj *img)
1342 VkExternalMemoryImageCreateInfo ext_img_info;
1343 VkImageCreateInfo img_info;
1345 memset(&ext_img_info, 0, sizeof ext_img_info);
1346 ext_img_info.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO;
1347 ext_img_info.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;
1349 memset(&img_info, 0, sizeof img_info);
1350 img_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
1351 img_info.pNext = &ext_img_info;
1352 img_info.imageType = get_image_type(props->h, props->depth);
1353 img_info.format = props->format;
1354 img_info.extent.width = props->w;
1355 img_info.extent.height = props->h;
1356 img_info.extent.depth = props->depth;
1357 img_info.mipLevels = props->num_levels ? props->num_levels : 1;
1358 img_info.arrayLayers = props->num_layers ?
1359 props->num_layers : VK_SAMPLE_COUNT_1_BIT;
1360 img_info.samples = get_num_samples(props->num_samples);
1361 img_info.tiling = props->tiling;
1362 img_info.usage = props->usage;
1363 img_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
1364 img_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
1365 /* issue 17 of EXT_external_objects
1366 * Required in OpenGL implementations that support
1367 * ARB_texture_view, OES_texture_view, EXT_texture_view,
1368 * or OpenGL 4.3 and above.
1370 img_info.flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
1372 if (vkCreateImage(ctx->dev, &img_info, 0, &img->img) != VK_SUCCESS)
1375 if(!alloc_image_memory(ctx, true, img))
1381 fprintf(stderr, "Failed to create external image.\n");
1382 vk_destroy_image(ctx, img);
1383 img->img = VK_NULL_HANDLE;
1384 img->mobj.mem = VK_NULL_HANDLE;
1389 vk_create_image(struct vk_ctx *ctx,
1390 struct vk_att_props *props,
1391 struct vk_image_obj *img)
1393 VkImageCreateInfo img_info;
1395 memset(&img_info, 0, sizeof img_info);
1396 img_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
1397 img_info.pNext = 0; /* do something if external */
1398 img_info.imageType = get_image_type(props->h, props->depth);
1399 img_info.format = props->format;
1400 img_info.extent.width = props->w;
1401 img_info.extent.height = props->h;
1402 img_info.extent.depth = props->depth;
1403 img_info.mipLevels = props->num_levels ? props->num_levels : 1;
1404 img_info.arrayLayers = props->num_layers ?
1405 props->num_layers : VK_SAMPLE_COUNT_1_BIT;
1406 img_info.samples = get_num_samples(props->num_samples);
1407 img_info.tiling = props->tiling;
1408 img_info.usage = props->usage ?
1409 props->usage : VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
1410 img_info.initialLayout = props->in_layout;
1411 img_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
1413 if (vkCreateImage(ctx->dev, &img_info, 0, &img->img) != VK_SUCCESS)
1416 if(!alloc_image_memory(ctx, props->need_export, img))
1422 fprintf(stderr, "Failed to create external image.\n");
1423 vk_destroy_image(ctx, img);
1424 img->img = VK_NULL_HANDLE;
1425 img->mobj.mem = VK_NULL_HANDLE;
1430 vk_create_image_view(struct vk_ctx *ctx,
1432 VkImageViewType view_type,
1435 VkImageView *image_view)
1437 VkImageViewCreateInfo info;
1438 VkImageSubresourceRange sr;
1439 VkImageAspectFlagBits aspect = get_aspect_from_depth_format(format);
1441 /* VkSubresourceRange */
1442 memset(&sr, 0, sizeof sr);
1443 sr.aspectMask = aspect ? aspect : VK_IMAGE_ASPECT_COLOR_BIT;
1447 memset(&info, 0, sizeof info);
1448 info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
1450 info.viewType = view_type;
1451 info.viewType = VK_IMAGE_VIEW_TYPE_2D;
1452 info.format = format;
1453 info.subresourceRange = sr;
1456 info.components.r = VK_COMPONENT_SWIZZLE_R;
1457 info.components.g = VK_COMPONENT_SWIZZLE_G;
1458 info.components.b = VK_COMPONENT_SWIZZLE_B;
1459 info.components.a = VK_COMPONENT_SWIZZLE_A;
1462 if (vkCreateImageView(ctx->dev, &info, 0, image_view) != VK_SUCCESS) {
1463 fprintf(stderr, "Failed to create image view.\n");
1464 image_view = VK_NULL_HANDLE;
1473 vk_destroy_image(struct vk_ctx *ctx, struct vk_image_obj *img_obj)
1475 if (img_obj->img != VK_NULL_HANDLE) {
1476 vkDestroyImage(ctx->dev, img_obj->img, 0);
1477 img_obj->img = VK_NULL_HANDLE;
1480 if (img_obj->mobj.mem != VK_NULL_HANDLE) {
1481 vkFreeMemory(ctx->dev, img_obj->mobj.mem, 0);
1482 img_obj->mobj.mem = VK_NULL_HANDLE;
1487 vk_fill_image_props(struct vk_ctx *ctx,
1491 uint32_t num_samples,
1492 uint32_t num_levels,
1493 uint32_t num_layers,
1495 VkImageTiling tiling,
1496 VkImageLayout in_layout,
1497 VkImageLayout end_layout,
1501 struct vk_att_props *props)
1507 props->num_samples = num_samples;
1508 props->num_levels = num_levels;
1509 props->num_layers = num_layers;
1511 props->format = format;
1512 props->tiling = tiling;
1514 props->in_layout = in_layout;
1515 props->end_layout = end_layout;
1517 props->is_swapchain = is_swapchain;
1518 props->is_depth = is_depth;
1519 props->need_export = need_export;
1521 if (!are_props_supported(ctx, props))
1527 struct vk_attachment
1528 vk_create_attachment_from_obj(struct vk_image_obj *obj,
1529 struct vk_att_props *props)
1531 struct vk_attachment att;
1539 struct vk_attachment
1540 vk_create_attachment(VkImage image,
1542 struct vk_att_props *props)
1544 struct vk_attachment att;
1546 att.obj.img = image;
1547 att.obj.img_view = view;
1550 memset(&att.obj.mobj, 0, sizeof att.obj.mobj);
1556 vk_create_framebuffer(struct vk_ctx *ctx,
1557 int width, int height,
1559 VkImageView *color_views,
1560 VkImageView *depth_view,
1564 VkFramebufferCreateInfo fb_info;
1567 int num_atts = num_color_atts + 1;
1569 atts = malloc(num_atts * sizeof atts[0]);
1570 for (i = 0; i < num_color_atts; i++) {
1571 atts[i] = color_views[i];
1573 atts[num_color_atts] = *depth_view;
1575 memset(&fb_info, 0, sizeof fb_info);
1576 fb_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
1577 fb_info.renderPass = rpass;
1578 fb_info.width = width;
1579 fb_info.height = height;
1581 fb_info.attachmentCount = num_atts;
1582 fb_info.pAttachments = atts;
1584 if (vkCreateFramebuffer(ctx->dev, &fb_info, 0, fb) != VK_SUCCESS) {
1585 fprintf(stderr, "Failed to create framebuffer.\n");
1587 fb = VK_NULL_HANDLE;
1598 vk_create_renderer(struct vk_ctx *ctx,
1600 unsigned int vs_size,
1602 unsigned int fs_size,
1604 uint32_t num_samples,
1606 bool enable_stencil,
1608 struct vk_att_props *color_props,
1609 struct vk_att_props *depth_props,
1610 struct vk_geometry *geometry,
1611 struct vk_renderer *renderer)
1613 /* create image views for each attachment */
1615 if (!create_attachment_views(ctx, num_color_att, color_att, depth_att))
1620 if (!vk_create_renderpass(ctx, num_color_att, color_props, depth_props,
1624 renderer->renderpass = rpass;
1626 VkShaderModule vs = create_shader_module(ctx, vs_src, vs_size);
1627 if (vs == VK_NULL_HANDLE)
1631 VkShaderModule fs = create_shader_module(ctx, fs_src, fs_size);
1632 if (fs == VK_NULL_HANDLE)
1637 renderer->geometry = geometry;
1639 /* FIXME this is only for graphics atm */
1640 if(!create_graphics_pipeline(ctx, w, h,
1644 enable_stencil, renderer))
1650 fprintf(stderr, "Failed to create renderer.\n");
1651 vk_destroy_renderer(ctx, renderer);
1656 vk_destroy_renderer(struct vk_ctx *ctx,
1657 struct vk_renderer *renderer)
1659 if (renderer->renderpass != VK_NULL_HANDLE) {
1660 vkDestroyRenderPass(ctx->dev, renderer->renderpass, 0);
1661 renderer->renderpass = VK_NULL_HANDLE;
1664 if (renderer->vs != VK_NULL_HANDLE) {
1665 vkDestroyShaderModule(ctx->dev, renderer->vs, 0);
1666 renderer->vs = VK_NULL_HANDLE;
1669 if (renderer->fs != VK_NULL_HANDLE) {
1670 vkDestroyShaderModule(ctx->dev, renderer->fs, 0);
1671 renderer->fs = VK_NULL_HANDLE;
1674 if (renderer->pipeline != VK_NULL_HANDLE) {
1675 vkDestroyPipeline(ctx->dev, renderer->pipeline, 0);
1676 renderer->pipeline = VK_NULL_HANDLE;
1679 if (renderer->pipeline_layout != VK_NULL_HANDLE) {
1680 vkDestroyPipelineLayout(ctx->dev, renderer->pipeline_layout, 0);
1681 renderer->pipeline_layout = VK_NULL_HANDLE;
1686 vk_create_ext_buffer(struct vk_ctx *ctx,
1688 VkBufferUsageFlagBits usage,
1691 VkExternalMemoryBufferCreateInfo ext_bo_info;
1693 memset(&ext_bo_info, 0, sizeof ext_bo_info);
1694 ext_bo_info.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO;
1695 ext_bo_info.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;
1697 if (!vk_create_buffer(ctx, true, sz, usage, &ext_bo_info, bo)) {
1698 fprintf(stderr, "Failed to allocate external buffer.\n");
1706 vk_create_buffer(struct vk_ctx *ctx,
1709 VkBufferUsageFlagBits usage,
1713 VkBufferCreateInfo buf_info;
1714 VkMemoryRequirements mem_reqs;
1716 bo->mobj.mem = VK_NULL_HANDLE;
1717 bo->buf = VK_NULL_HANDLE;
1719 /* VkBufferCreateInfo */
1720 memset(&buf_info, 0, sizeof buf_info);
1721 buf_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
1723 buf_info.usage = usage;
1724 buf_info.pNext = pnext;
1725 buf_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
1727 if (vkCreateBuffer(ctx->dev, &buf_info, 0, &bo->buf) != VK_SUCCESS)
1730 /* allocate buffer */
1731 vkGetBufferMemoryRequirements(ctx->dev, bo->buf, &mem_reqs);
1732 /* VK_MEMORY_PROPERTY_HOST_COHERENT_BIT bit specifies that the
1733 * host cache management commands vkFlushMappedMemoryRanges and
1734 * vkInvalidateMappedMemoryRanges are not needed to flush host
1735 * writes to the device or make device writes visible to the
1736 * host, respectively. */
1737 bo->mobj.mem = alloc_memory(ctx, is_external, &mem_reqs, VK_NULL_HANDLE,
1739 VK_MEMORY_PROPERTY_HOST_COHERENT_BIT |
1740 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
1742 if (bo->mobj.mem == VK_NULL_HANDLE)
1745 bo->mobj.mem_sz = sz;
1747 if (vkBindBufferMemory(ctx->dev, bo->buf, bo->mobj.mem, 0) != VK_SUCCESS) {
1748 fprintf(stderr, "Failed to bind buffer memory.\n");
1755 fprintf(stderr, "Failed to allocate buffer.\n");
1756 vk_destroy_buffer(ctx, bo);
1761 vk_update_buffer_data(struct vk_ctx *ctx,
1768 if (vkMapMemory(ctx->dev, bo->mobj.mem, 0, data_sz, 0, &map) != VK_SUCCESS) {
1769 fprintf(stderr, "Failed to map buffer memory.\n");
1773 memcpy(map, data, data_sz);
1775 vkUnmapMemory(ctx->dev, bo->mobj.mem);
1779 fprintf(stderr, "Failed to update buffer data. Destroying the buffer.\n");
1780 vk_destroy_buffer(ctx, bo);
1786 vk_destroy_buffer(struct vk_ctx *ctx,
1789 if (bo->buf != VK_NULL_HANDLE)
1790 vkDestroyBuffer(ctx->dev, bo->buf, 0);
1792 if (bo->mobj.mem != VK_NULL_HANDLE)
1793 vkFreeMemory(ctx->dev, bo->mobj.mem, 0);
1795 bo->mobj.mem_sz = 0;
1796 bo->buf = VK_NULL_HANDLE;
1797 bo->mobj.mem = VK_NULL_HANDLE;
1801 vk_create_fence(struct vk_ctx *ctx,
1804 VkFenceCreateInfo finfo;
1806 memset(&finfo, 0, sizeof finfo);
1807 finfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
1809 if (vkCreateFence(ctx->dev, &finfo, 0, fence) != VK_SUCCESS) {
1810 fprintf(stderr, "Failed to create fence.\n");
1819 vk_create_cmd_buffer(struct vk_ctx *ctx)
1821 VkCommandBuffer cmd_buf;
1822 VkCommandBufferAllocateInfo alloc_info;
1824 memset(&alloc_info, 0, sizeof alloc_info);
1825 alloc_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
1826 alloc_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
1827 alloc_info.commandBufferCount = 1;
1828 alloc_info.commandPool = ctx->cmd_pool;
1830 if (vkAllocateCommandBuffers(ctx->dev, &alloc_info,
1831 &cmd_buf) != VK_SUCCESS)
1838 vk_record_cmd_buffer(struct vk_ctx *ctx,
1839 VkCommandBuffer cmd_buf,
1840 struct vk_renderer *renderer,
1841 uint32_t vk_fb_color_count,
1845 struct vk_attachment *atts,
1849 VkCommandBufferBeginInfo cmd_begin_info;
1850 VkRenderPassBeginInfo rp_begin_info;
1852 VkClearValue *clear_values; int i;
1853 VkDeviceSize offsets[] = {0};
1854 int num_vertices = 0;
1855 struct vk_dims img_size;
1856 bool create_cmd_buf = false;
1857 bool has_geometry = renderer->geometry != 0;
1859 assert(vk_fb_color_count == 4);
1862 fprintf(stderr, "Can't record an empty command buffer.\n");
1866 /* VkCommandBufferBeginInfo */
1867 memset(&cmd_begin_info, 0, sizeof cmd_begin_info);
1868 cmd_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
1869 cmd_begin_info.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT;
1871 /* VkRect2D render area */
1872 memset(&rp_area, 0, sizeof rp_area);
1873 rp_area.extent.width = (uint32_t)w;
1874 rp_area.extent.height = (uint32_t)h;
1875 rp_area.offset.x = x;
1876 rp_area.offset.y = y;
1879 clear_values = malloc(num_atts * sizeof clear_values[0]);
1880 memset(clear_values, 0, num_atts * sizeof clear_values[0]);
1882 for (i = 0; i < num_atts - 1; i++) {
1883 clear_values[i].color.float32[0] = vk_fb_color[0];
1884 clear_values[i].color.float32[1] = vk_fb_color[1];
1885 clear_values[i].color.float32[2] = vk_fb_color[2];
1886 clear_values[i].color.float32[3] = vk_fb_color[3];
1888 clear_values[num_atts - 1].depthStencil.depth = 1.0f;
1889 clear_values[num_atts - 1].depthStencil.stencil = 0;
1891 /* VkRenderPassBeginInfo */
1892 memset(&rp_begin_info, 0, sizeof rp_begin_info);
1893 rp_begin_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
1894 rp_begin_info.renderPass = renderer->renderpass;
1895 rp_begin_info.framebuffer = fb;
1896 rp_begin_info.renderArea = rp_area;
1897 rp_begin_info.clearValueCount = num_atts;
1898 rp_begin_info.pClearValues = clear_values;
1900 vkBeginCommandBuffer(cmd_buf, &cmd_begin_info);
1901 vkCmdBeginRenderPass(cmd_buf, &rp_begin_info, VK_SUBPASS_CONTENTS_INLINE);
1906 viewport.height = h;
1908 scissor.offset.x = x;
1909 scissor.offset.y = y;
1910 scissor.extent.width = w;
1911 scissor.extent.height = h;
1913 vkCmdSetViewport(cmd_buf, 0, 1, &viewport);
1914 vkCmdSetScissor(cmd_buf, 0, 1, &scissor);
1916 img_size.w = (float)w;
1917 img_size.h = (float)h;
1918 vkCmdPushConstants(cmd_buf,
1919 renderer->pipeline_layout,
1920 VK_SHADER_STAGE_FRAGMENT_BIT,
1921 0, sizeof (struct vk_dims),
1924 if (has_geometry && renderer->geometry->vertices.num_vertices > 0) {
1925 num_vertices = renderer->geometry->vertices.num_vertices;
1926 vkCmdBindVertexBuffers(cmd_buf, 0, 1, &renderer->geometry->vertices.vbo, offsets);
1929 vkCmdBindPipeline(cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS,
1930 renderer->pipeline);
1932 /* FIXME: temporal hack because I hard code 4 vertices in the
1933 * vertex shader until I properly support VBOs */
1937 vkCmdDraw(cmd_buf, num_vertices, 1, 0, 0);
1938 vkCmdEndRenderPass(cmd_buf);
1943 VkImageMemoryBarrier *barriers =
1944 calloc(num_atts, sizeof(VkImageMemoryBarrier));
1945 VkImageMemoryBarrier *barrier = barriers;
1946 for (uint32_t n = 0; n < num_atts; n++, barrier++) {
1947 struct vk_attachment *att = &atts[n];
1948 VkImageAspectFlagBits depth_stencil_flags =
1949 get_aspect_from_depth_format(att->props.format);
1950 bool is_depth = (depth_stencil_flags != 0);
1952 /* Insert barrier to mark ownership transfer. */
1953 barrier->sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
1954 barrier->oldLayout = is_depth ?
1955 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL :
1956 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
1957 barrier->newLayout = VK_IMAGE_LAYOUT_GENERAL;
1958 barrier->srcAccessMask = get_access_mask(barrier->oldLayout);
1959 barrier->dstAccessMask = get_access_mask(barrier->newLayout);
1960 barrier->srcQueueFamilyIndex = ctx->qfam_idx;
1961 barrier->dstQueueFamilyIndex = VK_QUEUE_FAMILY_EXTERNAL;
1962 barrier->image = att->obj.img;
1963 barrier->subresourceRange.aspectMask = is_depth ?
1964 depth_stencil_flags :
1965 VK_IMAGE_ASPECT_COLOR_BIT;
1966 barrier->subresourceRange.baseMipLevel = 0;
1967 barrier->subresourceRange.levelCount = 1;
1968 barrier->subresourceRange.baseArrayLayer = 0;
1969 barrier->subresourceRange.layerCount = 1;
1972 vkCmdPipelineBarrier(cmd_buf,
1973 VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
1974 VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
1978 num_atts, barriers);
1983 vkEndCommandBuffer(cmd_buf);
1984 if (create_cmd_buf) {
1985 vk_destroy_cmd_buffers(ctx, 1, &cmd_buf);
1991 vk_draw(struct vk_ctx *ctx,
1992 struct vk_semaphores *semaphores,
1993 uint32_t num_buffers,
1994 VkCommandBuffer *cmd_buf)
1996 VkSubmitInfo submit_info;
1997 VkPipelineStageFlagBits stage_flags;
2000 memset(&submit_info, 0, sizeof submit_info);
2001 submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
2002 submit_info.commandBufferCount = num_buffers;
2003 submit_info.pCommandBuffers = cmd_buf;
2007 assert(semaphores->frame_ready);
2008 assert(semaphores->frame_done);
2010 /* The subpasses in a render pass automatically take care of
2011 * image layout transitions. These transitions are controlled
2012 * by subpass dependencies, which specify memory and execution
2013 * dependencies between subpasses. We have only a single subpass
2014 * right now, but the operations right before and right after
2015 * this subpass also count as implicit "subpasses". There are two
2016 * built-in dependencies that take care of the transition at the
2017 * start of the render pass and at the end of the render pass,
2018 * but the former does not occur at the right time. It assumes
2019 * that the transition occurs at the start of the pipeline,
2020 * but we haven't acquired the image yet at that point! There are
2021 * two ways to deal with this problem.
2023 * We could change the waitStages for the frame_ready semaphore
2024 * to VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT to ensure that the render
2025 * passes don't begin until the image is available, or we can make
2026 * the render pass wait for the
2027 * VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT stage.
2029 stage_flags = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT;
2031 submit_info.pWaitDstStageMask = &stage_flags;
2032 submit_info.waitSemaphoreCount = 1;
2033 submit_info.pWaitSemaphores = &semaphores->frame_done;
2035 submit_info.signalSemaphoreCount = 1;
2036 submit_info.pSignalSemaphores = &semaphores->frame_ready;
2040 if (vkQueueSubmit(ctx->queue, 1, &submit_info,
2041 VK_NULL_HANDLE) != VK_SUCCESS) {
2042 fprintf(stderr, "Failed to submit queue.\n");
2046 if (vkQueueWaitIdle(ctx->queue) != VK_SUCCESS) {
2047 fprintf(stderr, "Failed to wait idle.\n");
2053 vk_clear_color(struct vk_ctx *ctx,
2054 VkCommandBuffer cmd_buf,
2056 struct vk_renderer *renderer,
2058 uint32_t vk_fb_color_count,
2060 struct vk_semaphores *semaphores,
2061 bool has_wait, bool has_signal,
2062 struct vk_attachment *attachments,
2063 uint32_t n_attachments,
2067 VkCommandBufferBeginInfo cmd_begin_info;
2068 VkRenderPassBeginInfo rp_begin_info;
2070 VkClearValue clear_values[2];
2071 VkSubmitInfo submit_info;
2072 VkPipelineStageFlagBits stage_flags;
2073 VkImageSubresourceRange img_range;
2075 assert(vk_fb_color_count == 4);
2077 /* VkCommandBufferBeginInfo */
2078 memset(&cmd_begin_info, 0, sizeof cmd_begin_info);
2079 cmd_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
2080 cmd_begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
2082 /* VkRect2D render area */
2083 memset(&rp_area, 0, sizeof rp_area);
2084 rp_area.extent.width = (uint32_t)w;
2085 rp_area.extent.height = (uint32_t)h;
2086 rp_area.offset.x = x;
2087 rp_area.offset.y = y;
2090 memset(&clear_values[0], 0, sizeof clear_values[0]);
2091 clear_values[0].color.float32[0] = vk_fb_color[0]; /* red */
2092 clear_values[0].color.float32[1] = vk_fb_color[1]; /* green */
2093 clear_values[0].color.float32[2] = vk_fb_color[2]; /* blue */
2094 clear_values[0].color.float32[3] = vk_fb_color[3]; /* alpha */
2096 memset(&clear_values[1], 0, sizeof clear_values[1]);
2097 clear_values[1].depthStencil.depth = 1.0;
2098 clear_values[1].depthStencil.stencil = 0;
2100 /* VkRenderPassBeginInfo */
2101 memset(&rp_begin_info, 0, sizeof rp_begin_info);
2102 rp_begin_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
2103 rp_begin_info.renderPass = renderer->renderpass;
2104 rp_begin_info.framebuffer = fb;
2105 rp_begin_info.renderArea = rp_area;
2106 rp_begin_info.clearValueCount = 2;
2107 rp_begin_info.pClearValues = clear_values;
2110 stage_flags = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT;
2112 memset(&submit_info, 0, sizeof submit_info);
2113 submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
2114 submit_info.commandBufferCount = 1;
2115 submit_info.pCommandBuffers = &cmd_buf;
2119 submit_info.pWaitDstStageMask = &stage_flags;
2120 submit_info.waitSemaphoreCount = 1;
2121 submit_info.pWaitSemaphores = &semaphores->frame_done;
2125 submit_info.signalSemaphoreCount = 1;
2126 submit_info.pSignalSemaphores = &semaphores->frame_ready;
2129 img_range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
2130 img_range.baseMipLevel = 0;
2131 img_range.levelCount = 1;
2132 img_range.baseArrayLayer = 0;
2133 img_range.layerCount = 1;
2135 vkBeginCommandBuffer(cmd_buf, &cmd_begin_info);
2136 vk_transition_image_layout(&attachments[0],
2138 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
2139 VK_IMAGE_LAYOUT_GENERAL,
2140 VK_QUEUE_FAMILY_EXTERNAL,
2142 vkCmdClearColorImage(cmd_buf,
2143 attachments[0].obj.img,
2144 VK_IMAGE_LAYOUT_GENERAL,
2145 &clear_values[0].color,
2149 vkCmdBeginRenderPass(cmd_buf, &rp_begin_info, VK_SUBPASS_CONTENTS_INLINE);
2154 viewport.height = h;
2156 scissor.offset.x = x;
2157 scissor.offset.y = y;
2158 scissor.extent.width = w;
2159 scissor.extent.height = h;
2161 vkCmdSetViewport(cmd_buf, 0, 1, &viewport);
2162 vkCmdSetScissor(cmd_buf, 0, 1, &scissor);
2164 vkCmdBindPipeline(cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS,
2165 renderer->pipeline);
2167 vkCmdEndRenderPass(cmd_buf);
2170 VkImageMemoryBarrier *barriers =
2171 calloc(n_attachments, sizeof(VkImageMemoryBarrier));
2172 VkImageMemoryBarrier *barrier = barriers;
2174 for (uint32_t n = 0; n < n_attachments; n++, barrier++) {
2175 struct vk_attachment *att = &attachments[n];
2177 /* Insert barrier to mark ownership transfer. */
2178 barrier->sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
2181 get_aspect_from_depth_format(att->props.format) != 0;
2183 barrier->oldLayout = is_depth ?
2184 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL :
2185 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
2186 barrier->newLayout = VK_IMAGE_LAYOUT_GENERAL;
2187 barrier->srcAccessMask = get_access_mask(barrier->oldLayout);
2188 barrier->dstAccessMask = get_access_mask(barrier->newLayout);
2189 barrier->srcQueueFamilyIndex = ctx->qfam_idx;
2190 barrier->dstQueueFamilyIndex = VK_QUEUE_FAMILY_EXTERNAL;
2191 barrier->image = att->obj.img;
2192 barrier->subresourceRange.aspectMask = is_depth ?
2193 VK_IMAGE_ASPECT_DEPTH_BIT :
2194 VK_IMAGE_ASPECT_COLOR_BIT;
2195 barrier->subresourceRange.baseMipLevel = 0;
2196 barrier->subresourceRange.levelCount = 1;
2197 barrier->subresourceRange.baseArrayLayer = 0;
2198 barrier->subresourceRange.layerCount = 1;
2201 vkCmdPipelineBarrier(cmd_buf,
2202 VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
2203 VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
2207 n_attachments, barriers);
2211 vkEndCommandBuffer(cmd_buf);
2213 if (vkQueueSubmit(ctx->queue, 1, &submit_info,
2214 VK_NULL_HANDLE) != VK_SUCCESS) {
2215 fprintf(stderr, "Failed to submit queue.\n");
2218 if (!semaphores && !has_wait && !has_signal)
2219 vkQueueWaitIdle(ctx->queue);
2223 vk_set_viewport(struct vk_ctx *ctx,
2224 VkCommandBuffer cmd_buf,
2227 float near, float far)
2229 VkCommandBufferBeginInfo binfo;
2230 VkViewport viewport;
2232 memset(&viewport, 0, sizeof viewport);
2236 viewport.height = h;
2237 viewport.minDepth = near;
2238 viewport.maxDepth = far;
2240 memset(&binfo, 0, sizeof binfo);
2241 binfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
2242 binfo.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT;
2244 vkBeginCommandBuffer(cmd_buf, &binfo);
2245 vkCmdSetViewport(cmd_buf, 0, 1, &viewport);
2246 vkEndCommandBuffer(cmd_buf);
2250 vk_create_swapchain(struct vk_ctx *ctx,
2251 int width, int height,
2254 struct vk_swapchain *old_swapchain,
2255 struct vk_swapchain *swapchain)
2257 VkSurfaceCapabilitiesKHR surf_cap;
2258 VkSwapchainCreateInfoKHR s_info;
2262 if (!sc_validate_surface(ctx, surf)) {
2263 fprintf(stderr, "Failed to validate surface!\n");
2267 /* get pdevice capabilities
2268 * will need that to determine the swapchain number of images
2270 if (vkGetPhysicalDeviceSurfaceCapabilitiesKHR(ctx->pdev, surf, &surf_cap) != VK_SUCCESS) {
2271 fprintf(stderr, "Failed to query surface capabilities.\n");
2275 memset(swapchain, 0, sizeof *swapchain);
2277 memset(&s_info, 0, sizeof s_info);
2278 s_info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
2280 if (!sc_select_format(ctx, surf, &s_info)) {
2281 fprintf(stderr, "Failed to determine the surface format.\n");
2284 s_info.surface = surf;
2285 s_info.minImageCount = surf_cap.minImageCount;
2287 extent.width = width;
2288 extent.height = height;
2290 if (!sc_select_supported_present_modes(ctx, surf, has_vsync, &s_info)) {
2291 s_info.presentMode = VK_PRESENT_MODE_FIFO_KHR;
2293 s_info.imageExtent = extent;
2294 s_info.imageArrayLayers = 1;
2296 s_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
2297 if (surf_cap.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_SRC_BIT)
2298 s_info.imageUsage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
2299 if (surf_cap.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_DST_BIT)
2300 s_info.imageUsage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
2302 s_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
2303 s_info.queueFamilyIndexCount = ctx->qfam_idx;
2305 /* we might want to use this function when we recreate the swapchain too */
2306 s_info.preTransform = surf_cap.supportedTransforms &
2307 VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR ?
2308 VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR :
2309 surf_cap.currentTransform;
2311 /* we could also write a sc_select_supported_composite_alpha
2312 * later but VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR is universally
2314 s_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
2315 s_info.clipped = VK_TRUE;
2317 if (vkCreateSwapchainKHR(ctx->dev, &s_info, 0,
2318 &swapchain->swapchain) != VK_SUCCESS) {
2319 fprintf(stderr, "Failed to create a swapchain.\n");
2323 if (!swapchain->swapchain) {
2324 fprintf(stderr, "The swapchain seems null\n");
2328 /* get the number of swapchain images and the swapchain images
2329 * and store the new swapchain images
2331 vkGetSwapchainImagesKHR(ctx->dev, swapchain->swapchain,
2332 &swapchain->num_images, 0);
2333 printf("number of swapchain images: %d\n", swapchain->num_images);
2335 /* get the images */
2336 swapchain->images = (VkImage*)alloca(swapchain->num_images * sizeof(VkImage));
2337 vkGetSwapchainImagesKHR(ctx->dev, swapchain->swapchain,
2338 &swapchain->num_images,
2341 /* create attributes from those images */
2342 swapchain->image_fmt = s_info.imageFormat;
2344 vk_fill_image_props(ctx, width, height, 1,
2348 VK_IMAGE_LAYOUT_UNDEFINED,
2349 VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
2351 &swapchain->img_props);
2353 swapchain->img_props.usage = s_info.imageUsage;
2354 swapchain->views = malloc(swapchain->num_images * sizeof(VkImageView));
2356 for (i = 0; i < swapchain->num_images; i++) {
2357 if (!vk_create_image_view(ctx, swapchain->images[i],
2358 VK_IMAGE_VIEW_TYPE_2D,
2359 s_info.imageFormat, true,
2360 &swapchain->views[i])) {
2361 fprintf(stderr, "Failed to create image view for image: %d\n", i);
2369 for (j = 0; j < i; j++) {
2370 vkDestroyImageView(ctx->dev, swapchain->views[j], 0);
2376 vk_destroy_swapchain(struct vk_ctx *ctx,
2377 struct vk_swapchain *swapchain)
2380 for (i = 0; i < swapchain->num_images; i++) {
2381 vkDestroyImageView(ctx->dev, swapchain->views[i], 0);
2383 vkDestroySwapchainKHR(ctx->dev, swapchain->swapchain, 0);
2387 vk_queue_present(struct vk_swapchain *swapchain,
2390 VkSemaphore wait_sema)
2392 VkPresentInfoKHR pinfo;
2394 memset(&pinfo, 0, sizeof pinfo);
2395 pinfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
2396 pinfo.swapchainCount = 1;
2397 pinfo.pSwapchains = &swapchain->swapchain;
2398 pinfo.pImageIndices = &image_idx;
2400 pinfo.pWaitSemaphores = &wait_sema;
2401 pinfo.waitSemaphoreCount = 1;
2403 /* FIXME: add code for VK_KHR_incremental_present_enabled!! */
2405 if (vkQueuePresentKHR(queue, &pinfo) != VK_SUCCESS) {
2406 fprintf(stderr, "Failed to present queue.\n");
2414 vk_copy_image_to_buffer(struct vk_ctx *ctx,
2415 VkCommandBuffer cmd_buf,
2416 struct vk_attachment *src_img,
2417 struct vk_buf *dst_bo,
2420 VkCommandBufferBeginInfo cmd_begin_info;
2421 VkSubmitInfo submit_info;
2422 VkImageAspectFlagBits aspect_mask = get_aspect_from_depth_format(src_img->props.format);
2424 /* VkCommandBufferBeginInfo */
2425 memset(&cmd_begin_info, 0, sizeof cmd_begin_info);
2426 cmd_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
2427 cmd_begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
2429 memset(&submit_info, 0, sizeof submit_info);
2430 submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
2431 submit_info.commandBufferCount = 1;
2432 submit_info.pCommandBuffers = &cmd_buf;
2434 vkBeginCommandBuffer(cmd_buf, &cmd_begin_info);
2435 if (src_img->props.end_layout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL && dst_bo) {
2436 vk_transition_image_layout(src_img,
2438 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
2439 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
2440 VK_QUEUE_FAMILY_EXTERNAL,
2443 /* copy image to buf */
2444 VkBufferImageCopy copy_region = {
2446 .bufferRowLength = w,
2447 .bufferImageHeight = h,
2448 .imageSubresource = {
2449 .aspectMask = aspect_mask ? aspect_mask
2450 : VK_IMAGE_ASPECT_COLOR_BIT,
2452 .baseArrayLayer = 0,
2455 .imageOffset = { 0, 0, 0 },
2456 .imageExtent = { w, h, 1 }
2459 vkCmdCopyImageToBuffer(cmd_buf,
2461 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
2462 dst_bo->buf, 1, ©_region);
2464 vk_transition_image_layout(src_img,
2466 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
2467 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
2468 VK_QUEUE_FAMILY_EXTERNAL,
2471 VkBufferMemoryBarrier write_finish_buffer_memory_barrier = {
2472 .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
2473 .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
2474 .dstAccessMask = VK_ACCESS_HOST_READ_BIT,
2475 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_EXTERNAL,
2476 .dstQueueFamilyIndex = ctx->qfam_idx,
2477 .buffer = dst_bo->buf,
2479 .size = VK_WHOLE_SIZE
2482 vkCmdPipelineBarrier(cmd_buf,
2483 VK_PIPELINE_STAGE_TRANSFER_BIT,
2484 VK_PIPELINE_STAGE_HOST_BIT,
2485 (VkDependencyFlags) 0, 0, NULL,
2486 1, &write_finish_buffer_memory_barrier,
2489 vkEndCommandBuffer(cmd_buf);
2491 if (vkQueueSubmit(ctx->queue, 1, &submit_info, VK_NULL_HANDLE) != VK_SUCCESS) {
2492 fprintf(stderr, "Failed to submit queue.\n");
2494 vkQueueWaitIdle(ctx->queue);
2498 vk_create_semaphores(struct vk_ctx *ctx,
2500 struct vk_semaphores *semaphores)
2502 VkSemaphoreCreateInfo sema_info;
2503 VkExportSemaphoreCreateInfo exp_sema_info;
2506 /* VkExportSemaphoreCreateInfo */
2507 memset(&exp_sema_info, 0, sizeof exp_sema_info);
2508 exp_sema_info.sType = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO;
2509 exp_sema_info.handleTypes = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT;
2512 /* VkSemaphoreCreateInfo */
2513 memset(&sema_info, 0, sizeof sema_info);
2514 sema_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
2515 sema_info.pNext = is_external ? &exp_sema_info : 0;
2517 if (vkCreateSemaphore(ctx->dev, &sema_info, 0, &semaphores->frame_ready) != VK_SUCCESS) {
2518 fprintf(stderr, "Failed to create semaphore frame_ready.\n");
2522 if (vkCreateSemaphore(ctx->dev, &sema_info, 0, &semaphores->frame_done) != VK_SUCCESS) {
2523 fprintf(stderr, "Failed to create semaphore frame_done.\n");
2531 vk_destroy_semaphores(struct vk_ctx *ctx,
2532 struct vk_semaphores *semaphores)
2534 vkDestroySemaphore(ctx->dev, semaphores->frame_ready, 0);
2535 semaphores->frame_ready = VK_NULL_HANDLE;
2537 vkDestroySemaphore(ctx->dev, semaphores->frame_done, 0);
2538 semaphores->frame_done = VK_NULL_HANDLE;
2542 vk_create_fences(struct vk_ctx *ctx,
2544 VkFenceCreateFlagBits flags,
2547 VkFenceCreateInfo f_info;
2550 memset(&f_info, 0, sizeof f_info);
2551 f_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
2552 f_info.flags = flags ? flags : VK_FENCE_CREATE_SIGNALED_BIT;
2555 fences = malloc(num_cmd_buf * sizeof(VkFence));
2556 for (i = 0; i < num_cmd_buf; i++) {
2557 if (vkCreateFence(ctx->dev, &f_info, 0, &fences[i]) != VK_SUCCESS) {
2558 fprintf(stderr, "Failed to create fence number: %d\n", (i + 1));
2565 for (i = 0; i < j; i++) {
2566 vkDestroyFence(ctx->dev, fences[i], 0);
2575 vk_destroy_fences(struct vk_ctx *ctx,
2580 for (i = 0; i < num_fences; i++) {
2581 vkDestroyFence(ctx->dev, fences[i], 0);
2586 vk_transition_image_layout(struct vk_attachment *img_att,
2587 VkCommandBuffer cmd_buf,
2588 VkImageLayout old_layout,
2589 VkImageLayout new_layout,
2590 uint32_t src_queue_fam_idx,
2591 uint32_t dst_queue_fam_idx)
2593 VkImageMemoryBarrier barrier;
2594 struct vk_att_props props = img_att->props;
2595 VkImageAspectFlagBits aspect_mask = get_aspect_from_depth_format(props.format);
2597 memset(&barrier, 0, sizeof barrier);
2598 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
2599 barrier.srcAccessMask = get_access_mask(old_layout);
2600 barrier.dstAccessMask = get_access_mask(new_layout);
2601 barrier.oldLayout = old_layout;
2602 barrier.newLayout = new_layout;
2603 barrier.srcQueueFamilyIndex = src_queue_fam_idx;
2604 barrier.dstQueueFamilyIndex = dst_queue_fam_idx;
2605 barrier.image = img_att->obj.img;
2606 barrier.subresourceRange.aspectMask = aspect_mask ? aspect_mask :
2607 VK_IMAGE_ASPECT_COLOR_BIT;
2608 barrier.subresourceRange.levelCount = 1;
2609 barrier.subresourceRange.layerCount = 1;
2611 vkCmdPipelineBarrier(cmd_buf,
2612 get_pipeline_stage_flags(old_layout),
2613 get_pipeline_stage_flags(new_layout),
2614 0, 0, VK_NULL_HANDLE, 0, VK_NULL_HANDLE, 1, &barrier);