[Impeller] use native decal on metal and Vulkan backend (flutter/engine#40723)

[Impeller] use native decal on metal and Vulkan backend
This commit is contained in:
Jonah Williams 2023-03-30 15:37:55 -07:00 committed by GitHub
parent 0407296be4
commit c44b7c1192
13 changed files with 94 additions and 22 deletions

View File

@ -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 {

View File

@ -214,6 +214,12 @@ std::optional<Entity> 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<Entity> 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);

View File

@ -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<SamplerAddressMode> 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<SamplerAddressMode> 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<Scalar>(x_tile_mode_);
frag_info.y_tile_mode = static_cast<Scalar>(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<Scalar>(x_tile_mode_);
frag_info.y_tile_mode = static_cast<Scalar>(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))) {

View File

@ -53,7 +53,9 @@ class TiledTextureContents final : public ColorSourceContents {
std::optional<std::shared_ptr<Texture>> CreateFilterTexture(
const ContentContext& renderer) const;
SamplerDescriptor CreateDescriptor() const;
SamplerDescriptor CreateDescriptor(const Capabilities& capabilities) const;
bool UsesEmulatedTileMode(const Capabilities& capabilities) const;
std::shared_ptr<Texture> texture_;
SamplerDescriptor sampler_descriptor_ = {};

View File

@ -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();
}

View File

@ -53,6 +53,7 @@ static std::unique_ptr<Capabilities> InferMetalCapabilities(
.SetSupportsOffscreenMSAA(true)
.SetSupportsSSBO(true)
.SetSupportsTextureToTextureBlits(true)
.SetSupportsDecalTileMode(true)
.SetSupportsFramebufferFetch(DeviceSupportsFramebufferFetch(device))
.SetDefaultColorFormat(color_format)
.SetDefaultStencilFormat(PixelFormat::kS8UInt)

View File

@ -349,6 +349,8 @@ constexpr MTLSamplerAddressMode ToMTLSamplerAddressMode(
return MTLSamplerAddressModeRepeat;
case SamplerAddressMode::kMirror:
return MTLSamplerAddressModeMirrorRepeat;
case SamplerAddressMode::kDecal:
return MTLSamplerAddressModeClampToZero;
}
return MTLSamplerAddressModeClampToEdge;
}

View File

@ -338,6 +338,10 @@ bool CapabilitiesVK::SupportsReadFromResolve() const {
return false;
}
bool CapabilitiesVK::SupportsDecalTileMode() const {
return true;
}
// |Capabilities|
PixelFormat CapabilitiesVK::GetDefaultColorFormat() const {
return color_format_;

View File

@ -70,6 +70,9 @@ class CapabilitiesVK final : public Capabilities,
// |Capabilities|
bool SupportsReadFromResolve() const override;
// |Capabilities|
bool SupportsDecalTileMode() const override;
// |Capabilities|
PixelFormat GetDefaultColorFormat() const override;

View File

@ -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();

View File

@ -33,13 +33,15 @@ std::shared_ptr<const Sampler> 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) {

View File

@ -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<Capabilities> CapabilitiesBuilder::Build() {
return std::unique_ptr<StandardCapabilities>(new StandardCapabilities( //
has_threading_restrictions_, //
@ -166,6 +179,7 @@ std::unique_ptr<Capabilities> CapabilitiesBuilder::Build() {
supports_compute_, //
supports_compute_subgroups_, //
supports_read_from_resolve_, //
supports_decal_tile_mode_, //
*default_color_format_, //
*default_stencil_format_ //
));

View File

@ -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<Capabilities> 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<PixelFormat> default_color_format_ = std::nullopt;
std::optional<PixelFormat> default_stencil_format_ = std::nullopt;