blob: 2dcdc09165ef75e7d41deb2130a92f2bcc44325d [file] [log] [blame]
// 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.
#include "impeller/entity/contents/content_context.h"
#include <format>
#include <memory>
#include <utility>
#include "fml/trace_event.h"
#include "impeller/base/validation.h"
#include "impeller/core/formats.h"
#include "impeller/core/texture_descriptor.h"
#include "impeller/entity/contents/framebuffer_blend_contents.h"
#include "impeller/entity/contents/pipelines.h"
#include "impeller/entity/contents/text_shadow_cache.h"
#include "impeller/entity/entity.h"
#include "impeller/entity/render_target_cache.h"
#include "impeller/renderer/command_buffer.h"
#include "impeller/renderer/pipeline.h"
#include "impeller/renderer/pipeline_descriptor.h"
#include "impeller/renderer/pipeline_library.h"
#include "impeller/renderer/render_target.h"
#include "impeller/renderer/texture_util.h"
#include "impeller/tessellator/tessellator.h"
#include "impeller/typographer/typographer_context.h"
namespace impeller {
namespace {
/// A generic version of `Variants` which mostly exists to reduce code size.
class GenericVariants {
public:
void Set(const ContentContextOptions& options,
std::unique_ptr<GenericRenderPipelineHandle> pipeline) {
uint64_t p_key = options.ToKey();
for (const auto& [key, pipeline] : pipelines_) {
if (key == p_key) {
return;
}
}
pipelines_.push_back(std::make_pair(p_key, std::move(pipeline)));
}
void SetDefault(const ContentContextOptions& options,
std::unique_ptr<GenericRenderPipelineHandle> pipeline) {
default_options_ = options;
if (pipeline) {
Set(options, std::move(pipeline));
}
}
GenericRenderPipelineHandle* Get(const ContentContextOptions& options) const {
uint64_t p_key = options.ToKey();
for (const auto& [key, pipeline] : pipelines_) {
if (key == p_key) {
return pipeline.get();
}
}
return nullptr;
}
void SetDefaultDescriptor(std::optional<PipelineDescriptor> desc) {
desc_ = std::move(desc);
}
size_t GetPipelineCount() const { return pipelines_.size(); }
bool IsDefault(const ContentContextOptions& opts) {
return default_options_.has_value() &&
opts.ToKey() == default_options_.value().ToKey();
}
protected:
std::optional<PipelineDescriptor> desc_;
std::optional<ContentContextOptions> default_options_;
std::vector<std::pair<uint64_t, std::unique_ptr<GenericRenderPipelineHandle>>>
pipelines_;
};
/// Holds multiple Pipelines associated with the same PipelineHandle types.
///
/// For example, it may have multiple
/// RenderPipelineHandle<SolidFillVertexShader, SolidFillFragmentShader>
/// instances for different blend modes. From them you can access the
/// Pipeline.
///
/// See also:
/// - impeller::ContentContextOptions - options from which variants are
/// created.
/// - impeller::Pipeline::CreateVariant
/// - impeller::RenderPipelineHandle<> - The type of objects this typically
/// contains.
template <class PipelineHandleT>
class Variants : public GenericVariants {
static_assert(
ShaderStageCompatibilityChecker<
typename PipelineHandleT::VertexShader,
typename PipelineHandleT::FragmentShader>::Check(),
"The output slots for the fragment shader don't have matches in the "
"vertex shader's output slots. This will result in a linker error.");
public:
Variants() = default;
void Set(const ContentContextOptions& options,
std::unique_ptr<PipelineHandleT> pipeline) {
GenericVariants::Set(options, std::move(pipeline));
}
void SetDefault(const ContentContextOptions& options,
std::unique_ptr<PipelineHandleT> pipeline) {
GenericVariants::SetDefault(options, std::move(pipeline));
}
void CreateDefault(const Context& context,
const ContentContextOptions& options,
const std::vector<Scalar>& constants = {}) {
std::optional<PipelineDescriptor> desc =
PipelineHandleT::Builder::MakeDefaultPipelineDescriptor(context,
constants);
if (!desc.has_value()) {
VALIDATION_LOG << "Failed to create default pipeline.";
return;
}
context.GetPipelineLibrary()->LogPipelineCreation(*desc);
options.ApplyToPipelineDescriptor(*desc);
desc_ = desc;
SetDefault(options, std::make_unique<PipelineHandleT>(context, desc_,
/*async=*/true));
}
PipelineHandleT* Get(const ContentContextOptions& options) const {
return static_cast<PipelineHandleT*>(GenericVariants::Get(options));
}
PipelineHandleT* GetDefault(const Context& context) {
if (!default_options_.has_value()) {
return nullptr;
}
PipelineHandleT* result = Get(default_options_.value());
if (result != nullptr) {
return result;
}
SetDefault(default_options_.value(), std::make_unique<PipelineHandleT>(
context, desc_, /*async=*/false));
// NOLINTNEXTLINE(bugprone-unchecked-optional-access)
return Get(default_options_.value());
}
private:
Variants(const Variants&) = delete;
Variants& operator=(const Variants&) = delete;
};
template <class RenderPipelineHandleT>
RenderPipelineHandleT* CreateIfNeeded(
const ContentContext* context,
Variants<RenderPipelineHandleT>& container,
ContentContextOptions opts,
PipelineCompileQueue* compile_queue) {
if (!context->IsValid()) {
return nullptr;
}
if (RenderPipelineHandleT* found = container.Get(opts)) {
return found;
}
RenderPipelineHandleT* default_handle =
container.GetDefault(*context->GetContext());
if (container.IsDefault(opts)) {
return default_handle;
}
// The default must always be initialized in the constructor.
FML_CHECK(default_handle != nullptr);
const std::shared_ptr<Pipeline<PipelineDescriptor>>& pipeline =
default_handle->WaitAndGet(compile_queue);
if (!pipeline) {
return nullptr;
}
auto variant_future = pipeline->CreateVariant(
/*async=*/false, [&opts, variants_count = container.GetPipelineCount()](
PipelineDescriptor& desc) {
opts.ApplyToPipelineDescriptor(desc);
desc.SetLabel(std::format("{} V#{}", desc.GetLabel(), variants_count));
});
std::unique_ptr<RenderPipelineHandleT> variant =
std::make_unique<RenderPipelineHandleT>(std::move(variant_future));
container.Set(opts, std::move(variant));
return container.Get(opts);
}
template <class TypedPipeline>
PipelineRef GetPipeline(const ContentContext* context,
Variants<TypedPipeline>& container,
ContentContextOptions opts) {
auto compile_queue =
context->GetContext()->GetPipelineLibrary()->GetPipelineCompileQueue();
TypedPipeline* pipeline =
CreateIfNeeded(context, container, opts, compile_queue);
if (!pipeline) {
return raw_ptr<Pipeline<PipelineDescriptor>>();
}
return raw_ptr(pipeline->WaitAndGet(compile_queue));
}
} // namespace
struct ContentContext::Pipelines {
// clang-format off
Variants<BlendColorBurnPipeline> blend_colorburn;
Variants<BlendColorDodgePipeline> blend_colordodge;
Variants<BlendColorPipeline> blend_color;
Variants<BlendDarkenPipeline> blend_darken;
Variants<BlendDifferencePipeline> blend_difference;
Variants<BlendExclusionPipeline> blend_exclusion;
Variants<BlendHardLightPipeline> blend_hardlight;
Variants<BlendHuePipeline> blend_hue;
Variants<BlendLightenPipeline> blend_lighten;
Variants<BlendLuminosityPipeline> blend_luminosity;
Variants<BlendMultiplyPipeline> blend_multiply;
Variants<BlendOverlayPipeline> blend_overlay;
Variants<BlendSaturationPipeline> blend_saturation;
Variants<BlendScreenPipeline> blend_screen;
Variants<BlendSoftLightPipeline> blend_softlight;
Variants<BorderMaskBlurPipeline> border_mask_blur;
Variants<CirclePipeline> circle;
Variants<ClipPipeline> clip;
Variants<ColorMatrixColorFilterPipeline> color_matrix_color_filter;
Variants<ConicalGradientFillConicalPipeline> conical_gradient_fill;
Variants<ConicalGradientFillRadialPipeline> conical_gradient_fill_radial;
Variants<ConicalGradientFillStripPipeline> conical_gradient_fill_strip;
Variants<ConicalGradientFillStripRadialPipeline> conical_gradient_fill_strip_and_radial;
Variants<ConicalGradientSSBOFillPipeline> conical_gradient_ssbo_fill;
Variants<ConicalGradientSSBOFillPipeline> conical_gradient_ssbo_fill_radial;
Variants<ConicalGradientSSBOFillPipeline> conical_gradient_ssbo_fill_strip_and_radial;
Variants<ConicalGradientSSBOFillPipeline> conical_gradient_ssbo_fill_strip;
Variants<ConicalGradientUniformFillConicalPipeline> conical_gradient_uniform_fill;
Variants<ConicalGradientUniformFillRadialPipeline> conical_gradient_uniform_fill_radial;
Variants<ConicalGradientUniformFillStripPipeline> conical_gradient_uniform_fill_strip;
Variants<ConicalGradientUniformFillStripRadialPipeline> conical_gradient_uniform_fill_strip_and_radial;
Variants<FastGradientPipeline> fast_gradient;
Variants<FramebufferBlendColorBurnPipeline> framebuffer_blend_colorburn;
Variants<FramebufferBlendColorDodgePipeline> framebuffer_blend_colordodge;
Variants<FramebufferBlendColorPipeline> framebuffer_blend_color;
Variants<FramebufferBlendDarkenPipeline> framebuffer_blend_darken;
Variants<FramebufferBlendDifferencePipeline> framebuffer_blend_difference;
Variants<FramebufferBlendExclusionPipeline> framebuffer_blend_exclusion;
Variants<FramebufferBlendHardLightPipeline> framebuffer_blend_hardlight;
Variants<FramebufferBlendHuePipeline> framebuffer_blend_hue;
Variants<FramebufferBlendLightenPipeline> framebuffer_blend_lighten;
Variants<FramebufferBlendLuminosityPipeline> framebuffer_blend_luminosity;
Variants<FramebufferBlendMultiplyPipeline> framebuffer_blend_multiply;
Variants<FramebufferBlendOverlayPipeline> framebuffer_blend_overlay;
Variants<FramebufferBlendSaturationPipeline> framebuffer_blend_saturation;
Variants<FramebufferBlendScreenPipeline> framebuffer_blend_screen;
Variants<FramebufferBlendSoftLightPipeline> framebuffer_blend_softlight;
Variants<GaussianBlurPipeline> gaussian_blur;
Variants<GlyphAtlasPipeline> glyph_atlas;
Variants<LinePipeline> line;
Variants<LinearGradientFillPipeline> linear_gradient_fill;
Variants<LinearGradientSSBOFillPipeline> linear_gradient_ssbo_fill;
Variants<LinearGradientUniformFillPipeline> linear_gradient_uniform_fill;
Variants<LinearToSrgbFilterPipeline> linear_to_srgb_filter;
Variants<MorphologyFilterPipeline> morphology_filter;
Variants<PorterDuffBlendPipeline> clear_blend;
Variants<PorterDuffBlendPipeline> destination_a_top_blend;
Variants<PorterDuffBlendPipeline> destination_blend;
Variants<PorterDuffBlendPipeline> destination_in_blend;
Variants<PorterDuffBlendPipeline> destination_out_blend;
Variants<PorterDuffBlendPipeline> destination_over_blend;
Variants<PorterDuffBlendPipeline> modulate_blend;
Variants<PorterDuffBlendPipeline> plus_blend;
Variants<PorterDuffBlendPipeline> screen_blend;
Variants<PorterDuffBlendPipeline> source_a_top_blend;
Variants<PorterDuffBlendPipeline> source_blend;
Variants<PorterDuffBlendPipeline> source_in_blend;
Variants<PorterDuffBlendPipeline> source_out_blend;
Variants<PorterDuffBlendPipeline> source_over_blend;
Variants<PorterDuffBlendPipeline> xor_blend;
Variants<RadialGradientFillPipeline> radial_gradient_fill;
Variants<RadialGradientSSBOFillPipeline> radial_gradient_ssbo_fill;
Variants<RadialGradientUniformFillPipeline> radial_gradient_uniform_fill;
Variants<RRectBlurPipeline> rrect_blur;
Variants<RSuperellipseBlurPipeline> rsuperellipse_blur;
Variants<ShadowVerticesShader> shadow_vertices_;
Variants<SolidFillPipeline> solid_fill;
Variants<SrgbToLinearFilterPipeline> srgb_to_linear_filter;
Variants<SweepGradientFillPipeline> sweep_gradient_fill;
Variants<SweepGradientSSBOFillPipeline> sweep_gradient_ssbo_fill;
Variants<SweepGradientUniformFillPipeline> sweep_gradient_uniform_fill;
Variants<TextureDownsamplePipeline> texture_downsample;
Variants<TextureDownsampleBoundedPipeline> texture_downsample_bounded;
Variants<TexturePipeline> texture;
Variants<TextureStrictSrcPipeline> texture_strict_src;
Variants<TiledTexturePipeline> tiled_texture;
Variants<VerticesUber1Shader> vertices_uber_1_;
Variants<VerticesUber2Shader> vertices_uber_2_;
Variants<YUVToRGBFilterPipeline> yuv_to_rgb_filter;
// Web doesn't support external texture OpenGL extensions
#if defined(IMPELLER_ENABLE_OPENGLES) && !defined(FML_OS_EMSCRIPTEN)
Variants<TiledTextureExternalPipeline> tiled_texture_external;
Variants<TiledTextureUvExternalPipeline> tiled_texture_uv_external;
#endif
#if defined(IMPELLER_ENABLE_OPENGLES)
Variants<TextureDownsampleGlesPipeline> texture_downsample_gles;
#endif // IMPELLER_ENABLE_OPENGLES
// clang-format on
};
void ContentContextOptions::ApplyToPipelineDescriptor(
PipelineDescriptor& desc) const {
auto pipeline_blend = blend_mode;
if (blend_mode > Entity::kLastPipelineBlendMode) {
VALIDATION_LOG << "Cannot use blend mode " << static_cast<int>(blend_mode)
<< " as a pipeline blend.";
pipeline_blend = BlendMode::kSrcOver;
}
desc.SetSampleCount(sample_count);
ColorAttachmentDescriptor color0 = *desc.GetColorAttachmentDescriptor(0u);
color0.format = color_attachment_pixel_format;
color0.alpha_blend_op = BlendOperation::kAdd;
color0.color_blend_op = BlendOperation::kAdd;
color0.write_mask = ColorWriteMaskBits::kAll;
switch (pipeline_blend) {
case BlendMode::kClear:
if (is_for_rrect_blur_clear) {
color0.alpha_blend_op = BlendOperation::kReverseSubtract;
color0.color_blend_op = BlendOperation::kReverseSubtract;
color0.dst_alpha_blend_factor = BlendFactor::kOne;
color0.dst_color_blend_factor = BlendFactor::kOne;
color0.src_alpha_blend_factor = BlendFactor::kDestinationColor;
color0.src_color_blend_factor = BlendFactor::kDestinationColor;
} else {
color0.dst_alpha_blend_factor = BlendFactor::kZero;
color0.dst_color_blend_factor = BlendFactor::kZero;
color0.src_alpha_blend_factor = BlendFactor::kZero;
color0.src_color_blend_factor = BlendFactor::kZero;
}
break;
case BlendMode::kSrc:
color0.blending_enabled = false;
color0.dst_alpha_blend_factor = BlendFactor::kZero;
color0.dst_color_blend_factor = BlendFactor::kZero;
color0.src_alpha_blend_factor = BlendFactor::kOne;
color0.src_color_blend_factor = BlendFactor::kOne;
break;
case BlendMode::kDst:
color0.dst_alpha_blend_factor = BlendFactor::kOne;
color0.dst_color_blend_factor = BlendFactor::kOne;
color0.src_alpha_blend_factor = BlendFactor::kZero;
color0.src_color_blend_factor = BlendFactor::kZero;
color0.write_mask = ColorWriteMaskBits::kNone;
break;
case BlendMode::kSrcOver:
color0.dst_alpha_blend_factor = BlendFactor::kOneMinusSourceAlpha;
color0.dst_color_blend_factor = BlendFactor::kOneMinusSourceAlpha;
color0.src_alpha_blend_factor = BlendFactor::kOne;
color0.src_color_blend_factor = BlendFactor::kOne;
break;
case BlendMode::kDstOver:
color0.dst_alpha_blend_factor = BlendFactor::kOne;
color0.dst_color_blend_factor = BlendFactor::kOne;
color0.src_alpha_blend_factor = BlendFactor::kOneMinusDestinationAlpha;
color0.src_color_blend_factor = BlendFactor::kOneMinusDestinationAlpha;
break;
case BlendMode::kSrcIn:
color0.dst_alpha_blend_factor = BlendFactor::kZero;
color0.dst_color_blend_factor = BlendFactor::kZero;
color0.src_alpha_blend_factor = BlendFactor::kDestinationAlpha;
color0.src_color_blend_factor = BlendFactor::kDestinationAlpha;
break;
case BlendMode::kDstIn:
color0.dst_alpha_blend_factor = BlendFactor::kSourceAlpha;
color0.dst_color_blend_factor = BlendFactor::kSourceAlpha;
color0.src_alpha_blend_factor = BlendFactor::kZero;
color0.src_color_blend_factor = BlendFactor::kZero;
break;
case BlendMode::kSrcOut:
color0.dst_alpha_blend_factor = BlendFactor::kZero;
color0.dst_color_blend_factor = BlendFactor::kZero;
color0.src_alpha_blend_factor = BlendFactor::kOneMinusDestinationAlpha;
color0.src_color_blend_factor = BlendFactor::kOneMinusDestinationAlpha;
break;
case BlendMode::kDstOut:
color0.dst_alpha_blend_factor = BlendFactor::kOneMinusSourceAlpha;
color0.dst_color_blend_factor = BlendFactor::kOneMinusSourceAlpha;
color0.src_alpha_blend_factor = BlendFactor::kZero;
color0.src_color_blend_factor = BlendFactor::kZero;
break;
case BlendMode::kSrcATop:
color0.dst_alpha_blend_factor = BlendFactor::kOneMinusSourceAlpha;
color0.dst_color_blend_factor = BlendFactor::kOneMinusSourceAlpha;
color0.src_alpha_blend_factor = BlendFactor::kDestinationAlpha;
color0.src_color_blend_factor = BlendFactor::kDestinationAlpha;
break;
case BlendMode::kDstATop:
color0.dst_alpha_blend_factor = BlendFactor::kSourceAlpha;
color0.dst_color_blend_factor = BlendFactor::kSourceAlpha;
color0.src_alpha_blend_factor = BlendFactor::kOneMinusDestinationAlpha;
color0.src_color_blend_factor = BlendFactor::kOneMinusDestinationAlpha;
break;
case BlendMode::kXor:
color0.dst_alpha_blend_factor = BlendFactor::kOneMinusSourceAlpha;
color0.dst_color_blend_factor = BlendFactor::kOneMinusSourceAlpha;
color0.src_alpha_blend_factor = BlendFactor::kOneMinusDestinationAlpha;
color0.src_color_blend_factor = BlendFactor::kOneMinusDestinationAlpha;
break;
case BlendMode::kPlus:
color0.dst_alpha_blend_factor = BlendFactor::kOne;
color0.dst_color_blend_factor = BlendFactor::kOne;
color0.src_alpha_blend_factor = BlendFactor::kOne;
color0.src_color_blend_factor = BlendFactor::kOne;
break;
case BlendMode::kModulate:
color0.dst_alpha_blend_factor = BlendFactor::kSourceAlpha;
color0.dst_color_blend_factor = BlendFactor::kSourceColor;
color0.src_alpha_blend_factor = BlendFactor::kZero;
color0.src_color_blend_factor = BlendFactor::kZero;
break;
default:
FML_UNREACHABLE();
}
desc.SetColorAttachmentDescriptor(0u, color0);
if (!has_depth_stencil_attachments) {
desc.ClearDepthAttachment();
desc.ClearStencilAttachments();
}
auto maybe_stencil = desc.GetFrontStencilAttachmentDescriptor();
auto maybe_depth = desc.GetDepthStencilAttachmentDescriptor();
FML_DCHECK(has_depth_stencil_attachments == maybe_depth.has_value())
<< "Depth attachment doesn't match expected pipeline state. "
"has_depth_stencil_attachments="
<< has_depth_stencil_attachments;
FML_DCHECK(has_depth_stencil_attachments == maybe_stencil.has_value())
<< "Stencil attachment doesn't match expected pipeline state. "
"has_depth_stencil_attachments="
<< has_depth_stencil_attachments;
if (maybe_stencil.has_value()) {
StencilAttachmentDescriptor front_stencil = maybe_stencil.value();
StencilAttachmentDescriptor back_stencil = front_stencil;
switch (stencil_mode) {
case StencilMode::kIgnore:
front_stencil.stencil_compare = CompareFunction::kAlways;
front_stencil.depth_stencil_pass = StencilOperation::kKeep;
desc.SetStencilAttachmentDescriptors(front_stencil);
break;
case StencilMode::kStencilNonZeroFill:
// The stencil ref should be 0 on commands that use this mode.
front_stencil.stencil_compare = CompareFunction::kAlways;
front_stencil.depth_stencil_pass = StencilOperation::kIncrementWrap;
back_stencil.stencil_compare = CompareFunction::kAlways;
back_stencil.depth_stencil_pass = StencilOperation::kDecrementWrap;
desc.SetStencilAttachmentDescriptors(front_stencil, back_stencil);
break;
case StencilMode::kStencilEvenOddFill:
// The stencil ref should be 0 on commands that use this mode.
front_stencil.stencil_compare = CompareFunction::kEqual;
front_stencil.depth_stencil_pass = StencilOperation::kIncrementWrap;
front_stencil.stencil_failure = StencilOperation::kDecrementWrap;
desc.SetStencilAttachmentDescriptors(front_stencil);
break;
case StencilMode::kStencilIncrementAll:
// The stencil ref should be 0 on commands that use this mode.
front_stencil.stencil_compare = CompareFunction::kEqual;
front_stencil.depth_stencil_pass = StencilOperation::kIncrementWrap;
desc.SetStencilAttachmentDescriptors(front_stencil);
break;
case StencilMode::kCoverCompare:
// The stencil ref should be 0 on commands that use this mode.
front_stencil.stencil_compare = CompareFunction::kNotEqual;
front_stencil.depth_stencil_pass =
StencilOperation::kSetToReferenceValue;
desc.SetStencilAttachmentDescriptors(front_stencil);
break;
case StencilMode::kCoverCompareInverted:
// The stencil ref should be 0 on commands that use this mode.
front_stencil.stencil_compare = CompareFunction::kEqual;
front_stencil.stencil_failure = StencilOperation::kSetToReferenceValue;
desc.SetStencilAttachmentDescriptors(front_stencil);
break;
}
}
if (maybe_depth.has_value()) {
DepthAttachmentDescriptor depth = maybe_depth.value();
depth.depth_write_enabled = depth_write_enabled;
depth.depth_compare = depth_compare;
desc.SetDepthStencilAttachmentDescriptor(depth);
}
desc.SetPrimitiveType(primitive_type);
desc.SetPolygonMode(PolygonMode::kFill);
}
std::array<std::vector<Scalar>, 15> GetPorterDuffSpecConstants(
bool supports_decal) {
Scalar x = supports_decal ? 1 : 0;
return {{
{x, 0, 0, 0, 0, 0}, // Clear
{x, 1, 0, 0, 0, 0}, // Source
{x, 0, 0, 1, 0, 0}, // Destination
{x, 1, 0, 1, -1, 0}, // SourceOver
{x, 1, -1, 1, 0, 0}, // DestinationOver
{x, 0, 1, 0, 0, 0}, // SourceIn
{x, 0, 0, 0, 1, 0}, // DestinationIn
{x, 1, -1, 0, 0, 0}, // SourceOut
{x, 0, 0, 1, -1, 0}, // DestinationOut
{x, 0, 1, 1, -1, 0}, // SourceATop
{x, 1, -1, 0, 1, 0}, // DestinationATop
{x, 1, -1, 1, -1, 0}, // Xor
{x, 1, 0, 1, 0, 0}, // Plus
{x, 0, 0, 0, 0, 1}, // Modulate
{x, 0, 0, 1, 0, -1}, // Screen
}};
}
template <typename PipelineT>
static std::unique_ptr<PipelineT> CreateDefaultPipeline(
const Context& context) {
auto desc = PipelineT::Builder::MakeDefaultPipelineDescriptor(context);
if (!desc.has_value()) {
return nullptr;
}
// Apply default ContentContextOptions to the descriptor.
const auto default_color_format =
context.GetCapabilities()->GetDefaultColorFormat();
ContentContextOptions{.sample_count = SampleCount::kCount4,
.primitive_type = PrimitiveType::kTriangleStrip,
.color_attachment_pixel_format = default_color_format}
.ApplyToPipelineDescriptor(*desc);
return std::make_unique<PipelineT>(context, desc);
}
ContentContext::ContentContext(
std::shared_ptr<Context> context,
std::shared_ptr<TypographerContext> typographer_context,
std::shared_ptr<RenderTargetAllocator> render_target_allocator)
: context_(std::move(context)),
lazy_glyph_atlas_(
std::make_shared<LazyGlyphAtlas>(std::move(typographer_context))),
pipelines_(new Pipelines()),
tessellator_(std::make_shared<Tessellator>(
context_->GetCapabilities()->Supports32BitPrimitiveIndices())),
render_target_cache_(render_target_allocator == nullptr
? std::make_shared<RenderTargetCache>(
context_->GetResourceAllocator())
: std::move(render_target_allocator)),
data_host_buffer_(HostBuffer::Create(
context_->GetResourceAllocator(),
context_->GetIdleWaiter(),
context_->GetCapabilities()->GetMinimumUniformAlignment())),
text_shadow_cache_(std::make_unique<TextShadowCache>()) {
if (!context_ || !context_->IsValid()) {
return;
}
// On most backends, indexes and other data can be allocated into the same
// buffers. However, some backends (namely WebGL) require indexes used in
// indexed draws to be allocated separately from other data. For those
// backends, we allocate a separate host buffer just for indexes.
indexes_host_buffer_ =
context_->GetCapabilities()->NeedsPartitionedHostBuffer()
? HostBuffer::Create(
context_->GetResourceAllocator(), context_->GetIdleWaiter(),
context_->GetCapabilities()->GetMinimumUniformAlignment())
: data_host_buffer_;
{
TextureDescriptor desc;
desc.storage_mode = StorageMode::kDevicePrivate;
desc.format = PixelFormat::kR8G8B8A8UNormInt;
desc.size = ISize{1, 1};
empty_texture_ = GetContext()->GetResourceAllocator()->CreateTexture(desc);
std::array<uint8_t, 4> data = Color::BlackTransparent().ToR8G8B8A8();
std::shared_ptr<CommandBuffer> cmd_buffer =
GetContext()->CreateCommandBuffer();
std::shared_ptr<BlitPass> blit_pass = cmd_buffer->CreateBlitPass();
HostBuffer& data_host_buffer = GetTransientsDataBuffer();
BufferView buffer_view = data_host_buffer.Emplace(data);
blit_pass->AddCopy(buffer_view, empty_texture_);
if (!blit_pass->EncodeCommands() || !GetContext()
->GetCommandQueue()
->Submit({std::move(cmd_buffer)})
.ok()) {
VALIDATION_LOG << "Failed to create empty texture.";
}
}
auto options = ContentContextOptions{
.sample_count = SampleCount::kCount4,
.color_attachment_pixel_format =
context_->GetCapabilities()->GetDefaultColorFormat()};
auto options_trianglestrip = ContentContextOptions{
.sample_count = SampleCount::kCount4,
.primitive_type = PrimitiveType::kTriangleStrip,
.color_attachment_pixel_format =
context_->GetCapabilities()->GetDefaultColorFormat()};
auto options_no_msaa_no_depth_stencil = ContentContextOptions{
.sample_count = SampleCount::kCount1,
.primitive_type = PrimitiveType::kTriangleStrip,
.color_attachment_pixel_format =
context_->GetCapabilities()->GetDefaultColorFormat(),
.has_depth_stencil_attachments = false};
const auto supports_decal = static_cast<Scalar>(
context_->GetCapabilities()->SupportsDecalSamplerAddressMode());
// Futures for the following pipelines may block in case the first frame is
// rendered without the pipelines being ready. Put pipelines that are more
// likely to be used first.
{
pipelines_->glyph_atlas.CreateDefault(
*context_, options,
{static_cast<Scalar>(
GetContext()->GetCapabilities()->GetDefaultGlyphAtlasFormat() ==
PixelFormat::kA8UNormInt)});
pipelines_->solid_fill.CreateDefault(*context_, options);
pipelines_->texture.CreateDefault(*context_, options);
pipelines_->fast_gradient.CreateDefault(*context_, options);
pipelines_->line.CreateDefault(*context_, options);
pipelines_->circle.CreateDefault(*context_, options);
if (context_->GetCapabilities()->SupportsSSBO()) {
pipelines_->linear_gradient_ssbo_fill.CreateDefault(*context_, options);
pipelines_->radial_gradient_ssbo_fill.CreateDefault(*context_, options);
pipelines_->conical_gradient_ssbo_fill.CreateDefault(*context_, options,
{3.0});
pipelines_->conical_gradient_ssbo_fill_radial.CreateDefault(
*context_, options, {1.0});
pipelines_->conical_gradient_ssbo_fill_strip.CreateDefault(
*context_, options, {2.0});
pipelines_->conical_gradient_ssbo_fill_strip_and_radial.CreateDefault(
*context_, options, {0.0});
pipelines_->sweep_gradient_ssbo_fill.CreateDefault(*context_, options);
} else {
pipelines_->linear_gradient_uniform_fill.CreateDefault(*context_,
options);
pipelines_->radial_gradient_uniform_fill.CreateDefault(*context_,
options);
pipelines_->conical_gradient_uniform_fill.CreateDefault(*context_,
options);
pipelines_->conical_gradient_uniform_fill_radial.CreateDefault(*context_,
options);
pipelines_->conical_gradient_uniform_fill_strip.CreateDefault(*context_,
options);
pipelines_->conical_gradient_uniform_fill_strip_and_radial.CreateDefault(
*context_, options);
pipelines_->sweep_gradient_uniform_fill.CreateDefault(*context_, options);
pipelines_->linear_gradient_fill.CreateDefault(*context_, options);
pipelines_->radial_gradient_fill.CreateDefault(*context_, options);
pipelines_->conical_gradient_fill.CreateDefault(*context_, options);
pipelines_->conical_gradient_fill_radial.CreateDefault(*context_,
options);
pipelines_->conical_gradient_fill_strip.CreateDefault(*context_, options);
pipelines_->conical_gradient_fill_strip_and_radial.CreateDefault(
*context_, options);
pipelines_->sweep_gradient_fill.CreateDefault(*context_, options);
}
/// Setup default clip pipeline.
auto clip_pipeline_descriptor =
ClipPipeline::Builder::MakeDefaultPipelineDescriptor(*context_);
if (!clip_pipeline_descriptor.has_value()) {
return;
}
ContentContextOptions{
.sample_count = SampleCount::kCount4,
.color_attachment_pixel_format =
context_->GetCapabilities()->GetDefaultColorFormat()}
.ApplyToPipelineDescriptor(*clip_pipeline_descriptor);
// Disable write to all color attachments.
auto clip_color_attachments =
clip_pipeline_descriptor->GetColorAttachmentDescriptors();
for (auto& color_attachment : clip_color_attachments) {
color_attachment.second.write_mask = ColorWriteMaskBits::kNone;
}
clip_pipeline_descriptor->SetColorAttachmentDescriptors(
std::move(clip_color_attachments));
pipelines_->clip.SetDefault(
options,
std::make_unique<ClipPipeline>(*context_, clip_pipeline_descriptor));
pipelines_->texture_downsample.CreateDefault(
*context_, options_no_msaa_no_depth_stencil);
pipelines_->texture_downsample_bounded.CreateDefault(
*context_, options_no_msaa_no_depth_stencil);
pipelines_->rrect_blur.CreateDefault(*context_, options_trianglestrip);
pipelines_->rsuperellipse_blur.CreateDefault(*context_,
options_trianglestrip);
pipelines_->texture_strict_src.CreateDefault(*context_, options);
pipelines_->tiled_texture.CreateDefault(*context_, options,
{supports_decal});
pipelines_->gaussian_blur.CreateDefault(
*context_, options_no_msaa_no_depth_stencil, {supports_decal});
pipelines_->border_mask_blur.CreateDefault(*context_,
options_trianglestrip);
pipelines_->color_matrix_color_filter.CreateDefault(*context_,
options_trianglestrip);
pipelines_->shadow_vertices_.CreateDefault(*context_, options);
pipelines_->vertices_uber_1_.CreateDefault(*context_, options,
{supports_decal});
pipelines_->vertices_uber_2_.CreateDefault(*context_, options,
{supports_decal});
const std::array<std::vector<Scalar>, 15> porter_duff_constants =
GetPorterDuffSpecConstants(supports_decal);
pipelines_->clear_blend.CreateDefault(*context_, options_trianglestrip,
porter_duff_constants[0]);
pipelines_->source_blend.CreateDefault(*context_, options_trianglestrip,
porter_duff_constants[1]);
pipelines_->destination_blend.CreateDefault(
*context_, options_trianglestrip, porter_duff_constants[2]);
pipelines_->source_over_blend.CreateDefault(
*context_, options_trianglestrip, porter_duff_constants[3]);
pipelines_->destination_over_blend.CreateDefault(
*context_, options_trianglestrip, porter_duff_constants[4]);
pipelines_->source_in_blend.CreateDefault(*context_, options_trianglestrip,
porter_duff_constants[5]);
pipelines_->destination_in_blend.CreateDefault(
*context_, options_trianglestrip, porter_duff_constants[6]);
pipelines_->source_out_blend.CreateDefault(*context_, options_trianglestrip,
porter_duff_constants[7]);
pipelines_->destination_out_blend.CreateDefault(
*context_, options_trianglestrip, porter_duff_constants[8]);
pipelines_->source_a_top_blend.CreateDefault(
*context_, options_trianglestrip, porter_duff_constants[9]);
pipelines_->destination_a_top_blend.CreateDefault(
*context_, options_trianglestrip, porter_duff_constants[10]);
pipelines_->xor_blend.CreateDefault(*context_, options_trianglestrip,
porter_duff_constants[11]);
pipelines_->plus_blend.CreateDefault(*context_, options_trianglestrip,
porter_duff_constants[12]);
pipelines_->modulate_blend.CreateDefault(*context_, options_trianglestrip,
porter_duff_constants[13]);
pipelines_->screen_blend.CreateDefault(*context_, options_trianglestrip,
porter_duff_constants[14]);
}
if (context_->GetCapabilities()->SupportsFramebufferFetch()) {
pipelines_->framebuffer_blend_color.CreateDefault(
*context_, options_trianglestrip,
{static_cast<Scalar>(BlendSelectValues::kColor), supports_decal});
pipelines_->framebuffer_blend_colorburn.CreateDefault(
*context_, options_trianglestrip,
{static_cast<Scalar>(BlendSelectValues::kColorBurn), supports_decal});
pipelines_->framebuffer_blend_colordodge.CreateDefault(
*context_, options_trianglestrip,
{static_cast<Scalar>(BlendSelectValues::kColorDodge), supports_decal});
pipelines_->framebuffer_blend_darken.CreateDefault(
*context_, options_trianglestrip,
{static_cast<Scalar>(BlendSelectValues::kDarken), supports_decal});
pipelines_->framebuffer_blend_difference.CreateDefault(
*context_, options_trianglestrip,
{static_cast<Scalar>(BlendSelectValues::kDifference), supports_decal});
pipelines_->framebuffer_blend_exclusion.CreateDefault(
*context_, options_trianglestrip,
{static_cast<Scalar>(BlendSelectValues::kExclusion), supports_decal});
pipelines_->framebuffer_blend_hardlight.CreateDefault(
*context_, options_trianglestrip,
{static_cast<Scalar>(BlendSelectValues::kHardLight), supports_decal});
pipelines_->framebuffer_blend_hue.CreateDefault(
*context_, options_trianglestrip,
{static_cast<Scalar>(BlendSelectValues::kHue), supports_decal});
pipelines_->framebuffer_blend_lighten.CreateDefault(
*context_, options_trianglestrip,
{static_cast<Scalar>(BlendSelectValues::kLighten), supports_decal});
pipelines_->framebuffer_blend_luminosity.CreateDefault(
*context_, options_trianglestrip,
{static_cast<Scalar>(BlendSelectValues::kLuminosity), supports_decal});
pipelines_->framebuffer_blend_multiply.CreateDefault(
*context_, options_trianglestrip,
{static_cast<Scalar>(BlendSelectValues::kMultiply), supports_decal});
pipelines_->framebuffer_blend_overlay.CreateDefault(
*context_, options_trianglestrip,
{static_cast<Scalar>(BlendSelectValues::kOverlay), supports_decal});
pipelines_->framebuffer_blend_saturation.CreateDefault(
*context_, options_trianglestrip,
{static_cast<Scalar>(BlendSelectValues::kSaturation), supports_decal});
pipelines_->framebuffer_blend_screen.CreateDefault(
*context_, options_trianglestrip,
{static_cast<Scalar>(BlendSelectValues::kScreen), supports_decal});
pipelines_->framebuffer_blend_softlight.CreateDefault(
*context_, options_trianglestrip,
{static_cast<Scalar>(BlendSelectValues::kSoftLight), supports_decal});
} else {
pipelines_->blend_color.CreateDefault(
*context_, options_trianglestrip,
{static_cast<Scalar>(BlendSelectValues::kColor), supports_decal});
pipelines_->blend_colorburn.CreateDefault(
*context_, options_trianglestrip,
{static_cast<Scalar>(BlendSelectValues::kColorBurn), supports_decal});
pipelines_->blend_colordodge.CreateDefault(
*context_, options_trianglestrip,
{static_cast<Scalar>(BlendSelectValues::kColorDodge), supports_decal});
pipelines_->blend_darken.CreateDefault(
*context_, options_trianglestrip,
{static_cast<Scalar>(BlendSelectValues::kDarken), supports_decal});
pipelines_->blend_difference.CreateDefault(
*context_, options_trianglestrip,
{static_cast<Scalar>(BlendSelectValues::kDifference), supports_decal});
pipelines_->blend_exclusion.CreateDefault(
*context_, options_trianglestrip,
{static_cast<Scalar>(BlendSelectValues::kExclusion), supports_decal});
pipelines_->blend_hardlight.CreateDefault(
*context_, options_trianglestrip,
{static_cast<Scalar>(BlendSelectValues::kHardLight), supports_decal});
pipelines_->blend_hue.CreateDefault(
*context_, options_trianglestrip,
{static_cast<Scalar>(BlendSelectValues::kHue), supports_decal});
pipelines_->blend_lighten.CreateDefault(
*context_, options_trianglestrip,
{static_cast<Scalar>(BlendSelectValues::kLighten), supports_decal});
pipelines_->blend_luminosity.CreateDefault(
*context_, options_trianglestrip,
{static_cast<Scalar>(BlendSelectValues::kLuminosity), supports_decal});
pipelines_->blend_multiply.CreateDefault(
*context_, options_trianglestrip,
{static_cast<Scalar>(BlendSelectValues::kMultiply), supports_decal});
pipelines_->blend_overlay.CreateDefault(
*context_, options_trianglestrip,
{static_cast<Scalar>(BlendSelectValues::kOverlay), supports_decal});
pipelines_->blend_saturation.CreateDefault(
*context_, options_trianglestrip,
{static_cast<Scalar>(BlendSelectValues::kSaturation), supports_decal});
pipelines_->blend_screen.CreateDefault(
*context_, options_trianglestrip,
{static_cast<Scalar>(BlendSelectValues::kScreen), supports_decal});
pipelines_->blend_softlight.CreateDefault(
*context_, options_trianglestrip,
{static_cast<Scalar>(BlendSelectValues::kSoftLight), supports_decal});
}
pipelines_->morphology_filter.CreateDefault(*context_, options_trianglestrip,
{supports_decal});
pipelines_->linear_to_srgb_filter.CreateDefault(*context_,
options_trianglestrip);
pipelines_->srgb_to_linear_filter.CreateDefault(*context_,
options_trianglestrip);
pipelines_->yuv_to_rgb_filter.CreateDefault(*context_, options_trianglestrip);
if (GetContext()->GetBackendType() == Context::BackendType::kOpenGLES) {
#if defined(IMPELLER_ENABLE_OPENGLES) && !defined(FML_OS_MACOSX) && \
!defined(FML_OS_EMSCRIPTEN)
// GLES only shader that is unsupported on macOS and web.
pipelines_->tiled_texture_external.CreateDefault(*context_, options);
pipelines_->tiled_texture_uv_external.CreateDefault(*context_, options);
#endif // !defined(FML_OS_MACOSX)
#if defined(IMPELLER_ENABLE_OPENGLES)
pipelines_->texture_downsample_gles.CreateDefault(*context_,
options_trianglestrip);
#endif // IMPELLER_ENABLE_OPENGLES
}
is_valid_ = true;
InitializeCommonlyUsedShadersIfNeeded();
}
ContentContext::~ContentContext() = default;
bool ContentContext::IsValid() const {
return is_valid_;
}
std::shared_ptr<Texture> ContentContext::GetEmptyTexture() const {
return empty_texture_;
}
fml::StatusOr<RenderTarget> ContentContext::MakeSubpass(
std::string_view label,
ISize texture_size,
const std::shared_ptr<CommandBuffer>& command_buffer,
const SubpassCallback& subpass_callback,
bool msaa_enabled,
bool depth_stencil_enabled,
int32_t mip_count) const {
const std::shared_ptr<Context>& context = GetContext();
RenderTarget subpass_target;
std::optional<RenderTarget::AttachmentConfig> depth_stencil_config =
depth_stencil_enabled ? RenderTarget::kDefaultStencilAttachmentConfig
: std::optional<RenderTarget::AttachmentConfig>();
if (context->GetCapabilities()->SupportsOffscreenMSAA() && msaa_enabled) {
subpass_target = GetRenderTargetCache()->CreateOffscreenMSAA(
/*context=*/*context,
/*size=*/texture_size,
/*mip_count=*/mip_count,
/*label=*/label,
/*color_attachment_config=*/
RenderTarget::kDefaultColorAttachmentConfigMSAA,
/*stencil_attachment_config=*/depth_stencil_config,
/*existing_color_msaa_texture=*/nullptr,
/*existing_color_resolve_texture=*/nullptr,
/*existing_depth_stencil_texture=*/nullptr,
/*target_pixel_format=*/std::nullopt);
} else {
subpass_target = GetRenderTargetCache()->CreateOffscreen(
*context, texture_size,
/*mip_count=*/mip_count, label,
RenderTarget::kDefaultColorAttachmentConfig, depth_stencil_config);
}
return MakeSubpass(label, subpass_target, command_buffer, subpass_callback);
}
fml::StatusOr<RenderTarget> ContentContext::MakeSubpass(
std::string_view label,
const RenderTarget& subpass_target,
const std::shared_ptr<CommandBuffer>& command_buffer,
const SubpassCallback& subpass_callback) const {
const std::shared_ptr<Context>& context = GetContext();
auto subpass_texture = subpass_target.GetRenderTargetTexture();
if (!subpass_texture) {
return fml::Status(fml::StatusCode::kUnknown, "");
}
auto sub_renderpass = command_buffer->CreateRenderPass(subpass_target);
if (!sub_renderpass) {
return fml::Status(fml::StatusCode::kUnknown, "");
}
sub_renderpass->SetLabel(label);
if (!subpass_callback(*this, *sub_renderpass)) {
return fml::Status(fml::StatusCode::kUnknown, "");
}
if (!sub_renderpass->EncodeCommands()) {
return fml::Status(fml::StatusCode::kUnknown, "");
}
const std::shared_ptr<Texture>& target_texture =
subpass_target.GetRenderTargetTexture();
if (target_texture->GetMipCount() > 1) {
fml::Status mipmap_status =
AddMipmapGeneration(command_buffer, context, target_texture);
if (!mipmap_status.ok()) {
return mipmap_status;
}
}
return subpass_target;
}
Tessellator& ContentContext::GetTessellator() const {
return *tessellator_;
}
std::shared_ptr<Context> ContentContext::GetContext() const {
return context_;
}
const Capabilities& ContentContext::GetDeviceCapabilities() const {
return *context_->GetCapabilities();
}
PipelineRef ContentContext::GetCachedRuntimeEffectPipeline(
const std::string& unique_entrypoint_name,
const ContentContextOptions& options,
const std::function<std::shared_ptr<Pipeline<PipelineDescriptor>>()>&
create_callback) const {
RuntimeEffectPipelineKey key{unique_entrypoint_name, options};
auto it = runtime_effect_pipelines_.find(key);
if (it == runtime_effect_pipelines_.end()) {
it = runtime_effect_pipelines_.insert(it, {key, create_callback()});
}
return raw_ptr(it->second);
}
void ContentContext::ClearCachedRuntimeEffectPipeline(
const std::string& unique_entrypoint_name) const {
#ifdef IMPELLER_DEBUG
// destroying in-use pipleines is a validation error.
const auto& idle_waiter = GetContext()->GetIdleWaiter();
if (idle_waiter) {
idle_waiter->WaitIdle();
}
#endif // IMPELLER_DEBUG
for (auto it = runtime_effect_pipelines_.begin();
it != runtime_effect_pipelines_.end();) {
if (it->first.unique_entrypoint_name == unique_entrypoint_name) {
it = runtime_effect_pipelines_.erase(it);
} else {
it++;
}
}
}
void ContentContext::ResetTransientsBuffers() {
data_host_buffer_->Reset();
// We should only reset the indexes host buffer if it is actually different
// from the data host buffer. Otherwise we'll end up resetting the same host
// buffer twice.
if (data_host_buffer_ != indexes_host_buffer_) {
indexes_host_buffer_->Reset();
}
}
void ContentContext::InitializeCommonlyUsedShadersIfNeeded() const {
GetContext()->InitializeCommonlyUsedShadersIfNeeded();
}
PipelineRef ContentContext::GetFastGradientPipeline(
ContentContextOptions opts) const {
return GetPipeline(this, pipelines_->fast_gradient, opts);
}
PipelineRef ContentContext::GetLinearGradientFillPipeline(
ContentContextOptions opts) const {
return GetPipeline(this, pipelines_->linear_gradient_fill, opts);
}
PipelineRef ContentContext::GetLinearGradientUniformFillPipeline(
ContentContextOptions opts) const {
return GetPipeline(this, pipelines_->linear_gradient_uniform_fill, opts);
}
PipelineRef ContentContext::GetRadialGradientUniformFillPipeline(
ContentContextOptions opts) const {
return GetPipeline(this, pipelines_->radial_gradient_uniform_fill, opts);
}
PipelineRef ContentContext::GetSweepGradientUniformFillPipeline(
ContentContextOptions opts) const {
return GetPipeline(this, pipelines_->sweep_gradient_uniform_fill, opts);
}
PipelineRef ContentContext::GetLinearGradientSSBOFillPipeline(
ContentContextOptions opts) const {
FML_DCHECK(GetDeviceCapabilities().SupportsSSBO());
return GetPipeline(this, pipelines_->linear_gradient_ssbo_fill, opts);
}
PipelineRef ContentContext::GetRadialGradientSSBOFillPipeline(
ContentContextOptions opts) const {
FML_DCHECK(GetDeviceCapabilities().SupportsSSBO());
return GetPipeline(this, pipelines_->radial_gradient_ssbo_fill, opts);
}
PipelineRef ContentContext::GetConicalGradientUniformFillPipeline(
ContentContextOptions opts,
ConicalKind kind) const {
switch (kind) {
case ConicalKind::kConical:
return GetPipeline(this, pipelines_->conical_gradient_uniform_fill, opts);
case ConicalKind::kRadial:
return GetPipeline(this, pipelines_->conical_gradient_uniform_fill_radial,
opts);
case ConicalKind::kStrip:
return GetPipeline(this, pipelines_->conical_gradient_uniform_fill_strip,
opts);
case ConicalKind::kStripAndRadial:
return GetPipeline(
this, pipelines_->conical_gradient_uniform_fill_strip_and_radial,
opts);
}
}
PipelineRef ContentContext::GetConicalGradientSSBOFillPipeline(
ContentContextOptions opts,
ConicalKind kind) const {
FML_DCHECK(GetDeviceCapabilities().SupportsSSBO());
switch (kind) {
case ConicalKind::kConical:
return GetPipeline(this, pipelines_->conical_gradient_ssbo_fill, opts);
case ConicalKind::kRadial:
return GetPipeline(this, pipelines_->conical_gradient_ssbo_fill_radial,
opts);
case ConicalKind::kStrip:
return GetPipeline(this, pipelines_->conical_gradient_ssbo_fill_strip,
opts);
case ConicalKind::kStripAndRadial:
return GetPipeline(
this, pipelines_->conical_gradient_ssbo_fill_strip_and_radial, opts);
}
}
PipelineRef ContentContext::GetSweepGradientSSBOFillPipeline(
ContentContextOptions opts) const {
FML_DCHECK(GetDeviceCapabilities().SupportsSSBO());
return GetPipeline(this, pipelines_->sweep_gradient_ssbo_fill, opts);
}
PipelineRef ContentContext::GetRadialGradientFillPipeline(
ContentContextOptions opts) const {
return GetPipeline(this, pipelines_->radial_gradient_fill, opts);
}
PipelineRef ContentContext::GetConicalGradientFillPipeline(
ContentContextOptions opts,
ConicalKind kind) const {
switch (kind) {
case ConicalKind::kConical:
return GetPipeline(this, pipelines_->conical_gradient_fill, opts);
case ConicalKind::kRadial:
return GetPipeline(this, pipelines_->conical_gradient_fill_radial, opts);
case ConicalKind::kStrip:
return GetPipeline(this, pipelines_->conical_gradient_fill_strip, opts);
case ConicalKind::kStripAndRadial:
return GetPipeline(
this, pipelines_->conical_gradient_fill_strip_and_radial, opts);
}
}
PipelineRef ContentContext::GetRRectBlurPipeline(
ContentContextOptions opts) const {
return GetPipeline(this, pipelines_->rrect_blur, opts);
}
PipelineRef ContentContext::GetRSuperellipseBlurPipeline(
ContentContextOptions opts) const {
return GetPipeline(this, pipelines_->rsuperellipse_blur, opts);
}
PipelineRef ContentContext::GetSweepGradientFillPipeline(
ContentContextOptions opts) const {
return GetPipeline(this, pipelines_->sweep_gradient_fill, opts);
}
PipelineRef ContentContext::GetSolidFillPipeline(
ContentContextOptions opts) const {
return GetPipeline(this, pipelines_->solid_fill, opts);
}
PipelineRef ContentContext::GetTexturePipeline(
ContentContextOptions opts) const {
return GetPipeline(this, pipelines_->texture, opts);
}
PipelineRef ContentContext::GetTextureStrictSrcPipeline(
ContentContextOptions opts) const {
return GetPipeline(this, pipelines_->texture_strict_src, opts);
}
PipelineRef ContentContext::GetTiledTexturePipeline(
ContentContextOptions opts) const {
return GetPipeline(this, pipelines_->tiled_texture, opts);
}
PipelineRef ContentContext::GetGaussianBlurPipeline(
ContentContextOptions opts) const {
return GetPipeline(this, pipelines_->gaussian_blur, opts);
}
PipelineRef ContentContext::GetBorderMaskBlurPipeline(
ContentContextOptions opts) const {
return GetPipeline(this, pipelines_->border_mask_blur, opts);
}
PipelineRef ContentContext::GetMorphologyFilterPipeline(
ContentContextOptions opts) const {
return GetPipeline(this, pipelines_->morphology_filter, opts);
}
PipelineRef ContentContext::GetColorMatrixColorFilterPipeline(
ContentContextOptions opts) const {
return GetPipeline(this, pipelines_->color_matrix_color_filter, opts);
}
PipelineRef ContentContext::GetLinearToSrgbFilterPipeline(
ContentContextOptions opts) const {
return GetPipeline(this, pipelines_->linear_to_srgb_filter, opts);
}
PipelineRef ContentContext::GetSrgbToLinearFilterPipeline(
ContentContextOptions opts) const {
return GetPipeline(this, pipelines_->srgb_to_linear_filter, opts);
}
PipelineRef ContentContext::GetClipPipeline(ContentContextOptions opts) const {
return GetPipeline(this, pipelines_->clip, opts);
}
PipelineRef ContentContext::GetGlyphAtlasPipeline(
ContentContextOptions opts) const {
return GetPipeline(this, pipelines_->glyph_atlas, opts);
}
PipelineRef ContentContext::GetYUVToRGBFilterPipeline(
ContentContextOptions opts) const {
return GetPipeline(this, pipelines_->yuv_to_rgb_filter, opts);
}
PipelineRef ContentContext::GetPorterDuffPipeline(
BlendMode mode,
ContentContextOptions opts) const {
switch (mode) {
case BlendMode::kClear:
return GetClearBlendPipeline(opts);
case BlendMode::kSrc:
return GetSourceBlendPipeline(opts);
case BlendMode::kDst:
return GetDestinationBlendPipeline(opts);
case BlendMode::kSrcOver:
return GetSourceOverBlendPipeline(opts);
case BlendMode::kDstOver:
return GetDestinationOverBlendPipeline(opts);
case BlendMode::kSrcIn:
return GetSourceInBlendPipeline(opts);
case BlendMode::kDstIn:
return GetDestinationInBlendPipeline(opts);
case BlendMode::kSrcOut:
return GetSourceOutBlendPipeline(opts);
case BlendMode::kDstOut:
return GetDestinationOutBlendPipeline(opts);
case BlendMode::kSrcATop:
return GetSourceATopBlendPipeline(opts);
case BlendMode::kDstATop:
return GetDestinationATopBlendPipeline(opts);
case BlendMode::kXor:
return GetXorBlendPipeline(opts);
case BlendMode::kPlus:
return GetPlusBlendPipeline(opts);
case BlendMode::kModulate:
return GetModulateBlendPipeline(opts);
case BlendMode::kScreen:
return GetScreenBlendPipeline(opts);
case BlendMode::kOverlay:
case BlendMode::kDarken:
case BlendMode::kLighten:
case BlendMode::kColorDodge:
case BlendMode::kColorBurn:
case BlendMode::kHardLight:
case BlendMode::kSoftLight:
case BlendMode::kDifference:
case BlendMode::kExclusion:
case BlendMode::kMultiply:
case BlendMode::kHue:
case BlendMode::kSaturation:
case BlendMode::kColor:
case BlendMode::kLuminosity:
VALIDATION_LOG << "Invalid porter duff blend mode "
<< BlendModeToString(mode);
return GetClearBlendPipeline(opts);
break;
}
}
PipelineRef ContentContext::GetClearBlendPipeline(
ContentContextOptions opts) const {
return GetPipeline(this, pipelines_->clear_blend, opts);
}
PipelineRef ContentContext::GetSourceBlendPipeline(
ContentContextOptions opts) const {
return GetPipeline(this, pipelines_->source_blend, opts);
}
PipelineRef ContentContext::GetDestinationBlendPipeline(
ContentContextOptions opts) const {
return GetPipeline(this, pipelines_->destination_blend, opts);
}
PipelineRef ContentContext::GetSourceOverBlendPipeline(
ContentContextOptions opts) const {
return GetPipeline(this, pipelines_->source_over_blend, opts);
}
PipelineRef ContentContext::GetDestinationOverBlendPipeline(
ContentContextOptions opts) const {
return GetPipeline(this, pipelines_->destination_over_blend, opts);
}
PipelineRef ContentContext::GetSourceInBlendPipeline(
ContentContextOptions opts) const {
return GetPipeline(this, pipelines_->source_in_blend, opts);
}
PipelineRef ContentContext::GetDestinationInBlendPipeline(
ContentContextOptions opts) const {
return GetPipeline(this, pipelines_->destination_in_blend, opts);
}
PipelineRef ContentContext::GetSourceOutBlendPipeline(
ContentContextOptions opts) const {
return GetPipeline(this, pipelines_->source_out_blend, opts);
}
PipelineRef ContentContext::GetDestinationOutBlendPipeline(
ContentContextOptions opts) const {
return GetPipeline(this, pipelines_->destination_out_blend, opts);
}
PipelineRef ContentContext::GetSourceATopBlendPipeline(
ContentContextOptions opts) const {
return GetPipeline(this, pipelines_->source_a_top_blend, opts);
}
PipelineRef ContentContext::GetDestinationATopBlendPipeline(
ContentContextOptions opts) const {
return GetPipeline(this, pipelines_->destination_a_top_blend, opts);
}
PipelineRef ContentContext::GetXorBlendPipeline(
ContentContextOptions opts) const {
return GetPipeline(this, pipelines_->xor_blend, opts);
}
PipelineRef ContentContext::GetPlusBlendPipeline(
ContentContextOptions opts) const {
return GetPipeline(this, pipelines_->plus_blend, opts);
}
PipelineRef ContentContext::GetModulateBlendPipeline(
ContentContextOptions opts) const {
return GetPipeline(this, pipelines_->modulate_blend, opts);
}
PipelineRef ContentContext::GetScreenBlendPipeline(
ContentContextOptions opts) const {
return GetPipeline(this, pipelines_->screen_blend, opts);
}
PipelineRef ContentContext::GetBlendColorPipeline(
ContentContextOptions opts) const {
return GetPipeline(this, pipelines_->blend_color, opts);
}
PipelineRef ContentContext::GetBlendColorBurnPipeline(
ContentContextOptions opts) const {
return GetPipeline(this, pipelines_->blend_colorburn, opts);
}
PipelineRef ContentContext::GetBlendColorDodgePipeline(
ContentContextOptions opts) const {
return GetPipeline(this, pipelines_->blend_colordodge, opts);
}
PipelineRef ContentContext::GetBlendDarkenPipeline(
ContentContextOptions opts) const {
return GetPipeline(this, pipelines_->blend_darken, opts);
}
PipelineRef ContentContext::GetBlendDifferencePipeline(
ContentContextOptions opts) const {
return GetPipeline(this, pipelines_->blend_difference, opts);
}
PipelineRef ContentContext::GetBlendExclusionPipeline(
ContentContextOptions opts) const {
return GetPipeline(this, pipelines_->blend_exclusion, opts);
}
PipelineRef ContentContext::GetBlendHardLightPipeline(
ContentContextOptions opts) const {
return GetPipeline(this, pipelines_->blend_hardlight, opts);
}
PipelineRef ContentContext::GetBlendHuePipeline(
ContentContextOptions opts) const {
return GetPipeline(this, pipelines_->blend_hue, opts);
}
PipelineRef ContentContext::GetBlendLightenPipeline(
ContentContextOptions opts) const {
return GetPipeline(this, pipelines_->blend_lighten, opts);
}
PipelineRef ContentContext::GetBlendLuminosityPipeline(
ContentContextOptions opts) const {
return GetPipeline(this, pipelines_->blend_luminosity, opts);
}
PipelineRef ContentContext::GetBlendMultiplyPipeline(
ContentContextOptions opts) const {
return GetPipeline(this, pipelines_->blend_multiply, opts);
}
PipelineRef ContentContext::GetBlendOverlayPipeline(
ContentContextOptions opts) const {
return GetPipeline(this, pipelines_->blend_overlay, opts);
}
PipelineRef ContentContext::GetBlendSaturationPipeline(
ContentContextOptions opts) const {
return GetPipeline(this, pipelines_->blend_saturation, opts);
}
PipelineRef ContentContext::GetBlendScreenPipeline(
ContentContextOptions opts) const {
return GetPipeline(this, pipelines_->blend_screen, opts);
}
PipelineRef ContentContext::GetBlendSoftLightPipeline(
ContentContextOptions opts) const {
return GetPipeline(this, pipelines_->blend_softlight, opts);
}
PipelineRef ContentContext::GetDownsamplePipeline(
ContentContextOptions opts) const {
return GetPipeline(this, pipelines_->texture_downsample, opts);
}
PipelineRef ContentContext::GetDownsampleBoundedPipeline(
ContentContextOptions opts) const {
return GetPipeline(this, pipelines_->texture_downsample_bounded, opts);
}
PipelineRef ContentContext::GetFramebufferBlendColorPipeline(
ContentContextOptions opts) const {
FML_DCHECK(GetDeviceCapabilities().SupportsFramebufferFetch());
return GetPipeline(this, pipelines_->framebuffer_blend_color, opts);
}
PipelineRef ContentContext::GetFramebufferBlendColorBurnPipeline(
ContentContextOptions opts) const {
FML_DCHECK(GetDeviceCapabilities().SupportsFramebufferFetch());
return GetPipeline(this, pipelines_->framebuffer_blend_colorburn, opts);
}
PipelineRef ContentContext::GetFramebufferBlendColorDodgePipeline(
ContentContextOptions opts) const {
FML_DCHECK(GetDeviceCapabilities().SupportsFramebufferFetch());
return GetPipeline(this, pipelines_->framebuffer_blend_colordodge, opts);
}
PipelineRef ContentContext::GetFramebufferBlendDarkenPipeline(
ContentContextOptions opts) const {
FML_DCHECK(GetDeviceCapabilities().SupportsFramebufferFetch());
return GetPipeline(this, pipelines_->framebuffer_blend_darken, opts);
}
PipelineRef ContentContext::GetFramebufferBlendDifferencePipeline(
ContentContextOptions opts) const {
FML_DCHECK(GetDeviceCapabilities().SupportsFramebufferFetch());
return GetPipeline(this, pipelines_->framebuffer_blend_difference, opts);
}
PipelineRef ContentContext::GetFramebufferBlendExclusionPipeline(
ContentContextOptions opts) const {
FML_DCHECK(GetDeviceCapabilities().SupportsFramebufferFetch());
return GetPipeline(this, pipelines_->framebuffer_blend_exclusion, opts);
}
PipelineRef ContentContext::GetFramebufferBlendHardLightPipeline(
ContentContextOptions opts) const {
FML_DCHECK(GetDeviceCapabilities().SupportsFramebufferFetch());
return GetPipeline(this, pipelines_->framebuffer_blend_hardlight, opts);
}
PipelineRef ContentContext::GetFramebufferBlendHuePipeline(
ContentContextOptions opts) const {
FML_DCHECK(GetDeviceCapabilities().SupportsFramebufferFetch());
return GetPipeline(this, pipelines_->framebuffer_blend_hue, opts);
}
PipelineRef ContentContext::GetFramebufferBlendLightenPipeline(
ContentContextOptions opts) const {
FML_DCHECK(GetDeviceCapabilities().SupportsFramebufferFetch());
return GetPipeline(this, pipelines_->framebuffer_blend_lighten, opts);
}
PipelineRef ContentContext::GetFramebufferBlendLuminosityPipeline(
ContentContextOptions opts) const {
FML_DCHECK(GetDeviceCapabilities().SupportsFramebufferFetch());
return GetPipeline(this, pipelines_->framebuffer_blend_luminosity, opts);
}
PipelineRef ContentContext::GetFramebufferBlendMultiplyPipeline(
ContentContextOptions opts) const {
FML_DCHECK(GetDeviceCapabilities().SupportsFramebufferFetch());
return GetPipeline(this, pipelines_->framebuffer_blend_multiply, opts);
}
PipelineRef ContentContext::GetFramebufferBlendOverlayPipeline(
ContentContextOptions opts) const {
FML_DCHECK(GetDeviceCapabilities().SupportsFramebufferFetch());
return GetPipeline(this, pipelines_->framebuffer_blend_overlay, opts);
}
PipelineRef ContentContext::GetFramebufferBlendSaturationPipeline(
ContentContextOptions opts) const {
FML_DCHECK(GetDeviceCapabilities().SupportsFramebufferFetch());
return GetPipeline(this, pipelines_->framebuffer_blend_saturation, opts);
}
PipelineRef ContentContext::GetFramebufferBlendScreenPipeline(
ContentContextOptions opts) const {
FML_DCHECK(GetDeviceCapabilities().SupportsFramebufferFetch());
return GetPipeline(this, pipelines_->framebuffer_blend_screen, opts);
}
PipelineRef ContentContext::GetFramebufferBlendSoftLightPipeline(
ContentContextOptions opts) const {
FML_DCHECK(GetDeviceCapabilities().SupportsFramebufferFetch());
return GetPipeline(this, pipelines_->framebuffer_blend_softlight, opts);
}
PipelineRef ContentContext::GetDrawShadowVerticesPipeline(
ContentContextOptions opts) const {
return GetPipeline(this, pipelines_->shadow_vertices_, opts);
}
PipelineRef ContentContext::GetDrawVerticesUberPipeline(
BlendMode blend_mode,
ContentContextOptions opts) const {
if (blend_mode <= BlendMode::kHardLight) {
return GetPipeline(this, pipelines_->vertices_uber_1_, opts);
} else {
return GetPipeline(this, pipelines_->vertices_uber_2_, opts);
}
}
PipelineRef ContentContext::GetCirclePipeline(
ContentContextOptions opts) const {
return GetPipeline(this, pipelines_->circle, opts);
}
PipelineRef ContentContext::GetLinePipeline(ContentContextOptions opts) const {
return GetPipeline(this, pipelines_->line, opts);
}
#ifdef IMPELLER_ENABLE_OPENGLES
#if !defined(FML_OS_EMSCRIPTEN)
PipelineRef ContentContext::GetTiledTextureUvExternalPipeline(
ContentContextOptions opts) const {
FML_DCHECK(GetContext()->GetBackendType() == Context::BackendType::kOpenGLES);
return GetPipeline(this, pipelines_->tiled_texture_uv_external, opts);
}
PipelineRef ContentContext::GetTiledTextureExternalPipeline(
ContentContextOptions opts) const {
FML_DCHECK(GetContext()->GetBackendType() == Context::BackendType::kOpenGLES);
return GetPipeline(this, pipelines_->tiled_texture_external, opts);
}
#endif
PipelineRef ContentContext::GetDownsampleTextureGlesPipeline(
ContentContextOptions opts) const {
return GetPipeline(this, pipelines_->texture_downsample_gles, opts);
}
#endif // IMPELLER_ENABLE_OPENGLES
} // namespace impeller