From 3dfe2108cfab31ba3ee5527e217d0d8e99a51162 Mon Sep 17 00:00:00 2001 From: git perforce import user Date: Tue, 25 Oct 2016 12:29:14 -0600 Subject: Initial commit: PhysX 3.4.0 Update @ 21294896 APEX 1.4.0 Update @ 21275617 [CL 21300167] --- .../shared/general/RenderDebug/src/RenderDebug.cpp | 817 +++++++++++++++++++++ 1 file changed, 817 insertions(+) create mode 100644 APEX_1.4/shared/general/RenderDebug/src/RenderDebug.cpp (limited to 'APEX_1.4/shared/general/RenderDebug/src/RenderDebug.cpp') diff --git a/APEX_1.4/shared/general/RenderDebug/src/RenderDebug.cpp b/APEX_1.4/shared/general/RenderDebug/src/RenderDebug.cpp new file mode 100644 index 00000000..03554c43 --- /dev/null +++ b/APEX_1.4/shared/general/RenderDebug/src/RenderDebug.cpp @@ -0,0 +1,817 @@ +#include "RenderDebugTyped.h" + + +#include "RenderDebugImpl.h" +#include "ClientServer.h" +#include "ProcessRenderDebug.h" +#include "InternalRenderDebug.h" +#include "FileRenderDebug.h" + +#include +#include +#include + +#include "PsUserAllocated.h" +#include "PsMutex.h" +#include "PsString.h" +#include "PxErrorCallback.h" +#include "PxAllocatorCallback.h" +#include "PsArray.h" +#include "PsFoundation.h" + +namespace RENDER_DEBUG +{ +class RenderDebugIImpl; +void finalRelease(RenderDebugIImpl *nv); +} + +#include "GetArgs.h" +#include "PsFileBuffer.h" + +#if PX_WINDOWS_FAMILY +#pragma warning(disable:4986) +#endif + +#define SERVER_FILE_SIZE sizeof(ServerHeader)+(1024*1024) + +class EchoRemoteCommand +{ +public: + char mCommand[16384]; +}; + +typedef physx::shdfnd::Array< EchoRemoteCommand > EchoRemoteCommandVector; + +#ifdef USE_PX_FOUNDATION +#else +class DefaultErrorCallback : public physx::PxErrorCallback +{ +public: + DefaultErrorCallback(void) + { + } + + virtual void reportError(physx::PxErrorCode::Enum code, const char* message, const char* file, int line) + { + PX_UNUSED(code); + PX_UNUSED(file); + PX_UNUSED(line); + printf("PhysX: %s\r\n", message ); + } +private: +}; + +#if PX_WINDOWS_FAMILY +// on win32 we only have 8-byte alignment guaranteed, but the CRT provides special aligned allocation +// fns +#include +#include + +static void* platformAlignedAlloc(size_t size) +{ + return _aligned_malloc(size, 16); +} + +static void platformAlignedFree(void* ptr) +{ + _aligned_free(ptr); +} +#elif PX_LINUX || PX_ANDROID +static void* platformAlignedAlloc(size_t size) +{ + return ::memalign(16, size); +} + +static void platformAlignedFree(void* ptr) +{ + ::free(ptr); +} +#elif PX_WIIU +static void* platformAlignedAlloc(size_t size) +{ + size_t pad = 15 + sizeof(size_t); // store offset for delete. + uint8_t* base = (uint8_t*)::malloc(size+pad); + if(!base) + return NULL; + + uint8_t* ptr = (uint8_t*)(size_t(base + pad) & ~(15)); // aligned pointer + ((size_t*)ptr)[-1] = ptr - base; // store offset + + return ptr; +} + +static void platformAlignedFree(void* ptr) +{ + if(ptr == NULL) + return; + + uint8_t* base = ((uint8_t*)ptr) - ((size_t*)ptr)[-1]; + ::free(base); +} +#else + +// on PS3, XBox and Win64 we get 16-byte alignment by default +static void* platformAlignedAlloc(size_t size) +{ + void *ptr = ::malloc(size); + PX_ASSERT((reinterpret_cast(ptr) & 15)==0); + return ptr; +} + +static void platformAlignedFree(void* ptr) +{ + ::free(ptr); +} +#endif + + +class DefaultAllocator : public physx::PxAllocatorCallback +{ +public: + DefaultAllocator(void) + { + } + + ~DefaultAllocator(void) + { + } + + + virtual void* allocate(size_t size, const char* typeName, const char* filename, int line) + { + PX_UNUSED(typeName); + PX_UNUSED(filename); + PX_UNUSED(line); + void *ret = platformAlignedAlloc(size); + return ret; + } + + virtual void deallocate(void* ptr) + { + platformAlignedFree(ptr); + } +private: +}; + + +DefaultAllocator gDefaultAllocator; +DefaultErrorCallback gDefaultErrorCallback; +#endif + +#define RECORD_REMOTE_COMMANDS_VERSION 100 + +static char magic[4] = { 'R', 'R', 'C', 'V' }; + +static uint32_t isBigEndian(void) +{ + int32_t i = 1; + bool b = *(reinterpret_cast(&i))==0; + return b ? uint32_t(1) : uint32_t(0); +} + + +namespace RENDER_DEBUG +{ + +class PlaybackRemoteCommand +{ +public: + PlaybackRemoteCommand(void) + { + mFrameNumber = 0; + mArgc = 0; + for (uint32_t i=0; i<256; i++) + { + mArgv[i] = NULL; + } + } + void release(void) + { + mFrameNumber = 0; + for (uint32_t i=0; i(const_cast(mArgv[i]))); + mArgv[i] = NULL; + } + mArgc = 0; + } + uint32_t mFrameNumber; + uint32_t mArgc; + const char *mArgv[256]; +}; + +class RenderDebugIImpl : public physx::shdfnd::UserAllocated, public RenderDebugHook +{ + PX_NOCOPY(RenderDebugIImpl) +public: + RenderDebugIImpl(RENDER_DEBUG::RenderDebug::Desc &desc) : + mEchoRemoteCommandBuffer(PX_DEBUG_EXP("PxRenderDebug::mEchoRemoteCommandBuffer")) + { + mEndianSwap = false; + mRecordRemoteCommands = NULL; + mPlaybackRemoteCommands = NULL; + mCurrentFrame = 0; + mMeshId = 0; + mFileRenderDebug = NULL; + mIsValid = true; + mApexRenderDebug = NULL; + mInternalProcessRenderDebug = NULL; + mRenderDebug = NULL; + mClientServer = NULL; + mReadNext = false; + switch ( desc.runMode ) + { + case RenderDebug::RM_CLIENT: + case RenderDebug::RM_CLIENT_OR_FILE: + case RenderDebug::RM_SERVER: + { + if ( desc.runMode == RenderDebug::RM_SERVER ) // if running in server mode. + { + mClientServer = createClientServer(desc); + } + else + { + mClientServer = createClientServer(desc); + if ( mClientServer == NULL ) + { + if ( desc.runMode != RenderDebug::RM_CLIENT_OR_FILE ) + { + desc.errorCode = "Unable to locate server"; + } + else + { + desc.errorCode = NULL; + } + } + } + } + break; + case RenderDebug::RM_LOCAL: + break; + case RenderDebug::RM_FILE: + break; + } + + if ( desc.runMode == RenderDebug::RM_FILE || desc.runMode == RenderDebug::RM_CLIENT_OR_FILE || desc.runMode == RENDER_DEBUG::RenderDebug::RM_CLIENT ) + { + if ( desc.echoFileLocally ) + { + mInternalProcessRenderDebug = RENDER_DEBUG::createProcessRenderDebug(); + } + mFileRenderDebug = RENDER_DEBUG::createFileRenderDebug(desc.recordFileName,false,desc.echoFileLocally ? mInternalProcessRenderDebug : NULL, mClientServer); + if ( mFileRenderDebug == NULL ) + { + mIsValid = false; + desc.errorCode = "Failed to open recording file"; + } + } + if ( mIsValid ) + { + if ( mFileRenderDebug ) + { + mMeshId = 1000000; // + mRenderDebug = RENDER_DEBUG::createInternalRenderDebug(mFileRenderDebug,this); + } + else + { + if ( mInternalProcessRenderDebug == NULL ) + { + mInternalProcessRenderDebug = RENDER_DEBUG::createProcessRenderDebug(); + } + mRenderDebug = RENDER_DEBUG::createInternalRenderDebug(mInternalProcessRenderDebug,this); + } + } + if ( desc.errorCode ) + { + mIsValid = false; + } + if ( mIsValid && desc.recordRemoteCommands ) + { + mRecordRemoteCommands = PX_NEW(physx::PsFileBuffer)(desc.recordRemoteCommands, physx::PsFileBuffer::OPEN_WRITE_ONLY); + if ( mRecordRemoteCommands->isOpen() ) + { + mRecordRemoteCommands->write(magic, 4 ); + mRecordRemoteCommands->storeDword(RECORD_REMOTE_COMMANDS_VERSION); + uint32_t bigEndian = isBigEndian(); + mRecordRemoteCommands->storeDword(bigEndian); + mRecordRemoteCommands->flush(); + } + else + { + delete mRecordRemoteCommands; + mRecordRemoteCommands = NULL; + } + } + if ( mIsValid && desc.playbackRemoteCommands ) + { + mPlaybackRemoteCommands = PX_NEW(physx::PsFileBuffer)(desc.playbackRemoteCommands, physx::PsFileBuffer::OPEN_READ_ONLY); + if ( mPlaybackRemoteCommands->isOpen() ) + { + char temp[4]; + uint32_t r = mPlaybackRemoteCommands->read(temp,4); + uint32_t version = mPlaybackRemoteCommands->readDword(); + uint32_t bigEndian = mPlaybackRemoteCommands->readDword(); + + if ( r == 4 && magic[0] == temp[0] && magic[1] == temp[1] && magic[2] == temp[2] && magic[3] == temp[3] && version == RECORD_REMOTE_COMMANDS_VERSION ) + { + if ( bigEndian != isBigEndian() ) + { + mEndianSwap = true; + } + mReadNext = true; + } + else + { + delete mPlaybackRemoteCommands; + mPlaybackRemoteCommands = NULL; + } + } + else + { + delete mPlaybackRemoteCommands; + mPlaybackRemoteCommands = NULL; + } + } + mDesc = desc; + } + + virtual ~RenderDebugIImpl(void) + { + delete mRecordRemoteCommands; + delete mPlaybackRemoteCommands; + mPlaybackRemoteCommand.release(); + if ( mFileRenderDebug ) + { + mFileRenderDebug->release(); + } + if ( mClientServer ) + { + mClientServer->release(); + } + if ( mRenderDebug ) + { + mRenderDebug->releaseRenderDebug(); + } + if ( mInternalProcessRenderDebug ) + { + mInternalProcessRenderDebug->release(); + } + } + + virtual bool render(float dtime,RENDER_DEBUG::RenderDebugInterface *iface) + { + bool ret = true; + + mCurrentFrame++; + + mApexRenderDebug = iface; + + if ( mFileRenderDebug && mFileRenderDebug->getFrameCount() ) + { + mFileRenderDebug->processReadFrame(iface); + } + + if ( mClientServer && mDesc.runMode == RENDER_DEBUG::RenderDebug::RM_SERVER ) + { + mClientServer->processFrame(mInternalProcessRenderDebug,iface); + } + + ret = mRenderDebug->renderImpl(dtime,iface); + + return ret; + } + + + virtual void release(void) + { + finalRelease(this); + } + + bool isValid(void) const + { + return mIsValid; + } + + virtual uint32_t setFilePlayback(const char *fileName) + { + uint32_t ret = 0; + + if ( mFileRenderDebug ) + { + mFileRenderDebug->release(); + mFileRenderDebug = NULL; + } + + mFileRenderDebug = RENDER_DEBUG::createFileRenderDebug(fileName,true,mInternalProcessRenderDebug, NULL); + + if ( mFileRenderDebug ) + { + mFileRenderDebug->setFrame(0); + ret = mFileRenderDebug->getFrameCount(); + } + + return ret; + } + + virtual bool setPlaybackFrame(uint32_t playbackFrame) + { + bool ret = false; + + if ( mFileRenderDebug && playbackFrame < mFileRenderDebug->getFrameCount() ) + { + ret = true; + mFileRenderDebug->setFrame(playbackFrame); + } + + return ret; + } + + virtual uint32_t getPlaybackFrameCount(void) const + { + uint32_t ret = 0; + if ( mFileRenderDebug ) + { + ret = mFileRenderDebug->getFrameCount(); + } + return ret; + } + + virtual void stopPlayback(void) + { + if ( mFileRenderDebug ) + { + mFileRenderDebug->release(); + mFileRenderDebug = NULL; + } + } + + virtual bool trylock(void) + { + return mMutex.trylock(); + } + + virtual void lock(void) + { + mMutex.lock(); + } + + virtual void unlock(void) + { + mMutex.unlock(); + } + + /** + \brief Convenience method to return a unique mesh id number (simply a global counter to avoid clashing with other ids + */ + virtual uint32_t getMeshId(void) + { + mMeshId++; + return mMeshId; + } + + /** + \brief Transmit an actual input event to the remote client + + \param ev The input event data to transmit + */ + virtual void sendInputEvent(const InputEvent &ev) + { + if ( mClientServer ) + { + mClientServer->sendInputEvent(ev); + } + } + + + virtual bool sendRemoteCommand(const char *fmt,...) + { + bool ret = false; + + EchoRemoteCommand c; + va_list arg; + va_start( arg, fmt ); + physx::shdfnd::vsnprintf(c.mCommand,sizeof(c.mCommand)-1, fmt, arg); + va_end(arg); + + if ( mClientServer ) + { + ret = mClientServer->sendCommand(c.mCommand); + } + else + { + mEchoRemoteCommandBuffer.pushBack(c); + } + return ret; + } + + virtual const char ** getRemoteCommand(uint32_t &argc) + { + const char **ret = NULL; + argc = 0; + + if ( mClientServer ) + { + ret = mClientServer->getCommand(argc); + } + else if ( !mEchoRemoteCommandBuffer.empty() ) + { + mCurrentCommand = mEchoRemoteCommandBuffer[0]; + mEchoRemoteCommandBuffer.remove(0); + ret = mParser.getArgs(mCurrentCommand.mCommand,argc); + } + + if ( mReadNext ) + { + readNextRemoteCommand(); + mReadNext = false; + } + + if ( mPlaybackRemoteCommands ) + { + ret = NULL; + argc = 0; + if ( mPlaybackRemoteCommand.mFrameNumber == mCurrentFrame ) + { + argc = mPlaybackRemoteCommand.mArgc; + ret = mPlaybackRemoteCommand.mArgv; + mReadNext = true; + } + } + + if ( mRecordRemoteCommands && ret && argc < 256 ) + { + mRecordRemoteCommands->storeDword(mCurrentFrame); + mRecordRemoteCommands->storeDword(argc); + for (uint32_t i=0; istoreDword(len); + mRecordRemoteCommands->write(str,len); + } + mRecordRemoteCommands->flush(); + } + + return ret; + } + + + /** + \brief Transmits an arbitrary block of binary data to the remote machine. The block of data can have a command and id associated with it. + + It is important to note that due to the fact the RenderDebug system is synchronized every single frame, it is strongly recommended + that you only use this feature for relatively small data items; probably on the order of a few megabytes at most. If you try to do + a very large transfer, in theory it would work, but it might take a very long time to complete and look like a hang since it will + essentially be blocking. + + \param command An arbitrary command associated with this data transfer, for example this could indicate a remote file request. + \param id An arbitrary id associated with this data transfer, for example the id could be the file name of a file transfer request. + \param data The block of binary data to transmit, you are responsible for maintaining endian correctness of the internal data if necessary. + \param dlen The length of the lock of data to transmit. + + \return Returns true if the data was queued to be transmitted, false if it failed. + */ + virtual bool sendRemoteResource(const char *command, + const char *id, + const void *data, + uint32_t dlen) + { + bool ret = false; + + if ( mClientServer ) + { + ret = mClientServer->sendRemoteResource(command,id,data,dlen); + } + + return ret; + } + + /** + \brief This function allows you to request a file from the remote machine by name. If successful it will be returned via 'getRemoteData' + + \param command The command field associated with this request which will be returned by 'getRemoteData' + \param fileName The filename being requested from the remote machine. + + \return Returns true if the request was queued to be transmitted, false if it failed. + */ + virtual bool requestRemoteResource(const char *command, + const char *fileName) + { + bool ret = false; + + if ( mClientServer ) + { + ret = mClientServer->requestRemoteResource(command,fileName); + } + + return ret; + } + + /** + \brief Retrieves a block of remotely transmitted binary data. + + \param command A a reference to a pointer which will store the arbitrary command associated with this data transfer, for example this could indicate a remote file request. + \param id A reference to a pointer which will store an arbitrary id associated with this data transfer, for example the id could be the file name of a file transfer request. + \param dlen A reference that will contain length of the lock of data received. + \param remoteIsBigEndian A reference to a boolean which will be set to true if the remote machine that sent this data is big endian format. + + \retrun A pointer to the block of data received. + */ + virtual const void * getRemoteResource(const char *&command, + const char *&id, + uint32_t &dlen, + bool &remoteIsBigEndian) + { + const void *ret = NULL; + + if ( mClientServer ) + { + ret = mClientServer->getRemoteResource(command,id,dlen,remoteIsBigEndian); + } + + return ret; + } + + + virtual RENDER_DEBUG::RenderDebug::RunMode getRunMode(void) + { + RENDER_DEBUG::RenderDebug::RunMode ret = RENDER_DEBUG::RenderDebug::RM_LOCAL; + if ( mClientServer ) + { + if ( mClientServer->isServer() ) + { + ret = RENDER_DEBUG::RenderDebug::RM_SERVER; + } + else + { + ret = RENDER_DEBUG::RenderDebug::RM_CLIENT; + } + } + else if ( mFileRenderDebug ) + { + ret = RENDER_DEBUG::RenderDebug::RM_FILE; + } + return ret; + } + + virtual bool isConnected(void) const + { + bool ret = false; + + if ( mClientServer ) + { + ret = mClientServer->isConnected(); + } + + return ret; + } + + virtual uint32_t getCommunicationsFrame(void) const + { + return mClientServer ? mClientServer->getCommunicationsFrame() : 0; + } + + virtual const char *getRemoteApplicationName(void) + { + const char *ret = NULL; + + if ( mClientServer ) + { + ret = mClientServer->getRemoteApplicationName(); + } + + return ret; + } + + virtual RenderDebugTyped *getRenderDebugTyped(void) + { + return static_cast< RenderDebugTyped *>(mRenderDebug); + } + + void readNextRemoteCommand(void) + { + if ( mPlaybackRemoteCommands == NULL ) return; + mPlaybackRemoteCommand.release(); // release previous command + mPlaybackRemoteCommand.mFrameNumber = mPlaybackRemoteCommands->readDword(); + if ( mPlaybackRemoteCommand.mFrameNumber == 0 ) + { + mPlaybackRemoteCommand.release(); + delete mPlaybackRemoteCommands; + mPlaybackRemoteCommands = NULL; + } + else + { + mPlaybackRemoteCommand.mArgc = mPlaybackRemoteCommands->readDword(); + for (uint32_t i=0; ireadDword(); + mPlaybackRemoteCommand.mArgv[i] = static_cast(PX_ALLOC(len,"PlaybackRemoteCommand")); + uint32_t rbytes = mPlaybackRemoteCommands->read(reinterpret_cast(const_cast(mPlaybackRemoteCommand.mArgv[i])),len); + if ( rbytes != len ) + { + mPlaybackRemoteCommand.release(); + delete mPlaybackRemoteCommands; + mPlaybackRemoteCommands = NULL; + } + } + } + } + + + /** + \brief Returns any incoming input event for processing purposes + */ + virtual const InputEvent *getInputEvent(bool flush) + { + const InputEvent *ret = NULL; + + if ( mClientServer ) + { + ret = mClientServer->getInputEvent(flush); + } + + return ret; + } + + /** + \brief Set the base file name to record communications stream; or NULL to disable it. + + \param fileName The base name of the file to record the communications channel stream to, or NULL to disable it. + */ + virtual bool setStreamFilename(const char *fileName) + { + bool ret = false; + if ( mClientServer ) + { + ret = mClientServer->setStreamFilename(fileName); + } + return ret; + } + + /** + \brief Begin playing back a communications stream recording + + \param fileName The name of the previously captured communications stream file + */ + virtual bool setStreamPlayback(const char *fileName) + { + bool ret = false; + if ( mClientServer ) + { + ret = mClientServer->setStreamPlayback(fileName); + } + return ret; + } + + uint32_t mCurrentFrame; + uint32_t mMeshId; + physx::shdfnd::Mutex mMutex; + ClientServer *mClientServer; + RenderDebug::Desc mDesc; + bool mIsValid; + RENDER_DEBUG::RenderDebugInterface *mApexRenderDebug; + RENDER_DEBUG::RenderDebugImpl *mRenderDebug; + RENDER_DEBUG::FileRenderDebug *mFileRenderDebug; + RENDER_DEBUG::ProcessRenderDebug *mInternalProcessRenderDebug; + EchoRemoteCommand mCurrentCommand; + EchoRemoteCommandVector mEchoRemoteCommandBuffer; + GetArgs mParser; + physx::PsFileBuffer *mRecordRemoteCommands; + bool mEndianSwap; + physx::PsFileBuffer *mPlaybackRemoteCommands; + bool mReadNext; + PlaybackRemoteCommand mPlaybackRemoteCommand; +}; + +RENDER_DEBUG::RenderDebug *createRenderDebug(RENDER_DEBUG::RenderDebug::Desc &desc) +{ + RENDER_DEBUG::RenderDebug *ret = NULL; + + if ( desc.versionNumber != RENDER_DEBUG_VERSION || desc.foundation == NULL) + { + return NULL; + } + + RENDER_DEBUG::RenderDebugIImpl *c = PX_NEW(RENDER_DEBUG::RenderDebugIImpl)(desc); + + if ( !c->isValid() ) + { + c->release(); + c = NULL; + } + else + { + ret = static_cast< RENDER_DEBUG::RenderDebug *>(c->getRenderDebugTyped()); + } + + return ret; +} + +void finalRelease(RENDER_DEBUG::RenderDebugIImpl *nv) +{ + delete nv; +} + +} // end of namespace + + -- cgit v1.2.3