vphysics_jolt/vphysics_wrapper/vphysics_wrapper.cpp

209 lines
5.7 KiB
C++

//=================================================================================================
//
// The base physics DLL interface
//
// This is a thin CPU-agnostic wrapper for the actual Volt DLLs which are named
// vphysics_jolt_sse2.dll, vphysics_jolt_sse42.dll and vphysics_jolt_avx2.dll
//
//=================================================================================================
#include "tier0/basetypes.h"
#include "tier1/interface.h"
#include "vphysics_interface.h"
#ifdef _WIN32
#include <intrin.h>
#else
#include <cpuid.h>
#endif
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//-------------------------------------------------------------------------------------------------
class PhysicsWrapper final : public CBaseAppSystem<IPhysics>
{
public:
bool Connect( CreateInterfaceFn factory ) override;
void Disconnect() override;
InitReturnVal_t Init() override;
void Shutdown() override;
void *QueryInterface( const char *pInterfaceName ) override;
IPhysicsEnvironment *CreateEnvironment() override;
void DestroyEnvironment( IPhysicsEnvironment *pEnvironment ) override;
IPhysicsEnvironment *GetActiveEnvironmentByIndex( int index ) override;
IPhysicsObjectPairHash *CreateObjectPairHash() override;
void DestroyObjectPairHash( IPhysicsObjectPairHash *pHash ) override;
IPhysicsCollisionSet *FindOrCreateCollisionSet( unsigned int id, int maxElementCount ) override;
IPhysicsCollisionSet *FindCollisionSet( unsigned int id ) override;
void DestroyAllCollisionSets() override;
public:
static PhysicsWrapper &GetInstance() { return s_PhysicsInterface; }
private:
bool InitWrapper();
CSysModule *m_pActualPhysicsModule;
IPhysics *m_pActualPhysicsInterface;
static PhysicsWrapper s_PhysicsInterface;
};
PhysicsWrapper PhysicsWrapper::s_PhysicsInterface;
EXPOSE_SINGLE_INTERFACE_GLOBALVAR( PhysicsWrapper, IPhysics, VPHYSICS_INTERFACE_VERSION, PhysicsWrapper::GetInstance() );
//-------------------------------------------------------------------------------------------------
enum CPULevel_t
{
CPU_HAS_SSE2,
CPU_HAS_SSE42,
CPU_HAS_AVX2,
};
static void GetCPUID( int *pInfo, int func, int subfunc )
{
#ifdef _WIN32
__cpuidex( pInfo, func, subfunc );
#else
__cpuid_count( func, subfunc, pInfo[0], pInfo[1], pInfo[2], pInfo[3] );
#endif
}
static CPULevel_t GetCPULevel()
{
int cpuInfo[4];
CPULevel_t cpuLevel = CPU_HAS_SSE2;
GetCPUID( cpuInfo, 0, 0 ); // Get the number of functions
const int numFuncs = cpuInfo[0];
if ( numFuncs >= 7 )
{
GetCPUID( cpuInfo, 7, 0 ); // Call function 7
bool hasAVX2 = cpuInfo[1] & ( 1 << 5 ); // 5 is the AVX2 bit
if ( hasAVX2 )
cpuLevel = CPU_HAS_AVX2;
}
else
{
GetCPUID( cpuInfo, 1, 0 ); // Call function 1
bool hasSSE42 = cpuInfo[2] & ( 1 << 20 ); // 20 is the SSE42 bit
if ( hasSSE42 )
cpuLevel = CPU_HAS_SSE42;
}
return cpuLevel;
}
static const char *GetModuleFromCPULevel( CPULevel_t level )
{
switch ( level )
{
case CPU_HAS_AVX2: return "vphysics_jolt_avx2" DLL_EXT_STRING;
case CPU_HAS_SSE42: return "vphysics_jolt_sse42" DLL_EXT_STRING;
default: return "vphysics_jolt_sse2" DLL_EXT_STRING;
}
}
// Tries to load the actual vphysics DLL
bool PhysicsWrapper::InitWrapper()
{
if ( m_pActualPhysicsInterface )
return true;
const char *pModuleName = GetModuleFromCPULevel( GetCPULevel() );
if ( !Sys_LoadInterface( pModuleName, VPHYSICS_INTERFACE_VERSION, &m_pActualPhysicsModule, (void **)&m_pActualPhysicsInterface ) )
return false;
return true;
}
bool PhysicsWrapper::Connect( CreateInterfaceFn factory )
{
if ( !InitWrapper() )
return false;
return m_pActualPhysicsInterface->Connect( factory );
}
void PhysicsWrapper::Disconnect()
{
m_pActualPhysicsInterface->Disconnect();
Sys_UnloadModule( m_pActualPhysicsModule );
}
//-------------------------------------------------------------------------------------------------
InitReturnVal_t PhysicsWrapper::Init()
{
return m_pActualPhysicsInterface->Init();
}
void PhysicsWrapper::Shutdown()
{
m_pActualPhysicsInterface->Shutdown();
}
void *PhysicsWrapper::QueryInterface( const char *pInterfaceName )
{
// This function can be called before Connect, so try and load the real DLL early
if ( !InitWrapper() )
return nullptr;
return m_pActualPhysicsInterface->QueryInterface( pInterfaceName );
}
//-------------------------------------------------------------------------------------------------
IPhysicsEnvironment *PhysicsWrapper::CreateEnvironment()
{
return m_pActualPhysicsInterface->CreateEnvironment();
}
void PhysicsWrapper::DestroyEnvironment( IPhysicsEnvironment *pEnvironment )
{
m_pActualPhysicsInterface->DestroyEnvironment( pEnvironment );
}
IPhysicsEnvironment *PhysicsWrapper::GetActiveEnvironmentByIndex( int index )
{
return m_pActualPhysicsInterface->GetActiveEnvironmentByIndex( index );
}
//-------------------------------------------------------------------------------------------------
IPhysicsObjectPairHash *PhysicsWrapper::CreateObjectPairHash()
{
return m_pActualPhysicsInterface->CreateObjectPairHash();
}
void PhysicsWrapper::DestroyObjectPairHash( IPhysicsObjectPairHash *pHash )
{
m_pActualPhysicsInterface->DestroyObjectPairHash( pHash );
}
//-------------------------------------------------------------------------------------------------
IPhysicsCollisionSet *PhysicsWrapper::FindOrCreateCollisionSet( unsigned int id, int maxElementCount )
{
return m_pActualPhysicsInterface->FindOrCreateCollisionSet( id, maxElementCount );
}
IPhysicsCollisionSet *PhysicsWrapper::FindCollisionSet( unsigned int id )
{
return m_pActualPhysicsInterface->FindCollisionSet( id );
}
void PhysicsWrapper::DestroyAllCollisionSets()
{
m_pActualPhysicsInterface->DestroyAllCollisionSets();
}