blob: f1b670deea7d4fe21312c2636c868ea3e2092b74 [file] [log] [blame]
// Copyright 2016 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/ui/lib/escher/impl/mesh_manager.h"
#include <iterator>
#include "src/ui/lib/escher/geometry/types.h"
#include "src/ui/lib/escher/impl/command_buffer_pool.h"
#include "src/ui/lib/escher/impl/vulkan_utils.h"
#include "src/ui/lib/escher/resources/resource_recycler.h"
#include "src/ui/lib/escher/vk/buffer.h"
#include "src/ui/lib/escher/vk/gpu_allocator.h"
#include "src/ui/lib/escher/vk/vulkan_context.h"
namespace escher {
namespace impl {
MeshManager::MeshManager(CommandBufferPool* command_buffer_pool, GpuAllocator* allocator,
ResourceRecycler* resource_recycler)
: command_buffer_pool_(command_buffer_pool),
allocator_(allocator),
resource_recycler_(resource_recycler),
device_(command_buffer_pool->device()),
queue_(command_buffer_pool->queue()),
builder_count_(0) {}
MeshManager::~MeshManager() { FX_DCHECK(builder_count_ == 0); }
MeshBuilderPtr MeshManager::NewMeshBuilder(BatchGpuUploader* gpu_uploader, const MeshSpec& spec,
size_t max_vertex_count, size_t max_index_count) {
FX_DCHECK(spec.IsValidOneBufferMesh());
size_t stride = spec.stride(0);
return AdoptRef(new MeshManager::MeshBuilder(this, spec, max_vertex_count, max_index_count,
std::move(gpu_uploader)));
}
MeshManager::MeshBuilder::MeshBuilder(MeshManager* manager, const MeshSpec& spec,
size_t max_vertex_count, size_t max_index_count,
BatchGpuUploader* gpu_uploader)
: escher::MeshBuilder(max_vertex_count, max_index_count, spec.stride(0)),
manager_(manager),
spec_(spec),
is_built_(false),
gpu_uploader_(gpu_uploader) {
FX_DCHECK(spec.IsValidOneBufferMesh());
}
MeshManager::MeshBuilder::~MeshBuilder() {}
BoundingBox MeshManager::MeshBuilder::ComputeBoundingBox2D() const {
FX_DCHECK(spec_.attribute_offset(0, MeshAttribute::kPosition2D) == 0);
const uint8_t* vertex_ptr = vertex_staging_buffer_.data();
const vec2* pos = reinterpret_cast<const vec2*>(vertex_ptr);
vec3 min(*pos, 0);
vec3 max(*pos, 0);
for (size_t i = 1; i < vertex_count_; ++i) {
vertex_ptr += vertex_stride_;
pos = reinterpret_cast<const vec2*>(vertex_ptr);
min = glm::min(min, vec3(*pos, 0));
max = glm::max(max, vec3(*pos, 0));
}
return BoundingBox(min, max);
}
BoundingBox MeshManager::MeshBuilder::ComputeBoundingBox3D() const {
FX_DCHECK(spec_.attribute_offset(0, MeshAttribute::kPosition3D) == 0);
const uint8_t* vertex_ptr = vertex_staging_buffer_.data();
const vec3* pos = reinterpret_cast<const vec3*>(vertex_ptr);
vec3 min(*pos);
vec3 max(*pos);
for (size_t i = 1; i < vertex_count_; ++i) {
vertex_ptr += vertex_stride_;
pos = reinterpret_cast<const vec3*>(vertex_ptr);
min = glm::min(min, *pos);
max = glm::max(max, *pos);
}
return BoundingBox(min, max);
}
BoundingBox MeshManager::MeshBuilder::ComputeBoundingBox() const {
FX_DCHECK(vertex_count_ > 0);
FX_DCHECK(spec_.IsValidOneBufferMesh());
return spec_.has_attribute(0, MeshAttribute::kPosition2D) ? ComputeBoundingBox2D()
: ComputeBoundingBox3D();
}
MeshPtr MeshManager::MeshBuilder::Build() {
FX_DCHECK(!is_built_);
if (is_built_) {
return MeshPtr();
}
is_built_ = true;
vk::Device device = manager_->device_;
GpuAllocator* allocator = manager_->allocator_;
// TODO: use eTransferDstOptimal instead of eTransferDst?
auto vertex_buffer = allocator->AllocateBuffer(
manager_->resource_recycler(), vertex_count_ * vertex_stride_,
vk::BufferUsageFlagBits::eVertexBuffer | vk::BufferUsageFlagBits::eTransferSrc |
vk::BufferUsageFlagBits::eTransferDst,
vk::MemoryPropertyFlagBits::eDeviceLocal);
auto index_buffer = allocator->AllocateBuffer(
manager_->resource_recycler(), index_count_ * sizeof(uint32_t),
vk::BufferUsageFlagBits::eIndexBuffer | vk::BufferUsageFlagBits::eTransferSrc |
vk::BufferUsageFlagBits::eTransferDst,
vk::MemoryPropertyFlagBits::eDeviceLocal);
// Calculate bounding box using the staging buffers before they are cleared.
auto bounding_box = ComputeBoundingBox();
// |vertex_staging_buffer_| and |index_staging_buffer_| will be cleared after
// being moved to BatchGpuUploader, so that we will be able to reuse
// MeshBuilder.
gpu_uploader_->ScheduleWriteBuffer(vertex_buffer, std::move(vertex_staging_buffer_),
/* target_offset */ 0,
/* copy_size */ vertex_count_ * vertex_stride_);
gpu_uploader_->ScheduleWriteBuffer(index_buffer, std::move(index_staging_buffer_),
/* target_offset */ 0,
/* copy_size */ index_count_ * sizeof(uint32_t));
auto result = fxl::MakeRefCounted<Mesh>(manager_->resource_recycler(), spec_,
std::move(bounding_box), vertex_count_, index_count_,
std::move(vertex_buffer), std::move(index_buffer));
// Clear the vertex staging buffer and index staging buffer for future reuse.
vertex_count_ = 0U;
index_count_ = 0;
return result;
}
} // namespace impl
} // namespace escher