vice3ds icon indicating copy to clipboard operation
vice3ds copied to clipboard

Run handheld screen in 50 Hz for perfect frame pacing with PAL games

Open rsn8887 opened this issue 1 year ago • 3 comments

Red-Viper Virtual Boy emulator recently implemented 50 Hz refresh rate on the 3DS screen. Can this be implemented for Vice3DS as well, to remove all microstutters due to 50 fps game running on 60 Hz screen refresh rate?

See here: https://github.com/skyfloogle/red-viper/issues/46

rsn8887 avatar Apr 20 '24 22:04 rsn8887

All 3DS screens are natively 60hz. There were 2 different versions of C64 for ntsc and PAL, and most often, 2 versions of software to go with them. Just use the ntsc versions. But... If you read the latest release notes on gbatemp, it suggests that it already does 50hz? So your perceived issue might be the opposite...

https://gbatemp.net/threads/release-vice3ds-c64-emulator.534830/

urherenow avatar Apr 20 '24 23:04 urherenow

Vice3DS currently doesn't run the screen in 50 Hz. For example, in Uridium PAL the scrolling is not perfectly smooth. The source code shows that the code is not there to force the screen into 50 Hz.

It is true that the 3DS screen normally runs in 60 Hz. But it can be forced to run in 50 Hz. It requires a programming hack to force 50 Hz. There's proof that it works, because Red Viper does it. See here: https://github.com/skyfloogle/red-viper/issues/46

rsn8887 avatar Apr 21 '24 16:04 rsn8887

The 3DS screen can even be forced to 10 Hz!

Here's a code example taken from the Red Viper discussion https://github.com/skyfloogle/red-viper/issues/46#issuecomment-1991598414

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <stdlib.h>
#include <string.h>
#include <3ds.h>

int main(int argc, char* argv[])
{
	gfxInitDefault();
	consoleInit(GFX_TOP, NULL);

	u32 vtotal;
	Result res = GSPGPU_ReadHWRegs(0x400424, &vtotal, 4);
	printf("VTotal test: 0x%" PRIX32 "\nUp: + 1, Left: + 10, Down: - 1, Right: - 10\n", res);

	u64 startTicks = 0;
	u32 frameCount = 0;
	bool update = true;
	while (aptMainLoop())
	{
		if(frameCount == 0) startTicks = svcGetSystemTick();
		gspWaitForVBlank();
		frameCount++;
		if(frameCount == 60)
		{
			const u64 ticks = svcGetSystemTick() - startTicks;
			printf("\x1b[5;1H%f fps ", (double)268111856 * 60u / ticks);
			frameCount = 0;
		}

		gfxFlushBuffers();
		gfxSwapBuffers();
		hidScanInput();

		// Your code goes here
		u32 kDown = hidKeysDown();
		if (kDown & KEY_START)
			break; // break in order to return to hbmenu
		else if(kDown & KEY_DUP)
		{
			vtotal++;
			update = true;
		}
		else if(kDown & KEY_DLEFT)
		{
			vtotal += 10;
			update = true;
		}
		else if(kDown & KEY_DDOWN)
		{
			vtotal--;
			update = true;
		}
		else if(kDown & KEY_DRIGHT)
		{
			vtotal -= 10;
			update = true;
		}

		if(update)
		{
			update = false;
			vtotal &= 0xFFFu; // VTotal is 12 bits.
			GSPGPU_WriteHWRegs(0x400424, &vtotal, 4);
			printf("\x1b[4;1HVTotal: %" PRIu32 "    ", vtotal);
		}
	}

	gfxExit();
	return 0;
}

rsn8887 avatar Apr 21 '24 16:04 rsn8887