Skip to content

Commit bd54817

Browse files
authored
Merge pull request #1010 from zeux/mlc-tests
meshletcodec: Improve testing coverage
2 parents ff565a6 + fda228d commit bd54817

File tree

3 files changed

+125
-2
lines changed

3 files changed

+125
-2
lines changed

demo/main.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -761,10 +761,10 @@ void encodeIndexSequence(const std::vector<unsigned int>& data, size_t vertex_co
761761
}
762762

763763
template <typename V, typename T>
764-
void validateDecodeMeshlet(const unsigned char* data, size_t size, const unsigned int* vertices, size_t vertex_count, const unsigned char* triangles, size_t triangle_count)
764+
static void validateDecodeMeshlet(const unsigned char* data, size_t size, const unsigned int* vertices, size_t vertex_count, const unsigned char* triangles, size_t triangle_count)
765765
{
766766
V rv[256];
767-
T rt[sizeof(T) == 1 ? 256 * 3 + 3 : 256];
767+
T rt[sizeof(T) == 1 ? 256 * 3 : 256];
768768

769769
int rc = meshopt_decodeMeshlet(rv, vertex_count, rt, triangle_count, data, size);
770770
assert(rc == 0);

demo/tests.cpp

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2724,6 +2724,124 @@ static void dequantizeHalf()
27242724
assert(nanf != nanf);
27252725
}
27262726

2727+
static void encodeMeshletBound()
2728+
{
2729+
const unsigned char triangles[5 * 3] = {
2730+
0, 1, 2,
2731+
2, 1, 3,
2732+
3, 5, 4,
2733+
2, 0, 6,
2734+
7, 7, 7, // clang-format :-/
2735+
};
2736+
2737+
const unsigned int vertices[7] = {
2738+
5,
2739+
12,
2740+
140,
2741+
0,
2742+
12389,
2743+
123456789,
2744+
7,
2745+
};
2746+
2747+
size_t bound = meshopt_encodeMeshletBound(7, 5);
2748+
2749+
unsigned char enc[256];
2750+
size_t size = meshopt_encodeMeshlet(enc, sizeof(enc), vertices, 7, triangles, 5);
2751+
assert(size > 0 && size <= bound);
2752+
2753+
assert(meshopt_encodeMeshlet(enc, size - 1, vertices, 7, triangles, 5) == 0);
2754+
}
2755+
2756+
template <typename V, typename T, size_t VS, size_t TS>
2757+
static void validateDecodeMeshlet(const unsigned char* data, size_t size, const unsigned int* vertices, size_t vertex_count, const unsigned char* triangles, size_t triangle_count)
2758+
{
2759+
V rv[VS];
2760+
T rt[TS];
2761+
2762+
int rc = meshopt_decodeMeshlet(rv, vertex_count, rt, triangle_count, data, size);
2763+
assert(rc == 0);
2764+
2765+
for (size_t j = 0; j < vertex_count; ++j)
2766+
assert(rv[j] == V(vertices[j]));
2767+
2768+
for (size_t j = 0; j < triangle_count; ++j)
2769+
{
2770+
unsigned int a = triangles[j * 3 + 0];
2771+
unsigned int b = triangles[j * 3 + 1];
2772+
unsigned int c = triangles[j * 3 + 2];
2773+
2774+
unsigned int tri = sizeof(T) == 1 ? rt[j * 3] | (rt[j * 3 + 1] << 8) | (rt[j * 3 + 2] << 16) : rt[j];
2775+
2776+
unsigned int abc = (a << 0) | (b << 8) | (c << 16);
2777+
unsigned int bca = (b << 0) | (c << 8) | (a << 16);
2778+
unsigned int cba = (c << 0) | (a << 8) | (b << 16);
2779+
2780+
assert(tri == abc || tri == bca || tri == cba);
2781+
}
2782+
}
2783+
2784+
static void decodeMeshletSafety()
2785+
{
2786+
const unsigned char triangles[5 * 3] = {
2787+
0, 1, 2,
2788+
2, 1, 3,
2789+
3, 5, 4,
2790+
2, 0, 6,
2791+
7, 7, 7, // clang-format :-/
2792+
};
2793+
2794+
const unsigned int vertices[7] = {
2795+
5,
2796+
12,
2797+
140,
2798+
0,
2799+
12389,
2800+
123456789,
2801+
7,
2802+
};
2803+
2804+
unsigned char encb[256];
2805+
size_t size = meshopt_encodeMeshlet(encb, sizeof(encb), vertices, 7, triangles, 5);
2806+
assert(size > 0);
2807+
2808+
// move encoded buffer to the end to make sure any over-reads trigger sanitizers
2809+
unsigned char* enc = encb + sizeof(encb) - size;
2810+
memmove(enc, encb, size);
2811+
2812+
validateDecodeMeshlet<unsigned int, unsigned int, /* VS= */ 7, /* TS= */ 5>(enc, size, vertices, 7, triangles, 5);
2813+
2814+
// decodeMeshlet uses aligned 32-bit writes => must round vertex/triangle storage up when using short/char decoding
2815+
// note the +1 in triangle storage is because align(5*3, 4) = 16; it's up to +3 in general case
2816+
validateDecodeMeshlet<unsigned int, unsigned char, /* VS= */ 7, /* TS= */ 5 * 3 + 1>(enc, size, vertices, 7, triangles, 5);
2817+
validateDecodeMeshlet<unsigned short, unsigned int, /* VS= */ 7 + 1, /* TS= */ 5>(enc, size, vertices, 7, triangles, 5);
2818+
validateDecodeMeshlet<unsigned short, unsigned char, /* VS= */ 7 + 1, /* TS= */ 5 * 3 + 1>(enc, size, vertices, 7, triangles, 5);
2819+
2820+
// any truncated input should not be decodable; we check both prefix and suffix truncation
2821+
unsigned int rv[7], rt[5];
2822+
2823+
for (size_t i = 1; i < size; ++i)
2824+
assert(meshopt_decodeMeshlet(rv, 7, rt, 5, enc, i) < 0);
2825+
for (size_t i = 1; i < size; ++i)
2826+
assert(meshopt_decodeMeshlet(rv, 7, rt, 5, enc + i, size - i) < 0);
2827+
2828+
// when using decodeMeshletRaw, the output buffer sizes must be 16b aligned
2829+
unsigned int rvr[8], rtr[8];
2830+
2831+
for (size_t i = 1; i < size; ++i)
2832+
assert(meshopt_decodeMeshletRaw(rvr, 7, rtr, 5, enc, i) < 0);
2833+
for (size_t i = 1; i < size; ++i)
2834+
assert(meshopt_decodeMeshletRaw(rvr, 7, rtr, 5, enc + i, size - i) < 0);
2835+
2836+
// otherwise, decodeMeshlet and decodeMeshletRaw should agree
2837+
int rc = meshopt_decodeMeshlet(rv, 7, rt, 5, enc, size);
2838+
int rcr = meshopt_decodeMeshletRaw(rvr, 7, rtr, 5, enc, size);
2839+
2840+
assert(rc == 0 && rcr == 0);
2841+
assert(memcmp(rv, rvr, 7 * sizeof(unsigned int)) == 0);
2842+
assert(memcmp(rt, rtr, 5 * sizeof(unsigned int)) == 0);
2843+
}
2844+
27272845
void runTests()
27282846
{
27292847
decodeIndexV0();
@@ -2844,4 +2962,7 @@ void runTests()
28442962
quantizeFloat();
28452963
quantizeHalf();
28462964
dequantizeHalf();
2965+
2966+
encodeMeshletBound();
2967+
decodeMeshletSafety();
28472968
}

tools/codecfuzz.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ void fuzzRoundtripMeshlet(const uint8_t* data, size_t size)
7575
unsigned char buf[4096];
7676
size_t enc = meshopt_encodeMeshlet(buf, sizeof(buf), NULL, 0, reinterpret_cast<const unsigned char*>(data), triangle_count);
7777
assert(enc > 0);
78+
assert(enc <= meshopt_encodeMeshletBound(0, triangle_count));
7879

7980
unsigned int rt4[256];
8081
int rc4 = meshopt_decodeMeshlet(static_cast<unsigned int*>(NULL), 0, rt4, triangle_count, buf, enc);
@@ -122,6 +123,7 @@ void fuzzRoundtripMeshletV(const uint8_t* data, size_t size)
122123
unsigned char buf[4096];
123124
size_t enc = meshopt_encodeMeshlet(buf, sizeof(buf), reinterpret_cast<const uint32_t*>(data), vertex_count, tri, 1);
124125
assert(enc > 0);
126+
assert(enc <= meshopt_encodeMeshletBound(vertex_count, 1));
125127

126128
unsigned int rv4[256];
127129
int rc4 = meshopt_decodeMeshlet(rv4, vertex_count, tri, 1, buf, enc);

0 commit comments

Comments
 (0)