Home | History | Annotate | Download | only in vk
      1 /*
      2  * Copyright 2017 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #include "VkTestUtils.h"
      9 
     10 #ifdef SK_VULKAN
     11 
     12 #include "SkAutoMalloc.h"
     13 #include "vk/GrVkBackendContext.h"
     14 #include "vk/GrVkExtensions.h"
     15 #include "../ports/SkOSLibrary.h"
     16 
     17 #if defined(SK_ENABLE_SCOPED_LSAN_SUPPRESSIONS)
     18 #include <sanitizer/lsan_interface.h>
     19 #endif
     20 
     21 namespace sk_gpu_test {
     22 
     23 bool LoadVkLibraryAndGetProcAddrFuncs(PFN_vkGetInstanceProcAddr* instProc,
     24                                       PFN_vkGetDeviceProcAddr* devProc) {
     25 #ifdef SK_MOLTENVK
     26     // MoltenVK is a statically linked framework, so there is no Vulkan library to load.
     27     *instProc = &vkGetInstanceProcAddr;
     28     *devProc = &vkGetDeviceProcAddr;
     29     return true;
     30 #else
     31     static void* vkLib = nullptr;
     32     static PFN_vkGetInstanceProcAddr localInstProc = nullptr;
     33     static PFN_vkGetDeviceProcAddr localDevProc = nullptr;
     34     if (!vkLib) {
     35 #if defined _WIN32
     36         vkLib = DynamicLoadLibrary("vulkan-1.dll");
     37 #else
     38         vkLib = DynamicLoadLibrary("libvulkan.so");
     39 #endif
     40         if (!vkLib) {
     41             return false;
     42         }
     43         localInstProc = (PFN_vkGetInstanceProcAddr) GetProcedureAddress(vkLib,
     44                                                                         "vkGetInstanceProcAddr");
     45         localDevProc = (PFN_vkGetDeviceProcAddr) GetProcedureAddress(vkLib,
     46                                                                      "vkGetDeviceProcAddr");
     47     }
     48     if (!localInstProc || !localDevProc) {
     49         return false;
     50     }
     51     *instProc = localInstProc;
     52     *devProc = localDevProc;
     53     return true;
     54 #endif
     55 }
     56 
     57 ////////////////////////////////////////////////////////////////////////////////
     58 // Helper code to set up Vulkan context objects
     59 
     60 #ifdef SK_ENABLE_VK_LAYERS
     61 const char* kDebugLayerNames[] = {
     62     // elements of VK_LAYER_LUNARG_standard_validation
     63     "VK_LAYER_GOOGLE_threading",
     64     "VK_LAYER_LUNARG_parameter_validation",
     65     "VK_LAYER_LUNARG_object_tracker",
     66     "VK_LAYER_LUNARG_core_validation",
     67     "VK_LAYER_GOOGLE_unique_objects",
     68     // not included in standard_validation
     69     //"VK_LAYER_LUNARG_api_dump",
     70     //"VK_LAYER_LUNARG_vktrace",
     71     //"VK_LAYER_LUNARG_screenshot",
     72 };
     73 
     74 static uint32_t remove_patch_version(uint32_t specVersion) {
     75     return (specVersion >> 12) << 12;
     76 }
     77 
     78 // Returns the index into layers array for the layer we want. Returns -1 if not supported.
     79 static int should_include_debug_layer(const char* layerName,
     80                                        uint32_t layerCount, VkLayerProperties* layers,
     81                                        uint32_t version) {
     82     for (uint32_t i = 0; i < layerCount; ++i) {
     83         if (!strcmp(layerName, layers[i].layerName)) {
     84             // Since the layers intercept the vulkan calls and forward them on, we need to make sure
     85             // layer was written against a version that isn't older than the version of Vulkan we're
     86             // using so that it has all the api entry points.
     87             if (version <= remove_patch_version(layers[i].specVersion)) {
     88                 return i;
     89             }
     90             return -1;
     91         }
     92 
     93     }
     94     return -1;
     95 }
     96 
     97 VKAPI_ATTR VkBool32 VKAPI_CALL DebugReportCallback(
     98     VkDebugReportFlagsEXT       flags,
     99     VkDebugReportObjectTypeEXT  objectType,
    100     uint64_t                    object,
    101     size_t                      location,
    102     int32_t                     messageCode,
    103     const char*                 pLayerPrefix,
    104     const char*                 pMessage,
    105     void*                       pUserData) {
    106     if (flags & VK_DEBUG_REPORT_ERROR_BIT_EXT) {
    107         SkDebugf("Vulkan error [%s]: code: %d: %s\n", pLayerPrefix, messageCode, pMessage);
    108         return VK_TRUE; // skip further layers
    109     } else if (flags & VK_DEBUG_REPORT_WARNING_BIT_EXT) {
    110         // There is currently a bug in the spec which doesn't have
    111         // VK_STRUCTURE_TYPE_BLEND_OPERATION_ADVANCED_FEATURES_EXT as an allowable pNext struct in
    112         // VkDeviceCreateInfo. So we ignore that warning since it is wrong.
    113         if (!strstr(pMessage,
    114                     "pCreateInfo->pNext chain includes a structure with unexpected VkStructureType "
    115                     "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_FEATURES_EXT")) {
    116             SkDebugf("Vulkan warning [%s]: code: %d: %s\n", pLayerPrefix, messageCode, pMessage);
    117         }
    118     } else if (flags & VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT) {
    119         SkDebugf("Vulkan perf warning [%s]: code: %d: %s\n", pLayerPrefix, messageCode, pMessage);
    120     } else {
    121         SkDebugf("Vulkan info/debug [%s]: code: %d: %s\n", pLayerPrefix, messageCode, pMessage);
    122     }
    123     return VK_FALSE;
    124 }
    125 #endif
    126 
    127 #define GET_PROC_LOCAL(F, inst, device) PFN_vk ## F F = (PFN_vk ## F) getProc("vk" #F, inst, device)
    128 
    129 static bool init_instance_extensions_and_layers(GrVkGetProc getProc,
    130                                                 uint32_t specVersion,
    131                                                 SkTArray<VkExtensionProperties>* instanceExtensions,
    132                                                 SkTArray<VkLayerProperties>* instanceLayers) {
    133     if (getProc == nullptr) {
    134         return false;
    135     }
    136 
    137     GET_PROC_LOCAL(EnumerateInstanceExtensionProperties, VK_NULL_HANDLE, VK_NULL_HANDLE);
    138     GET_PROC_LOCAL(EnumerateInstanceLayerProperties, VK_NULL_HANDLE, VK_NULL_HANDLE);
    139 
    140     if (!EnumerateInstanceExtensionProperties ||
    141         !EnumerateInstanceLayerProperties) {
    142         return false;
    143     }
    144 
    145     VkResult res;
    146     uint32_t layerCount = 0;
    147 #ifdef SK_ENABLE_VK_LAYERS
    148     // instance layers
    149     res = EnumerateInstanceLayerProperties(&layerCount, nullptr);
    150     if (VK_SUCCESS != res) {
    151         return false;
    152     }
    153     VkLayerProperties* layers = new VkLayerProperties[layerCount];
    154     res = EnumerateInstanceLayerProperties(&layerCount, layers);
    155     if (VK_SUCCESS != res) {
    156         delete[] layers;
    157         return false;
    158     }
    159 
    160     uint32_t nonPatchVersion = remove_patch_version(specVersion);
    161     for (size_t i = 0; i < SK_ARRAY_COUNT(kDebugLayerNames); ++i) {
    162         int idx = should_include_debug_layer(kDebugLayerNames[i], layerCount, layers,
    163                                              nonPatchVersion);
    164         if (idx != -1) {
    165             instanceLayers->push_back() = layers[idx];
    166         }
    167     }
    168     delete[] layers;
    169 #endif
    170 
    171     // instance extensions
    172     // via Vulkan implementation and implicitly enabled layers
    173     uint32_t extensionCount = 0;
    174     res = EnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr);
    175     if (VK_SUCCESS != res) {
    176         return false;
    177     }
    178     VkExtensionProperties* extensions = new VkExtensionProperties[extensionCount];
    179     res = EnumerateInstanceExtensionProperties(nullptr, &extensionCount, extensions);
    180     if (VK_SUCCESS != res) {
    181         delete[] extensions;
    182         return false;
    183     }
    184     for (uint32_t i = 0; i < extensionCount; ++i) {
    185         instanceExtensions->push_back() = extensions[i];
    186     }
    187     delete [] extensions;
    188 
    189     // via explicitly enabled layers
    190     layerCount = instanceLayers->count();
    191     for (uint32_t layerIndex = 0; layerIndex < layerCount; ++layerIndex) {
    192         uint32_t extensionCount = 0;
    193         res = EnumerateInstanceExtensionProperties((*instanceLayers)[layerIndex].layerName,
    194                                                    &extensionCount, nullptr);
    195         if (VK_SUCCESS != res) {
    196             return false;
    197         }
    198         VkExtensionProperties* extensions = new VkExtensionProperties[extensionCount];
    199         res = EnumerateInstanceExtensionProperties((*instanceLayers)[layerIndex].layerName,
    200                                                    &extensionCount, extensions);
    201         if (VK_SUCCESS != res) {
    202             delete[] extensions;
    203             return false;
    204         }
    205         for (uint32_t i = 0; i < extensionCount; ++i) {
    206             instanceExtensions->push_back() = extensions[i];
    207         }
    208         delete[] extensions;
    209     }
    210 
    211     return true;
    212 }
    213 
    214 static bool init_device_extensions_and_layers(GrVkGetProc getProc, uint32_t specVersion,
    215                                               VkInstance inst, VkPhysicalDevice physDev,
    216                                               SkTArray<VkExtensionProperties>* deviceExtensions,
    217                                               SkTArray<VkLayerProperties>* deviceLayers) {
    218     if (getProc == nullptr) {
    219         return false;
    220     }
    221 
    222     GET_PROC_LOCAL(EnumerateDeviceExtensionProperties, inst, VK_NULL_HANDLE);
    223     GET_PROC_LOCAL(EnumerateDeviceLayerProperties, inst, VK_NULL_HANDLE);
    224 
    225     if (!EnumerateDeviceExtensionProperties ||
    226         !EnumerateDeviceLayerProperties) {
    227         return false;
    228     }
    229 
    230     VkResult res;
    231     // device layers
    232     uint32_t layerCount = 0;
    233 #ifdef SK_ENABLE_VK_LAYERS
    234     res = EnumerateDeviceLayerProperties(physDev, &layerCount, nullptr);
    235     if (VK_SUCCESS != res) {
    236         return false;
    237     }
    238     VkLayerProperties* layers = new VkLayerProperties[layerCount];
    239     res = EnumerateDeviceLayerProperties(physDev, &layerCount, layers);
    240     if (VK_SUCCESS != res) {
    241         delete[] layers;
    242         return false;
    243     }
    244 
    245     uint32_t nonPatchVersion = remove_patch_version(specVersion);
    246     for (size_t i = 0; i < SK_ARRAY_COUNT(kDebugLayerNames); ++i) {
    247         int idx = should_include_debug_layer(kDebugLayerNames[i], layerCount, layers,
    248                                              nonPatchVersion);
    249         if (idx != -1) {
    250             deviceLayers->push_back() = layers[idx];
    251         }
    252     }
    253     delete[] layers;
    254 #endif
    255 
    256     // device extensions
    257     // via Vulkan implementation and implicitly enabled layers
    258     uint32_t extensionCount = 0;
    259     res = EnumerateDeviceExtensionProperties(physDev, nullptr, &extensionCount, nullptr);
    260     if (VK_SUCCESS != res) {
    261         return false;
    262     }
    263     VkExtensionProperties* extensions = new VkExtensionProperties[extensionCount];
    264     res = EnumerateDeviceExtensionProperties(physDev, nullptr, &extensionCount, extensions);
    265     if (VK_SUCCESS != res) {
    266         delete[] extensions;
    267         return false;
    268     }
    269     for (uint32_t i = 0; i < extensionCount; ++i) {
    270         deviceExtensions->push_back() = extensions[i];
    271     }
    272     delete[] extensions;
    273 
    274     // via explicitly enabled layers
    275     layerCount = deviceLayers->count();
    276     for (uint32_t layerIndex = 0; layerIndex < layerCount; ++layerIndex) {
    277         uint32_t extensionCount = 0;
    278         res = EnumerateDeviceExtensionProperties(physDev,
    279             (*deviceLayers)[layerIndex].layerName,
    280             &extensionCount, nullptr);
    281         if (VK_SUCCESS != res) {
    282             return false;
    283         }
    284         VkExtensionProperties* extensions = new VkExtensionProperties[extensionCount];
    285         res = EnumerateDeviceExtensionProperties(physDev,
    286             (*deviceLayers)[layerIndex].layerName,
    287             &extensionCount, extensions);
    288         if (VK_SUCCESS != res) {
    289             delete[] extensions;
    290             return false;
    291         }
    292         for (uint32_t i = 0; i < extensionCount; ++i) {
    293             deviceExtensions->push_back() = extensions[i];
    294         }
    295         delete[] extensions;
    296     }
    297 
    298     return true;
    299 }
    300 
    301 #define ACQUIRE_VK_PROC_NOCHECK(name, instance, device) \
    302     PFN_vk##name grVk##name = reinterpret_cast<PFN_vk##name>(getProc("vk" #name, instance, device))
    303 
    304 #define ACQUIRE_VK_PROC(name, instance, device)                                    \
    305     PFN_vk##name grVk##name =                                                      \
    306             reinterpret_cast<PFN_vk##name>(getProc("vk" #name, instance, device)); \
    307     do {                                                                           \
    308         if (grVk##name == nullptr) {                                               \
    309             SkDebugf("Function ptr for vk%s could not be acquired\n", #name);      \
    310             if (device != VK_NULL_HANDLE) {                                        \
    311                 destroy_instance(getProc, inst, debugCallback, hasDebugExtension); \
    312             }                                                                      \
    313             return false;                                                          \
    314         }                                                                          \
    315     } while (0)
    316 
    317 #define ACQUIRE_VK_PROC_LOCAL(name, instance, device)                              \
    318     PFN_vk##name grVk##name =                                                      \
    319             reinterpret_cast<PFN_vk##name>(getProc("vk" #name, instance, device)); \
    320     do {                                                                           \
    321         if (grVk##name == nullptr) {                                               \
    322             SkDebugf("Function ptr for vk%s could not be acquired\n", #name);      \
    323             return;                                                                \
    324         }                                                                          \
    325     } while (0)
    326 
    327 static void destroy_instance(GrVkGetProc getProc, VkInstance inst,
    328                              VkDebugReportCallbackEXT* debugCallback,
    329                              bool hasDebugExtension) {
    330     if (hasDebugExtension && *debugCallback != VK_NULL_HANDLE) {
    331         ACQUIRE_VK_PROC_LOCAL(DestroyDebugReportCallbackEXT, inst, VK_NULL_HANDLE);
    332         grVkDestroyDebugReportCallbackEXT(inst, *debugCallback, nullptr);
    333         *debugCallback = VK_NULL_HANDLE;
    334     }
    335     ACQUIRE_VK_PROC_LOCAL(DestroyInstance, inst, VK_NULL_HANDLE);
    336     grVkDestroyInstance(inst, nullptr);
    337 }
    338 
    339 static void setup_extension_features(GrVkGetProc getProc, VkInstance inst, VkPhysicalDevice physDev,
    340                                      uint32_t physDeviceVersion, GrVkExtensions* extensions,
    341                                      VkPhysicalDeviceFeatures2* features) {
    342     SkASSERT(physDeviceVersion >= VK_MAKE_VERSION(1, 1, 0) ||
    343              extensions->hasExtension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, 1));
    344 
    345     // Setup all extension feature structs we may want to use.
    346 
    347     void** tailPNext = &features->pNext;
    348 
    349     VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT* blend = nullptr;
    350     if (extensions->hasExtension(VK_EXT_BLEND_OPERATION_ADVANCED_EXTENSION_NAME, 2)) {
    351         blend = (VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT*) sk_malloc_throw(
    352                 sizeof(VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT));
    353         blend->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_FEATURES_EXT;
    354         blend->pNext = nullptr;
    355         *tailPNext = blend;
    356         tailPNext = &blend->pNext;
    357     }
    358 
    359     VkPhysicalDeviceSamplerYcbcrConversionFeatures* ycbcrFeature = nullptr;
    360     if (physDeviceVersion >= VK_MAKE_VERSION(1, 1, 0) ||
    361         extensions->hasExtension(VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME, 1)) {
    362         ycbcrFeature = (VkPhysicalDeviceSamplerYcbcrConversionFeatures*) sk_malloc_throw(
    363                 sizeof(VkPhysicalDeviceSamplerYcbcrConversionFeatures));
    364         ycbcrFeature->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES;
    365         ycbcrFeature->pNext = nullptr;
    366         *tailPNext = ycbcrFeature;
    367         tailPNext = &ycbcrFeature->pNext;
    368     }
    369 
    370     if (physDeviceVersion >= VK_MAKE_VERSION(1, 1, 0)) {
    371         ACQUIRE_VK_PROC_LOCAL(GetPhysicalDeviceFeatures2, inst, VK_NULL_HANDLE);
    372         grVkGetPhysicalDeviceFeatures2(physDev, features);
    373     } else {
    374         SkASSERT(extensions->hasExtension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME,
    375                                           1));
    376         ACQUIRE_VK_PROC_LOCAL(GetPhysicalDeviceFeatures2KHR, inst, VK_NULL_HANDLE);
    377         grVkGetPhysicalDeviceFeatures2KHR(physDev, features);
    378     }
    379 
    380     // If we want to disable any extension features do so here.
    381 }
    382 
    383 bool CreateVkBackendContext(GrVkGetProc getProc,
    384                             GrVkBackendContext* ctx,
    385                             GrVkExtensions* extensions,
    386                             VkPhysicalDeviceFeatures2* features,
    387                             VkDebugReportCallbackEXT* debugCallback,
    388                             uint32_t* presentQueueIndexPtr,
    389                             CanPresentFn canPresent) {
    390     VkResult err;
    391 
    392     ACQUIRE_VK_PROC_NOCHECK(EnumerateInstanceVersion, VK_NULL_HANDLE, VK_NULL_HANDLE);
    393     uint32_t instanceVersion = 0;
    394     if (!grVkEnumerateInstanceVersion) {
    395         instanceVersion = VK_MAKE_VERSION(1, 0, 0);
    396     } else {
    397         err = grVkEnumerateInstanceVersion(&instanceVersion);
    398         if (err) {
    399             SkDebugf("failed ot enumerate instance version. Err: %d\n", err);
    400             return false;
    401         }
    402     }
    403     SkASSERT(instanceVersion >= VK_MAKE_VERSION(1, 0, 0));
    404     uint32_t apiVersion = VK_MAKE_VERSION(1, 0, 0);
    405     if (instanceVersion >= VK_MAKE_VERSION(1, 1, 0)) {
    406         // If the instance version is 1.0 we must have the apiVersion also be 1.0. However, if the
    407         // instance version is 1.1 or higher, we can set the apiVersion to be whatever the highest
    408         // api we may use in skia (technically it can be arbitrary). So for now we set it to 1.1
    409         // since that is the highest vulkan version.
    410         apiVersion = VK_MAKE_VERSION(1, 1, 0);
    411     }
    412 
    413     instanceVersion = SkTMin(instanceVersion, apiVersion);
    414 
    415     VkPhysicalDevice physDev;
    416     VkDevice device;
    417     VkInstance inst;
    418 
    419     const VkApplicationInfo app_info = {
    420         VK_STRUCTURE_TYPE_APPLICATION_INFO, // sType
    421         nullptr,                            // pNext
    422         "vktest",                           // pApplicationName
    423         0,                                  // applicationVersion
    424         "vktest",                           // pEngineName
    425         0,                                  // engineVerison
    426         apiVersion,                         // apiVersion
    427     };
    428 
    429     SkTArray<VkLayerProperties> instanceLayers;
    430     SkTArray<VkExtensionProperties> instanceExtensions;
    431 
    432     if (!init_instance_extensions_and_layers(getProc, instanceVersion,
    433                                              &instanceExtensions,
    434                                              &instanceLayers)) {
    435         return false;
    436     }
    437 
    438     SkTArray<const char*> instanceLayerNames;
    439     SkTArray<const char*> instanceExtensionNames;
    440     for (int i = 0; i < instanceLayers.count(); ++i) {
    441         instanceLayerNames.push_back(instanceLayers[i].layerName);
    442     }
    443     for (int i = 0; i < instanceExtensions.count(); ++i) {
    444         if (strncmp(instanceExtensions[i].extensionName, "VK_KHX", 6)) {
    445             instanceExtensionNames.push_back(instanceExtensions[i].extensionName);
    446         }
    447     }
    448 
    449     const VkInstanceCreateInfo instance_create = {
    450         VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,    // sType
    451         nullptr,                                   // pNext
    452         0,                                         // flags
    453         &app_info,                                 // pApplicationInfo
    454         (uint32_t) instanceLayerNames.count(),     // enabledLayerNameCount
    455         instanceLayerNames.begin(),                // ppEnabledLayerNames
    456         (uint32_t) instanceExtensionNames.count(), // enabledExtensionNameCount
    457         instanceExtensionNames.begin(),            // ppEnabledExtensionNames
    458     };
    459 
    460     bool hasDebugExtension = false;
    461 
    462     ACQUIRE_VK_PROC(CreateInstance, VK_NULL_HANDLE, VK_NULL_HANDLE);
    463     err = grVkCreateInstance(&instance_create, nullptr, &inst);
    464     if (err < 0) {
    465         SkDebugf("vkCreateInstance failed: %d\n", err);
    466         return false;
    467     }
    468 
    469 #ifdef SK_ENABLE_VK_LAYERS
    470     *debugCallback = VK_NULL_HANDLE;
    471     for (int i = 0; i < instanceExtensionNames.count() && !hasDebugExtension; ++i) {
    472         if (!strcmp(instanceExtensionNames[i], VK_EXT_DEBUG_REPORT_EXTENSION_NAME)) {
    473             hasDebugExtension = true;
    474         }
    475     }
    476     if (hasDebugExtension) {
    477         // Setup callback creation information
    478         VkDebugReportCallbackCreateInfoEXT callbackCreateInfo;
    479         callbackCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT;
    480         callbackCreateInfo.pNext = nullptr;
    481         callbackCreateInfo.flags = VK_DEBUG_REPORT_ERROR_BIT_EXT |
    482                                    VK_DEBUG_REPORT_WARNING_BIT_EXT |
    483                                    // VK_DEBUG_REPORT_INFORMATION_BIT_EXT |
    484                                    // VK_DEBUG_REPORT_DEBUG_BIT_EXT |
    485                                    VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT;
    486         callbackCreateInfo.pfnCallback = &DebugReportCallback;
    487         callbackCreateInfo.pUserData = nullptr;
    488 
    489         ACQUIRE_VK_PROC(CreateDebugReportCallbackEXT, inst, VK_NULL_HANDLE);
    490         // Register the callback
    491         grVkCreateDebugReportCallbackEXT(inst, &callbackCreateInfo, nullptr, debugCallback);
    492     }
    493 #endif
    494 
    495     ACQUIRE_VK_PROC(EnumeratePhysicalDevices, inst, VK_NULL_HANDLE);
    496     ACQUIRE_VK_PROC(GetPhysicalDeviceProperties, inst, VK_NULL_HANDLE);
    497     ACQUIRE_VK_PROC(GetPhysicalDeviceQueueFamilyProperties, inst, VK_NULL_HANDLE);
    498     ACQUIRE_VK_PROC(GetPhysicalDeviceFeatures, inst, VK_NULL_HANDLE);
    499     ACQUIRE_VK_PROC(CreateDevice, inst, VK_NULL_HANDLE);
    500     ACQUIRE_VK_PROC(GetDeviceQueue, inst, VK_NULL_HANDLE);
    501     ACQUIRE_VK_PROC(DeviceWaitIdle, inst, VK_NULL_HANDLE);
    502     ACQUIRE_VK_PROC(DestroyDevice, inst, VK_NULL_HANDLE);
    503 
    504     uint32_t gpuCount;
    505     err = grVkEnumeratePhysicalDevices(inst, &gpuCount, nullptr);
    506     if (err) {
    507         SkDebugf("vkEnumeratePhysicalDevices failed: %d\n", err);
    508         destroy_instance(getProc, inst, debugCallback, hasDebugExtension);
    509         return false;
    510     }
    511     if (!gpuCount) {
    512         SkDebugf("vkEnumeratePhysicalDevices returned no supported devices.\n");
    513         destroy_instance(getProc, inst, debugCallback, hasDebugExtension);
    514         return false;
    515     }
    516     // Just returning the first physical device instead of getting the whole array.
    517     // TODO: find best match for our needs
    518     gpuCount = 1;
    519     err = grVkEnumeratePhysicalDevices(inst, &gpuCount, &physDev);
    520     // VK_INCOMPLETE is returned when the count we provide is less than the total device count.
    521     if (err && VK_INCOMPLETE != err) {
    522         SkDebugf("vkEnumeratePhysicalDevices failed: %d\n", err);
    523         destroy_instance(getProc, inst, debugCallback, hasDebugExtension);
    524         return false;
    525     }
    526 
    527     VkPhysicalDeviceProperties physDeviceProperties;
    528     grVkGetPhysicalDeviceProperties(physDev, &physDeviceProperties);
    529     int physDeviceVersion = SkTMin(physDeviceProperties.apiVersion, apiVersion);
    530 
    531     // query to get the initial queue props size
    532     uint32_t queueCount;
    533     grVkGetPhysicalDeviceQueueFamilyProperties(physDev, &queueCount, nullptr);
    534     if (!queueCount) {
    535         SkDebugf("vkGetPhysicalDeviceQueueFamilyProperties returned no queues.\n");
    536         destroy_instance(getProc, inst, debugCallback, hasDebugExtension);
    537         return false;
    538     }
    539 
    540     SkAutoMalloc queuePropsAlloc(queueCount * sizeof(VkQueueFamilyProperties));
    541     // now get the actual queue props
    542     VkQueueFamilyProperties* queueProps = (VkQueueFamilyProperties*)queuePropsAlloc.get();
    543 
    544     grVkGetPhysicalDeviceQueueFamilyProperties(physDev, &queueCount, queueProps);
    545 
    546     // iterate to find the graphics queue
    547     uint32_t graphicsQueueIndex = queueCount;
    548     for (uint32_t i = 0; i < queueCount; i++) {
    549         if (queueProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
    550             graphicsQueueIndex = i;
    551             break;
    552         }
    553     }
    554     if (graphicsQueueIndex == queueCount) {
    555         SkDebugf("Could not find any supported graphics queues.\n");
    556         destroy_instance(getProc, inst, debugCallback, hasDebugExtension);
    557         return false;
    558     }
    559 
    560     // iterate to find the present queue, if needed
    561     uint32_t presentQueueIndex = queueCount;
    562     if (presentQueueIndexPtr && canPresent) {
    563         for (uint32_t i = 0; i < queueCount; i++) {
    564             if (canPresent(inst, physDev, i)) {
    565                 presentQueueIndex = i;
    566                 break;
    567             }
    568         }
    569         if (presentQueueIndex == queueCount) {
    570             SkDebugf("Could not find any supported present queues.\n");
    571             destroy_instance(getProc, inst, debugCallback, hasDebugExtension);
    572             return false;
    573         }
    574         *presentQueueIndexPtr = presentQueueIndex;
    575     } else {
    576         // Just setting this so we end up make a single queue for graphics since there was no
    577         // request for a present queue.
    578         presentQueueIndex = graphicsQueueIndex;
    579     }
    580 
    581     SkTArray<VkLayerProperties> deviceLayers;
    582     SkTArray<VkExtensionProperties> deviceExtensions;
    583     if (!init_device_extensions_and_layers(getProc, physDeviceVersion,
    584                                            inst, physDev,
    585                                            &deviceExtensions,
    586                                            &deviceLayers)) {
    587         destroy_instance(getProc, inst, debugCallback, hasDebugExtension);
    588         return false;
    589     }
    590 
    591     SkTArray<const char*> deviceLayerNames;
    592     SkTArray<const char*> deviceExtensionNames;
    593     for (int i = 0; i < deviceLayers.count(); ++i) {
    594         deviceLayerNames.push_back(deviceLayers[i].layerName);
    595     }
    596     for (int i = 0; i < deviceExtensions.count(); ++i) {
    597         // Don't use experimental extensions since they typically don't work with debug layers and
    598         // often are missing dependecy requirements for other extensions. Additionally, these are
    599         // often left behind in the driver even after they've been promoted to real extensions.
    600         if (strncmp(deviceExtensions[i].extensionName, "VK_KHX", 6) &&
    601             strncmp(deviceExtensions[i].extensionName, "VK_NVX", 6)) {
    602             deviceExtensionNames.push_back(deviceExtensions[i].extensionName);
    603         }
    604     }
    605 
    606     extensions->init(getProc, inst, physDev,
    607                      (uint32_t) instanceExtensionNames.count(),
    608                      instanceExtensionNames.begin(),
    609                      (uint32_t) deviceExtensionNames.count(),
    610                      deviceExtensionNames.begin());
    611 
    612     memset(features, 0, sizeof(VkPhysicalDeviceFeatures2));
    613     features->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
    614     features->pNext = nullptr;
    615 
    616     VkPhysicalDeviceFeatures* deviceFeatures = &features->features;
    617     void* pointerToFeatures = nullptr;
    618     if (physDeviceVersion >= VK_MAKE_VERSION(1, 1, 0) ||
    619         extensions->hasExtension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, 1)) {
    620         setup_extension_features(getProc, inst, physDev, physDeviceVersion, extensions, features);
    621         // If we set the pNext of the VkDeviceCreateInfo to our VkPhysicalDeviceFeatures2 struct,
    622         // the device creation will use that instead of the ppEnabledFeatures.
    623         pointerToFeatures = features;
    624     } else {
    625         grVkGetPhysicalDeviceFeatures(physDev, deviceFeatures);
    626     }
    627 
    628     // this looks like it would slow things down,
    629     // and we can't depend on it on all platforms
    630     deviceFeatures->robustBufferAccess = VK_FALSE;
    631 
    632     float queuePriorities[1] = { 0.0 };
    633     // Here we assume no need for swapchain queue
    634     // If one is needed, the client will need its own setup code
    635     const VkDeviceQueueCreateInfo queueInfo[2] = {
    636         {
    637             VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, // sType
    638             nullptr,                                    // pNext
    639             0,                                          // VkDeviceQueueCreateFlags
    640             graphicsQueueIndex,                         // queueFamilyIndex
    641             1,                                          // queueCount
    642             queuePriorities,                            // pQueuePriorities
    643         },
    644         {
    645             VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, // sType
    646             nullptr,                                    // pNext
    647             0,                                          // VkDeviceQueueCreateFlags
    648             presentQueueIndex,                          // queueFamilyIndex
    649             1,                                          // queueCount
    650             queuePriorities,                            // pQueuePriorities
    651         }
    652     };
    653     uint32_t queueInfoCount = (presentQueueIndex != graphicsQueueIndex) ? 2 : 1;
    654 
    655     const VkDeviceCreateInfo deviceInfo = {
    656         VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,        // sType
    657         pointerToFeatures,                           // pNext
    658         0,                                           // VkDeviceCreateFlags
    659         queueInfoCount,                              // queueCreateInfoCount
    660         queueInfo,                                   // pQueueCreateInfos
    661         (uint32_t) deviceLayerNames.count(),         // layerCount
    662         deviceLayerNames.begin(),                    // ppEnabledLayerNames
    663         (uint32_t) deviceExtensionNames.count(),     // extensionCount
    664         deviceExtensionNames.begin(),                // ppEnabledExtensionNames
    665         pointerToFeatures ? nullptr : deviceFeatures // ppEnabledFeatures
    666     };
    667 
    668     {
    669 #if defined(SK_ENABLE_SCOPED_LSAN_SUPPRESSIONS)
    670         // skia:8712
    671         __lsan::ScopedDisabler lsanDisabler;
    672 #endif
    673         err = grVkCreateDevice(physDev, &deviceInfo, nullptr, &device);
    674     }
    675     if (err) {
    676         SkDebugf("CreateDevice failed: %d\n", err);
    677         destroy_instance(getProc, inst, debugCallback, hasDebugExtension);
    678         return false;
    679     }
    680 
    681     VkQueue queue;
    682     grVkGetDeviceQueue(device, graphicsQueueIndex, 0, &queue);
    683 
    684     ctx->fInstance = inst;
    685     ctx->fPhysicalDevice = physDev;
    686     ctx->fDevice = device;
    687     ctx->fQueue = queue;
    688     ctx->fGraphicsQueueIndex = graphicsQueueIndex;
    689     ctx->fMaxAPIVersion = apiVersion;
    690     ctx->fVkExtensions = extensions;
    691     ctx->fDeviceFeatures2 = features;
    692     ctx->fGetProc = getProc;
    693     ctx->fOwnsInstanceAndDevice = false;
    694 
    695     return true;
    696 }
    697 
    698 void FreeVulkanFeaturesStructs(const VkPhysicalDeviceFeatures2* features) {
    699     // All Vulkan structs that could be part of the features chain will start with the
    700     // structure type followed by the pNext pointer. We cast to the CommonVulkanHeader
    701     // so we can get access to the pNext for the next struct.
    702     struct CommonVulkanHeader {
    703         VkStructureType sType;
    704         void*           pNext;
    705     };
    706 
    707     void* pNext = features->pNext;
    708     while (pNext) {
    709         void* current = pNext;
    710         pNext = static_cast<CommonVulkanHeader*>(current)->pNext;
    711         sk_free(current);
    712     }
    713 }
    714 
    715 }
    716 
    717 #endif
    718