Files
XCEngine/engine/third_party/physx/source/pvd/src/PxPvdDataStream.cpp

863 lines
27 KiB
C++
Raw Normal View History

// 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.
#include "foundation/PxAssert.h"
#include "PxPvdCommStreamEventSink.h"
#include "PxPvdDataStreamHelpers.h"
#include "PxPvdObjectModelInternalTypes.h"
#include "PxPvdImpl.h"
using namespace physx;
using namespace physx::pvdsdk;
namespace
{
struct ScopedMetaData
{
PvdOMMetaDataProvider& mProvider;
PvdObjectModelMetaData& mMeta;
ScopedMetaData(PvdOMMetaDataProvider& provider) : mProvider(provider), mMeta(provider.lock())
{
}
~ScopedMetaData()
{
mProvider.unlock();
}
PvdObjectModelMetaData* operator->()
{
return &mMeta;
}
private:
ScopedMetaData& operator=(const ScopedMetaData&);
};
struct PropertyDefinitionHelper : public PvdPropertyDefinitionHelper
{
PvdDataStream* mStream;
PvdOMMetaDataProvider& mProvider;
PxArray<char> mNameBuffer;
PxArray<uint32_t> mNameStack;
PxArray<NamedValue> mNamedValues;
PxArray<PropertyMessageArg> mPropertyMessageArgs;
PropertyDefinitionHelper(PvdOMMetaDataProvider& provider)
: mStream(NULL)
, mProvider(provider)
, mNameBuffer("PropertyDefinitionHelper::mNameBuffer")
, mNameStack("PropertyDefinitionHelper::mNameStack")
, mNamedValues("PropertyDefinitionHelper::mNamedValues")
, mPropertyMessageArgs("PropertyDefinitionHelper::mPropertyMessageArgs")
{
}
void setStream(PvdDataStream* stream)
{
mStream = stream;
}
inline void appendStrToBuffer(const char* str)
{
if(str == NULL)
return;
size_t strLen = strlen(str);
size_t endBufOffset = mNameBuffer.size();
size_t resizeLen = endBufOffset;
// account for null
if(mNameBuffer.empty())
resizeLen += 1;
else
endBufOffset -= 1;
mNameBuffer.resize(static_cast<uint32_t>(resizeLen + strLen));
char* endPtr = mNameBuffer.begin() + endBufOffset;
PxMemCopy(endPtr, str, static_cast<uint32_t>(strLen));
}
virtual void pushName(const char* nm, const char* appender = ".")
{
size_t nameBufLen = mNameBuffer.size();
mNameStack.pushBack(static_cast<uint32_t>(nameBufLen));
if(mNameBuffer.empty() == false)
appendStrToBuffer(appender);
appendStrToBuffer(nm);
mNameBuffer.back() = 0;
}
virtual void pushBracketedName(const char* inName, const char* leftBracket = "[", const char* rightBracket = "]")
{
size_t nameBufLen = mNameBuffer.size();
mNameStack.pushBack(static_cast<uint32_t>(nameBufLen));
appendStrToBuffer(leftBracket);
appendStrToBuffer(inName);
appendStrToBuffer(rightBracket);
mNameBuffer.back() = 0;
}
virtual void popName()
{
if(mNameStack.empty())
return;
mNameBuffer.resize(static_cast<uint32_t>(mNameStack.back()));
mNameStack.popBack();
if(mNameBuffer.empty() == false)
mNameBuffer.back() = 0;
}
virtual const char* getTopName()
{
if(mNameBuffer.size())
return mNameBuffer.begin();
return "";
}
virtual void clearNameStack()
{
mNameBuffer.clear();
mNameStack.clear();
}
virtual void addNamedValue(const char* name, uint32_t value)
{
mNamedValues.pushBack(NamedValue(name, value));
}
virtual void clearNamedValues()
{
mNamedValues.clear();
}
virtual DataRef<NamedValue> getNamedValues()
{
return DataRef<NamedValue>(mNamedValues.begin(), mNamedValues.size());
}
virtual void createProperty(const NamespacedName& clsName, const char* inSemantic, const NamespacedName& dtypeName,
PropertyType::Enum propType)
{
mStream->createProperty(clsName, getTopName(), inSemantic, dtypeName, propType, getNamedValues());
clearNamedValues();
}
const char* registerStr(const char* str)
{
ScopedMetaData scopedProvider(mProvider);
return scopedProvider->getStringTable().registerStr(str);
}
virtual void addPropertyMessageArg(const NamespacedName& inDatatype, uint32_t inOffset, uint32_t inSize)
{
mPropertyMessageArgs.pushBack(PropertyMessageArg(registerStr(getTopName()), inDatatype, inOffset, inSize));
}
virtual void addPropertyMessage(const NamespacedName& clsName, const NamespacedName& msgName,
uint32_t inStructSizeInBytes)
{
if(mPropertyMessageArgs.empty())
{
PX_ASSERT(false);
return;
}
mStream->createPropertyMessage(
clsName, msgName, DataRef<PropertyMessageArg>(mPropertyMessageArgs.begin(), mPropertyMessageArgs.size()),
inStructSizeInBytes);
}
virtual void clearPropertyMessageArgs()
{
mPropertyMessageArgs.clear();
}
private:
PropertyDefinitionHelper& operator=(const PropertyDefinitionHelper&);
};
class PvdMemPool
{
// Link List
PxArray<uint8_t*> mMemBuffer;
uint32_t mLength;
uint32_t mBufIndex;
// 4k for one page
static const int BUFFER_LENGTH = 4096;
PX_NOCOPY(PvdMemPool)
public:
PvdMemPool(const char* bufDataName) : mMemBuffer(bufDataName), mLength(0), mBufIndex(0)
{
grow();
}
~PvdMemPool()
{
for(uint32_t i = 0; i < mMemBuffer.size(); i++)
{
PX_FREE(mMemBuffer[i]);
}
}
void grow()
{
if(mBufIndex + 1 < mMemBuffer.size())
{
mBufIndex++;
}
else
{
uint8_t* Buf = reinterpret_cast<uint8_t*>(PX_ALLOC(BUFFER_LENGTH, "PvdMemPool::mMemBuffer.buf"));
mMemBuffer.pushBack(Buf);
mBufIndex = mMemBuffer.size() - 1;
}
mLength = 0;
}
void* allocate(uint32_t length)
{
if(length > uint32_t(BUFFER_LENGTH))
return NULL;
if(length + mLength > uint32_t(BUFFER_LENGTH))
grow();
void* mem = reinterpret_cast<void*>(&mMemBuffer[mBufIndex][mLength]);
mLength += length;
return mem;
}
void clear()
{
mLength = 0;
mBufIndex = 0;
}
};
struct PvdOutStream : public PvdDataStream, public PxUserAllocated
{
PxHashMap<String, uint32_t> mStringHashMap;
PvdOMMetaDataProvider& mMetaDataProvider;
PxArray<uint8_t> mTempBuffer;
PropertyDefinitionHelper mPropertyDefinitionHelper;
DataStreamState::Enum mStreamState;
ClassDescription mSPVClass;
PropertyMessageDescription mMessageDesc;
// Set property value and SetPropertyMessage calls require
// us to write the data out to a separate buffer
// when strings are involved.
ForwardingMemoryBuffer mSPVBuffer;
uint32_t mEventCount;
uint32_t mPropertyMessageSize;
bool mConnected;
uint64_t mStreamId;
PxArray<PvdCommand*> mPvdCommandArray;
PvdMemPool mPvdCommandPool;
PxPvdTransport& mTransport;
PvdOutStream(PxPvdTransport& transport, PvdOMMetaDataProvider& provider, uint64_t streamId)
: mStringHashMap("PvdOutStream::mStringHashMap")
, mMetaDataProvider(provider)
, mTempBuffer("PvdOutStream::mTempBuffer")
, mPropertyDefinitionHelper(mMetaDataProvider)
, mStreamState(DataStreamState::Open)
, mSPVBuffer("PvdCommStreamBufferedEventSink::mSPVBuffer")
, mEventCount(0)
, mPropertyMessageSize(0)
, mConnected(true)
, mStreamId(streamId)
, mPvdCommandArray("PvdCommStreamBufferedEventSink::mPvdCommandArray")
, mPvdCommandPool("PvdCommStreamBufferedEventSink::mPvdCommandPool")
, mTransport(transport)
{
mPropertyDefinitionHelper.setStream(this);
}
virtual ~PvdOutStream()
{
}
virtual void release()
{
PVD_DELETE(this);
}
StringHandle toStream(String nm)
{
if(nm == NULL || *nm == 0)
return 0;
const PxHashMap<String, uint32_t>::Entry* entry(mStringHashMap.find(nm));
if(entry)
return entry->second;
ScopedMetaData meta(mMetaDataProvider);
StringHandle hdl = meta->getStringTable().strToHandle(nm);
nm = meta->getStringTable().handleToStr(hdl);
handlePvdEvent(StringHandleEvent(nm, hdl));
mStringHashMap.insert(nm, hdl);
return hdl;
}
StreamNamespacedName toStream(const NamespacedName& nm)
{
return StreamNamespacedName(toStream(nm.mNamespace), toStream(nm.mName));
}
bool isClassExist(const NamespacedName& nm)
{
ScopedMetaData meta(mMetaDataProvider);
return meta->findClass(nm).hasValue();
}
bool createMetaClass(const NamespacedName& nm)
{
ScopedMetaData meta(mMetaDataProvider);
meta->getOrCreateClass(nm);
return true;
}
bool deriveMetaClass(const NamespacedName& parent, const NamespacedName& child)
{
ScopedMetaData meta(mMetaDataProvider);
return meta->deriveClass(parent, child);
}
// You will notice that some functions are #pragma'd out throughout this file.
// This is because they are only called from asserts which means they aren't
// called in release. This causes warnings when building using snc which break
// the build.
#if PX_DEBUG
bool propertyExists(const NamespacedName& nm, String pname)
{
ScopedMetaData meta(mMetaDataProvider);
return meta->findProperty(nm, pname).hasValue();
}
#endif
PvdError boolToError(bool val)
{
if(val)
return PvdErrorType::Success;
return PvdErrorType::NetworkError;
}
// PvdMetaDataStream
virtual PvdError createClass(const NamespacedName& nm)
{
PX_ASSERT(mStreamState == DataStreamState::Open);
#if PX_DEBUG
PX_ASSERT(isClassExist(nm) == false);
#endif
createMetaClass(nm);
return boolToError(handlePvdEvent(CreateClass(toStream(nm))));
}
virtual PvdError deriveClass(const NamespacedName& parent, const NamespacedName& child)
{
PX_ASSERT(mStreamState == DataStreamState::Open);
#if PX_DEBUG
PX_ASSERT(isClassExist(parent));
PX_ASSERT(isClassExist(child));
#endif
deriveMetaClass(parent, child);
return boolToError(handlePvdEvent(DeriveClass(toStream(parent), toStream(child))));
}
template <typename TDataType>
TDataType* allocTemp(uint32_t numItems)
{
uint32_t desiredBytes = numItems * sizeof(TDataType);
if(desiredBytes > mTempBuffer.size())
mTempBuffer.resize(desiredBytes);
TDataType* retval = reinterpret_cast<TDataType*>(mTempBuffer.begin());
if(numItems)
{
PVD_FOREACH(idx, numItems) new (retval + idx) TDataType();
}
return retval;
}
#if PX_DEBUG
// Property datatypes need to be uniform.
// At this point, the data stream cannot handle properties that
// A struct with a float member and a char member would work.
// A struct with a float member and a long member would work (more efficiently).
bool isValidPropertyDatatype(const NamespacedName& dtypeName)
{
ScopedMetaData meta(mMetaDataProvider);
ClassDescription clsDesc(meta->findClass(dtypeName));
return clsDesc.mRequiresDestruction == false;
}
#endif
NamespacedName createMetaProperty(const NamespacedName& clsName, String name, String semantic,
const NamespacedName& dtypeName, PropertyType::Enum propertyType)
{
ScopedMetaData meta(mMetaDataProvider);
int32_t dtypeType = meta->findClass(dtypeName)->mClassId;
NamespacedName typeName = dtypeName;
if(dtypeType == getPvdTypeForType<String>())
{
dtypeType = getPvdTypeForType<StringHandle>();
typeName = getPvdNamespacedNameForType<StringHandle>();
}
Option<PropertyDescription> propOpt =
meta->createProperty(meta->findClass(clsName)->mClassId, name, semantic, dtypeType, propertyType);
PX_ASSERT(propOpt.hasValue());
PX_UNUSED(propOpt);
return typeName;
}
virtual PvdError createProperty(const NamespacedName& clsName, String name, String semantic,
const NamespacedName& incomingDtypeName, PropertyType::Enum propertyType,
DataRef<NamedValue> values)
{
PX_ASSERT(mStreamState == DataStreamState::Open);
#if PX_DEBUG
PX_ASSERT(isClassExist(clsName));
PX_ASSERT(propertyExists(clsName, name) == false);
#endif
NamespacedName dtypeName(incomingDtypeName);
if(safeStrEq(dtypeName.mName, "VoidPtr"))
dtypeName.mName = "ObjectRef";
#if PX_DEBUG
PX_ASSERT(isClassExist(dtypeName));
PX_ASSERT(isValidPropertyDatatype(dtypeName));
#endif
NamespacedName typeName = createMetaProperty(clsName, name, semantic, dtypeName, propertyType);
// Can't have arrays of strings or arrays of string handles due to the difficulty
// of quickly dealing with them on the network receiving side.
if(propertyType == PropertyType::Array && safeStrEq(typeName.mName, "StringHandle"))
{
PX_ASSERT(false);
return PvdErrorType::ArgumentError;
}
uint32_t numItems = values.size();
NameHandleValue* streamValues = allocTemp<NameHandleValue>(numItems);
PVD_FOREACH(idx, numItems)
streamValues[idx] = NameHandleValue(toStream(values[idx].mName), values[idx].mValue);
CreateProperty evt(toStream(clsName), toStream(name), toStream(semantic), toStream(typeName), propertyType,
DataRef<NameHandleValue>(streamValues, numItems));
return boolToError(handlePvdEvent(evt));
}
bool createMetaPropertyMessage(const NamespacedName& cls, const NamespacedName& msgName,
DataRef<PropertyMessageArg> entries, uint32_t messageSizeInBytes)
{
ScopedMetaData meta(mMetaDataProvider);
return meta->createPropertyMessage(cls, msgName, entries, messageSizeInBytes).hasValue();
}
#if PX_DEBUG
bool messageExists(const NamespacedName& msgName)
{
ScopedMetaData meta(mMetaDataProvider);
return meta->findPropertyMessage(msgName).hasValue();
}
#endif
virtual PvdError createPropertyMessage(const NamespacedName& cls, const NamespacedName& msgName,
DataRef<PropertyMessageArg> entries, uint32_t messageSizeInBytes)
{
PX_ASSERT(mStreamState == DataStreamState::Open);
#if PX_DEBUG
PX_ASSERT(isClassExist(cls));
PX_ASSERT(messageExists(msgName) == false);
#endif
createMetaPropertyMessage(cls, msgName, entries, messageSizeInBytes);
uint32_t numItems = entries.size();
StreamPropMessageArg* streamValues = allocTemp<StreamPropMessageArg>(numItems);
PVD_FOREACH(idx, numItems)
streamValues[idx] =
StreamPropMessageArg(toStream(entries[idx].mPropertyName), toStream(entries[idx].mDatatypeName),
entries[idx].mMessageOffset, entries[idx].mByteSize);
CreatePropertyMessage evt(toStream(cls), toStream(msgName),
DataRef<StreamPropMessageArg>(streamValues, numItems), messageSizeInBytes);
return boolToError(handlePvdEvent(evt));
}
uint64_t toStream(const void* instance)
{
return PVD_POINTER_TO_U64(instance);
}
virtual PvdError createInstance(const NamespacedName& cls, const void* instance)
{
PX_ASSERT(isInstanceValid(instance) == false);
PX_ASSERT(mStreamState == DataStreamState::Open);
bool success = mMetaDataProvider.createInstance(cls, instance);
PX_ASSERT(success);
(void)success;
return boolToError(handlePvdEvent(CreateInstance(toStream(cls), toStream(instance))));
}
virtual bool isInstanceValid(const void* instance)
{
return mMetaDataProvider.isInstanceValid(instance);
}
#if PX_DEBUG
// If the property will fit or is already completely in memory
bool checkPropertyType(const void* instance, String name, const NamespacedName& incomingType)
{
int32_t instType = mMetaDataProvider.getInstanceClassType(instance);
ScopedMetaData meta(mMetaDataProvider);
Option<PropertyDescription> prop = meta->findProperty(instType, name);
if(prop.hasValue() == false)
return false;
int32_t propType = prop->mDatatype;
int32_t incomingTypeId = meta->findClass(incomingType)->mClassId;
if(incomingTypeId != getPvdTypeForType<VoidPtr>())
{
MarshalQueryResult result = meta->checkMarshalling(incomingTypeId, propType);
bool possible = result.needsMarshalling == false || result.canMarshal;
return possible;
}
else
{
if(propType != getPvdTypeForType<ObjectRef>())
return false;
}
return true;
}
#endif
DataRef<const uint8_t> bufferPropertyValue(ClassDescriptionSizeInfo info, DataRef<const uint8_t> data)
{
uint32_t realSize = info.mByteSize;
uint32_t numItems = data.size() / realSize;
if(info.mPtrOffsets.size() != 0)
{
mSPVBuffer.clear();
PVD_FOREACH(item, numItems)
{
const uint8_t* itemPtr = data.begin() + item * realSize;
mSPVBuffer.write(itemPtr, realSize);
PVD_FOREACH(stringIdx, info.mPtrOffsets.size())
{
PtrOffset offset(info.mPtrOffsets[stringIdx]);
if(offset.mOffsetType == PtrOffsetType::VoidPtrOffset)
continue;
const char* strPtr;
physx::intrinsics::memCopy(&strPtr, itemPtr + offset.mOffset, sizeof(char*));
strPtr = nonNull(strPtr);
uint32_t len = safeStrLen(strPtr) + 1;
mSPVBuffer.write(strPtr, len);
}
}
data = DataRef<const uint8_t>(mSPVBuffer.begin(), mSPVBuffer.size());
}
return data;
}
virtual PvdError setPropertyValue(const void* instance, String name, DataRef<const uint8_t> data,
const NamespacedName& incomingTypeName)
{
PX_ASSERT(isInstanceValid(instance));
#if PX_DEBUG
PX_ASSERT(isClassExist(incomingTypeName));
#endif
PX_ASSERT(mStreamState == DataStreamState::Open);
ClassDescription clsDesc;
{
ScopedMetaData meta(mMetaDataProvider);
clsDesc = meta->findClass(incomingTypeName);
}
uint32_t realSize = clsDesc.getNativeSize();
uint32_t numItems = data.size() / realSize;
data = bufferPropertyValue(clsDesc.getNativeSizeInfo(), data);
SetPropertyValue evt(toStream(instance), toStream(name), data, toStream(incomingTypeName), numItems);
return boolToError(handlePvdEvent(evt));
}
// Else if the property is very large (contact reports) you can send it in chunks.
virtual PvdError beginSetPropertyValue(const void* instance, String name, const NamespacedName& incomingTypeName)
{
PX_ASSERT(isInstanceValid(instance));
#if PX_DEBUG
PX_ASSERT(isClassExist(incomingTypeName));
PX_ASSERT(checkPropertyType(instance, name, incomingTypeName));
#endif
PX_ASSERT(mStreamState == DataStreamState::Open);
mStreamState = DataStreamState::SetPropertyValue;
{
ScopedMetaData meta(mMetaDataProvider);
mSPVClass = meta->findClass(incomingTypeName);
}
BeginSetPropertyValue evt(toStream(instance), toStream(name), toStream(incomingTypeName));
return boolToError(handlePvdEvent(evt));
}
virtual PvdError appendPropertyValueData(DataRef<const uint8_t> data)
{
uint32_t realSize = mSPVClass.getNativeSize();
uint32_t numItems = data.size() / realSize;
data = bufferPropertyValue(mSPVClass.getNativeSizeInfo(), data);
PX_ASSERT(mStreamState == DataStreamState::SetPropertyValue);
return boolToError(handlePvdEvent(AppendPropertyValueData(data, numItems)));
}
virtual PvdError endSetPropertyValue()
{
PX_ASSERT(mStreamState == DataStreamState::SetPropertyValue);
mStreamState = DataStreamState::Open;
return boolToError(handlePvdEvent(EndSetPropertyValue()));
}
#if PX_DEBUG
bool checkPropertyMessage(const void* instance, const NamespacedName& msgName)
{
int32_t clsId = mMetaDataProvider.getInstanceClassType(instance);
ScopedMetaData meta(mMetaDataProvider);
PropertyMessageDescription desc(meta->findPropertyMessage(msgName));
bool retval = meta->isDerivedFrom(clsId, desc.mClassId);
return retval;
}
#endif
DataRef<const uint8_t> bufferPropertyMessage(const PropertyMessageDescription& desc, DataRef<const uint8_t> data)
{
if(desc.mStringOffsets.size())
{
mSPVBuffer.clear();
mSPVBuffer.write(data.begin(), data.size());
PVD_FOREACH(idx, desc.mStringOffsets.size())
{
const char* strPtr;
physx::intrinsics::memCopy(&strPtr, data.begin() + desc.mStringOffsets[idx], sizeof(char*));
strPtr = nonNull(strPtr);
uint32_t len = safeStrLen(strPtr) + 1;
mSPVBuffer.write(strPtr, len);
}
data = DataRef<const uint8_t>(mSPVBuffer.begin(), mSPVBuffer.end());
}
return data;
}
virtual PvdError setPropertyMessage(const void* instance, const NamespacedName& msgName, DataRef<const uint8_t> data)
{
ScopedMetaData meta(mMetaDataProvider);
PX_ASSERT(isInstanceValid(instance));
#if PX_DEBUG
PX_ASSERT(messageExists(msgName));
PX_ASSERT(checkPropertyMessage(instance, msgName));
#endif
PropertyMessageDescription desc(meta->findPropertyMessage(msgName));
if(data.size() < desc.mMessageByteSize)
{
PX_ASSERT(false);
return PvdErrorType::ArgumentError;
}
data = bufferPropertyMessage(desc, data);
PX_ASSERT(mStreamState == DataStreamState::Open);
return boolToError(handlePvdEvent(SetPropertyMessage(toStream(instance), toStream(msgName), data)));
}
#if PX_DEBUG
bool checkBeginPropertyMessageGroup(const NamespacedName& msgName)
{
ScopedMetaData meta(mMetaDataProvider);
PropertyMessageDescription desc(meta->findPropertyMessage(msgName));
return desc.mStringOffsets.size() == 0;
}
#endif
// If you need to send of lot of identical messages, this avoids a hashtable lookup per message.
virtual PvdError beginPropertyMessageGroup(const NamespacedName& msgName)
{
#if PX_DEBUG
PX_ASSERT(messageExists(msgName));
PX_ASSERT(checkBeginPropertyMessageGroup(msgName));
#endif
PX_ASSERT(mStreamState == DataStreamState::Open);
mStreamState = DataStreamState::PropertyMessageGroup;
ScopedMetaData meta(mMetaDataProvider);
mMessageDesc = meta->findPropertyMessage(msgName);
return boolToError(handlePvdEvent(BeginPropertyMessageGroup(toStream(msgName))));
}
virtual PvdError sendPropertyMessageFromGroup(const void* instance, DataRef<const uint8_t> data)
{
PX_ASSERT(mStreamState == DataStreamState::PropertyMessageGroup);
PX_ASSERT(isInstanceValid(instance));
#if PX_DEBUG
PX_ASSERT(checkPropertyMessage(instance, mMessageDesc.mMessageName));
#endif
if(mMessageDesc.mMessageByteSize != data.size())
{
PX_ASSERT(false);
return PvdErrorType::ArgumentError;
}
if(data.size() < mMessageDesc.mMessageByteSize)
return PvdErrorType::ArgumentError;
data = bufferPropertyMessage(mMessageDesc, data);
return boolToError(handlePvdEvent(SendPropertyMessageFromGroup(toStream(instance), data)));
}
virtual PvdError endPropertyMessageGroup()
{
PX_ASSERT(mStreamState == DataStreamState::PropertyMessageGroup);
mStreamState = DataStreamState::Open;
return boolToError(handlePvdEvent(EndPropertyMessageGroup()));
}
virtual PvdError pushBackObjectRef(const void* instance, String propName, const void* data)
{
PX_ASSERT(isInstanceValid(instance));
PX_ASSERT(isInstanceValid(data));
PX_ASSERT(mStreamState == DataStreamState::Open);
return boolToError(handlePvdEvent(PushBackObjectRef(toStream(instance), toStream(propName), toStream(data))));
}
virtual PvdError removeObjectRef(const void* instance, String propName, const void* data)
{
PX_ASSERT(isInstanceValid(instance));
PX_ASSERT(isInstanceValid(data));
PX_ASSERT(mStreamState == DataStreamState::Open);
return boolToError(handlePvdEvent(RemoveObjectRef(toStream(instance), toStream(propName), toStream(data))));
}
// Instance elimination.
virtual PvdError destroyInstance(const void* instance)
{
PX_ASSERT(isInstanceValid(instance));
PX_ASSERT(mStreamState == DataStreamState::Open);
mMetaDataProvider.destroyInstance(instance);
return boolToError(handlePvdEvent(DestroyInstance(toStream(instance))));
}
// Profiling hooks
virtual PvdError beginSection(const void* instance, String name)
{
PX_ASSERT(mStreamState == DataStreamState::Open);
return boolToError(handlePvdEvent(
BeginSection(toStream(instance), toStream(name), PxTime::getCurrentCounterValue())));
}
virtual PvdError endSection(const void* instance, String name)
{
PX_ASSERT(mStreamState == DataStreamState::Open);
return boolToError(handlePvdEvent(
EndSection(toStream(instance), toStream(name), PxTime::getCurrentCounterValue())));
}
virtual PvdError originShift(const void* scene, PxVec3 shift)
{
PX_ASSERT(mStreamState == DataStreamState::Open);
return boolToError(handlePvdEvent(OriginShift(toStream(scene), shift)));
}
virtual void addProfileZone(void* zone, const char* name)
{
handlePvdEvent(AddProfileZone(toStream(zone), name));
}
virtual void addProfileZoneEvent(void* zone, const char* name, uint16_t eventId, bool compileTimeEnabled)
{
handlePvdEvent(AddProfileZoneEvent(toStream(zone), name, eventId, compileTimeEnabled));
}
// add a variable sized event
void addEvent(const EventSerializeable& evt, PvdCommStreamEventTypes::Enum evtType)
{
MeasureStream measure;
PvdCommStreamEventSink::writeStreamEvent(evt, evtType, measure);
EventGroup evtGroup(measure.mSize, 1, mStreamId, PxTime::getCurrentCounterValue());
EventStreamifier<PxPvdTransport> streamifier(mTransport.lock());
evtGroup.serialize(streamifier);
PvdCommStreamEventSink::writeStreamEvent(evt, evtType, mTransport);
mTransport.unlock();
}
void setIsTopLevelUIElement(const void* instance, bool topLevel)
{
addEvent(SetIsTopLevel(static_cast<uint64_t>(reinterpret_cast<size_t>(instance)), topLevel),
getCommStreamEventType<SetIsTopLevel>());
}
void sendErrorMessage(uint32_t code, const char* message, const char* file, uint32_t line)
{
addEvent(ErrorMessage(code, message, file, line), getCommStreamEventType<ErrorMessage>());
}
void updateCamera(const char* name, const PxVec3& origin, const PxVec3& up, const PxVec3& target)
{
addEvent(SetCamera(name, origin, up, target), getCommStreamEventType<SetCamera>());
}
template <typename TEventType>
bool handlePvdEvent(const TEventType& evt)
{
addEvent(evt, getCommStreamEventType<TEventType>());
return mConnected;
}
virtual PvdPropertyDefinitionHelper& getPropertyDefinitionHelper()
{
mPropertyDefinitionHelper.clearBufferedData();
return mPropertyDefinitionHelper;
}
virtual bool isConnected()
{
return mConnected;
}
virtual void* allocateMemForCmd(uint32_t length)
{
return mPvdCommandPool.allocate(length);
}
virtual void pushPvdCommand(PvdCommand& cmd)
{
mPvdCommandArray.pushBack(&cmd);
}
virtual void flushPvdCommand()
{
uint32_t cmdQueueSize = mPvdCommandArray.size();
for(uint32_t i = 0; i < cmdQueueSize; i++)
{
if(mPvdCommandArray[i])
{
// if(mPvdCommandArray[i]->canRun(*this))
mPvdCommandArray[i]->run(*this);
mPvdCommandArray[i]->~PvdCommand();
}
}
mPvdCommandArray.clear();
mPvdCommandPool.clear();
}
PX_NOCOPY(PvdOutStream)
};
}
PvdDataStream* PvdDataStream::create(PxPvd* pvd)
{
if(pvd == NULL)
{
PxGetFoundation().error(PxErrorCode::eINVALID_PARAMETER, PX_FL, "PvdDataStream::create - pvd must be non-NULL!");
return NULL;
}
PvdImpl* pvdImpl = static_cast<PvdImpl*>(pvd);
return PVD_NEW(PvdOutStream)(*pvdImpl->getTransport(), pvdImpl->getMetaDataProvider(), pvdImpl->getNextStreamId());
}