• 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) \
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