mirror of
https://github.com/overte-org/overte.git
synced 2025-06-01 23:20:33 +02:00
148 lines
5.1 KiB
C++
148 lines
5.1 KiB
C++
//
|
|
// 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 code
|
|
static 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);
|
|
}
|
|
}
|
|
}
|