cc68a136 |
1 | /*******************************************************************\r |
2 | *\r |
3 | * File: Engine.cpp\r |
4 | *\r |
5 | * Author: Peter van Sebille (peter@yipton.net)\r |
6 | *\r |
7 | * Modified/adapted for picodriveN by notaz, 2006\r |
8 | *\r |
9 | * (c) Copyright 2006, notaz\r |
10 | * (c) Copyright 2002, Peter van Sebille\r |
11 | * All Rights Reserved\r |
12 | *\r |
13 | *******************************************************************/\r |
14 | \r |
15 | \r |
16 | #include "Engine.h"\r |
17 | #include <w32std.h>\r |
18 | #include <eikenv.h>\r |
19 | #include <e32svr.h>\r |
20 | #include <e32math.h>\r |
21 | #include <e32uid.h>\r |
22 | \r |
23 | #include <string.h>\r |
24 | \r |
25 | #include "version.h"\r |
ca482e5d |
26 | #include <Pico/PicoInt.h>\r |
27 | #include "../common/emu.h"\r |
cc68a136 |
28 | #include "engine/debug.h"\r |
ca482e5d |
29 | #include "App.h"\r |
cc68a136 |
30 | \r |
31 | // this is where we start to break a bunch of symbian rules\r |
32 | extern TInt machineUid;\r |
33 | extern int gamestate, gamestate_next;\r |
ca482e5d |
34 | extern char *loadrom_fname;\r |
35 | extern int loadrom_result;\r |
cc68a136 |
36 | extern const char *actionNames[];\r |
cc68a136 |
37 | RSemaphore initSemaphore;\r |
ca482e5d |
38 | RSemaphore pauseSemaphore;\r |
39 | RSemaphore loadWaitSemaphore;\r |
cc68a136 |
40 | int pico_was_reset = 0;\r |
cc68a136 |
41 | static CPicolAppView *appView = 0;\r |
42 | \r |
43 | \r |
44 | TInt CPicoGameSession::Do(const TPicoServRqst what, TAny *param)\r |
45 | {\r |
ca482e5d |
46 | switch (what)\r |
47 | {\r |
cc68a136 |
48 | case PicoMsgLoadState: \r |
ca482e5d |
49 | if(!rom_loaded) return -1; // no ROM\r |
50 | return emu_SaveLoadGame(1, 0);\r |
cc68a136 |
51 | \r |
52 | case PicoMsgSaveState:\r |
ca482e5d |
53 | if(!rom_loaded) return -1;\r |
54 | return emu_SaveLoadGame(0, 0);\r |
cc68a136 |
55 | \r |
56 | case PicoMsgLoadROM:\r |
57 | return loadROM((TPtrC16 *)param);\r |
58 | \r |
59 | case PicoMsgResume:\r |
ca482e5d |
60 | DEBUGPRINT(_L("resume"));\r |
61 | if(rom_loaded) {\r |
cc68a136 |
62 | return ChangeRunState(PGS_Running);\r |
63 | }\r |
64 | return 1;\r |
65 | \r |
66 | case PicoMsgReset: \r |
ca482e5d |
67 | if(rom_loaded) {\r |
1cb1584b |
68 | PicoReset();\r |
cc68a136 |
69 | pico_was_reset = 1;\r |
70 | return ChangeRunState(PGS_Running);\r |
71 | }\r |
72 | return 1;\r |
73 | \r |
74 | case PicoMsgKeys:\r |
75 | return ChangeRunState(PGS_KeyConfig);\r |
76 | \r |
77 | case PicoMsgPause:\r |
78 | return ChangeRunState(PGS_Paused);\r |
79 | \r |
80 | case PicoMsgQuit:\r |
81 | DEBUGPRINT(_L("got quit msg."));\r |
82 | return ChangeRunState(PGS_Quit);\r |
83 | \r |
84 | // config change\r |
85 | case PicoMsgConfigChange:\r |
86 | return changeConfig((TPicoConfig *)param);\r |
87 | \r |
88 | case PicoMsgSetAppView:\r |
89 | appView = (CPicolAppView *)param;\r |
90 | return 1;\r |
91 | \r |
92 | default:\r |
93 | return 1;\r |
94 | }\r |
95 | }\r |
96 | \r |
97 | TInt EmuThreadFunction(TAny* anArg);\r |
98 | \r |
99 | TInt CPicoGameSession::StartEmuThread()\r |
100 | {\r |
101 | TInt res=KErrNone;\r |
102 | iEmuRunning = EFalse;\r |
103 | \r |
104 | if (initSemaphore.Handle() > 0)\r |
105 | initSemaphore.Close();\r |
106 | initSemaphore.CreateLocal(0);\r |
107 | if (pauseSemaphore.Handle() <= 0)\r |
108 | pauseSemaphore.CreateLocal(0);\r |
ca482e5d |
109 | if (loadWaitSemaphore.Handle() <= 0)\r |
110 | loadWaitSemaphore.CreateLocal(0);\r |
cc68a136 |
111 | \r |
112 | RThread thread;\r |
113 | if(iThreadWatcher && (res = thread.Open(iThreadWatcher->iTid)) == KErrNone) {\r |
114 | // should be a dead thread in some strange state.\r |
115 | DEBUGPRINT(_L("found thread with the same id (id=%i, RequestCount=%i), killing.."),\r |
116 | (TInt32)thread.Id(), thread.RequestCount());\r |
117 | // what can we do in this situation? Nothing seems to help, it just stays in this state.\r |
118 | delete iThreadWatcher;\r |
119 | iThreadWatcher = 0;\r |
120 | thread.Kill(1);\r |
121 | thread.Terminate(1);\r |
122 | thread.Close();\r |
123 | }\r |
124 | \r |
cc68a136 |
125 | res=thread.Create(_L("PicoEmuThread"), // create new server thread\r |
126 | EmuThreadFunction, // thread's main function\r |
127 | KDefaultStackSize,\r |
128 | KMinHeapSize,\r |
129 | KPicoMaxHeapSize,\r |
130 | 0 // &semaphore // passed as TAny* argument to thread function\r |
131 | );\r |
132 | \r |
133 | if(res == KErrNone) { // thread created ok - now start it going\r |
134 | thread.SetPriority(EPriorityMore);\r |
135 | iEmuRunning = ETrue;\r |
136 | if (iThreadWatcher) delete iThreadWatcher;\r |
137 | iThreadWatcher = CThreadWatcher::NewL(thread.Id());\r |
138 | thread.Resume(); // start it going\r |
139 | DEBUGPRINT(_L("initSemaphore.Wait()"));\r |
ca482e5d |
140 | res = initSemaphore.Wait(3*1000*1000); // wait until it's initialized\r |
cc68a136 |
141 | DEBUGPRINT(_L("initSemaphore resume, ExitReason() == %i"), thread.ExitReason());\r |
142 | res |= thread.ExitReason();\r |
143 | thread.Close(); // we're no longer interested in the other thread\r |
144 | if(res != KErrNone) iEmuRunning = EFalse;\r |
145 | return res;\r |
146 | }\r |
147 | \r |
148 | return res;\r |
149 | }\r |
150 | \r |
151 | TInt CPicoGameSession::ChangeRunState(TPicoGameState newstate, TPicoGameState newstate_next)\r |
152 | {\r |
153 | if (!iEmuRunning) {\r |
154 | gamestate = PGS_Paused;\r |
155 | TInt res = StartEmuThread();\r |
156 | if(res != KErrNone) DEBUGPRINT(_L("StartEmuThread() returned %i"), res);\r |
157 | if (!iEmuRunning) return PicoErrEmuThread;\r |
158 | }\r |
159 | \r |
160 | int oldstate = gamestate;\r |
161 | gamestate = newstate;\r |
162 | gamestate_next = newstate_next ? newstate_next : PGS_Paused;\r |
163 | if (oldstate == PGS_Paused) pauseSemaphore.Signal();\r |
164 | return 0;\r |
165 | }\r |
166 | \r |
167 | \r |
168 | TInt CPicoGameSession::loadROM(TPtrC16 *pptr)\r |
169 | {\r |
ca482e5d |
170 | TInt ret;\r |
171 | char buff[150];\r |
cc68a136 |
172 | \r |
ca482e5d |
173 | // make sure emu thread is ok\r |
174 | ret = ChangeRunState(PGS_Paused);\r |
175 | if(ret) return ret;\r |
cc68a136 |
176 | \r |
177 | // read the contents of the client pointer into a TPtr.\r |
178 | static TBuf8<KMaxFileName> writeBuf;\r |
179 | writeBuf.Copy(*pptr);\r |
180 | \r |
ca482e5d |
181 | // push the emu thead to a load state. This is done so that it owns all file handles.\r |
182 | // If successful, in will enter PGS_Running state by itself.\r |
183 | loadrom_fname = (char *)writeBuf.PtrZ();\r |
184 | loadrom_result = 0;\r |
185 | ret = ChangeRunState(PGS_ReloadRom);\r |
186 | if(ret) return ret;\r |
cc68a136 |
187 | \r |
ca482e5d |
188 | loadWaitSemaphore.Wait(20*1000*1000);\r |
cc68a136 |
189 | \r |
ca482e5d |
190 | if (loadrom_result == 0)\r |
cc68a136 |
191 | return PicoErrNotRom;\r |
cc68a136 |
192 | \r |
ca482e5d |
193 | emu_getGameName(buff);\r |
cc68a136 |
194 | TPtrC8 buff8((TUint8*) buff);\r |
195 | iRomInternalName.Copy(buff8);\r |
196 | \r |
ca482e5d |
197 | DEBUGPRINT(_L("done waiting for ROM load"));\r |
cc68a136 |
198 | \r |
199 | // debug\r |
200 | #ifdef __DEBUG_PRINT\r |
201 | TInt cells = User::CountAllocCells();\r |
202 | TInt mem;\r |
203 | User::AllocSize(mem);\r |
204 | DEBUGPRINT(_L("comm: cels=%d, size=%d KB"), cells, mem/1024);\r |
205 | ChangeRunState(PGS_DebugHeap, PGS_Running);\r |
cc68a136 |
206 | #endif\r |
207 | \r |
208 | return 0;\r |
209 | }\r |
210 | \r |
211 | \r |
212 | TInt CPicoGameSession::changeConfig(TPicoConfig *aConfig)\r |
213 | {\r |
cc68a136 |
214 | // 6 button pad, enable XYZM config if needed\r |
ca482e5d |
215 | if (PicoOpt & POPT_6BTN_PAD)\r |
216 | {\r |
cc68a136 |
217 | actionNames[8] = "Z";\r |
218 | actionNames[9] = "Y";\r |
219 | actionNames[10] = "X";\r |
220 | actionNames[11] = "MODE";\r |
221 | } else {\r |
222 | actionNames[8] = actionNames[9] = actionNames[10] = actionNames[11] = 0;\r |
223 | }\r |
224 | \r |
225 | // if we are in center 90||270 modes, we can bind renderer switcher\r |
ca482e5d |
226 | if (currentConfig.scaling == TPicoConfig::PMFit &&\r |
227 | (currentConfig.rotation == TPicoConfig::PRot0 || currentConfig.rotation == TPicoConfig::PRot180))\r |
228 | actionNames[25] = 0;\r |
229 | else actionNames[25] = "RENDERER";\r |
cc68a136 |
230 | \r |
231 | return 0;\r |
232 | }\r |
233 | \r |
234 | \r |
cc68a136 |
235 | #ifdef __DEBUG_PRINT_FILE\r |
236 | extern RMutex logMutex;\r |
237 | #endif\r |
238 | \r |
239 | void CPicoGameSession::freeResources()\r |
240 | {\r |
241 | RThread thread;\r |
242 | TInt i;\r |
243 | \r |
244 | DEBUGPRINT(_L("CPicoGameSession::freeResources()"));\r |
245 | \r |
246 | if(iThreadWatcher && thread.Open(iThreadWatcher->iTid) == KErrNone)\r |
247 | {\r |
248 | // try to stop our emu thread\r |
249 | gamestate = PGS_Quit;\r |
250 | if(pauseSemaphore.Handle() > 0)\r |
251 | pauseSemaphore.Signal();\r |
252 | \r |
253 | if(thread.Handle() > 0)\r |
254 | {\r |
255 | // tried reopening thread handle here over time intervals to detect if thread is alive,\r |
256 | // but would run into handle panics.\r |
257 | \r |
258 | for(i = 0; i < 8; i++) {\r |
259 | User::After(100 * 1000);\r |
260 | if(thread.ExitReason() != 0) break;\r |
261 | }\r |
262 | \r |
263 | if(thread.ExitReason() == 0) {\r |
264 | // too late, time to die\r |
265 | DEBUGPRINT(_L("thread %i not responding, killing.."), (TInt32) thread.Id());\r |
266 | thread.Terminate(1);\r |
267 | }\r |
268 | thread.Close();\r |
269 | }\r |
270 | \r |
271 | }\r |
272 | \r |
ca482e5d |
273 | if (iThreadWatcher != NULL)\r |
cc68a136 |
274 | {\r |
275 | DEBUGPRINT(_L("delete iThreadWatcher"));\r |
276 | delete iThreadWatcher;\r |
277 | DEBUGPRINT(_L("after delete iThreadWatcher"));\r |
278 | iThreadWatcher = NULL;\r |
279 | }\r |
280 | \r |
cc68a136 |
281 | if (initSemaphore.Handle() > 0)\r |
282 | initSemaphore.Close();\r |
283 | if (pauseSemaphore.Handle() > 0)\r |
284 | pauseSemaphore.Close();\r |
ca482e5d |
285 | if (loadWaitSemaphore.Handle() > 0)\r |
286 | loadWaitSemaphore.Close();\r |
287 | DEBUGPRINT(_L("freeResources() returning"));\r |
cc68a136 |
288 | #ifdef __DEBUG_PRINT_FILE\r |
289 | if (logMutex.Handle() > 0)\r |
290 | logMutex.Close();\r |
291 | #endif\r |
292 | }\r |
293 | \r |
294 | TBool CPicoGameSession::iEmuRunning = EFalse;\r |
295 | CThreadWatcher *CPicoGameSession::iThreadWatcher = 0;\r |
ca482e5d |
296 | TBuf<150> CPicoGameSession::iRomInternalName;\r |
cc68a136 |
297 | \r |
298 | \r |
299 | // CThreadWatcher\r |
300 | CThreadWatcher::~CThreadWatcher()\r |
301 | {\r |
302 | Cancel();\r |
303 | DEBUGPRINT(_L("after CThreadWatcher::Cancel();"));\r |
304 | }\r |
305 | \r |
306 | CThreadWatcher::CThreadWatcher(const TThreadId& aTid)\r |
307 | : CActive(CActive::EPriorityStandard), iTid(aTid)\r |
308 | {\r |
309 | }\r |
310 | \r |
311 | \r |
312 | CThreadWatcher* CThreadWatcher::NewL(const TThreadId& aTid)\r |
313 | {\r |
314 | CThreadWatcher* self = new(ELeave) CThreadWatcher(aTid);\r |
315 | CleanupStack::PushL(self);\r |
316 | self->ConstructL();\r |
317 | CleanupStack::Pop(); // self\r |
318 | return self;\r |
319 | }\r |
320 | \r |
321 | void CThreadWatcher::ConstructL()\r |
322 | {\r |
323 | CActiveScheduler::Add(this);\r |
324 | RThread thread;\r |
325 | if(thread.Open(iTid) == KErrNone) {\r |
326 | thread.Logon(iStatus);\r |
327 | thread.Close();\r |
328 | SetActive();\r |
329 | }\r |
330 | }\r |
331 | \r |
332 | void CThreadWatcher::RunL()\r |
333 | {\r |
334 | DEBUGPRINT(_L("CThreadWatcher::RunL()"));\r |
335 | CPicoGameSession::iEmuRunning = EFalse;\r |
336 | if(appView) appView->UpdateCommandList();\r |
337 | //initSemaphore.Signal(); // no point to do that here, AS can't get here if it is waiting\r |
338 | }\r |
339 | \r |
340 | void CThreadWatcher::DoCancel()\r |
341 | {\r |
342 | RThread thread;\r |
343 | DEBUGPRINT(_L("CThreadWatcher::DoCancel()"));\r |
344 | if(thread.Open(iTid) == KErrNone) {\r |
345 | DEBUGPRINT(_L("thread.LogonCancel(iStatus);"));\r |
346 | thread.LogonCancel(iStatus);\r |
347 | thread.Close();\r |
348 | }\r |
349 | }\r |
ca482e5d |
350 | \r |
351 | extern "C" void cache_flush_d_inval_i(const void *start_addr, const void *end_addr)\r |
352 | {\r |
353 | // TODO\r |
354 | User::IMB_Range((TAny *)start_addr, (TAny *)end_addr);\r |
355 | }\r |
356 | \r |