// Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions // are met: // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // * Neither the name of NVIDIA CORPORATION nor the names of its // contributors may be used to endorse or promote products derived // from this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY // OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Copyright (c) 2008-2023 NVIDIA Corporation. All rights reserved. #ifndef PX_TASK_H #define PX_TASK_H #include "task/PxTaskManager.h" #include "task/PxCpuDispatcher.h" #include "foundation/PxAssert.h" #if !PX_DOXYGEN namespace physx { #endif /** * \brief Base class of all task types * * PxBaseTask defines a runnable reference counted task with built-in profiling. */ class PxBaseTask { public: PxBaseTask() : mContextID(0), mTm(NULL) {} virtual ~PxBaseTask() {} /** * \brief The user-implemented run method where the task's work should be performed * * run() methods must be thread safe, stack friendly (no alloca, etc), and * must never block. */ virtual void run() = 0; /** * \brief Return a user-provided task name for profiling purposes. * * It does not have to be unique, but unique names are helpful. * * \return The name of this task */ virtual const char* getName() const = 0; //! \brief Implemented by derived implementation classes virtual void addReference() = 0; //! \brief Implemented by derived implementation classes virtual void removeReference() = 0; //! \brief Implemented by derived implementation classes virtual int32_t getReference() const = 0; /** \brief Implemented by derived implementation classes * * A task may assume in its release() method that the task system no longer holds * references to it - so it may safely run its destructor, recycle itself, etc. * provided no additional user references to the task exist */ virtual void release() = 0; /** * \brief Return PxTaskManager to which this task was submitted * * Note, can return NULL if task was not submitted, or has been * completed. */ PX_FORCE_INLINE PxTaskManager* getTaskManager() const { return mTm; } PX_FORCE_INLINE void setContextId(PxU64 id) { mContextID = id; } PX_FORCE_INLINE PxU64 getContextId() const { return mContextID; } protected: PxU64 mContextID; //!< Context ID for profiler interface PxTaskManager* mTm; //!< Owning PxTaskManager instance friend class PxTaskMgr; }; /** * \brief A PxBaseTask implementation with deferred execution and full dependencies * * A PxTask must be submitted to a PxTaskManager to to be executed, Tasks may * optionally be named when they are submitted. */ class PxTask : public PxBaseTask { public: PxTask() : mTaskID(0) {} virtual ~PxTask() {} //! \brief Release method implementation virtual void release() PX_OVERRIDE { PX_ASSERT(mTm); // clear mTm before calling taskCompleted() for safety PxTaskManager* save = mTm; mTm = NULL; save->taskCompleted(*this); } //! \brief Inform the PxTaskManager this task must finish before the given // task is allowed to start. PX_INLINE void finishBefore(PxTaskID taskID) { PX_ASSERT(mTm); mTm->finishBefore(*this, taskID); } //! \brief Inform the PxTaskManager this task cannot start until the given // task has completed. PX_INLINE void startAfter(PxTaskID taskID) { PX_ASSERT(mTm); mTm->startAfter(*this, taskID); } /** * \brief Manually increment this task's reference count. The task will * not be allowed to run until removeReference() is called. */ virtual void addReference() PX_OVERRIDE { PX_ASSERT(mTm); mTm->addReference(mTaskID); } /** * \brief Manually decrement this task's reference count. If the reference * count reaches zero, the task will be dispatched. */ virtual void removeReference() PX_OVERRIDE { PX_ASSERT(mTm); mTm->decrReference(mTaskID); } /** * \brief Return the ref-count for this task */ virtual int32_t getReference() const PX_OVERRIDE { return mTm->getReference(mTaskID); } /** * \brief Return the unique ID for this task */ PX_INLINE PxTaskID getTaskID() const { return mTaskID; } /** * \brief Called by PxTaskManager at submission time for initialization * * Perform simulation step initialization here. */ virtual void submitted() { } protected: PxTaskID mTaskID; //!< ID assigned at submission friend class PxTaskMgr; }; /** * \brief A PxBaseTask implementation with immediate execution and simple dependencies * * A PxLightCpuTask bypasses the PxTaskManager launch dependencies and will be * submitted directly to your scene's CpuDispatcher. When the run() function * completes, it will decrement the reference count of the specified * continuation task. * * You must use a full-blown PxTask if you want your task to be resolved * by another PxTask, or you need more than a single dependency to be * resolved when your task completes, or your task will not run on the * CpuDispatcher. */ class PxLightCpuTask : public PxBaseTask { public: PxLightCpuTask() : mCont( NULL ) , mRefCount( 0 ) { } virtual ~PxLightCpuTask() { mTm = NULL; } /** * \brief Initialize this task and specify the task that will have its ref count decremented on completion. * * Submission is deferred until the task's mRefCount is decremented to zero. * Note that we only use the PxTaskManager to query the appropriate dispatcher. * * \param[in] tm The PxTaskManager this task is managed by * \param[in] c The task to be executed when this task has finished running */ PX_INLINE void setContinuation(PxTaskManager& tm, PxBaseTask* c) { PX_ASSERT(mRefCount == 0); mRefCount = 1; mCont = c; mTm = &tm; if(mCont) mCont->addReference(); } /** * \brief Initialize this task and specify the task that will have its ref count decremented on completion. * * This overload of setContinuation() queries the PxTaskManager from the continuation * task, which cannot be NULL. * \param[in] c The task to be executed after this task has finished running */ PX_INLINE void setContinuation(PxBaseTask* c) { PX_ASSERT(c); PX_ASSERT(mRefCount == 0); mRefCount = 1; mCont = c; if(mCont) { mCont->addReference(); mTm = mCont->getTaskManager(); PX_ASSERT(mTm); } } /** * \brief Retrieves continuation task */ PX_INLINE PxBaseTask* getContinuation() const { return mCont; } /** * \brief Manually decrement this task's reference count. If the reference * count reaches zero, the task will be dispatched. */ virtual void removeReference() PX_OVERRIDE { mTm->decrReference(*this); } /** \brief Return the ref-count for this task */ virtual int32_t getReference() const PX_OVERRIDE { return mRefCount; } /** * \brief Manually increment this task's reference count. The task will * not be allowed to run until removeReference() is called. */ virtual void addReference() PX_OVERRIDE { mTm->addReference(*this); } /** * \brief called by CpuDispatcher after run method has completed * * Decrements the continuation task's reference count, if specified. */ virtual void release() PX_OVERRIDE { if(mCont) mCont->removeReference(); } protected: PxBaseTask* mCont; //!< Continuation task, can be NULL volatile int32_t mRefCount; //!< PxTask is dispatched when reaches 0 friend class PxTaskMgr; }; #if !PX_DOXYGEN } // namespace physx #endif #endif