| Flutter Impeller |

capabilities_vk.cc
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "impeller/renderer/backend/vulkan/capabilities_vk.h"
6
7 #include <algorithm>
8 #include <array>
9
10 #include "impeller/base/validation.h"
11 #include "impeller/core/formats.h"
12 #include "impeller/renderer/backend/vulkan/vk.h"
13 #include "impeller/renderer/backend/vulkan/workarounds_vk.h"
14
15 // vulkan.hpp generates some clang-tidy warnings.
16 // NOLINTBEGIN(clang-analyzer-security.PointerSub)
17
18 namespace impeller {
19
20 static constexpr const char* kInstanceLayer = "ImpellerInstance";
21
22 CapabilitiesVK::CapabilitiesVK(bool enable_validations,
23 bool fatal_missing_validations,
24 bool use_embedder_extensions,
25 std::vector<std::string> instance_extensions,
26 std::vector<std::string> device_extensions)
27 : use_embedder_extensions_(use_embedder_extensions),
28 embedder_instance_extensions_(std::move(instance_extensions)),
29 embedder_device_extensions_(std::move(device_extensions)) {
30 if (!use_embedder_extensions_) {
31 auto extensions = vk::enumerateInstanceExtensionProperties();
32 auto layers = vk::enumerateInstanceLayerProperties();
33
34 if (extensions.result != vk::Result::eSuccess ||
35 layers.result != vk::Result::eSuccess) {
36 return;
37 }
38
39 for (const auto& ext : extensions.value) {
40 exts_[kInstanceLayer].insert(ext.extensionName);
41 }
42
43 for (const auto& layer : layers.value) {
44 const std::string layer_name = layer.layerName;
45 auto layer_exts = vk::enumerateInstanceExtensionProperties(layer_name);
46 if (layer_exts.result != vk::Result::eSuccess) {
47 return;
48 }
49 for (const auto& layer_ext : layer_exts.value) {
50 exts_[layer_name].insert(layer_ext.extensionName);
51 }
52 }
53 } else {
54 for (const auto& ext : embedder_instance_extensions_) {
55 exts_[kInstanceLayer].insert(ext);
56 }
57 }
58
59 validations_enabled_ =
60 enable_validations && HasLayer("VK_LAYER_KHRONOS_validation");
61 if (enable_validations && !validations_enabled_) {
62 FML_LOG(ERROR)
63 << "Requested Impeller context creation with validations but the "
64 "validation layers could not be found. Expect no Vulkan validation "
65 "checks!";
66 if (fatal_missing_validations) {
67 FML_LOG(FATAL) << "Validation missing. Exiting.";
68 }
69 }
70 if (validations_enabled_) {
71 FML_LOG(INFO) << "Vulkan validations are enabled.";
72 }
73 is_valid_ = true;
74 }
75
76 CapabilitiesVK::~CapabilitiesVK() = default;
77
78 bool CapabilitiesVK::IsValid() const {
79 return is_valid_;
80 }
81
82 bool CapabilitiesVK::AreValidationsEnabled() const {
83 return validations_enabled_;
84 }
85
86 std::optional<std::vector<std::string>> CapabilitiesVK::GetEnabledLayers()
87 const {
88 std::vector<std::string> required;
89
90 if (validations_enabled_) {
91 // The presence of this layer is already checked in the ctor.
92 required.push_back("VK_LAYER_KHRONOS_validation");
93 }
94
95 return required;
96 }
97
98 std::optional<std::vector<std::string>>
99 CapabilitiesVK::GetEnabledInstanceExtensions() const {
100 std::vector<std::string> required;
101
102 if (!HasExtension("VK_KHR_surface")) {
103 // Swapchain support is required and this is a dependency of
104 // VK_KHR_swapchain.
105 VALIDATION_LOG << "Could not find the surface extension.";
106 return std::nullopt;
107 }
108 required.push_back("VK_KHR_surface");
109
110 auto has_wsi = false;
111 if (HasExtension("VK_MVK_macos_surface")) {
112 required.push_back("VK_MVK_macos_surface");
113 has_wsi = true;
114 }
115
116 if (HasExtension("VK_EXT_metal_surface")) {
117 required.push_back("VK_EXT_metal_surface");
118 has_wsi = true;
119 }
120
121 if (HasExtension("VK_KHR_portability_enumeration")) {
122 required.push_back("VK_KHR_portability_enumeration");
123 has_wsi = true;
124 }
125
126 if (HasExtension("VK_KHR_win32_surface")) {
127 required.push_back("VK_KHR_win32_surface");
128 has_wsi = true;
129 }
130
131 if (HasExtension("VK_KHR_android_surface")) {
132 required.push_back("VK_KHR_android_surface");
133 has_wsi = true;
134 }
135
136 if (HasExtension("VK_KHR_xcb_surface")) {
137 required.push_back("VK_KHR_xcb_surface");
138 has_wsi = true;
139 }
140
141 if (HasExtension("VK_KHR_xlib_surface")) {
142 required.push_back("VK_KHR_xlib_surface");
143 has_wsi = true;
144 }
145
146 if (HasExtension("VK_KHR_wayland_surface")) {
147 required.push_back("VK_KHR_wayland_surface");
148 has_wsi = true;
149 }
150
151 if (!has_wsi) {
152 // Don't really care which WSI extension there is as long there is at least
153 // one.
154 VALIDATION_LOG << "Could not find a WSI extension.";
155 return std::nullopt;
156 }
157
158 if (validations_enabled_) {
159 if (!HasExtension("VK_EXT_debug_utils")) {
160 VALIDATION_LOG << "Requested validations but could not find the "
161 "VK_EXT_debug_utils extension.";
162 return std::nullopt;
163 }
164 required.push_back("VK_EXT_debug_utils");
165
166 if (HasExtension("VK_EXT_validation_features")) {
167 // It's valid to not have `VK_EXT_validation_features` available. That's
168 // the case when using AGI as a frame debugger.
169 required.push_back("VK_EXT_validation_features");
170 }
171 }
172
173 return required;
174 }
175
176 static const char* GetExtensionName(RequiredCommonDeviceExtensionVK ext) {
177 switch (ext) {
178 case RequiredCommonDeviceExtensionVK::kKHRSwapchain:
179 return VK_KHR_SWAPCHAIN_EXTENSION_NAME;
180 case RequiredCommonDeviceExtensionVK::kLast:
181 return "Unknown";
182 }
183 FML_UNREACHABLE();
184 }
185
186 static const char* GetExtensionName(RequiredAndroidDeviceExtensionVK ext) {
187 switch (ext) {
188 case RequiredAndroidDeviceExtensionVK::
189 kANDROIDExternalMemoryAndroidHardwareBuffer:
190 return "VK_ANDROID_external_memory_android_hardware_buffer";
191 case RequiredAndroidDeviceExtensionVK::kKHRSamplerYcbcrConversion:
192 return VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME;
193 case RequiredAndroidDeviceExtensionVK::kKHRExternalMemory:
194 return VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME;
195 case RequiredAndroidDeviceExtensionVK::kEXTQueueFamilyForeign:
196 return VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME;
197 case RequiredAndroidDeviceExtensionVK::kKHRDedicatedAllocation:
198 return VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME;
199 case RequiredAndroidDeviceExtensionVK::kLast:
200 return "Unknown";
201 }
202 FML_UNREACHABLE();
203 }
204
205 static const char* GetExtensionName(OptionalAndroidDeviceExtensionVK ext) {
206 switch (ext) {
207 case OptionalAndroidDeviceExtensionVK::kKHRExternalFenceFd:
208 return VK_KHR_EXTERNAL_FENCE_FD_EXTENSION_NAME;
209 case OptionalAndroidDeviceExtensionVK::kKHRExternalFence:
210 return VK_KHR_EXTERNAL_FENCE_EXTENSION_NAME;
211 case OptionalAndroidDeviceExtensionVK::kKHRExternalSemaphoreFd:
212 return VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME;
213 case OptionalAndroidDeviceExtensionVK::kKHRExternalSemaphore:
214 return VK_KHR_EXTERNAL_SEMAPHORE_EXTENSION_NAME;
215 case OptionalAndroidDeviceExtensionVK::kLast:
216 return "Unknown";
217 }
218 }
219
220 static const char* GetExtensionName(OptionalDeviceExtensionVK ext) {
221 switch (ext) {
222 case OptionalDeviceExtensionVK::kEXTPipelineCreationFeedback:
223 return VK_EXT_PIPELINE_CREATION_FEEDBACK_EXTENSION_NAME;
224 case OptionalDeviceExtensionVK::kVKKHRPortabilitySubset:
225 return "VK_KHR_portability_subset";
226 case OptionalDeviceExtensionVK::kEXTImageCompressionControl:
227 return VK_EXT_IMAGE_COMPRESSION_CONTROL_EXTENSION_NAME;
228 case OptionalDeviceExtensionVK::kLast:
229 return "Unknown";
230 }
231 FML_UNREACHABLE();
232 }
233
234 template <class T>
235 static bool IterateExtensions(const std::function<bool(T)>& it) {
236 if (!it) {
237 return false;
238 }
239 for (size_t i = 0; i < static_cast<uint32_t>(T::kLast); i++) {
240 if (!it(static_cast<T>(i))) {
241 return false;
242 }
243 }
244 return true;
245 }
246
247 static std::optional<std::set<std::string>> GetSupportedDeviceExtensions(
248 const vk::PhysicalDevice& physical_device) {
249 auto device_extensions = physical_device.enumerateDeviceExtensionProperties();
250 if (device_extensions.result != vk::Result::eSuccess) {
251 return std::nullopt;
252 }
253
254 std::set<std::string> exts;
255 for (const auto& device_extension : device_extensions.value) {
256 exts.insert(device_extension.extensionName);
257 };
258
259 return exts;
260 }
261
262 std::optional<std::vector<std::string>>
263 CapabilitiesVK::GetEnabledDeviceExtensions(
264 const vk::PhysicalDevice& physical_device) const {
265 std::set<std::string> exts;
266
267 if (!use_embedder_extensions_) {
268 auto maybe_exts = GetSupportedDeviceExtensions(physical_device);
269
270 if (!maybe_exts.has_value()) {
271 return std::nullopt;
272 }
273 exts = maybe_exts.value();
274 } else {
275 for (const auto& ext : embedder_device_extensions_) {
276 exts.insert(ext);
277 }
278 }
279
280 std::vector<std::string> enabled;
281
282 auto for_each_common_extension = [&](RequiredCommonDeviceExtensionVK ext) {
283 auto name = GetExtensionName(ext);
284 if (exts.find(name) == exts.end()) {
285 VALIDATION_LOG << "Device does not support required extension: " << name;
286 return false;
287 }
288 enabled.push_back(name);
289 return true;
290 };
291
292 auto for_each_android_extension = [&](RequiredAndroidDeviceExtensionVK ext) {
293 #ifdef FML_OS_ANDROID
294 auto name = GetExtensionName(ext);
295 if (exts.find(name) == exts.end()) {
296 VALIDATION_LOG << "Device does not support required Android extension: "
297 << name;
298 return false;
299 }
300 enabled.push_back(name);
301 #endif // FML_OS_ANDROID
302 return true;
303 };
304
305 auto for_each_optional_android_extension =
306 [&](OptionalAndroidDeviceExtensionVK ext) {
307 #ifdef FML_OS_ANDROID
308 auto name = GetExtensionName(ext);
309 if (exts.find(name) != exts.end()) {
310 enabled.push_back(name);
311 }
312 #endif // FML_OS_ANDROID
313 return true;
314 };
315
316 auto for_each_optional_extension = [&](OptionalDeviceExtensionVK ext) {
317 auto name = GetExtensionName(ext);
318 if (exts.find(name) != exts.end()) {
319 enabled.push_back(name);
320 }
321 return true;
322 };
323
324 const auto iterate_extensions =
325 IterateExtensions<RequiredCommonDeviceExtensionVK>(
326 for_each_common_extension) &&
327 IterateExtensions<RequiredAndroidDeviceExtensionVK>(
328 for_each_android_extension) &&
329 IterateExtensions<OptionalDeviceExtensionVK>(
330 for_each_optional_extension) &&
331 IterateExtensions<OptionalAndroidDeviceExtensionVK>(
332 for_each_optional_android_extension);
333
334 if (!iterate_extensions) {
335 VALIDATION_LOG << "Device not suitable since required extensions are not "
336 "supported.";
337 return std::nullopt;
338 }
339
340 return enabled;
341 }
342
343 static bool HasSuitableColorFormat(const vk::PhysicalDevice& device,
344 vk::Format format) {
345 const auto props = device.getFormatProperties(format);
346 // This needs to be more comprehensive.
347 return !!(props.optimalTilingFeatures &
348 vk::FormatFeatureFlagBits::eColorAttachment);
349 }
350
351 static bool HasSuitableDepthStencilFormat(const vk::PhysicalDevice& device,
352 vk::Format format) {
353 const auto props = device.getFormatProperties(format);
354 return !!(props.optimalTilingFeatures &
355 vk::FormatFeatureFlagBits::eDepthStencilAttachment);
356 }
357
358 static bool PhysicalDeviceSupportsRequiredFormats(
359 const vk::PhysicalDevice& device) {
360 const auto has_color_format =
361 HasSuitableColorFormat(device, vk::Format::eR8G8B8A8Unorm);
362 const auto has_stencil_format =
363 HasSuitableDepthStencilFormat(device, vk::Format::eD32SfloatS8Uint) ||
364 HasSuitableDepthStencilFormat(device, vk::Format::eD24UnormS8Uint);
365 return has_color_format && has_stencil_format;
366 }
367
368 static bool HasRequiredProperties(const vk::PhysicalDevice& physical_device) {
369 auto properties = physical_device.getProperties();
370 if (!(properties.limits.framebufferColorSampleCounts &
371 (vk::SampleCountFlagBits::e1 | vk::SampleCountFlagBits::e4))) {
372 return false;
373 }
374 return true;
375 }
376
377 static bool HasRequiredQueues(const vk::PhysicalDevice& physical_device) {
378 auto queue_flags = vk::QueueFlags{};
379 for (const auto& queue : physical_device.getQueueFamilyProperties()) {
380 if (queue.queueCount == 0) {
381 continue;
382 }
383 queue_flags |= queue.queueFlags;
384 }
385 return static_cast<VkQueueFlags>(queue_flags &
386 (vk::QueueFlagBits::eGraphics |
387 vk::QueueFlagBits::eCompute |
388 vk::QueueFlagBits::eTransfer));
389 }
390
391 template <class ExtensionEnum>
392 static bool IsExtensionInList(const std::vector<std::string>& list,
393 ExtensionEnum ext) {
394 const std::string name = GetExtensionName(ext);
395 return std::find(list.begin(), list.end(), name) != list.end();
396 }
397
398 std::optional<CapabilitiesVK::PhysicalDeviceFeatures>
399 CapabilitiesVK::GetEnabledDeviceFeatures(
400 const vk::PhysicalDevice& device) const {
401 if (!PhysicalDeviceSupportsRequiredFormats(device)) {
402 VALIDATION_LOG << "Device doesn't support the required formats.";
403 return std::nullopt;
404 }
405
406 if (!HasRequiredProperties(device)) {
407 VALIDATION_LOG << "Device doesn't support the required properties.";
408 return std::nullopt;
409 }
410
411 if (!HasRequiredQueues(device)) {
412 VALIDATION_LOG << "Device doesn't support the required queues.";
413 return std::nullopt;
414 }
415
416 const auto enabled_extensions = GetEnabledDeviceExtensions(device);
417 if (!enabled_extensions.has_value()) {
418 VALIDATION_LOG << "Device doesn't support the required queues.";
419 return std::nullopt;
420 }
421
422 PhysicalDeviceFeatures supported_chain;
423
424 // Swiftshader seems to be fussy about just this structure even being in the
425 // chain. Just unlink it if its not supported. We already perform an
426 // extensions check on the other side when reading.
427 if (!IsExtensionInList(
428 enabled_extensions.value(),
429 OptionalDeviceExtensionVK::kEXTImageCompressionControl)) {
430 supported_chain
431 .unlink<vk::PhysicalDeviceImageCompressionControlFeaturesEXT>();
432 }
433
434 device.getFeatures2(&supported_chain.get());
435
436 PhysicalDeviceFeatures required_chain;
437
438 // Base features.
439 {
440 auto& required = required_chain.get().features;
441 const auto& supported = supported_chain.get().features;
442
443 // We require this for enabling wireframes in the playground. But its not
444 // necessarily a big deal if we don't have this feature.
445 required.fillModeNonSolid = supported.fillModeNonSolid;
446 }
447 // VK_KHR_sampler_ycbcr_conversion features.
448 if (IsExtensionInList(
449 enabled_extensions.value(),
450 RequiredAndroidDeviceExtensionVK::kKHRSamplerYcbcrConversion)) {
451 auto& required =
452 required_chain
453 .get<vk::PhysicalDeviceSamplerYcbcrConversionFeaturesKHR>();
454 const auto& supported =
455 supported_chain
456 .get<vk::PhysicalDeviceSamplerYcbcrConversionFeaturesKHR>();
457
458 required.samplerYcbcrConversion = supported.samplerYcbcrConversion;
459 }
460
461 // VK_EXT_image_compression_control
462 if (IsExtensionInList(
463 enabled_extensions.value(),
464 OptionalDeviceExtensionVK::kEXTImageCompressionControl)) {
465 auto& required =
466 required_chain
467 .get<vk::PhysicalDeviceImageCompressionControlFeaturesEXT>();
468 const auto& supported =
469 supported_chain
470 .get<vk::PhysicalDeviceImageCompressionControlFeaturesEXT>();
471
472 required.imageCompressionControl = supported.imageCompressionControl;
473 } else {
474 required_chain
475 .unlink<vk::PhysicalDeviceImageCompressionControlFeaturesEXT>();
476 }
477
478 // Vulkan 1.1
479 {
480 auto& required =
481 required_chain.get<vk::PhysicalDevice16BitStorageFeatures>();
482 const auto& supported =
483 supported_chain.get<vk::PhysicalDevice16BitStorageFeatures>();
484
485 required.uniformAndStorageBuffer16BitAccess =
486 supported.uniformAndStorageBuffer16BitAccess;
487 }
488
489 return required_chain;
490 }
491
492 bool CapabilitiesVK::HasLayer(const std::string& layer) const {
493 for (const auto& [found_layer, exts] : exts_) {
494 if (found_layer == layer) {
495 return true;
496 }
497 }
498 return false;
499 }
500
501 bool CapabilitiesVK::HasExtension(const std::string& ext) const {
502 for (const auto& [layer, exts] : exts_) {
503 if (exts.find(ext) != exts.end()) {
504 return true;
505 }
506 }
507 return false;
508 }
509
510 bool CapabilitiesVK::SupportsPrimitiveRestart() const {
511 return has_primitive_restart_;
512 }
513
514 bool CapabilitiesVK::Supports32BitPrimitiveIndices() const {
515 return true;
516 }
517
518 void CapabilitiesVK::SetOffscreenFormat(PixelFormat pixel_format) const {
519 default_color_format_ = pixel_format;
520 }
521
522 bool CapabilitiesVK::SetPhysicalDevice(
523 const vk::PhysicalDevice& device,
524 const PhysicalDeviceFeatures& enabled_features) {
525 if (HasSuitableColorFormat(device, vk::Format::eR8G8B8A8Unorm)) {
526 default_color_format_ = PixelFormat::kR8G8B8A8UNormInt;
527 } else {
528 default_color_format_ = PixelFormat::kUnknown;
529 }
530
531 if (HasSuitableDepthStencilFormat(device, vk::Format::eD24UnormS8Uint)) {
532 default_depth_stencil_format_ = PixelFormat::kD24UnormS8Uint;
533 } else if (HasSuitableDepthStencilFormat(device,
534 vk::Format::eD32SfloatS8Uint)) {
535 default_depth_stencil_format_ = PixelFormat::kD32FloatS8UInt;
536 } else {
537 default_depth_stencil_format_ = PixelFormat::kUnknown;
538 }
539
540 if (HasSuitableDepthStencilFormat(device, vk::Format::eS8Uint)) {
541 default_stencil_format_ = PixelFormat::kS8UInt;
542 } else if (default_depth_stencil_format_ != PixelFormat::kUnknown) {
543 default_stencil_format_ = default_depth_stencil_format_;
544 }
545
546 physical_device_ = device;
547 device_properties_ = device.getProperties();
548
549 auto physical_properties_2 =
550 device.getProperties2<vk::PhysicalDeviceProperties2,
551 vk::PhysicalDeviceSubgroupProperties>();
552
553 // Currently shaders only want access to arithmetic subgroup features.
554 // If that changes this needs to get updated, and so does Metal (which right
555 // now assumes it from compile time flags based on the MSL target version).
556
557 supports_compute_subgroups_ =
558 !!(physical_properties_2.get<vk::PhysicalDeviceSubgroupProperties>()
559 .supportedOperations &
560 vk::SubgroupFeatureFlagBits::eArithmetic);
561
562 {
563 // Query texture support.
564 // TODO(129784): Add a capability check for expected memory types.
565 vk::PhysicalDeviceMemoryProperties memory_properties;
566 device.getMemoryProperties(&memory_properties);
567
568 for (auto i = 0u; i < memory_properties.memoryTypeCount; i++) {
569 if (memory_properties.memoryTypes[i].propertyFlags &
570 vk::MemoryPropertyFlagBits::eLazilyAllocated) {
571 supports_device_transient_textures_ = true;
572 }
573 }
574 }
575
576 // Determine the optional device extensions this physical device supports.
577 {
578 required_common_device_extensions_.clear();
579 required_android_device_extensions_.clear();
580 optional_device_extensions_.clear();
581 optional_android_device_extensions_.clear();
582
583 std::set<std::string> exts;
584 if (!use_embedder_extensions_) {
585 auto maybe_exts = GetSupportedDeviceExtensions(device);
586 if (!maybe_exts.has_value()) {
587 return false;
588 }
589 exts = maybe_exts.value();
590 } else {
591 for (const auto& ext : embedder_device_extensions_) {
592 exts.insert(ext);
593 }
594 }
595
596 IterateExtensions<RequiredCommonDeviceExtensionVK>([&](auto ext) -> bool {
597 auto ext_name = GetExtensionName(ext);
598 if (exts.find(ext_name) != exts.end()) {
599 required_common_device_extensions_.insert(ext);
600 }
601 return true;
602 });
603 IterateExtensions<RequiredAndroidDeviceExtensionVK>([&](auto ext) -> bool {
604 auto ext_name = GetExtensionName(ext);
605 if (exts.find(ext_name) != exts.end()) {
606 required_android_device_extensions_.insert(ext);
607 }
608 return true;
609 });
610 IterateExtensions<OptionalDeviceExtensionVK>([&](auto ext) -> bool {
611 auto ext_name = GetExtensionName(ext);
612 if (exts.find(ext_name) != exts.end()) {
613 optional_device_extensions_.insert(ext);
614 }
615 return true;
616 });
617 IterateExtensions<OptionalAndroidDeviceExtensionVK>(
618 [&](OptionalAndroidDeviceExtensionVK ext) {
619 auto name = GetExtensionName(ext);
620 if (exts.find(name) != exts.end()) {
621 optional_android_device_extensions_.insert(ext);
622 }
623 return true;
624 });
625 }
626
627 supports_texture_fixed_rate_compression_ =
628 enabled_features
629 .isLinked<vk::PhysicalDeviceImageCompressionControlFeaturesEXT>() &&
630 enabled_features
631 .get<vk::PhysicalDeviceImageCompressionControlFeaturesEXT>()
632 .imageCompressionControl;
633
634 max_render_pass_attachment_size_ =
635 ISize{device_properties_.limits.maxFramebufferWidth,
636 device_properties_.limits.maxFramebufferHeight};
637
638 // Molten, Vulkan on Metal, cannot support triangle fans because Metal doesn't
639 // support triangle fans.
640 // See VUID-VkPipelineInputAssemblyStateCreateInfo-triangleFans-04452.
641 has_triangle_fans_ =
642 !HasExtension(OptionalDeviceExtensionVK::kVKKHRPortabilitySubset);
643
644 // External Fence/Semaphore for AHB swapchain
645 if (HasExtension(OptionalAndroidDeviceExtensionVK::kKHRExternalFenceFd) &&
646 HasExtension(OptionalAndroidDeviceExtensionVK::kKHRExternalFence) &&
647 HasExtension(OptionalAndroidDeviceExtensionVK::kKHRExternalSemaphore) &&
648 HasExtension(OptionalAndroidDeviceExtensionVK::kKHRExternalSemaphoreFd)) {
649 supports_external_fence_and_semaphore_ = true;
650 }
651
652 minimum_uniform_alignment_ =
653 device_properties_.limits.minUniformBufferOffsetAlignment;
654 minimum_storage_alignment_ =
655 device_properties_.limits.minStorageBufferOffsetAlignment;
656
657 return true;
658 }
659
660 // |Capabilities|
661 bool CapabilitiesVK::SupportsOffscreenMSAA() const {
662 return true;
663 }
664
665 // |Capabilities|
666 bool CapabilitiesVK::SupportsImplicitResolvingMSAA() const {
667 return false;
668 }
669
670 // |Capabilities|
671 bool CapabilitiesVK::SupportsSSBO() const {
672 return true;
673 }
674
675 // |Capabilities|
676 bool CapabilitiesVK::SupportsTextureToTextureBlits() const {
677 return true;
678 }
679
680 // |Capabilities|
681 bool CapabilitiesVK::SupportsFramebufferFetch() const {
682 return has_framebuffer_fetch_;
683 }
684
685 // |Capabilities|
686 bool CapabilitiesVK::SupportsCompute() const {
687 // Vulkan 1.1 requires support for compute.
688 return true;
689 }
690
691 // |Capabilities|
692 bool CapabilitiesVK::SupportsComputeSubgroups() const {
693 // Set by |SetPhysicalDevice|.
694 return supports_compute_subgroups_;
695 }
696
697 // |Capabilities|
698 bool CapabilitiesVK::SupportsReadFromResolve() const {
699 return false;
700 }
701
702 bool CapabilitiesVK::SupportsDecalSamplerAddressMode() const {
703 return true;
704 }
705
706 // |Capabilities|
707 bool CapabilitiesVK::SupportsDeviceTransientTextures() const {
708 return supports_device_transient_textures_;
709 }
710
711 // |Capabilities|
712 PixelFormat CapabilitiesVK::GetDefaultColorFormat() const {
713 return default_color_format_;
714 }
715
716 // |Capabilities|
717 PixelFormat CapabilitiesVK::GetDefaultStencilFormat() const {
718 return default_stencil_format_;
719 }
720
721 // |Capabilities|
722 PixelFormat CapabilitiesVK::GetDefaultDepthStencilFormat() const {
723 return default_depth_stencil_format_;
724 }
725
726 const vk::PhysicalDeviceProperties&
727 CapabilitiesVK::GetPhysicalDeviceProperties() const {
728 return device_properties_;
729 }
730
731 PixelFormat CapabilitiesVK::GetDefaultGlyphAtlasFormat() const {
732 return PixelFormat::kR8UNormInt;
733 }
734
735 size_t CapabilitiesVK::GetMinimumUniformAlignment() const {
736 return minimum_uniform_alignment_;
737 }
738
739 size_t CapabilitiesVK::GetMinimumStorageBufferAlignment() const {
740 return minimum_storage_alignment_;
741 }
742
743 bool CapabilitiesVK::NeedsPartitionedHostBuffer() const {
744 return false;
745 }
746
747 bool CapabilitiesVK::HasExtension(RequiredCommonDeviceExtensionVK ext) const {
748 return required_common_device_extensions_.find(ext) !=
749 required_common_device_extensions_.end();
750 }
751
752 bool CapabilitiesVK::HasExtension(RequiredAndroidDeviceExtensionVK ext) const {
753 return required_android_device_extensions_.find(ext) !=
754 required_android_device_extensions_.end();
755 }
756
757 bool CapabilitiesVK::HasExtension(OptionalDeviceExtensionVK ext) const {
758 return optional_device_extensions_.find(ext) !=
759 optional_device_extensions_.end();
760 }
761
762 bool CapabilitiesVK::HasExtension(OptionalAndroidDeviceExtensionVK ext) const {
763 return optional_android_device_extensions_.find(ext) !=
764 optional_android_device_extensions_.end();
765 }
766
767 bool CapabilitiesVK::SupportsTextureFixedRateCompression() const {
768 return supports_texture_fixed_rate_compression_;
769 }
770
771 std::optional<vk::ImageCompressionFixedRateFlagBitsEXT>
772 CapabilitiesVK::GetSupportedFRCRate(CompressionType compression_type,
773 const FRCFormatDescriptor& desc) const {
774 if (compression_type != CompressionType::kLossy) {
775 return std::nullopt;
776 }
777 if (!supports_texture_fixed_rate_compression_) {
778 return std::nullopt;
779 }
780 // There are opportunities to hash and cache the FRCFormatDescriptor if
781 // needed.
782 vk::StructureChain<vk::PhysicalDeviceImageFormatInfo2,
783 vk::ImageCompressionControlEXT>
784 format_chain;
785
786 auto& format_info = format_chain.get();
787
788 format_info.format = desc.format;
789 format_info.type = desc.type;
790 format_info.tiling = desc.tiling;
791 format_info.usage = desc.usage;
792 format_info.flags = desc.flags;
793
794 const auto kIdealFRCRate = vk::ImageCompressionFixedRateFlagBitsEXT::e4Bpc;
795
796 std::array<vk::ImageCompressionFixedRateFlagsEXT, 1u> rates = {kIdealFRCRate};
797
798 auto& compression = format_chain.get<vk::ImageCompressionControlEXT>();
799 compression.flags = vk::ImageCompressionFlagBitsEXT::eFixedRateExplicit;
800 compression.compressionControlPlaneCount = rates.size();
801 compression.pFixedRateFlags = rates.data();
802
803 const auto [result, supported] = physical_device_.getImageFormatProperties2<
804 vk::ImageFormatProperties2, vk::ImageCompressionPropertiesEXT>(
805 format_chain.get());
806
807 if (result != vk::Result::eSuccess ||
808 !supported.isLinked<vk::ImageCompressionPropertiesEXT>()) {
809 return std::nullopt;
810 }
811
812 const auto& compression_props =
813 supported.get<vk::ImageCompressionPropertiesEXT>();
814
815 if ((compression_props.imageCompressionFlags &
816 vk::ImageCompressionFlagBitsEXT::eFixedRateExplicit) &&
817 (compression_props.imageCompressionFixedRateFlags & kIdealFRCRate)) {
818 return kIdealFRCRate;
819 }
820
821 return std::nullopt;
822 }
823
824 bool CapabilitiesVK::SupportsTriangleFan() const {
825 return has_triangle_fans_;
826 }
827
828 ISize CapabilitiesVK::GetMaximumRenderPassAttachmentSize() const {
829 return max_render_pass_attachment_size_;
830 }
831
832 void CapabilitiesVK::ApplyWorkarounds(const WorkaroundsVK& workarounds) {
833 has_primitive_restart_ = !workarounds.slow_primitive_restart_performance;
834 has_framebuffer_fetch_ = !workarounds.input_attachment_self_dependency_broken;
835 }
836
837 bool CapabilitiesVK::SupportsExternalSemaphoreExtensions() const {
838 return supports_external_fence_and_semaphore_;
839 }
840
841 bool CapabilitiesVK::SupportsExtendedRangeFormats() const {
842 return false;
843 }
844
845 } // namespace impeller
846
847 // NOLINTEND(clang-analyzer-security.PointerSub)
capabilities_vk.h
impeller::CapabilitiesVK::SupportsTriangleFan
bool SupportsTriangleFan() const override
Whether the primitive type TriangleFan is supported by the backend.
Definition: capabilities_vk.cc:824
impeller::CapabilitiesVK::GetMinimumUniformAlignment
size_t GetMinimumUniformAlignment() const override
The minimum alignment of uniform value offsets in bytes.
Definition: capabilities_vk.cc:735
impeller::CapabilitiesVK::SupportsDeviceTransientTextures
bool SupportsDeviceTransientTextures() const override
Whether the context backend supports allocating StorageMode::kDeviceTransient (aka "memoryless") text...
Definition: capabilities_vk.cc:707
impeller::CapabilitiesVK::GetEnabledInstanceExtensions
std::optional< std::vector< std::string > > GetEnabledInstanceExtensions() const
Definition: capabilities_vk.cc:99
impeller::CapabilitiesVK::AreValidationsEnabled
bool AreValidationsEnabled() const
Definition: capabilities_vk.cc:82
impeller::CapabilitiesVK::SetPhysicalDevice
bool SetPhysicalDevice(const vk::PhysicalDevice &physical_device, const PhysicalDeviceFeatures &enabled_features)
Definition: capabilities_vk.cc:522
impeller::CapabilitiesVK::GetMaximumRenderPassAttachmentSize
ISize GetMaximumRenderPassAttachmentSize() const override
Return the maximum size of a render pass attachment.
Definition: capabilities_vk.cc:828
impeller::CapabilitiesVK::SupportsSSBO
bool SupportsSSBO() const override
Whether the context backend supports binding Shader Storage Buffer Objects (SSBOs) to pipelines.
Definition: capabilities_vk.cc:671
impeller::CapabilitiesVK::SupportsFramebufferFetch
bool SupportsFramebufferFetch() const override
Whether the context backend is able to support pipelines with shaders that read from the framebuffer ...
Definition: capabilities_vk.cc:681
impeller::CapabilitiesVK::SupportsExternalSemaphoreExtensions
bool SupportsExternalSemaphoreExtensions() const
Definition: capabilities_vk.cc:837
impeller::CapabilitiesVK::CapabilitiesVK
CapabilitiesVK(bool enable_validations, bool fatal_missing_validations=false, bool use_embedder_extensions=false, std::vector< std::string > instance_extensions={}, std::vector< std::string > device_extensions={})
Definition: capabilities_vk.cc:22
impeller::CapabilitiesVK::~CapabilitiesVK
~CapabilitiesVK()
impeller::CapabilitiesVK::SupportsOffscreenMSAA
bool SupportsOffscreenMSAA() const override
Whether the context backend supports attaching offscreen MSAA color/stencil textures.
Definition: capabilities_vk.cc:661
impeller::CapabilitiesVK::SupportsCompute
bool SupportsCompute() const override
Whether the context backend supports ComputePass.
Definition: capabilities_vk.cc:686
impeller::CapabilitiesVK::HasExtension
bool HasExtension(RequiredCommonDeviceExtensionVK ext) const
Definition: capabilities_vk.cc:747
impeller::CapabilitiesVK::GetSupportedFRCRate
std::optional< vk::ImageCompressionFixedRateFlagBitsEXT > GetSupportedFRCRate(CompressionType compression_type, const FRCFormatDescriptor &desc) const
Get the fixed compression rate supported by the context for the given format and usage.
Definition: capabilities_vk.cc:772
impeller::CapabilitiesVK::SetOffscreenFormat
void SetOffscreenFormat(PixelFormat pixel_format) const
Definition: capabilities_vk.cc:518
impeller::CapabilitiesVK::GetDefaultStencilFormat
PixelFormat GetDefaultStencilFormat() const override
Returns a supported PixelFormat for textures that store stencil information. May include a depth chan...
Definition: capabilities_vk.cc:717
impeller::CapabilitiesVK::ApplyWorkarounds
void ApplyWorkarounds(const WorkaroundsVK &workarounds)
Update capabilities for the given set of workarounds.
Definition: capabilities_vk.cc:832
impeller::CapabilitiesVK::IsValid
bool IsValid() const
Definition: capabilities_vk.cc:78
impeller::CapabilitiesVK::PhysicalDeviceFeatures
vk::StructureChain< vk::PhysicalDeviceFeatures2, vk::PhysicalDeviceSamplerYcbcrConversionFeaturesKHR, vk::PhysicalDevice16BitStorageFeatures, vk::PhysicalDeviceImageCompressionControlFeaturesEXT > PhysicalDeviceFeatures
Definition: capabilities_vk.h:214
impeller::CapabilitiesVK::SupportsComputeSubgroups
bool SupportsComputeSubgroups() const override
Whether the context backend supports configuring ComputePass command subgroups.
Definition: capabilities_vk.cc:692
impeller::CapabilitiesVK::GetMinimumStorageBufferAlignment
size_t GetMinimumStorageBufferAlignment() const override
The minimum alignment of storage buffer value offsets in bytes.
Definition: capabilities_vk.cc:739
impeller::CapabilitiesVK::GetDefaultDepthStencilFormat
PixelFormat GetDefaultDepthStencilFormat() const override
Returns a supported PixelFormat for textures that store both a stencil and depth component....
Definition: capabilities_vk.cc:722
impeller::CapabilitiesVK::SupportsTextureToTextureBlits
bool SupportsTextureToTextureBlits() const override
Whether the context backend supports blitting from one texture region to another texture region (via ...
Definition: capabilities_vk.cc:676
impeller::CapabilitiesVK::Supports32BitPrimitiveIndices
bool Supports32BitPrimitiveIndices() const override
Whether 32-bit values are supported in index buffers used to draw primitives.
Definition: capabilities_vk.cc:514
impeller::CapabilitiesVK::GetEnabledDeviceExtensions
std::optional< std::vector< std::string > > GetEnabledDeviceExtensions(const vk::PhysicalDevice &physical_device) const
Definition: capabilities_vk.cc:263
impeller::CapabilitiesVK::SupportsReadFromResolve
bool SupportsReadFromResolve() const override
Whether the context backend supports binding the current RenderPass attachments. This is supported if...
Definition: capabilities_vk.cc:698
impeller::CapabilitiesVK::SupportsDecalSamplerAddressMode
bool SupportsDecalSamplerAddressMode() const override
Whether the context backend supports SamplerAddressMode::Decal.
Definition: capabilities_vk.cc:702
impeller::CapabilitiesVK::SupportsPrimitiveRestart
bool SupportsPrimitiveRestart() const override
Whether primitive restart is supported.
Definition: capabilities_vk.cc:510
impeller::CapabilitiesVK::GetEnabledLayers
std::optional< std::vector< std::string > > GetEnabledLayers() const
Definition: capabilities_vk.cc:86
impeller::CapabilitiesVK::SupportsTextureFixedRateCompression
bool SupportsTextureFixedRateCompression() const
Definition: capabilities_vk.cc:767
impeller::CapabilitiesVK::NeedsPartitionedHostBuffer
bool NeedsPartitionedHostBuffer() const override
Whether the host buffer should use separate device buffers for indexes from other data.
Definition: capabilities_vk.cc:743
impeller::CapabilitiesVK::GetDefaultGlyphAtlasFormat
PixelFormat GetDefaultGlyphAtlasFormat() const override
Returns the default pixel format for the alpha bitmap glyph atlas.
Definition: capabilities_vk.cc:731
impeller::CapabilitiesVK::GetDefaultColorFormat
PixelFormat GetDefaultColorFormat() const override
Returns a supported PixelFormat for textures that store 4-channel colors (red/green/blue/alpha).
Definition: capabilities_vk.cc:712
impeller::CapabilitiesVK::GetPhysicalDeviceProperties
const vk::PhysicalDeviceProperties & GetPhysicalDeviceProperties() const
Definition: capabilities_vk.cc:727
impeller::CapabilitiesVK::SupportsExtendedRangeFormats
bool SupportsExtendedRangeFormats() const override
Whether the XR formats are supported on this device.
Definition: capabilities_vk.cc:841
impeller::CapabilitiesVK::SupportsImplicitResolvingMSAA
bool SupportsImplicitResolvingMSAA() const override
Whether the context backend supports multisampled rendering to the on-screen surface without requirin...
Definition: capabilities_vk.cc:666
impeller::CapabilitiesVK::GetEnabledDeviceFeatures
std::optional< PhysicalDeviceFeatures > GetEnabledDeviceFeatures(const vk::PhysicalDevice &physical_device) const
Definition: capabilities_vk.cc:399
formats.h
e1
Vector3 e1
Definition: line_contents.cc:107
impeller
Definition: allocation.cc:12
impeller::IterateExtensions
static bool IterateExtensions(const std::function< bool(T)> &it)
Definition: capabilities_vk.cc:235
impeller::GetSupportedDeviceExtensions
static std::optional< std::set< std::string > > GetSupportedDeviceExtensions(const vk::PhysicalDevice &physical_device)
Definition: capabilities_vk.cc:247
impeller::PhysicalDeviceSupportsRequiredFormats
static bool PhysicalDeviceSupportsRequiredFormats(const vk::PhysicalDevice &device)
Definition: capabilities_vk.cc:358
impeller::HasRequiredProperties
static bool HasRequiredProperties(const vk::PhysicalDevice &physical_device)
Definition: capabilities_vk.cc:368
impeller::IsExtensionInList
static bool IsExtensionInList(const std::vector< std::string > &list, ExtensionEnum ext)
Definition: capabilities_vk.cc:392
impeller::HasSuitableColorFormat
static bool HasSuitableColorFormat(const vk::PhysicalDevice &device, vk::Format format)
Definition: capabilities_vk.cc:343
impeller::RequiredAndroidDeviceExtensionVK
RequiredAndroidDeviceExtensionVK
A device extension available on all Android platforms. Without the presence of these extensions on An...
Definition: capabilities_vk.h:48
impeller::RequiredAndroidDeviceExtensionVK::kKHRExternalMemory
@ kKHRExternalMemory
impeller::RequiredAndroidDeviceExtensionVK::kKHRSamplerYcbcrConversion
@ kKHRSamplerYcbcrConversion
impeller::RequiredAndroidDeviceExtensionVK::kKHRDedicatedAllocation
@ kKHRDedicatedAllocation
impeller::RequiredAndroidDeviceExtensionVK::kLast
@ kLast
impeller::RequiredAndroidDeviceExtensionVK::kEXTQueueFamilyForeign
@ kEXTQueueFamilyForeign
impeller::RequiredAndroidDeviceExtensionVK::kANDROIDExternalMemoryAndroidHardwareBuffer
@ kANDROIDExternalMemoryAndroidHardwareBuffer
impeller::PixelFormat
PixelFormat
The Pixel formats supported by Impeller. The naming convention denotes the usage of the component,...
Definition: formats.h:99
impeller::PixelFormat::kD24UnormS8Uint
@ kD24UnormS8Uint
impeller::PixelFormat::kR8UNormInt
@ kR8UNormInt
impeller::PixelFormat::kUnknown
@ kUnknown
impeller::PixelFormat::kS8UInt
@ kS8UInt
impeller::PixelFormat::kD32FloatS8UInt
@ kD32FloatS8UInt
impeller::PixelFormat::kR8G8B8A8UNormInt
@ kR8G8B8A8UNormInt
impeller::HasSuitableDepthStencilFormat
static bool HasSuitableDepthStencilFormat(const vk::PhysicalDevice &device, vk::Format format)
Definition: capabilities_vk.cc:351
impeller::RequiredCommonDeviceExtensionVK
RequiredCommonDeviceExtensionVK
A device extension available on all platforms. Without the presence of these extensions,...
Definition: capabilities_vk.h:29
impeller::RequiredCommonDeviceExtensionVK::kKHRSwapchain
@ kKHRSwapchain
impeller::RequiredCommonDeviceExtensionVK::kLast
@ kLast
impeller::OptionalAndroidDeviceExtensionVK
OptionalAndroidDeviceExtensionVK
A device extension available on some Android platforms.
Definition: capabilities_vk.h:93
impeller::OptionalAndroidDeviceExtensionVK::kKHRExternalFenceFd
@ kKHRExternalFenceFd
impeller::OptionalAndroidDeviceExtensionVK::kKHRExternalSemaphore
@ kKHRExternalSemaphore
impeller::OptionalAndroidDeviceExtensionVK::kKHRExternalFence
@ kKHRExternalFence
impeller::OptionalAndroidDeviceExtensionVK::kKHRExternalSemaphoreFd
@ kKHRExternalSemaphoreFd
impeller::OptionalAndroidDeviceExtensionVK::kLast
@ kLast
impeller::GetExtensionName
static const char * GetExtensionName(RequiredCommonDeviceExtensionVK ext)
Definition: capabilities_vk.cc:176
impeller::kInstanceLayer
static constexpr const char * kInstanceLayer
Definition: capabilities_vk.cc:20
impeller::CompressionType
CompressionType
Additional compression to apply to a texture. This value is ignored on platforms which do not support...
Definition: texture_descriptor.h:19
impeller::CompressionType::kLossy
@ kLossy
impeller::OptionalDeviceExtensionVK
OptionalDeviceExtensionVK
A device extension enabled if available. Subsystems cannot assume availability and must check if thes...
Definition: capabilities_vk.h:131
impeller::OptionalDeviceExtensionVK::kEXTImageCompressionControl
@ kEXTImageCompressionControl
impeller::OptionalDeviceExtensionVK::kLast
@ kLast
impeller::OptionalDeviceExtensionVK::kVKKHRPortabilitySubset
@ kVKKHRPortabilitySubset
impeller::OptionalDeviceExtensionVK::kEXTPipelineCreationFeedback
@ kEXTPipelineCreationFeedback
impeller::HasRequiredQueues
static bool HasRequiredQueues(const vk::PhysicalDevice &physical_device)
Definition: capabilities_vk.cc:377
std
Definition: comparable.h:95
impeller::FRCFormatDescriptor
A pixel format and usage that is sufficient to check if images of that format and usage are suitable ...
Definition: capabilities_vk.h:162
impeller::FRCFormatDescriptor::tiling
vk::ImageTiling tiling
Definition: capabilities_vk.h:165
impeller::FRCFormatDescriptor::usage
vk::ImageUsageFlags usage
Definition: capabilities_vk.h:166
impeller::FRCFormatDescriptor::flags
vk::ImageCreateFlags flags
Definition: capabilities_vk.h:167
impeller::FRCFormatDescriptor::type
vk::ImageType type
Definition: capabilities_vk.h:164
impeller::FRCFormatDescriptor::format
vk::Format format
Definition: capabilities_vk.h:163
impeller::TSize
Definition: size.h:25
impeller::WorkaroundsVK
A non-exhaustive set of driver specific workarounds.
Definition: workarounds_vk.h:13
impeller::WorkaroundsVK::slow_primitive_restart_performance
bool slow_primitive_restart_performance
Definition: workarounds_vk.h:18
impeller::WorkaroundsVK::input_attachment_self_dependency_broken
bool input_attachment_self_dependency_broken
Definition: workarounds_vk.h:30
validation.h
VALIDATION_LOG
#define VALIDATION_LOG
Definition: validation.h:91
vk.h
workarounds_vk.h