Skip to content

Commit 1923ec0

Browse files
committed
clusterizer: Increase max vertex limit to 256
Before this change, the maximum meshlet configuration that we allowed was 255v/512t; "255" was not a typo and reflected the internal implementation limit: we track the index of each vertex in the meshlet with a sentinel value 0xff to indicate vertices that haven't been added yet. This is a surprising paper cut that nobody expects, and while 256v isn't dramatically different from 255v, it's still not ideal. Upon testing, while in theory using a 2-byte lookup entry to allow -1 for sentinels technically requires more memory, in practice it's not a concern for anything except buildMeshletsScan, and even there while this requires more memory, the performance seems equivalent. If this becomes a problem in the future we can switch to a bitset.
1 parent f50be39 commit 1923ec0

File tree

1 file changed

+32
-32
lines changed

1 file changed

+32
-32
lines changed

src/clusterizer.cpp

Lines changed: 32 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@
1313
namespace meshopt
1414
{
1515

16-
// This must be <= 255 since index 0xff is used internally to indice a vertex that doesn't belong to a meshlet
17-
const size_t kMeshletMaxVertices = 255;
16+
// This must be <= 256 since meshlet indices are stored as bytes
17+
const size_t kMeshletMaxVertices = 256;
1818

1919
// A reasonable limit is around 2*max_vertices or less
2020
const size_t kMeshletMaxTriangles = 512;
@@ -328,22 +328,22 @@ static void finishMeshlet(meshopt_Meshlet& meshlet, unsigned char* meshlet_trian
328328
meshlet_triangles[offset++] = 0;
329329
}
330330

331-
static bool appendMeshlet(meshopt_Meshlet& meshlet, unsigned int a, unsigned int b, unsigned int c, unsigned char* used, meshopt_Meshlet* meshlets, unsigned int* meshlet_vertices, unsigned char* meshlet_triangles, size_t meshlet_offset, size_t max_vertices, size_t max_triangles, bool split = false)
331+
static bool appendMeshlet(meshopt_Meshlet& meshlet, unsigned int a, unsigned int b, unsigned int c, short* used, meshopt_Meshlet* meshlets, unsigned int* meshlet_vertices, unsigned char* meshlet_triangles, size_t meshlet_offset, size_t max_vertices, size_t max_triangles, bool split = false)
332332
{
333-
unsigned char& av = used[a];
334-
unsigned char& bv = used[b];
335-
unsigned char& cv = used[c];
333+
short& av = used[a];
334+
short& bv = used[b];
335+
short& cv = used[c];
336336

337337
bool result = false;
338338

339-
int used_extra = (av == 0xff) + (bv == 0xff) + (cv == 0xff);
339+
int used_extra = (av < 0) + (bv < 0) + (cv < 0);
340340

341341
if (meshlet.vertex_count + used_extra > max_vertices || meshlet.triangle_count >= max_triangles || split)
342342
{
343343
meshlets[meshlet_offset] = meshlet;
344344

345345
for (size_t j = 0; j < meshlet.vertex_count; ++j)
346-
used[meshlet_vertices[meshlet.vertex_offset + j]] = 0xff;
346+
used[meshlet_vertices[meshlet.vertex_offset + j]] = -1;
347347

348348
finishMeshlet(meshlet, meshlet_triangles);
349349

@@ -355,33 +355,33 @@ static bool appendMeshlet(meshopt_Meshlet& meshlet, unsigned int a, unsigned int
355355
result = true;
356356
}
357357

358-
if (av == 0xff)
358+
if (av < 0)
359359
{
360-
av = (unsigned char)meshlet.vertex_count;
360+
av = short(meshlet.vertex_count);
361361
meshlet_vertices[meshlet.vertex_offset + meshlet.vertex_count++] = a;
362362
}
363363

364-
if (bv == 0xff)
364+
if (bv < 0)
365365
{
366-
bv = (unsigned char)meshlet.vertex_count;
366+
bv = short(meshlet.vertex_count);
367367
meshlet_vertices[meshlet.vertex_offset + meshlet.vertex_count++] = b;
368368
}
369369

370-
if (cv == 0xff)
370+
if (cv < 0)
371371
{
372-
cv = (unsigned char)meshlet.vertex_count;
372+
cv = short(meshlet.vertex_count);
373373
meshlet_vertices[meshlet.vertex_offset + meshlet.vertex_count++] = c;
374374
}
375375

376-
meshlet_triangles[meshlet.triangle_offset + meshlet.triangle_count * 3 + 0] = av;
377-
meshlet_triangles[meshlet.triangle_offset + meshlet.triangle_count * 3 + 1] = bv;
378-
meshlet_triangles[meshlet.triangle_offset + meshlet.triangle_count * 3 + 2] = cv;
376+
meshlet_triangles[meshlet.triangle_offset + meshlet.triangle_count * 3 + 0] = (unsigned char)av;
377+
meshlet_triangles[meshlet.triangle_offset + meshlet.triangle_count * 3 + 1] = (unsigned char)bv;
378+
meshlet_triangles[meshlet.triangle_offset + meshlet.triangle_count * 3 + 2] = (unsigned char)cv;
379379
meshlet.triangle_count++;
380380

381381
return result;
382382
}
383383

384-
static unsigned int getNeighborTriangle(const meshopt_Meshlet& meshlet, const Cone& meshlet_cone, const unsigned int* meshlet_vertices, const unsigned int* indices, const TriangleAdjacency2& adjacency, const Cone* triangles, const unsigned int* live_triangles, const unsigned char* used, float meshlet_expected_radius, float cone_weight)
384+
static unsigned int getNeighborTriangle(const meshopt_Meshlet& meshlet, const Cone& meshlet_cone, const unsigned int* meshlet_vertices, const unsigned int* indices, const TriangleAdjacency2& adjacency, const Cone* triangles, const unsigned int* live_triangles, const short* used, float meshlet_expected_radius, float cone_weight)
385385
{
386386
unsigned int best_triangle = ~0u;
387387
int best_priority = 5;
@@ -399,7 +399,7 @@ static unsigned int getNeighborTriangle(const meshopt_Meshlet& meshlet, const Co
399399
unsigned int triangle = neighbors[j];
400400
unsigned int a = indices[triangle * 3 + 0], b = indices[triangle * 3 + 1], c = indices[triangle * 3 + 2];
401401

402-
int extra = (used[a] == 0xff) + (used[b] == 0xff) + (used[c] == 0xff);
402+
int extra = (used[a] < 0) + (used[b] < 0) + (used[c] < 0);
403403
assert(extra <= 2);
404404

405405
int priority = -1;
@@ -785,9 +785,9 @@ size_t meshopt_buildMeshletsFlex(meshopt_Meshlet* meshlets, unsigned int* meshle
785785
cornerz = cornerz > tri.pz ? tri.pz : cornerz;
786786
}
787787

788-
// index of the vertex in the meshlet, 0xff if the vertex isn't used
789-
unsigned char* used = allocator.allocate<unsigned char>(vertex_count);
790-
memset(used, -1, vertex_count);
788+
// index of the vertex in the meshlet, -1 if the vertex isn't used
789+
short* used = allocator.allocate<short>(vertex_count);
790+
memset(used, -1, vertex_count * sizeof(short));
791791

792792
// initial seed triangle is the one closest to the corner
793793
unsigned int initial_seed = ~0u;
@@ -846,7 +846,7 @@ size_t meshopt_buildMeshletsFlex(meshopt_Meshlet* meshlets, unsigned int* meshle
846846
if (best_triangle == ~0u)
847847
break;
848848

849-
int best_extra = (used[indices[best_triangle * 3 + 0]] == 0xff) + (used[indices[best_triangle * 3 + 1]] == 0xff) + (used[indices[best_triangle * 3 + 2]] == 0xff);
849+
int best_extra = (used[indices[best_triangle * 3 + 0]] < 0) + (used[indices[best_triangle * 3 + 1]] < 0) + (used[indices[best_triangle * 3 + 2]] < 0);
850850

851851
// if the best triangle doesn't fit into current meshlet, we re-select using seeds to maintain global flow
852852
if (split || (meshlet.vertex_count + best_extra > max_vertices || meshlet.triangle_count >= max_triangles))
@@ -936,9 +936,9 @@ size_t meshopt_buildMeshletsScan(meshopt_Meshlet* meshlets, unsigned int* meshle
936936

937937
meshopt_Allocator allocator;
938938

939-
// index of the vertex in the meshlet, 0xff if the vertex isn't used
940-
unsigned char* used = allocator.allocate<unsigned char>(vertex_count);
941-
memset(used, -1, vertex_count);
939+
// index of the vertex in the meshlet, -1 if the vertex isn't used
940+
short* used = allocator.allocate<short>(vertex_count);
941+
memset(used, -1, vertex_count * sizeof(short));
942942

943943
meshopt_Meshlet meshlet = {};
944944
size_t meshlet_offset = 0;
@@ -1233,23 +1233,23 @@ void meshopt_optimizeMeshlet(unsigned int* meshlet_vertices, unsigned char* mesh
12331233
// reorder meshlet vertices for access locality assuming index buffer is scanned sequentially
12341234
unsigned int order[kMeshletMaxVertices];
12351235

1236-
unsigned char remap[kMeshletMaxVertices];
1237-
memset(remap, -1, vertex_count);
1236+
short remap[kMeshletMaxVertices];
1237+
memset(remap, -1, vertex_count * sizeof(short));
12381238

12391239
size_t vertex_offset = 0;
12401240

12411241
for (size_t i = 0; i < triangle_count * 3; ++i)
12421242
{
1243-
unsigned char& r = remap[indices[i]];
1243+
short& r = remap[indices[i]];
12441244

1245-
if (r == 0xff)
1245+
if (r < 0)
12461246
{
1247-
r = (unsigned char)(vertex_offset);
1247+
r = short(vertex_offset);
12481248
order[vertex_offset] = vertices[indices[i]];
12491249
vertex_offset++;
12501250
}
12511251

1252-
indices[i] = r;
1252+
indices[i] = (unsigned char)r;
12531253
}
12541254

12551255
assert(vertex_offset <= vertex_count);

0 commit comments

Comments
 (0)