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