• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "include/core/SkTypes.h"
9 
10 #if SK_SUPPORT_GPU && defined(SK_VULKAN)
11 
12 #include "include/gpu/vk/GrVkTypes.h"
13 #include "src/core/SkAutoMalloc.h"
14 #include "tests/Test.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 
destroy_instance(GrVkGetProc getProc,VkInstance inst)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.
DEF_GPUTEST(VulkanPriorityExtension,reporter,options)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 = std::min(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