| 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 | #ifndef PSFOUNDATION_PSBROADCAST_H |
| 31 | #define PSFOUNDATION_PSBROADCAST_H |
| 32 | |
| 33 | #include "Ps.h" |
| 34 | #include "PsInlineArray.h" |
| 35 | |
| 36 | #include "foundation/PxSimpleTypes.h" |
| 37 | #include "foundation/PxErrorCallback.h" |
| 38 | |
| 39 | namespace physx |
| 40 | { |
| 41 | namespace shdfnd |
| 42 | { |
| 43 | |
| 44 | /** |
| 45 | \brief Abstract listener class that listens to allocation and deallocation events from the |
| 46 | foundation memory system. |
| 47 | |
| 48 | <b>Threading:</b> All methods of this class should be thread safe as it can be called from the user thread |
| 49 | or the physics processing thread(s). |
| 50 | */ |
| 51 | class AllocationListener |
| 52 | { |
| 53 | public: |
| 54 | /** |
| 55 | \brief callback when memory is allocated. |
| 56 | \param size Size of the allocation in bytes. |
| 57 | \param typeName Type this data is being allocated for. |
| 58 | \param filename File the allocation came from. |
| 59 | \param line the allocation came from. |
| 60 | \param allocatedMemory memory that will be returned from the allocation. |
| 61 | */ |
| 62 | virtual void onAllocation(size_t size, const char* typeName, const char* filename, int line, |
| 63 | void* allocatedMemory) = 0; |
| 64 | |
| 65 | /** |
| 66 | \brief callback when memory is deallocated. |
| 67 | \param allocatedMemory memory just before allocation. |
| 68 | */ |
| 69 | virtual void onDeallocation(void* allocatedMemory) = 0; |
| 70 | |
| 71 | protected: |
| 72 | virtual ~AllocationListener() |
| 73 | { |
| 74 | } |
| 75 | }; |
| 76 | |
| 77 | /** |
| 78 | \brief Broadcast class implementation, registering listeners. |
| 79 | |
| 80 | <b>Threading:</b> All methods of this class should be thread safe as it can be called from the user thread |
| 81 | or the physics processing thread(s). There is not internal locking |
| 82 | */ |
| 83 | template <class Listener, class Base> |
| 84 | class Broadcast : public Base |
| 85 | { |
| 86 | public: |
| 87 | static const uint32_t MAX_NB_LISTENERS = 16; |
| 88 | |
| 89 | /** |
| 90 | \brief The default constructor. |
| 91 | */ |
| 92 | Broadcast() |
| 93 | { |
| 94 | } |
| 95 | |
| 96 | /** |
| 97 | \brief Register new listener. |
| 98 | |
| 99 | \note It is NOT SAFE to register and deregister listeners while allocations may be taking place. |
| 100 | moreover, there is no thread safety to registration/deregistration. |
| 101 | |
| 102 | \param listener Listener to register. |
| 103 | */ |
| 104 | void registerListener(Listener& listener) |
| 105 | { |
| 106 | if(mListeners.size() < MAX_NB_LISTENERS) |
| 107 | mListeners.pushBack(&listener); |
| 108 | } |
| 109 | |
| 110 | /** |
| 111 | \brief Deregister an existing listener. |
| 112 | |
| 113 | \note It is NOT SAFE to register and deregister listeners while allocations may be taking place. |
| 114 | moreover, there is no thread safety to registration/deregistration. |
| 115 | |
| 116 | \param listener Listener to deregister. |
| 117 | */ |
| 118 | void deregisterListener(Listener& listener) |
| 119 | { |
| 120 | mListeners.findAndReplaceWithLast(&listener); |
| 121 | } |
| 122 | |
| 123 | /** |
| 124 | \brief Get number of registered listeners. |
| 125 | |
| 126 | \return Number of listeners. |
| 127 | */ |
| 128 | uint32_t getNbListeners() const |
| 129 | { |
| 130 | return mListeners.size(); |
| 131 | } |
| 132 | |
| 133 | /** |
| 134 | \brief Get an existing listener from given index. |
| 135 | |
| 136 | \param index Index of the listener. |
| 137 | \return Listener on given index. |
| 138 | */ |
| 139 | Listener& getListener(uint32_t index) |
| 140 | { |
| 141 | PX_ASSERT(index <= mListeners.size()); |
| 142 | return *mListeners[index]; |
| 143 | } |
| 144 | |
| 145 | protected: |
| 146 | virtual ~Broadcast() |
| 147 | { |
| 148 | } |
| 149 | |
| 150 | physx::shdfnd::InlineArray<Listener*, MAX_NB_LISTENERS, physx::shdfnd::NonTrackingAllocator> mListeners; |
| 151 | }; |
| 152 | |
| 153 | /** |
| 154 | \brief Abstract base class for an application defined memory allocator that allows an external listener |
| 155 | to audit the memory allocations. |
| 156 | */ |
| 157 | class BroadcastingAllocator : public Broadcast<AllocationListener, PxAllocatorCallback> |
| 158 | { |
| 159 | PX_NOCOPY(BroadcastingAllocator) |
| 160 | |
| 161 | public: |
| 162 | /** |
| 163 | \brief The default constructor. |
| 164 | */ |
| 165 | BroadcastingAllocator(PxAllocatorCallback& allocator, PxErrorCallback& error) : mAllocator(allocator), mError(error) |
| 166 | { |
| 167 | mListeners.clear(); |
| 168 | } |
| 169 | |
| 170 | /** |
| 171 | \brief The default constructor. |
| 172 | */ |
| 173 | virtual ~BroadcastingAllocator() |
| 174 | { |
| 175 | mListeners.clear(); |
| 176 | } |
| 177 | |
| 178 | /** |
| 179 | \brief Allocates size bytes of memory, which must be 16-byte aligned. |
| 180 | |
| 181 | This method should never return NULL. If you run out of memory, then |
| 182 | you should terminate the app or take some other appropriate action. |
| 183 | |
| 184 | <b>Threading:</b> This function should be thread safe as it can be called in the context of the user thread |
| 185 | and physics processing thread(s). |
| 186 | |
| 187 | \param size Number of bytes to allocate. |
| 188 | \param typeName Name of the datatype that is being allocated |
| 189 | \param filename The source file which allocated the memory |
| 190 | \param line The source line which allocated the memory |
| 191 | \return The allocated block of memory. |
| 192 | */ |
| 193 | void* allocate(size_t size, const char* typeName, const char* filename, int line) |
| 194 | { |
| 195 | void* mem = mAllocator.allocate(size, typeName, filename, line); |
| 196 | |
| 197 | if(!mem) |
| 198 | { |
| 199 | mError.reportError(code: PxErrorCode::eABORT, message: "User allocator returned NULL." , __FILE__, __LINE__); |
| 200 | return NULL; |
| 201 | } |
| 202 | |
| 203 | if((reinterpret_cast<size_t>(mem) & 15)) |
| 204 | { |
| 205 | mError.reportError(code: PxErrorCode::eABORT, message: "Allocations must be 16-byte aligned." , __FILE__, __LINE__); |
| 206 | return NULL; |
| 207 | } |
| 208 | |
| 209 | for(uint32_t i = 0; i < mListeners.size(); i++) |
| 210 | mListeners[i]->onAllocation(size, typeName, filename, line, allocatedMemory: mem); |
| 211 | |
| 212 | return mem; |
| 213 | } |
| 214 | |
| 215 | /** |
| 216 | \brief Frees memory previously allocated by allocate(). |
| 217 | |
| 218 | <b>Threading:</b> This function should be thread safe as it can be called in the context of the user thread |
| 219 | and physics processing thread(s). |
| 220 | |
| 221 | \param ptr Memory to free. |
| 222 | */ |
| 223 | void deallocate(void* ptr) |
| 224 | { |
| 225 | for(uint32_t i = 0; i < mListeners.size(); i++) |
| 226 | { |
| 227 | mListeners[i]->onDeallocation(allocatedMemory: ptr); |
| 228 | } |
| 229 | mAllocator.deallocate(ptr); |
| 230 | } |
| 231 | |
| 232 | private: |
| 233 | PxAllocatorCallback& mAllocator; |
| 234 | PxErrorCallback& mError; |
| 235 | }; |
| 236 | |
| 237 | /** |
| 238 | \brief Abstract base class for an application defined error callback that allows an external listener |
| 239 | to report errors. |
| 240 | */ |
| 241 | class BroadcastingErrorCallback : public Broadcast<PxErrorCallback, PxErrorCallback> |
| 242 | { |
| 243 | PX_NOCOPY(BroadcastingErrorCallback) |
| 244 | public: |
| 245 | /** |
| 246 | \brief The default constructor. |
| 247 | */ |
| 248 | BroadcastingErrorCallback(PxErrorCallback& errorCallback) |
| 249 | { |
| 250 | registerListener(listener&: errorCallback); |
| 251 | } |
| 252 | |
| 253 | /** |
| 254 | \brief The default destructor. |
| 255 | */ |
| 256 | virtual ~BroadcastingErrorCallback() |
| 257 | { |
| 258 | mListeners.clear(); |
| 259 | } |
| 260 | |
| 261 | /** |
| 262 | \brief Reports an error code. |
| 263 | \param code Error code, see #PxErrorCode |
| 264 | \param message Message to display. |
| 265 | \param file File error occured in. |
| 266 | \param line Line number error occured on. |
| 267 | */ |
| 268 | void reportError(PxErrorCode::Enum code, const char* message, const char* file, int line) |
| 269 | { |
| 270 | for(uint32_t i = 0; i < mListeners.size(); i++) |
| 271 | mListeners[i]->reportError(code, message, file, line); |
| 272 | } |
| 273 | }; |
| 274 | } |
| 275 | } // namespace physx |
| 276 | |
| 277 | #endif // PSFOUNDATION_PXBROADCAST_H |
| 278 | |