9 static VkViewport viewport;
10 static VkRect2D scissor;
12 /* static functions */
13 static VkSampleCountFlagBits
14 get_num_samples(uint32_t num_samples)
18 return VK_SAMPLE_COUNT_64_BIT;
20 return VK_SAMPLE_COUNT_32_BIT;
22 return VK_SAMPLE_COUNT_16_BIT;
24 return VK_SAMPLE_COUNT_8_BIT;
26 return VK_SAMPLE_COUNT_4_BIT;
28 return VK_SAMPLE_COUNT_2_BIT;
32 fprintf(stderr, "Invalid number of samples in VkSampleCountFlagBits. Using one sample.\n");
35 return VK_SAMPLE_COUNT_1_BIT;
38 static VkAccessFlagBits
39 get_access_mask(const VkImageLayout layout)
41 /* dstAccessMask of barriers must be supported from the pipeline
42 * stage, see also access scopes and this table:
43 * https://www.khronos.org/registry/vulkan/specs/1.2-extensions/html/vkspec.html#synchronization-access-types-supported
46 case VK_IMAGE_LAYOUT_UNDEFINED:
48 case VK_IMAGE_LAYOUT_GENERAL:
49 return VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT;
50 case VK_IMAGE_LAYOUT_PREINITIALIZED:
51 return VK_ACCESS_HOST_WRITE_BIT;
52 case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
53 return VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
54 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
55 case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
56 return VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_INPUT_ATTACHMENT_READ_BIT;
57 case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
58 return VK_ACCESS_TRANSFER_READ_BIT;
59 case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
60 return VK_ACCESS_TRANSFER_WRITE_BIT;
61 case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR:
71 enable_validation_layers(VkInstanceCreateInfo *info)
75 VkLayerProperties *layers;
76 static const char *layer_names[] = {
77 "VK_LAYER_KHRONOS_validation",
80 vkEnumerateInstanceLayerProperties(&num_layers, 0);
81 layers = alloca(num_layers * sizeof *layers);
82 vkEnumerateInstanceLayerProperties(&num_layers, layers);
85 printf("Available validation layers:\n");
86 for(i = 0; i < (int)num_layers; i++) {
87 printf(" %s\n", layers[i].layerName);
90 info->ppEnabledLayerNames = layer_names;
91 info->enabledLayerCount = sizeof layer_names / sizeof *layer_names;
93 fprintf(stderr, "Vulkan validation layers not found.\n");
98 create_instance(bool enable_layers)
100 VkApplicationInfo app_info;
101 VkInstanceCreateInfo inst_info;
104 memset(&app_info, 0, sizeof app_info);
105 app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
106 app_info.pApplicationName = "vktest";
107 app_info.apiVersion = VK_API_VERSION_1_1;
109 memset(&inst_info, 0, sizeof inst_info);
110 inst_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
111 inst_info.pApplicationInfo = &app_info;
114 enable_validation_layers(&inst_info);
116 if (vkCreateInstance(&inst_info, 0, &inst) != VK_SUCCESS)
122 static VkPhysicalDevice
123 select_physical_device(VkInstance inst)
125 VkResult res = VK_SUCCESS;
126 uint32_t dev_count = 0;
127 VkPhysicalDevice *pdevices;
128 VkPhysicalDevice pdevice0;
131 vkEnumeratePhysicalDevices(inst, &dev_count, 0)) != VK_SUCCESS)
134 pdevices = malloc(dev_count * sizeof(VkPhysicalDevice));
135 if (vkEnumeratePhysicalDevices(inst, &dev_count, pdevices) !=
139 pdevice0 = pdevices[0];
146 create_device(struct vk_ctx *ctx, VkPhysicalDevice pdev)
148 /* FIXME: swapchain */
149 const char *deviceExtensions[] = { "VK_KHR_external_memory_fd",
150 "VK_KHR_external_semaphore_fd" };
151 VkDeviceQueueCreateInfo dev_queue_info;
152 VkDeviceCreateInfo dev_info;
155 VkQueueFamilyProperties *fam_props;
160 vkGetPhysicalDeviceQueueFamilyProperties(pdev, &prop_count, 0);
161 if (prop_count < 0) {
162 fprintf(stderr, "Invalid queue family properties.\n");
166 fam_props = malloc(prop_count * sizeof *fam_props);
167 vkGetPhysicalDeviceQueueFamilyProperties(pdev, &prop_count, fam_props);
169 for (i = 0; i < prop_count; i++) {
170 if (fam_props[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
177 memset(&dev_queue_info, 0, sizeof dev_queue_info);
178 dev_queue_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
179 dev_queue_info.queueFamilyIndex = ctx->qfam_idx;
180 dev_queue_info.queueCount = 1;
181 dev_queue_info.pQueuePriorities = &qprio;
183 memset(&dev_info, 0, sizeof dev_info);
184 dev_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
185 dev_info.queueCreateInfoCount = 1;
186 dev_info.pQueueCreateInfos = &dev_queue_info;
187 dev_info.enabledExtensionCount = ARRAY_SIZE(deviceExtensions);
188 dev_info.ppEnabledExtensionNames = deviceExtensions;
190 if (vkCreateDevice(pdev, &dev_info, 0, &dev) != VK_SUCCESS)
197 fill_uuid(VkPhysicalDevice pdev, uint8_t *deviceUUID, uint8_t *driverUUID)
199 VkPhysicalDeviceIDProperties devProp;
200 VkPhysicalDeviceProperties2 prop2;
202 memset(&devProp, 0, sizeof devProp);
203 devProp.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES;
205 memset(&prop2, 0, sizeof prop2);
206 prop2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
207 prop2.pNext = &devProp;
209 vkGetPhysicalDeviceProperties2(pdev, &prop2);
210 memcpy(deviceUUID, devProp.deviceUUID, VK_UUID_SIZE);
211 memcpy(driverUUID, devProp.driverUUID, VK_UUID_SIZE);
215 create_cmd_pool(struct vk_ctx *ctx)
217 VkCommandPoolCreateInfo cmd_pool_info;
218 VkCommandPool cmd_pool;
219 VkDevice dev = ctx->dev;
221 memset(&cmd_pool_info, 0, sizeof cmd_pool_info);
222 cmd_pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
223 cmd_pool_info.queueFamilyIndex = ctx->qfam_idx;
224 cmd_pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
226 if (vkCreateCommandPool(dev, &cmd_pool_info, 0, &cmd_pool) != VK_SUCCESS)
233 create_renderpass(struct vk_ctx *ctx,
234 struct vk_image_props *color_img_props,
235 struct vk_image_props *depth_img_props)
237 uint32_t num_attachments = 2;
238 VkAttachmentDescription att_dsc[2];
239 VkAttachmentReference att_rfc[2];
240 VkSubpassDescription subpass_dsc[1];
241 VkRenderPassCreateInfo rpass_info;
243 /* VkAttachmentDescription */
244 memset(att_dsc, 0, num_attachments * sizeof att_dsc[0]);
246 att_dsc[0].samples = get_num_samples(color_img_props->num_samples);
247 att_dsc[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
248 att_dsc[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
249 att_dsc[0].initialLayout = color_img_props->in_layout;
250 att_dsc[0].finalLayout = color_img_props->end_layout;
251 att_dsc[0].format = color_img_props->format;
252 att_dsc[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
253 att_dsc[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
255 att_dsc[1].samples = get_num_samples(depth_img_props->num_samples);
257 /* We might want to reuse a depth buffer */
258 if (depth_img_props->in_layout != VK_IMAGE_LAYOUT_UNDEFINED) {
259 att_dsc[1].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
260 att_dsc[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
263 att_dsc[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
264 att_dsc[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
267 att_dsc[1].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
268 att_dsc[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
269 att_dsc[1].initialLayout = depth_img_props->in_layout;
270 att_dsc[1].finalLayout = depth_img_props->end_layout;
271 att_dsc[1].format = depth_img_props->format;
273 /* VkAttachmentReference */
274 memset(att_rfc, 0, num_attachments * sizeof att_rfc[0]);
276 att_rfc[0].layout = color_img_props->tiling == VK_IMAGE_TILING_OPTIMAL ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_GENERAL;
277 att_rfc[0].attachment = 0;
279 att_rfc[1].layout = depth_img_props->tiling == VK_IMAGE_TILING_OPTIMAL ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_GENERAL;
280 att_rfc[1].attachment = 1;
282 /* VkSubpassDescription */
283 memset(&subpass_dsc, 0, sizeof subpass_dsc);
284 subpass_dsc[0].pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
285 subpass_dsc[0].colorAttachmentCount = 1;
286 subpass_dsc[0].pColorAttachments = &att_rfc[0];
287 subpass_dsc[0].pDepthStencilAttachment = &att_rfc[1];
289 /* VkRenderPassCreateInfo */
290 memset(&rpass_info, 0, sizeof rpass_info);
291 rpass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
292 rpass_info.attachmentCount = num_attachments;
293 rpass_info.pAttachments = att_dsc;
294 rpass_info.subpassCount = 1;
295 rpass_info.pSubpasses = subpass_dsc;
298 if (vkCreateRenderPass(ctx->dev, &rpass_info, 0, &rpass) != VK_SUCCESS) {
299 fprintf(stderr, "Failed to create renderpass.\n");
300 rpass = VK_NULL_HANDLE;
306 static inline VkImageType
307 get_image_type(uint32_t h, uint32_t d)
310 return VK_IMAGE_TYPE_1D;
313 return VK_IMAGE_TYPE_3D;
315 return VK_IMAGE_TYPE_2D;
318 static VkImageViewType
319 get_image_view_type(struct vk_image_props *props)
321 VkImageType type = get_image_type(props->h, props->depth);
323 case VK_IMAGE_TYPE_1D:
324 return props->num_layers > 1 ?
325 VK_IMAGE_VIEW_TYPE_1D_ARRAY :
326 VK_IMAGE_VIEW_TYPE_1D;
327 case VK_IMAGE_TYPE_2D:
328 if (props->num_layers == 1)
329 return VK_IMAGE_VIEW_TYPE_2D;
330 if (props->num_layers == 6)
331 return VK_IMAGE_VIEW_TYPE_CUBE;
332 if (props->num_layers % 6 == 0)
333 return VK_IMAGE_VIEW_TYPE_CUBE_ARRAY;
334 if (props->num_layers > 1)
335 return VK_IMAGE_VIEW_TYPE_2D_ARRAY;
336 case VK_IMAGE_TYPE_3D:
337 if (props->num_layers == 1)
338 return VK_IMAGE_VIEW_TYPE_3D;
339 if ((props->num_layers == 1) &&
340 (props->num_levels == 1))
341 return VK_IMAGE_VIEW_TYPE_2D;
342 if ((props->num_levels == 1) &&
343 (props->num_layers > 1))
344 return VK_IMAGE_VIEW_TYPE_2D_ARRAY;
346 return VK_IMAGE_VIEW_TYPE_2D;
350 static VkImageAspectFlagBits
351 get_aspect_from_depth_format(VkFormat depth_format)
353 switch (depth_format) {
354 case VK_FORMAT_D16_UNORM:
355 case VK_FORMAT_X8_D24_UNORM_PACK32:
356 case VK_FORMAT_D32_SFLOAT:
357 return VK_IMAGE_ASPECT_DEPTH_BIT;
358 case VK_FORMAT_S8_UINT:
359 return VK_IMAGE_ASPECT_STENCIL_BIT;
360 case VK_FORMAT_D16_UNORM_S8_UINT:
361 case VK_FORMAT_D24_UNORM_S8_UINT:
362 case VK_FORMAT_D32_SFLOAT_S8_UINT:
363 return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
370 static VkPipelineStageFlags
371 get_pipeline_stage_flags(const VkImageLayout layout)
374 case VK_IMAGE_LAYOUT_UNDEFINED:
375 return VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
376 case VK_IMAGE_LAYOUT_GENERAL:
377 return VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
378 case VK_IMAGE_LAYOUT_PREINITIALIZED:
379 return VK_PIPELINE_STAGE_HOST_BIT;
380 case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
381 case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
382 return VK_PIPELINE_STAGE_TRANSFER_BIT;
383 case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
384 return VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
385 case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
386 return VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
387 VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
388 case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR:
389 return VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
397 create_framebuffer(struct vk_ctx *ctx,
398 struct vk_image_att *color_att,
399 struct vk_image_att *depth_att,
400 struct vk_renderer *renderer)
402 VkImageSubresourceRange sr;
403 VkImageViewCreateInfo color_info;
404 VkImageViewCreateInfo depth_info;
405 VkFramebufferCreateInfo fb_info;
407 VkImageViewType view_type = get_image_view_type(&color_att->props);
409 if (!color_att->obj.img || !depth_att->obj.img) {
410 fprintf(stderr, "Invalid framebuffer attachment image.\n");
414 /* create image views */
416 /* VKImageSubresourceRange */
417 memset(&sr, 0, sizeof sr);
418 sr.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
419 /* If an application wants to use all mip levels
420 * or layers in an image after the baseMipLevel
421 * or baseArrayLayer, it can set levelCount and
422 * layerCount to the special values
423 * VK_REMAINING_MIP_LEVELS and
424 * VK_REMAINING_ARRAY_LAYERS without knowing the
425 * exact number of mip levels or layers.
428 sr.levelCount = color_att->props.num_levels;
429 sr.baseArrayLayer = 0;
430 sr.layerCount = color_att->props.num_layers;
433 memset(&color_info, 0, sizeof color_info);
434 color_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
435 color_info.image = color_att->obj.img;
436 color_info.viewType = view_type;
437 color_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
438 color_info.format = color_att->props.format;
439 color_info.subresourceRange = sr;
441 if (vkCreateImageView(ctx->dev, &color_info, 0, &color_att->obj.img_view) != VK_SUCCESS) {
442 fprintf(stderr, "Failed to create color image view for framebuffer.\n");
443 vk_destroy_image(ctx, &color_att->obj);
448 memset(&sr, 0, sizeof sr);
449 sr.aspectMask = get_aspect_from_depth_format(depth_att->props.format);
451 sr.levelCount = depth_att->props.num_levels ? depth_att->props.num_levels : 1;
452 sr.baseArrayLayer = 0;
453 sr.layerCount = depth_att->props.num_layers ? depth_att->props.num_layers : 1;
455 memset(&depth_info, 0, sizeof depth_info);
456 depth_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
457 depth_info.image = depth_att->obj.img;
458 depth_info.viewType = depth_att->props.num_layers > 1 ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D;
459 depth_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
460 depth_info.format = depth_att->props.format;
461 depth_info.subresourceRange = sr;
463 if (vkCreateImageView(ctx->dev, &depth_info, 0, &depth_att->obj.img_view) != VK_SUCCESS) {
465 fprintf(stderr, "Failed to create depth image view for framebuffer.\n");
466 vk_destroy_image(ctx, &depth_att->obj);
470 atts[0] = color_att->obj.img_view;
471 atts[1] = depth_att->obj.img_view;
473 memset(&fb_info, 0, sizeof fb_info);
474 fb_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
475 fb_info.renderPass = renderer->renderpass;
476 fb_info.width = color_att->props.w;
477 fb_info.height = color_att->props.h;
478 fb_info.layers = color_att->props.num_layers ? color_att->props.num_layers : 1;
479 fb_info.attachmentCount = 2;
480 fb_info.pAttachments = atts;
482 if (vkCreateFramebuffer(ctx->dev, &fb_info, 0, &renderer->fb) != VK_SUCCESS)
488 fprintf(stderr, "Failed to create framebuffer.\n");
489 renderer->fb = VK_NULL_HANDLE;
492 static VkShaderModule
493 create_shader_module(struct vk_ctx *ctx,
497 VkShaderModuleCreateInfo sm_info;
500 /* VkShaderModuleCreateInfo */
501 memset(&sm_info, 0, sizeof sm_info);
502 sm_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
503 sm_info.codeSize = size;
504 sm_info.pCode = (void*)src;
506 if (vkCreateShaderModule(ctx->dev, &sm_info, 0, &sm) != VK_SUCCESS) {
507 fprintf(stderr, "Failed to create shader module.\n");
515 create_pipeline(struct vk_ctx *ctx,
518 uint32_t num_samples,
521 struct vk_renderer *renderer)
523 VkVertexInputBindingDescription vert_bind_dsc[1];
524 VkVertexInputAttributeDescription vert_att_dsc[1];
526 VkPipelineColorBlendAttachmentState cb_att_state[1];
527 VkPipelineVertexInputStateCreateInfo vert_input_info;
528 VkPipelineInputAssemblyStateCreateInfo asm_info;
529 VkPipelineViewportStateCreateInfo viewport_info;
530 VkPipelineRasterizationStateCreateInfo rs_info;
531 VkPipelineMultisampleStateCreateInfo ms_info;
532 VkPipelineDepthStencilStateCreateInfo ds_info;
533 VkPipelineColorBlendStateCreateInfo cb_info;
534 VkPipelineShaderStageCreateInfo sdr_stages[2];
535 VkPipelineLayoutCreateInfo layout_info;
536 VkGraphicsPipelineCreateInfo pipeline_info;
538 VkFormatProperties fmt_props;
539 VkPushConstantRange pc_range[1];
541 VkStencilOpState front;
542 VkStencilOpState back;
544 VkPipelineLayout pipeline_layout;
547 /* format of vertex attributes:
548 * we have 2D vectors so we need a RG format:
550 * the stride (distance between 2 consecutive elements)
551 * must be 8 because we use 32 bit floats and
553 format = VK_FORMAT_R32G32_SFLOAT;
554 vkGetPhysicalDeviceFormatProperties(ctx->pdev, format, &fmt_props);
555 assert(fmt_props.bufferFeatures & VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT);
558 /* VkVertexInputAttributeDescription */
559 memset(&vert_att_dsc, 0, sizeof vert_att_dsc);
560 vert_att_dsc[0].location = 0;
561 vert_att_dsc[0].binding = 0;
562 vert_att_dsc[0].format = format; /* see comment */
563 vert_att_dsc[0].offset = 0;
565 /* VkVertexInputBindingDescription */
566 memset(&vert_bind_dsc, 0, sizeof vert_bind_dsc);
567 vert_bind_dsc[0].binding = 0;
568 vert_bind_dsc[0].stride = stride;
569 vert_bind_dsc[0].inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
571 /* If using vbo, we have setup vertex_info in the renderer. */
572 bool use_vbo = renderer->vertex_info.num_verts > 0;
574 /* VkPipelineVertexInputStateCreateInfo */
575 memset(&vert_input_info, 0, sizeof vert_input_info);
576 vert_input_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
577 vert_input_info.vertexBindingDescriptionCount = use_vbo ? 1 : 0;
578 vert_input_info.pVertexBindingDescriptions = vert_bind_dsc;
579 vert_input_info.vertexAttributeDescriptionCount = use_vbo ? 1 : 0;
580 vert_input_info.pVertexAttributeDescriptions = vert_att_dsc;
582 /* VkPipelineInputAssemblyStateCreateInfo */
583 memset(&asm_info, 0, sizeof asm_info);
584 asm_info.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
585 asm_info.topology = renderer->vertex_info.topology ?
586 renderer->vertex_info.topology
587 : VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
588 asm_info.primitiveRestartEnable = false;
591 viewport.x = viewport.y = 0;
592 viewport.width = width;
593 viewport.height = height;
594 viewport.minDepth = 0;
595 viewport.maxDepth = 1;
597 /* VkRect2D scissor */
598 scissor.offset.x = scissor.offset.y = 0;
599 scissor.extent.width = width;
600 scissor.extent.height = height;
602 /* VkPipelineViewportStateCreateInfo */
603 memset(&viewport_info, 0, sizeof viewport_info);
604 viewport_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
605 viewport_info.viewportCount = 1;
606 viewport_info.pViewports = &viewport;
607 viewport_info.scissorCount = 1;
608 viewport_info.pScissors = &scissor;
610 /* VkPipelineRasterizationStateCreateInfo */
611 memset(&rs_info, 0, sizeof rs_info);
612 rs_info.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
613 rs_info.polygonMode = VK_POLYGON_MODE_FILL;
614 rs_info.cullMode = VK_CULL_MODE_NONE;
615 rs_info.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
616 rs_info.lineWidth = 1.0;
618 /* VkPipelineMultisampleStateCreateInfo */
619 memset(&ms_info, 0, sizeof ms_info);
620 ms_info.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
621 ms_info.rasterizationSamples = num_samples;
623 /* VkStencilOpState */
624 /* The default values for ES are taken by Topi Pohjolainen's code */
625 /* defaults in OpenGL ES 3.1 */
626 memset(&front, 0, sizeof front);
627 front.compareMask = ~0;
628 front.writeMask = ~0;
631 memset(&back, 0, sizeof back);
632 back.compareMask = ~0;
636 /* VkPipelineDepthStencilStateCreateInfo */
637 memset(&ds_info, 0, sizeof ds_info);
638 ds_info.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
639 ds_info.front = front;
641 /* defaults in OpenGL ES 3.1 */
642 ds_info.minDepthBounds = 0;
643 ds_info.maxDepthBounds = 1;
644 /* z buffer, stencil buffer */
646 ds_info.depthTestEnable = VK_TRUE;
647 ds_info.depthWriteEnable = VK_TRUE;
648 ds_info.depthCompareOp = VK_COMPARE_OP_LESS;
650 if (enable_stencil) {
651 ds_info.stencilTestEnable = VK_TRUE;
652 ds_info.depthTestEnable = VK_FALSE;
653 ds_info.depthWriteEnable = VK_TRUE;
656 /* we only care about the passOp here */
657 ds_info.back.compareOp = VK_COMPARE_OP_ALWAYS;
658 ds_info.back.failOp = VK_STENCIL_OP_REPLACE;
659 ds_info.back.depthFailOp = VK_STENCIL_OP_REPLACE;
660 ds_info.back.passOp = VK_STENCIL_OP_REPLACE;
661 ds_info.back.compareMask = 0xffffffff;
662 ds_info.back.writeMask = 0xffffffff;
663 ds_info.back.reference = 1;
664 ds_info.front = ds_info.back;
666 /* VkPipelineColorBlendAttachmentState */
667 memset(&cb_att_state[0], 0, sizeof cb_att_state[0]);
668 cb_att_state[0].colorWriteMask = (VK_COLOR_COMPONENT_R_BIT |
669 VK_COLOR_COMPONENT_G_BIT |
670 VK_COLOR_COMPONENT_B_BIT |
671 VK_COLOR_COMPONENT_A_BIT);
673 /* VkPipelineColorBlendStateCreateInfo */
674 memset(&cb_info, 0, sizeof cb_info);
675 cb_info.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
676 cb_info.attachmentCount = 1;
677 cb_info.pAttachments = cb_att_state;
678 /* default in ES 3.1 */
679 for (i = 0; i < 4; i++) {
680 cb_info.blendConstants[i] = 0.0f;
683 /* VkPipelineShaderStageCreateInfo */
684 memset(sdr_stages, 0, 2 * sizeof sdr_stages[0]);
686 sdr_stages[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
687 sdr_stages[0].stage = VK_SHADER_STAGE_VERTEX_BIT;
688 sdr_stages[0].module = renderer->vs;
689 sdr_stages[0].pName = "main";
691 sdr_stages[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
692 sdr_stages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT;
693 sdr_stages[1].module = renderer->fs;
694 sdr_stages[1].pName = "main";
696 /* VkPushConstantRange */
697 memset(pc_range, 0, sizeof pc_range[0]);
698 pc_range[0].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
699 pc_range[0].size = sizeof (struct vk_dims); /* w, h */
701 /* VkPipelineLayoutCreateInfo */
702 memset(&layout_info, 0, sizeof layout_info);
703 layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
704 layout_info.pushConstantRangeCount = 1;
705 layout_info.pPushConstantRanges = pc_range;
707 if (vkCreatePipelineLayout(ctx->dev, &layout_info, 0, &pipeline_layout) != VK_SUCCESS) {
708 fprintf(stderr, "Failed to create pipeline layout\n");
709 renderer->pipeline = VK_NULL_HANDLE;
713 renderer->pipeline_layout = pipeline_layout;
715 /* VkGraphicsPipelineCreateInfo */
716 memset(&pipeline_info, 0, sizeof pipeline_info);
717 pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
718 pipeline_info.layout = pipeline_layout;
719 pipeline_info.renderPass = renderer->renderpass;
720 pipeline_info.pVertexInputState = &vert_input_info;
721 pipeline_info.pInputAssemblyState = &asm_info;
722 pipeline_info.pViewportState = &viewport_info;
723 pipeline_info.pRasterizationState = &rs_info;
724 pipeline_info.pMultisampleState = &ms_info;
725 pipeline_info.pDepthStencilState = &ds_info;
726 pipeline_info.pColorBlendState = &cb_info;
727 pipeline_info.stageCount = 2;
728 pipeline_info.pStages = sdr_stages;
730 if (vkCreateGraphicsPipelines(ctx->dev, 0, 1,
732 &renderer->pipeline) != VK_SUCCESS) {
733 fprintf(stderr, "Failed to create graphics pipeline.\n");
734 renderer->pipeline = VK_NULL_HANDLE;
738 static VkCommandBuffer
739 create_cmd_buf(VkDevice dev, VkCommandPool cmd_pool)
741 VkCommandBuffer cmd_buf;
742 VkCommandBufferAllocateInfo alloc_info;
744 memset(&alloc_info, 0, sizeof alloc_info);
745 alloc_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
746 alloc_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
747 alloc_info.commandBufferCount = 1;
748 alloc_info.commandPool = cmd_pool;
750 if (vkAllocateCommandBuffers(dev, &alloc_info, &cmd_buf) != VK_SUCCESS)
757 get_memory_type_idx(VkPhysicalDevice pdev,
758 const VkMemoryRequirements *mem_reqs,
759 VkMemoryPropertyFlagBits prop_flags)
761 VkPhysicalDeviceMemoryProperties pdev_mem_props;
764 vkGetPhysicalDeviceMemoryProperties(pdev, &pdev_mem_props);
766 for (i = 0; i < pdev_mem_props.memoryTypeCount; i++) {
767 const VkMemoryType *type = &pdev_mem_props.memoryTypes[i];
769 if ((mem_reqs->memoryTypeBits & (1 << i)) &&
770 (type->propertyFlags & prop_flags) == prop_flags) {
778 static VkDeviceMemory
779 alloc_memory(struct vk_ctx *ctx,
781 const VkMemoryRequirements *mem_reqs,
784 VkMemoryPropertyFlagBits prop_flags)
786 VkExportMemoryAllocateInfo exp_mem_info;
787 VkMemoryAllocateInfo mem_alloc_info;
789 VkMemoryDedicatedAllocateInfoKHR ded_info;
792 memset(&exp_mem_info, 0, sizeof exp_mem_info);
793 exp_mem_info.sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO;
794 exp_mem_info.handleTypes =
795 VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
798 memset(&mem_alloc_info, 0, sizeof mem_alloc_info);
799 mem_alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
800 mem_alloc_info.pNext = &exp_mem_info;
801 mem_alloc_info.allocationSize = mem_reqs->size;
802 mem_alloc_info.memoryTypeIndex =
803 get_memory_type_idx(ctx->pdev, mem_reqs, prop_flags);
805 if (mem_alloc_info.memoryTypeIndex == UINT32_MAX) {
806 fprintf(stderr, "No suitable memory type index found.\n");
810 if (image || buffer) {
811 memset(&ded_info, 0, sizeof ded_info);
812 ded_info.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO;
813 ded_info.image = image;
814 ded_info.buffer = buffer;
816 exp_mem_info.pNext = &ded_info;
819 if (vkAllocateMemory(ctx->dev, &mem_alloc_info, 0, &mem) !=
827 alloc_image_memory(struct vk_ctx *ctx, struct vk_image_obj *img_obj)
829 VkMemoryDedicatedRequirements ded_reqs;
830 VkImageMemoryRequirementsInfo2 req_info2;
831 VkMemoryRequirements2 mem_reqs2;
833 memset(&ded_reqs, 0, sizeof ded_reqs);
834 ded_reqs.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS;
836 /* VkImageMemoryRequirementsInfo2 */
837 memset(&req_info2, 0, sizeof req_info2);
838 req_info2.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2;
839 req_info2.image = img_obj->img;
841 /* VkMemoryRequirements2 */
842 memset(&mem_reqs2, 0, sizeof mem_reqs2);
843 mem_reqs2.sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2;
844 mem_reqs2.pNext = &ded_reqs;
846 vkGetImageMemoryRequirements2(ctx->dev, &req_info2, &mem_reqs2);
847 img_obj->mobj.mem = alloc_memory(ctx,
848 true, /* is_external = FIXME */
849 &mem_reqs2.memoryRequirements,
850 ded_reqs.requiresDedicatedAllocation ?
851 img_obj->img : VK_NULL_HANDLE,
853 mem_reqs2.memoryRequirements.memoryTypeBits &
854 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
856 img_obj->mobj.mem_sz = mem_reqs2.memoryRequirements.size;
857 img_obj->mobj.dedicated = ded_reqs.requiresDedicatedAllocation;
858 if (img_obj->mobj.mem == VK_NULL_HANDLE) {
859 fprintf(stderr, "Failed to allocate image memory.\n");
863 if (vkBindImageMemory(ctx->dev, img_obj->img, img_obj->mobj.mem, 0) !=
865 fprintf(stderr, "Failed to bind image memory.\n");
873 are_props_supported(struct vk_ctx *ctx, struct vk_image_props *props)
875 VkPhysicalDeviceExternalImageFormatInfo ext_img_fmt_info;
876 VkExternalImageFormatProperties ext_img_fmt_props;
879 VkPhysicalDeviceImageFormatInfo2 img_fmt_info;
880 VkImageFormatProperties2 img_fmt_props;
881 VkImageUsageFlagBits all_flags[] = {
882 VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
883 VK_IMAGE_USAGE_TRANSFER_DST_BIT,
884 VK_IMAGE_USAGE_SAMPLED_BIT,
885 VK_IMAGE_USAGE_STORAGE_BIT,
886 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
887 VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
888 VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT,
889 /* Shouldn't be used together with COLOR, DEPTH_STENCIL
891 * VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT,
892 * Provided by VK_EXT_fragment_density_map
893 * VK_IMAGE_USAGE_FRAGMENT_DENSITY_MAP_BIT_EXT,
894 * Provided by VK_NV_shading_rate_image
895 * VK_IMAGE_USAGE_SHADING_RATE_IMAGE_BIT_NV,
896 * Provided by VK_KHR_fragment_shading_rate
897 * VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR,
900 VkImageUsageFlagBits flags = 0;
902 VkExternalMemoryFeatureFlagBits export_feature_flags =
903 VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT;
904 VkExternalMemoryHandleTypeFlagBits handle_type =
905 VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;
907 memset(&ext_img_fmt_info, 0, sizeof ext_img_fmt_info);
908 ext_img_fmt_info.sType =
909 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO;
910 ext_img_fmt_info.handleType = handle_type;
912 memset(&ext_img_fmt_props, 0, sizeof ext_img_fmt_props);
913 ext_img_fmt_props.sType =
914 VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES;
916 memset(&img_fmt_props, 0, sizeof img_fmt_props);
917 img_fmt_props.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2;
918 img_fmt_props.pNext = &ext_img_fmt_props;
920 memset(&img_fmt_info, 0, sizeof img_fmt_info);
922 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2;
923 img_fmt_info.pNext = &ext_img_fmt_info;
924 img_fmt_info.format = props->format;
925 img_fmt_info.type = get_image_type(props->h, props->depth);
926 img_fmt_info.tiling = props->tiling;
928 for (i = 0; i < ARRAY_SIZE(all_flags); i++) {
929 img_fmt_info.usage = all_flags[i];
930 if (vkGetPhysicalDeviceImageFormatProperties2(ctx->pdev,
932 &img_fmt_props) == VK_SUCCESS) {
933 flags |= all_flags[i];
937 /* usage can't be null */
939 img_fmt_info.usage = flags;
942 fprintf(stderr, "Unsupported Vulkan format properties: usage.\n");
946 if (vkGetPhysicalDeviceImageFormatProperties2
947 (ctx->pdev, &img_fmt_info, &img_fmt_props) != VK_SUCCESS) {
949 "Unsupported Vulkan format properties.\n");
952 props->usage = flags;
954 if (props->need_export &&
955 !(ext_img_fmt_props.externalMemoryProperties.externalMemoryFeatures
956 & export_feature_flags)) {
957 fprintf(stderr, "Unsupported Vulkan external memory features.\n");
964 /* exposed Vulkan functions */
967 vk_init_ctx(struct vk_ctx *ctx)
969 if ((ctx->inst = create_instance(false)) == VK_NULL_HANDLE) {
970 fprintf(stderr, "Failed to create Vulkan instance.\n");
974 if ((ctx->pdev = select_physical_device(ctx->inst)) == VK_NULL_HANDLE) {
975 fprintf(stderr, "Failed to find suitable physical device.\n");
979 if ((ctx->dev = create_device(ctx, ctx->pdev)) == VK_NULL_HANDLE) {
980 fprintf(stderr, "Failed to create Vulkan device.\n");
984 fill_uuid(ctx->pdev, ctx->deviceUUID, ctx->driverUUID);
993 vk_init_ctx_for_rendering(struct vk_ctx *ctx)
995 if (!vk_init_ctx(ctx)) {
996 fprintf(stderr, "Failed to initialize Vulkan.\n");
1000 if ((ctx->cmd_pool = create_cmd_pool(ctx)) == VK_NULL_HANDLE) {
1001 fprintf(stderr, "Failed to create command pool.\n");
1005 if ((ctx->cmd_buf = create_cmd_buf(ctx->dev, ctx->cmd_pool)) ==
1007 fprintf(stderr, "Failed to create command buffer.\n");
1011 vkGetDeviceQueue(ctx->dev, ctx->qfam_idx, 0, &ctx->queue);
1013 fprintf(stderr, "Failed to get command queue.\n");
1020 vk_cleanup_ctx(ctx);
1025 vk_cleanup_ctx(struct vk_ctx *ctx)
1027 if (ctx->cmd_buf != VK_NULL_HANDLE) {
1028 vkResetCommandBuffer(ctx->cmd_buf,
1029 VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT);
1030 vkFreeCommandBuffers(ctx->dev, ctx->cmd_pool, 1, &ctx->cmd_buf);
1031 ctx->cmd_buf = VK_NULL_HANDLE;
1034 if (ctx->cmd_pool != VK_NULL_HANDLE) {
1035 vkResetCommandPool(ctx->dev, ctx->cmd_pool,
1036 VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT);
1037 vkDestroyCommandPool(ctx->dev, ctx->cmd_pool, 0);
1038 ctx->cmd_pool = VK_NULL_HANDLE;
1041 if (ctx->dev != VK_NULL_HANDLE) {
1042 vkDestroyDevice(ctx->dev, 0);
1043 ctx->dev = VK_NULL_HANDLE;
1046 if (ctx->inst != VK_NULL_HANDLE) {
1047 vkDestroyInstance(ctx->inst, 0);
1048 ctx->inst = VK_NULL_HANDLE;
1053 vk_create_image(struct vk_ctx *ctx,
1054 struct vk_image_props *props,
1055 struct vk_image_obj *img)
1057 VkImageCreateInfo img_info;
1059 memset(&img_info, 0, sizeof img_info);
1060 img_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
1061 img_info.pNext = 0; /* do something if external */
1062 img_info.imageType = get_image_type(props->h, props->depth);
1063 img_info.format = props->format;
1064 img_info.extent.width = props->w;
1065 img_info.extent.height = props->h;
1066 img_info.extent.depth = props->depth;
1067 img_info.mipLevels = props->num_levels ? props->num_levels : 1;
1068 img_info.arrayLayers = props->num_layers ?
1069 props->num_layers : VK_SAMPLE_COUNT_1_BIT;
1070 img_info.samples = get_num_samples(props->num_samples);
1071 img_info.tiling = props->tiling;
1072 img_info.usage = props->usage ?
1073 props->usage : VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
1074 img_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
1075 img_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
1077 if (vkCreateImage(ctx->dev, &img_info, 0, &img->img) != VK_SUCCESS)
1080 if(!alloc_image_memory(ctx, img))
1086 fprintf(stderr, "Failed to create external image.\n");
1087 vk_destroy_image(ctx, img);
1088 img->img = VK_NULL_HANDLE;
1089 img->mobj.mem = VK_NULL_HANDLE;
1094 vk_destroy_image(struct vk_ctx *ctx, struct vk_image_obj *img_obj)
1096 if (img_obj->img != VK_NULL_HANDLE) {
1097 vkDestroyImage(ctx->dev, img_obj->img, 0);
1098 img_obj->img = VK_NULL_HANDLE;
1101 if (img_obj->mobj.mem != VK_NULL_HANDLE) {
1102 vkFreeMemory(ctx->dev, img_obj->mobj.mem, 0);
1103 img_obj->mobj.mem = VK_NULL_HANDLE;
1108 vk_create_ext_image(struct vk_ctx *ctx,
1109 struct vk_image_props *props, struct vk_image_obj *img)
1111 VkExternalMemoryImageCreateInfo ext_img_info;
1112 VkImageCreateInfo img_info;
1114 memset(&ext_img_info, 0, sizeof ext_img_info);
1115 ext_img_info.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO;
1116 ext_img_info.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;
1118 memset(&img_info, 0, sizeof img_info);
1119 img_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
1120 img_info.pNext = &ext_img_info;
1121 img_info.imageType = get_image_type(props->h, props->depth);
1122 img_info.format = props->format;
1123 img_info.extent.width = props->w;
1124 img_info.extent.height = props->h;
1125 img_info.extent.depth = props->depth;
1126 img_info.mipLevels = props->num_levels ? props->num_levels : 1;
1127 img_info.arrayLayers = props->num_layers ? props->num_layers : VK_SAMPLE_COUNT_1_BIT;
1128 img_info.samples = get_num_samples(props->num_samples);
1129 img_info.tiling = props->tiling;
1130 img_info.usage = props->usage;
1131 img_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
1132 img_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
1133 /* issue 17 of EXT_external_objects
1134 * Required in OpenGL implementations that support
1135 * ARB_texture_view, OES_texture_view, EXT_texture_view,
1136 * or OpenGL 4.3 and above.
1138 img_info.flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
1140 if (vkCreateImage(ctx->dev, &img_info, 0, &img->img) != VK_SUCCESS)
1143 if(!alloc_image_memory(ctx, img))
1149 fprintf(stderr, "Failed to create external image.\n");
1150 vk_destroy_image(ctx, img);
1151 img->img = VK_NULL_HANDLE;
1152 img->mobj.mem = VK_NULL_HANDLE;
1157 vk_fill_ext_image_props(struct vk_ctx *ctx,
1161 uint32_t num_samples,
1162 uint32_t num_levels,
1163 uint32_t num_layers,
1165 VkImageTiling tiling,
1166 VkImageLayout in_layout,
1167 VkImageLayout end_layout,
1169 struct vk_image_props *props)
1175 props->num_samples = num_samples;
1176 props->num_levels = num_levels;
1177 props->num_layers = num_layers;
1179 props->format = format;
1180 props->tiling = tiling;
1182 props->in_layout = in_layout;
1183 props->end_layout = end_layout;
1184 props->need_export = need_export;
1186 if (!are_props_supported(ctx, props))
1193 vk_create_renderer(struct vk_ctx *ctx,
1195 unsigned int vs_size,
1197 unsigned int fs_size,
1199 bool enable_stencil,
1200 struct vk_image_att *color_att,
1201 struct vk_image_att *depth_att,
1202 struct vk_vertex_info *vert_info,
1203 struct vk_renderer *renderer)
1205 memset(&renderer->vertex_info, 0, sizeof renderer->vertex_info);
1207 renderer->vertex_info = *vert_info;
1209 renderer->renderpass = create_renderpass(ctx, &color_att->props,
1211 if (renderer->renderpass == VK_NULL_HANDLE)
1214 create_framebuffer(ctx, color_att, depth_att, renderer);
1215 if (renderer->fb == VK_NULL_HANDLE)
1218 renderer->vs = create_shader_module(ctx, vs_src, vs_size);
1219 if (renderer->vs == VK_NULL_HANDLE)
1222 renderer->fs = create_shader_module(ctx, fs_src, fs_size);
1223 if (renderer->fs == VK_NULL_HANDLE)
1226 create_pipeline(ctx, color_att->props.w, color_att->props.h,
1227 color_att->props.num_samples, enable_depth,
1228 enable_stencil, renderer);
1230 if (renderer->pipeline == VK_NULL_HANDLE)
1236 fprintf(stderr, "Failed to create graphics pipeline.\n");
1237 vk_destroy_renderer(ctx, renderer);
1242 vk_destroy_renderer(struct vk_ctx *ctx,
1243 struct vk_renderer *renderer)
1245 if (renderer->renderpass != VK_NULL_HANDLE) {
1246 vkDestroyRenderPass(ctx->dev, renderer->renderpass, 0);
1247 renderer->renderpass = VK_NULL_HANDLE;
1250 if (renderer->vs != VK_NULL_HANDLE) {
1251 vkDestroyShaderModule(ctx->dev, renderer->vs, 0);
1252 renderer->vs = VK_NULL_HANDLE;
1255 if (renderer->fs != VK_NULL_HANDLE) {
1256 vkDestroyShaderModule(ctx->dev, renderer->fs, 0);
1257 renderer->fs = VK_NULL_HANDLE;
1260 if (renderer->fb != VK_NULL_HANDLE) {
1261 vkDestroyFramebuffer(ctx->dev, renderer->fb, 0);
1262 renderer->fb = VK_NULL_HANDLE;
1265 if (renderer->pipeline != VK_NULL_HANDLE) {
1266 vkDestroyPipeline(ctx->dev, renderer->pipeline, 0);
1267 renderer->pipeline = VK_NULL_HANDLE;
1270 if (renderer->pipeline_layout != VK_NULL_HANDLE) {
1271 vkDestroyPipelineLayout(ctx->dev, renderer->pipeline_layout, 0);
1272 renderer->pipeline_layout = VK_NULL_HANDLE;
1277 vk_create_ext_buffer(struct vk_ctx *ctx,
1279 VkBufferUsageFlagBits usage,
1282 VkExternalMemoryBufferCreateInfo ext_bo_info;
1284 memset(&ext_bo_info, 0, sizeof ext_bo_info);
1285 ext_bo_info.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO;
1286 ext_bo_info.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;
1288 if (!vk_create_buffer(ctx, true, sz, usage, &ext_bo_info, bo)) {
1289 fprintf(stderr, "Failed to allocate external buffer.\n");
1297 vk_create_buffer(struct vk_ctx *ctx,
1300 VkBufferUsageFlagBits usage,
1304 VkBufferCreateInfo buf_info;
1305 VkMemoryRequirements mem_reqs;
1307 bo->mobj.mem = VK_NULL_HANDLE;
1308 bo->buf = VK_NULL_HANDLE;
1310 /* VkBufferCreateInfo */
1311 memset(&buf_info, 0, sizeof buf_info);
1312 buf_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
1314 buf_info.usage = usage;
1315 buf_info.pNext = pnext;
1316 buf_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
1318 if (vkCreateBuffer(ctx->dev, &buf_info, 0, &bo->buf) != VK_SUCCESS)
1321 /* allocate buffer */
1322 vkGetBufferMemoryRequirements(ctx->dev, bo->buf, &mem_reqs);
1323 /* VK_MEMORY_PROPERTY_HOST_COHERENT_BIT bit specifies that the
1324 * host cache management commands vkFlushMappedMemoryRanges and
1325 * vkInvalidateMappedMemoryRanges are not needed to flush host
1326 * writes to the device or make device writes visible to the
1327 * host, respectively. */
1328 bo->mobj.mem = alloc_memory(ctx, is_external, &mem_reqs, VK_NULL_HANDLE,
1330 VK_MEMORY_PROPERTY_HOST_COHERENT_BIT |
1331 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
1333 if (bo->mobj.mem == VK_NULL_HANDLE)
1336 bo->mobj.mem_sz = sz;
1338 if (vkBindBufferMemory(ctx->dev, bo->buf, bo->mobj.mem, 0) != VK_SUCCESS) {
1339 fprintf(stderr, "Failed to bind buffer memory.\n");
1346 fprintf(stderr, "Failed to allocate buffer.\n");
1347 vk_destroy_buffer(ctx, bo);
1352 vk_update_buffer_data(struct vk_ctx *ctx,
1359 if (vkMapMemory(ctx->dev, bo->mobj.mem, 0, data_sz, 0, &map) != VK_SUCCESS) {
1360 fprintf(stderr, "Failed to map buffer memory.\n");
1364 memcpy(map, data, data_sz);
1366 vkUnmapMemory(ctx->dev, bo->mobj.mem);
1370 fprintf(stderr, "Failed to update buffer data. Destroying the buffer.\n");
1371 vk_destroy_buffer(ctx, bo);
1377 vk_destroy_buffer(struct vk_ctx *ctx,
1380 if (bo->buf != VK_NULL_HANDLE)
1381 vkDestroyBuffer(ctx->dev, bo->buf, 0);
1383 if (bo->mobj.mem != VK_NULL_HANDLE)
1384 vkFreeMemory(ctx->dev, bo->mobj.mem, 0);
1386 bo->mobj.mem_sz = 0;
1387 bo->buf = VK_NULL_HANDLE;
1388 bo->mobj.mem = VK_NULL_HANDLE;
1392 vk_draw(struct vk_ctx *ctx,
1394 struct vk_renderer *renderer,
1396 uint32_t vk_fb_color_count,
1397 struct vk_semaphores *semaphores,
1398 struct vk_image_att *attachments,
1399 uint32_t n_attachments,
1403 VkCommandBufferBeginInfo cmd_begin_info;
1404 VkRenderPassBeginInfo rp_begin_info;
1406 VkClearValue clear_values[2];
1407 VkSubmitInfo submit_info;
1408 VkDeviceSize offsets[] = {0};
1409 VkPipelineStageFlagBits stage_flags;
1410 struct vk_dims img_size;
1412 assert(vk_fb_color_count == 4);
1414 /* VkCommandBufferBeginInfo */
1415 memset(&cmd_begin_info, 0, sizeof cmd_begin_info);
1416 cmd_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
1417 cmd_begin_info.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT;
1419 /* VkRect2D render area */
1420 memset(&rp_area, 0, sizeof rp_area);
1421 rp_area.extent.width = (uint32_t)w;
1422 rp_area.extent.height = (uint32_t)h;
1423 rp_area.offset.x = x;
1424 rp_area.offset.y = y;
1427 memset(&clear_values[0], 0, sizeof clear_values[0]);
1428 clear_values[0].color.float32[0] = vk_fb_color[0]; /* red */
1429 clear_values[0].color.float32[1] = vk_fb_color[1]; /* green */
1430 clear_values[0].color.float32[2] = vk_fb_color[2]; /* blue */
1431 clear_values[0].color.float32[3] = vk_fb_color[3]; /* alpha */
1433 memset(&clear_values[1], 0, sizeof clear_values[1]);
1434 clear_values[1].depthStencil.depth = 1.0;
1435 clear_values[1].depthStencil.stencil = 0;
1437 /* VkRenderPassBeginInfo */
1438 memset(&rp_begin_info, 0, sizeof rp_begin_info);
1439 rp_begin_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
1440 rp_begin_info.renderPass = renderer->renderpass;
1441 rp_begin_info.framebuffer = renderer->fb;
1442 rp_begin_info.renderArea = rp_area;
1443 rp_begin_info.clearValueCount = 2;
1444 rp_begin_info.pClearValues = clear_values;
1447 stage_flags = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT;
1449 memset(&submit_info, 0, sizeof submit_info);
1450 submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
1451 submit_info.commandBufferCount = 1;
1452 submit_info.pCommandBuffers = &ctx->cmd_buf;
1456 assert(semaphores->frame_ready);
1457 assert(semaphores->frame_done);
1459 submit_info.pWaitDstStageMask = &stage_flags;
1460 submit_info.waitSemaphoreCount = 1;
1461 submit_info.pWaitSemaphores = &semaphores->frame_done;
1463 submit_info.signalSemaphoreCount = 1;
1464 submit_info.pSignalSemaphores = &semaphores->frame_ready;
1467 vkBeginCommandBuffer(ctx->cmd_buf, &cmd_begin_info);
1468 vkCmdBeginRenderPass(ctx->cmd_buf, &rp_begin_info, VK_SUBPASS_CONTENTS_INLINE);
1473 viewport.height = h;
1475 scissor.offset.x = x;
1476 scissor.offset.y = y;
1477 scissor.extent.width = w;
1478 scissor.extent.height = h;
1480 vkCmdSetViewport(ctx->cmd_buf, 0, 1, &viewport);
1481 vkCmdSetScissor(ctx->cmd_buf, 0, 1, &scissor);
1483 img_size.w = (float)w;
1484 img_size.h = (float)h;
1485 vkCmdPushConstants(ctx->cmd_buf,
1486 renderer->pipeline_layout,
1487 VK_SHADER_STAGE_FRAGMENT_BIT,
1488 0, sizeof (struct vk_dims),
1492 vkCmdBindVertexBuffers(ctx->cmd_buf, 0, 1, &vbo->buf, offsets);
1494 vkCmdBindPipeline(ctx->cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS, renderer->pipeline);
1496 int num_vertices = vbo ? renderer->vertex_info.num_verts : 4;
1497 vkCmdDraw(ctx->cmd_buf, num_vertices, 1, 0, 0);
1498 vkCmdEndRenderPass(ctx->cmd_buf);
1500 VkImageMemoryBarrier *barriers =
1501 calloc(n_attachments, sizeof(VkImageMemoryBarrier));
1502 VkImageMemoryBarrier *barrier = barriers;
1503 for (uint32_t n = 0; n < n_attachments; n++, barrier++) {
1504 struct vk_image_att *att = &attachments[n];
1505 VkImageAspectFlagBits depth_stencil_flags =
1506 get_aspect_from_depth_format(att->props.format);
1507 bool is_depth = (depth_stencil_flags != 0);
1509 /* Insert barrier to mark ownership transfer. */
1510 barrier->sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
1511 barrier->oldLayout = is_depth ?
1512 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL :
1513 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
1514 barrier->newLayout = VK_IMAGE_LAYOUT_GENERAL;
1515 barrier->srcAccessMask = get_access_mask(barrier->oldLayout);
1516 barrier->dstAccessMask = get_access_mask(barrier->newLayout);
1517 barrier->srcQueueFamilyIndex = ctx->qfam_idx;
1518 barrier->dstQueueFamilyIndex = VK_QUEUE_FAMILY_EXTERNAL;
1519 barrier->image = att->obj.img;
1520 barrier->subresourceRange.aspectMask = is_depth ?
1521 depth_stencil_flags :
1522 VK_IMAGE_ASPECT_COLOR_BIT;
1523 barrier->subresourceRange.baseMipLevel = 0;
1524 barrier->subresourceRange.levelCount = 1;
1525 barrier->subresourceRange.baseArrayLayer = 0;
1526 barrier->subresourceRange.layerCount = 1;
1529 vkCmdPipelineBarrier(ctx->cmd_buf,
1530 VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
1531 VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
1535 n_attachments, barriers);
1539 vkEndCommandBuffer(ctx->cmd_buf);
1541 if (vkQueueSubmit(ctx->queue, 1, &submit_info, VK_NULL_HANDLE) != VK_SUCCESS) {
1542 fprintf(stderr, "Failed to submit queue.\n");
1546 vkQueueWaitIdle(ctx->queue);
1550 vk_clear_color(struct vk_ctx *ctx,
1552 struct vk_renderer *renderer,
1554 uint32_t vk_fb_color_count,
1555 struct vk_semaphores *semaphores,
1556 bool has_wait, bool has_signal,
1557 struct vk_image_att *attachments,
1558 uint32_t n_attachments,
1562 VkCommandBufferBeginInfo cmd_begin_info;
1563 VkRenderPassBeginInfo rp_begin_info;
1565 VkClearValue clear_values[2];
1566 VkSubmitInfo submit_info;
1567 VkPipelineStageFlagBits stage_flags;
1568 VkImageSubresourceRange img_range;
1570 assert(vk_fb_color_count == 4);
1572 /* VkCommandBufferBeginInfo */
1573 memset(&cmd_begin_info, 0, sizeof cmd_begin_info);
1574 cmd_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
1575 cmd_begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
1577 /* VkRect2D render area */
1578 memset(&rp_area, 0, sizeof rp_area);
1579 rp_area.extent.width = (uint32_t)w;
1580 rp_area.extent.height = (uint32_t)h;
1581 rp_area.offset.x = x;
1582 rp_area.offset.y = y;
1585 memset(&clear_values[0], 0, sizeof clear_values[0]);
1586 clear_values[0].color.float32[0] = vk_fb_color[0]; /* red */
1587 clear_values[0].color.float32[1] = vk_fb_color[1]; /* green */
1588 clear_values[0].color.float32[2] = vk_fb_color[2]; /* blue */
1589 clear_values[0].color.float32[3] = vk_fb_color[3]; /* alpha */
1591 memset(&clear_values[1], 0, sizeof clear_values[1]);
1592 clear_values[1].depthStencil.depth = 1.0;
1593 clear_values[1].depthStencil.stencil = 0;
1595 /* VkRenderPassBeginInfo */
1596 memset(&rp_begin_info, 0, sizeof rp_begin_info);
1597 rp_begin_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
1598 rp_begin_info.renderPass = renderer->renderpass;
1599 rp_begin_info.framebuffer = renderer->fb;
1600 rp_begin_info.renderArea = rp_area;
1601 rp_begin_info.clearValueCount = 2;
1602 rp_begin_info.pClearValues = clear_values;
1605 stage_flags = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT;
1607 memset(&submit_info, 0, sizeof submit_info);
1608 submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
1609 submit_info.commandBufferCount = 1;
1610 submit_info.pCommandBuffers = &ctx->cmd_buf;
1614 submit_info.pWaitDstStageMask = &stage_flags;
1615 submit_info.waitSemaphoreCount = 1;
1616 submit_info.pWaitSemaphores = &semaphores->frame_done;
1620 submit_info.signalSemaphoreCount = 1;
1621 submit_info.pSignalSemaphores = &semaphores->frame_ready;
1624 img_range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
1625 img_range.baseMipLevel = 0;
1626 img_range.levelCount = 1;
1627 img_range.baseArrayLayer = 0;
1628 img_range.layerCount = 1;
1630 vkBeginCommandBuffer(ctx->cmd_buf, &cmd_begin_info);
1631 vk_transition_image_layout(&attachments[0],
1633 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
1634 VK_IMAGE_LAYOUT_GENERAL,
1635 VK_QUEUE_FAMILY_EXTERNAL,
1637 vkCmdClearColorImage(ctx->cmd_buf,
1638 attachments[0].obj.img,
1639 VK_IMAGE_LAYOUT_GENERAL,
1640 &clear_values[0].color,
1644 vkCmdBeginRenderPass(ctx->cmd_buf, &rp_begin_info, VK_SUBPASS_CONTENTS_INLINE);
1649 viewport.height = h;
1651 scissor.offset.x = x;
1652 scissor.offset.y = y;
1653 scissor.extent.width = w;
1654 scissor.extent.height = h;
1656 vkCmdSetViewport(ctx->cmd_buf, 0, 1, &viewport);
1657 vkCmdSetScissor(ctx->cmd_buf, 0, 1, &scissor);
1659 vkCmdBindPipeline(ctx->cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS, renderer->pipeline);
1661 vkCmdEndRenderPass(ctx->cmd_buf);
1664 VkImageMemoryBarrier *barriers =
1665 calloc(n_attachments, sizeof(VkImageMemoryBarrier));
1666 VkImageMemoryBarrier *barrier = barriers;
1668 for (uint32_t n = 0; n < n_attachments; n++, barrier++) {
1669 struct vk_image_att *att = &attachments[n];
1671 /* Insert barrier to mark ownership transfer. */
1672 barrier->sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
1675 get_aspect_from_depth_format(att->props.format) != VK_NULL_HANDLE;
1677 barrier->oldLayout = is_depth ?
1678 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL :
1679 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
1680 barrier->newLayout = VK_IMAGE_LAYOUT_GENERAL;
1681 barrier->srcAccessMask = get_access_mask(barrier->oldLayout);
1682 barrier->dstAccessMask = get_access_mask(barrier->newLayout);
1683 barrier->srcQueueFamilyIndex = ctx->qfam_idx;
1684 barrier->dstQueueFamilyIndex = VK_QUEUE_FAMILY_EXTERNAL;
1685 barrier->image = att->obj.img;
1686 barrier->subresourceRange.aspectMask = is_depth ?
1687 VK_IMAGE_ASPECT_DEPTH_BIT :
1688 VK_IMAGE_ASPECT_COLOR_BIT;
1689 barrier->subresourceRange.baseMipLevel = 0;
1690 barrier->subresourceRange.levelCount = 1;
1691 barrier->subresourceRange.baseArrayLayer = 0;
1692 barrier->subresourceRange.layerCount = 1;
1695 vkCmdPipelineBarrier(ctx->cmd_buf,
1696 VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
1697 VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
1701 n_attachments, barriers);
1705 vkEndCommandBuffer(ctx->cmd_buf);
1707 if (vkQueueSubmit(ctx->queue, 1, &submit_info, VK_NULL_HANDLE) != VK_SUCCESS) {
1708 fprintf(stderr, "Failed to submit queue.\n");
1711 if (!semaphores && !has_wait && !has_signal)
1712 vkQueueWaitIdle(ctx->queue);
1716 vk_copy_image_to_buffer(struct vk_ctx *ctx,
1717 struct vk_image_att *src_img,
1718 struct vk_buf *dst_bo,
1721 VkCommandBufferBeginInfo cmd_begin_info;
1722 VkSubmitInfo submit_info;
1723 VkImageAspectFlagBits aspect_mask = get_aspect_from_depth_format(src_img->props.format);
1725 /* VkCommandBufferBeginInfo */
1726 memset(&cmd_begin_info, 0, sizeof cmd_begin_info);
1727 cmd_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
1728 cmd_begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
1730 memset(&submit_info, 0, sizeof submit_info);
1731 submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
1732 submit_info.commandBufferCount = 1;
1733 submit_info.pCommandBuffers = &ctx->cmd_buf;
1735 vkBeginCommandBuffer(ctx->cmd_buf, &cmd_begin_info);
1736 if (src_img->props.end_layout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL && dst_bo) {
1737 vk_transition_image_layout(src_img,
1739 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
1740 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
1741 VK_QUEUE_FAMILY_EXTERNAL,
1744 /* copy image to buf */
1745 VkBufferImageCopy copy_region = {
1747 .bufferRowLength = w,
1748 .bufferImageHeight = h,
1749 .imageSubresource = {
1750 .aspectMask = aspect_mask ? aspect_mask
1751 : VK_IMAGE_ASPECT_COLOR_BIT,
1753 .baseArrayLayer = 0,
1756 .imageOffset = { 0, 0, 0 },
1757 .imageExtent = { w, h, 1 }
1760 vkCmdCopyImageToBuffer(ctx->cmd_buf,
1762 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
1763 dst_bo->buf, 1, ©_region);
1765 vk_transition_image_layout(src_img,
1767 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
1768 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
1769 VK_QUEUE_FAMILY_EXTERNAL,
1772 VkBufferMemoryBarrier write_finish_buffer_memory_barrier = {
1773 .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
1774 .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
1775 .dstAccessMask = VK_ACCESS_HOST_READ_BIT,
1776 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_EXTERNAL,
1777 .dstQueueFamilyIndex = ctx->qfam_idx,
1778 .buffer = dst_bo->buf,
1780 .size = VK_WHOLE_SIZE
1783 vkCmdPipelineBarrier(ctx->cmd_buf,
1784 VK_PIPELINE_STAGE_TRANSFER_BIT,
1785 VK_PIPELINE_STAGE_HOST_BIT,
1786 (VkDependencyFlags) 0, 0, NULL,
1787 1, &write_finish_buffer_memory_barrier,
1790 vkEndCommandBuffer(ctx->cmd_buf);
1792 if (vkQueueSubmit(ctx->queue, 1, &submit_info, VK_NULL_HANDLE) != VK_SUCCESS) {
1793 fprintf(stderr, "Failed to submit queue.\n");
1795 vkQueueWaitIdle(ctx->queue);
1800 vk_create_semaphores(struct vk_ctx *ctx,
1801 struct vk_semaphores *semaphores)
1803 VkSemaphoreCreateInfo sema_info;
1804 VkExportSemaphoreCreateInfo exp_sema_info;
1806 /* VkExportSemaphoreCreateInfo */
1807 memset(&exp_sema_info, 0, sizeof exp_sema_info);
1808 exp_sema_info.sType = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO;
1809 exp_sema_info.handleTypes = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT;
1811 /* VkSemaphoreCreateInfo */
1812 memset(&sema_info, 0, sizeof sema_info);
1813 sema_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
1814 sema_info.pNext = &exp_sema_info;
1816 if (vkCreateSemaphore(ctx->dev, &sema_info, 0, &semaphores->frame_ready) != VK_SUCCESS) {
1817 fprintf(stderr, "Failed to create semaphore frame_ready.\n");
1821 if (vkCreateSemaphore(ctx->dev, &sema_info, 0, &semaphores->frame_done) != VK_SUCCESS) {
1822 fprintf(stderr, "Failed to create semaphore frame_done.\n");
1830 vk_destroy_semaphores(struct vk_ctx *ctx,
1831 struct vk_semaphores *semaphores)
1833 if (semaphores->frame_ready)
1834 vkDestroySemaphore(ctx->dev, semaphores->frame_ready, 0);
1835 if (semaphores->frame_done)
1836 vkDestroySemaphore(ctx->dev, semaphores->frame_done, 0);
1840 vk_transition_image_layout(struct vk_image_att *img_att,
1841 VkCommandBuffer cmd_buf,
1842 VkImageLayout old_layout,
1843 VkImageLayout new_layout,
1844 uint32_t src_queue_fam_idx,
1845 uint32_t dst_queue_fam_idx)
1847 VkImageMemoryBarrier barrier;
1848 struct vk_image_props props = img_att->props;
1849 VkImageAspectFlagBits aspect_mask = get_aspect_from_depth_format(props.format);
1851 memset(&barrier, 0, sizeof barrier);
1852 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
1853 barrier.srcAccessMask = get_access_mask(old_layout);
1854 barrier.dstAccessMask = get_access_mask(new_layout);
1855 barrier.oldLayout = old_layout;
1856 barrier.newLayout = new_layout;
1857 barrier.srcQueueFamilyIndex = src_queue_fam_idx;
1858 barrier.dstQueueFamilyIndex = dst_queue_fam_idx;
1859 barrier.image = img_att->obj.img;
1860 barrier.subresourceRange.aspectMask = aspect_mask ? aspect_mask :
1861 VK_IMAGE_ASPECT_COLOR_BIT;
1862 barrier.subresourceRange.levelCount = 1;
1863 barrier.subresourceRange.layerCount = 1;
1865 vkCmdPipelineBarrier(cmd_buf,
1866 get_pipeline_stage_flags(old_layout),
1867 get_pipeline_stage_flags(new_layout),
1868 0, 0, VK_NULL_HANDLE, 0, VK_NULL_HANDLE, 1, &barrier);