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

Commit 5a4a30a

Browse files
author
Jonah Williams
authored
[Impeller] use BufferSubData to update gles device buffer. (#55330)
Measures as substantially faster on windows. See the bufferSubData docs: > When replacing the entire data store, consider using glBufferSubData rather than completely recreating the data store with glBufferData. This avoids the cost of reallocating the data store. Tracks invalidated ranges and only updates those ranges using the Flush API. Fixes flutter/flutter#104447
1 parent f386465 commit 5a4a30a

File tree

5 files changed

+87
-14
lines changed

5 files changed

+87
-14
lines changed

impeller/core/allocator_unittests.cc

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,5 +79,52 @@ TEST(AllocatorTest, TextureDescriptorCompatibility) {
7979
}
8080
}
8181

82+
TEST(AllocatorTest, RangeTest) {
83+
{
84+
Range a = Range{0, 10};
85+
Range b = Range{10, 20};
86+
auto merged = a.Merge(b);
87+
88+
EXPECT_EQ(merged.offset, 0u);
89+
EXPECT_EQ(merged.length, 30u);
90+
}
91+
92+
{
93+
Range a = Range{0, 10};
94+
Range b = Range{100, 20};
95+
auto merged = a.Merge(b);
96+
97+
EXPECT_EQ(merged.offset, 0u);
98+
EXPECT_EQ(merged.length, 120u);
99+
}
100+
101+
{
102+
Range a = Range{0, 10};
103+
Range b = Range{100, 20};
104+
auto merged = b.Merge(a);
105+
106+
EXPECT_EQ(merged.offset, 0u);
107+
EXPECT_EQ(merged.length, 120u);
108+
}
109+
110+
{
111+
Range a = Range{0, 10};
112+
Range b = Range{100, 0};
113+
auto merged = b.Merge(a);
114+
115+
EXPECT_EQ(merged.offset, 0u);
116+
EXPECT_EQ(merged.length, 10u);
117+
}
118+
119+
{
120+
Range a = Range{0, 10};
121+
Range b = Range{0, 10};
122+
auto merged = b.Merge(a);
123+
124+
EXPECT_EQ(merged.offset, 0u);
125+
EXPECT_EQ(merged.length, 10u);
126+
}
127+
}
128+
82129
} // namespace testing
83130
} // namespace impeller

impeller/core/range.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#ifndef FLUTTER_IMPELLER_CORE_RANGE_H_
66
#define FLUTTER_IMPELLER_CORE_RANGE_H_
77

8+
#include <algorithm>
89
#include <cstddef>
910

1011
namespace impeller {
@@ -21,6 +22,19 @@ struct Range {
2122
constexpr bool operator==(const Range& o) const {
2223
return offset == o.offset && length == o.length;
2324
}
25+
26+
/// @brief Create a new range that is a union of this range and other.
27+
constexpr Range Merge(const Range& other) {
28+
if (other.length == 0) {
29+
return *this;
30+
}
31+
if (length == 0) {
32+
return other;
33+
}
34+
auto end_offset = std::max(offset + length, other.offset + other.length);
35+
auto start_offset = std::min(offset, other.offset);
36+
return Range{start_offset, end_offset - start_offset};
37+
}
2438
};
2539

2640
} // namespace impeller

impeller/renderer/backend/gles/device_buffer_gles.cc

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,8 @@
77
#include <cstring>
88
#include <memory>
99

10-
#include "flutter/fml/trace_event.h"
1110
#include "impeller/base/allocation.h"
1211
#include "impeller/base/config.h"
13-
#include "impeller/base/validation.h"
1412

1513
namespace impeller {
1614

@@ -53,13 +51,22 @@ bool DeviceBufferGLES::OnCopyHostBuffer(const uint8_t* source,
5351

5452
std::memmove(backing_store_->GetBuffer() + offset,
5553
source + source_range.offset, source_range.length);
56-
++generation_;
54+
Flush(Range{offset, source_range.length});
5755

5856
return true;
5957
}
6058

6159
void DeviceBufferGLES::Flush(std::optional<Range> range) const {
62-
generation_++;
60+
if (!range.has_value()) {
61+
dirty_range_ = Range{
62+
0, static_cast<size_t>(backing_store_->GetLength().GetByteSize())};
63+
} else {
64+
if (dirty_range_.has_value()) {
65+
dirty_range_ = dirty_range_->Merge(range.value());
66+
} else {
67+
dirty_range_ = range.value();
68+
}
69+
}
6370
}
6471

6572
static GLenum ToTarget(DeviceBufferGLES::BindingType type) {
@@ -86,14 +93,17 @@ bool DeviceBufferGLES::BindAndUploadDataIfNecessary(BindingType type) const {
8693
const auto& gl = reactor_->GetProcTable();
8794

8895
gl.BindBuffer(target_type, buffer.value());
89-
90-
if (upload_generation_ != generation_) {
91-
TRACE_EVENT1(
92-
"impeller", "BufferData", "Bytes",
93-
std::to_string(backing_store_->GetLength().GetByteSize()).c_str());
96+
if (!initialized_) {
9497
gl.BufferData(target_type, backing_store_->GetLength().GetByteSize(),
95-
backing_store_->GetBuffer(), GL_STATIC_DRAW);
96-
upload_generation_ = generation_;
98+
nullptr, GL_DYNAMIC_DRAW);
99+
initialized_ = true;
100+
}
101+
102+
if (dirty_range_.has_value()) {
103+
auto range = dirty_range_.value();
104+
gl.BufferSubData(target_type, range.offset, range.length,
105+
backing_store_->GetBuffer() + range.offset);
106+
dirty_range_ = std::nullopt;
97107
}
98108

99109
return true;
@@ -122,7 +132,8 @@ void DeviceBufferGLES::UpdateBufferData(
122132
if (update_buffer_data) {
123133
update_buffer_data(backing_store_->GetBuffer(),
124134
backing_store_->GetLength().GetByteSize());
125-
++generation_;
135+
Flush(Range{
136+
0, static_cast<size_t>(backing_store_->GetLength().GetByteSize())});
126137
}
127138
}
128139

impeller/renderer/backend/gles/device_buffer_gles.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@ class DeviceBufferGLES final
4444
ReactorGLES::Ref reactor_;
4545
HandleGLES handle_;
4646
mutable std::shared_ptr<Allocation> backing_store_;
47-
mutable uint32_t generation_ = 0;
48-
mutable uint32_t upload_generation_ = 0;
47+
mutable std::optional<Range> dirty_range_ = std::nullopt;
48+
mutable bool initialized_ = false;
4949

5050
// |DeviceBuffer|
5151
uint8_t* OnGetContents() const override;

impeller/renderer/backend/gles/proc_table_gles.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ struct GLProc {
104104
PROC(BlendEquationSeparate); \
105105
PROC(BlendFuncSeparate); \
106106
PROC(BufferData); \
107+
PROC(BufferSubData); \
107108
PROC(CheckFramebufferStatus); \
108109
PROC(Clear); \
109110
PROC(ClearColor); \

0 commit comments

Comments
 (0)