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;
650 minimum_storage_alignment_ =
651 device_properties_.limits.minStorageBufferOffsetAlignment;
678 return has_framebuffer_fetch_;
690 return supports_compute_subgroups_;
704 return supports_device_transient_textures_;
709 return default_color_format_;
714 return default_stencil_format_;
719 return default_depth_stencil_format_;
722 const vk::PhysicalDeviceProperties&
724 return device_properties_;
732 return minimum_uniform_alignment_;
736 return minimum_storage_alignment_;
744 return required_common_device_extensions_.find(ext) !=
745 required_common_device_extensions_.end();
749 return required_android_device_extensions_.find(ext) !=
750 required_android_device_extensions_.end();
754 return optional_device_extensions_.find(ext) !=
755 optional_device_extensions_.end();
759 return optional_android_device_extensions_.find(ext) !=
760 optional_android_device_extensions_.end();
764 return supports_texture_fixed_rate_compression_;
767 std::optional<vk::ImageCompressionFixedRateFlagBitsEXT>
773 if (!supports_texture_fixed_rate_compression_) {
778 vk::StructureChain<vk::PhysicalDeviceImageFormatInfo2,
779 vk::ImageCompressionControlEXT>
782 auto& format_info = format_chain.get();
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;
790 const auto kIdealFRCRate = vk::ImageCompressionFixedRateFlagBitsEXT::e4Bpc;
792 std::array<vk::ImageCompressionFixedRateFlagsEXT, 1u> rates = {kIdealFRCRate};
794 auto& compression = format_chain.get<vk::ImageCompressionControlEXT>();
795 compression.flags = vk::ImageCompressionFlagBitsEXT::eFixedRateExplicit;
796 compression.compressionControlPlaneCount = rates.size();
797 compression.pFixedRateFlags = rates.data();
799 const auto [result, supported] = physical_device_.getImageFormatProperties2<
800 vk::ImageFormatProperties2, vk::ImageCompressionPropertiesEXT>(
803 if (result != vk::Result::eSuccess ||
804 !supported.isLinked<vk::ImageCompressionPropertiesEXT>()) {
808 const auto& compression_props =
809 supported.get<vk::ImageCompressionPropertiesEXT>();
811 if ((compression_props.imageCompressionFlags &
812 vk::ImageCompressionFlagBitsEXT::eFixedRateExplicit) &&
813 (compression_props.imageCompressionFixedRateFlags & kIdealFRCRate)) {
814 return kIdealFRCRate;
821 return has_triangle_fans_;
825 return max_render_pass_attachment_size_;
834 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.
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
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