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