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