diff --git a/ci/licenses_golden/excluded_files b/ci/licenses_golden/excluded_files index ad3563f0d8eb2..46ff86662b08c 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 f73dac77ae003..3e5ebd6b5dbce 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -42128,8 +42128,6 @@ 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 @@ -45013,8 +45011,6 @@ 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 c75ca724dc17d..d91d56cdfe5fe 100644 --- a/impeller/entity/BUILD.gn +++ b/impeller/entity/BUILD.gn @@ -166,8 +166,6 @@ 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", @@ -250,7 +248,6 @@ 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 008674a99e7f6..5f72b13f05e82 100644 --- a/impeller/entity/contents/color_source_contents.h +++ b/impeller/entity/contents/color_source_contents.h @@ -213,11 +213,6 @@ 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 cf39b60e337bc..3fa906e89296c 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 @@ 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 7cc6befb517c8..a2af33e96c486 100644 --- a/impeller/entity/contents/texture_contents.cc +++ b/impeller/entity/contents/texture_contents.cc @@ -153,9 +153,6 @@ 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 deleted file mode 100644 index 5afdf438d0d2f..0000000000000 --- 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 5c8d7a91d4755..0000000000000 --- 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 -#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 deleted file mode 100644 index c19e781aaec63..0000000000000 --- 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 2e5229d707b62..cb336892d3a61 100644 --- a/impeller/entity/entity.cc +++ b/impeller/entity/entity.cc @@ -43,8 +43,6 @@ Entity::Entity(Entity&&) = default; 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 daaac1420a420..95f8b29b2400f 100644 --- a/impeller/entity/entity.h +++ b/impeller/entity/entity.h @@ -73,8 +73,6 @@ class Entity { 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 cd29877cbac14..bd1e070836cb0 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 @@ std::tuple, BlendMode> ElementAsBackgroundColor( } } // namespace -bool EntityPass::IsSubpass(const Element& element) { - return std::holds_alternative>(element); -} - EntityPass::EntityPass() = default; EntityPass::~EntityPass() = default; @@ -111,14 +106,11 @@ 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); } @@ -137,7 +129,6 @@ void EntityPass::PopClips(size_t num_clips, uint64_t depth) { FML_DCHECK(element); element->SetClipDepth(depth); active_clips_.pop_back(); - draw_order_resolver_.PopClip(); } } @@ -280,14 +271,8 @@ EntityPass* EntityPass::AddSubpass(std::unique_ptr pass) { 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 @@ 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); - if (has_backdrop_filter) { - draw_order_resolver_.Flush(); - } - return subpass_pointer; } @@ -765,55 +744,6 @@ bool EntityPass::RenderElement(Entity& element_entity, 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(); - 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 @@ bool EntityPass::RenderElement(Entity& element_entity, } 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 @@ bool EntityPass::OnRender( 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(&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++; - } - // 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; - 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; - }; - } - - 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 deferred_entity; - bool result = element_iterator([&](const Element& element) { EntityResult result = GetEntityForElement(element, // element renderer, // renderer @@ -1064,36 +924,70 @@ bool EntityPass::OnRender( // 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 (result.entity.GetBlendMode() > Entity::kLastPipelineBlendMode) { + if (renderer.GetDeviceCapabilities().SupportsFramebufferFetch()) { + auto src_contents = result.entity.GetContents(); + auto contents = std::make_shared(); + 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; + } - if (IsSubpass(element)) { - if (deferred_entity.has_value()) { - if (!render_element(*deferred_entity)) { + // 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 38e5d28d44231..87731602d6925 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 @@ class EntityPass { /// `GetEntityForElement()`. using Element = std::variant>; - static bool IsSubpass(const Element& element); - using BackdropFilterProc = std::function( FilterInput::Ref, const Matrix& effect_transform, @@ -217,7 +214,8 @@ class EntityPass { 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 @@ 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; @@ -342,8 +338,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; diff --git a/impeller/entity/entity_pass_clip_stack.cc b/impeller/entity/entity_pass_clip_stack.cc index 1cef7a108587a..eab0565b3d382 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 @@ void EntityPassClipStack::PushSubpass(std::optional subpass_coverage, .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 @@ -142,22 +138,12 @@ void EntityPassClipStack::RecordEntity(const Entity& entity, 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 @@ EntityPassClipStack::GetReplayEntities() const { 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 df230fddd4404..de1f1c9eee070 100644 --- a/impeller/entity/entity_pass_clip_stack.h +++ b/impeller/entity/entity_pass_clip_stack.h @@ -62,14 +62,9 @@ class EntityPassClipStack { Contents::ClipCoverage::Type type, std::optional clip_coverage); + // Visible for testing. const std::vector& 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 GetClipCoverageLayers() const; @@ -82,7 +77,6 @@ class EntityPassClipStack { SubpassState& GetCurrentSubpassState(); std::vector subpass_state_; - size_t next_replay_index_ = 0; }; } // namespace impeller