Jonah Williams cab4fe33c3
[Impeller] add a configuration option that allows defering all PSO construction until needed. (#165261)
The cost of bootstapping the initial PSOs can regress cold startup time
for customer money. As an experiment, attempt to defer PSO construction
to skia like.

---------

Co-authored-by: Aaron Clarke <aaclarke@google.com>
Co-authored-by: gaaclarke <30870216+gaaclarke@users.noreply.github.com>
2025-03-20 21:06:09 +00:00

759 lines
38 KiB
C++

// 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_ENTITY_CONTENTS_CONTENT_CONTEXT_H_
#define FLUTTER_IMPELLER_ENTITY_CONTENTS_CONTENT_CONTEXT_H_
#include <initializer_list>
#include <memory>
#include <optional>
#include <unordered_map>
#include <utility>
#include "flutter/fml/logging.h"
#include "flutter/fml/status_or.h"
#include "impeller/base/validation.h"
#include "impeller/core/formats.h"
#include "impeller/core/host_buffer.h"
#include "impeller/geometry/color.h"
#include "impeller/renderer/capabilities.h"
#include "impeller/renderer/command_buffer.h"
#include "impeller/renderer/pipeline.h"
#include "impeller/renderer/pipeline_descriptor.h"
#include "impeller/renderer/render_target.h"
#include "impeller/typographer/lazy_glyph_atlas.h"
#include "impeller/typographer/typographer_context.h"
#include "impeller/entity/border_mask_blur.frag.h"
#include "impeller/entity/clip.frag.h"
#include "impeller/entity/clip.vert.h"
#include "impeller/entity/color_matrix_color_filter.frag.h"
#include "impeller/entity/conical_gradient_fill_conical.frag.h"
#include "impeller/entity/conical_gradient_fill_radial.frag.h"
#include "impeller/entity/conical_gradient_fill_strip.frag.h"
#include "impeller/entity/conical_gradient_fill_strip_radial.frag.h"
#include "impeller/entity/fast_gradient.frag.h"
#include "impeller/entity/fast_gradient.vert.h"
#include "impeller/entity/filter_position.vert.h"
#include "impeller/entity/filter_position_uv.vert.h"
#include "impeller/entity/gaussian.frag.h"
#include "impeller/entity/glyph_atlas.frag.h"
#include "impeller/entity/glyph_atlas.vert.h"
#include "impeller/entity/gradient_fill.vert.h"
#include "impeller/entity/linear_gradient_fill.frag.h"
#include "impeller/entity/linear_to_srgb_filter.frag.h"
#include "impeller/entity/morphology_filter.frag.h"
#include "impeller/entity/porter_duff_blend.frag.h"
#include "impeller/entity/porter_duff_blend.vert.h"
#include "impeller/entity/radial_gradient_fill.frag.h"
#include "impeller/entity/rrect_blur.frag.h"
#include "impeller/entity/rrect_blur.vert.h"
#include "impeller/entity/solid_fill.frag.h"
#include "impeller/entity/solid_fill.vert.h"
#include "impeller/entity/srgb_to_linear_filter.frag.h"
#include "impeller/entity/sweep_gradient_fill.frag.h"
#include "impeller/entity/texture_downsample.frag.h"
#include "impeller/entity/texture_fill.frag.h"
#include "impeller/entity/texture_fill.vert.h"
#include "impeller/entity/texture_fill_strict_src.frag.h"
#include "impeller/entity/texture_uv_fill.vert.h"
#include "impeller/entity/tiled_texture_fill.frag.h"
#include "impeller/entity/yuv_to_rgb_filter.frag.h"
#include "impeller/entity/conical_gradient_uniform_fill_conical.frag.h"
#include "impeller/entity/conical_gradient_uniform_fill_radial.frag.h"
#include "impeller/entity/conical_gradient_uniform_fill_strip.frag.h"
#include "impeller/entity/conical_gradient_uniform_fill_strip_radial.frag.h"
#include "impeller/entity/linear_gradient_uniform_fill.frag.h"
#include "impeller/entity/radial_gradient_uniform_fill.frag.h"
#include "impeller/entity/sweep_gradient_uniform_fill.frag.h"
#include "impeller/entity/conical_gradient_ssbo_fill.frag.h"
#include "impeller/entity/linear_gradient_ssbo_fill.frag.h"
#include "impeller/entity/radial_gradient_ssbo_fill.frag.h"
#include "impeller/entity/sweep_gradient_ssbo_fill.frag.h"
#include "impeller/entity/advanced_blend.frag.h"
#include "impeller/entity/advanced_blend.vert.h"
#include "impeller/entity/framebuffer_blend.frag.h"
#include "impeller/entity/framebuffer_blend.vert.h"
#include "impeller/entity/vertices_uber.frag.h"
#ifdef IMPELLER_ENABLE_OPENGLES
#include "impeller/entity/texture_downsample_gles.frag.h"
#include "impeller/entity/tiled_texture_fill_external.frag.h"
#endif // IMPELLER_ENABLE_OPENGLES
namespace impeller {
template <typename T>
using GradientPipelineHandle =
RenderPipelineHandle<GradientFillVertexShader, T>;
using AdvancedBlendPipelineHandle =
RenderPipelineHandle<AdvancedBlendVertexShader,
AdvancedBlendFragmentShader>;
using FramebufferBlendPipelineHandle =
RenderPipelineHandle<FramebufferBlendVertexShader,
FramebufferBlendFragmentShader>;
// clang-format off
using BlendColorBurnPipeline = AdvancedBlendPipelineHandle;
using BlendColorDodgePipeline = AdvancedBlendPipelineHandle;
using BlendColorPipeline = AdvancedBlendPipelineHandle;
using BlendDarkenPipeline = AdvancedBlendPipelineHandle;
using BlendDifferencePipeline = AdvancedBlendPipelineHandle;
using BlendExclusionPipeline = AdvancedBlendPipelineHandle;
using BlendHardLightPipeline = AdvancedBlendPipelineHandle;
using BlendHuePipeline = AdvancedBlendPipelineHandle;
using BlendLightenPipeline = AdvancedBlendPipelineHandle;
using BlendLuminosityPipeline = AdvancedBlendPipelineHandle;
using BlendMultiplyPipeline = AdvancedBlendPipelineHandle;
using BlendOverlayPipeline = AdvancedBlendPipelineHandle;
using BlendSaturationPipeline = AdvancedBlendPipelineHandle;
using BlendScreenPipeline = AdvancedBlendPipelineHandle;
using BlendSoftLightPipeline = AdvancedBlendPipelineHandle;
using BorderMaskBlurPipeline = RenderPipelineHandle<FilterPositionUvVertexShader, BorderMaskBlurFragmentShader>;
using ClipPipeline = RenderPipelineHandle<ClipVertexShader, ClipFragmentShader>;
using ColorMatrixColorFilterPipeline = RenderPipelineHandle<FilterPositionVertexShader, ColorMatrixColorFilterFragmentShader>;
using ConicalGradientFillConicalPipeline = GradientPipelineHandle<ConicalGradientFillConicalFragmentShader>;
using ConicalGradientFillRadialPipeline = GradientPipelineHandle<ConicalGradientFillRadialFragmentShader>;
using ConicalGradientFillStripPipeline = GradientPipelineHandle<ConicalGradientFillStripFragmentShader>;
using ConicalGradientFillStripRadialPipeline = GradientPipelineHandle<ConicalGradientFillStripRadialFragmentShader>;
using ConicalGradientSSBOFillPipeline = GradientPipelineHandle<ConicalGradientSsboFillFragmentShader>;
using ConicalGradientUniformFillConicalPipeline = GradientPipelineHandle<ConicalGradientUniformFillConicalFragmentShader>;
using ConicalGradientUniformFillRadialPipeline = GradientPipelineHandle<ConicalGradientUniformFillRadialFragmentShader>;
using ConicalGradientUniformFillStripPipeline = GradientPipelineHandle<ConicalGradientUniformFillStripFragmentShader>;
using ConicalGradientUniformFillStripRadialPipeline = GradientPipelineHandle<ConicalGradientUniformFillStripRadialFragmentShader>;
using FastGradientPipeline = RenderPipelineHandle<FastGradientVertexShader, FastGradientFragmentShader>;
using FramebufferBlendColorBurnPipeline = FramebufferBlendPipelineHandle;
using FramebufferBlendColorDodgePipeline = FramebufferBlendPipelineHandle;
using FramebufferBlendColorPipeline = FramebufferBlendPipelineHandle;
using FramebufferBlendDarkenPipeline = FramebufferBlendPipelineHandle;
using FramebufferBlendDifferencePipeline = FramebufferBlendPipelineHandle;
using FramebufferBlendExclusionPipeline = FramebufferBlendPipelineHandle;
using FramebufferBlendHardLightPipeline = FramebufferBlendPipelineHandle;
using FramebufferBlendHuePipeline = FramebufferBlendPipelineHandle;
using FramebufferBlendLightenPipeline = FramebufferBlendPipelineHandle;
using FramebufferBlendLuminosityPipeline = FramebufferBlendPipelineHandle;
using FramebufferBlendMultiplyPipeline = FramebufferBlendPipelineHandle;
using FramebufferBlendOverlayPipeline = FramebufferBlendPipelineHandle;
using FramebufferBlendSaturationPipeline = FramebufferBlendPipelineHandle;
using FramebufferBlendScreenPipeline = FramebufferBlendPipelineHandle;
using FramebufferBlendSoftLightPipeline = FramebufferBlendPipelineHandle;
using GaussianBlurPipeline = RenderPipelineHandle<FilterPositionUvVertexShader, GaussianFragmentShader>;
using GlyphAtlasPipeline = RenderPipelineHandle<GlyphAtlasVertexShader, GlyphAtlasFragmentShader>;
using LinearGradientFillPipeline = GradientPipelineHandle<LinearGradientFillFragmentShader>;
using LinearGradientSSBOFillPipeline = GradientPipelineHandle<LinearGradientSsboFillFragmentShader>;
using LinearGradientUniformFillPipeline = GradientPipelineHandle<LinearGradientUniformFillFragmentShader>;
using LinearToSrgbFilterPipeline = RenderPipelineHandle<FilterPositionVertexShader, LinearToSrgbFilterFragmentShader>;
using MorphologyFilterPipeline = RenderPipelineHandle<FilterPositionUvVertexShader, MorphologyFilterFragmentShader>;
using PorterDuffBlendPipeline = RenderPipelineHandle<PorterDuffBlendVertexShader, PorterDuffBlendFragmentShader>;
using RadialGradientFillPipeline = GradientPipelineHandle<RadialGradientFillFragmentShader>;
using RadialGradientSSBOFillPipeline = GradientPipelineHandle<RadialGradientSsboFillFragmentShader>;
using RadialGradientUniformFillPipeline = GradientPipelineHandle<RadialGradientUniformFillFragmentShader>;
using RRectBlurPipeline = RenderPipelineHandle<RrectBlurVertexShader, RrectBlurFragmentShader>;
using SolidFillPipeline = RenderPipelineHandle<SolidFillVertexShader, SolidFillFragmentShader>;
using SrgbToLinearFilterPipeline = RenderPipelineHandle<FilterPositionVertexShader, SrgbToLinearFilterFragmentShader>;
using SweepGradientFillPipeline = GradientPipelineHandle<SweepGradientFillFragmentShader>;
using SweepGradientSSBOFillPipeline = GradientPipelineHandle<SweepGradientSsboFillFragmentShader>;
using SweepGradientUniformFillPipeline = GradientPipelineHandle<SweepGradientUniformFillFragmentShader>;
using TextureDownsamplePipeline = RenderPipelineHandle<TextureFillVertexShader, TextureDownsampleFragmentShader>;
using TexturePipeline = RenderPipelineHandle<TextureFillVertexShader, TextureFillFragmentShader>;
using TextureStrictSrcPipeline = RenderPipelineHandle<TextureFillVertexShader, TextureFillStrictSrcFragmentShader>;
using TiledTexturePipeline = RenderPipelineHandle<TextureUvFillVertexShader, TiledTextureFillFragmentShader>;
using VerticesUberShader = RenderPipelineHandle<PorterDuffBlendVertexShader, VerticesUberFragmentShader>;
using YUVToRGBFilterPipeline = RenderPipelineHandle<FilterPositionVertexShader, YuvToRgbFilterFragmentShader>;
// clang-format on
#ifdef IMPELLER_ENABLE_OPENGLES
using TiledTextureExternalPipeline =
RenderPipelineHandle<TextureFillVertexShader,
TiledTextureFillExternalFragmentShader>;
using TiledTextureUvExternalPipeline =
RenderPipelineHandle<TextureUvFillVertexShader,
TiledTextureFillExternalFragmentShader>;
using TextureDownsampleGlesPipeline =
RenderPipelineHandle<TextureFillVertexShader,
TextureDownsampleGlesFragmentShader>;
#endif // IMPELLER_ENABLE_OPENGLES
/// Pipeline state configuration.
///
/// Each unique combination of these options requires a different pipeline state
/// object to be built. This struct is used as a key for the per-pipeline
/// variant cache.
///
/// When adding fields to this key, reliant features should take care to limit
/// the combinatorical explosion of variations. A sufficiently complicated
/// Flutter application may easily require building hundreds of PSOs in total,
/// but they shouldn't require e.g. 10s of thousands.
struct ContentContextOptions {
enum class StencilMode : uint8_t {
/// Turn the stencil test off. Used when drawing without stencil-then-cover
/// or overdraw prevention.
kIgnore,
// Operations used for stencil-then-cover.
/// Draw the stencil for the NonZero fill path rule.
///
/// The stencil ref should always be 0 on commands using this mode.
kStencilNonZeroFill,
/// Draw the stencil for the EvenOdd fill path rule.
///
/// The stencil ref should always be 0 on commands using this mode.
kStencilEvenOddFill,
/// Used for draw calls which fill in the stenciled area. Intended to be
/// used after `kStencilNonZeroFill` or `kStencilEvenOddFill` is used to set
/// up the stencil buffer. Also cleans up the stencil buffer by resetting
/// everything to zero.
///
/// The stencil ref should always be 0 on commands using this mode.
kCoverCompare,
/// The opposite of `kCoverCompare`. Used for draw calls which fill in the
/// non-stenciled area (intersection clips). Intended to be used after
/// `kStencilNonZeroFill` or `kStencilEvenOddFill` is used to set up the
/// stencil buffer. Also cleans up the stencil buffer by resetting
/// everything to zero.
///
/// The stencil ref should always be 0 on commands using this mode.
kCoverCompareInverted,
// Operations used for the "overdraw prevention" mechanism. This is used for
// drawing strokes.
/// For each fragment, increment the stencil value if it's currently zero.
/// Discard fragments when the value is non-zero. This prevents
/// self-overlapping strokes from drawing over themselves.
///
/// Note that this is done for rendering correctness, not performance. If a
/// stroke is drawn with a backdrop-reliant blend and self-intersects, then
/// the intersected geometry will render incorrectly when overdrawn because
/// we don't adjust the geometry prevent self-intersection.
///
/// The stencil ref should always be 0 on commands using this mode.
kOverdrawPreventionIncrement,
/// Reset the stencil to a new maximum value specified by the ref (currently
/// always 0).
///
/// The stencil ref should always be 0 on commands using this mode.
kOverdrawPreventionRestore,
};
SampleCount sample_count = SampleCount::kCount1;
BlendMode blend_mode = BlendMode::kSrcOver;
CompareFunction depth_compare = CompareFunction::kAlways;
StencilMode stencil_mode = ContentContextOptions::StencilMode::kIgnore;
PrimitiveType primitive_type = PrimitiveType::kTriangle;
PixelFormat color_attachment_pixel_format = PixelFormat::kUnknown;
bool has_depth_stencil_attachments = true;
bool depth_write_enabled = false;
bool wireframe = false;
bool is_for_rrect_blur_clear = false;
constexpr uint64_t ToKey() const {
static_assert(sizeof(sample_count) == 1);
static_assert(sizeof(blend_mode) == 1);
static_assert(sizeof(sample_count) == 1);
static_assert(sizeof(depth_compare) == 1);
static_assert(sizeof(stencil_mode) == 1);
static_assert(sizeof(primitive_type) == 1);
static_assert(sizeof(color_attachment_pixel_format) == 1);
return (is_for_rrect_blur_clear ? 1llu : 0llu) << 0 |
(wireframe ? 1llu : 0llu) << 1 |
(has_depth_stencil_attachments ? 1llu : 0llu) << 2 |
(depth_write_enabled ? 1llu : 0llu) << 3 |
// enums
static_cast<uint64_t>(color_attachment_pixel_format) << 8 |
static_cast<uint64_t>(primitive_type) << 16 |
static_cast<uint64_t>(stencil_mode) << 24 |
static_cast<uint64_t>(depth_compare) << 32 |
static_cast<uint64_t>(blend_mode) << 40 |
static_cast<uint64_t>(sample_count) << 48;
}
void ApplyToPipelineDescriptor(PipelineDescriptor& desc) const;
};
enum ConicalKind {
kConical,
kRadial,
kStrip,
kStripAndRadial,
};
class Tessellator;
class RenderTargetCache;
class ContentContext {
public:
explicit ContentContext(
std::shared_ptr<Context> context,
std::shared_ptr<TypographerContext> typographer_context,
std::shared_ptr<RenderTargetAllocator> render_target_allocator = nullptr);
~ContentContext();
bool IsValid() const;
Tessellator& GetTessellator() const;
// clang-format off
PipelineRef GetBlendColorBurnPipeline(ContentContextOptions opts) const;
PipelineRef GetBlendColorDodgePipeline(ContentContextOptions opts) const;
PipelineRef GetBlendColorPipeline(ContentContextOptions opts) const;
PipelineRef GetBlendDarkenPipeline(ContentContextOptions opts) const;
PipelineRef GetBlendDifferencePipeline(ContentContextOptions opts) const;
PipelineRef GetBlendExclusionPipeline(ContentContextOptions opts) const;
PipelineRef GetBlendHardLightPipeline(ContentContextOptions opts) const;
PipelineRef GetBlendHuePipeline(ContentContextOptions opts) const;
PipelineRef GetBlendLightenPipeline(ContentContextOptions opts) const;
PipelineRef GetBlendLuminosityPipeline(ContentContextOptions opts) const;
PipelineRef GetBlendMultiplyPipeline(ContentContextOptions opts) const;
PipelineRef GetBlendOverlayPipeline(ContentContextOptions opts) const;
PipelineRef GetBlendSaturationPipeline(ContentContextOptions opts) const;
PipelineRef GetBlendScreenPipeline(ContentContextOptions opts) const;
PipelineRef GetBlendSoftLightPipeline(ContentContextOptions opts) const;
PipelineRef GetBorderMaskBlurPipeline(ContentContextOptions opts) const;
PipelineRef GetClearBlendPipeline(ContentContextOptions opts) const;
PipelineRef GetClipPipeline(ContentContextOptions opts) const;
PipelineRef GetColorMatrixColorFilterPipeline(ContentContextOptions opts) const;
PipelineRef GetConicalGradientFillPipeline(ContentContextOptions opts, ConicalKind kind) const;
PipelineRef GetConicalGradientSSBOFillPipeline(ContentContextOptions opts, ConicalKind kind) const;
PipelineRef GetConicalGradientUniformFillPipeline(ContentContextOptions opts, ConicalKind kind) const;
PipelineRef GetDestinationATopBlendPipeline(ContentContextOptions opts) const;
PipelineRef GetDestinationBlendPipeline(ContentContextOptions opts) const;
PipelineRef GetDestinationInBlendPipeline(ContentContextOptions opts) const;
PipelineRef GetDestinationOutBlendPipeline(ContentContextOptions opts) const;
PipelineRef GetDestinationOverBlendPipeline(ContentContextOptions opts) const;
PipelineRef GetDownsamplePipeline(ContentContextOptions opts) const;
PipelineRef GetDrawVerticesUberShader(ContentContextOptions opts) const;
PipelineRef GetFastGradientPipeline(ContentContextOptions opts) const;
PipelineRef GetFramebufferBlendColorBurnPipeline(ContentContextOptions opts) const;
PipelineRef GetFramebufferBlendColorDodgePipeline(ContentContextOptions opts) const;
PipelineRef GetFramebufferBlendColorPipeline( ContentContextOptions opts) const;
PipelineRef GetFramebufferBlendDarkenPipeline(ContentContextOptions opts) const;
PipelineRef GetFramebufferBlendDifferencePipeline(ContentContextOptions opts) const;
PipelineRef GetFramebufferBlendExclusionPipeline(ContentContextOptions opts) const;
PipelineRef GetFramebufferBlendHardLightPipeline(ContentContextOptions opts) const;
PipelineRef GetFramebufferBlendHuePipeline(ContentContextOptions opts) const;
PipelineRef GetFramebufferBlendLightenPipeline(ContentContextOptions opts) const;
PipelineRef GetFramebufferBlendLuminosityPipeline(ContentContextOptions opts) const;
PipelineRef GetFramebufferBlendMultiplyPipeline(ContentContextOptions opts) const;
PipelineRef GetFramebufferBlendOverlayPipeline(ContentContextOptions opts) const;
PipelineRef GetFramebufferBlendSaturationPipeline(ContentContextOptions opts) const;
PipelineRef GetFramebufferBlendScreenPipeline(ContentContextOptions opts) const;
PipelineRef GetFramebufferBlendSoftLightPipeline(ContentContextOptions opts) const;
PipelineRef GetGaussianBlurPipeline(ContentContextOptions opts) const;
PipelineRef GetGlyphAtlasPipeline(ContentContextOptions opts) const;
PipelineRef GetLinearGradientFillPipeline(ContentContextOptions opts) const;
PipelineRef GetLinearGradientSSBOFillPipeline(ContentContextOptions opts) const;
PipelineRef GetLinearGradientUniformFillPipeline(ContentContextOptions opts) const;
PipelineRef GetLinearToSrgbFilterPipeline(ContentContextOptions opts) const;
PipelineRef GetModulateBlendPipeline(ContentContextOptions opts) const;
PipelineRef GetMorphologyFilterPipeline(ContentContextOptions opts) const;
PipelineRef GetPlusBlendPipeline(ContentContextOptions opts) const;
PipelineRef GetPorterDuffPipeline(BlendMode mode, ContentContextOptions opts) const;
PipelineRef GetRadialGradientFillPipeline(ContentContextOptions opts) const;
PipelineRef GetRadialGradientSSBOFillPipeline(ContentContextOptions opts) const;
PipelineRef GetRadialGradientUniformFillPipeline(ContentContextOptions opts) const;
PipelineRef GetRRectBlurPipeline(ContentContextOptions opts) const;
PipelineRef GetScreenBlendPipeline(ContentContextOptions opts) const;
PipelineRef GetSolidFillPipeline(ContentContextOptions opts) const;
PipelineRef GetSourceATopBlendPipeline(ContentContextOptions opts) const;
PipelineRef GetSourceBlendPipeline(ContentContextOptions opts) const;
PipelineRef GetSourceInBlendPipeline(ContentContextOptions opts) const;
PipelineRef GetSourceOutBlendPipeline(ContentContextOptions opts) const;
PipelineRef GetSourceOverBlendPipeline(ContentContextOptions opts) const;
PipelineRef GetSrgbToLinearFilterPipeline(ContentContextOptions opts) const;
PipelineRef GetSweepGradientFillPipeline(ContentContextOptions opts) const;
PipelineRef GetSweepGradientSSBOFillPipeline( ContentContextOptions opts) const;
PipelineRef GetSweepGradientUniformFillPipeline(ContentContextOptions opts) const;
PipelineRef GetTexturePipeline(ContentContextOptions opts) const;
PipelineRef GetTextureStrictSrcPipeline(ContentContextOptions opts) const;
PipelineRef GetTiledTexturePipeline(ContentContextOptions opts) const;
PipelineRef GetXorBlendPipeline(ContentContextOptions opts) const;
PipelineRef GetYUVToRGBFilterPipeline(ContentContextOptions opts) const;
#ifdef IMPELLER_ENABLE_OPENGLES
PipelineRef GetDownsampleTextureGlesPipeline(ContentContextOptions opts) const;
PipelineRef GetTiledTextureExternalPipeline(ContentContextOptions opts) const;
PipelineRef GetTiledTextureUvExternalPipeline(ContentContextOptions opts) const;
#endif // IMPELLER_ENABLE_OPENGLES
// clang-format on
// An empty 1x1 texture for binding drawVertices/drawAtlas or other cases
// that don't always have a texture (due to blending).
std::shared_ptr<Texture> GetEmptyTexture() const;
std::shared_ptr<Context> GetContext() const;
const Capabilities& GetDeviceCapabilities() const;
void SetWireframe(bool wireframe);
using SubpassCallback =
std::function<bool(const ContentContext&, RenderPass&)>;
/// @brief Creates a new texture of size `texture_size` and calls
/// `subpass_callback` with a `RenderPass` for drawing to the texture.
fml::StatusOr<RenderTarget> MakeSubpass(
std::string_view label,
ISize texture_size,
const std::shared_ptr<CommandBuffer>& command_buffer,
const SubpassCallback& subpass_callback,
bool msaa_enabled = true,
bool depth_stencil_enabled = false,
int32_t mip_count = 1) const;
/// Makes a subpass that will render to `subpass_target`.
fml::StatusOr<RenderTarget> 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<LazyGlyphAtlas>& GetLazyGlyphAtlas() const {
return lazy_glyph_atlas_;
}
const std::shared_ptr<RenderTargetAllocator>& GetRenderTargetCache() const {
return render_target_cache_;
}
/// RuntimeEffect pipelines must be obtained via this method to avoid
/// re-creating them every frame.
///
/// The unique_entrypoint_name comes from RuntimeEffect::GetEntrypoint.
/// Impellerc generates a unique entrypoint name for runtime effect shaders
/// based on the input file name and shader stage.
///
/// The create_callback is synchronously invoked exactly once if a cached
/// pipeline is not found.
PipelineRef GetCachedRuntimeEffectPipeline(
const std::string& unique_entrypoint_name,
const ContentContextOptions& options,
const std::function<std::shared_ptr<Pipeline<PipelineDescriptor>>()>&
create_callback) const;
/// Used by hot reload/hot restart to clear a cached pipeline from
/// GetCachedRuntimeEffectPipeline.
void ClearCachedRuntimeEffectPipeline(
const std::string& unique_entrypoint_name) const;
/// @brief Retrieve the currnent host buffer for transient storage.
///
/// This is only safe to use from the raster threads. Other threads should
/// allocate their own device buffers.
HostBuffer& GetTransientsBuffer() const { return *host_buffer_; }
private:
std::shared_ptr<Context> context_;
std::shared_ptr<LazyGlyphAtlas> lazy_glyph_atlas_;
/// Run backend specific additional setup and create common shader variants.
///
/// This bootstrap is intended to improve the performance of several
/// first frame benchmarks that are tracked in the flutter device lab.
/// The workload includes initializing commonly used but not default
/// shader variants, as well as forcing driver initialization.
void InitializeCommonlyUsedShadersIfNeeded() const;
struct RuntimeEffectPipelineKey {
std::string unique_entrypoint_name;
ContentContextOptions options;
struct Hash {
std::size_t operator()(const RuntimeEffectPipelineKey& key) const {
return fml::HashCombine(key.unique_entrypoint_name,
key.options.ToKey());
}
};
struct Equal {
constexpr bool operator()(const RuntimeEffectPipelineKey& lhs,
const RuntimeEffectPipelineKey& rhs) const {
return lhs.unique_entrypoint_name == rhs.unique_entrypoint_name &&
lhs.options.ToKey() == rhs.options.ToKey();
}
};
};
mutable std::unordered_map<RuntimeEffectPipelineKey,
std::shared_ptr<Pipeline<PipelineDescriptor>>,
RuntimeEffectPipelineKey::Hash,
RuntimeEffectPipelineKey::Equal>
runtime_effect_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:
Variants() = default;
void Set(const ContentContextOptions& options,
std::unique_ptr<PipelineHandleT> 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<PipelineHandleT> pipeline) {
default_options_ = options;
if (pipeline) {
Set(options, std::move(pipeline));
}
}
void SetDefaultDescriptor(std::optional<PipelineDescriptor> desc) {
desc_ = std::move(desc);
}
void CreateDefault(const Context& context,
const ContentContextOptions& options,
const std::vector<Scalar>& constants = {}) {
auto desc = PipelineHandleT::Builder::MakeDefaultPipelineDescriptor(
context, constants);
if (!desc.has_value()) {
VALIDATION_LOG << "Failed to create default pipeline.";
return;
}
options.ApplyToPipelineDescriptor(*desc);
desc_ = desc;
if (context.GetFlags().lazy_shader_mode) {
SetDefault(options, nullptr);
} else {
SetDefault(options, std::make_unique<PipelineHandleT>(context, desc_,
/*async=*/true));
}
}
PipelineHandleT* 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;
}
bool IsDefault(const ContentContextOptions& opts) {
return default_options_.has_value() &&
opts.ToKey() == default_options_.value().ToKey();
}
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));
return Get(default_options_.value());
}
size_t GetPipelineCount() const { return pipelines_.size(); }
private:
std::optional<PipelineDescriptor> desc_;
std::optional<ContentContextOptions> default_options_;
std::vector<std::pair<uint64_t, std::unique_ptr<PipelineHandleT>>>
pipelines_;
Variants(const Variants&) = delete;
Variants& operator=(const Variants&) = delete;
};
// These are mutable because while the prototypes are created eagerly, any
// variants requested from that are lazily created and cached in the variants
// map.
// clang-format off
mutable Variants<BlendColorBurnPipeline> blend_colorburn_pipelines_;
mutable Variants<BlendColorDodgePipeline> blend_colordodge_pipelines_;
mutable Variants<BlendColorPipeline> blend_color_pipelines_;
mutable Variants<BlendDarkenPipeline> blend_darken_pipelines_;
mutable Variants<BlendDifferencePipeline> blend_difference_pipelines_;
mutable Variants<BlendExclusionPipeline> blend_exclusion_pipelines_;
mutable Variants<BlendHardLightPipeline> blend_hardlight_pipelines_;
mutable Variants<BlendHuePipeline> blend_hue_pipelines_;
mutable Variants<BlendLightenPipeline> blend_lighten_pipelines_;
mutable Variants<BlendLuminosityPipeline> blend_luminosity_pipelines_;
mutable Variants<BlendMultiplyPipeline> blend_multiply_pipelines_;
mutable Variants<BlendOverlayPipeline> blend_overlay_pipelines_;
mutable Variants<BlendSaturationPipeline> blend_saturation_pipelines_;
mutable Variants<BlendScreenPipeline> blend_screen_pipelines_;
mutable Variants<BlendSoftLightPipeline> blend_softlight_pipelines_;
mutable Variants<BorderMaskBlurPipeline> border_mask_blur_pipelines_;
mutable Variants<ClipPipeline> clip_pipelines_;
mutable Variants<ColorMatrixColorFilterPipeline> color_matrix_color_filter_pipelines_;
mutable Variants<ConicalGradientFillConicalPipeline> conical_gradient_fill_pipelines_;
mutable Variants<ConicalGradientFillRadialPipeline> conical_gradient_fill_radial_pipelines_;
mutable Variants<ConicalGradientFillStripPipeline> conical_gradient_fill_strip_pipelines_;
mutable Variants<ConicalGradientFillStripRadialPipeline> conical_gradient_fill_strip_and_radial_pipelines_;
mutable Variants<ConicalGradientSSBOFillPipeline> conical_gradient_ssbo_fill_pipelines_;
mutable Variants<ConicalGradientSSBOFillPipeline> conical_gradient_ssbo_fill_radial_pipelines_;
mutable Variants<ConicalGradientSSBOFillPipeline> conical_gradient_ssbo_fill_strip_and_radial_pipelines_;
mutable Variants<ConicalGradientSSBOFillPipeline> conical_gradient_ssbo_fill_strip_pipelines_;
mutable Variants<ConicalGradientUniformFillConicalPipeline> conical_gradient_uniform_fill_pipelines_;
mutable Variants<ConicalGradientUniformFillRadialPipeline> conical_gradient_uniform_fill_radial_pipelines_;
mutable Variants<ConicalGradientUniformFillStripPipeline> conical_gradient_uniform_fill_strip_pipelines_;
mutable Variants<ConicalGradientUniformFillStripRadialPipeline> conical_gradient_uniform_fill_strip_and_radial_pipelines_;
mutable Variants<FastGradientPipeline> fast_gradient_pipelines_;
mutable Variants<FramebufferBlendColorBurnPipeline> framebuffer_blend_colorburn_pipelines_;
mutable Variants<FramebufferBlendColorDodgePipeline> framebuffer_blend_colordodge_pipelines_;
mutable Variants<FramebufferBlendColorPipeline> framebuffer_blend_color_pipelines_;
mutable Variants<FramebufferBlendDarkenPipeline> framebuffer_blend_darken_pipelines_;
mutable Variants<FramebufferBlendDifferencePipeline> framebuffer_blend_difference_pipelines_;
mutable Variants<FramebufferBlendExclusionPipeline> framebuffer_blend_exclusion_pipelines_;
mutable Variants<FramebufferBlendHardLightPipeline> framebuffer_blend_hardlight_pipelines_;
mutable Variants<FramebufferBlendHuePipeline> framebuffer_blend_hue_pipelines_;
mutable Variants<FramebufferBlendLightenPipeline> framebuffer_blend_lighten_pipelines_;
mutable Variants<FramebufferBlendLuminosityPipeline> framebuffer_blend_luminosity_pipelines_;
mutable Variants<FramebufferBlendMultiplyPipeline> framebuffer_blend_multiply_pipelines_;
mutable Variants<FramebufferBlendOverlayPipeline> framebuffer_blend_overlay_pipelines_;
mutable Variants<FramebufferBlendSaturationPipeline> framebuffer_blend_saturation_pipelines_;
mutable Variants<FramebufferBlendScreenPipeline> framebuffer_blend_screen_pipelines_;
mutable Variants<FramebufferBlendSoftLightPipeline> framebuffer_blend_softlight_pipelines_;
mutable Variants<GaussianBlurPipeline> gaussian_blur_pipelines_;
mutable Variants<GlyphAtlasPipeline> glyph_atlas_pipelines_;
mutable Variants<LinearGradientFillPipeline> linear_gradient_fill_pipelines_;
mutable Variants<LinearGradientSSBOFillPipeline> linear_gradient_ssbo_fill_pipelines_;
mutable Variants<LinearGradientUniformFillPipeline> linear_gradient_uniform_fill_pipelines_;
mutable Variants<LinearToSrgbFilterPipeline> linear_to_srgb_filter_pipelines_;
mutable Variants<MorphologyFilterPipeline> morphology_filter_pipelines_;
mutable Variants<PorterDuffBlendPipeline> clear_blend_pipelines_;
mutable Variants<PorterDuffBlendPipeline> destination_a_top_blend_pipelines_;
mutable Variants<PorterDuffBlendPipeline> destination_blend_pipelines_;
mutable Variants<PorterDuffBlendPipeline> destination_in_blend_pipelines_;
mutable Variants<PorterDuffBlendPipeline> destination_out_blend_pipelines_;
mutable Variants<PorterDuffBlendPipeline> destination_over_blend_pipelines_;
mutable Variants<PorterDuffBlendPipeline> modulate_blend_pipelines_;
mutable Variants<PorterDuffBlendPipeline> plus_blend_pipelines_;
mutable Variants<PorterDuffBlendPipeline> screen_blend_pipelines_;
mutable Variants<PorterDuffBlendPipeline> source_a_top_blend_pipelines_;
mutable Variants<PorterDuffBlendPipeline> source_blend_pipelines_;
mutable Variants<PorterDuffBlendPipeline> source_in_blend_pipelines_;
mutable Variants<PorterDuffBlendPipeline> source_out_blend_pipelines_;
mutable Variants<PorterDuffBlendPipeline> source_over_blend_pipelines_;
mutable Variants<PorterDuffBlendPipeline> xor_blend_pipelines_;
mutable Variants<RadialGradientFillPipeline> radial_gradient_fill_pipelines_;
mutable Variants<RadialGradientSSBOFillPipeline> radial_gradient_ssbo_fill_pipelines_;
mutable Variants<RadialGradientUniformFillPipeline> radial_gradient_uniform_fill_pipelines_;
mutable Variants<RRectBlurPipeline> rrect_blur_pipelines_;
mutable Variants<SolidFillPipeline> solid_fill_pipelines_;
mutable Variants<SrgbToLinearFilterPipeline> srgb_to_linear_filter_pipelines_;
mutable Variants<SweepGradientFillPipeline> sweep_gradient_fill_pipelines_;
mutable Variants<SweepGradientSSBOFillPipeline> sweep_gradient_ssbo_fill_pipelines_;
mutable Variants<SweepGradientUniformFillPipeline> sweep_gradient_uniform_fill_pipelines_;
mutable Variants<TextureDownsamplePipeline> texture_downsample_pipelines_;
mutable Variants<TexturePipeline> texture_pipelines_;
mutable Variants<TextureStrictSrcPipeline> texture_strict_src_pipelines_;
mutable Variants<TiledTexturePipeline> tiled_texture_pipelines_;
mutable Variants<VerticesUberShader> vertices_uber_shader_;
mutable Variants<YUVToRGBFilterPipeline> yuv_to_rgb_filter_pipelines_;
#ifdef IMPELLER_ENABLE_OPENGLES
mutable Variants<TiledTextureExternalPipeline> tiled_texture_external_pipelines_;
mutable Variants<TextureDownsampleGlesPipeline> texture_downsample_gles_pipelines_;
mutable Variants<TiledTextureUvExternalPipeline> tiled_texture_uv_external_pipelines_;
#endif // IMPELLER_ENABLE_OPENGLES
// clang-format on
template <class TypedPipeline>
PipelineRef GetPipeline(Variants<TypedPipeline>& container,
ContentContextOptions opts) const {
TypedPipeline* pipeline = CreateIfNeeded(container, opts);
if (!pipeline) {
return raw_ptr<Pipeline<PipelineDescriptor>>();
}
return raw_ptr(pipeline->WaitAndGet());
}
template <class RenderPipelineHandleT>
RenderPipelineHandleT* CreateIfNeeded(
Variants<RenderPipelineHandleT>& container,
ContentContextOptions opts) const {
if (!IsValid()) {
return nullptr;
}
if (wireframe_) {
opts.wireframe = true;
}
if (RenderPipelineHandleT* found = container.Get(opts)) {
return found;
}
RenderPipelineHandleT* default_handle = container.GetDefault(*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();
if (!pipeline) {
return nullptr;
}
auto variant_future = pipeline->CreateVariant(
/*async=*/false, [&opts, variants_count = container.GetPipelineCount()](
PipelineDescriptor& desc) {
opts.ApplyToPipelineDescriptor(desc);
desc.SetLabel(
SPrintF("%s V#%zu", desc.GetLabel().data(), 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);
}
bool is_valid_ = false;
std::shared_ptr<Tessellator> tessellator_;
std::shared_ptr<RenderTargetAllocator> render_target_cache_;
std::shared_ptr<HostBuffer> host_buffer_;
std::shared_ptr<Texture> empty_texture_;
bool wireframe_ = false;
ContentContext(const ContentContext&) = delete;
ContentContext& operator=(const ContentContext&) = delete;
};
} // namespace impeller
#endif // FLUTTER_IMPELLER_ENTITY_CONTENTS_CONTENT_CONTEXT_H_