@@ -45,6 +45,10 @@ std::tuple<std::optional<Color>, BlendMode> ElementAsBackgroundColor(
45
45
}
46
46
} // namespace
47
47
48
+ bool EntityPass::IsSubpass (const Element& element) {
49
+ return std::holds_alternative<std::unique_ptr<EntityPass>>(element);
50
+ }
51
+
48
52
EntityPass::EntityPass () = default ;
49
53
50
54
EntityPass::~EntityPass () = default ;
@@ -276,7 +280,8 @@ EntityPass* EntityPass::AddSubpass(std::unique_ptr<EntityPass> pass) {
276
280
FML_DCHECK (pass->superpass_ == nullptr );
277
281
pass->superpass_ = this ;
278
282
279
- if (pass->backdrop_filter_proc_ ) {
283
+ bool has_backdrop_filter = pass->backdrop_filter_proc_ != nullptr ;
284
+ if (has_backdrop_filter) {
280
285
backdrop_filter_reads_from_pass_texture_ = true ;
281
286
282
287
// Since backdrop filters trigger the RenderPass to end and lose all depth
@@ -292,6 +297,10 @@ EntityPass* EntityPass::AddSubpass(std::unique_ptr<EntityPass> pass) {
292
297
elements_.emplace_back (std::move (pass));
293
298
294
299
draw_order_resolver_.AddElement (elements_.size () - 1 , false );
300
+ if (has_backdrop_filter) {
301
+ draw_order_resolver_.Flush ();
302
+ }
303
+
295
304
return subpass_pointer;
296
305
}
297
306
@@ -756,6 +765,55 @@ bool EntityPass::RenderElement(Entity& element_entity,
756
765
ContentContext& renderer,
757
766
EntityPassClipStack& clip_coverage_stack,
758
767
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
+
759
817
auto result = pass_context.GetRenderPass (pass_depth);
760
818
if (!result.pass ) {
761
819
// Failure to produce a render pass should be explained by specific errors
@@ -974,7 +1032,13 @@ bool EntityPass::OnRender(
974
1032
};
975
1033
}
976
1034
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) {
978
1042
EntityResult result =
979
1043
GetEntityForElement (element, // element
980
1044
renderer, // renderer
@@ -996,69 +1060,34 @@ bool EntityPass::OnRender(
996
1060
return true ;
997
1061
};
998
1062
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
+ }
1030
1070
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)) {
1037
1074
return false ;
1038
1075
}
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 );
1048
1076
}
1077
+ deferred_entity = std::move (result.entity );
1078
+ return true ;
1049
1079
}
1050
1080
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 );
1061
1082
});
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 ;
1062
1091
}
1063
1092
1064
1093
void EntityPass::IterateAllElements (
0 commit comments