Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion ci/licenses_golden/excluded_files
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@
../../../flutter/impeller/entity/contents/filters/directional_gaussian_blur_filter_contents_unittests.cc
../../../flutter/impeller/entity/contents/filters/gaussian_blur_filter_contents_unittests.cc
../../../flutter/impeller/entity/contents/filters/inputs/filter_input_unittests.cc
../../../flutter/impeller/entity/contents/host_buffer_unittests.cc
../../../flutter/impeller/entity/contents/test
../../../flutter/impeller/entity/contents/tiled_texture_contents_unittests.cc
../../../flutter/impeller/entity/contents/vertices_contents_unittests.cc
Expand Down Expand Up @@ -187,7 +188,6 @@
../../../flutter/impeller/renderer/compute_subgroup_unittests.cc
../../../flutter/impeller/renderer/compute_unittests.cc
../../../flutter/impeller/renderer/device_buffer_unittests.cc
../../../flutter/impeller/renderer/host_buffer_unittests.cc
../../../flutter/impeller/renderer/pipeline_descriptor_unittests.cc
../../../flutter/impeller/renderer/pool_unittests.cc
../../../flutter/impeller/renderer/renderer_dart_unittests.cc
Expand Down
10 changes: 9 additions & 1 deletion impeller/aiks/aiks_context.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#include "impeller/aiks/aiks_context.h"

#include "fml/closure.h"
#include "impeller/aiks/picture.h"
#include "impeller/typographer/typographer_context.h"

Expand Down Expand Up @@ -40,11 +41,18 @@ ContentContext& AiksContext::GetContentContext() const {
return *content_context_;
}

bool AiksContext::Render(const Picture& picture, RenderTarget& render_target) {
bool AiksContext::Render(const Picture& picture,
RenderTarget& render_target,
bool reset_host_buffer) {
if (!IsValid()) {
return false;
}

fml::ScopedCleanupClosure closure([&]() {
if (reset_host_buffer) {
content_context_->GetTransientsBuffer().Reset();
}
});
if (picture.pass) {
return picture.pass->Render(*content_context_, render_target);
}
Expand Down
4 changes: 3 additions & 1 deletion impeller/aiks/aiks_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@ class AiksContext {

ContentContext& GetContentContext() const;

bool Render(const Picture& picture, RenderTarget& render_target);
bool Render(const Picture& picture,
RenderTarget& render_target,
bool reset_host_buffer);

private:
std::shared_ptr<Context> context_;
Expand Down
2 changes: 1 addition & 1 deletion impeller/aiks/aiks_playground.cc
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ bool AiksPlayground::OpenPlaygroundHere(AiksPlaygroundCallback callback) {
if (!picture.has_value()) {
return false;
}
return renderer.Render(*picture, render_target);
return renderer.Render(*picture, render_target, true);
});
}

Expand Down
2 changes: 1 addition & 1 deletion impeller/aiks/picture.cc
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ std::shared_ptr<Texture> Picture::RenderToTexture(
return nullptr;
}

if (!context.Render(*this, target)) {
if (!context.Render(*this, target, false)) {
VALIDATION_LOG << "Could not render Picture to Texture.";
return nullptr;
}
Expand Down
1 change: 0 additions & 1 deletion impeller/base/allocation.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
#define FLUTTER_IMPELLER_BASE_ALLOCATION_H_

#include <cstdint>
#include <limits>
#include <memory>

#include "flutter/fml/mapping.h"
Expand Down
3 changes: 1 addition & 2 deletions impeller/core/buffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@ class Buffer {
public:
virtual ~Buffer();

virtual std::shared_ptr<const DeviceBuffer> GetDeviceBuffer(
Allocator& allocator) const = 0;
virtual std::shared_ptr<const DeviceBuffer> GetDeviceBuffer() const = 0;
};

} // namespace impeller
Expand Down
5 changes: 3 additions & 2 deletions impeller/core/device_buffer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@ DeviceBuffer::DeviceBuffer(DeviceBufferDescriptor desc) : desc_(desc) {}
DeviceBuffer::~DeviceBuffer() = default;

// |Buffer|
std::shared_ptr<const DeviceBuffer> DeviceBuffer::GetDeviceBuffer(
Allocator& allocator) const {
std::shared_ptr<const DeviceBuffer> DeviceBuffer::GetDeviceBuffer() const {
return shared_from_this();
}

void DeviceBuffer::Flush(std::optional<Range> range) const {}

BufferView DeviceBuffer::AsBufferView() const {
BufferView view;
view.buffer = shared_from_this();
Expand Down
12 changes: 10 additions & 2 deletions impeller/core/device_buffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,21 @@ class DeviceBuffer : public Buffer,
uint16_t row_bytes) const;

// |Buffer|
std::shared_ptr<const DeviceBuffer> GetDeviceBuffer(
Allocator& allocator) const;
std::shared_ptr<const DeviceBuffer> GetDeviceBuffer() const;

const DeviceBufferDescriptor& GetDeviceBufferDescriptor() const;

virtual uint8_t* OnGetContents() const = 0;

/// Make any pending writes visible to the GPU.
///
/// This method must be called if the device pointer provided by
/// [OnGetContents] is written to without using [CopyHostBuffer]. On Devices
/// with coherent host memory, this method will not perform extra work.
///
/// If the range is not provided, the entire buffer is flushed.
virtual void Flush(std::optional<Range> range = std::nullopt) const;

protected:
const DeviceBufferDescriptor desc_;

Expand Down
191 changes: 122 additions & 69 deletions impeller/core/host_buffer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,143 +4,196 @@

#include "impeller/core/host_buffer.h"

#include <algorithm>
#include <cstring>

#include "flutter/fml/logging.h"
#include <tuple>

#include "impeller/core/allocator.h"
#include "impeller/core/buffer_view.h"
#include "impeller/core/device_buffer.h"
#include "impeller/core/device_buffer_descriptor.h"
#include "impeller/core/formats.h"

namespace impeller {

std::shared_ptr<HostBuffer> HostBuffer::Create() {
return std::shared_ptr<HostBuffer>(new HostBuffer());
constexpr size_t kAllocatorBlockSize = 1024000; // 1024 Kb.

std::shared_ptr<HostBuffer> HostBuffer::Create(
const std::shared_ptr<Allocator>& allocator) {
return std::shared_ptr<HostBuffer>(new HostBuffer(allocator));
}

HostBuffer::HostBuffer() = default;
HostBuffer::HostBuffer(const std::shared_ptr<Allocator>& allocator)
: allocator_(allocator) {
DeviceBufferDescriptor desc;
desc.size = kAllocatorBlockSize;
desc.storage_mode = StorageMode::kHostVisible;
for (auto i = 0u; i < kHostBufferArenaSize; i++) {
device_buffers_[i].push_back(allocator->CreateBuffer(desc));
}
}

HostBuffer::~HostBuffer() = default;

void HostBuffer::SetLabel(std::string label) {
state_->label = std::move(label);
label_ = std::move(label);
}

BufferView HostBuffer::Emplace(const void* buffer,
size_t length,
size_t align) {
auto [device_buffer, range] = state_->Emplace(buffer, length, align);
auto [data, range, device_buffer] = EmplaceInternal(buffer, length, align);
if (!device_buffer) {
return {};
}
return BufferView{state_, device_buffer, range};
return BufferView{std::move(device_buffer), data, range};
}

BufferView HostBuffer::Emplace(const void* buffer, size_t length) {
auto [device_buffer, range] = state_->Emplace(buffer, length);
auto [data, range, device_buffer] = EmplaceInternal(buffer, length);
if (!device_buffer) {
return {};
}
return BufferView{state_, device_buffer, range};
return BufferView{std::move(device_buffer), data, range};
}

BufferView HostBuffer::Emplace(size_t length,
size_t align,
const EmplaceProc& cb) {
auto [buffer, range] = state_->Emplace(length, align, cb);
if (!buffer) {
auto [data, range, device_buffer] = EmplaceInternal(length, align, cb);
if (!device_buffer) {
return {};
}
return BufferView{state_, buffer, range};
}

std::shared_ptr<const DeviceBuffer> HostBuffer::GetDeviceBuffer(
Allocator& allocator) const {
return state_->GetDeviceBuffer(allocator);
return BufferView{std::move(device_buffer), data, range};
}

void HostBuffer::Reset() {
state_->Reset();
HostBuffer::TestStateQuery HostBuffer::GetStateForTest() {
return HostBuffer::TestStateQuery{
.current_frame = frame_index_,
.current_buffer = current_buffer_,
.total_buffer_count = device_buffers_[frame_index_].size(),
};
}

size_t HostBuffer::GetSize() const {
return state_->GetReservedLength();
}

size_t HostBuffer::GetLength() const {
return state_->GetLength();
void HostBuffer::MaybeCreateNewBuffer(size_t required_size) {
current_buffer_++;
if (current_buffer_ >= device_buffers_[frame_index_].size()) {
FML_DCHECK(required_size <= kAllocatorBlockSize);
DeviceBufferDescriptor desc;
desc.size = kAllocatorBlockSize;
desc.storage_mode = StorageMode::kHostVisible;
device_buffers_[frame_index_].push_back(allocator_->CreateBuffer(desc));
}
offset_ = 0;
}

std::pair<uint8_t*, Range> HostBuffer::HostBufferState::Emplace(
size_t length,
size_t align,
const EmplaceProc& cb) {
std::tuple<uint8_t*, Range, std::shared_ptr<DeviceBuffer>>
HostBuffer::EmplaceInternal(size_t length,
size_t align,
const EmplaceProc& cb) {
if (!cb) {
return {};
}

// If the requested allocation is bigger than the block size, create a one-off
// device buffer and write to that.
if (length > kAllocatorBlockSize) {
DeviceBufferDescriptor desc;
desc.size = length;
desc.storage_mode = StorageMode::kHostVisible;
auto device_buffer = allocator_->CreateBuffer(desc);
if (!device_buffer) {
return {};
}
if (cb) {
cb(device_buffer->OnGetContents());
device_buffer->Flush(Range{0, length});
}
return std::make_tuple(device_buffer->OnGetContents(), Range{0, length},
device_buffer);
}

auto old_length = GetLength();
if (!Truncate(old_length + length)) {
return {};
if (old_length + length > kAllocatorBlockSize) {
MaybeCreateNewBuffer(length);
}
generation++;
cb(GetBuffer() + old_length);
old_length = GetLength();

auto current_buffer = GetCurrentBuffer();
cb(current_buffer->OnGetContents() + old_length);
current_buffer->Flush(Range{old_length, length});

return std::make_pair(GetBuffer(), Range{old_length, length});
offset_ += length;
auto contents = current_buffer->OnGetContents();
return std::make_tuple(contents, Range{old_length, length},
std::move(current_buffer));
}

std::shared_ptr<const DeviceBuffer>
HostBuffer::HostBufferState::GetDeviceBuffer(Allocator& allocator) const {
if (generation == device_buffer_generation) {
return device_buffer;
}
auto new_buffer = allocator.CreateBufferWithCopy(GetBuffer(), GetLength());
if (!new_buffer) {
return nullptr;
std::tuple<uint8_t*, Range, std::shared_ptr<DeviceBuffer>>
HostBuffer::EmplaceInternal(const void* buffer, size_t length) {
// If the requested allocation is bigger than the block size, create a one-off
// device buffer and write to that.
if (length > kAllocatorBlockSize) {
DeviceBufferDescriptor desc;
desc.size = length;
desc.storage_mode = StorageMode::kHostVisible;
auto device_buffer = allocator_->CreateBuffer(desc);
if (!device_buffer) {
return {};
}
if (buffer) {
if (!device_buffer->CopyHostBuffer(static_cast<const uint8_t*>(buffer),
Range{0, length})) {
return {};
}
}
return std::make_tuple(device_buffer->OnGetContents(), Range{0, length},
device_buffer);
}
new_buffer->SetLabel(label);
device_buffer_generation = generation;
device_buffer = std::move(new_buffer);
return device_buffer;
}

std::pair<uint8_t*, Range> HostBuffer::HostBufferState::Emplace(
const void* buffer,
size_t length) {
auto old_length = GetLength();
if (!Truncate(old_length + length)) {
return {};
if (old_length + length > kAllocatorBlockSize) {
MaybeCreateNewBuffer(length);
}
generation++;
old_length = GetLength();

auto current_buffer = GetCurrentBuffer();
if (buffer) {
::memmove(GetBuffer() + old_length, buffer, length);
::memmove(current_buffer->OnGetContents() + old_length, buffer, length);
current_buffer->Flush(Range{old_length, length});
}
return std::make_pair(GetBuffer(), Range{old_length, length});
offset_ += length;
auto contents = current_buffer->OnGetContents();
return std::make_tuple(contents, Range{old_length, length},
std::move(current_buffer));
}

std::pair<uint8_t*, Range> HostBuffer::HostBufferState::Emplace(
const void* buffer,
size_t length,
size_t align) {
std::tuple<uint8_t*, Range, std::shared_ptr<DeviceBuffer>>
HostBuffer::EmplaceInternal(const void* buffer, size_t length, size_t align) {
if (align == 0 || (GetLength() % align) == 0) {
return Emplace(buffer, length);
return EmplaceInternal(buffer, length);
}

{
auto [buffer, range] = Emplace(nullptr, align - (GetLength() % align));
auto [buffer, range, device_buffer] =
EmplaceInternal(nullptr, align - (GetLength() % align));
if (!buffer) {
return {};
}
}

return Emplace(buffer, length);
return EmplaceInternal(buffer, length);
}

void HostBuffer::HostBufferState::Reset() {
generation += 1;
device_buffer = nullptr;
bool did_truncate = Truncate(0);
FML_CHECK(did_truncate);
void HostBuffer::Reset() {
// When resetting the host buffer state at the end of the frame, check if
// there are any unused buffers and remove them.
while (device_buffers_[frame_index_].size() > current_buffer_ + 1) {
device_buffers_[frame_index_].pop_back();
}

offset_ = 0u;
current_buffer_ = 0u;
frame_index_ = (frame_index_ + 1) % kHostBufferArenaSize;
}

} // namespace impeller
Loading