LCOV - code coverage report
Current view: top level - src/vulkan - context.c (source / functions) Hit Total Coverage
Test: Code coverage Lines: 513 663 77.4 %
Date: 2025-03-29 09:04:10 Functions: 16 18 88.9 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 321 604 53.1 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * This file is part of libplacebo.
       3                 :            :  *
       4                 :            :  * libplacebo is free software; you can redistribute it and/or
       5                 :            :  * modify it under the terms of the GNU Lesser General Public
       6                 :            :  * License as published by the Free Software Foundation; either
       7                 :            :  * version 2.1 of the License, or (at your option) any later version.
       8                 :            :  *
       9                 :            :  * libplacebo is distributed in the hope that it will be useful,
      10                 :            :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      11                 :            :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12                 :            :  * GNU Lesser General Public License for more details.
      13                 :            :  *
      14                 :            :  * You should have received a copy of the GNU Lesser General Public
      15                 :            :  * License along with libplacebo.  If not, see <http://www.gnu.org/licenses/>.
      16                 :            :  */
      17                 :            : 
      18                 :            : #include "common.h"
      19                 :            : #include "command.h"
      20                 :            : #include "utils.h"
      21                 :            : #include "gpu.h"
      22                 :            : 
      23                 :            : #ifdef PL_HAVE_VK_PROC_ADDR
      24                 :            : VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr(
      25                 :            :     VkInstance                                  instance,
      26                 :            :     const char*                                 pName);
      27                 :            : #endif
      28                 :            : 
      29                 :            : const struct pl_vk_inst_params pl_vk_inst_default_params = {0};
      30                 :            : 
      31                 :            : struct vk_fun {
      32                 :            :     const char *name;
      33                 :            :     size_t offset;
      34                 :            :     bool device_level;
      35                 :            : };
      36                 :            : 
      37                 :            : struct vk_ext {
      38                 :            :     const char *name;
      39                 :            :     const struct vk_fun *funs;
      40                 :            : };
      41                 :            : 
      42                 :            : #define PL_VK_INST_FUN(N)                   \
      43                 :            :     { .name = "vk" #N,                      \
      44                 :            :       .offset = offsetof(struct vk_ctx, N), \
      45                 :            :     }
      46                 :            : 
      47                 :            : #define PL_VK_DEV_FUN(N)                    \
      48                 :            :     { .name = "vk" #N,                      \
      49                 :            :       .offset = offsetof(struct vk_ctx, N), \
      50                 :            :       .device_level = true,                 \
      51                 :            :     }
      52                 :            : 
      53                 :            : // Table of optional vulkan instance extensions
      54                 :            : static const char *vk_instance_extensions[] = {
      55                 :            :     VK_KHR_SURFACE_EXTENSION_NAME,
      56                 :            :     VK_EXT_SWAPCHAIN_COLOR_SPACE_EXTENSION_NAME,
      57                 :            :     VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME,
      58                 :            : };
      59                 :            : 
      60                 :            : // List of mandatory instance-level function pointers, including functions
      61                 :            : // associated with mandatory instance extensions
      62                 :            : static const struct vk_fun vk_inst_funs[] = {
      63                 :            :     PL_VK_INST_FUN(CreateDevice),
      64                 :            :     PL_VK_INST_FUN(EnumerateDeviceExtensionProperties),
      65                 :            :     PL_VK_INST_FUN(GetDeviceProcAddr),
      66                 :            :     PL_VK_INST_FUN(GetPhysicalDeviceExternalBufferProperties),
      67                 :            :     PL_VK_INST_FUN(GetPhysicalDeviceExternalSemaphoreProperties),
      68                 :            :     PL_VK_INST_FUN(GetPhysicalDeviceFeatures2KHR),
      69                 :            :     PL_VK_INST_FUN(GetPhysicalDeviceFormatProperties),
      70                 :            :     PL_VK_INST_FUN(GetPhysicalDeviceFormatProperties2KHR),
      71                 :            :     PL_VK_INST_FUN(GetPhysicalDeviceImageFormatProperties2KHR),
      72                 :            :     PL_VK_INST_FUN(GetPhysicalDeviceMemoryProperties),
      73                 :            :     PL_VK_INST_FUN(GetPhysicalDeviceProperties),
      74                 :            :     PL_VK_INST_FUN(GetPhysicalDeviceProperties2),
      75                 :            :     PL_VK_INST_FUN(GetPhysicalDeviceQueueFamilyProperties),
      76                 :            : 
      77                 :            :     // These are not actually mandatory, but they're universal enough that we
      78                 :            :     // just load them unconditionally (in lieu of not having proper support for
      79                 :            :     // loading arbitrary instance extensions). Their use is generally guarded
      80                 :            :     // behind various VkSurfaceKHR values already being provided by the API
      81                 :            :     // user (implying this extension is loaded).
      82                 :            :     PL_VK_INST_FUN(GetPhysicalDeviceSurfaceCapabilitiesKHR),
      83                 :            :     PL_VK_INST_FUN(GetPhysicalDeviceSurfaceFormatsKHR),
      84                 :            :     PL_VK_INST_FUN(GetPhysicalDeviceSurfacePresentModesKHR),
      85                 :            :     PL_VK_INST_FUN(GetPhysicalDeviceSurfaceSupportKHR),
      86                 :            : };
      87                 :            : 
      88                 :            : // Table of vulkan device extensions and functions they load, including
      89                 :            : // functions exported by dependent instance-level extensions
      90                 :            : static const struct vk_ext vk_device_extensions[] = {
      91                 :            :     {
      92                 :            :         .name = VK_KHR_SWAPCHAIN_EXTENSION_NAME,
      93                 :            :         .funs = (const struct vk_fun[]) {
      94                 :            :             PL_VK_DEV_FUN(AcquireNextImageKHR),
      95                 :            :             PL_VK_DEV_FUN(CreateSwapchainKHR),
      96                 :            :             PL_VK_DEV_FUN(DestroySwapchainKHR),
      97                 :            :             PL_VK_DEV_FUN(GetSwapchainImagesKHR),
      98                 :            :             PL_VK_DEV_FUN(QueuePresentKHR),
      99                 :            :             {0}
     100                 :            :         },
     101                 :            :     }, {
     102                 :            :         .name = VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME,
     103                 :            :         .funs = (const struct vk_fun[]) {
     104                 :            :             PL_VK_DEV_FUN(CmdPushDescriptorSetKHR),
     105                 :            :             {0}
     106                 :            :         },
     107                 :            :     }, {
     108                 :            :         .name = VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME,
     109                 :            :         .funs = (const struct vk_fun[]) {
     110                 :            :             PL_VK_DEV_FUN(GetMemoryFdKHR),
     111                 :            :             {0}
     112                 :            :         },
     113                 :            :     }, {
     114                 :            :         .name = VK_EXT_EXTERNAL_MEMORY_DMA_BUF_EXTENSION_NAME,
     115                 :            :         .funs = (const struct vk_fun[]) {
     116                 :            :             PL_VK_DEV_FUN(GetMemoryFdPropertiesKHR),
     117                 :            :             {0}
     118                 :            :         },
     119                 :            : #ifdef PL_HAVE_WIN32
     120                 :            :     }, {
     121                 :            :         .name = VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME,
     122                 :            :         .funs = (const struct vk_fun[]) {
     123                 :            :             PL_VK_DEV_FUN(GetMemoryWin32HandleKHR),
     124                 :            :             {0}
     125                 :            :         },
     126                 :            : #endif
     127                 :            :     }, {
     128                 :            :         .name = VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME,
     129                 :            :         .funs = (const struct vk_fun[]) {
     130                 :            :             PL_VK_DEV_FUN(GetMemoryHostPointerPropertiesEXT),
     131                 :            :             {0}
     132                 :            :         },
     133                 :            :     }, {
     134                 :            :         .name = VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME,
     135                 :            :         .funs = (const struct vk_fun[]) {
     136                 :            :             PL_VK_DEV_FUN(GetSemaphoreFdKHR),
     137                 :            :             {0}
     138                 :            :         },
     139                 :            : #ifdef PL_HAVE_WIN32
     140                 :            :     }, {
     141                 :            :         .name = VK_KHR_EXTERNAL_SEMAPHORE_WIN32_EXTENSION_NAME,
     142                 :            :         .funs = (const struct vk_fun[]) {
     143                 :            :             PL_VK_DEV_FUN(GetSemaphoreWin32HandleKHR),
     144                 :            :             {0}
     145                 :            :         },
     146                 :            : #endif
     147                 :            :     }, {
     148                 :            :         .name = VK_EXT_PCI_BUS_INFO_EXTENSION_NAME,
     149                 :            :     }, {
     150                 :            :         .name = VK_EXT_HDR_METADATA_EXTENSION_NAME,
     151                 :            :         .funs = (const struct vk_fun[]) {
     152                 :            :             PL_VK_DEV_FUN(SetHdrMetadataEXT),
     153                 :            :             {0}
     154                 :            :         },
     155                 :            :     }, {
     156                 :            :         .name = VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME,
     157                 :            :         .funs = (const struct vk_fun[]) {
     158                 :            :             PL_VK_DEV_FUN(GetImageDrmFormatModifierPropertiesEXT),
     159                 :            :             {0}
     160                 :            :         },
     161                 :            : #ifdef VK_KHR_portability_subset
     162                 :            :     }, {
     163                 :            :         .name = VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME,
     164                 :            : #endif
     165                 :            : #ifdef VK_EXT_metal_objects
     166                 :            :     }, {
     167                 :            :         .name = VK_EXT_METAL_OBJECTS_EXTENSION_NAME,
     168                 :            :         .funs = (const struct vk_fun[]) {
     169                 :            :             PL_VK_DEV_FUN(ExportMetalObjectsEXT),
     170                 :            :             {0}
     171                 :            :         },
     172                 :            : #endif
     173                 :            : #ifdef VK_EXT_full_screen_exclusive
     174                 :            :     }, {
     175                 :            :         .name = VK_EXT_FULL_SCREEN_EXCLUSIVE_EXTENSION_NAME,
     176                 :            :         .funs = (const struct vk_fun[]) {
     177                 :            :             PL_VK_DEV_FUN(AcquireFullScreenExclusiveModeEXT),
     178                 :            :             {0}
     179                 :            :         },
     180                 :            : #endif
     181                 :            :     }, {
     182                 :            :         .name = VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME,
     183                 :            :         .funs = (const struct vk_fun[]) {
     184                 :            :             PL_VK_DEV_FUN(CmdPipelineBarrier2KHR),
     185                 :            :             PL_VK_DEV_FUN(QueueSubmit2KHR),
     186                 :            :             {0}
     187                 :            :         },
     188                 :            :     },
     189                 :            : };
     190                 :            : 
     191                 :            : // Make sure to keep this in sync with the above!
     192                 :            : const char * const pl_vulkan_recommended_extensions[] = {
     193                 :            :     VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME,
     194                 :            :     VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME,
     195                 :            :     VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME,
     196                 :            :     VK_EXT_EXTERNAL_MEMORY_DMA_BUF_EXTENSION_NAME,
     197                 :            :     VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME,
     198                 :            : #ifdef PL_HAVE_WIN32
     199                 :            :     VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME,
     200                 :            :     VK_KHR_EXTERNAL_SEMAPHORE_WIN32_EXTENSION_NAME,
     201                 :            : #endif
     202                 :            :     VK_EXT_PCI_BUS_INFO_EXTENSION_NAME,
     203                 :            :     VK_EXT_HDR_METADATA_EXTENSION_NAME,
     204                 :            :     VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME,
     205                 :            : #ifdef VK_KHR_portability_subset
     206                 :            :     VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME,
     207                 :            : #endif
     208                 :            : #ifdef VK_EXT_metal_objects
     209                 :            :     VK_EXT_METAL_OBJECTS_EXTENSION_NAME,
     210                 :            : #endif
     211                 :            : #ifdef VK_EXT_full_screen_exclusive
     212                 :            :     VK_EXT_FULL_SCREEN_EXCLUSIVE_EXTENSION_NAME,
     213                 :            : #endif
     214                 :            :     VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME,
     215                 :            : };
     216                 :            : 
     217                 :            : const int pl_vulkan_num_recommended_extensions =
     218                 :            :     PL_ARRAY_SIZE(pl_vulkan_recommended_extensions);
     219                 :            : 
     220                 :            : // +1 because VK_KHR_swapchain is not automatically pulled in
     221                 :            : static_assert(PL_ARRAY_SIZE(pl_vulkan_recommended_extensions) + 1 ==
     222                 :            :               PL_ARRAY_SIZE(vk_device_extensions),
     223                 :            :               "pl_vulkan_recommended_extensions out of sync with "
     224                 :            :               "vk_device_extensions?");
     225                 :            : 
     226                 :            : // Recommended features; keep in sync with libavutil vulkan hwcontext
     227                 :            : static const VkPhysicalDeviceVulkan13Features recommended_vk13 = {
     228                 :            :     .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES,
     229                 :            :     .computeFullSubgroups = true,
     230                 :            :     .maintenance4 = true,
     231                 :            :     .shaderZeroInitializeWorkgroupMemory = true,
     232                 :            :     .synchronization2 = true,
     233                 :            : };
     234                 :            : 
     235                 :            : static const VkPhysicalDeviceVulkan12Features recommended_vk12 = {
     236                 :            :     .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES,
     237                 :            :     .pNext = (void *) &recommended_vk13,
     238                 :            :     .bufferDeviceAddress = true,
     239                 :            :     .storagePushConstant8 = true,
     240                 :            :     .shaderInt8 = true,
     241                 :            :     .shaderFloat16 = true,
     242                 :            :     .shaderSharedInt64Atomics = true,
     243                 :            :     .storageBuffer8BitAccess = true,
     244                 :            :     .uniformAndStorageBuffer8BitAccess = true,
     245                 :            :     .vulkanMemoryModel = true,
     246                 :            :     .vulkanMemoryModelDeviceScope = true,
     247                 :            : };
     248                 :            : 
     249                 :            : static const VkPhysicalDeviceVulkan11Features recommended_vk11 = {
     250                 :            :     .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES,
     251                 :            :     .pNext = (void *) &recommended_vk12,
     252                 :            :     .samplerYcbcrConversion = true,
     253                 :            :     .storagePushConstant16 = true,
     254                 :            : };
     255                 :            : 
     256                 :            : const VkPhysicalDeviceFeatures2 pl_vulkan_recommended_features = {
     257                 :            :     .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2,
     258                 :            :     .pNext = (void *) &recommended_vk11,
     259                 :            :     .features = {
     260                 :            :         .shaderImageGatherExtended = true,
     261                 :            :         .shaderStorageImageReadWithoutFormat = true,
     262                 :            :         .shaderStorageImageWriteWithoutFormat = true,
     263                 :            : 
     264                 :            :         // Needed for GPU-assisted validation, but not harmful to enable
     265                 :            :         .fragmentStoresAndAtomics = true,
     266                 :            :         .vertexPipelineStoresAndAtomics = true,
     267                 :            :         .shaderInt64 = true,
     268                 :            :     }
     269                 :            : };
     270                 :            : 
     271                 :            : // Required features
     272                 :            : static const VkPhysicalDeviceVulkan12Features required_vk12 = {
     273                 :            :     .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES,
     274                 :            :     .hostQueryReset = true,
     275                 :            :     .timelineSemaphore = true,
     276                 :            : };
     277                 :            : 
     278                 :            : static const VkPhysicalDeviceVulkan11Features required_vk11 = {
     279                 :            :     .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES,
     280                 :            :     .pNext = (void *) &required_vk12,
     281                 :            : };
     282                 :            : 
     283                 :            : const VkPhysicalDeviceFeatures2 pl_vulkan_required_features = {
     284                 :            :     .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2,
     285                 :            :     .pNext = (void *) &required_vk11,
     286                 :            : };
     287                 :            : 
     288                 :          3 : static bool check_required_features(struct vk_ctx *vk)
     289                 :            : {
     290                 :            :     #define CHECK_FEATURE(maj, min, feat) do {                                  \
     291                 :            :         const VkPhysicalDeviceVulkan##maj##min##Features *f;                    \
     292                 :            :         f = vk_find_struct(&vk->features,                                       \
     293                 :            :             VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_##maj##_##min##_FEATURES); \
     294                 :            :         if (!f || !f->feat) {                                                   \
     295                 :            :             PL_ERR(vk, "Missing device feature: " #feat);                       \
     296                 :            :             return false;                                                       \
     297                 :            :         }                                                                       \
     298                 :            :     } while (0)
     299                 :            : 
     300   [ +  -  -  + ]:          3 :     CHECK_FEATURE(1, 2, hostQueryReset);
     301   [ +  -  -  + ]:          3 :     CHECK_FEATURE(1, 2, timelineSemaphore);
     302                 :            : 
     303                 :            :     #undef CHECK_FEATURE
     304                 :            :     return true;
     305                 :            : }
     306                 :            : 
     307                 :            : 
     308                 :            : // List of mandatory device-level functions
     309                 :            : //
     310                 :            : // Note: Also includes VK_EXT_debug_utils functions, even though they aren't
     311                 :            : // mandatory, simply because we load that extension in a special way.
     312                 :            : static const struct vk_fun vk_dev_funs[] = {
     313                 :            :     PL_VK_DEV_FUN(AllocateCommandBuffers),
     314                 :            :     PL_VK_DEV_FUN(AllocateDescriptorSets),
     315                 :            :     PL_VK_DEV_FUN(AllocateMemory),
     316                 :            :     PL_VK_DEV_FUN(BeginCommandBuffer),
     317                 :            :     PL_VK_DEV_FUN(BindBufferMemory),
     318                 :            :     PL_VK_DEV_FUN(BindImageMemory),
     319                 :            :     PL_VK_DEV_FUN(CmdBeginDebugUtilsLabelEXT),
     320                 :            :     PL_VK_DEV_FUN(CmdBeginRenderPass),
     321                 :            :     PL_VK_DEV_FUN(CmdBindDescriptorSets),
     322                 :            :     PL_VK_DEV_FUN(CmdBindIndexBuffer),
     323                 :            :     PL_VK_DEV_FUN(CmdBindPipeline),
     324                 :            :     PL_VK_DEV_FUN(CmdBindVertexBuffers),
     325                 :            :     PL_VK_DEV_FUN(CmdBlitImage),
     326                 :            :     PL_VK_DEV_FUN(CmdClearColorImage),
     327                 :            :     PL_VK_DEV_FUN(CmdCopyBuffer),
     328                 :            :     PL_VK_DEV_FUN(CmdCopyBufferToImage),
     329                 :            :     PL_VK_DEV_FUN(CmdCopyImage),
     330                 :            :     PL_VK_DEV_FUN(CmdCopyImageToBuffer),
     331                 :            :     PL_VK_DEV_FUN(CmdDispatch),
     332                 :            :     PL_VK_DEV_FUN(CmdDraw),
     333                 :            :     PL_VK_DEV_FUN(CmdDrawIndexed),
     334                 :            :     PL_VK_DEV_FUN(CmdEndDebugUtilsLabelEXT),
     335                 :            :     PL_VK_DEV_FUN(CmdEndRenderPass),
     336                 :            :     PL_VK_DEV_FUN(CmdPipelineBarrier),
     337                 :            :     PL_VK_DEV_FUN(CmdPushConstants),
     338                 :            :     PL_VK_DEV_FUN(CmdResetQueryPool),
     339                 :            :     PL_VK_DEV_FUN(CmdSetScissor),
     340                 :            :     PL_VK_DEV_FUN(CmdSetViewport),
     341                 :            :     PL_VK_DEV_FUN(CmdUpdateBuffer),
     342                 :            :     PL_VK_DEV_FUN(CmdWriteTimestamp),
     343                 :            :     PL_VK_DEV_FUN(CreateBuffer),
     344                 :            :     PL_VK_DEV_FUN(CreateBufferView),
     345                 :            :     PL_VK_DEV_FUN(CreateCommandPool),
     346                 :            :     PL_VK_DEV_FUN(CreateComputePipelines),
     347                 :            :     PL_VK_DEV_FUN(CreateDescriptorPool),
     348                 :            :     PL_VK_DEV_FUN(CreateDescriptorSetLayout),
     349                 :            :     PL_VK_DEV_FUN(CreateFence),
     350                 :            :     PL_VK_DEV_FUN(CreateFramebuffer),
     351                 :            :     PL_VK_DEV_FUN(CreateGraphicsPipelines),
     352                 :            :     PL_VK_DEV_FUN(CreateImage),
     353                 :            :     PL_VK_DEV_FUN(CreateImageView),
     354                 :            :     PL_VK_DEV_FUN(CreatePipelineCache),
     355                 :            :     PL_VK_DEV_FUN(CreatePipelineLayout),
     356                 :            :     PL_VK_DEV_FUN(CreateQueryPool),
     357                 :            :     PL_VK_DEV_FUN(CreateRenderPass),
     358                 :            :     PL_VK_DEV_FUN(CreateSampler),
     359                 :            :     PL_VK_DEV_FUN(CreateSemaphore),
     360                 :            :     PL_VK_DEV_FUN(CreateShaderModule),
     361                 :            :     PL_VK_DEV_FUN(DestroyBuffer),
     362                 :            :     PL_VK_DEV_FUN(DestroyBufferView),
     363                 :            :     PL_VK_DEV_FUN(DestroyCommandPool),
     364                 :            :     PL_VK_DEV_FUN(DestroyDescriptorPool),
     365                 :            :     PL_VK_DEV_FUN(DestroyDescriptorSetLayout),
     366                 :            :     PL_VK_DEV_FUN(DestroyDevice),
     367                 :            :     PL_VK_DEV_FUN(DestroyFence),
     368                 :            :     PL_VK_DEV_FUN(DestroyFramebuffer),
     369                 :            :     PL_VK_DEV_FUN(DestroyImage),
     370                 :            :     PL_VK_DEV_FUN(DestroyImageView),
     371                 :            :     PL_VK_DEV_FUN(DestroyPipeline),
     372                 :            :     PL_VK_DEV_FUN(DestroyPipelineCache),
     373                 :            :     PL_VK_DEV_FUN(DestroyPipelineLayout),
     374                 :            :     PL_VK_DEV_FUN(DestroyQueryPool),
     375                 :            :     PL_VK_DEV_FUN(DestroyRenderPass),
     376                 :            :     PL_VK_DEV_FUN(DestroySampler),
     377                 :            :     PL_VK_DEV_FUN(DestroySemaphore),
     378                 :            :     PL_VK_DEV_FUN(DestroyShaderModule),
     379                 :            :     PL_VK_DEV_FUN(DeviceWaitIdle),
     380                 :            :     PL_VK_DEV_FUN(EndCommandBuffer),
     381                 :            :     PL_VK_DEV_FUN(FlushMappedMemoryRanges),
     382                 :            :     PL_VK_DEV_FUN(FreeCommandBuffers),
     383                 :            :     PL_VK_DEV_FUN(FreeMemory),
     384                 :            :     PL_VK_DEV_FUN(GetBufferMemoryRequirements),
     385                 :            :     PL_VK_DEV_FUN(GetDeviceQueue),
     386                 :            :     PL_VK_DEV_FUN(GetImageMemoryRequirements2),
     387                 :            :     PL_VK_DEV_FUN(GetImageSubresourceLayout),
     388                 :            :     PL_VK_DEV_FUN(GetPipelineCacheData),
     389                 :            :     PL_VK_DEV_FUN(GetQueryPoolResults),
     390                 :            :     PL_VK_DEV_FUN(InvalidateMappedMemoryRanges),
     391                 :            :     PL_VK_DEV_FUN(MapMemory),
     392                 :            :     PL_VK_DEV_FUN(QueueSubmit),
     393                 :            :     PL_VK_DEV_FUN(QueueWaitIdle),
     394                 :            :     PL_VK_DEV_FUN(ResetFences),
     395                 :            :     PL_VK_DEV_FUN(ResetQueryPool),
     396                 :            :     PL_VK_DEV_FUN(SetDebugUtilsObjectNameEXT),
     397                 :            :     PL_VK_DEV_FUN(UpdateDescriptorSets),
     398                 :            :     PL_VK_DEV_FUN(WaitForFences),
     399                 :            :     PL_VK_DEV_FUN(WaitSemaphores),
     400                 :            : };
     401                 :            : 
     402                 :        351 : static void load_vk_fun(struct vk_ctx *vk, const struct vk_fun *fun)
     403                 :            : {
     404                 :        351 :     PFN_vkVoidFunction *pfn = (void *) ((uintptr_t) vk + (ptrdiff_t) fun->offset);
     405                 :            : 
     406         [ +  + ]:        351 :     if (fun->device_level) {
     407                 :        300 :         *pfn = vk->GetDeviceProcAddr(vk->dev, fun->name);
     408                 :            :     } else {
     409                 :         51 :         *pfn = vk->GetInstanceProcAddr(vk->inst, fun->name);
     410                 :            :     };
     411                 :            : 
     412         [ +  + ]:        351 :     if (!*pfn) {
     413                 :            :         // Some functions get their extension suffix stripped when promoted
     414                 :            :         // to core. As a very simple work-around to this, try loading the
     415                 :            :         // function a second time with the reserved suffixes stripped.
     416                 :            :         static const char *ext_suffixes[] = { "KHR", "EXT" };
     417         [ +  - ]:         15 :         pl_str fun_name = pl_str0(fun->name);
     418                 :            :         char buf[64];
     419                 :            : 
     420         [ +  - ]:         15 :         for (int i = 0; i < PL_ARRAY_SIZE(ext_suffixes); i++) {
     421         [ -  + ]:         15 :             if (!pl_str_eatend0(&fun_name, ext_suffixes[i]))
     422                 :            :                 continue;
     423                 :            : 
     424         [ -  + ]:         15 :             pl_assert(sizeof(buf) > fun_name.len);
     425   [ +  -  +  + ]:         30 :             snprintf(buf, sizeof(buf), "%.*s", PL_STR_FMT(fun_name));
     426         [ +  + ]:         15 :             if (fun->device_level) {
     427                 :          6 :                 *pfn = vk->GetDeviceProcAddr(vk->dev, buf);
     428                 :            :             } else {
     429                 :          9 :                 *pfn = vk->GetInstanceProcAddr(vk->inst, buf);
     430                 :            :             }
     431                 :         15 :             return;
     432                 :            :         }
     433                 :            :     }
     434                 :            : }
     435                 :            : 
     436                 :            : // Private struct for pl_vk_inst
     437                 :            : struct priv {
     438                 :            :     VkDebugUtilsMessengerEXT debug_utils_cb;
     439                 :            : };
     440                 :            : 
     441                 :          4 : void pl_vk_inst_destroy(pl_vk_inst *inst_ptr)
     442                 :            : {
     443                 :          4 :     pl_vk_inst inst = *inst_ptr;
     444         [ +  + ]:          4 :     if (!inst)
     445                 :            :         return;
     446                 :            : 
     447                 :          1 :     struct priv *p = PL_PRIV(inst);
     448         [ +  - ]:          1 :     if (p->debug_utils_cb) {
     449                 :          1 :         PL_VK_LOAD_FUN(inst->instance, DestroyDebugUtilsMessengerEXT, inst->get_proc_addr);
     450                 :          1 :         DestroyDebugUtilsMessengerEXT(inst->instance, p->debug_utils_cb, PL_VK_ALLOC);
     451                 :            :     }
     452                 :            : 
     453                 :          1 :     PL_VK_LOAD_FUN(inst->instance, DestroyInstance, inst->get_proc_addr);
     454                 :          1 :     DestroyInstance(inst->instance, PL_VK_ALLOC);
     455                 :          1 :     pl_free_ptr((void **) inst_ptr);
     456                 :            : }
     457                 :            : 
     458                 :        386 : static VkBool32 VKAPI_PTR vk_dbg_utils_cb(VkDebugUtilsMessageSeverityFlagBitsEXT sev,
     459                 :            :                                           VkDebugUtilsMessageTypeFlagsEXT msgType,
     460                 :            :                                           const VkDebugUtilsMessengerCallbackDataEXT *data,
     461                 :            :                                           void *priv)
     462                 :            : {
     463                 :            :     pl_log log = priv;
     464                 :            : 
     465                 :            :     // Ignore errors for messages that we consider false positives
     466      [ -  +  + ]:        386 :     switch (data->messageIdNumber) {
     467                 :            :     case 0x7cd0911d: // VUID-VkSwapchainCreateInfoKHR-imageExtent-01274
     468                 :            :     case 0x8928392f: // UNASSIGNED-BestPractices-NonSuccess-Result
     469                 :            :     case 0xdc18ad6b: // UNASSIGNED-BestPractices-vkAllocateMemory-small-allocation
     470                 :            :     case 0xb3d4346b: // UNASSIGNED-BestPractices-vkBindMemory-small-dedicated-allocation
     471                 :            :     case 0x6cfe18a5: // UNASSIGNED-BestPractices-SemaphoreCount
     472                 :            :     case 0x48a09f6c: // UNASSIGNED-BestPractices-pipeline-stage-flags
     473                 :            :     // profile chain expectations
     474                 :            :     case 0x30f4ac70: // VUID-VkImageCreateInfo-pNext-06811
     475                 :            :         return false;
     476                 :            : 
     477                 :          0 :     case 0x5f379b89: // UNASSIGNED-BestPractices-Error-Result
     478         [ #  # ]:          0 :         if (strstr(data->pMessage, "VK_ERROR_FORMAT_NOT_SUPPORTED"))
     479                 :            :             return false;
     480                 :            :         break;
     481                 :            : 
     482                 :            :     case 0xf6a37cfa: // VUID-vkGetImageSubresourceLayout-format-04461
     483                 :            :         // Work around https://github.com/KhronosGroup/Vulkan-Docs/issues/2109
     484                 :            :         return false;
     485                 :            : 
     486                 :            :     case 0x54023d1d: // VUID-VkDescriptorSetLayoutCreateInfo-flags-00281
     487                 :            :         // Work around https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/9542
     488                 :            :         return false;
     489                 :            :     }
     490                 :            : 
     491                 :            :     enum pl_log_level lev;
     492   [ +  +  +  -  :        376 :     switch (sev) {
                      + ]
     493                 :            :     case VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT:     lev = PL_LOG_ERR;   break;
     494                 :         58 :     case VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT:   lev = PL_LOG_WARN;  break;
     495                 :        254 :     case VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT:      lev = PL_LOG_DEBUG; break;
     496                 :         58 :     case VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT:   lev = PL_LOG_TRACE; break;
     497                 :          0 :     default:                                                lev = PL_LOG_INFO;  break;
     498                 :            :     }
     499                 :            : 
     500                 :        376 :     pl_msg(log, lev, "vk %s", data->pMessage);
     501                 :            : 
     502         [ -  + ]:        376 :     for (int i = 0; i < data->queueLabelCount; i++)
     503                 :          0 :         pl_msg(log, lev, "    during %s", data->pQueueLabels[i].pLabelName);
     504         [ +  + ]:        416 :     for (int i = 0; i < data->cmdBufLabelCount; i++)
     505                 :         40 :         pl_msg(log, lev, "    inside %s", data->pCmdBufLabels[i].pLabelName);
     506         [ +  + ]:        712 :     for (int i = 0; i < data->objectCount; i++) {
     507                 :        336 :         const VkDebugUtilsObjectNameInfoEXT *obj = &data->pObjects[i];
     508                 :        336 :         pl_msg(log, lev, "    using %s: %s (0x%llx)",
     509                 :        336 :                vk_obj_type(obj->objectType),
     510                 :        336 :                obj->pObjectName ? obj->pObjectName : "anon",
     511         [ +  + ]:        336 :                (unsigned long long) obj->objectHandle);
     512                 :            :     }
     513                 :            : 
     514                 :            :     // The return value of this function determines whether the call will
     515                 :            :     // be explicitly aborted (to prevent GPU errors) or not. In this case,
     516                 :            :     // we generally want this to be on for the validation errors, but nothing
     517                 :            :     // else (e.g. performance warnings)
     518         [ +  + ]:        376 :     bool is_error = (sev & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) &&
     519         [ -  + ]:          6 :                     (msgType & VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT);
     520                 :            : 
     521                 :            :     if (is_error) {
     522                 :          0 :         pl_log_stack_trace(log, lev);
     523                 :          0 :         pl_debug_abort();
     524                 :            :         return true;
     525                 :            :     }
     526                 :            : 
     527                 :            :     return false;
     528                 :            : }
     529                 :            : 
     530                 :            : static PFN_vkGetInstanceProcAddr get_proc_addr_fallback(pl_log log,
     531                 :            :                                     PFN_vkGetInstanceProcAddr get_proc_addr)
     532                 :            : {
     533                 :          6 :     if (get_proc_addr)
     534                 :          3 :         return get_proc_addr;
     535                 :            : 
     536                 :            : #ifdef PL_HAVE_VK_PROC_ADDR
     537                 :            :     return vkGetInstanceProcAddr;
     538                 :            : #else
     539                 :            :     pl_fatal(log, "No `vkGetInstanceProcAddr` function provided, and "
     540                 :            :              "libplacebo built without linking against this function!");
     541                 :            :     return NULL;
     542                 :            : #endif
     543                 :            : }
     544                 :            : 
     545                 :            : #define PRINTF_VER(ver) \
     546                 :            :     (int) VK_API_VERSION_MAJOR(ver), \
     547                 :            :     (int) VK_API_VERSION_MINOR(ver), \
     548                 :            :     (int) VK_API_VERSION_PATCH(ver)
     549                 :            : 
     550                 :          1 : pl_vk_inst pl_vk_inst_create(pl_log log, const struct pl_vk_inst_params *params)
     551                 :            : {
     552                 :          1 :     void *tmp = pl_tmp(NULL);
     553         [ -  + ]:          1 :     params = PL_DEF(params, &pl_vk_inst_default_params);
     554                 :          1 :     VkInstance inst = NULL;
     555                 :            :     pl_clock_t start;
     556                 :            : 
     557                 :            :     PL_ARRAY(const char *) exts = {0};
     558                 :            : 
     559                 :            :     PFN_vkGetInstanceProcAddr get_addr;
     560         [ +  - ]:          1 :     if (!(get_addr = get_proc_addr_fallback(log, params->get_proc_addr)))
     561                 :            :         goto error;
     562                 :            : 
     563                 :            :     // Query instance version support
     564                 :          1 :     uint32_t api_ver = VK_API_VERSION_1_0;
     565                 :          1 :     PL_VK_LOAD_FUN(NULL, EnumerateInstanceVersion, get_addr);
     566   [ +  -  -  + ]:          1 :     if (EnumerateInstanceVersion && EnumerateInstanceVersion(&api_ver) != VK_SUCCESS)
     567                 :          0 :         goto error;
     568                 :            : 
     569                 :          1 :     pl_debug(log, "Available instance version: %d.%d.%d", PRINTF_VER(api_ver));
     570                 :            : 
     571         [ -  + ]:          1 :     if (params->max_api_version) {
     572                 :          0 :         api_ver = PL_MIN(api_ver, params->max_api_version);
     573                 :          0 :         pl_info(log, "Restricting API version to %d.%d.%d... new version %d.%d.%d",
     574                 :            :                 PRINTF_VER(params->max_api_version), PRINTF_VER(api_ver));
     575                 :            :     }
     576                 :            : 
     577         [ -  + ]:          1 :     if (api_ver < PL_VK_MIN_VERSION) {
     578                 :          0 :         pl_fatal(log, "Instance API version %d.%d.%d is lower than the minimum "
     579                 :            :                  "required version of %d.%d.%d, cannot proceed!",
     580                 :            :                  PRINTF_VER(api_ver), PRINTF_VER(PL_VK_MIN_VERSION));
     581                 :          0 :         goto error;
     582                 :            :     }
     583                 :            : 
     584                 :          1 :     VkInstanceCreateInfo info = {
     585                 :            :         .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
     586                 :          1 :         .pApplicationInfo = &(VkApplicationInfo) {
     587                 :            :             .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
     588                 :            :             .apiVersion = api_ver,
     589                 :            :         },
     590                 :            :     };
     591                 :            : 
     592                 :            :     // Enumerate all supported layers
     593                 :            :     start = pl_clock_now();
     594                 :          1 :     PL_VK_LOAD_FUN(NULL, EnumerateInstanceLayerProperties, get_addr);
     595                 :          1 :     uint32_t num_layers_avail = 0;
     596                 :          1 :     EnumerateInstanceLayerProperties(&num_layers_avail, NULL);
     597                 :          1 :     VkLayerProperties *layers_avail = pl_calloc_ptr(tmp, num_layers_avail, layers_avail);
     598                 :          1 :     EnumerateInstanceLayerProperties(&num_layers_avail, layers_avail);
     599                 :          1 :     pl_log_cpu_time(log, start, pl_clock_now(), "enumerating instance layers");
     600                 :            : 
     601                 :          1 :     pl_debug(log, "Available layers:");
     602         [ +  + ]:          8 :     for (int i = 0; i < num_layers_avail; i++) {
     603                 :          7 :         pl_debug(log, "    %s (v%d.%d.%d)", layers_avail[i].layerName,
     604                 :            :                  PRINTF_VER(layers_avail[i].specVersion));
     605                 :            :     }
     606                 :            : 
     607                 :            :     PL_ARRAY(const char *) layers = {0};
     608                 :            : 
     609                 :            : 
     610                 :            :     // This layer has to be initialized first, otherwise all sorts of weirdness
     611                 :            :     // happens (random segfaults, yum)
     612                 :          1 :     bool debug = params->debug;
     613                 :            :     uint32_t debug_layer = 0; // layer idx of debug layer
     614                 :            :     uint32_t debug_layer_version = 0;
     615         [ -  + ]:          1 :     if (debug) {
     616         [ +  - ]:          3 :         for (int n = 0; n < num_layers_avail; n++) {
     617                 :            :             const char * const layer = "VK_LAYER_KHRONOS_validation";
     618         [ +  + ]:          3 :             if (strcmp(layer, layers_avail[n].layerName) != 0)
     619                 :            :                 continue;
     620                 :            : 
     621                 :            :             debug_layer = n;
     622                 :          1 :             debug_layer_version = layers_avail[n].specVersion;
     623                 :          1 :             pl_info(log, "Enabling debug layer: %s (v%d.%d.%d)",
     624                 :            :                     layer, PRINTF_VER(debug_layer_version));
     625         [ +  - ]:          1 :             PL_ARRAY_APPEND(tmp, layers, layer);
     626                 :          1 :             goto debug_layers_done;
     627                 :            :         }
     628                 :            : 
     629                 :            :         // No layer found..
     630                 :          0 :         pl_warn(log, "API debugging requested but no debug meta layers present... ignoring");
     631                 :            :         debug = false;
     632                 :            :     }
     633                 :            : 
     634                 :          0 : debug_layers_done: ;
     635                 :            : 
     636         [ -  + ]:          1 :     for (int i = 0; i < params->num_layers; i++)
     637   [ #  #  #  #  :          0 :         PL_ARRAY_APPEND(tmp, layers, params->layers[i]);
                   #  # ]
     638                 :            : 
     639         [ -  + ]:          1 :     for (int i = 0; i < params->num_opt_layers; i++) {
     640                 :          0 :         const char *layer = params->opt_layers[i];
     641         [ #  # ]:          0 :         for (int n = 0; n < num_layers_avail; n++) {
     642         [ #  # ]:          0 :             if (strcmp(layer, layers_avail[n].layerName) == 0) {
     643   [ #  #  #  #  :          0 :                 PL_ARRAY_APPEND(tmp, layers, layer);
                   #  # ]
     644                 :          0 :                 break;
     645                 :            :             }
     646                 :            :         }
     647                 :            :     }
     648                 :            : 
     649                 :            :     // Enumerate all supported extensions
     650                 :            :     start = pl_clock_now();
     651                 :          1 :     PL_VK_LOAD_FUN(NULL, EnumerateInstanceExtensionProperties, get_addr);
     652                 :          1 :     uint32_t num_exts_avail = 0;
     653                 :          1 :     EnumerateInstanceExtensionProperties(NULL, &num_exts_avail, NULL);
     654                 :          1 :     VkExtensionProperties *exts_avail = pl_calloc_ptr(tmp, num_exts_avail, exts_avail);
     655                 :          1 :     EnumerateInstanceExtensionProperties(NULL, &num_exts_avail, exts_avail);
     656                 :            : 
     657                 :            :     struct {
     658                 :            :         VkExtensionProperties *exts;
     659                 :            :         uint32_t num_exts;
     660                 :          1 :     } *layer_exts = pl_calloc_ptr(tmp, num_layers_avail, layer_exts);
     661                 :            : 
     662                 :            :     // Enumerate extensions from layers
     663         [ +  + ]:          8 :     for (int i = 0; i < num_layers_avail; i++) {
     664                 :          7 :         VkExtensionProperties **lexts = &layer_exts[i].exts;
     665                 :          7 :         uint32_t *num = &layer_exts[i].num_exts;
     666                 :            : 
     667                 :          7 :         EnumerateInstanceExtensionProperties(layers_avail[i].layerName, num, NULL);
     668                 :          7 :         *lexts = pl_calloc_ptr(tmp, *num, *lexts);
     669                 :          7 :         EnumerateInstanceExtensionProperties(layers_avail[i].layerName, num, *lexts);
     670                 :            : 
     671                 :            :         // Replace all extensions that are already available globally by {0}
     672         [ +  + ]:         14 :         for (int j = 0; j < *num; j++) {
     673         [ +  + ]:        175 :             for (int k = 0; k < num_exts_avail; k++) {
     674         [ +  + ]:        168 :                 if (strcmp((*lexts)[j].extensionName, exts_avail[k].extensionName) == 0)
     675                 :          2 :                     (*lexts)[j] = (VkExtensionProperties) {0};
     676                 :            :             }
     677                 :            :         }
     678                 :            :     }
     679                 :            : 
     680                 :          1 :     pl_log_cpu_time(log, start, pl_clock_now(), "enumerating instance extensions");
     681                 :          1 :     pl_debug(log, "Available instance extensions:");
     682         [ +  + ]:         25 :     for (int i = 0; i < num_exts_avail; i++)
     683                 :         24 :         pl_debug(log, "    %s", exts_avail[i].extensionName);
     684         [ +  + ]:          8 :     for (int i = 0; i < num_layers_avail; i++) {
     685         [ +  + ]:         14 :         for (int j = 0; j < layer_exts[i].num_exts; j++) {
     686         [ +  + ]:          7 :             if (!layer_exts[i].exts[j].extensionName[0])
     687                 :          2 :                 continue;
     688                 :            : 
     689                 :          5 :             pl_debug(log, "    %s (via %s)",
     690                 :            :                      layer_exts[i].exts[j].extensionName,
     691                 :            :                      layers_avail[i].layerName);
     692                 :            :         }
     693                 :            :     }
     694                 :            : 
     695                 :            :     // Add optional extensions
     696         [ +  + ]:          4 :     for (int i = 0; i < PL_ARRAY_SIZE(vk_instance_extensions); i++) {
     697                 :          3 :         const char *ext = vk_instance_extensions[i];
     698         [ +  - ]:         39 :         for (int n = 0; n < num_exts_avail; n++) {
     699         [ +  + ]:         39 :             if (strcmp(ext, exts_avail[n].extensionName) == 0) {
     700   [ +  +  -  +  :          3 :                 PL_ARRAY_APPEND(tmp, exts, ext);
                   -  + ]
     701                 :          3 :                 break;
     702                 :            :             }
     703                 :            :         }
     704                 :            :     }
     705                 :            : 
     706                 :            : #ifdef VK_KHR_portability_enumeration
     707                 :            :     // Required for macOS ( MoltenVK ) compatibility
     708         [ +  - ]:         23 :     for (int n = 0; n < num_exts_avail; n++) {
     709         [ +  + ]:         23 :         if (strcmp(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME, exts_avail[n].extensionName) == 0) {
     710   [ -  +  -  +  :          1 :             PL_ARRAY_APPEND(tmp, exts, VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME);
                   -  + ]
     711                 :          1 :             info.flags |= VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR;
     712                 :          1 :             break;
     713                 :            :         }
     714                 :            :     }
     715                 :            : #endif
     716                 :            : 
     717                 :            :     // Add extra user extensions
     718         [ -  + ]:          1 :     for (int i = 0; i < params->num_extensions; i++) {
     719                 :          0 :         const char *ext = params->extensions[i];
     720   [ #  #  #  #  :          0 :         PL_ARRAY_APPEND(tmp, exts, ext);
                   #  # ]
     721                 :            : 
     722                 :            :         // Enable any additional layers that are required for this extension
     723         [ #  # ]:          0 :         for (int n = 0; n < num_layers_avail; n++) {
     724         [ #  # ]:          0 :             for (int j = 0; j < layer_exts[n].num_exts; j++) {
     725         [ #  # ]:          0 :                 if (!layer_exts[n].exts[j].extensionName[0])
     726                 :          0 :                     continue;
     727         [ #  # ]:          0 :                 if (strcmp(ext, layer_exts[n].exts[j].extensionName) == 0) {
     728   [ #  #  #  #  :          0 :                     PL_ARRAY_APPEND(tmp, layers, layers_avail[n].layerName);
                   #  # ]
     729                 :          0 :                     goto next_user_ext;
     730                 :            :                 }
     731                 :            :             }
     732                 :            :         }
     733                 :            : 
     734                 :          0 : next_user_ext: ;
     735                 :            :     }
     736                 :            : 
     737                 :            :     // Add extra optional user extensions
     738         [ +  + ]:          3 :     for (int i = 0; i < params->num_opt_extensions; i++) {
     739                 :          2 :         const char *ext = params->opt_extensions[i];
     740         [ +  - ]:         29 :         for (int n = 0; n < num_exts_avail; n++) {
     741         [ +  + ]:         29 :             if (strcmp(ext, exts_avail[n].extensionName) == 0) {
     742   [ -  +  -  +  :          2 :                 PL_ARRAY_APPEND(tmp, exts, ext);
                   -  + ]
     743                 :          2 :                 goto next_opt_user_ext;
     744                 :            :             }
     745                 :            :         }
     746                 :            : 
     747         [ #  # ]:          0 :         for (int n = 0; n < num_layers_avail; n++) {
     748         [ #  # ]:          0 :             for (int j = 0; j < layer_exts[n].num_exts; j++) {
     749         [ #  # ]:          0 :                 if (!layer_exts[n].exts[j].extensionName[0])
     750                 :          0 :                     continue;
     751         [ #  # ]:          0 :                 if (strcmp(ext, layer_exts[n].exts[j].extensionName) == 0) {
     752   [ #  #  #  #  :          0 :                     PL_ARRAY_APPEND(tmp, exts, ext);
                   #  # ]
     753   [ #  #  #  #  :          0 :                     PL_ARRAY_APPEND(tmp, layers, layers_avail[n].layerName);
                   #  # ]
     754                 :          0 :                     goto next_opt_user_ext;
     755                 :            :                 }
     756                 :            :             }
     757                 :            :         }
     758                 :            : 
     759                 :          2 : next_opt_user_ext: ;
     760                 :            :     }
     761                 :            : 
     762                 :          1 :     const VkDebugUtilsMessengerCreateInfoEXT dinfo = {
     763                 :            :         .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT,
     764                 :            :         .messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT |
     765                 :            :                             VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT |
     766                 :            :                             VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT |
     767                 :            :                             VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT,
     768                 :            :         .messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |
     769                 :            :                         VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
     770                 :            :                         VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT,
     771                 :            :         .pfnUserCallback = vk_dbg_utils_cb,
     772                 :            :         .pUserData = (void *) log,
     773                 :            :     };
     774                 :            : 
     775                 :            :     // If debugging is enabled, load the necessary debug utils extension
     776         [ -  + ]:          1 :     if (debug) {
     777                 :            :         const char * const ext = VK_EXT_DEBUG_UTILS_EXTENSION_NAME;
     778         [ +  - ]:         17 :         for (int n = 0; n < num_exts_avail; n++) {
     779         [ +  + ]:         17 :             if (strcmp(ext, exts_avail[n].extensionName) == 0) {
     780   [ -  +  -  +  :          1 :                 PL_ARRAY_APPEND(tmp, exts, ext);
                   -  + ]
     781                 :          1 :                 vk_link_struct(&info, &dinfo);
     782                 :          1 :                 goto debug_ext_done;
     783                 :            :             }
     784                 :            :         }
     785                 :            : 
     786         [ #  # ]:          0 :         for (int n = 0; n < layer_exts[debug_layer].num_exts; n++) {
     787         [ #  # ]:          0 :             if (strcmp(ext, layer_exts[debug_layer].exts[n].extensionName) == 0) {
     788   [ #  #  #  #  :          0 :                 PL_ARRAY_APPEND(tmp, exts, ext);
                   #  # ]
     789                 :          0 :                 vk_link_struct(&info, &dinfo);
     790                 :          0 :                 goto debug_ext_done;
     791                 :            :             }
     792                 :            :         }
     793                 :            : 
     794                 :            :         // No extension found
     795                 :          0 :         pl_warn(log, "API debug layers enabled but no debug report extension "
     796                 :            :                 "found... ignoring. Debug messages may be spilling to "
     797                 :            :                 "stdout/stderr!");
     798                 :            :         debug = false;
     799                 :            :     }
     800                 :            : 
     801                 :          0 : debug_ext_done: ;
     802                 :            : 
     803                 :            :     #define ENABLE_BOOL(name) \
     804                 :            :         {"VK_LAYER_KHRONOS_validation", name, VK_LAYER_SETTING_TYPE_BOOL32_EXT, 1, &(VkBool32){VK_TRUE}}
     805                 :          1 :     const VkLayerSettingEXT debug_settings[] = {
     806                 :          1 :         ENABLE_BOOL("validate_best_practices"),
     807                 :            : 
     808                 :          1 :         ENABLE_BOOL("gpuav_enable"),
     809                 :          1 :         ENABLE_BOOL("gpuav_image_layout"),
     810                 :          1 :         ENABLE_BOOL("gpuav_debug_validate_instrumented_shaders"),
     811                 :            : 
     812                 :          1 :         ENABLE_BOOL("validate_sync"),
     813                 :          1 :         ENABLE_BOOL("syncval_shader_accesses_heuristic"),
     814                 :          1 :         ENABLE_BOOL("syncval_submit_time_validation"),
     815                 :            :     };
     816                 :            : 
     817                 :          1 :     const VkLayerSettingsCreateInfoEXT debug_layer_settings = {
     818                 :            :         .sType = VK_STRUCTURE_TYPE_LAYER_SETTINGS_CREATE_INFO_EXT,
     819                 :            :         .settingCount = PL_ARRAY_SIZE(debug_settings),
     820                 :            :         .pSettings = debug_settings,
     821                 :            :     };
     822                 :            : 
     823                 :            :     // Limit this to 1.3.296+ because of bugs in older versions.
     824   [ -  +  -  +  :          1 :     if (debug && params->debug_extra &&
                   -  + ]
     825                 :            :         debug_layer_version >= VK_MAKE_API_VERSION(0, 1, 3, 296))
     826                 :            :     {
     827                 :            :         const char * const ext = VK_EXT_LAYER_SETTINGS_EXTENSION_NAME;
     828         [ +  + ]:         25 :         for (int n = 0; n < num_exts_avail; n++) {
     829         [ -  + ]:         24 :             if (strcmp(ext, exts_avail[n].extensionName) == 0) {
     830   [ #  #  #  #  :          0 :                 PL_ARRAY_APPEND(tmp, exts, ext);
                   #  # ]
     831                 :          0 :                 vk_link_struct(&info, &debug_layer_settings);
     832                 :          0 :                 goto debug_extra_ext_done;
     833                 :            :             }
     834                 :            :         }
     835                 :            : 
     836         [ +  - ]:          3 :         for (int n = 0; n < layer_exts[debug_layer].num_exts; n++) {
     837         [ +  + ]:          3 :             if (strcmp(ext, layer_exts[debug_layer].exts[n].extensionName) == 0) {
     838   [ -  +  -  +  :          1 :                 PL_ARRAY_APPEND(tmp, exts, ext);
                   -  + ]
     839                 :          1 :                 vk_link_struct(&info, &debug_layer_settings);
     840                 :          1 :                 goto debug_extra_ext_done;
     841                 :            :             }
     842                 :            :         }
     843                 :            : 
     844                 :          0 :         pl_warn(log, "%s not available, debug_extra options were not applied.",
     845                 :            :                 VK_EXT_LAYER_SETTINGS_EXTENSION_NAME);
     846                 :            :     }
     847                 :            : 
     848                 :          0 : debug_extra_ext_done: ;
     849                 :            : 
     850                 :          1 :     info.ppEnabledExtensionNames = exts.elem;
     851                 :          1 :     info.enabledExtensionCount = exts.num;
     852                 :          1 :     info.ppEnabledLayerNames = layers.elem;
     853                 :          1 :     info.enabledLayerCount = layers.num;
     854                 :            : 
     855         [ -  + ]:          1 :     pl_info(log, "Creating vulkan instance%s", exts.num ? " with extensions:" : "");
     856         [ +  + ]:          9 :     for (int i = 0; i < exts.num; i++)
     857                 :          8 :         pl_info(log, "    %s", exts.elem[i]);
     858                 :            : 
     859         [ +  - ]:          1 :     if (layers.num) {
     860                 :          1 :         pl_info(log, "  and layers:");
     861         [ +  + ]:          2 :         for (int i = 0; i < layers.num; i++)
     862                 :          1 :             pl_info(log, "    %s", layers.elem[i]);
     863                 :            :     }
     864                 :            : 
     865                 :            :     start = pl_clock_now();
     866                 :          1 :     PL_VK_LOAD_FUN(NULL, CreateInstance, get_addr);
     867                 :          1 :     VkResult res = CreateInstance(&info, PL_VK_ALLOC, &inst);
     868                 :          1 :     pl_log_cpu_time(log, start, pl_clock_now(), "creating vulkan instance");
     869         [ -  + ]:          1 :     if (res != VK_SUCCESS) {
     870                 :          0 :         pl_fatal(log, "Failed creating instance: %s", vk_res_str(res));
     871                 :          0 :         goto error;
     872                 :            :     }
     873                 :            : 
     874                 :          1 :     struct pl_vk_inst_t *pl_vk = pl_zalloc_obj(NULL, pl_vk, struct priv);
     875                 :          1 :     struct priv *p = PL_PRIV(pl_vk);
     876                 :          2 :     *pl_vk = (struct pl_vk_inst_t) {
     877                 :            :         .instance = inst,
     878                 :            :         .api_version = api_ver,
     879                 :            :         .get_proc_addr = get_addr,
     880                 :          1 :         .extensions = pl_steal(pl_vk, exts.elem),
     881                 :            :         .num_extensions = exts.num,
     882                 :          1 :         .layers = pl_steal(pl_vk, layers.elem),
     883                 :            :         .num_layers = layers.num,
     884                 :            :     };
     885                 :            : 
     886                 :            :     // Set up a debug callback to catch validation messages
     887         [ +  - ]:          1 :     if (debug) {
     888                 :          1 :         PL_VK_LOAD_FUN(inst, CreateDebugUtilsMessengerEXT, get_addr);
     889                 :          1 :         CreateDebugUtilsMessengerEXT(inst, &dinfo, PL_VK_ALLOC, &p->debug_utils_cb);
     890                 :            :     }
     891                 :            : 
     892                 :          1 :     pl_free(tmp);
     893                 :          1 :     return pl_vk;
     894                 :            : 
     895                 :          0 : error:
     896                 :          0 :     pl_fatal(log, "Failed initializing vulkan instance");
     897         [ #  # ]:          0 :     if (inst) {
     898                 :          0 :         PL_VK_LOAD_FUN(inst, DestroyInstance, get_addr);
     899                 :          0 :         DestroyInstance(inst, PL_VK_ALLOC);
     900                 :            :     }
     901                 :          0 :     pl_free(tmp);
     902                 :          0 :     return NULL;
     903                 :            : }
     904                 :            : 
     905                 :            : const struct pl_vulkan_params pl_vulkan_default_params = { PL_VULKAN_DEFAULTS };
     906                 :            : 
     907                 :          3 : void pl_vulkan_destroy(pl_vulkan *pl_vk)
     908                 :            : {
     909         [ +  - ]:          3 :     if (!*pl_vk)
     910                 :            :         return;
     911                 :            : 
     912                 :          3 :     struct vk_ctx *vk = PL_PRIV(*pl_vk);
     913         [ +  - ]:          3 :     if (vk->dev) {
     914         [ +  - ]:          3 :         if ((*pl_vk)->gpu) {
     915                 :          3 :             PL_DEBUG(vk, "Waiting for remaining commands...");
     916                 :          3 :             pl_gpu_finish((*pl_vk)->gpu);
     917         [ -  + ]:          3 :             pl_assert(vk->cmds_pending.num == 0);
     918                 :            : 
     919                 :          3 :             pl_gpu_destroy((*pl_vk)->gpu);
     920                 :            :         }
     921                 :          3 :         vk_malloc_destroy(&vk->ma);
     922         [ +  + ]:          6 :         for (int i = 0; i < vk->pools.num; i++)
     923                 :          3 :             vk_cmdpool_destroy(vk->pools.elem[i]);
     924                 :            : 
     925         [ +  + ]:          3 :         if (!vk->imported)
     926                 :          2 :             vk->DestroyDevice(vk->dev, PL_VK_ALLOC);
     927                 :            :     }
     928                 :            : 
     929         [ +  + ]:          6 :     for (int i = 0; i < vk->queue_locks.num; i++) {
     930         [ +  + ]:          6 :         for (int n = 0; n < vk->queue_locks.elem[i].num; n++)
     931                 :          3 :             pl_mutex_destroy(&vk->queue_locks.elem[i].elem[n]);
     932                 :            :     }
     933                 :            : 
     934                 :          3 :     pl_vk_inst_destroy(&vk->internal_instance);
     935                 :          3 :     pl_mutex_destroy(&vk->lock);
     936                 :          3 :     pl_free_ptr((void **) pl_vk);
     937                 :            : }
     938                 :            : 
     939                 :          2 : static bool supports_surf(pl_log log, VkInstance inst,
     940                 :            :                           PFN_vkGetInstanceProcAddr get_addr,
     941                 :            :                           VkPhysicalDevice physd, VkSurfaceKHR surf)
     942                 :            : {
     943                 :            :     // Hack for the VK macro's logging to work
     944                 :            :     struct { pl_log log; } *vk = (void *) &log;
     945                 :            : 
     946                 :          2 :     PL_VK_LOAD_FUN(inst, GetPhysicalDeviceQueueFamilyProperties, get_addr);
     947                 :          2 :     PL_VK_LOAD_FUN(inst, GetPhysicalDeviceSurfaceSupportKHR, get_addr);
     948                 :          2 :     uint32_t qfnum = 0;
     949                 :          2 :     GetPhysicalDeviceQueueFamilyProperties(physd, &qfnum, NULL);
     950                 :            : 
     951         [ +  - ]:          2 :     for (int i = 0; i < qfnum; i++) {
     952                 :          2 :         VkBool32 sup = false;
     953         [ -  + ]:          2 :         VK(GetPhysicalDeviceSurfaceSupportKHR(physd, i, surf, &sup));
     954         [ +  - ]:          2 :         if (sup)
     955                 :          2 :             return true;
     956                 :            :     }
     957                 :            : 
     958                 :          0 : error:
     959                 :            :     return false;
     960                 :            : }
     961                 :            : 
     962                 :          2 : VkPhysicalDevice pl_vulkan_choose_device(pl_log log,
     963                 :            :                                 const struct pl_vulkan_device_params *params)
     964                 :            : {
     965                 :            :     // Hack for the VK macro's logging to work
     966                 :            :     struct { pl_log log; } *vk = (void *) &log;
     967                 :          2 :     PL_INFO(vk, "Probing for vulkan devices:");
     968                 :            : 
     969         [ -  + ]:          2 :     pl_assert(params->instance);
     970                 :            :     VkInstance inst = params->instance;
     971                 :            :     VkPhysicalDevice dev = VK_NULL_HANDLE;
     972                 :            : 
     973                 :            :     PFN_vkGetInstanceProcAddr get_addr;
     974         [ +  - ]:          2 :     if (!(get_addr = get_proc_addr_fallback(log, params->get_proc_addr)))
     975                 :            :         return NULL;
     976                 :            : 
     977                 :          2 :     PL_VK_LOAD_FUN(inst, EnumeratePhysicalDevices, get_addr);
     978                 :          2 :     PL_VK_LOAD_FUN(inst, GetPhysicalDeviceProperties2, get_addr);
     979         [ -  + ]:          2 :     pl_assert(GetPhysicalDeviceProperties2);
     980                 :            : 
     981                 :            :     pl_clock_t start = pl_clock_now();
     982                 :            :     VkPhysicalDevice *devices = NULL;
     983                 :          2 :     uint32_t num = 0;
     984         [ -  + ]:          2 :     VK(EnumeratePhysicalDevices(inst, &num, NULL));
     985                 :          2 :     devices = pl_calloc_ptr(NULL, num, devices);
     986         [ -  + ]:          2 :     VK(EnumeratePhysicalDevices(inst, &num, devices));
     987                 :          2 :     pl_log_cpu_time(log, start, pl_clock_now(), "enumerating physical devices");
     988                 :            : 
     989                 :            :     static const struct { const char *name; int priority; } types[] = {
     990                 :            :         [VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU]   = {"discrete",   5},
     991                 :            :         [VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU] = {"integrated", 4},
     992                 :            :         [VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU]    = {"virtual",    3},
     993                 :            :         [VK_PHYSICAL_DEVICE_TYPE_CPU]            = {"software",   2},
     994                 :            :         [VK_PHYSICAL_DEVICE_TYPE_OTHER]          = {"other",      1},
     995                 :            :     };
     996                 :            : 
     997                 :            :     static const uint8_t nil[VK_UUID_SIZE] = {0};
     998                 :          2 :     bool uuid_set = memcmp(params->device_uuid, nil, VK_UUID_SIZE) != 0;
     999                 :            : 
    1000                 :            :     int best = -1;
    1001         [ +  + ]:          6 :     for (int i = 0; i < num; i++) {
    1002                 :          4 :         VkPhysicalDeviceIDPropertiesKHR id_props = {
    1003                 :            :             .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES_KHR,
    1004                 :            :         };
    1005                 :            : 
    1006                 :          4 :         VkPhysicalDeviceProperties2 prop = {
    1007                 :            :             .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR,
    1008                 :            :             .pNext = &id_props,
    1009                 :            :         };
    1010                 :            : 
    1011                 :          4 :         GetPhysicalDeviceProperties2(devices[i], &prop);
    1012                 :          4 :         VkPhysicalDeviceType t = prop.properties.deviceType;
    1013         [ +  - ]:          4 :         const char *dtype = t < PL_ARRAY_SIZE(types) ? types[t].name : "unknown?";
    1014                 :          4 :         PL_INFO(vk, "    GPU %d: %s v%d.%d.%d (%s)", i, prop.properties.deviceName,
    1015                 :            :                 PRINTF_VER(prop.properties.apiVersion), dtype);
    1016                 :          4 :         PL_INFO(vk, "           uuid: %s", PRINT_UUID(id_props.deviceUUID));
    1017                 :            : 
    1018         [ +  + ]:          4 :         if (params->surface) {
    1019         [ -  + ]:          2 :             if (!supports_surf(log, inst, get_addr, devices[i], params->surface)) {
    1020                 :          0 :                 PL_DEBUG(vk, "      -> excluding due to lack of surface support");
    1021                 :          2 :                 continue;
    1022                 :            :             }
    1023                 :            :         }
    1024                 :            : 
    1025         [ -  + ]:          4 :         if (uuid_set) {
    1026         [ #  # ]:          0 :             if (memcmp(id_props.deviceUUID, params->device_uuid, VK_UUID_SIZE) == 0) {
    1027                 :          0 :                 dev = devices[i];
    1028                 :          0 :                 continue;
    1029                 :            :             } else {
    1030                 :          0 :                 PL_DEBUG(vk, "     -> excluding due to UUID mismatch");
    1031                 :          0 :                 continue;
    1032                 :            :             }
    1033   [ +  +  +  - ]:          4 :         } else if (params->device_name && params->device_name[0] != '\0') {
    1034         [ +  + ]:          2 :             if (strcmp(params->device_name, prop.properties.deviceName) == 0) {
    1035                 :          1 :                 dev = devices[i];
    1036                 :          1 :                 continue;
    1037                 :            :             } else {
    1038                 :          1 :                 PL_DEBUG(vk, "      -> excluding due to name mismatch");
    1039                 :          1 :                 continue;
    1040                 :            :             }
    1041                 :            :         }
    1042                 :            : 
    1043   [ -  +  -  - ]:          2 :         if (!params->allow_software && t == VK_PHYSICAL_DEVICE_TYPE_CPU) {
    1044                 :          0 :             PL_DEBUG(vk, "      -> excluding due to !params->allow_software");
    1045                 :          0 :             continue;
    1046                 :            :         }
    1047                 :            : 
    1048         [ -  + ]:          2 :         if (prop.properties.apiVersion < PL_VK_MIN_VERSION) {
    1049                 :          0 :             PL_DEBUG(vk, "      -> excluding due to too low API version");
    1050                 :          0 :             continue;
    1051                 :            :         }
    1052                 :            : 
    1053         [ +  - ]:          2 :         int priority = t < PL_ARRAY_SIZE(types) ? types[t].priority : 0;
    1054         [ +  + ]:          2 :         if (priority > best) {
    1055                 :          1 :             dev = devices[i];
    1056                 :            :             best = priority;
    1057                 :            :         }
    1058                 :            :     }
    1059                 :            : 
    1060                 :          2 : error:
    1061                 :          2 :     pl_free(devices);
    1062                 :            :     return dev;
    1063                 :            : }
    1064                 :            : 
    1065                 :        800 : static void lock_queue_internal(void *priv, uint32_t qf, uint32_t qidx)
    1066                 :            : {
    1067                 :            :     struct vk_ctx *vk = priv;
    1068                 :        800 :     pl_mutex_lock(&vk->queue_locks.elem[qf].elem[qidx]);
    1069                 :        800 : }
    1070                 :            : 
    1071                 :        800 : static void unlock_queue_internal(void *priv, uint32_t qf, uint32_t qidx)
    1072                 :            : {
    1073                 :            :     struct vk_ctx *vk = priv;
    1074                 :        800 :     pl_mutex_unlock(&vk->queue_locks.elem[qf].elem[qidx]);
    1075                 :        800 : }
    1076                 :            : 
    1077                 :          3 : static void init_queue_locks(struct vk_ctx *vk, uint32_t qfnum,
    1078                 :            :                              const VkQueueFamilyProperties *qfs)
    1079                 :            : {
    1080                 :          3 :     vk->queue_locks.elem = pl_calloc_ptr(vk->alloc, qfnum, vk->queue_locks.elem);
    1081                 :          3 :     vk->queue_locks.num = qfnum;
    1082         [ +  + ]:          6 :     for (int i = 0; i < qfnum; i++) {
    1083                 :          3 :         const uint32_t qnum = qfs[i].queueCount;
    1084                 :          3 :         vk->queue_locks.elem[i].elem = pl_calloc(vk->alloc, qnum, sizeof(pl_mutex));
    1085                 :          3 :         vk->queue_locks.elem[i].num = qnum;
    1086         [ +  + ]:          6 :         for (int n = 0; n < qnum; n++)
    1087         [ -  + ]:          3 :             pl_mutex_init(&vk->queue_locks.elem[i].elem[n]);
    1088                 :            :     }
    1089                 :            : 
    1090                 :          3 :     vk->lock_queue = lock_queue_internal;
    1091                 :          3 :     vk->unlock_queue = unlock_queue_internal;
    1092                 :          3 :     vk->queue_ctx = vk;
    1093                 :          3 : }
    1094                 :            : 
    1095                 :            : // Find the most specialized queue supported a combination of flags. In cases
    1096                 :            : // where there are multiple queue families at the same specialization level,
    1097                 :            : // this finds the one with the most queues. Returns -1 if no queue was found.
    1098                 :          6 : static int find_qf(VkQueueFamilyProperties *qfs, int qfnum, VkQueueFlags flags)
    1099                 :            : {
    1100                 :            :     int idx = -1;
    1101         [ +  + ]:         12 :     for (int i = 0; i < qfnum; i++) {
    1102         [ -  + ]:          6 :         if ((qfs[i].queueFlags & flags) != flags)
    1103                 :          0 :             continue;
    1104                 :            : 
    1105                 :            :         // QF is more specialized. Since we don't care about other bits like
    1106                 :            :         // SPARSE_BIT, mask the ones we're interestew in
    1107                 :            :         const VkQueueFlags mask = VK_QUEUE_GRAPHICS_BIT |
    1108                 :            :                                   VK_QUEUE_TRANSFER_BIT |
    1109                 :            :                                   VK_QUEUE_COMPUTE_BIT;
    1110                 :            : 
    1111   [ -  +  -  - ]:          6 :         if (idx < 0 || (qfs[i].queueFlags & mask) < (qfs[idx].queueFlags & mask))
    1112                 :            :             idx = i;
    1113                 :            : 
    1114                 :            :         // QF has more queues (at the same specialization level)
    1115         [ -  + ]:          6 :         if (qfs[i].queueFlags == qfs[idx].queueFlags &&
    1116         [ +  - ]:          6 :             qfs[i].queueCount > qfs[idx].queueCount)
    1117                 :            :             idx = i;
    1118                 :            :     }
    1119                 :            : 
    1120                 :          6 :     return idx;
    1121                 :            : }
    1122                 :            : 
    1123                 :          2 : static bool device_init(struct vk_ctx *vk, const struct pl_vulkan_params *params)
    1124                 :            : {
    1125         [ -  + ]:          2 :     pl_assert(vk->physd);
    1126                 :          2 :     void *tmp = pl_tmp(NULL);
    1127                 :            : 
    1128                 :            :     // Enumerate the queue families and find suitable families for each task
    1129                 :          2 :     uint32_t qfnum = 0;
    1130                 :          2 :     vk->GetPhysicalDeviceQueueFamilyProperties(vk->physd, &qfnum, NULL);
    1131                 :          2 :     VkQueueFamilyProperties *qfs = pl_calloc_ptr(tmp, qfnum, qfs);
    1132                 :          2 :     vk->GetPhysicalDeviceQueueFamilyProperties(vk->physd, &qfnum, qfs);
    1133                 :          2 :     init_queue_locks(vk, qfnum, qfs);
    1134                 :            : 
    1135                 :          2 :     PL_DEBUG(vk, "Queue families supported by device:");
    1136         [ +  + ]:          4 :     for (int i = 0; i < qfnum; i++) {
    1137                 :          2 :         PL_DEBUG(vk, "    %d: flags 0x%"PRIx32" num %"PRIu32, i,
    1138                 :            :                  qfs[i].queueFlags, qfs[i].queueCount);
    1139                 :            :     }
    1140                 :            : 
    1141                 :            :     VkQueueFlagBits gfx_flags = VK_QUEUE_GRAPHICS_BIT;
    1142         [ +  + ]:          2 :     if (!params->async_compute)
    1143                 :            :         gfx_flags |= VK_QUEUE_COMPUTE_BIT;
    1144                 :            : 
    1145                 :          2 :     int idx_gfx  = find_qf(qfs, qfnum, gfx_flags);
    1146                 :          2 :     int idx_comp = find_qf(qfs, qfnum, VK_QUEUE_COMPUTE_BIT);
    1147                 :          2 :     int idx_tf   = find_qf(qfs, qfnum, VK_QUEUE_TRANSFER_BIT);
    1148         [ -  + ]:          2 :     if (idx_tf < 0)
    1149                 :            :         idx_tf = idx_comp;
    1150                 :            : 
    1151         [ +  + ]:          2 :     if (!params->async_compute)
    1152                 :            :         idx_comp = idx_gfx;
    1153         [ +  + ]:          2 :     if (!params->async_transfer)
    1154                 :            :         idx_tf = idx_gfx;
    1155                 :            : 
    1156                 :          2 :     PL_DEBUG(vk, "Using graphics queue %d", idx_gfx);
    1157         [ -  + ]:          2 :     if (idx_tf != idx_gfx)
    1158                 :          0 :         PL_INFO(vk, "Using async transfer (queue %d)", idx_tf);
    1159         [ -  + ]:          2 :     if (idx_comp != idx_gfx)
    1160                 :          0 :         PL_INFO(vk, "Using async compute (queue %d)", idx_comp);
    1161                 :            : 
    1162                 :            :     // Vulkan requires at least one GRAPHICS+COMPUTE queue, so if this fails
    1163                 :            :     // something is horribly wrong.
    1164   [ +  -  -  + ]:          2 :     pl_assert(idx_gfx >= 0 && idx_comp >= 0 && idx_tf >= 0);
    1165                 :            : 
    1166                 :            :     // If needed, ensure we can actually present to the surface using this queue
    1167         [ +  - ]:          2 :     if (params->surface) {
    1168                 :          2 :         VkBool32 sup = false;
    1169         [ -  + ]:          2 :         VK(vk->GetPhysicalDeviceSurfaceSupportKHR(vk->physd, idx_gfx,
    1170                 :            :                                                   params->surface, &sup));
    1171         [ -  + ]:          2 :         if (!sup) {
    1172                 :          0 :             PL_FATAL(vk, "Queue family does not support surface presentation!");
    1173                 :          0 :             goto error;
    1174                 :            :         }
    1175                 :            :     }
    1176                 :            : 
    1177                 :            :     // Enumerate all supported extensions
    1178                 :            :     pl_clock_t start = pl_clock_now();
    1179                 :          2 :     uint32_t num_exts_avail = 0;
    1180         [ -  + ]:          2 :     VK(vk->EnumerateDeviceExtensionProperties(vk->physd, NULL, &num_exts_avail, NULL));
    1181                 :          2 :     VkExtensionProperties *exts_avail = pl_calloc_ptr(tmp, num_exts_avail, exts_avail);
    1182         [ -  + ]:          2 :     VK(vk->EnumerateDeviceExtensionProperties(vk->physd, NULL, &num_exts_avail, exts_avail));
    1183                 :          2 :     pl_log_cpu_time(vk->log, start, pl_clock_now(), "enumerating device extensions");
    1184                 :            : 
    1185                 :          2 :     PL_DEBUG(vk, "Available device extensions:");
    1186         [ +  + ]:        324 :     for (int i = 0; i < num_exts_avail; i++)
    1187                 :        322 :         PL_DEBUG(vk, "    %s", exts_avail[i].extensionName);
    1188                 :            : 
    1189                 :            :     // Add all extensions we need
    1190         [ +  - ]:          2 :     if (params->surface)
    1191   [ +  -  -  -  :          2 :         PL_ARRAY_APPEND(vk->alloc, vk->exts, VK_KHR_SWAPCHAIN_EXTENSION_NAME);
                   -  - ]
    1192                 :            : 
    1193                 :            :     // Keep track of all optional function pointers associated with extensions
    1194                 :            :     PL_ARRAY(const struct vk_fun *) ext_funs = {0};
    1195                 :            : 
    1196                 :            :     // Add all optional device-level extensions extensions
    1197         [ +  + ]:         24 :     for (int i = 0; i < PL_ARRAY_SIZE(vk_device_extensions); i++) {
    1198                 :            :         const struct vk_ext *ext = &vk_device_extensions[i];
    1199                 :         22 :         uint32_t core_ver = vk_ext_promoted_ver(ext->name);
    1200   [ +  +  +  + ]:         22 :         if (core_ver && vk->api_ver >= core_ver) {
    1201                 :            :             // Layer is already implicitly enabled by the API version
    1202   [ +  -  +  + ]:          6 :             for (const struct vk_fun *f = ext->funs; f && f->name; f++)
    1203   [ -  +  -  +  :          4 :                 PL_ARRAY_APPEND(tmp, ext_funs,  f);
                   -  + ]
    1204                 :          2 :             continue;
    1205                 :            :         }
    1206                 :            : 
    1207         [ +  + ]:       1790 :         for (int n = 0; n < num_exts_avail; n++) {
    1208         [ +  + ]:       1786 :             if (strcmp(ext->name, exts_avail[n].extensionName) == 0) {
    1209   [ -  +  -  +  :         16 :                 PL_ARRAY_APPEND(vk->alloc, vk->exts, ext->name);
                   -  + ]
    1210   [ +  +  +  + ]:         38 :                 for (const struct vk_fun *f = ext->funs; f && f->name; f++)
    1211   [ +  +  +  +  :         22 :                     PL_ARRAY_APPEND(tmp, ext_funs, f);
                   -  + ]
    1212                 :            :                 break;
    1213                 :            :             }
    1214                 :            :         }
    1215                 :            :     }
    1216                 :            : 
    1217                 :            :     // Add extra user extensions
    1218         [ -  + ]:          2 :     for (int i = 0; i < params->num_extensions; i++)
    1219   [ #  #  #  #  :          0 :         PL_ARRAY_APPEND(vk->alloc, vk->exts, params->extensions[i]);
                   #  # ]
    1220                 :            : 
    1221                 :            :     // Add optional extra user extensions
    1222         [ -  + ]:          2 :     for (int i = 0; i < params->num_opt_extensions; i++) {
    1223                 :          0 :         const char *ext = params->opt_extensions[i];
    1224         [ #  # ]:          0 :         for (int n = 0; n < num_exts_avail; n++) {
    1225         [ #  # ]:          0 :             if (strcmp(ext, exts_avail[n].extensionName) == 0) {
    1226   [ #  #  #  #  :          0 :                 PL_ARRAY_APPEND(vk->alloc, vk->exts, ext);
                   #  # ]
    1227                 :          0 :                 break;
    1228                 :            :             }
    1229                 :            :         }
    1230                 :            :     }
    1231                 :            : 
    1232                 :          2 :     VkPhysicalDeviceFeatures2 features = {
    1233                 :            :         .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR
    1234                 :            :     };
    1235                 :            : 
    1236                 :          2 :     vk_features_normalize(tmp, &pl_vulkan_required_features, vk->api_ver, &features);
    1237                 :          2 :     vk_features_normalize(tmp, &pl_vulkan_recommended_features, vk->api_ver, &features);
    1238                 :          2 :     vk_features_normalize(tmp, params->features, vk->api_ver, &features);
    1239                 :            : 
    1240                 :            :     // Explicitly clear the features struct before querying feature support
    1241                 :            :     // from the driver. This way, we don't mistakenly mark as supported
    1242                 :            :     // features coming from structs the driver doesn't have support for.
    1243                 :          2 :     VkPhysicalDeviceFeatures2 *features_sup = vk_chain_memdup(tmp, &features);;
    1244         [ +  + ]:         10 :     for (VkBaseOutStructure *out = (void *) features_sup; out; out = out->pNext) {
    1245                 :          8 :         const size_t size = vk_struct_size(out->sType);
    1246                 :          8 :         memset(&out[1], 0, size - sizeof(out[0]));
    1247                 :            :     }
    1248                 :            : 
    1249                 :          2 :     vk->GetPhysicalDeviceFeatures2KHR(vk->physd, features_sup);
    1250                 :            : 
    1251                 :            :     // Filter out unsupported features
    1252         [ +  + ]:         10 :     for (VkBaseOutStructure *f = (VkBaseOutStructure *) &features; f; f = f->pNext) {
    1253                 :          8 :         const VkBaseInStructure *sup = vk_find_struct(features_sup, f->sType);
    1254                 :            :         VkBool32 *flags = (VkBool32 *) &f[1];
    1255                 :            :         const VkBool32 *flags_sup = (const VkBool32 *) &sup[1];
    1256                 :          8 :         const size_t size = vk_struct_size(f->sType) - sizeof(VkBaseOutStructure);
    1257         [ +  + ]:        272 :         for (int i = 0; i < size / sizeof(VkBool32); i++)
    1258                 :        264 :             flags[i] &= flags_sup[i];
    1259                 :            :     }
    1260                 :            : 
    1261                 :            :     // Construct normalized output chain
    1262                 :          2 :     vk->features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
    1263                 :          2 :     vk_features_normalize(vk->alloc, &features, vk->api_ver, &vk->features);
    1264         [ -  + ]:          2 :     if (!check_required_features(vk)) {
    1265                 :          0 :         PL_FATAL(vk, "Vulkan device does not support all required features!");
    1266                 :          0 :         goto error;
    1267                 :            :     }
    1268                 :            : 
    1269                 :            :     // Enable all queues at device creation time, to maximize compatibility
    1270                 :            :     // with other API users (e.g. FFmpeg)
    1271                 :            :     PL_ARRAY(VkDeviceQueueCreateInfo) qinfos = {0};
    1272         [ +  + ]:          4 :     for (int i = 0; i < qfnum; i++) {
    1273   [ -  +  -  - ]:          2 :         bool use_qf = i == idx_gfx || i == idx_comp || i == idx_tf;
    1274                 :          2 :         use_qf |= qfs[i].queueFlags & params->extra_queues;
    1275         [ -  + ]:          2 :         if (!use_qf)
    1276                 :          0 :             continue;
    1277   [ +  -  -  -  :          2 :         PL_ARRAY_APPEND(tmp, qinfos, (VkDeviceQueueCreateInfo) {
                   -  - ]
    1278                 :            :             .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
    1279                 :            :             .queueFamilyIndex = i,
    1280                 :            :             .queueCount = qfs[i].queueCount,
    1281                 :            :             .pQueuePriorities = pl_calloc(tmp, qfs[i].queueCount, sizeof(float)),
    1282                 :            :         });
    1283                 :            :     }
    1284                 :            : 
    1285                 :          2 :     VkDeviceCreateInfo dinfo = {
    1286                 :            :         .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
    1287                 :            :         .pNext = &vk->features,
    1288                 :            :         .pQueueCreateInfos = qinfos.elem,
    1289                 :          2 :         .queueCreateInfoCount = qinfos.num,
    1290                 :          2 :         .ppEnabledExtensionNames = vk->exts.elem,
    1291                 :          2 :         .enabledExtensionCount = vk->exts.num,
    1292                 :            :     };
    1293                 :            : 
    1294         [ -  + ]:          2 :     PL_INFO(vk, "Creating vulkan device%s", vk->exts.num ? " with extensions:" : "");
    1295         [ +  + ]:         20 :     for (int i = 0; i < vk->exts.num; i++)
    1296                 :         18 :         PL_INFO(vk, "    %s", vk->exts.elem[i]);
    1297                 :            : 
    1298                 :            :     start = pl_clock_now();
    1299         [ -  + ]:          2 :     VK(vk->CreateDevice(vk->physd, &dinfo, PL_VK_ALLOC, &vk->dev));
    1300                 :          2 :     pl_log_cpu_time(vk->log, start, pl_clock_now(), "creating vulkan device");
    1301                 :            : 
    1302                 :            :     // Load all mandatory device-level functions
    1303         [ +  + ]:        176 :     for (int i = 0; i < PL_ARRAY_SIZE(vk_dev_funs); i++)
    1304                 :        174 :         load_vk_fun(vk, &vk_dev_funs[i]);
    1305                 :            : 
    1306                 :            :     // Load all of the optional functions from the extensions we enabled
    1307         [ +  + ]:         28 :     for (int i = 0; i < ext_funs.num; i++)
    1308                 :         26 :         load_vk_fun(vk, ext_funs.elem[i]);
    1309                 :            : 
    1310                 :            :     // Create the command pools for the queues we care about
    1311         [ +  - ]:          2 :     const uint32_t qmax = PL_DEF(params->queue_count, UINT32_MAX);
    1312         [ +  + ]:          4 :     for (int i = 0; i < qfnum; i++) {
    1313   [ -  +  -  - ]:          2 :         if (i != idx_gfx && i != idx_tf && i != idx_comp)
    1314                 :          0 :             continue; // ignore QFs not used internally
    1315                 :            : 
    1316                 :          2 :         int qnum = qfs[i].queueCount;
    1317         [ -  + ]:          2 :         if (qmax < qnum) {
    1318                 :          0 :             PL_DEBUG(vk, "Restricting QF %d from %d queues to %d", i, qnum, qmax);
    1319                 :          0 :             qnum = qmax;
    1320                 :            :         }
    1321                 :            : 
    1322                 :          2 :         struct vk_cmdpool *pool = vk_cmdpool_create(vk, i, qnum, qfs[i]);
    1323         [ -  + ]:          2 :         if (!pool)
    1324                 :          0 :             goto error;
    1325   [ +  -  -  -  :          2 :         PL_ARRAY_APPEND(vk->alloc, vk->pools, pool);
                   -  - ]
    1326                 :            : 
    1327                 :            :         // Update the pool_* pointers based on the corresponding index
    1328                 :            :         const char *qf_name = NULL;
    1329         [ +  - ]:          2 :         if (i == idx_tf) {
    1330                 :          2 :             vk->pool_transfer = pool;
    1331                 :            :             qf_name = "transfer";
    1332                 :            :         }
    1333         [ +  - ]:          2 :         if (i == idx_comp) {
    1334                 :          2 :             vk->pool_compute = pool;
    1335                 :            :             qf_name = "compute";
    1336                 :            :         }
    1337         [ +  - ]:          2 :         if (i == idx_gfx) {
    1338                 :          2 :             vk->pool_graphics = pool;
    1339                 :            :             qf_name = "graphics";
    1340                 :            :         }
    1341                 :            : 
    1342         [ +  + ]:          4 :         for (int n = 0; n < pool->num_queues; n++)
    1343         [ +  - ]:          2 :             PL_VK_NAME_HANDLE(QUEUE, pool->queues[n], qf_name);
    1344                 :            :     }
    1345                 :            : 
    1346                 :          2 :     pl_free(tmp);
    1347                 :          2 :     return true;
    1348                 :            : 
    1349                 :          0 : error:
    1350                 :          0 :     PL_FATAL(vk, "Failed creating logical device!");
    1351                 :          0 :     pl_free(tmp);
    1352                 :          0 :     vk->failed = true;
    1353                 :          0 :     return false;
    1354                 :            : }
    1355                 :            : 
    1356                 :          0 : static void lock_queue(pl_vulkan pl_vk, uint32_t qf, uint32_t qidx)
    1357                 :            : {
    1358                 :          0 :     struct vk_ctx *vk = PL_PRIV(pl_vk);
    1359                 :          0 :     vk->lock_queue(vk->queue_ctx, qf, qidx);
    1360                 :          0 : }
    1361                 :            : 
    1362                 :          0 : static void unlock_queue(pl_vulkan pl_vk, uint32_t qf, uint32_t qidx)
    1363                 :            : {
    1364                 :          0 :     struct vk_ctx *vk = PL_PRIV(pl_vk);
    1365                 :          0 :     vk->unlock_queue(vk->queue_ctx, qf, qidx);
    1366                 :          0 : }
    1367                 :            : 
    1368                 :          3 : static bool finalize_context(struct pl_vulkan_t *pl_vk, int max_glsl_version,
    1369                 :            :                              bool no_compute)
    1370                 :            : {
    1371                 :          3 :     struct vk_ctx *vk = PL_PRIV(pl_vk);
    1372                 :            : 
    1373         [ -  + ]:          3 :     pl_assert(vk->pool_graphics);
    1374         [ -  + ]:          3 :     pl_assert(vk->pool_compute);
    1375         [ -  + ]:          3 :     pl_assert(vk->pool_transfer);
    1376                 :            : 
    1377                 :          3 :     vk->ma = vk_malloc_create(vk);
    1378         [ +  - ]:          3 :     if (!vk->ma)
    1379                 :            :         return false;
    1380                 :            : 
    1381                 :          3 :     pl_vk->gpu = pl_gpu_create_vk(vk);
    1382         [ +  - ]:          3 :     if (!pl_vk->gpu)
    1383                 :            :         return false;
    1384                 :            : 
    1385                 :            :     // Blacklist / restrict features
    1386                 :            :     struct pl_glsl_version *glsl = (struct pl_glsl_version *) &pl_vk->gpu->glsl;
    1387         [ -  + ]:          3 :     if (max_glsl_version) {
    1388                 :          0 :         glsl->version = PL_MIN(glsl->version, max_glsl_version);
    1389                 :          0 :         glsl->version = PL_MAX(glsl->version, 140); // required for GL_KHR_vulkan_glsl
    1390                 :          0 :         PL_INFO(vk, "Restricting GLSL version to %d... new version is %d",
    1391                 :            :                 max_glsl_version, glsl->version);
    1392                 :            :     }
    1393                 :            : 
    1394                 :          3 :     glsl->compute &= !no_compute;
    1395                 :            : 
    1396                 :            :     // Expose the resulting vulkan objects
    1397                 :          3 :     pl_vk->instance = vk->inst;
    1398                 :          3 :     pl_vk->phys_device = vk->physd;
    1399                 :          3 :     pl_vk->device = vk->dev;
    1400                 :          3 :     pl_vk->get_proc_addr = vk->GetInstanceProcAddr;
    1401                 :          3 :     pl_vk->api_version = vk->api_ver;
    1402                 :          3 :     pl_vk->extensions = vk->exts.elem;
    1403                 :          3 :     pl_vk->num_extensions = vk->exts.num;
    1404                 :          3 :     pl_vk->features = &vk->features;
    1405                 :          3 :     pl_vk->num_queues = vk->pools.num;
    1406                 :          3 :     pl_vk->queues = pl_calloc_ptr(vk->alloc, vk->pools.num, pl_vk->queues);
    1407                 :          3 :     pl_vk->lock_queue = lock_queue;
    1408                 :          3 :     pl_vk->unlock_queue = unlock_queue;
    1409                 :            : 
    1410         [ +  + ]:          6 :     for (int i = 0; i < vk->pools.num; i++) {
    1411                 :            :         struct pl_vulkan_queue *queues = (struct pl_vulkan_queue *) pl_vk->queues;
    1412                 :          3 :         queues[i] = (struct pl_vulkan_queue) {
    1413                 :          3 :             .index = vk->pools.elem[i]->qf,
    1414                 :          3 :             .count = vk->pools.elem[i]->num_queues,
    1415                 :            :         };
    1416                 :            : 
    1417         [ +  - ]:          3 :         if (vk->pools.elem[i] == vk->pool_graphics)
    1418                 :          3 :             pl_vk->queue_graphics = queues[i];
    1419         [ +  - ]:          3 :         if (vk->pools.elem[i] == vk->pool_compute)
    1420                 :          3 :             pl_vk->queue_compute = queues[i];
    1421         [ +  - ]:          3 :         if (vk->pools.elem[i] == vk->pool_transfer)
    1422                 :          3 :             pl_vk->queue_transfer = queues[i];
    1423                 :            :     }
    1424                 :            : 
    1425         [ -  + ]:          3 :     pl_assert(vk->lock_queue);
    1426         [ -  + ]:          3 :     pl_assert(vk->unlock_queue);
    1427                 :            :     return true;
    1428                 :            : }
    1429                 :            : 
    1430                 :          2 : pl_vulkan pl_vulkan_create(pl_log log, const struct pl_vulkan_params *params)
    1431                 :            : {
    1432         [ -  + ]:          2 :     params = PL_DEF(params, &pl_vulkan_default_params);
    1433                 :          2 :     struct pl_vulkan_t *pl_vk = pl_zalloc_obj(NULL, pl_vk, struct vk_ctx);
    1434                 :          2 :     struct vk_ctx *vk = PL_PRIV(pl_vk);
    1435                 :          2 :     *vk = (struct vk_ctx) {
    1436                 :            :         .vulkan = pl_vk,
    1437                 :            :         .alloc = pl_vk,
    1438                 :            :         .log = log,
    1439                 :          2 :         .inst = params->instance,
    1440         [ +  - ]:          2 :         .GetInstanceProcAddr = get_proc_addr_fallback(log, params->get_proc_addr),
    1441                 :            :     };
    1442                 :            : 
    1443         [ -  + ]:          2 :     pl_mutex_init_type(&vk->lock, PL_MUTEX_RECURSIVE);
    1444         [ -  + ]:          2 :     if (!vk->GetInstanceProcAddr)
    1445                 :          0 :         goto error;
    1446                 :            : 
    1447         [ -  + ]:          2 :     if (!vk->inst) {
    1448         [ #  # ]:          0 :         pl_assert(!params->surface);
    1449         [ #  # ]:          0 :         pl_assert(!params->device);
    1450                 :          0 :         PL_DEBUG(vk, "No VkInstance provided, creating one...");
    1451                 :            : 
    1452                 :            :         // Mirror the instance params here to set `get_proc_addr` correctly
    1453                 :            :         struct pl_vk_inst_params iparams;
    1454         [ #  # ]:          0 :         iparams = *PL_DEF(params->instance_params, &pl_vk_inst_default_params);
    1455                 :          0 :         iparams.get_proc_addr = params->get_proc_addr;
    1456                 :          0 :         vk->internal_instance = pl_vk_inst_create(log, &iparams);
    1457         [ #  # ]:          0 :         if (!vk->internal_instance)
    1458                 :          0 :             goto error;
    1459                 :          0 :         vk->inst = vk->internal_instance->instance;
    1460                 :            :     }
    1461                 :            : 
    1462                 :            :     // Directly load all mandatory instance-level function pointers, since
    1463                 :            :     // these will be required for all further device creation logic
    1464         [ +  + ]:         36 :     for (int i = 0; i < PL_ARRAY_SIZE(vk_inst_funs); i++)
    1465                 :         34 :         load_vk_fun(vk, &vk_inst_funs[i]);
    1466                 :            : 
    1467                 :            :     // Choose the physical device
    1468         [ +  - ]:          2 :     if (params->device) {
    1469                 :          2 :         PL_DEBUG(vk, "Using specified VkPhysicalDevice");
    1470                 :          2 :         vk->physd = params->device;
    1471                 :            :     } else {
    1472                 :          0 :         struct pl_vulkan_device_params dparams = {
    1473                 :          0 :             .instance       = vk->inst,
    1474                 :          0 :             .get_proc_addr  = params->get_proc_addr,
    1475                 :          0 :             .surface        = params->surface,
    1476                 :          0 :             .device_name    = params->device_name,
    1477                 :          0 :             .allow_software = params->allow_software,
    1478                 :            :         };
    1479                 :            :         memcpy(dparams.device_uuid, params->device_uuid, VK_UUID_SIZE);
    1480                 :            : 
    1481                 :          0 :         vk->physd = pl_vulkan_choose_device(log, &dparams);
    1482         [ #  # ]:          0 :         if (!vk->physd) {
    1483                 :          0 :             PL_FATAL(vk, "Found no suitable device, giving up.");
    1484                 :          0 :             goto error;
    1485                 :            :         }
    1486                 :            :     }
    1487                 :            : 
    1488                 :          2 :     VkPhysicalDeviceIDPropertiesKHR id_props = {
    1489                 :            :         .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES_KHR,
    1490                 :            :     };
    1491                 :            : 
    1492                 :          2 :     VkPhysicalDeviceProperties2KHR prop = {
    1493                 :            :         .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR,
    1494                 :            :         .pNext = &id_props,
    1495                 :            :     };
    1496                 :            : 
    1497                 :          2 :     vk->GetPhysicalDeviceProperties2(vk->physd, &prop);
    1498                 :          2 :     vk->props = prop.properties;
    1499                 :            : 
    1500                 :          2 :     PL_INFO(vk, "Vulkan device properties:");
    1501                 :          2 :     PL_INFO(vk, "    Device Name: %s", prop.properties.deviceName);
    1502                 :          2 :     PL_INFO(vk, "    Device ID: %"PRIx32":%"PRIx32, prop.properties.vendorID,
    1503                 :            :             prop.properties.deviceID);
    1504                 :          2 :     PL_INFO(vk, "    Device UUID: %s", PRINT_UUID(id_props.deviceUUID));
    1505                 :          2 :     PL_INFO(vk, "    Driver version: %"PRIx32, prop.properties.driverVersion);
    1506                 :          2 :     PL_INFO(vk, "    API version: %d.%d.%d", PRINTF_VER(prop.properties.apiVersion));
    1507                 :            : 
    1508                 :            :     // Needed by device_init
    1509                 :          2 :     vk->api_ver = prop.properties.apiVersion;
    1510         [ -  + ]:          2 :     if (params->max_api_version) {
    1511                 :          0 :         vk->api_ver = PL_MIN(vk->api_ver, params->max_api_version);
    1512                 :          0 :         PL_INFO(vk, "Restricting API version to %d.%d.%d... new version %d.%d.%d",
    1513                 :            :                 PRINTF_VER(params->max_api_version), PRINTF_VER(vk->api_ver));
    1514                 :            :     }
    1515                 :            : 
    1516         [ -  + ]:          2 :     if (vk->api_ver < PL_VK_MIN_VERSION) {
    1517                 :          0 :         PL_FATAL(vk, "Device API version %d.%d.%d is lower than the minimum "
    1518                 :            :                  "required version of %d.%d.%d, cannot proceed!",
    1519                 :            :                  PRINTF_VER(vk->api_ver), PRINTF_VER(PL_VK_MIN_VERSION));
    1520                 :          0 :         goto error;
    1521                 :            :     }
    1522                 :            : 
    1523                 :            :     // Finally, initialize the logical device and the rest of the vk_ctx
    1524         [ -  + ]:          2 :     if (!device_init(vk, params))
    1525                 :          0 :         goto error;
    1526                 :            : 
    1527         [ -  + ]:          2 :     if (!finalize_context(pl_vk, params->max_glsl_version, params->no_compute))
    1528                 :          0 :         goto error;
    1529                 :            : 
    1530                 :          2 :     return pl_vk;
    1531                 :            : 
    1532                 :          0 : error:
    1533                 :          0 :     PL_FATAL(vk, "Failed initializing vulkan device");
    1534                 :          0 :     pl_vulkan_destroy((pl_vulkan *) &pl_vk);
    1535                 :          0 :     return NULL;
    1536                 :            : }
    1537                 :            : 
    1538                 :          1 : pl_vulkan pl_vulkan_import(pl_log log, const struct pl_vulkan_import_params *params)
    1539                 :            : {
    1540                 :          1 :     void *tmp = pl_tmp(NULL);
    1541                 :            : 
    1542                 :          1 :     struct pl_vulkan_t *pl_vk = pl_zalloc_obj(NULL, pl_vk, struct vk_ctx);
    1543                 :          1 :     struct vk_ctx *vk = PL_PRIV(pl_vk);
    1544                 :          1 :     *vk = (struct vk_ctx) {
    1545                 :            :         .vulkan = pl_vk,
    1546                 :            :         .alloc = pl_vk,
    1547                 :            :         .log = log,
    1548                 :            :         .imported = true,
    1549                 :          1 :         .inst = params->instance,
    1550                 :          1 :         .physd = params->phys_device,
    1551                 :          1 :         .dev = params->device,
    1552                 :          1 :         .GetInstanceProcAddr = get_proc_addr_fallback(log, params->get_proc_addr),
    1553                 :          1 :         .lock_queue = params->lock_queue,
    1554                 :          1 :         .unlock_queue = params->unlock_queue,
    1555         [ +  - ]:          1 :         .queue_ctx = params->queue_ctx,
    1556                 :            :     };
    1557                 :            : 
    1558         [ -  + ]:          1 :     pl_mutex_init_type(&vk->lock, PL_MUTEX_RECURSIVE);
    1559         [ -  + ]:          1 :     if (!vk->GetInstanceProcAddr)
    1560                 :          0 :         goto error;
    1561                 :            : 
    1562         [ +  + ]:         18 :     for (int i = 0; i < PL_ARRAY_SIZE(vk_inst_funs); i++)
    1563                 :         17 :         load_vk_fun(vk, &vk_inst_funs[i]);
    1564                 :            : 
    1565                 :          1 :     VkPhysicalDeviceIDPropertiesKHR id_props = {
    1566                 :            :         .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES_KHR,
    1567                 :            :     };
    1568                 :            : 
    1569                 :          1 :     VkPhysicalDeviceProperties2KHR prop = {
    1570                 :            :         .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR,
    1571                 :            :         .pNext = &id_props,
    1572                 :            :     };
    1573                 :            : 
    1574         [ -  + ]:          1 :     pl_assert(vk->GetPhysicalDeviceProperties2);
    1575                 :          1 :     vk->GetPhysicalDeviceProperties2(vk->physd, &prop);
    1576                 :          1 :     vk->props = prop.properties;
    1577                 :            : 
    1578                 :          1 :     PL_INFO(vk, "Imported vulkan device properties:");
    1579                 :          1 :     PL_INFO(vk, "    Device Name: %s", prop.properties.deviceName);
    1580                 :          1 :     PL_INFO(vk, "    Device ID: %"PRIx32":%"PRIx32, prop.properties.vendorID,
    1581                 :            :             prop.properties.deviceID);
    1582                 :          1 :     PL_INFO(vk, "    Device UUID: %s", PRINT_UUID(id_props.deviceUUID));
    1583                 :          1 :     PL_INFO(vk, "    Driver version: %"PRIx32, prop.properties.driverVersion);
    1584                 :          1 :     PL_INFO(vk, "    API version: %d.%d.%d", PRINTF_VER(prop.properties.apiVersion));
    1585                 :            : 
    1586                 :          1 :     vk->api_ver = prop.properties.apiVersion;
    1587         [ -  + ]:          1 :     if (params->max_api_version) {
    1588                 :          0 :         vk->api_ver = PL_MIN(vk->api_ver, params->max_api_version);
    1589                 :          0 :         PL_INFO(vk, "Restricting API version to %d.%d.%d... new version %d.%d.%d",
    1590                 :            :                 PRINTF_VER(params->max_api_version), PRINTF_VER(vk->api_ver));
    1591                 :            :     }
    1592                 :            : 
    1593         [ -  + ]:          1 :     if (vk->api_ver < PL_VK_MIN_VERSION) {
    1594                 :          0 :         PL_FATAL(vk, "Device API version %d.%d.%d is lower than the minimum "
    1595                 :            :                  "required version of %d.%d.%d, cannot proceed!",
    1596                 :            :                  PRINTF_VER(vk->api_ver), PRINTF_VER(PL_VK_MIN_VERSION));
    1597                 :          0 :         goto error;
    1598                 :            :     }
    1599                 :            : 
    1600                 :          1 :     vk->features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
    1601                 :          1 :     vk_features_normalize(vk->alloc, params->features, 0, &vk->features);
    1602         [ -  + ]:          1 :     if (!check_required_features(vk)) {
    1603                 :          0 :         PL_FATAL(vk, "Imported Vulkan device was not created with all required "
    1604                 :            :                  "features!");
    1605                 :          0 :         goto error;
    1606                 :            :     }
    1607                 :            : 
    1608                 :            :     // Load all mandatory device-level functions
    1609         [ +  + ]:         88 :     for (int i = 0; i < PL_ARRAY_SIZE(vk_dev_funs); i++)
    1610                 :         87 :         load_vk_fun(vk, &vk_dev_funs[i]);
    1611                 :            : 
    1612                 :            :     // Load all of the optional functions from the extensions enabled
    1613         [ +  + ]:         12 :     for (int i = 0; i < PL_ARRAY_SIZE(vk_device_extensions); i++) {
    1614                 :            :         const struct vk_ext *ext = &vk_device_extensions[i];
    1615                 :         11 :         uint32_t core_ver = vk_ext_promoted_ver(ext->name);
    1616   [ +  +  +  + ]:         11 :         if (core_ver && vk->api_ver >= core_ver) {
    1617   [ +  -  +  + ]:          3 :             for (const struct vk_fun *f = ext->funs; f && f->name; f++)
    1618                 :          2 :                 load_vk_fun(vk, f);
    1619                 :          1 :             continue;
    1620                 :            :         }
    1621         [ +  + ]:         63 :         for (int n = 0; n < params->num_extensions; n++) {
    1622         [ +  + ]:         61 :             if (strcmp(ext->name, params->extensions[n]) == 0) {
    1623   [ +  +  +  + ]:         19 :                 for (const struct vk_fun *f = ext->funs; f && f->name; f++)
    1624                 :         11 :                     load_vk_fun(vk, f);
    1625                 :            :                 break;
    1626                 :            :             }
    1627                 :            :         }
    1628                 :            :     }
    1629                 :            : 
    1630                 :          1 :     uint32_t qfnum = 0;
    1631                 :          1 :     vk->GetPhysicalDeviceQueueFamilyProperties(vk->physd, &qfnum, NULL);
    1632                 :          1 :     VkQueueFamilyProperties *qfs = pl_calloc_ptr(tmp, qfnum, qfs);
    1633                 :          1 :     vk->GetPhysicalDeviceQueueFamilyProperties(vk->physd, &qfnum, qfs);
    1634         [ +  - ]:          1 :     if (!params->lock_queue)
    1635                 :          1 :         init_queue_locks(vk, qfnum, qfs);
    1636                 :            : 
    1637                 :            :     // Create the command pools for each unique qf that exists
    1638                 :            :     struct {
    1639                 :            :         const struct pl_vulkan_queue *info;
    1640                 :            :         struct vk_cmdpool **pool;
    1641                 :            :         VkQueueFlagBits flags; // *any* of these flags provide the cap
    1642                 :          1 :     } qinfos[] = {
    1643                 :            :         {
    1644                 :          1 :             .info = &params->queue_graphics,
    1645                 :          1 :             .pool = &vk->pool_graphics,
    1646                 :            :             .flags = VK_QUEUE_GRAPHICS_BIT,
    1647                 :            :         }, {
    1648                 :          1 :             .info = &params->queue_compute,
    1649                 :          1 :             .pool = &vk->pool_compute,
    1650                 :            :             .flags = VK_QUEUE_COMPUTE_BIT,
    1651                 :            :         }, {
    1652                 :          1 :             .info = &params->queue_transfer,
    1653                 :          1 :             .pool = &vk->pool_transfer,
    1654                 :            :             .flags = VK_QUEUE_TRANSFER_BIT |
    1655                 :            :                      VK_QUEUE_GRAPHICS_BIT |
    1656                 :            :                      VK_QUEUE_COMPUTE_BIT,
    1657                 :            :         }
    1658                 :            :     };
    1659                 :            : 
    1660         [ +  + ]:          4 :     for (int i = 0; i < PL_ARRAY_SIZE(qinfos); i++) {
    1661                 :          3 :         int qf = qinfos[i].info->index;
    1662                 :          3 :         struct vk_cmdpool **pool = qinfos[i].pool;
    1663         [ -  + ]:          3 :         if (!qinfos[i].info->count)
    1664                 :          0 :             continue;
    1665                 :            : 
    1666                 :            :         // API sanity check
    1667         [ -  + ]:          3 :         pl_assert(qfs[qf].queueFlags & qinfos[i].flags);
    1668                 :            : 
    1669                 :            :         // See if we already created a pool for this queue family
    1670         [ +  + ]:          3 :         for (int j = 0; j < i; j++) {
    1671   [ +  -  +  - ]:          2 :             if (qinfos[j].info->count && qinfos[j].info->index == qf) {
    1672                 :          2 :                 *pool = *qinfos[j].pool;
    1673                 :          2 :                 goto next_qf;
    1674                 :            :             }
    1675                 :            :         }
    1676                 :            : 
    1677                 :          1 :         *pool = vk_cmdpool_create(vk, qf, qinfos[i].info->count, qfs[qf]);
    1678         [ -  + ]:          1 :         if (!*pool)
    1679                 :          0 :             goto error;
    1680   [ +  -  -  -  :          1 :         PL_ARRAY_APPEND(vk->alloc, vk->pools, *pool);
                   -  - ]
    1681                 :            : 
    1682                 :            :         // Pre-emptively set "lower priority" pools as well
    1683         [ +  + ]:          3 :         for (int j = i+1; j < PL_ARRAY_SIZE(qinfos); j++) {
    1684         [ +  - ]:          2 :             if (qfs[qf].queueFlags & qinfos[j].flags)
    1685                 :          2 :                 *qinfos[j].pool = *pool;
    1686                 :            :         }
    1687                 :            : 
    1688                 :          3 : next_qf: ;
    1689                 :            :     }
    1690                 :            : 
    1691         [ -  + ]:          1 :     if (!vk->pool_graphics) {
    1692                 :          0 :         PL_ERR(vk, "No valid queues provided?");
    1693                 :          0 :         goto error;
    1694                 :            :     }
    1695                 :            : 
    1696         [ -  + ]:          1 :     if (!finalize_context(pl_vk, params->max_glsl_version, params->no_compute))
    1697                 :          0 :         goto error;
    1698                 :            : 
    1699                 :          1 :     pl_free(tmp);
    1700                 :          1 :     return pl_vk;
    1701                 :            : 
    1702                 :          0 : error:
    1703                 :          0 :     PL_FATAL(vk, "Failed importing vulkan device");
    1704                 :          0 :     pl_vulkan_destroy((pl_vulkan *) &pl_vk);
    1705                 :          0 :     pl_free(tmp);
    1706                 :          0 :     return NULL;
    1707                 :            : }

Generated by: LCOV version 1.16