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