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