diff options
Diffstat (limited to 'indra/newview/llvoavatar.cpp')
-rwxr-xr-x | indra/newview/llvoavatar.cpp | 839 |
1 files changed, 661 insertions, 178 deletions
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 117f28cc36..afe8a037b7 100755 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -99,6 +99,7 @@ #include "lldebugmessagebox.h" #include "llsdutil.h" +#include "llsdserialize.h" extern F32 SPEED_ADJUST_MAX; extern F32 SPEED_ADJUST_MAX_SEC; @@ -189,11 +190,6 @@ enum ERenderName RENDER_NAME_FADE }; - -// Utility func - FIXME move out of avatar. -std::string get_sequential_numbered_file_name(const std::string& prefix, - const std::string& suffix); - //----------------------------------------------------------------------------- // Callback data //----------------------------------------------------------------------------- @@ -214,6 +210,24 @@ struct LLTextureMaskData ** **/ +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; +}; + //----------------------------------------------------------------------------- // class LLBodyNoiseMotion //----------------------------------------------------------------------------- @@ -628,7 +642,6 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id, mUseLocalAppearance(FALSE), mUseServerBakes(FALSE) // FIXME DRANO consider using boost::optional, defaulting to unknown. { - LLMemType mt(LLMemType::MTYPE_AVATAR); //VTResume(); // VTune // mVoiceVisualizer is created by the hud effects manager and uses the HUD Effects pipeline @@ -729,6 +742,8 @@ LLVOAvatar::~LLVOAvatar() debugAvatarRezTime("AvatarRezLeftNotification","left sometime after declouding"); } + logPendingPhases(); + lldebugs << "LLVOAvatar Destructor (0x" << this << ") id:" << mID << llendl; std::for_each(mAttachmentPoints.begin(), mAttachmentPoints.end(), DeletePairedPointer()); @@ -818,6 +833,7 @@ BOOL LLVOAvatar::hasGray() const S32 LLVOAvatar::getRezzedStatus() const { if (getIsCloud()) return 0; + if (isFullyTextured() && allBakedTexturesCompletelyDownloaded()) return 3; if (isFullyTextured()) return 2; llassert(hasGray()); return 1; // gray @@ -873,7 +889,7 @@ BOOL LLVOAvatar::areAllNearbyInstancesBaked(S32& grey_avatars) void LLVOAvatar::getNearbyRezzedStats(std::vector<S32>& counts) { counts.clear(); - counts.resize(3); + counts.resize(4); for (std::vector<LLCharacter*>::iterator iter = LLCharacter::sInstances.begin(); iter != LLCharacter::sInstances.end(); ++iter) { @@ -891,6 +907,7 @@ std::string LLVOAvatar::rezStatusToString(S32 rez_status) if (rez_status==0) return "cloud"; if (rez_status==1) return "gray"; if (rez_status==2) return "textured"; + if (rez_status==3) return "textured_and_downloaded"; return "unknown"; } @@ -1539,8 +1556,6 @@ void LLVOAvatar::buildCharacter() //----------------------------------------------------------------------------- void LLVOAvatar::releaseMeshData() { - LLMemType mt(LLMemType::MTYPE_AVATAR); - if (sInstances.size() < AVATAR_RELEASE_THRESHOLD || mIsDummy) { return; @@ -1595,7 +1610,6 @@ void LLVOAvatar::releaseMeshData() void LLVOAvatar::restoreMeshData() { llassert(!isSelf()); - LLMemType mt(LLMemType::MTYPE_AVATAR); //llinfos << "Restoring" << llendl; mMeshValid = TRUE; @@ -1753,8 +1767,6 @@ U32 LLVOAvatar::processUpdateMessage(LLMessageSystem *mesgsys, U32 block_num, const EObjectUpdateType update_type, LLDataPacker *dp) { - LLMemType mt(LLMemType::MTYPE_AVATAR); - const BOOL has_name = !getNVPair("FirstName"); // Do base class updates... @@ -1782,27 +1794,50 @@ 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); + LL_DEBUGS("Avatar") << avString() << "from URL " << url << llendl; + result = LLViewerTextureManager::getFetchedTextureFromUrl( + url, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE, 0, 0, uuid); + } + else + { + LL_DEBUGS("Avatar") << avString() << "from host " << uuid << llendl; + LLHost host = getObjectHost(); + result = LLViewerTextureManager::getFetchedTexture( + uuid, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE, 0, 0, host); } - - LLHost target_host = getObjectHost(); - return setTETextureCore(te, uuid, target_host); } - else + return result; +} + +// virtual +S32 LLVOAvatar::setTETexture(const U8 te, const LLUUID& uuid) +{ + if (!isIndexBakedTexture((ETextureIndex)te)) { - return setTETextureCore(te, uuid, LLHost::invalid); + // Sim still sends some uuids for non-baked slots sometimes - ignore. + 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"); @@ -1840,7 +1875,6 @@ void LLVOAvatar::dumpAnimationState() //------------------------------------------------------------------------ void LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) { - LLMemType mt(LLMemType::MTYPE_AVATAR); LLFastTimer t(FTM_AVATAR_UPDATE); if (isDead()) @@ -1849,7 +1883,8 @@ void LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) return; } - if (!(gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_AVATAR))) + if (!(gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_AVATAR)) + && !(gSavedSettings.getBOOL("DisableAllRenderTypes"))) { return; } @@ -2876,8 +2911,6 @@ bool LLVOAvatar::isVisuallyMuted() const //------------------------------------------------------------------------ BOOL LLVOAvatar::updateCharacter(LLAgent &agent) { - LLMemType mt(LLMemType::MTYPE_AVATAR); - // clear debug text mDebugText.clear(); @@ -2888,9 +2921,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", + isSelf() ? (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")) { @@ -4001,11 +4049,224 @@ U32 LLVOAvatar::renderImpostor(LLColor4U color, S32 diffuse_channel) return 6; } -//------------------------------------------------------------------------ -// LLVOAvatar::updateTextures() -//------------------------------------------------------------------------ +bool LLVOAvatar::allTexturesCompletelyDownloaded(std::set<LLUUID>& ids) const +{ + 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() const +{ + std::set<LLUUID> local_ids; + collectLocalTextureUUIDs(local_ids); + return allTexturesCompletelyDownloaded(local_ids); +} + +bool LLVOAvatar::allBakedTexturesCompletelyDownloaded() const +{ + 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 (U32 i = 0; i < mBakedTextureDatas.size(); i++) + { + ETextureIndex texture_index = mBakedTextureDatas[i].mTextureIndex; + LLViewerFetchedTexture *imagep = + LLViewerTextureManager::staticCastToFetchedTexture(getImage(texture_index,0), TRUE); + if (!imagep || + imagep->getID() == IMG_DEFAULT || + imagep->getID() == IMG_DEFAULT_AVATAR) + + { + result += "-"; + } + else + { + bool has_url = false, has_host = false; + if (!imagep->getUrl().empty()) + { + has_url = true; + } + if (imagep->getTargetHost().isOk()) + { + has_host = true; + } + S32 discard = imagep->getDiscardLevel(); + if (has_url && !has_host) result += discard ? "u" : "U"; // server-bake texture with url + else if (has_host && !has_url) result += discard ? "h" : "H"; // old-style texture on sim + else if (has_host && has_url) result += discard ? "x" : "X"; // both origins? + else if (!has_host && !has_url) result += discard ? "n" : "N"; // no origin? + if (discard != 0) + { + result += llformat("(%d/%d)",discard,imagep->getDesiredDiscardLevel()); + } + } + + } + 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) const +{ + 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) const +{ + 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) @@ -4229,6 +4490,7 @@ void LLVOAvatar::setTexEntry(const U8 index, const LLTextureEntry &te) const std::string LLVOAvatar::getImageURL(const U8 te, const LLUUID &uuid) { + llassert(isIndexBakedTexture(ETextureIndex(te))); std::string url = ""; if (isUsingServerBakes()) { @@ -4318,8 +4580,6 @@ const LLUUID& LLVOAvatar::getStepSound() const //----------------------------------------------------------------------------- void LLVOAvatar::processAnimationStateChanges() { - LLMemType mt(LLMemType::MTYPE_AVATAR); - if ( isAnyAnimationSignaled(AGENT_WALK_ANIMS, NUM_AGENT_WALK_ANIMS) ) { startMotion(ANIM_AGENT_WALK_ADJUST); @@ -4410,8 +4670,6 @@ void LLVOAvatar::processAnimationStateChanges() //----------------------------------------------------------------------------- BOOL LLVOAvatar::processSingleAnimationStateChange( const LLUUID& anim_id, BOOL start ) { - LLMemType mt(LLMemType::MTYPE_AVATAR); - BOOL result = FALSE; if ( start ) // start animation @@ -4546,8 +4804,6 @@ LLUUID LLVOAvatar::remapMotionID(const LLUUID& id) //----------------------------------------------------------------------------- BOOL LLVOAvatar::startMotion(const LLUUID& id, F32 time_offset) { - LLMemType mt(LLMemType::MTYPE_AVATAR); - lldebugs << "motion requested " << id.asString() << " " << gAnimLibrary.animationName(id) << llendl; LLUUID remap_id = remapMotionID(id); @@ -4936,8 +5192,6 @@ BOOL LLVOAvatar::isActive() const //----------------------------------------------------------------------------- void LLVOAvatar::setPixelAreaAndAngle(LLAgent &agent) { - LLMemType mt(LLMemType::MTYPE_AVATAR); - if (mDrawable.isNull()) { return; @@ -5653,42 +5907,167 @@ BOOL LLVOAvatar::getIsCloud() const void LLVOAvatar::updateRezzedStatusTimers() { - // State machine for rezzed status. Statuses are 0 = cloud, 1 = gray, 2 = textured. - // Purpose is to collect time data for each period of cloud or cloud+gray. + // State machine for rezzed status. Statuses are -1 on startup, 0 + // = cloud, 1 = gray, 2 = textured, 3 = textured_and_downloaded. + // Purpose is to collect time data for each it takes avatar to reach + // various loading landmarks: gray, textured (partial), textured fully. + S32 rez_status = getRezzedStatus(); 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 was_cloud_or_gray = (mLastRezzedStatus==0 || mLastRezzedStatus==1); - bool is_cloud = (rez_status==0); - bool was_cloud = (mLastRezzedStatus==0); - // Non-cloud to cloud - if (is_cloud && !was_cloud) + if (mLastRezzedStatus == -1 && rez_status != -1) { - // start cloud timer. - getPhases().startPhase("cloud"); + // First time initialization, start all timers. + for (S32 i = 1; i < 4; i++) + { + startPhase("load_" + LLVOAvatar::rezStatusToString(i)); + startPhase("first_load_" + LLVOAvatar::rezStatusToString(i)); + } } - else if (was_cloud && !is_cloud) + if (rez_status < mLastRezzedStatus) { - // stop cloud timer, which will capture stats. - getPhases().stopPhase("cloud"); + // load level has decreased. start phase timers for higher load levels. + for (S32 i = rez_status+1; i <= mLastRezzedStatus; i++) + { + startPhase("load_" + LLVOAvatar::rezStatusToString(i)); + } } + else if (rez_status > mLastRezzedStatus) + { + // load level has increased. stop phase timers for lower and equal load levels. + for (S32 i = llmax(mLastRezzedStatus+1,1); i <= rez_status; i++) + { + stopPhase("load_" + LLVOAvatar::rezStatusToString(i)); + stopPhase("first_load_" + LLVOAvatar::rezStatusToString(i), false); + } + if (rez_status == 3) + { + // "fully loaded", mark any pending appearance change complete. + selfStopPhase("update_appearance_from_cof"); + selfStopPhase("wear_inventory_category", false); + selfStopPhase("process_initial_wearables_update", false); + } + } + + mLastRezzedStatus = rez_status; + } +} + +void LLVOAvatar::clearPhases() +{ + getPhases().clearPhases(); +} + +void LLVOAvatar::startPhase(const std::string& phase_name) +{ + F32 elapsed; + bool completed; + if (getPhases().getPhaseValues(phase_name, elapsed, completed)) + { + if (!completed) + { + LL_DEBUGS("Avatar") << avString() << "no-op, start when started already for " << phase_name << llendl; + return; + } + } + LL_DEBUGS("Avatar") << "started phase " << phase_name << llendl; + getPhases().startPhase(phase_name); +} - // Non-cloud-or-gray to cloud-or-gray - if (is_cloud_or_gray && !was_cloud_or_gray) +void LLVOAvatar::stopPhase(const std::string& phase_name, bool err_check) +{ + F32 elapsed; + bool completed; + if (getPhases().getPhaseValues(phase_name, elapsed, completed)) + { + if (!completed) { - // start cloud-or-gray timer. - getPhases().startPhase("cloud-or-gray"); + getPhases().stopPhase(phase_name); + completed = true; + logMetricsTimerRecord(phase_name, elapsed, completed); + LL_DEBUGS("Avatar") << avString() << "stopped phase " << phase_name << " elapsed " << elapsed << llendl; } - else if (was_cloud_or_gray && !is_cloud_or_gray) + else { - // stop cloud-or-gray timer, which will capture stats. - getPhases().stopPhase("cloud-or-gray"); + if (err_check) + { + LL_DEBUGS("Avatar") << "no-op, stop when stopped already for " << phase_name << llendl; + } + } + } + else + { + if (err_check) + { + LL_DEBUGS("Avatar") << "no-op, stop when not started for " << phase_name << llendl; } - - mLastRezzedStatus = rez_status; + } +} + +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); + } + } + } +} + +//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["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(); + + +#if 0 // verbose logging + std::ostringstream ostr; + ostr << LLSDNotationStreamer(record); + LL_DEBUGS("Avatar") << "record\n" << ostr.str() << llendl; +#endif + + if (isAgentAvatarValid()) + { + gAgentAvatarp->addMetricsTimerRecord(record); } } @@ -5785,6 +6164,8 @@ LLMotion* LLVOAvatar::findMotion(const LLUUID& id) const return mMotionController.findMotion(id); } +// This is a semi-deprecated debugging tool - meshes will not show as +// colorized if using deferred rendering. void LLVOAvatar::debugColorizeSubMeshes(U32 i, const LLColor4& color) { if (gSavedSettings.getBOOL("DebugAvatarCompositeBaked")) @@ -5811,6 +6192,7 @@ void LLVOAvatar::debugColorizeSubMeshes(U32 i, const LLColor4& color) // virtual void LLVOAvatar::updateMeshTextures() { + static S32 update_counter = 0; mBakedTextureDebugText.clear(); // if user has never specified a texture, assign the default @@ -5840,7 +6222,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); @@ -5873,6 +6256,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 @@ -5895,28 +6280,7 @@ void LLVOAvatar::updateMeshTextures() LLViewerTexLayerSet* layerset = getTexLayerSet(i); if (use_lkg_baked_layer[i] && !isUsingLocalAppearance() ) { - LLViewerFetchedTexture* baked_img; -#ifndef LL_RELEASE_FOR_DOWNLOAD - LLViewerFetchedTexture* existing_baked_img = LLViewerTextureManager::getFetchedTexture(mBakedTextureDatas[i].mLastTextureID); -#endif - const std::string url = getImageURL(i, mBakedTextureDatas[i].mLastTextureID); - if (!url.empty()) - { - baked_img = LLViewerTextureManager::getFetchedTextureFromUrl(url, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE, 0, 0, mBakedTextureDatas[i].mLastTextureID); - } - else - { - // Baked textures should be requested from the sim this avatar is on. JC - const LLHost target_host = getObjectHost(); - if (!target_host.isOk()) - { - llwarns << "updateMeshTextures: invalid host for object: " << getID() << llendl; - } - - baked_img = LLViewerTextureManager::getFetchedTextureFromHost( mBakedTextureDatas[i].mLastTextureID, target_host ); - } - llassert(baked_img == existing_baked_img); - + LLViewerFetchedTexture* baked_img = LLViewerTextureManager::getFetchedTexture(mBakedTextureDatas[i].mLastTextureID); mBakedTextureDatas[i].mIsUsed = TRUE; debugColorizeSubMeshes(i,LLColor4::red); @@ -6379,10 +6743,11 @@ void dump_visual_param(apr_file_t* file, LLVisualParam* viewer_param, F32 value) void LLVOAvatar::dumpAppearanceMsgParams( const std::string& dump_prefix, - const std::vector<F32>& params_for_dump, - const LLTEContents& tec) + const LLAppearanceMessageContents& contents) { std::string outfilename = get_sequential_numbered_file_name(dump_prefix,".xml"); + const std::vector<F32>& params_for_dump = contents.mParamWeights; + const LLTEContents& tec = contents.mTEContents; LLAPRFile outfile; std::string fullpath = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,outfilename); @@ -6394,10 +6759,15 @@ 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; } + apr_file_printf(file, "<header>\n"); + apr_file_printf(file, "\t\t<cof_version %i />\n", contents.mCOFVersion); + apr_file_printf(file, "\t\t<appearance_version %i />\n", contents.mAppearanceVersion); + apr_file_printf(file, "</header>\n"); + apr_file_printf(file, "\n<params>\n"); LLVisualParam* param = getFirstVisualParam(); for (S32 i = 0; i < params_for_dump.size(); i++) { @@ -6410,12 +6780,132 @@ void LLVOAvatar::dumpAppearanceMsgParams( const std::string& dump_prefix, dump_visual_param(file, viewer_param, value); param = getNextVisualParam(); } + apr_file_printf(file, "</params>\n"); + + apr_file_printf(file, "\n<textures>\n"); for (U32 i = 0; i < tec.face_count; i++) { std::string uuid_str; ((LLUUID*)tec.image_data)[i].toString(uuid_str); apr_file_printf( file, "\t\t<texture te=\"%i\" uuid=\"%s\"/>\n", i, uuid_str.c_str()); } + apr_file_printf(file, "</textures>\n"); +} + +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; } //----------------------------------------------------------------------------- @@ -6423,41 +6913,34 @@ void LLVOAvatar::dumpAppearanceMsgParams( const std::string& dump_prefix, //----------------------------------------------------------------------------- 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; + LLAppearanceMessageContents contents; + parseAppearanceMessage(mesgsys, contents); + if (enable_verbose_dumps) + { + dumpAppearanceMsgParams(dump_prefix + "appearance_msg", contents); + } - if (mesgsys->has(_PREHASH_AppearanceData)) + S32 appearance_version; + if (!resolve_appearance_version(contents, appearance_version)) { - 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); + 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() ) @@ -6466,6 +6949,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; @@ -6475,7 +6960,10 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys ) return; } } - + else + { + LL_DEBUGS("Avatar") << "appearance message received" << llendl; + } // Check for stale update. if (isSelf() @@ -6493,9 +6981,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; + } + + setIsUsingServerBakes(appearance_version > 0); - applyParsedTEMessage(tec); + applyParsedTEMessage(contents.mTEContents); // prevent the overwriting of valid baked textures with invalid baked textures for (U8 baked_index = 0; baked_index < mBakedTextureDatas.size(); baked_index++) @@ -6509,10 +7008,15 @@ 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; + + LL_INFOS("Avatar") << avString() << "processAvatarAppearance start " << mID + << " first? " << is_first_appearance_message << " self? " << isSelf() << LL_ENDL; + if (is_first_appearance_message ) { onFirstTEMessageReceived(); @@ -6521,68 +7025,36 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys ) setCompositeUpdatesEnabled( FALSE ); gPipeline.markGLRebuild(this); - // 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 (is_first_appearance_message || (param->getWeight() != newWeight)) { - while( param && (param->getGroup() != VISUAL_PARAM_GROUP_TWEAKABLE) ) // should not be any of group VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT + params_changed = TRUE; + if(is_first_appearance_message) { - param = getNextVisualParam(); + param->setWeight(newWeight, FALSE); } - - 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()); - params_for_dump.push_back(newWeight); - - if (is_first_appearance_message || (param->getWeight() != newWeight)) + else { - //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); - } + interp_params = TRUE; + param->setAnimationTarget(newWeight, FALSE); } - param = getNextVisualParam(); } - 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; + 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) @@ -6606,14 +7078,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 @@ -6643,8 +7107,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 @@ -6674,12 +7137,12 @@ void LLVOAvatar::getAnimNames( LLDynamicArray<std::string>* names ) names->put( "enter_away_from_keyboard_state" ); } +// static void LLVOAvatar::onBakedTextureMasksLoaded( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata ) { if (!userdata) return; //llinfos << "onBakedTextureMasksLoaded: " << src_vi->getID() << llendl; - const LLMemType mt(LLMemType::MTYPE_AVATAR); const LLUUID id = src_vi->getID(); LLTextureMaskData* maskData = (LLTextureMaskData*) userdata; @@ -6693,7 +7156,7 @@ void LLVOAvatar::onBakedTextureMasksLoaded( BOOL success, LLViewerFetchedTexture { if (!aux_src->getData()) { - llerrs << "No auxiliary source data for onBakedTextureMasksLoaded" << llendl; + llerrs << "No auxiliary source (morph mask) data for image id " << id << llendl; return; } @@ -6745,7 +7208,7 @@ void LLVOAvatar::onBakedTextureMasksLoaded( BOOL success, LLViewerFetchedTexture } if (!found_texture_id) { - llinfos << "onBakedTextureMasksLoaded(): unexpected image id: " << id << llendl; + llinfos << "unexpected image id: " << id << llendl; } self->dirtyMesh(); } @@ -6753,7 +7216,7 @@ void LLVOAvatar::onBakedTextureMasksLoaded( BOOL success, LLViewerFetchedTexture { // this can happen when someone uses an old baked texture possibly provided by // viewer-side baked texture caching - llwarns << "Masks loaded callback but NO aux source!" << llendl; + llwarns << "Masks loaded callback but NO aux source, id " << id << llendl; } } @@ -7118,9 +7581,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 |