Chris@1074: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ Chris@1074: Chris@1074: /* Chris@1074: Sonic Visualiser Chris@1074: An audio file viewer and annotation editor. Chris@1074: Centre for Digital Music, Queen Mary, University of London. Chris@1074: Chris@1074: This program is free software; you can redistribute it and/or Chris@1074: modify it under the terms of the GNU General Public License as Chris@1074: published by the Free Software Foundation; either version 2 of the Chris@1074: License, or (at your option) any later version. See the file Chris@1074: COPYING included with this distribution for more information. Chris@1074: */ Chris@1074: Chris@1074: #ifndef RENDER_TIMER_H Chris@1074: #define RENDER_TIMER_H Chris@1074: Chris@1074: #include Chris@1074: Chris@1074: class RenderTimer Chris@1074: { Chris@1074: public: Chris@1074: enum Type { Chris@1266: /// A normal rendering operation with normal responsiveness demands Chris@1266: FastRender, Chris@1074: Chris@1266: /// An operation that the user might accept being slower Chris@1266: SlowRender, Chris@1074: Chris@1266: /// An operation that should always complete, i.e. as if there Chris@1266: /// were no RenderTimer in use, but without having to change Chris@1266: /// client code structurally Chris@1266: NoTimeout Chris@1074: }; Chris@1074: Chris@1074: /** Chris@1074: * Create a new RenderTimer and start timing. Make one of these Chris@1074: * before rendering, and then call outOfTime() regularly during Chris@1074: * rendering. If outOfTime() returns true, abandon rendering! and Chris@1074: * schedule the rest for after some user responsiveness has Chris@1074: * happened. Chris@1074: */ Chris@1074: RenderTimer(Type t) : Chris@1266: m_start(std::chrono::steady_clock::now()), Chris@1266: m_haveLimits(true), Chris@1266: m_minFraction(0.1), Chris@1266: m_softLimit(0.1), Chris@1266: m_hardLimit(0.2), Chris@1266: m_softLimitOverridden(false) { Chris@1074: Chris@1266: if (t == NoTimeout) { Chris@1266: m_haveLimits = false; Chris@1266: } else if (t == SlowRender) { Chris@1266: m_softLimit = 0.2; Chris@1266: m_hardLimit = 0.4; Chris@1266: } Chris@1074: } Chris@1074: Chris@1074: Chris@1074: /** Chris@1074: * Return true if we have run out of time and should suspend Chris@1074: * rendering and handle user events instead. Call this regularly Chris@1074: * during rendering work: fractionComplete should be an estimate Chris@1074: * of how much of the work has been done as of this call, as a Chris@1074: * number between 0.0 (none of it) and 1.0 (all of it). Chris@1074: */ Chris@1074: bool outOfTime(double fractionComplete) { Chris@1074: Chris@1266: if (!m_haveLimits || fractionComplete < m_minFraction) { Chris@1266: return false; Chris@1266: } Chris@1266: Chris@1266: auto t = std::chrono::steady_clock::now(); Chris@1266: double elapsed = std::chrono::duration(t - m_start).count(); Chris@1266: Chris@1266: if (elapsed > m_hardLimit) { Chris@1266: return true; Chris@1266: } else if (!m_softLimitOverridden && elapsed > m_softLimit) { Chris@1266: if (fractionComplete > 0.6) { Chris@1266: // If we're significantly more than half way by the Chris@1266: // time we reach the soft limit, ignore it (though Chris@1266: // always respect the hard limit, above). Otherwise Chris@1266: // respect the soft limit and report out of time now. Chris@1266: m_softLimitOverridden = true; Chris@1266: } else { Chris@1266: return true; Chris@1266: } Chris@1266: } Chris@1074: Chris@1266: return false; Chris@1074: } Chris@1074: Chris@1221: double secondsPerItem(int itemsRendered) const { Chris@1221: Chris@1221: if (itemsRendered == 0) return 0.0; Chris@1221: Chris@1266: auto t = std::chrono::steady_clock::now(); Chris@1266: double elapsed = std::chrono::duration(t - m_start).count(); Chris@1221: Chris@1221: return elapsed / itemsRendered; Chris@1221: } Chris@1221: Chris@1074: private: Chris@1074: std::chrono::time_point m_start; Chris@1074: bool m_haveLimits; Chris@1221: double m_minFraction; // proportion, 0.0 -> 1.0 Chris@1221: double m_softLimit; // seconds Chris@1221: double m_hardLimit; // seconds Chris@1074: bool m_softLimitOverridden; Chris@1074: }; Chris@1074: Chris@1074: #endif