diff options
Diffstat (limited to 'indra/newview/llmeshrepository.h')
-rw-r--r-- | indra/newview/llmeshrepository.h | 287 |
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; |