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