• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2018 The Amber Authors.
2 // Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //     http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 
16 #include "src/vulkan/device.h"
17 
18 #include <algorithm>
19 #include <cstring>
20 #include <iomanip>  // Vulkan wrappers: std::setw(), std::left/right
21 #include <iostream>
22 #include <memory>
23 #include <set>
24 #include <sstream>
25 #include <string>
26 #include <vector>
27 
28 #include "src/make_unique.h"
29 
30 namespace amber {
31 namespace vulkan {
32 namespace {
33 
34 const char kVariablePointers[] = "VariablePointerFeatures.variablePointers";
35 const char kVariablePointersStorageBuffer[] =
36     "VariablePointerFeatures.variablePointersStorageBuffer";
37 const char kFloat16Int8_Float16[] = "Float16Int8Features.shaderFloat16";
38 const char kFloat16Int8_Int8[] = "Float16Int8Features.shaderInt8";
39 const char k8BitStorage_Storage[] =
40     "Storage8BitFeatures.storageBuffer8BitAccess";
41 const char k8BitStorage_UniformAndStorage[] =
42     "Storage8BitFeatures.uniformAndStorageBuffer8BitAccess";
43 const char k8BitStorage_PushConstant[] =
44     "Storage8BitFeatures.storagePushConstant8";
45 const char k16BitStorage_Storage[] =
46     "Storage16BitFeatures.storageBuffer16BitAccess";
47 const char k16BitStorage_UniformAndStorage[] =
48     "Storage16BitFeatures.uniformAndStorageBuffer16BitAccess";
49 const char k16BitStorage_PushConstant[] =
50     "Storage16BitFeatures.storagePushConstant16";
51 const char k16BitStorage_InputOutput[] =
52     "Storage16BitFeatures.storageInputOutput16";
53 
54 const char kSubgroupSizeControl[] = "SubgroupSizeControl.subgroupSizeControl";
55 const char kComputeFullSubgroups[] = "SubgroupSizeControl.computeFullSubgroups";
56 
57 const char kSubgroupSupportedOperations[] = "SubgroupSupportedOperations";
58 const char kSubgroupSupportedOperationsBasic[] =
59     "SubgroupSupportedOperations.basic";
60 const char kSubgroupSupportedOperationsVote[] =
61     "SubgroupSupportedOperations.vote";
62 const char kSubgroupSupportedOperationsArithmetic[] =
63     "SubgroupSupportedOperations.arithmetic";
64 const char kSubgroupSupportedOperationsBallot[] =
65     "SubgroupSupportedOperations.ballot";
66 const char kSubgroupSupportedOperationsShuffle[] =
67     "SubgroupSupportedOperations.shuffle";
68 const char kSubgroupSupportedOperationsShuffleRelative[] =
69     "SubgroupSupportedOperations.shuffleRelative";
70 const char kSubgroupSupportedOperationsClustered[] =
71     "SubgroupSupportedOperations.clustered";
72 const char kSubgroupSupportedOperationsQuad[] =
73     "SubgroupSupportedOperations.quad";
74 const char kSubgroupSupportedStages[] = "SubgroupSupportedStages";
75 const char kSubgroupSupportedStagesVertex[] = "SubgroupSupportedStages.vertex";
76 const char kSubgroupSupportedStagesTessellationControl[] =
77     "SubgroupSupportedStages.tessellationControl";
78 const char kSubgroupSupportedStagesTessellationEvaluation[] =
79     "SubgroupSupportedStages.tessellationEvaluation";
80 const char kSubgroupSupportedStagesGeometry[] =
81     "SubgroupSupportedStages.geometry";
82 const char kSubgroupSupportedStagesFragment[] =
83     "SubgroupSupportedStages.fragment";
84 const char kSubgroupSupportedStagesCompute[] =
85     "SubgroupSupportedStages.compute";
86 
87 const char kShaderSubgroupExtendedTypes[] =
88     "ShaderSubgroupExtendedTypesFeatures.shaderSubgroupExtendedTypes";
89 
90 const char kIndexTypeUint8[] = "IndexTypeUint8Features.indexTypeUint8";
91 
92 const char kAccelerationStructure[] =
93     "AccelerationStructureFeaturesKHR.accelerationStructure";
94 const char kBufferDeviceAddress[] =
95     "BufferDeviceAddressFeatures.bufferDeviceAddress";
96 const char kRayTracingPipeline[] =
97     "RayTracingPipelineFeaturesKHR.rayTracingPipeline";
98 
99 struct BaseOutStructure {
100   VkStructureType sType;
101   void* pNext;
102 };
103 
AreAllRequiredFeaturesSupported(const VkPhysicalDeviceFeatures & available_features,const std::vector<std::string> & required_features)104 bool AreAllRequiredFeaturesSupported(
105     const VkPhysicalDeviceFeatures& available_features,
106     const std::vector<std::string>& required_features) {
107   if (required_features.empty())
108     return true;
109 
110   for (const auto& feature : required_features) {
111     if (feature == "robustBufferAccess") {
112       if (available_features.robustBufferAccess == VK_FALSE)
113         return false;
114       continue;
115     }
116     if (feature == "fullDrawIndexUint32") {
117       if (available_features.fullDrawIndexUint32 == VK_FALSE)
118         return false;
119       continue;
120     }
121     if (feature == "imageCubeArray") {
122       if (available_features.imageCubeArray == VK_FALSE)
123         return false;
124       continue;
125     }
126     if (feature == "independentBlend") {
127       if (available_features.independentBlend == VK_FALSE)
128         return false;
129       continue;
130     }
131     if (feature == "geometryShader") {
132       if (available_features.geometryShader == VK_FALSE)
133         return false;
134       continue;
135     }
136     if (feature == "tessellationShader") {
137       if (available_features.tessellationShader == VK_FALSE)
138         return false;
139       continue;
140     }
141     if (feature == "sampleRateShading") {
142       if (available_features.sampleRateShading == VK_FALSE)
143         return false;
144       continue;
145     }
146     if (feature == "dualSrcBlend") {
147       if (available_features.dualSrcBlend == VK_FALSE)
148         return false;
149       continue;
150     }
151     if (feature == "logicOp") {
152       if (available_features.logicOp == VK_FALSE)
153         return false;
154       continue;
155     }
156     if (feature == "multiDrawIndirect") {
157       if (available_features.multiDrawIndirect == VK_FALSE)
158         return false;
159       continue;
160     }
161     if (feature == "drawIndirectFirstInstance") {
162       if (available_features.drawIndirectFirstInstance == VK_FALSE)
163         return false;
164       continue;
165     }
166     if (feature == "depthClamp") {
167       if (available_features.depthClamp == VK_FALSE)
168         return false;
169       continue;
170     }
171     if (feature == "depthBiasClamp") {
172       if (available_features.depthBiasClamp == VK_FALSE)
173         return false;
174       continue;
175     }
176     if (feature == "fillModeNonSolid") {
177       if (available_features.fillModeNonSolid == VK_FALSE)
178         return false;
179       continue;
180     }
181     if (feature == "depthBounds") {
182       if (available_features.depthBounds == VK_FALSE)
183         return false;
184       continue;
185     }
186     if (feature == "wideLines") {
187       if (available_features.wideLines == VK_FALSE)
188         return false;
189       continue;
190     }
191     if (feature == "largePoints") {
192       if (available_features.largePoints == VK_FALSE)
193         return false;
194       continue;
195     }
196     if (feature == "alphaToOne") {
197       if (available_features.alphaToOne == VK_FALSE)
198         return false;
199       continue;
200     }
201     if (feature == "multiViewport") {
202       if (available_features.multiViewport == VK_FALSE)
203         return false;
204       continue;
205     }
206     if (feature == "samplerAnisotropy") {
207       if (available_features.samplerAnisotropy == VK_FALSE)
208         return false;
209       continue;
210     }
211     if (feature == "textureCompressionETC2") {
212       if (available_features.textureCompressionETC2 == VK_FALSE)
213         return false;
214       continue;
215     }
216     if (feature == "textureCompressionASTC_LDR") {
217       if (available_features.textureCompressionASTC_LDR == VK_FALSE)
218         return false;
219       continue;
220     }
221     if (feature == "textureCompressionBC") {
222       if (available_features.textureCompressionBC == VK_FALSE)
223         return false;
224       continue;
225     }
226     if (feature == "occlusionQueryPrecise") {
227       if (available_features.occlusionQueryPrecise == VK_FALSE)
228         return false;
229       continue;
230     }
231     if (feature == "pipelineStatisticsQuery") {
232       if (available_features.pipelineStatisticsQuery == VK_FALSE)
233         return false;
234       continue;
235     }
236     if (feature == "vertexPipelineStoresAndAtomics") {
237       if (available_features.vertexPipelineStoresAndAtomics == VK_FALSE)
238         return false;
239       continue;
240     }
241     if (feature == "fragmentStoresAndAtomics") {
242       if (available_features.fragmentStoresAndAtomics == VK_FALSE)
243         return false;
244       continue;
245     }
246     if (feature == "shaderTessellationAndGeometryPointSize") {
247       if (available_features.shaderTessellationAndGeometryPointSize == VK_FALSE)
248         return false;
249       continue;
250     }
251     if (feature == "shaderImageGatherExtended") {
252       if (available_features.shaderImageGatherExtended == VK_FALSE)
253         return false;
254       continue;
255     }
256     if (feature == "shaderStorageImageExtendedFormats") {
257       if (available_features.shaderStorageImageExtendedFormats == VK_FALSE)
258         return false;
259       continue;
260     }
261     if (feature == "shaderStorageImageMultisample") {
262       if (available_features.shaderStorageImageMultisample == VK_FALSE)
263         return false;
264       continue;
265     }
266     if (feature == "shaderStorageImageReadWithoutFormat") {
267       if (available_features.shaderStorageImageReadWithoutFormat == VK_FALSE)
268         return false;
269       continue;
270     }
271     if (feature == "shaderStorageImageWriteWithoutFormat") {
272       if (available_features.shaderStorageImageWriteWithoutFormat == VK_FALSE)
273         return false;
274       continue;
275     }
276     if (feature == "shaderUniformBufferArrayDynamicIndexing") {
277       if (available_features.shaderUniformBufferArrayDynamicIndexing ==
278           VK_FALSE)
279         return false;
280       continue;
281     }
282     if (feature == "shaderSampledImageArrayDynamicIndexing") {
283       if (available_features.shaderSampledImageArrayDynamicIndexing == VK_FALSE)
284         return false;
285       continue;
286     }
287     if (feature == "shaderStorageBufferArrayDynamicIndexing") {
288       if (available_features.shaderStorageBufferArrayDynamicIndexing ==
289           VK_FALSE)
290         return false;
291       continue;
292     }
293     if (feature == "shaderStorageImageArrayDynamicIndexing") {
294       if (available_features.shaderStorageImageArrayDynamicIndexing == VK_FALSE)
295         return false;
296       continue;
297     }
298     if (feature == "shaderClipDistance") {
299       if (available_features.shaderClipDistance == VK_FALSE)
300         return false;
301       continue;
302     }
303     if (feature == "shaderCullDistance") {
304       if (available_features.shaderCullDistance == VK_FALSE)
305         return false;
306       continue;
307     }
308     if (feature == "shaderFloat64") {
309       if (available_features.shaderFloat64 == VK_FALSE)
310         return false;
311       continue;
312     }
313     if (feature == "shaderInt64") {
314       if (available_features.shaderInt64 == VK_FALSE)
315         return false;
316       continue;
317     }
318     if (feature == "shaderInt16") {
319       if (available_features.shaderInt16 == VK_FALSE)
320         return false;
321       continue;
322     }
323     if (feature == "shaderResourceResidency") {
324       if (available_features.shaderResourceResidency == VK_FALSE)
325         return false;
326       continue;
327     }
328     if (feature == "shaderResourceMinLod") {
329       if (available_features.shaderResourceMinLod == VK_FALSE)
330         return false;
331       continue;
332     }
333     if (feature == "sparseBinding") {
334       if (available_features.sparseBinding == VK_FALSE)
335         return false;
336       continue;
337     }
338     if (feature == "sparseResidencyBuffer") {
339       if (available_features.sparseResidencyBuffer == VK_FALSE)
340         return false;
341       continue;
342     }
343     if (feature == "sparseResidencyImage2D") {
344       if (available_features.sparseResidencyImage2D == VK_FALSE)
345         return false;
346       continue;
347     }
348     if (feature == "sparseResidencyImage3D") {
349       if (available_features.sparseResidencyImage3D == VK_FALSE)
350         return false;
351       continue;
352     }
353     if (feature == "sparseResidency2Samples") {
354       if (available_features.sparseResidency2Samples == VK_FALSE)
355         return false;
356       continue;
357     }
358     if (feature == "sparseResidency4Samples") {
359       if (available_features.sparseResidency4Samples == VK_FALSE)
360         return false;
361       continue;
362     }
363     if (feature == "sparseResidency8Samples") {
364       if (available_features.sparseResidency8Samples == VK_FALSE)
365         return false;
366       continue;
367     }
368     if (feature == "sparseResidency16Samples") {
369       if (available_features.sparseResidency16Samples == VK_FALSE)
370         return false;
371       continue;
372     }
373     if (feature == "sparseResidencyAliased") {
374       if (available_features.sparseResidencyAliased == VK_FALSE)
375         return false;
376       continue;
377     }
378     if (feature == "variableMultisampleRate") {
379       if (available_features.variableMultisampleRate == VK_FALSE)
380         return false;
381       continue;
382     }
383     if (feature == "inheritedQueries") {
384       if (available_features.inheritedQueries == VK_FALSE)
385         return false;
386       continue;
387     }
388   }
389 
390   return true;
391 }
392 
AreAllExtensionsSupported(const std::vector<std::string> & available_extensions,const std::vector<std::string> & required_extensions)393 bool AreAllExtensionsSupported(
394     const std::vector<std::string>& available_extensions,
395     const std::vector<std::string>& required_extensions) {
396   if (required_extensions.empty())
397     return true;
398 
399   std::set<std::string> required_extension_set(required_extensions.begin(),
400                                                required_extensions.end());
401   for (const auto& extension : available_extensions) {
402     required_extension_set.erase(extension);
403   }
404 
405   return required_extension_set.empty();
406 }
407 
408 }  // namespace
409 
Device(VkInstance instance,VkPhysicalDevice physical_device,uint32_t queue_family_index,VkDevice device,VkQueue queue,Delegate * delegate)410 Device::Device(VkInstance instance,
411                VkPhysicalDevice physical_device,
412                uint32_t queue_family_index,
413                VkDevice device,
414                VkQueue queue,
415                Delegate* delegate)
416     : instance_(instance),
417       physical_device_(physical_device),
418       device_(device),
419       queue_(queue),
420       queue_family_index_(queue_family_index),
421       delegate_(delegate) {}
422 
423 Device::~Device() = default;
424 
LoadVulkanPointers(PFN_vkGetInstanceProcAddr getInstanceProcAddr,Delegate * delegate)425 Result Device::LoadVulkanPointers(PFN_vkGetInstanceProcAddr getInstanceProcAddr,
426                                   Delegate* delegate) {
427   // Note: logging Vulkan calls is done via the delegate rather than a Vulkan
428   // layer because we want such logging even when Amber is built as a native
429   // executable on Android, where Vulkan layers are usable only with APKs.
430   if (delegate && delegate->LogGraphicsCalls())
431     delegate->Log("Loading Vulkan Pointers");
432 
433 #include "vk-wrappers-1-0.inc"
434 
435   ptrs_.vkGetPhysicalDeviceProperties(physical_device_,
436                                       &physical_device_properties_);
437 
438   if (SupportsApiVersion(1, 1, 0)) {
439 #include "vk-wrappers-1-1.inc"
440   }
441 
442   return {};
443 }
444 
SupportsApiVersion(uint32_t major,uint32_t minor,uint32_t patch)445 bool Device::SupportsApiVersion(uint32_t major,
446                                 uint32_t minor,
447                                 uint32_t patch) {
448 #pragma clang diagnostic push
449 #pragma clang diagnostic ignored "-Wold-style-cast"
450   return physical_device_properties_.apiVersion >=
451          VK_MAKE_VERSION(major, minor, patch);
452 #pragma clang diagnostic pop
453 }
454 
ReportExecutionTiming(double time_in_ms)455 void Device::ReportExecutionTiming(double time_in_ms) {
456   if (delegate_) {
457     delegate_->ReportExecutionTiming(time_in_ms);
458   }
459 }
460 
Initialize(PFN_vkGetInstanceProcAddr getInstanceProcAddr,const std::vector<std::string> & required_features,const std::vector<std::string> & required_properties,const std::vector<std::string> & required_device_extensions,const VkPhysicalDeviceFeatures & available_features,const VkPhysicalDeviceFeatures2KHR & available_features2,const VkPhysicalDeviceProperties2KHR & available_properties2,const std::vector<std::string> & available_extensions)461 Result Device::Initialize(
462     PFN_vkGetInstanceProcAddr getInstanceProcAddr,
463     const std::vector<std::string>& required_features,
464     const std::vector<std::string>& required_properties,
465     const std::vector<std::string>& required_device_extensions,
466     const VkPhysicalDeviceFeatures& available_features,
467     const VkPhysicalDeviceFeatures2KHR& available_features2,
468     const VkPhysicalDeviceProperties2KHR& available_properties2,
469     const std::vector<std::string>& available_extensions) {
470   Result r = LoadVulkanPointers(getInstanceProcAddr, delegate_);
471   if (!r.IsSuccess())
472     return r;
473 
474   // Check for the core features. We don't know if available_features or
475   // available_features2 is provided, so check both.
476   if (!AreAllRequiredFeaturesSupported(available_features, required_features) &&
477       !AreAllRequiredFeaturesSupported(available_features2.features,
478                                        required_features)) {
479     return Result(
480         "Vulkan: Device::Initialize given physical device does not support "
481         "required features");
482   }
483 
484   // Search for additional features in case they are found in pNext field of
485   // available_features2.
486   VkPhysicalDeviceVariablePointerFeaturesKHR* var_ptrs = nullptr;
487   VkPhysicalDeviceFloat16Int8FeaturesKHR* float16_ptrs = nullptr;
488   VkPhysicalDevice8BitStorageFeaturesKHR* storage8_ptrs = nullptr;
489   VkPhysicalDevice16BitStorageFeaturesKHR* storage16_ptrs = nullptr;
490   VkPhysicalDeviceVulkan11Features* vulkan11_ptrs = nullptr;
491   VkPhysicalDeviceVulkan12Features* vulkan12_ptrs = nullptr;
492   VkPhysicalDeviceVulkan13Features* vulkan13_ptrs = nullptr;
493   VkPhysicalDeviceVulkan14Features* vulkan14_ptrs = nullptr;
494   VkPhysicalDeviceSubgroupSizeControlFeaturesEXT*
495       subgroup_size_control_features = nullptr;
496   VkPhysicalDeviceShaderSubgroupExtendedTypesFeatures*
497       shader_subgroup_extended_types_ptrs = nullptr;
498   VkPhysicalDeviceIndexTypeUint8FeaturesEXT* index_type_uint8_ptrs = nullptr;
499   VkPhysicalDeviceAccelerationStructureFeaturesKHR*
500       acceleration_structure_ptrs = nullptr;
501   VkPhysicalDeviceBufferDeviceAddressFeatures* bda_ptrs = nullptr;
502   VkPhysicalDeviceRayTracingPipelineFeaturesKHR* ray_tracing_pipeline_ptrs =
503       nullptr;
504 
505   void* ptr = available_features2.pNext;
506   while (ptr != nullptr) {
507     BaseOutStructure* s = static_cast<BaseOutStructure*>(ptr);
508     switch (s->sType) {
509       case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES_KHR:
510         var_ptrs =
511             static_cast<VkPhysicalDeviceVariablePointerFeaturesKHR*>(ptr);
512         break;
513       case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT16_INT8_FEATURES_KHR:
514         float16_ptrs =
515             static_cast<VkPhysicalDeviceFloat16Int8FeaturesKHR*>(ptr);
516         break;
517       case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES_KHR:
518         storage8_ptrs =
519             static_cast<VkPhysicalDevice8BitStorageFeaturesKHR*>(ptr);
520         break;
521       case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES_KHR:
522         storage16_ptrs =
523             static_cast<VkPhysicalDevice16BitStorageFeaturesKHR*>(ptr);
524         break;
525       case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_FEATURES_EXT:
526         subgroup_size_control_features =
527             static_cast<VkPhysicalDeviceSubgroupSizeControlFeaturesEXT*>(ptr);
528         break;
529       // NOLINTNEXTLINE(whitespace/line_length)
530       case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_EXTENDED_TYPES_FEATURES:
531         shader_subgroup_extended_types_ptrs =
532             static_cast<VkPhysicalDeviceShaderSubgroupExtendedTypesFeatures*>(
533                 ptr);
534         break;
535       case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INDEX_TYPE_UINT8_FEATURES_EXT:
536         index_type_uint8_ptrs =
537             static_cast<VkPhysicalDeviceIndexTypeUint8FeaturesEXT*>(ptr);
538         break;
539       // NOLINTNEXTLINE(whitespace/line_length)
540       case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR:
541         acceleration_structure_ptrs =
542             static_cast<VkPhysicalDeviceAccelerationStructureFeaturesKHR*>(ptr);
543         break;
544       case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES:
545         bda_ptrs =
546             static_cast<VkPhysicalDeviceBufferDeviceAddressFeatures*>(ptr);
547         break;
548       case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR:
549         ray_tracing_pipeline_ptrs =
550             static_cast<VkPhysicalDeviceRayTracingPipelineFeaturesKHR*>(ptr);
551         break;
552       case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES:
553         vulkan11_ptrs = static_cast<VkPhysicalDeviceVulkan11Features*>(ptr);
554         break;
555       case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES:
556         vulkan12_ptrs = static_cast<VkPhysicalDeviceVulkan12Features*>(ptr);
557         break;
558       case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES:
559         vulkan13_ptrs = static_cast<VkPhysicalDeviceVulkan13Features*>(ptr);
560         break;
561       case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_4_FEATURES:
562         vulkan14_ptrs = static_cast<VkPhysicalDeviceVulkan14Features*>(ptr);
563         break;
564       default:
565         break;
566     }
567     ptr = s->pNext;
568   }
569 
570   // Compare the available additional (non-core) features against the
571   // requirements.
572   //
573   // Vulkan 1.2 added support for defining non-core physical device features
574   // using VkPhysicalDeviceVulkan11Features and VkPhysicalDeviceVulkan12Features
575   // structures. If |vulkan11_ptrs| and/or |vulkan12_ptrs| are null, we must
576   // check for features using the old approach (by checking across various
577   // feature structs); otherwise, we can check features via the new structs.
578   for (const auto& feature : required_features) {
579     // First check the feature structures are provided for the required
580     // features.
581     if ((feature == kVariablePointers ||
582          feature == kVariablePointersStorageBuffer) &&
583         var_ptrs == nullptr && vulkan11_ptrs == nullptr) {
584       return amber::Result(
585           "Variable pointers requested but feature not returned");
586     }
587     if ((feature == k16BitStorage_Storage ||
588          feature == k16BitStorage_UniformAndStorage ||
589          feature == k16BitStorage_PushConstant ||
590          feature == k16BitStorage_InputOutput) &&
591         storage16_ptrs == nullptr && vulkan11_ptrs == nullptr) {
592       return amber::Result(
593           "Shader 16-bit storage requested but feature not returned");
594     }
595     if ((feature == kFloat16Int8_Float16 || feature == kFloat16Int8_Int8) &&
596         float16_ptrs == nullptr && vulkan12_ptrs == nullptr) {
597       return amber::Result(
598           "Shader float16/int8 requested but feature not returned");
599     }
600     if ((feature == k8BitStorage_UniformAndStorage ||
601          feature == k8BitStorage_Storage ||
602          feature == k8BitStorage_PushConstant) &&
603         storage8_ptrs == nullptr && vulkan12_ptrs == nullptr) {
604       return amber::Result(
605           "Shader 8-bit storage requested but feature not returned");
606     }
607     if ((feature == kSubgroupSizeControl || feature == kComputeFullSubgroups) &&
608         subgroup_size_control_features == nullptr && vulkan13_ptrs == nullptr) {
609       return amber::Result("Missing subgroup size control features");
610     }
611     if (feature == kShaderSubgroupExtendedTypes &&
612         shader_subgroup_extended_types_ptrs == nullptr &&
613         vulkan12_ptrs == nullptr) {
614       return amber::Result(
615           "Subgroup extended types requested but feature not returned");
616     }
617     if (feature == kAccelerationStructure) {
618       if (acceleration_structure_ptrs == nullptr)
619         return amber::Result(
620             "Acceleration structure requested but feature not returned");
621       if (ptrs_.vkCreateAccelerationStructureKHR == nullptr)
622         return amber::Result(
623             "vkCreateAccelerationStructureKHR is required, but not provided");
624       if (ptrs_.vkDestroyAccelerationStructureKHR == nullptr)
625         return amber::Result(
626             "vkDestroyAccelerationStructureKHR is required, but not provided");
627       if (ptrs_.vkGetAccelerationStructureBuildSizesKHR == nullptr)
628         return amber::Result(
629             "vkGetAccelerationStructureBuildSizesKHR is required, but not "
630             "provided");
631       if (ptrs_.vkBuildAccelerationStructuresKHR == nullptr)
632         return amber::Result(
633             "vkBuildAccelerationStructuresKHR is required, but not "
634             "provided");
635       if (ptrs_.vkCmdBuildAccelerationStructuresKHR == nullptr)
636         return amber::Result(
637             "vkCmdBuildAccelerationStructuresKHR is required, but not "
638             "provided");
639       if (ptrs_.vkGetAccelerationStructureDeviceAddressKHR == nullptr)
640         return amber::Result(
641             "vkGetAccelerationStructureDeviceAddressKHR is required, but not "
642             "provided");
643     }
644     if (feature == kBufferDeviceAddress && bda_ptrs == nullptr &&
645         vulkan12_ptrs == nullptr) {
646       return amber::Result(
647           "Buffer device address requested but feature not returned");
648     }
649     if (feature == kRayTracingPipeline) {
650       if (ray_tracing_pipeline_ptrs == nullptr)
651         return amber::Result(
652             "Ray tracing pipeline requested but feature not returned");
653       if (ptrs_.vkCreateRayTracingPipelinesKHR == nullptr)
654         return amber::Result(
655             "vkCreateRayTracingPipelinesKHR is required, but not provided");
656       if (ptrs_.vkCmdTraceRaysKHR == nullptr)
657         return amber::Result(
658             "vkCmdTraceRaysKHR is required, but not provided");
659       if (ptrs_.vkGetRayTracingShaderGroupHandlesKHR == nullptr)
660         return amber::Result(
661             "vkGetRayTracingShaderGroupHandlesKHR is required, but not "
662             "provided");
663     }
664 
665     // Next check the fields of the feature structures.
666 
667     // If Vulkan 1.1 structure exists the features are set there.
668     if (vulkan11_ptrs) {
669       if (feature == kVariablePointers &&
670           vulkan11_ptrs->variablePointers != VK_TRUE) {
671         return amber::Result("Missing variable pointers feature");
672       }
673       if (feature == kVariablePointersStorageBuffer &&
674           vulkan11_ptrs->variablePointersStorageBuffer != VK_TRUE) {
675         return amber::Result(
676             "Missing variable pointers storage buffer feature");
677       }
678       if (feature == k16BitStorage_Storage &&
679           vulkan11_ptrs->storageBuffer16BitAccess != VK_TRUE) {
680         return amber::Result("Missing 16-bit storage access");
681       }
682       if (feature == k16BitStorage_UniformAndStorage &&
683           vulkan11_ptrs->uniformAndStorageBuffer16BitAccess != VK_TRUE) {
684         return amber::Result("Missing 16-bit uniform and storage access");
685       }
686       if (feature == k16BitStorage_PushConstant &&
687           vulkan11_ptrs->storagePushConstant16 != VK_TRUE) {
688         return amber::Result("Missing 16-bit push constant access");
689       }
690       if (feature == k16BitStorage_InputOutput &&
691           vulkan11_ptrs->storageInputOutput16 != VK_TRUE) {
692         return amber::Result("Missing 16-bit input/output access");
693       }
694     } else {
695       // Vulkan 1.1 structure was not found. Use separate structures per each
696       // feature.
697       if (feature == kVariablePointers &&
698           var_ptrs->variablePointers != VK_TRUE) {
699         return amber::Result("Missing variable pointers feature");
700       }
701       if (feature == kVariablePointersStorageBuffer &&
702           var_ptrs->variablePointersStorageBuffer != VK_TRUE) {
703         return amber::Result(
704             "Missing variable pointers storage buffer feature");
705       }
706       if (feature == k16BitStorage_Storage &&
707           storage16_ptrs->storageBuffer16BitAccess != VK_TRUE) {
708         return amber::Result("Missing 16-bit storage access");
709       }
710       if (feature == k16BitStorage_UniformAndStorage &&
711           storage16_ptrs->uniformAndStorageBuffer16BitAccess != VK_TRUE) {
712         return amber::Result("Missing 16-bit uniform and storage access");
713       }
714       if (feature == k16BitStorage_PushConstant &&
715           storage16_ptrs->storagePushConstant16 != VK_TRUE) {
716         return amber::Result("Missing 16-bit push constant access");
717       }
718       if (feature == k16BitStorage_InputOutput &&
719           storage16_ptrs->storageInputOutput16 != VK_TRUE) {
720         return amber::Result("Missing 16-bit input/output access");
721       }
722     }
723 
724     // If Vulkan 1.2 structure exists the features are set there.
725     if (vulkan12_ptrs) {
726       if (feature == kFloat16Int8_Float16 &&
727           vulkan12_ptrs->shaderFloat16 != VK_TRUE) {
728         return amber::Result("Missing float16 feature");
729       }
730       if (feature == kFloat16Int8_Int8 &&
731           vulkan12_ptrs->shaderInt8 != VK_TRUE) {
732         return amber::Result("Missing int8 feature");
733       }
734       if (feature == k8BitStorage_Storage &&
735           vulkan12_ptrs->storageBuffer8BitAccess != VK_TRUE) {
736         return amber::Result("Missing 8-bit storage access");
737       }
738       if (feature == k8BitStorage_UniformAndStorage &&
739           vulkan12_ptrs->uniformAndStorageBuffer8BitAccess != VK_TRUE) {
740         return amber::Result("Missing 8-bit uniform and storage access");
741       }
742       if (feature == k8BitStorage_PushConstant &&
743           vulkan12_ptrs->storagePushConstant8 != VK_TRUE) {
744         return amber::Result("Missing 8-bit push constant access");
745       }
746       if (feature == kShaderSubgroupExtendedTypes &&
747           vulkan12_ptrs->shaderSubgroupExtendedTypes != VK_TRUE) {
748         return amber::Result("Missing subgroup extended types");
749       }
750       if (feature == kBufferDeviceAddress &&
751           vulkan12_ptrs->bufferDeviceAddress != VK_TRUE) {
752         return amber::Result("Missing buffer device address");
753       }
754     } else {
755       // Vulkan 1.2 structure was not found. Use separate structures per each
756       // feature.
757       if (feature == kFloat16Int8_Float16 &&
758           float16_ptrs->shaderFloat16 != VK_TRUE) {
759         return amber::Result("Missing float16 feature");
760       }
761       if (feature == kFloat16Int8_Int8 && float16_ptrs->shaderInt8 != VK_TRUE) {
762         return amber::Result("Missing int8 feature");
763       }
764       if (feature == k8BitStorage_Storage &&
765           storage8_ptrs->storageBuffer8BitAccess != VK_TRUE) {
766         return amber::Result("Missing 8-bit storage access");
767       }
768       if (feature == k8BitStorage_UniformAndStorage &&
769           storage8_ptrs->uniformAndStorageBuffer8BitAccess != VK_TRUE) {
770         return amber::Result("Missing 8-bit uniform and storage access");
771       }
772       if (feature == k8BitStorage_PushConstant &&
773           storage8_ptrs->storagePushConstant8 != VK_TRUE) {
774         return amber::Result("Missing 8-bit push constant access");
775       }
776       if (feature == kShaderSubgroupExtendedTypes &&
777           shader_subgroup_extended_types_ptrs->shaderSubgroupExtendedTypes !=
778               VK_TRUE) {
779         return amber::Result("Missing subgroup extended types");
780       }
781       if (feature == kBufferDeviceAddress &&
782           bda_ptrs->bufferDeviceAddress != VK_TRUE) {
783         return amber::Result("Missing buffer device address");
784       }
785     }
786 
787     // If Vulkan 1.3 structure exists the features are set there.
788     if (vulkan13_ptrs) {
789       if (feature == kSubgroupSizeControl &&
790           vulkan13_ptrs->subgroupSizeControl != VK_TRUE) {
791         return amber::Result("Missing subgroup size control feature");
792       }
793       if (feature == kComputeFullSubgroups &&
794           vulkan13_ptrs->computeFullSubgroups != VK_TRUE) {
795         return amber::Result("Missing compute full subgroups feature");
796       }
797     } else {
798       if (feature == kSubgroupSizeControl &&
799           subgroup_size_control_features->subgroupSizeControl != VK_TRUE) {
800         return amber::Result("Missing subgroup size control feature");
801       }
802       if (feature == kComputeFullSubgroups &&
803           subgroup_size_control_features->computeFullSubgroups != VK_TRUE) {
804         return amber::Result("Missing compute full subgroups feature");
805       }
806     }
807 
808     // If Vulkan 1.4 structure exists the features are set there.
809     if (vulkan14_ptrs) {
810       if (feature == kIndexTypeUint8 &&
811           vulkan14_ptrs->indexTypeUint8 != VK_TRUE) {
812         return amber::Result(
813             "Index type uint8_t requested but feature not returned");
814       }
815     } else {
816       if (feature == kIndexTypeUint8 &&
817           (index_type_uint8_ptrs == nullptr ||
818            index_type_uint8_ptrs->indexTypeUint8 != VK_TRUE)) {
819         return amber::Result(
820             "Index type uint8_t requested but feature not returned");
821       }
822     }
823   }
824 
825   if (!AreAllExtensionsSupported(available_extensions,
826                                  required_device_extensions)) {
827     return Result(
828         "Vulkan: Device::Initialize given physical device does not support "
829         "required extensions");
830   }
831 
832   const bool needs_shader_group_handle_size =
833       std::find(required_features.begin(), required_features.end(),
834                 kAccelerationStructure) != required_features.end();
835 
836   if (needs_shader_group_handle_size) {
837     VkPhysicalDeviceRayTracingPipelinePropertiesKHR rt_pipeline_properties = {};
838     rt_pipeline_properties.sType =
839         VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR;
840 
841     VkPhysicalDeviceProperties2KHR properties2 = {};
842     properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
843     properties2.pNext = &rt_pipeline_properties;
844 
845     ptrs_.vkGetPhysicalDeviceProperties2(physical_device_, &properties2);
846 
847     shader_group_handle_size_ = rt_pipeline_properties.shaderGroupHandleSize;
848   }
849 
850   VkPhysicalDeviceVulkan12Properties* pv12 = nullptr;
851   VkPhysicalDeviceFloatControlsProperties* pfc = nullptr;
852 
853   ptr = available_properties2.pNext;
854   while (ptr != nullptr) {
855     BaseOutStructure* s = static_cast<BaseOutStructure*>(ptr);
856     switch (s->sType) {
857       case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_PROPERTIES:
858         pv12 = static_cast<VkPhysicalDeviceVulkan12Properties*>(ptr);
859         break;
860       case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT_CONTROLS_PROPERTIES_KHR:
861         pfc = static_cast<VkPhysicalDeviceFloatControlsPropertiesKHR*>(ptr);
862         break;
863       default:
864         break;
865     }
866     ptr = s->pNext;
867   }
868 
869 #define CHK_P(R, P, NAME, S1, S2)                         \
870   do {                                                    \
871     if (R == -1 && P == #NAME)                            \
872       R = ((S1 && S1->NAME) || (S2 && S2->NAME)) ? 1 : 0; \
873   } while (false)
874 
875   for (const std::string& prop : required_properties) {
876     const size_t dot_pos = prop.find('.');
877     const size_t dot_found = dot_pos != std::string::npos;
878     const std::string prefix = dot_found ? prop.substr(0, dot_pos) : "";
879     const std::string name = dot_found ? prop.substr(dot_pos + 1) : prop;
880     int supported = -1;
881 
882     if (supported == -1 && prefix == "FloatControlsProperties") {
883       if (pfc == nullptr && pv12 == nullptr)
884         return Result(
885             "Vulkan: Device::Initialize given physical device does not support "
886             "required float control properties");
887 
888       CHK_P(supported, name, shaderSignedZeroInfNanPreserveFloat16, pfc, pv12);
889       CHK_P(supported, name, shaderSignedZeroInfNanPreserveFloat32, pfc, pv12);
890       CHK_P(supported, name, shaderSignedZeroInfNanPreserveFloat64, pfc, pv12);
891       CHK_P(supported, name, shaderDenormPreserveFloat16, pfc, pv12);
892       CHK_P(supported, name, shaderDenormPreserveFloat32, pfc, pv12);
893       CHK_P(supported, name, shaderDenormPreserveFloat64, pfc, pv12);
894       CHK_P(supported, name, shaderDenormFlushToZeroFloat16, pfc, pv12);
895       CHK_P(supported, name, shaderDenormFlushToZeroFloat32, pfc, pv12);
896       CHK_P(supported, name, shaderDenormFlushToZeroFloat64, pfc, pv12);
897       CHK_P(supported, name, shaderRoundingModeRTEFloat16, pfc, pv12);
898       CHK_P(supported, name, shaderRoundingModeRTEFloat32, pfc, pv12);
899       CHK_P(supported, name, shaderRoundingModeRTEFloat64, pfc, pv12);
900       CHK_P(supported, name, shaderRoundingModeRTZFloat16, pfc, pv12);
901       CHK_P(supported, name, shaderRoundingModeRTZFloat32, pfc, pv12);
902       CHK_P(supported, name, shaderRoundingModeRTZFloat64, pfc, pv12);
903     }
904 
905     if (supported == 0)
906       return Result("Vulkan: Device::Initialize missing " + prop + " property");
907 
908     if (supported == -1)
909       return Result("Vulkan: Device::Initialize property not handled " + prop);
910   }
911 
912   ptrs_.vkGetPhysicalDeviceMemoryProperties(physical_device_,
913                                             &physical_memory_properties_);
914 
915   subgroup_size_control_properties_ = {};
916   const bool needs_subgroup_size_control =
917       std::find(required_features.begin(), required_features.end(),
918                 kSubgroupSizeControl) != required_features.end();
919 
920   bool needs_subgroup_supported_operations = false;
921   bool needs_subgroup_supported_stages = false;
922 
923   // Search for subgroup supported operations requirements.
924   for (const auto& feature : required_features)
925     if (feature.find(kSubgroupSupportedOperations) != std::string::npos)
926       needs_subgroup_supported_operations = true;
927 
928   // Search for subgroup supported stages requirements.
929   for (const auto& feature : required_features)
930     if (feature.find(kSubgroupSupportedStages) != std::string::npos)
931       needs_subgroup_supported_stages = true;
932 
933   const bool needs_subgroup_properties =
934       needs_subgroup_supported_operations || needs_subgroup_supported_stages;
935 
936   if (needs_subgroup_size_control || needs_subgroup_properties) {
937     // Always chain all physical device properties structs in case at least one
938     // of them is needed.
939     VkPhysicalDeviceProperties2 properties2 = {};
940     VkPhysicalDeviceSubgroupProperties subgroup_properties = {};
941     VkPhysicalDeviceVulkan11Properties vulkan11_properties = {};
942     VkSubgroupFeatureFlags subgroup_supported_operations;
943     VkShaderStageFlags subgroup_supported_stages;
944     properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
945     properties2.pNext = &subgroup_size_control_properties_;
946     subgroup_size_control_properties_.sType =
947         VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_PROPERTIES_EXT;
948     if (SupportsApiVersion(1, 2, 0)) {
949       subgroup_size_control_properties_.pNext = &vulkan11_properties;
950       vulkan11_properties.sType =
951           VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_PROPERTIES;
952     } else {
953       subgroup_size_control_properties_.pNext = &subgroup_properties;
954       subgroup_properties.sType =
955           VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES;
956     }
957 
958     if (needs_subgroup_size_control && !SupportsApiVersion(1, 1, 0)) {
959       return Result(
960           "Vulkan: Device::Initialize subgroup size control feature also "
961           "requires an API version of 1.1 or higher");
962     }
963     if (needs_subgroup_properties && !SupportsApiVersion(1, 1, 0)) {
964       return Result(
965           "Vulkan: Device::Initialize subgroup properties also "
966           "requires an API version of 1.1 or higher");
967     }
968     ptrs_.vkGetPhysicalDeviceProperties2(physical_device_, &properties2);
969 
970     if (needs_subgroup_supported_operations) {
971       // Read supported subgroup operations from the correct struct depending on
972       // the device API
973       if (SupportsApiVersion(1, 2, 0)) {
974         subgroup_supported_operations =
975             vulkan11_properties.subgroupSupportedOperations;
976       } else {
977         subgroup_supported_operations = subgroup_properties.supportedOperations;
978       }
979 
980       for (const auto& feature : required_features) {
981         if (feature == kSubgroupSupportedOperationsBasic &&
982             !(subgroup_supported_operations & VK_SUBGROUP_FEATURE_BASIC_BIT)) {
983           return amber::Result("Missing subgroup operation basic feature");
984         }
985         if (feature == kSubgroupSupportedOperationsVote &&
986             !(subgroup_supported_operations & VK_SUBGROUP_FEATURE_VOTE_BIT)) {
987           return amber::Result("Missing subgroup operation vote feature");
988         }
989         if (feature == kSubgroupSupportedOperationsArithmetic &&
990             !(subgroup_supported_operations &
991               VK_SUBGROUP_FEATURE_ARITHMETIC_BIT)) {
992           return amber::Result("Missing subgroup operation arithmetic feature");
993         }
994         if (feature == kSubgroupSupportedOperationsBallot &&
995             !(subgroup_supported_operations & VK_SUBGROUP_FEATURE_BALLOT_BIT)) {
996           return amber::Result("Missing subgroup operation ballot feature");
997         }
998         if (feature == kSubgroupSupportedOperationsShuffle &&
999             !(subgroup_supported_operations &
1000               VK_SUBGROUP_FEATURE_SHUFFLE_BIT)) {
1001           return amber::Result("Missing subgroup operation shuffle feature");
1002         }
1003         if (feature == kSubgroupSupportedOperationsShuffleRelative &&
1004             !(subgroup_supported_operations &
1005               VK_SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT)) {
1006           return amber::Result(
1007               "Missing subgroup operation shuffle relative feature");
1008         }
1009         if (feature == kSubgroupSupportedOperationsClustered &&
1010             !(subgroup_supported_operations &
1011               VK_SUBGROUP_FEATURE_CLUSTERED_BIT)) {
1012           return amber::Result("Missing subgroup operation clustered feature");
1013         }
1014         if (feature == kSubgroupSupportedOperationsQuad &&
1015             !(subgroup_supported_operations & VK_SUBGROUP_FEATURE_QUAD_BIT)) {
1016           return amber::Result("Missing subgroup operation quad feature");
1017         }
1018       }
1019     }
1020 
1021     if (needs_subgroup_supported_stages) {
1022       // Read supported subgroup stages from the correct struct depending on the
1023       // device API
1024       if (SupportsApiVersion(1, 2, 0)) {
1025         subgroup_supported_stages = vulkan11_properties.subgroupSupportedStages;
1026       } else {
1027         subgroup_supported_stages = subgroup_properties.supportedStages;
1028       }
1029 
1030       for (const auto& feature : required_features) {
1031         if (feature == kSubgroupSupportedStagesVertex &&
1032             !(subgroup_supported_stages & VK_SHADER_STAGE_VERTEX_BIT)) {
1033           return amber::Result(
1034               "Subgroup operations not supported for vertex shader stage");
1035         }
1036         if (feature == kSubgroupSupportedStagesTessellationControl &&
1037             !(subgroup_supported_stages &
1038               VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT)) {
1039           return amber::Result(
1040               "Subgroup operations not supported for tessellation control "
1041               "shader stage");
1042         }
1043         if (feature == kSubgroupSupportedStagesTessellationEvaluation &&
1044             !(subgroup_supported_stages &
1045               VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)) {
1046           return amber::Result(
1047               "Subgroup operations not supported for tessellation evaluation "
1048               "shader stage");
1049         }
1050         if (feature == kSubgroupSupportedStagesGeometry &&
1051             !(subgroup_supported_stages & VK_SHADER_STAGE_GEOMETRY_BIT)) {
1052           return amber::Result(
1053               "Subgroup operations not supported for geometry shader stage");
1054         }
1055         if (feature == kSubgroupSupportedStagesFragment &&
1056             !(subgroup_supported_stages & VK_SHADER_STAGE_FRAGMENT_BIT)) {
1057           return amber::Result(
1058               "Subgroup operations not supported for fragment shader stage");
1059         }
1060         if (feature == kSubgroupSupportedStagesCompute &&
1061             !(subgroup_supported_stages & VK_SHADER_STAGE_COMPUTE_BIT)) {
1062           return amber::Result(
1063               "Subgroup operations not supported for compute shader stage");
1064         }
1065       }
1066     }
1067   }
1068 
1069   return {};
1070 }
1071 
IsFormatSupportedByPhysicalDevice(const Format & format,BufferType type)1072 bool Device::IsFormatSupportedByPhysicalDevice(const Format& format,
1073                                                BufferType type) {
1074   VkFormat vk_format = GetVkFormat(format);
1075   VkFormatProperties properties = VkFormatProperties();
1076   GetPtrs()->vkGetPhysicalDeviceFormatProperties(physical_device_, vk_format,
1077                                                  &properties);
1078 
1079   VkFormatFeatureFlagBits flag = VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT;
1080   bool is_buffer_type_image = false;
1081   switch (type) {
1082     case BufferType::kColor:
1083     case BufferType::kResolve:
1084     case BufferType::kStorageImage:
1085       flag = VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT;
1086       is_buffer_type_image = true;
1087       break;
1088     case BufferType::kDepthStencil:
1089       flag = VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT;
1090       is_buffer_type_image = true;
1091       break;
1092     case BufferType::kSampledImage:
1093     case BufferType::kCombinedImageSampler:
1094       flag = VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT;
1095       is_buffer_type_image = true;
1096       break;
1097     case BufferType::kVertex:
1098       flag = VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT;
1099       is_buffer_type_image = false;
1100       break;
1101     default:
1102       return false;
1103   }
1104 
1105   return ((is_buffer_type_image ? properties.optimalTilingFeatures
1106                                 : properties.bufferFeatures) &
1107           flag) == flag;
1108 }
1109 
HasMemoryFlags(uint32_t memory_type_index,const VkMemoryPropertyFlags flags) const1110 bool Device::HasMemoryFlags(uint32_t memory_type_index,
1111                             const VkMemoryPropertyFlags flags) const {
1112   return (physical_memory_properties_.memoryTypes[memory_type_index]
1113               .propertyFlags &
1114           flags) == flags;
1115 }
1116 
IsMemoryHostAccessible(uint32_t memory_type_index) const1117 bool Device::IsMemoryHostAccessible(uint32_t memory_type_index) const {
1118   return HasMemoryFlags(memory_type_index, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
1119 }
1120 
IsMemoryHostCoherent(uint32_t memory_type_index) const1121 bool Device::IsMemoryHostCoherent(uint32_t memory_type_index) const {
1122   return HasMemoryFlags(memory_type_index,
1123                         VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
1124 }
1125 
GetMaxPushConstants() const1126 uint32_t Device::GetMaxPushConstants() const {
1127   return physical_device_properties_.limits.maxPushConstantsSize;
1128 }
1129 
IsTimestampComputeAndGraphicsSupported() const1130 bool Device::IsTimestampComputeAndGraphicsSupported() const {
1131   return physical_device_properties_.limits.timestampComputeAndGraphics;
1132 }
1133 
GetTimestampPeriod() const1134 float Device::GetTimestampPeriod() const {
1135   return physical_device_properties_.limits.timestampPeriod;
1136 }
1137 
IsDescriptorSetInBounds(uint32_t descriptor_set) const1138 bool Device::IsDescriptorSetInBounds(uint32_t descriptor_set) const {
1139   VkPhysicalDeviceProperties properties = VkPhysicalDeviceProperties();
1140   GetPtrs()->vkGetPhysicalDeviceProperties(physical_device_, &properties);
1141   return properties.limits.maxBoundDescriptorSets > descriptor_set;
1142 }
1143 
GetVkFormat(const Format & format) const1144 VkFormat Device::GetVkFormat(const Format& format) const {
1145   VkFormat ret = VK_FORMAT_UNDEFINED;
1146   switch (format.GetFormatType()) {
1147     case FormatType::kUnknown:
1148       ret = VK_FORMAT_UNDEFINED;
1149       break;
1150     case FormatType::kA1R5G5B5_UNORM_PACK16:
1151       ret = VK_FORMAT_A1R5G5B5_UNORM_PACK16;
1152       break;
1153     case FormatType::kA2B10G10R10_SINT_PACK32:
1154       ret = VK_FORMAT_A2B10G10R10_SINT_PACK32;
1155       break;
1156     case FormatType::kA2B10G10R10_SNORM_PACK32:
1157       ret = VK_FORMAT_A2B10G10R10_SNORM_PACK32;
1158       break;
1159     case FormatType::kA2B10G10R10_SSCALED_PACK32:
1160       ret = VK_FORMAT_A2B10G10R10_SSCALED_PACK32;
1161       break;
1162     case FormatType::kA2B10G10R10_UINT_PACK32:
1163       ret = VK_FORMAT_A2B10G10R10_UINT_PACK32;
1164       break;
1165     case FormatType::kA2B10G10R10_UNORM_PACK32:
1166       ret = VK_FORMAT_A2B10G10R10_UNORM_PACK32;
1167       break;
1168     case FormatType::kA2B10G10R10_USCALED_PACK32:
1169       ret = VK_FORMAT_A2B10G10R10_USCALED_PACK32;
1170       break;
1171     case FormatType::kA2R10G10B10_SINT_PACK32:
1172       ret = VK_FORMAT_A2R10G10B10_SINT_PACK32;
1173       break;
1174     case FormatType::kA2R10G10B10_SNORM_PACK32:
1175       ret = VK_FORMAT_A2R10G10B10_SNORM_PACK32;
1176       break;
1177     case FormatType::kA2R10G10B10_SSCALED_PACK32:
1178       ret = VK_FORMAT_A2R10G10B10_SSCALED_PACK32;
1179       break;
1180     case FormatType::kA2R10G10B10_UINT_PACK32:
1181       ret = VK_FORMAT_A2R10G10B10_UINT_PACK32;
1182       break;
1183     case FormatType::kA2R10G10B10_UNORM_PACK32:
1184       ret = VK_FORMAT_A2R10G10B10_UNORM_PACK32;
1185       break;
1186     case FormatType::kA2R10G10B10_USCALED_PACK32:
1187       ret = VK_FORMAT_A2R10G10B10_USCALED_PACK32;
1188       break;
1189     case FormatType::kA8B8G8R8_SINT_PACK32:
1190       ret = VK_FORMAT_A8B8G8R8_SINT_PACK32;
1191       break;
1192     case FormatType::kA8B8G8R8_SNORM_PACK32:
1193       ret = VK_FORMAT_A8B8G8R8_SNORM_PACK32;
1194       break;
1195     case FormatType::kA8B8G8R8_SRGB_PACK32:
1196       ret = VK_FORMAT_A8B8G8R8_SRGB_PACK32;
1197       break;
1198     case FormatType::kA8B8G8R8_SSCALED_PACK32:
1199       ret = VK_FORMAT_A8B8G8R8_SSCALED_PACK32;
1200       break;
1201     case FormatType::kA8B8G8R8_UINT_PACK32:
1202       ret = VK_FORMAT_A8B8G8R8_UINT_PACK32;
1203       break;
1204     case FormatType::kA8B8G8R8_UNORM_PACK32:
1205       ret = VK_FORMAT_A8B8G8R8_UNORM_PACK32;
1206       break;
1207     case FormatType::kA8B8G8R8_USCALED_PACK32:
1208       ret = VK_FORMAT_A8B8G8R8_USCALED_PACK32;
1209       break;
1210     case FormatType::kB10G11R11_UFLOAT_PACK32:
1211       ret = VK_FORMAT_B10G11R11_UFLOAT_PACK32;
1212       break;
1213     case FormatType::kB4G4R4A4_UNORM_PACK16:
1214       ret = VK_FORMAT_B4G4R4A4_UNORM_PACK16;
1215       break;
1216     case FormatType::kB5G5R5A1_UNORM_PACK16:
1217       ret = VK_FORMAT_B5G5R5A1_UNORM_PACK16;
1218       break;
1219     case FormatType::kB5G6R5_UNORM_PACK16:
1220       ret = VK_FORMAT_B5G6R5_UNORM_PACK16;
1221       break;
1222     case FormatType::kB8G8R8A8_SINT:
1223       ret = VK_FORMAT_B8G8R8A8_SINT;
1224       break;
1225     case FormatType::kB8G8R8A8_SNORM:
1226       ret = VK_FORMAT_B8G8R8A8_SNORM;
1227       break;
1228     case FormatType::kB8G8R8A8_SRGB:
1229       ret = VK_FORMAT_B8G8R8A8_SRGB;
1230       break;
1231     case FormatType::kB8G8R8A8_SSCALED:
1232       ret = VK_FORMAT_B8G8R8A8_SSCALED;
1233       break;
1234     case FormatType::kB8G8R8A8_UINT:
1235       ret = VK_FORMAT_B8G8R8A8_UINT;
1236       break;
1237     case FormatType::kB8G8R8A8_UNORM:
1238       ret = VK_FORMAT_B8G8R8A8_UNORM;
1239       break;
1240     case FormatType::kB8G8R8A8_USCALED:
1241       ret = VK_FORMAT_B8G8R8A8_USCALED;
1242       break;
1243     case FormatType::kB8G8R8_SINT:
1244       ret = VK_FORMAT_B8G8R8_SINT;
1245       break;
1246     case FormatType::kB8G8R8_SNORM:
1247       ret = VK_FORMAT_B8G8R8_SNORM;
1248       break;
1249     case FormatType::kB8G8R8_SRGB:
1250       ret = VK_FORMAT_B8G8R8_SRGB;
1251       break;
1252     case FormatType::kB8G8R8_SSCALED:
1253       ret = VK_FORMAT_B8G8R8_SSCALED;
1254       break;
1255     case FormatType::kB8G8R8_UINT:
1256       ret = VK_FORMAT_B8G8R8_UINT;
1257       break;
1258     case FormatType::kB8G8R8_UNORM:
1259       ret = VK_FORMAT_B8G8R8_UNORM;
1260       break;
1261     case FormatType::kB8G8R8_USCALED:
1262       ret = VK_FORMAT_B8G8R8_USCALED;
1263       break;
1264     case FormatType::kD16_UNORM:
1265       ret = VK_FORMAT_D16_UNORM;
1266       break;
1267     case FormatType::kD16_UNORM_S8_UINT:
1268       ret = VK_FORMAT_D16_UNORM_S8_UINT;
1269       break;
1270     case FormatType::kD24_UNORM_S8_UINT:
1271       ret = VK_FORMAT_D24_UNORM_S8_UINT;
1272       break;
1273     case FormatType::kD32_SFLOAT:
1274       ret = VK_FORMAT_D32_SFLOAT;
1275       break;
1276     case FormatType::kD32_SFLOAT_S8_UINT:
1277       ret = VK_FORMAT_D32_SFLOAT_S8_UINT;
1278       break;
1279     case FormatType::kR16G16B16A16_SFLOAT:
1280       ret = VK_FORMAT_R16G16B16A16_SFLOAT;
1281       break;
1282     case FormatType::kR16G16B16A16_SINT:
1283       ret = VK_FORMAT_R16G16B16A16_SINT;
1284       break;
1285     case FormatType::kR16G16B16A16_SNORM:
1286       ret = VK_FORMAT_R16G16B16A16_SNORM;
1287       break;
1288     case FormatType::kR16G16B16A16_SSCALED:
1289       ret = VK_FORMAT_R16G16B16A16_SSCALED;
1290       break;
1291     case FormatType::kR16G16B16A16_UINT:
1292       ret = VK_FORMAT_R16G16B16A16_UINT;
1293       break;
1294     case FormatType::kR16G16B16A16_UNORM:
1295       ret = VK_FORMAT_R16G16B16A16_UNORM;
1296       break;
1297     case FormatType::kR16G16B16A16_USCALED:
1298       ret = VK_FORMAT_R16G16B16A16_USCALED;
1299       break;
1300     case FormatType::kR16G16B16_SFLOAT:
1301       ret = VK_FORMAT_R16G16B16_SFLOAT;
1302       break;
1303     case FormatType::kR16G16B16_SINT:
1304       ret = VK_FORMAT_R16G16B16_SINT;
1305       break;
1306     case FormatType::kR16G16B16_SNORM:
1307       ret = VK_FORMAT_R16G16B16_SNORM;
1308       break;
1309     case FormatType::kR16G16B16_SSCALED:
1310       ret = VK_FORMAT_R16G16B16_SSCALED;
1311       break;
1312     case FormatType::kR16G16B16_UINT:
1313       ret = VK_FORMAT_R16G16B16_UINT;
1314       break;
1315     case FormatType::kR16G16B16_UNORM:
1316       ret = VK_FORMAT_R16G16B16_UNORM;
1317       break;
1318     case FormatType::kR16G16B16_USCALED:
1319       ret = VK_FORMAT_R16G16B16_USCALED;
1320       break;
1321     case FormatType::kR16G16_SFLOAT:
1322       ret = VK_FORMAT_R16G16_SFLOAT;
1323       break;
1324     case FormatType::kR16G16_SINT:
1325       ret = VK_FORMAT_R16G16_SINT;
1326       break;
1327     case FormatType::kR16G16_SNORM:
1328       ret = VK_FORMAT_R16G16_SNORM;
1329       break;
1330     case FormatType::kR16G16_SSCALED:
1331       ret = VK_FORMAT_R16G16_SSCALED;
1332       break;
1333     case FormatType::kR16G16_UINT:
1334       ret = VK_FORMAT_R16G16_UINT;
1335       break;
1336     case FormatType::kR16G16_UNORM:
1337       ret = VK_FORMAT_R16G16_UNORM;
1338       break;
1339     case FormatType::kR16G16_USCALED:
1340       ret = VK_FORMAT_R16G16_USCALED;
1341       break;
1342     case FormatType::kR16_SFLOAT:
1343       ret = VK_FORMAT_R16_SFLOAT;
1344       break;
1345     case FormatType::kR16_SINT:
1346       ret = VK_FORMAT_R16_SINT;
1347       break;
1348     case FormatType::kR16_SNORM:
1349       ret = VK_FORMAT_R16_SNORM;
1350       break;
1351     case FormatType::kR16_SSCALED:
1352       ret = VK_FORMAT_R16_SSCALED;
1353       break;
1354     case FormatType::kR16_UINT:
1355       ret = VK_FORMAT_R16_UINT;
1356       break;
1357     case FormatType::kR16_UNORM:
1358       ret = VK_FORMAT_R16_UNORM;
1359       break;
1360     case FormatType::kR16_USCALED:
1361       ret = VK_FORMAT_R16_USCALED;
1362       break;
1363     case FormatType::kR32G32B32A32_SFLOAT:
1364       ret = VK_FORMAT_R32G32B32A32_SFLOAT;
1365       break;
1366     case FormatType::kR32G32B32A32_SINT:
1367       ret = VK_FORMAT_R32G32B32A32_SINT;
1368       break;
1369     case FormatType::kR32G32B32A32_UINT:
1370       ret = VK_FORMAT_R32G32B32A32_UINT;
1371       break;
1372     case FormatType::kR32G32B32_SFLOAT:
1373       ret = VK_FORMAT_R32G32B32_SFLOAT;
1374       break;
1375     case FormatType::kR32G32B32_SINT:
1376       ret = VK_FORMAT_R32G32B32_SINT;
1377       break;
1378     case FormatType::kR32G32B32_UINT:
1379       ret = VK_FORMAT_R32G32B32_UINT;
1380       break;
1381     case FormatType::kR32G32_SFLOAT:
1382       ret = VK_FORMAT_R32G32_SFLOAT;
1383       break;
1384     case FormatType::kR32G32_SINT:
1385       ret = VK_FORMAT_R32G32_SINT;
1386       break;
1387     case FormatType::kR32G32_UINT:
1388       ret = VK_FORMAT_R32G32_UINT;
1389       break;
1390     case FormatType::kR32_SFLOAT:
1391       ret = VK_FORMAT_R32_SFLOAT;
1392       break;
1393     case FormatType::kR32_SINT:
1394       ret = VK_FORMAT_R32_SINT;
1395       break;
1396     case FormatType::kR32_UINT:
1397       ret = VK_FORMAT_R32_UINT;
1398       break;
1399     case FormatType::kR4G4B4A4_UNORM_PACK16:
1400       ret = VK_FORMAT_R4G4B4A4_UNORM_PACK16;
1401       break;
1402     case FormatType::kR4G4_UNORM_PACK8:
1403       ret = VK_FORMAT_R4G4_UNORM_PACK8;
1404       break;
1405     case FormatType::kR5G5B5A1_UNORM_PACK16:
1406       ret = VK_FORMAT_R5G5B5A1_UNORM_PACK16;
1407       break;
1408     case FormatType::kR5G6B5_UNORM_PACK16:
1409       ret = VK_FORMAT_R5G6B5_UNORM_PACK16;
1410       break;
1411     case FormatType::kR64G64B64A64_SFLOAT:
1412       ret = VK_FORMAT_R64G64B64A64_SFLOAT;
1413       break;
1414     case FormatType::kR64G64B64A64_SINT:
1415       ret = VK_FORMAT_R64G64B64A64_SINT;
1416       break;
1417     case FormatType::kR64G64B64A64_UINT:
1418       ret = VK_FORMAT_R64G64B64A64_UINT;
1419       break;
1420     case FormatType::kR64G64B64_SFLOAT:
1421       ret = VK_FORMAT_R64G64B64_SFLOAT;
1422       break;
1423     case FormatType::kR64G64B64_SINT:
1424       ret = VK_FORMAT_R64G64B64_SINT;
1425       break;
1426     case FormatType::kR64G64B64_UINT:
1427       ret = VK_FORMAT_R64G64B64_UINT;
1428       break;
1429     case FormatType::kR64G64_SFLOAT:
1430       ret = VK_FORMAT_R64G64_SFLOAT;
1431       break;
1432     case FormatType::kR64G64_SINT:
1433       ret = VK_FORMAT_R64G64_SINT;
1434       break;
1435     case FormatType::kR64G64_UINT:
1436       ret = VK_FORMAT_R64G64_UINT;
1437       break;
1438     case FormatType::kR64_SFLOAT:
1439       ret = VK_FORMAT_R64_SFLOAT;
1440       break;
1441     case FormatType::kR64_SINT:
1442       ret = VK_FORMAT_R64_SINT;
1443       break;
1444     case FormatType::kR64_UINT:
1445       ret = VK_FORMAT_R64_UINT;
1446       break;
1447     case FormatType::kR8G8B8A8_SINT:
1448       ret = VK_FORMAT_R8G8B8A8_SINT;
1449       break;
1450     case FormatType::kR8G8B8A8_SNORM:
1451       ret = VK_FORMAT_R8G8B8A8_SNORM;
1452       break;
1453     case FormatType::kR8G8B8A8_SRGB:
1454       ret = VK_FORMAT_R8G8B8A8_SRGB;
1455       break;
1456     case FormatType::kR8G8B8A8_SSCALED:
1457       ret = VK_FORMAT_R8G8B8A8_SSCALED;
1458       break;
1459     case FormatType::kR8G8B8A8_UINT:
1460       ret = VK_FORMAT_R8G8B8A8_UINT;
1461       break;
1462     case FormatType::kR8G8B8A8_UNORM:
1463       ret = VK_FORMAT_R8G8B8A8_UNORM;
1464       break;
1465     case FormatType::kR8G8B8A8_USCALED:
1466       ret = VK_FORMAT_R8G8B8A8_USCALED;
1467       break;
1468     case FormatType::kR8G8B8_SINT:
1469       ret = VK_FORMAT_R8G8B8_SINT;
1470       break;
1471     case FormatType::kR8G8B8_SNORM:
1472       ret = VK_FORMAT_R8G8B8_SNORM;
1473       break;
1474     case FormatType::kR8G8B8_SRGB:
1475       ret = VK_FORMAT_R8G8B8_SRGB;
1476       break;
1477     case FormatType::kR8G8B8_SSCALED:
1478       ret = VK_FORMAT_R8G8B8_SSCALED;
1479       break;
1480     case FormatType::kR8G8B8_UINT:
1481       ret = VK_FORMAT_R8G8B8_UINT;
1482       break;
1483     case FormatType::kR8G8B8_UNORM:
1484       ret = VK_FORMAT_R8G8B8_UNORM;
1485       break;
1486     case FormatType::kR8G8B8_USCALED:
1487       ret = VK_FORMAT_R8G8B8_USCALED;
1488       break;
1489     case FormatType::kR8G8_SINT:
1490       ret = VK_FORMAT_R8G8_SINT;
1491       break;
1492     case FormatType::kR8G8_SNORM:
1493       ret = VK_FORMAT_R8G8_SNORM;
1494       break;
1495     case FormatType::kR8G8_SRGB:
1496       ret = VK_FORMAT_R8G8_SRGB;
1497       break;
1498     case FormatType::kR8G8_SSCALED:
1499       ret = VK_FORMAT_R8G8_SSCALED;
1500       break;
1501     case FormatType::kR8G8_UINT:
1502       ret = VK_FORMAT_R8G8_UINT;
1503       break;
1504     case FormatType::kR8G8_UNORM:
1505       ret = VK_FORMAT_R8G8_UNORM;
1506       break;
1507     case FormatType::kR8G8_USCALED:
1508       ret = VK_FORMAT_R8G8_USCALED;
1509       break;
1510     case FormatType::kR8_SINT:
1511       ret = VK_FORMAT_R8_SINT;
1512       break;
1513     case FormatType::kR8_SNORM:
1514       ret = VK_FORMAT_R8_SNORM;
1515       break;
1516     case FormatType::kR8_SRGB:
1517       ret = VK_FORMAT_R8_SRGB;
1518       break;
1519     case FormatType::kR8_SSCALED:
1520       ret = VK_FORMAT_R8_SSCALED;
1521       break;
1522     case FormatType::kR8_UINT:
1523       ret = VK_FORMAT_R8_UINT;
1524       break;
1525     case FormatType::kR8_UNORM:
1526       ret = VK_FORMAT_R8_UNORM;
1527       break;
1528     case FormatType::kR8_USCALED:
1529       ret = VK_FORMAT_R8_USCALED;
1530       break;
1531     case FormatType::kS8_UINT:
1532       ret = VK_FORMAT_S8_UINT;
1533       break;
1534     case FormatType::kX8_D24_UNORM_PACK32:
1535       ret = VK_FORMAT_X8_D24_UNORM_PACK32;
1536       break;
1537   }
1538   return ret;
1539 }
1540 
IsRequiredSubgroupSizeSupported(const ShaderType type,const uint32_t required_subgroup_size) const1541 bool Device::IsRequiredSubgroupSizeSupported(
1542     const ShaderType type,
1543     const uint32_t required_subgroup_size) const {
1544   VkShaderStageFlagBits stage = {};
1545   switch (type) {
1546     case kShaderTypeGeometry:
1547       stage = VK_SHADER_STAGE_GEOMETRY_BIT;
1548       break;
1549     case kShaderTypeFragment:
1550       stage = VK_SHADER_STAGE_FRAGMENT_BIT;
1551       break;
1552     case kShaderTypeVertex:
1553       stage = VK_SHADER_STAGE_VERTEX_BIT;
1554       break;
1555     case kShaderTypeTessellationControl:
1556       stage = VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT;
1557       break;
1558     case kShaderTypeTessellationEvaluation:
1559       stage = VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
1560       break;
1561     case kShaderTypeCompute:
1562       stage = VK_SHADER_STAGE_COMPUTE_BIT;
1563       break;
1564     default:
1565       return false;
1566   }
1567   if ((stage & subgroup_size_control_properties_.requiredSubgroupSizeStages) ==
1568       0) {
1569     return false;
1570   }
1571   if (required_subgroup_size == 0 ||
1572       required_subgroup_size <
1573           subgroup_size_control_properties_.minSubgroupSize ||
1574       required_subgroup_size >
1575           subgroup_size_control_properties_.maxSubgroupSize) {
1576     return false;
1577   }
1578 
1579   return true;
1580 }
1581 
GetMinSubgroupSize() const1582 uint32_t Device::GetMinSubgroupSize() const {
1583   return subgroup_size_control_properties_.minSubgroupSize;
1584 }
1585 
GetMaxSubgroupSize() const1586 uint32_t Device::GetMaxSubgroupSize() const {
1587   return subgroup_size_control_properties_.maxSubgroupSize;
1588 }
1589 
GetRayTracingShaderGroupHandleSize() const1590 uint32_t Device::GetRayTracingShaderGroupHandleSize() const {
1591   return shader_group_handle_size_;
1592 }
1593 
1594 }  // namespace vulkan
1595 }  // namespace amber
1596