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