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