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  default_color_format_ = pixel_format;
516 }
517 
519  const vk::PhysicalDevice& device,
520  const PhysicalDeviceFeatures& enabled_features) {
521  if (HasSuitableColorFormat(device, vk::Format::eR8G8B8A8Unorm)) {
522  default_color_format_ = PixelFormat::kR8G8B8A8UNormInt;
523  } else {
524  default_color_format_ = PixelFormat::kUnknown;
525  }
526 
527  if (HasSuitableDepthStencilFormat(device, vk::Format::eD24UnormS8Uint)) {
528  default_depth_stencil_format_ = PixelFormat::kD24UnormS8Uint;
529  } else if (HasSuitableDepthStencilFormat(device,
530  vk::Format::eD32SfloatS8Uint)) {
531  default_depth_stencil_format_ = PixelFormat::kD32FloatS8UInt;
532  } else {
533  default_depth_stencil_format_ = PixelFormat::kUnknown;
534  }
535 
536  if (HasSuitableDepthStencilFormat(device, vk::Format::eS8Uint)) {
537  default_stencil_format_ = PixelFormat::kS8UInt;
538  } else if (default_depth_stencil_format_ != PixelFormat::kUnknown) {
539  default_stencil_format_ = default_depth_stencil_format_;
540  }
541 
542  physical_device_ = device;
543  device_properties_ = device.getProperties();
544 
545  auto physical_properties_2 =
546  device.getProperties2<vk::PhysicalDeviceProperties2,
547  vk::PhysicalDeviceSubgroupProperties>();
548 
549  // Currently shaders only want access to arithmetic subgroup features.
550  // If that changes this needs to get updated, and so does Metal (which right
551  // now assumes it from compile time flags based on the MSL target version).
552 
553  supports_compute_subgroups_ =
554  !!(physical_properties_2.get<vk::PhysicalDeviceSubgroupProperties>()
555  .supportedOperations &
556  vk::SubgroupFeatureFlagBits::eArithmetic);
557 
558  {
559  // Query texture support.
560  // TODO(129784): Add a capability check for expected memory types.
561  vk::PhysicalDeviceMemoryProperties memory_properties;
562  device.getMemoryProperties(&memory_properties);
563 
564  for (auto i = 0u; i < memory_properties.memoryTypeCount; i++) {
565  if (memory_properties.memoryTypes[i].propertyFlags &
566  vk::MemoryPropertyFlagBits::eLazilyAllocated) {
567  supports_device_transient_textures_ = true;
568  }
569  }
570  }
571 
572  // Determine the optional device extensions this physical device supports.
573  {
574  required_common_device_extensions_.clear();
575  required_android_device_extensions_.clear();
576  optional_device_extensions_.clear();
577  optional_android_device_extensions_.clear();
578 
579  std::set<std::string> exts;
580  if (!use_embedder_extensions_) {
581  auto maybe_exts = GetSupportedDeviceExtensions(device);
582  if (!maybe_exts.has_value()) {
583  return false;
584  }
585  exts = maybe_exts.value();
586  } else {
587  for (const auto& ext : embedder_device_extensions_) {
588  exts.insert(ext);
589  }
590  }
591 
592  IterateExtensions<RequiredCommonDeviceExtensionVK>([&](auto ext) -> bool {
593  auto ext_name = GetExtensionName(ext);
594  if (exts.find(ext_name) != exts.end()) {
595  required_common_device_extensions_.insert(ext);
596  }
597  return true;
598  });
599  IterateExtensions<RequiredAndroidDeviceExtensionVK>([&](auto ext) -> bool {
600  auto ext_name = GetExtensionName(ext);
601  if (exts.find(ext_name) != exts.end()) {
602  required_android_device_extensions_.insert(ext);
603  }
604  return true;
605  });
606  IterateExtensions<OptionalDeviceExtensionVK>([&](auto ext) -> bool {
607  auto ext_name = GetExtensionName(ext);
608  if (exts.find(ext_name) != exts.end()) {
609  optional_device_extensions_.insert(ext);
610  }
611  return true;
612  });
613  IterateExtensions<OptionalAndroidDeviceExtensionVK>(
615  auto name = GetExtensionName(ext);
616  if (exts.find(name) != exts.end()) {
617  optional_android_device_extensions_.insert(ext);
618  }
619  return true;
620  });
621  }
622 
623  supports_texture_fixed_rate_compression_ =
624  enabled_features
625  .isLinked<vk::PhysicalDeviceImageCompressionControlFeaturesEXT>() &&
626  enabled_features
627  .get<vk::PhysicalDeviceImageCompressionControlFeaturesEXT>()
628  .imageCompressionControl;
629 
630  max_render_pass_attachment_size_ =
631  ISize{device_properties_.limits.maxFramebufferWidth,
632  device_properties_.limits.maxFramebufferHeight};
633 
634  // Molten, Vulkan on Metal, cannot support triangle fans because Metal doesn't
635  // support triangle fans.
636  // See VUID-VkPipelineInputAssemblyStateCreateInfo-triangleFans-04452.
637  has_triangle_fans_ =
639 
640  // External Fence/Semaphore for AHB swapchain
645  supports_external_fence_and_semaphore_ = true;
646  }
647 
648  minimum_uniform_alignment_ =
649  device_properties_.limits.minUniformBufferOffsetAlignment;
650  minimum_storage_alignment_ =
651  device_properties_.limits.minStorageBufferOffsetAlignment;
652 
653  return true;
654 }
655 
656 // |Capabilities|
658  return true;
659 }
660 
661 // |Capabilities|
663  return false;
664 }
665 
666 // |Capabilities|
668  return true;
669 }
670 
671 // |Capabilities|
673  return true;
674 }
675 
676 // |Capabilities|
678  return has_framebuffer_fetch_;
679 }
680 
681 // |Capabilities|
683  // Vulkan 1.1 requires support for compute.
684  return true;
685 }
686 
687 // |Capabilities|
689  // Set by |SetPhysicalDevice|.
690  return supports_compute_subgroups_;
691 }
692 
693 // |Capabilities|
695  return false;
696 }
697 
699  return true;
700 }
701 
702 // |Capabilities|
704  return supports_device_transient_textures_;
705 }
706 
707 // |Capabilities|
709  return default_color_format_;
710 }
711 
712 // |Capabilities|
714  return default_stencil_format_;
715 }
716 
717 // |Capabilities|
719  return default_depth_stencil_format_;
720 }
721 
722 const vk::PhysicalDeviceProperties&
724  return device_properties_;
725 }
726 
729 }
730 
732  return minimum_uniform_alignment_;
733 }
734 
736  return minimum_storage_alignment_;
737 }
738 
740  return false;
741 }
742 
744  return required_common_device_extensions_.find(ext) !=
745  required_common_device_extensions_.end();
746 }
747 
749  return required_android_device_extensions_.find(ext) !=
750  required_android_device_extensions_.end();
751 }
752 
754  return optional_device_extensions_.find(ext) !=
755  optional_device_extensions_.end();
756 }
757 
759  return optional_android_device_extensions_.find(ext) !=
760  optional_android_device_extensions_.end();
761 }
762 
764  return supports_texture_fixed_rate_compression_;
765 }
766 
767 std::optional<vk::ImageCompressionFixedRateFlagBitsEXT>
769  const FRCFormatDescriptor& desc) const {
770  if (compression_type != CompressionType::kLossy) {
771  return std::nullopt;
772  }
773  if (!supports_texture_fixed_rate_compression_) {
774  return std::nullopt;
775  }
776  // There are opportunities to hash and cache the FRCFormatDescriptor if
777  // needed.
778  vk::StructureChain<vk::PhysicalDeviceImageFormatInfo2,
779  vk::ImageCompressionControlEXT>
780  format_chain;
781 
782  auto& format_info = format_chain.get();
783 
784  format_info.format = desc.format;
785  format_info.type = desc.type;
786  format_info.tiling = desc.tiling;
787  format_info.usage = desc.usage;
788  format_info.flags = desc.flags;
789 
790  const auto kIdealFRCRate = vk::ImageCompressionFixedRateFlagBitsEXT::e4Bpc;
791 
792  std::array<vk::ImageCompressionFixedRateFlagsEXT, 1u> rates = {kIdealFRCRate};
793 
794  auto& compression = format_chain.get<vk::ImageCompressionControlEXT>();
795  compression.flags = vk::ImageCompressionFlagBitsEXT::eFixedRateExplicit;
796  compression.compressionControlPlaneCount = rates.size();
797  compression.pFixedRateFlags = rates.data();
798 
799  const auto [result, supported] = physical_device_.getImageFormatProperties2<
800  vk::ImageFormatProperties2, vk::ImageCompressionPropertiesEXT>(
801  format_chain.get());
802 
803  if (result != vk::Result::eSuccess ||
804  !supported.isLinked<vk::ImageCompressionPropertiesEXT>()) {
805  return std::nullopt;
806  }
807 
808  const auto& compression_props =
809  supported.get<vk::ImageCompressionPropertiesEXT>();
810 
811  if ((compression_props.imageCompressionFlags &
812  vk::ImageCompressionFlagBitsEXT::eFixedRateExplicit) &&
813  (compression_props.imageCompressionFixedRateFlags & kIdealFRCRate)) {
814  return kIdealFRCRate;
815  }
816 
817  return std::nullopt;
818 }
819 
821  return has_triangle_fans_;
822 }
823 
825  return max_render_pass_attachment_size_;
826 }
827 
829  has_primitive_restart_ = !workarounds.slow_primitive_restart_performance;
830  has_framebuffer_fetch_ = !workarounds.input_attachment_self_dependency_broken;
831 }
832 
834  return supports_external_fence_and_semaphore_;
835 }
836 
838  return false;
839 }
840 
841 } // namespace impeller
842 
843 // 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 ...
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