std::string video_manager::speed_text() { std::ostringstream str; // if we're paused, just display Paused bool paused = machine().paused(); if (paused) str << "paused"; // if we're fast forwarding, just display Fast-forward else if (m_fastforward) str << "fast "; // if we're auto frameskipping, display that plus the level else if (effective_autoframeskip()) util::stream_format(str, "auto%2d/%d", effective_frameskip(), MAX_FRAMESKIP); // otherwise, just display the frameskip plus the level else util::stream_format(str, "skip %d/%d", effective_frameskip(), MAX_FRAMESKIP); // append the speed for all cases except paused if (!paused) util::stream_format(str, "%4d%%", (int)(100 * m_speed_percent + 0.5)); // display the number of partial updates as well int partials = 0; screen_device_iterator iter(machine().root_device()); for (screen_device *screen = iter.first(); screen != nullptr; screen = iter.next()) partials += screen->partial_updates(); if (partials > 1) util::stream_format(str, "\n%d partial updates", partials); return str.str(); }
astring &video_manager::speed_text(astring &string) { string.reset(); // if we're paused, just display Paused bool paused = machine().paused(); if (paused) string.cat("paused"); // if we're fast forwarding, just display Fast-forward else if (m_fastforward) string.cat("fast "); // if we're auto frameskipping, display that plus the level else if (effective_autoframeskip()) string.catprintf("auto%2d/%d", effective_frameskip(), MAX_FRAMESKIP); // otherwise, just display the frameskip plus the level else string.catprintf("skip %d/%d", effective_frameskip(), MAX_FRAMESKIP); // append the speed for all cases except paused if (!paused) string.catprintf("%4d%%", (int)(100 * m_speed_percent + 0.5)); // display the number of partial updates as well int partials = 0; screen_device_iterator iter(machine().root_device()); for (screen_device *screen = iter.first(); screen != NULL; screen = iter.next()) partials += screen->partial_updates(); if (partials > 1) string.catprintf("\n%d partial updates", partials); return string; }
const char *osd_get_fps_text(const performance_info *performance) { static char buffer[1024]; char *dest = buffer; // if we're paused, display less info if (mame_is_paused(Machine)) dest += sprintf(dest, "Paused"); else { dest += sprintf(dest, "%s%2d%4d%%%4d/%d fps", effective_autoframeskip() ? "auto" : "fskp", effective_frameskip(), (int)(performance->game_speed_percent + 0.5), (int)(performance->frames_per_second + 0.5), (int)(Machine->screen[0].refresh + 0.5)); /* for vector games, add the number of vector updates */ if (Machine->drv->video_attributes & VIDEO_TYPE_VECTOR) dest += sprintf(dest, "\n %d vector updates", performance->vector_updates_last_second); else if (performance->partial_updates_this_frame > 1) dest += sprintf(dest, "\n %d partial updates", performance->partial_updates_this_frame); } /* return a pointer to the static buffer */ return buffer; }
int osd_update(mame_time emutime) { win_window_info *window; // if we're throttling, paused, or if the UI is up, synchronize if (effective_throttle()) update_throttle(emutime); // update the FPS computations update_fps(emutime); // update all the windows, but only if we're not skipping this frame if (!skiptable[effective_frameskip()][frameskip_counter]) { profiler_mark(PROFILER_BLIT); for (window = win_window_list; window != NULL; window = window->next) winwindow_video_window_update(window); profiler_mark(PROFILER_END); } // if we're throttling and autoframeskip is on, adjust if (effective_throttle() && effective_autoframeskip() && frameskip_counter == 0) update_autoframeskip(); // poll the joystick values here winwindow_process_events(TRUE); wininput_poll(); check_osd_inputs(); // increment the frameskip counter frameskip_counter = (frameskip_counter + 1) % FRAMESKIP_LEVELS; // return whether or not to skip the next frame return skiptable[effective_frameskip()][frameskip_counter]; }
osd_ticks_t video_manager::throttle_until_ticks(osd_ticks_t target_ticks) { // we're allowed to sleep via the OSD code only if we're configured to do so // and we're not frameskipping due to autoframeskip, or if we're paused bool allowed_to_sleep = false; if (machine().options().sleep() && (!effective_autoframeskip() || effective_frameskip() == 0)) allowed_to_sleep = true; if (machine().paused()) allowed_to_sleep = true; // loop until we reach our target g_profiler.start(PROFILER_IDLE); osd_ticks_t minimum_sleep = osd_ticks_per_second() / 1000; osd_ticks_t current_ticks = osd_ticks(); while (current_ticks < target_ticks) { // compute how much time to sleep for, taking into account the average oversleep osd_ticks_t delta = (target_ticks - current_ticks) * 1000 / (1000 + m_average_oversleep); // see if we can sleep bool slept = false; if (allowed_to_sleep && delta >= minimum_sleep) { osd_sleep(delta); slept = true; } // read the new value osd_ticks_t new_ticks = osd_ticks(); // keep some metrics on the sleeping patterns of the OSD layer if (slept) { // if we overslept, keep an average of the amount osd_ticks_t actual_ticks = new_ticks - current_ticks; if (actual_ticks > delta) { // take 90% of the previous average plus 10% of the new value osd_ticks_t oversleep_milliticks = 1000 * (actual_ticks - delta) / delta; m_average_oversleep = (m_average_oversleep * 99 + oversleep_milliticks) / 100; if (LOG_THROTTLE) machine().logerror("Slept for %d ticks, got %d ticks, avgover = %d\n", (int)delta, (int)actual_ticks, (int)m_average_oversleep); } } current_ticks = new_ticks; } g_profiler.stop(); return current_ticks; }
void video_manager::update_frameskip() { // if we're throttling and autoframeskip is on, adjust if (effective_throttle() && effective_autoframeskip() && m_frameskip_counter == 0) { // calibrate the "adjusted speed" based on the target double adjusted_speed_percent = m_speed_percent / (double) m_throttle_rate; // if we're too fast, attempt to increase the frameskip double speed = m_speed * 0.001; if (adjusted_speed_percent >= 0.995 * speed) { // but only after 3 consecutive frames where we are too fast if (++m_frameskip_adjust >= 3) { m_frameskip_adjust = 0; if (m_frameskip_level > 0) m_frameskip_level--; } } // if we're too slow, attempt to increase the frameskip else { // if below 80% speed, be more aggressive if (adjusted_speed_percent < 0.80 * speed) m_frameskip_adjust -= (0.90 * speed - m_speed_percent) / 0.05; // if we're close, only force it up to frameskip 8 else if (m_frameskip_level < 8) m_frameskip_adjust--; // perform the adjustment while (m_frameskip_adjust <= -2) { m_frameskip_adjust += 2; if (m_frameskip_level < MAX_FRAMESKIP) m_frameskip_level++; } } } // increment the frameskip counter and determine if we will skip the next frame m_frameskip_counter = (m_frameskip_counter + 1) % FRAMESKIP_LEVELS; m_skipping_this_frame = s_skiptable[effective_frameskip()][m_frameskip_counter]; }
static void update_throttle(mame_time emutime) { static double ticks_per_sleep_msec = 0; osd_ticks_t target, curr, cps, diffticks; int allowed_to_sleep; subseconds_t subsecs_per_cycle; int paused = mame_is_paused(Machine); // if we're only syncing to the refresh, bail now if (video_config.syncrefresh) return; // if we're paused, emutime will not advance; explicitly resync and set us backwards // 1/60th of a second if (paused) throttle_realtime = throttle_emutime = sub_subseconds_from_mame_time(emutime, MAX_SUBSECONDS / PAUSED_REFRESH_RATE); // if time moved backwards (reset), or if it's been more than 1 second in emulated time, resync if (compare_mame_times(emutime, throttle_emutime) < 0 || sub_mame_times(emutime, throttle_emutime).seconds > 0) goto resync; // get the current realtime; if it's been more than 1 second realtime, just resync cps = osd_ticks_per_second(); diffticks = osd_ticks() - throttle_last_ticks; throttle_last_ticks += diffticks; if (diffticks >= cps) goto resync; // add the time that has passed to the real time subsecs_per_cycle = MAX_SUBSECONDS / cps; throttle_realtime = add_subseconds_to_mame_time(throttle_realtime, diffticks * subsecs_per_cycle); // update the emulated time throttle_emutime = emutime; // if we're behind, just sync if (compare_mame_times(throttle_emutime, throttle_realtime) <= 0) goto resync; // determine our target ticks value target = throttle_last_ticks + sub_mame_times(throttle_emutime, throttle_realtime).subseconds / subsecs_per_cycle; // initialize the ticks per sleep if (ticks_per_sleep_msec == 0) ticks_per_sleep_msec = (double)(cps / 1000); // this counts as idle time profiler_mark(PROFILER_IDLE); // determine whether or not we are allowed to sleep allowed_to_sleep = video_config.sleep && (!effective_autoframeskip() || effective_frameskip() == 0); // sync for (curr = osd_ticks(); curr - target < 0; curr = osd_ticks()) { // if we have enough time to sleep, do it // ...but not if we're autoframeskipping and we're behind if (paused || (allowed_to_sleep && (target - curr) > (osd_ticks_t)(ticks_per_sleep_msec * 1.1))) { osd_ticks_t next; // keep track of how long we actually slept Sleep(1); next = osd_ticks(); ticks_per_sleep_msec = (ticks_per_sleep_msec * 0.90) + ((double)(next - curr) * 0.10); } } // idle time done profiler_mark(PROFILER_END); // update realtime diffticks = osd_ticks() - throttle_last_ticks; throttle_last_ticks += diffticks; throttle_realtime = add_subseconds_to_mame_time(throttle_realtime, diffticks * subsecs_per_cycle); return; resync: // reset realtime and emutime to the same value throttle_realtime = throttle_emutime = emutime; }