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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 31 - (hide annotations) (download)
Tue Sep 7 03:24:11 2010 UTC (10 years ago) by william
File MIME type: text/plain
File size: 33903 byte(s)
committing r3113 initial commit again...
1 william 31 /***************************************************************************
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