Merge branch 'master' of git://github.com/AlericInglewood/SingularityViewer
This commit is contained in:
@@ -570,7 +570,7 @@ static void v4dwt_interleave_h(v4dwt_t* restrict w, float* restrict a, int x, in
|
||||
int count = w->sn;
|
||||
int i, k;
|
||||
for(k = 0; k < 2; ++k){
|
||||
if (count + 3 * x < size && ((int) a & 0x0f) == 0 && ((int) bi & 0x0f) == 0 && (x & 0x0f) == 0) {
|
||||
if (count + 3 * x < size && ((long) a & 0x0f) == 0 && ((long) bi & 0x0f) == 0 && (x & 0x0f) == 0) {
|
||||
/* Fast code path */
|
||||
for(i = 0; i < count; ++i){
|
||||
int j = i;
|
||||
|
||||
@@ -15,6 +15,7 @@ include_directories(
|
||||
)
|
||||
|
||||
set(llcommon_SOURCE_FILES
|
||||
aiframetimer.cpp
|
||||
imageids.cpp
|
||||
indra_constants.cpp
|
||||
llapp.cpp
|
||||
@@ -89,6 +90,7 @@ set(llcommon_SOURCE_FILES
|
||||
set(llcommon_HEADER_FILES
|
||||
CMakeLists.txt
|
||||
|
||||
aiframetimer.h
|
||||
aithreadsafe.h
|
||||
bitpack.h
|
||||
ctype_workaround.h
|
||||
|
||||
150
indra/llcommon/aiframetimer.cpp
Normal file
150
indra/llcommon/aiframetimer.cpp
Normal file
@@ -0,0 +1,150 @@
|
||||
/**
|
||||
* @file aiframetimer.cpp
|
||||
*
|
||||
* Copyright (c) 2011, Aleric Inglewood.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* CHANGELOG
|
||||
* and additional copyright holders.
|
||||
*
|
||||
* 06/08/2011
|
||||
* - Initial version, written by Aleric Inglewood @ SL
|
||||
*/
|
||||
|
||||
#include "linden_common.h"
|
||||
|
||||
#include "aiframetimer.h"
|
||||
|
||||
static F64 const NEVER = 1e16; // 317 million years.
|
||||
|
||||
F64 AIFrameTimer::sNextExpiration;
|
||||
AIFrameTimer::timer_list_type AIFrameTimer::sTimerList;
|
||||
LLMutex AIFrameTimer::sMutex;
|
||||
|
||||
// Notes on thread-safety of AIRunningFrameTimer (continued from aiframetimer.h)
|
||||
//
|
||||
// Most notably, the constructor and init() should be called as follows:
|
||||
// 1) The object is constructed (AIRunningFrameTimer::AIRunningFrameTimer).
|
||||
// 2) The lock is obtained.
|
||||
// 3) The object is inserted in the list (operator<(AIRunningFrameTimer const&, AIRunningFrameTimer const&)).
|
||||
// 4) The object is initialized (AIRunningFrameTimer::init).
|
||||
// 5) The lock is released.
|
||||
// This assures that the object is not yet shared at the moment that it is initialized.
|
||||
|
||||
void AIFrameTimer::create(F64 expiration, signal_type::slot_type const& slot)
|
||||
{
|
||||
AIRunningFrameTimer new_timer(expiration, this);
|
||||
sMutex.lock();
|
||||
llassert(mHandle.mRunningTimer == sTimerList.end()); // Create may only be called when the timer isn't already running.
|
||||
mHandle.init(sTimerList.insert(new_timer), slot);
|
||||
sNextExpiration = sTimerList.begin()->expiration();
|
||||
sMutex.unlock();
|
||||
}
|
||||
|
||||
void AIFrameTimer::cancel(void)
|
||||
{
|
||||
// In order to stop us from returning from cancel() while
|
||||
// the callback function is being called (which is done
|
||||
// in AIFrameTimer::handleExpiration after obtaining the
|
||||
// mHandle.mMutex lock), we start with trying to obtain
|
||||
// it here and as such wait till the callback function
|
||||
// returned.
|
||||
mHandle.mMutex.lock();
|
||||
// Next we have to grab this lock in order to stop
|
||||
// AIFrameTimer::handleExpiration from even entering
|
||||
// in the case we manage to get it first.
|
||||
sMutex.lock();
|
||||
if (mHandle.mRunningTimer != sTimerList.end())
|
||||
{
|
||||
sTimerList.erase(mHandle.mRunningTimer);
|
||||
mHandle.mRunningTimer = sTimerList.end();
|
||||
sNextExpiration = sTimerList.empty() ? NEVER : sTimerList.begin()->expiration();
|
||||
}
|
||||
sMutex.unlock();
|
||||
mHandle.mMutex.unlock();
|
||||
}
|
||||
|
||||
void AIFrameTimer::handleExpiration(F64 current_frame_time)
|
||||
{
|
||||
sMutex.lock();
|
||||
for(;;)
|
||||
{
|
||||
if (sTimerList.empty())
|
||||
{
|
||||
// No running timers left.
|
||||
sNextExpiration = NEVER;
|
||||
break;
|
||||
}
|
||||
timer_list_type::iterator running_timer = sTimerList.begin();
|
||||
sNextExpiration = running_timer->expiration();
|
||||
if (sNextExpiration > current_frame_time)
|
||||
{
|
||||
// Didn't expire yet.
|
||||
break;
|
||||
}
|
||||
|
||||
// Obtain handle of running timer through the associated AIFrameTimer object.
|
||||
// Note that if the AIFrameTimer object was destructed (when running_timer->getTimer()
|
||||
// would return an invalid pointer) then it called cancel(), so we can't be here.
|
||||
Handle& handle(running_timer->getTimer()->mHandle);
|
||||
llassert_always(running_timer == handle.mRunningTimer);
|
||||
|
||||
// We're going to erase this timer, so stop cancel() from doing the same.
|
||||
handle.mRunningTimer = sTimerList.end();
|
||||
|
||||
// We keep handle.mMutex during the callback to prevent the thread that
|
||||
// owns the AIFrameTimer from deleting the callback function while we
|
||||
// call it: in order to do so it first has to call cancel(), which will
|
||||
// block until we release this mutex again, or we won't call the callback
|
||||
// function here because the trylock fails.
|
||||
//
|
||||
// Assuming the main thread arrived here, there are two possible states
|
||||
// for the other thread that tries to delete the call back function,
|
||||
// right after calling the cancel() function too:
|
||||
//
|
||||
// 1. It hasn't obtained the first lock yet, we obtain the handle.mMutex
|
||||
// lock and the other thread will stall on the first line of cancel().
|
||||
// After do_callback returns, the other thread will do nothing because
|
||||
// handle.mRunningTimer equals sTimerList.end(), exit the function and
|
||||
// (possibly) delete the callback object, but that is ok as we already
|
||||
// returned from the callback function.
|
||||
//
|
||||
// 2. It already called cancel() and hangs on the second line trying to
|
||||
// obtain sMutex.lock(). The trylock below fails and we never call the
|
||||
// callback function. We erase the running timer here and release sMutex
|
||||
// at the end, after which the other thread does nothing because
|
||||
// handle.mRunningTimer equals sTimerList.end(), exits the function and
|
||||
// (possibly) deletes the callback object.
|
||||
//
|
||||
// Note that if the other thread actually obtained the sMutex then we
|
||||
// can't be here: this is still inside the critical area of sMutex.
|
||||
if (handle.mMutex.tryLock()) // If this fails then another thread is in the process of cancelling this timer, so do nothing.
|
||||
{
|
||||
sMutex.unlock();
|
||||
running_timer->do_callback(); // May not throw exceptions.
|
||||
sMutex.lock();
|
||||
handle.mMutex.unlock(); // Allow other thread to return from cancel() and possibly delete the callback object.
|
||||
}
|
||||
|
||||
// Erase the timer from the running list.
|
||||
sTimerList.erase(running_timer);
|
||||
}
|
||||
sMutex.unlock();
|
||||
}
|
||||
|
||||
136
indra/llcommon/aiframetimer.h
Normal file
136
indra/llcommon/aiframetimer.h
Normal file
@@ -0,0 +1,136 @@
|
||||
/**
|
||||
* @file aiframetimer.h
|
||||
* @brief Implementation of AIFrameTimer.
|
||||
*
|
||||
* Copyright (c) 2011, Aleric Inglewood.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* CHANGELOG
|
||||
* and additional copyright holders.
|
||||
*
|
||||
* 05/08/2011
|
||||
* Initial version, written by Aleric Inglewood @ SL
|
||||
*/
|
||||
|
||||
#ifndef AIFRAMETIMER_H
|
||||
#define AIFRAMETIMER_H
|
||||
|
||||
#include "llframetimer.h"
|
||||
#include "llthread.h"
|
||||
#include <boost/signals2.hpp>
|
||||
#include <set>
|
||||
|
||||
class LL_COMMON_API AIFrameTimer
|
||||
{
|
||||
protected:
|
||||
typedef boost::signals2::signal<void (void)> signal_type;
|
||||
|
||||
private:
|
||||
// Use separate struct for this object because it is non-copyable.
|
||||
struct Signal {
|
||||
signal_type mSignal;
|
||||
};
|
||||
|
||||
// Notes on Thread-Safety
|
||||
//
|
||||
// This is the type of the objects stored in AIFrameTimer::sTimerList, and as such leans
|
||||
// for it's thread-safety on the same lock as is used for that std::multiset as follows.
|
||||
// An arbitrary thread can create, insert and initialize this object. Other threads can
|
||||
// not access it until that has completed.
|
||||
//
|
||||
// After creation two threads can access it: the thread that created it (owns the
|
||||
// AIFrameTimer object, which has an mHandle that points to this object), or the main
|
||||
// thread by finding it in sTimerList.
|
||||
//
|
||||
// See aiframetimer.cpp for more notes.
|
||||
class AIRunningFrameTimer {
|
||||
private:
|
||||
F64 mExpire; // Time at which the timer expires, in seconds since application start (compared to LLFrameTimer::sFrameTime).
|
||||
Signal* mCallback;
|
||||
AIFrameTimer* mTimer;
|
||||
|
||||
public:
|
||||
AIRunningFrameTimer(F64 expiration, AIFrameTimer* timer) : mExpire(LLFrameTimer::getElapsedSeconds() + expiration), mCallback(new Signal), mTimer(timer) { }
|
||||
~AIRunningFrameTimer() { delete mCallback; }
|
||||
void init(signal_type::slot_type const& slot) const { mCallback->mSignal.connect(slot); }
|
||||
|
||||
friend bool operator<(AIRunningFrameTimer const& ft1, AIRunningFrameTimer const& ft2) { return ft1.mExpire < ft2.mExpire; }
|
||||
|
||||
void do_callback(void) const { mCallback->mSignal(); }
|
||||
F64 expiration(void) const { return mExpire; }
|
||||
AIFrameTimer* getTimer(void) const { return mTimer; }
|
||||
};
|
||||
|
||||
typedef std::multiset<AIRunningFrameTimer> timer_list_type;
|
||||
|
||||
static LLMutex sMutex; // Mutex for the two global variables below.
|
||||
static timer_list_type sTimerList; // List with all running timers.
|
||||
static F64 sNextExpiration; // Cache of smallest value in sTimerList.
|
||||
friend class LLFrameTimer; // Access to sNextExpiration.
|
||||
|
||||
class Handle {
|
||||
public:
|
||||
timer_list_type::iterator mRunningTimer; // Points to the running timer, or to sTimerList.end() when not running.
|
||||
// Access to this iterator is protected by the AIFrameTimer::sMutex!
|
||||
LLMutex mMutex; // A mutex used to protect us from deletion of the callback object while
|
||||
// calling the callback function in the case of simultaneous expiration
|
||||
// and cancellation by the thread owning the AIFrameTimer (by calling
|
||||
// AIFrameTimer::cancel).
|
||||
|
||||
// Constructor for a not-running timer.
|
||||
Handle(void) : mRunningTimer(sTimerList.end()) { }
|
||||
|
||||
// Actual initialization used by AIFrameTimer::create.
|
||||
void init(timer_list_type::iterator const& running_timer, signal_type::slot_type const& slot)
|
||||
{
|
||||
// Locking AIFrameTimer::sMutex is not neccessary here, because we're creating
|
||||
// the object and no other thread knows of mRunningTimer at this point.
|
||||
mRunningTimer = running_timer;
|
||||
mRunningTimer->init(slot);
|
||||
}
|
||||
|
||||
private:
|
||||
// LLMutex has no assignment operator.
|
||||
Handle& operator=(Handle const&) { return *this; }
|
||||
};
|
||||
|
||||
Handle mHandle;
|
||||
|
||||
public:
|
||||
// Construct an AIFrameTimer that is not running.
|
||||
AIFrameTimer(void) { }
|
||||
|
||||
// Construction of a running AIFrameTimer with expiration time expiration in seconds, and callback slot.
|
||||
AIFrameTimer(F64 expiration, signal_type::slot_type const& slot) { create(expiration, slot); }
|
||||
|
||||
// Destructing the AIFrameTimer object terminates the running timer (if still running).
|
||||
// Note that cancel() must have returned BEFORE anything is destructed that would disallow the callback function to be called.
|
||||
// So, if the AIFrameTimer is a member of an object whose callback function is called then cancel() has
|
||||
// to be called manually (or from the destructor of THAT object), before that object is destructed.
|
||||
// Cancel may be called multiple times.
|
||||
~AIFrameTimer() { cancel(); }
|
||||
|
||||
void create(F64 expiration, signal_type::slot_type const& slot);
|
||||
void cancel(void);
|
||||
|
||||
protected:
|
||||
static void handleExpiration(F64 current_frame_time);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -35,56 +35,59 @@
|
||||
#include "u64.h"
|
||||
|
||||
#include "llframetimer.h"
|
||||
#include "aiframetimer.h"
|
||||
#include "llaprpool.h"
|
||||
|
||||
// Local constants.
|
||||
static F64 const USEC_PER_SECOND = 1000000.0;
|
||||
static F64 const USEC_TO_SEC_F64 = 0.000001;
|
||||
static F64 const NEVER = 1e16;
|
||||
|
||||
// Static members
|
||||
U64 const LLFrameTimer::sStartTotalTime = totalTime(); // Application start in microseconds since epoch.
|
||||
U64 LLFrameTimer::sTotalTime = LLFrameTimer::sStartTotalTime; // Current time in microseconds since epoch, updated at least once per frame.
|
||||
F64 LLFrameTimer::sTotalSeconds = // Current time in seconds since epoch, updated together with LLFrameTimer::sTotalTime.
|
||||
U64_to_F64(LLFrameTimer::sTotalTime) * USEC_TO_SEC_F64;
|
||||
U64_to_F64(LLFrameTimer::sTotalTime) * USEC_TO_SEC_F64;
|
||||
F64 LLFrameTimer::sFrameTime = 0.0; // Current time in seconds since application start, updated together with LLFrameTimer::sTotalTime.
|
||||
// Updated exactly once per frame:
|
||||
S32 LLFrameTimer::sFrameCount = 0; // Current frame number (number of frames since application start).
|
||||
U64 LLFrameTimer::sPrevTotalTime = LLFrameTimer::sStartTotalTime; // Previous (frame) time in microseconds since epoch, updated once per frame.
|
||||
U64 LLFrameTimer::sFrameDeltaTime = 0; // Microseconds between last two calls to LLFrameTimer::updateFrameTimeAndCount.
|
||||
// Mutex for the above.
|
||||
apr_thread_mutex_t* LLFrameTimer::sGlobalMutex;
|
||||
|
||||
// static
|
||||
void LLFrameTimer::updateFrameTime()
|
||||
void LLFrameTimer::global_initialization(void)
|
||||
{
|
||||
apr_thread_mutex_create(&sGlobalMutex, APR_THREAD_MUTEX_UNNESTED, LLAPRRootPool::get()());
|
||||
AIFrameTimer::sNextExpiration = NEVER;
|
||||
}
|
||||
|
||||
// static
|
||||
void LLFrameTimer::updateFrameTime(void)
|
||||
{
|
||||
llassert(is_main_thread());
|
||||
sTotalTime = totalTime();
|
||||
sTotalSeconds = U64_to_F64(sTotalTime) * USEC_TO_SEC_F64;
|
||||
sFrameTime = U64_to_F64(sTotalTime - sStartTotalTime) * USEC_TO_SEC_F64;
|
||||
}
|
||||
F64 new_frame_time = U64_to_F64(sTotalTime - sStartTotalTime) * USEC_TO_SEC_F64;
|
||||
apr_thread_mutex_lock(sGlobalMutex);
|
||||
sFrameTime = new_frame_time;
|
||||
apr_thread_mutex_unlock(sGlobalMutex);
|
||||
}
|
||||
|
||||
// static
|
||||
void LLFrameTimer::updateFrameTimeAndCount()
|
||||
void LLFrameTimer::updateFrameTimeAndCount(void)
|
||||
{
|
||||
updateFrameTime();
|
||||
sFrameDeltaTime = sTotalTime - sPrevTotalTime;
|
||||
sPrevTotalTime = sTotalTime;
|
||||
++sFrameCount;
|
||||
}
|
||||
|
||||
void LLFrameTimer::reset(F32 expiration)
|
||||
{
|
||||
llassert(!mPaused);
|
||||
mStartTime = sFrameTime;
|
||||
mExpiry = sFrameTime + expiration;
|
||||
}
|
||||
|
||||
void LLFrameTimer::start(F32 expiration)
|
||||
{
|
||||
reset(expiration);
|
||||
mRunning = true; // Start, if not already started.
|
||||
}
|
||||
|
||||
void LLFrameTimer::stop()
|
||||
{
|
||||
llassert(!mPaused);
|
||||
mRunning = false;
|
||||
// Handle AIFrameTimer expiration and callbacks.
|
||||
if (AIFrameTimer::sNextExpiration <= sFrameTime)
|
||||
{
|
||||
AIFrameTimer::handleExpiration(sFrameTime);
|
||||
}
|
||||
}
|
||||
|
||||
// Don't combine pause/unpause with start/stop
|
||||
@@ -95,38 +98,38 @@ void LLFrameTimer::stop()
|
||||
// foo.unpause() // unpauses
|
||||
// F32 elapsed = foo.getElapsedTimeF32() // does not include time between pause() and unpause()
|
||||
// Note: elapsed would also be valid with no unpause() call (= time run until pause() called)
|
||||
void LLFrameTimer::pause()
|
||||
void LLFrameTimer::pause(void)
|
||||
{
|
||||
llassert(is_main_thread());
|
||||
if (!mPaused)
|
||||
{
|
||||
// Only the main thread writes to sFrameTime, so there is no need for locking.
|
||||
mStartTime = sFrameTime - mStartTime; // Abuse mStartTime to store the elapsed time so far.
|
||||
}
|
||||
mPaused = true;
|
||||
}
|
||||
|
||||
void LLFrameTimer::unpause()
|
||||
void LLFrameTimer::unpause(void)
|
||||
{
|
||||
llassert(is_main_thread());
|
||||
if (mPaused)
|
||||
{
|
||||
// Only the main thread writes to sFrameTime, so there is no need for locking.
|
||||
mStartTime = sFrameTime - mStartTime; // Set mStartTime consistent with the elapsed time so far.
|
||||
}
|
||||
mPaused = false;
|
||||
}
|
||||
|
||||
void LLFrameTimer::setTimerExpirySec(F32 expiration)
|
||||
{
|
||||
llassert(!mPaused);
|
||||
mExpiry = mStartTime + expiration;
|
||||
}
|
||||
|
||||
void LLFrameTimer::setExpiryAt(F64 seconds_since_epoch)
|
||||
{
|
||||
llassert(is_main_thread());
|
||||
llassert(!mPaused);
|
||||
// Only the main thread writes to sFrameTime, so there is no need for locking.
|
||||
mStartTime = sFrameTime;
|
||||
mExpiry = seconds_since_epoch - (USEC_TO_SEC_F64 * sStartTotalTime);
|
||||
}
|
||||
|
||||
F64 LLFrameTimer::expiresAt() const
|
||||
F64 LLFrameTimer::expiresAt(void) const
|
||||
{
|
||||
F64 expires_at = U64_to_F64(sStartTotalTime) * USEC_TO_SEC_F64;
|
||||
expires_at += mExpiry;
|
||||
@@ -135,31 +138,47 @@ F64 LLFrameTimer::expiresAt() const
|
||||
|
||||
bool LLFrameTimer::checkExpirationAndReset(F32 expiration)
|
||||
{
|
||||
if (hasExpired())
|
||||
llassert(!mPaused);
|
||||
F64 frame_time = getElapsedSeconds();
|
||||
if (frame_time >= mExpiry)
|
||||
{
|
||||
reset(expiration);
|
||||
mStartTime = frame_time;
|
||||
mExpiry = mStartTime + expiration;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// static
|
||||
F32 LLFrameTimer::getFrameDeltaTimeF32()
|
||||
F32 LLFrameTimer::getElapsedTimeAndResetF32(void)
|
||||
{
|
||||
llassert(mRunning && !mPaused);
|
||||
F64 frame_time = getElapsedSeconds();
|
||||
F32 elapsed_time = (F32)(frame_time - mStartTime);
|
||||
mExpiry = mStartTime = frame_time;
|
||||
return elapsed_time;
|
||||
}
|
||||
|
||||
// static
|
||||
// Return number of seconds between the last two frames.
|
||||
F32 LLFrameTimer::getFrameDeltaTimeF32(void)
|
||||
{
|
||||
llassert(is_main_thread());
|
||||
// Only the main thread writes to sFrameDeltaTime, so there is no need for locking.
|
||||
return (F32)(U64_to_F64(sFrameDeltaTime) * USEC_TO_SEC_F64);
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
// static
|
||||
// Return seconds since the current frame started
|
||||
F32 LLFrameTimer::getCurrentFrameTime()
|
||||
F32 LLFrameTimer::getCurrentFrameTime(void)
|
||||
{
|
||||
llassert(is_main_thread());
|
||||
// Only the main thread writes to sTotalTime, so there is no need for locking.
|
||||
U64 frame_time = totalTime() - sTotalTime;
|
||||
return (F32)(U64_to_F64(frame_time) * USEC_TO_SEC_F64);
|
||||
}
|
||||
|
||||
// Glue code to avoid full class .h file #includes
|
||||
F32 getCurrentFrameTime()
|
||||
F32 getCurrentFrameTime(void)
|
||||
{
|
||||
return (F32)(LLFrameTimer::getCurrentFrameTime());
|
||||
}
|
||||
|
||||
@@ -43,88 +43,131 @@
|
||||
|
||||
#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) : mStartTime(sFrameTime), mExpiry(0), mRunning(true), mPaused(false) { }
|
||||
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()
|
||||
static F64 getElapsedSeconds(void)
|
||||
{
|
||||
// Loses msec precision after ~4.5 hours...
|
||||
return sFrameTime;
|
||||
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()
|
||||
static U64 getTotalTime(void)
|
||||
{
|
||||
llassert(sTotalTime);
|
||||
return sTotalTime;
|
||||
// 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()
|
||||
static F64 getTotalSeconds(void)
|
||||
{
|
||||
return sTotalSeconds;
|
||||
// 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();
|
||||
static void updateFrameTime(void);
|
||||
|
||||
// Call this method once, and only once, per frame to update the current frame count and sFrameDeltaTime.
|
||||
static void updateFrameTimeAndCount();
|
||||
|
||||
// Return current frame number (the number of frames since application start).
|
||||
static U32 getFrameCount() { return sFrameCount; }
|
||||
static void updateFrameTimeAndCount(void);
|
||||
|
||||
// Return duration of last frame in seconds.
|
||||
static F32 getFrameDeltaTimeF32();
|
||||
static F32 getFrameDeltaTimeF32(void);
|
||||
|
||||
// Return seconds since the current frame started
|
||||
static F32 getCurrentFrameTime();
|
||||
static F32 getCurrentFrameTime(void);
|
||||
|
||||
// MANIPULATORS
|
||||
|
||||
void reset(F32 expiration = 0.f); // Same as start() but leaves mRunning off when called after stop().
|
||||
void start(F32 expiration = 0.f); // Reset and (re)start with expiration.
|
||||
void stop(); // Stop running.
|
||||
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);
|
||||
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() { F32 t = getElapsedTimeF32(); reset(); return t; }
|
||||
void setAge(const F64 age) { llassert(!mPaused); mStartTime = sFrameTime - age; }
|
||||
F32 getElapsedTimeAndResetF32(void);
|
||||
void setAge(const F64 age) { llassert(!mPaused); mStartTime = getElapsedSeconds() - age; }
|
||||
|
||||
// ACCESSORS
|
||||
bool hasExpired() const { return sFrameTime >= mExpiry; }
|
||||
F32 getElapsedTimeF32() const { llassert(mRunning); return mPaused ? (F32)mStartTime : (F32)(sFrameTime - mStartTime); }
|
||||
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;
|
||||
|
||||
protected:
|
||||
// A single, high resolution timer that drives all LLFrameTimers
|
||||
// *NOTE: no longer used.
|
||||
//static LLTimer sInternalTimer;
|
||||
public:
|
||||
// Do one-time initialization of the static members.
|
||||
static void global_initialization(void);
|
||||
|
||||
protected:
|
||||
//
|
||||
// Aplication constants
|
||||
// Application constants
|
||||
//
|
||||
|
||||
// Application start in microseconds since epoch.
|
||||
static U64 const sStartTotalTime;
|
||||
|
||||
//
|
||||
// Data updated per frame
|
||||
// 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;
|
||||
|
||||
|
||||
@@ -775,7 +775,7 @@ char* LLPrivateMemoryPool::LLMemoryBlock::allocate()
|
||||
void LLPrivateMemoryPool::LLMemoryBlock::freeMem(void* addr)
|
||||
{
|
||||
//bit index
|
||||
U32 idx = ((U32)addr - (U32)mBuffer - mDummySize) / mSlotSize ;
|
||||
U32 idx = (static_cast<U32>((char*)addr - mBuffer) - mDummySize) / mSlotSize ;
|
||||
|
||||
U32* bits = &mUsageBits ;
|
||||
if(idx >= 32)
|
||||
@@ -957,7 +957,7 @@ char* LLPrivateMemoryPool::LLMemoryChunk::allocate(U32 size)
|
||||
|
||||
void LLPrivateMemoryPool::LLMemoryChunk::freeMem(void* addr)
|
||||
{
|
||||
U32 blk_idx = getPageIndex((U32)addr) ;
|
||||
U32 blk_idx = getPageIndex((char*)addr);
|
||||
LLMemoryBlock* blk = (LLMemoryBlock*)(mMetaBuffer + blk_idx * sizeof(LLMemoryBlock)) ;
|
||||
blk = blk->mSelf ;
|
||||
|
||||
@@ -982,7 +982,7 @@ bool LLPrivateMemoryPool::LLMemoryChunk::empty()
|
||||
|
||||
bool LLPrivateMemoryPool::LLMemoryChunk::containsAddress(const char* addr) const
|
||||
{
|
||||
return (U32)mBuffer <= (U32)addr && (U32)mBuffer + mBufferSize > (U32)addr ;
|
||||
return (size_t)mBuffer <= (size_t)addr && (size_t)mBuffer + mBufferSize > (size_t)addr ;
|
||||
}
|
||||
|
||||
//debug use
|
||||
@@ -1339,9 +1339,9 @@ void LLPrivateMemoryPool::LLMemoryChunk::addToAvailBlockList(LLMemoryBlock* blk)
|
||||
return ;
|
||||
}
|
||||
|
||||
U32 LLPrivateMemoryPool::LLMemoryChunk::getPageIndex(U32 addr)
|
||||
U32 LLPrivateMemoryPool::LLMemoryChunk::getPageIndex(char const* addr)
|
||||
{
|
||||
return (addr - (U32)mDataBuffer) / mMinBlockSize ;
|
||||
return static_cast<U32>(addr - mDataBuffer) / mMinBlockSize ;
|
||||
}
|
||||
|
||||
//for mAvailBlockList
|
||||
@@ -1679,7 +1679,7 @@ void LLPrivateMemoryPool::removeChunk(LLMemoryChunk* chunk)
|
||||
|
||||
U16 LLPrivateMemoryPool::findHashKey(const char* addr)
|
||||
{
|
||||
return (((U32)addr) / CHUNK_SIZE) % mHashFactor ;
|
||||
return (((size_t)addr) / CHUNK_SIZE) % mHashFactor ;
|
||||
}
|
||||
|
||||
LLPrivateMemoryPool::LLMemoryChunk* LLPrivateMemoryPool::findChunk(const char* addr)
|
||||
|
||||
@@ -250,7 +250,7 @@ public:
|
||||
{
|
||||
bool operator()(const LLMemoryBlock* const& lhs, const LLMemoryBlock* const& rhs)
|
||||
{
|
||||
return (U32)lhs->getBuffer() < (U32)rhs->getBuffer();
|
||||
return (size_t)lhs->getBuffer() < (size_t)rhs->getBuffer();
|
||||
}
|
||||
};
|
||||
};
|
||||
@@ -281,7 +281,7 @@ public:
|
||||
void dump() ;
|
||||
|
||||
private:
|
||||
U32 getPageIndex(U32 addr) ;
|
||||
U32 getPageIndex(char const* addr) ;
|
||||
U32 getBlockLevel(U32 size) ;
|
||||
U16 getPageLevel(U32 size) ;
|
||||
LLMemoryBlock* addBlock(U32 blk_idx) ;
|
||||
@@ -526,4 +526,4 @@ void LLPrivateMemoryPoolTester::operator delete[](void* addr)
|
||||
#include "llsingleton.h"
|
||||
#include "llsafehandle.h"
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -30,8 +30,8 @@
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include "linden_common.h"
|
||||
#include <iostream>
|
||||
|
||||
#include "llsaleinfo.h"
|
||||
|
||||
|
||||
@@ -593,6 +593,9 @@ bool LLAppViewer::init()
|
||||
// we run the "program crashed last time" error handler below.
|
||||
//
|
||||
|
||||
// We can call this early.
|
||||
LLFrameTimer::global_initialization();
|
||||
|
||||
// initialize SSE options
|
||||
LLVector4a::initClass();
|
||||
// Need to do this initialization before we do anything else, since anything
|
||||
|
||||
@@ -2552,7 +2552,7 @@ void LLPipeline::processPartitionQ()
|
||||
void LLPipeline::markRebuild(LLSpatialGroup* group, BOOL priority)
|
||||
{
|
||||
LLMemType mt(LLMemType::MTYPE_PIPELINE);
|
||||
//assert_main_thread();
|
||||
//llassert(is_main_thread());
|
||||
|
||||
if (group && !group->isDead() && group->mSpatialPartition)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user