Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
host_buffer.cc
Go to the documentation of this file.
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
6
7#include <cstring>
8#include <tuple>
9
15
16namespace impeller {
17
18constexpr size_t kAllocatorBlockSize = 1024000; // 1024 Kb.
19
20std::shared_ptr<HostBuffer> HostBuffer::Create(
21 const std::shared_ptr<Allocator>& allocator) {
22 return std::shared_ptr<HostBuffer>(new HostBuffer(allocator));
23}
24
25HostBuffer::HostBuffer(const std::shared_ptr<Allocator>& allocator)
26 : allocator_(allocator) {
28 desc.size = kAllocatorBlockSize;
29 desc.storage_mode = StorageMode::kHostVisible;
30 for (auto i = 0u; i < kHostBufferArenaSize; i++) {
31 device_buffers_[i].push_back(allocator->CreateBuffer(desc));
32 }
33}
34
35HostBuffer::~HostBuffer() = default;
36
37void HostBuffer::SetLabel(std::string label) {
38 label_ = std::move(label);
39}
40
42 size_t length,
43 size_t align) {
44 auto [range, device_buffer] = EmplaceInternal(buffer, length, align);
45 if (!device_buffer) {
46 return {};
47 }
48 return BufferView{std::move(device_buffer), range};
49}
50
51BufferView HostBuffer::Emplace(const void* buffer, size_t length) {
52 auto [range, device_buffer] = EmplaceInternal(buffer, length);
53 if (!device_buffer) {
54 return {};
55 }
56 return BufferView{std::move(device_buffer), range};
57}
58
60 size_t align,
61 const EmplaceProc& cb) {
62 auto [range, device_buffer] = EmplaceInternal(length, align, cb);
63 if (!device_buffer) {
64 return {};
65 }
66 return BufferView{std::move(device_buffer), range};
67}
68
71 .current_frame = frame_index_,
72 .current_buffer = current_buffer_,
73 .total_buffer_count = device_buffers_[frame_index_].size(),
74 };
75}
76
77void HostBuffer::MaybeCreateNewBuffer() {
78 current_buffer_++;
79 if (current_buffer_ >= device_buffers_[frame_index_].size()) {
81 desc.size = kAllocatorBlockSize;
82 desc.storage_mode = StorageMode::kHostVisible;
83 device_buffers_[frame_index_].push_back(allocator_->CreateBuffer(desc));
84 }
85 offset_ = 0;
86}
87
88std::tuple<Range, std::shared_ptr<DeviceBuffer>> HostBuffer::EmplaceInternal(
89 size_t length,
90 size_t align,
91 const EmplaceProc& cb) {
92 if (!cb) {
93 return {};
94 }
95
96 // If the requested allocation is bigger than the block size, create a one-off
97 // device buffer and write to that.
99 DeviceBufferDescriptor desc;
100 desc.size = length;
101 desc.storage_mode = StorageMode::kHostVisible;
102 std::shared_ptr<DeviceBuffer> device_buffer =
103 allocator_->CreateBuffer(desc);
104 if (!device_buffer) {
105 return {};
106 }
107 if (cb) {
108 cb(device_buffer->OnGetContents());
109 device_buffer->Flush(Range{0, length});
110 }
111 return std::make_tuple(Range{0, length}, std::move(device_buffer));
112 }
113
114 size_t padding = 0;
115 if (align > 0 && offset_ % align) {
116 padding = align - (offset_ % align);
117 }
118 if (offset_ + padding + length > kAllocatorBlockSize) {
119 MaybeCreateNewBuffer();
120 } else {
121 offset_ += padding;
122 }
123
124 const std::shared_ptr<DeviceBuffer>& current_buffer = GetCurrentBuffer();
125 auto contents = current_buffer->OnGetContents();
126 cb(contents + offset_);
127 Range output_range(offset_, length);
128 current_buffer->Flush(output_range);
129
130 offset_ += length;
131 return std::make_tuple(output_range, current_buffer);
132}
133
134std::tuple<Range, std::shared_ptr<DeviceBuffer>> HostBuffer::EmplaceInternal(
135 const void* buffer,
136 size_t length) {
137 // If the requested allocation is bigger than the block size, create a one-off
138 // device buffer and write to that.
140 DeviceBufferDescriptor desc;
141 desc.size = length;
142 desc.storage_mode = StorageMode::kHostVisible;
143 std::shared_ptr<DeviceBuffer> device_buffer =
144 allocator_->CreateBuffer(desc);
145 if (!device_buffer) {
146 return {};
147 }
148 if (buffer) {
149 if (!device_buffer->CopyHostBuffer(static_cast<const uint8_t*>(buffer),
150 Range{0, length})) {
151 return {};
152 }
153 }
154 return std::make_tuple(Range{0, length}, std::move(device_buffer));
155 }
156
157 auto old_length = GetLength();
158 if (old_length + length > kAllocatorBlockSize) {
159 MaybeCreateNewBuffer();
160 }
161 old_length = GetLength();
162
163 const std::shared_ptr<DeviceBuffer>& current_buffer = GetCurrentBuffer();
164 auto contents = current_buffer->OnGetContents();
165 if (buffer) {
166 ::memmove(contents + old_length, buffer, length);
167 current_buffer->Flush(Range{old_length, length});
168 }
169 offset_ += length;
170 return std::make_tuple(Range{old_length, length}, current_buffer);
171}
172
173std::tuple<Range, std::shared_ptr<DeviceBuffer>>
174HostBuffer::EmplaceInternal(const void* buffer, size_t length, size_t align) {
175 if (align == 0 || (GetLength() % align) == 0) {
176 return EmplaceInternal(buffer, length);
177 }
178
179 {
180 auto padding = align - (GetLength() % align);
181 if (offset_ + padding < kAllocatorBlockSize) {
182 offset_ += padding;
183 } else {
184 MaybeCreateNewBuffer();
185 }
186 }
187
188 return EmplaceInternal(buffer, length);
189}
190
191const std::shared_ptr<DeviceBuffer>& HostBuffer::GetCurrentBuffer() const {
192 return device_buffers_[frame_index_][current_buffer_];
193}
194
196 // When resetting the host buffer state at the end of the frame, check if
197 // there are any unused buffers and remove them.
198 while (device_buffers_[frame_index_].size() > current_buffer_ + 1) {
199 device_buffers_[frame_index_].pop_back();
200 }
201
202 offset_ = 0u;
203 current_buffer_ = 0u;
204 frame_index_ = (frame_index_ + 1) % kHostBufferArenaSize;
205}
206
207} // namespace impeller
void SetLabel(std::string label)
TestStateQuery GetStateForTest()
Retrieve internal buffer state for test expectations.
static std::shared_ptr< HostBuffer > Create(const std::shared_ptr< Allocator > &allocator)
BufferView Emplace(const BufferType &buffer)
Emplace non-uniform data (like contiguous vertices) onto the host buffer.
Definition host_buffer.h:94
std::function< void(uint8_t *buffer)> EmplaceProc
void Reset()
Resets the contents of the HostBuffer to nothing so it can be reused.
static const uint8_t buffer[]
size_t length
constexpr size_t kAllocatorBlockSize
static const constexpr size_t kHostBufferArenaSize
Approximately the same size as the max frames in flight.
Definition host_buffer.h:22
Test only internal state.