Skip to content

Commit 20528e2

Browse files
author
Jonah Williams
authored
[display_list] grow display list backing store by power of two. (flutter/engine#56004)
Fixes flutter#157108 Right now the DL is always growing by a minimum 4096 bytes at a time. On applications with large display lists, this can lead to hundreds of reallocations as the display list is build, as long as each draw op is small. For example, the framework benchmark long picture scrolling draws many lines, each of which is a pretty small op. Update the code so that we grow by doubling, with a minimum increment of ~16K
1 parent b4e95e6 commit 20528e2

File tree

3 files changed

+96
-6
lines changed

3 files changed

+96
-6
lines changed

engine/src/flutter/display_list/display_list_unittests.cc

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <utility>
99
#include <vector>
1010

11+
#include "display_list/geometry/dl_geometry_types.h"
1112
#include "flutter/display_list/display_list.h"
1213
#include "flutter/display_list/dl_blend_mode.h"
1314
#include "flutter/display_list/dl_builder.h"
@@ -5894,5 +5895,73 @@ TEST_F(DisplayListTest, BackdropFilterCulledAlongsideClipAndTransform) {
58945895
}
58955896
}
58965897

5898+
TEST_F(DisplayListTest, RecordManyLargeDisplayListOperations) {
5899+
DisplayListBuilder builder;
5900+
5901+
// 2050 points is sizeof(DlPoint) * 2050 = 16400 bytes, this is more
5902+
// than the page size of 16384 bytes.
5903+
std::vector<DlPoint> points(2050);
5904+
builder.DrawPoints(PointMode::kPoints, points.size(), points.data(),
5905+
DlPaint{});
5906+
builder.DrawPoints(PointMode::kPoints, points.size(), points.data(),
5907+
DlPaint{});
5908+
builder.DrawPoints(PointMode::kPoints, points.size(), points.data(),
5909+
DlPaint{});
5910+
builder.DrawPoints(PointMode::kPoints, points.size(), points.data(),
5911+
DlPaint{});
5912+
builder.DrawPoints(PointMode::kPoints, points.size(), points.data(),
5913+
DlPaint{});
5914+
builder.DrawPoints(PointMode::kPoints, points.size(), points.data(),
5915+
DlPaint{});
5916+
5917+
EXPECT_TRUE(!!builder.Build());
5918+
}
5919+
5920+
TEST_F(DisplayListTest, RecordSingleLargeDisplayListOperation) {
5921+
DisplayListBuilder builder;
5922+
5923+
std::vector<DlPoint> points(40000);
5924+
builder.DrawPoints(PointMode::kPoints, points.size(), points.data(),
5925+
DlPaint{});
5926+
5927+
EXPECT_TRUE(!!builder.Build());
5928+
}
5929+
5930+
TEST_F(DisplayListTest, NextPowerOfTwo) {
5931+
EXPECT_EQ(NextPowerOfTwo(0), 1u);
5932+
EXPECT_EQ(NextPowerOfTwo(1), 1u);
5933+
EXPECT_EQ(NextPowerOfTwo(2), 2u);
5934+
5935+
EXPECT_EQ(NextPowerOfTwo(3), 4u);
5936+
EXPECT_EQ(NextPowerOfTwo(4), 4u);
5937+
5938+
EXPECT_EQ(NextPowerOfTwo(5), 8u);
5939+
EXPECT_EQ(NextPowerOfTwo(8), 8u);
5940+
5941+
EXPECT_EQ(NextPowerOfTwo(14), 16u);
5942+
EXPECT_EQ(NextPowerOfTwo(16), 16u);
5943+
5944+
EXPECT_EQ(NextPowerOfTwo(20), 32u);
5945+
EXPECT_EQ(NextPowerOfTwo(32), 32u);
5946+
5947+
EXPECT_EQ(NextPowerOfTwo(50), 64u);
5948+
EXPECT_EQ(NextPowerOfTwo(64), 64u);
5949+
5950+
EXPECT_EQ(NextPowerOfTwo(120), 128u);
5951+
EXPECT_EQ(NextPowerOfTwo(128), 128u);
5952+
5953+
EXPECT_EQ(NextPowerOfTwo(250), 256u);
5954+
EXPECT_EQ(NextPowerOfTwo(256), 256u);
5955+
5956+
EXPECT_EQ(NextPowerOfTwo(1000), 1024u);
5957+
EXPECT_EQ(NextPowerOfTwo(1024), 1024u);
5958+
5959+
EXPECT_EQ(NextPowerOfTwo(2000), 2048u);
5960+
EXPECT_EQ(NextPowerOfTwo(2048), 2048u);
5961+
5962+
EXPECT_EQ(NextPowerOfTwo(4000), 4096u);
5963+
EXPECT_EQ(NextPowerOfTwo(4096), 4096u);
5964+
}
5965+
58975966
} // namespace testing
58985967
} // namespace flutter

engine/src/flutter/display_list/dl_builder.cc

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,27 @@
1515

1616
namespace flutter {
1717

18-
#define DL_BUILDER_PAGE 4096
18+
static const constexpr size_t kDLPageSize = 16384u;
19+
20+
/// @brief Return the next power of 2.
21+
///
22+
/// If the provided value is a power of 2, returns as is.
23+
uint64_t NextPowerOfTwo(uint64_t x) {
24+
if (x == 0) {
25+
return 1;
26+
}
27+
28+
x--;
29+
x |= x >> 1;
30+
x |= x >> 2;
31+
x |= x >> 4;
32+
x |= x >> 8;
33+
x |= x >> 16;
34+
x |= x >> 32;
35+
x++;
36+
37+
return x;
38+
}
1939

2040
// CopyV(dst, src,n, src,n, ...) copies any number of typed srcs into dst.
2141
static void CopyV(void* dst) {}
@@ -42,12 +62,12 @@ static constexpr inline bool is_power_of_two(int value) {
4262
template <typename T, typename... Args>
4363
void* DisplayListBuilder::Push(size_t pod, Args&&... args) {
4464
size_t size = SkAlignPtr(sizeof(T) + pod);
45-
FML_CHECK(size < (1 << 24));
4665
if (used_ + size > allocated_) {
47-
static_assert(is_power_of_two(DL_BUILDER_PAGE),
66+
static_assert(is_power_of_two(kDLPageSize),
4867
"This math needs updating for non-pow2.");
49-
// Next greater multiple of DL_BUILDER_PAGE.
50-
allocated_ = (used_ + size + DL_BUILDER_PAGE) & ~(DL_BUILDER_PAGE - 1);
68+
// Round up the allocated size + used size to the next power of 2, with a
69+
// minimum increment of kDLPageSize.
70+
allocated_ = NextPowerOfTwo(used_ + std::max(size, kDLPageSize));
5171
storage_.realloc(allocated_);
5272
FML_CHECK(storage_.get());
5373
memset(storage_.get() + used_, 0, allocated_ - used_);

engine/src/flutter/display_list/dl_builder.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,11 @@
1717
#include "flutter/display_list/utils/dl_accumulation_rect.h"
1818
#include "flutter/display_list/utils/dl_comparable.h"
1919
#include "flutter/display_list/utils/dl_matrix_clip_tracker.h"
20-
#include "flutter/fml/macros.h"
2120

2221
namespace flutter {
2322

23+
uint64_t NextPowerOfTwo(uint64_t x);
24+
2425
// The primary class used to build a display list. The list of methods
2526
// here matches the list of methods invoked on a |DlOpReceiver| combined
2627
// with the list of methods invoked on a |DlCanvas|.

0 commit comments

Comments
 (0)