meshopt_decodeIndexBuffer: 363| 844|{ 364| 844| using namespace meshopt; 365| | 366| 844| assert(index_count % 3 == 0); 367| 0| assert(index_size == 2 || index_size == 4); 368| | 369| | // the minimum valid encoding is header, 1 byte per triangle and a 16-byte codeaux table 370| 844| if (buffer_size < 1 + index_count / 3 + 16) ------------------ | Branch (370:6): [True: 124, False: 720] ------------------ 371| 124| return -2; 372| | 373| 720| if ((buffer[0] & 0xf0) != kIndexHeader) ------------------ | Branch (373:6): [True: 394, False: 326] ------------------ 374| 394| return -1; 375| | 376| 326| int version = buffer[0] & 0x0f; 377| 326| if (version > 1) ------------------ | Branch (377:6): [True: 6, False: 320] ------------------ 378| 6| return -1; 379| | 380| 320| EdgeFifo edgefifo; 381| 320| memset(edgefifo, -1, sizeof(edgefifo)); 382| | 383| 320| VertexFifo vertexfifo; 384| 320| memset(vertexfifo, -1, sizeof(vertexfifo)); 385| | 386| 320| size_t edgefifooffset = 0; 387| 320| size_t vertexfifooffset = 0; 388| | 389| 320| unsigned int next = 0; 390| 320| unsigned int last = 0; 391| | 392| 320| int fecmax = version >= 1 ? 13 : 15; ------------------ | Branch (392:15): [True: 298, False: 22] ------------------ 393| | 394| | // since we store 16-byte codeaux table at the end, triangle data has to begin before data_safe_end 395| 320| const unsigned char* code = buffer + 1; 396| 320| const unsigned char* data = code + index_count / 3; 397| 320| const unsigned char* data_safe_end = buffer + buffer_size - 16; 398| | 399| 320| const unsigned char* codeaux_table = data_safe_end; 400| | 401| 4.14k| for (size_t i = 0; i < index_count; i += 3) ------------------ | Branch (401:21): [True: 4.10k, False: 40] ------------------ 402| 4.10k| { 403| | // make sure we have enough data to read for a triangle 404| | // each triangle reads at most 16 bytes of data: 1b for codeaux and 5b for each free index 405| | // after this we can be sure we can read without extra bounds checks 406| 4.10k| if (data > data_safe_end) ------------------ | Branch (406:7): [True: 280, False: 3.82k] ------------------ 407| 280| return -2; 408| | 409| 3.82k| unsigned char codetri = *code++; 410| | 411| 3.82k| if (codetri < 0xf0) ------------------ | Branch (411:7): [True: 2.03k, False: 1.79k] ------------------ 412| 2.03k| { 413| 2.03k| int fe = codetri >> 4; 414| | 415| | // fifo reads are wrapped around 16 entry buffer 416| 2.03k| unsigned int a = edgefifo[(edgefifooffset - 1 - fe) & 15][0]; 417| 2.03k| unsigned int b = edgefifo[(edgefifooffset - 1 - fe) & 15][1]; 418| | 419| 2.03k| int fec = codetri & 15; 420| | 421| | // note: this is the most common path in the entire decoder 422| | // inside this if we try to stay branchless (by using cmov/etc.) since these aren't predictable 423| 2.03k| if (fec < fecmax) ------------------ | Branch (423:8): [True: 1.40k, False: 632] ------------------ 424| 1.40k| { 425| | // fifo reads are wrapped around 16 entry buffer 426| 1.40k| unsigned int cf = vertexfifo[(vertexfifooffset - 1 - fec) & 15]; 427| 1.40k| unsigned int c = (fec == 0) ? next : cf; ------------------ | Branch (427:22): [True: 772, False: 630] ------------------ 428| | 429| 1.40k| int fec0 = fec == 0; 430| 1.40k| next += fec0; 431| | 432| | // output triangle 433| 1.40k| writeTriangle(destination, i, index_size, a, b, c); 434| | 435| | // push vertex/edge fifo must match the encoding step *exactly* otherwise the data will not be decoded correctly 436| 1.40k| pushVertexFifo(vertexfifo, c, vertexfifooffset, fec0); 437| | 438| 1.40k| pushEdgeFifo(edgefifo, c, b, edgefifooffset); 439| 1.40k| pushEdgeFifo(edgefifo, a, c, edgefifooffset); 440| 1.40k| } 441| 632| else 442| 632| { 443| 632| unsigned int c = 0; 444| | 445| | // fec - (fec ^ 3) decodes 13, 14 into -1, 1 446| | // note that we need to update the last index since free indices are delta-encoded 447| 632| last = c = (fec != 15) ? last + (fec - (fec ^ 3)) : decodeIndex(data, last); ------------------ | Branch (447:16): [True: 260, False: 372] ------------------ 448| | 449| | // output triangle 450| 632| writeTriangle(destination, i, index_size, a, b, c); 451| | 452| | // push vertex/edge fifo must match the encoding step *exactly* otherwise the data will not be decoded correctly 453| 632| pushVertexFifo(vertexfifo, c, vertexfifooffset); 454| | 455| 632| pushEdgeFifo(edgefifo, c, b, edgefifooffset); 456| 632| pushEdgeFifo(edgefifo, a, c, edgefifooffset); 457| 632| } 458| 2.03k| } 459| 1.79k| else 460| 1.79k| { 461| | // fast path: read codeaux from the table 462| 1.79k| if (codetri < 0xfe) ------------------ | Branch (462:8): [True: 644, False: 1.14k] ------------------ 463| 644| { 464| 644| unsigned char codeaux = codeaux_table[codetri & 15]; 465| | 466| | // note: table can't contain feb/fec=15 467| 644| int feb = codeaux >> 4; 468| 644| int fec = codeaux & 15; 469| | 470| | // fifo reads are wrapped around 16 entry buffer 471| | // also note that we increment next for all three vertices before decoding indices - this matches encoder behavior 472| 644| unsigned int a = next++; 473| | 474| 644| unsigned int bf = vertexfifo[(vertexfifooffset - feb) & 15]; 475| 644| unsigned int b = (feb == 0) ? next : bf; ------------------ | Branch (475:22): [True: 362, False: 282] ------------------ 476| | 477| 644| int feb0 = feb == 0; 478| 644| next += feb0; 479| | 480| 644| unsigned int cf = vertexfifo[(vertexfifooffset - fec) & 15]; 481| 644| unsigned int c = (fec == 0) ? next : cf; ------------------ | Branch (481:22): [True: 306, False: 338] ------------------ 482| | 483| 644| int fec0 = fec == 0; 484| 644| next += fec0; 485| | 486| | // output triangle 487| 644| writeTriangle(destination, i, index_size, a, b, c); 488| | 489| | // push vertex/edge fifo must match the encoding step *exactly* otherwise the data will not be decoded correctly 490| 644| pushVertexFifo(vertexfifo, a, vertexfifooffset); 491| 644| pushVertexFifo(vertexfifo, b, vertexfifooffset, feb0); 492| 644| pushVertexFifo(vertexfifo, c, vertexfifooffset, fec0); 493| | 494| 644| pushEdgeFifo(edgefifo, b, a, edgefifooffset); 495| 644| pushEdgeFifo(edgefifo, c, b, edgefifooffset); 496| 644| pushEdgeFifo(edgefifo, a, c, edgefifooffset); 497| 644| } 498| 1.14k| else 499| 1.14k| { 500| | // slow path: read a full byte for codeaux instead of using a table lookup 501| 1.14k| unsigned char codeaux = *data++; 502| | 503| 1.14k| int fea = codetri == 0xfe ? 0 : 15; ------------------ | Branch (503:15): [True: 700, False: 448] ------------------ 504| 1.14k| int feb = codeaux >> 4; 505| 1.14k| int fec = codeaux & 15; 506| | 507| | // reset: codeaux is 0 but encoded as not-a-table 508| 1.14k| if (codeaux == 0) ------------------ | Branch (508:9): [True: 120, False: 1.02k] ------------------ 509| 120| next = 0; 510| | 511| | // fifo reads are wrapped around 16 entry buffer 512| | // also note that we increment next for all three vertices before decoding indices - this matches encoder behavior 513| 1.14k| unsigned int a = (fea == 0) ? next++ : 0; ------------------ | Branch (513:22): [True: 700, False: 448] ------------------ 514| 1.14k| unsigned int b = (feb == 0) ? next++ : vertexfifo[(vertexfifooffset - feb) & 15]; ------------------ | Branch (514:22): [True: 194, False: 954] ------------------ 515| 1.14k| unsigned int c = (fec == 0) ? next++ : vertexfifo[(vertexfifooffset - fec) & 15]; ------------------ | Branch (515:22): [True: 186, False: 962] ------------------ 516| | 517| | // note that we need to update the last index since free indices are delta-encoded 518| 1.14k| if (fea == 15) ------------------ | Branch (518:9): [True: 448, False: 700] ------------------ 519| 448| last = a = decodeIndex(data, last); 520| | 521| 1.14k| if (feb == 15) ------------------ | Branch (521:9): [True: 394, False: 754] ------------------ 522| 394| last = b = decodeIndex(data, last); 523| | 524| 1.14k| if (fec == 15) ------------------ | Branch (524:9): [True: 364, False: 784] ------------------ 525| 364| last = c = decodeIndex(data, last); 526| | 527| | // output triangle 528| 1.14k| writeTriangle(destination, i, index_size, a, b, c); 529| | 530| | // push vertex/edge fifo must match the encoding step *exactly* otherwise the data will not be decoded correctly 531| 1.14k| pushVertexFifo(vertexfifo, a, vertexfifooffset); 532| 1.14k| pushVertexFifo(vertexfifo, b, vertexfifooffset, (feb == 0) | (feb == 15)); 533| 1.14k| pushVertexFifo(vertexfifo, c, vertexfifooffset, (fec == 0) | (fec == 15)); 534| | 535| 1.14k| pushEdgeFifo(edgefifo, b, a, edgefifooffset); 536| 1.14k| pushEdgeFifo(edgefifo, c, b, edgefifooffset); 537| 1.14k| pushEdgeFifo(edgefifo, a, c, edgefifooffset); 538| 1.14k| } 539| 1.79k| } 540| 3.82k| } 541| | 542| | // we should've read all data bytes and stopped at the boundary between data and codeaux table 543| 40| if (data != data_safe_end) ------------------ | Branch (543:6): [True: 28, False: 12] ------------------ 544| 28| return -3; 545| | 546| 12| return 0; 547| 40|} meshopt_decodeIndexSequence: 619| 844|{ 620| 844| using namespace meshopt; 621| | 622| | // the minimum valid encoding is header, 1 byte per index and a 4-byte tail 623| 844| if (buffer_size < 1 + index_count + 4) ------------------ | Branch (623:6): [True: 456, False: 388] ------------------ 624| 456| return -2; 625| | 626| 388| if ((buffer[0] & 0xf0) != kSequenceHeader) ------------------ | Branch (626:6): [True: 290, False: 98] ------------------ 627| 290| return -1; 628| | 629| 98| int version = buffer[0] & 0x0f; 630| 98| if (version > 1) ------------------ | Branch (630:6): [True: 6, False: 92] ------------------ 631| 6| return -1; 632| | 633| 92| const unsigned char* data = buffer + 1; 634| 92| const unsigned char* data_safe_end = buffer + buffer_size - 4; 635| | 636| 92| unsigned int last[2] = {}; 637| | 638| 4.94k| for (size_t i = 0; i < index_count; ++i) ------------------ | Branch (638:21): [True: 4.89k, False: 48] ------------------ 639| 4.89k| { 640| | // make sure we have enough data to read 641| | // each index reads at most 5 bytes of data; there's a 4 byte tail after data_safe_end 642| | // after this we can be sure we can read without extra bounds checks 643| 4.89k| if (data >= data_safe_end) ------------------ | Branch (643:7): [True: 44, False: 4.85k] ------------------ 644| 44| return -2; 645| | 646| 4.85k| unsigned int v = decodeVByte(data); 647| | 648| | // decode the index of the last baseline 649| 4.85k| unsigned int current = v & 1; 650| 4.85k| v >>= 1; 651| | 652| | // reconstruct index as a delta 653| 4.85k| unsigned int d = (v >> 1) ^ -int(v & 1); 654| 4.85k| unsigned int index = last[current] + d; 655| | 656| | // update last for the next iteration that uses it 657| 4.85k| last[current] = index; 658| | 659| 4.85k| if (index_size == 2) ------------------ | Branch (659:7): [True: 2.42k, False: 2.42k] ------------------ 660| 2.42k| { 661| 2.42k| static_cast(destination)[i] = (unsigned short)(index); 662| 2.42k| } 663| 2.42k| else 664| 2.42k| { 665| 2.42k| static_cast(destination)[i] = index; 666| 2.42k| } 667| 4.85k| } 668| | 669| | // we should've read all data bytes and stopped at the boundary between data and tail 670| 48| if (data != data_safe_end) ------------------ | Branch (670:6): [True: 46, False: 2] ------------------ 671| 46| return -3; 672| | 673| 2| return 0; 674| 48|} indexcodec.cpp:_ZN7meshoptL14pushVertexFifoEPjjRmi: 80| 7.41k|{ 81| 7.41k| fifo[offset] = v; 82| 7.41k| offset = (offset + cond) & 15; 83| 7.41k|} indexcodec.cpp:_ZN7meshoptL12pushEdgeFifoEPA2_jjjRm: 60| 9.44k|{ 61| 9.44k| fifo[offset][0] = a; 62| 9.44k| fifo[offset][1] = b; 63| 9.44k| offset = (offset + 1) & 15; 64| 9.44k|} indexcodec.cpp:_ZN7meshoptL13writeTriangleEPvmmjjj: 147| 3.82k|{ 148| 3.82k| if (index_size == 2) ------------------ | Branch (148:6): [True: 1.91k, False: 1.91k] ------------------ 149| 1.91k| { 150| 1.91k| static_cast(destination)[offset + 0] = (unsigned short)(a); 151| 1.91k| static_cast(destination)[offset + 1] = (unsigned short)(b); 152| 1.91k| static_cast(destination)[offset + 2] = (unsigned short)(c); 153| 1.91k| } 154| 1.91k| else 155| 1.91k| { 156| 1.91k| static_cast(destination)[offset + 0] = a; 157| 1.91k| static_cast(destination)[offset + 1] = b; 158| 1.91k| static_cast(destination)[offset + 2] = c; 159| 1.91k| } 160| 3.82k|} indexcodec.cpp:_ZN7meshoptL11decodeIndexERPKhj: 130| 1.57k|{ 131| 1.57k| unsigned int v = decodeVByte(data); 132| 1.57k| unsigned int d = (v >> 1) ^ -int(v & 1); 133| | 134| 1.57k| return last + d; 135| 1.57k|} indexcodec.cpp:_ZN7meshoptL11decodeVByteERPKh: 96| 6.43k|{ 97| 6.43k| unsigned char lead = *data++; 98| | 99| | // fast path: single byte 100| 6.43k| if (lead < 128) ------------------ | Branch (100:6): [True: 3.79k, False: 2.64k] ------------------ 101| 3.79k| return lead; 102| | 103| | // slow path: up to 4 extra bytes 104| | // note that this loop always terminates, which is important for malformed data 105| 2.64k| unsigned int result = lead & 127; 106| 2.64k| unsigned int shift = 7; 107| | 108| 9.22k| for (int i = 0; i < 4; ++i) ------------------ | Branch (108:18): [True: 7.77k, False: 1.45k] ------------------ 109| 7.77k| { 110| 7.77k| unsigned char group = *data++; 111| 7.77k| result |= unsigned(group & 127) << shift; 112| 7.77k| shift += 7; 113| | 114| 7.77k| if (group < 128) ------------------ | Branch (114:7): [True: 1.18k, False: 6.58k] ------------------ 115| 1.18k| break; 116| 7.77k| } 117| | 118| 2.64k| return result; 119| 6.43k|} meshopt_decodeVertexBuffer: 1179| 1.68k|{ 1180| 1.68k| using namespace meshopt; 1181| | 1182| 1.68k| assert(vertex_size > 0 && vertex_size <= 256); 1183| 0| assert(vertex_size % 4 == 0); 1184| | 1185| 0| const unsigned char* (*decode)(const unsigned char*, const unsigned char*, unsigned char*, size_t, size_t, unsigned char[256]) = 0; 1186| | 1187| 1.68k|#if defined(SIMD_SSE) && defined(SIMD_FALLBACK) 1188| 1.68k| decode = (cpuid & (1 << 9)) ? decodeVertexBlockSimd : decodeVertexBlock; ------------------ | Branch (1188:11): [True: 1.68k, False: 0] ------------------ 1189| |#elif defined(SIMD_SSE) || defined(SIMD_AVX) || defined(SIMD_NEON) || defined(SIMD_WASM) 1190| | decode = decodeVertexBlockSimd; 1191| |#else 1192| | decode = decodeVertexBlock; 1193| |#endif 1194| | 1195| 1.68k|#if defined(SIMD_SSE) || defined(SIMD_NEON) || defined(SIMD_WASM) 1196| 1.68k| assert(gDecodeBytesGroupInitialized); 1197| 0| (void)gDecodeBytesGroupInitialized; 1198| 1.68k|#endif 1199| | 1200| 1.68k| unsigned char* vertex_data = static_cast(destination); 1201| | 1202| 1.68k| const unsigned char* data = buffer; 1203| 1.68k| const unsigned char* data_end = buffer + buffer_size; 1204| | 1205| 1.68k| if (size_t(data_end - data) < 1 + vertex_size) ------------------ | Branch (1205:6): [True: 113, False: 1.57k] ------------------ 1206| 113| return -2; 1207| | 1208| 1.57k| unsigned char data_header = *data++; 1209| | 1210| 1.57k| if ((data_header & 0xf0) != kVertexHeader) ------------------ | Branch (1210:6): [True: 919, False: 656] ------------------ 1211| 919| return -1; 1212| | 1213| 656| int version = data_header & 0x0f; 1214| 656| if (version > 0) ------------------ | Branch (1214:6): [True: 15, False: 641] ------------------ 1215| 15| return -1; 1216| | 1217| 641| unsigned char last_vertex[256]; 1218| 641| memcpy(last_vertex, data_end - vertex_size, vertex_size); 1219| | 1220| 641| size_t vertex_block_size = getVertexBlockSize(vertex_size); 1221| | 1222| 641| size_t vertex_offset = 0; 1223| | 1224| 1.03k| while (vertex_offset < vertex_count) ------------------ | Branch (1224:9): [True: 641, False: 395] ------------------ 1225| 641| { 1226| 641| size_t block_size = (vertex_offset + vertex_block_size < vertex_count) ? vertex_block_size : vertex_count - vertex_offset; ------------------ | Branch (1226:23): [True: 0, False: 641] ------------------ 1227| | 1228| 641| data = decode(data, data_end, vertex_data + vertex_offset * vertex_size, block_size, vertex_size, last_vertex); 1229| 641| if (!data) ------------------ | Branch (1229:7): [True: 246, False: 395] ------------------ 1230| 246| return -2; 1231| | 1232| 395| vertex_offset += block_size; 1233| 395| } 1234| | 1235| 395| size_t tail_size = vertex_size < kTailMaxSize ? kTailMaxSize : vertex_size; ------------------ | Branch (1235:21): [True: 315, False: 80] ------------------ 1236| | 1237| 395| if (size_t(data_end - data) != tail_size) ------------------ | Branch (1237:6): [True: 393, False: 2] ------------------ 1238| 393| return -3; 1239| | 1240| 2| return 0; 1241| 395|} vertexcodec.cpp:_ZN7meshoptL27decodeBytesGroupBuildTablesEv: 425| 2|{ 426| 514| for (int mask = 0; mask < 256; ++mask) ------------------ | Branch (426:21): [True: 512, False: 2] ------------------ 427| 512| { 428| 512| unsigned char shuffle[8]; 429| 512| unsigned char count = 0; 430| | 431| 4.60k| for (int i = 0; i < 8; ++i) ------------------ | Branch (431:19): [True: 4.09k, False: 512] ------------------ 432| 4.09k| { 433| 4.09k| int maski = (mask >> i) & 1; 434| 4.09k| shuffle[i] = maski ? count : 0x80; ------------------ | Branch (434:17): [True: 2.04k, False: 2.04k] ------------------ 435| 4.09k| count += (unsigned char)(maski); 436| 4.09k| } 437| | 438| 512| memcpy(kDecodeBytesGroupShuffle[mask], shuffle, 8); 439| 512| kDecodeBytesGroupCount[mask] = count; 440| 512| } 441| | 442| 2| return true; 443| 2|} vertexcodec.cpp:_ZN7meshoptL14getCpuFeaturesEv: 1076| 2|{ 1077| 2| int cpuinfo[4] = {}; 1078| |#ifdef _MSC_VER 1079| | __cpuid(cpuinfo, 1); 1080| |#else 1081| 2| __cpuid(1, cpuinfo[0], cpuinfo[1], cpuinfo[2], cpuinfo[3]); 1082| 2|#endif 1083| 2| return cpuinfo[2]; 1084| 2|} vertexcodec.cpp:_ZN7meshoptL18getVertexBlockSizeEm: 117| 641|{ 118| | // make sure the entire block fits into the scratch buffer 119| 641| size_t result = kVertexBlockSizeBytes / vertex_size; 120| | 121| | // align to byte group size; we encode each byte as a byte group 122| | // if vertex block is misaligned, it results in wasted bytes, so just truncate the block size 123| 641| result &= ~(kByteGroupSize - 1); 124| | 125| 641| return (result < kVertexBlockMaxSize) ? result : kVertexBlockMaxSize; ------------------ | Branch (125:9): [True: 0, False: 641] ------------------ 126| 641|} vertexcodec.cpp:_ZN7meshoptL21decodeVertexBlockSimdEPKhS1_PhmmS2_: 977| 641|{ 978| 641| assert(vertex_count > 0 && vertex_count <= kVertexBlockMaxSize); 979| | 980| 0| unsigned char buffer[kVertexBlockMaxSize * 4]; 981| 641| unsigned char transposed[kVertexBlockSizeBytes]; 982| | 983| 641| size_t vertex_count_aligned = (vertex_count + kByteGroupSize - 1) & ~(kByteGroupSize - 1); 984| | 985| 2.62k| for (size_t k = 0; k < vertex_size; k += 4) ------------------ | Branch (985:21): [True: 2.22k, False: 395] ------------------ 986| 2.22k| { 987| 10.4k| for (size_t j = 0; j < 4; ++j) ------------------ | Branch (987:22): [True: 8.43k, False: 1.98k] ------------------ 988| 8.43k| { 989| 8.43k| data = decodeBytesSimd(data, data_end, buffer + j * vertex_count_aligned, vertex_count_aligned); 990| 8.43k| if (!data) ------------------ | Branch (990:8): [True: 246, False: 8.18k] ------------------ 991| 246| return 0; 992| 8.43k| } 993| | 994| 1.98k|#if defined(SIMD_SSE) || defined(SIMD_AVX) 995| 1.98k|#define TEMP __m128i 996| 1.98k|#define PREP() __m128i pi = _mm_cvtsi32_si128(*reinterpret_cast(last_vertex + k)) 997| 1.98k|#define LOAD(i) __m128i r##i = _mm_loadu_si128(reinterpret_cast(buffer + j + i * vertex_count_aligned)) 998| 1.98k|#define GRP4(i) t0 = _mm_shuffle_epi32(r##i, 0), t1 = _mm_shuffle_epi32(r##i, 1), t2 = _mm_shuffle_epi32(r##i, 2), t3 = _mm_shuffle_epi32(r##i, 3) 999| 1.98k|#define FIXD(i) t##i = pi = _mm_add_epi8(pi, t##i) 1000| 1.98k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size 1001| 1.98k|#endif 1002| | 1003| |#ifdef SIMD_NEON 1004| |#define TEMP uint8x8_t 1005| |#define PREP() uint8x8_t pi = vreinterpret_u8_u32(vld1_lane_u32(reinterpret_cast(last_vertex + k), vdup_n_u32(0), 0)) 1006| |#define LOAD(i) uint8x16_t r##i = vld1q_u8(buffer + j + i * vertex_count_aligned) 1007| |#define GRP4(i) t0 = vget_low_u8(r##i), t1 = vreinterpret_u8_u32(vdup_lane_u32(vreinterpret_u32_u8(t0), 1)), t2 = vget_high_u8(r##i), t3 = vreinterpret_u8_u32(vdup_lane_u32(vreinterpret_u32_u8(t2), 1)) 1008| |#define FIXD(i) t##i = pi = vadd_u8(pi, t##i) 1009| |#define SAVE(i) vst1_lane_u32(reinterpret_cast(savep), vreinterpret_u32_u8(t##i), 0), savep += vertex_size 1010| |#endif 1011| | 1012| |#ifdef SIMD_WASM 1013| |#define TEMP v128_t 1014| |#define PREP() v128_t pi = wasm_v128_load(last_vertex + k) 1015| |#define LOAD(i) v128_t r##i = wasm_v128_load(buffer + j + i * vertex_count_aligned) 1016| |#define GRP4(i) t0 = wasmx_splat_v32x4(r##i, 0), t1 = wasmx_splat_v32x4(r##i, 1), t2 = wasmx_splat_v32x4(r##i, 2), t3 = wasmx_splat_v32x4(r##i, 3) 1017| |#define FIXD(i) t##i = pi = wasm_i8x16_add(pi, t##i) 1018| |#define SAVE(i) *reinterpret_cast(savep) = wasm_i32x4_extract_lane(t##i, 0), savep += vertex_size 1019| |#endif 1020| | 1021| 1.98k| PREP(); ------------------ | | 996| 1.98k|#define PREP() __m128i pi = _mm_cvtsi32_si128(*reinterpret_cast(last_vertex + k)) ------------------ 1022| | 1023| 1.98k| unsigned char* savep = transposed + k; 1024| | 1025| 11.8k| for (size_t j = 0; j < vertex_count_aligned; j += 16) ------------------ | Branch (1025:22): [True: 9.91k, False: 1.98k] ------------------ 1026| 9.91k| { 1027| 9.91k| LOAD(0); ------------------ | | 997| 9.91k|#define LOAD(i) __m128i r##i = _mm_loadu_si128(reinterpret_cast(buffer + j + i * vertex_count_aligned)) ------------------ 1028| 9.91k| LOAD(1); ------------------ | | 997| 9.91k|#define LOAD(i) __m128i r##i = _mm_loadu_si128(reinterpret_cast(buffer + j + i * vertex_count_aligned)) ------------------ 1029| 9.91k| LOAD(2); ------------------ | | 997| 9.91k|#define LOAD(i) __m128i r##i = _mm_loadu_si128(reinterpret_cast(buffer + j + i * vertex_count_aligned)) ------------------ 1030| 9.91k| LOAD(3); ------------------ | | 997| 9.91k|#define LOAD(i) __m128i r##i = _mm_loadu_si128(reinterpret_cast(buffer + j + i * vertex_count_aligned)) ------------------ 1031| | 1032| 9.91k| r0 = unzigzag8(r0); 1033| 9.91k| r1 = unzigzag8(r1); 1034| 9.91k| r2 = unzigzag8(r2); 1035| 9.91k| r3 = unzigzag8(r3); 1036| | 1037| 9.91k| transpose8(r0, r1, r2, r3); 1038| | 1039| 9.91k| TEMP t0, t1, t2, t3; ------------------ | | 995| 9.91k|#define TEMP __m128i ------------------ 1040| | 1041| 9.91k| GRP4(0); ------------------ | | 998| 9.91k|#define GRP4(i) t0 = _mm_shuffle_epi32(r##i, 0), t1 = _mm_shuffle_epi32(r##i, 1), t2 = _mm_shuffle_epi32(r##i, 2), t3 = _mm_shuffle_epi32(r##i, 3) ------------------ 1042| 9.91k| FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 999| 9.91k|#define FIXD(i) t##i = pi = _mm_add_epi8(pi, t##i) ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 999| 9.91k|#define FIXD(i) t##i = pi = _mm_add_epi8(pi, t##i) ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 999| 9.91k|#define FIXD(i) t##i = pi = _mm_add_epi8(pi, t##i) ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 999| 9.91k|#define FIXD(i) t##i = pi = _mm_add_epi8(pi, t##i) ------------------ 1043| 9.91k| SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1000| 9.91k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1000| 9.91k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1000| 9.91k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1000| 9.91k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ 1044| | 1045| 9.91k| GRP4(1); ------------------ | | 998| 9.91k|#define GRP4(i) t0 = _mm_shuffle_epi32(r##i, 0), t1 = _mm_shuffle_epi32(r##i, 1), t2 = _mm_shuffle_epi32(r##i, 2), t3 = _mm_shuffle_epi32(r##i, 3) ------------------ 1046| 9.91k| FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 999| 9.91k|#define FIXD(i) t##i = pi = _mm_add_epi8(pi, t##i) ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 999| 9.91k|#define FIXD(i) t##i = pi = _mm_add_epi8(pi, t##i) ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 999| 9.91k|#define FIXD(i) t##i = pi = _mm_add_epi8(pi, t##i) ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 999| 9.91k|#define FIXD(i) t##i = pi = _mm_add_epi8(pi, t##i) ------------------ 1047| 9.91k| SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1000| 9.91k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1000| 9.91k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1000| 9.91k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1000| 9.91k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ 1048| | 1049| 9.91k| GRP4(2); ------------------ | | 998| 9.91k|#define GRP4(i) t0 = _mm_shuffle_epi32(r##i, 0), t1 = _mm_shuffle_epi32(r##i, 1), t2 = _mm_shuffle_epi32(r##i, 2), t3 = _mm_shuffle_epi32(r##i, 3) ------------------ 1050| 9.91k| FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 999| 9.91k|#define FIXD(i) t##i = pi = _mm_add_epi8(pi, t##i) ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 999| 9.91k|#define FIXD(i) t##i = pi = _mm_add_epi8(pi, t##i) ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 999| 9.91k|#define FIXD(i) t##i = pi = _mm_add_epi8(pi, t##i) ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 999| 9.91k|#define FIXD(i) t##i = pi = _mm_add_epi8(pi, t##i) ------------------ 1051| 9.91k| SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1000| 9.91k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1000| 9.91k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1000| 9.91k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1000| 9.91k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ 1052| | 1053| 9.91k| GRP4(3); ------------------ | | 998| 9.91k|#define GRP4(i) t0 = _mm_shuffle_epi32(r##i, 0), t1 = _mm_shuffle_epi32(r##i, 1), t2 = _mm_shuffle_epi32(r##i, 2), t3 = _mm_shuffle_epi32(r##i, 3) ------------------ 1054| 9.91k| FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 999| 9.91k|#define FIXD(i) t##i = pi = _mm_add_epi8(pi, t##i) ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 999| 9.91k|#define FIXD(i) t##i = pi = _mm_add_epi8(pi, t##i) ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 999| 9.91k|#define FIXD(i) t##i = pi = _mm_add_epi8(pi, t##i) ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 999| 9.91k|#define FIXD(i) t##i = pi = _mm_add_epi8(pi, t##i) ------------------ 1055| 9.91k| SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1000| 9.91k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1000| 9.91k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1000| 9.91k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1000| 9.91k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ 1056| | 1057| 9.91k|#undef TEMP 1058| 9.91k|#undef PREP 1059| 9.91k|#undef LOAD 1060| 9.91k|#undef GRP4 1061| 9.91k|#undef FIXD 1062| 9.91k|#undef SAVE 1063| 9.91k| } 1064| 1.98k| } 1065| | 1066| 395| memcpy(vertex_data, transposed, vertex_count * vertex_size); 1067| | 1068| 395| memcpy(last_vertex, &transposed[vertex_size * (vertex_count - 1)], vertex_size); 1069| | 1070| 395| return data; 1071| 641|} vertexcodec.cpp:_ZN7meshoptL15decodeBytesSimdEPKhS1_Phm: 931| 8.43k|{ 932| 8.43k| assert(buffer_size % kByteGroupSize == 0); 933| 0| assert(kByteGroupSize == 16); 934| | 935| 0| const unsigned char* header = data; 936| | 937| | // round number of groups to 4 to get number of header bytes 938| 8.43k| size_t header_size = (buffer_size / kByteGroupSize + 3) / 4; 939| | 940| 8.43k| if (size_t(data_end - data) < header_size) ------------------ | Branch (940:6): [True: 25, False: 8.40k] ------------------ 941| 25| return 0; 942| | 943| 8.40k| data += header_size; 944| | 945| 8.40k| size_t i = 0; 946| | 947| | // fast-path: process 4 groups at a time, do a shared bounds check - each group reads <=24b 948| 14.9k| for (; i + kByteGroupSize * 4 <= buffer_size && size_t(data_end - data) >= kByteGroupDecodeLimit * 4; i += kByteGroupSize * 4) ------------------ | Branch (948:9): [True: 8.40k, False: 6.54k] | Branch (948:50): [True: 6.54k, False: 1.86k] ------------------ 949| 6.54k| { 950| 6.54k| size_t header_offset = i / kByteGroupSize; 951| 6.54k| unsigned char header_byte = header[header_offset / 4]; 952| | 953| 6.54k| data = decodeBytesGroupSimd(data, buffer + i + kByteGroupSize * 0, (header_byte >> 0) & 3); 954| 6.54k| data = decodeBytesGroupSimd(data, buffer + i + kByteGroupSize * 1, (header_byte >> 2) & 3); 955| 6.54k| data = decodeBytesGroupSimd(data, buffer + i + kByteGroupSize * 2, (header_byte >> 4) & 3); 956| 6.54k| data = decodeBytesGroupSimd(data, buffer + i + kByteGroupSize * 3, (header_byte >> 6) & 3); 957| 6.54k| } 958| | 959| | // slow-path: process remaining groups 960| 23.4k| for (; i < buffer_size; i += kByteGroupSize) ------------------ | Branch (960:9): [True: 15.2k, False: 8.18k] ------------------ 961| 15.2k| { 962| 15.2k| if (size_t(data_end - data) < kByteGroupDecodeLimit) ------------------ | Branch (962:7): [True: 221, False: 15.0k] ------------------ 963| 221| return 0; 964| | 965| 15.0k| size_t header_offset = i / kByteGroupSize; 966| | 967| 15.0k| int bitslog2 = (header[header_offset / 4] >> ((header_offset % 4) * 2)) & 3; 968| | 969| 15.0k| data = decodeBytesGroupSimd(data, buffer + i, bitslog2); 970| 15.0k| } 971| | 972| 8.18k| return data; 973| 8.40k|} vertexcodec.cpp:_ZN7meshoptL20decodeBytesGroupSimdEPKhPhi: 463| 41.2k|{ 464| 41.2k| switch (bitslog2) 465| 41.2k| { 466| 32.8k| case 0: ------------------ | Branch (466:2): [True: 32.8k, False: 8.39k] ------------------ 467| 32.8k| { 468| 32.8k| __m128i result = _mm_setzero_si128(); 469| | 470| 32.8k| _mm_storeu_si128(reinterpret_cast<__m128i*>(buffer), result); 471| | 472| 32.8k| return data; 473| 0| } 474| | 475| 2.12k| case 1: ------------------ | Branch (475:2): [True: 2.12k, False: 39.1k] ------------------ 476| 2.12k| { 477| 2.12k|#ifdef __GNUC__ 478| 2.12k| typedef int __attribute__((aligned(1))) unaligned_int; 479| |#else 480| | typedef int unaligned_int; 481| |#endif 482| | 483| 2.12k|#ifdef SIMD_LATENCYOPT 484| 2.12k| unsigned int data32; 485| 2.12k| memcpy(&data32, data, 4); 486| 2.12k| data32 &= data32 >> 1; 487| | 488| | // arrange bits such that low bits of nibbles of data64 contain all 2-bit elements of data32 489| 2.12k| unsigned long long data64 = ((unsigned long long)data32 << 30) | (data32 & 0x3fffffff); 490| | 491| | // adds all 1-bit nibbles together; the sum fits in 4 bits because datacnt=16 would have used mode 3 492| 2.12k| int datacnt = int(((data64 & 0x1111111111111111ull) * 0x1111111111111111ull) >> 60); 493| 2.12k|#endif 494| | 495| 2.12k| __m128i sel2 = _mm_cvtsi32_si128(*reinterpret_cast(data)); 496| 2.12k| __m128i rest = _mm_loadu_si128(reinterpret_cast(data + 4)); 497| | 498| 2.12k| __m128i sel22 = _mm_unpacklo_epi8(_mm_srli_epi16(sel2, 4), sel2); 499| 2.12k| __m128i sel2222 = _mm_unpacklo_epi8(_mm_srli_epi16(sel22, 2), sel22); 500| 2.12k| __m128i sel = _mm_and_si128(sel2222, _mm_set1_epi8(3)); 501| | 502| 2.12k| __m128i mask = _mm_cmpeq_epi8(sel, _mm_set1_epi8(3)); 503| 2.12k| int mask16 = _mm_movemask_epi8(mask); 504| 2.12k| unsigned char mask0 = (unsigned char)(mask16 & 255); 505| 2.12k| unsigned char mask1 = (unsigned char)(mask16 >> 8); 506| | 507| 2.12k| __m128i shuf = decodeShuffleMask(mask0, mask1); 508| | 509| 2.12k| __m128i result = _mm_or_si128(_mm_shuffle_epi8(rest, shuf), _mm_andnot_si128(mask, sel)); 510| | 511| 2.12k| _mm_storeu_si128(reinterpret_cast<__m128i*>(buffer), result); 512| | 513| 2.12k|#ifdef SIMD_LATENCYOPT 514| 2.12k| return data + 4 + datacnt; 515| |#else 516| | return data + 4 + kDecodeBytesGroupCount[mask0] + kDecodeBytesGroupCount[mask1]; 517| |#endif 518| 0| } 519| | 520| 2.43k| case 2: ------------------ | Branch (520:2): [True: 2.43k, False: 38.8k] ------------------ 521| 2.43k| { 522| 2.43k|#ifdef SIMD_LATENCYOPT 523| 2.43k| unsigned long long data64; 524| 2.43k| memcpy(&data64, data, 8); 525| 2.43k| data64 &= data64 >> 1; 526| 2.43k| data64 &= data64 >> 2; 527| | 528| | // adds all 1-bit nibbles together; the sum fits in 4 bits because datacnt=16 would have used mode 3 529| 2.43k| int datacnt = int(((data64 & 0x1111111111111111ull) * 0x1111111111111111ull) >> 60); 530| 2.43k|#endif 531| | 532| 2.43k| __m128i sel4 = _mm_loadl_epi64(reinterpret_cast(data)); 533| 2.43k| __m128i rest = _mm_loadu_si128(reinterpret_cast(data + 8)); 534| | 535| 2.43k| __m128i sel44 = _mm_unpacklo_epi8(_mm_srli_epi16(sel4, 4), sel4); 536| 2.43k| __m128i sel = _mm_and_si128(sel44, _mm_set1_epi8(15)); 537| | 538| 2.43k| __m128i mask = _mm_cmpeq_epi8(sel, _mm_set1_epi8(15)); 539| 2.43k| int mask16 = _mm_movemask_epi8(mask); 540| 2.43k| unsigned char mask0 = (unsigned char)(mask16 & 255); 541| 2.43k| unsigned char mask1 = (unsigned char)(mask16 >> 8); 542| | 543| 2.43k| __m128i shuf = decodeShuffleMask(mask0, mask1); 544| | 545| 2.43k| __m128i result = _mm_or_si128(_mm_shuffle_epi8(rest, shuf), _mm_andnot_si128(mask, sel)); 546| | 547| 2.43k| _mm_storeu_si128(reinterpret_cast<__m128i*>(buffer), result); 548| | 549| 2.43k|#ifdef SIMD_LATENCYOPT 550| 2.43k| return data + 8 + datacnt; 551| |#else 552| | return data + 8 + kDecodeBytesGroupCount[mask0] + kDecodeBytesGroupCount[mask1]; 553| |#endif 554| 0| } 555| | 556| 3.83k| case 3: ------------------ | Branch (556:2): [True: 3.83k, False: 37.3k] ------------------ 557| 3.83k| { 558| 3.83k| __m128i result = _mm_loadu_si128(reinterpret_cast(data)); 559| | 560| 3.83k| _mm_storeu_si128(reinterpret_cast<__m128i*>(buffer), result); 561| | 562| 3.83k| return data + 16; 563| 0| } 564| | 565| 0| default: ------------------ | Branch (565:2): [True: 0, False: 41.2k] ------------------ 566| 0| assert(!"Unexpected bit length"); // unreachable since bitslog2 is a 2-bit value 567| 0| return data; 568| 41.2k| } 569| 41.2k|} vertexcodec.cpp:_ZN7meshoptL17decodeShuffleMaskEhh: 451| 4.55k|{ 452| 4.55k| __m128i sm0 = _mm_loadl_epi64(reinterpret_cast(&kDecodeBytesGroupShuffle[mask0])); 453| 4.55k| __m128i sm1 = _mm_loadl_epi64(reinterpret_cast(&kDecodeBytesGroupShuffle[mask1])); 454| 4.55k| __m128i sm1off = _mm_set1_epi8(kDecodeBytesGroupCount[mask0]); 455| | 456| 4.55k| __m128i sm1r = _mm_add_epi8(sm1, sm1off); 457| | 458| 4.55k| return _mm_unpacklo_epi64(sm0, sm1r); 459| 4.55k|} vertexcodec.cpp:_ZN7meshoptL9unzigzag8EDv2_x: 871| 39.6k|{ 872| 39.6k| __m128i xl = _mm_sub_epi8(_mm_setzero_si128(), _mm_and_si128(v, _mm_set1_epi8(1))); 873| 39.6k| __m128i xr = _mm_and_si128(_mm_srli_epi16(v, 1), _mm_set1_epi8(127)); 874| | 875| 39.6k| return _mm_xor_si128(xl, xr); 876| 39.6k|} vertexcodec.cpp:_ZN7meshoptL10transpose8ERDv2_xS1_S1_S1_: 857| 9.91k|{ 858| 9.91k| __m128i t0 = _mm_unpacklo_epi8(x0, x1); 859| 9.91k| __m128i t1 = _mm_unpackhi_epi8(x0, x1); 860| 9.91k| __m128i t2 = _mm_unpacklo_epi8(x2, x3); 861| 9.91k| __m128i t3 = _mm_unpackhi_epi8(x2, x3); 862| | 863| 9.91k| x0 = _mm_unpacklo_epi16(t0, t2); 864| 9.91k| x1 = _mm_unpackhi_epi16(t0, t2); 865| 9.91k| x2 = _mm_unpacklo_epi16(t1, t3); 866| 9.91k| x3 = _mm_unpackhi_epi16(t1, t3); 867| 9.91k|} _Z11fuzzDecoderPKhmmPFiPvmmS0_mE: 7| 3.37k|{ 8| 3.37k| size_t count = 66; // must be divisible by 3 for decodeIndexBuffer; should be >=64 to cover large vertex blocks 9| | 10| 3.37k| void* destination = malloc(count * stride); 11| 3.37k| assert(destination); 12| | 13| 0| int rc = decode(destination, count, stride, reinterpret_cast(data), size); 14| 3.37k| (void)rc; 15| | 16| 3.37k| free(destination); 17| 3.37k|} LLVMFuzzerTestOneInput: 25| 422|{ 26| | // decodeIndexBuffer supports 2 and 4-byte indices 27| 422| fuzzDecoder(data, size, 2, meshopt_decodeIndexBuffer); 28| 422| fuzzDecoder(data, size, 4, meshopt_decodeIndexBuffer); 29| | 30| | // decodeIndexSequence supports 2 and 4-byte indices 31| 422| fuzzDecoder(data, size, 2, meshopt_decodeIndexSequence); 32| 422| fuzzDecoder(data, size, 4, meshopt_decodeIndexSequence); 33| | 34| | // decodeVertexBuffer supports any strides divisible by 4 in 4-256 interval 35| | // It's a waste of time to check all of them, so we'll just check a few with different alignment mod 16 36| 422| fuzzDecoder(data, size, 4, meshopt_decodeVertexBuffer); 37| 422| fuzzDecoder(data, size, 16, meshopt_decodeVertexBuffer); 38| 422| fuzzDecoder(data, size, 24, meshopt_decodeVertexBuffer); 39| 422| fuzzDecoder(data, size, 32, meshopt_decodeVertexBuffer); 40| | 41| 422| return 0; 42| 422|}