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 
6 
7 #include <algorithm>
8 #include <array>
9 
11 #include "impeller/core/formats.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 
77 
79  return is_valid_;
80 }
81 
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>>
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 
177  switch (ext) {
179  return VK_KHR_SWAPCHAIN_EXTENSION_NAME;
181  return "Unknown";
182  }
183  FML_UNREACHABLE();
184 }
185 
187  switch (ext) {
190  return "VK_ANDROID_external_memory_android_hardware_buffer";
192  return VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME;
194  return VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME;
196  return VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME;
198  return VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME;
200  return "Unknown";
201  }
202  FML_UNREACHABLE();
203 }
204 
206  switch (ext) {
208  return VK_KHR_EXTERNAL_FENCE_FD_EXTENSION_NAME;
210  return VK_KHR_EXTERNAL_FENCE_EXTENSION_NAME;
212  return VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME;
214  return VK_KHR_EXTERNAL_SEMAPHORE_EXTENSION_NAME;
216  return "Unknown";
217  }
218 }
219 
221  switch (ext) {
223  return VK_EXT_PIPELINE_CREATION_FEEDBACK_EXTENSION_NAME;
225  return "VK_KHR_portability_subset";
227  return VK_EXT_IMAGE_COMPRESSION_CONTROL_EXTENSION_NAME;
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>>
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 =
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 
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>
400  const vk::PhysicalDevice& device) const {
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(),
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(),
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(),
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 
511  return has_primitive_restart_;
512 }
513 
515  return true;
516 }
517 
519  default_color_format_ = pixel_format;
520 }
521 
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>(
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_ =
643 
644  // External Fence/Semaphore for AHB swapchain
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|
662  return true;
663 }
664 
665 // |Capabilities|
667  return false;
668 }
669 
670 // |Capabilities|
672  return true;
673 }
674 
675 // |Capabilities|
677  return true;
678 }
679 
680 // |Capabilities|
682  return has_framebuffer_fetch_;
683 }
684 
685 // |Capabilities|
687  // Vulkan 1.1 requires support for compute.
688  return true;
689 }
690 
691 // |Capabilities|
693  // Set by |SetPhysicalDevice|.
694  return supports_compute_subgroups_;
695 }
696 
697 // |Capabilities|
699  return false;
700 }
701 
703  return true;
704 }
705 
706 // |Capabilities|
708  return supports_device_transient_textures_;
709 }
710 
711 // |Capabilities|
713  return default_color_format_;
714 }
715 
716 // |Capabilities|
718  return default_stencil_format_;
719 }
720 
721 // |Capabilities|
723  return default_depth_stencil_format_;
724 }
725 
726 const vk::PhysicalDeviceProperties&
728  return device_properties_;
729 }
730 
733 }
734 
736  return minimum_uniform_alignment_;
737 }
738 
740  return minimum_storage_alignment_;
741 }
742 
744  return false;
745 }
746 
748  return required_common_device_extensions_.find(ext) !=
749  required_common_device_extensions_.end();
750 }
751 
753  return required_android_device_extensions_.find(ext) !=
754  required_android_device_extensions_.end();
755 }
756 
758  return optional_device_extensions_.find(ext) !=
759  optional_device_extensions_.end();
760 }
761 
763  return optional_android_device_extensions_.find(ext) !=
764  optional_android_device_extensions_.end();
765 }
766 
768  return supports_texture_fixed_rate_compression_;
769 }
770 
771 std::optional<vk::ImageCompressionFixedRateFlagBitsEXT>
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 
825  return has_triangle_fans_;
826 }
827 
829  return max_render_pass_attachment_size_;
830 }
831 
833  has_primitive_restart_ = !workarounds.slow_primitive_restart_performance;
834  has_framebuffer_fetch_ = !workarounds.input_attachment_self_dependency_broken;
835 }
836 
838  return supports_external_fence_and_semaphore_;
839 }
840 
842  return false;
843 }
844 
845 } // namespace impeller
846 
847 // NOLINTEND(clang-analyzer-security.PointerSub)
bool SupportsTriangleFan() const override
Whether the primitive type TriangleFan is supported by the backend.
size_t GetMinimumUniformAlignment() const override
The minimum alignment of uniform value offsets in bytes.
bool SupportsDeviceTransientTextures() const override
Whether the context backend supports allocating StorageMode::kDeviceTransient (aka "memoryless") text...
std::optional< std::vector< std::string > > GetEnabledInstanceExtensions() const
bool AreValidationsEnabled() const
bool SetPhysicalDevice(const vk::PhysicalDevice &physical_device, const PhysicalDeviceFeatures &enabled_features)
ISize GetMaximumRenderPassAttachmentSize() const override
Return the maximum size of a render pass attachment.
bool SupportsSSBO() const override
Whether the context backend supports binding Shader Storage Buffer Objects (SSBOs) to pipelines.
bool SupportsFramebufferFetch() const override
Whether the context backend is able to support pipelines with shaders that read from the framebuffer ...
bool SupportsExternalSemaphoreExtensions() const
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={})
bool SupportsOffscreenMSAA() const override
Whether the context backend supports attaching offscreen MSAA color/stencil textures.
bool SupportsCompute() const override
Whether the context backend supports ComputePass.
bool HasExtension(RequiredCommonDeviceExtensionVK ext) const
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.
void SetOffscreenFormat(PixelFormat pixel_format) const
PixelFormat GetDefaultStencilFormat() const override
Returns a supported PixelFormat for textures that store stencil information. May include a depth chan...
void ApplyWorkarounds(const WorkaroundsVK &workarounds)
Update capabilities for the given set of workarounds.
vk::StructureChain< vk::PhysicalDeviceFeatures2, vk::PhysicalDeviceSamplerYcbcrConversionFeaturesKHR, vk::PhysicalDevice16BitStorageFeatures, vk::PhysicalDeviceImageCompressionControlFeaturesEXT > PhysicalDeviceFeatures
bool SupportsComputeSubgroups() const override
Whether the context backend supports configuring ComputePass command subgroups.
size_t GetMinimumStorageBufferAlignment() const override
The minimum alignment of storage buffer value offsets in bytes.
PixelFormat GetDefaultDepthStencilFormat() const override
Returns a supported PixelFormat for textures that store both a stencil and depth component....
bool SupportsTextureToTextureBlits() const override
Whether the context backend supports blitting from one texture region to another texture region (via ...
bool Supports32BitPrimitiveIndices() const override
Whether 32-bit values are supported in index buffers used to draw primitives.
std::optional< std::vector< std::string > > GetEnabledDeviceExtensions(const vk::PhysicalDevice &physical_device) const
bool SupportsReadFromResolve() const override
Whether the context backend supports binding the current RenderPass attachments. This is supported if...
bool SupportsDecalSamplerAddressMode() const override
Whether the context backend supports SamplerAddressMode::Decal.
bool SupportsPrimitiveRestart() const override
Whether primitive restart is supported.
std::optional< std::vector< std::string > > GetEnabledLayers() const
bool SupportsTextureFixedRateCompression() const
bool NeedsPartitionedHostBuffer() const override
Whether the host buffer should use separate device buffers for indexes from other data.
PixelFormat GetDefaultGlyphAtlasFormat() const override
Returns the default pixel format for the alpha bitmap glyph atlas.
PixelFormat GetDefaultColorFormat() const override
Returns a supported PixelFormat for textures that store 4-channel colors (red/green/blue/alpha).
const vk::PhysicalDeviceProperties & GetPhysicalDeviceProperties() const
bool SupportsExtendedRangeFormats() const override
Whether the XR formats are supported on this device.
bool SupportsImplicitResolvingMSAA() const override
Whether the context backend supports multisampled rendering to the on-screen surface without requirin...
std::optional< PhysicalDeviceFeatures > GetEnabledDeviceFeatures(const vk::PhysicalDevice &physical_device) const
Vector3 e1
static bool IterateExtensions(const std::function< bool(T)> &it)
static std::optional< std::set< std::string > > GetSupportedDeviceExtensions(const vk::PhysicalDevice &physical_device)
static bool PhysicalDeviceSupportsRequiredFormats(const vk::PhysicalDevice &device)
static bool HasRequiredProperties(const vk::PhysicalDevice &physical_device)
static bool IsExtensionInList(const std::vector< std::string > &list, ExtensionEnum ext)
static bool HasSuitableColorFormat(const vk::PhysicalDevice &device, vk::Format format)
RequiredAndroidDeviceExtensionVK
A device extension available on all Android platforms. Without the presence of these extensions on An...
PixelFormat
The Pixel formats supported by Impeller. The naming convention denotes the usage of the component,...
Definition: formats.h:99
static bool HasSuitableDepthStencilFormat(const vk::PhysicalDevice &device, vk::Format format)
RequiredCommonDeviceExtensionVK
A device extension available on all platforms. Without the presence of these extensions,...
OptionalAndroidDeviceExtensionVK
A device extension available on some Android platforms.
static const char * GetExtensionName(RequiredCommonDeviceExtensionVK ext)
static constexpr const char * kInstanceLayer
CompressionType
Additional compression to apply to a texture. This value is ignored on platforms which do not support...
OptionalDeviceExtensionVK
A device extension enabled if available. Subsystems cannot assume availability and must check if thes...
static bool HasRequiredQueues(const vk::PhysicalDevice &physical_device)
Definition: comparable.h:95
A pixel format and usage that is sufficient to check if images of that format and usage are suitable ...
vk::ImageCreateFlags flags
A non-exhaustive set of driver specific workarounds.
bool input_attachment_self_dependency_broken
#define VALIDATION_LOG
Definition: validation.h:91