• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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