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