From: Shamus Hammons Date: Wed, 11 Sep 2013 22:33:54 +0000 (-0500) Subject: Fixed problem with frames running ahead of the sound thread. X-Git-Url: http://shamusworld.gotdns.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=cf5ff906a67338f7b87d8285a00d9e2b82ad033e;p=apple2 Fixed problem with frames running ahead of the sound thread. This involved fixing V65C02 (by subtracting out cycle overruns) and fixing the main thread callback wait loop. As someone once said, "Threading is hard." :-P --- diff --git a/src/apple2.cpp b/src/apple2.cpp index 2a1858e..8b6a36f 100755 --- a/src/apple2.cpp +++ b/src/apple2.cpp @@ -188,6 +188,7 @@ WriteLog("CPU: Execute65C02(&mainCPU, cycles);\n"); } #endif +WriteLog("CPUThread: Supposedly end of frame...\n"); #ifdef THREAD_DEBUGGING WriteLog("CPU: SDL_mutexP(cpuMutex);\n"); @@ -1155,6 +1156,8 @@ Z $DA $9A $DA $9A ESC $9B $9B $9B $9B No xlation */ +static uint64_t lastCPUCycles = 0; +static uint32_t frameCount = 0; static void FrameCallback(void) { SDL_Event event; @@ -1297,7 +1300,7 @@ else if (event.key.keysym.sym == SDLK_F10) } } -#warning "!!! Taking MAJOR time hit with the video frame rendering !!!" +//#warning "!!! Taking MAJOR time hit with the video frame rendering !!!" RenderVideoFrame(); SetCallbackTime(FrameCallback, 16666.66666667); @@ -1321,10 +1324,26 @@ if (counter == 60) //Actually, slows things down too much... //SDL_Delay(10); // while (SDL_GetTicks() - startTicks < 16); // Wait for next frame... - while (SDL_GetTicks() - startTicks < 16) + +// This is the problem: If you set the interval to 16, it runs faster than +// 1/60s per frame. If you set it to 17, it runs slower. What we need is to +// have it do 16 for one frame, then 17 for two others. Then it should average +// out to 1/60s per frame every 3 frames. + frameCount = (frameCount + 1) % 3; + + uint32_t waitFrameTime = 17 - (frameCount == 0 ? 1 : 0); + + while (SDL_GetTicks() - startTicks < waitFrameTime) SDL_Delay(1); // Wait for next frame... startTicks = SDL_GetTicks(); +#if 1 + uint64_t cpuCycles = GetCurrentV65C02Clock(); + uint32_t cyclesBurned = (uint32_t)(cpuCycles - lastCPUCycles); + WriteLog("FrameCallback: used %i cycles\n", cyclesBurned); + lastCPUCycles = cpuCycles; +#endif + //let's wait, then signal... //works longer, but then still falls behind... #ifdef THREADED_65C02 diff --git a/src/sound.cpp b/src/sound.cpp index fd6754d..0d794c9 100755 --- a/src/sound.cpp +++ b/src/sound.cpp @@ -162,7 +162,7 @@ static void SDLSoundCallback(void * /*userdata*/, Uint8 * buffer8, int length8) // Let's try using a mutex for shared resource consumption... //Actually, I think Lock/UnlockAudio() does this already... -//WriteLog("SDLSoundCallback(): SDL_mutexP(mutex2)\n"); +WriteLog("SDLSoundCallback: soundBufferPos = %i\n", soundBufferPos); SDL_mutexP(mutex2); // Recast this as a 16-bit type... diff --git a/src/v65c02.cpp b/src/v65c02.cpp index 216a0af..7f86895 100755 --- a/src/v65c02.cpp +++ b/src/v65c02.cpp @@ -2850,6 +2850,9 @@ bool dumpDis = false; //bleh. //static uint32_t limit = 0; +// This should be in the regs struct, in case we have multiple CPUs... +#warning "!!! Move overflow into regs struct !!!" +static uint64_t overflow = 0; // // Function to execute 65C02 for "cycles" cycles // @@ -2875,7 +2878,7 @@ Let's see... if (regs.clock + cycles > 0xFFFFFFFF) wraparound = true; */ - uint64_t endCycles = regs.clock + (uint64_t)cycles; + uint64_t endCycles = regs.clock + (uint64_t)cycles - overflow; while (regs.clock < endCycles) { @@ -3020,6 +3023,12 @@ WriteLog("\n*** IRQ ***\n\n"); } } + // If we went longer than the passed in cycles, make a note of it so we can + // subtract it out from a subsequent run. It's guaranteed to be positive, + // because the condition that exits the main loop above is written such + // that regs.clock has to be larger than endCycles to exit from it. + overflow = regs.clock - endCycles; + myMemcpy(context, ®s, sizeof(V65C02REGS)); }