1 // Copyright 2018 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 "src/vulkan/device.h"
16 
17 #include <algorithm>
18 #include <cstring>
19 #include <iomanip>  // Vulkan wrappers: std::setw(), std::left/right
20 #include <iostream>
21 #include <memory>
22 #include <set>
23 #include <sstream>
24 #include <string>
25 #include <vector>
26 
27 #include "src/make_unique.h"
28 
29 namespace amber {
30 namespace vulkan {
31 namespace {
32 
33 const char kVariablePointers[] = "VariablePointerFeatures.variablePointers";
34 const char kVariablePointersStorageBuffer[] =
35     "VariablePointerFeatures.variablePointersStorageBuffer";
36 const char kFloat16Int8_Float16[] = "Float16Int8Features.shaderFloat16";
37 const char kFloat16Int8_Int8[] = "Float16Int8Features.shaderInt8";
38 const char k8BitStorage_Storage[] =
39     "Storage8BitFeatures.storageBuffer8BitAccess";
40 const char k8BitStorage_UniformAndStorage[] =
41     "Storage8BitFeatures.uniformAndStorageBuffer8BitAccess";
42 const char k8BitStorage_PushConstant[] =
43     "Storage8BitFeatures.storagePushConstant8";
44 const char k16BitStorage_Storage[] =
45     "Storage16BitFeatures.storageBuffer16BitAccess";
46 const char k16BitStorage_UniformAndStorage[] =
47     "Storage16BitFeatures.uniformAndStorageBuffer16BitAccess";
48 const char k16BitStorage_PushConstant[] =
49     "Storage16BitFeatures.storagePushConstant16";
50 const char k16BitStorage_InputOutput[] =
51     "Storage16BitFeatures.storageInputOutput16";
52 
53 const char kSubgroupSizeControl[] = "SubgroupSizeControl.subgroupSizeControl";
54 const char kComputeFullSubgroups[] = "SubgroupSizeControl.computeFullSubgroups";
55 
56 struct BaseOutStructure {
57   VkStructureType sType;
58   void* pNext;
59 };
60 
AreAllRequiredFeaturesSupported(const VkPhysicalDeviceFeatures & available_features,const std::vector<std::string> & required_features)61 bool AreAllRequiredFeaturesSupported(
62     const VkPhysicalDeviceFeatures& available_features,
63     const std::vector<std::string>& required_features) {
64   if (required_features.empty())
65     return true;
66 
67   for (const auto& feature : required_features) {
68     if (feature == "robustBufferAccess") {
69       if (available_features.robustBufferAccess == VK_FALSE)
70         return false;
71       continue;
72     }
73     if (feature == "fullDrawIndexUint32") {
74       if (available_features.fullDrawIndexUint32 == VK_FALSE)
75         return false;
76       continue;
77     }
78     if (feature == "imageCubeArray") {
79       if (available_features.imageCubeArray == VK_FALSE)
80         return false;
81       continue;
82     }
83     if (feature == "independentBlend") {
84       if (available_features.independentBlend == VK_FALSE)
85         return false;
86       continue;
87     }
88     if (feature == "geometryShader") {
89       if (available_features.geometryShader == VK_FALSE)
90         return false;
91       continue;
92     }
93     if (feature == "tessellationShader") {
94       if (available_features.tessellationShader == VK_FALSE)
95         return false;
96       continue;
97     }
98     if (feature == "sampleRateShading") {
99       if (available_features.sampleRateShading == VK_FALSE)
100         return false;
101       continue;
102     }
103     if (feature == "dualSrcBlend") {
104       if (available_features.dualSrcBlend == VK_FALSE)
105         return false;
106       continue;
107     }
108     if (feature == "logicOp") {
109       if (available_features.logicOp == VK_FALSE)
110         return false;
111       continue;
112     }
113     if (feature == "multiDrawIndirect") {
114       if (available_features.multiDrawIndirect == VK_FALSE)
115         return false;
116       continue;
117     }
118     if (feature == "drawIndirectFirstInstance") {
119       if (available_features.drawIndirectFirstInstance == VK_FALSE)
120         return false;
121       continue;
122     }
123     if (feature == "depthClamp") {
124       if (available_features.depthClamp == VK_FALSE)
125         return false;
126       continue;
127     }
128     if (feature == "depthBiasClamp") {
129       if (available_features.depthBiasClamp == VK_FALSE)
130         return false;
131       continue;
132     }
133     if (feature == "fillModeNonSolid") {
134       if (available_features.fillModeNonSolid == VK_FALSE)
135         return false;
136       continue;
137     }
138     if (feature == "depthBounds") {
139       if (available_features.depthBounds == VK_FALSE)
140         return false;
141       continue;
142     }
143     if (feature == "wideLines") {
144       if (available_features.wideLines == VK_FALSE)
145         return false;
146       continue;
147     }
148     if (feature == "largePoints") {
149       if (available_features.largePoints == VK_FALSE)
150         return false;
151       continue;
152     }
153     if (feature == "alphaToOne") {
154       if (available_features.alphaToOne == VK_FALSE)
155         return false;
156       continue;
157     }
158     if (feature == "multiViewport") {
159       if (available_features.multiViewport == VK_FALSE)
160         return false;
161       continue;
162     }
163     if (feature == "samplerAnisotropy") {
164       if (available_features.samplerAnisotropy == VK_FALSE)
165         return false;
166       continue;
167     }
168     if (feature == "textureCompressionETC2") {
169       if (available_features.textureCompressionETC2 == VK_FALSE)
170         return false;
171       continue;
172     }
173     if (feature == "textureCompressionASTC_LDR") {
174       if (available_features.textureCompressionASTC_LDR == VK_FALSE)
175         return false;
176       continue;
177     }
178     if (feature == "textureCompressionBC") {
179       if (available_features.textureCompressionBC == VK_FALSE)
180         return false;
181       continue;
182     }
183     if (feature == "occlusionQueryPrecise") {
184       if (available_features.occlusionQueryPrecise == VK_FALSE)
185         return false;
186       continue;
187     }
188     if (feature == "pipelineStatisticsQuery") {
189       if (available_features.pipelineStatisticsQuery == VK_FALSE)
190         return false;
191       continue;
192     }
193     if (feature == "vertexPipelineStoresAndAtomics") {
194       if (available_features.vertexPipelineStoresAndAtomics == VK_FALSE)
195         return false;
196       continue;
197     }
198     if (feature == "fragmentStoresAndAtomics") {
199       if (available_features.fragmentStoresAndAtomics == VK_FALSE)
200         return false;
201       continue;
202     }
203     if (feature == "shaderTessellationAndGeometryPointSize") {
204       if (available_features.shaderTessellationAndGeometryPointSize == VK_FALSE)
205         return false;
206       continue;
207     }
208     if (feature == "shaderImageGatherExtended") {
209       if (available_features.shaderImageGatherExtended == VK_FALSE)
210         return false;
211       continue;
212     }
213     if (feature == "shaderStorageImageExtendedFormats") {
214       if (available_features.shaderStorageImageExtendedFormats == VK_FALSE)
215         return false;
216       continue;
217     }
218     if (feature == "shaderStorageImageMultisample") {
219       if (available_features.shaderStorageImageMultisample == VK_FALSE)
220         return false;
221       continue;
222     }
223     if (feature == "shaderStorageImageReadWithoutFormat") {
224       if (available_features.shaderStorageImageReadWithoutFormat == VK_FALSE)
225         return false;
226       continue;
227     }
228     if (feature == "shaderStorageImageWriteWithoutFormat") {
229       if (available_features.shaderStorageImageWriteWithoutFormat == VK_FALSE)
230         return false;
231       continue;
232     }
233     if (feature == "shaderUniformBufferArrayDynamicIndexing") {
234       if (available_features.shaderUniformBufferArrayDynamicIndexing ==
235           VK_FALSE)
236         return false;
237       continue;
238     }
239     if (feature == "shaderSampledImageArrayDynamicIndexing") {
240       if (available_features.shaderSampledImageArrayDynamicIndexing == VK_FALSE)
241         return false;
242       continue;
243     }
244     if (feature == "shaderStorageBufferArrayDynamicIndexing") {
245       if (available_features.shaderStorageBufferArrayDynamicIndexing ==
246           VK_FALSE)
247         return false;
248       continue;
249     }
250     if (feature == "shaderStorageImageArrayDynamicIndexing") {
251       if (available_features.shaderStorageImageArrayDynamicIndexing == VK_FALSE)
252         return false;
253       continue;
254     }
255     if (feature == "shaderClipDistance") {
256       if (available_features.shaderClipDistance == VK_FALSE)
257         return false;
258       continue;
259     }
260     if (feature == "shaderCullDistance") {
261       if (available_features.shaderCullDistance == VK_FALSE)
262         return false;
263       continue;
264     }
265     if (feature == "shaderFloat64") {
266       if (available_features.shaderFloat64 == VK_FALSE)
267         return false;
268       continue;
269     }
270     if (feature == "shaderInt64") {
271       if (available_features.shaderInt64 == VK_FALSE)
272         return false;
273       continue;
274     }
275     if (feature == "shaderInt16") {
276       if (available_features.shaderInt16 == VK_FALSE)
277         return false;
278       continue;
279     }
280     if (feature == "shaderResourceResidency") {
281       if (available_features.shaderResourceResidency == VK_FALSE)
282         return false;
283       continue;
284     }
285     if (feature == "shaderResourceMinLod") {
286       if (available_features.shaderResourceMinLod == VK_FALSE)
287         return false;
288       continue;
289     }
290     if (feature == "sparseBinding") {
291       if (available_features.sparseBinding == VK_FALSE)
292         return false;
293       continue;
294     }
295     if (feature == "sparseResidencyBuffer") {
296       if (available_features.sparseResidencyBuffer == VK_FALSE)
297         return false;
298       continue;
299     }
300     if (feature == "sparseResidencyImage2D") {
301       if (available_features.sparseResidencyImage2D == VK_FALSE)
302         return false;
303       continue;
304     }
305     if (feature == "sparseResidencyImage3D") {
306       if (available_features.sparseResidencyImage3D == VK_FALSE)
307         return false;
308       continue;
309     }
310     if (feature == "sparseResidency2Samples") {
311       if (available_features.sparseResidency2Samples == VK_FALSE)
312         return false;
313       continue;
314     }
315     if (feature == "sparseResidency4Samples") {
316       if (available_features.sparseResidency4Samples == VK_FALSE)
317         return false;
318       continue;
319     }
320     if (feature == "sparseResidency8Samples") {
321       if (available_features.sparseResidency8Samples == VK_FALSE)
322         return false;
323       continue;
324     }
325     if (feature == "sparseResidency16Samples") {
326       if (available_features.sparseResidency16Samples == VK_FALSE)
327         return false;
328       continue;
329     }
330     if (feature == "sparseResidencyAliased") {
331       if (available_features.sparseResidencyAliased == VK_FALSE)
332         return false;
333       continue;
334     }
335     if (feature == "variableMultisampleRate") {
336       if (available_features.variableMultisampleRate == VK_FALSE)
337         return false;
338       continue;
339     }
340     if (feature == "inheritedQueries") {
341       if (available_features.inheritedQueries == VK_FALSE)
342         return false;
343       continue;
344     }
345   }
346 
347   return true;
348 }
349 
AreAllExtensionsSupported(const std::vector<std::string> & available_extensions,const std::vector<std::string> & required_extensions)350 bool AreAllExtensionsSupported(
351     const std::vector<std::string>& available_extensions,
352     const std::vector<std::string>& required_extensions) {
353   if (required_extensions.empty())
354     return true;
355 
356   std::set<std::string> required_extension_set(required_extensions.begin(),
357                                                required_extensions.end());
358   for (const auto& extension : available_extensions) {
359     required_extension_set.erase(extension);
360   }
361 
362   return required_extension_set.empty();
363 }
364 
365 }  // namespace
366 
Device(VkInstance instance,VkPhysicalDevice physical_device,uint32_t queue_family_index,VkDevice device,VkQueue queue)367 Device::Device(VkInstance instance,
368                VkPhysicalDevice physical_device,
369                uint32_t queue_family_index,
370                VkDevice device,
371                VkQueue queue)
372     : instance_(instance),
373       physical_device_(physical_device),
374       device_(device),
375       queue_(queue),
376       queue_family_index_(queue_family_index) {}
377 
378 Device::~Device() = default;
379 
LoadVulkanPointers(PFN_vkGetInstanceProcAddr getInstanceProcAddr,Delegate * delegate)380 Result Device::LoadVulkanPointers(PFN_vkGetInstanceProcAddr getInstanceProcAddr,
381                                   Delegate* delegate) {
382   // Note: logging Vulkan calls is done via the delegate rather than a Vulkan
383   // layer because we want such logging even when Amber is built as a native
384   // executable on Android, where Vulkan layers are usable only with APKs.
385   if (delegate && delegate->LogGraphicsCalls())
386     delegate->Log("Loading Vulkan Pointers");
387 
388 #include "vk-wrappers-1-0.inc"
389 
390   ptrs_.vkGetPhysicalDeviceProperties(physical_device_,
391                                       &physical_device_properties_);
392 
393   if (SupportsApiVersion(1, 1, 0)) {
394 #include "vk-wrappers-1-1.inc"
395   }
396 
397   return {};
398 }
399 
SupportsApiVersion(uint32_t major,uint32_t minor,uint32_t patch)400 bool Device::SupportsApiVersion(uint32_t major,
401                                 uint32_t minor,
402                                 uint32_t patch) {
403 #pragma clang diagnostic push
404 #pragma clang diagnostic ignored "-Wold-style-cast"
405   return physical_device_properties_.apiVersion >=
406          VK_MAKE_VERSION(major, minor, patch);
407 #pragma clang diagnostic pop
408 }
409 
Initialize(PFN_vkGetInstanceProcAddr getInstanceProcAddr,Delegate * delegate,const std::vector<std::string> & required_features,const std::vector<std::string> & required_device_extensions,const VkPhysicalDeviceFeatures & available_features,const VkPhysicalDeviceFeatures2KHR & available_features2,const std::vector<std::string> & available_extensions)410 Result Device::Initialize(
411     PFN_vkGetInstanceProcAddr getInstanceProcAddr,
412     Delegate* delegate,
413     const std::vector<std::string>& required_features,
414     const std::vector<std::string>& required_device_extensions,
415     const VkPhysicalDeviceFeatures& available_features,
416     const VkPhysicalDeviceFeatures2KHR& available_features2,
417     const std::vector<std::string>& available_extensions) {
418   Result r = LoadVulkanPointers(getInstanceProcAddr, delegate);
419   if (!r.IsSuccess())
420     return r;
421 
422   // Check for the core features. We don't know if available_features or
423   // available_features2 is provided, so check both.
424   if (!AreAllRequiredFeaturesSupported(available_features, required_features) &&
425       !AreAllRequiredFeaturesSupported(available_features2.features,
426                                        required_features)) {
427     return Result(
428         "Vulkan: Device::Initialize given physical device does not support "
429         "required features");
430   }
431 
432   // Search for additional features in case they are found in pNext field of
433   // available_features2.
434   VkPhysicalDeviceVariablePointerFeaturesKHR* var_ptrs = nullptr;
435   VkPhysicalDeviceFloat16Int8FeaturesKHR* float16_ptrs = nullptr;
436   VkPhysicalDevice8BitStorageFeaturesKHR* storage8_ptrs = nullptr;
437   VkPhysicalDevice16BitStorageFeaturesKHR* storage16_ptrs = nullptr;
438   VkPhysicalDeviceVulkan11Features* vulkan11_ptrs = nullptr;
439   VkPhysicalDeviceVulkan12Features* vulkan12_ptrs = nullptr;
440   VkPhysicalDeviceSubgroupSizeControlFeaturesEXT*
441       subgroup_size_control_features = nullptr;
442   void* ptr = available_features2.pNext;
443   while (ptr != nullptr) {
444     BaseOutStructure* s = static_cast<BaseOutStructure*>(ptr);
445     switch (s->sType) {
446       case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES_KHR:
447         var_ptrs =
448             static_cast<VkPhysicalDeviceVariablePointerFeaturesKHR*>(ptr);
449         break;
450       case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT16_INT8_FEATURES_KHR:
451         float16_ptrs =
452             static_cast<VkPhysicalDeviceFloat16Int8FeaturesKHR*>(ptr);
453         break;
454       case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES_KHR:
455         storage8_ptrs =
456             static_cast<VkPhysicalDevice8BitStorageFeaturesKHR*>(ptr);
457         break;
458       case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES_KHR:
459         storage16_ptrs =
460             static_cast<VkPhysicalDevice16BitStorageFeaturesKHR*>(ptr);
461         break;
462       case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_FEATURES_EXT:
463         subgroup_size_control_features =
464             static_cast<VkPhysicalDeviceSubgroupSizeControlFeaturesEXT*>(ptr);
465         break;
466       case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES:
467         vulkan11_ptrs = static_cast<VkPhysicalDeviceVulkan11Features*>(ptr);
468         break;
469       case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES:
470         vulkan12_ptrs = static_cast<VkPhysicalDeviceVulkan12Features*>(ptr);
471         break;
472       default:
473         break;
474     }
475     ptr = s->pNext;
476   }
477 
478   // Compare the available additional (non-core) features against the
479   // requirements.
480   //
481   // Vulkan 1.2 added support for defining non-core physical device features
482   // using VkPhysicalDeviceVulkan11Features and VkPhysicalDeviceVulkan12Features
483   // structures. If |vulkan11_ptrs| and/or |vulkan12_ptrs| are null, we must
484   // check for features using the old approach (by checking across various
485   // feature structs); otherwise, we can check features via the new structs.
486   for (const auto& feature : required_features) {
487     // First check the feature structures are provided for the required
488     // features.
489     if ((feature == kVariablePointers ||
490          feature == kVariablePointersStorageBuffer) &&
491         var_ptrs == nullptr && vulkan11_ptrs == nullptr) {
492       return amber::Result(
493           "Variable pointers requested but feature not returned");
494     }
495     if ((feature == k16BitStorage_Storage ||
496          feature == k16BitStorage_UniformAndStorage ||
497          feature == k16BitStorage_PushConstant ||
498          feature == k16BitStorage_InputOutput) &&
499         storage16_ptrs == nullptr && vulkan11_ptrs == nullptr) {
500       return amber::Result(
501           "Shader 16-bit storage requested but feature not returned");
502     }
503     if ((feature == kFloat16Int8_Float16 || feature == kFloat16Int8_Int8) &&
504         float16_ptrs == nullptr && vulkan12_ptrs == nullptr) {
505       return amber::Result(
506           "Shader float16/int8 requested but feature not returned");
507     }
508     if ((feature == k8BitStorage_UniformAndStorage ||
509          feature == k8BitStorage_Storage ||
510          feature == k8BitStorage_PushConstant) &&
511         storage8_ptrs == nullptr && vulkan12_ptrs == nullptr) {
512       return amber::Result(
513           "Shader 8-bit storage requested but feature not returned");
514     }
515     if ((feature == kSubgroupSizeControl || feature == kComputeFullSubgroups) &&
516         subgroup_size_control_features == nullptr) {
517       return amber::Result("Missing subgroup size control features");
518     }
519 
520     // Next check the fields of the feature structures.
521 
522     // If Vulkan 1.1 structure exists the features are set there.
523     if (vulkan11_ptrs) {
524       if (feature == kVariablePointers &&
525           vulkan11_ptrs->variablePointers != VK_TRUE) {
526         return amber::Result("Missing variable pointers feature");
527       }
528       if (feature == kVariablePointersStorageBuffer &&
529           vulkan11_ptrs->variablePointersStorageBuffer != VK_TRUE) {
530         return amber::Result(
531             "Missing variable pointers storage buffer feature");
532       }
533       if (feature == k16BitStorage_Storage &&
534           vulkan11_ptrs->storageBuffer16BitAccess != VK_TRUE) {
535         return amber::Result("Missing 16-bit storage access");
536       }
537       if (feature == k16BitStorage_UniformAndStorage &&
538           vulkan11_ptrs->uniformAndStorageBuffer16BitAccess != VK_TRUE) {
539         return amber::Result("Missing 16-bit uniform and storage access");
540       }
541       if (feature == k16BitStorage_PushConstant &&
542           vulkan11_ptrs->storagePushConstant16 != VK_TRUE) {
543         return amber::Result("Missing 16-bit push constant access");
544       }
545       if (feature == k16BitStorage_InputOutput &&
546           vulkan11_ptrs->storageInputOutput16 != VK_TRUE) {
547         return amber::Result("Missing 16-bit input/output access");
548       }
549     } else {
550       // Vulkan 1.1 structure was not found. Use separate structures per each
551       // feature.
552       if (feature == kVariablePointers &&
553           var_ptrs->variablePointers != VK_TRUE) {
554         return amber::Result("Missing variable pointers feature");
555       }
556       if (feature == kVariablePointersStorageBuffer &&
557           var_ptrs->variablePointersStorageBuffer != VK_TRUE) {
558         return amber::Result(
559             "Missing variable pointers storage buffer feature");
560       }
561       if (feature == k16BitStorage_Storage &&
562           storage16_ptrs->storageBuffer16BitAccess != VK_TRUE) {
563         return amber::Result("Missing 16-bit storage access");
564       }
565       if (feature == k16BitStorage_UniformAndStorage &&
566           storage16_ptrs->uniformAndStorageBuffer16BitAccess != VK_TRUE) {
567         return amber::Result("Missing 16-bit uniform and storage access");
568       }
569       if (feature == k16BitStorage_PushConstant &&
570           storage16_ptrs->storagePushConstant16 != VK_TRUE) {
571         return amber::Result("Missing 16-bit push constant access");
572       }
573       if (feature == k16BitStorage_InputOutput &&
574           storage16_ptrs->storageInputOutput16 != VK_TRUE) {
575         return amber::Result("Missing 16-bit input/output access");
576       }
577     }
578 
579     // If Vulkan 1.2 structure exists the features are set there.
580     if (vulkan12_ptrs) {
581       if (feature == kFloat16Int8_Float16 &&
582           vulkan12_ptrs->shaderFloat16 != VK_TRUE) {
583         return amber::Result("Missing float16 feature");
584       }
585       if (feature == kFloat16Int8_Int8 &&
586           vulkan12_ptrs->shaderInt8 != VK_TRUE) {
587         return amber::Result("Missing int8 feature");
588       }
589       if (feature == k8BitStorage_Storage &&
590           vulkan12_ptrs->storageBuffer8BitAccess != VK_TRUE) {
591         return amber::Result("Missing 8-bit storage access");
592       }
593       if (feature == k8BitStorage_UniformAndStorage &&
594           vulkan12_ptrs->uniformAndStorageBuffer8BitAccess != VK_TRUE) {
595         return amber::Result("Missing 8-bit uniform and storage access");
596       }
597       if (feature == k8BitStorage_PushConstant &&
598           vulkan12_ptrs->storagePushConstant8 != VK_TRUE) {
599         return amber::Result("Missing 8-bit push constant access");
600       }
601     } else {
602       // Vulkan 1.2 structure was not found. Use separate structures per each
603       // feature.
604       if (feature == kFloat16Int8_Float16 &&
605           float16_ptrs->shaderFloat16 != VK_TRUE) {
606         return amber::Result("Missing float16 feature");
607       }
608       if (feature == kFloat16Int8_Int8 && float16_ptrs->shaderInt8 != VK_TRUE) {
609         return amber::Result("Missing int8 feature");
610       }
611       if (feature == k8BitStorage_Storage &&
612           storage8_ptrs->storageBuffer8BitAccess != VK_TRUE) {
613         return amber::Result("Missing 8-bit storage access");
614       }
615       if (feature == k8BitStorage_UniformAndStorage &&
616           storage8_ptrs->uniformAndStorageBuffer8BitAccess != VK_TRUE) {
617         return amber::Result("Missing 8-bit uniform and storage access");
618       }
619       if (feature == k8BitStorage_PushConstant &&
620           storage8_ptrs->storagePushConstant8 != VK_TRUE) {
621         return amber::Result("Missing 8-bit push constant access");
622       }
623     }
624 
625     if (feature == kSubgroupSizeControl &&
626         subgroup_size_control_features->subgroupSizeControl != VK_TRUE) {
627       return amber::Result("Missing subgroup size control feature");
628     }
629     if (feature == kComputeFullSubgroups &&
630         subgroup_size_control_features->computeFullSubgroups != VK_TRUE) {
631       return amber::Result("Missing compute full subgroups feature");
632     }
633   }
634 
635   if (!AreAllExtensionsSupported(available_extensions,
636                                  required_device_extensions)) {
637     return Result(
638         "Vulkan: Device::Initialize given physical device does not support "
639         "required extensions");
640   }
641 
642   ptrs_.vkGetPhysicalDeviceMemoryProperties(physical_device_,
643                                             &physical_memory_properties_);
644 
645   subgroup_size_control_properties_ = {};
646   const bool needs_subgroup_size_control =
647       std::find(required_features.begin(), required_features.end(),
648                 kSubgroupSizeControl) != required_features.end();
649 
650   if (needs_subgroup_size_control) {
651     VkPhysicalDeviceProperties2 properties2 = {};
652     properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
653     properties2.pNext = &subgroup_size_control_properties_;
654     subgroup_size_control_properties_.sType =
655         VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_PROPERTIES_EXT;
656 
657     if (!SupportsApiVersion(1, 1, 0)) {
658       return Result(
659           "Vulkan: Device::Initialize subgroup size control feature also "
660           "requires an API version of 1.1 or higher");
661     }
662     ptrs_.vkGetPhysicalDeviceProperties2(physical_device_, &properties2);
663   }
664 
665   return {};
666 }
667 
IsFormatSupportedByPhysicalDevice(const Format & format,BufferType type)668 bool Device::IsFormatSupportedByPhysicalDevice(const Format& format,
669                                                BufferType type) {
670   VkFormat vk_format = GetVkFormat(format);
671   VkFormatProperties properties = VkFormatProperties();
672   GetPtrs()->vkGetPhysicalDeviceFormatProperties(physical_device_, vk_format,
673                                                  &properties);
674 
675   VkFormatFeatureFlagBits flag = VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT;
676   bool is_buffer_type_image = false;
677   switch (type) {
678     case BufferType::kColor:
679     case BufferType::kStorageImage:
680       flag = VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT;
681       is_buffer_type_image = true;
682       break;
683     case BufferType::kDepthStencil:
684       flag = VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT;
685       is_buffer_type_image = true;
686       break;
687     case BufferType::kSampledImage:
688     case BufferType::kCombinedImageSampler:
689       flag = VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT;
690       is_buffer_type_image = true;
691       break;
692     case BufferType::kVertex:
693       flag = VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT;
694       is_buffer_type_image = false;
695       break;
696     default:
697       return false;
698   }
699 
700   return ((is_buffer_type_image ? properties.optimalTilingFeatures
701                                 : properties.bufferFeatures) &
702           flag) == flag;
703 }
704 
HasMemoryFlags(uint32_t memory_type_index,const VkMemoryPropertyFlags flags) const705 bool Device::HasMemoryFlags(uint32_t memory_type_index,
706                             const VkMemoryPropertyFlags flags) const {
707   return (physical_memory_properties_.memoryTypes[memory_type_index]
708               .propertyFlags &
709           flags) == flags;
710 }
711 
IsMemoryHostAccessible(uint32_t memory_type_index) const712 bool Device::IsMemoryHostAccessible(uint32_t memory_type_index) const {
713   return HasMemoryFlags(memory_type_index, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
714 }
715 
IsMemoryHostCoherent(uint32_t memory_type_index) const716 bool Device::IsMemoryHostCoherent(uint32_t memory_type_index) const {
717   return HasMemoryFlags(memory_type_index,
718                         VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
719 }
720 
GetMaxPushConstants() const721 uint32_t Device::GetMaxPushConstants() const {
722   return physical_device_properties_.limits.maxPushConstantsSize;
723 }
724 
IsDescriptorSetInBounds(uint32_t descriptor_set) const725 bool Device::IsDescriptorSetInBounds(uint32_t descriptor_set) const {
726   VkPhysicalDeviceProperties properties = VkPhysicalDeviceProperties();
727   GetPtrs()->vkGetPhysicalDeviceProperties(physical_device_, &properties);
728   return properties.limits.maxBoundDescriptorSets > descriptor_set;
729 }
730 
GetVkFormat(const Format & format) const731 VkFormat Device::GetVkFormat(const Format& format) const {
732   VkFormat ret = VK_FORMAT_UNDEFINED;
733   switch (format.GetFormatType()) {
734     case FormatType::kUnknown:
735       ret = VK_FORMAT_UNDEFINED;
736       break;
737     case FormatType::kA1R5G5B5_UNORM_PACK16:
738       ret = VK_FORMAT_A1R5G5B5_UNORM_PACK16;
739       break;
740     case FormatType::kA2B10G10R10_SINT_PACK32:
741       ret = VK_FORMAT_A2B10G10R10_SINT_PACK32;
742       break;
743     case FormatType::kA2B10G10R10_SNORM_PACK32:
744       ret = VK_FORMAT_A2B10G10R10_SNORM_PACK32;
745       break;
746     case FormatType::kA2B10G10R10_SSCALED_PACK32:
747       ret = VK_FORMAT_A2B10G10R10_SSCALED_PACK32;
748       break;
749     case FormatType::kA2B10G10R10_UINT_PACK32:
750       ret = VK_FORMAT_A2B10G10R10_UINT_PACK32;
751       break;
752     case FormatType::kA2B10G10R10_UNORM_PACK32:
753       ret = VK_FORMAT_A2B10G10R10_UNORM_PACK32;
754       break;
755     case FormatType::kA2B10G10R10_USCALED_PACK32:
756       ret = VK_FORMAT_A2B10G10R10_USCALED_PACK32;
757       break;
758     case FormatType::kA2R10G10B10_SINT_PACK32:
759       ret = VK_FORMAT_A2R10G10B10_SINT_PACK32;
760       break;
761     case FormatType::kA2R10G10B10_SNORM_PACK32:
762       ret = VK_FORMAT_A2R10G10B10_SNORM_PACK32;
763       break;
764     case FormatType::kA2R10G10B10_SSCALED_PACK32:
765       ret = VK_FORMAT_A2R10G10B10_SSCALED_PACK32;
766       break;
767     case FormatType::kA2R10G10B10_UINT_PACK32:
768       ret = VK_FORMAT_A2R10G10B10_UINT_PACK32;
769       break;
770     case FormatType::kA2R10G10B10_UNORM_PACK32:
771       ret = VK_FORMAT_A2R10G10B10_UNORM_PACK32;
772       break;
773     case FormatType::kA2R10G10B10_USCALED_PACK32:
774       ret = VK_FORMAT_A2R10G10B10_USCALED_PACK32;
775       break;
776     case FormatType::kA8B8G8R8_SINT_PACK32:
777       ret = VK_FORMAT_A8B8G8R8_SINT_PACK32;
778       break;
779     case FormatType::kA8B8G8R8_SNORM_PACK32:
780       ret = VK_FORMAT_A8B8G8R8_SNORM_PACK32;
781       break;
782     case FormatType::kA8B8G8R8_SRGB_PACK32:
783       ret = VK_FORMAT_A8B8G8R8_SRGB_PACK32;
784       break;
785     case FormatType::kA8B8G8R8_SSCALED_PACK32:
786       ret = VK_FORMAT_A8B8G8R8_SSCALED_PACK32;
787       break;
788     case FormatType::kA8B8G8R8_UINT_PACK32:
789       ret = VK_FORMAT_A8B8G8R8_UINT_PACK32;
790       break;
791     case FormatType::kA8B8G8R8_UNORM_PACK32:
792       ret = VK_FORMAT_A8B8G8R8_UNORM_PACK32;
793       break;
794     case FormatType::kA8B8G8R8_USCALED_PACK32:
795       ret = VK_FORMAT_A8B8G8R8_USCALED_PACK32;
796       break;
797     case FormatType::kB10G11R11_UFLOAT_PACK32:
798       ret = VK_FORMAT_B10G11R11_UFLOAT_PACK32;
799       break;
800     case FormatType::kB4G4R4A4_UNORM_PACK16:
801       ret = VK_FORMAT_B4G4R4A4_UNORM_PACK16;
802       break;
803     case FormatType::kB5G5R5A1_UNORM_PACK16:
804       ret = VK_FORMAT_B5G5R5A1_UNORM_PACK16;
805       break;
806     case FormatType::kB5G6R5_UNORM_PACK16:
807       ret = VK_FORMAT_B5G6R5_UNORM_PACK16;
808       break;
809     case FormatType::kB8G8R8A8_SINT:
810       ret = VK_FORMAT_B8G8R8A8_SINT;
811       break;
812     case FormatType::kB8G8R8A8_SNORM:
813       ret = VK_FORMAT_B8G8R8A8_SNORM;
814       break;
815     case FormatType::kB8G8R8A8_SRGB:
816       ret = VK_FORMAT_B8G8R8A8_SRGB;
817       break;
818     case FormatType::kB8G8R8A8_SSCALED:
819       ret = VK_FORMAT_B8G8R8A8_SSCALED;
820       break;
821     case FormatType::kB8G8R8A8_UINT:
822       ret = VK_FORMAT_B8G8R8A8_UINT;
823       break;
824     case FormatType::kB8G8R8A8_UNORM:
825       ret = VK_FORMAT_B8G8R8A8_UNORM;
826       break;
827     case FormatType::kB8G8R8A8_USCALED:
828       ret = VK_FORMAT_B8G8R8A8_USCALED;
829       break;
830     case FormatType::kB8G8R8_SINT:
831       ret = VK_FORMAT_B8G8R8_SINT;
832       break;
833     case FormatType::kB8G8R8_SNORM:
834       ret = VK_FORMAT_B8G8R8_SNORM;
835       break;
836     case FormatType::kB8G8R8_SRGB:
837       ret = VK_FORMAT_B8G8R8_SRGB;
838       break;
839     case FormatType::kB8G8R8_SSCALED:
840       ret = VK_FORMAT_B8G8R8_SSCALED;
841       break;
842     case FormatType::kB8G8R8_UINT:
843       ret = VK_FORMAT_B8G8R8_UINT;
844       break;
845     case FormatType::kB8G8R8_UNORM:
846       ret = VK_FORMAT_B8G8R8_UNORM;
847       break;
848     case FormatType::kB8G8R8_USCALED:
849       ret = VK_FORMAT_B8G8R8_USCALED;
850       break;
851     case FormatType::kD16_UNORM:
852       ret = VK_FORMAT_D16_UNORM;
853       break;
854     case FormatType::kD16_UNORM_S8_UINT:
855       ret = VK_FORMAT_D16_UNORM_S8_UINT;
856       break;
857     case FormatType::kD24_UNORM_S8_UINT:
858       ret = VK_FORMAT_D24_UNORM_S8_UINT;
859       break;
860     case FormatType::kD32_SFLOAT:
861       ret = VK_FORMAT_D32_SFLOAT;
862       break;
863     case FormatType::kD32_SFLOAT_S8_UINT:
864       ret = VK_FORMAT_D32_SFLOAT_S8_UINT;
865       break;
866     case FormatType::kR16G16B16A16_SFLOAT:
867       ret = VK_FORMAT_R16G16B16A16_SFLOAT;
868       break;
869     case FormatType::kR16G16B16A16_SINT:
870       ret = VK_FORMAT_R16G16B16A16_SINT;
871       break;
872     case FormatType::kR16G16B16A16_SNORM:
873       ret = VK_FORMAT_R16G16B16A16_SNORM;
874       break;
875     case FormatType::kR16G16B16A16_SSCALED:
876       ret = VK_FORMAT_R16G16B16A16_SSCALED;
877       break;
878     case FormatType::kR16G16B16A16_UINT:
879       ret = VK_FORMAT_R16G16B16A16_UINT;
880       break;
881     case FormatType::kR16G16B16A16_UNORM:
882       ret = VK_FORMAT_R16G16B16A16_UNORM;
883       break;
884     case FormatType::kR16G16B16A16_USCALED:
885       ret = VK_FORMAT_R16G16B16A16_USCALED;
886       break;
887     case FormatType::kR16G16B16_SFLOAT:
888       ret = VK_FORMAT_R16G16B16_SFLOAT;
889       break;
890     case FormatType::kR16G16B16_SINT:
891       ret = VK_FORMAT_R16G16B16_SINT;
892       break;
893     case FormatType::kR16G16B16_SNORM:
894       ret = VK_FORMAT_R16G16B16_SNORM;
895       break;
896     case FormatType::kR16G16B16_SSCALED:
897       ret = VK_FORMAT_R16G16B16_SSCALED;
898       break;
899     case FormatType::kR16G16B16_UINT:
900       ret = VK_FORMAT_R16G16B16_UINT;
901       break;
902     case FormatType::kR16G16B16_UNORM:
903       ret = VK_FORMAT_R16G16B16_UNORM;
904       break;
905     case FormatType::kR16G16B16_USCALED:
906       ret = VK_FORMAT_R16G16B16_USCALED;
907       break;
908     case FormatType::kR16G16_SFLOAT:
909       ret = VK_FORMAT_R16G16_SFLOAT;
910       break;
911     case FormatType::kR16G16_SINT:
912       ret = VK_FORMAT_R16G16_SINT;
913       break;
914     case FormatType::kR16G16_SNORM:
915       ret = VK_FORMAT_R16G16_SNORM;
916       break;
917     case FormatType::kR16G16_SSCALED:
918       ret = VK_FORMAT_R16G16_SSCALED;
919       break;
920     case FormatType::kR16G16_UINT:
921       ret = VK_FORMAT_R16G16_UINT;
922       break;
923     case FormatType::kR16G16_UNORM:
924       ret = VK_FORMAT_R16G16_UNORM;
925       break;
926     case FormatType::kR16G16_USCALED:
927       ret = VK_FORMAT_R16G16_USCALED;
928       break;
929     case FormatType::kR16_SFLOAT:
930       ret = VK_FORMAT_R16_SFLOAT;
931       break;
932     case FormatType::kR16_SINT:
933       ret = VK_FORMAT_R16_SINT;
934       break;
935     case FormatType::kR16_SNORM:
936       ret = VK_FORMAT_R16_SNORM;
937       break;
938     case FormatType::kR16_SSCALED:
939       ret = VK_FORMAT_R16_SSCALED;
940       break;
941     case FormatType::kR16_UINT:
942       ret = VK_FORMAT_R16_UINT;
943       break;
944     case FormatType::kR16_UNORM:
945       ret = VK_FORMAT_R16_UNORM;
946       break;
947     case FormatType::kR16_USCALED:
948       ret = VK_FORMAT_R16_USCALED;
949       break;
950     case FormatType::kR32G32B32A32_SFLOAT:
951       ret = VK_FORMAT_R32G32B32A32_SFLOAT;
952       break;
953     case FormatType::kR32G32B32A32_SINT:
954       ret = VK_FORMAT_R32G32B32A32_SINT;
955       break;
956     case FormatType::kR32G32B32A32_UINT:
957       ret = VK_FORMAT_R32G32B32A32_UINT;
958       break;
959     case FormatType::kR32G32B32_SFLOAT:
960       ret = VK_FORMAT_R32G32B32_SFLOAT;
961       break;
962     case FormatType::kR32G32B32_SINT:
963       ret = VK_FORMAT_R32G32B32_SINT;
964       break;
965     case FormatType::kR32G32B32_UINT:
966       ret = VK_FORMAT_R32G32B32_UINT;
967       break;
968     case FormatType::kR32G32_SFLOAT:
969       ret = VK_FORMAT_R32G32_SFLOAT;
970       break;
971     case FormatType::kR32G32_SINT:
972       ret = VK_FORMAT_R32G32_SINT;
973       break;
974     case FormatType::kR32G32_UINT:
975       ret = VK_FORMAT_R32G32_UINT;
976       break;
977     case FormatType::kR32_SFLOAT:
978       ret = VK_FORMAT_R32_SFLOAT;
979       break;
980     case FormatType::kR32_SINT:
981       ret = VK_FORMAT_R32_SINT;
982       break;
983     case FormatType::kR32_UINT:
984       ret = VK_FORMAT_R32_UINT;
985       break;
986     case FormatType::kR4G4B4A4_UNORM_PACK16:
987       ret = VK_FORMAT_R4G4B4A4_UNORM_PACK16;
988       break;
989     case FormatType::kR4G4_UNORM_PACK8:
990       ret = VK_FORMAT_R4G4_UNORM_PACK8;
991       break;
992     case FormatType::kR5G5B5A1_UNORM_PACK16:
993       ret = VK_FORMAT_R5G5B5A1_UNORM_PACK16;
994       break;
995     case FormatType::kR5G6B5_UNORM_PACK16:
996       ret = VK_FORMAT_R5G6B5_UNORM_PACK16;
997       break;
998     case FormatType::kR64G64B64A64_SFLOAT:
999       ret = VK_FORMAT_R64G64B64A64_SFLOAT;
1000       break;
1001     case FormatType::kR64G64B64A64_SINT:
1002       ret = VK_FORMAT_R64G64B64A64_SINT;
1003       break;
1004     case FormatType::kR64G64B64A64_UINT:
1005       ret = VK_FORMAT_R64G64B64A64_UINT;
1006       break;
1007     case FormatType::kR64G64B64_SFLOAT:
1008       ret = VK_FORMAT_R64G64B64_SFLOAT;
1009       break;
1010     case FormatType::kR64G64B64_SINT:
1011       ret = VK_FORMAT_R64G64B64_SINT;
1012       break;
1013     case FormatType::kR64G64B64_UINT:
1014       ret = VK_FORMAT_R64G64B64_UINT;
1015       break;
1016     case FormatType::kR64G64_SFLOAT:
1017       ret = VK_FORMAT_R64G64_SFLOAT;
1018       break;
1019     case FormatType::kR64G64_SINT:
1020       ret = VK_FORMAT_R64G64_SINT;
1021       break;
1022     case FormatType::kR64G64_UINT:
1023       ret = VK_FORMAT_R64G64_UINT;
1024       break;
1025     case FormatType::kR64_SFLOAT:
1026       ret = VK_FORMAT_R64_SFLOAT;
1027       break;
1028     case FormatType::kR64_SINT:
1029       ret = VK_FORMAT_R64_SINT;
1030       break;
1031     case FormatType::kR64_UINT:
1032       ret = VK_FORMAT_R64_UINT;
1033       break;
1034     case FormatType::kR8G8B8A8_SINT:
1035       ret = VK_FORMAT_R8G8B8A8_SINT;
1036       break;
1037     case FormatType::kR8G8B8A8_SNORM:
1038       ret = VK_FORMAT_R8G8B8A8_SNORM;
1039       break;
1040     case FormatType::kR8G8B8A8_SRGB:
1041       ret = VK_FORMAT_R8G8B8A8_SRGB;
1042       break;
1043     case FormatType::kR8G8B8A8_SSCALED:
1044       ret = VK_FORMAT_R8G8B8A8_SSCALED;
1045       break;
1046     case FormatType::kR8G8B8A8_UINT:
1047       ret = VK_FORMAT_R8G8B8A8_UINT;
1048       break;
1049     case FormatType::kR8G8B8A8_UNORM:
1050       ret = VK_FORMAT_R8G8B8A8_UNORM;
1051       break;
1052     case FormatType::kR8G8B8A8_USCALED:
1053       ret = VK_FORMAT_R8G8B8A8_USCALED;
1054       break;
1055     case FormatType::kR8G8B8_SINT:
1056       ret = VK_FORMAT_R8G8B8_SINT;
1057       break;
1058     case FormatType::kR8G8B8_SNORM:
1059       ret = VK_FORMAT_R8G8B8_SNORM;
1060       break;
1061     case FormatType::kR8G8B8_SRGB:
1062       ret = VK_FORMAT_R8G8B8_SRGB;
1063       break;
1064     case FormatType::kR8G8B8_SSCALED:
1065       ret = VK_FORMAT_R8G8B8_SSCALED;
1066       break;
1067     case FormatType::kR8G8B8_UINT:
1068       ret = VK_FORMAT_R8G8B8_UINT;
1069       break;
1070     case FormatType::kR8G8B8_UNORM:
1071       ret = VK_FORMAT_R8G8B8_UNORM;
1072       break;
1073     case FormatType::kR8G8B8_USCALED:
1074       ret = VK_FORMAT_R8G8B8_USCALED;
1075       break;
1076     case FormatType::kR8G8_SINT:
1077       ret = VK_FORMAT_R8G8_SINT;
1078       break;
1079     case FormatType::kR8G8_SNORM:
1080       ret = VK_FORMAT_R8G8_SNORM;
1081       break;
1082     case FormatType::kR8G8_SRGB:
1083       ret = VK_FORMAT_R8G8_SRGB;
1084       break;
1085     case FormatType::kR8G8_SSCALED:
1086       ret = VK_FORMAT_R8G8_SSCALED;
1087       break;
1088     case FormatType::kR8G8_UINT:
1089       ret = VK_FORMAT_R8G8_UINT;
1090       break;
1091     case FormatType::kR8G8_UNORM:
1092       ret = VK_FORMAT_R8G8_UNORM;
1093       break;
1094     case FormatType::kR8G8_USCALED:
1095       ret = VK_FORMAT_R8G8_USCALED;
1096       break;
1097     case FormatType::kR8_SINT:
1098       ret = VK_FORMAT_R8_SINT;
1099       break;
1100     case FormatType::kR8_SNORM:
1101       ret = VK_FORMAT_R8_SNORM;
1102       break;
1103     case FormatType::kR8_SRGB:
1104       ret = VK_FORMAT_R8_SRGB;
1105       break;
1106     case FormatType::kR8_SSCALED:
1107       ret = VK_FORMAT_R8_SSCALED;
1108       break;
1109     case FormatType::kR8_UINT:
1110       ret = VK_FORMAT_R8_UINT;
1111       break;
1112     case FormatType::kR8_UNORM:
1113       ret = VK_FORMAT_R8_UNORM;
1114       break;
1115     case FormatType::kR8_USCALED:
1116       ret = VK_FORMAT_R8_USCALED;
1117       break;
1118     case FormatType::kS8_UINT:
1119       ret = VK_FORMAT_S8_UINT;
1120       break;
1121     case FormatType::kX8_D24_UNORM_PACK32:
1122       ret = VK_FORMAT_X8_D24_UNORM_PACK32;
1123       break;
1124   }
1125   return ret;
1126 }
1127 
IsRequiredSubgroupSizeSupported(const ShaderType type,const uint32_t required_subgroup_size) const1128 bool Device::IsRequiredSubgroupSizeSupported(
1129     const ShaderType type,
1130     const uint32_t required_subgroup_size) const {
1131   VkShaderStageFlagBits stage = {};
1132   switch (type) {
1133     case kShaderTypeGeometry:
1134       stage = VK_SHADER_STAGE_GEOMETRY_BIT;
1135       break;
1136     case kShaderTypeFragment:
1137       stage = VK_SHADER_STAGE_FRAGMENT_BIT;
1138       break;
1139     case kShaderTypeVertex:
1140       stage = VK_SHADER_STAGE_VERTEX_BIT;
1141       break;
1142     case kShaderTypeTessellationControl:
1143       stage = VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT;
1144       break;
1145     case kShaderTypeTessellationEvaluation:
1146       stage = VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
1147       break;
1148     case kShaderTypeCompute:
1149       stage = VK_SHADER_STAGE_COMPUTE_BIT;
1150       break;
1151     default:
1152       return false;
1153   }
1154   if ((stage & subgroup_size_control_properties_.requiredSubgroupSizeStages) ==
1155       0) {
1156     return false;
1157   }
1158   if (required_subgroup_size == 0 ||
1159       required_subgroup_size <
1160           subgroup_size_control_properties_.minSubgroupSize ||
1161       required_subgroup_size >
1162           subgroup_size_control_properties_.maxSubgroupSize) {
1163     return false;
1164   }
1165 
1166   return true;
1167 }
1168 
GetMinSubgroupSize() const1169 uint32_t Device::GetMinSubgroupSize() const {
1170   return subgroup_size_control_properties_.minSubgroupSize;
1171 }
1172 
GetMaxSubgroupSize() const1173 uint32_t Device::GetMaxSubgroupSize() const {
1174   return subgroup_size_control_properties_.maxSubgroupSize;
1175 }
1176 
1177 }  // namespace vulkan
1178 }  // namespace amber
1179