This commit is contained in:
Inusaito Sayori
2014-08-19 19:55:34 -04:00
18 changed files with 404 additions and 337 deletions

View File

@@ -293,7 +293,36 @@ void AIEngine::add(AIStateMachine* state_machine)
}
}
extern void print_statemachine_diagnostics(U64 total_clocks, U64 max_delta, AIEngine::queued_type::const_reference slowest_state_machine);
#if STATE_MACHINE_PROFILING
// Called from AIStateMachine::mainloop
void print_statemachine_diagnostics(U64 total_clocks, AIStateMachine::StateTimerBase::TimeData& slowest_timer, AIEngine::queued_type::const_reference slowest_element)
{
AIStateMachine const& slowest_state_machine = slowest_element.statemachine();
F64 const tfactor = 1000 / calc_clock_frequency();
std::ostringstream msg;
U64 max_delta = slowest_timer.GetDuration();
if (total_clocks > max_delta)
{
msg << "AIStateMachine::mainloop did run for " << (total_clocks * tfactor) << " ms. The slowest ";
}
else
{
msg << "AIStateMachine::mainloop: A ";
}
msg << "state machine " << "(" << slowest_state_machine.getName() << ") " << "ran for " << (max_delta * tfactor) << " ms";
if (slowest_state_machine.getRuntime() > max_delta)
{
msg << " (" << (slowest_state_machine.getRuntime() * tfactor) << " ms in total now)";
}
msg << ".\n";
AIStateMachine::StateTimerBase::DumpTimers(msg);
llwarns << msg.str() << llendl;
}
#endif
// MAIN-THREAD
void AIEngine::mainloop(void)
@@ -305,28 +334,33 @@ void AIEngine::mainloop(void)
queued_element = engine_state_w->list.begin();
}
U64 total_clocks = 0;
#ifndef LL_RELEASE_FOR_DOWNLOAD
U64 max_delta = 0;
#if STATE_MACHINE_PROFILING
queued_type::value_type slowest_element(NULL);
AIStateMachine::StateTimerRoot::TimeData slowest_timer;
#endif
while (queued_element != end)
{
AIStateMachine& state_machine(queued_element->statemachine());
U64 start = get_clock_count();
if (!state_machine.sleep(start))
AIStateMachine::StateTimerBase::TimeData time_data;
if (!state_machine.sleep(get_clock_count()))
{
state_machine.multiplex(AIStateMachine::normal_run);
AIStateMachine::StateTimerRoot timer(state_machine.getName());
state_machine.multiplex(AIStateMachine::normal_run);
time_data = timer.GetTimerData();
}
U64 delta = get_clock_count() - start;
state_machine.add(delta);
total_clocks += delta;
#ifndef LL_RELEASE_FOR_DOWNLOAD
if (delta > max_delta)
if (U64 delta = time_data.GetDuration())
{
max_delta = delta;
slowest_element = *queued_element;
}
state_machine.add(delta);
total_clocks += delta;
#if STATE_MACHINE_PROFILING
if (delta > slowest_timer.GetDuration())
{
slowest_element = *queued_element;
slowest_timer = time_data;
}
#endif
}
bool active = state_machine.active(this); // This locks mState shortly, so it must be called before locking mEngineState because add() locks mEngineState while holding mState.
engine_state_type_wat engine_state_w(mEngineState);
if (!active)
@@ -340,8 +374,8 @@ void AIEngine::mainloop(void)
}
if (total_clocks >= sMaxCount)
{
#ifndef LL_RELEASE_FOR_DOWNLOAD
print_statemachine_diagnostics(total_clocks, max_delta, slowest_element);
#if STATE_MACHINE_PROFILING
print_statemachine_diagnostics(total_clocks, slowest_timer, slowest_element);
#endif
Dout(dc::statemachine, "Sorting " << engine_state_w->list.size() << " state machines.");
engine_state_w->list.sort(QueueElementComp());
@@ -752,6 +786,22 @@ void AIStateMachine::multiplex(event_type event)
}
}
#if STATE_MACHINE_PROFILING
std::vector<AIStateMachine::StateTimerBase*> AIStateMachine::StateTimerBase::mTimerStack;
AIStateMachine::StateTimerBase::TimeData AIStateMachine::StateTimerBase::TimeData::sRoot("");
void AIStateMachine::StateTimer::TimeData::DumpTimer(std::ostringstream& msg, std::string prefix)
{
F64 const tfactor = 1000 / calc_clock_frequency();
msg << prefix << mName << " " << (mEnd - mStart)*tfactor << "ms" << std::endl;
prefix.push_back(' ');
std::vector<TimeData>::iterator it;
for (it = mChildren.begin(); it != mChildren.end(); ++it)
{
it->DumpTimer(msg, prefix);
}
}
#endif
AIStateMachine::state_type AIStateMachine::begin_loop(base_state_type base_state)
{
DoutEntering(dc::statemachine(mSMDebug), "AIStateMachine::begin_loop(" << state_str(base_state) << ") [" << (void*)this << "]");

View File

@@ -36,6 +36,7 @@
#include "aithreadsafe.h"
#include <llpointer.h>
#include "lltimer.h"
#include <list>
#include <boost/signals2.hpp>
@@ -98,11 +99,140 @@ class AIEngine
extern AIEngine gMainThreadEngine;
extern AIEngine gStateMachineThreadEngine;
#ifndef STATE_MACHINE_PROFILING
#define STATE_MACHINE_PROFILING (LL_RELEASE_FOR_DOWNLOAD)
#endif
class AIStateMachine : public LLThreadSafeRefCount
{
public:
typedef U32 state_type; //!< The type of run_state
// A simple timer class that will calculate time delta between ctor and GetTimerData call.
// Time data is stored as a nested TimeData object.
// If STATE_MACHINE_PROFILING is defined then a stack of all StateTimers from root is maintained for debug output.
class StateTimerBase
{
public:
class TimeData
{
friend class StateTimerBase;
public:
TimeData() : mStart(-1), mEnd(-1) {}
U64 GetDuration() { return mEnd - mStart; }
private:
U64 mStart, mEnd;
#if !STATE_MACHINE_PROFILING
TimeData(const std::string& name) : mStart(get_clock_count()), mEnd(get_clock_count()) {}
#else
TimeData(const std::string& name) : mName(name), mStart(get_clock_count()), mEnd(get_clock_count()) {}
void DumpTimer(std::ostringstream& msg, std::string prefix);
std::vector<TimeData> mChildren;
std::string mName;
static TimeData sRoot;
#endif
};
protected:
#if !STATE_MACHINE_PROFILING
StateTimerBase(const std::string& name) : mData(name) {}
~StateTimerBase() {}
TimeData mData;
// Return a copy of the underlying timer data.
// This allows the data live beyond the scope of the state timer.
public:
const TimeData GetTimerData()
{
mData.mEnd = get_clock_count(); //set mEnd to current time, since GetTimerData() will always be called before the dtor, obv.
return mData;
}
#else
// Ctors/dtors are hidden. Only StateTimerRoot and StateTimer are permitted to access them.
StateTimerBase() : mData(NULL) {}
~StateTimerBase()
{
// If mData is null then the timer was not registered due to being in the wrong thread or the root timer wasn't in the expected state.
if (!mData)
return;
mData->mEnd = get_clock_count();
mTimerStack.pop_back();
}
// Also hide internals from everything except StateTimerRoot and StateTimer
bool AddAsRoot(const std::string& name)
{
if (!is_main_thread())
return true; //Ignoring this timer, but pretending it was added.
if (!mTimerStack.empty())
return false;
TimeData::sRoot = TimeData(name);
mData = &TimeData::sRoot;
mData->mChildren.clear();
mTimerStack.push_back(this);
return true;
}
bool AddAsChild(const std::string& name)
{
if (!is_main_thread())
return true; //Ignoring this timer, but pretending it was added.
if (mTimerStack.empty())
return false;
mTimerStack.back()->mData->mChildren.push_back(TimeData(name));
mData = &mTimerStack.back()->mData->mChildren.back();
mTimerStack.push_back(this);
return true;
}
TimeData* mData;
static std::vector<StateTimerBase*> mTimerStack;
public:
// Debug spew
static void DumpTimers(std::ostringstream& msg)
{
TimeData::sRoot.DumpTimer(msg, "");
}
// Return a copy of the underlying timer data.
// This allows the data live beyond the scope of the state timer.
const TimeData GetTimerData() const
{
if (mData)
{
TimeData ret = *mData;
ret.mEnd = get_clock_count(); //set mEnd to current time, since GetTimerData() will always be called before the dtor, obv.
return ret;
}
return TimeData();
}
#endif
};
public:
#if !STATE_MACHINE_PROFILING
typedef StateTimerBase StateTimerRoot;
typedef StateTimerBase StateTimer;
#else
class StateTimerRoot : public StateTimerBase
{ //A StateTimerRoot can become a child if a root already exists.
public:
StateTimerRoot(const std::string& name)
{
if(!AddAsRoot(name))
AddAsChild(name);
}
};
class StateTimer : public StateTimerBase
{ //A StateTimer can never become a root
public:
StateTimer(const std::string& name)
{
AddAsChild(name);
}
};
#endif
protected:
// The type of event that causes multiplex() to be called.
enum event_type {
@@ -302,6 +432,9 @@ class AIStateMachine : public LLThreadSafeRefCount
void add(U64 count) { mRuntime += count; }
U64 getRuntime(void) const { return mRuntime; }
// For diagnostics. Every derived class must override this.
virtual const char* getName() const = 0;
protected:
virtual void initialize_impl(void) = 0;
virtual void multiplex_impl(state_type run_state) = 0;

View File

@@ -232,6 +232,13 @@ class AIStateMachineThread : public AIStateMachineThreadBase {
// Accessor.
THREAD_IMPL& thread_impl(void) { return mThreadImpl; }
/*virtual*/ const char* getName() const
{
#define STRIZE(arg) #arg
return "AIStateMachineThread<"STRIZE(THREAD_IMPL)">";
#undef STRIZE
}
protected:
/*virtual*/ AIThreadImpl& impl(void) { return mThreadImpl; }
};

View File

@@ -98,6 +98,8 @@ class AITimer : public AIStateMachine {
*/
F64 getInterval(void) const { return mInterval; }
/*virtual*/ const char* getName() const { return "AITimer"; }
protected:
// Call finish() (or abort()), not delete.
/*virtual*/ ~AITimer() { DoutEntering(dc::statemachine(mSMDebug), "~AITimer() [" << (void*)this << "]"); mFrameTimer.cancel(); }

View File

@@ -105,8 +105,9 @@ void LLAvatarJoint::setValid( BOOL valid, BOOL recursive )
for (child_list_t::iterator iter = mChildren.begin();
iter != mChildren.end(); ++iter)
{
LLAvatarJoint* joint = (LLAvatarJoint*)(*iter);
joint->setValid(valid, TRUE);
LLAvatarJoint* joint = dynamic_cast<LLAvatarJoint*>(*iter);
if (joint)
joint->setValid(valid, TRUE);
}
}
@@ -138,8 +139,9 @@ void LLAvatarJoint::setVisible(BOOL visible, BOOL recursive)
for (child_list_t::iterator iter = mChildren.begin();
iter != mChildren.end(); ++iter)
{
LLAvatarJoint* joint = (LLAvatarJoint*)(*iter);
joint->setVisible(visible, recursive);
LLAvatarJoint* joint = dynamic_cast<LLAvatarJoint*>(*iter);
if(joint)
joint->setVisible(visible, recursive);
}
}
}

View File

@@ -366,8 +366,9 @@ void LLAvatarJointMesh::setupJoint(LLAvatarJoint* current_joint)
for (LLJoint::child_list_t::iterator iter = current_joint->mChildren.begin();
iter != current_joint->mChildren.end(); ++iter)
{
LLAvatarJoint* child_joint = (LLAvatarJoint*)(*iter);
setupJoint(child_joint);
LLAvatarJoint* child_joint = dynamic_cast<LLAvatarJoint*>(*iter);
if(child_joint)
setupJoint(child_joint);
}
}

View File

@@ -154,13 +154,13 @@ BOOL LLPolySkeletalDistortion::setInfo(LLPolySkeletalDistortionInfo *info)
for (LLJoint::child_list_t::iterator iter = joint->mChildren.begin();
iter != joint->mChildren.end(); ++iter)
{
LLAvatarJoint* child_joint = (LLAvatarJoint*)(*iter);
if (child_joint->inheritScale())
{
LLVector3 childDeformation = LLVector3(child_joint->getScale());
childDeformation.scaleVec(bone_info->mScaleDeformation);
mJointScales[child_joint] = childDeformation;
}
LLAvatarJoint* child_joint = dynamic_cast<LLAvatarJoint*>(*iter);
if (child_joint && child_joint->inheritScale())
{
LLVector3 childDeformation = LLVector3(child_joint->getScale());
childDeformation.scaleVec(bone_info->mScaleDeformation);
mJointScales[child_joint] = childDeformation;
}
}
if (bone_info->mHasPositionDeformation)

View File

@@ -239,7 +239,7 @@ inline typename T::mapped_type get_ptr_in_map(const T& inmap, typename T::key_ty
//
//Singu note: This has been generalized to support a broader range of sequence containers
template <typename T>
inline typename T::iterator vector_replace_with_last(T& invec, typename T::iterator& iter)
inline typename T::iterator vector_replace_with_last(T& invec, typename T::iterator iter)
{
typename T::iterator last = invec.end();
if (iter == invec.end())

View File

@@ -78,7 +78,7 @@ LLURLRequest::LLURLRequest(LLURLRequest::ERequestAction action, std::string cons
LLHTTPClient::ResponderPtr responder, AIHTTPHeaders& headers, AIPerService::Approvement* approved,
bool keepalive, bool is_auth, bool compression) :
mAction(action), mURL(url), mKeepAlive(keepalive), mIsAuth(is_auth), mNoCompression(!compression),
mBody(body), mResponder(responder), mHeaders(headers), mResponderNameCache(responder ? responder->getName() : "<uninitialized>")
mBody(body), mResponder(responder), mHeaders(headers), mResponderNameCache(std::string("LLURLRequest:") + std::string(responder ? responder->getName() : "<uninitialized>"))
{
if (approved)
{
@@ -276,32 +276,4 @@ bool LLURLRequest::configure(AICurlEasyRequest_wat const& curlEasyRequest_w)
return rv;
}
// Called from AIStateMachine::mainloop, but put here because we don't want to include llurlrequest.h there of course.
void print_statemachine_diagnostics(U64 total_clocks, U64 max_delta, AIEngine::queued_type::const_reference slowest_element)
{
AIStateMachine const& slowest_state_machine = slowest_element.statemachine();
LLURLRequest const* request = dynamic_cast<LLURLRequest const*>(&slowest_state_machine);
F64 const tfactor = 1000 / calc_clock_frequency();
std::ostringstream msg;
if (total_clocks > max_delta)
{
msg << "AIStateMachine::mainloop did run for " << (total_clocks * tfactor) << " ms. The slowest ";
}
else
{
msg << "AIStateMachine::mainloop: A ";
}
msg << "state machine ";
if (request)
{
msg << "(" << request->getResponderName() << ") ";
}
msg << "ran for " << (max_delta * tfactor) << " ms";
if (slowest_state_machine.getRuntime() > max_delta)
{
msg << " (" << (slowest_state_machine.getRuntime() * tfactor) << " ms in total now)";
}
msg << ".";
llwarns << msg.str() << llendl;
}

View File

@@ -72,7 +72,7 @@ class LLURLRequest : public AICurlEasyRequestStateMachine {
/**
* @brief Cached value of responder->getName() as passed to the constructor.
*/
char const* getResponderName(void) const { return mResponderNameCache; }
/*virtual*/ const char* getName() const { return mResponderNameCache.c_str(); }
protected:
// Call abort(), not delete.
@@ -113,7 +113,7 @@ class LLURLRequest : public AICurlEasyRequestStateMachine {
U32 mBodySize;
LLHTTPClient::ResponderPtr mResponder;
AIHTTPHeaders mHeaders;
char const* mResponderNameCache;
std::string mResponderNameCache;
protected:
// Handle initializing the object.

View File

@@ -1543,6 +1543,8 @@ class UpdateItemSM : public AIStateMachine
static void add(UpdateItem const& ui);
/*virtual*/ const char* getName() const { return "UpdateItemSM"; }
private:
static UpdateItemSM* sSelf;
typedef std::deque<UpdateItem> updateQueue_type;

View File

@@ -766,7 +766,7 @@ std::string LLMeshRepoThread::constructUrl(LLUUID mesh_id)
return http_url;
}
bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id)
bool LLMeshRepoThread::getMeshHeaderInfo(const LLUUID& mesh_id, const char* block_name, MeshHeaderInfo& info)
{ //protected by mMutex
if (!mHeaderMutex)
@@ -774,229 +774,141 @@ bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id)
return false;
}
mHeaderMutex->lock();
LLMutexLock lock(mHeaderMutex);
if (mMeshHeader.find(mesh_id) == mMeshHeader.end())
{ //we have no header info for this mesh, do nothing
mHeaderMutex->unlock();
return false;
}
bool ret = true ;
U32 header_size = mMeshHeaderSize[mesh_id];
if (header_size > 0)
if ((info.mHeaderSize = mMeshHeaderSize[mesh_id]) > 0)
{
S32 version = mMeshHeader[mesh_id]["version"].asInteger();
S32 offset = header_size + mMeshHeader[mesh_id]["skin"]["offset"].asInteger();
S32 size = mMeshHeader[mesh_id]["skin"]["size"].asInteger();
info.mVersion = mMeshHeader[mesh_id]["version"].asInteger();
info.mOffset = info.mHeaderSize + mMeshHeader[mesh_id][block_name]["offset"].asInteger();
info.mSize = mMeshHeader[mesh_id][block_name]["size"].asInteger();
}
return true;
}
mHeaderMutex->unlock();
bool LLMeshRepoThread::loadInfoFromVFS(const LLUUID& mesh_id, MeshHeaderInfo& info, boost::function<bool(const LLUUID&, U8*, S32)> fn)
{
//check VFS for mesh skin info
LLVFile file(gVFS, mesh_id, LLAssetType::AT_MESH);
if (file.getSize() >= info.mOffset + info.mSize)
{
LLMeshRepository::sCacheBytesRead += info.mSize;
if (version <= MAX_MESH_VERSION && offset >= 0 && size > 0)
file.seek(info.mOffset);
U8* buffer = new U8[info.mSize];
file.read(buffer, info.mSize);
//make sure buffer isn't all 0's by checking the first 1KB (reserved block but not written)
bool zero = true;
for (S32 i = 0; i < llmin(info.mSize, S32(1024)) && zero; ++i)
{
//check VFS for mesh skin info
LLVFile file(gVFS, mesh_id, LLAssetType::AT_MESH);
if (file.getSize() >= offset+size)
zero = buffer[i] > 0 ? false : true;
}
if (!zero)
{ //attempt to parse
if (fn(mesh_id, buffer, info.mSize))
{
LLMeshRepository::sCacheBytesRead += size;
file.seek(offset);
U8* buffer = new U8[size];
file.read(buffer, size);
//make sure buffer isn't all 0's by checking the first 1KB (reserved block but not written)
bool zero = true;
for (S32 i = 0; i < llmin(size, 1024) && zero; ++i)
{
zero = buffer[i] > 0 ? false : true;
}
if (!zero)
{ //attempt to parse
if (skinInfoReceived(mesh_id, buffer, size))
{
delete[] buffer;
return true;
}
}
delete[] buffer;
}
//reading from VFS failed for whatever reason, fetch from sim
AIHTTPHeaders headers("Accept", "application/octet-stream");
std::string http_url = constructUrl(mesh_id);
if (!http_url.empty())
{
ret = LLHTTPClient::getByteRange(http_url, headers, offset, size,
new LLMeshSkinInfoResponder(mesh_id, offset, size));
if (ret)
{
LLMeshRepository::sHTTPRequestCount++;
}
return true;
}
}
delete[] buffer;
}
else
{
mHeaderMutex->unlock();
return false;
}
bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id)
{
MeshHeaderInfo info;
if (!getMeshHeaderInfo(mesh_id, "skin", info))
{
return false;
}
if (info.mHeaderSize > 0 && info.mVersion <= MAX_MESH_VERSION && info.mOffset >= 0 && info.mSize > 0)
{
//check VFS for mesh skin info
if (loadInfoFromVFS(mesh_id, info, boost::bind(&LLMeshRepoThread::skinInfoReceived, this, _1, _2, _3 )))
return true;
//reading from VFS failed for whatever reason, fetch from sim
AIHTTPHeaders headers("Accept", "application/octet-stream");
std::string http_url = constructUrl(mesh_id);
if (!http_url.empty())
{
if (!LLHTTPClient::getByteRange(http_url, headers, info.mOffset, info.mSize,
new LLMeshSkinInfoResponder(mesh_id, info.mOffset, info.mSize)))
return false;
LLMeshRepository::sHTTPRequestCount++;
}
}
//early out was not hit, effectively fetched
return ret;
return true;
}
bool LLMeshRepoThread::fetchMeshDecomposition(const LLUUID& mesh_id)
{ //protected by mMutex
if (!mHeaderMutex)
{
MeshHeaderInfo info;
if (!getMeshHeaderInfo(mesh_id, "physics_convex", info))
{
return false;
}
mHeaderMutex->lock();
if (mMeshHeader.find(mesh_id) == mMeshHeader.end())
{ //we have no header info for this mesh, do nothing
mHeaderMutex->unlock();
return false;
}
U32 header_size = mMeshHeaderSize[mesh_id];
bool ret = true ;
if (header_size > 0)
if (info.mHeaderSize > 0 && info.mVersion <= MAX_MESH_VERSION && info.mOffset >= 0 && info.mSize > 0)
{
S32 version = mMeshHeader[mesh_id]["version"].asInteger();
S32 offset = header_size + mMeshHeader[mesh_id]["physics_convex"]["offset"].asInteger();
S32 size = mMeshHeader[mesh_id]["physics_convex"]["size"].asInteger();
if (loadInfoFromVFS(mesh_id, info, boost::bind(&LLMeshRepoThread::decompositionReceived, this, _1, _2, _3 )))
return true;
mHeaderMutex->unlock();
//reading from VFS failed for whatever reason, fetch from sim
AIHTTPHeaders headers("Accept", "application/octet-stream");
if (version <= MAX_MESH_VERSION && offset >= 0 && size > 0)
{
//check VFS for mesh skin info
LLVFile file(gVFS, mesh_id, LLAssetType::AT_MESH);
if (file.getSize() >= offset+size)
{
LLMeshRepository::sCacheBytesRead += size;
file.seek(offset);
U8* buffer = new U8[size];
file.read(buffer, size);
//make sure buffer isn't all 0's by checking the first 1KB (reserved block but not written)
bool zero = true;
for (S32 i = 0; i < llmin(size, 1024) && zero; ++i)
{
zero = buffer[i] > 0 ? false : true;
}
if (!zero)
{ //attempt to parse
if (decompositionReceived(mesh_id, buffer, size))
{
delete[] buffer;
return true;
}
}
delete[] buffer;
}
//reading from VFS failed for whatever reason, fetch from sim
AIHTTPHeaders headers("Accept", "application/octet-stream");
std::string http_url = constructUrl(mesh_id);
if (!http_url.empty())
{
ret = LLHTTPClient::getByteRange(http_url, headers, offset, size,
new LLMeshDecompositionResponder(mesh_id, offset, size));
if(ret)
{
LLMeshRepository::sHTTPRequestCount++;
}
}
std::string http_url = constructUrl(mesh_id);
if (!http_url.empty())
{
if (!LLHTTPClient::getByteRange(http_url, headers, info.mOffset, info.mSize,
new LLMeshDecompositionResponder(mesh_id, info.mOffset, info.mSize)))
return false;
LLMeshRepository::sHTTPRequestCount++;
}
}
else
{
mHeaderMutex->unlock();
}
//early out was not hit, effectively fetched
return ret;
return true;
}
bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id)
{ //protected by mMutex
if (!mHeaderMutex)
{
MeshHeaderInfo info;
if (!getMeshHeaderInfo(mesh_id, "physics_mesh", info))
{
return false;
}
mHeaderMutex->lock();
if (mMeshHeader.find(mesh_id) == mMeshHeader.end())
{ //we have no header info for this mesh, do nothing
mHeaderMutex->unlock();
return false;
}
U32 header_size = mMeshHeaderSize[mesh_id];
bool ret = true ;
if (header_size > 0)
if (info.mHeaderSize > 0)
{
S32 version = mMeshHeader[mesh_id]["version"].asInteger();
S32 offset = header_size + mMeshHeader[mesh_id]["physics_mesh"]["offset"].asInteger();
S32 size = mMeshHeader[mesh_id]["physics_mesh"]["size"].asInteger();
mHeaderMutex->unlock();
if (version <= MAX_MESH_VERSION && offset >= 0 && size > 0)
if (info.mVersion <= MAX_MESH_VERSION && info.mOffset >= 0 && info.mSize > 0)
{
//check VFS for mesh physics shape info
LLVFile file(gVFS, mesh_id, LLAssetType::AT_MESH);
if (file.getSize() >= offset+size)
{
LLMeshRepository::sCacheBytesRead += size;
file.seek(offset);
U8* buffer = new U8[size];
file.read(buffer, size);
//make sure buffer isn't all 0's by checking the first 1KB (reserved block but not written)
bool zero = true;
for (S32 i = 0; i < llmin(size, 1024) && zero; ++i)
{
zero = buffer[i] > 0 ? false : true;
}
if (!zero)
{ //attempt to parse
if (physicsShapeReceived(mesh_id, buffer, size))
{
delete[] buffer;
return true;
}
}
delete[] buffer;
}
if (loadInfoFromVFS(mesh_id, info, boost::bind(&LLMeshRepoThread::physicsShapeReceived, this, _1, _2, _3 )))
return true;
//reading from VFS failed for whatever reason, fetch from sim
AIHTTPHeaders headers("Accept", "application/octet-stream");
std::string http_url = constructUrl(mesh_id);
if (!http_url.empty())
{
ret = LLHTTPClient::getByteRange(http_url, headers, offset, size,
new LLMeshPhysicsShapeResponder(mesh_id, offset, size));
if(ret)
{
LLMeshRepository::sHTTPRequestCount++;
}
{
if (!LLHTTPClient::getByteRange(http_url, headers, info.mOffset, info.mSize,
new LLMeshPhysicsShapeResponder(mesh_id, info.mOffset, info.mSize)))
return false;
LLMeshRepository::sHTTPRequestCount++;
}
}
else
@@ -1004,13 +916,9 @@ bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id)
physicsShapeReceived(mesh_id, NULL, 0);
}
}
else
{
mHeaderMutex->unlock();
}
//early out was not hit, effectively fetched
return ret;
return true;
}
//static
@@ -1086,72 +994,34 @@ bool LLMeshRepoThread::fetchMeshHeader(const LLVolumeParams& mesh_params, U32& c
//return false if failed to get mesh lod.
bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod, U32& count)
{ //protected by mMutex
if (!mHeaderMutex)
{
LLUUID mesh_id = mesh_params.getSculptID();
MeshHeaderInfo info;
if (!getMeshHeaderInfo(mesh_id, header_lod[lod].c_str(), info))
{
return false;
}
mHeaderMutex->lock();
bool retval = true;
LLUUID mesh_id = mesh_params.getSculptID();
U32 header_size = mMeshHeaderSize[mesh_id];
if (header_size > 0)
if (info.mHeaderSize > 0)
{
S32 version = mMeshHeader[mesh_id]["version"].asInteger();
S32 offset = header_size + mMeshHeader[mesh_id][header_lod[lod]]["offset"].asInteger();
S32 size = mMeshHeader[mesh_id][header_lod[lod]]["size"].asInteger();
mHeaderMutex->unlock();
if (version <= MAX_MESH_VERSION && offset >= 0 && size > 0)
if(info.mVersion <= MAX_MESH_VERSION && info.mOffset >= 0 && info.mSize > 0)
{
//check VFS for mesh asset
LLVFile file(gVFS, mesh_id, LLAssetType::AT_MESH);
if (file.getSize() >= offset+size)
{
LLMeshRepository::sCacheBytesRead += size;
file.seek(offset);
U8* buffer = new U8[size];
file.read(buffer, size);
//make sure buffer isn't all 0's by checking the first 1KB (reserved block but not written)
bool zero = true;
for (S32 i = 0; i < llmin(size, 1024) && zero; ++i)
{
zero = buffer[i] > 0 ? false : true;
}
if (!zero)
{ //attempt to parse
if (lodReceived(mesh_params, lod, buffer, size))
{
delete[] buffer;
return true;
}
}
delete[] buffer;
}
if (loadInfoFromVFS(mesh_id, info, boost::bind(&LLMeshRepoThread::lodReceived, this, mesh_params, lod, _2, _3 )))
return true;
//reading from VFS failed for whatever reason, fetch from sim
AIHTTPHeaders headers("Accept", "application/octet-stream");
std::string http_url = constructUrl(mesh_id);
if (!http_url.empty())
{
retval = LLHTTPClient::getByteRange(constructUrl(mesh_id), headers, offset, size,
new LLMeshLODResponder(mesh_params, lod, offset, size));
if (retval)
{
LLMeshRepository::sHTTPRequestCount++;
}
count++;
{
count++;
if (!LLHTTPClient::getByteRange(constructUrl(mesh_id), headers, info.mOffset, info.mSize,
new LLMeshLODResponder(mesh_params, lod, info.mOffset, info.mSize)))
return false;
LLMeshRepository::sHTTPRequestCount++;
}
else
{
@@ -1163,12 +1033,8 @@ bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod,
mUnavailableQ.push(LODRequest(mesh_params, lod));
}
}
else
{
mHeaderMutex->unlock();
}
return retval;
return true;
}
bool LLMeshRepoThread::headerReceived(const LLVolumeParams& mesh_params, U8* data, S32 data_size)
@@ -1236,16 +1102,21 @@ bool LLMeshRepoThread::headerReceived(const LLVolumeParams& mesh_params, U8* dat
bool LLMeshRepoThread::lodReceived(const LLVolumeParams& mesh_params, S32 lod, U8* data, S32 data_size)
{
AIStateMachine::StateTimer timer("lodReceived");
LLPointer<LLVolume> volume = new LLVolume(mesh_params, LLVolumeLODGroup::getVolumeScaleFromDetail(lod));
std::string mesh_string((char*) data, data_size);
std::istringstream stream(mesh_string);
AIStateMachine::StateTimer timer2("unpackVolumeFaces");
if (volume->unpackVolumeFaces(stream, data_size))
{
AIStateMachine::StateTimer timer("getNumFaces");
if (volume->getNumFaces() > 0)
{
AIStateMachine::StateTimer timer("LoadedMesh");
LoadedMesh mesh(volume, mesh_params, lod);
{
AIStateMachine::StateTimer timer("LLMutexLock");
LLMutexLock lock(mMutex);
mLoadedQ.push(mesh);
}
@@ -1900,6 +1771,7 @@ void LLMeshLODResponder::completedRaw(LLChannelDescriptors const& channels,
{
if (is_internal_http_error_that_warrants_a_retry(mStatus) || mStatus == HTTP_SERVICE_UNAVAILABLE)
{ //timeout or service unavailable, try again
AIStateMachine::StateTimer timer("loadMeshLOD");
llwarns << "Timeout or service unavailable, retrying." << llendl;
LLMeshRepository::sHTTPRetryCount++;
gMeshRepo.mThread->loadMeshLOD(mMeshParams, mLOD);
@@ -1918,12 +1790,14 @@ void LLMeshLODResponder::completedRaw(LLChannelDescriptors const& channels,
if (data_size > 0)
{
AIStateMachine::StateTimer timer("readAfter");
data = new U8[data_size];
buffer->readAfter(channels.in(), NULL, data, data_size);
}
if (gMeshRepo.mThread->lodReceived(mMeshParams, mLOD, data, data_size))
{
AIStateMachine::StateTimer timer("FileOpen");
//good fetch from sim, write to VFS for caching
LLVFile file(gVFS, mMeshParams.getSculptID(), LLAssetType::AT_MESH, LLVFile::WRITE);
@@ -1932,6 +1806,7 @@ void LLMeshLODResponder::completedRaw(LLChannelDescriptors const& channels,
if (file.getSize() >= offset+size)
{
AIStateMachine::StateTimer timer("WriteData");
file.seek(offset);
file.write(data, size);
LLMeshRepository::sCacheBytesWritten += size;
@@ -2157,6 +2032,7 @@ void LLMeshHeaderResponder::completedRaw(LLChannelDescriptors const& channels,
if (is_internal_http_error_that_warrants_a_retry(mStatus) || mStatus == HTTP_SERVICE_UNAVAILABLE)
{ //retry
AIStateMachine::StateTimer timer("Retry");
llwarns << "Timeout or service unavailable, retrying." << llendl;
LLMeshRepository::sHTTPRetryCount++;
LLMeshRepoThread::HeaderRequest req(mMeshParams);
@@ -2173,16 +2049,19 @@ void LLMeshHeaderResponder::completedRaw(LLChannelDescriptors const& channels,
S32 data_size = buffer->countAfter(channels.in(), NULL);
U8* data = NULL;
static U8 data[16384];
llassert_always(data_size <= sizeof(data));
memset(data + data_size, 0, sizeof(data)-data_size);
if (data_size > 0)
{
data = new U8[data_size];
AIStateMachine::StateTimer timer("readAfter");
buffer->readAfter(channels.in(), NULL, data, data_size);
}
LLMeshRepository::sBytesReceived += llmin(data_size, 4096);
AIStateMachine::StateTimer timer("headerReceived");
bool success = gMeshRepo.mThread->headerReceived(mMeshParams, data, data_size);
llassert(success);
@@ -2193,7 +2072,7 @@ void LLMeshHeaderResponder::completedRaw(LLChannelDescriptors const& channels,
<< "Unable to parse mesh header: "
<< mStatus << ": " << mReason << llendl;
}
else if (data && data_size > 0)
else if (data_size > 0)
{
//header was successfully retrieved from sim, cache in vfs
LLUUID mesh_id = mMeshParams.getSculptID();
@@ -2225,33 +2104,27 @@ void LLMeshHeaderResponder::completedRaw(LLChannelDescriptors const& channels,
//only allocate as much space in the VFS as is needed for the local cache
data_size = llmin(data_size, bytes);
AIStateMachine::StateTimer timer("FileOpen");
LLVFile file(gVFS, mesh_id, LLAssetType::AT_MESH, LLVFile::WRITE);
if (file.getMaxSize() >= bytes || file.setMaxSize(bytes))
{
LLMeshRepository::sCacheBytesWritten += data_size;
file.write((const U8*) data, data_size);
//zero out the rest of the file
U8 block[4096];
memset(block, 0, 4096);
while (bytes-file.tell() > 4096)
AIStateMachine::StateTimer timer("WriteData");
S32 bytes_remaining = bytes;
while (bytes_remaining > 0)
{
file.write(block, 4096);
}
S32 remaining = bytes-file.tell();
if (remaining > 0)
{
file.write(block, remaining);
const S32 bytes_written = llmin(bytes_remaining, (S32)sizeof(data));
file.write(data, bytes_written);
if (bytes_remaining == bytes && bytes_written < bytes_remaining)
{
memset(data, 0, data_size);
}
bytes_remaining -= llmin(bytes_remaining, bytes_written);
}
}
}
}
delete [] data;
}

View File

@@ -40,6 +40,8 @@
#include "lluploadfloaterobservers.h"
#include "aistatemachinethread.h"
#include <boost/function.hpp>
class LLVOVolume;
class LLMeshResponder;
class LLMutex;
@@ -283,6 +285,16 @@ public:
};
struct MeshHeaderInfo
{
MeshHeaderInfo()
: mHeaderSize(0), mVersion(0), mOffset(-1), mSize(0) {}
U32 mHeaderSize;
U32 mVersion;
S32 mOffset;
S32 mSize;
};
//set of requested skin info
std::set<LLUUID> mSkinRequests;
@@ -332,6 +344,9 @@ public:
bool physicsShapeReceived(const LLUUID& mesh_id, U8* data, S32 data_size);
LLSD& getMeshHeader(const LLUUID& mesh_id);
bool getMeshHeaderInfo(const LLUUID& mesh_id, const char* block_name, MeshHeaderInfo& info);
bool loadInfoFromVFS(const LLUUID& mesh_id, MeshHeaderInfo& info, boost::function<bool(const LLUUID&, U8*, S32)> fn);
void notifyLoadedMeshes();
S32 getActualMeshLOD(const LLVolumeParams& mesh_params, S32 lod);
@@ -450,6 +465,8 @@ public:
void setWholeModelUploadURL(std::string const& whole_model_upload_url) { mWholeModelUploadURL = whole_model_upload_url; }
/*virtual*/ const char* getName() const { return "AIMeshUpload"; }
protected:
// Implement AIStateMachine.
/*virtual*/ const char* state_str_impl(state_type run_state) const;

View File

@@ -2204,8 +2204,17 @@ void reload_objects(LLTextureReloader& texture_list, LLViewerObject::const_child
for (U8 i = 0; i < object->getNumTEs(); i++)
{
texture_list.addTexture(object->getTEImage(i));
const LLTextureEntry* te = object->getTE(i);
if (LLMaterial* mat = te ? te->getMaterialParams().get() : NULL)
{
if (mat->getSpecularID().notNull())
texture_list.addTexture(LLViewerTextureManager::getFetchedTexture(mat->getSpecularID()));
if (mat->getNormalID().notNull())
texture_list.addTexture(LLViewerTextureManager::getFetchedTexture(mat->getNormalID()));
}
}
if(recurse)
{
reload_objects(texture_list,object->getChildren(), true);

View File

@@ -758,7 +758,7 @@ public:
// show an error to the user?
llwarns
<< "Application level error when fetching object "
<< "cost. Message: " << mContent["error"]["message"].asString()
<< "cost. Message: " << mContent["error"]["message"].asString()
<< ", identifier: " << mContent["error"]["identifier"].asString()
<< llendl;
@@ -871,7 +871,7 @@ public:
LLUUID object_id = iter->asUUID();
// Check to see if the request contains data for the object
if ( mContent.has(iter->asString()) )
if (mContent.has(iter->asString()))
{
const LLSD& data = mContent[iter->asString()];
@@ -1459,8 +1459,7 @@ void LLViewerObjectList::removeFromActiveList(LLViewerObject* objectp)
objectp->setListIndex(-1);
std::vector<LLPointer<LLViewerObject> >::iterator it(mActiveObjects.begin() + idx);
std::vector<LLPointer<LLViewerObject> >::iterator iter = vector_replace_with_last(mActiveObjects, it);
std::vector<LLPointer<LLViewerObject> >::iterator iter = vector_replace_with_last(mActiveObjects, mActiveObjects.begin() + idx);
if(iter != mActiveObjects.end())
(*iter)->setListIndex(idx);

View File

@@ -406,8 +406,7 @@ void LLViewerPartGroup::updateParticles(const F32 lastdt)
// Kill dead particles (either flagged dead, or too old)
if ((part->mLastUpdateTime > part->mMaxAge) || (LLViewerPart::LL_PART_DEAD_MASK == part->mFlags))
{
part_list_t::iterator it(mParticles.begin() + i);
vector_replace_with_last(mParticles, it);
vector_replace_with_last(mParticles, mParticles.begin() + i);
delete part ;
}
else
@@ -417,8 +416,7 @@ void LLViewerPartGroup::updateParticles(const F32 lastdt)
{
// Transfer particles between groups
LLViewerPartSim::getInstance()->put(part) ;
part_list_t::iterator it(mParticles.begin() + i);
vector_replace_with_last(mParticles, it);
vector_replace_with_last(mParticles, mParticles.begin() + i);
}
else
{
@@ -723,8 +721,7 @@ void LLViewerPartSim::updateSimulation()
if (mViewerPartSources[i]->isDead())
{
source_list_t::iterator it(mViewerPartSources.begin() + i);
vector_replace_with_last(mViewerPartSources, it);
vector_replace_with_last(mViewerPartSources, mViewerPartSources.begin() + i);
//mViewerPartSources.erase(it);
count--;
}
@@ -761,8 +758,7 @@ void LLViewerPartSim::updateSimulation()
if (!mViewerPartGroups[i]->getCount())
{
delete mViewerPartGroups[i];
group_list_t::iterator it(mViewerPartGroups.begin() + i);
vector_replace_with_last(mViewerPartGroups, it);
vector_replace_with_last(mViewerPartGroups, mViewerPartGroups.begin() + i);
//mViewerPartGroups.erase(it);
i--;
count--;

View File

@@ -63,6 +63,8 @@ public:
bool hasDirname(void) const { return hasFilename(); }
std::string const& getDirname(void) const { return getFilename(); }
/*virtual*/ const char* getName() const { return "AIDirPicker"; }
public:
// Basically all public members of AIStateMachine could made accessible here,
// but I don't think others will ever be needed (not even these, actually).

View File

@@ -188,6 +188,8 @@ public:
std::string getFolder(void) const;
std::vector<std::string> const& getFilenames(void) const { return mFilenames; }
/*virtual*/ const char* getName() const { return "AIFilePicker"; }
// Load the sContextMap from disk.
static bool loadFile(std::string const& filename);
// Save the sContextMap to disk.