Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/physics/src/bullet/BulletMultiThreaded/SpuLibspe2Support.cpp @ 1967

Last change on this file since 1967 was 1966, checked in by rgrieder, 16 years ago

Let's go for multithreaded physics!

  • Property svn:eol-style set to native
File size: 6.1 KB
Line 
1/*
2Bullet Continuous Collision Detection and Physics Library
3Copyright (c) 2003-2007 Erwin Coumans  http://bulletphysics.com
4
5This software is provided 'as-is', without any express or implied warranty.
6In no event will the authors be held liable for any damages arising from the use of this software.
7Permission is granted to anyone to use this software for any purpose,
8including commercial applications, and to alter it and redistribute it freely,
9subject to the following restrictions:
10
111. 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.
122. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
133. This notice may not be removed or altered from any source distribution.
14*/
15
16#ifdef USE_LIBSPE2
17
18#include "SpuLibspe2Support.h"
19
20
21
22
23//SpuLibspe2Support helps to initialize/shutdown libspe2, start/stop SPU tasks and communication
24///Setup and initialize SPU/CELL/Libspe2
25SpuLibspe2Support::SpuLibspe2Support(spe_program_handle_t *speprog, int numThreads)
26{
27        this->program = speprog;
28        this->numThreads =  ((numThreads <= spe_cpu_info_get(SPE_COUNT_PHYSICAL_SPES, -1)) ? numThreads : spe_cpu_info_get(SPE_COUNT_PHYSICAL_SPES, -1));
29}
30
31///cleanup/shutdown Libspe2
32SpuLibspe2Support::~SpuLibspe2Support()
33{
34       
35        stopSPU();
36}
37
38
39
40///send messages to SPUs
41void SpuLibspe2Support::sendRequest(uint32_t uiCommand, uint32_t uiArgument0, uint32_t uiArgument1)
42{
43        spe_context_ptr_t context;
44       
45        switch (uiCommand)
46        {
47        case CMD_SAMPLE_TASK_COMMAND:
48        {
49                //get taskdescription
50                SpuSampleTaskDesc* taskDesc = (SpuSampleTaskDesc*) uiArgument0;
51
52                btAssert(taskDesc->m_taskId<m_activeSpuStatus.size());
53
54                //get status of SPU on which task should run
55                btSpuStatus&    spuStatus = m_activeSpuStatus[taskDesc->m_taskId];
56
57                //set data for spuStatus
58                spuStatus.m_commandId = uiCommand;
59                spuStatus.m_status = Spu_Status_Occupied; //set SPU as "occupied"
60                spuStatus.m_taskDesc.p = taskDesc; 
61               
62                //get context
63                context = data[taskDesc->m_taskId].context;
64               
65               
66                taskDesc->m_mainMemoryPtr = reinterpret_cast<uint64_t> (spuStatus.m_lsMemory.p);
67               
68
69                break;
70        }
71        case CMD_GATHER_AND_PROCESS_PAIRLIST:
72                {
73                        //get taskdescription
74                        SpuGatherAndProcessPairsTaskDesc* taskDesc = (SpuGatherAndProcessPairsTaskDesc*) uiArgument0;
75
76                        btAssert(taskDesc->taskId<m_activeSpuStatus.size());
77
78                        //get status of SPU on which task should run
79                        btSpuStatus&    spuStatus = m_activeSpuStatus[taskDesc->taskId];
80
81                        //set data for spuStatus
82                        spuStatus.m_commandId = uiCommand;
83                        spuStatus.m_status = Spu_Status_Occupied; //set SPU as "occupied"
84                        spuStatus.m_taskDesc.p = taskDesc; 
85                       
86                        //get context
87                        context = data[taskDesc->taskId].context;
88                       
89                       
90                        taskDesc->m_lsMemory = (CollisionTask_LocalStoreMemory*)spuStatus.m_lsMemory.p;
91                       
92                        break;
93                }
94        default:
95                {
96                        ///not implemented
97                        btAssert(0);
98                }
99
100        };
101
102       
103        //write taskdescription in mailbox
104        unsigned int event = Spu_Mailbox_Event_Task;
105        spe_in_mbox_write(context, &event, 1, SPE_MBOX_ANY_NONBLOCKING);
106
107}
108
109///check for messages from SPUs
110void SpuLibspe2Support::waitForResponse(unsigned int *puiArgument0, unsigned int *puiArgument1)
111{
112        ///We should wait for (one of) the first tasks to finish (or other SPU messages), and report its response
113       
114        ///A possible response can be 'yes, SPU handled it', or 'no, please do a PPU fallback'
115       
116        btAssert(m_activeSpuStatus.size());
117
118       
119        int last = -1;
120       
121        //find an active spu/thread
122        while(last < 0)
123        {
124                for (int i=0;i<m_activeSpuStatus.size();i++)
125                {
126                        if ( m_activeSpuStatus[i].m_status == Spu_Status_Free)
127                        {
128                                last = i;
129                                break;
130                        }
131                }
132                if(last < 0)
133                        sched_yield();
134        }
135
136
137
138        btSpuStatus& spuStatus = m_activeSpuStatus[last];
139
140        ///need to find an active spu
141        btAssert(last>=0);
142
143       
144
145        *puiArgument0 = spuStatus.m_taskId;
146        *puiArgument1 = spuStatus.m_status;
147
148
149}
150
151
152void SpuLibspe2Support::startSPU()
153{
154        this->internal_startSPU();
155}
156
157
158
159///start the spus group (can be called at the beginning of each frame, to make sure that the right SPU program is loaded)
160void SpuLibspe2Support::internal_startSPU()
161{
162        m_activeSpuStatus.resize(numThreads);
163       
164       
165        for (int i=0; i < numThreads; i++)
166        {
167               
168                if(data[i].context == NULL) 
169                {
170                                       
171                         /* Create context */
172                        if ((data[i].context = spe_context_create(0, NULL)) == NULL)
173                        {
174                              perror ("Failed creating context");
175                          exit(1);
176                        }
177       
178                        /* Load program into context */
179                        if(spe_program_load(data[i].context, this->program))
180                        {
181                              perror ("Failed loading program");
182                          exit(1);
183                        }
184                       
185                        m_activeSpuStatus[i].m_status = Spu_Status_Startup; 
186                        m_activeSpuStatus[i].m_taskId = i; 
187                        m_activeSpuStatus[i].m_commandId = 0; 
188                        m_activeSpuStatus[i].m_lsMemory.p = NULL; 
189                       
190                       
191                        data[i].entry = SPE_DEFAULT_ENTRY;
192                        data[i].flags = 0;
193                        data[i].argp.p = &m_activeSpuStatus[i];
194                        data[i].envp.p = NULL;
195                       
196                    /* Create thread for each SPE context */
197                        if (pthread_create(&data[i].pthread, NULL, &ppu_pthread_function, &(data[i]) ))
198                        {
199                              perror ("Failed creating thread");
200                          exit(1);
201                        }
202                        /*
203                        else
204                        {
205                                printf("started thread %d\n",i);
206                        }*/
207                }               
208        }
209       
210       
211        for (int i=0; i < numThreads; i++)
212        {
213                if(data[i].context != NULL) 
214                {
215                        while( m_activeSpuStatus[i].m_status == Spu_Status_Startup)
216                        {
217                                // wait for spu to set up
218                                sched_yield();
219                        }
220                        printf("Spu %d is ready\n", i);
221                }
222        }
223}
224
225///tell the task scheduler we are done with the SPU tasks
226void SpuLibspe2Support::stopSPU()
227{
228        // wait for all threads to finish
229        int i;
230        for ( i = 0; i < this->numThreads; i++ ) 
231        { 
232               
233                unsigned int event = Spu_Mailbox_Event_Shutdown;
234                spe_context_ptr_t context = data[i].context;
235                spe_in_mbox_write(context, &event, 1, SPE_MBOX_ALL_BLOCKING);
236                pthread_join (data[i].pthread, NULL); 
237               
238        } 
239        // close SPE program
240        spe_image_close(program); 
241        // destroy SPE contexts
242        for ( i = 0; i < this->numThreads; i++ ) 
243        { 
244                if(data[i].context != NULL)
245                {
246                        spe_context_destroy (data[i].context);
247                }
248        } 
249       
250        m_activeSpuStatus.clear();
251       
252}
253
254
255
256#endif //USE_LIBSPE2
257
Note: See TracBrowser for help on using the repository browser.