[go: nahoru, domu]

Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Impeller] Document tricky bits in EntityPass, make positioning less confusing #40636

Merged
merged 1 commit into from
Mar 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 68 additions & 33 deletions impeller/entity/entity_pass.cc
Original file line number Diff line number Diff line change
Expand Up @@ -211,9 +211,15 @@ bool EntityPass::Render(ContentContext& renderer,
auto offscreen_target =
CreateRenderTarget(renderer, render_target.GetRenderTargetSize(), true);

if (!OnRender(
renderer, offscreen_target.GetRenderTarget().GetRenderTargetSize(),
offscreen_target, Point(), Point(), 0, stencil_coverage_stack)) {
if (!OnRender(renderer, // renderer
offscreen_target.GetRenderTarget()
.GetRenderTargetSize(), // root_pass_size
offscreen_target, // pass_target
Point(), // global_pass_position
Point(), // local_pass_position
0, // pass_depth
stencil_coverage_stack // stencil_coverage_stack
)) {
return false;
}

Expand Down Expand Up @@ -267,16 +273,22 @@ bool EntityPass::Render(ContentContext& renderer,
render_target,
renderer.GetDeviceCapabilities().SupportsReadFromResolve());

return OnRender(renderer, render_target.GetRenderTargetSize(), pass_target,
Point(), Point(), 0, stencil_coverage_stack);
return OnRender( //
renderer, // renderer
render_target.GetRenderTargetSize(), // root_pass_size
pass_target, // pass_target
Point(), // global_pass_position
Point(), // local_pass_position
0, // pass_depth
stencil_coverage_stack); // stencil_coverage_stack
}

EntityPass::EntityResult EntityPass::GetEntityForElement(
const EntityPass::Element& element,
ContentContext& renderer,
InlinePassContext& pass_context,
ISize root_pass_size,
Point position,
Point global_pass_position,
uint32_t pass_depth,
StencilCoverageStack& stencil_coverage_stack,
size_t stencil_depth_floor) const {
Expand All @@ -288,12 +300,12 @@ EntityPass::EntityResult EntityPass::GetEntityForElement(

if (const auto& entity = std::get_if<Entity>(&element)) {
element_entity = *entity;
if (!position.IsZero()) {
if (!global_pass_position.IsZero()) {
// If the pass image is going to be rendered with a non-zero position,
// apply the negative translation to entity copies before rendering them
// so that they'll end up rendering to the correct on-screen position.
element_entity.SetTransformation(
Matrix::MakeTranslation(Vector3(-position)) *
Matrix::MakeTranslation(Vector3(-global_pass_position)) *
element_entity.GetTransformation());
}
}
Expand All @@ -313,10 +325,18 @@ EntityPass::EntityResult EntityPass::GetEntityForElement(
if (!subpass->backdrop_filter_proc_.has_value() &&
subpass->delegate_->CanCollapseIntoParentPass(subpass)) {
// Directly render into the parent target and move on.
if (!subpass->OnRender(renderer, root_pass_size,
pass_context.GetPassTarget(), position, position,
pass_depth, stencil_coverage_stack, stencil_depth_,
nullptr, pass_context.GetRenderPass(pass_depth))) {
if (!subpass->OnRender(
renderer, // renderer
root_pass_size, // root_pass_size
pass_context.GetPassTarget(), // pass_target
global_pass_position, // global_pass_position
Point(), // local_pass_position
pass_depth, // pass_depth
stencil_coverage_stack, // stencil_coverage_stack
stencil_depth_, // stencil_depth_floor
nullptr, // backdrop_filter_contents
pass_context.GetRenderPass(pass_depth) // collapsed_parent_pass
)) {
return EntityPass::EntityResult::Failure();
}
return EntityPass::EntityResult::Skip();
Expand All @@ -340,14 +360,15 @@ EntityPass::EntityResult EntityPass::GetEntityForElement(
auto subpass_coverage =
GetSubpassCoverage(*subpass, Rect::MakeSize(root_pass_size));
if (subpass->cover_whole_screen_) {
subpass_coverage = Rect(position, Size(pass_context.GetPassTarget()
.GetRenderTarget()
.GetRenderTargetSize()));
subpass_coverage =
Rect(global_pass_position, Size(pass_context.GetPassTarget()
.GetRenderTarget()
.GetRenderTargetSize()));
}
if (backdrop_filter_contents) {
auto backdrop_coverage = backdrop_filter_contents->GetCoverage(Entity{});
if (backdrop_coverage.has_value()) {
backdrop_coverage->origin += position;
backdrop_coverage->origin += global_pass_position;

subpass_coverage =
subpass_coverage.has_value()
Expand Down Expand Up @@ -379,7 +400,8 @@ EntityPass::EntityResult EntityPass::GetEntityForElement(
auto offscreen_texture_contents =
subpass->delegate_->CreateContentsForSubpassTarget(
subpass_texture,
Matrix::MakeTranslation(Vector3{-position}) * subpass->xformation_);
Matrix::MakeTranslation(Vector3{-global_pass_position}) *
subpass->xformation_);

if (!offscreen_texture_contents) {
// This is an error because the subpass delegate said the pass couldn't
Expand All @@ -395,18 +417,25 @@ EntityPass::EntityResult EntityPass::GetEntityForElement(

// Stencil textures aren't shared between EntityPasses (as much of the
// time they are transient).
if (!subpass->OnRender(renderer, root_pass_size, subpass_target,
subpass_coverage->origin, position, ++pass_depth,
stencil_coverage_stack, subpass->stencil_depth_,
backdrop_filter_contents)) {
if (!subpass->OnRender(renderer, // renderer
root_pass_size, // root_pass_size
subpass_target, // pass_target
subpass_coverage->origin, // global_pass_position
subpass_coverage->origin -
global_pass_position, // local_pass_position
++pass_depth, // pass_depth
stencil_coverage_stack, // stencil_coverage_stack
subpass->stencil_depth_, // stencil_depth_floor
backdrop_filter_contents // backdrop_filter_contents
)) {
return EntityPass::EntityResult::Failure();
}

element_entity.SetContents(std::move(offscreen_texture_contents));
element_entity.SetStencilDepth(subpass->stencil_depth_);
element_entity.SetBlendMode(subpass->blend_mode_);
element_entity.SetTransformation(
Matrix::MakeTranslation(Vector3(subpass_coverage->origin - position)));
element_entity.SetTransformation(Matrix::MakeTranslation(
Vector3(subpass_coverage->origin - global_pass_position)));
} else {
FML_UNREACHABLE();
}
Expand All @@ -417,8 +446,8 @@ EntityPass::EntityResult EntityPass::GetEntityForElement(
bool EntityPass::OnRender(ContentContext& renderer,
ISize root_pass_size,
EntityPassTarget& pass_target,
Point position,
Point parent_position,
Point global_pass_position,
Point local_pass_position,
uint32_t pass_depth,
StencilCoverageStack& stencil_coverage_stack,
size_t stencil_depth_floor,
Expand All @@ -437,7 +466,7 @@ bool EntityPass::OnRender(ContentContext& renderer,

auto render_element = [&stencil_depth_floor, &pass_context, &pass_depth,
&renderer, &stencil_coverage_stack,
&position](Entity& element_entity) {
&global_pass_position](Entity& element_entity) {
auto result = pass_context.GetRenderPass(pass_depth);

if (!result.pass) {
Expand Down Expand Up @@ -469,7 +498,7 @@ bool EntityPass::OnRender(ContentContext& renderer,
if (current_stencil_coverage.has_value()) {
// Entity transforms are relative to the current pass position, so we need
// to check stencil coverage in the same space.
current_stencil_coverage->origin -= position;
current_stencil_coverage->origin -= global_pass_position;
}

if (!element_entity.ShouldRender(current_stencil_coverage)) {
Expand All @@ -479,7 +508,7 @@ bool EntityPass::OnRender(ContentContext& renderer,
auto stencil_coverage =
element_entity.GetStencilCoverage(current_stencil_coverage);
if (stencil_coverage.coverage.has_value()) {
stencil_coverage.coverage->origin += position;
stencil_coverage.coverage->origin += global_pass_position;
}

switch (stencil_coverage.type) {
Expand Down Expand Up @@ -517,7 +546,7 @@ bool EntityPass::OnRender(ContentContext& renderer,
: std::nullopt;
if (restore_coverage.has_value()) {
// Make the coverage rectangle relative to the current pass.
restore_coverage->origin -= position;
restore_coverage->origin -= global_pass_position;
}
stencil_coverage_stack.resize(restoration_depth + 1);

Expand Down Expand Up @@ -549,16 +578,22 @@ bool EntityPass::OnRender(ContentContext& renderer,
Entity backdrop_entity;
backdrop_entity.SetContents(std::move(backdrop_filter_contents));
backdrop_entity.SetTransformation(
Matrix::MakeTranslation(Vector3(parent_position - position)));
Matrix::MakeTranslation(Vector3(local_pass_position)));
backdrop_entity.SetStencilDepth(stencil_depth_floor);

render_element(backdrop_entity);
}

for (const auto& element : elements_) {
EntityResult result = GetEntityForElement(
element, renderer, pass_context, root_pass_size, position, pass_depth,
stencil_coverage_stack, stencil_depth_floor);
EntityResult result =
GetEntityForElement(element, // element
renderer, // renderer
pass_context, // pass_context
root_pass_size, // root_pass_size
global_pass_position, // global_pass_position
pass_depth, // pass_depth
stencil_coverage_stack, // stencil_coverage_stack
stencil_depth_floor); // stencil_depth_floor

switch (result.status) {
case EntityResult::kSuccess:
Expand Down
77 changes: 72 additions & 5 deletions impeller/entity/entity_pass.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,17 @@ 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,
Expand Down Expand Up @@ -104,7 +114,7 @@ class EntityPass {
/// error while resolving the Entity.
Status status = kFailure;

static EntityResult Success(Entity e) { return {e, kSuccess}; }
static EntityResult Success(const Entity& e) { return {e, kSuccess}; }
static EntityResult Failure() { return {{}, kFailure}; }
static EntityResult Skip() { return {{}, kSkip}; }
};
Expand All @@ -113,23 +123,80 @@ class EntityPass {
ContentContext& renderer,
InlinePassContext& pass_context,
ISize root_pass_size,
Point position,
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& render_target,
Point position,
Point parent_position,
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,
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;
Expand Down