UIQ3 update, some makefile unification, rm old configs, stuff
[picodrive.git] / platform / uiq3 / Engine.cpp
CommitLineData
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
32extern TInt machineUid;\r
33extern int gamestate, gamestate_next;\r
ca482e5d 34extern char *loadrom_fname;\r
35extern int loadrom_result;\r
cc68a136 36extern const char *actionNames[];\r
cc68a136 37RSemaphore initSemaphore;\r
ca482e5d 38RSemaphore pauseSemaphore;\r
39RSemaphore loadWaitSemaphore;\r
cc68a136 40int pico_was_reset = 0;\r
cc68a136 41static CPicolAppView *appView = 0;\r
42\r
43\r
44TInt 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
97TInt EmuThreadFunction(TAny* anArg);\r
98\r
99TInt 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
151TInt 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
168TInt 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
212TInt 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
236extern RMutex logMutex;\r
237#endif\r
238\r
239void 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
294TBool CPicoGameSession::iEmuRunning = EFalse;\r
295CThreadWatcher *CPicoGameSession::iThreadWatcher = 0;\r
ca482e5d 296TBuf<150> CPicoGameSession::iRomInternalName;\r
cc68a136 297\r
298\r
299// CThreadWatcher\r
300CThreadWatcher::~CThreadWatcher()\r
301{\r
302 Cancel();\r
303 DEBUGPRINT(_L("after CThreadWatcher::Cancel();"));\r
304}\r
305\r
306CThreadWatcher::CThreadWatcher(const TThreadId& aTid)\r
307: CActive(CActive::EPriorityStandard), iTid(aTid)\r
308{\r
309}\r
310\r
311\r
312CThreadWatcher* 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
321void 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
332void 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
340void 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
351extern "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