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
vertex_stride()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
vertex_input_binding()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
vertex_input_attributes()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
index_type()83 static VkIndexType index_type()
84 {
85 return VK_INDEX_TYPE_UINT32;
86 }
87
input_assembly_state()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
build(const std::vector<std::array<float,6>> & vertices,const std::vector<std::array<int,3>> & faces)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
vertex_count() const111 uint32_t vertex_count() const
112 {
113 return static_cast<uint32_t>(positions_.size());
114 }
115
vertex_buffer_size() const116 VkDeviceSize vertex_buffer_size() const
117 {
118 return vertex_stride() * vertex_count();
119 }
120
vertex_buffer_write(void * data) const121 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
index_count() const137 uint32_t index_count() const
138 {
139 return static_cast<uint32_t>(faces_.size()) * 3;
140 }
141
index_buffer_size() const142 VkDeviceSize index_buffer_size() const
143 {
144 return sizeof(uint32_t) * index_count();
145 }
146
index_buffer_write(void * data) const147 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
163 class BuildPyramid {
164 public:
BuildPyramid(Mesh & mesh)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
189 class BuildIcosphere {
190 public:
BuildIcosphere(Mesh & mesh)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
200 private:
build_icosahedron()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
tessellate()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
add_middle_point(int a,int b)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
326 class BuildTeapot {
327 public:
BuildTeapot(Mesh & mesh)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
get_transform(const float * positions,int position_count,Mesh::Position & translate,float & scale)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
build_meshes(std::array<Mesh,Meshes::MESH_COUNT> & meshes)404 void 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
Meshes(VkDevice dev,const std::vector<VkMemoryPropertyFlags> & mem_flags)413 Meshes::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
~Meshes()468 Meshes::~Meshes()
469 {
470 vk::FreeMemory(dev_, mem_, nullptr);
471 vk::DestroyBuffer(dev_, vb_, nullptr);
472 vk::DestroyBuffer(dev_, ib_, nullptr);
473 }
474
cmd_bind_buffers(VkCommandBuffer cmd) const475 void 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
cmd_draw(VkCommandBuffer cmd,Type type) const483 void 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
allocate_resources(VkDeviceSize vb_size,VkDeviceSize ib_size,const std::vector<VkMemoryPropertyFlags> & mem_flags)490 void 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