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 VkPhysicalDeviceFeatures required_vulkan_features =
762 VkPhysicalDeviceFeatures();
763
764 if (supports_get_physical_device_properties2_) {
765 VkPhysicalDeviceSubgroupSizeControlFeaturesEXT size_control =
766 VkPhysicalDeviceSubgroupSizeControlFeaturesEXT();
767 size_control.sType =
768 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_FEATURES_EXT;
769 size_control.pNext = nullptr;
770
771 VkPhysicalDeviceVariablePointerFeaturesKHR var_ptrs =
772 VkPhysicalDeviceVariablePointerFeaturesKHR();
773 var_ptrs.sType =
774 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES_KHR;
775 var_ptrs.pNext = &size_control;
776
777 VkPhysicalDeviceFeatures2KHR features2 = VkPhysicalDeviceFeatures2KHR();
778 features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR;
779 features2.pNext = &var_ptrs;
780
781 auto vkGetPhysicalDeviceFeatures2KHR =
782 reinterpret_cast<PFN_vkGetPhysicalDeviceFeatures2KHR>(
783 vkGetInstanceProcAddr(vulkan_instance_,
784 "vkGetPhysicalDeviceFeatures2KHR"));
785 vkGetPhysicalDeviceFeatures2KHR(physical_device, &features2);
786 available_features_ = features2.features;
787
788 std::vector<std::string> required_features1;
789 for (const auto& feature : required_features) {
790 // No dot means this is a features1 feature.
791 if (feature.find_first_of('.') == std::string::npos) {
792 required_features1.push_back(feature);
793 continue;
794 }
795
796 if ((feature == kVariablePointers &&
797 var_ptrs.variablePointers == VK_FALSE) ||
798 (feature == kVariablePointersStorageBuffer &&
799 var_ptrs.variablePointersStorageBuffer == VK_FALSE) ||
800 (feature == kSubgroupSizeControl &&
801 size_control.subgroupSizeControl == VK_FALSE) ||
802 (feature == kComputeFullSubgroups &&
803 size_control.computeFullSubgroups == VK_FALSE)) {
804 return amber::Result("Device does not support all required features");
805 }
806 }
807
808 amber::Result r =
809 NamesToVulkanFeatures(required_features1, &required_vulkan_features);
810 if (!r.IsSuccess())
811 return r;
812
813 } else {
814 amber::Result r =
815 NamesToVulkanFeatures(required_features, &required_vulkan_features);
816 if (!r.IsSuccess())
817 return r;
818
819 vkGetPhysicalDeviceFeatures(physical_device, &available_features_);
820 }
821 if (!AreAllRequiredFeaturesSupported(available_features_,
822 required_vulkan_features)) {
823 return amber::Result("Device does not support all required features");
824 }
825
826 available_device_extensions_ = GetAvailableDeviceExtensions(physical_device);
827 if (!AreAllExtensionsSupported(available_device_extensions_,
828 required_extensions)) {
829 return amber::Result("Device does not support all required extensions");
830 }
831 for (const auto& ext : available_device_extensions_) {
832 if (ext == "VK_KHR_shader_float16_int8")
833 supports_shader_float16_int8_ = true;
834 else if (ext == "VK_KHR_8bit_storage")
835 supports_shader_8bit_storage_ = true;
836 else if (ext == "VK_KHR_16bit_storage")
837 supports_shader_16bit_storage_ = true;
838 else if (ext == "VK_EXT_subgroup_size_control")
839 supports_subgroup_size_control_ = true;
840 }
841
842 vulkan_queue_family_index_ = ChooseQueueFamilyIndex(physical_device);
843 if (vulkan_queue_family_index_ == std::numeric_limits<uint32_t>::max()) {
844 return amber::Result("Device does not support required queue flags");
845 }
846
847 return {};
848 }
849
ChooseVulkanPhysicalDevice(const std::vector<std::string> & required_features,const std::vector<std::string> & required_extensions,const int32_t selected_device)850 amber::Result ConfigHelperVulkan::ChooseVulkanPhysicalDevice(
851 const std::vector<std::string>& required_features,
852 const std::vector<std::string>& required_extensions,
853 const int32_t selected_device) {
854 uint32_t count = 0;
855 std::vector<VkPhysicalDevice> physical_devices;
856
857 if (vkEnumeratePhysicalDevices(vulkan_instance_, &count, nullptr) !=
858 VK_SUCCESS) {
859 return amber::Result("Unable to enumerate physical devices");
860 }
861
862 physical_devices.resize(count);
863 if (vkEnumeratePhysicalDevices(vulkan_instance_, &count,
864 physical_devices.data()) != VK_SUCCESS) {
865 return amber::Result("Unable to enumerate physical devices");
866 }
867
868 if (selected_device > -1) {
869 uint32_t deviceID = static_cast<uint32_t>(selected_device);
870 if (deviceID >= count) {
871 return amber::Result("Unable to find Vulkan device with ID " +
872 std::to_string(deviceID));
873 }
874 amber::Result r = CheckVulkanPhysicalDeviceRequirements(
875 physical_devices[deviceID], required_features, required_extensions);
876 if (!r.IsSuccess())
877 return r;
878 vulkan_physical_device_ = physical_devices[deviceID];
879 return {};
880 } else {
881 for (uint32_t i = 0; i < count; ++i) {
882 amber::Result r = CheckVulkanPhysicalDeviceRequirements(
883 physical_devices[i], required_features, required_extensions);
884 if (!r.IsSuccess())
885 continue;
886 vulkan_physical_device_ = physical_devices[i];
887 return {};
888 }
889 }
890
891 std::ostringstream out;
892 out << "Unable to find Vulkan device supporting:" << std::endl;
893 for (const auto& str : required_features)
894 out << " " << str << std::endl;
895 for (const auto& str : required_extensions)
896 out << " " << str << std::endl;
897
898 return amber::Result(out.str());
899 }
900
CreateVulkanDevice(const std::vector<std::string> & required_features,const std::vector<std::string> & required_extensions)901 amber::Result ConfigHelperVulkan::CreateVulkanDevice(
902 const std::vector<std::string>& required_features,
903 const std::vector<std::string>& required_extensions) {
904 VkDeviceQueueCreateInfo queue_info = VkDeviceQueueCreateInfo();
905 const float priorities[] = {1.0f};
906
907 queue_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
908 queue_info.queueFamilyIndex = vulkan_queue_family_index_;
909 queue_info.queueCount = 1;
910 queue_info.pQueuePriorities = priorities;
911
912 std::vector<const char*> required_extensions_in_char;
913 std::transform(
914 required_extensions.begin(), required_extensions.end(),
915 std::back_inserter(required_extensions_in_char),
916 [](const std::string& ext) -> const char* { return ext.c_str(); });
917
918 VkDeviceCreateInfo info = VkDeviceCreateInfo();
919 info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
920 info.pQueueCreateInfos = &queue_info;
921 info.queueCreateInfoCount = 1;
922 info.enabledExtensionCount =
923 static_cast<uint32_t>(required_extensions_in_char.size());
924 info.ppEnabledExtensionNames = required_extensions_in_char.data();
925
926 if (supports_get_physical_device_properties2_)
927 return CreateDeviceWithFeatures2(required_features, &info);
928 return CreateDeviceWithFeatures1(required_features, &info);
929 }
930
CreateDeviceWithFeatures1(const std::vector<std::string> & required_features,VkDeviceCreateInfo * info)931 amber::Result ConfigHelperVulkan::CreateDeviceWithFeatures1(
932 const std::vector<std::string>& required_features,
933 VkDeviceCreateInfo* info) {
934 VkPhysicalDeviceFeatures required_vulkan_features =
935 VkPhysicalDeviceFeatures();
936 amber::Result r =
937 NamesToVulkanFeatures(required_features, &required_vulkan_features);
938 if (!r.IsSuccess())
939 return r;
940
941 info->pEnabledFeatures = &required_vulkan_features;
942 return DoCreateDevice(info);
943 }
944
CreateDeviceWithFeatures2(const std::vector<std::string> & required_features,VkDeviceCreateInfo * info)945 amber::Result ConfigHelperVulkan::CreateDeviceWithFeatures2(
946 const std::vector<std::string>& required_features,
947 VkDeviceCreateInfo* info) {
948 variable_pointers_feature_.sType =
949 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES_KHR;
950 variable_pointers_feature_.pNext = nullptr;
951
952 float16_int8_feature_.sType =
953 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT16_INT8_FEATURES_KHR;
954 float16_int8_feature_.pNext = nullptr;
955
956 storage_8bit_feature_.sType =
957 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES_KHR;
958 storage_8bit_feature_.pNext = nullptr;
959
960 storage_16bit_feature_.sType =
961 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES_KHR;
962 storage_16bit_feature_.pNext = nullptr;
963
964 subgroup_size_control_feature_.sType =
965 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_FEATURES_EXT;
966 subgroup_size_control_feature_.pNext = nullptr;
967
968 void** next_ptr = &variable_pointers_feature_.pNext;
969
970 if (supports_shader_float16_int8_) {
971 *next_ptr = &float16_int8_feature_;
972 next_ptr = &float16_int8_feature_.pNext;
973 }
974
975 if (supports_shader_8bit_storage_) {
976 *next_ptr = &storage_8bit_feature_;
977 next_ptr = &storage_8bit_feature_.pNext;
978 }
979
980 if (supports_shader_16bit_storage_) {
981 *next_ptr = &storage_16bit_feature_;
982 next_ptr = &storage_16bit_feature_.pNext;
983 }
984
985 if (supports_subgroup_size_control_) {
986 *next_ptr = &subgroup_size_control_feature_;
987 next_ptr = &subgroup_size_control_feature_.pNext;
988 }
989
990 available_features2_.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR;
991 available_features2_.pNext = &variable_pointers_feature_;
992
993 std::vector<std::string> feature1_names;
994 for (const auto& feature : required_features) {
995 // No dot means this is a features1 feature.
996 if (feature.find_first_of('.') == std::string::npos) {
997 feature1_names.push_back(feature);
998 continue;
999 }
1000
1001 if (feature == kVariablePointers)
1002 variable_pointers_feature_.variablePointers = VK_TRUE;
1003 else if (feature == kVariablePointersStorageBuffer)
1004 variable_pointers_feature_.variablePointersStorageBuffer = VK_TRUE;
1005 else if (feature == kFloat16Int8_Float16)
1006 float16_int8_feature_.shaderFloat16 = VK_TRUE;
1007 else if (feature == kFloat16Int8_Int8)
1008 float16_int8_feature_.shaderInt8 = VK_TRUE;
1009 else if (feature == k8BitStorage_Storage)
1010 storage_8bit_feature_.storageBuffer8BitAccess = VK_TRUE;
1011 else if (feature == k8BitStorage_UniformAndStorage)
1012 storage_8bit_feature_.uniformAndStorageBuffer8BitAccess = VK_TRUE;
1013 else if (feature == k8BitStorage_PushConstant)
1014 storage_8bit_feature_.storagePushConstant8 = VK_TRUE;
1015 else if (feature == k16BitStorage_Storage)
1016 storage_16bit_feature_.storageBuffer16BitAccess = VK_TRUE;
1017 else if (feature == k16BitStorage_UniformAndStorage)
1018 storage_16bit_feature_.uniformAndStorageBuffer16BitAccess = VK_TRUE;
1019 else if (feature == k16BitStorage_PushConstant)
1020 storage_16bit_feature_.storagePushConstant16 = VK_TRUE;
1021 else if (feature == k16BitStorage_InputOutput)
1022 storage_16bit_feature_.storageInputOutput16 = VK_TRUE;
1023 else if (feature == kSubgroupSizeControl)
1024 subgroup_size_control_feature_.subgroupSizeControl = VK_TRUE;
1025 else if (feature == kComputeFullSubgroups)
1026 subgroup_size_control_feature_.computeFullSubgroups = VK_TRUE;
1027 }
1028
1029 VkPhysicalDeviceFeatures required_vulkan_features =
1030 VkPhysicalDeviceFeatures();
1031 amber::Result r =
1032 NamesToVulkanFeatures(feature1_names, &required_vulkan_features);
1033 if (!r.IsSuccess())
1034 return r;
1035
1036 available_features2_.features = required_vulkan_features;
1037
1038 info->pNext = &available_features2_;
1039 info->pEnabledFeatures = nullptr;
1040 return DoCreateDevice(info);
1041 }
1042
DoCreateDevice(VkDeviceCreateInfo * info)1043 amber::Result ConfigHelperVulkan::DoCreateDevice(VkDeviceCreateInfo* info) {
1044 if (vkCreateDevice(vulkan_physical_device_, info, nullptr, &vulkan_device_) !=
1045 VK_SUCCESS) {
1046 return amber::Result("Unable to create vulkan device");
1047 }
1048 return {};
1049 }
1050
DumpPhysicalDeviceInfo()1051 void ConfigHelperVulkan::DumpPhysicalDeviceInfo() {
1052 VkPhysicalDeviceProperties2KHR properties2 = {
1053 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR,
1054 nullptr, // pNext: will point to our driver_properties struct if the
1055 // "VK_KHR_get_physical_device_properties2" and
1056 // "VK_KHR_driver_properties" extensions are both available.
1057 {}, // properties: this is the older VkPhysicalDeviceProperties struct,
1058 // wrapped by this newer struct that adds the pNext member. We use
1059 // this older struct if the "VK_KHR_get_physical_device_properties2"
1060 // extension is unavailable.
1061 };
1062
1063 VkPhysicalDeviceDriverPropertiesKHR driver_properties = {
1064 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES_KHR,
1065 nullptr,
1066 {},
1067 {},
1068 {},
1069 {},
1070 };
1071
1072 VkPhysicalDeviceSubgroupSizeControlPropertiesEXT
1073 subgroup_size_control_properties = {
1074 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_PROPERTIES_EXT, // NOLINT(whitespace/line_length)
1075 nullptr,
1076 {},
1077 {},
1078 {},
1079 {}};
1080
1081 // If the vkGetPhysicalDeviceProperties2KHR function is unavailable (because
1082 // the "VK_KHR_get_physical_device_properties2" extension is unavailable or
1083 // because vkGetInstanceProcAddr failed) or the "VK_KHR_driver_properties"
1084 // extension is unavailable, then this will stay as nullptr and we will
1085 // instead call the older vkGetPhysicalDeviceProperties function.
1086 PFN_vkGetPhysicalDeviceProperties2KHR vkGetPhysicalDeviceProperties2KHR =
1087 nullptr;
1088
1089 if (supports_get_physical_device_properties2_ &&
1090 std::find(available_device_extensions_.begin(),
1091 available_device_extensions_.end(),
1092 "VK_KHR_driver_properties") !=
1093 available_device_extensions_.end()) {
1094 properties2.pNext = &driver_properties;
1095
1096 vkGetPhysicalDeviceProperties2KHR =
1097 reinterpret_cast<PFN_vkGetPhysicalDeviceProperties2KHR>(
1098 vkGetInstanceProcAddr(vulkan_instance_,
1099 "vkGetPhysicalDeviceProperties2KHR"));
1100 if (!vkGetPhysicalDeviceProperties2KHR) {
1101 std::cout << "Warning: device claimed to support "
1102 "vkGetPhysicalDeviceProperties2KHR but could not find this "
1103 "function."
1104 << std::endl;
1105 }
1106 if (supports_subgroup_size_control_) {
1107 driver_properties.pNext = &subgroup_size_control_properties;
1108 }
1109 }
1110
1111 if (vkGetPhysicalDeviceProperties2KHR) {
1112 vkGetPhysicalDeviceProperties2KHR(vulkan_physical_device_, &properties2);
1113 } else {
1114 vkGetPhysicalDeviceProperties(vulkan_physical_device_,
1115 &properties2.properties);
1116 }
1117
1118 const VkPhysicalDeviceProperties& props = properties2.properties;
1119
1120 uint32_t api_version = props.apiVersion;
1121
1122 std::cout << std::endl;
1123 std::cout << "Physical device properties:" << std::endl;
1124 std::cout << " apiVersion: " << static_cast<uint32_t>(api_version >> 22u)
1125 << "." << static_cast<uint32_t>((api_version >> 12u) & 0x3ffu)
1126 << "." << static_cast<uint32_t>(api_version & 0xfffu) << std::endl;
1127 std::cout << " driverVersion: " << props.driverVersion << std::endl;
1128 std::cout << " vendorID: " << props.vendorID << std::endl;
1129 std::cout << " deviceID: " << props.deviceID << std::endl;
1130 std::cout << " deviceType: " << deviceTypeToName(props.deviceType)
1131 << std::endl;
1132 std::cout << " deviceName: " << props.deviceName << std::endl;
1133 if (vkGetPhysicalDeviceProperties2KHR) {
1134 std::cout << " driverName: " << driver_properties.driverName << std::endl;
1135 std::cout << " driverInfo: " << driver_properties.driverInfo << std::endl;
1136 if (supports_subgroup_size_control_) {
1137 std::cout << " minSubgroupSize: "
1138 << subgroup_size_control_properties.minSubgroupSize
1139 << std::endl;
1140 std::cout << " maxSubgroupSize: "
1141 << subgroup_size_control_properties.maxSubgroupSize
1142 << std::endl;
1143 std::cout << " maxComputeWorkgroupSubgroups: "
1144 << subgroup_size_control_properties.maxComputeWorkgroupSubgroups
1145 << std::endl;
1146 std::cout << " requiredSubgroupSizeStages: "
1147 << stageFlagBitsToNames(subgroup_size_control_properties
1148 .requiredSubgroupSizeStages)
1149 << std::endl;
1150 }
1151 }
1152 std::cout << "End of physical device properties." << std::endl;
1153 }
1154
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)1155 amber::Result ConfigHelperVulkan::CreateConfig(
1156 uint32_t engine_major,
1157 uint32_t engine_minor,
1158 int32_t selected_device,
1159 const std::vector<std::string>& required_features,
1160 const std::vector<std::string>& required_instance_extensions,
1161 const std::vector<std::string>& required_device_extensions,
1162 bool disable_validation_layer,
1163 bool show_version_info,
1164 std::unique_ptr<amber::EngineConfig>* cfg_holder) {
1165 amber::Result r = CreateVulkanInstance(engine_major, engine_minor,
1166 required_instance_extensions,
1167 disable_validation_layer);
1168 if (!r.IsSuccess())
1169 return r;
1170
1171 if (!disable_validation_layer) {
1172 r = CreateDebugReportCallback();
1173 if (!r.IsSuccess())
1174 return r;
1175 }
1176
1177 r = ChooseVulkanPhysicalDevice(required_features, required_device_extensions,
1178 selected_device);
1179 if (!r.IsSuccess())
1180 return r;
1181
1182 if (show_version_info)
1183 DumpPhysicalDeviceInfo();
1184
1185 r = CreateVulkanDevice(required_features, required_device_extensions);
1186 if (!r.IsSuccess())
1187 return r;
1188
1189 vkGetDeviceQueue(vulkan_device_, vulkan_queue_family_index_, 0,
1190 &vulkan_queue_);
1191
1192 *cfg_holder =
1193 std::unique_ptr<amber::EngineConfig>(new amber::VulkanEngineConfig());
1194 amber::VulkanEngineConfig* config =
1195 static_cast<amber::VulkanEngineConfig*>(cfg_holder->get());
1196 config->physical_device = vulkan_physical_device_;
1197 config->available_features = available_features_;
1198 config->available_features2 = available_features2_;
1199 config->available_instance_extensions = available_instance_extensions_;
1200 config->available_device_extensions = available_device_extensions_;
1201 config->instance = vulkan_instance_;
1202 config->queue_family_index = vulkan_queue_family_index_;
1203 config->queue = vulkan_queue_;
1204 config->device = vulkan_device_;
1205 config->vkGetInstanceProcAddr = vkGetInstanceProcAddr;
1206
1207 return {};
1208 }
1209
1210 } // namespace sample
1211