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