Home | History | Annotate | Download | only in tests
      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