Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 95b69d0

Browse files
committed
Defer subpass texture draw until subsequent opaque draws are finished.
1 parent 23a7baa commit 95b69d0

File tree

4 files changed

+94
-60
lines changed

4 files changed

+94
-60
lines changed

impeller/entity/entity.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ Entity::Entity(Entity&&) = default;
4343

4444
Entity::Entity(const Entity&) = default;
4545

46+
Entity& Entity::operator=(Entity&&) = default;
47+
4648
const Matrix& Entity::GetTransform() const {
4749
return transform_;
4850
}

impeller/entity/entity.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ class Entity {
7373

7474
Entity(Entity&&);
7575

76+
Entity& operator=(Entity&&);
77+
7678
/// @brief Get the global transform matrix for this Entity.
7779
const Matrix& GetTransform() const;
7880

impeller/entity/entity_pass.cc

Lines changed: 87 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@ std::tuple<std::optional<Color>, BlendMode> ElementAsBackgroundColor(
4545
}
4646
} // namespace
4747

48+
bool EntityPass::IsSubpass(const Element& element) {
49+
return std::holds_alternative<std::unique_ptr<EntityPass>>(element);
50+
}
51+
4852
EntityPass::EntityPass() = default;
4953

5054
EntityPass::~EntityPass() = default;
@@ -276,7 +280,8 @@ EntityPass* EntityPass::AddSubpass(std::unique_ptr<EntityPass> pass) {
276280
FML_DCHECK(pass->superpass_ == nullptr);
277281
pass->superpass_ = this;
278282

279-
if (pass->backdrop_filter_proc_) {
283+
bool has_backdrop_filter = pass->backdrop_filter_proc_ != nullptr;
284+
if (has_backdrop_filter) {
280285
backdrop_filter_reads_from_pass_texture_ = true;
281286

282287
// Since backdrop filters trigger the RenderPass to end and lose all depth
@@ -292,6 +297,10 @@ EntityPass* EntityPass::AddSubpass(std::unique_ptr<EntityPass> pass) {
292297
elements_.emplace_back(std::move(pass));
293298

294299
draw_order_resolver_.AddElement(elements_.size() - 1, false);
300+
if (has_backdrop_filter) {
301+
draw_order_resolver_.Flush();
302+
}
303+
295304
return subpass_pointer;
296305
}
297306

@@ -756,6 +765,55 @@ bool EntityPass::RenderElement(Entity& element_entity,
756765
ContentContext& renderer,
757766
EntityPassClipStack& clip_coverage_stack,
758767
Point global_pass_position) const {
768+
// Setup advanced blends.
769+
if (element_entity.GetBlendMode() > Entity::kLastPipelineBlendMode) {
770+
if (renderer.GetDeviceCapabilities().SupportsFramebufferFetch()) {
771+
auto src_contents = element_entity.GetContents();
772+
auto contents = std::make_shared<FramebufferBlendContents>();
773+
contents->SetChildContents(src_contents);
774+
contents->SetBlendMode(element_entity.GetBlendMode());
775+
element_entity.SetContents(std::move(contents));
776+
element_entity.SetBlendMode(BlendMode::kSource);
777+
} else {
778+
// End the active pass and flush the buffer before rendering
779+
// "advanced" blends. Advanced blends work by binding the current
780+
// render target texture as an input ("destination"), blending with a
781+
// second texture input ("source"), writing the result to an
782+
// intermediate texture, and finally copying the data from the
783+
// intermediate texture back to the render target texture. And so all
784+
// of the commands that have written to the render target texture so
785+
// far need to execute before it's bound for blending (otherwise the
786+
// blend pass will end up executing before all the previous commands
787+
// in the active pass).
788+
789+
if (!pass_context.EndPass()) {
790+
VALIDATION_LOG
791+
<< "Failed to end the current render pass in order to read "
792+
"from "
793+
"the backdrop texture and apply an advanced blend.";
794+
return false;
795+
}
796+
797+
// Amend an advanced blend filter to the contents, attaching the pass
798+
// texture.
799+
auto texture = pass_context.GetTexture();
800+
if (!texture) {
801+
VALIDATION_LOG << "Failed to fetch the color texture in order to "
802+
"apply an advanced blend.";
803+
return false;
804+
}
805+
806+
FilterInput::Vector inputs = {
807+
FilterInput::Make(texture, element_entity.GetTransform().Invert()),
808+
FilterInput::Make(element_entity.GetContents())};
809+
auto contents =
810+
ColorFilterContents::MakeBlend(element_entity.GetBlendMode(), inputs);
811+
contents->SetCoverageHint(element_entity.GetCoverage());
812+
element_entity.SetContents(std::move(contents));
813+
element_entity.SetBlendMode(BlendMode::kSource);
814+
}
815+
}
816+
759817
auto result = pass_context.GetRenderPass(pass_depth);
760818
if (!result.pass) {
761819
// Failure to produce a render pass should be explained by specific errors
@@ -974,7 +1032,13 @@ bool EntityPass::OnRender(
9741032
};
9751033
}
9761034

977-
return element_iterator([&](const Element& element) {
1035+
const auto& render_element = [&, this](Entity& entity) {
1036+
return RenderElement(entity, clip_height_floor, pass_context, pass_depth,
1037+
renderer, clip_coverage_stack, global_pass_position);
1038+
};
1039+
1040+
std::optional<Entity> deferred_entity;
1041+
bool result = element_iterator([&](const Element& element) {
9781042
EntityResult result =
9791043
GetEntityForElement(element, // element
9801044
renderer, // renderer
@@ -996,69 +1060,34 @@ bool EntityPass::OnRender(
9961060
return true;
9971061
};
9981062

999-
//--------------------------------------------------------------------------
1000-
/// Setup advanced blends.
1001-
///
1002-
1003-
if (result.entity.GetBlendMode() > Entity::kLastPipelineBlendMode) {
1004-
if (renderer.GetDeviceCapabilities().SupportsFramebufferFetch()) {
1005-
auto src_contents = result.entity.GetContents();
1006-
auto contents = std::make_shared<FramebufferBlendContents>();
1007-
contents->SetChildContents(src_contents);
1008-
contents->SetBlendMode(result.entity.GetBlendMode());
1009-
result.entity.SetContents(std::move(contents));
1010-
result.entity.SetBlendMode(BlendMode::kSource);
1011-
} else {
1012-
// End the active pass and flush the buffer before rendering
1013-
// "advanced" blends. Advanced blends work by binding the current
1014-
// render target texture as an input ("destination"), blending with a
1015-
// second texture input ("source"), writing the result to an
1016-
// intermediate texture, and finally copying the data from the
1017-
// intermediate texture back to the render target texture. And so all
1018-
// of the commands that have written to the render target texture so
1019-
// far need to execute before it's bound for blending (otherwise the
1020-
// blend pass will end up executing before all the previous commands
1021-
// in the active pass).
1022-
1023-
if (!pass_context.EndPass()) {
1024-
VALIDATION_LOG
1025-
<< "Failed to end the current render pass in order to read "
1026-
"from "
1027-
"the backdrop texture and apply an advanced blend.";
1028-
return false;
1029-
}
1063+
if (deferred_entity.has_value() &&
1064+
result.entity.GetBlendMode() != BlendMode::kSource) {
1065+
if (!render_element(*deferred_entity)) {
1066+
return false;
1067+
}
1068+
deferred_entity.reset();
1069+
}
10301070

1031-
// Amend an advanced blend filter to the contents, attaching the pass
1032-
// texture.
1033-
auto texture = pass_context.GetTexture();
1034-
if (!texture) {
1035-
VALIDATION_LOG << "Failed to fetch the color texture in order to "
1036-
"apply an advanced blend.";
1071+
if (IsSubpass(element)) {
1072+
if (deferred_entity.has_value()) {
1073+
if (!render_element(*deferred_entity)) {
10371074
return false;
10381075
}
1039-
1040-
FilterInput::Vector inputs = {
1041-
FilterInput::Make(texture, result.entity.GetTransform().Invert()),
1042-
FilterInput::Make(result.entity.GetContents())};
1043-
auto contents = ColorFilterContents::MakeBlend(
1044-
result.entity.GetBlendMode(), inputs);
1045-
contents->SetCoverageHint(result.entity.GetCoverage());
1046-
result.entity.SetContents(std::move(contents));
1047-
result.entity.SetBlendMode(BlendMode::kSource);
10481076
}
1077+
deferred_entity = std::move(result.entity);
1078+
return true;
10491079
}
10501080

1051-
//--------------------------------------------------------------------------
1052-
/// Render the Element.
1053-
///
1054-
if (!RenderElement(result.entity, clip_height_floor, pass_context,
1055-
pass_depth, renderer, clip_coverage_stack,
1056-
global_pass_position)) {
1057-
// Specific validation logs are handled in `render_element()`.
1058-
return false;
1059-
}
1060-
return true;
1081+
return render_element(result.entity);
10611082
});
1083+
if (!result) {
1084+
return false;
1085+
}
1086+
1087+
if (deferred_entity.has_value() && !render_element(*deferred_entity)) {
1088+
return false;
1089+
}
1090+
return true;
10621091
}
10631092

10641093
void EntityPass::IterateAllElements(

impeller/entity/entity_pass.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ class EntityPass {
5454
/// `GetEntityForElement()`.
5555
using Element = std::variant<Entity, std::unique_ptr<EntityPass>>;
5656

57+
static bool IsSubpass(const Element& element);
58+
5759
using BackdropFilterProc = std::function<std::shared_ptr<FilterContents>(
5860
FilterInput::Ref,
5961
const Matrix& effect_transform,
@@ -215,8 +217,7 @@ class EntityPass {
215217
kSkip,
216218
};
217219

218-
/// @brief The resulting entity that should be rendered. If `std::nullopt`,
219-
/// there is nothing to render.
220+
/// @brief The resulting entity that should be rendered.
220221
Entity entity;
221222
/// @brief This is set to `false` if there was an unexpected rendering
222223
/// error while resolving the Entity.

0 commit comments

Comments
 (0)