ResourceLoaderTests.cpp 71 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300
  1. /*******************************************************************************
  2. The content of this file includes portions of the proprietary AUDIOKINETIC Wwise
  3. Technology released in source code form as part of the game integration package.
  4. The content of this file may not be used without valid licenses to the
  5. AUDIOKINETIC Wwise Technology.
  6. Note that the use of the game engine is subject to the Unreal(R) Engine End User
  7. License Agreement at https://www.unrealengine.com/en-US/eula/unreal
  8. License Usage
  9. Licensees holding valid licenses to the AUDIOKINETIC Wwise Technology may use
  10. this file in accordance with the end user license agreement provided with the
  11. software or, alternatively, in accordance with the terms contained
  12. in a written agreement between you and Audiokinetic Inc.
  13. Copyright (c) 2023 Audiokinetic Inc.
  14. *******************************************************************************/
  15. #include "Wwise/WwiseUnitTests.h"
  16. #if WWISE_UNIT_TESTS
  17. #include "Wwise/WwiseResourceLoaderImpl.h"
  18. #include "Wwise/Mock/WwiseMockExternalSourceManager.h"
  19. #include "Wwise/Mock/WwiseMockMediaManager.h"
  20. #include "Wwise/Mock/WwiseMockSoundBankManager.h"
  21. #include <array>
  22. #include <atomic>
  23. #include <memory>
  24. WWISE_TEST_CASE(ResourceLoader_Smoke, "Wwise::ResourceLoader::ResourceLoader_Smoke", "[ApplicationContextMask][SmokeFilter]")
  25. {
  26. SECTION("Static")
  27. {
  28. static_assert(std::is_constructible<FWwiseResourceLoaderImpl>::value, "Resource Loader must be constructed without parameters");
  29. static_assert(!std::is_copy_constructible<FWwiseResourceLoaderImpl>::value, "Cannot copy a Resource Loader");
  30. static_assert(!std::is_copy_assignable<FWwiseResourceLoaderImpl>::value, "Cannot reassign a Resource Loader");
  31. static_assert(!std::is_move_constructible<FWwiseResourceLoaderImpl>::value, "Cannot move a Resource Loader");
  32. }
  33. SECTION("Instantiation")
  34. {
  35. FWwiseResourceLoaderImpl ResourceLoaderImpl;
  36. }
  37. SECTION("Sync AuxBus")
  38. {
  39. FWwiseMockExternalSourceManager ExternalSourceManager;
  40. FWwiseMockMediaManager MediaManager;
  41. FWwiseMockSoundBankManager SoundBankManager;
  42. FWwiseResourceLoaderImpl ResourceLoaderImpl(ExternalSourceManager, MediaManager, SoundBankManager);
  43. FWwiseLocalizedAuxBusCookedData CookedData;
  44. {
  45. FWwiseAuxBusCookedData Data1;
  46. Data1.Media.Emplace(FWwiseMediaCookedData{});
  47. Data1.SoundBanks.Emplace(FWwiseSoundBankCookedData{});
  48. CookedData.AuxBusLanguageMap.Emplace(FWwiseLanguageCookedData::Sfx, MoveTemp(Data1));
  49. }
  50. // Creating Node
  51. auto* Node = ResourceLoaderImpl.CreateAuxBusNode(CookedData, nullptr);
  52. CHECK(Node);
  53. if (UNLIKELY(!Node))
  54. {
  55. return;
  56. }
  57. // Loading Node
  58. FWwiseLoadedAuxBusPromise LoadPromise;
  59. auto LoadFuture = LoadPromise.GetFuture();
  60. ResourceLoaderImpl.LoadAuxBusAsync(MoveTemp(LoadPromise), MoveTemp(Node));
  61. auto LoadedNode = LoadFuture.Get(); // Synchronously
  62. CHECK(LoadedNode);
  63. if (UNLIKELY(!LoadedNode))
  64. {
  65. return;
  66. }
  67. // Unloading Node
  68. FWwiseResourceUnloadPromise UnloadPromise;
  69. auto UnloadFuture = UnloadPromise.GetFuture();
  70. ResourceLoaderImpl.UnloadAuxBusAsync(MoveTemp(UnloadPromise), MoveTemp(LoadedNode));
  71. UnloadFuture.Get(); // Synchronously
  72. CHECK(ExternalSourceManager.IsEmpty());
  73. CHECK(MediaManager.IsEmpty());
  74. CHECK(SoundBankManager.IsEmpty());
  75. CHECK(ResourceLoaderImpl.IsEmpty());
  76. CHECK(ResourceLoaderImpl.TrimGroupValueInfo());
  77. }
  78. SECTION("Sync Event")
  79. {
  80. FWwiseMockExternalSourceManager ExternalSourceManager;
  81. FWwiseMockMediaManager MediaManager;
  82. FWwiseMockSoundBankManager SoundBankManager;
  83. FWwiseResourceLoaderImpl ResourceLoaderImpl(ExternalSourceManager, MediaManager, SoundBankManager);
  84. FWwiseLocalizedEventCookedData CookedData;
  85. {
  86. FWwiseEventCookedData Data1;
  87. Data1.Media.Emplace(FWwiseMediaCookedData{});
  88. Data1.SoundBanks.Emplace(FWwiseSoundBankCookedData{});
  89. FWwiseSwitchContainerLeafCookedData Leaf1;
  90. FWwiseMediaCookedData Leaf1Media;
  91. Leaf1Media.MediaId = 1;
  92. Leaf1.Media.Emplace(MoveTemp(Leaf1Media));
  93. FWwiseGroupValueCookedData Leaf1GroupValue;
  94. Leaf1GroupValue.Id = 1;
  95. Leaf1GroupValue.GroupId = 1;
  96. Leaf1GroupValue.Type = EWwiseGroupType::Switch;
  97. Leaf1.GroupValueSet.Emplace(MoveTemp(Leaf1GroupValue));
  98. Data1.SwitchContainerLeaves.Emplace(MoveTemp(Leaf1));
  99. CookedData.EventLanguageMap.Emplace(FWwiseLanguageCookedData::Sfx, MoveTemp(Data1));
  100. }
  101. // Creating Node
  102. auto* Node = ResourceLoaderImpl.CreateEventNode(CookedData, nullptr);
  103. CHECK(Node);
  104. if (UNLIKELY(!Node))
  105. {
  106. return;
  107. }
  108. // Loading Node
  109. FWwiseLoadedEventPromise LoadPromise;
  110. auto LoadFuture = LoadPromise.GetFuture();
  111. ResourceLoaderImpl.LoadEventAsync(MoveTemp(LoadPromise), MoveTemp(Node));
  112. auto Loaded = LoadFuture.Get(); // Synchronously
  113. CHECK(Loaded);
  114. if (UNLIKELY(!Loaded))
  115. {
  116. return;
  117. }
  118. // Unloading Node
  119. FWwiseResourceUnloadPromise UnloadPromise;
  120. auto UnloadFuture = UnloadPromise.GetFuture();
  121. ResourceLoaderImpl.UnloadEventAsync(MoveTemp(UnloadPromise), MoveTemp(Loaded));
  122. UnloadFuture.Get(); // Synchronously
  123. CHECK(ExternalSourceManager.IsEmpty());
  124. CHECK(MediaManager.IsEmpty());
  125. CHECK(SoundBankManager.IsEmpty());
  126. CHECK(ResourceLoaderImpl.IsEmpty());
  127. CHECK(ResourceLoaderImpl.TrimGroupValueInfo());
  128. }
  129. SECTION("Sync External Sources")
  130. {
  131. FWwiseMockExternalSourceManager ExternalSourceManager;
  132. FWwiseMockMediaManager MediaManager;
  133. FWwiseMockSoundBankManager SoundBankManager;
  134. FWwiseResourceLoaderImpl ResourceLoaderImpl(ExternalSourceManager, MediaManager, SoundBankManager);
  135. FWwiseExternalSourceCookedData CookedData;
  136. // Creating Node
  137. auto* Node = ResourceLoaderImpl.CreateExternalSourceNode(CookedData);
  138. CHECK(Node)
  139. if (UNLIKELY(!Node))
  140. {
  141. return;;
  142. }
  143. // Loading Node
  144. FWwiseLoadedExternalSourcePromise LoadPromise;
  145. auto LoadFuture = LoadPromise.GetFuture();
  146. ResourceLoaderImpl.LoadExternalSourceAsync(MoveTemp(LoadPromise), MoveTemp(Node));
  147. auto Loaded = LoadFuture.Get(); // Synchronously
  148. CHECK(Loaded);
  149. if (UNLIKELY(!Loaded))
  150. {
  151. return;
  152. }
  153. // Unloading Node
  154. FWwiseResourceUnloadPromise UnloadPromise;
  155. auto UnloadFuture = UnloadPromise.GetFuture();
  156. ResourceLoaderImpl.UnloadExternalSourceAsync(MoveTemp(UnloadPromise), MoveTemp(Loaded));
  157. UnloadFuture.Get(); // Synchronously
  158. CHECK(ExternalSourceManager.IsEmpty());
  159. CHECK(MediaManager.IsEmpty());
  160. CHECK(SoundBankManager.IsEmpty());
  161. CHECK(ResourceLoaderImpl.IsEmpty());
  162. CHECK(ResourceLoaderImpl.TrimGroupValueInfo());
  163. }
  164. SECTION("Sync GroupValue Switch")
  165. {
  166. FWwiseMockExternalSourceManager ExternalSourceManager;
  167. FWwiseMockMediaManager MediaManager;
  168. FWwiseMockSoundBankManager SoundBankManager;
  169. FWwiseResourceLoaderImpl ResourceLoaderImpl(ExternalSourceManager, MediaManager, SoundBankManager);
  170. FWwiseGroupValueCookedData CookedData;
  171. CookedData.Type = EWwiseGroupType::Switch;
  172. // Creating Node
  173. auto* Node = ResourceLoaderImpl.CreateGroupValueNode(CookedData);
  174. CHECK(Node);
  175. if (UNLIKELY(!Node))
  176. {
  177. return;
  178. }
  179. // Loading Node
  180. FWwiseLoadedGroupValuePromise LoadPromise;
  181. auto LoadFuture = LoadPromise.GetFuture();
  182. ResourceLoaderImpl.LoadGroupValueAsync(MoveTemp(LoadPromise), MoveTemp(Node));
  183. auto Loaded = LoadFuture.Get(); // Synchronously
  184. CHECK(Loaded);
  185. if (UNLIKELY(!Loaded))
  186. {
  187. return;
  188. }
  189. // Unloading Node
  190. FWwiseResourceUnloadPromise UnloadPromise;
  191. auto UnloadFuture = UnloadPromise.GetFuture();
  192. ResourceLoaderImpl.UnloadGroupValueAsync(MoveTemp(UnloadPromise), MoveTemp(Loaded));
  193. UnloadFuture.Get(); // Synchronously
  194. CHECK(ExternalSourceManager.IsEmpty());
  195. CHECK(MediaManager.IsEmpty());
  196. CHECK(SoundBankManager.IsEmpty());
  197. CHECK(ResourceLoaderImpl.IsEmpty());
  198. CHECK(ResourceLoaderImpl.TrimGroupValueInfo());
  199. }
  200. SECTION("Sync GroupValue State")
  201. {
  202. FWwiseMockExternalSourceManager ExternalSourceManager;
  203. FWwiseMockMediaManager MediaManager;
  204. FWwiseMockSoundBankManager SoundBankManager;
  205. FWwiseResourceLoaderImpl ResourceLoaderImpl(ExternalSourceManager, MediaManager, SoundBankManager);
  206. FWwiseGroupValueCookedData CookedData;
  207. CookedData.Type = EWwiseGroupType::State;
  208. // Creating Node
  209. auto* Node = ResourceLoaderImpl.CreateGroupValueNode(CookedData);
  210. CHECK(Node);
  211. if (UNLIKELY(!Node))
  212. {
  213. return;
  214. }
  215. // Loading Node
  216. FWwiseLoadedGroupValuePromise LoadPromise;
  217. auto LoadFuture = LoadPromise.GetFuture();
  218. ResourceLoaderImpl.LoadGroupValueAsync(MoveTemp(LoadPromise), MoveTemp(Node));
  219. auto Loaded = LoadFuture.Get(); // Synchronously
  220. CHECK(Loaded);
  221. if (UNLIKELY(!Loaded))
  222. {
  223. return;
  224. }
  225. // Unloading Node
  226. FWwiseResourceUnloadPromise UnloadPromise;
  227. auto UnloadFuture = UnloadPromise.GetFuture();
  228. ResourceLoaderImpl.UnloadGroupValueAsync(MoveTemp(UnloadPromise), MoveTemp(Loaded));
  229. UnloadFuture.Get(); // Synchronously
  230. CHECK(ExternalSourceManager.IsEmpty());
  231. CHECK(MediaManager.IsEmpty());
  232. CHECK(SoundBankManager.IsEmpty());
  233. CHECK(ResourceLoaderImpl.IsEmpty());
  234. CHECK(ResourceLoaderImpl.TrimGroupValueInfo());
  235. }
  236. SECTION("Sync InitBank")
  237. {
  238. FWwiseMockExternalSourceManager ExternalSourceManager;
  239. FWwiseMockMediaManager MediaManager;
  240. FWwiseMockSoundBankManager SoundBankManager;
  241. FWwiseResourceLoaderImpl ResourceLoaderImpl(ExternalSourceManager, MediaManager, SoundBankManager);
  242. FWwiseInitBankCookedData CookedData;
  243. // Creating Node
  244. auto* Node = ResourceLoaderImpl.CreateInitBankNode(CookedData);
  245. CHECK(Node);
  246. if (UNLIKELY(!Node))
  247. {
  248. return;
  249. }
  250. // Loading Node
  251. FWwiseLoadedInitBankPromise LoadPromise;
  252. auto LoadFuture = LoadPromise.GetFuture();
  253. ResourceLoaderImpl.LoadInitBankAsync(MoveTemp(LoadPromise), MoveTemp(Node));
  254. auto Loaded = LoadFuture.Get(); // Synchronously
  255. CHECK(Loaded);
  256. if (UNLIKELY(!Loaded))
  257. {
  258. return;
  259. }
  260. // Unloading Node
  261. FWwiseResourceUnloadPromise UnloadPromise;
  262. auto UnloadFuture = UnloadPromise.GetFuture();
  263. ResourceLoaderImpl.UnloadInitBankAsync(MoveTemp(UnloadPromise), MoveTemp(Loaded));
  264. UnloadFuture.Get(); // Synchronously
  265. CHECK(ExternalSourceManager.IsEmpty());
  266. CHECK(MediaManager.IsEmpty());
  267. CHECK(SoundBankManager.IsEmpty());
  268. CHECK(ResourceLoaderImpl.IsEmpty());
  269. CHECK(ResourceLoaderImpl.TrimGroupValueInfo());
  270. }
  271. SECTION("Sync Media")
  272. {
  273. FWwiseMockExternalSourceManager ExternalSourceManager;
  274. FWwiseMockMediaManager MediaManager;
  275. FWwiseMockSoundBankManager SoundBankManager;
  276. FWwiseResourceLoaderImpl ResourceLoaderImpl(ExternalSourceManager, MediaManager, SoundBankManager);
  277. FWwiseMediaCookedData CookedData;
  278. // Creating Node
  279. auto* Node = ResourceLoaderImpl.CreateMediaNode(CookedData);
  280. CHECK(Node);
  281. if (UNLIKELY(!Node))
  282. {
  283. return;
  284. }
  285. // Loading Node
  286. FWwiseLoadedMediaPromise LoadPromise;
  287. auto LoadFuture = LoadPromise.GetFuture();
  288. ResourceLoaderImpl.LoadMediaAsync(MoveTemp(LoadPromise), MoveTemp(Node));
  289. auto Loaded = LoadFuture.Get(); // Synchronously
  290. CHECK(Loaded);
  291. if (UNLIKELY(!Loaded))
  292. {
  293. return;
  294. }
  295. // Unloading Node
  296. FWwiseResourceUnloadPromise UnloadPromise;
  297. auto UnloadFuture = UnloadPromise.GetFuture();
  298. ResourceLoaderImpl.UnloadMediaAsync(MoveTemp(UnloadPromise), MoveTemp(Loaded));
  299. UnloadFuture.Get(); // Synchronously
  300. CHECK(ExternalSourceManager.IsEmpty());
  301. CHECK(MediaManager.IsEmpty());
  302. CHECK(SoundBankManager.IsEmpty());
  303. CHECK(ResourceLoaderImpl.IsEmpty());
  304. CHECK(ResourceLoaderImpl.TrimGroupValueInfo());
  305. }
  306. SECTION("Sync ShareSet")
  307. {
  308. FWwiseMockExternalSourceManager ExternalSourceManager;
  309. FWwiseMockMediaManager MediaManager;
  310. FWwiseMockSoundBankManager SoundBankManager;
  311. FWwiseResourceLoaderImpl ResourceLoaderImpl(ExternalSourceManager, MediaManager, SoundBankManager);
  312. FWwiseLocalizedShareSetCookedData CookedData;
  313. {
  314. FWwiseShareSetCookedData Data1;
  315. Data1.Media.Emplace(FWwiseMediaCookedData{});
  316. Data1.SoundBanks.Emplace(FWwiseSoundBankCookedData{});
  317. CookedData.ShareSetLanguageMap.Emplace(FWwiseLanguageCookedData::Sfx, MoveTemp(Data1));
  318. }
  319. // Creating Node
  320. auto* Node = ResourceLoaderImpl.CreateShareSetNode(CookedData, &FWwiseLanguageCookedData::Sfx);
  321. CHECK(Node);
  322. if (UNLIKELY(!Node))
  323. {
  324. return;
  325. }
  326. // Loading Node
  327. FWwiseLoadedShareSetPromise LoadPromise;
  328. auto LoadFuture = LoadPromise.GetFuture();
  329. ResourceLoaderImpl.LoadShareSetAsync(MoveTemp(LoadPromise), MoveTemp(Node));
  330. auto Loaded = LoadFuture.Get(); // Synchronously
  331. CHECK(Loaded);
  332. if (UNLIKELY(!Loaded))
  333. {
  334. return;
  335. }
  336. // Unloading Node
  337. FWwiseResourceUnloadPromise UnloadPromise;
  338. auto UnloadFuture = UnloadPromise.GetFuture();
  339. ResourceLoaderImpl.UnloadShareSetAsync(MoveTemp(UnloadPromise), MoveTemp(Loaded));
  340. UnloadFuture.Get(); // Synchronously
  341. CHECK(ExternalSourceManager.IsEmpty());
  342. CHECK(MediaManager.IsEmpty());
  343. CHECK(SoundBankManager.IsEmpty());
  344. CHECK(ResourceLoaderImpl.IsEmpty());
  345. CHECK(ResourceLoaderImpl.TrimGroupValueInfo());
  346. }
  347. SECTION("Sync SoundBank")
  348. {
  349. FWwiseMockExternalSourceManager ExternalSourceManager;
  350. FWwiseMockMediaManager MediaManager;
  351. FWwiseMockSoundBankManager SoundBankManager;
  352. FWwiseResourceLoaderImpl ResourceLoaderImpl(ExternalSourceManager, MediaManager, SoundBankManager);
  353. FWwiseLocalizedSoundBankCookedData CookedData;
  354. {
  355. FWwiseSoundBankCookedData Data1;
  356. CookedData.SoundBankLanguageMap.Emplace(FWwiseLanguageCookedData::Sfx, MoveTemp(Data1));
  357. }
  358. // Creating Node
  359. auto* Node = ResourceLoaderImpl.CreateSoundBankNode(CookedData, nullptr);
  360. CHECK(Node);
  361. if (UNLIKELY(!Node))
  362. {
  363. return;
  364. }
  365. // Loading Node
  366. FWwiseLoadedSoundBankPromise LoadPromise;
  367. auto LoadFuture = LoadPromise.GetFuture();
  368. ResourceLoaderImpl.LoadSoundBankAsync(MoveTemp(LoadPromise), MoveTemp(Node));
  369. auto Loaded = LoadFuture.Get(); // Synchronously
  370. CHECK(Loaded);
  371. if (UNLIKELY(!Loaded))
  372. {
  373. return;
  374. }
  375. // Unloading Node
  376. FWwiseResourceUnloadPromise UnloadPromise;
  377. auto UnloadFuture = UnloadPromise.GetFuture();
  378. ResourceLoaderImpl.UnloadSoundBankAsync(MoveTemp(UnloadPromise), MoveTemp(Loaded));
  379. UnloadFuture.Get(); // Synchronously
  380. CHECK(ExternalSourceManager.IsEmpty());
  381. CHECK(MediaManager.IsEmpty());
  382. CHECK(SoundBankManager.IsEmpty());
  383. CHECK(ResourceLoaderImpl.IsEmpty());
  384. CHECK(ResourceLoaderImpl.TrimGroupValueInfo());
  385. }
  386. SECTION("Sync SwitchContainer (Event First)")
  387. {
  388. FWwiseMockExternalSourceManager ExternalSourceManager;
  389. FWwiseMockMediaManager MediaManager;
  390. FWwiseMockSoundBankManager SoundBankManager;
  391. FWwiseResourceLoaderImpl ResourceLoaderImpl(ExternalSourceManager, MediaManager, SoundBankManager);
  392. FWwiseGroupValueCookedData GroupValue;
  393. GroupValue.Id = 1;
  394. GroupValue.GroupId = 1;
  395. GroupValue.Type = EWwiseGroupType::Switch;
  396. FWwiseLoadedEventPtr LoadedEvent{nullptr};
  397. FWwiseLoadedGroupValuePtr LoadedGroupValue{nullptr};
  398. // Load Event
  399. do
  400. {
  401. FWwiseLocalizedEventCookedData CookedData;
  402. {
  403. FWwiseEventCookedData Data1;
  404. Data1.Media.Emplace(FWwiseMediaCookedData{});
  405. Data1.SoundBanks.Emplace(FWwiseSoundBankCookedData{});
  406. FWwiseSwitchContainerLeafCookedData Leaf1;
  407. FWwiseMediaCookedData Leaf1Media;
  408. Leaf1Media.MediaId = 1;
  409. Leaf1.Media.Emplace(MoveTemp(Leaf1Media));
  410. Leaf1.GroupValueSet.Emplace(GroupValue);
  411. Data1.SwitchContainerLeaves.Emplace(MoveTemp(Leaf1));
  412. CookedData.EventLanguageMap.Emplace(FWwiseLanguageCookedData::Sfx, MoveTemp(Data1));
  413. }
  414. // Creating Node
  415. auto* Node = ResourceLoaderImpl.CreateEventNode(CookedData, nullptr);
  416. CHECK(Node);
  417. if (UNLIKELY(!Node))
  418. {
  419. break;
  420. }
  421. // Loading Node
  422. FWwiseLoadedEventPromise LoadPromise;
  423. auto LoadFuture = LoadPromise.GetFuture();
  424. ResourceLoaderImpl.LoadEventAsync(MoveTemp(LoadPromise), MoveTemp(Node));
  425. LoadedEvent = LoadFuture.Get(); // Synchronously
  426. CHECK(LoadedEvent);
  427. if (UNLIKELY(!LoadedEvent))
  428. {
  429. break;
  430. }
  431. }
  432. while (false);
  433. // Load GroupValue
  434. do
  435. {
  436. // Creating Node
  437. auto* Node = ResourceLoaderImpl.CreateGroupValueNode(GroupValue);
  438. CHECK(Node);
  439. if (UNLIKELY(!Node))
  440. {
  441. break;
  442. }
  443. // Loading Node
  444. FWwiseLoadedGroupValuePromise LoadPromise;
  445. auto LoadFuture = LoadPromise.GetFuture();
  446. ResourceLoaderImpl.LoadGroupValueAsync(MoveTemp(LoadPromise), MoveTemp(Node));
  447. LoadedGroupValue = LoadFuture.Get(); // Synchronously
  448. CHECK(LoadedGroupValue);
  449. if (UNLIKELY(!LoadedGroupValue))
  450. {
  451. break;
  452. }
  453. }
  454. while(false);
  455. // Unloading GroupValue
  456. if (LIKELY(LoadedGroupValue))
  457. {
  458. FWwiseResourceUnloadPromise UnloadPromise;
  459. auto UnloadFuture = UnloadPromise.GetFuture();
  460. ResourceLoaderImpl.UnloadGroupValueAsync(MoveTemp(UnloadPromise), MoveTemp(LoadedGroupValue));
  461. UnloadFuture.Get(); // Synchronously
  462. }
  463. // Unloading Event
  464. if (LIKELY(LoadedEvent))
  465. {
  466. FWwiseResourceUnloadPromise UnloadPromise;
  467. auto UnloadFuture = UnloadPromise.GetFuture();
  468. ResourceLoaderImpl.UnloadEventAsync(MoveTemp(UnloadPromise), MoveTemp(LoadedEvent));
  469. UnloadFuture.Get(); // Synchronously
  470. }
  471. CHECK(ExternalSourceManager.IsEmpty());
  472. CHECK(MediaManager.IsEmpty());
  473. CHECK(SoundBankManager.IsEmpty());
  474. CHECK(ResourceLoaderImpl.IsEmpty());
  475. CHECK(ResourceLoaderImpl.TrimGroupValueInfo());
  476. }
  477. SECTION("Sync SwitchContainer (Switch First)")
  478. {
  479. FWwiseMockExternalSourceManager ExternalSourceManager;
  480. FWwiseMockMediaManager MediaManager;
  481. FWwiseMockSoundBankManager SoundBankManager;
  482. FWwiseResourceLoaderImpl ResourceLoaderImpl(ExternalSourceManager, MediaManager, SoundBankManager);
  483. FWwiseGroupValueCookedData GroupValue;
  484. GroupValue.Id = 1;
  485. GroupValue.GroupId = 1;
  486. GroupValue.Type = EWwiseGroupType::Switch;
  487. FWwiseLoadedEventPtr LoadedEvent{nullptr};
  488. FWwiseLoadedGroupValuePtr LoadedGroupValue{nullptr};
  489. // Load GroupValue
  490. do
  491. {
  492. // Creating Node
  493. auto* Node = ResourceLoaderImpl.CreateGroupValueNode(GroupValue);
  494. CHECK(Node);
  495. if (UNLIKELY(!Node))
  496. {
  497. break;
  498. }
  499. // Loading Node
  500. FWwiseLoadedGroupValuePromise LoadPromise;
  501. auto LoadFuture = LoadPromise.GetFuture();
  502. ResourceLoaderImpl.LoadGroupValueAsync(MoveTemp(LoadPromise), MoveTemp(Node));
  503. LoadedGroupValue = LoadFuture.Get(); // Synchronously
  504. CHECK(LoadedGroupValue);
  505. if (UNLIKELY(!LoadedGroupValue))
  506. {
  507. break;
  508. }
  509. }
  510. while(false);
  511. // Load Event
  512. do
  513. {
  514. FWwiseLocalizedEventCookedData CookedData;
  515. {
  516. FWwiseEventCookedData Data1;
  517. Data1.Media.Emplace(FWwiseMediaCookedData{});
  518. Data1.SoundBanks.Emplace(FWwiseSoundBankCookedData{});
  519. FWwiseSwitchContainerLeafCookedData Leaf1;
  520. FWwiseMediaCookedData Leaf1Media;
  521. Leaf1Media.MediaId = 1;
  522. Leaf1.Media.Emplace(MoveTemp(Leaf1Media));
  523. Leaf1.GroupValueSet.Emplace(GroupValue);
  524. Data1.SwitchContainerLeaves.Emplace(MoveTemp(Leaf1));
  525. CookedData.EventLanguageMap.Emplace(FWwiseLanguageCookedData::Sfx, MoveTemp(Data1));
  526. }
  527. // Creating Node
  528. auto* Node = ResourceLoaderImpl.CreateEventNode(CookedData, nullptr);
  529. CHECK(Node);
  530. if (UNLIKELY(!Node))
  531. {
  532. break;
  533. }
  534. // Loading Node
  535. FWwiseLoadedEventPromise LoadPromise;
  536. auto LoadFuture = LoadPromise.GetFuture();
  537. ResourceLoaderImpl.LoadEventAsync(MoveTemp(LoadPromise), MoveTemp(Node));
  538. LoadedEvent = LoadFuture.Get(); // Synchronously
  539. CHECK(LoadedEvent);
  540. if (UNLIKELY(!LoadedEvent))
  541. {
  542. break;
  543. }
  544. }
  545. while (false);
  546. // Unloading Event
  547. if (LIKELY(LoadedEvent))
  548. {
  549. FWwiseResourceUnloadPromise UnloadPromise;
  550. auto UnloadFuture = UnloadPromise.GetFuture();
  551. ResourceLoaderImpl.UnloadEventAsync(MoveTemp(UnloadPromise), MoveTemp(LoadedEvent));
  552. UnloadFuture.Get(); // Synchronously
  553. }
  554. // Unloading GroupValue
  555. if (LIKELY(LoadedGroupValue))
  556. {
  557. FWwiseResourceUnloadPromise UnloadPromise;
  558. auto UnloadFuture = UnloadPromise.GetFuture();
  559. ResourceLoaderImpl.UnloadGroupValueAsync(MoveTemp(UnloadPromise), MoveTemp(LoadedGroupValue));
  560. UnloadFuture.Get(); // Synchronously
  561. }
  562. CHECK(ExternalSourceManager.IsEmpty());
  563. CHECK(MediaManager.IsEmpty());
  564. CHECK(SoundBankManager.IsEmpty());
  565. CHECK(ResourceLoaderImpl.IsEmpty());
  566. CHECK(ResourceLoaderImpl.TrimGroupValueInfo());
  567. }
  568. }
  569. WWISE_TEST_CASE(ResourceLoader_Async, "Wwise::ResourceLoader::ResourceLoader_Async", "[ApplicationContextMask][ProductFilter]")
  570. {
  571. // Keeping these in prime numbers so we get a higher set of possibilities
  572. static constexpr const auto GroupValueCount = 7;
  573. static constexpr const auto FileCount = 23;
  574. static constexpr const auto CookedDataCount = 53;
  575. static constexpr const auto NodeCount = 173;
  576. SECTION("Async AuxBus")
  577. {
  578. FWwiseMockExternalSourceManager ExternalSourceManager;
  579. FWwiseMockMediaManager MediaManager;
  580. FWwiseMockSoundBankManager SoundBankManager;
  581. FWwiseResourceLoaderImpl ResourceLoaderImpl(ExternalSourceManager, MediaManager, SoundBankManager);
  582. FWwiseLocalizedAuxBusCookedData CookedDatas[CookedDataCount];
  583. for (auto i = 0; i < CookedDataCount; ++i)
  584. {
  585. FWwiseAuxBusCookedData Data;
  586. Data.AuxBusId = i % CookedDataCount;
  587. Data.Media.Emplace(FWwiseMediaCookedData{});
  588. Data.Media[0].MediaId = i % FileCount;
  589. Data.SoundBanks.Emplace(FWwiseSoundBankCookedData{});
  590. CookedDatas[i].AuxBusLanguageMap.Emplace(FWwiseLanguageCookedData::Sfx, MoveTemp(Data));
  591. }
  592. FWwiseResourceUnloadFuture UnloadFutures[NodeCount];
  593. for (auto i = 0; i < NodeCount; ++i)
  594. {
  595. // Creating Node
  596. auto* Node = ResourceLoaderImpl.CreateAuxBusNode(CookedDatas[i%CookedDataCount], nullptr);
  597. CHECK(Node);
  598. if (UNLIKELY(!Node))
  599. {
  600. continue;
  601. }
  602. // Loading Node
  603. FWwiseLoadedAuxBusPromise LoadPromise;
  604. auto NodeFuture = LoadPromise.GetFuture();
  605. ResourceLoaderImpl.LoadAuxBusAsync(MoveTemp(LoadPromise), MoveTemp(Node));
  606. // Unloading Node
  607. FWwiseResourceUnloadPromise UnloadPromise;
  608. UnloadFutures[i] = UnloadPromise.GetFuture();
  609. NodeFuture.Next([&ResourceLoaderImpl, UnloadPromise = MoveTemp(UnloadPromise)](FWwiseLoadedAuxBusPtr LoadedNode) mutable
  610. {
  611. CHECK(LoadedNode);
  612. if (UNLIKELY(!LoadedNode))
  613. {
  614. UnloadPromise.EmplaceValue();
  615. return;
  616. }
  617. ResourceLoaderImpl.UnloadAuxBusAsync(MoveTemp(UnloadPromise), MoveTemp(LoadedNode));
  618. });
  619. }
  620. for (auto i = 0; i < NodeCount; ++i)
  621. {
  622. UnloadFutures[i].Get();
  623. }
  624. CHECK(ExternalSourceManager.IsEmpty());
  625. CHECK(MediaManager.IsEmpty());
  626. CHECK(SoundBankManager.IsEmpty());
  627. CHECK(ResourceLoaderImpl.IsEmpty());
  628. CHECK(ResourceLoaderImpl.TrimGroupValueInfo());
  629. }
  630. SECTION("Async Event & GroupValue")
  631. {
  632. FWwiseMockExternalSourceManager ExternalSourceManager;
  633. FWwiseMockMediaManager MediaManager;
  634. FWwiseMockSoundBankManager SoundBankManager;
  635. FWwiseResourceLoaderImpl ResourceLoaderImpl(ExternalSourceManager, MediaManager, SoundBankManager);
  636. FWwiseLocalizedEventCookedData EventCookedDatas[CookedDataCount];
  637. for (auto i = 0; i < CookedDataCount; ++i)
  638. {
  639. FWwiseEventCookedData Data;
  640. Data.EventId = i % CookedDataCount;
  641. Data.Media.Emplace(FWwiseMediaCookedData{});
  642. Data.Media[0].MediaId = i % FileCount;
  643. Data.SoundBanks.Emplace(FWwiseSoundBankCookedData{});
  644. FWwiseSwitchContainerLeafCookedData Leaf;
  645. FWwiseMediaCookedData LeafMedia;
  646. LeafMedia.MediaId = (i % FileCount) + 2; // Allow overlap while allow for uniques
  647. Leaf.Media.Emplace(MoveTemp(LeafMedia));
  648. FWwiseGroupValueCookedData LeafGroupValue;
  649. LeafGroupValue.Id = i % GroupValueCount;
  650. LeafGroupValue.GroupId = 1;
  651. LeafGroupValue.Type = EWwiseGroupType::Switch;
  652. Leaf.GroupValueSet.Emplace(MoveTemp(LeafGroupValue));
  653. Data.SwitchContainerLeaves.Emplace(MoveTemp(Leaf));
  654. EventCookedDatas[i].EventLanguageMap.Emplace(FWwiseLanguageCookedData::Sfx, MoveTemp(Data));
  655. }
  656. FWwiseGroupValueCookedData GroupValueCookedDatas[CookedDataCount];
  657. for (auto i = 0; i < CookedDataCount; ++i)
  658. {
  659. GroupValueCookedDatas[i].Id = GroupValueCount - (i % GroupValueCount) - 1; // Make them opposite
  660. GroupValueCookedDatas[i].GroupId = 1;
  661. GroupValueCookedDatas[i].Type = EWwiseGroupType::Switch;
  662. }
  663. constexpr const auto FuturesCount = NodeCount * 2;
  664. FWwiseResourceUnloadFuture UnloadFutures[FuturesCount];
  665. for (auto i = 0; i < NodeCount; ++i)
  666. {
  667. auto DoEvent = [&ResourceLoaderImpl, &EventCookedDatas, i, &UnloadFutures]() mutable
  668. {
  669. // Creating Node
  670. auto* Node = ResourceLoaderImpl.CreateEventNode(EventCookedDatas[i%CookedDataCount], nullptr);
  671. CHECK(Node);
  672. if (UNLIKELY(!Node))
  673. {
  674. return;
  675. }
  676. // Loading Node
  677. FWwiseLoadedEventPromise LoadPromise;
  678. auto NodeFuture = LoadPromise.GetFuture();
  679. ResourceLoaderImpl.LoadEventAsync(MoveTemp(LoadPromise), MoveTemp(Node));
  680. // Unloading Node
  681. FWwiseResourceUnloadPromise UnloadPromise;
  682. UnloadFutures[i] = UnloadPromise.GetFuture();
  683. NodeFuture.Next([&ResourceLoaderImpl, UnloadPromise = MoveTemp(UnloadPromise)](FWwiseLoadedEventPtr LoadedNode) mutable
  684. {
  685. CHECK(LoadedNode);
  686. if (UNLIKELY(!LoadedNode))
  687. {
  688. UnloadPromise.EmplaceValue();
  689. return;
  690. }
  691. ResourceLoaderImpl.UnloadEventAsync(MoveTemp(UnloadPromise), MoveTemp(LoadedNode));
  692. });
  693. };
  694. auto DoGroupValue = [&ResourceLoaderImpl, &GroupValueCookedDatas, i, &UnloadFutures]() mutable
  695. {
  696. // Creating Node
  697. auto* Node = ResourceLoaderImpl.CreateGroupValueNode(GroupValueCookedDatas[i%CookedDataCount]);
  698. CHECK(Node);
  699. if (UNLIKELY(!Node))
  700. {
  701. return;
  702. }
  703. // Loading Node
  704. FWwiseLoadedGroupValuePromise LoadPromise;
  705. auto NodeFuture = LoadPromise.GetFuture();
  706. ResourceLoaderImpl.LoadGroupValueAsync(MoveTemp(LoadPromise), MoveTemp(Node));
  707. // Unloading Node
  708. FWwiseResourceUnloadPromise UnloadPromise;
  709. UnloadFutures[NodeCount+i] = UnloadPromise.GetFuture();
  710. NodeFuture.Next([&ResourceLoaderImpl, UnloadPromise = MoveTemp(UnloadPromise)](FWwiseLoadedGroupValuePtr LoadedNode) mutable
  711. {
  712. CHECK(LoadedNode);
  713. if (UNLIKELY(!LoadedNode))
  714. {
  715. UnloadPromise.EmplaceValue();
  716. return;
  717. }
  718. ResourceLoaderImpl.UnloadGroupValueAsync(MoveTemp(UnloadPromise), MoveTemp(LoadedNode));
  719. });
  720. };
  721. // Vary which one is done first
  722. if (i & 4)
  723. {
  724. DoEvent();
  725. DoGroupValue();
  726. }
  727. else
  728. {
  729. DoGroupValue();
  730. DoEvent();
  731. }
  732. }
  733. for (auto i = 0; i < FuturesCount; ++i)
  734. {
  735. UnloadFutures[i].Get();
  736. }
  737. CHECK(ExternalSourceManager.IsEmpty());
  738. CHECK(MediaManager.IsEmpty());
  739. CHECK(SoundBankManager.IsEmpty());
  740. CHECK(ResourceLoaderImpl.IsEmpty());
  741. CHECK(ResourceLoaderImpl.TrimGroupValueInfo());
  742. }
  743. SECTION("Async External Source")
  744. {
  745. FWwiseMockExternalSourceManager ExternalSourceManager;
  746. FWwiseMockMediaManager MediaManager;
  747. FWwiseMockSoundBankManager SoundBankManager;
  748. FWwiseResourceLoaderImpl ResourceLoaderImpl(ExternalSourceManager, MediaManager, SoundBankManager);
  749. FWwiseExternalSourceCookedData CookedDatas[CookedDataCount];
  750. for (auto i = 0; i < CookedDataCount; ++i)
  751. {
  752. CookedDatas[i].Cookie = i % FileCount;
  753. }
  754. FWwiseResourceUnloadFuture UnloadFutures[NodeCount];
  755. for (auto i = 0; i < NodeCount; ++i)
  756. {
  757. auto* Node = ResourceLoaderImpl.CreateExternalSourceNode(CookedDatas[i%CookedDataCount]);
  758. CHECK(Node);
  759. if (UNLIKELY(!Node))
  760. {
  761. continue;
  762. }
  763. // Loading node
  764. FWwiseLoadedExternalSourcePromise LoadPromise;
  765. auto NodeFuture = LoadPromise.GetFuture();
  766. ResourceLoaderImpl.LoadExternalSourceAsync(MoveTemp(LoadPromise), MoveTemp(Node));
  767. // Unloading node
  768. FWwiseResourceUnloadPromise UnloadPromise;
  769. UnloadFutures[i] = UnloadPromise.GetFuture();
  770. NodeFuture.Next([&ResourceLoaderImpl, UnloadPromise = MoveTemp(UnloadPromise)](FWwiseLoadedExternalSourcePtr LoadedNode) mutable
  771. {
  772. CHECK(LoadedNode);
  773. if (UNLIKELY(!LoadedNode))
  774. {
  775. UnloadPromise.EmplaceValue();
  776. return;
  777. }
  778. ResourceLoaderImpl.UnloadExternalSourceAsync(MoveTemp(UnloadPromise), MoveTemp(LoadedNode));
  779. });
  780. }
  781. for (auto i = 0; i < NodeCount; ++i)
  782. {
  783. UnloadFutures[i].Get();
  784. }
  785. CHECK(ExternalSourceManager.IsEmpty());
  786. CHECK(MediaManager.IsEmpty());
  787. CHECK(SoundBankManager.IsEmpty());
  788. CHECK(ResourceLoaderImpl.IsEmpty());
  789. CHECK(ResourceLoaderImpl.TrimGroupValueInfo());
  790. }
  791. SECTION("Async InitBank")
  792. {
  793. FWwiseMockExternalSourceManager ExternalSourceManager;
  794. FWwiseMockMediaManager MediaManager;
  795. FWwiseMockSoundBankManager SoundBankManager;
  796. FWwiseResourceLoaderImpl ResourceLoaderImpl(ExternalSourceManager, MediaManager, SoundBankManager);
  797. FWwiseInitBankCookedData CookedDatas[CookedDataCount];
  798. for (auto i = 0; i < CookedDataCount; ++i)
  799. {
  800. CookedDatas[i].Media.Emplace(FWwiseMediaCookedData{});
  801. CookedDatas[i].Media[0].MediaId = i % FileCount;
  802. }
  803. FWwiseResourceUnloadFuture UnloadFutures[NodeCount];
  804. for (auto i = 0; i < NodeCount; ++i)
  805. {
  806. // Creating Node
  807. auto* Node = ResourceLoaderImpl.CreateInitBankNode(CookedDatas[i%CookedDataCount]);
  808. CHECK(Node);
  809. if (UNLIKELY(!Node))
  810. {
  811. continue;
  812. }
  813. // Loading Node
  814. FWwiseLoadedInitBankPromise LoadPromise;
  815. auto NodeFuture = LoadPromise.GetFuture();
  816. ResourceLoaderImpl.LoadInitBankAsync(MoveTemp(LoadPromise), MoveTemp(Node));
  817. // Unloading Node
  818. FWwiseResourceUnloadPromise UnloadPromise;
  819. UnloadFutures[i] = UnloadPromise.GetFuture();
  820. NodeFuture.Next([&ResourceLoaderImpl, UnloadPromise = MoveTemp(UnloadPromise)](FWwiseLoadedInitBankPtr LoadedNode) mutable
  821. {
  822. CHECK(LoadedNode);
  823. if (UNLIKELY(!LoadedNode))
  824. {
  825. UnloadPromise.EmplaceValue();
  826. return;
  827. }
  828. ResourceLoaderImpl.UnloadInitBankAsync(MoveTemp(UnloadPromise), MoveTemp(LoadedNode));
  829. });
  830. }
  831. for (auto i = 0; i < NodeCount; ++i)
  832. {
  833. UnloadFutures[i].Get();
  834. }
  835. CHECK(ExternalSourceManager.IsEmpty());
  836. CHECK(MediaManager.IsEmpty());
  837. CHECK(SoundBankManager.IsEmpty());
  838. CHECK(ResourceLoaderImpl.IsEmpty());
  839. CHECK(ResourceLoaderImpl.TrimGroupValueInfo());
  840. }
  841. SECTION("Async Media")
  842. {
  843. FWwiseMockExternalSourceManager ExternalSourceManager;
  844. FWwiseMockMediaManager MediaManager;
  845. FWwiseMockSoundBankManager SoundBankManager;
  846. FWwiseResourceLoaderImpl ResourceLoaderImpl(ExternalSourceManager, MediaManager, SoundBankManager);
  847. FWwiseMediaCookedData CookedDatas[CookedDataCount];
  848. for (auto i = 0; i < CookedDataCount; ++i)
  849. {
  850. CookedDatas[i].MediaId = i % FileCount;
  851. CookedDatas[i].bStreaming = !!(i % 2);
  852. }
  853. FWwiseResourceUnloadFuture UnloadFutures[NodeCount];
  854. for (auto i = 0; i < NodeCount; ++i)
  855. {
  856. // Creating Node
  857. auto* Node = ResourceLoaderImpl.CreateMediaNode(CookedDatas[i%CookedDataCount]);
  858. CHECK(Node);
  859. if (UNLIKELY(!Node))
  860. {
  861. continue;
  862. }
  863. // Loading Node
  864. FWwiseLoadedMediaPromise LoadPromise;
  865. auto NodeFuture = LoadPromise.GetFuture();
  866. ResourceLoaderImpl.LoadMediaAsync(MoveTemp(LoadPromise), MoveTemp(Node));
  867. // Unloading Node
  868. FWwiseResourceUnloadPromise UnloadPromise;
  869. UnloadFutures[i] = UnloadPromise.GetFuture();
  870. NodeFuture.Next([&ResourceLoaderImpl, UnloadPromise = MoveTemp(UnloadPromise)](FWwiseLoadedMediaPtr LoadedNode) mutable
  871. {
  872. CHECK(LoadedNode);
  873. if (UNLIKELY(!LoadedNode))
  874. {
  875. UnloadPromise.EmplaceValue();
  876. return;
  877. }
  878. ResourceLoaderImpl.UnloadMediaAsync(MoveTemp(UnloadPromise), MoveTemp(LoadedNode));
  879. });
  880. }
  881. for (auto i = 0; i < NodeCount; ++i)
  882. {
  883. UnloadFutures[i].Get();
  884. }
  885. CHECK(ExternalSourceManager.IsEmpty());
  886. CHECK(MediaManager.IsEmpty());
  887. CHECK(SoundBankManager.IsEmpty());
  888. CHECK(ResourceLoaderImpl.IsEmpty());
  889. CHECK(ResourceLoaderImpl.TrimGroupValueInfo());
  890. }
  891. SECTION("Async ShareSet")
  892. {
  893. FWwiseMockExternalSourceManager ExternalSourceManager;
  894. FWwiseMockMediaManager MediaManager;
  895. FWwiseMockSoundBankManager SoundBankManager;
  896. FWwiseResourceLoaderImpl ResourceLoaderImpl(ExternalSourceManager, MediaManager, SoundBankManager);
  897. FWwiseLocalizedShareSetCookedData CookedDatas[CookedDataCount];
  898. for (auto i = 0; i < CookedDataCount; ++i)
  899. {
  900. FWwiseShareSetCookedData Data;
  901. Data.ShareSetId = i % CookedDataCount;
  902. Data.Media.Emplace(FWwiseMediaCookedData{});
  903. Data.Media[0].MediaId = i % FileCount;
  904. Data.SoundBanks.Emplace(FWwiseSoundBankCookedData{});
  905. CookedDatas[i].ShareSetLanguageMap.Emplace(FWwiseLanguageCookedData::Sfx, MoveTemp(Data));
  906. }
  907. FWwiseResourceUnloadFuture UnloadFutures[NodeCount];
  908. for (auto i = 0; i < NodeCount; ++i)
  909. {
  910. // Creating Node
  911. auto* Node = ResourceLoaderImpl.CreateShareSetNode(CookedDatas[i%CookedDataCount], &FWwiseLanguageCookedData::Sfx);
  912. CHECK(Node);
  913. if (UNLIKELY(!Node))
  914. {
  915. continue;
  916. }
  917. // Loading Node
  918. FWwiseLoadedShareSetPromise LoadPromise;
  919. auto NodeFuture = LoadPromise.GetFuture();
  920. ResourceLoaderImpl.LoadShareSetAsync(MoveTemp(LoadPromise), MoveTemp(Node));
  921. // Unloading Node
  922. FWwiseResourceUnloadPromise UnloadPromise;
  923. UnloadFutures[i] = UnloadPromise.GetFuture();
  924. NodeFuture.Next([&ResourceLoaderImpl, UnloadPromise = MoveTemp(UnloadPromise)](FWwiseLoadedShareSetPtr LoadedNode) mutable
  925. {
  926. CHECK(LoadedNode);
  927. if (UNLIKELY(!LoadedNode))
  928. {
  929. UnloadPromise.EmplaceValue();
  930. return;
  931. }
  932. ResourceLoaderImpl.UnloadShareSetAsync(MoveTemp(UnloadPromise), MoveTemp(LoadedNode));
  933. });
  934. }
  935. for (auto i = 0; i < NodeCount; ++i)
  936. {
  937. UnloadFutures[i].Get();
  938. }
  939. CHECK(ExternalSourceManager.IsEmpty());
  940. CHECK(MediaManager.IsEmpty());
  941. CHECK(SoundBankManager.IsEmpty());
  942. CHECK(ResourceLoaderImpl.IsEmpty());
  943. CHECK(ResourceLoaderImpl.TrimGroupValueInfo());
  944. }
  945. SECTION("Async SoundBank")
  946. {
  947. FWwiseMockExternalSourceManager ExternalSourceManager;
  948. FWwiseMockMediaManager MediaManager;
  949. FWwiseMockSoundBankManager SoundBankManager;
  950. FWwiseResourceLoaderImpl ResourceLoaderImpl(ExternalSourceManager, MediaManager, SoundBankManager);
  951. FWwiseLocalizedSoundBankCookedData CookedDatas[CookedDataCount];
  952. for (auto i = 0; i < CookedDataCount; ++i)
  953. {
  954. FWwiseSoundBankCookedData Data;
  955. Data.SoundBankId = i % FileCount;
  956. CookedDatas[i].SoundBankLanguageMap.Emplace(FWwiseLanguageCookedData::Sfx, MoveTemp(Data));
  957. }
  958. FWwiseResourceUnloadFuture UnloadFutures[NodeCount];
  959. for (auto i = 0; i < NodeCount; ++i)
  960. {
  961. // Creating Node
  962. auto* Node = ResourceLoaderImpl.CreateSoundBankNode(CookedDatas[i%CookedDataCount], nullptr);
  963. CHECK(Node);
  964. if (UNLIKELY(!Node))
  965. {
  966. continue;
  967. }
  968. // Loading Node
  969. FWwiseLoadedSoundBankPromise LoadPromise;
  970. auto NodeFuture = LoadPromise.GetFuture();
  971. ResourceLoaderImpl.LoadSoundBankAsync(MoveTemp(LoadPromise), MoveTemp(Node));
  972. // Unloading Node
  973. FWwiseResourceUnloadPromise UnloadPromise;
  974. UnloadFutures[i] = UnloadPromise.GetFuture();
  975. NodeFuture.Next([&ResourceLoaderImpl, UnloadPromise = MoveTemp(UnloadPromise)](FWwiseLoadedSoundBankPtr LoadedNode) mutable
  976. {
  977. CHECK(LoadedNode);
  978. if (UNLIKELY(!LoadedNode))
  979. {
  980. UnloadPromise.EmplaceValue();
  981. return;
  982. }
  983. ResourceLoaderImpl.UnloadSoundBankAsync(MoveTemp(UnloadPromise), MoveTemp(LoadedNode));
  984. });
  985. }
  986. for (auto i = 0; i < NodeCount; ++i)
  987. {
  988. UnloadFutures[i].Get();
  989. }
  990. CHECK(ExternalSourceManager.IsEmpty());
  991. CHECK(MediaManager.IsEmpty());
  992. CHECK(SoundBankManager.IsEmpty());
  993. CHECK(ResourceLoaderImpl.IsEmpty());
  994. CHECK(ResourceLoaderImpl.TrimGroupValueInfo());
  995. }
  996. }
  997. WWISE_TEST_CASE(ResourceLoader_EdgeCases, "Wwise::ResourceLoader::ResourceLoader_EdgeCases", "[ApplicationContextMask][ProductFilter]")
  998. {
  999. SECTION("GroupValue PendingKill Reload")
  1000. {
  1001. static constexpr const auto Count = 16;
  1002. const bool bMockSleepOnMediaLoad = FWwiseResourceLoaderImpl::Test::bMockSleepOnMediaLoad;
  1003. FWwiseResourceLoaderImpl::Test::bMockSleepOnMediaLoad = true;
  1004. ON_SCOPE_EXIT { FWwiseResourceLoaderImpl::Test::bMockSleepOnMediaLoad = bMockSleepOnMediaLoad; };
  1005. FWwiseMockExternalSourceManager ExternalSourceManager;
  1006. FWwiseMockMediaManager MediaManager;
  1007. FWwiseMockSoundBankManager SoundBankManager;
  1008. FWwiseResourceLoaderImpl ResourceLoaderImpl(ExternalSourceManager, MediaManager, SoundBankManager);
  1009. FWwiseLocalizedEventCookedData EventCookedDatas[Count];
  1010. FWwiseGroupValueCookedData GroupValueCookedDatas[Count];
  1011. for (auto i = 0; i < Count; ++i)
  1012. {
  1013. // Event
  1014. FWwiseEventCookedData Data;
  1015. Data.EventId = i;
  1016. Data.Media.Emplace(FWwiseMediaCookedData{});
  1017. Data.Media[0].MediaId = i + Count;
  1018. FWwiseSwitchContainerLeafCookedData Leaf;
  1019. FWwiseMediaCookedData LeafMedia;
  1020. LeafMedia.MediaId = i;
  1021. Leaf.Media.Emplace(MoveTemp(LeafMedia));
  1022. FWwiseGroupValueCookedData LeafGroupValue;
  1023. LeafGroupValue.Id = i;
  1024. LeafGroupValue.GroupId = 1;
  1025. LeafGroupValue.Type = EWwiseGroupType::Switch;
  1026. Leaf.GroupValueSet.Emplace(MoveTemp(LeafGroupValue));
  1027. Data.SwitchContainerLeaves.Emplace(MoveTemp(Leaf));
  1028. EventCookedDatas[i].EventLanguageMap.Emplace(FWwiseLanguageCookedData::Sfx, MoveTemp(Data));
  1029. // GroupValue
  1030. GroupValueCookedDatas[i].Id = i;
  1031. GroupValueCookedDatas[i].GroupId = 1;
  1032. GroupValueCookedDatas[i].Type = EWwiseGroupType::Switch;
  1033. }
  1034. constexpr const auto FuturesCount = Count * 2;
  1035. FWwiseLoadedEventFuture LoadFutures[Count];
  1036. FWwiseResourceUnloadFuture UnloadFutures[FuturesCount];
  1037. for (auto i = 0; i < Count; ++i)
  1038. {
  1039. auto DoEvent = [&LoadFutures, &ResourceLoaderImpl, &EventCookedDatas, i]() mutable
  1040. {
  1041. // Creating Node
  1042. auto* Node = ResourceLoaderImpl.CreateEventNode(EventCookedDatas[i%Count], nullptr);
  1043. CHECK(Node);
  1044. if (UNLIKELY(!Node))
  1045. {
  1046. return;
  1047. }
  1048. // Loading Node 1
  1049. FWwiseLoadedEventPromise LoadPromise;
  1050. LoadFutures[i] = LoadPromise.GetFuture();
  1051. ResourceLoaderImpl.LoadEventAsync(MoveTemp(LoadPromise), MoveTemp(Node));
  1052. LoadFutures[i].Wait();
  1053. };
  1054. auto UnloadEvent = [i, &ResourceLoaderImpl, &LoadFutures, &UnloadFutures]() mutable
  1055. {
  1056. // Unloading Event
  1057. FWwiseResourceUnloadPromise UnloadPromise;
  1058. UnloadFutures[i] = UnloadPromise.GetFuture();
  1059. ResourceLoaderImpl.UnloadEventAsync(MoveTemp(UnloadPromise), LoadFutures[i].Get());
  1060. };
  1061. auto DoGroupValue = [&ResourceLoaderImpl, &GroupValueCookedDatas, i, &UnloadFutures]() mutable
  1062. {
  1063. // Creating Node
  1064. auto* Node = ResourceLoaderImpl.CreateGroupValueNode(GroupValueCookedDatas[i%Count]);
  1065. CHECK(Node);
  1066. if (UNLIKELY(!Node))
  1067. {
  1068. return;
  1069. }
  1070. // Loading Node 1
  1071. FWwiseLoadedGroupValuePromise LoadPromise;
  1072. auto NodeFuture = LoadPromise.GetFuture();
  1073. ResourceLoaderImpl.LoadGroupValueAsync(MoveTemp(LoadPromise), MoveTemp(Node));
  1074. // Future for completion (Unloading Node 2)
  1075. FWwiseResourceUnloadPromise UnloadPromise2;
  1076. UnloadFutures[Count+i] = UnloadPromise2.GetFuture();
  1077. NodeFuture.Next([i, &GroupValueCookedDatas, &ResourceLoaderImpl, UnloadPromise2 = MoveTemp(UnloadPromise2)](FWwiseLoadedGroupValuePtr LoadedNode) mutable
  1078. {
  1079. CHECK(LoadedNode);
  1080. if (UNLIKELY(!LoadedNode))
  1081. {
  1082. UnloadPromise2.EmplaceValue();
  1083. return;
  1084. }
  1085. // Loading Node 2
  1086. auto* Node = ResourceLoaderImpl.CreateGroupValueNode(GroupValueCookedDatas[i%Count]);
  1087. FWwiseLoadedGroupValuePromise LoadPromise2;
  1088. auto NodeFuture2 = LoadPromise2.GetFuture();
  1089. if (i&8)
  1090. {
  1091. ResourceLoaderImpl.LoadGroupValueAsync(MoveTemp(LoadPromise2), MoveTemp(Node));
  1092. }
  1093. // Unload Node 1
  1094. FWwiseResourceUnloadPromise UnloadPromise;
  1095. auto UnloadFuture = UnloadPromise.GetFuture();
  1096. ResourceLoaderImpl.UnloadGroupValueAsync(MoveTemp(UnloadPromise), MoveTemp(LoadedNode));
  1097. if (!(i&8))
  1098. {
  1099. ResourceLoaderImpl.LoadGroupValueAsync(MoveTemp(LoadPromise2), MoveTemp(Node));
  1100. }
  1101. // Wait for Loading Node 2
  1102. NodeFuture2.Next([&ResourceLoaderImpl, UnloadFuture = MoveTemp(UnloadFuture), UnloadPromise2 = MoveTemp(UnloadPromise2)](FWwiseLoadedGroupValuePtr LoadedNode) mutable
  1103. {
  1104. CHECK(LoadedNode);
  1105. if (UNLIKELY(!LoadedNode))
  1106. {
  1107. UnloadPromise2.EmplaceValue();
  1108. return;
  1109. }
  1110. // Wait for Unloading Node 1
  1111. UnloadFuture.Next([&ResourceLoaderImpl, UnloadPromise2 = MoveTemp(UnloadPromise2), LoadedNode](int) mutable
  1112. {
  1113. // Unloading Node 2 and terminate
  1114. ResourceLoaderImpl.UnloadGroupValueAsync(MoveTemp(UnloadPromise2), MoveTemp(LoadedNode));
  1115. });
  1116. });
  1117. });
  1118. };
  1119. DoEvent();
  1120. DoGroupValue();
  1121. UnloadEvent();
  1122. }
  1123. for (auto i = 0; i < FuturesCount; ++i)
  1124. {
  1125. UnloadFutures[i].Get();
  1126. }
  1127. CHECK(ExternalSourceManager.IsEmpty());
  1128. CHECK(MediaManager.IsEmpty());
  1129. CHECK(SoundBankManager.IsEmpty());
  1130. CHECK(ResourceLoaderImpl.IsEmpty());
  1131. CHECK(ResourceLoaderImpl.TrimGroupValueInfo());
  1132. }
  1133. SECTION("Event PendingKill Reload")
  1134. {
  1135. static constexpr const auto Count = 16;
  1136. const bool bMockSleepOnMediaLoad = FWwiseResourceLoaderImpl::Test::bMockSleepOnMediaLoad;
  1137. FWwiseResourceLoaderImpl::Test::bMockSleepOnMediaLoad = true;
  1138. ON_SCOPE_EXIT { FWwiseResourceLoaderImpl::Test::bMockSleepOnMediaLoad = bMockSleepOnMediaLoad; };
  1139. FWwiseMockExternalSourceManager ExternalSourceManager;
  1140. FWwiseMockMediaManager MediaManager;
  1141. FWwiseMockSoundBankManager SoundBankManager;
  1142. FWwiseResourceLoaderImpl ResourceLoaderImpl(ExternalSourceManager, MediaManager, SoundBankManager);
  1143. FWwiseLocalizedEventCookedData EventCookedDatas[Count];
  1144. FWwiseGroupValueCookedData GroupValueCookedDatas[Count];
  1145. for (auto i = 0; i < Count; ++i)
  1146. {
  1147. // Event
  1148. FWwiseEventCookedData Data;
  1149. Data.EventId = i;
  1150. Data.Media.Emplace(FWwiseMediaCookedData{});
  1151. Data.Media[0].MediaId = i + Count;
  1152. FWwiseSwitchContainerLeafCookedData Leaf;
  1153. FWwiseMediaCookedData LeafMedia;
  1154. LeafMedia.MediaId = i;
  1155. Leaf.Media.Emplace(MoveTemp(LeafMedia));
  1156. FWwiseGroupValueCookedData LeafGroupValue;
  1157. LeafGroupValue.Id = i;
  1158. LeafGroupValue.GroupId = 1;
  1159. LeafGroupValue.Type = EWwiseGroupType::Switch;
  1160. Leaf.GroupValueSet.Emplace(MoveTemp(LeafGroupValue));
  1161. Data.SwitchContainerLeaves.Emplace(MoveTemp(Leaf));
  1162. EventCookedDatas[i].EventLanguageMap.Emplace(FWwiseLanguageCookedData::Sfx, MoveTemp(Data));
  1163. // GroupValue
  1164. GroupValueCookedDatas[i].Id = i;
  1165. GroupValueCookedDatas[i].GroupId = 1;
  1166. GroupValueCookedDatas[i].Type = EWwiseGroupType::Switch;
  1167. }
  1168. constexpr const auto FuturesCount = Count * 2;
  1169. FWwiseLoadedGroupValueFuture LoadFutures[Count];
  1170. FWwiseResourceUnloadFuture UnloadFutures[FuturesCount];
  1171. for (auto i = 0; i < Count; ++i)
  1172. {
  1173. auto DoEvent = [&ResourceLoaderImpl, &EventCookedDatas, i, &UnloadFutures]() mutable
  1174. {
  1175. // Creating Node
  1176. auto* Node = ResourceLoaderImpl.CreateEventNode(EventCookedDatas[i%Count], nullptr);
  1177. CHECK(Node);
  1178. if (UNLIKELY(!Node))
  1179. {
  1180. return;
  1181. }
  1182. // Loading Node 1
  1183. FWwiseLoadedEventPromise LoadPromise;
  1184. auto NodeFuture = LoadPromise.GetFuture();
  1185. ResourceLoaderImpl.LoadEventAsync(MoveTemp(LoadPromise), MoveTemp(Node));
  1186. // Future for completion (Unloading Node 2)
  1187. FWwiseResourceUnloadPromise UnloadPromise2;
  1188. UnloadFutures[i] = UnloadPromise2.GetFuture();
  1189. NodeFuture.Next([i, &EventCookedDatas, &ResourceLoaderImpl, UnloadPromise2 = MoveTemp(UnloadPromise2)](FWwiseLoadedEventPtr LoadedNode) mutable
  1190. {
  1191. CHECK(LoadedNode);
  1192. if (UNLIKELY(!LoadedNode))
  1193. {
  1194. UnloadPromise2.EmplaceValue();
  1195. return;
  1196. }
  1197. // Creating Node 2
  1198. auto* Node2 = ResourceLoaderImpl.CreateEventNode(EventCookedDatas[i%Count], nullptr);
  1199. // Loading Node 2
  1200. FWwiseLoadedEventPromise LoadPromise2;
  1201. auto NodeFuture2 = LoadPromise2.GetFuture();
  1202. if (i&4)
  1203. {
  1204. ResourceLoaderImpl.LoadEventAsync(MoveTemp(LoadPromise2), MoveTemp(Node2));
  1205. }
  1206. // Unloading Node 1
  1207. FWwiseResourceUnloadPromise UnloadPromise;
  1208. auto UnloadFuture = UnloadPromise.GetFuture();
  1209. ResourceLoaderImpl.UnloadEventAsync(MoveTemp(UnloadPromise), MoveTemp(LoadedNode));
  1210. if (!(i&4))
  1211. {
  1212. ResourceLoaderImpl.LoadEventAsync(MoveTemp(LoadPromise2), MoveTemp(Node2));
  1213. }
  1214. // Wait for Loading Node 2
  1215. NodeFuture2.Next([&ResourceLoaderImpl, UnloadFuture = MoveTemp(UnloadFuture), UnloadPromise2 = MoveTemp(UnloadPromise2)](FWwiseLoadedEventPtr LoadedNode) mutable
  1216. {
  1217. CHECK(LoadedNode);
  1218. if (UNLIKELY(!LoadedNode))
  1219. {
  1220. UnloadPromise2.EmplaceValue();
  1221. return;
  1222. }
  1223. // Wait for Unloading Node 1
  1224. UnloadFuture.Next([&ResourceLoaderImpl, UnloadPromise2 = MoveTemp(UnloadPromise2), LoadedNode](int) mutable
  1225. {
  1226. // Unloading Node 2 and terminate
  1227. ResourceLoaderImpl.UnloadEventAsync(MoveTemp(UnloadPromise2), MoveTemp(LoadedNode));
  1228. });
  1229. });
  1230. });
  1231. };
  1232. auto DoGroupValue = [&LoadFutures, &ResourceLoaderImpl, &GroupValueCookedDatas, i]() mutable
  1233. {
  1234. // Creating Node
  1235. auto* Node = ResourceLoaderImpl.CreateGroupValueNode(GroupValueCookedDatas[i%Count]);
  1236. CHECK(Node);
  1237. if (UNLIKELY(!Node))
  1238. {
  1239. return;
  1240. }
  1241. // Loading Node 1
  1242. FWwiseLoadedGroupValuePromise LoadPromise;
  1243. LoadFutures[i] = LoadPromise.GetFuture();
  1244. ResourceLoaderImpl.LoadGroupValueAsync(MoveTemp(LoadPromise), MoveTemp(Node));
  1245. LoadFutures[i].Wait();
  1246. };
  1247. auto UnloadGroupValue = [&LoadFutures, &ResourceLoaderImpl, i, &UnloadFutures]() mutable
  1248. {
  1249. // Future for completion (Unloading Node 2)
  1250. FWwiseResourceUnloadPromise UnloadPromise2;
  1251. UnloadFutures[Count+i] = UnloadPromise2.GetFuture();
  1252. ResourceLoaderImpl.UnloadGroupValueAsync(MoveTemp(UnloadPromise2), LoadFutures[i].Get());
  1253. };
  1254. DoEvent();
  1255. DoGroupValue();
  1256. UnloadGroupValue();
  1257. }
  1258. for (auto i = 0; i < FuturesCount; ++i)
  1259. {
  1260. UnloadFutures[i].Get();
  1261. }
  1262. CHECK(ExternalSourceManager.IsEmpty());
  1263. CHECK(MediaManager.IsEmpty());
  1264. CHECK(SoundBankManager.IsEmpty());
  1265. CHECK(ResourceLoaderImpl.IsEmpty());
  1266. CHECK(ResourceLoaderImpl.TrimGroupValueInfo());
  1267. }
  1268. }
  1269. WWISE_TEST_CASE(ResourceLoader_Stress, "Wwise::ResourceLoader::ResourceLoader_Stress", "[ApplicationContextMask][StressFilter]")
  1270. {
  1271. SECTION("Random All")
  1272. {
  1273. static constexpr const auto NumOp = 10000;
  1274. static constexpr const uint32 NumAuxBusses = 31;
  1275. static constexpr const uint32 NumEvents = 500;
  1276. static constexpr const uint32 NumExternalSources = 16;
  1277. static constexpr const uint32 NumInitBanks = 10;
  1278. static constexpr const uint32 NumMedia = 2000;
  1279. static constexpr const uint32 NumShareSets = 15;
  1280. static constexpr const uint32 NumSoundBanks = 200;
  1281. static constexpr const uint32 NumStates = 17;
  1282. static constexpr const uint32 NumSwitches = 14;
  1283. static constexpr const uint32 MaxLeaves = 10;
  1284. auto AuxBussesPtr = std::make_unique<std::array<FWwiseLocalizedAuxBusCookedData, NumAuxBusses>>();
  1285. auto EventsPtr = std::make_unique<std::array<FWwiseLocalizedEventCookedData, NumEvents>>();
  1286. auto ExternalSourcePtr = std::make_unique<std::array<FWwiseExternalSourceCookedData, NumExternalSources>>();
  1287. auto InitBanksPtr = std::make_unique<std::array<FWwiseInitBankCookedData, NumInitBanks>>();
  1288. auto MediaPtr = std::make_unique<std::array<FWwiseMediaCookedData, NumMedia>>();
  1289. auto ShareSetsPtr = std::make_unique<std::array<FWwiseLocalizedShareSetCookedData, NumShareSets>>();
  1290. auto SoundBanksPtr = std::make_unique<std::array<FWwiseLocalizedSoundBankCookedData, NumSoundBanks>>();
  1291. auto StatesPtr = std::make_unique<std::array<FWwiseGroupValueCookedData, NumStates>>();
  1292. auto SwitchesPtr = std::make_unique<std::array<FWwiseGroupValueCookedData, NumSwitches>>();
  1293. auto& AuxBusses = *AuxBussesPtr;
  1294. auto& Events = *EventsPtr;
  1295. auto& ExternalSources = *ExternalSourcePtr;
  1296. auto& InitBanks = *InitBanksPtr;
  1297. auto& Media = *MediaPtr;
  1298. auto& ShareSets = *ShareSetsPtr;
  1299. auto& SoundBanks = *SoundBanksPtr;
  1300. auto& States = *StatesPtr;
  1301. auto& Switches = *SwitchesPtr;
  1302. // Fill up data
  1303. {
  1304. int32 Id = 0;
  1305. for (auto& Medii : Media)
  1306. {
  1307. const auto Rnd = WwiseHashCombineFast(GetTypeHash(Id), 54209201);
  1308. Medii.MediaId = ++Id;
  1309. Medii.bStreaming = (Rnd % 4) == 0;
  1310. }
  1311. for (auto& SoundBank : SoundBanks)
  1312. {
  1313. FWwiseSoundBankCookedData Data;
  1314. Data.SoundBankId = ++Id;
  1315. SoundBank.SoundBankLanguageMap.Add(FWwiseLanguageCookedData::Sfx, MoveTemp(Data));
  1316. }
  1317. for (auto& ShareSet : ShareSets)
  1318. {
  1319. FWwiseShareSetCookedData Data;
  1320. Data.ShareSetId = ++Id;
  1321. auto RequiredMediaCount = WwiseHashCombineFast(GetTypeHash(Id), 139) % (MaxLeaves*2);
  1322. if (RequiredMediaCount > MaxLeaves) RequiredMediaCount = 0;
  1323. auto RequiredSoundBankCount = WwiseHashCombineFast(GetTypeHash(Id),295) % (MaxLeaves*3);
  1324. if (RequiredSoundBankCount > MaxLeaves) RequiredSoundBankCount = 0;
  1325. for (uint32 i=0; i < RequiredMediaCount; ++i)
  1326. {
  1327. const auto MediaToAdd = WwiseHashCombineFast(GetTypeHash(Id), i ^ 9042) % NumMedia;
  1328. Data.Media.Add(Media[MediaToAdd]);
  1329. }
  1330. for (uint32 i=0; i < RequiredSoundBankCount; ++i)
  1331. {
  1332. const auto SoundBankToAdd = WwiseHashCombineFast(GetTypeHash(Id), i ^ 5930) % NumSoundBanks;
  1333. Data.SoundBanks.Add(SoundBanks[SoundBankToAdd].SoundBankLanguageMap[FWwiseLanguageCookedData::Sfx]);
  1334. }
  1335. ShareSet.ShareSetLanguageMap.Add(FWwiseLanguageCookedData::Sfx, MoveTemp(Data));
  1336. }
  1337. for (auto& State : States)
  1338. {
  1339. State.GroupId = 0;
  1340. State.Id = ++Id;
  1341. State.Type = EWwiseGroupType::State;
  1342. }
  1343. for (auto& Switch : Switches)
  1344. {
  1345. Switch.GroupId = 0;
  1346. Switch.Id = ++Id;
  1347. Switch.Type = EWwiseGroupType::Switch;
  1348. }
  1349. for (auto& AuxBus : AuxBusses)
  1350. {
  1351. FWwiseAuxBusCookedData Data;
  1352. Data.AuxBusId = ++Id;
  1353. auto RequiredMediaCount = WwiseHashCombineFast(GetTypeHash(Id), 57381) % (MaxLeaves*2);
  1354. if (RequiredMediaCount > MaxLeaves) RequiredMediaCount = 0;
  1355. auto RequiredSoundBankCount = WwiseHashCombineFast(GetTypeHash(Id), 414) % (MaxLeaves*3);
  1356. if (RequiredSoundBankCount > MaxLeaves) RequiredSoundBankCount = 0;
  1357. for (uint32 i=0; i < RequiredMediaCount; ++i)
  1358. {
  1359. const auto MediaToAdd = WwiseHashCombineFast(GetTypeHash(Id), i ^ 9385938) % NumMedia;
  1360. Data.Media.Add(Media[MediaToAdd]);
  1361. }
  1362. for (uint32 i=0; i < RequiredSoundBankCount; ++i)
  1363. {
  1364. const auto SoundBankToAdd = WwiseHashCombineFast(GetTypeHash(Id), i ^ 223982) % NumSoundBanks;
  1365. Data.SoundBanks.Add(SoundBanks[SoundBankToAdd].SoundBankLanguageMap[FWwiseLanguageCookedData::Sfx]);
  1366. }
  1367. AuxBus.AuxBusLanguageMap.Add(FWwiseLanguageCookedData::Sfx, MoveTemp(Data));
  1368. }
  1369. for (auto& InitBank : InitBanks)
  1370. {
  1371. InitBank.SoundBankId = ++Id;
  1372. auto RequiredMediaCount = WwiseHashCombineFast(GetTypeHash(Id), 1758317) % (MaxLeaves*2);
  1373. if (RequiredMediaCount > MaxLeaves) RequiredMediaCount = 0;
  1374. for (uint32 i=0; i < RequiredMediaCount; ++i)
  1375. {
  1376. const auto MediaToAdd = WwiseHashCombineFast(GetTypeHash(Id), i ^ 190469) % NumMedia;
  1377. InitBank.Media.Add(Media[MediaToAdd]);
  1378. }
  1379. }
  1380. for (auto& Event : Events)
  1381. {
  1382. FWwiseEventCookedData Data;
  1383. Data.EventId = ++Id;
  1384. auto RequiredMediaCount = WwiseHashCombineFast(GetTypeHash(Id), 57381) % (MaxLeaves*2);
  1385. if (RequiredMediaCount > MaxLeaves) RequiredMediaCount = 0;
  1386. auto RequiredSoundBankCount = WwiseHashCombineFast(GetTypeHash(Id), 414) % (MaxLeaves*3);
  1387. if (RequiredSoundBankCount > MaxLeaves) RequiredSoundBankCount = 0;
  1388. auto RequiredGroupValueCount = WwiseHashCombineFast(GetTypeHash(Id), 462058) % (MaxLeaves*4);
  1389. if (RequiredGroupValueCount > MaxLeaves) RequiredGroupValueCount = 0;
  1390. auto RequiredSwitchContainerLeafCount = WwiseHashCombineFast(GetTypeHash(Id), 953019401) % (MaxLeaves*2);
  1391. if (RequiredSwitchContainerLeafCount > MaxLeaves) RequiredSwitchContainerLeafCount = 0;
  1392. for (uint32 i=0; i < RequiredMediaCount; ++i)
  1393. {
  1394. const auto MediaToAdd = WwiseHashCombineFast(GetTypeHash(Id), i ^ 9385938) % NumMedia;
  1395. Data.Media.Add(Media[MediaToAdd]);
  1396. }
  1397. for (uint32 i=0; i < RequiredSoundBankCount; ++i)
  1398. {
  1399. const auto SoundBankToAdd = WwiseHashCombineFast(GetTypeHash(Id), i ^ 223982) % NumSoundBanks;
  1400. Data.SoundBanks.Add(SoundBanks[SoundBankToAdd].SoundBankLanguageMap[FWwiseLanguageCookedData::Sfx]);
  1401. }
  1402. for (uint32 i=0; i < RequiredGroupValueCount; ++i)
  1403. {
  1404. const bool bIsState = WwiseHashCombineFast(GetTypeHash(Id), i ^ 190101) % 4 == 0; // Mostly switches
  1405. const auto NumToAdd = WwiseHashCombineFast(GetTypeHash(Id), i ^ 415938) % (bIsState ? NumStates : NumSwitches);
  1406. Data.RequiredGroupValueSet.Add(bIsState ? States[NumToAdd] : Switches[NumToAdd]);
  1407. }
  1408. for (uint32 LeafIter=0; LeafIter < RequiredSwitchContainerLeafCount; ++LeafIter)
  1409. {
  1410. FWwiseSwitchContainerLeafCookedData Leaf;
  1411. auto MediaCount = WwiseHashCombineFast(GetTypeHash(Id), LeafIter ^ 4863419941) % (MaxLeaves * 2);
  1412. if (MediaCount > MaxLeaves) MediaCount = 0;
  1413. ++MediaCount; // At least one
  1414. auto SoundBankCount = WwiseHashCombineFast(GetTypeHash(Id), LeafIter ^ 1065842795) % (MaxLeaves*3);
  1415. if (SoundBankCount > MaxLeaves) SoundBankCount = 0;
  1416. auto GroupValueCount = WwiseHashCombineFast(GetTypeHash(Id), LeafIter ^ 2828284104) % MaxLeaves;
  1417. if (GroupValueCount > MaxLeaves / 2) GroupValueCount = 0;
  1418. ++GroupValueCount; // At least one
  1419. for (uint32 i=0; i < MediaCount; ++i)
  1420. {
  1421. const auto MediaToAdd = WwiseHashCombineFast(GetTypeHash(Id), i ^ LeafIter ^ 19891919) % NumMedia;
  1422. Leaf.Media.Add(Media[MediaToAdd]);
  1423. }
  1424. for (uint32 i=0; i < SoundBankCount; ++i)
  1425. {
  1426. const auto SoundBankToAdd = WwiseHashCombineFast(GetTypeHash(Id), i ^ LeafIter ^ 924606208) % NumSoundBanks;
  1427. Leaf.SoundBanks.Add(SoundBanks[SoundBankToAdd].SoundBankLanguageMap[FWwiseLanguageCookedData::Sfx]);
  1428. }
  1429. for (uint32 i=0; i < GroupValueCount; ++i)
  1430. {
  1431. const bool bIsState = WwiseHashCombineFast(GetTypeHash(Id), i ^ LeafIter ^ 8484846414) % 4 == 0; // Mostly switches
  1432. const auto NumToAdd = WwiseHashCombineFast(GetTypeHash(Id), i ^ LeafIter ^ 10671953) % (bIsState ? NumStates : NumSwitches);
  1433. Leaf.GroupValueSet.Add(bIsState ? States[NumToAdd] : Switches[NumToAdd]);
  1434. }
  1435. Data.SwitchContainerLeaves.Add(MoveTemp(Leaf));
  1436. }
  1437. Event.EventLanguageMap.Add(FWwiseLanguageCookedData::Sfx, MoveTemp(Data));
  1438. }
  1439. for (auto& ExternalSource: ExternalSources)
  1440. {
  1441. FWwiseExternalSourceCookedData Data;
  1442. Data.Cookie = ++Id;
  1443. }
  1444. }
  1445. // Operations
  1446. FWwiseMockExternalSourceManager ExternalSourceManager;
  1447. FWwiseMockMediaManager MediaManager;
  1448. FWwiseMockSoundBankManager SoundBankManager;
  1449. FWwiseResourceLoaderImpl ResourceLoaderImpl(ExternalSourceManager, MediaManager, SoundBankManager);
  1450. auto UnloadFuturesPtr = std::make_unique<std::array<FWwiseResourceUnloadFuture, NumOp>>();
  1451. auto& UnloadFutures = *UnloadFuturesPtr;
  1452. for (uint32 Op = 0; Op < NumOp; ++Op)
  1453. {
  1454. const auto Type = WwiseHashCombineFast(GetTypeHash(Op), 939401805) % 10;
  1455. switch(Type)
  1456. {
  1457. case 0: // AuxBus
  1458. {
  1459. const auto AuxBus = WwiseHashCombineFast(GetTypeHash(Op), 2076755927) % NumAuxBusses;
  1460. // Creating Node
  1461. auto* Node = ResourceLoaderImpl.CreateAuxBusNode(AuxBusses[AuxBus], nullptr);
  1462. CHECK(Node);
  1463. if (UNLIKELY(!Node))
  1464. {
  1465. continue;
  1466. }
  1467. // Loading Node
  1468. FWwiseLoadedAuxBusPromise LoadPromise;
  1469. auto NodeFuture = LoadPromise.GetFuture();
  1470. ResourceLoaderImpl.LoadAuxBusAsync(MoveTemp(LoadPromise), MoveTemp(Node));
  1471. // Unloading Node
  1472. FWwiseResourceUnloadPromise UnloadPromise;
  1473. UnloadFutures[Op] = UnloadPromise.GetFuture();
  1474. NodeFuture.Next([&ResourceLoaderImpl, UnloadPromise = MoveTemp(UnloadPromise)](FWwiseLoadedAuxBusPtr LoadedNode) mutable
  1475. {
  1476. CHECK(LoadedNode);
  1477. if (UNLIKELY(!LoadedNode))
  1478. {
  1479. UnloadPromise.EmplaceValue();
  1480. return;
  1481. }
  1482. ResourceLoaderImpl.UnloadAuxBusAsync(MoveTemp(UnloadPromise), MoveTemp(LoadedNode));
  1483. });
  1484. }
  1485. break;
  1486. default: // More Events than anything else! (see Type's Modulo for how many are events)
  1487. case 1: // Event
  1488. {
  1489. const auto Event = WwiseHashCombineFast(GetTypeHash(Op), 549205820) % NumEvents;
  1490. // Creating Node
  1491. auto* Node = ResourceLoaderImpl.CreateEventNode(Events[Event], nullptr);
  1492. CHECK(Node);
  1493. if (UNLIKELY(!Node))
  1494. {
  1495. return;
  1496. }
  1497. // Loading Node
  1498. FWwiseLoadedEventPromise LoadPromise;
  1499. auto NodeFuture = LoadPromise.GetFuture();
  1500. ResourceLoaderImpl.LoadEventAsync(MoveTemp(LoadPromise), MoveTemp(Node));
  1501. // Unloading Node
  1502. FWwiseResourceUnloadPromise UnloadPromise;
  1503. UnloadFutures[Op] = UnloadPromise.GetFuture();
  1504. NodeFuture.Next([&ResourceLoaderImpl, UnloadPromise = MoveTemp(UnloadPromise)](FWwiseLoadedEventPtr LoadedNode) mutable
  1505. {
  1506. CHECK(LoadedNode);
  1507. if (UNLIKELY(!LoadedNode))
  1508. {
  1509. UnloadPromise.EmplaceValue();
  1510. return;
  1511. }
  1512. ResourceLoaderImpl.UnloadEventAsync(MoveTemp(UnloadPromise), MoveTemp(LoadedNode));
  1513. });
  1514. }
  1515. break;
  1516. case 2: // External source
  1517. {
  1518. const auto ExternalSource = WwiseHashCombineFast(GetTypeHash(Op), 64897712) % NumExternalSources;
  1519. // Creating Node
  1520. auto* Node = ResourceLoaderImpl.CreateExternalSourceNode(ExternalSources[ExternalSource]);
  1521. CHECK(Node);
  1522. if (UNLIKELY(!Node))
  1523. {
  1524. continue;
  1525. }
  1526. // Loading Node
  1527. FWwiseLoadedExternalSourcePromise LoadPromise;
  1528. auto NodeFuture = LoadPromise.GetFuture();
  1529. ResourceLoaderImpl.LoadExternalSourceAsync(MoveTemp(LoadPromise), MoveTemp(Node));
  1530. // Unloading Node
  1531. FWwiseResourceUnloadPromise UnloadPromise;
  1532. UnloadFutures[Op] = UnloadPromise.GetFuture();
  1533. NodeFuture.Next([&ResourceLoaderImpl, UnloadPromise = MoveTemp(UnloadPromise)](FWwiseLoadedExternalSourcePtr LoadedNode) mutable
  1534. {
  1535. CHECK(LoadedNode);
  1536. if (UNLIKELY(!LoadedNode))
  1537. {
  1538. UnloadPromise.EmplaceValue();
  1539. return;
  1540. }
  1541. ResourceLoaderImpl.UnloadExternalSourceAsync(MoveTemp(UnloadPromise), MoveTemp(LoadedNode));
  1542. });
  1543. }
  1544. break;
  1545. case 3: // Init Bank
  1546. {
  1547. const auto InitBank = WwiseHashCombineFast(GetTypeHash(Op), 65471010) % NumInitBanks;
  1548. // Creating Node
  1549. auto* Node = ResourceLoaderImpl.CreateInitBankNode(InitBanks[InitBank]);
  1550. CHECK(Node);
  1551. if (UNLIKELY(!Node))
  1552. {
  1553. continue;
  1554. }
  1555. // Loading Node
  1556. FWwiseLoadedInitBankPromise LoadPromise;
  1557. auto NodeFuture = LoadPromise.GetFuture();
  1558. ResourceLoaderImpl.LoadInitBankAsync(MoveTemp(LoadPromise), MoveTemp(Node));
  1559. // Unloading Node
  1560. FWwiseResourceUnloadPromise UnloadPromise;
  1561. UnloadFutures[Op] = UnloadPromise.GetFuture();
  1562. NodeFuture.Next([&ResourceLoaderImpl, UnloadPromise = MoveTemp(UnloadPromise)](FWwiseLoadedInitBankPtr LoadedNode) mutable
  1563. {
  1564. CHECK(LoadedNode);
  1565. if (UNLIKELY(!LoadedNode))
  1566. {
  1567. UnloadPromise.EmplaceValue();
  1568. return;
  1569. }
  1570. ResourceLoaderImpl.UnloadInitBankAsync(MoveTemp(UnloadPromise), MoveTemp(LoadedNode));
  1571. });
  1572. }
  1573. break;
  1574. case 4: // Media
  1575. {
  1576. const auto Medii = WwiseHashCombineFast(GetTypeHash(Op), 193119891) % NumMedia;
  1577. // Creating Node
  1578. auto* Node = ResourceLoaderImpl.CreateMediaNode(Media[Medii]);
  1579. CHECK(Node);
  1580. if (UNLIKELY(!Node))
  1581. {
  1582. continue;
  1583. }
  1584. // Loading Node
  1585. FWwiseLoadedMediaPromise LoadPromise;
  1586. auto NodeFuture = LoadPromise.GetFuture();
  1587. ResourceLoaderImpl.LoadMediaAsync(MoveTemp(LoadPromise), MoveTemp(Node));
  1588. // Unloading Node
  1589. FWwiseResourceUnloadPromise UnloadPromise;
  1590. UnloadFutures[Op] = UnloadPromise.GetFuture();
  1591. NodeFuture.Next([&ResourceLoaderImpl, UnloadPromise = MoveTemp(UnloadPromise)](FWwiseLoadedMediaPtr LoadedNode) mutable
  1592. {
  1593. CHECK(LoadedNode);
  1594. if (UNLIKELY(!LoadedNode))
  1595. {
  1596. UnloadPromise.EmplaceValue();
  1597. return;
  1598. }
  1599. ResourceLoaderImpl.UnloadMediaAsync(MoveTemp(UnloadPromise), MoveTemp(LoadedNode));
  1600. });
  1601. }
  1602. break;
  1603. case 5: // ShareSet
  1604. {
  1605. const auto ShareSet = WwiseHashCombineFast(GetTypeHash(Op), 331319104) % NumShareSets;
  1606. // Creating Node
  1607. auto* Node = ResourceLoaderImpl.CreateShareSetNode(ShareSets[ShareSet], &FWwiseLanguageCookedData::Sfx);
  1608. CHECK(Node);
  1609. if (UNLIKELY(!Node))
  1610. {
  1611. continue;
  1612. }
  1613. // Loading Node
  1614. FWwiseLoadedShareSetPromise LoadPromise;
  1615. auto NodeFuture = LoadPromise.GetFuture();
  1616. ResourceLoaderImpl.LoadShareSetAsync(MoveTemp(LoadPromise), MoveTemp(Node));
  1617. // Unloading Node
  1618. FWwiseResourceUnloadPromise UnloadPromise;
  1619. UnloadFutures[Op] = UnloadPromise.GetFuture();
  1620. NodeFuture.Next([&ResourceLoaderImpl, UnloadPromise = MoveTemp(UnloadPromise)](FWwiseLoadedShareSetPtr LoadedNode) mutable
  1621. {
  1622. CHECK(LoadedNode);
  1623. if (UNLIKELY(!LoadedNode))
  1624. {
  1625. UnloadPromise.EmplaceValue();
  1626. return;
  1627. }
  1628. ResourceLoaderImpl.UnloadShareSetAsync(MoveTemp(UnloadPromise), MoveTemp(LoadedNode));
  1629. });
  1630. }
  1631. break;
  1632. case 6: // SoundBank
  1633. {
  1634. const auto SoundBank = WwiseHashCombineFast(GetTypeHash(Op), 953952742) % NumSoundBanks;
  1635. // Creating Node
  1636. auto* Node = ResourceLoaderImpl.CreateSoundBankNode(SoundBanks[SoundBank], nullptr);
  1637. CHECK(Node);
  1638. if (UNLIKELY(!Node))
  1639. {
  1640. continue;
  1641. }
  1642. // Loading Node
  1643. FWwiseLoadedSoundBankPromise LoadPromise;
  1644. auto NodeFuture = LoadPromise.GetFuture();
  1645. ResourceLoaderImpl.LoadSoundBankAsync(MoveTemp(LoadPromise), MoveTemp(Node));
  1646. // Unloading Node
  1647. FWwiseResourceUnloadPromise UnloadPromise;
  1648. UnloadFutures[Op] = UnloadPromise.GetFuture();
  1649. NodeFuture.Next([&ResourceLoaderImpl, UnloadPromise = MoveTemp(UnloadPromise)](FWwiseLoadedSoundBankPtr LoadedNode) mutable
  1650. {
  1651. CHECK(LoadedNode);
  1652. if (UNLIKELY(!LoadedNode))
  1653. {
  1654. UnloadPromise.EmplaceValue();
  1655. return;
  1656. }
  1657. ResourceLoaderImpl.UnloadSoundBankAsync(MoveTemp(UnloadPromise), MoveTemp(LoadedNode));
  1658. });
  1659. }
  1660. break;
  1661. case 7: // State
  1662. {
  1663. const auto State = WwiseHashCombineFast(GetTypeHash(Op), 8198259) % NumStates;
  1664. // Creating Node
  1665. auto* Node = ResourceLoaderImpl.CreateGroupValueNode(States[State]);
  1666. CHECK(Node);
  1667. if (UNLIKELY(!Node))
  1668. {
  1669. return;
  1670. }
  1671. // Loading Node
  1672. FWwiseLoadedGroupValuePromise LoadPromise;
  1673. auto NodeFuture = LoadPromise.GetFuture();
  1674. ResourceLoaderImpl.LoadGroupValueAsync(MoveTemp(LoadPromise), MoveTemp(Node));
  1675. // Unloading Node
  1676. FWwiseResourceUnloadPromise UnloadPromise;
  1677. UnloadFutures[Op] = UnloadPromise.GetFuture();
  1678. NodeFuture.Next([&ResourceLoaderImpl, UnloadPromise = MoveTemp(UnloadPromise)](FWwiseLoadedGroupValuePtr LoadedNode) mutable
  1679. {
  1680. CHECK(LoadedNode);
  1681. if (UNLIKELY(!LoadedNode))
  1682. {
  1683. UnloadPromise.EmplaceValue();
  1684. return;
  1685. }
  1686. ResourceLoaderImpl.UnloadGroupValueAsync(MoveTemp(UnloadPromise), MoveTemp(LoadedNode));
  1687. });
  1688. }
  1689. break;
  1690. case 8: // Switch
  1691. {
  1692. const auto Switch = WwiseHashCombineFast(GetTypeHash(Op), 24650269) % NumSwitches;
  1693. // Creating Node
  1694. auto* Node = ResourceLoaderImpl.CreateGroupValueNode(Switches[Switch]);
  1695. CHECK(Node);
  1696. if (UNLIKELY(!Node))
  1697. {
  1698. return;
  1699. }
  1700. // Loading Node
  1701. FWwiseLoadedGroupValuePromise LoadPromise;
  1702. auto NodeFuture = LoadPromise.GetFuture();
  1703. ResourceLoaderImpl.LoadGroupValueAsync(MoveTemp(LoadPromise), MoveTemp(Node));
  1704. // Unloading Node
  1705. FWwiseResourceUnloadPromise UnloadPromise;
  1706. UnloadFutures[Op] = UnloadPromise.GetFuture();
  1707. NodeFuture.Next([&ResourceLoaderImpl, UnloadPromise = MoveTemp(UnloadPromise)](FWwiseLoadedGroupValuePtr LoadedNode) mutable
  1708. {
  1709. CHECK(LoadedNode);
  1710. if (UNLIKELY(!LoadedNode))
  1711. {
  1712. UnloadPromise.EmplaceValue();
  1713. return;
  1714. }
  1715. ResourceLoaderImpl.UnloadGroupValueAsync(MoveTemp(UnloadPromise), MoveTemp(LoadedNode));
  1716. });
  1717. }
  1718. break;
  1719. }
  1720. // Leave some leeway to execute some of the operations before starting the next batch
  1721. if (Op % 100 == 0)
  1722. {
  1723. FPlatformProcess::Sleep(0.01f);
  1724. }
  1725. }
  1726. for (auto& UnloadFuture : UnloadFutures)
  1727. {
  1728. UnloadFuture.Get();
  1729. }
  1730. CHECK(ExternalSourceManager.IsEmpty());
  1731. CHECK(MediaManager.IsEmpty());
  1732. CHECK(SoundBankManager.IsEmpty());
  1733. CHECK(ResourceLoaderImpl.IsEmpty());
  1734. CHECK(ResourceLoaderImpl.TrimGroupValueInfo());
  1735. }
  1736. SECTION("Sequential Leaf Load")
  1737. {
  1738. const bool bMockSleepOnMediaLoad = FWwiseResourceLoaderImpl::Test::bMockSleepOnMediaLoad;
  1739. FWwiseResourceLoaderImpl::Test::bMockSleepOnMediaLoad = true;
  1740. ON_SCOPE_EXIT { FWwiseResourceLoaderImpl::Test::bMockSleepOnMediaLoad = bMockSleepOnMediaLoad; };
  1741. FWwiseMockExternalSourceManager ExternalSourceManager;
  1742. FWwiseMockMediaManager MediaManager;
  1743. FWwiseMockSoundBankManager SoundBankManager;
  1744. FWwiseResourceLoaderImpl ResourceLoaderImpl(ExternalSourceManager, MediaManager, SoundBankManager);
  1745. static constexpr const auto MediaOverlap = 1.25f;
  1746. static constexpr const uint32 NumGroupValues = 1000;
  1747. static constexpr const auto NumLoops = 2;
  1748. static constexpr const auto FuturesCount = (NumGroupValues + 2) * NumLoops;
  1749. static constexpr const auto EventsCount = 2 * NumLoops;
  1750. FWwiseLocalizedEventCookedData EventCookedDatas[2];
  1751. // Fill ordered EventCookedData (0)
  1752. {
  1753. FWwiseEventCookedData Data;
  1754. Data.EventId = 1;
  1755. FWwiseSwitchContainerLeafCookedData Leaf;
  1756. for (int i = 0; i < NumGroupValues; ++i)
  1757. {
  1758. FWwiseMediaCookedData LeafMedia;
  1759. LeafMedia.MediaId = 10000 + i / MediaOverlap;
  1760. Leaf.Media.Emplace(MoveTemp(LeafMedia));
  1761. FWwiseGroupValueCookedData LeafGroupValue;
  1762. LeafGroupValue.Id = 15000 + i;
  1763. LeafGroupValue.GroupId = 1;
  1764. LeafGroupValue.Type = EWwiseGroupType::Switch;
  1765. Leaf.GroupValueSet.Emplace(MoveTemp(LeafGroupValue));
  1766. Data.SwitchContainerLeaves.Emplace(MoveTemp(Leaf));
  1767. }
  1768. EventCookedDatas[0].EventLanguageMap.Emplace(FWwiseLanguageCookedData::Sfx, MoveTemp(Data));
  1769. }
  1770. // Fill unordered EventCookedData (1)
  1771. {
  1772. FWwiseEventCookedData Data;
  1773. Data.EventId = 1;
  1774. FWwiseSwitchContainerLeafCookedData Leaf;
  1775. for (int i = 0; i < NumGroupValues; ++i)
  1776. {
  1777. for (uint32 j = 0; j < 2; ++j)
  1778. {
  1779. FWwiseMediaCookedData LeafMedia;
  1780. LeafMedia.MediaId = 10000 + (WwiseHashCombineFast(GetTypeHash(i), 142401 + j) % NumGroupValues) / MediaOverlap;
  1781. Leaf.Media.Emplace(MoveTemp(LeafMedia));
  1782. }
  1783. FWwiseGroupValueCookedData LeafGroupValue;
  1784. LeafGroupValue.Id = 15000 + i;
  1785. LeafGroupValue.GroupId = 1;
  1786. LeafGroupValue.Type = EWwiseGroupType::Switch;
  1787. Leaf.GroupValueSet.Emplace(MoveTemp(LeafGroupValue));
  1788. Data.SwitchContainerLeaves.Emplace(MoveTemp(Leaf));
  1789. }
  1790. EventCookedDatas[1].EventLanguageMap.Emplace(FWwiseLanguageCookedData::Sfx, MoveTemp(Data));
  1791. }
  1792. FWwiseGroupValueCookedData GroupValueCookedDatas[NumGroupValues];
  1793. for (auto i = 0; i < NumGroupValues; ++i)
  1794. {
  1795. GroupValueCookedDatas[i].Id = 15000 + i;
  1796. GroupValueCookedDatas[i].GroupId = 1;
  1797. GroupValueCookedDatas[i].Type = EWwiseGroupType::Switch;
  1798. }
  1799. FWwiseLoadedEventFuture EventFuturesArray[EventsCount];
  1800. FWwiseResourceUnloadFuture UnloadFuturesArray[FuturesCount];
  1801. for (auto Loop = 0; Loop < NumLoops; ++Loop)
  1802. {
  1803. auto* EventFutures( &EventFuturesArray[2 * Loop] );
  1804. auto* UnloadFutures( &UnloadFuturesArray[(NumGroupValues + 2) * Loop] );
  1805. for (auto i = 0; i < NumGroupValues; ++i)
  1806. {
  1807. if (i == 0)
  1808. {
  1809. // Creating Node
  1810. auto* Node = ResourceLoaderImpl.CreateEventNode(EventCookedDatas[0], nullptr);
  1811. CHECK(Node);
  1812. if (UNLIKELY(!Node))
  1813. {
  1814. return;
  1815. }
  1816. // Loading Node
  1817. FWwiseLoadedEventPromise LoadPromise;
  1818. EventFutures[0] = LoadPromise.GetFuture();
  1819. ResourceLoaderImpl.LoadEventAsync(MoveTemp(LoadPromise), MoveTemp(Node));
  1820. }
  1821. else if (i == NumGroupValues / 4 * 3)
  1822. {
  1823. // Unloading Node
  1824. FWwiseResourceUnloadPromise UnloadPromise;
  1825. UnloadFutures[NumGroupValues] = UnloadPromise.GetFuture();
  1826. EventFutures[0].Next([&ResourceLoaderImpl, UnloadPromise = MoveTemp(UnloadPromise)](FWwiseLoadedEventPtr LoadedNode) mutable
  1827. {
  1828. CHECK(LoadedNode);
  1829. if (UNLIKELY(!LoadedNode))
  1830. {
  1831. UnloadPromise.EmplaceValue();
  1832. return;
  1833. }
  1834. ResourceLoaderImpl.UnloadEventAsync(MoveTemp(UnloadPromise), MoveTemp(LoadedNode));
  1835. });
  1836. }
  1837. if (i == NumGroupValues / 4 * 2)
  1838. {
  1839. // Creating Node
  1840. auto* Node = ResourceLoaderImpl.CreateEventNode(EventCookedDatas[1], nullptr);
  1841. CHECK(Node);
  1842. if (UNLIKELY(!Node))
  1843. {
  1844. return;
  1845. }
  1846. // Loading Node
  1847. FWwiseLoadedEventPromise LoadPromise;
  1848. EventFutures[1] = LoadPromise.GetFuture();
  1849. ResourceLoaderImpl.LoadEventAsync(MoveTemp(LoadPromise), MoveTemp(Node));
  1850. }
  1851. else if (i == NumGroupValues - 1)
  1852. {
  1853. // Unloading Node
  1854. FWwiseResourceUnloadPromise UnloadPromise;
  1855. UnloadFutures[NumGroupValues + 1] = UnloadPromise.GetFuture();
  1856. EventFutures[1].Next([&ResourceLoaderImpl, UnloadPromise = MoveTemp(UnloadPromise)](FWwiseLoadedEventPtr LoadedNode) mutable
  1857. {
  1858. CHECK(LoadedNode);
  1859. if (UNLIKELY(!LoadedNode))
  1860. {
  1861. UnloadPromise.EmplaceValue();
  1862. return;
  1863. }
  1864. ResourceLoaderImpl.UnloadEventAsync(MoveTemp(UnloadPromise), MoveTemp(LoadedNode));
  1865. });
  1866. }
  1867. {
  1868. // Creating Node
  1869. auto* Node = ResourceLoaderImpl.CreateGroupValueNode(GroupValueCookedDatas[i]);
  1870. CHECK(Node);
  1871. if (UNLIKELY(!Node))
  1872. {
  1873. return;
  1874. }
  1875. // Loading Node
  1876. FWwiseLoadedGroupValuePromise LoadPromise;
  1877. auto NodeFuture = LoadPromise.GetFuture();
  1878. ResourceLoaderImpl.LoadGroupValueAsync(MoveTemp(LoadPromise), MoveTemp(Node));
  1879. // Unloading Node
  1880. FWwiseResourceUnloadPromise UnloadPromise;
  1881. UnloadFutures[i] = UnloadPromise.GetFuture();
  1882. NodeFuture.Next([&ResourceLoaderImpl, UnloadPromise = MoveTemp(UnloadPromise)](FWwiseLoadedGroupValuePtr LoadedNode) mutable
  1883. {
  1884. CHECK(LoadedNode);
  1885. if (UNLIKELY(!LoadedNode))
  1886. {
  1887. UnloadPromise.EmplaceValue();
  1888. return;
  1889. }
  1890. ResourceLoaderImpl.UnloadGroupValueAsync(MoveTemp(UnloadPromise), MoveTemp(LoadedNode));
  1891. });
  1892. }
  1893. // Leave some leeway to execute some of the operations before starting the next batch
  1894. if (i % 100 == 0)
  1895. {
  1896. FPlatformProcess::Sleep(0.01f);
  1897. }
  1898. }
  1899. // Leave some leeway to execute some of the operations before starting the next loop
  1900. FPlatformProcess::Sleep(0.1f);
  1901. }
  1902. for (auto i = 0; i < FuturesCount; ++i)
  1903. {
  1904. UnloadFuturesArray[i].Get();
  1905. }
  1906. CHECK(ExternalSourceManager.IsEmpty());
  1907. CHECK(MediaManager.IsEmpty());
  1908. CHECK(SoundBankManager.IsEmpty());
  1909. CHECK(ResourceLoaderImpl.IsEmpty());
  1910. CHECK(ResourceLoaderImpl.TrimGroupValueInfo());
  1911. }
  1912. }
  1913. #endif // WWISE_UNIT_TESTS