Files
SingularityViewer/indra/newview/llmeshrepository.h
Aleric Inglewood 8d028e6948 Fix for AIStateMachineThread (LLThreadSafeRefCount: deleting non-zero reference)
This fixes
https://code.google.com/p/singularity-viewer/issues/detail?id=736

The problem was that we need to keep the 'user' derived THREAD_IMPL
alive in the thread, and therefore used an LLPointer<THREAD_IMPL>
(as base class of AIStateMachineThread<THREAD_IMPL>), and therefore
THREAD_IMPL, derived from AIThreadImpl had to be derived from
LLThreadSafeRefCount. However, AIStateMachineThread<THREAD_IMPL> also
needed to be a statemachine of itself and is derived from
AIStateMachineThreadBase derived from AIStateMachine which is ALSO
derived from LLThreadSafeRefCount - that in this case wasn't really
needed. An attempt to deactive it by calling ref() from the constructor
of AIStateMachineThreadBase failed on the fact that LLThreadSafeRefCount
insists that its ref count mRef is exactly zero when it is being
deleted.

The chosen solution is to remove the ref count from AIThreadImpl and use
the LLThreadSafeRefCount base class of AIStateMachineThreadBase. The
result is that not only THREAD_IMPL, but also the state machine object
is kept alive, but that doesn't seem like a problem.

Thus, instead of passing a AIThreadImpl* to
AIStateMachineThreadBase::Thread, we now pass a
AIStateMachineThreadBase* to it to keep the whole of the
AIStateMachineThread<THREAD_IMPL> object alive, which has a THREAD_IMPL
as member now. This member then can be accessed through a virtual
function impl(). Another result of this change is that the 'user' (the
class derived from AIThreadImpl, THREAD_IMPL) now has to deal with the
LLPointer, and use LLPointer<AIStateMachineThread<THREAD_IMPL> >
instead of just AIStateMachineThread<THREAD_IMPL> and also allocate
this object himself. The access from there then changes into a -> to
access the state machine (as opposed to a .) and ->thread_impl() to
access the THREAD_IMPL object (as opposed to a ->).
2013-04-20 04:54:25 +02:00

572 lines
15 KiB
C++

/**
* @file llmeshrepository.h
* @brief Client-side repository of mesh assets.
*
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#ifndef LL_MESH_REPOSITORY_H
#define LL_MESH_REPOSITORY_H
#include "llassettype.h"
#include "llmodel.h"
#include "lluuid.h"
#include "llviewertexture.h"
#include "llvolume.h"
#define LLCONVEXDECOMPINTER_STATIC 1
#include "LLConvexDecomposition.h"
#include "lluploadfloaterobservers.h"
#include "aistatemachinethread.h"
class LLVOVolume;
class LLMeshResponder;
class LLMutex;
class LLCondition;
class LLVFS;
class LLMeshRepository;
class AIMeshUpload;
class LLMeshUploadData
{
public:
LLPointer<LLModel> mBaseModel;
LLPointer<LLModel> mModel[5];
LLUUID mUUID;
U32 mRetries;
std::string mRSVP;
std::string mAssetData;
LLSD mPostData;
LLMeshUploadData()
{
mRetries = 0;
}
};
class LLTextureUploadData
{
public:
LLViewerFetchedTexture* mTexture;
LLUUID mUUID;
std::string mRSVP;
std::string mLabel;
U32 mRetries;
std::string mAssetData;
LLSD mPostData;
LLTextureUploadData()
{
mRetries = 0;
}
LLTextureUploadData(LLViewerFetchedTexture* texture, std::string& label)
: mTexture(texture), mLabel(label)
{
mRetries = 0;
}
};
class LLImportMaterial
{
public:
LLPointer<LLViewerFetchedTexture> mDiffuseMap;
std::string mDiffuseMapFilename;
std::string mDiffuseMapLabel;
std::string mBinding;
LLColor4 mDiffuseColor;
bool mFullbright;
bool operator<(const LLImportMaterial &params) const;
LLImportMaterial()
: mFullbright(false)
{
mDiffuseColor.set(1, 1, 1, 1);
}
LLImportMaterial(LLSD& data);
LLSD asLLSD();
};
class LLModelInstance
{
public:
LLPointer<LLModel> mModel;
LLPointer<LLModel> mLOD[5];
std::string mLabel;
LLUUID mMeshID;
S32 mLocalMeshID;
LLMatrix4 mTransform;
std::map<std::string, LLImportMaterial> mMaterial;
LLModelInstance(LLModel* model, const std::string& label, LLMatrix4& transform, std::map<std::string, LLImportMaterial>& materials)
: mModel(model), mLabel(label), mTransform(transform), mMaterial(materials)
{
mLocalMeshID = -1;
}
LLModelInstance(LLSD& data);
LLSD asLLSD();
};
class LLPhysicsDecomp : public LLThread
{
public:
typedef std::map<std::string, LLSD> decomp_params;
class Request : public LLRefCount
{
public:
//input params
S32* mDecompID;
std::string mStage;
std::vector<LLVector3> mPositions;
std::vector<U16> mIndices;
decomp_params mParams;
//output state
std::string mStatusMessage;
std::vector<LLModel::PhysicsMesh> mHullMesh;
LLModel::convex_hull_decomposition mHull;
//status message callback, called from decomposition thread
virtual S32 statusCallback(const char* status, S32 p1, S32 p2) = 0;
//completed callback, called from the main thread
virtual void completed() = 0;
virtual void setStatusMessage(const std::string& msg);
bool isValid() const {return mPositions.size() > 2 && mIndices.size() > 2 ;}
protected:
//internal use
LLVector3 mBBox[2] ;
F32 mTriangleAreaThreshold ;
void assignData(LLModel* mdl) ;
void updateTriangleAreaThreshold() ;
bool isValidTriangle(U16 idx1, U16 idx2, U16 idx3) ;
};
LLCondition* mSignal;
LLMutex* mMutex;
bool mInited;
bool mQuitting;
bool mDone;
LLPhysicsDecomp();
~LLPhysicsDecomp();
void shutdown();
void submitRequest(Request* request);
static S32 llcdCallback(const char*, S32, S32);
void cancel();
void setMeshData(LLCDMeshData& mesh, bool vertex_based);
void doDecomposition();
void doDecompositionSingleHull();
virtual void run();
void completeCurrent();
void notifyCompleted();
std::map<std::string, S32> mStageID;
typedef std::queue<LLPointer<Request> > request_queue;
request_queue mRequestQ;
LLPointer<Request> mCurRequest;
std::queue<LLPointer<Request> > mCompletedQ;
};
class LLMeshRepoThread : public LLThread
{
public:
static S32 sActiveHeaderRequests;
static S32 sActiveLODRequests;
static U32 sMaxConcurrentRequests;
LLMutex* mMutex;
LLMutex* mHeaderMutex;
LLCondition* mSignal;
//map of known mesh headers
typedef std::map<LLUUID, LLSD> mesh_header_map;
mesh_header_map mMeshHeader;
std::map<LLUUID, U32> mMeshHeaderSize;
class HeaderRequest
{
public:
const LLVolumeParams mMeshParams;
HeaderRequest(const LLVolumeParams& mesh_params)
: mMeshParams(mesh_params)
{
}
bool operator<(const HeaderRequest& rhs) const
{
return mMeshParams < rhs.mMeshParams;
}
};
class LODRequest
{
public:
LLVolumeParams mMeshParams;
S32 mLOD;
F32 mScore;
LODRequest(const LLVolumeParams& mesh_params, S32 lod)
: mMeshParams(mesh_params), mLOD(lod), mScore(0.f)
{
}
};
struct CompareScoreGreater
{
bool operator()(const LODRequest& lhs, const LODRequest& rhs)
{
return lhs.mScore > rhs.mScore; // greatest = first
}
};
class LoadedMesh
{
public:
LLPointer<LLVolume> mVolume;
LLVolumeParams mMeshParams;
S32 mLOD;
LoadedMesh(LLVolume* volume, const LLVolumeParams& mesh_params, S32 lod)
: mVolume(volume), mMeshParams(mesh_params), mLOD(lod)
{
}
};
//set of requested skin info
std::set<LLUUID> mSkinRequests;
//queue of completed skin info requests
std::queue<LLMeshSkinInfo> mSkinInfoQ;
//set of requested decompositions
std::set<LLUUID> mDecompositionRequests;
//set of requested physics shapes
std::set<LLUUID> mPhysicsShapeRequests;
//queue of completed Decomposition info requests
std::queue<LLModel::Decomposition*> mDecompositionQ;
//queue of requested headers
std::queue<HeaderRequest> mHeaderReqQ;
//queue of requested LODs
std::queue<LODRequest> mLODReqQ;
//queue of unavailable LODs (either asset doesn't exist or asset doesn't have desired LOD)
std::queue<LODRequest> mUnavailableQ;
//queue of successfully loaded meshes
std::queue<LoadedMesh> mLoadedQ;
//map of pending header requests and currently desired LODs
typedef std::map<LLVolumeParams, std::vector<S32> > pending_lod_map;
pending_lod_map mPendingLOD;
static std::string constructUrl(LLUUID mesh_id);
LLMeshRepoThread();
~LLMeshRepoThread();
virtual void run();
void loadMeshLOD(const LLVolumeParams& mesh_params, S32 lod);
bool fetchMeshHeader(const LLVolumeParams& mesh_params, U32& count);
void fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod, U32& count);
bool headerReceived(const LLVolumeParams& mesh_params, U8* data, S32 data_size);
bool lodReceived(const LLVolumeParams& mesh_params, S32 lod, U8* data, S32 data_size);
bool skinInfoReceived(const LLUUID& mesh_id, U8* data, S32 data_size);
bool decompositionReceived(const LLUUID& mesh_id, U8* data, S32 data_size);
bool physicsShapeReceived(const LLUUID& mesh_id, U8* data, S32 data_size);
LLSD& getMeshHeader(const LLUUID& mesh_id);
void notifyLoadedMeshes();
S32 getActualMeshLOD(const LLVolumeParams& mesh_params, S32 lod);
void loadMeshSkinInfo(const LLUUID& mesh_id);
void loadMeshDecomposition(const LLUUID& mesh_id);
void loadMeshPhysicsShape(const LLUUID& mesh_id);
//send request for skin info, returns true if header info exists
// (should hold onto mesh_id and try again later if header info does not exist)
bool fetchMeshSkinInfo(const LLUUID& mesh_id);
//send request for decomposition, returns true if header info exists
// (should hold onto mesh_id and try again later if header info does not exist)
bool fetchMeshDecomposition(const LLUUID& mesh_id);
//send request for PhysicsShape, returns true if header info exists
// (should hold onto mesh_id and try again later if header info does not exist)
bool fetchMeshPhysicsShape(const LLUUID& mesh_id);
};
class LLMeshUploadThread : public AIThreadImpl
{
private:
S32 mMeshUploadTimeOut ; //maximum time in seconds to execute an uploading request.
public:
class DecompRequest : public LLPhysicsDecomp::Request
{
public:
LLPointer<LLModel> mModel;
LLPointer<LLModel> mBaseModel;
LLMeshUploadThread* mThread;
DecompRequest(LLModel* mdl, LLModel* base_model, LLMeshUploadThread* thread);
S32 statusCallback(const char* status, S32 p1, S32 p2) { return 1; }
void completed();
};
LLPointer<DecompRequest> mFinalDecomp;
bool mPhysicsComplete;
LLSD mModelData;
LLSD mBody;
typedef std::map<LLPointer<LLModel>, std::vector<LLVector3> > hull_map;
hull_map mHullMap;
typedef std::vector<LLModelInstance> instance_list;
instance_list mInstanceList;
typedef std::map<LLPointer<LLModel>, instance_list> instance_map;
instance_map mInstance;
LLVector3 mOrigin;
bool mUploadTextures;
bool mUploadSkin;
bool mUploadJoints;
LLHost mHost;
std::string mWholeModelFeeCapability;
#ifdef LL_DEBUG
LLMeshUploadThread(void) : AIThreadImpl("mesh upload") { }
#endif
void init(instance_list& data, LLVector3& scale, bool upload_textures, bool upload_skin, bool upload_joints, bool do_upload,
LLHandle<LLWholeModelFeeObserver> const& fee_observer, LLHandle<LLWholeModelUploadObserver> const& upload_observer);
void postRequest(std::string& url, AIMeshUpload* state_machine);
/*virtual*/ bool run();
void preStart();
void generateHulls();
void wholeModelToLLSD(LLSD& dest, bool include_textures);
void decomposeMeshMatrix(LLMatrix4& transformation,
LLVector3& result_pos,
LLQuaternion& result_rot,
LLVector3& result_scale);
void setFeeObserverHandle(LLHandle<LLWholeModelFeeObserver> observer_handle) { mFeeObserverHandle = observer_handle; }
void setUploadObserverHandle(LLHandle<LLWholeModelUploadObserver> observer_handle) { mUploadObserverHandle = observer_handle; }
private:
LLHandle<LLWholeModelFeeObserver> mFeeObserverHandle;
LLHandle<LLWholeModelUploadObserver> mUploadObserverHandle;
bool mDoUpload; // if FALSE only model data will be requested, otherwise the model will be uploaded
};
enum AIMeshUpload_state_type {
AIMeshUpload_start = AIStateMachine::max_state,
AIMeshUpload_threadFinished,
AIMeshUpload_responderFinished
};
class AIMeshUpload : public AIStateMachine
{
private:
LLPointer<AIStateMachineThread<LLMeshUploadThread> > mMeshUpload;
std::string mWholeModelUploadURL;
public:
AIMeshUpload(LLMeshUploadThread::instance_list& data, LLVector3& scale,
bool upload_textures, bool upload_skin, bool upload_joints, std::string const& upload_url, bool do_upload,
LLHandle<LLWholeModelFeeObserver> const& fee_observer, LLHandle<LLWholeModelUploadObserver> const& upload_observer);
void setWholeModelUploadURL(std::string const& whole_model_upload_url) { mWholeModelUploadURL = whole_model_upload_url; }
protected:
// Implement AIStateMachine.
/*virtual*/ const char* state_str_impl(state_type run_state) const;
/*virtual*/ void initialize_impl();
/*virtual*/ void multiplex_impl(state_type run_state);
};
class LLMeshRepository
{
public:
//metrics
static U32 sBytesReceived;
static U32 sHTTPRequestCount;
static U32 sHTTPRetryCount;
static U32 sLODPending;
static U32 sLODProcessing;
static U32 sCacheBytesRead;
static U32 sCacheBytesWritten;
static U32 sPeakKbps;
static F32 getStreamingCost(LLSD& header, F32 radius, S32* bytes = NULL, S32* visible_bytes = NULL, S32 detail = -1, F32 *unscaled_value = NULL);
LLMeshRepository();
void init();
void shutdown();
//mesh management functions
S32 loadMesh(LLVOVolume* volume, const LLVolumeParams& mesh_params, S32 detail = 0, S32 last_lod = -1);
void notifyLoadedMeshes();
void notifyMeshLoaded(const LLVolumeParams& mesh_params, LLVolume* volume);
void notifyMeshUnavailable(const LLVolumeParams& mesh_params, S32 lod);
void notifySkinInfoReceived(LLMeshSkinInfo& info);
void notifyDecompositionReceived(LLModel::Decomposition* info);
S32 getActualMeshLOD(const LLVolumeParams& mesh_params, S32 lod);
static S32 getActualMeshLOD(LLSD& header, S32 lod);
const LLMeshSkinInfo* getSkinInfo(const LLUUID& mesh_id, const LLVOVolume* requesting_obj);
LLModel::Decomposition* getDecomposition(const LLUUID& mesh_id);
void fetchPhysicsShape(const LLUUID& mesh_id);
bool hasPhysicsShape(const LLUUID& mesh_id);
void buildHull(const LLVolumeParams& params, S32 detail);
void buildPhysicsMesh(LLModel::Decomposition& decomp);
bool meshUploadEnabled();
bool meshRezEnabled();
LLSD& getMeshHeader(const LLUUID& mesh_id);
void uploadModel(std::vector<LLModelInstance>& data, LLVector3& scale, bool upload_textures,
bool upload_skin, bool upload_joints, std::string upload_url, bool do_upload = true,
LLHandle<LLWholeModelFeeObserver> fee_observer= (LLHandle<LLWholeModelFeeObserver>()),
LLHandle<LLWholeModelUploadObserver> upload_observer = (LLHandle<LLWholeModelUploadObserver>()));
S32 getMeshSize(const LLUUID& mesh_id, S32 lod);
typedef std::map<LLVolumeParams, std::set<LLUUID> > mesh_load_map;
mesh_load_map mLoadingMeshes[4];
typedef std::map<LLUUID, LLMeshSkinInfo> skin_map;
skin_map mSkinMap;
typedef std::map<LLUUID, LLModel::Decomposition*> decomposition_map;
decomposition_map mDecompositionMap;
LLMutex* mMeshMutex;
std::vector<LLMeshRepoThread::LODRequest> mPendingRequests;
//list of mesh ids awaiting skin info
typedef std::map<LLUUID, std::set<LLUUID> > skin_load_map;
skin_load_map mLoadingSkins;
//list of mesh ids that need to send skin info fetch requests
std::queue<LLUUID> mPendingSkinRequests;
//list of mesh ids awaiting decompositions
std::set<LLUUID> mLoadingDecompositions;
//list of mesh ids that need to send decomposition fetch requests
std::queue<LLUUID> mPendingDecompositionRequests;
//list of mesh ids awaiting physics shapes
std::set<LLUUID> mLoadingPhysicsShapes;
//list of mesh ids that need to send physics shape fetch requests
std::queue<LLUUID> mPendingPhysicsShapeRequests;
U32 mMeshThreadCount;
void cacheOutgoingMesh(LLMeshUploadData& data, LLSD& header);
LLMeshRepoThread* mThread;
LLPhysicsDecomp* mDecompThread;
class inventory_data
{
public:
LLSD mPostData;
LLSD mResponse;
inventory_data(const LLSD& data, const LLSD& content)
: mPostData(data), mResponse(content)
{
}
};
std::queue<inventory_data> mInventoryQ;
std::queue<LLSD> mUploadErrorQ;
void uploadError(LLSD& args);
void updateInventory(inventory_data data);
std::string mGetMeshCapability;
};
extern LLMeshRepository gMeshRepo;
#endif