@@ -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+
27272845void runTests ()
27282846{
27292847 decodeIndexV0 ();
@@ -2844,4 +2962,7 @@ void runTests()
28442962 quantizeFloat ();
28452963 quantizeHalf ();
28462964 dequantizeHalf ();
2965+
2966+ encodeMeshletBound ();
2967+ decodeMeshletSafety ();
28472968}
0 commit comments