meshopt_decodeIndexBuffer: 390| 3.77k|{ 391| 3.77k| using namespace meshopt; 392| | 393| 3.77k| assert(index_count % 3 == 0); ------------------ | Branch (393:2): [True: 3.77k, False: 0] ------------------ 394| 3.77k| assert(index_size == 2 || index_size == 4); ------------------ | Branch (394:2): [True: 1.88k, False: 1.88k] | Branch (394:2): [True: 1.88k, False: 0] | Branch (394:2): [True: 3.77k, False: 0] ------------------ 395| | 396| | // the minimum valid encoding is header, 1 byte per triangle and a 16-byte codeaux table 397| 3.77k| if (buffer_size < 1 + index_count / 3 + 16) ------------------ | Branch (397:6): [True: 1.58k, False: 2.19k] ------------------ 398| 1.58k| return -2; 399| | 400| 2.19k| if ((buffer[0] & 0xf0) != kIndexHeader) ------------------ | Branch (400:6): [True: 1.54k, False: 644] ------------------ 401| 1.54k| return -1; 402| | 403| 644| int version = buffer[0] & 0x0f; 404| 644| if (version > kDecodeIndexVersion) ------------------ | Branch (404:6): [True: 72, False: 572] ------------------ 405| 72| return -1; 406| | 407| 572| EdgeFifo edgefifo; 408| 572| memset(edgefifo, -1, sizeof(edgefifo)); 409| | 410| 572| VertexFifo vertexfifo; 411| 572| memset(vertexfifo, -1, sizeof(vertexfifo)); 412| | 413| 572| size_t edgefifooffset = 0; 414| 572| size_t vertexfifooffset = 0; 415| | 416| 572| unsigned int next = 0; 417| 572| unsigned int last = 0; 418| | 419| 572| int fecmax = version >= 1 ? 13 : 15; ------------------ | Branch (419:15): [True: 128, False: 444] ------------------ 420| | 421| | // since we store 16-byte codeaux table at the end, triangle data has to begin before data_safe_end 422| 572| const unsigned char* code = buffer + 1; 423| 572| const unsigned char* code_end = code + index_count / 3; 424| 572| const unsigned char* data = code_end; 425| | 426| | // each triangle reads at most 16 bytes of data: 1b for codeaux and 5b for each free index 427| 572| const unsigned char* data_safe_end = buffer + buffer_size - 16; 428| | 429| 572| const unsigned char* codeaux_table = data_safe_end; 430| | 431| 10.1k| while (code < code_end) ------------------ | Branch (431:9): [True: 9.86k, False: 306] ------------------ 432| 9.86k| { 433| 9.86k| unsigned char codetri = *code++; 434| | 435| 9.86k| if (codetri < 0xf0) ------------------ | Branch (435:7): [True: 5.77k, False: 4.09k] ------------------ 436| 5.77k| { 437| 5.77k| int fe = codetri >> 4; 438| | 439| | // fifo reads are wrapped around 16 entry buffer 440| 5.77k| unsigned int a = edgefifo[(edgefifooffset - 1 - fe) & 15][0]; 441| 5.77k| unsigned int b = edgefifo[(edgefifooffset - 1 - fe) & 15][1]; 442| 5.77k| unsigned int c = 0; 443| | 444| 5.77k| int fec = codetri & 15; 445| | 446| | // note: this is the most common path in the entire decoder 447| | // inside this if we try to stay branchless (by using cmov/etc.) since these aren't predictable 448| 5.77k| if (fec < fecmax) ------------------ | Branch (448:8): [True: 4.77k, False: 1.00k] ------------------ 449| 4.77k| { 450| | // fifo reads are wrapped around 16 entry buffer 451| 4.77k| unsigned int cf = vertexfifo[(vertexfifooffset - 1 - fec) & 15]; 452| | 453| 4.77k|#if (defined(__GNUC__) || defined(__clang__)) && (defined(__x86_64__) || defined(__aarch64__)) 454| | // on clang, x86-cmov-conversion pass emits a branch since cf is a load from memory; asm barrier defeats this 455| | // this can be fixed with __builtin_unpredictable, but gcc doesn't support it and has a similar problem due to if-conversion 456| | // additionally, gcc can fuse a/b into one 64-bit load but use 32-bit edgefifo[] stores, which breaks load store forwarding 457| 4.77k| __asm__("" : "+r"(a) : "r"(cf)); 458| 4.77k|#endif 459| | 460| 4.77k| c = (fec == 0) ? next : cf; ------------------ | Branch (460:9): [True: 1.79k, False: 2.97k] ------------------ 461| | 462| 4.77k| int fec0 = fec == 0; 463| 4.77k| next += fec0; 464| | 465| | // push vertex fifo must match the encoding step *exactly* otherwise the data will not be decoded correctly 466| 4.77k| pushVertexFifo(vertexfifo, c, vertexfifooffset, fec0); 467| 4.77k| } 468| 1.00k| else 469| 1.00k| { 470| | // make sure we have enough data to read for a triangle; this check covers worst case advance 471| 1.00k| if (data > data_safe_end) ------------------ | Branch (471:9): [True: 72, False: 932] ------------------ 472| 72| return -2; 473| | 474| | // fec * 2 - 27 decodes 13, 14 into -1, 1 475| | // note that we need to update the last index since free indices are delta-encoded 476| 932| last = c = (fec != 15) ? last + (fec * 2 - 27) : decodeIndex(data, last); ------------------ | Branch (476:16): [True: 180, False: 752] ------------------ 477| | 478| | // push vertex/edge fifo must match the encoding step *exactly* otherwise the data will not be decoded correctly 479| 932| pushVertexFifo(vertexfifo, c, vertexfifooffset); 480| 932| } 481| | 482| | // push edge fifo must match the encoding step *exactly* otherwise the data will not be decoded correctly 483| 5.70k| pushEdgeFifo(edgefifo, c, b, edgefifooffset); 484| 5.70k| pushEdgeFifo(edgefifo, a, c, edgefifooffset); 485| | 486| | // output triangle 487| 5.70k| destination = writeTriangle(destination, index_size, a, b, c); 488| 5.70k| } 489| 4.09k| else 490| 4.09k| { 491| | // fast path: read codeaux from the table 492| 4.09k| if (codetri < 0xfe) ------------------ | Branch (492:8): [True: 1.29k, False: 2.79k] ------------------ 493| 1.29k| { 494| 1.29k| unsigned char codeaux = codeaux_table[codetri & 15]; 495| | 496| | // note: table can't contain feb/fec=15 497| 1.29k| int feb = codeaux >> 4; 498| 1.29k| int fec = codeaux & 15; 499| | 500| | // fifo reads are wrapped around 16 entry buffer 501| | // also note that we increment next for all three vertices before decoding indices - this matches encoder behavior 502| 1.29k| unsigned int a = next++; 503| | 504| 1.29k| unsigned int bf = vertexfifo[(vertexfifooffset - feb) & 15]; 505| 1.29k| unsigned int b = (feb == 0) ? next : bf; ------------------ | Branch (505:22): [True: 504, False: 790] ------------------ 506| | 507| 1.29k| int feb0 = feb == 0; 508| 1.29k| next += feb0; 509| | 510| 1.29k| unsigned int cf = vertexfifo[(vertexfifooffset - fec) & 15]; 511| 1.29k| unsigned int c = (fec == 0) ? next : cf; ------------------ | Branch (511:22): [True: 358, False: 936] ------------------ 512| | 513| 1.29k| int fec0 = fec == 0; 514| 1.29k| next += fec0; 515| | 516| | // output triangle 517| 1.29k| destination = writeTriangle(destination, index_size, a, b, c); 518| | 519| | // push vertex/edge fifo must match the encoding step *exactly* otherwise the data will not be decoded correctly 520| 1.29k| pushVertexFifo(vertexfifo, a, vertexfifooffset); 521| 1.29k| pushVertexFifo(vertexfifo, b, vertexfifooffset, feb0); 522| 1.29k| pushVertexFifo(vertexfifo, c, vertexfifooffset, fec0); 523| | 524| 1.29k| pushEdgeFifo(edgefifo, b, a, edgefifooffset); 525| 1.29k| pushEdgeFifo(edgefifo, c, b, edgefifooffset); 526| 1.29k| pushEdgeFifo(edgefifo, a, c, edgefifooffset); 527| 1.29k| } 528| 2.79k| else 529| 2.79k| { 530| | // make sure we have enough data to read for a triangle; this check covers worst case advance 531| 2.79k| if (data > data_safe_end) ------------------ | Branch (531:9): [True: 194, False: 2.60k] ------------------ 532| 194| return -2; 533| | 534| | // slow path: read a full byte for codeaux instead of using a table lookup 535| 2.60k| unsigned char codeaux = *data++; 536| | 537| 2.60k| int fea = codetri == 0xfe ? 0 : 15; ------------------ | Branch (537:15): [True: 1.03k, False: 1.57k] ------------------ 538| 2.60k| int feb = codeaux >> 4; 539| 2.60k| int fec = codeaux & 15; 540| | 541| | // reset: codeaux is 0 but encoded as not-a-table 542| 2.60k| if (codeaux == 0) ------------------ | Branch (542:9): [True: 606, False: 1.99k] ------------------ 543| 606| next = 0; 544| | 545| | // fifo reads are wrapped around 16 entry buffer 546| | // also note that we increment next for all three vertices before decoding indices - this matches encoder behavior 547| 2.60k| unsigned int a = (fea == 0) ? next++ : 0; ------------------ | Branch (547:22): [True: 1.03k, False: 1.57k] ------------------ 548| 2.60k| unsigned int b = (feb == 0) ? next++ : vertexfifo[(vertexfifooffset - feb) & 15]; ------------------ | Branch (548:22): [True: 742, False: 1.86k] ------------------ 549| 2.60k| unsigned int c = (fec == 0) ? next++ : vertexfifo[(vertexfifooffset - fec) & 15]; ------------------ | Branch (549:22): [True: 836, False: 1.76k] ------------------ 550| | 551| | // note that we need to update the last index since free indices are delta-encoded 552| 2.60k| if (fea == 15) ------------------ | Branch (552:9): [True: 1.57k, False: 1.03k] ------------------ 553| 1.57k| last = a = decodeIndex(data, last); 554| | 555| 2.60k| if (feb == 15) ------------------ | Branch (555:9): [True: 850, False: 1.75k] ------------------ 556| 850| last = b = decodeIndex(data, last); 557| | 558| 2.60k| if (fec == 15) ------------------ | Branch (558:9): [True: 764, False: 1.84k] ------------------ 559| 764| last = c = decodeIndex(data, last); 560| | 561| | // output triangle 562| 2.60k| destination = writeTriangle(destination, index_size, a, b, c); 563| | 564| | // push vertex/edge fifo must match the encoding step *exactly* otherwise the data will not be decoded correctly 565| 2.60k| pushVertexFifo(vertexfifo, a, vertexfifooffset); 566| 2.60k| pushVertexFifo(vertexfifo, b, vertexfifooffset, (feb == 0) | (feb == 15)); 567| 2.60k| pushVertexFifo(vertexfifo, c, vertexfifooffset, (fec == 0) | (fec == 15)); 568| | 569| 2.60k| pushEdgeFifo(edgefifo, b, a, edgefifooffset); 570| 2.60k| pushEdgeFifo(edgefifo, c, b, edgefifooffset); 571| 2.60k| pushEdgeFifo(edgefifo, a, c, edgefifooffset); 572| 2.60k| } 573| 4.09k| } 574| 9.86k| } 575| | 576| | // we should've read all data bytes and stopped at the boundary between data and codeaux table 577| 306| if (data != data_safe_end) ------------------ | Branch (577:6): [True: 286, False: 20] ------------------ 578| 286| return -3; 579| | 580| 20| return 0; 581| 306|} meshopt_decodeIndexSequence: 653| 3.77k|{ 654| 3.77k| using namespace meshopt; 655| | 656| | // the minimum valid encoding is header, 1 byte per index and a 4-byte tail 657| 3.77k| if (buffer_size < 1 + index_count + 4) ------------------ | Branch (657:6): [True: 2.17k, False: 1.60k] ------------------ 658| 2.17k| return -2; 659| | 660| 1.60k| if ((buffer[0] & 0xf0) != kSequenceHeader) ------------------ | Branch (660:6): [True: 1.24k, False: 364] ------------------ 661| 1.24k| return -1; 662| | 663| 364| int version = buffer[0] & 0x0f; 664| 364| if (version > kDecodeIndexVersion) ------------------ | Branch (664:6): [True: 26, False: 338] ------------------ 665| 26| return -1; 666| | 667| 338| const unsigned char* data = buffer + 1; 668| 338| const unsigned char* data_safe_end = buffer + buffer_size - 4; 669| | 670| 338| unsigned int last[2] = {}; 671| | 672| 20.8k| for (size_t i = 0; i < index_count; ++i) ------------------ | Branch (672:21): [True: 20.5k, False: 266] ------------------ 673| 20.5k| { 674| | // make sure we have enough data to read 675| | // each index reads at most 5 bytes of data; there's a 4 byte tail after data_safe_end 676| | // after this we can be sure we can read without extra bounds checks 677| 20.5k| if (data >= data_safe_end) ------------------ | Branch (677:7): [True: 72, False: 20.4k] ------------------ 678| 72| return -2; 679| | 680| 20.4k| unsigned int v = decodeVByte(data); 681| | 682| | // decode the index of the last baseline 683| 20.4k| unsigned int current = v & 1; 684| 20.4k| v >>= 1; 685| | 686| | // reconstruct index as a delta 687| 20.4k| unsigned int d = (v >> 1) ^ -int(v & 1); 688| 20.4k| unsigned int index = last[current] + d; 689| | 690| | // update last for the next iteration that uses it 691| 20.4k| last[current] = index; 692| | 693| 20.4k| if (index_size == 2) ------------------ | Branch (693:7): [True: 10.2k, False: 10.2k] ------------------ 694| 10.2k| { 695| 10.2k| static_cast(destination)[i] = (unsigned short)(index); 696| 10.2k| } 697| 10.2k| else 698| 10.2k| { 699| 10.2k| static_cast(destination)[i] = index; 700| 10.2k| } 701| 20.4k| } 702| | 703| | // we should've read all data bytes and stopped at the boundary between data and tail 704| 266| if (data != data_safe_end) ------------------ | Branch (704:6): [True: 264, False: 2] ------------------ 705| 264| return -3; 706| | 707| 2| return 0; 708| 266|} indexcodec.cpp:_ZN7meshoptL14pushVertexFifoEPjjRmi: 80| 17.3k|{ 81| 17.3k| fifo[offset] = v; 82| 17.3k| offset = (offset + cond) & 15; 83| 17.3k|} indexcodec.cpp:_ZN7meshoptL12pushEdgeFifoEPA2_jjjRm: 60| 23.0k|{ 61| 23.0k| fifo[offset][0] = a; 62| 23.0k| fifo[offset][1] = b; 63| 23.0k| offset = (offset + 1) & 15; 64| 23.0k|} indexcodec.cpp:_ZN7meshoptL11decodeIndexERPKhj: 130| 3.94k|{ 131| 3.94k| unsigned int v = decodeVByte(data); 132| 3.94k| unsigned int d = (v >> 1) ^ -int(v & 1); 133| | 134| 3.94k| return last + d; 135| 3.94k|} indexcodec.cpp:_ZN7meshoptL13writeTriangleEPvmjjj: 147| 9.60k|{ 148| 9.60k| if (index_size == 2) ------------------ | Branch (148:6): [True: 4.80k, False: 4.80k] ------------------ 149| 4.80k| { 150| 4.80k| unsigned short* tri = static_cast(destination); 151| 4.80k| tri[0] = (unsigned short)(a); 152| 4.80k| tri[1] = (unsigned short)(b); 153| 4.80k| tri[2] = (unsigned short)(c); 154| | 155| 4.80k| return tri + 3; 156| 4.80k| } 157| 4.80k| else 158| 4.80k| { 159| 4.80k| unsigned int* tri = static_cast(destination); 160| 4.80k| tri[0] = a; 161| 4.80k| tri[1] = b; 162| 4.80k| tri[2] = c; 163| | 164| 4.80k| return tri + 3; 165| 4.80k| } 166| 9.60k|} indexcodec.cpp:_ZN7meshoptL11decodeVByteERPKh: 96| 24.4k|{ 97| 24.4k| unsigned char lead = *data++; 98| | 99| | // fast path: single byte 100| 24.4k| if (lead < 128) ------------------ | Branch (100:6): [True: 14.3k, False: 10.0k] ------------------ 101| 14.3k| return lead; 102| | 103| | // slow path: up to 4 extra bytes 104| | // note that this loop always terminates, which is important for malformed data 105| 10.0k| unsigned int result = lead & 127; 106| 10.0k| unsigned int shift = 7; 107| | 108| 31.9k| for (int i = 0; i < 4; ++i) ------------------ | Branch (108:18): [True: 27.6k, False: 4.32k] ------------------ 109| 27.6k| { 110| 27.6k| unsigned char group = *data++; 111| 27.6k| result |= unsigned(group & 127) << shift; 112| 27.6k| shift += 7; 113| | 114| 27.6k| if (group < 128) ------------------ | Branch (114:7): [True: 5.76k, False: 21.9k] ------------------ 115| 5.76k| break; 116| 27.6k| } 117| | 118| 10.0k| return result; 119| 24.4k|} meshopt_encodeMeshletBound: 899| 3.77k|{ 900| 3.77k| size_t codes_size = (max_triangles + 1) / 2; 901| 3.77k| size_t extra_size = max_triangles * 3; 902| | 903| 3.77k| size_t ctrl_size = (max_vertices + 3) / 4; 904| 3.77k| size_t data_size = (max_vertices + 3) / 4 * 16; // worst case: 16 bytes per vertex group 905| | 906| 3.77k| size_t gap_size = (codes_size + ctrl_size < 16) ? 16 - (codes_size + ctrl_size) : 0; ------------------ | Branch (906:20): [True: 2.48k, False: 1.29k] ------------------ 907| | 908| 3.77k| return codes_size + extra_size + ctrl_size + data_size + gap_size; 909| 3.77k|} meshopt_encodeMeshlet: 912| 3.77k|{ 913| 3.77k| using namespace meshopt; 914| | 915| 3.77k| assert(triangle_count <= 256 && vertex_count <= 256); ------------------ | Branch (915:2): [True: 3.77k, False: 0] | Branch (915:2): [True: 3.77k, False: 0] | Branch (915:2): [True: 3.77k, False: 0] ------------------ 916| | 917| | // 4 bits per triangle + up to three bytes of extra data 918| 3.77k| unsigned char codes[256 / 2]; 919| 3.77k| unsigned char extra[256 * 3]; 920| 3.77k| size_t codes_size = (triangle_count + 1) / 2; 921| 3.77k| size_t extra_size = encodeTriangles(codes, extra, triangles, triangle_count); 922| 3.77k| assert(extra_size <= sizeof(extra)); ------------------ | Branch (922:2): [True: 3.77k, False: 0] ------------------ 923| | 924| | // 2 bits per vertex + up to 4 bytes of actual data 925| 3.77k| unsigned char ctrl[256 / 4]; 926| 3.77k| unsigned char data[256 * 4]; 927| 3.77k| size_t ctrl_size = (vertex_count + 3) / 4; 928| 3.77k| size_t data_size = encodeVertices(ctrl, data, vertices, vertex_count); 929| 3.77k| assert(data_size <= sizeof(data)); ------------------ | Branch (929:2): [True: 3.77k, 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| 3.77k| size_t gap_size = (codes_size + ctrl_size < 16) ? 16 - (codes_size + ctrl_size) : 0; ------------------ | Branch (933:20): [True: 2.48k, False: 1.29k] ------------------ 934| | 935| 3.77k| size_t result = codes_size + extra_size + ctrl_size + data_size + gap_size; 936| | 937| 3.77k| if (result > buffer_size) ------------------ | Branch (937:6): [True: 0, False: 3.77k] ------------------ 938| 0| return 0; 939| | 940| | // variable-size data first 941| 3.77k| memcpy(buffer, data, data_size); 942| 3.77k| buffer += data_size; 943| 3.77k| memcpy(buffer, extra, extra_size); 944| 3.77k| buffer += extra_size; 945| | 946| | // gap (for accelerated decoding) separates variable-size and fixed-size data 947| 3.77k| memset(buffer, 0, gap_size); 948| 3.77k| buffer += gap_size; 949| | 950| | // fixed-size data last; it can be located from buffer end during decoding 951| 3.77k| memcpy(buffer, ctrl, ctrl_size); 952| 3.77k| buffer += ctrl_size; 953| 3.77k| memcpy(buffer, codes, codes_size); 954| 3.77k| 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| 3.77k| return result; 979| 3.77k|} meshopt_decodeMeshlet: 982| 15.0k|{ 983| 15.0k| using namespace meshopt; 984| | 985| 15.0k| assert(triangle_count <= 256 && vertex_count <= 256); ------------------ | Branch (985:2): [True: 15.0k, False: 0] | Branch (985:2): [True: 15.0k, False: 0] | Branch (985:2): [True: 15.0k, False: 0] ------------------ 986| 15.0k| assert(vertex_size == 4 || vertex_size == 2); ------------------ | Branch (986:2): [True: 9.41k, False: 5.63k] | Branch (986:2): [True: 5.63k, False: 0] | Branch (986:2): [True: 15.0k, False: 0] ------------------ 987| 15.0k| assert(triangle_size == 4 || triangle_size == 3); ------------------ | Branch (987:2): [True: 5.63k, False: 9.41k] | Branch (987:2): [True: 9.41k, False: 0] | Branch (987:2): [True: 15.0k, False: 0] ------------------ 988| | 989| | // layout must match encoding 990| 15.0k| size_t codes_size = (triangle_count + 1) / 2; 991| 15.0k| size_t ctrl_size = (vertex_count + 3) / 4; 992| 15.0k| size_t gap_size = (codes_size + ctrl_size < 16) ? 16 - (codes_size + ctrl_size) : 0; ------------------ | Branch (992:20): [True: 6.38k, False: 8.67k] ------------------ 993| | 994| 15.0k| if (buffer_size < codes_size + ctrl_size + gap_size) ------------------ | Branch (994:6): [True: 3.99k, False: 11.0k] ------------------ 995| 3.99k| return -2; 996| | 997| 11.0k| const unsigned char* end = buffer + buffer_size; 998| 11.0k| const unsigned char* codes = end - codes_size; 999| 11.0k| const unsigned char* ctrl = codes - ctrl_size; 1000| 11.0k| 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| 11.0k| const unsigned char* bound = ctrl - gap_size; 1004| 11.0k| assert(bound >= buffer && bound + 16 <= buffer + buffer_size); ------------------ | Branch (1004:2): [True: 11.0k, False: 0] | Branch (1004:2): [True: 11.0k, False: 0] | Branch (1004:2): [True: 11.0k, False: 0] ------------------ 1005| | 1006| 11.0k|#if defined(SIMD_FALLBACK) 1007| 11.0k| return (gDecodeTablesInitialized ? decodeMeshletSimd<0> : decodeMeshlet)(vertices, triangles, codes, ctrl, data, bound, vertex_count, triangle_count, vertex_size, triangle_size); ------------------ | Branch (1007:10): [True: 11.0k, 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| 11.0k|} meshopt_decodeMeshletRaw: 1016| 1.87k|{ 1017| 1.87k| using namespace meshopt; 1018| | 1019| 1.87k| assert(triangle_count <= 256 && vertex_count <= 256); ------------------ | Branch (1019:2): [True: 1.87k, False: 0] | Branch (1019:2): [True: 1.87k, False: 0] | Branch (1019:2): [True: 1.87k, False: 0] ------------------ 1020| | 1021| | // layout must match encoding 1022| 1.87k| size_t codes_size = (triangle_count + 1) / 2; 1023| 1.87k| size_t ctrl_size = (vertex_count + 3) / 4; 1024| 1.87k| size_t gap_size = (codes_size + ctrl_size < 16) ? 16 - (codes_size + ctrl_size) : 0; ------------------ | Branch (1024:20): [True: 355, False: 1.51k] ------------------ 1025| | 1026| 1.87k| if (buffer_size < codes_size + ctrl_size + gap_size) ------------------ | Branch (1026:6): [True: 999, False: 875] ------------------ 1027| 999| return -2; 1028| | 1029| 875| const unsigned char* end = buffer + buffer_size; 1030| 875| const unsigned char* codes = end - codes_size; 1031| 875| const unsigned char* ctrl = codes - ctrl_size; 1032| 875| 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| 875| const unsigned char* bound = ctrl - gap_size; 1036| 875| assert(bound >= buffer && bound + 16 <= buffer + buffer_size); ------------------ | Branch (1036:2): [True: 875, False: 0] | Branch (1036:2): [True: 875, False: 0] | Branch (1036:2): [True: 875, False: 0] ------------------ 1037| | 1038| 875|#if defined(SIMD_FALLBACK) 1039| 875| return (gDecodeTablesInitialized ? decodeMeshletSimd<1> : decodeMeshlet)(vertices, triangles, codes, ctrl, data, bound, vertex_count, triangle_count, 4, 4); ------------------ | Branch (1039:10): [True: 875, 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| 875|} 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| 3.77k|{ 110| 3.77k| EdgeFifo8 edgefifo; 111| 3.77k| memset(edgefifo, -1, sizeof(edgefifo)); 112| | 113| 3.77k| size_t edgefifooffset = 0; 114| | 115| 3.77k| 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| 3.77k| memset(codes, 0, (triangle_count + 1) / 2); 122| | 123| 3.77k| static const int rotations[] = {0, 1, 2, 0, 1}; 124| | 125| 3.77k| unsigned char* start = extra; 126| | 127| 151k| for (size_t i = 0; i < triangle_count; ++i) ------------------ | Branch (127:21): [True: 147k, False: 3.77k] ------------------ 128| 147k| { 129| |#if TRACE > 1 130| | unsigned int last = next; 131| |#endif 132| | 133| 147k| int fer = getEdgeFifo8(edgefifo, triangles[i * 3 + 0], triangles[i * 3 + 1], triangles[i * 3 + 2], edgefifooffset); 134| | 135| 147k| if (fer >= 0 && (fer >> 2) < 6) ------------------ | Branch (135:7): [True: 75.3k, False: 72.6k] | Branch (135:19): [True: 71.8k, False: 3.45k] ------------------ 136| 71.8k| { 137| | // note: getEdgeFifo8 implicitly rotates triangles by matching a/b to existing edge 138| 71.8k| const int* order = rotations + (fer & 3); 139| | 140| 71.8k| unsigned int a = triangles[i * 3 + order[0]], b = triangles[i * 3 + order[1]], c = triangles[i * 3 + order[2]]; 141| | 142| 71.8k| int fec = (c == next) ? (next++, 0) : 1; ------------------ | Branch (142:14): [True: 618, False: 71.2k] ------------------ 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| 71.8k| unsigned int code = (fer >> 2) * 2 + fec; 149| | 150| 71.8k| codes[i / 2] |= (unsigned char)(code << ((i & 1) * 4)); 151| | 152| 71.8k| if (fec) ------------------ | Branch (152:8): [True: 71.2k, False: 618] ------------------ 153| 71.2k| *extra++ = (unsigned char)c; 154| | 155| 71.8k| pushEdgeFifo8(edgefifo, c, b, edgefifooffset); 156| 71.8k| pushEdgeFifo8(edgefifo, a, c, edgefifooffset); 157| 71.8k| } 158| 76.0k| else 159| 76.0k| { 160| | // rotate triangles to minimize the need for extra vertices 161| 76.0k| int rotation = rotateTriangle(triangles[i * 3 + 0], triangles[i * 3 + 1], triangles[i * 3 + 2]); 162| 76.0k| const int* order = rotations + rotation; 163| | 164| 76.0k| 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| 76.0k| int fea = (a == next && b == next + 1 && c == next + 2) ? (next++, 0) : 1; ------------------ | Branch (167:15): [True: 7.43k, False: 68.6k] | Branch (167:28): [True: 3.20k, False: 4.23k] | Branch (167:45): [True: 2.81k, False: 389] ------------------ 168| 76.0k| int feb = (b == next && c == next + 1) ? (next++, 0) : 1; ------------------ | Branch (168:15): [True: 8.92k, False: 67.1k] | Branch (168:28): [True: 3.03k, False: 5.89k] ------------------ 169| 76.0k| int fec = (c == next) ? (next++, 0) : 1; ------------------ | Branch (169:14): [True: 3.95k, False: 72.1k] ------------------ 170| | 171| 76.0k| assert(fea == 1 || feb == 0); ------------------ | Branch (171:4): [True: 73.2k, False: 2.81k] | Branch (171:4): [True: 2.81k, False: 0] | Branch (171:4): [True: 76.0k, False: 0] ------------------ 172| 76.0k| assert(feb == 1 || fec == 0); ------------------ | Branch (172:4): [True: 73.0k, False: 3.03k] | Branch (172:4): [True: 3.03k, False: 0] | Branch (172:4): [True: 76.0k, 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| 76.0k| unsigned int code = 12 + (fea + feb + fec); 179| | 180| 76.0k| codes[i / 2] |= (unsigned char)(code << ((i & 1) * 4)); 181| | 182| 76.0k| if (fea) ------------------ | Branch (182:8): [True: 73.2k, False: 2.81k] ------------------ 183| 73.2k| *extra++ = (unsigned char)a; 184| 76.0k| if (feb) ------------------ | Branch (184:8): [True: 73.0k, False: 3.03k] ------------------ 185| 73.0k| *extra++ = (unsigned char)b; 186| 76.0k| if (fec) ------------------ | Branch (186:8): [True: 72.1k, False: 3.95k] ------------------ 187| 72.1k| *extra++ = (unsigned char)c; 188| | 189| 76.0k| pushEdgeFifo8(edgefifo, c, b, edgefifooffset); 190| 76.0k| pushEdgeFifo8(edgefifo, a, c, edgefifooffset); 191| 76.0k| } 192| 147k| } 193| | 194| 3.77k| return extra - start; 195| 3.77k|} meshletcodec.cpp:_ZN7meshoptL12getEdgeFifo8EPA2_jjjjm: 82| 147k|{ 83| 789k| for (int i = 0; i < 8; ++i) ------------------ | Branch (83:18): [True: 716k, False: 72.6k] ------------------ 84| 716k| { 85| 716k| size_t index = (offset - 1 - i) & 7; 86| | 87| 716k| unsigned int e0 = fifo[index][0]; 88| 716k| unsigned int e1 = fifo[index][1]; 89| | 90| 716k| if (e0 == a && e1 == b) ------------------ | Branch (90:7): [True: 122k, False: 594k] | Branch (90:18): [True: 62.2k, False: 59.9k] ------------------ 91| 62.2k| return (i << 2) | 0; 92| 654k| if (e0 == b && e1 == c) ------------------ | Branch (92:7): [True: 49.6k, False: 604k] | Branch (92:18): [True: 7.04k, False: 42.5k] ------------------ 93| 7.04k| return (i << 2) | 1; 94| 647k| if (e0 == c && e1 == a) ------------------ | Branch (94:7): [True: 48.7k, False: 598k] | Branch (94:18): [True: 6.08k, False: 42.6k] ------------------ 95| 6.08k| return (i << 2) | 2; 96| 647k| } 97| | 98| 72.6k| return -1; 99| 147k|} meshletcodec.cpp:_ZN7meshoptL13pushEdgeFifo8EPA2_jjjRm: 102| 295k|{ 103| 295k| fifo[offset][0] = a; 104| 295k| fifo[offset][1] = b; 105| 295k| offset = (offset + 1) & 7; 106| 295k|} meshletcodec.cpp:_ZN7meshoptL14rotateTriangleEjjj: 77| 76.0k|{ 78| 76.0k| return (a > b && a > c) ? 1 : (b > c ? 2 : 0); ------------------ | Branch (78:10): [True: 31.7k, False: 44.3k] | Branch (78:19): [True: 21.6k, False: 10.1k] | Branch (78:33): [True: 20.4k, False: 33.9k] ------------------ 79| 76.0k|} meshletcodec.cpp:_ZN7meshoptL14encodeVerticesEPhS0_PKjm: 198| 3.77k|{ 199| | // grouped varint, 2 bit per value to indicate 0/1/2/3 byte deltas, with per-group 4-byte fallback 200| 3.77k| memset(ctrl, 0, (vertex_count + 3) / 4); 201| | 202| 3.77k| unsigned char* start = data; 203| | 204| 3.77k| unsigned int last = ~0u; 205| | 206| 37.9k| for (size_t i = 0; i < vertex_count; i += 4) ------------------ | Branch (206:21): [True: 34.2k, False: 3.77k] ------------------ 207| 34.2k| { 208| 34.2k| unsigned int gv[4] = {}; 209| | 210| 168k| for (int k = 0; k < 4 && i + k < vertex_count; ++k) ------------------ | Branch (210:19): [True: 135k, False: 33.1k] | Branch (210:28): [True: 134k, False: 1.01k] ------------------ 211| 134k| { 212| 134k| unsigned int d = vertices[i + k] - last - 1; 213| 134k| unsigned int v = (d << 1) ^ (int(d) >> 31); 214| | 215| 134k| gv[k] = v; 216| 134k| last = vertices[i + k]; 217| 134k| } 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| 34.2k| 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: 22.1k, False: 12.0k] | Branch (221:62): [True: 1.25k, False: 10.7k] | Branch (221:80): [True: 840, False: 418] | Branch (221:98): [True: 489, False: 351] | Branch (221:116): [True: 304, False: 185] ------------------ 222| | 223| 171k| for (int k = 0; k < 4; ++k) ------------------ | Branch (223:19): [True: 136k, False: 34.2k] ------------------ 224| 136k| { 225| 136k| unsigned int v = gv[k]; 226| | 227| | // 0/1/2/3 bytes per value, or all 4 values use 4 bytes 228| 136k| int code = use4 ? 3 : (v == 0 ? 0 : (v < 256 ? 1 : (v < 65536 ? 2 : 3))); ------------------ | Branch (228:15): [True: 89.9k, False: 46.8k] | Branch (228:27): [True: 2.04k, False: 44.8k] | Branch (228:41): [True: 39.4k, False: 5.37k] | Branch (228:56): [True: 2.55k, False: 2.81k] ------------------ 229| | 230| 136k| if (code > 0) ------------------ | Branch (230:8): [True: 134k, False: 2.04k] ------------------ 231| 134k| *data++ = (unsigned char)(v & 0xff); 232| 136k| if (code > 1) ------------------ | Branch (232:8): [True: 95.2k, False: 41.5k] ------------------ 233| 95.2k| *data++ = (unsigned char)((v >> 8) & 0xff); 234| 136k| if (code > 2) ------------------ | Branch (234:8): [True: 92.7k, False: 44.0k] ------------------ 235| 92.7k| *data++ = (unsigned char)((v >> 16) & 0xff); 236| 136k| if (use4) ------------------ | Branch (236:8): [True: 89.9k, False: 46.8k] ------------------ 237| 89.9k| *data++ = (unsigned char)((v >> 24) & 0xff); 238| | 239| | // split low and high bits into two nibbles for better packing 240| 136k| ctrl[i / 4] |= ((code & 1) << k) | ((code >> 1) << (k + 4)); 241| 136k| } 242| 34.2k| } 243| | 244| 3.77k| return data - start; 245| 3.77k|} meshletcodec.cpp:_ZN7meshoptL17decodeMeshletSimdILi0EEEiPvS1_PKhS3_S3_S3_mmmm: 865| 11.0k|{ 866| 11.0k| assert(gDecodeTablesInitialized); ------------------ | Branch (866:2): [True: 11.0k, False: 0] ------------------ 867| 11.0k| (void)gDecodeTablesInitialized; 868| | 869| 11.0k|#ifdef __clang__ 870| | // data is guaranteed to be non-null initially; if decode loops never hit bounds errors, it remains non-null 871| 11.0k| __builtin_assume(data); 872| 11.0k|#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| 11.0k| if (vertex_size == 4 || Raw) ------------------ | Branch (876:6): [True: 7.41k, False: 3.63k] | Branch (876:26): [Folded, False: 0] ------------------ 877| 7.41k| data = decodeVerticesSimd(static_cast(vertices), ctrl, data, bound, Raw ? (vertex_count + 3) & ~3 : vertex_count); ------------------ | Branch (877:86): [Folded, False: 7.41k] ------------------ 878| 3.63k| else 879| 3.63k| data = decodeVerticesSimd(static_cast(vertices), ctrl, data, bound, vertex_count); 880| 11.0k| if (!data) ------------------ | Branch (880:6): [True: 724, False: 10.3k] ------------------ 881| 724| 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| 10.3k| if (triangle_size == 4 || Raw) ------------------ | Branch (885:6): [True: 3.27k, False: 7.05k] | Branch (885:28): [Folded, False: 0] ------------------ 886| 3.27k| data = decodeTrianglesSimd(static_cast(triangles), codes, data, bound, Raw ? (triangle_count + 1) & ~1 : triangle_count); ------------------ | Branch (886:89): [Folded, False: 3.27k] ------------------ 887| 7.05k| else 888| 7.05k| data = decodeTrianglesSimd(static_cast(triangles), codes, data, bound, triangle_count); 889| 10.3k| if (!data) ------------------ | Branch (889:6): [True: 282, False: 10.0k] ------------------ 890| 282| return -2; 891| | 892| 10.0k| return (data == bound) ? 0 : -3; ------------------ | Branch (892:9): [True: 7.61k, False: 2.43k] ------------------ 893| 10.3k|} meshletcodec.cpp:_ZN7meshoptL18decodeVerticesSimdEPjPKhS2_S2_m: 750| 8.29k|{ 751| 8.29k|#if defined(SIMD_SSE) 752| 8.29k| __m128i last = _mm_set1_epi32(-1); 753| |#elif defined(SIMD_NEON) 754| | uint32x4_t last = vdupq_n_u32(~0u); 755| |#endif 756| | 757| 8.29k| size_t groups = vertex_count / 4; 758| | 759| | // process all complete groups 760| 110k| for (size_t i = 0; i < groups; ++i) ------------------ | Branch (760:21): [True: 102k, False: 7.76k] ------------------ 761| 102k| { 762| 102k| unsigned char code = *ctrl++; 763| 102k| if (data > bound) ------------------ | Branch (763:7): [True: 529, False: 101k] ------------------ 764| 529| return NULL; 765| | 766| 101k| last = decodeVertexGroup(last, code, data); 767| | 768| 101k|#if defined(SIMD_SSE) 769| 101k| _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| 101k| } 774| | 775| | // process a 1-3 vertex tail; to maintain the memory safety guarantee we have to write individual elements 776| 7.76k| if (vertex_count & 3) ------------------ | Branch (776:6): [True: 2.19k, False: 5.56k] ------------------ 777| 2.19k| { 778| 2.19k| unsigned char code = *ctrl++; 779| | 780| 2.19k| if (data > bound) ------------------ | Branch (780:7): [True: 14, False: 2.18k] ------------------ 781| 14| return NULL; 782| | 783| 2.18k| last = decodeVertexGroup(last, code, data); 784| | 785| 2.18k| unsigned int* tail = &vertices[vertex_count & ~3u]; 786| | 787| 2.18k|#if defined(SIMD_SSE) 788| 2.18k| tail[0] = _mm_cvtsi128_si32(last); 789| 2.18k| if ((vertex_count & 3) > 1) ------------------ | Branch (789:7): [True: 960, False: 1.22k] ------------------ 790| 960| tail[1] = _mm_extract_epi32(last, 1); 791| 2.18k| if ((vertex_count & 3) > 2) ------------------ | Branch (791:7): [True: 360, False: 1.82k] ------------------ 792| 360| 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.18k| } 801| | 802| 7.74k| return data; 803| 7.76k|} _ZN7meshopt17decodeVertexGroupEDv2_xhRPKh: 540| 184k|{ 541| 184k| __m128i word = _mm_loadu_si128(reinterpret_cast(data)); 542| 184k| __m128i shuf = _mm_loadu_si128(reinterpret_cast(kDecodeTableVerts[code])); 543| | 544| 184k| __m128i v = _mm_shuffle_epi8(word, shuf); 545| | 546| | // unzigzag+1 547| 184k| __m128i xl = _mm_sub_epi32(_mm_setzero_si128(), _mm_and_si128(v, _mm_set1_epi32(1))); 548| 184k| __m128i xr = _mm_srli_epi32(v, 1); 549| 184k| __m128i x = _mm_add_epi32(_mm_xor_si128(xl, xr), _mm_set1_epi32(1)); 550| | 551| | // prefix sum 552| 184k| x = _mm_add_epi32(x, _mm_slli_si128(x, 8)); 553| 184k| x = _mm_add_epi32(x, _mm_slli_si128(x, 4)); 554| 184k| x = _mm_add_epi32(x, _mm_shuffle_epi32(last, 0xff)); 555| | 556| 184k| data += kDecodeTableLength[code]; 557| | 558| 184k| return x; 559| 184k|} meshletcodec.cpp:_ZN7meshoptL18decodeVerticesSimdEPtPKhS2_S2_m: 807| 3.63k|{ 808| 3.63k|#if defined(SIMD_SSE) 809| 3.63k| __m128i repack = _mm_setr_epi8(0, 1, 4, 5, 8, 9, 12, 13, 0, 0, 0, 0, 0, 0, 0, 0); 810| 3.63k| __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| 3.63k| size_t groups = (vertex_count + 1) / 4; 818| | 819| | // process all complete groups 820| 82.4k| for (size_t i = 0; i < groups; ++i) ------------------ | Branch (820:21): [True: 79.2k, False: 3.29k] ------------------ 821| 79.2k| { 822| 79.2k| unsigned char code = *ctrl++; 823| | 824| 79.2k| if (data > bound) ------------------ | Branch (824:7): [True: 348, False: 78.8k] ------------------ 825| 348| return NULL; 826| | 827| 78.8k| last = decodeVertexGroup(last, code, data); 828| | 829| 78.8k|#if defined(SIMD_SSE) 830| 78.8k| __m128i r = _mm_shuffle_epi8(last, repack); 831| 78.8k| _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| 78.8k| } 837| | 838| | // process a 1-2 vertex tail; to maintain the memory safety guarantee we have to write a 32-bit element 839| 3.29k| if (groups * 4 < vertex_count) ------------------ | Branch (839:6): [True: 1.83k, False: 1.45k] ------------------ 840| 1.83k| { 841| 1.83k| unsigned char code = *ctrl++; 842| | 843| 1.83k| if (data > bound) ------------------ | Branch (843:7): [True: 14, False: 1.82k] ------------------ 844| 14| return NULL; 845| | 846| 1.82k| last = decodeVertexGroup(last, code, data); 847| | 848| 1.82k| unsigned short* tail = &vertices[vertex_count & ~3u]; 849| | 850| 1.82k|#if defined(SIMD_SSE) 851| 1.82k| __m128i r = _mm_shufflelo_epi16(last, 8); 852| 1.82k| *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| 1.82k| } 858| | 859| 3.27k| return data; 860| 3.29k|} meshletcodec.cpp:_ZN7meshoptL19decodeTrianglesSimdEPjPKhS2_S2_m: 615| 3.97k|{ 616| 3.97k|#if defined(SIMD_SSE) 617| 3.97k| __m128i repack = _mm_setr_epi8(9, 10, 11, -1, 12, 13, 14, -1, 0, 0, 0, 0, 0, 0, 0, 0); 618| 3.97k| __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| 3.97k| size_t groups = triangle_count / 2; 625| | 626| | // process all complete groups 627| 173k| for (size_t i = 0; i < groups; ++i) ------------------ | Branch (627:21): [True: 169k, False: 3.78k] ------------------ 628| 169k| { 629| 169k| unsigned char code = *codes++; 630| | 631| 169k| if (extra > bound) ------------------ | Branch (631:7): [True: 184, False: 169k] ------------------ 632| 184| return NULL; 633| | 634| 169k| state = decodeTriangleGroup(state, code, extra); 635| | 636| | // write 6 bytes of new triangle data into output, formatted as 8 bytes with 0 padding 637| 169k|#if defined(SIMD_SSE) 638| 169k| __m128i r = _mm_shuffle_epi8(state, repack); 639| 169k| _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| 169k| } 645| | 646| | // process a 1 triangle tail; to maintain the memory safety guarantee we have to write a 32-bit element 647| 3.78k| if (triangle_count & 1) ------------------ | Branch (647:6): [True: 1.46k, False: 2.32k] ------------------ 648| 1.46k| { 649| 1.46k| unsigned char code = *codes++; 650| | 651| 1.46k| if (extra > bound) ------------------ | Branch (651:7): [True: 38, False: 1.42k] ------------------ 652| 38| return NULL; 653| | 654| 1.42k| state = decodeTriangleGroup(state, code, extra); 655| | 656| 1.42k| unsigned int* tail = &triangles[triangle_count & ~1u]; 657| | 658| 1.42k|#if defined(SIMD_SSE) 659| 1.42k| __m128i r = _mm_shuffle_epi8(state, repack); 660| 1.42k| *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.42k| } 666| | 667| 3.74k| return extra; 668| 3.78k|} _ZN7meshopt19decodeTriangleGroupEDv2_xhRPKh: 524| 312k|{ 525| 312k| __m128i shuf = _mm_loadu_si128(reinterpret_cast(kDecodeTableMasks[code])); 526| 312k| __m128i next = _mm_slli_si128(shuf, 10); 527| | 528| | // patch first 6 bytes with current extra and roll state forward 529| 312k| __m128i ext = _mm_loadl_epi64(reinterpret_cast(extra)); 530| 312k| state = _mm_blend_epi16(state, ext, 7); 531| 312k| state = _mm_add_epi8(_mm_shuffle_epi8(state, shuf), next); 532| | 533| 312k| extra += kDecodeTableExtra[code]; 534| | 535| 312k| return state; 536| 312k|} meshletcodec.cpp:_ZN7meshoptL19decodeTrianglesSimdEPhPKhS2_S2_m: 672| 7.05k|{ 673| 7.05k|#if defined(SIMD_SSE) 674| 7.05k| __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| 7.05k| size_t groups = (triangle_count + 1) / 4; 683| | 684| | // process all complete groups 685| 75.3k| for (size_t i = 0; i < groups; ++i) ------------------ | Branch (685:21): [True: 68.3k, False: 6.96k] ------------------ 686| 68.3k| { 687| 68.3k| unsigned char code0 = *codes++; 688| 68.3k| 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| 68.3k| if (extra > bound) ------------------ | Branch (691:7): [True: 94, False: 68.2k] ------------------ 692| 94| return NULL; 693| | 694| 68.2k| state = decodeTriangleGroup(state, code0, extra); 695| | 696| | // write first decoded triangle and first index of second decoded triangle 697| 68.2k|#if defined(SIMD_SSE) 698| 68.2k| __m128i r0 = _mm_srli_si128(state, 9); 699| 68.2k| *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| 68.2k| 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| 68.2k|#if defined(SIMD_SSE) 710| 68.2k| __m128i r1 = _mm_srli_si128(state, 7); 711| 68.2k| _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| 68.2k| } 717| | 718| | // process a 1-2 triangle tail; to maintain the memory safety guarantee we have to write 1-2 32-bit elements 719| 6.96k| if (groups * 4 < triangle_count) ------------------ | Branch (719:6): [True: 5.53k, False: 1.42k] ------------------ 720| 5.53k| { 721| 5.53k| unsigned char code = *codes++; 722| | 723| 5.53k| if (extra > bound) ------------------ | Branch (723:7): [True: 40, False: 5.49k] ------------------ 724| 40| return NULL; 725| | 726| 5.49k| state = decodeTriangleGroup(state, code, extra); 727| | 728| 5.49k| unsigned char* tail = &triangles[(triangle_count & ~3u) * 3]; 729| | 730| 5.49k|#if defined(SIMD_SSE) 731| 5.49k| __m128i r = _mm_srli_si128(state, 9); 732| | 733| 5.49k| *reinterpret_cast(tail) = _mm_cvtsi128_si32(r); 734| 5.49k| if ((triangle_count & 3) > 1) ------------------ | Branch (734:7): [True: 643, False: 4.85k] ------------------ 735| 643| *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| 5.49k| } 744| | 745| 6.92k| return extra; 746| 6.96k|} meshletcodec.cpp:_ZN7meshoptL17decodeMeshletSimdILi1EEEiPvS1_PKhS3_S3_S3_mmmm: 865| 875|{ 866| 875| assert(gDecodeTablesInitialized); ------------------ | Branch (866:2): [True: 875, False: 0] ------------------ 867| 875| (void)gDecodeTablesInitialized; 868| | 869| 875|#ifdef __clang__ 870| | // data is guaranteed to be non-null initially; if decode loops never hit bounds errors, it remains non-null 871| 875| __builtin_assume(data); 872| 875|#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| 875| if (vertex_size == 4 || Raw) ------------------ | Branch (876:6): [True: 875, False: 0] | Branch (876:26): [True: 0, Folded] ------------------ 877| 875| data = decodeVerticesSimd(static_cast(vertices), ctrl, data, bound, Raw ? (vertex_count + 3) & ~3 : vertex_count); ------------------ | Branch (877:86): [True: 875, Folded] ------------------ 878| 0| else 879| 0| data = decodeVerticesSimd(static_cast(vertices), ctrl, data, bound, vertex_count); 880| 875| if (!data) ------------------ | Branch (880:6): [True: 181, False: 694] ------------------ 881| 181| 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| 694| if (triangle_size == 4 || Raw) ------------------ | Branch (885:6): [True: 694, False: 0] | Branch (885:28): [True: 0, Folded] ------------------ 886| 694| data = decodeTrianglesSimd(static_cast(triangles), codes, data, bound, Raw ? (triangle_count + 1) & ~1 : triangle_count); ------------------ | Branch (886:89): [True: 694, Folded] ------------------ 887| 0| else 888| 0| data = decodeTrianglesSimd(static_cast(triangles), codes, data, bound, triangle_count); 889| 694| if (!data) ------------------ | Branch (889:6): [True: 74, False: 620] ------------------ 890| 74| return -2; 891| | 892| 620| return (data == bound) ? 0 : -3; ------------------ | Branch (892:9): [True: 14, False: 606] ------------------ 893| 694|} _Z21meshopt_decodeMeshletIjjEiPT_mPT0_mPKhm: 1515| 1.88k|{ 1516| 1.88k| char types_valid[(sizeof(V) == 2 || sizeof(V) == 4) && (sizeof(T) == 1 || sizeof(T) == 4) ? 1 : -1]; 1517| 1.88k| (void)types_valid; 1518| | 1519| 1.88k| return meshopt_decodeMeshlet(vertices, vertex_count, sizeof(V), triangles, triangle_count, sizeof(T) == 1 ? 3 : 4, buffer, buffer_size); ------------------ | Branch (1519:93): [Folded, False: 1.88k] ------------------ 1520| 1.88k|} _Z21meshopt_decodeMeshletIjhEiPT_mPT0_mPKhm: 1515| 3.77k|{ 1516| 3.77k| char types_valid[(sizeof(V) == 2 || sizeof(V) == 4) && (sizeof(T) == 1 || sizeof(T) == 4) ? 1 : -1]; 1517| 3.77k| (void)types_valid; 1518| | 1519| 3.77k| return meshopt_decodeMeshlet(vertices, vertex_count, sizeof(V), triangles, triangle_count, sizeof(T) == 1 ? 3 : 4, buffer, buffer_size); ------------------ | Branch (1519:93): [True: 3.77k, Folded] ------------------ 1520| 3.77k|} _Z21meshopt_decodeMeshletIthEiPT_mPT0_mPKhm: 1515| 1.88k|{ 1516| 1.88k| char types_valid[(sizeof(V) == 2 || sizeof(V) == 4) && (sizeof(T) == 1 || sizeof(T) == 4) ? 1 : -1]; 1517| 1.88k| (void)types_valid; 1518| | 1519| 1.88k| return meshopt_decodeMeshlet(vertices, vertex_count, sizeof(V), triangles, triangle_count, sizeof(T) == 1 ? 3 : 4, buffer, buffer_size); ------------------ | Branch (1519:93): [True: 1.88k, Folded] ------------------ 1520| 1.88k|} meshopt_encodeVertexBufferLevel: 1633| 15.1k|{ 1634| 15.1k| using namespace meshopt; 1635| | 1636| 15.1k| assert(vertex_size > 0 && vertex_size <= 256); ------------------ | Branch (1636:2): [True: 15.1k, False: 0] | Branch (1636:2): [True: 15.1k, False: 0] | Branch (1636:2): [True: 15.1k, False: 0] ------------------ 1637| 15.1k| assert(vertex_size % 4 == 0); ------------------ | Branch (1637:2): [True: 15.1k, False: 0] ------------------ 1638| 15.1k| assert(level >= 0 && level <= 9); // only a subset of this range is used right now ------------------ | Branch (1638:2): [True: 15.1k, False: 0] | Branch (1638:2): [True: 15.1k, False: 0] | Branch (1638:2): [True: 15.1k, False: 0] ------------------ 1639| 15.1k| assert(version < 0 || unsigned(version) <= kDecodeVertexVersion); ------------------ | Branch (1639:2): [True: 15.1k, False: 0] | Branch (1639:2): [True: 0, False: 0] | Branch (1639:2): [True: 15.1k, False: 0] ------------------ 1640| | 1641| 15.1k| version = version < 0 ? gEncodeVertexVersion : version; ------------------ | Branch (1641:12): [True: 15.1k, False: 0] ------------------ 1642| | 1643| |#if TRACE 1644| | memset(vertexstats, 0, sizeof(vertexstats)); 1645| |#endif 1646| | 1647| 15.1k| const unsigned char* vertex_data = static_cast(vertices); 1648| | 1649| 15.1k| unsigned char* data = buffer; 1650| 15.1k| unsigned char* data_end = buffer + buffer_size; 1651| | 1652| 15.1k| if (size_t(data_end - data) < 1) ------------------ | Branch (1652:6): [True: 0, False: 15.1k] ------------------ 1653| 0| return 0; 1654| | 1655| 15.1k| *data++ = (unsigned char)(kVertexHeader | version); 1656| | 1657| 15.1k| unsigned char first_vertex[256] = {}; 1658| 15.1k| if (vertex_count > 0) ------------------ | Branch (1658:6): [True: 11.5k, False: 3.52k] ------------------ 1659| 11.5k| memcpy(first_vertex, vertex_data, vertex_size); 1660| | 1661| 15.1k| unsigned char last_vertex[256] = {}; 1662| 15.1k| memcpy(last_vertex, first_vertex, vertex_size); 1663| | 1664| 15.1k| size_t vertex_block_size = getVertexBlockSize(vertex_size); 1665| | 1666| 15.1k| unsigned char channels[64] = {}; 1667| 15.1k| if (version != 0 && level > 1 && vertex_count > 1) ------------------ | Branch (1667:6): [True: 11.9k, False: 3.18k] | Branch (1667:22): [True: 6.11k, False: 5.81k] | Branch (1667:35): [True: 4.25k, False: 1.86k] ------------------ 1668| 22.3k| for (size_t k = 0; k < vertex_size; k += 4) ------------------ | Branch (1668:22): [True: 18.0k, False: 4.25k] ------------------ 1669| 18.0k| { 1670| 18.0k| int rot = level >= 3 ? estimateRotate(vertex_data, vertex_count, vertex_size, k, /* group_size= */ 16) : 0; ------------------ | Branch (1670:14): [True: 15.7k, False: 2.31k] ------------------ 1671| 18.0k| int channel = estimateChannel(vertex_data, vertex_count, vertex_size, k, vertex_block_size, /* block_skip= */ 3, /* max_channel= */ level >= 3 ? 3 : 2, rot); ------------------ | Branch (1671:136): [True: 15.7k, False: 2.31k] ------------------ 1672| | 1673| 18.0k| assert(unsigned(channel) < 2 || ((channel & 3) == 2 && unsigned(channel >> 4) < 8)); ------------------ | Branch (1673:4): [True: 1.99k, False: 0] | Branch (1673:4): [True: 1.99k, False: 0] | Branch (1673:4): [True: 16.0k, False: 1.99k] | Branch (1673:4): [True: 18.0k, False: 0] ------------------ 1674| 18.0k| channels[k / 4] = (unsigned char)channel; 1675| 18.0k| } 1676| | 1677| 15.1k| size_t vertex_offset = 0; 1678| | 1679| 295k| while (vertex_offset < vertex_count) ------------------ | Branch (1679:9): [True: 280k, False: 15.1k] ------------------ 1680| 280k| { 1681| 280k| size_t block_size = (vertex_offset + vertex_block_size < vertex_count) ? vertex_block_size : vertex_count - vertex_offset; ------------------ | Branch (1681:23): [True: 268k, False: 11.5k] ------------------ 1682| | 1683| 280k| data = encodeVertexBlock(data, data_end, vertex_data + vertex_offset * vertex_size, block_size, vertex_size, last_vertex, channels, version, level); 1684| 280k| if (!data) ------------------ | Branch (1684:7): [True: 0, False: 280k] ------------------ 1685| 0| return 0; 1686| | 1687| 280k| vertex_offset += block_size; 1688| 280k| } 1689| | 1690| 15.1k| size_t tail_size = vertex_size + (version == 0 ? 0 : vertex_size / 4); ------------------ | Branch (1690:36): [True: 3.18k, False: 11.9k] ------------------ 1691| 15.1k| size_t tail_size_min = version == 0 ? kTailMinSizeV0 : kTailMinSizeV1; ------------------ | Branch (1691:25): [True: 3.18k, False: 11.9k] ------------------ 1692| 15.1k| size_t tail_size_pad = tail_size < tail_size_min ? tail_size_min : tail_size; ------------------ | Branch (1692:25): [True: 8.35k, False: 6.76k] ------------------ 1693| | 1694| 15.1k| if (size_t(data_end - data) < tail_size_pad) ------------------ | Branch (1694:6): [True: 0, False: 15.1k] ------------------ 1695| 0| return 0; 1696| | 1697| 15.1k| if (tail_size < tail_size_pad) ------------------ | Branch (1697:6): [True: 8.35k, False: 6.76k] ------------------ 1698| 8.35k| { 1699| 8.35k| memset(data, 0, tail_size_pad - tail_size); 1700| 8.35k| data += tail_size_pad - tail_size; 1701| 8.35k| } 1702| | 1703| 15.1k| memcpy(data, first_vertex, vertex_size); 1704| 15.1k| data += vertex_size; 1705| | 1706| 15.1k| if (version != 0) ------------------ | Branch (1706:6): [True: 11.9k, False: 3.18k] ------------------ 1707| 11.9k| { 1708| 11.9k| memcpy(data, channels, vertex_size / 4); 1709| 11.9k| data += vertex_size / 4; 1710| 11.9k| } 1711| | 1712| 15.1k| assert(data >= buffer + tail_size); ------------------ | Branch (1712:2): [True: 15.1k, False: 0] ------------------ 1713| 15.1k| assert(data <= buffer + buffer_size); ------------------ | Branch (1713:2): [True: 15.1k, False: 0] ------------------ 1714| | 1715| |#if TRACE 1716| | size_t total_size = data - buffer; 1717| | 1718| | for (size_t k = 0; k < vertex_size; ++k) 1719| | { 1720| | const Stats& vsk = vertexstats[k]; 1721| | 1722| | 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); 1723| | 1724| | size_t total_k = vsk.header + vsk.bitg[1] + vsk.bitg[2] + vsk.bitg[4] + vsk.bitg[8]; 1725| | double total_kr = total_k ? 1.0 / double(total_k) : 0; 1726| | 1727| | if (version != 0) 1728| | { 1729| | int channel = channels[k / 4]; 1730| | 1731| | if ((channel & 3) == 2 && k % 4 == 0) 1732| | printf(" | ^%d", channel >> 4); 1733| | else 1734| | printf(" | %2s", channel == 0 ? "1" : (channel == 1 && k % 2 == 0 ? "2" : ".")); 1735| | } 1736| | 1737| | printf(" | hdr [%5.1f%%] bitg [1 %4.1f%% 2 %4.1f%% 4 %4.1f%% 8 %4.1f%%]", 1738| | double(vsk.header) * total_kr * 100, 1739| | double(vsk.bitg[1]) * total_kr * 100, double(vsk.bitg[2]) * total_kr * 100, 1740| | double(vsk.bitg[4]) * total_kr * 100, double(vsk.bitg[8]) * total_kr * 100); 1741| | 1742| | size_t total_ctrl = vsk.ctrl[0] + vsk.ctrl[1] + vsk.ctrl[2] + vsk.ctrl[3]; 1743| | 1744| | if (total_ctrl) 1745| | { 1746| | printf(" | ctrl %3.0f%% %3.0f%% %3.0f%% %3.0f%%", 1747| | double(vsk.ctrl[0]) / double(total_ctrl) * 100, double(vsk.ctrl[1]) / double(total_ctrl) * 100, 1748| | double(vsk.ctrl[2]) / double(total_ctrl) * 100, double(vsk.ctrl[3]) / double(total_ctrl) * 100); 1749| | } 1750| | 1751| | if (level >= 3) 1752| | printf(" | bitc [%3.0f%% %3.0f%% %3.0f%% %3.0f%% %3.0f%% %3.0f%% %3.0f%% %3.0f%%]", 1753| | double(vsk.bitc[0]) / double(vertex_count) * 100, double(vsk.bitc[1]) / double(vertex_count) * 100, 1754| | double(vsk.bitc[2]) / double(vertex_count) * 100, double(vsk.bitc[3]) / double(vertex_count) * 100, 1755| | double(vsk.bitc[4]) / double(vertex_count) * 100, double(vsk.bitc[5]) / double(vertex_count) * 100, 1756| | double(vsk.bitc[6]) / double(vertex_count) * 100, double(vsk.bitc[7]) / double(vertex_count) * 100); 1757| | 1758| | printf("\n"); 1759| | } 1760| |#endif 1761| | 1762| 15.1k| return data - buffer; 1763| 15.1k|} meshopt_encodeVertexBufferBound: 1771| 7.55k|{ 1772| 7.55k| using namespace meshopt; 1773| | 1774| 7.55k| assert(vertex_size > 0 && vertex_size <= 256); ------------------ | Branch (1774:2): [True: 7.55k, False: 0] | Branch (1774:2): [True: 7.55k, False: 0] | Branch (1774:2): [True: 7.55k, False: 0] ------------------ 1775| 7.55k| assert(vertex_size % 4 == 0); ------------------ | Branch (1775:2): [True: 7.55k, False: 0] ------------------ 1776| | 1777| 7.55k| size_t vertex_block_size = getVertexBlockSize(vertex_size); 1778| 7.55k| size_t vertex_block_count = (vertex_count + vertex_block_size - 1) / vertex_block_size; 1779| | 1780| 7.55k| size_t vertex_block_control_size = vertex_size / 4; 1781| 7.55k| size_t vertex_byte_header_size = (vertex_block_size / kByteGroupSize + 3) / 4; 1782| 7.55k| size_t vertex_byte_data_size = vertex_block_size; 1783| | 1784| 7.55k| size_t tail_size = vertex_size + (vertex_size / 4); 1785| 7.55k| size_t tail_size_min = kTailMinSizeV0 > kTailMinSizeV1 ? kTailMinSizeV0 : kTailMinSizeV1; ------------------ | Branch (1785:25): [True: 7.55k, Folded] ------------------ 1786| 7.55k| size_t tail_size_pad = tail_size < tail_size_min ? tail_size_min : tail_size; ------------------ | Branch (1786:25): [True: 5.66k, False: 1.88k] ------------------ 1787| 7.55k| assert(tail_size_pad >= kByteGroupDecodeLimit); ------------------ | Branch (1787:2): [True: 7.55k, False: 0] ------------------ 1788| | 1789| 7.55k| return 1 + vertex_block_count * (vertex_block_control_size + vertex_size * (vertex_byte_header_size + vertex_byte_data_size)) + tail_size_pad; 1790| 7.55k|} meshopt_encodeVertexVersion: 1793| 1.88k|{ 1794| 1.88k| assert(unsigned(version) <= unsigned(meshopt::kDecodeVertexVersion)); ------------------ | Branch (1794:2): [True: 1.88k, False: 0] ------------------ 1795| | 1796| 1.88k| meshopt::gEncodeVertexVersion = version; 1797| 1.88k|} meshopt_decodeVertexBuffer: 1817| 15.1k|{ 1818| 15.1k| using namespace meshopt; 1819| | 1820| 15.1k| assert(vertex_size > 0 && vertex_size <= 256); ------------------ | Branch (1820:2): [True: 15.1k, False: 0] | Branch (1820:2): [True: 15.1k, False: 0] | Branch (1820:2): [True: 15.1k, False: 0] ------------------ 1821| 15.1k| assert(vertex_size % 4 == 0); ------------------ | Branch (1821:2): [True: 15.1k, False: 0] ------------------ 1822| | 1823| 15.1k| const unsigned char* (*decode)(const unsigned char*, const unsigned char*, unsigned char*, size_t, size_t, unsigned char[256], const unsigned char*, int) = NULL; 1824| | 1825| 15.1k|#if defined(SIMD_SSE) && defined(SIMD_FALLBACK) 1826| 15.1k| const unsigned int cpumask = (1 << 9) | (1 << 23); // SSSE3+POPCNT 1827| 15.1k| decode = (cpuid & cpumask) == cpumask ? decodeVertexBlockSimd : decodeVertexBlock; ------------------ | Branch (1827:11): [True: 15.1k, False: 0] ------------------ 1828| |#elif defined(SIMD_SSE) || defined(SIMD_AVX) || defined(SIMD_NEON) || defined(SIMD_WASM) 1829| | decode = decodeVertexBlockSimd; 1830| |#else 1831| | decode = decodeVertexBlock; 1832| |#endif 1833| | 1834| 15.1k|#if defined(SIMD_SSE) || defined(SIMD_NEON) || defined(SIMD_WASM) 1835| 15.1k| assert(gDecodeBytesGroupInitialized); ------------------ | Branch (1835:2): [True: 15.1k, False: 0] ------------------ 1836| 15.1k| (void)gDecodeBytesGroupInitialized; 1837| 15.1k|#endif 1838| | 1839| 15.1k| unsigned char* vertex_data = static_cast(destination); 1840| | 1841| 15.1k| const unsigned char* data = buffer; 1842| 15.1k| const unsigned char* data_end = buffer + buffer_size; 1843| | 1844| 15.1k| if (size_t(data_end - data) < 1) ------------------ | Branch (1844:6): [True: 0, False: 15.1k] ------------------ 1845| 0| return -2; 1846| | 1847| 15.1k| unsigned char data_header = *data++; 1848| | 1849| 15.1k| if ((data_header & 0xf0) != kVertexHeader) ------------------ | Branch (1849:6): [True: 6.54k, False: 8.56k] ------------------ 1850| 6.54k| return -1; 1851| | 1852| 8.56k| int version = data_header & 0x0f; 1853| 8.56k| if (version > kDecodeVertexVersion) ------------------ | Branch (1853:6): [True: 92, False: 8.47k] ------------------ 1854| 92| return -1; 1855| | 1856| 8.47k| size_t tail_size = vertex_size + (version == 0 ? 0 : vertex_size / 4); ------------------ | Branch (1856:36): [True: 1.80k, False: 6.67k] ------------------ 1857| 8.47k| size_t tail_size_min = version == 0 ? kTailMinSizeV0 : kTailMinSizeV1; ------------------ | Branch (1857:25): [True: 1.80k, False: 6.67k] ------------------ 1858| 8.47k| size_t tail_size_pad = tail_size < tail_size_min ? tail_size_min : tail_size; ------------------ | Branch (1858:25): [True: 4.68k, False: 3.78k] ------------------ 1859| | 1860| 8.47k| if (size_t(data_end - data) < tail_size_pad) ------------------ | Branch (1860:6): [True: 147, False: 8.32k] ------------------ 1861| 147| return -2; 1862| | 1863| 8.32k| const unsigned char* tail = data_end - tail_size; 1864| | 1865| 8.32k| unsigned char last_vertex[256]; 1866| 8.32k| memcpy(last_vertex, tail, vertex_size); 1867| | 1868| 8.32k| const unsigned char* channels = version == 0 ? NULL : tail + vertex_size; ------------------ | Branch (1868:34): [True: 1.78k, False: 6.54k] ------------------ 1869| | 1870| 8.32k| size_t vertex_block_size = getVertexBlockSize(vertex_size); 1871| | 1872| 8.32k| size_t vertex_offset = 0; 1873| | 1874| 148k| while (vertex_offset < vertex_count) ------------------ | Branch (1874:9): [True: 141k, False: 7.89k] ------------------ 1875| 141k| { 1876| 141k| size_t block_size = (vertex_offset + vertex_block_size < vertex_count) ? vertex_block_size : vertex_count - vertex_offset; ------------------ | Branch (1876:23): [True: 134k, False: 6.56k] ------------------ 1877| | 1878| 141k| data = decode(data, data_end, vertex_data + vertex_offset * vertex_size, block_size, vertex_size, last_vertex, channels, version); 1879| 141k| if (!data) ------------------ | Branch (1879:7): [True: 437, False: 140k] ------------------ 1880| 437| return -2; 1881| | 1882| 140k| vertex_offset += block_size; 1883| 140k| } 1884| | 1885| 7.89k| if (size_t(data_end - data) != tail_size_pad) ------------------ | Branch (1885:6): [True: 335, False: 7.55k] ------------------ 1886| 335| return -3; 1887| | 1888| 7.55k| return 0; 1889| 7.89k|} vertexcodec.cpp:_ZN7meshoptL27decodeBytesGroupBuildTablesEv: 809| 2|{ 810| 514| for (int mask = 0; mask < 256; ++mask) ------------------ | Branch (810:21): [True: 512, False: 2] ------------------ 811| 512| { 812| 512| unsigned char shuffle[8]; 813| 512| unsigned char count = 0; 814| | 815| 4.60k| for (int i = 0; i < 8; ++i) ------------------ | Branch (815:19): [True: 4.09k, False: 512] ------------------ 816| 4.09k| { 817| 4.09k| int maski = (mask >> i) & 1; 818| 4.09k| shuffle[i] = maski ? count : 0x80; ------------------ | Branch (818:17): [True: 2.04k, False: 2.04k] ------------------ 819| 4.09k| count += (unsigned char)(maski); 820| 4.09k| } 821| | 822| 512| memcpy(kDecodeBytesGroupShuffle[mask], shuffle, 8); 823| 512| kDecodeBytesGroupCount[mask] = count; 824| 512| } 825| | 826| 2| return true; 827| 2|} vertexcodec.cpp:_ZN7meshoptL14getCpuFeaturesEv: 1617| 2|{ 1618| 2| int cpuinfo[4] = {}; 1619| |#ifdef _MSC_VER 1620| | __cpuid(cpuinfo, 1); 1621| |#else 1622| | __cpuid(1, cpuinfo[0], cpuinfo[1], cpuinfo[2], cpuinfo[3]); 1623| 2|#endif 1624| 2| return cpuinfo[2]; 1625| 2|} vertexcodec.cpp:_ZN7meshoptL18getVertexBlockSizeEm: 141| 30.9k|{ 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| 30.9k| size_t result = (kVertexBlockSizeBytes / vertex_size) & ~(kByteGroupSize - 1); 145| | 146| 30.9k| return (result < kVertexBlockMaxSize) ? result : kVertexBlockMaxSize; ------------------ | Branch (146:9): [True: 0, False: 30.9k] ------------------ 147| 30.9k|} vertexcodec.cpp:_ZN7meshoptL14estimateRotateEPKhmmmm: 378| 15.7k|{ 379| 15.7k| size_t sizes[8] = {}; 380| | 381| 15.7k| const unsigned char* vertex = vertex_data + k; 382| 15.7k| unsigned int last = vertex[0] | (vertex[1] << 8) | (vertex[2] << 16) | (vertex[3] << 24); 383| | 384| 4.87M| for (size_t i = 0; i < vertex_count; i += group_size) ------------------ | Branch (384:21): [True: 4.85M, False: 15.7k] ------------------ 385| 4.85M| { 386| 4.85M| unsigned int bitg = 0; 387| | 388| | // calculate bit consistency mask for the group 389| 82.4M| for (size_t j = 0; j < group_size && i + j < vertex_count; ++j) ------------------ | Branch (389:22): [True: 77.6M, False: 4.84M] | Branch (389:40): [True: 77.5M, False: 13.5k] ------------------ 390| 77.5M| { 391| 77.5M| unsigned int v = vertex[0] | (vertex[1] << 8) | (vertex[2] << 16) | (vertex[3] << 24); 392| 77.5M| unsigned int d = v ^ last; 393| | 394| 77.5M| bitg |= d; 395| 77.5M| last = v; 396| 77.5M| vertex += vertex_size; 397| 77.5M| } 398| | 399| |#if TRACE 400| | for (int j = 0; j < 32; ++j) 401| | vertexstats[k + (j / 8)].bitc[j % 8] += (i + group_size < vertex_count ? group_size : vertex_count - i) * (1 - ((bitg >> j) & 1)); 402| |#endif 403| | 404| 43.7M| for (int j = 0; j < 8; ++j) ------------------ | Branch (404:19): [True: 38.8M, False: 4.85M] ------------------ 405| 38.8M| { 406| 38.8M| unsigned int bitr = rotate(bitg, j); 407| | 408| 38.8M| sizes[j] += estimateBits((unsigned char)(bitr >> 0)) + estimateBits((unsigned char)(bitr >> 8)); 409| 38.8M| sizes[j] += estimateBits((unsigned char)(bitr >> 16)) + estimateBits((unsigned char)(bitr >> 24)); 410| 38.8M| } 411| 4.85M| } 412| | 413| 15.7k| int best_rot = 0; 414| 126k| for (int rot = 1; rot < 8; ++rot) ------------------ | Branch (414:20): [True: 110k, False: 15.7k] ------------------ 415| 110k| best_rot = (sizes[rot] < sizes[best_rot]) ? rot : best_rot; ------------------ | Branch (415:14): [True: 5.49k, False: 104k] ------------------ 416| | 417| 15.7k| return best_rot; 418| 15.7k|} _ZN7meshopt6rotateEji: 150| 70.6M|{ 151| 70.6M| return (v << r) | (v >> ((32 - r) & 31)); 152| 70.6M|} vertexcodec.cpp:_ZN7meshoptL12estimateBitsEh: 373| 155M|{ 374| 155M| return v <= 15 ? (v <= 3 ? (v == 0 ? 0 : 2) : 4) : 8; ------------------ | Branch (374:9): [True: 49.5M, False: 105M] | Branch (374:20): [True: 48.8M, False: 756k] | Branch (374:30): [True: 48.1M, False: 661k] ------------------ 375| 155M|} vertexcodec.cpp:_ZN7meshoptL15estimateChannelEPKhmmmmmii: 421| 18.0k|{ 422| 18.0k| unsigned char blocks[kVertexBlockMaxSize * 4]; 423| 18.0k| assert(vertex_block_size <= kVertexBlockMaxSize); ------------------ | Branch (423:2): [True: 18.0k, False: 0] ------------------ 424| | 425| 18.0k| unsigned char last_vertex[256] = {}; 426| | 427| 18.0k| size_t sizes[3] = {}; 428| 18.0k| assert(max_channel <= 3); ------------------ | Branch (428:2): [True: 18.0k, False: 0] ------------------ 429| | 430| 144k| for (size_t i = 0; i < vertex_count; i += vertex_block_size * block_skip) ------------------ | Branch (430:21): [True: 125k, False: 18.0k] ------------------ 431| 125k| { 432| 125k| size_t block_size = i + vertex_block_size < vertex_count ? vertex_block_size : vertex_count - i; ------------------ | Branch (432:23): [True: 111k, False: 14.1k] ------------------ 433| 125k| size_t block_size_aligned = (block_size + kByteGroupSize - 1) & ~(kByteGroupSize - 1); 434| | 435| 125k| memcpy(last_vertex, vertex_data + (i == 0 ? 0 : i - 1) * vertex_size, vertex_size); ------------------ | Branch (435:38): [True: 18.0k, False: 107k] ------------------ 436| | 437| | // we sometimes encode elements we didn't fill when rounding to kByteGroupSize 438| 125k| if (block_size < block_size_aligned) ------------------ | Branch (438:7): [True: 12.3k, False: 113k] ------------------ 439| 61.7k| for (size_t j = 0; j < 4; ++j) ------------------ | Branch (439:23): [True: 49.4k, False: 12.3k] ------------------ 440| 49.4k| memset(blocks + j * kVertexBlockMaxSize + block_size, 0, block_size_aligned - block_size); 441| | 442| 491k| for (int channel = 0; channel < max_channel; ++channel) ------------------ | Branch (442:25): [True: 365k, False: 125k] ------------------ 443| 1.82M| for (size_t j = 0; j < 4; ++j) ------------------ | Branch (443:23): [True: 1.46M, False: 365k] ------------------ 444| 1.46M| { 445| | // fill blocks with deltas for 4 bytes per vertex (current channel) at once 446| 1.46M| if (j == 0) ------------------ | Branch (446:9): [True: 365k, False: 1.09M] ------------------ 447| 365k| encodeDeltas(blocks, vertex_data + i * vertex_size, block_size, vertex_size, last_vertex, k, channel | (xor_rot << 4)); 448| | 449| 1.46M| const unsigned char* block = blocks + j * kVertexBlockMaxSize; 450| | 451| 22.8M| for (size_t ig = 0; ig < block_size; ig += kByteGroupSize) ------------------ | Branch (451:25): [True: 21.3M, False: 1.46M] ------------------ 452| 21.3M| { 453| | // to maximize encoding performance we only evaluate 1/2/4/8 bit groups 454| 21.3M| size_t size1 = encodeBytesGroupMeasure(block + ig, 1); 455| 21.3M| size_t size2 = encodeBytesGroupMeasure(block + ig, 2); 456| 21.3M| size_t size4 = encodeBytesGroupMeasure(block + ig, 4); 457| 21.3M| size_t size8 = encodeBytesGroupMeasure(block + ig, 8); 458| | 459| 21.3M| size_t best_size = size1 < size2 ? size1 : size2; ------------------ | Branch (459:25): [True: 20.4M, False: 908k] ------------------ 460| 21.3M| best_size = best_size < size4 ? best_size : size4; ------------------ | Branch (460:18): [True: 21.3M, False: 77.5k] ------------------ 461| 21.3M| best_size = best_size < size8 ? best_size : size8; ------------------ | Branch (461:18): [True: 8.63M, False: 12.7M] ------------------ 462| | 463| 21.3M| sizes[channel] += best_size; 464| 21.3M| } 465| 1.46M| } 466| 125k| } 467| | 468| 18.0k| int best_channel = 0; 469| 51.9k| for (int channel = 1; channel < max_channel; ++channel) ------------------ | Branch (469:24): [True: 33.8k, False: 18.0k] ------------------ 470| 33.8k| best_channel = (sizes[channel] < sizes[best_channel]) ? channel : best_channel; ------------------ | Branch (470:18): [True: 5.04k, False: 28.8k] ------------------ 471| | 472| 18.0k| return best_channel == 2 ? best_channel | (xor_rot << 4) : best_channel; ------------------ | Branch (472:9): [True: 1.99k, False: 16.0k] ------------------ 473| 18.0k|} vertexcodec.cpp:_ZN7meshoptL12encodeDeltasEPhPKhmmS2_mi: 357| 1.11M|{ 358| | // encode deltas for a single channel (4 bytes per vertex) into [buffer + 0..3 * kVertexBlockMaxSize] 359| 1.11M| switch (channel & 3) 360| 1.11M| { 361| 776k| case 0: ------------------ | Branch (361:2): [True: 776k, False: 333k] ------------------ 362| 776k| return encodeDeltas4(buffer, vertex_data + k, vertex_count, vertex_size, last_vertex + k, 0); 363| 198k| case 1: ------------------ | Branch (363:2): [True: 198k, False: 911k] ------------------ 364| 198k| return encodeDeltas4(buffer, vertex_data + k, vertex_count, vertex_size, last_vertex + k, 0); 365| 135k| case 2: ------------------ | Branch (365:2): [True: 135k, False: 974k] ------------------ 366| 135k| return encodeDeltas4(buffer, vertex_data + k, vertex_count, vertex_size, last_vertex + k, channel >> 4); 367| 0| default: ------------------ | Branch (367:2): [True: 0, False: 1.11M] ------------------ 368| | assert(!"Unsupported channel encoding"); // unreachable ------------------ | Branch (368:3): [Folded, False: 0] ------------------ 369| 1.11M| } 370| 1.11M|} vertexcodec.cpp:_ZN7meshoptL13encodeDeltas4IhLb0EEEvPhPKhmmS3_i: 332| 776k|{ 333| 186M| for (size_t i = 0; i < vertex_count; ++i) ------------------ | Branch (333:21): [True: 186M, False: 776k] ------------------ 334| 186M| { 335| 930M| for (size_t k = 0; k < 4; k += sizeof(T)) ------------------ | Branch (335:22): [True: 744M, False: 186M] ------------------ 336| 744M| { 337| 744M| T p = last_vertex[k]; 338| 744M| for (size_t j = 1; j < sizeof(T); ++j) ------------------ | Branch (338:23): [True: 0, False: 744M] ------------------ 339| 0| p |= last_vertex[k + j] << (j * 8); 340| | 341| 744M| T v = vertex[k]; 342| 744M| for (size_t j = 1; j < sizeof(T); ++j) ------------------ | Branch (342:23): [True: 0, False: 744M] ------------------ 343| 0| v |= vertex[k + j] << (j * 8); 344| | 345| 744M| T d = Xor ? T(rotate(v ^ p, rot)) : zigzag(T(v - p)); ------------------ | Branch (345:10): [Folded, False: 744M] ------------------ 346| | 347| 1.48G| for (size_t j = 0; j < sizeof(T); ++j) ------------------ | Branch (347:23): [True: 744M, False: 744M] ------------------ 348| 744M| buffer[(k + j) * kVertexBlockMaxSize + i] = (unsigned char)(d >> (j * 8)); 349| 744M| } 350| | 351| 186M| last_vertex = vertex; 352| 186M| vertex += vertex_size; 353| 186M| } 354| 776k|} _ZN7meshopt6zigzagIhEET_S1_: 156| 744M|{ 157| 744M| return (0 - (v >> (sizeof(T) * 8 - 1))) ^ (v << 1); 158| 744M|} vertexcodec.cpp:_ZN7meshoptL13encodeDeltas4ItLb0EEEvPhPKhmmS3_i: 332| 198k|{ 333| 47.5M| for (size_t i = 0; i < vertex_count; ++i) ------------------ | Branch (333:21): [True: 47.3M, False: 198k] ------------------ 334| 47.3M| { 335| 142M| for (size_t k = 0; k < 4; k += sizeof(T)) ------------------ | Branch (335:22): [True: 94.7M, False: 47.3M] ------------------ 336| 94.7M| { 337| 94.7M| T p = last_vertex[k]; 338| 189M| for (size_t j = 1; j < sizeof(T); ++j) ------------------ | Branch (338:23): [True: 94.7M, False: 94.7M] ------------------ 339| 94.7M| p |= last_vertex[k + j] << (j * 8); 340| | 341| 94.7M| T v = vertex[k]; 342| 189M| for (size_t j = 1; j < sizeof(T); ++j) ------------------ | Branch (342:23): [True: 94.7M, False: 94.7M] ------------------ 343| 94.7M| v |= vertex[k + j] << (j * 8); 344| | 345| 94.7M| T d = Xor ? T(rotate(v ^ p, rot)) : zigzag(T(v - p)); ------------------ | Branch (345:10): [Folded, False: 94.7M] ------------------ 346| | 347| 284M| for (size_t j = 0; j < sizeof(T); ++j) ------------------ | Branch (347:23): [True: 189M, False: 94.7M] ------------------ 348| 189M| buffer[(k + j) * kVertexBlockMaxSize + i] = (unsigned char)(d >> (j * 8)); 349| 94.7M| } 350| | 351| 47.3M| last_vertex = vertex; 352| 47.3M| vertex += vertex_size; 353| 47.3M| } 354| 198k|} _ZN7meshopt6zigzagItEET_S1_: 156| 94.7M|{ 157| 94.7M| return (0 - (v >> (sizeof(T) * 8 - 1))) ^ (v << 1); 158| 94.7M|} vertexcodec.cpp:_ZN7meshoptL13encodeDeltas4IjLb1EEEvPhPKhmmS3_i: 332| 135k|{ 333| 31.9M| for (size_t i = 0; i < vertex_count; ++i) ------------------ | Branch (333:21): [True: 31.8M, False: 135k] ------------------ 334| 31.8M| { 335| 63.6M| for (size_t k = 0; k < 4; k += sizeof(T)) ------------------ | Branch (335:22): [True: 31.8M, False: 31.8M] ------------------ 336| 31.8M| { 337| 31.8M| T p = last_vertex[k]; 338| 127M| for (size_t j = 1; j < sizeof(T); ++j) ------------------ | Branch (338:23): [True: 95.4M, False: 31.8M] ------------------ 339| 95.4M| p |= last_vertex[k + j] << (j * 8); 340| | 341| 31.8M| T v = vertex[k]; 342| 127M| for (size_t j = 1; j < sizeof(T); ++j) ------------------ | Branch (342:23): [True: 95.4M, False: 31.8M] ------------------ 343| 95.4M| v |= vertex[k + j] << (j * 8); 344| | 345| 31.8M| T d = Xor ? T(rotate(v ^ p, rot)) : zigzag(T(v - p)); ------------------ | Branch (345:10): [True: 31.8M, Folded] ------------------ 346| | 347| 159M| for (size_t j = 0; j < sizeof(T); ++j) ------------------ | Branch (347:23): [True: 127M, False: 31.8M] ------------------ 348| 127M| buffer[(k + j) * kVertexBlockMaxSize + i] = (unsigned char)(d >> (j * 8)); 349| 31.8M| } 350| | 351| 31.8M| last_vertex = vertex; 352| 31.8M| vertex += vertex_size; 353| 31.8M| } 354| 135k|} vertexcodec.cpp:_ZN7meshoptL23encodeBytesGroupMeasureEPKhi: 191| 239M|{ 192| 239M| assert(bits >= 0 && bits <= 8); ------------------ | Branch (192:2): [True: 239M, False: 0] | Branch (192:2): [True: 239M, False: 0] | Branch (192:2): [True: 239M, False: 0] ------------------ 193| 239M| assert(kByteGroupSize == sizeof(unsigned long long) * 2); ------------------ | Branch (193:2): [True: 239M, Folded] ------------------ 194| | 195| 239M| if (bits == 0) ------------------ | Branch (195:6): [True: 20.9M, False: 218M] ------------------ 196| 20.9M| return encodeBytesGroupZero(buffer) ? 0 : size_t(-1); ------------------ | Branch (196:10): [True: 3.36M, False: 17.5M] ------------------ 197| | 198| 218M| if (bits == 8) ------------------ | Branch (198:6): [True: 53.4M, False: 164M] ------------------ 199| 53.4M| return kByteGroupSize; 200| | 201| 164M| unsigned long long v[2]; 202| 164M| memcpy(v, buffer, sizeof(v)); 203| | 204| 164M| unsigned long long sent = ((1ull << bits) - 1) * 0x0101010101010101ull; 205| 164M| unsigned long long mask = 0x8080808080808080ull; 206| | 207| | // each byte gets high bit 1 iff x >= sentinel; subtraction borrows high bit, so we need to reset high bit to 1 for all bytes that already had it as 1 208| 164M| unsigned long long m0 = (((v[0] | mask) - sent) | v[0]) & mask; 209| 164M| unsigned long long m1 = (((v[1] | mask) - sent) | v[1]) & mask; 210| | 211| | // adds all bytes together to get the number of bytes that were >= sentinel 212| 164M| size_t rest = size_t((((m0 >> 7) + (m1 >> 7)) * 0x0101010101010101ull) >> 56); 213| | 214| 164M| return kByteGroupSize / 8 * bits + rest; 215| 218M|} vertexcodec.cpp:_ZN7meshoptL20encodeBytesGroupZeroEPKh: 181| 38.9M|{ 182| 38.9M| assert(kByteGroupSize == sizeof(unsigned long long) * 2); ------------------ | Branch (182:2): [True: 38.9M, Folded] ------------------ 183| | 184| 38.9M| unsigned long long v[2]; 185| 38.9M| memcpy(v, buffer, sizeof(v)); 186| | 187| 38.9M| return (v[0] | v[1]) == 0; 188| 38.9M|} vertexcodec.cpp:_ZN7meshoptL17encodeVertexBlockEPhS0_PKhmmS0_S2_ii: 523| 280k|{ 524| 280k| assert(vertex_count > 0 && vertex_count <= kVertexBlockMaxSize); ------------------ | Branch (524:2): [True: 280k, False: 0] | Branch (524:2): [True: 280k, False: 0] | Branch (524:2): [True: 280k, False: 0] ------------------ 525| 280k| assert(vertex_size % 4 == 0); ------------------ | Branch (525:2): [True: 280k, False: 0] ------------------ 526| | 527| 280k| unsigned char buffers[kVertexBlockMaxSize * 4]; 528| 280k| assert(kVertexBlockMaxSize % kByteGroupSize == 0); ------------------ | Branch (528:2): [True: 280k, Folded] ------------------ 529| | 530| 280k| size_t vertex_count_aligned = (vertex_count + kByteGroupSize - 1) & ~(kByteGroupSize - 1); 531| | 532| | // we sometimes encode elements we didn't fill when rounding to kByteGroupSize 533| 280k| memset(buffers, 0, sizeof(buffers)); 534| | 535| 280k| size_t control_size = version == 0 ? 0 : vertex_size / 4; ------------------ | Branch (535:24): [True: 9.18k, False: 271k] ------------------ 536| 280k| if (size_t(data_end - data) < control_size) ------------------ | Branch (536:6): [True: 0, False: 280k] ------------------ 537| 0| return NULL; 538| | 539| 280k| unsigned char* control = data; 540| 280k| data += control_size; 541| | 542| 280k| memset(control, 0, control_size); 543| | 544| 3.25M| for (size_t k = 0; k < vertex_size; ++k) ------------------ | Branch (544:21): [True: 2.97M, False: 280k] ------------------ 545| 2.97M| { 546| | // fill buffers with deltas for 4 bytes per vertex (current channel) at once 547| 2.97M| if (k % 4 == 0) ------------------ | Branch (547:7): [True: 744k, False: 2.23M] ------------------ 548| 744k| encodeDeltas(buffers, vertex_data, vertex_count, vertex_size, last_vertex, k, version == 0 ? 0 : channels[k / 4]); ------------------ | Branch (548:82): [True: 28.4k, False: 716k] ------------------ 549| | 550| 2.97M| const unsigned char* buffer = buffers + (k % 4) * kVertexBlockMaxSize; 551| | 552| |#if TRACE 553| | const unsigned char* olddata = data; 554| | bytestats = &vertexstats[k]; 555| |#endif 556| | 557| 2.97M| int ctrl = 0; 558| | 559| 2.97M| if (version != 0) ------------------ | Branch (559:7): [True: 2.86M, False: 113k] ------------------ 560| 2.86M| { 561| 2.86M| ctrl = estimateControl(buffer, vertex_count, vertex_count_aligned, level); 562| | 563| 2.86M| assert(unsigned(ctrl) < 4); ------------------ | Branch (563:4): [True: 2.86M, False: 0] ------------------ 564| 2.86M| control[k / 4] |= ctrl << ((k % 4) * 2); 565| | 566| |#if TRACE 567| | vertexstats[k].ctrl[ctrl]++; 568| |#endif 569| 2.86M| } 570| | 571| 2.97M| if (ctrl == 3) ------------------ | Branch (571:7): [True: 886k, False: 2.09M] ------------------ 572| 886k| { 573| | // literal encoding 574| 886k| if (size_t(data_end - data) < vertex_count) ------------------ | Branch (574:8): [True: 0, False: 886k] ------------------ 575| 0| return NULL; 576| | 577| 886k| memcpy(data, buffer, vertex_count); 578| 886k| data += vertex_count; 579| 886k| } 580| 2.09M| else if (ctrl != 2) // non-zero encoding ------------------ | Branch (580:12): [True: 1.08M, False: 1.01M] ------------------ 581| 1.08M| { 582| 1.08M| data = encodeBytes(data, data_end, buffer, vertex_count_aligned, version == 0 ? kBitsV0 : kBitsV1 + ctrl); ------------------ | Branch (582:69): [True: 113k, False: 966k] ------------------ 583| 1.08M| if (!data) ------------------ | Branch (583:8): [True: 0, False: 1.08M] ------------------ 584| 0| return NULL; 585| 1.08M| } 586| | 587| |#if TRACE 588| | bytestats = NULL; 589| | vertexstats[k].size += data - olddata; 590| |#endif 591| 2.97M| } 592| | 593| 280k| memcpy(last_vertex, &vertex_data[vertex_size * (vertex_count - 1)], vertex_size); 594| | 595| 280k| return data; 596| 280k|} vertexcodec.cpp:_ZN7meshoptL15estimateControlEPKhmmi: 485| 2.86M|{ 486| 2.86M| if (estimateControlZero(buffer, vertex_count_aligned)) ------------------ | Branch (486:6): [True: 1.01M, False: 1.85M] ------------------ 487| 1.01M| return 2; // zero encoding 488| | 489| 1.85M| if (level == 0) ------------------ | Branch (489:6): [True: 681k, False: 1.17M] ------------------ 490| 681k| return 1; // 1248 encoding in level 0 for encoding speed 491| | 492| | // round number of groups to 4 to get number of header bytes 493| 1.17M| size_t header_size = (vertex_count_aligned / kByteGroupSize + 3) / 4; 494| | 495| 1.17M| size_t est_bytes0 = header_size, est_bytes1 = header_size; 496| | 497| 19.0M| for (size_t i = 0; i < vertex_count_aligned; i += kByteGroupSize) ------------------ | Branch (497:21): [True: 17.8M, False: 1.17M] ------------------ 498| 17.8M| { 499| | // assumes kBitsV1[] = {0, 1, 2, 4, 8} for performance 500| 17.8M| size_t size0 = encodeBytesGroupMeasure(buffer + i, 0); 501| 17.8M| size_t size1 = encodeBytesGroupMeasure(buffer + i, 1); 502| 17.8M| size_t size2 = encodeBytesGroupMeasure(buffer + i, 2); 503| 17.8M| size_t size4 = encodeBytesGroupMeasure(buffer + i, 4); 504| 17.8M| size_t size8 = encodeBytesGroupMeasure(buffer + i, 8); 505| | 506| | // both control modes have access to 1/2/4 bit encoding 507| 17.8M| size_t size12 = size1 < size2 ? size1 : size2; ------------------ | Branch (507:19): [True: 16.3M, False: 1.45M] ------------------ 508| 17.8M| size_t size124 = size12 < size4 ? size12 : size4; ------------------ | Branch (508:20): [True: 17.7M, False: 72.2k] ------------------ 509| | 510| | // each control mode has access to 0/8 bit encoding respectively 511| 17.8M| est_bytes0 += size124 < size0 ? size124 : size0; ------------------ | Branch (511:17): [True: 16.3M, False: 1.45M] ------------------ 512| 17.8M| est_bytes1 += size124 < size8 ? size124 : size8; ------------------ | Branch (512:17): [True: 3.61M, False: 14.2M] ------------------ 513| 17.8M| } 514| | 515| | // pick shortest control entry but prefer literal encoding 516| 1.17M| if (est_bytes0 < vertex_count || est_bytes1 < vertex_count) ------------------ | Branch (516:6): [True: 254k, False: 917k] | Branch (516:35): [True: 31.2k, False: 886k] ------------------ 517| 285k| return est_bytes0 < est_bytes1 ? 0 : 1; ------------------ | Branch (517:10): [True: 123k, False: 162k] ------------------ 518| 886k| else 519| 886k| return 3; // literal encoding 520| 1.17M|} vertexcodec.cpp:_ZN7meshoptL19estimateControlZeroEPKhm: 476| 2.86M|{ 477| 19.0M| for (size_t i = 0; i < vertex_count_aligned; i += kByteGroupSize) ------------------ | Branch (477:21): [True: 18.0M, False: 1.01M] ------------------ 478| 18.0M| if (!encodeBytesGroupZero(buffer + i)) ------------------ | Branch (478:7): [True: 1.85M, False: 16.1M] ------------------ 479| 1.85M| return false; 480| | 481| 1.01M| return true; 482| 2.86M|} vertexcodec.cpp:_ZN7meshoptL11encodeBytesEPhS0_PKhmPKi: 271| 1.08M|{ 272| 1.08M| assert(buffer_size % kByteGroupSize == 0); ------------------ | Branch (272:2): [True: 1.08M, False: 0] ------------------ 273| | 274| 1.08M| unsigned char* header = data; 275| | 276| | // round number of groups to 4 to get number of header bytes 277| 1.08M| size_t header_size = (buffer_size / kByteGroupSize + 3) / 4; 278| | 279| 1.08M| if (size_t(data_end - data) < header_size) ------------------ | Branch (279:6): [True: 0, False: 1.08M] ------------------ 280| 0| return NULL; 281| | 282| 1.08M| data += header_size; 283| | 284| 1.08M| memset(header, 0, header_size); 285| | 286| 1.08M| int last_bits = -1; 287| | 288| 17.1M| for (size_t i = 0; i < buffer_size; i += kByteGroupSize) ------------------ | Branch (288:21): [True: 16.0M, False: 1.08M] ------------------ 289| 16.0M| { 290| 16.0M| if (size_t(data_end - data) < kByteGroupDecodeLimit) ------------------ | Branch (290:7): [True: 0, False: 16.0M] ------------------ 291| 0| return NULL; 292| | 293| 16.0M| int best_bitk = 3; 294| 16.0M| size_t best_size = encodeBytesGroupMeasure(buffer + i, bits[best_bitk]); 295| | 296| 64.3M| for (int bitk = 0; bitk < 3; ++bitk) ------------------ | Branch (296:22): [True: 48.2M, False: 16.0M] ------------------ 297| 48.2M| { 298| 48.2M| size_t size = encodeBytesGroupMeasure(buffer + i, bits[bitk]); 299| | 300| | // favor consistent bit selection across groups, but never replace literals 301| 48.2M| if (size < best_size || (size == best_size && bits[bitk] == last_bits && bits[best_bitk] != 8)) ------------------ | Branch (301:8): [True: 7.91M, False: 40.3M] | Branch (301:29): [True: 947k, False: 39.3M] | Branch (301:50): [True: 246k, False: 700k] | Branch (301:77): [True: 28.6k, False: 218k] ------------------ 302| 7.94M| { 303| 7.94M| best_bitk = bitk; 304| 7.94M| best_size = size; 305| 7.94M| } 306| 48.2M| } 307| | 308| 16.0M| size_t header_offset = i / kByteGroupSize; 309| 16.0M| header[header_offset / 4] |= best_bitk << ((header_offset % 4) * 2); 310| | 311| 16.0M| int best_bits = bits[best_bitk]; 312| 16.0M| unsigned char* next = encodeBytesGroup(data, buffer + i, best_bits); 313| | 314| 16.0M| assert(data + best_size == next); ------------------ | Branch (314:3): [True: 16.0M, False: 0] ------------------ 315| 16.0M| data = next; 316| 16.0M| last_bits = best_bits; 317| | 318| |#if TRACE 319| | bytestats->bitg[best_bits] += best_size; 320| |#endif 321| 16.0M| } 322| | 323| |#if TRACE 324| | bytestats->header += header_size; 325| |#endif 326| | 327| 1.08M| return data; 328| 1.08M|} vertexcodec.cpp:_ZN7meshoptL16encodeBytesGroupEPhPKhi: 218| 16.0M|{ 219| 16.0M| assert(bits >= 0 && bits <= 8); ------------------ | Branch (219:2): [True: 16.0M, False: 0] | Branch (219:2): [True: 16.0M, False: 0] | Branch (219:2): [True: 16.0M, False: 0] ------------------ 220| 16.0M| assert(kByteGroupSize % 8 == 0); ------------------ | Branch (220:2): [True: 16.0M, Folded] ------------------ 221| | 222| 16.0M| if (bits == 0) ------------------ | Branch (222:6): [True: 1.90M, False: 14.1M] ------------------ 223| 1.90M| return data; 224| | 225| 14.1M| if (bits == 8) ------------------ | Branch (225:6): [True: 9.20M, False: 4.97M] ------------------ 226| 9.20M| { 227| 9.20M| memcpy(data, buffer, kByteGroupSize); 228| 9.20M| return data + kByteGroupSize; 229| 9.20M| } 230| | 231| 14.1M| assert(8 % bits == 0); ------------------ | Branch (231:2): [True: 4.97M, False: 0] ------------------ 232| 4.97M| size_t byte_size = size_t(8) >> (bits >> 1); // 8 / bits for bits 1/2/4 233| | 234| | // fixed portion: bits bits for each value 235| | // variable portion: full byte for each out-of-range value (using 1...1 as sentinel) 236| 4.97M| unsigned char sentinel = (1 << bits) - 1; 237| | 238| 18.0M| for (size_t i = 0; i < kByteGroupSize; i += byte_size) ------------------ | Branch (238:21): [True: 13.0M, False: 4.97M] ------------------ 239| 13.0M| { 240| 13.0M| unsigned char byte = 0; 241| | 242| 92.6M| for (size_t k = 0; k < byte_size; ++k) ------------------ | Branch (242:22): [True: 79.5M, False: 13.0M] ------------------ 243| 79.5M| { 244| 79.5M| unsigned char enc = (buffer[i + k] >= sentinel) ? sentinel : buffer[i + k]; ------------------ | Branch (244:24): [True: 30.9M, False: 48.6M] ------------------ 245| | 246| 79.5M| byte <<= bits; 247| 79.5M| byte |= enc; 248| 79.5M| } 249| | 250| | // encode 1-bit groups in reverse bit order 251| | // this makes them faster to decode alongside other groups 252| 13.0M| if (bits == 1) ------------------ | Branch (252:7): [True: 7.03M, False: 5.99M] ------------------ 253| 7.03M| byte = (unsigned char)(((byte * 0x80200802ull) & 0x0884422110ull) * 0x0101010101ull >> 32); 254| | 255| 13.0M| *data++ = byte; 256| 13.0M| } 257| | 258| 84.5M| for (size_t i = 0; i < kByteGroupSize; ++i) ------------------ | Branch (258:21): [True: 79.5M, False: 4.97M] ------------------ 259| 79.5M| { 260| 79.5M| unsigned char v = buffer[i]; 261| | 262| | // branchless append of out-of-range values 263| 79.5M| *data = v; 264| 79.5M| data += v >= sentinel; 265| 79.5M| } 266| | 267| 4.97M| return data; 268| 4.97M|} vertexcodec.cpp:_ZN7meshoptL21decodeVertexBlockSimdEPKhS1_PhmmS2_S1_i: 1532| 141k|{ 1533| 141k| assert(vertex_count > 0 && vertex_count <= kVertexBlockMaxSize); ------------------ | Branch (1533:2): [True: 141k, False: 0] | Branch (1533:2): [True: 141k, False: 0] | Branch (1533:2): [True: 141k, False: 0] ------------------ 1534| | 1535| 141k| unsigned char buffer[kVertexBlockMaxSize * 4]; 1536| 141k| unsigned char transposed[kVertexBlockSizeBytes]; 1537| | 1538| 141k| size_t vertex_count_aligned = (vertex_count + kByteGroupSize - 1) & ~(kByteGroupSize - 1); 1539| | 1540| | // we can decode directly into the output buffer if vertex count is aligned to 16 (delta decode works 16 vertices at a time) 1541| | // 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 1542| |#ifdef MESHOPTIMIZER_VERTEXCODEC_ZEROCOPY 1543| | unsigned char* target = vertex_count == vertex_count_aligned ? vertex_data : transposed; 1544| |#else 1545| 141k| unsigned char* target = transposed; 1546| 141k|#endif 1547| | 1548| 141k| size_t control_size = version == 0 ? 0 : vertex_size / 4; ------------------ | Branch (1548:24): [True: 4.78k, False: 136k] ------------------ 1549| 141k| if (size_t(data_end - data) < control_size) ------------------ | Branch (1549:6): [True: 0, False: 141k] ------------------ 1550| 0| return NULL; 1551| | 1552| 141k| const unsigned char* control = data; 1553| 141k| data += control_size; 1554| | 1555| 514k| for (size_t k = 0; k < vertex_size; k += 4) ------------------ | Branch (1555:21): [True: 374k, False: 140k] ------------------ 1556| 374k| { 1557| 374k| unsigned char ctrl_byte = version == 0 ? 0 : control[k / 4]; ------------------ | Branch (1557:29): [True: 14.8k, False: 359k] ------------------ 1558| | 1559| 1.87M| for (size_t j = 0; j < 4; ++j) ------------------ | Branch (1559:22): [True: 1.49M, False: 374k] ------------------ 1560| 1.49M| { 1561| 1.49M| int ctrl = (ctrl_byte >> (j * 2)) & 3; 1562| | 1563| 1.49M| if (ctrl == 3) ------------------ | Branch (1563:8): [True: 443k, False: 1.05M] ------------------ 1564| 443k| { 1565| | // literal encoding; safe to over-copy due to tail 1566| 443k| if (size_t(data_end - data) < vertex_count_aligned) ------------------ | Branch (1566:9): [True: 109, False: 443k] ------------------ 1567| 109| return NULL; 1568| | 1569| 443k| memcpy(buffer + j * vertex_count_aligned, data, vertex_count_aligned); 1570| 443k| data += vertex_count; 1571| 443k| } 1572| 1.05M| else if (ctrl == 2) ------------------ | Branch (1572:13): [True: 508k, False: 544k] ------------------ 1573| 508k| { 1574| | // zero encoding 1575| 508k| memset(buffer + j * vertex_count_aligned, 0, vertex_count_aligned); 1576| 508k| } 1577| 544k| else 1578| 544k| { 1579| | // for v0, headers are mapped to 0..3; for v1, headers are mapped to 4..8 1580| 544k| int hshift = version == 0 ? 0 : 4 + ctrl; ------------------ | Branch (1580:18): [True: 59.1k, False: 485k] ------------------ 1581| | 1582| 544k| data = decodeBytesSimd(data, data_end, buffer + j * vertex_count_aligned, vertex_count_aligned, hshift); 1583| 544k| if (!data) ------------------ | Branch (1583:9): [True: 235, False: 544k] ------------------ 1584| 235| return NULL; 1585| 544k| } 1586| 1.49M| } 1587| | 1588| 374k| int channel = version == 0 ? 0 : channels[k / 4]; ------------------ | Branch (1588:17): [True: 14.7k, False: 359k] ------------------ 1589| | 1590| 374k| switch (channel & 3) 1591| 374k| { 1592| 326k| case 0: ------------------ | Branch (1592:3): [True: 326k, False: 47.5k] ------------------ 1593| 326k| decodeDeltas4Simd<0>(buffer, target + k, vertex_count_aligned, vertex_size, last_vertex + k, 0); 1594| 326k| break; 1595| 36.2k| case 1: ------------------ | Branch (1595:3): [True: 36.2k, False: 337k] ------------------ 1596| 36.2k| decodeDeltas4Simd<1>(buffer, target + k, vertex_count_aligned, vertex_size, last_vertex + k, 0); 1597| 36.2k| break; 1598| 11.1k| case 2: ------------------ | Branch (1598:3): [True: 11.1k, False: 362k] ------------------ 1599| 11.1k| decodeDeltas4Simd<2>(buffer, target + k, vertex_count_aligned, vertex_size, last_vertex + k, (32 - (channel >> 4)) & 31); 1600| 11.1k| break; 1601| 93| default: ------------------ | Branch (1601:3): [True: 93, False: 373k] ------------------ 1602| 93| return NULL; // invalid channel type 1603| 374k| } 1604| 374k| } 1605| | 1606| 140k| if (target == transposed) ------------------ | Branch (1606:6): [True: 140k, False: 0] ------------------ 1607| 140k| memcpy(vertex_data, transposed, vertex_count * vertex_size); 1608| | 1609| 140k| memcpy(last_vertex, &target[vertex_size * (vertex_count - 1)], vertex_size); 1610| | 1611| 140k| return data; 1612| 141k|} vertexcodec.cpp:_ZN7meshoptL15decodeBytesSimdEPKhS1_Phmi: 1387| 544k|{ 1388| 544k| assert(buffer_size % kByteGroupSize == 0); ------------------ | Branch (1388:2): [True: 544k, False: 0] ------------------ 1389| 544k| assert(kByteGroupSize == 16); ------------------ | Branch (1389:2): [True: 544k, Folded] ------------------ 1390| | 1391| | // round number of groups to 4 to get number of header bytes 1392| 544k| size_t header_size = (buffer_size / kByteGroupSize + 3) / 4; 1393| 544k| if (size_t(data_end - data) < header_size) ------------------ | Branch (1393:6): [True: 29, False: 544k] ------------------ 1394| 29| return NULL; 1395| | 1396| 544k| const unsigned char* header = data; 1397| 544k| data += header_size; 1398| | 1399| 544k| size_t i = 0; 1400| | 1401| | // fast-path: process 4 groups at a time, do a shared bounds check 1402| 2.53M| for (; i + kByteGroupSize * 4 <= buffer_size && size_t(data_end - data) >= kByteGroupDecodeLimit * 4; i += kByteGroupSize * 4) ------------------ | Branch (1402:9): [True: 1.99M, False: 541k] | Branch (1402:50): [True: 1.99M, False: 3.35k] ------------------ 1403| 1.99M| { 1404| 1.99M| size_t header_offset = i / kByteGroupSize; 1405| 1.99M| unsigned char header_byte = header[header_offset / 4]; 1406| | 1407| 1.99M|#if defined(SIMD_SSE) || defined(SIMD_AVX) 1408| | // 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), 1409| | // the branchless decoders are slower than branching over the decoding of 4 groups and issuing a few load/store ops 1410| 1.99M| if (hshift != 5 && header_byte == 0) ------------------ | Branch (1410:7): [True: 375k, False: 1.61M] | Branch (1410:22): [True: 181k, False: 193k] ------------------ 1411| 181k| { 1412| 181k| memset(buffer + i, 0, kByteGroupSize * 4); 1413| 181k| continue; 1414| 181k| } 1415| 1.81M| else if (hshift != 4 && header_byte == 255) ------------------ | Branch (1415:12): [True: 1.70M, False: 110k] | Branch (1415:27): [True: 1.06M, False: 637k] ------------------ 1416| 1.06M| { 1417| 1.06M| memcpy(buffer + i, data, kByteGroupSize * 4); 1418| 1.06M| data += kByteGroupSize * 4; 1419| 1.06M| continue; 1420| 1.06M| } 1421| 748k|#endif 1422| | 1423| 748k| data = decodeBytesGroupSimd(data, buffer + i + kByteGroupSize * 0, hshift + ((header_byte >> 0) & 3)); 1424| 748k| data = decodeBytesGroupSimd(data, buffer + i + kByteGroupSize * 1, hshift + ((header_byte >> 2) & 3)); 1425| 748k| data = decodeBytesGroupSimd(data, buffer + i + kByteGroupSize * 2, hshift + ((header_byte >> 4) & 3)); 1426| 748k| data = decodeBytesGroupSimd(data, buffer + i + kByteGroupSize * 3, hshift + ((header_byte >> 6) & 3)); 1427| 748k| } 1428| | 1429| | // slow-path: process remaining groups 1430| 636k| for (; i < buffer_size; i += kByteGroupSize) ------------------ | Branch (1430:9): [True: 92.1k, False: 544k] ------------------ 1431| 92.1k| { 1432| 92.1k| if (size_t(data_end - data) < kByteGroupDecodeLimit) ------------------ | Branch (1432:7): [True: 206, False: 91.9k] ------------------ 1433| 206| return NULL; 1434| | 1435| 91.9k| size_t header_offset = i / kByteGroupSize; 1436| 91.9k| unsigned char header_byte = header[header_offset / 4]; 1437| | 1438| 91.9k| data = decodeBytesGroupSimd(data, buffer + i, hshift + ((header_byte >> ((header_offset % 4) * 2)) & 3)); 1439| 91.9k| } 1440| | 1441| 544k| return data; 1442| 544k|} vertexcodec.cpp:_ZN7meshoptL20decodeBytesGroupSimdEPKhPhi: 848| 3.08M|{ 849| | // 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 850| 3.08M| static const int hbtn[9] = {4, 1, 2, 3, 4, 0, 1, 2, 3}; 851| | 852| 3.08M| int n = hbtn[hbits]; 853| | 854| 3.08M|#ifdef SIMD_LATENCYOPT 855| 3.08M| unsigned long long data64; 856| 3.08M| memcpy(&data64, data, 8); 857| 3.08M| data64 &= data64 >> n; 858| 3.08M| data64 &= data64 >> (n >> 1); 859| | 860| | // mask out one bit per group that is set if all group bits were 1 861| 3.08M| static const unsigned long long lanes[9] = {0, 0x55555555, 0x1111111111111111ull, 0, 0, 0xffff, 0x55555555, 0x1111111111111111ull, 0}; 862| 3.08M| int datacnt = int(_mm_popcnt_u64(data64 & lanes[hbits])); 863| 3.08M|#endif 864| | 865| | // for 8-bit groups, instead of loading the bytes through 'data', we load them through 'skip' as they are easier to preserve 866| | // for 0-bit groups, the load results get discarded because mask is always 0; in both cases the shift wraps to zero 867| 3.08M| const unsigned char* skip = data + ((2 << n) & 15); 868| | 869| 3.08M| __m128i selb = _mm_loadl_epi64(reinterpret_cast(data)); 870| 3.08M| __m128i rest = _mm_loadu_si128(reinterpret_cast(skip)); 871| | 872| | // unpack 1, 2 or 4-bit values: shuffle replicates each source byte into both halves of a 16-bit lane 873| | // mulhi extracts even and odd fields into the low byte; the results are interleaved back with shift/or 874| 3.08M| __m128i selw = _mm_shuffle_epi8(selb, _mm_loadu_si128(reinterpret_cast(kDecodeBytesGroupConfig[hbits][1]))); 875| 3.08M| __m128i sel0 = _mm_mulhi_epu16(selw, _mm_loadu_si128(reinterpret_cast(kDecodeBytesGroupConfig[hbits][2]))); 876| 3.08M| __m128i sel1 = _mm_mulhi_epu16(selw, _mm_loadu_si128(reinterpret_cast(kDecodeBytesGroupConfig[hbits][3]))); 877| 3.08M| __m128i seli = _mm_or_si128(sel0, _mm_slli_epi16(sel1, 8)); 878| | 879| | // the interleaved fields are masked by the bit count (special handling: for 0/8-bit values, mul produces 0) 880| 3.08M| __m128i sent = _mm_loadu_si128(reinterpret_cast(kDecodeBytesGroupConfig[hbits][0])); 881| 3.08M| __m128i sel = _mm_and_si128(seli, sent); 882| | 883| | // 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) 884| 3.08M| __m128i mask = _mm_cmpeq_epi8(sel, sent); 885| 3.08M| int mask16 = _mm_movemask_epi8(mask); 886| 3.08M| unsigned char mask0 = (unsigned char)(mask16 & 255); 887| 3.08M| unsigned char mask1 = (unsigned char)(mask16 >> 8); 888| | 889| | // decode shuffle mask from two halves; second half needs to be shifted by popcount(mask0) 890| 3.08M| __m128i sm0 = _mm_loadl_epi64(reinterpret_cast(&kDecodeBytesGroupShuffle[mask0])); 891| 3.08M| __m128i sm1 = _mm_loadl_epi64(reinterpret_cast(&kDecodeBytesGroupShuffle[mask1])); 892| | 893| | // each lane of mask is 0x00 or 0xff; sad yields 255*popcount(mask0) in low word => low byte is -popcount(mask0) 894| 3.08M| __m128i npops = _mm_sad_epu8(mask, _mm_setzero_si128()); 895| 3.08M| __m128i sm1r = _mm_sub_epi8(sm1, _mm_shuffle_epi8(npops, _mm_setzero_si128())); 896| 3.08M| __m128i shuf = _mm_unpacklo_epi64(sm0, sm1r); 897| | 898| | // expand rest via shuffle mask and combine with sel; shuffle mask zeroes out bytes that are replaced by sel 899| 3.08M| __m128i result = _mm_or_si128(_mm_shuffle_epi8(rest, shuf), _mm_andnot_si128(mask, sel)); 900| | 901| 3.08M| _mm_storeu_si128(reinterpret_cast<__m128i*>(buffer), result); 902| | 903| 3.08M|#ifdef SIMD_LATENCYOPT 904| | // datacnt is 0 for 8-bit groups so we can't use skip to advance; 0-bit groups wrap the shift to zero 905| 3.08M| return data + ((2 << n) & 31) + datacnt; 906| |#else 907| | return skip + _mm_popcnt_u32(mask16); 908| |#endif 909| 3.08M|} vertexcodec.cpp:_ZN7meshoptL17decodeDeltas4SimdILi0EEEvPKhPhmmS3_i: 1447| 326k|{ 1448| 326k|#if defined(SIMD_SSE) || defined(SIMD_AVX) 1449| 326k|#define TEMP __m128i 1450| 326k|#define PREP() __m128i pi = _mm_cvtsi32_si128(*reinterpret_cast(last_vertex)) 1451| 326k|#define LOAD(i) __m128i r##i = _mm_loadu_si128(reinterpret_cast(buffer + j + i * vertex_count_aligned)) 1452| 326k|#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) 1453| 326k|#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)) 1454| 326k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size 1455| 326k|#endif 1456| | 1457| |#ifdef SIMD_NEON 1458| |#define TEMP uint8x8_t 1459| |#define PREP() uint8x8_t pi = vreinterpret_u8_u32(vld1_lane_u32(reinterpret_cast(last_vertex), vdup_n_u32(0), 0)) 1460| |#define LOAD(i) uint8x16_t r##i = vld1q_u8(buffer + j + i * vertex_count_aligned) 1461| |#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)) 1462| |#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)) 1463| |#define SAVE(i) vst1_lane_u32(reinterpret_cast(savep), vreinterpret_u32_u8(t##i), 0), savep += vertex_size 1464| |#endif 1465| | 1466| |#ifdef SIMD_WASM 1467| |#define TEMP v128_t 1468| |#define PREP() v128_t pi = wasm_v128_load(last_vertex) 1469| |#define LOAD(i) v128_t r##i = wasm_v128_load(buffer + j + i * vertex_count_aligned) 1470| |#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) 1471| |#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)) 1472| |#define SAVE(i) wasm_v128_store32_lane(savep, t##i, 0), savep += vertex_size 1473| |#endif 1474| | 1475| 326k|#define UNZR(i) r##i = Channel == 0 ? unzigzag8(r##i) : (Channel == 1 ? unzigzag16(r##i) : rotate32(r##i, rot)) 1476| | 1477| 326k| PREP(); ------------------ | | 1450| 326k|#define PREP() __m128i pi = _mm_cvtsi32_si128(*reinterpret_cast(last_vertex)) ------------------ 1478| | 1479| 326k| unsigned char* savep = transposed; 1480| | 1481| 5.24M| for (size_t j = 0; j < vertex_count_aligned; j += 16) ------------------ | Branch (1481:21): [True: 4.92M, False: 326k] ------------------ 1482| 4.92M| { 1483| 4.92M| LOAD(0); ------------------ | | 1451| 4.92M|#define LOAD(i) __m128i r##i = _mm_loadu_si128(reinterpret_cast(buffer + j + i * vertex_count_aligned)) ------------------ 1484| 4.92M| LOAD(1); ------------------ | | 1451| 4.92M|#define LOAD(i) __m128i r##i = _mm_loadu_si128(reinterpret_cast(buffer + j + i * vertex_count_aligned)) ------------------ 1485| 4.92M| LOAD(2); ------------------ | | 1451| 4.92M|#define LOAD(i) __m128i r##i = _mm_loadu_si128(reinterpret_cast(buffer + j + i * vertex_count_aligned)) ------------------ 1486| 4.92M| LOAD(3); ------------------ | | 1451| 4.92M|#define LOAD(i) __m128i r##i = _mm_loadu_si128(reinterpret_cast(buffer + j + i * vertex_count_aligned)) ------------------ 1487| | 1488| 4.92M| transpose8(r0, r1, r2, r3); 1489| | 1490| 4.92M| TEMP t0, t1, t2, t3; ------------------ | | 1449| 4.92M|#define TEMP __m128i ------------------ 1491| 4.92M| TEMP npi = pi; ------------------ | | 1449| 4.92M|#define TEMP __m128i ------------------ 1492| | 1493| 4.92M| UNZR(0); ------------------ | | 1475| 4.92M|#define UNZR(i) r##i = Channel == 0 ? unzigzag8(r##i) : (Channel == 1 ? unzigzag16(r##i) : rotate32(r##i, rot)) | | ------------------ | | | Branch (1475:24): [True: 4.92M, Folded] | | | Branch (1475:58): [Folded, False: 0] | | ------------------ ------------------ 1494| 4.92M| GRP4(0); ------------------ | | 1452| 4.92M|#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) ------------------ 1495| 4.92M| FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1453| 4.92M|#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 (1453:29): [True: 4.92M, Folded] | | | Branch (1453:70): [Folded, False: 0] | | ------------------ ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1453| 4.92M|#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 (1453:29): [True: 4.92M, Folded] | | | Branch (1453:70): [Folded, False: 0] | | ------------------ ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1453| 4.92M|#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 (1453:29): [True: 4.92M, Folded] | | | Branch (1453:70): [Folded, False: 0] | | ------------------ ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1453| 4.92M|#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 (1453:29): [True: 4.92M, Folded] | | | Branch (1453:70): [Folded, False: 0] | | ------------------ ------------------ 1496| 4.92M| SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1454| 4.92M|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1454| 4.92M|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1454| 4.92M|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1454| 4.92M|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ 1497| | 1498| 4.92M| UNZR(1); ------------------ | | 1475| 4.92M|#define UNZR(i) r##i = Channel == 0 ? unzigzag8(r##i) : (Channel == 1 ? unzigzag16(r##i) : rotate32(r##i, rot)) | | ------------------ | | | Branch (1475:24): [True: 4.92M, Folded] | | | Branch (1475:58): [Folded, False: 0] | | ------------------ ------------------ 1499| 4.92M| GRP4(1); ------------------ | | 1452| 4.92M|#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) ------------------ 1500| 4.92M| FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1453| 4.92M|#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 (1453:29): [True: 4.92M, Folded] | | | Branch (1453:70): [Folded, False: 0] | | ------------------ ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1453| 4.92M|#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 (1453:29): [True: 4.92M, Folded] | | | Branch (1453:70): [Folded, False: 0] | | ------------------ ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1453| 4.92M|#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 (1453:29): [True: 4.92M, Folded] | | | Branch (1453:70): [Folded, False: 0] | | ------------------ ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1453| 4.92M|#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 (1453:29): [True: 4.92M, Folded] | | | Branch (1453:70): [Folded, False: 0] | | ------------------ ------------------ 1501| 4.92M| SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1454| 4.92M|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1454| 4.92M|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1454| 4.92M|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1454| 4.92M|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ 1502| | 1503| 4.92M| UNZR(2); ------------------ | | 1475| 4.92M|#define UNZR(i) r##i = Channel == 0 ? unzigzag8(r##i) : (Channel == 1 ? unzigzag16(r##i) : rotate32(r##i, rot)) | | ------------------ | | | Branch (1475:24): [True: 4.92M, Folded] | | | Branch (1475:58): [Folded, False: 0] | | ------------------ ------------------ 1504| 4.92M| GRP4(2); ------------------ | | 1452| 4.92M|#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) ------------------ 1505| 4.92M| FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1453| 4.92M|#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 (1453:29): [True: 4.92M, Folded] | | | Branch (1453:70): [Folded, False: 0] | | ------------------ ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1453| 4.92M|#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 (1453:29): [True: 4.92M, Folded] | | | Branch (1453:70): [Folded, False: 0] | | ------------------ ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1453| 4.92M|#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 (1453:29): [True: 4.92M, Folded] | | | Branch (1453:70): [Folded, False: 0] | | ------------------ ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1453| 4.92M|#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 (1453:29): [True: 4.92M, Folded] | | | Branch (1453:70): [Folded, False: 0] | | ------------------ ------------------ 1506| 4.92M| SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1454| 4.92M|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1454| 4.92M|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1454| 4.92M|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1454| 4.92M|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ 1507| | 1508| 4.92M| UNZR(3); ------------------ | | 1475| 4.92M|#define UNZR(i) r##i = Channel == 0 ? unzigzag8(r##i) : (Channel == 1 ? unzigzag16(r##i) : rotate32(r##i, rot)) | | ------------------ | | | Branch (1475:24): [True: 4.92M, Folded] | | | Branch (1475:58): [Folded, False: 0] | | ------------------ ------------------ 1509| 4.92M| GRP4(3); ------------------ | | 1452| 4.92M|#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) ------------------ 1510| 4.92M| FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1453| 4.92M|#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 (1453:29): [True: 4.92M, Folded] | | | Branch (1453:70): [Folded, False: 0] | | ------------------ ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1453| 4.92M|#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 (1453:29): [True: 4.92M, Folded] | | | Branch (1453:70): [Folded, False: 0] | | ------------------ ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1453| 4.92M|#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 (1453:29): [True: 4.92M, Folded] | | | Branch (1453:70): [Folded, False: 0] | | ------------------ ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1453| 4.92M|#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 (1453:29): [True: 4.92M, Folded] | | | Branch (1453:70): [Folded, False: 0] | | ------------------ ------------------ 1511| 4.92M| SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1454| 4.92M|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1454| 4.92M|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1454| 4.92M|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1454| 4.92M|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ 1512| | 1513| |#if defined(SIMD_LATENCYOPT) && defined(SIMD_NEON) && (defined(__APPLE__) || defined(_WIN32)) 1514| | // instead of relying on accumulated pi, recompute it from scratch from r0..r3; this shortens dependency between loop iterations 1515| | pi = rebase(npi, r0, r1, r2, r3); 1516| |#else 1517| 4.92M| (void)npi; 1518| 4.92M|#endif 1519| | 1520| 4.92M|#undef UNZR 1521| 4.92M|#undef TEMP 1522| 4.92M|#undef PREP 1523| 4.92M|#undef LOAD 1524| 4.92M|#undef GRP4 1525| 4.92M|#undef FIXD 1526| 4.92M|#undef SAVE 1527| 4.92M| } 1528| 326k|} _ZN7meshopt10transpose8ERDv2_xS1_S1_S1_: 1236| 5.65M|{ 1237| 5.65M| __m128i t0 = _mm_unpacklo_epi8(x0, x1); 1238| 5.65M| __m128i t1 = _mm_unpackhi_epi8(x0, x1); 1239| 5.65M| __m128i t2 = _mm_unpacklo_epi8(x2, x3); 1240| 5.65M| __m128i t3 = _mm_unpackhi_epi8(x2, x3); 1241| | 1242| 5.65M| x0 = _mm_unpacklo_epi16(t0, t2); 1243| 5.65M| x1 = _mm_unpackhi_epi16(t0, t2); 1244| 5.65M| x2 = _mm_unpacklo_epi16(t1, t3); 1245| 5.65M| x3 = _mm_unpackhi_epi16(t1, t3); 1246| 5.65M|} _ZN7meshopt9unzigzag8EDv2_x: 1250| 19.6M|{ 1251| 19.6M| __m128i xl = _mm_sub_epi8(_mm_setzero_si128(), _mm_and_si128(v, _mm_set1_epi8(1))); 1252| 19.6M| __m128i xr = _mm_and_si128(_mm_srli_epi16(v, 1), _mm_set1_epi8(127)); 1253| | 1254| 19.6M| return _mm_xor_si128(xl, xr); 1255| 19.6M|} vertexcodec.cpp:_ZN7meshoptL17decodeDeltas4SimdILi1EEEvPKhPhmmS3_i: 1447| 36.2k|{ 1448| 36.2k|#if defined(SIMD_SSE) || defined(SIMD_AVX) 1449| 36.2k|#define TEMP __m128i 1450| 36.2k|#define PREP() __m128i pi = _mm_cvtsi32_si128(*reinterpret_cast(last_vertex)) 1451| 36.2k|#define LOAD(i) __m128i r##i = _mm_loadu_si128(reinterpret_cast(buffer + j + i * vertex_count_aligned)) 1452| 36.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) 1453| 36.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)) 1454| 36.2k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size 1455| 36.2k|#endif 1456| | 1457| |#ifdef SIMD_NEON 1458| |#define TEMP uint8x8_t 1459| |#define PREP() uint8x8_t pi = vreinterpret_u8_u32(vld1_lane_u32(reinterpret_cast(last_vertex), vdup_n_u32(0), 0)) 1460| |#define LOAD(i) uint8x16_t r##i = vld1q_u8(buffer + j + i * vertex_count_aligned) 1461| |#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)) 1462| |#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)) 1463| |#define SAVE(i) vst1_lane_u32(reinterpret_cast(savep), vreinterpret_u32_u8(t##i), 0), savep += vertex_size 1464| |#endif 1465| | 1466| |#ifdef SIMD_WASM 1467| |#define TEMP v128_t 1468| |#define PREP() v128_t pi = wasm_v128_load(last_vertex) 1469| |#define LOAD(i) v128_t r##i = wasm_v128_load(buffer + j + i * vertex_count_aligned) 1470| |#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) 1471| |#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)) 1472| |#define SAVE(i) wasm_v128_store32_lane(savep, t##i, 0), savep += vertex_size 1473| |#endif 1474| | 1475| 36.2k|#define UNZR(i) r##i = Channel == 0 ? unzigzag8(r##i) : (Channel == 1 ? unzigzag16(r##i) : rotate32(r##i, rot)) 1476| | 1477| 36.2k| PREP(); ------------------ | | 1450| 36.2k|#define PREP() __m128i pi = _mm_cvtsi32_si128(*reinterpret_cast(last_vertex)) ------------------ 1478| | 1479| 36.2k| unsigned char* savep = transposed; 1480| | 1481| 601k| for (size_t j = 0; j < vertex_count_aligned; j += 16) ------------------ | Branch (1481:21): [True: 565k, False: 36.2k] ------------------ 1482| 565k| { 1483| 565k| LOAD(0); ------------------ | | 1451| 565k|#define LOAD(i) __m128i r##i = _mm_loadu_si128(reinterpret_cast(buffer + j + i * vertex_count_aligned)) ------------------ 1484| 565k| LOAD(1); ------------------ | | 1451| 565k|#define LOAD(i) __m128i r##i = _mm_loadu_si128(reinterpret_cast(buffer + j + i * vertex_count_aligned)) ------------------ 1485| 565k| LOAD(2); ------------------ | | 1451| 565k|#define LOAD(i) __m128i r##i = _mm_loadu_si128(reinterpret_cast(buffer + j + i * vertex_count_aligned)) ------------------ 1486| 565k| LOAD(3); ------------------ | | 1451| 565k|#define LOAD(i) __m128i r##i = _mm_loadu_si128(reinterpret_cast(buffer + j + i * vertex_count_aligned)) ------------------ 1487| | 1488| 565k| transpose8(r0, r1, r2, r3); 1489| | 1490| 565k| TEMP t0, t1, t2, t3; ------------------ | | 1449| 565k|#define TEMP __m128i ------------------ 1491| 565k| TEMP npi = pi; ------------------ | | 1449| 565k|#define TEMP __m128i ------------------ 1492| | 1493| 565k| UNZR(0); ------------------ | | 1475| 565k|#define UNZR(i) r##i = Channel == 0 ? unzigzag8(r##i) : (Channel == 1 ? unzigzag16(r##i) : rotate32(r##i, rot)) | | ------------------ | | | Branch (1475:24): [Folded, False: 565k] | | | Branch (1475:58): [True: 565k, Folded] | | ------------------ ------------------ 1494| 565k| GRP4(0); ------------------ | | 1452| 565k|#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) ------------------ 1495| 565k| FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1453| 565k|#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 (1453:29): [Folded, False: 565k] | | | Branch (1453:70): [True: 565k, Folded] | | ------------------ ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1453| 565k|#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 (1453:29): [Folded, False: 565k] | | | Branch (1453:70): [True: 565k, Folded] | | ------------------ ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1453| 565k|#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 (1453:29): [Folded, False: 565k] | | | Branch (1453:70): [True: 565k, Folded] | | ------------------ ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1453| 565k|#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 (1453:29): [Folded, False: 565k] | | | Branch (1453:70): [True: 565k, Folded] | | ------------------ ------------------ 1496| 565k| SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1454| 565k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1454| 565k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1454| 565k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1454| 565k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ 1497| | 1498| 565k| UNZR(1); ------------------ | | 1475| 565k|#define UNZR(i) r##i = Channel == 0 ? unzigzag8(r##i) : (Channel == 1 ? unzigzag16(r##i) : rotate32(r##i, rot)) | | ------------------ | | | Branch (1475:24): [Folded, False: 565k] | | | Branch (1475:58): [True: 565k, Folded] | | ------------------ ------------------ 1499| 565k| GRP4(1); ------------------ | | 1452| 565k|#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) ------------------ 1500| 565k| FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1453| 565k|#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 (1453:29): [Folded, False: 565k] | | | Branch (1453:70): [True: 565k, Folded] | | ------------------ ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1453| 565k|#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 (1453:29): [Folded, False: 565k] | | | Branch (1453:70): [True: 565k, Folded] | | ------------------ ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1453| 565k|#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 (1453:29): [Folded, False: 565k] | | | Branch (1453:70): [True: 565k, Folded] | | ------------------ ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1453| 565k|#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 (1453:29): [Folded, False: 565k] | | | Branch (1453:70): [True: 565k, Folded] | | ------------------ ------------------ 1501| 565k| SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1454| 565k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1454| 565k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1454| 565k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1454| 565k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ 1502| | 1503| 565k| UNZR(2); ------------------ | | 1475| 565k|#define UNZR(i) r##i = Channel == 0 ? unzigzag8(r##i) : (Channel == 1 ? unzigzag16(r##i) : rotate32(r##i, rot)) | | ------------------ | | | Branch (1475:24): [Folded, False: 565k] | | | Branch (1475:58): [True: 565k, Folded] | | ------------------ ------------------ 1504| 565k| GRP4(2); ------------------ | | 1452| 565k|#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) ------------------ 1505| 565k| FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1453| 565k|#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 (1453:29): [Folded, False: 565k] | | | Branch (1453:70): [True: 565k, Folded] | | ------------------ ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1453| 565k|#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 (1453:29): [Folded, False: 565k] | | | Branch (1453:70): [True: 565k, Folded] | | ------------------ ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1453| 565k|#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 (1453:29): [Folded, False: 565k] | | | Branch (1453:70): [True: 565k, Folded] | | ------------------ ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1453| 565k|#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 (1453:29): [Folded, False: 565k] | | | Branch (1453:70): [True: 565k, Folded] | | ------------------ ------------------ 1506| 565k| SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1454| 565k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1454| 565k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1454| 565k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1454| 565k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ 1507| | 1508| 565k| UNZR(3); ------------------ | | 1475| 565k|#define UNZR(i) r##i = Channel == 0 ? unzigzag8(r##i) : (Channel == 1 ? unzigzag16(r##i) : rotate32(r##i, rot)) | | ------------------ | | | Branch (1475:24): [Folded, False: 565k] | | | Branch (1475:58): [True: 565k, Folded] | | ------------------ ------------------ 1509| 565k| GRP4(3); ------------------ | | 1452| 565k|#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) ------------------ 1510| 565k| FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1453| 565k|#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 (1453:29): [Folded, False: 565k] | | | Branch (1453:70): [True: 565k, Folded] | | ------------------ ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1453| 565k|#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 (1453:29): [Folded, False: 565k] | | | Branch (1453:70): [True: 565k, Folded] | | ------------------ ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1453| 565k|#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 (1453:29): [Folded, False: 565k] | | | Branch (1453:70): [True: 565k, Folded] | | ------------------ ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1453| 565k|#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 (1453:29): [Folded, False: 565k] | | | Branch (1453:70): [True: 565k, Folded] | | ------------------ ------------------ 1511| 565k| SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1454| 565k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1454| 565k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1454| 565k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1454| 565k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ 1512| | 1513| |#if defined(SIMD_LATENCYOPT) && defined(SIMD_NEON) && (defined(__APPLE__) || defined(_WIN32)) 1514| | // instead of relying on accumulated pi, recompute it from scratch from r0..r3; this shortens dependency between loop iterations 1515| | pi = rebase(npi, r0, r1, r2, r3); 1516| |#else 1517| 565k| (void)npi; 1518| 565k|#endif 1519| | 1520| 565k|#undef UNZR 1521| 565k|#undef TEMP 1522| 565k|#undef PREP 1523| 565k|#undef LOAD 1524| 565k|#undef GRP4 1525| 565k|#undef FIXD 1526| 565k|#undef SAVE 1527| 565k| } 1528| 36.2k|} _ZN7meshopt10unzigzag16EDv2_x: 1259| 2.26M|{ 1260| 2.26M| __m128i xl = _mm_sub_epi16(_mm_setzero_si128(), _mm_and_si128(v, _mm_set1_epi16(1))); 1261| 2.26M| __m128i xr = _mm_srli_epi16(v, 1); 1262| | 1263| 2.26M| return _mm_xor_si128(xl, xr); 1264| 2.26M|} vertexcodec.cpp:_ZN7meshoptL17decodeDeltas4SimdILi2EEEvPKhPhmmS3_i: 1447| 11.1k|{ 1448| 11.1k|#if defined(SIMD_SSE) || defined(SIMD_AVX) 1449| 11.1k|#define TEMP __m128i 1450| 11.1k|#define PREP() __m128i pi = _mm_cvtsi32_si128(*reinterpret_cast(last_vertex)) 1451| 11.1k|#define LOAD(i) __m128i r##i = _mm_loadu_si128(reinterpret_cast(buffer + j + i * vertex_count_aligned)) 1452| 11.1k|#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) 1453| 11.1k|#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)) 1454| 11.1k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size 1455| 11.1k|#endif 1456| | 1457| |#ifdef SIMD_NEON 1458| |#define TEMP uint8x8_t 1459| |#define PREP() uint8x8_t pi = vreinterpret_u8_u32(vld1_lane_u32(reinterpret_cast(last_vertex), vdup_n_u32(0), 0)) 1460| |#define LOAD(i) uint8x16_t r##i = vld1q_u8(buffer + j + i * vertex_count_aligned) 1461| |#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)) 1462| |#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)) 1463| |#define SAVE(i) vst1_lane_u32(reinterpret_cast(savep), vreinterpret_u32_u8(t##i), 0), savep += vertex_size 1464| |#endif 1465| | 1466| |#ifdef SIMD_WASM 1467| |#define TEMP v128_t 1468| |#define PREP() v128_t pi = wasm_v128_load(last_vertex) 1469| |#define LOAD(i) v128_t r##i = wasm_v128_load(buffer + j + i * vertex_count_aligned) 1470| |#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) 1471| |#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)) 1472| |#define SAVE(i) wasm_v128_store32_lane(savep, t##i, 0), savep += vertex_size 1473| |#endif 1474| | 1475| 11.1k|#define UNZR(i) r##i = Channel == 0 ? unzigzag8(r##i) : (Channel == 1 ? unzigzag16(r##i) : rotate32(r##i, rot)) 1476| | 1477| 11.1k| PREP(); ------------------ | | 1450| 11.1k|#define PREP() __m128i pi = _mm_cvtsi32_si128(*reinterpret_cast(last_vertex)) ------------------ 1478| | 1479| 11.1k| unsigned char* savep = transposed; 1480| | 1481| 176k| for (size_t j = 0; j < vertex_count_aligned; j += 16) ------------------ | Branch (1481:21): [True: 165k, False: 11.1k] ------------------ 1482| 165k| { 1483| 165k| LOAD(0); ------------------ | | 1451| 165k|#define LOAD(i) __m128i r##i = _mm_loadu_si128(reinterpret_cast(buffer + j + i * vertex_count_aligned)) ------------------ 1484| 165k| LOAD(1); ------------------ | | 1451| 165k|#define LOAD(i) __m128i r##i = _mm_loadu_si128(reinterpret_cast(buffer + j + i * vertex_count_aligned)) ------------------ 1485| 165k| LOAD(2); ------------------ | | 1451| 165k|#define LOAD(i) __m128i r##i = _mm_loadu_si128(reinterpret_cast(buffer + j + i * vertex_count_aligned)) ------------------ 1486| 165k| LOAD(3); ------------------ | | 1451| 165k|#define LOAD(i) __m128i r##i = _mm_loadu_si128(reinterpret_cast(buffer + j + i * vertex_count_aligned)) ------------------ 1487| | 1488| 165k| transpose8(r0, r1, r2, r3); 1489| | 1490| 165k| TEMP t0, t1, t2, t3; ------------------ | | 1449| 165k|#define TEMP __m128i ------------------ 1491| 165k| TEMP npi = pi; ------------------ | | 1449| 165k|#define TEMP __m128i ------------------ 1492| | 1493| 165k| UNZR(0); ------------------ | | 1475| 165k|#define UNZR(i) r##i = Channel == 0 ? unzigzag8(r##i) : (Channel == 1 ? unzigzag16(r##i) : rotate32(r##i, rot)) | | ------------------ | | | Branch (1475:24): [Folded, False: 165k] | | | Branch (1475:58): [Folded, False: 165k] | | ------------------ ------------------ 1494| 165k| GRP4(0); ------------------ | | 1452| 165k|#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) ------------------ 1495| 165k| FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1453| 165k|#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 (1453:29): [Folded, False: 165k] | | | Branch (1453:70): [Folded, False: 165k] | | ------------------ ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1453| 165k|#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 (1453:29): [Folded, False: 165k] | | | Branch (1453:70): [Folded, False: 165k] | | ------------------ ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1453| 165k|#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 (1453:29): [Folded, False: 165k] | | | Branch (1453:70): [Folded, False: 165k] | | ------------------ ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1453| 165k|#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 (1453:29): [Folded, False: 165k] | | | Branch (1453:70): [Folded, False: 165k] | | ------------------ ------------------ 1496| 165k| SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1454| 165k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1454| 165k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1454| 165k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1454| 165k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ 1497| | 1498| 165k| UNZR(1); ------------------ | | 1475| 165k|#define UNZR(i) r##i = Channel == 0 ? unzigzag8(r##i) : (Channel == 1 ? unzigzag16(r##i) : rotate32(r##i, rot)) | | ------------------ | | | Branch (1475:24): [Folded, False: 165k] | | | Branch (1475:58): [Folded, False: 165k] | | ------------------ ------------------ 1499| 165k| GRP4(1); ------------------ | | 1452| 165k|#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) ------------------ 1500| 165k| FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1453| 165k|#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 (1453:29): [Folded, False: 165k] | | | Branch (1453:70): [Folded, False: 165k] | | ------------------ ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1453| 165k|#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 (1453:29): [Folded, False: 165k] | | | Branch (1453:70): [Folded, False: 165k] | | ------------------ ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1453| 165k|#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 (1453:29): [Folded, False: 165k] | | | Branch (1453:70): [Folded, False: 165k] | | ------------------ ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1453| 165k|#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 (1453:29): [Folded, False: 165k] | | | Branch (1453:70): [Folded, False: 165k] | | ------------------ ------------------ 1501| 165k| SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1454| 165k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1454| 165k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1454| 165k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1454| 165k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ 1502| | 1503| 165k| UNZR(2); ------------------ | | 1475| 165k|#define UNZR(i) r##i = Channel == 0 ? unzigzag8(r##i) : (Channel == 1 ? unzigzag16(r##i) : rotate32(r##i, rot)) | | ------------------ | | | Branch (1475:24): [Folded, False: 165k] | | | Branch (1475:58): [Folded, False: 165k] | | ------------------ ------------------ 1504| 165k| GRP4(2); ------------------ | | 1452| 165k|#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) ------------------ 1505| 165k| FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1453| 165k|#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 (1453:29): [Folded, False: 165k] | | | Branch (1453:70): [Folded, False: 165k] | | ------------------ ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1453| 165k|#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 (1453:29): [Folded, False: 165k] | | | Branch (1453:70): [Folded, False: 165k] | | ------------------ ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1453| 165k|#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 (1453:29): [Folded, False: 165k] | | | Branch (1453:70): [Folded, False: 165k] | | ------------------ ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1453| 165k|#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 (1453:29): [Folded, False: 165k] | | | Branch (1453:70): [Folded, False: 165k] | | ------------------ ------------------ 1506| 165k| SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1454| 165k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1454| 165k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1454| 165k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1454| 165k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ 1507| | 1508| 165k| UNZR(3); ------------------ | | 1475| 165k|#define UNZR(i) r##i = Channel == 0 ? unzigzag8(r##i) : (Channel == 1 ? unzigzag16(r##i) : rotate32(r##i, rot)) | | ------------------ | | | Branch (1475:24): [Folded, False: 165k] | | | Branch (1475:58): [Folded, False: 165k] | | ------------------ ------------------ 1509| 165k| GRP4(3); ------------------ | | 1452| 165k|#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) ------------------ 1510| 165k| FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1453| 165k|#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 (1453:29): [Folded, False: 165k] | | | Branch (1453:70): [Folded, False: 165k] | | ------------------ ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1453| 165k|#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 (1453:29): [Folded, False: 165k] | | | Branch (1453:70): [Folded, False: 165k] | | ------------------ ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1453| 165k|#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 (1453:29): [Folded, False: 165k] | | | Branch (1453:70): [Folded, False: 165k] | | ------------------ ------------------ FIXD(0), FIXD(1), FIXD(2), FIXD(3); ------------------ | | 1453| 165k|#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 (1453:29): [Folded, False: 165k] | | | Branch (1453:70): [Folded, False: 165k] | | ------------------ ------------------ 1511| 165k| SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1454| 165k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1454| 165k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1454| 165k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ SAVE(0), SAVE(1), SAVE(2), SAVE(3); ------------------ | | 1454| 165k|#define SAVE(i) *reinterpret_cast(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size ------------------ 1512| | 1513| |#if defined(SIMD_LATENCYOPT) && defined(SIMD_NEON) && (defined(__APPLE__) || defined(_WIN32)) 1514| | // instead of relying on accumulated pi, recompute it from scratch from r0..r3; this shortens dependency between loop iterations 1515| | pi = rebase(npi, r0, r1, r2, r3); 1516| |#else 1517| 165k| (void)npi; 1518| 165k|#endif 1519| | 1520| 165k|#undef UNZR 1521| 165k|#undef TEMP 1522| 165k|#undef PREP 1523| 165k|#undef LOAD 1524| 165k|#undef GRP4 1525| 165k|#undef FIXD 1526| 165k|#undef SAVE 1527| 165k| } 1528| 11.1k|} _ZN7meshopt8rotate32EDv2_xi: 1268| 660k|{ 1269| 660k| return _mm_or_si128(_mm_slli_epi32(v, r), _mm_srli_epi32(v, 32 - r)); 1270| 660k|} _Z11fuzzDecoderPKhmmPFiPvmmS0_mE: 8| 15.1k|{ 9| 15.1k| size_t count = 66; // must be divisible by 3 for decodeIndexBuffer; should be >=64 to cover large vertex blocks 10| | 11| 15.1k| void* destination = malloc(count * stride); 12| 15.1k| assert(destination); ------------------ | Branch (12:2): [True: 15.1k, False: 0] ------------------ 13| | 14| 15.1k| int rc = decode(destination, count, stride, reinterpret_cast(data), size); 15| 15.1k| (void)rc; 16| | 17| 15.1k| free(destination); 18| 15.1k|} _Z13fuzzRoundtripPKhmmi: 21| 7.55k|{ 22| 7.55k| size_t count = size / stride; 23| | 24| 7.55k| size_t bound = meshopt_encodeVertexBufferBound(count, stride); 25| 7.55k| void* encoded = malloc(bound); 26| 7.55k| void* decoded = malloc(count * stride); 27| 7.55k| assert(encoded && decoded); ------------------ | Branch (27:2): [True: 7.55k, False: 0] | Branch (27:2): [True: 7.55k, False: 0] | Branch (27:2): [True: 7.55k, False: 0] ------------------ 28| | 29| 7.55k| size_t res = meshopt_encodeVertexBufferLevel(static_cast(encoded), bound, data, count, stride, level, -1); 30| 7.55k| assert(res > 0 && res <= bound); ------------------ | Branch (30:2): [True: 7.55k, False: 0] | Branch (30:2): [True: 7.55k, False: 0] | Branch (30:2): [True: 7.55k, 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| 7.55k| size_t rese = meshopt_encodeVertexBufferLevel(static_cast(encoded) + bound - res, res, data, count, stride, level, -1); 35| 7.55k| assert(rese == res); ------------------ | Branch (35:2): [True: 7.55k, False: 0] ------------------ 36| | 37| 7.55k| int rc = meshopt_decodeVertexBuffer(decoded, count, stride, static_cast(encoded) + bound - res, res); 38| 7.55k| assert(rc == 0); ------------------ | Branch (38:2): [True: 7.55k, False: 0] ------------------ 39| | 40| 7.55k| assert(memcmp(data, decoded, count * stride) == 0); ------------------ | Branch (40:2): [True: 7.55k, False: 0] ------------------ 41| | 42| 7.55k| free(decoded); 43| 7.55k| free(encoded); 44| 7.55k|} _Z5alignmm: 47| 11.2k|{ 48| 11.2k| return (value + alignment - 1) & ~(alignment - 1); 49| 11.2k|} _Z17fuzzDecodeMeshletmmPKhm: 52| 1.87k|{ 53| | // raw decoding: allowed to write align(count, 4) elements 54| 1.87k| unsigned int rt[256]; 55| 1.87k| unsigned int rv[256]; 56| 1.87k| 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| 1.87k| unsigned short rsv[256]; 61| 1.87k| unsigned char rbt[256 * 3]; 62| | 63| 1.87k| meshopt_decodeMeshlet(rv + 256 - vertex_count, vertex_count, 4, rt + 256 - triangle_count, triangle_count, 4, data, size); 64| 1.87k| meshopt_decodeMeshlet(rsv + 256 - align(vertex_count, 2), vertex_count, 2, rt + 256 - triangle_count, triangle_count, 4, data, size); 65| 1.87k| meshopt_decodeMeshlet(rv + 256 - vertex_count, vertex_count, 4, rbt + 256 * 3 - align(triangle_count * 3, 4), triangle_count, 3, data, size); 66| 1.87k| 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| 1.87k|} _Z20fuzzRoundtripMeshletPKhm: 70| 1.88k|{ 71| 1.88k| size_t triangle_count = size / 3; 72| 1.88k| if (triangle_count > 256) ------------------ | Branch (72:6): [True: 411, False: 1.47k] ------------------ 73| 411| triangle_count = 256; 74| | 75| 1.88k| unsigned char buf[4096]; 76| 1.88k| size_t enc = meshopt_encodeMeshlet(buf, sizeof(buf), NULL, 0, reinterpret_cast(data), triangle_count); 77| 1.88k| assert(enc > 0); ------------------ | Branch (77:2): [True: 1.88k, False: 0] ------------------ 78| 1.88k| assert(enc <= meshopt_encodeMeshletBound(0, triangle_count)); ------------------ | Branch (78:2): [True: 1.88k, False: 0] ------------------ 79| | 80| 1.88k| unsigned int rt4[256]; 81| 1.88k| int rc4 = meshopt_decodeMeshlet(static_cast(NULL), 0, rt4, triangle_count, buf, enc); 82| 1.88k| assert(rc4 == 0); ------------------ | Branch (82:2): [True: 1.88k, False: 0] ------------------ 83| | 84| 147k| for (size_t i = 0; i < triangle_count; ++i) ------------------ | Branch (84:21): [True: 146k, False: 1.88k] ------------------ 85| 146k| { 86| 146k| unsigned char a = data[i * 3 + 0], b = data[i * 3 + 1], c = data[i * 3 + 2]; 87| | 88| 146k| unsigned int abc = (a << 0) | (b << 8) | (c << 16); 89| 146k| unsigned int bca = (b << 0) | (c << 8) | (a << 16); 90| 146k| unsigned int cba = (c << 0) | (a << 8) | (b << 16); 91| | 92| 146k| unsigned int tri = rt4[i]; 93| | 94| 146k| assert(tri == abc || tri == bca || tri == cba); ------------------ | Branch (94:3): [True: 91.9k, False: 54.1k] | Branch (94:3): [True: 28.0k, False: 26.0k] | Branch (94:3): [True: 26.0k, False: 0] | Branch (94:3): [True: 146k, False: 0] ------------------ 95| 146k| } 96| | 97| 1.88k| unsigned char rt3[256 * 3]; 98| 1.88k| int rc3 = meshopt_decodeMeshlet(static_cast(NULL), 0, rt3, triangle_count, buf, enc); 99| 1.88k| assert(rc3 == 0); ------------------ | Branch (99:2): [True: 1.88k, False: 0] ------------------ 100| | 101| 147k| for (size_t i = 0; i < triangle_count; ++i) ------------------ | Branch (101:21): [True: 146k, False: 1.88k] ------------------ 102| 146k| { 103| 146k| unsigned char a = data[i * 3 + 0], b = data[i * 3 + 1], c = data[i * 3 + 2]; 104| | 105| 146k| unsigned int abc = (a << 0) | (b << 8) | (c << 16); 106| 146k| unsigned int bca = (b << 0) | (c << 8) | (a << 16); 107| 146k| unsigned int cba = (c << 0) | (a << 8) | (b << 16); 108| | 109| 146k| 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: 91.9k, False: 54.1k] | Branch (111:3): [True: 28.0k, False: 26.0k] | Branch (111:3): [True: 26.0k, False: 0] | Branch (111:3): [True: 146k, False: 0] ------------------ 112| 146k| } 113| 1.88k|} _Z21fuzzRoundtripMeshletVPKhm: 116| 1.88k|{ 117| 1.88k| size_t vertex_count = size / 4; 118| 1.88k| if (vertex_count > 256) ------------------ | Branch (118:6): [True: 362, False: 1.52k] ------------------ 119| 362| vertex_count = 256; 120| | 121| 1.88k| unsigned char tri[4] = {0, 1, 2}; 122| | 123| 1.88k| unsigned char buf[4096]; 124| 1.88k| size_t enc = meshopt_encodeMeshlet(buf, sizeof(buf), reinterpret_cast(data), vertex_count, tri, 1); 125| 1.88k| assert(enc > 0); ------------------ | Branch (125:2): [True: 1.88k, False: 0] ------------------ 126| 1.88k| assert(enc <= meshopt_encodeMeshletBound(vertex_count, 1)); ------------------ | Branch (126:2): [True: 1.88k, False: 0] ------------------ 127| | 128| 1.88k| unsigned int rv4[256]; 129| 1.88k| int rc4 = meshopt_decodeMeshlet(rv4, vertex_count, tri, 1, buf, enc); 130| 1.88k| assert(rc4 == 0); ------------------ | Branch (130:2): [True: 1.88k, False: 0] ------------------ 131| | 132| 136k| for (size_t i = 0; i < vertex_count; ++i) ------------------ | Branch (132:21): [True: 134k, False: 1.88k] ------------------ 133| 134k| assert(rv4[i] == reinterpret_cast(data)[i]); ------------------ | Branch (133:3): [True: 134k, False: 0] ------------------ 134| | 135| 1.88k| unsigned short rv2[256]; 136| 1.88k| int rc2 = meshopt_decodeMeshlet(rv2, vertex_count, tri, 1, buf, enc); 137| 1.88k| assert(rc2 == 0); ------------------ | Branch (137:2): [True: 1.88k, False: 0] ------------------ 138| | 139| 136k| for (size_t i = 0; i < vertex_count; ++i) ------------------ | Branch (139:21): [True: 134k, False: 1.88k] ------------------ 140| | assert(rv2[i] == uint16_t(reinterpret_cast(data)[i])); ------------------ | Branch (140:3): [True: 134k, False: 0] ------------------ 141| 1.88k|} LLVMFuzzerTestOneInput: 144| 1.88k|{ 145| | // decodeIndexBuffer supports 2 and 4-byte indices 146| 1.88k| fuzzDecoder(data, size, 2, meshopt_decodeIndexBuffer); 147| 1.88k| fuzzDecoder(data, size, 4, meshopt_decodeIndexBuffer); 148| | 149| | // decodeIndexSequence supports 2 and 4-byte indices 150| 1.88k| fuzzDecoder(data, size, 2, meshopt_decodeIndexSequence); 151| 1.88k| 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| 1.88k| fuzzDecoder(data, size, 4, meshopt_decodeVertexBuffer); 156| 1.88k| fuzzDecoder(data, size, 16, meshopt_decodeVertexBuffer); 157| 1.88k| fuzzDecoder(data, size, 24, meshopt_decodeVertexBuffer); 158| 1.88k| 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| 1.88k| uint8_t data0 = size > 0 ? data[0] : 0; ------------------ | Branch (163:18): [True: 1.88k, False: 0] ------------------ 164| 1.88k| int level = data0 % 5; 165| | 166| 1.88k| meshopt_encodeVertexVersion(level < 4 ? 1 : 0); ------------------ | Branch (166:30): [True: 1.49k, False: 398] ------------------ 167| | 168| 1.88k| fuzzRoundtrip(data, size, 4, level); 169| 1.88k| fuzzRoundtrip(data, size, 16, level); 170| 1.88k| fuzzRoundtrip(data, size, 24, level); 171| 1.88k| fuzzRoundtrip(data, size, 32, level); 172| | 173| | // validate that decodeMeshlet works on untrusted data and is memory safe within documented limits 174| 1.88k| if (size > 2) ------------------ | Branch (174:6): [True: 1.87k, False: 15] ------------------ 175| 1.87k| 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| 1.88k| fuzzRoundtripMeshlet(data, size); 179| | 180| | // validate that vertex data roundtrips in meshlet encoding 181| 1.88k| fuzzRoundtripMeshletV(data, size); 182| | 183| 1.88k| return 0; 184| 1.88k|}