== SoC Bullet - Bullet Upgrade to 2.76 ==
[blender.git] / extern / bullet2 / 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                                         m_workUnitTaskBuffers = (unsigned char *)btAlignedAlloc(MIDPHASE_WORKUNIT_TASK_SIZE*6, 128);
48         }
49         
50 }
51
52
53
54 SpuCollisionTaskProcess::SpuCollisionTaskProcess(class  btThreadSupportInterface*       threadInterface, unsigned int   maxNumOutstandingTasks)
55 :m_threadInterface(threadInterface),
56 m_maxNumOutstandingTasks(0)
57 {
58         m_workUnitTaskBuffers = (unsigned char *)0;
59         setNumTasks(maxNumOutstandingTasks);
60         m_numBusyTasks = 0;
61         m_currentTask = 0;
62         m_currentPage = 0;
63         m_currentPageEntry = 0;
64
65 #ifdef DEBUG_SpuCollisionTaskProcess
66         m_initialized = false;
67 #endif
68
69         m_threadInterface->startSPU();
70
71         //printf("sizeof vec_float4: %d\n", sizeof(vec_float4));
72         printf("sizeof SpuGatherAndProcessWorkUnitInput: %d\n", int(sizeof(SpuGatherAndProcessWorkUnitInput)));
73
74 }
75
76 SpuCollisionTaskProcess::~SpuCollisionTaskProcess()
77 {
78         
79         if (m_workUnitTaskBuffers != 0)
80         {
81                 btAlignedFree(m_workUnitTaskBuffers);
82                 m_workUnitTaskBuffers = 0;
83         }
84         
85
86
87         m_threadInterface->stopSPU();
88         
89 }
90
91
92
93 void SpuCollisionTaskProcess::initialize2(bool useEpa)
94 {
95
96 #ifdef DEBUG_SPU_TASK_SCHEDULING
97         printf("SpuCollisionTaskProcess::initialize()\n");
98 #endif //DEBUG_SPU_TASK_SCHEDULING
99         
100         for (int i = 0; i < int (m_maxNumOutstandingTasks); i++)
101         {
102                 m_taskBusy[i] = false;
103         }
104         m_numBusyTasks = 0;
105         m_currentTask = 0;
106         m_currentPage = 0;
107         m_currentPageEntry = 0;
108         m_useEpa = useEpa;
109
110 #ifdef DEBUG_SpuCollisionTaskProcess
111         m_initialized = true;
112         btAssert(MIDPHASE_NUM_WORKUNITS_PER_TASK*sizeof(SpuGatherAndProcessWorkUnitInput) <= MIDPHASE_WORKUNIT_TASK_SIZE);
113 #endif
114 }
115
116
117 void SpuCollisionTaskProcess::issueTask2()
118 {
119
120 #ifdef DEBUG_SPU_TASK_SCHEDULING
121         printf("SpuCollisionTaskProcess::issueTask (m_currentTask= %d\n)", m_currentTask);
122 #endif //DEBUG_SPU_TASK_SCHEDULING
123
124         m_taskBusy[m_currentTask] = true;
125         m_numBusyTasks++;
126
127
128         SpuGatherAndProcessPairsTaskDesc& taskDesc = m_spuGatherTaskDesc[m_currentTask];
129         taskDesc.m_useEpa = m_useEpa;
130
131         {
132                 // send task description in event message
133                 // no error checking here...
134                 // but, currently, event queue can be no larger than NUM_WORKUNIT_TASKS.
135         
136                 taskDesc.m_inPairPtr = reinterpret_cast<uint64_t>(MIDPHASE_TASK_PTR(m_currentTask));
137         
138                 taskDesc.taskId = m_currentTask;
139                 taskDesc.numPages = m_currentPage+1;
140                 taskDesc.numOnLastPage = m_currentPageEntry;
141         }
142
143
144
145         m_threadInterface->sendRequest(CMD_GATHER_AND_PROCESS_PAIRLIST, (ppu_address_t) &taskDesc,m_currentTask);
146
147         // if all tasks busy, wait for spu event to clear the task.
148         
149
150         if (m_numBusyTasks >= m_maxNumOutstandingTasks)
151         {
152                 unsigned int taskId;
153                 unsigned int outputSize;
154
155                 
156                 for (int i=0;i<int (m_maxNumOutstandingTasks);i++)
157                   {
158                           if (m_taskBusy[i])
159                           {
160                                   taskId = i;
161                                   break;
162                           }
163                   }
164
165           btAssert(taskId>=0);
166
167           
168                 m_threadInterface->waitForResponse(&taskId, &outputSize);
169
170 //              printf("issueTask taskId %d completed, numBusy=%d\n",taskId,m_numBusyTasks);
171
172                 //printf("PPU: after issue, received event: %u %d\n", taskId, outputSize);
173
174                 //postProcess(taskId, outputSize);
175
176                 m_taskBusy[taskId] = false;
177
178                 m_numBusyTasks--;
179         }
180         
181 }
182
183 void SpuCollisionTaskProcess::addWorkToTask(void* pairArrayPtr,int startIndex,int endIndex)
184 {
185 #ifdef DEBUG_SPU_TASK_SCHEDULING
186         printf("#");
187 #endif //DEBUG_SPU_TASK_SCHEDULING
188         
189 #ifdef DEBUG_SpuCollisionTaskProcess
190         btAssert(m_initialized);
191         btAssert(m_workUnitTaskBuffers);
192
193 #endif
194
195         bool batch = true;
196
197         if (batch)
198         {
199                 if (m_currentPageEntry == MIDPHASE_NUM_WORKUNITS_PER_PAGE)
200                 {
201                         if (m_currentPage == MIDPHASE_NUM_WORKUNIT_PAGES-1)
202                         {
203                                 // task buffer is full, issue current task.
204                                 // if all task buffers busy, this waits until SPU is done.
205                                 issueTask2();
206
207                                 // find new task buffer
208                                 for (unsigned int i = 0; i < m_maxNumOutstandingTasks; i++)
209                                 {
210                                         if (!m_taskBusy[i])
211                                         {
212                                                 m_currentTask = i;
213                                                 //init the task data
214
215                                                 break;
216                                         }
217                                 }
218
219                                 m_currentPage = 0;
220                         }
221                         else
222                         {
223                                 m_currentPage++;
224                         }
225
226                         m_currentPageEntry = 0;
227                 }
228         }
229
230         {
231
232
233
234                 SpuGatherAndProcessWorkUnitInput &wuInput = 
235                         *(reinterpret_cast<SpuGatherAndProcessWorkUnitInput*>
236                         (MIDPHASE_ENTRY_PTR(m_currentTask, m_currentPage, m_currentPageEntry)));
237                 
238                 wuInput.m_pairArrayPtr = reinterpret_cast<uint64_t>(pairArrayPtr);
239                 wuInput.m_startIndex = startIndex;
240                 wuInput.m_endIndex = endIndex;
241
242                 
243         
244                 m_currentPageEntry++;
245
246                 if (!batch)
247                 {
248                         issueTask2();
249
250                         // find new task buffer
251                         for (unsigned int i = 0; i < m_maxNumOutstandingTasks; i++)
252                         {
253                                 if (!m_taskBusy[i])
254                                 {
255                                         m_currentTask = i;
256                                         //init the task data
257
258                                         break;
259                                 }
260                         }
261
262                         m_currentPage = 0;
263                         m_currentPageEntry =0;
264                 }
265         }
266 }
267
268
269 void 
270 SpuCollisionTaskProcess::flush2()
271 {
272 #ifdef DEBUG_SPU_TASK_SCHEDULING
273         printf("\nSpuCollisionTaskProcess::flush()\n");
274 #endif //DEBUG_SPU_TASK_SCHEDULING
275         
276         // if there's a partially filled task buffer, submit that task
277         if (m_currentPage > 0 || m_currentPageEntry > 0)
278         {
279                 issueTask2();
280         }
281
282
283         // all tasks are issued, wait for all tasks to be complete
284         while(m_numBusyTasks > 0)
285         {
286           // Consolidating SPU code
287           unsigned int taskId=-1;
288           unsigned int outputSize;
289           
290           for (int i=0;i<int (m_maxNumOutstandingTasks);i++)
291           {
292                   if (m_taskBusy[i])
293                   {
294                           taskId = i;
295                           break;
296                   }
297           }
298
299           btAssert(taskId>=0);
300
301         
302           {
303                         
304                 // SPURS support.
305                   m_threadInterface->waitForResponse(&taskId, &outputSize);
306           }
307 //               printf("flush2 taskId %d completed, numBusy =%d \n",taskId,m_numBusyTasks);
308                 //printf("PPU: flushing, received event: %u %d\n", taskId, outputSize);
309
310                 //postProcess(taskId, outputSize);
311
312                 m_taskBusy[taskId] = false;
313
314                 m_numBusyTasks--;
315         }
316
317
318 }