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 "mesh.h"
24 
25 #include <numeric>
26 #include <stdexcept>
27 
28 namespace
29 {
30 
vk_formats_to_float_formats(std::vector<vk::Format> const & formats)31 std::vector<size_t> vk_formats_to_float_formats(
32     std::vector<vk::Format> const& formats)
33 {
34     std::vector<size_t> ret;
35 
36     for (auto const f : formats)
37     {
38         switch (f)
39         {
40             case vk::Format::eR32Sfloat:
41                 ret.push_back(1);
42                 break;
43             case vk::Format::eR32G32Sfloat:
44                 ret.push_back(2);
45                 break;
46             case vk::Format::eR32G32B32Sfloat:
47                 ret.push_back(3);
48                 break;
49             case vk::Format::eR32G32B32A32Sfloat:
50                 ret.push_back(4);
51                 break;
52             default:
53                 throw std::runtime_error{"Unsupported vertex format " + to_string(f)};
54         };
55     }
56 
57     return ret;
58 }
59 
calc_vertex_num_floats(std::vector<size_t> const & formats)60 size_t calc_vertex_num_floats(std::vector<size_t> const& formats)
61 {
62     return std::accumulate(formats.begin(), formats.end(), 0);
63 }
64 
65 }
66 
Mesh(std::vector<vk::Format> const & vk_formats)67 Mesh::Mesh(std::vector<vk::Format> const& vk_formats)
68     : vk_formats{vk_formats},
69       formats{vk_formats_to_float_formats(vk_formats)},
70       vertex_num_floats{calc_vertex_num_floats(formats)},
71       interleave{false}
72 {
73 
74 }
75 
set_interleave(bool interleave_)76 void Mesh::set_interleave(bool interleave_)
77 {
78     interleave = interleave_;
79 }
80 
next_vertex()81 void Mesh::next_vertex()
82 {
83     vertices.push_back(std::vector<float>(vertex_num_floats));
84 }
85 
num_vertices() const86 size_t Mesh::num_vertices() const
87 {
88     return vertices.size();
89 }
90 
set_attribute(size_t pos,float data)91 void Mesh::set_attribute(size_t pos, float data)
92 {
93     if (formats[pos] != 1)
94         throw std::logic_error{"Trying to set vertex attribute with incorrectly sized data"};
95 
96     auto const offset = std::accumulate(formats.begin(), formats.begin() + pos, 0);
97     auto& vertex = vertices.back();
98 
99     vertex[offset] = data;
100 }
101 
set_attribute(size_t pos,glm::vec2 const & data)102 void Mesh::set_attribute(size_t pos, glm::vec2 const& data)
103 {
104     if (formats[pos] != 2)
105         throw std::logic_error{"Trying to set vertex attribute with incorrectly sized data"};
106 
107     auto const offset = std::accumulate(formats.begin(), formats.begin() + pos, 0);
108     auto& vertex = vertices.back();
109 
110     vertex[offset] = data.x;
111     vertex[offset + 1] = data.y;
112 }
113 
set_attribute(size_t pos,glm::vec3 const & data)114 void Mesh::set_attribute(size_t pos, glm::vec3 const& data)
115 {
116     if (formats[pos] != 3)
117         throw std::logic_error{"Trying to set vertex attribute with incorrectly sized data"};
118 
119     auto const offset = std::accumulate(formats.begin(), formats.begin() + pos, 0);
120     auto& vertex = vertices.back();
121 
122     vertex[offset] = data.x;
123     vertex[offset + 1] = data.y;
124     vertex[offset + 2] = data.z;
125 }
126 
set_attribute(size_t pos,glm::vec4 const & data)127 void Mesh::set_attribute(size_t pos, glm::vec4 const& data)
128 {
129     if (formats[pos] != 4)
130         throw std::logic_error{"Trying to set vertex attribute with incorrectly sized data"};
131 
132     auto const offset = std::accumulate(formats.begin(), formats.begin() + pos, 0);
133     auto& vertex = vertices.back();
134 
135     vertex[offset] = data.x;
136     vertex[offset + 1] = data.y;
137     vertex[offset + 2] = data.z;
138     vertex[offset + 3] = data.w;
139 }
140 
min_attribute_bound(size_t pos)141 glm::vec3 Mesh::min_attribute_bound(size_t pos)
142 {
143     if (formats[pos] != 3)
144         throw std::logic_error{"Trying to get min attribute bound from incorrectly sized data"};
145 
146     auto const offset = std::accumulate(formats.begin(), formats.begin() + pos, 0);
147 
148     glm::vec3 ret{std::numeric_limits<float>::max(),
149                   std::numeric_limits<float>::max(),
150                   std::numeric_limits<float>::max()};
151 
152     for (auto const& v : vertices)
153     {
154         if (v[offset] < ret.x)
155             ret.x = v[offset];
156         if (v[offset + 1] < ret.y)
157             ret.y = v[offset + 1];
158         if (v[offset + 2] < ret.z)
159             ret.z = v[offset + 2];
160     }
161 
162     return ret;
163 }
164 
max_attribute_bound(size_t pos)165 glm::vec3 Mesh::max_attribute_bound(size_t pos)
166 {
167     if (formats[pos] != 3)
168         throw std::logic_error{"Trying to get max attribute bound from incorrectly sized data"};
169 
170     auto const offset = std::accumulate(formats.begin(), formats.begin() + pos, 0);
171 
172     glm::vec3 ret{std::numeric_limits<float>::min(),
173                   std::numeric_limits<float>::min(),
174                   std::numeric_limits<float>::min()};
175 
176     for (auto const& v : vertices)
177     {
178         if (v[offset] > ret.x)
179             ret.x = v[offset];
180         if (v[offset + 1] > ret.y)
181             ret.y = v[offset + 1];
182         if (v[offset + 2] > ret.z)
183             ret.z = v[offset + 2];
184     }
185 
186     return ret;
187 }
188 
189 std::vector<vk::VertexInputBindingDescription>
binding_descriptions() const190 Mesh::binding_descriptions() const
191 {
192     std::vector<vk::VertexInputBindingDescription> ret;
193 
194     if (interleave)
195     {
196         ret.push_back(
197             vk::VertexInputBindingDescription{}
198                 .setBinding(0)
199                 .setStride(sizeof(float) * vertex_num_floats)
200                 .setInputRate(vk::VertexInputRate::eVertex));
201     }
202     else
203     {
204         int binding = 0;
205 
206         for (auto const& f : formats)
207         {
208             ret.push_back(
209                 vk::VertexInputBindingDescription{}
210                     .setBinding(binding)
211                     .setStride(sizeof(float) * f)
212                     .setInputRate(vk::VertexInputRate::eVertex));
213 
214             ++binding;
215         }
216     }
217 
218     return ret;
219 }
220 
221 std::vector<vk::VertexInputAttributeDescription>
attribute_descriptions() const222 Mesh::attribute_descriptions() const
223 {
224     std::vector<vk::VertexInputAttributeDescription> ret;
225 
226     int binding = 0;
227     int i = 0;
228 
229     for (auto const& vf : vk_formats)
230     {
231         auto const offset =
232             interleave ?
233             sizeof(float) * std::accumulate(formats.begin(), formats.begin() + i, 0) :
234             0;
235 
236         ret.push_back(
237             vk::VertexInputAttributeDescription{}
238                 .setBinding(binding)
239                 .setLocation(i)
240                 .setFormat(vf)
241                 .setOffset(offset));
242 
243         if (!interleave)
244             ++binding;
245         ++i;
246     }
247 
248     return ret;
249 }
250 
copy_vertex_data_to(void * dst) const251 void Mesh::copy_vertex_data_to(void* dst) const
252 {
253     auto const dst_c = static_cast<char*>(dst);
254 
255     if (interleave)
256     {
257         auto current = dst_c;
258 
259         for (auto const& vertex : vertices)
260         {
261             auto const nbytes = vertex.size() * sizeof(float);
262             memcpy(current, vertex.data(), nbytes);
263             current += nbytes;
264         }
265     }
266     else
267     {
268         auto current = dst_c;
269 
270         for (size_t i = 0; i < formats.size(); ++i)
271         {
272             auto const offset = std::accumulate(formats.begin(), formats.begin() + i, 0);
273             auto const nbytes = formats[i] * sizeof(float);
274 
275             for (auto const& vertex : vertices)
276             {
277                 memcpy(current, &vertex[offset], nbytes);
278                 current += nbytes;
279             }
280         }
281     }
282 }
283 
vertex_data_binding_offsets() const284 std::vector<vk::DeviceSize> Mesh::vertex_data_binding_offsets() const
285 {
286     std::vector<vk::DeviceSize> ret;
287 
288     if (interleave)
289     {
290         ret.push_back(0);
291     }
292     else
293     {
294         for (size_t i = 0; i < formats.size(); ++i)
295         {
296             auto attrib_offset = std::accumulate(formats.begin(), formats.begin() + i, 0);
297             ret.push_back(attrib_offset * sizeof(float) * vertices.size());
298         }
299     }
300 
301     return ret;
302 }
303 
vertex_data_size() const304 size_t Mesh::vertex_data_size() const
305 {
306     return vertices.size() * vertex_num_floats * sizeof(float);
307 }
308