blob: 673e162c578810e58b8425f44dffa63cc45851e3 [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.
#pragma once
#include <functional>
#include <memory>
#include <optional>
#include <vector>
#include "flutter/fml/macros.h"
#include "impeller/core/texture.h"
#include "impeller/entity/contents/contents.h"
#include "impeller/entity/contents/filters/filter_contents.h"
#include "impeller/entity/entity.h"
#include "impeller/entity/entity_pass_delegate.h"
#include "impeller/entity/inline_pass_context.h"
#include "impeller/renderer/render_target.h"
#include "impeller/typographer/lazy_glyph_atlas.h"
namespace impeller {
class ContentContext;
class EntityPass {
public:
/// Elements are renderable items in the `EntityPass`. Each can either be an
/// `Entity` or a child `EntityPass`.
///
/// When the element is a child `EntityPass`, it may be rendered to an
/// offscreen texture and converted into an `Entity` that draws the texture
/// into the current pass, or its children may be collapsed into the current
///
/// `EntityPass`. Elements are converted to Entities in
/// `GetEntityForElement()`.
using Element = std::variant<Entity, std::unique_ptr<EntityPass>>;
using BackdropFilterProc = std::function<std::shared_ptr<FilterContents>(
FilterInput::Ref,
const Matrix& effect_transform,
bool is_subpass)>;
struct StencilCoverageLayer {
std::optional<Rect> coverage;
size_t stencil_depth;
};
using StencilCoverageStack = std::vector<StencilCoverageLayer>;
EntityPass();
~EntityPass();
void SetDelegate(std::unique_ptr<EntityPassDelegate> delgate);
size_t GetSubpassesDepth() const;
std::unique_ptr<EntityPass> Clone() const;
void AddEntity(Entity entity);
void SetElements(std::vector<Element> elements);
EntityPass* AddSubpass(std::unique_ptr<EntityPass> pass);
EntityPass* GetSuperpass() const;
bool Render(ContentContext& renderer,
const RenderTarget& render_target) const;
void IterateAllEntities(const std::function<bool(Entity&)>& iterator);
/// @brief Iterate entities in this pass up until the first subpass is found.
/// This is useful for limiting look-ahead optimizations.
///
/// @return Returns whether a subpass was encountered.
bool IterateUntilSubpass(const std::function<bool(Entity&)>& iterator);
/// @brief Return the number of elements on this pass.
size_t GetElementCount() const;
void SetTransformation(Matrix xformation);
void SetStencilDepth(size_t stencil_depth);
void SetBlendMode(BlendMode blend_mode);
void SetClearColor(Color clear_color);
Color GetClearColor() const;
void SetBackdropFilter(std::optional<BackdropFilterProc> proc);
void SetEnableOffscreenCheckerboard(bool enabled);
std::optional<Rect> GetSubpassCoverage(
const EntityPass& subpass,
std::optional<Rect> coverage_limit) const;
std::optional<Rect> GetElementsCoverage(
std::optional<Rect> coverage_limit) const;
private:
struct EntityResult {
enum Status {
/// The entity was successfully resolved and can be rendered.
kSuccess,
/// An unexpected rendering error occurred while resolving the Entity.
kFailure,
/// The entity should be skipped because rendering it will contribute
/// nothing to the frame.
kSkip,
};
/// @brief The resulting entity that should be rendered. If `std::nullopt`,
/// there is nothing to render.
Entity entity;
/// @brief This is set to `false` if there was an unexpected rendering
/// error while resolving the Entity.
Status status = kFailure;
static EntityResult Success(const Entity& e) { return {e, kSuccess}; }
static EntityResult Failure() { return {{}, kFailure}; }
static EntityResult Skip() { return {{}, kSkip}; }
};
EntityResult GetEntityForElement(const EntityPass::Element& element,
ContentContext& renderer,
InlinePassContext& pass_context,
ISize root_pass_size,
Point global_pass_position,
uint32_t pass_depth,
StencilCoverageStack& stencil_coverage_stack,
size_t stencil_depth_floor) const;
/// @brief OnRender is the internal command recording routine for
/// `EntityPass`. Its job is to walk through each `Element` which
/// was appended to the scene (either an `Entity` via `AddEntity()`
/// or a child `EntityPass` via `AddSubpass()`) and render them to
/// the given `pass_target`.
/// @param[in] renderer The Contents context, which manages
/// pipeline state.
/// @param[in] root_pass_size The size of the texture being
/// rendered into at the root of the
/// `EntityPass` tree. This is the size
/// of the `RenderTarget` color
/// attachment passed to the public
/// `EntityPass::Render` method.
/// @param[out] pass_target Stores the render target that should
/// be used for rendering.
/// @param[in] global_pass_position The position that this `EntityPass`
/// will be drawn to the parent pass
/// relative to the root pass origin.
/// Used for offsetting drawn `Element`s,
/// whose origins are all in root
/// pass/screen space,
/// @param[in] local_pass_position The position that this `EntityPass`
/// will be drawn to the parent pass
/// relative to the parent pass origin.
/// Used for positioning backdrop
/// filters.
/// @param[in] pass_depth The tree depth of the `EntityPass` at
/// render time. Only used for labeling
/// and debugging purposes. This can vary
/// depending on whether passes are
/// collapsed or not.
/// @param[in] stencil_coverage_stack A global stack of coverage rectangles
/// for the stencil buffer at each depth.
/// Higher depths are more restrictive.
/// Used to cull Elements that we
/// know won't result in a visible
/// change.
/// @param[in] stencil_depth_floor The stencil depth that a value of
/// zero corresponds to in the given
/// `pass_target` stencil buffer.
/// When new `pass_target`s are created
/// for subpasses, their stencils are
/// initialized at zero, and so this
/// value is used to offset Entity clip
/// depths to match the stencil.
/// @param[in] backdrop_filter_contents Optional. Is supplied, this contents
/// is rendered prior to anything else in
/// the `EntityPass`, offset by the
/// `local_pass_position`.
/// @param[in] collapsed_parent_pass Optional. If supplied, this
/// `InlinePassContext` state is used to
/// begin rendering elements instead of
/// creating a new `RenderPass`. This
/// "collapses" the Elements into the
/// parent pass.
bool OnRender(ContentContext& renderer,
ISize root_pass_size,
EntityPassTarget& pass_target,
Point global_pass_position,
Point local_pass_position,
uint32_t pass_depth,
StencilCoverageStack& stencil_coverage_stack,
size_t stencil_depth_floor = 0,
std::shared_ptr<Contents> backdrop_filter_contents = nullptr,
const std::optional<InlinePassContext::RenderPassResult>&
collapsed_parent_pass = std::nullopt) const;
/// The list of renderable items in the scene. Each of these items is
/// evaluated and recorded to an `EntityPassTarget` by the `OnRender` method.
std::vector<Element> elements_;
EntityPass* superpass_ = nullptr;
Matrix xformation_;
size_t stencil_depth_ = 0u;
BlendMode blend_mode_ = BlendMode::kSourceOver;
bool flood_clip_ = false;
Color clear_color_ = Color::BlackTransparent();
bool enable_offscreen_debug_checkerboard_ = false;
/// These values are incremented whenever something is added to the pass that
/// requires reading from the backdrop texture. Currently, this can happen in
/// the following scenarios:
/// 1. An entity with an "advanced blend" is added to the pass.
/// 2. A subpass with a backdrop filter is added to the pass.
/// These are tracked as separate values because we may ignore
/// blend_reads_from_pass_texture_ if the device supports framebuffer based
/// advanced blends.
uint32_t advanced_blend_reads_from_pass_texture_ = 0;
uint32_t backdrop_filter_reads_from_pass_texture_ = 0;
uint32_t GetTotalPassReads(ContentContext& renderer) const;
std::optional<BackdropFilterProc> backdrop_filter_proc_ = std::nullopt;
std::unique_ptr<EntityPassDelegate> delegate_ =
EntityPassDelegate::MakeDefault();
FML_DISALLOW_COPY_AND_ASSIGN(EntityPass);
};
} // namespace impeller