WwiseDeferredQueue.h 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  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. #pragma once
  16. #include "Wwise/WwiseExecutionQueue.h"
  17. #include "WwiseUnrealDefines.h"
  18. namespace AK
  19. {
  20. class IAkGlobalPluginContext;
  21. }
  22. enum class WWISECONCURRENCY_API EWwiseDeferredAsyncResult
  23. {
  24. /**
  25. * @brief The Deferred Queue task is now done executing. Stop executing it.
  26. */
  27. Done,
  28. /**
  29. * @brief The Deferred Queue task is recurrent. Execute it again at next request.
  30. */
  31. KeepRunning
  32. };
  33. struct WWISECONCURRENCY_API FWwiseDeferredQueue
  34. {
  35. using FFunction = TUniqueFunction<EWwiseDeferredAsyncResult()>;
  36. using FSyncFunction = TUniqueFunction<EWwiseDeferredAsyncResult (AK::IAkGlobalPluginContext*)>;
  37. #if UE_5_1_OR_LATER
  38. DECLARE_TS_MULTICAST_DELEGATE_OneParam(FThreadSafeDelegate, AK::IAkGlobalPluginContext*);
  39. #else
  40. DECLARE_MULTICAST_DELEGATE_OneParam(FThreadSafeDelegate, AK::IAkGlobalPluginContext*);
  41. #endif
  42. DECLARE_MULTICAST_DELEGATE(FGameThreadDelegate);
  43. #define WWISE_DQ_NAME(name) TEXT(name ## " Deferred Queue worker")
  44. FWwiseDeferredQueue(const TCHAR* InDebugName);
  45. ~FWwiseDeferredQueue();
  46. /**
  47. * @brief Defer execution of an operation on the next Run() or Wait() call, where a task is started, and the function is run asynchronously.
  48. * @param InFunction The function to execute
  49. *
  50. * For most uses, there is no time sensitivity to a deferred operation. Every single deferred Async operation are run sequentially, however,
  51. * they might be executed at the same time than the Sync and Game operations. Also, these will probably be called in a non-game thread, so you are
  52. * responsible to properly bound your code if this causes issues.
  53. *
  54. * The return value of the passed function should be "Done" if it was properly executed, whether there was an error or not. The return value
  55. * should be "KeepRunning" if it should be deferred for the next callback loop.
  56. */
  57. void AsyncDefer(FFunction&& InFunction);
  58. /**
  59. * @brief Defer execution of an operation on the next Run() or Wait() call, where the function is immediately called in the Run() or Wait() thread.
  60. * @param InFunction The function to execute, synchronous to the Run() thread.
  61. *
  62. * @warning Since this function will be called synchronously to the Run() call, if the running thread is time-sensitive, it can cause glitches
  63. * or hitches. In most cases, you should use DeferAsync or DeferGame.
  64. *
  65. * This is required for time-sensitive issues, such as waiting for an operation that absolutely needs to be done before the Run() thread gains
  66. * control back.
  67. */
  68. void SyncDefer(FSyncFunction&& InFunction);
  69. /**
  70. * @brief Defer execution of an operation on the next Run() or Wait() call, where the function is subsequently run on the Game Thread.
  71. * @param InFunction The function to execute
  72. *
  73. * For most game uses, there is no time sensitivity to a deferred operation, but you might want to notify game objects when an event occurs.
  74. *
  75. * Every single deferred Game operation are run sequentially, however, they might be executed at the same time than the other Async and Sync
  76. * operations.
  77. */
  78. void GameDefer(FFunction&& InFunction);
  79. void Run(AK::IAkGlobalPluginContext* InContext);
  80. void Wait();
  81. bool IsEmpty() const { return AsyncOpQueue.IsEmpty() && SyncOpQueue.IsEmpty() && GameOpQueue.IsEmpty(); }
  82. FGameThreadDelegate OnGameRun;
  83. FThreadSafeDelegate OnSyncRunTS;
  84. protected:
  85. FWwiseExecutionQueue AsyncExecutionQueue;
  86. using FOps = TQueue<FFunction, EQueueMode::Mpsc>;
  87. using FSyncOps = TQueue<FSyncFunction, EQueueMode::Mpsc>;
  88. FOps AsyncOpQueue;
  89. FSyncOps SyncOpQueue;
  90. FOps GameOpQueue;
  91. TAtomic<int> GameThreadExecuting {0};
  92. bool bSyncThreadDone = false;
  93. bool bClosing = false;
  94. AK::IAkGlobalPluginContext* Context { nullptr };
  95. private:
  96. void AsyncExec();
  97. void SyncExec();
  98. void SyncExecLoop();
  99. void GameThreadExec();
  100. void GameThreadExecLoop();
  101. };