Home | History | Annotate | Download | only in smoke
      1 /*
      2  * Copyright (C) 2016 Google, Inc.
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *     http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include <cassert>
     18 #include <cmath>
     19 #include <cstring>
     20 #include <array>
     21 #include <unordered_map>
     22 
     23 #include "Helpers.h"
     24 #include "Meshes.h"
     25 
     26 namespace {
     27 
     28 class Mesh {
     29    public:
     30     struct Position {
     31         float x;
     32         float y;
     33         float z;
     34     };
     35 
     36     struct Normal {
     37         float x;
     38         float y;
     39         float z;
     40     };
     41 
     42     struct Face {
     43         int v0;
     44         int v1;
     45         int v2;
     46     };
     47 
     48     static uint32_t vertex_stride() {
     49         // Position + Normal
     50         const int comp_count = 6;
     51 
     52         return sizeof(float) * comp_count;
     53     }
     54 
     55     static VkVertexInputBindingDescription vertex_input_binding() {
     56         VkVertexInputBindingDescription vi_binding = {};
     57         vi_binding.binding = 0;
     58         vi_binding.stride = vertex_stride();
     59         vi_binding.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
     60 
     61         return vi_binding;
     62     }
     63 
     64     static std::vector<VkVertexInputAttributeDescription> vertex_input_attributes() {
     65         std::vector<VkVertexInputAttributeDescription> vi_attrs(2);
     66         // Position
     67         vi_attrs[0].location = 0;
     68         vi_attrs[0].binding = 0;
     69         vi_attrs[0].format = VK_FORMAT_R32G32B32_SFLOAT;
     70         vi_attrs[0].offset = 0;
     71         // Normal
     72         vi_attrs[1].location = 1;
     73         vi_attrs[1].binding = 0;
     74         vi_attrs[1].format = VK_FORMAT_R32G32B32_SFLOAT;
     75         vi_attrs[1].offset = sizeof(float) * 3;
     76 
     77         return vi_attrs;
     78     }
     79 
     80     static VkIndexType index_type() { return VK_INDEX_TYPE_UINT32; }
     81 
     82     static VkPipelineInputAssemblyStateCreateInfo input_assembly_state() {
     83         VkPipelineInputAssemblyStateCreateInfo ia_info = {};
     84         ia_info.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
     85         ia_info.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
     86         ia_info.primitiveRestartEnable = false;
     87         return ia_info;
     88     }
     89 
     90     void build(const std::vector<std::array<float, 6>> &vertices, const std::vector<std::array<int, 3>> &faces) {
     91         positions_.reserve(vertices.size());
     92         normals_.reserve(vertices.size());
     93         for (const auto &v : vertices) {
     94             positions_.emplace_back(Position{v[0], v[1], v[2]});
     95             normals_.emplace_back(Normal{v[3], v[4], v[5]});
     96         }
     97 
     98         faces_.reserve(faces.size());
     99         for (const auto &f : faces) faces_.emplace_back(Face{f[0], f[1], f[2]});
    100     }
    101 
    102     uint32_t vertex_count() const { return static_cast<uint32_t>(positions_.size()); }
    103 
    104     VkDeviceSize vertex_buffer_size() const { return vertex_stride() * vertex_count(); }
    105 
    106     void vertex_buffer_write(void *data) const {
    107         float *dst = reinterpret_cast<float *>(data);
    108         for (size_t i = 0; i < positions_.size(); i++) {
    109             const Position &pos = positions_[i];
    110             const Normal &normal = normals_[i];
    111             dst[0] = pos.x;
    112             dst[1] = pos.y;
    113             dst[2] = pos.z;
    114             dst[3] = normal.x;
    115             dst[4] = normal.y;
    116             dst[5] = normal.z;
    117             dst += 6;
    118         }
    119     }
    120 
    121     uint32_t index_count() const { return static_cast<uint32_t>(faces_.size()) * 3; }
    122 
    123     VkDeviceSize index_buffer_size() const { return sizeof(uint32_t) * index_count(); }
    124 
    125     void index_buffer_write(void *data) const {
    126         uint32_t *dst = reinterpret_cast<uint32_t *>(data);
    127         for (const auto &face : faces_) {
    128             dst[0] = face.v0;
    129             dst[1] = face.v1;
    130             dst[2] = face.v2;
    131             dst += 3;
    132         }
    133     }
    134 
    135     std::vector<Position> positions_;
    136     std::vector<Normal> normals_;
    137     std::vector<Face> faces_;
    138 };
    139 
    140 class BuildPyramid {
    141    public:
    142     BuildPyramid(Mesh &mesh) {
    143         const std::vector<std::array<float, 6>> vertices = {
    144             //      position                normal
    145             {{0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f}},     {{-1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f}},
    146             {{1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f}}, {{1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f}},
    147             {{-1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f}},
    148         };
    149 
    150         const std::vector<std::array<int, 3>> faces = {
    151             {{0, 1, 2}}, {{0, 2, 3}}, {{0, 3, 4}}, {{0, 4, 1}}, {{1, 4, 3}}, {{1, 3, 2}},
    152         };
    153 
    154         mesh.build(vertices, faces);
    155     }
    156 };
    157 
    158 class BuildIcosphere {
    159    public:
    160     BuildIcosphere(Mesh &mesh) : mesh_(mesh), radius_(1.0f) {
    161         const int tessellate_level = 2;
    162 
    163         build_icosahedron();
    164         for (int i = 0; i < tessellate_level; i++) tessellate();
    165     }
    166 
    167    private:
    168     void build_icosahedron() {
    169         // https://en.wikipedia.org/wiki/Regular_icosahedron
    170         const float l1 = std::sqrt(2.0f / (5.0f + std::sqrt(5.0f))) * radius_;
    171         const float l2 = std::sqrt(2.0f / (5.0f - std::sqrt(5.0f))) * radius_;
    172         // vertices are from three golden rectangles
    173         const std::vector<std::array<float, 6>> icosahedron_vertices = {
    174             //   position           normal
    175             {{
    176                 -l1, -l2, 0.0f, -l1, -l2, 0.0f,
    177             }},
    178             {{
    179                 l1, -l2, 0.0f, l1, -l2, 0.0f,
    180             }},
    181             {{
    182                 l1, l2, 0.0f, l1, l2, 0.0f,
    183             }},
    184             {{
    185                 -l1, l2, 0.0f, -l1, l2, 0.0f,
    186             }},
    187 
    188             {{
    189                 -l2, 0.0f, -l1, -l2, 0.0f, -l1,
    190             }},
    191             {{
    192                 l2, 0.0f, -l1, l2, 0.0f, -l1,
    193             }},
    194             {{
    195                 l2, 0.0f, l1, l2, 0.0f, l1,
    196             }},
    197             {{
    198                 -l2, 0.0f, l1, -l2, 0.0f, l1,
    199             }},
    200 
    201             {{
    202                 0.0f, -l1, -l2, 0.0f, -l1, -l2,
    203             }},
    204             {{
    205                 0.0f, l1, -l2, 0.0f, l1, -l2,
    206             }},
    207             {{
    208                 0.0f, l1, l2, 0.0f, l1, l2,
    209             }},
    210             {{
    211                 0.0f, -l1, l2, 0.0f, -l1, l2,
    212             }},
    213         };
    214         const std::vector<std::array<int, 3>> icosahedron_faces = {
    215             // triangles sharing vertex 0
    216             {{0, 1, 11}},
    217             {{0, 11, 7}},
    218             {{0, 7, 4}},
    219             {{0, 4, 8}},
    220             {{0, 8, 1}},
    221             // adjacent triangles
    222             {{11, 1, 6}},
    223             {{7, 11, 10}},
    224             {{4, 7, 3}},
    225             {{8, 4, 9}},
    226             {{1, 8, 5}},
    227             // triangles sharing vertex 2
    228             {{2, 3, 10}},
    229             {{2, 10, 6}},
    230             {{2, 6, 5}},
    231             {{2, 5, 9}},
    232             {{2, 9, 3}},
    233             // adjacent triangles
    234             {{10, 3, 7}},
    235             {{6, 10, 11}},
    236             {{5, 6, 1}},
    237             {{9, 5, 8}},
    238             {{3, 9, 4}},
    239         };
    240 
    241         mesh_.build(icosahedron_vertices, icosahedron_faces);
    242     }
    243 
    244     void tessellate() {
    245         size_t middle_point_count = mesh_.faces_.size() * 3 / 2;
    246         size_t final_face_count = mesh_.faces_.size() * 4;
    247 
    248         std::vector<Mesh::Face> faces;
    249         faces.reserve(final_face_count);
    250 
    251         middle_points_.clear();
    252         middle_points_.reserve(middle_point_count);
    253 
    254         mesh_.positions_.reserve(mesh_.vertex_count() + middle_point_count);
    255         mesh_.normals_.reserve(mesh_.vertex_count() + middle_point_count);
    256 
    257         for (const auto &f : mesh_.faces_) {
    258             int v0 = f.v0;
    259             int v1 = f.v1;
    260             int v2 = f.v2;
    261 
    262             int v01 = add_middle_point(v0, v1);
    263             int v12 = add_middle_point(v1, v2);
    264             int v20 = add_middle_point(v2, v0);
    265 
    266             faces.emplace_back(Mesh::Face{v0, v01, v20});
    267             faces.emplace_back(Mesh::Face{v1, v12, v01});
    268             faces.emplace_back(Mesh::Face{v2, v20, v12});
    269             faces.emplace_back(Mesh::Face{v01, v12, v20});
    270         }
    271 
    272         mesh_.faces_.swap(faces);
    273     }
    274 
    275     int add_middle_point(int a, int b) {
    276         uint64_t key = (a < b) ? ((uint64_t)a << 32 | b) : ((uint64_t)b << 32 | a);
    277         auto it = middle_points_.find(key);
    278         if (it != middle_points_.end()) return it->second;
    279 
    280         const Mesh::Position &pos_a = mesh_.positions_[a];
    281         const Mesh::Position &pos_b = mesh_.positions_[b];
    282         Mesh::Position pos_mid = {
    283             (pos_a.x + pos_b.x) / 2.0f, (pos_a.y + pos_b.y) / 2.0f, (pos_a.z + pos_b.z) / 2.0f,
    284         };
    285         float scale = radius_ / std::sqrt(pos_mid.x * pos_mid.x + pos_mid.y * pos_mid.y + pos_mid.z * pos_mid.z);
    286         pos_mid.x *= scale;
    287         pos_mid.y *= scale;
    288         pos_mid.z *= scale;
    289 
    290         Mesh::Normal normal_mid = {pos_mid.x, pos_mid.y, pos_mid.z};
    291         normal_mid.x /= radius_;
    292         normal_mid.y /= radius_;
    293         normal_mid.z /= radius_;
    294 
    295         mesh_.positions_.emplace_back(pos_mid);
    296         mesh_.normals_.emplace_back(normal_mid);
    297 
    298         int mid = mesh_.vertex_count() - 1;
    299         middle_points_.emplace(std::make_pair(key, mid));
    300 
    301         return mid;
    302     }
    303 
    304     Mesh &mesh_;
    305     const float radius_;
    306     std::unordered_map<uint64_t, uint32_t> middle_points_;
    307 };
    308 
    309 class BuildTeapot {
    310    public:
    311     BuildTeapot(Mesh &mesh) {
    312 #include "Meshes.teapot.h"
    313         const int position_count = sizeof(teapot_positions) / sizeof(teapot_positions[0]);
    314         const int index_count = sizeof(teapot_indices) / sizeof(teapot_indices[0]);
    315         assert(position_count % 3 == 0 && index_count % 3 == 0);
    316 
    317         Mesh::Position translate;
    318         float scale;
    319         get_transform(teapot_positions, position_count, translate, scale);
    320 
    321         for (int i = 0; i < position_count; i += 3) {
    322             mesh.positions_.emplace_back(Mesh::Position{
    323                 (teapot_positions[i + 0] + translate.x) * scale, (teapot_positions[i + 1] + translate.y) * scale,
    324                 (teapot_positions[i + 2] + translate.z) * scale,
    325             });
    326 
    327             mesh.normals_.emplace_back(Mesh::Normal{
    328                 teapot_normals[i + 0], teapot_normals[i + 1], teapot_normals[i + 2],
    329             });
    330         }
    331 
    332         for (int i = 0; i < index_count; i += 3) {
    333             mesh.faces_.emplace_back(Mesh::Face{teapot_indices[i + 0], teapot_indices[i + 1], teapot_indices[i + 2]});
    334         }
    335     }
    336 
    337     void get_transform(const float *positions, int position_count, Mesh::Position &translate, float &scale) {
    338         float min[3] = {
    339             positions[0], positions[1], positions[2],
    340         };
    341         float max[3] = {
    342             positions[0], positions[1], positions[2],
    343         };
    344         for (int i = 3; i < position_count; i += 3) {
    345             for (int j = 0; j < 3; j++) {
    346                 if (min[j] > positions[i + j]) min[j] = positions[i + j];
    347                 if (max[j] < positions[i + j]) max[j] = positions[i + j];
    348             }
    349         }
    350 
    351         translate.x = -(min[0] + max[0]) / 2.0f;
    352         translate.y = -(min[1] + max[1]) / 2.0f;
    353         translate.z = -(min[2] + max[2]) / 2.0f;
    354 
    355         float extents[3] = {
    356             max[0] + translate.x, max[1] + translate.y, max[2] + translate.z,
    357         };
    358 
    359         float max_extent = extents[0];
    360         if (max_extent < extents[1]) max_extent = extents[1];
    361         if (max_extent < extents[2]) max_extent = extents[2];
    362 
    363         scale = 1.0f / max_extent;
    364     }
    365 };
    366 
    367 void build_meshes(std::array<Mesh, Meshes::MESH_COUNT> &meshes) {
    368     BuildPyramid build_pyramid(meshes[Meshes::MESH_PYRAMID]);
    369     BuildIcosphere build_icosphere(meshes[Meshes::MESH_ICOSPHERE]);
    370     BuildTeapot build_teapot(meshes[Meshes::MESH_TEAPOT]);
    371 }
    372 
    373 }  // namespace
    374 
    375 Meshes::Meshes(VkDevice dev, const std::vector<VkMemoryPropertyFlags> &mem_flags)
    376     : dev_(dev),
    377       vertex_input_binding_(Mesh::vertex_input_binding()),
    378       vertex_input_attrs_(Mesh::vertex_input_attributes()),
    379       vertex_input_state_(),
    380       input_assembly_state_(Mesh::input_assembly_state()),
    381       index_type_(Mesh::index_type()) {
    382     vertex_input_state_.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
    383     vertex_input_state_.vertexBindingDescriptionCount = 1;
    384     vertex_input_state_.pVertexBindingDescriptions = &vertex_input_binding_;
    385     vertex_input_state_.vertexAttributeDescriptionCount = static_cast<uint32_t>(vertex_input_attrs_.size());
    386     vertex_input_state_.pVertexAttributeDescriptions = vertex_input_attrs_.data();
    387 
    388     std::array<Mesh, MESH_COUNT> meshes;
    389     build_meshes(meshes);
    390 
    391     draw_commands_.reserve(meshes.size());
    392     uint32_t first_index = 0;
    393     int32_t vertex_offset = 0;
    394     VkDeviceSize vb_size = 0;
    395     VkDeviceSize ib_size = 0;
    396     for (const auto &mesh : meshes) {
    397         VkDrawIndexedIndirectCommand draw = {};
    398         draw.indexCount = mesh.index_count();
    399         draw.instanceCount = 1;
    400         draw.firstIndex = first_index;
    401         draw.vertexOffset = vertex_offset;
    402         draw.firstInstance = 0;
    403 
    404         draw_commands_.push_back(draw);
    405 
    406         first_index += mesh.index_count();
    407         vertex_offset += mesh.vertex_count();
    408         vb_size += mesh.vertex_buffer_size();
    409         ib_size += mesh.index_buffer_size();
    410     }
    411 
    412     allocate_resources(vb_size, ib_size, mem_flags);
    413 
    414     uint8_t *vb_data, *ib_data;
    415     vk::assert_success(vk::MapMemory(dev_, mem_, 0, VK_WHOLE_SIZE, 0, reinterpret_cast<void **>(&vb_data)));
    416     ib_data = vb_data + ib_mem_offset_;
    417 
    418     for (const auto &mesh : meshes) {
    419         mesh.vertex_buffer_write(vb_data);
    420         mesh.index_buffer_write(ib_data);
    421         vb_data += mesh.vertex_buffer_size();
    422         ib_data += mesh.index_buffer_size();
    423     }
    424 
    425     vk::UnmapMemory(dev_, mem_);
    426 }
    427 
    428 Meshes::~Meshes() {
    429     vk::FreeMemory(dev_, mem_, nullptr);
    430     vk::DestroyBuffer(dev_, vb_, nullptr);
    431     vk::DestroyBuffer(dev_, ib_, nullptr);
    432 }
    433 
    434 void Meshes::cmd_bind_buffers(VkCommandBuffer cmd) const {
    435     const VkDeviceSize vb_offset = 0;
    436     vk::CmdBindVertexBuffers(cmd, 0, 1, &vb_, &vb_offset);
    437 
    438     vk::CmdBindIndexBuffer(cmd, ib_, 0, index_type_);
    439 }
    440 
    441 void Meshes::cmd_draw(VkCommandBuffer cmd, Type type) const {
    442     const auto &draw = draw_commands_[type];
    443     vk::CmdDrawIndexed(cmd, draw.indexCount, draw.instanceCount, draw.firstIndex, draw.vertexOffset, draw.firstInstance);
    444 }
    445 
    446 void Meshes::allocate_resources(VkDeviceSize vb_size, VkDeviceSize ib_size, const std::vector<VkMemoryPropertyFlags> &mem_flags) {
    447     VkBufferCreateInfo buf_info = {};
    448     buf_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
    449     buf_info.size = vb_size;
    450     buf_info.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
    451     buf_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
    452     vk::CreateBuffer(dev_, &buf_info, nullptr, &vb_);
    453 
    454     buf_info.size = ib_size;
    455     buf_info.usage = VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
    456     vk::CreateBuffer(dev_, &buf_info, nullptr, &ib_);
    457 
    458     VkMemoryRequirements vb_mem_reqs, ib_mem_reqs;
    459     vk::GetBufferMemoryRequirements(dev_, vb_, &vb_mem_reqs);
    460     vk::GetBufferMemoryRequirements(dev_, ib_, &ib_mem_reqs);
    461 
    462     // indices follow vertices
    463     ib_mem_offset_ = vb_mem_reqs.size + (ib_mem_reqs.alignment - (vb_mem_reqs.size % ib_mem_reqs.alignment));
    464 
    465     VkMemoryAllocateInfo mem_info = {};
    466     mem_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
    467     mem_info.allocationSize = ib_mem_offset_ + ib_mem_reqs.size;
    468 
    469     // find any supported and mappable memory type
    470     uint32_t mem_types = (vb_mem_reqs.memoryTypeBits & ib_mem_reqs.memoryTypeBits);
    471     for (uint32_t idx = 0; idx < mem_flags.size(); idx++) {
    472         if ((mem_types & (1 << idx)) && (mem_flags[idx] & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) &&
    473             (mem_flags[idx] & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) {
    474             // TODO this may not be reachable
    475             mem_info.memoryTypeIndex = idx;
    476             break;
    477         }
    478     }
    479 
    480     vk::AllocateMemory(dev_, &mem_info, nullptr, &mem_);
    481 
    482     vk::BindBufferMemory(dev_, vb_, mem_, 0);
    483     vk::BindBufferMemory(dev_, ib_, mem_, ib_mem_offset_);
    484 }
    485