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