• 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 #include <utility>
26 
27 #include "samples/log.h"
28 
29 namespace sample {
30 namespace {
31 
32 const char* const kRequiredValidationLayers[] = {
33 #ifdef __ANDROID__
34     // Note that the order of enabled layers is important. It is
35     // based on Android NDK Vulkan document.
36     "VK_LAYER_GOOGLE_threading",      "VK_LAYER_LUNARG_parameter_validation",
37     "VK_LAYER_LUNARG_object_tracker", "VK_LAYER_LUNARG_core_validation",
38     "VK_LAYER_GOOGLE_unique_objects",
39 #else   // __ANDROID__
40     "VK_LAYER_KHRONOS_validation",
41 #endif  // __ANDROID__
42 };
43 
44 const size_t kNumberOfRequiredValidationLayers =
45     sizeof(kRequiredValidationLayers) / sizeof(const char*);
46 
47 const char kVariablePointers[] = "VariablePointerFeatures.variablePointers";
48 const char kVariablePointersStorageBuffer[] =
49     "VariablePointerFeatures.variablePointersStorageBuffer";
50 const char kFloat16Int8_Float16[] = "Float16Int8Features.shaderFloat16";
51 const char kFloat16Int8_Int8[] = "Float16Int8Features.shaderInt8";
52 const char k8BitStorage_Storage[] =
53     "Storage8BitFeatures.storageBuffer8BitAccess";
54 const char k8BitStorage_UniformAndStorage[] =
55     "Storage8BitFeatures.uniformAndStorageBuffer8BitAccess";
56 const char k8BitStorage_PushConstant[] =
57     "Storage8BitFeatures.storagePushConstant8";
58 const char k16BitStorage_Storage[] =
59     "Storage16BitFeatures.storageBuffer16BitAccess";
60 const char k16BitStorage_UniformAndStorage[] =
61     "Storage16BitFeatures.uniformAndStorageBuffer16BitAccess";
62 const char k16BitStorage_PushConstant[] =
63     "Storage16BitFeatures.storagePushConstant16";
64 const char k16BitStorage_InputOutput[] =
65     "Storage16BitFeatures.storageInputOutput16";
66 
67 const char kSubgroupSizeControl[] = "SubgroupSizeControl.subgroupSizeControl";
68 const char kComputeFullSubgroups[] = "SubgroupSizeControl.computeFullSubgroups";
69 
70 const char kExtensionForValidationLayer[] = "VK_EXT_debug_report";
71 
debugCallback(VkDebugReportFlagsEXT flag,VkDebugReportObjectTypeEXT,uint64_t,size_t,int32_t,const char * layerPrefix,const char * msg,void *)72 VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(VkDebugReportFlagsEXT flag,
73                                              VkDebugReportObjectTypeEXT,
74                                              uint64_t,
75                                              size_t,
76                                              int32_t,
77                                              const char* layerPrefix,
78                                              const char* msg,
79                                              void*) {
80   std::string flag_message;
81   switch (flag) {
82     case VK_DEBUG_REPORT_ERROR_BIT_EXT:
83       flag_message = "[ERROR]";
84       break;
85     case VK_DEBUG_REPORT_WARNING_BIT_EXT:
86       flag_message = "[WARNING]";
87       break;
88     default:
89       flag_message = "[UNKNOWN]";
90       break;
91   }
92 
93   LogError(flag_message + " validation layer (" + layerPrefix + "):\n" + msg);
94   return VK_FALSE;
95 }
96 
97 // Convert required features given as a string array to
98 // VkPhysicalDeviceFeatures.
NamesToVulkanFeatures(const std::vector<std::string> & required_feature_names,VkPhysicalDeviceFeatures * features)99 amber::Result NamesToVulkanFeatures(
100     const std::vector<std::string>& required_feature_names,
101     VkPhysicalDeviceFeatures* features) {
102   for (const auto& name : required_feature_names) {
103     if (name == "robustBufferAccess") {
104       features->robustBufferAccess = VK_TRUE;
105     } else if (name == "fullDrawIndexUint32") {
106       features->fullDrawIndexUint32 = VK_TRUE;
107     } else if (name == "imageCubeArray") {
108       features->imageCubeArray = VK_TRUE;
109     } else if (name == "independentBlend") {
110       features->independentBlend = VK_TRUE;
111     } else if (name == "geometryShader") {
112       features->geometryShader = VK_TRUE;
113     } else if (name == "tessellationShader") {
114       features->tessellationShader = VK_TRUE;
115     } else if (name == "sampleRateShading") {
116       features->sampleRateShading = VK_TRUE;
117     } else if (name == "dualSrcBlend") {
118       features->dualSrcBlend = VK_TRUE;
119     } else if (name == "logicOp") {
120       features->logicOp = VK_TRUE;
121     } else if (name == "multiDrawIndirect") {
122       features->multiDrawIndirect = VK_TRUE;
123     } else if (name == "drawIndirectFirstInstance") {
124       features->drawIndirectFirstInstance = VK_TRUE;
125     } else if (name == "depthClamp") {
126       features->depthClamp = VK_TRUE;
127     } else if (name == "depthBiasClamp") {
128       features->depthBiasClamp = VK_TRUE;
129     } else if (name == "fillModeNonSolid") {
130       features->fillModeNonSolid = VK_TRUE;
131     } else if (name == "depthBounds") {
132       features->depthBounds = VK_TRUE;
133     } else if (name == "wideLines") {
134       features->wideLines = VK_TRUE;
135     } else if (name == "largePoints") {
136       features->largePoints = VK_TRUE;
137     } else if (name == "alphaToOne") {
138       features->alphaToOne = VK_TRUE;
139     } else if (name == "multiViewport") {
140       features->multiViewport = VK_TRUE;
141     } else if (name == "samplerAnisotropy") {
142       features->samplerAnisotropy = VK_TRUE;
143     } else if (name == "textureCompressionETC2") {
144       features->textureCompressionETC2 = VK_TRUE;
145     } else if (name == "textureCompressionASTC_LDR") {
146       features->textureCompressionASTC_LDR = VK_TRUE;
147     } else if (name == "textureCompressionBC") {
148       features->textureCompressionBC = VK_TRUE;
149     } else if (name == "occlusionQueryPrecise") {
150       features->occlusionQueryPrecise = VK_TRUE;
151     } else if (name == "pipelineStatisticsQuery") {
152       features->pipelineStatisticsQuery = VK_TRUE;
153     } else if (name == "vertexPipelineStoresAndAtomics") {
154       features->vertexPipelineStoresAndAtomics = VK_TRUE;
155     } else if (name == "fragmentStoresAndAtomics") {
156       features->fragmentStoresAndAtomics = VK_TRUE;
157     } else if (name == "shaderTessellationAndGeometryPointSize") {
158       features->shaderTessellationAndGeometryPointSize = VK_TRUE;
159     } else if (name == "shaderImageGatherExtended") {
160       features->shaderImageGatherExtended = VK_TRUE;
161     } else if (name == "shaderStorageImageExtendedFormats") {
162       features->shaderStorageImageExtendedFormats = VK_TRUE;
163     } else if (name == "shaderStorageImageMultisample") {
164       features->shaderStorageImageMultisample = VK_TRUE;
165     } else if (name == "shaderStorageImageReadWithoutFormat") {
166       features->shaderStorageImageReadWithoutFormat = VK_TRUE;
167     } else if (name == "shaderStorageImageWriteWithoutFormat") {
168       features->shaderStorageImageWriteWithoutFormat = VK_TRUE;
169     } else if (name == "shaderUniformBufferArrayDynamicIndexing") {
170       features->shaderUniformBufferArrayDynamicIndexing = VK_TRUE;
171     } else if (name == "shaderSampledImageArrayDynamicIndexing") {
172       features->shaderSampledImageArrayDynamicIndexing = VK_TRUE;
173     } else if (name == "shaderStorageBufferArrayDynamicIndexing") {
174       features->shaderStorageBufferArrayDynamicIndexing = VK_TRUE;
175     } else if (name == "shaderStorageImageArrayDynamicIndexing") {
176       features->shaderStorageImageArrayDynamicIndexing = VK_TRUE;
177     } else if (name == "shaderClipDistance") {
178       features->shaderClipDistance = VK_TRUE;
179     } else if (name == "shaderCullDistance") {
180       features->shaderCullDistance = VK_TRUE;
181     } else if (name == "shaderFloat64") {
182       features->shaderFloat64 = VK_TRUE;
183     } else if (name == "shaderInt64") {
184       features->shaderInt64 = VK_TRUE;
185     } else if (name == "shaderInt16") {
186       features->shaderInt16 = VK_TRUE;
187     } else if (name == "shaderResourceResidency") {
188       features->shaderResourceResidency = VK_TRUE;
189     } else if (name == "shaderResourceMinLod") {
190       features->shaderResourceMinLod = VK_TRUE;
191     } else if (name == "sparseBinding") {
192       features->sparseBinding = VK_TRUE;
193     } else if (name == "sparseResidencyBuffer") {
194       features->sparseResidencyBuffer = VK_TRUE;
195     } else if (name == "sparseResidencyImage2D") {
196       features->sparseResidencyImage2D = VK_TRUE;
197     } else if (name == "sparseResidencyImage3D") {
198       features->sparseResidencyImage3D = VK_TRUE;
199     } else if (name == "sparseResidency2Samples") {
200       features->sparseResidency2Samples = VK_TRUE;
201     } else if (name == "sparseResidency4Samples") {
202       features->sparseResidency4Samples = VK_TRUE;
203     } else if (name == "sparseResidency8Samples") {
204       features->sparseResidency8Samples = VK_TRUE;
205     } else if (name == "sparseResidency16Samples") {
206       features->sparseResidency16Samples = VK_TRUE;
207     } else if (name == "sparseResidencyAliased") {
208       features->sparseResidencyAliased = VK_TRUE;
209     } else if (name == "variableMultisampleRate") {
210       features->variableMultisampleRate = VK_TRUE;
211     } else if (name == "inheritedQueries") {
212       features->inheritedQueries = VK_TRUE;
213     } else {
214       return amber::Result("Sample: Unknown Vulkan feature: " + name);
215     }
216   }
217   return {};
218 }
219 
AreAllValidationLayersSupported()220 bool AreAllValidationLayersSupported() {
221   std::vector<VkLayerProperties> available_layer_properties;
222   uint32_t available_layer_count = 0;
223   if (vkEnumerateInstanceLayerProperties(&available_layer_count, nullptr) !=
224       VK_SUCCESS) {
225     return false;
226   }
227   available_layer_properties.resize(available_layer_count);
228   if (vkEnumerateInstanceLayerProperties(&available_layer_count,
229                                          available_layer_properties.data()) !=
230       VK_SUCCESS) {
231     return false;
232   }
233 
234   std::set<std::string> required_layer_set(
235       kRequiredValidationLayers,
236       &kRequiredValidationLayers[kNumberOfRequiredValidationLayers]);
237   for (const auto& property : available_layer_properties) {
238     required_layer_set.erase(property.layerName);
239   }
240 
241   if (required_layer_set.empty())
242     return true;
243 
244   std::string missing_layers;
245   for (const auto& missing_layer : required_layer_set)
246     missing_layers = missing_layers + missing_layer + ",\n\t\t";
247   LogError("Vulkan: missing validation layers:\n\t\t" + missing_layers);
248   return true;
249 }
250 
AreAllValidationExtensionsSupported()251 bool AreAllValidationExtensionsSupported() {
252   for (const auto& layer : kRequiredValidationLayers) {
253     uint32_t available_extension_count = 0;
254     std::vector<VkExtensionProperties> extension_properties;
255 
256     if (vkEnumerateInstanceExtensionProperties(
257             layer, &available_extension_count, nullptr) != VK_SUCCESS) {
258       return false;
259     }
260     extension_properties.resize(available_extension_count);
261     if (vkEnumerateInstanceExtensionProperties(
262             layer, &available_extension_count, extension_properties.data()) !=
263         VK_SUCCESS) {
264       return false;
265     }
266 
267     for (const auto& ext : extension_properties) {
268       if (!strcmp(kExtensionForValidationLayer, ext.extensionName))
269         return true;
270     }
271   }
272 
273   return false;
274 }
275 
276 // Check if |physical_device| supports all required features given
277 // in |required_features|.
AreAllRequiredFeaturesSupported(const VkPhysicalDeviceFeatures & available_features,const VkPhysicalDeviceFeatures & required_features)278 bool AreAllRequiredFeaturesSupported(
279     const VkPhysicalDeviceFeatures& available_features,
280     const VkPhysicalDeviceFeatures& required_features) {
281   if (available_features.robustBufferAccess == VK_FALSE &&
282       required_features.robustBufferAccess == VK_TRUE) {
283     return false;
284   }
285   if (available_features.fullDrawIndexUint32 == VK_FALSE &&
286       required_features.fullDrawIndexUint32 == VK_TRUE) {
287     return false;
288   }
289   if (available_features.imageCubeArray == VK_FALSE &&
290       required_features.imageCubeArray == VK_TRUE) {
291     return false;
292   }
293   if (available_features.independentBlend == VK_FALSE &&
294       required_features.independentBlend == VK_TRUE) {
295     return false;
296   }
297   if (available_features.geometryShader == VK_FALSE &&
298       required_features.geometryShader == VK_TRUE) {
299     return false;
300   }
301   if (available_features.tessellationShader == VK_FALSE &&
302       required_features.tessellationShader == VK_TRUE) {
303     return false;
304   }
305   if (available_features.sampleRateShading == VK_FALSE &&
306       required_features.sampleRateShading == VK_TRUE) {
307     return false;
308   }
309   if (available_features.dualSrcBlend == VK_FALSE &&
310       required_features.dualSrcBlend == VK_TRUE) {
311     return false;
312   }
313   if (available_features.logicOp == VK_FALSE &&
314       required_features.logicOp == VK_TRUE) {
315     return false;
316   }
317   if (available_features.multiDrawIndirect == VK_FALSE &&
318       required_features.multiDrawIndirect == VK_TRUE) {
319     return false;
320   }
321   if (available_features.drawIndirectFirstInstance == VK_FALSE &&
322       required_features.drawIndirectFirstInstance == VK_TRUE) {
323     return false;
324   }
325   if (available_features.depthClamp == VK_FALSE &&
326       required_features.depthClamp == VK_TRUE) {
327     return false;
328   }
329   if (available_features.depthBiasClamp == VK_FALSE &&
330       required_features.depthBiasClamp == VK_TRUE) {
331     return false;
332   }
333   if (available_features.fillModeNonSolid == VK_FALSE &&
334       required_features.fillModeNonSolid == VK_TRUE) {
335     return false;
336   }
337   if (available_features.depthBounds == VK_FALSE &&
338       required_features.depthBounds == VK_TRUE) {
339     return false;
340   }
341   if (available_features.wideLines == VK_FALSE &&
342       required_features.wideLines == VK_TRUE) {
343     return false;
344   }
345   if (available_features.largePoints == VK_FALSE &&
346       required_features.largePoints == VK_TRUE) {
347     return false;
348   }
349   if (available_features.alphaToOne == VK_FALSE &&
350       required_features.alphaToOne == VK_TRUE) {
351     return false;
352   }
353   if (available_features.multiViewport == VK_FALSE &&
354       required_features.multiViewport == VK_TRUE) {
355     return false;
356   }
357   if (available_features.samplerAnisotropy == VK_FALSE &&
358       required_features.samplerAnisotropy == VK_TRUE) {
359     return false;
360   }
361   if (available_features.textureCompressionETC2 == VK_FALSE &&
362       required_features.textureCompressionETC2 == VK_TRUE) {
363     return false;
364   }
365   if (available_features.textureCompressionASTC_LDR == VK_FALSE &&
366       required_features.textureCompressionASTC_LDR == VK_TRUE) {
367     return false;
368   }
369   if (available_features.textureCompressionBC == VK_FALSE &&
370       required_features.textureCompressionBC == VK_TRUE) {
371     return false;
372   }
373   if (available_features.occlusionQueryPrecise == VK_FALSE &&
374       required_features.occlusionQueryPrecise == VK_TRUE) {
375     return false;
376   }
377   if (available_features.pipelineStatisticsQuery == VK_FALSE &&
378       required_features.pipelineStatisticsQuery == VK_TRUE) {
379     return false;
380   }
381   if (available_features.vertexPipelineStoresAndAtomics == VK_FALSE &&
382       required_features.vertexPipelineStoresAndAtomics == VK_TRUE) {
383     return false;
384   }
385   if (available_features.fragmentStoresAndAtomics == VK_FALSE &&
386       required_features.fragmentStoresAndAtomics == VK_TRUE) {
387     return false;
388   }
389   if (available_features.shaderTessellationAndGeometryPointSize == VK_FALSE &&
390       required_features.shaderTessellationAndGeometryPointSize == VK_TRUE) {
391     return false;
392   }
393   if (available_features.shaderImageGatherExtended == VK_FALSE &&
394       required_features.shaderImageGatherExtended == VK_TRUE) {
395     return false;
396   }
397   if (available_features.shaderStorageImageExtendedFormats == VK_FALSE &&
398       required_features.shaderStorageImageExtendedFormats == VK_TRUE) {
399     return false;
400   }
401   if (available_features.shaderStorageImageMultisample == VK_FALSE &&
402       required_features.shaderStorageImageMultisample == VK_TRUE) {
403     return false;
404   }
405   if (available_features.shaderStorageImageReadWithoutFormat == VK_FALSE &&
406       required_features.shaderStorageImageReadWithoutFormat == VK_TRUE) {
407     return false;
408   }
409   if (available_features.shaderStorageImageWriteWithoutFormat == VK_FALSE &&
410       required_features.shaderStorageImageWriteWithoutFormat == VK_TRUE) {
411     return false;
412   }
413   if (available_features.shaderUniformBufferArrayDynamicIndexing == VK_FALSE &&
414       required_features.shaderUniformBufferArrayDynamicIndexing == VK_TRUE) {
415     return false;
416   }
417   if (available_features.shaderSampledImageArrayDynamicIndexing == VK_FALSE &&
418       required_features.shaderSampledImageArrayDynamicIndexing == VK_TRUE) {
419     return false;
420   }
421   if (available_features.shaderStorageBufferArrayDynamicIndexing == VK_FALSE &&
422       required_features.shaderStorageBufferArrayDynamicIndexing == VK_TRUE) {
423     return false;
424   }
425   if (available_features.shaderStorageImageArrayDynamicIndexing == VK_FALSE &&
426       required_features.shaderStorageImageArrayDynamicIndexing == VK_TRUE) {
427     return false;
428   }
429   if (available_features.shaderClipDistance == VK_FALSE &&
430       required_features.shaderClipDistance == VK_TRUE) {
431     return false;
432   }
433   if (available_features.shaderCullDistance == VK_FALSE &&
434       required_features.shaderCullDistance == VK_TRUE) {
435     return false;
436   }
437   if (available_features.shaderFloat64 == VK_FALSE &&
438       required_features.shaderFloat64 == VK_TRUE) {
439     return false;
440   }
441   if (available_features.shaderInt64 == VK_FALSE &&
442       required_features.shaderInt64 == VK_TRUE) {
443     return false;
444   }
445   if (available_features.shaderInt16 == VK_FALSE &&
446       required_features.shaderInt16 == VK_TRUE) {
447     return false;
448   }
449   if (available_features.shaderResourceResidency == VK_FALSE &&
450       required_features.shaderResourceResidency == VK_TRUE) {
451     return false;
452   }
453   if (available_features.shaderResourceMinLod == VK_FALSE &&
454       required_features.shaderResourceMinLod == VK_TRUE) {
455     return false;
456   }
457   if (available_features.sparseBinding == VK_FALSE &&
458       required_features.sparseBinding == VK_TRUE) {
459     return false;
460   }
461   if (available_features.sparseResidencyBuffer == VK_FALSE &&
462       required_features.sparseResidencyBuffer == VK_TRUE) {
463     return false;
464   }
465   if (available_features.sparseResidencyImage2D == VK_FALSE &&
466       required_features.sparseResidencyImage2D == VK_TRUE) {
467     return false;
468   }
469   if (available_features.sparseResidencyImage3D == VK_FALSE &&
470       required_features.sparseResidencyImage3D == VK_TRUE) {
471     return false;
472   }
473   if (available_features.sparseResidency2Samples == VK_FALSE &&
474       required_features.sparseResidency2Samples == VK_TRUE) {
475     return false;
476   }
477   if (available_features.sparseResidency4Samples == VK_FALSE &&
478       required_features.sparseResidency4Samples == VK_TRUE) {
479     return false;
480   }
481   if (available_features.sparseResidency8Samples == VK_FALSE &&
482       required_features.sparseResidency8Samples == VK_TRUE) {
483     return false;
484   }
485   if (available_features.sparseResidency16Samples == VK_FALSE &&
486       required_features.sparseResidency16Samples == VK_TRUE) {
487     return false;
488   }
489   if (available_features.sparseResidencyAliased == VK_FALSE &&
490       required_features.sparseResidencyAliased == VK_TRUE) {
491     return false;
492   }
493   if (available_features.variableMultisampleRate == VK_FALSE &&
494       required_features.variableMultisampleRate == VK_TRUE) {
495     return false;
496   }
497   if (available_features.inheritedQueries == VK_FALSE &&
498       required_features.inheritedQueries == VK_TRUE) {
499     return false;
500   }
501   return true;
502 }
503 
504 // Get all available instance extensions.
GetAvailableInstanceExtensions()505 std::vector<std::string> GetAvailableInstanceExtensions() {
506   std::vector<std::string> available_extensions;
507   uint32_t available_extension_count = 0;
508   std::vector<VkExtensionProperties> available_extension_properties;
509 
510   if (vkEnumerateInstanceExtensionProperties(
511           nullptr, &available_extension_count, nullptr) != VK_SUCCESS) {
512     return available_extensions;
513   }
514 
515   if (available_extension_count == 0)
516     return available_extensions;
517 
518   available_extension_properties.resize(available_extension_count);
519   if (vkEnumerateInstanceExtensionProperties(
520           nullptr, &available_extension_count,
521           available_extension_properties.data()) != VK_SUCCESS) {
522     return available_extensions;
523   }
524 
525   for (const auto& property : available_extension_properties)
526     available_extensions.push_back(property.extensionName);
527 
528   return available_extensions;
529 }
530 
531 // Get all available extensions of |physical_device|.
GetAvailableDeviceExtensions(const VkPhysicalDevice & physical_device)532 std::vector<std::string> GetAvailableDeviceExtensions(
533     const VkPhysicalDevice& physical_device) {
534   std::vector<std::string> available_extensions;
535   uint32_t available_extension_count = 0;
536   std::vector<VkExtensionProperties> available_extension_properties;
537 
538   if (vkEnumerateDeviceExtensionProperties(physical_device, nullptr,
539                                            &available_extension_count,
540                                            nullptr) != VK_SUCCESS) {
541     return available_extensions;
542   }
543 
544   if (available_extension_count == 0)
545     return available_extensions;
546 
547   available_extension_properties.resize(available_extension_count);
548   if (vkEnumerateDeviceExtensionProperties(
549           physical_device, nullptr, &available_extension_count,
550           available_extension_properties.data()) != VK_SUCCESS) {
551     return available_extensions;
552   }
553 
554   for (const auto& property : available_extension_properties)
555     available_extensions.push_back(property.extensionName);
556 
557   return available_extensions;
558 }
559 
560 // Check if |physical_device| supports all required extensions given
561 // in |required_extensions|.
AreAllExtensionsSupported(const std::vector<std::string> & available_extensions,const std::vector<std::string> & required_extensions)562 bool AreAllExtensionsSupported(
563     const std::vector<std::string>& available_extensions,
564     const std::vector<std::string>& required_extensions) {
565   if (required_extensions.empty())
566     return true;
567 
568   std::set<std::string> required_extension_set(required_extensions.begin(),
569                                                required_extensions.end());
570   for (const auto& extension : available_extensions) {
571     required_extension_set.erase(extension);
572   }
573 
574   return required_extension_set.empty();
575 }
576 
577 // Check if |physical_device| supports both compute and graphics
578 // pipelines.
ChooseQueueFamilyIndex(const VkPhysicalDevice & physical_device)579 uint32_t ChooseQueueFamilyIndex(const VkPhysicalDevice& physical_device) {
580   uint32_t count = 0;
581   std::vector<VkQueueFamilyProperties> properties;
582 
583   vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &count, nullptr);
584   properties.resize(count);
585   vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &count,
586                                            properties.data());
587 
588   for (uint32_t i = 0; i < count; ++i) {
589     if (properties[i].queueFlags &
590         (VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT)) {
591       return i;
592     }
593   }
594 
595   return std::numeric_limits<uint32_t>::max();
596 }
597 
deviceTypeToName(VkPhysicalDeviceType type)598 std::string deviceTypeToName(VkPhysicalDeviceType type) {
599   switch (type) {
600     case VK_PHYSICAL_DEVICE_TYPE_OTHER:
601       return "other";
602     case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU:
603       return "integrated gpu";
604     case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU:
605       return "discrete gpu";
606     case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU:
607       return "virtual gpu";
608     case VK_PHYSICAL_DEVICE_TYPE_CPU:
609       return "cpu";
610     default:
611       break;
612   }
613   return "unknown";
614 }
615 
stageFlagBitsToNames(const VkShaderStageFlags bits)616 std::string stageFlagBitsToNames(const VkShaderStageFlags bits) {
617   static const std::pair<VkShaderStageFlagBits, const char*> stages[] = {
618       std::make_pair(VK_SHADER_STAGE_VERTEX_BIT, "vert"),
619       std::make_pair(VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, "tessc"),
620       std::make_pair(VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, "tesse"),
621       std::make_pair(VK_SHADER_STAGE_GEOMETRY_BIT, "geom"),
622       std::make_pair(VK_SHADER_STAGE_FRAGMENT_BIT, "frag"),
623       std::make_pair(VK_SHADER_STAGE_COMPUTE_BIT, "comp")};
624   std::ostringstream result;
625   bool addSeparator = false;
626   for (const auto& stage : stages) {
627     if ((bits & stage.first) != 0) {
628       if (addSeparator)
629         result << ", ";
630       result << stage.second;
631       addSeparator = true;
632     }
633   }
634   return result.str();
635 }
636 
637 }  // namespace
638 
ConfigHelperVulkan()639 ConfigHelperVulkan::ConfigHelperVulkan()
640     : available_features_(VkPhysicalDeviceFeatures()),
641       available_features2_(VkPhysicalDeviceFeatures2KHR()),
642       variable_pointers_feature_(VkPhysicalDeviceVariablePointerFeaturesKHR()),
643       float16_int8_feature_(VkPhysicalDeviceFloat16Int8FeaturesKHR()),
644       storage_8bit_feature_(VkPhysicalDevice8BitStorageFeaturesKHR()),
645       storage_16bit_feature_(VkPhysicalDevice16BitStorageFeaturesKHR()),
646       subgroup_size_control_feature_(
647           VkPhysicalDeviceSubgroupSizeControlFeaturesEXT()) {}
648 
~ConfigHelperVulkan()649 ConfigHelperVulkan::~ConfigHelperVulkan() {
650   if (vulkan_device_)
651     vkDestroyDevice(vulkan_device_, nullptr);
652 
653   if (vulkan_callback_) {
654     auto vkDestroyDebugReportCallbackEXT =
655         reinterpret_cast<PFN_vkDestroyDebugReportCallbackEXT>(
656             vkGetInstanceProcAddr(vulkan_instance_,
657                                   "vkDestroyDebugReportCallbackEXT"));
658     if (vkDestroyDebugReportCallbackEXT) {
659       vkDestroyDebugReportCallbackEXT(vulkan_instance_, vulkan_callback_,
660                                       nullptr);
661     }
662   }
663 
664   if (vulkan_instance_)
665     vkDestroyInstance(vulkan_instance_, nullptr);
666 }
667 
CreateVulkanInstance(uint32_t engine_major,uint32_t engine_minor,std::vector<std::string> required_extensions,bool disable_validation_layer)668 amber::Result ConfigHelperVulkan::CreateVulkanInstance(
669     uint32_t engine_major,
670     uint32_t engine_minor,
671     std::vector<std::string> required_extensions,
672     bool disable_validation_layer) {
673   VkApplicationInfo app_info = VkApplicationInfo();
674   app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
675 
676 #pragma clang diagnostic push
677 #pragma clang diagnostic ignored "-Wold-style-cast"
678   app_info.apiVersion = VK_MAKE_VERSION(engine_major, engine_minor, 0);
679 #pragma clang diagnostic pop
680 
681   VkInstanceCreateInfo instance_info = VkInstanceCreateInfo();
682   instance_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
683   instance_info.pApplicationInfo = &app_info;
684 
685   if (!disable_validation_layer) {
686     if (!AreAllValidationLayersSupported())
687       return amber::Result("Sample: not all validation layers are supported");
688     if (!AreAllValidationExtensionsSupported()) {
689       return amber::Result(
690           "Sample: extensions of validation layers are not supported");
691     }
692     instance_info.enabledLayerCount = kNumberOfRequiredValidationLayers;
693     instance_info.ppEnabledLayerNames = kRequiredValidationLayers;
694 
695     required_extensions.push_back(kExtensionForValidationLayer);
696   }
697 
698   available_instance_extensions_ = GetAvailableInstanceExtensions();
699   if (!required_extensions.empty()) {
700     if (!AreAllExtensionsSupported(available_instance_extensions_,
701                                    required_extensions)) {
702       return amber::Result("Missing required instance extensions");
703     }
704   }
705 
706   if (std::find(available_instance_extensions_.begin(),
707                 available_instance_extensions_.end(),
708                 "VK_KHR_get_physical_device_properties2") !=
709       available_instance_extensions_.end()) {
710     required_extensions.push_back("VK_KHR_get_physical_device_properties2");
711   }
712 
713   // Determine if VkPhysicalDeviceProperties2KHR should be used
714   for (auto& ext : required_extensions) {
715     if (ext == "VK_KHR_get_physical_device_properties2")
716       supports_get_physical_device_properties2_ = true;
717   }
718 
719   std::vector<const char*> required_extensions_in_char;
720   std::transform(
721       required_extensions.begin(), required_extensions.end(),
722       std::back_inserter(required_extensions_in_char),
723       [](const std::string& ext) -> const char* { return ext.c_str(); });
724 
725   instance_info.enabledExtensionCount =
726       static_cast<uint32_t>(required_extensions_in_char.size());
727   instance_info.ppEnabledExtensionNames = required_extensions_in_char.data();
728 
729   if (vkCreateInstance(&instance_info, nullptr, &vulkan_instance_) !=
730       VK_SUCCESS) {
731     return amber::Result("Unable to create vulkan instance");
732   }
733   return {};
734 }
735 
CreateDebugReportCallback()736 amber::Result ConfigHelperVulkan::CreateDebugReportCallback() {
737   VkDebugReportCallbackCreateInfoEXT info =
738       VkDebugReportCallbackCreateInfoEXT();
739   info.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT;
740   info.flags = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT;
741   info.pfnCallback = debugCallback;
742 
743   auto vkCreateDebugReportCallbackEXT =
744       reinterpret_cast<PFN_vkCreateDebugReportCallbackEXT>(
745           vkGetInstanceProcAddr(vulkan_instance_,
746                                 "vkCreateDebugReportCallbackEXT"));
747   if (!vkCreateDebugReportCallbackEXT)
748     return amber::Result("Sample: vkCreateDebugReportCallbackEXT is nullptr");
749 
750   if (vkCreateDebugReportCallbackEXT(vulkan_instance_, &info, nullptr,
751                                      &vulkan_callback_) != VK_SUCCESS) {
752     return amber::Result("Sample: vkCreateDebugReportCallbackEXT fail");
753   }
754   return {};
755 }
756 
CheckVulkanPhysicalDeviceRequirements(const VkPhysicalDevice physical_device,const std::vector<std::string> & required_features,const std::vector<std::string> & required_extensions)757 amber::Result ConfigHelperVulkan::CheckVulkanPhysicalDeviceRequirements(
758     const VkPhysicalDevice physical_device,
759     const std::vector<std::string>& required_features,
760     const std::vector<std::string>& required_extensions) {
761   VkPhysicalDeviceFeatures required_vulkan_features =
762       VkPhysicalDeviceFeatures();
763 
764   if (supports_get_physical_device_properties2_) {
765     VkPhysicalDeviceSubgroupSizeControlFeaturesEXT size_control =
766         VkPhysicalDeviceSubgroupSizeControlFeaturesEXT();
767     size_control.sType =
768         VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_FEATURES_EXT;
769     size_control.pNext = nullptr;
770 
771     VkPhysicalDeviceVariablePointerFeaturesKHR var_ptrs =
772         VkPhysicalDeviceVariablePointerFeaturesKHR();
773     var_ptrs.sType =
774         VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES_KHR;
775     var_ptrs.pNext = &size_control;
776 
777     VkPhysicalDeviceFeatures2KHR features2 = VkPhysicalDeviceFeatures2KHR();
778     features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR;
779     features2.pNext = &var_ptrs;
780 
781     auto vkGetPhysicalDeviceFeatures2KHR =
782         reinterpret_cast<PFN_vkGetPhysicalDeviceFeatures2KHR>(
783             vkGetInstanceProcAddr(vulkan_instance_,
784                                   "vkGetPhysicalDeviceFeatures2KHR"));
785     vkGetPhysicalDeviceFeatures2KHR(physical_device, &features2);
786     available_features_ = features2.features;
787 
788     std::vector<std::string> required_features1;
789     for (const auto& feature : required_features) {
790       // No dot means this is a features1 feature.
791       if (feature.find_first_of('.') == std::string::npos) {
792         required_features1.push_back(feature);
793         continue;
794       }
795 
796       if ((feature == kVariablePointers &&
797            var_ptrs.variablePointers == VK_FALSE) ||
798           (feature == kVariablePointersStorageBuffer &&
799            var_ptrs.variablePointersStorageBuffer == VK_FALSE) ||
800           (feature == kSubgroupSizeControl &&
801            size_control.subgroupSizeControl == VK_FALSE) ||
802           (feature == kComputeFullSubgroups &&
803            size_control.computeFullSubgroups == VK_FALSE)) {
804         return amber::Result("Device does not support all required features");
805       }
806     }
807 
808     amber::Result r =
809         NamesToVulkanFeatures(required_features1, &required_vulkan_features);
810     if (!r.IsSuccess())
811       return r;
812 
813   } else {
814     amber::Result r =
815         NamesToVulkanFeatures(required_features, &required_vulkan_features);
816     if (!r.IsSuccess())
817       return r;
818 
819     vkGetPhysicalDeviceFeatures(physical_device, &available_features_);
820   }
821   if (!AreAllRequiredFeaturesSupported(available_features_,
822                                        required_vulkan_features)) {
823     return amber::Result("Device does not support all required features");
824   }
825 
826   available_device_extensions_ = GetAvailableDeviceExtensions(physical_device);
827   if (!AreAllExtensionsSupported(available_device_extensions_,
828                                  required_extensions)) {
829     return amber::Result("Device does not support all required extensions");
830   }
831   for (const auto& ext : available_device_extensions_) {
832     if (ext == "VK_KHR_shader_float16_int8")
833       supports_shader_float16_int8_ = true;
834     else if (ext == "VK_KHR_8bit_storage")
835       supports_shader_8bit_storage_ = true;
836     else if (ext == "VK_KHR_16bit_storage")
837       supports_shader_16bit_storage_ = true;
838     else if (ext == "VK_EXT_subgroup_size_control")
839       supports_subgroup_size_control_ = true;
840   }
841 
842   vulkan_queue_family_index_ = ChooseQueueFamilyIndex(physical_device);
843   if (vulkan_queue_family_index_ == std::numeric_limits<uint32_t>::max()) {
844     return amber::Result("Device does not support required queue flags");
845   }
846 
847   return {};
848 }
849 
ChooseVulkanPhysicalDevice(const std::vector<std::string> & required_features,const std::vector<std::string> & required_extensions,const int32_t selected_device)850 amber::Result ConfigHelperVulkan::ChooseVulkanPhysicalDevice(
851     const std::vector<std::string>& required_features,
852     const std::vector<std::string>& required_extensions,
853     const int32_t selected_device) {
854   uint32_t count = 0;
855   std::vector<VkPhysicalDevice> physical_devices;
856 
857   if (vkEnumeratePhysicalDevices(vulkan_instance_, &count, nullptr) !=
858       VK_SUCCESS) {
859     return amber::Result("Unable to enumerate physical devices");
860   }
861 
862   physical_devices.resize(count);
863   if (vkEnumeratePhysicalDevices(vulkan_instance_, &count,
864                                  physical_devices.data()) != VK_SUCCESS) {
865     return amber::Result("Unable to enumerate physical devices");
866   }
867 
868   if (selected_device > -1) {
869     uint32_t deviceID = static_cast<uint32_t>(selected_device);
870     if (deviceID >= count) {
871       return amber::Result("Unable to find Vulkan device with ID " +
872                            std::to_string(deviceID));
873     }
874     amber::Result r = CheckVulkanPhysicalDeviceRequirements(
875         physical_devices[deviceID], required_features, required_extensions);
876     if (!r.IsSuccess())
877       return r;
878     vulkan_physical_device_ = physical_devices[deviceID];
879     return {};
880   } else {
881     for (uint32_t i = 0; i < count; ++i) {
882       amber::Result r = CheckVulkanPhysicalDeviceRequirements(
883           physical_devices[i], required_features, required_extensions);
884       if (!r.IsSuccess())
885         continue;
886       vulkan_physical_device_ = physical_devices[i];
887       return {};
888     }
889   }
890 
891   std::ostringstream out;
892   out << "Unable to find Vulkan device supporting:" << std::endl;
893   for (const auto& str : required_features)
894     out << "  " << str << std::endl;
895   for (const auto& str : required_extensions)
896     out << "  " << str << std::endl;
897 
898   return amber::Result(out.str());
899 }
900 
CreateVulkanDevice(const std::vector<std::string> & required_features,const std::vector<std::string> & required_extensions)901 amber::Result ConfigHelperVulkan::CreateVulkanDevice(
902     const std::vector<std::string>& required_features,
903     const std::vector<std::string>& required_extensions) {
904   VkDeviceQueueCreateInfo queue_info = VkDeviceQueueCreateInfo();
905   const float priorities[] = {1.0f};
906 
907   queue_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
908   queue_info.queueFamilyIndex = vulkan_queue_family_index_;
909   queue_info.queueCount = 1;
910   queue_info.pQueuePriorities = priorities;
911 
912   std::vector<const char*> required_extensions_in_char;
913   std::transform(
914       required_extensions.begin(), required_extensions.end(),
915       std::back_inserter(required_extensions_in_char),
916       [](const std::string& ext) -> const char* { return ext.c_str(); });
917 
918   VkDeviceCreateInfo info = VkDeviceCreateInfo();
919   info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
920   info.pQueueCreateInfos = &queue_info;
921   info.queueCreateInfoCount = 1;
922   info.enabledExtensionCount =
923       static_cast<uint32_t>(required_extensions_in_char.size());
924   info.ppEnabledExtensionNames = required_extensions_in_char.data();
925 
926   if (supports_get_physical_device_properties2_)
927     return CreateDeviceWithFeatures2(required_features, &info);
928   return CreateDeviceWithFeatures1(required_features, &info);
929 }
930 
CreateDeviceWithFeatures1(const std::vector<std::string> & required_features,VkDeviceCreateInfo * info)931 amber::Result ConfigHelperVulkan::CreateDeviceWithFeatures1(
932     const std::vector<std::string>& required_features,
933     VkDeviceCreateInfo* info) {
934   VkPhysicalDeviceFeatures required_vulkan_features =
935       VkPhysicalDeviceFeatures();
936   amber::Result r =
937       NamesToVulkanFeatures(required_features, &required_vulkan_features);
938   if (!r.IsSuccess())
939     return r;
940 
941   info->pEnabledFeatures = &required_vulkan_features;
942   return DoCreateDevice(info);
943 }
944 
CreateDeviceWithFeatures2(const std::vector<std::string> & required_features,VkDeviceCreateInfo * info)945 amber::Result ConfigHelperVulkan::CreateDeviceWithFeatures2(
946     const std::vector<std::string>& required_features,
947     VkDeviceCreateInfo* info) {
948   variable_pointers_feature_.sType =
949       VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES_KHR;
950   variable_pointers_feature_.pNext = nullptr;
951 
952   float16_int8_feature_.sType =
953       VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT16_INT8_FEATURES_KHR;
954   float16_int8_feature_.pNext = nullptr;
955 
956   storage_8bit_feature_.sType =
957       VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES_KHR;
958   storage_8bit_feature_.pNext = nullptr;
959 
960   storage_16bit_feature_.sType =
961       VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES_KHR;
962   storage_16bit_feature_.pNext = nullptr;
963 
964   subgroup_size_control_feature_.sType =
965       VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_FEATURES_EXT;
966   subgroup_size_control_feature_.pNext = nullptr;
967 
968   void** next_ptr = &variable_pointers_feature_.pNext;
969 
970   if (supports_shader_float16_int8_) {
971     *next_ptr = &float16_int8_feature_;
972     next_ptr = &float16_int8_feature_.pNext;
973   }
974 
975   if (supports_shader_8bit_storage_) {
976     *next_ptr = &storage_8bit_feature_;
977     next_ptr = &storage_8bit_feature_.pNext;
978   }
979 
980   if (supports_shader_16bit_storage_) {
981     *next_ptr = &storage_16bit_feature_;
982     next_ptr = &storage_16bit_feature_.pNext;
983   }
984 
985   if (supports_subgroup_size_control_) {
986     *next_ptr = &subgroup_size_control_feature_;
987     next_ptr = &subgroup_size_control_feature_.pNext;
988   }
989 
990   available_features2_.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR;
991   available_features2_.pNext = &variable_pointers_feature_;
992 
993   std::vector<std::string> feature1_names;
994   for (const auto& feature : required_features) {
995     // No dot means this is a features1 feature.
996     if (feature.find_first_of('.') == std::string::npos) {
997       feature1_names.push_back(feature);
998       continue;
999     }
1000 
1001     if (feature == kVariablePointers)
1002       variable_pointers_feature_.variablePointers = VK_TRUE;
1003     else if (feature == kVariablePointersStorageBuffer)
1004       variable_pointers_feature_.variablePointersStorageBuffer = VK_TRUE;
1005     else if (feature == kFloat16Int8_Float16)
1006       float16_int8_feature_.shaderFloat16 = VK_TRUE;
1007     else if (feature == kFloat16Int8_Int8)
1008       float16_int8_feature_.shaderInt8 = VK_TRUE;
1009     else if (feature == k8BitStorage_Storage)
1010       storage_8bit_feature_.storageBuffer8BitAccess = VK_TRUE;
1011     else if (feature == k8BitStorage_UniformAndStorage)
1012       storage_8bit_feature_.uniformAndStorageBuffer8BitAccess = VK_TRUE;
1013     else if (feature == k8BitStorage_PushConstant)
1014       storage_8bit_feature_.storagePushConstant8 = VK_TRUE;
1015     else if (feature == k16BitStorage_Storage)
1016       storage_16bit_feature_.storageBuffer16BitAccess = VK_TRUE;
1017     else if (feature == k16BitStorage_UniformAndStorage)
1018       storage_16bit_feature_.uniformAndStorageBuffer16BitAccess = VK_TRUE;
1019     else if (feature == k16BitStorage_PushConstant)
1020       storage_16bit_feature_.storagePushConstant16 = VK_TRUE;
1021     else if (feature == k16BitStorage_InputOutput)
1022       storage_16bit_feature_.storageInputOutput16 = VK_TRUE;
1023     else if (feature == kSubgroupSizeControl)
1024       subgroup_size_control_feature_.subgroupSizeControl = VK_TRUE;
1025     else if (feature == kComputeFullSubgroups)
1026       subgroup_size_control_feature_.computeFullSubgroups = VK_TRUE;
1027   }
1028 
1029   VkPhysicalDeviceFeatures required_vulkan_features =
1030       VkPhysicalDeviceFeatures();
1031   amber::Result r =
1032       NamesToVulkanFeatures(feature1_names, &required_vulkan_features);
1033   if (!r.IsSuccess())
1034     return r;
1035 
1036   available_features2_.features = required_vulkan_features;
1037 
1038   info->pNext = &available_features2_;
1039   info->pEnabledFeatures = nullptr;
1040   return DoCreateDevice(info);
1041 }
1042 
DoCreateDevice(VkDeviceCreateInfo * info)1043 amber::Result ConfigHelperVulkan::DoCreateDevice(VkDeviceCreateInfo* info) {
1044   if (vkCreateDevice(vulkan_physical_device_, info, nullptr, &vulkan_device_) !=
1045       VK_SUCCESS) {
1046     return amber::Result("Unable to create vulkan device");
1047   }
1048   return {};
1049 }
1050 
DumpPhysicalDeviceInfo()1051 void ConfigHelperVulkan::DumpPhysicalDeviceInfo() {
1052   VkPhysicalDeviceProperties2KHR properties2 = {
1053       VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR,
1054       nullptr,  // pNext: will point to our driver_properties struct if the
1055                 // "VK_KHR_get_physical_device_properties2" and
1056                 // "VK_KHR_driver_properties" extensions are both available.
1057       {},  // properties: this is the older VkPhysicalDeviceProperties struct,
1058            // wrapped by this newer struct that adds the pNext member. We use
1059            // this older struct if the "VK_KHR_get_physical_device_properties2"
1060            // extension is unavailable.
1061   };
1062 
1063   VkPhysicalDeviceDriverPropertiesKHR driver_properties = {
1064       VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES_KHR,
1065       nullptr,
1066       {},
1067       {},
1068       {},
1069       {},
1070   };
1071 
1072   VkPhysicalDeviceSubgroupSizeControlPropertiesEXT
1073       subgroup_size_control_properties = {
1074           VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_PROPERTIES_EXT,  // NOLINT(whitespace/line_length)
1075           nullptr,
1076           {},
1077           {},
1078           {},
1079           {}};
1080 
1081   // If the vkGetPhysicalDeviceProperties2KHR function is unavailable (because
1082   // the "VK_KHR_get_physical_device_properties2" extension is unavailable or
1083   // because vkGetInstanceProcAddr failed) or the "VK_KHR_driver_properties"
1084   // extension is unavailable, then this will stay as nullptr and we will
1085   // instead call the older vkGetPhysicalDeviceProperties function.
1086   PFN_vkGetPhysicalDeviceProperties2KHR vkGetPhysicalDeviceProperties2KHR =
1087       nullptr;
1088 
1089   if (supports_get_physical_device_properties2_ &&
1090       std::find(available_device_extensions_.begin(),
1091                 available_device_extensions_.end(),
1092                 "VK_KHR_driver_properties") !=
1093           available_device_extensions_.end()) {
1094     properties2.pNext = &driver_properties;
1095 
1096     vkGetPhysicalDeviceProperties2KHR =
1097         reinterpret_cast<PFN_vkGetPhysicalDeviceProperties2KHR>(
1098             vkGetInstanceProcAddr(vulkan_instance_,
1099                                   "vkGetPhysicalDeviceProperties2KHR"));
1100     if (!vkGetPhysicalDeviceProperties2KHR) {
1101       std::cout << "Warning: device claimed to support "
1102                    "vkGetPhysicalDeviceProperties2KHR but could not find this "
1103                    "function."
1104                 << std::endl;
1105     }
1106     if (supports_subgroup_size_control_) {
1107       driver_properties.pNext = &subgroup_size_control_properties;
1108     }
1109   }
1110 
1111   if (vkGetPhysicalDeviceProperties2KHR) {
1112     vkGetPhysicalDeviceProperties2KHR(vulkan_physical_device_, &properties2);
1113   } else {
1114     vkGetPhysicalDeviceProperties(vulkan_physical_device_,
1115                                   &properties2.properties);
1116   }
1117 
1118   const VkPhysicalDeviceProperties& props = properties2.properties;
1119 
1120   uint32_t api_version = props.apiVersion;
1121 
1122   std::cout << std::endl;
1123   std::cout << "Physical device properties:" << std::endl;
1124   std::cout << "  apiVersion: " << static_cast<uint32_t>(api_version >> 22u)
1125             << "." << static_cast<uint32_t>((api_version >> 12u) & 0x3ffu)
1126             << "." << static_cast<uint32_t>(api_version & 0xfffu) << std::endl;
1127   std::cout << "  driverVersion: " << props.driverVersion << std::endl;
1128   std::cout << "  vendorID: " << props.vendorID << std::endl;
1129   std::cout << "  deviceID: " << props.deviceID << std::endl;
1130   std::cout << "  deviceType: " << deviceTypeToName(props.deviceType)
1131             << std::endl;
1132   std::cout << "  deviceName: " << props.deviceName << std::endl;
1133   if (vkGetPhysicalDeviceProperties2KHR) {
1134     std::cout << "  driverName: " << driver_properties.driverName << std::endl;
1135     std::cout << "  driverInfo: " << driver_properties.driverInfo << std::endl;
1136     if (supports_subgroup_size_control_) {
1137       std::cout << "  minSubgroupSize: "
1138                 << subgroup_size_control_properties.minSubgroupSize
1139                 << std::endl;
1140       std::cout << "  maxSubgroupSize: "
1141                 << subgroup_size_control_properties.maxSubgroupSize
1142                 << std::endl;
1143       std::cout << "  maxComputeWorkgroupSubgroups: "
1144                 << subgroup_size_control_properties.maxComputeWorkgroupSubgroups
1145                 << std::endl;
1146       std::cout << "  requiredSubgroupSizeStages: "
1147                 << stageFlagBitsToNames(subgroup_size_control_properties
1148                                             .requiredSubgroupSizeStages)
1149                 << std::endl;
1150     }
1151   }
1152   std::cout << "End of physical device properties." << std::endl;
1153 }
1154 
CreateConfig(uint32_t engine_major,uint32_t engine_minor,int32_t selected_device,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)1155 amber::Result ConfigHelperVulkan::CreateConfig(
1156     uint32_t engine_major,
1157     uint32_t engine_minor,
1158     int32_t selected_device,
1159     const std::vector<std::string>& required_features,
1160     const std::vector<std::string>& required_instance_extensions,
1161     const std::vector<std::string>& required_device_extensions,
1162     bool disable_validation_layer,
1163     bool show_version_info,
1164     std::unique_ptr<amber::EngineConfig>* cfg_holder) {
1165   amber::Result r = CreateVulkanInstance(engine_major, engine_minor,
1166                                          required_instance_extensions,
1167                                          disable_validation_layer);
1168   if (!r.IsSuccess())
1169     return r;
1170 
1171   if (!disable_validation_layer) {
1172     r = CreateDebugReportCallback();
1173     if (!r.IsSuccess())
1174       return r;
1175   }
1176 
1177   r = ChooseVulkanPhysicalDevice(required_features, required_device_extensions,
1178                                  selected_device);
1179   if (!r.IsSuccess())
1180     return r;
1181 
1182   if (show_version_info)
1183     DumpPhysicalDeviceInfo();
1184 
1185   r = CreateVulkanDevice(required_features, required_device_extensions);
1186   if (!r.IsSuccess())
1187     return r;
1188 
1189   vkGetDeviceQueue(vulkan_device_, vulkan_queue_family_index_, 0,
1190                    &vulkan_queue_);
1191 
1192   *cfg_holder =
1193       std::unique_ptr<amber::EngineConfig>(new amber::VulkanEngineConfig());
1194   amber::VulkanEngineConfig* config =
1195       static_cast<amber::VulkanEngineConfig*>(cfg_holder->get());
1196   config->physical_device = vulkan_physical_device_;
1197   config->available_features = available_features_;
1198   config->available_features2 = available_features2_;
1199   config->available_instance_extensions = available_instance_extensions_;
1200   config->available_device_extensions = available_device_extensions_;
1201   config->instance = vulkan_instance_;
1202   config->queue_family_index = vulkan_queue_family_index_;
1203   config->queue = vulkan_queue_;
1204   config->device = vulkan_device_;
1205   config->vkGetInstanceProcAddr = vkGetInstanceProcAddr;
1206 
1207   return {};
1208 }
1209 
1210 }  // namespace sample
1211