Skip to content

Commit 4dc94d6

Browse files
authored
[Impeller] Reland 2: Implement draw order optimization. (flutter#54268)
This time for sure! For each clip scope, draw opaque items in reverse order and translucent/backdrop-independent items in their original order afterwards. Clips are treated as translucent by the parent scope. Respects clips, subpass collapse, and the clear color optimization. Attempt 1: flutter#54136 Revert 1: flutter#54067 Attempt 2: flutter#54215 Revert 2: flutter#54261
1 parent f546fef commit 4dc94d6

15 files changed

+635
-88
lines changed

ci/licenses_golden/excluded_files

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@
165165
../../../flutter/impeller/entity/contents/host_buffer_unittests.cc
166166
../../../flutter/impeller/entity/contents/test
167167
../../../flutter/impeller/entity/contents/tiled_texture_contents_unittests.cc
168+
../../../flutter/impeller/entity/draw_order_resolver_unittests.cc
168169
../../../flutter/impeller/entity/entity_pass_target_unittests.cc
169170
../../../flutter/impeller/entity/entity_pass_unittests.cc
170171
../../../flutter/impeller/entity/entity_unittests.cc

ci/licenses_golden/licenses_flutter

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42128,6 +42128,8 @@ ORIGIN: ../../../flutter/impeller/entity/contents/tiled_texture_contents.cc + ..
4212842128
ORIGIN: ../../../flutter/impeller/entity/contents/tiled_texture_contents.h + ../../../flutter/LICENSE
4212942129
ORIGIN: ../../../flutter/impeller/entity/contents/vertices_contents.cc + ../../../flutter/LICENSE
4213042130
ORIGIN: ../../../flutter/impeller/entity/contents/vertices_contents.h + ../../../flutter/LICENSE
42131+
ORIGIN: ../../../flutter/impeller/entity/draw_order_resolver.cc + ../../../flutter/LICENSE
42132+
ORIGIN: ../../../flutter/impeller/entity/draw_order_resolver.h + ../../../flutter/LICENSE
4213142133
ORIGIN: ../../../flutter/impeller/entity/entity.cc + ../../../flutter/LICENSE
4213242134
ORIGIN: ../../../flutter/impeller/entity/entity.h + ../../../flutter/LICENSE
4213342135
ORIGIN: ../../../flutter/impeller/entity/entity_pass.cc + ../../../flutter/LICENSE
@@ -45009,6 +45011,8 @@ FILE: ../../../flutter/impeller/entity/contents/tiled_texture_contents.cc
4500945011
FILE: ../../../flutter/impeller/entity/contents/tiled_texture_contents.h
4501045012
FILE: ../../../flutter/impeller/entity/contents/vertices_contents.cc
4501145013
FILE: ../../../flutter/impeller/entity/contents/vertices_contents.h
45014+
FILE: ../../../flutter/impeller/entity/draw_order_resolver.cc
45015+
FILE: ../../../flutter/impeller/entity/draw_order_resolver.h
4501245016
FILE: ../../../flutter/impeller/entity/entity.cc
4501345017
FILE: ../../../flutter/impeller/entity/entity.h
4501445018
FILE: ../../../flutter/impeller/entity/entity_pass.cc

impeller/entity/BUILD.gn

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,8 @@ impeller_component("entity") {
166166
"contents/tiled_texture_contents.h",
167167
"contents/vertices_contents.cc",
168168
"contents/vertices_contents.h",
169+
"draw_order_resolver.cc",
170+
"draw_order_resolver.h",
169171
"entity.cc",
170172
"entity.h",
171173
"entity_pass.cc",
@@ -248,6 +250,7 @@ impeller_component("entity_unittests") {
248250
"contents/filters/matrix_filter_contents_unittests.cc",
249251
"contents/host_buffer_unittests.cc",
250252
"contents/tiled_texture_contents_unittests.cc",
253+
"draw_order_resolver_unittests.cc",
251254
"entity_pass_target_unittests.cc",
252255
"entity_pass_unittests.cc",
253256
"entity_playground.cc",

impeller/entity/contents/color_source_contents.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,11 @@ class ColorSourceContents : public Contents {
213213
pass.SetVertexBuffer(std::move(geometry_result.vertex_buffer));
214214
options.primitive_type = geometry_result.type;
215215

216+
// Enable depth writing for all opaque entities in order to allow
217+
// reordering. Opaque entities are coerced to source blending by
218+
// `EntityPass::AddEntity`.
219+
options.depth_write_enabled = options.blend_mode == BlendMode::kSource;
220+
216221
// Take the pre-populated vertex shader uniform struct and set managed
217222
// values.
218223
frame_info.mvp = geometry_result.transform;

impeller/entity/contents/filters/gaussian_blur_filter_contents.cc

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -575,16 +575,16 @@ Entity ApplyBlurStyle(FilterContents::BlurStyle blur_style,
575575
const ContentContext& renderer, const Entity& entity,
576576
RenderPass& pass) mutable {
577577
bool result = true;
578-
blur_entity.SetClipDepth(entity.GetClipDepth());
579-
blur_entity.SetTransform(entity.GetTransform() *
580-
blurred_transform);
581-
result = result && blur_entity.Render(renderer, pass);
582578
snapshot_entity.SetTransform(
583579
entity.GetTransform() *
584580
Matrix::MakeScale(1.f / source_space_scalar) *
585581
snapshot_transform);
586582
snapshot_entity.SetClipDepth(entity.GetClipDepth());
587583
result = result && snapshot_entity.Render(renderer, pass);
584+
blur_entity.SetClipDepth(entity.GetClipDepth());
585+
blur_entity.SetTransform(entity.GetTransform() *
586+
blurred_transform);
587+
result = result && blur_entity.Render(renderer, pass);
588588
return result;
589589
}),
590590
fml::MakeCopyable([blur_entity = blur_entity.Clone(),

impeller/entity/contents/texture_contents.cc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,9 @@ bool TextureContents::Render(const ContentContext& renderer,
153153
}
154154
pipeline_options.primitive_type = PrimitiveType::kTriangleStrip;
155155

156+
pipeline_options.depth_write_enabled =
157+
stencil_enabled_ && pipeline_options.blend_mode == BlendMode::kSource;
158+
156159
pass.SetPipeline(strict_source_rect_enabled_
157160
? renderer.GetTextureStrictSrcPipeline(pipeline_options)
158161
: renderer.GetTexturePipeline(pipeline_options));
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
#include "impeller/entity/draw_order_resolver.h"
6+
7+
#include "flutter/fml/logging.h"
8+
#include "impeller/base/validation.h"
9+
10+
namespace impeller {
11+
12+
DrawOrderResolver::DrawOrderResolver() : draw_order_layers_({{}}){};
13+
14+
void DrawOrderResolver::AddElement(size_t element_index, bool is_opaque) {
15+
DrawOrderLayer& layer = draw_order_layers_.back();
16+
if (is_opaque) {
17+
layer.opaque_elements.push_back(element_index);
18+
} else {
19+
layer.dependent_elements.push_back(element_index);
20+
}
21+
}
22+
void DrawOrderResolver::PushClip(size_t element_index) {
23+
draw_order_layers_.back().dependent_elements.push_back(element_index);
24+
draw_order_layers_.push_back({});
25+
};
26+
27+
void DrawOrderResolver::PopClip() {
28+
if (draw_order_layers_.size() == 1u) {
29+
// This is likely recoverable, so don't assert.
30+
VALIDATION_LOG
31+
<< "Attemped to pop the first draw order clip layer. This is a bug in "
32+
"`EntityPass`.";
33+
return;
34+
}
35+
36+
DrawOrderLayer& layer = draw_order_layers_.back();
37+
DrawOrderLayer& parent_layer =
38+
draw_order_layers_[draw_order_layers_.size() - 2];
39+
40+
layer.WriteCombinedDraws(parent_layer.dependent_elements, 0, 0);
41+
42+
draw_order_layers_.pop_back();
43+
}
44+
45+
void DrawOrderResolver::Flush() {
46+
FML_DCHECK(draw_order_layers_.size() >= 1u);
47+
48+
size_t layer_count = draw_order_layers_.size();
49+
50+
// Pop all clip layers.
51+
while (draw_order_layers_.size() > 1u) {
52+
PopClip();
53+
}
54+
55+
// Move the root layer items into the sorted list.
56+
DrawOrderLayer& layer = draw_order_layers_.back();
57+
if (!first_root_flush_.has_value()) {
58+
// Record the first flush.
59+
first_root_flush_ = std::move(layer);
60+
layer = {};
61+
} else {
62+
// Write subsequent flushes into the sorted root list.
63+
layer.WriteCombinedDraws(sorted_elements_, 0, 0);
64+
layer.opaque_elements.clear();
65+
layer.dependent_elements.clear();
66+
}
67+
68+
// Refill with empty layers.
69+
draw_order_layers_.resize(layer_count);
70+
}
71+
72+
DrawOrderResolver::ElementRefs DrawOrderResolver::GetSortedDraws(
73+
size_t opaque_skip_count,
74+
size_t translucent_skip_count) const {
75+
FML_DCHECK(draw_order_layers_.size() == 1u)
76+
<< "Attempted to get sorted draws before all clips were popped.";
77+
78+
ElementRefs sorted_elements;
79+
sorted_elements.reserve(
80+
(first_root_flush_.has_value()
81+
? first_root_flush_->opaque_elements.size() +
82+
first_root_flush_->dependent_elements.size()
83+
: 0u) +
84+
sorted_elements_.size() +
85+
draw_order_layers_.back().opaque_elements.size() +
86+
draw_order_layers_.back().dependent_elements.size());
87+
88+
// Write all flushed items.
89+
if (first_root_flush_.has_value()) {
90+
first_root_flush_->WriteCombinedDraws(sorted_elements, opaque_skip_count,
91+
translucent_skip_count);
92+
}
93+
sorted_elements.insert(sorted_elements.end(), sorted_elements_.begin(),
94+
sorted_elements_.end());
95+
96+
// Write any remaining non-flushed items.
97+
draw_order_layers_.back().WriteCombinedDraws(
98+
sorted_elements, first_root_flush_.has_value() ? 0 : opaque_skip_count,
99+
first_root_flush_.has_value() ? 0 : translucent_skip_count);
100+
101+
return sorted_elements;
102+
}
103+
104+
void DrawOrderResolver::DrawOrderLayer::WriteCombinedDraws(
105+
ElementRefs& destination,
106+
size_t opaque_skip_count,
107+
size_t translucent_skip_count) const {
108+
FML_DCHECK(opaque_skip_count <= opaque_elements.size());
109+
FML_DCHECK(translucent_skip_count <= dependent_elements.size());
110+
111+
destination.reserve(destination.size() + //
112+
opaque_elements.size() - opaque_skip_count + //
113+
dependent_elements.size() - translucent_skip_count);
114+
115+
// Draw backdrop-independent elements in reverse order first.
116+
destination.insert(destination.end(), opaque_elements.rbegin(),
117+
opaque_elements.rend() - opaque_skip_count);
118+
// Then, draw backdrop-dependent elements in their original order.
119+
destination.insert(destination.end(),
120+
dependent_elements.begin() + translucent_skip_count,
121+
dependent_elements.end());
122+
}
123+
124+
} // namespace impeller

impeller/entity/draw_order_resolver.h

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
#ifndef FLUTTER_IMPELLER_ENTITY_DRAW_ORDER_RESOLVER_H_
6+
#define FLUTTER_IMPELLER_ENTITY_DRAW_ORDER_RESOLVER_H_
7+
8+
#include <optional>
9+
#include <vector>
10+
11+
namespace impeller {
12+
13+
/// Helper that records draw indices in painter's order and sorts the draws into
14+
/// an optimized order based on translucency and clips.
15+
class DrawOrderResolver {
16+
public:
17+
using ElementRefs = std::vector<size_t>;
18+
19+
DrawOrderResolver();
20+
21+
void AddElement(size_t element_index, bool is_opaque);
22+
23+
void PushClip(size_t element_index);
24+
25+
void PopClip();
26+
27+
void Flush();
28+
29+
//-------------------------------------------------------------------------
30+
/// @brief Returns the sorted draws for the current draw order layer.
31+
/// This should only be called after all recording has finished.
32+
///
33+
/// @param[in] opaque_skip_count The number of opaque elements to skip
34+
/// when appending the combined elements.
35+
/// This is used for the "clear color"
36+
/// optimization.
37+
/// @param[in] translucent_skip_count The number of translucent elements to
38+
/// skip when appending the combined
39+
/// elements. This is used for the
40+
/// "clear color" optimization.
41+
///
42+
ElementRefs GetSortedDraws(size_t opaque_skip_count,
43+
size_t translucent_skip_count) const;
44+
45+
private:
46+
/// A data structure for collecting sorted draws for a given "draw order
47+
/// layer". Currently these layers just correspond to the local clip stack.
48+
struct DrawOrderLayer {
49+
/// The list of backdrop-independent elements (always just opaque). These
50+
/// are order independent, and so we render these elements in reverse
51+
/// painter's order so that they cull one another.
52+
ElementRefs opaque_elements;
53+
54+
/// The list of backdrop-dependent elements with respect to this draw
55+
/// order layer. These elements are drawn after all of the independent
56+
/// elements.
57+
ElementRefs dependent_elements;
58+
59+
//-----------------------------------------------------------------------
60+
/// @brief Appends the combined opaque and transparent elements into
61+
/// a final destination buffer.
62+
///
63+
/// @param[in] destination The buffer to append the combined
64+
/// elements to.
65+
/// @param[in] opaque_skip_count The number of opaque elements to
66+
/// skip when appending the combined
67+
/// elements. This is used for the
68+
/// "clear color" optimization.
69+
/// @param[in] translucent_skip_count The number of translucent elements
70+
/// to skip when appending the combined
71+
/// elements. This is used for the
72+
/// "clear color" optimization.
73+
///
74+
void WriteCombinedDraws(ElementRefs& destination,
75+
size_t opaque_skip_count,
76+
size_t translucent_skip_count) const;
77+
};
78+
std::vector<DrawOrderLayer> draw_order_layers_;
79+
80+
// The first time the root layer is flushed, the layer contents are stored
81+
// here. This is done to enable element skipping for the clear color
82+
// optimization.
83+
std::optional<DrawOrderLayer> first_root_flush_;
84+
// All subsequent root flushes are stored here.
85+
ElementRefs sorted_elements_;
86+
87+
DrawOrderResolver(const DrawOrderResolver&) = delete;
88+
89+
DrawOrderResolver& operator=(const DrawOrderResolver&) = delete;
90+
};
91+
92+
} // namespace impeller
93+
94+
#endif // FLUTTER_IMPELLER_ENTITY_DRAW_ORDER_RESOLVER_H_

0 commit comments

Comments
 (0)