diff --git a/desmume/src/NDSSystem.cpp b/desmume/src/NDSSystem.cpp index 798d59a2a..64e17b5c5 100644 --- a/desmume/src/NDSSystem.cpp +++ b/desmume/src/NDSSystem.cpp @@ -1378,31 +1378,10 @@ static void execHardware_hblank() SPU_Emulate_core(); driver->AVI_SoundUpdate(SPU_core->outbuf,spu_core_samples); WAV_WavSoundUpdate(SPU_core->outbuf,spu_core_samples); - - //this logic was formerly at hblank time. it was moved to the beginning of the scanline on a whim - if(nds.VCount<192) - { - //so, we have chosen to do the line drawing at hblank time. - //this is the traditional time for it in desmume. - //while it may seem more ruthlessly accurate to do it at hstart, - //in practice we need to be more forgiving, in case things have overrun the scanline start. - //this should be safe since games cannot do anything timing dependent until this next - //scanline begins, anyway (as this scanline was in the middle of drawing) - //taskSubGpu.execute(renderSubScreen,NULL); - GPU_RenderLine(&MainScreen, nds.VCount, frameSkipper.ShouldSkip2D()); - GPU_RenderLine(&SubScreen, nds.VCount, frameSkipper.ShouldSkip2D()); - //taskSubGpu.finish(); - - //trigger hblank dmas - //but notice, we do that just after we finished drawing the line - //(values copied by this hdma should not be used until the next scanline) - triggerDma(EDMAMode_HBlank); - } } static void execHardware_hstart_vblankEnd() { - nds.VCount = 0; sequencer.nds_vblankEnded = true; sequencer.reschedule = true; @@ -1469,9 +1448,41 @@ static void execHardware_hstart_vcount() static void execHardware_hstart() { + //this logic keeps moving around. + //now, we try and give the game as much time as possible to finish doing its work for the scanline, + //by drawing scanline N at the very, very end of scanline N (here at the beginning of scanline N+1) + if(nds.VCount<192) + { + //taskSubGpu.execute(renderSubScreen,NULL); + GPU_RenderLine(&MainScreen, nds.VCount, frameSkipper.ShouldSkip2D()); + GPU_RenderLine(&SubScreen, nds.VCount, frameSkipper.ShouldSkip2D()); + //taskSubGpu.finish(); + + //trigger hblank dmas + //but notice, we do that just after we finished drawing the line + //(values copied by this hdma should not be used until the next scanline) + triggerDma(EDMAMode_HBlank); + } + + if(nds.VCount==192) + { + //we need to trigger one last hblank dma since + //a. we're sort of lagged behind by one scanline + //b. i think that 193 hblanks actually fire (one for the hblank in scanline 262) + //this is demonstrated by NSMB splot-parallaxing clouds + //for some reason the game will setup two hdma scroll register buffers + //to be run consecutively, and unless we do this, the second buffer will be offset by one scanline + //causing a glitch in the 0th scanline + triggerDma(EDMAMode_HBlank); + } + nds.VCount++; if(nds.VCount==263) + { + nds.VCount=0; + } + if(nds.VCount==262) { execHardware_hstart_vblankEnd(); } else if(nds.VCount==192) @@ -1505,8 +1516,12 @@ static void execHardware_hstart() triggerDma(EDMAMode_MemDisplay); } + //end of 3d vblank - if(nds.VCount==214) + //this should be 214, but we are going to be generous for games with tight timing + //they shouldnt be changing any textures at 262 but they might accidentally still be at 214 + //so.. + if(CommonSettings.rigorous_timing && nds.VCount==214 || !CommonSettings.rigorous_timing && nds.VCount==262) { gfx3d_VBlankEndSignal(frameSkipper.ShouldSkip3D()); } @@ -2151,7 +2166,6 @@ void NDS_Reset() nds.wifiCycle = 0; memset(nds.timerCycle, 0, sizeof(u64) * 2 * 4); - nds.VCount = 0; nds.old = 0; nds.touchX = nds.touchY = 0; nds.isTouch = 0; diff --git a/desmume/src/NDSSystem.h b/desmume/src/NDSSystem.h index 660a68cf9..d90aab7f7 100644 --- a/desmume/src/NDSSystem.h +++ b/desmume/src/NDSSystem.h @@ -525,6 +525,7 @@ extern struct TCommonSettings { int num_cores; bool single_core() { return num_cores==1; } + bool rigorous_timing; struct _Wifi { int mode; diff --git a/desmume/src/commandline.cpp b/desmume/src/commandline.cpp index 60bdc950f..bf75fbd8c 100644 --- a/desmume/src/commandline.cpp +++ b/desmume/src/commandline.cpp @@ -37,6 +37,7 @@ CommandLine::CommandLine() : is_cflash_configured(false) , error(NULL) , ctx(g_option_context_new ("")) +, _rigorous_timing(0) , _play_movie_file(0) , _record_movie_file(0) , _cflash_image(0) @@ -84,6 +85,7 @@ void CommandLine::loadCommonOptions() { "num-cores", 0, 0, G_OPTION_ARG_INT, &_num_cores, "Override numcores detection and use this many", "NUM_CORES"}, { "scanline-filter-a", 0, 0, G_OPTION_ARG_INT, &scanline_filter_a, "Intensity of fadeout for scanlines filter (edge) (default 2)", "SCANLINE_FILTER_A"}, { "scanline-filter-b", 0, 0, G_OPTION_ARG_INT, &scanline_filter_b, "Intensity of fadeout for scanlines filter (corner) (default 4)", "SCANLINE_FILTER_B"}, + { "rigorous-timing", 0, 0, G_OPTION_ARG_INT, &_rigorous_timing, "Use some rigorous timings instead of unrealistically generous (default 0)", "RIGOROUS_TIMING"}, #ifndef _MSC_VER { "disable-sound", 0, 0, G_OPTION_ARG_NONE, &disable_sound, "Disables the sound emulation", NULL}, { "disable-limiter", 0, 0, G_OPTION_ARG_NONE, &disable_limiter, "Disables the 60fps limiter", NULL}, @@ -115,6 +117,7 @@ bool CommandLine::parse(int argc,char **argv) if(_gbaslot_rom) gbaslot_rom = _gbaslot_rom; if(_num_cores != -1) CommonSettings.num_cores = _num_cores; + if(_rigorous_timing) CommonSettings.rigorous_timing = true; //TODO MAX PRIORITY! change ARM9BIOS etc to be a std::string if(_bios_arm9) { CommonSettings.UseExtBIOS = true; strcpy(CommonSettings.ARM9BIOS,_bios_arm9); } diff --git a/desmume/src/commandline.h b/desmume/src/commandline.h index ea675b743..3d9fe0350 100644 --- a/desmume/src/commandline.h +++ b/desmume/src/commandline.h @@ -86,6 +86,7 @@ private: int _bios_swi; int _spu_advanced; int _num_cores; + int _rigorous_timing; }; #endif