From b4b292d2194d3765ec468a6d32be70fcdc907268 Mon Sep 17 00:00:00 2001 From: "Jake.Stine" Date: Fri, 28 Aug 2009 21:23:32 +0000 Subject: [PATCH] More CDVD fixes. I *think* this revision might provide some noticeable speedups when running games directly from cd drives. Also built-in CDVD blockdumps work now (DVD images only, legacy CdRom games still don't blockdump right unless you use the cdvdiso plugin). git-svn-id: http://pcsx2.googlecode.com/svn/trunk@1701 96395faa-99c1-11dd-bbfe-3dabce05a288 --- common/include/PS2Edefs.h | 2 +- pcsx2/CDVD/CDVD.cpp | 45 ++++++++++++++--------- pcsx2/CDVD/CDVDaccess.cpp | 46 ++++++++++++------------ pcsx2/CDVD/CDVDisoReader.cpp | 17 +++++++-- pcsx2/CDVD/CdRom.cpp | 23 ++++++------ pcsx2/CDVD/IsoFileFormats.cpp | 67 +++++++++++++++++++---------------- pcsx2/CDVD/IsoFileFormats.h | 23 ++++++------ pcsx2/CDVD/IsoFileTools.cpp | 2 +- pcsx2/Plugins.cpp | 4 ++- 9 files changed, 130 insertions(+), 99 deletions(-) diff --git a/common/include/PS2Edefs.h b/common/include/PS2Edefs.h index aa42ef0c32..024cb82a4a 100644 --- a/common/include/PS2Edefs.h +++ b/common/include/PS2Edefs.h @@ -629,8 +629,8 @@ typedef u8* (CALLBACK* _CDVDgetBuffer)(); // Copies loaded data to the target buffer. // Returns -2 if the asynchronous read is still pending. +// Returns -1 if the asyncronous read failed. // Returns 0 on success. -// This function is not allowed to return -1 (reserved for use by readTrack) typedef s32 (CALLBACK* _CDVDgetBuffer2)(u8* buffer); typedef s32 (CALLBACK* _CDVDreadSubQ)(u32 lsn, cdvdSubQ* subq); diff --git a/pcsx2/CDVD/CDVD.cpp b/pcsx2/CDVD/CDVD.cpp index dff2701f3e..5cf28db064 100644 --- a/pcsx2/CDVD/CDVD.cpp +++ b/pcsx2/CDVD/CDVD.cpp @@ -714,36 +714,49 @@ __forceinline void cdvdReadInterrupt() } else { - // Read Error -1 is only returned by readTrack, so handle it first here. - // If readTrack failed it means we don't have any valid data to fetch. - if (cdvd.RErr == -1) + if( cdvd.RErr == 0 ) { - cdvd.RetryCntP++; - Console::Error("CDVD READ ERROR, sector=%d", params cdvd.Sector); - - if (cdvd.RetryCntP <= cdvd.RetryCnt) + while( (cdvd.RErr = DoCDVDgetBuffer(cdr.Transfer)), cdvd.RErr == -2 ) { - cdvd.RErr = DoCDVDreadTrack(cdvd.Sector, cdvd.ReadMode); - CDVDREAD_INT(cdvd.ReadTime); - return; + // not finished yet ... block on the read until it finishes. + Threading::Sleep( 0 ); + Threading::SpinWait(); } } - cdvd.RErr = DoCDVDgetBuffer(cdr.Transfer); - - if(cdvd.RErr == -2) + if (cdvd.RErr == -1) { - // not finished yet ... give it a bit more time - CDVDREAD_INT(cdvd.ReadTime/4); + cdvd.RetryCntP++; + + if (cdvd.RetryCntP <= cdvd.RetryCnt) + { + CDVD_LOG( "CDVD read err, retrying... (attempt %d of %d)", cdvd.RetryCntP, cdvd.RetryCnt ); + cdvd.RErr = DoCDVDreadTrack(cdvd.Sector, cdvd.ReadMode); + CDVDREAD_INT(cdvd.ReadTime); + } + else + Console::Error("CDVD READ ERROR, sector = 0x%08x", params cdvd.Sector); + return; } + cdvd.Reading = false; + + // Any other value besides 0 should be considered invalid here (wtf is that wacky + // plugin trying to do?) + jASSUME( cdvd.RErr == 0 ); } if (cdvdReadSector() == -1) { + // This means that the BCR/DMA hasn't finished yet, and rather than fire off the + // sector-finished notice too early (which might overwrite game data) we delay a + // bit and try to read the sector again later. + // An arbitrary delay of some number of cycles probably makes more sense here, + // but for now it's based on the cdvd.ReadTime value. -- air + assert((int)cdvd.ReadTime > 0 ); - CDVDREAD_INT(cdvd.ReadTime); + CDVDREAD_INT(cdvd.ReadTime/4); return; } diff --git a/pcsx2/CDVD/CDVDaccess.cpp b/pcsx2/CDVD/CDVDaccess.cpp index 33024d0654..d140ee5a0d 100644 --- a/pcsx2/CDVD/CDVDaccess.cpp +++ b/pcsx2/CDVD/CDVDaccess.cpp @@ -44,6 +44,7 @@ static int diskTypeCached = -1; // used to bridge the gap between the old getBuffer api and the new getBuffer2 api. int lastReadSize; +int lastLSN; // needed for block dumping // Records last read block length for block dumping static int plsn = 0; @@ -56,11 +57,9 @@ static void CheckNullCDVD() DevAssert( CDVD != NULL, "Invalid CDVD object state (null pointer exception)" ); } -///////////////////////////////////////////////// -// +////////////////////////////////////////////////////////////////////////////////////////// // Disk Type detection stuff (from cdvdGigaherz) // - int CheckDiskTypeFS(int baseType) { int f; @@ -118,7 +117,7 @@ static int FindDiskType(int mType) } else if (mType < 0) { - static u8 bleh[2352]; + static u8 bleh[CD_FRAMESIZE_RAW]; cdvdTD td; CDVD->getTD(0,&td); @@ -322,26 +321,25 @@ s32 DoCDVDopen(const char* pTitleFilename) cdvdTD td; CDVD->getTD(0, &td); - int blockofs = 0, blocksize = 0, blocks = td.lsn; - - switch(cdtype) + blockDumpFile = isoCreate(Path::Combine( Path::GetWorkingDirectory(), fname ).c_str(), ISOFLAGS_BLOCKDUMP_V3); + if (blockDumpFile) { - case CDVD_TYPE_PS2DVD: - case CDVD_TYPE_DVDV: - case CDVD_TYPE_DETCTDVDS: - case CDVD_TYPE_DETCTDVDD: - blockofs = 24; - blocksize = 2048; - break; - - default: - blockofs = 0; - blocksize= 2352; - break; - } + int blockofs = 0, blocksize = CD_FRAMESIZE_RAW, blocks = td.lsn; - blockDumpFile = isoCreate(fname.c_str(), ISOFLAGS_BLOCKDUMP); - if (blockDumpFile) isoSetFormat(blockDumpFile, blockofs, blocksize, blocks); + // hack: Because of limitations of the current cdvd design, we can't query the blocksize + // of the underlying media. So lets make a best guess: + + switch(cdtype) + { + case CDVD_TYPE_PS2DVD: + case CDVD_TYPE_DVDV: + case CDVD_TYPE_DETCTDVDS: + case CDVD_TYPE_DETCTDVDD: + blocksize = 2048; + break; + } + isoSetFormat(blockDumpFile, blockofs, blocksize, blocks); + } } else { @@ -396,7 +394,7 @@ s32 DoCDVDreadTrack(u32 lsn, int mode) } //DevCon::Notice("CDVD readTrack(lsn=%d,mode=%d)",params lsn, lastReadSize); - + lastLSN = lsn; return CDVD->readTrack(lsn,mode); } @@ -407,7 +405,7 @@ s32 DoCDVDgetBuffer(u8* buffer) if (ret == 0 && blockDumpFile != NULL) { - isoWriteBlock(blockDumpFile, buffer, lastReadSize); + isoWriteBlock(blockDumpFile, buffer, lastLSN); } return ret; diff --git a/pcsx2/CDVD/CDVDisoReader.cpp b/pcsx2/CDVD/CDVDisoReader.cpp index 273d7691e2..0b19a2033c 100644 --- a/pcsx2/CDVD/CDVDisoReader.cpp +++ b/pcsx2/CDVD/CDVDisoReader.cpp @@ -295,9 +295,10 @@ s32 CALLBACK ISOreadSector(u8* tempbuffer, u32 lsn, int mode) return 0; } - isoReadBlock(iso, cdbuffer + iso->blockofs, lsn); + isoReadBlock(iso, cdbuffer, lsn); pbuffer = cdbuffer; + switch (mode) { case CDVD_MODE_2352: @@ -317,6 +318,11 @@ s32 CALLBACK ISOreadSector(u8* tempbuffer, u32 lsn, int mode) break; } + // version 3 blockdumps have no pbuffer header, so lets reset back to the + // original pointer. :) + if( iso->flags & ISOFLAGS_BLOCKDUMP_V3 ) + pbuffer = cdbuffer; + memcpy_fast(tempbuffer,pbuffer,psize); return 0; @@ -329,9 +335,9 @@ s32 CALLBACK ISOreadTrack(u32 lsn, int mode) if (_lsn < 0) lsn = iso->blocks + _lsn; if (lsn > iso->blocks) return -1; - isoReadBlock(iso, cdbuffer + iso->blockofs, lsn); - + isoReadBlock(iso, cdbuffer, lsn); pbuffer = cdbuffer; + switch (mode) { case CDVD_MODE_2352: @@ -351,6 +357,11 @@ s32 CALLBACK ISOreadTrack(u32 lsn, int mode) break; } + // version 3 blockdumps have no pbuffer header, so lets reset back to the + // original pointer. :) + if( iso->flags & ISOFLAGS_BLOCKDUMP_V3 ) + pbuffer = cdbuffer; + return 0; } diff --git a/pcsx2/CDVD/CdRom.cpp b/pcsx2/CDVD/CdRom.cpp index 7cecf04277..aec69a4c63 100644 --- a/pcsx2/CDVD/CdRom.cpp +++ b/pcsx2/CDVD/CdRom.cpp @@ -497,28 +497,27 @@ void cdrReadInterrupt() { cdr.StatP|= 0x22; cdr.Result[0] = cdr.StatP; - // Read Error -1 is only returned by readTrack, so handle it first here. - // If readTrack failed it means we don't have any valid data to fetch. + if( cdr.RErr == 0 ) + { + while( (cdr.RErr = DoCDVDgetBuffer(cdr.Transfer)), cdr.RErr == -2 ) + { + // not finished yet ... block on the read until it finishes. + Threading::Sleep( 0 ); + Threading::SpinWait(); + } + } + if (cdr.RErr == -1) { CDR_LOG(" err\n"); memzero_obj(cdr.Transfer); cdr.Stat = DiskError; - cdr.Result[0]|= 0x01; + cdr.Result[0] |= 0x01; ReadTrack(); CDREAD_INT((cdr.Mode & 0x80) ? (cdReadTime / 2) : cdReadTime); return; } - cdr.RErr = DoCDVDgetBuffer(cdr.Transfer); - - if(cdr.RErr == -2) - { - // async mode is not finished yet ... give it a bit more time - CDREAD_INT(cdReadTime / 4); - return; - } - cdr.Stat = DataReady; CDR_LOG(" %x:%x:%x", cdr.Transfer[0], cdr.Transfer[1], cdr.Transfer[2]); diff --git a/pcsx2/CDVD/IsoFileFormats.cpp b/pcsx2/CDVD/IsoFileFormats.cpp index fb0f8a4d67..80a29f6221 100644 --- a/pcsx2/CDVD/IsoFileFormats.cpp +++ b/pcsx2/CDVD/IsoFileFormats.cpp @@ -29,12 +29,12 @@ int detect(isoFile *iso) { u8 buf[2448]; - struct cdVolDesc *volDesc; + cdVolDesc *volDesc; - if (isoReadBlock(iso, buf + iso->blockofs, 16) == -1) return -1; - - volDesc = (struct cdVolDesc *)(buf + 24); + if (isoReadBlock(iso, buf, 16) == -1) return -1; + volDesc = (cdVolDesc *) (( iso->flags & ISOFLAGS_BLOCKDUMP_V3 ) ? buf : (buf + 24)); + if (strncmp((char*)volDesc->volID, "CD001", 5)) return 0; if (volDesc->rootToc.tocSize == 2048) @@ -87,7 +87,16 @@ int isoDetect(isoFile *iso) // based on florin's CDVDbin detection code :) if (strncmp(buf, "BDV2", 4) == 0) { - iso->flags = ISOFLAGS_BLOCKDUMP; + iso->flags = ISOFLAGS_BLOCKDUMP_V2; + _readfile(iso->handle, &iso->blocksize, 4); + _readfile(iso->handle, &iso->blocks, 4); + _readfile(iso->handle, &iso->blockofs, 4); + _isoReadDtable(iso); + return (detect(iso) == 1) ? 0 : -1; + } + else if (strncmp(buf, "BDV3", 4) == 0) + { + iso->flags = ISOFLAGS_BLOCKDUMP_V3; _readfile(iso->handle, &iso->blocksize, 4); _readfile(iso->handle, &iso->blocks, 4); _readfile(iso->handle, &iso->blockofs, 4); @@ -111,7 +120,7 @@ int isoDetect(isoFile *iso) // based on florin's CDVDbin detection code :) if (tryIsoType(iso, 2448, -8, 0)) return 0; // RAWQ 2448 iso->offset = 0; - iso->blocksize = 2352; + iso->blocksize = CD_FRAMESIZE_RAW; iso->blockofs = 0; iso->type = ISOTYPE_AUDIO; return 0; @@ -232,13 +241,19 @@ int isoSetFormat(isoFile *iso, int blockofs, int blocksize, int blocks) Console::WriteLn("blocksize = %d", params iso->blocksize); Console::WriteLn("blocks = %d", params iso->blocks); - if (iso->flags & ISOFLAGS_BLOCKDUMP) + if (iso->flags & ISOFLAGS_BLOCKDUMP_V2) { if (_writefile(iso->handle, "BDV2", 4) < 4) return -1; if (_writefile(iso->handle, &blocksize, 4) < 4) return -1; if (_writefile(iso->handle, &blocks, 4) < 4) return -1; if (_writefile(iso->handle, &blockofs, 4) < 4) return -1; } + else if (iso->flags & ISOFLAGS_BLOCKDUMP_V3) + { + if (_writefile(iso->handle, "BDV3", 4) < 4) return -1; + if (_writefile(iso->handle, &blocksize, 4) < 4) return -1; + if (_writefile(iso->handle, &blocks, 4) < 4) return -1; + } return 0; } @@ -275,7 +290,7 @@ int _isoReadBlock(isoFile *iso, u8 *dst, int lsn) memset(dst, 0, iso->blockofs); _seekfile(iso->handle, ofs, SEEK_SET); - ret = _readfile(iso->handle, dst, iso->blocksize); + ret = _readfile(iso->handle, dst + iso->blockofs, iso->blocksize); if (ret < iso->blocksize) { @@ -293,13 +308,13 @@ int _isoReadBlockD(isoFile *iso, u8 *dst, int lsn) // Console::WriteLn("_isoReadBlockD %d, blocksize=%d, blockofs=%d\n", params lsn, iso->blocksize, iso->blockofs); memset(dst, 0, iso->blockofs); - for (int i = 0; i < iso->dtablesize;i++) + for (int i = 0; i < iso->dtablesize; i++) { if (iso->dtable[i] != lsn) continue; _seekfile(iso->handle, 16 + i * (iso->blocksize + 4) + 4, SEEK_SET); - ret = _readfile(iso->handle, dst, iso->blocksize); - + ret = _readfile(iso->handle, dst + iso->blockofs, iso->blocksize); + if (ret < iso->blocksize) return -1; return 0; @@ -330,7 +345,7 @@ int _isoReadBlockM(isoFile *iso, u8 *dst, int lsn) memset(dst, 0, iso->blockofs); _seekfile(iso->multih[i].handle, ofs, SEEK_SET); - ret = _readfile(iso->multih[i].handle, dst, iso->blocksize); + ret = _readfile(iso->multih[i].handle, dst + iso->blockofs, iso->blocksize); if (ret < iso->blocksize) { @@ -351,7 +366,9 @@ int isoReadBlock(isoFile *iso, u8 *dst, int lsn) return -1; } - if (iso->flags & ISOFLAGS_BLOCKDUMP) + if (iso->flags & ISOFLAGS_BLOCKDUMP_V2) + ret = _isoReadBlockD(iso, dst, lsn); + else if( iso->flags & ISOFLAGS_BLOCKDUMP_V3 ) ret = _isoReadBlockD(iso, dst, lsn); else if (iso->flags & ISOFLAGS_MULTI) ret = _isoReadBlockM(iso, dst, lsn); @@ -362,13 +379,8 @@ int isoReadBlock(isoFile *iso, u8 *dst, int lsn) if (iso->type == ISOTYPE_CD) { - // This is weird voodoo mess that does some kind of time adjustment on the - // block headers of CD-Rom images. hackfixed it to work with 24 byte block - // offsets... no idea if it'll work with others. - DevAssert( iso->blockofs == 24, "Undocumented CD-Rom checkpoint." ); - - LSNtoMSF(dst - iso->blockofs + 12, lsn); - dst[15-iso->blockofs] = 2; + LSNtoMSF(dst + 12, lsn); + dst[15] = 2; } return 0; @@ -381,7 +393,7 @@ int _isoWriteBlock(isoFile *iso, u8 *src, int lsn) u64 ofs = (u64)lsn * iso->blocksize + iso->offset; _seekfile(iso->handle, ofs, SEEK_SET); - ret = _writefile(iso->handle, src, iso->blocksize); + ret = _writefile(iso->handle, src + iso->blockofs, iso->blocksize); if (ret < iso->blocksize) return -1; return 0; @@ -395,7 +407,7 @@ int _isoWriteBlockD(isoFile *iso, u8 *src, int lsn) ret = _writefile(iso->handle, &lsn, 4); if (ret < 4) return -1; - ret = _writefile(iso->handle, src, iso->blocksize); + ret = _writefile(iso->handle, src + iso->blockofs, iso->blocksize); // Console::WriteLn("_isoWriteBlock %d", params ret); @@ -406,15 +418,10 @@ int _isoWriteBlockD(isoFile *iso, u8 *src, int lsn) int isoWriteBlock(isoFile *iso, u8 *src, int lsn) { - int ret; - - if (iso->flags & ISOFLAGS_BLOCKDUMP) - ret = _isoWriteBlockD(iso, src, lsn); + if (iso->flags & ISOFLAGS_BLOCKDUMP_V3) + return _isoWriteBlockD(iso, src, lsn); else - ret = _isoWriteBlock(iso, src, lsn); - - if (ret == -1) return -1; - return 0; + return _isoWriteBlock(iso, src, lsn); } void isoClose(isoFile *iso) diff --git a/pcsx2/CDVD/IsoFileFormats.h b/pcsx2/CDVD/IsoFileFormats.h index 0645e7d36f..d57be8bbae 100644 --- a/pcsx2/CDVD/IsoFileFormats.h +++ b/pcsx2/CDVD/IsoFileFormats.h @@ -35,13 +35,14 @@ enum isoFlags { ISOFLAGS_Z = 0x0001, ISOFLAGS_Z2 = 0x0002, - ISOFLAGS_BLOCKDUMP = 0x0004, + ISOFLAGS_BLOCKDUMP_V2 = 0x0004, ISOFLAGS_MULTI = 0x0008, - ISOFLAGS_BZ2 = 0x0010 + ISOFLAGS_BZ2 = 0x0010, + ISOFLAGS_BLOCKDUMP_V3 = 0x0020 }; -#define CD_FRAMESIZE_RAW 2352 -#define DATA_SIZE (CD_FRAMESIZE_RAW-12) +static const int CD_FRAMESIZE_RAW = 2352; +static const int CD_DATA_SIZE = CD_FRAMESIZE_RAW - 12; //#define itob(i) ((i)/10*16 + (i)%10) /* u_char to BCD */ //#define btoi(b) ((b)/16*10 + (b)%16) /* BCD to u_char */ @@ -73,12 +74,12 @@ struct isoFile }; -isoFile *isoOpen(const char *filename); -isoFile *isoCreate(const char *filename, int mode); -int isoSetFormat(isoFile *iso, int blockofs, int blocksize, int blocks); -int isoDetect(isoFile *iso); -int isoReadBlock(isoFile *iso, u8 *dst, int lsn); -int isoWriteBlock(isoFile *iso, u8 *src, int lsn); -void isoClose(isoFile *iso); +extern isoFile *isoOpen(const char *filename); +extern isoFile *isoCreate(const char *filename, int mode); +extern int isoSetFormat(isoFile *iso, int blockofs, int blocksize, int blocks); +extern int isoDetect(isoFile *iso); +extern int isoReadBlock(isoFile *iso, u8 *dst, int lsn); +extern int isoWriteBlock(isoFile *iso, u8 *src, int lsn); +extern void isoClose(isoFile *iso); #endif /* __LIBISO_H__ */ diff --git a/pcsx2/CDVD/IsoFileTools.cpp b/pcsx2/CDVD/IsoFileTools.cpp index c69f18b71b..f7f253e644 100644 --- a/pcsx2/CDVD/IsoFileTools.cpp +++ b/pcsx2/CDVD/IsoFileTools.cpp @@ -38,7 +38,7 @@ void *_openfile(const char *filename, int flags) handle = CreateFile(filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL); } - return handle == INVALID_HANDLE_VALUE ? NULL : handle; + return (handle == INVALID_HANDLE_VALUE) ? NULL : handle; } u64 _tellfile(void *handle) diff --git a/pcsx2/Plugins.cpp b/pcsx2/Plugins.cpp index a523321f07..ecfc55367b 100644 --- a/pcsx2/Plugins.cpp +++ b/pcsx2/Plugins.cpp @@ -485,7 +485,7 @@ static void CALLBACK CDVD_about() {} static s32 CALLBACK CDVD_test() { return 0; } static void CALLBACK CDVD_newDiskCB(void (*callback)()) {} -extern int lastReadSize; +extern int lastReadSize, lastLSN; static s32 CALLBACK CDVD_getBuffer2(u8* buffer) { // TEMP: until I fix all the plugins to use this function style @@ -517,6 +517,8 @@ static s32 CALLBACK CDVD_readSector(u8* buffer, u32 lsn, int mode) lastReadSize = 2048; break; } + + lastLSN = lsn; return CDVD->getBuffer2(buffer); }