1 // Copyright 2019 The Amber Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "samples/config_helper_vulkan.h"
16
17 #include <vulkan/vulkan.h>
18
19 #include <algorithm>
20 #include <cstring>
21 #include <iostream>
22 #include <iterator>
23 #include <set>
24 #include <sstream>
25
26 #include "samples/log.h"
27
28 namespace sample {
29 namespace {
30
31 const char* const kRequiredValidationLayers[] = {
32 #ifdef __ANDROID__
33 // Note that the order of enabled layers is important. It is
34 // based on Android NDK Vulkan document.
35 "VK_LAYER_GOOGLE_threading", "VK_LAYER_LUNARG_parameter_validation",
36 "VK_LAYER_LUNARG_object_tracker", "VK_LAYER_LUNARG_core_validation",
37 "VK_LAYER_GOOGLE_unique_objects",
38 #else // __ANDROID__
39 "VK_LAYER_LUNARG_standard_validation",
40 #endif // __ANDROID__
41 };
42
43 const size_t kNumberOfRequiredValidationLayers =
44 sizeof(kRequiredValidationLayers) / sizeof(const char*);
45
46 const char kVariablePointers[] = "VariablePointerFeatures.variablePointers";
47 const char kVariablePointersStorageBuffer[] =
48 "VariablePointerFeatures.variablePointersStorageBuffer";
49
50 const char kExtensionForValidationLayer[] = "VK_EXT_debug_report";
51
debugCallback(VkDebugReportFlagsEXT flag,VkDebugReportObjectTypeEXT,uint64_t,size_t,int32_t,const char * layerPrefix,const char * msg,void *)52 VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(VkDebugReportFlagsEXT flag,
53 VkDebugReportObjectTypeEXT,
54 uint64_t,
55 size_t,
56 int32_t,
57 const char* layerPrefix,
58 const char* msg,
59 void*) {
60 std::string flag_message;
61 switch (flag) {
62 case VK_DEBUG_REPORT_ERROR_BIT_EXT:
63 flag_message = "[ERROR]";
64 break;
65 case VK_DEBUG_REPORT_WARNING_BIT_EXT:
66 flag_message = "[WARNING]";
67 break;
68 default:
69 flag_message = "[UNKNOWN]";
70 break;
71 }
72
73 LogError(flag_message + " validation layer (" + layerPrefix + "):\n" + msg);
74 return VK_FALSE;
75 }
76
77 // Convert required features given as a string array to
78 // VkPhysicalDeviceFeatures.
NamesToVulkanFeatures(const std::vector<std::string> & required_feature_names,VkPhysicalDeviceFeatures * features)79 amber::Result NamesToVulkanFeatures(
80 const std::vector<std::string>& required_feature_names,
81 VkPhysicalDeviceFeatures* features) {
82 for (const auto& name : required_feature_names) {
83 if (name == "robustBufferAccess") {
84 features->robustBufferAccess = VK_TRUE;
85 } else if (name == "fullDrawIndexUint32") {
86 features->fullDrawIndexUint32 = VK_TRUE;
87 } else if (name == "imageCubeArray") {
88 features->imageCubeArray = VK_TRUE;
89 } else if (name == "independentBlend") {
90 features->independentBlend = VK_TRUE;
91 } else if (name == "geometryShader") {
92 features->geometryShader = VK_TRUE;
93 } else if (name == "tessellationShader") {
94 features->tessellationShader = VK_TRUE;
95 } else if (name == "sampleRateShading") {
96 features->sampleRateShading = VK_TRUE;
97 } else if (name == "dualSrcBlend") {
98 features->dualSrcBlend = VK_TRUE;
99 } else if (name == "logicOp") {
100 features->logicOp = VK_TRUE;
101 } else if (name == "multiDrawIndirect") {
102 features->multiDrawIndirect = VK_TRUE;
103 } else if (name == "drawIndirectFirstInstance") {
104 features->drawIndirectFirstInstance = VK_TRUE;
105 } else if (name == "depthClamp") {
106 features->depthClamp = VK_TRUE;
107 } else if (name == "depthBiasClamp") {
108 features->depthBiasClamp = VK_TRUE;
109 } else if (name == "fillModeNonSolid") {
110 features->fillModeNonSolid = VK_TRUE;
111 } else if (name == "depthBounds") {
112 features->depthBounds = VK_TRUE;
113 } else if (name == "wideLines") {
114 features->wideLines = VK_TRUE;
115 } else if (name == "largePoints") {
116 features->largePoints = VK_TRUE;
117 } else if (name == "alphaToOne") {
118 features->alphaToOne = VK_TRUE;
119 } else if (name == "multiViewport") {
120 features->multiViewport = VK_TRUE;
121 } else if (name == "samplerAnisotropy") {
122 features->samplerAnisotropy = VK_TRUE;
123 } else if (name == "textureCompressionETC2") {
124 features->textureCompressionETC2 = VK_TRUE;
125 } else if (name == "textureCompressionASTC_LDR") {
126 features->textureCompressionASTC_LDR = VK_TRUE;
127 } else if (name == "textureCompressionBC") {
128 features->textureCompressionBC = VK_TRUE;
129 } else if (name == "occlusionQueryPrecise") {
130 features->occlusionQueryPrecise = VK_TRUE;
131 } else if (name == "pipelineStatisticsQuery") {
132 features->pipelineStatisticsQuery = VK_TRUE;
133 } else if (name == "vertexPipelineStoresAndAtomics") {
134 features->vertexPipelineStoresAndAtomics = VK_TRUE;
135 } else if (name == "fragmentStoresAndAtomics") {
136 features->fragmentStoresAndAtomics = VK_TRUE;
137 } else if (name == "shaderTessellationAndGeometryPointSize") {
138 features->shaderTessellationAndGeometryPointSize = VK_TRUE;
139 } else if (name == "shaderImageGatherExtended") {
140 features->shaderImageGatherExtended = VK_TRUE;
141 } else if (name == "shaderStorageImageExtendedFormats") {
142 features->shaderStorageImageExtendedFormats = VK_TRUE;
143 } else if (name == "shaderStorageImageMultisample") {
144 features->shaderStorageImageMultisample = VK_TRUE;
145 } else if (name == "shaderStorageImageReadWithoutFormat") {
146 features->shaderStorageImageReadWithoutFormat = VK_TRUE;
147 } else if (name == "shaderStorageImageWriteWithoutFormat") {
148 features->shaderStorageImageWriteWithoutFormat = VK_TRUE;
149 } else if (name == "shaderUniformBufferArrayDynamicIndexing") {
150 features->shaderUniformBufferArrayDynamicIndexing = VK_TRUE;
151 } else if (name == "shaderSampledImageArrayDynamicIndexing") {
152 features->shaderSampledImageArrayDynamicIndexing = VK_TRUE;
153 } else if (name == "shaderStorageBufferArrayDynamicIndexing") {
154 features->shaderStorageBufferArrayDynamicIndexing = VK_TRUE;
155 } else if (name == "shaderStorageImageArrayDynamicIndexing") {
156 features->shaderStorageImageArrayDynamicIndexing = VK_TRUE;
157 } else if (name == "shaderClipDistance") {
158 features->shaderClipDistance = VK_TRUE;
159 } else if (name == "shaderCullDistance") {
160 features->shaderCullDistance = VK_TRUE;
161 } else if (name == "shaderFloat64") {
162 features->shaderFloat64 = VK_TRUE;
163 } else if (name == "shaderInt64") {
164 features->shaderInt64 = VK_TRUE;
165 } else if (name == "shaderInt16") {
166 features->shaderInt16 = VK_TRUE;
167 } else if (name == "shaderResourceResidency") {
168 features->shaderResourceResidency = VK_TRUE;
169 } else if (name == "shaderResourceMinLod") {
170 features->shaderResourceMinLod = VK_TRUE;
171 } else if (name == "sparseBinding") {
172 features->sparseBinding = VK_TRUE;
173 } else if (name == "sparseResidencyBuffer") {
174 features->sparseResidencyBuffer = VK_TRUE;
175 } else if (name == "sparseResidencyImage2D") {
176 features->sparseResidencyImage2D = VK_TRUE;
177 } else if (name == "sparseResidencyImage3D") {
178 features->sparseResidencyImage3D = VK_TRUE;
179 } else if (name == "sparseResidency2Samples") {
180 features->sparseResidency2Samples = VK_TRUE;
181 } else if (name == "sparseResidency4Samples") {
182 features->sparseResidency4Samples = VK_TRUE;
183 } else if (name == "sparseResidency8Samples") {
184 features->sparseResidency8Samples = VK_TRUE;
185 } else if (name == "sparseResidency16Samples") {
186 features->sparseResidency16Samples = VK_TRUE;
187 } else if (name == "sparseResidencyAliased") {
188 features->sparseResidencyAliased = VK_TRUE;
189 } else if (name == "variableMultisampleRate") {
190 features->variableMultisampleRate = VK_TRUE;
191 } else if (name == "inheritedQueries") {
192 features->inheritedQueries = VK_TRUE;
193 } else {
194 return amber::Result("Sample: Unknown Vulkan feature: " + name);
195 }
196 }
197 return {};
198 }
199
AreAllValidationLayersSupported()200 bool AreAllValidationLayersSupported() {
201 std::vector<VkLayerProperties> available_layer_properties;
202 uint32_t available_layer_count = 0;
203 if (vkEnumerateInstanceLayerProperties(&available_layer_count, nullptr) !=
204 VK_SUCCESS) {
205 return false;
206 }
207 available_layer_properties.resize(available_layer_count);
208 if (vkEnumerateInstanceLayerProperties(&available_layer_count,
209 available_layer_properties.data()) !=
210 VK_SUCCESS) {
211 return false;
212 }
213
214 std::set<std::string> required_layer_set(
215 kRequiredValidationLayers,
216 &kRequiredValidationLayers[kNumberOfRequiredValidationLayers]);
217 for (const auto& property : available_layer_properties) {
218 required_layer_set.erase(property.layerName);
219 }
220
221 if (required_layer_set.empty())
222 return true;
223
224 std::string missing_layers;
225 for (const auto& missing_layer : required_layer_set)
226 missing_layers = missing_layers + missing_layer + ",\n\t\t";
227 LogError("Vulkan: missing validation layers:\n\t\t" + missing_layers);
228 return true;
229 }
230
AreAllValidationExtensionsSupported()231 bool AreAllValidationExtensionsSupported() {
232 for (const auto& layer : kRequiredValidationLayers) {
233 uint32_t available_extension_count = 0;
234 std::vector<VkExtensionProperties> extension_properties;
235
236 if (vkEnumerateInstanceExtensionProperties(
237 layer, &available_extension_count, nullptr) != VK_SUCCESS) {
238 return false;
239 }
240 extension_properties.resize(available_extension_count);
241 if (vkEnumerateInstanceExtensionProperties(
242 layer, &available_extension_count, extension_properties.data()) !=
243 VK_SUCCESS) {
244 return false;
245 }
246
247 for (const auto& ext : extension_properties) {
248 if (!strcmp(kExtensionForValidationLayer, ext.extensionName))
249 return true;
250 }
251 }
252
253 return false;
254 }
255
256 // Check if |physical_device| supports all required features given
257 // in |required_features|.
AreAllRequiredFeaturesSupported(const VkPhysicalDeviceFeatures & available_features,const VkPhysicalDeviceFeatures & required_features)258 bool AreAllRequiredFeaturesSupported(
259 const VkPhysicalDeviceFeatures& available_features,
260 const VkPhysicalDeviceFeatures& required_features) {
261 if (available_features.robustBufferAccess == VK_FALSE &&
262 required_features.robustBufferAccess == VK_TRUE) {
263 return false;
264 }
265 if (available_features.fullDrawIndexUint32 == VK_FALSE &&
266 required_features.fullDrawIndexUint32 == VK_TRUE) {
267 return false;
268 }
269 if (available_features.imageCubeArray == VK_FALSE &&
270 required_features.imageCubeArray == VK_TRUE) {
271 return false;
272 }
273 if (available_features.independentBlend == VK_FALSE &&
274 required_features.independentBlend == VK_TRUE) {
275 return false;
276 }
277 if (available_features.geometryShader == VK_FALSE &&
278 required_features.geometryShader == VK_TRUE) {
279 return false;
280 }
281 if (available_features.tessellationShader == VK_FALSE &&
282 required_features.tessellationShader == VK_TRUE) {
283 return false;
284 }
285 if (available_features.sampleRateShading == VK_FALSE &&
286 required_features.sampleRateShading == VK_TRUE) {
287 return false;
288 }
289 if (available_features.dualSrcBlend == VK_FALSE &&
290 required_features.dualSrcBlend == VK_TRUE) {
291 return false;
292 }
293 if (available_features.logicOp == VK_FALSE &&
294 required_features.logicOp == VK_TRUE) {
295 return false;
296 }
297 if (available_features.multiDrawIndirect == VK_FALSE &&
298 required_features.multiDrawIndirect == VK_TRUE) {
299 return false;
300 }
301 if (available_features.drawIndirectFirstInstance == VK_FALSE &&
302 required_features.drawIndirectFirstInstance == VK_TRUE) {
303 return false;
304 }
305 if (available_features.depthClamp == VK_FALSE &&
306 required_features.depthClamp == VK_TRUE) {
307 return false;
308 }
309 if (available_features.depthBiasClamp == VK_FALSE &&
310 required_features.depthBiasClamp == VK_TRUE) {
311 return false;
312 }
313 if (available_features.fillModeNonSolid == VK_FALSE &&
314 required_features.fillModeNonSolid == VK_TRUE) {
315 return false;
316 }
317 if (available_features.depthBounds == VK_FALSE &&
318 required_features.depthBounds == VK_TRUE) {
319 return false;
320 }
321 if (available_features.wideLines == VK_FALSE &&
322 required_features.wideLines == VK_TRUE) {
323 return false;
324 }
325 if (available_features.largePoints == VK_FALSE &&
326 required_features.largePoints == VK_TRUE) {
327 return false;
328 }
329 if (available_features.alphaToOne == VK_FALSE &&
330 required_features.alphaToOne == VK_TRUE) {
331 return false;
332 }
333 if (available_features.multiViewport == VK_FALSE &&
334 required_features.multiViewport == VK_TRUE) {
335 return false;
336 }
337 if (available_features.samplerAnisotropy == VK_FALSE &&
338 required_features.samplerAnisotropy == VK_TRUE) {
339 return false;
340 }
341 if (available_features.textureCompressionETC2 == VK_FALSE &&
342 required_features.textureCompressionETC2 == VK_TRUE) {
343 return false;
344 }
345 if (available_features.textureCompressionASTC_LDR == VK_FALSE &&
346 required_features.textureCompressionASTC_LDR == VK_TRUE) {
347 return false;
348 }
349 if (available_features.textureCompressionBC == VK_FALSE &&
350 required_features.textureCompressionBC == VK_TRUE) {
351 return false;
352 }
353 if (available_features.occlusionQueryPrecise == VK_FALSE &&
354 required_features.occlusionQueryPrecise == VK_TRUE) {
355 return false;
356 }
357 if (available_features.pipelineStatisticsQuery == VK_FALSE &&
358 required_features.pipelineStatisticsQuery == VK_TRUE) {
359 return false;
360 }
361 if (available_features.vertexPipelineStoresAndAtomics == VK_FALSE &&
362 required_features.vertexPipelineStoresAndAtomics == VK_TRUE) {
363 return false;
364 }
365 if (available_features.fragmentStoresAndAtomics == VK_FALSE &&
366 required_features.fragmentStoresAndAtomics == VK_TRUE) {
367 return false;
368 }
369 if (available_features.shaderTessellationAndGeometryPointSize == VK_FALSE &&
370 required_features.shaderTessellationAndGeometryPointSize == VK_TRUE) {
371 return false;
372 }
373 if (available_features.shaderImageGatherExtended == VK_FALSE &&
374 required_features.shaderImageGatherExtended == VK_TRUE) {
375 return false;
376 }
377 if (available_features.shaderStorageImageExtendedFormats == VK_FALSE &&
378 required_features.shaderStorageImageExtendedFormats == VK_TRUE) {
379 return false;
380 }
381 if (available_features.shaderStorageImageMultisample == VK_FALSE &&
382 required_features.shaderStorageImageMultisample == VK_TRUE) {
383 return false;
384 }
385 if (available_features.shaderStorageImageReadWithoutFormat == VK_FALSE &&
386 required_features.shaderStorageImageReadWithoutFormat == VK_TRUE) {
387 return false;
388 }
389 if (available_features.shaderStorageImageWriteWithoutFormat == VK_FALSE &&
390 required_features.shaderStorageImageWriteWithoutFormat == VK_TRUE) {
391 return false;
392 }
393 if (available_features.shaderUniformBufferArrayDynamicIndexing == VK_FALSE &&
394 required_features.shaderUniformBufferArrayDynamicIndexing == VK_TRUE) {
395 return false;
396 }
397 if (available_features.shaderSampledImageArrayDynamicIndexing == VK_FALSE &&
398 required_features.shaderSampledImageArrayDynamicIndexing == VK_TRUE) {
399 return false;
400 }
401 if (available_features.shaderStorageBufferArrayDynamicIndexing == VK_FALSE &&
402 required_features.shaderStorageBufferArrayDynamicIndexing == VK_TRUE) {
403 return false;
404 }
405 if (available_features.shaderStorageImageArrayDynamicIndexing == VK_FALSE &&
406 required_features.shaderStorageImageArrayDynamicIndexing == VK_TRUE) {
407 return false;
408 }
409 if (available_features.shaderClipDistance == VK_FALSE &&
410 required_features.shaderClipDistance == VK_TRUE) {
411 return false;
412 }
413 if (available_features.shaderCullDistance == VK_FALSE &&
414 required_features.shaderCullDistance == VK_TRUE) {
415 return false;
416 }
417 if (available_features.shaderFloat64 == VK_FALSE &&
418 required_features.shaderFloat64 == VK_TRUE) {
419 return false;
420 }
421 if (available_features.shaderInt64 == VK_FALSE &&
422 required_features.shaderInt64 == VK_TRUE) {
423 return false;
424 }
425 if (available_features.shaderInt16 == VK_FALSE &&
426 required_features.shaderInt16 == VK_TRUE) {
427 return false;
428 }
429 if (available_features.shaderResourceResidency == VK_FALSE &&
430 required_features.shaderResourceResidency == VK_TRUE) {
431 return false;
432 }
433 if (available_features.shaderResourceMinLod == VK_FALSE &&
434 required_features.shaderResourceMinLod == VK_TRUE) {
435 return false;
436 }
437 if (available_features.sparseBinding == VK_FALSE &&
438 required_features.sparseBinding == VK_TRUE) {
439 return false;
440 }
441 if (available_features.sparseResidencyBuffer == VK_FALSE &&
442 required_features.sparseResidencyBuffer == VK_TRUE) {
443 return false;
444 }
445 if (available_features.sparseResidencyImage2D == VK_FALSE &&
446 required_features.sparseResidencyImage2D == VK_TRUE) {
447 return false;
448 }
449 if (available_features.sparseResidencyImage3D == VK_FALSE &&
450 required_features.sparseResidencyImage3D == VK_TRUE) {
451 return false;
452 }
453 if (available_features.sparseResidency2Samples == VK_FALSE &&
454 required_features.sparseResidency2Samples == VK_TRUE) {
455 return false;
456 }
457 if (available_features.sparseResidency4Samples == VK_FALSE &&
458 required_features.sparseResidency4Samples == VK_TRUE) {
459 return false;
460 }
461 if (available_features.sparseResidency8Samples == VK_FALSE &&
462 required_features.sparseResidency8Samples == VK_TRUE) {
463 return false;
464 }
465 if (available_features.sparseResidency16Samples == VK_FALSE &&
466 required_features.sparseResidency16Samples == VK_TRUE) {
467 return false;
468 }
469 if (available_features.sparseResidencyAliased == VK_FALSE &&
470 required_features.sparseResidencyAliased == VK_TRUE) {
471 return false;
472 }
473 if (available_features.variableMultisampleRate == VK_FALSE &&
474 required_features.variableMultisampleRate == VK_TRUE) {
475 return false;
476 }
477 if (available_features.inheritedQueries == VK_FALSE &&
478 required_features.inheritedQueries == VK_TRUE) {
479 return false;
480 }
481 return true;
482 }
483
484 // Get all available instance extensions.
GetAvailableInstanceExtensions()485 std::vector<std::string> GetAvailableInstanceExtensions() {
486 std::vector<std::string> available_extensions;
487 uint32_t available_extension_count = 0;
488 std::vector<VkExtensionProperties> available_extension_properties;
489
490 if (vkEnumerateInstanceExtensionProperties(
491 nullptr, &available_extension_count, nullptr) != VK_SUCCESS) {
492 return available_extensions;
493 }
494
495 if (available_extension_count == 0)
496 return available_extensions;
497
498 available_extension_properties.resize(available_extension_count);
499 if (vkEnumerateInstanceExtensionProperties(
500 nullptr, &available_extension_count,
501 available_extension_properties.data()) != VK_SUCCESS) {
502 return available_extensions;
503 }
504
505 for (const auto& property : available_extension_properties)
506 available_extensions.push_back(property.extensionName);
507
508 return available_extensions;
509 }
510
511 // Get all available extensions of |physical_device|.
GetAvailableDeviceExtensions(const VkPhysicalDevice & physical_device)512 std::vector<std::string> GetAvailableDeviceExtensions(
513 const VkPhysicalDevice& physical_device) {
514 std::vector<std::string> available_extensions;
515 uint32_t available_extension_count = 0;
516 std::vector<VkExtensionProperties> available_extension_properties;
517
518 if (vkEnumerateDeviceExtensionProperties(physical_device, nullptr,
519 &available_extension_count,
520 nullptr) != VK_SUCCESS) {
521 return available_extensions;
522 }
523
524 if (available_extension_count == 0)
525 return available_extensions;
526
527 available_extension_properties.resize(available_extension_count);
528 if (vkEnumerateDeviceExtensionProperties(
529 physical_device, nullptr, &available_extension_count,
530 available_extension_properties.data()) != VK_SUCCESS) {
531 return available_extensions;
532 }
533
534 for (const auto& property : available_extension_properties)
535 available_extensions.push_back(property.extensionName);
536
537 return available_extensions;
538 }
539
540 // Check if |physical_device| supports all required extensions given
541 // in |required_extensions|.
AreAllExtensionsSupported(const std::vector<std::string> & available_extensions,const std::vector<std::string> & required_extensions)542 bool AreAllExtensionsSupported(
543 const std::vector<std::string>& available_extensions,
544 const std::vector<std::string>& required_extensions) {
545 if (required_extensions.empty())
546 return true;
547
548 std::set<std::string> required_extension_set(required_extensions.begin(),
549 required_extensions.end());
550 for (const auto& extension : available_extensions) {
551 required_extension_set.erase(extension);
552 }
553
554 return required_extension_set.empty();
555 }
556
557 // Check if |physical_device| supports both compute and graphics
558 // pipelines.
ChooseQueueFamilyIndex(const VkPhysicalDevice & physical_device)559 uint32_t ChooseQueueFamilyIndex(const VkPhysicalDevice& physical_device) {
560 uint32_t count = 0;
561 std::vector<VkQueueFamilyProperties> properties;
562
563 vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &count, nullptr);
564 properties.resize(count);
565 vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &count,
566 properties.data());
567
568 for (uint32_t i = 0; i < count; ++i) {
569 if (properties[i].queueFlags &
570 (VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT)) {
571 return i;
572 }
573 }
574
575 return std::numeric_limits<uint32_t>::max();
576 }
577
deviceTypeToName(VkPhysicalDeviceType type)578 std::string deviceTypeToName(VkPhysicalDeviceType type) {
579 switch (type) {
580 case VK_PHYSICAL_DEVICE_TYPE_OTHER:
581 return "other";
582 case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU:
583 return "integrated gpu";
584 case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU:
585 return "discrete gpu";
586 case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU:
587 return "virtual gpu";
588 case VK_PHYSICAL_DEVICE_TYPE_CPU:
589 return "cpu";
590 default:
591 break;
592 }
593 return "unknown";
594 }
595
596 } // namespace
597
ConfigHelperVulkan()598 ConfigHelperVulkan::ConfigHelperVulkan()
599 : available_features_(VkPhysicalDeviceFeatures()),
600 available_features2_(VkPhysicalDeviceFeatures2KHR()),
601 variable_pointers_feature_(VkPhysicalDeviceVariablePointerFeaturesKHR()) {
602 }
603
~ConfigHelperVulkan()604 ConfigHelperVulkan::~ConfigHelperVulkan() {
605 if (vulkan_device_)
606 vkDestroyDevice(vulkan_device_, nullptr);
607
608 if (vulkan_callback_) {
609 auto vkDestroyDebugReportCallbackEXT =
610 reinterpret_cast<PFN_vkDestroyDebugReportCallbackEXT>(
611 vkGetInstanceProcAddr(vulkan_instance_,
612 "vkDestroyDebugReportCallbackEXT"));
613 if (vkDestroyDebugReportCallbackEXT) {
614 vkDestroyDebugReportCallbackEXT(vulkan_instance_, vulkan_callback_,
615 nullptr);
616 }
617 }
618
619 if (vulkan_instance_)
620 vkDestroyInstance(vulkan_instance_, nullptr);
621 }
622
CreateVulkanInstance(uint32_t engine_major,uint32_t engine_minor,std::vector<std::string> required_extensions,bool disable_validation_layer)623 amber::Result ConfigHelperVulkan::CreateVulkanInstance(
624 uint32_t engine_major,
625 uint32_t engine_minor,
626 std::vector<std::string> required_extensions,
627 bool disable_validation_layer) {
628 VkApplicationInfo app_info = VkApplicationInfo();
629 app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
630 app_info.apiVersion = VK_MAKE_VERSION(engine_major, engine_minor, 0);
631
632 VkInstanceCreateInfo instance_info = VkInstanceCreateInfo();
633 instance_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
634 instance_info.pApplicationInfo = &app_info;
635
636 if (!disable_validation_layer) {
637 if (!AreAllValidationLayersSupported())
638 return amber::Result("Sample: not all validation layers are supported");
639 if (!AreAllValidationExtensionsSupported()) {
640 return amber::Result(
641 "Sample: extensions of validation layers are not supported");
642 }
643 instance_info.enabledLayerCount = kNumberOfRequiredValidationLayers;
644 instance_info.ppEnabledLayerNames = kRequiredValidationLayers;
645
646 required_extensions.push_back(kExtensionForValidationLayer);
647 }
648
649 if (!required_extensions.empty()) {
650 available_instance_extensions_ = GetAvailableInstanceExtensions();
651 if (!AreAllExtensionsSupported(available_instance_extensions_,
652 required_extensions)) {
653 return amber::Result("Missing required instance extensions");
654 }
655 }
656
657 // Determine if VkPhysicalDeviceProperties2KHR should be used
658 for (auto& ext : required_extensions) {
659 if (ext == "VK_KHR_get_physical_device_properties2") {
660 use_physical_device_features2_ = true;
661 }
662 }
663
664 std::vector<const char*> required_extensions_in_char;
665 std::transform(
666 required_extensions.begin(), required_extensions.end(),
667 std::back_inserter(required_extensions_in_char),
668 [](const std::string& ext) -> const char* { return ext.c_str(); });
669
670 instance_info.enabledExtensionCount =
671 static_cast<uint32_t>(required_extensions_in_char.size());
672 instance_info.ppEnabledExtensionNames = required_extensions_in_char.data();
673
674 if (vkCreateInstance(&instance_info, nullptr, &vulkan_instance_) !=
675 VK_SUCCESS) {
676 return amber::Result("Unable to create vulkan instance");
677 }
678 return {};
679 }
680
CreateDebugReportCallback()681 amber::Result ConfigHelperVulkan::CreateDebugReportCallback() {
682 VkDebugReportCallbackCreateInfoEXT info =
683 VkDebugReportCallbackCreateInfoEXT();
684 info.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT;
685 info.flags = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT;
686 info.pfnCallback = debugCallback;
687
688 auto vkCreateDebugReportCallbackEXT =
689 reinterpret_cast<PFN_vkCreateDebugReportCallbackEXT>(
690 vkGetInstanceProcAddr(vulkan_instance_,
691 "vkCreateDebugReportCallbackEXT"));
692 if (!vkCreateDebugReportCallbackEXT)
693 return amber::Result("Sample: vkCreateDebugReportCallbackEXT is nullptr");
694
695 if (vkCreateDebugReportCallbackEXT(vulkan_instance_, &info, nullptr,
696 &vulkan_callback_) != VK_SUCCESS) {
697 return amber::Result("Sample: vkCreateDebugReportCallbackEXT fail");
698 }
699 return {};
700 }
701
ChooseVulkanPhysicalDevice(const std::vector<std::string> & required_features,const std::vector<std::string> & required_extensions)702 amber::Result ConfigHelperVulkan::ChooseVulkanPhysicalDevice(
703 const std::vector<std::string>& required_features,
704 const std::vector<std::string>& required_extensions) {
705 uint32_t count = 0;
706 std::vector<VkPhysicalDevice> physical_devices;
707
708 if (vkEnumeratePhysicalDevices(vulkan_instance_, &count, nullptr) !=
709 VK_SUCCESS) {
710 return amber::Result("Unable to enumerate physical devices");
711 }
712
713 physical_devices.resize(count);
714 if (vkEnumeratePhysicalDevices(vulkan_instance_, &count,
715 physical_devices.data()) != VK_SUCCESS) {
716 return amber::Result("Unable to enumerate physical devices");
717 }
718
719 VkPhysicalDeviceFeatures required_vulkan_features =
720 VkPhysicalDeviceFeatures();
721 for (uint32_t i = 0; i < count; ++i) {
722 if (use_physical_device_features2_) {
723 VkPhysicalDeviceVariablePointerFeaturesKHR var_ptrs =
724 VkPhysicalDeviceVariablePointerFeaturesKHR();
725 var_ptrs.sType =
726 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES_KHR;
727 var_ptrs.pNext = nullptr;
728
729 VkPhysicalDeviceFeatures2KHR features2 = VkPhysicalDeviceFeatures2KHR();
730 features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR;
731 features2.pNext = &var_ptrs;
732
733 auto vkGetPhysicalDeviceFeatures2KHR =
734 reinterpret_cast<PFN_vkGetPhysicalDeviceFeatures2KHR>(
735 vkGetInstanceProcAddr(vulkan_instance_,
736 "vkGetPhysicalDeviceFeatures2KHR"));
737 vkGetPhysicalDeviceFeatures2KHR(physical_devices[i], &features2);
738 available_features_ = features2.features;
739
740 std::vector<std::string> required_features1;
741 for (const auto& feature : required_features) {
742 // No dot means this is a features1 feature.
743 if (feature.find_first_of('.') == std::string::npos) {
744 required_features1.push_back(feature);
745 continue;
746 }
747
748 if (feature == kVariablePointers &&
749 var_ptrs.variablePointers != VK_TRUE) {
750 continue;
751 }
752 if (feature == kVariablePointersStorageBuffer &&
753 var_ptrs.variablePointersStorageBuffer != VK_TRUE) {
754 continue;
755 }
756 }
757
758 amber::Result r =
759 NamesToVulkanFeatures(required_features1, &required_vulkan_features);
760 if (!r.IsSuccess())
761 return r;
762
763 } else {
764 amber::Result r =
765 NamesToVulkanFeatures(required_features, &required_vulkan_features);
766 if (!r.IsSuccess())
767 return r;
768
769 vkGetPhysicalDeviceFeatures(physical_devices[i], &available_features_);
770 }
771 if (!AreAllRequiredFeaturesSupported(available_features_,
772 required_vulkan_features)) {
773 continue;
774 }
775
776 available_device_extensions_ =
777 GetAvailableDeviceExtensions(physical_devices[i]);
778 if (!AreAllExtensionsSupported(available_device_extensions_,
779 required_extensions)) {
780 continue;
781 }
782
783 vulkan_queue_family_index_ = ChooseQueueFamilyIndex(physical_devices[i]);
784 if (vulkan_queue_family_index_ != std::numeric_limits<uint32_t>::max()) {
785 vulkan_physical_device_ = physical_devices[i];
786 return {};
787 }
788 }
789
790 std::ostringstream out;
791 out << "Unable to find Vulkan device supporting:" << std::endl;
792 for (const auto& str : required_features)
793 out << " " << str << std::endl;
794 for (const auto& str : required_extensions)
795 out << " " << str << std::endl;
796
797 return amber::Result(out.str());
798 }
799
CreateVulkanDevice(const std::vector<std::string> & required_features,const std::vector<std::string> & required_extensions)800 amber::Result ConfigHelperVulkan::CreateVulkanDevice(
801 const std::vector<std::string>& required_features,
802 const std::vector<std::string>& required_extensions) {
803 VkDeviceQueueCreateInfo queue_info = VkDeviceQueueCreateInfo();
804 const float priorities[] = {1.0f};
805
806 queue_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
807 queue_info.queueFamilyIndex = vulkan_queue_family_index_;
808 queue_info.queueCount = 1;
809 queue_info.pQueuePriorities = priorities;
810
811 std::vector<const char*> required_extensions_in_char;
812 std::transform(
813 required_extensions.begin(), required_extensions.end(),
814 std::back_inserter(required_extensions_in_char),
815 [](const std::string& ext) -> const char* { return ext.c_str(); });
816
817 VkDeviceCreateInfo info = VkDeviceCreateInfo();
818 info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
819 info.pQueueCreateInfos = &queue_info;
820 info.queueCreateInfoCount = 1;
821 info.enabledExtensionCount =
822 static_cast<uint32_t>(required_extensions_in_char.size());
823 info.ppEnabledExtensionNames = required_extensions_in_char.data();
824
825 if (use_physical_device_features2_)
826 return CreateDeviceWithFeatures2(required_features, &info);
827 return CreateDeviceWithFeatures1(required_features, &info);
828 }
829
CreateDeviceWithFeatures1(const std::vector<std::string> & required_features,VkDeviceCreateInfo * info)830 amber::Result ConfigHelperVulkan::CreateDeviceWithFeatures1(
831 const std::vector<std::string>& required_features,
832 VkDeviceCreateInfo* info) {
833 VkPhysicalDeviceFeatures required_vulkan_features =
834 VkPhysicalDeviceFeatures();
835 amber::Result r =
836 NamesToVulkanFeatures(required_features, &required_vulkan_features);
837 if (!r.IsSuccess())
838 return r;
839
840 info->pEnabledFeatures = &required_vulkan_features;
841 return DoCreateDevice(info);
842 }
843
CreateDeviceWithFeatures2(const std::vector<std::string> & required_features,VkDeviceCreateInfo * info)844 amber::Result ConfigHelperVulkan::CreateDeviceWithFeatures2(
845 const std::vector<std::string>& required_features,
846 VkDeviceCreateInfo* info) {
847 variable_pointers_feature_.sType =
848 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES_KHR;
849 variable_pointers_feature_.pNext = nullptr;
850
851 available_features2_.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR;
852 available_features2_.pNext = &variable_pointers_feature_;
853
854 std::vector<std::string> feature1_names;
855 for (const auto& feature : required_features) {
856 // No dot means this is a features1 feature.
857 if (feature.find_first_of('.') == std::string::npos) {
858 feature1_names.push_back(feature);
859 continue;
860 }
861
862 if (feature == kVariablePointers)
863 variable_pointers_feature_.variablePointers = VK_TRUE;
864 else if (feature == kVariablePointersStorageBuffer)
865 variable_pointers_feature_.variablePointersStorageBuffer = VK_TRUE;
866 }
867
868 VkPhysicalDeviceFeatures required_vulkan_features =
869 VkPhysicalDeviceFeatures();
870 amber::Result r =
871 NamesToVulkanFeatures(feature1_names, &required_vulkan_features);
872 if (!r.IsSuccess())
873 return r;
874
875 available_features2_.features = required_vulkan_features;
876
877 info->pNext = &available_features2_;
878 info->pEnabledFeatures = nullptr;
879 return DoCreateDevice(info);
880 }
881
DoCreateDevice(VkDeviceCreateInfo * info)882 amber::Result ConfigHelperVulkan::DoCreateDevice(VkDeviceCreateInfo* info) {
883 if (vkCreateDevice(vulkan_physical_device_, info, nullptr, &vulkan_device_) !=
884 VK_SUCCESS) {
885 return amber::Result("Unable to create vulkan device");
886 }
887 return {};
888 }
889
DumpPhysicalDeviceInfo()890 void ConfigHelperVulkan::DumpPhysicalDeviceInfo() {
891 VkPhysicalDeviceProperties props;
892 vkGetPhysicalDeviceProperties(vulkan_physical_device_, &props);
893
894 uint32_t api_version = props.apiVersion;
895
896 std::cout << std::endl;
897 std::cout << "Physical device properties:" << std::endl;
898 std::cout << " apiVersion: " << static_cast<uint32_t>(api_version >> 22)
899 << "." << static_cast<uint32_t>((api_version >> 12) & 0x3ff) << "."
900 << static_cast<uint32_t>(api_version & 0xfff) << std::endl;
901 std::cout << " driverVersion: " << props.driverVersion << std::endl;
902 std::cout << " vendorID: " << props.vendorID << std::endl;
903 std::cout << " deviceID: " << props.deviceID << std::endl;
904 std::cout << " deviceType: " << deviceTypeToName(props.deviceType)
905 << std::endl;
906 std::cout << " deviceName: " << props.deviceName << std::endl;
907 }
908
CreateConfig(uint32_t engine_major,uint32_t engine_minor,const std::vector<std::string> & required_features,const std::vector<std::string> & required_instance_extensions,const std::vector<std::string> & required_device_extensions,bool disable_validation_layer,bool show_version_info,std::unique_ptr<amber::EngineConfig> * cfg_holder)909 amber::Result ConfigHelperVulkan::CreateConfig(
910 uint32_t engine_major,
911 uint32_t engine_minor,
912 const std::vector<std::string>& required_features,
913 const std::vector<std::string>& required_instance_extensions,
914 const std::vector<std::string>& required_device_extensions,
915 bool disable_validation_layer,
916 bool show_version_info,
917 std::unique_ptr<amber::EngineConfig>* cfg_holder) {
918 amber::Result r = CreateVulkanInstance(engine_major, engine_minor,
919 required_instance_extensions,
920 disable_validation_layer);
921 if (!r.IsSuccess())
922 return r;
923
924 if (!disable_validation_layer) {
925 r = CreateDebugReportCallback();
926 if (!r.IsSuccess())
927 return r;
928 }
929
930 r = ChooseVulkanPhysicalDevice(required_features, required_device_extensions);
931 if (!r.IsSuccess())
932 return r;
933
934 if (show_version_info)
935 DumpPhysicalDeviceInfo();
936
937 r = CreateVulkanDevice(required_features, required_device_extensions);
938 if (!r.IsSuccess())
939 return r;
940
941 vkGetDeviceQueue(vulkan_device_, vulkan_queue_family_index_, 0,
942 &vulkan_queue_);
943
944 *cfg_holder =
945 std::unique_ptr<amber::EngineConfig>(new amber::VulkanEngineConfig());
946 amber::VulkanEngineConfig* config =
947 static_cast<amber::VulkanEngineConfig*>(cfg_holder->get());
948 config->physical_device = vulkan_physical_device_;
949 config->available_features = available_features_;
950 config->available_features2 = available_features2_;
951 config->available_instance_extensions = available_instance_extensions_;
952 config->available_device_extensions = available_device_extensions_;
953 config->instance = vulkan_instance_;
954 config->queue_family_index = vulkan_queue_family_index_;
955 config->queue = vulkan_queue_;
956 config->device = vulkan_device_;
957 config->vkGetInstanceProcAddr = vkGetInstanceProcAddr;
958
959 return {};
960 }
961
962 } // namespace sample
963