hkJobQueue.h
上传用户:yisoukefu
上传日期:2020-08-09
资源大小:39506k
文件大小:14k
源码类别:

其他游戏

开发平台:

Visual C++

  1. /* 
  2.  * 
  3.  * Confidential Information of Telekinesys Research Limited (t/a Havok). Not for disclosure or distribution without Havok's
  4.  * prior written consent. This software contains code, techniques and know-how which is confidential and proprietary to Havok.
  5.  * Level 2 and Level 3 source code contains trade secrets of Havok. Havok Software (C) Copyright 1999-2009 Telekinesys Research Limited t/a Havok. All Rights Reserved. Use of this software is subject to the terms of an end user license agreement.
  6.  * 
  7.  */
  8. #ifndef HK_BASE_THREAD_JOB_QUEUE_H
  9. #define HK_BASE_THREAD_JOB_QUEUE_H
  10. #include <Common/Base/Thread/CriticalSection/hkCriticalSection.h>
  11. #include <Common/Base/Thread/Semaphore/hkSemaphoreBusyWait.h>
  12. #include <Common/Base/Container/Array/hkObjectArray.h>
  13. #include <Common/Base/Container/Queue/hkQueue.h>
  14. extern HK_THREAD_LOCAL( int ) hkThreadNumber;
  15. #define HK_INVALID_JOB 0xff
  16. typedef hkUint8 hkJobSubType;
  17. enum hkJobType
  18. {
  19. HK_JOB_TYPE_DYNAMICS,
  20. HK_JOB_TYPE_COLLIDE,
  21. HK_JOB_TYPE_COLLISION_QUERY,
  22. HK_JOB_TYPE_RAYCAST_QUERY,
  23. HK_JOB_TYPE_ANIMATION,
  24. HK_JOB_TYPE_BEHAVIOR,
  25. HK_JOB_TYPE_CLOTH,
  26. HK_JOB_TYPE_PATHFINDING,
  27. HK_JOB_TYPE_HAVOK_MAX,
  28. HK_JOB_TYPE_USER_0 = HK_JOB_TYPE_HAVOK_MAX,
  29. //HK_JOB_TYPE_USER_1,
  30. HK_JOB_TYPE_MAX
  31. };
  32. enum hkJobSpuType
  33. {
  34. HK_JOB_SPU_TYPE_INVALID,
  35. HK_JOB_SPU_TYPE_ENABLED,
  36. HK_JOB_SPU_TYPE_DISABLED
  37. };
  38. /// Base type for all jobs.
  39. struct hkJob
  40. {
  41. HK_FORCE_INLINE hkJob( hkJobType jobType, hkUint32 jobSubType, hkUint16 size, hkJobSpuType jobProcessorTypes = HK_JOB_SPU_TYPE_ENABLED );
  42. hkJob() {}
  43. HK_ALIGN16(hkJobSubType m_jobSubType);
  44. hkEnum<hkJobType, hkUint8> m_jobType;
  45. hkEnum<hkJobSpuType, hkUint8> m_jobSpuType;
  46. hkUint16 m_size;
  47. hkInt16 m_threadAffinity; // -1 by default indicates no thread affinity
  48. };
  49. /// A structure used for specifying the number of threads, shared caches, and additionally for the 
  50. /// PLAYSTATION(R)3, whether the PPU can take SPU tasks
  51. struct hkJobQueueHwSetup
  52. {
  53. hkJobQueueHwSetup();
  54. /// PLAYSTATION(R)3 only. A flag used to determine if the PPU can take SPU tasks.
  55. enum CellRules
  56. {
  57. /// If there are only SPU jobs on the queue and no SPU is free to take one, the
  58. /// PPU is allowed to take the job.
  59. PPU_CAN_TAKE_SPU_TASKS,
  60. /// The PPU will never take SPU jobs, even if there are only SPU jobs on the queue.
  61. /// This is the default setting.
  62. PPU_CANNOT_TAKE_SPU_TASKS
  63. };
  64. CellRules m_cellRules;
  65. int m_numCpuThreads;
  66. hkObjectArray<hkArray<int> > m_threadIdsSharingCaches;
  67. };
  68. struct hkJobQueueCinfo
  69. {
  70. hkJobQueueCinfo() { m_maxNumJobTypes = HK_JOB_TYPE_HAVOK_MAX; }
  71. hkJobQueueHwSetup m_jobQueueHwSetup;
  72. int m_maxNumJobTypes;
  73. };
  74. /// This class implements a job queue with all necessary locking and waiting
  75. class hkJobQueue
  76. {
  77. public:
  78. // NOTE: Using these fixed values instead of hkArrays for easy SPU
  79. #define CUSTOM_JOB_TYPE_MAX 2
  80. #define MAX_NUM_THREAD_TYPES CUSTOM_JOB_TYPE_MAX + 2 + 1// Max shared caches + 1 for master thread
  81. #define MAX_NUM_CPU_THREADS 4
  82. #define MAX_NUM_QUEUES MAX_NUM_THREAD_TYPES + HK_JOB_TYPE_MAX
  83. HK_DECLARE_NONVIRTUAL_CLASS_ALLOCATOR( HK_MEMORY_CLASS_BASE, hkJobQueue );
  84. typedef int QueueIndex;
  85. /// The basic struct stored in the job queue
  86. #if (HK_POINTER_SIZE == 4)
  87. enum { JOB_QUEUE_ENTRY_SIZE = 128 };
  88. #else
  89. enum { JOB_QUEUE_ENTRY_SIZE = 256 };
  90. #endif
  91. struct JobQueueEntry : public hkJob
  92. {
  93. JobQueueEntry() {}
  94. hkUchar m_data[ JOB_QUEUE_ENTRY_SIZE - sizeof(hkJob) ];
  95. };
  96. // 12 bytes
  97. struct Queue: public hkQueue<JobQueueEntry>
  98. {
  99. };
  100. //
  101. // Enums to specify job types
  102. //
  103. enum WaitPolicy
  104. {
  105. WAIT_UNTIL_ALL_WORK_COMPLETE,
  106. WAIT_INDEFINITELY
  107. };
  108. struct DynamicData
  109. {
  110. HK_DECLARE_NONVIRTUAL_CLASS_ALLOCATOR( HK_MEMORY_CLASS_DYNAMICS, DynamicData );
  111. // The number of jobs which are currently processed (this is both spu and ppu jobs)
  112. HK_ALIGN16( int m_numActiveJobs[HK_JOB_TYPE_MAX] );
  113. int m_masterThreadFinishingFlags;
  114. // If this is true, the SPUs won't leave their current physics (collide or integrate) .ELF
  115. WaitPolicy m_waitPolicy;
  116. // one entry per semaphore
  117. hkUint16 m_numThreadsWaiting[MAX_NUM_THREAD_TYPES];
  118. Queue m_jobQueue[MAX_NUM_QUEUES];
  119. };
  120. /// Whether a job is placed at the front or the end of its appropriate queue
  121. enum JobPriority
  122. {
  123. JOB_HIGH_PRIORITY,
  124. JOB_LOW_PRIORITY,
  125. };
  126. //
  127. // Callback functions used from within critical sections
  128. //
  129. /// The result from JobPopFunc
  130. enum JobPopFuncResult
  131. {
  132. /// Set to this if the function is taking the element off the queue
  133. POP_QUEUE_ENTRY,
  134. /// Set to this if the function has modified the element, and left it on the queue
  135. DO_NOT_POP_QUEUE_ENTRY 
  136. };
  137. typedef JobPopFuncResult (HK_CALL *JobPopFunc)( hkJobQueue& queue, hkJobQueue::DynamicData* data, JobQueueEntry& jobIn, JobQueueEntry& jobOut );
  138. enum JobCreationStatus
  139. {
  140. JOB_CREATED,
  141. NO_JOB_CREATED
  142. };
  143. /// A flag to tell getNextJob what to do if no job is immediately available
  144. enum WaitStatus
  145. {
  146. WAIT_FOR_NEXT_JOB,
  147. DO_NOT_WAIT_FOR_NEXT_JOB
  148. };
  149. struct JobQueueEntryInput
  150. {
  151. hkPadSpu<hkUint32> m_jobPriority; // JobPriority
  152. JobQueueEntry m_job;
  153. };
  154. typedef JobCreationStatus (HK_CALL *FinishJobFunc)( hkJobQueue& queue, DynamicData* data, const JobQueueEntry& jobIn, JobQueueEntryInput& newJobCreatedOut );
  155. /// Whether a getNextJob call got another job or not
  156. enum JobStatus
  157. {
  158. JOB_INVALID = -1,
  159. GOT_NEXT_JOB,
  160. NO_JOBS_AVAILABLE,
  161. ALL_JOBS_FINISHED,
  162. JOBS_AVAILABLE_BUT_NOT_FOR_CURRENT_ELF,
  163. };
  164. typedef JobStatus (HK_CALL *ProcessJobFunc)( hkJobQueue& jobQueue, JobQueueEntry& jobInOut );
  165. struct hkJobHandlerFuncs
  166. {
  167. ProcessJobFunc* m_processJobFuncs;
  168. int m_numProcessJobFuncs;
  169. JobPopFunc m_popJobFunc;
  170. FinishJobFunc m_finishJobFunc;
  171. HK_FORCE_INLINE void initProcessJobFuncs( ProcessJobFunc* processJobFuncs, int numProcessJobFuncs)
  172. {
  173. m_processJobFuncs = processJobFuncs;
  174. m_numProcessJobFuncs = numProcessJobFuncs;
  175. }
  176. HK_FORCE_INLINE void registerProcessJobFunc( hkJobSubType jobId, ProcessJobFunc func )
  177. {
  178. HK_ASSERT2(0x543e432e, (jobId & 0xff) < m_numProcessJobFuncs, " Job ID out of range for registerd function table"); 
  179. m_processJobFuncs[ (jobId & 0xff) ] = func;
  180. }
  181. };
  182. inline JobStatus findJobInternal( QueueIndex queueIndexOfNewJob, DynamicData* data, WaitStatus waitStatus, JobQueueEntry& jobOut );
  183. void getFinishingFlags(DynamicData* data, bool& masterThreadShouldFinish, bool& allWorkComplete);
  184. public:
  185. //
  186. // CPU only functions
  187. //
  188. /// Note: this class should only ever be constructed on a CPU. If running on an SPU it must be dma'd into an
  189. /// appropriately sized 128 byte aligned local store buffer.
  190.  hkJobQueue( const hkJobQueueCinfo& cinfo );
  191. ~hkJobQueue();
  192. void registerJobWithCpuThread( hkJobType jobType, hkJobSubType subType, int threadId );
  193. /// Batch add 'n' jobs of the same priority and job thread type - without entering critical section for every job.
  194. void addJobBatch( hkArray<JobQueueEntry*>& jobs, JobPriority priority );
  195. // Called automatically
  196. void updateJobQueryRules();
  197. /// Set the wait policy on the job queue. By default it is WAIT_UNTIL_ALL_WORK_COMPLETE, which means
  198. /// worker threads return when all jobs placed on the queue have been completed. 
  199. /// Setting the policy to WAIT_INDEFINITELY will make worker threads continue to wait for new jobs.
  200. /// This does not affect the thread that created the queue, which will always return when all jobs
  201. /// have been completed.
  202. void setWaitPolicy( WaitPolicy waitPolicy );
  203. /// Get the wait policy. See comments for setWaitPolicy for details.
  204. WaitPolicy getWaitPolicy();
  205. int getMasterThreadFinishingFlags();
  206. void setMasterThreadFinishingFlags( int flags );
  207. void setQueueCapacityForJobType( hkJobType type, int queueCapacity );
  208. /// This function will process jobs from the queue until the queue is empty, then return.
  209. JobStatus processAllJobs( );
  210. /// Register a handler for the supplied jobs
  211. /// Only the upper 8 bits of the jobId is used so register with one of the types in hkJobBaseId
  212. void registerJobHandler( hkJobType jobId, hkJobHandlerFuncs jobHandlerFuncs );
  213. //
  214. // Runtime functions
  215. //
  216. /// Adds a new job to the queue with a given priority
  217. void addJob( hkJob& job, JobPriority priority );
  218. /// Adds a new job to the queue for a given priority and job thread type.
  219. /// This call requires you to pass the job as a JobQueueEntry struct, and so avoids the memcpy();
  220. void addJob( JobQueueEntry& job, JobPriority priority );
  221. // Can be used to add jobs when the job queue is already locked. This can only be called from
  222. // pop and finish callback functions. It should not be called elsewhere.
  223. void addJobQueueLocked( DynamicData* data, const JobQueueEntry& job, JobPriority priority );
  224. /// Gets a new job. Note: this function should only be called at the start of the main loop.
  225. /// If you can you should call addAndGetNextJob
  226. JobStatus getNextJob( JobQueueEntry& job, WaitStatus waitStatus = WAIT_FOR_NEXT_JOB );
  227. enum FinishJobFlag
  228. {
  229. FINISH_FLAG_NORMAL,
  230. FINISH_FLAG_JUST_CALL_FINISH_CALLBACK
  231. };
  232. /// Call this to finish a job if you do not wish to get another job. If you wish to get another job it is faster to
  233. /// call finishJobAndGetNextJob. The FinishJobFlag should left to i ts default setting. It is used internally
  234. /// to just trigger the finish callback without decrementing the active jobs counter.
  235. void finishJob( const JobQueueEntry* oldJob, FinishJobFlag flag = FINISH_FLAG_NORMAL );
  236. //
  237. // Compound functions
  238. //
  239. /// Call this when one job is finished and you are not calling finishAddAndGetNextJob
  240. JobStatus finishJobAndGetNextJob( const JobQueueEntry* oldJob, JobQueueEntry& jobOut, WaitStatus waitStatus = WAIT_FOR_NEXT_JOB );
  241. /// Finishes a job and gets a new one
  242. /// This is faster than calling addJob and getNextJob separately, because it can do the
  243. /// entire operation in one critical section, rather than two critical sections.
  244. JobStatus finishAddAndGetNextJob( hkJobType oldJobType, JobPriority priority, JobQueueEntry& jobInOut, WaitStatus waitStatus = WAIT_FOR_NEXT_JOB );
  245. public:
  246. //
  247. // Internal helper functions
  248. //
  249. // Release a single waiting thread
  250. void releaseOneWaitingThread( DynamicData* data );
  251. // Check if a thread with the given threadType is waiting for a job on a semaphore.
  252. // If one thread is, release the semaphore
  253. void checkQueueAndReleaseOneWaitingThread( QueueIndex queueIndex, DynamicData* data );
  254. // Call this to release all waiting threads
  255. void releaseWaitingThreads(DynamicData* data);
  256. HK_FORCE_INLINE QueueIndex findNextJob( JobQueueEntry& jobOut, DynamicData* data );
  257. QueueIndex getQueueIndexForJob( hkJob& job );
  258. HK_FORCE_INLINE hkBool allQueuesEmpty( DynamicData* data );
  259. DynamicData* lockQueue( char* dynamicDataStorage );
  260. void unlockQueue( DynamicData* dynamicDataStorage );
  261. HK_FORCE_INLINE int getSemaphoreIndex( int threadNumber );
  262. public:
  263. HK_ALIGN( hkCriticalSection m_criticalSection, 64 );
  264. // Data to each time the queue is locked
  265. DynamicData* m_data;
  266. //
  267. // Static, locally set data
  268. //
  269. JobPopFunc m_popJobFunc; 
  270. FinishJobFunc m_finishJobFunc;
  271. public:
  272. // The number of jobs types the job queue will handle - a queue is created for each type
  273. int m_numJobTypes;
  274. // Offsets into the queue list, in order.
  275. // Note that SPU queus, if there, start from 0
  276. int m_cpuCacheQueuesBegin;
  277. int m_cpuCustomQueuesBegin;
  278. int m_cpuTypesQueuesBegin;
  279. int m_numJobQueues;
  280. struct CustomJobType
  281. {
  282. hkJobType m_jobType;
  283. hkUint8 m_jobSubType;
  284. hkUint8 m_queueId;
  285. };
  286. CustomJobType m_customJobs[CUSTOM_JOB_TYPE_MAX];
  287. int m_numCustomJobs;
  288. int m_cpuSemaphoreBegin; 
  289. int m_directMapSemaphoreEnd; 
  290. int m_masterThreadQueue;
  291. // Flags relating to how the hardware should be used
  292. hkJobQueueHwSetup m_hwSetup;
  293. int m_numSpuElfs;
  294. hkBool m_queryRulesAreUpdated;
  295. hkSemaphoreBusyWait* m_queueSemaphores[ MAX_NUM_THREAD_TYPES ]; // one semaphore for every thread (can be shared)
  296. int m_numQueueSemaphores;
  297. hkInt8 m_nextQueueToGet  [MAX_NUM_THREAD_TYPES][MAX_NUM_QUEUES + 2]; // +2 (end marker and padding)
  298. // Used to decide what semaphore to wait on for CPU threads.
  299. // SPU threads have a 1-1 mapping. CPU threads also go from 0-N but need a map to map them to the right semaphore
  300. // (depending on shared caches / custom jobs)
  301. hkInt8 m_cpuThreadIndexToSemaphoreIndex[ MAX_NUM_CPU_THREADS ]; 
  302. hkJobHandlerFuncs m_jobFuncs[HK_JOB_TYPE_MAX];
  303. //
  304. // Setup info
  305. //
  306. struct CustomJobTypeSetup
  307. {
  308. hkJobType m_jobType;
  309. hkUint8 m_jobSubType;
  310. int m_threadId;
  311. };
  312. hkArray<CustomJobTypeSetup> m_customJobSetup;
  313. };
  314. #include <Common/Base/Thread/JobQueue/hkJobQueue.inl>
  315. #endif // HK_BASE_THREAD_JOB_QUEUE_H
  316. /*
  317. * Havok SDK - NO SOURCE PC DOWNLOAD, BUILD(#20090216)
  318. * Confidential Information of Havok.  (C) Copyright 1999-2009
  319. * Telekinesys Research Limited t/a Havok. All Rights Reserved. The Havok
  320. * Logo, and the Havok buzzsaw logo are trademarks of Havok.  Title, ownership
  321. * rights, and intellectual property rights in the Havok software remain in
  322. * Havok and/or its suppliers.
  323. * Use of this software for evaluation purposes is subject to and indicates
  324. * acceptance of the End User licence Agreement for this product. A copy of
  325. * the license is included with this software and is also available at www.havok.com/tryhavok.
  326. */