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();
34 if (extensions.result != vk::Result::eSuccess ||
35 layers.result != vk::Result::eSuccess) {
39 for (
const auto& ext : extensions.value) {
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) {
49 for (
const auto& layer_ext : layer_exts.value) {
50 exts_[layer_name].insert(layer_ext.extensionName);
54 for (
const auto& ext : embedder_instance_extensions_) {
59 validations_enabled_ =
60 enable_validations && HasLayer(
"VK_LAYER_KHRONOS_validation");
61 if (enable_validations && !validations_enabled_) {
63 <<
"Requested Impeller context creation with validations but the "
64 "validation layers could not be found. Expect no Vulkan validation "
66 if (fatal_missing_validations) {
67 FML_LOG(FATAL) <<
"Validation missing. Exiting.";
70 if (validations_enabled_) {
71 FML_LOG(INFO) <<
"Vulkan validations are enabled.";
83 return validations_enabled_;
88 std::vector<std::string> required;
90 if (validations_enabled_) {
92 required.push_back(
"VK_LAYER_KHRONOS_validation");
98 std::optional<std::vector<std::string>>
100 std::vector<std::string> required;
108 required.push_back(
"VK_KHR_surface");
110 auto has_wsi =
false;
112 required.push_back(
"VK_MVK_macos_surface");
117 required.push_back(
"VK_EXT_metal_surface");
122 required.push_back(
"VK_KHR_portability_enumeration");
127 required.push_back(
"VK_KHR_win32_surface");
132 required.push_back(
"VK_KHR_android_surface");
137 required.push_back(
"VK_KHR_xcb_surface");
142 required.push_back(
"VK_KHR_xlib_surface");
147 required.push_back(
"VK_KHR_wayland_surface");
158 if (validations_enabled_) {
161 "VK_EXT_debug_utils extension.";
164 required.push_back(
"VK_EXT_debug_utils");
169 required.push_back(
"VK_EXT_validation_features");
179 return VK_KHR_SWAPCHAIN_EXTENSION_NAME;
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;
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;
223 return VK_EXT_PIPELINE_CREATION_FEEDBACK_EXTENSION_NAME;
225 return "VK_KHR_portability_subset";
227 return VK_EXT_IMAGE_COMPRESSION_CONTROL_EXTENSION_NAME;
239 for (
size_t i = 0; i < static_cast<uint32_t>(T::kLast); i++) {
240 if (!it(
static_cast<T
>(i))) {
248 const vk::PhysicalDevice& physical_device) {
249 auto device_extensions = physical_device.enumerateDeviceExtensionProperties();
250 if (device_extensions.result != vk::Result::eSuccess) {
254 std::set<std::string> exts;
255 for (
const auto& device_extension : device_extensions.value) {
256 exts.insert(device_extension.extensionName);
262 std::optional<std::vector<std::string>>
264 const vk::PhysicalDevice& physical_device)
const {
265 std::set<std::string> exts;
267 if (!use_embedder_extensions_) {
270 if (!maybe_exts.has_value()) {
273 exts = maybe_exts.value();
275 for (
const auto& ext : embedder_device_extensions_) {
280 std::vector<std::string> enabled;
284 if (exts.find(name) == exts.end()) {
285 VALIDATION_LOG <<
"Device does not support required extension: " << name;
288 enabled.push_back(name);
293 #ifdef FML_OS_ANDROID
295 if (exts.find(name) == exts.end()) {
296 VALIDATION_LOG <<
"Device does not support required Android extension: "
300 enabled.push_back(name);
305 auto for_each_optional_android_extension =
307 #ifdef FML_OS_ANDROID
309 if (exts.find(name) != exts.end()) {
310 enabled.push_back(name);
318 if (exts.find(name) != exts.end()) {
319 enabled.push_back(name);
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);
334 if (!iterate_extensions) {
335 VALIDATION_LOG <<
"Device not suitable since required extensions are not "
345 const auto props = device.getFormatProperties(format);
347 return !!(props.optimalTilingFeatures &
348 vk::FormatFeatureFlagBits::eColorAttachment);
353 const auto props = device.getFormatProperties(format);
354 return !!(props.optimalTilingFeatures &
355 vk::FormatFeatureFlagBits::eDepthStencilAttachment);
359 const vk::PhysicalDevice& device) {
360 const auto has_color_format =
362 const auto has_stencil_format =
365 return has_color_format && has_stencil_format;
369 auto properties = physical_device.getProperties();
370 if (!(properties.limits.framebufferColorSampleCounts &
378 auto queue_flags = vk::QueueFlags{};
379 for (
const auto& queue : physical_device.getQueueFamilyProperties()) {
380 if (queue.queueCount == 0) {
383 queue_flags |= queue.queueFlags;
385 return static_cast<VkQueueFlags
>(queue_flags &
386 (vk::QueueFlagBits::eGraphics |
387 vk::QueueFlagBits::eCompute |
388 vk::QueueFlagBits::eTransfer));
391 template <
class ExtensionEnum>
395 return std::find(list.begin(), list.end(), name) != list.end();
398 std::optional<CapabilitiesVK::PhysicalDeviceFeatures>
400 const vk::PhysicalDevice& device)
const {
407 VALIDATION_LOG <<
"Device doesn't support the required properties.";
417 if (!enabled_extensions.has_value()) {
428 enabled_extensions.value(),
431 .unlink<vk::PhysicalDeviceImageCompressionControlFeaturesEXT>();
434 device.getFeatures2(&supported_chain.get());
440 auto& required = required_chain.get().features;
441 const auto& supported = supported_chain.get().features;
445 required.fillModeNonSolid = supported.fillModeNonSolid;
449 enabled_extensions.value(),
453 .get<vk::PhysicalDeviceSamplerYcbcrConversionFeaturesKHR>();
454 const auto& supported =
456 .get<vk::PhysicalDeviceSamplerYcbcrConversionFeaturesKHR>();
458 required.samplerYcbcrConversion = supported.samplerYcbcrConversion;
463 enabled_extensions.value(),
467 .get<vk::PhysicalDeviceImageCompressionControlFeaturesEXT>();
468 const auto& supported =
470 .get<vk::PhysicalDeviceImageCompressionControlFeaturesEXT>();
472 required.imageCompressionControl = supported.imageCompressionControl;
475 .unlink<vk::PhysicalDeviceImageCompressionControlFeaturesEXT>();
481 required_chain.get<vk::PhysicalDevice16BitStorageFeatures>();
482 const auto& supported =
483 supported_chain.get<vk::PhysicalDevice16BitStorageFeatures>();
485 required.uniformAndStorageBuffer16BitAccess =
486 supported.uniformAndStorageBuffer16BitAccess;
489 return required_chain;
492 bool CapabilitiesVK::HasLayer(
const std::string& layer)
const {
493 for (
const auto& [found_layer, exts] : exts_) {
494 if (found_layer == layer) {
502 for (
const auto& [layer, exts] : exts_) {
503 if (exts.find(ext) != exts.end()) {
511 return has_primitive_restart_;
515 default_color_format_ = pixel_format;
519 const vk::PhysicalDevice& device,
530 vk::Format::eD32SfloatS8Uint)) {
539 default_stencil_format_ = default_depth_stencil_format_;
542 physical_device_ = device;
543 device_properties_ = device.getProperties();
545 auto physical_properties_2 =
546 device.getProperties2<vk::PhysicalDeviceProperties2,
547 vk::PhysicalDeviceSubgroupProperties>();
553 supports_compute_subgroups_ =
554 !!(physical_properties_2.get<vk::PhysicalDeviceSubgroupProperties>()
555 .supportedOperations &
556 vk::SubgroupFeatureFlagBits::eArithmetic);
561 vk::PhysicalDeviceMemoryProperties memory_properties;
562 device.getMemoryProperties(&memory_properties);
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;
574 required_common_device_extensions_.clear();
575 required_android_device_extensions_.clear();
576 optional_device_extensions_.clear();
577 optional_android_device_extensions_.clear();
579 std::set<std::string> exts;
580 if (!use_embedder_extensions_) {
582 if (!maybe_exts.has_value()) {
585 exts = maybe_exts.value();
587 for (
const auto& ext : embedder_device_extensions_) {
592 IterateExtensions<RequiredCommonDeviceExtensionVK>([&](
auto ext) ->
bool {
594 if (exts.find(ext_name) != exts.end()) {
595 required_common_device_extensions_.insert(ext);
599 IterateExtensions<RequiredAndroidDeviceExtensionVK>([&](
auto ext) ->
bool {
601 if (exts.find(ext_name) != exts.end()) {
602 required_android_device_extensions_.insert(ext);
606 IterateExtensions<OptionalDeviceExtensionVK>([&](
auto ext) ->
bool {
608 if (exts.find(ext_name) != exts.end()) {
609 optional_device_extensions_.insert(ext);
613 IterateExtensions<OptionalAndroidDeviceExtensionVK>(
616 if (exts.find(name) != exts.end()) {
617 optional_android_device_extensions_.insert(ext);
623 supports_texture_fixed_rate_compression_ =
625 .isLinked<vk::PhysicalDeviceImageCompressionControlFeaturesEXT>() &&
627 .get<vk::PhysicalDeviceImageCompressionControlFeaturesEXT>()
628 .imageCompressionControl;
630 max_render_pass_attachment_size_ =
631 ISize{device_properties_.limits.maxFramebufferWidth,
632 device_properties_.limits.maxFramebufferHeight};
645 supports_external_fence_and_semaphore_ =
true;
648 minimum_uniform_alignment_ =
649 device_properties_.limits.minUniformBufferOffsetAlignment;
676 return has_framebuffer_fetch_;
688 return supports_compute_subgroups_;
702 return supports_device_transient_textures_;
707 return default_color_format_;
712 return default_stencil_format_;
717 return default_depth_stencil_format_;
720 const vk::PhysicalDeviceProperties&
722 return device_properties_;
730 return minimum_uniform_alignment_;
738 return required_common_device_extensions_.find(ext) !=
739 required_common_device_extensions_.end();
743 return required_android_device_extensions_.find(ext) !=
744 required_android_device_extensions_.end();
748 return optional_device_extensions_.find(ext) !=
749 optional_device_extensions_.end();
753 return optional_android_device_extensions_.find(ext) !=
754 optional_android_device_extensions_.end();
758 return supports_texture_fixed_rate_compression_;
761 std::optional<vk::ImageCompressionFixedRateFlagBitsEXT>
767 if (!supports_texture_fixed_rate_compression_) {
772 vk::StructureChain<vk::PhysicalDeviceImageFormatInfo2,
773 vk::ImageCompressionControlEXT>
776 auto& format_info = format_chain.get();
778 format_info.format = desc.
format;
779 format_info.type = desc.
type;
780 format_info.tiling = desc.
tiling;
781 format_info.usage = desc.
usage;
782 format_info.flags = desc.
flags;
784 const auto kIdealFRCRate = vk::ImageCompressionFixedRateFlagBitsEXT::e4Bpc;
786 std::array<vk::ImageCompressionFixedRateFlagsEXT, 1u> rates = {kIdealFRCRate};
788 auto& compression = format_chain.get<vk::ImageCompressionControlEXT>();
789 compression.flags = vk::ImageCompressionFlagBitsEXT::eFixedRateExplicit;
790 compression.compressionControlPlaneCount = rates.size();
791 compression.pFixedRateFlags = rates.data();
793 const auto [result, supported] = physical_device_.getImageFormatProperties2<
794 vk::ImageFormatProperties2, vk::ImageCompressionPropertiesEXT>(
797 if (result != vk::Result::eSuccess ||
798 !supported.isLinked<vk::ImageCompressionPropertiesEXT>()) {
802 const auto& compression_props =
803 supported.get<vk::ImageCompressionPropertiesEXT>();
805 if ((compression_props.imageCompressionFlags &
806 vk::ImageCompressionFlagBitsEXT::eFixedRateExplicit) &&
807 (compression_props.imageCompressionFixedRateFlags & kIdealFRCRate)) {
808 return kIdealFRCRate;
815 return has_triangle_fans_;
819 return max_render_pass_attachment_size_;
828 return supports_external_fence_and_semaphore_;
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.
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
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...
@ kKHRSamplerYcbcrConversion
@ kKHRDedicatedAllocation
@ kANDROIDExternalMemoryAndroidHardwareBuffer
PixelFormat
The Pixel formats supported by Impeller. The naming convention denotes the usage of the component,...
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.
@ kKHRExternalSemaphoreFd
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...
@ kEXTImageCompressionControl
@ kVKKHRPortabilitySubset
@ kEXTPipelineCreationFeedback
static bool HasRequiredQueues(const vk::PhysicalDevice &physical_device)
A non-exhaustive set of driver specific workarounds.
bool slow_primitive_restart_performance
bool input_attachment_self_dependency_broken