148 lines · 5.1 KB · C++
RawDownload
////  BlendshapePackingTests.cpp//  tests/shared/src////  Created by Ken Cooke on 6/24/19.//  Copyright 2019 High Fidelity, Inc.////  Distributed under the Apache License, Version 2.0.//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html// #include "BlendshapePackingTests.h" #include <vector> #include <test-utils/QTestExtensions.h> #include <GLMHelpers.h>#include <glm/gtc/random.hpp> struct BlendshapeOffsetUnpacked {    glm::vec3 positionOffset;    glm::vec3 normalOffset;    glm::vec3 tangentOffset;}; struct BlendshapeOffsetPacked {    glm::uvec4 packedPosNorTan;}; QTEST_MAIN(BlendshapePackingTests) static void packBlendshapeOffsetTo_Pos_F32_3xSN10_Nor_3xSN10_Tan_3xSN10(glm::uvec4& packed, const BlendshapeOffsetUnpacked& unpacked) {    float len = glm::compMax(glm::abs(unpacked.positionOffset));    glm::vec3 normalizedPos(unpacked.positionOffset);    if (len > 0.0f) {        normalizedPos /= len;    } else {        len = 1.0f;    }     packed = glm::uvec4(        glm::floatBitsToUint(len),        glm_packSnorm3x10_1x2(glm::vec4(normalizedPos, 0.0f)),        glm_packSnorm3x10_1x2(glm::vec4(unpacked.normalOffset, 0.0f)),        glm_packSnorm3x10_1x2(glm::vec4(unpacked.tangentOffset, 0.0f))    );} static void packBlendshapeOffsets_ref(BlendshapeOffsetUnpacked* unpacked, BlendshapeOffsetPacked* packed, int size) {    for (int i = 0; i < size; ++i) {        packBlendshapeOffsetTo_Pos_F32_3xSN10_Nor_3xSN10_Tan_3xSN10((*packed).packedPosNorTan, (*unpacked));        ++unpacked;        ++packed;    }} #if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__x86_64__)//// Runtime CPU dispatch//#include <CPUDetect.h> void packBlendshapeOffsets_AVX2(float (*unpacked)[9], uint32_t (*packed)[4], int size); static void packBlendshapeOffsets(BlendshapeOffsetUnpacked* unpacked, BlendshapeOffsetPacked* packed, int size) {    static bool _cpuSupportsAVX2 = cpuSupportsAVX2();    if (_cpuSupportsAVX2) {        static_assert(sizeof(BlendshapeOffsetUnpacked) == 9 * sizeof(float), "struct BlendshapeOffsetUnpacked size doesn't match.");        static_assert(sizeof(BlendshapeOffsetPacked) == 4 * sizeof(uint32_t), "struct BlendshapeOffsetPacked size doesn't match.");        packBlendshapeOffsets_AVX2((float(*)[9])unpacked, (uint32_t(*)[4])packed, size);    } else {        packBlendshapeOffsets_ref(unpacked, packed, size);    }} #else   // portable reference codestatic auto& packBlendshapeOffsets = packBlendshapeOffsets_ref;#endif void comparePacked(BlendshapeOffsetPacked& ref, BlendshapeOffsetPacked& tst) {    union i10i10i10i2 {        struct {            int x : 10;            int y : 10;            int z : 10;            int w : 2;        } data;        uint32_t pack;    } Ref[4], Tst[4];     for (int i = 0; i < 4; i++) {        Ref[i].pack = ref.packedPosNorTan[i];        Tst[i].pack = tst.packedPosNorTan[i];    }     // allow 1 ULP due to rounding differences    QCOMPARE_WITH_ABS_ERROR(Tst[0].pack, Ref[0].pack, 1);     QCOMPARE_WITH_ABS_ERROR(Tst[1].data.x, Ref[1].data.x, 1);    QCOMPARE_WITH_ABS_ERROR(Tst[1].data.y, Ref[1].data.y, 1);    QCOMPARE_WITH_ABS_ERROR(Tst[1].data.z, Ref[1].data.z, 1);     QCOMPARE_WITH_ABS_ERROR(Tst[2].data.x, Ref[2].data.x, 1);    QCOMPARE_WITH_ABS_ERROR(Tst[2].data.y, Ref[2].data.y, 1);    QCOMPARE_WITH_ABS_ERROR(Tst[2].data.z, Ref[2].data.z, 1);     QCOMPARE_WITH_ABS_ERROR(Tst[3].data.x, Ref[3].data.x, 1);    QCOMPARE_WITH_ABS_ERROR(Tst[3].data.y, Ref[3].data.y, 1);    QCOMPARE_WITH_ABS_ERROR(Tst[3].data.z, Ref[3].data.z, 1);} void BlendshapePackingTests::testAVX2() {     for (int numBlendshapeOffsets = 0; numBlendshapeOffsets < 4096; ++numBlendshapeOffsets) {         std::vector<BlendshapeOffsetUnpacked> unpackedBlendshapeOffsets(numBlendshapeOffsets);        std::vector<BlendshapeOffsetPacked> packedBlendshapeOffsets1(numBlendshapeOffsets);        std::vector<BlendshapeOffsetPacked> packedBlendshapeOffsets2(numBlendshapeOffsets);         // init test data        if (numBlendshapeOffsets > 0) {            unpackedBlendshapeOffsets[0] = {                 glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 0.0f, 0.0f),            };        }        for (int i = 1; i < numBlendshapeOffsets; ++i) {            unpackedBlendshapeOffsets[i] = {                glm::linearRand(glm::vec3(-2.0f, -2.0f, -2.0f), glm::vec3(2.0f, 2.0f, 2.0f)),                glm::linearRand(glm::vec3(-2.0f, -2.0f, -2.0f), glm::vec3(2.0f, 2.0f, 2.0f)),                glm::linearRand(glm::vec3(-2.0f, -2.0f, -2.0f), glm::vec3(2.0f, 2.0f, 2.0f)),            };        }         // ref version        packBlendshapeOffsets_ref(unpackedBlendshapeOffsets.data(), packedBlendshapeOffsets1.data(), numBlendshapeOffsets);         // AVX2 version, if supported by CPU        packBlendshapeOffsets(unpackedBlendshapeOffsets.data(), packedBlendshapeOffsets2.data(), numBlendshapeOffsets);         // verify        for (int i = 0; i < numBlendshapeOffsets; ++i) {            auto ref = packedBlendshapeOffsets1.at(i);            auto tst = packedBlendshapeOffsets2.at(i);            comparePacked(ref, tst);        }    }}