1 /*
2  * Copyright © 2017 Collabora Ltd.
3  *
4  * This file is part of vkmark.
5  *
6  * vkmark is free software: you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation, either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * vkmark is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with vkmark. If not, see <http://www.gnu.org/licenses/>.
18  *
19  * Authors:
20  *   Alexandros Frantzis <alexandros.frantzis@collabora.com>
21  */
22 
23 #include "src/mesh.h"
24 
25 #include "catch.hpp"
26 
27 #include <vulkan/vulkan.hpp>
28 #include <glm/glm.hpp>
29 #include <memory>
30 #include <numeric>
31 
32 using namespace Catch::Matchers;
33 
34 SCENARIO("mesh object construction", "")
35 {
36     GIVEN("Unsupported formats")
37     {
38         std::vector<vk::Format> const unsupported_formats{
39             vk::Format::eR32G32B32Sint,
40             vk::Format::eR64G64B64Sfloat};
41 
42         WHEN("constructing a mesh")
43         {
44             THEN("the construction throws")
45             {
46                 for (auto const f : unsupported_formats)
47                 {
48                     std::vector<vk::Format> formats{vk::Format::eR32G32B32A32Sfloat, f};
49                     REQUIRE_THROWS(Mesh{formats});
50                 }
51             }
52         }
53     }
54 
55     GIVEN("Supported formats")
56     {
57         std::vector<vk::Format> const supported_formats{
58             vk::Format::eR32G32Sfloat,
59             vk::Format::eR32G32B32Sfloat,
60             vk::Format::eR32G32B32A32Sfloat};
61 
62         WHEN("constructing a mesh")
63         {
64             THEN("the construction succeeeds")
65             {
66                 Mesh mesh{supported_formats};
67             }
68         }
69     }
70 }
71 
72 SCENARIO("mesh creation", "")
73 {
74     std::vector<vk::Format> const formats{
75         vk::Format::eR32Sfloat,
76         vk::Format::eR32G32Sfloat,
77         vk::Format::eR32G32B32Sfloat,
78         vk::Format::eR32G32B32A32Sfloat};
79     size_t const num_vertex_floats = 10;
80 
81     Mesh mesh{formats};
82 
83     GIVEN("A mesh")
84     {
85         WHEN("setting vertex attribute with incorrectly sized data")
86         {
87             mesh.next_vertex();
88 
89             THEN("setting the attributes throws")
90             {
91                 REQUIRE_THROWS(mesh.set_attribute(0, glm::vec2{1, 2}));
92                 REQUIRE_THROWS(mesh.set_attribute(1, glm::vec3{1, 2, 3}));
93                 REQUIRE_THROWS(mesh.set_attribute(2, glm::vec2{1, 2}));
94                 REQUIRE_THROWS(mesh.set_attribute(3, glm::vec3{1, 2, 3}));
95             }
96         }
97 
98         WHEN("setting vertex attributes with correctly sized data")
99         {
100             mesh.next_vertex();
101 
102             THEN("setting the attributes works")
103             {
104                 mesh.set_attribute(0, 0);
105                 mesh.set_attribute(1, glm::vec2{1, 2});
106                 mesh.set_attribute(2, glm::vec3{1, 2, 3});
107                 mesh.set_attribute(3, glm::vec4{1, 2, 3, 4});
108             }
109         }
110     }
111 
112     GIVEN("A mesh with vertices")
113     {
114         for (int i = 0; i < 5; ++i)
115         {
116             auto const v = i * num_vertex_floats;
117             mesh.next_vertex();
118             mesh.set_attribute(0, v);
119             mesh.set_attribute(1, glm::vec2{v + 1, v + 2});
120             mesh.set_attribute(2, glm::vec3{v + 3, v + 4, v + 5});
121             mesh.set_attribute(3, glm::vec4{v + 6, v + 7, v + 8, v + 9});
122         }
123 
124         WHEN("interleave is true")
125         {
126             mesh.set_interleave(true);
127 
128             THEN("the copied vertex data is interleaved")
129             {
130                 std::vector<float> data(mesh.vertex_data_size() / sizeof(float));
131                 mesh.copy_vertex_data_to(data.data());
132 
133                 std::vector<float> expected(num_vertex_floats * 5);
134                 std::iota(expected.begin(), expected.end(), 0);
135 
136                 REQUIRE_THAT(data, Equals(expected));
137             }
138 
139             THEN("binding descriptions are interleaved")
140             {
141                 auto const binding_descs = mesh.binding_descriptions();
142 
143                 REQUIRE(binding_descs.size() == 1);
144                 REQUIRE(binding_descs[0].binding == 0);
145                 REQUIRE(binding_descs[0].stride == num_vertex_floats * sizeof(float));
146                 REQUIRE(binding_descs[0].inputRate == vk::VertexInputRate::eVertex);
147             }
148 
149             THEN("attribute descriptions are interleaved")
150             {
151                 auto const attrib_descs = mesh.attribute_descriptions();
152 
153                 REQUIRE(attrib_descs.size() == formats.size());
154                 for (size_t i = 0; i < attrib_descs.size(); ++i)
155                 {
156                     REQUIRE(attrib_descs[i].binding == 0);
157                     REQUIRE(attrib_descs[i].location == i);
158                 }
159                 REQUIRE(attrib_descs[0].offset == 0 * sizeof(float));
160                 REQUIRE(attrib_descs[1].offset == 1 * sizeof(float));
161                 REQUIRE(attrib_descs[2].offset == 3 * sizeof(float));
162                 REQUIRE(attrib_descs[3].offset == 6 * sizeof(float));
163             }
164         }
165 
166         WHEN("interleave is false")
167         {
168             mesh.set_interleave(false);
169 
170             THEN("the copied vertex data is not interleaved")
171             {
172                 std::vector<float> data(mesh.vertex_data_size() / sizeof(float));
173                 mesh.copy_vertex_data_to(data.data());
174 
175                 std::vector<float> expected;
176                 for (int i = 0; i < 5; ++i)
177                 {
178                     expected.push_back(i * num_vertex_floats);
179                 }
180                 for (int i = 0; i < 5; ++i)
181                 {
182                     for (int j = 0; j < 2; ++j)
183                         expected.push_back(i * num_vertex_floats + 1 + j);
184                 }
185                 for (int i = 0; i < 5; ++i)
186                 {
187                     for (int j = 0; j < 3; ++j)
188                         expected.push_back(i * num_vertex_floats + 3 + j);
189                 }
190                 for (int i = 0; i < 5; ++i)
191                 {
192                     for (int j = 0; j < 4; ++j)
193                         expected.push_back(i * num_vertex_floats + 6 + j);
194                 }
195 
196                 REQUIRE_THAT(data, Equals(expected));
197             }
198 
199             THEN("binding descriptions are not interleaved")
200             {
201                 auto const binding_descs = mesh.binding_descriptions();
202 
203                 REQUIRE(binding_descs.size() == formats.size());
204                 for (size_t i = 0; i < binding_descs.size(); ++i)
205                 {
206                     REQUIRE(binding_descs[i].binding == i);
207                     // format[i] corresponds to a float vector of size i + 1
208                     REQUIRE(binding_descs[i].stride == (i + 1) * sizeof(float));
209                     REQUIRE(binding_descs[i].inputRate == vk::VertexInputRate::eVertex);
210                 }
211             }
212 
213             THEN("attribute descriptions are not interleaved")
214             {
215                 auto const attrib_descs = mesh.attribute_descriptions();
216 
217                 REQUIRE(attrib_descs.size() == formats.size());
218                 for (size_t i = 0; i < attrib_descs.size(); ++i)
219                 {
220                     REQUIRE(attrib_descs[i].binding == i);
221                     REQUIRE(attrib_descs[i].location == i);
222                     REQUIRE(attrib_descs[i].offset == 0);
223                 }
224             }
225         }
226     }
227 }
228