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