fbo-mrt-alphatest: Actually require MRTs to be available.
[piglit.git] / tests / spec / ext_external_objects / vk.c
blobd5ff36097e3e6c4a1bc19059ea52fa4fa4cfc2ea
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);
167 fam_props = malloc(prop_count * sizeof *fam_props);
168 vkGetPhysicalDeviceQueueFamilyProperties(pdev, &prop_count, fam_props);
170 for (i = 0; i < prop_count; i++) {
171 if (fam_props[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
172 ctx->qfam_idx = i;
173 break;
176 free(fam_props);
178 memset(&dev_queue_info, 0, sizeof dev_queue_info);
179 dev_queue_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
180 dev_queue_info.queueFamilyIndex = ctx->qfam_idx;
181 dev_queue_info.queueCount = 1;
182 dev_queue_info.pQueuePriorities = &qprio;
184 memset(&dev_info, 0, sizeof dev_info);
185 dev_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
186 dev_info.queueCreateInfoCount = 1;
187 dev_info.pQueueCreateInfos = &dev_queue_info;
188 dev_info.enabledExtensionCount = ARRAY_SIZE(deviceExtensions);
189 dev_info.ppEnabledExtensionNames = deviceExtensions;
191 if (vkCreateDevice(pdev, &dev_info, 0, &dev) != VK_SUCCESS)
192 return VK_NULL_HANDLE;
194 return dev;
197 static void
198 fill_uuid(VkPhysicalDevice pdev, uint8_t *deviceUUID, uint8_t *driverUUID)
200 VkPhysicalDeviceIDProperties devProp;
201 VkPhysicalDeviceProperties2 prop2;
203 memset(&devProp, 0, sizeof devProp);
204 devProp.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES;
206 memset(&prop2, 0, sizeof prop2);
207 prop2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
208 prop2.pNext = &devProp;
210 vkGetPhysicalDeviceProperties2(pdev, &prop2);
211 memcpy(deviceUUID, devProp.deviceUUID, VK_UUID_SIZE);
212 memcpy(driverUUID, devProp.driverUUID, VK_UUID_SIZE);
215 static VkCommandPool
216 create_cmd_pool(struct vk_ctx *ctx)
218 VkCommandPoolCreateInfo cmd_pool_info;
219 VkCommandPool cmd_pool;
220 VkDevice dev = ctx->dev;
222 memset(&cmd_pool_info, 0, sizeof cmd_pool_info);
223 cmd_pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
224 cmd_pool_info.queueFamilyIndex = ctx->qfam_idx;
225 cmd_pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
227 if (vkCreateCommandPool(dev, &cmd_pool_info, 0, &cmd_pool) != VK_SUCCESS)
228 return VK_NULL_HANDLE;
230 return cmd_pool;
233 static VkRenderPass
234 create_renderpass(struct vk_ctx *ctx,
235 struct vk_image_props *color_img_props,
236 struct vk_image_props *depth_img_props)
238 uint32_t num_attachments = depth_img_props ? 2 : 1;
239 VkAttachmentDescription att_dsc[2];
240 VkAttachmentReference att_rfc[2];
241 VkSubpassDescription subpass_dsc[1];
242 VkRenderPassCreateInfo rpass_info;
244 /* VkAttachmentDescription */
245 memset(att_dsc, 0, num_attachments * sizeof att_dsc[0]);
247 att_dsc[0].samples = get_num_samples(color_img_props->num_samples);
248 att_dsc[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
249 att_dsc[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
250 att_dsc[0].initialLayout = color_img_props->in_layout;
251 att_dsc[0].finalLayout = color_img_props->end_layout;
252 att_dsc[0].format = color_img_props->format;
253 att_dsc[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
254 att_dsc[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
256 if (depth_img_props) {
258 att_dsc[1].samples = get_num_samples(depth_img_props->num_samples);
259 /* We might want to reuse a depth buffer */
260 if (depth_img_props->in_layout != VK_IMAGE_LAYOUT_UNDEFINED) {
261 att_dsc[1].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
262 att_dsc[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
264 else {
265 att_dsc[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
266 att_dsc[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
268 att_dsc[1].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
269 att_dsc[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
270 att_dsc[1].initialLayout = depth_img_props->in_layout;
271 att_dsc[1].finalLayout = depth_img_props->end_layout;
272 att_dsc[1].format = depth_img_props->format;
275 /* VkAttachmentReference */
276 memset(att_rfc, 0, num_attachments * sizeof att_rfc[0]);
278 att_rfc[0].layout = color_img_props->tiling == VK_IMAGE_TILING_OPTIMAL ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_GENERAL;
279 att_rfc[0].attachment = 0;
281 if (depth_img_props) {
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;
286 /* VkSubpassDescription */
287 memset(&subpass_dsc, 0, sizeof subpass_dsc);
288 subpass_dsc[0].pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
289 subpass_dsc[0].colorAttachmentCount = 1;
290 subpass_dsc[0].pColorAttachments = &att_rfc[0];
292 if (depth_img_props) {
293 subpass_dsc[0].pDepthStencilAttachment = &att_rfc[1];
296 /* VkRenderPassCreateInfo */
297 memset(&rpass_info, 0, sizeof rpass_info);
298 rpass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
299 rpass_info.attachmentCount = num_attachments;
300 rpass_info.pAttachments = att_dsc;
301 rpass_info.subpassCount = 1;
302 rpass_info.pSubpasses = subpass_dsc;
304 VkRenderPass rpass;
305 if (vkCreateRenderPass(ctx->dev, &rpass_info, 0, &rpass) != VK_SUCCESS) {
306 fprintf(stderr, "Failed to create renderpass.\n");
307 rpass = VK_NULL_HANDLE;
310 return rpass;
313 static inline VkImageType
314 get_image_type(uint32_t h, uint32_t d)
316 if (h == 1)
317 return VK_IMAGE_TYPE_1D;
319 if (d > 1)
320 return VK_IMAGE_TYPE_3D;
322 return VK_IMAGE_TYPE_2D;
325 static VkImageViewType
326 get_image_view_type(struct vk_image_props *props)
328 VkImageType type = get_image_type(props->h, props->depth);
329 switch(type) {
330 case VK_IMAGE_TYPE_1D:
331 return props->num_layers > 1 ?
332 VK_IMAGE_VIEW_TYPE_1D_ARRAY :
333 VK_IMAGE_VIEW_TYPE_1D;
334 case VK_IMAGE_TYPE_2D:
335 if (props->num_layers == 1)
336 return VK_IMAGE_VIEW_TYPE_2D;
337 if (props->num_layers == 6)
338 return VK_IMAGE_VIEW_TYPE_CUBE;
339 if (props->num_layers % 6 == 0)
340 return VK_IMAGE_VIEW_TYPE_CUBE_ARRAY;
341 if (props->num_layers > 1)
342 return VK_IMAGE_VIEW_TYPE_2D_ARRAY;
343 case VK_IMAGE_TYPE_3D:
344 if (props->num_layers == 1)
345 return VK_IMAGE_VIEW_TYPE_3D;
346 if ((props->num_layers == 1) &&
347 (props->num_levels == 1))
348 return VK_IMAGE_VIEW_TYPE_2D;
349 if ((props->num_levels == 1) &&
350 (props->num_layers > 1))
351 return VK_IMAGE_VIEW_TYPE_2D_ARRAY;
352 default:
353 return VK_IMAGE_VIEW_TYPE_2D;
357 static VkImageAspectFlagBits
358 get_aspect_from_depth_format(VkFormat depth_format)
360 switch (depth_format) {
361 case VK_FORMAT_D16_UNORM:
362 case VK_FORMAT_X8_D24_UNORM_PACK32:
363 case VK_FORMAT_D32_SFLOAT:
364 return VK_IMAGE_ASPECT_DEPTH_BIT;
365 case VK_FORMAT_S8_UINT:
366 return VK_IMAGE_ASPECT_STENCIL_BIT;
367 case VK_FORMAT_D16_UNORM_S8_UINT:
368 case VK_FORMAT_D24_UNORM_S8_UINT:
369 case VK_FORMAT_D32_SFLOAT_S8_UINT:
370 return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
371 default:
372 break;
374 return 0;
377 static VkPipelineStageFlags
378 get_pipeline_stage_flags(const VkImageLayout layout)
380 switch (layout) {
381 case VK_IMAGE_LAYOUT_UNDEFINED:
382 return VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
383 case VK_IMAGE_LAYOUT_GENERAL:
384 return VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
385 case VK_IMAGE_LAYOUT_PREINITIALIZED:
386 return VK_PIPELINE_STAGE_HOST_BIT;
387 case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
388 case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
389 return VK_PIPELINE_STAGE_TRANSFER_BIT;
390 case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
391 return VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
392 case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
393 return VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
394 VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
395 case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR:
396 return VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
397 default:
398 return 0;
400 return 0;
403 static void
404 create_framebuffer(struct vk_ctx *ctx,
405 struct vk_image_att *color_att,
406 struct vk_image_att *depth_att,
407 struct vk_renderer *renderer)
409 VkImageSubresourceRange sr;
410 VkImageViewCreateInfo color_info;
411 VkImageViewCreateInfo depth_info;
412 VkFramebufferCreateInfo fb_info;
413 VkImageViewType view_type = get_image_view_type(&color_att->props);
414 VkImageView atts[2];
416 if (!color_att->obj.img || (depth_att && !depth_att->obj.img)) {
417 fprintf(stderr, "Invalid framebuffer attachment image.\n");
418 goto fail;
421 /* create image views */
423 /* VKImageSubresourceRange */
424 memset(&sr, 0, sizeof sr);
425 sr.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
426 /* If an application wants to use all mip levels
427 * or layers in an image after the baseMipLevel
428 * or baseArrayLayer, it can set levelCount and
429 * layerCount to the special values
430 * VK_REMAINING_MIP_LEVELS and
431 * VK_REMAINING_ARRAY_LAYERS without knowing the
432 * exact number of mip levels or layers.
434 sr.baseMipLevel = 0;
435 sr.levelCount = color_att->props.num_levels;
436 sr.baseArrayLayer = 0;
437 sr.layerCount = color_att->props.num_layers;
439 /* color view */
440 memset(&color_info, 0, sizeof color_info);
441 color_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
442 color_info.image = color_att->obj.img;
443 color_info.viewType = view_type;
444 color_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
445 color_info.format = color_att->props.format;
446 color_info.subresourceRange = sr;
448 if (vkCreateImageView(ctx->dev, &color_info, 0, &color_att->obj.img_view) != VK_SUCCESS) {
449 fprintf(stderr, "Failed to create color image view for framebuffer.\n");
450 vk_destroy_ext_image(ctx, &color_att->obj);
451 goto fail;
454 if (depth_att) {
455 /* depth view */
456 memset(&sr, 0, sizeof sr);
457 sr.aspectMask = get_aspect_from_depth_format(depth_att->props.format);
458 sr.baseMipLevel = 0;
459 sr.levelCount = depth_att->props.num_levels ? depth_att->props.num_levels : 1;
460 sr.baseArrayLayer = 0;
461 sr.layerCount = depth_att->props.num_layers ? depth_att->props.num_layers : 1;
463 memset(&depth_info, 0, sizeof depth_info);
464 depth_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
465 depth_info.image = depth_att->obj.img;
466 depth_info.viewType = depth_att->props.num_layers > 1 ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D;
467 depth_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
468 depth_info.format = depth_att->props.format;
469 depth_info.subresourceRange = sr;
471 if (vkCreateImageView(ctx->dev, &depth_info, 0, &depth_att->obj.img_view) != VK_SUCCESS) {
472 fprintf(stderr, "Failed to create depth image view for framebuffer.\n");
473 vk_destroy_ext_image(ctx, &depth_att->obj);
474 goto fail;
478 atts[0] = color_att->obj.img_view;
480 if (depth_att)
481 atts[1] = depth_att->obj.img_view;
483 memset(&fb_info, 0, sizeof fb_info);
484 fb_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
485 fb_info.renderPass = renderer->renderpass;
486 fb_info.width = color_att->props.w;
487 fb_info.height = color_att->props.h;
488 fb_info.layers = color_att->props.num_layers ? color_att->props.num_layers : 1;
489 fb_info.attachmentCount = depth_att ? 2 : 1;
490 fb_info.pAttachments = atts;
492 if (vkCreateFramebuffer(ctx->dev, &fb_info, 0, &renderer->fb) != VK_SUCCESS)
493 goto fail;
495 return;
497 fail:
498 fprintf(stderr, "Failed to create framebuffer.\n");
499 renderer->fb = VK_NULL_HANDLE;
502 static VkShaderModule
503 create_shader_module(struct vk_ctx *ctx,
504 const char *src,
505 unsigned int size)
507 VkShaderModuleCreateInfo sm_info;
508 VkShaderModule sm;
510 /* VkShaderModuleCreateInfo */
511 memset(&sm_info, 0, sizeof sm_info);
512 sm_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
513 sm_info.codeSize = size;
514 sm_info.pCode = (void*)src;
516 if (vkCreateShaderModule(ctx->dev, &sm_info, 0, &sm) != VK_SUCCESS) {
517 fprintf(stderr, "Failed to create shader module.\n");
518 sm = VK_NULL_HANDLE;
521 return sm;
524 static void
525 create_pipeline(struct vk_ctx *ctx,
526 uint32_t width,
527 uint32_t height,
528 uint32_t num_samples,
529 bool enable_depth,
530 bool enable_stencil,
531 struct vk_renderer *renderer)
533 VkVertexInputBindingDescription vert_bind_dsc[1];
534 VkVertexInputAttributeDescription vert_att_dsc[1];
536 VkPipelineColorBlendAttachmentState cb_att_state[1];
537 VkPipelineVertexInputStateCreateInfo vert_input_info;
538 VkPipelineInputAssemblyStateCreateInfo asm_info;
539 VkPipelineViewportStateCreateInfo viewport_info;
540 VkPipelineRasterizationStateCreateInfo rs_info;
541 VkPipelineMultisampleStateCreateInfo ms_info;
542 VkPipelineDepthStencilStateCreateInfo ds_info;
543 VkPipelineColorBlendStateCreateInfo cb_info;
544 VkPipelineShaderStageCreateInfo sdr_stages[2];
545 VkPipelineLayoutCreateInfo layout_info;
546 VkGraphicsPipelineCreateInfo pipeline_info;
547 VkFormat format;
548 VkFormatProperties fmt_props;
549 VkPushConstantRange pc_range[1];
551 VkStencilOpState front;
552 VkStencilOpState back;
553 int i;
554 VkPipelineLayout pipeline_layout;
555 uint32_t stride;
557 /* format of vertex attributes:
558 * we have 2D vectors so we need a RG format:
559 * R for x, G for y
560 * the stride (distance between 2 consecutive elements)
561 * must be 8 because we use 32 bit floats and
562 * 32bits = 8bytes */
563 format = VK_FORMAT_R32G32_SFLOAT;
564 vkGetPhysicalDeviceFormatProperties(ctx->pdev, format, &fmt_props);
565 assert(fmt_props.bufferFeatures & VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT);
566 stride = 8;
568 /* VkVertexInputAttributeDescription */
569 memset(&vert_att_dsc, 0, sizeof vert_att_dsc);
570 vert_att_dsc[0].location = 0;
571 vert_att_dsc[0].binding = 0;
572 vert_att_dsc[0].format = format; /* see comment */
573 vert_att_dsc[0].offset = 0;
575 /* VkVertexInputBindingDescription */
576 memset(&vert_bind_dsc, 0, sizeof vert_bind_dsc);
577 vert_bind_dsc[0].binding = 0;
578 vert_bind_dsc[0].stride = stride;
579 vert_bind_dsc[0].inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
581 /* If using vbo, we have setup vertex_info in the renderer. */
582 bool use_vbo = renderer->vertex_info.num_verts > 0;
584 /* VkPipelineVertexInputStateCreateInfo */
585 memset(&vert_input_info, 0, sizeof vert_input_info);
586 vert_input_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
587 vert_input_info.vertexBindingDescriptionCount = use_vbo ? 1 : 0;
588 vert_input_info.pVertexBindingDescriptions = vert_bind_dsc;
589 vert_input_info.vertexAttributeDescriptionCount = use_vbo ? 1 : 0;
590 vert_input_info.pVertexAttributeDescriptions = vert_att_dsc;
592 /* VkPipelineInputAssemblyStateCreateInfo */
593 memset(&asm_info, 0, sizeof asm_info);
594 asm_info.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
595 asm_info.topology = renderer->vertex_info.topology ?
596 renderer->vertex_info.topology : VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
597 asm_info.primitiveRestartEnable = false;
599 /* VkViewport */
600 viewport.x = viewport.y = 0;
601 viewport.width = width;
602 viewport.height = height;
603 viewport.minDepth = 0;
604 viewport.maxDepth = 1;
606 /* VkRect2D scissor */
607 scissor.offset.x = scissor.offset.y = 0;
608 scissor.extent.width = width;
609 scissor.extent.height = height;
611 /* VkPipelineViewportStateCreateInfo */
612 memset(&viewport_info, 0, sizeof viewport_info);
613 viewport_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
614 viewport_info.viewportCount = 1;
615 viewport_info.pViewports = &viewport;
616 viewport_info.scissorCount = 1;
617 viewport_info.pScissors = &scissor;
619 /* VkPipelineRasterizationStateCreateInfo */
620 memset(&rs_info, 0, sizeof rs_info);
621 rs_info.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
622 rs_info.polygonMode = VK_POLYGON_MODE_FILL;
623 rs_info.cullMode = VK_CULL_MODE_NONE;
624 rs_info.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
625 rs_info.lineWidth = 1.0;
627 /* VkPipelineMultisampleStateCreateInfo */
628 memset(&ms_info, 0, sizeof ms_info);
629 ms_info.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
630 ms_info.rasterizationSamples = num_samples;
632 /* VkStencilOpState */
633 /* The default values for ES are taken by Topi Pohjolainen's code */
634 /* defaults in OpenGL ES 3.1 */
635 memset(&front, 0, sizeof front);
636 front.compareMask = ~0;
637 front.writeMask = ~0;
638 front.reference = 0;
640 memset(&back, 0, sizeof back);
642 /* VkPipelineDepthStencilStateCreateInfo */
643 memset(&ds_info, 0, sizeof ds_info);
644 ds_info.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
645 ds_info.front = front;
646 ds_info.back = back;
647 /* defaults in OpenGL ES 3.1 */
648 ds_info.minDepthBounds = 0;
649 ds_info.maxDepthBounds = 1;
650 /* z buffer, stencil buffer */
651 if (enable_depth) {
652 ds_info.depthTestEnable = VK_TRUE;
653 ds_info.depthWriteEnable = VK_TRUE;
654 ds_info.depthCompareOp = VK_COMPARE_OP_LESS;
656 if (enable_stencil) {
657 ds_info.stencilTestEnable = VK_TRUE;
658 ds_info.depthTestEnable = VK_FALSE;
659 ds_info.depthWriteEnable = VK_TRUE;
662 /* we only care about the passOp here */
663 ds_info.back.compareOp = VK_COMPARE_OP_ALWAYS;
664 ds_info.back.failOp = VK_STENCIL_OP_REPLACE;
665 ds_info.back.depthFailOp = VK_STENCIL_OP_REPLACE;
666 ds_info.back.passOp = VK_STENCIL_OP_REPLACE;
667 ds_info.back.compareMask = 0xffffffff;
668 ds_info.back.writeMask = 0xffffffff;
669 ds_info.back.reference = 1;
670 ds_info.front = ds_info.back;
672 /* VkPipelineColorBlendAttachmentState */
673 memset(&cb_att_state[0], 0, sizeof cb_att_state[0]);
674 cb_att_state[0].colorWriteMask = (VK_COLOR_COMPONENT_R_BIT |
675 VK_COLOR_COMPONENT_G_BIT |
676 VK_COLOR_COMPONENT_B_BIT |
677 VK_COLOR_COMPONENT_A_BIT);
679 /* VkPipelineColorBlendStateCreateInfo */
680 memset(&cb_info, 0, sizeof cb_info);
681 cb_info.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
682 cb_info.attachmentCount = 1;
683 cb_info.pAttachments = cb_att_state;
684 /* default in ES 3.1 */
685 for (i = 0; i < 4; i++) {
686 cb_info.blendConstants[i] = 0.0f;
689 /* VkPipelineShaderStageCreateInfo */
690 memset(sdr_stages, 0, 2 * sizeof sdr_stages[0]);
692 sdr_stages[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
693 sdr_stages[0].stage = VK_SHADER_STAGE_VERTEX_BIT;
694 sdr_stages[0].module = renderer->vs;
695 sdr_stages[0].pName = "main";
697 sdr_stages[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
698 sdr_stages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT;
699 sdr_stages[1].module = renderer->fs;
700 sdr_stages[1].pName = "main";
702 /* VkPushConstantRange */
703 memset(pc_range, 0, sizeof pc_range[0]);
704 pc_range[0].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
705 pc_range[0].size = sizeof (struct vk_dims); /* w, h */
707 /* VkPipelineLayoutCreateInfo */
708 memset(&layout_info, 0, sizeof layout_info);
709 layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
710 layout_info.pushConstantRangeCount = 1;
711 layout_info.pPushConstantRanges = pc_range;
713 if (vkCreatePipelineLayout(ctx->dev, &layout_info, 0, &pipeline_layout) != VK_SUCCESS) {
714 fprintf(stderr, "Failed to create pipeline layout\n");
715 renderer->pipeline = VK_NULL_HANDLE;
716 return;
719 renderer->pipeline_layout = pipeline_layout;
721 /* VkGraphicsPipelineCreateInfo */
722 memset(&pipeline_info, 0, sizeof pipeline_info);
723 pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
724 pipeline_info.layout = pipeline_layout;
725 pipeline_info.renderPass = renderer->renderpass;
726 pipeline_info.pVertexInputState = &vert_input_info;
727 pipeline_info.pInputAssemblyState = &asm_info;
728 pipeline_info.pViewportState = &viewport_info;
729 pipeline_info.pRasterizationState = &rs_info;
730 pipeline_info.pMultisampleState = &ms_info;
731 pipeline_info.pDepthStencilState = &ds_info;
732 pipeline_info.pColorBlendState = &cb_info;
733 pipeline_info.stageCount = 2;
734 pipeline_info.pStages = sdr_stages;
736 if (vkCreateGraphicsPipelines(ctx->dev, 0, 1,
737 &pipeline_info, 0, &renderer->pipeline) !=
738 VK_SUCCESS) {
739 fprintf(stderr, "Failed to create graphics pipeline.\n");
740 renderer->pipeline = VK_NULL_HANDLE;
744 static VkCommandBuffer
745 create_cmd_buf(VkDevice dev, VkCommandPool cmd_pool)
747 VkCommandBuffer cmd_buf;
748 VkCommandBufferAllocateInfo alloc_info;
750 memset(&alloc_info, 0, sizeof alloc_info);
751 alloc_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
752 alloc_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
753 alloc_info.commandBufferCount = 1;
754 alloc_info.commandPool = cmd_pool;
756 if (vkAllocateCommandBuffers(dev, &alloc_info, &cmd_buf) != VK_SUCCESS)
757 return VK_NULL_HANDLE;
759 return cmd_buf;
762 static uint32_t
763 get_memory_type_idx(VkPhysicalDevice pdev,
764 const VkMemoryRequirements *mem_reqs,
765 VkMemoryPropertyFlagBits prop_flags)
767 VkPhysicalDeviceMemoryProperties pdev_mem_props;
768 uint32_t i;
770 vkGetPhysicalDeviceMemoryProperties(pdev, &pdev_mem_props);
772 for (i = 0; i < pdev_mem_props.memoryTypeCount; i++) {
773 const VkMemoryType *type = &pdev_mem_props.memoryTypes[i];
775 if ((mem_reqs->memoryTypeBits & (1 << i)) &&
776 (type->propertyFlags & prop_flags) == prop_flags) {
777 return i;
778 break;
781 return UINT32_MAX;
784 static VkSampleCountFlagBits
785 get_num_samples(uint32_t num_samples)
787 switch(num_samples) {
788 case 64:
789 return VK_SAMPLE_COUNT_64_BIT;
790 case 32:
791 return VK_SAMPLE_COUNT_32_BIT;
792 case 16:
793 return VK_SAMPLE_COUNT_16_BIT;
794 case 8:
795 return VK_SAMPLE_COUNT_8_BIT;
796 case 4:
797 return VK_SAMPLE_COUNT_4_BIT;
798 case 2:
799 return VK_SAMPLE_COUNT_2_BIT;
800 case 1:
801 break;
802 default:
803 fprintf(stderr, "Invalid number of samples in VkSampleCountFlagBits. Using one sample.\n");
804 break;
806 return VK_SAMPLE_COUNT_1_BIT;
809 static VkDeviceMemory
810 alloc_memory(struct vk_ctx *ctx,
811 bool is_external,
812 const VkMemoryRequirements *mem_reqs,
813 VkImage image,
814 VkBuffer buffer,
815 VkMemoryPropertyFlagBits prop_flags)
817 VkExportMemoryAllocateInfo exp_mem_info;
818 VkMemoryAllocateInfo mem_alloc_info;
819 VkDeviceMemory mem;
820 VkMemoryDedicatedAllocateInfoKHR ded_info;
822 if (is_external) {
823 memset(&exp_mem_info, 0, sizeof exp_mem_info);
824 exp_mem_info.sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO;
825 exp_mem_info.handleTypes =
826 VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;
829 memset(&mem_alloc_info, 0, sizeof mem_alloc_info);
830 mem_alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
831 mem_alloc_info.pNext = is_external ? &exp_mem_info : 0;
832 mem_alloc_info.allocationSize = mem_reqs->size;
833 mem_alloc_info.memoryTypeIndex =
834 get_memory_type_idx(ctx->pdev, mem_reqs, prop_flags);
836 if (mem_alloc_info.memoryTypeIndex == UINT32_MAX) {
837 fprintf(stderr, "No suitable memory type index found.\n");
838 return VK_NULL_HANDLE;
841 if (image || buffer) {
842 memset(&ded_info, 0, sizeof ded_info);
843 ded_info.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO;
844 ded_info.image = image;
845 ded_info.buffer = buffer;
847 exp_mem_info.pNext = &ded_info;
850 if (vkAllocateMemory(ctx->dev, &mem_alloc_info, 0, &mem) !=
851 VK_SUCCESS)
852 return VK_NULL_HANDLE;
854 return mem;
857 static bool
858 alloc_image_memory(struct vk_ctx *ctx, struct vk_image_obj *img_obj)
860 VkMemoryDedicatedRequirements ded_reqs;
861 VkImageMemoryRequirementsInfo2 req_info2;
862 VkMemoryRequirements2 mem_reqs2;
864 memset(&ded_reqs, 0, sizeof ded_reqs);
865 ded_reqs.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS;
867 /* VkImageMemoryRequirementsInfo2 */
868 memset(&req_info2, 0, sizeof req_info2);
869 req_info2.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2;
870 req_info2.image = img_obj->img;
872 /* VkMemoryRequirements2 */
873 memset(&mem_reqs2, 0, sizeof mem_reqs2);
874 mem_reqs2.sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2;
875 mem_reqs2.pNext = &ded_reqs;
877 vkGetImageMemoryRequirements2(ctx->dev, &req_info2, &mem_reqs2);
878 img_obj->mobj.mem = alloc_memory(ctx,
879 true,
880 &mem_reqs2.memoryRequirements,
881 ded_reqs.requiresDedicatedAllocation? img_obj->img : VK_NULL_HANDLE,
882 VK_NULL_HANDLE,
883 mem_reqs2.memoryRequirements.memoryTypeBits &
884 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
886 img_obj->mobj.mem_sz = mem_reqs2.memoryRequirements.size;
887 img_obj->mobj.dedicated = ded_reqs.requiresDedicatedAllocation;
888 if (img_obj->mobj.mem == VK_NULL_HANDLE) {
889 fprintf(stderr, "Failed to allocate image memory.\n");
890 return false;
893 if (vkBindImageMemory(ctx->dev, img_obj->img, img_obj->mobj.mem, 0) != VK_SUCCESS) {
894 fprintf(stderr, "Failed to bind image memory.\n");
895 return false;
898 return true;
901 static bool
902 are_props_supported(struct vk_ctx *ctx, struct vk_image_props *props)
904 VkPhysicalDeviceExternalImageFormatInfo ext_img_fmt_info;
905 VkExternalImageFormatProperties ext_img_fmt_props;
907 int i;
908 VkPhysicalDeviceImageFormatInfo2 img_fmt_info;
909 VkImageFormatProperties2 img_fmt_props;
910 VkImageUsageFlagBits all_flags[] = {
911 VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
912 VK_IMAGE_USAGE_TRANSFER_DST_BIT,
913 VK_IMAGE_USAGE_SAMPLED_BIT,
914 VK_IMAGE_USAGE_STORAGE_BIT,
915 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
916 VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
917 VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT,
918 /* Shouldn't be used together with COLOR, DEPTH_STENCIL
919 * attachment bits:
920 * VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT,
921 * Provided by VK_EXT_fragment_density_map
922 * VK_IMAGE_USAGE_FRAGMENT_DENSITY_MAP_BIT_EXT,
923 * Provided by VK_NV_shading_rate_image
924 * VK_IMAGE_USAGE_SHADING_RATE_IMAGE_BIT_NV,
925 * Provided by VK_KHR_fragment_shading_rate
926 * VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR,
929 VkImageUsageFlagBits flags = 0;
931 VkExternalMemoryFeatureFlagBits export_feature_flags =
932 VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT;
933 VkExternalMemoryHandleTypeFlagBits handle_type =
934 VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;
936 memset(&ext_img_fmt_info, 0, sizeof ext_img_fmt_info);
937 ext_img_fmt_info.sType =
938 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO;
939 ext_img_fmt_info.handleType = handle_type;
941 memset(&ext_img_fmt_props, 0, sizeof ext_img_fmt_props);
942 ext_img_fmt_props.sType =
943 VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES;
945 memset(&img_fmt_props, 0, sizeof img_fmt_props);
946 img_fmt_props.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2;
947 img_fmt_props.pNext = &ext_img_fmt_props;
949 memset(&img_fmt_info, 0, sizeof img_fmt_info);
950 img_fmt_info.sType =
951 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2;
952 img_fmt_info.pNext = &ext_img_fmt_info;
953 img_fmt_info.format = props->format;
954 img_fmt_info.type = get_image_type(props->h, props->depth);
955 img_fmt_info.tiling = props->tiling;
957 for (i = 0; i < ARRAY_SIZE(all_flags); i++) {
958 img_fmt_info.usage = all_flags[i];
959 if (vkGetPhysicalDeviceImageFormatProperties2(ctx->pdev,
960 &img_fmt_info,
961 &img_fmt_props) == VK_SUCCESS) {
962 flags |= all_flags[i];
966 /* usage can't be null */
967 if (flags) {
968 img_fmt_info.usage = flags;
970 else {
971 fprintf(stderr, "Unsupported Vulkan format properties: usage.\n");
972 return false;
975 if (vkGetPhysicalDeviceImageFormatProperties2
976 (ctx->pdev, &img_fmt_info, &img_fmt_props) != VK_SUCCESS) {
977 fprintf(stderr,
978 "Unsupported Vulkan format properties.\n");
979 return false;
981 props->usage = flags;
983 if (props->need_export &&
984 !(ext_img_fmt_props.externalMemoryProperties.externalMemoryFeatures
985 & export_feature_flags)) {
986 fprintf(stderr, "Unsupported Vulkan external memory features.\n");
987 return false;
990 return true;
993 /* Vulkan test visible functions */
995 bool
996 vk_init_ctx(struct vk_ctx *ctx)
998 if ((ctx->inst = create_instance(false)) == VK_NULL_HANDLE) {
999 fprintf(stderr, "Failed to create Vulkan instance.\n");
1000 goto fail;
1003 if ((ctx->pdev = select_physical_device(ctx->inst)) == VK_NULL_HANDLE) {
1004 fprintf(stderr, "Failed to find suitable physical device.\n");
1005 goto fail;
1008 if ((ctx->dev = create_device(ctx, ctx->pdev)) == VK_NULL_HANDLE) {
1009 fprintf(stderr, "Failed to create Vulkan device.\n");
1010 goto fail;
1013 fill_uuid(ctx->pdev, ctx->deviceUUID, ctx->driverUUID);
1014 return true;
1016 fail:
1017 vk_cleanup_ctx(ctx);
1018 return false;
1021 bool
1022 vk_init_ctx_for_rendering(struct vk_ctx *ctx)
1024 if (!vk_init_ctx(ctx)) {
1025 fprintf(stderr, "Failed to initialize Vulkan.\n");
1026 return false;
1029 if ((ctx->cmd_pool = create_cmd_pool(ctx)) == VK_NULL_HANDLE) {
1030 fprintf(stderr, "Failed to create command pool.\n");
1031 goto fail;
1034 if ((ctx->cmd_buf = create_cmd_buf(ctx->dev, ctx->cmd_pool)) ==
1035 VK_NULL_HANDLE) {
1036 fprintf(stderr, "Failed to create command buffer.\n");
1037 goto fail;
1040 vkGetDeviceQueue(ctx->dev, ctx->qfam_idx, 0, &ctx->queue);
1041 if (!ctx->queue) {
1042 fprintf(stderr, "Failed to get command queue.\n");
1043 goto fail;
1046 return true;
1048 fail:
1049 vk_cleanup_ctx(ctx);
1050 return false;
1053 void
1054 vk_cleanup_ctx(struct vk_ctx *ctx)
1056 if (ctx->cmd_buf != VK_NULL_HANDLE) {
1057 vkResetCommandBuffer(ctx->cmd_buf, VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT);
1058 vkFreeCommandBuffers(ctx->dev, ctx->cmd_pool, 1, &ctx->cmd_buf);
1059 ctx->cmd_buf = VK_NULL_HANDLE;
1062 if (ctx->cmd_pool != VK_NULL_HANDLE) {
1063 vkResetCommandPool(ctx->dev, ctx->cmd_pool, VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT);
1064 vkDestroyCommandPool(ctx->dev, ctx->cmd_pool, 0);
1065 ctx->cmd_pool = VK_NULL_HANDLE;
1068 if (ctx->dev != VK_NULL_HANDLE) {
1069 vkDestroyDevice(ctx->dev, 0);
1070 ctx->dev = VK_NULL_HANDLE;
1073 if (ctx->inst != VK_NULL_HANDLE) {
1074 vkDestroyInstance(ctx->inst, 0);
1075 ctx->inst = VK_NULL_HANDLE;
1079 bool
1080 vk_create_ext_image(struct vk_ctx *ctx,
1081 struct vk_image_props *props, struct vk_image_obj *img)
1083 VkExternalMemoryImageCreateInfo ext_img_info;
1084 VkImageCreateInfo img_info;
1086 memset(&ext_img_info, 0, sizeof ext_img_info);
1087 ext_img_info.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO;
1088 ext_img_info.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;
1090 memset(&img_info, 0, sizeof img_info);
1091 img_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
1092 img_info.pNext = &ext_img_info;
1093 img_info.imageType = get_image_type(props->h, props->depth);
1094 img_info.format = props->format;
1095 img_info.extent.width = props->w;
1096 img_info.extent.height = props->h;
1097 img_info.extent.depth = props->depth;
1098 img_info.mipLevels = props->num_levels ? props->num_levels : 1;
1099 img_info.arrayLayers = props->num_layers ? props->num_layers : VK_SAMPLE_COUNT_1_BIT;
1100 img_info.samples = get_num_samples(props->num_samples);
1101 img_info.tiling = props->tiling;
1102 img_info.usage = props->usage;
1103 img_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
1104 img_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
1105 /* issue 17 of EXT_external_objects
1106 * Required in OpenGL implementations that support
1107 * ARB_texture_view, OES_texture_view, EXT_texture_view,
1108 * or OpenGL 4.3 and above.
1110 img_info.flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
1112 if (vkCreateImage(ctx->dev, &img_info, 0, &img->img) != VK_SUCCESS)
1113 goto fail;
1115 if(!alloc_image_memory(ctx, img))
1116 goto fail;
1118 return true;
1120 fail:
1121 fprintf(stderr, "Failed to create external image.\n");
1122 vk_destroy_ext_image(ctx, img);
1123 img->img = VK_NULL_HANDLE;
1124 img->mobj.mem = VK_NULL_HANDLE;
1125 return false;
1128 bool
1129 vk_create_ext_buffer(struct vk_ctx *ctx,
1130 uint32_t sz,
1131 VkBufferUsageFlagBits usage,
1132 struct vk_buf *bo)
1134 VkExternalMemoryBufferCreateInfo ext_bo_info;
1136 memset(&ext_bo_info, 0, sizeof ext_bo_info);
1137 ext_bo_info.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO;
1138 ext_bo_info.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;
1140 if (!vk_create_buffer(ctx, true, sz, usage, &ext_bo_info, bo)) {
1141 fprintf(stderr, "Failed to allocate external buffer.\n");
1142 return false;
1145 return true;
1148 void
1149 vk_destroy_ext_image(struct vk_ctx *ctx, struct vk_image_obj *img_obj)
1151 if (img_obj->img != VK_NULL_HANDLE) {
1152 vkDestroyImage(ctx->dev, img_obj->img, 0);
1153 img_obj->img = VK_NULL_HANDLE;
1156 if (img_obj->mobj.mem != VK_NULL_HANDLE) {
1157 vkFreeMemory(ctx->dev, img_obj->mobj.mem, 0);
1158 img_obj->mobj.mem = VK_NULL_HANDLE;
1161 if (img_obj->img_view != VK_NULL_HANDLE) {
1162 vkDestroyImageView(ctx->dev, img_obj->img_view, 0);
1163 img_obj->img_view = VK_NULL_HANDLE;
1167 void
1168 vk_destroy_ext_bo(struct vk_ctx *ctx,
1169 struct vk_buf *bo)
1171 if (bo->buf != VK_NULL_HANDLE) {
1172 vkDestroyBuffer(ctx->dev, bo->buf, 0);
1173 bo->buf = VK_NULL_HANDLE;
1176 if (bo->mobj.mem != VK_NULL_HANDLE) {
1177 vkFreeMemory(ctx->dev, bo->mobj.mem, 0);
1178 bo->mobj.mem = VK_NULL_HANDLE;
1182 bool
1183 vk_fill_ext_image_props(struct vk_ctx *ctx,
1184 uint32_t w,
1185 uint32_t h,
1186 uint32_t d,
1187 uint32_t num_samples,
1188 uint32_t num_levels,
1189 uint32_t num_layers,
1190 VkFormat format,
1191 VkImageTiling tiling,
1192 VkImageLayout in_layout,
1193 VkImageLayout end_layout,
1194 bool need_export,
1195 struct vk_image_props *props)
1197 props->w = w;
1198 props->h = h;
1199 props->depth = d;
1201 props->num_samples = num_samples;
1202 props->num_levels = num_levels;
1203 props->num_layers = num_layers;
1205 props->format = format;
1206 props->tiling = tiling;
1208 props->in_layout = in_layout;
1209 props->end_layout = end_layout;
1211 props->need_export = need_export;
1213 if (!are_props_supported(ctx, props))
1214 return false;
1216 return true;
1219 bool
1220 vk_create_renderer(struct vk_ctx *ctx,
1221 const char *vs_src,
1222 unsigned int vs_size,
1223 const char *fs_src,
1224 unsigned int fs_size,
1225 bool enable_depth,
1226 bool enable_stencil,
1227 struct vk_image_att *color_att,
1228 struct vk_image_att *depth_att,
1229 struct vk_vertex_info *vert_info,
1230 struct vk_renderer *renderer)
1232 memset(&renderer->vertex_info, 0, sizeof renderer->vertex_info);
1233 if (vert_info)
1234 renderer->vertex_info = *vert_info;
1236 renderer->renderpass = create_renderpass(ctx, &color_att->props, depth_att ? &depth_att->props : NULL);
1237 if (renderer->renderpass == VK_NULL_HANDLE)
1238 goto fail;
1240 create_framebuffer(ctx, color_att, depth_att, renderer);
1241 if (renderer->fb == VK_NULL_HANDLE)
1242 goto fail;
1244 renderer->vs = create_shader_module(ctx, vs_src, vs_size);
1245 if (renderer->vs == VK_NULL_HANDLE)
1246 goto fail;
1248 renderer->fs = create_shader_module(ctx, fs_src, fs_size);
1249 if (renderer->fs == VK_NULL_HANDLE)
1250 goto fail;
1252 create_pipeline(ctx, color_att->props.w, color_att->props.h,
1253 color_att->props.num_samples, enable_depth, enable_stencil, renderer);
1255 if (renderer->pipeline == VK_NULL_HANDLE)
1256 goto fail;
1258 return true;
1260 fail:
1261 fprintf(stderr, "Failed to create graphics pipeline.\n");
1262 vk_destroy_renderer(ctx, renderer);
1263 return false;
1266 void
1267 vk_destroy_renderer(struct vk_ctx *ctx,
1268 struct vk_renderer *renderer)
1270 if (renderer->renderpass != VK_NULL_HANDLE) {
1271 vkDestroyRenderPass(ctx->dev, renderer->renderpass, 0);
1272 renderer->renderpass = VK_NULL_HANDLE;
1275 if (renderer->vs != VK_NULL_HANDLE) {
1276 vkDestroyShaderModule(ctx->dev, renderer->vs, 0);
1277 renderer->vs = VK_NULL_HANDLE;
1280 if (renderer->fs != VK_NULL_HANDLE) {
1281 vkDestroyShaderModule(ctx->dev, renderer->fs, 0);
1282 renderer->fs = VK_NULL_HANDLE;
1285 if (renderer->fb != VK_NULL_HANDLE) {
1286 vkDestroyFramebuffer(ctx->dev, renderer->fb, 0);
1287 renderer->fb = VK_NULL_HANDLE;
1290 if (renderer->pipeline != VK_NULL_HANDLE) {
1291 vkDestroyPipeline(ctx->dev, renderer->pipeline, 0);
1292 renderer->pipeline = VK_NULL_HANDLE;
1295 if (renderer->pipeline_layout != VK_NULL_HANDLE) {
1296 vkDestroyPipelineLayout(ctx->dev, renderer->pipeline_layout, 0);
1297 renderer->pipeline_layout = VK_NULL_HANDLE;
1301 bool
1302 vk_create_buffer(struct vk_ctx *ctx,
1303 bool is_external,
1304 uint32_t sz,
1305 VkBufferUsageFlagBits usage,
1306 void *pnext,
1307 struct vk_buf *bo)
1309 VkBufferCreateInfo buf_info;
1310 VkMemoryRequirements mem_reqs;
1312 bo->mobj.mem = VK_NULL_HANDLE;
1313 bo->buf = VK_NULL_HANDLE;
1315 /* VkBufferCreateInfo */
1316 memset(&buf_info, 0, sizeof buf_info);
1317 buf_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
1318 buf_info.size = sz;
1319 buf_info.usage = usage;
1320 buf_info.pNext = pnext;
1321 buf_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
1323 if (vkCreateBuffer(ctx->dev, &buf_info, 0, &bo->buf) != VK_SUCCESS)
1324 goto fail;
1326 /* allocate buffer */
1327 vkGetBufferMemoryRequirements(ctx->dev, bo->buf, &mem_reqs);
1328 /* VK_MEMORY_PROPERTY_HOST_COHERENT_BIT bit specifies that the
1329 * host cache management commands vkFlushMappedMemoryRanges and
1330 * vkInvalidateMappedMemoryRanges are not needed to flush host
1331 * writes to the device or make device writes visible to the
1332 * host, respectively. */
1333 bo->mobj.mem = alloc_memory(ctx, is_external, &mem_reqs, VK_NULL_HANDLE, VK_NULL_HANDLE,
1334 VK_MEMORY_PROPERTY_HOST_COHERENT_BIT |
1335 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
1337 if (bo->mobj.mem == VK_NULL_HANDLE)
1338 goto fail;
1340 bo->mobj.mem_sz = sz;
1342 if (vkBindBufferMemory(ctx->dev, bo->buf, bo->mobj.mem, 0) != VK_SUCCESS) {
1343 fprintf(stderr, "Failed to bind buffer memory.\n");
1344 goto fail;
1347 return true;
1349 fail:
1350 fprintf(stderr, "Failed to allocate buffer.\n");
1351 vk_destroy_buffer(ctx, bo);
1352 return false;
1355 bool
1356 vk_update_buffer_data(struct vk_ctx *ctx,
1357 void *data,
1358 uint32_t data_sz,
1359 struct vk_buf *bo)
1361 void *map;
1363 if (vkMapMemory(ctx->dev, bo->mobj.mem, 0, data_sz, 0, &map) != VK_SUCCESS) {
1364 fprintf(stderr, "Failed to map buffer memory.\n");
1365 goto fail;
1368 memcpy(map, data, data_sz);
1370 vkUnmapMemory(ctx->dev, bo->mobj.mem);
1371 return true;
1373 fail:
1374 fprintf(stderr, "Failed to update buffer data. Destroying the buffer.\n");
1375 vk_destroy_buffer(ctx, bo);
1377 return false;
1380 void
1381 vk_destroy_buffer(struct vk_ctx *ctx,
1382 struct vk_buf *bo)
1384 if (bo->buf != VK_NULL_HANDLE)
1385 vkDestroyBuffer(ctx->dev, bo->buf, 0);
1387 if (bo->mobj.mem != VK_NULL_HANDLE)
1388 vkFreeMemory(ctx->dev, bo->mobj.mem, 0);
1390 bo->mobj.mem_sz = 0;
1391 bo->buf = VK_NULL_HANDLE;
1392 bo->mobj.mem = VK_NULL_HANDLE;
1395 void
1396 vk_draw(struct vk_ctx *ctx,
1397 struct vk_buf *vbo,
1398 struct vk_renderer *renderer,
1399 float *vk_fb_color,
1400 uint32_t vk_fb_color_count,
1401 struct vk_semaphores *semaphores,
1402 bool has_wait, bool has_signal,
1403 struct vk_image_att *attachments,
1404 uint32_t n_attachments,
1405 float x, float y,
1406 float w, float h)
1408 VkCommandBufferBeginInfo cmd_begin_info;
1409 VkRenderPassBeginInfo rp_begin_info;
1410 VkRect2D rp_area;
1411 VkClearValue clear_values[2];
1412 VkSubmitInfo submit_info;
1413 VkDeviceSize offsets[] = {0};
1414 VkPipelineStageFlagBits stage_flags;
1415 struct vk_dims img_size;
1417 assert(vk_fb_color_count == 4);
1418 if (has_wait)
1419 assert(semaphores->gl_frame_done);
1420 if (has_signal)
1421 assert(semaphores->vk_frame_ready);
1423 /* VkCommandBufferBeginInfo */
1424 memset(&cmd_begin_info, 0, sizeof cmd_begin_info);
1425 cmd_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
1426 cmd_begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
1428 /* VkRect2D render area */
1429 memset(&rp_area, 0, sizeof rp_area);
1430 rp_area.extent.width = (uint32_t)w;
1431 rp_area.extent.height = (uint32_t)h;
1432 rp_area.offset.x = x;
1433 rp_area.offset.y = y;
1435 /* VkClearValue */
1436 memset(&clear_values[0], 0, sizeof clear_values[0]);
1437 clear_values[0].color.float32[0] = vk_fb_color[0]; /* red */
1438 clear_values[0].color.float32[1] = vk_fb_color[1]; /* green */
1439 clear_values[0].color.float32[2] = vk_fb_color[2]; /* blue */
1440 clear_values[0].color.float32[3] = vk_fb_color[3]; /* alpha */
1442 memset(&clear_values[1], 0, sizeof clear_values[1]);
1443 clear_values[1].depthStencil.depth = 1.0;
1444 clear_values[1].depthStencil.stencil = 0;
1446 /* VkRenderPassBeginInfo */
1447 memset(&rp_begin_info, 0, sizeof rp_begin_info);
1448 rp_begin_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
1449 rp_begin_info.renderPass = renderer->renderpass;
1450 rp_begin_info.framebuffer = renderer->fb;
1451 rp_begin_info.renderArea = rp_area;
1452 rp_begin_info.clearValueCount = 2;
1453 rp_begin_info.pClearValues = clear_values;
1455 /* VkSubmitInfo */
1456 stage_flags = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT;
1458 memset(&submit_info, 0, sizeof submit_info);
1459 submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
1460 submit_info.commandBufferCount = 1;
1461 submit_info.pCommandBuffers = &ctx->cmd_buf;
1462 if (has_wait) {
1463 submit_info.pWaitDstStageMask = &stage_flags;
1464 submit_info.waitSemaphoreCount = 1;
1465 submit_info.pWaitSemaphores = &semaphores->gl_frame_done;
1468 if (has_signal) {
1469 submit_info.signalSemaphoreCount = 1;
1470 submit_info.pSignalSemaphores = &semaphores->vk_frame_ready;
1473 vkBeginCommandBuffer(ctx->cmd_buf, &cmd_begin_info);
1474 vkCmdBeginRenderPass(ctx->cmd_buf, &rp_begin_info, VK_SUBPASS_CONTENTS_INLINE);
1476 viewport.x = x;
1477 viewport.y = y;
1478 viewport.width = w;
1479 viewport.height = h;
1481 scissor.offset.x = x;
1482 scissor.offset.y = y;
1483 scissor.extent.width = w;
1484 scissor.extent.height = h;
1486 vkCmdSetViewport(ctx->cmd_buf, 0, 1, &viewport);
1487 vkCmdSetScissor(ctx->cmd_buf, 0, 1, &scissor);
1489 img_size.w = (float)w;
1490 img_size.h = (float)h;
1491 vkCmdPushConstants(ctx->cmd_buf,
1492 renderer->pipeline_layout,
1493 VK_SHADER_STAGE_FRAGMENT_BIT,
1494 0, sizeof (struct vk_dims),
1495 &img_size);
1497 if (vbo) {
1498 vkCmdBindVertexBuffers(ctx->cmd_buf, 0, 1, &vbo->buf, offsets);
1500 vkCmdBindPipeline(ctx->cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS, renderer->pipeline);
1502 int num_vertices = vbo ? renderer->vertex_info.num_verts : 4;
1503 vkCmdDraw(ctx->cmd_buf, num_vertices, 1, 0, 0);
1505 vkCmdEndRenderPass(ctx->cmd_buf);
1506 if (attachments) {
1507 VkImageMemoryBarrier *barriers =
1508 calloc(n_attachments, sizeof(VkImageMemoryBarrier));
1509 VkImageMemoryBarrier *barrier = barriers;
1510 for (uint32_t n = 0; n < n_attachments; n++, barrier++) {
1511 struct vk_image_att *att = &attachments[n];
1512 VkImageAspectFlagBits depth_stencil_flags =
1513 get_aspect_from_depth_format(att->props.format);
1514 bool is_depth = (depth_stencil_flags != 0);
1516 /* Insert barrier to mark ownership transfer. */
1517 barrier->sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
1518 barrier->oldLayout = is_depth ?
1519 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL :
1520 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
1521 barrier->newLayout = VK_IMAGE_LAYOUT_GENERAL;
1522 barrier->srcAccessMask = get_access_mask(barrier->oldLayout);
1523 barrier->dstAccessMask = get_access_mask(barrier->newLayout);
1524 barrier->srcQueueFamilyIndex = ctx->qfam_idx;
1525 barrier->dstQueueFamilyIndex = VK_QUEUE_FAMILY_EXTERNAL;
1526 barrier->image = att->obj.img;
1527 barrier->subresourceRange.aspectMask = is_depth ?
1528 depth_stencil_flags :
1529 VK_IMAGE_ASPECT_COLOR_BIT;
1530 barrier->subresourceRange.baseMipLevel = 0;
1531 barrier->subresourceRange.levelCount = 1;
1532 barrier->subresourceRange.baseArrayLayer = 0;
1533 barrier->subresourceRange.layerCount = 1;
1536 vkCmdPipelineBarrier(ctx->cmd_buf,
1537 VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
1538 VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
1540 0, NULL,
1541 0, NULL,
1542 n_attachments, barriers);
1543 free(barriers);
1545 vkEndCommandBuffer(ctx->cmd_buf);
1547 if (vkQueueSubmit(ctx->queue, 1, &submit_info, VK_NULL_HANDLE) != VK_SUCCESS) {
1548 fprintf(stderr, "Failed to submit queue.\n");
1551 /* FIXME */
1552 if (!semaphores && !has_wait && !has_signal)
1553 vkQueueWaitIdle(ctx->queue);
1556 void
1557 vk_clear_color(struct vk_ctx *ctx,
1558 struct vk_buf *vbo,
1559 struct vk_renderer *renderer,
1560 float *vk_fb_color,
1561 uint32_t vk_fb_color_count,
1562 struct vk_semaphores *semaphores,
1563 bool has_wait, bool has_signal,
1564 struct vk_image_att *attachments,
1565 uint32_t n_attachments,
1566 float x, float y,
1567 float w, float h)
1569 VkCommandBufferBeginInfo cmd_begin_info;
1570 VkRenderPassBeginInfo rp_begin_info;
1571 VkRect2D rp_area;
1572 VkClearValue clear_values[2];
1573 VkSubmitInfo submit_info;
1574 VkPipelineStageFlagBits stage_flags;
1575 VkImageSubresourceRange img_range;
1577 assert(vk_fb_color_count == 4);
1579 if (has_wait)
1580 assert(semaphores->gl_frame_done);
1581 if (has_signal)
1582 assert(semaphores->vk_frame_ready);
1584 /* VkCommandBufferBeginInfo */
1585 memset(&cmd_begin_info, 0, sizeof cmd_begin_info);
1586 cmd_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
1587 cmd_begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
1589 /* VkRect2D render area */
1590 memset(&rp_area, 0, sizeof rp_area);
1591 rp_area.extent.width = (uint32_t)w;
1592 rp_area.extent.height = (uint32_t)h;
1593 rp_area.offset.x = x;
1594 rp_area.offset.y = y;
1596 /* VkClearValue */
1597 memset(&clear_values[0], 0, sizeof clear_values[0]);
1598 clear_values[0].color.float32[0] = vk_fb_color[0]; /* red */
1599 clear_values[0].color.float32[1] = vk_fb_color[1]; /* green */
1600 clear_values[0].color.float32[2] = vk_fb_color[2]; /* blue */
1601 clear_values[0].color.float32[3] = vk_fb_color[3]; /* alpha */
1603 memset(&clear_values[1], 0, sizeof clear_values[1]);
1604 clear_values[1].depthStencil.depth = 1.0;
1605 clear_values[1].depthStencil.stencil = 0;
1607 /* VkRenderPassBeginInfo */
1608 memset(&rp_begin_info, 0, sizeof rp_begin_info);
1609 rp_begin_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
1610 rp_begin_info.renderPass = renderer->renderpass;
1611 rp_begin_info.framebuffer = renderer->fb;
1612 rp_begin_info.renderArea = rp_area;
1613 rp_begin_info.clearValueCount = 2;
1614 rp_begin_info.pClearValues = clear_values;
1616 /* VkSubmitInfo */
1617 stage_flags = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT;
1619 memset(&submit_info, 0, sizeof submit_info);
1620 submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
1621 submit_info.commandBufferCount = 1;
1622 submit_info.pCommandBuffers = &ctx->cmd_buf;
1623 if (has_wait) {
1624 submit_info.pWaitDstStageMask = &stage_flags;
1625 submit_info.waitSemaphoreCount = 1;
1626 submit_info.pWaitSemaphores = &semaphores->gl_frame_done;
1629 if (has_signal) {
1630 submit_info.signalSemaphoreCount = 1;
1631 submit_info.pSignalSemaphores = &semaphores->vk_frame_ready;
1634 img_range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
1635 img_range.baseMipLevel = 0;
1636 img_range.levelCount = 1;
1637 img_range.baseArrayLayer = 0;
1638 img_range.layerCount = 1;
1640 vkBeginCommandBuffer(ctx->cmd_buf, &cmd_begin_info);
1641 vk_transition_image_layout(&attachments[0],
1642 ctx->cmd_buf,
1643 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
1644 VK_IMAGE_LAYOUT_GENERAL,
1645 VK_QUEUE_FAMILY_EXTERNAL,
1646 ctx->qfam_idx);
1647 vkCmdClearColorImage(ctx->cmd_buf,
1648 attachments[0].obj.img,
1649 VK_IMAGE_LAYOUT_GENERAL,
1650 &clear_values[0].color,
1652 &img_range);
1654 vkCmdBeginRenderPass(ctx->cmd_buf, &rp_begin_info, VK_SUBPASS_CONTENTS_INLINE);
1656 viewport.x = x;
1657 viewport.y = y;
1658 viewport.width = w;
1659 viewport.height = h;
1661 scissor.offset.x = x;
1662 scissor.offset.y = y;
1663 scissor.extent.width = w;
1664 scissor.extent.height = h;
1666 vkCmdSetViewport(ctx->cmd_buf, 0, 1, &viewport);
1667 vkCmdSetScissor(ctx->cmd_buf, 0, 1, &scissor);
1669 vkCmdBindPipeline(ctx->cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS, renderer->pipeline);
1671 vkCmdEndRenderPass(ctx->cmd_buf);
1673 VkImageMemoryBarrier *barriers =
1674 calloc(n_attachments, sizeof(VkImageMemoryBarrier));
1675 VkImageMemoryBarrier *barrier = barriers;
1677 for (uint32_t n = 0; n < n_attachments; n++, barrier++) {
1678 struct vk_image_att *att = &attachments[n];
1680 /* Insert barrier to mark ownership transfer. */
1681 barrier->sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
1683 bool is_depth =
1684 get_aspect_from_depth_format(att->props.format) != (uintptr_t)VK_NULL_HANDLE;
1686 barrier->oldLayout = is_depth ?
1687 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL :
1688 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
1689 barrier->newLayout = VK_IMAGE_LAYOUT_GENERAL;
1690 barrier->srcAccessMask = get_access_mask(barrier->oldLayout);
1691 barrier->dstAccessMask = get_access_mask(barrier->newLayout);
1692 barrier->srcQueueFamilyIndex = ctx->qfam_idx;
1693 barrier->dstQueueFamilyIndex = VK_QUEUE_FAMILY_EXTERNAL;
1694 barrier->image = att->obj.img;
1695 barrier->subresourceRange.aspectMask = is_depth ?
1696 VK_IMAGE_ASPECT_DEPTH_BIT :
1697 VK_IMAGE_ASPECT_COLOR_BIT;
1698 barrier->subresourceRange.baseMipLevel = 0;
1699 barrier->subresourceRange.levelCount = 1;
1700 barrier->subresourceRange.baseArrayLayer = 0;
1701 barrier->subresourceRange.layerCount = 1;
1704 vkCmdPipelineBarrier(ctx->cmd_buf,
1705 VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
1706 VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
1708 0, NULL,
1709 0, NULL,
1710 n_attachments, barriers);
1711 free(barriers);
1713 vkEndCommandBuffer(ctx->cmd_buf);
1715 if (vkQueueSubmit(ctx->queue, 1, &submit_info, VK_NULL_HANDLE) != VK_SUCCESS) {
1716 fprintf(stderr, "Failed to submit queue.\n");
1719 if (!semaphores && !has_wait && !has_signal)
1720 vkQueueWaitIdle(ctx->queue);
1723 void
1724 vk_copy_image_to_buffer(struct vk_ctx *ctx,
1725 struct vk_image_att *src_img,
1726 struct vk_buf *dst_bo,
1727 float w, float h)
1729 VkCommandBufferBeginInfo cmd_begin_info;
1730 VkSubmitInfo submit_info;
1731 VkImageAspectFlagBits aspect_mask = get_aspect_from_depth_format(src_img->props.format);
1733 /* VkCommandBufferBeginInfo */
1734 memset(&cmd_begin_info, 0, sizeof cmd_begin_info);
1735 cmd_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
1736 cmd_begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
1738 memset(&submit_info, 0, sizeof submit_info);
1739 submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
1740 submit_info.commandBufferCount = 1;
1741 submit_info.pCommandBuffers = &ctx->cmd_buf;
1743 vkBeginCommandBuffer(ctx->cmd_buf, &cmd_begin_info);
1744 if (src_img->props.end_layout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL && dst_bo) {
1745 vk_transition_image_layout(src_img,
1746 ctx->cmd_buf,
1747 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
1748 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
1749 VK_QUEUE_FAMILY_EXTERNAL,
1750 ctx->qfam_idx);
1752 /* copy image to buf */
1753 VkBufferImageCopy copy_region = {
1754 .bufferOffset = 0,
1755 .bufferRowLength = w,
1756 .bufferImageHeight = h,
1757 .imageSubresource = {
1758 .aspectMask = aspect_mask ? aspect_mask : VK_IMAGE_ASPECT_COLOR_BIT,
1759 .mipLevel = 0,
1760 .baseArrayLayer = 0,
1761 .layerCount = 1,
1763 .imageOffset = { 0, 0, 0 },
1764 .imageExtent = { w, h, 1 }
1767 vkCmdCopyImageToBuffer(ctx->cmd_buf,
1768 src_img->obj.img,
1769 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
1770 dst_bo->buf, 1, &copy_region);
1772 vk_transition_image_layout(src_img,
1773 ctx->cmd_buf,
1774 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
1775 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
1776 VK_QUEUE_FAMILY_EXTERNAL,
1777 ctx->qfam_idx);
1779 VkBufferMemoryBarrier write_finish_buffer_memory_barrier = {
1780 .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
1781 .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
1782 .dstAccessMask = VK_ACCESS_HOST_READ_BIT,
1783 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_EXTERNAL,
1784 .dstQueueFamilyIndex = ctx->qfam_idx,
1785 .buffer = dst_bo->buf,
1786 .offset = 0,
1787 .size = VK_WHOLE_SIZE
1790 vkCmdPipelineBarrier(ctx->cmd_buf,
1791 VK_PIPELINE_STAGE_TRANSFER_BIT,
1792 VK_PIPELINE_STAGE_HOST_BIT,
1793 (VkDependencyFlags) 0, 0, NULL,
1794 1, &write_finish_buffer_memory_barrier,
1795 0, NULL);
1797 vkEndCommandBuffer(ctx->cmd_buf);
1799 if (vkQueueSubmit(ctx->queue, 1, &submit_info, VK_NULL_HANDLE) != VK_SUCCESS) {
1800 fprintf(stderr, "Failed to submit queue.\n");
1802 vkQueueWaitIdle(ctx->queue);
1805 bool
1806 vk_create_semaphores(struct vk_ctx *ctx,
1807 struct vk_semaphores *semaphores)
1809 VkSemaphoreCreateInfo sema_info;
1810 VkExportSemaphoreCreateInfo exp_sema_info;
1812 /* VkExportSemaphoreCreateInfo */
1813 memset(&exp_sema_info, 0, sizeof exp_sema_info);
1814 exp_sema_info.sType = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO;
1815 exp_sema_info.handleTypes = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;
1817 /* VkSemaphoreCreateInfo */
1818 memset(&sema_info, 0, sizeof sema_info);
1819 sema_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
1820 sema_info.pNext = &exp_sema_info;
1822 if (vkCreateSemaphore(ctx->dev, &sema_info, 0, &semaphores->vk_frame_ready) != VK_SUCCESS) {
1823 fprintf(stderr, "Failed to create semaphore vk_frame_ready.\n");
1824 return false;
1827 if (vkCreateSemaphore(ctx->dev, &sema_info, 0, &semaphores->gl_frame_done) != VK_SUCCESS) {
1828 fprintf(stderr, "Failed to create semaphore gl_frame_done.\n");
1829 return false;
1832 return true;
1835 void
1836 vk_destroy_semaphores(struct vk_ctx *ctx,
1837 struct vk_semaphores *semaphores)
1839 if (semaphores->vk_frame_ready)
1840 vkDestroySemaphore(ctx->dev, semaphores->vk_frame_ready, 0);
1841 if (semaphores->gl_frame_done)
1842 vkDestroySemaphore(ctx->dev, semaphores->gl_frame_done, 0);
1845 void
1846 vk_transition_image_layout(struct vk_image_att *img_att,
1847 VkCommandBuffer cmd_buf,
1848 VkImageLayout old_layout,
1849 VkImageLayout new_layout,
1850 uint32_t src_queue_fam_idx,
1851 uint32_t dst_queue_fam_idx)
1853 VkImageMemoryBarrier barrier;
1854 struct vk_image_props props = img_att->props;
1855 VkImageAspectFlagBits aspect_mask = get_aspect_from_depth_format(props.format);
1857 memset(&barrier, 0, sizeof barrier);
1858 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
1859 barrier.srcAccessMask = get_access_mask(old_layout);
1860 barrier.dstAccessMask = get_access_mask(new_layout);
1861 barrier.oldLayout = old_layout;
1862 barrier.newLayout = new_layout;
1863 barrier.srcQueueFamilyIndex = src_queue_fam_idx;
1864 barrier.dstQueueFamilyIndex = dst_queue_fam_idx;
1865 barrier.image = img_att->obj.img;
1866 barrier.subresourceRange.aspectMask = aspect_mask ? aspect_mask : VK_IMAGE_ASPECT_COLOR_BIT;
1867 barrier.subresourceRange.levelCount = 1;
1868 barrier.subresourceRange.layerCount = 1;
1870 vkCmdPipelineBarrier(cmd_buf,
1871 get_pipeline_stage_flags(old_layout),
1872 get_pipeline_stage_flags(new_layout),
1873 0, 0, VK_NULL_HANDLE, 0, VK_NULL_HANDLE, 1, &barrier);