diff options
| author | Bryan Galdrikian <[email protected]> | 2018-05-31 11:36:08 -0700 |
|---|---|---|
| committer | Bryan Galdrikian <[email protected]> | 2018-05-31 11:36:08 -0700 |
| commit | 7115f60b91b5717d90f643fd692010905c7004db (patch) | |
| tree | effd68c6978751c517d54c2f2bb5bb6e7dc93e18 /test/src/unit/AssetTests.cpp | |
| parent | Updating BlastTool zip (diff) | |
| download | blast-1.1.3_rc1.tar.xz blast-1.1.3_rc1.zip | |
Blast 1.1.3. See docs/release_notes.txt.v1.1.3_rc1
Diffstat (limited to 'test/src/unit/AssetTests.cpp')
| -rwxr-xr-x[-rw-r--r--] | test/src/unit/AssetTests.cpp | 1716 |
1 files changed, 858 insertions, 858 deletions
diff --git a/test/src/unit/AssetTests.cpp b/test/src/unit/AssetTests.cpp index 9bd8aa0..6511f60 100644..100755 --- a/test/src/unit/AssetTests.cpp +++ b/test/src/unit/AssetTests.cpp @@ -1,858 +1,858 @@ -// This code contains NVIDIA Confidential Information and is disclosed to you -// under a form of NVIDIA software license agreement provided separately to you. -// -// Notice -// NVIDIA Corporation and its licensors retain all intellectual property and -// proprietary rights in and to this software and related documentation and -// any modifications thereto. Any use, reproduction, disclosure, or -// distribution of this software and related documentation without an express -// license agreement from NVIDIA Corporation is strictly prohibited. -// -// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES -// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO -// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, -// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. -// -// Information and code furnished is believed to be accurate and reliable. -// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such -// information or for any infringement of patents or other rights of third parties that may -// result from its use. No license is granted by implication or otherwise under any patent -// or patent rights of NVIDIA Corporation. Details are subject to change without notice. -// This code supersedes and replaces all information previously supplied. -// NVIDIA Corporation products are not authorized for use as critical -// components in life support devices or systems without express written approval of -// NVIDIA Corporation. -// -// Copyright (c) 2016-2018 NVIDIA Corporation. All rights reserved. - - -#include "NvBlastAsset.h" -#include "NvBlastMath.h" - -#include "BlastBaseTest.h" - -#include "NvBlastTkFramework.h" - -#include <algorithm> - - -// all supported platform now provide serialization -// keep the define for future platforms that won't -#define ENABLE_SERIALIZATION_TESTS 1 - -#pragma warning( push ) -#pragma warning( disable : 4267 ) -// NOTE: Instead of excluding serialization and the tests when on VC12, should break the tests out into a separate C++ file. - -#if ENABLE_SERIALIZATION_TESTS -#include "NvBlastExtSerialization.h" -#include "NvBlastExtLlSerialization.h" -#include "NvBlastExtSerializationInternal.h" -#endif - -#include "NvBlastExtAssetUtils.h" - -#pragma warning( pop ) - -#include <fstream> -#include <iosfwd> - -#ifdef WIN32 -#include <windows.h> -#endif - -template<int FailLevel, int Verbosity> -class AssetTest : public BlastBaseTest<FailLevel, Verbosity> -{ -public: - - AssetTest() - { - NvBlastTkFrameworkCreate(); - } - - ~AssetTest() - { - NvBlastTkFrameworkGet()->release(); - } - - static void messageLog(int type, const char* msg, const char* file, int line) - { - BlastBaseTest<FailLevel, Verbosity>::messageLog(type, msg, file, line); - } - - static void* alloc(size_t size) - { - return BlastBaseTest<FailLevel, Verbosity>::alignedZeroedAlloc(size); - } - - static void free(void* mem) - { - BlastBaseTest<FailLevel, Verbosity>::alignedFree(mem); - } - - void testSubtreeLeafChunkCounts(const Nv::Blast::Asset& a) - { - const NvBlastChunk* chunks = a.getChunks(); - const uint32_t* subtreeLeafChunkCounts = a.getSubtreeLeafChunkCounts(); - uint32_t totalLeafChunkCount = 0; - for (uint32_t chunkIndex = 0; chunkIndex < a.m_chunkCount; ++chunkIndex) - { - const NvBlastChunk& chunk = chunks[chunkIndex]; - if (Nv::Blast::isInvalidIndex(chunk.parentChunkIndex)) - { - totalLeafChunkCount += subtreeLeafChunkCounts[chunkIndex]; - } - const bool isLeafChunk = chunk.firstChildIndex >= chunk.childIndexStop; - uint32_t subtreeLeafChunkCount = isLeafChunk ? 1 : 0; - for (uint32_t childIndex = chunk.firstChildIndex; childIndex < chunk.childIndexStop; ++childIndex) - { - subtreeLeafChunkCount += subtreeLeafChunkCounts[childIndex]; - } - EXPECT_EQ(subtreeLeafChunkCount, subtreeLeafChunkCounts[chunkIndex]); - } - EXPECT_EQ(totalLeafChunkCount, a.m_leafChunkCount); - } - - void testChunkToNodeMap(const Nv::Blast::Asset& a) - { - for (uint32_t chunkIndex = 0; chunkIndex < a.m_chunkCount; ++chunkIndex) - { - const uint32_t nodeIndex = a.getChunkToGraphNodeMap()[chunkIndex]; - if (!Nv::Blast::isInvalidIndex(nodeIndex)) - { - EXPECT_LT(nodeIndex, a.m_graph.m_nodeCount); - EXPECT_EQ(chunkIndex, a.m_graph.getChunkIndices()[nodeIndex]); - } - else - { - const uint32_t* chunkIndexStop = a.m_graph.getChunkIndices() + a.m_graph.m_nodeCount; - const uint32_t* it = std::find<const uint32_t*, uint32_t>(a.m_graph.getChunkIndices(), chunkIndexStop, chunkIndex); - EXPECT_EQ(chunkIndexStop, it); - } - } - } - - NvBlastAsset* buildAsset(const ExpectedAssetValues& expected, const NvBlastAssetDesc* desc) - { - std::vector<char> scratch; - scratch.resize((size_t)NvBlastGetRequiredScratchForCreateAsset(desc, messageLog)); - void* mem = alloc(NvBlastGetAssetMemorySize(desc, messageLog)); - NvBlastAsset* asset = NvBlastCreateAsset(mem, desc, scratch.data(), messageLog); - EXPECT_TRUE(asset != nullptr); - if (asset == nullptr) - { - free(mem); - return nullptr; - } - Nv::Blast::Asset& a = *(Nv::Blast::Asset*)asset; - EXPECT_EQ(expected.totalChunkCount, a.m_chunkCount); - EXPECT_EQ(expected.graphNodeCount, a.m_graph.m_nodeCount); - EXPECT_EQ(expected.bondCount, a.m_graph.getAdjacencyPartition()[a.m_graph.m_nodeCount] / 2); - EXPECT_EQ(expected.leafChunkCount, a.m_leafChunkCount); - EXPECT_EQ(expected.subsupportChunkCount, a.m_chunkCount - a.m_firstSubsupportChunkIndex); - testSubtreeLeafChunkCounts(a); - testChunkToNodeMap(a); - return asset; - } - - void checkAssetsExpected(Nv::Blast::Asset& asset, const ExpectedAssetValues& expected) - { - EXPECT_EQ(expected.totalChunkCount, asset.m_chunkCount); - EXPECT_EQ(expected.graphNodeCount, asset.m_graph.m_nodeCount); - EXPECT_EQ(expected.bondCount, asset.m_graph.getAdjacencyPartition()[asset.m_graph.m_nodeCount] / 2); - EXPECT_EQ(expected.leafChunkCount, asset.m_leafChunkCount); - EXPECT_EQ(expected.subsupportChunkCount, asset.m_chunkCount - asset.m_firstSubsupportChunkIndex); - testSubtreeLeafChunkCounts(asset); - testChunkToNodeMap(asset); - } - - // expects that the bond normal points from the lower indexed chunk to higher index chunk - // uses chunk.centroid - // convention, requirement from findClosestNode - void checkNormalDir(NvBlastChunkDesc* chunkDescs, size_t chunkDescCount, NvBlastBondDesc* bondDescs, size_t bondDescCount) - { - for (size_t bondIndex = 0; bondIndex < bondDescCount; ++bondIndex) - { - NvBlastBondDesc& bond = bondDescs[bondIndex]; - uint32_t chunkIndex0 = bond.chunkIndices[0]; - uint32_t chunkIndex1 = bond.chunkIndices[1]; - - bool swap = chunkIndex0 > chunkIndex1; - uint32_t testIndex0 = swap ? chunkIndex1 : chunkIndex0; - uint32_t testIndex1 = swap ? chunkIndex0 : chunkIndex1; - - EXPECT_TRUE(testIndex0 < testIndex1); - - // no convention for world chunks - if (!Nv::Blast::isInvalidIndex(testIndex0) && !Nv::Blast::isInvalidIndex(testIndex1)) - { - NvBlastChunkDesc& chunk0 = chunkDescs[testIndex0]; - NvBlastChunkDesc& chunk1 = chunkDescs[testIndex1]; - - float dir[3]; - Nv::Blast::VecMath::sub(chunk1.centroid, chunk0.centroid, dir); - bool meetsConvention = Nv::Blast::VecMath::dot(bond.bond.normal, dir) > 0; - EXPECT_TRUE(meetsConvention); - if (!meetsConvention) - { - printf("bond %zd chunks(%d,%d): %.2f %.2f %.2f %.2f %.2f %.2f %d\n", - bondIndex, chunkIndex0, chunkIndex1, - bond.bond.normal[0], bond.bond.normal[1], bond.bond.normal[2], - dir[0], dir[1], dir[2], - Nv::Blast::VecMath::dot(bond.bond.normal, dir) > 0); - } - } - } - } - - // expects that the bond normal points from the lower indexed node to higher index node - // uses chunk.centroid - // convention, requirement from findClosestNode - void checkNormalDir(const NvBlastSupportGraph graph, const NvBlastChunk* assetChunks, const NvBlastBond* assetBonds) - { - for (uint32_t nodeIndex = 0; nodeIndex < graph.nodeCount; nodeIndex++) - { - uint32_t adjStart = graph.adjacencyPartition[nodeIndex]; - uint32_t adjStop = graph.adjacencyPartition[nodeIndex + 1]; - for (uint32_t adj = adjStart; adj < adjStop; ++adj) - { - uint32_t adjNodeIndex = graph.adjacentNodeIndices[adj]; - - bool swap = nodeIndex > adjNodeIndex; - uint32_t testIndex0 = swap ? adjNodeIndex : nodeIndex; - uint32_t testIndex1 = swap ? nodeIndex : adjNodeIndex; - - // no convention for world chunks - if (!Nv::Blast::isInvalidIndex(graph.chunkIndices[testIndex0]) && !Nv::Blast::isInvalidIndex(graph.chunkIndices[testIndex1])) - { - const NvBlastChunk& chunk0 = assetChunks[graph.chunkIndices[testIndex0]]; - const NvBlastChunk& chunk1 = assetChunks[graph.chunkIndices[testIndex1]]; - - uint32_t bondIndex = graph.adjacentBondIndices[adj]; - const NvBlastBond& bond = assetBonds[bondIndex]; - - float dir[3]; - Nv::Blast::VecMath::sub(chunk1.centroid, chunk0.centroid, dir); - bool meetsConvention = Nv::Blast::VecMath::dot(bond.normal, dir) > 0; - EXPECT_TRUE(meetsConvention); - if (!meetsConvention) - { - printf("bond %d nodes(%d,%d): %.2f %.2f %.2f %.2f %.2f %.2f %d\n", - bondIndex, nodeIndex, adjNodeIndex, - bond.normal[0], bond.normal[1], bond.normal[2], - dir[0], dir[1], dir[2], - Nv::Blast::VecMath::dot(bond.normal, dir) > 0); - } - } - } - } - } - - void checkNormalDir(const NvBlastAsset* asset) - { - const NvBlastChunk* assetChunks = NvBlastAssetGetChunks(asset, nullptr); - const NvBlastBond* assetBonds = NvBlastAssetGetBonds(asset, nullptr); - const NvBlastSupportGraph graph = NvBlastAssetGetSupportGraph(asset, nullptr); - checkNormalDir(graph, assetChunks, assetBonds); - } - - void buildAssetShufflingDescriptors(const NvBlastAssetDesc* desc, const ExpectedAssetValues& expected, uint32_t shuffleCount, bool useTk) - { - NvBlastAssetDesc shuffledDesc = *desc; - std::vector<NvBlastChunkDesc> chunkDescs(desc->chunkDescs, desc->chunkDescs + desc->chunkCount); - shuffledDesc.chunkDescs = chunkDescs.data(); - std::vector<NvBlastBondDesc> bondDescs(desc->bondDescs, desc->bondDescs + desc->bondCount); - shuffledDesc.bondDescs = bondDescs.data(); - if (!useTk) - { - std::vector<char> scratch(desc->chunkCount); - NvBlastEnsureAssetExactSupportCoverage(chunkDescs.data(), desc->chunkCount, scratch.data(), messageLog); - } - else - { - NvBlastTkFrameworkGet()->ensureAssetExactSupportCoverage(chunkDescs.data(), desc->chunkCount); - } - for (uint32_t i = 0; i < shuffleCount; ++i) - { - checkNormalDir(chunkDescs.data(), chunkDescs.size(), bondDescs.data(), bondDescs.size()); - shuffleAndFixChunkDescs(chunkDescs.data(), desc->chunkCount, bondDescs.data(), desc->bondCount, useTk); - checkNormalDir(chunkDescs.data(), chunkDescs.size(), bondDescs.data(), bondDescs.size()); - - NvBlastAsset* asset = buildAsset(expected, &shuffledDesc); - EXPECT_TRUE(asset != nullptr); - checkNormalDir(asset); - if (asset) - { - free(asset); - } - } - } - - void shuffleAndFixChunkDescs(NvBlastChunkDesc* chunkDescs, uint32_t chunkDescCount, NvBlastBondDesc* bondDescs, uint32_t bondDescCount, bool useTk) - { - // Create reorder array and fill with identity map - std::vector<uint32_t> shuffledOrder(chunkDescCount); - for (uint32_t i = 0; i < chunkDescCount; ++i) - { - shuffledOrder[i] = i; - } - - // An array into which to copy the reordered descs - std::vector<NvBlastChunkDesc> shuffledChunkDescs(chunkDescCount); - - std::vector<char> scratch; - const uint32_t trials = 30; - uint32_t attempt = 0; - while(1) - { - // Shuffle the reorder array - std::random_shuffle(shuffledOrder.begin(), shuffledOrder.end()); - - // Save initial bonds - std::vector<NvBlastBondDesc> savedBondDescs(bondDescs, bondDescs + bondDescCount); - - // Shuffle chunks and bonds - NvBlastApplyAssetDescChunkReorderMap(shuffledChunkDescs.data(), chunkDescs, chunkDescCount, bondDescs, bondDescCount, shuffledOrder.data(), true, nullptr); - - // All the normals are pointing in the expected direction (they have been swapped) - checkNormalDir(shuffledChunkDescs.data(), chunkDescCount, bondDescs, bondDescCount); - checkNormalDir(chunkDescs, chunkDescCount, savedBondDescs.data(), bondDescCount); - - // Check the results - for (uint32_t i = 0; i < chunkDescCount; ++i) - { - EXPECT_EQ(chunkDescs[i].userData, shuffledChunkDescs[shuffledOrder[i]].userData); - EXPECT_TRUE(chunkDescs[i].parentChunkIndex > chunkDescCount || shuffledChunkDescs[shuffledOrder[i]].parentChunkIndex == shuffledOrder[chunkDescs[i].parentChunkIndex]); - } - for (uint32_t i = 0; i < bondDescCount; ++i) - { - for (uint32_t k = 0; k < 2; ++k) - { - if (!Nv::Blast::isInvalidIndex(savedBondDescs[i].chunkIndices[k])) - { - EXPECT_EQ(shuffledOrder[savedBondDescs[i].chunkIndices[k]], bondDescs[i].chunkIndices[k]); - } - } - } - - // Try creating asset, usually it should fail (otherwise make another attempt) - NvBlastAssetDesc desc = { chunkDescCount, shuffledChunkDescs.data(), bondDescCount, bondDescs }; - scratch.resize((size_t)NvBlastGetRequiredScratchForCreateAsset(&desc, nullptr)); - void* mem = alloc(NvBlastGetAssetMemorySize(&desc, nullptr)); - NvBlastAsset* asset = NvBlastCreateAsset(mem, &desc, scratch.data(), nullptr); - if (asset == nullptr) - { - free(mem); - break; - } - else - { - free(asset); - memcpy(bondDescs, savedBondDescs.data(), sizeof(NvBlastBondDesc) * bondDescCount); - attempt++; - if (attempt >= trials) - { - GTEST_NONFATAL_FAILURE_("Shuffled chunk descs should fail asset creation (most of the time)."); - break; - } - } - } - - // Now we want to fix that order - if (!useTk) - { - std::vector<uint32_t> chunkReorderMap(chunkDescCount); - std::vector<char> scratch2(2 * chunkDescCount * sizeof(uint32_t)); - const bool isIdentity = NvBlastBuildAssetDescChunkReorderMap(chunkReorderMap.data(), shuffledChunkDescs.data(), chunkDescCount, scratch2.data(), messageLog); - EXPECT_FALSE(isIdentity); - NvBlastApplyAssetDescChunkReorderMap(chunkDescs, shuffledChunkDescs.data(), chunkDescCount, bondDescs, bondDescCount, chunkReorderMap.data(), true, messageLog); - } - else - { - memcpy(chunkDescs, shuffledChunkDescs.data(), chunkDescCount * sizeof(NvBlastChunkDesc)); - const bool isIdentity = NvBlastTkFrameworkGet()->reorderAssetDescChunks(chunkDescs, chunkDescCount, bondDescs, bondDescCount, nullptr, true); - EXPECT_FALSE(isIdentity); - } - } - - void mergeAssetTest(const NvBlastAssetDesc& desc, bool fail) - { - std::vector<char> scratch; - - scratch.resize((size_t)NvBlastGetRequiredScratchForCreateAsset(&desc, messageLog)); - void* mem = NVBLAST_ALLOC(NvBlastGetAssetMemorySize(&desc, messageLog)); - NvBlastAsset* asset = NvBlastCreateAsset(mem, &desc, scratch.data(), messageLog); - EXPECT_TRUE(asset != nullptr); - if (asset == nullptr) - { - free(mem); - return; - } - - // Merge two copies of this asset together - const NvBlastAsset* components[2] = { asset, asset }; - const NvcVec3 translations[2] = { { 0, 0, 0 },{ 2, 0, 0 } }; - - const NvBlastBond bond = { { 1.0f, 0.0f, 0.0f }, 1.0f,{ 1.0f, 0.0f, 0.0f }, 0 }; - - NvBlastExtAssetUtilsBondDesc newBondDescs[4]; - for (int i = 0; i < 4; ++i) - { - newBondDescs[i].bond = bond; - newBondDescs[i].chunkIndices[0] = 2 * (i + 1); - newBondDescs[i].chunkIndices[1] = 2 * i + 1; - newBondDescs[i].componentIndices[0] = 0; - newBondDescs[i].componentIndices[1] = 1; - } - - // Create a merged descriptor - std::vector<uint32_t> chunkIndexOffsets(2); - std::vector<uint32_t> chunkReorderMap(2 * desc.chunkCount); - - NvBlastAssetDesc mergedDesc = NvBlastExtAssetUtilsMergeAssets(components, nullptr, nullptr, translations, 2, newBondDescs, 4, chunkIndexOffsets.data(), chunkReorderMap.data(), 2 * desc.chunkCount); - EXPECT_EQ(2 * desc.bondCount + 4, mergedDesc.bondCount); - EXPECT_EQ(2 * desc.chunkCount, mergedDesc.chunkCount); - for (uint32_t i = 0; i < 2 * desc.chunkCount; ++i) - { - EXPECT_LT(chunkReorderMap[i], 2 * desc.chunkCount); - } - EXPECT_EQ(0, chunkIndexOffsets[0]); - EXPECT_EQ(desc.chunkCount, chunkIndexOffsets[1]); - - scratch.resize((size_t)NvBlastGetRequiredScratchForCreateAsset(&mergedDesc, messageLog)); - mem = NVBLAST_ALLOC(NvBlastGetAssetMemorySize(&mergedDesc, messageLog)); - NvBlastAsset* mergedAsset = NvBlastCreateAsset(mem, &mergedDesc, scratch.data(), messageLog); - EXPECT_TRUE(mergedAsset != nullptr); - if (mergedAsset == nullptr) - { - free(mem); - return; - } - - NVBLAST_FREE(const_cast<NvBlastBondDesc*>(mergedDesc.bondDescs)); - NVBLAST_FREE(const_cast<NvBlastChunkDesc*>(mergedDesc.chunkDescs)); - NVBLAST_FREE(mergedAsset); - - if (!fail) - { - mergedDesc = NvBlastExtAssetUtilsMergeAssets(components, nullptr, nullptr, translations, 2, newBondDescs, 4, nullptr, chunkReorderMap.data(), 2 * desc.chunkCount); - EXPECT_EQ(2 * desc.bondCount + 4, mergedDesc.bondCount); - EXPECT_EQ(2 * desc.chunkCount, mergedDesc.chunkCount); - for (uint32_t i = 0; i < 2 * desc.chunkCount; ++i) - { - EXPECT_LT(chunkReorderMap[i], 2 * desc.chunkCount); - } - scratch.resize((size_t)NvBlastGetRequiredScratchForCreateAsset(&mergedDesc, messageLog)); - mem = NVBLAST_ALLOC(NvBlastGetAssetMemorySize(&mergedDesc, messageLog)); - mergedAsset = NvBlastCreateAsset(mem, &mergedDesc, scratch.data(), messageLog); - EXPECT_TRUE(mergedAsset != nullptr); - free(mem); - NVBLAST_FREE(const_cast<NvBlastBondDesc*>(mergedDesc.bondDescs)); - NVBLAST_FREE(const_cast<NvBlastChunkDesc*>(mergedDesc.chunkDescs)); - } - else - { - // We don't pass in a valid chunkReorderMap so asset creation should fail - mergedDesc = NvBlastExtAssetUtilsMergeAssets(components, nullptr, nullptr, translations, 2, newBondDescs, 4, chunkIndexOffsets.data(), nullptr, 0); - EXPECT_EQ(2 * desc.bondCount + 4, mergedDesc.bondCount); - EXPECT_EQ(2 * desc.chunkCount, mergedDesc.chunkCount); - EXPECT_EQ(0, chunkIndexOffsets[0]); - EXPECT_EQ(desc.chunkCount, chunkIndexOffsets[1]); - scratch.resize((size_t)NvBlastGetRequiredScratchForCreateAsset(&mergedDesc, messageLog)); - mem = NVBLAST_ALLOC(NvBlastGetAssetMemorySize(&mergedDesc, messageLog)); - mergedAsset = NvBlastCreateAsset(mem, &mergedDesc, scratch.data(), messageLog); - EXPECT_TRUE(mergedAsset == nullptr); - free(mem); - NVBLAST_FREE(const_cast<NvBlastBondDesc*>(mergedDesc.bondDescs)); - NVBLAST_FREE(const_cast<NvBlastChunkDesc*>(mergedDesc.chunkDescs)); - - mergedDesc = NvBlastExtAssetUtilsMergeAssets(components, nullptr, nullptr, translations, 2, newBondDescs, 4, nullptr, nullptr, 0); - EXPECT_EQ(2 * desc.bondCount + 4, mergedDesc.bondCount); - EXPECT_EQ(2 * desc.chunkCount, mergedDesc.chunkCount); - scratch.resize((size_t)NvBlastGetRequiredScratchForCreateAsset(&mergedDesc, messageLog)); - mem = NVBLAST_ALLOC(NvBlastGetAssetMemorySize(&mergedDesc, messageLog)); - mergedAsset = NvBlastCreateAsset(mem, &mergedDesc, scratch.data(), messageLog); - EXPECT_TRUE(mergedAsset == nullptr); - free(mem); - NVBLAST_FREE(const_cast<NvBlastBondDesc*>(mergedDesc.bondDescs)); - NVBLAST_FREE(const_cast<NvBlastChunkDesc*>(mergedDesc.chunkDescs)); - - // We lie and say the chunkReorderMap is not large enough. It should be filled with 0xFFFFFFFF up to the size we gave - mergedDesc = NvBlastExtAssetUtilsMergeAssets(components, nullptr, nullptr, translations, 2, newBondDescs, 4, nullptr, chunkReorderMap.data(), desc.chunkCount); - EXPECT_EQ(2 * desc.bondCount + 4, mergedDesc.bondCount); - EXPECT_EQ(2 * desc.chunkCount, mergedDesc.chunkCount); - for (uint32_t i = 0; i < desc.chunkCount; ++i) - { - EXPECT_TRUE(Nv::Blast::isInvalidIndex(chunkReorderMap[i])); - } - scratch.resize((size_t)NvBlastGetRequiredScratchForCreateAsset(&mergedDesc, messageLog)); - mem = NVBLAST_ALLOC(NvBlastGetAssetMemorySize(&mergedDesc, messageLog)); - mergedAsset = NvBlastCreateAsset(mem, &mergedDesc, scratch.data(), messageLog); - EXPECT_TRUE(mergedAsset == nullptr); - free(mem); - NVBLAST_FREE(const_cast<NvBlastBondDesc*>(mergedDesc.bondDescs)); - NVBLAST_FREE(const_cast<NvBlastChunkDesc*>(mergedDesc.chunkDescs)); - - mergedDesc = NvBlastExtAssetUtilsMergeAssets(components, nullptr, nullptr, translations, 2, newBondDescs, 4, chunkIndexOffsets.data(), chunkReorderMap.data(), desc.chunkCount); - EXPECT_EQ(2 * desc.bondCount + 4, mergedDesc.bondCount); - EXPECT_EQ(2 * desc.chunkCount, mergedDesc.chunkCount); - for (uint32_t i = 0; i < desc.chunkCount; ++i) - { - EXPECT_TRUE(Nv::Blast::isInvalidIndex(chunkReorderMap[i])); - } - EXPECT_EQ(0, chunkIndexOffsets[0]); - EXPECT_EQ(desc.chunkCount, chunkIndexOffsets[1]); - scratch.resize((size_t)NvBlastGetRequiredScratchForCreateAsset(&mergedDesc, messageLog)); - mem = NVBLAST_ALLOC(NvBlastGetAssetMemorySize(&mergedDesc, messageLog)); - mergedAsset = NvBlastCreateAsset(mem, &mergedDesc, scratch.data(), messageLog); - EXPECT_TRUE(mergedAsset == nullptr); - free(mem); - NVBLAST_FREE(const_cast<NvBlastBondDesc*>(mergedDesc.bondDescs)); - NVBLAST_FREE(const_cast<NvBlastChunkDesc*>(mergedDesc.chunkDescs)); - } - - // Finally free the original asset - NVBLAST_FREE(asset); - } -}; - -typedef AssetTest<-1, 0> AssetTestAllowErrorsSilently; -typedef AssetTest<NvBlastMessage::Error, 0> AssetTestAllowWarningsSilently; -typedef AssetTest<NvBlastMessage::Error, 1> AssetTestAllowWarnings; -typedef AssetTest<NvBlastMessage::Warning, 1> AssetTestStrict; - - -TEST_F(AssetTestStrict, BuildAssets) -{ - const uint32_t assetDescCount = sizeof(g_assetDescs) / sizeof(g_assetDescs[0]); - - std::vector<NvBlastAsset*> assets(assetDescCount); - - // Build - for (uint32_t i = 0; i < assetDescCount; ++i) - { - assets[i] = buildAsset(g_assetExpectedValues[i], &g_assetDescs[i]); - } - - // Destroy - for (uint32_t i = 0; i < assetDescCount; ++i) - { - if (assets[i]) - { - free(assets[i]); - } - } -} - -#if ENABLE_SERIALIZATION_TESTS -TEST_F(AssetTestStrict, SerializeAssets) -{ - Nv::Blast::ExtSerialization* ser = NvBlastExtSerializationCreate(); - EXPECT_TRUE(ser != nullptr); - - const uint32_t assetDescCount = sizeof(g_assetDescs) / sizeof(g_assetDescs[0]); - - std::vector<Nv::Blast::Asset*> assets(assetDescCount); - - // Build - for (uint32_t i = 0; i < assetDescCount; ++i) - { - assets[i] = reinterpret_cast<Nv::Blast::Asset*>(buildAsset(g_assetExpectedValues[i], &g_assetDescs[i])); - } - - // Serialize them - for (Nv::Blast::Asset* asset : assets) - { - void* buffer; - const uint64_t size = NvBlastExtSerializationSerializeAssetIntoBuffer(buffer, *ser, asset); - EXPECT_TRUE(size != 0); - - uint32_t objectTypeID; - uint32_t encodingID; - uint64_t dataSize = 0; - EXPECT_TRUE(ser->peekHeader(&objectTypeID, &encodingID, &dataSize, buffer, size)); - EXPECT_EQ(objectTypeID, Nv::Blast::LlObjectTypeID::Asset); - EXPECT_EQ(encodingID, ser->getSerializationEncoding()); - EXPECT_EQ(dataSize + Nv::Blast::ExtSerializationInternal::HeaderSize, size); - } - - // Destroy - for (uint32_t i = 0; i < assetDescCount; ++i) - { - if (assets[i]) - { - free(assets[i]); - } - } - - ser->release(); -} - -TEST_F(AssetTestStrict, SerializeAssetsRoundTrip) -{ - Nv::Blast::ExtSerialization* ser = NvBlastExtSerializationCreate(); - EXPECT_TRUE(ser != nullptr); - - const uint32_t assetDescCount = sizeof(g_assetDescs) / sizeof(g_assetDescs[0]); - - std::vector<Nv::Blast::Asset*> assets(assetDescCount); - - // Build - for (uint32_t i = 0; i < assetDescCount; ++i) - { - assets[i] = reinterpret_cast<Nv::Blast::Asset*>(buildAsset(g_assetExpectedValues[i], &g_assetDescs[i])); - } - - const uint32_t encodings[] = - { - Nv::Blast::ExtSerialization::EncodingID::CapnProtoBinary, - Nv::Blast::ExtSerialization::EncodingID::RawBinary - }; - - for (auto encoding : encodings) - { - ser->setSerializationEncoding(encoding); - - // Serialize them - for (uint32_t i = 0; i < assetDescCount; ++i) - { - Nv::Blast::Asset* asset = assets[i]; - - void* buffer; - const uint64_t size = NvBlastExtSerializationSerializeAssetIntoBuffer(buffer, *ser, asset); - EXPECT_TRUE(size != 0); - - Nv::Blast::Asset* rtAsset = reinterpret_cast<Nv::Blast::Asset*>(ser->deserializeFromBuffer(buffer, size)); - - //TODO: Compare assets - checkAssetsExpected(*rtAsset, g_assetExpectedValues[i]); - - free(static_cast<void*>(rtAsset)); - } - } - - // Destroy - for (uint32_t i = 0; i < assetDescCount; ++i) - { - if (assets[i]) - { - free(assets[i]); - } - } - - ser->release(); -} - -TEST_F(AssetTestStrict, SerializeAssetsRoundTripWithSkipping) -{ - Nv::Blast::ExtSerialization* ser = NvBlastExtSerializationCreate(); - EXPECT_TRUE(ser != nullptr); - - std::vector<char> stream; - - class StreamBufferProvider : public Nv::Blast::ExtSerialization::BufferProvider - { - public: - StreamBufferProvider(std::vector<char>& stream) : m_stream(stream), m_cursor(0) {} - - virtual void* requestBuffer(size_t size) override - { - m_stream.resize(m_cursor + size); - void* data = m_stream.data() + m_cursor; - m_cursor += size; - return data; - } - - private: - std::vector<char>& m_stream; - size_t m_cursor; - } myStreamProvider(stream); - - ser->setBufferProvider(&myStreamProvider); - - const uint32_t assetDescCount = sizeof(g_assetDescs) / sizeof(g_assetDescs[0]); - - std::vector<Nv::Blast::Asset*> assets(assetDescCount); - - // Build - for (uint32_t i = 0; i < assetDescCount; ++i) - { - assets[i] = reinterpret_cast<Nv::Blast::Asset*>(buildAsset(g_assetExpectedValues[i], &g_assetDescs[i])); - } - - const uint32_t encodings[] = - { - Nv::Blast::ExtSerialization::EncodingID::CapnProtoBinary, - Nv::Blast::ExtSerialization::EncodingID::RawBinary - }; - - for (auto encoding : encodings) - { - ser->setSerializationEncoding(encoding); - - // Serialize them - for (uint32_t i = 0; i < assetDescCount; ++i) - { - void* buffer; - const uint64_t size = NvBlastExtSerializationSerializeAssetIntoBuffer(buffer, *ser, assets[i]); - EXPECT_TRUE(size != 0); - } - } - - // Deserialize from stream - const void* buffer = stream.data(); - uint64_t bufferSize = stream.size(); - for (uint32_t assetCount = 0; bufferSize; ++assetCount) - { - uint32_t objectTypeID; - uint32_t encodingID; - const bool peekSuccess = ser->peekHeader(&objectTypeID, &encodingID, nullptr, buffer, bufferSize); - EXPECT_TRUE(peekSuccess); - if (!peekSuccess) - { - break; - } - - EXPECT_EQ(Nv::Blast::LlObjectTypeID::Asset, objectTypeID); - if (assetCount < assetDescCount) - { - EXPECT_EQ(Nv::Blast::ExtSerialization::EncodingID::CapnProtoBinary, encodingID); - } - else - { - EXPECT_EQ(Nv::Blast::ExtSerialization::EncodingID::RawBinary, encodingID); - } - - const bool skip = (assetCount & 1) != 0; - - if (!skip) - { - const uint32_t assetnum = assetCount % assetDescCount; - Nv::Blast::Asset* rtAsset = reinterpret_cast<Nv::Blast::Asset*>(ser->deserializeFromBuffer(buffer, bufferSize)); - EXPECT_TRUE(rtAsset != nullptr); - if (rtAsset == nullptr) - { - break; - } - - //TODO: Compare assets - checkAssetsExpected(*rtAsset, g_assetExpectedValues[assetnum]); - - free(static_cast<void*>(rtAsset)); - } - - buffer = ser->skipObject(bufferSize, buffer); - } - - // Destroy - for (uint32_t i = 0; i < assetDescCount; ++i) - { - if (assets[i]) - { - free(assets[i]); - } - } - - ser->release(); -} -#endif // ENABLE_SERIALIZATION_TESTS - -TEST_F(AssetTestAllowWarnings, BuildAssetsMissingCoverage) -{ - const uint32_t assetDescCount = sizeof(g_assetDescsMissingCoverage) / sizeof(g_assetDescsMissingCoverage[0]); - - std::vector<NvBlastAsset*> assets(assetDescCount); - - // Build - for (uint32_t i = 0; i < assetDescCount; ++i) - { - const NvBlastAssetDesc* desc = &g_assetDescsMissingCoverage[i]; - NvBlastAssetDesc fixedDesc = *desc; - std::vector<NvBlastChunkDesc> chunkDescs(desc->chunkDescs, desc->chunkDescs + desc->chunkCount); - std::vector<NvBlastBondDesc> bondDescs(desc->bondDescs, desc->bondDescs + desc->bondCount); - std::vector<uint32_t> chunkReorderMap(desc->chunkCount); - std::vector<char> scratch(desc->chunkCount * sizeof(NvBlastChunkDesc)); - const bool changedCoverage = !NvBlastEnsureAssetExactSupportCoverage(chunkDescs.data(), fixedDesc.chunkCount, scratch.data(), messageLog); - EXPECT_TRUE(changedCoverage); - NvBlastReorderAssetDescChunks(chunkDescs.data(), fixedDesc.chunkCount, bondDescs.data(), fixedDesc.bondCount, chunkReorderMap.data(), true, scratch.data(), messageLog); - fixedDesc.chunkDescs = chunkDescs.data(); - fixedDesc.bondDescs = bondDescs.data(); - assets[i] = buildAsset(g_assetsFromMissingCoverageExpectedValues[i], &fixedDesc); - } - - // Destroy - for (uint32_t i = 0; i < assetDescCount; ++i) - { - if (assets[i]) - { - free(assets[i]); - } - } -} - -TEST_F(AssetTestAllowWarningsSilently, BuildAssetsShufflingChunkDescriptors) -{ - for (uint32_t i = 0; i < sizeof(g_assetDescs) / sizeof(g_assetDescs[0]); ++i) - { - buildAssetShufflingDescriptors(&g_assetDescs[i], g_assetExpectedValues[i], 10, false); - } - - for (uint32_t i = 0; i < sizeof(g_assetDescsMissingCoverage) / sizeof(g_assetDescsMissingCoverage[0]); ++i) - { - buildAssetShufflingDescriptors(&g_assetDescsMissingCoverage[i], g_assetsFromMissingCoverageExpectedValues[i], 10, false); - } -} - -TEST_F(AssetTestAllowWarningsSilently, BuildAssetsShufflingChunkDescriptorsUsingTk) -{ - for (uint32_t i = 0; i < sizeof(g_assetDescs) / sizeof(g_assetDescs[0]); ++i) - { - buildAssetShufflingDescriptors(&g_assetDescs[i], g_assetExpectedValues[i], 10, true); - } - - for (uint32_t i = 0; i < sizeof(g_assetDescsMissingCoverage) / sizeof(g_assetDescsMissingCoverage[0]); ++i) - { - buildAssetShufflingDescriptors(&g_assetDescsMissingCoverage[i], g_assetsFromMissingCoverageExpectedValues[i], 10, true); - } -} - -TEST_F(AssetTestStrict, MergeAssetsUpperSupportOnly) -{ - mergeAssetTest(g_assetDescs[0], false); -} - -TEST_F(AssetTestStrict, MergeAssetsWithSubsupport) -{ - mergeAssetTest(g_assetDescs[1], false); -} - -TEST_F(AssetTestStrict, MergeAssetsWithWorldBondsUpperSupportOnly) -{ - mergeAssetTest(g_assetDescs[3], false); -} - -TEST_F(AssetTestStrict, MergeAssetsWithWorldBondsWithSubsupport) -{ - mergeAssetTest(g_assetDescs[4], false); -} - -TEST_F(AssetTestAllowErrorsSilently, MergeAssetsUpperSupportOnlyExpectFail) -{ - mergeAssetTest(g_assetDescs[0], true); -} - -TEST_F(AssetTestAllowErrorsSilently, MergeAssetsWithSubsupportExpectFail) -{ - mergeAssetTest(g_assetDescs[1], true); -} - -TEST_F(AssetTestAllowErrorsSilently, MergeAssetsWithWorldBondsUpperSupportOnlyExpectFail) -{ - mergeAssetTest(g_assetDescs[3], true); -} - -TEST_F(AssetTestAllowErrorsSilently, MergeAssetsWithWorldBondsWithSubsupportExpectFail) -{ - mergeAssetTest(g_assetDescs[4], true); -} +// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2016-2018 NVIDIA Corporation. All rights reserved.
+
+
+#include "NvBlastAsset.h"
+#include "NvBlastMath.h"
+
+#include "BlastBaseTest.h"
+
+#include "NvBlastTkFramework.h"
+
+#include <algorithm>
+
+
+// all supported platform now provide serialization
+// keep the define for future platforms that won't
+#define ENABLE_SERIALIZATION_TESTS 1
+
+#pragma warning( push )
+#pragma warning( disable : 4267 )
+// NOTE: Instead of excluding serialization and the tests when on VC12, should break the tests out into a separate C++ file.
+
+#if ENABLE_SERIALIZATION_TESTS
+#include "NvBlastExtSerialization.h"
+#include "NvBlastExtLlSerialization.h"
+#include "NvBlastExtSerializationInternal.h"
+#endif
+
+#include "NvBlastExtAssetUtils.h"
+
+#pragma warning( pop )
+
+#include <fstream>
+#include <iosfwd>
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+template<int FailLevel, int Verbosity>
+class AssetTest : public BlastBaseTest<FailLevel, Verbosity>
+{
+public:
+
+ AssetTest()
+ {
+ NvBlastTkFrameworkCreate();
+ }
+
+ ~AssetTest()
+ {
+ NvBlastTkFrameworkGet()->release();
+ }
+
+ static void messageLog(int type, const char* msg, const char* file, int line)
+ {
+ BlastBaseTest<FailLevel, Verbosity>::messageLog(type, msg, file, line);
+ }
+
+ static void* alloc(size_t size)
+ {
+ return BlastBaseTest<FailLevel, Verbosity>::alignedZeroedAlloc(size);
+ }
+
+ static void free(void* mem)
+ {
+ BlastBaseTest<FailLevel, Verbosity>::alignedFree(mem);
+ }
+
+ void testSubtreeLeafChunkCounts(const Nv::Blast::Asset& a)
+ {
+ const NvBlastChunk* chunks = a.getChunks();
+ const uint32_t* subtreeLeafChunkCounts = a.getSubtreeLeafChunkCounts();
+ uint32_t totalLeafChunkCount = 0;
+ for (uint32_t chunkIndex = 0; chunkIndex < a.m_chunkCount; ++chunkIndex)
+ {
+ const NvBlastChunk& chunk = chunks[chunkIndex];
+ if (Nv::Blast::isInvalidIndex(chunk.parentChunkIndex))
+ {
+ totalLeafChunkCount += subtreeLeafChunkCounts[chunkIndex];
+ }
+ const bool isLeafChunk = chunk.firstChildIndex >= chunk.childIndexStop;
+ uint32_t subtreeLeafChunkCount = isLeafChunk ? 1 : 0;
+ for (uint32_t childIndex = chunk.firstChildIndex; childIndex < chunk.childIndexStop; ++childIndex)
+ {
+ subtreeLeafChunkCount += subtreeLeafChunkCounts[childIndex];
+ }
+ EXPECT_EQ(subtreeLeafChunkCount, subtreeLeafChunkCounts[chunkIndex]);
+ }
+ EXPECT_EQ(totalLeafChunkCount, a.m_leafChunkCount);
+ }
+
+ void testChunkToNodeMap(const Nv::Blast::Asset& a)
+ {
+ for (uint32_t chunkIndex = 0; chunkIndex < a.m_chunkCount; ++chunkIndex)
+ {
+ const uint32_t nodeIndex = a.getChunkToGraphNodeMap()[chunkIndex];
+ if (!Nv::Blast::isInvalidIndex(nodeIndex))
+ {
+ EXPECT_LT(nodeIndex, a.m_graph.m_nodeCount);
+ EXPECT_EQ(chunkIndex, a.m_graph.getChunkIndices()[nodeIndex]);
+ }
+ else
+ {
+ const uint32_t* chunkIndexStop = a.m_graph.getChunkIndices() + a.m_graph.m_nodeCount;
+ const uint32_t* it = std::find<const uint32_t*, uint32_t>(a.m_graph.getChunkIndices(), chunkIndexStop, chunkIndex);
+ EXPECT_EQ(chunkIndexStop, it);
+ }
+ }
+ }
+
+ NvBlastAsset* buildAsset(const ExpectedAssetValues& expected, const NvBlastAssetDesc* desc)
+ {
+ std::vector<char> scratch;
+ scratch.resize((size_t)NvBlastGetRequiredScratchForCreateAsset(desc, messageLog));
+ void* mem = alloc(NvBlastGetAssetMemorySize(desc, messageLog));
+ NvBlastAsset* asset = NvBlastCreateAsset(mem, desc, scratch.data(), messageLog);
+ EXPECT_TRUE(asset != nullptr);
+ if (asset == nullptr)
+ {
+ free(mem);
+ return nullptr;
+ }
+ Nv::Blast::Asset& a = *(Nv::Blast::Asset*)asset;
+ EXPECT_EQ(expected.totalChunkCount, a.m_chunkCount);
+ EXPECT_EQ(expected.graphNodeCount, a.m_graph.m_nodeCount);
+ EXPECT_EQ(expected.bondCount, a.m_graph.getAdjacencyPartition()[a.m_graph.m_nodeCount] / 2);
+ EXPECT_EQ(expected.leafChunkCount, a.m_leafChunkCount);
+ EXPECT_EQ(expected.subsupportChunkCount, a.m_chunkCount - a.m_firstSubsupportChunkIndex);
+ testSubtreeLeafChunkCounts(a);
+ testChunkToNodeMap(a);
+ return asset;
+ }
+
+ void checkAssetsExpected(Nv::Blast::Asset& asset, const ExpectedAssetValues& expected)
+ {
+ EXPECT_EQ(expected.totalChunkCount, asset.m_chunkCount);
+ EXPECT_EQ(expected.graphNodeCount, asset.m_graph.m_nodeCount);
+ EXPECT_EQ(expected.bondCount, asset.m_graph.getAdjacencyPartition()[asset.m_graph.m_nodeCount] / 2);
+ EXPECT_EQ(expected.leafChunkCount, asset.m_leafChunkCount);
+ EXPECT_EQ(expected.subsupportChunkCount, asset.m_chunkCount - asset.m_firstSubsupportChunkIndex);
+ testSubtreeLeafChunkCounts(asset);
+ testChunkToNodeMap(asset);
+ }
+
+ // expects that the bond normal points from the lower indexed chunk to higher index chunk
+ // uses chunk.centroid
+ // convention, requirement from findClosestNode
+ void checkNormalDir(NvBlastChunkDesc* chunkDescs, size_t chunkDescCount, NvBlastBondDesc* bondDescs, size_t bondDescCount)
+ {
+ for (size_t bondIndex = 0; bondIndex < bondDescCount; ++bondIndex)
+ {
+ NvBlastBondDesc& bond = bondDescs[bondIndex];
+ uint32_t chunkIndex0 = bond.chunkIndices[0];
+ uint32_t chunkIndex1 = bond.chunkIndices[1];
+
+ bool swap = chunkIndex0 > chunkIndex1;
+ uint32_t testIndex0 = swap ? chunkIndex1 : chunkIndex0;
+ uint32_t testIndex1 = swap ? chunkIndex0 : chunkIndex1;
+
+ EXPECT_TRUE(testIndex0 < testIndex1);
+
+ // no convention for world chunks
+ if (!Nv::Blast::isInvalidIndex(testIndex0) && !Nv::Blast::isInvalidIndex(testIndex1))
+ {
+ NvBlastChunkDesc& chunk0 = chunkDescs[testIndex0];
+ NvBlastChunkDesc& chunk1 = chunkDescs[testIndex1];
+
+ float dir[3];
+ Nv::Blast::VecMath::sub(chunk1.centroid, chunk0.centroid, dir);
+ bool meetsConvention = Nv::Blast::VecMath::dot(bond.bond.normal, dir) > 0;
+ EXPECT_TRUE(meetsConvention);
+ if (!meetsConvention)
+ {
+ printf("bond %zd chunks(%d,%d): %.2f %.2f %.2f %.2f %.2f %.2f %d\n",
+ bondIndex, chunkIndex0, chunkIndex1,
+ bond.bond.normal[0], bond.bond.normal[1], bond.bond.normal[2],
+ dir[0], dir[1], dir[2],
+ Nv::Blast::VecMath::dot(bond.bond.normal, dir) > 0);
+ }
+ }
+ }
+ }
+
+ // expects that the bond normal points from the lower indexed node to higher index node
+ // uses chunk.centroid
+ // convention, requirement from findClosestNode
+ void checkNormalDir(const NvBlastSupportGraph graph, const NvBlastChunk* assetChunks, const NvBlastBond* assetBonds)
+ {
+ for (uint32_t nodeIndex = 0; nodeIndex < graph.nodeCount; nodeIndex++)
+ {
+ uint32_t adjStart = graph.adjacencyPartition[nodeIndex];
+ uint32_t adjStop = graph.adjacencyPartition[nodeIndex + 1];
+ for (uint32_t adj = adjStart; adj < adjStop; ++adj)
+ {
+ uint32_t adjNodeIndex = graph.adjacentNodeIndices[adj];
+
+ bool swap = nodeIndex > adjNodeIndex;
+ uint32_t testIndex0 = swap ? adjNodeIndex : nodeIndex;
+ uint32_t testIndex1 = swap ? nodeIndex : adjNodeIndex;
+
+ // no convention for world chunks
+ if (!Nv::Blast::isInvalidIndex(graph.chunkIndices[testIndex0]) && !Nv::Blast::isInvalidIndex(graph.chunkIndices[testIndex1]))
+ {
+ const NvBlastChunk& chunk0 = assetChunks[graph.chunkIndices[testIndex0]];
+ const NvBlastChunk& chunk1 = assetChunks[graph.chunkIndices[testIndex1]];
+
+ uint32_t bondIndex = graph.adjacentBondIndices[adj];
+ const NvBlastBond& bond = assetBonds[bondIndex];
+
+ float dir[3];
+ Nv::Blast::VecMath::sub(chunk1.centroid, chunk0.centroid, dir);
+ bool meetsConvention = Nv::Blast::VecMath::dot(bond.normal, dir) > 0;
+ EXPECT_TRUE(meetsConvention);
+ if (!meetsConvention)
+ {
+ printf("bond %d nodes(%d,%d): %.2f %.2f %.2f %.2f %.2f %.2f %d\n",
+ bondIndex, nodeIndex, adjNodeIndex,
+ bond.normal[0], bond.normal[1], bond.normal[2],
+ dir[0], dir[1], dir[2],
+ Nv::Blast::VecMath::dot(bond.normal, dir) > 0);
+ }
+ }
+ }
+ }
+ }
+
+ void checkNormalDir(const NvBlastAsset* asset)
+ {
+ const NvBlastChunk* assetChunks = NvBlastAssetGetChunks(asset, nullptr);
+ const NvBlastBond* assetBonds = NvBlastAssetGetBonds(asset, nullptr);
+ const NvBlastSupportGraph graph = NvBlastAssetGetSupportGraph(asset, nullptr);
+ checkNormalDir(graph, assetChunks, assetBonds);
+ }
+
+ void buildAssetShufflingDescriptors(const NvBlastAssetDesc* desc, const ExpectedAssetValues& expected, uint32_t shuffleCount, bool useTk)
+ {
+ NvBlastAssetDesc shuffledDesc = *desc;
+ std::vector<NvBlastChunkDesc> chunkDescs(desc->chunkDescs, desc->chunkDescs + desc->chunkCount);
+ shuffledDesc.chunkDescs = chunkDescs.data();
+ std::vector<NvBlastBondDesc> bondDescs(desc->bondDescs, desc->bondDescs + desc->bondCount);
+ shuffledDesc.bondDescs = bondDescs.data();
+ if (!useTk)
+ {
+ std::vector<char> scratch(desc->chunkCount);
+ NvBlastEnsureAssetExactSupportCoverage(chunkDescs.data(), desc->chunkCount, scratch.data(), messageLog);
+ }
+ else
+ {
+ NvBlastTkFrameworkGet()->ensureAssetExactSupportCoverage(chunkDescs.data(), desc->chunkCount);
+ }
+ for (uint32_t i = 0; i < shuffleCount; ++i)
+ {
+ checkNormalDir(chunkDescs.data(), chunkDescs.size(), bondDescs.data(), bondDescs.size());
+ shuffleAndFixChunkDescs(chunkDescs.data(), desc->chunkCount, bondDescs.data(), desc->bondCount, useTk);
+ checkNormalDir(chunkDescs.data(), chunkDescs.size(), bondDescs.data(), bondDescs.size());
+
+ NvBlastAsset* asset = buildAsset(expected, &shuffledDesc);
+ EXPECT_TRUE(asset != nullptr);
+ checkNormalDir(asset);
+ if (asset)
+ {
+ free(asset);
+ }
+ }
+ }
+
+ void shuffleAndFixChunkDescs(NvBlastChunkDesc* chunkDescs, uint32_t chunkDescCount, NvBlastBondDesc* bondDescs, uint32_t bondDescCount, bool useTk)
+ {
+ // Create reorder array and fill with identity map
+ std::vector<uint32_t> shuffledOrder(chunkDescCount);
+ for (uint32_t i = 0; i < chunkDescCount; ++i)
+ {
+ shuffledOrder[i] = i;
+ }
+
+ // An array into which to copy the reordered descs
+ std::vector<NvBlastChunkDesc> shuffledChunkDescs(chunkDescCount);
+
+ std::vector<char> scratch;
+ const uint32_t trials = 30;
+ uint32_t attempt = 0;
+ while(1)
+ {
+ // Shuffle the reorder array
+ std::random_shuffle(shuffledOrder.begin(), shuffledOrder.end());
+
+ // Save initial bonds
+ std::vector<NvBlastBondDesc> savedBondDescs(bondDescs, bondDescs + bondDescCount);
+
+ // Shuffle chunks and bonds
+ NvBlastApplyAssetDescChunkReorderMap(shuffledChunkDescs.data(), chunkDescs, chunkDescCount, bondDescs, bondDescCount, shuffledOrder.data(), true, nullptr);
+
+ // All the normals are pointing in the expected direction (they have been swapped)
+ checkNormalDir(shuffledChunkDescs.data(), chunkDescCount, bondDescs, bondDescCount);
+ checkNormalDir(chunkDescs, chunkDescCount, savedBondDescs.data(), bondDescCount);
+
+ // Check the results
+ for (uint32_t i = 0; i < chunkDescCount; ++i)
+ {
+ EXPECT_EQ(chunkDescs[i].userData, shuffledChunkDescs[shuffledOrder[i]].userData);
+ EXPECT_TRUE(chunkDescs[i].parentChunkIndex > chunkDescCount || shuffledChunkDescs[shuffledOrder[i]].parentChunkIndex == shuffledOrder[chunkDescs[i].parentChunkIndex]);
+ }
+ for (uint32_t i = 0; i < bondDescCount; ++i)
+ {
+ for (uint32_t k = 0; k < 2; ++k)
+ {
+ if (!Nv::Blast::isInvalidIndex(savedBondDescs[i].chunkIndices[k]))
+ {
+ EXPECT_EQ(shuffledOrder[savedBondDescs[i].chunkIndices[k]], bondDescs[i].chunkIndices[k]);
+ }
+ }
+ }
+
+ // Try creating asset, usually it should fail (otherwise make another attempt)
+ NvBlastAssetDesc desc = { chunkDescCount, shuffledChunkDescs.data(), bondDescCount, bondDescs };
+ scratch.resize((size_t)NvBlastGetRequiredScratchForCreateAsset(&desc, nullptr));
+ void* mem = alloc(NvBlastGetAssetMemorySize(&desc, nullptr));
+ NvBlastAsset* asset = NvBlastCreateAsset(mem, &desc, scratch.data(), nullptr);
+ if (asset == nullptr)
+ {
+ free(mem);
+ break;
+ }
+ else
+ {
+ free(asset);
+ memcpy(bondDescs, savedBondDescs.data(), sizeof(NvBlastBondDesc) * bondDescCount);
+ attempt++;
+ if (attempt >= trials)
+ {
+ GTEST_NONFATAL_FAILURE_("Shuffled chunk descs should fail asset creation (most of the time).");
+ break;
+ }
+ }
+ }
+
+ // Now we want to fix that order
+ if (!useTk)
+ {
+ std::vector<uint32_t> chunkReorderMap(chunkDescCount);
+ std::vector<char> scratch2(2 * chunkDescCount * sizeof(uint32_t));
+ const bool isIdentity = NvBlastBuildAssetDescChunkReorderMap(chunkReorderMap.data(), shuffledChunkDescs.data(), chunkDescCount, scratch2.data(), messageLog);
+ EXPECT_FALSE(isIdentity);
+ NvBlastApplyAssetDescChunkReorderMap(chunkDescs, shuffledChunkDescs.data(), chunkDescCount, bondDescs, bondDescCount, chunkReorderMap.data(), true, messageLog);
+ }
+ else
+ {
+ memcpy(chunkDescs, shuffledChunkDescs.data(), chunkDescCount * sizeof(NvBlastChunkDesc));
+ const bool isIdentity = NvBlastTkFrameworkGet()->reorderAssetDescChunks(chunkDescs, chunkDescCount, bondDescs, bondDescCount, nullptr, true);
+ EXPECT_FALSE(isIdentity);
+ }
+ }
+
+ void mergeAssetTest(const NvBlastAssetDesc& desc, bool fail)
+ {
+ std::vector<char> scratch;
+
+ scratch.resize((size_t)NvBlastGetRequiredScratchForCreateAsset(&desc, messageLog));
+ void* mem = NVBLAST_ALLOC(NvBlastGetAssetMemorySize(&desc, messageLog));
+ NvBlastAsset* asset = NvBlastCreateAsset(mem, &desc, scratch.data(), messageLog);
+ EXPECT_TRUE(asset != nullptr);
+ if (asset == nullptr)
+ {
+ free(mem);
+ return;
+ }
+
+ // Merge two copies of this asset together
+ const NvBlastAsset* components[2] = { asset, asset };
+ const NvcVec3 translations[2] = { { 0, 0, 0 },{ 2, 0, 0 } };
+
+ const NvBlastBond bond = { { 1.0f, 0.0f, 0.0f }, 1.0f,{ 1.0f, 0.0f, 0.0f }, 0 };
+
+ NvBlastExtAssetUtilsBondDesc newBondDescs[4];
+ for (int i = 0; i < 4; ++i)
+ {
+ newBondDescs[i].bond = bond;
+ newBondDescs[i].chunkIndices[0] = 2 * (i + 1);
+ newBondDescs[i].chunkIndices[1] = 2 * i + 1;
+ newBondDescs[i].componentIndices[0] = 0;
+ newBondDescs[i].componentIndices[1] = 1;
+ }
+
+ // Create a merged descriptor
+ std::vector<uint32_t> chunkIndexOffsets(2);
+ std::vector<uint32_t> chunkReorderMap(2 * desc.chunkCount);
+
+ NvBlastAssetDesc mergedDesc = NvBlastExtAssetUtilsMergeAssets(components, nullptr, nullptr, translations, 2, newBondDescs, 4, chunkIndexOffsets.data(), chunkReorderMap.data(), 2 * desc.chunkCount);
+ EXPECT_EQ(2 * desc.bondCount + 4, mergedDesc.bondCount);
+ EXPECT_EQ(2 * desc.chunkCount, mergedDesc.chunkCount);
+ for (uint32_t i = 0; i < 2 * desc.chunkCount; ++i)
+ {
+ EXPECT_LT(chunkReorderMap[i], 2 * desc.chunkCount);
+ }
+ EXPECT_EQ(0, chunkIndexOffsets[0]);
+ EXPECT_EQ(desc.chunkCount, chunkIndexOffsets[1]);
+
+ scratch.resize((size_t)NvBlastGetRequiredScratchForCreateAsset(&mergedDesc, messageLog));
+ mem = NVBLAST_ALLOC(NvBlastGetAssetMemorySize(&mergedDesc, messageLog));
+ NvBlastAsset* mergedAsset = NvBlastCreateAsset(mem, &mergedDesc, scratch.data(), messageLog);
+ EXPECT_TRUE(mergedAsset != nullptr);
+ if (mergedAsset == nullptr)
+ {
+ free(mem);
+ return;
+ }
+
+ NVBLAST_FREE(const_cast<NvBlastBondDesc*>(mergedDesc.bondDescs));
+ NVBLAST_FREE(const_cast<NvBlastChunkDesc*>(mergedDesc.chunkDescs));
+ NVBLAST_FREE(mergedAsset);
+
+ if (!fail)
+ {
+ mergedDesc = NvBlastExtAssetUtilsMergeAssets(components, nullptr, nullptr, translations, 2, newBondDescs, 4, nullptr, chunkReorderMap.data(), 2 * desc.chunkCount);
+ EXPECT_EQ(2 * desc.bondCount + 4, mergedDesc.bondCount);
+ EXPECT_EQ(2 * desc.chunkCount, mergedDesc.chunkCount);
+ for (uint32_t i = 0; i < 2 * desc.chunkCount; ++i)
+ {
+ EXPECT_LT(chunkReorderMap[i], 2 * desc.chunkCount);
+ }
+ scratch.resize((size_t)NvBlastGetRequiredScratchForCreateAsset(&mergedDesc, messageLog));
+ mem = NVBLAST_ALLOC(NvBlastGetAssetMemorySize(&mergedDesc, messageLog));
+ mergedAsset = NvBlastCreateAsset(mem, &mergedDesc, scratch.data(), messageLog);
+ EXPECT_TRUE(mergedAsset != nullptr);
+ free(mem);
+ NVBLAST_FREE(const_cast<NvBlastBondDesc*>(mergedDesc.bondDescs));
+ NVBLAST_FREE(const_cast<NvBlastChunkDesc*>(mergedDesc.chunkDescs));
+ }
+ else
+ {
+ // We don't pass in a valid chunkReorderMap so asset creation should fail
+ mergedDesc = NvBlastExtAssetUtilsMergeAssets(components, nullptr, nullptr, translations, 2, newBondDescs, 4, chunkIndexOffsets.data(), nullptr, 0);
+ EXPECT_EQ(2 * desc.bondCount + 4, mergedDesc.bondCount);
+ EXPECT_EQ(2 * desc.chunkCount, mergedDesc.chunkCount);
+ EXPECT_EQ(0, chunkIndexOffsets[0]);
+ EXPECT_EQ(desc.chunkCount, chunkIndexOffsets[1]);
+ scratch.resize((size_t)NvBlastGetRequiredScratchForCreateAsset(&mergedDesc, messageLog));
+ mem = NVBLAST_ALLOC(NvBlastGetAssetMemorySize(&mergedDesc, messageLog));
+ mergedAsset = NvBlastCreateAsset(mem, &mergedDesc, scratch.data(), messageLog);
+ EXPECT_TRUE(mergedAsset == nullptr);
+ free(mem);
+ NVBLAST_FREE(const_cast<NvBlastBondDesc*>(mergedDesc.bondDescs));
+ NVBLAST_FREE(const_cast<NvBlastChunkDesc*>(mergedDesc.chunkDescs));
+
+ mergedDesc = NvBlastExtAssetUtilsMergeAssets(components, nullptr, nullptr, translations, 2, newBondDescs, 4, nullptr, nullptr, 0);
+ EXPECT_EQ(2 * desc.bondCount + 4, mergedDesc.bondCount);
+ EXPECT_EQ(2 * desc.chunkCount, mergedDesc.chunkCount);
+ scratch.resize((size_t)NvBlastGetRequiredScratchForCreateAsset(&mergedDesc, messageLog));
+ mem = NVBLAST_ALLOC(NvBlastGetAssetMemorySize(&mergedDesc, messageLog));
+ mergedAsset = NvBlastCreateAsset(mem, &mergedDesc, scratch.data(), messageLog);
+ EXPECT_TRUE(mergedAsset == nullptr);
+ free(mem);
+ NVBLAST_FREE(const_cast<NvBlastBondDesc*>(mergedDesc.bondDescs));
+ NVBLAST_FREE(const_cast<NvBlastChunkDesc*>(mergedDesc.chunkDescs));
+
+ // We lie and say the chunkReorderMap is not large enough. It should be filled with 0xFFFFFFFF up to the size we gave
+ mergedDesc = NvBlastExtAssetUtilsMergeAssets(components, nullptr, nullptr, translations, 2, newBondDescs, 4, nullptr, chunkReorderMap.data(), desc.chunkCount);
+ EXPECT_EQ(2 * desc.bondCount + 4, mergedDesc.bondCount);
+ EXPECT_EQ(2 * desc.chunkCount, mergedDesc.chunkCount);
+ for (uint32_t i = 0; i < desc.chunkCount; ++i)
+ {
+ EXPECT_TRUE(Nv::Blast::isInvalidIndex(chunkReorderMap[i]));
+ }
+ scratch.resize((size_t)NvBlastGetRequiredScratchForCreateAsset(&mergedDesc, messageLog));
+ mem = NVBLAST_ALLOC(NvBlastGetAssetMemorySize(&mergedDesc, messageLog));
+ mergedAsset = NvBlastCreateAsset(mem, &mergedDesc, scratch.data(), messageLog);
+ EXPECT_TRUE(mergedAsset == nullptr);
+ free(mem);
+ NVBLAST_FREE(const_cast<NvBlastBondDesc*>(mergedDesc.bondDescs));
+ NVBLAST_FREE(const_cast<NvBlastChunkDesc*>(mergedDesc.chunkDescs));
+
+ mergedDesc = NvBlastExtAssetUtilsMergeAssets(components, nullptr, nullptr, translations, 2, newBondDescs, 4, chunkIndexOffsets.data(), chunkReorderMap.data(), desc.chunkCount);
+ EXPECT_EQ(2 * desc.bondCount + 4, mergedDesc.bondCount);
+ EXPECT_EQ(2 * desc.chunkCount, mergedDesc.chunkCount);
+ for (uint32_t i = 0; i < desc.chunkCount; ++i)
+ {
+ EXPECT_TRUE(Nv::Blast::isInvalidIndex(chunkReorderMap[i]));
+ }
+ EXPECT_EQ(0, chunkIndexOffsets[0]);
+ EXPECT_EQ(desc.chunkCount, chunkIndexOffsets[1]);
+ scratch.resize((size_t)NvBlastGetRequiredScratchForCreateAsset(&mergedDesc, messageLog));
+ mem = NVBLAST_ALLOC(NvBlastGetAssetMemorySize(&mergedDesc, messageLog));
+ mergedAsset = NvBlastCreateAsset(mem, &mergedDesc, scratch.data(), messageLog);
+ EXPECT_TRUE(mergedAsset == nullptr);
+ free(mem);
+ NVBLAST_FREE(const_cast<NvBlastBondDesc*>(mergedDesc.bondDescs));
+ NVBLAST_FREE(const_cast<NvBlastChunkDesc*>(mergedDesc.chunkDescs));
+ }
+
+ // Finally free the original asset
+ NVBLAST_FREE(asset);
+ }
+};
+
+typedef AssetTest<-1, 0> AssetTestAllowErrorsSilently;
+typedef AssetTest<NvBlastMessage::Error, 0> AssetTestAllowWarningsSilently;
+typedef AssetTest<NvBlastMessage::Error, 1> AssetTestAllowWarnings;
+typedef AssetTest<NvBlastMessage::Warning, 1> AssetTestStrict;
+
+
+TEST_F(AssetTestStrict, BuildAssets)
+{
+ const uint32_t assetDescCount = sizeof(g_assetDescs) / sizeof(g_assetDescs[0]);
+
+ std::vector<NvBlastAsset*> assets(assetDescCount);
+
+ // Build
+ for (uint32_t i = 0; i < assetDescCount; ++i)
+ {
+ assets[i] = buildAsset(g_assetExpectedValues[i], &g_assetDescs[i]);
+ }
+
+ // Destroy
+ for (uint32_t i = 0; i < assetDescCount; ++i)
+ {
+ if (assets[i])
+ {
+ free(assets[i]);
+ }
+ }
+}
+
+#if ENABLE_SERIALIZATION_TESTS
+TEST_F(AssetTestStrict, SerializeAssets)
+{
+ Nv::Blast::ExtSerialization* ser = NvBlastExtSerializationCreate();
+ EXPECT_TRUE(ser != nullptr);
+
+ const uint32_t assetDescCount = sizeof(g_assetDescs) / sizeof(g_assetDescs[0]);
+
+ std::vector<Nv::Blast::Asset*> assets(assetDescCount);
+
+ // Build
+ for (uint32_t i = 0; i < assetDescCount; ++i)
+ {
+ assets[i] = reinterpret_cast<Nv::Blast::Asset*>(buildAsset(g_assetExpectedValues[i], &g_assetDescs[i]));
+ }
+
+ // Serialize them
+ for (Nv::Blast::Asset* asset : assets)
+ {
+ void* buffer;
+ const uint64_t size = NvBlastExtSerializationSerializeAssetIntoBuffer(buffer, *ser, asset);
+ EXPECT_TRUE(size != 0);
+
+ uint32_t objectTypeID;
+ uint32_t encodingID;
+ uint64_t dataSize = 0;
+ EXPECT_TRUE(ser->peekHeader(&objectTypeID, &encodingID, &dataSize, buffer, size));
+ EXPECT_EQ(objectTypeID, Nv::Blast::LlObjectTypeID::Asset);
+ EXPECT_EQ(encodingID, ser->getSerializationEncoding());
+ EXPECT_EQ(dataSize + Nv::Blast::ExtSerializationInternal::HeaderSize, size);
+ }
+
+ // Destroy
+ for (uint32_t i = 0; i < assetDescCount; ++i)
+ {
+ if (assets[i])
+ {
+ free(assets[i]);
+ }
+ }
+
+ ser->release();
+}
+
+TEST_F(AssetTestStrict, SerializeAssetsRoundTrip)
+{
+ Nv::Blast::ExtSerialization* ser = NvBlastExtSerializationCreate();
+ EXPECT_TRUE(ser != nullptr);
+
+ const uint32_t assetDescCount = sizeof(g_assetDescs) / sizeof(g_assetDescs[0]);
+
+ std::vector<Nv::Blast::Asset*> assets(assetDescCount);
+
+ // Build
+ for (uint32_t i = 0; i < assetDescCount; ++i)
+ {
+ assets[i] = reinterpret_cast<Nv::Blast::Asset*>(buildAsset(g_assetExpectedValues[i], &g_assetDescs[i]));
+ }
+
+ const uint32_t encodings[] =
+ {
+ Nv::Blast::ExtSerialization::EncodingID::CapnProtoBinary,
+ Nv::Blast::ExtSerialization::EncodingID::RawBinary
+ };
+
+ for (auto encoding : encodings)
+ {
+ ser->setSerializationEncoding(encoding);
+
+ // Serialize them
+ for (uint32_t i = 0; i < assetDescCount; ++i)
+ {
+ Nv::Blast::Asset* asset = assets[i];
+
+ void* buffer;
+ const uint64_t size = NvBlastExtSerializationSerializeAssetIntoBuffer(buffer, *ser, asset);
+ EXPECT_TRUE(size != 0);
+
+ Nv::Blast::Asset* rtAsset = reinterpret_cast<Nv::Blast::Asset*>(ser->deserializeFromBuffer(buffer, size));
+
+ //TODO: Compare assets
+ checkAssetsExpected(*rtAsset, g_assetExpectedValues[i]);
+
+ free(static_cast<void*>(rtAsset));
+ }
+ }
+
+ // Destroy
+ for (uint32_t i = 0; i < assetDescCount; ++i)
+ {
+ if (assets[i])
+ {
+ free(assets[i]);
+ }
+ }
+
+ ser->release();
+}
+
+TEST_F(AssetTestStrict, SerializeAssetsRoundTripWithSkipping)
+{
+ Nv::Blast::ExtSerialization* ser = NvBlastExtSerializationCreate();
+ EXPECT_TRUE(ser != nullptr);
+
+ std::vector<char> stream;
+
+ class StreamBufferProvider : public Nv::Blast::ExtSerialization::BufferProvider
+ {
+ public:
+ StreamBufferProvider(std::vector<char>& stream) : m_stream(stream), m_cursor(0) {}
+
+ virtual void* requestBuffer(size_t size) override
+ {
+ m_stream.resize(m_cursor + size);
+ void* data = m_stream.data() + m_cursor;
+ m_cursor += size;
+ return data;
+ }
+
+ private:
+ std::vector<char>& m_stream;
+ size_t m_cursor;
+ } myStreamProvider(stream);
+
+ ser->setBufferProvider(&myStreamProvider);
+
+ const uint32_t assetDescCount = sizeof(g_assetDescs) / sizeof(g_assetDescs[0]);
+
+ std::vector<Nv::Blast::Asset*> assets(assetDescCount);
+
+ // Build
+ for (uint32_t i = 0; i < assetDescCount; ++i)
+ {
+ assets[i] = reinterpret_cast<Nv::Blast::Asset*>(buildAsset(g_assetExpectedValues[i], &g_assetDescs[i]));
+ }
+
+ const uint32_t encodings[] =
+ {
+ Nv::Blast::ExtSerialization::EncodingID::CapnProtoBinary,
+ Nv::Blast::ExtSerialization::EncodingID::RawBinary
+ };
+
+ for (auto encoding : encodings)
+ {
+ ser->setSerializationEncoding(encoding);
+
+ // Serialize them
+ for (uint32_t i = 0; i < assetDescCount; ++i)
+ {
+ void* buffer;
+ const uint64_t size = NvBlastExtSerializationSerializeAssetIntoBuffer(buffer, *ser, assets[i]);
+ EXPECT_TRUE(size != 0);
+ }
+ }
+
+ // Deserialize from stream
+ const void* buffer = stream.data();
+ uint64_t bufferSize = stream.size();
+ for (uint32_t assetCount = 0; bufferSize; ++assetCount)
+ {
+ uint32_t objectTypeID;
+ uint32_t encodingID;
+ const bool peekSuccess = ser->peekHeader(&objectTypeID, &encodingID, nullptr, buffer, bufferSize);
+ EXPECT_TRUE(peekSuccess);
+ if (!peekSuccess)
+ {
+ break;
+ }
+
+ EXPECT_EQ(Nv::Blast::LlObjectTypeID::Asset, objectTypeID);
+ if (assetCount < assetDescCount)
+ {
+ EXPECT_EQ(Nv::Blast::ExtSerialization::EncodingID::CapnProtoBinary, encodingID);
+ }
+ else
+ {
+ EXPECT_EQ(Nv::Blast::ExtSerialization::EncodingID::RawBinary, encodingID);
+ }
+
+ const bool skip = (assetCount & 1) != 0;
+
+ if (!skip)
+ {
+ const uint32_t assetnum = assetCount % assetDescCount;
+ Nv::Blast::Asset* rtAsset = reinterpret_cast<Nv::Blast::Asset*>(ser->deserializeFromBuffer(buffer, bufferSize));
+ EXPECT_TRUE(rtAsset != nullptr);
+ if (rtAsset == nullptr)
+ {
+ break;
+ }
+
+ //TODO: Compare assets
+ checkAssetsExpected(*rtAsset, g_assetExpectedValues[assetnum]);
+
+ free(static_cast<void*>(rtAsset));
+ }
+
+ buffer = ser->skipObject(bufferSize, buffer);
+ }
+
+ // Destroy
+ for (uint32_t i = 0; i < assetDescCount; ++i)
+ {
+ if (assets[i])
+ {
+ free(assets[i]);
+ }
+ }
+
+ ser->release();
+}
+#endif // ENABLE_SERIALIZATION_TESTS
+
+TEST_F(AssetTestAllowWarnings, BuildAssetsMissingCoverage)
+{
+ const uint32_t assetDescCount = sizeof(g_assetDescsMissingCoverage) / sizeof(g_assetDescsMissingCoverage[0]);
+
+ std::vector<NvBlastAsset*> assets(assetDescCount);
+
+ // Build
+ for (uint32_t i = 0; i < assetDescCount; ++i)
+ {
+ const NvBlastAssetDesc* desc = &g_assetDescsMissingCoverage[i];
+ NvBlastAssetDesc fixedDesc = *desc;
+ std::vector<NvBlastChunkDesc> chunkDescs(desc->chunkDescs, desc->chunkDescs + desc->chunkCount);
+ std::vector<NvBlastBondDesc> bondDescs(desc->bondDescs, desc->bondDescs + desc->bondCount);
+ std::vector<uint32_t> chunkReorderMap(desc->chunkCount);
+ std::vector<char> scratch(desc->chunkCount * sizeof(NvBlastChunkDesc));
+ const bool changedCoverage = !NvBlastEnsureAssetExactSupportCoverage(chunkDescs.data(), fixedDesc.chunkCount, scratch.data(), messageLog);
+ EXPECT_TRUE(changedCoverage);
+ NvBlastReorderAssetDescChunks(chunkDescs.data(), fixedDesc.chunkCount, bondDescs.data(), fixedDesc.bondCount, chunkReorderMap.data(), true, scratch.data(), messageLog);
+ fixedDesc.chunkDescs = chunkDescs.data();
+ fixedDesc.bondDescs = bondDescs.data();
+ assets[i] = buildAsset(g_assetsFromMissingCoverageExpectedValues[i], &fixedDesc);
+ }
+
+ // Destroy
+ for (uint32_t i = 0; i < assetDescCount; ++i)
+ {
+ if (assets[i])
+ {
+ free(assets[i]);
+ }
+ }
+}
+
+TEST_F(AssetTestAllowWarningsSilently, BuildAssetsShufflingChunkDescriptors)
+{
+ for (uint32_t i = 0; i < sizeof(g_assetDescs) / sizeof(g_assetDescs[0]); ++i)
+ {
+ buildAssetShufflingDescriptors(&g_assetDescs[i], g_assetExpectedValues[i], 10, false);
+ }
+
+ for (uint32_t i = 0; i < sizeof(g_assetDescsMissingCoverage) / sizeof(g_assetDescsMissingCoverage[0]); ++i)
+ {
+ buildAssetShufflingDescriptors(&g_assetDescsMissingCoverage[i], g_assetsFromMissingCoverageExpectedValues[i], 10, false);
+ }
+}
+
+TEST_F(AssetTestAllowWarningsSilently, BuildAssetsShufflingChunkDescriptorsUsingTk)
+{
+ for (uint32_t i = 0; i < sizeof(g_assetDescs) / sizeof(g_assetDescs[0]); ++i)
+ {
+ buildAssetShufflingDescriptors(&g_assetDescs[i], g_assetExpectedValues[i], 10, true);
+ }
+
+ for (uint32_t i = 0; i < sizeof(g_assetDescsMissingCoverage) / sizeof(g_assetDescsMissingCoverage[0]); ++i)
+ {
+ buildAssetShufflingDescriptors(&g_assetDescsMissingCoverage[i], g_assetsFromMissingCoverageExpectedValues[i], 10, true);
+ }
+}
+
+TEST_F(AssetTestStrict, MergeAssetsUpperSupportOnly)
+{
+ mergeAssetTest(g_assetDescs[0], false);
+}
+
+TEST_F(AssetTestStrict, MergeAssetsWithSubsupport)
+{
+ mergeAssetTest(g_assetDescs[1], false);
+}
+
+TEST_F(AssetTestStrict, MergeAssetsWithWorldBondsUpperSupportOnly)
+{
+ mergeAssetTest(g_assetDescs[3], false);
+}
+
+TEST_F(AssetTestStrict, MergeAssetsWithWorldBondsWithSubsupport)
+{
+ mergeAssetTest(g_assetDescs[4], false);
+}
+
+TEST_F(AssetTestAllowErrorsSilently, MergeAssetsUpperSupportOnlyExpectFail)
+{
+ mergeAssetTest(g_assetDescs[0], true);
+}
+
+TEST_F(AssetTestAllowErrorsSilently, MergeAssetsWithSubsupportExpectFail)
+{
+ mergeAssetTest(g_assetDescs[1], true);
+}
+
+TEST_F(AssetTestAllowErrorsSilently, MergeAssetsWithWorldBondsUpperSupportOnlyExpectFail)
+{
+ mergeAssetTest(g_assetDescs[3], true);
+}
+
+TEST_F(AssetTestAllowErrorsSilently, MergeAssetsWithWorldBondsWithSubsupportExpectFail)
+{
+ mergeAssetTest(g_assetDescs[4], true);
+}
|