Skip to content

Commit

Permalink
Use 16-bit vertex references for meshlets
Browse files Browse the repository at this point in the history
Most meshlets reference a short range of vertices which can fit into 16
bits with an offset. Since we already store base vertex per meshlet this
can be very easily supported with a conditional load in the shader.

This reduces meshlet data from 35 MB to 25 MB on Bistro.

After this, 20% of meshlets can still use 1-byte range but the savings
are less pronounced so this can be done at some future point separately.
  • Loading branch information
zeux committed Dec 31, 2024
1 parent c2957bb commit 700c84b
Show file tree
Hide file tree
Showing 4 changed files with 29 additions and 5 deletions.
21 changes: 18 additions & 3 deletions src/scene.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,29 @@ static size_t appendMeshlets(Geometry& result, const std::vector<vec3>& vertices
else
meshlets.resize(meshopt_buildMeshlets(meshlets.data(), meshlet_vertices.data(), meshlet_triangles.data(), indices.data(), indices.size(), &vertices[0].x, vertices.size(), sizeof(vec3), max_vertices, max_triangles, cone_weight));

// note: we can append meshlet_vertices & meshlet_triangles buffers more or less directly with small changes in Meshlet struct, but for now keep the GPU side layout flexible and separate
for (auto& meshlet : meshlets)
{
meshopt_optimizeMeshlet(&meshlet_vertices[meshlet.vertex_offset], &meshlet_triangles[meshlet.triangle_offset], meshlet.triangle_count, meshlet.vertex_count);

size_t dataOffset = result.meshletdata.size();

unsigned int minVertex = ~0u, maxVertex = 0;
for (unsigned int i = 0; i < meshlet.vertex_count; ++i)
result.meshletdata.push_back(meshlet_vertices[meshlet.vertex_offset + i]);
{
minVertex = std::min(meshlet_vertices[meshlet.vertex_offset + i], minVertex);
maxVertex = std::max(meshlet_vertices[meshlet.vertex_offset + i], maxVertex);
}

bool shortRefs = maxVertex - minVertex < (1 << 16);

for (unsigned int i = 0; i < meshlet.vertex_count; ++i)
{
unsigned int ref = meshlet_vertices[meshlet.vertex_offset + i] - minVertex;
if (shortRefs && i % 2)
result.meshletdata.back() |= ref << 16;
else
result.meshletdata.push_back(ref);
}

const unsigned int* indexGroups = reinterpret_cast<const unsigned int*>(&meshlet_triangles[0] + meshlet.triangle_offset);
unsigned int indexGroupCount = (meshlet.triangle_count * 3 + 3) / 4;
Expand All @@ -48,9 +62,10 @@ static size_t appendMeshlets(Geometry& result, const std::vector<vec3>& vertices

Meshlet m = {};
m.dataOffset = uint32_t(dataOffset);
m.baseVertex = baseVertex;
m.baseVertex = baseVertex + minVertex;
m.triangleCount = meshlet.triangle_count;
m.vertexCount = meshlet.vertex_count;
m.shortRefs = shortRefs;

m.center = vec3(bounds.center[0], bounds.center[1], bounds.center[2]);
m.radius = bounds.radius;
Expand Down
2 changes: 2 additions & 0 deletions src/scene.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ struct alignas(16) Meshlet
uint32_t baseVertex;
uint8_t vertexCount;
uint8_t triangleCount;
uint8_t shortRefs;
uint8_t padding;
};

struct alignas(16) Material
Expand Down
1 change: 1 addition & 0 deletions src/shaders/mesh.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ struct Meshlet
uint baseVertex;
uint8_t vertexCount;
uint8_t triangleCount;
uint8_t shortRefs;
};

struct CullData
Expand Down
10 changes: 8 additions & 2 deletions src/shaders/meshlet.mesh.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ layout(binding = 3) readonly buffer MeshletData
uint meshletData[];
};

layout(binding = 3) readonly buffer MeshletData16
{
uint16_t meshletData16[];
};

layout(binding = 3) readonly buffer MeshletData8
{
uint8_t meshletData8[];
Expand Down Expand Up @@ -106,8 +111,9 @@ void main()

uint dataOffset = meshlets[mi].dataOffset;
uint baseVertex = meshlets[mi].baseVertex;
bool shortRefs = uint(meshlets[mi].shortRefs) == 1;
uint vertexOffset = dataOffset;
uint indexOffset = dataOffset + vertexCount;
uint indexOffset = dataOffset + (shortRefs ? (vertexCount + 1) / 2 : vertexCount);

#if DEBUG
uint mhash = hash(mi);
Expand All @@ -118,7 +124,7 @@ void main()

for (uint i = ti; i < vertexCount; )
{
uint vi = meshletData[vertexOffset + i] + baseVertex;
uint vi = shortRefs ? uint(meshletData16[vertexOffset * 2 + i]) + baseVertex : meshletData[vertexOffset + i] + baseVertex;

vec3 position = vec3(vertices[vi].vx, vertices[vi].vy, vertices[vi].vz);
vec2 texcoord = vec2(vertices[vi].tu, vertices[vi].tv);
Expand Down

0 comments on commit 700c84b

Please sign in to comment.