From da31028324b365261bb0d0fcfd86abccd4df2529 Mon Sep 17 00:00:00 2001 From: notaz Date: Wed, 26 Mar 2008 19:00:40 +0000 Subject: [PATCH] experimental thread I/O code, fps counter fix git-svn-id: file:///home/notaz/opt/svn/PicoDrive@396 be3aeb3a-fb24-0410-a615-afba39da0efa --- Pico/cd/buffering.c | 145 +++++++++++++++++++++++++++++- platform/base_readme.txt | 2 + platform/gizmondo/emu.c | 4 +- platform/gp2x/emu.c | 187 ++++++++++++++++++++------------------- platform/psp/emu.c | 4 +- 5 files changed, 245 insertions(+), 97 deletions(-) diff --git a/Pico/cd/buffering.c b/Pico/cd/buffering.c index 205e7777..965c031b 100644 --- a/Pico/cd/buffering.c +++ b/Pico/cd/buffering.c @@ -9,6 +9,125 @@ static int prev_lba = 0x80000000; static int hits, reads; +//#define THREADED_CD_IO + +/* threaded reader */ +#ifdef THREADED_CD_IO +#include +#define tioprintf printf + +static pthread_t thr_thread = 0; +static pthread_cond_t thr_cond = PTHREAD_COND_INITIALIZER; +static pthread_mutex_t thr_mutex = PTHREAD_MUTEX_INITIALIZER; +static unsigned char *thr_buffer[2][2048 + 304] __attribute__((aligned(4))); +static int thr_lba_need; +static int thr_lba_have[2]; + +static void thr_read_lba(int slot, int lba) +{ + int is_bin = Pico_mcd->TOC.Tracks[0].ftype == TYPE_BIN; + int where_seek = is_bin ? (lba * 2352 + 16) : (lba << 11); + + pm_seek(Pico_mcd->TOC.Tracks[0].F, where_seek, SEEK_SET); + pm_read(thr_buffer[slot], 2048, Pico_mcd->TOC.Tracks[0].F); + thr_lba_have[slot] = lba; +} + +static void *buffering_thread(void *arg) +{ + int free_slot, lba; + + elprintf(EL_STATUS, "CD I/O thread started."); + + pthread_mutex_lock(&thr_mutex); + + while (1) + { + if (thr_lba_need < 0) goto wait; + + free_slot = -1; + if (thr_lba_have[0] == -1) free_slot = 0; + if (thr_lba_have[1] == -1) free_slot = 1; + if (free_slot == -1) goto wait; + + lba = thr_lba_need; + if (lba != thr_lba_have[free_slot^1]) { + thr_read_lba(free_slot, lba); + tioprintf("t done %i %i\n", lba, free_slot); + continue; + } + lba++; + if (lba != thr_lba_have[free_slot^1]) { + thr_read_lba(free_slot, lba); + tioprintf("t done %i %i\n", lba, free_slot); + continue; + } + +wait: + pthread_cond_wait(&thr_cond, &thr_mutex); + tioprintf("t wake\n"); + } + + pthread_mutex_unlock(&thr_mutex); + + return NULL; +} + +static void threaded_read(void *dest, int lba) +{ + int i, have = -1; + tioprintf("\n"); + + if (lba == thr_lba_have[0]) have = 0; + if (lba == thr_lba_have[1]) have = 1; + if (have != -1) + { + tioprintf("r hit %i %i\n", lba, have); + memcpy32(dest, (int *)thr_buffer[have], 2048/4); + if (lba != prev_lba) { + thr_lba_have[have] = -1; // make free slot + thr_lba_need = lba + 1; // guess a sequential read.. + pthread_cond_signal(&thr_cond); + sched_yield(); + prev_lba = lba; + } + return; + } + + tioprintf("r miss %i\n", lba); + thr_lba_need = lba; + pthread_mutex_lock(&thr_mutex); + pthread_mutex_unlock(&thr_mutex); + if (lba == thr_lba_have[0]) have = 0; + if (lba == thr_lba_have[1]) have = 1; + if (have == -1) + { + // try again.. + thr_lba_have[0] = thr_lba_have[1] = -1; + for (i = 0; have == -1 && i < 10; i++) + { + tioprintf("r hard %i\n", lba); + pthread_cond_signal(&thr_cond); + sched_yield(); + pthread_mutex_lock(&thr_mutex); + pthread_mutex_unlock(&thr_mutex); + if (lba == thr_lba_have[0]) have = 0; + if (lba == thr_lba_have[1]) have = 1; + } + } + + // we MUST have the data at this point.. + if (have == -1) { tioprintf("BUG!\n"); exit(1); } + tioprintf("r reco %i %i\n", lba, have); + memcpy32(dest, (int *)thr_buffer[have], 2048/4); + thr_lba_have[have] = -1; + pthread_cond_signal(&thr_cond); + + prev_lba = lba; + return; +} +#endif + void PicoCDBufferInit(void) { @@ -16,10 +135,11 @@ void PicoCDBufferInit(void) prev_lba = 0x80000000; hits = reads = 0; + cd_buffer = NULL; if (PicoCDBuffers <= 1) { PicoCDBuffers = 0; - return; /* buffering off */ + goto no_buffering; /* buffering off */ } /* try alloc'ing until we succeed */ @@ -30,14 +150,28 @@ void PicoCDBufferInit(void) PicoCDBuffers >>= 1; } - if (PicoCDBuffers <= 0) return; /* buffering became off */ + if (PicoCDBuffers > 0) { + cd_buffer = tmp; + return; + } - cd_buffer = tmp; +no_buffering:; +#ifdef THREADED_CD_IO + thr_lba_need = thr_lba_have[0] = thr_lba_have[1] = -1; + if (thr_thread == 0) + { + pthread_create(&thr_thread, NULL, buffering_thread, NULL); + } +#endif } void PicoCDBufferFree(void) { +#ifdef THREADED_CD_IO + pthread_mutex_lock(&thr_mutex); + pthread_mutex_unlock(&thr_mutex); +#endif if (cd_buffer) { free(cd_buffer); cd_buffer = NULL; @@ -57,11 +191,16 @@ PICO_INTERNAL void PicoCDBufferRead(void *dest, int lba) if (PicoCDBuffers <= 0) { +#ifdef THREADED_CD_IO + threaded_read(dest, lba); + return; +#else /* no buffering */ int where_seek = is_bin ? (lba * 2352 + 16) : (lba << 11); pm_seek(Pico_mcd->TOC.Tracks[0].F, where_seek, SEEK_SET); pm_read(dest, 2048, Pico_mcd->TOC.Tracks[0].F); return; +#endif } /* hit? */ diff --git a/platform/base_readme.txt b/platform/base_readme.txt index 947ac98a..1a13a4d7 100644 --- a/platform/base_readme.txt +++ b/platform/base_readme.txt @@ -643,6 +643,8 @@ Changelog configs are now held in single file (but old game config files are still read). * Fixed a bug where some key combos didn't work. + * Fixed a regression in renderer (rare graphic glitches). + * Adjusted fast rernderer to work with more games, including VR. 1.35b * PSP: mp3 code should no longer fail on 1.5 firmware. diff --git a/platform/gizmondo/emu.c b/platform/gizmondo/emu.c index 82c3dddb..523da879 100644 --- a/platform/gizmondo/emu.c +++ b/platform/gizmondo/emu.c @@ -458,10 +458,10 @@ static void updateKeys(void) pl = (acts >> 16) & 1; if (kb_combo_keys & (1 << i)) { - int u, acts_c = acts & kb_combo_acts; + int u = i+1, acts_c = acts & kb_combo_acts; // let's try to find the other one if (acts_c) { - for (u = i + 1; u < 32; u++) + for (; u < 32; u++) if ( (keys & (1 << u)) && (currentConfig.KeyBinds[u] & acts_c) ) { allActions[pl] |= acts_c & currentConfig.KeyBinds[u]; keys &= ~((1 << i) | (1 << u)); diff --git a/platform/gp2x/emu.c b/platform/gp2x/emu.c index f251188e..a3e7f83e 100644 --- a/platform/gp2x/emu.c +++ b/platform/gp2x/emu.c @@ -11,6 +11,7 @@ #include #include #include +#include #include @@ -541,10 +542,10 @@ static void updateKeys(void) pl = (acts >> 16) & 1; if (kb_combo_keys & (1 << i)) { - int u, acts_c = acts & kb_combo_acts; + int u = i+1, acts_c = acts & kb_combo_acts; // let's try to find the other one if (acts_c) { - for (u = i + 1; u < 32; u++) + for (; u < 32; u++) if ( (keys & (1 << u)) && (currentConfig.KeyBinds[u] & acts_c) ) { allActions[pl] |= acts_c & currentConfig.KeyBinds[u]; keys &= ~((1 << i) | (1 << u)); @@ -650,25 +651,78 @@ static void simpleWait(int thissec, int lim_time) spend_cycles(1024); gettimeofday(&tval, 0); - if(thissec != tval.tv_sec) tval.tv_usec+=1000000; + if (thissec != tval.tv_sec) tval.tv_usec+=1000000; - while(tval.tv_usec < lim_time) + if (tval.tv_usec < lim_time) + sched_yield(); + + while (tval.tv_usec < lim_time) { spend_cycles(1024); gettimeofday(&tval, 0); - if(thissec != tval.tv_sec) tval.tv_usec+=1000000; + if (thissec != tval.tv_sec) tval.tv_usec+=1000000; } } +#if 0 +static void tga_dump(void) +{ +#define BYTE unsigned char +#define WORD unsigned short + struct + { + BYTE IDLength; /* 00h Size of Image ID field */ + BYTE ColorMapType; /* 01h Color map type */ + BYTE ImageType; /* 02h Image type code */ + WORD CMapStart; /* 03h Color map origin */ + WORD CMapLength; /* 05h Color map length */ + BYTE CMapDepth; /* 07h Depth of color map entries */ + WORD XOffset; /* 08h X origin of image */ + WORD YOffset; /* 0Ah Y origin of image */ + WORD Width; /* 0Ch Width of image */ + WORD Height; /* 0Eh Height of image */ + BYTE PixelDepth; /* 10h Image pixel size */ + BYTE ImageDescriptor; /* 11h Image descriptor byte */ + } __attribute__((packed)) TGAHEAD; + static unsigned short oldscr[320*240]; + FILE *f; char name[128]; int i; + + memset(&TGAHEAD, 0, sizeof(TGAHEAD)); + TGAHEAD.ImageType = 2; + TGAHEAD.Width = 320; + TGAHEAD.Height = 240; + TGAHEAD.PixelDepth = 16; + TGAHEAD.ImageDescriptor = 2<<4; // image starts at top-left + +#define CONV(X) (((X>>1)&0x7fe0)|(X&0x1f)) // 555? + + for (i = 0; i < 320*240; i++) + if(oldscr[i] != CONV(((unsigned short *)gp2x_screen)[i])) break; + if (i < 320*240) + { + for (i = 0; i < 320*240; i++) + oldscr[i] = CONV(((unsigned short *)gp2x_screen)[i]); + sprintf(name, "%05i.tga", Pico.m.frame_count); + f = fopen(name, "wb"); + if (!f) { printf("!f\n"); exit(1); } + fwrite(&TGAHEAD, 1, sizeof(TGAHEAD), f); + fwrite(oldscr, 1, 320*240*2, f); + fclose(f); + } +} +#endif + + void emu_Loop(void) { static int gp2x_old_clock = 200; static int PsndRate_old = 0, PicoOpt_old = 0, EmuOpt_old = 0, pal_old = 0; char fpsbuff[24]; // fps count c string struct timeval tval; // timing - int thissec = 0, frames_done = 0, frames_shown = 0, oldmodes = 0; - int target_fps, target_frametime, lim_time, vsync_offset, i; + int pframes_done, pframes_shown, pthissec; // "period" frames, used for sync + int frames_done, frames_shown, thissec; // actual frames + int oldmodes = 0, target_fps, target_frametime, lim_time, vsync_offset, i; char *notice = 0; printf("entered emu_Loop()\n"); @@ -747,7 +801,10 @@ void emu_Loop(void) } else vsync_offset = 0; - // loop? + frames_done = frames_shown = thissec = + pframes_done = pframes_shown = pthissec = 0; + + // loop while (engineState == PGS_Running) { int modes; @@ -755,8 +812,8 @@ void emu_Loop(void) gettimeofday(&tval, 0); if (reset_timing) { reset_timing = 0; - thissec = tval.tv_sec; - frames_shown = frames_done = tval.tv_usec/target_frametime; + pthissec = tval.tv_sec; + pframes_shown = pframes_done = tval.tv_usec/target_frametime; } // show notice message? @@ -816,42 +873,50 @@ void emu_Loop(void) sprintf(fpsbuff, "%02i/%02i", frames_shown, frames_done); if (fpsbuff[5] == 0) { fpsbuff[5] = fpsbuff[6] = ' '; fpsbuff[7] = 0; } #endif + frames_shown = frames_done = 0; thissec = tval.tv_sec; + } +#ifdef PFRAMES + sprintf(fpsbuff, "%i", Pico.m.frame_count); +#endif + if (pthissec != tval.tv_sec) + { if (PsndOut == 0 && currentConfig.Frameskip >= 0) { - frames_done = frames_shown = 0; + pframes_done = pframes_shown = 0; } else { // it is quite common for this implementation to leave 1 fame unfinished // when second changes, but we don't want buffer to starve. - if(PsndOut && frames_done < target_fps && frames_done > target_fps-5) { + if(PsndOut && pframes_done < target_fps && pframes_done > target_fps-5) { updateKeys(); - SkipFrame(1); frames_done++; + SkipFrame(1); pframes_done++; } - frames_done -= target_fps; if (frames_done < 0) frames_done = 0; - frames_shown -= target_fps; if (frames_shown < 0) frames_shown = 0; - if (frames_shown > frames_done) frames_shown = frames_done; + pframes_done -= target_fps; if (pframes_done < 0) pframes_done = 0; + pframes_shown -= target_fps; if (pframes_shown < 0) pframes_shown = 0; + if (pframes_shown > pframes_done) pframes_shown = pframes_done; } + pthissec = tval.tv_sec; } -#ifdef PFRAMES - sprintf(fpsbuff, "%i", Pico.m.frame_count); -#endif - lim_time = (frames_done+1) * target_frametime + vsync_offset; - if(currentConfig.Frameskip >= 0) { // frameskip enabled + lim_time = (pframes_done+1) * target_frametime + vsync_offset; + if (currentConfig.Frameskip >= 0) // frameskip enabled + { for(i = 0; i < currentConfig.Frameskip; i++) { updateKeys(); - SkipFrame(1); frames_done++; + SkipFrame(1); pframes_done++; frames_done++; if (PsndOut && !reset_timing) { // do framelimitting if sound is enabled gettimeofday(&tval, 0); - if(thissec != tval.tv_sec) tval.tv_usec+=1000000; - if(tval.tv_usec < lim_time) { // we are too fast - simpleWait(thissec, lim_time); + if (pthissec != tval.tv_sec) tval.tv_usec+=1000000; + if (tval.tv_usec < lim_time) { // we are too fast + simpleWait(pthissec, lim_time); } } lim_time += target_frametime; } - } else if(tval.tv_usec > lim_time) { // auto frameskip + } + else if (tval.tv_usec > lim_time) // auto frameskip + { // no time left for this frame - skip if (tval.tv_usec - lim_time >= 300000) { /* something caused a slowdown for us (disk access? cache flush?) @@ -860,74 +925,16 @@ void emu_Loop(void) continue; } updateKeys(); - SkipFrame(tval.tv_usec < lim_time+target_frametime*2); frames_done++; + SkipFrame(tval.tv_usec < lim_time+target_frametime*2); pframes_done++; frames_done++; continue; } updateKeys(); PicoFrame(); -#if 0 -if (Pico.m.frame_count == 31563) { - FILE *f; - f = fopen("ram_p.bin", "wb"); - if (!f) { printf("!f\n"); exit(1); } - fwrite(Pico.ram, 1, 0x10000, f); - fclose(f); - exit(0); -} -#endif -#if 0 - // debug - { - #define BYTE unsigned char - #define WORD unsigned short - struct - { - BYTE IDLength; /* 00h Size of Image ID field */ - BYTE ColorMapType; /* 01h Color map type */ - BYTE ImageType; /* 02h Image type code */ - WORD CMapStart; /* 03h Color map origin */ - WORD CMapLength; /* 05h Color map length */ - BYTE CMapDepth; /* 07h Depth of color map entries */ - WORD XOffset; /* 08h X origin of image */ - WORD YOffset; /* 0Ah Y origin of image */ - WORD Width; /* 0Ch Width of image */ - WORD Height; /* 0Eh Height of image */ - BYTE PixelDepth; /* 10h Image pixel size */ - BYTE ImageDescriptor; /* 11h Image descriptor byte */ - } __attribute__((packed)) TGAHEAD; - static unsigned short oldscr[320*240]; - FILE *f; char name[128]; int i; - - memset(&TGAHEAD, 0, sizeof(TGAHEAD)); - TGAHEAD.ImageType = 2; - TGAHEAD.Width = 320; - TGAHEAD.Height = 240; - TGAHEAD.PixelDepth = 16; - TGAHEAD.ImageDescriptor = 2<<4; // image starts at top-left - - #define CONV(X) (((X>>1)&0x7fe0)|(X&0x1f)) // 555? - - for (i = 0; i < 320*240; i++) - if(oldscr[i] != CONV(((unsigned short *)gp2x_screen)[i])) break; - if (i < 320*240) - { - for (i = 0; i < 320*240; i++) - oldscr[i] = CONV(((unsigned short *)gp2x_screen)[i]); - sprintf(name, "%05i.tga", Pico.m.frame_count); - f = fopen(name, "wb"); - if (!f) { printf("!f\n"); exit(1); } - fwrite(&TGAHEAD, 1, sizeof(TGAHEAD), f); - fwrite(oldscr, 1, 320*240*2, f); - fclose(f); - } - } -#endif - // check time gettimeofday(&tval, 0); - if (thissec != tval.tv_sec) tval.tv_usec+=1000000; + if (pthissec != tval.tv_sec) tval.tv_usec+=1000000; if (currentConfig.Frameskip < 0 && tval.tv_usec - lim_time >= 300000) // slowdown detection reset_timing = 1; @@ -940,17 +947,18 @@ if (Pico.m.frame_count == 31563) { // we are too fast if (vsync_offset) { if (lim_time - tval.tv_usec > target_frametime/2) - simpleWait(thissec, lim_time - target_frametime/4); + simpleWait(pthissec, lim_time - target_frametime/4); gp2x_video_wait_vsync(); } else { - simpleWait(thissec, lim_time); + simpleWait(pthissec, lim_time); } } } blit(fpsbuff, notice); - frames_done++; frames_shown++; + pframes_done++; pframes_shown++; + frames_done++; frames_shown++; } change_fast_forward(0); @@ -976,4 +984,3 @@ void emu_ResetGame(void) reset_timing = 1; } - diff --git a/platform/psp/emu.c b/platform/psp/emu.c index 2ea26732..acbe643b 100644 --- a/platform/psp/emu.c +++ b/platform/psp/emu.c @@ -765,10 +765,10 @@ static void updateKeys(void) pl = (acts >> 16) & 1; if (kb_combo_keys & (1 << i)) { - int u, acts_c = acts & kb_combo_acts; + int u = i+1, acts_c = acts & kb_combo_acts; // let's try to find the other one if (acts_c) { - for (u = i + 1; u < 32; u++) + for (; u < 32; u++) if ( (keys & (1 << u)) && (currentConfig.KeyBinds[u] & acts_c) ) { allActions[pl] |= acts_c & currentConfig.KeyBinds[u]; keys &= ~((1 << i) | (1 << u)); -- 2.39.5