X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=libpcsxcore%2Fcdriso.c;h=07adbe6743ad817ff6adaede5bcc9abe66e2fe40;hb=679b71e250ce6557f05b57882747029ab6af7edc;hp=7007f551a377ec5cc4544f07a08bad6173f62f48;hpb=4e0deb4b36b49a45061098fc531556bb6cea3e9e;p=pcsx_rearmed.git diff --git a/libpcsxcore/cdriso.c b/libpcsxcore/cdriso.c index 7007f551..07adbe67 100644 --- a/libpcsxcore/cdriso.c +++ b/libpcsxcore/cdriso.c @@ -27,7 +27,9 @@ #include #include +#ifdef HAVE_CHD #include +#endif #ifdef _WIN32 #define WIN32_LEAN_AND_MEAN @@ -94,6 +96,7 @@ static struct { unsigned int sector_in_blk; } *compr_img; +#ifdef HAVE_CHD static struct { unsigned char (*buffer)[CD_FRAMESIZE_RAW + SUB_FRAMESIZE]; chd_file* chd; @@ -102,6 +105,7 @@ static struct { unsigned int current_hunk; unsigned int sector_in_hunk; } *chd_img; +#endif int (*cdimg_read_func)(FILE *f, unsigned int base, void *dest, int sector); @@ -1039,6 +1043,7 @@ fail_io: return -1; } +#ifdef HAVE_CHD static int handlechd(const char *isofile) { chd_img = calloc(1, sizeof(*chd_img)); if (chd_img == NULL) @@ -1110,6 +1115,7 @@ fail_io: } return -1; } +#endif // this function tries to get the .sub file of the given .img static int opensubfile(const char *isoname) { @@ -1134,13 +1140,18 @@ static int opensubfile(const char *isoname) { } static int opensbifile(const char *isoname) { - char sbiname[MAXPATHLEN]; + char sbiname[MAXPATHLEN], disknum[MAXPATHLEN] = "0"; int s; strncpy(sbiname, isoname, sizeof(sbiname)); sbiname[MAXPATHLEN - 1] = '\0'; if (strlen(sbiname) >= 4) { - strcpy(sbiname + strlen(sbiname) - 4, ".sbi"); + if (cdrIsoMultidiskCount > 1) { + sprintf(disknum, "_%i.sbi", cdrIsoMultidiskSelect + 1); + strcpy(sbiname + strlen(sbiname) - 4, disknum); + } + else + strcpy(sbiname + strlen(sbiname) - 4, ".sbi"); } else { return -1; @@ -1152,6 +1163,194 @@ static int opensbifile(const char *isoname) { return LoadSBI(sbiname, s); } +#ifdef _WIN32 +static void readThreadStop() {} +static void readThreadStart() {} +#else +static pthread_t read_thread_id; + +static pthread_cond_t read_thread_msg_avail; +static pthread_cond_t read_thread_msg_done; +static pthread_mutex_t read_thread_msg_lock; + +static pthread_cond_t sectorbuffer_cond; +static pthread_mutex_t sectorbuffer_lock; + +static boolean read_thread_running = FALSE; +static int read_thread_sector_start = -1; +static int read_thread_sector_end = -1; + +typedef struct { + int sector; + long ret; + unsigned char data[CD_FRAMESIZE_RAW]; +} SectorBufferEntry; + +#define SECTOR_BUFFER_SIZE 4096 + +static SectorBufferEntry *sectorbuffer; +static size_t sectorbuffer_index; + +int (*sync_cdimg_read_func)(FILE *f, unsigned int base, void *dest, int sector); +unsigned char *(*sync_CDR_getBuffer)(void); + +static unsigned char * CALLBACK ISOgetBuffer_async(void); +static int cdread_async(FILE *f, unsigned int base, void *dest, int sector); + +static void *readThreadMain(void *param) { + int max_sector = -1; + int requested_sector_start = -1; + int requested_sector_end = -1; + int last_read_sector = -1; + int index = 0; + + int ra_sector = -1; + int max_ra = 128; + int initial_ra = 1; + int speedmult_ra = 4; + + int ra_count = 0; + int how_far_ahead = 0; + + unsigned char tmpdata[CD_FRAMESIZE_RAW]; + long ret; + + max_sector = msf2sec(ti[numtracks].start) + msf2sec(ti[numtracks].length); + + while(1) { + pthread_mutex_lock(&read_thread_msg_lock); + + // If we don't have readahead and we don't have a sector request, wait for one. + // If we still have readahead to go, don't block, just keep going. + // And if we ever have a sector request pending, acknowledge and reset it. + + if (!ra_count) { + if (read_thread_sector_start == -1 && read_thread_running) { + pthread_cond_wait(&read_thread_msg_avail, &read_thread_msg_lock); + } + } + + if (read_thread_sector_start != -1) { + requested_sector_start = read_thread_sector_start; + requested_sector_end = read_thread_sector_end; + read_thread_sector_start = -1; + read_thread_sector_end = -1; + pthread_cond_signal(&read_thread_msg_done); + } + + pthread_mutex_unlock(&read_thread_msg_lock); + + if (!read_thread_running) + break; + + // Readahead code, based on the implementation in mednafen psx's cdromif.cpp + if (requested_sector_start != -1) { + if (last_read_sector != -1 && last_read_sector == (requested_sector_start - 1)) { + how_far_ahead = ra_sector - requested_sector_end; + + if(how_far_ahead <= max_ra) + ra_count = (max_ra - how_far_ahead + 1 ? max_ra - how_far_ahead + 1 : speedmult_ra); + else + ra_count++; + } else if (requested_sector_end != last_read_sector) { + ra_sector = requested_sector_end; + ra_count = initial_ra; + } + + last_read_sector = requested_sector_end; + } + + // check for end of CD + if (ra_count && ra_sector >= max_sector) { + ra_count = 0; + } + + if (ra_count) { + + index = ra_sector % SECTOR_BUFFER_SIZE; + pthread_mutex_lock(§orbuffer_lock); + if (sectorbuffer[index].sector != ra_sector) { + pthread_mutex_unlock(§orbuffer_lock); + + ret = sync_cdimg_read_func(cdHandle, 0, tmpdata, ra_sector); + + pthread_mutex_lock(§orbuffer_lock); + sectorbuffer[index].ret = ret; + sectorbuffer[index].sector = ra_sector; + memcpy(sectorbuffer[index].data, tmpdata, CD_FRAMESIZE_RAW); + } + pthread_cond_signal(§orbuffer_cond); + pthread_mutex_unlock(§orbuffer_lock); + + ra_sector++; + ra_count--; + } + } + + return NULL; +} + +static void readThreadStop() { + if (read_thread_running == TRUE) { + read_thread_running = FALSE; + pthread_cond_signal(&read_thread_msg_avail); + pthread_join(read_thread_id, NULL); + } + + pthread_cond_destroy(&read_thread_msg_done); + pthread_cond_destroy(&read_thread_msg_avail); + pthread_mutex_destroy(&read_thread_msg_lock); + + pthread_cond_destroy(§orbuffer_cond); + pthread_mutex_destroy(§orbuffer_lock); + + CDR_getBuffer = sync_CDR_getBuffer; + cdimg_read_func = sync_cdimg_read_func; + + free(sectorbuffer); + sectorbuffer = NULL; +} + +static void readThreadStart() { + SysPrintf("Starting async CD thread\n"); + + if (read_thread_running == TRUE) + return; + + read_thread_running = TRUE; + read_thread_sector_start = -1; + read_thread_sector_end = -1; + sectorbuffer_index = 0; + + sectorbuffer = calloc(SECTOR_BUFFER_SIZE, sizeof(SectorBufferEntry)); + if(!sectorbuffer) + goto error; + + sectorbuffer[0].sector = -1; // Otherwise we might think we've already fetched sector 0! + + sync_CDR_getBuffer = CDR_getBuffer; + CDR_getBuffer = ISOgetBuffer_async; + sync_cdimg_read_func = cdimg_read_func; + cdimg_read_func = cdread_async; + + if (pthread_cond_init(&read_thread_msg_avail, NULL) || + pthread_cond_init(&read_thread_msg_done, NULL) || + pthread_mutex_init(&read_thread_msg_lock, NULL) || + pthread_cond_init(§orbuffer_cond, NULL) || + pthread_mutex_init(§orbuffer_lock, NULL) || + pthread_create(&read_thread_id, NULL, readThreadMain, NULL)) + goto error; + + return; + + error: + SysPrintf("Error starting async CD thread\n"); + SysPrintf("Falling back to sync\n"); + + readThreadStop(); +} +#endif + static int cdread_normal(FILE *f, unsigned int base, void *dest, int sector) { fseek(f, base + sector * CD_FRAMESIZE_RAW, SEEK_SET); @@ -1272,6 +1471,7 @@ finish: return CD_FRAMESIZE_RAW; } +#ifdef HAVE_CHD static int cdread_chd(FILE *f, unsigned int base, void *dest, int sector) { int hunk; @@ -1295,7 +1495,7 @@ finish: CD_FRAMESIZE_RAW); return CD_FRAMESIZE_RAW; } - +#endif static int cdread_2048(FILE *f, unsigned int base, void *dest, int sector) { int ret; @@ -1311,13 +1511,74 @@ static int cdread_2048(FILE *f, unsigned int base, void *dest, int sector) return ret; } +#ifndef _WIN32 + +static int cdread_async(FILE *f, unsigned int base, void *dest, int sector) { + boolean found = FALSE; + int i = sector % SECTOR_BUFFER_SIZE; + long ret; + + if (f != cdHandle || base != 0 || dest != cdbuffer) { + // Async reads are only supported for cdbuffer, so call the sync + // function directly. + return sync_cdimg_read_func(f, base, dest, sector); + } + + pthread_mutex_lock(&read_thread_msg_lock); + + // Only wait if we're not trying to read the next sector and + // sector_start is set (meaning the last request hasn't been + // processed yet) + while(read_thread_sector_start != -1 && read_thread_sector_end + 1 != sector) { + pthread_cond_wait(&read_thread_msg_done, &read_thread_msg_lock); + } + + if (read_thread_sector_start == -1) + read_thread_sector_start = sector; + + read_thread_sector_end = sector; + pthread_cond_signal(&read_thread_msg_avail); + pthread_mutex_unlock(&read_thread_msg_lock); + + do { + pthread_mutex_lock(§orbuffer_lock); + if (sectorbuffer[i].sector == sector) { + sectorbuffer_index = i; + ret = sectorbuffer[i].ret; + found = TRUE; + } + + if (!found) { + pthread_cond_wait(§orbuffer_cond, §orbuffer_lock); + } + pthread_mutex_unlock(§orbuffer_lock); + } while (!found); + + return ret; +} + +#endif + static unsigned char * CALLBACK ISOgetBuffer_compr(void) { return compr_img->buff_raw[compr_img->sector_in_blk] + 12; } +#ifdef HAVE_CHD static unsigned char * CALLBACK ISOgetBuffer_chd(void) { return chd_img->buffer[chd_img->sector_in_hunk] + 12; } +#endif + +#ifndef _WIN32 +static unsigned char * CALLBACK ISOgetBuffer_async(void) { + unsigned char *buffer; + pthread_mutex_lock(§orbuffer_lock); + buffer = sectorbuffer[sectorbuffer_index].data; + pthread_mutex_unlock(§orbuffer_lock); + return buffer + 12; +} + +#endif static unsigned char * CALLBACK ISOgetBuffer(void) { return cdbuffer + 12; @@ -1340,6 +1601,7 @@ static long CALLBACK ISOopen(void) { boolean isMode1ISO = FALSE; char alt_bin_filename[MAXPATHLEN]; const char *bin_filename; + char image_str[1024] = {0}; if (cdHandle != NULL) { return 0; // it's already open @@ -1352,7 +1614,7 @@ static long CALLBACK ISOopen(void) { return -1; } - SysPrintf(_("Loaded CD Image: %s"), GetIsoFile()); + sprintf(image_str, "Loaded CD Image: %s", GetIsoFile()); cddaBigEndian = FALSE; subChanMixed = FALSE; @@ -1365,38 +1627,40 @@ static long CALLBACK ISOopen(void) { cdimg_read_func = cdread_normal; if (parsetoc(GetIsoFile()) == 0) { - SysPrintf("[+toc]"); + strcat(image_str, "[+toc]"); } else if (parseccd(GetIsoFile()) == 0) { - SysPrintf("[+ccd]"); + strcat(image_str, "[+ccd]"); } else if (parsemds(GetIsoFile()) == 0) { - SysPrintf("[+mds]"); + strcat(image_str, "[+mds]"); } else if (parsecue(GetIsoFile()) == 0) { - SysPrintf("[+cue]"); + strcat(image_str, "[+cue]"); } if (handlepbp(GetIsoFile()) == 0) { - SysPrintf("[pbp]"); + strcat(image_str, "[+pbp]"); CDR_getBuffer = ISOgetBuffer_compr; cdimg_read_func = cdread_compressed; } else if (handlecbin(GetIsoFile()) == 0) { - SysPrintf("[cbin]"); + strcat(image_str, "[+cbin]"); CDR_getBuffer = ISOgetBuffer_compr; cdimg_read_func = cdread_compressed; } +#ifdef HAVE_CHD else if (handlechd(GetIsoFile()) == 0) { - SysPrintf("[chd]"); + strcat(image_str, "[+chd]"); CDR_getBuffer = ISOgetBuffer_chd; cdimg_read_func = cdread_chd; } +#endif if (!subChanMixed && opensubfile(GetIsoFile()) == 0) { - SysPrintf("[+sub]"); + strcat(image_str, "[+sub]"); } if (opensbifile(GetIsoFile()) == 0) { - SysPrintf("[+sbi]"); + strcat(image_str, "[+sbi]"); } fseeko(cdHandle, 0, SEEK_END); @@ -1434,13 +1698,13 @@ static long CALLBACK ISOopen(void) { fseek(cdHandle, 0, SEEK_SET); fread(&modeTest, 4, 1, cdHandle); if (SWAP32(modeTest) != 0xffffff00) { - SysPrintf("[2048]"); + strcat(image_str, "[2048]"); isMode1ISO = TRUE; } } fseek(cdHandle, 0, SEEK_SET); - SysPrintf(".\n"); + SysPrintf("%s.\n", image_str); PrintTracks(); @@ -1456,6 +1720,9 @@ static long CALLBACK ISOopen(void) { cdda_cur_sector = 0; cdda_file_offset = 0; + if (Config.AsyncCD) { + readThreadStart(); + } return 0; } @@ -1479,12 +1746,14 @@ static long CALLBACK ISOclose(void) { compr_img = NULL; } +#ifdef HAVE_CHD if (chd_img != NULL) { chd_close(chd_img->chd); free(chd_img->buffer); free(chd_img); chd_img = NULL; } +#endif for (i = 1; i <= numtracks; i++) { if (ti[i].handle != NULL) { @@ -1499,6 +1768,7 @@ static long CALLBACK ISOclose(void) { memset(cdbuffer, 0, sizeof(cdbuffer)); CDR_getBuffer = ISOgetBuffer; + readThreadStop(); return 0; }