From c44b7c119202372eb4e11b3c48e5e011db0ec262 Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Thu, 30 Mar 2023 15:37:55 -0700 Subject: [PATCH] [Impeller] use native decal on metal and Vulkan backend (flutter/engine#40723) [Impeller] use native decal on metal and Vulkan backend --- engine/src/flutter/impeller/core/formats.h | 4 ++ .../filters/gaussian_blur_filter_contents.cc | 10 +++- .../entity/contents/tiled_texture_contents.cc | 49 ++++++++++++++----- .../entity/contents/tiled_texture_contents.h | 4 +- .../renderer/backend/gles/sampler_gles.cc | 2 + .../renderer/backend/metal/context_mtl.mm | 1 + .../renderer/backend/metal/formats_mtl.h | 2 + .../backend/vulkan/capabilities_vk.cc | 4 ++ .../renderer/backend/vulkan/capabilities_vk.h | 3 ++ .../renderer/backend/vulkan/formats_vk.h | 2 + .../backend/vulkan/sampler_library_vk.cc | 16 +++--- .../flutter/impeller/renderer/capabilities.cc | 14 ++++++ .../flutter/impeller/renderer/capabilities.h | 5 ++ 13 files changed, 94 insertions(+), 22 deletions(-) diff --git a/engine/src/flutter/impeller/core/formats.h b/engine/src/flutter/impeller/core/formats.h index cf1aef2c10e..eb58dda9d97 100644 --- a/engine/src/flutter/impeller/core/formats.h +++ b/engine/src/flutter/impeller/core/formats.h @@ -306,6 +306,10 @@ enum class SamplerAddressMode { // More modes are almost always supported but they are usually behind // extensions checks. The ones current in these structs are safe (always // supported) defaults. + + /// @brief decal sampling mode is only supported on devices that pass + /// the Capabilities.SupportsDecalTileMode check. + kDecal, }; enum class ColorWriteMask : uint64_t { diff --git a/engine/src/flutter/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc b/engine/src/flutter/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc index 73f9591c769..e98af38f7ed 100644 --- a/engine/src/flutter/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc +++ b/engine/src/flutter/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc @@ -214,6 +214,12 @@ std::optional DirectionalGaussianBlurFilterContents::RenderFilter( auto source_descriptor = source_snapshot->sampler_descriptor; switch (tile_mode_) { case Entity::TileMode::kDecal: + if (renderer.GetDeviceCapabilities().SupportsDecalTileMode()) { + input_descriptor.width_address_mode = SamplerAddressMode::kDecal; + input_descriptor.height_address_mode = SamplerAddressMode::kDecal; + source_descriptor.width_address_mode = SamplerAddressMode::kDecal; + source_descriptor.height_address_mode = SamplerAddressMode::kDecal; + } break; case Entity::TileMode::kClamp: input_descriptor.width_address_mode = SamplerAddressMode::kClampToEdge; @@ -237,7 +243,9 @@ std::optional DirectionalGaussianBlurFilterContents::RenderFilter( } bool has_alpha_mask = blur_style_ != BlurStyle::kNormal; - bool has_decal_specialization = tile_mode_ == Entity::TileMode::kDecal; + bool has_decal_specialization = + tile_mode_ == Entity::TileMode::kDecal && + !renderer.GetDeviceCapabilities().SupportsDecalTileMode(); if (has_alpha_mask && has_decal_specialization) { cmd.pipeline = renderer.GetGaussianBlurAlphaDecalPipeline(options); diff --git a/engine/src/flutter/impeller/entity/contents/tiled_texture_contents.cc b/engine/src/flutter/impeller/entity/contents/tiled_texture_contents.cc index 90b6b2bf448..a53af0d0b82 100644 --- a/engine/src/flutter/impeller/entity/contents/tiled_texture_contents.cc +++ b/engine/src/flutter/impeller/entity/contents/tiled_texture_contents.cc @@ -7,6 +7,7 @@ #include "impeller/entity/contents/clip_contents.h" #include "impeller/entity/contents/content_context.h" #include "impeller/entity/geometry.h" +#include "impeller/entity/texture_fill.frag.h" #include "impeller/entity/tiled_texture_fill.frag.h" #include "impeller/entity/tiled_texture_fill.vert.h" #include "impeller/geometry/path_builder.h" @@ -16,7 +17,8 @@ namespace impeller { static std::optional TileModeToAddressMode( - Entity::TileMode tile_mode) { + Entity::TileMode tile_mode, + const Capabilities& capabilities) { switch (tile_mode) { case Entity::TileMode::kClamp: return SamplerAddressMode::kClampToEdge; @@ -28,6 +30,9 @@ static std::optional TileModeToAddressMode( return SamplerAddressMode::kRepeat; break; case Entity::TileMode::kDecal: + if (capabilities.SupportsDecalTileMode()) { + return SamplerAddressMode::kDecal; + } return std::nullopt; } } @@ -67,10 +72,11 @@ TiledTextureContents::CreateFilterTexture( return std::nullopt; } -SamplerDescriptor TiledTextureContents::CreateDescriptor() const { +SamplerDescriptor TiledTextureContents::CreateDescriptor( + const Capabilities& capabilities) const { SamplerDescriptor descriptor = sampler_descriptor_; - auto width_mode = TileModeToAddressMode(x_tile_mode_); - auto height_mode = TileModeToAddressMode(y_tile_mode_); + auto width_mode = TileModeToAddressMode(x_tile_mode_, capabilities); + auto height_mode = TileModeToAddressMode(y_tile_mode_, capabilities); if (width_mode.has_value()) { descriptor.width_address_mode = width_mode.value(); } @@ -80,6 +86,12 @@ SamplerDescriptor TiledTextureContents::CreateDescriptor() const { return descriptor; } +bool TiledTextureContents::UsesEmulatedTileMode( + const Capabilities& capabilities) const { + return TileModeToAddressMode(x_tile_mode_, capabilities).has_value() && + TileModeToAddressMode(y_tile_mode_, capabilities).has_value(); +} + bool TiledTextureContents::Render(const ContentContext& renderer, const Entity& entity, RenderPass& pass) const { @@ -101,16 +113,13 @@ bool TiledTextureContents::Render(const ContentContext& renderer, auto geometry_result = GetGeometry()->GetPositionUVBuffer( Rect(bounds_origin, Size(texture_size)), GetInverseMatrix(), renderer, entity, pass); + bool uses_emulated_tile_mode = + UsesEmulatedTileMode(renderer.GetDeviceCapabilities()); VS::FrameInfo frame_info; frame_info.mvp = geometry_result.transform; frame_info.texture_sampler_y_coord_scale = texture_->GetYCoordScale(); - FS::FragInfo frag_info; - frag_info.x_tile_mode = static_cast(x_tile_mode_); - frag_info.y_tile_mode = static_cast(y_tile_mode_); - frag_info.alpha = GetOpacity(); - Command cmd; cmd.label = "TiledTextureFill"; cmd.stencil_reference = entity.GetStencilDepth(); @@ -121,11 +130,25 @@ bool TiledTextureContents::Render(const ContentContext& renderer, options.stencil_operation = StencilOperation::kIncrementClamp; } options.primitive_type = geometry_result.type; - cmd.pipeline = renderer.GetTiledTexturePipeline(options); + cmd.pipeline = uses_emulated_tile_mode + ? renderer.GetTiledTexturePipeline(options) + : renderer.GetTexturePipeline(options); cmd.BindVertices(geometry_result.vertex_buffer); VS::BindFrameInfo(cmd, host_buffer.EmplaceUniform(frame_info)); - FS::BindFragInfo(cmd, host_buffer.EmplaceUniform(frag_info)); + + if (uses_emulated_tile_mode) { + FS::FragInfo frag_info; + frag_info.x_tile_mode = static_cast(x_tile_mode_); + frag_info.y_tile_mode = static_cast(y_tile_mode_); + frag_info.alpha = GetOpacity(); + FS::BindFragInfo(cmd, host_buffer.EmplaceUniform(frag_info)); + } else { + TextureFillFragmentShader::FragInfo frag_info; + frag_info.alpha = GetOpacity(); + TextureFillFragmentShader::BindFragInfo( + cmd, host_buffer.EmplaceUniform(frag_info)); + } if (color_filter_.has_value()) { auto filtered_texture = CreateFilterTexture(renderer); @@ -135,12 +158,12 @@ bool TiledTextureContents::Render(const ContentContext& renderer, FS::BindTextureSampler( cmd, filtered_texture.value(), renderer.GetContext()->GetSamplerLibrary()->GetSampler( - CreateDescriptor())); + CreateDescriptor(renderer.GetDeviceCapabilities()))); } else { FS::BindTextureSampler( cmd, texture_, renderer.GetContext()->GetSamplerLibrary()->GetSampler( - CreateDescriptor())); + CreateDescriptor(renderer.GetDeviceCapabilities()))); } if (!pass.AddCommand(std::move(cmd))) { diff --git a/engine/src/flutter/impeller/entity/contents/tiled_texture_contents.h b/engine/src/flutter/impeller/entity/contents/tiled_texture_contents.h index 953d5f6c10c..9aa7755d904 100644 --- a/engine/src/flutter/impeller/entity/contents/tiled_texture_contents.h +++ b/engine/src/flutter/impeller/entity/contents/tiled_texture_contents.h @@ -53,7 +53,9 @@ class TiledTextureContents final : public ColorSourceContents { std::optional> CreateFilterTexture( const ContentContext& renderer) const; - SamplerDescriptor CreateDescriptor() const; + SamplerDescriptor CreateDescriptor(const Capabilities& capabilities) const; + + bool UsesEmulatedTileMode(const Capabilities& capabilities) const; std::shared_ptr texture_; SamplerDescriptor sampler_descriptor_ = {}; diff --git a/engine/src/flutter/impeller/renderer/backend/gles/sampler_gles.cc b/engine/src/flutter/impeller/renderer/backend/gles/sampler_gles.cc index c96ff1700a0..f1a54debcbc 100644 --- a/engine/src/flutter/impeller/renderer/backend/gles/sampler_gles.cc +++ b/engine/src/flutter/impeller/renderer/backend/gles/sampler_gles.cc @@ -61,6 +61,8 @@ static GLint ToAddressMode(SamplerAddressMode mode) { return GL_REPEAT; case SamplerAddressMode::kMirror: return GL_MIRRORED_REPEAT; + case SamplerAddressMode::kDecal: + break; // Unsupported. } FML_UNREACHABLE(); } diff --git a/engine/src/flutter/impeller/renderer/backend/metal/context_mtl.mm b/engine/src/flutter/impeller/renderer/backend/metal/context_mtl.mm index 9bee27963f7..c8b52eebb6d 100644 --- a/engine/src/flutter/impeller/renderer/backend/metal/context_mtl.mm +++ b/engine/src/flutter/impeller/renderer/backend/metal/context_mtl.mm @@ -53,6 +53,7 @@ static std::unique_ptr InferMetalCapabilities( .SetSupportsOffscreenMSAA(true) .SetSupportsSSBO(true) .SetSupportsTextureToTextureBlits(true) + .SetSupportsDecalTileMode(true) .SetSupportsFramebufferFetch(DeviceSupportsFramebufferFetch(device)) .SetDefaultColorFormat(color_format) .SetDefaultStencilFormat(PixelFormat::kS8UInt) diff --git a/engine/src/flutter/impeller/renderer/backend/metal/formats_mtl.h b/engine/src/flutter/impeller/renderer/backend/metal/formats_mtl.h index 566f7eeb877..5b06094e21f 100644 --- a/engine/src/flutter/impeller/renderer/backend/metal/formats_mtl.h +++ b/engine/src/flutter/impeller/renderer/backend/metal/formats_mtl.h @@ -349,6 +349,8 @@ constexpr MTLSamplerAddressMode ToMTLSamplerAddressMode( return MTLSamplerAddressModeRepeat; case SamplerAddressMode::kMirror: return MTLSamplerAddressModeMirrorRepeat; + case SamplerAddressMode::kDecal: + return MTLSamplerAddressModeClampToZero; } return MTLSamplerAddressModeClampToEdge; } diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/capabilities_vk.cc b/engine/src/flutter/impeller/renderer/backend/vulkan/capabilities_vk.cc index 45e6a4cb246..7071f012d9f 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/capabilities_vk.cc +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/capabilities_vk.cc @@ -338,6 +338,10 @@ bool CapabilitiesVK::SupportsReadFromResolve() const { return false; } +bool CapabilitiesVK::SupportsDecalTileMode() const { + return true; +} + // |Capabilities| PixelFormat CapabilitiesVK::GetDefaultColorFormat() const { return color_format_; diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/capabilities_vk.h b/engine/src/flutter/impeller/renderer/backend/vulkan/capabilities_vk.h index a2b46e5c77c..dc23d432075 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/capabilities_vk.h +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/capabilities_vk.h @@ -70,6 +70,9 @@ class CapabilitiesVK final : public Capabilities, // |Capabilities| bool SupportsReadFromResolve() const override; + // |Capabilities| + bool SupportsDecalTileMode() const override; + // |Capabilities| PixelFormat GetDefaultColorFormat() const override; diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/formats_vk.h b/engine/src/flutter/impeller/renderer/backend/vulkan/formats_vk.h index f11887a48c3..16931d4132d 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/formats_vk.h +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/formats_vk.h @@ -240,6 +240,8 @@ constexpr vk::SamplerAddressMode ToVKSamplerAddressMode( return vk::SamplerAddressMode::eMirroredRepeat; case SamplerAddressMode::kClampToEdge: return vk::SamplerAddressMode::eClampToEdge; + case SamplerAddressMode::kDecal: + return vk::SamplerAddressMode::eClampToBorder; } FML_UNREACHABLE(); diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/sampler_library_vk.cc b/engine/src/flutter/impeller/renderer/backend/vulkan/sampler_library_vk.cc index b62549eb88a..8d4c82e39cc 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/sampler_library_vk.cc +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/sampler_library_vk.cc @@ -33,13 +33,15 @@ std::shared_ptr SamplerLibraryVK::GetSampler( const auto address_mode_v = ToVKSamplerAddressMode(desc.height_address_mode); const auto address_mode_w = ToVKSamplerAddressMode(desc.depth_address_mode); - const auto sampler_create_info = vk::SamplerCreateInfo() - .setMagFilter(mag_filter) - .setMinFilter(min_filter) - .setAddressModeU(address_mode_u) - .setAddressModeV(address_mode_v) - .setAddressModeW(address_mode_w) - .setMipmapMode(mip_map); + const auto sampler_create_info = + vk::SamplerCreateInfo() + .setMagFilter(mag_filter) + .setMinFilter(min_filter) + .setAddressModeU(address_mode_u) + .setAddressModeV(address_mode_v) + .setAddressModeW(address_mode_w) + .setBorderColor(vk::BorderColor::eFloatTransparentBlack) + .setMipmapMode(mip_map); auto res = device_.createSamplerUnique(sampler_create_info); if (res.result != vk::Result::eSuccess) { diff --git a/engine/src/flutter/impeller/renderer/capabilities.cc b/engine/src/flutter/impeller/renderer/capabilities.cc index f89482ea871..77b082b8f3c 100644 --- a/engine/src/flutter/impeller/renderer/capabilities.cc +++ b/engine/src/flutter/impeller/renderer/capabilities.cc @@ -51,6 +51,11 @@ class StandardCapabilities final : public Capabilities { return supports_read_from_resolve_; } + // |Capabilities| + bool SupportsDecalTileMode() const override { + return supports_decal_tile_mode_; + } + // |Capabilities| PixelFormat GetDefaultColorFormat() const override { return default_color_format_; @@ -70,6 +75,7 @@ class StandardCapabilities final : public Capabilities { bool supports_compute, bool supports_compute_subgroups, bool supports_read_from_resolve, + bool supports_decal_tile_mode, PixelFormat default_color_format, PixelFormat default_stencil_format) : has_threading_restrictions_(has_threading_restrictions), @@ -80,6 +86,7 @@ class StandardCapabilities final : public Capabilities { supports_compute_(supports_compute), supports_compute_subgroups_(supports_compute_subgroups), supports_read_from_resolve_(supports_read_from_resolve), + supports_decal_tile_mode_(supports_decal_tile_mode), default_color_format_(default_color_format), default_stencil_format_(default_stencil_format) {} @@ -93,6 +100,7 @@ class StandardCapabilities final : public Capabilities { bool supports_compute_ = false; bool supports_compute_subgroups_ = false; bool supports_read_from_resolve_ = false; + bool supports_decal_tile_mode_ = false; PixelFormat default_color_format_ = PixelFormat::kUnknown; PixelFormat default_stencil_format_ = PixelFormat::kUnknown; @@ -156,6 +164,11 @@ CapabilitiesBuilder& CapabilitiesBuilder::SetDefaultStencilFormat( return *this; } +CapabilitiesBuilder& CapabilitiesBuilder::SetSupportsDecalTileMode(bool value) { + supports_decal_tile_mode_ = value; + return *this; +} + std::unique_ptr CapabilitiesBuilder::Build() { return std::unique_ptr(new StandardCapabilities( // has_threading_restrictions_, // @@ -166,6 +179,7 @@ std::unique_ptr CapabilitiesBuilder::Build() { supports_compute_, // supports_compute_subgroups_, // supports_read_from_resolve_, // + supports_decal_tile_mode_, // *default_color_format_, // *default_stencil_format_ // )); diff --git a/engine/src/flutter/impeller/renderer/capabilities.h b/engine/src/flutter/impeller/renderer/capabilities.h index cac369087a3..c66fd27b20c 100644 --- a/engine/src/flutter/impeller/renderer/capabilities.h +++ b/engine/src/flutter/impeller/renderer/capabilities.h @@ -31,6 +31,8 @@ class Capabilities { virtual bool SupportsReadFromResolve() const = 0; + virtual bool SupportsDecalTileMode() const = 0; + virtual PixelFormat GetDefaultColorFormat() const = 0; virtual PixelFormat GetDefaultStencilFormat() const = 0; @@ -65,6 +67,8 @@ class CapabilitiesBuilder { CapabilitiesBuilder& SetDefaultStencilFormat(PixelFormat value); + CapabilitiesBuilder& SetSupportsDecalTileMode(bool value); + std::unique_ptr Build(); private: @@ -76,6 +80,7 @@ class CapabilitiesBuilder { bool supports_compute_ = false; bool supports_compute_subgroups_ = false; bool supports_read_from_resolve_ = false; + bool supports_decal_tile_mode_ = false; std::optional default_color_format_ = std::nullopt; std::optional default_stencil_format_ = std::nullopt;