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