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