/[pcsx2_0.9.7]/trunk/plugins/CDVDpeops/read.c
ViewVC logotype

Contents of /trunk/plugins/CDVDpeops/read.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 31 - (show annotations) (download)
Tue Sep 7 03:24:11 2010 UTC (9 years, 11 months ago) by william
File MIME type: text/plain
File size: 33903 byte(s)
committing r3113 initial commit again...
1 /***************************************************************************
2 read.c - description
3 -------------------
4 begin : Sun Nov 16 2003
5 copyright : (C) 2003 by Pete Bernert
6 email : BlackDove@addcom.de
7 ***************************************************************************/
8
9 /***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. See also the license.txt file for *
15 * additional informations. *
16 * *
17 ***************************************************************************/
18
19 //*************************************************************************//
20 // History of changes:
21 //
22 // 2003/11/16 - Pete
23 // - generic cleanup for the Peops release
24 //
25 //*************************************************************************//
26
27 /////////////////////////////////////////////////////////
28
29 #include "stdafx.h"
30 #define _IN_READ
31 #include "externals.h"
32
33 /////////////////////////////////////////////////////////
34
35 READTRACKFUNC pReadTrackFunc=NULL;
36 GETPTRFUNC pGetPtrFunc=NULL;
37
38 int iUseCaching=0;
39 int iTryAsync=0;
40 int iBufSel=0;
41
42 unsigned char * pMainBuffer=0;
43 unsigned char * pCurrReadBuf=0;
44 unsigned char * pFirstReadBuf=0;
45 unsigned char * pAsyncBuffer=0;
46
47 unsigned long lMaxAddr=0;
48 unsigned long lLastAddr = 0xFFFFFFFF;
49 unsigned long lLastAsyncAddr = 0xFFFFFFFF;
50 unsigned long lNeededAddr = 0xFFFFFFFF;
51 unsigned long lLastAccessedAddr = 0xFFFFFFFF;
52 int iLastAccessedMode=0;
53
54 unsigned char * ptrBuffer[2];
55 unsigned char * pAsyncFirstReadBuf[2];
56
57
58 #define MAXQSIZE 16
59 #define MAXQFETCH 8
60
61 unsigned long lAddrQ[MAXQSIZE];
62 int iQPos=0;
63 int iQIdle=0;
64 int iQLockPos=-1;
65
66 /////////////////////////////////////////////////////////
67 // thread helper vars
68
69 HANDLE hReadThread = NULL;
70 BOOL bThreadEnded = FALSE;
71 HANDLE hThreadEvent[3];
72 HANDLE hThreadMutex[2];
73
74 /////////////////////////////////////////////////////////
75 // internal MAXDATACACHE*64KB (4MB) data cache
76
77 #define MAXDATACACHE 64
78 unsigned long lDataCacheAddr[MAXDATACACHE];
79 unsigned char * pDataCacheBuf[MAXDATACACHE];
80 BOOL bDataCacheHit=FALSE;
81 int iUseDataCache=0;
82
83 /////////////////////////////////////////////////////////
84 // main init func
85
86 void CreateREADBufs(void)
87 {
88 switch(iUseCaching)
89 {
90 case 4: iUseDataCache = 2; // use a special data cache on threadex reading
91 pReadTrackFunc = DoReadThreadEx;
92 pGetPtrFunc = GetREADThreadExPtr; break;
93 case 3: pReadTrackFunc = DoReadThread;
94 pGetPtrFunc = GetREADThreadPtr; break;
95 case 2: pReadTrackFunc = DoReadAsync;
96 pGetPtrFunc = NULL; break;
97 default: pReadTrackFunc = DoRead;
98 pGetPtrFunc = NULL; break;
99 }
100
101 hThreadEvent[0]=NULL; // clear events/mutex
102 hThreadEvent[1]=NULL;
103 hThreadEvent[2]=NULL;
104 hThreadMutex[0]=NULL;
105 hThreadMutex[1]=NULL;
106
107 AllocDataCache(); // build data cache, if wanted
108
109 lLastAddr = 0xFFFFFFFF;
110 lLastAsyncAddr = 0xFFFFFFFF;
111 iBufSel = 0;
112
113 if(iUseCaching) // some caching? need bigger buffer
114 pMainBuffer=(unsigned char *)malloc(MAXCDBUFFER);
115 else pMainBuffer=(unsigned char *)malloc(CDSECTOR+208+96);
116
117 pCurrReadBuf=pFirstReadBuf=pMainBuffer+FRAMEBUFEXTRA;
118
119 if(iUseCaching>=2) // async/thread mode
120 {
121 pAsyncBuffer=(unsigned char *)malloc(MAXCDBUFFER);
122 ptrBuffer[0]=pMainBuffer;
123 ptrBuffer[1]=pAsyncBuffer;
124 pAsyncFirstReadBuf[0]=pFirstReadBuf;
125 pAsyncFirstReadBuf[1]=pAsyncBuffer+FRAMEBUFEXTRA;
126
127 if(iUseCaching>=3) // thread mode
128 {
129 DWORD dw;
130 bThreadEnded = FALSE;
131
132 for(dw=0;dw<3;dw++) // -> create events
133 {
134 hThreadEvent[dw]=CreateEvent(NULL,TRUE,FALSE,NULL);
135 ResetEvent(hThreadEvent[dw]);
136 }
137 for(dw=0;dw<2;dw++) // -> create mutex
138 {
139 hThreadMutex[dw]=CreateMutex(NULL,FALSE,NULL);
140 }
141 if(iUseCaching==3) // -> create thread
142 hReadThread=CreateThread(NULL,0,READThread,0,0,&dw);
143 else
144 {
145 for(dw=0;dw<MAXQSIZE;dw++) lAddrQ[dw]=0xFFFFFFFF;
146 iQPos=0;
147 iQLockPos=-1;
148 hReadThread=CreateThread(NULL,0,READThreadEx,0,0,&dw);
149 }
150 }
151 }
152 else
153 pAsyncBuffer=0;
154 }
155
156 /////////////////////////////////////////////////////////
157
158 void FreeREADBufs(void)
159 {
160 if(hReadThread) // thread?
161 {
162 SetEvent(hThreadEvent[1]); // -> signal: end thread
163 while(!bThreadEnded) {Sleep(5L);} // -> wait til ended
164 WaitForSingleObject(hThreadMutex[1],INFINITE);
165 ReleaseMutex(hThreadMutex[1]);
166 hReadThread=NULL; // -> clear handle
167 }
168
169 if(hThreadEvent[0]) CloseHandle(hThreadEvent[0]); // kill events/mutex
170 if(hThreadEvent[1]) CloseHandle(hThreadEvent[1]);
171 if(hThreadEvent[2]) CloseHandle(hThreadEvent[2]);
172 if(hThreadMutex[0]) CloseHandle(hThreadMutex[0]);
173 if(hThreadMutex[1]) CloseHandle(hThreadMutex[1]);
174
175 if(pMainBuffer) free(pMainBuffer); // free main data buf
176 pMainBuffer=NULL;
177 if(pAsyncBuffer) free(pAsyncBuffer); // free async data buf
178 pAsyncBuffer=NULL;
179
180 FreeDataCache();
181 }
182
183 /////////////////////////////////////////////////////////
184 // retry on readng error (blocking)
185
186 BOOL bReadRetry(FRAMEBUF * f)
187 {
188 int iRetry=0;
189
190 while (iRetry<iMaxRetry)
191 {
192 if(pReadFunc(TRUE,f)==SS_COMP) break; // try sync read
193 iRetry++;
194 }
195
196 if(iRetry==iMaxRetry) // no success?
197 {
198 if(iShowReadErr) // -> tell it to user
199 {
200 char szB[64];
201 wsprintf(szB,"Read error on address %08lx!",f->dwFrame);
202 MessageBox(NULL,szB,libraryName,MB_OK);
203 }
204 return FALSE; // -> tell emu: bad
205 }
206
207 return TRUE;
208 }
209
210 ////////////////////////////////////////////////////////
211 /////////////////////////////////////////////////////////
212 /////////////////////////////////////////////////////////
213 // sync modes (caching 0 and 1)
214 // just reads one or more blocks, and always waits until
215 // reading is done
216 /////////////////////////////////////////////////////////
217
218 BOOL DoRead(unsigned long addr)
219 {
220 FRAMEBUF * f;
221
222 ////////////////////////////////////////////////////////
223
224 if(iUseCaching && // cache block available?
225 lLastAddr!=0xFFFFFFFF &&
226 addr>=lLastAddr && // and addr in block?
227 addr<=(lLastAddr+MAXCACHEBLOCK))
228 {
229 pCurrReadBuf=pFirstReadBuf+ // -> calc data ptr
230 ((addr-lLastAddr)*iUsedBlockSize);
231 if(ppfHead) CheckPPFCache(addr,pCurrReadBuf); // -> apply ppf
232 return TRUE; // -> done
233 }
234
235 ////////////////////////////////////////////////////////
236
237 if(iUseDataCache && CheckDataCache(addr)) // cache used and data is in cache? set read ptr, if yes
238 return TRUE; // -> also fine
239
240 ////////////////////////////////////////////////////////
241
242 f=(FRAMEBUF *)pMainBuffer; // setup read for one sector
243
244 f->dwFrameCnt = 1;
245 f->dwBufLen = iUsedBlockSize;
246 f->dwFrame = addr;
247
248 pCurrReadBuf=pFirstReadBuf;
249
250 ////////////////////////////////////////////////////////
251
252 if(iUseCaching) // cache block?
253 {
254 if((addr+MAXCACHEBLOCK)<lMaxAddr) // and big read is possible?
255 {
256 f->dwFrameCnt = MAXCACHEBLOCK+1; // -> set bigger read
257 f->dwBufLen = (MAXCACHEBLOCK+1)*iUsedBlockSize;
258 lLastAddr = addr; // -> store addr of block
259 }
260 else
261 {
262 lLastAddr=0xFFFFFFFF; // no caching, no block addr
263 }
264 }
265
266 ////////////////////////////////////////////////////////
267
268 if(pReadFunc(TRUE,f)!=SS_COMP) // do a waiting read
269 {
270 if(!bReadRetry(f)) return FALSE; // and retry on error
271 }
272
273 if(iUseDataCache && lLastAddr!=0xFFFFFFFF) // data cache used? and whole 64 k read block?
274 AddToDataCache(addr,pFirstReadBuf); // -> add the complete data to cache
275
276 if(ppfHead) CheckPPFCache(addr,pCurrReadBuf); // apply ppf
277
278 return TRUE;
279 }
280
281 /////////////////////////////////////////////////////////
282 /////////////////////////////////////////////////////////
283 /////////////////////////////////////////////////////////
284 // async mode (caching 2)
285 // this mode works fine with ASPI...
286 // the first read will be done sync, though, only the
287 // additional pre-fetching will be done async...
288 // well, with mdecs most reads will be prefetched, so
289 // speed is good... with IOCTL this mode is more like
290 // a 'double sync' reading, since IOCTL seems always
291 // to be blocking (see also notes for caching mode 3)
292 /////////////////////////////////////////////////////////
293
294 BOOL DoReadAsync(unsigned long addr)
295 {
296 FRAMEBUF * f;
297
298 ////////////////////////////////////////////////////////
299 // 1. check if data is in already filled buffer
300
301 if(lLastAddr!=0xFFFFFFFF &&
302 addr>=lLastAddr &&
303 addr<=(lLastAddr+MAXCACHEBLOCK))
304 {
305 pCurrReadBuf=pAsyncFirstReadBuf[iBufSel]+
306 ((addr-lLastAddr)*iUsedBlockSize);
307
308 if(ppfHead) CheckPPFCache(addr,pCurrReadBuf);
309
310 iTryAsync=0;
311 return TRUE;
312 }
313
314 ////////////////////////////////////////////////////////
315 // check data cache
316
317 if(iUseDataCache && CheckDataCache(addr)) // cache used and data is in cache? set read ptr, if yes
318 return TRUE; // -> also fine
319
320 ////////////////////////////////////////////////////////
321 // 2. not in main buffer? wait for async to be finished
322
323 if(bDoWaiting)
324 {
325 WaitGenEvent(0xFFFFFFFF);bDoWaiting=FALSE;
326 if(sx.SRB_Status!=SS_COMP) lLastAsyncAddr=0xFFFFFFFF;
327 }
328
329 ////////////////////////////////////////////////////////
330 // 3. check in asyncbuffer. if yes, swap buffers and do next async read
331
332 if(lLastAsyncAddr!=0xFFFFFFFF &&
333 addr>=lLastAsyncAddr &&
334 addr<=(lLastAsyncAddr+MAXCACHEBLOCK))
335 {
336 int iAsyncSel=iBufSel; // store old buf num
337 if(iBufSel==0) iBufSel=1; else iBufSel=0; // toggle to new num
338
339 lLastAddr=lLastAsyncAddr; // set adr of block
340 pCurrReadBuf=pAsyncFirstReadBuf[iBufSel]+ // set data ptr
341 ((addr-lLastAddr)*iUsedBlockSize);
342
343 if(iUseDataCache) // data cache used?
344 AddToDataCache(lLastAddr,pAsyncFirstReadBuf[iBufSel]); // -> add the complete 64k data to cache
345
346 if(ppfHead) CheckPPFCache(addr,pCurrReadBuf); // apply ppf
347
348 iTryAsync=0; // data was async, reset count
349 addr=lLastAddr+MAXCACHEBLOCK+1; // calc adr of next prefetch
350 if(!((addr+MAXCACHEBLOCK)<lMaxAddr)) // mmm, no whole block can be done... so we do no prefetch at all
351 {lLastAsyncAddr=0xFFFFFFFF;return TRUE;}
352
353 f=(FRAMEBUF *)ptrBuffer[iAsyncSel]; // setup prefetch addr
354 f->dwFrameCnt = MAXCACHEBLOCK+1;
355 f->dwBufLen = (MAXCACHEBLOCK+1)*iUsedBlockSize;
356 f->dwFrame = addr;
357
358 lLastAsyncAddr=addr; // store prefetch addr
359
360 if(pReadFunc(FALSE,f)!=SS_COMP) // start the async read
361 lLastAsyncAddr=0xFFFFFFFF; // -> if no success, no async prefetch buf available
362
363 return TRUE;
364 }
365
366 ////////////////////////////////////////////////////////
367 // here we do a sync read
368
369 iBufSel=0; // read in buf 0
370
371 f=(FRAMEBUF *)ptrBuffer[0];
372 f->dwFrame = addr;
373
374 pCurrReadBuf=pFirstReadBuf;
375
376 ////////////////////////////////////////////////////////
377 // if it's possible, we do a bigger read
378
379 if((addr+MAXCACHEBLOCK)<lMaxAddr)
380 {
381 f->dwFrameCnt = MAXCACHEBLOCK+1;
382 f->dwBufLen = (MAXCACHEBLOCK+1)*iUsedBlockSize;
383 lLastAddr = addr;
384 }
385 else
386 {
387 f->dwFrameCnt = 1;
388 f->dwBufLen = iUsedBlockSize;
389 lLastAddr = 0xFFFFFFFF;
390 }
391
392 ////////////////////////////////////////////////////////
393 // start read, wait til finished
394
395 if(pReadFunc(TRUE,f)!=SS_COMP)
396 {
397 if(!bReadRetry(f)) return FALSE;
398 }
399
400 if(iUseDataCache && lLastAddr!=0xFFFFFFFF) // data cache used? and complete 64k block?
401 AddToDataCache(addr,pAsyncFirstReadBuf[0]); // -> add the complete data to cache
402
403 if(ppfHead) CheckPPFCache(addr,pCurrReadBuf);
404
405 ////////////////////////////////////////////////////////
406 // start additional async prefetch read, if it's ok
407
408 iTryAsync++;
409 if(iTryAsync>1) {iTryAsync=2;return TRUE;} // prefetches seems to be useless right now, so turn them off until next real read
410
411 addr+=MAXCACHEBLOCK+1; // prefetch addr
412 if(!((addr+MAXCACHEBLOCK)<lMaxAddr)) // not possible? do't do prefetch
413 {lLastAsyncAddr=0xFFFFFFFF;return TRUE;}
414
415 f=(FRAMEBUF *)ptrBuffer[1]; // setup prefetch into buf 1
416 f->dwFrameCnt = MAXCACHEBLOCK+1;
417 f->dwBufLen = (MAXCACHEBLOCK+1)*iUsedBlockSize;
418 f->dwFrame = addr;
419
420 lLastAsyncAddr= addr;
421
422 if(pReadFunc(FALSE,f)!=SS_COMP) // start the async prefetch
423 lLastAsyncAddr=0xFFFFFFFF;
424
425 return TRUE;
426 }
427
428 /////////////////////////////////////////////////////////
429 /////////////////////////////////////////////////////////
430 /////////////////////////////////////////////////////////
431 // thread mode (caching 3)
432 // this mode helps with slower drives using the IOCTL
433 // interface (since that one seems to do always blocking
434 // reads, even when they are done overlapped).
435 // With ASPI, the thread mode performance will be more or less
436 // the same as with async caching mode 2...
437 // thread reading would be much more powerful, if the main
438 // emu would do:
439 // ...
440 // CDRreadTrack()
441 // ... do some other stuff here ...
442 // CDRgetBuffer()
443 // ...
444 // but lazy main emu coders seem to prefer:
445 // ...
446 // CDRreadTrack()
447 // CDRgetBuffer()
448 // ...
449 // so there is no time between the calls to do a good
450 // asynchronous read... sad, sad...
451 /////////////////////////////////////////////////////////
452
453 /////////////////////////////////////////////////////////
454 // reading thread... sleeps until a new read is signaled
455
456 DWORD WINAPI READThread(LPVOID lpParameter)
457 {
458 FRAMEBUF * f;
459
460 while(WaitForMultipleObjects(2,hThreadEvent,FALSE, // wait until event to start (or event to end) get raised
461 INFINITE)==WAIT_OBJECT_0)
462 {
463 WaitForSingleObject(hThreadMutex[0],INFINITE); // read mutex: nobody else is allowed to read now
464 WaitForSingleObject(hThreadMutex[1],INFINITE); // variable access mutex: nobody else can change the vars now
465 ResetEvent(hThreadEvent[0]); // ok, kick event has been handled
466 SetEvent(hThreadEvent[2]); // set flag: we have started the read
467
468 lLastAsyncAddr = lNeededAddr; // setup read and vars
469 f=(FRAMEBUF *)ptrBuffer[!iBufSel]; // !iSel = async buffer
470 f->dwFrame = lNeededAddr;
471 f->dwFrameCnt = min((lMaxAddr-lNeededAddr+1),(MAXCACHEBLOCK+1));
472 f->dwBufLen = f->dwFrameCnt*iUsedBlockSize;
473
474 ReleaseMutex(hThreadMutex[1]); // ok, vars have been changed, now that vars are again available for all
475
476 if(pReadFunc(TRUE,f)!=SS_COMP) // do a blocking (sync) read
477 {
478 bReadRetry(f); // mmm... if reading fails a number of times, we don't have a chance to return 'bad' to emu with tread reading... life is hard :)
479 }
480
481 ReleaseMutex(hThreadMutex[0]); // ok, read has done
482 }
483
484 bThreadEnded=1;
485 return 0;
486 }
487
488 /////////////////////////////////////////////////////////
489 // emu says: we need data at given addr soon...
490 // so, if we don't have it in any buffer, we kick a read
491 // ... called on CDRreadTrack()
492
493 BOOL DoReadThread(unsigned long addr)
494 {
495 if(!hReadThread) return FALSE; // no thread, no fun
496
497 bDataCacheHit=FALSE; // init data cache hit flag (even if no cache is used...)
498
499 if(lLastAddr!=0xFFFFFFFF && // data is in curr data buffer?
500 addr>=lLastAddr &&
501 addr<=(lLastAddr+MAXCACHEBLOCK))
502 return TRUE; // -> fine
503
504 if(iUseDataCache && CheckDataCache(addr)) // data cache used and data is in cache? set read ptr, if yes
505 {bDataCacheHit=TRUE;return TRUE;} // -> and raise 'hit' flag, so we don't need to do anything in 'getbuffer'
506
507 WaitForSingleObject(hThreadMutex[1],INFINITE); // wait to access 'buffer 1 vars'
508
509 if(lLastAsyncAddr!=0xFFFFFFFF && // data is (or will be soon if reading is going on in thread now) in async buffer?
510 addr>=lLastAsyncAddr &&
511 addr<=(lLastAsyncAddr+MAXCACHEBLOCK))
512 {
513 ReleaseMutex(hThreadMutex[1]); // -> fine
514 return TRUE;
515 }
516 // data is not in buf0 and not in buf1:
517 lNeededAddr=addr; // set needed adr (mutex is active, so it's safe to change that)
518 ResetEvent(hThreadEvent[2]); // reset "read has started" flag
519 SetEvent(hThreadEvent[0]); // set "start read" flag... the read will start reading soon after
520 ReleaseMutex(hThreadMutex[1]); // done with var access
521 return TRUE;
522 }
523
524 /////////////////////////////////////////////////////////
525 // emu says: gimme ptr to needed data... this will
526 // automatically do an async data prefetch read as well
527 // ... called on CDRgetBuffer()
528
529 void GetREADThreadPtr(void)
530 {
531 unsigned long addr=lLastAccessedAddr;
532
533 if(bDataCacheHit) return; // if we had a data cache hit, the readbuf ptr is already fine, nothing else to do
534
535 if(lLastAddr!=0xFFFFFFFF && // data is in buffer 0?
536 addr>=lLastAddr &&
537 addr<=(lLastAddr+MAXCACHEBLOCK))
538 {
539 pCurrReadBuf=pAsyncFirstReadBuf[iBufSel]+ // -> ok, return curr data buffer ptr
540 ((addr-lLastAddr)*iUsedBlockSize);
541 if(ppfHead) CheckPPFCache(addr,pCurrReadBuf);
542 return;
543 }
544
545 WaitForSingleObject(hThreadEvent[2],INFINITE); // wait until reading has started (it will take a small time after the read start kick, so we have to go sure that it has _really_ started)
546 WaitForSingleObject(hThreadMutex[0],INFINITE); // wait until reading has finished
547
548 lLastAddr=lLastAsyncAddr; // move data to from async data to curr data buffer (by toggling iSel)
549 iBufSel=!iBufSel;
550 lLastAsyncAddr=0xFFFFFFFF; // nothing in async data buffer now
551
552 lNeededAddr=addr+MAXCACHEBLOCK+1; // prefetch read addr
553 ResetEvent(hThreadEvent[2]); // reset "read has started" flag
554 SetEvent(hThreadEvent[0]); // signal for start next read
555 ReleaseMutex(hThreadMutex[0]); // ok, now reading in buffer 1 can start
556
557 if(iUseDataCache) // data cache used? can be less then 64 kb with thread reading, but that doesn't matter here... will be either 64 k or (max-addr) sectors
558 AddToDataCache(lLastAddr,
559 pAsyncFirstReadBuf[iBufSel]); // -> add the complete data to cache
560
561 pCurrReadBuf=pAsyncFirstReadBuf[iBufSel]+ // -> return the curr data buffer ptr
562 ((addr-lLastAddr)*iUsedBlockSize);
563 if(ppfHead) CheckPPFCache(addr,pCurrReadBuf);
564 }
565
566 /////////////////////////////////////////////////////////
567 /////////////////////////////////////////////////////////
568 /////////////////////////////////////////////////////////
569 // special thread mode (caching 4)
570 // this mode helps with certain drives
571 // basically it does the following:
572 // It has a queue for n prefetch reads. If the main emu is
573 // asking for an addr, the mode will check, if
574 // this addr is a) getting read right now, b) already
575 // in our 4 MB cache, c) already in the q.
576 // If no condition matches, it will add it in q...
577 // the same is done with the next n/2 addr blocks, so
578 // the q will keep the drive busy... also, if everything
579 // is cached (and the q is empty), we will add additional
580 // addresses to read, also to keep the drive busy, and to
581 // do the needed reading as soon as possible :)
582
583 /////////////////////////////////////////////////////////
584 // reading thread...
585
586 DWORD WINAPI READThreadEx(LPVOID lpParameter)
587 {
588 FRAMEBUF * f;
589
590 while(WaitForMultipleObjects(2,hThreadEvent,FALSE, // wait until event to start (or event to end) get raised
591 INFINITE)==WAIT_OBJECT_0)
592 {
593 while(1)
594 {
595 //------------------------------------------------//
596 WaitForSingleObject(hThreadMutex[1],INFINITE); // variable access mutex: nobody else can change the vars now
597 ResetEvent(hThreadEvent[0]); // ok, kick event has been handled
598
599 if(lAddrQ[iQPos]==0xFFFFFFFF) // nothing to do? strange :)
600 {ReleaseMutex(hThreadMutex[1]);break;}
601
602 f=(FRAMEBUF *)ptrBuffer[0];
603 lNeededAddr = lAddrQ[iQPos]; // store it in 'Neededaddr' for checks outside the thread
604 f->dwFrame = lNeededAddr;
605 f->dwFrameCnt = min((lMaxAddr-f->dwFrame+1),(MAXCACHEBLOCK+1));
606 f->dwBufLen = f->dwFrameCnt*iUsedBlockSize;
607
608 lAddrQ[iQPos++]=0xFFFFFFFF; // set this slot as 'done'
609 if(iQPos>=MAXQSIZE) iQPos=0; // amnd inc the head pos
610
611 ReleaseMutex(hThreadMutex[1]); // ok, vars have been changed, now that vars are again available for all
612 //------------------------------------------------//
613 WaitForSingleObject(hThreadMutex[0],INFINITE); // read mutex: nobody else is allowed to read now
614 if(!iCDROK)
615 {
616 ReleaseMutex(hThreadMutex[0]);
617 break;
618 }
619
620 if(bCDDAPlay) // some cdda security...
621 { // it should just prevent prefetch reads happening in cdda mode, if this one breaks a 'needed' read, we are lost...
622 lNeededAddr=0xFFFFFFFF; // so maybe we should remove this check? mmm, we will see
623 ReleaseMutex(hThreadMutex[0]);
624 break;
625 }
626
627 if(pReadFunc(TRUE,f)!=SS_COMP) // do a blocking (sync) read
628 { // mmm... if reading fails a number of times, we don't have a chance to return 'bad' to emu with thread reading... life is hard :)
629 bReadRetry(f); // but at least our 'wait for data in cache' getptr will not wait forever (just returning wrong data, ehehe)
630 }
631
632 ReleaseMutex(hThreadMutex[0]); // ok, read has done
633 //------------------------------------------------//
634 WaitForSingleObject(hThreadMutex[1],INFINITE); // variable access mutex: nobody else can change the vars now
635 lNeededAddr=0xFFFFFFFF; // no read is now active
636 AddToDataCache(f->dwFrame,pFirstReadBuf); // add the complete data to cache
637 ReleaseMutex(hThreadMutex[1]); // ok, vars have been changed, now that vars are again available for all
638 //------------------------------------------------//
639 if(WaitForSingleObject(hThreadEvent[0],0)!=WAIT_OBJECT_0)
640 Sleep(1); // if nobody has started a new kick, let's sleep awhile to give Windows more room to breath
641 }
642 }
643
644 bThreadEnded=1;
645 return 0;
646 }
647
648 /////////////////////////////////////////////////////////
649 // emu says: we need data at given addr soon...
650 // so, if we don't have it in any buffer, we kick a read
651 // ... called on CDRreadTrack()
652
653 //#define THREADEX_STRAIGHT
654
655 BOOL DoReadThreadEx(unsigned long addr)
656 {
657 int i,k,j=0;
658
659 if(!hReadThread) return FALSE; // no thread, no fun
660
661 WaitForSingleObject(hThreadMutex[1],INFINITE); // wait for data access
662
663 //-----------------------------------------------------//
664 // straight reading try... should have been faster, but
665 // in 'real life' this approach keeps the cdrom drive
666 // spinning too much, giving other pc resources no room
667 // to breath... by increasing the thread 'Sleep' value
668 // the performance can get better, but then the annoying
669 // breaks we wanted to fight will show up again...
670 // so this type is disabled as long as nobody enables the
671 // define again :)
672
673 #ifdef THREADEX_STRAIGHT
674
675 if(addr>=lNeededAddr &&
676 addr<=(lNeededAddr+MAXCACHEBLOCK))
677 {
678 ReleaseMutex(hThreadMutex[1]);
679 return TRUE;
680 }
681
682 for(k=0;k<MAXQSIZE;k++) // loop max of prefetch blocks
683 {
684 for(i=0;i<MAXDATACACHE;i++) // loop whole cache
685 {
686 if(addr>=lDataCacheAddr[i] && // -> addr found?
687 addr<=(lDataCacheAddr[i]+MAXCACHEBLOCK))
688 {
689 if(k==0) iQLockPos=i; // -> if it's the current main addr, lock it, so no prefetch read overwrites its content
690 break;
691 }
692 }
693 if(i!=MAXDATACACHE) // found in data cache?
694 {addr=addr+MAXCACHEBLOCK+1;continue;} // -> do nothing with this addr, we have its content
695 else break; // here is the first unknown addr
696 }
697
698 if(addr>=lMaxAddr) // check, if addr too big
699 {
700 ReleaseMutex(hThreadMutex[1]);
701 if(k==0) return FALSE; // -> if it's the main addr, there is an error
702 return TRUE; // -> otherwise we can't simply cache that addr
703 }
704
705 for(i=0;i<MAXQSIZE;i++) // loop q list
706 {
707 if(addr>=lAddrQ[i] && // -> addr will be read soon?
708 addr<=(lAddrQ[i]+MAXCACHEBLOCK))
709 {
710 addr=lAddrQ[i]; // --> take this aligned addr for new header
711 break;
712 }
713 }
714
715 for(i=0;i<MAXQSIZE;i++) // loop q list
716 {
717 lAddrQ[i]=addr;
718 addr=addr+MAXCACHEBLOCK+1;
719 if(addr>=lMaxAddr) break;
720 }
721
722 for(;i<MAXQSIZE;i++) // loop q list
723 {
724 lAddrQ[i]=0xFFFFFFFF;
725 }
726
727 iQPos=0;
728
729 SetEvent(hThreadEvent[0]); // kick a read, if neccessary
730
731 #else
732
733 //-----------------------------------------------------//
734 // ok, here is the current ReadThreadEx mode: more
735 // complex, and it doesn't arrange the prefetch sectors
736 // as straight as the type above, but the final result is
737 // still smoother (no more pauses on the tested LG drive)
738
739 for(k=0;k<MAXQFETCH;k++) // loop max of prefetch blocks
740 {
741 if(addr>=lNeededAddr && // addr is getting read right now?
742 addr<=(lNeededAddr+MAXCACHEBLOCK)) // -> ok, we do nothing with it
743 {addr=addr+MAXCACHEBLOCK+1;continue;}
744
745 for(i=0;i<MAXDATACACHE;i++) // loop whole cache
746 {
747 if(addr>=lDataCacheAddr[i] && // -> addr found?
748 addr<=(lDataCacheAddr[i]+MAXCACHEBLOCK))
749 {
750 if(k==0) iQLockPos=i; // -> if it's the current main addr, lock it, so no other prefetch read overwrites its content
751 break;
752 }
753 }
754 if(i!=MAXDATACACHE) // found in data cache?
755 {addr=addr+MAXCACHEBLOCK+1;continue;} // -> do nothing with this addr, we have its content
756
757 for(i=0;i<MAXQSIZE;i++) // loop prefetch q list
758 {
759 if(addr>=lAddrQ[i] && // -> addr will be read soon?
760 addr<=(lAddrQ[i]+MAXCACHEBLOCK))
761 {
762 if(k==0 && i!=iQPos) // curr needed addr is not on top of the q?
763 {
764 addr=lAddrQ[i]; // -> get the addr (our main addr is in it, but that one is more aligned to prev reads)
765 for(i=0;i<MAXQSIZE;i++) lAddrQ[i]=0xFFFFFFFF; // -> clear whole q (we will fill the slots in that loop again)
766 i=MAXQSIZE; // -> sign for storing the addr in q
767 }
768 break;
769 }
770 }
771 if(i!=MAXQSIZE) // found in q?
772 {addr=addr+MAXCACHEBLOCK+1;continue;} // -> do nothing with this addr, we will have its content soon
773
774 // not in q or data cache?
775 if(k==0) lAddrQ[iQPos]=addr; // -> if it's the main addr, store it on top of list
776 else // -> if it's a prefetch addr, try to store it elsewhere at the end of the q
777 {
778 j=iQPos;
779 for(i=0;i<MAXQSIZE;i++)
780 {
781 if(lAddrQ[j]==0xFFFFFFFF) {lAddrQ[j]=addr;break;}
782 j++;if(j>=MAXQSIZE) j=0;
783 }
784 }
785
786 SetEvent(hThreadEvent[0]); // kick a read, if neccessary
787 addr=addr+MAXCACHEBLOCK+1; // next prefetch addr
788 if(addr>=lMaxAddr) break; // security, for detecting if we are at the end of cd
789 }
790
791 //----------------------------------------------------// ok, and here's something to keep the drive busy...
792
793 if(lAddrQ[iQPos]==0xFFFFFFFF && addr<lMaxAddr) // nothing in prefetch q?
794 {
795 iQIdle++; // count how many empty q's in-a-row are happening
796 if(iQIdle>10) // more then x times?
797 {
798 iQIdle=0;
799 lAddrQ[iQPos]=addr; // we add the farest prefetch addr
800 SetEvent(hThreadEvent[0]); // and do an additional kick
801 }
802 }
803 else iQIdle=0; // not idling? ok
804
805 //----------------------------------------------------//
806
807 #endif
808
809 ReleaseMutex(hThreadMutex[1]);
810
811 return TRUE;
812 }
813
814 /////////////////////////////////////////////////////////
815 // emu says: gimme ptr to needed data... this will
816 // automatically do an async data prefetch read as well
817 // ... called on CDRgetBuffer()
818
819 void GetREADThreadExPtr(void)
820 {
821 unsigned long addr=lLastAccessedAddr;
822
823 while(1)
824 {
825 if(bThreadEnded) return; // main emu is already closing (thread is down)? bye
826 WaitForSingleObject(hThreadMutex[1],INFINITE); // wait for data access
827 if(CheckDataCache(addr)) // data now in cache?
828 {
829 ReleaseMutex(hThreadMutex[1]); // -> ok, done
830 return;
831 }
832 ReleaseMutex(hThreadMutex[1]); // else try again (no sleep here, we are blocking everything anyway)
833 }
834
835 }
836
837 /////////////////////////////////////////////////////////
838 /////////////////////////////////////////////////////////
839 /////////////////////////////////////////////////////////
840
841 /////////////////////////////////////////////////////////
842 // simple data cache
843
844 void AllocDataCache(void)
845 {
846 bDataCacheHit=FALSE; // init thread cache hit flag
847 if(!iUseCaching) iUseDataCache=0; // security: no additinal data cache, if no caching active
848 if(iUseDataCache)
849 {
850 int i;
851 for(i=0;i<MAXDATACACHE;i++) // init all cache slots
852 {
853 lDataCacheAddr[i] = 0xFFFFFFFF;
854 pDataCacheBuf[i] = malloc(MAXCDBUFFER-FRAMEBUFEXTRA);
855 }
856 }
857 }
858
859 /////////////////////////////////////////////////////////
860
861 void FreeDataCache(void)
862 {
863 if(iUseDataCache)
864 {
865 int i;
866 for(i=0;i<MAXDATACACHE;i++)
867 {
868 free(pDataCacheBuf[i]);
869 pDataCacheBuf[i]=NULL;
870 }
871 }
872 }
873
874 /////////////////////////////////////////////////////////
875 // easy data cache: stores data blocks
876
877 void AddToDataCache(unsigned long addr,unsigned char * pB)
878 {
879 static int iPos=0;
880 if(iPos==iQLockPos) // special thread mode lock?
881 {iPos++;if(iPos>=MAXDATACACHE) iPos=0;} // -> don't use that pos, use next one
882 lDataCacheAddr[iPos]=addr;
883 memcpy(pDataCacheBuf[iPos],pB,
884 MAXCDBUFFER-FRAMEBUFEXTRA);
885 iPos++; if(iPos>=MAXDATACACHE) iPos=0;
886 }
887
888 /////////////////////////////////////////////////////////
889 // easy data cache check: loop MAXDATACACHE blocks, set ptr if addr found
890
891 BOOL CheckDataCache(unsigned long addr)
892 {
893 int i;
894
895 for(i=0;i<MAXDATACACHE;i++)
896 {
897 if(addr>=lDataCacheAddr[i] &&
898 addr<=(lDataCacheAddr[i]+MAXCACHEBLOCK))
899 {
900 pCurrReadBuf=pDataCacheBuf[i]+
901 ((addr-lDataCacheAddr[i])*iUsedBlockSize);
902 if(ppfHead) CheckPPFCache(addr,pCurrReadBuf);
903 return TRUE;
904 }
905 }
906 return FALSE;
907 }
908
909 /////////////////////////////////////////////////////////
910

  ViewVC Help
Powered by ViewVC 1.1.22