diff --git a/src/emu/machine.cpp b/src/emu/machine.cpp index e32d8f73..1e1e23c5 100644 --- a/src/emu/machine.cpp +++ b/src/emu/machine.cpp @@ -1328,16 +1328,31 @@ void running_machine::emscripten_main_loop() auto profile = g_profiler.start(PROFILER_EXTRA); + // the page reads game controllers here, so the step sees the newest input + EM_ASM({ if (Module.beforeStep) Module.beforeStep(); }); + // execute CPUs if not paused if (!machine->m_paused) { device_scheduler * scheduler; scheduler = &(machine->scheduler()); - // Emscripten will call this function at 60Hz, so step the simulation - // forward for the amount of time that has passed since the last frame - const attotime frametime(0,HZ_TO_ATTOSECONDS(60)); - const attotime stoptime(scheduler->time() + frametime); + // Step the simulation forward by the real time since the last browser + // frame, so its speed does not depend on the display's refresh rate. + // The clamp stops a jump after the tab has been in the background. + // The stop time carries over, so a step that runs long shortens the next. + static double last_ms = 0.0; + static attotime stoptime; + const double now_ms = emscripten_get_now(); + double seconds = 1.0 / 60.0; + if (last_ms) + seconds = (now_ms - last_ms) / 1000.0; + else + stoptime = scheduler->time(); + last_ms = now_ms; + if (seconds > 0.1) + seconds = 0.1; + stoptime += attotime::from_double(seconds); while (!machine->m_paused && !machine->scheduled_event_pending() && scheduler->time() < stoptime) { @@ -1354,6 +1369,9 @@ void running_machine::emscripten_main_loop() else machine->m_video->frame_update(); + // the page draws in the same browser frame, so the picture is not a frame late + EM_ASM({ if (Module.afterStep) Module.afterStep(); }); + // cancel the emscripten loop if the system has been told to exit if (machine->exit_pending()) {