blob: 017d767dc54e8c18cc887ac63c7b1654e4cc5a6c [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); \
Greg Daniel37329b32018-07-02 20:16:44 +000085 if (device != VK_NULL_HANDLE) { \
86 destroy_instance(getProc, inst, debugCallback, hasDebugExtension); \
87 } \
Greg Danielf730c182018-07-02 20:15:37 +000088 return false; \
89 }
90
Greg Daniel37329b32018-07-02 20:16:44 +000091#ifdef SK_ENABLE_VK_LAYERS
92VKAPI_ATTR VkBool32 VKAPI_CALL DebugReportCallback(
93 VkDebugReportFlagsEXT flags,
94 VkDebugReportObjectTypeEXT objectType,
95 uint64_t object,
96 size_t location,
97 int32_t messageCode,
98 const char* pLayerPrefix,
99 const char* pMessage,
100 void* pUserData) {
101 if (flags & VK_DEBUG_REPORT_ERROR_BIT_EXT) {
102 SkDebugf("Vulkan error [%s]: code: %d: %s\n", pLayerPrefix, messageCode, pMessage);
103 return VK_TRUE; // skip further layers
104 } else if (flags & VK_DEBUG_REPORT_WARNING_BIT_EXT) {
105 SkDebugf("Vulkan warning [%s]: code: %d: %s\n", pLayerPrefix, messageCode, pMessage);
106 } else if (flags & VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT) {
107 SkDebugf("Vulkan perf warning [%s]: code: %d: %s\n", pLayerPrefix, messageCode, pMessage);
108 } else {
109 SkDebugf("Vulkan info/debug [%s]: code: %d: %s\n", pLayerPrefix, messageCode, pMessage);
110 }
111 return VK_FALSE;
112}
113#endif
114
115#define ACQUIRE_VK_PROC_LOCAL(name, instance, device) \
116 PFN_vk##name grVk##name = \
117 reinterpret_cast<PFN_vk##name>(getProc("vk" #name, instance, device)); \
118 if (grVk##name == nullptr) { \
119 SkDebugf("Function ptr for vk%s could not be acquired\n", #name); \
120 return; \
121 }
122
123static void destroy_instance(GrVkInterface::GetProc getProc, VkInstance inst,
124 VkDebugReportCallbackEXT* debugCallback,
125 bool hasDebugExtension) {
126 if (hasDebugExtension && *debugCallback != VK_NULL_HANDLE) {
127 ACQUIRE_VK_PROC_LOCAL(DestroyDebugReportCallbackEXT, inst, VK_NULL_HANDLE);
128 grVkDestroyDebugReportCallbackEXT(inst, *debugCallback, nullptr);
129 *debugCallback = VK_NULL_HANDLE;
130 }
131 ACQUIRE_VK_PROC_LOCAL(DestroyInstance, inst, VK_NULL_HANDLE);
132 grVkDestroyInstance(inst, nullptr);
133}
134
Greg Danielf730c182018-07-02 20:15:37 +0000135bool CreateVkBackendContext(const GrVkInterface::GetInstanceProc& getInstanceProc,
136 const GrVkInterface::GetDeviceProc& getDeviceProc,
137 GrVkBackendContext* ctx,
Greg Daniel37329b32018-07-02 20:16:44 +0000138 VkDebugReportCallbackEXT* debugCallback,
Greg Danielf730c182018-07-02 20:15:37 +0000139 uint32_t* presentQueueIndexPtr,
140 CanPresentFn canPresent) {
Greg Danielc8cd45a2018-07-12 10:02:37 -0400141 auto getProc = [getInstanceProc, getDeviceProc](const char* proc_name,
142 VkInstance instance, VkDevice device) {
Greg Danielf730c182018-07-02 20:15:37 +0000143 if (device != VK_NULL_HANDLE) {
144 return getDeviceProc(device, proc_name);
145 }
146 return getInstanceProc(instance, proc_name);
147 };
148
149 VkPhysicalDevice physDev;
150 VkDevice device;
151 VkInstance inst;
152 VkResult err;
153
154 const VkApplicationInfo app_info = {
155 VK_STRUCTURE_TYPE_APPLICATION_INFO, // sType
156 nullptr, // pNext
157 "vktest", // pApplicationName
158 0, // applicationVersion
159 "vktest", // pEngineName
160 0, // engineVerison
161 kGrVkMinimumVersion, // apiVersion
162 };
163
164 GrVkExtensions extensions(getProc);
165 extensions.initInstance(kGrVkMinimumVersion);
166
167 SkTArray<const char*> instanceLayerNames;
168 SkTArray<const char*> instanceExtensionNames;
169 uint32_t extensionFlags = 0;
Greg Daniel37329b32018-07-02 20:16:44 +0000170 bool hasDebugExtension = false;
Greg Danielf730c182018-07-02 20:15:37 +0000171#ifdef SK_ENABLE_VK_LAYERS
172 for (size_t i = 0; i < SK_ARRAY_COUNT(kDebugLayerNames); ++i) {
173 if (extensions.hasInstanceLayer(kDebugLayerNames[i])) {
174 instanceLayerNames.push_back(kDebugLayerNames[i]);
175 }
176 }
177 if (extensions.hasInstanceExtension(VK_EXT_DEBUG_REPORT_EXTENSION_NAME)) {
178 instanceExtensionNames.push_back(VK_EXT_DEBUG_REPORT_EXTENSION_NAME);
179 extensionFlags |= kEXT_debug_report_GrVkExtensionFlag;
Greg Daniel37329b32018-07-02 20:16:44 +0000180 hasDebugExtension = true;
Greg Danielf730c182018-07-02 20:15:37 +0000181 }
182#endif
183
184 if (extensions.hasInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME)) {
185 instanceExtensionNames.push_back(VK_KHR_SURFACE_EXTENSION_NAME);
186 extensionFlags |= kKHR_surface_GrVkExtensionFlag;
187 }
188 if (extensions.hasInstanceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME)) {
189 instanceExtensionNames.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
190 extensionFlags |= kKHR_swapchain_GrVkExtensionFlag;
191 }
192#ifdef SK_BUILD_FOR_WIN
193 if (extensions.hasInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME)) {
194 instanceExtensionNames.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
195 extensionFlags |= kKHR_win32_surface_GrVkExtensionFlag;
196 }
197#elif defined(SK_BUILD_FOR_ANDROID)
198 if (extensions.hasInstanceExtension(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME)) {
199 instanceExtensionNames.push_back(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME);
200 extensionFlags |= kKHR_android_surface_GrVkExtensionFlag;
201 }
202#elif defined(SK_BUILD_FOR_UNIX) && !defined(__Fuchsia__)
203 if (extensions.hasInstanceExtension(VK_KHR_XCB_SURFACE_EXTENSION_NAME)) {
204 instanceExtensionNames.push_back(VK_KHR_XCB_SURFACE_EXTENSION_NAME);
205 extensionFlags |= kKHR_xcb_surface_GrVkExtensionFlag;
206 }
207#endif
208
209 const VkInstanceCreateInfo instance_create = {
210 VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, // sType
211 nullptr, // pNext
212 0, // flags
213 &app_info, // pApplicationInfo
214 (uint32_t) instanceLayerNames.count(), // enabledLayerNameCount
215 instanceLayerNames.begin(), // ppEnabledLayerNames
216 (uint32_t) instanceExtensionNames.count(), // enabledExtensionNameCount
217 instanceExtensionNames.begin(), // ppEnabledExtensionNames
218 };
219
220 ACQUIRE_VK_PROC(CreateInstance, VK_NULL_HANDLE, VK_NULL_HANDLE);
221 err = grVkCreateInstance(&instance_create, nullptr, &inst);
222 if (err < 0) {
223 SkDebugf("vkCreateInstance failed: %d\n", err);
224 return false;
225 }
226
Greg Daniel37329b32018-07-02 20:16:44 +0000227#ifdef SK_ENABLE_VK_LAYERS
228 *debugCallback = VK_NULL_HANDLE;
229 for (int i = 0; i < instanceExtensionNames.count() && !hasDebugExtension; ++i) {
230 if (!strcmp(instanceExtensionNames[i], VK_EXT_DEBUG_REPORT_EXTENSION_NAME)) {
231 hasDebugExtension = true;
232 }
233 }
234 if (hasDebugExtension) {
235 // Setup callback creation information
236 VkDebugReportCallbackCreateInfoEXT callbackCreateInfo;
237 callbackCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT;
238 callbackCreateInfo.pNext = nullptr;
239 callbackCreateInfo.flags = VK_DEBUG_REPORT_ERROR_BIT_EXT |
240 VK_DEBUG_REPORT_WARNING_BIT_EXT |
241 // VK_DEBUG_REPORT_INFORMATION_BIT_EXT |
242 // VK_DEBUG_REPORT_DEBUG_BIT_EXT |
243 VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT;
244 callbackCreateInfo.pfnCallback = &DebugReportCallback;
245 callbackCreateInfo.pUserData = nullptr;
246
247 ACQUIRE_VK_PROC(CreateDebugReportCallbackEXT, inst, VK_NULL_HANDLE);
248 // Register the callback
249 grVkCreateDebugReportCallbackEXT(inst, &callbackCreateInfo, nullptr, debugCallback);
250 }
251#endif
252
Greg Danielf730c182018-07-02 20:15:37 +0000253 ACQUIRE_VK_PROC(DestroyInstance, inst, VK_NULL_HANDLE);
254 ACQUIRE_VK_PROC(EnumeratePhysicalDevices, inst, VK_NULL_HANDLE);
255 ACQUIRE_VK_PROC(GetPhysicalDeviceQueueFamilyProperties, inst, VK_NULL_HANDLE);
256 ACQUIRE_VK_PROC(GetPhysicalDeviceFeatures, inst, VK_NULL_HANDLE);
257 ACQUIRE_VK_PROC(CreateDevice, inst, VK_NULL_HANDLE);
258 ACQUIRE_VK_PROC(GetDeviceQueue, inst, VK_NULL_HANDLE);
259 ACQUIRE_VK_PROC(DeviceWaitIdle, inst, VK_NULL_HANDLE);
260 ACQUIRE_VK_PROC(DestroyDevice, inst, VK_NULL_HANDLE);
261
262 uint32_t gpuCount;
263 err = grVkEnumeratePhysicalDevices(inst, &gpuCount, nullptr);
264 if (err) {
265 SkDebugf("vkEnumeratePhysicalDevices failed: %d\n", err);
Greg Daniel37329b32018-07-02 20:16:44 +0000266 destroy_instance(getProc, inst, debugCallback, hasDebugExtension);
Greg Danielf730c182018-07-02 20:15:37 +0000267 return false;
268 }
269 if (!gpuCount) {
270 SkDebugf("vkEnumeratePhysicalDevices returned no supported devices.\n");
Greg Daniel37329b32018-07-02 20:16:44 +0000271 destroy_instance(getProc, inst, debugCallback, hasDebugExtension);
Greg Danielf730c182018-07-02 20:15:37 +0000272 return false;
273 }
274 // Just returning the first physical device instead of getting the whole array.
275 // TODO: find best match for our needs
276 gpuCount = 1;
277 err = grVkEnumeratePhysicalDevices(inst, &gpuCount, &physDev);
278 // VK_INCOMPLETE is returned when the count we provide is less than the total device count.
279 if (err && VK_INCOMPLETE != err) {
280 SkDebugf("vkEnumeratePhysicalDevices failed: %d\n", err);
Greg Daniel37329b32018-07-02 20:16:44 +0000281 destroy_instance(getProc, inst, debugCallback, hasDebugExtension);
Greg Danielf730c182018-07-02 20:15:37 +0000282 return false;
283 }
284
285 // query to get the initial queue props size
286 uint32_t queueCount;
287 grVkGetPhysicalDeviceQueueFamilyProperties(physDev, &queueCount, nullptr);
288 if (!queueCount) {
289 SkDebugf("vkGetPhysicalDeviceQueueFamilyProperties returned no queues.\n");
Greg Daniel37329b32018-07-02 20:16:44 +0000290 destroy_instance(getProc, inst, debugCallback, hasDebugExtension);
Greg Danielf730c182018-07-02 20:15:37 +0000291 return false;
292 }
293
294 SkAutoMalloc queuePropsAlloc(queueCount * sizeof(VkQueueFamilyProperties));
295 // now get the actual queue props
296 VkQueueFamilyProperties* queueProps = (VkQueueFamilyProperties*)queuePropsAlloc.get();
297
298 grVkGetPhysicalDeviceQueueFamilyProperties(physDev, &queueCount, queueProps);
299
300 // iterate to find the graphics queue
301 uint32_t graphicsQueueIndex = queueCount;
302 for (uint32_t i = 0; i < queueCount; i++) {
303 if (queueProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
304 graphicsQueueIndex = i;
305 break;
306 }
307 }
308 if (graphicsQueueIndex == queueCount) {
309 SkDebugf("Could not find any supported graphics queues.\n");
Greg Daniel37329b32018-07-02 20:16:44 +0000310 destroy_instance(getProc, inst, debugCallback, hasDebugExtension);
Greg Danielf730c182018-07-02 20:15:37 +0000311 return false;
312 }
313
314 // iterate to find the present queue, if needed
315 uint32_t presentQueueIndex = queueCount;
316 if (presentQueueIndexPtr && canPresent) {
317 for (uint32_t i = 0; i < queueCount; i++) {
318 if (canPresent(inst, physDev, i)) {
319 presentQueueIndex = i;
320 break;
321 }
322 }
323 if (presentQueueIndex == queueCount) {
324 SkDebugf("Could not find any supported present queues.\n");
Greg Daniel37329b32018-07-02 20:16:44 +0000325 destroy_instance(getProc, inst, debugCallback, hasDebugExtension);
Greg Danielf730c182018-07-02 20:15:37 +0000326 return false;
327 }
328 *presentQueueIndexPtr = presentQueueIndex;
329 } else {
330 // Just setting this so we end up make a single queue for graphics since there was no
331 // request for a present queue.
332 presentQueueIndex = graphicsQueueIndex;
333 }
334
335 extensions.initDevice(kGrVkMinimumVersion, inst, physDev);
336
337 SkTArray<const char*> deviceLayerNames;
338 SkTArray<const char*> deviceExtensionNames;
Greg Danielf730c182018-07-02 20:15:37 +0000339 if (extensions.hasDeviceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME)) {
340 deviceExtensionNames.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
341 extensionFlags |= kKHR_swapchain_GrVkExtensionFlag;
342 }
343 if (extensions.hasDeviceExtension("VK_NV_glsl_shader")) {
344 deviceExtensionNames.push_back("VK_NV_glsl_shader");
345 extensionFlags |= kNV_glsl_shader_GrVkExtensionFlag;
346 }
347
348 // query to get the physical device properties
349 VkPhysicalDeviceFeatures deviceFeatures;
350 grVkGetPhysicalDeviceFeatures(physDev, &deviceFeatures);
351 // this looks like it would slow things down,
352 // and we can't depend on it on all platforms
353 deviceFeatures.robustBufferAccess = VK_FALSE;
354
355 uint32_t featureFlags = 0;
356 if (deviceFeatures.geometryShader) {
357 featureFlags |= kGeometryShader_GrVkFeatureFlag;
358 }
359 if (deviceFeatures.dualSrcBlend) {
360 featureFlags |= kDualSrcBlend_GrVkFeatureFlag;
361 }
362 if (deviceFeatures.sampleRateShading) {
363 featureFlags |= kSampleRateShading_GrVkFeatureFlag;
364 }
365
366 float queuePriorities[1] = { 0.0 };
367 // Here we assume no need for swapchain queue
368 // If one is needed, the client will need its own setup code
369 const VkDeviceQueueCreateInfo queueInfo[2] = {
370 {
371 VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, // sType
372 nullptr, // pNext
373 0, // VkDeviceQueueCreateFlags
374 graphicsQueueIndex, // queueFamilyIndex
375 1, // queueCount
376 queuePriorities, // pQueuePriorities
377 },
378 {
379 VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, // sType
380 nullptr, // pNext
381 0, // VkDeviceQueueCreateFlags
382 presentQueueIndex, // queueFamilyIndex
383 1, // queueCount
384 queuePriorities, // pQueuePriorities
385 }
386 };
387 uint32_t queueInfoCount = (presentQueueIndex != graphicsQueueIndex) ? 2 : 1;
388
389 const VkDeviceCreateInfo deviceInfo = {
390 VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, // sType
391 nullptr, // pNext
392 0, // VkDeviceCreateFlags
393 queueInfoCount, // queueCreateInfoCount
394 queueInfo, // pQueueCreateInfos
395 (uint32_t) deviceLayerNames.count(), // layerCount
396 deviceLayerNames.begin(), // ppEnabledLayerNames
397 (uint32_t) deviceExtensionNames.count(), // extensionCount
398 deviceExtensionNames.begin(), // ppEnabledExtensionNames
399 &deviceFeatures // ppEnabledFeatures
400 };
401
402 err = grVkCreateDevice(physDev, &deviceInfo, nullptr, &device);
403 if (err) {
404 SkDebugf("CreateDevice failed: %d\n", err);
Greg Daniel37329b32018-07-02 20:16:44 +0000405 destroy_instance(getProc, inst, debugCallback, hasDebugExtension);
Greg Danielf730c182018-07-02 20:15:37 +0000406 return false;
407 }
408
Greg Danielf730c182018-07-02 20:15:37 +0000409 VkQueue queue;
410 grVkGetDeviceQueue(device, graphicsQueueIndex, 0, &queue);
411
412 ctx->fInstance = inst;
413 ctx->fPhysicalDevice = physDev;
414 ctx->fDevice = device;
415 ctx->fQueue = queue;
416 ctx->fGraphicsQueueIndex = graphicsQueueIndex;
417 ctx->fMinAPIVersion = kGrVkMinimumVersion;
418 ctx->fExtensions = extensionFlags;
419 ctx->fFeatures = featureFlags;
Greg Danielc8cd45a2018-07-12 10:02:37 -0400420 ctx->fInterface = nullptr;
421 ctx->fGetProc = getProc;
Greg Danielf730c182018-07-02 20:15:37 +0000422 ctx->fOwnsInstanceAndDevice = false;
423
424 return true;
Greg Danielf730c182018-07-02 20:15:37 +0000425}
426
Greg Daniel35970ec2017-11-10 10:03:05 -0500427}
428
429#endif