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