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;
197 return VK_KHR_EXTERNAL_FENCE_FD_EXTENSION_NAME;
199 return VK_KHR_EXTERNAL_FENCE_EXTENSION_NAME;
201 return VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME;
203 return VK_KHR_EXTERNAL_SEMAPHORE_EXTENSION_NAME;
213 return VK_EXT_PIPELINE_CREATION_FEEDBACK_EXTENSION_NAME;
215 return "VK_KHR_portability_subset";
217 return VK_EXT_IMAGE_COMPRESSION_CONTROL_EXTENSION_NAME;
229 for (
size_t i = 0; i < static_cast<uint32_t>(T::kLast); i++) {
230 if (!it(
static_cast<T
>(i))) {
238 const vk::PhysicalDevice& physical_device) {
239 auto device_extensions = physical_device.enumerateDeviceExtensionProperties();
240 if (device_extensions.result != vk::Result::eSuccess) {
244 std::set<std::string> exts;
245 for (
const auto& device_extension : device_extensions.value) {
246 exts.insert(device_extension.extensionName);
252 std::optional<std::vector<std::string>>
254 const vk::PhysicalDevice& physical_device)
const {
255 std::set<std::string> exts;
257 if (!use_embedder_extensions_) {
260 if (!maybe_exts.has_value()) {
263 exts = maybe_exts.value();
265 exts = std::set(embedder_device_extensions_.begin(),
266 embedder_device_extensions_.end());
269 std::vector<std::string> enabled;
273 if (exts.find(name) == exts.end()) {
274 VALIDATION_LOG <<
"Device does not support required extension: " << name;
277 enabled.push_back(name);
282 #ifdef FML_OS_ANDROID
284 if (exts.find(name) == exts.end()) {
285 VALIDATION_LOG <<
"Device does not support required Android extension: "
289 enabled.push_back(name);
296 if (exts.find(name) != exts.end()) {
297 enabled.push_back(name);
302 const auto iterate_extensions =
303 IterateExtensions<RequiredCommonDeviceExtensionVK>(
304 for_each_common_extension) &&
305 IterateExtensions<RequiredAndroidDeviceExtensionVK>(
306 for_each_android_extension) &&
307 IterateExtensions<OptionalDeviceExtensionVK>(for_each_optional_extension);
309 if (!iterate_extensions) {
310 VALIDATION_LOG <<
"Device not suitable since required extensions are not "
320 const auto props = device.getFormatProperties(format);
322 return !!(props.optimalTilingFeatures &
323 vk::FormatFeatureFlagBits::eColorAttachment);
328 const auto props = device.getFormatProperties(format);
329 return !!(props.optimalTilingFeatures &
330 vk::FormatFeatureFlagBits::eDepthStencilAttachment);
334 const vk::PhysicalDevice& device) {
335 const auto has_color_format =
337 const auto has_stencil_format =
340 return has_color_format && has_stencil_format;
344 auto properties = physical_device.getProperties();
345 if (!(properties.limits.framebufferColorSampleCounts &
346 (vk::SampleCountFlagBits::e1 | vk::SampleCountFlagBits::e4))) {
353 auto queue_flags = vk::QueueFlags{};
354 for (
const auto& queue : physical_device.getQueueFamilyProperties()) {
355 if (queue.queueCount == 0) {
358 queue_flags |= queue.queueFlags;
360 return static_cast<VkQueueFlags
>(queue_flags &
361 (vk::QueueFlagBits::eGraphics |
362 vk::QueueFlagBits::eCompute |
363 vk::QueueFlagBits::eTransfer));
366 template <
class ExtensionEnum>
370 return std::find(list.begin(), list.end(), name) != list.end();
373 std::optional<CapabilitiesVK::PhysicalDeviceFeatures>
375 const vk::PhysicalDevice& device)
const {
382 VALIDATION_LOG <<
"Device doesn't support the required properties.";
392 if (!enabled_extensions.has_value()) {
403 enabled_extensions.value(),
406 .unlink<vk::PhysicalDeviceImageCompressionControlFeaturesEXT>();
409 device.getFeatures2(&supported_chain.get());
415 auto& required = required_chain.get().features;
416 const auto& supported = supported_chain.get().features;
420 required.fillModeNonSolid = supported.fillModeNonSolid;
424 enabled_extensions.value(),
428 .get<vk::PhysicalDeviceSamplerYcbcrConversionFeaturesKHR>();
429 const auto& supported =
431 .get<vk::PhysicalDeviceSamplerYcbcrConversionFeaturesKHR>();
433 required.samplerYcbcrConversion = supported.samplerYcbcrConversion;
438 enabled_extensions.value(),
442 .get<vk::PhysicalDeviceImageCompressionControlFeaturesEXT>();
443 const auto& supported =
445 .get<vk::PhysicalDeviceImageCompressionControlFeaturesEXT>();
447 required.imageCompressionControl = supported.imageCompressionControl;
450 .unlink<vk::PhysicalDeviceImageCompressionControlFeaturesEXT>();
456 required_chain.get<vk::PhysicalDevice16BitStorageFeatures>();
457 const auto& supported =
458 supported_chain.get<vk::PhysicalDevice16BitStorageFeatures>();
460 required.uniformAndStorageBuffer16BitAccess =
461 supported.uniformAndStorageBuffer16BitAccess;
464 return required_chain;
467 bool CapabilitiesVK::HasLayer(
const std::string& layer)
const {
468 for (
const auto& [found_layer, exts] : exts_) {
469 if (found_layer == layer) {
477 for (
const auto& [layer, exts] : exts_) {
478 if (exts.find(ext) != exts.end()) {
486 return has_primitive_restart_;
490 default_color_format_ = pixel_format;
494 const vk::PhysicalDevice& device,
505 vk::Format::eD24UnormS8Uint)) {
514 default_stencil_format_ = default_depth_stencil_format_;
517 physical_device_ = device;
518 device_properties_ = device.getProperties();
520 auto physical_properties_2 =
521 device.getProperties2<vk::PhysicalDeviceProperties2,
522 vk::PhysicalDeviceSubgroupProperties>();
528 supports_compute_subgroups_ =
529 !!(physical_properties_2.get<vk::PhysicalDeviceSubgroupProperties>()
530 .supportedOperations &
531 vk::SubgroupFeatureFlagBits::eArithmetic);
536 vk::PhysicalDeviceMemoryProperties memory_properties;
537 device.getMemoryProperties(&memory_properties);
539 for (
auto i = 0u; i < memory_properties.memoryTypeCount; i++) {
540 if (memory_properties.memoryTypes[i].propertyFlags &
541 vk::MemoryPropertyFlagBits::eLazilyAllocated) {
542 supports_device_transient_textures_ =
true;
549 required_common_device_extensions_.clear();
550 required_android_device_extensions_.clear();
551 optional_device_extensions_.clear();
553 std::set<std::string> exts;
554 if (!use_embedder_extensions_) {
556 if (!maybe_exts.has_value()) {
559 exts = maybe_exts.value();
561 exts = std::set(embedder_device_extensions_.begin(),
562 embedder_device_extensions_.end());
565 IterateExtensions<RequiredCommonDeviceExtensionVK>([&](
auto ext) ->
bool {
567 if (exts.find(ext_name) != exts.end()) {
568 required_common_device_extensions_.insert(ext);
572 IterateExtensions<RequiredAndroidDeviceExtensionVK>([&](
auto ext) ->
bool {
574 if (exts.find(ext_name) != exts.end()) {
575 required_android_device_extensions_.insert(ext);
579 IterateExtensions<OptionalDeviceExtensionVK>([&](
auto ext) ->
bool {
581 if (exts.find(ext_name) != exts.end()) {
582 optional_device_extensions_.insert(ext);
588 supports_texture_fixed_rate_compression_ =
590 .isLinked<vk::PhysicalDeviceImageCompressionControlFeaturesEXT>() &&
592 .get<vk::PhysicalDeviceImageCompressionControlFeaturesEXT>()
593 .imageCompressionControl;
595 max_render_pass_attachment_size_ =
596 ISize{device_properties_.limits.maxFramebufferWidth,
597 device_properties_.limits.maxFramebufferHeight};
630 return has_framebuffer_fetch_;
642 return supports_compute_subgroups_;
656 return supports_device_transient_textures_;
661 return default_color_format_;
666 return default_stencil_format_;
671 return default_depth_stencil_format_;
674 const vk::PhysicalDeviceProperties&
676 return device_properties_;
684 return required_common_device_extensions_.find(ext) !=
685 required_common_device_extensions_.end();
689 return required_android_device_extensions_.find(ext) !=
690 required_android_device_extensions_.end();
694 return optional_device_extensions_.find(ext) !=
695 optional_device_extensions_.end();
699 return supports_texture_fixed_rate_compression_;
702 std::optional<vk::ImageCompressionFixedRateFlagBitsEXT>
708 if (!supports_texture_fixed_rate_compression_) {
713 vk::StructureChain<vk::PhysicalDeviceImageFormatInfo2,
714 vk::ImageCompressionControlEXT>
717 auto& format_info = format_chain.get();
719 format_info.format = desc.
format;
720 format_info.type = desc.
type;
721 format_info.tiling = desc.
tiling;
722 format_info.usage = desc.
usage;
723 format_info.flags = desc.
flags;
725 const auto kIdealFRCRate = vk::ImageCompressionFixedRateFlagBitsEXT::e4Bpc;
727 std::array<vk::ImageCompressionFixedRateFlagsEXT, 1u> rates = {kIdealFRCRate};
729 auto& compression = format_chain.get<vk::ImageCompressionControlEXT>();
730 compression.flags = vk::ImageCompressionFlagBitsEXT::eFixedRateExplicit;
731 compression.compressionControlPlaneCount = rates.size();
732 compression.pFixedRateFlags = rates.data();
734 const auto [result, supported] = physical_device_.getImageFormatProperties2<
735 vk::ImageFormatProperties2, vk::ImageCompressionPropertiesEXT>(
738 if (result != vk::Result::eSuccess ||
739 !supported.isLinked<vk::ImageCompressionPropertiesEXT>()) {
743 const auto& compression_props =
744 supported.get<vk::ImageCompressionPropertiesEXT>();
746 if ((compression_props.imageCompressionFlags &
747 vk::ImageCompressionFlagBitsEXT::eFixedRateExplicit) &&
748 (compression_props.imageCompressionFixedRateFlags & kIdealFRCRate)) {
749 return kIdealFRCRate;
756 return has_triangle_fans_;
760 return max_render_pass_attachment_size_;
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 ...
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 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
@ kKHRExternalSemaphoreFd
@ 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,...
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