diff --git a/ci/licenses_golden/excluded_files b/ci/licenses_golden/excluded_files index c9d5aa13b609d..82a94e60e4b19 100644 --- a/ci/licenses_golden/excluded_files +++ b/ci/licenses_golden/excluded_files @@ -162,6 +162,7 @@ ../../../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 3dcb5429fe2a0..6a2607381977e 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -42128,6 +42128,8 @@ ORIGIN: ../../../flutter/impeller/entity/contents/tiled_texture_contents.cc + .. 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 @@ -45010,6 +45012,8 @@ FILE: ../../../flutter/impeller/entity/contents/tiled_texture_contents.cc 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 d91d56cdfe5fe..c75ca724dc17d 100644 --- a/impeller/entity/BUILD.gn +++ b/impeller/entity/BUILD.gn @@ -166,6 +166,8 @@ impeller_component("entity") { "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", @@ -248,6 +250,7 @@ impeller_component("entity_unittests") { "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 5f72b13f05e82..008674a99e7f6 100644 --- a/impeller/entity/contents/color_source_contents.h +++ b/impeller/entity/contents/color_source_contents.h @@ -213,6 +213,11 @@ class ColorSourceContents : public Contents { 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 ad184172317df..57d5e94a118f0 100644 --- a/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc +++ b/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc @@ -555,16 +555,16 @@ Entity ApplyBlurStyle(FilterContents::BlurStyle blur_style, 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 a2af33e96c486..7cc6befb517c8 100644 --- a/impeller/entity/contents/texture_contents.cc +++ b/impeller/entity/contents/texture_contents.cc @@ -153,6 +153,9 @@ bool TextureContents::Render(const ContentContext& renderer, } 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 new file mode 100644 index 0000000000000..5afdf438d0d2f --- /dev/null +++ b/impeller/entity/draw_order_resolver.cc @@ -0,0 +1,124 @@ +// 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 new file mode 100644 index 0000000000000..5c8d7a91d4755 --- /dev/null +++ b/impeller/entity/draw_order_resolver.h @@ -0,0 +1,94 @@ +// 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 +#include + +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; + + 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 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 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 new file mode 100644 index 0000000000000..c19e781aaec63 --- /dev/null +++ b/impeller/entity/draw_order_resolver_unittests.cc @@ -0,0 +1,156 @@ +// 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_pass.cc b/impeller/entity/entity_pass.cc index bd1e070836cb0..dcafc6ece31ac 100644 --- a/impeller/entity/entity_pass.cc +++ b/impeller/entity/entity_pass.cc @@ -20,6 +20,7 @@ #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" @@ -106,11 +107,14 @@ void EntityPass::AddEntity(Entity entity) { 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); } @@ -129,6 +133,7 @@ void EntityPass::PopClips(size_t num_clips, uint64_t depth) { FML_DCHECK(element); element->SetClipDepth(depth); active_clips_.pop_back(); + draw_order_resolver_.PopClip(); } } @@ -273,6 +278,11 @@ EntityPass* EntityPass::AddSubpass(std::unique_ptr pass) { 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; @@ -280,6 +290,8 @@ EntityPass* EntityPass::AddSubpass(std::unique_ptr pass) { auto subpass_pointer = pass.get(); elements_.emplace_back(std::move(pass)); + + draw_order_resolver_.AddElement(elements_.size() - 1, false); return subpass_pointer; } @@ -891,21 +903,75 @@ bool EntityPass::OnRender( renderer, clip_coverage_stack, global_pass_position); } - 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; + 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. + 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(&element)) { + std::optional 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++; + } + continue; + } + break; } - is_collapsing_clear_colors = false; } + } + + using ElementCallback = std::function; + using ElementIterator = std::function; + + 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; + }; + } + return element_iterator([&](const Element& element) { EntityResult result = GetEntityForElement(element, // element renderer, // renderer @@ -924,7 +990,7 @@ bool EntityPass::OnRender( // in `GetEntityForElement()`. return false; case EntityResult::kSkip: - continue; + return true; }; //-------------------------------------------------------------------------- @@ -940,19 +1006,21 @@ bool EntityPass::OnRender( 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). + // 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 " + << "Failed to end the current render pass in order to read " + "from " "the backdrop texture and apply an advanced blend."; return false; } @@ -986,9 +1054,8 @@ bool EntityPass::OnRender( // Specific validation logs are handled in `render_element()`. return false; } - } - - return true; + return true; + }); } void EntityPass::IterateAllElements( diff --git a/impeller/entity/entity_pass.h b/impeller/entity/entity_pass.h index 87731602d6925..3dae310eac485 100644 --- a/impeller/entity/entity_pass.h +++ b/impeller/entity/entity_pass.h @@ -13,6 +13,7 @@ #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" @@ -316,10 +317,12 @@ class EntityPass { /// evaluated and recorded to an `EntityPassTarget` by the `OnRender` method. std::vector 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 active_clips_; EntityPass* superpass_ = nullptr; @@ -338,8 +341,8 @@ class EntityPass { /// 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;