| Chris@1074 | 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */ | 
| Chris@1074 | 2 | 
| Chris@1074 | 3 /* | 
| Chris@1074 | 4     Sonic Visualiser | 
| Chris@1074 | 5     An audio file viewer and annotation editor. | 
| Chris@1074 | 6     Centre for Digital Music, Queen Mary, University of London. | 
| Chris@1074 | 7 | 
| Chris@1074 | 8     This program is free software; you can redistribute it and/or | 
| Chris@1074 | 9     modify it under the terms of the GNU General Public License as | 
| Chris@1074 | 10     published by the Free Software Foundation; either version 2 of the | 
| Chris@1074 | 11     License, or (at your option) any later version.  See the file | 
| Chris@1074 | 12     COPYING included with this distribution for more information. | 
| Chris@1074 | 13 */ | 
| Chris@1074 | 14 | 
| Chris@1074 | 15 #ifndef RENDER_TIMER_H | 
| Chris@1074 | 16 #define RENDER_TIMER_H | 
| Chris@1074 | 17 | 
| Chris@1074 | 18 #include <chrono> | 
| Chris@1074 | 19 | 
| Chris@1074 | 20 class RenderTimer | 
| Chris@1074 | 21 { | 
| Chris@1074 | 22 public: | 
| Chris@1074 | 23     enum Type { | 
| Chris@1074 | 24 	/// A normal rendering operation with normal responsiveness demands | 
| Chris@1074 | 25 	FastRender, | 
| Chris@1074 | 26 | 
| Chris@1074 | 27 	/// An operation that the user might accept being slower | 
| Chris@1074 | 28 	SlowRender, | 
| Chris@1074 | 29 | 
| Chris@1074 | 30 	/// An operation that should always complete, i.e. as if there | 
| Chris@1074 | 31 	/// were no RenderTimer in use, but without having to change | 
| Chris@1074 | 32 	/// client code structurally | 
| Chris@1074 | 33 	NoTimeout | 
| Chris@1074 | 34     }; | 
| Chris@1074 | 35 | 
| Chris@1074 | 36     /** | 
| Chris@1074 | 37      * Create a new RenderTimer and start timing. Make one of these | 
| Chris@1074 | 38      * before rendering, and then call outOfTime() regularly during | 
| Chris@1074 | 39      * rendering. If outOfTime() returns true, abandon rendering!  and | 
| Chris@1074 | 40      * schedule the rest for after some user responsiveness has | 
| Chris@1074 | 41      * happened. | 
| Chris@1074 | 42      */ | 
| Chris@1074 | 43     RenderTimer(Type t) : | 
| Chris@1074 | 44 	m_start(std::chrono::steady_clock::now()), | 
| Chris@1074 | 45 	m_haveLimits(true), | 
| Chris@1074 | 46 	m_minFraction(0.1), | 
| Chris@1074 | 47 	m_softLimit(0.1), | 
| Chris@1074 | 48 	m_hardLimit(0.2), | 
| Chris@1074 | 49 	m_softLimitOverridden(false) { | 
| Chris@1074 | 50 | 
| Chris@1074 | 51 	if (t == NoTimeout) { | 
| Chris@1074 | 52 	    m_haveLimits = false; | 
| Chris@1074 | 53 	} else if (t == SlowRender) { | 
| Chris@1074 | 54 	    m_softLimit = 0.2; | 
| Chris@1074 | 55 	    m_hardLimit = 0.4; | 
| Chris@1074 | 56 	} | 
| Chris@1074 | 57     } | 
| Chris@1074 | 58 | 
| Chris@1074 | 59 | 
| Chris@1074 | 60     /** | 
| Chris@1074 | 61      * Return true if we have run out of time and should suspend | 
| Chris@1074 | 62      * rendering and handle user events instead. Call this regularly | 
| Chris@1074 | 63      * during rendering work: fractionComplete should be an estimate | 
| Chris@1074 | 64      * of how much of the work has been done as of this call, as a | 
| Chris@1074 | 65      * number between 0.0 (none of it) and 1.0 (all of it). | 
| Chris@1074 | 66      */ | 
| Chris@1074 | 67     bool outOfTime(double fractionComplete) { | 
| Chris@1074 | 68 | 
| Chris@1074 | 69 	if (!m_haveLimits || fractionComplete < m_minFraction) { | 
| Chris@1074 | 70 	    return false; | 
| Chris@1074 | 71 	} | 
| Chris@1074 | 72 | 
| Chris@1074 | 73 	auto t = std::chrono::steady_clock::now(); | 
| Chris@1074 | 74 	double elapsed = std::chrono::duration<double>(t - m_start).count(); | 
| Chris@1074 | 75 | 
| Chris@1074 | 76 	if (elapsed > m_hardLimit) { | 
| Chris@1074 | 77 	    return true; | 
| Chris@1074 | 78 	} else if (!m_softLimitOverridden && elapsed > m_softLimit) { | 
| Chris@1074 | 79 	    if (fractionComplete > 0.6) { | 
| Chris@1074 | 80 		// If we're significantly more than half way by the | 
| Chris@1074 | 81 		// time we reach the soft limit, ignore it (though | 
| Chris@1074 | 82 		// always respect the hard limit, above). Otherwise | 
| Chris@1074 | 83 		// respect the soft limit and report out of time now. | 
| Chris@1074 | 84 		m_softLimitOverridden = true; | 
| Chris@1074 | 85 	    } else { | 
| Chris@1074 | 86 		return true; | 
| Chris@1074 | 87 	    } | 
| Chris@1074 | 88 	} | 
| Chris@1074 | 89 | 
| Chris@1074 | 90 	return false; | 
| Chris@1074 | 91     } | 
| Chris@1074 | 92 | 
| Chris@1074 | 93 private: | 
| Chris@1074 | 94     std::chrono::time_point<std::chrono::steady_clock> m_start; | 
| Chris@1074 | 95     bool m_haveLimits; | 
| Chris@1074 | 96     double m_minFraction; | 
| Chris@1074 | 97     double m_softLimit; | 
| Chris@1074 | 98     double m_hardLimit; | 
| Chris@1074 | 99     bool m_softLimitOverridden; | 
| Chris@1074 | 100 }; | 
| Chris@1074 | 101 | 
| Chris@1074 | 102 #endif |