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