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