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