blob: d8998a120eefcf9debf77cf43560a720d5977eb9 [file] [log] [blame]
// Copyright 2018 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 "lib/escher/paper/paper_render_funcs.h"
#include "lib/escher/renderer/frame.h"
#include "lib/escher/renderer/render_queue_item.h"
#include "lib/escher/shape/mesh.h"
#include "lib/escher/vk/texture.h"
#include "lib/fxl/logging.h"
namespace {
constexpr uint32_t kMeshVertexBufferBindingIndex = 0;
constexpr uint32_t kMeshAttributeBindingIndices_Position2D[] = {
kMeshVertexBufferBindingIndex, 0};
constexpr uint32_t kMeshAttributeBindingIndices_Position3D[] = {
kMeshVertexBufferBindingIndex, 0};
constexpr uint32_t kMeshAttributeBindingIndices_PositionOffset[] = {
kMeshVertexBufferBindingIndex, 1};
constexpr uint32_t kMeshAttributeBindingIndices_UV[] = {
kMeshVertexBufferBindingIndex, 2};
constexpr uint32_t kMeshAttributeBindingIndices_PerimeterPos[] = {
kMeshVertexBufferBindingIndex, 3};
constexpr uint32_t kMeshUniformBindingIndices_ViewProjectionMatrix[] = {0, 0};
} // anonymous namespace
namespace escher {
void PaperRenderFuncs::RenderMesh(CommandBuffer* cb,
const RenderQueueItem* items,
uint32_t instance_count) {
FXL_DCHECK(cb && items && instance_count > 0);
auto* mesh_data = static_cast<const MeshObjectData*>(items[0].object_data);
// Set up per-object state.
cb->SetShaderProgram(mesh_data->shader_program);
cb->BindTexture(1, 1, mesh_data->texture);
cb->BindIndices(mesh_data->index_buffer, mesh_data->index_buffer_offset,
vk::IndexType::eUint32);
for (uint32_t i = 0; i < mesh_data->vertex_binding_count; ++i) {
auto& b = mesh_data->vertex_bindings[i];
cb->BindVertices(b.binding_index, b.buffer, b.offset, b.stride);
}
for (uint32_t i = 0; i < mesh_data->vertex_attribute_count; ++i) {
auto& at = mesh_data->vertex_attributes[i];
cb->SetVertexAttributes(at.binding_index, at.attribute_index, at.format,
at.offset);
}
for (uint32_t i = 0; i < mesh_data->uniform_binding_count; ++i) {
auto& b = mesh_data->uniform_bindings[i];
cb->BindUniformBuffer(b.descriptor_set_index, b.binding_index, b.buffer,
b.offset, b.size);
}
// For each instance, set up per-instance state and draw.
for (uint32_t i = 0; i < instance_count; ++i) {
FXL_DCHECK(items[i].object_data == mesh_data);
const MeshInstanceData* instance_data =
static_cast<const MeshInstanceData*>(items[i].instance_data);
auto& b = instance_data->object_properties;
cb->BindUniformBuffer(b.descriptor_set_index, b.binding_index, b.buffer,
b.offset, b.size);
cb->DrawIndexed(mesh_data->num_indices);
}
}
PaperRenderFuncs::MeshObjectData* PaperRenderFuncs::NewMeshObjectData(
const FramePtr& frame, const MeshPtr& mesh, const TexturePtr& texture,
const ShaderProgramPtr& program,
const UniformAllocation& view_projection_uniform) {
FXL_DCHECK(mesh);
FXL_DCHECK(texture);
// TODO(ES-103): avoid reaching in to impl::CommandBuffer for keep-alive.
frame->command_buffer()->KeepAlive(mesh.get());
frame->command_buffer()->KeepAlive(texture.get());
// TODO(ES-104): Replace TakeWaitSemaphore() with something better.
frame->command_buffer()->TakeWaitSemaphore(
mesh, vk::PipelineStageFlagBits::eTopOfPipe);
auto* obj = frame->Allocate<MeshObjectData>();
obj->index_buffer = mesh->vk_index_buffer();
obj->index_type = vk::IndexType::eUint32;
obj->index_buffer_offset = mesh->index_buffer_offset();
obj->num_indices = mesh->num_indices();
obj->vertex_binding_count = 1;
obj->vertex_bindings = frame->Allocate<VertexBinding>();
auto& vertex_buffer = mesh->vertex_buffer();
// TODO(ES-103): avoid reaching in to impl::CommandBuffer for keep-alive.
frame->command_buffer()->KeepAlive(vertex_buffer);
obj->vertex_bindings[0] =
VertexBinding{.binding_index = kMeshVertexBufferBindingIndex,
.buffer = vertex_buffer.get(),
.offset = mesh->vertex_buffer_offset(),
.stride = mesh->spec().GetStride()};
// Set up vertex attributes based on MeshSpec.
auto& mesh_spec = mesh->spec();
size_t num_attributes = mesh_spec.GetNumAttributes();
obj->vertex_attribute_count = num_attributes;
obj->vertex_attributes =
frame->AllocateMany<VertexAttributeBinding>(num_attributes);
size_t attribute_index = 0;
if (mesh_spec.flags & MeshAttribute::kPosition2D) {
obj->vertex_attributes[attribute_index++] = VertexAttributeBinding{
.binding_index = kMeshAttributeBindingIndices_Position2D[0],
.attribute_index = kMeshAttributeBindingIndices_Position2D[1],
.format = vk::Format::eR32G32Sfloat,
.offset = mesh->spec().GetAttributeOffset(MeshAttribute::kPosition2D)};
}
if (mesh_spec.flags & MeshAttribute::kPosition3D) {
obj->vertex_attributes[attribute_index++] = VertexAttributeBinding{
.binding_index = kMeshAttributeBindingIndices_Position3D[0],
.attribute_index = kMeshAttributeBindingIndices_Position3D[1],
.format = vk::Format::eR32G32B32Sfloat,
.offset = mesh->spec().GetAttributeOffset(MeshAttribute::kPosition3D)};
}
if (mesh_spec.flags & MeshAttribute::kPositionOffset) {
obj->vertex_attributes[attribute_index++] = VertexAttributeBinding{
.binding_index = kMeshAttributeBindingIndices_PositionOffset[0],
.attribute_index = kMeshAttributeBindingIndices_PositionOffset[1],
.format = vk::Format::eR32G32Sfloat,
.offset =
mesh->spec().GetAttributeOffset(MeshAttribute::kPositionOffset)};
}
if (mesh_spec.flags & MeshAttribute::kUV) {
obj->vertex_attributes[attribute_index++] = VertexAttributeBinding{
.binding_index = kMeshAttributeBindingIndices_UV[0],
.attribute_index = kMeshAttributeBindingIndices_UV[1],
.format = vk::Format::eR32G32Sfloat,
.offset = mesh->spec().GetAttributeOffset(MeshAttribute::kUV)};
}
if (mesh_spec.flags & MeshAttribute::kPerimeterPos) {
obj->vertex_attributes[attribute_index++] = VertexAttributeBinding{
.binding_index = kMeshAttributeBindingIndices_PerimeterPos[0],
.attribute_index = kMeshAttributeBindingIndices_PerimeterPos[1],
.format = vk::Format::eR32G32Sfloat,
.offset =
mesh->spec().GetAttributeOffset(MeshAttribute::kPerimeterPos)};
}
FXL_DCHECK(attribute_index == num_attributes); // sanity check
obj->uniform_binding_count = 1;
obj->uniform_bindings = frame->Allocate<UniformBinding>();
// Use the same view-projection matrix for each mesh.
obj->uniform_bindings[0] = UniformBinding{
.descriptor_set_index =
kMeshUniformBindingIndices_ViewProjectionMatrix[0],
.binding_index = kMeshUniformBindingIndices_ViewProjectionMatrix[1],
.buffer = view_projection_uniform.buffer,
.offset = view_projection_uniform.offset,
.size = view_projection_uniform.size};
obj->texture = texture.get();
obj->shader_program = program.get();
return obj;
}
} // namespace escher