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