// // 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-2019 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 "PxPvdImpl.h" #include "PxPvdMemClient.h" #include "PxPvdProfileZoneClient.h" #include "PxPvdProfileZone.h" #include "PsFoundation.h" #if PX_NVTX #include "nvToolsExt.h" #endif namespace { const char* gSdkName = "PhysXSDK"; } namespace physx { namespace pvdsdk { class CmEventNameProvider : public physx::profile::PxProfileNameProvider { public: physx::profile::PxProfileNames getProfileNames() const { physx::profile::PxProfileNames ret; ret.eventCount = 0; return ret; } }; CmEventNameProvider gProfileNameProvider; void initializeModelTypes(PvdDataStream& stream) { stream.createClass(); stream.createProperty( "events", PvdCommStreamEmbeddedTypes::getProfileEventStreamSemantic(), PropertyType::Array); stream.createClass(); stream.createProperty( "events", PvdCommStreamEmbeddedTypes::getMemoryEventStreamSemantic(), PropertyType::Array); stream.createClass(); stream.createProperty( "events", PvdCommStreamEmbeddedTypes::getRendererEventStreamSemantic(), PropertyType::Array); } PvdImpl* PvdImpl::sInstance = NULL; uint32_t PvdImpl::sRefCount = 0; PvdImpl::PvdImpl() : mPvdTransport(NULL) , mSharedMetaProvider(NULL) , mMemClient(NULL) , mIsConnected(false) , mIsNVTXSupportEnabled(true) , mNVTXContext(0) , mNextStreamId(1) , mProfileClient(NULL) , mProfileZone(NULL) { mProfileZoneManager = &physx::profile::PxProfileZoneManager::createProfileZoneManager(&physx::shdfnd::getAllocator()); mProfileClient = PVD_NEW(PvdProfileZoneClient)(*this); } PvdImpl::~PvdImpl() { if((mFlags & PxPvdInstrumentationFlag::ePROFILE) ) { PxSetProfilerCallback(NULL); } disconnect(); if ( mProfileZoneManager ) { mProfileZoneManager->release(); mProfileZoneManager = NULL; } PVD_DELETE(mProfileClient); mProfileClient = NULL; } bool PvdImpl::connect(PxPvdTransport& transport, PxPvdInstrumentationFlags flags) { if(mIsConnected) { physx::shdfnd::getFoundation().error(PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, "PxPvd::connect - recall connect! Should call disconnect before re-connect."); return false; } mFlags = flags; mPvdTransport = &transport; mIsConnected = mPvdTransport->connect(); if(mIsConnected) { mSharedMetaProvider = PVD_NEW(MetaDataProvider); sendTransportInitialization(); PvdDataStream* stream = PvdDataStream::create(this); initializeModelTypes(*stream); stream->release(); if(mFlags & PxPvdInstrumentationFlag::eMEMORY) { mMemClient = PVD_NEW(PvdMemClient)(*this); mPvdClients.pushBack(mMemClient); } if((mFlags & PxPvdInstrumentationFlag::ePROFILE) && mProfileZoneManager) { mPvdClients.pushBack(mProfileClient); mProfileZone = &physx::profile::PxProfileZone::createProfileZone(&physx::shdfnd::getAllocator(),gSdkName,gProfileNameProvider.getProfileNames()); } for(uint32_t i = 0; i < mPvdClients.size(); i++) mPvdClients[i]->onPvdConnected(); if (mProfileZone) { mProfileZoneManager->addProfileZoneHandler(*mProfileClient); mProfileZoneManager->addProfileZone( *mProfileZone ); } if ((mFlags & PxPvdInstrumentationFlag::ePROFILE)) { PxSetProfilerCallback(this); } } return mIsConnected; } void PvdImpl::disconnect() { if(mProfileZone) { mProfileZoneManager->removeProfileZoneHandler(*mProfileClient); mProfileZoneManager->removeProfileZone( *mProfileZone ); mProfileZone->release(); mProfileZone=NULL; removeClient(mProfileClient); } if(mIsConnected) { for(uint32_t i = 0; i < mPvdClients.size(); i++) mPvdClients[i]->onPvdDisconnected(); if(mMemClient) { removeClient(mMemClient); PvdMemClient* tmp = mMemClient; //avoid tracking deallocation itsself mMemClient = NULL; PVD_DELETE(tmp); } mSharedMetaProvider->release(); mPvdTransport->disconnect(); mObjectRegistrar.clear(); mIsConnected = false; } } void PvdImpl::flush() { for(uint32_t i = 0; i < mPvdClients.size(); i++) mPvdClients[i]->flush(); if ( mProfileZone ) { mProfileZone->flushEventIdNameMap(); mProfileZone->flushProfileEvents(); } } bool PvdImpl::isConnected(bool useCachedStatus) { if(mPvdTransport) return useCachedStatus ? mIsConnected : mPvdTransport->isConnected(); else return false; } PxPvdTransport* PvdImpl::getTransport() { return mPvdTransport; } PxPvdInstrumentationFlags PvdImpl::getInstrumentationFlags() { return mFlags; } void PvdImpl::sendTransportInitialization() { StreamInitialization init; EventStreamifier stream(mPvdTransport->lock()); init.serialize(stream); mPvdTransport->unlock(); } void PvdImpl::addClient(PvdClient* client) { PX_ASSERT(client); for(uint32_t i = 0; i < mPvdClients.size(); i++) { if(client == mPvdClients[i]) return; } mPvdClients.pushBack(client); if(mIsConnected) { client->onPvdConnected(); } } void PvdImpl::removeClient(PvdClient* client) { for(uint32_t i = 0; i < mPvdClients.size(); i++) { if(client == mPvdClients[i]) { client->onPvdDisconnected(); mPvdClients.remove(i); } } } void PvdImpl::onAllocation(size_t inSize, const char* inType, const char* inFile, int inLine, void* inAddr) { if(mMemClient) mMemClient->onAllocation(inSize, inType, inFile, inLine, inAddr); } void PvdImpl::onDeallocation(void* inAddr) { if(mMemClient) mMemClient->onDeallocation(inAddr); } PvdOMMetaDataProvider& PvdImpl::getMetaDataProvider() { return *mSharedMetaProvider; } bool PvdImpl::registerObject(const void* inItem) { return mObjectRegistrar.addItem(inItem); } bool PvdImpl::unRegisterObject(const void* inItem) { return mObjectRegistrar.decItem(inItem); } uint64_t PvdImpl::getNextStreamId() { uint64_t retval = ++mNextStreamId; return retval; } bool PvdImpl::initialize() { if(0 == sRefCount) { sInstance = PVD_NEW(PvdImpl)(); } ++sRefCount; return !!sInstance; } void PvdImpl::release() { if(sRefCount > 0) { if(--sRefCount) return; PVD_DELETE(sInstance); sInstance = NULL; } } PvdImpl* PvdImpl::getInstance() { return sInstance; } /************************************************************************************************************************** Instrumented profiling events ***************************************************************************************************************************/ static const uint32_t CrossThreadId = 99999789; void* PvdImpl::zoneStart(const char* eventName, bool detached, uint64_t contextId) { if(mProfileZone) { const uint16_t id = mProfileZone->getEventIdForName(eventName); if(detached) mProfileZone->startEvent(id, contextId, CrossThreadId); else mProfileZone->startEvent(id, contextId); } #if PX_NVTX if(mIsNVTXSupportEnabled) { if(detached) { // TODO : Need to use the nvtxRangeStart API for cross thread events nvtxEventAttributes_t eventAttrib; memset(&eventAttrib, 0, sizeof(eventAttrib)); eventAttrib.version = NVTX_VERSION; eventAttrib.size = NVTX_EVENT_ATTRIB_STRUCT_SIZE; eventAttrib.colorType = NVTX_COLOR_ARGB; eventAttrib.color = 0xFF00FF00; eventAttrib.messageType = NVTX_MESSAGE_TYPE_ASCII; eventAttrib.message.ascii = eventName; nvtxMarkEx(&eventAttrib); } else { nvtxRangePush(eventName); } } #endif return NULL; } void PvdImpl::zoneEnd(void* /*profilerData*/, const char* eventName, bool detached, uint64_t contextId) { if(mProfileZone) { const uint16_t id = mProfileZone->getEventIdForName(eventName); if(detached) mProfileZone->stopEvent(id, contextId, CrossThreadId); else mProfileZone->stopEvent(id, contextId); } #if PX_NVTX if(mIsNVTXSupportEnabled) { if(detached) { nvtxEventAttributes_t eventAttrib; memset(&eventAttrib, 0, sizeof(eventAttrib)); eventAttrib.version = NVTX_VERSION; eventAttrib.size = NVTX_EVENT_ATTRIB_STRUCT_SIZE; eventAttrib.colorType = NVTX_COLOR_ARGB; eventAttrib.color = 0xFFFF0000; eventAttrib.messageType = NVTX_MESSAGE_TYPE_ASCII; eventAttrib.message.ascii = eventName; nvtxMarkEx(&eventAttrib); } else { nvtxRangePop(); } } #endif } } // pvd } // physx