Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

188 lines
5.5 KiB

  1. //========== Copyright � Valve Corporation, All rights reserved. ========
  2. #if !defined( VJOBS_CHAINUTILS_HDR ) && defined( _PS3 )
  3. #define VJOBS_CHAINUTILS_HDR
  4. #include "tier0/platform.h"
  5. #include <cell/spurs.h>
  6. #include "ps3/job_notify.h"
  7. struct VJobsRoot;
  8. //
  9. // The chain consists of blocks of commands; the head block has SYNC-JOB(notify)-GUARD sequence
  10. // initially the chain waits on the GUARD , and is ready to "run". "Run" means releasing the guard.
  11. // I'm using GUARD instead of JTS because patching JTS will render it unpatcheable until jobchain execution completes;
  12. // and if it's unpatcheable, it effectively can't be used as a guard for the next cycle
  13. // Each block refers to the next one by inserting NEXT in the very last slot
  14. // the last block is pointed to by m_pLastBlock, which is NULL initially (before entering the "run" state)
  15. //
  16. //
  17. struct ALIGN128 VjobChain
  18. {
  19. public:
  20. cell::Spurs::JobChain m_spursJobChain;
  21. cell::Spurs::JobGuard m_guard;
  22. CellSpursJob64 m_jobNotify;
  23. job_notify::NotifyArea_t m_notifyArea;
  24. enum { BLOCK_COMMANDS = 256 };
  25. uint64 m_headBlock[BLOCK_COMMANDS+1]; // in one variant, the first entry in this list is used for END command; overwrite it with NOP to release the list
  26. uint64 * m_pLastBlock;
  27. uint m_nCurrentBlockCommands;
  28. uint m_nSpinWaitNotify;
  29. char m_name[16];
  30. public:
  31. int Init( VJobsRoot * pRoot, uint nMaxContention, const char* pFormatName, ... );
  32. bool IsRunning()const { return m_pLastBlock != NULL; }
  33. int Run();
  34. void Push( uint64 nCommand );
  35. void Push( const uint64 * nCommands, uint nCommandCount );
  36. int End( );
  37. int Join();
  38. void Shutdown();
  39. JobChain & Jobchain() { return m_spursJobChain; }
  40. }ALIGN128_POST;
  41. // VjobChain2 hosts 2 jobchains and double-buffers between them
  42. class VjobChain2
  43. {
  44. public:
  45. int Init( VJobsRoot * pRoot, uint nMaxContention, const char* pName );
  46. void Begin();
  47. void End();
  48. void Shutdown();
  49. VjobChain& Jobchain(){ return m_vjobChainRing[m_nCurrentChain]; }
  50. protected:
  51. enum{VJOB_CHAINS = 2};
  52. VjobChain *m_vjobChainRing; // may be more than double-buffered if necessary
  53. uint m_nCurrentChain;
  54. };
  55. //#define VJOBCHAIN3_GUARD
  56. struct ALIGN128 VjobBufferHeader_t
  57. {
  58. public:
  59. #ifdef VJOBCHAIN3_GUARD
  60. cell::Spurs::JobGuard m_guard;
  61. #endif
  62. CellSpursJob64 m_jobNotify;
  63. job_notify::NotifyArea_t m_notifyArea;
  64. #ifdef _DEBUG
  65. CellSpursJob64 m_jobNotify2;
  66. job_notify::NotifyArea_t m_notifyArea2;
  67. #endif
  68. }
  69. ALIGN128_POST;
  70. struct VjobBuffer_t: public VjobBufferHeader_t
  71. {
  72. public:
  73. enum ConstEnum_t
  74. {
  75. VERBATIM_COMMAND_COUNT = 2 // we employ syncronization scheme: SYNC, JOB(notify), ...
  76. #ifdef VJOBCHAIN3_GUARD // we add GUARD, ...
  77. + 1
  78. #endif
  79. #ifdef _DEBUG
  80. + 1 // we add JOB(notify2), ...
  81. #else
  82. #endif
  83. };
  84. uint64 m_spursCommands[16]; // there will be at least verbatim commands, a user command, and a NEXT
  85. void Init( VJobsRoot * pRoot, cell::Spurs::JobChain * pSpursJobChain );
  86. };
  87. // VjobChain3 has only 1 jobchain but double-buffers it to facilitate continuous wait-free execution
  88. class VjobChain3
  89. {
  90. protected:
  91. enum ConstEnum_t {
  92. BUFFER_COUNT = 4
  93. };
  94. cell::Spurs::JobChain *m_pSpursJobChain;
  95. VjobBuffer_t * m_pBuffers[BUFFER_COUNT];
  96. VjobBuffer_t * m_pFrontBuffer;
  97. uint m_nFrontBuffer; // the buffer currently in use
  98. uint m_nMaxCommandsPerBuffer; // max count of commands fitting into one buffer
  99. uint m_nFrontBufferCommandCount; // count of commands in the current front buffer
  100. uint m_nSpinWaitNotify; // did we spin waiting for job_notify ? if we did, we probably need to increase the command buffer size
  101. uint64 m_nLastCommandPushed; // at the beginning of the scene, it's considered to be synced up
  102. const char * m_pName;
  103. public:
  104. int Init( VJobsRoot * pRoot, uint nMaxContention, uint nMinCommandsPerBuffer, uint8_t nVjobChainPriority[8], const char* pName, uint nDmaTags );
  105. uint64* Push( uint64 nCommand );
  106. uint64* PushSyncJobSync( uint64 nCommand );
  107. void PushSync();
  108. void Shutdown(){End();Join();}
  109. void End();
  110. void Join();
  111. protected:
  112. void WaitForEntryNotify( VjobBuffer_t * pBuffer );
  113. uint64* StartCommandBuffer( uint nNext1Buffer, uint64 nInsertCommand );
  114. uint64* SwapCommandBuffer( uint64 nInsertCommand );
  115. };
  116. inline uint64* VjobChain3::Push( uint64 nCommand )
  117. {
  118. uint64 * pInsertionPoint;
  119. if( m_nFrontBufferCommandCount == m_nMaxCommandsPerBuffer - 1 )
  120. {
  121. // time to switch the buffer
  122. pInsertionPoint = SwapCommandBuffer( nCommand );
  123. }
  124. else
  125. {
  126. m_pFrontBuffer->m_spursCommands[ m_nFrontBufferCommandCount + 1 ] = CELL_SPURS_JOB_COMMAND_JTS;
  127. __lwsync(); // Important: this sync ensures that both the command header AND JTS are written before SPU sees them
  128. pInsertionPoint = &m_pFrontBuffer->m_spursCommands[ m_nFrontBufferCommandCount ];
  129. *pInsertionPoint = nCommand;
  130. m_nFrontBufferCommandCount ++;
  131. }
  132. m_nLastCommandPushed = nCommand;
  133. return pInsertionPoint;
  134. }
  135. inline void VjobChain3::PushSync()
  136. {
  137. Push( CELL_SPURS_JOB_COMMAND_LWSYNC );
  138. }
  139. inline uint64* VjobChain3::PushSyncJobSync( uint64 nCommand )
  140. {
  141. if( m_nLastCommandPushed != CELL_SPURS_JOB_COMMAND_LWSYNC )
  142. {
  143. // we need to wait for previous jobs to finish in order to patch the state efficiently
  144. // todo: double-buffer the states to avoid stalls, but only if we become SPU-bound here (un
  145. Push( CELL_SPURS_JOB_COMMAND_LWSYNC );
  146. }
  147. uint64 * pInsertionPoint = Push( nCommand );
  148. // this is instead of stalling successor because I'm not sure if it stalls all logical successors (some of which may be picked up by other SPUs)
  149. // the SYNC here will ensure completion of the previous job before the new jobs will be pushed
  150. Push( CELL_SPURS_JOB_COMMAND_LWSYNC );
  151. return pInsertionPoint;
  152. }
  153. #endif