blob: de190aa3aefa64f7b4fdaf508477420c9cd91ba0 [file] [log] [blame]
Greg Daniel35970ec2017-11-10 10:03:05 -05001/*
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
Greg Danielf730c182018-07-02 20:15:37 +000012#include "SkAutoMalloc.h"
13#include "vk/GrVkBackendContext.h"
14#include "vk/GrVkExtensions.h"
Greg Daniel35970ec2017-11-10 10:03:05 -050015#include "../ports/SkOSLibrary.h"
16
17namespace sk_gpu_test {
18
19bool LoadVkLibraryAndGetProcAddrFuncs(PFN_vkGetInstanceProcAddr* instProc,
Greg Danield3e65aa2018-08-01 09:19:45 -040020 PFN_vkGetDeviceProcAddr* devProc) {
Chris Dalton3a67b8e2018-05-03 09:30:29 -060021#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
Greg Daniel35970ec2017-11-10 10:03:05 -050027 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;
Chris Dalton3a67b8e2018-05-03 09:30:29 -060050#endif
Greg Daniel35970ec2017-11-10 10:03:05 -050051}
Greg Danielf730c182018-07-02 20:15:37 +000052
53////////////////////////////////////////////////////////////////////////////////
54// Helper code to set up Vulkan context objects
55
56#ifdef SK_ENABLE_VK_LAYERS
57const 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",
Greg Danielf730c182018-07-02 20:15:37 +000062 "VK_LAYER_LUNARG_core_validation",
Greg Danielf730c182018-07-02 20:15:37 +000063 "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};
Greg Danielf730c182018-07-02 20:15:37 +000069
Greg Daniel98bffae2018-08-01 13:25:41 -040070static bool should_include_debug_layer(const VkLayerProperties& layerProps) {
71 for (size_t i = 0; i < SK_ARRAY_COUNT(kDebugLayerNames); ++i) {
72 if (!strcmp(layerProps.layerName, kDebugLayerNames[i])) {
73 return true;
74 }
Greg Danielf730c182018-07-02 20:15:37 +000075 }
Greg Daniel98bffae2018-08-01 13:25:41 -040076 return false;
77}
Greg Daniel92aef4b2018-08-02 13:55:49 -040078
Greg Daniel37329b32018-07-02 20:16:44 +000079VKAPI_ATTR VkBool32 VKAPI_CALL DebugReportCallback(
80 VkDebugReportFlagsEXT flags,
81 VkDebugReportObjectTypeEXT objectType,
82 uint64_t object,
83 size_t location,
84 int32_t messageCode,
85 const char* pLayerPrefix,
86 const char* pMessage,
87 void* pUserData) {
88 if (flags & VK_DEBUG_REPORT_ERROR_BIT_EXT) {
89 SkDebugf("Vulkan error [%s]: code: %d: %s\n", pLayerPrefix, messageCode, pMessage);
90 return VK_TRUE; // skip further layers
91 } else if (flags & VK_DEBUG_REPORT_WARNING_BIT_EXT) {
92 SkDebugf("Vulkan warning [%s]: code: %d: %s\n", pLayerPrefix, messageCode, pMessage);
93 } else if (flags & VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT) {
94 SkDebugf("Vulkan perf warning [%s]: code: %d: %s\n", pLayerPrefix, messageCode, pMessage);
95 } else {
96 SkDebugf("Vulkan info/debug [%s]: code: %d: %s\n", pLayerPrefix, messageCode, pMessage);
97 }
98 return VK_FALSE;
99}
100#endif
101
Greg Daniel98bffae2018-08-01 13:25:41 -0400102#define GET_PROC_LOCAL(F, inst, device) PFN_vk ## F F = (PFN_vk ## F) getProc("vk" #F, inst, device)
103
104#ifdef SK_ENABLE_VK_LAYERS
105static uint32_t remove_patch_version(uint32_t specVersion) {
106 return (specVersion >> 12) << 12;
107}
108#endif
109
110static bool init_instance_extensions_and_layers(GrVkGetProc getProc,
111 uint32_t specVersion,
112 SkTArray<VkExtensionProperties>* instanceExtensions,
113 SkTArray<VkLayerProperties>* instanceLayers) {
114 if (getProc == nullptr) {
115 return false;
116 }
117
118 GET_PROC_LOCAL(EnumerateInstanceExtensionProperties, VK_NULL_HANDLE, VK_NULL_HANDLE);
119 GET_PROC_LOCAL(EnumerateInstanceLayerProperties, VK_NULL_HANDLE, VK_NULL_HANDLE);
120
121 if (!EnumerateInstanceExtensionProperties ||
122 !EnumerateInstanceLayerProperties) {
123 return false;
124 }
125
126 VkResult res;
127 uint32_t layerCount = 0;
128#ifdef SK_ENABLE_VK_LAYERS
129 // instance layers
130 res = EnumerateInstanceLayerProperties(&layerCount, nullptr);
131 if (VK_SUCCESS != res) {
132 return false;
133 }
134 VkLayerProperties* layers = new VkLayerProperties[layerCount];
135 res = EnumerateInstanceLayerProperties(&layerCount, layers);
136 if (VK_SUCCESS != res) {
137 delete[] layers;
138 return false;
139 }
140
141 uint32_t nonPatchVersion = remove_patch_version(specVersion);
142 for (uint32_t i = 0; i < layerCount; ++i) {
143 if (nonPatchVersion <= remove_patch_version(layers[i].specVersion) &&
144 should_include_debug_layer(layers[i])) {
145 instanceLayers->push_back() = layers[i];
146 }
147 }
148 delete[] layers;
149#endif
150
151 // instance extensions
152 // via Vulkan implementation and implicitly enabled layers
153 uint32_t extensionCount = 0;
154 res = EnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr);
155 if (VK_SUCCESS != res) {
156 return false;
157 }
158 VkExtensionProperties* extensions = new VkExtensionProperties[extensionCount];
159 res = EnumerateInstanceExtensionProperties(nullptr, &extensionCount, extensions);
160 if (VK_SUCCESS != res) {
161 delete[] extensions;
162 return false;
163 }
164 for (uint32_t i = 0; i < extensionCount; ++i) {
165 instanceExtensions->push_back() = extensions[i];
166 }
167 delete [] extensions;
168
169 // via explicitly enabled layers
170 layerCount = instanceLayers->count();
171 for (uint32_t layerIndex = 0; layerIndex < layerCount; ++layerIndex) {
172 uint32_t extensionCount = 0;
173 res = EnumerateInstanceExtensionProperties((*instanceLayers)[layerIndex].layerName,
174 &extensionCount, nullptr);
175 if (VK_SUCCESS != res) {
176 return false;
177 }
178 VkExtensionProperties* extensions = new VkExtensionProperties[extensionCount];
179 res = EnumerateInstanceExtensionProperties((*instanceLayers)[layerIndex].layerName,
180 &extensionCount, extensions);
181 if (VK_SUCCESS != res) {
182 delete[] extensions;
183 return false;
184 }
185 for (uint32_t i = 0; i < extensionCount; ++i) {
186 instanceExtensions->push_back() = extensions[i];
187 }
188 delete[] extensions;
189 }
190
191 return true;
192}
193
194static bool init_device_extensions_and_layers(GrVkGetProc getProc, uint32_t specVersion,
195 VkInstance inst, VkPhysicalDevice physDev,
196 SkTArray<VkExtensionProperties>* deviceExtensions,
197 SkTArray<VkLayerProperties>* deviceLayers) {
198 if (getProc == nullptr) {
199 return false;
200 }
201
202 GET_PROC_LOCAL(EnumerateDeviceExtensionProperties, inst, VK_NULL_HANDLE);
203 GET_PROC_LOCAL(EnumerateDeviceLayerProperties, inst, VK_NULL_HANDLE);
204
205 if (!EnumerateDeviceExtensionProperties ||
206 !EnumerateDeviceLayerProperties) {
207 return false;
208 }
209
210 VkResult res;
211 // device layers
212 uint32_t layerCount = 0;
213#ifdef SK_ENABLE_VK_LAYERS
214 res = EnumerateDeviceLayerProperties(physDev, &layerCount, nullptr);
215 if (VK_SUCCESS != res) {
216 return false;
217 }
218 VkLayerProperties* layers = new VkLayerProperties[layerCount];
219 res = EnumerateDeviceLayerProperties(physDev, &layerCount, layers);
220 if (VK_SUCCESS != res) {
221 delete[] layers;
222 return false;
223 }
224
225 uint32_t nonPatchVersion = remove_patch_version(specVersion);
226 for (uint32_t i = 0; i < layerCount; ++i) {
227 if (nonPatchVersion <= remove_patch_version(layers[i].specVersion) &&
228 should_include_debug_layer(layers[i])) {
229 deviceLayers->push_back() = layers[i];
230 }
231 }
232 delete[] layers;
233#endif
234
235 // device extensions
236 // via Vulkan implementation and implicitly enabled layers
237 uint32_t extensionCount = 0;
238 res = EnumerateDeviceExtensionProperties(physDev, nullptr, &extensionCount, nullptr);
239 if (VK_SUCCESS != res) {
240 return false;
241 }
242 VkExtensionProperties* extensions = new VkExtensionProperties[extensionCount];
243 res = EnumerateDeviceExtensionProperties(physDev, nullptr, &extensionCount, extensions);
244 if (VK_SUCCESS != res) {
245 delete[] extensions;
246 return false;
247 }
248 for (uint32_t i = 0; i < extensionCount; ++i) {
249 deviceExtensions->push_back() = extensions[i];
250 }
251 delete[] extensions;
252
253 // via explicitly enabled layers
254 layerCount = deviceLayers->count();
255 for (uint32_t layerIndex = 0; layerIndex < layerCount; ++layerIndex) {
256 uint32_t extensionCount = 0;
257 res = EnumerateDeviceExtensionProperties(physDev,
258 (*deviceLayers)[layerIndex].layerName,
259 &extensionCount, nullptr);
260 if (VK_SUCCESS != res) {
261 return false;
262 }
263 VkExtensionProperties* extensions = new VkExtensionProperties[extensionCount];
264 res = EnumerateDeviceExtensionProperties(physDev,
265 (*deviceLayers)[layerIndex].layerName,
266 &extensionCount, extensions);
267 if (VK_SUCCESS != res) {
268 delete[] extensions;
269 return false;
270 }
271 for (uint32_t i = 0; i < extensionCount; ++i) {
272 deviceExtensions->push_back() = extensions[i];
273 }
274 delete[] extensions;
275 }
276
277 return true;
278}
279
Greg Daniel92aef4b2018-08-02 13:55:49 -0400280#define ACQUIRE_VK_PROC_NOCHECK(name, instance, device) \
281 PFN_vk##name grVk##name = \
282 reinterpret_cast<PFN_vk##name>(getProc("vk" #name, instance, device));
283
Greg Daniel98bffae2018-08-01 13:25:41 -0400284
285#define ACQUIRE_VK_PROC(name, instance, device) \
286 PFN_vk##name grVk##name = \
287 reinterpret_cast<PFN_vk##name>(getProc("vk" #name, instance, device)); \
288 if (grVk##name == nullptr) { \
289 SkDebugf("Function ptr for vk%s could not be acquired\n", #name); \
290 if (device != VK_NULL_HANDLE) { \
291 destroy_instance(getProc, inst, debugCallback, hasDebugExtension); \
292 } \
293 return false; \
294 }
295
Greg Daniel37329b32018-07-02 20:16:44 +0000296#define ACQUIRE_VK_PROC_LOCAL(name, instance, device) \
297 PFN_vk##name grVk##name = \
298 reinterpret_cast<PFN_vk##name>(getProc("vk" #name, instance, device)); \
299 if (grVk##name == nullptr) { \
300 SkDebugf("Function ptr for vk%s could not be acquired\n", #name); \
301 return; \
302 }
303
Greg Danield3e65aa2018-08-01 09:19:45 -0400304static void destroy_instance(GrVkGetProc getProc, VkInstance inst,
Greg Daniel37329b32018-07-02 20:16:44 +0000305 VkDebugReportCallbackEXT* debugCallback,
306 bool hasDebugExtension) {
307 if (hasDebugExtension && *debugCallback != VK_NULL_HANDLE) {
308 ACQUIRE_VK_PROC_LOCAL(DestroyDebugReportCallbackEXT, inst, VK_NULL_HANDLE);
309 grVkDestroyDebugReportCallbackEXT(inst, *debugCallback, nullptr);
310 *debugCallback = VK_NULL_HANDLE;
311 }
312 ACQUIRE_VK_PROC_LOCAL(DestroyInstance, inst, VK_NULL_HANDLE);
313 grVkDestroyInstance(inst, nullptr);
314}
315
Greg Daniela0651ac2018-08-08 09:23:18 -0400316static void setup_extension_features(GrVkGetProc getProc, VkInstance inst, VkPhysicalDevice physDev,
317 uint32_t physDeviceVersion, GrVkExtensions* extensions,
318 VkPhysicalDeviceFeatures2* features) {
319 SkASSERT(physDeviceVersion >= VK_MAKE_VERSION(1, 1, 0) ||
320 extensions->hasExtension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, 1));
321
322 // Setup all extension feature structs we may want to use.
323
324 void** tailPNext = &features->pNext;
325
326 VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT* blend = nullptr;
327 if (extensions->hasExtension(VK_EXT_BLEND_OPERATION_ADVANCED_EXTENSION_NAME, 2)) {
328 blend = (VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT*) sk_malloc_throw(
329 sizeof(VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT));
330 blend->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_FEATURES_EXT;
331 blend->pNext = nullptr;
332 *tailPNext = blend;
333 tailPNext = &blend->pNext;
334 }
335
336 if (physDeviceVersion >= VK_MAKE_VERSION(1, 1, 0)) {
337 ACQUIRE_VK_PROC_LOCAL(GetPhysicalDeviceFeatures2, inst, VK_NULL_HANDLE);
338 grVkGetPhysicalDeviceFeatures2(physDev, features);
339 } else {
340 SkASSERT(extensions->hasExtension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME,
341 1));
342 ACQUIRE_VK_PROC_LOCAL(GetPhysicalDeviceFeatures2KHR, inst, VK_NULL_HANDLE);
343 grVkGetPhysicalDeviceFeatures2KHR(physDev, features);
344 }
345
346 // If we want to disable any extension features do so here.
347}
348
Greg Danield3e65aa2018-08-01 09:19:45 -0400349bool CreateVkBackendContext(GrVkGetProc getProc,
Greg Danielf730c182018-07-02 20:15:37 +0000350 GrVkBackendContext* ctx,
Greg Daniel98bffae2018-08-01 13:25:41 -0400351 GrVkExtensions* extensions,
Greg Daniela0651ac2018-08-08 09:23:18 -0400352 VkPhysicalDeviceFeatures2* features,
Greg Daniel37329b32018-07-02 20:16:44 +0000353 VkDebugReportCallbackEXT* debugCallback,
Greg Danielf730c182018-07-02 20:15:37 +0000354 uint32_t* presentQueueIndexPtr,
355 CanPresentFn canPresent) {
Greg Daniel92aef4b2018-08-02 13:55:49 -0400356 VkResult err;
357
358 ACQUIRE_VK_PROC_NOCHECK(EnumerateInstanceVersion, VK_NULL_HANDLE, VK_NULL_HANDLE);
359 uint32_t instanceVersion = 0;
360 if (!grVkEnumerateInstanceVersion) {
361 instanceVersion = VK_MAKE_VERSION(1, 0, 0);
362 } else {
363 err = grVkEnumerateInstanceVersion(&instanceVersion);
364 if (err) {
365 SkDebugf("failed ot enumerate instance version. Err: %d\n", err);
366 return false;
367 }
368 }
369 SkASSERT(instanceVersion >= VK_MAKE_VERSION(1, 0, 0));
370
Greg Danielf730c182018-07-02 20:15:37 +0000371 VkPhysicalDevice physDev;
372 VkDevice device;
373 VkInstance inst;
Greg Danielf730c182018-07-02 20:15:37 +0000374
375 const VkApplicationInfo app_info = {
376 VK_STRUCTURE_TYPE_APPLICATION_INFO, // sType
377 nullptr, // pNext
378 "vktest", // pApplicationName
379 0, // applicationVersion
380 "vktest", // pEngineName
381 0, // engineVerison
Greg Daniel92aef4b2018-08-02 13:55:49 -0400382 instanceVersion, // apiVersion
Greg Danielf730c182018-07-02 20:15:37 +0000383 };
384
Greg Daniel98bffae2018-08-01 13:25:41 -0400385 SkTArray<VkLayerProperties> instanceLayers;
386 SkTArray<VkExtensionProperties> instanceExtensions;
387
Greg Daniel92aef4b2018-08-02 13:55:49 -0400388 if (!init_instance_extensions_and_layers(getProc, instanceVersion,
Greg Daniel98bffae2018-08-01 13:25:41 -0400389 &instanceExtensions,
390 &instanceLayers)) {
391 return false;
392 }
Greg Danielf730c182018-07-02 20:15:37 +0000393
394 SkTArray<const char*> instanceLayerNames;
395 SkTArray<const char*> instanceExtensionNames;
Greg Daniel98bffae2018-08-01 13:25:41 -0400396 for (int i = 0; i < instanceLayers.count(); ++i) {
397 instanceLayerNames.push_back(instanceLayers[i].layerName);
398 }
399 for (int i = 0; i < instanceExtensions.count(); ++i) {
400 if (strncmp(instanceExtensions[i].extensionName, "VK_KHX", 6)) {
401 instanceExtensionNames.push_back(instanceExtensions[i].extensionName);
Greg Danielf730c182018-07-02 20:15:37 +0000402 }
403 }
Greg Danielf730c182018-07-02 20:15:37 +0000404
405 const VkInstanceCreateInfo instance_create = {
406 VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, // sType
407 nullptr, // pNext
408 0, // flags
409 &app_info, // pApplicationInfo
410 (uint32_t) instanceLayerNames.count(), // enabledLayerNameCount
411 instanceLayerNames.begin(), // ppEnabledLayerNames
412 (uint32_t) instanceExtensionNames.count(), // enabledExtensionNameCount
413 instanceExtensionNames.begin(), // ppEnabledExtensionNames
414 };
415
Greg Daniel98bffae2018-08-01 13:25:41 -0400416 bool hasDebugExtension = false;
417
Greg Danielf730c182018-07-02 20:15:37 +0000418 ACQUIRE_VK_PROC(CreateInstance, VK_NULL_HANDLE, VK_NULL_HANDLE);
419 err = grVkCreateInstance(&instance_create, nullptr, &inst);
420 if (err < 0) {
421 SkDebugf("vkCreateInstance failed: %d\n", err);
422 return false;
423 }
424
Greg Daniel37329b32018-07-02 20:16:44 +0000425#ifdef SK_ENABLE_VK_LAYERS
426 *debugCallback = VK_NULL_HANDLE;
427 for (int i = 0; i < instanceExtensionNames.count() && !hasDebugExtension; ++i) {
428 if (!strcmp(instanceExtensionNames[i], VK_EXT_DEBUG_REPORT_EXTENSION_NAME)) {
429 hasDebugExtension = true;
430 }
431 }
432 if (hasDebugExtension) {
433 // Setup callback creation information
434 VkDebugReportCallbackCreateInfoEXT callbackCreateInfo;
435 callbackCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT;
436 callbackCreateInfo.pNext = nullptr;
437 callbackCreateInfo.flags = VK_DEBUG_REPORT_ERROR_BIT_EXT |
438 VK_DEBUG_REPORT_WARNING_BIT_EXT |
439 // VK_DEBUG_REPORT_INFORMATION_BIT_EXT |
440 // VK_DEBUG_REPORT_DEBUG_BIT_EXT |
441 VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT;
442 callbackCreateInfo.pfnCallback = &DebugReportCallback;
443 callbackCreateInfo.pUserData = nullptr;
444
445 ACQUIRE_VK_PROC(CreateDebugReportCallbackEXT, inst, VK_NULL_HANDLE);
446 // Register the callback
447 grVkCreateDebugReportCallbackEXT(inst, &callbackCreateInfo, nullptr, debugCallback);
448 }
449#endif
450
Greg Danielf730c182018-07-02 20:15:37 +0000451 ACQUIRE_VK_PROC(EnumeratePhysicalDevices, inst, VK_NULL_HANDLE);
Greg Daniel92aef4b2018-08-02 13:55:49 -0400452 ACQUIRE_VK_PROC(GetPhysicalDeviceProperties, inst, VK_NULL_HANDLE);
Greg Danielf730c182018-07-02 20:15:37 +0000453 ACQUIRE_VK_PROC(GetPhysicalDeviceQueueFamilyProperties, inst, VK_NULL_HANDLE);
454 ACQUIRE_VK_PROC(GetPhysicalDeviceFeatures, inst, VK_NULL_HANDLE);
455 ACQUIRE_VK_PROC(CreateDevice, inst, VK_NULL_HANDLE);
456 ACQUIRE_VK_PROC(GetDeviceQueue, inst, VK_NULL_HANDLE);
457 ACQUIRE_VK_PROC(DeviceWaitIdle, inst, VK_NULL_HANDLE);
458 ACQUIRE_VK_PROC(DestroyDevice, inst, VK_NULL_HANDLE);
459
460 uint32_t gpuCount;
461 err = grVkEnumeratePhysicalDevices(inst, &gpuCount, nullptr);
462 if (err) {
463 SkDebugf("vkEnumeratePhysicalDevices failed: %d\n", err);
Greg Daniel37329b32018-07-02 20:16:44 +0000464 destroy_instance(getProc, inst, debugCallback, hasDebugExtension);
Greg Danielf730c182018-07-02 20:15:37 +0000465 return false;
466 }
467 if (!gpuCount) {
468 SkDebugf("vkEnumeratePhysicalDevices returned no supported devices.\n");
Greg Daniel37329b32018-07-02 20:16:44 +0000469 destroy_instance(getProc, inst, debugCallback, hasDebugExtension);
Greg Danielf730c182018-07-02 20:15:37 +0000470 return false;
471 }
472 // Just returning the first physical device instead of getting the whole array.
473 // TODO: find best match for our needs
474 gpuCount = 1;
475 err = grVkEnumeratePhysicalDevices(inst, &gpuCount, &physDev);
476 // VK_INCOMPLETE is returned when the count we provide is less than the total device count.
477 if (err && VK_INCOMPLETE != err) {
478 SkDebugf("vkEnumeratePhysicalDevices failed: %d\n", err);
Greg Daniel37329b32018-07-02 20:16:44 +0000479 destroy_instance(getProc, inst, debugCallback, hasDebugExtension);
Greg Danielf730c182018-07-02 20:15:37 +0000480 return false;
481 }
482
Greg Daniel92aef4b2018-08-02 13:55:49 -0400483 VkPhysicalDeviceProperties physDeviceProperties;
484 grVkGetPhysicalDeviceProperties(physDev, &physDeviceProperties);
485 int physDeviceVersion = physDeviceProperties.apiVersion;
486
Greg Danielf730c182018-07-02 20:15:37 +0000487 // query to get the initial queue props size
488 uint32_t queueCount;
489 grVkGetPhysicalDeviceQueueFamilyProperties(physDev, &queueCount, nullptr);
490 if (!queueCount) {
491 SkDebugf("vkGetPhysicalDeviceQueueFamilyProperties returned no queues.\n");
Greg Daniel37329b32018-07-02 20:16:44 +0000492 destroy_instance(getProc, inst, debugCallback, hasDebugExtension);
Greg Danielf730c182018-07-02 20:15:37 +0000493 return false;
494 }
495
496 SkAutoMalloc queuePropsAlloc(queueCount * sizeof(VkQueueFamilyProperties));
497 // now get the actual queue props
498 VkQueueFamilyProperties* queueProps = (VkQueueFamilyProperties*)queuePropsAlloc.get();
499
500 grVkGetPhysicalDeviceQueueFamilyProperties(physDev, &queueCount, queueProps);
501
502 // iterate to find the graphics queue
503 uint32_t graphicsQueueIndex = queueCount;
504 for (uint32_t i = 0; i < queueCount; i++) {
505 if (queueProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
506 graphicsQueueIndex = i;
507 break;
508 }
509 }
510 if (graphicsQueueIndex == queueCount) {
511 SkDebugf("Could not find any supported graphics queues.\n");
Greg Daniel37329b32018-07-02 20:16:44 +0000512 destroy_instance(getProc, inst, debugCallback, hasDebugExtension);
Greg Danielf730c182018-07-02 20:15:37 +0000513 return false;
514 }
515
516 // iterate to find the present queue, if needed
517 uint32_t presentQueueIndex = queueCount;
518 if (presentQueueIndexPtr && canPresent) {
519 for (uint32_t i = 0; i < queueCount; i++) {
520 if (canPresent(inst, physDev, i)) {
521 presentQueueIndex = i;
522 break;
523 }
524 }
525 if (presentQueueIndex == queueCount) {
526 SkDebugf("Could not find any supported present queues.\n");
Greg Daniel37329b32018-07-02 20:16:44 +0000527 destroy_instance(getProc, inst, debugCallback, hasDebugExtension);
Greg Danielf730c182018-07-02 20:15:37 +0000528 return false;
529 }
530 *presentQueueIndexPtr = presentQueueIndex;
531 } else {
532 // Just setting this so we end up make a single queue for graphics since there was no
533 // request for a present queue.
534 presentQueueIndex = graphicsQueueIndex;
535 }
536
Greg Daniel98bffae2018-08-01 13:25:41 -0400537 SkTArray<VkLayerProperties> deviceLayers;
538 SkTArray<VkExtensionProperties> deviceExtensions;
Greg Daniel92aef4b2018-08-02 13:55:49 -0400539 if (!init_device_extensions_and_layers(getProc, physDeviceVersion,
Greg Daniel98bffae2018-08-01 13:25:41 -0400540 inst, physDev,
541 &deviceExtensions,
542 &deviceLayers)) {
543 destroy_instance(getProc, inst, debugCallback, hasDebugExtension);
544 return false;
545 }
Greg Danielf730c182018-07-02 20:15:37 +0000546
547 SkTArray<const char*> deviceLayerNames;
548 SkTArray<const char*> deviceExtensionNames;
Greg Daniel98bffae2018-08-01 13:25:41 -0400549 for (int i = 0; i < deviceLayers.count(); ++i) {
550 deviceLayerNames.push_back(deviceLayers[i].layerName);
Greg Danielf730c182018-07-02 20:15:37 +0000551 }
Greg Daniel98bffae2018-08-01 13:25:41 -0400552 for (int i = 0; i < deviceExtensions.count(); ++i) {
553 // Don't use experimental extensions since they typically don't work with debug layers and
554 // often are missing dependecy requirements for other extensions. Additionally, these are
555 // often left behind in the driver even after they've been promoted to real extensions.
556 if (strncmp(deviceExtensions[i].extensionName, "VK_KHX", 6) &&
557 strncmp(deviceExtensions[i].extensionName, "VK_NVX", 6)) {
558 deviceExtensionNames.push_back(deviceExtensions[i].extensionName);
559 }
Greg Danielf730c182018-07-02 20:15:37 +0000560 }
561
Greg Daniela0651ac2018-08-08 09:23:18 -0400562 extensions->init(getProc, inst, physDev,
563 (uint32_t) instanceExtensionNames.count(),
564 instanceExtensionNames.begin(),
565 (uint32_t) deviceExtensionNames.count(),
566 deviceExtensionNames.begin());
567
568 memset(features, 0, sizeof(VkPhysicalDeviceFeatures2));
569 features->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
570 features->pNext = nullptr;
571
572 VkPhysicalDeviceFeatures* deviceFeatures = &features->features;
573 void* pointerToFeatures = nullptr;
574 if (physDeviceVersion >= VK_MAKE_VERSION(1, 1, 0) ||
575 extensions->hasExtension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, 1)) {
576 setup_extension_features(getProc, inst, physDev, physDeviceVersion, extensions, features);
577 // If we set the pNext of the VkDeviceCreateInfo to our VkPhysicalDeviceFeatures2 struct,
578 // the device creation will use that instead of the ppEnabledFeatures.
579 pointerToFeatures = features;
580 } else {
581 grVkGetPhysicalDeviceFeatures(physDev, deviceFeatures);
582 }
583
Greg Danielf730c182018-07-02 20:15:37 +0000584 // this looks like it would slow things down,
585 // and we can't depend on it on all platforms
Greg Daniela0651ac2018-08-08 09:23:18 -0400586 deviceFeatures->robustBufferAccess = VK_FALSE;
Greg Danielf730c182018-07-02 20:15:37 +0000587
Greg Danielf730c182018-07-02 20:15:37 +0000588 float queuePriorities[1] = { 0.0 };
589 // Here we assume no need for swapchain queue
590 // If one is needed, the client will need its own setup code
591 const VkDeviceQueueCreateInfo queueInfo[2] = {
592 {
593 VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, // sType
594 nullptr, // pNext
595 0, // VkDeviceQueueCreateFlags
596 graphicsQueueIndex, // queueFamilyIndex
597 1, // queueCount
598 queuePriorities, // pQueuePriorities
599 },
600 {
601 VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, // sType
602 nullptr, // pNext
603 0, // VkDeviceQueueCreateFlags
604 presentQueueIndex, // queueFamilyIndex
605 1, // queueCount
606 queuePriorities, // pQueuePriorities
607 }
608 };
609 uint32_t queueInfoCount = (presentQueueIndex != graphicsQueueIndex) ? 2 : 1;
610
611 const VkDeviceCreateInfo deviceInfo = {
Greg Daniela0651ac2018-08-08 09:23:18 -0400612 VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, // sType
613 pointerToFeatures, // pNext
614 0, // VkDeviceCreateFlags
615 queueInfoCount, // queueCreateInfoCount
616 queueInfo, // pQueueCreateInfos
617 (uint32_t) deviceLayerNames.count(), // layerCount
618 deviceLayerNames.begin(), // ppEnabledLayerNames
619 (uint32_t) deviceExtensionNames.count(), // extensionCount
620 deviceExtensionNames.begin(), // ppEnabledExtensionNames
621 pointerToFeatures ? nullptr : deviceFeatures // ppEnabledFeatures
Greg Danielf730c182018-07-02 20:15:37 +0000622 };
623
624 err = grVkCreateDevice(physDev, &deviceInfo, nullptr, &device);
625 if (err) {
626 SkDebugf("CreateDevice failed: %d\n", err);
Greg Daniel37329b32018-07-02 20:16:44 +0000627 destroy_instance(getProc, inst, debugCallback, hasDebugExtension);
Greg Danielf730c182018-07-02 20:15:37 +0000628 return false;
629 }
630
Greg Danielf730c182018-07-02 20:15:37 +0000631 VkQueue queue;
632 grVkGetDeviceQueue(device, graphicsQueueIndex, 0, &queue);
633
634 ctx->fInstance = inst;
635 ctx->fPhysicalDevice = physDev;
636 ctx->fDevice = device;
637 ctx->fQueue = queue;
638 ctx->fGraphicsQueueIndex = graphicsQueueIndex;
Greg Daniel92aef4b2018-08-02 13:55:49 -0400639 ctx->fInstanceVersion = instanceVersion;
Greg Daniel98bffae2018-08-01 13:25:41 -0400640 ctx->fVkExtensions = extensions;
Greg Daniela0651ac2018-08-08 09:23:18 -0400641 ctx->fDeviceFeatures2 = features;
Greg Danielc8cd45a2018-07-12 10:02:37 -0400642 ctx->fGetProc = getProc;
Greg Danielf730c182018-07-02 20:15:37 +0000643 ctx->fOwnsInstanceAndDevice = false;
644
645 return true;
Greg Danielf730c182018-07-02 20:15:37 +0000646}
647
Greg Daniela0651ac2018-08-08 09:23:18 -0400648void FreeVulkanFeaturesStructs(const VkPhysicalDeviceFeatures2* features) {
649 // All Vulkan structs that could be part of the features chain will start with the
650 // structure type followed by the pNext pointer. We cast to the CommonVulkanHeader
651 // so we can get access to the pNext for the next struct.
652 struct CommonVulkanHeader {
653 VkStructureType sType;
654 void* pNext;
655 };
656
657 void* pNext = features->pNext;
658 while (pNext) {
659 void* current = pNext;
660 pNext = static_cast<CommonVulkanHeader*>(current)->pNext;
661 sk_free(current);
662 }
663}
664
Greg Daniel35970ec2017-11-10 10:03:05 -0500665}
666
667#endif