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