// This code contains NVIDIA Confidential Information and is disclosed to you // under a form of NVIDIA software license agreement provided separately to you. // // Notice // NVIDIA Corporation and its licensors retain all intellectual property and // proprietary rights in and to this software and related documentation and // any modifications thereto. Any use, reproduction, disclosure, or // distribution of this software and related documentation without an express // license agreement from NVIDIA Corporation is strictly prohibited. // // ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES // NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO // THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, // MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. // // Information and code furnished is believed to be accurate and reliable. // However, NVIDIA Corporation assumes no responsibility for the consequences of use of such // information or for any infringement of patents or other rights of third parties that may // result from its use. No license is granted by implication or otherwise under any patent // or patent rights of NVIDIA Corporation. Details are subject to change without notice. // This code supersedes and replaces all information previously supplied. // NVIDIA Corporation products are not authorized for use as critical // components in life support devices or systems without express written approval of // NVIDIA Corporation. // // Copyright (c) 2008-2020 NVIDIA Corporation. All rights reserved. #ifndef PX_SERIALIZE_BINARY_HELPER_H #define PX_SERIALIZE_BINARY_HELPER_H // WARNING: before doing any changes to this file // check comments at the head of BinSerializer.cpp #include "PxAssert.h" #include #include "nvparameterized/NvParameterized.h" #include "nvparameterized/NvParameterizedTraits.h" namespace NvParameterized { template static PX_INLINE T NvMax3(T x, T y, T z) { return physx::PxMax(x, physx::PxMax(y, z)); } #ifndef offsetof # define offsetof(StructType, field) reinterpret_cast(&((StructType *)0)->field) #endif // Alignment calculator template class GetAlignment { struct TestStruct { char _; T x; }; public: static const size_t value = offsetof(struct TestStruct, x); }; // Maps C type to NvParameterized::DataType template struct GetDataType { static const DataType value = NvParameterized::TYPE_UNDEFINED; }; // Currently we only need to distinguish PxVec2 from other 64-bit stuff // (like uint64_t, int64_t, double, pointer) in SwapBytes template<> struct GetDataType { static const DataType value = NvParameterized::TYPE_VEC2; }; //Copied from NvApexStream PX_INLINE static bool IsBigEndian() { uint32_t i = 1; return 0 == *(char *)&i; } PX_INLINE static void SwapBytes(char *data, uint32_t size, NvParameterized::DataType type) { // XDK compiler does not like switch here if( 1 == size ) { // Do nothing } else if( 2 == size ) { char one_byte; one_byte = data[0]; data[0] = data[1]; data[1] = one_byte; } else if( 4 == size ) { char one_byte; one_byte = data[0]; data[0] = data[3]; data[3] = one_byte; one_byte = data[1]; data[1] = data[2]; data[2] = one_byte; } else if( 8 == size ) { //Handling of PxVec2 agregate is different from 64-bit atomic types if( TYPE_VEC2 == type ) { //PxVec2 => swap each field separately SwapBytes(data + 0, 4, TYPE_F32); SwapBytes(data + 4, 4, TYPE_F32); } else { char one_byte; one_byte = data[0]; data[0] = data[7]; data[7] = one_byte; one_byte = data[1]; data[1] = data[6]; data[6] = one_byte; one_byte = data[2]; data[2] = data[5]; data[5] = one_byte; one_byte = data[3]; data[3] = data[4]; data[4] = one_byte; } } else { //Generic algorithm for containers of float const size_t elemSize = sizeof(float); //We assume that float sizes match on both platforms PX_ASSERT( elemSize >= GetAlignment::value ); //If alignment is non-trivial below algorithm will not work PX_ASSERT( size > elemSize ); //Just swap all PxReals for(size_t i = 0; i < size; i += elemSize) SwapBytes(data + i, elemSize, TYPE_F32); } } //Convert value to platform-independent format (network byte order) template PX_INLINE static T Canonize(T x) { if( !IsBigEndian() ) SwapBytes((char *)&x, sizeof(T), GetDataType::value); return x; } //Convert value to native format (from network byte order) template PX_INLINE static T Decanonize(T x) { return Canonize(x); } //Read platform-independent value from stream and convert it to native format template static PX_INLINE T readAndConvert(const char *&p) { T val; memcpy((char *)&val, p, sizeof(T)); val = Decanonize(val); p += sizeof(T); return val; } //Byte array used for data serialization //TODO: replace this with Array? class StringBuf { Traits *mTraits; char *mData; uint32_t mSize, mCapacity; PX_INLINE void internalAppend(const char *data, uint32_t size, bool doCopy = true) { if( 0 == size ) return; if( mCapacity < mSize + size ) reserve(physx::PxMax(mSize + size, 3 * mCapacity / 2)); if( doCopy ) memcpy(mData + mSize, data, size); else memset(mData + mSize, 0, size); //We want padding bytes filled with 0 mSize += size; } public: PX_INLINE StringBuf(Traits *traits) : mTraits(traits), mData(0), mSize(0), mCapacity(0) {} PX_INLINE StringBuf(const StringBuf &s) : mTraits(s.mTraits), mSize(s.mSize), mCapacity(s.mSize) { mData = (char *)mTraits->alloc(mSize); memcpy(mData, s.mData, mSize); } PX_INLINE ~StringBuf() { mTraits->free((void *)mData); } PX_INLINE void reserve(uint32_t newCapacity) { if( mCapacity >= newCapacity ) return; char *newData = (char *)mTraits->alloc(newCapacity); PX_ASSERT(newData); if( mData ) { memcpy(newData, mData, mSize); mTraits->free(mData); } mData = newData; mCapacity = newCapacity; } PX_INLINE char *getBuffer() { char *data = mData; mSize = mCapacity = 0; mData = 0; return data; } PX_INLINE uint32_t size() const { return mSize; } template< typename T > PX_INLINE void append(T x) { internalAppend((char *)&x, sizeof(T)); } template< typename T > PX_INLINE void append(T *x) { PX_UNUSED(x); PX_ASSERT(0 && "Unable to append pointer"); } PX_INLINE void appendBytes(const char *data, uint32_t size) { internalAppend(data, size); } PX_INLINE void skipBytes(uint32_t size) { internalAppend(0, size, false); } PX_INLINE char &operator [](uint32_t i) { PX_ASSERT( i < mSize ); return mData[i]; } PX_INLINE operator char *() { return mData; } PX_INLINE operator const char *() const { return mData; } }; //Dictionary of strings used for binary serialization class Dictionary { struct Entry { const char *s; uint32_t offset; }; physx::shdfnd::Array entries; //TODO: use hash map after DE402 is fixed public: Dictionary(Traits *traits_): entries(Traits::Allocator(traits_)) {} uint32_t put(const char *s); void setOffset(const char *s, uint32_t off); PX_INLINE void setOffset(uint32_t i, uint32_t off) { setOffset(get(i), off); } uint32_t getOffset(const char *s) const; uint32_t getOffset(uint32_t i) const { return getOffset(get(i)); } const char *get(uint32_t i) const { return entries[i].s; } PX_INLINE uint32_t size() const { return entries.size(); } void serialize(StringBuf &res) const; }; //Binary file pretty-printer (mimics xxd) void dumpBytes(const char *data, uint32_t nbytes); } #endif