1//
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions
4// are met:
5// * Redistributions of source code must retain the above copyright
6// notice, this list of conditions and the following disclaimer.
7// * Redistributions in binary form must reproduce the above copyright
8// notice, this list of conditions and the following disclaimer in the
9// documentation and/or other materials provided with the distribution.
10// * Neither the name of NVIDIA CORPORATION nor the names of its
11// contributors may be used to endorse or promote products derived
12// from this software without specific prior written permission.
13//
14// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
15// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
18// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25//
26// Copyright (c) 2008-2021 NVIDIA Corporation. All rights reserved.
27// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
28// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
29
30
31#ifndef PX_PHYSICS_COMMON_TASK
32#define PX_PHYSICS_COMMON_TASK
33
34#include "task/PxTask.h"
35#include "CmPhysXCommon.h"
36#include "PsUserAllocated.h"
37#include "PsAtomic.h"
38#include "PsMutex.h"
39#include "PsInlineArray.h"
40#include "PsFPU.h"
41
42namespace physx
43{
44namespace Cm
45{
46 // wrapper around the public PxLightCpuTask
47 // internal SDK tasks should be inherited from
48 // this and override the runInternal() method
49 // to ensure that the correct floating point
50 // state is set / reset during execution
51 class Task : public physx::PxLightCpuTask
52 {
53 public:
54 Task(PxU64 contextId)
55 {
56 mContextID = contextId;
57 }
58
59 virtual void run()
60 {
61#if PX_SWITCH // special case because default rounding mode is not nearest
62 PX_FPU_GUARD;
63#else
64 PX_SIMD_GUARD;
65#endif
66 runInternal();
67 }
68
69 virtual void runInternal()=0;
70 };
71
72 // same as Cm::Task but inheriting from physx::PxBaseTask
73 // instead of PxLightCpuTask
74 class BaseTask : public physx::PxBaseTask
75 {
76 public:
77
78 virtual void run()
79 {
80#if PX_SWITCH // special case because default rounding mode is not nearest
81 PX_FPU_GUARD;
82#else
83 PX_SIMD_GUARD;
84#endif
85 runInternal();
86 }
87
88 virtual void runInternal()=0;
89 };
90
91 template <class T, void (T::*Fn)(physx::PxBaseTask*) >
92 class DelegateTask : public Cm::Task, public shdfnd::UserAllocated
93 {
94 public:
95
96 DelegateTask(PxU64 contextID, T* obj, const char* name) : Cm::Task(contextID), mObj(obj), mName(name) {}
97
98 virtual void runInternal()
99 {
100 (mObj->*Fn)(mCont);
101 }
102
103 virtual const char* getName() const
104 {
105 return mName;
106 }
107
108 void setObject(T* obj) { mObj = obj; }
109
110 private:
111 T* mObj;
112 const char* mName;
113 };
114
115
116 /**
117 \brief A task that maintains a list of dependent tasks.
118
119 This task maintains a list of dependent tasks that have their reference counts
120 reduced on completion of the task.
121
122 The refcount is incremented every time a dependent task is added.
123 */
124 class FanoutTask : public Cm::BaseTask
125 {
126 PX_NOCOPY(FanoutTask)
127 public:
128 FanoutTask(PxU64 contextID, const char* name) : Cm::BaseTask(), mRefCount(0), mName(name), mNotifySubmission(false) { mContextID = contextID; }
129
130 virtual void runInternal() {}
131
132 virtual const char* getName() const { return mName; }
133
134 /**
135 Swap mDependents with mReferencesToRemove when refcount goes to 0.
136 */
137 virtual void removeReference()
138 {
139 shdfnd::Mutex::ScopedLock lock(mMutex);
140 if (!physx::shdfnd::atomicDecrement(val: &mRefCount))
141 {
142 // prevents access to mReferencesToRemove until release
143 physx::shdfnd::atomicIncrement(val: &mRefCount);
144 mNotifySubmission = false;
145 PX_ASSERT(mReferencesToRemove.empty());
146 for (PxU32 i = 0; i < mDependents.size(); i++)
147 mReferencesToRemove.pushBack(a: mDependents[i]);
148 mDependents.clear();
149 mTm->getCpuDispatcher()->submitTask(task&: *this);
150 }
151 }
152
153 /**
154 \brief Increases reference count
155 */
156 virtual void addReference()
157 {
158 shdfnd::Mutex::ScopedLock lock(mMutex);
159 physx::shdfnd::atomicIncrement(val: &mRefCount);
160 mNotifySubmission = true;
161 }
162
163 /**
164 \brief Return the ref-count for this task
165 */
166 PX_INLINE PxI32 getReference() const
167 {
168 return mRefCount;
169 }
170
171 /**
172 Sets the task manager. Doesn't increase the reference count.
173 */
174 PX_INLINE void setTaskManager(physx::PxTaskManager& tm)
175 {
176 mTm = &tm;
177 }
178
179 /**
180 Adds a dependent task. It also sets the task manager querying it from the dependent task.
181 The refcount is incremented every time a dependent task is added.
182 */
183 PX_INLINE void addDependent(physx::PxBaseTask& dependent)
184 {
185 shdfnd::Mutex::ScopedLock lock(mMutex);
186 physx::shdfnd::atomicIncrement(val: &mRefCount);
187 mTm = dependent.getTaskManager();
188 mDependents.pushBack(a: &dependent);
189 dependent.addReference();
190 mNotifySubmission = true;
191 }
192
193 /**
194 Reduces reference counts of the continuation task and the dependent tasks, also
195 clearing the copy of continuation and dependents task list.
196 */
197 virtual void release()
198 {
199 Ps::InlineArray<physx::PxBaseTask*, 10> referencesToRemove;
200
201 {
202 shdfnd::Mutex::ScopedLock lock(mMutex);
203
204 const PxU32 contCount = mReferencesToRemove.size();
205 referencesToRemove.reserve(capacity: contCount);
206 for (PxU32 i=0; i < contCount; ++i)
207 referencesToRemove.pushBack(a: mReferencesToRemove[i]);
208
209 mReferencesToRemove.clear();
210 // allow access to mReferencesToRemove again
211 if (mNotifySubmission)
212 {
213 removeReference();
214 }
215 else
216 {
217 physx::shdfnd::atomicDecrement(val: &mRefCount);
218 }
219
220 // the scoped lock needs to get freed before the continuation tasks get (potentially) submitted because
221 // those continuation tasks might trigger events that delete this task and corrupt the memory of the
222 // mutex (for example, assume this task is a member of the scene then the submitted tasks cause the simulation
223 // to finish and then the scene gets released which in turn will delete this task. When this task then finally
224 // continues the heap memory will be corrupted.
225 }
226
227 for (PxU32 i=0; i < referencesToRemove.size(); ++i)
228 referencesToRemove[i]->removeReference();
229 }
230
231 protected:
232 volatile PxI32 mRefCount;
233 const char* mName;
234 Ps::InlineArray<physx::PxBaseTask*, 4> mDependents;
235 Ps::InlineArray<physx::PxBaseTask*, 4> mReferencesToRemove;
236 bool mNotifySubmission;
237 Ps::Mutex mMutex; // guarding mDependents and mNotifySubmission
238 };
239
240
241 /**
242 \brief Specialization of FanoutTask class in order to provide the delegation mechanism.
243 */
244 template <class T, void (T::*Fn)(physx::PxBaseTask*) >
245 class DelegateFanoutTask : public FanoutTask, public shdfnd::UserAllocated
246 {
247 public:
248 DelegateFanoutTask(PxU64 contextID, T* obj, const char* name) :
249 FanoutTask(contextID, name), mObj(obj) { }
250
251 virtual void runInternal()
252 {
253 physx::PxBaseTask* continuation = mReferencesToRemove.empty() ? NULL : mReferencesToRemove[0];
254 (mObj->*Fn)(continuation);
255 }
256
257 void setObject(T* obj) { mObj = obj; }
258
259 private:
260 T* mObj;
261 };
262
263} // namespace Cm
264
265}
266
267#endif
268

source code of qtquick3dphysics/src/3rdparty/PhysX/source/common/src/CmTask.h