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 VK_EXT_TEXTURE_COMPRESSION_ASTC_HDR_EXTENSION_NAME;
231  return "Unknown";
232  }
233  FML_UNREACHABLE();
234 }
235 
236 template <class T>
237 static bool IterateExtensions(const std::function<bool(T)>& it) {
238  if (!it) {
239  return false;
240  }
241  for (size_t i = 0; i < static_cast<uint32_t>(T::kLast); i++) {
242  if (!it(static_cast<T>(i))) {
243  return false;
244  }
245  }
246  return true;
247 }
248 
249 static std::optional<std::set<std::string>> GetSupportedDeviceExtensions(
250  const vk::PhysicalDevice& physical_device) {
251  auto device_extensions = physical_device.enumerateDeviceExtensionProperties();
252  if (device_extensions.result != vk::Result::eSuccess) {
253  return std::nullopt;
254  }
255 
256  std::set<std::string> exts;
257  for (const auto& device_extension : device_extensions.value) {
258  exts.insert(device_extension.extensionName);
259  };
260 
261  return exts;
262 }
263 
264 std::optional<std::vector<std::string>>
266  const vk::PhysicalDevice& physical_device) const {
267  std::set<std::string> exts;
268 
269  if (!use_embedder_extensions_) {
270  auto maybe_exts = GetSupportedDeviceExtensions(physical_device);
271 
272  if (!maybe_exts.has_value()) {
273  return std::nullopt;
274  }
275  exts = maybe_exts.value();
276  } else {
277  for (const auto& ext : embedder_device_extensions_) {
278  exts.insert(ext);
279  }
280  }
281 
282  std::vector<std::string> enabled;
283 
284  auto for_each_common_extension = [&](RequiredCommonDeviceExtensionVK ext) {
285  auto name = GetExtensionName(ext);
286  if (exts.find(name) == exts.end()) {
287  VALIDATION_LOG << "Device does not support required extension: " << name;
288  return false;
289  }
290  enabled.push_back(name);
291  return true;
292  };
293 
294  auto for_each_android_extension = [&](RequiredAndroidDeviceExtensionVK ext) {
295 #ifdef FML_OS_ANDROID
296  auto name = GetExtensionName(ext);
297  if (exts.find(name) == exts.end()) {
298  VALIDATION_LOG << "Device does not support required Android extension: "
299  << name;
300  return false;
301  }
302  enabled.push_back(name);
303 #endif // FML_OS_ANDROID
304  return true;
305  };
306 
307  auto for_each_optional_android_extension =
309 #ifdef FML_OS_ANDROID
310  auto name = GetExtensionName(ext);
311  if (exts.find(name) != exts.end()) {
312  enabled.push_back(name);
313  }
314 #endif // FML_OS_ANDROID
315  return true;
316  };
317 
318  auto for_each_optional_extension = [&](OptionalDeviceExtensionVK ext) {
319  auto name = GetExtensionName(ext);
320  if (exts.find(name) != exts.end()) {
321  enabled.push_back(name);
322  }
323  return true;
324  };
325 
326  const auto iterate_extensions =
327  IterateExtensions<RequiredCommonDeviceExtensionVK>(
328  for_each_common_extension) &&
329  IterateExtensions<RequiredAndroidDeviceExtensionVK>(
330  for_each_android_extension) &&
331  IterateExtensions<OptionalDeviceExtensionVK>(
332  for_each_optional_extension) &&
333  IterateExtensions<OptionalAndroidDeviceExtensionVK>(
334  for_each_optional_android_extension);
335 
336  if (!iterate_extensions) {
337  VALIDATION_LOG << "Device not suitable since required extensions are not "
338  "supported.";
339  return std::nullopt;
340  }
341 
342  return enabled;
343 }
344 
345 static bool HasSuitableColorFormat(const vk::PhysicalDevice& device,
346  vk::Format format) {
347  const auto props = device.getFormatProperties(format);
348  // This needs to be more comprehensive.
349  return !!(props.optimalTilingFeatures &
350  vk::FormatFeatureFlagBits::eColorAttachment);
351 }
352 
353 static bool HasSuitableDepthStencilFormat(const vk::PhysicalDevice& device,
354  vk::Format format) {
355  const auto props = device.getFormatProperties(format);
356  return !!(props.optimalTilingFeatures &
357  vk::FormatFeatureFlagBits::eDepthStencilAttachment);
358 }
359 
361  const vk::PhysicalDevice& device) {
362  const auto has_color_format =
363  HasSuitableColorFormat(device, vk::Format::eR8G8B8A8Unorm);
364  const auto has_stencil_format =
365  HasSuitableDepthStencilFormat(device, vk::Format::eD32SfloatS8Uint) ||
366  HasSuitableDepthStencilFormat(device, vk::Format::eD24UnormS8Uint);
367  return has_color_format && has_stencil_format;
368 }
369 
370 static bool HasRequiredProperties(const vk::PhysicalDevice& physical_device) {
371  auto properties = physical_device.getProperties();
372  if (!(properties.limits.framebufferColorSampleCounts &
373  (vk::SampleCountFlagBits::e1 | vk::SampleCountFlagBits::e4))) {
374  return false;
375  }
376  return true;
377 }
378 
379 static bool HasRequiredQueues(const vk::PhysicalDevice& physical_device) {
380  auto queue_flags = vk::QueueFlags{};
381  for (const auto& queue : physical_device.getQueueFamilyProperties()) {
382  if (queue.queueCount == 0) {
383  continue;
384  }
385  queue_flags |= queue.queueFlags;
386  }
387  return static_cast<VkQueueFlags>(queue_flags &
388  (vk::QueueFlagBits::eGraphics |
389  vk::QueueFlagBits::eCompute |
390  vk::QueueFlagBits::eTransfer));
391 }
392 
393 template <class ExtensionEnum>
394 static bool IsExtensionInList(const std::vector<std::string>& list,
395  ExtensionEnum ext) {
396  const std::string name = GetExtensionName(ext);
397  return std::find(list.begin(), list.end(), name) != list.end();
398 }
399 
400 std::optional<CapabilitiesVK::PhysicalDeviceFeatures>
402  const vk::PhysicalDevice& device) const {
404  VALIDATION_LOG << "Device doesn't support the required formats.";
405  return std::nullopt;
406  }
407 
408  if (!HasRequiredProperties(device)) {
409  VALIDATION_LOG << "Device doesn't support the required properties.";
410  return std::nullopt;
411  }
412 
413  if (!HasRequiredQueues(device)) {
414  VALIDATION_LOG << "Device doesn't support the required queues.";
415  return std::nullopt;
416  }
417 
418  const auto enabled_extensions = GetEnabledDeviceExtensions(device);
419  if (!enabled_extensions.has_value()) {
420  VALIDATION_LOG << "Device doesn't support the required queues.";
421  return std::nullopt;
422  }
423 
424  PhysicalDeviceFeatures supported_chain;
425 
426  // Swiftshader seems to be fussy about just this structure even being in the
427  // chain. Just unlink it if its not supported. We already perform an
428  // extensions check on the other side when reading.
429  if (!IsExtensionInList(
430  enabled_extensions.value(),
432  supported_chain
433  .unlink<vk::PhysicalDeviceImageCompressionControlFeaturesEXT>();
434  }
435  if (!IsExtensionInList(
436  enabled_extensions.value(),
438  supported_chain
439  .unlink<vk::PhysicalDeviceTextureCompressionASTCHDRFeatures>();
440  }
441 
442  device.getFeatures2(&supported_chain.get());
443 
444  PhysicalDeviceFeatures required_chain;
445 
446  // Base features.
447  {
448  auto& required = required_chain.get().features;
449  const auto& supported = supported_chain.get().features;
450 
451  // We require this for enabling wireframes in the playground. But its not
452  // necessarily a big deal if we don't have this feature.
453  required.fillModeNonSolid = supported.fillModeNonSolid;
454 
455  // Enable anisotropic filtering when available. Samplers with
456  // `max_anisotropy` greater than 1 may only be created when this feature
457  // is enabled.
458  required.samplerAnisotropy = supported.samplerAnisotropy;
459  }
460  // VK_KHR_sampler_ycbcr_conversion features.
461  if (IsExtensionInList(
462  enabled_extensions.value(),
464  auto& required =
465  required_chain
466  .get<vk::PhysicalDeviceSamplerYcbcrConversionFeaturesKHR>();
467  const auto& supported =
468  supported_chain
469  .get<vk::PhysicalDeviceSamplerYcbcrConversionFeaturesKHR>();
470 
471  required.samplerYcbcrConversion = supported.samplerYcbcrConversion;
472  }
473 
474  // VK_EXT_image_compression_control
475  if (IsExtensionInList(
476  enabled_extensions.value(),
478  auto& required =
479  required_chain
480  .get<vk::PhysicalDeviceImageCompressionControlFeaturesEXT>();
481  const auto& supported =
482  supported_chain
483  .get<vk::PhysicalDeviceImageCompressionControlFeaturesEXT>();
484 
485  required.imageCompressionControl = supported.imageCompressionControl;
486  } else {
487  required_chain
488  .unlink<vk::PhysicalDeviceImageCompressionControlFeaturesEXT>();
489  }
490 
491  // VK_EXT_texture_compression_astc_hdr
492  if (IsExtensionInList(
493  enabled_extensions.value(),
495  auto& required =
496  required_chain
497  .get<vk::PhysicalDeviceTextureCompressionASTCHDRFeatures>();
498  const auto& supported =
499  supported_chain
500  .get<vk::PhysicalDeviceTextureCompressionASTCHDRFeatures>();
501 
502  required.textureCompressionASTC_HDR = supported.textureCompressionASTC_HDR;
503  } else {
504  required_chain
505  .unlink<vk::PhysicalDeviceTextureCompressionASTCHDRFeatures>();
506  }
507 
508  // Vulkan 1.1
509  {
510  auto& required =
511  required_chain.get<vk::PhysicalDevice16BitStorageFeatures>();
512  const auto& supported =
513  supported_chain.get<vk::PhysicalDevice16BitStorageFeatures>();
514 
515  required.uniformAndStorageBuffer16BitAccess =
516  supported.uniformAndStorageBuffer16BitAccess;
517  }
518 
519  return required_chain;
520 }
521 
522 bool CapabilitiesVK::HasLayer(const std::string& layer) const {
523  for (const auto& [found_layer, exts] : exts_) {
524  if (found_layer == layer) {
525  return true;
526  }
527  }
528  return false;
529 }
530 
531 bool CapabilitiesVK::HasExtension(const std::string& ext) const {
532  for (const auto& [layer, exts] : exts_) {
533  if (exts.find(ext) != exts.end()) {
534  return true;
535  }
536  }
537  return false;
538 }
539 
541  return has_primitive_restart_;
542 }
543 
545  return true;
546 }
547 
549  return true;
550 }
551 
553  default_color_format_ = pixel_format;
554 }
555 
557  const vk::PhysicalDevice& device,
558  const PhysicalDeviceFeatures& enabled_features) {
559  if (HasSuitableColorFormat(device, vk::Format::eR8G8B8A8Unorm)) {
560  default_color_format_ = PixelFormat::kR8G8B8A8UNormInt;
561  } else {
562  default_color_format_ = PixelFormat::kUnknown;
563  }
564 
565  if (HasSuitableDepthStencilFormat(device, vk::Format::eD24UnormS8Uint)) {
566  default_depth_stencil_format_ = PixelFormat::kD24UnormS8Uint;
567  } else if (HasSuitableDepthStencilFormat(device,
568  vk::Format::eD32SfloatS8Uint)) {
569  default_depth_stencil_format_ = PixelFormat::kD32FloatS8UInt;
570  } else {
571  default_depth_stencil_format_ = PixelFormat::kUnknown;
572  }
573 
574  if (HasSuitableDepthStencilFormat(device, vk::Format::eS8Uint)) {
575  default_stencil_format_ = PixelFormat::kS8UInt;
576  } else if (default_depth_stencil_format_ != PixelFormat::kUnknown) {
577  default_stencil_format_ = default_depth_stencil_format_;
578  }
579 
580  physical_device_ = device;
581  device_properties_ = device.getProperties();
582 
583  auto physical_properties_2 =
584  device.getProperties2<vk::PhysicalDeviceProperties2,
585  vk::PhysicalDeviceSubgroupProperties>();
586 
587  // Currently shaders only want access to arithmetic subgroup features.
588  // If that changes this needs to get updated, and so does Metal (which right
589  // now assumes it from compile time flags based on the MSL target version).
590 
591  supports_compute_subgroups_ =
592  !!(physical_properties_2.get<vk::PhysicalDeviceSubgroupProperties>()
593  .supportedOperations &
594  vk::SubgroupFeatureFlagBits::eArithmetic);
595 
596  {
597  // Query texture support.
598  // TODO(129784): Add a capability check for expected memory types.
599  vk::PhysicalDeviceMemoryProperties memory_properties;
600  device.getMemoryProperties(&memory_properties);
601 
602  for (auto i = 0u; i < memory_properties.memoryTypeCount; i++) {
603  if (memory_properties.memoryTypes[i].propertyFlags &
604  vk::MemoryPropertyFlagBits::eLazilyAllocated) {
605  supports_device_transient_textures_ = true;
606  }
607  }
608  }
609 
610  // Determine the optional device extensions this physical device supports.
611  {
612  required_common_device_extensions_.clear();
613  required_android_device_extensions_.clear();
614  optional_device_extensions_.clear();
615  optional_android_device_extensions_.clear();
616 
617  std::set<std::string> exts;
618  if (!use_embedder_extensions_) {
619  auto maybe_exts = GetSupportedDeviceExtensions(device);
620  if (!maybe_exts.has_value()) {
621  return false;
622  }
623  exts = maybe_exts.value();
624  } else {
625  for (const auto& ext : embedder_device_extensions_) {
626  exts.insert(ext);
627  }
628  }
629 
630  IterateExtensions<RequiredCommonDeviceExtensionVK>([&](auto ext) -> bool {
631  auto ext_name = GetExtensionName(ext);
632  if (exts.find(ext_name) != exts.end()) {
633  required_common_device_extensions_.insert(ext);
634  }
635  return true;
636  });
637  IterateExtensions<RequiredAndroidDeviceExtensionVK>([&](auto ext) -> bool {
638  auto ext_name = GetExtensionName(ext);
639  if (exts.find(ext_name) != exts.end()) {
640  required_android_device_extensions_.insert(ext);
641  }
642  return true;
643  });
644  IterateExtensions<OptionalDeviceExtensionVK>([&](auto ext) -> bool {
645  auto ext_name = GetExtensionName(ext);
646  if (exts.find(ext_name) != exts.end()) {
647  optional_device_extensions_.insert(ext);
648  }
649  return true;
650  });
651  IterateExtensions<OptionalAndroidDeviceExtensionVK>(
653  auto name = GetExtensionName(ext);
654  if (exts.find(name) != exts.end()) {
655  optional_android_device_extensions_.insert(ext);
656  }
657  return true;
658  });
659  }
660 
661  supports_texture_fixed_rate_compression_ =
662  enabled_features
663  .isLinked<vk::PhysicalDeviceImageCompressionControlFeaturesEXT>() &&
664  enabled_features
665  .get<vk::PhysicalDeviceImageCompressionControlFeaturesEXT>()
666  .imageCompressionControl;
667 
668  {
669  const auto& features = enabled_features.get().features;
670  supports_texture_compression_bc_ = features.textureCompressionBC;
671  supports_texture_compression_etc2_ = features.textureCompressionETC2;
672  supports_texture_compression_astc_ = features.textureCompressionASTC_LDR;
673  }
674 
675  supports_texture_compression_astc_hdr_ =
676  enabled_features
677  .isLinked<vk::PhysicalDeviceTextureCompressionASTCHDRFeatures>() &&
678  enabled_features
679  .get<vk::PhysicalDeviceTextureCompressionASTCHDRFeatures>()
680  .textureCompressionASTC_HDR;
681 
682  max_render_pass_attachment_size_ =
683  ISize{device_properties_.limits.maxFramebufferWidth,
684  device_properties_.limits.maxFramebufferHeight};
685 
686  // Anisotropic filtering is gated on the samplerAnisotropy feature. When the
687  // feature is unavailable, report a maximum of 1 (disabled). The device limit
688  // is a float but is always an integer in practice, so floor it.
689  max_sampler_anisotropy_ =
690  enabled_features.get().features.samplerAnisotropy
691  ? static_cast<uint32_t>(
692  device_properties_.limits.maxSamplerAnisotropy)
693  : 1u;
694 
695  // Molten, Vulkan on Metal, cannot support triangle fans because Metal doesn't
696  // support triangle fans.
697  // See VUID-VkPipelineInputAssemblyStateCreateInfo-triangleFans-04452.
698  has_triangle_fans_ =
700 
701  // External Fence/Semaphore for AHB swapchain
706  supports_external_fence_and_semaphore_ = true;
707  }
708 
709  minimum_uniform_alignment_ =
710  device_properties_.limits.minUniformBufferOffsetAlignment;
711  minimum_storage_alignment_ =
712  device_properties_.limits.minStorageBufferOffsetAlignment;
713 
714  return true;
715 }
716 
717 // |Capabilities|
719  return true;
720 }
721 
722 // |Capabilities|
724  return false;
725 }
726 
727 // |Capabilities|
729  return true;
730 }
731 
732 // |Capabilities|
734  return true;
735 }
736 
737 // |Capabilities|
739  return has_framebuffer_fetch_;
740 }
741 
742 // |Capabilities|
744  // Vulkan 1.1 requires support for compute.
745  return true;
746 }
747 
748 // |Capabilities|
750  // Set by |SetPhysicalDevice|.
751  return supports_compute_subgroups_;
752 }
753 
754 // |Capabilities|
756  return false;
757 }
758 
760  return true;
761 }
762 
763 // |Capabilities|
765  return supports_device_transient_textures_;
766 }
767 
768 // |Capabilities|
770  return default_color_format_;
771 }
772 
773 // |Capabilities|
775  return default_stencil_format_;
776 }
777 
778 // |Capabilities|
780  return default_depth_stencil_format_;
781 }
782 
783 const vk::PhysicalDeviceProperties&
785  return device_properties_;
786 }
787 
790 }
791 
793  return minimum_uniform_alignment_;
794 }
795 
797  return minimum_storage_alignment_;
798 }
799 
801  return false;
802 }
803 
805  return required_common_device_extensions_.find(ext) !=
806  required_common_device_extensions_.end();
807 }
808 
810  return required_android_device_extensions_.find(ext) !=
811  required_android_device_extensions_.end();
812 }
813 
815  return optional_device_extensions_.find(ext) !=
816  optional_device_extensions_.end();
817 }
818 
820  return optional_android_device_extensions_.find(ext) !=
821  optional_android_device_extensions_.end();
822 }
823 
825  return supports_texture_fixed_rate_compression_;
826 }
827 
828 std::optional<vk::ImageCompressionFixedRateFlagBitsEXT>
830  const FRCFormatDescriptor& desc) const {
831  if (compression_type != CompressionType::kLossy) {
832  return std::nullopt;
833  }
834  if (!supports_texture_fixed_rate_compression_) {
835  return std::nullopt;
836  }
837  // There are opportunities to hash and cache the FRCFormatDescriptor if
838  // needed.
839  vk::StructureChain<vk::PhysicalDeviceImageFormatInfo2,
840  vk::ImageCompressionControlEXT>
841  format_chain;
842 
843  auto& format_info = format_chain.get();
844 
845  format_info.format = desc.format;
846  format_info.type = desc.type;
847  format_info.tiling = desc.tiling;
848  format_info.usage = desc.usage;
849  format_info.flags = desc.flags;
850 
851  const auto kIdealFRCRate = vk::ImageCompressionFixedRateFlagBitsEXT::e4Bpc;
852 
853  std::array<vk::ImageCompressionFixedRateFlagsEXT, 1u> rates = {kIdealFRCRate};
854 
855  auto& compression = format_chain.get<vk::ImageCompressionControlEXT>();
856  compression.flags = vk::ImageCompressionFlagBitsEXT::eFixedRateExplicit;
857  compression.compressionControlPlaneCount = rates.size();
858  compression.pFixedRateFlags = rates.data();
859 
860  const auto [result, supported] = physical_device_.getImageFormatProperties2<
861  vk::ImageFormatProperties2, vk::ImageCompressionPropertiesEXT>(
862  format_chain.get());
863 
864  if (result != vk::Result::eSuccess ||
865  !supported.isLinked<vk::ImageCompressionPropertiesEXT>()) {
866  return std::nullopt;
867  }
868 
869  const auto& compression_props =
870  supported.get<vk::ImageCompressionPropertiesEXT>();
871 
872  if ((compression_props.imageCompressionFlags &
873  vk::ImageCompressionFlagBitsEXT::eFixedRateExplicit) &&
874  (compression_props.imageCompressionFixedRateFlags & kIdealFRCRate)) {
875  return kIdealFRCRate;
876  }
877 
878  return std::nullopt;
879 }
880 
882  return has_triangle_fans_;
883 }
884 
886  return max_render_pass_attachment_size_;
887 }
888 
890  return max_sampler_anisotropy_;
891 }
892 
894  has_primitive_restart_ = !workarounds.slow_primitive_restart_performance;
895  has_framebuffer_fetch_ = !workarounds.input_attachment_self_dependency_broken;
896 }
897 
899  return supports_external_fence_and_semaphore_;
900 }
901 
903  return false;
904 }
905 
907  return true;
908 }
909 
911  CompressedTextureFamily family) const {
912  switch (family) {
914  return supports_texture_compression_bc_;
916  return supports_texture_compression_etc2_;
918  return supports_texture_compression_astc_;
920  return supports_texture_compression_astc_hdr_;
921  }
922  return false;
923 }
924 
925 } // namespace impeller
926 
927 // NOLINTEND(clang-analyzer-security.PointerSub)
bool SupportsFramebufferRenderMipmap() const override
Whether a non-zero mip level of a texture can be attached as a render target. Rendering into a cube m...
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
bool SupportsManuallyMippedTextures() const override
Whether a texture whose mip levels were uploaded by hand (rather than produced by BlitPass::GenerateM...
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.
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.
uint32_t GetMaxSamplerAnisotropy() const override
The maximum anisotropy clamp supported by device samplers.
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
bool SupportsTextureCompression(CompressedTextureFamily family) const override
Whether the given family of block-compressed texture formats is supported by this device....
vk::StructureChain< vk::PhysicalDeviceFeatures2, vk::PhysicalDeviceSamplerYcbcrConversionFeaturesKHR, vk::PhysicalDevice16BitStorageFeatures, vk::PhysicalDeviceImageCompressionControlFeaturesEXT, vk::PhysicalDeviceTextureCompressionASTCHDRFeatures > PhysicalDeviceFeatures
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
CompressedTextureFamily
The family of a block-compressed pixel format. GPUs support compressed formats on a per-family basis,...
Definition: formats.h:146
@ kASTCHDR
ASTC HDR. A separate device feature from ASTC LDR.
@ kBC
S3TC, RGTC, and BPTC (BC1 through BC7). Desktop GPUs.
@ kETC2
ETC2 and EAC. Mobile, OpenGL ES 3.0, and WebGL2.
@ kASTC
ASTC LDR. Modern mobile and some desktop.
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:93
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