HTTP Mesh fetch FTW.. still busted

meow-7.2.2
Dave Parks 2009-12-11 14:47:11 -06:00
parent cd138869d5
commit 695969c770
11 changed files with 93 additions and 286 deletions

View File

@ -62,6 +62,9 @@
//
//----------------------------------------------------------------------------
U32 ll_thread_local sThreadID = 0;
U32 LLThread::sIDIter = 0;
//
// Handed to the APR thread creation function
//
@ -72,6 +75,8 @@ void *APR_THREAD_FUNC LLThread::staticRun(apr_thread_t *apr_threadp, void *datap
// Set thread state to running
threadp->mStatus = RUNNING;
sThreadID = threadp->mID;
// Run the user supplied function
threadp->run();
@ -90,6 +95,8 @@ LLThread::LLThread(const std::string& name, apr_pool_t *poolp) :
mAPRThreadp(NULL),
mStatus(STOPPED)
{
mID = ++sIDIter;
// Thread creation probably CAN be paranoid about APR being initialized, if necessary
if (poolp)
{
@ -273,7 +280,7 @@ void LLThread::wakeLocked()
//============================================================================
LLMutex::LLMutex(apr_pool_t *poolp) :
mAPRMutexp(NULL)
mAPRMutexp(NULL), mCount(0), mLockingThread(NO_THREAD)
{
//if (poolp)
//{
@ -305,7 +312,14 @@ LLMutex::~LLMutex()
void LLMutex::lock()
{
if (mLockingThread == sThreadID)
{ //redundant lock
mCount++;
return;
}
apr_thread_mutex_lock(mAPRMutexp);
#if MUTEX_DEBUG
// Have to have the lock before we can access the debug info
U32 id = LLThread::currentID();
@ -313,10 +327,18 @@ void LLMutex::lock()
llerrs << "Already locked in Thread: " << id << llendl;
mIsLocked[id] = TRUE;
#endif
mLockingThread = sThreadID;
}
void LLMutex::unlock()
{
if (mCount > 0)
{ //not the root unlock
mCount--;
return;
}
#if MUTEX_DEBUG
// Access the debug info while we have the lock
U32 id = LLThread::currentID();
@ -324,6 +346,8 @@ void LLMutex::unlock()
llerrs << "Not locked in Thread: " << id << llendl;
mIsLocked[id] = FALSE;
#endif
mLockingThread = NO_THREAD;
apr_thread_mutex_unlock(mAPRMutexp);
}
@ -341,6 +365,11 @@ bool LLMutex::isLocked()
}
}
U32 LLMutex::lockingThread() const
{
return mLockingThread;
}
//============================================================================
LLCondition::LLCondition(apr_pool_t *poolp) :

View File

@ -40,8 +40,17 @@ class LLThread;
class LLMutex;
class LLCondition;
#if LL_WINDOWS
#define ll_thread_local __declspec(thread)
#else
#define ll_thread_local __thread
#endif
class LL_COMMON_API LLThread
{
private:
static U32 sIDIter;
public:
typedef enum e_thread_status
{
@ -82,6 +91,8 @@ public:
apr_pool_t *getAPRPool() { return mAPRPoolp; }
LLVolatileAPRPool* getLocalAPRFilePool() { return mLocalAPRFilePoolp ; }
U32 getID() const { return mID; }
private:
BOOL mPaused;
@ -96,6 +107,7 @@ protected:
apr_pool_t *mAPRPoolp;
BOOL mIsLocalPool;
EThreadStatus mStatus;
U32 mID;
//a local apr_pool for APRFile operations in this thread. If it exists, LLAPRFile::sAPRFilePoolp should not be used.
//Note: this pool is used by APRFile ONLY, do NOT use it for any other purposes.
@ -133,17 +145,27 @@ protected:
class LL_COMMON_API LLMutex
{
public:
typedef enum
{
NO_THREAD = 0xFFFFFFFF
} e_locking_thread;
LLMutex(apr_pool_t *apr_poolp); // NULL pool constructs a new pool for the mutex
~LLMutex();
void lock(); // blocks
void unlock();
bool isLocked(); // non-blocking, but does do a lock/unlock so not free
U32 lockingThread() const; //get ID of locking thread
protected:
apr_thread_mutex_t *mAPRMutexp;
mutable U32 mCount;
mutable U32 mLockingThread;
apr_pool_t *mAPRPoolp;
BOOL mIsLocalPool;
S32 mLockCount;
#if MUTEX_DEBUG
std::map<U32, BOOL> mIsLocked;
#endif

View File

@ -1952,8 +1952,12 @@ BOOL LLVolume::createVolumeFacesFromStream(std::istream& is)
}
is.seekg(header[nm[lod]]["offset"].asInteger(), std::ios_base::cur);
return unpackVolumeFaces(is, header[nm[lod]]["size"].asInteger());
}
BOOL LLVolume::unpackVolumeFaces(std::istream& is, S32 size)
{
U8* result = NULL;
U32 cur_size = 0;
@ -1964,7 +1968,6 @@ BOOL LLVolume::createVolumeFacesFromStream(std::istream& is)
const U32 CHUNK = 65536;
S32 size = header[nm[lod]]["size"].asInteger();
U8 *in = new U8[size];
is.read((char*) in, size);

View File

@ -971,6 +971,8 @@ protected:
public:
virtual BOOL createVolumeFacesFromFile(const std::string& file_name);
virtual BOOL createVolumeFacesFromStream(std::istream& is);
virtual BOOL unpackVolumeFaces(std::istream& is, S32 size);
virtual void makeTetrahedron();
virtual BOOL isTetrahedron();

View File

@ -284,6 +284,7 @@ set(viewer_SOURCE_FILES
llmediaremotectrl.cpp
llmemoryview.cpp
llmenucommands.cpp
llmeshrepository.cpp
llmetricperformancetester.cpp
llmimetypes.cpp
llmorphview.cpp
@ -789,6 +790,7 @@ set(viewer_HEADER_FILES
llmediaremotectrl.h
llmemoryview.h
llmenucommands.h
llmeshrepository.h
llmetricperformancetester.h
llmimetypes.h
llmorphview.h

View File

@ -9998,7 +9998,7 @@
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>1</integer>
<integer>0</integer>
</map>
<key>UseStartScreen</key>
<map>

View File

@ -48,6 +48,7 @@
#include "llwindow.h"
#include "llviewerstats.h"
#include "llmd5.h"
#include "llmeshrepository.h"
#include "llpumpio.h"
#include "llmimetypes.h"
#include "llslurl.h"
@ -1266,6 +1267,9 @@ bool LLAppViewer::cleanup()
llinfos << "Cleaning Up" << llendflush;
// shut down mesh streamer
gMeshRepo.shutdown();
// Must clean up texture references before viewer window is destroyed.
LLHUDManager::getInstance()->updateEffects();
LLHUDObject::updateAll();
@ -1678,6 +1682,9 @@ bool LLAppViewer::initThreads()
mFastTimerLogThread->start();
}
// Mesh streaming and caching
gMeshRepo.init();
// *FIX: no error handling here!
return true;
}
@ -2394,6 +2401,7 @@ bool LLAppViewer::initWindow()
gSavedSettings.saveToFile( gSavedSettings.getString("ClientSettingsFile"), TRUE );
gPipeline.init();
stop_glerror();
gViewerWindow->initGLDefaults();

View File

@ -1432,6 +1432,7 @@ void LLViewerRegion::setSeedCapability(const std::string& url)
capabilityNames.append("FetchLib");
capabilityNames.append("FetchLibDescendents");
capabilityNames.append("GetTexture");
capabilityNames.append("GetMesh");
capabilityNames.append("GroupProposalBallot");
capabilityNames.append("HomeLocation");
capabilityNames.append("MapLayer");

View File

@ -70,6 +70,7 @@
#include "llsdutil.h"
#include "llmediaentry.h"
#include "llmediadataclient.h"
#include "llmeshrepository.h"
#include "llagent.h"
const S32 MIN_QUIET_FRAMES_COALESCE = 30;
@ -861,6 +862,16 @@ BOOL LLVOVolume::setVolume(const LLVolumeParams &params, const S32 detail, bool
{
LLVolumeParams volume_params = params;
if (isSculpted())
{
// if it's a mesh
if ((volume_params.getSculptType() & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH)
{ //meshes might not have all LODs, get the force detail to best existing LOD
LLUUID mesh_id = params.getSculptID();
mLOD = gMeshRepo.getActualMeshLOD(mesh_id, mLOD);
}
}
// Check if we need to change implementations
bool is_flexible = (volume_params.getPathParams().getCurveType() == LL_PCODE_PATH_FLEXIBLE);
if (is_flexible)
@ -888,6 +899,8 @@ BOOL LLVOVolume::setVolume(const LLVolumeParams &params, const S32 detail, bool
}
}
if ((LLPrimitive::setVolume(volume_params, mLOD, (mVolumeImpl && mVolumeImpl->isVolumeUnique()))) || mSculptChanged)
{
mFaceMappingChanged = TRUE;
@ -906,7 +919,7 @@ BOOL LLVOVolume::setVolume(const LLVolumeParams &params, const S32 detail, bool
{
//load request not yet issued, request pipeline load this mesh
LLUUID asset_id = volume_params.getSculptID();
gPipeline.loadMesh(this, asset_id, LLVolumeLODGroup::getVolumeDetailFromScale(getVolume()->getDetail()));
gMeshRepo.loadMesh(this, asset_id, LLVolumeLODGroup::getVolumeDetailFromScale(getVolume()->getDetail()));
}
}
else // otherwise is sculptie

View File

@ -70,6 +70,7 @@
#include "llgldbg.h"
#include "llhudmanager.h"
#include "lllightconstants.h"
#include "llmeshrepository.h"
#include "llresmgr.h"
#include "llselectmgr.h"
#include "llsky.h"
@ -103,6 +104,7 @@
#include "llspatialpartition.h"
#include "llmutelist.h"
#include "lltoolpie.h"
#include "llcurl.h"
#ifdef _DEBUG
@ -342,8 +344,6 @@ LLPipeline::LLPipeline() :
mGlowPool(NULL),
mBumpPool(NULL),
mWLSkyPool(NULL),
mMeshMutex(NULL),
mMeshThreadCount(0),
mLightMask(0),
mLightMovingMask(0),
mLightingDetail(0),
@ -403,7 +403,6 @@ void LLPipeline::init()
stop_glerror();
mMeshMutex = new LLMutex(NULL);
for (U32 i = 0; i < 2; ++i)
{
mSpotLightFade[i] = 1.f;
@ -478,9 +477,6 @@ void LLPipeline::cleanup()
//delete mWLSkyPool;
mWLSkyPool = NULL;
delete mMeshMutex;
mMeshMutex = NULL;
releaseGLBuffers();
mBloomImagep = NULL;
@ -1802,6 +1798,8 @@ void LLPipeline::rebuildPriorityGroups()
assertInitialized();
gMeshRepo.notifyLoadedMeshes();
// Iterate through all drawables on the priority build queue,
for (LLSpatialGroup::sg_list_t::iterator iter = mGroupQ1.begin();
iter != mGroupQ1.end(); ++iter)
@ -1881,8 +1879,6 @@ void LLPipeline::updateGeom(F32 max_dtime)
// for now, only LLVOVolume does this to throttle LOD changes
LLVOVolume::preUpdateGeom();
notifyLoadedMeshes();
// Iterate through all drawables on the priority build queue,
for (LLDrawable::drawable_list_t::iterator iter = mBuildQ1.begin();
iter != mBuildQ1.end();)
@ -8912,246 +8908,3 @@ LLCullResult::sg_list_t::iterator LLPipeline::endAlphaGroups()
}
void LLPipeline::loadMesh(LLVOVolume* vobj, LLUUID mesh_id, S32 detail)
{
if (detail < 0 || detail > 4)
{
return;
}
{
LLMutexLock lock(mMeshMutex);
//add volume to list of loading meshes
mesh_load_map::iterator iter = mLoadingMeshes[detail].find(mesh_id);
if (iter != mLoadingMeshes[detail].end())
{ //request pending for this mesh, append volume id to list
iter->second.insert(vobj->getID());
return;
}
//first request for this mesh
mLoadingMeshes[detail][mesh_id].insert(vobj->getID());
}
if (gAssetStorage->hasLocalAsset(mesh_id, LLAssetType::AT_MESH))
{ //already have asset, load desired LOD in background
mPendingMeshes.push_back(new LLMeshThread(mesh_id, vobj->getVolume(), detail));
}
else
{ //fetch asset and load when done
gAssetStorage->getAssetData(mesh_id, LLAssetType::AT_MESH,
getMeshAssetCallback, vobj->getVolume(), TRUE);
}
//do a quick search to see if we can't display something while we wait for this mesh to load
LLVolume* volume = vobj->getVolume();
if (volume)
{
LLVolumeParams params = volume->getParams();
LLVolumeLODGroup* group = LLPrimitive::getVolumeManager()->getGroup(params);
if (group)
{
//first see what the next lowest LOD available might be
for (S32 i = detail-1; i >= 0; --i)
{
LLVolume* lod = group->refLOD(i);
if (lod && !lod->isTetrahedron() && lod->getNumVolumeFaces() > 0)
{
volume->copyVolumeFaces(lod);
group->derefLOD(lod);
return;
}
group->derefLOD(lod);
}
//no lower LOD is a available, is a higher lod available?
for (S32 i = detail+1; i < 4; ++i)
{
LLVolume* lod = group->refLOD(i);
if (lod && !lod->isTetrahedron() && lod->getNumVolumeFaces() > 0)
{
volume->copyVolumeFaces(lod);
group->derefLOD(lod);
return;
}
group->derefLOD(lod);
}
}
else
{
llerrs << "WTF?" << llendl;
}
//nothing found, so make a tetrahedron
volume->makeTetrahedron();
}
}
//static
void LLPipeline::getMeshAssetCallback(LLVFS *vfs,
const LLUUID& asset_uuid,
LLAssetType::EType type,
void* user_data, S32 status, LLExtStat ext_status)
{
gPipeline.mPendingMeshes.push_back(new LLMeshThread(asset_uuid, (LLVolume*) user_data));
}
LLPipeline::LLMeshThread::LLMeshThread(LLUUID mesh_id, LLVolume* target, S32 detail)
: LLThread("mesh_loading_thread")
{
mMeshID = mesh_id;
mVolume = NULL;
mDetail = target->getDetail();
if (detail == -1)
{
mDetailIndex = LLVolumeLODGroup::getVolumeDetailFromScale(target->getDetail());
}
else
{
mDetailIndex = detail;
}
mTargetVolume = target;
}
LLPipeline::LLMeshThread::~LLMeshThread()
{
}
void LLPipeline::LLMeshThread::run()
{
if (!gAssetStorage || LLApp::instance()->isQuitting())
{
return;
}
char* buffer = NULL;
S32 size = 0;
LLVFS* vfs = gAssetStorage->mVFS;
{
LLVFile file(vfs, mMeshID, LLAssetType::AT_MESH, LLVFile::READ);
file.waitForLock(VFSLOCK_READ);
size = file.getSize();
if (size == 0)
{
gPipeline.meshLoaded(this);
return;
}
buffer = new char[size];
file.read((U8*)&buffer[0], size);
}
{
std::string buffer_string(buffer, size);
std::istringstream buffer_stream(buffer_string);
{
LLVolumeParams volume_params;
volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE);
volume_params.setSculptID(mMeshID, LL_SCULPT_TYPE_MESH);
mVolume = new LLVolume(volume_params, mDetail);
mVolume->createVolumeFacesFromStream(buffer_stream);
}
}
delete[] buffer;
gPipeline.meshLoaded(this);
}
void LLPipeline::meshLoaded(LLPipeline::LLMeshThread* mesh_thread)
{
LLMutexLock lock(mMeshMutex);
mLoadedMeshes.push_back(mesh_thread);
}
void LLPipeline::notifyLoadedMeshes()
{ //called from main thread
U32 max_thread_count = llmax(gSavedSettings.getU32("MeshThreadCount"), (U32) 1);
while (mMeshThreadCount < max_thread_count && !mPendingMeshes.empty())
{
LLMeshThread* mesh_thread = mPendingMeshes.front();
mesh_thread->start();
++mMeshThreadCount;
mPendingMeshes.pop_front();
}
LLMutexLock lock(mMeshMutex);
std::list<LLMeshThread*> stopping_threads;
for (std::list<LLMeshThread*>::iterator iter = mLoadedMeshes.begin(); iter != mLoadedMeshes.end(); ++iter)
{ //for each mesh done loading
LLMeshThread* mesh = *iter;
if (!mesh->isStopped())
{ //don't process a LLMeshThread until it's stopped
stopping_threads.push_back(mesh);
continue;
}
S32 detail = mesh->mDetailIndex;
//get list of objects waiting to be notified this mesh is loaded
mesh_load_map::iterator obj_iter = mLoadingMeshes[detail].find(mesh->mMeshID);
if (mesh->mVolume && obj_iter != mLoadingMeshes[detail].end())
{
//make sure target volume is still valid
BOOL valid = FALSE;
for (std::set<LLUUID>::iterator vobj_iter = obj_iter->second.begin(); vobj_iter != obj_iter->second.end(); ++vobj_iter)
{
LLVOVolume* vobj = (LLVOVolume*) gObjectList.findObject(*vobj_iter);
if (vobj)
{
if (vobj->getVolume() == mesh->mTargetVolume)
{
valid = TRUE;
}
}
}
if (valid)
{
if (mesh->mVolume->getNumVolumeFaces() <= 0)
{
llwarns << "Mesh loading returned empty volume." << llendl;
mesh->mVolume->makeTetrahedron();
}
mesh->mTargetVolume->copyVolumeFaces(mesh->mVolume);
for (std::set<LLUUID>::iterator vobj_iter = obj_iter->second.begin(); vobj_iter != obj_iter->second.end(); ++vobj_iter)
{
LLVOVolume* vobj = (LLVOVolume*) gObjectList.findObject(*vobj_iter);
if (vobj)
{
vobj->notifyMeshLoaded();
}
}
}
mLoadingMeshes[detail].erase(mesh->mMeshID);
}
delete mesh;
--mMeshThreadCount;
}
mLoadedMeshes = stopping_threads;
}

View File

@ -58,6 +58,8 @@ class LLCubeMap;
class LLCullResult;
class LLVOAvatar;
class LLGLSLShader;
class LLCurlRequest;
class LLMeshResponder;
typedef enum e_avatar_skinning_method
{
@ -278,10 +280,6 @@ public:
LLCullResult::sg_list_t::iterator beginAlphaGroups();
LLCullResult::sg_list_t::iterator endAlphaGroups();
//mesh management functions
void loadMesh(LLVOVolume* volume, LLUUID mesh_id, S32 detail = 0);
void addTrianglesDrawn(S32 count);
BOOL hasRenderType(const U32 type) const { return (type && (mRenderTypeMask & (1<<type))) ? TRUE : FALSE; }
BOOL hasRenderDebugFeatureMask(const U32 mask) const { return (mRenderDebugFeatureMask & mask) ? TRUE : FALSE; }
@ -683,32 +681,8 @@ protected:
typedef std::map<LLUUID, std::set<LLUUID> > mesh_load_map;
mesh_load_map mLoadingMeshes[4];
LLMutex* mMeshMutex;
class LLMeshThread : public LLThread
{
public:
LLPointer<LLVolume> mVolume;
LLVolume* mTargetVolume;
LLUUID mMeshID;
F32 mDetail;
S32 mDetailIndex;
LLMeshThread(LLUUID mesh_id, LLVolume* target, S32 detail = -1);
~LLMeshThread();
void run();
};
static void getMeshAssetCallback(LLVFS *vfs,
const LLUUID& asset_uuid,
LLAssetType::EType type,
void* user_data, S32 status, LLExtStat ext_status);
std::list<LLMeshThread*> mLoadedMeshes;
std::list<LLMeshThread*> mPendingMeshes;
U32 mMeshThreadCount;
void meshLoaded(LLMeshThread* mesh_thread);
void notifyLoadedMeshes();
typedef std::list<LLMeshResponder*> mesh_response_list;
mesh_response_list mMeshResponseList;
LLPointer<LLViewerFetchedTexture> mFaceSelectImagep;
LLPointer<LLViewerTexture> mBloomImagep;