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 // Create the base Vulkan objects needed by the GrVkGpu object
Create(uint32_t * presentQueueIndexPtr,CanPresentFn canPresent)42 const GrVkBackendContext* GrVkBackendContext::Create(uint32_t* presentQueueIndexPtr,
43 CanPresentFn canPresent) {
44 VkPhysicalDevice physDev;
45 VkDevice device;
46 VkInstance inst;
47 VkResult err;
48
49 const VkApplicationInfo app_info = {
50 VK_STRUCTURE_TYPE_APPLICATION_INFO, // sType
51 nullptr, // pNext
52 "vktest", // pApplicationName
53 0, // applicationVersion
54 "vktest", // pEngineName
55 0, // engineVerison
56 kGrVkMinimumVersion, // apiVersion
57 };
58
59 GrVkExtensions extensions;
60 extensions.initInstance(kGrVkMinimumVersion);
61
62 SkTArray<const char*> instanceLayerNames;
63 SkTArray<const char*> instanceExtensionNames;
64 uint32_t extensionFlags = 0;
65 #ifdef SK_ENABLE_VK_LAYERS
66 for (size_t i = 0; i < SK_ARRAY_COUNT(kDebugLayerNames); ++i) {
67 if (extensions.hasInstanceLayer(kDebugLayerNames[i])) {
68 instanceLayerNames.push_back(kDebugLayerNames[i]);
69 }
70 }
71 if (extensions.hasInstanceExtension(VK_EXT_DEBUG_REPORT_EXTENSION_NAME)) {
72 instanceExtensionNames.push_back(VK_EXT_DEBUG_REPORT_EXTENSION_NAME);
73 extensionFlags |= kEXT_debug_report_GrVkExtensionFlag;
74 }
75 #endif
76
77 if (extensions.hasInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME)) {
78 instanceExtensionNames.push_back(VK_KHR_SURFACE_EXTENSION_NAME);
79 extensionFlags |= kKHR_surface_GrVkExtensionFlag;
80 }
81 if (extensions.hasInstanceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME)) {
82 instanceExtensionNames.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
83 extensionFlags |= kKHR_swapchain_GrVkExtensionFlag;
84 }
85 #ifdef SK_BUILD_FOR_WIN
86 if (extensions.hasInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME)) {
87 instanceExtensionNames.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
88 extensionFlags |= kKHR_win32_surface_GrVkExtensionFlag;
89 }
90 #elif defined(SK_BUILD_FOR_ANDROID)
91 if (extensions.hasInstanceExtension(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME)) {
92 instanceExtensionNames.push_back(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME);
93 extensionFlags |= kKHR_android_surface_GrVkExtensionFlag;
94 }
95 #elif defined(SK_BUILD_FOR_UNIX)
96 if (extensions.hasInstanceExtension(VK_KHR_XCB_SURFACE_EXTENSION_NAME)) {
97 instanceExtensionNames.push_back(VK_KHR_XCB_SURFACE_EXTENSION_NAME);
98 extensionFlags |= kKHR_xcb_surface_GrVkExtensionFlag;
99 }
100 #endif
101
102 const VkInstanceCreateInfo instance_create = {
103 VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, // sType
104 nullptr, // pNext
105 0, // flags
106 &app_info, // pApplicationInfo
107 (uint32_t) instanceLayerNames.count(), // enabledLayerNameCount
108 instanceLayerNames.begin(), // ppEnabledLayerNames
109 (uint32_t) instanceExtensionNames.count(), // enabledExtensionNameCount
110 instanceExtensionNames.begin(), // ppEnabledExtensionNames
111 };
112
113 err = vkCreateInstance(&instance_create, nullptr, &inst);
114 if (err < 0) {
115 SkDebugf("vkCreateInstance failed: %d\n", err);
116 return nullptr;
117 }
118
119 uint32_t gpuCount;
120 err = vkEnumeratePhysicalDevices(inst, &gpuCount, nullptr);
121 if (err) {
122 SkDebugf("vkEnumeratePhysicalDevices failed: %d\n", err);
123 vkDestroyInstance(inst, nullptr);
124 return nullptr;
125 }
126 SkASSERT(gpuCount > 0);
127 // Just returning the first physical device instead of getting the whole array.
128 // TODO: find best match for our needs
129 gpuCount = 1;
130 err = vkEnumeratePhysicalDevices(inst, &gpuCount, &physDev);
131 if (err) {
132 SkDebugf("vkEnumeratePhysicalDevices failed: %d\n", err);
133 vkDestroyInstance(inst, nullptr);
134 return nullptr;
135 }
136
137 // query to get the initial queue props size
138 uint32_t queueCount;
139 vkGetPhysicalDeviceQueueFamilyProperties(physDev, &queueCount, nullptr);
140 SkASSERT(queueCount >= 1);
141
142 SkAutoMalloc queuePropsAlloc(queueCount * sizeof(VkQueueFamilyProperties));
143 // now get the actual queue props
144 VkQueueFamilyProperties* queueProps = (VkQueueFamilyProperties*)queuePropsAlloc.get();
145
146 vkGetPhysicalDeviceQueueFamilyProperties(physDev, &queueCount, queueProps);
147
148 // iterate to find the graphics queue
149 uint32_t graphicsQueueIndex = queueCount;
150 for (uint32_t i = 0; i < queueCount; i++) {
151 if (queueProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
152 graphicsQueueIndex = i;
153 break;
154 }
155 }
156 SkASSERT(graphicsQueueIndex < queueCount);
157
158 // iterate to find the present queue, if needed
159 uint32_t presentQueueIndex = graphicsQueueIndex;
160 if (presentQueueIndexPtr && canPresent) {
161 for (uint32_t i = 0; i < queueCount; i++) {
162 if (canPresent(inst, physDev, i)) {
163 presentQueueIndex = i;
164 break;
165 }
166 }
167 SkASSERT(presentQueueIndex < queueCount);
168 *presentQueueIndexPtr = presentQueueIndex;
169 }
170
171 extensions.initDevice(kGrVkMinimumVersion, inst, physDev);
172
173 SkTArray<const char*> deviceLayerNames;
174 SkTArray<const char*> deviceExtensionNames;
175 #ifdef SK_ENABLE_VK_LAYERS
176 for (size_t i = 0; i < SK_ARRAY_COUNT(kDebugLayerNames); ++i) {
177 if (extensions.hasDeviceLayer(kDebugLayerNames[i])) {
178 deviceLayerNames.push_back(kDebugLayerNames[i]);
179 }
180 }
181 #endif
182 if (extensions.hasDeviceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME)) {
183 deviceExtensionNames.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
184 extensionFlags |= kKHR_swapchain_GrVkExtensionFlag;
185 }
186 if (extensions.hasDeviceExtension("VK_NV_glsl_shader")) {
187 deviceExtensionNames.push_back("VK_NV_glsl_shader");
188 extensionFlags |= kNV_glsl_shader_GrVkExtensionFlag;
189 }
190
191 // query to get the physical device properties
192 VkPhysicalDeviceFeatures deviceFeatures;
193 vkGetPhysicalDeviceFeatures(physDev, &deviceFeatures);
194 // this looks like it would slow things down,
195 // and we can't depend on it on all platforms
196 deviceFeatures.robustBufferAccess = VK_FALSE;
197
198 uint32_t featureFlags = 0;
199 if (deviceFeatures.geometryShader) {
200 featureFlags |= kGeometryShader_GrVkFeatureFlag;
201 }
202 if (deviceFeatures.dualSrcBlend) {
203 featureFlags |= kDualSrcBlend_GrVkFeatureFlag;
204 }
205 if (deviceFeatures.sampleRateShading) {
206 featureFlags |= kSampleRateShading_GrVkFeatureFlag;
207 }
208
209 float queuePriorities[1] = { 0.0 };
210 // Here we assume no need for swapchain queue
211 // If one is needed, the client will need its own setup code
212 const VkDeviceQueueCreateInfo queueInfo[2] = {
213 {
214 VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, // sType
215 nullptr, // pNext
216 0, // VkDeviceQueueCreateFlags
217 graphicsQueueIndex, // queueFamilyIndex
218 1, // queueCount
219 queuePriorities, // pQueuePriorities
220 },
221 {
222 VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, // sType
223 nullptr, // pNext
224 0, // VkDeviceQueueCreateFlags
225 presentQueueIndex, // queueFamilyIndex
226 1, // queueCount
227 queuePriorities, // pQueuePriorities
228 }
229 };
230 uint32_t queueInfoCount = (presentQueueIndex != graphicsQueueIndex) ? 2 : 1;
231
232 const VkDeviceCreateInfo deviceInfo = {
233 VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, // sType
234 nullptr, // pNext
235 0, // VkDeviceCreateFlags
236 queueInfoCount, // queueCreateInfoCount
237 queueInfo, // pQueueCreateInfos
238 (uint32_t) deviceLayerNames.count(), // layerCount
239 deviceLayerNames.begin(), // ppEnabledLayerNames
240 (uint32_t) deviceExtensionNames.count(), // extensionCount
241 deviceExtensionNames.begin(), // ppEnabledExtensionNames
242 &deviceFeatures // ppEnabledFeatures
243 };
244
245 err = vkCreateDevice(physDev, &deviceInfo, nullptr, &device);
246 if (err) {
247 SkDebugf("CreateDevice failed: %d\n", err);
248 vkDestroyInstance(inst, nullptr);
249 return nullptr;
250 }
251
252 VkQueue queue;
253 vkGetDeviceQueue(device, graphicsQueueIndex, 0, &queue);
254
255 GrVkBackendContext* ctx = new GrVkBackendContext();
256 ctx->fInstance = inst;
257 ctx->fPhysicalDevice = physDev;
258 ctx->fDevice = device;
259 ctx->fQueue = queue;
260 ctx->fGraphicsQueueIndex = graphicsQueueIndex;
261 ctx->fMinAPIVersion = kGrVkMinimumVersion;
262 ctx->fExtensions = extensionFlags;
263 ctx->fFeatures = featureFlags;
264 ctx->fInterface.reset(GrVkCreateInterface(inst, device, extensionFlags));
265
266 return ctx;
267 }
268
~GrVkBackendContext()269 GrVkBackendContext::~GrVkBackendContext() {
270 vkDeviceWaitIdle(fDevice);
271 vkDestroyDevice(fDevice, nullptr);
272 fDevice = VK_NULL_HANDLE;
273 vkDestroyInstance(fInstance, nullptr);
274 fInstance = VK_NULL_HANDLE;
275 }
276