diff --git a/Extras/BulletMultiThreaded/SpuLibspe2Support.cpp b/Extras/BulletMultiThreaded/SpuLibspe2Support.cpp index daef6fc11..a312450ed 100644 --- a/Extras/BulletMultiThreaded/SpuLibspe2Support.cpp +++ b/Extras/BulletMultiThreaded/SpuLibspe2Support.cpp @@ -1,216 +1,257 @@ -/* -Bullet Continuous Collision Detection and Physics Library -Copyright (c) 2003-2007 Erwin Coumans http://bulletphysics.com - -This software is provided 'as-is', without any express or implied warranty. -In no event will the authors be held liable for any damages arising from the use of this software. -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it freely, -subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. -2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. -3. This notice may not be removed or altered from any source distribution. -*/ -#ifdef USE_LIBSPE2 - -#include "SpuLibspe2Support.h" - -#include "SpuCollisionTaskProcess.h" -#include "SpuNarrowPhaseCollisionTask/SpuGatheringCollisionTask.h" - -#include - -///SpuLibspe2Support helps to initialize/shutdown libspe2, start/stop SPU tasks and communication -///Setup and initialize SPU/CELL/Libspe2 -SpuLibspe2Support::SpuLibspe2Support(spe_program_handle_t *speprog,int numThreads) -{ - program = speprog - startSPUs(numThreads); - N = numThreads; -} - -///cleanup/shutdown Libspe2 -SpuLibspe2Support::~SpuLibspe2Support() -{ - stopSPUs(); -} - - - -#include - -#ifdef WIN32 -DWORD WINAPI Thread_no_1( LPVOID lpParam ) -{ - - btSpuStatus* status = (btSpuStatus*)lpParam; - - - while (1) - { - WaitForSingleObject(status->m_eventStartHandle,INFINITE); - btAssert(status->m_status); - - SpuGatherAndProcessPairsTaskDesc* taskDesc = status->m_taskDesc; - - if (taskDesc) - { - processCollisionTask(*taskDesc); - SetEvent(status->m_eventCompletetHandle); - } else - { - //exit Thread - break; - } - - } - - return 0; - -} -#endif -///send messages to SPUs -void SpuLibspe2Support::sendRequest(uint32_t uiCommand, uint32_t uiArgument0, uint32_t uiArgument1) -{ - /// gMidphaseSPU.sendRequest(CMD_GATHER_AND_PROCESS_PAIRLIST, (uint32_t) &taskDesc); - - ///we should spawn an SPU task here, and in 'waitForResponse' it should wait for response of the (one of) the first tasks that finished - - - - switch (uiCommand) - { - case CMD_GATHER_AND_PROCESS_PAIRLIST: - { - - SpuGatherAndProcessPairsTaskDesc* taskDesc = (SpuGatherAndProcessPairsTaskDesc*) uiArgument0 ; - -//#define SINGLE_THREADED 1 -#ifdef SINGLE_THREADED - - btSpuStatus& spuStatus = m_activeSpuStatus[0]; - taskDesc->m_lsMemory = (CollisionTask_LocalStoreMemory*)spuStatus.m_lsMemory; - processCollisionTask(*taskDesc); - HANDLE handle =0; -#else - - btAssert(taskDesc->taskId>=0); - btAssert(taskDesc->taskIdtaskId]; - - spuStatus.m_commandId = uiCommand; - spuStatus.m_status = 1; - spuStatus.m_taskDesc = taskDesc; - taskDesc->m_lsMemory = (CollisionTask_LocalStoreMemory*)spuStatus.m_lsMemory; - ///fire event to start new task - SetEvent(spuStatus.m_eventStartHandle); - -#endif //CollisionTask_LocalStoreMemory - - - - break; - } - default: - { - ///not implemented - btAssert(0); - } - - }; - - -} - -///check for messages from SPUs -void SpuLibspe2Support::waitForResponse(unsigned int *puiArgument0, unsigned int *puiArgument1) -{ - ///We should wait for (one of) the first tasks to finish (or other SPU messages), and report its response - - ///A possible response can be 'yes, SPU handled it', or 'no, please do a PPU fallback' - - - btAssert(m_activeSpuStatus.size()); - - int last = -1; - - //find an active spu/thread - for (int i=0;i=0); - -#else - last=0; - btSpuStatus& spuStatus = m_activeSpuStatus[last]; -#endif //SINGLE_THREADED - - - - *puiArgument0 = spuStatus.m_taskId; - *puiArgument1 = spuStatus.m_status; - - -} - - -///start the spus (can be called at the beginning of each frame, to make sure that the right SPU program is loaded) -void SpuLibspe2Support::startSPUs(int numThreads) -{ -#ifdef WIN32 - m_activeSpuStatus.resize(numThreads); -#endif - - for (int i=0;iprogram = speprog; + this->numThreads = ((numThreads <= spe_cpu_info_get(SPE_COUNT_PHYSICAL_SPES, -1)) ? numThreads : spe_cpu_info_get(SPE_COUNT_PHYSICAL_SPES, -1)); +} + +///cleanup/shutdown Libspe2 +SpuLibspe2Support::~SpuLibspe2Support() +{ + + stopSPU(); +} + + + +///send messages to SPUs +void SpuLibspe2Support::sendRequest(uint32_t uiCommand, uint32_t uiArgument0, uint32_t uiArgument1) +{ + spe_context_ptr_t context; + + switch (uiCommand) + { + case CMD_SAMPLE_TASK_COMMAND: + { + //get taskdescription + SpuSampleTaskDesc* taskDesc = (SpuSampleTaskDesc*) uiArgument0; + + btAssert(taskDesc->m_taskIdm_taskId]; + + //set data for spuStatus + spuStatus.m_commandId = uiCommand; + spuStatus.m_status = Spu_Status_Occupied; //set SPU as "occupied" + spuStatus.m_taskDesc.p = taskDesc; + + //get context + context = data[taskDesc->m_taskId].context; + + + taskDesc->m_mainMemoryPtr = reinterpret_cast (spuStatus.m_lsMemory.p); + + + break; + } + case CMD_GATHER_AND_PROCESS_PAIRLIST: + { + //get taskdescription + SpuGatherAndProcessPairsTaskDesc* taskDesc = (SpuGatherAndProcessPairsTaskDesc*) uiArgument0; + + btAssert(taskDesc->taskIdtaskId]; + + //set data for spuStatus + spuStatus.m_commandId = uiCommand; + spuStatus.m_status = Spu_Status_Occupied; //set SPU as "occupied" + spuStatus.m_taskDesc.p = taskDesc; + + //get context + context = data[taskDesc->taskId].context; + + + taskDesc->m_lsMemory = (CollisionTask_LocalStoreMemory*)spuStatus.m_lsMemory.p; + + break; + } + default: + { + ///not implemented + btAssert(0); + } + + }; + + + //write taskdescription in mailbox + unsigned int event = Spu_Mailbox_Event_Task; + spe_in_mbox_write(context, &event, 1, SPE_MBOX_ANY_NONBLOCKING); + +} + +///check for messages from SPUs +void SpuLibspe2Support::waitForResponse(unsigned int *puiArgument0, unsigned int *puiArgument1) +{ + ///We should wait for (one of) the first tasks to finish (or other SPU messages), and report its response + + ///A possible response can be 'yes, SPU handled it', or 'no, please do a PPU fallback' + + btAssert(m_activeSpuStatus.size()); + + + int last = -1; + + //find an active spu/thread + while(last < 0) + { + for (int i=0;i=0); + + + + *puiArgument0 = spuStatus.m_taskId; + *puiArgument1 = spuStatus.m_status; + + +} + + +void SpuLibspe2Support::startSPU() +{ + this->internal_startSPU(); +} + + + +///start the spus group (can be called at the beginning of each frame, to make sure that the right SPU program is loaded) +void SpuLibspe2Support::internal_startSPU() +{ + m_activeSpuStatus.resize(numThreads); + + + for (int i=0; i < numThreads; i++) + { + + if(data[i].context == NULL) + { + + /* Create context */ + if ((data[i].context = spe_context_create(0, NULL)) == NULL) + { + perror ("Failed creating context"); + exit(1); + } + + /* Load program into context */ + if(spe_program_load(data[i].context, this->program)) + { + perror ("Failed loading program"); + exit(1); + } + + m_activeSpuStatus[i].m_status = Spu_Status_Startup; + m_activeSpuStatus[i].m_taskId = i; + m_activeSpuStatus[i].m_commandId = 0; + m_activeSpuStatus[i].m_lsMemory.p = NULL; + + + data[i].entry = SPE_DEFAULT_ENTRY; + data[i].flags = 0; + data[i].argp.p = &m_activeSpuStatus[i]; + data[i].envp.p = NULL; + + /* Create thread for each SPE context */ + if (pthread_create(&data[i].pthread, NULL, &ppu_pthread_function, &(data[i]) )) + { + perror ("Failed creating thread"); + exit(1); + } + /* + else + { + printf("started thread %d\n",i); + }*/ + } + } + + + for (int i=0; i < numThreads; i++) + { + if(data[i].context != NULL) + { + while( m_activeSpuStatus[i].m_status == Spu_Status_Startup) + { + // wait for spu to set up + sched_yield(); + } + printf("Spu %d is ready\n", i); + } + } +} + +///tell the task scheduler we are done with the SPU tasks +void SpuLibspe2Support::stopSPU() +{ + // wait for all threads to finish + int i; + for ( i = 0; i < this->numThreads; i++ ) + { + + unsigned int event = Spu_Mailbox_Event_Shutdown; + spe_context_ptr_t context = data[i].context; + spe_in_mbox_write(context, &event, 1, SPE_MBOX_ALL_BLOCKING); + pthread_join (data[i].pthread, NULL); + + } + // close SPE program + spe_image_close(program); + // destroy SPE contexts + for ( i = 0; i < this->numThreads; i++ ) + { + if(data[i].context != NULL) + { + spe_context_destroy (data[i].context); + } + } + + m_activeSpuStatus.clear(); + +} + + + +#endif //USE_LIBSPE2 + diff --git a/Extras/BulletMultiThreaded/SpuLibspe2Support.h b/Extras/BulletMultiThreaded/SpuLibspe2Support.h index 0608d3f89..4e542c5af 100644 --- a/Extras/BulletMultiThreaded/SpuLibspe2Support.h +++ b/Extras/BulletMultiThreaded/SpuLibspe2Support.h @@ -1,131 +1,173 @@ -/* -Bullet Continuous Collision Detection and Physics Library -Copyright (c) 2003-2007 Erwin Coumans http://bulletphysics.com - -This software is provided 'as-is', without any express or implied warranty. -In no event will the authors be held liable for any damages arising from the use of this software. -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it freely, -subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. -2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. -3. This notice may not be removed or altered from any source distribution. -*/ - -///USE_LIBSPE2: this define should be in the build system, or in -//#define USE_LIBSPE2 1 -#ifdef USE_LIBSPE2 - -#ifndef SPU_LIBSPE2_SUPPORT_H -#define SPU_LIBSPE2_SUPPORT_H - -#include "LinearMath/btAlignedObjectArray.h" -#include -#include - - -/** - * Note: - * The order of elements in this enum are important, that's why each one is explicitly - * given a value. They will correspond to the .elf names/addresses that will be - * loaded into Libspe2. - * Mixing up these values will cause the wrong code to execute, for instance, the - * solver may be asked to do a collision detection job. - */ -#ifdef WIN32 // original enum, but for libspe2 will pass the SPE program handle ptr directly -typedef enum { - SPU_ELF_COLLISION_DETECTION=0, - SPU_ELF_SAMPLE, -//SPU_ELF_INTEGRATION, -//SPU_ELF_SOLVER, - SPU_ELF_LAST, -} SpuLibspe2ElfId_t; -#endif -#ifdef WIN32 -#include -#define memalign(alignment, size) malloc(size); -#else -#include -#endif // WIN32 - -#define MAXSPUS 16 -typedef struct ppu_pthread_data { -spe_context_ptr_t context; -pthread_t pthread; -unsigned int entry; -unsigned int flags; -void *argp; -void *envp; -spe_stop_info_t stopinfo; -} ppu_pthread_data_t; - -void *ppu_pthread_function(void *arg) -{ - ppu_pthread_data_t datap = *(ppu_pthread_data_t *)arg; - int rc; - do { - rc = spe_context_run(datap->context, &datap->entry, datap->flags, datap->argp, datap->envp, &datap->stopinfo); - } while (rc > 0); // loop until exit or error, and while any stop & signal - pthread_exit(NULL); -} - - - -#include //for uint32_t etc. - -///placeholder, until libspe2 support is there -struct btSpuStatus -{ - uint32_t m_taskId; - uint32_t m_commandId; - uint32_t m_status; - - struct SpuGatherAndProcessPairsTaskDesc* m_taskDesc; - - void* m_threadHandle; - void* m_lsMemory; - - void* m_eventStartHandle; - char m_eventStartHandleName[32]; - - void* m_eventCompletetHandle; - char m_eventCompletetHandleName[32]; - - -}; - -///SpuLibspe2Support helps to initialize/shutdown libspe2, start/stop SPU tasks and communication -class SpuLibspe2Support { - - btAlignedObjectArray m_activeSpuStatus; - -public: - ///Setup and initialize SPU/CELL/Libspe2 - SpuLibspe2Support(spe_program_handle_t *speprog,int numThreads); - // SPE program handle ptr. - spe_program_handle_t *program; - // SPE program data - ppu_pthread_data_t data[MAX_SPUS]; - // num SPE Threads - unsigned int N; - ///cleanup/shutdown Libspe2 - ~SpuLibspe2Support(); - - ///send messages to SPUs - void sendRequest(uint32_t uiCommand, uint32_t uiArgument0, uint32_t uiArgument1=0); - - ///check for messages from SPUs - void waitForResponse(unsigned int *puiArgument0, unsigned int *puiArgument1); - - ///start the spus (can be called at the beginning of each frame, to make sure that the right SPU program is loaded) - void startSPUs(int numThreads); - - ///tell the task scheduler we are done with the SPU tasks - void stopSPUs(); - -}; - -#endif //SPU_LIBSPE2_SUPPORT_H - -#endif //USE_LIBSPE2 +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2007 Erwin Coumans http://bulletphysics.com + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + + +#ifndef SPU_LIBSPE2_SUPPORT_H +#define SPU_LIBSPE2_SUPPORT_H + +#include //for uint32_t etc. + +#ifdef USE_LIBSPE2 + +#include +#include +//#include "SpuNarrowPhaseCollisionTask/SpuGatheringCollisionTask.h" +#include "PlatformDefinitions.h" + + +//extern struct SpuGatherAndProcessPairsTaskDesc; + +enum +{ + Spu_Mailbox_Event_Nothing = 0, + Spu_Mailbox_Event_Task = 1, + Spu_Mailbox_Event_Shutdown = 2, + + Spu_Mailbox_Event_ForceDword = 0xFFFFFFFF + +}; + +enum +{ + Spu_Status_Free = 0, + Spu_Status_Occupied = 1, + Spu_Status_Startup = 2, + + Spu_Status_ForceDword = 0xFFFFFFFF + +}; + + +struct btSpuStatus +{ + uint32_t m_taskId; + uint32_t m_commandId; + uint32_t m_status; + + addr64 m_taskDesc; + addr64 m_lsMemory; + +} +__attribute__ ((aligned (128))) +; + + + +#ifndef __SPU__ + +#include "LinearMath/btAlignedObjectArray.h" +#include "SpuCollisionTaskProcess.h" +#include "SpuSampleTaskProcess.h" +#include "btThreadSupportInterface.h" +#include +#include +#include + +#define MAX_SPUS 4 + +typedef struct ppu_pthread_data +{ + spe_context_ptr_t context; + pthread_t pthread; + unsigned int entry; + unsigned int flags; + addr64 argp; + addr64 envp; + spe_stop_info_t stopinfo; +} ppu_pthread_data_t; + + +static void *ppu_pthread_function(void *arg) +{ + ppu_pthread_data_t * datap = (ppu_pthread_data_t *)arg; + /* + int rc; + do + {*/ + spe_context_run(datap->context, &datap->entry, datap->flags, datap->argp.p, datap->envp.p, &datap->stopinfo); + if (datap->stopinfo.stop_reason == SPE_EXIT) + { + if (datap->stopinfo.result.spe_exit_code != 0) + { + perror("FAILED: SPE returned a non-zero exit status: \n"); + exit(1); + } + } + else + { + perror("FAILED: SPE abnormally terminated\n"); + exit(1); + } + + + //} while (rc > 0); // loop until exit or error, and while any stop & signal + pthread_exit(NULL); +} + + + + + + +///SpuLibspe2Support helps to initialize/shutdown libspe2, start/stop SPU tasks and communication +class SpuLibspe2Support : public btThreadSupportInterface +{ + + btAlignedObjectArray m_activeSpuStatus; + +public: + //Setup and initialize SPU/CELL/Libspe2 + SpuLibspe2Support(spe_program_handle_t *speprog,int numThreads); + + // SPE program handle ptr. + spe_program_handle_t *program; + + // SPE program data + ppu_pthread_data_t data[MAX_SPUS]; + + //cleanup/shutdown Libspe2 + ~SpuLibspe2Support(); + + ///send messages to SPUs + void sendRequest(uint32_t uiCommand, uint32_t uiArgument0, uint32_t uiArgument1=0); + + //check for messages from SPUs + void waitForResponse(unsigned int *puiArgument0, unsigned int *puiArgument1); + + //start the spus (can be called at the beginning of each frame, to make sure that the right SPU program is loaded) + virtual void startSPU(); + + //tell the task scheduler we are done with the SPU tasks + virtual void stopSPU(); + +private: + + ///start the spus (can be called at the beginning of each frame, to make sure that the right SPU program is loaded) + void internal_startSPU(); + + + int numThreads; + +}; + +#endif // NOT __SPU__ + +#endif //USE_LIBSPE2 + +#endif //SPU_LIBSPE2_SUPPORT_H + + + +