22 const std::shared_ptr<Allocator>&
allocator,
23 const std::shared_ptr<const IdleWaiter>& idle_waiter,
24 size_t minimum_uniform_alignment,
25 std::shared_ptr<const GpuSubmissionTracker> submission_tracker) {
26 return std::shared_ptr<HostBuffer>(
28 std::move(submission_tracker)));
31HostBuffer::HostBuffer(
32 const std::shared_ptr<Allocator>&
allocator,
33 const std::shared_ptr<const IdleWaiter>& idle_waiter,
34 size_t minimum_uniform_alignment,
35 std::shared_ptr<const GpuSubmissionTracker> submission_tracker)
37 idle_waiter_(idle_waiter),
38 submission_tracker_(
std::move(submission_tracker)),
39 minimum_uniform_alignment_(minimum_uniform_alignment) {
44 std::shared_ptr<DeviceBuffer> device_buffer =
allocator->CreateBuffer(desc);
45 FML_CHECK(device_buffer) <<
"Failed to allocate device buffer.";
46 device_buffers_[
i].push_back(device_buffer);
54 idle_waiter_->WaitIdle();
61 auto [range, device_buffer, raw_device_buffer] =
62 EmplaceInternal(buffer,
length, align);
64 return BufferView(std::move(device_buffer), range);
65 }
else if (raw_device_buffer) {
73 auto [range, device_buffer, raw_device_buffer] =
74 EmplaceInternal(buffer,
length);
76 return BufferView(std::move(device_buffer), range);
77 }
else if (raw_device_buffer) {
78 return BufferView(raw_device_buffer, range);
87 auto [range, device_buffer, raw_device_buffer] =
88 EmplaceInternal(
length, align, cb);
90 return BufferView(std::move(device_buffer), range);
91 }
else if (raw_device_buffer) {
101 .current_buffer = current_buffer_,
102 .total_buffer_count = device_buffers_[frame_index_].size(),
106bool HostBuffer::MaybeCreateNewBuffer() {
108 if (current_buffer_ >= device_buffers_[frame_index_].size()) {
112 std::shared_ptr<DeviceBuffer> buffer = allocator_->CreateBuffer(desc);
117 device_buffers_[frame_index_].push_back(std::move(buffer));
123std::tuple<Range, std::shared_ptr<DeviceBuffer>, DeviceBuffer*>
124HostBuffer::EmplaceInternal(
size_t length,
126 const EmplaceProc& cb) {
134 DeviceBufferDescriptor desc;
137 std::shared_ptr<DeviceBuffer> device_buffer =
138 allocator_->CreateBuffer(desc);
139 if (!device_buffer) {
143 cb(device_buffer->OnGetContents());
144 device_buffer->Flush(Range{0,
length});
146 return std::make_tuple(Range{0,
length}, std::move(device_buffer),
nullptr);
150 if (align > 0 && offset_ % align) {
151 padding = align - (offset_ % align);
154 if (!MaybeCreateNewBuffer()) {
161 const std::shared_ptr<DeviceBuffer>& current_buffer = GetCurrentBuffer();
162 auto contents = current_buffer->OnGetContents();
163 cb(contents + offset_);
164 Range output_range(offset_,
length);
165 current_buffer->Flush(output_range);
168 return std::make_tuple(output_range,
nullptr, current_buffer.get());
171std::tuple<Range, std::shared_ptr<DeviceBuffer>, DeviceBuffer*>
172HostBuffer::EmplaceInternal(
const void* buffer,
size_t length) {
176 DeviceBufferDescriptor desc;
179 std::shared_ptr<DeviceBuffer> device_buffer =
180 allocator_->CreateBuffer(desc);
181 if (!device_buffer) {
185 if (!device_buffer->CopyHostBuffer(
static_cast<const uint8_t*
>(buffer),
190 return std::make_tuple(Range{0,
length}, std::move(device_buffer),
nullptr);
193 auto old_length = GetLength();
195 if (!MaybeCreateNewBuffer()) {
199 old_length = GetLength();
201 const std::shared_ptr<DeviceBuffer>& current_buffer = GetCurrentBuffer();
202 auto contents = current_buffer->OnGetContents();
204 ::memmove(contents + old_length, buffer,
length);
205 current_buffer->Flush(Range{old_length,
length});
208 return std::make_tuple(Range{old_length,
length},
nullptr,
209 current_buffer.get());
212std::tuple<Range, std::shared_ptr<DeviceBuffer>, DeviceBuffer*>
213HostBuffer::EmplaceInternal(
const void* buffer,
size_t length,
size_t align) {
214 if (align == 0 || (GetLength() % align) == 0) {
215 return EmplaceInternal(buffer,
length);
219 auto padding = align - (GetLength() % align);
222 }
else if (!MaybeCreateNewBuffer()) {
227 return EmplaceInternal(buffer,
length);
230const std::shared_ptr<DeviceBuffer>& HostBuffer::GetCurrentBuffer()
const {
231 return device_buffers_[frame_index_][current_buffer_];
237 while (device_buffers_[frame_index_].size() > current_buffer_ + 1) {
238 device_buffers_[frame_index_].pop_back();
241 if (submission_tracker_) {
243 entry_stamps_[frame_index_] = submission_tracker_->LatestSubmission();
247 current_buffer_ = 0u;
250 if (!submission_tracker_) {
253 uint64_t completed = submission_tracker_->CompletedThrough();
256 std::erase_if(retired_buffers_, [completed](
const auto& retired) {
257 return retired.first <= completed;
260 if (entry_stamps_[frame_index_] <= completed) {
270 std::shared_ptr<DeviceBuffer> buffer = allocator_->CreateBuffer(desc);
272 VALIDATION_LOG <<
"Failed to replace an in-flight host buffer entry.";
275 retired_buffers_.emplace_back(entry_stamps_[frame_index_],
276 std::move(device_buffers_[frame_index_]));
277 device_buffers_[frame_index_].clear();
278 device_buffers_[frame_index_].push_back(std::move(buffer));
279 entry_stamps_[frame_index_] = 0;
283 return minimum_uniform_alignment_;
BufferView Emplace(const BufferType &buffer, size_t alignment=0)
Emplace non-uniform data (like contiguous vertices) onto the host buffer.
size_t GetMinimumUniformAlignment() const
Retrieve the minimum uniform buffer alignment in bytes.
TestStateQuery GetStateForTest()
Retrieve internal buffer state for test expectations.
std::function< void(uint8_t *buffer)> EmplaceProc
static std::shared_ptr< HostBuffer > Create(const std::shared_ptr< Allocator > &allocator, const std::shared_ptr< const IdleWaiter > &idle_waiter, size_t minimum_uniform_alignment, std::shared_ptr< const GpuSubmissionTracker > submission_tracker=nullptr)
void Reset()
Resets the contents of the HostBuffer to nothing so it can be reused.
#define FML_CHECK(condition)
Vector2 padding
The halo padding in source space.
std::shared_ptr< ImpellerAllocator > allocator
constexpr size_t kAllocatorBlockSize
static const constexpr size_t kHostBufferArenaSize
Approximately the same size as the max frames in flight.
Test only internal state.