blob: e4731782233785da1bf3a823cedcdc41e708769e [file] [log] [blame]
jvanverth633b3562016-03-23 11:01:22 -07001/*
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
Hal Canary95e3c052017-01-11 12:44:43 -05008#include "SkAutoMalloc.h"
jvanverth633b3562016-03-23 11:01:22 -07009#include "vk/GrVkBackendContext.h"
jvanverthfd7bd452016-03-25 06:29:52 -070010#include "vk/GrVkExtensions.h"
jvanverth633b3562016-03-23 11:01:22 -070011#include "vk/GrVkInterface.h"
12#include "vk/GrVkUtil.h"
13
14////////////////////////////////////////////////////////////////////////////////
15// Helper code to set up Vulkan context objects
16
egdaniel735109c2016-07-27 08:03:57 -070017#ifdef SK_ENABLE_VK_LAYERS
jvanverthfd7bd452016-03-25 06:29:52 -070018const char* kDebugLayerNames[] = {
jvanverth633b3562016-03-23 11:01:22 -070019 // elements of VK_LAYER_LUNARG_standard_validation
egdaniel58a8d922016-04-21 08:03:10 -070020 "VK_LAYER_GOOGLE_threading",
21 "VK_LAYER_LUNARG_parameter_validation",
jvanverth633b3562016-03-23 11:01:22 -070022 "VK_LAYER_LUNARG_object_tracker",
23 "VK_LAYER_LUNARG_image",
egdaniel58a8d922016-04-21 08:03:10 -070024 "VK_LAYER_LUNARG_core_validation",
jvanverth633b3562016-03-23 11:01:22 -070025 "VK_LAYER_LUNARG_swapchain",
egdaniel58a8d922016-04-21 08:03:10 -070026 "VK_LAYER_GOOGLE_unique_objects",
jvanverth633b3562016-03-23 11:01:22 -070027 // not included in standard_validation
28 //"VK_LAYER_LUNARG_api_dump",
jvanverthfd7bd452016-03-25 06:29:52 -070029 //"VK_LAYER_LUNARG_vktrace",
30 //"VK_LAYER_LUNARG_screenshot",
jvanverth633b3562016-03-23 11:01:22 -070031};
jvanverth633b3562016-03-23 11:01:22 -070032#endif
33
jvanverthfd7bd452016-03-25 06:29:52 -070034// the minimum version of Vulkan supported
liyuqianb138fdc2016-04-29 10:00:26 -070035#ifdef SK_BUILD_FOR_ANDROID
36const uint32_t kGrVkMinimumVersion = VK_MAKE_VERSION(1, 0, 3);
37#else
egdaniel58a8d922016-04-21 08:03:10 -070038const uint32_t kGrVkMinimumVersion = VK_MAKE_VERSION(1, 0, 8);
liyuqianb138fdc2016-04-29 10:00:26 -070039#endif
jvanverthfd7bd452016-03-25 06:29:52 -070040
Michael Jurka3251ed82017-04-05 09:52:55 -070041#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
jvanverth633b3562016-03-23 11:01:22 -070049// Create the base Vulkan objects needed by the GrVkGpu object
jvanverthb0d43522016-04-21 11:46:23 -070050const GrVkBackendContext* GrVkBackendContext::Create(uint32_t* presentQueueIndexPtr,
Michael Jurka3251ed82017-04-05 09:52:55 -070051 CanPresentFn canPresent,
52 GrVkInterface::GetProc getProc) {
Brian Salomoncc901742017-04-25 13:28:45 -040053 if (!getProc) {
Brian Salomoncc901742017-04-25 13:28:45 -040054 return nullptr;
Brian Salomoncc901742017-04-25 13:28:45 -040055 }
56 SkASSERT(getProc);
Michael Jurka3251ed82017-04-05 09:52:55 -070057
jvanverth633b3562016-03-23 11:01:22 -070058 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
Michael Jurka3251ed82017-04-05 09:52:55 -070073 GrVkExtensions extensions(getProc);
jvanverthfd7bd452016-03-25 06:29:52 -070074 extensions.initInstance(kGrVkMinimumVersion);
75
76 SkTArray<const char*> instanceLayerNames;
77 SkTArray<const char*> instanceExtensionNames;
78 uint32_t extensionFlags = 0;
egdaniel735109c2016-07-27 08:03:57 -070079#ifdef SK_ENABLE_VK_LAYERS
ethannicholas384b5e92016-03-25 11:04:06 -070080 for (size_t i = 0; i < SK_ARRAY_COUNT(kDebugLayerNames); ++i) {
jvanverthfd7bd452016-03-25 06:29:52 -070081 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;
jvanverth633b3562016-03-23 11:01:22 -070088 }
jvanverth9f372462016-04-06 06:08:59 -070089#endif
90
jvanverthe50f3e72016-03-28 07:03:06 -070091 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 }
djsollen7e731082016-06-09 13:07:13 -0700104#elif defined(SK_BUILD_FOR_ANDROID)
jvanverthe50f3e72016-03-28 07:03:06 -0700105 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;
jvanverth1d155962016-05-23 13:13:36 -0700108 }
Michael Jurka3251ed82017-04-05 09:52:55 -0700109#elif defined(SK_BUILD_FOR_UNIX) && !defined(__Fuchsia__)
jvanverth1d155962016-05-23 13:13:36 -0700110 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;
jvanverthe50f3e72016-03-28 07:03:06 -0700113 }
114#endif
jvanverth633b3562016-03-23 11:01:22 -0700115
116 const VkInstanceCreateInfo instance_create = {
ethannicholas384b5e92016-03-25 11:04:06 -0700117 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
jvanverth633b3562016-03-23 11:01:22 -0700125 };
126
Michael Jurka3251ed82017-04-05 09:52:55 -0700127 ACQUIRE_VK_PROC(CreateInstance, VK_NULL_HANDLE, VK_NULL_HANDLE);
128 err = grVkCreateInstance(&instance_create, nullptr, &inst);
jvanverth633b3562016-03-23 11:01:22 -0700129 if (err < 0) {
130 SkDebugf("vkCreateInstance failed: %d\n", err);
bsalomondc0fcd42016-04-11 14:21:33 -0700131 return nullptr;
jvanverth633b3562016-03-23 11:01:22 -0700132 }
133
Michael Jurka3251ed82017-04-05 09:52:55 -0700134 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
jvanverth633b3562016-03-23 11:01:22 -0700143 uint32_t gpuCount;
Michael Jurka3251ed82017-04-05 09:52:55 -0700144 err = grVkEnumeratePhysicalDevices(inst, &gpuCount, nullptr);
jvanverth633b3562016-03-23 11:01:22 -0700145 if (err) {
146 SkDebugf("vkEnumeratePhysicalDevices failed: %d\n", err);
Michael Jurka3251ed82017-04-05 09:52:55 -0700147 grVkDestroyInstance(inst, nullptr);
bsalomondc0fcd42016-04-11 14:21:33 -0700148 return nullptr;
jvanverth633b3562016-03-23 11:01:22 -0700149 }
Greg Daniela41d48b2017-04-27 12:57:59 -0400150 if (!gpuCount) {
151 SkDebugf("vkEnumeratePhysicalDevices returned no supported devices.\n");
152 grVkDestroyInstance(inst, nullptr);
153 return nullptr;
154 }
jvanverth633b3562016-03-23 11:01:22 -0700155 // Just returning the first physical device instead of getting the whole array.
156 // TODO: find best match for our needs
157 gpuCount = 1;
Michael Jurka3251ed82017-04-05 09:52:55 -0700158 err = grVkEnumeratePhysicalDevices(inst, &gpuCount, &physDev);
jvanverth633b3562016-03-23 11:01:22 -0700159 if (err) {
160 SkDebugf("vkEnumeratePhysicalDevices failed: %d\n", err);
Michael Jurka3251ed82017-04-05 09:52:55 -0700161 grVkDestroyInstance(inst, nullptr);
bsalomondc0fcd42016-04-11 14:21:33 -0700162 return nullptr;
jvanverth633b3562016-03-23 11:01:22 -0700163 }
164
165 // query to get the initial queue props size
166 uint32_t queueCount;
Michael Jurka3251ed82017-04-05 09:52:55 -0700167 grVkGetPhysicalDeviceQueueFamilyProperties(physDev, &queueCount, nullptr);
Greg Daniela41d48b2017-04-27 12:57:59 -0400168 if (!queueCount) {
169 SkDebugf("vkGetPhysicalDeviceQueueFamilyProperties returned no queues.\n");
170 grVkDestroyInstance(inst, nullptr);
171 return nullptr;
172 }
jvanverth633b3562016-03-23 11:01:22 -0700173
174 SkAutoMalloc queuePropsAlloc(queueCount * sizeof(VkQueueFamilyProperties));
175 // now get the actual queue props
176 VkQueueFamilyProperties* queueProps = (VkQueueFamilyProperties*)queuePropsAlloc.get();
177
Michael Jurka3251ed82017-04-05 09:52:55 -0700178 grVkGetPhysicalDeviceQueueFamilyProperties(physDev, &queueCount, queueProps);
jvanverth633b3562016-03-23 11:01:22 -0700179
180 // iterate to find the graphics queue
jvanverthb0d43522016-04-21 11:46:23 -0700181 uint32_t graphicsQueueIndex = queueCount;
jvanverth633b3562016-03-23 11:01:22 -0700182 for (uint32_t i = 0; i < queueCount; i++) {
183 if (queueProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
184 graphicsQueueIndex = i;
185 break;
186 }
187 }
Greg Daniela41d48b2017-04-27 12:57:59 -0400188 if (graphicsQueueIndex == queueCount) {
189 SkDebugf("Could not find any supported graphics queues.\n");
190 grVkDestroyInstance(inst, nullptr);
191 return nullptr;
192 }
jvanverth633b3562016-03-23 11:01:22 -0700193
jvanverthb0d43522016-04-21 11:46:23 -0700194 // iterate to find the present queue, if needed
Greg Daniela41d48b2017-04-27 12:57:59 -0400195 uint32_t presentQueueIndex = queueCount;
jvanverthb0d43522016-04-21 11:46:23 -0700196 if (presentQueueIndexPtr && canPresent) {
197 for (uint32_t i = 0; i < queueCount; i++) {
bsalomond1bdd1f2016-07-26 12:02:50 -0700198 if (canPresent(inst, physDev, i)) {
jvanverthb0d43522016-04-21 11:46:23 -0700199 presentQueueIndex = i;
200 break;
201 }
202 }
Greg Daniela41d48b2017-04-27 12:57:59 -0400203 if (presentQueueIndex == queueCount) {
204 SkDebugf("Could not find any supported present queues.\n");
205 grVkDestroyInstance(inst, nullptr);
206 return nullptr;
207 }
jvanverthb0d43522016-04-21 11:46:23 -0700208 *presentQueueIndexPtr = presentQueueIndex;
Greg Daniela41d48b2017-04-27 12:57:59 -0400209 } 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;
jvanverthb0d43522016-04-21 11:46:23 -0700213 }
214
jvanverthfd7bd452016-03-25 06:29:52 -0700215 extensions.initDevice(kGrVkMinimumVersion, inst, physDev);
216
217 SkTArray<const char*> deviceLayerNames;
218 SkTArray<const char*> deviceExtensionNames;
egdaniel735109c2016-07-27 08:03:57 -0700219#ifdef SK_ENABLE_VK_LAYERS
ethannicholas384b5e92016-03-25 11:04:06 -0700220 for (size_t i = 0; i < SK_ARRAY_COUNT(kDebugLayerNames); ++i) {
jvanverthfd7bd452016-03-25 06:29:52 -0700221 if (extensions.hasDeviceLayer(kDebugLayerNames[i])) {
222 deviceLayerNames.push_back(kDebugLayerNames[i]);
223 }
jvanverth633b3562016-03-23 11:01:22 -0700224 }
225#endif
jvanverth9f372462016-04-06 06:08:59 -0700226 if (extensions.hasDeviceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME)) {
227 deviceExtensionNames.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
228 extensionFlags |= kKHR_swapchain_GrVkExtensionFlag;
229 }
jvanverthfd7bd452016-03-25 06:29:52 -0700230 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;
Michael Jurka3251ed82017-04-05 09:52:55 -0700237 grVkGetPhysicalDeviceFeatures(physDev, &deviceFeatures);
halcanary9d524f22016-03-29 09:03:52 -0700238 // this looks like it would slow things down,
jvanverthfd7bd452016-03-25 06:29:52 -0700239 // 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 }
jvanverth633b3562016-03-23 11:01:22 -0700252
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
jvanverthb0d43522016-04-21 11:46:23 -0700256 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 }
jvanverth633b3562016-03-23 11:01:22 -0700273 };
jvanverthb0d43522016-04-21 11:46:23 -0700274 uint32_t queueInfoCount = (presentQueueIndex != graphicsQueueIndex) ? 2 : 1;
275
jvanverth633b3562016-03-23 11:01:22 -0700276 const VkDeviceCreateInfo deviceInfo = {
ethannicholas384b5e92016-03-25 11:04:06 -0700277 VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, // sType
278 nullptr, // pNext
279 0, // VkDeviceCreateFlags
jvanverthb0d43522016-04-21 11:46:23 -0700280 queueInfoCount, // queueCreateInfoCount
281 queueInfo, // pQueueCreateInfos
ethannicholas384b5e92016-03-25 11:04:06 -0700282 (uint32_t) deviceLayerNames.count(), // layerCount
283 deviceLayerNames.begin(), // ppEnabledLayerNames
284 (uint32_t) deviceExtensionNames.count(), // extensionCount
285 deviceExtensionNames.begin(), // ppEnabledExtensionNames
286 &deviceFeatures // ppEnabledFeatures
jvanverth633b3562016-03-23 11:01:22 -0700287 };
288
Michael Jurka3251ed82017-04-05 09:52:55 -0700289 err = grVkCreateDevice(physDev, &deviceInfo, nullptr, &device);
jvanverth633b3562016-03-23 11:01:22 -0700290 if (err) {
291 SkDebugf("CreateDevice failed: %d\n", err);
Michael Jurka3251ed82017-04-05 09:52:55 -0700292 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);
jvanverth633b3562016-03-23 11:01:22 -0700303 return nullptr;
304 }
305
306 VkQueue queue;
Michael Jurka3251ed82017-04-05 09:52:55 -0700307 grVkGetDeviceQueue(device, graphicsQueueIndex, 0, &queue);
jvanverth633b3562016-03-23 11:01:22 -0700308
309 GrVkBackendContext* ctx = new GrVkBackendContext();
310 ctx->fInstance = inst;
311 ctx->fPhysicalDevice = physDev;
312 ctx->fDevice = device;
313 ctx->fQueue = queue;
jvanverthb0d43522016-04-21 11:46:23 -0700314 ctx->fGraphicsQueueIndex = graphicsQueueIndex;
jvanverthfd7bd452016-03-25 06:29:52 -0700315 ctx->fMinAPIVersion = kGrVkMinimumVersion;
316 ctx->fExtensions = extensionFlags;
317 ctx->fFeatures = featureFlags;
Michael Jurka3251ed82017-04-05 09:52:55 -0700318 ctx->fInterface.reset(interface.release());
Brian Salomon290c6902017-04-25 15:03:41 -0400319 ctx->fOwnsInstanceAndDevice = true;
halcanary9d524f22016-03-29 09:03:52 -0700320
jvanverth633b3562016-03-23 11:01:22 -0700321 return ctx;
322}
323
324GrVkBackendContext::~GrVkBackendContext() {
Brian Salomon290c6902017-04-25 15:03:41 -0400325 if (fInterface == nullptr || !fOwnsInstanceAndDevice) {
Michael Jurka3251ed82017-04-05 09:52:55 -0700326 return;
327 }
328
329 fInterface->fFunctions.fDeviceWaitIdle(fDevice);
330 fInterface->fFunctions.fDestroyDevice(fDevice, nullptr);
jvanverth633b3562016-03-23 11:01:22 -0700331 fDevice = VK_NULL_HANDLE;
Michael Jurka3251ed82017-04-05 09:52:55 -0700332 fInterface->fFunctions.fDestroyInstance(fInstance, nullptr);
jvanverth633b3562016-03-23 11:01:22 -0700333 fInstance = VK_NULL_HANDLE;
334}