SpuLibspe2Support.cpp

Go to the documentation of this file.
00001 /*
00002 Bullet Continuous Collision Detection and Physics Library
00003 Copyright (c) 2003-2007 Erwin Coumans  http://bulletphysics.com
00004 
00005 This software is provided 'as-is', without any express or implied warranty.
00006 In no event will the authors be held liable for any damages arising from the use of this software.
00007 Permission is granted to anyone to use this software for any purpose, 
00008 including commercial applications, and to alter it and redistribute it freely, 
00009 subject to the following restrictions:
00010 
00011 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.
00012 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
00013 3. This notice may not be removed or altered from any source distribution.
00014 */
00015 
00016 #ifdef USE_LIBSPE2
00017 
00018 #include "SpuLibspe2Support.h"
00019 
00020 
00021 
00022 
00023 //SpuLibspe2Support helps to initialize/shutdown libspe2, start/stop SPU tasks and communication
00025 SpuLibspe2Support::SpuLibspe2Support(spe_program_handle_t *speprog, int numThreads)
00026 {
00027         this->program = speprog;
00028         this->numThreads =  ((numThreads <= spe_cpu_info_get(SPE_COUNT_PHYSICAL_SPES, -1)) ? numThreads : spe_cpu_info_get(SPE_COUNT_PHYSICAL_SPES, -1));
00029 }
00030 
00032 SpuLibspe2Support::~SpuLibspe2Support()
00033 {
00034         
00035         stopSPU();
00036 }
00037 
00038 
00039 
00041 void SpuLibspe2Support::sendRequest(uint32_t uiCommand, uint32_t uiArgument0, uint32_t uiArgument1)
00042 {
00043         spe_context_ptr_t context;
00044         
00045         switch (uiCommand)
00046         {
00047         case CMD_SAMPLE_TASK_COMMAND:
00048         {
00049                 //get taskdescription
00050                 SpuSampleTaskDesc* taskDesc = (SpuSampleTaskDesc*) uiArgument0;
00051 
00052                 btAssert(taskDesc->m_taskId<m_activeSpuStatus.size());
00053 
00054                 //get status of SPU on which task should run
00055                 btSpuStatus&    spuStatus = m_activeSpuStatus[taskDesc->m_taskId];
00056 
00057                 //set data for spuStatus
00058                 spuStatus.m_commandId = uiCommand;
00059                 spuStatus.m_status = Spu_Status_Occupied; //set SPU as "occupied"
00060                 spuStatus.m_taskDesc.p = taskDesc; 
00061                 
00062                 //get context
00063                 context = data[taskDesc->m_taskId].context;
00064                 
00065                 
00066                 taskDesc->m_mainMemoryPtr = reinterpret_cast<uint64_t> (spuStatus.m_lsMemory.p);
00067                 
00068 
00069                 break;
00070         }
00071         case CMD_GATHER_AND_PROCESS_PAIRLIST:
00072                 {
00073                         //get taskdescription
00074                         SpuGatherAndProcessPairsTaskDesc* taskDesc = (SpuGatherAndProcessPairsTaskDesc*) uiArgument0;
00075 
00076                         btAssert(taskDesc->taskId<m_activeSpuStatus.size());
00077 
00078                         //get status of SPU on which task should run
00079                         btSpuStatus&    spuStatus = m_activeSpuStatus[taskDesc->taskId];
00080 
00081                         //set data for spuStatus
00082                         spuStatus.m_commandId = uiCommand;
00083                         spuStatus.m_status = Spu_Status_Occupied; //set SPU as "occupied"
00084                         spuStatus.m_taskDesc.p = taskDesc; 
00085                         
00086                         //get context
00087                         context = data[taskDesc->taskId].context;
00088                         
00089                         
00090                         taskDesc->m_lsMemory = (CollisionTask_LocalStoreMemory*)spuStatus.m_lsMemory.p;
00091                         
00092                         break;
00093                 }
00094         default:
00095                 {
00097                         btAssert(0);
00098                 }
00099 
00100         };
00101 
00102         
00103         //write taskdescription in mailbox
00104         unsigned int event = Spu_Mailbox_Event_Task;
00105         spe_in_mbox_write(context, &event, 1, SPE_MBOX_ANY_NONBLOCKING);
00106 
00107 }
00108 
00110 void SpuLibspe2Support::waitForResponse(unsigned int *puiArgument0, unsigned int *puiArgument1)
00111 {
00113         
00115         
00116         btAssert(m_activeSpuStatus.size());
00117 
00118         
00119         int last = -1;
00120         
00121         //find an active spu/thread
00122         while(last < 0)
00123         {
00124                 for (int i=0;i<m_activeSpuStatus.size();i++)
00125                 {
00126                         if ( m_activeSpuStatus[i].m_status == Spu_Status_Free)
00127                         {
00128                                 last = i;
00129                                 break;
00130                         }
00131                 }
00132                 if(last < 0)
00133                         sched_yield();
00134         }
00135 
00136 
00137 
00138         btSpuStatus& spuStatus = m_activeSpuStatus[last];
00139 
00141         btAssert(last>=0);
00142 
00143         
00144 
00145         *puiArgument0 = spuStatus.m_taskId;
00146         *puiArgument1 = spuStatus.m_status;
00147 
00148 
00149 }
00150 
00151 
00152 void SpuLibspe2Support::startSPU()
00153 {
00154         this->internal_startSPU();
00155 }
00156 
00157 
00158 
00160 void SpuLibspe2Support::internal_startSPU()
00161 {
00162         m_activeSpuStatus.resize(numThreads);
00163         
00164         
00165         for (int i=0; i < numThreads; i++)
00166         {
00167                 
00168                 if(data[i].context == NULL) 
00169                 {
00170                                         
00171                          /* Create context */
00172                         if ((data[i].context = spe_context_create(0, NULL)) == NULL)
00173                         {
00174                               perror ("Failed creating context");
00175                           exit(1);
00176                         }
00177         
00178                         /* Load program into context */
00179                         if(spe_program_load(data[i].context, this->program))
00180                         {
00181                               perror ("Failed loading program");
00182                           exit(1);
00183                         }
00184                         
00185                         m_activeSpuStatus[i].m_status = Spu_Status_Startup; 
00186                         m_activeSpuStatus[i].m_taskId = i; 
00187                         m_activeSpuStatus[i].m_commandId = 0; 
00188                         m_activeSpuStatus[i].m_lsMemory.p = NULL; 
00189                         
00190                         
00191                         data[i].entry = SPE_DEFAULT_ENTRY;
00192                         data[i].flags = 0;
00193                         data[i].argp.p = &m_activeSpuStatus[i];
00194                         data[i].envp.p = NULL;
00195                         
00196                     /* Create thread for each SPE context */
00197                         if (pthread_create(&data[i].pthread, NULL, &ppu_pthread_function, &(data[i]) ))
00198                         {
00199                               perror ("Failed creating thread");
00200                           exit(1);
00201                         }
00202                         /*
00203                         else
00204                         {
00205                                 printf("started thread %d\n",i);
00206                         }*/
00207                 }               
00208         }
00209         
00210         
00211         for (int i=0; i < numThreads; i++)
00212         {
00213                 if(data[i].context != NULL) 
00214                 {
00215                         while( m_activeSpuStatus[i].m_status == Spu_Status_Startup)
00216                         {
00217                                 // wait for spu to set up
00218                                 sched_yield();
00219                         }
00220                         printf("Spu %d is ready\n", i);
00221                 }
00222         }
00223 }
00224 
00226 void SpuLibspe2Support::stopSPU()
00227 {
00228         // wait for all threads to finish 
00229         int i;
00230         for ( i = 0; i < this->numThreads; i++ ) 
00231         { 
00232                 
00233                 unsigned int event = Spu_Mailbox_Event_Shutdown;
00234                 spe_context_ptr_t context = data[i].context;
00235                 spe_in_mbox_write(context, &event, 1, SPE_MBOX_ALL_BLOCKING);
00236                 pthread_join (data[i].pthread, NULL); 
00237                 
00238         } 
00239         // close SPE program 
00240         spe_image_close(program); 
00241         // destroy SPE contexts 
00242         for ( i = 0; i < this->numThreads; i++ ) 
00243         { 
00244                 if(data[i].context != NULL)
00245                 {
00246                         spe_context_destroy (data[i].context);
00247                 }
00248         } 
00249         
00250         m_activeSpuStatus.clear();
00251         
00252 }
00253 
00254 
00255 
00256 #endif //USE_LIBSPE2
00257