#3960 Fix expensive mesh thread score calculations
parent
87b6428f55
commit
b30283e5ef
|
|
@ -544,6 +544,66 @@ bool RequestStats::isDelayed() const
|
|||
return mTimer.getStarted() && !mTimer.hasExpired();
|
||||
}
|
||||
|
||||
F32 calculate_score(LLVOVolume* object)
|
||||
{
|
||||
if (!object)
|
||||
{
|
||||
return -1.f;
|
||||
}
|
||||
LLDrawable* drawable = object->mDrawable;
|
||||
if (!drawable)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if (drawable->isState(LLDrawable::RIGGED) || object->isAttachment())
|
||||
{
|
||||
LLVOAvatar* avatar = object->getAvatar();
|
||||
LLDrawable* av_drawable = avatar ? avatar->mDrawable : nullptr;
|
||||
if (avatar && av_drawable)
|
||||
{
|
||||
// See LLVOVolume::calcLOD()
|
||||
F32 radius;
|
||||
if (avatar->isControlAvatar())
|
||||
{
|
||||
const LLVector3* box = avatar->getLastAnimExtents();
|
||||
LLVector3 diag = box[1] - box[0];
|
||||
radius = diag.magVec() * 0.5f;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Volume in a rigged mesh attached to a regular avatar.
|
||||
const LLVector3* box = avatar->getLastAnimExtents();
|
||||
LLVector3 diag = box[1] - box[0];
|
||||
radius = diag.magVec();
|
||||
|
||||
if (!avatar->isSelf() && !avatar->hasFirstFullAttachmentData())
|
||||
{
|
||||
// slightly deprioritize avatars that are still receiving data
|
||||
radius *= 0.9f;
|
||||
}
|
||||
}
|
||||
return radius / llmax(av_drawable->mDistanceWRTCamera, 1.f);
|
||||
}
|
||||
}
|
||||
return drawable->getRadius() / llmax(drawable->mDistanceWRTCamera, 1.f);
|
||||
}
|
||||
|
||||
void PendingRequestBase::updateScore()
|
||||
{
|
||||
mScore = 0;
|
||||
if (mTrackedData)
|
||||
{
|
||||
for (LLVOVolume* volume : mTrackedData->mVolumes)
|
||||
{
|
||||
F32 cur_score = calculate_score(volume);
|
||||
if (cur_score > 0)
|
||||
{
|
||||
mScore = llmax(mScore, cur_score);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LLViewerFetchedTexture* LLMeshUploadThread::FindViewerTexture(const LLImportMaterial& material)
|
||||
{
|
||||
LLPointer< LLViewerFetchedTexture > * ppTex = static_cast< LLPointer< LLViewerFetchedTexture > * >(material.mOpaqueData);
|
||||
|
|
@ -2220,7 +2280,7 @@ EMeshProcessingResult LLMeshRepoThread::headerReceived(const LLVolumeParams& mes
|
|||
|
||||
if (gMeshRepo.mLoadingSkins.find(mesh_id) == gMeshRepo.mLoadingSkins.end())
|
||||
{
|
||||
gMeshRepo.mLoadingSkins[mesh_id] = {}; // add an empty vector to indicate to main thread that we are loading skin info
|
||||
gMeshRepo.mLoadingSkins[mesh_id]; // add an empty vector to indicate to main thread that we are loading skin info
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -4212,13 +4272,13 @@ void LLMeshRepository::unregisterMesh(LLVOVolume* vobj)
|
|||
{
|
||||
for (auto& param : lod)
|
||||
{
|
||||
vector_replace_with_last(param.second, vobj);
|
||||
vector_replace_with_last(param.second.mVolumes, vobj);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& skin_pair : mLoadingSkins)
|
||||
{
|
||||
vector_replace_with_last(skin_pair.second, vobj);
|
||||
vector_replace_with_last(skin_pair.second.mVolumes, vobj);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -4241,16 +4301,17 @@ S32 LLMeshRepository::loadMesh(LLVOVolume* vobj, const LLVolumeParams& mesh_para
|
|||
mesh_load_map::iterator iter = mLoadingMeshes[new_lod].find(mesh_id);
|
||||
if (iter != mLoadingMeshes[new_lod].end())
|
||||
{ //request pending for this mesh, append volume id to list
|
||||
auto it = std::find(iter->second.begin(), iter->second.end(), vobj);
|
||||
if (it == iter->second.end()) {
|
||||
iter->second.push_back(vobj);
|
||||
auto it = std::find(iter->second.mVolumes.begin(), iter->second.mVolumes.end(), vobj);
|
||||
if (it == iter->second.mVolumes.end()) {
|
||||
iter->second.addVolume(vobj);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//first request for this mesh
|
||||
mLoadingMeshes[new_lod][mesh_id].push_back(vobj);
|
||||
mPendingRequests.emplace_back(new PendingRequestLOD(mesh_params, new_lod));
|
||||
std::shared_ptr<PendingRequestBase> request(new PendingRequestLOD(mesh_params, new_lod));
|
||||
mPendingRequests.emplace_back(request);
|
||||
mLoadingMeshes[new_lod][mesh_id].initData(vobj, request);
|
||||
LLMeshRepository::sLODPending++;
|
||||
}
|
||||
}
|
||||
|
|
@ -4309,50 +4370,6 @@ S32 LLMeshRepository::loadMesh(LLVOVolume* vobj, const LLVolumeParams& mesh_para
|
|||
return new_lod;
|
||||
}
|
||||
|
||||
F32 calculate_score(LLVOVolume* object)
|
||||
{
|
||||
if (!object)
|
||||
{
|
||||
return -1.f;
|
||||
}
|
||||
LLDrawable* drawable = object->mDrawable;
|
||||
if (!drawable)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if (drawable->isState(LLDrawable::RIGGED) || object->isAttachment())
|
||||
{
|
||||
LLVOAvatar* avatar = object->getAvatar();
|
||||
LLDrawable* av_drawable = avatar ? avatar->mDrawable : nullptr;
|
||||
if (avatar && av_drawable)
|
||||
{
|
||||
// See LLVOVolume::calcLOD()
|
||||
F32 radius;
|
||||
if (avatar->isControlAvatar())
|
||||
{
|
||||
const LLVector3* box = avatar->getLastAnimExtents();
|
||||
LLVector3 diag = box[1] - box[0];
|
||||
radius = diag.magVec() * 0.5f;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Volume in a rigged mesh attached to a regular avatar.
|
||||
const LLVector3* box = avatar->getLastAnimExtents();
|
||||
LLVector3 diag = box[1] - box[0];
|
||||
radius = diag.magVec();
|
||||
|
||||
if (!avatar->isSelf() && !avatar->hasFirstFullAttachmentData())
|
||||
{
|
||||
// slightly deprioritize avatars that are still receiving data
|
||||
radius *= 0.9f;
|
||||
}
|
||||
}
|
||||
return radius / llmax(av_drawable->mDistanceWRTCamera, 1.f);
|
||||
}
|
||||
}
|
||||
return drawable->getRadius() / llmax(drawable->mDistanceWRTCamera, 1.f);
|
||||
}
|
||||
|
||||
void LLMeshRepository::notifyLoadedMeshes()
|
||||
{ //called from main thread
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; //LL_RECORD_BLOCK_TIME(FTM_MESH_FETCH);
|
||||
|
|
@ -4549,51 +4566,14 @@ void LLMeshRepository::notifyLoadedMeshes()
|
|||
|
||||
if (mPendingRequests.size() > push_count)
|
||||
{
|
||||
LL_PROFILE_ZONE_NAMED("Mesh score_map");
|
||||
LL_PROFILE_ZONE_NAMED("Mesh score update");
|
||||
// More requests than the high-water limit allows so
|
||||
// sort and forward the most important.
|
||||
|
||||
//calculate "score" for pending requests
|
||||
|
||||
//create score map
|
||||
std::map<LLUUID, F32> score_map;
|
||||
|
||||
for (U32 i = 0; i < LLVolumeLODGroup::NUM_LODS; ++i)
|
||||
// update "score" for pending requests
|
||||
for (std::shared_ptr<PendingRequestBase>& req_p : mPendingRequests)
|
||||
{
|
||||
for (mesh_load_map::iterator iter = mLoadingMeshes[i].begin(); iter != mLoadingMeshes[i].end(); ++iter)
|
||||
{
|
||||
F32 max_score = 0.f;
|
||||
for (auto obj_iter = iter->second.begin(); obj_iter != iter->second.end(); ++obj_iter)
|
||||
{
|
||||
F32 cur_score = calculate_score(*obj_iter);
|
||||
if (cur_score >= 0.f)
|
||||
{
|
||||
max_score = llmax(max_score, cur_score);
|
||||
}
|
||||
}
|
||||
|
||||
score_map[iter->first] = max_score;
|
||||
}
|
||||
}
|
||||
for (mesh_load_map::iterator iter = mLoadingSkins.begin(); iter != mLoadingSkins.end(); ++iter)
|
||||
{
|
||||
F32 max_score = 0.f;
|
||||
for (auto obj_iter = iter->second.begin(); obj_iter != iter->second.end(); ++obj_iter)
|
||||
{
|
||||
F32 cur_score = calculate_score(*obj_iter);
|
||||
if (cur_score >= 0.f)
|
||||
{
|
||||
max_score = llmax(max_score, cur_score);
|
||||
}
|
||||
}
|
||||
|
||||
score_map[iter->first] = max_score;
|
||||
}
|
||||
|
||||
//set "score" for pending requests
|
||||
for (std::unique_ptr<PendingRequestBase>& req_p : mPendingRequests)
|
||||
{
|
||||
req_p->setScore(score_map[req_p->getId()]);
|
||||
req_p->checkScore();
|
||||
}
|
||||
|
||||
//sort by "score"
|
||||
|
|
@ -4602,7 +4582,9 @@ void LLMeshRepository::notifyLoadedMeshes()
|
|||
}
|
||||
while (!mPendingRequests.empty() && push_count > 0)
|
||||
{
|
||||
std::unique_ptr<PendingRequestBase>& req_p = mPendingRequests.front();
|
||||
std::shared_ptr<PendingRequestBase>& req_p = mPendingRequests.front();
|
||||
// todo: check hasTrackedData here and erase request if none
|
||||
// since this is supposed to mean that request was removed
|
||||
switch (req_p->getRequestType())
|
||||
{
|
||||
case MESH_REQUEST_LOD:
|
||||
|
|
@ -4657,7 +4639,7 @@ void LLMeshRepository::notifySkinInfoReceived(LLMeshSkinInfo* info)
|
|||
skin_load_map::iterator iter = mLoadingSkins.find(info->mMeshID);
|
||||
if (iter != mLoadingSkins.end())
|
||||
{
|
||||
for (LLVOVolume* vobj : iter->second)
|
||||
for (LLVOVolume* vobj : iter->second.mVolumes)
|
||||
{
|
||||
if (vobj)
|
||||
{
|
||||
|
|
@ -4673,7 +4655,7 @@ void LLMeshRepository::notifySkinInfoUnavailable(const LLUUID& mesh_id)
|
|||
skin_load_map::iterator iter = mLoadingSkins.find(mesh_id);
|
||||
if (iter != mLoadingSkins.end())
|
||||
{
|
||||
for (LLVOVolume* vobj : iter->second)
|
||||
for (LLVOVolume* vobj : iter->second.mVolumes)
|
||||
{
|
||||
if (vobj)
|
||||
{
|
||||
|
|
@ -4737,7 +4719,7 @@ void LLMeshRepository::notifyMeshLoaded(const LLVolumeParams& mesh_params, LLVol
|
|||
}
|
||||
|
||||
//notify waiting LLVOVolume instances that their requested mesh is available
|
||||
for (LLVOVolume* vobj : obj_iter->second)
|
||||
for (LLVOVolume* vobj : obj_iter->second.mVolumes)
|
||||
{
|
||||
if (vobj)
|
||||
{
|
||||
|
|
@ -4767,7 +4749,7 @@ void LLMeshRepository::notifyMeshUnavailable(const LLVolumeParams& mesh_params,
|
|||
LLPrimitive::getVolumeManager()->unrefVolume(sys_volume);
|
||||
}
|
||||
|
||||
for (LLVOVolume* vobj : obj_iter->second)
|
||||
for (LLVOVolume* vobj : obj_iter->second.mVolumes)
|
||||
{
|
||||
if (vobj)
|
||||
{
|
||||
|
|
@ -4810,16 +4792,17 @@ const LLMeshSkinInfo* LLMeshRepository::getSkinInfo(const LLUUID& mesh_id, LLVOV
|
|||
skin_load_map::iterator iter = mLoadingSkins.find(mesh_id);
|
||||
if (iter != mLoadingSkins.end())
|
||||
{ //request pending for this mesh, append volume id to list
|
||||
auto it = std::find(iter->second.begin(), iter->second.end(), requesting_obj);
|
||||
if (it == iter->second.end()) {
|
||||
iter->second.push_back(requesting_obj);
|
||||
auto it = std::find(iter->second.mVolumes.begin(), iter->second.mVolumes.end(), requesting_obj);
|
||||
if (it == iter->second.mVolumes.end()) {
|
||||
iter->second.addVolume(requesting_obj);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//first request for this mesh
|
||||
mLoadingSkins[mesh_id].push_back(requesting_obj);
|
||||
mPendingRequests.emplace_back(new PendingRequestUUID(mesh_id, MESH_REQUEST_SKIN));
|
||||
std::shared_ptr<PendingRequestBase> request(new PendingRequestUUID(mesh_id, MESH_REQUEST_SKIN));
|
||||
mLoadingSkins[mesh_id].initData(requesting_obj, request);
|
||||
mPendingRequests.emplace_back(request);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -168,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();
|
||||
|
|
@ -206,19 +205,19 @@ private:
|
|||
LLFrameTimer mTimer;
|
||||
};
|
||||
|
||||
|
||||
class MeshLoadData;
|
||||
class PendingRequestBase
|
||||
{
|
||||
public:
|
||||
struct CompareScoreGreater
|
||||
{
|
||||
bool operator()(const std::unique_ptr<PendingRequestBase>& lhs, const std::unique_ptr<PendingRequestBase>& rhs)
|
||||
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) {};
|
||||
PendingRequestBase() : mScore(0.f), mTrackedData(nullptr), mScoreDirty(true) {};
|
||||
virtual ~PendingRequestBase() {}
|
||||
|
||||
bool operator<(const PendingRequestBase& rhs) const
|
||||
|
|
@ -226,14 +225,34 @@ public:
|
|||
return mId < rhs.mId;
|
||||
}
|
||||
|
||||
void setScore(F32 score) { mScore = score; }
|
||||
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:
|
||||
F32 mScore;
|
||||
void updateScore();
|
||||
|
||||
LLUUID mId;
|
||||
F32 mScore;
|
||||
bool mScoreDirty;
|
||||
LLTimer mScoreTimer;
|
||||
MeshLoadData* mTrackedData;
|
||||
};
|
||||
|
||||
class PendingRequestLOD : public PendingRequestBase
|
||||
|
|
@ -267,6 +286,37 @@ 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:
|
||||
|
|
@ -814,7 +864,7 @@ public:
|
|||
static void metricsProgress(unsigned int count);
|
||||
static void metricsUpdate();
|
||||
|
||||
typedef std::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;
|
||||
|
|
@ -825,11 +875,11 @@ public:
|
|||
|
||||
LLMutex* mMeshMutex;
|
||||
|
||||
typedef std::vector <std::unique_ptr<PendingRequestBase> > pending_requests_vec;
|
||||
typedef std::vector <std::shared_ptr<PendingRequestBase> > pending_requests_vec;
|
||||
pending_requests_vec mPendingRequests;
|
||||
|
||||
//list of mesh ids awaiting skin info
|
||||
typedef std::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 awaiting decompositions
|
||||
|
|
|
|||
Loading…
Reference in New Issue