Massive sunshine/viewer-dev catchup. Further implemented serverside baking and added/updated metrics feedback.
This commit is contained in:
@@ -150,6 +150,10 @@ BOOL LLTexLayerSetBuffer::renderTexLayerSet()
|
||||
gAlphaMaskProgram.bind();
|
||||
gAlphaMaskProgram.setMinimumAlpha(0.004f);
|
||||
}
|
||||
else
|
||||
{
|
||||
gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.00f);
|
||||
}
|
||||
|
||||
LLVertexBuffer::unbind();
|
||||
|
||||
@@ -928,7 +932,45 @@ LLWearableType::EType LLTexLayerInterface::getWearableType() const
|
||||
ETextureIndex te = getLocalTextureIndex();
|
||||
if (TEX_INVALID == te)
|
||||
{
|
||||
return LLWearableType::WT_INVALID;
|
||||
LLWearableType::EType type = LLWearableType::WT_INVALID;
|
||||
param_color_list_t::const_iterator color_iter = mParamColorList.begin();
|
||||
param_alpha_list_t::const_iterator alpha_iter = mParamAlphaList.begin();
|
||||
|
||||
for (; color_iter != mParamColorList.end(); color_iter++)
|
||||
{
|
||||
LLTexLayerParamColor* param = *color_iter;
|
||||
if (param)
|
||||
{
|
||||
LLWearableType::EType new_type = (LLWearableType::EType)param->getWearableType();
|
||||
if (new_type != LLWearableType::WT_INVALID && new_type != type)
|
||||
{
|
||||
if (type != LLWearableType::WT_INVALID)
|
||||
{
|
||||
return LLWearableType::WT_INVALID;
|
||||
}
|
||||
type = new_type;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (; alpha_iter != mParamAlphaList.end(); alpha_iter++)
|
||||
{
|
||||
LLTexLayerParamAlpha* param = *alpha_iter;
|
||||
if (param)
|
||||
{
|
||||
LLWearableType::EType new_type = (LLWearableType::EType)param->getWearableType();
|
||||
if (new_type != LLWearableType::WT_INVALID && new_type != type)
|
||||
{
|
||||
if (type != LLWearableType::WT_INVALID)
|
||||
{
|
||||
return LLWearableType::WT_INVALID;
|
||||
}
|
||||
type = new_type;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
return LLAvatarAppearanceDictionary::getTEWearableType(te);
|
||||
}
|
||||
@@ -1132,7 +1174,8 @@ BOOL LLTexLayer::render(S32 x, S32 y, S32 width, S32 height)
|
||||
}
|
||||
}//*/
|
||||
|
||||
renderMorphMasks(x, y, width, height, net_color);
|
||||
const bool force_render = true;
|
||||
renderMorphMasks(x, y, width, height, net_color, force_render);
|
||||
alpha_mask_specified = TRUE;
|
||||
gGL.flush();
|
||||
gGL.blendFunc(LLRender::BF_DEST_ALPHA, LLRender::BF_ONE_MINUS_DEST_ALPHA);
|
||||
@@ -1381,8 +1424,13 @@ BOOL LLTexLayer::blendAlphaTexture(S32 x, S32 y, S32 width, S32 height)
|
||||
}
|
||||
|
||||
static LLFastTimer::DeclareTimer FTM_RENDER_MORPH_MASKS("renderMorphMasks");
|
||||
BOOL LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLColor4 &layer_color)
|
||||
void LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLColor4 &layer_color, bool force_render)
|
||||
{
|
||||
if (!force_render && !hasMorph())
|
||||
{
|
||||
lldebugs << "skipping renderMorphMasks for " << getUUID() << llendl;
|
||||
return;
|
||||
}
|
||||
LLFastTimer t(FTM_RENDER_MORPH_MASKS);
|
||||
BOOL success = TRUE;
|
||||
|
||||
@@ -1419,6 +1467,11 @@ BOOL LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLC
|
||||
{
|
||||
LLTexLayerParamAlpha* param = *iter;
|
||||
success &= param->render( x, y, width, height );
|
||||
if (!success && !force_render)
|
||||
{
|
||||
lldebugs << "Failed to render param " << param->getID() << " ; skipping morph mask." << llendl;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Approximates a min() function
|
||||
@@ -1444,25 +1497,29 @@ BOOL LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLC
|
||||
}
|
||||
}
|
||||
|
||||
if( !getInfo()->mStaticImageFileName.empty() )
|
||||
if( !getInfo()->mStaticImageFileName.empty() && getInfo()->mStaticImageIsMask )
|
||||
{
|
||||
LLGLTexture* tex = LLTexLayerStaticImageList::getInstance()->getTexture(getInfo()->mStaticImageFileName, getInfo()->mStaticImageIsMask);
|
||||
if( tex )
|
||||
{
|
||||
if( (tex->getComponents() == 4) ||
|
||||
( (tex->getComponents() == 1) && getInfo()->mStaticImageIsMask ) )
|
||||
if( (tex->getComponents() == 4) || (tex->getComponents() == 1) )
|
||||
{
|
||||
LLGLSNoAlphaTest gls_no_alpha_test;
|
||||
gGL.getTexUnit(0)->bind(tex, TRUE);
|
||||
gl_rect_2d_simple_tex( width, height );
|
||||
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
|
||||
}
|
||||
else
|
||||
{
|
||||
llwarns << "Skipping rendering of " << getInfo()->mStaticImageFileName
|
||||
<< "; expected 1 or 4 components." << llendl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Draw a rectangle with the layer color to multiply the alpha by that color's alpha.
|
||||
// Note: we're still using gGL.blendFunc( GL_DST_ALPHA, GL_ZERO );
|
||||
if (layer_color.mV[VW] != 1.f)
|
||||
if ( !is_approx_equal(layer_color.mV[VW], 1.f) )
|
||||
{
|
||||
LLGLDisable no_alpha(GL_ALPHA_TEST);
|
||||
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
|
||||
@@ -1515,8 +1572,6 @@ BOOL LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLC
|
||||
mMorphMasksValid = TRUE;
|
||||
getTexLayerSet()->applyMorphMask(alpha_data, width, height, 1);
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
static LLFastTimer::DeclareTimer FTM_ADD_ALPHA_MASK("addAlphaMask");
|
||||
@@ -1531,7 +1586,8 @@ void LLTexLayer::addAlphaMask(U8 *data, S32 originX, S32 originY, S32 width, S32
|
||||
findNetColor( &net_color );
|
||||
// TODO: eliminate need for layer morph mask valid flag
|
||||
invalidateMorphMasks();
|
||||
renderMorphMasks(originX, originY, width, height, net_color);
|
||||
const bool force_render = false;
|
||||
renderMorphMasks(originX, originY, width, height, net_color, force_render);
|
||||
alphaData = getAlphaData();
|
||||
}
|
||||
if (alphaData)
|
||||
@@ -1540,7 +1596,7 @@ void LLTexLayer::addAlphaMask(U8 *data, S32 originX, S32 originY, S32 width, S32
|
||||
{
|
||||
U8 curAlpha = data[i];
|
||||
U16 resultAlpha = curAlpha;
|
||||
resultAlpha *= (alphaData[i] + 1);
|
||||
resultAlpha *= ( ((U16)alphaData[i]) + 1);
|
||||
resultAlpha = resultAlpha >> 8;
|
||||
data[i] = (U8)resultAlpha;
|
||||
}
|
||||
@@ -1915,9 +1971,15 @@ LLGLTexture* LLTexLayerStaticImageList::getTexture(const std::string& file_name,
|
||||
{
|
||||
if( (image_raw->getComponents() == 1) && is_mask )
|
||||
{
|
||||
// Note: these are static, unchanging images so it's ok to assume
|
||||
// that once an image is a mask it's always a mask.
|
||||
tex->setExplicitFormat( GL_ALPHA8, GL_ALPHA );
|
||||
// Convert grayscale alpha masks from single channel into RGBA.
|
||||
// Fill RGB with black to allow fixed function gl calls
|
||||
// to match shader implementation.
|
||||
LLPointer<LLImageRaw> alpha_image_raw = image_raw;
|
||||
image_raw = new LLImageRaw(image_raw->getWidth(),
|
||||
image_raw->getHeight(),
|
||||
4);
|
||||
|
||||
image_raw->copyUnscaledAlphaMask(alpha_image_raw, LLColor4U::black);
|
||||
}
|
||||
tex->createGLTexture(0, image_raw, 0, TRUE, LLGLTexture::LOCAL);
|
||||
|
||||
|
||||
@@ -160,7 +160,7 @@ public:
|
||||
BOOL findNetColor(LLColor4* color) const;
|
||||
/*virtual*/ BOOL blendAlphaTexture(S32 x, S32 y, S32 width, S32 height); // Multiplies a single alpha texture against the frame buffer
|
||||
/*virtual*/ void gatherAlphaMasks(U8 *data, S32 originX, S32 originY, S32 width, S32 height);
|
||||
BOOL renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLColor4 &layer_color);
|
||||
void renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLColor4 &layer_color, bool force_render);
|
||||
void addAlphaMask(U8 *data, S32 originX, S32 originY, S32 width, S32 height);
|
||||
/*virtual*/ BOOL isInvisibleAlphaMask() const;
|
||||
|
||||
|
||||
@@ -178,10 +178,6 @@ void LLTexLayerParamAlpha::setWeight(F32 weight, BOOL upload_bake)
|
||||
if ((mAvatarAppearance->getSex() & getSex()) &&
|
||||
(mAvatarAppearance->isSelf() && !mIsDummy)) // only trigger a baked texture update if we're changing a wearable's visual param.
|
||||
{
|
||||
if (mAvatarAppearance->isValid() && mAvatarAppearance->isEditingAppearance())
|
||||
{
|
||||
upload_bake = FALSE;
|
||||
}
|
||||
mAvatarAppearance->invalidateComposite(mTexLayer->getTexLayerSet(), upload_bake);
|
||||
mTexLayer->invalidateMorphMasks();
|
||||
}
|
||||
|
||||
@@ -95,7 +95,8 @@ void LLWearableData::setWearable(const LLWearableType::EType type, U32 index, LL
|
||||
}
|
||||
|
||||
U32 LLWearableData::pushWearable(const LLWearableType::EType type,
|
||||
LLWearable *wearable)
|
||||
LLWearable *wearable,
|
||||
bool trigger_updated /* = true */)
|
||||
{
|
||||
if (wearable == NULL)
|
||||
{
|
||||
@@ -121,8 +122,11 @@ U32 LLWearableData::pushWearable(const LLWearableType::EType type,
|
||||
mWearableDatas[type].push_back(wearable);
|
||||
idxWearable = mWearableDatas[type].size() - 1;
|
||||
}
|
||||
const BOOL removed = FALSE;
|
||||
wearableUpdated(wearable, removed);
|
||||
if (trigger_updated)
|
||||
{
|
||||
const BOOL removed = FALSE;
|
||||
wearableUpdated(wearable, removed);
|
||||
}
|
||||
return idxWearable;
|
||||
// [/RLVa:KB]
|
||||
}
|
||||
@@ -175,6 +179,17 @@ void LLWearableData::popWearable(const LLWearableType::EType type, U32 index)
|
||||
}
|
||||
}
|
||||
|
||||
void LLWearableData::clearWearableType(const LLWearableType::EType type)
|
||||
{
|
||||
wearableentry_map_t::iterator wearable_iter = mWearableDatas.find(type);
|
||||
if (wearable_iter == mWearableDatas.end())
|
||||
{
|
||||
return;
|
||||
}
|
||||
wearableentry_vec_t& wearable_vec = wearable_iter->second;
|
||||
wearable_vec.clear();
|
||||
}
|
||||
|
||||
bool LLWearableData::swapWearables(const LLWearableType::EType type, U32 index_a, U32 index_b)
|
||||
{
|
||||
wearableentry_map_t::iterator wearable_iter = mWearableDatas.find(type);
|
||||
|
||||
@@ -72,10 +72,12 @@ public:
|
||||
protected:
|
||||
// Low-level data structure setter - public access is via setWearableItem, etc.
|
||||
void setWearable(const LLWearableType::EType type, U32 index, LLWearable *wearable);
|
||||
U32 pushWearable(const LLWearableType::EType type, LLWearable *wearable);
|
||||
virtual void wearableUpdated(LLWearable *wearable, BOOL removed) = 0;
|
||||
U32 pushWearable(const LLWearableType::EType type, LLWearable *wearable,
|
||||
bool trigger_updated = true);
|
||||
virtual void wearableUpdated(LLWearable *wearable, BOOL removed);
|
||||
void popWearable(LLWearable *wearable);
|
||||
void popWearable(const LLWearableType::EType type, U32 index);
|
||||
void clearWearableType(const LLWearableType::EType type);
|
||||
bool swapWearables(const LLWearableType::EType type, U32 index_a, U32 index_b);
|
||||
|
||||
private:
|
||||
@@ -88,7 +90,7 @@ public:
|
||||
LLUUID computeBakedTextureHash(LLAvatarAppearanceDefines::EBakedTextureIndex baked_index,
|
||||
BOOL generate_valid_hash = TRUE);
|
||||
protected:
|
||||
virtual void invalidateBakedTextureHash(LLMD5& hash) const = 0;
|
||||
virtual void invalidateBakedTextureHash(LLMD5& hash) const {}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Member variables
|
||||
|
||||
@@ -127,30 +127,73 @@ BOOL LLHandMotion::onUpdate(F32 time, U8* joint_mask)
|
||||
mLastTime = time;
|
||||
|
||||
requestedHandPose = (eHandPose *)mCharacter->getAnimationData("Hand Pose");
|
||||
// <edit>
|
||||
if(requestedHandPose && *requestedHandPose >= NUM_HAND_POSES)
|
||||
{
|
||||
llwarns << "requested hand pose >= NUM_HAND_POSES" << llendl;
|
||||
requestedHandPose = &mCurrentPose;
|
||||
}
|
||||
// </edit>
|
||||
// check to see if requested pose has changed
|
||||
if (!requestedHandPose)
|
||||
{
|
||||
if (mNewPose != HAND_POSE_RELAXED && mNewPose != mCurrentPose)
|
||||
{
|
||||
mCharacter->setVisualParamWeight(gHandPoseNames[mNewPose], 0.f);
|
||||
// Only set param weight for poses other than
|
||||
// default (HAND_POSE_SPREAD); HAND_POSE_SPREAD
|
||||
// is not an animatable morph!
|
||||
if (mNewPose != HAND_POSE_SPREAD)
|
||||
{
|
||||
mCharacter->setVisualParamWeight(gHandPoseNames[mNewPose], 0.f);
|
||||
}
|
||||
|
||||
// Reset morph weight for current pose back to its
|
||||
// full extend or it might be stuck somewhere in the middle if a
|
||||
// pose is requested and the old pose is requested again shortly
|
||||
// after while still blending to the other pose!
|
||||
if (mCurrentPose != HAND_POSE_SPREAD)
|
||||
{
|
||||
mCharacter->setVisualParamWeight(gHandPoseNames[mCurrentPose], 1.f);
|
||||
}
|
||||
|
||||
// Update visual params now if we won't blend
|
||||
if (mCurrentPose == HAND_POSE_RELAXED)
|
||||
{
|
||||
mCharacter->updateVisualParams();
|
||||
}
|
||||
}
|
||||
mNewPose = HAND_POSE_RELAXED;
|
||||
}
|
||||
else
|
||||
{
|
||||
// this is a new morph we didn't know about before
|
||||
if (*requestedHandPose != mNewPose && mNewPose != mCurrentPose && mNewPose != HAND_POSE_SPREAD)
|
||||
// Sometimes we seem to get garbage here, with poses that are out of bounds.
|
||||
// So check for a valid pose first.
|
||||
if (*requestedHandPose >= 0 && *requestedHandPose < NUM_HAND_POSES)
|
||||
{
|
||||
mCharacter->setVisualParamWeight(gHandPoseNames[mNewPose], 0.f);
|
||||
// This is a new morph we didn't know about before:
|
||||
// Reset morph weight for both current and new pose
|
||||
// back their starting values while still blending.
|
||||
if (*requestedHandPose != mNewPose && mNewPose != mCurrentPose)
|
||||
{
|
||||
if (mNewPose != HAND_POSE_SPREAD)
|
||||
{
|
||||
mCharacter->setVisualParamWeight(gHandPoseNames[mNewPose], 0.f);
|
||||
}
|
||||
|
||||
// Reset morph weight for current pose back to its full extend
|
||||
// or it might be stuck somewhere in the middle if a pose is
|
||||
// requested and the old pose is requested again shortly after
|
||||
// while still blending to the other pose!
|
||||
if (mCurrentPose != HAND_POSE_SPREAD)
|
||||
{
|
||||
mCharacter->setVisualParamWeight(gHandPoseNames[mCurrentPose], 1.f);
|
||||
}
|
||||
|
||||
// Update visual params now if we won't blend
|
||||
if (mCurrentPose == *requestedHandPose)
|
||||
{
|
||||
mCharacter->updateVisualParams();
|
||||
}
|
||||
}
|
||||
mNewPose = *requestedHandPose;
|
||||
}
|
||||
else
|
||||
{
|
||||
llwarns << "Requested hand pose out of range. Ignoring requested pose." << llendl;
|
||||
}
|
||||
mNewPose = *requestedHandPose;
|
||||
}
|
||||
|
||||
mCharacter->removeAnimationData("Hand Pose");
|
||||
|
||||
@@ -50,6 +50,7 @@ const U32 MAX_MOTION_INSTANCES = 32;
|
||||
//-----------------------------------------------------------------------------
|
||||
// Constants and statics
|
||||
//-----------------------------------------------------------------------------
|
||||
F32 LLMotionController::sCurrentTimeFactor = 1.f;
|
||||
LLMotionRegistry LLMotionController::sRegistry;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -133,7 +134,7 @@ LLMotion *LLMotionRegistry::createMotion( const LLUUID &id )
|
||||
// Class Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
LLMotionController::LLMotionController()
|
||||
: mTimeFactor(1.f),
|
||||
: mTimeFactor(sCurrentTimeFactor),
|
||||
mCharacter(NULL),
|
||||
mAnimTime(0.f),
|
||||
mPrevTimerElapsed(0.f),
|
||||
|
||||
@@ -174,6 +174,9 @@ public:
|
||||
|
||||
const LLFrameTimer& getFrameTimer() { return mTimer; }
|
||||
|
||||
static F32 getCurrentTimeFactor() { return sCurrentTimeFactor; };
|
||||
static void setCurrentTimeFactor(F32 factor) { sCurrentTimeFactor = factor; };
|
||||
|
||||
protected:
|
||||
// internal operations act on motion instances directly
|
||||
// as there can be duplicate motions per id during blending overlap
|
||||
@@ -193,7 +196,8 @@ protected:
|
||||
void deactivateStoppedMotions();
|
||||
|
||||
protected:
|
||||
F32 mTimeFactor;
|
||||
F32 mTimeFactor; // 1.f for normal speed
|
||||
static F32 sCurrentTimeFactor; // Value to use for initialization
|
||||
static LLMotionRegistry sRegistry;
|
||||
LLPoseBlender mPoseBlender;
|
||||
|
||||
|
||||
@@ -67,15 +67,6 @@ const S32 LSL_PRIM_TEXGEN = 22;
|
||||
const S32 LSL_PRIM_POINT_LIGHT = 23;
|
||||
const S32 LSL_PRIM_CAST_SHADOWS = 24;
|
||||
const S32 LSL_PRIM_GLOW = 25;
|
||||
const S32 LSL_PRIM_TEXT = 26;
|
||||
const S32 LSL_PRIM_NAME = 27;
|
||||
const S32 LSL_PRIM_DESC = 28;
|
||||
const S32 LSL_PRIM_ROT_LOCAL = 29;
|
||||
const S32 LSL_PRIM_PHYSICS_SHAPE_TYPE = 30;
|
||||
const S32 LSL_PRIM_OMEGA = 32;
|
||||
const S32 LSL_PRIM_POS_LOCAL = 33;
|
||||
const S32 LSL_PRIM_LINK_TARGET = 34;
|
||||
const S32 LSL_PRIM_SLICE = 35;
|
||||
|
||||
const S32 LSL_PRIM_TYPE_BOX = 0;
|
||||
const S32 LSL_PRIM_TYPE_CYLINDER= 1;
|
||||
@@ -135,15 +126,6 @@ const S32 LSL_PRIM_SCULPT_TYPE_MASK = 7;
|
||||
const S32 LSL_PRIM_SCULPT_FLAG_INVERT = 64;
|
||||
const S32 LSL_PRIM_SCULPT_FLAG_MIRROR = 128;
|
||||
|
||||
const S32 LSL_PRIM_PHYSICS_SHAPE_PRIM = 0;
|
||||
const S32 LSL_PRIM_PHYSICS_SHAPE_NONE = 1;
|
||||
const S32 LSL_PRIM_PHYSICS_SHAPE_CONVEX = 2;
|
||||
|
||||
const S32 LSL_DENSITY = 1;
|
||||
const S32 LSL_FRICTION = 2;
|
||||
const S32 LSL_RESTITUTION = 4;
|
||||
const S32 LSL_GRAVITY_MULTIPLIER = 8;
|
||||
|
||||
const S32 LSL_ALL_SIDES = -1;
|
||||
const S32 LSL_LINK_ROOT = 1;
|
||||
const S32 LSL_LINK_FIRST_CHILD = 2;
|
||||
@@ -197,16 +179,8 @@ const S32 OBJECT_VELOCITY = 5;
|
||||
const S32 OBJECT_OWNER = 6;
|
||||
const S32 OBJECT_GROUP = 7;
|
||||
const S32 OBJECT_CREATOR = 8;
|
||||
const S32 OBJECT_RUNNING_SCRIPT_COUNT = 9;
|
||||
const S32 OBJECT_TOTAL_SCRIPT_COUNT = 10;
|
||||
const S32 OBJECT_SCRIPT_MEMORY = 11;
|
||||
const S32 OBJECT_SCRIPT_TIME = 12;
|
||||
const S32 OBJECT_PRIM_EQUIVALENCE = 13;
|
||||
const S32 OBJECT_SERVER_COST = 14;
|
||||
const S32 OBJECT_STREAMING_COST = 15;
|
||||
const S32 OBJECT_PHYSICS_COST = 16;
|
||||
|
||||
// llTextBox() magic token string - yes it's a hack.
|
||||
// llTextBox() magic token string - yes this is a hack. sue me.
|
||||
char const* const TEXTBOX_MAGIC_TOKEN = "!!llTextBox!!";
|
||||
|
||||
// changed() event flags
|
||||
@@ -236,155 +210,4 @@ const U32 LSL_STATUS_INTERNAL_ERROR = 1999;
|
||||
// Start per-function errors below, starting at 2000:
|
||||
const U32 LSL_STATUS_WHITELIST_FAILED = 2001;
|
||||
|
||||
// Memory profiling support
|
||||
const S32 LSL_PROFILE_SCRIPT_NONE = 0;
|
||||
const S32 LSL_PROFILE_SCRIPT_MEMORY = 1;
|
||||
|
||||
// HTTP responses contents type
|
||||
const S32 LSL_CONTENT_TYPE_TEXT = 0;
|
||||
const S32 LSL_CONTENT_TYPE_HTML = 1;
|
||||
|
||||
// Ray casting
|
||||
const S32 LSL_RCERR_UNKNOWN = -1;
|
||||
const S32 LSL_RCERR_SIM_PERF_LOW = -2;
|
||||
const S32 LSL_RCERR_CAST_TIME_EXCEEDED = -3;
|
||||
|
||||
const S32 LSL_RC_REJECT_TYPES = 0;
|
||||
const S32 LSL_RC_DETECT_PHANTOM = 1;
|
||||
const S32 LSL_RC_DATA_FLAGS = 2;
|
||||
const S32 LSL_RC_MAX_HITS = 3;
|
||||
|
||||
const S32 LSL_RC_REJECT_AGENTS = 1;
|
||||
const S32 LSL_RC_REJECT_PHYSICAL = 2;
|
||||
const S32 LSL_RC_REJECT_NONPHYSICAL = 4;
|
||||
const S32 LSL_RC_REJECT_LAND = 8;
|
||||
|
||||
const S32 LSL_RC_GET_NORMAL = 1;
|
||||
const S32 LSL_RC_GET_ROOT_KEY = 2;
|
||||
const S32 LSL_RC_GET_LINK_NUM = 4;
|
||||
|
||||
// Estate management
|
||||
const S32 LSL_ESTATE_ACCESS_ALLOWED_AGENT_ADD = 4;
|
||||
const S32 LSL_ESTATE_ACCESS_ALLOWED_AGENT_REMOVE = 8;
|
||||
const S32 LSL_ESTATE_ACCESS_ALLOWED_GROUP_ADD = 16;
|
||||
const S32 LSL_ESTATE_ACCESS_ALLOWED_GROUP_REMOVE = 32;
|
||||
const S32 LSL_ESTATE_ACCESS_BANNED_AGENT_ADD = 64;
|
||||
const S32 LSL_ESTATE_ACCESS_BANNED_AGENT_REMOVE = 128;
|
||||
|
||||
// Key Frame Motion:
|
||||
const S32 LSL_KFM_COMMAND = 0;
|
||||
const S32 LSL_KFM_MODE = 1;
|
||||
const S32 LSL_KFM_DATA = 2;
|
||||
const S32 LSL_KFM_FORWARD = 0;
|
||||
const S32 LSL_KFM_LOOP = 1;
|
||||
const S32 LSL_KFM_PING_PONG = 2;
|
||||
const S32 LSL_KFM_REVERSE = 3;
|
||||
const S32 LSL_KFM_ROTATION = 1;
|
||||
const S32 LSL_KFM_TRANSLATION = 2;
|
||||
const S32 LSL_KFM_CMD_PLAY = 0;
|
||||
const S32 LSL_KFM_CMD_STOP = 1;
|
||||
const S32 LSL_KFM_CMD_PAUSE = 2;
|
||||
|
||||
// Second Life Server/12 12.04.30.255166 constants for llGetAgentList
|
||||
const S32 AGENT_LIST_PARCEL = 1;
|
||||
const S32 AGENT_LIST_PARCEL_OWNER = 2;
|
||||
const S32 AGENT_LIST_REGION = 4;
|
||||
|
||||
|
||||
// --- SL Constants ABOVE this line ---
|
||||
// --- OpenSim / Aurora-Sim constants Below ---
|
||||
// OpenSim Constants (\OpenSim\Region\ScriptEngine\Shared\Api\Runtime\LSL_Constants.cs)
|
||||
// Constants for cmWindlight (\OpenSim\Region\ScriptEngine\Shared\Api\Runtime\CM_Constants.cs)
|
||||
const S32 CHANGED_ANIMATION = 16384;
|
||||
const S32 PARCEL_DETAILS_CLAIMDATE = 10; // used by OpenSim osSetParcelDetails
|
||||
const S32 STATS_TIME_DILATION = 0;
|
||||
const S32 STATS_SIM_FPS = 1;
|
||||
const S32 STATS_PHYSICS_FPS = 2;
|
||||
const S32 STATS_AGENT_UPDATES = 3;
|
||||
const S32 STATS_ROOT_AGENTS = 4;
|
||||
const S32 STATS_CHILD_AGENTS = 5;
|
||||
const S32 STATS_TOTAL_PRIMS = 6;
|
||||
const S32 STATS_ACTIVE_PRIMS = 7;
|
||||
const S32 STATS_FRAME_MS = 8;
|
||||
const S32 STATS_NET_MS = 9;
|
||||
const S32 STATS_PHYSICS_MS = 10;
|
||||
const S32 STATS_IMAGE_MS = 11;
|
||||
const S32 STATS_OTHER_MS = 12;
|
||||
const S32 STATS_IN_PACKETS_PER_SECOND = 13;
|
||||
const S32 STATS_OUT_PACKETS_PER_SECOND = 14;
|
||||
const S32 STATS_UNACKED_BYTES = 15;
|
||||
const S32 STATS_AGENT_MS = 16;
|
||||
const S32 STATS_PENDING_DOWNLOADS = 17;
|
||||
const S32 STATS_PENDING_UPLOADS = 18;
|
||||
const S32 STATS_ACTIVE_SCRIPTS = 19;
|
||||
const S32 STATS_SCRIPT_LPS = 20;
|
||||
// osNPC
|
||||
const S32 OS_NPC_FLY = 0;
|
||||
const S32 OS_NPC_NO_FLY = 1;
|
||||
const S32 OS_NPC_LAND_AT_TARGET = 2;
|
||||
const S32 OS_NPC_SIT_NOW = 0;
|
||||
const U32 OS_NPC_CREATOR_OWNED = 0x1;
|
||||
const U32 OS_NPC_NOT_OWNED = 0x2;
|
||||
const U32 OS_NPC_SENSE_AS_AGENT = 0x4;
|
||||
const U32 OS_NPC_RUNNING = 4;
|
||||
// Lightshare / Windlight
|
||||
const S32 WL_WATER_COLOR = 0;
|
||||
const S32 WL_WATER_FOG_DENSITY_EXPONENT = 1;
|
||||
const S32 WL_UNDERWATER_FOG_MODIFIER = 2;
|
||||
const S32 WL_REFLECTION_WAVELET_SCALE = 3;
|
||||
const S32 WL_FRESNEL_SCALE = 4;
|
||||
const S32 WL_FRESNEL_OFFSET = 5;
|
||||
const S32 WL_REFRACT_SCALE_ABOVE = 6;
|
||||
const S32 WL_REFRACT_SCALE_BELOW = 7;
|
||||
const S32 WL_BLUR_MULTIPLIER = 8;
|
||||
const S32 WL_BIG_WAVE_DIRECTION = 9;
|
||||
const S32 WL_LITTLE_WAVE_DIRECTION = 10;
|
||||
const S32 WL_NORMAL_MAP_TEXTURE = 11;
|
||||
const S32 WL_HORIZON = 12;
|
||||
const S32 WL_HAZE_HORIZON = 13;
|
||||
const S32 WL_BLUE_DENSITY = 14;
|
||||
const S32 WL_HAZE_DENSITY = 15;
|
||||
const S32 WL_DENSITY_MULTIPLIER = 16;
|
||||
const S32 WL_DISTANCE_MULTIPLIER = 17;
|
||||
const S32 WL_MAX_ALTITUDE = 18;
|
||||
const S32 WL_SUN_MOON_COLOR = 19;
|
||||
const S32 WL_AMBIENT = 20;
|
||||
const S32 WL_EAST_ANGLE = 21;
|
||||
const S32 WL_SUN_GLOW_FOCUS = 22;
|
||||
const S32 WL_SUN_GLOW_SIZE = 23;
|
||||
const S32 WL_SCENE_GAMMA = 24;
|
||||
const S32 WL_STAR_BRIGHTNESS = 25;
|
||||
const S32 WL_CLOUD_COLOR = 26;
|
||||
const S32 WL_CLOUD_XY_DENSITY = 27;
|
||||
const S32 WL_CLOUD_COVERAGE = 28;
|
||||
const S32 WL_CLOUD_SCALE = 29;
|
||||
const S32 WL_CLOUD_DETAIL_XY_DENSITY = 30;
|
||||
const S32 WL_CLOUD_SCROLL_X = 31;
|
||||
const S32 WL_CLOUD_SCROLL_Y = 32;
|
||||
const S32 WL_CLOUD_SCROLL_Y_LOCK = 33;
|
||||
const S32 WL_CLOUD_SCROLL_X_LOCK = 34;
|
||||
const S32 WL_DRAW_CLASSIC_CLOUDS = 35;
|
||||
const S32 WL_SUN_MOON_POSITION = 36;
|
||||
// Aurora-Sim Constants (\Aurora\AuroraDotNetEngine\APIs\AA_Constants.cs) -->
|
||||
const S32 BOT_FOLLOW_FLAG_NONE = 0;
|
||||
const S32 BOT_FOLLOW_FLAG_INDEFINITELY = 1;
|
||||
const S32 BOT_FOLLOW_WALK = 0;
|
||||
const S32 BOT_FOLLOW_RUN = 1;
|
||||
const S32 BOT_FOLLOW_FLY = 2;
|
||||
const S32 BOT_FOLLOW_TELEPORT = 3;
|
||||
const S32 BOT_FOLLOW_WAIT = 4;
|
||||
const S32 BOT_FOLLOW_TRIGGER_HERE_EVENT = 1;
|
||||
const S32 BOT_FOLLOW_FLAG_FORCEDIRECTPATH = 4;
|
||||
// string constants from Aurora-Sim
|
||||
char const* const ENABLE_GRAVITY = "enable_gravity";
|
||||
char const* const GRAVITY_FORCE_X = "gravity_force_x";
|
||||
char const* const GRAVITY_FORCE_Y = "gravity_force_y";
|
||||
char const* const GRAVITY_FORCE_Z = "gravity_force_z";
|
||||
char const* const ADD_GRAVITY_POINT = "add_gravity_point";
|
||||
char const* const ADD_GRAVITY_FORCE = "add_gravity_force";
|
||||
char const* const START_TIME_REVERSAL_SAVING = "start_time_reversal_saving";
|
||||
char const* const STOP_TIME_REVERSAL_SAVING = "stop_time_reversal_saving";
|
||||
char const* const START_TIME_REVERSAL = "start_time_reversal";
|
||||
char const* const STOP_TIME_REVERSAL = "stop_time_reversal";
|
||||
|
||||
#endif
|
||||
|
||||
@@ -725,6 +725,29 @@ void LLImageRaw::compositeUnscaled4onto3( LLImageRaw* src )
|
||||
}
|
||||
}
|
||||
|
||||
void LLImageRaw::copyUnscaledAlphaMask( LLImageRaw* src, const LLColor4U& fill)
|
||||
{
|
||||
LLImageRaw* dst = this; // Just for clarity.
|
||||
|
||||
llassert( 1 == src->getComponents() );
|
||||
llassert( 4 == dst->getComponents() );
|
||||
llassert( (src->getWidth() == dst->getWidth()) && (src->getHeight() == dst->getHeight()) );
|
||||
|
||||
S32 pixels = getWidth() * getHeight();
|
||||
U8* src_data = src->getData();
|
||||
U8* dst_data = dst->getData();
|
||||
for ( S32 i = 0; i < pixels; i++ )
|
||||
{
|
||||
dst_data[0] = fill.mV[0];
|
||||
dst_data[1] = fill.mV[1];
|
||||
dst_data[2] = fill.mV[2];
|
||||
dst_data[3] = src_data[0];
|
||||
src_data += 1;
|
||||
dst_data += 4;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Fill the buffer with a constant color
|
||||
void LLImageRaw::fill( const LLColor4U& color )
|
||||
{
|
||||
|
||||
@@ -219,6 +219,11 @@ public:
|
||||
// Src and dst are same size. Src has 3 components. Dst has 4 components.
|
||||
void copyUnscaled3onto4( LLImageRaw* src );
|
||||
|
||||
// Src and dst are same size. Src has 1 component. Dst has 4 components.
|
||||
// Alpha component is set to source alpha mask component.
|
||||
// RGB components are set to fill color.
|
||||
void copyUnscaledAlphaMask( LLImageRaw* src, const LLColor4U& fill);
|
||||
|
||||
// Src and dst can be any size. Src and dst have same number of components.
|
||||
void copyScaled( LLImageRaw* src );
|
||||
|
||||
|
||||
@@ -342,15 +342,6 @@ void LLInventoryItem::copyItem(const LLInventoryItem* other)
|
||||
mCreationDate = other->mCreationDate;
|
||||
}
|
||||
|
||||
// As a constructor alternative, the clone() method works like a
|
||||
// copy constructor, but gens a new UUID.
|
||||
void LLInventoryItem::cloneItem(LLPointer<LLInventoryItem>& newitem) const
|
||||
{
|
||||
newitem = new LLInventoryItem;
|
||||
newitem->copyItem(this);
|
||||
newitem->mUUID.generate();
|
||||
}
|
||||
|
||||
// If this is a linked item, then the UUID of the base object is
|
||||
// this item's assetID.
|
||||
// virtual
|
||||
@@ -390,6 +381,11 @@ const std::string& LLInventoryItem::getDescription() const
|
||||
return mDescription;
|
||||
}
|
||||
|
||||
const std::string& LLInventoryItem::getActualDescription() const
|
||||
{
|
||||
return mDescription;
|
||||
}
|
||||
|
||||
time_t LLInventoryItem::getCreationDate() const
|
||||
{
|
||||
return mCreationDate;
|
||||
@@ -1632,36 +1628,6 @@ LLSD ll_create_sd_from_inventory_item(LLPointer<LLInventoryItem> item)
|
||||
return rv;
|
||||
}
|
||||
|
||||
LLPointer<LLInventoryItem> ll_create_item_from_sd(const LLSD& sd_item)
|
||||
{
|
||||
LLPointer<LLInventoryItem> rv = new LLInventoryItem;
|
||||
rv->setUUID(sd_item[INV_ITEM_ID_LABEL].asUUID());
|
||||
rv->setParent(sd_item[INV_PARENT_ID_LABEL].asUUID());
|
||||
rv->rename(sd_item[INV_NAME_LABEL].asString());
|
||||
rv->setType(
|
||||
LLAssetType::lookup(sd_item[INV_ASSET_TYPE_LABEL].asString()));
|
||||
if (sd_item.has("shadow_id"))
|
||||
{
|
||||
LLUUID asset_id = sd_item["shadow_id"];
|
||||
LLXORCipher cipher(MAGIC_ID.mData, UUID_BYTES);
|
||||
cipher.decrypt(asset_id.mData, UUID_BYTES);
|
||||
rv->setAssetUUID(asset_id);
|
||||
}
|
||||
if (sd_item.has(INV_ASSET_ID_LABEL))
|
||||
{
|
||||
rv->setAssetUUID(sd_item[INV_ASSET_ID_LABEL].asUUID());
|
||||
}
|
||||
rv->setDescription(sd_item[INV_DESC_LABEL].asString());
|
||||
rv->setSaleInfo(ll_sale_info_from_sd(sd_item[INV_SALE_INFO_LABEL]));
|
||||
rv->setPermissions(ll_permissions_from_sd(sd_item[INV_PERMISSIONS_LABEL]));
|
||||
rv->setInventoryType(
|
||||
LLInventoryType::lookup(
|
||||
sd_item[INV_INVENTORY_TYPE_LABEL].asString()));
|
||||
rv->setFlags((U32)(sd_item[INV_FLAGS_LABEL].asInteger()));
|
||||
rv->setCreationDate(sd_item[INV_CREATION_DATE_LABEL].asInteger());
|
||||
return rv;
|
||||
}
|
||||
|
||||
LLSD ll_create_sd_from_inventory_category(LLPointer<LLInventoryCategory> cat)
|
||||
{
|
||||
LLSD rv;
|
||||
|
||||
@@ -54,7 +54,6 @@ public:
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------
|
||||
public:
|
||||
MEM_TYPE_NEW(LLMemType::MTYPE_INVENTORY);
|
||||
LLInventoryObject();
|
||||
LLInventoryObject(const LLUUID& uuid,
|
||||
const LLUUID& parent_uuid,
|
||||
@@ -129,7 +128,6 @@ public:
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------
|
||||
public:
|
||||
MEM_TYPE_NEW(LLMemType::MTYPE_INVENTORY);
|
||||
LLInventoryItem(const LLUUID& uuid,
|
||||
const LLUUID& parent_uuid,
|
||||
const LLPermissions& permissions,
|
||||
@@ -148,11 +146,6 @@ public:
|
||||
LLInventoryItem(const LLInventoryItem* other);
|
||||
virtual void copyItem(const LLInventoryItem* other); // LLRefCount requires custom copy
|
||||
void generateUUID() { mUUID.generate(); }
|
||||
|
||||
// As a constructor alternative, the clone() method works like a
|
||||
// copy constructor, but gens a new UUID.
|
||||
// It is up to the caller to delete (unref) the item.
|
||||
virtual void cloneItem(LLPointer<LLInventoryItem>& newitem) const;
|
||||
protected:
|
||||
~LLInventoryItem(); // ref counted
|
||||
|
||||
@@ -165,6 +158,7 @@ public:
|
||||
virtual const LLUUID& getCreatorUUID() const;
|
||||
virtual const LLUUID& getAssetUUID() const;
|
||||
virtual const std::string& getDescription() const;
|
||||
virtual const std::string& getActualDescription() const; // Does not follow links
|
||||
virtual const LLSaleInfo& getSaleInfo() const;
|
||||
virtual LLInventoryType::EType getInventoryType() const;
|
||||
virtual U32 getFlags() const;
|
||||
@@ -247,7 +241,6 @@ public:
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------
|
||||
public:
|
||||
MEM_TYPE_NEW(LLMemType::MTYPE_INVENTORY);
|
||||
LLInventoryCategory(const LLUUID& uuid, const LLUUID& parent_uuid,
|
||||
LLFolderType::EType preferred_type,
|
||||
const std::string& name);
|
||||
@@ -297,7 +290,6 @@ protected:
|
||||
// item, appropriate for serialization.
|
||||
//-----------------------------------------------------------------------------
|
||||
LLSD ll_create_sd_from_inventory_item(LLPointer<LLInventoryItem> item);
|
||||
LLPointer<LLInventoryItem> ll_create_item_from_sd(const LLSD& sd_item);
|
||||
LLSD ll_create_sd_from_inventory_category(LLPointer<LLInventoryCategory> cat);
|
||||
LLPointer<LLInventoryCategory> ll_create_category_from_sd(const LLSD& sd_cat);
|
||||
|
||||
|
||||
@@ -206,7 +206,7 @@ void LLParcel::init(const LLUUID &owner_id,
|
||||
mAABBMin.setVec(SOME_BIG_NUMBER, SOME_BIG_NUMBER, SOME_BIG_NUMBER);
|
||||
mAABBMax.setVec(SOME_BIG_NEG_NUMBER, SOME_BIG_NEG_NUMBER, SOME_BIG_NEG_NUMBER);
|
||||
|
||||
mLocalID = 0;
|
||||
mLocalID = INVALID_PARCEL_ID;
|
||||
|
||||
//mSimWidePrimCorrection = 0;
|
||||
setMaxPrimCapacity((S32)(sim_object_limit * area / (F32)(REGION_WIDTH_METERS * REGION_WIDTH_METERS)));
|
||||
|
||||
@@ -103,6 +103,7 @@ const U32 RT_OTHER = 0x1 << 3;
|
||||
const U32 RT_LIST = 0x1 << 4;
|
||||
const U32 RT_SELL = 0x1 << 5;
|
||||
|
||||
const S32 INVALID_PARCEL_ID = -1;
|
||||
|
||||
// Timeouts for parcels
|
||||
// default is 21 days * 24h/d * 60m/h * 60s/m *1000000 usec/s = 1814400000000
|
||||
|
||||
@@ -745,7 +745,7 @@ public:
|
||||
}
|
||||
|
||||
//node is now root
|
||||
llwarns << "!!! OCTREE REMOVING FACE BY ADDRESS, SEVERE PERFORMANCE PENALTY |||" << llendl;
|
||||
llwarns << "!!! OCTREE REMOVING ELEMENT BY ADDRESS, SEVERE PERFORMANCE PENALTY |||" << llendl;
|
||||
node->removeByAddress(data);
|
||||
llassert(data->getBinIndex() == -1);
|
||||
return true;
|
||||
|
||||
@@ -4830,237 +4830,6 @@ BOOL equalTriangle(const S32 *a, const S32 *b)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL LLVolume::cleanupTriangleData( const S32 num_input_vertices,
|
||||
const std::vector<Point>& input_vertices,
|
||||
const S32 num_input_triangles,
|
||||
S32 *input_triangles,
|
||||
S32 &num_output_vertices,
|
||||
LLVector3 **output_vertices,
|
||||
S32 &num_output_triangles,
|
||||
S32 **output_triangles)
|
||||
{
|
||||
LLMemType m1(LLMemType::MTYPE_VOLUME);
|
||||
|
||||
/* Testing: avoid any cleanup
|
||||
static BOOL skip_cleanup = TRUE;
|
||||
if ( skip_cleanup )
|
||||
{
|
||||
num_output_vertices = num_input_vertices;
|
||||
num_output_triangles = num_input_triangles;
|
||||
|
||||
*output_vertices = new LLVector3[num_input_vertices];
|
||||
for (S32 index = 0; index < num_input_vertices; index++)
|
||||
{
|
||||
(*output_vertices)[index] = input_vertices[index].mPos;
|
||||
}
|
||||
|
||||
*output_triangles = new S32[num_input_triangles*3];
|
||||
memcpy(*output_triangles, input_triangles, 3*num_input_triangles*sizeof(S32)); // Flawfinder: ignore
|
||||
return TRUE;
|
||||
}
|
||||
*/
|
||||
|
||||
// Here's how we do this:
|
||||
// Create a structure which contains the original vertex index and the
|
||||
// LLVector3 data.
|
||||
// "Sort" the data by the vectors
|
||||
// Create an array the size of the old vertex list, with a mapping of
|
||||
// old indices to new indices.
|
||||
// Go through triangles, shift so the lowest index is first
|
||||
// Sort triangles by first index
|
||||
// Remove duplicate triangles
|
||||
// Allocate and pack new triangle data.
|
||||
|
||||
//LLTimer cleanupTimer;
|
||||
//llinfos << "In vertices: " << num_input_vertices << llendl;
|
||||
//llinfos << "In triangles: " << num_input_triangles << llendl;
|
||||
|
||||
S32 i;
|
||||
typedef std::multiset<LLVertexIndexPair*, lessVertex> vertex_set_t;
|
||||
vertex_set_t vertex_list;
|
||||
|
||||
LLVertexIndexPair *pairp = NULL;
|
||||
for (i = 0; i < num_input_vertices; i++)
|
||||
{
|
||||
LLVertexIndexPair *new_pairp = new LLVertexIndexPair(input_vertices[i].mPos, i);
|
||||
vertex_list.insert(new_pairp);
|
||||
}
|
||||
|
||||
// Generate the vertex mapping and the list of vertices without
|
||||
// duplicates. This will crash if there are no vertices.
|
||||
llassert(num_input_vertices > 0); // check for no vertices!
|
||||
S32 *vertex_mapping = new S32[num_input_vertices];
|
||||
LLVector3 *new_vertices = new LLVector3[num_input_vertices];
|
||||
LLVertexIndexPair *prev_pairp = NULL;
|
||||
|
||||
S32 new_num_vertices;
|
||||
|
||||
new_num_vertices = 0;
|
||||
for (vertex_set_t::iterator iter = vertex_list.begin(),
|
||||
end = vertex_list.end();
|
||||
iter != end; iter++)
|
||||
{
|
||||
pairp = *iter;
|
||||
if (!prev_pairp || ((pairp->mVertex - prev_pairp->mVertex).magVecSquared() >= VERTEX_SLOP_SQRD))
|
||||
{
|
||||
new_vertices[new_num_vertices] = pairp->mVertex;
|
||||
//llinfos << "Added vertex " << new_num_vertices << " : " << pairp->mVertex << llendl;
|
||||
new_num_vertices++;
|
||||
// Update the previous
|
||||
prev_pairp = pairp;
|
||||
}
|
||||
else
|
||||
{
|
||||
//llinfos << "Removed duplicate vertex " << pairp->mVertex << ", distance magVecSquared() is " << (pairp->mVertex - prev_pairp->mVertex).magVecSquared() << llendl;
|
||||
}
|
||||
vertex_mapping[pairp->mIndex] = new_num_vertices - 1;
|
||||
}
|
||||
|
||||
// Iterate through triangles and remove degenerates, re-ordering vertices
|
||||
// along the way.
|
||||
S32 *new_triangles = new S32[num_input_triangles * 3];
|
||||
S32 new_num_triangles = 0;
|
||||
|
||||
for (i = 0; i < num_input_triangles; i++)
|
||||
{
|
||||
S32 v1 = i*3;
|
||||
S32 v2 = v1 + 1;
|
||||
S32 v3 = v1 + 2;
|
||||
|
||||
//llinfos << "Checking triangle " << input_triangles[v1] << ":" << input_triangles[v2] << ":" << input_triangles[v3] << llendl;
|
||||
input_triangles[v1] = vertex_mapping[input_triangles[v1]];
|
||||
input_triangles[v2] = vertex_mapping[input_triangles[v2]];
|
||||
input_triangles[v3] = vertex_mapping[input_triangles[v3]];
|
||||
|
||||
if ((input_triangles[v1] == input_triangles[v2])
|
||||
|| (input_triangles[v1] == input_triangles[v3])
|
||||
|| (input_triangles[v2] == input_triangles[v3]))
|
||||
{
|
||||
//llinfos << "Removing degenerate triangle " << input_triangles[v1] << ":" << input_triangles[v2] << ":" << input_triangles[v3] << llendl;
|
||||
// Degenerate triangle, skip
|
||||
continue;
|
||||
}
|
||||
|
||||
if (input_triangles[v1] < input_triangles[v2])
|
||||
{
|
||||
if (input_triangles[v1] < input_triangles[v3])
|
||||
{
|
||||
// (0 < 1) && (0 < 2)
|
||||
new_triangles[new_num_triangles*3] = input_triangles[v1];
|
||||
new_triangles[new_num_triangles*3+1] = input_triangles[v2];
|
||||
new_triangles[new_num_triangles*3+2] = input_triangles[v3];
|
||||
}
|
||||
else
|
||||
{
|
||||
// (0 < 1) && (2 < 0)
|
||||
new_triangles[new_num_triangles*3] = input_triangles[v3];
|
||||
new_triangles[new_num_triangles*3+1] = input_triangles[v1];
|
||||
new_triangles[new_num_triangles*3+2] = input_triangles[v2];
|
||||
}
|
||||
}
|
||||
else if (input_triangles[v2] < input_triangles[v3])
|
||||
{
|
||||
// (1 < 0) && (1 < 2)
|
||||
new_triangles[new_num_triangles*3] = input_triangles[v2];
|
||||
new_triangles[new_num_triangles*3+1] = input_triangles[v3];
|
||||
new_triangles[new_num_triangles*3+2] = input_triangles[v1];
|
||||
}
|
||||
else
|
||||
{
|
||||
// (1 < 0) && (2 < 1)
|
||||
new_triangles[new_num_triangles*3] = input_triangles[v3];
|
||||
new_triangles[new_num_triangles*3+1] = input_triangles[v1];
|
||||
new_triangles[new_num_triangles*3+2] = input_triangles[v2];
|
||||
}
|
||||
new_num_triangles++;
|
||||
}
|
||||
|
||||
if (new_num_triangles == 0)
|
||||
{
|
||||
llwarns << "Created volume object with 0 faces." << llendl;
|
||||
delete[] new_triangles;
|
||||
delete[] vertex_mapping;
|
||||
delete[] new_vertices;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
typedef std::set<S32*, lessTriangle> triangle_set_t;
|
||||
triangle_set_t triangle_list;
|
||||
|
||||
for (i = 0; i < new_num_triangles; i++)
|
||||
{
|
||||
triangle_list.insert(&new_triangles[i*3]);
|
||||
}
|
||||
|
||||
// Sort through the triangle list, and delete duplicates
|
||||
|
||||
S32 *prevp = NULL;
|
||||
S32 *curp = NULL;
|
||||
|
||||
S32 *sorted_tris = new S32[new_num_triangles*3];
|
||||
S32 cur_tri = 0;
|
||||
for (triangle_set_t::iterator iter = triangle_list.begin(),
|
||||
end = triangle_list.end();
|
||||
iter != end; iter++)
|
||||
{
|
||||
curp = *iter;
|
||||
if (!prevp || !equalTriangle(prevp, curp))
|
||||
{
|
||||
//llinfos << "Added triangle " << *curp << ":" << *(curp+1) << ":" << *(curp+2) << llendl;
|
||||
sorted_tris[cur_tri*3] = *curp;
|
||||
sorted_tris[cur_tri*3+1] = *(curp+1);
|
||||
sorted_tris[cur_tri*3+2] = *(curp+2);
|
||||
cur_tri++;
|
||||
prevp = curp;
|
||||
}
|
||||
else
|
||||
{
|
||||
//llinfos << "Skipped triangle " << *curp << ":" << *(curp+1) << ":" << *(curp+2) << llendl;
|
||||
}
|
||||
}
|
||||
|
||||
*output_vertices = new LLVector3[new_num_vertices];
|
||||
num_output_vertices = new_num_vertices;
|
||||
for (i = 0; i < new_num_vertices; i++)
|
||||
{
|
||||
(*output_vertices)[i] = new_vertices[i];
|
||||
}
|
||||
|
||||
*output_triangles = new S32[cur_tri*3];
|
||||
num_output_triangles = cur_tri;
|
||||
memcpy(*output_triangles, sorted_tris, 3*cur_tri*sizeof(S32)); /* Flawfinder: ignore */
|
||||
|
||||
/*
|
||||
llinfos << "Out vertices: " << num_output_vertices << llendl;
|
||||
llinfos << "Out triangles: " << num_output_triangles << llendl;
|
||||
for (i = 0; i < num_output_vertices; i++)
|
||||
{
|
||||
llinfos << i << ":" << (*output_vertices)[i] << llendl;
|
||||
}
|
||||
for (i = 0; i < num_output_triangles; i++)
|
||||
{
|
||||
llinfos << i << ":" << (*output_triangles)[i*3] << ":" << (*output_triangles)[i*3+1] << ":" << (*output_triangles)[i*3+2] << llendl;
|
||||
}
|
||||
*/
|
||||
|
||||
//llinfos << "Out vertices: " << num_output_vertices << llendl;
|
||||
//llinfos << "Out triangles: " << num_output_triangles << llendl;
|
||||
delete[] vertex_mapping;
|
||||
vertex_mapping = NULL;
|
||||
delete[] new_vertices;
|
||||
new_vertices = NULL;
|
||||
delete[] new_triangles;
|
||||
new_triangles = NULL;
|
||||
delete[] sorted_tris;
|
||||
sorted_tris = NULL;
|
||||
triangle_list.clear();
|
||||
std::for_each(vertex_list.begin(), vertex_list.end(), DeletePointer());
|
||||
vertex_list.clear();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
BOOL LLVolumeParams::importFile(LLFILE *fp)
|
||||
{
|
||||
LLMemType m1(LLMemType::MTYPE_VOLUME);
|
||||
@@ -6385,12 +6154,7 @@ BOOL LLVolumeFace::createUnCutCubeCap(LLVolume* volume, BOOL partial_build)
|
||||
S32 max_t = volume->getPath().mPath.size();
|
||||
|
||||
// S32 i;
|
||||
S32 num_vertices = 0, num_indices = 0;
|
||||
S32 grid_size = (profile.size()-1)/4;
|
||||
S32 quad_count = (grid_size * grid_size);
|
||||
|
||||
num_vertices = (grid_size+1)*(grid_size+1);
|
||||
num_indices = quad_count * 4;
|
||||
|
||||
LLVector4a& min = mExtents[0];
|
||||
LLVector4a& max = mExtents[1];
|
||||
|
||||
@@ -1025,17 +1025,6 @@ public:
|
||||
LLVector3* normal = NULL,
|
||||
LLVector3* bi_normal = NULL);
|
||||
|
||||
// The following cleans up vertices and triangles,
|
||||
// getting rid of degenerate triangles and duplicate vertices,
|
||||
// and allocates new arrays with the clean data.
|
||||
static BOOL cleanupTriangleData( const S32 num_input_vertices,
|
||||
const std::vector<Point> &input_vertices,
|
||||
const S32 num_input_triangles,
|
||||
S32 *input_triangles,
|
||||
S32 &num_output_vertices,
|
||||
LLVector3 **output_vertices,
|
||||
S32 &num_output_triangles,
|
||||
S32 **output_triangles);
|
||||
LLFaceID generateFaceMask();
|
||||
|
||||
BOOL isFaceMaskValid(LLFaceID face_mask);
|
||||
|
||||
@@ -824,7 +824,9 @@ AIHTTPTimeoutPolicy const* AIHTTPTimeoutPolicy::getTimeoutPolicyByName(std::stri
|
||||
// Policy name Policy
|
||||
P(accountingCostResponder);
|
||||
P(agentStateResponder);
|
||||
P(appearanceChangeMetricsResponder);
|
||||
P(assetUploadResponder);
|
||||
P(assetReportHandler);
|
||||
P(asyncConsoleResponder);
|
||||
P(avatarPickerResponder);
|
||||
P(authHandler);
|
||||
|
||||
@@ -886,8 +886,17 @@ void LLXferManager::processFileRequest (LLMessageSystem *mesgsys, void ** /*user
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
std::string expanded_filename = gDirUtilp->getExpandedFilename( local_path, local_filename );
|
||||
// If we want to use a special path (e.g. LL_PATH_CACHE), we want to make sure we create the
|
||||
// proper expanded filename.
|
||||
std::string expanded_filename;
|
||||
if (local_path != LL_PATH_NONE)
|
||||
{
|
||||
expanded_filename = gDirUtilp->getExpandedFilename( local_path, local_filename );
|
||||
}
|
||||
else
|
||||
{
|
||||
expanded_filename = local_filename;
|
||||
}
|
||||
llinfos << "starting file transfer: " << expanded_filename << " to " << mesgsys->getSender() << llendl;
|
||||
|
||||
BOOL delete_local_on_completion = FALSE;
|
||||
|
||||
@@ -79,6 +79,15 @@ public:
|
||||
MAX_GL_IMAGE_CATEGORY
|
||||
};
|
||||
|
||||
typedef enum
|
||||
{
|
||||
DELETED = 0, //removed from memory
|
||||
DELETION_CANDIDATE, //ready to be removed from memory
|
||||
INACTIVE, //not be used for the last certain period (i.e., 30 seconds).
|
||||
ACTIVE, //just being used, can become inactive if not being used for a certain time (10 seconds).
|
||||
NO_DELETE = 99 //stay in memory, can not be removed.
|
||||
} LLGLTextureState;
|
||||
|
||||
static S32 getTotalNumOfCategories() ;
|
||||
static S32 getIndexFromCategory(S32 category) ;
|
||||
static S32 getCategoryFromIndex(S32 index) ;
|
||||
@@ -143,6 +152,8 @@ public:
|
||||
U32 getTexelsInGLTexture() const ;
|
||||
BOOL isGLTextureCreated() const ;
|
||||
S32 getDiscardLevelInAtlas() const ;*/
|
||||
LLGLTextureState getTextureState() const { return mTextureState; }
|
||||
|
||||
//---------------------------------------------------------------------------------------------
|
||||
//end of functions to access LLImageGL
|
||||
//---------------------------------------------------------------------------------------------
|
||||
@@ -179,14 +190,6 @@ protected:
|
||||
S8 mDontDiscard; // Keep full res version of this image (for UI, etc)
|
||||
|
||||
protected:
|
||||
typedef enum
|
||||
{
|
||||
DELETED = 0, //removed from memory
|
||||
DELETION_CANDIDATE, //ready to be removed from memory
|
||||
INACTIVE, //not be used for the last certain period (i.e., 30 seconds).
|
||||
ACTIVE, //just being used, can become inactive if not being used for a certain time (10 seconds).
|
||||
NO_DELETE = 99 //stay in memory, can not be removed.
|
||||
} LLGLTextureState;
|
||||
LLGLTextureState mTextureState ;
|
||||
|
||||
|
||||
|
||||
@@ -467,6 +467,7 @@ set(viewer_SOURCE_FILES
|
||||
llvectorperfoptions.cpp
|
||||
llvelocitybar.cpp
|
||||
llviewchildren.cpp
|
||||
llviewerassetstats.cpp
|
||||
llviewerassetstorage.cpp
|
||||
llviewerassettype.cpp
|
||||
llvieweraudio.cpp
|
||||
@@ -917,6 +918,7 @@ set(viewer_HEADER_FILES
|
||||
llscrollingpanelparam.h
|
||||
llscrollingpanelparambase.h
|
||||
llselectmgr.h
|
||||
llsimplestat.h
|
||||
llsky.h
|
||||
llspatialpartition.h
|
||||
llsprite.h
|
||||
@@ -972,6 +974,7 @@ set(viewer_HEADER_FILES
|
||||
llvectorperfoptions.h
|
||||
llvelocitybar.h
|
||||
llviewchildren.h
|
||||
llviewerassetstats.h
|
||||
llviewerassetstorage.h
|
||||
llviewerassettype.h
|
||||
llvieweraudio.h
|
||||
|
||||
@@ -26,22 +26,26 @@
|
||||
|
||||
ATTRIBUTE vec4 weight4;
|
||||
|
||||
uniform mat4 matrixPalette[32];
|
||||
uniform mat4 matrixPalette[64];
|
||||
|
||||
mat4 getObjectSkinnedTransform()
|
||||
{
|
||||
int i;
|
||||
float w0 = fract(weight4.x);
|
||||
float w1 = fract(weight4.y);
|
||||
float w2 = fract(weight4.z);
|
||||
float w3 = fract(weight4.w);
|
||||
|
||||
vec4 w = fract(weight4);
|
||||
vec4 index = floor(weight4);
|
||||
int i0 = int(floor(weight4.x));
|
||||
int i1 = int(floor(weight4.y));
|
||||
int i2 = int(floor(weight4.z));
|
||||
int i3 = int(floor(weight4.w));
|
||||
|
||||
float scale = 1.0/(w.x+w.y+w.z+w.w);
|
||||
w *= scale;
|
||||
|
||||
mat4 mat = matrixPalette[int(index.x)]*w.x;
|
||||
mat += matrixPalette[int(index.y)]*w.y;
|
||||
mat += matrixPalette[int(index.z)]*w.z;
|
||||
mat += matrixPalette[int(index.w)]*w.w;
|
||||
//float scale = 1.0/(w.x+w.y+w.z+w.w);
|
||||
//w *= scale;
|
||||
mat4 mat = matrixPalette[i0]*w0;
|
||||
mat += matrixPalette[i1]*w1;
|
||||
mat += matrixPalette[i2]*w2;
|
||||
mat += matrixPalette[i3]*w3;
|
||||
|
||||
return mat;
|
||||
}
|
||||
|
||||
@@ -11843,6 +11843,17 @@
|
||||
value_max="1">
|
||||
<param_driver />
|
||||
</param>
|
||||
|
||||
<param
|
||||
id="11000"
|
||||
group="0"
|
||||
name="AppearanceMessage_Version"
|
||||
label="AppearanceMessage Version"
|
||||
value_default="0"
|
||||
value_min="0"
|
||||
value_max="255">
|
||||
<param_driver />
|
||||
</param>
|
||||
</driver_parameters>
|
||||
|
||||
<morph_masks>
|
||||
|
||||
@@ -34,8 +34,8 @@
|
||||
#include "llagentcamera.h"
|
||||
#include "llagentwearables.h"
|
||||
#include "llagentui.h"
|
||||
#include "llanimationstates.h"
|
||||
#include "llappearancemgr.h"
|
||||
#include "llanimationstates.h"
|
||||
#include "llcallingcard.h"
|
||||
#include "llcapabilitylistener.h"
|
||||
#include "llconsole.h"
|
||||
@@ -780,6 +780,7 @@ void LLAgent::handleServerBakeRegionTransition(const LLUUID& region_id)
|
||||
!gAgentAvatarp->isUsingServerBakes() &&
|
||||
(mRegionp->getCentralBakeVersion()>0))
|
||||
{
|
||||
llinfos << "update requested due to region transition" << llendl;
|
||||
LLAppearanceMgr::instance().requestServerAppearanceUpdate();
|
||||
}
|
||||
}
|
||||
@@ -852,6 +853,9 @@ void LLAgent::setRegion(LLViewerRegion *regionp)
|
||||
// Update all of the regions.
|
||||
LLWorld::getInstance()->updateAgentOffset(mAgentOriginGlobal);
|
||||
}
|
||||
|
||||
// Pass new region along to metrics components that care about this level of detail.
|
||||
LLAppViewer::metricsUpdateRegion(regionp->getHandle());
|
||||
}
|
||||
mRegionp = regionp;
|
||||
|
||||
@@ -3717,6 +3721,10 @@ void LLAgent::processControlRelease(LLMessageSystem *msg, void **)
|
||||
void LLAgent::processAgentCachedTextureResponse(LLMessageSystem *mesgsys, void **user_data)
|
||||
{
|
||||
gAgentQueryManager.mNumPendingQueries--;
|
||||
if (gAgentQueryManager.mNumPendingQueries == 0)
|
||||
{
|
||||
selfStopPhase("fetch_texture_cache_entries");
|
||||
}
|
||||
|
||||
if (!isAgentAvatarValid() || gAgentAvatarp->isDead())
|
||||
{
|
||||
@@ -4419,24 +4427,92 @@ void LLAgent::requestLeaveGodMode()
|
||||
sendReliableMessage();
|
||||
}
|
||||
|
||||
extern void dump_visual_param(apr_file_t* file, LLVisualParam* viewer_param, F32 value);
|
||||
extern std::string get_sequential_numbered_file_name(const std::string& prefix,
|
||||
const std::string& suffix);
|
||||
|
||||
// For debugging, trace agent state at times appearance message are sent out.
|
||||
void LLAgent::dumpSentAppearance(const std::string& dump_prefix)
|
||||
{
|
||||
std::string outfilename = get_sequential_numbered_file_name(dump_prefix,".xml");
|
||||
|
||||
LLAPRFile outfile;
|
||||
std::string fullpath = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,outfilename);
|
||||
outfile.open(fullpath, LL_APR_WB );
|
||||
apr_file_t* file = outfile.getFileHandle();
|
||||
if (!file)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_DEBUGS("Avatar") << "dumping sent appearance message to " << fullpath << llendl;
|
||||
}
|
||||
|
||||
LLVisualParam* appearance_version_param = gAgentAvatarp->getVisualParam(11000);
|
||||
if (appearance_version_param)
|
||||
{
|
||||
F32 value = appearance_version_param->getWeight();
|
||||
dump_visual_param(file, appearance_version_param, value);
|
||||
}
|
||||
for (LLAvatarAppearanceDictionary::Textures::const_iterator iter = LLAvatarAppearanceDictionary::getInstance()->getTextures().begin();
|
||||
iter != LLAvatarAppearanceDictionary::getInstance()->getTextures().end();
|
||||
++iter)
|
||||
{
|
||||
const ETextureIndex index = iter->first;
|
||||
const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = iter->second;
|
||||
if (texture_dict->mIsBakedTexture)
|
||||
{
|
||||
LLTextureEntry* entry = gAgentAvatarp->getTE((U8) index);
|
||||
const LLUUID& uuid = entry->getID();
|
||||
apr_file_printf( file, "\t\t<texture te=\"%i\" uuid=\"%s\"/>\n", index, uuid.asString().c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// sendAgentSetAppearance()
|
||||
//-----------------------------------------------------------------------------
|
||||
void LLAgent::sendAgentSetAppearance()
|
||||
{
|
||||
// FIXME DRANO - problems around new-style appearance in an old-style region.
|
||||
// - does this get called?
|
||||
// - need to change mUseServerBakes->FALSE in that case
|
||||
// - need to call processAvatarAppearance as if server had returned this result?
|
||||
// gAgentAvatarp->mUseServerBakes = FALSE;
|
||||
|
||||
if (gAgentQueryManager.mNumPendingQueries > 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!gAgentWearables.changeInProgress())
|
||||
{
|
||||
// Change is fully resolved, can close some open phases.
|
||||
gAgentAvatarp->stopPhase("process_initial_wearables_update");
|
||||
gAgentAvatarp->stopPhase("wear_inventory_category");
|
||||
}
|
||||
|
||||
if (!isAgentAvatarValid() || (getRegion() && getRegion()->getCentralBakeVersion())) return;
|
||||
|
||||
// At this point we have a complete appearance to send and are in a non-baking region.
|
||||
// DRANO FIXME
|
||||
//gAgentAvatarp->setIsUsingServerBakes(FALSE);
|
||||
S32 sb_count, host_count, both_count, neither_count;
|
||||
gAgentAvatarp->bakedTextureOriginCounts(sb_count, host_count, both_count, neither_count);
|
||||
if (both_count != 0 || neither_count != 0)
|
||||
{
|
||||
llwarns << "bad bake texture state " << sb_count << "," << host_count << "," << both_count << "," << neither_count << llendl;
|
||||
}
|
||||
if (sb_count != 0 && host_count == 0)
|
||||
{
|
||||
gAgentAvatarp->setIsUsingServerBakes(true);
|
||||
}
|
||||
else if (sb_count == 0 && host_count != 0)
|
||||
{
|
||||
gAgentAvatarp->setIsUsingServerBakes(false);
|
||||
}
|
||||
else if (sb_count + host_count > 0)
|
||||
{
|
||||
llwarns << "unclear baked texture state, not sending appearance" << llendl;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
LL_INFOS("Avatar") << gAgentAvatarp->avString() << "TAT: Sent AgentSetAppearance: " << gAgentAvatarp->getBakedStatusForPrintout() << LL_ENDL;
|
||||
//dumpAvatarTEs( "sendAgentSetAppearance()" );
|
||||
|
||||
@@ -4488,14 +4564,25 @@ void LLAgent::sendAgentSetAppearance()
|
||||
// IMG_DEFAULT_AVATAR means not baked. 0 index should be ignored for baked textures
|
||||
if (!gAgentAvatarp->isTextureDefined(texture_index, 0))
|
||||
{
|
||||
LL_DEBUGS("Avatar") << "texture not current for baked " << (S32)baked_index << " local " << (S32)texture_index << llendl;
|
||||
textures_current = FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// only update cache entries if we have all our baked textures
|
||||
|
||||
// FIXME DRANO need additional check for not in appearance editing
|
||||
// mode, if still using local composites need to set using local
|
||||
// composites to false, and update mesh textures.
|
||||
if (textures_current)
|
||||
{
|
||||
bool enable_verbose_dumps = gSavedSettings.getBOOL("DebugAvatarAppearanceMessage");
|
||||
std::string dump_prefix = gAgentAvatarp->getFullname() + "_sent_appearance";
|
||||
if (enable_verbose_dumps)
|
||||
{
|
||||
dumpSentAppearance(dump_prefix);
|
||||
}
|
||||
LL_INFOS("Avatar") << gAgentAvatarp->avString() << "TAT: Sending cached texture data" << LL_ENDL;
|
||||
for (U8 baked_index = 0; baked_index < BAKED_NUM_INDICES; baked_index++)
|
||||
{
|
||||
|
||||
@@ -861,8 +861,9 @@ private:
|
||||
// Send
|
||||
//--------------------------------------------------------------------
|
||||
public:
|
||||
void sendMessage(); // Send message to this agent's region.
|
||||
void sendMessage(); // Send message to this agent's region
|
||||
void sendReliableMessage();
|
||||
void dumpSentAppearance(const std::string& dump_prefix);
|
||||
void sendAgentSetAppearance();
|
||||
void sendAgentDataUpdateRequest();
|
||||
void sendAgentUserInfoRequest();
|
||||
|
||||
@@ -1416,7 +1416,7 @@ void LLAgentCamera::updateCamera()
|
||||
// llinfos << "Current FOV Zoom: " << mCameraCurrentFOVZoomFactor << " Target FOV Zoom: " << mCameraFOVZoomFactor << " Object penetration: " << mFocusObjectDist << llendl;
|
||||
|
||||
F32 ui_offset = 0.f;
|
||||
if( LLFloaterCustomize::instanceExists() /*CAMERA_MODE_CUSTOMIZE_AVATAR == mCameraMode*/ )
|
||||
if( CAMERA_MODE_CUSTOMIZE_AVATAR == mCameraMode )
|
||||
{
|
||||
ui_offset = calcCustomizeAvatarUIOffset( camera_pos_global );
|
||||
}
|
||||
@@ -1543,7 +1543,7 @@ F32 LLAgentCamera::calcCustomizeAvatarUIOffset( const LLVector3d& camera_pos_glo
|
||||
{
|
||||
F32 ui_offset = 0.f;
|
||||
|
||||
if( LLFloaterCustomize::instanceExists() )
|
||||
if( LLFloaterCustomize::instanceExists() && CAMERA_MODE_CUSTOMIZE_AVATAR == mCameraMode )
|
||||
{
|
||||
const LLRect& rect = LLFloaterCustomize::getInstance()->getRect();
|
||||
|
||||
@@ -2603,7 +2603,7 @@ void LLAgentCamera::setCameraPosAndFocusGlobal(const LLVector3d& camera_pos, con
|
||||
{
|
||||
startCameraAnimation();
|
||||
|
||||
if( LLFloaterCustomize::instanceExists()/*CAMERA_MODE_CUSTOMIZE_AVATAR == mCameraMode*/ )
|
||||
if( CAMERA_MODE_CUSTOMIZE_AVATAR == mCameraMode )
|
||||
{
|
||||
// Compensate for the fact that the camera has already been offset to make room for LLFloaterCustomize.
|
||||
mAnimationCameraStartGlobal -= LLVector3d(LLViewerCamera::getInstance()->getLeftAxis() * calcCustomizeAvatarUIOffset( mAnimationCameraStartGlobal ));
|
||||
|
||||
@@ -226,14 +226,14 @@ LLAgentWearables::sendAgentWearablesUpdateCallback::~sendAgentWearablesUpdateCal
|
||||
* @param todo Bitmask of actions to take on completion.
|
||||
*/
|
||||
LLAgentWearables::addWearableToAgentInventoryCallback::addWearableToAgentInventoryCallback(
|
||||
LLPointer<LLRefCount> cb, LLWearableType::EType type, U32 index, LLViewerWearable* wearable, U32 todo) :
|
||||
LLPointer<LLRefCount> cb, LLWearableType::EType type, U32 index, LLViewerWearable* wearable, U32 todo, const std::string description) :
|
||||
mType(type),
|
||||
mIndex(index),
|
||||
mWearable(wearable),
|
||||
mTodo(todo),
|
||||
mCB(cb)
|
||||
mCB(cb),
|
||||
mDescription(description)
|
||||
{
|
||||
//llassert_always(index == 0);
|
||||
llinfos << "constructor" << llendl;
|
||||
}
|
||||
|
||||
@@ -272,7 +272,7 @@ void LLAgentWearables::addWearableToAgentInventoryCallback::fire(const LLUUID& i
|
||||
}
|
||||
if (mTodo & CALL_WEARITEM)
|
||||
{
|
||||
LLAppearanceMgr::instance().addCOFItemLink(inv_item, true);
|
||||
LLAppearanceMgr::instance().addCOFItemLink(inv_item, true, NULL, mDescription);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -473,6 +473,7 @@ void LLAgentWearables::saveWearable(const LLWearableType::EType type, const U32
|
||||
LLViewerWearable* LLAgentWearables::saveWearableAs(const LLWearableType::EType type,
|
||||
const U32 index,
|
||||
const std::string& new_name,
|
||||
const std::string& description,
|
||||
BOOL save_in_lost_and_found)
|
||||
{
|
||||
if (!isWearableCopyable(type, index))
|
||||
@@ -504,7 +505,9 @@ LLViewerWearable* LLAgentWearables::saveWearableAs(const LLWearableType::EType t
|
||||
type,
|
||||
index,
|
||||
new_wearable,
|
||||
addWearableToAgentInventoryCallback::CALL_WEARITEM);
|
||||
addWearableToAgentInventoryCallback::CALL_WEARITEM,
|
||||
description
|
||||
);
|
||||
LLUUID category_id;
|
||||
if (save_in_lost_and_found)
|
||||
{
|
||||
@@ -850,6 +853,8 @@ void LLAgentWearables::processAgentInitialWearablesUpdate(LLMessageSystem* mesgs
|
||||
|
||||
if (isAgentAvatarValid())
|
||||
{
|
||||
//gAgentAvatarp->clearPhases(); // reset phase timers for outfit loading.
|
||||
gAgentAvatarp->startPhase("process_initial_wearables_update");
|
||||
gAgentAvatarp->outputRezTiming("Received initial wearables update");
|
||||
}
|
||||
|
||||
@@ -1646,6 +1651,7 @@ void LLAgentWearables::queryWearableCache()
|
||||
{
|
||||
if (isAgentAvatarValid())
|
||||
{
|
||||
selfStartPhase("fetch_texture_cache_entries");
|
||||
gAgentAvatarp->outputRezTiming("Fetching textures from cache");
|
||||
}
|
||||
|
||||
|
||||
@@ -191,7 +191,7 @@ private:
|
||||
// Save Wearables
|
||||
//--------------------------------------------------------------------
|
||||
public:
|
||||
LLViewerWearable* saveWearableAs(const LLWearableType::EType type, const U32 index, const std::string& new_name, BOOL save_in_lost_and_found);
|
||||
LLViewerWearable* saveWearableAs(const LLWearableType::EType type, const U32 index, const std::string& new_name, const std::string& description, BOOL save_in_lost_and_found);
|
||||
void saveWearable(const LLWearableType::EType type, const U32 index, BOOL send_update = TRUE,
|
||||
const std::string new_name = "");
|
||||
void saveAllWearables();
|
||||
@@ -291,7 +291,8 @@ private:
|
||||
LLWearableType::EType type,
|
||||
U32 index,
|
||||
LLViewerWearable* wearable,
|
||||
U32 todo = CALL_NONE);
|
||||
U32 todo = CALL_NONE,
|
||||
const std::string description = "");
|
||||
virtual void fire(const LLUUID& inv_item);
|
||||
private:
|
||||
LLWearableType::EType mType;
|
||||
@@ -299,6 +300,7 @@ private:
|
||||
LLViewerWearable* mWearable;
|
||||
U32 mTodo;
|
||||
LLPointer<LLRefCount> mCB;
|
||||
std::string mDescription;
|
||||
};
|
||||
|
||||
}; // LLAgentWearables
|
||||
|
||||
@@ -86,6 +86,7 @@ LLInitialWearablesFetch::LLInitialWearablesFetch(const LLUUID& cof_id) :
|
||||
{
|
||||
if (isAgentAvatarValid())
|
||||
{
|
||||
gAgentAvatarp->startPhase("initial_wearables_fetch");
|
||||
gAgentAvatarp->outputRezTiming("Initial wearables fetch started");
|
||||
}
|
||||
}
|
||||
@@ -111,6 +112,7 @@ void LLInitialWearablesFetch::done()
|
||||
// [/RLVa:KB]
|
||||
if (isAgentAvatarValid())
|
||||
{
|
||||
gAgentAvatarp->stopPhase("initial_wearables_fetch");
|
||||
gAgentAvatarp->outputRezTiming("Initial wearables fetch done");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,6 +48,7 @@
|
||||
#include "llviewerregion.h"
|
||||
#include "llviewerstats.h"
|
||||
#include "llwearablelist.h"
|
||||
#include "llsdutil.h"
|
||||
#include "llinventorypanel.h"
|
||||
#include "llfloatercustomize.h"
|
||||
// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1a)
|
||||
@@ -58,10 +59,8 @@
|
||||
|
||||
std::string self_av_string()
|
||||
{
|
||||
if(isAgentAvatarValid())
|
||||
return gAgentAvatarp->avString();
|
||||
else
|
||||
return std::string();
|
||||
// On logout gAgentAvatarp can already be invalid
|
||||
return isAgentAvatarValid() ? gAgentAvatarp->avString() : "";
|
||||
}
|
||||
|
||||
// RAII thingy to guarantee that a variable gets reset when the Setter
|
||||
@@ -163,6 +162,16 @@ LLUUID findDescendentCategoryIDByName(const LLUUID& parent_id, const std::string
|
||||
}
|
||||
}
|
||||
|
||||
// We want this to be much lower (e.g. 15.0 is usually fine), bumping
|
||||
// up for now until we can diagnose some cases of very slow response
|
||||
// to requests.
|
||||
const F32 DEFAULT_RETRY_AFTER_INTERVAL = 300.0;
|
||||
|
||||
// Given the current back-end problems, retrying is causing too many
|
||||
// duplicate items. Bump this back to 2 once they are resolved (or can
|
||||
// leave at 0 if the operations become actually reliable).
|
||||
const S32 DEFAULT_MAX_RETRIES = 0;
|
||||
|
||||
class LLCallAfterInventoryBatchMgr: public LLEventTimer
|
||||
{
|
||||
public:
|
||||
@@ -170,8 +179,8 @@ public:
|
||||
const std::string& phase_name,
|
||||
nullary_func_t on_completion_func,
|
||||
nullary_func_t on_failure_func = no_op,
|
||||
F32 retry_after = 15.0,
|
||||
S32 max_retries = 2
|
||||
F32 retry_after = DEFAULT_RETRY_AFTER_INTERVAL,
|
||||
S32 max_retries = DEFAULT_MAX_RETRIES
|
||||
):
|
||||
mDstCatID(dst_cat_id),
|
||||
mTrackingPhase(phase_name),
|
||||
@@ -183,11 +192,11 @@ public:
|
||||
mFailCount(0),
|
||||
mCompletionOrFailureCalled(false),
|
||||
mRetryCount(0),
|
||||
LLEventTimer(retry_after)
|
||||
LLEventTimer(5.0)
|
||||
{
|
||||
if (!mTrackingPhase.empty())
|
||||
{
|
||||
//selfStartPhase(mTrackingPhase);
|
||||
selfStartPhase(mTrackingPhase);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -206,52 +215,38 @@ public:
|
||||
// Request or re-request operation for specified item.
|
||||
void addItem(const LLUUID& item_id)
|
||||
{
|
||||
LLUUID linked_id;
|
||||
if (gInventory.getItem(item_id))
|
||||
{
|
||||
linked_id = gInventory.getItem(item_id)->getLinkedUUID();
|
||||
}
|
||||
else if (gInventory.getCategory(item_id))
|
||||
{
|
||||
linked_id = item_id;
|
||||
}
|
||||
else
|
||||
{
|
||||
llwarns << "no referent found for item_id " << item_id << llendl;
|
||||
return;
|
||||
}
|
||||
LL_DEBUGS("Avatar") << "item_id " << item_id << " -> linked_id " << linked_id << llendl;
|
||||
LL_DEBUGS("Avatar") << "item_id " << item_id << llendl;
|
||||
|
||||
if (ll_frand()<gSavedSettings.getF32("InventoryDebugSimulateOpFailureRate"))
|
||||
if (!requestOperation(item_id))
|
||||
{
|
||||
// simulate server failure by not sending the request.
|
||||
return;
|
||||
}
|
||||
|
||||
if (!requestOperation(linked_id))
|
||||
{
|
||||
LL_DEBUGS("Avatar") << "item_id " << item_id << " linked_id " << linked_id << " not requested" << llendl;
|
||||
LL_DEBUGS("Avatar") << "item_id " << item_id << " requestOperation false, skipping" << llendl;
|
||||
return;
|
||||
}
|
||||
|
||||
mPendingRequests++;
|
||||
// On a re-request, this will reset the timer.
|
||||
mWaitTimes[linked_id] = LLTimer();
|
||||
if (mRetryCounts.find(linked_id) == mRetryCounts.end())
|
||||
mWaitTimes[item_id] = LLTimer();
|
||||
if (mRetryCounts.find(item_id) == mRetryCounts.end())
|
||||
{
|
||||
mRetryCounts[linked_id] = 0;
|
||||
mRetryCounts[item_id] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
mRetryCounts[linked_id]++;
|
||||
mRetryCounts[item_id]++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
virtual bool requestOperation(const LLUUID& item_id) = 0;
|
||||
|
||||
void onOp(const LLUUID& src_id, const LLUUID& dst_id, LLTimer timestamp)
|
||||
{
|
||||
if (ll_frand() < gSavedSettings.getF32("InventoryDebugSimulateLateOpRate"))
|
||||
{
|
||||
llwarns << "Simulating late operation by punting handling to later" << llendl;
|
||||
doAfterInterval(boost::bind(&LLCallAfterInventoryBatchMgr::onOp,this,src_id,dst_id,timestamp),
|
||||
mRetryAfter);
|
||||
return;
|
||||
}
|
||||
mPendingRequests--;
|
||||
F32 elapsed = timestamp.getElapsedTimeF32();
|
||||
LL_DEBUGS("Avatar") << "op done, src_id " << src_id << " dst_id " << dst_id << " after " << elapsed << " seconds" << llendl;
|
||||
@@ -281,7 +276,7 @@ public:
|
||||
reportStats();
|
||||
if (!mTrackingPhase.empty())
|
||||
{
|
||||
//selfStopPhase(mTrackingPhase);
|
||||
selfStopPhase(mTrackingPhase);
|
||||
}
|
||||
if (!mFailCount)
|
||||
{
|
||||
@@ -394,8 +389,8 @@ public:
|
||||
const std::string& phase_name,
|
||||
nullary_func_t on_completion_func,
|
||||
nullary_func_t on_failure_func = no_op,
|
||||
F32 retry_after = 15.0,
|
||||
S32 max_retries = 2
|
||||
F32 retry_after = DEFAULT_RETRY_AFTER_INTERVAL,
|
||||
S32 max_retries = DEFAULT_MAX_RETRIES
|
||||
):
|
||||
LLCallAfterInventoryBatchMgr(dst_cat_id, phase_name, on_completion_func, on_failure_func, retry_after, max_retries)
|
||||
{
|
||||
@@ -407,6 +402,11 @@ public:
|
||||
LLViewerInventoryItem *item = gInventory.getItem(item_id);
|
||||
llassert(item);
|
||||
LL_DEBUGS("Avatar") << "copying item " << item_id << llendl;
|
||||
if (ll_frand() < gSavedSettings.getF32("InventoryDebugSimulateOpFailureRate"))
|
||||
{
|
||||
LL_DEBUGS("Avatar") << "simulating failure by not sending request for item " << item_id << llendl;
|
||||
return true;
|
||||
}
|
||||
copy_inventory_item(
|
||||
gAgent.getID(),
|
||||
item->getPermissions().getOwner(),
|
||||
@@ -427,8 +427,8 @@ public:
|
||||
const std::string& phase_name,
|
||||
nullary_func_t on_completion_func,
|
||||
nullary_func_t on_failure_func = no_op,
|
||||
F32 retry_after = 15.0,
|
||||
S32 max_retries = 2
|
||||
F32 retry_after = DEFAULT_RETRY_AFTER_INTERVAL,
|
||||
S32 max_retries = DEFAULT_MAX_RETRIES
|
||||
):
|
||||
LLCallAfterInventoryBatchMgr(dst_cat_id, phase_name, on_completion_func, on_failure_func, retry_after, max_retries)
|
||||
{
|
||||
@@ -441,17 +441,27 @@ public:
|
||||
LLViewerInventoryItem *item = gInventory.getItem(item_id);
|
||||
if (item)
|
||||
{
|
||||
if (item->getParentUUID() == mDstCatID)
|
||||
{
|
||||
LL_DEBUGS("Avatar") << "item " << item_id << " name " << item->getName() << " is already a child of " << mDstCatID << llendl;
|
||||
return false;
|
||||
}
|
||||
LL_DEBUGS("Avatar") << "linking item " << item_id << " name " << item->getName() << " to " << mDstCatID << llendl;
|
||||
// create an inventory item link.
|
||||
if (ll_frand() < gSavedSettings.getF32("InventoryDebugSimulateOpFailureRate"))
|
||||
{
|
||||
LL_DEBUGS("Avatar") << "simulating failure by not sending request for item " << item_id << llendl;
|
||||
return true;
|
||||
}
|
||||
link_inventory_item(gAgent.getID(),
|
||||
item_id,
|
||||
item->getLinkedUUID(),
|
||||
mDstCatID,
|
||||
item->getName(),
|
||||
item->LLInventoryItem::getDescription(),
|
||||
item->getActualDescription(),
|
||||
LLAssetType::AT_LINK,
|
||||
new LLBoostFuncInventoryCallback(
|
||||
boost::bind(&LLCallAfterInventoryBatchMgr::onOp,this,item_id,_1,LLTimer())));
|
||||
request_sent = true;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -459,7 +469,7 @@ public:
|
||||
LLViewerInventoryCategory *catp = gInventory.getCategory(item_id);
|
||||
if (!catp)
|
||||
{
|
||||
llwarns << "id not found as inventory item or category " << item_id << llendl;
|
||||
llwarns << "link request failed, id not found as inventory item or category " << item_id << llendl;
|
||||
return false;
|
||||
}
|
||||
const LLUUID cof = LLAppearanceMgr::instance().getCOF();
|
||||
@@ -469,6 +479,11 @@ public:
|
||||
|
||||
if (catp && catp->getPreferredType() == LLFolderType::FT_OUTFIT)
|
||||
{
|
||||
if (ll_frand() < gSavedSettings.getF32("InventoryDebugSimulateOpFailureRate"))
|
||||
{
|
||||
LL_DEBUGS("Avatar") << "simulating failure by not sending request for item " << item_id << llendl;
|
||||
return true;
|
||||
}
|
||||
LL_DEBUGS("Avatar") << "linking folder " << item_id << " name " << catp->getName() << " to cof " << cof << llendl;
|
||||
link_inventory_item(gAgent.getID(), item_id, cof, catp->getName(), "",
|
||||
LLAssetType::AT_LINK_FOLDER,
|
||||
@@ -488,7 +503,7 @@ LLUpdateAppearanceOnDestroy::LLUpdateAppearanceOnDestroy(bool update_base_outfit
|
||||
mFireCount(0),
|
||||
mUpdateBaseOrder(update_base_outfit_ordering)
|
||||
{
|
||||
//selfStartPhase("update_appearance_on_destroy");
|
||||
selfStartPhase("update_appearance_on_destroy");
|
||||
}
|
||||
|
||||
LLUpdateAppearanceOnDestroy::~LLUpdateAppearanceOnDestroy()
|
||||
@@ -498,7 +513,7 @@ LLUpdateAppearanceOnDestroy::~LLUpdateAppearanceOnDestroy()
|
||||
// speculative fix for MAINT-1150
|
||||
LL_INFOS("Avatar") << self_av_string() << "done update appearance on destroy" << LL_ENDL;
|
||||
|
||||
//selfStopPhase("update_appearance_on_destroy");
|
||||
selfStopPhase("update_appearance_on_destroy");
|
||||
|
||||
LLAppearanceMgr::instance().updateAppearanceFromCOF(mUpdateBaseOrder);
|
||||
}
|
||||
@@ -631,7 +646,7 @@ LLWearableHoldingPattern::~LLWearableHoldingPattern()
|
||||
sActiveHoldingPatterns.erase(this);
|
||||
if (isMostRecent())
|
||||
{
|
||||
//selfStopPhase("holding_pattern");
|
||||
selfStopPhase("holding_pattern");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -722,7 +737,7 @@ void LLWearableHoldingPattern::checkMissingWearables()
|
||||
|
||||
resetTime(60.0F);
|
||||
|
||||
//selfStartPhase("get_missing_wearables");
|
||||
selfStartPhase("get_missing_wearables");
|
||||
if (!pollMissingWearables())
|
||||
{
|
||||
doOnIdleRepeating(boost::bind(&LLWearableHoldingPattern::pollMissingWearables,this));
|
||||
@@ -787,7 +802,7 @@ void LLWearableHoldingPattern::onAllComplete()
|
||||
|
||||
void LLWearableHoldingPattern::onFetchCompletion()
|
||||
{
|
||||
//selfStopPhase("get_wearables");
|
||||
selfStopPhase("get_wearables");
|
||||
|
||||
if (!isMostRecent())
|
||||
{
|
||||
@@ -998,7 +1013,7 @@ bool LLWearableHoldingPattern::pollMissingWearables()
|
||||
|
||||
if (done)
|
||||
{
|
||||
//selfStopPhase("get_missing_wearables");
|
||||
selfStopPhase("get_missing_wearables");
|
||||
|
||||
gAgentAvatarp->debugWearablesLoaded();
|
||||
|
||||
@@ -1228,6 +1243,21 @@ S32 LLAppearanceMgr::getCOFVersion() const
|
||||
}
|
||||
}
|
||||
|
||||
S32 LLAppearanceMgr::getLastUpdateRequestCOFVersion() const
|
||||
{
|
||||
return mLastUpdateRequestCOFVersion;
|
||||
}
|
||||
|
||||
S32 LLAppearanceMgr::getLastAppearanceUpdateCOFVersion() const
|
||||
{
|
||||
return mLastAppearanceUpdateCOFVersion;
|
||||
}
|
||||
|
||||
void LLAppearanceMgr::setLastAppearanceUpdateCOFVersion(S32 new_val)
|
||||
{
|
||||
mLastAppearanceUpdateCOFVersion = new_val;
|
||||
}
|
||||
|
||||
const LLViewerInventoryItem* LLAppearanceMgr::getBaseOutfitLink()
|
||||
{
|
||||
const LLUUID& current_outfit_cat = getCOF();
|
||||
@@ -1522,7 +1552,8 @@ void LLAppearanceMgr::shallowCopyCategory(const LLUUID& src_id, const LLUUID& ds
|
||||
}
|
||||
|
||||
// Copy contents of src_id to dst_id.
|
||||
void LLAppearanceMgr::shallowCopyCategoryContents(const LLUUID& src_id, const LLUUID& dst_id, LLPointer<LLInventoryCallback> cb)
|
||||
void LLAppearanceMgr::shallowCopyCategoryContents(const LLUUID& src_id, const LLUUID& dst_id,
|
||||
LLPointer<LLInventoryCallback> cb)
|
||||
{
|
||||
LLInventoryModel::cat_array_t* cats;
|
||||
LLInventoryModel::item_array_t* items;
|
||||
@@ -1548,7 +1579,7 @@ void LLAppearanceMgr::copyItems(const LLUUID& dst_id, LLInventoryModel::item_arr
|
||||
item->getLinkedUUID(),
|
||||
dst_id,
|
||||
item->getName(),
|
||||
item->LLInventoryItem::getDescription(),
|
||||
item->getActualDescription(),
|
||||
LLAssetType::AT_LINK, cb);
|
||||
break;
|
||||
}
|
||||
@@ -1838,7 +1869,7 @@ void LLAppearanceMgr::linkAll(const LLUUID& cat_uuid,
|
||||
item->getLinkedUUID(),
|
||||
cat_uuid,
|
||||
item->getName(),
|
||||
item->LLInventoryItem::getDescription(),
|
||||
item->getActualDescription(),
|
||||
LLAssetType::AT_LINK,
|
||||
cb);
|
||||
|
||||
@@ -1981,34 +2012,23 @@ void LLAppearanceMgr::updateCOF(LLInventoryModel::item_array_t& body_items_new,
|
||||
|
||||
// Create links to new COF contents.
|
||||
LL_DEBUGS("Avatar") << self_av_string() << "creating LLCallAfterInventoryLinkMgr" << LL_ENDL;
|
||||
|
||||
LLInventoryModel::item_array_t all_items;
|
||||
/*all_items += body_items;
|
||||
all_items += wear_items;
|
||||
all_items += obj_items;
|
||||
all_items += gest_items;*/
|
||||
|
||||
// Will link all the above items.
|
||||
bool update_base_outfit_ordering = !append;
|
||||
LLCallAfterInventoryLinkMgr *link_waiter =
|
||||
new LLCallAfterInventoryLinkMgr(body_items,cof,"update_appearance_on_destroy",
|
||||
new LLCallAfterInventoryLinkMgr(all_items,cof,"update_appearance_on_destroy",
|
||||
boost::bind(&LLAppearanceMgr::updateAppearanceFromCOF,
|
||||
LLAppearanceMgr::getInstance(),
|
||||
update_base_outfit_ordering));
|
||||
|
||||
// [SL:KB] - Checked: 2010-04-24 (RLVa-1.2.0f) | Added: RLVa-1.2.0f
|
||||
if (!append)
|
||||
{
|
||||
// [/SL:KB]
|
||||
#ifndef LL_RELEASE_FOR_DOWNLOAD
|
||||
LL_DEBUGS("Avatar") << self_av_string() << "Linking wear items" << LL_ENDL;
|
||||
#endif
|
||||
link_waiter->addItems(wear_items);
|
||||
|
||||
#ifndef LL_RELEASE_FOR_DOWNLOAD
|
||||
LL_DEBUGS("Avatar") << self_av_string() << "Linking obj items" << LL_ENDL;
|
||||
#endif
|
||||
link_waiter->addItems(obj_items);
|
||||
|
||||
#ifndef LL_RELEASE_FOR_DOWNLOAD
|
||||
LL_DEBUGS("Avatar") << self_av_string() << "Linking gesture items" << LL_ENDL;
|
||||
#endif
|
||||
link_waiter->addItems(gest_items);
|
||||
// [SL:KB] - Checked: 2010-04-24 (RLVa-1.2.0f) | Added: RLVa-1.2.0f
|
||||
}
|
||||
else
|
||||
if(append)
|
||||
{
|
||||
// Synchronize COF
|
||||
// -> it's possible that we don't link to any new items in which case 'link_waiter' fires when it goes out of scope below
|
||||
@@ -2023,9 +2043,14 @@ void LLAppearanceMgr::updateCOF(LLInventoryModel::item_array_t& body_items_new,
|
||||
// [RLVa:KB] - Checked: Never | Added: RLVa-1.2.0b
|
||||
if (!append && category.notNull())
|
||||
// [/RLVa:KB]
|
||||
// if (!append)
|
||||
if (!append)
|
||||
{
|
||||
link_waiter->addItem(category);
|
||||
link_waiter->addItems(body_items);
|
||||
link_waiter->addItems(wear_items);
|
||||
link_waiter->addItems(obj_items);
|
||||
link_waiter->addItems(gest_items);
|
||||
if(category.notNull())
|
||||
link_waiter->addItem(category);
|
||||
|
||||
// Remove current COF contents. Have to do this after creating
|
||||
// the link_waiter so links can be followed for any items that get
|
||||
@@ -2174,7 +2199,7 @@ static void remove_non_link_items(LLInventoryModel::item_array_t &items)
|
||||
}
|
||||
|
||||
//a predicate for sorting inventory items by actual descriptions
|
||||
bool sort_by_description(const LLInventoryItem* item1, const LLInventoryItem* item2)
|
||||
bool sort_by_actual_description(const LLInventoryItem* item1, const LLInventoryItem* item2)
|
||||
{
|
||||
if (!item1 || !item2)
|
||||
{
|
||||
@@ -2182,7 +2207,7 @@ bool sort_by_description(const LLInventoryItem* item1, const LLInventoryItem* it
|
||||
return true;
|
||||
}
|
||||
|
||||
return item1->LLInventoryItem::getDescription() < item2->LLInventoryItem::getDescription();
|
||||
return item1->getActualDescription() < item2->getActualDescription();
|
||||
}
|
||||
|
||||
void item_array_diff(LLInventoryModel::item_array_t& full_list,
|
||||
@@ -2287,7 +2312,7 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool update_base_outfit_ordering)
|
||||
}
|
||||
// DRANO really should wait for the appearance message to set this.
|
||||
// verify that deleting this line doesn't break anything.
|
||||
gAgentAvatarp->setIsUsingServerBakes(gAgent.getRegion() && gAgent.getRegion()->getCentralBakeVersion());
|
||||
//gAgentAvatarp->setIsUsingServerBakes(gAgent.getRegion() && gAgent.getRegion()->getCentralBakeVersion());
|
||||
|
||||
//dumpCat(getCOF(),"COF, start");
|
||||
|
||||
@@ -2424,7 +2449,7 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool update_base_outfit_ordering)
|
||||
}
|
||||
}
|
||||
|
||||
//selfStartPhase("get_wearables");
|
||||
selfStartPhase("get_wearables");
|
||||
|
||||
for (LLWearableHoldingPattern::found_list_t::iterator it = holder->getFoundList().begin();
|
||||
it != holder->getFoundList().end(); ++it)
|
||||
@@ -2519,15 +2544,15 @@ void LLAppearanceMgr::wearInventoryCategory(LLInventoryCategory* category, bool
|
||||
{
|
||||
if(!category) return;
|
||||
|
||||
//selfClearPhases();
|
||||
//selfStartPhase("wear_inventory_category");
|
||||
selfClearPhases();
|
||||
selfStartPhase("wear_inventory_category");
|
||||
|
||||
gAgentWearables.notifyLoadingStarted();
|
||||
|
||||
LL_INFOS("Avatar") << self_av_string() << "wearInventoryCategory( " << category->getName()
|
||||
<< " )" << LL_ENDL;
|
||||
|
||||
//selfStartPhase("wear_inventory_category_fetch");
|
||||
selfStartPhase("wear_inventory_category_fetch");
|
||||
callAfterCategoryFetch(category->getUUID(),boost::bind(&LLAppearanceMgr::wearCategoryFinal,
|
||||
&LLAppearanceMgr::instance(),
|
||||
category->getUUID(), copy, append));
|
||||
@@ -2537,7 +2562,7 @@ void LLAppearanceMgr::wearCategoryFinal(LLUUID& cat_id, bool copy_items, bool ap
|
||||
{
|
||||
LL_INFOS("Avatar") << self_av_string() << "starting" << LL_ENDL;
|
||||
|
||||
//selfStopPhase("wear_inventory_category_fetch");
|
||||
selfStopPhase("wear_inventory_category_fetch");
|
||||
|
||||
// We now have an outfit ready to be copied to agent inventory. Do
|
||||
// it, and wear that outfit normally.
|
||||
@@ -2687,10 +2712,11 @@ bool areMatchingWearables(const LLViewerInventoryItem *a, const LLViewerInventor
|
||||
class LLDeferredCOFLinkObserver: public LLInventoryObserver
|
||||
{
|
||||
public:
|
||||
LLDeferredCOFLinkObserver(const LLUUID& item_id, bool do_update, LLPointer<LLInventoryCallback> cb = NULL):
|
||||
LLDeferredCOFLinkObserver(const LLUUID& item_id, bool do_update, LLPointer<LLInventoryCallback> cb = NULL, std::string description = ""):
|
||||
mItemID(item_id),
|
||||
mDoUpdate(do_update),
|
||||
mCallback(cb)
|
||||
mCallback(cb),
|
||||
mDescription(description)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -2712,23 +2738,24 @@ public:
|
||||
private:
|
||||
const LLUUID mItemID;
|
||||
bool mDoUpdate;
|
||||
std::string mDescription;
|
||||
LLPointer<LLInventoryCallback> mCallback;
|
||||
};
|
||||
|
||||
|
||||
// BAP - note that this runs asynchronously if the item is not already loaded from inventory.
|
||||
// Dangerous if caller assumes link will exist after calling the function.
|
||||
void LLAppearanceMgr::addCOFItemLink(const LLUUID &item_id, bool do_update, LLPointer<LLInventoryCallback> cb)
|
||||
void LLAppearanceMgr::addCOFItemLink(const LLUUID &item_id, bool do_update, LLPointer<LLInventoryCallback> cb, const std::string description)
|
||||
{
|
||||
const LLInventoryItem *item = gInventory.getItem(item_id);
|
||||
if (!item)
|
||||
{
|
||||
LLDeferredCOFLinkObserver *observer = new LLDeferredCOFLinkObserver(item_id, do_update, cb);
|
||||
LLDeferredCOFLinkObserver *observer = new LLDeferredCOFLinkObserver(item_id, do_update, cb, description);
|
||||
gInventory.addObserver(observer);
|
||||
}
|
||||
else
|
||||
{
|
||||
addCOFItemLink(item, do_update, cb);
|
||||
addCOFItemLink(item, do_update, cb, description);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2751,8 +2778,10 @@ void modified_cof_cb(const LLUUID& inv_item)
|
||||
LLFloaterCustomize::getInstance()->switchToDefaultSubpart();
|
||||
}
|
||||
}
|
||||
void LLAppearanceMgr::addCOFItemLink(const LLInventoryItem *item, bool do_update, LLPointer<LLInventoryCallback> cb)
|
||||
|
||||
void LLAppearanceMgr::addCOFItemLink(const LLInventoryItem *item, bool do_update, LLPointer<LLInventoryCallback> cb, const std::string description)
|
||||
{
|
||||
std::string link_description = description;
|
||||
const LLViewerInventoryItem *vitem = dynamic_cast<const LLViewerInventoryItem*>(item);
|
||||
if (!vitem)
|
||||
{
|
||||
@@ -2823,32 +2852,48 @@ void LLAppearanceMgr::addCOFItemLink(const LLInventoryItem *item, bool do_update
|
||||
{
|
||||
cb = new LLBoostFuncInventoryCallback(modified_cof_cb);
|
||||
}
|
||||
std::string description = vitem->getIsLinkType() ? vitem->getDescription() : "";
|
||||
if(description.empty())
|
||||
if (vitem->getIsLinkType())
|
||||
{
|
||||
LLViewerWearable* wearable = gAgentWearables.getWearableFromItemID(vitem->getLinkedUUID());
|
||||
if(wearable)
|
||||
{
|
||||
U32 index = gAgentWearables.getWearableIndex(wearable);
|
||||
if(index < LLAgentWearables::MAX_CLOTHING_PER_TYPE)
|
||||
{
|
||||
std::ostringstream order_num;
|
||||
order_num << ORDER_NUMBER_SEPARATOR << wearable->getType() * 100 + index;
|
||||
description = order_num.str();
|
||||
}
|
||||
}
|
||||
link_description = vitem->getActualDescription();
|
||||
}
|
||||
link_inventory_item( gAgent.getID(),
|
||||
vitem->getLinkedUUID(),
|
||||
getCOF(),
|
||||
vitem->getName(),
|
||||
description,
|
||||
link_description,
|
||||
LLAssetType::AT_LINK,
|
||||
cb);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
LLInventoryModel::item_array_t LLAppearanceMgr::findCOFItemLinks(const LLUUID& item_id)
|
||||
{
|
||||
|
||||
LLInventoryModel::item_array_t result;
|
||||
const LLViewerInventoryItem *vitem =
|
||||
dynamic_cast<const LLViewerInventoryItem*>(gInventory.getItem(item_id));
|
||||
|
||||
if (vitem)
|
||||
{
|
||||
LLInventoryModel::cat_array_t cat_array;
|
||||
LLInventoryModel::item_array_t item_array;
|
||||
gInventory.collectDescendents(LLAppearanceMgr::getCOF(),
|
||||
cat_array,
|
||||
item_array,
|
||||
LLInventoryModel::EXCLUDE_TRASH);
|
||||
for (S32 i=0; i<item_array.count(); i++)
|
||||
{
|
||||
const LLViewerInventoryItem* inv_item = item_array.get(i).get();
|
||||
if (inv_item->getLinkedUUID() == vitem->getLinkedUUID())
|
||||
{
|
||||
result.put(item_array.get(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void LLAppearanceMgr::removeAllClothesFromAvatar()
|
||||
{
|
||||
// Fetch worn clothes (i.e. the ones in COF).
|
||||
@@ -3012,7 +3057,7 @@ void LLAppearanceMgr::updateIsDirty()
|
||||
|
||||
if (item1->getLinkedUUID() != item2->getLinkedUUID() ||
|
||||
item1->getName() != item2->getName() ||
|
||||
item1->LLInventoryItem::getDescription() != item2->LLInventoryItem::getDescription())
|
||||
item1->getActualDescription() != item2->getActualDescription())
|
||||
{
|
||||
mOutfitIsDirty = true;
|
||||
return;
|
||||
@@ -3223,8 +3268,8 @@ struct WearablesOrderComparator
|
||||
return true;
|
||||
}
|
||||
|
||||
const std::string& desc1 = item1->LLInventoryItem::getDescription();
|
||||
const std::string& desc2 = item2->LLInventoryItem::getDescription();
|
||||
const std::string& desc1 = item1->getActualDescription();
|
||||
const std::string& desc2 = item2->getActualDescription();
|
||||
|
||||
bool item1_valid = (desc1.size() == mControlSize) && (ORDER_NUMBER_SEPARATOR == desc1[0]);
|
||||
bool item2_valid = (desc2.size() == mControlSize) && (ORDER_NUMBER_SEPARATOR == desc2[0]);
|
||||
@@ -3282,7 +3327,7 @@ void LLAppearanceMgr::updateClothingOrderingInfo(LLUUID cat_id, bool update_base
|
||||
if (!item) continue;
|
||||
|
||||
std::string new_order_str = build_order_string((LLWearableType::EType)type, i);
|
||||
if (new_order_str == item->LLInventoryItem::getDescription()) continue;
|
||||
if (new_order_str == item->getActualDescription()) continue;
|
||||
|
||||
item->setDescription(new_order_str);
|
||||
item->setComplete(TRUE);
|
||||
@@ -3368,13 +3413,27 @@ public:
|
||||
// Successful completion.
|
||||
/* virtual */ void result(const LLSD& content)
|
||||
{
|
||||
llinfos << "request OK" << llendl;
|
||||
LL_DEBUGS("Avatar") << "content: " << ll_pretty_print_sd(content) << LL_ENDL;
|
||||
if (content["success"].asBoolean())
|
||||
{
|
||||
LL_DEBUGS("Avatar") << "OK" << LL_ENDL;
|
||||
}
|
||||
else
|
||||
{
|
||||
onFailure(200);
|
||||
}
|
||||
}
|
||||
|
||||
// Error
|
||||
/*virtual*/ void error(U32 status, const std::string& reason)
|
||||
/*virtual*/ void errorWithContent(U32 status, const std::string& reason, const LLSD& content)
|
||||
{
|
||||
llwarns << "appearance update request failed, status: " << status << " reason: " << reason << llendl;
|
||||
LL_DEBUGS("Avatar") << "content: " << ll_pretty_print_sd(content) << LL_ENDL;
|
||||
onFailure(status);
|
||||
}
|
||||
|
||||
void onFailure(U32 status)
|
||||
{
|
||||
F32 seconds_to_wait;
|
||||
if (mRetryPolicy->shouldRetry(status,seconds_to_wait))
|
||||
{
|
||||
@@ -3882,8 +3941,8 @@ bool LLAppearanceMgr::moveWearable(LLViewerInventoryItem* item, bool closer_to_b
|
||||
closer_to_body ? --it : ++it;
|
||||
LLViewerInventoryItem* swap_item = *it;
|
||||
if (!swap_item) return false;
|
||||
std::string tmp = swap_item->LLInventoryItem::getDescription();
|
||||
swap_item->setDescription(item->LLInventoryItem::getDescription());
|
||||
std::string tmp = swap_item->getActualDescription();
|
||||
swap_item->setDescription(item->getActualDescription());
|
||||
item->setDescription(tmp);
|
||||
|
||||
|
||||
@@ -3916,7 +3975,7 @@ void LLAppearanceMgr::sortItemsByActualDescription(LLInventoryModel::item_array_
|
||||
{
|
||||
if (items.size() < 2) return;
|
||||
|
||||
std::sort(items.begin(), items.end(), sort_by_description);
|
||||
std::sort(items.begin(), items.end(), sort_by_actual_description);
|
||||
}
|
||||
|
||||
//#define DUMP_CAT_VERBOSE
|
||||
@@ -3963,7 +4022,8 @@ LLAppearanceMgr::LLAppearanceMgr():
|
||||
mOutfitIsDirty(false),
|
||||
mOutfitLocked(false),
|
||||
mIsInUpdateAppearanceFromCOF(false),
|
||||
mLastUpdateRequestCOFVersion(LLViewerInventoryCategory::VERSION_UNKNOWN)
|
||||
mLastUpdateRequestCOFVersion(LLViewerInventoryCategory::VERSION_UNKNOWN),
|
||||
mLastAppearanceUpdateCOFVersion(LLViewerInventoryCategory::VERSION_UNKNOWN)
|
||||
{
|
||||
LLOutfitObserver& outfit_observer = LLOutfitObserver::instance();
|
||||
|
||||
|
||||
@@ -108,6 +108,12 @@ public:
|
||||
S32 getCOFVersion() const;
|
||||
|
||||
S32 mLastUpdateRequestCOFVersion;
|
||||
S32 getLastUpdateRequestCOFVersion() const;
|
||||
|
||||
// COF version of last appearance message received for self av.
|
||||
S32 mLastAppearanceUpdateCOFVersion;
|
||||
S32 getLastAppearanceUpdateCOFVersion() const;
|
||||
void setLastAppearanceUpdateCOFVersion(S32 new_val);
|
||||
|
||||
// Finds the folder link to the currently worn outfit
|
||||
const LLViewerInventoryItem *getBaseOutfitLink();
|
||||
@@ -142,8 +148,11 @@ public:
|
||||
LLPointer<LLInventoryCallback> cb);
|
||||
|
||||
// Add COF link to individual item.
|
||||
void addCOFItemLink(const LLUUID& item_id, bool do_update = true, LLPointer<LLInventoryCallback> cb = NULL);
|
||||
void addCOFItemLink(const LLInventoryItem *item, bool do_update = true, LLPointer<LLInventoryCallback> cb = NULL);
|
||||
void addCOFItemLink(const LLUUID& item_id, bool do_update = true, LLPointer<LLInventoryCallback> cb = NULL, const std::string description = "");
|
||||
void addCOFItemLink(const LLInventoryItem *item, bool do_update = true, LLPointer<LLInventoryCallback> cb = NULL, const std::string description = "");
|
||||
|
||||
// Find COF entries referencing the given item.
|
||||
LLInventoryModel::item_array_t findCOFItemLinks(const LLUUID& item_id);
|
||||
|
||||
// Remove COF entries
|
||||
void removeCOFItemLinks(const LLUUID& item_id);
|
||||
|
||||
@@ -193,7 +193,7 @@
|
||||
#include "llimview.h"
|
||||
#include "llviewerthrottle.h"
|
||||
#include "llparcel.h"
|
||||
|
||||
#include "llviewerassetstats.h"
|
||||
#include "llcommandlineparser.h"
|
||||
#include "llprogressview.h"
|
||||
|
||||
@@ -395,6 +395,14 @@ static std::string gHelperURI;
|
||||
|
||||
LLAppViewer::LLUpdaterInfo *LLAppViewer::sUpdaterInfo = NULL ;
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Metrics logging control constants
|
||||
//----------------------------------------------------------------------------
|
||||
static const F32 METRICS_INTERVAL_DEFAULT = 600.0;
|
||||
static const F32 METRICS_INTERVAL_QA = 30.0;
|
||||
static F32 app_metrics_interval = METRICS_INTERVAL_DEFAULT;
|
||||
static bool app_metrics_qa_mode = false;
|
||||
|
||||
void idle_afk_check()
|
||||
{
|
||||
// check idle timers
|
||||
@@ -670,10 +678,26 @@ bool LLAppViewer::init()
|
||||
);
|
||||
AIHTTPTimeoutPolicy::setDefaultCurlTimeout(policy_tmp);
|
||||
}
|
||||
{
|
||||
// Viewer metrics initialization
|
||||
//static LLCachedControl<bool> metrics_submode(gSavedSettings,
|
||||
// "QAModeMetrics",
|
||||
// false,
|
||||
// "Enables QA features (logging, faster cycling) for metrics collector");
|
||||
|
||||
if (gSavedSettings.getBOOL("QAModeMetrics"))
|
||||
{
|
||||
app_metrics_qa_mode = true;
|
||||
app_metrics_interval = METRICS_INTERVAL_QA;
|
||||
}
|
||||
LLViewerAssetStatsFF::init();
|
||||
}
|
||||
|
||||
initThreads();
|
||||
LL_INFOS("InitInfo") << "Threads initialized." << LL_ENDL ;
|
||||
|
||||
|
||||
|
||||
writeSystemInfo();
|
||||
|
||||
// Build a string representing the current version number.
|
||||
@@ -742,6 +766,11 @@ bool LLAppViewer::init()
|
||||
ui_audio_callback,
|
||||
&LLUI::getScaleFactor()
|
||||
);
|
||||
|
||||
// Setup notifications after LLUI::initClass() has been called.
|
||||
LLNotifications::instance();
|
||||
LL_INFOS("InitInfo") << "Notifications initialized." << LL_ENDL ;
|
||||
|
||||
LLWeb::initClass(); // do this after LLUI
|
||||
|
||||
LLUICtrlFactory::getInstance()->setupPaths(); // update paths with correct language set
|
||||
@@ -1811,6 +1840,7 @@ bool LLAppViewer::cleanup()
|
||||
gSavedSettings.cleanup();
|
||||
gColors.cleanup();
|
||||
gCrashSettings.cleanup();
|
||||
LLViewerAssetStatsFF::cleanup();
|
||||
|
||||
// If we're exiting to launch an URL, do that here so the screen
|
||||
// is at the right resolution before we launch IE.
|
||||
@@ -1893,7 +1923,10 @@ bool LLAppViewer::initThreads()
|
||||
// Image decoding
|
||||
LLAppViewer::sImageDecodeThread = new LLImageDecodeThread(enable_threads && true);
|
||||
LLAppViewer::sTextureCache = new LLTextureCache(enable_threads && true);
|
||||
LLAppViewer::sTextureFetch = new LLTextureFetch(LLAppViewer::getTextureCache(), sImageDecodeThread, enable_threads && true);
|
||||
LLAppViewer::sTextureFetch = new LLTextureFetch(LLAppViewer::getTextureCache(),
|
||||
sImageDecodeThread,
|
||||
enable_threads && true,
|
||||
app_metrics_qa_mode);
|
||||
|
||||
|
||||
// Mesh streaming and caching
|
||||
@@ -3119,6 +3152,15 @@ void LLAppViewer::requestQuit()
|
||||
return;
|
||||
}
|
||||
|
||||
// Try to send metrics back to the grid
|
||||
metricsSend(!gDisconnected);
|
||||
|
||||
// Try to send last batch of avatar rez metrics.
|
||||
if (!gDisconnected && isAgentAvatarValid())
|
||||
{
|
||||
gAgentAvatarp->updateAvatarRezMetrics(true); // force a last packet to be sent.
|
||||
}
|
||||
|
||||
LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral*)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINT, TRUE);
|
||||
effectp->setPositionGlobal(gAgent.getPositionGlobal());
|
||||
effectp->setColor(LLColor4U(gAgent.getEffectColor()));
|
||||
@@ -3938,6 +3980,11 @@ void LLAppViewer::idle()
|
||||
llinfos << "Unknown object updates: " << gObjectList.mNumUnknownUpdates << llendl;
|
||||
gObjectList.mNumUnknownUpdates = 0;
|
||||
}
|
||||
|
||||
// ViewerMetrics FPS piggy-backing on the debug timer.
|
||||
// The 5-second interval is nice for this purpose. If the object debug
|
||||
// bit moves or is disabled, please give this a suitable home.
|
||||
LLViewerAssetStatsFF::record_fps_main(gFPSClamped);
|
||||
}
|
||||
gFrameStats.addFrameData();
|
||||
}
|
||||
@@ -3985,6 +4032,19 @@ void LLAppViewer::idle()
|
||||
gInventory.idleNotifyObservers();
|
||||
}
|
||||
|
||||
// Metrics logging (LLViewerAssetStats, etc.)
|
||||
{
|
||||
static LLTimer report_interval;
|
||||
|
||||
// *TODO: Add configuration controls for this
|
||||
F32 seconds = report_interval.getElapsedTimeF32();
|
||||
if (seconds >= app_metrics_interval)
|
||||
{
|
||||
metricsSend(! gDisconnected);
|
||||
report_interval.reset();
|
||||
}
|
||||
}
|
||||
|
||||
if (gDisconnected)
|
||||
{
|
||||
return;
|
||||
@@ -4737,3 +4797,71 @@ void LLAppViewer::handleLoginComplete()
|
||||
writeDebugInfo();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* LLViewerAssetStats collects data on a per-region (as defined by the agent's
|
||||
* location) so we need to tell it about region changes which become a kind of
|
||||
* hidden variable/global state in the collectors. For collectors not running
|
||||
* on the main thread, we need to send a message to move the data over safely
|
||||
* and cheaply (amortized over a run).
|
||||
*/
|
||||
void LLAppViewer::metricsUpdateRegion(U64 region_handle)
|
||||
{
|
||||
if (0 != region_handle)
|
||||
{
|
||||
LLViewerAssetStatsFF::set_region_main(region_handle);
|
||||
if (LLAppViewer::sTextureFetch)
|
||||
{
|
||||
// Send a region update message into 'thread1' to get the new region.
|
||||
LLAppViewer::sTextureFetch->commandSetRegion(region_handle);
|
||||
}
|
||||
else
|
||||
{
|
||||
// No 'thread1', a.k.a. TextureFetch, so update directly
|
||||
LLViewerAssetStatsFF::set_region_thread1(region_handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Attempts to start a multi-threaded metrics report to be sent back to
|
||||
* the grid for consumption.
|
||||
*/
|
||||
void LLAppViewer::metricsSend(bool enable_reporting)
|
||||
{
|
||||
if (! gViewerAssetStatsMain)
|
||||
return;
|
||||
|
||||
if (LLAppViewer::sTextureFetch)
|
||||
{
|
||||
LLViewerRegion * regionp = gAgent.getRegion();
|
||||
|
||||
if (enable_reporting && regionp)
|
||||
{
|
||||
std::string caps_url = regionp->getCapability("ViewerMetrics");
|
||||
|
||||
// Make a copy of the main stats to send into another thread.
|
||||
// Receiving thread takes ownership.
|
||||
LLViewerAssetStats * main_stats(new LLViewerAssetStats(*gViewerAssetStatsMain));
|
||||
|
||||
// Send a report request into 'thread1' to get the rest of the data
|
||||
// and provide some additional parameters while here.
|
||||
LLAppViewer::sTextureFetch->commandSendMetrics(caps_url,
|
||||
gAgentSessionID,
|
||||
gAgentID,
|
||||
main_stats);
|
||||
main_stats = 0; // Ownership transferred
|
||||
}
|
||||
else
|
||||
{
|
||||
LLAppViewer::sTextureFetch->commandDataBreak();
|
||||
}
|
||||
}
|
||||
|
||||
// Reset even if we can't report. Rather than gather up a huge chunk of
|
||||
// data, we'll keep to our sampling interval and retain the data
|
||||
// resolution in time.
|
||||
gViewerAssetStatsMain->reset();
|
||||
}
|
||||
|
||||
|
||||
@@ -168,6 +168,10 @@ public:
|
||||
void addOnIdleCallback(const boost::function<void()>& cb); // add a callback to fire (once) when idle
|
||||
|
||||
void purgeCache(); // Clear the local cache.
|
||||
|
||||
// Metrics policy helper statics.
|
||||
static void metricsUpdateRegion(U64 region_handle);
|
||||
static void metricsSend(bool enable_reporting);
|
||||
protected:
|
||||
virtual bool initWindow(); // Initialize the viewer's window.
|
||||
virtual bool initLogging(); // Initialize log files, logging system, return false on failure.
|
||||
|
||||
@@ -250,11 +250,17 @@ S32 LLDrawable::findReferences(LLDrawable *drawablep)
|
||||
return count;
|
||||
}
|
||||
|
||||
static LLFastTimer::DeclareTimer FTM_ALLOCATE_FACE("Allocate Face", true);
|
||||
|
||||
LLFace* LLDrawable::addFace(LLFacePool *poolp, LLViewerTexture *texturep)
|
||||
{
|
||||
LLMemType mt(LLMemType::MTYPE_DRAWABLE);
|
||||
|
||||
LLFace *face = new LLFace(this, mVObjp);
|
||||
LLFace *face;
|
||||
{
|
||||
LLFastTimer t(FTM_ALLOCATE_FACE);
|
||||
face = new LLFace(this, mVObjp);
|
||||
}
|
||||
|
||||
if (!face) llerrs << "Allocating new Face: " << mFaces.size() << llendl;
|
||||
|
||||
if (face)
|
||||
@@ -276,10 +282,12 @@ LLFace* LLDrawable::addFace(LLFacePool *poolp, LLViewerTexture *texturep)
|
||||
|
||||
LLFace* LLDrawable::addFace(const LLTextureEntry *te, LLViewerTexture *texturep)
|
||||
{
|
||||
LLMemType mt(LLMemType::MTYPE_DRAWABLE);
|
||||
|
||||
LLFace *face;
|
||||
face = new LLFace(this, mVObjp);
|
||||
|
||||
{
|
||||
LLFastTimer t(FTM_ALLOCATE_FACE);
|
||||
face = new LLFace(this, mVObjp);
|
||||
}
|
||||
|
||||
face->setTEOffset(mFaces.size());
|
||||
face->setTexture(texturep);
|
||||
@@ -537,6 +545,12 @@ F32 LLDrawable::updateXform(BOOL undamped)
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dist_squared = dist_vec_squared(old_pos, target_pos);
|
||||
dist_squared += (1.f - dot(old_rot, target_rot)) * 10.f;
|
||||
dist_squared += dist_vec_squared(old_scale, target_scale);
|
||||
}
|
||||
|
||||
LLVector3 vec = mCurrentScale-target_scale;
|
||||
|
||||
|
||||
@@ -1278,6 +1278,9 @@ void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer(LLVOAvatar* avatar, LLFace*
|
||||
face->setGeomIndex(0);
|
||||
face->setIndicesIndex(0);
|
||||
|
||||
//rigged faces do not batch textures
|
||||
face->setTextureIndex(255);
|
||||
|
||||
if (buffer.isNull() || buffer->getTypeMask() != data_mask || !buffer->isWriteable())
|
||||
{ //make a new buffer
|
||||
if (sShaderLevel > 0)
|
||||
@@ -1636,6 +1639,7 @@ void LLDrawPoolAvatar::renderRiggedAlpha(LLVOAvatar* avatar)
|
||||
LLRender::BF_ONE_MINUS_SOURCE_ALPHA);
|
||||
|
||||
renderRigged(avatar, RIGGED_ALPHA);
|
||||
gGL.setColorMask(true, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1652,6 +1656,7 @@ void LLDrawPoolAvatar::renderRiggedFullbrightAlpha(LLVOAvatar* avatar)
|
||||
LLRender::BF_ONE_MINUS_SOURCE_ALPHA);
|
||||
|
||||
renderRigged(avatar, RIGGED_FULLBRIGHT_ALPHA);
|
||||
gGL.setColorMask(true, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1192,7 +1192,7 @@ static LLFastTimer::DeclareTimer FTM_BUMP_SOURCE_MIN_MAX("Min/Max");
|
||||
static LLFastTimer::DeclareTimer FTM_BUMP_SOURCE_RGB2LUM("RGB to Luminance");
|
||||
static LLFastTimer::DeclareTimer FTM_BUMP_SOURCE_RESCALE("Rescale");
|
||||
static LLFastTimer::DeclareTimer FTM_BUMP_SOURCE_GEN_NORMAL("Generate Normal");
|
||||
static LLFastTimer::DeclareTimer FTM_BUMP_SOURCE_CREATE("Create");
|
||||
static LLFastTimer::DeclareTimer FTM_BUMP_SOURCE_CREATE("Bump Source Create");
|
||||
|
||||
// static
|
||||
void LLBumpImageList::onSourceLoaded( BOOL success, LLViewerTexture *src_vi, LLImageRaw* src, LLUUID& source_asset_id, EBumpEffect bump_code )
|
||||
|
||||
@@ -48,7 +48,7 @@ std::vector<LLVolumeImplFlexible*> LLVolumeImplFlexible::sInstanceList;
|
||||
std::vector<U32> LLVolumeImplFlexible::sUpdateDelay;
|
||||
|
||||
static LLFastTimer::DeclareTimer FTM_FLEXIBLE_REBUILD("Rebuild");
|
||||
static LLFastTimer::DeclareTimer FTM_DO_FLEXIBLE_UPDATE("Update");
|
||||
static LLFastTimer::DeclareTimer FTM_DO_FLEXIBLE_UPDATE("Flexible Update");
|
||||
|
||||
// LLFlexibleObjectData::pack/unpack now in llprimitive.cpp
|
||||
|
||||
@@ -361,7 +361,7 @@ void LLVolumeImplFlexible::doIdleUpdate()
|
||||
if (visible)
|
||||
{
|
||||
if (!drawablep->isState(LLDrawable::IN_REBUILD_Q1) &&
|
||||
mVO->getPixelArea() > 256.f)
|
||||
pixel_area > 256.f)
|
||||
{
|
||||
U32 id;
|
||||
|
||||
|
||||
@@ -180,9 +180,10 @@ void LLFloaterColorPicker::createUI ()
|
||||
//
|
||||
void LLFloaterColorPicker::showUI ()
|
||||
{
|
||||
open(); /*Flawfinder: ignore*/
|
||||
setVisible ( TRUE );
|
||||
setFocus ( TRUE );
|
||||
open(); /*Flawfinder: ignore*/
|
||||
|
||||
|
||||
// HACK: if system color picker is required - close the SL one we made and use default system dialog
|
||||
if ( gSavedSettings.getBOOL ( "UseDefaultColorPicker" ) )
|
||||
|
||||
@@ -78,6 +78,7 @@
|
||||
#include "llpaneleditwearable.h"
|
||||
#include "llmakeoutfitdialog.h"
|
||||
#include "llagentcamera.h"
|
||||
#include "llappearancemgr.h"
|
||||
|
||||
#include "statemachine/aifilepicker.h"
|
||||
|
||||
@@ -256,6 +257,7 @@ void LLFloaterCustomize::delayedClose(bool proceed, bool app_quitting)
|
||||
{
|
||||
LLVOAvatarSelf::onCustomizeEnd();
|
||||
LLFloater::onClose(app_quitting);
|
||||
if(gAgentAvatarp)gAgentAvatarp->mSpecialRenderMode = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -425,17 +427,7 @@ void LLFloaterCustomize::onBtnExport_continued(AIFilePicker* filepicker)
|
||||
|
||||
void LLFloaterCustomize::onBtnOk()
|
||||
{
|
||||
gAgentWearables.saveAllWearables();
|
||||
|
||||
if ( gAgentAvatarp )
|
||||
{
|
||||
gAgentAvatarp->invalidateAll();
|
||||
|
||||
gAgentAvatarp->requestLayerSetUploads();
|
||||
|
||||
gAgent.sendAgentSetAppearance();
|
||||
}
|
||||
|
||||
saveCurrentWearables();
|
||||
gFloaterView->sendChildToBack(this);
|
||||
close(false);
|
||||
}
|
||||
@@ -595,7 +587,10 @@ void LLFloaterCustomize::updateVisiblity(bool force_disable_camera_switch/*=fals
|
||||
if(!getVisible())
|
||||
{
|
||||
if(force_disable_camera_switch || !gAgentCamera.cameraCustomizeAvatar() || !gAgentCamera.getCameraAnimating() || (gMorphView && gMorphView->getVisible()))
|
||||
{
|
||||
if(gAgentAvatarp)gAgentAvatarp->mSpecialRenderMode = 3;
|
||||
setVisibleAndFrontmost(TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -621,12 +616,8 @@ void LLFloaterCustomize::askToSaveIfDirty( boost::function<void (BOOL)> cb )
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool LLFloaterCustomize::onSaveDialog(const LLSD& notification, const LLSD& response )
|
||||
void LLFloaterCustomize::saveCurrentWearables()
|
||||
{
|
||||
S32 option = LLNotification::getSelectedOption(notification, response);
|
||||
|
||||
BOOL proceed = FALSE;
|
||||
LLWearableType::EType cur = getCurrentWearableType();
|
||||
|
||||
for(U32 i = 0;i < gAgentWearables.getWearableCount(cur);++i)
|
||||
@@ -634,32 +625,71 @@ bool LLFloaterCustomize::onSaveDialog(const LLSD& notification, const LLSD& resp
|
||||
LLViewerWearable* wearable = gAgentWearables.getViewerWearable(cur,i);
|
||||
if(wearable && wearable->isDirty())
|
||||
{
|
||||
switch( option )
|
||||
/*
|
||||
===============================================================================================
|
||||
Copy-pasted some code from LLPanelEditWearable::saveChanges instead of just calling saveChanges, as
|
||||
we only have one 'active' panel per wearable type, not per layer. The panels just update when
|
||||
layer of focus is changed. Easier just to do it right here manually.
|
||||
===============================================================================================
|
||||
*/
|
||||
// Find an existing link to this wearable's inventory item, if any, and its description field.
|
||||
if(gAgentAvatarp->isUsingServerBakes())
|
||||
{
|
||||
case 0: // "Save"
|
||||
gAgentWearables.saveWearable( cur, i );
|
||||
proceed = TRUE;
|
||||
break;
|
||||
|
||||
case 1: // "Don't Save"
|
||||
LLInventoryItem *link_item = NULL;
|
||||
std::string description;
|
||||
LLInventoryModel::item_array_t links =
|
||||
LLAppearanceMgr::instance().findCOFItemLinks(wearable->getItemID());
|
||||
if (links.size()>0)
|
||||
{
|
||||
gAgentWearables.revertWearable( cur, i );
|
||||
proceed = TRUE;
|
||||
link_item = links.get(0).get();
|
||||
if (link_item && link_item->getIsLinkType())
|
||||
{
|
||||
description = link_item->getActualDescription();
|
||||
}
|
||||
}
|
||||
break;
|
||||
// Make another copy of this link, with the same
|
||||
// description. This is needed to bump the COF
|
||||
// version so texture baking service knows appearance has changed.
|
||||
if (link_item)
|
||||
{
|
||||
// Create new link
|
||||
link_inventory_item( gAgent.getID(),
|
||||
link_item->getLinkedUUID(),
|
||||
LLAppearanceMgr::instance().getCOF(),
|
||||
link_item->getName(),
|
||||
description,
|
||||
LLAssetType::AT_LINK,
|
||||
NULL);
|
||||
// Remove old link
|
||||
gInventory.purgeObject(link_item->getUUID());
|
||||
}
|
||||
}
|
||||
gAgentWearables.saveWearable( cur, i );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case 2: // "Cancel"
|
||||
break;
|
||||
|
||||
default:
|
||||
llassert(0);
|
||||
break;
|
||||
bool LLFloaterCustomize::onSaveDialog(const LLSD& notification, const LLSD& response )
|
||||
{
|
||||
S32 option = LLNotification::getSelectedOption(notification, response);
|
||||
if(option == 0)
|
||||
{
|
||||
saveCurrentWearables();
|
||||
}
|
||||
else
|
||||
{
|
||||
LLWearableType::EType cur = getCurrentWearableType();
|
||||
for(U32 i = 0;i < gAgentWearables.getWearableCount(cur);++i)
|
||||
{
|
||||
LLViewerWearable* wearable = gAgentWearables.getViewerWearable(cur,i);
|
||||
if(wearable && wearable->isDirty())
|
||||
{
|
||||
gAgentWearables.revertWearable( cur, i );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
mNextStepAfterSaveCallback(proceed);
|
||||
mNextStepAfterSaveCallback(option < 2);
|
||||
mNextStepAfterSaveCallback.disconnect_all_slots(); //Should this be done?
|
||||
|
||||
return false;
|
||||
|
||||
@@ -117,6 +117,7 @@ private:
|
||||
|
||||
public:
|
||||
void askToSaveIfDirty( boost::function<void (BOOL)> cb );
|
||||
void saveCurrentWearables();
|
||||
void switchToDefaultSubpart();
|
||||
|
||||
private:
|
||||
|
||||
@@ -741,7 +741,7 @@ void LLPanelLandGeneral::refresh()
|
||||
mBtnReleaseLand->setEnabled( can_release );
|
||||
}
|
||||
|
||||
BOOL use_pass = parcel->getParcelFlag(PF_USE_PASS_LIST) && !LLViewerParcelMgr::getInstance()->isCollisionBanned();;
|
||||
BOOL use_pass = parcel->getOwnerID()!= gAgent.getID() && parcel->getParcelFlag(PF_USE_PASS_LIST) && !LLViewerParcelMgr::getInstance()->isCollisionBanned();;
|
||||
mBtnBuyPass->setEnabled(use_pass);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4781,6 +4781,10 @@ void LLCallingCardBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((flags & FIRST_SELECTED_ITEM) == 0)
|
||||
{
|
||||
disabled_items.push_back(std::string("Open"));
|
||||
}
|
||||
addOpenRightClickMenuOption(items);
|
||||
items.push_back(std::string("Properties"));
|
||||
|
||||
@@ -5961,7 +5965,8 @@ void LLWearableBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
|
||||
}
|
||||
// [/RLVa:KB]*/
|
||||
|
||||
if ((flags & FIRST_SELECTED_ITEM) == 0)
|
||||
bool not_modifiable = !gAgentWearables.isWearableModifiable(item->getUUID());
|
||||
if (((flags & FIRST_SELECTED_ITEM) == 0) || not_modifiable)
|
||||
{
|
||||
disabled_items.push_back(std::string("Wearable Edit"));
|
||||
}
|
||||
|
||||
@@ -72,7 +72,6 @@ void LLManip::rebuild(LLViewerObject* vobj)
|
||||
LLDrawable* drawablep = vobj->mDrawable;
|
||||
if (drawablep && drawablep->getVOVolume())
|
||||
{
|
||||
|
||||
gPipeline.markRebuild(drawablep,LLDrawable::REBUILD_VOLUME, TRUE);
|
||||
drawablep->setState(LLDrawable::MOVE_UNDAMPED); // force to UNDAMPED
|
||||
drawablep->updateMove();
|
||||
@@ -82,6 +81,14 @@ void LLManip::rebuild(LLViewerObject* vobj)
|
||||
group->dirtyGeom();
|
||||
gPipeline.markRebuild(group, TRUE);
|
||||
}
|
||||
|
||||
LLViewerObject::const_child_list_t& child_list = vobj->getChildren();
|
||||
for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin(), endIter = child_list.end();
|
||||
iter != endIter; ++iter)
|
||||
{
|
||||
LLViewerObject* child = *iter;
|
||||
rebuild(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -92,7 +92,7 @@ void LLMorphView::initialize()
|
||||
}
|
||||
|
||||
gAgentAvatarp->stopMotion( ANIM_AGENT_BODY_NOISE );
|
||||
gAgentAvatarp->mSpecialRenderMode = 3;
|
||||
//gAgentAvatarp->mSpecialRenderMode = 3;
|
||||
|
||||
// set up camera for close look at avatar
|
||||
mOldCameraNearClip = LLViewerCamera::getInstance()->getNear();
|
||||
@@ -107,7 +107,7 @@ void LLMorphView::shutdown()
|
||||
if (isAgentAvatarValid())
|
||||
{
|
||||
gAgentAvatarp->startMotion( ANIM_AGENT_BODY_NOISE );
|
||||
gAgentAvatarp->mSpecialRenderMode = 0;
|
||||
//gAgentAvatarp->mSpecialRenderMode = 0;
|
||||
// reset camera
|
||||
LLViewerCamera::getInstance()->setNear(mOldCameraNearClip);
|
||||
}
|
||||
|
||||
@@ -1241,11 +1241,30 @@ void LLPanelEditWearable::saveChanges(bool force_save_as, std::string new_name)
|
||||
|
||||
U32 index = gAgentWearables.getWearableIndex(getWearable());
|
||||
|
||||
|
||||
// Find an existing link to this wearable's inventory item, if any, and its description field.
|
||||
LLInventoryItem *link_item = NULL;
|
||||
|
||||
std::string description;
|
||||
if(gAgentAvatarp->isUsingServerBakes())
|
||||
{
|
||||
LLInventoryModel::item_array_t links =
|
||||
LLAppearanceMgr::instance().findCOFItemLinks(getWearable()->getItemID());
|
||||
if (links.size()>0)
|
||||
{
|
||||
link_item = links.get(0).get();
|
||||
if (link_item && link_item->getIsLinkType())
|
||||
{
|
||||
description = link_item->getActualDescription();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (force_save_as)
|
||||
{
|
||||
// the name of the wearable has changed, re-save wearable with new name
|
||||
LLAppearanceMgr::instance().removeCOFItemLinks(getWearable()->getItemID());
|
||||
LLViewerWearable* new_wearable = gAgentWearables.saveWearableAs(mType, index, new_name, FALSE);
|
||||
LLViewerWearable* new_wearable = gAgentWearables.saveWearableAs(mType, index, new_name, description, FALSE);
|
||||
if(new_wearable)
|
||||
{
|
||||
mPendingWearable = new_wearable;
|
||||
@@ -1256,7 +1275,23 @@ void LLPanelEditWearable::saveChanges(bool force_save_as, std::string new_name)
|
||||
}
|
||||
else
|
||||
{
|
||||
gAgentWearables.saveWearable(mType, index, TRUE, new_name);
|
||||
// Make another copy of this link, with the same
|
||||
// description. This is needed to bump the COF
|
||||
// version so texture baking service knows appearance has changed.
|
||||
if (link_item)
|
||||
{
|
||||
// Create new link
|
||||
link_inventory_item( gAgent.getID(),
|
||||
link_item->getLinkedUUID(),
|
||||
LLAppearanceMgr::instance().getCOF(),
|
||||
link_item->getName(),
|
||||
description,
|
||||
LLAssetType::AT_LINK,
|
||||
NULL);
|
||||
// Remove old link
|
||||
gInventory.purgeObject(link_item->getUUID());
|
||||
}
|
||||
gAgentWearables.saveWearable(mType, index, TRUE, new_name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -430,7 +430,7 @@ void LLPanelPermissions::refresh()
|
||||
}
|
||||
}
|
||||
|
||||
childSetEnabled("button set group",owners_identical && (mOwnerID == gAgent.getID()) && is_nonpermanent_enforced);
|
||||
childSetEnabled("button set group",root_selected && owners_identical && (mOwnerID == gAgent.getID()) && is_nonpermanent_enforced);
|
||||
childSetEnabled("button open group", group_id.notNull());
|
||||
|
||||
// figure out the contents of the name, description, & category
|
||||
|
||||
152
indra/newview/llsimplestat.h
Normal file
152
indra/newview/llsimplestat.h
Normal file
@@ -0,0 +1,152 @@
|
||||
/**
|
||||
* @file llsimplestat.h
|
||||
* @brief Runtime statistics accumulation.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2010&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_SIMPLESTAT_H
|
||||
#define LL_SIMPLESTAT_H
|
||||
|
||||
// History
|
||||
//
|
||||
// The original source for this code is the server repositories'
|
||||
// llcommon/llstat.h file. This particular code was added after the
|
||||
// viewer/server code schism but before the effort to convert common
|
||||
// code to libraries was complete. Rather than add to merge issues,
|
||||
// the needed code was cut'n'pasted into this new header as it isn't
|
||||
// too awful a burden. Post-modularization, we can look at removing
|
||||
// this redundancy.
|
||||
|
||||
|
||||
/**
|
||||
* @class LLSimpleStatCounter
|
||||
* @brief Just counts events.
|
||||
*
|
||||
* Really not needed but have a pattern in mind in the future.
|
||||
* Interface limits what can be done at that's just fine.
|
||||
*
|
||||
* *TODO: Update/transfer unit tests
|
||||
* Unit tests: indra/test/llcommon_llstat_tut.cpp
|
||||
*/
|
||||
class LLSimpleStatCounter
|
||||
{
|
||||
public:
|
||||
inline LLSimpleStatCounter() { reset(); }
|
||||
// Default destructor and assignment operator are valid
|
||||
|
||||
inline void reset() { mCount = 0; }
|
||||
|
||||
inline void merge(const LLSimpleStatCounter & src)
|
||||
{ mCount += src.mCount; }
|
||||
|
||||
inline U32 operator++() { return ++mCount; }
|
||||
|
||||
inline U32 getCount() const { return mCount; }
|
||||
|
||||
protected:
|
||||
U32 mCount;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @class LLSimpleStatMMM
|
||||
* @brief Templated collector of min, max and mean data for stats.
|
||||
*
|
||||
* Fed a stream of data samples, keeps a running account of the
|
||||
* min, max and mean seen since construction or the last reset()
|
||||
* call. A freshly-constructed or reset instance returns counts
|
||||
* and values of zero.
|
||||
*
|
||||
* Overflows and underflows (integer, inf or -inf) and NaN's
|
||||
* are the caller's problem. As is loss of precision when
|
||||
* the running sum's exponent (when parameterized by a floating
|
||||
* point of some type) differs from a given data sample's.
|
||||
*
|
||||
* Unit tests: indra/test/llcommon_llstat_tut.cpp
|
||||
*/
|
||||
template <typename VALUE_T = F32>
|
||||
class LLSimpleStatMMM
|
||||
{
|
||||
public:
|
||||
typedef VALUE_T Value;
|
||||
|
||||
public:
|
||||
LLSimpleStatMMM() { reset(); }
|
||||
// Default destructor and assignment operator are valid
|
||||
|
||||
/**
|
||||
* Resets the object returning all counts and derived
|
||||
* values back to zero.
|
||||
*/
|
||||
void reset()
|
||||
{
|
||||
mCount = 0;
|
||||
mMin = Value(0);
|
||||
mMax = Value(0);
|
||||
mTotal = Value(0);
|
||||
}
|
||||
|
||||
void record(Value v)
|
||||
{
|
||||
if (mCount)
|
||||
{
|
||||
mMin = llmin(mMin, v);
|
||||
mMax = llmax(mMax, v);
|
||||
}
|
||||
else
|
||||
{
|
||||
mMin = v;
|
||||
mMax = v;
|
||||
}
|
||||
mTotal += v;
|
||||
++mCount;
|
||||
}
|
||||
|
||||
void merge(const LLSimpleStatMMM<VALUE_T> & src)
|
||||
{
|
||||
if (! mCount)
|
||||
{
|
||||
*this = src;
|
||||
}
|
||||
else if (src.mCount)
|
||||
{
|
||||
mMin = llmin(mMin, src.mMin);
|
||||
mMax = llmax(mMax, src.mMax);
|
||||
mCount += src.mCount;
|
||||
mTotal += src.mTotal;
|
||||
}
|
||||
}
|
||||
|
||||
inline U32 getCount() const { return mCount; }
|
||||
inline Value getMin() const { return mMin; }
|
||||
inline Value getMax() const { return mMax; }
|
||||
inline Value getMean() const { return mCount ? mTotal / mCount : mTotal; }
|
||||
|
||||
protected:
|
||||
U32 mCount;
|
||||
Value mMin;
|
||||
Value mMax;
|
||||
Value mTotal;
|
||||
};
|
||||
|
||||
#endif // LL_SIMPLESTAT_H
|
||||
@@ -224,6 +224,7 @@
|
||||
// </edit>
|
||||
|
||||
#include "llpathfindingmanager.h"
|
||||
#include "llevents.h"
|
||||
|
||||
#include "llavatarnamecache.h"
|
||||
#include "lgghunspell_wrapper.h"
|
||||
@@ -281,6 +282,11 @@ static LLHost gFirstSim;
|
||||
static std::string gFirstSimSeedCap;
|
||||
static LLVector3 gAgentStartLookAt(1.0f, 0.f, 0.f);
|
||||
static std::string gAgentStartLocation = "safe";
|
||||
|
||||
|
||||
boost::scoped_ptr<LLEventPump> LLStartUp::sStateWatcher(new LLEventStream("StartupState"));
|
||||
boost::scoped_ptr<LLViewerStats::PhaseMap> LLStartUp::sPhases(new LLViewerStats::PhaseMap);
|
||||
|
||||
//
|
||||
// local function declaration
|
||||
//
|
||||
@@ -423,6 +429,15 @@ bool idle_startup()
|
||||
|
||||
if ( STATE_FIRST == LLStartUp::getStartupState() )
|
||||
{
|
||||
static bool first_call = true;
|
||||
if (first_call)
|
||||
{
|
||||
// Other phases get handled when startup state changes,
|
||||
// need to capture the initial state as well.
|
||||
LLStartUp::getPhases().startPhase(LLStartUp::getStartupStateString());
|
||||
first_call = false;
|
||||
}
|
||||
|
||||
gViewerWindow->showCursor();
|
||||
gViewerWindow->getWindow()->setCursor(UI_CURSOR_WAIT);
|
||||
|
||||
@@ -1885,7 +1900,7 @@ bool idle_startup()
|
||||
display_startup();
|
||||
|
||||
//reset statistics
|
||||
LLViewerStats::getInstance()->resetStats();
|
||||
LLViewerStats::instance().resetStats();
|
||||
|
||||
if (!gNoRender)
|
||||
{
|
||||
@@ -3649,11 +3664,23 @@ std::string LLStartUp::startupStateToString(EStartupState state)
|
||||
void LLStartUp::setStartupState( EStartupState state )
|
||||
{
|
||||
LL_INFOS("AppInit") << "Startup state changing from " <<
|
||||
startupStateToString(gStartupState) << " to " <<
|
||||
getStartupStateString() << " to " <<
|
||||
startupStateToString(state) << LL_ENDL;
|
||||
|
||||
getPhases().stopPhase(getStartupStateString());
|
||||
gStartupState = state;
|
||||
getPhases().startPhase(getStartupStateString());
|
||||
|
||||
postStartupState();
|
||||
}
|
||||
|
||||
void LLStartUp::postStartupState()
|
||||
{
|
||||
LLSD stateInfo;
|
||||
stateInfo["str"] = getStartupStateString();
|
||||
stateInfo["enum"] = gStartupState;
|
||||
sStateWatcher->post(stateInfo);
|
||||
}
|
||||
|
||||
void reset_login()
|
||||
{
|
||||
|
||||
@@ -33,7 +33,12 @@
|
||||
#ifndef LL_LLSTARTUP_H
|
||||
#define LL_LLSTARTUP_H
|
||||
|
||||
class LLViewerTexture;
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
|
||||
class LLViewerTexture ;
|
||||
class LLEventPump;
|
||||
|
||||
#include "llviewerstats.h"
|
||||
|
||||
// functions
|
||||
bool idle_startup();
|
||||
@@ -101,7 +106,6 @@ public:
|
||||
|
||||
static void initNameCache();
|
||||
|
||||
|
||||
static void cleanupNameCache();
|
||||
|
||||
// outfit_folder_name can be a folder anywhere in your inventory,
|
||||
@@ -128,15 +132,20 @@ public:
|
||||
// if we have a SLURL or sim string ("Ahern/123/45") that started
|
||||
// the viewer, dispatch it
|
||||
|
||||
static void postStartupState();
|
||||
static std::string sSLURLCommand;
|
||||
// *HACK: On startup, if we were passed a secondlife://app/do/foo
|
||||
// command URL, store it for later processing.
|
||||
|
||||
static bool startLLProxy(); // Initialize the SOCKS 5 proxy
|
||||
|
||||
static LLViewerStats::PhaseMap& getPhases() { return *sPhases; }
|
||||
private:
|
||||
|
||||
static std::string startupStateToString(EStartupState state);
|
||||
static EStartupState gStartupState; // Do not set directly, use LLStartup::setStartupState
|
||||
static boost::scoped_ptr<LLEventPump> sStateWatcher;
|
||||
static boost::scoped_ptr<LLViewerStats::PhaseMap> sPhases;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -54,13 +54,17 @@
|
||||
#include "llviewerregion.h"
|
||||
#include "llviewerstats.h"
|
||||
#include "llviewerstatsrecorder.h"
|
||||
#include "llviewerassetstats.h"
|
||||
#include "llworld.h"
|
||||
#include "llsdutil.h"
|
||||
#include "llstartup.h"
|
||||
#include "llsdserialize.h"
|
||||
#include "llbuffer.h"
|
||||
|
||||
class AIHTTPTimeoutPolicy;
|
||||
extern AIHTTPTimeoutPolicy HTTPGetResponder_timeout;
|
||||
extern AIHTTPTimeoutPolicy lcl_responder_timeout;
|
||||
extern AIHTTPTimeoutPolicy assetReportHandler_timeout;
|
||||
|
||||
LLStat LLTextureFetch::sCacheHitRate("texture_cache_hits", 128);
|
||||
LLStat LLTextureFetch::sCacheReadLatency("texture_cache_read_latency", 128);
|
||||
@@ -200,6 +204,12 @@ private:
|
||||
bool processSimulatorPackets();
|
||||
bool writeToCacheComplete();
|
||||
|
||||
// Threads: Ttf
|
||||
void recordTextureStart(bool is_http);
|
||||
|
||||
// Threads: Ttf
|
||||
void recordTextureDone(bool is_http);
|
||||
|
||||
void lockWorkMutex() { mWorkMutex.lock(); }
|
||||
void unlockWorkMutex() { mWorkMutex.unlock(); }
|
||||
|
||||
@@ -295,6 +305,11 @@ private:
|
||||
S32 mLastPacket;
|
||||
U16 mTotalPackets;
|
||||
U8 mImageCodec;
|
||||
|
||||
LLViewerAssetStats::duration_t mMetricsStartTime;
|
||||
// State history
|
||||
U32 mCacheReadCount;
|
||||
U32 mCacheWriteCount;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
@@ -387,6 +402,7 @@ public:
|
||||
}
|
||||
|
||||
mFetcher->removeFromHTTPQueue(mID, data_size);
|
||||
worker->recordTextureDone(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -503,6 +519,229 @@ static bool sgConnectionThrottle() {
|
||||
}
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Cross-thread messaging for asset metrics.
|
||||
|
||||
/**
|
||||
* @brief Base class for cross-thread requests made of the fetcher
|
||||
*
|
||||
* I believe the intent of the LLQueuedThread class was to
|
||||
* have these operations derived from LLQueuedThread::QueuedRequest
|
||||
* but the texture fetcher has elected to manage the queue
|
||||
* in its own manner. So these are free-standing objects which are
|
||||
* managed in simple FIFO order on the mCommands queue of the
|
||||
* LLTextureFetch object.
|
||||
*
|
||||
* What each represents is a simple command sent from an
|
||||
* outside thread into the TextureFetch thread to be processed
|
||||
* in order and in a timely fashion (though not an absolute
|
||||
* higher priority than other operations of the thread).
|
||||
* Each operation derives a new class from the base customizing
|
||||
* members, constructors and the doWork() method to effect
|
||||
* the command.
|
||||
*
|
||||
* The flow is one-directional. There are two global instances
|
||||
* of the LLViewerAssetStats collector, one for the main program's
|
||||
* thread pointed to by gViewerAssetStatsMain and one for the
|
||||
* TextureFetch thread pointed to by gViewerAssetStatsThread1.
|
||||
* Common operations has each thread recording metrics events
|
||||
* into the respective collector unconcerned with locking and
|
||||
* the state of any other thread. But when the agent moves into
|
||||
* a different region or the metrics timer expires and a report
|
||||
* needs to be sent back to the grid, messaging across threads
|
||||
* is required to distribute data and perform global actions.
|
||||
* In pseudo-UML, it looks like:
|
||||
*
|
||||
* Main Thread1
|
||||
* . .
|
||||
* . .
|
||||
* +-----+ .
|
||||
* | AM | .
|
||||
* +--+--+ .
|
||||
* +-------+ | .
|
||||
* | Main | +--+--+ .
|
||||
* | | | SRE |---. .
|
||||
* | Stats | +-----+ \ .
|
||||
* | | | \ (uuid) +-----+
|
||||
* | Coll. | +--+--+ `-------->| SR |
|
||||
* +-------+ | MSC | +--+--+
|
||||
* | ^ +-----+ |
|
||||
* | | (uuid) / . +-----+ (uuid)
|
||||
* | `--------' . | MSC |---------.
|
||||
* | . +-----+ |
|
||||
* | +-----+ . v
|
||||
* | | TE | . +-------+
|
||||
* | +--+--+ . | Thd1 |
|
||||
* | | . | |
|
||||
* | +-----+ . | Stats |
|
||||
* `--------->| RSC | . | |
|
||||
* +--+--+ . | Coll. |
|
||||
* | . +-------+
|
||||
* +--+--+ . |
|
||||
* | SME |---. . |
|
||||
* +-----+ \ . |
|
||||
* . \ (clone) +-----+ |
|
||||
* . `-------->| SM | |
|
||||
* . +--+--+ |
|
||||
* . | |
|
||||
* . +-----+ |
|
||||
* . | RSC |<--------'
|
||||
* . +-----+
|
||||
* . |
|
||||
* . +-----+
|
||||
* . | CP |--> HTTP POST
|
||||
* . +-----+
|
||||
* . .
|
||||
* . .
|
||||
*
|
||||
*
|
||||
* Key:
|
||||
*
|
||||
* SRE - Set Region Enqueued. Enqueue a 'Set Region' command in
|
||||
* the other thread providing the new UUID of the region.
|
||||
* TFReqSetRegion carries the data.
|
||||
* SR - Set Region. New region UUID is sent to the thread-local
|
||||
* collector.
|
||||
* SME - Send Metrics Enqueued. Enqueue a 'Send Metrics' command
|
||||
* including an ownership transfer of a cloned LLViewerAssetStats.
|
||||
* TFReqSendMetrics carries the data.
|
||||
* SM - Send Metrics. Global metrics reporting operation. Takes
|
||||
* the cloned stats from the command, merges it with the
|
||||
* thread's local stats, converts to LLSD and sends it on
|
||||
* to the grid.
|
||||
* AM - Agent Moved. Agent has completed some sort of move to a
|
||||
* new region.
|
||||
* TE - Timer Expired. Metrics timer has expired (on the order
|
||||
* of 10 minutes).
|
||||
* CP - CURL Post
|
||||
* MSC - Modify Stats Collector. State change in the thread-local
|
||||
* collector. Typically a region change which affects the
|
||||
* global pointers used to find the 'current stats'.
|
||||
* RSC - Read Stats Collector. Extract collector data cloning it
|
||||
* (i.e. deep copy) when necessary.
|
||||
*
|
||||
*/
|
||||
class LLTextureFetch::TFRequest // : public LLQueuedThread::QueuedRequest
|
||||
{
|
||||
public:
|
||||
// Default ctors and assignment operator are correct.
|
||||
|
||||
virtual ~TFRequest()
|
||||
{}
|
||||
|
||||
// Patterned after QueuedRequest's method but expected behavior
|
||||
// is different. Always expected to complete on the first call
|
||||
// and work dispatcher will assume the same and delete the
|
||||
// request after invocation.
|
||||
virtual bool doWork(LLTextureFetch * fetcher) = 0;
|
||||
};
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief Implements a 'Set Region' cross-thread command.
|
||||
*
|
||||
* When an agent moves to a new region, subsequent metrics need
|
||||
* to be binned into a new or existing stats collection in 1:1
|
||||
* relationship with the region. We communicate this region
|
||||
* change across the threads involved in the communication with
|
||||
* this message.
|
||||
*
|
||||
* Corresponds to LLTextureFetch::commandSetRegion()
|
||||
*/
|
||||
class TFReqSetRegion : public LLTextureFetch::TFRequest
|
||||
{
|
||||
public:
|
||||
TFReqSetRegion(U64 region_handle)
|
||||
: LLTextureFetch::TFRequest(),
|
||||
mRegionHandle(region_handle)
|
||||
{}
|
||||
TFReqSetRegion & operator=(const TFReqSetRegion &); // Not defined
|
||||
|
||||
virtual ~TFReqSetRegion()
|
||||
{}
|
||||
|
||||
virtual bool doWork(LLTextureFetch * fetcher);
|
||||
|
||||
public:
|
||||
const U64 mRegionHandle;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Implements a 'Send Metrics' cross-thread command.
|
||||
*
|
||||
* This is the big operation. The main thread gathers metrics
|
||||
* for a period of minutes into LLViewerAssetStats and other
|
||||
* objects then makes a snapshot of the data by cloning the
|
||||
* collector. This command transfers the clone, along with a few
|
||||
* additional arguments (UUIDs), handing ownership to the
|
||||
* TextureFetch thread. It then merges its own data into the
|
||||
* cloned copy, converts to LLSD and kicks off an HTTP POST of
|
||||
* the resulting data to the currently active metrics collector.
|
||||
*
|
||||
* Corresponds to LLTextureFetch::commandSendMetrics()
|
||||
*/
|
||||
class TFReqSendMetrics : public LLTextureFetch::TFRequest
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Construct the 'Send Metrics' command to have the TextureFetch
|
||||
* thread add and log metrics data.
|
||||
*
|
||||
* @param caps_url URL of a "ViewerMetrics" Caps target
|
||||
* to receive the data. Does not have to
|
||||
* be associated with a particular region.
|
||||
*
|
||||
* @param session_id UUID of the agent's session.
|
||||
*
|
||||
* @param agent_id UUID of the agent. (Being pure here...)
|
||||
*
|
||||
* @param main_stats Pointer to a clone of the main thread's
|
||||
* LLViewerAssetStats data. Thread1 takes
|
||||
* ownership of the copy and disposes of it
|
||||
* when done.
|
||||
*/
|
||||
TFReqSendMetrics(const std::string & caps_url,
|
||||
const LLUUID & session_id,
|
||||
const LLUUID & agent_id,
|
||||
LLViewerAssetStats * main_stats)
|
||||
: LLTextureFetch::TFRequest(),
|
||||
mCapsURL(caps_url),
|
||||
mSessionID(session_id),
|
||||
mAgentID(agent_id),
|
||||
mMainStats(main_stats)
|
||||
{}
|
||||
TFReqSendMetrics & operator=(const TFReqSendMetrics &); // Not defined
|
||||
|
||||
virtual ~TFReqSendMetrics();
|
||||
|
||||
virtual bool doWork(LLTextureFetch * fetcher);
|
||||
|
||||
public:
|
||||
const std::string mCapsURL;
|
||||
const LLUUID mSessionID;
|
||||
const LLUUID mAgentID;
|
||||
LLViewerAssetStats * mMainStats;
|
||||
};
|
||||
|
||||
/*
|
||||
* Examines the merged viewer metrics report and if found to be too long,
|
||||
* will attempt to truncate it in some reasonable fashion.
|
||||
*
|
||||
* @param max_regions Limit of regions allowed in report.
|
||||
*
|
||||
* @param metrics Full, merged viewer metrics report.
|
||||
*
|
||||
* @returns If data was truncated, returns true.
|
||||
*/
|
||||
bool truncate_viewer_metrics(int max_regions, LLSD & metrics);
|
||||
|
||||
} // end of anonymous namespace
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//static
|
||||
@@ -522,6 +761,9 @@ const char* LLTextureFetchWorker::sStateDescs[] = {
|
||||
"DONE",
|
||||
};
|
||||
|
||||
// static
|
||||
volatile bool LLTextureFetch::svMetricsDataBreak(true); // Start with a data break
|
||||
|
||||
// called from MAIN THREAD
|
||||
|
||||
LLTextureFetchWorker::LLTextureFetchWorker(LLTextureFetch* fetcher,
|
||||
@@ -570,7 +812,10 @@ LLTextureFetchWorker::LLTextureFetchWorker(LLTextureFetch* fetcher,
|
||||
mFirstPacket(0),
|
||||
mLastPacket(-1),
|
||||
mTotalPackets(0),
|
||||
mImageCodec(IMG_CODEC_INVALID)
|
||||
mImageCodec(IMG_CODEC_INVALID),
|
||||
mMetricsStartTime(0),
|
||||
mCacheReadCount(0U),
|
||||
mCacheWriteCount(0U)
|
||||
{
|
||||
mCanUseNET = mUrl.empty() ;
|
||||
|
||||
@@ -605,6 +850,7 @@ LLTextureFetchWorker::~LLTextureFetchWorker()
|
||||
clearPackets();
|
||||
unlockWorkMutex();
|
||||
mFetcher->removeFromHTTPQueue(mID);
|
||||
mFetcher->updateStateStats(mCacheReadCount, mCacheWriteCount);
|
||||
}
|
||||
|
||||
void LLTextureFetchWorker::clearPackets()
|
||||
@@ -818,6 +1064,7 @@ bool LLTextureFetchWorker::doWork(S32 param)
|
||||
setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); // Set priority first since Responder may change it
|
||||
|
||||
// read file from local disk
|
||||
++mCacheReadCount;
|
||||
std::string filename = mUrl.substr(7, std::string::npos);
|
||||
CacheReadResponder* responder = new CacheReadResponder(mFetcher, mID, mFormattedImage);
|
||||
mCacheReadHandle = mFetcher->mTextureCache->readFromCache(filename, mID, cache_priority,
|
||||
@@ -828,6 +1075,7 @@ bool LLTextureFetchWorker::doWork(S32 param)
|
||||
{
|
||||
setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); // Set priority first since Responder may change it
|
||||
|
||||
++mCacheReadCount;
|
||||
CacheReadResponder* responder = new CacheReadResponder(mFetcher, mID, mFormattedImage);
|
||||
mCacheReadHandle = mFetcher->mTextureCache->readFromCache(mID, cache_priority,
|
||||
offset, size, responder);
|
||||
@@ -963,6 +1211,7 @@ bool LLTextureFetchWorker::doWork(S32 param)
|
||||
mRequestedDiscard = mDesiredDiscard;
|
||||
mSentRequest = QUEUED;
|
||||
mFetcher->addToNetworkQueue(this);
|
||||
recordTextureStart(false);
|
||||
setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
|
||||
|
||||
return false;
|
||||
@@ -997,11 +1246,13 @@ bool LLTextureFetchWorker::doWork(S32 param)
|
||||
setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
|
||||
mState = DECODE_IMAGE;
|
||||
mWriteToCacheState = SHOULD_WRITE;
|
||||
recordTextureDone(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
mFetcher->addToNetworkQueue(this); // failsafe
|
||||
setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
|
||||
recordTextureStart(false);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -1404,6 +1655,7 @@ bool LLTextureFetchWorker::doWork(S32 param)
|
||||
U32 cache_priority = mWorkPriority;
|
||||
mWritten = FALSE;
|
||||
mState = WAIT_ON_WRITE;
|
||||
++mCacheWriteCount;
|
||||
CacheWriteResponder* responder = new CacheWriteResponder(mFetcher, mID);
|
||||
mCacheWriteHandle = mFetcher->mTextureCache->writeToCache(mID, cache_priority,
|
||||
mFormattedImage->getData(), datasize,
|
||||
@@ -1762,6 +2014,35 @@ bool LLTextureFetchWorker::writeToCacheComplete()
|
||||
}
|
||||
|
||||
|
||||
// Threads: Ttf
|
||||
void LLTextureFetchWorker::recordTextureStart(bool is_http)
|
||||
{
|
||||
if (! mMetricsStartTime)
|
||||
{
|
||||
mMetricsStartTime = LLViewerAssetStatsFF::get_timestamp();
|
||||
}
|
||||
LLViewerAssetStatsFF::record_enqueue_thread1(LLViewerAssetType::AT_TEXTURE,
|
||||
is_http,
|
||||
LLImageBase::TYPE_AVATAR_BAKE == mType);
|
||||
}
|
||||
|
||||
|
||||
// Threads: Ttf
|
||||
void LLTextureFetchWorker::recordTextureDone(bool is_http)
|
||||
{
|
||||
if (mMetricsStartTime)
|
||||
{
|
||||
LLViewerAssetStatsFF::record_response_thread1(LLViewerAssetType::AT_TEXTURE,
|
||||
is_http,
|
||||
LLImageBase::TYPE_AVATAR_BAKE == mType,
|
||||
LLViewerAssetStatsFF::get_timestamp() - mMetricsStartTime);
|
||||
mMetricsStartTime = 0;
|
||||
}
|
||||
LLViewerAssetStatsFF::record_dequeue_thread1(LLViewerAssetType::AT_TEXTURE,
|
||||
is_http,
|
||||
LLImageBase::TYPE_AVATAR_BAKE == mType);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// public
|
||||
@@ -1776,7 +2057,10 @@ LLTextureFetch::LLTextureFetch(LLTextureCache* cache, LLImageDecodeThread* image
|
||||
mImageDecodeThread(imagedecodethread),
|
||||
mTextureBandwidth(0),
|
||||
mHTTPTextureBits(0),
|
||||
mTotalHTTPRequests(0)
|
||||
mTotalHTTPRequests(0),
|
||||
mQAMode(qa_mode),
|
||||
mTotalCacheReadCount(0U),
|
||||
mTotalCacheWriteCount(0U)
|
||||
{
|
||||
mTextureInfo.setUpLogging(gSavedSettings.getBOOL("LogTextureDownloadsToViewerLog"), gSavedSettings.getBOOL("LogTextureDownloadsToSimulator"), gSavedSettings.getU32("TextureLoggingThreshold"));
|
||||
}
|
||||
@@ -2108,6 +2392,7 @@ S32 LLTextureFetch::getPending()
|
||||
return res;
|
||||
}
|
||||
|
||||
// Locks: Ct
|
||||
// virtual
|
||||
bool LLTextureFetch::runCondition()
|
||||
{
|
||||
@@ -2120,7 +2405,15 @@ bool LLTextureFetch::runCondition()
|
||||
//
|
||||
// Changes here may need to be reflected in getPending().
|
||||
|
||||
return ! (mRequestQueue.empty() && mIdleThread); // From base class
|
||||
bool have_no_commands(false);
|
||||
{
|
||||
LLMutexLock lock(&mQueueMutex); // +Mfq
|
||||
|
||||
have_no_commands = mCommands.empty();
|
||||
} // -Mfq
|
||||
|
||||
return ! (have_no_commands
|
||||
&& (mRequestQueue.empty() && mIdleThread)); // From base class
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
@@ -2128,6 +2421,8 @@ bool LLTextureFetch::runCondition()
|
||||
// MAIN THREAD (unthreaded envs), WORKER THREAD (threaded envs)
|
||||
void LLTextureFetch::commonUpdate()
|
||||
{
|
||||
// Run a cross-thread command, if any.
|
||||
cmdDoWork();
|
||||
}
|
||||
|
||||
|
||||
@@ -2185,7 +2480,21 @@ void LLTextureFetch::shutDownImageDecodeThread()
|
||||
}
|
||||
}
|
||||
|
||||
// WORKER THREAD
|
||||
// Threads: Ttf
|
||||
void LLTextureFetch::startThread()
|
||||
{
|
||||
}
|
||||
|
||||
// Threads: Ttf
|
||||
void LLTextureFetch::endThread()
|
||||
{
|
||||
LL_INFOS("Texture") << "CacheReads: " << mTotalCacheReadCount
|
||||
<< ", CacheWrites: " << mTotalCacheWriteCount
|
||||
<< ", TotalHTTPReq: " << getTotalNumHTTPRequests()
|
||||
<< LL_ENDL;
|
||||
}
|
||||
|
||||
// Threads: Ttf
|
||||
void LLTextureFetch::threadedUpdate()
|
||||
{
|
||||
// Limit update frequency
|
||||
@@ -2480,10 +2789,10 @@ bool LLTextureFetch::receiveImageHeader(const LLHost& host, const LLUUID& id, U8
|
||||
}
|
||||
if (!res)
|
||||
{
|
||||
mNetworkQueueMutex.lock(); // +Mfnq
|
||||
++mBadPacketCount;
|
||||
mNetworkQueueMutex.lock() ;
|
||||
mCancelQueue[host].insert(id);
|
||||
mNetworkQueueMutex.unlock() ;
|
||||
mNetworkQueueMutex.unlock(); // -Mfnq
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -2530,10 +2839,10 @@ bool LLTextureFetch::receiveImagePacket(const LLHost& host, const LLUUID& id, U1
|
||||
}
|
||||
if (!res)
|
||||
{
|
||||
mNetworkQueueMutex.lock(); // +Mfnq
|
||||
++mBadPacketCount;
|
||||
mNetworkQueueMutex.lock() ;
|
||||
mCancelQueue[host].insert(id);
|
||||
mNetworkQueueMutex.unlock() ;
|
||||
mNetworkQueueMutex.unlock(); // -Mfnq
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -2664,3 +2973,264 @@ void LLTextureFetch::dump()
|
||||
llinfos << " ID: " << (*iter) << llendl;
|
||||
}
|
||||
}
|
||||
|
||||
// Threads: T*
|
||||
void LLTextureFetch::updateStateStats(U32 cache_read, U32 cache_write)
|
||||
{
|
||||
LLMutexLock lock(&mQueueMutex); // +Mfq
|
||||
|
||||
mTotalCacheReadCount += cache_read;
|
||||
mTotalCacheWriteCount += cache_write;
|
||||
} // -Mfq
|
||||
|
||||
|
||||
// Threads: T*
|
||||
void LLTextureFetch::getStateStats(U32 * cache_read, U32 * cache_write)
|
||||
{
|
||||
U32 ret1(0U), ret2(0U);
|
||||
|
||||
{
|
||||
LLMutexLock lock(&mQueueMutex); // +Mfq
|
||||
ret1 = mTotalCacheReadCount;
|
||||
ret2 = mTotalCacheWriteCount;
|
||||
} // -Mfq
|
||||
|
||||
*cache_read = ret1;
|
||||
*cache_write = ret2;
|
||||
}
|
||||
// Threads: T*
|
||||
void LLTextureFetch::commandSetRegion(U64 region_handle)
|
||||
{
|
||||
TFReqSetRegion * req = new TFReqSetRegion(region_handle);
|
||||
|
||||
cmdEnqueue(req);
|
||||
}
|
||||
|
||||
// Threads: T*
|
||||
void LLTextureFetch::commandSendMetrics(const std::string & caps_url,
|
||||
const LLUUID & session_id,
|
||||
const LLUUID & agent_id,
|
||||
LLViewerAssetStats * main_stats)
|
||||
{
|
||||
TFReqSendMetrics * req = new TFReqSendMetrics(caps_url, session_id, agent_id, main_stats);
|
||||
|
||||
cmdEnqueue(req);
|
||||
}
|
||||
// Threads: T*
|
||||
void LLTextureFetch::commandDataBreak()
|
||||
{
|
||||
// The pedantically correct way to implement this is to create a command
|
||||
// request object in the above fashion and enqueue it. However, this is
|
||||
// simple data of an advisorial not operational nature and this case
|
||||
// of shared-write access is tolerable.
|
||||
|
||||
LLTextureFetch::svMetricsDataBreak = true;
|
||||
}
|
||||
|
||||
// Threads: T*
|
||||
void LLTextureFetch::cmdEnqueue(TFRequest * req)
|
||||
{
|
||||
lockQueue(); // +Mfq
|
||||
mCommands.push_back(req);
|
||||
unlockQueue(); // -Mfq
|
||||
|
||||
unpause();
|
||||
}
|
||||
|
||||
// Threads: T*
|
||||
LLTextureFetch::TFRequest * LLTextureFetch::cmdDequeue()
|
||||
{
|
||||
TFRequest * ret = 0;
|
||||
|
||||
lockQueue(); // +Mfq
|
||||
if (! mCommands.empty())
|
||||
{
|
||||
ret = mCommands.front();
|
||||
mCommands.erase(mCommands.begin());
|
||||
}
|
||||
unlockQueue(); // -Mfq
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Threads: Ttf
|
||||
void LLTextureFetch::cmdDoWork()
|
||||
{
|
||||
if (mDebugPause)
|
||||
{
|
||||
return; // debug: don't do any work
|
||||
}
|
||||
|
||||
TFRequest * req = cmdDequeue();
|
||||
if (req)
|
||||
{
|
||||
// One request per pass should really be enough for this.
|
||||
req->doWork(this);
|
||||
delete req;
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Private (anonymous) class methods implementing the command scheme.
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
|
||||
// Example of a simple notification handler for metrics
|
||||
// delivery notification. Earlier versions of the code used
|
||||
// a Responder that tried harder to detect delivery breaks
|
||||
// but it really isn't that important. If someone wants to
|
||||
// revisit that effort, here is a place to start.
|
||||
class AssetReportHandler : public LLHTTPClient::ResponderWithCompleted
|
||||
{
|
||||
public:
|
||||
|
||||
// Threads: Ttf
|
||||
/*virtual*/ virtual void completed(U32 status, std::string const& reason, LLSD const& content)
|
||||
{
|
||||
if (status)
|
||||
{
|
||||
LL_WARNS("Texture") << "Successfully delivered asset metrics to grid."
|
||||
<< LL_ENDL;
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS("Texture") << "Error delivering asset metrics to grid. Reason: "
|
||||
<< status << LL_ENDL;
|
||||
}
|
||||
}
|
||||
|
||||
/*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return assetReportHandler_timeout; }
|
||||
/*virtual*/ char const* getName(void) const { return "AssetReportHandler"; }
|
||||
}; // end class AssetReportHandler
|
||||
|
||||
|
||||
/**
|
||||
* Implements the 'Set Region' command.
|
||||
*
|
||||
* Thread: Thread1 (TextureFetch)
|
||||
*/
|
||||
bool
|
||||
TFReqSetRegion::doWork(LLTextureFetch *)
|
||||
{
|
||||
LLViewerAssetStatsFF::set_region_thread1(mRegionHandle);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
TFReqSendMetrics::~TFReqSendMetrics()
|
||||
{
|
||||
delete mMainStats;
|
||||
mMainStats = 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Implements the 'Send Metrics' command. Takes over
|
||||
* ownership of the passed LLViewerAssetStats pointer.
|
||||
*
|
||||
* Thread: Thread1 (TextureFetch)
|
||||
*/
|
||||
bool
|
||||
TFReqSendMetrics::doWork(LLTextureFetch * fetcher)
|
||||
{
|
||||
static const U32 report_priority(1);
|
||||
|
||||
if (! gViewerAssetStatsThread1)
|
||||
return true;
|
||||
|
||||
static volatile bool reporting_started(false);
|
||||
static volatile S32 report_sequence(0);
|
||||
|
||||
// We've taken over ownership of the stats copy at this
|
||||
// point. Get a working reference to it for merging here
|
||||
// but leave it in 'this'. Destructor will rid us of it.
|
||||
LLViewerAssetStats & main_stats = *mMainStats;
|
||||
|
||||
// Merge existing stats into those from main, convert to LLSD
|
||||
main_stats.merge(*gViewerAssetStatsThread1);
|
||||
LLSD merged_llsd = main_stats.asLLSD(true);
|
||||
|
||||
// Add some additional meta fields to the content
|
||||
merged_llsd["session_id"] = mSessionID;
|
||||
merged_llsd["agent_id"] = mAgentID;
|
||||
merged_llsd["message"] = "ViewerAssetMetrics"; // Identifies the type of metrics
|
||||
merged_llsd["sequence"] = report_sequence; // Sequence number
|
||||
merged_llsd["initial"] = ! reporting_started; // Initial data from viewer
|
||||
merged_llsd["break"] = LLTextureFetch::svMetricsDataBreak; // Break in data prior to this report
|
||||
|
||||
// Update sequence number
|
||||
if (S32_MAX == ++report_sequence)
|
||||
report_sequence = 0;
|
||||
reporting_started = true;
|
||||
|
||||
// Limit the size of the stats report if necessary.
|
||||
merged_llsd["truncated"] = truncate_viewer_metrics(10, merged_llsd);
|
||||
|
||||
if (! mCapsURL.empty())
|
||||
{
|
||||
if(fetcher->isQAMode() || true) //Assuming the 'true' will vanish eventually.
|
||||
LLHTTPClient::post(mCapsURL, merged_llsd, new AssetReportHandler());
|
||||
else
|
||||
LLHTTPClient::post(mCapsURL, merged_llsd, new LLHTTPClient::ResponderIgnore());
|
||||
LLTextureFetch::svMetricsDataBreak = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
LLTextureFetch::svMetricsDataBreak = true;
|
||||
}
|
||||
|
||||
// In QA mode, Metrics submode, log the result for ease of testing
|
||||
if (fetcher->isQAMode())
|
||||
{
|
||||
LL_INFOS("Textures") << ll_pretty_print_sd(merged_llsd) << LL_ENDL;
|
||||
}
|
||||
|
||||
gViewerAssetStatsThread1->reset();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
truncate_viewer_metrics(int max_regions, LLSD & metrics)
|
||||
{
|
||||
static const LLSD::String reg_tag("regions");
|
||||
static const LLSD::String duration_tag("duration");
|
||||
|
||||
LLSD & reg_map(metrics[reg_tag]);
|
||||
if (reg_map.size() <= max_regions)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Build map of region hashes ordered by duration
|
||||
typedef std::multimap<LLSD::Real, int> reg_ordered_list_t;
|
||||
reg_ordered_list_t regions_by_duration;
|
||||
|
||||
int ind(0);
|
||||
LLSD::array_const_iterator it_end(reg_map.endArray());
|
||||
for (LLSD::array_const_iterator it(reg_map.beginArray()); it_end != it; ++it, ++ind)
|
||||
{
|
||||
LLSD::Real duration = (*it)[duration_tag].asReal();
|
||||
regions_by_duration.insert(reg_ordered_list_t::value_type(duration, ind));
|
||||
}
|
||||
|
||||
// Build a replacement regions array with the longest-persistence regions
|
||||
LLSD new_region(LLSD::emptyArray());
|
||||
reg_ordered_list_t::const_reverse_iterator it2_end(regions_by_duration.rend());
|
||||
reg_ordered_list_t::const_reverse_iterator it2(regions_by_duration.rbegin());
|
||||
for (int i(0); i < max_regions && it2_end != it2; ++i, ++it2)
|
||||
{
|
||||
new_region.append(reg_map[it2->second]);
|
||||
}
|
||||
reg_map = new_region;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // end of anonymous namespace
|
||||
|
||||
|
||||
@@ -33,19 +33,24 @@
|
||||
#ifndef LL_LLTEXTUREFETCH_H
|
||||
#define LL_LLTEXTUREFETCH_H
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
#include "lldir.h"
|
||||
#include "llimage.h"
|
||||
#include "lluuid.h"
|
||||
#include "llworkerthread.h"
|
||||
#include "lltextureinfo.h"
|
||||
#include "llapr.h"
|
||||
#include "llstat.h"
|
||||
|
||||
class LLViewerTexture;
|
||||
class LLTextureFetchWorker;
|
||||
class HTTPGetResponder;
|
||||
class LLTextureCache;
|
||||
class LLImageDecodeThread;
|
||||
class LLHost;
|
||||
class LLViewerAssetStats;
|
||||
class LLTextureCache;
|
||||
|
||||
// Interface class
|
||||
class LLTextureFetch : public LLWorkerThread
|
||||
@@ -93,8 +98,23 @@ public:
|
||||
LLTextureFetchWorker* getWorker(const LLUUID& id);
|
||||
LLTextureFetchWorker* getWorkerAfterLock(const LLUUID& id);
|
||||
|
||||
LLTextureInfo* getTextureInfo() { return &mTextureInfo; }
|
||||
// Commands available to other threads to control metrics gathering operations.
|
||||
|
||||
// Threads: T*
|
||||
void commandSetRegion(U64 region_handle);
|
||||
|
||||
// Threads: T*
|
||||
void commandSendMetrics(const std::string & caps_url,
|
||||
const LLUUID & session_id,
|
||||
const LLUUID & agent_id,
|
||||
LLViewerAssetStats * main_stats);
|
||||
|
||||
// Threads: T*
|
||||
void commandDataBreak();
|
||||
|
||||
bool isQAMode() const { return mQAMode; }
|
||||
void updateStateStats(U32 cache_read, U32 cache_write);
|
||||
void getStateStats(U32 * cache_read, U32 * cache_write);
|
||||
protected:
|
||||
void addToNetworkQueue(LLTextureFetchWorker* worker);
|
||||
void removeFromNetworkQueue(LLTextureFetchWorker* worker, bool cancel);
|
||||
@@ -107,9 +127,14 @@ protected:
|
||||
|
||||
private:
|
||||
void sendRequestListToSimulators();
|
||||
/*virtual*/ void startThread(void);
|
||||
/*virtual*/ void endThread(void);
|
||||
/*virtual*/ void threadedUpdate(void);
|
||||
void commonUpdate();
|
||||
|
||||
void cmdEnqueue(TFRequest *);
|
||||
TFRequest * cmdDequeue();
|
||||
void cmdDoWork();
|
||||
|
||||
public:
|
||||
LLUUID mDebugID;
|
||||
@@ -148,6 +173,25 @@ private:
|
||||
//debug use
|
||||
U32 mTotalHTTPRequests ;
|
||||
|
||||
// Out-of-band cross-thread command queue. This command queue
|
||||
// is logically tied to LLQueuedThread's list of
|
||||
// QueuedRequest instances and so must be covered by the
|
||||
// same locks.
|
||||
typedef std::vector<TFRequest *> command_queue_t;
|
||||
command_queue_t mCommands;
|
||||
|
||||
// If true, modifies some behaviors that help with QA tasks.
|
||||
const bool mQAMode;
|
||||
// Cumulative stats on the states/requests issued by
|
||||
// textures running through here.
|
||||
U32 mTotalCacheReadCount;
|
||||
U32 mTotalCacheWriteCount;
|
||||
|
||||
public:
|
||||
// A probabilistically-correct indicator that the current
|
||||
// attempt to log metrics follows a break in the metrics stream
|
||||
// reporting due to either startup or a problem POSTing data.
|
||||
static volatile bool svMetricsDataBreak;
|
||||
};
|
||||
|
||||
#endif // LL_LLTEXTUREFETCH_H
|
||||
|
||||
@@ -57,6 +57,7 @@
|
||||
#include "llviewerwindow.h"
|
||||
#include "llvoavatarself.h"
|
||||
#include "llmorphview.h"
|
||||
#include "llfloatercustomize.h"
|
||||
|
||||
// Globals
|
||||
BOOL gCameraBtnZoom = TRUE;
|
||||
@@ -232,6 +233,7 @@ void LLToolCamera::pickCallback(const LLPickInfo& pick_info)
|
||||
|
||||
if( CAMERA_MODE_CUSTOMIZE_AVATAR == gAgentCamera.getCameraMode() )
|
||||
{
|
||||
if(CAMERA_MODE_CUSTOMIZE_AVATAR == gAgentCamera.getCameraMode())
|
||||
gAgentCamera.setFocusOnAvatar(FALSE, FALSE);
|
||||
|
||||
LLVector3d cam_pos = gAgentCamera.getCameraPositionGlobal();
|
||||
|
||||
611
indra/newview/llviewerassetstats.cpp
Normal file
611
indra/newview/llviewerassetstats.cpp
Normal file
@@ -0,0 +1,611 @@
|
||||
/**
|
||||
* @file llviewerassetstats.cpp
|
||||
* @brief
|
||||
*
|
||||
* $LicenseInfo:firstyear=2010&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$
|
||||
*/
|
||||
|
||||
#include "llviewerprecompiledheaders.h"
|
||||
|
||||
#include "llviewerassetstats.h"
|
||||
#include "llregionhandle.h"
|
||||
|
||||
#include "stdtypes.h"
|
||||
|
||||
/*
|
||||
* Classes and utility functions for per-thread and per-region
|
||||
* asset and experiential metrics to be aggregated grid-wide.
|
||||
*
|
||||
* The basic metrics grouping is LLViewerAssetStats::PerRegionStats.
|
||||
* This provides various counters and simple statistics for asset
|
||||
* fetches binned into a few categories. One of these is maintained
|
||||
* for each region encountered and the 'current' region is available
|
||||
* as a simple reference. Each thread (presently two) interested
|
||||
* in participating in these stats gets an instance of the
|
||||
* LLViewerAssetStats class so that threads are completely
|
||||
* independent.
|
||||
*
|
||||
* The idea of a current region is used for simplicity and speed
|
||||
* of categorization. Each metrics event could have taken a
|
||||
* region uuid argument resulting in a suitable lookup. Arguments
|
||||
* against this design include:
|
||||
*
|
||||
* - Region uuid not trivially available to caller.
|
||||
* - Cost (cpu, disruption in real work flow) too high.
|
||||
* - Additional precision not really meaningful.
|
||||
*
|
||||
* By itself, the LLViewerAssetStats class is thread- and
|
||||
* viewer-agnostic and can be used anywhere without assumptions
|
||||
* of global pointers and other context. For the viewer,
|
||||
* a set of free functions are provided in the namespace
|
||||
* LLViewerAssetStatsFF which *do* implement viewer-native
|
||||
* policies about per-thread globals and will do correct
|
||||
* defensive tests of same.
|
||||
*
|
||||
* References
|
||||
*
|
||||
* Project:
|
||||
* <TBD>
|
||||
*
|
||||
* Test Plan:
|
||||
* <TBD>
|
||||
*
|
||||
* Jiras:
|
||||
* <TBD>
|
||||
*
|
||||
* Unit Tests:
|
||||
* indra/newview/tests/llviewerassetstats_test.cpp
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
// ------------------------------------------------------
|
||||
// Global data definitions
|
||||
// ------------------------------------------------------
|
||||
LLViewerAssetStats * gViewerAssetStatsMain(0);
|
||||
LLViewerAssetStats * gViewerAssetStatsThread1(0);
|
||||
|
||||
|
||||
// ------------------------------------------------------
|
||||
// Local declarations
|
||||
// ------------------------------------------------------
|
||||
namespace
|
||||
{
|
||||
|
||||
static LLViewerAssetStats::EViewerAssetCategories
|
||||
asset_type_to_category(const LLViewerAssetType::EType at, bool with_http, bool is_temp);
|
||||
|
||||
}
|
||||
|
||||
// ------------------------------------------------------
|
||||
// LLViewerAssetStats::PerRegionStats struct definition
|
||||
// ------------------------------------------------------
|
||||
void
|
||||
LLViewerAssetStats::PerRegionStats::reset()
|
||||
{
|
||||
for (int i(0); i < LL_ARRAY_SIZE(mRequests); ++i)
|
||||
{
|
||||
mRequests[i].mEnqueued.reset();
|
||||
mRequests[i].mDequeued.reset();
|
||||
mRequests[i].mResponse.reset();
|
||||
}
|
||||
mFPS.reset();
|
||||
|
||||
mTotalTime = 0;
|
||||
mStartTimestamp = LLViewerAssetStatsFF::get_timestamp();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
LLViewerAssetStats::PerRegionStats::merge(const LLViewerAssetStats::PerRegionStats & src)
|
||||
{
|
||||
// mRegionHandle, mTotalTime, mStartTimestamp are left alone.
|
||||
|
||||
// mFPS
|
||||
if (src.mFPS.getCount() && mFPS.getCount())
|
||||
{
|
||||
mFPS.merge(src.mFPS);
|
||||
}
|
||||
|
||||
// Requests
|
||||
for (int i = 0; i < LL_ARRAY_SIZE(mRequests); ++i)
|
||||
{
|
||||
mRequests[i].mEnqueued.merge(src.mRequests[i].mEnqueued);
|
||||
mRequests[i].mDequeued.merge(src.mRequests[i].mDequeued);
|
||||
mRequests[i].mResponse.merge(src.mRequests[i].mResponse);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
LLViewerAssetStats::PerRegionStats::accumulateTime(duration_t now)
|
||||
{
|
||||
mTotalTime += (now - mStartTimestamp);
|
||||
mStartTimestamp = now;
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------
|
||||
// LLViewerAssetStats class definition
|
||||
// ------------------------------------------------------
|
||||
LLViewerAssetStats::LLViewerAssetStats()
|
||||
: mRegionHandle(U64(0))
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
|
||||
LLViewerAssetStats::LLViewerAssetStats(const LLViewerAssetStats & src)
|
||||
: mRegionHandle(src.mRegionHandle),
|
||||
mResetTimestamp(src.mResetTimestamp)
|
||||
{
|
||||
const PerRegionContainer::const_iterator it_end(src.mRegionStats.end());
|
||||
for (PerRegionContainer::const_iterator it(src.mRegionStats.begin()); it_end != it; ++it)
|
||||
{
|
||||
mRegionStats[it->first] = new PerRegionStats(*it->second);
|
||||
}
|
||||
mCurRegionStats = mRegionStats[mRegionHandle];
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
LLViewerAssetStats::reset()
|
||||
{
|
||||
// Empty the map of all region stats
|
||||
mRegionStats.clear();
|
||||
|
||||
// If we have a current stats, reset it, otherwise, as at construction,
|
||||
// create a new one as we must always have a current stats block.
|
||||
if (mCurRegionStats)
|
||||
{
|
||||
mCurRegionStats->reset();
|
||||
}
|
||||
else
|
||||
{
|
||||
mCurRegionStats = new PerRegionStats(mRegionHandle);
|
||||
}
|
||||
|
||||
// And add reference to map
|
||||
mRegionStats[mRegionHandle] = mCurRegionStats;
|
||||
|
||||
// Start timestamp consistent with per-region collector
|
||||
mResetTimestamp = mCurRegionStats->mStartTimestamp;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
LLViewerAssetStats::setRegion(region_handle_t region_handle)
|
||||
{
|
||||
if (region_handle == mRegionHandle)
|
||||
{
|
||||
// Already active, ignore.
|
||||
return;
|
||||
}
|
||||
|
||||
// Get duration for current set
|
||||
const duration_t now = LLViewerAssetStatsFF::get_timestamp();
|
||||
mCurRegionStats->accumulateTime(now);
|
||||
|
||||
// Prepare new set
|
||||
PerRegionContainer::iterator new_stats = mRegionStats.find(region_handle);
|
||||
if (mRegionStats.end() == new_stats)
|
||||
{
|
||||
// Haven't seen this region_id before, create a new block and make it current.
|
||||
mCurRegionStats = new PerRegionStats(region_handle);
|
||||
mRegionStats[region_handle] = mCurRegionStats;
|
||||
}
|
||||
else
|
||||
{
|
||||
mCurRegionStats = new_stats->second;
|
||||
}
|
||||
mCurRegionStats->mStartTimestamp = now;
|
||||
mRegionHandle = region_handle;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
LLViewerAssetStats::recordGetEnqueued(LLViewerAssetType::EType at, bool with_http, bool is_temp)
|
||||
{
|
||||
const EViewerAssetCategories eac(asset_type_to_category(at, with_http, is_temp));
|
||||
|
||||
++(mCurRegionStats->mRequests[int(eac)].mEnqueued);
|
||||
}
|
||||
|
||||
void
|
||||
LLViewerAssetStats::recordGetDequeued(LLViewerAssetType::EType at, bool with_http, bool is_temp)
|
||||
{
|
||||
const EViewerAssetCategories eac(asset_type_to_category(at, with_http, is_temp));
|
||||
|
||||
++(mCurRegionStats->mRequests[int(eac)].mDequeued);
|
||||
}
|
||||
|
||||
void
|
||||
LLViewerAssetStats::recordGetServiced(LLViewerAssetType::EType at, bool with_http, bool is_temp, duration_t duration)
|
||||
{
|
||||
const EViewerAssetCategories eac(asset_type_to_category(at, with_http, is_temp));
|
||||
|
||||
mCurRegionStats->mRequests[int(eac)].mResponse.record(duration);
|
||||
}
|
||||
|
||||
void
|
||||
LLViewerAssetStats::recordFPS(F32 fps)
|
||||
{
|
||||
mCurRegionStats->mFPS.record(fps);
|
||||
}
|
||||
|
||||
LLSD
|
||||
LLViewerAssetStats::asLLSD(bool compact_output)
|
||||
{
|
||||
// Top-level tags
|
||||
static const LLSD::String tags[EVACCount] =
|
||||
{
|
||||
LLSD::String("get_texture_temp_http"),
|
||||
LLSD::String("get_texture_temp_udp"),
|
||||
LLSD::String("get_texture_non_temp_http"),
|
||||
LLSD::String("get_texture_non_temp_udp"),
|
||||
LLSD::String("get_wearable_udp"),
|
||||
LLSD::String("get_sound_udp"),
|
||||
LLSD::String("get_gesture_udp"),
|
||||
LLSD::String("get_other")
|
||||
};
|
||||
|
||||
// Stats Group Sub-tags.
|
||||
static const LLSD::String enq_tag("enqueued");
|
||||
static const LLSD::String deq_tag("dequeued");
|
||||
static const LLSD::String rcnt_tag("resp_count");
|
||||
static const LLSD::String rmin_tag("resp_min");
|
||||
static const LLSD::String rmax_tag("resp_max");
|
||||
static const LLSD::String rmean_tag("resp_mean");
|
||||
|
||||
// MMM Group Sub-tags.
|
||||
static const LLSD::String cnt_tag("count");
|
||||
static const LLSD::String min_tag("min");
|
||||
static const LLSD::String max_tag("max");
|
||||
static const LLSD::String mean_tag("mean");
|
||||
|
||||
const duration_t now = LLViewerAssetStatsFF::get_timestamp();
|
||||
mCurRegionStats->accumulateTime(now);
|
||||
|
||||
LLSD regions = LLSD::emptyArray();
|
||||
for (PerRegionContainer::iterator it = mRegionStats.begin();
|
||||
mRegionStats.end() != it;
|
||||
++it)
|
||||
{
|
||||
if (0 == it->first)
|
||||
{
|
||||
// Never emit NULL UUID/handle in results.
|
||||
continue;
|
||||
}
|
||||
|
||||
PerRegionStats & stats = *it->second;
|
||||
|
||||
LLSD reg_stat = LLSD::emptyMap();
|
||||
|
||||
for (int i = 0; i < LL_ARRAY_SIZE(tags); ++i)
|
||||
{
|
||||
PerRegionStats::prs_group & group(stats.mRequests[i]);
|
||||
|
||||
if ((! compact_output) ||
|
||||
group.mEnqueued.getCount() ||
|
||||
group.mDequeued.getCount() ||
|
||||
group.mResponse.getCount())
|
||||
{
|
||||
LLSD & slot = reg_stat[tags[i]];
|
||||
slot = LLSD::emptyMap();
|
||||
slot[enq_tag] = LLSD(S32(stats.mRequests[i].mEnqueued.getCount()));
|
||||
slot[deq_tag] = LLSD(S32(stats.mRequests[i].mDequeued.getCount()));
|
||||
slot[rcnt_tag] = LLSD(S32(stats.mRequests[i].mResponse.getCount()));
|
||||
slot[rmin_tag] = LLSD(F64(stats.mRequests[i].mResponse.getMin() * 1.0e-6));
|
||||
slot[rmax_tag] = LLSD(F64(stats.mRequests[i].mResponse.getMax() * 1.0e-6));
|
||||
slot[rmean_tag] = LLSD(F64(stats.mRequests[i].mResponse.getMean() * 1.0e-6));
|
||||
}
|
||||
}
|
||||
|
||||
if ((! compact_output) || stats.mFPS.getCount())
|
||||
{
|
||||
LLSD & slot = reg_stat["fps"];
|
||||
slot = LLSD::emptyMap();
|
||||
slot[cnt_tag] = LLSD(S32(stats.mFPS.getCount()));
|
||||
slot[min_tag] = LLSD(F64(stats.mFPS.getMin()));
|
||||
slot[max_tag] = LLSD(F64(stats.mFPS.getMax()));
|
||||
slot[mean_tag] = LLSD(F64(stats.mFPS.getMean()));
|
||||
}
|
||||
U32 grid_x(0), grid_y(0);
|
||||
grid_from_region_handle(it->first, &grid_x, &grid_y);
|
||||
reg_stat["grid_x"] = LLSD::Integer(grid_x);
|
||||
reg_stat["grid_y"] = LLSD::Integer(grid_y);
|
||||
reg_stat["duration"] = LLSD::Real(stats.mTotalTime * 1.0e-6);
|
||||
regions.append(reg_stat);
|
||||
}
|
||||
|
||||
LLSD ret = LLSD::emptyMap();
|
||||
ret["regions"] = regions;
|
||||
ret["duration"] = LLSD::Real((now - mResetTimestamp) * 1.0e-6);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
LLViewerAssetStats::merge(const LLViewerAssetStats & src)
|
||||
{
|
||||
// mRegionHandle, mCurRegionStats and mResetTimestamp are left untouched.
|
||||
// Just merge the stats bodies
|
||||
|
||||
const PerRegionContainer::const_iterator it_end(src.mRegionStats.end());
|
||||
for (PerRegionContainer::const_iterator it(src.mRegionStats.begin()); it_end != it; ++it)
|
||||
{
|
||||
PerRegionContainer::iterator dst(mRegionStats.find(it->first));
|
||||
if (mRegionStats.end() == dst)
|
||||
{
|
||||
// Destination is missing data, just make a private copy
|
||||
mRegionStats[it->first] = new PerRegionStats(*it->second);
|
||||
}
|
||||
else
|
||||
{
|
||||
dst->second->merge(*it->second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------
|
||||
// Global free-function definitions (LLViewerAssetStatsFF namespace)
|
||||
// ------------------------------------------------------
|
||||
|
||||
namespace LLViewerAssetStatsFF
|
||||
{
|
||||
|
||||
//
|
||||
// Target thread is elaborated in the function name. This could
|
||||
// have been something 'templatey' like specializations iterated
|
||||
// over a set of constants but with so few, this is clearer I think.
|
||||
//
|
||||
// As for the threads themselves... rather than do fine-grained
|
||||
// locking as we gather statistics, this code creates a collector
|
||||
// for each thread, allocated and run independently. Logging
|
||||
// happens at relatively infrequent intervals and at that time
|
||||
// the data is sent to a single thread to be aggregated into
|
||||
// a single entity with locks, thread safety and other niceties.
|
||||
//
|
||||
// A particularly fussy implementation would distribute the
|
||||
// per-thread pointers across separate cache lines. But that should
|
||||
// be beyond current requirements.
|
||||
//
|
||||
|
||||
// 'main' thread - initial program thread
|
||||
|
||||
void
|
||||
set_region_main(LLViewerAssetStats::region_handle_t region_handle)
|
||||
{
|
||||
if (! gViewerAssetStatsMain)
|
||||
return;
|
||||
|
||||
gViewerAssetStatsMain->setRegion(region_handle);
|
||||
}
|
||||
|
||||
void
|
||||
record_enqueue_main(LLViewerAssetType::EType at, bool with_http, bool is_temp)
|
||||
{
|
||||
if (! gViewerAssetStatsMain)
|
||||
return;
|
||||
|
||||
gViewerAssetStatsMain->recordGetEnqueued(at, with_http, is_temp);
|
||||
}
|
||||
|
||||
void
|
||||
record_dequeue_main(LLViewerAssetType::EType at, bool with_http, bool is_temp)
|
||||
{
|
||||
if (! gViewerAssetStatsMain)
|
||||
return;
|
||||
|
||||
gViewerAssetStatsMain->recordGetDequeued(at, with_http, is_temp);
|
||||
}
|
||||
|
||||
void
|
||||
record_response_main(LLViewerAssetType::EType at, bool with_http, bool is_temp, LLViewerAssetStats::duration_t duration)
|
||||
{
|
||||
if (! gViewerAssetStatsMain)
|
||||
return;
|
||||
|
||||
gViewerAssetStatsMain->recordGetServiced(at, with_http, is_temp, duration);
|
||||
}
|
||||
|
||||
void
|
||||
record_fps_main(F32 fps)
|
||||
{
|
||||
if (! gViewerAssetStatsMain)
|
||||
return;
|
||||
|
||||
gViewerAssetStatsMain->recordFPS(fps);
|
||||
}
|
||||
|
||||
// 'thread1' - should be for TextureFetch thread
|
||||
|
||||
void
|
||||
set_region_thread1(LLViewerAssetStats::region_handle_t region_handle)
|
||||
{
|
||||
if (! gViewerAssetStatsThread1)
|
||||
return;
|
||||
|
||||
gViewerAssetStatsThread1->setRegion(region_handle);
|
||||
}
|
||||
|
||||
void
|
||||
record_enqueue_thread1(LLViewerAssetType::EType at, bool with_http, bool is_temp)
|
||||
{
|
||||
if (! gViewerAssetStatsThread1)
|
||||
return;
|
||||
|
||||
gViewerAssetStatsThread1->recordGetEnqueued(at, with_http, is_temp);
|
||||
}
|
||||
|
||||
void
|
||||
record_dequeue_thread1(LLViewerAssetType::EType at, bool with_http, bool is_temp)
|
||||
{
|
||||
if (! gViewerAssetStatsThread1)
|
||||
return;
|
||||
|
||||
gViewerAssetStatsThread1->recordGetDequeued(at, with_http, is_temp);
|
||||
}
|
||||
|
||||
void
|
||||
record_response_thread1(LLViewerAssetType::EType at, bool with_http, bool is_temp, LLViewerAssetStats::duration_t duration)
|
||||
{
|
||||
if (! gViewerAssetStatsThread1)
|
||||
return;
|
||||
|
||||
gViewerAssetStatsThread1->recordGetServiced(at, with_http, is_temp, duration);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
init()
|
||||
{
|
||||
if (! gViewerAssetStatsMain)
|
||||
{
|
||||
gViewerAssetStatsMain = new LLViewerAssetStats();
|
||||
}
|
||||
if (! gViewerAssetStatsThread1)
|
||||
{
|
||||
gViewerAssetStatsThread1 = new LLViewerAssetStats();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
cleanup()
|
||||
{
|
||||
delete gViewerAssetStatsMain;
|
||||
gViewerAssetStatsMain = 0;
|
||||
|
||||
delete gViewerAssetStatsThread1;
|
||||
gViewerAssetStatsThread1 = 0;
|
||||
}
|
||||
|
||||
|
||||
} // namespace LLViewerAssetStatsFF
|
||||
|
||||
|
||||
// ------------------------------------------------------
|
||||
// Local function definitions
|
||||
// ------------------------------------------------------
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
LLViewerAssetStats::EViewerAssetCategories
|
||||
asset_type_to_category(const LLViewerAssetType::EType at, bool with_http, bool is_temp)
|
||||
{
|
||||
// For statistical purposes, we divide GETs into several
|
||||
// populations of asset fetches:
|
||||
// - textures which are de-prioritized in the asset system
|
||||
// - wearables (clothing, bodyparts) which directly affect
|
||||
// user experiences when they log in
|
||||
// - sounds
|
||||
// - gestures
|
||||
// - everything else.
|
||||
//
|
||||
llassert_always(50 == LLViewerAssetType::AT_COUNT);
|
||||
|
||||
// Multiple asset definitions are floating around so this requires some
|
||||
// maintenance and attention.
|
||||
static const LLViewerAssetStats::EViewerAssetCategories asset_to_bin_map[LLViewerAssetType::AT_COUNT] =
|
||||
{
|
||||
LLViewerAssetStats::EVACTextureTempHTTPGet, // (0) AT_TEXTURE
|
||||
LLViewerAssetStats::EVACSoundUDPGet, // AT_SOUND
|
||||
LLViewerAssetStats::EVACOtherGet, // AT_CALLINGCARD
|
||||
LLViewerAssetStats::EVACOtherGet, // AT_LANDMARK
|
||||
LLViewerAssetStats::EVACOtherGet, // AT_SCRIPT
|
||||
LLViewerAssetStats::EVACWearableUDPGet, // AT_CLOTHING
|
||||
LLViewerAssetStats::EVACOtherGet, // AT_OBJECT
|
||||
LLViewerAssetStats::EVACOtherGet, // AT_NOTECARD
|
||||
LLViewerAssetStats::EVACOtherGet, // AT_CATEGORY
|
||||
LLViewerAssetStats::EVACOtherGet, // AT_ROOT_CATEGORY
|
||||
LLViewerAssetStats::EVACOtherGet, // (10) AT_LSL_TEXT
|
||||
LLViewerAssetStats::EVACOtherGet, // AT_LSL_BYTECODE
|
||||
LLViewerAssetStats::EVACOtherGet, // AT_TEXTURE_TGA
|
||||
LLViewerAssetStats::EVACWearableUDPGet, // AT_BODYPART
|
||||
LLViewerAssetStats::EVACOtherGet, // AT_TRASH
|
||||
LLViewerAssetStats::EVACOtherGet, // AT_SNAPSHOT_CATEGORY
|
||||
LLViewerAssetStats::EVACOtherGet, // AT_LOST_AND_FOUND
|
||||
LLViewerAssetStats::EVACSoundUDPGet, // AT_SOUND_WAV
|
||||
LLViewerAssetStats::EVACOtherGet, // AT_IMAGE_TGA
|
||||
LLViewerAssetStats::EVACOtherGet, // AT_IMAGE_JPEG
|
||||
LLViewerAssetStats::EVACGestureUDPGet, // (20) AT_ANIMATION
|
||||
LLViewerAssetStats::EVACGestureUDPGet, // AT_GESTURE
|
||||
LLViewerAssetStats::EVACOtherGet, // AT_SIMSTATE
|
||||
LLViewerAssetStats::EVACOtherGet, // AT_FAVORITE
|
||||
LLViewerAssetStats::EVACOtherGet, // AT_LINK
|
||||
LLViewerAssetStats::EVACOtherGet, // AT_LINK_FOLDER
|
||||
LLViewerAssetStats::EVACOtherGet, //
|
||||
LLViewerAssetStats::EVACOtherGet, //
|
||||
LLViewerAssetStats::EVACOtherGet, //
|
||||
LLViewerAssetStats::EVACOtherGet, //
|
||||
LLViewerAssetStats::EVACOtherGet, // (30)
|
||||
LLViewerAssetStats::EVACOtherGet, //
|
||||
LLViewerAssetStats::EVACOtherGet, //
|
||||
LLViewerAssetStats::EVACOtherGet, //
|
||||
LLViewerAssetStats::EVACOtherGet, //
|
||||
LLViewerAssetStats::EVACOtherGet, //
|
||||
LLViewerAssetStats::EVACOtherGet, //
|
||||
LLViewerAssetStats::EVACOtherGet, //
|
||||
LLViewerAssetStats::EVACOtherGet, //
|
||||
LLViewerAssetStats::EVACOtherGet, //
|
||||
LLViewerAssetStats::EVACOtherGet, // (40)
|
||||
LLViewerAssetStats::EVACOtherGet, //
|
||||
LLViewerAssetStats::EVACOtherGet, //
|
||||
LLViewerAssetStats::EVACOtherGet, //
|
||||
LLViewerAssetStats::EVACOtherGet, //
|
||||
LLViewerAssetStats::EVACOtherGet, //
|
||||
LLViewerAssetStats::EVACOtherGet, //
|
||||
LLViewerAssetStats::EVACOtherGet, //
|
||||
LLViewerAssetStats::EVACOtherGet, //
|
||||
LLViewerAssetStats::EVACOtherGet, // AT_MESH
|
||||
// (50)
|
||||
};
|
||||
|
||||
if (at < 0 || at >= LLViewerAssetType::AT_COUNT)
|
||||
{
|
||||
return LLViewerAssetStats::EVACOtherGet;
|
||||
}
|
||||
LLViewerAssetStats::EViewerAssetCategories ret(asset_to_bin_map[at]);
|
||||
if (LLViewerAssetStats::EVACTextureTempHTTPGet == ret)
|
||||
{
|
||||
// Indexed with [is_temp][with_http]
|
||||
static const LLViewerAssetStats::EViewerAssetCategories texture_bin_map[2][2] =
|
||||
{
|
||||
{
|
||||
LLViewerAssetStats::EVACTextureNonTempUDPGet,
|
||||
LLViewerAssetStats::EVACTextureNonTempHTTPGet,
|
||||
},
|
||||
{
|
||||
LLViewerAssetStats::EVACTextureTempUDPGet,
|
||||
LLViewerAssetStats::EVACTextureTempHTTPGet,
|
||||
}
|
||||
};
|
||||
|
||||
ret = texture_bin_map[is_temp][with_http];
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
327
indra/newview/llviewerassetstats.h
Normal file
327
indra/newview/llviewerassetstats.h
Normal file
@@ -0,0 +1,327 @@
|
||||
/**
|
||||
* @file llviewerassetstats.h
|
||||
* @brief Client-side collection of asset request statistics
|
||||
*
|
||||
* $LicenseInfo:firstyear=2010&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_LLVIEWERASSETSTATUS_H
|
||||
#define LL_LLVIEWERASSETSTATUS_H
|
||||
|
||||
|
||||
#include "linden_common.h"
|
||||
|
||||
#include "llpointer.h"
|
||||
#include "llrefcount.h"
|
||||
#include "llviewerassettype.h"
|
||||
#include "llviewerassetstorage.h"
|
||||
#include "llsimplestat.h"
|
||||
#include "llsd.h"
|
||||
|
||||
/**
|
||||
* @class LLViewerAssetStats
|
||||
* @brief Records performance aspects of asset access operations.
|
||||
*
|
||||
* This facility is derived from a very similar simulator-based
|
||||
* one, LLSimAssetStats. It's function is to count asset access
|
||||
* operations and characterize response times. Collected data
|
||||
* are binned in several dimensions:
|
||||
*
|
||||
* - Asset types collapsed into a few aggregated categories
|
||||
* - By simulator UUID
|
||||
* - By transport mechanism (HTTP vs MessageSystem)
|
||||
* - By persistence (temp vs non-temp)
|
||||
*
|
||||
* Statistics collected are fairly basic at this point:
|
||||
*
|
||||
* - Counts of enqueue and dequeue operations
|
||||
* - Min/Max/Mean of asset transfer operations
|
||||
*
|
||||
* This collector differs from the simulator-based on in a
|
||||
* number of ways:
|
||||
*
|
||||
* - The front-end/back-end distinction doesn't exist in viewer
|
||||
* code
|
||||
* - Multiple threads must be safely accomodated in the viewer
|
||||
*
|
||||
* Access to results is by conversion to an LLSD with some standardized
|
||||
* key names. The intent of this structure is that it be emitted as
|
||||
* standard syslog-based metrics formatting where it can be picked
|
||||
* up by interested parties.
|
||||
*
|
||||
* For convenience, a set of free functions in namespace
|
||||
* LLViewerAssetStatsFF is provided for conditional test-and-call
|
||||
* operations.
|
||||
*/
|
||||
class LLViewerAssetStats
|
||||
{
|
||||
public:
|
||||
enum EViewerAssetCategories
|
||||
{
|
||||
EVACTextureTempHTTPGet, //< Texture GETs - temp/baked, HTTP
|
||||
EVACTextureTempUDPGet, //< Texture GETs - temp/baked, UDP
|
||||
EVACTextureNonTempHTTPGet, //< Texture GETs - perm, HTTP
|
||||
EVACTextureNonTempUDPGet, //< Texture GETs - perm, UDP
|
||||
EVACWearableUDPGet, //< Wearable GETs
|
||||
EVACSoundUDPGet, //< Sound GETs
|
||||
EVACGestureUDPGet, //< Gesture GETs
|
||||
EVACOtherGet, //< Other GETs
|
||||
|
||||
EVACCount // Must be last
|
||||
};
|
||||
|
||||
/**
|
||||
* Type for duration and other time values in the metrics. Selected
|
||||
* for compatibility with the pre-existing timestamp on the texture
|
||||
* fetcher class, LLTextureFetch.
|
||||
*/
|
||||
typedef U64 duration_t;
|
||||
|
||||
/**
|
||||
* Type for the region identifier used in stats. Currently uses
|
||||
* the region handle's type (a U64) rather than the regions's LLUUID
|
||||
* as the latter isn't available immediately.
|
||||
*/
|
||||
typedef U64 region_handle_t;
|
||||
|
||||
/**
|
||||
* @brief Collected data for a single region visited by the avatar.
|
||||
*
|
||||
* Fairly simple, for each asset bin enumerated above a count
|
||||
* of enqueue and dequeue operations and simple stats on response
|
||||
* times for completed requests.
|
||||
*/
|
||||
class PerRegionStats : public LLRefCount
|
||||
{
|
||||
public:
|
||||
PerRegionStats(const region_handle_t region_handle)
|
||||
: LLRefCount(),
|
||||
mRegionHandle(region_handle)
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
PerRegionStats(const PerRegionStats & src)
|
||||
: LLRefCount(),
|
||||
mRegionHandle(src.mRegionHandle),
|
||||
mTotalTime(src.mTotalTime),
|
||||
mStartTimestamp(src.mStartTimestamp),
|
||||
mFPS(src.mFPS)
|
||||
{
|
||||
for (int i = 0; i < LL_ARRAY_SIZE(mRequests); ++i)
|
||||
{
|
||||
mRequests[i] = src.mRequests[i];
|
||||
}
|
||||
}
|
||||
|
||||
// Default assignment and destructor are correct.
|
||||
|
||||
void reset();
|
||||
|
||||
void merge(const PerRegionStats & src);
|
||||
|
||||
// Apply current running time to total and reset start point.
|
||||
// Return current timestamp as a convenience.
|
||||
void accumulateTime(duration_t now);
|
||||
|
||||
public:
|
||||
region_handle_t mRegionHandle;
|
||||
duration_t mTotalTime;
|
||||
duration_t mStartTimestamp;
|
||||
LLSimpleStatMMM<> mFPS;
|
||||
|
||||
struct prs_group
|
||||
{
|
||||
LLSimpleStatCounter mEnqueued;
|
||||
LLSimpleStatCounter mDequeued;
|
||||
LLSimpleStatMMM<duration_t> mResponse;
|
||||
}
|
||||
mRequests [EVACCount];
|
||||
};
|
||||
|
||||
public:
|
||||
LLViewerAssetStats();
|
||||
LLViewerAssetStats(const LLViewerAssetStats &);
|
||||
// Default destructor is correct.
|
||||
LLViewerAssetStats & operator=(const LLViewerAssetStats &); // Not defined
|
||||
|
||||
// Clear all metrics data. This leaves the currently-active region
|
||||
// in place but with zero'd data for all metrics. All other regions
|
||||
// are removed from the collection map.
|
||||
void reset();
|
||||
|
||||
// Set hidden region argument and establish context for subsequent
|
||||
// collection calls.
|
||||
void setRegion(region_handle_t region_handle);
|
||||
|
||||
// Asset GET Requests
|
||||
void recordGetEnqueued(LLViewerAssetType::EType at, bool with_http, bool is_temp);
|
||||
void recordGetDequeued(LLViewerAssetType::EType at, bool with_http, bool is_temp);
|
||||
void recordGetServiced(LLViewerAssetType::EType at, bool with_http, bool is_temp, duration_t duration);
|
||||
|
||||
// Frames-Per-Second Samples
|
||||
void recordFPS(F32 fps);
|
||||
|
||||
// Merge a source instance into a destination instance. This is
|
||||
// conceptually an 'operator+=()' method:
|
||||
// - counts are added
|
||||
// - minimums are min'd
|
||||
// - maximums are max'd
|
||||
// - other scalars are ignored ('this' wins)
|
||||
//
|
||||
void merge(const LLViewerAssetStats & src);
|
||||
|
||||
// Retrieve current metrics for all visited regions (NULL region UUID/handle excluded)
|
||||
// Returned LLSD is structured as follows:
|
||||
//
|
||||
// &stats_group = {
|
||||
// enqueued : int,
|
||||
// dequeued : int,
|
||||
// resp_count : int,
|
||||
// resp_min : float,
|
||||
// resp_max : float,
|
||||
// resp_mean : float
|
||||
// }
|
||||
//
|
||||
// &mmm_group = {
|
||||
// count : int,
|
||||
// min : float,
|
||||
// max : float,
|
||||
// mean : float
|
||||
// }
|
||||
//
|
||||
// {
|
||||
// duration: int
|
||||
// regions: {
|
||||
// $: { // Keys are strings of the region's handle in hex
|
||||
// duration: : int,
|
||||
// fps: : &mmm_group,
|
||||
// get_texture_temp_http : &stats_group,
|
||||
// get_texture_temp_udp : &stats_group,
|
||||
// get_texture_non_temp_http : &stats_group,
|
||||
// get_texture_non_temp_udp : &stats_group,
|
||||
// get_wearable_udp : &stats_group,
|
||||
// get_sound_udp : &stats_group,
|
||||
// get_gesture_udp : &stats_group,
|
||||
// get_other : &stats_group
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// @param compact_output If true, omits from conversion any mmm_block
|
||||
// or stats_block that would contain all zero data.
|
||||
// Useful for transmission when the receiver knows
|
||||
// what is expected and will assume zero for missing
|
||||
// blocks.
|
||||
LLSD asLLSD(bool compact_output);
|
||||
|
||||
protected:
|
||||
typedef std::map<region_handle_t, LLPointer<PerRegionStats> > PerRegionContainer;
|
||||
|
||||
// Region of the currently-active region. Always valid but may
|
||||
// be zero after construction or when explicitly set. Unchanged
|
||||
// by a reset() call.
|
||||
region_handle_t mRegionHandle;
|
||||
|
||||
// Pointer to metrics collection for currently-active region. Always
|
||||
// valid and unchanged after reset() though contents will be changed.
|
||||
// Always points to a collection contained in mRegionStats.
|
||||
LLPointer<PerRegionStats> mCurRegionStats;
|
||||
|
||||
// Metrics data for all regions during one collection cycle
|
||||
PerRegionContainer mRegionStats;
|
||||
|
||||
// Time of last reset
|
||||
duration_t mResetTimestamp;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Global stats collectors one for each independent thread where
|
||||
* assets and other statistics are gathered. The globals are
|
||||
* expected to be created at startup time and then picked up by
|
||||
* their respective threads afterwards. A set of free functions
|
||||
* are provided to access methods behind the globals while both
|
||||
* minimally disrupting visual flow and supplying a description
|
||||
* of intent.
|
||||
*
|
||||
* Expected thread assignments:
|
||||
*
|
||||
* - Main: main() program execution thread
|
||||
* - Thread1: TextureFetch worker thread
|
||||
*/
|
||||
extern LLViewerAssetStats * gViewerAssetStatsMain;
|
||||
|
||||
extern LLViewerAssetStats * gViewerAssetStatsThread1;
|
||||
|
||||
namespace LLViewerAssetStatsFF
|
||||
{
|
||||
/**
|
||||
* @brief Allocation and deallocation of globals.
|
||||
*
|
||||
* init() should be called before threads are started that will access it though
|
||||
* you'll likely get away with calling it afterwards. cleanup() should only be
|
||||
* called after threads are shutdown to prevent races on the global pointers.
|
||||
*/
|
||||
void init();
|
||||
|
||||
void cleanup();
|
||||
|
||||
/**
|
||||
* We have many timers, clocks etc. in the runtime. This is the
|
||||
* canonical timestamp for these metrics which is compatible with
|
||||
* the pre-existing timestamping in the texture fetcher.
|
||||
*/
|
||||
inline LLViewerAssetStats::duration_t get_timestamp()
|
||||
{
|
||||
return LLTimer::getTotalTime();
|
||||
}
|
||||
|
||||
/**
|
||||
* Region context, event and duration loggers for the Main thread.
|
||||
*/
|
||||
void set_region_main(LLViewerAssetStats::region_handle_t region_handle);
|
||||
|
||||
void record_enqueue_main(LLViewerAssetType::EType at, bool with_http, bool is_temp);
|
||||
|
||||
void record_dequeue_main(LLViewerAssetType::EType at, bool with_http, bool is_temp);
|
||||
|
||||
void record_response_main(LLViewerAssetType::EType at, bool with_http, bool is_temp,
|
||||
LLViewerAssetStats::duration_t duration);
|
||||
|
||||
void record_fps_main(F32 fps);
|
||||
|
||||
/**
|
||||
* Region context, event and duration loggers for Thread 1.
|
||||
*/
|
||||
void set_region_thread1(LLViewerAssetStats::region_handle_t region_handle);
|
||||
|
||||
void record_enqueue_thread1(LLViewerAssetType::EType at, bool with_http, bool is_temp);
|
||||
|
||||
void record_dequeue_thread1(LLViewerAssetType::EType at, bool with_http, bool is_temp);
|
||||
|
||||
void record_response_thread1(LLViewerAssetType::EType at, bool with_http, bool is_temp,
|
||||
LLViewerAssetStats::duration_t duration);
|
||||
|
||||
} // namespace LLViewerAssetStatsFF
|
||||
|
||||
#endif // LL_LLVIEWERASSETSTATUS_H
|
||||
@@ -2,44 +2,92 @@
|
||||
* @file llviewerassetstorage.cpp
|
||||
* @brief Subclass capable of loading asset data to/from an external source.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2003&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2003-2009, Linden Research, Inc.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2003&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
||||
* to you under the terms of the GNU General Public License, version 2.0
|
||||
* ("GPL"), unless you have obtained a separate licensing agreement
|
||||
* ("Other License"), formally executed by you and Linden Lab. Terms of
|
||||
* the GPL can be found in doc/GPL-license.txt in this distribution, or
|
||||
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution, or
|
||||
* online at
|
||||
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
|
||||
* 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.
|
||||
*
|
||||
* By copying, modifying or distributing this software, you acknowledge
|
||||
* that you have read and understood your obligations described above,
|
||||
* and agree to abide by those obligations.
|
||||
* 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.
|
||||
*
|
||||
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
||||
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
||||
* COMPLETENESS OR PERFORMANCE.
|
||||
* 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$
|
||||
*/
|
||||
|
||||
#include "llviewerprecompiledheaders.h"
|
||||
|
||||
#include "linden_common.h"
|
||||
|
||||
#include "llagent.h"
|
||||
#include "llviewerassetstorage.h"
|
||||
#include "llviewerbuild.h"
|
||||
|
||||
#include "llvfile.h"
|
||||
#include "llvfs.h"
|
||||
#include "message.h"
|
||||
|
||||
#include "llagent.h"
|
||||
#include "lltransfersourceasset.h"
|
||||
#include "lltransfertargetvfile.h"
|
||||
#include "llviewerassetstats.h"
|
||||
|
||||
///----------------------------------------------------------------------------
|
||||
/// LLViewerAssetRequest
|
||||
///----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief Local class to encapsulate asset fetch requests with a timestamp.
|
||||
*
|
||||
* Derived from the common LLAssetRequest class, this is currently used
|
||||
* only for fetch/get operations and its only function is to wrap remote
|
||||
* asset fetch requests so that they can be timed.
|
||||
*/
|
||||
class LLViewerAssetRequest : public LLAssetRequest
|
||||
{
|
||||
public:
|
||||
LLViewerAssetRequest(const LLUUID &uuid, const LLAssetType::EType type)
|
||||
: LLAssetRequest(uuid, type),
|
||||
mMetricsStartTime(0)
|
||||
{
|
||||
}
|
||||
|
||||
LLViewerAssetRequest & operator=(const LLViewerAssetRequest &); // Not defined
|
||||
// Default assignment operator valid
|
||||
|
||||
// virtual
|
||||
~LLViewerAssetRequest()
|
||||
{
|
||||
recordMetrics();
|
||||
}
|
||||
|
||||
protected:
|
||||
void recordMetrics()
|
||||
{
|
||||
if (mMetricsStartTime)
|
||||
{
|
||||
// Okay, it appears this request was used for useful things. Record
|
||||
// the expected dequeue and duration of request processing.
|
||||
LLViewerAssetStatsFF::record_dequeue_main(mType, false, false);
|
||||
LLViewerAssetStatsFF::record_response_main(mType, false, false,
|
||||
(LLViewerAssetStatsFF::get_timestamp()
|
||||
- mMetricsStartTime));
|
||||
mMetricsStartTime = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
LLViewerAssetStats::duration_t mMetricsStartTime;
|
||||
};
|
||||
|
||||
///----------------------------------------------------------------------------
|
||||
/// LLViewerAssetStorage
|
||||
///----------------------------------------------------------------------------
|
||||
|
||||
LLViewerAssetStorage::LLViewerAssetStorage(LLMessageSystem *msg, LLXferManager *xfer,
|
||||
LLVFS *vfs, LLVFS *static_vfs,
|
||||
@@ -68,7 +116,7 @@ void LLViewerAssetStorage::storeAssetData(
|
||||
F64 timeout)
|
||||
{
|
||||
LLAssetID asset_id = tid.makeAssetID(gAgent.getSecureSessionID());
|
||||
llinfos << "LLViewerAssetStorage::storeAssetData (legacy) " << tid << ":" << LLAssetType::lookup(asset_type)
|
||||
LL_DEBUGS("AssetStorage") << "LLViewerAssetStorage::storeAssetData (legacy) " << tid << ":" << LLAssetType::lookup(asset_type)
|
||||
<< " ASSET_ID: " << asset_id << llendl;
|
||||
|
||||
if (mUpstreamHost.isOk())
|
||||
@@ -201,9 +249,9 @@ void LLViewerAssetStorage::storeAssetData(
|
||||
}
|
||||
|
||||
LLAssetID asset_id = tid.makeAssetID(gAgent.getSecureSessionID());
|
||||
llinfos << "LLViewerAssetStorage::storeAssetData (legacy)" << asset_id << ":" << LLAssetType::lookup(asset_type) << llendl;
|
||||
LL_DEBUGS("AssetStorage") << "LLViewerAssetStorage::storeAssetData (legacy)" << asset_id << ":" << LLAssetType::lookup(asset_type) << llendl;
|
||||
|
||||
llinfos << "ASSET_ID: " << asset_id << llendl;
|
||||
LL_DEBUGS("AssetStorage") << "ASSET_ID: " << asset_id << llendl;
|
||||
|
||||
S32 size = 0;
|
||||
LLFILE* fp = LLFile::fopen(filename, "rb");
|
||||
@@ -266,3 +314,77 @@ void LLViewerAssetStorage::storeAssetData(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Allocate and queue an asset fetch request for the viewer
|
||||
*
|
||||
* This is a nearly-verbatim copy of the base class's implementation
|
||||
* with the following changes:
|
||||
* - Use a locally-derived request class
|
||||
* - Start timing for metrics when request is queued
|
||||
*
|
||||
* This is an unfortunate implementation choice but it's forced by
|
||||
* current conditions. A refactoring that might clean up the layers
|
||||
* of responsibility or introduce factories or more virtualization
|
||||
* of methods would enable a more attractive solution.
|
||||
*
|
||||
* If LLAssetStorage::_queueDataRequest changes, this must change
|
||||
* as well.
|
||||
*/
|
||||
|
||||
// virtual
|
||||
void LLViewerAssetStorage::_queueDataRequest(
|
||||
const LLUUID& uuid,
|
||||
LLAssetType::EType atype,
|
||||
LLGetAssetCallback callback,
|
||||
void *user_data,
|
||||
BOOL duplicate,
|
||||
BOOL is_priority)
|
||||
{
|
||||
if (mUpstreamHost.isOk())
|
||||
{
|
||||
// stash the callback info so we can find it after we get the response message
|
||||
LLViewerAssetRequest *req = new LLViewerAssetRequest(uuid, atype);
|
||||
req->mDownCallback = callback;
|
||||
req->mUserData = user_data;
|
||||
req->mIsPriority = is_priority;
|
||||
if (!duplicate)
|
||||
{
|
||||
// Only collect metrics for non-duplicate requests. Others
|
||||
// are piggy-backing and will artificially lower averages.
|
||||
req->mMetricsStartTime = LLViewerAssetStatsFF::get_timestamp();
|
||||
}
|
||||
|
||||
mPendingDownloads.push_back(req);
|
||||
|
||||
if (!duplicate)
|
||||
{
|
||||
// send request message to our upstream data provider
|
||||
// Create a new asset transfer.
|
||||
LLTransferSourceParamsAsset spa;
|
||||
spa.setAsset(uuid, atype);
|
||||
|
||||
// Set our destination file, and the completion callback.
|
||||
LLTransferTargetParamsVFile tpvf;
|
||||
tpvf.setAsset(uuid, atype);
|
||||
tpvf.setCallback(downloadCompleteCallback, req);
|
||||
|
||||
LL_DEBUGS("AssetStorage") << "Starting transfer for " << uuid << llendl;
|
||||
LLTransferTargetChannel *ttcp = gTransferManager.getTargetChannel(mUpstreamHost, LLTCT_ASSET);
|
||||
ttcp->requestTransfer(spa, tpvf, 100.f + (is_priority ? 1.f : 0.f));
|
||||
|
||||
LLViewerAssetStatsFF::record_enqueue_main(atype, false, false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// uh-oh, we shouldn't have gotten here
|
||||
llwarns << "Attempt to move asset data request upstream w/o valid upstream provider" << llendl;
|
||||
if (callback)
|
||||
{
|
||||
callback(mVFS, uuid, atype, user_data, LL_ERR_CIRCUIT_GONE, LL_EXSTAT_NO_UPSTREAM);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,31 +2,25 @@
|
||||
* @file llviewerassetstorage.h
|
||||
* @brief Class for loading asset data to/from an external source.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2003&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2003-2009, Linden Research, Inc.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2003&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
||||
* to you under the terms of the GNU General Public License, version 2.0
|
||||
* ("GPL"), unless you have obtained a separate licensing agreement
|
||||
* ("Other License"), formally executed by you and Linden Lab. Terms of
|
||||
* the GPL can be found in doc/GPL-license.txt in this distribution, or
|
||||
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution, or
|
||||
* online at
|
||||
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
|
||||
* 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.
|
||||
*
|
||||
* By copying, modifying or distributing this software, you acknowledge
|
||||
* that you have read and understood your obligations described above,
|
||||
* and agree to abide by those obligations.
|
||||
* 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.
|
||||
*
|
||||
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
||||
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
||||
* COMPLETENESS OR PERFORMANCE.
|
||||
* 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$
|
||||
*/
|
||||
|
||||
@@ -34,6 +28,7 @@
|
||||
#define LLVIEWERASSETSTORAGE_H
|
||||
|
||||
#include "llassetstorage.h"
|
||||
//#include "curl/curl.h"
|
||||
|
||||
class LLVFile;
|
||||
|
||||
@@ -68,8 +63,17 @@ public:
|
||||
bool is_priority = false,
|
||||
bool user_waiting=FALSE,
|
||||
F64 timeout=LL_ASSET_STORAGE_TIMEOUT);
|
||||
|
||||
protected:
|
||||
using LLAssetStorage::_queueDataRequest;
|
||||
|
||||
// virtual
|
||||
void _queueDataRequest(const LLUUID& uuid,
|
||||
LLAssetType::EType type,
|
||||
void (*callback) (LLVFS *vfs, const LLUUID&, LLAssetType::EType, void *, S32, LLExtStat),
|
||||
void *user_data,
|
||||
BOOL duplicate,
|
||||
BOOL is_priority);
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -4175,15 +4175,15 @@ void LLViewerObject::setTEImage(const U8 te, LLViewerTexture *imagep)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
S32 LLViewerObject::setTETextureCore(const U8 te, const LLUUID& uuid, const std::string &url )
|
||||
S32 LLViewerObject::setTETextureCore(const U8 te, LLViewerTexture *image)
|
||||
{
|
||||
const LLUUID& uuid = image->getID();
|
||||
S32 retval = 0;
|
||||
if (uuid != getTE(te)->getID() ||
|
||||
uuid == LLUUID::null)
|
||||
{
|
||||
retval = LLPrimitive::setTETexture(te, uuid);
|
||||
mTEImages[te] = LLViewerTextureManager::getFetchedTextureFromUrl (url, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE, 0, 0, uuid);
|
||||
mTEImages[te] = image;
|
||||
setChanged(TEXTURE);
|
||||
if (mDrawable.notNull())
|
||||
{
|
||||
@@ -4193,24 +4193,7 @@ S32 LLViewerObject::setTETextureCore(const U8 te, const LLUUID& uuid, const std:
|
||||
return retval;
|
||||
}
|
||||
|
||||
S32 LLViewerObject::setTETextureCore(const U8 te, const LLUUID& uuid, LLHost host)
|
||||
{
|
||||
S32 retval = 0;
|
||||
if (uuid != getTE(te)->getID() ||
|
||||
uuid == LLUUID::null)
|
||||
{
|
||||
retval = LLPrimitive::setTETexture(te, uuid);
|
||||
mTEImages[te] = LLViewerTextureManager::getFetchedTexture(uuid, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE, 0, 0, host);
|
||||
setChanged(TEXTURE);
|
||||
if (mDrawable.notNull())
|
||||
{
|
||||
gPipeline.markTextured(mDrawable);
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
//virtual
|
||||
void LLViewerObject::changeTEImage(S32 index, LLViewerTexture* new_image)
|
||||
{
|
||||
if(index < 0 || index >= getNumTEs())
|
||||
@@ -4223,7 +4206,9 @@ void LLViewerObject::changeTEImage(S32 index, LLViewerTexture* new_image)
|
||||
S32 LLViewerObject::setTETexture(const U8 te, const LLUUID& uuid)
|
||||
{
|
||||
// Invalid host == get from the agent's sim
|
||||
return setTETextureCore(te, uuid, LLHost::invalid);
|
||||
LLViewerFetchedTexture *image = LLViewerTextureManager::getFetchedTexture(
|
||||
uuid, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE, 0, 0, LLHost::invalid);
|
||||
return setTETextureCore(te,image);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -307,8 +307,7 @@ public:
|
||||
/*virtual*/ void setNumTEs(const U8 num_tes);
|
||||
/*virtual*/ void setTE(const U8 te, const LLTextureEntry &texture_entry);
|
||||
/*virtual*/ S32 setTETexture(const U8 te, const LLUUID &uuid);
|
||||
S32 setTETextureCore(const U8 te, const LLUUID& uuid, LLHost host);
|
||||
S32 setTETextureCore(const U8 te, const LLUUID& uuid, const std::string &url );
|
||||
S32 setTETextureCore(const U8 te, LLViewerTexture *image);
|
||||
/*virtual*/ S32 setTEColor(const U8 te, const LLColor3 &color);
|
||||
/*virtual*/ S32 setTEColor(const U8 te, const LLColor4 &color);
|
||||
/*virtual*/ S32 setTEScale(const U8 te, const F32 s, const F32 t);
|
||||
|
||||
@@ -1558,6 +1558,17 @@ void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **use
|
||||
// Actually extract the data.
|
||||
if (parcel)
|
||||
{
|
||||
if (sequence_id == SELECTED_PARCEL_SEQ_ID
|
||||
&& parcel->getLocalID() != INVALID_PARCEL_ID
|
||||
&& parcel->getLocalID() != local_id)
|
||||
{
|
||||
// The parcel has a valid parcel ID but it doesn't match the parcel
|
||||
// for the data received.
|
||||
llinfos << "Expecting data for parcel " << parcel->getLocalID() \
|
||||
<< " but got data for parcel " << local_id << llendl;
|
||||
return;
|
||||
}
|
||||
|
||||
parcel->init(owner_id,
|
||||
FALSE, FALSE, FALSE,
|
||||
claim_date, claim_price_per_meter, rent_price_per_meter,
|
||||
|
||||
@@ -742,7 +742,7 @@ void LLViewerRegion::processRegionInfo(LLMessageSystem* msg, void**)
|
||||
// send it to 'observers'
|
||||
// *TODO: switch the floaters to using LLRegionInfoModel
|
||||
llinfos << "Processing region info" << llendl;
|
||||
LLRegionInfoModel::getInstance()->update(msg);
|
||||
LLRegionInfoModel::instance().update(msg);
|
||||
LLFloaterGodTools::processRegionInfo(msg);
|
||||
LLFloaterRegionInfo::processRegionInfo(msg);
|
||||
LLFloaterReporter::processRegionInfo(msg);
|
||||
@@ -1660,7 +1660,7 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames)
|
||||
capabilityNames.append("UpdateScriptAgent");
|
||||
capabilityNames.append("UpdateScriptTask");
|
||||
capabilityNames.append("UploadBakedTexture");
|
||||
//capabilityNames.append("ViewerMetrics");
|
||||
capabilityNames.append("ViewerMetrics");
|
||||
capabilityNames.append("ViewerStartAuction");
|
||||
capabilityNames.append("ViewerStats");
|
||||
|
||||
|
||||
@@ -881,3 +881,72 @@ void send_stats()
|
||||
LLHTTPClient::post(url, body, new ViewerStatsResponder);
|
||||
}
|
||||
|
||||
LLViewerStats::PhaseMap::PhaseMap()
|
||||
{
|
||||
}
|
||||
|
||||
LLTimer& LLViewerStats::PhaseMap::getPhaseTimer(const std::string& phase_name)
|
||||
{
|
||||
phase_map_t::iterator iter = mPhaseMap.find(phase_name);
|
||||
if (iter == mPhaseMap.end())
|
||||
{
|
||||
LLTimer timer;
|
||||
mPhaseMap[phase_name] = timer;
|
||||
}
|
||||
LLTimer& timer = mPhaseMap[phase_name];
|
||||
return timer;
|
||||
}
|
||||
|
||||
void LLViewerStats::PhaseMap::startPhase(const std::string& phase_name)
|
||||
{
|
||||
LLTimer& timer = getPhaseTimer(phase_name);
|
||||
lldebugs << "startPhase " << phase_name << llendl;
|
||||
timer.start();
|
||||
}
|
||||
|
||||
void LLViewerStats::PhaseMap::stopPhase(const std::string& phase_name)
|
||||
{
|
||||
phase_map_t::iterator iter = mPhaseMap.find(phase_name);
|
||||
if (iter != mPhaseMap.end())
|
||||
{
|
||||
if (iter->second.getStarted())
|
||||
{
|
||||
// Going from started to paused state - record stats.
|
||||
iter->second.stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool LLViewerStats::PhaseMap::getPhaseValues(const std::string& phase_name, F32& elapsed, bool& completed)
|
||||
{
|
||||
phase_map_t::iterator iter = mPhaseMap.find(phase_name);
|
||||
if (iter != mPhaseMap.end())
|
||||
{
|
||||
elapsed = iter->second.getElapsedTimeF32();
|
||||
completed = !iter->second.getStarted();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void LLViewerStats::PhaseMap::clearPhases()
|
||||
{
|
||||
lldebugs << "clearPhases" << llendl;
|
||||
|
||||
mPhaseMap.clear();
|
||||
}
|
||||
|
||||
LLSD LLViewerStats::PhaseMap::dumpPhases()
|
||||
{
|
||||
LLSD result;
|
||||
for (phase_map_t::iterator iter = mPhaseMap.begin(); iter != mPhaseMap.end(); ++iter)
|
||||
{
|
||||
const std::string& phase_name = iter->first;
|
||||
result[phase_name]["completed"] = LLSD::Integer(!(iter->second.getStarted()));
|
||||
result[phase_name]["elapsed"] = iter->second.getElapsedTimeF32();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -285,6 +285,26 @@ public:
|
||||
|
||||
StatsAccumulator mAgentPositionSnaps;
|
||||
|
||||
// Phase tracking (originally put in for avatar rezzing), tracking
|
||||
// progress of active/completed phases for activities like outfit changing.
|
||||
typedef std::map<std::string,LLTimer> phase_map_t;
|
||||
typedef std::map<std::string,StatsAccumulator> phase_stats_t;
|
||||
class PhaseMap
|
||||
{
|
||||
private:
|
||||
phase_map_t mPhaseMap;
|
||||
public:
|
||||
PhaseMap();
|
||||
LLTimer& getPhaseTimer(const std::string& phase_name);
|
||||
bool getPhaseValues(const std::string& phase_name, F32& elapsed, bool& completed);
|
||||
void startPhase(const std::string& phase_name);
|
||||
void stopPhase(const std::string& phase_name);
|
||||
void clearPhases();
|
||||
LLSD dumpPhases();
|
||||
phase_map_t::iterator begin() { return mPhaseMap.begin(); }
|
||||
phase_map_t::iterator end() { return mPhaseMap.end(); }
|
||||
};
|
||||
|
||||
private:
|
||||
F64 mStats[ST_COUNT];
|
||||
|
||||
|
||||
@@ -1137,7 +1137,7 @@ void LLViewerFetchedTexture::dump()
|
||||
// ONLY called from LLViewerFetchedTextureList
|
||||
void LLViewerFetchedTexture::destroyTexture()
|
||||
{
|
||||
if(LLImageGL::sGlobalTextureMemoryInBytes < sMaxDesiredTextureMemInBytes)//not ready to release unused memory.
|
||||
if(LLImageGL::sGlobalTextureMemoryInBytes < sMaxDesiredTextureMemInBytes * 0.95f)//not ready to release unused memory.
|
||||
{
|
||||
return ;
|
||||
}
|
||||
|
||||
@@ -137,6 +137,7 @@ public:
|
||||
void resetTextureStats();
|
||||
void setMaxVirtualSizeResetInterval(S32 interval)const {mMaxVirtualSizeResetInterval = interval;}
|
||||
void resetMaxVirtualSizeResetCounter()const {mMaxVirtualSizeResetCounter = mMaxVirtualSizeResetInterval;}
|
||||
S32 getMaxVirtualSizeResetCounter() const { return mMaxVirtualSizeResetCounter; }
|
||||
|
||||
virtual F32 getMaxVirtualSize() ;
|
||||
|
||||
@@ -309,6 +310,7 @@ public:
|
||||
// the priority list, and cause horrible things to happen.
|
||||
void setDecodePriority(F32 priority = -1.0f);
|
||||
F32 getDecodePriority() const { return mDecodePriority; };
|
||||
F32 getAdditionalDecodePriority() const { return mAdditionalDecodePriority; };
|
||||
|
||||
void setAdditionalDecodePriority(F32 priority) ;
|
||||
|
||||
|
||||
@@ -400,6 +400,23 @@ LLViewerFetchedTexture* LLViewerTextureList::getImageFromUrl(const std::string&
|
||||
|
||||
LLPointer<LLViewerFetchedTexture> imagep = findImage(new_id);
|
||||
|
||||
if (!imagep.isNull())
|
||||
{
|
||||
LLViewerFetchedTexture *texture = imagep.get();
|
||||
if (texture->getUrl().empty())
|
||||
{
|
||||
llwarns << "Requested texture " << new_id << " already exists but does not have a URL" << llendl;
|
||||
}
|
||||
else if (texture->getUrl() != url)
|
||||
{
|
||||
// This is not an error as long as the images really match -
|
||||
// e.g. could be two avatars wearing the same outfit.
|
||||
LL_DEBUGS("Avatar") << "Requested texture " << new_id
|
||||
<< " already exists with a different url, requested: " << url
|
||||
<< " current: " << texture->getUrl() << llendl;
|
||||
}
|
||||
|
||||
}
|
||||
if (imagep.isNull())
|
||||
{
|
||||
switch(texture_type)
|
||||
@@ -461,7 +478,23 @@ LLViewerFetchedTexture* LLViewerTextureList::getImage(const LLUUID &image_id,
|
||||
}
|
||||
|
||||
LLPointer<LLViewerFetchedTexture> imagep = findImage(image_id);
|
||||
if (!imagep.isNull())
|
||||
{
|
||||
LLViewerFetchedTexture *texture = imagep.get();
|
||||
if (request_from_host.isOk() &&
|
||||
!texture->getTargetHost().isOk())
|
||||
{
|
||||
llwarns << "Requested texture " << image_id << " already exists but does not have a host" << llendl;
|
||||
}
|
||||
else if (request_from_host.isOk() &&
|
||||
texture->getTargetHost().isOk() &&
|
||||
request_from_host != texture->getTargetHost())
|
||||
{
|
||||
llwarns << "Requested texture " << image_id << " already exists with a different target host, requested: "
|
||||
<< request_from_host << " current: " << texture->getTargetHost() << llendl;
|
||||
}
|
||||
|
||||
}
|
||||
if (imagep.isNull())
|
||||
{
|
||||
imagep = createImage(image_id, usemipmaps, boost_priority, texture_type, internal_format, primary_format, request_from_host) ;
|
||||
@@ -531,6 +564,7 @@ LLViewerFetchedTexture *LLViewerTextureList::findImage(const LLUUID &image_id)
|
||||
|
||||
void LLViewerTextureList::addImageToList(LLViewerFetchedTexture *image)
|
||||
{
|
||||
assert_main_thread();
|
||||
llassert_always(mInitialized) ;
|
||||
llassert(image);
|
||||
if (image->isInImageList())
|
||||
@@ -547,6 +581,7 @@ void LLViewerTextureList::addImageToList(LLViewerFetchedTexture *image)
|
||||
|
||||
void LLViewerTextureList::removeImageFromList(LLViewerFetchedTexture *image)
|
||||
{
|
||||
assert_main_thread();
|
||||
llassert_always(mInitialized) ;
|
||||
llassert(image);
|
||||
if (!image->isInImageList())
|
||||
@@ -900,8 +935,7 @@ void LLViewerTextureList::forceImmediateUpdate(LLViewerFetchedTexture* imagep)
|
||||
imagep->processTextureStats();
|
||||
F32 decode_priority = LLViewerFetchedTexture::maxDecodePriority() ;
|
||||
imagep->setDecodePriority(decode_priority);
|
||||
mImageList.insert(imagep);
|
||||
imagep->setInImageList(TRUE) ;
|
||||
addImageToList(imagep);
|
||||
|
||||
return ;
|
||||
}
|
||||
@@ -1022,8 +1056,7 @@ void LLViewerTextureList::decodeAllImages(F32 max_time)
|
||||
imagep->processTextureStats();
|
||||
F32 decode_priority = imagep->calcDecodePriority();
|
||||
imagep->setDecodePriority(decode_priority);
|
||||
mImageList.insert(imagep);
|
||||
imagep->setInImageList(TRUE) ;
|
||||
addImageToList(imagep);
|
||||
}
|
||||
image_list.clear();
|
||||
|
||||
|
||||
@@ -1129,6 +1129,8 @@ LLVOAvatar::~LLVOAvatar()
|
||||
mAnimationSources.clear();
|
||||
LLLoadedCallbackEntry::cleanUpCallbackList(&mCallbackTextureList) ;
|
||||
|
||||
getPhases().clearPhases();
|
||||
|
||||
SHClientTagMgr::instance().clearAvatarTag(this);
|
||||
|
||||
lldebugs << "LLVOAvatar Destructor end" << llendl;
|
||||
@@ -2193,27 +2195,53 @@ U32 LLVOAvatar::processUpdateMessage(LLMessageSystem *mesgsys,
|
||||
return retval;
|
||||
}
|
||||
|
||||
// virtual
|
||||
S32 LLVOAvatar::setTETexture(const U8 te, const LLUUID& uuid)
|
||||
LLViewerFetchedTexture *LLVOAvatar::getBakedTextureImage(const U8 te, const LLUUID& uuid)
|
||||
{
|
||||
// The core setTETexture() method requests images, so we need
|
||||
// to redirect certain avatar texture requests to different sims.
|
||||
if (isIndexBakedTexture((ETextureIndex)te))
|
||||
LLViewerFetchedTexture *result = NULL;
|
||||
|
||||
if (uuid == IMG_DEFAULT_AVATAR ||
|
||||
uuid == IMG_DEFAULT ||
|
||||
uuid == IMG_INVISIBLE)
|
||||
{
|
||||
// Should already exist, don't need to find it on sim or baked-texture host.
|
||||
result = gTextureList.findImage(uuid);
|
||||
}
|
||||
|
||||
if (!result)
|
||||
{
|
||||
const std::string url = getImageURL(te,uuid);
|
||||
if (!url.empty())
|
||||
{
|
||||
llinfos << "texture URL " << url << llendl;
|
||||
return setTETextureCore(te, uuid, url);
|
||||
result = LLViewerTextureManager::getFetchedTextureFromUrl(
|
||||
url, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE, 0, 0, uuid);
|
||||
}
|
||||
else
|
||||
{
|
||||
llinfos << "get texture from host " << uuid << llendl;
|
||||
LLHost host = getObjectHost();
|
||||
result = LLViewerTextureManager::getFetchedTexture(
|
||||
uuid, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE, 0, 0, host);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
LLHost target_host = getObjectHost();
|
||||
return setTETextureCore(te, uuid, target_host);
|
||||
}
|
||||
else
|
||||
// virtual
|
||||
S32 LLVOAvatar::setTETexture(const U8 te, const LLUUID& uuid)
|
||||
{
|
||||
if (!isIndexBakedTexture((ETextureIndex)te))
|
||||
{
|
||||
return setTETextureCore(te, uuid, LLHost::invalid);
|
||||
if (!uuid.isNull())
|
||||
{
|
||||
llinfos << "ignoring texture " << uuid << " in non-baked slot " << (S32)te << " - will use null " << llendl;
|
||||
}
|
||||
return LLViewerObject::setTETexture(te, LLUUID::null);
|
||||
}
|
||||
|
||||
LLViewerFetchedTexture *image = getBakedTextureImage(te,uuid);
|
||||
llassert(image);
|
||||
return setTETextureCore(te, image);
|
||||
}
|
||||
|
||||
static LLFastTimer::DeclareTimer FTM_AVATAR_UPDATE("Avatar Update");
|
||||
@@ -3536,9 +3564,24 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent)
|
||||
{
|
||||
central_bake_version = getRegion()->getCentralBakeVersion();
|
||||
}
|
||||
addDebugText(llformat("mLocal: %d, mEdit: %d, mUSB: %d, CBV: %d",
|
||||
mUseLocalAppearance, mIsEditingAppearance,
|
||||
mUseServerBakes, central_bake_version));
|
||||
bool all_baked_downloaded = allBakedTexturesCompletelyDownloaded();
|
||||
bool all_local_downloaded = allLocalTexturesCompletelyDownloaded();
|
||||
std::string debug_line = llformat("%s%s - mLocal: %d, mEdit: %d, mUSB: %d, CBV: %d",
|
||||
all_local_downloaded ? "L" : "l",
|
||||
all_baked_downloaded ? "B" : "b",
|
||||
mUseLocalAppearance, mIsEditingAppearance,
|
||||
mUseServerBakes, central_bake_version);
|
||||
std::string origin_string = bakedTextureOriginInfo();
|
||||
debug_line += " [" + origin_string + "]";
|
||||
if (isSelf())
|
||||
{
|
||||
S32 curr_cof_version = LLAppearanceMgr::instance().getCOFVersion();
|
||||
S32 last_request_cof_version = LLAppearanceMgr::instance().getLastUpdateRequestCOFVersion();
|
||||
S32 last_received_cof_version = LLAppearanceMgr::instance().getLastAppearanceUpdateCOFVersion();
|
||||
debug_line += llformat(" - cof: %d req: %d rcv:%d",
|
||||
curr_cof_version, last_request_cof_version, last_received_cof_version);
|
||||
}
|
||||
addDebugText(debug_line);
|
||||
}
|
||||
if (gSavedSettings.getBOOL("DebugAvatarCompositeBaked"))
|
||||
{
|
||||
@@ -4675,11 +4718,206 @@ U32 LLVOAvatar::renderImpostor(LLColor4U color, S32 diffuse_channel)
|
||||
return 6;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// LLVOAvatar::updateTextures()
|
||||
//------------------------------------------------------------------------
|
||||
bool LLVOAvatar::allTexturesCompletelyDownloaded(std::set<LLUUID>& ids)
|
||||
{
|
||||
for (std::set<LLUUID>::const_iterator it = ids.begin(); it != ids.end(); ++it)
|
||||
{
|
||||
LLViewerFetchedTexture *imagep = gTextureList.findImage(*it);
|
||||
if (imagep && imagep->getDiscardLevel()!=0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LLVOAvatar::allLocalTexturesCompletelyDownloaded()
|
||||
{
|
||||
std::set<LLUUID> local_ids;
|
||||
collectLocalTextureUUIDs(local_ids);
|
||||
return allTexturesCompletelyDownloaded(local_ids);
|
||||
}
|
||||
|
||||
bool LLVOAvatar::allBakedTexturesCompletelyDownloaded()
|
||||
{
|
||||
std::set<LLUUID> baked_ids;
|
||||
collectBakedTextureUUIDs(baked_ids);
|
||||
return allTexturesCompletelyDownloaded(baked_ids);
|
||||
}
|
||||
|
||||
void LLVOAvatar::bakedTextureOriginCounts(S32 &sb_count, // server-bake, has origin URL.
|
||||
S32 &host_count, // host-based bake, has host.
|
||||
S32 &both_count, // error - both host and URL set.
|
||||
S32 &neither_count) // error - neither set.
|
||||
{
|
||||
sb_count = host_count = both_count = neither_count = 0;
|
||||
|
||||
std::set<LLUUID> baked_ids;
|
||||
collectBakedTextureUUIDs(baked_ids);
|
||||
for (std::set<LLUUID>::const_iterator it = baked_ids.begin(); it != baked_ids.end(); ++it)
|
||||
{
|
||||
LLViewerFetchedTexture *imagep = gTextureList.findImage(*it);
|
||||
bool has_url = false, has_host = false;
|
||||
if (!imagep->getUrl().empty())
|
||||
{
|
||||
has_url = true;
|
||||
}
|
||||
if (imagep->getTargetHost().isOk())
|
||||
{
|
||||
has_host = true;
|
||||
}
|
||||
if (has_url && !has_host) sb_count++;
|
||||
else if (has_host && !has_url) host_count++;
|
||||
else if (has_host && has_url) both_count++;
|
||||
else if (!has_host && !has_url) neither_count++;
|
||||
}
|
||||
}
|
||||
|
||||
std::string LLVOAvatar::bakedTextureOriginInfo()
|
||||
{
|
||||
std::string result;
|
||||
|
||||
std::set<LLUUID> baked_ids;
|
||||
collectBakedTextureUUIDs(baked_ids);
|
||||
for (std::set<LLUUID>::const_iterator it = baked_ids.begin(); it != baked_ids.end(); ++it)
|
||||
{
|
||||
LLViewerFetchedTexture *imagep = gTextureList.findImage(*it);
|
||||
bool has_url = false, has_host = false;
|
||||
if (!imagep->getUrl().empty())
|
||||
{
|
||||
has_url = true;
|
||||
}
|
||||
if (imagep->getTargetHost().isOk())
|
||||
{
|
||||
has_host = true;
|
||||
}
|
||||
if (has_url && !has_host) result += "u"; // server-bake texture with url
|
||||
else if (has_host && !has_url) result += "h"; // old-style texture on sim
|
||||
else if (has_host && has_url) result += "?"; // both origins?
|
||||
else if (!has_host && !has_url) result += "n"; // no origin?
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
S32 LLVOAvatar::totalTextureMemForUUIDS(std::set<LLUUID>& ids)
|
||||
{
|
||||
S32 result = 0;
|
||||
for (std::set<LLUUID>::const_iterator it = ids.begin(); it != ids.end(); ++it)
|
||||
{
|
||||
LLViewerFetchedTexture *imagep = gTextureList.findImage(*it);
|
||||
if (imagep)
|
||||
{
|
||||
result += imagep->getTextureMemory();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void LLVOAvatar::collectLocalTextureUUIDs(std::set<LLUUID>& ids)
|
||||
{
|
||||
for (U32 texture_index = 0; texture_index < getNumTEs(); texture_index++)
|
||||
{
|
||||
LLWearableType::EType wearable_type = LLAvatarAppearanceDictionary::getTEWearableType((ETextureIndex)texture_index);
|
||||
U32 num_wearables = gAgentWearables.getWearableCount(wearable_type);
|
||||
|
||||
LLViewerFetchedTexture *imagep = NULL;
|
||||
for (U32 wearable_index = 0; wearable_index < num_wearables; wearable_index++)
|
||||
{
|
||||
imagep = LLViewerTextureManager::staticCastToFetchedTexture(getImage(texture_index, wearable_index), TRUE);
|
||||
if (imagep)
|
||||
{
|
||||
const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = LLAvatarAppearanceDictionary::getInstance()->getTexture((ETextureIndex)texture_index);
|
||||
if (texture_dict->mIsLocalTexture)
|
||||
{
|
||||
ids.insert(imagep->getID());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ids.erase(IMG_DEFAULT);
|
||||
ids.erase(IMG_DEFAULT_AVATAR);
|
||||
ids.erase(IMG_INVISIBLE);
|
||||
}
|
||||
|
||||
void LLVOAvatar::collectBakedTextureUUIDs(std::set<LLUUID>& ids)
|
||||
{
|
||||
for (U32 texture_index = 0; texture_index < getNumTEs(); texture_index++)
|
||||
{
|
||||
LLViewerFetchedTexture *imagep = NULL;
|
||||
if (isIndexBakedTexture((ETextureIndex) texture_index))
|
||||
{
|
||||
imagep = LLViewerTextureManager::staticCastToFetchedTexture(getImage(texture_index,0), TRUE);
|
||||
if (imagep)
|
||||
{
|
||||
ids.insert(imagep->getID());
|
||||
}
|
||||
}
|
||||
}
|
||||
ids.erase(IMG_DEFAULT);
|
||||
ids.erase(IMG_DEFAULT_AVATAR);
|
||||
ids.erase(IMG_INVISIBLE);
|
||||
}
|
||||
|
||||
void LLVOAvatar::collectTextureUUIDs(std::set<LLUUID>& ids)
|
||||
{
|
||||
collectLocalTextureUUIDs(ids);
|
||||
collectBakedTextureUUIDs(ids);
|
||||
}
|
||||
|
||||
void LLVOAvatar::releaseOldTextures()
|
||||
{
|
||||
S32 current_texture_mem = 0;
|
||||
|
||||
// Any textures that we used to be using but are no longer using should no longer be flagged as "NO_DELETE"
|
||||
std::set<LLUUID> baked_texture_ids;
|
||||
collectBakedTextureUUIDs(baked_texture_ids);
|
||||
S32 new_baked_mem = totalTextureMemForUUIDS(baked_texture_ids);
|
||||
|
||||
std::set<LLUUID> local_texture_ids;
|
||||
collectLocalTextureUUIDs(local_texture_ids);
|
||||
S32 new_local_mem = totalTextureMemForUUIDS(local_texture_ids);
|
||||
|
||||
std::set<LLUUID> new_texture_ids;
|
||||
new_texture_ids.insert(baked_texture_ids.begin(),baked_texture_ids.end());
|
||||
new_texture_ids.insert(local_texture_ids.begin(),local_texture_ids.end());
|
||||
S32 new_total_mem = totalTextureMemForUUIDS(new_texture_ids);
|
||||
|
||||
S32 old_total_mem = totalTextureMemForUUIDS(mTextureIDs);
|
||||
LL_DEBUGS("Avatar") << getFullname() << " old_total_mem: " << old_total_mem << " new_total_mem (L/B): " << new_total_mem << " (" << new_local_mem <<", " << new_baked_mem << ")" << llendl;
|
||||
if (!isSelf() && new_total_mem > new_baked_mem)
|
||||
{
|
||||
llwarns << "extra local textures stored for non-self av" << llendl;
|
||||
}
|
||||
for (std::set<LLUUID>::iterator it = mTextureIDs.begin(); it != mTextureIDs.end(); ++it)
|
||||
{
|
||||
if (new_texture_ids.find(*it) == new_texture_ids.end())
|
||||
{
|
||||
LLViewerFetchedTexture *imagep = gTextureList.findImage(*it);
|
||||
if (imagep)
|
||||
{
|
||||
current_texture_mem += imagep->getTextureMemory();
|
||||
if (imagep->getTextureState() == LLGLTexture::NO_DELETE)
|
||||
{
|
||||
// This will allow the texture to be deleted if not in use.
|
||||
imagep->forceActive();
|
||||
|
||||
// This resets the clock to texture being flagged
|
||||
// as unused, preventing the texture from being
|
||||
// deleted immediately. If other avatars or
|
||||
// objects are using it, it can still be flagged
|
||||
// no-delete by them.
|
||||
imagep->forceUpdateBindStats();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
mTextureIDs = new_texture_ids;
|
||||
}
|
||||
|
||||
void LLVOAvatar::updateTextures()
|
||||
{
|
||||
releaseOldTextures();
|
||||
|
||||
BOOL render_avatar = TRUE;
|
||||
|
||||
if (mIsDummy || gNoRender)
|
||||
@@ -6604,39 +6842,141 @@ void LLVOAvatar::updateRezzedStatusTimers()
|
||||
if (rez_status != mLastRezzedStatus)
|
||||
{
|
||||
LL_DEBUGS("Avatar") << avString() << "rez state change: " << mLastRezzedStatus << " -> " << rez_status << LL_ENDL;
|
||||
/*bool is_cloud_or_gray = (rez_status==0 || rez_status==1);
|
||||
bool is_cloud_or_gray = (rez_status==0 || rez_status==1);
|
||||
bool was_cloud_or_gray = (mLastRezzedStatus==0 || mLastRezzedStatus==1);
|
||||
bool is_cloud = (rez_status==0);
|
||||
bool was_cloud = (mLastRezzedStatus==0);
|
||||
|
||||
]// Non-cloud to cloud
|
||||
// Non-cloud to cloud
|
||||
if (is_cloud && !was_cloud)
|
||||
{
|
||||
// start cloud timer.
|
||||
getPhases().startPhase("cloud");
|
||||
startPhase("cloud");
|
||||
}
|
||||
else if (was_cloud && !is_cloud)
|
||||
{
|
||||
// stop cloud timer, which will capture stats.
|
||||
getPhases().stopPhase("cloud");
|
||||
stopPhase("cloud");
|
||||
}
|
||||
|
||||
// Non-cloud-or-gray to cloud-or-gray
|
||||
if (is_cloud_or_gray && !was_cloud_or_gray)
|
||||
{
|
||||
// start cloud-or-gray timer.
|
||||
getPhases().startPhase("cloud-or-gray");
|
||||
startPhase("cloud-or-gray");
|
||||
}
|
||||
else if (was_cloud_or_gray && !is_cloud_or_gray)
|
||||
{
|
||||
// stop cloud-or-gray timer, which will capture stats.
|
||||
getPhases().stopPhase("cloud-or-gray");
|
||||
}*/
|
||||
stopPhase("cloud-or-gray");
|
||||
}
|
||||
|
||||
mLastRezzedStatus = rez_status;
|
||||
}
|
||||
}
|
||||
|
||||
void LLVOAvatar::clearPhases()
|
||||
{
|
||||
getPhases().clearPhases();
|
||||
}
|
||||
|
||||
void LLVOAvatar::startPhase(const std::string& phase_name)
|
||||
{
|
||||
getPhases().startPhase(phase_name);
|
||||
}
|
||||
|
||||
void LLVOAvatar::logPendingPhases()
|
||||
{
|
||||
for (LLViewerStats::phase_map_t::iterator it = getPhases().begin();
|
||||
it != getPhases().end();
|
||||
++it)
|
||||
{
|
||||
const std::string& phase_name = it->first;
|
||||
F32 elapsed;
|
||||
bool completed;
|
||||
if (getPhases().getPhaseValues(phase_name, elapsed, completed))
|
||||
{
|
||||
if (!completed)
|
||||
{
|
||||
logMetricsTimerRecord(phase_name, elapsed, completed);
|
||||
}
|
||||
else
|
||||
{
|
||||
llwarns << "ignoring " << phase_name << llendl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//static
|
||||
void LLVOAvatar::logPendingPhasesAllAvatars()
|
||||
{
|
||||
for (std::vector<LLCharacter*>::iterator iter = LLCharacter::sInstances.begin();
|
||||
iter != LLCharacter::sInstances.end(); ++iter)
|
||||
{
|
||||
LLVOAvatar* inst = (LLVOAvatar*) *iter;
|
||||
if( inst->isDead() )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
inst->logPendingPhases();
|
||||
}
|
||||
}
|
||||
|
||||
void LLVOAvatar::logMetricsTimerRecord(const std::string& phase_name, F32 elapsed, bool completed)
|
||||
{
|
||||
LLSD record;
|
||||
record["timer_name"] = phase_name;
|
||||
record["agent_id"] = gAgent.getID();
|
||||
record["avatar_id"] = getID();
|
||||
record["elapsed"] = elapsed;
|
||||
record["completed"] = completed;
|
||||
U32 grid_x(0), grid_y(0);
|
||||
if (getRegion())
|
||||
{
|
||||
record["central_bake_version"] = LLSD::Integer(getRegion()->getCentralBakeVersion());
|
||||
grid_from_region_handle(getRegion()->getHandle(), &grid_x, &grid_y);
|
||||
}
|
||||
record["grid_x"] = LLSD::Integer(grid_x);
|
||||
record["grid_y"] = LLSD::Integer(grid_y);
|
||||
record["is_using_server_bakes"] = ((bool) isUsingServerBakes());
|
||||
record["is_self"] = isSelf();
|
||||
|
||||
|
||||
std::ostringstream ostr;
|
||||
ostr << LLSDNotationStreamer(record);
|
||||
LL_DEBUGS("Avatar") << "record\n" << ostr.str() << llendl;
|
||||
|
||||
if (isAgentAvatarValid())
|
||||
{
|
||||
gAgentAvatarp->addMetricsTimerRecord(record);
|
||||
}
|
||||
}
|
||||
|
||||
void LLVOAvatar::stopPhase(const std::string& phase_name)
|
||||
{
|
||||
F32 elapsed;
|
||||
bool completed;
|
||||
if (getPhases().getPhaseValues(phase_name, elapsed, completed))
|
||||
{
|
||||
if (!completed)
|
||||
{
|
||||
getPhases().stopPhase(phase_name);
|
||||
completed = true;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
llwarns << "stop when stopped already for " << phase_name << llendl;
|
||||
}
|
||||
logMetricsTimerRecord(phase_name, elapsed, completed);
|
||||
}
|
||||
else
|
||||
{
|
||||
llwarns << "stop when not started for " << phase_name << llendl;
|
||||
}
|
||||
}
|
||||
|
||||
// call periodically to keep isFullyLoaded up to date.
|
||||
// returns true if the value has changed.
|
||||
BOOL LLVOAvatar::updateIsFullyLoaded()
|
||||
@@ -6764,6 +7104,7 @@ void LLVOAvatar::debugColorizeSubMeshes(U32 i, const LLColor4& color)
|
||||
// virtual
|
||||
void LLVOAvatar::updateMeshTextures()
|
||||
{
|
||||
static S32 update_counter = 0;
|
||||
mBakedTextureDebugText.clear();
|
||||
// llinfos << "updateMeshTextures" << llendl;
|
||||
if (gNoRender) return;
|
||||
@@ -6794,7 +7135,8 @@ void LLVOAvatar::updateMeshTextures()
|
||||
std::vector<BOOL> use_lkg_baked_layer; // lkg = "last known good"
|
||||
use_lkg_baked_layer.resize(mBakedTextureDatas.size(), false);
|
||||
|
||||
mBakedTextureDebugText += "indx layerset linvld ltda ilb ulkg ltid\n";
|
||||
mBakedTextureDebugText += llformat("%06d\n",update_counter++);
|
||||
mBakedTextureDebugText += "indx layerset linvld ltda ilb ulkg ltid\n";
|
||||
for (U32 i=0; i < mBakedTextureDatas.size(); i++)
|
||||
{
|
||||
is_layer_baked[i] = isTextureDefined(mBakedTextureDatas[i].mTextureIndex);
|
||||
@@ -6827,6 +7169,8 @@ void LLVOAvatar::updateMeshTextures()
|
||||
last_id_string = "A";
|
||||
else if (mBakedTextureDatas[i].mLastTextureID == IMG_DEFAULT)
|
||||
last_id_string = "D";
|
||||
else if (mBakedTextureDatas[i].mLastTextureID == IMG_INVISIBLE)
|
||||
last_id_string = "I";
|
||||
else
|
||||
last_id_string = "*";
|
||||
bool is_ltda = layerset
|
||||
@@ -7370,7 +7714,7 @@ void LLVOAvatar::dumpAppearanceMsgParams( const std::string& dump_prefix,
|
||||
}
|
||||
else
|
||||
{
|
||||
llinfos << "xmlfile write handle obtained : " << fullpath << llendl;
|
||||
LL_DEBUGS("Avatar") << "dumping appearance message to " << fullpath << llendl;
|
||||
}
|
||||
|
||||
|
||||
@@ -7394,47 +7738,174 @@ void LLVOAvatar::dumpAppearanceMsgParams( const std::string& dump_prefix,
|
||||
}
|
||||
}
|
||||
|
||||
struct LLAppearanceMessageContents
|
||||
{
|
||||
LLAppearanceMessageContents():
|
||||
mAppearanceVersion(-1),
|
||||
mParamAppearanceVersion(-1),
|
||||
mCOFVersion(LLViewerInventoryCategory::VERSION_UNKNOWN)
|
||||
{
|
||||
}
|
||||
LLTEContents mTEContents;
|
||||
S32 mAppearanceVersion;
|
||||
S32 mParamAppearanceVersion;
|
||||
S32 mCOFVersion;
|
||||
// For future use:
|
||||
//U32 appearance_flags = 0;
|
||||
std::vector<F32> mParamWeights;
|
||||
std::vector<LLVisualParam*> mParams;
|
||||
};
|
||||
|
||||
void LLVOAvatar::parseAppearanceMessage(LLMessageSystem* mesgsys, LLAppearanceMessageContents& contents)
|
||||
{
|
||||
parseTEMessage(mesgsys, _PREHASH_ObjectData, -1, contents.mTEContents);
|
||||
|
||||
// Parse the AppearanceData field, if any.
|
||||
if (mesgsys->has(_PREHASH_AppearanceData))
|
||||
{
|
||||
U8 av_u8;
|
||||
mesgsys->getU8Fast(_PREHASH_AppearanceData, _PREHASH_AppearanceVersion, av_u8, 0);
|
||||
contents.mAppearanceVersion = av_u8;
|
||||
llinfos << "appversion set by AppearanceData field: " << contents.mAppearanceVersion << llendl;
|
||||
mesgsys->getS32Fast(_PREHASH_AppearanceData, _PREHASH_CofVersion, contents.mCOFVersion, 0);
|
||||
// For future use:
|
||||
//mesgsys->getU32Fast(_PREHASH_AppearanceData, _PREHASH_Flags, appearance_flags, 0);
|
||||
}
|
||||
|
||||
// Parse visual params, if any.
|
||||
S32 num_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_VisualParam);
|
||||
bool drop_visual_params_debug = gSavedSettings.getBOOL("BlockSomeAvatarAppearanceVisualParams") && (ll_rand(2) == 0); // pretend that ~12% of AvatarAppearance messages arrived without a VisualParam block, for testing
|
||||
if( num_blocks > 1 && !drop_visual_params_debug)
|
||||
{
|
||||
LL_DEBUGS("Avatar") << avString() << " handle visual params, num_blocks " << num_blocks << LL_ENDL;
|
||||
|
||||
LLVisualParam* param = getFirstVisualParam();
|
||||
llassert(param); // if this ever fires, we should do the same as when num_blocks<=1
|
||||
if (!param)
|
||||
{
|
||||
llwarns << "No visual params!" << llendl;
|
||||
}
|
||||
else
|
||||
{
|
||||
for( S32 i = 0; i < num_blocks; i++ )
|
||||
{
|
||||
while( param && (param->getGroup() != VISUAL_PARAM_GROUP_TWEAKABLE) ) // should not be any of group VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT
|
||||
{
|
||||
param = getNextVisualParam();
|
||||
}
|
||||
|
||||
if( !param )
|
||||
{
|
||||
// more visual params supplied than expected - just process what we know about
|
||||
break;
|
||||
}
|
||||
|
||||
U8 value;
|
||||
mesgsys->getU8Fast(_PREHASH_VisualParam, _PREHASH_ParamValue, value, i);
|
||||
F32 newWeight = U8_to_F32(value, param->getMinWeight(), param->getMaxWeight());
|
||||
contents.mParamWeights.push_back(newWeight);
|
||||
contents.mParams.push_back(param);
|
||||
|
||||
param = getNextVisualParam();
|
||||
}
|
||||
}
|
||||
|
||||
const S32 expected_tweakable_count = getVisualParamCountInGroup(VISUAL_PARAM_GROUP_TWEAKABLE); // don't worry about VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT
|
||||
if (num_blocks != expected_tweakable_count)
|
||||
{
|
||||
llinfos << "Number of params in AvatarAppearance msg (" << num_blocks << ") does not match number of tweakable params in avatar xml file (" << expected_tweakable_count << "). Processing what we can. object: " << getID() << llendl;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (drop_visual_params_debug)
|
||||
{
|
||||
llinfos << "Debug-faked lack of parameters on AvatarAppearance for object: " << getID() << llendl;
|
||||
}
|
||||
else
|
||||
{
|
||||
llinfos << "AvatarAppearance msg received without any parameters, object: " << getID() << llendl;
|
||||
}
|
||||
}
|
||||
|
||||
LLVisualParam* appearance_version_param = getVisualParam(11000);
|
||||
if (appearance_version_param)
|
||||
{
|
||||
std::vector<LLVisualParam*>::iterator it = std::find(contents.mParams.begin(), contents.mParams.end(),appearance_version_param);
|
||||
if (it != contents.mParams.end())
|
||||
{
|
||||
S32 index = it - contents.mParams.begin();
|
||||
llinfos << "index: " << index << llendl;
|
||||
contents.mParamAppearanceVersion = llround(contents.mParamWeights[index]);
|
||||
LL_DEBUGS("Avatar") << "appversion req by appearance_version param: " << contents.mParamAppearanceVersion << llendl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool resolve_appearance_version(const LLAppearanceMessageContents& contents, S32& appearance_version)
|
||||
{
|
||||
appearance_version = -1;
|
||||
|
||||
if ((contents.mAppearanceVersion) >= 0 &&
|
||||
(contents.mParamAppearanceVersion >= 0) &&
|
||||
(contents.mAppearanceVersion != contents.mParamAppearanceVersion))
|
||||
{
|
||||
llwarns << "inconsistent appearance_version settings - field: " <<
|
||||
contents.mAppearanceVersion << ", param: " << contents.mParamAppearanceVersion << llendl;
|
||||
return false;
|
||||
}
|
||||
if (contents.mParamAppearanceVersion >= 0) // use visual param if available.
|
||||
{
|
||||
appearance_version = contents.mParamAppearanceVersion;
|
||||
}
|
||||
if (contents.mAppearanceVersion >= 0)
|
||||
{
|
||||
appearance_version = contents.mAppearanceVersion;
|
||||
}
|
||||
if (appearance_version < 0) // still not set, go with 0.
|
||||
{
|
||||
appearance_version = 0;
|
||||
}
|
||||
LL_DEBUGS("Avatar") << "appearance version info - field " << contents.mAppearanceVersion
|
||||
<< " param: " << contents.mParamAppearanceVersion
|
||||
<< " final: " << appearance_version << llendl;
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// processAvatarAppearance()
|
||||
//-----------------------------------------------------------------------------
|
||||
void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )
|
||||
{
|
||||
LL_DEBUGS("Avatar") << "starts" << llendl;
|
||||
|
||||
bool enable_verbose_dumps = gSavedSettings.getBOOL("DebugAvatarAppearanceMessage");
|
||||
std::string dump_prefix = getFullname() + "_" + (isSelf()?"s":"o") + "_";
|
||||
if (enable_verbose_dumps) { dumpArchetypeXML(dump_prefix + "process_start"); }
|
||||
//if (enable_verbose_dumps) { dumpArchetypeXML(dump_prefix + "process_start"); }
|
||||
if (gSavedSettings.getBOOL("BlockAvatarAppearanceMessages"))
|
||||
{
|
||||
llwarns << "Blocking AvatarAppearance message" << llendl;
|
||||
return;
|
||||
}
|
||||
LLMemType mt(LLMemType::MTYPE_AVATAR);
|
||||
|
||||
BOOL is_first_appearance_message = !mFirstAppearanceMessageReceived;
|
||||
mFirstAppearanceMessageReceived = TRUE;
|
||||
|
||||
LL_INFOS("Avatar") << avString() << "processAvatarAppearance start " << mID
|
||||
<< " first? " << is_first_appearance_message << " self? " << isSelf() << LL_ENDL;
|
||||
|
||||
|
||||
ESex old_sex = getSex();
|
||||
|
||||
LLTEContents tec;
|
||||
parseTEMessage(mesgsys, _PREHASH_ObjectData, -1, tec);
|
||||
|
||||
U8 appearance_version = 0;
|
||||
S32 this_update_cof_version = LLViewerInventoryCategory::VERSION_UNKNOWN;
|
||||
S32 last_update_request_cof_version = LLAppearanceMgr::instance().mLastUpdateRequestCOFVersion;
|
||||
// For future use:
|
||||
//U32 appearance_flags = 0;
|
||||
|
||||
if (mesgsys->has(_PREHASH_AppearanceData))
|
||||
LLAppearanceMessageContents contents;
|
||||
parseAppearanceMessage(mesgsys, contents);
|
||||
if (enable_verbose_dumps)
|
||||
{
|
||||
mesgsys->getU8Fast(_PREHASH_AppearanceData, _PREHASH_AppearanceVersion, appearance_version, 0);
|
||||
mesgsys->getS32Fast(_PREHASH_AppearanceData, _PREHASH_CofVersion, this_update_cof_version, 0);
|
||||
// For future use:
|
||||
//mesgsys->getU32Fast(_PREHASH_AppearanceData, _PREHASH_Flags, appearance_flags, 0);
|
||||
dumpAppearanceMsgParams(dump_prefix + "appearance_msg", contents.mParamWeights, contents.mTEContents);
|
||||
}
|
||||
|
||||
S32 appearance_version;
|
||||
if (!resolve_appearance_version(contents, appearance_version))
|
||||
{
|
||||
llwarns << "bad appearance version info, discarding" << llendl;
|
||||
return;
|
||||
}
|
||||
S32 this_update_cof_version = contents.mCOFVersion;
|
||||
S32 last_update_request_cof_version = LLAppearanceMgr::instance().mLastUpdateRequestCOFVersion;
|
||||
|
||||
// Only now that we have result of appearance_version can we decide whether to bail out.
|
||||
if( isSelf() )
|
||||
{
|
||||
@@ -7442,6 +7913,8 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )
|
||||
<< " last_update_request_cof_version " << last_update_request_cof_version
|
||||
<< " my_cof_version " << LLAppearanceMgr::instance().getCOFVersion() << llendl;
|
||||
|
||||
LLAppearanceMgr::instance().setLastAppearanceUpdateCOFVersion(this_update_cof_version);
|
||||
|
||||
if (getRegion() && (getRegion()->getCentralBakeVersion()==0))
|
||||
{
|
||||
llwarns << avString() << "Received AvatarAppearance message for self in non-server-bake region" << llendl;
|
||||
@@ -7451,6 +7924,10 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_DEBUGS("Avatar") << "appearance message received" << llendl;
|
||||
}
|
||||
|
||||
if (gNoRender)
|
||||
{
|
||||
@@ -7473,9 +7950,20 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )
|
||||
return;
|
||||
}
|
||||
|
||||
mUseServerBakes = (appearance_version > 0);
|
||||
S32 num_params = contents.mParamWeights.size();
|
||||
if (num_params <= 1)
|
||||
{
|
||||
// In this case, we have no reliable basis for knowing
|
||||
// appearance version, which may cause us to look for baked
|
||||
// textures in the wrong place and flag them as missing
|
||||
// assets.
|
||||
llinfos << "ignoring appearance message due to lack of params" << llendl;
|
||||
return;
|
||||
}
|
||||
|
||||
applyParsedTEMessage(tec);
|
||||
setIsUsingServerBakes(appearance_version > 0);
|
||||
|
||||
applyParsedTEMessage(contents.mTEContents);
|
||||
|
||||
SHClientTagMgr::instance().updateAvatarTag(this);
|
||||
|
||||
@@ -7493,16 +7981,16 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )
|
||||
}
|
||||
}
|
||||
|
||||
// runway - was
|
||||
// if (!is_first_appearance_message )
|
||||
// which means it would be called on second appearance message - probably wrong.
|
||||
BOOL is_first_appearance_message = !mFirstAppearanceMessageReceived;
|
||||
mFirstAppearanceMessageReceived = TRUE;
|
||||
|
||||
//llinfos << "Received AvatarAppearance: " << (isSelf() ? "(self): " : "(other): ") << std::endl <<
|
||||
// (isTextureDefined(TEX_HEAD_BAKED) ? "HEAD " : "head " ) << (getTEImage(TEX_HEAD_BAKED)->getID()) << std::endl <<
|
||||
// (isTextureDefined(TEX_UPPER_BAKED) ? "UPPER " : "upper " ) << (getTEImage(TEX_UPPER_BAKED)->getID()) << std::endl <<
|
||||
// (isTextureDefined(TEX_LOWER_BAKED) ? "LOWER " : "lower " ) << (getTEImage(TEX_LOWER_BAKED)->getID()) << std::endl <<
|
||||
// (isTextureDefined(TEX_SKIRT_BAKED) ? "SKIRT " : "skirt " ) << (getTEImage(TEX_SKIRT_BAKED)->getID()) << std::endl <<
|
||||
// (isTextureDefined(TEX_HAIR_BAKED) ? "HAIR" : "hair " ) << (getTEImage(TEX_HAIR_BAKED)->getID()) << std::endl <<
|
||||
// (isTextureDefined(TEX_EYES_BAKED) ? "EYES" : "eyes" ) << (getTEImage(TEX_EYES_BAKED)->getID()) << llendl ;
|
||||
LL_INFOS("Avatar") << avString() << "processAvatarAppearance start " << mID
|
||||
<< " first? " << is_first_appearance_message << " self? " << isSelf() << LL_ENDL;
|
||||
|
||||
if( is_first_appearance_message )
|
||||
if (is_first_appearance_message )
|
||||
{
|
||||
onFirstTEMessageReceived();
|
||||
}
|
||||
@@ -7512,85 +8000,45 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )
|
||||
|
||||
mSupportsPhysics = false;
|
||||
|
||||
// parse visual params
|
||||
S32 num_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_VisualParam);
|
||||
bool drop_visual_params_debug = gSavedSettings.getBOOL("BlockSomeAvatarAppearanceVisualParams") && (ll_rand(2) == 0); // pretend that ~12% of AvatarAppearance messages arrived without a VisualParam block, for testing
|
||||
if( num_blocks > 1 && !drop_visual_params_debug)
|
||||
// Apply visual params
|
||||
if( num_params > 1)
|
||||
{
|
||||
LL_DEBUGS("Avatar") << avString() << " handle visual params, num_blocks " << num_blocks << LL_ENDL;
|
||||
LL_DEBUGS("Avatar") << avString() << " handle visual params, num_params " << num_params << LL_ENDL;
|
||||
BOOL params_changed = FALSE;
|
||||
BOOL interp_params = FALSE;
|
||||
|
||||
LLVisualParam* param = getFirstVisualParam();
|
||||
llassert(param); // if this ever fires, we should do the same as when num_blocks<=1
|
||||
if (!param)
|
||||
for( S32 i = 0; i < num_params; i++ )
|
||||
{
|
||||
llwarns << "No visual params!" << llendl;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::vector<F32> params_for_dump;
|
||||
for( S32 i = 0; i < num_blocks; i++ )
|
||||
LLVisualParam* param = contents.mParams[i];
|
||||
F32 newWeight = contents.mParamWeights[i];
|
||||
|
||||
if(param->getID() == 10000)
|
||||
{
|
||||
while( param && (param->getGroup() != VISUAL_PARAM_GROUP_TWEAKABLE) ) // should not be any of group VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT
|
||||
{
|
||||
param = getNextVisualParam();
|
||||
}
|
||||
|
||||
if( !param )
|
||||
{
|
||||
// more visual params supplied than expected - just process what we know about
|
||||
break;
|
||||
}
|
||||
|
||||
U8 value;
|
||||
mesgsys->getU8Fast(_PREHASH_VisualParam, _PREHASH_ParamValue, value, i);
|
||||
F32 newWeight = U8_to_F32(value, param->getMinWeight(), param->getMaxWeight());
|
||||
|
||||
if(param->getID() == 10000)
|
||||
{
|
||||
mSupportsPhysics = true;
|
||||
}
|
||||
else if(param->getID() == EMERALD_BOOB_GRAVITY_PARAM && newWeight != getActualBoobGrav())
|
||||
{
|
||||
setActualBoobGrav(newWeight);
|
||||
}
|
||||
|
||||
params_for_dump.push_back(newWeight);
|
||||
|
||||
if (is_first_appearance_message || (param->getWeight() != newWeight))
|
||||
{
|
||||
//llinfos << "Received update for param " << param->getDisplayName() << " at value " << newWeight << llendl;
|
||||
params_changed = TRUE;
|
||||
if(is_first_appearance_message)
|
||||
{
|
||||
param->setWeight(newWeight, FALSE);
|
||||
}
|
||||
else
|
||||
{
|
||||
interp_params = TRUE;
|
||||
param->setAnimationTarget(newWeight, FALSE);
|
||||
}
|
||||
}
|
||||
param = getNextVisualParam();
|
||||
mSupportsPhysics = true;
|
||||
}
|
||||
else if(param->getID() == EMERALD_BOOB_GRAVITY_PARAM && newWeight != getActualBoobGrav())
|
||||
{
|
||||
setActualBoobGrav(newWeight);
|
||||
}
|
||||
|
||||
if (is_first_appearance_message || (param->getWeight() != newWeight))
|
||||
{
|
||||
params_changed = TRUE;
|
||||
if(is_first_appearance_message)
|
||||
{
|
||||
param->setWeight(newWeight, FALSE);
|
||||
}
|
||||
else
|
||||
{
|
||||
interp_params = TRUE;
|
||||
param->setAnimationTarget(newWeight, FALSE);
|
||||
}
|
||||
}
|
||||
if (enable_verbose_dumps)
|
||||
dumpAppearanceMsgParams(dump_prefix + "appearance_msg", params_for_dump, tec);
|
||||
}
|
||||
|
||||
if (enable_verbose_dumps) { dumpArchetypeXML(dump_prefix + "process_post_set_weights"); }
|
||||
|
||||
const S32 expected_tweakable_count = getVisualParamCountInGroup(VISUAL_PARAM_GROUP_TWEAKABLE); // don't worry about VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT
|
||||
if (num_blocks != expected_tweakable_count)
|
||||
if (num_params != expected_tweakable_count)
|
||||
{
|
||||
llinfos << "Number of params in AvatarAppearance msg (" << num_blocks << ") does not match number of tweakable params in avatar xml file (" << expected_tweakable_count << "). Processing what we can. object: " << getID() << llendl;
|
||||
if(is_first_appearance_message)
|
||||
{
|
||||
while( param && (param->getGroup() != VISUAL_PARAM_GROUP_TWEAKABLE) )
|
||||
param = getNextVisualParam();
|
||||
if(param && param->getName() == "breast_physics_mass")
|
||||
llinfos << getFullname() << " does not have avatar physics." << llendl;
|
||||
}
|
||||
llinfos << "Number of params in AvatarAppearance msg (" << num_params << ") does not match number of tweakable params in avatar xml file (" << expected_tweakable_count << "). Processing what we can. object: " << getID() << llendl;
|
||||
}
|
||||
|
||||
if (params_changed)
|
||||
@@ -7614,14 +8062,6 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )
|
||||
{
|
||||
// AvatarAppearance message arrived without visual params
|
||||
LL_DEBUGS("Avatar") << avString() << "no visual params" << LL_ENDL;
|
||||
if (drop_visual_params_debug)
|
||||
{
|
||||
llinfos << "Debug-faked lack of parameters on AvatarAppearance for object: " << getID() << llendl;
|
||||
}
|
||||
else
|
||||
{
|
||||
llinfos << "AvatarAppearance msg received without any parameters, object: " << getID() << llendl;
|
||||
}
|
||||
|
||||
const F32 LOADING_TIMEOUT_SECONDS = 60.f;
|
||||
// this isn't really a problem if we already have a non-default shape
|
||||
@@ -7651,8 +8091,7 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )
|
||||
|
||||
updateMeshTextures();
|
||||
|
||||
if (enable_verbose_dumps) dumpArchetypeXML(dump_prefix + "process_end");
|
||||
// llinfos << "processAvatarAppearance end " << mID << llendl;
|
||||
//if (enable_verbose_dumps) dumpArchetypeXML(dump_prefix + "process_end");
|
||||
}
|
||||
|
||||
// static
|
||||
@@ -8124,9 +8563,29 @@ void LLVOAvatar::bodySizeChanged()
|
||||
}
|
||||
}
|
||||
|
||||
BOOL LLVOAvatar::isUsingServerBakes() const
|
||||
{
|
||||
#if 1
|
||||
// Sanity check - visual param for appearance version should match mUseServerBakes
|
||||
LLVisualParam* appearance_version_param = getVisualParam(11000);
|
||||
llassert(appearance_version_param);
|
||||
F32 wt = appearance_version_param->getWeight();
|
||||
F32 expect_wt = mUseServerBakes ? 1.0 : 0.0;
|
||||
if (!is_approx_equal(wt,expect_wt))
|
||||
{
|
||||
llwarns << "wt " << wt << " differs from expected " << expect_wt << llendl;
|
||||
}
|
||||
#endif
|
||||
|
||||
return mUseServerBakes;
|
||||
}
|
||||
|
||||
void LLVOAvatar::setIsUsingServerBakes(BOOL newval)
|
||||
{
|
||||
mUseServerBakes = newval;
|
||||
LLVisualParam* appearance_version_param = getVisualParam(11000);
|
||||
llassert(appearance_version_param);
|
||||
appearance_version_param->setWeight(newval ? 1.0 : 0.0, false);
|
||||
}
|
||||
|
||||
// virtual
|
||||
|
||||
@@ -50,6 +50,7 @@
|
||||
#include "lldriverparam.h"
|
||||
#include "llviewertexlayer.h"
|
||||
#include "material_codes.h" // LL_MCODE_END
|
||||
#include "llviewerstats.h"
|
||||
|
||||
#include "emeraldboobutils.h"
|
||||
#include "llavatarname.h"
|
||||
@@ -72,6 +73,7 @@ class LLHUDNameTag;
|
||||
class LLHUDEffectSpiral;
|
||||
class LLTexGlobalColor;
|
||||
class LLViewerJoint;
|
||||
struct LLAppearanceMessageContents;
|
||||
|
||||
class SHClientTagMgr : public LLSingleton<SHClientTagMgr>, public boost::signals2::trackable
|
||||
{
|
||||
@@ -173,9 +175,21 @@ public:
|
||||
virtual void idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time);
|
||||
/*virtual*/ BOOL updateLOD();
|
||||
BOOL updateJointLODs();
|
||||
void updateLODRiggedAttachments( void );
|
||||
void updateLODRiggedAttachments( void );
|
||||
/*virtual*/ BOOL isActive() const; // Whether this object needs to do an idleUpdate.
|
||||
S32 totalTextureMemForUUIDS(std::set<LLUUID>& ids);
|
||||
bool allTexturesCompletelyDownloaded(std::set<LLUUID>& ids);
|
||||
bool allLocalTexturesCompletelyDownloaded();
|
||||
bool allBakedTexturesCompletelyDownloaded();
|
||||
void bakedTextureOriginCounts(S32 &sb_count, S32 &host_count,
|
||||
S32 &both_count, S32 &neither_count);
|
||||
std::string bakedTextureOriginInfo();
|
||||
void collectLocalTextureUUIDs(std::set<LLUUID>& ids);
|
||||
void collectBakedTextureUUIDs(std::set<LLUUID>& ids);
|
||||
void collectTextureUUIDs(std::set<LLUUID>& ids);
|
||||
void releaseOldTextures();
|
||||
/*virtual*/ void updateTextures();
|
||||
LLViewerFetchedTexture* getBakedTextureImage(const U8 te, const LLUUID& uuid);
|
||||
/*virtual*/ S32 setTETexture(const U8 te, const LLUUID& uuid); // If setting a baked texture, need to request it from a non-local sim.
|
||||
/*virtual*/ void onShift(const LLVector4a& shift_vector);
|
||||
/*virtual*/ U32 getPartitionType() const;
|
||||
@@ -323,7 +337,17 @@ public:
|
||||
bool isFrozenDead() const { return mFreezeTimeDead; }
|
||||
|
||||
S32 mLastRezzedStatus;
|
||||
|
||||
|
||||
void startPhase(const std::string& phase_name);
|
||||
void stopPhase(const std::string& phase_name);
|
||||
void clearPhases();
|
||||
void logPendingPhases();
|
||||
static void logPendingPhasesAllAvatars();
|
||||
void logMetricsTimerRecord(const std::string& phase_name, F32 elapsed, bool completed);
|
||||
|
||||
protected:
|
||||
LLViewerStats::PhaseMap& getPhases() { return mPhases; }
|
||||
BOOL updateIsFullyLoaded();
|
||||
BOOL processFullyLoadedChange(bool loading);
|
||||
void updateRuthTimer(bool loading);
|
||||
@@ -339,6 +363,28 @@ private:
|
||||
LLFrameTimer mRuthTimer;
|
||||
bool mFreezeTimeLangolier; // True when this avatar was created during snapshot FreezeTime mode, and that mode is still active.
|
||||
bool mFreezeTimeDead; // True when the avatar was marked dead (ie, TP-ed away) while in FreezeTime mode.
|
||||
|
||||
public:
|
||||
class ScopedPhaseSetter
|
||||
{
|
||||
public:
|
||||
ScopedPhaseSetter(LLVOAvatar *avatarp, std::string phase_name):
|
||||
mAvatar(avatarp), mPhaseName(phase_name)
|
||||
{
|
||||
if (mAvatar) { mAvatar->getPhases().startPhase(mPhaseName); }
|
||||
}
|
||||
~ScopedPhaseSetter()
|
||||
{
|
||||
if (mAvatar) { mAvatar->getPhases().stopPhase(mPhaseName); }
|
||||
}
|
||||
private:
|
||||
std::string mPhaseName;
|
||||
LLVOAvatar* mAvatar;
|
||||
};
|
||||
|
||||
private:
|
||||
LLViewerStats::PhaseMap mPhases;
|
||||
|
||||
protected:
|
||||
LLFrameTimer mInvisibleTimer;
|
||||
|
||||
@@ -546,6 +592,7 @@ protected:
|
||||
|
||||
LLLoadedCallbackEntry::source_callback_list_t mCallbackTextureList ;
|
||||
BOOL mLoadedCallbacksPaused;
|
||||
std::set<LLUUID> mTextureIDs;
|
||||
//--------------------------------------------------------------------
|
||||
// Local Textures
|
||||
//--------------------------------------------------------------------
|
||||
@@ -644,6 +691,7 @@ protected:
|
||||
**/
|
||||
|
||||
public:
|
||||
void parseAppearanceMessage(LLMessageSystem* mesgsys, LLAppearanceMessageContents& msg);
|
||||
void processAvatarAppearance(LLMessageSystem* mesgsys);
|
||||
void hideSkirt();
|
||||
void startAppearanceAnimation();
|
||||
@@ -662,7 +710,7 @@ public:
|
||||
|
||||
// True if this avatar should fetch its baked textures via the new
|
||||
// appearance mechanism.
|
||||
/*virtual*/ BOOL isUsingServerBakes() const { return mUseServerBakes; }
|
||||
BOOL isUsingServerBakes() const;
|
||||
void setIsUsingServerBakes(BOOL newval);
|
||||
|
||||
|
||||
|
||||
@@ -61,6 +61,8 @@
|
||||
#include "llappearancemgr.h"
|
||||
#include "llmeshrepository.h"
|
||||
#include "llvovolume.h"
|
||||
#include "llsdutil.h"
|
||||
#include "llsdserialize.h"
|
||||
// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1a)
|
||||
#include "rlvhandler.h"
|
||||
#include "rlvlocks.h"
|
||||
@@ -77,11 +79,36 @@ LLPointer<LLVOAvatarSelf> gAgentAvatarp = NULL;
|
||||
|
||||
BOOL isAgentAvatarValid()
|
||||
{
|
||||
return (gAgentAvatarp.notNull() &&
|
||||
return (gAgentAvatarp.notNull() && gAgentAvatarp->isValid() &&
|
||||
(gAgentAvatarp->getRegion() != NULL) &&
|
||||
(!gAgentAvatarp->isDead()));
|
||||
}
|
||||
|
||||
void selfStartPhase(const std::string& phase_name)
|
||||
{
|
||||
if (isAgentAvatarValid())
|
||||
{
|
||||
gAgentAvatarp->startPhase(phase_name);
|
||||
}
|
||||
}
|
||||
|
||||
void selfStopPhase(const std::string& phase_name)
|
||||
{
|
||||
if (isAgentAvatarValid())
|
||||
{
|
||||
gAgentAvatarp->stopPhase(phase_name);
|
||||
}
|
||||
}
|
||||
|
||||
void selfClearPhases()
|
||||
{
|
||||
if (isAgentAvatarValid())
|
||||
{
|
||||
gAgentAvatarp->clearPhases();
|
||||
gAgentAvatarp->mLastRezzedStatus = -1;
|
||||
}
|
||||
}
|
||||
|
||||
using namespace LLAvatarAppearanceDefines;
|
||||
|
||||
/*********************************************************************************
|
||||
@@ -151,6 +178,17 @@ LLVOAvatarSelf::LLVOAvatarSelf(const LLUUID& id,
|
||||
lldebugs << "Marking avatar as self " << id << llendl;
|
||||
}
|
||||
|
||||
// Called periodically for diagnostics, return true when done.
|
||||
bool output_self_av_texture_diagnostics()
|
||||
{
|
||||
if (!isAgentAvatarValid())
|
||||
return true; // done checking
|
||||
|
||||
gAgentAvatarp->outputRezDiagnostics();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void LLVOAvatarSelf::initInstance()
|
||||
{
|
||||
BOOL status = TRUE;
|
||||
@@ -188,6 +226,9 @@ void LLVOAvatarSelf::initInstance()
|
||||
llerrs << "Unable to load user's avatar" << llendl;
|
||||
return;
|
||||
}
|
||||
|
||||
//doPeriodically(output_self_av_texture_diagnostics, 30.0);
|
||||
doPeriodically(boost::bind(&LLVOAvatarSelf::updateAvatarRezMetrics, this, false), 5.0);
|
||||
}
|
||||
|
||||
// virtual
|
||||
@@ -659,6 +700,15 @@ U32 LLVOAvatarSelf::processUpdateMessage(LLMessageSystem *mesgsys,
|
||||
{
|
||||
U32 retval = LLVOAvatar::processUpdateMessage(mesgsys,user_data,block_num,update_type,dp);
|
||||
|
||||
#if 0
|
||||
// DRANO - it's not clear this does anything useful. If we wait
|
||||
// until an appearance message has been received, we already have
|
||||
// the texture ids. If we don't wait, we don't yet know where to
|
||||
// look for baked textures, because we haven't received the
|
||||
// appearance version data from the appearance message. This looks
|
||||
// like an old optimization that's incompatible with server-side
|
||||
// texture baking.
|
||||
|
||||
// FIXME DRANO - skipping in the case of !mFirstAppearanceMessageReceived prevents us from trying to
|
||||
// load textures before we know where they come from (ie, from baking service or not);
|
||||
// unknown impact on performance.
|
||||
@@ -668,7 +718,7 @@ U32 LLVOAvatarSelf::processUpdateMessage(LLMessageSystem *mesgsys,
|
||||
updateMeshTextures();
|
||||
|
||||
// unpack the texture UUIDs to the texture slots
|
||||
retval = unpackTEMessage(mesgsys, _PREHASH_ObjectData, block_num);
|
||||
retval = unpackTEMessage(mesgsys, _PREHASH_ObjectData, (S32) block_num);
|
||||
|
||||
// need to trigger a few operations to get the avatar to use the new bakes
|
||||
for (U32 i = 0; i < mBakedTextureDatas.size(); i++)
|
||||
@@ -683,6 +733,7 @@ U32 LLVOAvatarSelf::processUpdateMessage(LLMessageSystem *mesgsys,
|
||||
|
||||
mInitialBakesLoaded = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
return retval;
|
||||
}
|
||||
@@ -1431,7 +1482,9 @@ BOOL LLVOAvatarSelf::isAllLocalTextureDataFinal() const
|
||||
const U32 wearable_count = gAgentWearables.getWearableCount(wearable_type);
|
||||
for (U32 wearable_index = 0; wearable_index < wearable_count; wearable_index++)
|
||||
{
|
||||
if (getLocalDiscardLevel(*local_tex_iter, wearable_index) > (S32)(desired_tex_discard_level))
|
||||
S32 local_discard_level = getLocalDiscardLevel(*local_tex_iter, wearable_index);
|
||||
if ((local_discard_level > (S32)(desired_tex_discard_level)) ||
|
||||
(local_discard_level < 0 ))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
@@ -1994,6 +2047,84 @@ void LLVOAvatarSelf::debugBakedTextureUpload(EBakedTextureIndex index, BOOL fini
|
||||
mDebugBakedTextureTimes[index][done] = mDebugSelfLoadTimer.getElapsedTimeF32();
|
||||
}
|
||||
|
||||
const std::string LLVOAvatarSelf::verboseDebugDumpLocalTextureDataInfo(const LLViewerTexLayerSet* layerset) const
|
||||
{
|
||||
std::ostringstream outbuf;
|
||||
for (LLAvatarAppearanceDictionary::BakedTextures::const_iterator baked_iter =
|
||||
LLAvatarAppearanceDictionary::getInstance()->getBakedTextures().begin();
|
||||
baked_iter != LLAvatarAppearanceDictionary::getInstance()->getBakedTextures().end();
|
||||
++baked_iter)
|
||||
{
|
||||
const EBakedTextureIndex baked_index = baked_iter->first;
|
||||
if (layerset == mBakedTextureDatas[baked_index].mTexLayerSet)
|
||||
{
|
||||
outbuf << "baked_index: " << baked_index << "\n";
|
||||
const LLAvatarAppearanceDictionary::BakedEntry *baked_dict = baked_iter->second;
|
||||
for (texture_vec_t::const_iterator local_tex_iter = baked_dict->mLocalTextures.begin();
|
||||
local_tex_iter != baked_dict->mLocalTextures.end();
|
||||
++local_tex_iter)
|
||||
{
|
||||
const ETextureIndex tex_index = *local_tex_iter;
|
||||
const std::string tex_name = LLAvatarAppearanceDictionary::getInstance()->getTexture(tex_index)->mName;
|
||||
outbuf << " tex_index " << (S32) tex_index << " name " << tex_name << "\n";
|
||||
const LLWearableType::EType wearable_type = LLAvatarAppearanceDictionary::getTEWearableType(tex_index);
|
||||
const U32 wearable_count = gAgentWearables.getWearableCount(wearable_type);
|
||||
if (wearable_count > 0)
|
||||
{
|
||||
for (U32 wearable_index = 0; wearable_index < wearable_count; wearable_index++)
|
||||
{
|
||||
outbuf << " " << LLWearableType::getTypeName(wearable_type) << " " << wearable_index << ":";
|
||||
const LLLocalTextureObject *local_tex_obj = getLocalTextureObject(tex_index, wearable_index);
|
||||
if (local_tex_obj)
|
||||
{
|
||||
LLViewerFetchedTexture* image = dynamic_cast<LLViewerFetchedTexture*>( local_tex_obj->getImage() );
|
||||
if (tex_index >= 0
|
||||
&& local_tex_obj->getID() != IMG_DEFAULT_AVATAR
|
||||
&& !image->isMissingAsset())
|
||||
{
|
||||
outbuf << " id: " << image->getID()
|
||||
<< " refs: " << image->getNumRefs()
|
||||
<< " glocdisc: " << getLocalDiscardLevel(tex_index, wearable_index)
|
||||
<< " discard: " << image->getDiscardLevel()
|
||||
<< " desired: " << image->getDesiredDiscardLevel()
|
||||
<< " decode: " << image->getDecodePriority()
|
||||
<< " addl: " << image->getAdditionalDecodePriority()
|
||||
<< " ts: " << image->getTextureState()
|
||||
<< " bl: " << image->getBoostLevel()
|
||||
<< " fl: " << image->isFullyLoaded() // this is not an accessor for mFullyLoaded - see comment there.
|
||||
<< " cl: " << (image->isFullyLoaded() && image->getDiscardLevel()==0) // "completely loaded"
|
||||
<< " mvs: " << image->getMaxVirtualSize()
|
||||
<< " mvsc: " << image->getMaxVirtualSizeResetCounter()
|
||||
<< " mem: " << image->getTextureMemory();
|
||||
}
|
||||
}
|
||||
outbuf << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return outbuf.str();
|
||||
}
|
||||
|
||||
void LLVOAvatarSelf::dumpAllTextures() const
|
||||
{
|
||||
std::string vd_text = "Local textures per baked index and wearable:\n";
|
||||
for (LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary::BakedTextures::const_iterator baked_iter = LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary::getInstance()->getBakedTextures().begin();
|
||||
baked_iter != LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary::getInstance()->getBakedTextures().end();
|
||||
++baked_iter)
|
||||
{
|
||||
const LLAvatarAppearanceDefines::EBakedTextureIndex baked_index = baked_iter->first;
|
||||
const LLViewerTexLayerSet *layerset = debugGetLayerSet(baked_index);
|
||||
if (!layerset) continue;
|
||||
const LLViewerTexLayerSetBuffer *layerset_buffer = layerset->getViewerComposite();
|
||||
if (!layerset_buffer) continue;
|
||||
vd_text += verboseDebugDumpLocalTextureDataInfo(layerset);
|
||||
}
|
||||
LL_DEBUGS("Avatar") << vd_text << llendl;
|
||||
}
|
||||
|
||||
const std::string LLVOAvatarSelf::debugDumpLocalTextureDataInfo(const LLViewerTexLayerSet* layerset) const
|
||||
{
|
||||
std::string text="";
|
||||
@@ -2062,6 +2193,194 @@ const std::string LLVOAvatarSelf::debugDumpAllLocalTextureDataInfo() const
|
||||
return text;
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
// Dump avatar metrics data.
|
||||
LLSD LLVOAvatarSelf::metricsData()
|
||||
{
|
||||
// runway - add region info
|
||||
LLSD result;
|
||||
result["rez_status"] = LLVOAvatar::rezStatusToString(getRezzedStatus());
|
||||
result["timers"]["debug_existence"] = mDebugExistenceTimer.getElapsedTimeF32();
|
||||
result["timers"]["ruth_debug"] = mRuthDebugTimer.getElapsedTimeF32();
|
||||
result["timers"]["ruth"] = mRuthTimer.getElapsedTimeF32();
|
||||
result["timers"]["invisible"] = mInvisibleTimer.getElapsedTimeF32();
|
||||
result["timers"]["fully_loaded"] = mFullyLoadedTimer.getElapsedTimeF32();
|
||||
result["startup"] = LLStartUp::getPhases().dumpPhases();
|
||||
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
extern AIHTTPTimeoutPolicy appearanceChangeMetricsResponder_timeout;
|
||||
class ViewerAppearanceChangeMetricsResponder: public LLHTTPClient::ResponderWithResult
|
||||
{
|
||||
public:
|
||||
ViewerAppearanceChangeMetricsResponder( S32 expected_sequence,
|
||||
volatile const S32 & live_sequence,
|
||||
volatile bool & reporting_started):
|
||||
mExpectedSequence(expected_sequence),
|
||||
mLiveSequence(live_sequence),
|
||||
mReportingStarted(reporting_started)
|
||||
{
|
||||
}
|
||||
|
||||
/*virtual*/ void result(LLSD const& content)
|
||||
{
|
||||
LL_DEBUGS("Avatar") << "OK" << LL_ENDL;
|
||||
if (mLiveSequence == mExpectedSequence)
|
||||
{
|
||||
mReportingStarted = true;
|
||||
}
|
||||
}
|
||||
/*virtual*/ void error(U32 status, std::string const& reason)
|
||||
{
|
||||
LL_WARNS("Avatar") << "Failed " << status << " reason " << reason << LL_ENDL;
|
||||
}
|
||||
/*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return appearanceChangeMetricsResponder_timeout; }
|
||||
/*virtual*/ char const* getName(void) const { return "AppearanceChangeMetricsResponder"; }
|
||||
private:
|
||||
S32 mExpectedSequence;
|
||||
volatile const S32 & mLiveSequence;
|
||||
volatile bool & mReportingStarted;
|
||||
};
|
||||
|
||||
bool LLVOAvatarSelf::updateAvatarRezMetrics(bool force_send)
|
||||
{
|
||||
const F32 AV_METRICS_INTERVAL_QA = 30.0;
|
||||
F32 send_period = 300.0;
|
||||
if (gSavedSettings.getBOOL("QAModeMetrics"))
|
||||
{
|
||||
send_period = AV_METRICS_INTERVAL_QA;
|
||||
}
|
||||
|
||||
if (force_send || mTimeSinceLastRezMessage.getElapsedTimeF32() > send_period)
|
||||
{
|
||||
// Stats for completed phases have been getting logged as they
|
||||
// complete. This will give us stats for any timers that
|
||||
// haven't finished as of the metric's being sent.
|
||||
LLVOAvatar::logPendingPhasesAllAvatars();
|
||||
sendViewerAppearanceChangeMetrics();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void LLVOAvatarSelf::addMetricsTimerRecord(const LLSD& record)
|
||||
{
|
||||
mPendingTimerRecords.push_back(record);
|
||||
}
|
||||
|
||||
bool operator<(const LLSD& a, const LLSD& b)
|
||||
{
|
||||
std::ostringstream aout, bout;
|
||||
aout << LLSDNotationStreamer(a);
|
||||
bout << LLSDNotationStreamer(b);
|
||||
std::string astring = aout.str();
|
||||
std::string bstring = bout.str();
|
||||
|
||||
return astring < bstring;
|
||||
|
||||
}
|
||||
|
||||
// Given a vector of LLSD records, return an LLSD array of bucketed stats for val_field.
|
||||
LLSD summarize_by_buckets(std::vector<LLSD> in_records,
|
||||
std::vector<std::string> by_fields,
|
||||
std::string& val_field)
|
||||
{
|
||||
LLSD result = LLSD::emptyArray();
|
||||
std::map<LLSD,LLViewerStats::StatsAccumulator> accum;
|
||||
for (std::vector<LLSD>::iterator in_record_iter = in_records.begin();
|
||||
in_record_iter != in_records.end(); ++in_record_iter)
|
||||
{
|
||||
LLSD& record = *in_record_iter;
|
||||
LLSD key;
|
||||
for (std::vector<std::string>::iterator field_iter = by_fields.begin();
|
||||
field_iter != by_fields.end(); ++field_iter)
|
||||
{
|
||||
const std::string& field = *field_iter;
|
||||
key[field] = record[field];
|
||||
}
|
||||
LLViewerStats::StatsAccumulator& stats = accum[key];
|
||||
F32 value = record[val_field].asReal();
|
||||
stats.push(value);
|
||||
}
|
||||
for (std::map<LLSD,LLViewerStats::StatsAccumulator>::iterator accum_it = accum.begin();
|
||||
accum_it != accum.end(); ++accum_it)
|
||||
{
|
||||
LLSD out_record = accum_it->first;
|
||||
out_record["stats"] = accum_it->second.getData();
|
||||
result.append(out_record);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void LLVOAvatarSelf::sendViewerAppearanceChangeMetrics()
|
||||
{
|
||||
// gAgentAvatarp->stopAllPhases();
|
||||
static volatile bool reporting_started(false);
|
||||
static volatile S32 report_sequence(0);
|
||||
|
||||
LLSD msg; // = metricsData();
|
||||
msg["message"] = "ViewerAppearanceChangeMetrics";
|
||||
msg["session_id"] = gAgentSessionID;
|
||||
msg["agent_id"] = gAgentID;
|
||||
msg["sequence"] = report_sequence;
|
||||
msg["initial"] = !reporting_started;
|
||||
msg["break"] = false;
|
||||
msg["duration"] = mTimeSinceLastRezMessage.getElapsedTimeF32();
|
||||
|
||||
// Status of our own rezzing.
|
||||
msg["rez_status"] = LLVOAvatar::rezStatusToString(getRezzedStatus());
|
||||
|
||||
// Status of all nearby avs including ourself.
|
||||
msg["nearby"] = LLSD::emptyArray();
|
||||
std::vector<S32> rez_counts;
|
||||
LLVOAvatar::getNearbyRezzedStats(rez_counts);
|
||||
for (std::vector<S32>::size_type rez_stat=0; rez_stat < rez_counts.size(); ++rez_stat)
|
||||
{
|
||||
std::string rez_status_name = LLVOAvatar::rezStatusToString(rez_stat);
|
||||
msg["nearby"][rez_status_name] = rez_counts[rez_stat];
|
||||
}
|
||||
|
||||
// std::vector<std::string> bucket_fields("timer_name","agent_id","is_self","grid_x","grid_y","is_using_server_bake");
|
||||
std::vector<std::string> by_fields;
|
||||
by_fields.push_back("timer_name");
|
||||
by_fields.push_back("agent_id");
|
||||
by_fields.push_back("completed");
|
||||
by_fields.push_back("grid_x");
|
||||
by_fields.push_back("grid_y");
|
||||
by_fields.push_back("is_using_server_bakes");
|
||||
by_fields.push_back("is_self");
|
||||
by_fields.push_back("central_bake_version");
|
||||
LLSD summary = summarize_by_buckets(mPendingTimerRecords, by_fields, std::string("elapsed"));
|
||||
msg["timers"] = summary;
|
||||
|
||||
mPendingTimerRecords.clear();
|
||||
|
||||
// Update sequence number
|
||||
if (S32_MAX == ++report_sequence)
|
||||
report_sequence = 0;
|
||||
|
||||
LL_DEBUGS("Avatar") << avString() << "message: " << ll_pretty_print_sd(msg) << LL_ENDL;
|
||||
std::string caps_url;
|
||||
if (getRegion())
|
||||
{
|
||||
// runway - change here to activate.
|
||||
caps_url = getRegion()->getCapability("ViewerMetrics");
|
||||
}
|
||||
if (!caps_url.empty())
|
||||
{
|
||||
AIHTTPHeaders headers;
|
||||
LLHTTPClient::post(caps_url,
|
||||
msg,
|
||||
new ViewerAppearanceChangeMetricsResponder(report_sequence,
|
||||
report_sequence,
|
||||
reporting_started));
|
||||
mTimeSinceLastRezMessage.reset();
|
||||
}
|
||||
}
|
||||
|
||||
const LLUUID& LLVOAvatarSelf::grabBakedTexture(EBakedTextureIndex baked_index) const
|
||||
{
|
||||
if (canGrabBakedTexture(baked_index))
|
||||
@@ -2155,23 +2474,28 @@ void LLVOAvatarSelf::addLocalTextureStats( ETextureIndex type, LLViewerFetchedTe
|
||||
{
|
||||
if (!isIndexLocalTexture(type)) return;
|
||||
|
||||
if (getLocalTextureID(type, index) != IMG_DEFAULT_AVATAR && imagep->getDiscardLevel() != 0)
|
||||
if (getLocalTextureID(type, index) != IMG_DEFAULT_AVATAR)
|
||||
{
|
||||
F32 desired_pixels;
|
||||
desired_pixels = llmin(mPixelArea, (F32)getTexImageArea());
|
||||
imagep->setNoDelete();
|
||||
if (imagep->getDiscardLevel() != 0)
|
||||
{
|
||||
F32 desired_pixels;
|
||||
desired_pixels = llmin(mPixelArea, (F32)getTexImageArea());
|
||||
|
||||
if (isUsingLocalAppearance())
|
||||
{
|
||||
imagep->setBoostLevel(getAvatarBoostLevel());
|
||||
imagep->setAdditionalDecodePriority(SELF_ADDITIONAL_PRI) ;
|
||||
}
|
||||
imagep->resetTextureStats();
|
||||
imagep->setMaxVirtualSizeResetInterval(MAX_TEXTURE_VIRTURE_SIZE_RESET_INTERVAL);
|
||||
imagep->addTextureStats( desired_pixels / texel_area_ratio );
|
||||
imagep->forceUpdateBindStats() ;
|
||||
if (imagep->getDiscardLevel() < 0)
|
||||
{
|
||||
mHasGrey = TRUE; // for statistics gathering
|
||||
// DRANO what priority should wearable-based textures have?
|
||||
if (isUsingLocalAppearance())
|
||||
{
|
||||
imagep->setBoostLevel(getAvatarBoostLevel());
|
||||
imagep->setAdditionalDecodePriority(SELF_ADDITIONAL_PRI) ;
|
||||
}
|
||||
imagep->resetTextureStats();
|
||||
imagep->setMaxVirtualSizeResetInterval(MAX_TEXTURE_VIRTURE_SIZE_RESET_INTERVAL);
|
||||
imagep->addTextureStats( desired_pixels / texel_area_ratio );
|
||||
imagep->forceUpdateBindStats() ;
|
||||
if (imagep->getDiscardLevel() < 0)
|
||||
{
|
||||
mHasGrey = TRUE; // for statistics gathering
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -2344,6 +2668,8 @@ void LLVOAvatarSelf::outputRezDiagnostics() const
|
||||
if (!layerset_buffer) continue;
|
||||
LL_DEBUGS("Avatar") << layerset_buffer->dumpTextureInfo() << llendl;
|
||||
}
|
||||
|
||||
dumpAllTextures();
|
||||
}
|
||||
|
||||
void LLVOAvatarSelf::outputRezTiming(const std::string& msg) const
|
||||
|
||||
@@ -378,6 +378,13 @@ public:
|
||||
LLUUID mAvatarID;
|
||||
LLAvatarAppearanceDefines::ETextureIndex mIndex;
|
||||
};
|
||||
|
||||
LLTimer mTimeSinceLastRezMessage;
|
||||
bool updateAvatarRezMetrics(bool force_send);
|
||||
|
||||
std::vector<LLSD> mPendingTimerRecords;
|
||||
void addMetricsTimerRecord(const LLSD& record);
|
||||
|
||||
void debugWearablesLoaded() { mDebugTimeWearablesLoaded = mDebugSelfLoadTimer.getElapsedTimeF32(); }
|
||||
void debugAvatarVisible() { mDebugTimeAvatarVisible = mDebugSelfLoadTimer.getElapsedTimeF32(); }
|
||||
void outputRezDiagnostics() const;
|
||||
@@ -389,8 +396,11 @@ public:
|
||||
BOOL isAllLocalTextureDataFinal() const;
|
||||
|
||||
const LLViewerTexLayerSet* debugGetLayerSet(LLAvatarAppearanceDefines::EBakedTextureIndex index) const { return (LLViewerTexLayerSet*)(mBakedTextureDatas[index].mTexLayerSet); }
|
||||
const std::string verboseDebugDumpLocalTextureDataInfo(const LLViewerTexLayerSet* layerset) const; // Lists out state of this particular baked texture layer
|
||||
void dumpAllTextures() const;
|
||||
const std::string debugDumpLocalTextureDataInfo(const LLViewerTexLayerSet* layerset) const; // Lists out state of this particular baked texture layer
|
||||
const std::string debugDumpAllLocalTextureDataInfo() const; // Lists out which baked textures are at highest LOD
|
||||
void sendViewerAppearanceChangeMetrics(); // send data associated with completing a change.
|
||||
private:
|
||||
LLFrameTimer mDebugSelfLoadTimer;
|
||||
F32 mDebugTimeWearablesLoaded;
|
||||
@@ -412,4 +422,10 @@ extern LLPointer<LLVOAvatarSelf> gAgentAvatarp;
|
||||
|
||||
BOOL isAgentAvatarValid();
|
||||
|
||||
void selfStartPhase(const std::string& phase_name);
|
||||
void selfStopPhase(const std::string& phase_name);
|
||||
void selfClearPhases();
|
||||
|
||||
void update_avatar_rez_metrics(bool force_send);
|
||||
|
||||
#endif // LL_VO_AVATARSELF_H
|
||||
|
||||
@@ -3260,10 +3260,6 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
|
||||
else
|
||||
{
|
||||
model_mat = &(drawable->getRegion()->mRenderMatrix);
|
||||
if (model_mat->isIdentity())
|
||||
{
|
||||
model_mat = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
//drawable->getVObj()->setDebugText(llformat("%d", drawable->isState(LLDrawable::ANIMATED_CHILD)));
|
||||
|
||||
@@ -676,7 +676,10 @@ void LLWorld::updateRegions(F32 max_update_time)
|
||||
if (did_one && max_time <= 0.f)
|
||||
break;
|
||||
max_time = llmin(max_time, max_update_time*.1f);
|
||||
did_one |= regionp->idleUpdate(max_update_time);
|
||||
if (regionp->idleUpdate(max_update_time))
|
||||
{
|
||||
did_one = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1450,7 +1453,8 @@ void LLWorld::getAvatars(std::vector<LLUUID>* avatar_ids, std::vector<LLVector3d
|
||||
iter != LLCharacter::sInstances.end(); ++iter)
|
||||
{
|
||||
LLVOAvatar* pVOAvatar = (LLVOAvatar*) *iter;
|
||||
if(!pVOAvatar->isDead() && !pVOAvatar->isSelf())
|
||||
|
||||
if (!pVOAvatar->isDead() && !pVOAvatar->isSelf() && !pVOAvatar->mIsDummy)
|
||||
{
|
||||
LLUUID uuid = pVOAvatar->getID();
|
||||
if(!uuid.isNull())
|
||||
|
||||
Reference in New Issue
Block a user