Skip to content

Commit fbb4978

Browse files
committed
tools: Add triangle only meshlet benchmark to codecbench
Since meshlet encoding has two use cases, with vertex references and without, we need to benchmark both. The triangle-only use case estimates effective bandwidth as #tri*3, which makes this measure more intuitively connected to triangles/sec (9 GB/s = 3B tri/s). In both modes, it can be useful for decoding throughput to sort the meshlets to maximize configuration coherency; this reduces branch mispredictions in processing loops. For now this is not enabled to make tuning of various formats match real workflows, but it might make sense to enable in the future to get a sense of peak performance. Also fix integer truncation warnings on MSVC.
1 parent 4e60d28 commit fbb4978

1 file changed

Lines changed: 26 additions & 15 deletions

File tree

‎tools/codecbench.cpp‎

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ void benchFilters(size_t count, double& besto8, double& besto12, double& bestq12
161161
}
162162
}
163163

164-
void benchMeshlets(const std::vector<float>& positions, const std::vector<unsigned int>& indices, double& bestml, bool verbose)
164+
void benchMeshlets(const std::vector<float>& positions, const std::vector<unsigned int>& indices, bool encoderefs, double& bestml, bool verbose)
165165
{
166166
const size_t max_vertices = 64;
167167
const size_t max_triangles = 96;
@@ -186,28 +186,38 @@ void benchMeshlets(const std::vector<float>& positions, const std::vector<unsign
186186
meshopt_optimizeMeshlet(&meshlet_vertices[meshlets[i].vertex_offset], &meshlet_triangles[meshlets[i].triangle_offset], meshlets[i].triangle_count, meshlets[i].vertex_count);
187187

188188
// optimize meshlet_vertices for locality (requires vertex reorder)
189+
// TODO: over-allocate meshlet_vertices to multiple of 3 to make meshopt_optimizeVertexFetch below work without assertions
189190
std::vector<float> positionscopy(positions.size());
190191
meshlet_vertices.resize((meshlet_vertices.size() + 2) / 3 * 3);
191192
meshopt_optimizeVertexFetch(&positionscopy[0], &meshlet_vertices[0], meshlet_vertices.size(), &positions[0], positions.size() / 3, sizeof(float) * 3);
192193

194+
#if 0 // TODO: disabled for now to make meshlet decoder tuning more accurate; might make sense to re-enable in the future for SOL timings
195+
// pack meshlets in decreasing triangle count order to reduce branch mispredictions
196+
// (this matters less on real-world meshes but is more prominent on regular grids?)
197+
std::sort(meshlets.begin(), meshlets.end(), [](const meshopt_Meshlet& lhs, const meshopt_Meshlet& rhs)
198+
{ return lhs.triangle_count > rhs.triangle_count; });
199+
#endif
200+
193201
std::vector<unsigned char> packed;
194202

195-
size_t total_meshlet_data = 0;
203+
size_t totals = 0;
196204

197205
for (size_t i = 0; i < meshlets.size(); ++i)
198206
{
199207
const meshopt_Meshlet& meshlet = meshlets[i];
200208

201-
size_t mbs = meshopt_encodeMeshlet(&cbuf[0], cbuf.size(), &meshlet_vertices[meshlet.vertex_offset], meshlet.vertex_count, &meshlet_triangles[meshlet.triangle_offset], meshlet.triangle_count);
209+
size_t mvc = encoderefs ? meshlet.vertex_count : 0;
210+
211+
size_t mbs = meshopt_encodeMeshlet(&cbuf[0], cbuf.size(), &meshlet_vertices[meshlet.vertex_offset], mvc, &meshlet_triangles[meshlet.triangle_offset], meshlet.triangle_count);
202212
assert(mbs > 0);
203213

204-
packed.push_back(meshlet.vertex_count);
205-
packed.push_back(meshlet.triangle_count);
206-
packed.push_back(mbs & 0xff);
207-
packed.push_back((mbs >> 8) & 0xff);
214+
packed.push_back((unsigned char)mvc);
215+
packed.push_back((unsigned char)meshlet.triangle_count);
216+
packed.push_back((unsigned char)(mbs & 0xff));
217+
packed.push_back((unsigned char)((mbs >> 8) & 0xff));
208218
packed.insert(packed.end(), cbuf.begin(), cbuf.begin() + mbs);
209219

210-
total_meshlet_data += size_t(meshlet.triangle_count) * 3 + size_t(meshlet.vertex_count) * 4;
220+
totals += size_t(meshlet.triangle_count) * 3 + size_t(mvc) * 4;
211221
}
212222

213223
if (verbose)
@@ -237,9 +247,9 @@ void benchMeshlets(const std::vector<float>& positions, const std::vector<unsign
237247
double t1 = timestamp();
238248

239249
if (verbose)
240-
printf("meshlet decode: %.2f ms (%.2f GB/sec)\n", (t1 - t0) * 1000, double(total_meshlet_data) / 1e9 / (t1 - t0));
250+
printf("meshlet decode: %.2f ms (%.2f GB/sec)\n", (t1 - t0) * 1000, double(totals) / 1e9 / (t1 - t0));
241251

242-
bestml = std::max(bestml, double(total_meshlet_data) / 1e9 / (t1 - t0));
252+
bestml = std::max(bestml, double(totals) / 1e9 / (t1 - t0));
243253
}
244254
}
245255

@@ -402,20 +412,21 @@ int main(int argc, char** argv)
402412
}
403413
}
404414

405-
printf("Algorithm :\tvtx\tidx\tmlet\toct8\toct12\tquat12\tcol8\tcol12\texp\n");
415+
printf("Codec:\tvtx\tidx\tmlet\tmletΔ\toct8\toct12\tquat12\tcol8\tcol12\texp\n");
406416

407417
for (int l = 0; l < (loop ? 100 : 1); ++l)
408418
{
409419
double bestvd = 0, bestid = 0;
410420
benchCodecs(vertices, indices, bestvd, bestid, verbose);
411421

412-
double bestml = 0;
413-
benchMeshlets(positions, indices, bestml, verbose);
422+
double bestml = 0, bestmt = 0;
423+
benchMeshlets(positions, indices, /* encoderefs= */ true, bestml, verbose);
424+
benchMeshlets(positions, indices, /* encoderefs= */ false, bestmt, verbose);
414425

415426
double besto8 = 0, besto12 = 0, bestq12 = 0, bestc8 = 0, bestc12 = 0, bestexp = 0;
416427
benchFilters(8 * N * N, besto8, besto12, bestq12, bestc8, bestc12, bestexp, verbose);
417428

418-
printf("Score (GB/s):\t%.2f\t%.2f\t%.2f\t%.2f\t%.2f\t%.2f\t%.2f\t%.2f\t%.2f\n",
419-
bestvd, bestid, bestml, besto8, besto12, bestq12, bestc8, bestc12, bestexp);
429+
printf("GB/s :\t%.2f\t%.2f\t%.2f\t%.2f\t%.2f\t%.2f\t%.2f\t%.2f\t%.2f\t%.2f\n",
430+
bestvd, bestid, bestml, bestmt, besto8, besto12, bestq12, bestc8, bestc12, bestexp);
420431
}
421432
}

0 commit comments

Comments
 (0)