blob: 927f4fbe824107ef08a89cbf81c2fd029441aa62 [file] [log] [blame]
Greg Daniel35970ec2017-11-10 10:03:05 -05001/*
2 * Copyright 2017 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 "VkTestUtils.h"
9
10#ifdef SK_VULKAN
11
Greg Danielf730c182018-07-02 20:15:37 +000012#include "SkAutoMalloc.h"
13#include "vk/GrVkBackendContext.h"
14#include "vk/GrVkExtensions.h"
Greg Daniel35970ec2017-11-10 10:03:05 -050015#include "../ports/SkOSLibrary.h"
16
17namespace sk_gpu_test {
18
19bool LoadVkLibraryAndGetProcAddrFuncs(PFN_vkGetInstanceProcAddr* instProc,
20 PFN_vkGetDeviceProcAddr* devProc) {
Chris Dalton3a67b8e2018-05-03 09:30:29 -060021#ifdef SK_MOLTENVK
22 // MoltenVK is a statically linked framework, so there is no Vulkan library to load.
23 *instProc = &vkGetInstanceProcAddr;
24 *devProc = &vkGetDeviceProcAddr;
25 return true;
26#else
Greg Daniel35970ec2017-11-10 10:03:05 -050027 static void* vkLib = nullptr;
28 static PFN_vkGetInstanceProcAddr localInstProc = nullptr;
29 static PFN_vkGetDeviceProcAddr localDevProc = nullptr;
30 if (!vkLib) {
31#if defined _WIN32
32 vkLib = DynamicLoadLibrary("vulkan-1.dll");
33#else
34 vkLib = DynamicLoadLibrary("libvulkan.so");
35#endif
36 if (!vkLib) {
37 return false;
38 }
39 localInstProc = (PFN_vkGetInstanceProcAddr) GetProcedureAddress(vkLib,
40 "vkGetInstanceProcAddr");
41 localDevProc = (PFN_vkGetDeviceProcAddr) GetProcedureAddress(vkLib,
42 "vkGetDeviceProcAddr");
43 }
44 if (!localInstProc || !localDevProc) {
45 return false;
46 }
47 *instProc = localInstProc;
48 *devProc = localDevProc;
49 return true;
Chris Dalton3a67b8e2018-05-03 09:30:29 -060050#endif
Greg Daniel35970ec2017-11-10 10:03:05 -050051}
Greg Danielf730c182018-07-02 20:15:37 +000052
53////////////////////////////////////////////////////////////////////////////////
54// Helper code to set up Vulkan context objects
55
56#ifdef SK_ENABLE_VK_LAYERS
57const char* kDebugLayerNames[] = {
58 // elements of VK_LAYER_LUNARG_standard_validation
59 "VK_LAYER_GOOGLE_threading",
60 "VK_LAYER_LUNARG_parameter_validation",
61 "VK_LAYER_LUNARG_object_tracker",
62 "VK_LAYER_LUNARG_image",
63 "VK_LAYER_LUNARG_core_validation",
64 "VK_LAYER_LUNARG_swapchain",
65 "VK_LAYER_GOOGLE_unique_objects",
66 // not included in standard_validation
67 //"VK_LAYER_LUNARG_api_dump",
68 //"VK_LAYER_LUNARG_vktrace",
69 //"VK_LAYER_LUNARG_screenshot",
70};
71#endif
72
73// the minimum version of Vulkan supported
74#ifdef SK_BUILD_FOR_ANDROID
75const uint32_t kGrVkMinimumVersion = VK_MAKE_VERSION(1, 0, 3);
76#else
77const uint32_t kGrVkMinimumVersion = VK_MAKE_VERSION(1, 0, 8);
78#endif
79
80#define ACQUIRE_VK_PROC(name, instance, device) \
81 PFN_vk##name grVk##name = \
82 reinterpret_cast<PFN_vk##name>(getProc("vk" #name, instance, device)); \
83 if (grVk##name == nullptr) { \
84 SkDebugf("Function ptr for vk%s could not be acquired\n", #name); \
85 return false; \
86 }
87
88bool CreateVkBackendContext(const GrVkInterface::GetInstanceProc& getInstanceProc,
89 const GrVkInterface::GetDeviceProc& getDeviceProc,
90 GrVkBackendContext* ctx,
91 uint32_t* presentQueueIndexPtr,
92 CanPresentFn canPresent) {
93 auto getProc = [&getInstanceProc, &getDeviceProc](const char* proc_name,
94 VkInstance instance, VkDevice device) {
95 if (device != VK_NULL_HANDLE) {
96 return getDeviceProc(device, proc_name);
97 }
98 return getInstanceProc(instance, proc_name);
99 };
100
101 VkPhysicalDevice physDev;
102 VkDevice device;
103 VkInstance inst;
104 VkResult err;
105
106 const VkApplicationInfo app_info = {
107 VK_STRUCTURE_TYPE_APPLICATION_INFO, // sType
108 nullptr, // pNext
109 "vktest", // pApplicationName
110 0, // applicationVersion
111 "vktest", // pEngineName
112 0, // engineVerison
113 kGrVkMinimumVersion, // apiVersion
114 };
115
116 GrVkExtensions extensions(getProc);
117 extensions.initInstance(kGrVkMinimumVersion);
118
119 SkTArray<const char*> instanceLayerNames;
120 SkTArray<const char*> instanceExtensionNames;
121 uint32_t extensionFlags = 0;
122#ifdef SK_ENABLE_VK_LAYERS
123 for (size_t i = 0; i < SK_ARRAY_COUNT(kDebugLayerNames); ++i) {
124 if (extensions.hasInstanceLayer(kDebugLayerNames[i])) {
125 instanceLayerNames.push_back(kDebugLayerNames[i]);
126 }
127 }
128 if (extensions.hasInstanceExtension(VK_EXT_DEBUG_REPORT_EXTENSION_NAME)) {
129 instanceExtensionNames.push_back(VK_EXT_DEBUG_REPORT_EXTENSION_NAME);
130 extensionFlags |= kEXT_debug_report_GrVkExtensionFlag;
131 }
132#endif
133
134 if (extensions.hasInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME)) {
135 instanceExtensionNames.push_back(VK_KHR_SURFACE_EXTENSION_NAME);
136 extensionFlags |= kKHR_surface_GrVkExtensionFlag;
137 }
138 if (extensions.hasInstanceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME)) {
139 instanceExtensionNames.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
140 extensionFlags |= kKHR_swapchain_GrVkExtensionFlag;
141 }
142#ifdef SK_BUILD_FOR_WIN
143 if (extensions.hasInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME)) {
144 instanceExtensionNames.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
145 extensionFlags |= kKHR_win32_surface_GrVkExtensionFlag;
146 }
147#elif defined(SK_BUILD_FOR_ANDROID)
148 if (extensions.hasInstanceExtension(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME)) {
149 instanceExtensionNames.push_back(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME);
150 extensionFlags |= kKHR_android_surface_GrVkExtensionFlag;
151 }
152#elif defined(SK_BUILD_FOR_UNIX) && !defined(__Fuchsia__)
153 if (extensions.hasInstanceExtension(VK_KHR_XCB_SURFACE_EXTENSION_NAME)) {
154 instanceExtensionNames.push_back(VK_KHR_XCB_SURFACE_EXTENSION_NAME);
155 extensionFlags |= kKHR_xcb_surface_GrVkExtensionFlag;
156 }
157#endif
158
159 const VkInstanceCreateInfo instance_create = {
160 VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, // sType
161 nullptr, // pNext
162 0, // flags
163 &app_info, // pApplicationInfo
164 (uint32_t) instanceLayerNames.count(), // enabledLayerNameCount
165 instanceLayerNames.begin(), // ppEnabledLayerNames
166 (uint32_t) instanceExtensionNames.count(), // enabledExtensionNameCount
167 instanceExtensionNames.begin(), // ppEnabledExtensionNames
168 };
169
170 ACQUIRE_VK_PROC(CreateInstance, VK_NULL_HANDLE, VK_NULL_HANDLE);
171 err = grVkCreateInstance(&instance_create, nullptr, &inst);
172 if (err < 0) {
173 SkDebugf("vkCreateInstance failed: %d\n", err);
174 return false;
175 }
176
177 ACQUIRE_VK_PROC(DestroyInstance, inst, VK_NULL_HANDLE);
178 ACQUIRE_VK_PROC(EnumeratePhysicalDevices, inst, VK_NULL_HANDLE);
179 ACQUIRE_VK_PROC(GetPhysicalDeviceQueueFamilyProperties, inst, VK_NULL_HANDLE);
180 ACQUIRE_VK_PROC(GetPhysicalDeviceFeatures, inst, VK_NULL_HANDLE);
181 ACQUIRE_VK_PROC(CreateDevice, inst, VK_NULL_HANDLE);
182 ACQUIRE_VK_PROC(GetDeviceQueue, inst, VK_NULL_HANDLE);
183 ACQUIRE_VK_PROC(DeviceWaitIdle, inst, VK_NULL_HANDLE);
184 ACQUIRE_VK_PROC(DestroyDevice, inst, VK_NULL_HANDLE);
185
186 uint32_t gpuCount;
187 err = grVkEnumeratePhysicalDevices(inst, &gpuCount, nullptr);
188 if (err) {
189 SkDebugf("vkEnumeratePhysicalDevices failed: %d\n", err);
190 grVkDestroyInstance(inst, nullptr);
191 return false;
192 }
193 if (!gpuCount) {
194 SkDebugf("vkEnumeratePhysicalDevices returned no supported devices.\n");
195 grVkDestroyInstance(inst, nullptr);
196 return false;
197 }
198 // Just returning the first physical device instead of getting the whole array.
199 // TODO: find best match for our needs
200 gpuCount = 1;
201 err = grVkEnumeratePhysicalDevices(inst, &gpuCount, &physDev);
202 // VK_INCOMPLETE is returned when the count we provide is less than the total device count.
203 if (err && VK_INCOMPLETE != err) {
204 SkDebugf("vkEnumeratePhysicalDevices failed: %d\n", err);
205 grVkDestroyInstance(inst, nullptr);
206 return false;
207 }
208
209 // query to get the initial queue props size
210 uint32_t queueCount;
211 grVkGetPhysicalDeviceQueueFamilyProperties(physDev, &queueCount, nullptr);
212 if (!queueCount) {
213 SkDebugf("vkGetPhysicalDeviceQueueFamilyProperties returned no queues.\n");
214 grVkDestroyInstance(inst, nullptr);
215 return false;
216 }
217
218 SkAutoMalloc queuePropsAlloc(queueCount * sizeof(VkQueueFamilyProperties));
219 // now get the actual queue props
220 VkQueueFamilyProperties* queueProps = (VkQueueFamilyProperties*)queuePropsAlloc.get();
221
222 grVkGetPhysicalDeviceQueueFamilyProperties(physDev, &queueCount, queueProps);
223
224 // iterate to find the graphics queue
225 uint32_t graphicsQueueIndex = queueCount;
226 for (uint32_t i = 0; i < queueCount; i++) {
227 if (queueProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
228 graphicsQueueIndex = i;
229 break;
230 }
231 }
232 if (graphicsQueueIndex == queueCount) {
233 SkDebugf("Could not find any supported graphics queues.\n");
234 grVkDestroyInstance(inst, nullptr);
235 return false;
236 }
237
238 // iterate to find the present queue, if needed
239 uint32_t presentQueueIndex = queueCount;
240 if (presentQueueIndexPtr && canPresent) {
241 for (uint32_t i = 0; i < queueCount; i++) {
242 if (canPresent(inst, physDev, i)) {
243 presentQueueIndex = i;
244 break;
245 }
246 }
247 if (presentQueueIndex == queueCount) {
248 SkDebugf("Could not find any supported present queues.\n");
249 grVkDestroyInstance(inst, nullptr);
250 return false;
251 }
252 *presentQueueIndexPtr = presentQueueIndex;
253 } else {
254 // Just setting this so we end up make a single queue for graphics since there was no
255 // request for a present queue.
256 presentQueueIndex = graphicsQueueIndex;
257 }
258
259 extensions.initDevice(kGrVkMinimumVersion, inst, physDev);
260
261 SkTArray<const char*> deviceLayerNames;
262 SkTArray<const char*> deviceExtensionNames;
263#ifdef SK_ENABLE_VK_LAYERS
264 for (size_t i = 0; i < SK_ARRAY_COUNT(kDebugLayerNames); ++i) {
265 if (extensions.hasDeviceLayer(kDebugLayerNames[i])) {
266 deviceLayerNames.push_back(kDebugLayerNames[i]);
267 }
268 }
269#endif
270 if (extensions.hasDeviceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME)) {
271 deviceExtensionNames.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
272 extensionFlags |= kKHR_swapchain_GrVkExtensionFlag;
273 }
274 if (extensions.hasDeviceExtension("VK_NV_glsl_shader")) {
275 deviceExtensionNames.push_back("VK_NV_glsl_shader");
276 extensionFlags |= kNV_glsl_shader_GrVkExtensionFlag;
277 }
278
279 // query to get the physical device properties
280 VkPhysicalDeviceFeatures deviceFeatures;
281 grVkGetPhysicalDeviceFeatures(physDev, &deviceFeatures);
282 // this looks like it would slow things down,
283 // and we can't depend on it on all platforms
284 deviceFeatures.robustBufferAccess = VK_FALSE;
285
286 uint32_t featureFlags = 0;
287 if (deviceFeatures.geometryShader) {
288 featureFlags |= kGeometryShader_GrVkFeatureFlag;
289 }
290 if (deviceFeatures.dualSrcBlend) {
291 featureFlags |= kDualSrcBlend_GrVkFeatureFlag;
292 }
293 if (deviceFeatures.sampleRateShading) {
294 featureFlags |= kSampleRateShading_GrVkFeatureFlag;
295 }
296
297 float queuePriorities[1] = { 0.0 };
298 // Here we assume no need for swapchain queue
299 // If one is needed, the client will need its own setup code
300 const VkDeviceQueueCreateInfo queueInfo[2] = {
301 {
302 VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, // sType
303 nullptr, // pNext
304 0, // VkDeviceQueueCreateFlags
305 graphicsQueueIndex, // queueFamilyIndex
306 1, // queueCount
307 queuePriorities, // pQueuePriorities
308 },
309 {
310 VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, // sType
311 nullptr, // pNext
312 0, // VkDeviceQueueCreateFlags
313 presentQueueIndex, // queueFamilyIndex
314 1, // queueCount
315 queuePriorities, // pQueuePriorities
316 }
317 };
318 uint32_t queueInfoCount = (presentQueueIndex != graphicsQueueIndex) ? 2 : 1;
319
320 const VkDeviceCreateInfo deviceInfo = {
321 VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, // sType
322 nullptr, // pNext
323 0, // VkDeviceCreateFlags
324 queueInfoCount, // queueCreateInfoCount
325 queueInfo, // pQueueCreateInfos
326 (uint32_t) deviceLayerNames.count(), // layerCount
327 deviceLayerNames.begin(), // ppEnabledLayerNames
328 (uint32_t) deviceExtensionNames.count(), // extensionCount
329 deviceExtensionNames.begin(), // ppEnabledExtensionNames
330 &deviceFeatures // ppEnabledFeatures
331 };
332
333 err = grVkCreateDevice(physDev, &deviceInfo, nullptr, &device);
334 if (err) {
335 SkDebugf("CreateDevice failed: %d\n", err);
336 grVkDestroyInstance(inst, nullptr);
337 return false;
338 }
339
340 auto interface =
341 sk_make_sp<GrVkInterface>(getProc, inst, device, extensionFlags);
342 if (!interface->validate(extensionFlags)) {
343 SkDebugf("Vulkan interface validation failed\n");
344 grVkDeviceWaitIdle(device);
345 grVkDestroyDevice(device, nullptr);
346 grVkDestroyInstance(inst, nullptr);
347 return false;
348 }
349
350 VkQueue queue;
351 grVkGetDeviceQueue(device, graphicsQueueIndex, 0, &queue);
352
353 ctx->fInstance = inst;
354 ctx->fPhysicalDevice = physDev;
355 ctx->fDevice = device;
356 ctx->fQueue = queue;
357 ctx->fGraphicsQueueIndex = graphicsQueueIndex;
358 ctx->fMinAPIVersion = kGrVkMinimumVersion;
359 ctx->fExtensions = extensionFlags;
360 ctx->fFeatures = featureFlags;
361 ctx->fInterface.reset(interface.release());
362 ctx->fOwnsInstanceAndDevice = false;
363
364 return true;
365
366
367}
368
Greg Daniel35970ec2017-11-10 10:03:05 -0500369}
370
371#endif