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