ext_external_objects: Remove unnecessary NULL check.
[piglit.git] / tests / spec / ext_external_objects / vk.c
blob9219013a1ad4d7e8577f5d8dfe17be7ba46507cd
1 /*
2 * Copyright © 2020 Intel Corporation
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
23 * Author:
24 * Eleni Maria Stea <estea@igalia.com>
25 * Juan A. Suarez Romero <jasuarez@igalia.com>
26 * Topi Pohjolainen <topi.pohjolainen@intel.com>
29 #include "vk.h"
31 #ifndef VK_NULL_HANDLE
32 #define VK_NULL_HANDLE 0
33 #endif
35 /* static variables */
36 static VkViewport viewport;
37 static VkRect2D scissor;
39 /* static functions */
40 static VkSampleCountFlagBits
41 get_num_samples(uint32_t num_samples);
43 /* Vulkan static functions */
44 static VkAccessFlagBits
45 get_access_mask(const VkImageLayout layout)
47 /* dstAccessMask of barriers must be supported from the pipeline
48 * stage, see also access scopes and this table:
49 * https://www.khronos.org/registry/vulkan/specs/1.2-extensions/html/vkspec.html#synchronization-access-types-supported
51 switch (layout) {
52 case VK_IMAGE_LAYOUT_UNDEFINED:
53 return 0;
54 case VK_IMAGE_LAYOUT_GENERAL:
55 return VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT;
56 case VK_IMAGE_LAYOUT_PREINITIALIZED:
57 return VK_ACCESS_HOST_WRITE_BIT;
58 case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
59 return VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
60 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
61 case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
62 return VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_INPUT_ATTACHMENT_READ_BIT;
63 case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
64 return VK_ACCESS_TRANSFER_READ_BIT;
65 case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
66 return VK_ACCESS_TRANSFER_WRITE_BIT;
67 case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR:
68 return 0;
69 default:
70 return 0;
73 return 0;
76 static void
77 enable_validation_layers(VkInstanceCreateInfo *info)
79 int i;
80 uint32_t num_layers;
81 VkLayerProperties *layers;
82 static const char *layer_names[] = {
83 "VK_LAYER_KHRONOS_validation",
86 vkEnumerateInstanceLayerProperties(&num_layers, 0);
87 layers = alloca(num_layers * sizeof *layers);
88 vkEnumerateInstanceLayerProperties(&num_layers, layers);
90 if (num_layers) {
91 printf("Available validation layers:\n");
92 for(i = 0; i < (int)num_layers; i++) {
93 printf(" %s\n", layers[i].layerName);
96 info->ppEnabledLayerNames = layer_names;
97 info->enabledLayerCount = sizeof layer_names / sizeof *layer_names;
98 } else {
99 fprintf(stderr, "Vulkan validation layers not found.\n");
103 static VkInstance
104 create_instance(bool enable_layers)
106 VkApplicationInfo app_info;
107 VkInstanceCreateInfo inst_info;
108 VkInstance inst;
110 memset(&app_info, 0, sizeof app_info);
111 app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
112 app_info.pApplicationName = "vktest";
113 app_info.apiVersion = VK_API_VERSION_1_1;
115 memset(&inst_info, 0, sizeof inst_info);
116 inst_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
117 inst_info.pApplicationInfo = &app_info;
119 if (enable_layers)
120 enable_validation_layers(&inst_info);
122 if (vkCreateInstance(&inst_info, 0, &inst) != VK_SUCCESS)
123 return VK_NULL_HANDLE;
125 return inst;
128 static VkPhysicalDevice
129 select_physical_device(VkInstance inst)
131 VkResult res = VK_SUCCESS;
132 uint32_t dev_count = 0;
133 VkPhysicalDevice *pdevices;
134 VkPhysicalDevice pdevice0;
136 if ((res =
137 vkEnumeratePhysicalDevices(inst, &dev_count, 0)) != VK_SUCCESS)
138 return VK_NULL_HANDLE;
140 pdevices = malloc(dev_count * sizeof(VkPhysicalDevice));
141 if (vkEnumeratePhysicalDevices(inst, &dev_count, pdevices) !=
142 VK_SUCCESS)
143 return VK_NULL_HANDLE;
145 pdevice0 = pdevices[0];
146 free(pdevices);
148 return pdevice0;
151 static VkDevice
152 create_device(struct vk_ctx *ctx, VkPhysicalDevice pdev)
154 const char *deviceExtensions[] = { "VK_KHR_external_memory_fd",
155 "VK_KHR_external_semaphore_fd" };
156 VkDeviceQueueCreateInfo dev_queue_info;
157 VkDeviceCreateInfo dev_info;
158 VkDevice dev;
159 uint32_t prop_count;
160 VkQueueFamilyProperties *fam_props;
161 uint32_t i;
162 float qprio = 0;
164 ctx->qfam_idx = -1;
165 vkGetPhysicalDeviceQueueFamilyProperties(pdev, &prop_count, 0);
166 if (prop_count < 0) {
167 fprintf(stderr, "Invalid queue family properties.\n");
168 return VK_NULL_HANDLE;
171 fam_props = malloc(prop_count * sizeof *fam_props);
172 vkGetPhysicalDeviceQueueFamilyProperties(pdev, &prop_count, fam_props);
174 for (i = 0; i < prop_count; i++) {
175 if (fam_props[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
176 ctx->qfam_idx = i;
177 break;
180 free(fam_props);
182 memset(&dev_queue_info, 0, sizeof dev_queue_info);
183 dev_queue_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
184 dev_queue_info.queueFamilyIndex = ctx->qfam_idx;
185 dev_queue_info.queueCount = 1;
186 dev_queue_info.pQueuePriorities = &qprio;
188 memset(&dev_info, 0, sizeof dev_info);
189 dev_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
190 dev_info.queueCreateInfoCount = 1;
191 dev_info.pQueueCreateInfos = &dev_queue_info;
192 dev_info.enabledExtensionCount = ARRAY_SIZE(deviceExtensions);
193 dev_info.ppEnabledExtensionNames = deviceExtensions;
195 if (vkCreateDevice(pdev, &dev_info, 0, &dev) != VK_SUCCESS)
196 return VK_NULL_HANDLE;
198 return dev;
201 static void
202 fill_uuid(VkPhysicalDevice pdev, uint8_t *deviceUUID, uint8_t *driverUUID)
204 VkPhysicalDeviceIDProperties devProp;
205 VkPhysicalDeviceProperties2 prop2;
207 memset(&devProp, 0, sizeof devProp);
208 devProp.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES;
210 memset(&prop2, 0, sizeof prop2);
211 prop2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
212 prop2.pNext = &devProp;
214 vkGetPhysicalDeviceProperties2(pdev, &prop2);
215 memcpy(deviceUUID, devProp.deviceUUID, VK_UUID_SIZE);
216 memcpy(driverUUID, devProp.driverUUID, VK_UUID_SIZE);
219 static VkCommandPool
220 create_cmd_pool(struct vk_ctx *ctx)
222 VkCommandPoolCreateInfo cmd_pool_info;
223 VkCommandPool cmd_pool;
224 VkDevice dev = ctx->dev;
226 memset(&cmd_pool_info, 0, sizeof cmd_pool_info);
227 cmd_pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
228 cmd_pool_info.queueFamilyIndex = ctx->qfam_idx;
229 cmd_pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
231 if (vkCreateCommandPool(dev, &cmd_pool_info, 0, &cmd_pool) != VK_SUCCESS)
232 return VK_NULL_HANDLE;
234 return cmd_pool;
237 static VkRenderPass
238 create_renderpass(struct vk_ctx *ctx,
239 struct vk_image_props *color_img_props,
240 struct vk_image_props *depth_img_props)
242 uint32_t num_attachments = 2;
243 VkAttachmentDescription att_dsc[2];
244 VkAttachmentReference att_rfc[2];
245 VkSubpassDescription subpass_dsc[1];
246 VkRenderPassCreateInfo rpass_info;
248 /* VkAttachmentDescription */
249 memset(att_dsc, 0, num_attachments * sizeof att_dsc[0]);
251 att_dsc[0].samples = get_num_samples(color_img_props->num_samples);
252 att_dsc[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
253 att_dsc[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
254 att_dsc[0].initialLayout = color_img_props->in_layout;
255 att_dsc[0].finalLayout = color_img_props->end_layout;
256 att_dsc[0].format = color_img_props->format;
257 att_dsc[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
258 att_dsc[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
260 att_dsc[1].samples = get_num_samples(depth_img_props->num_samples);
261 /* We might want to reuse a depth buffer */
262 if (depth_img_props->in_layout != VK_IMAGE_LAYOUT_UNDEFINED) {
263 att_dsc[1].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
264 att_dsc[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
266 else {
267 att_dsc[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
268 att_dsc[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
270 att_dsc[1].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
271 att_dsc[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
272 att_dsc[1].initialLayout = depth_img_props->in_layout;
273 att_dsc[1].finalLayout = depth_img_props->end_layout;
274 att_dsc[1].format = depth_img_props->format;
276 /* VkAttachmentReference */
277 memset(att_rfc, 0, num_attachments * sizeof att_rfc[0]);
279 att_rfc[0].layout = color_img_props->tiling == VK_IMAGE_TILING_OPTIMAL ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_GENERAL;
280 att_rfc[0].attachment = 0;
282 att_rfc[1].layout = depth_img_props->tiling == VK_IMAGE_TILING_OPTIMAL ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_GENERAL;
283 att_rfc[1].attachment = 1;
285 /* VkSubpassDescription */
286 memset(&subpass_dsc, 0, sizeof subpass_dsc);
287 subpass_dsc[0].pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
288 subpass_dsc[0].colorAttachmentCount = 1;
289 subpass_dsc[0].pColorAttachments = &att_rfc[0];
290 subpass_dsc[0].pDepthStencilAttachment = &att_rfc[1];
292 /* VkRenderPassCreateInfo */
293 memset(&rpass_info, 0, sizeof rpass_info);
294 rpass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
295 rpass_info.attachmentCount = num_attachments;
296 rpass_info.pAttachments = att_dsc;
297 rpass_info.subpassCount = 1;
298 rpass_info.pSubpasses = subpass_dsc;
300 VkRenderPass rpass;
301 if (vkCreateRenderPass(ctx->dev, &rpass_info, 0, &rpass) != VK_SUCCESS) {
302 fprintf(stderr, "Failed to create renderpass.\n");
303 rpass = VK_NULL_HANDLE;
306 return rpass;
309 static inline VkImageType
310 get_image_type(uint32_t h, uint32_t d)
312 if (h == 1)
313 return VK_IMAGE_TYPE_1D;
315 if (d > 1)
316 return VK_IMAGE_TYPE_3D;
318 return VK_IMAGE_TYPE_2D;
321 static VkImageViewType
322 get_image_view_type(struct vk_image_props *props)
324 VkImageType type = get_image_type(props->h, props->depth);
325 switch(type) {
326 case VK_IMAGE_TYPE_1D:
327 return props->num_layers > 1 ?
328 VK_IMAGE_VIEW_TYPE_1D_ARRAY :
329 VK_IMAGE_VIEW_TYPE_1D;
330 case VK_IMAGE_TYPE_2D:
331 if (props->num_layers == 1)
332 return VK_IMAGE_VIEW_TYPE_2D;
333 if (props->num_layers == 6)
334 return VK_IMAGE_VIEW_TYPE_CUBE;
335 if (props->num_layers % 6 == 0)
336 return VK_IMAGE_VIEW_TYPE_CUBE_ARRAY;
337 if (props->num_layers > 1)
338 return VK_IMAGE_VIEW_TYPE_2D_ARRAY;
339 case VK_IMAGE_TYPE_3D:
340 if (props->num_layers == 1)
341 return VK_IMAGE_VIEW_TYPE_3D;
342 if ((props->num_layers == 1) &&
343 (props->num_levels == 1))
344 return VK_IMAGE_VIEW_TYPE_2D;
345 if ((props->num_levels == 1) &&
346 (props->num_layers > 1))
347 return VK_IMAGE_VIEW_TYPE_2D_ARRAY;
348 default:
349 return VK_IMAGE_VIEW_TYPE_2D;
353 static VkImageAspectFlagBits
354 get_aspect_from_depth_format(VkFormat depth_format)
356 switch (depth_format) {
357 case VK_FORMAT_D16_UNORM:
358 case VK_FORMAT_X8_D24_UNORM_PACK32:
359 case VK_FORMAT_D32_SFLOAT:
360 return VK_IMAGE_ASPECT_DEPTH_BIT;
361 case VK_FORMAT_S8_UINT:
362 return VK_IMAGE_ASPECT_STENCIL_BIT;
363 case VK_FORMAT_D16_UNORM_S8_UINT:
364 case VK_FORMAT_D24_UNORM_S8_UINT:
365 case VK_FORMAT_D32_SFLOAT_S8_UINT:
366 return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
367 default:
368 break;
370 return 0;
373 static VkPipelineStageFlags
374 get_pipeline_stage_flags(const VkImageLayout layout)
376 switch (layout) {
377 case VK_IMAGE_LAYOUT_UNDEFINED:
378 return VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
379 case VK_IMAGE_LAYOUT_GENERAL:
380 return VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
381 case VK_IMAGE_LAYOUT_PREINITIALIZED:
382 return VK_PIPELINE_STAGE_HOST_BIT;
383 case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
384 case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
385 return VK_PIPELINE_STAGE_TRANSFER_BIT;
386 case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
387 return VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
388 case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
389 return VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
390 VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
391 case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR:
392 return VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
393 default:
394 return 0;
396 return 0;
399 static void
400 create_framebuffer(struct vk_ctx *ctx,
401 struct vk_image_att *color_att,
402 struct vk_image_att *depth_att,
403 struct vk_renderer *renderer)
405 VkImageSubresourceRange sr;
406 VkImageViewCreateInfo color_info;
407 VkImageViewCreateInfo depth_info;
408 VkFramebufferCreateInfo fb_info;
409 VkImageViewType view_type = get_image_view_type(&color_att->props);
410 VkImageView atts[2];
412 if (!color_att->obj.img || !depth_att->obj.img) {
413 fprintf(stderr, "Invalid framebuffer attachment image.\n");
414 goto fail;
417 /* create image views */
419 /* VKImageSubresourceRange */
420 memset(&sr, 0, sizeof sr);
421 sr.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
422 /* If an application wants to use all mip levels
423 * or layers in an image after the baseMipLevel
424 * or baseArrayLayer, it can set levelCount and
425 * layerCount to the special values
426 * VK_REMAINING_MIP_LEVELS and
427 * VK_REMAINING_ARRAY_LAYERS without knowing the
428 * exact number of mip levels or layers.
430 sr.baseMipLevel = 0;
431 sr.levelCount = color_att->props.num_levels;
432 sr.baseArrayLayer = 0;
433 sr.layerCount = color_att->props.num_layers;
435 /* color view */
436 memset(&color_info, 0, sizeof color_info);
437 color_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
438 color_info.image = color_att->obj.img;
439 color_info.viewType = view_type;
440 color_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
441 color_info.format = color_att->props.format;
442 color_info.subresourceRange = sr;
444 if (vkCreateImageView(ctx->dev, &color_info, 0, &color_att->obj.img_view) != VK_SUCCESS) {
445 fprintf(stderr, "Failed to create color image view for framebuffer.\n");
446 vk_destroy_ext_image(ctx, &color_att->obj);
447 goto fail;
450 /* depth view */
451 memset(&sr, 0, sizeof sr);
452 sr.aspectMask = get_aspect_from_depth_format(depth_att->props.format);
453 sr.baseMipLevel = 0;
454 sr.levelCount = depth_att->props.num_levels ? depth_att->props.num_levels : 1;
455 sr.baseArrayLayer = 0;
456 sr.layerCount = depth_att->props.num_layers ? depth_att->props.num_layers : 1;
458 memset(&depth_info, 0, sizeof depth_info);
459 depth_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
460 depth_info.image = depth_att->obj.img;
461 depth_info.viewType = depth_att->props.num_layers > 1 ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D;
462 depth_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
463 depth_info.format = depth_att->props.format;
464 depth_info.subresourceRange = sr;
466 if (vkCreateImageView(ctx->dev, &depth_info, 0, &depth_att->obj.img_view) != VK_SUCCESS) {
467 fprintf(stderr, "Failed to create depth image view for framebuffer.\n");
468 vk_destroy_ext_image(ctx, &depth_att->obj);
469 goto fail;
472 atts[0] = color_att->obj.img_view;
473 atts[1] = depth_att->obj.img_view;
475 memset(&fb_info, 0, sizeof fb_info);
476 fb_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
477 fb_info.renderPass = renderer->renderpass;
478 fb_info.width = color_att->props.w;
479 fb_info.height = color_att->props.h;
480 fb_info.layers = color_att->props.num_layers ? color_att->props.num_layers : 1;
481 fb_info.attachmentCount = 2;
482 fb_info.pAttachments = atts;
484 if (vkCreateFramebuffer(ctx->dev, &fb_info, 0, &renderer->fb) != VK_SUCCESS)
485 goto fail;
487 return;
489 fail:
490 fprintf(stderr, "Failed to create framebuffer.\n");
491 renderer->fb = VK_NULL_HANDLE;
494 static VkShaderModule
495 create_shader_module(struct vk_ctx *ctx,
496 const char *src,
497 unsigned int size)
499 VkShaderModuleCreateInfo sm_info;
500 VkShaderModule sm;
502 /* VkShaderModuleCreateInfo */
503 memset(&sm_info, 0, sizeof sm_info);
504 sm_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
505 sm_info.codeSize = size;
506 sm_info.pCode = (void*)src;
508 if (vkCreateShaderModule(ctx->dev, &sm_info, 0, &sm) != VK_SUCCESS) {
509 fprintf(stderr, "Failed to create shader module.\n");
510 sm = VK_NULL_HANDLE;
513 return sm;
516 static void
517 create_pipeline(struct vk_ctx *ctx,
518 uint32_t width,
519 uint32_t height,
520 uint32_t num_samples,
521 bool enable_depth,
522 bool enable_stencil,
523 struct vk_renderer *renderer)
525 VkVertexInputBindingDescription vert_bind_dsc[1];
526 VkVertexInputAttributeDescription vert_att_dsc[1];
528 VkPipelineColorBlendAttachmentState cb_att_state[1];
529 VkPipelineVertexInputStateCreateInfo vert_input_info;
530 VkPipelineInputAssemblyStateCreateInfo asm_info;
531 VkPipelineViewportStateCreateInfo viewport_info;
532 VkPipelineRasterizationStateCreateInfo rs_info;
533 VkPipelineMultisampleStateCreateInfo ms_info;
534 VkPipelineDepthStencilStateCreateInfo ds_info;
535 VkPipelineColorBlendStateCreateInfo cb_info;
536 VkPipelineShaderStageCreateInfo sdr_stages[2];
537 VkPipelineLayoutCreateInfo layout_info;
538 VkGraphicsPipelineCreateInfo pipeline_info;
539 VkFormat format;
540 VkFormatProperties fmt_props;
541 VkPushConstantRange pc_range[1];
543 VkStencilOpState front;
544 VkStencilOpState back;
545 int i;
546 VkPipelineLayout pipeline_layout;
547 uint32_t stride;
549 /* format of vertex attributes:
550 * we have 2D vectors so we need a RG format:
551 * R for x, G for y
552 * the stride (distance between 2 consecutive elements)
553 * must be 8 because we use 32 bit floats and
554 * 32bits = 8bytes */
555 format = VK_FORMAT_R32G32_SFLOAT;
556 vkGetPhysicalDeviceFormatProperties(ctx->pdev, format, &fmt_props);
557 assert(fmt_props.bufferFeatures & VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT);
558 stride = 8;
560 /* VkVertexInputAttributeDescription */
561 memset(&vert_att_dsc, 0, sizeof vert_att_dsc);
562 vert_att_dsc[0].location = 0;
563 vert_att_dsc[0].binding = 0;
564 vert_att_dsc[0].format = format; /* see comment */
565 vert_att_dsc[0].offset = 0;
567 /* VkVertexInputBindingDescription */
568 memset(&vert_bind_dsc, 0, sizeof vert_bind_dsc);
569 vert_bind_dsc[0].binding = 0;
570 vert_bind_dsc[0].stride = stride;
571 vert_bind_dsc[0].inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
573 /* If using vbo, we have setup vertex_info in the renderer. */
574 bool use_vbo = renderer->vertex_info.num_verts > 0;
576 /* VkPipelineVertexInputStateCreateInfo */
577 memset(&vert_input_info, 0, sizeof vert_input_info);
578 vert_input_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
579 vert_input_info.vertexBindingDescriptionCount = use_vbo ? 1 : 0;
580 vert_input_info.pVertexBindingDescriptions = vert_bind_dsc;
581 vert_input_info.vertexAttributeDescriptionCount = use_vbo ? 1 : 0;
582 vert_input_info.pVertexAttributeDescriptions = vert_att_dsc;
584 /* VkPipelineInputAssemblyStateCreateInfo */
585 memset(&asm_info, 0, sizeof asm_info);
586 asm_info.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
587 asm_info.topology = renderer->vertex_info.topology ?
588 renderer->vertex_info.topology : VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
589 asm_info.primitiveRestartEnable = false;
591 /* VkViewport */
592 viewport.x = viewport.y = 0;
593 viewport.width = width;
594 viewport.height = height;
595 viewport.minDepth = 0;
596 viewport.maxDepth = 1;
598 /* VkRect2D scissor */
599 scissor.offset.x = scissor.offset.y = 0;
600 scissor.extent.width = width;
601 scissor.extent.height = height;
603 /* VkPipelineViewportStateCreateInfo */
604 memset(&viewport_info, 0, sizeof viewport_info);
605 viewport_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
606 viewport_info.viewportCount = 1;
607 viewport_info.pViewports = &viewport;
608 viewport_info.scissorCount = 1;
609 viewport_info.pScissors = &scissor;
611 /* VkPipelineRasterizationStateCreateInfo */
612 memset(&rs_info, 0, sizeof rs_info);
613 rs_info.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
614 rs_info.polygonMode = VK_POLYGON_MODE_FILL;
615 rs_info.cullMode = VK_CULL_MODE_NONE;
616 rs_info.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
617 rs_info.lineWidth = 1.0;
619 /* VkPipelineMultisampleStateCreateInfo */
620 memset(&ms_info, 0, sizeof ms_info);
621 ms_info.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
622 ms_info.rasterizationSamples = num_samples;
624 /* VkStencilOpState */
625 /* The default values for ES are taken by Topi Pohjolainen's code */
626 /* defaults in OpenGL ES 3.1 */
627 memset(&front, 0, sizeof front);
628 front.compareMask = ~0;
629 front.writeMask = ~0;
630 front.reference = 0;
632 memset(&back, 0, sizeof back);
634 /* VkPipelineDepthStencilStateCreateInfo */
635 memset(&ds_info, 0, sizeof ds_info);
636 ds_info.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
637 ds_info.front = front;
638 ds_info.back = back;
639 /* defaults in OpenGL ES 3.1 */
640 ds_info.minDepthBounds = 0;
641 ds_info.maxDepthBounds = 1;
642 /* z buffer, stencil buffer */
643 if (enable_depth) {
644 ds_info.depthTestEnable = VK_TRUE;
645 ds_info.depthWriteEnable = VK_TRUE;
646 ds_info.depthCompareOp = VK_COMPARE_OP_LESS;
648 if (enable_stencil) {
649 ds_info.stencilTestEnable = VK_TRUE;
650 ds_info.depthTestEnable = VK_FALSE;
651 ds_info.depthWriteEnable = VK_TRUE;
654 /* we only care about the passOp here */
655 ds_info.back.compareOp = VK_COMPARE_OP_ALWAYS;
656 ds_info.back.failOp = VK_STENCIL_OP_REPLACE;
657 ds_info.back.depthFailOp = VK_STENCIL_OP_REPLACE;
658 ds_info.back.passOp = VK_STENCIL_OP_REPLACE;
659 ds_info.back.compareMask = 0xffffffff;
660 ds_info.back.writeMask = 0xffffffff;
661 ds_info.back.reference = 1;
662 ds_info.front = ds_info.back;
664 /* VkPipelineColorBlendAttachmentState */
665 memset(&cb_att_state[0], 0, sizeof cb_att_state[0]);
666 cb_att_state[0].colorWriteMask = (VK_COLOR_COMPONENT_R_BIT |
667 VK_COLOR_COMPONENT_G_BIT |
668 VK_COLOR_COMPONENT_B_BIT |
669 VK_COLOR_COMPONENT_A_BIT);
671 /* VkPipelineColorBlendStateCreateInfo */
672 memset(&cb_info, 0, sizeof cb_info);
673 cb_info.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
674 cb_info.attachmentCount = 1;
675 cb_info.pAttachments = cb_att_state;
676 /* default in ES 3.1 */
677 for (i = 0; i < 4; i++) {
678 cb_info.blendConstants[i] = 0.0f;
681 /* VkPipelineShaderStageCreateInfo */
682 memset(sdr_stages, 0, 2 * sizeof sdr_stages[0]);
684 sdr_stages[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
685 sdr_stages[0].stage = VK_SHADER_STAGE_VERTEX_BIT;
686 sdr_stages[0].module = renderer->vs;
687 sdr_stages[0].pName = "main";
689 sdr_stages[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
690 sdr_stages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT;
691 sdr_stages[1].module = renderer->fs;
692 sdr_stages[1].pName = "main";
694 /* VkPushConstantRange */
695 memset(pc_range, 0, sizeof pc_range[0]);
696 pc_range[0].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
697 pc_range[0].size = sizeof (struct vk_dims); /* w, h */
699 /* VkPipelineLayoutCreateInfo */
700 memset(&layout_info, 0, sizeof layout_info);
701 layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
702 layout_info.pushConstantRangeCount = 1;
703 layout_info.pPushConstantRanges = pc_range;
705 if (vkCreatePipelineLayout(ctx->dev, &layout_info, 0, &pipeline_layout) != VK_SUCCESS) {
706 fprintf(stderr, "Failed to create pipeline layout\n");
707 renderer->pipeline = VK_NULL_HANDLE;
708 return;
711 renderer->pipeline_layout = pipeline_layout;
713 /* VkGraphicsPipelineCreateInfo */
714 memset(&pipeline_info, 0, sizeof pipeline_info);
715 pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
716 pipeline_info.layout = pipeline_layout;
717 pipeline_info.renderPass = renderer->renderpass;
718 pipeline_info.pVertexInputState = &vert_input_info;
719 pipeline_info.pInputAssemblyState = &asm_info;
720 pipeline_info.pViewportState = &viewport_info;
721 pipeline_info.pRasterizationState = &rs_info;
722 pipeline_info.pMultisampleState = &ms_info;
723 pipeline_info.pDepthStencilState = &ds_info;
724 pipeline_info.pColorBlendState = &cb_info;
725 pipeline_info.stageCount = 2;
726 pipeline_info.pStages = sdr_stages;
728 if (vkCreateGraphicsPipelines(ctx->dev, 0, 1,
729 &pipeline_info, 0, &renderer->pipeline) !=
730 VK_SUCCESS) {
731 fprintf(stderr, "Failed to create graphics pipeline.\n");
732 renderer->pipeline = VK_NULL_HANDLE;
736 static VkCommandBuffer
737 create_cmd_buf(VkDevice dev, VkCommandPool cmd_pool)
739 VkCommandBuffer cmd_buf;
740 VkCommandBufferAllocateInfo alloc_info;
742 memset(&alloc_info, 0, sizeof alloc_info);
743 alloc_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
744 alloc_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
745 alloc_info.commandBufferCount = 1;
746 alloc_info.commandPool = cmd_pool;
748 if (vkAllocateCommandBuffers(dev, &alloc_info, &cmd_buf) != VK_SUCCESS)
749 return VK_NULL_HANDLE;
751 return cmd_buf;
754 static uint32_t
755 get_memory_type_idx(VkPhysicalDevice pdev,
756 const VkMemoryRequirements *mem_reqs,
757 VkMemoryPropertyFlagBits prop_flags)
759 VkPhysicalDeviceMemoryProperties pdev_mem_props;
760 uint32_t i;
762 vkGetPhysicalDeviceMemoryProperties(pdev, &pdev_mem_props);
764 for (i = 0; i < pdev_mem_props.memoryTypeCount; i++) {
765 const VkMemoryType *type = &pdev_mem_props.memoryTypes[i];
767 if ((mem_reqs->memoryTypeBits & (1 << i)) &&
768 (type->propertyFlags & prop_flags) == prop_flags) {
769 return i;
770 break;
773 return UINT32_MAX;
776 static VkSampleCountFlagBits
777 get_num_samples(uint32_t num_samples)
779 switch(num_samples) {
780 case 64:
781 return VK_SAMPLE_COUNT_64_BIT;
782 case 32:
783 return VK_SAMPLE_COUNT_32_BIT;
784 case 16:
785 return VK_SAMPLE_COUNT_16_BIT;
786 case 8:
787 return VK_SAMPLE_COUNT_8_BIT;
788 case 4:
789 return VK_SAMPLE_COUNT_4_BIT;
790 case 2:
791 return VK_SAMPLE_COUNT_2_BIT;
792 case 1:
793 break;
794 default:
795 fprintf(stderr, "Invalid number of samples in VkSampleCountFlagBits. Using one sample.\n");
796 break;
798 return VK_SAMPLE_COUNT_1_BIT;
801 static VkDeviceMemory
802 alloc_memory(struct vk_ctx *ctx,
803 bool is_external,
804 const VkMemoryRequirements *mem_reqs,
805 VkImage image,
806 VkBuffer buffer,
807 VkMemoryPropertyFlagBits prop_flags)
809 VkExportMemoryAllocateInfo exp_mem_info;
810 VkMemoryAllocateInfo mem_alloc_info;
811 VkDeviceMemory mem;
812 VkMemoryDedicatedAllocateInfoKHR ded_info;
814 if (is_external) {
815 memset(&exp_mem_info, 0, sizeof exp_mem_info);
816 exp_mem_info.sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO;
817 exp_mem_info.handleTypes =
818 VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;
821 memset(&mem_alloc_info, 0, sizeof mem_alloc_info);
822 mem_alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
823 mem_alloc_info.pNext = is_external ? &exp_mem_info : 0;
824 mem_alloc_info.allocationSize = mem_reqs->size;
825 mem_alloc_info.memoryTypeIndex =
826 get_memory_type_idx(ctx->pdev, mem_reqs, prop_flags);
828 if (mem_alloc_info.memoryTypeIndex == UINT32_MAX) {
829 fprintf(stderr, "No suitable memory type index found.\n");
830 return VK_NULL_HANDLE;
833 if (image || buffer) {
834 memset(&ded_info, 0, sizeof ded_info);
835 ded_info.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO;
836 ded_info.image = image;
837 ded_info.buffer = buffer;
839 exp_mem_info.pNext = &ded_info;
842 if (vkAllocateMemory(ctx->dev, &mem_alloc_info, 0, &mem) !=
843 VK_SUCCESS)
844 return VK_NULL_HANDLE;
846 return mem;
849 static bool
850 alloc_image_memory(struct vk_ctx *ctx, struct vk_image_obj *img_obj)
852 VkMemoryDedicatedRequirements ded_reqs;
853 VkImageMemoryRequirementsInfo2 req_info2;
854 VkMemoryRequirements2 mem_reqs2;
856 memset(&ded_reqs, 0, sizeof ded_reqs);
857 ded_reqs.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS;
859 /* VkImageMemoryRequirementsInfo2 */
860 memset(&req_info2, 0, sizeof req_info2);
861 req_info2.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2;
862 req_info2.image = img_obj->img;
864 /* VkMemoryRequirements2 */
865 memset(&mem_reqs2, 0, sizeof mem_reqs2);
866 mem_reqs2.sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2;
867 mem_reqs2.pNext = &ded_reqs;
869 vkGetImageMemoryRequirements2(ctx->dev, &req_info2, &mem_reqs2);
870 img_obj->mobj.mem = alloc_memory(ctx,
871 true,
872 &mem_reqs2.memoryRequirements,
873 ded_reqs.requiresDedicatedAllocation? img_obj->img : VK_NULL_HANDLE,
874 VK_NULL_HANDLE,
875 mem_reqs2.memoryRequirements.memoryTypeBits &
876 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
878 img_obj->mobj.mem_sz = mem_reqs2.memoryRequirements.size;
879 img_obj->mobj.dedicated = ded_reqs.requiresDedicatedAllocation;
880 if (img_obj->mobj.mem == VK_NULL_HANDLE) {
881 fprintf(stderr, "Failed to allocate image memory.\n");
882 return false;
885 if (vkBindImageMemory(ctx->dev, img_obj->img, img_obj->mobj.mem, 0) != VK_SUCCESS) {
886 fprintf(stderr, "Failed to bind image memory.\n");
887 return false;
890 return true;
893 static bool
894 are_props_supported(struct vk_ctx *ctx, struct vk_image_props *props)
896 VkPhysicalDeviceExternalImageFormatInfo ext_img_fmt_info;
897 VkExternalImageFormatProperties ext_img_fmt_props;
899 int i;
900 VkPhysicalDeviceImageFormatInfo2 img_fmt_info;
901 VkImageFormatProperties2 img_fmt_props;
902 VkImageUsageFlagBits all_flags[] = {
903 VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
904 VK_IMAGE_USAGE_TRANSFER_DST_BIT,
905 VK_IMAGE_USAGE_SAMPLED_BIT,
906 VK_IMAGE_USAGE_STORAGE_BIT,
907 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
908 VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
909 VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT,
910 /* Shouldn't be used together with COLOR, DEPTH_STENCIL
911 * attachment bits:
912 * VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT,
913 * Provided by VK_EXT_fragment_density_map
914 * VK_IMAGE_USAGE_FRAGMENT_DENSITY_MAP_BIT_EXT,
915 * Provided by VK_NV_shading_rate_image
916 * VK_IMAGE_USAGE_SHADING_RATE_IMAGE_BIT_NV,
917 * Provided by VK_KHR_fragment_shading_rate
918 * VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR,
921 VkImageUsageFlagBits flags = 0;
923 VkExternalMemoryFeatureFlagBits export_feature_flags =
924 VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT;
925 VkExternalMemoryHandleTypeFlagBits handle_type =
926 VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;
928 memset(&ext_img_fmt_info, 0, sizeof ext_img_fmt_info);
929 ext_img_fmt_info.sType =
930 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO;
931 ext_img_fmt_info.handleType = handle_type;
933 memset(&ext_img_fmt_props, 0, sizeof ext_img_fmt_props);
934 ext_img_fmt_props.sType =
935 VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES;
937 memset(&img_fmt_props, 0, sizeof img_fmt_props);
938 img_fmt_props.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2;
939 img_fmt_props.pNext = &ext_img_fmt_props;
941 memset(&img_fmt_info, 0, sizeof img_fmt_info);
942 img_fmt_info.sType =
943 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2;
944 img_fmt_info.pNext = &ext_img_fmt_info;
945 img_fmt_info.format = props->format;
946 img_fmt_info.type = get_image_type(props->h, props->depth);
947 img_fmt_info.tiling = props->tiling;
949 for (i = 0; i < ARRAY_SIZE(all_flags); i++) {
950 img_fmt_info.usage = all_flags[i];
951 if (vkGetPhysicalDeviceImageFormatProperties2(ctx->pdev,
952 &img_fmt_info,
953 &img_fmt_props) == VK_SUCCESS) {
954 flags |= all_flags[i];
958 /* usage can't be null */
959 if (flags) {
960 img_fmt_info.usage = flags;
962 else {
963 fprintf(stderr, "Unsupported Vulkan format properties: usage.\n");
964 return false;
967 if (vkGetPhysicalDeviceImageFormatProperties2
968 (ctx->pdev, &img_fmt_info, &img_fmt_props) != VK_SUCCESS) {
969 fprintf(stderr,
970 "Unsupported Vulkan format properties.\n");
971 return false;
973 props->usage = flags;
975 if (props->need_export &&
976 !(ext_img_fmt_props.externalMemoryProperties.externalMemoryFeatures
977 & export_feature_flags)) {
978 fprintf(stderr, "Unsupported Vulkan external memory features.\n");
979 return false;
982 return true;
985 /* Vulkan test visible functions */
987 bool
988 vk_init_ctx(struct vk_ctx *ctx)
990 if ((ctx->inst = create_instance(false)) == VK_NULL_HANDLE) {
991 fprintf(stderr, "Failed to create Vulkan instance.\n");
992 goto fail;
995 if ((ctx->pdev = select_physical_device(ctx->inst)) == VK_NULL_HANDLE) {
996 fprintf(stderr, "Failed to find suitable physical device.\n");
997 goto fail;
1000 if ((ctx->dev = create_device(ctx, ctx->pdev)) == VK_NULL_HANDLE) {
1001 fprintf(stderr, "Failed to create Vulkan device.\n");
1002 goto fail;
1005 fill_uuid(ctx->pdev, ctx->deviceUUID, ctx->driverUUID);
1006 return true;
1008 fail:
1009 vk_cleanup_ctx(ctx);
1010 return false;
1013 bool
1014 vk_init_ctx_for_rendering(struct vk_ctx *ctx)
1016 if (!vk_init_ctx(ctx)) {
1017 fprintf(stderr, "Failed to initialize Vulkan.\n");
1018 return false;
1021 if ((ctx->cmd_pool = create_cmd_pool(ctx)) == VK_NULL_HANDLE) {
1022 fprintf(stderr, "Failed to create command pool.\n");
1023 goto fail;
1026 if ((ctx->cmd_buf = create_cmd_buf(ctx->dev, ctx->cmd_pool)) ==
1027 VK_NULL_HANDLE) {
1028 fprintf(stderr, "Failed to create command buffer.\n");
1029 goto fail;
1032 vkGetDeviceQueue(ctx->dev, ctx->qfam_idx, 0, &ctx->queue);
1033 if (!ctx->queue) {
1034 fprintf(stderr, "Failed to get command queue.\n");
1035 goto fail;
1038 return true;
1040 fail:
1041 vk_cleanup_ctx(ctx);
1042 return false;
1045 void
1046 vk_cleanup_ctx(struct vk_ctx *ctx)
1048 if (ctx->cmd_buf != VK_NULL_HANDLE) {
1049 vkResetCommandBuffer(ctx->cmd_buf, VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT);
1050 vkFreeCommandBuffers(ctx->dev, ctx->cmd_pool, 1, &ctx->cmd_buf);
1051 ctx->cmd_buf = VK_NULL_HANDLE;
1054 if (ctx->cmd_pool != VK_NULL_HANDLE) {
1055 vkResetCommandPool(ctx->dev, ctx->cmd_pool, VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT);
1056 vkDestroyCommandPool(ctx->dev, ctx->cmd_pool, 0);
1057 ctx->cmd_pool = VK_NULL_HANDLE;
1060 if (ctx->dev != VK_NULL_HANDLE) {
1061 vkDestroyDevice(ctx->dev, 0);
1062 ctx->dev = VK_NULL_HANDLE;
1065 if (ctx->inst != VK_NULL_HANDLE) {
1066 vkDestroyInstance(ctx->inst, 0);
1067 ctx->inst = VK_NULL_HANDLE;
1071 bool
1072 vk_create_ext_image(struct vk_ctx *ctx,
1073 struct vk_image_props *props, struct vk_image_obj *img)
1075 VkExternalMemoryImageCreateInfo ext_img_info;
1076 VkImageCreateInfo img_info;
1078 memset(&ext_img_info, 0, sizeof ext_img_info);
1079 ext_img_info.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO;
1080 ext_img_info.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;
1082 memset(&img_info, 0, sizeof img_info);
1083 img_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
1084 img_info.pNext = &ext_img_info;
1085 img_info.imageType = get_image_type(props->h, props->depth);
1086 img_info.format = props->format;
1087 img_info.extent.width = props->w;
1088 img_info.extent.height = props->h;
1089 img_info.extent.depth = props->depth;
1090 img_info.mipLevels = props->num_levels ? props->num_levels : 1;
1091 img_info.arrayLayers = props->num_layers ? props->num_layers : VK_SAMPLE_COUNT_1_BIT;
1092 img_info.samples = get_num_samples(props->num_samples);
1093 img_info.tiling = props->tiling;
1094 img_info.usage = props->usage;
1095 img_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
1096 img_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
1097 /* issue 17 of EXT_external_objects
1098 * Required in OpenGL implementations that support
1099 * ARB_texture_view, OES_texture_view, EXT_texture_view,
1100 * or OpenGL 4.3 and above.
1102 img_info.flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
1104 if (vkCreateImage(ctx->dev, &img_info, 0, &img->img) != VK_SUCCESS)
1105 goto fail;
1107 if(!alloc_image_memory(ctx, img))
1108 goto fail;
1110 return true;
1112 fail:
1113 fprintf(stderr, "Failed to create external image.\n");
1114 vk_destroy_ext_image(ctx, img);
1115 img->img = VK_NULL_HANDLE;
1116 img->mobj.mem = VK_NULL_HANDLE;
1117 return false;
1120 bool
1121 vk_create_ext_buffer(struct vk_ctx *ctx,
1122 uint32_t sz,
1123 VkBufferUsageFlagBits usage,
1124 struct vk_buf *bo)
1126 VkExternalMemoryBufferCreateInfo ext_bo_info;
1128 memset(&ext_bo_info, 0, sizeof ext_bo_info);
1129 ext_bo_info.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO;
1130 ext_bo_info.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;
1132 if (!vk_create_buffer(ctx, true, sz, usage, &ext_bo_info, bo)) {
1133 fprintf(stderr, "Failed to allocate external buffer.\n");
1134 return false;
1137 return true;
1140 void
1141 vk_destroy_ext_image(struct vk_ctx *ctx, struct vk_image_obj *img_obj)
1143 if (img_obj->img != VK_NULL_HANDLE) {
1144 vkDestroyImage(ctx->dev, img_obj->img, 0);
1145 img_obj->img = VK_NULL_HANDLE;
1148 if (img_obj->mobj.mem != VK_NULL_HANDLE) {
1149 vkFreeMemory(ctx->dev, img_obj->mobj.mem, 0);
1150 img_obj->mobj.mem = VK_NULL_HANDLE;
1153 if (img_obj->img_view != VK_NULL_HANDLE) {
1154 vkDestroyImageView(ctx->dev, img_obj->img_view, 0);
1155 img_obj->img_view = VK_NULL_HANDLE;
1159 void
1160 vk_destroy_ext_bo(struct vk_ctx *ctx,
1161 struct vk_buf *bo)
1163 if (bo->buf != VK_NULL_HANDLE) {
1164 vkDestroyBuffer(ctx->dev, bo->buf, 0);
1165 bo->buf = VK_NULL_HANDLE;
1168 if (bo->mobj.mem != VK_NULL_HANDLE) {
1169 vkFreeMemory(ctx->dev, bo->mobj.mem, 0);
1170 bo->mobj.mem = VK_NULL_HANDLE;
1174 bool
1175 vk_fill_ext_image_props(struct vk_ctx *ctx,
1176 uint32_t w,
1177 uint32_t h,
1178 uint32_t d,
1179 uint32_t num_samples,
1180 uint32_t num_levels,
1181 uint32_t num_layers,
1182 VkFormat format,
1183 VkImageTiling tiling,
1184 VkImageLayout in_layout,
1185 VkImageLayout end_layout,
1186 bool need_export,
1187 struct vk_image_props *props)
1189 props->w = w;
1190 props->h = h;
1191 props->depth = d;
1193 props->num_samples = num_samples;
1194 props->num_levels = num_levels;
1195 props->num_layers = num_layers;
1197 props->format = format;
1198 props->tiling = tiling;
1200 props->in_layout = in_layout;
1201 props->end_layout = end_layout;
1203 props->need_export = need_export;
1205 if (!are_props_supported(ctx, props))
1206 return false;
1208 return true;
1211 bool
1212 vk_create_renderer(struct vk_ctx *ctx,
1213 const char *vs_src,
1214 unsigned int vs_size,
1215 const char *fs_src,
1216 unsigned int fs_size,
1217 bool enable_depth,
1218 bool enable_stencil,
1219 struct vk_image_att *color_att,
1220 struct vk_image_att *depth_att,
1221 struct vk_vertex_info *vert_info,
1222 struct vk_renderer *renderer)
1224 memset(&renderer->vertex_info, 0, sizeof renderer->vertex_info);
1225 if (vert_info)
1226 renderer->vertex_info = *vert_info;
1228 renderer->renderpass = create_renderpass(ctx, &color_att->props, &depth_att->props);
1229 if (renderer->renderpass == VK_NULL_HANDLE)
1230 goto fail;
1232 create_framebuffer(ctx, color_att, depth_att, renderer);
1233 if (renderer->fb == VK_NULL_HANDLE)
1234 goto fail;
1236 renderer->vs = create_shader_module(ctx, vs_src, vs_size);
1237 if (renderer->vs == VK_NULL_HANDLE)
1238 goto fail;
1240 renderer->fs = create_shader_module(ctx, fs_src, fs_size);
1241 if (renderer->fs == VK_NULL_HANDLE)
1242 goto fail;
1244 create_pipeline(ctx, color_att->props.w, color_att->props.h,
1245 color_att->props.num_samples, enable_depth, enable_stencil, renderer);
1247 if (renderer->pipeline == VK_NULL_HANDLE)
1248 goto fail;
1250 return true;
1252 fail:
1253 fprintf(stderr, "Failed to create graphics pipeline.\n");
1254 vk_destroy_renderer(ctx, renderer);
1255 return false;
1258 void
1259 vk_destroy_renderer(struct vk_ctx *ctx,
1260 struct vk_renderer *renderer)
1262 if (renderer->renderpass != VK_NULL_HANDLE) {
1263 vkDestroyRenderPass(ctx->dev, renderer->renderpass, 0);
1264 renderer->renderpass = VK_NULL_HANDLE;
1267 if (renderer->vs != VK_NULL_HANDLE) {
1268 vkDestroyShaderModule(ctx->dev, renderer->vs, 0);
1269 renderer->vs = VK_NULL_HANDLE;
1272 if (renderer->fs != VK_NULL_HANDLE) {
1273 vkDestroyShaderModule(ctx->dev, renderer->fs, 0);
1274 renderer->fs = VK_NULL_HANDLE;
1277 if (renderer->fb != VK_NULL_HANDLE) {
1278 vkDestroyFramebuffer(ctx->dev, renderer->fb, 0);
1279 renderer->fb = VK_NULL_HANDLE;
1282 if (renderer->pipeline != VK_NULL_HANDLE) {
1283 vkDestroyPipeline(ctx->dev, renderer->pipeline, 0);
1284 renderer->pipeline = VK_NULL_HANDLE;
1287 if (renderer->pipeline_layout != VK_NULL_HANDLE) {
1288 vkDestroyPipelineLayout(ctx->dev, renderer->pipeline_layout, 0);
1289 renderer->pipeline_layout = VK_NULL_HANDLE;
1293 bool
1294 vk_create_buffer(struct vk_ctx *ctx,
1295 bool is_external,
1296 uint32_t sz,
1297 VkBufferUsageFlagBits usage,
1298 void *pnext,
1299 struct vk_buf *bo)
1301 VkBufferCreateInfo buf_info;
1302 VkMemoryRequirements mem_reqs;
1304 bo->mobj.mem = VK_NULL_HANDLE;
1305 bo->buf = VK_NULL_HANDLE;
1307 /* VkBufferCreateInfo */
1308 memset(&buf_info, 0, sizeof buf_info);
1309 buf_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
1310 buf_info.size = sz;
1311 buf_info.usage = usage;
1312 buf_info.pNext = pnext;
1313 buf_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
1315 if (vkCreateBuffer(ctx->dev, &buf_info, 0, &bo->buf) != VK_SUCCESS)
1316 goto fail;
1318 /* allocate buffer */
1319 vkGetBufferMemoryRequirements(ctx->dev, bo->buf, &mem_reqs);
1320 /* VK_MEMORY_PROPERTY_HOST_COHERENT_BIT bit specifies that the
1321 * host cache management commands vkFlushMappedMemoryRanges and
1322 * vkInvalidateMappedMemoryRanges are not needed to flush host
1323 * writes to the device or make device writes visible to the
1324 * host, respectively. */
1325 bo->mobj.mem = alloc_memory(ctx, is_external, &mem_reqs, VK_NULL_HANDLE, VK_NULL_HANDLE,
1326 VK_MEMORY_PROPERTY_HOST_COHERENT_BIT |
1327 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
1329 if (bo->mobj.mem == VK_NULL_HANDLE)
1330 goto fail;
1332 bo->mobj.mem_sz = sz;
1334 if (vkBindBufferMemory(ctx->dev, bo->buf, bo->mobj.mem, 0) != VK_SUCCESS) {
1335 fprintf(stderr, "Failed to bind buffer memory.\n");
1336 goto fail;
1339 return true;
1341 fail:
1342 fprintf(stderr, "Failed to allocate buffer.\n");
1343 vk_destroy_buffer(ctx, bo);
1344 return false;
1347 bool
1348 vk_update_buffer_data(struct vk_ctx *ctx,
1349 void *data,
1350 uint32_t data_sz,
1351 struct vk_buf *bo)
1353 void *map;
1355 if (vkMapMemory(ctx->dev, bo->mobj.mem, 0, data_sz, 0, &map) != VK_SUCCESS) {
1356 fprintf(stderr, "Failed to map buffer memory.\n");
1357 goto fail;
1360 memcpy(map, data, data_sz);
1362 vkUnmapMemory(ctx->dev, bo->mobj.mem);
1363 return true;
1365 fail:
1366 fprintf(stderr, "Failed to update buffer data. Destroying the buffer.\n");
1367 vk_destroy_buffer(ctx, bo);
1369 return false;
1372 void
1373 vk_destroy_buffer(struct vk_ctx *ctx,
1374 struct vk_buf *bo)
1376 if (bo->buf != VK_NULL_HANDLE)
1377 vkDestroyBuffer(ctx->dev, bo->buf, 0);
1379 if (bo->mobj.mem != VK_NULL_HANDLE)
1380 vkFreeMemory(ctx->dev, bo->mobj.mem, 0);
1382 bo->mobj.mem_sz = 0;
1383 bo->buf = VK_NULL_HANDLE;
1384 bo->mobj.mem = VK_NULL_HANDLE;
1387 void
1388 vk_draw(struct vk_ctx *ctx,
1389 struct vk_buf *vbo,
1390 struct vk_renderer *renderer,
1391 float *vk_fb_color,
1392 uint32_t vk_fb_color_count,
1393 struct vk_semaphores *semaphores,
1394 bool has_wait, bool has_signal,
1395 struct vk_image_att *attachments,
1396 uint32_t n_attachments,
1397 float x, float y,
1398 float w, float h)
1400 VkCommandBufferBeginInfo cmd_begin_info;
1401 VkRenderPassBeginInfo rp_begin_info;
1402 VkRect2D rp_area;
1403 VkClearValue clear_values[2];
1404 VkSubmitInfo submit_info;
1405 VkDeviceSize offsets[] = {0};
1406 VkPipelineStageFlagBits stage_flags;
1407 struct vk_dims img_size;
1409 assert(vk_fb_color_count == 4);
1410 if (has_wait)
1411 assert(semaphores->gl_frame_done);
1412 if (has_signal)
1413 assert(semaphores->vk_frame_ready);
1415 /* VkCommandBufferBeginInfo */
1416 memset(&cmd_begin_info, 0, sizeof cmd_begin_info);
1417 cmd_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
1418 cmd_begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
1420 /* VkRect2D render area */
1421 memset(&rp_area, 0, sizeof rp_area);
1422 rp_area.extent.width = (uint32_t)w;
1423 rp_area.extent.height = (uint32_t)h;
1424 rp_area.offset.x = x;
1425 rp_area.offset.y = y;
1427 /* VkClearValue */
1428 memset(&clear_values[0], 0, sizeof clear_values[0]);
1429 clear_values[0].color.float32[0] = vk_fb_color[0]; /* red */
1430 clear_values[0].color.float32[1] = vk_fb_color[1]; /* green */
1431 clear_values[0].color.float32[2] = vk_fb_color[2]; /* blue */
1432 clear_values[0].color.float32[3] = vk_fb_color[3]; /* alpha */
1434 memset(&clear_values[1], 0, sizeof clear_values[1]);
1435 clear_values[1].depthStencil.depth = 1.0;
1436 clear_values[1].depthStencil.stencil = 0;
1438 /* VkRenderPassBeginInfo */
1439 memset(&rp_begin_info, 0, sizeof rp_begin_info);
1440 rp_begin_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
1441 rp_begin_info.renderPass = renderer->renderpass;
1442 rp_begin_info.framebuffer = renderer->fb;
1443 rp_begin_info.renderArea = rp_area;
1444 rp_begin_info.clearValueCount = 2;
1445 rp_begin_info.pClearValues = clear_values;
1447 /* VkSubmitInfo */
1448 stage_flags = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT;
1450 memset(&submit_info, 0, sizeof submit_info);
1451 submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
1452 submit_info.commandBufferCount = 1;
1453 submit_info.pCommandBuffers = &ctx->cmd_buf;
1454 if (has_wait) {
1455 submit_info.pWaitDstStageMask = &stage_flags;
1456 submit_info.waitSemaphoreCount = 1;
1457 submit_info.pWaitSemaphores = &semaphores->gl_frame_done;
1460 if (has_signal) {
1461 submit_info.signalSemaphoreCount = 1;
1462 submit_info.pSignalSemaphores = &semaphores->vk_frame_ready;
1465 vkBeginCommandBuffer(ctx->cmd_buf, &cmd_begin_info);
1466 vkCmdBeginRenderPass(ctx->cmd_buf, &rp_begin_info, VK_SUBPASS_CONTENTS_INLINE);
1468 viewport.x = x;
1469 viewport.y = y;
1470 viewport.width = w;
1471 viewport.height = h;
1473 scissor.offset.x = x;
1474 scissor.offset.y = y;
1475 scissor.extent.width = w;
1476 scissor.extent.height = h;
1478 vkCmdSetViewport(ctx->cmd_buf, 0, 1, &viewport);
1479 vkCmdSetScissor(ctx->cmd_buf, 0, 1, &scissor);
1481 img_size.w = (float)w;
1482 img_size.h = (float)h;
1483 vkCmdPushConstants(ctx->cmd_buf,
1484 renderer->pipeline_layout,
1485 VK_SHADER_STAGE_FRAGMENT_BIT,
1486 0, sizeof (struct vk_dims),
1487 &img_size);
1489 if (vbo) {
1490 vkCmdBindVertexBuffers(ctx->cmd_buf, 0, 1, &vbo->buf, offsets);
1492 vkCmdBindPipeline(ctx->cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS, renderer->pipeline);
1494 int num_vertices = vbo ? renderer->vertex_info.num_verts : 4;
1495 vkCmdDraw(ctx->cmd_buf, num_vertices, 1, 0, 0);
1497 vkCmdEndRenderPass(ctx->cmd_buf);
1498 if (attachments) {
1499 VkImageMemoryBarrier *barriers =
1500 calloc(n_attachments, sizeof(VkImageMemoryBarrier));
1501 VkImageMemoryBarrier *barrier = barriers;
1502 for (uint32_t n = 0; n < n_attachments; n++, barrier++) {
1503 struct vk_image_att *att = &attachments[n];
1504 VkImageAspectFlagBits depth_stencil_flags =
1505 get_aspect_from_depth_format(att->props.format);
1506 bool is_depth = (depth_stencil_flags != 0);
1508 /* Insert barrier to mark ownership transfer. */
1509 barrier->sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
1510 barrier->oldLayout = is_depth ?
1511 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL :
1512 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
1513 barrier->newLayout = VK_IMAGE_LAYOUT_GENERAL;
1514 barrier->srcAccessMask = get_access_mask(barrier->oldLayout);
1515 barrier->dstAccessMask = get_access_mask(barrier->newLayout);
1516 barrier->srcQueueFamilyIndex = ctx->qfam_idx;
1517 barrier->dstQueueFamilyIndex = VK_QUEUE_FAMILY_EXTERNAL;
1518 barrier->image = att->obj.img;
1519 barrier->subresourceRange.aspectMask = is_depth ?
1520 depth_stencil_flags :
1521 VK_IMAGE_ASPECT_COLOR_BIT;
1522 barrier->subresourceRange.baseMipLevel = 0;
1523 barrier->subresourceRange.levelCount = 1;
1524 barrier->subresourceRange.baseArrayLayer = 0;
1525 barrier->subresourceRange.layerCount = 1;
1528 vkCmdPipelineBarrier(ctx->cmd_buf,
1529 VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
1530 VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
1532 0, NULL,
1533 0, NULL,
1534 n_attachments, barriers);
1535 free(barriers);
1537 vkEndCommandBuffer(ctx->cmd_buf);
1539 if (vkQueueSubmit(ctx->queue, 1, &submit_info, VK_NULL_HANDLE) != VK_SUCCESS) {
1540 fprintf(stderr, "Failed to submit queue.\n");
1543 /* FIXME */
1544 if (!semaphores && !has_wait && !has_signal)
1545 vkQueueWaitIdle(ctx->queue);
1548 void
1549 vk_clear_color(struct vk_ctx *ctx,
1550 struct vk_buf *vbo,
1551 struct vk_renderer *renderer,
1552 float *vk_fb_color,
1553 uint32_t vk_fb_color_count,
1554 struct vk_semaphores *semaphores,
1555 bool has_wait, bool has_signal,
1556 struct vk_image_att *attachments,
1557 uint32_t n_attachments,
1558 float x, float y,
1559 float w, float h)
1561 VkCommandBufferBeginInfo cmd_begin_info;
1562 VkRenderPassBeginInfo rp_begin_info;
1563 VkRect2D rp_area;
1564 VkClearValue clear_values[2];
1565 VkSubmitInfo submit_info;
1566 VkPipelineStageFlagBits stage_flags;
1567 VkImageSubresourceRange img_range;
1569 assert(vk_fb_color_count == 4);
1571 if (has_wait)
1572 assert(semaphores->gl_frame_done);
1573 if (has_signal)
1574 assert(semaphores->vk_frame_ready);
1576 /* VkCommandBufferBeginInfo */
1577 memset(&cmd_begin_info, 0, sizeof cmd_begin_info);
1578 cmd_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
1579 cmd_begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
1581 /* VkRect2D render area */
1582 memset(&rp_area, 0, sizeof rp_area);
1583 rp_area.extent.width = (uint32_t)w;
1584 rp_area.extent.height = (uint32_t)h;
1585 rp_area.offset.x = x;
1586 rp_area.offset.y = y;
1588 /* VkClearValue */
1589 memset(&clear_values[0], 0, sizeof clear_values[0]);
1590 clear_values[0].color.float32[0] = vk_fb_color[0]; /* red */
1591 clear_values[0].color.float32[1] = vk_fb_color[1]; /* green */
1592 clear_values[0].color.float32[2] = vk_fb_color[2]; /* blue */
1593 clear_values[0].color.float32[3] = vk_fb_color[3]; /* alpha */
1595 memset(&clear_values[1], 0, sizeof clear_values[1]);
1596 clear_values[1].depthStencil.depth = 1.0;
1597 clear_values[1].depthStencil.stencil = 0;
1599 /* VkRenderPassBeginInfo */
1600 memset(&rp_begin_info, 0, sizeof rp_begin_info);
1601 rp_begin_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
1602 rp_begin_info.renderPass = renderer->renderpass;
1603 rp_begin_info.framebuffer = renderer->fb;
1604 rp_begin_info.renderArea = rp_area;
1605 rp_begin_info.clearValueCount = 2;
1606 rp_begin_info.pClearValues = clear_values;
1608 /* VkSubmitInfo */
1609 stage_flags = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT;
1611 memset(&submit_info, 0, sizeof submit_info);
1612 submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
1613 submit_info.commandBufferCount = 1;
1614 submit_info.pCommandBuffers = &ctx->cmd_buf;
1615 if (has_wait) {
1616 submit_info.pWaitDstStageMask = &stage_flags;
1617 submit_info.waitSemaphoreCount = 1;
1618 submit_info.pWaitSemaphores = &semaphores->gl_frame_done;
1621 if (has_signal) {
1622 submit_info.signalSemaphoreCount = 1;
1623 submit_info.pSignalSemaphores = &semaphores->vk_frame_ready;
1626 img_range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
1627 img_range.baseMipLevel = 0;
1628 img_range.levelCount = 1;
1629 img_range.baseArrayLayer = 0;
1630 img_range.layerCount = 1;
1632 vkBeginCommandBuffer(ctx->cmd_buf, &cmd_begin_info);
1633 vk_transition_image_layout(&attachments[0],
1634 ctx->cmd_buf,
1635 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
1636 VK_IMAGE_LAYOUT_GENERAL,
1637 VK_QUEUE_FAMILY_EXTERNAL,
1638 ctx->qfam_idx);
1639 vkCmdClearColorImage(ctx->cmd_buf,
1640 attachments[0].obj.img,
1641 VK_IMAGE_LAYOUT_GENERAL,
1642 &clear_values[0].color,
1644 &img_range);
1646 vkCmdBeginRenderPass(ctx->cmd_buf, &rp_begin_info, VK_SUBPASS_CONTENTS_INLINE);
1648 viewport.x = x;
1649 viewport.y = y;
1650 viewport.width = w;
1651 viewport.height = h;
1653 scissor.offset.x = x;
1654 scissor.offset.y = y;
1655 scissor.extent.width = w;
1656 scissor.extent.height = h;
1658 vkCmdSetViewport(ctx->cmd_buf, 0, 1, &viewport);
1659 vkCmdSetScissor(ctx->cmd_buf, 0, 1, &scissor);
1661 vkCmdBindPipeline(ctx->cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS, renderer->pipeline);
1663 vkCmdEndRenderPass(ctx->cmd_buf);
1665 VkImageMemoryBarrier *barriers =
1666 calloc(n_attachments, sizeof(VkImageMemoryBarrier));
1667 VkImageMemoryBarrier *barrier = barriers;
1669 for (uint32_t n = 0; n < n_attachments; n++, barrier++) {
1670 struct vk_image_att *att = &attachments[n];
1672 /* Insert barrier to mark ownership transfer. */
1673 barrier->sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
1675 bool is_depth =
1676 get_aspect_from_depth_format(att->props.format) != VK_NULL_HANDLE;
1678 barrier->oldLayout = is_depth ?
1679 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL :
1680 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
1681 barrier->newLayout = VK_IMAGE_LAYOUT_GENERAL;
1682 barrier->srcAccessMask = get_access_mask(barrier->oldLayout);
1683 barrier->dstAccessMask = get_access_mask(barrier->newLayout);
1684 barrier->srcQueueFamilyIndex = ctx->qfam_idx;
1685 barrier->dstQueueFamilyIndex = VK_QUEUE_FAMILY_EXTERNAL;
1686 barrier->image = att->obj.img;
1687 barrier->subresourceRange.aspectMask = is_depth ?
1688 VK_IMAGE_ASPECT_DEPTH_BIT :
1689 VK_IMAGE_ASPECT_COLOR_BIT;
1690 barrier->subresourceRange.baseMipLevel = 0;
1691 barrier->subresourceRange.levelCount = 1;
1692 barrier->subresourceRange.baseArrayLayer = 0;
1693 barrier->subresourceRange.layerCount = 1;
1696 vkCmdPipelineBarrier(ctx->cmd_buf,
1697 VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
1698 VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
1700 0, NULL,
1701 0, NULL,
1702 n_attachments, barriers);
1703 free(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);
1715 void
1716 vk_copy_image_to_buffer(struct vk_ctx *ctx,
1717 struct vk_image_att *src_img,
1718 struct vk_buf *dst_bo,
1719 float w, float h)
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,
1738 ctx->cmd_buf,
1739 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
1740 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
1741 VK_QUEUE_FAMILY_EXTERNAL,
1742 ctx->qfam_idx);
1744 /* copy image to buf */
1745 VkBufferImageCopy copy_region = {
1746 .bufferOffset = 0,
1747 .bufferRowLength = w,
1748 .bufferImageHeight = h,
1749 .imageSubresource = {
1750 .aspectMask = aspect_mask ? aspect_mask : VK_IMAGE_ASPECT_COLOR_BIT,
1751 .mipLevel = 0,
1752 .baseArrayLayer = 0,
1753 .layerCount = 1,
1755 .imageOffset = { 0, 0, 0 },
1756 .imageExtent = { w, h, 1 }
1759 vkCmdCopyImageToBuffer(ctx->cmd_buf,
1760 src_img->obj.img,
1761 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
1762 dst_bo->buf, 1, &copy_region);
1764 vk_transition_image_layout(src_img,
1765 ctx->cmd_buf,
1766 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
1767 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
1768 VK_QUEUE_FAMILY_EXTERNAL,
1769 ctx->qfam_idx);
1771 VkBufferMemoryBarrier write_finish_buffer_memory_barrier = {
1772 .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
1773 .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
1774 .dstAccessMask = VK_ACCESS_HOST_READ_BIT,
1775 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_EXTERNAL,
1776 .dstQueueFamilyIndex = ctx->qfam_idx,
1777 .buffer = dst_bo->buf,
1778 .offset = 0,
1779 .size = VK_WHOLE_SIZE
1782 vkCmdPipelineBarrier(ctx->cmd_buf,
1783 VK_PIPELINE_STAGE_TRANSFER_BIT,
1784 VK_PIPELINE_STAGE_HOST_BIT,
1785 (VkDependencyFlags) 0, 0, NULL,
1786 1, &write_finish_buffer_memory_barrier,
1787 0, NULL);
1789 vkEndCommandBuffer(ctx->cmd_buf);
1791 if (vkQueueSubmit(ctx->queue, 1, &submit_info, VK_NULL_HANDLE) != VK_SUCCESS) {
1792 fprintf(stderr, "Failed to submit queue.\n");
1794 vkQueueWaitIdle(ctx->queue);
1797 bool
1798 vk_create_semaphores(struct vk_ctx *ctx,
1799 struct vk_semaphores *semaphores)
1801 VkSemaphoreCreateInfo sema_info;
1802 VkExportSemaphoreCreateInfo exp_sema_info;
1804 /* VkExportSemaphoreCreateInfo */
1805 memset(&exp_sema_info, 0, sizeof exp_sema_info);
1806 exp_sema_info.sType = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO;
1807 exp_sema_info.handleTypes = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;
1809 /* VkSemaphoreCreateInfo */
1810 memset(&sema_info, 0, sizeof sema_info);
1811 sema_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
1812 sema_info.pNext = &exp_sema_info;
1814 if (vkCreateSemaphore(ctx->dev, &sema_info, 0, &semaphores->vk_frame_ready) != VK_SUCCESS) {
1815 fprintf(stderr, "Failed to create semaphore vk_frame_ready.\n");
1816 return false;
1819 if (vkCreateSemaphore(ctx->dev, &sema_info, 0, &semaphores->gl_frame_done) != VK_SUCCESS) {
1820 fprintf(stderr, "Failed to create semaphore gl_frame_done.\n");
1821 return false;
1824 return true;
1827 void
1828 vk_destroy_semaphores(struct vk_ctx *ctx,
1829 struct vk_semaphores *semaphores)
1831 if (semaphores->vk_frame_ready)
1832 vkDestroySemaphore(ctx->dev, semaphores->vk_frame_ready, 0);
1833 if (semaphores->gl_frame_done)
1834 vkDestroySemaphore(ctx->dev, semaphores->gl_frame_done, 0);
1837 void
1838 vk_transition_image_layout(struct vk_image_att *img_att,
1839 VkCommandBuffer cmd_buf,
1840 VkImageLayout old_layout,
1841 VkImageLayout new_layout,
1842 uint32_t src_queue_fam_idx,
1843 uint32_t dst_queue_fam_idx)
1845 VkImageMemoryBarrier barrier;
1846 struct vk_image_props props = img_att->props;
1847 VkImageAspectFlagBits aspect_mask = get_aspect_from_depth_format(props.format);
1849 memset(&barrier, 0, sizeof barrier);
1850 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
1851 barrier.srcAccessMask = get_access_mask(old_layout);
1852 barrier.dstAccessMask = get_access_mask(new_layout);
1853 barrier.oldLayout = old_layout;
1854 barrier.newLayout = new_layout;
1855 barrier.srcQueueFamilyIndex = src_queue_fam_idx;
1856 barrier.dstQueueFamilyIndex = dst_queue_fam_idx;
1857 barrier.image = img_att->obj.img;
1858 barrier.subresourceRange.aspectMask = aspect_mask ? aspect_mask : VK_IMAGE_ASPECT_COLOR_BIT;
1859 barrier.subresourceRange.levelCount = 1;
1860 barrier.subresourceRange.layerCount = 1;
1862 vkCmdPipelineBarrier(cmd_buf,
1863 get_pipeline_stage_flags(old_layout),
1864 get_pipeline_stage_flags(new_layout),
1865 0, 0, VK_NULL_HANDLE, 0, VK_NULL_HANDLE, 1, &barrier);