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