mirror of
https://github.com/openharmony/third_party_meshoptimizer.git
synced 2026-07-19 20:03:59 -04:00
clusterizer: Implement experimental meshlet optimizer
So far we were mostly concerned with meshlet clustering from the perspective of treating meshlets as an unordered set of triangles; while this matches the computational and documented model, this may not be optimal for a given GPU. Notably, NVidia GPUs are much more sensitive to the order of triangles in the meshlet than to the number and fill percentage; so much so that from pure rasterization performance, scan may win over proper clustering because it implicitly generates a better order. We do not know the precise criteria / mechanism that NV GPUs use here but it helps to do locality optimization; most importantly, triangle order, but also reordering meshlet-local vertices helps a little bit. This change implements a simple meshlet optimizer; while this can also be achieved by running existing optimization algorithms (vcache / vfetch) on meshlet data, a custom optimizer is faster even when using unoptimized quadratic implementation, and may allow us to implement better locality reodering algorithms in the future assuming a small input patch. For now we just select the next triangle to maximize the number of shared vertices with the previous triangle; this results in a pseudo-strip order which seems reasonably optimal for NV; note that neither the hardware nor this algorithm is concerned with the specifics of edge matching as it doesn't seem to matter for performance.
This commit is contained in:
@@ -882,3 +882,81 @@ meshopt_Bounds meshopt_computeMeshletBounds(const unsigned int* meshlet_vertices
|
||||
|
||||
return meshopt_computeClusterBounds(indices, triangle_count * 3, vertex_positions, vertex_count, vertex_positions_stride);
|
||||
}
|
||||
|
||||
void meshopt_optimizeMeshlet(unsigned int* meshlet_vertices, unsigned char* meshlet_triangles, size_t triangle_count, size_t vertex_count)
|
||||
{
|
||||
using namespace meshopt;
|
||||
|
||||
assert(triangle_count <= kMeshletMaxTriangles);
|
||||
assert(vertex_count <= kMeshletMaxVertices);
|
||||
|
||||
unsigned char* indices = meshlet_triangles;
|
||||
unsigned int* vertices = meshlet_vertices;
|
||||
|
||||
unsigned char result[kMeshletMaxTriangles * 3];
|
||||
|
||||
unsigned char visited[kMeshletMaxTriangles];
|
||||
memset(visited, 0, triangle_count);
|
||||
|
||||
unsigned char lasta = 0, lastb = 0, lastc = 0;
|
||||
|
||||
for (size_t i = 0; i < triangle_count; ++i)
|
||||
{
|
||||
int next = -1;
|
||||
|
||||
for (int pass = 2; pass >= 0; pass--)
|
||||
{
|
||||
for (size_t j = 0; j < triangle_count; ++j)
|
||||
{
|
||||
if (visited[j])
|
||||
continue;
|
||||
|
||||
unsigned char a = indices[j * 3 + 0], b = indices[j * 3 + 1], c = indices[j * 3 + 2];
|
||||
|
||||
int aok = (a == lasta || a == lastb || a == lastc);
|
||||
int bok = (b == lasta || b == lastb || b == lastc);
|
||||
int cok = (c == lasta || c == lastb || c == lastc);
|
||||
|
||||
if (aok + bok + cok >= pass)
|
||||
{
|
||||
next = (int)j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (next >= 0)
|
||||
break;
|
||||
}
|
||||
|
||||
assert(next >= 0);
|
||||
visited[next] = 1;
|
||||
result[i * 3 + 0] = lasta = indices[next * 3 + 0];
|
||||
result[i * 3 + 1] = lastb = indices[next * 3 + 1];
|
||||
result[i * 3 + 2] = lastc = indices[next * 3 + 2];
|
||||
}
|
||||
|
||||
memcpy(indices, result, triangle_count * 3);
|
||||
|
||||
unsigned int newv[kMeshletMaxVertices];
|
||||
|
||||
unsigned char remap[kMeshletMaxVertices];
|
||||
memset(remap, -1, vertex_count);
|
||||
|
||||
size_t vertex_offset = 0;
|
||||
|
||||
for (size_t i = 0; i < triangle_count * 3; ++i)
|
||||
{
|
||||
unsigned char& r = remap[indices[i]];
|
||||
|
||||
if (r == 0xff)
|
||||
{
|
||||
r = unsigned(vertex_offset);
|
||||
newv[vertex_offset] = vertices[indices[i]];
|
||||
vertex_offset++;
|
||||
}
|
||||
|
||||
indices[i] = r;
|
||||
}
|
||||
|
||||
memcpy(vertices, newv, vertex_offset * sizeof(unsigned int));
|
||||
}
|
||||
|
||||
@@ -493,6 +493,16 @@ MESHOPTIMIZER_API size_t meshopt_buildMeshlets(struct meshopt_Meshlet* meshlets,
|
||||
MESHOPTIMIZER_API size_t meshopt_buildMeshletsScan(struct meshopt_Meshlet* meshlets, unsigned int* meshlet_vertices, unsigned char* meshlet_triangles, const unsigned int* indices, size_t index_count, size_t vertex_count, size_t max_vertices, size_t max_triangles);
|
||||
MESHOPTIMIZER_API size_t meshopt_buildMeshletsBound(size_t index_count, size_t max_vertices, size_t max_triangles);
|
||||
|
||||
/**
|
||||
* Experimental: Meshlet optimizer
|
||||
* Reorders meshlet vertices and triangles to maximize locality to improve rasterizer throughput
|
||||
*
|
||||
* meshlet_triangles and meshlet_vertices must refer to meshlet triangle and vertex index data; when buildMeshlets* is used, these
|
||||
* need to be computed from meshlet's vertex_offset and triangle_offset
|
||||
* triangle_count and vertex_count must not exceed implementation limits (vertex_count <= 255 - not 256!, triangle_count <= 512)
|
||||
*/
|
||||
MESHOPTIMIZER_EXPERIMENTAL void meshopt_optimizeMeshlet(unsigned int* meshlet_vertices, unsigned char* meshlet_triangles, size_t triangle_count, size_t vertex_count);
|
||||
|
||||
struct meshopt_Bounds
|
||||
{
|
||||
/* bounding sphere, useful for frustum and occlusion culling */
|
||||
|
||||
Reference in New Issue
Block a user