1 | /* |
2 | * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. |
3 | * |
4 | * NVIDIA CORPORATION and its licensors retain all intellectual property |
5 | * and proprietary rights in and to this software, related documentation |
6 | * and any modifications thereto. Any use, reproduction, disclosure or |
7 | * distribution of this software and related documentation without an express |
8 | * license agreement from NVIDIA CORPORATION is strictly prohibited. |
9 | */ |
10 | |
11 | #ifndef PX_TASK_H |
12 | #define PX_TASK_H |
13 | |
14 | #include "foundation/Px.h" |
15 | #include "pxtask/PxTaskManager.h" |
16 | #include "foundation/PxAssert.h" |
17 | |
18 | #ifndef PX_DOXYGEN |
19 | namespace physx |
20 | { |
21 | #endif |
22 | |
23 | /** |
24 | * \brief Base class of all task types |
25 | * |
26 | * PxBaseTask defines a runnable reference counted task with built-in profiling. |
27 | */ |
28 | class PxBaseTask |
29 | { |
30 | public: |
31 | PxBaseTask() : mEventID(0xFFFF), mProfileStat(0), mTm(0) {} |
32 | virtual ~PxBaseTask() {} |
33 | |
34 | /** |
35 | * \brief The user-implemented run method where the task's work should be performed |
36 | * |
37 | * run() methods must be thread safe, stack friendly (no alloca, etc), and |
38 | * must never block. |
39 | */ |
40 | virtual void run() = 0; |
41 | |
42 | /** |
43 | * \brief Return a user-provided task name for profiling purposes. |
44 | * |
45 | * It does not have to be unique, but unique names are helpful. |
46 | * |
47 | * \return The name of this task |
48 | */ |
49 | virtual const char* getName() const = 0; |
50 | |
51 | //! \brief Implemented by derived implementation classes |
52 | virtual void addReference() = 0; |
53 | //! \brief Implemented by derived implementation classes |
54 | virtual void removeReference() = 0; |
55 | //! \brief Implemented by derived implementation classes |
56 | virtual PxI32 getReference() const = 0; |
57 | |
58 | /** \brief Implemented by derived implementation classes |
59 | * |
60 | * A task may assume in its release() method that the task system no longer holds |
61 | * references to it - so it may safely run its destructor, recycle itself, etc. |
62 | * provided no additional user references to the task exist |
63 | */ |
64 | |
65 | virtual void release() = 0; |
66 | |
67 | /** |
68 | * \brief Execute user run method with wrapping profiling events. |
69 | * |
70 | * Optional entry point for use by CpuDispatchers. |
71 | * |
72 | * \param[in] threadId The threadId of the thread that executed the task. |
73 | */ |
74 | PX_INLINE void runProfiled(PxU32 threadId=0) |
75 | { |
76 | mTm->emitStartEvent(*this, threadId); |
77 | run(); |
78 | mTm->emitStopEvent(*this, threadId); |
79 | } |
80 | |
81 | /** |
82 | * \brief Specify stop event statistic |
83 | * |
84 | * If called before or while the task is executing, the given value |
85 | * will appear in the task's event bar in the profile viewer |
86 | * |
87 | * \param[in] stat The stat to signal when the task is finished |
88 | */ |
89 | PX_INLINE void setProfileStat( PxU16 stat ) |
90 | { |
91 | mProfileStat = stat; |
92 | } |
93 | |
94 | /** |
95 | * \brief Return PxTaskManager to which this task was submitted |
96 | * |
97 | * Note, can return NULL if task was not submitted, or has been |
98 | * completed. |
99 | */ |
100 | PX_INLINE PxTaskManager* getTaskManager() const |
101 | { |
102 | return mTm; |
103 | } |
104 | |
105 | protected: |
106 | PxU16 mEventID; //!< Registered profile event ID |
107 | PxU16 mProfileStat; //!< Profiling statistic |
108 | PxTaskManager* mTm; //!< Owning PxTaskManager instance |
109 | |
110 | friend class PxTaskMgr; |
111 | }; |
112 | |
113 | |
114 | /** |
115 | * \brief A PxBaseTask implementation with deferred execution and full dependencies |
116 | * |
117 | * A PxTask must be submitted to a PxTaskManager to to be executed, Tasks may |
118 | * optionally be named when they are submitted. |
119 | */ |
120 | class PxTask : public PxBaseTask |
121 | { |
122 | public: |
123 | PxTask() : mTaskID(0) {} |
124 | virtual ~PxTask() {} |
125 | |
126 | //! \brief Release method implementation |
127 | virtual void release() |
128 | { |
129 | PX_ASSERT(mTm); |
130 | |
131 | // clear mTm before calling taskCompleted() for safety |
132 | PxTaskManager* save = mTm; |
133 | mTm = NULL; |
134 | save->taskCompleted( *this ); |
135 | } |
136 | |
137 | //! \brief Inform the PxTaskManager this task must finish before the given |
138 | // task is allowed to start. |
139 | PX_INLINE void finishBefore( PxTaskID taskID ) |
140 | { |
141 | PX_ASSERT(mTm); |
142 | mTm->finishBefore( *this, taskID); |
143 | } |
144 | |
145 | //! \brief Inform the PxTaskManager this task cannot start until the given |
146 | // task has completed. |
147 | PX_INLINE void startAfter( PxTaskID taskID ) |
148 | { |
149 | PX_ASSERT(mTm); |
150 | mTm->startAfter( *this, taskID ); |
151 | } |
152 | |
153 | /** |
154 | * \brief Manually increment this task's reference count. The task will |
155 | * not be allowed to run until removeReference() is called. |
156 | */ |
157 | PX_INLINE void addReference() |
158 | { |
159 | PX_ASSERT(mTm); |
160 | mTm->addReference( mTaskID ); |
161 | } |
162 | |
163 | /** |
164 | * \brief Manually decrement this task's reference count. If the reference |
165 | * count reaches zero, the task will be dispatched. |
166 | */ |
167 | PX_INLINE void removeReference() |
168 | { |
169 | PX_ASSERT(mTm); |
170 | mTm->decrReference( mTaskID ); |
171 | } |
172 | |
173 | /** |
174 | * \brief Return the ref-count for this task |
175 | */ |
176 | PX_INLINE PxI32 getReference() const |
177 | { |
178 | return mTm->getReference( mTaskID ); |
179 | } |
180 | |
181 | /** |
182 | * \brief Return the unique ID for this task |
183 | */ |
184 | PX_INLINE PxTaskID getTaskID() const |
185 | { |
186 | return mTaskID; |
187 | } |
188 | |
189 | /** |
190 | * \brief Called by PxTaskManager at submission time for initialization |
191 | * |
192 | * Perform simulation step initialization here. |
193 | */ |
194 | virtual void submitted() |
195 | { |
196 | mStreamIndex = 0; |
197 | mPreSyncRequired = false; |
198 | mProfileStat = 0; |
199 | } |
200 | |
201 | /** |
202 | * \brief Specify that the GpuTask sync flag be set |
203 | */ |
204 | PX_INLINE void requestSyncPoint() |
205 | { |
206 | mPreSyncRequired = true; |
207 | } |
208 | |
209 | |
210 | protected: |
211 | PxTaskID mTaskID; //!< ID assigned at submission |
212 | PxU32 mStreamIndex; //!< GpuTask CUDA stream index |
213 | bool mPreSyncRequired; //!< GpuTask sync flag |
214 | |
215 | friend class PxTaskMgr; |
216 | friend class PxGpuWorkerThread; |
217 | }; |
218 | |
219 | |
220 | /** |
221 | * \brief A PxBaseTask implementation with immediate execution and simple dependencies |
222 | * |
223 | * A PxLightCpuTask bypasses the PxTaskManager launch dependencies and will be |
224 | * submitted directly to your scene's CpuDispatcher. When the run() function |
225 | * completes, it will decrement the reference count of the specified |
226 | * continuation task. |
227 | * |
228 | * You must use a full-blown PxTask if you want your task to be resolved |
229 | * by another PxTask, or you need more than a single dependency to be |
230 | * resolved when your task completes, or your task will not run on the |
231 | * CpuDispatcher. |
232 | */ |
233 | class PxLightCpuTask : public PxBaseTask |
234 | { |
235 | public: |
236 | PxLightCpuTask() |
237 | : mCont( NULL ) |
238 | , mRefCount( 0 ) |
239 | { |
240 | } |
241 | virtual ~PxLightCpuTask() |
242 | { |
243 | mTm = NULL; |
244 | } |
245 | |
246 | /** |
247 | * \brief Initialize this task and specify the task that will have its ref count decremented on completion. |
248 | * |
249 | * Submission is deferred until the task's mRefCount is decremented to zero. |
250 | * Note that we only use the PxTaskManager to query the appropriate dispatcher. |
251 | * |
252 | * \param[in] tm The PxTaskManager this task is managed by |
253 | * \param[in] c The task to be executed when this task has finished running |
254 | */ |
255 | PX_INLINE void setContinuation(PxTaskManager& tm, PxBaseTask* c) |
256 | { |
257 | PX_ASSERT( mRefCount == 0 ); |
258 | mRefCount = 1; |
259 | mCont = c; |
260 | mTm = &tm; |
261 | if( mCont ) |
262 | { |
263 | mCont->addReference(); |
264 | } |
265 | } |
266 | |
267 | /** |
268 | * \brief Initialize this task and specify the task that will have its ref count decremented on completion. |
269 | * |
270 | * This overload of setContinuation() queries the PxTaskManager from the continuation |
271 | * task, which cannot be NULL. |
272 | * \param[in] c The task to be executed after this task has finished running |
273 | */ |
274 | PX_INLINE void setContinuation( PxBaseTask* c ) |
275 | { |
276 | PX_ASSERT( c ); |
277 | PX_ASSERT( mRefCount == 0 ); |
278 | mRefCount = 1; |
279 | mCont = c; |
280 | if( mCont ) |
281 | { |
282 | mCont->addReference(); |
283 | mTm = mCont->getTaskManager(); |
284 | PX_ASSERT( mTm ); |
285 | } |
286 | } |
287 | |
288 | /** |
289 | * \brief Retrieves continuation task |
290 | */ |
291 | PX_INLINE PxBaseTask* getContinuation() const |
292 | { |
293 | return mCont; |
294 | } |
295 | |
296 | /** |
297 | * \brief Manually decrement this task's reference count. If the reference |
298 | * count reaches zero, the task will be dispatched. |
299 | */ |
300 | PX_INLINE void removeReference() |
301 | { |
302 | mTm->decrReference(*this); |
303 | } |
304 | |
305 | /** \brief Return the ref-count for this task */ |
306 | PX_INLINE PxI32 getReference() const |
307 | { |
308 | return mRefCount; |
309 | } |
310 | |
311 | /** |
312 | * \brief Manually increment this task's reference count. The task will |
313 | * not be allowed to run until removeReference() is called. |
314 | */ |
315 | PX_INLINE void addReference() |
316 | { |
317 | mTm->addReference(*this); |
318 | } |
319 | |
320 | /** |
321 | * \brief called by CpuDispatcher after run method has completed |
322 | * |
323 | * Decrements the continuation task's reference count, if specified. |
324 | */ |
325 | PX_INLINE void release() |
326 | { |
327 | if( mCont ) |
328 | { |
329 | mCont->removeReference(); |
330 | } |
331 | } |
332 | |
333 | protected: |
334 | |
335 | PxBaseTask* mCont; //!< Continuation task, can be NULL |
336 | volatile PxI32 mRefCount; //!< PxTask is dispatched when reaches 0 |
337 | |
338 | friend class PxTaskMgr; |
339 | }; |
340 | |
341 | #ifndef PX_DOXYGEN |
342 | } // end physx namespace |
343 | #endif |
344 | |
345 | #endif |
346 | |