experimental thread I/O code, fps counter fix

git-svn-id: file:///home/notaz/opt/svn/PicoDrive@396 be3aeb3a-fb24-0410-a615-afba39da0efa
This commit is contained in:
notaz 2008-03-26 19:00:40 +00:00
parent 7b802576b2
commit da31028324
5 changed files with 251 additions and 103 deletions

View file

@ -9,6 +9,125 @@ static int prev_lba = 0x80000000;
static int hits, reads; static int hits, reads;
//#define THREADED_CD_IO
/* threaded reader */
#ifdef THREADED_CD_IO
#include <pthread.h>
#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) void PicoCDBufferInit(void)
{ {
@ -16,10 +135,11 @@ void PicoCDBufferInit(void)
prev_lba = 0x80000000; prev_lba = 0x80000000;
hits = reads = 0; hits = reads = 0;
cd_buffer = NULL;
if (PicoCDBuffers <= 1) { if (PicoCDBuffers <= 1) {
PicoCDBuffers = 0; PicoCDBuffers = 0;
return; /* buffering off */ goto no_buffering; /* buffering off */
} }
/* try alloc'ing until we succeed */ /* try alloc'ing until we succeed */
@ -30,14 +150,28 @@ void PicoCDBufferInit(void)
PicoCDBuffers >>= 1; 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) void PicoCDBufferFree(void)
{ {
#ifdef THREADED_CD_IO
pthread_mutex_lock(&thr_mutex);
pthread_mutex_unlock(&thr_mutex);
#endif
if (cd_buffer) { if (cd_buffer) {
free(cd_buffer); free(cd_buffer);
cd_buffer = NULL; cd_buffer = NULL;
@ -57,11 +191,16 @@ PICO_INTERNAL void PicoCDBufferRead(void *dest, int lba)
if (PicoCDBuffers <= 0) if (PicoCDBuffers <= 0)
{ {
#ifdef THREADED_CD_IO
threaded_read(dest, lba);
return;
#else
/* no buffering */ /* no buffering */
int where_seek = is_bin ? (lba * 2352 + 16) : (lba << 11); int where_seek = is_bin ? (lba * 2352 + 16) : (lba << 11);
pm_seek(Pico_mcd->TOC.Tracks[0].F, where_seek, SEEK_SET); pm_seek(Pico_mcd->TOC.Tracks[0].F, where_seek, SEEK_SET);
pm_read(dest, 2048, Pico_mcd->TOC.Tracks[0].F); pm_read(dest, 2048, Pico_mcd->TOC.Tracks[0].F);
return; return;
#endif
} }
/* hit? */ /* hit? */

View file

@ -643,6 +643,8 @@ Changelog
configs are now held in single file (but old game config files are still configs are now held in single file (but old game config files are still
read). read).
* Fixed a bug where some key combos didn't work. * 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 1.35b
* PSP: mp3 code should no longer fail on 1.5 firmware. * PSP: mp3 code should no longer fail on 1.5 firmware.

View file

@ -458,10 +458,10 @@ static void updateKeys(void)
pl = (acts >> 16) & 1; pl = (acts >> 16) & 1;
if (kb_combo_keys & (1 << i)) 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 // let's try to find the other one
if (acts_c) { if (acts_c) {
for (u = i + 1; u < 32; u++) for (; u < 32; u++)
if ( (keys & (1 << u)) && (currentConfig.KeyBinds[u] & acts_c) ) { if ( (keys & (1 << u)) && (currentConfig.KeyBinds[u] & acts_c) ) {
allActions[pl] |= acts_c & currentConfig.KeyBinds[u]; allActions[pl] |= acts_c & currentConfig.KeyBinds[u];
keys &= ~((1 << i) | (1 << u)); keys &= ~((1 << i) | (1 << u));

View file

@ -11,6 +11,7 @@
#include <linux/limits.h> #include <linux/limits.h>
#include <ctype.h> #include <ctype.h>
#include <unistd.h> #include <unistd.h>
#include <sched.h>
#include <stdarg.h> #include <stdarg.h>
@ -541,10 +542,10 @@ static void updateKeys(void)
pl = (acts >> 16) & 1; pl = (acts >> 16) & 1;
if (kb_combo_keys & (1 << i)) 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 // let's try to find the other one
if (acts_c) { if (acts_c) {
for (u = i + 1; u < 32; u++) for (; u < 32; u++)
if ( (keys & (1 << u)) && (currentConfig.KeyBinds[u] & acts_c) ) { if ( (keys & (1 << u)) && (currentConfig.KeyBinds[u] & acts_c) ) {
allActions[pl] |= acts_c & currentConfig.KeyBinds[u]; allActions[pl] |= acts_c & currentConfig.KeyBinds[u];
keys &= ~((1 << i) | (1 << u)); keys &= ~((1 << i) | (1 << u));
@ -650,25 +651,78 @@ static void simpleWait(int thissec, int lim_time)
spend_cycles(1024); spend_cycles(1024);
gettimeofday(&tval, 0); 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); spend_cycles(1024);
gettimeofday(&tval, 0); 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) void emu_Loop(void)
{ {
static int gp2x_old_clock = 200; static int gp2x_old_clock = 200;
static int PsndRate_old = 0, PicoOpt_old = 0, EmuOpt_old = 0, pal_old = 0; static int PsndRate_old = 0, PicoOpt_old = 0, EmuOpt_old = 0, pal_old = 0;
char fpsbuff[24]; // fps count c string char fpsbuff[24]; // fps count c string
struct timeval tval; // timing struct timeval tval; // timing
int thissec = 0, frames_done = 0, frames_shown = 0, oldmodes = 0; int pframes_done, pframes_shown, pthissec; // "period" frames, used for sync
int target_fps, target_frametime, lim_time, vsync_offset, i; int frames_done, frames_shown, thissec; // actual frames
int oldmodes = 0, target_fps, target_frametime, lim_time, vsync_offset, i;
char *notice = 0; char *notice = 0;
printf("entered emu_Loop()\n"); printf("entered emu_Loop()\n");
@ -747,7 +801,10 @@ void emu_Loop(void)
} else } else
vsync_offset = 0; vsync_offset = 0;
// loop? frames_done = frames_shown = thissec =
pframes_done = pframes_shown = pthissec = 0;
// loop
while (engineState == PGS_Running) while (engineState == PGS_Running)
{ {
int modes; int modes;
@ -755,8 +812,8 @@ void emu_Loop(void)
gettimeofday(&tval, 0); gettimeofday(&tval, 0);
if (reset_timing) { if (reset_timing) {
reset_timing = 0; reset_timing = 0;
thissec = tval.tv_sec; pthissec = tval.tv_sec;
frames_shown = frames_done = tval.tv_usec/target_frametime; pframes_shown = pframes_done = tval.tv_usec/target_frametime;
} }
// show notice message? // show notice message?
@ -816,42 +873,50 @@ void emu_Loop(void)
sprintf(fpsbuff, "%02i/%02i", frames_shown, frames_done); sprintf(fpsbuff, "%02i/%02i", frames_shown, frames_done);
if (fpsbuff[5] == 0) { fpsbuff[5] = fpsbuff[6] = ' '; fpsbuff[7] = 0; } if (fpsbuff[5] == 0) { fpsbuff[5] = fpsbuff[6] = ' '; fpsbuff[7] = 0; }
#endif #endif
frames_shown = frames_done = 0;
thissec = tval.tv_sec; thissec = tval.tv_sec;
if (PsndOut == 0 && currentConfig.Frameskip >= 0) {
frames_done = frames_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) {
updateKeys();
SkipFrame(1); frames_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;
}
} }
#ifdef PFRAMES #ifdef PFRAMES
sprintf(fpsbuff, "%i", Pico.m.frame_count); sprintf(fpsbuff, "%i", Pico.m.frame_count);
#endif #endif
lim_time = (frames_done+1) * target_frametime + vsync_offset; if (pthissec != tval.tv_sec)
if(currentConfig.Frameskip >= 0) { // frameskip enabled {
if (PsndOut == 0 && currentConfig.Frameskip >= 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 && pframes_done < target_fps && pframes_done > target_fps-5) {
updateKeys();
SkipFrame(1); pframes_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;
}
lim_time = (pframes_done+1) * target_frametime + vsync_offset;
if (currentConfig.Frameskip >= 0) // frameskip enabled
{
for(i = 0; i < currentConfig.Frameskip; i++) { for(i = 0; i < currentConfig.Frameskip; i++) {
updateKeys(); updateKeys();
SkipFrame(1); frames_done++; SkipFrame(1); pframes_done++; frames_done++;
if (PsndOut && !reset_timing) { // do framelimitting if sound is enabled if (PsndOut && !reset_timing) { // do framelimitting if sound is enabled
gettimeofday(&tval, 0); gettimeofday(&tval, 0);
if(thissec != tval.tv_sec) tval.tv_usec+=1000000; if (pthissec != tval.tv_sec) tval.tv_usec+=1000000;
if(tval.tv_usec < lim_time) { // we are too fast if (tval.tv_usec < lim_time) { // we are too fast
simpleWait(thissec, lim_time); simpleWait(pthissec, lim_time);
} }
} }
lim_time += target_frametime; 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 // no time left for this frame - skip
if (tval.tv_usec - lim_time >= 300000) { if (tval.tv_usec - lim_time >= 300000) {
/* something caused a slowdown for us (disk access? cache flush?) /* something caused a slowdown for us (disk access? cache flush?)
@ -860,74 +925,16 @@ void emu_Loop(void)
continue; continue;
} }
updateKeys(); 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; continue;
} }
updateKeys(); updateKeys();
PicoFrame(); 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 // check time
gettimeofday(&tval, 0); 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 if (currentConfig.Frameskip < 0 && tval.tv_usec - lim_time >= 300000) // slowdown detection
reset_timing = 1; reset_timing = 1;
@ -940,17 +947,18 @@ if (Pico.m.frame_count == 31563) {
// we are too fast // we are too fast
if (vsync_offset) { if (vsync_offset) {
if (lim_time - tval.tv_usec > target_frametime/2) 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(); gp2x_video_wait_vsync();
} else { } else {
simpleWait(thissec, lim_time); simpleWait(pthissec, lim_time);
} }
} }
} }
blit(fpsbuff, notice); blit(fpsbuff, notice);
frames_done++; frames_shown++; pframes_done++; pframes_shown++;
frames_done++; frames_shown++;
} }
change_fast_forward(0); change_fast_forward(0);
@ -976,4 +984,3 @@ void emu_ResetGame(void)
reset_timing = 1; reset_timing = 1;
} }

View file

@ -765,10 +765,10 @@ static void updateKeys(void)
pl = (acts >> 16) & 1; pl = (acts >> 16) & 1;
if (kb_combo_keys & (1 << i)) 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 // let's try to find the other one
if (acts_c) { if (acts_c) {
for (u = i + 1; u < 32; u++) for (; u < 32; u++)
if ( (keys & (1 << u)) && (currentConfig.KeyBinds[u] & acts_c) ) { if ( (keys & (1 << u)) && (currentConfig.KeyBinds[u] & acts_c) ) {
allActions[pl] |= acts_c & currentConfig.KeyBinds[u]; allActions[pl] |= acts_c & currentConfig.KeyBinds[u];
keys &= ~((1 << i) | (1 << u)); keys &= ~((1 << i) | (1 << u));