1 /* 2 * Copyright 2019 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 "SkTypes.h" 9 10 #if SK_SUPPORT_GPU && defined(SK_VULKAN) 11 12 #include "SkAutoMalloc.h" 13 #include "Test.h" 14 #include "vk/GrVkTypes.h" 15 #include "../tools/gpu/vk/VkTestUtils.h" 16 17 #define ACQUIRE_VK_PROC_NOCHECK(name, instance, device) \ 18 PFN_vk##name grVk##name = reinterpret_cast<PFN_vk##name>(getProc("vk" #name, instance, device)) 19 20 #define ACQUIRE_VK_PROC(name, instance, device) \ 21 PFN_vk##name grVk##name = \ 22 reinterpret_cast<PFN_vk##name>(getProc("vk" #name, instance, device)); \ 23 do { \ 24 if (grVk##name == nullptr) { \ 25 if (device != VK_NULL_HANDLE) { \ 26 destroy_instance(getProc, inst); \ 27 } \ 28 return; \ 29 } \ 30 } while (0) 31 32 #define ACQUIRE_VK_PROC_LOCAL(name, instance, device) \ 33 PFN_vk##name grVk##name = \ 34 reinterpret_cast<PFN_vk##name>(getProc("vk" #name, instance, device)); \ 35 do { \ 36 if (grVk##name == nullptr) { \ 37 return; \ 38 } \ 39 } while (0) 40 41 #define GET_PROC_LOCAL(F, inst, device) PFN_vk ## F F = (PFN_vk ## F) getProc("vk" #F, inst, device) 42 43 static void destroy_instance(GrVkGetProc getProc, VkInstance inst) { 44 ACQUIRE_VK_PROC_LOCAL(DestroyInstance, inst, VK_NULL_HANDLE); 45 grVkDestroyInstance(inst, nullptr); 46 } 47 48 // If the extension VK_EXT_GLOBAL_PRIORITY is supported, this test just tries to create a VkDevice 49 // using the various global priorities. The test passes if no errors are reported or the test 50 // doesn't crash. 51 DEF_GPUTEST(VulkanPriorityExtension, reporter, options) { 52 PFN_vkGetInstanceProcAddr instProc; 53 PFN_vkGetDeviceProcAddr devProc; 54 if (!sk_gpu_test::LoadVkLibraryAndGetProcAddrFuncs(&instProc, &devProc)) { 55 return; 56 } 57 auto getProc = [instProc, devProc](const char* proc_name, 58 VkInstance instance, VkDevice device) { 59 if (device != VK_NULL_HANDLE) { 60 return devProc(device, proc_name); 61 } 62 return instProc(instance, proc_name); 63 }; 64 65 VkResult err; 66 67 ACQUIRE_VK_PROC_NOCHECK(EnumerateInstanceVersion, VK_NULL_HANDLE, VK_NULL_HANDLE); 68 uint32_t instanceVersion = 0; 69 if (!grVkEnumerateInstanceVersion) { 70 instanceVersion = VK_MAKE_VERSION(1, 0, 0); 71 } else { 72 err = grVkEnumerateInstanceVersion(&instanceVersion); 73 if (err) { 74 ERRORF(reporter, "failed ot enumerate instance version. Err: %d", err); 75 return; 76 } 77 } 78 SkASSERT(instanceVersion >= VK_MAKE_VERSION(1, 0, 0)); 79 uint32_t apiVersion = VK_MAKE_VERSION(1, 0, 0); 80 if (instanceVersion >= VK_MAKE_VERSION(1, 1, 0)) { 81 // If the instance version is 1.0 we must have the apiVersion also be 1.0. However, if the 82 // instance version is 1.1 or higher, we can set the apiVersion to be whatever the highest 83 // api we may use in skia (technically it can be arbitrary). So for now we set it to 1.1 84 // since that is the highest vulkan version. 85 apiVersion = VK_MAKE_VERSION(1, 1, 0); 86 } 87 88 instanceVersion = SkTMin(instanceVersion, apiVersion); 89 90 VkPhysicalDevice physDev; 91 VkDevice device; 92 VkInstance inst; 93 94 const VkApplicationInfo app_info = { 95 VK_STRUCTURE_TYPE_APPLICATION_INFO, // sType 96 nullptr, // pNext 97 "vktest", // pApplicationName 98 0, // applicationVersion 99 "vktest", // pEngineName 100 0, // engineVersion 101 apiVersion, // apiVersion 102 }; 103 104 const VkInstanceCreateInfo instance_create = { 105 VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, // sType 106 nullptr, // pNext 107 0, // flags 108 &app_info, // pApplicationInfo 109 0, // enabledLayerNameCount 110 nullptr, // ppEnabledLayerNames 111 0, // enabledExtensionNameCount 112 nullptr, // ppEnabledExtensionNames 113 }; 114 115 ACQUIRE_VK_PROC(CreateInstance, VK_NULL_HANDLE, VK_NULL_HANDLE); 116 err = grVkCreateInstance(&instance_create, nullptr, &inst); 117 if (err < 0) { 118 ERRORF(reporter, "Failed to create VkInstance"); 119 return; 120 } 121 122 ACQUIRE_VK_PROC(EnumeratePhysicalDevices, inst, VK_NULL_HANDLE); 123 ACQUIRE_VK_PROC(GetPhysicalDeviceProperties, inst, VK_NULL_HANDLE); 124 ACQUIRE_VK_PROC(GetPhysicalDeviceQueueFamilyProperties, inst, VK_NULL_HANDLE); 125 ACQUIRE_VK_PROC(GetPhysicalDeviceFeatures, inst, VK_NULL_HANDLE); 126 ACQUIRE_VK_PROC(CreateDevice, inst, VK_NULL_HANDLE); 127 ACQUIRE_VK_PROC(GetDeviceQueue, inst, VK_NULL_HANDLE); 128 ACQUIRE_VK_PROC(DeviceWaitIdle, inst, VK_NULL_HANDLE); 129 ACQUIRE_VK_PROC(DestroyDevice, inst, VK_NULL_HANDLE); 130 131 uint32_t gpuCount; 132 err = grVkEnumeratePhysicalDevices(inst, &gpuCount, nullptr); 133 if (err) { 134 ERRORF(reporter, "vkEnumeratePhysicalDevices failed: %d", err); 135 destroy_instance(getProc, inst); 136 return; 137 } 138 if (!gpuCount) { 139 ERRORF(reporter, "vkEnumeratePhysicalDevices returned no supported devices."); 140 destroy_instance(getProc, inst); 141 return; 142 } 143 // Just returning the first physical device instead of getting the whole array. 144 // TODO: find best match for our needs 145 gpuCount = 1; 146 err = grVkEnumeratePhysicalDevices(inst, &gpuCount, &physDev); 147 // VK_INCOMPLETE is returned when the count we provide is less than the total device count. 148 if (err && VK_INCOMPLETE != err) { 149 ERRORF(reporter, "vkEnumeratePhysicalDevices failed: %d", err); 150 destroy_instance(getProc, inst); 151 return; 152 } 153 154 // query to get the initial queue props size 155 uint32_t queueCount; 156 grVkGetPhysicalDeviceQueueFamilyProperties(physDev, &queueCount, nullptr); 157 if (!queueCount) { 158 ERRORF(reporter, "vkGetPhysicalDeviceQueueFamilyProperties returned no queues."); 159 destroy_instance(getProc, inst); 160 return; 161 } 162 163 SkAutoMalloc queuePropsAlloc(queueCount * sizeof(VkQueueFamilyProperties)); 164 // now get the actual queue props 165 VkQueueFamilyProperties* queueProps = (VkQueueFamilyProperties*)queuePropsAlloc.get(); 166 167 grVkGetPhysicalDeviceQueueFamilyProperties(physDev, &queueCount, queueProps); 168 169 // iterate to find the graphics queue 170 uint32_t graphicsQueueIndex = queueCount; 171 for (uint32_t i = 0; i < queueCount; i++) { 172 if (queueProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) { 173 graphicsQueueIndex = i; 174 break; 175 } 176 } 177 if (graphicsQueueIndex == queueCount) { 178 ERRORF(reporter, "Could not find any supported graphics queues."); 179 destroy_instance(getProc, inst); 180 return; 181 } 182 183 GET_PROC_LOCAL(EnumerateDeviceExtensionProperties, inst, VK_NULL_HANDLE); 184 GET_PROC_LOCAL(EnumerateDeviceLayerProperties, inst, VK_NULL_HANDLE); 185 186 if (!EnumerateDeviceExtensionProperties || 187 !EnumerateDeviceLayerProperties) { 188 destroy_instance(getProc, inst); 189 return; 190 } 191 192 // device extensions 193 // via Vulkan implementation and implicitly enabled layers 194 uint32_t extensionCount = 0; 195 err = EnumerateDeviceExtensionProperties(physDev, nullptr, &extensionCount, nullptr); 196 if (VK_SUCCESS != err) { 197 ERRORF(reporter, "Could not enumerate device extension properties."); 198 destroy_instance(getProc, inst); 199 return; 200 } 201 VkExtensionProperties* extensions = new VkExtensionProperties[extensionCount]; 202 err = EnumerateDeviceExtensionProperties(physDev, nullptr, &extensionCount, extensions); 203 if (VK_SUCCESS != err) { 204 delete[] extensions; 205 ERRORF(reporter, "Could not enumerate device extension properties."); 206 destroy_instance(getProc, inst); 207 return; 208 } 209 bool hasPriorityExt = false; 210 for (uint32_t i = 0; i < extensionCount; ++i) { 211 if (!strcmp(extensions[i].extensionName, VK_EXT_GLOBAL_PRIORITY_EXTENSION_NAME)) { 212 hasPriorityExt = true; 213 } 214 } 215 delete[] extensions; 216 217 if (!hasPriorityExt) { 218 destroy_instance(getProc, inst); 219 return; 220 } 221 222 const char* priorityExt = VK_EXT_GLOBAL_PRIORITY_EXTENSION_NAME; 223 224 VkPhysicalDeviceFeatures deviceFeatures; 225 grVkGetPhysicalDeviceFeatures(physDev, &deviceFeatures); 226 227 // this looks like it would slow things down, 228 // and we can't depend on it on all platforms 229 deviceFeatures.robustBufferAccess = VK_FALSE; 230 231 float queuePriorities[1] = { 0.0 }; 232 233 VkDeviceQueueGlobalPriorityCreateInfoEXT queuePriorityCreateInfo; 234 queuePriorityCreateInfo.sType = 235 VK_STRUCTURE_TYPE_DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO_EXT; 236 queuePriorityCreateInfo.pNext = nullptr; 237 238 VkDeviceQueueCreateInfo queueInfo = { 239 VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, // sType 240 &queuePriorityCreateInfo, // pNext 241 0, // VkDeviceQueueCreateFlags 242 graphicsQueueIndex, // queueFamilyIndex 243 1, // queueCount 244 queuePriorities, // pQueuePriorities 245 }; 246 247 for (VkQueueGlobalPriorityEXT globalPriority : { VK_QUEUE_GLOBAL_PRIORITY_LOW_EXT, 248 VK_QUEUE_GLOBAL_PRIORITY_MEDIUM_EXT, 249 VK_QUEUE_GLOBAL_PRIORITY_HIGH_EXT, 250 VK_QUEUE_GLOBAL_PRIORITY_REALTIME_EXT }) { 251 queuePriorityCreateInfo.globalPriority = globalPriority; 252 253 const VkDeviceCreateInfo deviceInfo = { 254 VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, // sType 255 nullptr, // pNext 256 0, // VkDeviceCreateFlags 257 1, // queueCreateInfoCount 258 &queueInfo, // pQueueCreateInfos 259 0, // layerCount 260 nullptr, // ppEnabledLayerNames 261 1, // extensionCount 262 &priorityExt, // ppEnabledExtensionNames 263 &deviceFeatures // ppEnabledFeatures 264 }; 265 266 err = grVkCreateDevice(physDev, &deviceInfo, nullptr, &device); 267 268 if (err != VK_SUCCESS && err != VK_ERROR_NOT_PERMITTED_EXT) { 269 ERRORF(reporter, "CreateDevice failed: %d, priority %d", err, globalPriority); 270 destroy_instance(getProc, inst); 271 continue; 272 } 273 if (err != VK_ERROR_NOT_PERMITTED_EXT) { 274 grVkDestroyDevice(device, nullptr); 275 } 276 } 277 destroy_instance(getProc, inst); 278 } 279 280 #endif 281