Thanks for all your work, Tatsuya79! However, I think I we might have gone down the wrong path. I skimmed the emu links you posted (thanks!), regarding input handling. At one of the links, the following can be read:
When enabled, the SNES will read 16 bits from each of the 4 controller port data lines into registers $4218-f. This begins between dots 32.5 and 95.5 of the first V-Blank scanline, and ends 4224 master cycles later.
So, the joypad is obviously read within the vblank period, which means that the frame must be ready by then. This means that there must be a possibility of exiting the main loop and outputting the frame before the polling takes place. My thinking here is that we should not need to modify joypad.cpp at all, just the emulator exit point. I actually don’t really think you were so wrong in your first attempt… I have thought about this during the past two days (I’ve been away from home, so couldn’t test until now) and just tried to modify system.cpp line 285 from this:
if(cpu.vcounter() == 241) scheduler.exit(Scheduler::ExitReason::FrameEvent);
to this:
if(cpu.vcounter() == (ppu.overscan() == false ? 225 : 240)) scheduler.exit(Scheduler::ExitReason::FrameEvent);
I have done two quick tests with this code:
- Yoshi’s Island emulator lag: down from 3 frames to 2 frames (yay!).
- R.P.M. Racing: Does NOT detect a false “Start” press when pressing up/down in the menu.
The code above outputs the frame during the very first line of vblank. From what I read, the actual visible frame starts at V=0 and ends at either V=224 or V=239 (i.e. 225 or 240 lines), so it should be safe to end the main loop and output the rendered frame at V=225 or V=240. I don’t know why byuu choose to output at V=241, but this causes the frame to be output just after the polling event, which in turn causes the extra frame of input lag.
Could you please try this code and see how it works? Also, to test input lag differences between the stock core and the modified one, please use the frame advance method, i.e. press ‘p’ to pause emulation, press and hold button on controller while pressing ‘k’ repeatedly to run the emulator loop and count how many presses it takes until you see a reaction on screen.