SpuCollisionTaskProcess.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 
00017 //#define DEBUG_SPU_TASK_SCHEDULING 1
00018 
00019 
00020 //class OptimizedBvhNode;
00021 
00022 #include "SpuCollisionTaskProcess.h"
00023 
00024 
00025 
00026 
00027 void    SpuCollisionTaskProcess::setNumTasks(int maxNumTasks)
00028 {
00029         if (int(m_maxNumOutstandingTasks) != maxNumTasks)
00030         {
00031                 m_maxNumOutstandingTasks = maxNumTasks;
00032                 m_taskBusy.resize(m_maxNumOutstandingTasks);
00033                 m_spuGatherTaskDesc.resize(m_maxNumOutstandingTasks);
00034 
00035                 for (int i = 0; i < m_taskBusy.size(); i++)
00036                 {
00037                         m_taskBusy[i] = false;
00038                 }
00039 
00041                 if (m_workUnitTaskBuffers != 0)
00042                 {
00043                         btAlignedFree(m_workUnitTaskBuffers);
00044                 }
00045                 
00046                 m_workUnitTaskBuffers = (unsigned char *)btAlignedAlloc(MIDPHASE_WORKUNIT_TASK_SIZE*m_maxNumOutstandingTasks, 128);
00047         }
00048         
00049 }
00050 
00051 
00052 
00053 SpuCollisionTaskProcess::SpuCollisionTaskProcess(class  btThreadSupportInterface*       threadInterface, unsigned int   maxNumOutstandingTasks)
00054 :m_threadInterface(threadInterface),
00055 m_maxNumOutstandingTasks(0)
00056 {
00057         m_workUnitTaskBuffers = (unsigned char *)0;
00058         setNumTasks(maxNumOutstandingTasks);
00059         m_numBusyTasks = 0;
00060         m_currentTask = 0;
00061         m_currentPage = 0;
00062         m_currentPageEntry = 0;
00063 
00064 #ifdef DEBUG_SpuCollisionTaskProcess
00065         m_initialized = false;
00066 #endif
00067 
00068         m_threadInterface->startSPU();
00069 
00070         //printf("sizeof vec_float4: %d\n", sizeof(vec_float4));
00071         printf("sizeof SpuGatherAndProcessWorkUnitInput: %d\n", int(sizeof(SpuGatherAndProcessWorkUnitInput)));
00072 
00073 }
00074 
00075 SpuCollisionTaskProcess::~SpuCollisionTaskProcess()
00076 {
00077         
00078         if (m_workUnitTaskBuffers != 0)
00079         {
00080                 btAlignedFree(m_workUnitTaskBuffers);
00081                 m_workUnitTaskBuffers = 0;
00082         }
00083         
00084 
00085 
00086         m_threadInterface->stopSPU();
00087         
00088 }
00089 
00090 
00091 
00092 void SpuCollisionTaskProcess::initialize2(bool useEpa)
00093 {
00094 
00095 #ifdef DEBUG_SPU_TASK_SCHEDULING
00096         printf("SpuCollisionTaskProcess::initialize()\n");
00097 #endif //DEBUG_SPU_TASK_SCHEDULING
00098         
00099         for (int i = 0; i < int (m_maxNumOutstandingTasks); i++)
00100         {
00101                 m_taskBusy[i] = false;
00102         }
00103         m_numBusyTasks = 0;
00104         m_currentTask = 0;
00105         m_currentPage = 0;
00106         m_currentPageEntry = 0;
00107         m_useEpa = useEpa;
00108 
00109 #ifdef DEBUG_SpuCollisionTaskProcess
00110         m_initialized = true;
00111         btAssert(MIDPHASE_NUM_WORKUNITS_PER_TASK*sizeof(SpuGatherAndProcessWorkUnitInput) <= MIDPHASE_WORKUNIT_TASK_SIZE);
00112 #endif
00113 }
00114 
00115 
00116 void SpuCollisionTaskProcess::issueTask2()
00117 {
00118 
00119 #ifdef DEBUG_SPU_TASK_SCHEDULING
00120         printf("SpuCollisionTaskProcess::issueTask (m_currentTask= %d\n)", m_currentTask);
00121 #endif //DEBUG_SPU_TASK_SCHEDULING
00122 
00123         m_taskBusy[m_currentTask] = true;
00124         m_numBusyTasks++;
00125 
00126 
00127         SpuGatherAndProcessPairsTaskDesc& taskDesc = m_spuGatherTaskDesc[m_currentTask];
00128         taskDesc.m_useEpa = m_useEpa;
00129 
00130         {
00131                 // send task description in event message
00132                 // no error checking here...
00133                 // but, currently, event queue can be no larger than NUM_WORKUNIT_TASKS.
00134         
00135                 taskDesc.m_inPairPtr = reinterpret_cast<uint64_t>(MIDPHASE_TASK_PTR(m_currentTask));
00136         
00137                 taskDesc.taskId = m_currentTask;
00138                 taskDesc.numPages = m_currentPage+1;
00139                 taskDesc.numOnLastPage = m_currentPageEntry;
00140         }
00141 
00142 
00143 
00144         m_threadInterface->sendRequest(CMD_GATHER_AND_PROCESS_PAIRLIST, (ppu_address_t) &taskDesc,m_currentTask);
00145 
00146         // if all tasks busy, wait for spu event to clear the task.
00147         
00148 
00149         if (m_numBusyTasks >= m_maxNumOutstandingTasks)
00150         {
00151                 unsigned int taskId;
00152                 unsigned int outputSize;
00153 
00154                 
00155                 for (int i=0;i<int (m_maxNumOutstandingTasks);i++)
00156                   {
00157                           if (m_taskBusy[i])
00158                           {
00159                                   taskId = i;
00160                                   break;
00161                           }
00162                   }
00163 
00164           btAssert(taskId>=0);
00165 
00166           
00167                 m_threadInterface->waitForResponse(&taskId, &outputSize);
00168 
00169 //              printf("issueTask taskId %d completed, numBusy=%d\n",taskId,m_numBusyTasks);
00170 
00171                 //printf("PPU: after issue, received event: %u %d\n", taskId, outputSize);
00172 
00173                 //postProcess(taskId, outputSize);
00174 
00175                 m_taskBusy[taskId] = false;
00176 
00177                 m_numBusyTasks--;
00178         }
00179         
00180 }
00181 
00182 void SpuCollisionTaskProcess::addWorkToTask(void* pairArrayPtr,int startIndex,int endIndex)
00183 {
00184 #ifdef DEBUG_SPU_TASK_SCHEDULING
00185         printf("#");
00186 #endif //DEBUG_SPU_TASK_SCHEDULING
00187         
00188 #ifdef DEBUG_SpuCollisionTaskProcess
00189         btAssert(m_initialized);
00190         btAssert(m_workUnitTaskBuffers);
00191 
00192 #endif
00193 
00194         bool batch = true;
00195 
00196         if (batch)
00197         {
00198                 if (m_currentPageEntry == MIDPHASE_NUM_WORKUNITS_PER_PAGE)
00199                 {
00200                         if (m_currentPage == MIDPHASE_NUM_WORKUNIT_PAGES-1)
00201                         {
00202                                 // task buffer is full, issue current task.
00203                                 // if all task buffers busy, this waits until SPU is done.
00204                                 issueTask2();
00205 
00206                                 // find new task buffer
00207                                 for (unsigned int i = 0; i < m_maxNumOutstandingTasks; i++)
00208                                 {
00209                                         if (!m_taskBusy[i])
00210                                         {
00211                                                 m_currentTask = i;
00212                                                 //init the task data
00213 
00214                                                 break;
00215                                         }
00216                                 }
00217 
00218                                 m_currentPage = 0;
00219                         }
00220                         else
00221                         {
00222                                 m_currentPage++;
00223                         }
00224 
00225                         m_currentPageEntry = 0;
00226                 }
00227         }
00228 
00229         {
00230 
00231 
00232 
00233                 SpuGatherAndProcessWorkUnitInput &wuInput = 
00234                         *(reinterpret_cast<SpuGatherAndProcessWorkUnitInput*>
00235                         (MIDPHASE_ENTRY_PTR(m_currentTask, m_currentPage, m_currentPageEntry)));
00236                 
00237                 wuInput.m_pairArrayPtr = reinterpret_cast<uint64_t>(pairArrayPtr);
00238                 wuInput.m_startIndex = startIndex;
00239                 wuInput.m_endIndex = endIndex;
00240 
00241                 
00242         
00243                 m_currentPageEntry++;
00244 
00245                 if (!batch)
00246                 {
00247                         issueTask2();
00248 
00249                         // find new task buffer
00250                         for (unsigned int i = 0; i < m_maxNumOutstandingTasks; i++)
00251                         {
00252                                 if (!m_taskBusy[i])
00253                                 {
00254                                         m_currentTask = i;
00255                                         //init the task data
00256 
00257                                         break;
00258                                 }
00259                         }
00260 
00261                         m_currentPage = 0;
00262                         m_currentPageEntry =0;
00263                 }
00264         }
00265 }
00266 
00267 
00268 void 
00269 SpuCollisionTaskProcess::flush2()
00270 {
00271 #ifdef DEBUG_SPU_TASK_SCHEDULING
00272         printf("\nSpuCollisionTaskProcess::flush()\n");
00273 #endif //DEBUG_SPU_TASK_SCHEDULING
00274         
00275         // if there's a partially filled task buffer, submit that task
00276         if (m_currentPage > 0 || m_currentPageEntry > 0)
00277         {
00278                 issueTask2();
00279         }
00280 
00281 
00282         // all tasks are issued, wait for all tasks to be complete
00283         while(m_numBusyTasks > 0)
00284         {
00285           // Consolidating SPU code
00286           unsigned int taskId=-1;
00287           unsigned int outputSize;
00288           
00289           for (int i=0;i<int (m_maxNumOutstandingTasks);i++)
00290           {
00291                   if (m_taskBusy[i])
00292                   {
00293                           taskId = i;
00294                           break;
00295                   }
00296           }
00297 
00298           btAssert(taskId>=0);
00299 
00300         
00301           {
00302                         
00303                 // SPURS support.
00304                   m_threadInterface->waitForResponse(&taskId, &outputSize);
00305           }
00306 //               printf("flush2 taskId %d completed, numBusy =%d \n",taskId,m_numBusyTasks);
00307                 //printf("PPU: flushing, received event: %u %d\n", taskId, outputSize);
00308 
00309                 //postProcess(taskId, outputSize);
00310 
00311                 m_taskBusy[taskId] = false;
00312 
00313                 m_numBusyTasks--;
00314         }
00315 
00316 
00317 }