20 bool fatal_missing_validations,
21 bool use_embedder_extensions,
22 std::vector<std::string> instance_extensions,
23 std::vector<std::string> device_extensions)
24 : use_embedder_extensions_(use_embedder_extensions),
25 embedder_instance_extensions_(
std::move(instance_extensions)),
26 embedder_device_extensions_(
std::move(device_extensions)) {
27 if (!use_embedder_extensions_) {
28 auto extensions = vk::enumerateInstanceExtensionProperties();
29 auto layers = vk::enumerateInstanceLayerProperties();
31 if (extensions.result != vk::Result::eSuccess ||
32 layers.result != vk::Result::eSuccess) {
36 for (
const auto& ext : extensions.value) {
40 for (
const auto& layer : layers.value) {
41 const std::string layer_name = layer.layerName;
42 auto layer_exts = vk::enumerateInstanceExtensionProperties(layer_name);
43 if (layer_exts.result != vk::Result::eSuccess) {
46 for (
const auto& layer_ext : layer_exts.value) {
47 exts_[layer_name].insert(layer_ext.extensionName);
51 for (
const auto& ext : embedder_instance_extensions_) {
56 validations_enabled_ =
57 enable_validations && HasLayer(
"VK_LAYER_KHRONOS_validation");
58 if (enable_validations && !validations_enabled_) {
60 <<
"Requested Impeller context creation with validations but the "
61 "validation layers could not be found. Expect no Vulkan validation "
63 if (fatal_missing_validations) {
64 FML_LOG(FATAL) <<
"Validation missing. Exiting.";
67 if (validations_enabled_) {
68 FML_LOG(INFO) <<
"Vulkan validations are enabled.";
80 return validations_enabled_;
85 std::vector<std::string> required;
87 if (validations_enabled_) {
89 required.push_back(
"VK_LAYER_KHRONOS_validation");
95 std::optional<std::vector<std::string>>
97 std::vector<std::string> required;
105 required.push_back(
"VK_KHR_surface");
107 auto has_wsi =
false;
109 required.push_back(
"VK_MVK_macos_surface");
114 required.push_back(
"VK_EXT_metal_surface");
119 required.push_back(
"VK_KHR_portability_enumeration");
124 required.push_back(
"VK_KHR_win32_surface");
129 required.push_back(
"VK_KHR_android_surface");
134 required.push_back(
"VK_KHR_xcb_surface");
139 required.push_back(
"VK_KHR_xlib_surface");
144 required.push_back(
"VK_KHR_wayland_surface");
155 if (validations_enabled_) {
158 "VK_EXT_debug_utils extension.";
161 required.push_back(
"VK_EXT_debug_utils");
166 required.push_back(
"VK_EXT_validation_features");
176 return VK_KHR_SWAPCHAIN_EXTENSION_NAME;
187 return "VK_ANDROID_external_memory_android_hardware_buffer";
189 return VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME;
191 return VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME;
193 return VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME;
195 return VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME;
205 return VK_KHR_EXTERNAL_FENCE_FD_EXTENSION_NAME;
207 return VK_KHR_EXTERNAL_FENCE_EXTENSION_NAME;
209 return VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME;
211 return VK_KHR_EXTERNAL_SEMAPHORE_EXTENSION_NAME;
220 return VK_EXT_PIPELINE_CREATION_FEEDBACK_EXTENSION_NAME;
222 return "VK_KHR_portability_subset";
224 return VK_EXT_IMAGE_COMPRESSION_CONTROL_EXTENSION_NAME;
236 for (
size_t i = 0; i < static_cast<uint32_t>(T::kLast); i++) {
237 if (!it(
static_cast<T
>(i))) {
245 const vk::PhysicalDevice& physical_device) {
246 auto device_extensions = physical_device.enumerateDeviceExtensionProperties();
247 if (device_extensions.result != vk::Result::eSuccess) {
251 std::set<std::string> exts;
252 for (
const auto& device_extension : device_extensions.value) {
253 exts.insert(device_extension.extensionName);
259 std::optional<std::vector<std::string>>
261 const vk::PhysicalDevice& physical_device)
const {
262 std::set<std::string> exts;
264 if (!use_embedder_extensions_) {
267 if (!maybe_exts.has_value()) {
270 exts = maybe_exts.value();
272 exts = std::set(embedder_device_extensions_.begin(),
273 embedder_device_extensions_.end());
276 std::vector<std::string> enabled;
280 if (exts.find(name) == exts.end()) {
281 VALIDATION_LOG <<
"Device does not support required extension: " << name;
284 enabled.push_back(name);
289 #ifdef FML_OS_ANDROID
291 if (exts.find(name) == exts.end()) {
292 VALIDATION_LOG <<
"Device does not support required Android extension: "
296 enabled.push_back(name);
301 auto for_each_optional_android_extension =
303 #ifdef FML_OS_ANDROID
305 if (exts.find(name) != exts.end()) {
306 enabled.push_back(name);
314 if (exts.find(name) != exts.end()) {
315 enabled.push_back(name);
320 const auto iterate_extensions =
321 IterateExtensions<RequiredCommonDeviceExtensionVK>(
322 for_each_common_extension) &&
323 IterateExtensions<RequiredAndroidDeviceExtensionVK>(
324 for_each_android_extension) &&
325 IterateExtensions<OptionalDeviceExtensionVK>(
326 for_each_optional_extension) &&
327 IterateExtensions<OptionalAndroidDeviceExtensionVK>(
328 for_each_optional_android_extension);
330 if (!iterate_extensions) {
331 VALIDATION_LOG <<
"Device not suitable since required extensions are not "
341 const auto props = device.getFormatProperties(format);
343 return !!(props.optimalTilingFeatures &
344 vk::FormatFeatureFlagBits::eColorAttachment);
349 const auto props = device.getFormatProperties(format);
350 return !!(props.optimalTilingFeatures &
351 vk::FormatFeatureFlagBits::eDepthStencilAttachment);
355 const vk::PhysicalDevice& device) {
356 const auto has_color_format =
358 const auto has_stencil_format =
361 return has_color_format && has_stencil_format;
365 auto properties = physical_device.getProperties();
366 if (!(properties.limits.framebufferColorSampleCounts &
374 auto queue_flags = vk::QueueFlags{};
375 for (
const auto& queue : physical_device.getQueueFamilyProperties()) {
376 if (queue.queueCount == 0) {
379 queue_flags |= queue.queueFlags;
381 return static_cast<VkQueueFlags
>(queue_flags &
382 (vk::QueueFlagBits::eGraphics |
383 vk::QueueFlagBits::eCompute |
384 vk::QueueFlagBits::eTransfer));
387 template <
class ExtensionEnum>
391 return std::find(list.begin(), list.end(), name) != list.end();
394 std::optional<CapabilitiesVK::PhysicalDeviceFeatures>
396 const vk::PhysicalDevice& device)
const {
403 VALIDATION_LOG <<
"Device doesn't support the required properties.";
413 if (!enabled_extensions.has_value()) {
424 enabled_extensions.value(),
427 .unlink<vk::PhysicalDeviceImageCompressionControlFeaturesEXT>();
430 device.getFeatures2(&supported_chain.get());
436 auto& required = required_chain.get().features;
437 const auto& supported = supported_chain.get().features;
441 required.fillModeNonSolid = supported.fillModeNonSolid;
445 enabled_extensions.value(),
449 .get<vk::PhysicalDeviceSamplerYcbcrConversionFeaturesKHR>();
450 const auto& supported =
452 .get<vk::PhysicalDeviceSamplerYcbcrConversionFeaturesKHR>();
454 required.samplerYcbcrConversion = supported.samplerYcbcrConversion;
459 enabled_extensions.value(),
463 .get<vk::PhysicalDeviceImageCompressionControlFeaturesEXT>();
464 const auto& supported =
466 .get<vk::PhysicalDeviceImageCompressionControlFeaturesEXT>();
468 required.imageCompressionControl = supported.imageCompressionControl;
471 .unlink<vk::PhysicalDeviceImageCompressionControlFeaturesEXT>();
477 required_chain.get<vk::PhysicalDevice16BitStorageFeatures>();
478 const auto& supported =
479 supported_chain.get<vk::PhysicalDevice16BitStorageFeatures>();
481 required.uniformAndStorageBuffer16BitAccess =
482 supported.uniformAndStorageBuffer16BitAccess;
485 return required_chain;
488 bool CapabilitiesVK::HasLayer(
const std::string& layer)
const {
489 for (
const auto& [found_layer, exts] : exts_) {
490 if (found_layer == layer) {
498 for (
const auto& [layer, exts] : exts_) {
499 if (exts.find(ext) != exts.end()) {
507 return has_primitive_restart_;
511 default_color_format_ = pixel_format;
515 const vk::PhysicalDevice& device,
526 vk::Format::eD24UnormS8Uint)) {
535 default_stencil_format_ = default_depth_stencil_format_;
538 physical_device_ = device;
539 device_properties_ = device.getProperties();
541 auto physical_properties_2 =
542 device.getProperties2<vk::PhysicalDeviceProperties2,
543 vk::PhysicalDeviceSubgroupProperties>();
549 supports_compute_subgroups_ =
550 !!(physical_properties_2.get<vk::PhysicalDeviceSubgroupProperties>()
551 .supportedOperations &
552 vk::SubgroupFeatureFlagBits::eArithmetic);
557 vk::PhysicalDeviceMemoryProperties memory_properties;
558 device.getMemoryProperties(&memory_properties);
560 for (
auto i = 0u; i < memory_properties.memoryTypeCount; i++) {
561 if (memory_properties.memoryTypes[i].propertyFlags &
562 vk::MemoryPropertyFlagBits::eLazilyAllocated) {
563 supports_device_transient_textures_ =
true;
570 required_common_device_extensions_.clear();
571 required_android_device_extensions_.clear();
572 optional_device_extensions_.clear();
573 optional_android_device_extensions_.clear();
575 std::set<std::string> exts;
576 if (!use_embedder_extensions_) {
578 if (!maybe_exts.has_value()) {
581 exts = maybe_exts.value();
583 exts = std::set(embedder_device_extensions_.begin(),
584 embedder_device_extensions_.end());
587 IterateExtensions<RequiredCommonDeviceExtensionVK>([&](
auto ext) ->
bool {
589 if (exts.find(ext_name) != exts.end()) {
590 required_common_device_extensions_.insert(ext);
594 IterateExtensions<RequiredAndroidDeviceExtensionVK>([&](
auto ext) ->
bool {
596 if (exts.find(ext_name) != exts.end()) {
597 required_android_device_extensions_.insert(ext);
601 IterateExtensions<OptionalDeviceExtensionVK>([&](
auto ext) ->
bool {
603 if (exts.find(ext_name) != exts.end()) {
604 optional_device_extensions_.insert(ext);
608 IterateExtensions<OptionalAndroidDeviceExtensionVK>(
611 if (exts.find(name) != exts.end()) {
612 optional_android_device_extensions_.insert(ext);
618 supports_texture_fixed_rate_compression_ =
620 .isLinked<vk::PhysicalDeviceImageCompressionControlFeaturesEXT>() &&
622 .get<vk::PhysicalDeviceImageCompressionControlFeaturesEXT>()
623 .imageCompressionControl;
625 max_render_pass_attachment_size_ =
626 ISize{device_properties_.limits.maxFramebufferWidth,
627 device_properties_.limits.maxFramebufferHeight};
640 supports_external_fence_and_semaphore_ =
true;
668 return has_framebuffer_fetch_;
680 return supports_compute_subgroups_;
694 return supports_device_transient_textures_;
699 return default_color_format_;
704 return default_stencil_format_;
709 return default_depth_stencil_format_;
712 const vk::PhysicalDeviceProperties&
714 return device_properties_;
722 return required_common_device_extensions_.find(ext) !=
723 required_common_device_extensions_.end();
727 return required_android_device_extensions_.find(ext) !=
728 required_android_device_extensions_.end();
732 return optional_device_extensions_.find(ext) !=
733 optional_device_extensions_.end();
737 return optional_android_device_extensions_.find(ext) !=
738 optional_android_device_extensions_.end();
742 return supports_texture_fixed_rate_compression_;
745 std::optional<vk::ImageCompressionFixedRateFlagBitsEXT>
751 if (!supports_texture_fixed_rate_compression_) {
756 vk::StructureChain<vk::PhysicalDeviceImageFormatInfo2,
757 vk::ImageCompressionControlEXT>
760 auto& format_info = format_chain.get();
762 format_info.format = desc.
format;
763 format_info.type = desc.
type;
764 format_info.tiling = desc.
tiling;
765 format_info.usage = desc.
usage;
766 format_info.flags = desc.
flags;
768 const auto kIdealFRCRate = vk::ImageCompressionFixedRateFlagBitsEXT::e4Bpc;
770 std::array<vk::ImageCompressionFixedRateFlagsEXT, 1u> rates = {kIdealFRCRate};
772 auto& compression = format_chain.get<vk::ImageCompressionControlEXT>();
773 compression.flags = vk::ImageCompressionFlagBitsEXT::eFixedRateExplicit;
774 compression.compressionControlPlaneCount = rates.size();
775 compression.pFixedRateFlags = rates.data();
777 const auto [result, supported] = physical_device_.getImageFormatProperties2<
778 vk::ImageFormatProperties2, vk::ImageCompressionPropertiesEXT>(
781 if (result != vk::Result::eSuccess ||
782 !supported.isLinked<vk::ImageCompressionPropertiesEXT>()) {
786 const auto& compression_props =
787 supported.get<vk::ImageCompressionPropertiesEXT>();
789 if ((compression_props.imageCompressionFlags &
790 vk::ImageCompressionFlagBitsEXT::eFixedRateExplicit) &&
791 (compression_props.imageCompressionFixedRateFlags & kIdealFRCRate)) {
792 return kIdealFRCRate;
799 return has_triangle_fans_;
803 return max_render_pass_attachment_size_;
812 return supports_external_fence_and_semaphore_;
bool SupportsTriangleFan() const override
Whether the primitive type TriangleFan is supported by the backend.
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
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