CTS-231 WIP create new ARC algorithm to be more accurate and account for meshes

First pass - uses the new algorithm to hopefully be more accurate of render load
on low-end machines. Also accounts for mesh complexity, including if a mesh is
weighted or non-weighted.

Code reviewed by davep
meow-7.2.2
Nyx (Neal Orman) 2010-09-01 10:59:45 -04:00
parent d8fd52341a
commit e3fec30097
6 changed files with 239 additions and 35 deletions

View File

@ -1007,7 +1007,7 @@ void LLFloaterTools::onClickGridOptions()
S32 LLFloaterTools::calcRenderCost()
{
S32 cost = 0;
std::set<LLUUID> textures;
LLVOVolume::texture_cost_t textures;
for (LLObjectSelection::iterator selection_iter = LLSelectMgr::getInstance()->getSelection()->begin();
selection_iter != LLSelectMgr::getInstance()->getSelection()->end();
@ -1020,7 +1020,11 @@ S32 LLFloaterTools::calcRenderCost()
if (viewer_volume)
{
cost += viewer_volume->getRenderCost(textures);
cost += textures.size() * LLVOVolume::ARC_TEXTURE_COST;
for (LLVOVolume::texture_cost_t::iterator iter = textures.begin(); iter != textures.end(); ++iter)
{
// add the cost of each individual texture in the linkset
cost += iter->second;
}
textures.clear();
}
}

View File

@ -2104,6 +2104,30 @@ void LLMeshRepository::uploadModel(std::vector<LLModelInstance>& data, LLVector3
thread->start();
}
S32 LLMeshRepository::getMeshSize(const LLUUID& mesh_id, S32 lod)
{
if (mThread)
{
LLMeshRepoThread::mesh_header_map::iterator iter = mThread->mMeshHeader.find(mesh_id);
if (iter != mThread->mMeshHeader.end())
{
LLSD& header = iter->second;
if (header.has("404"))
{
return -1;
}
S32 size = header[header_lod[lod]]["size"].asInteger();
return size;
}
}
return -1;
}
void LLMeshUploadThread::sendCostRequest(LLMeshUploadData& data)
{
//write model file to memory buffer

View File

@ -405,8 +405,7 @@ public:
void uploadModel(std::vector<LLModelInstance>& data, LLVector3& scale, bool upload_textures);
S32 getMeshSize(const LLUUID& mesh_id, S32 lod);
typedef std::map<LLVolumeParams, std::set<LLUUID> > mesh_load_map;
mesh_load_map mLoadingMeshes[4];

View File

@ -7968,7 +7968,7 @@ void LLVOAvatar::getImpostorValues(LLVector4a* extents, LLVector3& angle, F32& d
void LLVOAvatar::idleUpdateRenderCost()
{
static const U32 ARC_BODY_PART_COST = 20;
static const U32 ARC_BODY_PART_COST = 200;
static const U32 ARC_LIMIT = 2048;
static std::set<LLUUID> all_textures;
@ -7979,7 +7979,7 @@ void LLVOAvatar::idleUpdateRenderCost()
}
U32 cost = 0;
std::set<LLUUID> textures;
LLVOVolume::texture_cost_t textures;
for (U8 baked_index = 0; baked_index < BAKED_NUM_INDICES; baked_index++)
{
@ -8017,16 +8017,24 @@ void LLVOAvatar::idleUpdateRenderCost()
}
}
}
}
for (LLVOVolume::texture_cost_t::iterator iter = textures.begin(); iter != textures.end(); ++iter)
{
// add the cost of each individual texture in the linkset
cost += iter->second;
}
// Diagnostic output to identify all avatar-related textures.
// Does not affect rendering cost calculation.
// Could be wrapped in a debug option if output becomes problematic.
if (isSelf())
{
// print any attachment textures we didn't already know about.
for (std::set<LLUUID>::iterator it = textures.begin(); it != textures.end(); ++it)
for (LLVOVolume::texture_cost_t::iterator it = textures.begin(); it != textures.end(); ++it)
{
LLUUID image_id = *it;
LLUUID image_id = it->first;
if( image_id.isNull() || image_id == IMG_DEFAULT || image_id == IMG_DEFAULT_AVATAR)
continue;
if (all_textures.find(image_id) == all_textures.end())
@ -8057,7 +8065,6 @@ void LLVOAvatar::idleUpdateRenderCost()
}
}
}
cost += textures.size() * LLVOVolume::ARC_TEXTURE_COST;
setDebugText(llformat("%d", cost));
F32 green = 1.f-llclamp(((F32) cost-(F32)ARC_LIMIT)/(F32)ARC_LIMIT, 0.f, 1.f);

View File

@ -2872,17 +2872,31 @@ const LLMatrix4 LLVOVolume::getRenderMatrix() const
// total cost is returned value + 5 * size of the resulting set.
// Cannot include cost of textures, as they may be re-used in linked
// children, and cost should only be increased for unique textures -Nyx
U32 LLVOVolume::getRenderCost(std::set<LLUUID> &textures) const
U32 LLVOVolume::getRenderCost(texture_cost_t &textures) const
{
// base cost of each prim should be 10 points
static const U32 ARC_PRIM_COST = 10;
// get access to params we'll need at various points
LLVolumeParams volume_params = getVolume()->getParams();
LLPathParams path_params = volume_params.getPathParams();
LLProfileParams profile_params = volume_params.getProfileParams();
// per-prim costs
static const U32 ARC_INVISI_COST = 1;
static const U32 ARC_SHINY_COST = 1;
static const U32 ARC_GLOW_COST = 1;
static const U32 ARC_FLEXI_COST = 8;
static const U32 ARC_PARTICLE_COST = 16;
static const U32 ARC_BUMP_COST = 4;
static const U32 ARC_CUT_COST = 1;
static const U32 ARC_TEXTURE_COST = 5;
// per-prim multipliers
static const U32 ARC_HOLLOW_MULT = 2;
static const U32 ARC_TWIST_MULT = 2;
static const U32 ARC_CIRC_PROF_MULT = 2;
static const U32 ARC_CIRC_PATH_MULT = 2;
static const U32 ARC_GLOW_MULT = 2;
static const U32 ARC_BUMP_MULT = 2;
static const U32 ARC_FLEXI_MULT = 4;
static const U32 ARC_SHINY_MULT = 2;
// per-face costs
static const U32 ARC_PLANAR_COST = 1;
@ -2901,6 +2915,61 @@ U32 LLVOVolume::getRenderCost(std::set<LLUUID> &textures) const
U32 scale = 0;
U32 bump = 0;
U32 planar = 0;
U32 cuts = 0;
U32 hollow = 0;
U32 twist = 0;
U32 circular_profile = 0;
U32 circular_path = 0;
const LLDrawable* drawablep = mDrawable;
if (isSculpted())
{
if (isMesh())
{
// base cost is dependent on mesh complexity
// note that 3 is the highest LOD as of the time of this coding.
S32 size = gMeshRepo.getMeshSize(volume_params.getSculptID(),3);
if ( size > 0)
{
if (gMeshRepo.getSkinInfo(volume_params.getSculptID()))
{
// weighted attachment - 1 point for every 3 bytes
shame = (U32)(size / 3.f);
}
else
{
// non-weighted attachment - 1 point for every 4 bytes
shame = (U32)(size / 4.f);
}
if (shame == 0)
{
// someone made a really tiny mesh.
shame = 1;
}
}
else
{
// something went wrong - user should know their content isn't render-free
return 0;
}
}
else
{
const LLSculptParams *sculpt_params = (LLSculptParams *) getParameterEntry(LLNetworkData::PARAMS_SCULPT);
LLUUID sculpt_id = sculpt_params->getSculptTexture();
if (textures.find(sculpt_id) == textures.end())
{
LLViewerFetchedTexture *texture = LLViewerTextureManager::getFetchedTexture(sculpt_id);
if (texture)
{
S32 texture_cost = ARC_TEXTURE_COST * (texture->getFullHeight() / 128 + texture->getFullWidth() / 128 + 1);
textures.insert(texture_cost_t::value_type(sculpt_id, texture_cost));
}
}
}
}
if (isFlexible())
{
@ -2913,14 +2982,63 @@ U32 LLVOVolume::getRenderCost(std::set<LLUUID> &textures) const
const LLVector3& sc = getScale();
scale += (U32) sc.mV[0] + (U32) sc.mV[1] + (U32) sc.mV[2];
const LLDrawable* drawablep = mDrawable;
if (isSculpted())
if (scale > 4)
{
const LLSculptParams *sculpt_params = (LLSculptParams *) getParameterEntry(LLNetworkData::PARAMS_SCULPT);
LLUUID sculpt_id = sculpt_params->getSculptTexture();
textures.insert(sculpt_id);
// scale is a multiplier, cap it at 4.
scale = 4;
}
// add points for cut prims
if (path_params.getBegin() != 0.f || path_params.getEnd() != 1.f)
{
++cuts;
}
if (profile_params.getBegin() != 0.f || profile_params.getEnd() != 1.f)
{
++cuts;
}
// double cost for hollow prims / sculpties
if (volume_params.getHollow() != 0.f)
{
hollow = 1;
}
// twist - scale by twist extent / 90
if (volume_params.getTwistBegin() != 0.f)
{
U32 scale = abs((S32)(volume_params.getTwistBegin() / 90.f) + 1);
twist += scale;
}
// twist - scale by twist extent / 90
if (volume_params.getTwist() != 0.f)
{
U32 scale = abs((S32)(volume_params.getTwist() / 90.f) + 1);
twist += scale;
}
// double cost for circular profiles / sculpties
if (profile_params.getCurveType() == LL_PCODE_PROFILE_CIRCLE ||
profile_params.getCurveType() == LL_PCODE_PROFILE_CIRCLE_HALF)
{
circular_profile = 1;
}
// double cost for circular paths / sculpties
if (path_params.getCurveType() == LL_PCODE_PATH_CIRCLE ||
path_params.getCurveType() == LL_PCODE_PATH_CIRCLE2)
{
circular_path = 1;
}
// treat sculpties as hollow prims with circular paths & profiles
if (isSculpted() && !isMesh())
{
hollow = 1;
circular_profile = 1;
circular_path = 1;
}
for (S32 i = 0; i < drawablep->getNumFaces(); ++i)
@ -2931,7 +3049,11 @@ U32 LLVOVolume::getRenderCost(std::set<LLUUID> &textures) const
if (img)
{
textures.insert(img->getID());
if (textures.find(img->getID()) == textures.end())
{
S32 texture_cost = ARC_TEXTURE_COST * (img->getFullHeight() / 128 + img->getFullWidth() / 128 + 1);
textures.insert(texture_cost_t::value_type(img->getID(), texture_cost));
}
}
if (face->getPoolType() == LLDrawPool::POOL_ALPHA)
@ -2940,21 +3062,24 @@ U32 LLVOVolume::getRenderCost(std::set<LLUUID> &textures) const
}
else if (img && img->getPrimaryFormat() == GL_ALPHA)
{
invisi = 1;
invisi++;
}
if (te)
{
if (te->getBumpmap())
{
// bump is a multiplier, don't add per-face
bump = 1;
}
if (te->getShiny())
{
// shiny is a multiplier, don't add per-face
shiny = 1;
}
if (te->getGlow() > 0.f)
{
// glow is a multiplier, don't add per-face
glow = 1;
}
if (face->mTextureMatrix != NULL)
@ -2968,17 +3093,63 @@ U32 LLVOVolume::getRenderCost(std::set<LLUUID> &textures) const
}
}
// shame currently has the "base" cost of 10 for normal prims, variable for mesh
shame += invisi * ARC_INVISI_COST;
shame += shiny * ARC_SHINY_COST;
shame += glow * ARC_GLOW_COST;
shame += alpha * ARC_ALPHA_COST;
shame += flexi * ARC_FLEXI_COST;
shame += animtex * ARC_ANIM_TEX_COST;
shame += particles * ARC_PARTICLE_COST;
shame += bump * ARC_BUMP_COST;
// add modifier settings
shame += cuts * ARC_CUT_COST;
shame += planar * ARC_PLANAR_COST;
shame += scale;
shame += animtex * ARC_ANIM_TEX_COST;
shame += alpha * ARC_ALPHA_COST;
shame += invisi * ARC_INVISI_COST;
// multiply shame by multipliers
if (hollow)
{
shame *= hollow * ARC_HOLLOW_MULT;
}
if (twist)
{
shame *= twist * ARC_TWIST_MULT;
}
if (circular_profile)
{
shame *= circular_profile * ARC_CIRC_PROF_MULT;
}
if (circular_path)
{
shame *= circular_path * ARC_CIRC_PATH_MULT;
}
if (glow)
{
shame *= glow * ARC_GLOW_MULT;
}
if (bump)
{
shame *= bump * ARC_BUMP_MULT;
}
if (flexi)
{
shame *= flexi * ARC_FLEXI_MULT;
}
if (shiny)
{
shame *= shiny * ARC_SHINY_MULT;
}
if (scale)
{
shame *= scale;
}
// add additional costs
shame += particles * ARC_PARTICLE_COST;
LLViewerObject::const_child_list_t& child_list = getChildren();
for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin();

View File

@ -120,7 +120,8 @@ public:
const LLMatrix4& getRelativeXform() const { return mRelativeXform; }
const LLMatrix3& getRelativeXformInvTrans() const { return mRelativeXformInvTrans; }
/*virtual*/ const LLMatrix4 getRenderMatrix() const;
U32 getRenderCost(std::set<LLUUID> &textures) const;
typedef std::map<LLUUID, S32> texture_cost_t;
U32 getRenderCost(texture_cost_t &textures) const;
/*virtual*/ BOOL lineSegmentIntersect(const LLVector3& start, const LLVector3& end,
S32 face = -1, // which face to check, -1 = ALL_SIDES
@ -330,8 +331,6 @@ public:
static LLPointer<LLObjectMediaDataClient> sObjectMediaClient;
static LLPointer<LLObjectMediaNavigateClient> sObjectMediaNavigateClient;
static const U32 ARC_TEXTURE_COST = 5;
protected:
static S32 sNumLODChanges;