meshopt_decodeIndexBuffer: 385| 4.33k|{ 386| 4.33k| using namespace meshopt; 387| | 388| 4.33k| assert(index_count % 3 == 0); ------------------ | Branch (388:2): [True: 4.33k, False: 0] ------------------ 389| 4.33k| assert(index_size == 2 || index_size == 4); ------------------ | Branch (389:2): [True: 2.16k, False: 2.16k] | Branch (389:2): [True: 2.16k, False: 0] | Branch (389:2): [True: 4.33k, False: 0] ------------------ 390| | 391| | // the minimum valid encoding is header, 1 byte per triangle and a 16-byte codeaux table 392| 4.33k| if (buffer_size < 1 + index_count / 3 + 16) ------------------ | Branch (392:6): [True: 1.88k, False: 2.45k] ------------------ 393| 1.88k| return -2; 394| | 395| 2.45k| if ((buffer[0] & 0xf0) != kIndexHeader) ------------------ | Branch (395:6): [True: 1.82k, False: 628] ------------------ 396| 1.82k| return -1; 397| | 398| 628| int version = buffer[0] & 0x0f; 399| 628| if (version > kDecodeIndexVersion) ------------------ | Branch (399:6): [True: 62, False: 566] ------------------ 400| 62| return -1; 401| | 402| 566| EdgeFifo edgefifo; 403| 566| memset(edgefifo, -1, sizeof(edgefifo)); 404| | 405| 566| VertexFifo vertexfifo; 406| 566| memset(vertexfifo, -1, sizeof(vertexfifo)); 407| | 408| 566| size_t edgefifooffset = 0; 409| 566| size_t vertexfifooffset = 0; 410| | 411| 566| unsigned int next = 0; 412| 566| unsigned int last = 0; 413| | 414| 566| int fecmax = version >= 1 ? 13 : 15; ------------------ | Branch (414:15): [True: 148, False: 418] ------------------ 415| | 416| | // since we store 16-byte codeaux table at the end, triangle data has to begin before data_safe_end 417| 566| const unsigned char* code = buffer + 1; 418| 566| const unsigned char* code_end = code + index_count / 3; 419| 566| const unsigned char* data = code_end; 420| | 421| | // each triangle reads at most 16 bytes of data: 1b for codeaux and 5b for each free index 422| 566| const unsigned char* data_safe_end = buffer + buffer_size - 16; 423| | 424| 566| const unsigned char* codeaux_table = data_safe_end; 425| | 426| 9.79k| while (code < code_end) ------------------ | Branch (426:9): [True: 9.49k, False: 296] ------------------ 427| 9.49k| { 428| 9.49k| unsigned char codetri = *code++; 429| | 430| 9.49k| if (codetri < 0xf0) ------------------ | Branch (430:7): [True: 5.41k, False: 4.08k] ------------------ 431| 5.41k| { 432| 5.41k| int fe = codetri >> 4; 433| | 434| | // fifo reads are wrapped around 16 entry buffer 435| 5.41k| unsigned int a = edgefifo[(edgefifooffset - 1 - fe) & 15][0]; 436| 5.41k| unsigned int b = edgefifo[(edgefifooffset - 1 - fe) & 15][1]; 437| 5.41k| unsigned int c = 0; 438| | 439| 5.41k| int fec = codetri & 15; 440| | 441| | // note: this is the most common path in the entire decoder 442| | // inside this if we try to stay branchless (by using cmov/etc.) since these aren't predictable 443| 5.41k| if (fec < fecmax) ------------------ | Branch (443:8): [True: 4.37k, False: 1.04k] ------------------ 444| 4.37k| { 445| | // fifo reads are wrapped around 16 entry buffer 446| 4.37k| unsigned int cf = vertexfifo[(vertexfifooffset - 1 - fec) & 15]; 447| | 448| 4.37k|#if (defined(__GNUC__) || defined(__clang__)) && (defined(__x86_64__) || defined(__aarch64__)) 449| | // on clang, x86-cmov-conversion pass emits a branch since cf is a load from memory; asm barrier defeats this 450| | // this can be fixed with __builtin_unpredictable, but gcc doesn't support it and has a similar problem due to if-conversion 451| | // additionally, gcc can fuse a/b into one 64-bit load but use 32-bit edgefifo[] stores, which breaks load store forwarding 452| 4.37k| __asm__("" : "+r"(a) : "r"(cf)); 453| 4.37k|#endif 454| | 455| 4.37k| c = (fec == 0) ? next : cf; ------------------ | Branch (455:9): [True: 1.96k, False: 2.40k] ------------------ 456| | 457| 4.37k| int fec0 = fec == 0; 458| 4.37k| next += fec0; 459| | 460| | // push vertex fifo must match the encoding step *exactly* otherwise the data will not be decoded correctly 461| 4.37k| pushVertexFifo(vertexfifo, c, vertexfifooffset, fec0); 462| 4.37k| } 463| 1.04k| else 464| 1.04k| { 465| | // make sure we have enough data to read for a triangle; this check covers worst case advance 466| 1.04k| if (data > data_safe_end) ------------------ | Branch (466:9): [True: 80, False: 960] ------------------ 467| 80| return -2; 468| | 469| | // fec * 2 - 27 decodes 13, 14 into -1, 1 470| | // note that we need to update the last index since free indices are delta-encoded 471| 960| last = c = (fec != 15) ? last + (fec * 2 - 27) : decodeIndex(data, last); ------------------ | Branch (471:16): [True: 278, False: 682] ------------------ 472| | 473| | // push vertex/edge fifo must match the encoding step *exactly* otherwise the data will not be decoded correctly 474| 960| pushVertexFifo(vertexfifo, c, vertexfifooffset); 475| 960| } 476| | 477| | // push edge fifo must match the encoding step *exactly* otherwise the data will not be decoded correctly 478| 5.33k| pushEdgeFifo(edgefifo, c, b, edgefifooffset); 479| 5.33k| pushEdgeFifo(edgefifo, a, c, edgefifooffset); 480| | 481| | // output triangle 482| 5.33k| destination = writeTriangle(destination, index_size, a, b, c); 483| 5.33k| } 484| 4.08k| else 485| 4.08k| { 486| | // fast path: read codeaux from the table 487| 4.08k| if (codetri < 0xfe) ------------------ | Branch (487:8): [True: 1.13k, False: 2.95k] ------------------ 488| 1.13k| { 489| 1.13k| unsigned char codeaux = codeaux_table[codetri & 15]; 490| | 491| | // note: table can't contain feb/fec=15 492| 1.13k| int feb = codeaux >> 4; 493| 1.13k| int fec = codeaux & 15; 494| | 495| | // fifo reads are wrapped around 16 entry buffer 496| | // also note that we increment next for all three vertices before decoding indices - this matches encoder behavior 497| 1.13k| unsigned int a = next++; 498| | 499| 1.13k| unsigned int bf = vertexfifo[(vertexfifooffset - feb) & 15]; 500| 1.13k| unsigned int b = (feb == 0) ? next : bf; ------------------ | Branch (500:22): [True: 314, False: 818] ------------------ 501| | 502| 1.13k| int feb0 = feb == 0; 503| 1.13k| next += feb0; 504| | 505| 1.13k| unsigned int cf = vertexfifo[(vertexfifooffset - fec) & 15]; 506| 1.13k| unsigned int c = (fec == 0) ? next : cf; ------------------ | Branch (506:22): [True: 404, False: 728] ------------------ 507| | 508| 1.13k| int fec0 = fec == 0; 509| 1.13k| next += fec0; 510| | 511| | // output triangle 512| 1.13k| destination = writeTriangle(destination, index_size, a, b, c); 513| | 514| | // push vertex/edge fifo must match the encoding step *exactly* otherwise the data will not be decoded correctly 515| 1.13k| pushVertexFifo(vertexfifo, a, vertexfifooffset); 516| 1.13k| pushVertexFifo(vertexfifo, b, vertexfifooffset, feb0); 517| 1.13k| pushVertexFifo(vertexfifo, c, vertexfifooffset, fec0); 518| | 519| 1.13k| pushEdgeFifo(edgefifo, b, a, edgefifooffset); 520| 1.13k| pushEdgeFifo(edgefifo, c, b, edgefifooffset); 521| 1.13k| pushEdgeFifo(edgefifo, a, c, edgefifooffset); 522| 1.13k| } 523| 2.95k| else 524| 2.95k| { 525| | // make sure we have enough data to read for a triangle; this check covers worst case advance 526| 2.95k| if (data > data_safe_end) ------------------ | Branch (526:9): [True: 190, False: 2.76k] ------------------ 527| 190| return -2; 528| | 529| | // slow path: read a full byte for codeaux instead of using a table lookup 530| 2.76k| unsigned char codeaux = *data++; 531| | 532| 2.76k| int fea = codetri == 0xfe ? 0 : 15; ------------------ | Branch (532:15): [True: 1.13k, False: 1.63k] ------------------ 533| 2.76k| int feb = codeaux >> 4; 534| 2.76k| int fec = codeaux & 15; 535| | 536| | // reset: codeaux is 0 but encoded as not-a-table 537| 2.76k| if (codeaux == 0) ------------------ | Branch (537:9): [True: 498, False: 2.26k] ------------------ 538| 498| next = 0; 539| | 540| | // fifo reads are wrapped around 16 entry buffer 541| | // also note that we increment next for all three vertices before decoding indices - this matches encoder behavior 542| 2.76k| unsigned int a = (fea == 0) ? next++ : 0; ------------------ | Branch (542:22): [True: 1.13k, False: 1.63k] ------------------ 543| 2.76k| unsigned int b = (feb == 0) ? next++ : vertexfifo[(vertexfifooffset - feb) & 15]; ------------------ | Branch (543:22): [True: 704, False: 2.05k] ------------------ 544| 2.76k| unsigned int c = (fec == 0) ? next++ : vertexfifo[(vertexfifooffset - fec) & 15]; ------------------ | Branch (544:22): [True: 714, False: 2.04k] ------------------ 545| | 546| | // note that we need to update the last index since free indices are delta-encoded 547| 2.76k| if (fea == 15) ------------------ | Branch (547:9): [True: 1.63k, False: 1.13k] ------------------ 548| 1.63k| last = a = decodeIndex(data, last); 549| | 550| 2.76k| if (feb == 15) ------------------ | Branch (550:9): [True: 854, False: 1.90k] ------------------ 551| 854| last = b = decodeIndex(data, last); 552| | 553| 2.76k| if (fec == 15) ------------------ | Branch (553:9): [True: 764, False: 1.99k] ------------------ 554| 764| last = c = decodeIndex(data, last); 555| | 556| | // output triangle 557| 2.76k| destination = writeTriangle(destination, index_size, a, b, c); 558| | 559| | // push vertex/edge fifo must match the encoding step *exactly* otherwise the data will not be decoded correctly 560| 2.76k| pushVertexFifo(vertexfifo, a, vertexfifooffset); 561| 2.76k| pushVertexFifo(vertexfifo, b, vertexfifooffset, (feb == 0) | (feb == 15)); 562| 2.76k| pushVertexFifo(vertexfifo, c, vertexfifooffset, (fec == 0) | (fec == 15)); 563| | 564| 2.76k| pushEdgeFifo(edgefifo, b, a, edgefifooffset); 565| 2.76k| pushEdgeFifo(edgefifo, c, b, edgefifooffset); 566| 2.76k| pushEdgeFifo(edgefifo, a, c, edgefifooffset); 567| 2.76k| } 568| 4.08k| } 569| 9.49k| } 570| | 571| | // we should've read all data bytes and stopped at the boundary between data and codeaux table 572| 296| if (data != data_safe_end) ------------------ | Branch (572:6): [True: 276, False: 20] ------------------ 573| 276| return -3; 574| | 575| 20| return 0; 576| 296|} meshopt_decodeIndexSequence: 648| 4.33k|{ 649| 4.33k| using namespace meshopt; 650| | 651| | // the minimum valid encoding is header, 1 byte per index and a 4-byte tail 652| 4.33k| if (buffer_size < 1 + index_count + 4) ------------------ | Branch (652:6): [True: 2.45k, False: 1.88k] ------------------ 653| 2.45k| return -2; 654| | 655| 1.88k| if ((buffer[0] & 0xf0) != kSequenceHeader) ------------------ | Branch (655:6): [True: 1.44k, False: 440] ------------------ 656| 1.44k| return -1; 657| | 658| 440| int version = buffer[0] & 0x0f; 659| 440| if (version > kDecodeIndexVersion) ------------------ | Branch (659:6): [True: 46, False: 394] ------------------ 660| 46| return -1; 661| | 662| 394| const unsigned char* data = buffer + 1; 663| 394| const unsigned char* data_safe_end = buffer + buffer_size - 4; 664| | 665| 394| unsigned int last[2] = {}; 666| | 667| 24.8k| for (size_t i = 0; i < index_count; ++i) ------------------ | Branch (667:21): [True: 24.4k, False: 328] ------------------ 668| 24.4k| { 669| | // make sure we have enough data to read 670| | // each index reads at most 5 bytes of data; there's a 4 byte tail after data_safe_end 671| | // after this we can be sure we can read without extra bounds checks 672| 24.4k| if (data >= data_safe_end) ------------------ | Branch (672:7): [True: 66, False: 24.4k] ------------------ 673| 66| return -2; 674| | 675| 24.4k| unsigned int v = decodeVByte(data); 676| | 677| | // decode the index of the last baseline 678| 24.4k| unsigned int current = v & 1; 679| 24.4k| v >>= 1; 680| | 681| | // reconstruct index as a delta 682| 24.4k| unsigned int d = (v >> 1) ^ -int(v & 1); 683| 24.4k| unsigned int index = last[current] + d; 684| | 685| | // update last for the next iteration that uses it 686| 24.4k| last[current] = index; 687| | 688| 24.4k| if (index_size == 2) ------------------ | Branch (688:7): [True: 12.2k, False: 12.2k] ------------------ 689| 12.2k| { 690| 12.2k| static_cast(destination)[i] = (unsigned short)(index); 691| 12.2k| } 692| 12.2k| else 693| 12.2k| { 694| 12.2k| static_cast(destination)[i] = index; 695| 12.2k| } 696| 24.4k| } 697| | 698| | // we should've read all data bytes and stopped at the boundary between data and tail 699| 328| if (data != data_safe_end) ------------------ | Branch (699:6): [True: 320, False: 8] ------------------ 700| 320| return -3; 701| | 702| 8| return 0; 703| 328|} indexcodec.cpp:_ZN7meshoptL14pushVertexFifoEPjjRmi: 75| 17.0k|{ 76| 17.0k| fifo[offset] = v; 77| 17.0k| offset = (offset + cond) & 15; 78| 17.0k|} indexcodec.cpp:_ZN7meshoptL12pushEdgeFifoEPA2_jjjRm: 55| 22.3k|{ 56| 22.3k| fifo[offset][0] = a; 57| 22.3k| fifo[offset][1] = b; 58| 22.3k| offset = (offset + 1) & 15; 59| 22.3k|} indexcodec.cpp:_ZN7meshoptL11decodeIndexERPKhj: 125| 3.93k|{ 126| 3.93k| unsigned int v = decodeVByte(data); 127| 3.93k| unsigned int d = (v >> 1) ^ -int(v & 1); 128| | 129| 3.93k| return last + d; 130| 3.93k|} indexcodec.cpp:_ZN7meshoptL13writeTriangleEPvmjjj: 142| 9.22k|{ 143| 9.22k| if (index_size == 2) ------------------ | Branch (143:6): [True: 4.61k, False: 4.61k] ------------------ 144| 4.61k| { 145| 4.61k| unsigned short* tri = static_cast(destination); 146| 4.61k| tri[0] = (unsigned short)(a); 147| 4.61k| tri[1] = (unsigned short)(b); 148| 4.61k| tri[2] = (unsigned short)(c); 149| | 150| 4.61k| return tri + 3; 151| 4.61k| } 152| 4.61k| else 153| 4.61k| { 154| 4.61k| unsigned int* tri = static_cast(destination); 155| 4.61k| tri[0] = a; 156| 4.61k| tri[1] = b; 157| 4.61k| tri[2] = c; 158| | 159| 4.61k| return tri + 3; 160| 4.61k| } 161| 9.22k|} indexcodec.cpp:_ZN7meshoptL11decodeVByteERPKh: 91| 28.3k|{ 92| 28.3k| unsigned char lead = *data++; 93| | 94| | // fast path: single byte 95| 28.3k| if (lead < 128) ------------------ | Branch (95:6): [True: 18.3k, False: 10.0k] ------------------ 96| 18.3k| return lead; 97| | 98| | // slow path: up to 4 extra bytes 99| | // note that this loop always terminates, which is important for malformed data 100| 10.0k| unsigned int result = lead & 127; 101| 10.0k| unsigned int shift = 7; 102| | 103| 29.9k| for (int i = 0; i < 4; ++i) ------------------ | Branch (103:18): [True: 26.3k, False: 3.54k] ------------------ 104| 26.3k| { 105| 26.3k| unsigned char group = *data++; 106| 26.3k| result |= unsigned(group & 127) << shift; 107| 26.3k| shift += 7; 108| | 109| 26.3k| if (group < 128) ------------------ | Branch (109:7): [True: 6.51k, False: 19.8k] ------------------ 110| 6.51k| break; 111| 26.3k| } 112| | 113| 10.0k| return result; 114| 28.3k|} meshopt_encodeMeshletBound: 899| 4.33k|{ 900| 4.33k| size_t codes_size = (max_triangles + 1) / 2; 901| 4.33k| size_t extra_size = max_triangles * 3; 902| | 903| 4.33k| size_t ctrl_size = (max_vertices + 3) / 4; 904| 4.33k| size_t data_size = (max_vertices + 3) / 4 * 16; // worst case: 16 bytes per vertex group 905| | 906| 4.33k| size_t gap_size = (codes_size + ctrl_size < 16) ? 16 - (codes_size + ctrl_size) : 0; ------------------ | Branch (906:20): [True: 2.77k, False: 1.56k] ------------------ 907| | 908| 4.33k| return codes_size + extra_size + ctrl_size + data_size + gap_size; 909| 4.33k|} meshopt_encodeMeshlet: 912| 4.33k|{ 913| 4.33k| using namespace meshopt; 914| | 915| 4.33k| assert(triangle_count <= 256 && vertex_count <= 256); ------------------ | Branch (915:2): [True: 4.33k, False: 0] | Branch (915:2): [True: 4.33k, False: 0] | Branch (915:2): [True: 4.33k, False: 0] ------------------ 916| | 917| | // 4 bits per triangle + up to three bytes of extra data 918| 4.33k| unsigned char codes[256 / 2]; 919| 4.33k| unsigned char extra[256 * 3]; 920| 4.33k| size_t codes_size = (triangle_count + 1) / 2; 921| 4.33k| size_t extra_size = encodeTriangles(codes, extra, triangles, triangle_count); 922| 4.33k| assert(extra_size <= sizeof(extra)); ------------------ | Branch (922:2): [True: 4.33k, False: 0] ------------------ 923| | 924| | // 2 bits per vertex + up to 4 bytes of actual data 925| 4.33k| unsigned char ctrl[256 / 4]; 926| 4.33k| unsigned char data[256 * 4]; 927| 4.33k| size_t ctrl_size = (vertex_count + 3) / 4; 928| 4.33k| size_t data_size = encodeVertices(ctrl, data, vertices, vertex_count); 929| 4.33k| assert(data_size <= sizeof(data)); ------------------ | Branch (929:2): [True: 4.33k, False: 0] ------------------ 930| | 931| | // we need to ensure that up to 16 bytes after extra+data are available for SIMD decoding 932| | // to minimize overhead, we place fixed-size codes+control at the end of the buffer 933| 4.33k| size_t gap_size = (codes_size + ctrl_size < 16) ? 16 - (codes_size + ctrl_size) : 0; ------------------ | Branch (933:20): [True: 2.77k, False: 1.56k] ------------------ 934| | 935| 4.33k| size_t result = codes_size + extra_size + ctrl_size + data_size + gap_size; 936| | 937| 4.33k| if (result > buffer_size) ------------------ | Branch (937:6): [True: 0, False: 4.33k] ------------------ 938| 0| return 0; 939| | 940| | // variable-size data first 941| 4.33k| memcpy(buffer, data, data_size); 942| 4.33k| buffer += data_size; 943| 4.33k| memcpy(buffer, extra, extra_size); 944| 4.33k| buffer += extra_size; 945| | 946| | // gap (for accelerated decoding) separates variable-size and fixed-size data 947| 4.33k| memset(buffer, 0, gap_size); 948| 4.33k| buffer += gap_size; 949| | 950| | // fixed-size data last; it can be located from buffer end during decoding 951| 4.33k| memcpy(buffer, ctrl, ctrl_size); 952| 4.33k| buffer += ctrl_size; 953| 4.33k| memcpy(buffer, codes, codes_size); 954| 4.33k| buffer += codes_size; 955| | 956| |#if TRACE > 1 957| | printf("extra:"); 958| | for (size_t i = 0; i < extra_size; ++i) 959| | printf(" %d", extra[i]); 960| | printf("\n"); 961| | 962| | unsigned int minv = ~0u; 963| | for (size_t i = 0; i < vertex_count; ++i) 964| | minv = minv < vertices[i] ? minv : vertices[i]; 965| | 966| | printf("vertices: [%d+]", minv); 967| | for (size_t i = 0; i < vertex_count; ++i) 968| | printf(" %d", vertices[i] - minv); 969| | printf("\n"); 970| |#endif 971| | 972| |#if TRACE 973| | printf("stats: %d vertices, %d triangles => %d bytes (triangles: %d codes, %d extra; vertices: %d control, %d data; %d gap)\n", 974| | int(vertex_count), int(triangle_count), int(result), 975| | int(codes_size), int(extra_size), int(ctrl_size), int(data_size), int(gap_size)); 976| |#endif 977| | 978| 4.33k| return result; 979| 4.33k|} meshopt_decodeMeshlet: 982| 17.2k|{ 983| 17.2k| using namespace meshopt; 984| | 985| 17.2k| assert(triangle_count <= 256 && vertex_count <= 256); ------------------ | Branch (985:2): [True: 17.2k, False: 0] | Branch (985:2): [True: 17.2k, False: 0] | Branch (985:2): [True: 17.2k, False: 0] ------------------ 986| 17.2k| assert(vertex_size == 4 || vertex_size == 2); ------------------ | Branch (986:2): [True: 10.8k, False: 6.47k] | Branch (986:2): [True: 6.47k, False: 0] | Branch (986:2): [True: 17.2k, False: 0] ------------------ 987| 17.2k| assert(triangle_size == 4 || triangle_size == 3); ------------------ | Branch (987:2): [True: 6.47k, False: 10.8k] | Branch (987:2): [True: 10.8k, False: 0] | Branch (987:2): [True: 17.2k, False: 0] ------------------ 988| | 989| | // layout must match encoding 990| 17.2k| size_t codes_size = (triangle_count + 1) / 2; 991| 17.2k| size_t ctrl_size = (vertex_count + 3) / 4; 992| 17.2k| size_t gap_size = (codes_size + ctrl_size < 16) ? 16 - (codes_size + ctrl_size) : 0; ------------------ | Branch (992:20): [True: 7.12k, False: 10.1k] ------------------ 993| | 994| 17.2k| if (buffer_size < codes_size + ctrl_size + gap_size) ------------------ | Branch (994:6): [True: 4.30k, False: 12.9k] ------------------ 995| 4.30k| return -2; 996| | 997| 12.9k| const unsigned char* end = buffer + buffer_size; 998| 12.9k| const unsigned char* codes = end - codes_size; 999| 12.9k| const unsigned char* ctrl = codes - ctrl_size; 1000| 12.9k| const unsigned char* data = buffer; 1001| | 1002| | // gap ensures we have at least 16 bytes available after bound; this allows SIMD decoders to over-read safely 1003| 12.9k| const unsigned char* bound = ctrl - gap_size; 1004| 12.9k| assert(bound >= buffer && bound + 16 <= buffer + buffer_size); ------------------ | Branch (1004:2): [True: 12.9k, False: 0] | Branch (1004:2): [True: 12.9k, False: 0] | Branch (1004:2): [True: 12.9k, False: 0] ------------------ 1005| | 1006| 12.9k|#if defined(SIMD_FALLBACK) 1007| 12.9k| return (gDecodeTablesInitialized ? decodeMeshletSimd<0> : decodeMeshlet)(vertices, triangles, codes, ctrl, data, bound, vertex_count, triangle_count, vertex_size, triangle_size); ------------------ | Branch (1007:10): [True: 12.9k, False: 0] ------------------ 1008| |#elif defined(SIMD_SSE) || defined(SIMD_NEON) 1009| | return decodeMeshletSimd<0>(vertices, triangles, codes, ctrl, data, bound, vertex_count, triangle_count, vertex_size, triangle_size); 1010| |#else 1011| | return decodeMeshlet(vertices, triangles, codes, ctrl, data, bound, vertex_count, triangle_count, vertex_size, triangle_size); 1012| |#endif 1013| 12.9k|} meshopt_decodeMeshletRaw: 1016| 2.15k|{ 1017| 2.15k| using namespace meshopt; 1018| | 1019| 2.15k| assert(triangle_count <= 256 && vertex_count <= 256); ------------------ | Branch (1019:2): [True: 2.15k, False: 0] | Branch (1019:2): [True: 2.15k, False: 0] | Branch (1019:2): [True: 2.15k, False: 0] ------------------ 1020| | 1021| | // layout must match encoding 1022| 2.15k| size_t codes_size = (triangle_count + 1) / 2; 1023| 2.15k| size_t ctrl_size = (vertex_count + 3) / 4; 1024| 2.15k| size_t gap_size = (codes_size + ctrl_size < 16) ? 16 - (codes_size + ctrl_size) : 0; ------------------ | Branch (1024:20): [True: 394, False: 1.76k] ------------------ 1025| | 1026| 2.15k| if (buffer_size < codes_size + ctrl_size + gap_size) ------------------ | Branch (1026:6): [True: 1.07k, False: 1.08k] ------------------ 1027| 1.07k| return -2; 1028| | 1029| 1.08k| const unsigned char* end = buffer + buffer_size; 1030| 1.08k| const unsigned char* codes = end - codes_size; 1031| 1.08k| const unsigned char* ctrl = codes - ctrl_size; 1032| 1.08k| const unsigned char* data = buffer; 1033| | 1034| | // gap ensures we have at least 16 bytes available after bound; this allows SIMD decoders to over-read safely 1035| 1.08k| const unsigned char* bound = ctrl - gap_size; 1036| 1.08k| assert(bound >= buffer && bound + 16 <= buffer + buffer_size); ------------------ | Branch (1036:2): [True: 1.08k, False: 0] | Branch (1036:2): [True: 1.08k, False: 0] | Branch (1036:2): [True: 1.08k, False: 0] ------------------ 1037| | 1038| 1.08k|#if defined(SIMD_FALLBACK) 1039| 1.08k| return (gDecodeTablesInitialized ? decodeMeshletSimd<1> : decodeMeshlet)(vertices, triangles, codes, ctrl, data, bound, vertex_count, triangle_count, 4, 4); ------------------ | Branch (1039:10): [True: 1.08k, False: 0] ------------------ 1040| |#elif defined(SIMD_SSE) || defined(SIMD_NEON) 1041| | return decodeMeshletSimd<1>(vertices, triangles, codes, ctrl, data, bound, vertex_count, triangle_count, 4, 4); 1042| |#else 1043| | return decodeMeshlet(vertices, triangles, codes, ctrl, data, bound, vertex_count, triangle_count, 4, 4); 1044| |#endif 1045| 1.08k|} meshletcodec.cpp:_ZN7meshoptL17decodeBuildTablesEv: 398| 2|{ 399| 2|#define NEXT(var, ec) \ 400| 2| shuf[var] = (ec) ? (unsigned char)extra : 15; \ 401| 2| next[var] = (ec) ? 0 : (unsigned char)nextoff; \ 402| 2| extra += (ec), nextoff += 1 - (ec) 403| | 404| | // check for SSE4.1 support if we have a fallback path 405| 2|#if defined(SIMD_SSE) && defined(SIMD_FALLBACK) 406| 2| int cpuinfo[4] = {}; 407| |#ifdef _MSC_VER 408| | __cpuid(cpuinfo, 1); 409| |#else 410| 2| __cpuid(1, cpuinfo[0], cpuinfo[1], cpuinfo[2], cpuinfo[3]); 411| 2|#endif 412| | // bit 19 = SSE4.1 413| 2| if ((cpuinfo[2] & (1 << 19)) == 0) ------------------ | Branch (413:6): [True: 0, False: 2] ------------------ 414| 0| return false; 415| 2|#endif 416| | 417| | // fill triangle decoding tables for each combination of two triangle codes 418| 514| for (int code = 0; code < 256; ++code) ------------------ | Branch (418:21): [True: 512, False: 2] ------------------ 419| 512| { 420| 512| unsigned char shuf[16] = {}; 421| 512| unsigned char next[16] = {}; 422| 512| int extra = 0; 423| 512| int nextoff = 0; 424| | 425| | // state 0..5 will be refilled every iteration, so we ignore that 426| | // state 6..8 will always contain the last decoded triangle because every triangle shifts fifo equally, so we can decode it independently 427| 512| shuf[6] = 12; 428| 512| shuf[7] = 13; 429| 512| shuf[8] = 14; 430| | 431| | // state 15 will contain next (potentially incremented a few times) 432| 512| shuf[15] = 15; 433| | 434| | // state 9..11 will contain the first decoded triangle (tri0), which can refer to extra/next and the original triangle history 435| | // state 12..14 will contain the second decoded triangle (tri1); when decoding edge reuse, we need to handle edge 0/1 specially as it was just decoded earlier 436| 1.53k| for (int k = 0; k < 2; ++k) ------------------ | Branch (436:19): [True: 1.02k, False: 512] ------------------ 437| 1.02k| { 438| 1.02k| int tri = (code >> (k * 4)) & 0xf; 439| | 440| 1.02k| if (tri < 12) ------------------ | Branch (440:8): [True: 768, False: 256] ------------------ 441| 768| { 442| 768| if (k == 1 && tri / 4 == 0) ------------------ | Branch (442:9): [True: 384, False: 384] | Branch (442:19): [True: 128, False: 256] ------------------ 443| 128| { 444| | // we need to decode one of two edges from the triangle we just decoded earlier 445| | // for that we simply need to copy shuf/next values for the two decoded indices 446| 128| shuf[9 + k * 3] = shuf[9 + ((tri & 2) ? 2 : 0)]; ------------------ | Branch (446:34): [True: 64, False: 64] ------------------ 447| 128| next[9 + k * 3] = next[9 + ((tri & 2) ? 2 : 0)]; ------------------ | Branch (447:34): [True: 64, False: 64] ------------------ 448| | 449| 128| shuf[10 + k * 3] = shuf[9 + ((tri & 2) ? 1 : 2)]; ------------------ | Branch (449:35): [True: 64, False: 64] ------------------ 450| 128| next[10 + k * 3] = next[9 + ((tri & 2) ? 1 : 2)]; ------------------ | Branch (450:35): [True: 64, False: 64] ------------------ 451| 128| } 452| 640| else 453| 640| { 454| | // reuse: edge comes from the history based on edge index 455| | // note: we reuse with an offset because last triangle in the original history was consumed by tri0 456| 640| int trioff = 6 + k * 3 + (2 - tri / 4) * 3; 457| | 458| | // edge cb or ac 459| 640| shuf[9 + k * 3] = (unsigned char)(trioff + ((tri & 2) ? 2 : 0)); ------------------ | Branch (459:50): [True: 320, False: 320] ------------------ 460| 640| shuf[10 + k * 3] = (unsigned char)(trioff + ((tri & 2) ? 1 : 2)); ------------------ | Branch (460:51): [True: 320, False: 320] ------------------ 461| 640| } 462| | 463| | // third vertex is either next or comes from extra 464| 768| NEXT(11 + k * 3, tri & 1); ------------------ | | 400| 768| shuf[var] = (ec) ? (unsigned char)extra : 15; \ | | ------------------ | | | Branch (400:14): [True: 384, False: 384] | | ------------------ | | 401| 768| next[var] = (ec) ? 0 : (unsigned char)nextoff; \ | | ------------------ | | | Branch (401:14): [True: 384, False: 384] | | ------------------ | | 402| 768| extra += (ec), nextoff += 1 - (ec) ------------------ 465| 768| } 466| 256| else 467| 256| { 468| | // restart: three vertices, each comes from next or extra 469| 256| int fea = tri > 12; 470| 256| int feb = tri > 13; 471| 256| int fec = tri > 14; 472| | 473| 256| NEXT(9 + k * 3, fea); ------------------ | | 400| 256| shuf[var] = (ec) ? (unsigned char)extra : 15; \ | | ------------------ | | | Branch (400:14): [True: 192, False: 64] | | ------------------ | | 401| 256| next[var] = (ec) ? 0 : (unsigned char)nextoff; \ | | ------------------ | | | Branch (401:14): [True: 192, False: 64] | | ------------------ | | 402| 256| extra += (ec), nextoff += 1 - (ec) ------------------ 474| 256| NEXT(10 + k * 3, feb); ------------------ | | 400| 256| shuf[var] = (ec) ? (unsigned char)extra : 15; \ | | ------------------ | | | Branch (400:14): [True: 128, False: 128] | | ------------------ | | 401| 256| next[var] = (ec) ? 0 : (unsigned char)nextoff; \ | | ------------------ | | | Branch (401:14): [True: 128, False: 128] | | ------------------ | | 402| 256| extra += (ec), nextoff += 1 - (ec) ------------------ 475| 256| NEXT(11 + k * 3, fec); ------------------ | | 400| 256| shuf[var] = (ec) ? (unsigned char)extra : 15; \ | | ------------------ | | | Branch (400:14): [True: 64, False: 192] | | ------------------ | | 401| 256| next[var] = (ec) ? 0 : (unsigned char)nextoff; \ | | ------------------ | | | Branch (401:14): [True: 64, False: 192] | | ------------------ | | 402| 256| extra += (ec), nextoff += 1 - (ec) ------------------ 476| 256| } 477| 1.02k| } 478| | 479| | // next needs to advance 480| 512| next[15] = (unsigned char)nextoff; 481| | 482| | // next[0..8] = 0 trivially (never written to); next[9] must also be 0 because nextoff is 0 initially 483| | // shuf[0..5] is not used, which allows us to pack next[10..15] + shuf[6..15] into a single 16-byte entry 484| 512| assert(next[9] == 0); ------------------ | Branch (484:3): [True: 512, False: 0] ------------------ 485| 512| memcpy(&kDecodeTableMasks[code][0], &next[10], 6); 486| 512| memcpy(&kDecodeTableMasks[code][6], &shuf[6], 10); 487| 512| kDecodeTableExtra[code] = (unsigned char)extra; 488| 512| } 489| | 490| | // fill vertex decoding tables for each combination of four vertex references 491| 514| for (unsigned int i = 0; i < 256; ++i) ------------------ | Branch (491:27): [True: 512, False: 2] ------------------ 492| 512| { 493| 512| unsigned char shuf[16] = {}; 494| 512| int offset = 0; 495| | 496| 2.56k| for (int k = 0; k < 4; ++k) ------------------ | Branch (496:19): [True: 2.04k, False: 512] ------------------ 497| 2.04k| { 498| 2.04k| int code = ((i >> k) & 1) | ((i >> (k + 3)) & 2); 499| 2.04k| int length = i == 0xff ? 4 : code; // 0/1/2/3 bytes, or all 4 bytes if code==0xff ------------------ | Branch (499:17): [True: 8, False: 2.04k] ------------------ 500| | 501| 2.04k| shuf[k * 4 + 0] = (length > 0) ? (unsigned char)(offset + 0) : 0x80; ------------------ | Branch (501:22): [True: 1.53k, False: 512] ------------------ 502| 2.04k| shuf[k * 4 + 1] = (length > 1) ? (unsigned char)(offset + 1) : 0x80; ------------------ | Branch (502:22): [True: 1.02k, False: 1.02k] ------------------ 503| 2.04k| shuf[k * 4 + 2] = (length > 2) ? (unsigned char)(offset + 2) : 0x80; ------------------ | Branch (503:22): [True: 512, False: 1.53k] ------------------ 504| 2.04k| shuf[k * 4 + 3] = (length > 3) ? (unsigned char)(offset + 3) : 0x80; ------------------ | Branch (504:22): [True: 8, False: 2.04k] ------------------ 505| | 506| 2.04k| offset += length; 507| 2.04k| } 508| | 509| 512| memcpy(kDecodeTableVerts[i], shuf, sizeof(shuf)); 510| 512| kDecodeTableLength[i] = (unsigned char)offset; 511| 512| } 512| | 513| 2| return true; 514| | 515| 2|#undef NEXT 516| 2|} meshletcodec.cpp:_ZN7meshoptL15encodeTrianglesEPhS0_PKhm: 109| 4.33k|{ 110| 4.33k| EdgeFifo8 edgefifo; 111| 4.33k| memset(edgefifo, -1, sizeof(edgefifo)); 112| | 113| 4.33k| size_t edgefifooffset = 0; 114| | 115| 4.33k| unsigned int next = 0; 116| | 117| | // 4-bit triangle codes give us 16 options that we use as follows: 118| | // 3*2 edge reuse (2 edges * 3 last triangles) * 2 next/explicit = 12 options 119| | // 4 remaining options = next bits; 000, 001, 011, 111. 120| | // triangles are rotated to make next bits line up. 121| 4.33k| memset(codes, 0, (triangle_count + 1) / 2); 122| | 123| 4.33k| static const int rotations[] = {0, 1, 2, 0, 1}; 124| | 125| 4.33k| unsigned char* start = extra; 126| | 127| 183k| for (size_t i = 0; i < triangle_count; ++i) ------------------ | Branch (127:21): [True: 179k, False: 4.33k] ------------------ 128| 179k| { 129| |#if TRACE > 1 130| | unsigned int last = next; 131| |#endif 132| | 133| 179k| int fer = getEdgeFifo8(edgefifo, triangles[i * 3 + 0], triangles[i * 3 + 1], triangles[i * 3 + 2], edgefifooffset); 134| | 135| 179k| if (fer >= 0 && (fer >> 2) < 6) ------------------ | Branch (135:7): [True: 90.1k, False: 88.9k] | Branch (135:19): [True: 86.3k, False: 3.83k] ------------------ 136| 86.3k| { 137| | // note: getEdgeFifo8 implicitly rotates triangles by matching a/b to existing edge 138| 86.3k| const int* order = rotations + (fer & 3); 139| | 140| 86.3k| unsigned int a = triangles[i * 3 + order[0]], b = triangles[i * 3 + order[1]], c = triangles[i * 3 + order[2]]; 141| | 142| 86.3k| int fec = (c == next) ? (next++, 0) : 1; ------------------ | Branch (142:14): [True: 750, False: 85.6k] ------------------ 143| | 144| |#if TRACE > 1 145| | printf("%3d+ | %3d %3d %3d | edge: e%d c%d\n", last, a, b, c, fer >> 2, fec); 146| |#endif 147| | 148| 86.3k| unsigned int code = (fer >> 2) * 2 + fec; 149| | 150| 86.3k| codes[i / 2] |= (unsigned char)(code << ((i & 1) * 4)); 151| | 152| 86.3k| if (fec) ------------------ | Branch (152:8): [True: 85.6k, False: 750] ------------------ 153| 85.6k| *extra++ = (unsigned char)c; 154| | 155| 86.3k| pushEdgeFifo8(edgefifo, c, b, edgefifooffset); 156| 86.3k| pushEdgeFifo8(edgefifo, a, c, edgefifooffset); 157| 86.3k| } 158| 92.8k| else 159| 92.8k| { 160| | // rotate triangles to minimize the need for extra vertices 161| 92.8k| int rotation = rotateTriangle(triangles[i * 3 + 0], triangles[i * 3 + 1], triangles[i * 3 + 2]); 162| 92.8k| const int* order = rotations + rotation; 163| | 164| 92.8k| unsigned int a = triangles[i * 3 + order[0]], b = triangles[i * 3 + order[1]], c = triangles[i * 3 + order[2]]; 165| | 166| | // fe must be continuous: once a vertex is encoded with next, further vertices must also be encoded with next 167| 92.8k| int fea = (a == next && b == next + 1 && c == next + 2) ? (next++, 0) : 1; ------------------ | Branch (167:15): [True: 8.83k, False: 83.9k] | Branch (167:28): [True: 3.80k, False: 5.03k] | Branch (167:45): [True: 3.06k, False: 732] ------------------ 168| 92.8k| int feb = (b == next && c == next + 1) ? (next++, 0) : 1; ------------------ | Branch (168:15): [True: 8.03k, False: 84.7k] | Branch (168:28): [True: 3.29k, False: 4.74k] ------------------ 169| 92.8k| int fec = (c == next) ? (next++, 0) : 1; ------------------ | Branch (169:14): [True: 4.32k, False: 88.4k] ------------------ 170| | 171| 92.8k| assert(fea == 1 || feb == 0); ------------------ | Branch (171:4): [True: 89.7k, False: 3.06k] | Branch (171:4): [True: 3.06k, False: 0] | Branch (171:4): [True: 92.8k, False: 0] ------------------ 172| 92.8k| assert(feb == 1 || fec == 0); ------------------ | Branch (172:4): [True: 89.5k, False: 3.29k] | Branch (172:4): [True: 3.29k, False: 0] | Branch (172:4): [True: 92.8k, False: 0] ------------------ 173| | 174| |#if TRACE > 1 175| | printf("%3d+ | %3d %3d %3d | restart: %d%d%d\n", last, a, b, c, fea, feb, fec); 176| |#endif 177| | 178| 92.8k| unsigned int code = 12 + (fea + feb + fec); 179| | 180| 92.8k| codes[i / 2] |= (unsigned char)(code << ((i & 1) * 4)); 181| | 182| 92.8k| if (fea) ------------------ | Branch (182:8): [True: 89.7k, False: 3.06k] ------------------ 183| 89.7k| *extra++ = (unsigned char)a; 184| 92.8k| if (feb) ------------------ | Branch (184:8): [True: 89.5k, False: 3.29k] ------------------ 185| 89.5k| *extra++ = (unsigned char)b; 186| 92.8k| if (fec) ------------------ | Branch (186:8): [True: 88.4k, False: 4.32k] ------------------ 187| 88.4k| *extra++ = (unsigned char)c; 188| | 189| 92.8k| pushEdgeFifo8(edgefifo, c, b, edgefifooffset); 190| 92.8k| pushEdgeFifo8(edgefifo, a, c, edgefifooffset); 191| 92.8k| } 192| 179k| } 193| | 194| 4.33k| return extra - start; 195| 4.33k|} meshletcodec.cpp:_ZN7meshoptL12getEdgeFifo8EPA2_jjjjm: 82| 179k|{ 83| 954k| for (int i = 0; i < 8; ++i) ------------------ | Branch (83:18): [True: 865k, False: 88.9k] ------------------ 84| 865k| { 85| 865k| size_t index = (offset - 1 - i) & 7; 86| | 87| 865k| unsigned int e0 = fifo[index][0]; 88| 865k| unsigned int e1 = fifo[index][1]; 89| | 90| 865k| if (e0 == a && e1 == b) ------------------ | Branch (90:7): [True: 137k, False: 727k] | Branch (90:18): [True: 73.3k, False: 63.9k] ------------------ 91| 73.3k| return (i << 2) | 0; 92| 791k| if (e0 == b && e1 == c) ------------------ | Branch (92:7): [True: 55.3k, False: 736k] | Branch (92:18): [True: 8.96k, False: 46.3k] ------------------ 93| 8.96k| return (i << 2) | 1; 94| 782k| if (e0 == c && e1 == a) ------------------ | Branch (94:7): [True: 56.4k, False: 726k] | Branch (94:18): [True: 7.91k, False: 48.5k] ------------------ 95| 7.91k| return (i << 2) | 2; 96| 782k| } 97| | 98| 88.9k| return -1; 99| 179k|} meshletcodec.cpp:_ZN7meshoptL13pushEdgeFifo8EPA2_jjjRm: 102| 358k|{ 103| 358k| fifo[offset][0] = a; 104| 358k| fifo[offset][1] = b; 105| 358k| offset = (offset + 1) & 7; 106| 358k|} meshletcodec.cpp:_ZN7meshoptL14rotateTriangleEjjj: 77| 92.8k|{ 78| 92.8k| return (a > b && a > c) ? 1 : (b > c ? 2 : 0); ------------------ | Branch (78:10): [True: 39.2k, False: 53.6k] | Branch (78:19): [True: 26.8k, False: 12.3k] | Branch (78:33): [True: 25.6k, False: 40.2k] ------------------ 79| 92.8k|} meshletcodec.cpp:_ZN7meshoptL14encodeVerticesEPhS0_PKjm: 198| 4.33k|{ 199| | // grouped varint, 2 bit per value to indicate 0/1/2/3 byte deltas, with per-group 4-byte fallback 200| 4.33k| memset(ctrl, 0, (vertex_count + 3) / 4); 201| | 202| 4.33k| unsigned char* start = data; 203| | 204| 4.33k| unsigned int last = ~0u; 205| | 206| 46.2k| for (size_t i = 0; i < vertex_count; i += 4) ------------------ | Branch (206:21): [True: 41.9k, False: 4.33k] ------------------ 207| 41.9k| { 208| 41.9k| unsigned int gv[4] = {}; 209| | 210| 207k| for (int k = 0; k < 4 && i + k < vertex_count; ++k) ------------------ | Branch (210:19): [True: 166k, False: 40.8k] | Branch (210:28): [True: 165k, False: 1.10k] ------------------ 211| 165k| { 212| 165k| unsigned int d = vertices[i + k] - last - 1; 213| 165k| unsigned int v = (d << 1) ^ (int(d) >> 31); 214| | 215| 165k| gv[k] = v; 216| 165k| last = vertices[i + k]; 217| 165k| } 218| | 219| | // if any value needs 4 bytes, or if *all* values need 3 bytes, we use 4 bytes for all values 220| | // this allows us to encode most 3-byte deltas with 3 bytes which saves space overall 221| 41.9k| bool use4 = (gv[0] | gv[1] | gv[2] | gv[3]) > 0xffffff || (gv[0] > 0xffff && gv[1] > 0xffff && gv[2] > 0xffff && gv[3] > 0xffff); ------------------ | Branch (221:15): [True: 28.1k, False: 13.7k] | Branch (221:62): [True: 1.20k, False: 12.5k] | Branch (221:80): [True: 732, False: 473] | Branch (221:98): [True: 395, False: 337] | Branch (221:116): [True: 291, False: 104] ------------------ 222| | 223| 209k| for (int k = 0; k < 4; ++k) ------------------ | Branch (223:19): [True: 167k, False: 41.9k] ------------------ 224| 167k| { 225| 167k| unsigned int v = gv[k]; 226| | 227| | // 0/1/2/3 bytes per value, or all 4 values use 4 bytes 228| 167k| int code = use4 ? 3 : (v == 0 ? 0 : (v < 256 ? 1 : (v < 65536 ? 2 : 3))); ------------------ | Branch (228:15): [True: 113k, False: 53.9k] | Branch (228:27): [True: 1.99k, False: 51.9k] | Branch (228:41): [True: 46.5k, False: 5.40k] | Branch (228:56): [True: 2.90k, False: 2.49k] ------------------ 229| | 230| 167k| if (code > 0) ------------------ | Branch (230:8): [True: 165k, False: 1.99k] ------------------ 231| 165k| *data++ = (unsigned char)(v & 0xff); 232| 167k| if (code > 1) ------------------ | Branch (232:8): [True: 119k, False: 48.5k] ------------------ 233| 119k| *data++ = (unsigned char)((v >> 8) & 0xff); 234| 167k| if (code > 2) ------------------ | Branch (234:8): [True: 116k, False: 51.4k] ------------------ 235| 116k| *data++ = (unsigned char)((v >> 16) & 0xff); 236| 167k| if (use4) ------------------ | Branch (236:8): [True: 113k, False: 53.9k] ------------------ 237| 113k| *data++ = (unsigned char)((v >> 24) & 0xff); 238| | 239| | // split low and high bits into two nibbles for better packing 240| 167k| ctrl[i / 4] |= ((code & 1) << k) | ((code >> 1) << (k + 4)); 241| 167k| } 242| 41.9k| } 243| | 244| 4.33k| return data - start; 245| 4.33k|} meshletcodec.cpp:_ZN7meshoptL17decodeMeshletSimdILi0EEEiPvS1_PKhS3_S3_S3_mmmm: 865| 12.9k|{ 866| 12.9k| assert(gDecodeTablesInitialized); ------------------ | Branch (866:2): [True: 12.9k, False: 0] ------------------ 867| 12.9k| (void)gDecodeTablesInitialized; 868| | 869| 12.9k|#ifdef __clang__ 870| | // data is guaranteed to be non-null initially; if decode loops never hit bounds errors, it remains non-null 871| 12.9k| __builtin_assume(data); 872| 12.9k|#endif 873| | 874| | // decodes 4 vertices at a time with tail processing; writes up to align(vertex_size * vertex_count, 4) 875| | // raw decoding skips tail processing by rounding up vertex count; it's safe because output buffer is guaranteed to have extra space, and tail control data is 0 876| 12.9k| if (vertex_size == 4 || Raw) ------------------ | Branch (876:6): [True: 8.66k, False: 4.32k] | Branch (876:26): [Folded, False: 0] ------------------ 877| 8.66k| data = decodeVerticesSimd(static_cast(vertices), ctrl, data, bound, Raw ? (vertex_count + 3) & ~3 : vertex_count); ------------------ | Branch (877:86): [Folded, False: 8.66k] ------------------ 878| 4.32k| else 879| 4.32k| data = decodeVerticesSimd(static_cast(vertices), ctrl, data, bound, vertex_count); 880| 12.9k| if (!data) ------------------ | Branch (880:6): [True: 888, False: 12.1k] ------------------ 881| 888| return -2; 882| | 883| | // decodes 2/4 triangles at a time with tail processing; writes up to align(triangle_size * triangle_count, 4) 884| | // raw decoding skips tail processing by rounding up triangle count; it's safe because output buffer is guaranteed to have extra space, and tail code data is 0 885| 12.1k| if (triangle_size == 4 || Raw) ------------------ | Branch (885:6): [True: 3.88k, False: 8.22k] | Branch (885:28): [Folded, False: 0] ------------------ 886| 3.88k| data = decodeTrianglesSimd(static_cast(triangles), codes, data, bound, Raw ? (triangle_count + 1) & ~1 : triangle_count); ------------------ | Branch (886:89): [Folded, False: 3.88k] ------------------ 887| 8.22k| else 888| 8.22k| data = decodeTrianglesSimd(static_cast(triangles), codes, data, bound, triangle_count); 889| 12.1k| if (!data) ------------------ | Branch (889:6): [True: 290, False: 11.8k] ------------------ 890| 290| return -2; 891| | 892| 11.8k| return (data == bound) ? 0 : -3; ------------------ | Branch (892:9): [True: 8.74k, False: 3.07k] ------------------ 893| 12.1k|} meshletcodec.cpp:_ZN7meshoptL18decodeVerticesSimdEPjPKhS2_S2_m: 750| 9.74k|{ 751| 9.74k|#if defined(SIMD_SSE) 752| 9.74k| __m128i last = _mm_set1_epi32(-1); 753| |#elif defined(SIMD_NEON) 754| | uint32x4_t last = vdupq_n_u32(~0u); 755| |#endif 756| | 757| 9.74k| size_t groups = vertex_count / 4; 758| | 759| | // process all complete groups 760| 134k| for (size_t i = 0; i < groups; ++i) ------------------ | Branch (760:21): [True: 124k, False: 9.10k] ------------------ 761| 124k| { 762| 124k| unsigned char code = *ctrl++; 763| 124k| if (data > bound) ------------------ | Branch (763:7): [True: 642, False: 124k] ------------------ 764| 642| return NULL; 765| | 766| 124k| last = decodeVertexGroup(last, code, data); 767| | 768| 124k|#if defined(SIMD_SSE) 769| 124k| _mm_storeu_si128(reinterpret_cast<__m128i*>(&vertices[i * 4]), last); 770| |#elif defined(SIMD_NEON) 771| | vst1q_u32(&vertices[i * 4], last); 772| |#endif 773| 124k| } 774| | 775| | // process a 1-3 vertex tail; to maintain the memory safety guarantee we have to write individual elements 776| 9.10k| if (vertex_count & 3) ------------------ | Branch (776:6): [True: 2.64k, False: 6.46k] ------------------ 777| 2.64k| { 778| 2.64k| unsigned char code = *ctrl++; 779| | 780| 2.64k| if (data > bound) ------------------ | Branch (780:7): [True: 24, False: 2.61k] ------------------ 781| 24| return NULL; 782| | 783| 2.61k| last = decodeVertexGroup(last, code, data); 784| | 785| 2.61k| unsigned int* tail = &vertices[vertex_count & ~3u]; 786| | 787| 2.61k|#if defined(SIMD_SSE) 788| 2.61k| tail[0] = _mm_cvtsi128_si32(last); 789| 2.61k| if ((vertex_count & 3) > 1) ------------------ | Branch (789:7): [True: 1.12k, False: 1.49k] ------------------ 790| 1.12k| tail[1] = _mm_extract_epi32(last, 1); 791| 2.61k| if ((vertex_count & 3) > 2) ------------------ | Branch (791:7): [True: 389, False: 2.22k] ------------------ 792| 389| tail[2] = _mm_extract_epi32(last, 2); 793| |#elif defined(SIMD_NEON) 794| | vst1q_lane_u32(&tail[0], last, 0); 795| | if ((vertex_count & 3) > 1) 796| | vst1q_lane_u32(&tail[1], last, 1); 797| | if ((vertex_count & 3) > 2) 798| | vst1q_lane_u32(&tail[2], last, 2); 799| |#endif 800| 2.61k| } 801| | 802| 9.08k| return data; 803| 9.10k|} _ZN7meshopt17decodeVertexGroupEDv2_xhRPKh: 540| 225k|{ 541| 225k| __m128i word = _mm_loadu_si128(reinterpret_cast(data)); 542| 225k| __m128i shuf = _mm_loadu_si128(reinterpret_cast(kDecodeTableVerts[code])); 543| | 544| 225k| __m128i v = _mm_shuffle_epi8(word, shuf); 545| | 546| | // unzigzag+1 547| 225k| __m128i xl = _mm_sub_epi32(_mm_setzero_si128(), _mm_and_si128(v, _mm_set1_epi32(1))); 548| 225k| __m128i xr = _mm_srli_epi32(v, 1); 549| 225k| __m128i x = _mm_add_epi32(_mm_xor_si128(xl, xr), _mm_set1_epi32(1)); 550| | 551| | // prefix sum 552| 225k| x = _mm_add_epi32(x, _mm_slli_si128(x, 8)); 553| 225k| x = _mm_add_epi32(x, _mm_slli_si128(x, 4)); 554| 225k| x = _mm_add_epi32(x, _mm_shuffle_epi32(last, 0xff)); 555| | 556| 225k| data += kDecodeTableLength[code]; 557| | 558| 225k| return x; 559| 225k|} meshletcodec.cpp:_ZN7meshoptL18decodeVerticesSimdEPtPKhS2_S2_m: 807| 4.32k|{ 808| 4.32k|#if defined(SIMD_SSE) 809| 4.32k| __m128i repack = _mm_setr_epi8(0, 1, 4, 5, 8, 9, 12, 13, 0, 0, 0, 0, 0, 0, 0, 0); 810| 4.32k| __m128i last = _mm_set1_epi32(-1); 811| |#elif defined(SIMD_NEON) 812| | uint32x4_t last = vdupq_n_u32(~0u); 813| |#endif 814| | 815| | // because the output buffer is guaranteed to have 32-bit aligned size available, we can simplify tail processing 816| | // if the number of vertices mod 4 is 3, we'd normally need to write 8+6 bytes, but we can instead overwrite up to 2 bytes in the main loop 817| 4.32k| size_t groups = (vertex_count + 1) / 4; 818| | 819| | // process all complete groups 820| 100k| for (size_t i = 0; i < groups; ++i) ------------------ | Branch (820:21): [True: 96.8k, False: 3.90k] ------------------ 821| 96.8k| { 822| 96.8k| unsigned char code = *ctrl++; 823| | 824| 96.8k| if (data > bound) ------------------ | Branch (824:7): [True: 428, False: 96.3k] ------------------ 825| 428| return NULL; 826| | 827| 96.3k| last = decodeVertexGroup(last, code, data); 828| | 829| 96.3k|#if defined(SIMD_SSE) 830| 96.3k| __m128i r = _mm_shuffle_epi8(last, repack); 831| 96.3k| _mm_storel_epi64(reinterpret_cast<__m128i*>(&vertices[i * 4]), r); 832| |#elif defined(SIMD_NEON) 833| | uint16x4_t r = vmovn_u32(last); 834| | vst1_u16(&vertices[i * 4], r); 835| |#endif 836| 96.3k| } 837| | 838| | // process a 1-2 vertex tail; to maintain the memory safety guarantee we have to write a 32-bit element 839| 3.90k| if (groups * 4 < vertex_count) ------------------ | Branch (839:6): [True: 2.24k, False: 1.65k] ------------------ 840| 2.24k| { 841| 2.24k| unsigned char code = *ctrl++; 842| | 843| 2.24k| if (data > bound) ------------------ | Branch (843:7): [True: 16, False: 2.22k] ------------------ 844| 16| return NULL; 845| | 846| 2.22k| last = decodeVertexGroup(last, code, data); 847| | 848| 2.22k| unsigned short* tail = &vertices[vertex_count & ~3u]; 849| | 850| 2.22k|#if defined(SIMD_SSE) 851| 2.22k| __m128i r = _mm_shufflelo_epi16(last, 8); 852| 2.22k| *reinterpret_cast(tail) = _mm_cvtsi128_si32(r); 853| |#elif defined(SIMD_NEON) 854| | uint16x4_t r = vmovn_u32(last); 855| | vst1_lane_u32(reinterpret_cast(tail), vreinterpret_u32_u16(r), 0); 856| |#endif 857| 2.22k| } 858| | 859| 3.88k| return data; 860| 3.90k|} meshletcodec.cpp:_ZN7meshoptL19decodeTrianglesSimdEPjPKhS2_S2_m: 615| 4.74k|{ 616| 4.74k|#if defined(SIMD_SSE) 617| 4.74k| __m128i repack = _mm_setr_epi8(9, 10, 11, -1, 12, 13, 14, -1, 0, 0, 0, 0, 0, 0, 0, 0); 618| 4.74k| __m128i state = _mm_setzero_si128(); 619| |#elif defined(SIMD_NEON) 620| | uint8x8_t repack = vcreate_u8(0xff0e0d0cff0b0a09ull); 621| | uint8x16_t state = vdupq_n_u8(0); 622| |#endif 623| | 624| 4.74k| size_t groups = triangle_count / 2; 625| | 626| | // process all complete groups 627| 210k| for (size_t i = 0; i < groups; ++i) ------------------ | Branch (627:21): [True: 205k, False: 4.54k] ------------------ 628| 205k| { 629| 205k| unsigned char code = *codes++; 630| | 631| 205k| if (extra > bound) ------------------ | Branch (631:7): [True: 198, False: 205k] ------------------ 632| 198| return NULL; 633| | 634| 205k| state = decodeTriangleGroup(state, code, extra); 635| | 636| | // write 6 bytes of new triangle data into output, formatted as 8 bytes with 0 padding 637| 205k|#if defined(SIMD_SSE) 638| 205k| __m128i r = _mm_shuffle_epi8(state, repack); 639| 205k| _mm_storel_epi64(reinterpret_cast<__m128i*>(&triangles[i * 2]), r); 640| |#elif defined(SIMD_NEON) 641| | uint32x2_t r = vreinterpret_u32_u8(vqtbl1_u8(state, repack)); 642| | vst1_u32(&triangles[i * 2], r); 643| |#endif 644| 205k| } 645| | 646| | // process a 1 triangle tail; to maintain the memory safety guarantee we have to write a 32-bit element 647| 4.54k| if (triangle_count & 1) ------------------ | Branch (647:6): [True: 1.68k, False: 2.85k] ------------------ 648| 1.68k| { 649| 1.68k| unsigned char code = *codes++; 650| | 651| 1.68k| if (extra > bound) ------------------ | Branch (651:7): [True: 30, False: 1.65k] ------------------ 652| 30| return NULL; 653| | 654| 1.65k| state = decodeTriangleGroup(state, code, extra); 655| | 656| 1.65k| unsigned int* tail = &triangles[triangle_count & ~1u]; 657| | 658| 1.65k|#if defined(SIMD_SSE) 659| 1.65k| __m128i r = _mm_shuffle_epi8(state, repack); 660| 1.65k| *tail = unsigned(_mm_cvtsi128_si32(r)); 661| |#elif defined(SIMD_NEON) 662| | uint32x2_t r = vreinterpret_u32_u8(vqtbl1_u8(state, repack)); 663| | vst1_lane_u32(tail, r, 0); 664| |#endif 665| 1.65k| } 666| | 667| 4.51k| return extra; 668| 4.54k|} _ZN7meshopt19decodeTriangleGroupEDv2_xhRPKh: 524| 379k|{ 525| 379k| __m128i shuf = _mm_loadu_si128(reinterpret_cast(kDecodeTableMasks[code])); 526| 379k| __m128i next = _mm_slli_si128(shuf, 10); 527| | 528| | // patch first 6 bytes with current extra and roll state forward 529| 379k| __m128i ext = _mm_loadl_epi64(reinterpret_cast(extra)); 530| 379k| state = _mm_blend_epi16(state, ext, 7); 531| 379k| state = _mm_add_epi8(_mm_shuffle_epi8(state, shuf), next); 532| | 533| 379k| extra += kDecodeTableExtra[code]; 534| | 535| 379k| return state; 536| 379k|} meshletcodec.cpp:_ZN7meshoptL19decodeTrianglesSimdEPhPKhS2_S2_m: 672| 8.22k|{ 673| 8.22k|#if defined(SIMD_SSE) 674| 8.22k| __m128i state = _mm_setzero_si128(); 675| |#elif defined(SIMD_NEON) 676| | uint8x16_t state = vdupq_n_u8(0); 677| |#endif 678| | 679| | // because the output buffer is guaranteed to have 32-bit aligned size available, we can optimize writes and tail processing 680| | // instead of processing triangles 2 at a time, we process 2 *pairs* at a time (12-byte write) followed by a tail pair, if present 681| | // if the number of triangles mod 4 is 3, we'd normally need to write 12k+9 bytes, but we can instead overwrite up to 3 bytes in the main loop 682| 8.22k| size_t groups = (triangle_count + 1) / 4; 683| | 684| | // process all complete groups 685| 91.1k| for (size_t i = 0; i < groups; ++i) ------------------ | Branch (685:21): [True: 83.0k, False: 8.12k] ------------------ 686| 83.0k| { 687| 83.0k| unsigned char code0 = *codes++; 688| 83.0k| unsigned char code1 = *codes++; 689| | 690| | // each triangle pair reads <=6 bytes from extra, so two pairs need <=12 bytes and gap guarantees 16 byte of overread 691| 83.0k| if (extra > bound) ------------------ | Branch (691:7): [True: 100, False: 82.9k] ------------------ 692| 100| return NULL; 693| | 694| 82.9k| state = decodeTriangleGroup(state, code0, extra); 695| | 696| | // write first decoded triangle and first index of second decoded triangle 697| 82.9k|#if defined(SIMD_SSE) 698| 82.9k| __m128i r0 = _mm_srli_si128(state, 9); 699| 82.9k| *reinterpret_cast(&triangles[i * 12]) = _mm_cvtsi128_si32(r0); 700| |#elif defined(SIMD_NEON) 701| | uint8x16_t r0 = vextq_u8(state, vdupq_n_u8(0), 9); 702| | vst1q_lane_u32(reinterpret_cast(&triangles[i * 12]), vreinterpretq_u32_u8(r0), 0); 703| |#endif 704| | 705| 82.9k| state = decodeTriangleGroup(state, code1, extra); 706| | 707| | // write last two indices of second decoded triangle that we didn't write above plus two new ones 708| | // note that the second decoded triangle has shifted down to 6-8 bytes, hence shift by 7 709| 82.9k|#if defined(SIMD_SSE) 710| 82.9k| __m128i r1 = _mm_srli_si128(state, 7); 711| 82.9k| _mm_storel_epi64(reinterpret_cast<__m128i*>(&triangles[i * 12 + 4]), r1); 712| |#elif defined(SIMD_NEON) 713| | uint8x16_t r1 = vextq_u8(state, vdupq_n_u8(0), 7); 714| | vst1_u8(&triangles[i * 12 + 4], vget_low_u8(r1)); 715| |#endif 716| 82.9k| } 717| | 718| | // process a 1-2 triangle tail; to maintain the memory safety guarantee we have to write 1-2 32-bit elements 719| 8.12k| if (groups * 4 < triangle_count) ------------------ | Branch (719:6): [True: 6.47k, False: 1.65k] ------------------ 720| 6.47k| { 721| 6.47k| unsigned char code = *codes++; 722| | 723| 6.47k| if (extra > bound) ------------------ | Branch (723:7): [True: 38, False: 6.43k] ------------------ 724| 38| return NULL; 725| | 726| 6.43k| state = decodeTriangleGroup(state, code, extra); 727| | 728| 6.43k| unsigned char* tail = &triangles[(triangle_count & ~3u) * 3]; 729| | 730| 6.43k|#if defined(SIMD_SSE) 731| 6.43k| __m128i r = _mm_srli_si128(state, 9); 732| | 733| 6.43k| *reinterpret_cast(tail) = _mm_cvtsi128_si32(r); 734| 6.43k| if ((triangle_count & 3) > 1) ------------------ | Branch (734:7): [True: 856, False: 5.57k] ------------------ 735| 856| *reinterpret_cast(tail + 4) = _mm_extract_epi32(r, 1); 736| |#elif defined(SIMD_NEON) 737| | uint8x16_t r = vextq_u8(state, vdupq_n_u8(0), 9); 738| | 739| | vst1q_lane_u32(reinterpret_cast(tail), vreinterpretq_u32_u8(r), 0); 740| | if ((triangle_count & 3) > 1) 741| | vst1q_lane_u32(reinterpret_cast(tail + 4), vreinterpretq_u32_u8(r), 1); 742| |#endif 743| 6.43k| } 744| | 745| 8.08k| return extra; 746| 8.12k|} meshletcodec.cpp:_ZN7meshoptL17decodeMeshletSimdILi1EEEiPvS1_PKhS3_S3_S3_mmmm: 865| 1.08k|{ 866| 1.08k| assert(gDecodeTablesInitialized); ------------------ | Branch (866:2): [True: 1.08k, False: 0] ------------------ 867| 1.08k| (void)gDecodeTablesInitialized; 868| | 869| 1.08k|#ifdef __clang__ 870| | // data is guaranteed to be non-null initially; if decode loops never hit bounds errors, it remains non-null 871| 1.08k| __builtin_assume(data); 872| 1.08k|#endif 873| | 874| | // decodes 4 vertices at a time with tail processing; writes up to align(vertex_size * vertex_count, 4) 875| | // raw decoding skips tail processing by rounding up vertex count; it's safe because output buffer is guaranteed to have extra space, and tail control data is 0 876| 1.08k| if (vertex_size == 4 || Raw) ------------------ | Branch (876:6): [True: 1.08k, False: 0] | Branch (876:26): [True: 0, Folded] ------------------ 877| 1.08k| data = decodeVerticesSimd(static_cast(vertices), ctrl, data, bound, Raw ? (vertex_count + 3) & ~3 : vertex_count); ------------------ | Branch (877:86): [True: 1.08k, Folded] ------------------ 878| 0| else 879| 0| data = decodeVerticesSimd(static_cast(vertices), ctrl, data, bound, vertex_count); 880| 1.08k| if (!data) ------------------ | Branch (880:6): [True: 222, False: 858] ------------------ 881| 222| return -2; 882| | 883| | // decodes 2/4 triangles at a time with tail processing; writes up to align(triangle_size * triangle_count, 4) 884| | // raw decoding skips tail processing by rounding up triangle count; it's safe because output buffer is guaranteed to have extra space, and tail code data is 0 885| 858| if (triangle_size == 4 || Raw) ------------------ | Branch (885:6): [True: 858, False: 0] | Branch (885:28): [True: 0, Folded] ------------------ 886| 858| data = decodeTrianglesSimd(static_cast(triangles), codes, data, bound, Raw ? (triangle_count + 1) & ~1 : triangle_count); ------------------ | Branch (886:89): [True: 858, Folded] ------------------ 887| 0| else 888| 0| data = decodeTrianglesSimd(static_cast(triangles), codes, data, bound, triangle_count); 889| 858| if (!data) ------------------ | Branch (889:6): [True: 76, False: 782] ------------------ 890| 76| return -2; 891| | 892| 782| return (data == bound) ? 0 : -3; ------------------ | Branch (892:9): [True: 17, False: 765] ------------------ 893| 858|} _Z21meshopt_decodeMeshletIjjEiPT_mPT0_mPKhm: 1502| 2.16k|{ 1503| 2.16k| char types_valid[(sizeof(V) == 2 || sizeof(V) == 4) && (sizeof(T) == 1 || sizeof(T) == 4) ? 1 : -1]; 1504| 2.16k| (void)types_valid; 1505| | 1506| 2.16k| return meshopt_decodeMeshlet(vertices, vertex_count, sizeof(V), triangles, triangle_count, sizeof(T) == 1 ? 3 : 4, buffer, buffer_size); ------------------ | Branch (1506:93): [Folded, False: 2.16k] ------------------ 1507| 2.16k|} _Z21meshopt_decodeMeshletIjhEiPT_mPT0_mPKhm: 1502| 4.33k|{ 1503| 4.33k| char types_valid[(sizeof(V) == 2 || sizeof(V) == 4) && (sizeof(T) == 1 || sizeof(T) == 4) ? 1 : -1]; 1504| 4.33k| (void)types_valid; 1505| | 1506| 4.33k| return meshopt_decodeMeshlet(vertices, vertex_count, sizeof(V), triangles, triangle_count, sizeof(T) == 1 ? 3 : 4, buffer, buffer_size); ------------------ | Branch (1506:93): [True: 4.33k, Folded] ------------------ 1507| 4.33k|} _Z21meshopt_decodeMeshletIthEiPT_mPT0_mPKhm: 1502| 2.16k|{ 1503| 2.16k| char types_valid[(sizeof(V) == 2 || sizeof(V) == 4) && (sizeof(T) == 1 || sizeof(T) == 4) ? 1 : -1]; 1504| 2.16k| (void)types_valid; 1505| | 1506| 2.16k| return meshopt_decodeMeshlet(vertices, vertex_count, sizeof(V), triangles, triangle_count, sizeof(T) == 1 ? 3 : 4, buffer, buffer_size); ------------------ | Branch (1506:93): [True: 2.16k, Folded] ------------------ 1507| 2.16k|} meshopt_encodeVertexBufferLevel: 1616| 17.3k|{ 1617| 17.3k| using namespace meshopt; 1618| | 1619| 17.3k| assert(vertex_size > 0 && vertex_size <= 256); ------------------ | Branch (1619:2): [True: 17.3k, False: 0] | Branch (1619:2): [True: 17.3k, False: 0] | Branch (1619:2): [True: 17.3k, False: 0] ------------------ 1620| 17.3k| assert(vertex_size % 4 == 0); ------------------ | Branch (1620:2): [True: 17.3k, False: 0] ------------------ 1621| 17.3k| assert(level >= 0 && level <= 9); // only a subset of this range is used right now ------------------ | Branch (1621:2): [True: 17.3k, False: 0] | Branch (1621:2): [True: 17.3k, False: 0] | Branch (1621:2): [True: 17.3k, False: 0] ------------------ 1622| 17.3k| assert(version < 0 || unsigned(version) <= kDecodeVertexVersion); ------------------ | Branch (1622:2): [True: 17.3k, False: 0] | Branch (1622:2): [True: 0, False: 0] | Branch (1622:2): [True: 17.3k, False: 0] ------------------ 1623| | 1624| 17.3k| version = version < 0 ? gEncodeVertexVersion : version; ------------------ | Branch (1624:12): [True: 17.3k, False: 0] ------------------ 1625| | 1626| |#if TRACE 1627| | memset(vertexstats, 0, sizeof(vertexstats)); 1628| |#endif 1629| | 1630| 17.3k| const unsigned char* vertex_data = static_cast(vertices); 1631| | 1632| 17.3k| unsigned char* data = buffer; 1633| 17.3k| unsigned char* data_end = buffer + buffer_size; 1634| | 1635| 17.3k| if (size_t(data_end - data) < 1) ------------------ | Branch (1635:6): [True: 0, False: 17.3k] ------------------ 1636| 0| return 0; 1637| | 1638| 17.3k| *data++ = (unsigned char)(kVertexHeader | version); 1639| | 1640| 17.3k| unsigned char first_vertex[256] = {}; 1641| 17.3k| if (vertex_count > 0) ------------------ | Branch (1641:6): [True: 13.4k, False: 3.95k] ------------------ 1642| 13.4k| memcpy(first_vertex, vertex_data, vertex_size); 1643| | 1644| 17.3k| unsigned char last_vertex[256] = {}; 1645| 17.3k| memcpy(last_vertex, first_vertex, vertex_size); 1646| | 1647| 17.3k| size_t vertex_block_size = getVertexBlockSize(vertex_size); 1648| | 1649| 17.3k| unsigned char channels[64] = {}; 1650| 17.3k| if (version != 0 && level > 1 && vertex_count > 1) ------------------ | Branch (1650:6): [True: 13.7k, False: 3.58k] | Branch (1650:22): [True: 7.00k, False: 6.76k] | Branch (1650:35): [True: 4.69k, False: 2.30k] ------------------ 1651| 24.4k| for (size_t k = 0; k < vertex_size; k += 4) ------------------ | Branch (1651:22): [True: 19.7k, False: 4.69k] ------------------ 1652| 19.7k| { 1653| 19.7k| int rot = level >= 3 ? estimateRotate(vertex_data, vertex_count, vertex_size, k, /* group_size= */ 16) : 0; ------------------ | Branch (1653:14): [True: 16.2k, False: 3.50k] ------------------ 1654| 19.7k| int channel = estimateChannel(vertex_data, vertex_count, vertex_size, k, vertex_block_size, /* block_skip= */ 3, /* max_channel= */ level >= 3 ? 3 : 2, rot); ------------------ | Branch (1654:136): [True: 16.2k, False: 3.50k] ------------------ 1655| | 1656| 19.7k| assert(unsigned(channel) < 2 || ((channel & 3) == 2 && unsigned(channel >> 4) < 8)); ------------------ | Branch (1656:4): [True: 2.47k, False: 0] | Branch (1656:4): [True: 2.47k, False: 0] | Branch (1656:4): [True: 17.2k, False: 2.47k] | Branch (1656:4): [True: 19.7k, False: 0] ------------------ 1657| 19.7k| channels[k / 4] = (unsigned char)channel; 1658| 19.7k| } 1659| | 1660| 17.3k| size_t vertex_offset = 0; 1661| | 1662| 374k| while (vertex_offset < vertex_count) ------------------ | Branch (1662:9): [True: 356k, False: 17.3k] ------------------ 1663| 356k| { 1664| 356k| size_t block_size = (vertex_offset + vertex_block_size < vertex_count) ? vertex_block_size : vertex_count - vertex_offset; ------------------ | Branch (1664:23): [True: 343k, False: 13.4k] ------------------ 1665| | 1666| 356k| data = encodeVertexBlock(data, data_end, vertex_data + vertex_offset * vertex_size, block_size, vertex_size, last_vertex, channels, version, level); 1667| 356k| if (!data) ------------------ | Branch (1667:7): [True: 0, False: 356k] ------------------ 1668| 0| return 0; 1669| | 1670| 356k| vertex_offset += block_size; 1671| 356k| } 1672| | 1673| 17.3k| size_t tail_size = vertex_size + (version == 0 ? 0 : vertex_size / 4); ------------------ | Branch (1673:36): [True: 3.58k, False: 13.7k] ------------------ 1674| 17.3k| size_t tail_size_min = version == 0 ? kTailMinSizeV0 : kTailMinSizeV1; ------------------ | Branch (1674:25): [True: 3.58k, False: 13.7k] ------------------ 1675| 17.3k| size_t tail_size_pad = tail_size < tail_size_min ? tail_size_min : tail_size; ------------------ | Branch (1675:25): [True: 9.57k, False: 7.78k] ------------------ 1676| | 1677| 17.3k| if (size_t(data_end - data) < tail_size_pad) ------------------ | Branch (1677:6): [True: 0, False: 17.3k] ------------------ 1678| 0| return 0; 1679| | 1680| 17.3k| if (tail_size < tail_size_pad) ------------------ | Branch (1680:6): [True: 9.57k, False: 7.78k] ------------------ 1681| 9.57k| { 1682| 9.57k| memset(data, 0, tail_size_pad - tail_size); 1683| 9.57k| data += tail_size_pad - tail_size; 1684| 9.57k| } 1685| | 1686| 17.3k| memcpy(data, first_vertex, vertex_size); 1687| 17.3k| data += vertex_size; 1688| | 1689| 17.3k| if (version != 0) ------------------ | Branch (1689:6): [True: 13.7k, False: 3.58k] ------------------ 1690| 13.7k| { 1691| 13.7k| memcpy(data, channels, vertex_size / 4); 1692| 13.7k| data += vertex_size / 4; 1693| 13.7k| } 1694| | 1695| 17.3k| assert(data >= buffer + tail_size); ------------------ | Branch (1695:2): [True: 17.3k, False: 0] ------------------ 1696| 17.3k| assert(data <= buffer + buffer_size); ------------------ | Branch (1696:2): [True: 17.3k, False: 0] ------------------ 1697| | 1698| |#if TRACE 1699| | size_t total_size = data - buffer; 1700| | 1701| | for (size_t k = 0; k < vertex_size; ++k) 1702| | { 1703| | const Stats& vsk = vertexstats[k]; 1704| | 1705| | printf("%2d: %7d bytes [%4.1f%%] %.1f bpv", int(k), int(vsk.size), double(vsk.size) / double(total_size) * 100, double(vsk.size) / double(vertex_count) * 8); 1706| | 1707| | size_t total_k = vsk.header + vsk.bitg[1] + vsk.bitg[2] + vsk.bitg[4] + vsk.bitg[8]; 1708| | double total_kr = total_k ? 1.0 / double(total_k) : 0; 1709| | 1710| | if (version != 0) 1711| | { 1712| | int channel = channels[k / 4]; 1713| | 1714| | if ((channel & 3) == 2 && k % 4 == 0) 1715| | printf(" | ^%d", channel >> 4); 1716| | else 1717| | printf(" | %2s", channel == 0 ? "1" : (channel == 1 && k % 2 == 0 ? "2" : ".")); 1718| | } 1719| | 1720| | printf(" | hdr [%5.1f%%] bitg [1 %4.1f%% 2 %4.1f%% 4 %4.1f%% 8 %4.1f%%]", 1721| | double(vsk.header) * total_kr * 100, 1722| | double(vsk.bitg[1]) * total_kr * 100, double(vsk.bitg[2]) * total_kr * 100, 1723| | double(vsk.bitg[4]) * total_kr * 100, double(vsk.bitg[8]) * total_kr * 100); 1724| | 1725| | size_t total_ctrl = vsk.ctrl[0] + vsk.ctrl[1] + vsk.ctrl[2] + vsk.ctrl[3]; 1726| | 1727| | if (total_ctrl) 1728| | { 1729| | printf(" | ctrl %3.0f%% %3.0f%% %3.0f%% %3.0f%%", 1730| | double(vsk.ctrl[0]) / double(total_ctrl) * 100, double(vsk.ctrl[1]) / double(total_ctrl) * 100, 1731| | double(vsk.ctrl[2]) / double(total_ctrl) * 100, double(vsk.ctrl[3]) / double(total_ctrl) * 100); 1732| | } 1733| | 1734| | if (level >= 3) 1735| | printf(" | bitc [%3.0f%% %3.0f%% %3.0f%% %3.0f%% %3.0f%% %3.0f%% %3.0f%% %3.0f%%]", 1736| | double(vsk.bitc[0]) / double(vertex_count) * 100, double(vsk.bitc[1]) / double(vertex_count) * 100, 1737| | double(vsk.bitc[2]) / double(vertex_count) * 100, double(vsk.bitc[3]) / double(vertex_count) * 100, 1738| | double(vsk.bitc[4]) / double(vertex_count) * 100, double(vsk.bitc[5]) / double(vertex_count) * 100, 1739| | double(vsk.bitc[6]) / double(vertex_count) * 100, double(vsk.bitc[7]) / double(vertex_count) * 100); 1740| | 1741| | printf("\n"); 1742| | } 1743| |#endif 1744| | 1745| 17.3k| return data - buffer; 1746| 17.3k|} meshopt_encodeVertexBufferBound: 1754| 8.67k|{ 1755| 8.67k| using namespace meshopt; 1756| | 1757| 8.67k| assert(vertex_size > 0 && vertex_size <= 256); ------------------ | Branch (1757:2): [True: 8.67k, False: 0] | Branch (1757:2): [True: 8.67k, False: 0] | Branch (1757:2): [True: 8.67k, False: 0] ------------------ 1758| 8.67k| assert(vertex_size % 4 == 0); ------------------ | Branch (1758:2): [True: 8.67k, False: 0] ------------------ 1759| | 1760| 8.67k| size_t vertex_block_size = getVertexBlockSize(vertex_size); 1761| 8.67k| size_t vertex_block_count = (vertex_count + vertex_block_size - 1) / vertex_block_size; 1762| | 1763| 8.67k| size_t vertex_block_control_size = vertex_size / 4; 1764| 8.67k| size_t vertex_block_header_size = (vertex_block_size / kByteGroupSize + 3) / 4; 1765| 8.67k| size_t vertex_block_data_size = vertex_block_size; 1766| | 1767| 8.67k| size_t tail_size = vertex_size + (vertex_size / 4); 1768| 8.67k| size_t tail_size_min = kTailMinSizeV0 > kTailMinSizeV1 ? kTailMinSizeV0 : kTailMinSizeV1; ------------------ | Branch (1768:25): [True: 8.67k, Folded] ------------------ 1769| 8.67k| size_t tail_size_pad = tail_size < tail_size_min ? tail_size_min : tail_size; ------------------ | Branch (1769:25): [True: 6.50k, False: 2.16k] ------------------ 1770| 8.67k| assert(tail_size_pad >= kByteGroupDecodeLimit); ------------------ | Branch (1770:2): [True: 8.67k, False: 0] ------------------ 1771| | 1772| 8.67k| return 1 + vertex_block_count * vertex_size * (vertex_block_control_size + vertex_block_header_size + vertex_block_data_size) + tail_size_pad; 1773| 8.67k|} meshopt_encodeVertexVersion: 1776| 2.16k|{ 1777| 2.16k| assert(unsigned(version) <= unsigned(meshopt::kDecodeVertexVersion)); ------------------ | Branch (1777:2): [True: 2.16k, False: 0] ------------------ 1778| | 1779| 2.16k| meshopt::gEncodeVertexVersion = version; 1780| 2.16k|} meshopt_decodeVertexBuffer: 1800| 17.3k|{ 1801| 17.3k| using namespace meshopt; 1802| | 1803| 17.3k| assert(vertex_size > 0 && vertex_size <= 256); ------------------ | Branch (1803:2): [True: 17.3k, False: 0] | Branch (1803:2): [True: 17.3k, False: 0] | Branch (1803:2): [True: 17.3k, False: 0] ------------------ 1804| 17.3k| assert(vertex_size % 4 == 0); ------------------ | Branch (1804:2): [True: 17.3k, False: 0] ------------------ 1805| | 1806| 17.3k| const unsigned char* (*decode)(const unsigned char*, const unsigned char*, unsigned char*, size_t, size_t, unsigned char[256], const unsigned char*, int) = NULL; 1807| | 1808| 17.3k|#if defined(SIMD_SSE) && defined(SIMD_FALLBACK) 1809| 17.3k| const unsigned int cpumask = (1 << 9) | (1 << 23); // SSSE3+POPCNT 1810| 17.3k| decode = (cpuid & cpumask) == cpumask ? decodeVertexBlockSimd : decodeVertexBlock; ------------------ | Branch (1810:11): [True: 17.3k, False: 0] ------------------ 1811| |#elif defined(SIMD_SSE) || defined(SIMD_AVX) || defined(SIMD_NEON) || defined(SIMD_WASM) 1812| | decode = decodeVertexBlockSimd; 1813| |#else 1814| | decode = decodeVertexBlock; 1815| |#endif 1816| | 1817| 17.3k|#if defined(SIMD_SSE) || defined(SIMD_NEON) || defined(SIMD_WASM) 1818| 17.3k| assert(gDecodeBytesGroupInitialized); ------------------ | Branch (1818:2): [True: 17.3k, False: 0] ------------------ 1819| 17.3k| (void)gDecodeBytesGroupInitialized; 1820| 17.3k|#endif 1821| | 1822| 17.3k| unsigned char* vertex_data = static_cast(destination); 1823| | 1824| 17.3k| const unsigned char* data = buffer; 1825| 17.3k| const unsigned char* data_end = buffer + buffer_size; 1826| | 1827| 17.3k| if (size_t(data_end - data) < 1) ------------------ | Branch (1827:6): [True: 0, False: 17.3k] ------------------ 1828| 0| return -2; 1829| | 1830| 17.3k| unsigned char data_header = *data++; 1831| | 1832| 17.3k| if ((data_header & 0xf0) != kVertexHeader) ------------------ | Branch (1832:6): [True: 7.38k, False: 9.96k] ------------------ 1833| 7.38k| return -1; 1834| | 1835| 9.96k| int version = data_header & 0x0f; 1836| 9.96k| if (version > kDecodeVertexVersion) ------------------ | Branch (1836:6): [True: 148, False: 9.82k] ------------------ 1837| 148| return -1; 1838| | 1839| 9.82k| size_t tail_size = vertex_size + (version == 0 ? 0 : vertex_size / 4); ------------------ | Branch (1839:36): [True: 2.11k, False: 7.70k] ------------------ 1840| 9.82k| size_t tail_size_min = version == 0 ? kTailMinSizeV0 : kTailMinSizeV1; ------------------ | Branch (1840:25): [True: 2.11k, False: 7.70k] ------------------ 1841| 9.82k| size_t tail_size_pad = tail_size < tail_size_min ? tail_size_min : tail_size; ------------------ | Branch (1841:25): [True: 5.43k, False: 4.38k] ------------------ 1842| | 1843| 9.82k| if (size_t(data_end - data) < tail_size_pad) ------------------ | Branch (1843:6): [True: 203, False: 9.61k] ------------------ 1844| 203| return -2; 1845| | 1846| 9.61k| const unsigned char* tail = data_end - tail_size; 1847| | 1848| 9.61k| unsigned char last_vertex[256]; 1849| 9.61k| memcpy(last_vertex, tail, vertex_size); 1850| | 1851| 9.61k| const unsigned char* channels = version == 0 ? NULL : tail + vertex_size; ------------------ | Branch (1851:34): [True: 2.07k, False: 7.54k] ------------------ 1852| | 1853| 9.61k| size_t vertex_block_size = getVertexBlockSize(vertex_size); 1854| | 1855| 9.61k| size_t vertex_offset = 0; 1856| | 1857| 188k| while (vertex_offset < vertex_count) ------------------ | Branch (1857:9): [True: 179k, False: 9.15k] ------------------ 1858| 179k| { 1859| 179k| size_t block_size = (vertex_offset + vertex_block_size < vertex_count) ? vertex_block_size : vertex_count - vertex_offset; ------------------ | Branch (1859:23): [True: 171k, False: 7.64k] ------------------ 1860| | 1861| 179k| data = decode(data, data_end, vertex_data + vertex_offset * vertex_size, block_size, vertex_size, last_vertex, channels, version); 1862| 179k| if (!data) ------------------ | Branch (1862:7): [True: 464, False: 178k] ------------------ 1863| 464| return -2; 1864| | 1865| 178k| vertex_offset += block_size; 1866| 178k| } 1867| | 1868| 9.15k| if (size_t(data_end - data) != tail_size_pad) ------------------ | Branch (1868:6): [True: 476, False: 8.67k] ------------------ 1869| 476| return -3; 1870| | 1871| 8.67k| return 0; 1872| 9.15k|} vertexcodec.cpp:_ZN7meshoptL27decodeBytesGroupBuildTablesEv: 792| 2|{ 793| 514| for (int mask = 0; mask < 256; ++mask) ------------------ | Branch (793:21): [True: 512, False: 2] ------------------ 794| 512| { 795| 512| unsigned char shuffle[8]; 796| 512| unsigned char count = 0; 797| | 798| 4.60k| for (int i = 0; i < 8; ++i) ------------------ | Branch (798:19): [True: 4.09k, False: 512] ------------------ 799| 4.09k| { 800| 4.09k| int maski = (mask >> i) & 1; 801| 4.09k| shuffle[i] = maski ? count : 0x80; ------------------ | Branch (801:17): [True: 2.04k, False: 2.04k] ------------------ 802| 4.09k| count += (unsigned char)(maski); 803| 4.09k| } 804| | 805| 512| memcpy(kDecodeBytesGroupShuffle[mask], shuffle, 8); 806| 512| kDecodeBytesGroupCount[mask] = count; 807| 512| } 808| | 809| 2| return true; 810| 2|} vertexcodec.cpp:_ZN7meshoptL14getCpuFeaturesEv: 1600| 2|{ 1601| 2| int cpuinfo[4] = {}; 1602| |#ifdef _MSC_VER 1603| | __cpuid(cpuinfo, 1); 1604| |#else 1605| | __cpuid(1, cpuinfo[0], cpuinfo[1], cpuinfo[2], cpuinfo[3]); 1606| 2|#endif 1607| 2| return cpuinfo[2]; 1608| 2|} vertexcodec.cpp:_ZN7meshoptL18getVertexBlockSizeEm: 141| 35.6k|{ 142| | // make sure the entire block fits into the scratch buffer and is aligned to byte group size 143| | // note: the block size is implicitly part of the format, so we can't change it without breaking compatibility 144| 35.6k| size_t result = (kVertexBlockSizeBytes / vertex_size) & ~(kByteGroupSize - 1); 145| | 146| 35.6k| return (result < kVertexBlockMaxSize) ? result : kVertexBlockMaxSize; ------------------ | Branch (146:9): [True: 0, False: 35.6k] ------------------ 147| 35.6k|} vertexcodec.cpp:_ZN7meshoptL14estimateRotateEPKhmmmm: 370| 16.2k|{ 371| 16.2k| size_t sizes[8] = {}; 372| | 373| 16.2k| const unsigned char* vertex = vertex_data + k; 374| 16.2k| unsigned int last = vertex[0] | (vertex[1] << 8) | (vertex[2] << 16) | (vertex[3] << 24); 375| | 376| 4.81M| for (size_t i = 0; i < vertex_count; i += group_size) ------------------ | Branch (376:21): [True: 4.79M, False: 16.2k] ------------------ 377| 4.79M| { 378| 4.79M| unsigned int bitg = 0; 379| | 380| | // calculate bit consistency mask for the group 381| 81.3M| for (size_t j = 0; j < group_size && i + j < vertex_count; ++j) ------------------ | Branch (381:22): [True: 76.6M, False: 4.78M] | Branch (381:40): [True: 76.5M, False: 14.2k] ------------------ 382| 76.5M| { 383| 76.5M| unsigned int v = vertex[0] | (vertex[1] << 8) | (vertex[2] << 16) | (vertex[3] << 24); 384| 76.5M| unsigned int d = v ^ last; 385| | 386| 76.5M| bitg |= d; 387| 76.5M| last = v; 388| 76.5M| vertex += vertex_size; 389| 76.5M| } 390| | 391| |#if TRACE 392| | for (int j = 0; j < 32; ++j) 393| | vertexstats[k + (j / 8)].bitc[j % 8] += (i + group_size < vertex_count ? group_size : vertex_count - i) * (1 - ((bitg >> j) & 1)); 394| |#endif 395| | 396| 43.1M| for (int j = 0; j < 8; ++j) ------------------ | Branch (396:19): [True: 38.3M, False: 4.79M] ------------------ 397| 38.3M| { 398| 38.3M| unsigned int bitr = rotate(bitg, j); 399| | 400| 38.3M| sizes[j] += estimateBits((unsigned char)(bitr >> 0)) + estimateBits((unsigned char)(bitr >> 8)); 401| 38.3M| sizes[j] += estimateBits((unsigned char)(bitr >> 16)) + estimateBits((unsigned char)(bitr >> 24)); 402| 38.3M| } 403| 4.79M| } 404| | 405| 16.2k| int best_rot = 0; 406| 129k| for (int rot = 1; rot < 8; ++rot) ------------------ | Branch (406:20): [True: 113k, False: 16.2k] ------------------ 407| 113k| best_rot = (sizes[rot] < sizes[best_rot]) ? rot : best_rot; ------------------ | Branch (407:14): [True: 7.00k, False: 106k] ------------------ 408| | 409| 16.2k| return best_rot; 410| 16.2k|} _ZN7meshopt6rotateEji: 150| 187M|{ 151| 187M| return (v << r) | (v >> ((32 - r) & 31)); 152| 187M|} vertexcodec.cpp:_ZN7meshoptL12estimateBitsEh: 365| 153M|{ 366| 153M| return v <= 15 ? (v <= 3 ? (v == 0 ? 0 : 2) : 4) : 8; ------------------ | Branch (366:9): [True: 62.4M, False: 90.9M] | Branch (366:20): [True: 60.5M, False: 1.90M] | Branch (366:30): [True: 58.8M, False: 1.70M] ------------------ 367| 153M|} vertexcodec.cpp:_ZN7meshoptL15estimateChannelEPKhmmmmmii: 413| 19.7k|{ 414| 19.7k| unsigned char block[kVertexBlockMaxSize]; 415| 19.7k| assert(vertex_block_size <= kVertexBlockMaxSize); ------------------ | Branch (415:2): [True: 19.7k, False: 0] ------------------ 416| | 417| 19.7k| unsigned char last_vertex[256] = {}; 418| | 419| 19.7k| size_t sizes[3] = {}; 420| 19.7k| assert(max_channel <= 3); ------------------ | Branch (420:2): [True: 19.7k, False: 0] ------------------ 421| | 422| 182k| for (size_t i = 0; i < vertex_count; i += vertex_block_size * block_skip) ------------------ | Branch (422:21): [True: 163k, False: 19.7k] ------------------ 423| 163k| { 424| 163k| size_t block_size = i + vertex_block_size < vertex_count ? vertex_block_size : vertex_count - i; ------------------ | Branch (424:23): [True: 148k, False: 14.9k] ------------------ 425| 163k| size_t block_size_aligned = (block_size + kByteGroupSize - 1) & ~(kByteGroupSize - 1); 426| | 427| 163k| memcpy(last_vertex, vertex_data + (i == 0 ? 0 : i - 1) * vertex_size, vertex_size); ------------------ | Branch (427:38): [True: 19.7k, False: 143k] ------------------ 428| | 429| | // we sometimes encode elements we didn't fill when rounding to kByteGroupSize 430| 163k| if (block_size < block_size_aligned) ------------------ | Branch (430:7): [True: 13.3k, False: 149k] ------------------ 431| 13.3k| memset(block + block_size, 0, block_size_aligned - block_size); 432| | 433| 601k| for (int channel = 0; channel < max_channel; ++channel) ------------------ | Branch (433:25): [True: 438k, False: 163k] ------------------ 434| 2.19M| for (size_t j = 0; j < 4; ++j) ------------------ | Branch (434:23): [True: 1.75M, False: 438k] ------------------ 435| 1.75M| { 436| 1.75M| encodeDeltas(block, vertex_data + i * vertex_size, block_size, vertex_size, last_vertex, k + j, channel | (xor_rot << 4)); 437| | 438| 27.7M| for (size_t ig = 0; ig < block_size; ig += kByteGroupSize) ------------------ | Branch (438:25): [True: 26.0M, False: 1.75M] ------------------ 439| 26.0M| { 440| | // to maximize encoding performance we only evaluate 1/2/4/8 bit groups 441| 26.0M| size_t size1 = encodeBytesGroupMeasure(block + ig, 1); 442| 26.0M| size_t size2 = encodeBytesGroupMeasure(block + ig, 2); 443| 26.0M| size_t size4 = encodeBytesGroupMeasure(block + ig, 4); 444| 26.0M| size_t size8 = encodeBytesGroupMeasure(block + ig, 8); 445| | 446| 26.0M| size_t best_size = size1 < size2 ? size1 : size2; ------------------ | Branch (446:25): [True: 24.7M, False: 1.23M] ------------------ 447| 26.0M| best_size = best_size < size4 ? best_size : size4; ------------------ | Branch (447:18): [True: 25.9M, False: 57.7k] ------------------ 448| 26.0M| best_size = best_size < size8 ? best_size : size8; ------------------ | Branch (448:18): [True: 15.5M, False: 10.4M] ------------------ 449| | 450| 26.0M| sizes[channel] += best_size; 451| 26.0M| } 452| 1.75M| } 453| 163k| } 454| | 455| 19.7k| int best_channel = 0; 456| 55.7k| for (int channel = 1; channel < max_channel; ++channel) ------------------ | Branch (456:24): [True: 36.0k, False: 19.7k] ------------------ 457| 36.0k| best_channel = (sizes[channel] < sizes[best_channel]) ? channel : best_channel; ------------------ | Branch (457:18): [True: 5.58k, False: 30.4k] ------------------ 458| | 459| 19.7k| return best_channel == 2 ? best_channel | (xor_rot << 4) : best_channel; ------------------ | Branch (459:9): [True: 2.47k, False: 17.2k] ------------------ 460| 19.7k|} vertexcodec.cpp:_ZN7meshoptL12encodeDeltasEPhPKhmmS2_mi: 350| 5.53M|{ 351| 5.53M| switch (channel & 3) 352| 5.53M| { 353| 4.09M| case 0: ------------------ | Branch (353:2): [True: 4.09M, False: 1.44M] ------------------ 354| 4.09M| return encodeDeltas1(buffer, vertex_data, vertex_count, vertex_size, last_vertex, k, 0); 355| 817k| case 1: ------------------ | Branch (355:2): [True: 817k, False: 4.71M] ------------------ 356| 817k| return encodeDeltas1(buffer, vertex_data, vertex_count, vertex_size, last_vertex, k, 0); 357| 626k| case 2: ------------------ | Branch (357:2): [True: 626k, False: 4.90M] ------------------ 358| 626k| return encodeDeltas1(buffer, vertex_data, vertex_count, vertex_size, last_vertex, k, channel >> 4); 359| 0| default: ------------------ | Branch (359:2): [True: 0, False: 5.53M] ------------------ 360| | assert(!"Unsupported channel encoding"); // unreachable ------------------ | Branch (360:3): [Folded, False: 0] ------------------ 361| 5.53M| } 362| 5.53M|} vertexcodec.cpp:_ZN7meshoptL13encodeDeltas1IhLb0EEEvPhPKhmmS3_mi: 325| 4.09M|{ 326| 4.09M| size_t k0 = k & ~(sizeof(T) - 1); 327| 4.09M| int ks = (k & (sizeof(T) - 1)) * 8; 328| | 329| 4.09M| T p = last_vertex[k0]; 330| 4.09M| for (size_t j = 1; j < sizeof(T); ++j) ------------------ | Branch (330:21): [True: 0, False: 4.09M] ------------------ 331| 0| p |= T(last_vertex[k0 + j]) << (j * 8); 332| | 333| 4.09M| const unsigned char* vertex = vertex_data + k0; 334| | 335| 994M| for (size_t i = 0; i < vertex_count; ++i) ------------------ | Branch (335:21): [True: 990M, False: 4.09M] ------------------ 336| 990M| { 337| 990M| T v = vertex[0]; 338| 990M| for (size_t j = 1; j < sizeof(T); ++j) ------------------ | Branch (338:22): [True: 0, False: 990M] ------------------ 339| 0| v |= vertex[j] << (j * 8); 340| | 341| 990M| T d = Xor ? T(rotate(v ^ p, rot)) : zigzag(T(v - p)); ------------------ | Branch (341:9): [Folded, False: 990M] ------------------ 342| | 343| 990M| buffer[i] = (unsigned char)(d >> ks); 344| 990M| p = v; 345| 990M| vertex += vertex_size; 346| 990M| } 347| 4.09M|} _ZN7meshopt6zigzagIhEET_S1_: 156| 990M|{ 157| 990M| return (0 - (v >> (sizeof(T) * 8 - 1))) ^ (v << 1); 158| 990M|} vertexcodec.cpp:_ZN7meshoptL13encodeDeltas1ItLb0EEEvPhPKhmmS3_mi: 325| 817k|{ 326| 817k| size_t k0 = k & ~(sizeof(T) - 1); 327| 817k| int ks = (k & (sizeof(T) - 1)) * 8; 328| | 329| 817k| T p = last_vertex[k0]; 330| 1.63M| for (size_t j = 1; j < sizeof(T); ++j) ------------------ | Branch (330:21): [True: 817k, False: 817k] ------------------ 331| 817k| p |= T(last_vertex[k0 + j]) << (j * 8); 332| | 333| 817k| const unsigned char* vertex = vertex_data + k0; 334| | 335| 195M| for (size_t i = 0; i < vertex_count; ++i) ------------------ | Branch (335:21): [True: 194M, False: 817k] ------------------ 336| 194M| { 337| 194M| T v = vertex[0]; 338| 389M| for (size_t j = 1; j < sizeof(T); ++j) ------------------ | Branch (338:22): [True: 194M, False: 194M] ------------------ 339| 194M| v |= vertex[j] << (j * 8); 340| | 341| 194M| T d = Xor ? T(rotate(v ^ p, rot)) : zigzag(T(v - p)); ------------------ | Branch (341:9): [Folded, False: 194M] ------------------ 342| | 343| 194M| buffer[i] = (unsigned char)(d >> ks); 344| 194M| p = v; 345| 194M| vertex += vertex_size; 346| 194M| } 347| 817k|} _ZN7meshopt6zigzagItEET_S1_: 156| 194M|{ 157| 194M| return (0 - (v >> (sizeof(T) * 8 - 1))) ^ (v << 1); 158| 194M|} vertexcodec.cpp:_ZN7meshoptL13encodeDeltas1IjLb1EEEvPhPKhmmS3_mi: 325| 626k|{ 326| 626k| size_t k0 = k & ~(sizeof(T) - 1); 327| 626k| int ks = (k & (sizeof(T) - 1)) * 8; 328| | 329| 626k| T p = last_vertex[k0]; 330| 2.50M| for (size_t j = 1; j < sizeof(T); ++j) ------------------ | Branch (330:21): [True: 1.87M, False: 626k] ------------------ 331| 1.87M| p |= T(last_vertex[k0 + j]) << (j * 8); 332| | 333| 626k| const unsigned char* vertex = vertex_data + k0; 334| | 335| 149M| for (size_t i = 0; i < vertex_count; ++i) ------------------ | Branch (335:21): [True: 148M, False: 626k] ------------------ 336| 148M| { 337| 148M| T v = vertex[0]; 338| 595M| for (size_t j = 1; j < sizeof(T); ++j) ------------------ | Branch (338:22): [True: 446M, False: 148M] ------------------ 339| 446M| v |= vertex[j] << (j * 8); 340| | 341| 148M| T d = Xor ? T(rotate(v ^ p, rot)) : zigzag(T(v - p)); ------------------ | Branch (341:9): [True: 148M, Folded] ------------------ 342| | 343| 148M| buffer[i] = (unsigned char)(d >> ks); 344| 148M| p = v; 345| 148M| vertex += vertex_size; 346| 148M| } 347| 626k|} vertexcodec.cpp:_ZN7meshoptL23encodeBytesGroupMeasureEPKhi: 191| 293M|{ 192| 293M| assert(bits >= 0 && bits <= 8); ------------------ | Branch (192:2): [True: 293M, False: 0] | Branch (192:2): [True: 293M, False: 0] | Branch (192:2): [True: 293M, False: 0] ------------------ 193| | 194| 293M| if (bits == 0) ------------------ | Branch (194:6): [True: 27.7M, False: 265M] ------------------ 195| 27.7M| return encodeBytesGroupZero(buffer) ? 0 : size_t(-1); ------------------ | Branch (195:10): [True: 9.33M, False: 18.4M] ------------------ 196| | 197| 265M| if (bits == 8) ------------------ | Branch (197:6): [True: 64.1M, False: 201M] ------------------ 198| 64.1M| return kByteGroupSize; 199| | 200| 201M| size_t result = kByteGroupSize * bits / 8; 201| | 202| 201M| unsigned char sentinel = (1 << bits) - 1; 203| | 204| 3.42G| for (size_t i = 0; i < kByteGroupSize; ++i) ------------------ | Branch (204:21): [True: 3.22G, False: 201M] ------------------ 205| 3.22G| result += buffer[i] >= sentinel; 206| | 207| 201M| return result; 208| 265M|} vertexcodec.cpp:_ZN7meshoptL20encodeBytesGroupZeroEPKh: 181| 54.0M|{ 182| 54.0M| assert(kByteGroupSize == sizeof(unsigned long long) * 2); ------------------ | Branch (182:2): [True: 54.0M, Folded] ------------------ 183| | 184| 54.0M| unsigned long long v[2]; 185| 54.0M| memcpy(v, buffer, sizeof(v)); 186| | 187| 54.0M| return (v[0] | v[1]) == 0; 188| 54.0M|} vertexcodec.cpp:_ZN7meshoptL17encodeVertexBlockEPhS0_PKhmmS0_S2_ii: 510| 356k|{ 511| 356k| assert(vertex_count > 0 && vertex_count <= kVertexBlockMaxSize); ------------------ | Branch (511:2): [True: 356k, False: 0] | Branch (511:2): [True: 356k, False: 0] | Branch (511:2): [True: 356k, False: 0] ------------------ 512| 356k| assert(vertex_size % 4 == 0); ------------------ | Branch (512:2): [True: 356k, False: 0] ------------------ 513| | 514| 356k| unsigned char buffer[kVertexBlockMaxSize]; 515| 356k| assert(sizeof(buffer) % kByteGroupSize == 0); ------------------ | Branch (515:2): [True: 356k, Folded] ------------------ 516| | 517| 356k| size_t vertex_count_aligned = (vertex_count + kByteGroupSize - 1) & ~(kByteGroupSize - 1); 518| | 519| | // we sometimes encode elements we didn't fill when rounding to kByteGroupSize 520| 356k| memset(buffer, 0, sizeof(buffer)); 521| | 522| 356k| size_t control_size = version == 0 ? 0 : vertex_size / 4; ------------------ | Branch (522:24): [True: 28.0k, False: 328k] ------------------ 523| 356k| if (size_t(data_end - data) < control_size) ------------------ | Branch (523:6): [True: 0, False: 356k] ------------------ 524| 0| return NULL; 525| | 526| 356k| unsigned char* control = data; 527| 356k| data += control_size; 528| | 529| 356k| memset(control, 0, control_size); 530| | 531| 4.13M| for (size_t k = 0; k < vertex_size; ++k) ------------------ | Branch (531:21): [True: 3.78M, False: 356k] ------------------ 532| 3.78M| { 533| 3.78M| encodeDeltas(buffer, vertex_data, vertex_count, vertex_size, last_vertex, k, version == 0 ? 0 : channels[k / 4]); ------------------ | Branch (533:80): [True: 311k, False: 3.46M] ------------------ 534| | 535| |#if TRACE 536| | const unsigned char* olddata = data; 537| | bytestats = &vertexstats[k]; 538| |#endif 539| | 540| 3.78M| int ctrl = 0; 541| | 542| 3.78M| if (version != 0) ------------------ | Branch (542:7): [True: 3.46M, False: 311k] ------------------ 543| 3.46M| { 544| 3.46M| ctrl = estimateControl(buffer, vertex_count, vertex_count_aligned, level); 545| | 546| 3.46M| assert(unsigned(ctrl) < 4); ------------------ | Branch (546:4): [True: 3.46M, False: 0] ------------------ 547| 3.46M| control[k / 4] |= ctrl << ((k % 4) * 2); 548| | 549| |#if TRACE 550| | vertexstats[k].ctrl[ctrl]++; 551| |#endif 552| 3.46M| } 553| | 554| 3.78M| if (ctrl == 3) ------------------ | Branch (554:7): [True: 752k, False: 3.02M] ------------------ 555| 752k| { 556| | // literal encoding 557| 752k| if (size_t(data_end - data) < vertex_count) ------------------ | Branch (557:8): [True: 0, False: 752k] ------------------ 558| 0| return NULL; 559| | 560| 752k| memcpy(data, buffer, vertex_count); 561| 752k| data += vertex_count; 562| 752k| } 563| 3.02M| else if (ctrl != 2) // non-zero encoding ------------------ | Branch (563:12): [True: 1.56M, False: 1.46M] ------------------ 564| 1.56M| { 565| 1.56M| data = encodeBytes(data, data_end, buffer, vertex_count_aligned, version == 0 ? kBitsV0 : kBitsV1 + ctrl); ------------------ | Branch (565:69): [True: 311k, False: 1.24M] ------------------ 566| 1.56M| if (!data) ------------------ | Branch (566:8): [True: 0, False: 1.56M] ------------------ 567| 0| return NULL; 568| 1.56M| } 569| | 570| |#if TRACE 571| | bytestats = NULL; 572| | vertexstats[k].size += data - olddata; 573| |#endif 574| 3.78M| } 575| | 576| 356k| memcpy(last_vertex, &vertex_data[vertex_size * (vertex_count - 1)], vertex_size); 577| | 578| 356k| return data; 579| 356k|} vertexcodec.cpp:_ZN7meshoptL15estimateControlEPKhmmi: 472| 3.46M|{ 473| 3.46M| if (estimateControlZero(buffer, vertex_count_aligned)) ------------------ | Branch (473:6): [True: 1.46M, False: 2.00M] ------------------ 474| 1.46M| return 2; // zero encoding 475| | 476| 2.00M| if (level == 0) ------------------ | Branch (476:6): [True: 750k, False: 1.25M] ------------------ 477| 750k| return 1; // 1248 encoding in level 0 for encoding speed 478| | 479| | // round number of groups to 4 to get number of header bytes 480| 1.25M| size_t header_size = (vertex_count_aligned / kByteGroupSize + 3) / 4; 481| | 482| 1.25M| size_t est_bytes0 = header_size, est_bytes1 = header_size; 483| | 484| 20.2M| for (size_t i = 0; i < vertex_count_aligned; i += kByteGroupSize) ------------------ | Branch (484:21): [True: 19.0M, False: 1.25M] ------------------ 485| 19.0M| { 486| | // assumes kBitsV1[] = {0, 1, 2, 4, 8} for performance 487| 19.0M| size_t size0 = encodeBytesGroupMeasure(buffer + i, 0); 488| 19.0M| size_t size1 = encodeBytesGroupMeasure(buffer + i, 1); 489| 19.0M| size_t size2 = encodeBytesGroupMeasure(buffer + i, 2); 490| 19.0M| size_t size4 = encodeBytesGroupMeasure(buffer + i, 4); 491| 19.0M| size_t size8 = encodeBytesGroupMeasure(buffer + i, 8); 492| | 493| | // both control modes have access to 1/2/4 bit encoding 494| 19.0M| size_t size12 = size1 < size2 ? size1 : size2; ------------------ | Branch (494:19): [True: 16.9M, False: 2.05M] ------------------ 495| 19.0M| size_t size124 = size12 < size4 ? size12 : size4; ------------------ | Branch (495:20): [True: 18.9M, False: 84.7k] ------------------ 496| | 497| | // each control mode has access to 0/8 bit encoding respectively 498| 19.0M| est_bytes0 += size124 < size0 ? size124 : size0; ------------------ | Branch (498:17): [True: 15.5M, False: 3.51M] ------------------ 499| 19.0M| est_bytes1 += size124 < size8 ? size124 : size8; ------------------ | Branch (499:17): [True: 6.99M, False: 12.0M] ------------------ 500| 19.0M| } 501| | 502| | // pick shortest control entry but prefer literal encoding 503| 1.25M| if (est_bytes0 < vertex_count || est_bytes1 < vertex_count) ------------------ | Branch (503:6): [True: 474k, False: 776k] | Branch (503:35): [True: 23.7k, False: 752k] ------------------ 504| 498k| return est_bytes0 < est_bytes1 ? 0 : 1; ------------------ | Branch (504:10): [True: 283k, False: 214k] ------------------ 505| 752k| else 506| 752k| return 3; // literal encoding 507| 1.25M|} vertexcodec.cpp:_ZN7meshoptL19estimateControlZeroEPKhm: 463| 3.46M|{ 464| 27.7M| for (size_t i = 0; i < vertex_count_aligned; i += kByteGroupSize) ------------------ | Branch (464:21): [True: 26.2M, False: 1.46M] ------------------ 465| 26.2M| if (!encodeBytesGroupZero(buffer + i)) ------------------ | Branch (465:7): [True: 2.00M, False: 24.2M] ------------------ 466| 2.00M| return false; 467| | 468| 1.46M| return true; 469| 3.46M|} vertexcodec.cpp:_ZN7meshoptL11encodeBytesEPhS0_PKhmPKi: 264| 1.56M|{ 265| 1.56M| assert(buffer_size % kByteGroupSize == 0); ------------------ | Branch (265:2): [True: 1.56M, False: 0] ------------------ 266| | 267| 1.56M| unsigned char* header = data; 268| | 269| | // round number of groups to 4 to get number of header bytes 270| 1.56M| size_t header_size = (buffer_size / kByteGroupSize + 3) / 4; 271| | 272| 1.56M| if (size_t(data_end - data) < header_size) ------------------ | Branch (272:6): [True: 0, False: 1.56M] ------------------ 273| 0| return NULL; 274| | 275| 1.56M| data += header_size; 276| | 277| 1.56M| memset(header, 0, header_size); 278| | 279| 1.56M| int last_bits = -1; 280| | 281| 25.1M| for (size_t i = 0; i < buffer_size; i += kByteGroupSize) ------------------ | Branch (281:21): [True: 23.5M, False: 1.56M] ------------------ 282| 23.5M| { 283| 23.5M| if (size_t(data_end - data) < kByteGroupDecodeLimit) ------------------ | Branch (283:7): [True: 0, False: 23.5M] ------------------ 284| 0| return NULL; 285| | 286| 23.5M| int best_bitk = 3; 287| 23.5M| size_t best_size = encodeBytesGroupMeasure(buffer + i, bits[best_bitk]); 288| | 289| 94.3M| for (int bitk = 0; bitk < 3; ++bitk) ------------------ | Branch (289:22): [True: 70.7M, False: 23.5M] ------------------ 290| 70.7M| { 291| 70.7M| size_t size = encodeBytesGroupMeasure(buffer + i, bits[bitk]); 292| | 293| | // favor consistent bit selection across groups, but never replace literals 294| 70.7M| if (size < best_size || (size == best_size && bits[bitk] == last_bits && bits[best_bitk] != 8)) ------------------ | Branch (294:8): [True: 14.3M, False: 56.4M] | Branch (294:29): [True: 1.28M, False: 55.1M] | Branch (294:50): [True: 339k, False: 946k] | Branch (294:77): [True: 38.4k, False: 300k] ------------------ 295| 14.3M| { 296| 14.3M| best_bitk = bitk; 297| 14.3M| best_size = size; 298| 14.3M| } 299| 70.7M| } 300| | 301| 23.5M| size_t header_offset = i / kByteGroupSize; 302| 23.5M| header[header_offset / 4] |= best_bitk << ((header_offset % 4) * 2); 303| | 304| 23.5M| int best_bits = bits[best_bitk]; 305| 23.5M| unsigned char* next = encodeBytesGroup(data, buffer + i, best_bits); 306| | 307| 23.5M| assert(data + best_size == next); ------------------ | Branch (307:3): [True: 23.5M, False: 0] ------------------ 308| 23.5M| data = next; 309| 23.5M| last_bits = best_bits; 310| | 311| |#if TRACE 312| | bytestats->bitg[best_bits] += best_size; 313| |#endif 314| 23.5M| } 315| | 316| |#if TRACE 317| | bytestats->header += header_size; 318| |#endif 319| | 320| 1.56M| return data; 321| 1.56M|} vertexcodec.cpp:_ZN7meshoptL16encodeBytesGroupEPhPKhi: 211| 23.5M|{ 212| 23.5M| assert(bits >= 0 && bits <= 8); ------------------ | Branch (212:2): [True: 23.5M, False: 0] | Branch (212:2): [True: 23.5M, False: 0] | Branch (212:2): [True: 23.5M, False: 0] ------------------ 213| 23.5M| assert(kByteGroupSize % 8 == 0); ------------------ | Branch (213:2): [True: 23.5M, Folded] ------------------ 214| | 215| 23.5M| if (bits == 0) ------------------ | Branch (215:6): [True: 5.82M, False: 17.7M] ------------------ 216| 5.82M| return data; 217| | 218| 17.7M| if (bits == 8) ------------------ | Branch (218:6): [True: 10.7M, False: 7.05M] ------------------ 219| 10.7M| { 220| 10.7M| memcpy(data, buffer, kByteGroupSize); 221| 10.7M| return data + kByteGroupSize; 222| 10.7M| } 223| | 224| 7.05M| size_t byte_size = 8 / bits; 225| 7.05M| assert(kByteGroupSize % byte_size == 0); ------------------ | Branch (225:2): [True: 7.05M, False: 0] ------------------ 226| | 227| | // fixed portion: bits bits for each value 228| | // variable portion: full byte for each out-of-range value (using 1...1 as sentinel) 229| 7.05M| unsigned char sentinel = (1 << bits) - 1; 230| | 231| 25.6M| for (size_t i = 0; i < kByteGroupSize; i += byte_size) ------------------ | Branch (231:21): [True: 18.6M, False: 7.05M] ------------------ 232| 18.6M| { 233| 18.6M| unsigned char byte = 0; 234| | 235| 131M| for (size_t k = 0; k < byte_size; ++k) ------------------ | Branch (235:22): [True: 112M, False: 18.6M] ------------------ 236| 112M| { 237| 112M| unsigned char enc = (buffer[i + k] >= sentinel) ? sentinel : buffer[i + k]; ------------------ | Branch (237:24): [True: 40.4M, False: 72.4M] ------------------ 238| | 239| 112M| byte <<= bits; 240| 112M| byte |= enc; 241| 112M| } 242| | 243| | // encode 1-bit groups in reverse bit order 244| | // this makes them faster to decode alongside other groups 245| 18.6M| if (bits == 1) ------------------ | Branch (245:7): [True: 9.82M, False: 8.80M] ------------------ 246| 9.82M| byte = (unsigned char)(((byte * 0x80200802ull) & 0x0884422110ull) * 0x0101010101ull >> 32); 247| | 248| 18.6M| *data++ = byte; 249| 18.6M| } 250| | 251| 119M| for (size_t i = 0; i < kByteGroupSize; ++i) ------------------ | Branch (251:21): [True: 112M, False: 7.05M] ------------------ 252| 112M| { 253| 112M| unsigned char v = buffer[i]; 254| | 255| | // branchless append of out-of-range values 256| 112M| *data = v; 257| 112M| data += v >= sentinel; 258| 112M| } 259| | 260| 7.05M| return data; 261| 7.05M|} vertexcodec.cpp:_ZN7meshoptL21decodeVertexBlockSimdEPKhS1_PhmmS2_S1_i: 1515| 179k|{ 1516| 179k| assert(vertex_count > 0 && vertex_count <= kVertexBlockMaxSize); ------------------ | Branch (1516:2): [True: 179k, False: 0] | Branch (1516:2): [True: 179k, False: 0] | Branch (1516:2): [True: 179k, False: 0] ------------------ 1517| | 1518| 179k| unsigned char buffer[kVertexBlockMaxSize * 4]; 1519| 179k| unsigned char transposed[kVertexBlockSizeBytes]; 1520| | 1521| 179k| size_t vertex_count_aligned = (vertex_count + kByteGroupSize - 1) & ~(kByteGroupSize - 1); 1522| | 1523| | // we can decode directly into the output buffer if vertex count is aligned to 16 (delta decode works 16 vertices at a time) 1524| | // this uses strided writes and also reads the last vertex once, which is bad for performance for write-combined memory so we only enable this if configured 1525| |#ifdef MESHOPTIMIZER_VERTEXCODEC_ZEROCOPY 1526| | unsigned char* target = vertex_count == vertex_count_aligned ? vertex_data : transposed; 1527| |#else 1528| 179k| unsigned char* target = transposed; 1529| 179k|#endif 1530| | 1531| 179k| size_t control_size = version == 0 ? 0 : vertex_size / 4; ------------------ | Branch (1531:24): [True: 14.3k, False: 165k] ------------------ 1532| 179k| if (size_t(data_end - data) < control_size) ------------------ | Branch (1532:6): [True: 0, False: 179k] ------------------ 1533| 0| return NULL; 1534| | 1535| 179k| const unsigned char* control = data; 1536| 179k| data += control_size; 1537| | 1538| 654k| for (size_t k = 0; k < vertex_size; k += 4) ------------------ | Branch (1538:21): [True: 475k, False: 178k] ------------------ 1539| 475k| { 1540| 475k| unsigned char ctrl_byte = version == 0 ? 0 : control[k / 4]; ------------------ | Branch (1540:29): [True: 39.9k, False: 435k] ------------------ 1541| | 1542| 2.37M| for (size_t j = 0; j < 4; ++j) ------------------ | Branch (1542:22): [True: 1.90M, False: 475k] ------------------ 1543| 1.90M| { 1544| 1.90M| int ctrl = (ctrl_byte >> (j * 2)) & 3; 1545| | 1546| 1.90M| if (ctrl == 3) ------------------ | Branch (1546:8): [True: 377k, False: 1.52M] ------------------ 1547| 377k| { 1548| | // literal encoding; safe to over-copy due to tail 1549| 377k| if (size_t(data_end - data) < vertex_count_aligned) ------------------ | Branch (1549:9): [True: 66, False: 377k] ------------------ 1550| 66| return NULL; 1551| | 1552| 377k| memcpy(buffer + j * vertex_count_aligned, data, vertex_count_aligned); 1553| 377k| data += vertex_count; 1554| 377k| } 1555| 1.52M| else if (ctrl == 2) ------------------ | Branch (1555:13): [True: 736k, False: 786k] ------------------ 1556| 736k| { 1557| | // zero encoding 1558| 736k| memset(buffer + j * vertex_count_aligned, 0, vertex_count_aligned); 1559| 736k| } 1560| 786k| else 1561| 786k| { 1562| | // for v0, headers are mapped to 0..3; for v1, headers are mapped to 4..8 1563| 786k| int hshift = version == 0 ? 0 : 4 + ctrl; ------------------ | Branch (1563:18): [True: 159k, False: 627k] ------------------ 1564| | 1565| 786k| data = decodeBytesSimd(data, data_end, buffer + j * vertex_count_aligned, vertex_count_aligned, hshift); 1566| 786k| if (!data) ------------------ | Branch (1566:9): [True: 267, False: 786k] ------------------ 1567| 267| return NULL; 1568| 786k| } 1569| 1.90M| } 1570| | 1571| 475k| int channel = version == 0 ? 0 : channels[k / 4]; ------------------ | Branch (1571:17): [True: 39.8k, False: 435k] ------------------ 1572| | 1573| 475k| switch (channel & 3) 1574| 475k| { 1575| 431k| case 0: ------------------ | Branch (1575:3): [True: 431k, False: 43.2k] ------------------ 1576| 431k| decodeDeltas4Simd<0>(buffer, target + k, vertex_count_aligned, vertex_size, last_vertex + k, 0); 1577| 431k| break; 1578| 20.8k| case 1: ------------------ | Branch (1578:3): [True: 20.8k, False: 454k] ------------------ 1579| 20.8k| decodeDeltas4Simd<1>(buffer, target + k, vertex_count_aligned, vertex_size, last_vertex + k, 0); 1580| 20.8k| break; 1581| 22.2k| case 2: ------------------ | Branch (1581:3): [True: 22.2k, False: 452k] ------------------ 1582| 22.2k| decodeDeltas4Simd<2>(buffer, target + k, vertex_count_aligned, vertex_size, last_vertex + k, (32 - (channel >> 4)) & 31); 1583| 22.2k| break; 1584| 131| default: ------------------ | Branch (1584:3): [True: 131, False: 474k] ------------------ 1585| 131| return NULL; // invalid channel type 1586| 475k| } 1587| 475k| } 1588| | 1589| 178k| if (target == transposed) ------------------ | Branch (1589:6): [True: 178k, False: 0] ------------------ 1590| 178k| memcpy(vertex_data, transposed, vertex_count * vertex_size); 1591| | 1592| 178k| memcpy(last_vertex, &target[vertex_size * (vertex_count - 1)], vertex_size); 1593| | 1594| 178k| return data; 1595| 179k|} vertexcodec.cpp:_ZN7meshoptL15decodeBytesSimdEPKhS1_Phmi: 1370| 786k|{ 1371| 786k| assert(buffer_size % kByteGroupSize == 0); ------------------ | Branch (1371:2): [True: 786k, False: 0] ------------------ 1372| 786k| assert(kByteGroupSize == 16); ------------------ | Branch (1372:2): [True: 786k, Folded] ------------------ 1373| | 1374| | // round number of groups to 4 to get number of header bytes 1375| 786k| size_t header_size = (buffer_size / kByteGroupSize + 3) / 4; 1376| 786k| if (size_t(data_end - data) < header_size) ------------------ | Branch (1376:6): [True: 11, False: 786k] ------------------ 1377| 11| return NULL; 1378| | 1379| 786k| const unsigned char* header = data; 1380| 786k| data += header_size; 1381| | 1382| 786k| size_t i = 0; 1383| | 1384| | // fast-path: process 4 groups at a time, do a shared bounds check 1385| 3.71M| for (; i + kByteGroupSize * 4 <= buffer_size && size_t(data_end - data) >= kByteGroupDecodeLimit * 4; i += kByteGroupSize * 4) ------------------ | Branch (1385:9): [True: 2.93M, False: 782k] | Branch (1385:50): [True: 2.92M, False: 4.26k] ------------------ 1386| 2.92M| { 1387| 2.92M| size_t header_offset = i / kByteGroupSize; 1388| 2.92M| unsigned char header_byte = header[header_offset / 4]; 1389| | 1390| 2.92M|#if defined(SIMD_SSE) || defined(SIMD_AVX) 1391| | // very-fast-path: for consecutive 4 groups that are all 0-bit (v0/0, v1/0/0000) or 8-bit (v0/3333, v1/1/3333), 1392| | // the branchless decoders are slower than branching over the decoding of 4 groups and issuing a few load/store ops 1393| 2.92M| if (hshift != 5 && header_byte == 0) ------------------ | Branch (1393:7): [True: 1.08M, False: 1.84M] | Branch (1393:22): [True: 577k, False: 503k] ------------------ 1394| 577k| { 1395| 577k| memset(buffer + i, 0, kByteGroupSize * 4); 1396| 577k| continue; 1397| 577k| } 1398| 2.35M| else if (hshift != 4 && header_byte == 255) ------------------ | Branch (1398:12): [True: 2.09M, False: 259k] | Branch (1398:27): [True: 1.21M, False: 871k] ------------------ 1399| 1.21M| { 1400| 1.21M| memcpy(buffer + i, data, kByteGroupSize * 4); 1401| 1.21M| data += kByteGroupSize * 4; 1402| 1.21M| continue; 1403| 1.21M| } 1404| 1.13M|#endif 1405| | 1406| 1.13M| data = decodeBytesGroupSimd(data, buffer + i + kByteGroupSize * 0, hshift + ((header_byte >> 0) & 3)); 1407| 1.13M| data = decodeBytesGroupSimd(data, buffer + i + kByteGroupSize * 1, hshift + ((header_byte >> 2) & 3)); 1408| 1.13M| data = decodeBytesGroupSimd(data, buffer + i + kByteGroupSize * 2, hshift + ((header_byte >> 4) & 3)); 1409| 1.13M| data = decodeBytesGroupSimd(data, buffer + i + kByteGroupSize * 3, hshift + ((header_byte >> 6) & 3)); 1410| 1.13M| } 1411| | 1412| | // slow-path: process remaining groups 1413| 898k| for (; i < buffer_size; i += kByteGroupSize) ------------------ | Branch (1413:9): [True: 112k, False: 786k] ------------------ 1414| 112k| { 1415| 112k| if (size_t(data_end - data) < kByteGroupDecodeLimit) ------------------ | Branch (1415:7): [True: 256, False: 111k] ------------------ 1416| 256| return NULL; 1417| | 1418| 111k| size_t header_offset = i / kByteGroupSize; 1419| 111k| unsigned char header_byte = header[header_offset / 4]; 1420| | 1421| 111k| data = decodeBytesGroupSimd(data, buffer + i, hshift + ((header_byte >> ((header_offset % 4) * 2)) & 3)); 1422| 111k| } 1423| | 1424| 786k| return data; 1425| 786k|} vertexcodec.cpp:_ZN7meshoptL20decodeBytesGroupSimdEPKhPhi: 831| 4.63M|{ 832| | // 0 for 1-bit, 1 for 2-bit, 2 for 4-bit, 3 for 8-bit, and 4 for 0-bit as it makes some of the uses easier 833| 4.63M| static const int hbtn[9] = {4, 1, 2, 3, 4, 0, 1, 2, 3}; 834| | 835| 4.63M| int n = hbtn[hbits]; 836| | 837| 4.63M|#ifdef SIMD_LATENCYOPT 838| 4.63M| unsigned long long data64; 839| 4.63M| memcpy(&data64, data, 8); 840| 4.63M| data64 &= data64 >> n; 841| 4.63M| data64 &= data64 >> (n >> 1); 842| | 843| | // mask out one bit per group that is set if all group bits were 1 844| 4.63M| static const unsigned long long lanes[9] = {0, 0x55555555, 0x1111111111111111ull, 0, 0, 0xffff, 0x55555555, 0x1111111111111111ull, 0}; 845| 4.63M| int datacnt = int(_mm_popcnt_u64(data64 & lanes[hbits])); 846| 4.63M|#endif 847| | 848| | // for 8-bit groups, instead of loading the bytes through 'data', we load them through 'skip' as they are easier to preserve 849| | // for 0-bit groups, the load results get discarded because mask is always 0; in both cases the shift wraps to zero 850| 4.63M| const unsigned char* skip = data + ((2 << n) & 15); 851| | 852| 4.63M| __m128i selb = _mm_loadl_epi64(reinterpret_cast(data)); 853| 4.63M| __m128i rest = _mm_loadu_si128(reinterpret_cast(skip)); 854| | 855| | // unpack 1, 2 or 4-bit values: shuffle replicates each source byte into both halves of a 16-bit lane 856| | // mulhi extracts even and odd fields into the low byte; the results are interleaved back with shift/or 857| 4.63M| __m128i selw = _mm_shuffle_epi8(selb, _mm_loadu_si128(reinterpret_cast(kDecodeBytesGroupConfig[hbits][1]))); 858| 4.63M| __m128i sel0 = _mm_mulhi_epu16(selw, _mm_loadu_si128(reinterpret_cast(kDecodeBytesGroupConfig[hbits][2]))); 859| 4.63M| __m128i sel1 = _mm_mulhi_epu16(selw, _mm_loadu_si128(reinterpret_cast(kDecodeBytesGroupConfig[hbits][3]))); 860| 4.63M| __m128i seli = _mm_or_si128(sel0, _mm_slli_epi16(sel1, 8)); 861| | 862| | // the interleaved fields are masked by the bit count (special handling: for 0/8-bit values, mul produces 0) 863| 4.63M| __m128i sent = _mm_loadu_si128(reinterpret_cast(kDecodeBytesGroupConfig[hbits][0])); 864| 4.63M| __m128i sel = _mm_and_si128(seli, sent); 865| | 866| | // compare sel to sentinel; returns 0 for 0-bit (mul produces 0, sent is 1), 1 for 8-bit (mul produces 0, sent is 0) 867| 4.63M| __m128i mask = _mm_cmpeq_epi8(sel, sent); 868| 4.63M| int mask16 = _mm_movemask_epi8(mask); 869| 4.63M| unsigned char mask0 = (unsigned char)(mask16 & 255); 870| 4.63M| unsigned char mask1 = (unsigned char)(mask16 >> 8); 871| | 872| | // decode shuffle mask from two halves; second half needs to be shifted by popcount(mask0) 873| 4.63M| __m128i sm0 = _mm_loadl_epi64(reinterpret_cast(&kDecodeBytesGroupShuffle[mask0])); 874| 4.63M| __m128i sm1 = _mm_loadl_epi64(reinterpret_cast(&kDecodeBytesGroupShuffle[mask1])); 875| | 876| | // each lane of mask is 0x00 or 0xff; sad yields 255*popcount(mask0) in low word => low byte is -popcount(mask0) 877| 4.63M| __m128i npops = _mm_sad_epu8(mask, _mm_setzero_si128()); 878| 4.63M| __m128i sm1r = _mm_sub_epi8(sm1, _mm_shuffle_epi8(npops, _mm_setzero_si128())); 879| 4.63M| __m128i shuf = _mm_unpacklo_epi64(sm0, sm1r); 880| | 881| | // expand rest via shuffle mask and combine with sel; shuffle mask zeroes out bytes that are replaced by sel 882| 4.63M| __m128i result = _mm_or_si128(_mm_shuffle_epi8(rest, shuf), _mm_andnot_si128(mask, sel)); 883| | 884| 4.63M| _mm_storeu_si128(reinterpret_cast<__m128i*>(buffer), result); 885| | 886| 4.63M|#ifdef SIMD_LATENCYOPT 887| | // datacnt is 0 for 8-bit groups so we can't use skip to advance; 0-bit groups wrap the shift to zero 888| 4.63M| return data + ((2 << n) & 31) + datacnt; 889| |#else 890| | return skip + _mm_popcnt_u32(mask16); 891| |#endif 892| 4.63M|} vertexcodec.cpp:_ZN7meshoptL17decodeDeltas4SimdILi0EEEvPKhPhmmS3_i: 1430| 431k|{ 1431| 431k|#if defined(SIMD_SSE) || defined(SIMD_AVX) 1432| 431k|#define TEMP __m128i 1433| 431k|#define PREP() __m128i pi = _mm_cvtsi32_si128(*reinterpret_cast(last_vertex)) 1434| 431k|#define LOAD(i) __m128i r##i = _mm_loadu_si128(reinterpret_cast(buffer + j + i * vertex_count_aligned)) 1435| 431k|#define GRP4(i) t0 = r##i, t1 = _mm_shuffle_epi32(r##i, 1), t2 = _mm_shuffle_epi32(r##i, 2), t3 = _mm_shuffle_epi32(r##i, 3) 1436| 431k|#define FIXD(i) t##i = pi = Channel == 0 ? _mm_add_epi8(pi, t##i) : (Channel == 1 ? _mm_add_epi16(pi, t##i) : _mm_xor_si128(pi, t##i)) 1437| 431k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size 1438| 431k|#endif 1439| | 1440| |#ifdef SIMD_NEON 1441| |#define TEMP uint8x8_t 1442| |#define PREP() uint8x8_t pi = vreinterpret_u8_u32(vld1_lane_u32(reinterpret_cast(last_vertex), vdup_n_u32(0), 0)) 1443| |#define LOAD(i) uint8x16_t r##i = vld1q_u8(buffer + j + i * vertex_count_aligned) 1444| |#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)) 1445| |#define FIXD(i) t##i = pi = Channel == 0 ? vadd_u8(pi, t##i) : (Channel == 1 ? vreinterpret_u8_u16(vadd_u16(vreinterpret_u16_u8(pi), vreinterpret_u16_u8(t##i))) : veor_u8(pi, t##i)) 1446| |#define SAVE(i) vst1_lane_u32(reinterpret_cast(savep), vreinterpret_u32_u8(t##i), 0), savep += vertex_size 1447| |#endif 1448| | 1449| |#ifdef SIMD_WASM 1450| |#define TEMP v128_t 1451| |#define PREP() v128_t pi = wasm_v128_load(last_vertex) 1452| |#define LOAD(i) v128_t r##i = wasm_v128_load(buffer + j + i * vertex_count_aligned) 1453| |#define GRP4(i) t0 = r##i, t1 = wasmx_splat_v32x4(r##i, 1), t2 = wasmx_splat_v32x4(r##i, 2), t3 = wasmx_splat_v32x4(r##i, 3) 1454| |#define FIXD(i) t##i = pi = Channel == 0 ? wasm_i8x16_add(pi, t##i) : (Channel == 1 ? wasm_i16x8_add(pi, t##i) : wasm_v128_xor(pi, t##i)) 1455| |#define SAVE(i) wasm_v128_store32_lane(savep, t##i, 0), savep += vertex_size 1456| |#endif 1457| | 1458| 431k|#define UNZR(i) r##i = Channel == 0 ? unzigzag8(r##i) : (Channel == 1 ? unzigzag16(r##i) : rotate32(r##i, rot)) 1459| | 1460| 431k| PREP(); ------------------ | | 1433| 431k|#define PREP() __m128i pi = _mm_cvtsi32_si128(*reinterpret_cast(last_vertex)) ------------------ 1461| | 1462| 431k| unsigned char* savep = transposed; 1463| | 1464| 6.98M| for (size_t j = 0; j < vertex_count_aligned; j += 16) ------------------ | Branch (1464:21): [True: 6.55M, False: 431k] ------------------ 1465| 6.55M| { 1466| 6.55M| LOAD(0); ------------------ | | 1434| 6.55M|#define LOAD(i) __m128i r##i = _mm_loadu_si128(reinterpret_cast(buffer + j + i * vertex_count_aligned)) ------------------ 1467| 6.55M| LOAD(1); ------------------ | | 1434| 6.55M|#define LOAD(i) __m128i r##i = _mm_loadu_si128(reinterpret_cast(buffer + j + i * vertex_count_aligned)) ------------------ 1468| 6.55M| LOAD(2); ------------------ | | 1434| 6.55M|#define LOAD(i) __m128i r##i = _mm_loadu_si128(reinterpret_cast(buffer + j + i * vertex_count_aligned)) ------------------ 1469| 6.55M| LOAD(3); ------------------ | | 1434| 6.55M|#define LOAD(i) __m128i r##i = _mm_loadu_si128(reinterpret_cast(buffer + j + i * vertex_count_aligned)) ------------------ 1470| | 1471| 6.55M| transpose8(r0, r1, r2, r3); 1472| | 1473| 6.55M| TEMP t0, t1, t2, t3; ------------------ | | 1432| 6.55M|#define TEMP __m128i ------------------ 1474| 6.55M| TEMP npi = pi; ------------------ | | 1432| 6.55M|#define TEMP __m128i ------------------ 1475| | 1476| 6.55M| UNZR(0); ------------------ | | 1458| 6.55M|#define UNZR(i) r##i = Channel == 0 ? unzigzag8(r##i) : (Channel == 1 ? unzigzag16(r##i) : rotate32(r##i, rot)) | | ------------------ | | | Branch (1458:24): [True: 6.55M, Folded] | | | Branch (1458:58): [Folded, False: 0] | | ------------------ ------------------ 1477| 6.55M| GRP4(0); ------------------ | | 1435| 6.55M|#define GRP4(i) t0 = r##i, t1 = _mm_shuffle_epi32(r##i, 1), t2 = _mm_shuffle_epi32(r##i, 2), t3 = _mm_shuffle_epi32(r##i, 3) ------------------ 1478| 6.55M| FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1436| 6.55M|#define FIXD(i) t##i = pi = Channel == 0 ? _mm_add_epi8(pi, t##i) : (Channel == 1 ? _mm_add_epi16(pi, t##i) : _mm_xor_si128(pi, t##i)) | | ------------------ | | | Branch (1436:29): [True: 6.55M, Folded] | | | Branch (1436:70): [Folded, False: 0] | | ------------------ ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1436| 6.55M|#define FIXD(i) t##i = pi = Channel == 0 ? _mm_add_epi8(pi, t##i) : (Channel == 1 ? _mm_add_epi16(pi, t##i) : _mm_xor_si128(pi, t##i)) | | ------------------ | | | Branch (1436:29): [True: 6.55M, Folded] | | | Branch (1436:70): [Folded, False: 0] | | ------------------ ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1436| 6.55M|#define FIXD(i) t##i = pi = Channel == 0 ? _mm_add_epi8(pi, t##i) : (Channel == 1 ? _mm_add_epi16(pi, t##i) : _mm_xor_si128(pi, t##i)) | | ------------------ | | | Branch (1436:29): [True: 6.55M, Folded] | | | Branch (1436:70): [Folded, False: 0] | | ------------------ ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1436| 6.55M|#define FIXD(i) t##i = pi = Channel == 0 ? _mm_add_epi8(pi, t##i) : (Channel == 1 ? _mm_add_epi16(pi, t##i) : _mm_xor_si128(pi, t##i)) | | ------------------ | | | Branch (1436:29): [True: 6.55M, Folded] | | | Branch (1436:70): [Folded, False: 0] | | ------------------ ------------------ 1479| 6.55M| SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1437| 6.55M|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1437| 6.55M|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1437| 6.55M|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1437| 6.55M|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ 1480| | 1481| 6.55M| UNZR(1); ------------------ | | 1458| 6.55M|#define UNZR(i) r##i = Channel == 0 ? unzigzag8(r##i) : (Channel == 1 ? unzigzag16(r##i) : rotate32(r##i, rot)) | | ------------------ | | | Branch (1458:24): [True: 6.55M, Folded] | | | Branch (1458:58): [Folded, False: 0] | | ------------------ ------------------ 1482| 6.55M| GRP4(1); ------------------ | | 1435| 6.55M|#define GRP4(i) t0 = r##i, t1 = _mm_shuffle_epi32(r##i, 1), t2 = _mm_shuffle_epi32(r##i, 2), t3 = _mm_shuffle_epi32(r##i, 3) ------------------ 1483| 6.55M| FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1436| 6.55M|#define FIXD(i) t##i = pi = Channel == 0 ? _mm_add_epi8(pi, t##i) : (Channel == 1 ? _mm_add_epi16(pi, t##i) : _mm_xor_si128(pi, t##i)) | | ------------------ | | | Branch (1436:29): [True: 6.55M, Folded] | | | Branch (1436:70): [Folded, False: 0] | | ------------------ ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1436| 6.55M|#define FIXD(i) t##i = pi = Channel == 0 ? _mm_add_epi8(pi, t##i) : (Channel == 1 ? _mm_add_epi16(pi, t##i) : _mm_xor_si128(pi, t##i)) | | ------------------ | | | Branch (1436:29): [True: 6.55M, Folded] | | | Branch (1436:70): [Folded, False: 0] | | ------------------ ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1436| 6.55M|#define FIXD(i) t##i = pi = Channel == 0 ? _mm_add_epi8(pi, t##i) : (Channel == 1 ? _mm_add_epi16(pi, t##i) : _mm_xor_si128(pi, t##i)) | | ------------------ | | | Branch (1436:29): [True: 6.55M, Folded] | | | Branch (1436:70): [Folded, False: 0] | | ------------------ ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1436| 6.55M|#define FIXD(i) t##i = pi = Channel == 0 ? _mm_add_epi8(pi, t##i) : (Channel == 1 ? _mm_add_epi16(pi, t##i) : _mm_xor_si128(pi, t##i)) | | ------------------ | | | Branch (1436:29): [True: 6.55M, Folded] | | | Branch (1436:70): [Folded, False: 0] | | ------------------ ------------------ 1484| 6.55M| SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1437| 6.55M|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1437| 6.55M|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1437| 6.55M|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1437| 6.55M|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ 1485| | 1486| 6.55M| UNZR(2); ------------------ | | 1458| 6.55M|#define UNZR(i) r##i = Channel == 0 ? unzigzag8(r##i) : (Channel == 1 ? unzigzag16(r##i) : rotate32(r##i, rot)) | | ------------------ | | | Branch (1458:24): [True: 6.55M, Folded] | | | Branch (1458:58): [Folded, False: 0] | | ------------------ ------------------ 1487| 6.55M| GRP4(2); ------------------ | | 1435| 6.55M|#define GRP4(i) t0 = r##i, t1 = _mm_shuffle_epi32(r##i, 1), t2 = _mm_shuffle_epi32(r##i, 2), t3 = _mm_shuffle_epi32(r##i, 3) ------------------ 1488| 6.55M| FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1436| 6.55M|#define FIXD(i) t##i = pi = Channel == 0 ? _mm_add_epi8(pi, t##i) : (Channel == 1 ? _mm_add_epi16(pi, t##i) : _mm_xor_si128(pi, t##i)) | | ------------------ | | | Branch (1436:29): [True: 6.55M, Folded] | | | Branch (1436:70): [Folded, False: 0] | | ------------------ ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1436| 6.55M|#define FIXD(i) t##i = pi = Channel == 0 ? _mm_add_epi8(pi, t##i) : (Channel == 1 ? _mm_add_epi16(pi, t##i) : _mm_xor_si128(pi, t##i)) | | ------------------ | | | Branch (1436:29): [True: 6.55M, Folded] | | | Branch (1436:70): [Folded, False: 0] | | ------------------ ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1436| 6.55M|#define FIXD(i) t##i = pi = Channel == 0 ? _mm_add_epi8(pi, t##i) : (Channel == 1 ? _mm_add_epi16(pi, t##i) : _mm_xor_si128(pi, t##i)) | | ------------------ | | | Branch (1436:29): [True: 6.55M, Folded] | | | Branch (1436:70): [Folded, False: 0] | | ------------------ ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1436| 6.55M|#define FIXD(i) t##i = pi = Channel == 0 ? _mm_add_epi8(pi, t##i) : (Channel == 1 ? _mm_add_epi16(pi, t##i) : _mm_xor_si128(pi, t##i)) | | ------------------ | | | Branch (1436:29): [True: 6.55M, Folded] | | | Branch (1436:70): [Folded, False: 0] | | ------------------ ------------------ 1489| 6.55M| SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1437| 6.55M|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1437| 6.55M|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1437| 6.55M|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1437| 6.55M|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ 1490| | 1491| 6.55M| UNZR(3); ------------------ | | 1458| 6.55M|#define UNZR(i) r##i = Channel == 0 ? unzigzag8(r##i) : (Channel == 1 ? unzigzag16(r##i) : rotate32(r##i, rot)) | | ------------------ | | | Branch (1458:24): [True: 6.55M, Folded] | | | Branch (1458:58): [Folded, False: 0] | | ------------------ ------------------ 1492| 6.55M| GRP4(3); ------------------ | | 1435| 6.55M|#define GRP4(i) t0 = r##i, t1 = _mm_shuffle_epi32(r##i, 1), t2 = _mm_shuffle_epi32(r##i, 2), t3 = _mm_shuffle_epi32(r##i, 3) ------------------ 1493| 6.55M| FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1436| 6.55M|#define FIXD(i) t##i = pi = Channel == 0 ? _mm_add_epi8(pi, t##i) : (Channel == 1 ? _mm_add_epi16(pi, t##i) : _mm_xor_si128(pi, t##i)) | | ------------------ | | | Branch (1436:29): [True: 6.55M, Folded] | | | Branch (1436:70): [Folded, False: 0] | | ------------------ ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1436| 6.55M|#define FIXD(i) t##i = pi = Channel == 0 ? _mm_add_epi8(pi, t##i) : (Channel == 1 ? _mm_add_epi16(pi, t##i) : _mm_xor_si128(pi, t##i)) | | ------------------ | | | Branch (1436:29): [True: 6.55M, Folded] | | | Branch (1436:70): [Folded, False: 0] | | ------------------ ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1436| 6.55M|#define FIXD(i) t##i = pi = Channel == 0 ? _mm_add_epi8(pi, t##i) : (Channel == 1 ? _mm_add_epi16(pi, t##i) : _mm_xor_si128(pi, t##i)) | | ------------------ | | | Branch (1436:29): [True: 6.55M, Folded] | | | Branch (1436:70): [Folded, False: 0] | | ------------------ ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1436| 6.55M|#define FIXD(i) t##i = pi = Channel == 0 ? _mm_add_epi8(pi, t##i) : (Channel == 1 ? _mm_add_epi16(pi, t##i) : _mm_xor_si128(pi, t##i)) | | ------------------ | | | Branch (1436:29): [True: 6.55M, Folded] | | | Branch (1436:70): [Folded, False: 0] | | ------------------ ------------------ 1494| 6.55M| SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1437| 6.55M|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1437| 6.55M|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1437| 6.55M|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1437| 6.55M|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ 1495| | 1496| |#if defined(SIMD_LATENCYOPT) && defined(SIMD_NEON) && (defined(__APPLE__) || defined(_WIN32)) 1497| | // instead of relying on accumulated pi, recompute it from scratch from r0..r3; this shortens dependency between loop iterations 1498| | pi = rebase(npi, r0, r1, r2, r3); 1499| |#else 1500| 6.55M| (void)npi; 1501| 6.55M|#endif 1502| | 1503| 6.55M|#undef UNZR 1504| 6.55M|#undef TEMP 1505| 6.55M|#undef PREP 1506| 6.55M|#undef LOAD 1507| 6.55M|#undef GRP4 1508| 6.55M|#undef FIXD 1509| 6.55M|#undef SAVE 1510| 6.55M| } 1511| 431k|} _ZN7meshopt10transpose8ERDv2_xS1_S1_S1_: 1219| 7.21M|{ 1220| 7.21M| __m128i t0 = _mm_unpacklo_epi8(x0, x1); 1221| 7.21M| __m128i t1 = _mm_unpackhi_epi8(x0, x1); 1222| 7.21M| __m128i t2 = _mm_unpacklo_epi8(x2, x3); 1223| 7.21M| __m128i t3 = _mm_unpackhi_epi8(x2, x3); 1224| | 1225| 7.21M| x0 = _mm_unpacklo_epi16(t0, t2); 1226| 7.21M| x1 = _mm_unpackhi_epi16(t0, t2); 1227| 7.21M| x2 = _mm_unpacklo_epi16(t1, t3); 1228| 7.21M| x3 = _mm_unpackhi_epi16(t1, t3); 1229| 7.21M|} _ZN7meshopt9unzigzag8EDv2_x: 1233| 26.2M|{ 1234| 26.2M| __m128i xl = _mm_sub_epi8(_mm_setzero_si128(), _mm_and_si128(v, _mm_set1_epi8(1))); 1235| 26.2M| __m128i xr = _mm_and_si128(_mm_srli_epi16(v, 1), _mm_set1_epi8(127)); 1236| | 1237| 26.2M| return _mm_xor_si128(xl, xr); 1238| 26.2M|} vertexcodec.cpp:_ZN7meshoptL17decodeDeltas4SimdILi1EEEvPKhPhmmS3_i: 1430| 20.8k|{ 1431| 20.8k|#if defined(SIMD_SSE) || defined(SIMD_AVX) 1432| 20.8k|#define TEMP __m128i 1433| 20.8k|#define PREP() __m128i pi = _mm_cvtsi32_si128(*reinterpret_cast(last_vertex)) 1434| 20.8k|#define LOAD(i) __m128i r##i = _mm_loadu_si128(reinterpret_cast(buffer + j + i * vertex_count_aligned)) 1435| 20.8k|#define GRP4(i) t0 = r##i, t1 = _mm_shuffle_epi32(r##i, 1), t2 = _mm_shuffle_epi32(r##i, 2), t3 = _mm_shuffle_epi32(r##i, 3) 1436| 20.8k|#define FIXD(i) t##i = pi = Channel == 0 ? _mm_add_epi8(pi, t##i) : (Channel == 1 ? _mm_add_epi16(pi, t##i) : _mm_xor_si128(pi, t##i)) 1437| 20.8k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size 1438| 20.8k|#endif 1439| | 1440| |#ifdef SIMD_NEON 1441| |#define TEMP uint8x8_t 1442| |#define PREP() uint8x8_t pi = vreinterpret_u8_u32(vld1_lane_u32(reinterpret_cast(last_vertex), vdup_n_u32(0), 0)) 1443| |#define LOAD(i) uint8x16_t r##i = vld1q_u8(buffer + j + i * vertex_count_aligned) 1444| |#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)) 1445| |#define FIXD(i) t##i = pi = Channel == 0 ? vadd_u8(pi, t##i) : (Channel == 1 ? vreinterpret_u8_u16(vadd_u16(vreinterpret_u16_u8(pi), vreinterpret_u16_u8(t##i))) : veor_u8(pi, t##i)) 1446| |#define SAVE(i) vst1_lane_u32(reinterpret_cast(savep), vreinterpret_u32_u8(t##i), 0), savep += vertex_size 1447| |#endif 1448| | 1449| |#ifdef SIMD_WASM 1450| |#define TEMP v128_t 1451| |#define PREP() v128_t pi = wasm_v128_load(last_vertex) 1452| |#define LOAD(i) v128_t r##i = wasm_v128_load(buffer + j + i * vertex_count_aligned) 1453| |#define GRP4(i) t0 = r##i, t1 = wasmx_splat_v32x4(r##i, 1), t2 = wasmx_splat_v32x4(r##i, 2), t3 = wasmx_splat_v32x4(r##i, 3) 1454| |#define FIXD(i) t##i = pi = Channel == 0 ? wasm_i8x16_add(pi, t##i) : (Channel == 1 ? wasm_i16x8_add(pi, t##i) : wasm_v128_xor(pi, t##i)) 1455| |#define SAVE(i) wasm_v128_store32_lane(savep, t##i, 0), savep += vertex_size 1456| |#endif 1457| | 1458| 20.8k|#define UNZR(i) r##i = Channel == 0 ? unzigzag8(r##i) : (Channel == 1 ? unzigzag16(r##i) : rotate32(r##i, rot)) 1459| | 1460| 20.8k| PREP(); ------------------ | | 1433| 20.8k|#define PREP() __m128i pi = _mm_cvtsi32_si128(*reinterpret_cast(last_vertex)) ------------------ 1461| | 1462| 20.8k| unsigned char* savep = transposed; 1463| | 1464| 335k| for (size_t j = 0; j < vertex_count_aligned; j += 16) ------------------ | Branch (1464:21): [True: 314k, False: 20.8k] ------------------ 1465| 314k| { 1466| 314k| LOAD(0); ------------------ | | 1434| 314k|#define LOAD(i) __m128i r##i = _mm_loadu_si128(reinterpret_cast(buffer + j + i * vertex_count_aligned)) ------------------ 1467| 314k| LOAD(1); ------------------ | | 1434| 314k|#define LOAD(i) __m128i r##i = _mm_loadu_si128(reinterpret_cast(buffer + j + i * vertex_count_aligned)) ------------------ 1468| 314k| LOAD(2); ------------------ | | 1434| 314k|#define LOAD(i) __m128i r##i = _mm_loadu_si128(reinterpret_cast(buffer + j + i * vertex_count_aligned)) ------------------ 1469| 314k| LOAD(3); ------------------ | | 1434| 314k|#define LOAD(i) __m128i r##i = _mm_loadu_si128(reinterpret_cast(buffer + j + i * vertex_count_aligned)) ------------------ 1470| | 1471| 314k| transpose8(r0, r1, r2, r3); 1472| | 1473| 314k| TEMP t0, t1, t2, t3; ------------------ | | 1432| 314k|#define TEMP __m128i ------------------ 1474| 314k| TEMP npi = pi; ------------------ | | 1432| 314k|#define TEMP __m128i ------------------ 1475| | 1476| 314k| UNZR(0); ------------------ | | 1458| 314k|#define UNZR(i) r##i = Channel == 0 ? unzigzag8(r##i) : (Channel == 1 ? unzigzag16(r##i) : rotate32(r##i, rot)) | | ------------------ | | | Branch (1458:24): [Folded, False: 314k] | | | Branch (1458:58): [True: 314k, Folded] | | ------------------ ------------------ 1477| 314k| GRP4(0); ------------------ | | 1435| 314k|#define GRP4(i) t0 = r##i, t1 = _mm_shuffle_epi32(r##i, 1), t2 = _mm_shuffle_epi32(r##i, 2), t3 = _mm_shuffle_epi32(r##i, 3) ------------------ 1478| 314k| FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1436| 314k|#define FIXD(i) t##i = pi = Channel == 0 ? _mm_add_epi8(pi, t##i) : (Channel == 1 ? _mm_add_epi16(pi, t##i) : _mm_xor_si128(pi, t##i)) | | ------------------ | | | Branch (1436:29): [Folded, False: 314k] | | | Branch (1436:70): [True: 314k, Folded] | | ------------------ ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1436| 314k|#define FIXD(i) t##i = pi = Channel == 0 ? _mm_add_epi8(pi, t##i) : (Channel == 1 ? _mm_add_epi16(pi, t##i) : _mm_xor_si128(pi, t##i)) | | ------------------ | | | Branch (1436:29): [Folded, False: 314k] | | | Branch (1436:70): [True: 314k, Folded] | | ------------------ ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1436| 314k|#define FIXD(i) t##i = pi = Channel == 0 ? _mm_add_epi8(pi, t##i) : (Channel == 1 ? _mm_add_epi16(pi, t##i) : _mm_xor_si128(pi, t##i)) | | ------------------ | | | Branch (1436:29): [Folded, False: 314k] | | | Branch (1436:70): [True: 314k, Folded] | | ------------------ ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1436| 314k|#define FIXD(i) t##i = pi = Channel == 0 ? _mm_add_epi8(pi, t##i) : (Channel == 1 ? _mm_add_epi16(pi, t##i) : _mm_xor_si128(pi, t##i)) | | ------------------ | | | Branch (1436:29): [Folded, False: 314k] | | | Branch (1436:70): [True: 314k, Folded] | | ------------------ ------------------ 1479| 314k| SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1437| 314k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1437| 314k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1437| 314k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1437| 314k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ 1480| | 1481| 314k| UNZR(1); ------------------ | | 1458| 314k|#define UNZR(i) r##i = Channel == 0 ? unzigzag8(r##i) : (Channel == 1 ? unzigzag16(r##i) : rotate32(r##i, rot)) | | ------------------ | | | Branch (1458:24): [Folded, False: 314k] | | | Branch (1458:58): [True: 314k, Folded] | | ------------------ ------------------ 1482| 314k| GRP4(1); ------------------ | | 1435| 314k|#define GRP4(i) t0 = r##i, t1 = _mm_shuffle_epi32(r##i, 1), t2 = _mm_shuffle_epi32(r##i, 2), t3 = _mm_shuffle_epi32(r##i, 3) ------------------ 1483| 314k| FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1436| 314k|#define FIXD(i) t##i = pi = Channel == 0 ? _mm_add_epi8(pi, t##i) : (Channel == 1 ? _mm_add_epi16(pi, t##i) : _mm_xor_si128(pi, t##i)) | | ------------------ | | | Branch (1436:29): [Folded, False: 314k] | | | Branch (1436:70): [True: 314k, Folded] | | ------------------ ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1436| 314k|#define FIXD(i) t##i = pi = Channel == 0 ? _mm_add_epi8(pi, t##i) : (Channel == 1 ? _mm_add_epi16(pi, t##i) : _mm_xor_si128(pi, t##i)) | | ------------------ | | | Branch (1436:29): [Folded, False: 314k] | | | Branch (1436:70): [True: 314k, Folded] | | ------------------ ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1436| 314k|#define FIXD(i) t##i = pi = Channel == 0 ? _mm_add_epi8(pi, t##i) : (Channel == 1 ? _mm_add_epi16(pi, t##i) : _mm_xor_si128(pi, t##i)) | | ------------------ | | | Branch (1436:29): [Folded, False: 314k] | | | Branch (1436:70): [True: 314k, Folded] | | ------------------ ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1436| 314k|#define FIXD(i) t##i = pi = Channel == 0 ? _mm_add_epi8(pi, t##i) : (Channel == 1 ? _mm_add_epi16(pi, t##i) : _mm_xor_si128(pi, t##i)) | | ------------------ | | | Branch (1436:29): [Folded, False: 314k] | | | Branch (1436:70): [True: 314k, Folded] | | ------------------ ------------------ 1484| 314k| SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1437| 314k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1437| 314k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1437| 314k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1437| 314k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ 1485| | 1486| 314k| UNZR(2); ------------------ | | 1458| 314k|#define UNZR(i) r##i = Channel == 0 ? unzigzag8(r##i) : (Channel == 1 ? unzigzag16(r##i) : rotate32(r##i, rot)) | | ------------------ | | | Branch (1458:24): [Folded, False: 314k] | | | Branch (1458:58): [True: 314k, Folded] | | ------------------ ------------------ 1487| 314k| GRP4(2); ------------------ | | 1435| 314k|#define GRP4(i) t0 = r##i, t1 = _mm_shuffle_epi32(r##i, 1), t2 = _mm_shuffle_epi32(r##i, 2), t3 = _mm_shuffle_epi32(r##i, 3) ------------------ 1488| 314k| FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1436| 314k|#define FIXD(i) t##i = pi = Channel == 0 ? _mm_add_epi8(pi, t##i) : (Channel == 1 ? _mm_add_epi16(pi, t##i) : _mm_xor_si128(pi, t##i)) | | ------------------ | | | Branch (1436:29): [Folded, False: 314k] | | | Branch (1436:70): [True: 314k, Folded] | | ------------------ ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1436| 314k|#define FIXD(i) t##i = pi = Channel == 0 ? _mm_add_epi8(pi, t##i) : (Channel == 1 ? _mm_add_epi16(pi, t##i) : _mm_xor_si128(pi, t##i)) | | ------------------ | | | Branch (1436:29): [Folded, False: 314k] | | | Branch (1436:70): [True: 314k, Folded] | | ------------------ ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1436| 314k|#define FIXD(i) t##i = pi = Channel == 0 ? _mm_add_epi8(pi, t##i) : (Channel == 1 ? _mm_add_epi16(pi, t##i) : _mm_xor_si128(pi, t##i)) | | ------------------ | | | Branch (1436:29): [Folded, False: 314k] | | | Branch (1436:70): [True: 314k, Folded] | | ------------------ ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1436| 314k|#define FIXD(i) t##i = pi = Channel == 0 ? _mm_add_epi8(pi, t##i) : (Channel == 1 ? _mm_add_epi16(pi, t##i) : _mm_xor_si128(pi, t##i)) | | ------------------ | | | Branch (1436:29): [Folded, False: 314k] | | | Branch (1436:70): [True: 314k, Folded] | | ------------------ ------------------ 1489| 314k| SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1437| 314k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1437| 314k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1437| 314k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1437| 314k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ 1490| | 1491| 314k| UNZR(3); ------------------ | | 1458| 314k|#define UNZR(i) r##i = Channel == 0 ? unzigzag8(r##i) : (Channel == 1 ? unzigzag16(r##i) : rotate32(r##i, rot)) | | ------------------ | | | Branch (1458:24): [Folded, False: 314k] | | | Branch (1458:58): [True: 314k, Folded] | | ------------------ ------------------ 1492| 314k| GRP4(3); ------------------ | | 1435| 314k|#define GRP4(i) t0 = r##i, t1 = _mm_shuffle_epi32(r##i, 1), t2 = _mm_shuffle_epi32(r##i, 2), t3 = _mm_shuffle_epi32(r##i, 3) ------------------ 1493| 314k| FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1436| 314k|#define FIXD(i) t##i = pi = Channel == 0 ? _mm_add_epi8(pi, t##i) : (Channel == 1 ? _mm_add_epi16(pi, t##i) : _mm_xor_si128(pi, t##i)) | | ------------------ | | | Branch (1436:29): [Folded, False: 314k] | | | Branch (1436:70): [True: 314k, Folded] | | ------------------ ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1436| 314k|#define FIXD(i) t##i = pi = Channel == 0 ? _mm_add_epi8(pi, t##i) : (Channel == 1 ? _mm_add_epi16(pi, t##i) : _mm_xor_si128(pi, t##i)) | | ------------------ | | | Branch (1436:29): [Folded, False: 314k] | | | Branch (1436:70): [True: 314k, Folded] | | ------------------ ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1436| 314k|#define FIXD(i) t##i = pi = Channel == 0 ? _mm_add_epi8(pi, t##i) : (Channel == 1 ? _mm_add_epi16(pi, t##i) : _mm_xor_si128(pi, t##i)) | | ------------------ | | | Branch (1436:29): [Folded, False: 314k] | | | Branch (1436:70): [True: 314k, Folded] | | ------------------ ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1436| 314k|#define FIXD(i) t##i = pi = Channel == 0 ? _mm_add_epi8(pi, t##i) : (Channel == 1 ? _mm_add_epi16(pi, t##i) : _mm_xor_si128(pi, t##i)) | | ------------------ | | | Branch (1436:29): [Folded, False: 314k] | | | Branch (1436:70): [True: 314k, Folded] | | ------------------ ------------------ 1494| 314k| SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1437| 314k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1437| 314k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1437| 314k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1437| 314k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ 1495| | 1496| |#if defined(SIMD_LATENCYOPT) && defined(SIMD_NEON) && (defined(__APPLE__) || defined(_WIN32)) 1497| | // instead of relying on accumulated pi, recompute it from scratch from r0..r3; this shortens dependency between loop iterations 1498| | pi = rebase(npi, r0, r1, r2, r3); 1499| |#else 1500| 314k| (void)npi; 1501| 314k|#endif 1502| | 1503| 314k|#undef UNZR 1504| 314k|#undef TEMP 1505| 314k|#undef PREP 1506| 314k|#undef LOAD 1507| 314k|#undef GRP4 1508| 314k|#undef FIXD 1509| 314k|#undef SAVE 1510| 314k| } 1511| 20.8k|} _ZN7meshopt10unzigzag16EDv2_x: 1242| 1.25M|{ 1243| 1.25M| __m128i xl = _mm_sub_epi16(_mm_setzero_si128(), _mm_and_si128(v, _mm_set1_epi16(1))); 1244| 1.25M| __m128i xr = _mm_srli_epi16(v, 1); 1245| | 1246| 1.25M| return _mm_xor_si128(xl, xr); 1247| 1.25M|} vertexcodec.cpp:_ZN7meshoptL17decodeDeltas4SimdILi2EEEvPKhPhmmS3_i: 1430| 22.2k|{ 1431| 22.2k|#if defined(SIMD_SSE) || defined(SIMD_AVX) 1432| 22.2k|#define TEMP __m128i 1433| 22.2k|#define PREP() __m128i pi = _mm_cvtsi32_si128(*reinterpret_cast(last_vertex)) 1434| 22.2k|#define LOAD(i) __m128i r##i = _mm_loadu_si128(reinterpret_cast(buffer + j + i * vertex_count_aligned)) 1435| 22.2k|#define GRP4(i) t0 = r##i, t1 = _mm_shuffle_epi32(r##i, 1), t2 = _mm_shuffle_epi32(r##i, 2), t3 = _mm_shuffle_epi32(r##i, 3) 1436| 22.2k|#define FIXD(i) t##i = pi = Channel == 0 ? _mm_add_epi8(pi, t##i) : (Channel == 1 ? _mm_add_epi16(pi, t##i) : _mm_xor_si128(pi, t##i)) 1437| 22.2k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size 1438| 22.2k|#endif 1439| | 1440| |#ifdef SIMD_NEON 1441| |#define TEMP uint8x8_t 1442| |#define PREP() uint8x8_t pi = vreinterpret_u8_u32(vld1_lane_u32(reinterpret_cast(last_vertex), vdup_n_u32(0), 0)) 1443| |#define LOAD(i) uint8x16_t r##i = vld1q_u8(buffer + j + i * vertex_count_aligned) 1444| |#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)) 1445| |#define FIXD(i) t##i = pi = Channel == 0 ? vadd_u8(pi, t##i) : (Channel == 1 ? vreinterpret_u8_u16(vadd_u16(vreinterpret_u16_u8(pi), vreinterpret_u16_u8(t##i))) : veor_u8(pi, t##i)) 1446| |#define SAVE(i) vst1_lane_u32(reinterpret_cast(savep), vreinterpret_u32_u8(t##i), 0), savep += vertex_size 1447| |#endif 1448| | 1449| |#ifdef SIMD_WASM 1450| |#define TEMP v128_t 1451| |#define PREP() v128_t pi = wasm_v128_load(last_vertex) 1452| |#define LOAD(i) v128_t r##i = wasm_v128_load(buffer + j + i * vertex_count_aligned) 1453| |#define GRP4(i) t0 = r##i, t1 = wasmx_splat_v32x4(r##i, 1), t2 = wasmx_splat_v32x4(r##i, 2), t3 = wasmx_splat_v32x4(r##i, 3) 1454| |#define FIXD(i) t##i = pi = Channel == 0 ? wasm_i8x16_add(pi, t##i) : (Channel == 1 ? wasm_i16x8_add(pi, t##i) : wasm_v128_xor(pi, t##i)) 1455| |#define SAVE(i) wasm_v128_store32_lane(savep, t##i, 0), savep += vertex_size 1456| |#endif 1457| | 1458| 22.2k|#define UNZR(i) r##i = Channel == 0 ? unzigzag8(r##i) : (Channel == 1 ? unzigzag16(r##i) : rotate32(r##i, rot)) 1459| | 1460| 22.2k| PREP(); ------------------ | | 1433| 22.2k|#define PREP() __m128i pi = _mm_cvtsi32_si128(*reinterpret_cast(last_vertex)) ------------------ 1461| | 1462| 22.2k| unsigned char* savep = transposed; 1463| | 1464| 364k| for (size_t j = 0; j < vertex_count_aligned; j += 16) ------------------ | Branch (1464:21): [True: 341k, False: 22.2k] ------------------ 1465| 341k| { 1466| 341k| LOAD(0); ------------------ | | 1434| 341k|#define LOAD(i) __m128i r##i = _mm_loadu_si128(reinterpret_cast(buffer + j + i * vertex_count_aligned)) ------------------ 1467| 341k| LOAD(1); ------------------ | | 1434| 341k|#define LOAD(i) __m128i r##i = _mm_loadu_si128(reinterpret_cast(buffer + j + i * vertex_count_aligned)) ------------------ 1468| 341k| LOAD(2); ------------------ | | 1434| 341k|#define LOAD(i) __m128i r##i = _mm_loadu_si128(reinterpret_cast(buffer + j + i * vertex_count_aligned)) ------------------ 1469| 341k| LOAD(3); ------------------ | | 1434| 341k|#define LOAD(i) __m128i r##i = _mm_loadu_si128(reinterpret_cast(buffer + j + i * vertex_count_aligned)) ------------------ 1470| | 1471| 341k| transpose8(r0, r1, r2, r3); 1472| | 1473| 341k| TEMP t0, t1, t2, t3; ------------------ | | 1432| 341k|#define TEMP __m128i ------------------ 1474| 341k| TEMP npi = pi; ------------------ | | 1432| 341k|#define TEMP __m128i ------------------ 1475| | 1476| 341k| UNZR(0); ------------------ | | 1458| 341k|#define UNZR(i) r##i = Channel == 0 ? unzigzag8(r##i) : (Channel == 1 ? unzigzag16(r##i) : rotate32(r##i, rot)) | | ------------------ | | | Branch (1458:24): [Folded, False: 341k] | | | Branch (1458:58): [Folded, False: 341k] | | ------------------ ------------------ 1477| 341k| GRP4(0); ------------------ | | 1435| 341k|#define GRP4(i) t0 = r##i, t1 = _mm_shuffle_epi32(r##i, 1), t2 = _mm_shuffle_epi32(r##i, 2), t3 = _mm_shuffle_epi32(r##i, 3) ------------------ 1478| 341k| FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1436| 341k|#define FIXD(i) t##i = pi = Channel == 0 ? _mm_add_epi8(pi, t##i) : (Channel == 1 ? _mm_add_epi16(pi, t##i) : _mm_xor_si128(pi, t##i)) | | ------------------ | | | Branch (1436:29): [Folded, False: 341k] | | | Branch (1436:70): [Folded, False: 341k] | | ------------------ ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1436| 341k|#define FIXD(i) t##i = pi = Channel == 0 ? _mm_add_epi8(pi, t##i) : (Channel == 1 ? _mm_add_epi16(pi, t##i) : _mm_xor_si128(pi, t##i)) | | ------------------ | | | Branch (1436:29): [Folded, False: 341k] | | | Branch (1436:70): [Folded, False: 341k] | | ------------------ ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1436| 341k|#define FIXD(i) t##i = pi = Channel == 0 ? _mm_add_epi8(pi, t##i) : (Channel == 1 ? _mm_add_epi16(pi, t##i) : _mm_xor_si128(pi, t##i)) | | ------------------ | | | Branch (1436:29): [Folded, False: 341k] | | | Branch (1436:70): [Folded, False: 341k] | | ------------------ ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1436| 341k|#define FIXD(i) t##i = pi = Channel == 0 ? _mm_add_epi8(pi, t##i) : (Channel == 1 ? _mm_add_epi16(pi, t##i) : _mm_xor_si128(pi, t##i)) | | ------------------ | | | Branch (1436:29): [Folded, False: 341k] | | | Branch (1436:70): [Folded, False: 341k] | | ------------------ ------------------ 1479| 341k| SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1437| 341k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1437| 341k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1437| 341k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1437| 341k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ 1480| | 1481| 341k| UNZR(1); ------------------ | | 1458| 341k|#define UNZR(i) r##i = Channel == 0 ? unzigzag8(r##i) : (Channel == 1 ? unzigzag16(r##i) : rotate32(r##i, rot)) | | ------------------ | | | Branch (1458:24): [Folded, False: 341k] | | | Branch (1458:58): [Folded, False: 341k] | | ------------------ ------------------ 1482| 341k| GRP4(1); ------------------ | | 1435| 341k|#define GRP4(i) t0 = r##i, t1 = _mm_shuffle_epi32(r##i, 1), t2 = _mm_shuffle_epi32(r##i, 2), t3 = _mm_shuffle_epi32(r##i, 3) ------------------ 1483| 341k| FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1436| 341k|#define FIXD(i) t##i = pi = Channel == 0 ? _mm_add_epi8(pi, t##i) : (Channel == 1 ? _mm_add_epi16(pi, t##i) : _mm_xor_si128(pi, t##i)) | | ------------------ | | | Branch (1436:29): [Folded, False: 341k] | | | Branch (1436:70): [Folded, False: 341k] | | ------------------ ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1436| 341k|#define FIXD(i) t##i = pi = Channel == 0 ? _mm_add_epi8(pi, t##i) : (Channel == 1 ? _mm_add_epi16(pi, t##i) : _mm_xor_si128(pi, t##i)) | | ------------------ | | | Branch (1436:29): [Folded, False: 341k] | | | Branch (1436:70): [Folded, False: 341k] | | ------------------ ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1436| 341k|#define FIXD(i) t##i = pi = Channel == 0 ? _mm_add_epi8(pi, t##i) : (Channel == 1 ? _mm_add_epi16(pi, t##i) : _mm_xor_si128(pi, t##i)) | | ------------------ | | | Branch (1436:29): [Folded, False: 341k] | | | Branch (1436:70): [Folded, False: 341k] | | ------------------ ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1436| 341k|#define FIXD(i) t##i = pi = Channel == 0 ? _mm_add_epi8(pi, t##i) : (Channel == 1 ? _mm_add_epi16(pi, t##i) : _mm_xor_si128(pi, t##i)) | | ------------------ | | | Branch (1436:29): [Folded, False: 341k] | | | Branch (1436:70): [Folded, False: 341k] | | ------------------ ------------------ 1484| 341k| SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1437| 341k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1437| 341k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1437| 341k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1437| 341k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ 1485| | 1486| 341k| UNZR(2); ------------------ | | 1458| 341k|#define UNZR(i) r##i = Channel == 0 ? unzigzag8(r##i) : (Channel == 1 ? unzigzag16(r##i) : rotate32(r##i, rot)) | | ------------------ | | | Branch (1458:24): [Folded, False: 341k] | | | Branch (1458:58): [Folded, False: 341k] | | ------------------ ------------------ 1487| 341k| GRP4(2); ------------------ | | 1435| 341k|#define GRP4(i) t0 = r##i, t1 = _mm_shuffle_epi32(r##i, 1), t2 = _mm_shuffle_epi32(r##i, 2), t3 = _mm_shuffle_epi32(r##i, 3) ------------------ 1488| 341k| FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1436| 341k|#define FIXD(i) t##i = pi = Channel == 0 ? _mm_add_epi8(pi, t##i) : (Channel == 1 ? _mm_add_epi16(pi, t##i) : _mm_xor_si128(pi, t##i)) | | ------------------ | | | Branch (1436:29): [Folded, False: 341k] | | | Branch (1436:70): [Folded, False: 341k] | | ------------------ ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1436| 341k|#define FIXD(i) t##i = pi = Channel == 0 ? _mm_add_epi8(pi, t##i) : (Channel == 1 ? _mm_add_epi16(pi, t##i) : _mm_xor_si128(pi, t##i)) | | ------------------ | | | Branch (1436:29): [Folded, False: 341k] | | | Branch (1436:70): [Folded, False: 341k] | | ------------------ ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1436| 341k|#define FIXD(i) t##i = pi = Channel == 0 ? _mm_add_epi8(pi, t##i) : (Channel == 1 ? _mm_add_epi16(pi, t##i) : _mm_xor_si128(pi, t##i)) | | ------------------ | | | Branch (1436:29): [Folded, False: 341k] | | | Branch (1436:70): [Folded, False: 341k] | | ------------------ ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1436| 341k|#define FIXD(i) t##i = pi = Channel == 0 ? _mm_add_epi8(pi, t##i) : (Channel == 1 ? _mm_add_epi16(pi, t##i) : _mm_xor_si128(pi, t##i)) | | ------------------ | | | Branch (1436:29): [Folded, False: 341k] | | | Branch (1436:70): [Folded, False: 341k] | | ------------------ ------------------ 1489| 341k| SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1437| 341k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1437| 341k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1437| 341k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1437| 341k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ 1490| | 1491| 341k| UNZR(3); ------------------ | | 1458| 341k|#define UNZR(i) r##i = Channel == 0 ? unzigzag8(r##i) : (Channel == 1 ? unzigzag16(r##i) : rotate32(r##i, rot)) | | ------------------ | | | Branch (1458:24): [Folded, False: 341k] | | | Branch (1458:58): [Folded, False: 341k] | | ------------------ ------------------ 1492| 341k| GRP4(3); ------------------ | | 1435| 341k|#define GRP4(i) t0 = r##i, t1 = _mm_shuffle_epi32(r##i, 1), t2 = _mm_shuffle_epi32(r##i, 2), t3 = _mm_shuffle_epi32(r##i, 3) ------------------ 1493| 341k| FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1436| 341k|#define FIXD(i) t##i = pi = Channel == 0 ? _mm_add_epi8(pi, t##i) : (Channel == 1 ? _mm_add_epi16(pi, t##i) : _mm_xor_si128(pi, t##i)) | | ------------------ | | | Branch (1436:29): [Folded, False: 341k] | | | Branch (1436:70): [Folded, False: 341k] | | ------------------ ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1436| 341k|#define FIXD(i) t##i = pi = Channel == 0 ? _mm_add_epi8(pi, t##i) : (Channel == 1 ? _mm_add_epi16(pi, t##i) : _mm_xor_si128(pi, t##i)) | | ------------------ | | | Branch (1436:29): [Folded, False: 341k] | | | Branch (1436:70): [Folded, False: 341k] | | ------------------ ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1436| 341k|#define FIXD(i) t##i = pi = Channel == 0 ? _mm_add_epi8(pi, t##i) : (Channel == 1 ? _mm_add_epi16(pi, t##i) : _mm_xor_si128(pi, t##i)) | | ------------------ | | | Branch (1436:29): [Folded, False: 341k] | | | Branch (1436:70): [Folded, False: 341k] | | ------------------ ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1436| 341k|#define FIXD(i) t##i = pi = Channel == 0 ? _mm_add_epi8(pi, t##i) : (Channel == 1 ? _mm_add_epi16(pi, t##i) : _mm_xor_si128(pi, t##i)) | | ------------------ | | | Branch (1436:29): [Folded, False: 341k] | | | Branch (1436:70): [Folded, False: 341k] | | ------------------ ------------------ 1494| 341k| SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1437| 341k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1437| 341k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1437| 341k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1437| 341k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ 1495| | 1496| |#if defined(SIMD_LATENCYOPT) && defined(SIMD_NEON) && (defined(__APPLE__) || defined(_WIN32)) 1497| | // instead of relying on accumulated pi, recompute it from scratch from r0..r3; this shortens dependency between loop iterations 1498| | pi = rebase(npi, r0, r1, r2, r3); 1499| |#else 1500| 341k| (void)npi; 1501| 341k|#endif 1502| | 1503| 341k|#undef UNZR 1504| 341k|#undef TEMP 1505| 341k|#undef PREP 1506| 341k|#undef LOAD 1507| 341k|#undef GRP4 1508| 341k|#undef FIXD 1509| 341k|#undef SAVE 1510| 341k| } 1511| 22.2k|} _ZN7meshopt8rotate32EDv2_xi: 1251| 1.36M|{ 1252| 1.36M| return _mm_or_si128(_mm_slli_epi32(v, r), _mm_srli_epi32(v, 32 - r)); 1253| 1.36M|} _Z11fuzzDecoderPKhmmPFiPvmmS0_mE: 8| 17.3k|{ 9| 17.3k| size_t count = 66; // must be divisible by 3 for decodeIndexBuffer; should be >=64 to cover large vertex blocks 10| | 11| 17.3k| void* destination = malloc(count * stride); 12| 17.3k| assert(destination); ------------------ | Branch (12:2): [True: 17.3k, False: 0] ------------------ 13| | 14| 17.3k| int rc = decode(destination, count, stride, reinterpret_cast(data), size); 15| 17.3k| (void)rc; 16| | 17| 17.3k| free(destination); 18| 17.3k|} _Z13fuzzRoundtripPKhmmi: 21| 8.67k|{ 22| 8.67k| size_t count = size / stride; 23| | 24| 8.67k| size_t bound = meshopt_encodeVertexBufferBound(count, stride); 25| 8.67k| void* encoded = malloc(bound); 26| 8.67k| void* decoded = malloc(count * stride); 27| 8.67k| assert(encoded && decoded); ------------------ | Branch (27:2): [True: 8.67k, False: 0] | Branch (27:2): [True: 8.67k, False: 0] | Branch (27:2): [True: 8.67k, False: 0] ------------------ 28| | 29| 8.67k| size_t res = meshopt_encodeVertexBufferLevel(static_cast(encoded), bound, data, count, stride, level, -1); 30| 8.67k| assert(res > 0 && res <= bound); ------------------ | Branch (30:2): [True: 8.67k, False: 0] | Branch (30:2): [True: 8.67k, False: 0] | Branch (30:2): [True: 8.67k, False: 0] ------------------ 31| | 32| | // encode again at the boundary to check for memory safety 33| | // this should produce the same output because encoder is deterministic 34| 8.67k| size_t rese = meshopt_encodeVertexBufferLevel(static_cast(encoded) + bound - res, res, data, count, stride, level, -1); 35| 8.67k| assert(rese == res); ------------------ | Branch (35:2): [True: 8.67k, False: 0] ------------------ 36| | 37| 8.67k| int rc = meshopt_decodeVertexBuffer(decoded, count, stride, static_cast(encoded) + bound - res, res); 38| 8.67k| assert(rc == 0); ------------------ | Branch (38:2): [True: 8.67k, False: 0] ------------------ 39| | 40| 8.67k| assert(memcmp(data, decoded, count * stride) == 0); ------------------ | Branch (40:2): [True: 8.67k, False: 0] ------------------ 41| | 42| 8.67k| free(decoded); 43| 8.67k| free(encoded); 44| 8.67k|} _Z5alignmm: 47| 12.9k|{ 48| 12.9k| return (value + alignment - 1) & ~(alignment - 1); 49| 12.9k|} _Z17fuzzDecodeMeshletmmPKhm: 52| 2.15k|{ 53| | // raw decoding: allowed to write align(count, 4) elements 54| 2.15k| unsigned int rt[256]; 55| 2.15k| unsigned int rv[256]; 56| 2.15k| meshopt_decodeMeshletRaw(rv + 256 - align(vertex_count, 4), vertex_count, rt + 256 - align(triangle_count, 4), triangle_count, data, size); 57| | 58| | // regular decoding: allowed to write align(count * size, 4) bytes 59| | // with variations for 3-byte triangles and 2-byte vertex references 60| 2.15k| unsigned short rsv[256]; 61| 2.15k| unsigned char rbt[256 * 3]; 62| | 63| 2.15k| meshopt_decodeMeshlet(rv + 256 - vertex_count, vertex_count, 4, rt + 256 - triangle_count, triangle_count, 4, data, size); 64| 2.15k| meshopt_decodeMeshlet(rsv + 256 - align(vertex_count, 2), vertex_count, 2, rt + 256 - triangle_count, triangle_count, 4, data, size); 65| 2.15k| meshopt_decodeMeshlet(rv + 256 - vertex_count, vertex_count, 4, rbt + 256 * 3 - align(triangle_count * 3, 4), triangle_count, 3, data, size); 66| 2.15k| meshopt_decodeMeshlet(rsv + 256 - align(vertex_count, 2), vertex_count, 2, rbt + 256 * 3 - align(triangle_count * 3, 4), triangle_count, 3, data, size); 67| 2.15k|} _Z20fuzzRoundtripMeshletPKhm: 70| 2.16k|{ 71| 2.16k| size_t triangle_count = size / 3; 72| 2.16k| if (triangle_count > 256) ------------------ | Branch (72:6): [True: 526, False: 1.64k] ------------------ 73| 526| triangle_count = 256; 74| | 75| 2.16k| unsigned char buf[4096]; 76| 2.16k| size_t enc = meshopt_encodeMeshlet(buf, sizeof(buf), NULL, 0, reinterpret_cast(data), triangle_count); 77| 2.16k| assert(enc > 0); ------------------ | Branch (77:2): [True: 2.16k, False: 0] ------------------ 78| 2.16k| assert(enc <= meshopt_encodeMeshletBound(0, triangle_count)); ------------------ | Branch (78:2): [True: 2.16k, False: 0] ------------------ 79| | 80| 2.16k| unsigned int rt4[256]; 81| 2.16k| int rc4 = meshopt_decodeMeshlet(static_cast(NULL), 0, rt4, triangle_count, buf, enc); 82| 2.16k| assert(rc4 == 0); ------------------ | Branch (82:2): [True: 2.16k, False: 0] ------------------ 83| | 84| 179k| for (size_t i = 0; i < triangle_count; ++i) ------------------ | Branch (84:21): [True: 177k, False: 2.16k] ------------------ 85| 177k| { 86| 177k| unsigned char a = data[i * 3 + 0], b = data[i * 3 + 1], c = data[i * 3 + 2]; 87| | 88| 177k| unsigned int abc = (a << 0) | (b << 8) | (c << 16); 89| 177k| unsigned int bca = (b << 0) | (c << 8) | (a << 16); 90| 177k| unsigned int cba = (c << 0) | (a << 8) | (b << 16); 91| | 92| 177k| unsigned int tri = rt4[i]; 93| | 94| 177k| assert(tri == abc || tri == bca || tri == cba); ------------------ | Branch (94:3): [True: 109k, False: 67.7k] | Branch (94:3): [True: 34.9k, False: 32.7k] | Branch (94:3): [True: 32.7k, False: 0] | Branch (94:3): [True: 177k, False: 0] ------------------ 95| 177k| } 96| | 97| 2.16k| unsigned char rt3[256 * 3]; 98| 2.16k| int rc3 = meshopt_decodeMeshlet(static_cast(NULL), 0, rt3, triangle_count, buf, enc); 99| 2.16k| assert(rc3 == 0); ------------------ | Branch (99:2): [True: 2.16k, False: 0] ------------------ 100| | 101| 179k| for (size_t i = 0; i < triangle_count; ++i) ------------------ | Branch (101:21): [True: 177k, False: 2.16k] ------------------ 102| 177k| { 103| 177k| unsigned char a = data[i * 3 + 0], b = data[i * 3 + 1], c = data[i * 3 + 2]; 104| | 105| 177k| unsigned int abc = (a << 0) | (b << 8) | (c << 16); 106| 177k| unsigned int bca = (b << 0) | (c << 8) | (a << 16); 107| 177k| unsigned int cba = (c << 0) | (a << 8) | (b << 16); 108| | 109| 177k| unsigned int tri = rt3[i * 3 + 0] | (rt3[i * 3 + 1] << 8) | (rt3[i * 3 + 2] << 16); 110| | 111| | assert(tri == abc || tri == bca || tri == cba); ------------------ | Branch (111:3): [True: 109k, False: 67.7k] | Branch (111:3): [True: 34.9k, False: 32.7k] | Branch (111:3): [True: 32.7k, False: 0] | Branch (111:3): [True: 177k, False: 0] ------------------ 112| 177k| } 113| 2.16k|} _Z21fuzzRoundtripMeshletVPKhm: 116| 2.16k|{ 117| 2.16k| size_t vertex_count = size / 4; 118| 2.16k| if (vertex_count > 256) ------------------ | Branch (118:6): [True: 478, False: 1.69k] ------------------ 119| 478| vertex_count = 256; 120| | 121| 2.16k| unsigned char tri[4] = {0, 1, 2}; 122| | 123| 2.16k| unsigned char buf[4096]; 124| 2.16k| size_t enc = meshopt_encodeMeshlet(buf, sizeof(buf), reinterpret_cast(data), vertex_count, tri, 1); 125| 2.16k| assert(enc > 0); ------------------ | Branch (125:2): [True: 2.16k, False: 0] ------------------ 126| 2.16k| assert(enc <= meshopt_encodeMeshletBound(vertex_count, 1)); ------------------ | Branch (126:2): [True: 2.16k, False: 0] ------------------ 127| | 128| 2.16k| unsigned int rv4[256]; 129| 2.16k| int rc4 = meshopt_decodeMeshlet(rv4, vertex_count, tri, 1, buf, enc); 130| 2.16k| assert(rc4 == 0); ------------------ | Branch (130:2): [True: 2.16k, False: 0] ------------------ 131| | 132| 167k| for (size_t i = 0; i < vertex_count; ++i) ------------------ | Branch (132:21): [True: 165k, False: 2.16k] ------------------ 133| 165k| assert(rv4[i] == reinterpret_cast(data)[i]); ------------------ | Branch (133:3): [True: 165k, False: 0] ------------------ 134| | 135| 2.16k| unsigned short rv2[256]; 136| 2.16k| int rc2 = meshopt_decodeMeshlet(rv2, vertex_count, tri, 1, buf, enc); 137| 2.16k| assert(rc2 == 0); ------------------ | Branch (137:2): [True: 2.16k, False: 0] ------------------ 138| | 139| 167k| for (size_t i = 0; i < vertex_count; ++i) ------------------ | Branch (139:21): [True: 165k, False: 2.16k] ------------------ 140| | assert(rv2[i] == uint16_t(reinterpret_cast(data)[i])); ------------------ | Branch (140:3): [True: 165k, False: 0] ------------------ 141| 2.16k|} LLVMFuzzerTestOneInput: 144| 2.16k|{ 145| | // decodeIndexBuffer supports 2 and 4-byte indices 146| 2.16k| fuzzDecoder(data, size, 2, meshopt_decodeIndexBuffer); 147| 2.16k| fuzzDecoder(data, size, 4, meshopt_decodeIndexBuffer); 148| | 149| | // decodeIndexSequence supports 2 and 4-byte indices 150| 2.16k| fuzzDecoder(data, size, 2, meshopt_decodeIndexSequence); 151| 2.16k| fuzzDecoder(data, size, 4, meshopt_decodeIndexSequence); 152| | 153| | // decodeVertexBuffer supports any strides divisible by 4 in 4-256 interval 154| | // it's a waste of time to check all of them, so we'll just check a few with different alignment mod 16 155| 2.16k| fuzzDecoder(data, size, 4, meshopt_decodeVertexBuffer); 156| 2.16k| fuzzDecoder(data, size, 16, meshopt_decodeVertexBuffer); 157| 2.16k| fuzzDecoder(data, size, 24, meshopt_decodeVertexBuffer); 158| 2.16k| fuzzDecoder(data, size, 32, meshopt_decodeVertexBuffer); 159| | 160| | // encodeVertexBuffer/decodeVertexBuffer should roundtrip for any stride, check a few with different alignment mod 16 161| | // this also checks memory safety properties of the encoder 162| | // to conserve time, we only check one version/level combination, biased towards version 1 163| 2.16k| uint8_t data0 = size > 0 ? data[0] : 0; ------------------ | Branch (163:18): [True: 2.16k, False: 0] ------------------ 164| 2.16k| int level = data0 % 5; 165| | 166| 2.16k| meshopt_encodeVertexVersion(level < 4 ? 1 : 0); ------------------ | Branch (166:30): [True: 1.72k, False: 448] ------------------ 167| | 168| 2.16k| fuzzRoundtrip(data, size, 4, level); 169| 2.16k| fuzzRoundtrip(data, size, 16, level); 170| 2.16k| fuzzRoundtrip(data, size, 24, level); 171| 2.16k| fuzzRoundtrip(data, size, 32, level); 172| | 173| | // validate that decodeMeshlet works on untrusted data and is memory safe within documented limits 174| 2.16k| if (size > 2) ------------------ | Branch (174:6): [True: 2.15k, False: 14] ------------------ 175| 2.15k| fuzzDecodeMeshlet(data[0] + 1, data[1] + 1, reinterpret_cast(data + 2), size - 2); 176| | 177| | // validate that index data roundtrips in meshlet encoding modulo rotation 178| 2.16k| fuzzRoundtripMeshlet(data, size); 179| | 180| | // validate that vertex data roundtrips in meshlet encoding 181| 2.16k| fuzzRoundtripMeshletV(data, size); 182| | 183| 2.16k| return 0; 184| 2.16k|}