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