Revert "[Impeller] Reland 2: Implement draw order optimization. (#54268) (#54325)
Manual revert of https://github.com/flutter/engine/pull/54268, since the time expired for automatic reverting.
@jason-simmons found this patch to be causing a regression in a downstream app. Some draws are getting clipped away, and disabling the scissor fixes it. So there is likely still a case not being handled correctly with the clip replay or subpass draw deferral behavior.
diff --git a/ci/licenses_golden/excluded_files b/ci/licenses_golden/excluded_files
index 65321d1..4420a94 100644
--- a/ci/licenses_golden/excluded_files
+++ b/ci/licenses_golden/excluded_files
@@ -165,7 +165,6 @@
../../../flutter/impeller/entity/contents/host_buffer_unittests.cc
../../../flutter/impeller/entity/contents/test
../../../flutter/impeller/entity/contents/tiled_texture_contents_unittests.cc
-../../../flutter/impeller/entity/draw_order_resolver_unittests.cc
../../../flutter/impeller/entity/entity_pass_target_unittests.cc
../../../flutter/impeller/entity/entity_pass_unittests.cc
../../../flutter/impeller/entity/entity_unittests.cc
diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter
index 28bbe47..bd838fd 100644
--- a/ci/licenses_golden/licenses_flutter
+++ b/ci/licenses_golden/licenses_flutter
@@ -42127,8 +42127,6 @@
ORIGIN: ../../../flutter/impeller/entity/contents/tiled_texture_contents.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/contents/vertices_contents.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/contents/vertices_contents.h + ../../../flutter/LICENSE
-ORIGIN: ../../../flutter/impeller/entity/draw_order_resolver.cc + ../../../flutter/LICENSE
-ORIGIN: ../../../flutter/impeller/entity/draw_order_resolver.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/entity.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/entity.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/entity_pass.cc + ../../../flutter/LICENSE
@@ -45011,8 +45009,6 @@
FILE: ../../../flutter/impeller/entity/contents/tiled_texture_contents.h
FILE: ../../../flutter/impeller/entity/contents/vertices_contents.cc
FILE: ../../../flutter/impeller/entity/contents/vertices_contents.h
-FILE: ../../../flutter/impeller/entity/draw_order_resolver.cc
-FILE: ../../../flutter/impeller/entity/draw_order_resolver.h
FILE: ../../../flutter/impeller/entity/entity.cc
FILE: ../../../flutter/impeller/entity/entity.h
FILE: ../../../flutter/impeller/entity/entity_pass.cc
diff --git a/impeller/entity/BUILD.gn b/impeller/entity/BUILD.gn
index c75ca72..d91d56c 100644
--- a/impeller/entity/BUILD.gn
+++ b/impeller/entity/BUILD.gn
@@ -166,8 +166,6 @@
"contents/tiled_texture_contents.h",
"contents/vertices_contents.cc",
"contents/vertices_contents.h",
- "draw_order_resolver.cc",
- "draw_order_resolver.h",
"entity.cc",
"entity.h",
"entity_pass.cc",
@@ -250,7 +248,6 @@
"contents/filters/matrix_filter_contents_unittests.cc",
"contents/host_buffer_unittests.cc",
"contents/tiled_texture_contents_unittests.cc",
- "draw_order_resolver_unittests.cc",
"entity_pass_target_unittests.cc",
"entity_pass_unittests.cc",
"entity_playground.cc",
diff --git a/impeller/entity/contents/color_source_contents.h b/impeller/entity/contents/color_source_contents.h
index 008674a..5f72b13 100644
--- a/impeller/entity/contents/color_source_contents.h
+++ b/impeller/entity/contents/color_source_contents.h
@@ -213,11 +213,6 @@
pass.SetVertexBuffer(std::move(geometry_result.vertex_buffer));
options.primitive_type = geometry_result.type;
- // Enable depth writing for all opaque entities in order to allow
- // reordering. Opaque entities are coerced to source blending by
- // `EntityPass::AddEntity`.
- options.depth_write_enabled = options.blend_mode == BlendMode::kSource;
-
// Take the pre-populated vertex shader uniform struct and set managed
// values.
frame_info.mvp = geometry_result.transform;
diff --git a/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc b/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc
index cf39b60..3fa906e 100644
--- a/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc
+++ b/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc
@@ -575,16 +575,16 @@
const ContentContext& renderer, const Entity& entity,
RenderPass& pass) mutable {
bool result = true;
+ blur_entity.SetClipDepth(entity.GetClipDepth());
+ blur_entity.SetTransform(entity.GetTransform() *
+ blurred_transform);
+ result = result && blur_entity.Render(renderer, pass);
snapshot_entity.SetTransform(
entity.GetTransform() *
Matrix::MakeScale(1.f / source_space_scalar) *
snapshot_transform);
snapshot_entity.SetClipDepth(entity.GetClipDepth());
result = result && snapshot_entity.Render(renderer, pass);
- blur_entity.SetClipDepth(entity.GetClipDepth());
- blur_entity.SetTransform(entity.GetTransform() *
- blurred_transform);
- result = result && blur_entity.Render(renderer, pass);
return result;
}),
fml::MakeCopyable([blur_entity = blur_entity.Clone(),
diff --git a/impeller/entity/contents/texture_contents.cc b/impeller/entity/contents/texture_contents.cc
index 7cc6bef..a2af33e 100644
--- a/impeller/entity/contents/texture_contents.cc
+++ b/impeller/entity/contents/texture_contents.cc
@@ -153,9 +153,6 @@
}
pipeline_options.primitive_type = PrimitiveType::kTriangleStrip;
- pipeline_options.depth_write_enabled =
- stencil_enabled_ && pipeline_options.blend_mode == BlendMode::kSource;
-
pass.SetPipeline(strict_source_rect_enabled_
? renderer.GetTextureStrictSrcPipeline(pipeline_options)
: renderer.GetTexturePipeline(pipeline_options));
diff --git a/impeller/entity/draw_order_resolver.cc b/impeller/entity/draw_order_resolver.cc
deleted file mode 100644
index 5afdf43..0000000
--- a/impeller/entity/draw_order_resolver.cc
+++ /dev/null
@@ -1,124 +0,0 @@
-// 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/draw_order_resolver.h"
-
-#include "flutter/fml/logging.h"
-#include "impeller/base/validation.h"
-
-namespace impeller {
-
-DrawOrderResolver::DrawOrderResolver() : draw_order_layers_({{}}){};
-
-void DrawOrderResolver::AddElement(size_t element_index, bool is_opaque) {
- DrawOrderLayer& layer = draw_order_layers_.back();
- if (is_opaque) {
- layer.opaque_elements.push_back(element_index);
- } else {
- layer.dependent_elements.push_back(element_index);
- }
-}
-void DrawOrderResolver::PushClip(size_t element_index) {
- draw_order_layers_.back().dependent_elements.push_back(element_index);
- draw_order_layers_.push_back({});
-};
-
-void DrawOrderResolver::PopClip() {
- if (draw_order_layers_.size() == 1u) {
- // This is likely recoverable, so don't assert.
- VALIDATION_LOG
- << "Attemped to pop the first draw order clip layer. This is a bug in "
- "`EntityPass`.";
- return;
- }
-
- DrawOrderLayer& layer = draw_order_layers_.back();
- DrawOrderLayer& parent_layer =
- draw_order_layers_[draw_order_layers_.size() - 2];
-
- layer.WriteCombinedDraws(parent_layer.dependent_elements, 0, 0);
-
- draw_order_layers_.pop_back();
-}
-
-void DrawOrderResolver::Flush() {
- FML_DCHECK(draw_order_layers_.size() >= 1u);
-
- size_t layer_count = draw_order_layers_.size();
-
- // Pop all clip layers.
- while (draw_order_layers_.size() > 1u) {
- PopClip();
- }
-
- // Move the root layer items into the sorted list.
- DrawOrderLayer& layer = draw_order_layers_.back();
- if (!first_root_flush_.has_value()) {
- // Record the first flush.
- first_root_flush_ = std::move(layer);
- layer = {};
- } else {
- // Write subsequent flushes into the sorted root list.
- layer.WriteCombinedDraws(sorted_elements_, 0, 0);
- layer.opaque_elements.clear();
- layer.dependent_elements.clear();
- }
-
- // Refill with empty layers.
- draw_order_layers_.resize(layer_count);
-}
-
-DrawOrderResolver::ElementRefs DrawOrderResolver::GetSortedDraws(
- size_t opaque_skip_count,
- size_t translucent_skip_count) const {
- FML_DCHECK(draw_order_layers_.size() == 1u)
- << "Attempted to get sorted draws before all clips were popped.";
-
- ElementRefs sorted_elements;
- sorted_elements.reserve(
- (first_root_flush_.has_value()
- ? first_root_flush_->opaque_elements.size() +
- first_root_flush_->dependent_elements.size()
- : 0u) +
- sorted_elements_.size() +
- draw_order_layers_.back().opaque_elements.size() +
- draw_order_layers_.back().dependent_elements.size());
-
- // Write all flushed items.
- if (first_root_flush_.has_value()) {
- first_root_flush_->WriteCombinedDraws(sorted_elements, opaque_skip_count,
- translucent_skip_count);
- }
- sorted_elements.insert(sorted_elements.end(), sorted_elements_.begin(),
- sorted_elements_.end());
-
- // Write any remaining non-flushed items.
- draw_order_layers_.back().WriteCombinedDraws(
- sorted_elements, first_root_flush_.has_value() ? 0 : opaque_skip_count,
- first_root_flush_.has_value() ? 0 : translucent_skip_count);
-
- return sorted_elements;
-}
-
-void DrawOrderResolver::DrawOrderLayer::WriteCombinedDraws(
- ElementRefs& destination,
- size_t opaque_skip_count,
- size_t translucent_skip_count) const {
- FML_DCHECK(opaque_skip_count <= opaque_elements.size());
- FML_DCHECK(translucent_skip_count <= dependent_elements.size());
-
- destination.reserve(destination.size() + //
- opaque_elements.size() - opaque_skip_count + //
- dependent_elements.size() - translucent_skip_count);
-
- // Draw backdrop-independent elements in reverse order first.
- destination.insert(destination.end(), opaque_elements.rbegin(),
- opaque_elements.rend() - opaque_skip_count);
- // Then, draw backdrop-dependent elements in their original order.
- destination.insert(destination.end(),
- dependent_elements.begin() + translucent_skip_count,
- dependent_elements.end());
-}
-
-} // namespace impeller
diff --git a/impeller/entity/draw_order_resolver.h b/impeller/entity/draw_order_resolver.h
deleted file mode 100644
index 5c8d7a9..0000000
--- a/impeller/entity/draw_order_resolver.h
+++ /dev/null
@@ -1,94 +0,0 @@
-// 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_DRAW_ORDER_RESOLVER_H_
-#define FLUTTER_IMPELLER_ENTITY_DRAW_ORDER_RESOLVER_H_
-
-#include <optional>
-#include <vector>
-
-namespace impeller {
-
-/// Helper that records draw indices in painter's order and sorts the draws into
-/// an optimized order based on translucency and clips.
-class DrawOrderResolver {
- public:
- using ElementRefs = std::vector<size_t>;
-
- DrawOrderResolver();
-
- void AddElement(size_t element_index, bool is_opaque);
-
- void PushClip(size_t element_index);
-
- void PopClip();
-
- void Flush();
-
- //-------------------------------------------------------------------------
- /// @brief Returns the sorted draws for the current draw order layer.
- /// This should only be called after all recording has finished.
- ///
- /// @param[in] opaque_skip_count The number of opaque elements to skip
- /// when appending the combined elements.
- /// This is used for the "clear color"
- /// optimization.
- /// @param[in] translucent_skip_count The number of translucent elements to
- /// skip when appending the combined
- /// elements. This is used for the
- /// "clear color" optimization.
- ///
- ElementRefs GetSortedDraws(size_t opaque_skip_count,
- size_t translucent_skip_count) const;
-
- private:
- /// A data structure for collecting sorted draws for a given "draw order
- /// layer". Currently these layers just correspond to the local clip stack.
- struct DrawOrderLayer {
- /// The list of backdrop-independent elements (always just opaque). These
- /// are order independent, and so we render these elements in reverse
- /// painter's order so that they cull one another.
- ElementRefs opaque_elements;
-
- /// The list of backdrop-dependent elements with respect to this draw
- /// order layer. These elements are drawn after all of the independent
- /// elements.
- ElementRefs dependent_elements;
-
- //-----------------------------------------------------------------------
- /// @brief Appends the combined opaque and transparent elements into
- /// a final destination buffer.
- ///
- /// @param[in] destination The buffer to append the combined
- /// elements to.
- /// @param[in] opaque_skip_count The number of opaque elements to
- /// skip when appending the combined
- /// elements. This is used for the
- /// "clear color" optimization.
- /// @param[in] translucent_skip_count The number of translucent elements
- /// to skip when appending the combined
- /// elements. This is used for the
- /// "clear color" optimization.
- ///
- void WriteCombinedDraws(ElementRefs& destination,
- size_t opaque_skip_count,
- size_t translucent_skip_count) const;
- };
- std::vector<DrawOrderLayer> draw_order_layers_;
-
- // The first time the root layer is flushed, the layer contents are stored
- // here. This is done to enable element skipping for the clear color
- // optimization.
- std::optional<DrawOrderLayer> first_root_flush_;
- // All subsequent root flushes are stored here.
- ElementRefs sorted_elements_;
-
- DrawOrderResolver(const DrawOrderResolver&) = delete;
-
- DrawOrderResolver& operator=(const DrawOrderResolver&) = delete;
-};
-
-} // namespace impeller
-
-#endif // FLUTTER_IMPELLER_ENTITY_DRAW_ORDER_RESOLVER_H_
diff --git a/impeller/entity/draw_order_resolver_unittests.cc b/impeller/entity/draw_order_resolver_unittests.cc
deleted file mode 100644
index c19e781..0000000
--- a/impeller/entity/draw_order_resolver_unittests.cc
+++ /dev/null
@@ -1,156 +0,0 @@
-// 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 "flutter/testing/testing.h"
-#include "impeller/entity/draw_order_resolver.h"
-#include "third_party/googletest/googletest/include/gtest/gtest.h"
-
-namespace impeller {
-namespace testing {
-
-TEST(DrawOrderResolverTest, GetSortedDrawsReturnsCorrectOrderWithNoClips) {
- DrawOrderResolver resolver;
-
- // Opaque items.
- resolver.AddElement(0, true);
- resolver.AddElement(1, true);
- // Translucent items.
- resolver.AddElement(2, false);
- resolver.AddElement(3, false);
-
- auto sorted_elements = resolver.GetSortedDraws(0, 0);
-
- EXPECT_EQ(sorted_elements.size(), 4u);
- // First, the opaque items are drawn in reverse order.
- EXPECT_EQ(sorted_elements[0], 1u);
- EXPECT_EQ(sorted_elements[1], 0u);
- // Then the translucent items are drawn.
- EXPECT_EQ(sorted_elements[2], 2u);
- EXPECT_EQ(sorted_elements[3], 3u);
-}
-
-TEST(DrawOrderResolverTest, GetSortedDrawsReturnsCorrectOrderWithClips) {
- DrawOrderResolver resolver;
-
- // Items before clip.
- resolver.AddElement(0, false);
- resolver.AddElement(1, true);
- resolver.AddElement(2, false);
- resolver.AddElement(3, true);
-
- // Clip.
- resolver.PushClip(4);
- {
- // Clipped items.
- resolver.AddElement(5, false);
- resolver.AddElement(6, false);
- // Clipped translucent items.
- resolver.AddElement(7, true);
- resolver.AddElement(8, true);
- }
- resolver.PopClip();
-
- // Items after clip.
- resolver.AddElement(9, true);
- resolver.AddElement(10, false);
- resolver.AddElement(11, true);
- resolver.AddElement(12, false);
-
- auto sorted_elements = resolver.GetSortedDraws(0, 0);
-
- EXPECT_EQ(sorted_elements.size(), 13u);
- // First, all the non-clipped opaque items are drawn in reverse order.
- EXPECT_EQ(sorted_elements[0], 11u);
- EXPECT_EQ(sorted_elements[1], 9u);
- EXPECT_EQ(sorted_elements[2], 3u);
- EXPECT_EQ(sorted_elements[3], 1u);
- // Then, non-clipped translucent items that came before the clip are drawn in
- // their original order.
- EXPECT_EQ(sorted_elements[4], 0u);
- EXPECT_EQ(sorted_elements[5], 2u);
-
- // Then, the clip and its sorted child items are drawn.
- EXPECT_EQ(sorted_elements[6], 4u);
- {
- // Opaque clipped items are drawn in reverse order.
- EXPECT_EQ(sorted_elements[7], 8u);
- EXPECT_EQ(sorted_elements[8], 7u);
- // Translucent clipped items are drawn.
- EXPECT_EQ(sorted_elements[9], 5u);
- EXPECT_EQ(sorted_elements[10], 6u);
- }
- // Finally, the non-clipped translucent items which came after the clip are
- // drawn in their original order.
- EXPECT_EQ(sorted_elements[11], 10u);
- EXPECT_EQ(sorted_elements[12], 12u);
-}
-
-TEST(DrawOrderResolverTest, GetSortedDrawsRespectsSkipCounts) {
- DrawOrderResolver resolver;
-
- // These items will be skipped.
- resolver.AddElement(0, false);
- resolver.AddElement(1, true);
- resolver.AddElement(2, false);
- // These ones will be included in the final draw list.
- resolver.AddElement(3, false);
- resolver.AddElement(4, true);
- resolver.AddElement(5, true);
-
- // Form the draw list, skipping elements 0, 1, and 2.
- // This emulates what happens when entitypass applies the clear color
- // optimization.
- auto sorted_elements = resolver.GetSortedDraws(1, 2);
-
- EXPECT_EQ(sorted_elements.size(), 3u);
- // First, opaque items are drawn in reverse order.
- EXPECT_EQ(sorted_elements[0], 5u);
- EXPECT_EQ(sorted_elements[1], 4u);
- // Then, translucent items are drawn.
- EXPECT_EQ(sorted_elements[2], 3u);
-}
-
-TEST(DrawOrderResolverTest, GetSortedDrawsReturnsCorrectOrderWithFlush) {
- DrawOrderResolver resolver;
-
- resolver.AddElement(0, false);
- resolver.AddElement(1, true);
- resolver.AddElement(2, false);
- resolver.AddElement(3, true);
-
- resolver.Flush();
-
- resolver.AddElement(4, false);
- resolver.AddElement(5, true);
- resolver.AddElement(6, false);
- resolver.AddElement(7, true);
-
- resolver.Flush();
-
- resolver.AddElement(8, false);
- resolver.AddElement(9, true);
- resolver.AddElement(10, false);
- resolver.AddElement(11, true);
-
- auto sorted_elements = resolver.GetSortedDraws(1, 1);
-
- EXPECT_EQ(sorted_elements.size(), 10u);
-
- // Skipped draws apply to the first flush.
- EXPECT_EQ(sorted_elements[0], 3u);
- EXPECT_EQ(sorted_elements[1], 2u);
-
- EXPECT_EQ(sorted_elements[2], 7u);
- EXPECT_EQ(sorted_elements[3], 5u);
- EXPECT_EQ(sorted_elements[4], 4u);
- EXPECT_EQ(sorted_elements[5], 6u);
-
- EXPECT_EQ(sorted_elements[6], 11u);
- EXPECT_EQ(sorted_elements[7], 9u);
- EXPECT_EQ(sorted_elements[8], 8u);
- EXPECT_EQ(sorted_elements[9], 10u);
-}
-
-} // namespace testing
-} // namespace impeller
diff --git a/impeller/entity/entity.cc b/impeller/entity/entity.cc
index 2e5229d..cb33689 100644
--- a/impeller/entity/entity.cc
+++ b/impeller/entity/entity.cc
@@ -43,8 +43,6 @@
Entity::Entity(const Entity&) = default;
-Entity& Entity::operator=(Entity&&) = default;
-
const Matrix& Entity::GetTransform() const {
return transform_;
}
diff --git a/impeller/entity/entity.h b/impeller/entity/entity.h
index daaac14..95f8b29 100644
--- a/impeller/entity/entity.h
+++ b/impeller/entity/entity.h
@@ -73,8 +73,6 @@
Entity(Entity&&);
- Entity& operator=(Entity&&);
-
/// @brief Get the global transform matrix for this Entity.
const Matrix& GetTransform() const;
diff --git a/impeller/entity/entity_pass.cc b/impeller/entity/entity_pass.cc
index cd29877..bd1e070 100644
--- a/impeller/entity/entity_pass.cc
+++ b/impeller/entity/entity_pass.cc
@@ -20,7 +20,6 @@
#include "impeller/entity/contents/filters/inputs/filter_input.h"
#include "impeller/entity/contents/framebuffer_blend_contents.h"
#include "impeller/entity/contents/texture_contents.h"
-#include "impeller/entity/draw_order_resolver.h"
#include "impeller/entity/entity.h"
#include "impeller/entity/entity_pass_clip_stack.h"
#include "impeller/entity/inline_pass_context.h"
@@ -45,10 +44,6 @@
}
} // namespace
-bool EntityPass::IsSubpass(const Element& element) {
- return std::holds_alternative<std::unique_ptr<EntityPass>>(element);
-}
-
EntityPass::EntityPass() = default;
EntityPass::~EntityPass() = default;
@@ -111,14 +106,11 @@
if (entity.GetBlendMode() > Entity::kLastPipelineBlendMode) {
advanced_blend_reads_from_pass_texture_ = true;
}
- draw_order_resolver_.AddElement(elements_.size(),
- entity.GetBlendMode() == BlendMode::kSource);
elements_.emplace_back(std::move(entity));
}
void EntityPass::PushClip(Entity entity) {
elements_.emplace_back(std::move(entity));
- draw_order_resolver_.PushClip(elements_.size() - 1);
active_clips_.emplace_back(elements_.size() - 1);
}
@@ -137,7 +129,6 @@
FML_DCHECK(element);
element->SetClipDepth(depth);
active_clips_.pop_back();
- draw_order_resolver_.PopClip();
}
}
@@ -280,14 +271,8 @@
FML_DCHECK(pass->superpass_ == nullptr);
pass->superpass_ = this;
- bool has_backdrop_filter = pass->backdrop_filter_proc_ != nullptr;
- if (has_backdrop_filter) {
+ if (pass->backdrop_filter_proc_) {
backdrop_filter_reads_from_pass_texture_ = true;
-
- // Since backdrop filters trigger the RenderPass to end and lose all depth
- // information for opaque draws, this is a hard barrier for the draw order
- // optimization. Flush all sorted draws accumulated up to this point.
- draw_order_resolver_.Flush();
}
if (pass->blend_mode_ > Entity::kLastPipelineBlendMode) {
advanced_blend_reads_from_pass_texture_ = true;
@@ -295,12 +280,6 @@
auto subpass_pointer = pass.get();
elements_.emplace_back(std::move(pass));
-
- draw_order_resolver_.AddElement(elements_.size() - 1, false);
- if (has_backdrop_filter) {
- draw_order_resolver_.Flush();
- }
-
return subpass_pointer;
}
@@ -765,55 +744,6 @@
ContentContext& renderer,
EntityPassClipStack& clip_coverage_stack,
Point global_pass_position) const {
- // Setup advanced blends.
- if (element_entity.GetBlendMode() > Entity::kLastPipelineBlendMode) {
- if (renderer.GetDeviceCapabilities().SupportsFramebufferFetch()) {
- auto src_contents = element_entity.GetContents();
- auto contents = std::make_shared<FramebufferBlendContents>();
- contents->SetChildContents(src_contents);
- contents->SetBlendMode(element_entity.GetBlendMode());
- element_entity.SetContents(std::move(contents));
- element_entity.SetBlendMode(BlendMode::kSource);
- } else {
- // End the active pass and flush the buffer before rendering
- // "advanced" blends. Advanced blends work by binding the current
- // render target texture as an input ("destination"), blending with a
- // second texture input ("source"), writing the result to an
- // intermediate texture, and finally copying the data from the
- // intermediate texture back to the render target texture. And so all
- // of the commands that have written to the render target texture so
- // far need to execute before it's bound for blending (otherwise the
- // blend pass will end up executing before all the previous commands
- // in the active pass).
-
- if (!pass_context.EndPass()) {
- VALIDATION_LOG
- << "Failed to end the current render pass in order to read "
- "from "
- "the backdrop texture and apply an advanced blend.";
- return false;
- }
-
- // Amend an advanced blend filter to the contents, attaching the pass
- // texture.
- auto texture = pass_context.GetTexture();
- if (!texture) {
- VALIDATION_LOG << "Failed to fetch the color texture in order to "
- "apply an advanced blend.";
- return false;
- }
-
- FilterInput::Vector inputs = {
- FilterInput::Make(texture, element_entity.GetTransform().Invert()),
- FilterInput::Make(element_entity.GetContents())};
- auto contents =
- ColorFilterContents::MakeBlend(element_entity.GetBlendMode(), inputs);
- contents->SetCoverageHint(element_entity.GetCoverage());
- element_entity.SetContents(std::move(contents));
- element_entity.SetBlendMode(BlendMode::kSource);
- }
- }
-
auto result = pass_context.GetRenderPass(pass_depth);
if (!result.pass) {
// Failure to produce a render pass should be explained by specific errors
@@ -846,19 +776,15 @@
}
if (result.just_created) {
- clip_coverage_stack.ActivateClipReplay();
- }
-
- // If there are any pending clips to replay, render any that may affect
- // the entity we're about to render.
- while (const EntityPassClipStack::ReplayResult* next_replay_clip =
- clip_coverage_stack.GetNextReplayResult(element_entity)) {
- auto& replay_entity = next_replay_clip->entity;
- SetClipScissor(clip_coverage_stack.CurrentClipCoverage(), *result.pass,
- global_pass_position);
- if (!replay_entity.Render(renderer, *result.pass)) {
- VALIDATION_LOG << "Failed to render entity for clip replay.";
- return false;
+ // Restore any clips that were recorded before the backdrop filter was
+ // applied.
+ auto& replay_entities = clip_coverage_stack.GetReplayEntities();
+ for (const auto& replay : replay_entities) {
+ SetClipScissor(clip_coverage_stack.CurrentClipCoverage(), *result.pass,
+ global_pass_position);
+ if (!replay.entity.Render(renderer, *result.pass)) {
+ VALIDATION_LOG << "Failed to render entity for clip restore.";
+ }
}
}
@@ -965,87 +891,21 @@
renderer, clip_coverage_stack, global_pass_position);
}
- bool should_collapse_clear_colors =
- !collapsed_parent_pass &&
- // Backdrop filters act as a entity before
- // everything and disrupt the optimization.
- !backdrop_filter_proc_;
-
- // Count the number of elements eaten by the clear color optimization. Break
- // it down in terms of opaque and translucent elements so that we can skip
- // over these entities when applying the clear color optimization.
- size_t opaque_clear_entity_count = 0;
- size_t translucent_clear_entity_count = 0;
- if (should_collapse_clear_colors) {
- for (const auto& element : elements_) {
- if (const Entity* entity = std::get_if<Entity>(&element)) {
- std::optional<Color> entity_color =
- entity->AsBackgroundColor(clear_color_size);
- if (entity_color.has_value()) {
- if (entity->GetBlendMode() == BlendMode::kSource) {
- opaque_clear_entity_count++;
- } else {
- translucent_clear_entity_count++;
- }
- // We've found an entity that replaces the whole background color of
- // this layer, so continue counting.
- continue;
- }
+ bool is_collapsing_clear_colors = !collapsed_parent_pass &&
+ // Backdrop filters act as a entity before
+ // everything and disrupt the optimization.
+ !backdrop_filter_proc_;
+ for (const auto& element : elements_) {
+ // Skip elements that are incorporated into the clear color.
+ if (is_collapsing_clear_colors) {
+ auto [entity_color, _] =
+ ElementAsBackgroundColor(element, clear_color_size);
+ if (entity_color.has_value()) {
+ continue;
}
- // We came across an element that doesn't replace the background color of
- // this layer, so stop counting.
- break;
+ is_collapsing_clear_colors = false;
}
- }
- using ElementCallback = std::function<bool(const Element&)>;
- using ElementIterator = std::function<bool(const ElementCallback&)>;
-
- ElementIterator element_iterator;
-
- if (renderer.GetDeviceCapabilities().SupportsFramebufferFetch()) {
- element_iterator =
- [this, &opaque_clear_entity_count,
- &translucent_clear_entity_count](const ElementCallback& callback) {
- const auto& sorted_elements = draw_order_resolver_.GetSortedDraws(
- opaque_clear_entity_count, translucent_clear_entity_count);
-
- for (const auto& element_ref : sorted_elements) {
- const Element& element = elements_[element_ref];
- if (!callback(element)) {
- return false;
- }
- }
- return true;
- };
- } else {
- // If framebuffer fetch isn't supported, just disable the draw order
- // optimization. We could technically make it work by flushing each time
- // we encounter an advanced blend at recording time down the road.
- element_iterator = [this, &opaque_clear_entity_count,
- &translucent_clear_entity_count](
- const ElementCallback& callback) {
- size_t skips = opaque_clear_entity_count + translucent_clear_entity_count;
- for (const auto& element : elements_) {
- if (skips > 0) {
- skips--;
- continue;
- }
- if (!callback(element)) {
- return false;
- }
- }
- return true;
- };
- }
-
- const auto& render_element = [&, this](Entity& entity) {
- return RenderElement(entity, clip_height_floor, pass_context, pass_depth,
- renderer, clip_coverage_stack, global_pass_position);
- };
-
- std::optional<Entity> deferred_entity;
- bool result = element_iterator([&](const Element& element) {
EntityResult result =
GetEntityForElement(element, // element
renderer, // renderer
@@ -1064,36 +924,70 @@
// in `GetEntityForElement()`.
return false;
case EntityResult::kSkip:
- return true;
+ continue;
};
- if (deferred_entity.has_value() &&
- result.entity.GetBlendMode() != BlendMode::kSource) {
- if (!render_element(*deferred_entity)) {
- return false;
- }
- deferred_entity.reset();
- }
+ //--------------------------------------------------------------------------
+ /// Setup advanced blends.
+ ///
- if (IsSubpass(element)) {
- if (deferred_entity.has_value()) {
- if (!render_element(*deferred_entity)) {
+ if (result.entity.GetBlendMode() > Entity::kLastPipelineBlendMode) {
+ if (renderer.GetDeviceCapabilities().SupportsFramebufferFetch()) {
+ auto src_contents = result.entity.GetContents();
+ auto contents = std::make_shared<FramebufferBlendContents>();
+ contents->SetChildContents(src_contents);
+ contents->SetBlendMode(result.entity.GetBlendMode());
+ result.entity.SetContents(std::move(contents));
+ result.entity.SetBlendMode(BlendMode::kSource);
+ } else {
+ // End the active pass and flush the buffer before rendering "advanced"
+ // blends. Advanced blends work by binding the current render target
+ // texture as an input ("destination"), blending with a second texture
+ // input ("source"), writing the result to an intermediate texture, and
+ // finally copying the data from the intermediate texture back to the
+ // render target texture. And so all of the commands that have written
+ // to the render target texture so far need to execute before it's bound
+ // for blending (otherwise the blend pass will end up executing before
+ // all the previous commands in the active pass).
+
+ if (!pass_context.EndPass()) {
+ VALIDATION_LOG
+ << "Failed to end the current render pass in order to read from "
+ "the backdrop texture and apply an advanced blend.";
return false;
}
+
+ // Amend an advanced blend filter to the contents, attaching the pass
+ // texture.
+ auto texture = pass_context.GetTexture();
+ if (!texture) {
+ VALIDATION_LOG << "Failed to fetch the color texture in order to "
+ "apply an advanced blend.";
+ return false;
+ }
+
+ FilterInput::Vector inputs = {
+ FilterInput::Make(texture, result.entity.GetTransform().Invert()),
+ FilterInput::Make(result.entity.GetContents())};
+ auto contents = ColorFilterContents::MakeBlend(
+ result.entity.GetBlendMode(), inputs);
+ contents->SetCoverageHint(result.entity.GetCoverage());
+ result.entity.SetContents(std::move(contents));
+ result.entity.SetBlendMode(BlendMode::kSource);
}
- deferred_entity = std::move(result.entity);
- return true;
}
- return render_element(result.entity);
- });
- if (!result) {
- return false;
+ //--------------------------------------------------------------------------
+ /// Render the Element.
+ ///
+ if (!RenderElement(result.entity, clip_height_floor, pass_context,
+ pass_depth, renderer, clip_coverage_stack,
+ global_pass_position)) {
+ // Specific validation logs are handled in `render_element()`.
+ return false;
+ }
}
- if (deferred_entity.has_value() && !render_element(*deferred_entity)) {
- return false;
- }
return true;
}
diff --git a/impeller/entity/entity_pass.h b/impeller/entity/entity_pass.h
index 38e5d28..8773160 100644
--- a/impeller/entity/entity_pass.h
+++ b/impeller/entity/entity_pass.h
@@ -13,7 +13,6 @@
#include "impeller/entity/contents/contents.h"
#include "impeller/entity/contents/filters/filter_contents.h"
-#include "impeller/entity/draw_order_resolver.h"
#include "impeller/entity/entity.h"
#include "impeller/entity/entity_pass_clip_stack.h"
#include "impeller/entity/entity_pass_delegate.h"
@@ -54,8 +53,6 @@
/// `GetEntityForElement()`.
using Element = std::variant<Entity, std::unique_ptr<EntityPass>>;
- static bool IsSubpass(const Element& element);
-
using BackdropFilterProc = std::function<std::shared_ptr<FilterContents>(
FilterInput::Ref,
const Matrix& effect_transform,
@@ -217,7 +214,8 @@
kSkip,
};
- /// @brief The resulting entity that should be rendered.
+ /// @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.
@@ -318,12 +316,10 @@
/// evaluated and recorded to an `EntityPassTarget` by the `OnRender` method.
std::vector<Element> elements_;
- DrawOrderResolver draw_order_resolver_;
-
/// The stack of currently active clips (during Aiks recording time). Each
- /// entry is an index into the `elements_` list. The depth value of a clip
- /// is the max of all the entities it affects, so assignment of the depth
- /// value is deferred until clip restore or end of the EntityPass.
+ /// entry is an index into the `elements_` list. The depth value of a clip is
+ /// the max of all the entities it affects, so assignment of the depth value
+ /// is deferred until clip restore or end of the EntityPass.
std::vector<size_t> active_clips_;
EntityPass* superpass_ = nullptr;
@@ -342,8 +338,8 @@
/// 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.
+ /// `blend_reads_from_pass_texture_` if the device supports framebuffer based
+ /// advanced blends.
bool advanced_blend_reads_from_pass_texture_ = false;
bool backdrop_filter_reads_from_pass_texture_ = false;
diff --git a/impeller/entity/entity_pass_clip_stack.cc b/impeller/entity/entity_pass_clip_stack.cc
index 1cef7a1..eab0565 100644
--- a/impeller/entity/entity_pass_clip_stack.cc
+++ b/impeller/entity/entity_pass_clip_stack.cc
@@ -3,8 +3,6 @@
// found in the LICENSE file.
#include "impeller/entity/entity_pass_clip_stack.h"
-
-#include "flutter/fml/logging.h"
#include "impeller/entity/contents/clip_contents.h"
#include "impeller/entity/entity.h"
@@ -39,12 +37,10 @@
.clip_height = clip_height},
},
});
- next_replay_index_ = 0;
}
void EntityPassClipStack::PopSubpass() {
subpass_state_.pop_back();
- next_replay_index_ = subpass_state_.back().rendered_clip_entities.size();
}
const std::vector<ClipCoverageLayer>
@@ -142,22 +138,12 @@
case Contents::ClipCoverage::Type::kNoChange:
return;
case Contents::ClipCoverage::Type::kAppend:
- FML_DCHECK(next_replay_index_ ==
- subpass_state.rendered_clip_entities.size())
- << "Not all clips have been replayed before appending new clip.";
subpass_state.rendered_clip_entities.push_back(
{.entity = entity.Clone(), .clip_coverage = clip_coverage});
- next_replay_index_++;
break;
case Contents::ClipCoverage::Type::kRestore:
- FML_DCHECK(next_replay_index_ <=
- subpass_state.rendered_clip_entities.size());
if (!subpass_state.rendered_clip_entities.empty()) {
subpass_state.rendered_clip_entities.pop_back();
-
- if (next_replay_index_ > subpass_state.rendered_clip_entities.size()) {
- next_replay_index_ = subpass_state.rendered_clip_entities.size();
- }
}
break;
}
@@ -173,27 +159,4 @@
return subpass_state_.back().rendered_clip_entities;
}
-void EntityPassClipStack::ActivateClipReplay() {
- next_replay_index_ = 0;
-}
-
-const EntityPassClipStack::ReplayResult*
-EntityPassClipStack::GetNextReplayResult(const Entity& entity) {
- if (next_replay_index_ >=
- subpass_state_.back().rendered_clip_entities.size()) {
- // No clips need to be replayed.
- return nullptr;
- }
- ReplayResult* next_replay =
- &subpass_state_.back().rendered_clip_entities[next_replay_index_];
- if (next_replay->entity.GetClipDepth() < entity.GetClipDepth()) {
- // The next replay clip doesn't affect the current entity, so don't replay
- // it yet.
- return nullptr;
- }
-
- next_replay_index_++;
- return next_replay;
-}
-
} // namespace impeller
diff --git a/impeller/entity/entity_pass_clip_stack.h b/impeller/entity/entity_pass_clip_stack.h
index df230fd..de1f1c9 100644
--- a/impeller/entity/entity_pass_clip_stack.h
+++ b/impeller/entity/entity_pass_clip_stack.h
@@ -62,14 +62,9 @@
Contents::ClipCoverage::Type type,
std::optional<Rect> clip_coverage);
+ // Visible for testing.
const std::vector<ReplayResult>& GetReplayEntities() const;
- void ActivateClipReplay();
-
- /// @brief Returns the next Entity that should be replayed. If there are no
- /// enities to replay, then nullptr is returned.
- const ReplayResult* GetNextReplayResult(const Entity& entity);
-
// Visible for testing.
const std::vector<ClipCoverageLayer> GetClipCoverageLayers() const;
@@ -82,7 +77,6 @@
SubpassState& GetCurrentSubpassState();
std::vector<SubpassState> subpass_state_;
- size_t next_replay_index_ = 0;
};
} // namespace impeller