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