Imported Upstream version 2.81
[platform/upstream/libbullet.git] / src / BulletMultiThreaded / SpuCollisionTaskProcess.cpp
1 /*
2 Bullet Continuous Collision Detection and Physics Library
3 Copyright (c) 2003-2007 Erwin Coumans  http://bulletphysics.com
4
5 This software is provided 'as-is', without any express or implied warranty.
6 In no event will the authors be held liable for any damages arising from the use of this software.
7 Permission is granted to anyone to use this software for any purpose, 
8 including commercial applications, and to alter it and redistribute it freely, 
9 subject to the following restrictions:
10
11 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.
12 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
13 3. This notice may not be removed or altered from any source distribution.
14 */
15
16
17 //#define DEBUG_SPU_TASK_SCHEDULING 1
18
19
20 //class OptimizedBvhNode;
21
22 #include "SpuCollisionTaskProcess.h"
23
24
25
26
27 void    SpuCollisionTaskProcess::setNumTasks(int maxNumTasks)
28 {
29         if (int(m_maxNumOutstandingTasks) != maxNumTasks)
30         {
31                 m_maxNumOutstandingTasks = maxNumTasks;
32                 m_taskBusy.resize(m_maxNumOutstandingTasks);
33                 m_spuGatherTaskDesc.resize(m_maxNumOutstandingTasks);
34
35                 for (int i = 0; i < m_taskBusy.size(); i++)
36                 {
37                         m_taskBusy[i] = false;
38                 }
39
40                 ///re-allocate task memory buffers
41                 if (m_workUnitTaskBuffers != 0)
42                 {
43                         btAlignedFree(m_workUnitTaskBuffers);
44                 }
45                 
46                 m_workUnitTaskBuffers = (unsigned char *)btAlignedAlloc(MIDPHASE_WORKUNIT_TASK_SIZE*m_maxNumOutstandingTasks, 128);
47         }
48         
49 }
50
51
52
53 SpuCollisionTaskProcess::SpuCollisionTaskProcess(class  btThreadSupportInterface*       threadInterface, unsigned int   maxNumOutstandingTasks)
54 :m_threadInterface(threadInterface),
55 m_maxNumOutstandingTasks(0)
56 {
57         m_workUnitTaskBuffers = (unsigned char *)0;
58         setNumTasks(maxNumOutstandingTasks);
59         m_numBusyTasks = 0;
60         m_currentTask = 0;
61         m_currentPage = 0;
62         m_currentPageEntry = 0;
63
64 #ifdef DEBUG_SpuCollisionTaskProcess
65         m_initialized = false;
66 #endif
67
68         m_threadInterface->startSPU();
69
70         //printf("sizeof vec_float4: %d\n", sizeof(vec_float4));
71         printf("sizeof SpuGatherAndProcessWorkUnitInput: %d\n", int(sizeof(SpuGatherAndProcessWorkUnitInput)));
72
73 }
74
75 SpuCollisionTaskProcess::~SpuCollisionTaskProcess()
76 {
77         
78         if (m_workUnitTaskBuffers != 0)
79         {
80                 btAlignedFree(m_workUnitTaskBuffers);
81                 m_workUnitTaskBuffers = 0;
82         }
83         
84
85
86         m_threadInterface->stopSPU();
87         
88 }
89
90
91
92 void SpuCollisionTaskProcess::initialize2(bool useEpa)
93 {
94
95 #ifdef DEBUG_SPU_TASK_SCHEDULING
96         printf("SpuCollisionTaskProcess::initialize()\n");
97 #endif //DEBUG_SPU_TASK_SCHEDULING
98         
99         for (int i = 0; i < int (m_maxNumOutstandingTasks); i++)
100         {
101                 m_taskBusy[i] = false;
102         }
103         m_numBusyTasks = 0;
104         m_currentTask = 0;
105         m_currentPage = 0;
106         m_currentPageEntry = 0;
107         m_useEpa = useEpa;
108
109 #ifdef DEBUG_SpuCollisionTaskProcess
110         m_initialized = true;
111         btAssert(MIDPHASE_NUM_WORKUNITS_PER_TASK*sizeof(SpuGatherAndProcessWorkUnitInput) <= MIDPHASE_WORKUNIT_TASK_SIZE);
112 #endif
113 }
114
115
116 void SpuCollisionTaskProcess::issueTask2()
117 {
118
119 #ifdef DEBUG_SPU_TASK_SCHEDULING
120         printf("SpuCollisionTaskProcess::issueTask (m_currentTask= %d\n)", m_currentTask);
121 #endif //DEBUG_SPU_TASK_SCHEDULING
122
123         m_taskBusy[m_currentTask] = true;
124         m_numBusyTasks++;
125
126
127         SpuGatherAndProcessPairsTaskDesc& taskDesc = m_spuGatherTaskDesc[m_currentTask];
128         taskDesc.m_useEpa = m_useEpa;
129
130         {
131                 // send task description in event message
132                 // no error checking here...
133                 // but, currently, event queue can be no larger than NUM_WORKUNIT_TASKS.
134         
135                 taskDesc.m_inPairPtr = reinterpret_cast<uint64_t>(MIDPHASE_TASK_PTR(m_currentTask));
136         
137                 taskDesc.taskId = m_currentTask;
138                 taskDesc.numPages = m_currentPage+1;
139                 taskDesc.numOnLastPage = m_currentPageEntry;
140         }
141
142
143
144         m_threadInterface->sendRequest(CMD_GATHER_AND_PROCESS_PAIRLIST, (ppu_address_t) &taskDesc,m_currentTask);
145
146         // if all tasks busy, wait for spu event to clear the task.
147         
148
149         if (m_numBusyTasks >= m_maxNumOutstandingTasks)
150         {
151                 unsigned int taskId;
152                 unsigned int outputSize;
153
154                 
155                 for (int i=0;i<int (m_maxNumOutstandingTasks);i++)
156                   {
157                           if (m_taskBusy[i])
158                           {
159                                   taskId = i;
160                                   break;
161                           }
162                   }
163
164           btAssert(taskId>=0);
165
166           
167                 m_threadInterface->waitForResponse(&taskId, &outputSize);
168
169 //              printf("issueTask taskId %d completed, numBusy=%d\n",taskId,m_numBusyTasks);
170
171                 //printf("PPU: after issue, received event: %u %d\n", taskId, outputSize);
172
173                 //postProcess(taskId, outputSize);
174
175                 m_taskBusy[taskId] = false;
176
177                 m_numBusyTasks--;
178         }
179         
180 }
181
182 void SpuCollisionTaskProcess::addWorkToTask(void* pairArrayPtr,int startIndex,int endIndex)
183 {
184 #ifdef DEBUG_SPU_TASK_SCHEDULING
185         printf("#");
186 #endif //DEBUG_SPU_TASK_SCHEDULING
187         
188 #ifdef DEBUG_SpuCollisionTaskProcess
189         btAssert(m_initialized);
190         btAssert(m_workUnitTaskBuffers);
191
192 #endif
193
194         bool batch = true;
195
196         if (batch)
197         {
198                 if (m_currentPageEntry == MIDPHASE_NUM_WORKUNITS_PER_PAGE)
199                 {
200                         if (m_currentPage == MIDPHASE_NUM_WORKUNIT_PAGES-1)
201                         {
202                                 // task buffer is full, issue current task.
203                                 // if all task buffers busy, this waits until SPU is done.
204                                 issueTask2();
205
206                                 // find new task buffer
207                                 for (unsigned int i = 0; i < m_maxNumOutstandingTasks; i++)
208                                 {
209                                         if (!m_taskBusy[i])
210                                         {
211                                                 m_currentTask = i;
212                                                 //init the task data
213
214                                                 break;
215                                         }
216                                 }
217
218                                 m_currentPage = 0;
219                         }
220                         else
221                         {
222                                 m_currentPage++;
223                         }
224
225                         m_currentPageEntry = 0;
226                 }
227         }
228
229         {
230
231
232
233                 SpuGatherAndProcessWorkUnitInput &wuInput = 
234                         *(reinterpret_cast<SpuGatherAndProcessWorkUnitInput*>
235                         (MIDPHASE_ENTRY_PTR(m_currentTask, m_currentPage, m_currentPageEntry)));
236                 
237                 wuInput.m_pairArrayPtr = reinterpret_cast<uint64_t>(pairArrayPtr);
238                 wuInput.m_startIndex = startIndex;
239                 wuInput.m_endIndex = endIndex;
240
241                 
242         
243                 m_currentPageEntry++;
244
245                 if (!batch)
246                 {
247                         issueTask2();
248
249                         // find new task buffer
250                         for (unsigned int i = 0; i < m_maxNumOutstandingTasks; i++)
251                         {
252                                 if (!m_taskBusy[i])
253                                 {
254                                         m_currentTask = i;
255                                         //init the task data
256
257                                         break;
258                                 }
259                         }
260
261                         m_currentPage = 0;
262                         m_currentPageEntry =0;
263                 }
264         }
265 }
266
267
268 void 
269 SpuCollisionTaskProcess::flush2()
270 {
271 #ifdef DEBUG_SPU_TASK_SCHEDULING
272         printf("\nSpuCollisionTaskProcess::flush()\n");
273 #endif //DEBUG_SPU_TASK_SCHEDULING
274         
275         // if there's a partially filled task buffer, submit that task
276         if (m_currentPage > 0 || m_currentPageEntry > 0)
277         {
278                 issueTask2();
279         }
280
281
282         // all tasks are issued, wait for all tasks to be complete
283         while(m_numBusyTasks > 0)
284         {
285           // Consolidating SPU code
286           unsigned int taskId=-1;
287           unsigned int outputSize;
288           
289           for (int i=0;i<int (m_maxNumOutstandingTasks);i++)
290           {
291                   if (m_taskBusy[i])
292                   {
293                           taskId = i;
294                           break;
295                   }
296           }
297
298           btAssert(taskId>=0);
299
300         
301           {
302                         
303                 // SPURS support.
304                   m_threadInterface->waitForResponse(&taskId, &outputSize);
305           }
306 //               printf("flush2 taskId %d completed, numBusy =%d \n",taskId,m_numBusyTasks);
307                 //printf("PPU: flushing, received event: %u %d\n", taskId, outputSize);
308
309                 //postProcess(taskId, outputSize);
310
311                 m_taskBusy[taskId] = false;
312
313                 m_numBusyTasks--;
314         }
315
316
317 }