// 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 "TkBaseTest.h" #include "NvBlastExtSync.h" #include "NvBlastTkEvent.h" #include /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // ExtSync Tests /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// class Base { public: Base(TkTestStrict* test) : m_test(test) { } void run(std::stringstream& finalState) { //////// initial setup //////// m_test->createTestAssets(); TkFramework* fwk = NvBlastTkFrameworkGet(); TkGroupDesc gdesc; gdesc.workerCount = m_test->m_taskman->getCpuDispatcher()->getWorkerCount(); m_group = fwk->createGroup(gdesc); EXPECT_TRUE(m_group != nullptr); TkActorDesc adesc(m_test->testAssets[0]); NvBlastID id; TkActor* actor0 = fwk->createActor(adesc); EXPECT_TRUE(actor0 != nullptr); families[0] = &actor0->getFamily(); memcpy(id.data, "Mumble Jumble Bumble", sizeof(NvBlastID)); // Stuffing an arbitrary 16 bytes (The prefix of the given string) families[0]->setID(id); m_group->addActor(*actor0); TkActor* actor1 = fwk->createActor(adesc); EXPECT_TRUE(actor1 != nullptr); families[1] = &actor1->getFamily(); memcpy(id.data, "buzzkillerdiller", sizeof(NvBlastID)); // Stuffing an arbitrary 16 bytes (The prefix of the given string) families[1]->setID(id); m_group->addActor(*actor1); m_test->m_groupTM->setGroup(m_group); //////// server/client specific impl //////// impl(); //////// write out framework final state //////// finalState.clear(); for (auto family : families) { std::vector actors(family->getActorCount()); family->getActors(actors.data(), static_cast(actors.size())); for (auto actor : actors) { finalState << actor->getVisibleChunkCount(); finalState << actor->getGraphNodeCount(); std::vector chunkIndices(actor->getGraphNodeCount()); actor->getVisibleChunkIndices(chunkIndices.data(), (uint32_t)chunkIndices.size()); for (uint32_t chunkIndex : chunkIndices) finalState << chunkIndex; const float* bondHealths = actor->getBondHealths(); for (uint32_t i = 0; i < actor->getAsset()->getBondCount(); ++i) finalState << bondHealths[i]; } } //////// release //////// m_group->release(); for (auto family : families) { family->release(); } m_test->releaseTestAssets(); } protected: virtual void impl() = 0; TkTestStrict* m_test; TkGroup* m_group; TkFamily* families[2]; }; class Server : public Base { public: Server(TkTestStrict* test, std::vector& syncBuffer) : Base(test), m_syncBuffer(syncBuffer) {} protected: virtual void impl() override { // create sync ext ExtSync* sync = ExtSync::create(); // add sync as listener to family #1 families[1]->addListener(*sync); // damage params CSParams cs0(1, 0.0f); NvBlastExtProgramParams csParams0 = { &cs0, nullptr }; NvBlastExtRadialDamageDesc radialDamage0 = m_test->getRadialDamageDesc(0, 0, 0); NvBlastExtProgramParams radialParams0 = { &radialDamage0, nullptr }; NvBlastExtRadialDamageDesc radialDamage1 = m_test->getRadialDamageDesc(0, 0, 0, 10.0f, 10.0f, 0.1f); NvBlastExtProgramParams radialParams1 = { &radialDamage1, nullptr }; // damage family #0 (make it split) { TkActor* actor; families[0]->getActors(&actor, 1); actor->damage(m_test->getCubeSlicerProgram(), &csParams0); } // process m_test->m_groupTM->process(); m_test->m_groupTM->wait(); EXPECT_EQ(families[0]->getActorCount(), 2); // sync family #0 sync->syncFamily(*families[0]); // add sync as listener to family #0 families[0]->addListener(*sync); // damage family #0 (make it split fully) { TkActor* actor; families[0]->getActors(&actor, 1, 1); actor->damage(m_test->getFalloffProgram(), &radialParams0); } // damage family 1 (just damage bonds health) { TkActor* actor; families[1]->getActors(&actor, 1); NvBlastExtRadialDamageDesc radialDamage = m_test->getRadialDamageDesc(0, 0, 0, 10.0f, 10.0f, 0.1f); actor->damage(m_test->getFalloffProgram(), &radialParams1); } // process m_test->m_groupTM->process(); m_test->m_groupTM->wait(); EXPECT_EQ(families[0]->getActorCount(), 5); EXPECT_EQ(families[1]->getActorCount(), 1); // take sync buffer from sync { const ExtSyncEvent*const* buffer; uint32_t size; sync->acquireSyncBuffer(buffer, size); m_syncBuffer.resize(size); for (size_t i = 0; i < size; ++i) { m_syncBuffer[i] = buffer[i]->clone(); } sync->releaseSyncBuffer(); } // families[0]->removeListener(*sync); families[1]->removeListener(*sync); // sync->release(); } private: std::vector& m_syncBuffer; }; class Client : public Base, public TkEventListener { public: Client(TkTestStrict* test, std::vector& syncBuffer) : Base(test), m_syncBuffer(syncBuffer) {} protected: virtual void impl() override { ExtSync* sync = ExtSync::create(); // fill map for (auto& family : families) { std::vector actors(family->getActorCount()); family->getActors(actors.data(), static_cast(actors.size())); auto& actorsSet = m_actorsPerFamily[family]; for (auto actor : actors) EXPECT_TRUE(actorsSet.insert(actor->getIndex()).second); } // subscribe for (auto& family : families) { family->addListener(*this); } // apply sync buffer sync->applySyncBuffer(*NvBlastTkFrameworkGet(), (const Nv::Blast::ExtSyncEvent**)m_syncBuffer.data(), static_cast(m_syncBuffer.size()), m_group); // check map for (auto& family : families) { std::vector actors(family->getActorCount()); family->getActors(actors.data(), static_cast(actors.size())); std::set actorsSet; for (auto actor : actors) EXPECT_TRUE(actorsSet.insert(actor->getIndex()).second); EXPECT_TRUE(m_actorsPerFamily[family] == actorsSet); } // unsubscribe for (auto& family : families) { family->removeListener(*this); } m_test->m_groupTM->process(); m_test->m_groupTM->wait(); sync->release(); } // listen for Split event and update actors map virtual void receive(const TkEvent* events, uint32_t eventCount) override { for (size_t i = 0; i < eventCount; ++i) { const TkEvent& e = events[i]; switch (e.type) { case (TkEvent::Split) : { const TkSplitEvent* splitEvent = e.getPayload(); auto& actorsSet = m_actorsPerFamily[splitEvent->parentData.family]; if (!isInvalidIndex(splitEvent->parentData.index)) { EXPECT_EQ((size_t)1, actorsSet.erase(splitEvent->parentData.index)); } for (size_t i = 0; i < splitEvent->numChildren; ++i) { TkActor* a = splitEvent->children[i]; EXPECT_TRUE(actorsSet.insert(a->getIndex()).second); } break; } case (TkEvent::FractureCommand) : { break; } case (TkEvent::JointUpdate) : { FAIL(); break; } default: break; } } } private: std::map> m_actorsPerFamily; std::vector& m_syncBuffer; }; TEST_F(TkTestStrict, SyncTest1) { this->createFramework(); std::vector syncBuffer; std::stringstream serverFinalState; { Server s(this, syncBuffer); s.run(serverFinalState); } EXPECT_TRUE(syncBuffer.size() > 0); std::stringstream clientFinalState; { Client c(this, syncBuffer); c.run(clientFinalState); } for (auto e : syncBuffer) { e->release(); } syncBuffer.clear(); EXPECT_EQ(serverFinalState.str(), clientFinalState.str()); this->releaseFramework(); }