| // Copyright 2013 The Flutter Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef FLUTTER_IMPELLER_RENDERER_BACKEND_VULKAN_FORMATS_VK_H_ |
| #define FLUTTER_IMPELLER_RENDERER_BACKEND_VULKAN_FORMATS_VK_H_ |
| |
| #include <cstdint> |
| #include <ostream> |
| |
| #include "flutter/fml/hash_combine.h" |
| #include "flutter/fml/macros.h" |
| #include "impeller/base/validation.h" |
| #include "impeller/core/formats.h" |
| #include "impeller/core/shader_types.h" |
| #include "impeller/renderer/backend/vulkan/vk.h" |
| #include "vulkan/vulkan_enums.hpp" |
| |
| namespace impeller { |
| |
| constexpr vk::SampleCountFlagBits ToVKSampleCountFlagBits(SampleCount count) { |
| switch (count) { |
| case SampleCount::kCount1: |
| return vk::SampleCountFlagBits::e1; |
| case SampleCount::kCount4: |
| return vk::SampleCountFlagBits::e4; |
| } |
| FML_UNREACHABLE(); |
| } |
| |
| constexpr vk::BlendFactor ToVKBlendFactor(BlendFactor factor) { |
| switch (factor) { |
| case BlendFactor::kZero: |
| return vk::BlendFactor::eZero; |
| case BlendFactor::kOne: |
| return vk::BlendFactor::eOne; |
| case BlendFactor::kSourceColor: |
| return vk::BlendFactor::eSrcColor; |
| case BlendFactor::kOneMinusSourceColor: |
| return vk::BlendFactor::eOneMinusSrcColor; |
| case BlendFactor::kSourceAlpha: |
| return vk::BlendFactor::eSrcAlpha; |
| case BlendFactor::kOneMinusSourceAlpha: |
| return vk::BlendFactor::eOneMinusSrcAlpha; |
| case BlendFactor::kDestinationColor: |
| return vk::BlendFactor::eDstColor; |
| case BlendFactor::kOneMinusDestinationColor: |
| return vk::BlendFactor::eOneMinusDstColor; |
| case BlendFactor::kDestinationAlpha: |
| return vk::BlendFactor::eDstAlpha; |
| case BlendFactor::kOneMinusDestinationAlpha: |
| return vk::BlendFactor::eOneMinusDstAlpha; |
| case BlendFactor::kSourceAlphaSaturated: |
| return vk::BlendFactor::eSrcAlphaSaturate; |
| case BlendFactor::kBlendColor: |
| return vk::BlendFactor::eConstantColor; |
| case BlendFactor::kOneMinusBlendColor: |
| return vk::BlendFactor::eOneMinusConstantColor; |
| case BlendFactor::kBlendAlpha: |
| return vk::BlendFactor::eConstantAlpha; |
| case BlendFactor::kOneMinusBlendAlpha: |
| return vk::BlendFactor::eOneMinusConstantAlpha; |
| } |
| FML_UNREACHABLE(); |
| } |
| |
| constexpr vk::BlendOp ToVKBlendOp(BlendOperation op) { |
| switch (op) { |
| case BlendOperation::kAdd: |
| return vk::BlendOp::eAdd; |
| case BlendOperation::kSubtract: |
| return vk::BlendOp::eSubtract; |
| case BlendOperation::kReverseSubtract: |
| return vk::BlendOp::eReverseSubtract; |
| } |
| FML_UNREACHABLE(); |
| } |
| |
| constexpr vk::ColorComponentFlags ToVKColorComponentFlags(ColorWriteMask type) { |
| vk::ColorComponentFlags mask; |
| |
| if (type & ColorWriteMaskBits::kRed) { |
| mask |= vk::ColorComponentFlagBits::eR; |
| } |
| |
| if (type & ColorWriteMaskBits::kGreen) { |
| mask |= vk::ColorComponentFlagBits::eG; |
| } |
| |
| if (type & ColorWriteMaskBits::kBlue) { |
| mask |= vk::ColorComponentFlagBits::eB; |
| } |
| |
| if (type & ColorWriteMaskBits::kAlpha) { |
| mask |= vk::ColorComponentFlagBits::eA; |
| } |
| |
| return mask; |
| } |
| |
| constexpr vk::PipelineColorBlendAttachmentState |
| ToVKPipelineColorBlendAttachmentState(const ColorAttachmentDescriptor& desc) { |
| vk::PipelineColorBlendAttachmentState res; |
| |
| res.setBlendEnable(desc.blending_enabled); |
| |
| res.setSrcColorBlendFactor(ToVKBlendFactor(desc.src_color_blend_factor)); |
| res.setColorBlendOp(ToVKBlendOp(desc.color_blend_op)); |
| res.setDstColorBlendFactor(ToVKBlendFactor(desc.dst_color_blend_factor)); |
| |
| res.setSrcAlphaBlendFactor(ToVKBlendFactor(desc.src_alpha_blend_factor)); |
| res.setAlphaBlendOp(ToVKBlendOp(desc.alpha_blend_op)); |
| res.setDstAlphaBlendFactor(ToVKBlendFactor(desc.dst_alpha_blend_factor)); |
| |
| res.setColorWriteMask(ToVKColorComponentFlags(desc.write_mask)); |
| |
| return res; |
| } |
| |
| constexpr std::optional<vk::ShaderStageFlagBits> ToVKShaderStageFlagBits( |
| ShaderStage stage) { |
| switch (stage) { |
| case ShaderStage::kUnknown: |
| return std::nullopt; |
| case ShaderStage::kVertex: |
| return vk::ShaderStageFlagBits::eVertex; |
| case ShaderStage::kFragment: |
| return vk::ShaderStageFlagBits::eFragment; |
| case ShaderStage::kCompute: |
| return vk::ShaderStageFlagBits::eCompute; |
| } |
| FML_UNREACHABLE(); |
| } |
| |
| constexpr vk::Format ToVKImageFormat(PixelFormat format) { |
| switch (format) { |
| case PixelFormat::kUnknown: |
| case PixelFormat::kB10G10R10XR: |
| case PixelFormat::kB10G10R10A10XR: |
| case PixelFormat::kB10G10R10XRSRGB: |
| return vk::Format::eUndefined; |
| case PixelFormat::kA8UNormInt: |
| // TODO(csg): This is incorrect. Don't depend on swizzle support for GLES. |
| return vk::Format::eR8Unorm; |
| case PixelFormat::kR8G8B8A8UNormInt: |
| return vk::Format::eR8G8B8A8Unorm; |
| case PixelFormat::kR8G8B8A8UNormIntSRGB: |
| return vk::Format::eR8G8B8A8Srgb; |
| case PixelFormat::kB8G8R8A8UNormInt: |
| return vk::Format::eB8G8R8A8Unorm; |
| case PixelFormat::kB8G8R8A8UNormIntSRGB: |
| return vk::Format::eB8G8R8A8Srgb; |
| case PixelFormat::kR32G32B32A32Float: |
| return vk::Format::eR32G32B32A32Sfloat; |
| case PixelFormat::kR16G16B16A16Float: |
| return vk::Format::eR16G16B16A16Sfloat; |
| case PixelFormat::kS8UInt: |
| return vk::Format::eS8Uint; |
| case PixelFormat::kD24UnormS8Uint: |
| return vk::Format::eD24UnormS8Uint; |
| case PixelFormat::kD32FloatS8UInt: |
| return vk::Format::eD32SfloatS8Uint; |
| case PixelFormat::kR8UNormInt: |
| return vk::Format::eR8Unorm; |
| case PixelFormat::kR8G8UNormInt: |
| return vk::Format::eR8G8Unorm; |
| } |
| |
| FML_UNREACHABLE(); |
| } |
| |
| constexpr PixelFormat ToPixelFormat(vk::Format format) { |
| switch (format) { |
| case vk::Format::eUndefined: |
| return PixelFormat::kUnknown; |
| case vk::Format::eR8G8B8A8Unorm: |
| return PixelFormat::kR8G8B8A8UNormInt; |
| case vk::Format::eR8G8B8A8Srgb: |
| return PixelFormat::kR8G8B8A8UNormIntSRGB; |
| case vk::Format::eB8G8R8A8Unorm: |
| return PixelFormat::kB8G8R8A8UNormInt; |
| case vk::Format::eB8G8R8A8Srgb: |
| return PixelFormat::kB8G8R8A8UNormIntSRGB; |
| case vk::Format::eR32G32B32A32Sfloat: |
| return PixelFormat::kR32G32B32A32Float; |
| case vk::Format::eR16G16B16A16Sfloat: |
| return PixelFormat::kR16G16B16A16Float; |
| case vk::Format::eS8Uint: |
| return PixelFormat::kS8UInt; |
| case vk::Format::eD24UnormS8Uint: |
| return PixelFormat::kD24UnormS8Uint; |
| case vk::Format::eD32SfloatS8Uint: |
| return PixelFormat::kD32FloatS8UInt; |
| case vk::Format::eR8Unorm: |
| return PixelFormat::kR8UNormInt; |
| case vk::Format::eR8G8Unorm: |
| return PixelFormat::kR8G8UNormInt; |
| default: |
| return PixelFormat::kUnknown; |
| } |
| } |
| |
| constexpr vk::SampleCountFlagBits ToVKSampleCount(SampleCount sample_count) { |
| switch (sample_count) { |
| case SampleCount::kCount1: |
| return vk::SampleCountFlagBits::e1; |
| case SampleCount::kCount4: |
| return vk::SampleCountFlagBits::e4; |
| } |
| |
| FML_UNREACHABLE(); |
| } |
| |
| constexpr vk::Filter ToVKSamplerMinMagFilter(MinMagFilter filter) { |
| switch (filter) { |
| case MinMagFilter::kNearest: |
| return vk::Filter::eNearest; |
| case MinMagFilter::kLinear: |
| return vk::Filter::eLinear; |
| } |
| |
| FML_UNREACHABLE(); |
| } |
| |
| constexpr vk::SamplerMipmapMode ToVKSamplerMipmapMode(MipFilter filter) { |
| switch (filter) { |
| case MipFilter::kNearest: |
| return vk::SamplerMipmapMode::eNearest; |
| case MipFilter::kLinear: |
| return vk::SamplerMipmapMode::eLinear; |
| } |
| |
| FML_UNREACHABLE(); |
| } |
| |
| constexpr vk::SamplerAddressMode ToVKSamplerAddressMode( |
| SamplerAddressMode mode) { |
| switch (mode) { |
| case SamplerAddressMode::kRepeat: |
| return vk::SamplerAddressMode::eRepeat; |
| case SamplerAddressMode::kMirror: |
| return vk::SamplerAddressMode::eMirroredRepeat; |
| case SamplerAddressMode::kClampToEdge: |
| return vk::SamplerAddressMode::eClampToEdge; |
| case SamplerAddressMode::kDecal: |
| return vk::SamplerAddressMode::eClampToBorder; |
| } |
| |
| FML_UNREACHABLE(); |
| } |
| |
| constexpr vk::ShaderStageFlags ToVkShaderStage(ShaderStage stage) { |
| switch (stage) { |
| case ShaderStage::kUnknown: |
| return vk::ShaderStageFlagBits::eAll; |
| case ShaderStage::kFragment: |
| return vk::ShaderStageFlagBits::eFragment; |
| case ShaderStage::kCompute: |
| return vk::ShaderStageFlagBits::eCompute; |
| case ShaderStage::kVertex: |
| return vk::ShaderStageFlagBits::eVertex; |
| } |
| |
| FML_UNREACHABLE(); |
| } |
| |
| constexpr vk::DescriptorType ToVKDescriptorType(DescriptorType type) { |
| switch (type) { |
| case DescriptorType::kSampledImage: |
| return vk::DescriptorType::eCombinedImageSampler; |
| break; |
| case DescriptorType::kUniformBuffer: |
| return vk::DescriptorType::eUniformBuffer; |
| break; |
| case DescriptorType::kStorageBuffer: |
| return vk::DescriptorType::eStorageBuffer; |
| break; |
| case DescriptorType::kImage: |
| return vk::DescriptorType::eSampledImage; |
| break; |
| case DescriptorType::kSampler: |
| return vk::DescriptorType::eSampler; |
| break; |
| case DescriptorType::kInputAttachment: |
| return vk::DescriptorType::eInputAttachment; |
| } |
| |
| FML_UNREACHABLE(); |
| } |
| |
| constexpr vk::DescriptorSetLayoutBinding ToVKDescriptorSetLayoutBinding( |
| const DescriptorSetLayout& layout) { |
| vk::DescriptorSetLayoutBinding binding; |
| binding.binding = layout.binding; |
| binding.descriptorCount = 1u; |
| binding.descriptorType = ToVKDescriptorType(layout.descriptor_type); |
| binding.stageFlags = ToVkShaderStage(layout.shader_stage); |
| return binding; |
| } |
| |
| constexpr vk::AttachmentLoadOp ToVKAttachmentLoadOp(LoadAction load_action) { |
| switch (load_action) { |
| case LoadAction::kLoad: |
| return vk::AttachmentLoadOp::eLoad; |
| case LoadAction::kClear: |
| return vk::AttachmentLoadOp::eClear; |
| case LoadAction::kDontCare: |
| return vk::AttachmentLoadOp::eDontCare; |
| } |
| |
| FML_UNREACHABLE(); |
| } |
| |
| constexpr vk::AttachmentStoreOp ToVKAttachmentStoreOp(StoreAction store_action, |
| bool is_resolve_texture) { |
| switch (store_action) { |
| case StoreAction::kStore: |
| // Both MSAA and resolve textures need to be stored. A resolve is NOT |
| // performed. |
| return vk::AttachmentStoreOp::eStore; |
| case StoreAction::kDontCare: |
| // Both MSAA and resolve textures can be discarded. A resolve is NOT |
| // performed. |
| return vk::AttachmentStoreOp::eDontCare; |
| case StoreAction::kMultisampleResolve: |
| // The resolve texture is stored but the MSAA texture can be discarded. A |
| // resolve IS performed. |
| return is_resolve_texture ? vk::AttachmentStoreOp::eStore |
| : vk::AttachmentStoreOp::eDontCare; |
| case StoreAction::kStoreAndMultisampleResolve: |
| // Both MSAA and resolve textures need to be stored. A resolve IS |
| // performed. |
| return vk::AttachmentStoreOp::eStore; |
| } |
| FML_UNREACHABLE(); |
| } |
| |
| constexpr bool StoreActionPerformsResolve(StoreAction store_action) { |
| switch (store_action) { |
| case StoreAction::kDontCare: |
| case StoreAction::kStore: |
| return false; |
| case StoreAction::kMultisampleResolve: |
| case StoreAction::kStoreAndMultisampleResolve: |
| return true; |
| } |
| FML_UNREACHABLE(); |
| } |
| |
| constexpr vk::IndexType ToVKIndexType(IndexType index_type) { |
| switch (index_type) { |
| case IndexType::k16bit: |
| return vk::IndexType::eUint16; |
| case IndexType::k32bit: |
| return vk::IndexType::eUint32; |
| case IndexType::kUnknown: |
| return vk::IndexType::eUint32; |
| case IndexType::kNone: |
| FML_UNREACHABLE(); |
| } |
| |
| FML_UNREACHABLE(); |
| } |
| |
| constexpr vk::PolygonMode ToVKPolygonMode(PolygonMode mode) { |
| switch (mode) { |
| case PolygonMode::kFill: |
| return vk::PolygonMode::eFill; |
| case PolygonMode::kLine: |
| return vk::PolygonMode::eLine; |
| } |
| FML_UNREACHABLE(); |
| } |
| |
| constexpr vk::PrimitiveTopology ToVKPrimitiveTopology(PrimitiveType primitive) { |
| switch (primitive) { |
| case PrimitiveType::kTriangle: |
| return vk::PrimitiveTopology::eTriangleList; |
| case PrimitiveType::kTriangleStrip: |
| return vk::PrimitiveTopology::eTriangleStrip; |
| case PrimitiveType::kLine: |
| return vk::PrimitiveTopology::eLineList; |
| case PrimitiveType::kLineStrip: |
| return vk::PrimitiveTopology::eLineStrip; |
| case PrimitiveType::kPoint: |
| return vk::PrimitiveTopology::ePointList; |
| } |
| |
| FML_UNREACHABLE(); |
| } |
| |
| constexpr bool PixelFormatIsDepthStencil(PixelFormat format) { |
| switch (format) { |
| case PixelFormat::kUnknown: |
| case PixelFormat::kA8UNormInt: |
| case PixelFormat::kR8UNormInt: |
| case PixelFormat::kR8G8UNormInt: |
| case PixelFormat::kR8G8B8A8UNormInt: |
| case PixelFormat::kR8G8B8A8UNormIntSRGB: |
| case PixelFormat::kB8G8R8A8UNormInt: |
| case PixelFormat::kB8G8R8A8UNormIntSRGB: |
| case PixelFormat::kR32G32B32A32Float: |
| case PixelFormat::kR16G16B16A16Float: |
| case PixelFormat::kB10G10R10XR: |
| case PixelFormat::kB10G10R10XRSRGB: |
| case PixelFormat::kB10G10R10A10XR: |
| return false; |
| case PixelFormat::kS8UInt: |
| case PixelFormat::kD24UnormS8Uint: |
| case PixelFormat::kD32FloatS8UInt: |
| return true; |
| } |
| return false; |
| } |
| |
| static constexpr vk::AttachmentReference kUnusedAttachmentReference = { |
| VK_ATTACHMENT_UNUSED, vk::ImageLayout::eUndefined}; |
| |
| constexpr vk::CullModeFlags ToVKCullModeFlags(CullMode mode) { |
| switch (mode) { |
| case CullMode::kNone: |
| return vk::CullModeFlagBits::eNone; |
| case CullMode::kFrontFace: |
| return vk::CullModeFlagBits::eFront; |
| case CullMode::kBackFace: |
| return vk::CullModeFlagBits::eBack; |
| } |
| FML_UNREACHABLE(); |
| } |
| |
| constexpr vk::CompareOp ToVKCompareOp(CompareFunction op) { |
| switch (op) { |
| case CompareFunction::kNever: |
| return vk::CompareOp::eNever; |
| case CompareFunction::kAlways: |
| return vk::CompareOp::eAlways; |
| case CompareFunction::kLess: |
| return vk::CompareOp::eLess; |
| case CompareFunction::kEqual: |
| return vk::CompareOp::eEqual; |
| case CompareFunction::kLessEqual: |
| return vk::CompareOp::eLessOrEqual; |
| case CompareFunction::kGreater: |
| return vk::CompareOp::eGreater; |
| case CompareFunction::kNotEqual: |
| return vk::CompareOp::eNotEqual; |
| case CompareFunction::kGreaterEqual: |
| return vk::CompareOp::eGreaterOrEqual; |
| } |
| FML_UNREACHABLE(); |
| } |
| |
| constexpr vk::StencilOp ToVKStencilOp(StencilOperation op) { |
| switch (op) { |
| case StencilOperation::kKeep: |
| return vk::StencilOp::eKeep; |
| case StencilOperation::kZero: |
| return vk::StencilOp::eZero; |
| case StencilOperation::kSetToReferenceValue: |
| return vk::StencilOp::eReplace; |
| case StencilOperation::kIncrementClamp: |
| return vk::StencilOp::eIncrementAndClamp; |
| case StencilOperation::kDecrementClamp: |
| return vk::StencilOp::eDecrementAndClamp; |
| case StencilOperation::kInvert: |
| return vk::StencilOp::eInvert; |
| case StencilOperation::kIncrementWrap: |
| return vk::StencilOp::eIncrementAndWrap; |
| case StencilOperation::kDecrementWrap: |
| return vk::StencilOp::eDecrementAndWrap; |
| break; |
| } |
| FML_UNREACHABLE(); |
| } |
| |
| constexpr vk::StencilOpState ToVKStencilOpState( |
| const StencilAttachmentDescriptor& desc) { |
| vk::StencilOpState state; |
| state.failOp = ToVKStencilOp(desc.stencil_failure); |
| state.passOp = ToVKStencilOp(desc.depth_stencil_pass); |
| state.depthFailOp = ToVKStencilOp(desc.depth_failure); |
| state.compareOp = ToVKCompareOp(desc.stencil_compare); |
| state.compareMask = desc.read_mask; |
| state.writeMask = desc.write_mask; |
| // This is irrelevant as the stencil references are always dynamic state and |
| // will be set in the render pass. |
| state.reference = 1988; |
| return state; |
| } |
| |
| constexpr vk::ImageAspectFlags ToVKImageAspectFlags(PixelFormat format) { |
| switch (format) { |
| case PixelFormat::kUnknown: |
| case PixelFormat::kA8UNormInt: |
| case PixelFormat::kR8UNormInt: |
| case PixelFormat::kR8G8UNormInt: |
| case PixelFormat::kR8G8B8A8UNormInt: |
| case PixelFormat::kR8G8B8A8UNormIntSRGB: |
| case PixelFormat::kB8G8R8A8UNormInt: |
| case PixelFormat::kB8G8R8A8UNormIntSRGB: |
| case PixelFormat::kR32G32B32A32Float: |
| case PixelFormat::kR16G16B16A16Float: |
| case PixelFormat::kB10G10R10XR: |
| case PixelFormat::kB10G10R10XRSRGB: |
| case PixelFormat::kB10G10R10A10XR: |
| return vk::ImageAspectFlagBits::eColor; |
| case PixelFormat::kS8UInt: |
| return vk::ImageAspectFlagBits::eStencil; |
| case PixelFormat::kD24UnormS8Uint: |
| case PixelFormat::kD32FloatS8UInt: |
| return vk::ImageAspectFlagBits::eDepth | |
| vk::ImageAspectFlagBits::eStencil; |
| } |
| FML_UNREACHABLE(); |
| } |
| |
| constexpr uint32_t ToArrayLayerCount(TextureType type) { |
| switch (type) { |
| case TextureType::kTexture2D: |
| case TextureType::kTexture2DMultisample: |
| return 1u; |
| case TextureType::kTextureCube: |
| return 6u; |
| case TextureType::kTextureExternalOES: |
| VALIDATION_LOG |
| << "kTextureExternalOES can not be used with the Vulkan backend."; |
| } |
| FML_UNREACHABLE(); |
| } |
| |
| constexpr vk::ImageViewType ToVKImageViewType(TextureType type) { |
| switch (type) { |
| case TextureType::kTexture2D: |
| case TextureType::kTexture2DMultisample: |
| return vk::ImageViewType::e2D; |
| case TextureType::kTextureCube: |
| return vk::ImageViewType::eCube; |
| case TextureType::kTextureExternalOES: |
| VALIDATION_LOG |
| << "kTextureExternalOES can not be used with the Vulkan backend."; |
| } |
| FML_UNREACHABLE(); |
| } |
| |
| constexpr vk::ImageCreateFlags ToVKImageCreateFlags(TextureType type) { |
| switch (type) { |
| case TextureType::kTexture2D: |
| case TextureType::kTexture2DMultisample: |
| return {}; |
| case TextureType::kTextureCube: |
| return vk::ImageCreateFlagBits::eCubeCompatible; |
| case TextureType::kTextureExternalOES: |
| VALIDATION_LOG |
| << "kTextureExternalOES can not be used with the Vulkan backend."; |
| } |
| FML_UNREACHABLE(); |
| } |
| |
| vk::PipelineDepthStencilStateCreateInfo ToVKPipelineDepthStencilStateCreateInfo( |
| std::optional<DepthAttachmentDescriptor> depth, |
| std::optional<StencilAttachmentDescriptor> front, |
| std::optional<StencilAttachmentDescriptor> back); |
| |
| constexpr vk::ImageAspectFlags ToImageAspectFlags(PixelFormat format) { |
| switch (format) { |
| case PixelFormat::kUnknown: |
| return {}; |
| case PixelFormat::kA8UNormInt: |
| case PixelFormat::kR8UNormInt: |
| case PixelFormat::kR8G8UNormInt: |
| case PixelFormat::kR8G8B8A8UNormInt: |
| case PixelFormat::kR8G8B8A8UNormIntSRGB: |
| case PixelFormat::kB8G8R8A8UNormInt: |
| case PixelFormat::kB8G8R8A8UNormIntSRGB: |
| case PixelFormat::kR32G32B32A32Float: |
| case PixelFormat::kR16G16B16A16Float: |
| case PixelFormat::kB10G10R10XR: |
| case PixelFormat::kB10G10R10XRSRGB: |
| case PixelFormat::kB10G10R10A10XR: |
| return vk::ImageAspectFlagBits::eColor; |
| case PixelFormat::kS8UInt: |
| return vk::ImageAspectFlagBits::eStencil; |
| case PixelFormat::kD24UnormS8Uint: |
| case PixelFormat::kD32FloatS8UInt: |
| return vk::ImageAspectFlagBits::eDepth | |
| vk::ImageAspectFlagBits::eStencil; |
| } |
| FML_UNREACHABLE(); |
| } |
| |
| } // namespace impeller |
| |
| #endif // FLUTTER_IMPELLER_RENDERER_BACKEND_VULKAN_FORMATS_VK_H_ |