summaryrefslogtreecommitdiff
path: root/indra/newview/llmeshrepository.h
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview/llmeshrepository.h')
-rw-r--r--indra/newview/llmeshrepository.h287
1 files changed, 237 insertions, 50 deletions
diff --git a/indra/newview/llmeshrepository.h b/indra/newview/llmeshrepository.h
index b850ade0bb..0847c29d0d 100644
--- a/indra/newview/llmeshrepository.h
+++ b/indra/newview/llmeshrepository.h
@@ -28,6 +28,7 @@
#define LL_MESH_REPOSITORY_H
#include <unordered_map>
+#include <unordered_set>
#include "llassettype.h"
#include "llmodel.h"
#include "lluuid.h"
@@ -62,6 +63,16 @@ typedef enum e_mesh_processing_result_enum
MESH_UNKNOWN
} EMeshProcessingResult;
+typedef enum e_mesh_request_type_enum
+{
+ MESH_REQUEST_HEADER,
+ MESH_REQUEST_LOD,
+ MESH_REQUEST_SKIN,
+ MESH_REQUEST_DECOMPOSITION,
+ MESH_REQUEST_PHYSICS,
+ MESH_REQUEST_UKNOWN
+} EMeshRequestType;
+
class LLMeshUploadData
{
public:
@@ -157,7 +168,6 @@ public:
void submitRequest(Request* request);
static S32 llcdCallback(const char*, S32, S32);
- void cancel();
void setMeshData(LLCDMeshData& mesh, bool vertex_based);
void doDecomposition();
@@ -182,7 +192,8 @@ public:
class RequestStats
{
public:
- RequestStats() : mRetries(0) {};
+
+ RequestStats() :mRetries(0) {};
void updateTime();
bool canRetry() const;
@@ -194,6 +205,118 @@ private:
LLFrameTimer mTimer;
};
+class MeshLoadData;
+class PendingRequestBase
+{
+public:
+ struct CompareScoreGreater
+ {
+ bool operator()(const std::shared_ptr<PendingRequestBase>& lhs, const std::shared_ptr<PendingRequestBase>& rhs)
+ {
+ return lhs->mScore > rhs->mScore; // greatest = first
+ }
+ };
+
+ PendingRequestBase() : mScore(0.f), mTrackedData(nullptr), mScoreDirty(true) {};
+ virtual ~PendingRequestBase() {}
+
+ bool operator<(const PendingRequestBase& rhs) const
+ {
+ return mId < rhs.mId;
+ }
+
+ F32 getScore() const { return mScore; }
+ void checkScore()
+ {
+ constexpr F32 EXPIRE_TIME_SECS = 8.f;
+ if (mScoreTimer.getElapsedTimeF32() > EXPIRE_TIME_SECS || mScoreDirty)
+ {
+ updateScore();
+ mScoreDirty = false;
+ mScoreTimer.reset();
+ }
+ };
+
+ LLUUID getId() const { return mId; }
+ virtual EMeshRequestType getRequestType() const = 0;
+
+ void trackData(MeshLoadData* data) { mTrackedData = data; mScoreDirty = true; }
+ void untrackData() { mTrackedData = nullptr; }
+ bool hasTrackedData() { return mTrackedData != nullptr; }
+ void setScoreDirty() { mScoreDirty = true; }
+
+protected:
+ void updateScore();
+
+ LLUUID mId;
+ F32 mScore;
+ bool mScoreDirty;
+ LLTimer mScoreTimer;
+ MeshLoadData* mTrackedData;
+};
+
+class PendingRequestLOD : public PendingRequestBase
+{
+public:
+ LLVolumeParams mMeshParams;
+ S32 mLOD;
+
+ PendingRequestLOD(const LLVolumeParams& mesh_params, S32 lod)
+ : PendingRequestBase(), mMeshParams(mesh_params), mLOD(lod)
+ {
+ mId = mMeshParams.getSculptID();
+ }
+
+ EMeshRequestType getRequestType() const override { return MESH_REQUEST_LOD; }
+};
+
+class PendingRequestUUID : public PendingRequestBase
+{
+public:
+
+ PendingRequestUUID(const LLUUID& id, EMeshRequestType type)
+ : PendingRequestBase(), mRequestType(type)
+ {
+ mId = id;
+ }
+
+ EMeshRequestType getRequestType() const override { return mRequestType; }
+
+private:
+ EMeshRequestType mRequestType;
+};
+
+
+class MeshLoadData
+{
+public:
+ MeshLoadData() {}
+ ~MeshLoadData()
+ {
+ if (std::shared_ptr<PendingRequestBase> request = mRequest.lock())
+ {
+ request->untrackData();
+ }
+ }
+ void initData(LLVOVolume* vol, std::shared_ptr<PendingRequestBase>& request)
+ {
+ mVolumes.push_back(vol);
+ request->trackData(this);
+ mRequest = request;
+ }
+ void addVolume(LLVOVolume* vol)
+ {
+ mVolumes.push_back(vol);
+ if (std::shared_ptr<PendingRequestBase> request = mRequest.lock())
+ {
+ request->setScoreDirty();
+ }
+ }
+ std::vector<LLVOVolume*> mVolumes;
+private:
+ std::weak_ptr<PendingRequestBase> mRequest;
+};
+
class LLMeshHeader
{
public:
@@ -234,19 +357,67 @@ public:
m404 = header.has("404");
}
+private:
+
+ enum EDiskCacheFlags {
+ FLAG_SKIN = 1 << LLModel::NUM_LODS,
+ FLAG_PHYSCONVEX = 1 << (LLModel::NUM_LODS + 1),
+ FLAG_PHYSMESH = 1 << (LLModel::NUM_LODS + 2),
+ };
+public:
+ U32 getFlags()
+ {
+ U32 flags = 0;
+ for (U32 i = 0; i < LLModel::NUM_LODS; i++)
+ {
+ if (mLodInCache[i])
+ {
+ flags |= 1 << i;
+ }
+ }
+ if (mSkinInCache)
+ {
+ flags |= FLAG_SKIN;
+ }
+ if (mPhysicsConvexInCache)
+ {
+ flags |= FLAG_PHYSCONVEX;
+ }
+ if (mPhysicsMeshInCache)
+ {
+ flags |= FLAG_PHYSMESH;
+ }
+ return flags;
+ }
+
+ void setFromFlags(U32 flags)
+ {
+ for (U32 i = 0; i < LLModel::NUM_LODS; i++)
+ {
+ mLodInCache[i] = (flags & (1 << i)) != 0;
+ }
+ mSkinInCache = (flags & FLAG_SKIN) != 0;
+ mPhysicsConvexInCache = (flags & FLAG_PHYSCONVEX) != 0;
+ mPhysicsMeshInCache = (flags & FLAG_PHYSMESH) != 0;
+ }
S32 mVersion = -1;
S32 mSkinOffset = -1;
S32 mSkinSize = -1;
+ bool mSkinInCache = false;
S32 mPhysicsConvexOffset = -1;
S32 mPhysicsConvexSize = -1;
+ bool mPhysicsConvexInCache = false;
S32 mPhysicsMeshOffset = -1;
S32 mPhysicsMeshSize = -1;
+ bool mPhysicsMeshInCache = false;
- S32 mLodOffset[4] = { -1 };
- S32 mLodSize[4] = { -1 };
+ S32 mLodOffset[LLModel::NUM_LODS] = { -1 };
+ S32 mLodSize[LLModel::NUM_LODS] = { -1 };
+ bool mLodInCache[LLModel::NUM_LODS] = { false };
+ S32 mHeaderSize = -1;
bool m404 = false;
};
@@ -255,8 +426,9 @@ class LLMeshRepoThread : public LLThread
{
public:
- volatile static S32 sActiveHeaderRequests;
- volatile static S32 sActiveLODRequests;
+ static std::atomic<S32> sActiveHeaderRequests;
+ static std::atomic<S32> sActiveLODRequests;
+ static std::atomic<S32> sActiveSkinRequests;
static U32 sMaxConcurrentRequests;
static S32 sRequestLowWater;
static S32 sRequestHighWater;
@@ -264,10 +436,13 @@ public:
LLMutex* mMutex;
LLMutex* mHeaderMutex;
+ LLMutex* mLoadedMutex;
+ LLMutex* mPendingMutex;
+ LLMutex* mSkinMapMutex;
LLCondition* mSignal;
//map of known mesh headers
- typedef boost::unordered_map<LLUUID, std::pair<U32, LLMeshHeader>> mesh_header_map; // pair is header_size and data
+ typedef boost::unordered_map<LLUUID, LLMeshHeader> mesh_header_map; // pair is header_size and data
mesh_header_map mMeshHeader;
class HeaderRequest : public RequestStats
@@ -291,22 +466,13 @@ public:
public:
LLVolumeParams mMeshParams;
S32 mLOD;
- F32 mScore;
LODRequest(const LLVolumeParams& mesh_params, S32 lod)
- : RequestStats(), mMeshParams(mesh_params), mLOD(lod), mScore(0.f)
+ : RequestStats(), mMeshParams(mesh_params), mLOD(lod)
{
}
};
- struct CompareScoreGreater
- {
- bool operator()(const LODRequest& lhs, const LODRequest& rhs)
- {
- return lhs.mScore > rhs.mScore; // greatest = first
- }
- };
-
class UUIDBasedRequest : public RequestStats
{
public:
@@ -341,7 +507,7 @@ public:
std::deque<UUIDBasedRequest> mSkinRequests;
// list of completed skin info requests
- std::deque<LLMeshSkinInfo*> mSkinInfoQ;
+ std::deque<LLPointer<LLMeshSkinInfo>> mSkinInfoQ;
// list of skin info requests that have failed or are unavailaibe
std::deque<UUIDBasedRequest> mSkinUnavailableQ;
@@ -368,9 +534,19 @@ public:
std::deque<LoadedMesh> mLoadedQ;
//map of pending header requests and currently desired LODs
- typedef boost::unordered_map<LLUUID, std::vector<S32> > pending_lod_map;
+ typedef std::unordered_map<LLUUID, std::array<S32, LLModel::NUM_LODS> > pending_lod_map;
pending_lod_map mPendingLOD;
+ // map of mesh ID to skin info (mirrors LLMeshRepository::mSkinMap)
+ /// NOTE: LLMeshRepository::mSkinMap is accessed very frequently, so maintain a copy here to avoid mutex overhead
+ typedef std::unordered_map<LLUUID, LLPointer<LLMeshSkinInfo>> skin_map;
+ skin_map mSkinMap;
+
+ // workqueue for processing generic requests
+ LL::WorkQueue mWorkQueue;
+ // lods have their own thread due to costly cacheOptimize() calls
+ std::unique_ptr<LL::ThreadPool> mMeshThreadPool;
+
// llcorehttp library interface objects.
LLCore::HttpStatus mHttpStatus;
LLCore::HttpRequest * mHttpRequest;
@@ -380,7 +556,7 @@ public:
LLCore::HttpRequest::policy_t mHttpPolicyClass;
LLCore::HttpRequest::policy_t mHttpLargePolicyClass;
- typedef std::set<LLCore::HttpHandler::ptr_t> http_request_set;
+ typedef std::unordered_set<LLCore::HttpHandler::ptr_t> http_request_set;
http_request_set mHttpRequestSet; // Outstanding HTTP requests
std::string mGetMeshCapability;
@@ -389,20 +565,22 @@ public:
~LLMeshRepoThread();
virtual void run();
+ void cleanup();
+ bool isShuttingDown() { return mShuttingDown; }
void lockAndLoadMeshLOD(const LLVolumeParams& mesh_params, S32 lod);
void loadMeshLOD(const LLVolumeParams& mesh_params, S32 lod);
- bool fetchMeshHeader(const LLVolumeParams& mesh_params, bool can_retry = true);
- bool fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod, bool can_retry = true);
- EMeshProcessingResult headerReceived(const LLVolumeParams& mesh_params, U8* data, S32 data_size);
+ bool fetchMeshHeader(const LLVolumeParams& mesh_params);
+ bool fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod);
+ EMeshProcessingResult headerReceived(const LLVolumeParams& mesh_params, U8* data, S32 data_size, U32 flags = 0);
EMeshProcessingResult 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);
EMeshProcessingResult physicsShapeReceived(const LLUUID& mesh_id, U8* data, S32 data_size);
- bool hasPhysicsShapeInHeader(const LLUUID& mesh_id);
- bool hasSkinInfoInHeader(const LLUUID& mesh_id);
- bool hasHeader(const LLUUID& mesh_id);
+ bool hasPhysicsShapeInHeader(const LLUUID& mesh_id) const;
+ bool hasSkinInfoInHeader(const LLUUID& mesh_id) const;
+ bool hasHeader(const LLUUID& mesh_id) const;
void notifyLoadedMeshes();
S32 getActualMeshLOD(const LLVolumeParams& mesh_params, S32 lod);
@@ -413,7 +591,7 @@ public:
//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, bool can_retry = true);
+ 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)
@@ -427,6 +605,8 @@ public:
static void decActiveLODRequests();
static void incActiveHeaderRequests();
static void decActiveHeaderRequests();
+ static void incActiveSkinRequests();
+ static void decActiveSkinRequests();
// Set the caps strings and preferred version for constructing
// mesh fetch URLs.
@@ -447,6 +627,15 @@ private:
LLCore::HttpHandle getByteRange(const std::string & url,
size_t offset, size_t len,
const LLCore::HttpHandler::ptr_t &handler);
+
+ // Mutex: acquires mPendingMutex, mMutex and mHeaderMutex as needed
+ void loadMeshLOD(const LLUUID &mesh_id, const LLVolumeParams& mesh_params, S32 lod);
+
+ // Threads: Repo thread only
+ U8* getDiskCacheBuffer(S32 size);
+ S32 mDiskCacheBufferSize = 0;
+ U8* mDiskCacheBuffer = nullptr;
+ bool mShuttingDown = false;
};
@@ -559,35 +748,35 @@ public:
bool init(const LLMeshHeader& header);
// Size for given LOD
- S32 getSizeByLOD(S32 lod);
+ S32 getSizeByLOD(S32 lod) const;
// Sum of all LOD sizes.
- S32 getSizeTotal();
+ S32 getSizeTotal() const;
// Estimated triangle counts for the given LOD.
- F32 getEstTrisByLOD(S32 lod);
+ F32 getEstTrisByLOD(S32 lod) const;
// Estimated triangle counts for the largest LOD. Typically this
// is also the "high" LOD, but not necessarily.
- F32 getEstTrisMax();
+ F32 getEstTrisMax() const;
// Triangle count as computed by original streaming cost
// formula. Triangles in each LOD are weighted based on how
// frequently they will be seen.
// This was called "unscaled_value" in the original getStreamingCost() functions.
- F32 getRadiusWeightedTris(F32 radius);
+ F32 getRadiusWeightedTris(F32 radius) const;
// Triangle count used by triangle-based cost formula. Based on
// triangles in highest LOD plus potentially partial charges for
// lower LODs depending on complexity.
- F32 getEstTrisForStreamingCost();
+ F32 getEstTrisForStreamingCost() const;
// Streaming cost. This should match the server-side calculation
// for the corresponding volume.
- F32 getRadiusBasedStreamingCost(F32 radius);
+ F32 getRadiusBasedStreamingCost(F32 radius) const;
// New streaming cost formula, currently only used for animated objects.
- F32 getTriangleBasedStreamingCost();
+ F32 getTriangleBasedStreamingCost() const;
private:
// From the "size" field of the mesh header. LOD 0=lowest, 3=highest.
@@ -611,12 +800,12 @@ public:
static U32 sLODPending;
static U32 sLODProcessing;
static U32 sCacheBytesRead;
- static U32 sCacheBytesWritten;
+ static std::atomic<U32> sCacheBytesWritten;
static U32 sCacheBytesHeaders;
static U32 sCacheBytesSkins;
static U32 sCacheBytesDecomps;
static U32 sCacheReads;
- static U32 sCacheWrites;
+ static std::atomic<U32> sCacheWrites;
static U32 sMaxLockHoldoffs; // Maximum sequential locking failures
static LLDeadmanTimer sQuiescentTimer; // Time-to-complete-mesh-downloads after significant events
@@ -637,11 +826,11 @@ public:
void unregisterMesh(LLVOVolume* volume);
//mesh management functions
- S32 loadMesh(LLVOVolume* volume, const LLVolumeParams& mesh_params, S32 detail = 0, S32 last_lod = -1);
+ S32 loadMesh(LLVOVolume* volume, const LLVolumeParams& mesh_params, S32 new_lod = 0, S32 last_lod = -1);
void notifyLoadedMeshes();
- void notifyMeshLoaded(const LLVolumeParams& mesh_params, LLVolume* volume);
- void notifyMeshUnavailable(const LLVolumeParams& mesh_params, S32 lod);
+ void notifyMeshLoaded(const LLVolumeParams& mesh_params, LLVolume* volume, S32 lod);
+ void notifyMeshUnavailable(const LLVolumeParams& mesh_params, S32 request_lod, S32 volume_lod);
void notifySkinInfoReceived(LLMeshSkinInfo* info);
void notifySkinInfoUnavailable(const LLUUID& info);
void notifyDecompositionReceived(LLModel::Decomposition* info);
@@ -653,7 +842,7 @@ public:
void fetchPhysicsShape(const LLUUID& mesh_id);
bool hasPhysicsShape(const LLUUID& mesh_id);
bool hasSkinInfo(const LLUUID& mesh_id);
- bool hasHeader(const LLUUID& mesh_id);
+ bool hasHeader(const LLUUID& mesh_id) const;
void buildHull(const LLVolumeParams& params, S32 detail);
void buildPhysicsMesh(LLModel::Decomposition& decomp);
@@ -667,7 +856,7 @@ public:
LLHandle<LLWholeModelFeeObserver> fee_observer= (LLHandle<LLWholeModelFeeObserver>()),
LLHandle<LLWholeModelUploadObserver> upload_observer = (LLHandle<LLWholeModelUploadObserver>()));
- S32 getMeshSize(const LLUUID& mesh_id, S32 lod);
+ S32 getMeshSize(const LLUUID& mesh_id, S32 lod) const;
// Quiescent timer management, main thread only.
static void metricsStart();
@@ -675,7 +864,7 @@ public:
static void metricsProgress(unsigned int count);
static void metricsUpdate();
- typedef boost::unordered_map<LLUUID, std::vector<LLVOVolume*> > mesh_load_map;
+ typedef std::unordered_map<LLUUID, MeshLoadData> mesh_load_map;
mesh_load_map mLoadingMeshes[4];
typedef std::unordered_map<LLUUID, LLPointer<LLMeshSkinInfo>> skin_map;
@@ -686,23 +875,21 @@ public:
LLMutex* mMeshMutex;
- std::vector<LLMeshRepoThread::LODRequest> mPendingRequests;
+ typedef std::vector <std::shared_ptr<PendingRequestBase> > pending_requests_vec;
+ pending_requests_vec mPendingRequests;
//list of mesh ids awaiting skin info
- typedef boost::unordered_map<LLUUID, std::vector<LLVOVolume*> > skin_load_map;
+ typedef std::unordered_map<LLUUID, MeshLoadData > 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;
+ std::unordered_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;
+ std::unordered_set<LLUUID> mLoadingPhysicsShapes;
//list of mesh ids that need to send physics shape fetch requests
std::queue<LLUUID> mPendingPhysicsShapeRequests;