浏览代码

experimental thread I/O code, fps counter fix

git-svn-id: file:///home/notaz/opt/svn/PicoDrive@396 be3aeb3a-fb24-0410-a615-afba39da0efa
notaz 16 年之前
父节点
当前提交
da31028324
共有 5 个文件被更改,包括 245 次插入97 次删除
  1. 142 3
      Pico/cd/buffering.c
  2. 2 0
      platform/base_readme.txt
  3. 2 2
      platform/gizmondo/emu.c
  4. 97 90
      platform/gp2x/emu.c
  5. 2 2
      platform/psp/emu.c

+ 142 - 3
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 <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)
 {
@@ -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? */

+ 2 - 0
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.

+ 2 - 2
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));

+ 97 - 90
platform/gp2x/emu.c

@@ -11,6 +11,7 @@
 #include <linux/limits.h>
 #include <ctype.h>
 #include <unistd.h>
+#include <sched.h>
 
 #include <stdarg.h>
 
@@ -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;
 }
 
-

+ 2 - 2
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));