blob: 96c114202f4cf8bf8267af918a8bd2e493d69f14 [file] [log] [blame]
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#pragma once
#include <initializer_list>
#include <map>
#include <vector>
#include "flutter/fml/macros.h"
#include "impeller/base/strings.h"
#include "impeller/core/allocator.h"
#include "impeller/core/device_buffer.h"
#include "impeller/core/formats.h"
#include "impeller/core/host_buffer.h"
#include "impeller/core/vertex_buffer.h"
#include "impeller/geometry/vector.h"
namespace impeller {
template <class VertexType_, class IndexType_ = uint16_t>
class VertexBufferBuilder {
public:
using VertexType = VertexType_;
using IndexType = IndexType_;
VertexBufferBuilder() = default;
~VertexBufferBuilder() = default;
constexpr impeller::IndexType GetIndexType() const {
if constexpr (sizeof(IndexType) == 2) {
return impeller::IndexType::k16bit;
} else if (sizeof(IndexType) == 4) {
return impeller::IndexType::k32bit;
} else {
return impeller::IndexType::kUnknown;
}
}
void SetLabel(std::string label) { label_ = std::move(label); }
void Reserve(size_t count) { return vertices_.reserve(count); }
void ReserveIndices(size_t count) { return indices_.reserve(count); }
bool HasVertices() const { return !vertices_.empty(); }
size_t GetVertexCount() const { return vertices_.size(); }
size_t GetIndexCount() const {
return indices_.size() > 0 ? indices_.size() : vertices_.size();
}
VertexBufferBuilder& AppendVertex(VertexType_ vertex) {
vertices_.emplace_back(std::move(vertex));
return *this;
}
VertexBufferBuilder& AddVertices(
std::initializer_list<VertexType_> vertices) {
vertices_.reserve(vertices.size());
for (auto& vertex : vertices) {
vertices_.emplace_back(std::move(vertex));
}
return *this;
}
VertexBufferBuilder& AppendIndex(IndexType_ index) {
indices_.emplace_back(index);
return *this;
}
VertexBuffer CreateVertexBuffer(HostBuffer& host_buffer) const {
VertexBuffer buffer;
buffer.vertex_buffer = CreateVertexBufferView(host_buffer);
buffer.index_buffer = CreateIndexBufferView(host_buffer);
buffer.index_count = GetIndexCount();
buffer.index_type = GetIndexType();
return buffer;
};
VertexBuffer CreateVertexBuffer(Allocator& device_allocator) const {
VertexBuffer buffer;
// This can be merged into a single allocation.
buffer.vertex_buffer = CreateVertexBufferView(device_allocator);
buffer.index_buffer = CreateIndexBufferView(device_allocator);
buffer.index_count = GetIndexCount();
buffer.index_type = GetIndexType();
return buffer;
};
void IterateVertices(const std::function<void(VertexType&)>& iterator) {
for (auto& vertex : vertices_) {
iterator(vertex);
}
}
private:
std::vector<VertexType> vertices_;
std::vector<IndexType> indices_;
std::string label_;
BufferView CreateVertexBufferView(HostBuffer& buffer) const {
return buffer.Emplace(vertices_.data(),
vertices_.size() * sizeof(VertexType),
alignof(VertexType));
}
BufferView CreateVertexBufferView(Allocator& allocator) const {
auto buffer = allocator.CreateBufferWithCopy(
reinterpret_cast<const uint8_t*>(vertices_.data()),
vertices_.size() * sizeof(VertexType));
if (!buffer) {
return {};
}
if (!label_.empty()) {
buffer->SetLabel(SPrintF("%s Vertices", label_.c_str()));
}
return buffer->AsBufferView();
}
std::vector<IndexType> CreateIndexBuffer() const {
if (indices_.size() > 0) {
return indices_;
}
// So dumb! We don't actually need an index buffer right now. But we will
// once de-duplication is done. So assume this is always done.
std::vector<IndexType> index_buffer;
for (size_t i = 0; i < vertices_.size(); i++) {
index_buffer.push_back(i);
}
return index_buffer;
}
BufferView CreateIndexBufferView(HostBuffer& buffer) const {
const auto index_buffer = CreateIndexBuffer();
return buffer.Emplace(index_buffer.data(),
index_buffer.size() * sizeof(IndexType),
alignof(IndexType));
}
BufferView CreateIndexBufferView(Allocator& allocator) const {
const auto index_buffer = CreateIndexBuffer();
auto buffer = allocator.CreateBufferWithCopy(
reinterpret_cast<const uint8_t*>(index_buffer.data()),
index_buffer.size() * sizeof(IndexType));
if (!buffer) {
return {};
}
if (!label_.empty()) {
buffer->SetLabel(SPrintF("%s Indices", label_.c_str()));
}
return buffer->AsBufferView();
}
};
} // namespace impeller