feat(physics): wire physx sdk into build
This commit is contained in:
28
engine/third_party/physx/source/foundation/FdAllocator.cpp
vendored
Normal file
28
engine/third_party/physx/source/foundation/FdAllocator.cpp
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
// 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-2025 NVIDIA Corporation. All rights reserved.
|
||||
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
|
||||
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
|
||||
|
||||
66
engine/third_party/physx/source/foundation/FdAssert.cpp
vendored
Normal file
66
engine/third_party/physx/source/foundation/FdAssert.cpp
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
// 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-2025 NVIDIA Corporation. All rights reserved.
|
||||
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
|
||||
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
|
||||
|
||||
#include "foundation/PxAssert.h"
|
||||
#include "foundation/PxString.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#if PX_WINDOWS_FAMILY
|
||||
#include <crtdbg.h>
|
||||
#elif PX_SWITCH
|
||||
#include "foundation/switch/PxSwitchAbort.h"
|
||||
#endif
|
||||
|
||||
void physx::PxAssert(const char* expr, const char* file, int line, bool& ignore)
|
||||
{
|
||||
PX_UNUSED(ignore); // is used only in debug windows config
|
||||
char buffer[1024];
|
||||
#if PX_WINDOWS_FAMILY
|
||||
sprintf_s(buffer, "%s(%d) : Assertion failed: %s\n", file, line, expr);
|
||||
#else
|
||||
sprintf(buffer, "%s(%d) : Assertion failed: %s\n", file, line, expr);
|
||||
#endif
|
||||
physx::PxPrintString(buffer);
|
||||
#if PX_WINDOWS_FAMILY&& PX_DEBUG && PX_DEBUG_CRT
|
||||
// _CrtDbgReport returns -1 on error, 1 on 'retry', 0 otherwise including 'ignore'.
|
||||
// Hitting 'abort' will terminate the process immediately.
|
||||
int result = _CrtDbgReport(_CRT_ASSERT, file, line, NULL, "%s", buffer);
|
||||
int mode = _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_REPORT_MODE);
|
||||
ignore = _CRTDBG_MODE_WNDW == mode && result == 0;
|
||||
if(ignore)
|
||||
return;
|
||||
__debugbreak();
|
||||
#elif PX_WINDOWS_FAMILY&& PX_CHECKED
|
||||
__debugbreak();
|
||||
#elif PX_SWITCH
|
||||
abort(buffer);
|
||||
#else
|
||||
abort();
|
||||
#endif
|
||||
}
|
||||
333
engine/third_party/physx/source/foundation/FdFoundation.cpp
vendored
Normal file
333
engine/third_party/physx/source/foundation/FdFoundation.cpp
vendored
Normal file
@@ -0,0 +1,333 @@
|
||||
// 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-2025 NVIDIA Corporation. All rights reserved.
|
||||
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
|
||||
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
|
||||
|
||||
#include "FdFoundation.h"
|
||||
#include "foundation/PxString.h"
|
||||
#include "foundation/PxPhysicsVersion.h"
|
||||
#include "foundation/PxUserAllocated.h"
|
||||
#include "foundation/PxBroadcast.h"
|
||||
|
||||
namespace physx
|
||||
{
|
||||
#if PX_VC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4251) // class needs to have dll-interface to be used by clients of class
|
||||
#endif
|
||||
|
||||
class PX_FOUNDATION_API Foundation : public PxFoundation, public PxUserAllocated
|
||||
{
|
||||
PX_NOCOPY(Foundation)
|
||||
|
||||
public:
|
||||
// PxFoundation
|
||||
virtual void release() PX_OVERRIDE;
|
||||
virtual PxErrorCallback& getErrorCallback() PX_OVERRIDE { return mErrorCallback; }
|
||||
virtual void setErrorLevel(PxErrorCode::Enum mask) PX_OVERRIDE { mErrorMask = mask; }
|
||||
virtual PxErrorCode::Enum getErrorLevel() const PX_OVERRIDE { return mErrorMask; }
|
||||
virtual PxAllocatorCallback& getAllocatorCallback() PX_OVERRIDE { return mAllocatorCallback; }
|
||||
virtual bool getReportAllocationNames() const PX_OVERRIDE { return mReportAllocationNames; }
|
||||
virtual void setReportAllocationNames(bool value) PX_OVERRIDE { mReportAllocationNames = value; }
|
||||
virtual void registerAllocationListener(physx::PxAllocationListener& listener) PX_OVERRIDE;
|
||||
virtual void deregisterAllocationListener(physx::PxAllocationListener& listener) PX_OVERRIDE;
|
||||
virtual void registerErrorCallback(PxErrorCallback& listener) PX_OVERRIDE;
|
||||
virtual void deregisterErrorCallback(PxErrorCallback& listener) PX_OVERRIDE;
|
||||
virtual bool error(PxErrorCode::Enum, const char* file, int line, const char* messageFmt, ...) PX_OVERRIDE;
|
||||
virtual bool error(PxErrorCode::Enum, const char* file, int line, const char* messageFmt, va_list) PX_OVERRIDE;
|
||||
//~PxFoundation
|
||||
|
||||
Foundation(PxErrorCallback& errc, PxAllocatorCallback& alloc);
|
||||
~Foundation();
|
||||
|
||||
// init order is tricky here: the mutexes require the allocator, the allocator may require the error stream
|
||||
PxAllocatorCallback& mAllocatorCallback;
|
||||
PxErrorCallback& mErrorCallback;
|
||||
|
||||
PxBroadcastingAllocator mBroadcastingAllocator;
|
||||
PxBroadcastingErrorCallback mBroadcastingError;
|
||||
|
||||
bool mReportAllocationNames;
|
||||
|
||||
PxErrorCode::Enum mErrorMask;
|
||||
Mutex mErrorMutex;
|
||||
|
||||
AllocFreeTable mTempAllocFreeTable;
|
||||
Mutex mTempAllocMutex;
|
||||
|
||||
Mutex mListenerMutex;
|
||||
|
||||
PxU32 mRefCount;
|
||||
static PxU32 mWarnOnceTimestap;
|
||||
};
|
||||
#if PX_VC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
} // namespace physx
|
||||
|
||||
using namespace physx;
|
||||
|
||||
static PxProfilerCallback* gProfilerCallback = NULL;
|
||||
static Foundation* gInstance = NULL;
|
||||
|
||||
// PT: not in header so that people don't use it, only for temp allocator, will be removed
|
||||
AllocFreeTable& getTempAllocFreeTable()
|
||||
{
|
||||
PX_ASSERT(gInstance);
|
||||
return gInstance->mTempAllocFreeTable;
|
||||
}
|
||||
|
||||
// PT: not in header so that people don't use it, only for temp allocator, will be removed
|
||||
Mutex& getTempAllocMutex()
|
||||
{
|
||||
PX_ASSERT(gInstance);
|
||||
return gInstance->mTempAllocMutex;
|
||||
}
|
||||
|
||||
Foundation::Foundation(PxErrorCallback& errc, PxAllocatorCallback& alloc) :
|
||||
mAllocatorCallback (alloc),
|
||||
mErrorCallback (errc),
|
||||
mBroadcastingAllocator (alloc, errc),
|
||||
mBroadcastingError (errc),
|
||||
#if PX_CHECKED
|
||||
mReportAllocationNames (true),
|
||||
#else
|
||||
mReportAllocationNames (false),
|
||||
#endif
|
||||
mErrorMask (PxErrorCode::Enum(~0)),
|
||||
mErrorMutex ("Foundation::mErrorMutex"),
|
||||
mTempAllocMutex ("Foundation::mTempAllocMutex"),
|
||||
mRefCount (0)
|
||||
{
|
||||
}
|
||||
|
||||
void deallocateTempBufferAllocations(AllocFreeTable& mTempAllocFreeTable);
|
||||
|
||||
Foundation::~Foundation()
|
||||
{
|
||||
deallocateTempBufferAllocations(mTempAllocFreeTable);
|
||||
}
|
||||
|
||||
bool Foundation::error(PxErrorCode::Enum c, const char* file, int line, const char* messageFmt, ...)
|
||||
{
|
||||
va_list va;
|
||||
va_start(va, messageFmt);
|
||||
error(c, file, line, messageFmt, va);
|
||||
va_end(va);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Foundation::error(PxErrorCode::Enum e, const char* file, int line, const char* messageFmt, va_list va)
|
||||
{
|
||||
PX_ASSERT(messageFmt);
|
||||
if(e & mErrorMask)
|
||||
{
|
||||
// this function is reentrant but user's error callback may not be, so...
|
||||
Mutex::ScopedLock lock(mErrorMutex);
|
||||
|
||||
// using a static fixed size buffer here because:
|
||||
// 1. vsnprintf return values differ between platforms
|
||||
// 2. va_start is only usable in functions with ellipses
|
||||
// 3. ellipses (...) cannot be passed to called function
|
||||
// which would be necessary to dynamically grow the buffer here
|
||||
|
||||
static const size_t bufSize = 1024;
|
||||
char stringBuffer[bufSize];
|
||||
Pxvsnprintf(stringBuffer, bufSize, messageFmt, va);
|
||||
|
||||
mBroadcastingError.reportError(e, stringBuffer, file, line);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Foundation::release()
|
||||
{
|
||||
PX_ASSERT(gInstance);
|
||||
|
||||
if(gInstance->mRefCount == 1)
|
||||
{
|
||||
PxAllocatorCallback& alloc = gInstance->getAllocatorCallback();
|
||||
gInstance->~Foundation();
|
||||
alloc.deallocate(gInstance);
|
||||
gInstance = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
gInstance->error(PxErrorCode::eINVALID_OPERATION, PX_FL,
|
||||
"Foundation destruction failed due to pending module references. Close/release all depending modules first.");
|
||||
}
|
||||
}
|
||||
|
||||
PxU32 Foundation::mWarnOnceTimestap = 0;
|
||||
|
||||
void Foundation::registerAllocationListener(PxAllocationListener& listener)
|
||||
{
|
||||
Mutex::ScopedLock lock(mListenerMutex);
|
||||
mBroadcastingAllocator.registerListener(listener);
|
||||
}
|
||||
|
||||
void Foundation::deregisterAllocationListener(PxAllocationListener& listener)
|
||||
{
|
||||
Mutex::ScopedLock lock(mListenerMutex);
|
||||
mBroadcastingAllocator.deregisterListener(listener);
|
||||
}
|
||||
|
||||
void Foundation::registerErrorCallback(PxErrorCallback& callback)
|
||||
{
|
||||
Mutex::ScopedLock lock(mListenerMutex);
|
||||
mBroadcastingError.registerListener(callback);
|
||||
}
|
||||
|
||||
void Foundation::deregisterErrorCallback(PxErrorCallback& callback)
|
||||
{
|
||||
Mutex::ScopedLock lock(mListenerMutex);
|
||||
mBroadcastingError.deregisterListener(callback);
|
||||
}
|
||||
|
||||
PxFoundation* PxCreateFoundation(PxU32 version, PxAllocatorCallback& allocator, PxErrorCallback& errorCallback)
|
||||
{
|
||||
if(version != PX_PHYSICS_VERSION)
|
||||
{
|
||||
char buffer[256];
|
||||
Pxsnprintf(buffer, 256, "Wrong version: physics version is 0x%08x, tried to create 0x%08x", PX_PHYSICS_VERSION, version);
|
||||
errorCallback.reportError(PxErrorCode::eINVALID_PARAMETER, buffer, PX_FL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(!gInstance)
|
||||
{
|
||||
// if we don't assign this here, the Foundation object can't create member
|
||||
// subobjects which require the allocator
|
||||
|
||||
gInstance = reinterpret_cast<Foundation*>(allocator.allocate(sizeof(Foundation), "Foundation", PX_FL));
|
||||
|
||||
if(gInstance)
|
||||
{
|
||||
PX_PLACEMENT_NEW(gInstance, Foundation)(errorCallback, allocator);
|
||||
|
||||
PX_ASSERT(gInstance->mRefCount == 0);
|
||||
gInstance->mRefCount = 1;
|
||||
|
||||
// skip 0 which marks uninitialized timestaps in PX_WARN_ONCE
|
||||
gInstance->mWarnOnceTimestap = (gInstance->mWarnOnceTimestap == PX_MAX_U32) ? 1 : gInstance->mWarnOnceTimestap + 1;
|
||||
|
||||
return gInstance;
|
||||
}
|
||||
else
|
||||
{
|
||||
errorCallback.reportError(PxErrorCode::eINTERNAL_ERROR, "Memory allocation for foundation object failed.", PX_FL);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
errorCallback.reportError(PxErrorCode::eINVALID_OPERATION, "Foundation object exists already. Only one instance per process can be created.", PX_FL);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void PxSetFoundationInstance(PxFoundation& foundation)
|
||||
{
|
||||
gInstance = &static_cast<Foundation&>(foundation);
|
||||
}
|
||||
|
||||
PxAllocatorCallback* PxGetAllocatorCallback()
|
||||
{
|
||||
return &gInstance->getAllocatorCallback();
|
||||
}
|
||||
|
||||
PxAllocatorCallback* PxGetBroadcastAllocator(bool* reportAllocationNames)
|
||||
{
|
||||
PX_ASSERT(gInstance);
|
||||
if(reportAllocationNames)
|
||||
*reportAllocationNames = gInstance->mReportAllocationNames;
|
||||
|
||||
return &gInstance->mBroadcastingAllocator;
|
||||
}
|
||||
|
||||
PxErrorCallback* PX_CALL_CONV PxGetErrorCallback()
|
||||
{
|
||||
return &gInstance->getErrorCallback();
|
||||
}
|
||||
|
||||
PxErrorCallback* PX_CALL_CONV PxGetBroadcastError()
|
||||
{
|
||||
return &gInstance->mBroadcastingError;
|
||||
}
|
||||
|
||||
PxFoundation& PxGetFoundation()
|
||||
{
|
||||
PX_ASSERT(gInstance);
|
||||
return *gInstance;
|
||||
}
|
||||
|
||||
PxFoundation* PxIsFoundationValid()
|
||||
{
|
||||
return gInstance;
|
||||
}
|
||||
|
||||
PxProfilerCallback* PxGetProfilerCallback()
|
||||
{
|
||||
return gProfilerCallback;
|
||||
}
|
||||
|
||||
void PxSetProfilerCallback(PxProfilerCallback* profiler)
|
||||
{
|
||||
gProfilerCallback = profiler;
|
||||
}
|
||||
|
||||
PxU32 PxGetWarnOnceTimeStamp()
|
||||
{
|
||||
PX_ASSERT(gInstance);
|
||||
return gInstance->mWarnOnceTimestap;
|
||||
}
|
||||
|
||||
void PxDecFoundationRefCount()
|
||||
{
|
||||
PX_ASSERT(gInstance);
|
||||
|
||||
if(gInstance->mRefCount > 0)
|
||||
gInstance->mRefCount--;
|
||||
else
|
||||
gInstance->error(PxErrorCode::eINVALID_OPERATION, PX_FL, "Foundation: Invalid deregistration detected.");
|
||||
}
|
||||
|
||||
void PxIncFoundationRefCount()
|
||||
{
|
||||
PX_ASSERT(gInstance);
|
||||
|
||||
if(gInstance->mRefCount > 0)
|
||||
gInstance->mRefCount++;
|
||||
else
|
||||
gInstance->error(PxErrorCode::eINVALID_OPERATION, PX_FL, "Foundation: Invalid registration detected.");
|
||||
}
|
||||
|
||||
// Private method to set the global foundation instance to NULL
|
||||
PX_C_EXPORT PX_FOUNDATION_API void PX_CALL_CONV PxResetFoundationInstance()
|
||||
{
|
||||
gInstance = NULL;
|
||||
}
|
||||
46
engine/third_party/physx/source/foundation/FdFoundation.h
vendored
Normal file
46
engine/third_party/physx/source/foundation/FdFoundation.h
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
// 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-2025 NVIDIA Corporation. All rights reserved.
|
||||
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
|
||||
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
|
||||
|
||||
#ifndef PX_FOUNDATION_PSFOUNDATION_H
|
||||
#define PX_FOUNDATION_PSFOUNDATION_H
|
||||
|
||||
#include "foundation/PxAllocator.h"
|
||||
#include "foundation/PxArray.h"
|
||||
#include "foundation/PxMutex.h"
|
||||
|
||||
namespace physx
|
||||
{
|
||||
union PxTempAllocatorChunk;
|
||||
|
||||
typedef PxMutexT<PxAllocator> Mutex;
|
||||
typedef PxArray<PxTempAllocatorChunk*, PxAllocator> AllocFreeTable;
|
||||
|
||||
} // namespace physx
|
||||
|
||||
|
||||
#endif
|
||||
209
engine/third_party/physx/source/foundation/FdMathUtils.cpp
vendored
Normal file
209
engine/third_party/physx/source/foundation/FdMathUtils.cpp
vendored
Normal file
@@ -0,0 +1,209 @@
|
||||
// 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-2025 NVIDIA Corporation. All rights reserved.
|
||||
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
|
||||
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
|
||||
|
||||
#include "foundation/PxSIMDHelpers.h"
|
||||
#include "foundation/PxMathUtils.h"
|
||||
#include "foundation/PxVec4.h"
|
||||
#include "foundation/PxAssert.h"
|
||||
#include "foundation/PxBasicTemplates.h"
|
||||
#include "foundation/PxUtilities.h"
|
||||
#include "foundation/PxTransform.h"
|
||||
|
||||
using namespace physx;
|
||||
using namespace physx::intrinsics;
|
||||
|
||||
PX_FOUNDATION_API PxTransform physx::PxTransformFromPlaneEquation(const PxPlane& plane)
|
||||
{
|
||||
PxPlane p = plane;
|
||||
p.normalize();
|
||||
|
||||
// special case handling for axis aligned planes
|
||||
const PxReal halfsqrt2 = 0.707106781f;
|
||||
PxQuat q;
|
||||
if(2 == (p.n.x == 0.0f) + (p.n.y == 0.0f) + (p.n.z == 0.0f)) // special handling for axis aligned planes
|
||||
{
|
||||
if(p.n.x > 0) q = PxQuat(PxIdentity);
|
||||
else if(p.n.x < 0) q = PxQuat(0, 0, 1.0f, 0);
|
||||
else q = PxQuat(0.0f, -p.n.z, p.n.y, 1.0f) * halfsqrt2;
|
||||
}
|
||||
else q = PxShortestRotation(PxVec3(1.f,0,0), p.n);
|
||||
|
||||
return PxTransform(-p.n * p.d, q);
|
||||
}
|
||||
|
||||
PX_FOUNDATION_API PxTransform physx::PxTransformFromSegment(const PxVec3& p0, const PxVec3& p1, PxReal* halfHeight)
|
||||
{
|
||||
const PxVec3 axis = p1-p0;
|
||||
const PxReal height = axis.magnitude();
|
||||
if(halfHeight)
|
||||
*halfHeight = height/2;
|
||||
|
||||
return PxTransform((p1+p0) * 0.5f,
|
||||
height<1e-6f ? PxQuat(PxIdentity) : PxShortestRotation(PxVec3(1.f,0,0), axis/height));
|
||||
}
|
||||
|
||||
PX_FOUNDATION_API PxQuat physx::PxShortestRotation(const PxVec3& v0, const PxVec3& v1)
|
||||
{
|
||||
const PxReal d = v0.dot(v1);
|
||||
const PxVec3 cross = v0.cross(v1);
|
||||
|
||||
const PxQuat q = d > -1 ? PxQuat(cross.x, cross.y, cross.z, 1 + d) : PxAbs(v0.x) < 0.1f ? PxQuat(0.0f, v0.z, -v0.y, 0.0f)
|
||||
: PxQuat(v0.y, -v0.x, 0.0f, 0.0f);
|
||||
|
||||
return q.getNormalized();
|
||||
}
|
||||
|
||||
// indexed rotation around axis, with sine and cosine of half-angle
|
||||
static PxQuat indexedRotation(PxU32 axis, PxReal s, PxReal c)
|
||||
{
|
||||
PxReal v[3] = { 0, 0, 0 };
|
||||
v[axis] = s;
|
||||
return PxQuat(v[0], v[1], v[2], c);
|
||||
}
|
||||
|
||||
PX_FOUNDATION_API PxVec3 physx::PxDiagonalize(const PxMat33& m, PxQuat& massFrame)
|
||||
{
|
||||
// jacobi rotation using quaternions (from an idea of Stan Melax, with fix for precision issues)
|
||||
|
||||
const PxU32 MAX_ITERS = 24;
|
||||
|
||||
PxQuat q(PxIdentity);
|
||||
|
||||
PxMat33 d;
|
||||
for(PxU32 i = 0; i < MAX_ITERS; i++)
|
||||
{
|
||||
// PT: removed for now, it makes one UT fail because the error is slightly above the threshold
|
||||
//const PxMat33Padded axes(q);
|
||||
const PxMat33 axes(q);
|
||||
d = axes.getTranspose() * m * axes;
|
||||
|
||||
const PxReal d0 = PxAbs(d[1][2]), d1 = PxAbs(d[0][2]), d2 = PxAbs(d[0][1]);
|
||||
const PxU32 a = PxU32(d0 > d1 && d0 > d2 ? 0 : d1 > d2 ? 1 : 2); // rotation axis index, from largest off-diagonal element
|
||||
|
||||
const PxU32 a1 = PxGetNextIndex3(a), a2 = PxGetNextIndex3(a1);
|
||||
if(d[a1][a2] == 0.0f || PxAbs(d[a1][a1] - d[a2][a2]) > 2e6f * PxAbs(2.0f * d[a1][a2]))
|
||||
break;
|
||||
|
||||
const PxReal w = (d[a1][a1] - d[a2][a2]) / (2.0f * d[a1][a2]); // cot(2 * phi), where phi is the rotation angle
|
||||
const PxReal absw = PxAbs(w);
|
||||
|
||||
PxQuat r;
|
||||
if(absw > 1000)
|
||||
r = indexedRotation(a, 1.0f / (4.0f * w), 1.0f); // h will be very close to 1, so use small angle approx instead
|
||||
else
|
||||
{
|
||||
const PxReal t = 1.0f / (absw + PxSqrt(w * w + 1.0f)); // absolute value of tan phi
|
||||
const PxReal h = 1.0f / PxSqrt(t * t + 1.0f); // absolute value of cos phi
|
||||
|
||||
PX_ASSERT(h != 1); // |w|<1000 guarantees this with typical IEEE754 machine eps (approx 6e-8)
|
||||
r = indexedRotation(a, PxSqrt((1.0f - h) / 2.0f) * PxSign(w), PxSqrt((1.0f + h) / 2.0f));
|
||||
}
|
||||
|
||||
q = (q * r).getNormalized();
|
||||
}
|
||||
|
||||
massFrame = q;
|
||||
return PxVec3(d.column0.x, d.column1.y, d.column2.z);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief computes a oriented bounding box around the scaled basis.
|
||||
\param basis Input = skewed basis, Output = (normalized) orthogonal basis.
|
||||
\return Bounding box extent.
|
||||
*/
|
||||
PxVec3 physx::PxOptimizeBoundingBox(PxMat33& basis)
|
||||
{
|
||||
PxVec3* PX_RESTRICT vec = &basis[0]; // PT: don't copy vectors if not needed...
|
||||
|
||||
// PT: since we store the magnitudes to memory, we can avoid the FCMPs afterwards
|
||||
PxVec3 magnitude(vec[0].magnitudeSquared(), vec[1].magnitudeSquared(), vec[2].magnitudeSquared());
|
||||
|
||||
// find indices sorted by magnitude
|
||||
unsigned int i = magnitude[1] > magnitude[0] ? 1 : 0u;
|
||||
unsigned int j = magnitude[2] > magnitude[1 - i] ? 2 : 1 - i;
|
||||
const unsigned int k = 3 - i - j;
|
||||
|
||||
if(magnitude[i] < magnitude[j])
|
||||
PxSwap(i, j);
|
||||
|
||||
PX_ASSERT(magnitude[i] >= magnitude[j] && magnitude[i] >= magnitude[k] && magnitude[j] >= magnitude[k]);
|
||||
|
||||
// ortho-normalize basis
|
||||
|
||||
PxReal invSqrt = PxRecipSqrt(magnitude[i]);
|
||||
magnitude[i] *= invSqrt;
|
||||
vec[i] *= invSqrt; // normalize the first axis
|
||||
PxReal dotij = vec[i].dot(vec[j]);
|
||||
PxReal dotik = vec[i].dot(vec[k]);
|
||||
magnitude[i] += PxAbs(dotij) + PxAbs(dotik); // elongate the axis by projection of the other two
|
||||
vec[j] -= vec[i] * dotij; // orthogonize the two remaining axii relative to vec[i]
|
||||
vec[k] -= vec[i] * dotik;
|
||||
|
||||
magnitude[j] = vec[j].normalize();
|
||||
PxReal dotjk = vec[j].dot(vec[k]);
|
||||
magnitude[j] += PxAbs(dotjk); // elongate the axis by projection of the other one
|
||||
vec[k] -= vec[j] * dotjk; // orthogonize vec[k] relative to vec[j]
|
||||
|
||||
magnitude[k] = vec[k].normalize();
|
||||
|
||||
return magnitude;
|
||||
}
|
||||
|
||||
void physx::PxIntegrateTransform(const PxTransform& curTrans, const PxVec3& linvel, const PxVec3& angvel,
|
||||
PxReal timeStep, PxTransform& result)
|
||||
{
|
||||
result.p = curTrans.p + linvel * timeStep;
|
||||
|
||||
// from void DynamicsContext::integrateAtomPose(PxsRigidBody* atom, Cm::BitMap &shapeChangedMap) const:
|
||||
// Integrate the rotation using closed form quaternion integrator
|
||||
PxReal w = angvel.magnitudeSquared();
|
||||
|
||||
if (w != 0.0f)
|
||||
{
|
||||
w = PxSqrt(w);
|
||||
if (w != 0.0f)
|
||||
{
|
||||
const PxReal v = timeStep * w * 0.5f;
|
||||
const PxReal q = PxCos(v);
|
||||
const PxReal s = PxSin(v) / w;
|
||||
|
||||
const PxVec3 pqr = angvel * s;
|
||||
const PxQuat quatVel(pqr.x, pqr.y, pqr.z, 0);
|
||||
PxQuat out; // need to have temporary, otherwise we may overwrite input if &curTrans == &result.
|
||||
out = quatVel * curTrans.q;
|
||||
out.x += curTrans.q.x * q;
|
||||
out.y += curTrans.q.y * q;
|
||||
out.z += curTrans.q.z * q;
|
||||
out.w += curTrans.q.w * q;
|
||||
result.q = out;
|
||||
return;
|
||||
}
|
||||
}
|
||||
// orientation stays the same - convert from quat to matrix:
|
||||
result.q = curTrans.q;
|
||||
}
|
||||
170
engine/third_party/physx/source/foundation/FdString.cpp
vendored
Normal file
170
engine/third_party/physx/source/foundation/FdString.cpp
vendored
Normal file
@@ -0,0 +1,170 @@
|
||||
// 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-2025 NVIDIA Corporation. All rights reserved.
|
||||
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
|
||||
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
|
||||
|
||||
#include "foundation/PxString.h"
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#if PX_WINDOWS_FAMILY
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4996) // unsafe string functions
|
||||
#endif
|
||||
|
||||
#if PX_APPLE_FAMILY
|
||||
#pragma clang diagnostic push
|
||||
// error : format string is not a string literal
|
||||
#pragma clang diagnostic ignored "-Wformat-nonliteral"
|
||||
#endif
|
||||
|
||||
namespace physx
|
||||
{
|
||||
// cross-platform implementations
|
||||
|
||||
int32_t Pxstrcmp(const char* str1, const char* str2)
|
||||
{
|
||||
return (str1 && str2) ? ::strcmp(str1, str2) : -1;
|
||||
}
|
||||
|
||||
int32_t Pxstrncmp(const char* str1, const char* str2, size_t count)
|
||||
{
|
||||
return ::strncmp(str1, str2, count);
|
||||
}
|
||||
|
||||
int32_t Pxsnprintf(char* dst, size_t dstSize, const char* format, ...)
|
||||
{
|
||||
va_list arg;
|
||||
va_start(arg, format);
|
||||
int32_t r = Pxvsnprintf(dst, dstSize, format, arg);
|
||||
va_end(arg);
|
||||
return r;
|
||||
}
|
||||
|
||||
int32_t Pxsscanf(const char* buffer, const char* format, ...)
|
||||
{
|
||||
va_list arg;
|
||||
va_start(arg, format);
|
||||
#if (PX_VC < 12) && !PX_LINUX
|
||||
int32_t r = ::sscanf(buffer, format, arg);
|
||||
#else
|
||||
int32_t r = ::vsscanf(buffer, format, arg);
|
||||
#endif
|
||||
va_end(arg);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
size_t Pxstrlcpy(char* dst, size_t dstSize, const char* src)
|
||||
{
|
||||
size_t i = 0;
|
||||
if(dst && dstSize)
|
||||
{
|
||||
for(; i + 1 < dstSize && src[i]; i++) // copy up to dstSize-1 bytes
|
||||
dst[i] = src[i];
|
||||
dst[i] = 0; // always null-terminate
|
||||
}
|
||||
|
||||
while(src[i]) // read any remaining characters in the src string to get the length
|
||||
i++;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
size_t Pxstrlcat(char* dst, size_t dstSize, const char* src)
|
||||
{
|
||||
size_t i = 0, s = 0;
|
||||
if(dst && dstSize)
|
||||
{
|
||||
s = strlen(dst);
|
||||
for(; i + s + 1 < dstSize && src[i]; i++) // copy until total is at most dstSize-1
|
||||
dst[i + s] = src[i];
|
||||
dst[i + s] = 0; // always null-terminate
|
||||
}
|
||||
|
||||
while(src[i]) // read any remaining characters in the src string to get the length
|
||||
i++;
|
||||
|
||||
return i + s;
|
||||
}
|
||||
|
||||
void Pxstrlwr(char* str)
|
||||
{
|
||||
for(; *str; str++)
|
||||
if(*str >= 'A' && *str <= 'Z')
|
||||
*str += 32;
|
||||
}
|
||||
|
||||
void Pxstrupr(char* str)
|
||||
{
|
||||
for(; *str; str++)
|
||||
if(*str >= 'a' && *str <= 'z')
|
||||
*str -= 32;
|
||||
}
|
||||
|
||||
int32_t Pxvsnprintf(char* dst, size_t dstSize, const char* src, va_list arg)
|
||||
{
|
||||
|
||||
#if PX_VC // MSVC is not C99-compliant...
|
||||
int32_t result = dst ? ::vsnprintf(dst, dstSize, src, arg) : -1;
|
||||
if(dst && (result == int32_t(dstSize) || result < 0))
|
||||
dst[dstSize - 1] = 0; // string was truncated or there wasn't room for the NULL
|
||||
if(result < 0)
|
||||
result = _vscprintf(src, arg); // work out how long the answer would have been.
|
||||
#else
|
||||
int32_t result = ::vsnprintf(dst, dstSize, src, arg);
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
int32_t Pxstricmp(const char* str, const char* str1)
|
||||
{
|
||||
#if PX_VC
|
||||
return (::_stricmp(str, str1));
|
||||
#else
|
||||
return (::strcasecmp(str, str1));
|
||||
#endif
|
||||
}
|
||||
|
||||
int32_t Pxstrnicmp(const char* str, const char* str1, size_t n)
|
||||
{
|
||||
#if PX_VC
|
||||
return (::_strnicmp(str, str1, n));
|
||||
#else
|
||||
return (::strncasecmp(str, str1, n));
|
||||
#endif
|
||||
}
|
||||
|
||||
}//namespace physx
|
||||
|
||||
#if PX_APPLE_FAMILY
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
#if PX_WINDOWS_FAMILY
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
145
engine/third_party/physx/source/foundation/FdTempAllocator.cpp
vendored
Normal file
145
engine/third_party/physx/source/foundation/FdTempAllocator.cpp
vendored
Normal file
@@ -0,0 +1,145 @@
|
||||
// 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-2025 NVIDIA Corporation. All rights reserved.
|
||||
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
|
||||
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
|
||||
|
||||
#include "foundation/PxMath.h"
|
||||
#include "foundation/PxIntrinsics.h"
|
||||
#include "foundation/PxBitUtils.h"
|
||||
#include "foundation/PxArray.h"
|
||||
#include "foundation/PxMutex.h"
|
||||
#include "foundation/PxAtomic.h"
|
||||
#include "foundation/PxTempAllocator.h"
|
||||
|
||||
#include "FdFoundation.h"
|
||||
|
||||
#if PX_VC
|
||||
#pragma warning(disable : 4706) // assignment within conditional expression
|
||||
#endif
|
||||
|
||||
physx::AllocFreeTable& getTempAllocFreeTable();
|
||||
physx::Mutex& getTempAllocMutex();
|
||||
|
||||
namespace physx
|
||||
{
|
||||
union PxTempAllocatorChunk
|
||||
{
|
||||
PxTempAllocatorChunk* mNext; // while chunk is free
|
||||
PxU32 mIndex; // while chunk is allocated
|
||||
PxU8 mPad[16]; // 16 byte aligned allocations
|
||||
};
|
||||
namespace
|
||||
{
|
||||
typedef PxTempAllocatorChunk Chunk;
|
||||
|
||||
const PxU32 sMinIndex = 8; // 256B min
|
||||
const PxU32 sMaxIndex = 17; // 128kB max
|
||||
}
|
||||
|
||||
void* PxTempAllocator::allocate(size_t size, const char* filename, PxI32 line)
|
||||
{
|
||||
if(!size)
|
||||
return 0;
|
||||
|
||||
PxU32 index = PxMax(PxHighestSetBit(PxU32(size) + sizeof(Chunk) - 1), sMinIndex);
|
||||
|
||||
Chunk* chunk = 0;
|
||||
if(index < sMaxIndex)
|
||||
{
|
||||
Mutex::ScopedLock lock(getTempAllocMutex());
|
||||
|
||||
// find chunk up to 16x bigger than necessary
|
||||
AllocFreeTable& freeTable = getTempAllocFreeTable();
|
||||
Chunk** it = freeTable.begin() + index - sMinIndex;
|
||||
Chunk** end = PxMin(it + 3, freeTable.end());
|
||||
while(it < end && !(*it))
|
||||
++it;
|
||||
|
||||
if(it < end)
|
||||
{
|
||||
// pop top off freelist
|
||||
chunk = *it;
|
||||
*it = chunk->mNext;
|
||||
index = PxU32(it - freeTable.begin() + sMinIndex);
|
||||
}
|
||||
else
|
||||
// create new chunk
|
||||
chunk = reinterpret_cast<Chunk*>(PxAllocator().allocate(size_t(2 << index), filename, line));
|
||||
}
|
||||
else
|
||||
{
|
||||
// too big for temp allocation, forward to base allocator
|
||||
chunk = reinterpret_cast<Chunk*>(PxAllocator().allocate(size + sizeof(Chunk), filename, line));
|
||||
}
|
||||
|
||||
chunk->mIndex = index;
|
||||
void* ret = chunk + 1;
|
||||
PX_ASSERT((size_t(ret) & 0xf) == 0); // SDK types require at minimum 16 byte alignment.
|
||||
return ret;
|
||||
}
|
||||
|
||||
void PxTempAllocator::deallocate(void* ptr)
|
||||
{
|
||||
if(!ptr)
|
||||
return;
|
||||
|
||||
Chunk* chunk = reinterpret_cast<Chunk*>(ptr) - 1;
|
||||
PxU32 index = chunk->mIndex;
|
||||
|
||||
if(index >= sMaxIndex)
|
||||
return PxAllocator().deallocate(chunk);
|
||||
|
||||
Mutex::ScopedLock lock(getTempAllocMutex());
|
||||
|
||||
index -= sMinIndex;
|
||||
|
||||
AllocFreeTable& freeTable = getTempAllocFreeTable();
|
||||
|
||||
if(freeTable.size() <= index)
|
||||
freeTable.resize(index + 1);
|
||||
|
||||
chunk->mNext = freeTable[index];
|
||||
freeTable[index] = chunk;
|
||||
}
|
||||
|
||||
} // namespace physx
|
||||
|
||||
using namespace physx;
|
||||
|
||||
void deallocateTempBufferAllocations(AllocFreeTable& mTempAllocFreeTable)
|
||||
{
|
||||
PxAllocator alloc;
|
||||
for(PxU32 i = 0; i < mTempAllocFreeTable.size(); ++i)
|
||||
{
|
||||
for(PxTempAllocatorChunk* ptr = mTempAllocFreeTable[i]; ptr;)
|
||||
{
|
||||
PxTempAllocatorChunk* next = ptr->mNext;
|
||||
alloc.deallocate(ptr);
|
||||
ptr = next;
|
||||
}
|
||||
}
|
||||
mTempAllocFreeTable.reset();
|
||||
}
|
||||
171
engine/third_party/physx/source/foundation/unix/FdUnixAtomic.cpp
vendored
Normal file
171
engine/third_party/physx/source/foundation/unix/FdUnixAtomic.cpp
vendored
Normal file
@@ -0,0 +1,171 @@
|
||||
// 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-2025 NVIDIA Corporation. All rights reserved.
|
||||
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
|
||||
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
|
||||
|
||||
#include "foundation/PxAtomic.h"
|
||||
|
||||
#if ! PX_EMSCRIPTEN
|
||||
#define PAUSE() asm("nop")
|
||||
#else
|
||||
#define PAUSE()
|
||||
#endif
|
||||
|
||||
namespace physx
|
||||
{
|
||||
|
||||
void* PxAtomicCompareExchangePointer(volatile void** dest, void* exch, void* comp)
|
||||
{
|
||||
return __sync_val_compare_and_swap(const_cast<void**>(dest), comp, exch);
|
||||
}
|
||||
|
||||
PxI32 PxAtomicCompareExchange(volatile PxI32* dest, PxI32 exch, PxI32 comp)
|
||||
{
|
||||
return __sync_val_compare_and_swap(dest, comp, exch);
|
||||
}
|
||||
|
||||
PxI64 PxAtomicCompareExchange(volatile PxI64* dest, PxI64 exch, PxI64 comp)
|
||||
{
|
||||
return __sync_val_compare_and_swap(dest, comp, exch);
|
||||
}
|
||||
|
||||
PxI32 PxAtomicIncrement(volatile PxI32* val)
|
||||
{
|
||||
return __sync_add_and_fetch(val, 1);
|
||||
}
|
||||
|
||||
PxI64 PxAtomicIncrement(volatile PxI64* val)
|
||||
{
|
||||
return __sync_add_and_fetch(val, 1);
|
||||
}
|
||||
|
||||
PxI32 PxAtomicDecrement(volatile PxI32* val)
|
||||
{
|
||||
return __sync_sub_and_fetch(val, 1);
|
||||
}
|
||||
|
||||
PxI64 PxAtomicDecrement(volatile PxI64* val)
|
||||
{
|
||||
return __sync_sub_and_fetch(val, 1);
|
||||
}
|
||||
|
||||
PxI32 PxAtomicAdd(volatile PxI32* val, PxI32 delta)
|
||||
{
|
||||
return __sync_add_and_fetch(val, delta);
|
||||
}
|
||||
|
||||
PxI64 PxAtomicAdd(volatile PxI64* val, PxI64 delta)
|
||||
{
|
||||
return __sync_add_and_fetch(val, delta);
|
||||
}
|
||||
|
||||
PxI32 PxAtomicMax(volatile PxI32* val, PxI32 val2)
|
||||
{
|
||||
PxI32 oldVal, newVal;
|
||||
|
||||
do
|
||||
{
|
||||
PAUSE();
|
||||
oldVal = *val;
|
||||
|
||||
if(val2 > oldVal)
|
||||
newVal = val2;
|
||||
else
|
||||
newVal = oldVal;
|
||||
|
||||
} while(PxAtomicCompareExchange(val, newVal, oldVal) != oldVal);
|
||||
|
||||
return *val;
|
||||
}
|
||||
|
||||
PxI64 PxAtomicMax(volatile PxI64* val, PxI64 val2)
|
||||
{
|
||||
PxI64 oldVal, newVal;
|
||||
|
||||
do
|
||||
{
|
||||
PAUSE();
|
||||
oldVal = *val;
|
||||
|
||||
if(val2 > oldVal)
|
||||
newVal = val2;
|
||||
else
|
||||
newVal = oldVal;
|
||||
|
||||
} while(PxAtomicCompareExchange(val, newVal, oldVal) != oldVal);
|
||||
|
||||
return *val;
|
||||
}
|
||||
|
||||
PxI32 PxAtomicExchange(volatile PxI32* val, PxI32 val2)
|
||||
{
|
||||
PxI32 newVal, oldVal;
|
||||
|
||||
do
|
||||
{
|
||||
PAUSE();
|
||||
oldVal = *val;
|
||||
newVal = val2;
|
||||
} while(PxAtomicCompareExchange(val, newVal, oldVal) != oldVal);
|
||||
|
||||
return oldVal;
|
||||
}
|
||||
|
||||
PxI64 PxAtomicExchange(volatile PxI64* val, PxI64 val2)
|
||||
{
|
||||
PxI64 newVal, oldVal;
|
||||
|
||||
do
|
||||
{
|
||||
PAUSE();
|
||||
oldVal = *val;
|
||||
newVal = val2;
|
||||
} while(PxAtomicCompareExchange(val, newVal, oldVal) != oldVal);
|
||||
|
||||
return oldVal;
|
||||
}
|
||||
|
||||
PxI32 PxAtomicOr(volatile PxI32* val, PxI32 mask)
|
||||
{
|
||||
return __sync_or_and_fetch(val, mask);
|
||||
}
|
||||
|
||||
PxI64 PxAtomicOr(volatile PxI64* val, PxI64 mask)
|
||||
{
|
||||
return __sync_or_and_fetch(val, mask);
|
||||
}
|
||||
|
||||
PxI32 PxAtomicAnd(volatile PxI32* val, PxI32 mask)
|
||||
{
|
||||
return __sync_and_and_fetch(val, mask);
|
||||
}
|
||||
|
||||
PxI64 PxAtomicAnd(volatile PxI64* val, PxI64 mask)
|
||||
{
|
||||
return __sync_and_and_fetch(val, mask);
|
||||
}
|
||||
|
||||
} // namespace physx
|
||||
107
engine/third_party/physx/source/foundation/unix/FdUnixFPU.cpp
vendored
Normal file
107
engine/third_party/physx/source/foundation/unix/FdUnixFPU.cpp
vendored
Normal file
@@ -0,0 +1,107 @@
|
||||
// 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-2025 NVIDIA Corporation. All rights reserved.
|
||||
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
|
||||
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
|
||||
#include "foundation/PxFPU.h"
|
||||
|
||||
#if !defined(__CYGWIN__)
|
||||
#include <fenv.h>
|
||||
PX_COMPILE_TIME_ASSERT(8 * sizeof(uint32_t) >= sizeof(fenv_t));
|
||||
#endif
|
||||
|
||||
#if PX_OSX
|
||||
// osx defines SIMD as standard for floating point operations.
|
||||
#include <xmmintrin.h>
|
||||
#endif
|
||||
|
||||
physx::PxFPUGuard::PxFPUGuard()
|
||||
{
|
||||
#if defined(__CYGWIN__)
|
||||
#pragma message "FPUGuard::FPUGuard() is not implemented"
|
||||
#elif PX_OSX
|
||||
mControlWords[0] = _mm_getcsr();
|
||||
// set default (disable exceptions: _MM_MASK_MASK) and FTZ (_MM_FLUSH_ZERO_ON), DAZ (_MM_DENORMALS_ZERO_ON: (1<<6))
|
||||
_mm_setcsr(_MM_MASK_MASK | _MM_FLUSH_ZERO_ON | (1 << 6));
|
||||
#elif defined(__EMSCRIPTEN__)
|
||||
// not supported
|
||||
#else
|
||||
PX_COMPILE_TIME_ASSERT(sizeof(fenv_t) <= sizeof(mControlWords));
|
||||
|
||||
fegetenv(reinterpret_cast<fenv_t*>(mControlWords));
|
||||
fesetenv(FE_DFL_ENV);
|
||||
|
||||
#if PX_LINUX
|
||||
// need to explicitly disable exceptions because fesetenv does not modify
|
||||
// the sse control word on 32bit linux (64bit is fine, but do it here just be sure)
|
||||
fedisableexcept(FE_ALL_EXCEPT);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
physx::PxFPUGuard::~PxFPUGuard()
|
||||
{
|
||||
#if defined(__CYGWIN__)
|
||||
#pragma message "PxFPUGuard::~PxFPUGuard() is not implemented"
|
||||
#elif PX_OSX
|
||||
// restore control word and clear exception flags
|
||||
// (setting exception state flags cause exceptions on the first following fp operation)
|
||||
_mm_setcsr(mControlWords[0] & ~_MM_EXCEPT_MASK);
|
||||
#elif defined(__EMSCRIPTEN__)
|
||||
// not supported
|
||||
#else
|
||||
fesetenv(reinterpret_cast<fenv_t*>(mControlWords));
|
||||
#endif
|
||||
}
|
||||
|
||||
PX_FOUNDATION_API void physx::PxEnableFPExceptions()
|
||||
{
|
||||
#if PX_LINUX && !defined(__EMSCRIPTEN__)
|
||||
feclearexcept(FE_ALL_EXCEPT);
|
||||
feenableexcept(FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW);
|
||||
#elif PX_OSX
|
||||
// clear any pending exceptions
|
||||
// (setting exception state flags cause exceptions on the first following fp operation)
|
||||
uint32_t control = _mm_getcsr() & ~_MM_EXCEPT_MASK;
|
||||
|
||||
// enable all fp exceptions except inexact and underflow (common, benign)
|
||||
// note: denorm has to be disabled as well because underflow can create denorms
|
||||
_mm_setcsr((control & ~_MM_MASK_MASK) | _MM_MASK_INEXACT | _MM_MASK_UNDERFLOW | _MM_MASK_DENORM);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
PX_FOUNDATION_API void physx::PxDisableFPExceptions()
|
||||
{
|
||||
#if PX_LINUX && !defined(__EMSCRIPTEN__)
|
||||
fedisableexcept(FE_ALL_EXCEPT);
|
||||
#elif PX_OSX
|
||||
// clear any pending exceptions
|
||||
// (setting exception state flags cause exceptions on the first following fp operation)
|
||||
uint32_t control = _mm_getcsr() & ~_MM_EXCEPT_MASK;
|
||||
_mm_setcsr(control | _MM_MASK_MASK);
|
||||
#endif
|
||||
}
|
||||
199
engine/third_party/physx/source/foundation/unix/FdUnixMutex.cpp
vendored
Normal file
199
engine/third_party/physx/source/foundation/unix/FdUnixMutex.cpp
vendored
Normal file
@@ -0,0 +1,199 @@
|
||||
// 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-2025 NVIDIA Corporation. All rights reserved.
|
||||
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
|
||||
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
|
||||
|
||||
#include "foundation/PxAssert.h"
|
||||
#include "foundation/PxErrorCallback.h"
|
||||
#include "foundation/PxUserAllocated.h"
|
||||
#include "foundation/PxMutex.h"
|
||||
#include "foundation/PxAtomic.h"
|
||||
#include "foundation/PxThread.h"
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
namespace physx
|
||||
{
|
||||
|
||||
#if PX_LINUX
|
||||
|
||||
#include <sched.h>
|
||||
|
||||
static int gMutexProtocol = PTHREAD_PRIO_INHERIT;
|
||||
|
||||
PX_FORCE_INLINE bool isLegalProtocol(const int mutexProtocol)
|
||||
{
|
||||
return
|
||||
(
|
||||
(PTHREAD_PRIO_NONE == mutexProtocol) ||
|
||||
(PTHREAD_PRIO_INHERIT == mutexProtocol) ||
|
||||
((PTHREAD_PRIO_PROTECT == mutexProtocol) && ((sched_getscheduler(0) == SCHED_FIFO) || (sched_getscheduler(0) == SCHED_RR)))
|
||||
);
|
||||
}
|
||||
|
||||
bool PxSetMutexProtocol(const int mutexProtocol)
|
||||
{
|
||||
if(isLegalProtocol(mutexProtocol))
|
||||
{
|
||||
gMutexProtocol = mutexProtocol;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int PxGetMutexProtocol()
|
||||
{
|
||||
return gMutexProtocol;
|
||||
}
|
||||
|
||||
#endif //PX_LINUX
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
struct MutexUnixImpl
|
||||
{
|
||||
pthread_mutex_t lock;
|
||||
PxThread::Id owner;
|
||||
};
|
||||
|
||||
MutexUnixImpl* getMutex(PxMutexImpl* impl)
|
||||
{
|
||||
return reinterpret_cast<MutexUnixImpl*>(impl);
|
||||
}
|
||||
}
|
||||
|
||||
PxMutexImpl::PxMutexImpl()
|
||||
{
|
||||
pthread_mutexattr_t attr;
|
||||
pthread_mutexattr_init(&attr);
|
||||
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
|
||||
#if PX_LINUX
|
||||
pthread_mutexattr_setprotocol(&attr, gMutexProtocol);
|
||||
pthread_mutexattr_setprioceiling(&attr, 0);
|
||||
#endif
|
||||
pthread_mutex_init(&getMutex(this)->lock, &attr);
|
||||
pthread_mutexattr_destroy(&attr);
|
||||
}
|
||||
|
||||
PxMutexImpl::~PxMutexImpl()
|
||||
{
|
||||
pthread_mutex_destroy(&getMutex(this)->lock);
|
||||
}
|
||||
|
||||
void PxMutexImpl::lock()
|
||||
{
|
||||
int err = pthread_mutex_lock(&getMutex(this)->lock);
|
||||
PX_ASSERT(!err);
|
||||
PX_UNUSED(err);
|
||||
|
||||
#if PX_DEBUG
|
||||
getMutex(this)->owner = PxThread::getId();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool PxMutexImpl::trylock()
|
||||
{
|
||||
bool success = !pthread_mutex_trylock(&getMutex(this)->lock);
|
||||
#if PX_DEBUG
|
||||
if(success)
|
||||
getMutex(this)->owner = PxThread::getId();
|
||||
#endif
|
||||
return success;
|
||||
}
|
||||
|
||||
void PxMutexImpl::unlock()
|
||||
{
|
||||
#if PX_DEBUG
|
||||
if(getMutex(this)->owner != PxThread::getId())
|
||||
{
|
||||
PxGetFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__,
|
||||
"Mutex must be unlocked only by thread that has already acquired lock");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
int err = pthread_mutex_unlock(&getMutex(this)->lock);
|
||||
PX_ASSERT(!err);
|
||||
PX_UNUSED(err);
|
||||
}
|
||||
|
||||
uint32_t PxMutexImpl::getSize()
|
||||
{
|
||||
return sizeof(MutexUnixImpl);
|
||||
}
|
||||
|
||||
class ReadWriteLockImpl
|
||||
{
|
||||
public:
|
||||
PxMutex mutex;
|
||||
volatile int readerCounter;
|
||||
};
|
||||
|
||||
PxReadWriteLock::PxReadWriteLock()
|
||||
{
|
||||
mImpl = reinterpret_cast<ReadWriteLockImpl*>(PX_ALLOC(sizeof(ReadWriteLockImpl), "ReadWriteLockImpl"));
|
||||
PX_PLACEMENT_NEW(mImpl, ReadWriteLockImpl);
|
||||
|
||||
mImpl->readerCounter = 0;
|
||||
}
|
||||
|
||||
PxReadWriteLock::~PxReadWriteLock()
|
||||
{
|
||||
mImpl->~ReadWriteLockImpl();
|
||||
PX_FREE(mImpl);
|
||||
}
|
||||
|
||||
void PxReadWriteLock::lockReader(bool takeLock)
|
||||
{
|
||||
if(takeLock)
|
||||
mImpl->mutex.lock();
|
||||
|
||||
PxAtomicIncrement(&mImpl->readerCounter);
|
||||
|
||||
if(takeLock)
|
||||
mImpl->mutex.unlock();
|
||||
}
|
||||
|
||||
void PxReadWriteLock::lockWriter()
|
||||
{
|
||||
mImpl->mutex.lock();
|
||||
|
||||
// spin lock until no readers
|
||||
while(mImpl->readerCounter);
|
||||
}
|
||||
|
||||
void PxReadWriteLock::unlockReader()
|
||||
{
|
||||
PxAtomicDecrement(&mImpl->readerCounter);
|
||||
}
|
||||
|
||||
void PxReadWriteLock::unlockWriter()
|
||||
{
|
||||
mImpl->mutex.unlock();
|
||||
}
|
||||
|
||||
} // namespace physx
|
||||
40
engine/third_party/physx/source/foundation/unix/FdUnixPrintString.cpp
vendored
Normal file
40
engine/third_party/physx/source/foundation/unix/FdUnixPrintString.cpp
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
// 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-2025 NVIDIA Corporation. All rights reserved.
|
||||
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
|
||||
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
|
||||
|
||||
#include "foundation/PxString.h"
|
||||
#include <stdio.h>
|
||||
|
||||
namespace physx
|
||||
{
|
||||
|
||||
void PxPrintString(const char* str)
|
||||
{
|
||||
puts(str);
|
||||
}
|
||||
|
||||
} // namespace physx
|
||||
152
engine/third_party/physx/source/foundation/unix/FdUnixSList.cpp
vendored
Normal file
152
engine/third_party/physx/source/foundation/unix/FdUnixSList.cpp
vendored
Normal file
@@ -0,0 +1,152 @@
|
||||
// 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-2025 NVIDIA Corporation. All rights reserved.
|
||||
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
|
||||
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
|
||||
|
||||
#include "foundation/PxAllocator.h"
|
||||
#include "foundation/PxAtomic.h"
|
||||
#include "foundation/PxSList.h"
|
||||
#include "foundation/PxThread.h"
|
||||
#include <pthread.h>
|
||||
|
||||
#if PX_EMSCRIPTEN
|
||||
#define USE_MUTEX
|
||||
#endif
|
||||
|
||||
namespace physx
|
||||
{
|
||||
namespace
|
||||
{
|
||||
#if defined(USE_MUTEX)
|
||||
class ScopedMutexLock
|
||||
{
|
||||
pthread_mutex_t& mMutex;
|
||||
|
||||
public:
|
||||
PX_INLINE ScopedMutexLock(pthread_mutex_t& mutex) : mMutex(mutex)
|
||||
{
|
||||
pthread_mutex_lock(&mMutex);
|
||||
}
|
||||
|
||||
PX_INLINE ~ScopedMutexLock()
|
||||
{
|
||||
pthread_mutex_unlock(&mMutex);
|
||||
}
|
||||
};
|
||||
|
||||
typedef ScopedMutexLock ScopedLock;
|
||||
#else
|
||||
struct ScopedSpinLock
|
||||
{
|
||||
PX_FORCE_INLINE ScopedSpinLock(volatile int32_t& lock) : mLock(lock)
|
||||
{
|
||||
while(__sync_lock_test_and_set(&mLock, 1))
|
||||
{
|
||||
// spinning without atomics is usually
|
||||
// causing less bus traffic. -> only one
|
||||
// CPU is modifying the cache line.
|
||||
while(lock)
|
||||
PxSpinLockPause();
|
||||
}
|
||||
}
|
||||
|
||||
PX_FORCE_INLINE ~ScopedSpinLock()
|
||||
{
|
||||
__sync_lock_release(&mLock);
|
||||
}
|
||||
|
||||
private:
|
||||
volatile int32_t& mLock;
|
||||
};
|
||||
|
||||
typedef ScopedSpinLock ScopedLock;
|
||||
#endif
|
||||
|
||||
struct SListDetail
|
||||
{
|
||||
PxSListEntry* head;
|
||||
#if defined(USE_MUTEX)
|
||||
pthread_mutex_t lock;
|
||||
#else
|
||||
volatile int32_t lock;
|
||||
#endif
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
SListDetail* getDetail(T* impl)
|
||||
{
|
||||
return reinterpret_cast<SListDetail*>(impl);
|
||||
}
|
||||
}
|
||||
|
||||
PxSListImpl::PxSListImpl()
|
||||
{
|
||||
getDetail(this)->head = NULL;
|
||||
|
||||
#if defined(USE_MUTEX)
|
||||
pthread_mutex_init(&getDetail(this)->lock, NULL);
|
||||
#else
|
||||
getDetail(this)->lock = 0; // 0 == unlocked
|
||||
#endif
|
||||
}
|
||||
|
||||
PxSListImpl::~PxSListImpl()
|
||||
{
|
||||
#if defined(USE_MUTEX)
|
||||
pthread_mutex_destroy(&getDetail(this)->lock);
|
||||
#endif
|
||||
}
|
||||
|
||||
void PxSListImpl::push(PxSListEntry* entry)
|
||||
{
|
||||
ScopedLock lock(getDetail(this)->lock);
|
||||
entry->mNext = getDetail(this)->head;
|
||||
getDetail(this)->head = entry;
|
||||
}
|
||||
|
||||
PxSListEntry* PxSListImpl::pop()
|
||||
{
|
||||
ScopedLock lock(getDetail(this)->lock);
|
||||
PxSListEntry* result = getDetail(this)->head;
|
||||
if(result != NULL)
|
||||
getDetail(this)->head = result->mNext;
|
||||
return result;
|
||||
}
|
||||
|
||||
PxSListEntry* PxSListImpl::flush()
|
||||
{
|
||||
ScopedLock lock(getDetail(this)->lock);
|
||||
PxSListEntry* result = getDetail(this)->head;
|
||||
getDetail(this)->head = NULL;
|
||||
return result;
|
||||
}
|
||||
|
||||
uint32_t PxSListImpl::getSize()
|
||||
{
|
||||
return sizeof(SListDetail);
|
||||
}
|
||||
|
||||
} // namespace physx
|
||||
479
engine/third_party/physx/source/foundation/unix/FdUnixSocket.cpp
vendored
Normal file
479
engine/third_party/physx/source/foundation/unix/FdUnixSocket.cpp
vendored
Normal file
@@ -0,0 +1,479 @@
|
||||
// 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-2025 NVIDIA Corporation. All rights reserved.
|
||||
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
|
||||
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
|
||||
|
||||
#include "foundation/PxIntrinsics.h"
|
||||
#include "foundation/PxMathIntrinsics.h"
|
||||
#include "foundation/PxSocket.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/poll.h>
|
||||
#include <sys/time.h>
|
||||
#include <netdb.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define INVALID_SOCKET -1
|
||||
|
||||
#ifndef SOMAXCONN
|
||||
#define SOMAXCONN 5
|
||||
#endif
|
||||
|
||||
namespace physx
|
||||
{
|
||||
|
||||
const uint32_t PxSocket::DEFAULT_BUFFER_SIZE = 32768;
|
||||
|
||||
class SocketImpl
|
||||
{
|
||||
public:
|
||||
SocketImpl(bool isBlocking);
|
||||
virtual ~SocketImpl();
|
||||
|
||||
bool connect(const char* host, uint16_t port, uint32_t timeout);
|
||||
bool listen(uint16_t port);
|
||||
bool accept(bool block);
|
||||
void disconnect();
|
||||
|
||||
void setBlocking(bool blocking);
|
||||
|
||||
virtual uint32_t write(const uint8_t* data, uint32_t length);
|
||||
virtual bool flush();
|
||||
uint32_t read(uint8_t* data, uint32_t length);
|
||||
|
||||
PX_FORCE_INLINE bool isBlocking() const
|
||||
{
|
||||
return mIsBlocking;
|
||||
}
|
||||
PX_FORCE_INLINE bool isConnected() const
|
||||
{
|
||||
return mIsConnected;
|
||||
}
|
||||
PX_FORCE_INLINE const char* getHost() const
|
||||
{
|
||||
return mHost;
|
||||
}
|
||||
PX_FORCE_INLINE uint16_t getPort() const
|
||||
{
|
||||
return mPort;
|
||||
}
|
||||
|
||||
protected:
|
||||
bool nonBlockingTimeout() const;
|
||||
|
||||
int32_t mSocket;
|
||||
int32_t mListenSocket;
|
||||
const char* mHost;
|
||||
uint16_t mPort;
|
||||
bool mIsConnected;
|
||||
bool mIsBlocking;
|
||||
bool mListenMode;
|
||||
};
|
||||
|
||||
void socketSetBlockingInternal(int32_t socket, bool blocking);
|
||||
|
||||
SocketImpl::SocketImpl(bool isBlocking)
|
||||
: mSocket(INVALID_SOCKET)
|
||||
, mListenSocket(INVALID_SOCKET)
|
||||
, mHost(NULL)
|
||||
, mPort(0)
|
||||
, mIsConnected(false)
|
||||
, mIsBlocking(isBlocking)
|
||||
, mListenMode(false)
|
||||
{
|
||||
}
|
||||
|
||||
SocketImpl::~SocketImpl()
|
||||
{
|
||||
}
|
||||
|
||||
bool SocketImpl::connect(const char* host, uint16_t port, uint32_t timeout)
|
||||
{
|
||||
sockaddr_in socketAddress;
|
||||
intrinsics::memSet(&socketAddress, 0, sizeof(sockaddr_in));
|
||||
socketAddress.sin_family = AF_INET;
|
||||
socketAddress.sin_port = htons(port);
|
||||
|
||||
// get host
|
||||
hostent* hp = gethostbyname(host);
|
||||
if(!hp)
|
||||
{
|
||||
in_addr a;
|
||||
a.s_addr = inet_addr(host);
|
||||
hp = gethostbyaddr(reinterpret_cast<const char*>(&a), sizeof(in_addr), AF_INET);
|
||||
if(!hp)
|
||||
return false;
|
||||
}
|
||||
intrinsics::memCopy(&socketAddress.sin_addr, hp->h_addr_list[0], hp->h_length);
|
||||
|
||||
// connect
|
||||
mSocket = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if(mSocket == INVALID_SOCKET)
|
||||
return false;
|
||||
|
||||
socketSetBlockingInternal(mSocket, false);
|
||||
|
||||
int connectRet = ::connect(mSocket, reinterpret_cast<sockaddr*>(&socketAddress), sizeof(socketAddress));
|
||||
if(connectRet < 0)
|
||||
{
|
||||
if(errno != EINPROGRESS)
|
||||
{
|
||||
disconnect();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Setup poll function call to monitor the connect call.
|
||||
// By querying for POLLOUT we're checking if the socket is
|
||||
// ready for writing.
|
||||
pollfd pfd;
|
||||
pfd.fd = mSocket;
|
||||
pfd.events = POLLOUT;
|
||||
const int pollResult = ::poll(&pfd, 1, timeout /*milliseconds*/);
|
||||
|
||||
const bool pollTimeout = (pollResult == 0);
|
||||
const bool pollError = (pollResult < 0); // an error inside poll happened. Can check error with `errno` variable.
|
||||
if(pollTimeout || pollError)
|
||||
{
|
||||
disconnect();
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
PX_ASSERT(pollResult == 1);
|
||||
|
||||
// check that event was precisely POLLOUT and not anything else (e.g., errors, hang-up)
|
||||
bool test = (pfd.revents & POLLOUT) && !(pfd.revents & (~POLLOUT));
|
||||
if(!test)
|
||||
{
|
||||
disconnect();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// check if we are really connected, above code seems to return
|
||||
// true if host is a unix machine even if the connection was
|
||||
// not accepted.
|
||||
char buffer;
|
||||
if(recv(mSocket, &buffer, 0, 0) < 0)
|
||||
{
|
||||
if(errno != EWOULDBLOCK)
|
||||
{
|
||||
disconnect();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
socketSetBlockingInternal(mSocket, mIsBlocking);
|
||||
|
||||
#if PX_APPLE_FAMILY
|
||||
int noSigPipe = 1;
|
||||
setsockopt(mSocket, SOL_SOCKET, SO_NOSIGPIPE, &noSigPipe, sizeof(int));
|
||||
#endif
|
||||
|
||||
mIsConnected = true;
|
||||
mPort = port;
|
||||
mHost = host;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SocketImpl::listen(uint16_t port)
|
||||
{
|
||||
mListenSocket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if(mListenSocket == INVALID_SOCKET)
|
||||
return false;
|
||||
|
||||
// enable address reuse: "Address already in use" error message
|
||||
int yes = 1;
|
||||
if(setsockopt(mListenSocket, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1)
|
||||
return false;
|
||||
|
||||
mListenMode = true;
|
||||
|
||||
sockaddr_in addr;
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(port);
|
||||
addr.sin_addr.s_addr = INADDR_ANY;
|
||||
intrinsics::memSet(addr.sin_zero, '\0', sizeof addr.sin_zero);
|
||||
|
||||
return bind(mListenSocket, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) != -1 &&
|
||||
::listen(mListenSocket, SOMAXCONN) != -1;
|
||||
}
|
||||
|
||||
bool SocketImpl::accept(bool block)
|
||||
{
|
||||
if(mIsConnected || !mListenMode)
|
||||
return false;
|
||||
|
||||
// set the listen socket to be non-blocking.
|
||||
socketSetBlockingInternal(mListenSocket, block);
|
||||
int32_t clientSocket = ::accept(mListenSocket, 0, 0);
|
||||
if(clientSocket == INVALID_SOCKET)
|
||||
return false;
|
||||
|
||||
mSocket = clientSocket;
|
||||
mIsConnected = true;
|
||||
socketSetBlockingInternal(mSocket, mIsBlocking); // force the mode to whatever the user set
|
||||
|
||||
return mIsConnected;
|
||||
}
|
||||
|
||||
void SocketImpl::disconnect()
|
||||
{
|
||||
if(mListenSocket != INVALID_SOCKET)
|
||||
{
|
||||
close(mListenSocket);
|
||||
mListenSocket = INVALID_SOCKET;
|
||||
}
|
||||
if(mSocket != INVALID_SOCKET)
|
||||
{
|
||||
if(mIsConnected)
|
||||
{
|
||||
socketSetBlockingInternal(mSocket, true);
|
||||
shutdown(mSocket, SHUT_RDWR);
|
||||
}
|
||||
close(mSocket);
|
||||
mSocket = INVALID_SOCKET;
|
||||
}
|
||||
mIsConnected = false;
|
||||
mListenMode = false;
|
||||
mPort = 0;
|
||||
mHost = NULL;
|
||||
}
|
||||
|
||||
bool SocketImpl::nonBlockingTimeout() const
|
||||
{
|
||||
return !mIsBlocking && errno == EWOULDBLOCK;
|
||||
}
|
||||
|
||||
void socketSetBlockingInternal(int32_t socket, bool blocking)
|
||||
{
|
||||
int mode = fcntl(socket, F_GETFL, 0);
|
||||
if(!blocking)
|
||||
mode |= O_NONBLOCK;
|
||||
else
|
||||
mode &= ~O_NONBLOCK;
|
||||
fcntl(socket, F_SETFL, mode);
|
||||
}
|
||||
|
||||
// should be cross-platform from here down
|
||||
|
||||
void SocketImpl::setBlocking(bool blocking)
|
||||
{
|
||||
if(blocking != mIsBlocking)
|
||||
{
|
||||
mIsBlocking = blocking;
|
||||
if(isConnected())
|
||||
socketSetBlockingInternal(mSocket, blocking);
|
||||
}
|
||||
}
|
||||
|
||||
bool SocketImpl::flush()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t SocketImpl::write(const uint8_t* data, uint32_t length)
|
||||
{
|
||||
if(length == 0)
|
||||
return 0;
|
||||
|
||||
int sent = send(mSocket, reinterpret_cast<const char*>(data), int32_t(length), 0);
|
||||
|
||||
if(sent <= 0 && !nonBlockingTimeout())
|
||||
disconnect();
|
||||
|
||||
return uint32_t(sent > 0 ? sent : 0);
|
||||
}
|
||||
|
||||
uint32_t SocketImpl::read(uint8_t* data, uint32_t length)
|
||||
{
|
||||
if(length == 0)
|
||||
return 0;
|
||||
|
||||
int32_t received = recv(mSocket, reinterpret_cast<char*>(data), int32_t(length), 0);
|
||||
|
||||
if(received <= 0 && !nonBlockingTimeout())
|
||||
disconnect();
|
||||
|
||||
return uint32_t(received > 0 ? received : 0);
|
||||
}
|
||||
|
||||
class BufferedSocketImpl : public SocketImpl
|
||||
{
|
||||
public:
|
||||
BufferedSocketImpl(bool isBlocking) : SocketImpl(isBlocking), mBufferPos(0)
|
||||
{
|
||||
}
|
||||
virtual ~BufferedSocketImpl()
|
||||
{
|
||||
}
|
||||
bool flush();
|
||||
uint32_t write(const uint8_t* data, uint32_t length);
|
||||
|
||||
private:
|
||||
uint32_t mBufferPos;
|
||||
uint8_t mBuffer[PxSocket::DEFAULT_BUFFER_SIZE];
|
||||
};
|
||||
|
||||
bool BufferedSocketImpl::flush()
|
||||
{
|
||||
uint32_t totalBytesWritten = 0;
|
||||
|
||||
while(totalBytesWritten < mBufferPos && mIsConnected)
|
||||
totalBytesWritten += int32_t(SocketImpl::write(mBuffer + totalBytesWritten, mBufferPos - totalBytesWritten));
|
||||
|
||||
bool ret = (totalBytesWritten == mBufferPos);
|
||||
mBufferPos = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t BufferedSocketImpl::write(const uint8_t* data, uint32_t length)
|
||||
{
|
||||
uint32_t bytesWritten = 0;
|
||||
while(mBufferPos + length >= PxSocket::DEFAULT_BUFFER_SIZE)
|
||||
{
|
||||
uint32_t currentChunk = PxSocket::DEFAULT_BUFFER_SIZE - mBufferPos;
|
||||
intrinsics::memCopy(mBuffer + mBufferPos, data + bytesWritten, currentChunk);
|
||||
bytesWritten += uint32_t(currentChunk); // for the user, this is consumed even if we fail to shove it down a
|
||||
// non-blocking socket
|
||||
|
||||
uint32_t sent = SocketImpl::write(mBuffer, PxSocket::DEFAULT_BUFFER_SIZE);
|
||||
mBufferPos = PxSocket::DEFAULT_BUFFER_SIZE - sent;
|
||||
|
||||
if(sent < PxSocket::DEFAULT_BUFFER_SIZE) // non-blocking or error
|
||||
{
|
||||
if(sent) // we can reasonably hope this is rare
|
||||
intrinsics::memMove(mBuffer, mBuffer + sent, mBufferPos);
|
||||
|
||||
return bytesWritten;
|
||||
}
|
||||
length -= currentChunk;
|
||||
}
|
||||
|
||||
if(length > 0)
|
||||
{
|
||||
intrinsics::memCopy(mBuffer + mBufferPos, data + bytesWritten, length);
|
||||
bytesWritten += length;
|
||||
mBufferPos += length;
|
||||
}
|
||||
|
||||
return bytesWritten;
|
||||
}
|
||||
|
||||
PxSocket::PxSocket(bool inIsBuffering, bool isBlocking)
|
||||
{
|
||||
if(inIsBuffering)
|
||||
{
|
||||
void* mem = PX_ALLOC(sizeof(BufferedSocketImpl), "BufferedSocketImpl");
|
||||
mImpl = PX_PLACEMENT_NEW(mem, BufferedSocketImpl)(isBlocking);
|
||||
}
|
||||
else
|
||||
{
|
||||
void* mem = PX_ALLOC(sizeof(SocketImpl), "SocketImpl");
|
||||
mImpl = PX_PLACEMENT_NEW(mem, SocketImpl)(isBlocking);
|
||||
}
|
||||
}
|
||||
|
||||
PxSocket::~PxSocket()
|
||||
{
|
||||
mImpl->flush();
|
||||
mImpl->disconnect();
|
||||
mImpl->~SocketImpl();
|
||||
PX_FREE(mImpl);
|
||||
}
|
||||
|
||||
bool PxSocket::connect(const char* host, uint16_t port, uint32_t timeout)
|
||||
{
|
||||
return mImpl->connect(host, port, timeout);
|
||||
}
|
||||
|
||||
bool PxSocket::listen(uint16_t port)
|
||||
{
|
||||
return mImpl->listen(port);
|
||||
}
|
||||
|
||||
bool PxSocket::accept(bool block)
|
||||
{
|
||||
return mImpl->accept(block);
|
||||
}
|
||||
|
||||
void PxSocket::disconnect()
|
||||
{
|
||||
mImpl->disconnect();
|
||||
}
|
||||
|
||||
bool PxSocket::isConnected() const
|
||||
{
|
||||
return mImpl->isConnected();
|
||||
}
|
||||
|
||||
const char* PxSocket::getHost() const
|
||||
{
|
||||
return mImpl->getHost();
|
||||
}
|
||||
|
||||
uint16_t PxSocket::getPort() const
|
||||
{
|
||||
return mImpl->getPort();
|
||||
}
|
||||
|
||||
bool PxSocket::flush()
|
||||
{
|
||||
if(!mImpl->isConnected())
|
||||
return false;
|
||||
return mImpl->flush();
|
||||
}
|
||||
|
||||
uint32_t PxSocket::write(const uint8_t* data, uint32_t length)
|
||||
{
|
||||
if(!mImpl->isConnected())
|
||||
return 0;
|
||||
return mImpl->write(data, length);
|
||||
}
|
||||
|
||||
uint32_t PxSocket::read(uint8_t* data, uint32_t length)
|
||||
{
|
||||
if(!mImpl->isConnected())
|
||||
return 0;
|
||||
return mImpl->read(data, length);
|
||||
}
|
||||
|
||||
void PxSocket::setBlocking(bool blocking)
|
||||
{
|
||||
mImpl->setBlocking(blocking);
|
||||
}
|
||||
|
||||
bool PxSocket::isBlocking() const
|
||||
{
|
||||
return mImpl->isBlocking();
|
||||
}
|
||||
|
||||
} // namespace physx
|
||||
159
engine/third_party/physx/source/foundation/unix/FdUnixSync.cpp
vendored
Normal file
159
engine/third_party/physx/source/foundation/unix/FdUnixSync.cpp
vendored
Normal file
@@ -0,0 +1,159 @@
|
||||
// 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-2025 NVIDIA Corporation. All rights reserved.
|
||||
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
|
||||
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
|
||||
|
||||
#include "foundation/PxAssert.h"
|
||||
|
||||
#include "foundation/PxUserAllocated.h"
|
||||
#include "foundation/PxSync.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <pthread.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
namespace physx
|
||||
{
|
||||
|
||||
namespace
|
||||
{
|
||||
class SyncImpl
|
||||
{
|
||||
public:
|
||||
pthread_mutex_t mutex;
|
||||
pthread_cond_t cond;
|
||||
volatile int setCounter;
|
||||
volatile bool is_set;
|
||||
};
|
||||
|
||||
SyncImpl* getSync(PxSyncImpl* impl)
|
||||
{
|
||||
return reinterpret_cast<SyncImpl*>(impl);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t PxSyncImpl::getSize()
|
||||
{
|
||||
return sizeof(SyncImpl);
|
||||
}
|
||||
|
||||
struct PxUnixScopeLock
|
||||
{
|
||||
PxUnixScopeLock(pthread_mutex_t& m) : mMutex(m)
|
||||
{
|
||||
pthread_mutex_lock(&mMutex);
|
||||
}
|
||||
|
||||
~PxUnixScopeLock()
|
||||
{
|
||||
pthread_mutex_unlock(&mMutex);
|
||||
}
|
||||
|
||||
private:
|
||||
pthread_mutex_t& mMutex;
|
||||
};
|
||||
|
||||
PxSyncImpl::PxSyncImpl()
|
||||
{
|
||||
int status = pthread_mutex_init(&getSync(this)->mutex, 0);
|
||||
PX_ASSERT(!status);
|
||||
status = pthread_cond_init(&getSync(this)->cond, 0);
|
||||
PX_ASSERT(!status);
|
||||
PX_UNUSED(status);
|
||||
getSync(this)->is_set = false;
|
||||
getSync(this)->setCounter = 0;
|
||||
}
|
||||
|
||||
PxSyncImpl::~PxSyncImpl()
|
||||
{
|
||||
pthread_cond_destroy(&getSync(this)->cond);
|
||||
pthread_mutex_destroy(&getSync(this)->mutex);
|
||||
}
|
||||
|
||||
void PxSyncImpl::reset()
|
||||
{
|
||||
PxUnixScopeLock lock(getSync(this)->mutex);
|
||||
getSync(this)->is_set = false;
|
||||
}
|
||||
|
||||
void PxSyncImpl::set()
|
||||
{
|
||||
PxUnixScopeLock lock(getSync(this)->mutex);
|
||||
if(!getSync(this)->is_set)
|
||||
{
|
||||
getSync(this)->is_set = true;
|
||||
getSync(this)->setCounter++;
|
||||
pthread_cond_broadcast(&getSync(this)->cond);
|
||||
}
|
||||
}
|
||||
|
||||
bool PxSyncImpl::wait(uint32_t ms)
|
||||
{
|
||||
PxUnixScopeLock lock(getSync(this)->mutex);
|
||||
int lastSetCounter = getSync(this)->setCounter;
|
||||
if(!getSync(this)->is_set)
|
||||
{
|
||||
if(ms == uint32_t(-1))
|
||||
{
|
||||
// have to loop here and check is_set since pthread_cond_wait can return successfully
|
||||
// even if it was not signaled by pthread_cond_broadcast (OS efficiency design decision)
|
||||
int status = 0;
|
||||
while(!status && !getSync(this)->is_set && (lastSetCounter == getSync(this)->setCounter))
|
||||
status = pthread_cond_wait(&getSync(this)->cond, &getSync(this)->mutex);
|
||||
PX_ASSERT((!status && getSync(this)->is_set) || (lastSetCounter != getSync(this)->setCounter));
|
||||
}
|
||||
else
|
||||
{
|
||||
timespec ts;
|
||||
timeval tp;
|
||||
gettimeofday(&tp, NULL);
|
||||
uint32_t sec = ms / 1000;
|
||||
uint32_t usec = (ms - 1000 * sec) * 1000;
|
||||
|
||||
// sschirm: taking into account that us might accumulate to a second
|
||||
// otherwise the pthread_cond_timedwait complains on osx.
|
||||
usec = tp.tv_usec + usec;
|
||||
uint32_t div_sec = usec / 1000000;
|
||||
uint32_t rem_usec = usec - div_sec * 1000000;
|
||||
|
||||
ts.tv_sec = tp.tv_sec + sec + div_sec;
|
||||
ts.tv_nsec = rem_usec * 1000;
|
||||
|
||||
// have to loop here and check is_set since pthread_cond_timedwait can return successfully
|
||||
// even if it was not signaled by pthread_cond_broadcast (OS efficiency design decision)
|
||||
int status = 0;
|
||||
while(!status && !getSync(this)->is_set && (lastSetCounter == getSync(this)->setCounter))
|
||||
status = pthread_cond_timedwait(&getSync(this)->cond, &getSync(this)->mutex, &ts);
|
||||
PX_ASSERT((!status && getSync(this)->is_set) || (status == ETIMEDOUT) ||
|
||||
(lastSetCounter != getSync(this)->setCounter));
|
||||
}
|
||||
}
|
||||
return getSync(this)->is_set || (lastSetCounter != getSync(this)->setCounter);
|
||||
}
|
||||
|
||||
} // namespace physx
|
||||
466
engine/third_party/physx/source/foundation/unix/FdUnixThread.cpp
vendored
Normal file
466
engine/third_party/physx/source/foundation/unix/FdUnixThread.cpp
vendored
Normal file
@@ -0,0 +1,466 @@
|
||||
// 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-2025 NVIDIA Corporation. All rights reserved.
|
||||
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
|
||||
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
|
||||
|
||||
#include "foundation/PxAssert.h"
|
||||
#include "foundation/PxErrorCallback.h"
|
||||
#include "foundation/PxAtomic.h"
|
||||
#include "foundation/PxThread.h"
|
||||
|
||||
#include <math.h>
|
||||
#if !PX_APPLE_FAMILY && !defined(__CYGWIN__) && !PX_EMSCRIPTEN
|
||||
#include <bits/local_lim.h> // PTHREAD_STACK_MIN
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/syscall.h>
|
||||
#if !PX_APPLE_FAMILY && !PX_EMSCRIPTEN
|
||||
#include <asm/unistd.h>
|
||||
#include <sys/resource.h>
|
||||
#endif
|
||||
|
||||
#if PX_APPLE_FAMILY
|
||||
#include <sys/types.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <TargetConditionals.h>
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
#define PxSpinLockPause() asm("nop")
|
||||
|
||||
namespace physx
|
||||
{
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
typedef enum
|
||||
{
|
||||
ePxThreadNotStarted,
|
||||
ePxThreadStarted,
|
||||
ePxThreadStopped
|
||||
} PxThreadState;
|
||||
|
||||
class ThreadImpl
|
||||
{
|
||||
public:
|
||||
PxThreadImpl::ExecuteFn fn;
|
||||
void* arg;
|
||||
volatile int32_t quitNow;
|
||||
volatile int32_t threadStarted;
|
||||
volatile int32_t state;
|
||||
|
||||
pthread_t thread;
|
||||
pid_t tid;
|
||||
|
||||
uint32_t affinityMask;
|
||||
const char* name;
|
||||
};
|
||||
|
||||
ThreadImpl* getThread(PxThreadImpl* impl)
|
||||
{
|
||||
return reinterpret_cast<ThreadImpl*>(impl);
|
||||
}
|
||||
|
||||
static void setTid(ThreadImpl& threadImpl)
|
||||
{
|
||||
// query TID
|
||||
// AM: TODO: neither of the below are implemented
|
||||
#if PX_APPLE_FAMILY
|
||||
threadImpl.tid = syscall(SYS_gettid);
|
||||
#elif PX_EMSCRIPTEN
|
||||
threadImpl.tid = pthread_self();
|
||||
#else
|
||||
threadImpl.tid = syscall(__NR_gettid);
|
||||
#endif
|
||||
|
||||
// notify/unblock parent thread
|
||||
PxAtomicCompareExchange(&(threadImpl.threadStarted), 1, 0);
|
||||
}
|
||||
|
||||
void* PxThreadStart(void* arg)
|
||||
{
|
||||
ThreadImpl* impl = getThread(reinterpret_cast<PxThreadImpl*>(arg));
|
||||
impl->state = ePxThreadStarted;
|
||||
|
||||
// run setTid in thread's context
|
||||
setTid(*impl);
|
||||
|
||||
// then run either the passed in function or execute from the derived class (Runnable).
|
||||
if(impl->fn)
|
||||
(*impl->fn)(impl->arg);
|
||||
else if(impl->arg)
|
||||
(reinterpret_cast<PxRunnable*>(impl->arg))->execute();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t PxThreadImpl::getSize()
|
||||
{
|
||||
return sizeof(ThreadImpl);
|
||||
}
|
||||
|
||||
PxThreadImpl::Id PxThreadImpl::getId()
|
||||
{
|
||||
return Id(pthread_self());
|
||||
}
|
||||
|
||||
PxThreadImpl::PxThreadImpl()
|
||||
{
|
||||
getThread(this)->thread = 0;
|
||||
getThread(this)->tid = 0;
|
||||
getThread(this)->state = ePxThreadNotStarted;
|
||||
getThread(this)->quitNow = 0;
|
||||
getThread(this)->threadStarted = 0;
|
||||
getThread(this)->fn = NULL;
|
||||
getThread(this)->arg = NULL;
|
||||
getThread(this)->affinityMask = 0;
|
||||
getThread(this)->name = "set my name before starting me";
|
||||
}
|
||||
|
||||
PxThreadImpl::PxThreadImpl(PxThreadImpl::ExecuteFn fn, void* arg, const char* name)
|
||||
{
|
||||
getThread(this)->thread = 0;
|
||||
getThread(this)->tid = 0;
|
||||
getThread(this)->state = ePxThreadNotStarted;
|
||||
getThread(this)->quitNow = 0;
|
||||
getThread(this)->threadStarted = 0;
|
||||
getThread(this)->fn = fn;
|
||||
getThread(this)->arg = arg;
|
||||
getThread(this)->affinityMask = 0;
|
||||
getThread(this)->name = name;
|
||||
|
||||
start(0, NULL);
|
||||
}
|
||||
|
||||
PxThreadImpl::~PxThreadImpl()
|
||||
{
|
||||
if(getThread(this)->state == ePxThreadStarted)
|
||||
kill();
|
||||
}
|
||||
|
||||
void PxThreadImpl::start(uint32_t stackSize, PxRunnable* runnable)
|
||||
{
|
||||
if(getThread(this)->state != ePxThreadNotStarted)
|
||||
return;
|
||||
|
||||
if(stackSize == 0)
|
||||
stackSize = getDefaultStackSize();
|
||||
|
||||
#if defined(PTHREAD_STACK_MIN)
|
||||
if(stackSize < PTHREAD_STACK_MIN)
|
||||
{
|
||||
PxGetFoundation().error(PxErrorCode::eDEBUG_WARNING, __FILE__, __LINE__,
|
||||
"PxThreadImpl::start(): stack size was set below PTHREAD_STACK_MIN");
|
||||
stackSize = PTHREAD_STACK_MIN;
|
||||
}
|
||||
#endif
|
||||
|
||||
if(runnable && !getThread(this)->arg && !getThread(this)->fn)
|
||||
getThread(this)->arg = runnable;
|
||||
|
||||
pthread_attr_t attr;
|
||||
int status = pthread_attr_init(&attr);
|
||||
PX_ASSERT(!status);
|
||||
PX_UNUSED(status);
|
||||
|
||||
status = pthread_attr_setstacksize(&attr, stackSize);
|
||||
PX_ASSERT(!status);
|
||||
status = pthread_create(&getThread(this)->thread, &attr, PxThreadStart, this);
|
||||
PX_ASSERT(!status);
|
||||
|
||||
// wait for thread to startup and write out TID
|
||||
// otherwise TID dependent calls like setAffinity will fail.
|
||||
while(PxAtomicCompareExchange(&(getThread(this)->threadStarted), 1, 1) == 0)
|
||||
yield();
|
||||
|
||||
// here we are sure that getThread(this)->state >= ePxThreadStarted
|
||||
|
||||
status = pthread_attr_destroy(&attr);
|
||||
PX_ASSERT(!status);
|
||||
|
||||
// apply stored affinity mask
|
||||
if(getThread(this)->affinityMask)
|
||||
setAffinityMask(getThread(this)->affinityMask);
|
||||
|
||||
if (getThread(this)->name)
|
||||
setName(getThread(this)->name);
|
||||
}
|
||||
|
||||
void PxThreadImpl::signalQuit()
|
||||
{
|
||||
PxAtomicIncrement(&(getThread(this)->quitNow));
|
||||
}
|
||||
|
||||
bool PxThreadImpl::waitForQuit()
|
||||
{
|
||||
if(getThread(this)->state == ePxThreadNotStarted)
|
||||
return false;
|
||||
|
||||
// works also with a stopped/exited thread if the handle is still valid
|
||||
pthread_join(getThread(this)->thread, NULL);
|
||||
getThread(this)->state = ePxThreadStopped;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PxThreadImpl::quitIsSignalled()
|
||||
{
|
||||
return PxAtomicCompareExchange(&(getThread(this)->quitNow), 0, 0) != 0;
|
||||
}
|
||||
|
||||
#if defined(PX_GCC_FAMILY)
|
||||
__attribute__((noreturn))
|
||||
#endif
|
||||
void PxThreadImpl::quit()
|
||||
{
|
||||
getThread(this)->state = ePxThreadStopped;
|
||||
pthread_exit(0);
|
||||
}
|
||||
|
||||
void PxThreadImpl::kill()
|
||||
{
|
||||
if(getThread(this)->state == ePxThreadStarted)
|
||||
pthread_cancel(getThread(this)->thread);
|
||||
getThread(this)->state = ePxThreadStopped;
|
||||
}
|
||||
|
||||
void PxThreadImpl::sleep(uint32_t ms)
|
||||
{
|
||||
timespec sleepTime;
|
||||
uint32_t remainder = ms % 1000;
|
||||
sleepTime.tv_sec = ms - remainder;
|
||||
sleepTime.tv_nsec = remainder * 1000000L;
|
||||
|
||||
while(nanosleep(&sleepTime, &sleepTime) == -1)
|
||||
continue;
|
||||
}
|
||||
|
||||
void PxThreadImpl::yield()
|
||||
{
|
||||
sched_yield();
|
||||
}
|
||||
|
||||
void PxThreadImpl::yieldProcessor()
|
||||
{
|
||||
#if (PX_ARM || PX_A64)
|
||||
__asm__ __volatile__("yield");
|
||||
#else
|
||||
__asm__ __volatile__("pause");
|
||||
#endif
|
||||
}
|
||||
|
||||
uint32_t PxThreadImpl::setAffinityMask(uint32_t mask)
|
||||
{
|
||||
// Same as windows impl if mask is zero
|
||||
if(!mask)
|
||||
return 0;
|
||||
|
||||
getThread(this)->affinityMask = mask;
|
||||
|
||||
uint64_t prevMask = 0;
|
||||
|
||||
if(getThread(this)->state == ePxThreadStarted)
|
||||
{
|
||||
#if PX_EMSCRIPTEN
|
||||
// not supported
|
||||
#elif !PX_APPLE_FAMILY // Apple doesn't support syscall with getaffinity and setaffinity
|
||||
int32_t errGet = syscall(__NR_sched_getaffinity, getThread(this)->tid, sizeof(prevMask), &prevMask);
|
||||
if(errGet < 0)
|
||||
return 0;
|
||||
|
||||
int32_t errSet = syscall(__NR_sched_setaffinity, getThread(this)->tid, sizeof(mask), &mask);
|
||||
if(errSet != 0)
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
return uint32_t(prevMask);
|
||||
}
|
||||
|
||||
void PxThreadImpl::setName(const char* name)
|
||||
{
|
||||
getThread(this)->name = name;
|
||||
|
||||
if (getThread(this)->state == ePxThreadStarted)
|
||||
{
|
||||
// not implemented because most unix APIs expect setName()
|
||||
// to be called from the thread's context. Example see next comment:
|
||||
|
||||
// this works only with the current thread and can rename
|
||||
// the main process if used in the wrong context:
|
||||
// prctl(PR_SET_NAME, reinterpret_cast<unsigned long>(name) ,0,0,0);
|
||||
PX_UNUSED(name);
|
||||
}
|
||||
}
|
||||
|
||||
#if !PX_APPLE_FAMILY
|
||||
static PxThreadPriority::Enum convertPriorityFromLinux(uint32_t inPrio, int policy)
|
||||
{
|
||||
PX_COMPILE_TIME_ASSERT(PxThreadPriority::eLOW > PxThreadPriority::eHIGH);
|
||||
PX_COMPILE_TIME_ASSERT(PxThreadPriority::eHIGH == 0);
|
||||
|
||||
int maxL = sched_get_priority_max(policy);
|
||||
int minL = sched_get_priority_min(policy);
|
||||
int rangeL = maxL - minL;
|
||||
int rangeNv = PxThreadPriority::eLOW - PxThreadPriority::eHIGH;
|
||||
|
||||
// case for default scheduler policy
|
||||
if(rangeL == 0)
|
||||
return PxThreadPriority::eNORMAL;
|
||||
|
||||
float floatPrio = (float(maxL - inPrio) * float(rangeNv)) / float(rangeL);
|
||||
|
||||
return PxThreadPriority::Enum(int(roundf(floatPrio)));
|
||||
}
|
||||
|
||||
static int convertPriorityToLinux(PxThreadPriority::Enum inPrio, int policy)
|
||||
{
|
||||
int maxL = sched_get_priority_max(policy);
|
||||
int minL = sched_get_priority_min(policy);
|
||||
int rangeL = maxL - minL;
|
||||
int rangeNv = PxThreadPriority::eLOW - PxThreadPriority::eHIGH;
|
||||
|
||||
// case for default scheduler policy
|
||||
if(rangeL == 0)
|
||||
return 0;
|
||||
|
||||
float floatPrio = (float(PxThreadPriority::eLOW - inPrio) * float(rangeL)) / float(rangeNv);
|
||||
|
||||
return minL + int(roundf(floatPrio));
|
||||
}
|
||||
#endif
|
||||
|
||||
void PxThreadImpl::setPriority(PxThreadPriority::Enum val)
|
||||
{
|
||||
PX_UNUSED(val);
|
||||
#if !PX_APPLE_FAMILY
|
||||
int policy;
|
||||
sched_param s_param;
|
||||
pthread_getschedparam(getThread(this)->thread, &policy, &s_param);
|
||||
s_param.sched_priority = convertPriorityToLinux(val, policy);
|
||||
pthread_setschedparam(getThread(this)->thread, policy, &s_param);
|
||||
#endif
|
||||
}
|
||||
|
||||
PxThreadPriority::Enum PxThreadImpl::getPriority(Id pthread)
|
||||
{
|
||||
PX_UNUSED(pthread);
|
||||
#if !PX_APPLE_FAMILY
|
||||
int policy;
|
||||
sched_param s_param;
|
||||
int ret = pthread_getschedparam(pthread_t(pthread), &policy, &s_param);
|
||||
if(ret == 0)
|
||||
return convertPriorityFromLinux(s_param.sched_priority, policy);
|
||||
else
|
||||
return PxThreadPriority::eNORMAL;
|
||||
#else
|
||||
return PxThreadPriority::eNORMAL;
|
||||
#endif
|
||||
}
|
||||
|
||||
uint32_t PxThreadImpl::getNbPhysicalCores()
|
||||
{
|
||||
#if PX_APPLE_FAMILY
|
||||
int count;
|
||||
size_t size = sizeof(count);
|
||||
return sysctlbyname("hw.physicalcpu", &count, &size, NULL, 0) ? 0 : count;
|
||||
#else
|
||||
// Linux exposes CPU topology using /sys/devices/system/cpu
|
||||
// https://www.kernel.org/doc/Documentation/cputopology.txt
|
||||
if(FILE* f = fopen("/sys/devices/system/cpu/possible", "r"))
|
||||
{
|
||||
int minIndex, maxIndex;
|
||||
int n = fscanf(f, "%d-%d", &minIndex, &maxIndex);
|
||||
fclose(f);
|
||||
|
||||
if(n == 2)
|
||||
return (maxIndex - minIndex) + 1;
|
||||
else if(n == 1)
|
||||
return minIndex + 1;
|
||||
}
|
||||
|
||||
// For non-Linux kernels this fallback is possibly the best we can do
|
||||
// but will report logical (hyper-threaded) counts
|
||||
int n = sysconf(_SC_NPROCESSORS_CONF);
|
||||
if(n < 0)
|
||||
return 0;
|
||||
else
|
||||
return n;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
PxU32 PxTlsAlloc()
|
||||
{
|
||||
pthread_key_t key;
|
||||
int status = pthread_key_create(&key, NULL);
|
||||
PX_ASSERT(!status);
|
||||
PX_UNUSED(status);
|
||||
return PxU32(key);
|
||||
}
|
||||
|
||||
void PxTlsFree(PxU32 index)
|
||||
{
|
||||
int status = pthread_key_delete(pthread_key_t(index));
|
||||
PX_ASSERT(!status);
|
||||
PX_UNUSED(status);
|
||||
}
|
||||
|
||||
void* PxTlsGet(PxU32 index)
|
||||
{
|
||||
return reinterpret_cast<void*>(pthread_getspecific(pthread_key_t(index)));
|
||||
}
|
||||
|
||||
size_t PxTlsGetValue(PxU32 index)
|
||||
{
|
||||
return reinterpret_cast<size_t>(pthread_getspecific(pthread_key_t(index)));
|
||||
}
|
||||
|
||||
PxU32 PxTlsSet(PxU32 index, void* value)
|
||||
{
|
||||
int status = pthread_setspecific(pthread_key_t(index), value);
|
||||
PX_ASSERT(!status);
|
||||
return !status;
|
||||
}
|
||||
|
||||
PxU32 PxTlsSetValue(PxU32 index, size_t value)
|
||||
{
|
||||
int status = pthread_setspecific(pthread_key_t(index), reinterpret_cast<void*>(value));
|
||||
PX_ASSERT(!status);
|
||||
return !status;
|
||||
}
|
||||
|
||||
// DM: On Linux x86-32, without implementation-specific restrictions
|
||||
// the default stack size for a new thread should be 2 megabytes (kernel.org).
|
||||
// NOTE: take care of this value on other architectures!
|
||||
PxU32 PxThreadImpl::getDefaultStackSize()
|
||||
{
|
||||
return 1 << 21;
|
||||
}
|
||||
|
||||
} // namespace physx
|
||||
115
engine/third_party/physx/source/foundation/unix/FdUnixTime.cpp
vendored
Normal file
115
engine/third_party/physx/source/foundation/unix/FdUnixTime.cpp
vendored
Normal file
@@ -0,0 +1,115 @@
|
||||
// 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-2025 NVIDIA Corporation. All rights reserved.
|
||||
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
|
||||
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
|
||||
|
||||
#include "foundation/PxTime.h"
|
||||
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#if PX_APPLE_FAMILY
|
||||
#include <mach/mach_time.h>
|
||||
#endif
|
||||
|
||||
// Use real-time high-precision timer.
|
||||
#if !PX_APPLE_FAMILY
|
||||
#define CLOCKID CLOCK_REALTIME
|
||||
#endif
|
||||
|
||||
namespace physx
|
||||
{
|
||||
|
||||
static const PxCounterFrequencyToTensOfNanos gCounterFreq = PxTime::getCounterFrequency();
|
||||
|
||||
const PxCounterFrequencyToTensOfNanos& PxTime::getBootCounterFrequency()
|
||||
{
|
||||
return gCounterFreq;
|
||||
}
|
||||
|
||||
static PxTime::Second getTimeSeconds()
|
||||
{
|
||||
static struct timeval _tv;
|
||||
gettimeofday(&_tv, NULL);
|
||||
return double(_tv.tv_sec) + double(_tv.tv_usec) * 0.000001;
|
||||
}
|
||||
|
||||
PxTime::PxTime()
|
||||
{
|
||||
mLastTime = getTimeSeconds();
|
||||
}
|
||||
|
||||
PxTime::Second PxTime::getElapsedSeconds()
|
||||
{
|
||||
PxTime::Second curTime = getTimeSeconds();
|
||||
PxTime::Second diff = curTime - mLastTime;
|
||||
mLastTime = curTime;
|
||||
return diff;
|
||||
}
|
||||
|
||||
PxTime::Second PxTime::peekElapsedSeconds()
|
||||
{
|
||||
PxTime::Second curTime = getTimeSeconds();
|
||||
PxTime::Second diff = curTime - mLastTime;
|
||||
return diff;
|
||||
}
|
||||
|
||||
PxTime::Second PxTime::getLastTime() const
|
||||
{
|
||||
return mLastTime;
|
||||
}
|
||||
|
||||
#if PX_APPLE_FAMILY
|
||||
PxCounterFrequencyToTensOfNanos PxTime::getCounterFrequency()
|
||||
{
|
||||
mach_timebase_info_data_t info;
|
||||
mach_timebase_info(&info);
|
||||
// mach_absolute_time * (info.numer/info.denom) is in units of nano seconds
|
||||
return PxCounterFrequencyToTensOfNanos(info.numer, info.denom * 10);
|
||||
}
|
||||
|
||||
uint64_t PxTime::getCurrentCounterValue()
|
||||
{
|
||||
return mach_absolute_time();
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
PxCounterFrequencyToTensOfNanos PxTime::getCounterFrequency()
|
||||
{
|
||||
return PxCounterFrequencyToTensOfNanos(1, 10);
|
||||
}
|
||||
|
||||
uint64_t PxTime::getCurrentCounterValue()
|
||||
{
|
||||
struct timespec mCurrTimeInt;
|
||||
clock_gettime(CLOCKID, &mCurrTimeInt);
|
||||
// Convert to nanos as this doesn't cause a large divide here
|
||||
return (static_cast<uint64_t>(mCurrTimeInt.tv_sec) * 1000000000) + (static_cast<uint64_t>(mCurrTimeInt.tv_nsec));
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace physx
|
||||
172
engine/third_party/physx/source/foundation/windows/FdWindowsAtomic.cpp
vendored
Normal file
172
engine/third_party/physx/source/foundation/windows/FdWindowsAtomic.cpp
vendored
Normal file
@@ -0,0 +1,172 @@
|
||||
// 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-2025 NVIDIA Corporation. All rights reserved.
|
||||
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
|
||||
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
|
||||
|
||||
#include "foundation/windows/PxWindowsInclude.h"
|
||||
#include "foundation/PxAtomic.h"
|
||||
|
||||
namespace physx
|
||||
{
|
||||
|
||||
PxI32 PxAtomicExchange(volatile PxI32* val, PxI32 val2)
|
||||
{
|
||||
return (PxI32)InterlockedExchange((volatile LONG*)val, (LONG)val2);
|
||||
}
|
||||
|
||||
PxI64 PxAtomicExchange(volatile PxI64* val, PxI64 val2)
|
||||
{
|
||||
return (PxI64)InterlockedExchange64((volatile LONG64*)val, (LONG64)val2);
|
||||
}
|
||||
|
||||
PxI32 PxAtomicCompareExchange(volatile PxI32* dest, PxI32 exch, PxI32 comp)
|
||||
{
|
||||
return (PxI32)InterlockedCompareExchange((volatile LONG*)dest, exch, comp);
|
||||
}
|
||||
|
||||
PxI64 PxAtomicCompareExchange(volatile PxI64* dest, PxI64 exch, PxI64 comp)
|
||||
{
|
||||
return (PxI64)InterlockedCompareExchange64((volatile LONG64*)dest, exch, comp);
|
||||
}
|
||||
|
||||
void* PxAtomicCompareExchangePointer(volatile void** dest, void* exch, void* comp)
|
||||
{
|
||||
return InterlockedCompareExchangePointer((volatile PVOID*)dest, exch, comp);
|
||||
}
|
||||
|
||||
PxI32 PxAtomicIncrement(volatile PxI32* val)
|
||||
{
|
||||
return (PxI32)InterlockedIncrement((volatile LONG*)val);
|
||||
}
|
||||
|
||||
PxI64 PxAtomicIncrement(volatile PxI64* val)
|
||||
{
|
||||
return (PxI64)InterlockedIncrement64((volatile LONG64*)val);
|
||||
}
|
||||
|
||||
PxI32 PxAtomicDecrement(volatile PxI32* val)
|
||||
{
|
||||
return (PxI32)InterlockedDecrement((volatile LONG*)val);
|
||||
}
|
||||
|
||||
PxI64 PxAtomicDecrement(volatile PxI64* val)
|
||||
{
|
||||
return (PxI64)InterlockedDecrement64((volatile LONG64*)val);
|
||||
}
|
||||
|
||||
PxI32 PxAtomicAdd(volatile PxI32* val, PxI32 delta)
|
||||
{
|
||||
if(1)
|
||||
{
|
||||
return (PxI32)InterlockedAdd((volatile LONG*)val, delta);
|
||||
}
|
||||
else
|
||||
{
|
||||
LONG newValue, oldValue;
|
||||
do
|
||||
{
|
||||
oldValue = *val;
|
||||
newValue = oldValue + delta;
|
||||
} while(InterlockedCompareExchange((volatile LONG*)val, newValue, oldValue) != oldValue);
|
||||
|
||||
return newValue;
|
||||
}
|
||||
}
|
||||
|
||||
PxI64 PxAtomicAdd(volatile PxI64* val, PxI64 delta)
|
||||
{
|
||||
if(1)
|
||||
{
|
||||
return (PxI64)InterlockedAdd64((volatile LONG64*)val, delta);
|
||||
}
|
||||
else
|
||||
{
|
||||
LONG64 newValue, oldValue;
|
||||
do
|
||||
{
|
||||
oldValue = *val;
|
||||
newValue = oldValue + delta;
|
||||
} while(InterlockedCompareExchange64((volatile LONG64*)val, newValue, oldValue) != oldValue);
|
||||
|
||||
return newValue;
|
||||
}
|
||||
}
|
||||
|
||||
PxI32 PxAtomicMax(volatile PxI32* val, PxI32 val2)
|
||||
{
|
||||
// Could do this more efficiently in asm...
|
||||
|
||||
LONG newValue, oldValue;
|
||||
|
||||
do
|
||||
{
|
||||
oldValue = *val;
|
||||
|
||||
newValue = val2 > oldValue ? val2 : oldValue;
|
||||
|
||||
} while(InterlockedCompareExchange((volatile LONG*)val, newValue, oldValue) != oldValue);
|
||||
|
||||
return newValue;
|
||||
}
|
||||
|
||||
PxI64 PxAtomicMax(volatile PxI64* val, PxI64 val2)
|
||||
{
|
||||
// Could do this more efficiently in asm...
|
||||
|
||||
LONG64 newValue, oldValue;
|
||||
|
||||
do
|
||||
{
|
||||
oldValue = *val;
|
||||
|
||||
newValue = val2 > oldValue ? val2 : oldValue;
|
||||
|
||||
} while(InterlockedCompareExchange64((volatile LONG64*)val, newValue, oldValue) != oldValue);
|
||||
|
||||
return newValue;
|
||||
}
|
||||
|
||||
PxI32 PxAtomicOr(volatile PxI32* val, PxI32 mask)
|
||||
{
|
||||
return (PxI32)InterlockedOr((volatile LONG*)val, mask);
|
||||
}
|
||||
|
||||
PxI64 PxAtomicOr(volatile PxI64* val, PxI64 mask)
|
||||
{
|
||||
return (PxI64)InterlockedOr64((volatile LONG64*)val, mask);
|
||||
}
|
||||
|
||||
PxI32 PxAtomicAnd(volatile PxI32* val, PxI32 mask)
|
||||
{
|
||||
return (PxI32)InterlockedAnd((volatile LONG*)val, mask);
|
||||
}
|
||||
|
||||
PxI64 PxAtomicAnd(volatile PxI64* val, PxI64 mask)
|
||||
{
|
||||
return (PxI64)InterlockedAnd64((volatile LONG64*)val, mask);
|
||||
}
|
||||
|
||||
} // namespace physx
|
||||
88
engine/third_party/physx/source/foundation/windows/FdWindowsFPU.cpp
vendored
Normal file
88
engine/third_party/physx/source/foundation/windows/FdWindowsFPU.cpp
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
// 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-2025 NVIDIA Corporation. All rights reserved.
|
||||
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
|
||||
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
|
||||
|
||||
#include "foundation/PxFPU.h"
|
||||
#include "float.h"
|
||||
#include "foundation/PxIntrinsics.h"
|
||||
|
||||
#if PX_X64 || PX_ARM || PX_A64
|
||||
#define _MCW_ALL _MCW_DN | _MCW_EM | _MCW_RC
|
||||
#else
|
||||
#define _MCW_ALL _MCW_DN | _MCW_EM | _MCW_IC | _MCW_RC | _MCW_PC
|
||||
#endif
|
||||
|
||||
physx::PxFPUGuard::PxFPUGuard()
|
||||
{
|
||||
// default plus FTZ and DAZ
|
||||
#if PX_X64 || PX_ARM || PX_A64
|
||||
// query current control word state
|
||||
_controlfp_s(mControlWords, 0, 0);
|
||||
|
||||
// set both x87 and sse units to default + DAZ
|
||||
unsigned int cw;
|
||||
_controlfp_s(&cw, _CW_DEFAULT | _DN_FLUSH, _MCW_ALL);
|
||||
#else
|
||||
// query current control word state
|
||||
__control87_2(0, 0, mControlWords, mControlWords + 1);
|
||||
|
||||
// set both x87 and sse units to default + DAZ
|
||||
unsigned int x87, sse;
|
||||
__control87_2(_CW_DEFAULT | _DN_FLUSH, _MCW_ALL, &x87, &sse);
|
||||
#endif
|
||||
}
|
||||
|
||||
physx::PxFPUGuard::~PxFPUGuard()
|
||||
{
|
||||
_clearfp();
|
||||
|
||||
#if PX_X64 || PX_ARM || PX_A64
|
||||
// reset FP state
|
||||
unsigned int cw;
|
||||
_controlfp_s(&cw, *mControlWords, _MCW_ALL);
|
||||
#else
|
||||
|
||||
// reset FP state
|
||||
unsigned int x87, sse;
|
||||
__control87_2(mControlWords[0], _MCW_ALL, &x87, 0);
|
||||
__control87_2(mControlWords[1], _MCW_ALL, 0, &sse);
|
||||
#endif
|
||||
}
|
||||
|
||||
void physx::PxEnableFPExceptions()
|
||||
{
|
||||
// clear any pending exceptions
|
||||
_clearfp();
|
||||
|
||||
// enable all fp exceptions except inexact and underflow (common, benign)
|
||||
_controlfp_s(NULL, uint32_t(~_MCW_EM) | _EM_INEXACT | _EM_UNDERFLOW, _MCW_EM);
|
||||
}
|
||||
|
||||
void physx::PxDisableFPExceptions()
|
||||
{
|
||||
_controlfp_s(NULL, _MCW_EM, _MCW_EM);
|
||||
}
|
||||
154
engine/third_party/physx/source/foundation/windows/FdWindowsMutex.cpp
vendored
Normal file
154
engine/third_party/physx/source/foundation/windows/FdWindowsMutex.cpp
vendored
Normal file
@@ -0,0 +1,154 @@
|
||||
// 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-2025 NVIDIA Corporation. All rights reserved.
|
||||
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
|
||||
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
|
||||
|
||||
#include "foundation/windows/PxWindowsInclude.h"
|
||||
#include "foundation/PxUserAllocated.h"
|
||||
#include "foundation/PxMutex.h"
|
||||
#include "foundation/PxErrorCallback.h"
|
||||
#include "foundation/PxThread.h"
|
||||
|
||||
namespace physx
|
||||
{
|
||||
namespace
|
||||
{
|
||||
struct MutexWinImpl
|
||||
{
|
||||
CRITICAL_SECTION mLock;
|
||||
PxThread::Id mOwner;
|
||||
};
|
||||
}
|
||||
|
||||
static PX_FORCE_INLINE MutexWinImpl* getMutex(PxMutexImpl* impl)
|
||||
{
|
||||
return reinterpret_cast<MutexWinImpl*>(impl);
|
||||
}
|
||||
|
||||
PxMutexImpl::PxMutexImpl()
|
||||
{
|
||||
InitializeCriticalSection(&getMutex(this)->mLock);
|
||||
getMutex(this)->mOwner = 0;
|
||||
}
|
||||
|
||||
PxMutexImpl::~PxMutexImpl()
|
||||
{
|
||||
DeleteCriticalSection(&getMutex(this)->mLock);
|
||||
}
|
||||
|
||||
void PxMutexImpl::lock()
|
||||
{
|
||||
EnterCriticalSection(&getMutex(this)->mLock);
|
||||
|
||||
#if PX_DEBUG
|
||||
getMutex(this)->mOwner = PxThread::getId();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool PxMutexImpl::trylock()
|
||||
{
|
||||
bool success = TryEnterCriticalSection(&getMutex(this)->mLock) != 0;
|
||||
#if PX_DEBUG
|
||||
if(success)
|
||||
getMutex(this)->mOwner = PxThread::getId();
|
||||
#endif
|
||||
return success;
|
||||
}
|
||||
|
||||
void PxMutexImpl::unlock()
|
||||
{
|
||||
#if PX_DEBUG
|
||||
// ensure we are already holding the lock
|
||||
if(getMutex(this)->mOwner != PxThread::getId())
|
||||
{
|
||||
PxGetFoundation().error(PxErrorCode::eINVALID_OPERATION, PX_FL, "Mutex must be unlocked only by thread that has already acquired lock");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
LeaveCriticalSection(&getMutex(this)->mLock);
|
||||
}
|
||||
|
||||
uint32_t PxMutexImpl::getSize()
|
||||
{
|
||||
return sizeof(MutexWinImpl);
|
||||
}
|
||||
|
||||
class ReadWriteLockImpl
|
||||
{
|
||||
PX_NOCOPY(ReadWriteLockImpl)
|
||||
public:
|
||||
ReadWriteLockImpl()
|
||||
{
|
||||
}
|
||||
PxMutex mutex;
|
||||
volatile LONG readerCount; // handle recursive writer locking
|
||||
};
|
||||
|
||||
PxReadWriteLock::PxReadWriteLock()
|
||||
{
|
||||
mImpl = reinterpret_cast<ReadWriteLockImpl*>(PX_ALLOC(sizeof(ReadWriteLockImpl), "ReadWriteLockImpl"));
|
||||
PX_PLACEMENT_NEW(mImpl, ReadWriteLockImpl);
|
||||
|
||||
mImpl->readerCount = 0;
|
||||
}
|
||||
|
||||
PxReadWriteLock::~PxReadWriteLock()
|
||||
{
|
||||
mImpl->~ReadWriteLockImpl();
|
||||
PX_FREE(mImpl);
|
||||
}
|
||||
|
||||
void PxReadWriteLock::lockReader(bool takeLock)
|
||||
{
|
||||
if(takeLock)
|
||||
mImpl->mutex.lock();
|
||||
|
||||
InterlockedIncrement(&mImpl->readerCount);
|
||||
|
||||
if(takeLock)
|
||||
mImpl->mutex.unlock();
|
||||
}
|
||||
|
||||
void PxReadWriteLock::lockWriter()
|
||||
{
|
||||
mImpl->mutex.lock();
|
||||
|
||||
// spin lock until no readers
|
||||
while(mImpl->readerCount);
|
||||
}
|
||||
|
||||
void PxReadWriteLock::unlockReader()
|
||||
{
|
||||
InterlockedDecrement(&mImpl->readerCount);
|
||||
}
|
||||
|
||||
void PxReadWriteLock::unlockWriter()
|
||||
{
|
||||
mImpl->mutex.unlock();
|
||||
}
|
||||
|
||||
} // namespace physx
|
||||
42
engine/third_party/physx/source/foundation/windows/FdWindowsPrintString.cpp
vendored
Normal file
42
engine/third_party/physx/source/foundation/windows/FdWindowsPrintString.cpp
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
// 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-2025 NVIDIA Corporation. All rights reserved.
|
||||
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
|
||||
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
|
||||
|
||||
#include "foundation/PxString.h"
|
||||
#include <stdio.h>
|
||||
#include "foundation/windows/PxWindowsInclude.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
void physx::PxPrintString(const char* str)
|
||||
{
|
||||
puts(str); // do not use printf here, since str can contain multiple % signs that will not be printed
|
||||
OutputDebugStringA(str);
|
||||
OutputDebugStringA("\n");
|
||||
}
|
||||
68
engine/third_party/physx/source/foundation/windows/FdWindowsSList.cpp
vendored
Normal file
68
engine/third_party/physx/source/foundation/windows/FdWindowsSList.cpp
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
// 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-2025 NVIDIA Corporation. All rights reserved.
|
||||
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
|
||||
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
|
||||
|
||||
#include "foundation/windows/PxWindowsInclude.h"
|
||||
#include "foundation/PxAllocator.h"
|
||||
#include "foundation/PxSList.h"
|
||||
|
||||
using namespace physx;
|
||||
|
||||
template <typename T>
|
||||
static PX_FORCE_INLINE SLIST_HEADER* getDetail(T* impl)
|
||||
{
|
||||
return reinterpret_cast<SLIST_HEADER*>(impl);
|
||||
}
|
||||
|
||||
PxSListImpl::PxSListImpl()
|
||||
{
|
||||
InitializeSListHead(getDetail(this));
|
||||
}
|
||||
|
||||
PxSListImpl::~PxSListImpl()
|
||||
{
|
||||
}
|
||||
|
||||
void PxSListImpl::push(PxSListEntry* entry)
|
||||
{
|
||||
InterlockedPushEntrySList(getDetail(this), reinterpret_cast<SLIST_ENTRY*>(entry));
|
||||
}
|
||||
|
||||
PxSListEntry* PxSListImpl::pop()
|
||||
{
|
||||
return reinterpret_cast<PxSListEntry*>(InterlockedPopEntrySList(getDetail(this)));
|
||||
}
|
||||
|
||||
PxSListEntry* PxSListImpl::flush()
|
||||
{
|
||||
return reinterpret_cast<PxSListEntry*>(InterlockedFlushSList(getDetail(this)));
|
||||
}
|
||||
|
||||
uint32_t PxSListImpl::getSize()
|
||||
{
|
||||
return sizeof(SLIST_HEADER);
|
||||
}
|
||||
438
engine/third_party/physx/source/foundation/windows/FdWindowsSocket.cpp
vendored
Normal file
438
engine/third_party/physx/source/foundation/windows/FdWindowsSocket.cpp
vendored
Normal file
@@ -0,0 +1,438 @@
|
||||
// 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-2025 NVIDIA Corporation. All rights reserved.
|
||||
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
|
||||
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
|
||||
|
||||
#include "foundation/PxMathIntrinsics.h"
|
||||
#include "foundation/windows/PxWindowsInclude.h"
|
||||
#include "foundation/PxSocket.h"
|
||||
#include "foundation/PxThread.h"
|
||||
#include "foundation/PxArray.h"
|
||||
|
||||
#include <Winsock2.h>
|
||||
#pragma comment(lib, "Ws2_32")
|
||||
|
||||
namespace physx
|
||||
{
|
||||
const uint32_t PxSocket::DEFAULT_BUFFER_SIZE = 32768;
|
||||
|
||||
class SocketImpl
|
||||
{
|
||||
public:
|
||||
SocketImpl(bool isBlocking);
|
||||
virtual ~SocketImpl();
|
||||
|
||||
bool connect(const char* host, uint16_t port, uint32_t timeout);
|
||||
bool listen(uint16_t port);
|
||||
bool accept(bool block);
|
||||
void disconnect();
|
||||
|
||||
void setBlocking(bool blocking);
|
||||
|
||||
virtual uint32_t write(const uint8_t* data, uint32_t length);
|
||||
virtual bool flush();
|
||||
uint32_t read(uint8_t* data, uint32_t length);
|
||||
|
||||
PX_FORCE_INLINE bool isBlocking() const
|
||||
{
|
||||
return mIsBlocking;
|
||||
}
|
||||
PX_FORCE_INLINE bool isConnected() const
|
||||
{
|
||||
return mIsConnected;
|
||||
}
|
||||
PX_FORCE_INLINE const char* getHost() const
|
||||
{
|
||||
return mHost;
|
||||
}
|
||||
PX_FORCE_INLINE uint16_t getPort() const
|
||||
{
|
||||
return mPort;
|
||||
}
|
||||
|
||||
protected:
|
||||
bool nonBlockingTimeout() const;
|
||||
void setBlockingInternal(SOCKET socket, bool blocking);
|
||||
|
||||
mutable SOCKET mSocket;
|
||||
SOCKET mListenSocket;
|
||||
const char* mHost;
|
||||
uint16_t mPort;
|
||||
mutable bool mIsConnected;
|
||||
bool mIsBlocking;
|
||||
bool mListenMode;
|
||||
bool mSocketLayerIntialized;
|
||||
};
|
||||
|
||||
SocketImpl::SocketImpl(bool isBlocking)
|
||||
: mSocket(INVALID_SOCKET)
|
||||
, mListenSocket(INVALID_SOCKET)
|
||||
, mPort(0)
|
||||
, mHost(NULL)
|
||||
, mIsConnected(false)
|
||||
, mIsBlocking(isBlocking)
|
||||
, mListenMode(false)
|
||||
, mSocketLayerIntialized(false)
|
||||
{
|
||||
WORD vreq;
|
||||
WSADATA wsaData;
|
||||
vreq = MAKEWORD(2, 2);
|
||||
mSocketLayerIntialized = (WSAStartup(vreq, &wsaData) == 0);
|
||||
}
|
||||
|
||||
SocketImpl::~SocketImpl()
|
||||
{
|
||||
if(mSocketLayerIntialized)
|
||||
WSACleanup();
|
||||
}
|
||||
|
||||
void SocketImpl::setBlockingInternal(SOCKET socket, bool blocking)
|
||||
{
|
||||
uint32_t mode = uint32_t(blocking ? 0 : 1);
|
||||
ioctlsocket(socket, FIONBIO, (u_long*)&mode);
|
||||
}
|
||||
|
||||
bool SocketImpl::connect(const char* host, uint16_t port, uint32_t timeout)
|
||||
{
|
||||
if(!mSocketLayerIntialized)
|
||||
return false;
|
||||
|
||||
sockaddr_in socketAddress;
|
||||
hostent* hp;
|
||||
|
||||
intrinsics::memSet(&socketAddress, 0, sizeof(sockaddr_in));
|
||||
socketAddress.sin_family = AF_INET;
|
||||
socketAddress.sin_port = htons(port);
|
||||
|
||||
// get host
|
||||
hp = gethostbyname(host);
|
||||
if(!hp)
|
||||
{
|
||||
in_addr a;
|
||||
a.s_addr = inet_addr(host);
|
||||
hp = gethostbyaddr((const char*)&a, sizeof(in_addr), AF_INET);
|
||||
if(!hp)
|
||||
return false;
|
||||
}
|
||||
intrinsics::memCopy(&socketAddress.sin_addr, hp->h_addr_list[0], (uint32_t)hp->h_length);
|
||||
|
||||
// connect
|
||||
mSocket = socket(PF_INET, SOCK_STREAM, 0);
|
||||
if(mSocket == INVALID_SOCKET)
|
||||
return false;
|
||||
|
||||
setBlockingInternal(mSocket, false);
|
||||
|
||||
::connect(mSocket, (sockaddr*)&socketAddress, sizeof(socketAddress));
|
||||
|
||||
// Setup poll function call to monitor the connect call.
|
||||
// By querying for POLLOUT we're checking if the socket is
|
||||
// ready for writing.
|
||||
WSAPOLLFD pfd;
|
||||
pfd.fd = mSocket;
|
||||
pfd.events = POLLOUT;
|
||||
const int pollResult = WSAPoll(&pfd, 1, timeout /*milliseconds*/);
|
||||
|
||||
const bool pollTimeout = (pollResult == 0);
|
||||
const bool pollError = (pollResult == SOCKET_ERROR); // an error inside poll happened. Can check error with `WSAGetLastError`.
|
||||
if(pollTimeout || pollError)
|
||||
{
|
||||
disconnect();
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
PX_ASSERT(pollResult == 1);
|
||||
// check that event was precisely POLLOUT and not anything else (e.g., errors, hang-up)
|
||||
bool test = (pfd.revents & POLLOUT) && !(pfd.revents & (~POLLOUT));
|
||||
if(!test)
|
||||
{
|
||||
disconnect();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
setBlockingInternal(mSocket, mIsBlocking);
|
||||
|
||||
mIsConnected = true;
|
||||
mPort = port;
|
||||
mHost = host;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SocketImpl::listen(uint16_t port)
|
||||
{
|
||||
if(!mSocketLayerIntialized)
|
||||
return false;
|
||||
|
||||
mListenSocket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if(mListenSocket == INVALID_SOCKET)
|
||||
return false;
|
||||
|
||||
mListenMode = true;
|
||||
|
||||
sockaddr_in addr = { 0 };
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(port);
|
||||
addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
return bind(mListenSocket, (sockaddr*)&addr, sizeof(addr)) == 0 && ::listen(mListenSocket, SOMAXCONN) == 0;
|
||||
}
|
||||
|
||||
bool SocketImpl::accept(bool block)
|
||||
{
|
||||
if(mIsConnected || !mListenMode)
|
||||
return false;
|
||||
|
||||
// set the listen socket to be non-blocking.
|
||||
setBlockingInternal(mListenSocket, block);
|
||||
SOCKET clientSocket = ::accept(mListenSocket, 0, 0);
|
||||
if(clientSocket == INVALID_SOCKET)
|
||||
return false;
|
||||
|
||||
mSocket = clientSocket;
|
||||
mIsConnected = true;
|
||||
setBlockingInternal(mSocket, mIsBlocking); // force the mode to whatever the user set
|
||||
|
||||
return mIsConnected;
|
||||
}
|
||||
|
||||
void SocketImpl::disconnect()
|
||||
{
|
||||
if(mListenSocket != INVALID_SOCKET)
|
||||
{
|
||||
closesocket(mListenSocket);
|
||||
mListenSocket = INVALID_SOCKET;
|
||||
}
|
||||
if(mSocket != INVALID_SOCKET)
|
||||
{
|
||||
WSASendDisconnect(mSocket, NULL);
|
||||
closesocket(mSocket);
|
||||
mSocket = INVALID_SOCKET;
|
||||
}
|
||||
mIsConnected = false;
|
||||
mListenMode = false;
|
||||
mPort = 0;
|
||||
mHost = NULL;
|
||||
}
|
||||
|
||||
bool SocketImpl::nonBlockingTimeout() const
|
||||
{
|
||||
return !mIsBlocking && WSAGetLastError() == WSAEWOULDBLOCK;
|
||||
}
|
||||
|
||||
// should be cross-platform from here down
|
||||
|
||||
void SocketImpl::setBlocking(bool blocking)
|
||||
{
|
||||
if(blocking != mIsBlocking)
|
||||
{
|
||||
mIsBlocking = blocking;
|
||||
if(isConnected())
|
||||
setBlockingInternal(mSocket, blocking);
|
||||
}
|
||||
}
|
||||
|
||||
bool SocketImpl::flush()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t SocketImpl::write(const uint8_t* data, uint32_t length)
|
||||
{
|
||||
if(length == 0)
|
||||
return 0;
|
||||
|
||||
int sent = send(mSocket, (const char*)data, (int32_t)length, 0);
|
||||
|
||||
if(sent <= 0 && !nonBlockingTimeout())
|
||||
disconnect();
|
||||
|
||||
return uint32_t(sent > 0 ? sent : 0);
|
||||
}
|
||||
|
||||
uint32_t SocketImpl::read(uint8_t* data, uint32_t length)
|
||||
{
|
||||
if(length == 0)
|
||||
return 0;
|
||||
|
||||
int32_t received = recv(mSocket, (char*)data, (int32_t)length, 0);
|
||||
|
||||
if(received <= 0 && !nonBlockingTimeout())
|
||||
disconnect();
|
||||
|
||||
return uint32_t(received > 0 ? received : 0);
|
||||
}
|
||||
|
||||
class BufferedSocketImpl : public SocketImpl
|
||||
{
|
||||
public:
|
||||
BufferedSocketImpl(bool isBlocking) : SocketImpl(isBlocking), mBufferPos(0)
|
||||
{
|
||||
}
|
||||
virtual ~BufferedSocketImpl()
|
||||
{
|
||||
}
|
||||
bool flush();
|
||||
uint32_t write(const uint8_t* data, uint32_t length);
|
||||
|
||||
private:
|
||||
uint32_t mBufferPos;
|
||||
uint8_t mBuffer[PxSocket::DEFAULT_BUFFER_SIZE];
|
||||
};
|
||||
|
||||
bool BufferedSocketImpl::flush()
|
||||
{
|
||||
uint32_t totalBytesWritten = 0;
|
||||
|
||||
while(totalBytesWritten < mBufferPos && mIsConnected)
|
||||
totalBytesWritten += (int32_t)SocketImpl::write(mBuffer + totalBytesWritten, mBufferPos - totalBytesWritten);
|
||||
|
||||
bool ret = (totalBytesWritten == mBufferPos);
|
||||
mBufferPos = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t BufferedSocketImpl::write(const uint8_t* data, uint32_t length)
|
||||
{
|
||||
uint32_t bytesWritten = 0;
|
||||
while(mBufferPos + length >= PxSocket::DEFAULT_BUFFER_SIZE)
|
||||
{
|
||||
uint32_t currentChunk = PxSocket::DEFAULT_BUFFER_SIZE - mBufferPos;
|
||||
intrinsics::memCopy(mBuffer + mBufferPos, data + bytesWritten, currentChunk);
|
||||
bytesWritten += (uint32_t)currentChunk; // for the user, this is consumed even if we fail to shove it down a
|
||||
// non-blocking socket
|
||||
|
||||
uint32_t sent = SocketImpl::write(mBuffer, PxSocket::DEFAULT_BUFFER_SIZE);
|
||||
mBufferPos = PxSocket::DEFAULT_BUFFER_SIZE - sent;
|
||||
|
||||
if(sent < PxSocket::DEFAULT_BUFFER_SIZE) // non-blocking or error
|
||||
{
|
||||
if(sent) // we can reasonably hope this is rare
|
||||
intrinsics::memMove(mBuffer, mBuffer + sent, mBufferPos);
|
||||
|
||||
return bytesWritten;
|
||||
}
|
||||
length -= currentChunk;
|
||||
}
|
||||
|
||||
if(length > 0)
|
||||
{
|
||||
intrinsics::memCopy(mBuffer + mBufferPos, data + bytesWritten, length);
|
||||
bytesWritten += length;
|
||||
mBufferPos += length;
|
||||
}
|
||||
|
||||
return bytesWritten;
|
||||
}
|
||||
|
||||
PxSocket::PxSocket(bool inIsBuffering, bool isBlocking)
|
||||
{
|
||||
if(inIsBuffering)
|
||||
{
|
||||
void* mem = PX_ALLOC(sizeof(BufferedSocketImpl), "BufferedSocketImpl");
|
||||
mImpl = PX_PLACEMENT_NEW(mem, BufferedSocketImpl)(isBlocking);
|
||||
}
|
||||
else
|
||||
{
|
||||
void* mem = PX_ALLOC(sizeof(SocketImpl), "SocketImpl");
|
||||
mImpl = PX_PLACEMENT_NEW(mem, SocketImpl)(isBlocking);
|
||||
}
|
||||
}
|
||||
|
||||
PxSocket::~PxSocket()
|
||||
{
|
||||
mImpl->flush();
|
||||
mImpl->disconnect();
|
||||
mImpl->~SocketImpl();
|
||||
PX_FREE(mImpl);
|
||||
}
|
||||
|
||||
bool PxSocket::connect(const char* host, uint16_t port, uint32_t timeout)
|
||||
{
|
||||
return mImpl->connect(host, port, timeout);
|
||||
}
|
||||
|
||||
bool PxSocket::listen(uint16_t port)
|
||||
{
|
||||
return mImpl->listen(port);
|
||||
}
|
||||
|
||||
bool PxSocket::accept(bool block)
|
||||
{
|
||||
return mImpl->accept(block);
|
||||
}
|
||||
|
||||
void PxSocket::disconnect()
|
||||
{
|
||||
mImpl->disconnect();
|
||||
}
|
||||
|
||||
bool PxSocket::isConnected() const
|
||||
{
|
||||
return mImpl->isConnected();
|
||||
}
|
||||
|
||||
const char* PxSocket::getHost() const
|
||||
{
|
||||
return mImpl->getHost();
|
||||
}
|
||||
|
||||
uint16_t PxSocket::getPort() const
|
||||
{
|
||||
return mImpl->getPort();
|
||||
}
|
||||
|
||||
bool PxSocket::flush()
|
||||
{
|
||||
if(!mImpl->isConnected())
|
||||
return false;
|
||||
return mImpl->flush();
|
||||
}
|
||||
|
||||
uint32_t PxSocket::write(const uint8_t* data, uint32_t length)
|
||||
{
|
||||
if(!mImpl->isConnected())
|
||||
return 0;
|
||||
return mImpl->write(data, length);
|
||||
}
|
||||
|
||||
uint32_t PxSocket::read(uint8_t* data, uint32_t length)
|
||||
{
|
||||
if(!mImpl->isConnected())
|
||||
return 0;
|
||||
return mImpl->read(data, length);
|
||||
}
|
||||
|
||||
void PxSocket::setBlocking(bool blocking)
|
||||
{
|
||||
mImpl->setBlocking(blocking);
|
||||
}
|
||||
|
||||
bool PxSocket::isBlocking() const
|
||||
{
|
||||
return mImpl->isBlocking();
|
||||
}
|
||||
} // namespace physx
|
||||
72
engine/third_party/physx/source/foundation/windows/FdWindowsSync.cpp
vendored
Normal file
72
engine/third_party/physx/source/foundation/windows/FdWindowsSync.cpp
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
// 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-2025 NVIDIA Corporation. All rights reserved.
|
||||
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
|
||||
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
|
||||
|
||||
#include "foundation/windows/PxWindowsInclude.h"
|
||||
#include "foundation/PxUserAllocated.h"
|
||||
#include "foundation/PxSync.h"
|
||||
|
||||
using namespace physx;
|
||||
|
||||
static PX_FORCE_INLINE HANDLE& getSync(PxSyncImpl* impl)
|
||||
{
|
||||
return *reinterpret_cast<HANDLE*>(impl);
|
||||
}
|
||||
|
||||
uint32_t PxSyncImpl::getSize()
|
||||
{
|
||||
return sizeof(HANDLE);
|
||||
}
|
||||
|
||||
PxSyncImpl::PxSyncImpl()
|
||||
{
|
||||
getSync(this) = CreateEvent(0, true, false, 0);
|
||||
}
|
||||
|
||||
PxSyncImpl::~PxSyncImpl()
|
||||
{
|
||||
CloseHandle(getSync(this));
|
||||
}
|
||||
|
||||
void PxSyncImpl::reset()
|
||||
{
|
||||
ResetEvent(getSync(this));
|
||||
}
|
||||
|
||||
void PxSyncImpl::set()
|
||||
{
|
||||
SetEvent(getSync(this));
|
||||
}
|
||||
|
||||
bool PxSyncImpl::wait(uint32_t milliseconds)
|
||||
{
|
||||
if(milliseconds == -1)
|
||||
milliseconds = INFINITE;
|
||||
|
||||
return WaitForSingleObject(getSync(this), milliseconds) == WAIT_OBJECT_0;
|
||||
}
|
||||
|
||||
421
engine/third_party/physx/source/foundation/windows/FdWindowsThread.cpp
vendored
Normal file
421
engine/third_party/physx/source/foundation/windows/FdWindowsThread.cpp
vendored
Normal file
@@ -0,0 +1,421 @@
|
||||
// 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-2025 NVIDIA Corporation. All rights reserved.
|
||||
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
|
||||
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
|
||||
|
||||
#include "foundation/windows/PxWindowsInclude.h"
|
||||
#include "foundation/PxErrorCallback.h"
|
||||
#include "foundation/PxAssert.h"
|
||||
#include "foundation/PxThread.h"
|
||||
#include "foundation/PxAlloca.h"
|
||||
|
||||
// an exception for setting the thread name in Microsoft debuggers
|
||||
#define NS_MS_VC_EXCEPTION 0x406D1388
|
||||
|
||||
namespace physx
|
||||
{
|
||||
namespace
|
||||
{
|
||||
|
||||
#if PX_VC
|
||||
#pragma warning(disable : 4061) // enumerator 'identifier' in switch of enum 'enumeration' is not handled
|
||||
#pragma warning(disable : 4191) //'operator/operation' : unsafe conversion from 'type of expression' to 'type required'
|
||||
#endif
|
||||
|
||||
// struct for naming a thread in the debugger
|
||||
#pragma pack(push, 8)
|
||||
|
||||
typedef struct tagTHREADNAME_INFO
|
||||
{
|
||||
DWORD dwType; // Must be 0x1000.
|
||||
LPCSTR szName; // Pointer to name (in user addr space).
|
||||
DWORD dwThreadID; // Thread ID (-1=caller thread).
|
||||
DWORD dwFlags; // Reserved for future use, must be zero.
|
||||
} THREADNAME_INFO;
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
class ThreadImpl
|
||||
{
|
||||
public:
|
||||
enum State
|
||||
{
|
||||
NotStarted,
|
||||
Started,
|
||||
Stopped
|
||||
};
|
||||
|
||||
HANDLE thread;
|
||||
LONG quitNow; // Should be 32bit aligned on SMP systems.
|
||||
State state;
|
||||
DWORD threadID;
|
||||
|
||||
PxThreadImpl::ExecuteFn fn;
|
||||
void* arg;
|
||||
|
||||
uint32_t affinityMask;
|
||||
const char* name;
|
||||
};
|
||||
|
||||
static PX_FORCE_INLINE ThreadImpl* getThread(PxThreadImpl* impl)
|
||||
{
|
||||
return reinterpret_cast<ThreadImpl*>(impl);
|
||||
}
|
||||
|
||||
static DWORD WINAPI PxThreadStart(LPVOID arg)
|
||||
{
|
||||
ThreadImpl* impl = getThread((PxThreadImpl*)arg);
|
||||
|
||||
// run either the passed in function or execute from the derived class (Runnable).
|
||||
if(impl->fn)
|
||||
(*impl->fn)(impl->arg);
|
||||
else if(impl->arg)
|
||||
((PxRunnable*)impl->arg)->execute();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// cache physical thread count
|
||||
static uint32_t gPhysicalCoreCount = 0;
|
||||
}
|
||||
|
||||
uint32_t PxThreadImpl::getSize()
|
||||
{
|
||||
return sizeof(ThreadImpl);
|
||||
}
|
||||
|
||||
PxThreadImpl::Id PxThreadImpl::getId()
|
||||
{
|
||||
return static_cast<Id>(GetCurrentThreadId());
|
||||
}
|
||||
|
||||
// fwd GetLogicalProcessorInformation()
|
||||
typedef BOOL(WINAPI* LPFN_GLPI)(PSYSTEM_LOGICAL_PROCESSOR_INFORMATION, PDWORD);
|
||||
|
||||
uint32_t PxThreadImpl::getNbPhysicalCores()
|
||||
{
|
||||
if(!gPhysicalCoreCount)
|
||||
{
|
||||
// modified example code from: http://msdn.microsoft.com/en-us/library/ms683194
|
||||
LPFN_GLPI glpi;
|
||||
PSYSTEM_LOGICAL_PROCESSOR_INFORMATION buffer = NULL;
|
||||
PSYSTEM_LOGICAL_PROCESSOR_INFORMATION ptr = NULL;
|
||||
DWORD returnLength = 0;
|
||||
DWORD processorCoreCount = 0;
|
||||
DWORD byteOffset = 0;
|
||||
|
||||
glpi = (LPFN_GLPI)GetProcAddress(GetModuleHandle(TEXT("kernel32")), "GetLogicalProcessorInformation");
|
||||
|
||||
if(NULL == glpi)
|
||||
{
|
||||
// GetLogicalProcessorInformation not supported on OS < XP Service Pack 3
|
||||
return 0;
|
||||
}
|
||||
|
||||
DWORD rc = (DWORD)glpi(NULL, &returnLength);
|
||||
PX_ASSERT(rc == FALSE);
|
||||
PX_UNUSED(rc);
|
||||
|
||||
// first query reports required buffer space
|
||||
if(GetLastError() == ERROR_INSUFFICIENT_BUFFER)
|
||||
{
|
||||
buffer = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION)PxAlloca(returnLength);
|
||||
}
|
||||
else
|
||||
{
|
||||
PxGetFoundation().error(PxErrorCode::eINTERNAL_ERROR, PX_FL, "Error querying buffer size for number of physical processors");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// retrieve data
|
||||
rc = (DWORD)glpi(buffer, &returnLength);
|
||||
if(rc != TRUE)
|
||||
{
|
||||
PxGetFoundation().error(PxErrorCode::eINTERNAL_ERROR, PX_FL, "Error querying number of physical processors");
|
||||
return 0;
|
||||
}
|
||||
|
||||
ptr = buffer;
|
||||
|
||||
while(byteOffset + sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION) <= returnLength)
|
||||
{
|
||||
switch(ptr->Relationship)
|
||||
{
|
||||
case RelationProcessorCore:
|
||||
processorCoreCount++;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
byteOffset += sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
|
||||
ptr++;
|
||||
}
|
||||
|
||||
gPhysicalCoreCount = processorCoreCount;
|
||||
}
|
||||
|
||||
return gPhysicalCoreCount;
|
||||
}
|
||||
|
||||
PxThreadImpl::PxThreadImpl()
|
||||
{
|
||||
getThread(this)->thread = NULL;
|
||||
getThread(this)->state = ThreadImpl::NotStarted;
|
||||
getThread(this)->quitNow = 0;
|
||||
getThread(this)->fn = NULL;
|
||||
getThread(this)->arg = NULL;
|
||||
getThread(this)->affinityMask = 0;
|
||||
getThread(this)->name = NULL;
|
||||
}
|
||||
|
||||
PxThreadImpl::PxThreadImpl(ExecuteFn fn, void* arg, const char* name)
|
||||
{
|
||||
getThread(this)->thread = NULL;
|
||||
getThread(this)->state = ThreadImpl::NotStarted;
|
||||
getThread(this)->quitNow = 0;
|
||||
getThread(this)->fn = fn;
|
||||
getThread(this)->arg = arg;
|
||||
getThread(this)->affinityMask = 0;
|
||||
getThread(this)->name = name;
|
||||
|
||||
start(0, NULL);
|
||||
}
|
||||
|
||||
PxThreadImpl::~PxThreadImpl()
|
||||
{
|
||||
if(getThread(this)->state == ThreadImpl::Started)
|
||||
kill();
|
||||
CloseHandle(getThread(this)->thread);
|
||||
}
|
||||
|
||||
void PxThreadImpl::start(uint32_t stackSize, PxRunnable* runnable)
|
||||
{
|
||||
if(getThread(this)->state != ThreadImpl::NotStarted)
|
||||
return;
|
||||
getThread(this)->state = ThreadImpl::Started;
|
||||
|
||||
if(runnable && !getThread(this)->arg && !getThread(this)->fn)
|
||||
getThread(this)->arg = runnable;
|
||||
|
||||
getThread(this)->thread =
|
||||
CreateThread(NULL, stackSize, PxThreadStart, (LPVOID) this, CREATE_SUSPENDED, &getThread(this)->threadID);
|
||||
if(!getThread(this)->thread)
|
||||
{
|
||||
PxGetFoundation().error(PxErrorCode::eINTERNAL_ERROR, PX_FL, "FdWindowsThread::start: Failed to create thread.");
|
||||
getThread(this)->state = ThreadImpl::NotStarted;
|
||||
return;
|
||||
}
|
||||
|
||||
// set affinity, set name and resume
|
||||
if(getThread(this)->affinityMask)
|
||||
setAffinityMask(getThread(this)->affinityMask);
|
||||
|
||||
if (getThread(this)->name)
|
||||
setName(getThread(this)->name);
|
||||
|
||||
DWORD rc = ResumeThread(getThread(this)->thread);
|
||||
if(rc == DWORD(-1))
|
||||
{
|
||||
PxGetFoundation().error(PxErrorCode::eINTERNAL_ERROR, PX_FL, "FdWindowsThread::start: Failed to resume thread.");
|
||||
getThread(this)->state = ThreadImpl::NotStarted;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void PxThreadImpl::signalQuit()
|
||||
{
|
||||
InterlockedIncrement(&(getThread(this)->quitNow));
|
||||
}
|
||||
|
||||
bool PxThreadImpl::waitForQuit()
|
||||
{
|
||||
if(getThread(this)->state == ThreadImpl::NotStarted)
|
||||
return false;
|
||||
|
||||
WaitForSingleObject(getThread(this)->thread, INFINITE);
|
||||
getThread(this)->state = ThreadImpl::Stopped;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PxThreadImpl::quitIsSignalled()
|
||||
{
|
||||
return InterlockedCompareExchange(&(getThread(this)->quitNow), 0, 0) != 0;
|
||||
}
|
||||
|
||||
void PxThreadImpl::quit()
|
||||
{
|
||||
getThread(this)->state = ThreadImpl::Stopped;
|
||||
ExitThread(0);
|
||||
}
|
||||
|
||||
void PxThreadImpl::kill()
|
||||
{
|
||||
if(getThread(this)->state == ThreadImpl::Started)
|
||||
TerminateThread(getThread(this)->thread, 0);
|
||||
getThread(this)->state = ThreadImpl::Stopped;
|
||||
}
|
||||
|
||||
void PxThreadImpl::sleep(uint32_t ms)
|
||||
{
|
||||
Sleep(ms);
|
||||
}
|
||||
|
||||
void PxThreadImpl::yield()
|
||||
{
|
||||
SwitchToThread();
|
||||
}
|
||||
|
||||
void PxThreadImpl::yieldProcessor()
|
||||
{
|
||||
YieldProcessor();
|
||||
}
|
||||
|
||||
uint32_t PxThreadImpl::setAffinityMask(uint32_t mask)
|
||||
{
|
||||
if(mask)
|
||||
{
|
||||
// store affinity
|
||||
getThread(this)->affinityMask = mask;
|
||||
|
||||
// if thread already started apply immediately
|
||||
if(getThread(this)->state == ThreadImpl::Started)
|
||||
{
|
||||
uint32_t err = uint32_t(SetThreadAffinityMask(getThread(this)->thread, mask));
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void PxThreadImpl::setName(const char* name)
|
||||
{
|
||||
getThread(this)->name = name;
|
||||
|
||||
if (getThread(this)->state == ThreadImpl::Started)
|
||||
{
|
||||
THREADNAME_INFO info;
|
||||
info.dwType = 0x1000;
|
||||
info.szName = name;
|
||||
info.dwThreadID = getThread(this)->threadID;
|
||||
info.dwFlags = 0;
|
||||
|
||||
// C++ Exceptions are disabled for this project, but SEH is not (and cannot be)
|
||||
// http://stackoverflow.com/questions/943087/what-exactly-will-happen-if-i-disable-c-exceptions-in-a-project
|
||||
__try
|
||||
{
|
||||
RaiseException(NS_MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR*)&info);
|
||||
}
|
||||
__except (EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
// this runs if not attached to a debugger (thus not really naming the thread)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PxThreadImpl::setPriority(PxThreadPriority::Enum prio)
|
||||
{
|
||||
BOOL rc = false;
|
||||
switch(prio)
|
||||
{
|
||||
case PxThreadPriority::eHIGH:
|
||||
rc = SetThreadPriority(getThread(this)->thread, THREAD_PRIORITY_HIGHEST);
|
||||
break;
|
||||
case PxThreadPriority::eABOVE_NORMAL:
|
||||
rc = SetThreadPriority(getThread(this)->thread, THREAD_PRIORITY_ABOVE_NORMAL);
|
||||
break;
|
||||
case PxThreadPriority::eNORMAL:
|
||||
rc = SetThreadPriority(getThread(this)->thread, THREAD_PRIORITY_NORMAL);
|
||||
break;
|
||||
case PxThreadPriority::eBELOW_NORMAL:
|
||||
rc = SetThreadPriority(getThread(this)->thread, THREAD_PRIORITY_BELOW_NORMAL);
|
||||
break;
|
||||
case PxThreadPriority::eLOW:
|
||||
rc = SetThreadPriority(getThread(this)->thread, THREAD_PRIORITY_LOWEST);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if(!rc)
|
||||
{
|
||||
PxGetFoundation().error(PxErrorCode::eINTERNAL_ERROR, PX_FL, "FdWindowsThread::setPriority: Failed to set thread priority.");
|
||||
}
|
||||
}
|
||||
|
||||
PxThreadPriority::Enum PxThreadImpl::getPriority(Id threadId)
|
||||
{
|
||||
PxThreadPriority::Enum retval = PxThreadPriority::eLOW;
|
||||
int priority = GetThreadPriority((HANDLE)threadId);
|
||||
PX_COMPILE_TIME_ASSERT(THREAD_PRIORITY_HIGHEST > THREAD_PRIORITY_ABOVE_NORMAL);
|
||||
if(priority >= THREAD_PRIORITY_HIGHEST)
|
||||
retval = PxThreadPriority::eHIGH;
|
||||
else if(priority >= THREAD_PRIORITY_ABOVE_NORMAL)
|
||||
retval = PxThreadPriority::eABOVE_NORMAL;
|
||||
else if(priority >= THREAD_PRIORITY_NORMAL)
|
||||
retval = PxThreadPriority::eNORMAL;
|
||||
else if(priority >= THREAD_PRIORITY_BELOW_NORMAL)
|
||||
retval = PxThreadPriority::eBELOW_NORMAL;
|
||||
return retval;
|
||||
}
|
||||
|
||||
PxU32 PxTlsAlloc()
|
||||
{
|
||||
DWORD rv = ::TlsAlloc();
|
||||
PX_ASSERT(rv != TLS_OUT_OF_INDEXES);
|
||||
return (PxU32)rv;
|
||||
}
|
||||
|
||||
void PxTlsFree(PxU32 index)
|
||||
{
|
||||
::TlsFree(index);
|
||||
}
|
||||
|
||||
void* PxTlsGet(PxU32 index)
|
||||
{
|
||||
return ::TlsGetValue(index);
|
||||
}
|
||||
|
||||
size_t PxTlsGetValue(PxU32 index)
|
||||
{
|
||||
return size_t(::TlsGetValue(index));
|
||||
}
|
||||
|
||||
PxU32 PxTlsSet(PxU32 index, void* value)
|
||||
{
|
||||
return PxU32(::TlsSetValue(index, value));
|
||||
}
|
||||
|
||||
PxU32 PxTlsSetValue(PxU32 index, size_t value)
|
||||
{
|
||||
return PxU32(::TlsSetValue(index, reinterpret_cast<void*>(value)));
|
||||
}
|
||||
|
||||
PxU32 PxThreadImpl::getDefaultStackSize()
|
||||
{
|
||||
return 1048576;
|
||||
};
|
||||
|
||||
} // namespace physx
|
||||
92
engine/third_party/physx/source/foundation/windows/FdWindowsTime.cpp
vendored
Normal file
92
engine/third_party/physx/source/foundation/windows/FdWindowsTime.cpp
vendored
Normal file
@@ -0,0 +1,92 @@
|
||||
// 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-2025 NVIDIA Corporation. All rights reserved.
|
||||
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
|
||||
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
|
||||
|
||||
#include "foundation/PxTime.h"
|
||||
#include "foundation/windows/PxWindowsInclude.h"
|
||||
|
||||
using namespace physx;
|
||||
|
||||
static int64_t getTimeTicks()
|
||||
{
|
||||
LARGE_INTEGER a;
|
||||
QueryPerformanceCounter(&a);
|
||||
return a.QuadPart;
|
||||
}
|
||||
|
||||
static double getTickDuration()
|
||||
{
|
||||
LARGE_INTEGER a;
|
||||
QueryPerformanceFrequency(&a);
|
||||
return 1.0f / double(a.QuadPart);
|
||||
}
|
||||
|
||||
static double sTickDuration = getTickDuration();
|
||||
|
||||
static const PxCounterFrequencyToTensOfNanos gCounterFreq = PxTime::getCounterFrequency();
|
||||
|
||||
const PxCounterFrequencyToTensOfNanos& PxTime::getBootCounterFrequency()
|
||||
{
|
||||
return gCounterFreq;
|
||||
}
|
||||
|
||||
PxCounterFrequencyToTensOfNanos PxTime::getCounterFrequency()
|
||||
{
|
||||
LARGE_INTEGER freq;
|
||||
QueryPerformanceFrequency(&freq);
|
||||
return PxCounterFrequencyToTensOfNanos(PxTime::sNumTensOfNanoSecondsInASecond, (uint64_t)freq.QuadPart);
|
||||
}
|
||||
|
||||
uint64_t PxTime::getCurrentCounterValue()
|
||||
{
|
||||
LARGE_INTEGER ticks;
|
||||
QueryPerformanceCounter(&ticks);
|
||||
return (uint64_t)ticks.QuadPart;
|
||||
}
|
||||
|
||||
PxTime::PxTime() : mTickCount(0)
|
||||
{
|
||||
getElapsedSeconds();
|
||||
}
|
||||
|
||||
PxTime::Second PxTime::getElapsedSeconds()
|
||||
{
|
||||
int64_t lastTickCount = mTickCount;
|
||||
mTickCount = getTimeTicks();
|
||||
return (mTickCount - lastTickCount) * sTickDuration;
|
||||
}
|
||||
|
||||
PxTime::Second PxTime::peekElapsedSeconds()
|
||||
{
|
||||
return (getTimeTicks() - mTickCount) * sTickDuration;
|
||||
}
|
||||
|
||||
PxTime::Second PxTime::getLastTime() const
|
||||
{
|
||||
return mTickCount * sTickDuration;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user