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
19namespace 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 */
28class PxBaseTask
29{
30public:
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
105protected:
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 */
120class PxTask : public PxBaseTask
121{
122public:
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
210protected:
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 */
233class PxLightCpuTask : public PxBaseTask
234{
235public:
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
333protected:
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