== SoC Bullet - Bullet Upgrade to 2.76 ==
[blender.git] / extern / bullet2 / BulletMultiThreaded / Win32ThreadSupport.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 #include "Win32ThreadSupport.h"
17
18 #ifdef USE_WIN32_THREADING
19
20 #include <windows.h>
21
22 #include "SpuCollisionTaskProcess.h"
23
24 #include "SpuNarrowPhaseCollisionTask/SpuGatheringCollisionTask.h"
25
26
27
28 ///The number of threads should be equal to the number of available cores
29 ///@todo: each worker should be linked to a single core, using SetThreadIdealProcessor.
30
31 ///Win32ThreadSupport helps to initialize/shutdown libspe2, start/stop SPU tasks and communication
32 ///Setup and initialize SPU/CELL/Libspe2
33 Win32ThreadSupport::Win32ThreadSupport(const Win32ThreadConstructionInfo & threadConstructionInfo)
34 {
35         m_maxNumTasks = threadConstructionInfo.m_numThreads;
36         startThreads(threadConstructionInfo);
37 }
38
39 ///cleanup/shutdown Libspe2
40 Win32ThreadSupport::~Win32ThreadSupport()
41 {
42         stopSPU();
43 }
44
45
46
47
48 #include <stdio.h>
49
50 DWORD WINAPI Thread_no_1( LPVOID lpParam ) 
51 {
52
53         Win32ThreadSupport::btSpuStatus* status = (Win32ThreadSupport::btSpuStatus*)lpParam;
54
55         
56         while (1)
57         {
58                 WaitForSingleObject(status->m_eventStartHandle,INFINITE);
59                 
60                 void* userPtr = status->m_userPtr;
61
62                 if (userPtr)
63                 {
64                         btAssert(status->m_status);
65                         status->m_userThreadFunc(userPtr,status->m_lsMemory);
66                         status->m_status = 2;
67                         SetEvent(status->m_eventCompletetHandle);
68                 } else
69                 {
70                         //exit Thread
71                         status->m_status = 3;
72                         SetEvent(status->m_eventCompletetHandle);
73                         printf("Thread with taskId %i with handle %p exiting\n",status->m_taskId, status->m_threadHandle);
74                         break;
75                 }
76                 
77         }
78
79         printf("Thread TERMINATED\n");
80         return 0;
81
82 }
83
84 ///send messages to SPUs
85 void Win32ThreadSupport::sendRequest(uint32_t uiCommand, ppu_address_t uiArgument0, uint32_t taskId)
86 {
87         ///     gMidphaseSPU.sendRequest(CMD_GATHER_AND_PROCESS_PAIRLIST, (ppu_address_t) &taskDesc);
88         
89         ///we should spawn an SPU task here, and in 'waitForResponse' it should wait for response of the (one of) the first tasks that finished
90         
91
92
93         switch (uiCommand)
94         {
95         case    CMD_GATHER_AND_PROCESS_PAIRLIST:
96                 {
97
98
99 //#define SINGLE_THREADED 1
100 #ifdef SINGLE_THREADED
101
102                         btSpuStatus&    spuStatus = m_activeSpuStatus[0];
103                         spuStatus.m_userPtr=(void*)uiArgument0;
104                         spuStatus.m_userThreadFunc(spuStatus.m_userPtr,spuStatus.m_lsMemory);
105                         HANDLE handle =0;
106 #else
107
108
109                         btSpuStatus&    spuStatus = m_activeSpuStatus[taskId];
110                         btAssert(taskId>=0);
111                         btAssert(int(taskId)<m_activeSpuStatus.size());
112
113                         spuStatus.m_commandId = uiCommand;
114                         spuStatus.m_status = 1;
115                         spuStatus.m_userPtr = (void*)uiArgument0;
116
117                         ///fire event to start new task
118                         SetEvent(spuStatus.m_eventStartHandle);
119
120 #endif //CollisionTask_LocalStoreMemory
121
122                         
123
124                         break;
125                 }
126         default:
127                 {
128                         ///not implemented
129                         btAssert(0);
130                 }
131
132         };
133
134
135 }
136
137
138 ///check for messages from SPUs
139 void Win32ThreadSupport::waitForResponse(unsigned int *puiArgument0, unsigned int *puiArgument1)
140 {
141         ///We should wait for (one of) the first tasks to finish (or other SPU messages), and report its response
142         
143         ///A possible response can be 'yes, SPU handled it', or 'no, please do a PPU fallback'
144
145
146         btAssert(m_activeSpuStatus.size());
147
148         int last = -1;
149 #ifndef SINGLE_THREADED
150         DWORD res = WaitForMultipleObjects(m_completeHandles.size(), &m_completeHandles[0], FALSE, INFINITE);
151         btAssert(res != WAIT_FAILED);
152         last = res - WAIT_OBJECT_0;
153
154         btSpuStatus& spuStatus = m_activeSpuStatus[last];
155         btAssert(spuStatus.m_threadHandle);
156         btAssert(spuStatus.m_eventCompletetHandle);
157
158         //WaitForSingleObject(spuStatus.m_eventCompletetHandle, INFINITE);
159         btAssert(spuStatus.m_status > 1);
160         spuStatus.m_status = 0;
161
162         ///need to find an active spu
163         btAssert(last>=0);
164
165 #else
166         last=0;
167         btSpuStatus& spuStatus = m_activeSpuStatus[last];
168 #endif //SINGLE_THREADED
169
170         
171
172         *puiArgument0 = spuStatus.m_taskId;
173         *puiArgument1 = spuStatus.m_status;
174
175
176 }
177
178
179
180 void Win32ThreadSupport::startThreads(const Win32ThreadConstructionInfo& threadConstructionInfo)
181 {
182
183         m_activeSpuStatus.resize(threadConstructionInfo.m_numThreads);
184         m_completeHandles.resize(threadConstructionInfo.m_numThreads);
185
186         m_maxNumTasks = threadConstructionInfo.m_numThreads;
187
188         for (int i=0;i<threadConstructionInfo.m_numThreads;i++)
189         {
190                 printf("starting thread %d\n",i);
191
192                 btSpuStatus&    spuStatus = m_activeSpuStatus[i];
193
194                 LPSECURITY_ATTRIBUTES lpThreadAttributes=NULL;
195                 SIZE_T dwStackSize=threadConstructionInfo.m_threadStackSize;
196                 LPTHREAD_START_ROUTINE lpStartAddress=&Thread_no_1;
197                 LPVOID lpParameter=&spuStatus;
198                 DWORD dwCreationFlags=0;
199                 LPDWORD lpThreadId=0;
200
201                 spuStatus.m_userPtr=0;
202
203                 sprintf(spuStatus.m_eventStartHandleName,"eventStart%s%d",threadConstructionInfo.m_uniqueName,i);
204                 spuStatus.m_eventStartHandle = CreateEventA (0,false,false,spuStatus.m_eventStartHandleName);
205
206                 sprintf(spuStatus.m_eventCompletetHandleName,"eventComplete%s%d",threadConstructionInfo.m_uniqueName,i);
207                 spuStatus.m_eventCompletetHandle = CreateEventA (0,false,false,spuStatus.m_eventCompletetHandleName);
208
209                 m_completeHandles[i] = spuStatus.m_eventCompletetHandle;
210
211                 HANDLE handle = CreateThread(lpThreadAttributes,dwStackSize,lpStartAddress,lpParameter, dwCreationFlags,lpThreadId);
212                 SetThreadPriority(handle,THREAD_PRIORITY_HIGHEST);
213                 //SetThreadPriority(handle,THREAD_PRIORITY_TIME_CRITICAL);
214
215                 SetThreadAffinityMask(handle, 1<<i);
216
217                 spuStatus.m_taskId = i;
218                 spuStatus.m_commandId = 0;
219                 spuStatus.m_status = 0;
220                 spuStatus.m_threadHandle = handle;
221                 spuStatus.m_lsMemory = threadConstructionInfo.m_lsMemoryFunc();
222                 spuStatus.m_userThreadFunc = threadConstructionInfo.m_userThreadFunc;
223
224                 printf("started thread %d with threadHandle %p\n",i,handle);
225                 
226         }
227
228 }
229
230 void Win32ThreadSupport::startSPU()
231 {
232 }
233
234
235 ///tell the task scheduler we are done with the SPU tasks
236 void Win32ThreadSupport::stopSPU()
237 {
238         int i;
239         for (i=0;i<m_activeSpuStatus.size();i++)
240         {
241                 btSpuStatus& spuStatus = m_activeSpuStatus[i];
242                 if (spuStatus.m_status>0)
243                 {
244                         WaitForSingleObject(spuStatus.m_eventCompletetHandle, INFINITE);
245                 }
246                 
247
248                 spuStatus.m_userPtr = 0;
249                 SetEvent(spuStatus.m_eventStartHandle);
250                 WaitForSingleObject(spuStatus.m_eventCompletetHandle, INFINITE);
251
252                 CloseHandle(spuStatus.m_eventCompletetHandle);
253                 CloseHandle(spuStatus.m_eventStartHandle);
254                 CloseHandle(spuStatus.m_threadHandle);
255         }
256
257         m_activeSpuStatus.clear();
258         m_completeHandles.clear();
259
260 }
261
262 #endif //USE_WIN32_THREADING