Skip to content
Snippets Groups Projects
Commit 5f182098 authored by Artur Wasmut's avatar Artur Wasmut
Browse files

[#87] add documentation.

parent 094d81a8
No related branches found
No related tags found
1 merge request!74Resolve "Mesh Shader Implementation"
Pipeline #26548 failed
...@@ -4,5 +4,15 @@ ...@@ -4,5 +4,15 @@
namespace vkcv::meshlet namespace vkcv::meshlet
{ {
/**
* Reorders the index buffer, simulating a LRU cache, so that vertices are grouped together in close triangle patches
* @param idxBuf current IndexBuffer
* @param vertexCount of the mesh
* @return new reordered index buffer to replace the input index buffer
* References:
* https://tomforsyth1000.github.io/papers/fast_vert_cache_opt.html
* https://www.martin.st/thesis/efficient_triangle_reordering.pdf
* https://github.com/vivkin/forsyth/blob/master/forsyth.h
*/
std::vector<uint32_t> forsythReorder(const std::vector<uint32_t> &idxBuf, const size_t vertexCount); std::vector<uint32_t> forsythReorder(const std::vector<uint32_t> &idxBuf, const size_t vertexCount);
} }
...@@ -2,10 +2,15 @@ ...@@ -2,10 +2,15 @@
#include <vkcv/Logger.hpp> #include <vkcv/Logger.hpp>
#include <array> #include <array>
#include <cmath> #include <cmath>
#include <iostream>
namespace vkcv::meshlet namespace vkcv::meshlet
{ {
/*
* CACHE AND VALENCE
* SIZE AND SCORE CONSTANTS
* CHANGE AS NEEDED
*/
// set these to adjust performance and result quality // set these to adjust performance and result quality
const size_t VERTEX_CACHE_SIZE = 8; const size_t VERTEX_CACHE_SIZE = 8;
const size_t CACHE_FUNCTION_LENGTH = 32; const size_t CACHE_FUNCTION_LENGTH = 32;
...@@ -26,6 +31,7 @@ namespace vkcv::meshlet ...@@ -26,6 +31,7 @@ namespace vkcv::meshlet
std::array<float, CACHE_SCORE_TABLE_SIZE> cachePositionScore = {}; std::array<float, CACHE_SCORE_TABLE_SIZE> cachePositionScore = {};
std::array<float, VALENCE_SCORE_TABLE_SIZE> valenceScore = {}; std::array<float, VALENCE_SCORE_TABLE_SIZE> valenceScore = {};
// function to populate the cache position and valence score tables
void initScoreTables() void initScoreTables()
{ {
for(size_t i = 0; i < CACHE_SCORE_TABLE_SIZE; i++) for(size_t i = 0; i < CACHE_SCORE_TABLE_SIZE; i++)
...@@ -53,6 +59,13 @@ namespace vkcv::meshlet ...@@ -53,6 +59,13 @@ namespace vkcv::meshlet
} }
} }
/**
* Return the vertex' score, depending on its current active triangle count and cache position
* Add a valence boost to score, if active triangles are below VALENCE_SCORE_TABLE_SIZE
* @param numActiveTris the active triangles on this vertex
* @param cachePos the vertex' position in the cache
* @return vertex' score
*/
float findVertexScore(uint32_t numActiveTris, int32_t cachePos) float findVertexScore(uint32_t numActiveTris, int32_t cachePos)
{ {
if(numActiveTris == 0) if(numActiveTris == 0)
...@@ -72,15 +85,8 @@ namespace vkcv::meshlet ...@@ -72,15 +85,8 @@ namespace vkcv::meshlet
std::vector<uint32_t> forsythReorder(const std::vector<uint32_t> &idxBuf, const size_t vertexCount) std::vector<uint32_t> forsythReorder(const std::vector<uint32_t> &idxBuf, const size_t vertexCount)
{ {
initScoreTables(); initScoreTables();
/**
std::cout << "CACHE POSITION SCORES:" << std::endl; // get the total triangle count from the index buffer
for(const auto element : cachePositionScore)
std::cout << element << std::endl;
std::cout << "VALENCE SCORES:" << std::endl;
for(const auto element : valenceScore)
std::cout << element << std::endl;
**/
const size_t triangleCount = idxBuf.size() / 3; const size_t triangleCount = idxBuf.size() / 3;
// per-vertex active triangle count // per-vertex active triangle count
...@@ -100,6 +106,20 @@ namespace vkcv::meshlet ...@@ -100,6 +106,20 @@ namespace vkcv::meshlet
// allocate remaining vectors // allocate remaining vectors
/**
* offsets: contains the vertices' offset into the triangleIndices vector
* Offset itself is the sum of triangles required by the previous vertices
*
* lastScore: the vertices' most recent calculated score
*
* cacheTag: the vertices' most recent cache score
*
* triangleAdded: boolean flags to denote whether a triangle has been processed or not
*
* triangleScore: total score of the three vertices making up the triangle
*
* triangleIndices: indices for the triangles
*/
std::vector<uint32_t> offsets(vertexCount, 0); std::vector<uint32_t> offsets(vertexCount, 0);
std::vector<float> lastScore(vertexCount, 0.0f); std::vector<float> lastScore(vertexCount, 0.0f);
std::vector<int8_t> cacheTag(vertexCount, -1); std::vector<int8_t> cacheTag(vertexCount, -1);
...@@ -110,8 +130,8 @@ namespace vkcv::meshlet ...@@ -110,8 +130,8 @@ namespace vkcv::meshlet
std::vector<int32_t> triangleIndices(idxBuf.size(), 0); std::vector<int32_t> triangleIndices(idxBuf.size(), 0);
// count the triangle array offset for each vertex, initialize the rest of the data. // sum the number of active triangles for all previous vertices
// ?????????????????????????? // null the number of active triangles afterwards for recalculation in second loop
uint32_t sum = 0; uint32_t sum = 0;
for(size_t i = 0; i < vertexCount; i++) for(size_t i = 0; i < vertexCount; i++)
{ {
...@@ -119,9 +139,8 @@ namespace vkcv::meshlet ...@@ -119,9 +139,8 @@ namespace vkcv::meshlet
sum += numActiveTris[i]; sum += numActiveTris[i];
numActiveTris[i] = 0; numActiveTris[i] = 0;
} }
// create the triangle indices, using the newly calculated offsets, and increment numActiveTris
// fill the vertex data structures with indices to the triangles using each vertex // every vertex should be referenced by a triangle index now
// ??????????????????????????
for(size_t i = 0; i < triangleCount; i++) for(size_t i = 0; i < triangleCount; i++)
{ {
for(size_t j = 0; j < 3; j++) for(size_t j = 0; j < 3; j++)
...@@ -132,8 +151,7 @@ namespace vkcv::meshlet ...@@ -132,8 +151,7 @@ namespace vkcv::meshlet
} }
} }
// init score for all vertices // calculate and initialize the triangle score, by summing the vertices' score
// ??????????????????????????
for (size_t i = 0; i < vertexCount; i++) for (size_t i = 0; i < vertexCount; i++)
{ {
lastScore[i] = findVertexScore(numActiveTris[i], static_cast<int32_t>(cacheTag[i])); lastScore[i] = findVertexScore(numActiveTris[i], static_cast<int32_t>(cacheTag[i]));
...@@ -144,7 +162,7 @@ namespace vkcv::meshlet ...@@ -144,7 +162,7 @@ namespace vkcv::meshlet
} }
} }
// find best triangle // find best triangle to start reordering with
int32_t bestTriangle = -1; int32_t bestTriangle = -1;
float bestScore = -1.0f; float bestScore = -1.0f;
for(size_t i = 0; i < triangleCount; i++) for(size_t i = 0; i < triangleCount; i++)
...@@ -160,7 +178,7 @@ namespace vkcv::meshlet ...@@ -160,7 +178,7 @@ namespace vkcv::meshlet
std::vector<int32_t> outTriangles(triangleCount, 0); std::vector<int32_t> outTriangles(triangleCount, 0);
uint32_t outPos = 0; uint32_t outPos = 0;
// init cache (with -1) // initialize cache (with -1)
std::array<int32_t, VERTEX_CACHE_SIZE + 3> cache = {}; std::array<int32_t, VERTEX_CACHE_SIZE + 3> cache = {};
for(auto &element : cache) for(auto &element : cache)
{ {
...@@ -169,33 +187,42 @@ namespace vkcv::meshlet ...@@ -169,33 +187,42 @@ namespace vkcv::meshlet
uint32_t scanPos = 0; uint32_t scanPos = 0;
// begin reordering routine
// output the currently best triangle, as long as there are triangles left to output
while(bestTriangle >= 0) while(bestTriangle >= 0)
{ {
// mark triangle as added // mark best triangle as added
triangleAdded[bestTriangle] = true; triangleAdded[bestTriangle] = true;
// output triangle // output this triangle
outTriangles[outPos++] = bestTriangle; outTriangles[outPos++] = bestTriangle;
// push best triangle's vertices into the cache
for(size_t i = 0; i < 3; i++) for(size_t i = 0; i < 3; i++)
{ {
uint32_t v = idxBuf[3 * bestTriangle + i]; uint32_t v = idxBuf[3 * bestTriangle + i];
// get vertex' cache position, if its -1, set its position to the end
int8_t endPos = cacheTag[v]; int8_t endPos = cacheTag[v];
if(endPos < 0) if(endPos < 0)
endPos = static_cast<int8_t>(VERTEX_CACHE_SIZE + i); endPos = static_cast<int8_t>(VERTEX_CACHE_SIZE + i);
// shift vertices' cache entries forward by one
for(int8_t j = endPos; j > i; j--) for(int8_t j = endPos; j > i; j--)
{ {
cache[j] = cache[j - 1]; cache[j] = cache[j - 1];
// if cache slot is valid vertex,
// update the vertex cache tag accordingly
if (cache[j] >= 0) if (cache[j] >= 0)
cacheTag[cache[j]]++; cacheTag[cache[j]]++;
} }
// insert current vertex into its new target slot
cache[i] = static_cast<int32_t>(v); cache[i] = static_cast<int32_t>(v);
cacheTag[v] = static_cast<int8_t>(i); cacheTag[v] = static_cast<int8_t>(i);
// find current triangle in the list of active triangles
// remove it by moving the last triangle into the slot the current triangle is holding.
for (size_t j = 0; j < numActiveTris[v]; j++) for (size_t j = 0; j < numActiveTris[v]; j++)
{ {
if(triangleIndices[offsets[v] + j] == bestTriangle) if(triangleIndices[offsets[v] + j] == bestTriangle)
...@@ -204,6 +231,7 @@ namespace vkcv::meshlet ...@@ -204,6 +231,7 @@ namespace vkcv::meshlet
break; break;
} }
} }
// shorten the list
numActiveTris[v]--; numActiveTris[v]--;
} }
...@@ -214,6 +242,7 @@ namespace vkcv::meshlet ...@@ -214,6 +242,7 @@ namespace vkcv::meshlet
if (v < 0) if (v < 0)
break; break;
// this vertex has been pushed outside of the actual cache
if(i >= VERTEX_CACHE_SIZE) if(i >= VERTEX_CACHE_SIZE)
{ {
cacheTag[v] = -1; cacheTag[v] = -1;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment