Revision control
Copy as Markdown
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
// SPDX-FileCopyrightText: Copyright (c) 2008-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
#ifndef PX_BROADCAST_H
#define PX_BROADCAST_H
#include "foundation/PxInlineArray.h"
#include "foundation/PxSimpleTypes.h"
#include "foundation/PxErrorCallback.h"
#if !PX_DOXYGEN
namespace physx
{
#endif
/**
\brief Abstract listener class that listens to allocation and deallocation events from the
foundation memory system.
<b>Threading:</b> All methods of this class should be thread safe as it can be called from the user thread
or the physics processing thread(s).
*/
class PxAllocationListener
{
public:
/**
\brief callback when memory is allocated.
\param size Size of the allocation in bytes.
\param typeName Type this data is being allocated for.
\param filename File the allocation came from.
\param line the allocation came from.
\param allocatedMemory memory that will be returned from the allocation.
*/
virtual void onAllocation(size_t size, const char* typeName, const char* filename, int line,
void* allocatedMemory) = 0;
/**
\brief callback when memory is deallocated.
\param allocatedMemory memory just before allocation.
*/
virtual void onDeallocation(void* allocatedMemory) = 0;
protected:
virtual ~PxAllocationListener()
{
}
};
/**
\brief Broadcast class implementation, registering listeners.
<b>Threading:</b> All methods of this class should be thread safe as it can be called from the user thread
or the physics processing thread(s). There is not internal locking
*/
template <class Listener, class Base>
class PxBroadcast : public Base
{
public:
static const uint32_t MAX_NB_LISTENERS = 16;
/**
\brief The default constructor.
*/
PxBroadcast()
{
}
/**
\brief Register new listener.
\note It is NOT SAFE to register and deregister listeners while allocations may be taking place.
moreover, there is no thread safety to registration/deregistration.
\param listener Listener to register.
*/
void registerListener(Listener& listener)
{
if(mListeners.size() < MAX_NB_LISTENERS)
mListeners.pushBack(&listener);
}
/**
\brief Deregister an existing listener.
\note It is NOT SAFE to register and deregister listeners while allocations may be taking place.
moreover, there is no thread safety to registration/deregistration.
\param listener Listener to deregister.
*/
void deregisterListener(Listener& listener)
{
mListeners.findAndReplaceWithLast(&listener);
}
/**
\brief Get number of registered listeners.
\return Number of listeners.
*/
uint32_t getNbListeners() const
{
return mListeners.size();
}
/**
\brief Get an existing listener from given index.
\param index Index of the listener.
\return Listener on given index.
*/
Listener& getListener(uint32_t index)
{
PX_ASSERT(index <= mListeners.size());
return *mListeners[index];
}
protected:
virtual ~PxBroadcast()
{
}
physx::PxInlineArray<Listener*, MAX_NB_LISTENERS, physx::PxAllocator> mListeners;
};
/**
\brief Abstract base class for an application defined memory allocator that allows an external listener
to audit the memory allocations.
*/
class PxBroadcastingAllocator : public PxBroadcast<PxAllocationListener, PxAllocatorCallback>
{
PX_NOCOPY(PxBroadcastingAllocator)
public:
/**
\brief The default constructor.
*/
PxBroadcastingAllocator(PxAllocatorCallback& allocator, PxErrorCallback& error) : mAllocator(allocator), mError(error)
{
mListeners.clear();
}
/**
\brief The default constructor.
*/
virtual ~PxBroadcastingAllocator()
{
mListeners.clear();
}
/**
\brief Allocates size bytes of memory, which must be 16-byte aligned.
This method should never return NULL. If you run out of memory, then
you should terminate the app or take some other appropriate action.
<b>Threading:</b> This function should be thread safe as it can be called in the context of the user thread
and physics processing thread(s).
\param size Number of bytes to allocate.
\param typeName Name of the datatype that is being allocated
\param filename The source file which allocated the memory
\param line The source line which allocated the memory
\return The allocated block of memory.
*/
void* allocate(size_t size, const char* typeName, const char* filename, int line)
{
void* mem = mAllocator.allocate(size, typeName, filename, line);
if(!mem)
{
mError.reportError(PxErrorCode::eABORT, "User allocator returned NULL.", filename, line);
return NULL;
}
if((size_t(mem) & 15))
{
mError.reportError(PxErrorCode::eABORT, "Allocations must be 16-byte aligned.", filename, line);
return NULL;
}
for(uint32_t i = 0; i < mListeners.size(); i++)
mListeners[i]->onAllocation(size, typeName, filename, line, mem);
return mem;
}
/**
\brief Frees memory previously allocated by allocate().
<b>Threading:</b> This function should be thread safe as it can be called in the context of the user thread
and physics processing thread(s).
\param ptr Memory to free.
*/
void deallocate(void* ptr)
{
for(uint32_t i = 0; i < mListeners.size(); i++)
{
mListeners[i]->onDeallocation(ptr);
}
mAllocator.deallocate(ptr);
}
private:
PxAllocatorCallback& mAllocator;
PxErrorCallback& mError;
};
/**
\brief Abstract base class for an application defined error callback that allows an external listener
to report errors.
*/
class PxBroadcastingErrorCallback : public PxBroadcast<PxErrorCallback, PxErrorCallback>
{
PX_NOCOPY(PxBroadcastingErrorCallback)
public:
/**
\brief The default constructor.
*/
PxBroadcastingErrorCallback(PxErrorCallback& errorCallback)
{
registerListener(errorCallback);
}
/**
\brief The default destructor.
*/
virtual ~PxBroadcastingErrorCallback()
{
mListeners.clear();
}
/**
\brief Reports an error code.
\param code Error code, see #PxErrorCode
\param message Message to display.
\param file File error occured in.
\param line Line number error occured on.
*/
void reportError(PxErrorCode::Enum code, const char* message, const char* file, int line)
{
for(uint32_t i = 0; i < mListeners.size(); i++)
mListeners[i]->reportError(code, message, file, line);
}
};
#if !PX_DOXYGEN
} // namespace physx
#endif
#endif