Files
SingularityViewer/indra/llcommon/llframetimer.h
Aleric Inglewood e95ee85804 Make LLFrameTimer thread-safe.
LLFrameTimer::sFrameTime is accessed by the texture
thread as well. Although the only consequences are
that it's possible for a timer in the texture thread
to time out too early (or to never time out when
it's started) when it reads this variable at the
same time as that it is updated, which is pretty
inlikely, it's just not-done to leave anything
thread-unsafe when it's known to be thread-unsafe.

This patch also adds a framework for AIFrameTimer, but
that isn't implemented yet.
2011-08-08 19:21:27 +02:00

213 lines
6.9 KiB
C++

/**
* @file llframetimer.h
* @brief A lightweight timer that measures seconds and is only
* updated once per frame.
*
* $LicenseInfo:firstyear=2002&license=viewergpl$
*
* Copyright (c) 2002-2009, Linden Research, Inc.
* Copyright (c) 2011, Aleric Inglewood.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
*
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*/
#ifndef LL_LLFRAMETIMER_H
#define LL_LLFRAMETIMER_H
/**
* *NOTE: Because of limitations on linux which we do not really have
* time to explore, the total time is derived from the frame time
* and is resynchronized on every frame.
*/
#include "lltimer.h"
#include "timing.h"
#include <apr_thread_mutex.h>
class LL_COMMON_API LLFrameTimer
{
public:
// Create an LLFrameTimer and start it. After creation it is running and in the state expired (hasExpired will return true).
LLFrameTimer(void) : mExpiry(0), mRunning(true), mPaused(false) { if (!sGlobalMutex) global_initialization(); setAge(0.0); }
// Atomic reads of static variables.
// Return the number of seconds since the start of the application.
static F64 getElapsedSeconds(void)
{
// Loses msec precision after ~4.5 hours...
apr_thread_mutex_lock(sGlobalMutex);
F64 res = sFrameTime;
apr_thread_mutex_unlock(sGlobalMutex);
return res;
}
// Return a low precision usec since epoch.
static U64 getTotalTime(void)
{
// sTotalTime is only accessed by the main thread, so no locking is necessary.
llassert(is_main_thread());
//apr_thread_mutex_lock(sGlobalMutex);
U64 res = sTotalTime;
//apr_thread_mutex_unlock(sGlobalMutex);
llassert(res);
return res;
}
// Return a low precision seconds since epoch.
static F64 getTotalSeconds(void)
{
// sTotalSeconds is only accessed by the main thread, so no locking is necessary.
llassert(is_main_thread());
//apr_thread_mutex_lock(sGlobalMutex);
F64 res = sTotalSeconds;
//apr_thread_mutex_unlock(sGlobalMutex);
return res;
}
// Return current frame number (the number of frames since application start).
static U32 getFrameCount(void)
{
// sFrameCount is only accessed by the main thread, so no locking is necessary.
llassert(is_main_thread());
//apr_thread_mutex_lock(sGlobalMutex);
U32 res = sFrameCount;
//apr_thread_mutex_unlock(sGlobalMutex);
return res;
}
// Call this method once per frame to update the current frame time.
// This is actually called at some other times as well.
static void updateFrameTime(void);
// Call this method once, and only once, per frame to update the current frame count and sFrameDeltaTime.
static void updateFrameTimeAndCount(void);
// Return duration of last frame in seconds.
static F32 getFrameDeltaTimeF32(void);
// Return seconds since the current frame started
static F32 getCurrentFrameTime(void);
// MANIPULATORS
void reset(F32 expiration = 0.f) // Same as start() but leaves mRunning off when called after stop().
{
llassert(!mPaused);
mStartTime = getElapsedSeconds();
mExpiry = mStartTime + expiration;
}
void start(F32 expiration = 0.f) // Reset and (re)start with expiration.
{
reset(expiration);
mRunning = true; // Start, if not already started.
}
void stop(void) // Stop running.
{
llassert(!mPaused);
mRunning = false;
}
void pause(); // Mark elapsed time so far.
void unpause(); // Move 'start' time in order to decrement time between pause and unpause from ElapsedTime.
void setTimerExpirySec(F32 expiration) { llassert(!mPaused); mExpiry = mStartTime + expiration; }
void setExpiryAt(F64 seconds_since_epoch);
bool checkExpirationAndReset(F32 expiration); // Returns true when expired. Only resets if expired.
F32 getElapsedTimeAndResetF32(void);
void setAge(const F64 age) { llassert(!mPaused); mStartTime = getElapsedSeconds() - age; }
// ACCESSORS
bool hasExpired() const { return getElapsedSeconds() >= mExpiry; }
F32 getElapsedTimeF32() const { llassert(mRunning); return mPaused ? (F32)mStartTime : (F32)(getElapsedSeconds() - mStartTime); }
bool getStarted() const { return mRunning; }
// return the seconds since epoch when this timer will expire.
F64 expiresAt() const;
public:
// Do one-time initialization of the static members.
static void global_initialization(void);
protected:
//
// Application constants
//
// Application start in microseconds since epoch.
static U64 const sStartTotalTime;
//
// Global data.
//
// More than one thread are accessing (some of) these variables, therefore we need locking.
static apr_thread_mutex_t* sGlobalMutex;
// Current time in seconds since application start, updated together with sTotalTime.
static F64 sFrameTime;
// Microseconds between last two calls to updateFrameTimeAndCount (time between last two frames).
static U64 sFrameDeltaTime;
// Current time in microseconds since epoch, updated at least once per frame.
static U64 sTotalTime;
// Previous (frame) time in microseconds since epoch, updated once per frame.
static U64 sPrevTotalTime;
// Current time in seconds since epoch, updated together with sTotalTime.
static F64 sTotalSeconds;
// Current frame number (number of frames since application start).
static S32 sFrameCount;
//
// Member data
//
// When not paused (mPaused is false): number of seconds since application start,
// otherwise this value is equal to the accumulated run time (ElapsedTime).
// Set equal to sFrameTime when reset.
F64 mStartTime;
// Timer expires when sFrameTime reaches this value (in seconds since application start).
F64 mExpiry;
// True when running, merely a boolean return by getStarted(). The timer always runs.
bool mRunning;
// True when accumulating ElapsedTime. If false mStartTime has a different meaning
// and really unpause() should be called before anything else.
bool mPaused;
};
// Glue code for Havok (or anything else that doesn't want the full .h files)
extern F32 getCurrentFrameTime();
#endif // LL_LLFRAMETIMER_H