]> Shamusworld >> Repos - apple2/commitdiff
Fixed problem with frames running ahead of the sound thread.
authorShamus Hammons <jlhamm@acm.org>
Wed, 11 Sep 2013 22:33:54 +0000 (17:33 -0500)
committerShamus Hammons <jlhamm@acm.org>
Wed, 11 Sep 2013 22:33:54 +0000 (17:33 -0500)
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

src/apple2.cpp
src/sound.cpp
src/v65c02.cpp

index 2a1858e7dd1e7697b24b9a366ac0fdb3380f19a2..8b6a36f140332c305a0a6c81aed2d335ef5695a2 100755 (executable)
@@ -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
index fd6754d7bc0c8c7e4483e652319df22efc5c3abf..0d794c997ede1d06bf42c9efd866375a2f86a9da 100755 (executable)
@@ -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...
index 216a0aff313c78a4723fb97db113d2c8235b795d..7f86895c6927f5ff3afff81299bcebe13fc566df 100755 (executable)
@@ -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, &regs, sizeof(V65C02REGS));
 }