From 424786d8d05093abd816a3decd86aace64816179 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 18 Nov 2010 15:55:53 -0800 Subject: Added viewer-side "object overlaps parcel" check encroachment returnabilty UI Reviewed with Falcon --- indra/llmath/llbbox.cpp | 23 +++++++++++++++++++++++ indra/llmath/llbbox.h | 5 +++++ indra/llmessage/llregionflags.h | 28 ++++++++++++++-------------- indra/newview/llviewermenu.cpp | 6 +++--- indra/newview/llviewerobject.cpp | 18 +++++------------- indra/newview/llviewerobject.h | 9 +++------ indra/newview/llviewerparceloverlay.cpp | 24 ++++++++++++++++++++++++ indra/newview/llviewerparceloverlay.h | 7 +++++++ indra/newview/llviewerregion.cpp | 13 +++++++++++++ indra/newview/llviewerregion.h | 3 +++ 10 files changed, 100 insertions(+), 36 deletions(-) diff --git a/indra/llmath/llbbox.cpp b/indra/llmath/llbbox.cpp index b46a6e03d2..72c906b5ca 100644 --- a/indra/llmath/llbbox.cpp +++ b/indra/llmath/llbbox.cpp @@ -89,6 +89,20 @@ void LLBBox::addBBoxAgent(const LLBBox& b) } } +LLBBox LLBBox::getAxisAligned() const +{ + // no rotiation = axis aligned rotation + LLBBox aligned(mPosAgent, LLQuaternion(), LLVector3(), LLVector3()); + + // add the center point so that it's not empty + aligned.addPointAgent(mPosAgent); + + // add our BBox + aligned.addBBoxAgent(*this); + + return aligned; +} + void LLBBox::expand( F32 delta ) { @@ -147,6 +161,15 @@ BOOL LLBBox::containsPointAgent(const LLVector3& p) const return containsPointLocal(point_local); } +LLVector3 LLBBox::getMinAgent() const +{ + return localToAgent(mMinLocal); +} + +LLVector3 LLBBox::getMaxAgent() const +{ + return localToAgent(mMaxLocal); +} /* LLBBox operator*(const LLBBox &a, const LLMatrix4 &b) diff --git a/indra/llmath/llbbox.h b/indra/llmath/llbbox.h index 5b911793f0..a0d434b051 100644 --- a/indra/llmath/llbbox.h +++ b/indra/llmath/llbbox.h @@ -51,9 +51,11 @@ public: const LLVector3& getPositionAgent() const { return mPosAgent; } const LLQuaternion& getRotation() const { return mRotation; } + LLVector3 getMinAgent() const; const LLVector3& getMinLocal() const { return mMinLocal; } void setMinLocal( const LLVector3& min ) { mMinLocal = min; } + LLVector3 getMaxAgent() const; const LLVector3& getMaxLocal() const { return mMaxLocal; } void setMaxLocal( const LLVector3& max ) { mMaxLocal = max; } @@ -80,6 +82,9 @@ public: LLVector3 localToAgentBasis(const LLVector3& v) const; LLVector3 agentToLocalBasis(const LLVector3& v) const; + // Get the smallest possible axis aligned bbox that contains this bbox + LLBBox getAxisAligned() const; + // friend LLBBox operator*(const LLBBox& a, const LLMatrix4& b); diff --git a/indra/llmessage/llregionflags.h b/indra/llmessage/llregionflags.h index b9b974ec4f..d81051f413 100644 --- a/indra/llmessage/llregionflags.h +++ b/indra/llmessage/llregionflags.h @@ -42,8 +42,7 @@ const U32 REGION_FLAGS_RESET_HOME_ON_TELEPORT = (1 << 3); // Does the sun move? const U32 REGION_FLAGS_SUN_FIXED = (1 << 4); -// Tax free zone (no taxes on objects, land, etc.) -const U32 REGION_FLAGS_TAX_FREE = (1 << 5); +//const U32 REGION_FLAGS_TAX_FREE = (1 << 5); // legacy // Can't change the terrain heightfield, even on owned parcels, // but can plant trees and grass. @@ -54,17 +53,15 @@ const U32 REGION_FLAGS_BLOCK_LAND_RESELL = (1 << 7); // All content wiped once per night const U32 REGION_FLAGS_SANDBOX = (1 << 8); -const U32 REGION_FLAGS_NULL_LAYER = (1 << 9); -// const U32 REGION_FLAGS_SKIP_AGENT_ACTION = (1 << 10); -const U32 REGION_FLAGS_HARD_ALLOW_LAND_TRANSFER = (1 << 10); // Region allows land reselling -// const U32 REGION_FLAGS_SKIP_UPDATE_INTEREST_LIST= (1 << 11); -const U32 REGION_FLAGS_HARD_ALLOW_POST_CLASSIFIED = (1 << 11); // Region allows posting of classified ads +//const U32 REGION_FLAGS_NULL_LAYER = (1 << 9); +//const U32 REGION_FLAGS_HARD_ALLOW_LAND_TRANSFER = (1 << 10); +//const U32 REGION_FLAGS_SKIP_UPDATE_INTEREST_LIST= (1 << 11); const U32 REGION_FLAGS_SKIP_COLLISIONS = (1 << 12); // Pin all non agent rigid bodies const U32 REGION_FLAGS_SKIP_SCRIPTS = (1 << 13); const U32 REGION_FLAGS_SKIP_PHYSICS = (1 << 14); // Skip all physics const U32 REGION_FLAGS_EXTERNALLY_VISIBLE = (1 << 15); -//const U32 REGION_FLAGS_MAINLAND_VISIBLE = (1 << 16); -const U32 REGION_FLAGS_PUBLIC_ALLOWED = (1 << 17); +const U32 REGION_FLAGS_ALLOW_RETURN_ENCROACHING_OBJECT = (1 << 16); +const U32 REGION_FLAGS_ALLOW_RETURN_ENCROACHING_ESTATE_OBJECT = (1 << 17); const U32 REGION_FLAGS_BLOCK_DWELL = (1 << 18); // Is flight allowed? @@ -81,18 +78,22 @@ const U32 REGION_FLAGS_ESTATE_SKIP_SCRIPTS = (1 << 21); const U32 REGION_FLAGS_RESTRICT_PUSHOBJECT = (1 << 22); const U32 REGION_FLAGS_DENY_ANONYMOUS = (1 << 23); -// const U32 REGION_FLAGS_DENY_IDENTIFIED = (1 << 24); -// const U32 REGION_FLAGS_DENY_TRANSACTED = (1 << 25); +//const U32 REGION_FLAGS_DENY_IDENTIFIED = (1 << 24); +//const U32 REGION_FLAGS_DENY_TRANSACTED = (1 << 25); const U32 REGION_FLAGS_ALLOW_PARCEL_CHANGES = (1 << 26); -// const U32 REGION_FLAGS_ABUSE_EMAIL_TO_ESTATE_OWNER = (1 << 27); // We no longer support ELAR +// Deprecated. Phoeinx 2009-12-11 +// REGION_FLAGS_ABUSE_EMAIL_TO_ESTATE_OWNER is unused beyond viewer-1.23 +// but we leave uncommented because viewer-1.23 still uses it +//const U32 REGION_FLAGS_ABUSE_EMAIL_TO_ESTATE_OWNER = (1 << 27); const U32 REGION_FLAGS_ALLOW_VOICE = (1 << 28); const U32 REGION_FLAGS_BLOCK_PARCEL_SEARCH = (1 << 29); const U32 REGION_FLAGS_DENY_AGEUNVERIFIED = (1 << 30); -const U32 REGION_FLAGS_SKIP_MONO_SCRIPTS = (1 << 31); +//const U32 REGION_FLAGS_SKIP_MONO_SCRIPTS = (1 << 31); + const U32 REGION_FLAGS_DEFAULT = REGION_FLAGS_ALLOW_LANDMARK | REGION_FLAGS_ALLOW_SET_HOME | @@ -105,7 +106,6 @@ const U32 REGION_FLAGS_PRELUDE_UNSET = REGION_FLAGS_ALLOW_LANDMARK | REGION_FLAGS_ALLOW_SET_HOME; const U32 REGION_FLAGS_ESTATE_MASK = REGION_FLAGS_EXTERNALLY_VISIBLE - | REGION_FLAGS_PUBLIC_ALLOWED | REGION_FLAGS_SUN_FIXED | REGION_FLAGS_DENY_ANONYMOUS | REGION_FLAGS_DENY_AGEUNVERIFIED; diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index ec27eebab1..92a78c155e 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -4166,9 +4166,9 @@ class LLObjectEnableReturn : public view_listener_t { virtual bool apply(LLViewerObject* obj) { - return (obj->isOverAgentOwnedLand() || - obj->isOverGroupOwnedLand() || - obj->permModify()); + return + obj->permModify() || + obj->isReturnable(); } } func; const bool firstonly = true; diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 1804fac1b3..64892c7ee1 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -516,20 +516,12 @@ void LLViewerObject::setNameValueList(const std::string& name_value_list) // This method returns true if the object is over land owned by the // agent. -BOOL LLViewerObject::isOverAgentOwnedLand() const +bool LLViewerObject::isReturnable() { - return mRegionp - && mRegionp->getParcelOverlay() - && mRegionp->getParcelOverlay()->isOwnedSelf(getPositionRegion()); -} - -// This method returns true if the object is over land owned by the -// agent. -BOOL LLViewerObject::isOverGroupOwnedLand() const -{ - return mRegionp - && mRegionp->getParcelOverlay() - && mRegionp->getParcelOverlay()->isOwnedGroup(getPositionRegion()); + LLBBox(getPositionRegion(), getRotationRegion(), getScale() * -0.5f, getScale() * 0.5f); + return !isAttachment() + && mRegionp + && mRegionp->objectIsReturnable(getPositionRegion(), getBoundingBoxRegion()); } BOOL LLViewerObject::setParent(LLViewerObject* parent) diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index fe670f8827..21de5d28be 100644 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -226,12 +226,9 @@ public: virtual BOOL hasLightTexture() const { return FALSE; } // This method returns true if the object is over land owned by - // the agent. - BOOL isOverAgentOwnedLand() const; - - // True if over land owned by group of which the agent is - // either officer or member. - BOOL isOverGroupOwnedLand() const; + // the agent, one of its groups, or it it encroaches and + // anti-encroachment is enabled + bool isReturnable(); /* // This method will scan through this object, and then query the diff --git a/indra/newview/llviewerparceloverlay.cpp b/indra/newview/llviewerparceloverlay.cpp index eee653b0c1..58d9009c90 100644 --- a/indra/newview/llviewerparceloverlay.cpp +++ b/indra/newview/llviewerparceloverlay.cpp @@ -145,6 +145,30 @@ BOOL LLViewerParcelOverlay::isOwnedOther(const LLVector3& pos) const return (PARCEL_OWNED == overlay || PARCEL_FOR_SALE == overlay); } +bool LLViewerParcelOverlay::encroachesOwned(const LLBBox& bbox) const +{ + LLBBox bbox_aligned = bbox.getAxisAligned(); + + LLVector3 min = bbox_aligned.getMinAgent(); + LLVector3 max = bbox_aligned.getMaxAgent(); + + S32 left = S32(llclamp((min.mV[VX] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1)); + S32 right = S32(llclamp((max.mV[VX] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1)); + S32 top = S32(llclamp((min.mV[VY] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1)); + S32 bottom = S32(llclamp((max.mV[VY] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1)); + + for (S32 row = top; row <= bottom; row++) + for (S32 column = left; column <= right; column++) + { + U8 type = ownership(row, column); + if (PARCEL_SELF == type + || PARCEL_GROUP == type ) + return true; + } + + return false; +} + BOOL LLViewerParcelOverlay::isSoundLocal(const LLVector3& pos) const { S32 row = S32(pos.mV[VY] / PARCEL_GRID_STEP_METERS); diff --git a/indra/newview/llviewerparceloverlay.h b/indra/newview/llviewerparceloverlay.h index 61be220312..4aa42eb8a4 100644 --- a/indra/newview/llviewerparceloverlay.h +++ b/indra/newview/llviewerparceloverlay.h @@ -30,6 +30,7 @@ // The ownership data for land parcels. // One of these structures per region. +#include "llbbox.h" #include "lldarray.h" #include "llframetimer.h" #include "lluuid.h" @@ -54,6 +55,12 @@ public: BOOL isOwnedSelf(const LLVector3& pos) const; BOOL isOwnedGroup(const LLVector3& pos) const; BOOL isOwnedOther(const LLVector3& pos) const; + + // "encroaches" means the prim hangs over the parcel, but its center + // might be in another parcel. for now, we simply test bounding boxes + // which isn't perfect, but is close + bool encroachesOwned(const LLBBox& bbox) const; + BOOL isSoundLocal(const LLVector3& pos) const; BOOL isBuildCameraAllowed(const LLVector3& pos) const; diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index 9790301d11..e693fc65ea 100644 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -1495,6 +1495,19 @@ LLSpatialPartition* LLViewerRegion::getSpatialPartition(U32 type) return NULL; } +// the viewer can not yet distinquish between normal- and estate-owned objects +// so we collapse these two bits and enable the UI if either are set +const U32 ALLOW_RETURN_ENCROACHING_OBJECT = REGION_FLAGS_ALLOW_RETURN_ENCROACHING_OBJECT + | REGION_FLAGS_ALLOW_RETURN_ENCROACHING_ESTATE_OBJECT; + +bool LLViewerRegion::objectIsReturnable(const LLVector3& pos, const LLBBox& bbox) +{ + return mParcelOverlay + && ( mParcelOverlay->isOwned(pos) + || ((mRegionFlags & ALLOW_RETURN_ENCROACHING_OBJECT) + && mParcelOverlay->encroachesOwned(bbox)) ); +} + void LLViewerRegion::showReleaseNotes() { std::string url = this->getCapability("ServerReleaseNotes"); diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h index 8b71998f60..76228c0d2a 100644 --- a/indra/newview/llviewerregion.h +++ b/indra/newview/llviewerregion.h @@ -33,6 +33,7 @@ #include "lldarray.h" #include "llwind.h" +#include "llbbox.h" #include "llcloud.h" #include "llstat.h" #include "v3dmath.h" @@ -293,6 +294,8 @@ public: std::string getHttpUrl() const { return mHttpUrl ;} LLSpatialPartition* getSpatialPartition(U32 type); + + bool objectIsReturnable(const LLVector3& pos, const LLBBox& bbox); public: struct CompareDistance { -- cgit v1.2.3 From c320b2cef916cc8f0e42f041c29c04bf55d40d77 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 19 Nov 2010 08:36:53 -0800 Subject: Fixing a typo that broke the build. --- indra/newview/llviewerobject.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 64892c7ee1..df89e6759d 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -518,10 +518,10 @@ void LLViewerObject::setNameValueList(const std::string& name_value_list) // agent. bool LLViewerObject::isReturnable() { - LLBBox(getPositionRegion(), getRotationRegion(), getScale() * -0.5f, getScale() * 0.5f); + LLBBox box_in_region_frame(getPositionRegion(), getRotationRegion(), getScale() * -0.5f, getScale() * 0.5f); return !isAttachment() && mRegionp - && mRegionp->objectIsReturnable(getPositionRegion(), getBoundingBoxRegion()); + && mRegionp->objectIsReturnable(getPositionRegion(), box_in_region_frame); } BOOL LLViewerObject::setParent(LLViewerObject* parent) -- cgit v1.2.3 From 0dce88bc92cfb1ebebb575087ca950a6d5363c0c Mon Sep 17 00:00:00 2001 From: Dave SIMmONs Date: Fri, 19 Nov 2010 16:49:24 -0800 Subject: ER-330 : Improve ObjectUpdateCached message packing. Added some viewer metrics, will disable later. --- indra/llcommon/llfile.cpp | 11 +++ indra/llcommon/llfile.h | 2 + indra/newview/CMakeLists.txt | 2 + indra/newview/llviewerobjectlist.cpp | 21 +++++- indra/newview/llviewerstatsrecorder.cpp | 121 ++++++++++++++++++++++++++++++++ indra/newview/llviewerstatsrecorder.h | 66 +++++++++++++++++ 6 files changed, 222 insertions(+), 1 deletion(-) create mode 100644 indra/newview/llviewerstatsrecorder.cpp create mode 100644 indra/newview/llviewerstatsrecorder.h diff --git a/indra/llcommon/llfile.cpp b/indra/llcommon/llfile.cpp index 289ce0bc2c..694c90e184 100644 --- a/indra/llcommon/llfile.cpp +++ b/indra/llcommon/llfile.cpp @@ -92,6 +92,17 @@ LLFILE* LLFile::_fsopen(const std::string& filename, const char* mode, int shari #endif } +int LLFile::close(LLFILE * file) +{ + int ret_value = 0; + if (file) + { + ret_value = fclose(file); + } + return ret_value; +} + + int LLFile::remove(const std::string& filename) { #if LL_WINDOWS diff --git a/indra/llcommon/llfile.h b/indra/llcommon/llfile.h index 4913af7cb5..dd7d36513a 100644 --- a/indra/llcommon/llfile.h +++ b/indra/llcommon/llfile.h @@ -71,6 +71,8 @@ public: static LLFILE* fopen(const std::string& filename,const char* accessmode); /* Flawfinder: ignore */ static LLFILE* _fsopen(const std::string& filename,const char* accessmode,int sharingFlag); + static int close(LLFILE * file); + // perms is a permissions mask like 0777 or 0700. In most cases it will // be overridden by the user's umask. It is ignored on Windows. static int mkdir(const std::string& filename, int perms = 0700); diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 3a4b9be0d7..7724f41931 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -523,6 +523,7 @@ set(viewer_SOURCE_FILES llviewerregion.cpp llviewershadermgr.cpp llviewerstats.cpp + llviewerstatsrecorder.cpp llviewertexteditor.cpp llviewertexture.cpp llviewertextureanim.cpp @@ -1051,6 +1052,7 @@ set(viewer_HEADER_FILES llviewerregion.h llviewershadermgr.h llviewerstats.h + llviewerstatsrecorder.h llviewertexteditor.h llviewertexture.h llviewertextureanim.h diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp index f5a32438cf..d14fd69348 100644 --- a/indra/newview/llviewerobjectlist.cpp +++ b/indra/newview/llviewerobjectlist.cpp @@ -56,6 +56,7 @@ #include "llresmgr.h" #include "llviewerregion.h" #include "llviewerstats.h" +#include "llviewerstatsrecorder.h" #include "llvoavatarself.h" #include "lltoolmgr.h" #include "lltoolpie.h" @@ -345,7 +346,13 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, U8 compressed_dpbuffer[2048]; LLDataPackerBinaryBuffer compressed_dp(compressed_dpbuffer, 2048); LLDataPacker *cached_dpp = NULL; - + +#if LL_RECORD_VIEWER_STATS + static LLViewerStatsRecorder stats_recorder; + stats_recorder.initStatsRecorder(regionp); + stats_recorder.initCachedObjectUpdate(regionp); +#endif + for (i = 0; i < num_objects; i++) { LLTimer update_timer; @@ -369,6 +376,10 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, } else { + #if LL_RECORD_VIEWER_STATS + stats_recorder.recordCachedObjectEvent(regionp, id, NULL); + #endif + continue; // no data packer, skip this object } } @@ -540,6 +551,10 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, { objectp->mLocalID = local_id; processUpdateCore(objectp, user_data, i, update_type, cached_dpp, justCreated); + + #if LL_RECORD_VIEWER_STATS + stats_recorder.recordCachedObjectEvent(regionp, local_id, objectp); + #endif } else { @@ -551,6 +566,10 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, } } +#if LL_RECORD_VIEWER_STATS + stats_recorder.closeCachedObjectUpdate(regionp); +#endif + LLVOAvatar::cullAvatarsByPixelArea(); } diff --git a/indra/newview/llviewerstatsrecorder.cpp b/indra/newview/llviewerstatsrecorder.cpp new file mode 100644 index 0000000000..4e7cf00ba0 --- /dev/null +++ b/indra/newview/llviewerstatsrecorder.cpp @@ -0,0 +1,121 @@ +/** + * @file llviewerstatsrecorder.cpp + * @brief record info about viewer events to a metrics log file + * + * $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 "llviewerstatsrecorder.h" +#include "llfile.h" +#include "llviewerregion.h" +#include "llviewerobject.h" + +LLViewerStatsRecorder::LLViewerStatsRecorder() : + mObjectCacheFile(NULL), + mTimer() +{ + mStartTime = LLTimer::getTotalTime(); +} + +LLViewerStatsRecorder::~LLViewerStatsRecorder() +{ + LLFile::close(mObjectCacheFile); + mObjectCacheFile = NULL; +} + + +void LLViewerStatsRecorder::initStatsRecorder(LLViewerRegion *regionp) +{ + // To do - something using region name or global position +#if LL_WINDOWS + std::string stats_file_name("C:\\ViewerObjectCacheStats.csv"); +#else + std::string stats_file_name("~/viewerstats.csv"); +#endif + + if (mObjectCacheFile == NULL) + { + mObjectCacheFile = LLFile::fopen(stats_file_name, "wb"); + if (mObjectCacheFile) + { // Write column headers + std::ostringstream data_msg; + data_msg << "Time, " + << "Hits, " + << "Misses, " + << "Objects " + << "\n"; + + fwrite(data_msg.str().c_str(), 1, data_msg.str().size(), mObjectCacheFile ); + } + } +} + + +void LLViewerStatsRecorder::initCachedObjectUpdate(LLViewerRegion *regionp) +{ + mObjectCacheHitCount = 0; + mObjectCacheMissCount = 0; +} + + +void LLViewerStatsRecorder::recordCachedObjectEvent(LLViewerRegion *regionp, U32 local_id, LLViewerObject * objectp) +{ + if (objectp) + { + mObjectCacheHitCount++; + } + else + { // no object, must be a miss + mObjectCacheMissCount++; + } +} + +void LLViewerStatsRecorder::closeCachedObjectUpdate(LLViewerRegion *regionp) +{ + llinfos << "ILX: " << mObjectCacheHitCount + << " hits " + << mObjectCacheMissCount << " misses" + << llendl; + + S32 total_objects = mObjectCacheHitCount + mObjectCacheMissCount; + if (mObjectCacheFile != NULL && + total_objects > 0) + { + std::ostringstream data_msg; + F32 now32 = (F32) ((LLTimer::getTotalTime() - mStartTime) / 1000.0); + + data_msg << now32 + << ", " << mObjectCacheHitCount + << ", " << mObjectCacheMissCount + << ", " << total_objects + << "\n"; + + fwrite(data_msg.str().c_str(), 1, data_msg.str().size(), mObjectCacheFile ); + } + + mObjectCacheHitCount = 0; + mObjectCacheMissCount = 0; +} + + + diff --git a/indra/newview/llviewerstatsrecorder.h b/indra/newview/llviewerstatsrecorder.h new file mode 100644 index 0000000000..0c5e6d5010 --- /dev/null +++ b/indra/newview/llviewerstatsrecorder.h @@ -0,0 +1,66 @@ +/** + * @file llviewerstatsrecorder.h + * @brief record info about viewer events to a metrics log file + * + * $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 LLVIEWERSTATSRECORDER_H +#define LLVIEWERSTATSRECORDER_H + + +// This is a diagnostic class used to record information from the viewer +// for analysis. + +// This is normally 0. Set to 1 to enable viewer stats recording +#define LL_RECORD_VIEWER_STATS 1 + + +#if LL_RECORD_VIEWER_STATS +#include "llframetimer.h" + +class LLViewerRegion; +class LLViewerObject; + +class LLViewerStatsRecorder +{ + public: + LLViewerStatsRecorder(); + ~LLViewerStatsRecorder(); + + void initStatsRecorder(LLViewerRegion *regionp); + + void initCachedObjectUpdate(LLViewerRegion *regionp); + void recordCachedObjectEvent(LLViewerRegion *regionp, U32 local_id, LLViewerObject * objectp); + void closeCachedObjectUpdate(LLViewerRegion *regionp); + +private: + LLFrameTimer mTimer; + F64 mStartTime; + + LLFILE * mObjectCacheFile; // File to write data into + S32 mObjectCacheHitCount; + S32 mObjectCacheMissCount; +}; +#endif // LL_RECORD_VIEWER_STATS + +#endif // LLVIEWERSTATSRECORDER_H -- cgit v1.2.3 From 0386f3e9c69d888d57baade56535de738decde44 Mon Sep 17 00:00:00 2001 From: Jonathan Yap Date: Tue, 30 Nov 2010 05:46:05 -0500 Subject: Object menu: put Delete at top level, rename Remove> to Manage> --- indra/newview/skins/default/xui/en/menu_object.xml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/indra/newview/skins/default/xui/en/menu_object.xml b/indra/newview/skins/default/xui/en/menu_object.xml index c751aa4e0c..719509301b 100644 --- a/indra/newview/skins/default/xui/en/menu_object.xml +++ b/indra/newview/skins/default/xui/en/menu_object.xml @@ -100,7 +100,7 @@ name="Object Attach HUD" /> - - - - + + + + -- cgit v1.2.3 From 31f738583e770856a571653a9e23c096ce4049db Mon Sep 17 00:00:00 2001 From: Jonathan Yap Date: Wed, 1 Dec 2010 13:35:30 -0500 Subject: Forgot to give myself credit --- doc/contributions.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/contributions.txt b/doc/contributions.txt index d4e459039d..43ab6ecd60 100644 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -356,6 +356,7 @@ Joghert LeSabre Jonathan Yap VWR-17801 STORM-616 + STORM-615 Kage Pixel VWR-11 Ken March -- cgit v1.2.3 From 71a1fd09e3344920fef56cd0fbeac9710f2b698c Mon Sep 17 00:00:00 2001 From: Jonathan Yap Date: Fri, 3 Dec 2010 10:15:33 -0500 Subject: Add ability to see Details button in Object Profile for 1-prim objects --- doc/contributions.txt | 5 +++-- indra/newview/llsidepaneltaskinfo.cpp | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/doc/contributions.txt b/doc/contributions.txt index 2334aeb17b..8cb3fd9f35 100644 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -354,10 +354,11 @@ JB Kraft Joghert LeSabre VWR-64 Jonathan Yap - VWR-17801 + STORM-596 STORM-616 STORM-679 - STORM-596 + STORM-723 + VWR-17801 Kage Pixel VWR-11 Ken March diff --git a/indra/newview/llsidepaneltaskinfo.cpp b/indra/newview/llsidepaneltaskinfo.cpp index 47d904dfcc..ff472c2141 100644 --- a/indra/newview/llsidepaneltaskinfo.cpp +++ b/indra/newview/llsidepaneltaskinfo.cpp @@ -1125,8 +1125,8 @@ void LLSidepanelTaskInfo::updateVerbs() mOpenBtn->setVisible(!multi_select); mPayBtn->setVisible(!multi_select); mBuyBtn->setVisible(!multi_select); - mDetailsBtn->setVisible(multi_select); - mDetailsBtn->setEnabled(multi_select); + mDetailsBtn->setVisible(TRUE); + mDetailsBtn->setEnabled(TRUE); mOpenBtn->setEnabled(enable_object_open()); mPayBtn->setEnabled(enable_pay_object()); -- cgit v1.2.3 From dd8e387d66bec042bde299b88bab81d465bf4df1 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 6 Dec 2010 15:47:35 -0800 Subject: ER-343 viewer UI does not correctly enable/disable object return The problem: a misunderstanding of what LLViewerParcelOverlay::isOwned() means. --- indra/newview/llviewerregion.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index e693fc65ea..8508b1847b 100644 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -1502,8 +1502,9 @@ const U32 ALLOW_RETURN_ENCROACHING_OBJECT = REGION_FLAGS_ALLOW_RETURN_ENCROACHIN bool LLViewerRegion::objectIsReturnable(const LLVector3& pos, const LLBBox& bbox) { - return mParcelOverlay - && ( mParcelOverlay->isOwned(pos) + return (mParcelOverlay != NULL) + && (mParcelOverlay->isOwnedSelf(pos) + || mParcelOverlay->isOwnedGroup(pos) || ((mRegionFlags & ALLOW_RETURN_ENCROACHING_OBJECT) && mParcelOverlay->encroachesOwned(bbox)) ); } -- cgit v1.2.3 From 0239421aa0c69fe9ce6b12671e927baaf05e5ae1 Mon Sep 17 00:00:00 2001 From: Don Kjer Date: Wed, 8 Dec 2010 17:42:47 -0800 Subject: Changed non-windows viewer stats recorder file to live in /tmp --- indra/newview/llviewerstatsrecorder.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/llviewerstatsrecorder.cpp b/indra/newview/llviewerstatsrecorder.cpp index 4e7cf00ba0..83c115af90 100644 --- a/indra/newview/llviewerstatsrecorder.cpp +++ b/indra/newview/llviewerstatsrecorder.cpp @@ -50,7 +50,7 @@ void LLViewerStatsRecorder::initStatsRecorder(LLViewerRegion *regionp) #if LL_WINDOWS std::string stats_file_name("C:\\ViewerObjectCacheStats.csv"); #else - std::string stats_file_name("~/viewerstats.csv"); + std::string stats_file_name("/tmp/viewerstats.csv"); #endif if (mObjectCacheFile == NULL) -- cgit v1.2.3 From 03b68dad4bb6da4fa6ca7dcd05af91cfc96b4e31 Mon Sep 17 00:00:00 2001 From: Don Kjer Date: Thu, 9 Dec 2010 20:02:36 -0800 Subject: Expanded viewer stats recorder metrics to include all object update types --- indra/newview/llviewerobjectlist.cpp | 75 +++++++++++++++++++++------------ indra/newview/llviewerstatsrecorder.cpp | 63 ++++++++++++++++++++------- indra/newview/llviewerstatsrecorder.h | 11 +++-- 3 files changed, 105 insertions(+), 44 deletions(-) diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp index d14fd69348..5a42f10c8f 100644 --- a/indra/newview/llviewerobjectlist.cpp +++ b/indra/newview/llviewerobjectlist.cpp @@ -303,8 +303,10 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, // have to transform to absolute coordinates. num_objects = mesgsys->getNumberOfBlocksFast(_PREHASH_ObjectData); + // I don't think this case is ever hit. TODO* Test this. if (!cached && !compressed && update_type != OUT_FULL) { + llinfos << "TEST: !cached && !compressed && update_type != OUT_FULL" << llendl; gTerseObjectUpdates += num_objects; S32 size; if (mesgsys->getReceiveCompressedSize()) @@ -315,7 +317,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, { size = mesgsys->getReceiveSize(); } - // llinfos << "Received terse " << num_objects << " in " << size << " byte (" << size/num_objects << ")" << llendl; + llinfos << "Received terse " << num_objects << " in " << size << " byte (" << size/num_objects << ")" << llendl; } else { @@ -349,12 +351,12 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, #if LL_RECORD_VIEWER_STATS static LLViewerStatsRecorder stats_recorder; - stats_recorder.initStatsRecorder(regionp); - stats_recorder.initCachedObjectUpdate(regionp); + stats_recorder.initObjectUpdateEvents(regionp); #endif for (i = 0; i < num_objects; i++) { + // timer is unused? LLTimer update_timer; BOOL justCreated = FALSE; @@ -369,6 +371,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, cached_dpp = regionp->getDP(id, crc); if (cached_dpp) { + // Cache Hit. cached_dpp->reset(); cached_dpp->unpackUUID(fullid, "ID"); cached_dpp->unpackU32(local_id, "LocalID"); @@ -376,8 +379,10 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, } else { + // Cache Miss. #if LL_RECORD_VIEWER_STATS - stats_recorder.recordCachedObjectEvent(regionp, id, NULL); + const BOOL success = TRUE; + stats_recorder.recordObjectUpdateEvent(regionp, id, update_type, success, NULL); #endif continue; // no data packer, skip this object @@ -391,13 +396,15 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, compressed_dp.reset(); U32 flags = 0; - if (update_type != OUT_TERSE_IMPROVED) + if (update_type != OUT_TERSE_IMPROVED) // OUT_FULL_COMPRESSED only? { mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_UpdateFlags, flags, i); } + // I don't think we ever use this flag from the server. DK 2010/12/09 if (flags & FLAGS_ZLIB_COMPRESSED) { + llinfos << "TEST: flags & FLAGS_ZLIB_COMPRESSED" << llendl; compressed_length = mesgsys->getSizeFast(_PREHASH_ObjectData, i, _PREHASH_Data); mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_Data, compbuffer, 0, i); uncompressed_length = 2048; @@ -413,7 +420,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, } - if (update_type != OUT_TERSE_IMPROVED) + if (update_type != OUT_TERSE_IMPROVED) // OUT_FULL_COMPRESSED only? { compressed_dp.unpackUUID(fullid, "ID"); compressed_dp.unpackU32(local_id, "LocalID"); @@ -433,7 +440,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, } } } - else if (update_type != OUT_FULL) + else if (update_type != OUT_FULL) // !compressed, !OUT_FULL ==> OUT_FULL_CACHED only? { mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_ID, local_id, i); getUUIDFromLocal(fullid, @@ -446,7 +453,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, mNumUnknownUpdates++; } } - else + else // OUT_FULL only? { mesgsys->getUUIDFast(_PREHASH_ObjectData, _PREHASH_FullID, fullid, i); mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_ID, local_id, i); @@ -478,12 +485,12 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, gMessageSystem->getSenderPort()); if (objectp->mLocalID != local_id) - { // Update local ID in object with the one sent from the region + { // Update local ID in object with the one sent from the region objectp->mLocalID = local_id; } if (objectp->getRegion() != regionp) - { // Object changed region, so update it + { // Object changed region, so update it objectp->updateRegion(regionp); // for LLVOAvatar } } @@ -495,10 +502,14 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, if (update_type == OUT_TERSE_IMPROVED) { // llinfos << "terse update for an unknown object:" << fullid << llendl; + #if LL_RECORD_VIEWER_STATS + const BOOL success = FALSE; + stats_recorder.recordObjectUpdateEvent(regionp, local_id, update_type, success, NULL); + #endif continue; } } - else if (cached) + else if (cached) // Cache hit only? { } else @@ -506,6 +517,10 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, if (update_type != OUT_FULL) { // llinfos << "terse update for an unknown object:" << fullid << llendl; + #if LL_RECORD_VIEWER_STATS + const BOOL success = FALSE; + stats_recorder.recordObjectUpdateEvent(regionp, local_id, update_type, success, NULL); + #endif continue; } @@ -516,6 +531,10 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, { mNumDeadObjectUpdates++; // llinfos << "update for a dead object:" << fullid << llendl; + #if LL_RECORD_VIEWER_STATS + const BOOL success = FALSE; + stats_recorder.recordObjectUpdateEvent(regionp, local_id, update_type, success, NULL); + #endif continue; } #endif @@ -523,6 +542,10 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, objectp = createObject(pcode, regionp, fullid, local_id, gMessageSystem->getSender()); if (!objectp) { + #if LL_RECORD_VIEWER_STATS + const BOOL success = FALSE; + stats_recorder.recordObjectUpdateEvent(regionp, local_id, update_type, success, NULL); + #endif continue; } justCreated = TRUE; @@ -537,24 +560,20 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, if (compressed) { - if (update_type != OUT_TERSE_IMPROVED) + if (update_type != OUT_TERSE_IMPROVED) // OUT_FULL_COMPRESSED only? { objectp->mLocalID = local_id; } processUpdateCore(objectp, user_data, i, update_type, &compressed_dp, justCreated); - if (update_type != OUT_TERSE_IMPROVED) + if (update_type != OUT_TERSE_IMPROVED) // OUT_FULL_COMPRESSED only? { objectp->mRegionp->cacheFullUpdate(objectp, compressed_dp); } } - else if (cached) + else if (cached) // Cache hit only? { objectp->mLocalID = local_id; processUpdateCore(objectp, user_data, i, update_type, cached_dpp, justCreated); - - #if LL_RECORD_VIEWER_STATS - stats_recorder.recordCachedObjectEvent(regionp, local_id, objectp); - #endif } else { @@ -564,10 +583,14 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, } processUpdateCore(objectp, user_data, i, update_type, NULL, justCreated); } + #if LL_RECORD_VIEWER_STATS + const BOOL success = TRUE; + stats_recorder.recordObjectUpdateEvent(regionp, local_id, update_type, success, objectp); + #endif } #if LL_RECORD_VIEWER_STATS - stats_recorder.closeCachedObjectUpdate(regionp); + stats_recorder.closeObjectUpdateEvents(regionp); #endif LLVOAvatar::cullAvatarsByPixelArea(); @@ -700,12 +723,12 @@ void LLViewerObjectList::update(LLAgent &agent, LLWorld &world) // update global timer F32 last_time = gFrameTimeSeconds; - U64 time = totalTime(); // this will become the new gFrameTime when the update is done + U64 time = totalTime(); // this will become the new gFrameTime when the update is done // Time _can_ go backwards, for example if the user changes the system clock. // It doesn't cause any fatal problems (just some oddness with stats), so we shouldn't assert here. // llassert(time > gFrameTime); F64 time_diff = U64_to_F64(time - gFrameTime)/(F64)SEC_TO_MICROSEC; - gFrameTime = time; + gFrameTime = time; F64 time_since_start = U64_to_F64(gFrameTime - gStartTime)/(F64)SEC_TO_MICROSEC; gFrameTimeSeconds = (F32)time_since_start; @@ -807,7 +830,7 @@ void LLViewerObjectList::update(LLAgent &agent, LLWorld &world) { std::string id_str; objectp->mID.toString(id_str); - std::string tmpstr = std::string("Par: ") + id_str; + std::string tmpstr = std::string("Par: ") + id_str; addDebugBeacon(objectp->getPositionAgent(), tmpstr, LLColor4(1.f,0.f,0.f,1.f), @@ -827,12 +850,12 @@ void LLViewerObjectList::update(LLAgent &agent, LLWorld &world) std::string tmpstr; if (objectp->getParent()) { - tmpstr = std::string("ChP: ") + id_str; + tmpstr = std::string("ChP: ") + id_str; text_color = LLColor4(0.f, 1.f, 0.f, 1.f); } else { - tmpstr = std::string("ChNoP: ") + id_str; + tmpstr = std::string("ChNoP: ") + id_str; text_color = LLColor4(1.f, 0.f, 0.f, 1.f); } id = sIndexAndLocalIDToUUID[oi.mParentInfo]; @@ -1538,8 +1561,8 @@ void LLViewerObjectList::findOrphans(LLViewerObject* objectp, U32 ip, U32 port) llinfos << "Agent: " << objectp->getPositionAgent() << llendl; addDebugBeacon(objectp->getPositionAgent(),""); #endif - gPipeline.markMoved(objectp->mDrawable); - objectp->setChanged(LLXform::MOVED | LLXform::SILHOUETTE); + gPipeline.markMoved(objectp->mDrawable); + objectp->setChanged(LLXform::MOVED | LLXform::SILHOUETTE); // Flag the object as no longer orphaned childp->mOrphaned = FALSE; diff --git a/indra/newview/llviewerstatsrecorder.cpp b/indra/newview/llviewerstatsrecorder.cpp index 83c115af90..1b80a2bc1c 100644 --- a/indra/newview/llviewerstatsrecorder.cpp +++ b/indra/newview/llviewerstatsrecorder.cpp @@ -59,10 +59,14 @@ void LLViewerStatsRecorder::initStatsRecorder(LLViewerRegion *regionp) if (mObjectCacheFile) { // Write column headers std::ostringstream data_msg; - data_msg << "Time, " - << "Hits, " - << "Misses, " - << "Objects " + data_msg << "EventTime, " + << "ProcessingTime, " + << "CacheHits, " + << "CacheMisses, " + << "FullUpdates, " + << "TerseUpdates, " + << "CacheMissResponses, " + << "TotalUpdates " << "\n"; fwrite(data_msg.str().c_str(), 1, data_msg.str().size(), mObjectCacheFile ); @@ -71,42 +75,71 @@ void LLViewerStatsRecorder::initStatsRecorder(LLViewerRegion *regionp) } -void LLViewerStatsRecorder::initCachedObjectUpdate(LLViewerRegion *regionp) +void LLViewerStatsRecorder::initObjectUpdateEvents(LLViewerRegion *regionp) { + initStatsRecorder(regionp); mObjectCacheHitCount = 0; mObjectCacheMissCount = 0; + mObjectFullUpdates = 0; + mObjectTerseUpdates = 0; + mObjectCacheMissResponses = 0; + mProcessingTime = LLTimer::getTotalTime(); } -void LLViewerStatsRecorder::recordCachedObjectEvent(LLViewerRegion *regionp, U32 local_id, LLViewerObject * objectp) +void LLViewerStatsRecorder::recordObjectUpdateEvent(LLViewerRegion *regionp, U32 local_id, const EObjectUpdateType update_type, BOOL success, LLViewerObject * objectp) { - if (objectp) + if (!objectp) { - mObjectCacheHitCount++; + // no object, must be a miss + mObjectCacheMissCount++; } else - { // no object, must be a miss - mObjectCacheMissCount++; + { + switch (update_type) + { + case OUT_FULL: + mObjectFullUpdates++; + break; + case OUT_TERSE_IMPROVED: + mObjectTerseUpdates++; + break; + case OUT_FULL_COMPRESSED: + mObjectCacheMissResponses++; + break; + case OUT_FULL_CACHED: + default: + mObjectCacheHitCount++; + break; + }; } } -void LLViewerStatsRecorder::closeCachedObjectUpdate(LLViewerRegion *regionp) +void LLViewerStatsRecorder::closeObjectUpdateEvents(LLViewerRegion *regionp) { - llinfos << "ILX: " << mObjectCacheHitCount - << " hits " - << mObjectCacheMissCount << " misses" + llinfos << "ILX: " + << mObjectCacheHitCount << " hits, " + << mObjectCacheMissCount << " misses, " + << mObjectFullUpdates << " full updates, " + << mObjectTerseUpdates << " terse updates, " + << mObjectCacheMissResponses << " cache miss responses" << llendl; - S32 total_objects = mObjectCacheHitCount + mObjectCacheMissCount; + S32 total_objects = mObjectCacheHitCount + mObjectCacheMissCount + mObjectFullUpdates + mObjectTerseUpdates + mObjectCacheMissResponses;; if (mObjectCacheFile != NULL && total_objects > 0) { std::ostringstream data_msg; F32 now32 = (F32) ((LLTimer::getTotalTime() - mStartTime) / 1000.0); + F32 processing32 = (F32) ((LLTimer::getTotalTime() - mProcessingTime) / 1000.0); data_msg << now32 + << ", " << processing32 << ", " << mObjectCacheHitCount << ", " << mObjectCacheMissCount + << ", " << mObjectFullUpdates + << ", " << mObjectTerseUpdates + << ", " << mObjectCacheMissResponses << ", " << total_objects << "\n"; diff --git a/indra/newview/llviewerstatsrecorder.h b/indra/newview/llviewerstatsrecorder.h index 0c5e6d5010..213d15f963 100644 --- a/indra/newview/llviewerstatsrecorder.h +++ b/indra/newview/llviewerstatsrecorder.h @@ -37,6 +37,7 @@ #if LL_RECORD_VIEWER_STATS #include "llframetimer.h" +#include "llviewerobject.h" class LLViewerRegion; class LLViewerObject; @@ -49,17 +50,21 @@ class LLViewerStatsRecorder void initStatsRecorder(LLViewerRegion *regionp); - void initCachedObjectUpdate(LLViewerRegion *regionp); - void recordCachedObjectEvent(LLViewerRegion *regionp, U32 local_id, LLViewerObject * objectp); - void closeCachedObjectUpdate(LLViewerRegion *regionp); + void initObjectUpdateEvents(LLViewerRegion *regionp); + void recordObjectUpdateEvent(LLViewerRegion *regionp, U32 local_id, const EObjectUpdateType update_type, BOOL success, LLViewerObject * objectp); + void closeObjectUpdateEvents(LLViewerRegion *regionp); private: LLFrameTimer mTimer; F64 mStartTime; + F64 mProcessingTime; LLFILE * mObjectCacheFile; // File to write data into S32 mObjectCacheHitCount; S32 mObjectCacheMissCount; + S32 mObjectFullUpdates; + S32 mObjectTerseUpdates; + S32 mObjectCacheMissResponses; }; #endif // LL_RECORD_VIEWER_STATS -- cgit v1.2.3 From 553a1a3b59b85fe792173c5d728e3950d59bb315 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 10 Dec 2010 21:00:58 -0800 Subject: Sigh... another fix for ER-343. Or maybe I forgot to commit the first time? LLViewerParcelOverlay::isOwned() just reports that *someone* ownes the parcel rather than the main *avatar* ownes the parcel. --- indra/newview/llviewerregion.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index c73b5fdd40..d9fd731ad3 100644 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -1503,7 +1503,8 @@ const U32 ALLOW_RETURN_ENCROACHING_OBJECT = REGION_FLAGS_ALLOW_RETURN_ENCROACHIN bool LLViewerRegion::objectIsReturnable(const LLVector3& pos, const LLBBox& bbox) { return mParcelOverlay - && ( mParcelOverlay->isOwned(pos) + && ( (mParcelOverlay->isOwnedSelf(pos) + || mParcelOverlay->isOwnedGroup(pos)) || ((mRegionFlags & ALLOW_RETURN_ENCROACHING_OBJECT) && mParcelOverlay->encroachesOwned(bbox)) ); } -- cgit v1.2.3 From f4884faf3a020a718c611f34aa534e80d8a8b666 Mon Sep 17 00:00:00 2001 From: Don Kjer Date: Mon, 13 Dec 2010 12:33:19 -0800 Subject: Expanded viewer stats recorder to include cache miss type, cache miss requests, and update failures --- indra/newview/llappviewer.cpp | 11 +++ indra/newview/llviewerobjectlist.cpp | 26 +++--- indra/newview/llviewerregion.cpp | 14 ++- indra/newview/llviewerregion.h | 9 +- indra/newview/llviewerstatsrecorder.cpp | 150 ++++++++++++++++++++++---------- indra/newview/llviewerstatsrecorder.h | 44 +++++++--- 6 files changed, 173 insertions(+), 81 deletions(-) diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 6c07974f69..5972e7aef8 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -44,6 +44,7 @@ #include "llagentwearables.h" #include "llwindow.h" #include "llviewerstats.h" +#include "llviewerstatsrecorder.h" #include "llmd5.h" #include "llpumpio.h" #include "llmimetypes.h" @@ -648,6 +649,10 @@ bool LLAppViewer::init() mAlloc.setProfilingEnabled(gSavedSettings.getBOOL("MemProfiling")); +#if LL_RECORD_VIEWER_STATS + LLViewerStatsRecorder::initClass(); +#endif + // *NOTE:Mani - LLCurl::initClass is not thread safe. // Called before threads are created. LLCurl::initClass(); @@ -950,6 +955,8 @@ bool LLAppViewer::init() LLAgentLanguage::init(); + + return true; } @@ -1665,6 +1672,10 @@ bool LLAppViewer::cleanup() } LLMetricPerformanceTesterBasic::cleanClass() ; +#if LL_RECORD_VIEWER_STATS + LLViewerStatsRecorder::cleanupClass(); +#endif + llinfos << "Cleaning up Media and Textures" << llendflush; //Note: diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp index 5a42f10c8f..249799bf55 100644 --- a/indra/newview/llviewerobjectlist.cpp +++ b/indra/newview/llviewerobjectlist.cpp @@ -350,8 +350,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, LLDataPacker *cached_dpp = NULL; #if LL_RECORD_VIEWER_STATS - static LLViewerStatsRecorder stats_recorder; - stats_recorder.initObjectUpdateEvents(regionp); + LLViewerStatsRecorder::instance()->beginObjectUpdateEvents(regionp); #endif for (i = 0; i < num_objects; i++) @@ -368,7 +367,8 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_CRC, crc, i); // Lookup data packer and add this id to cache miss lists if necessary. - cached_dpp = regionp->getDP(id, crc); + U8 cache_miss_type = LLViewerRegion::CACHE_MISS_TYPE_NONE; + cached_dpp = regionp->getDP(id, crc, cache_miss_type); if (cached_dpp) { // Cache Hit. @@ -381,8 +381,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, { // Cache Miss. #if LL_RECORD_VIEWER_STATS - const BOOL success = TRUE; - stats_recorder.recordObjectUpdateEvent(regionp, id, update_type, success, NULL); + LLViewerStatsRecorder::instance()->recordCacheMissEvent(id, update_type, cache_miss_type); #endif continue; // no data packer, skip this object @@ -503,8 +502,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, { // llinfos << "terse update for an unknown object:" << fullid << llendl; #if LL_RECORD_VIEWER_STATS - const BOOL success = FALSE; - stats_recorder.recordObjectUpdateEvent(regionp, local_id, update_type, success, NULL); + LLViewerStatsRecorder::instance()->recordObjectUpdateFailure(local_id, update_type); #endif continue; } @@ -518,8 +516,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, { // llinfos << "terse update for an unknown object:" << fullid << llendl; #if LL_RECORD_VIEWER_STATS - const BOOL success = FALSE; - stats_recorder.recordObjectUpdateEvent(regionp, local_id, update_type, success, NULL); + LLViewerStatsRecorder::instance()->recordObjectUpdateFailure(local_id, update_type); #endif continue; } @@ -532,8 +529,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, mNumDeadObjectUpdates++; // llinfos << "update for a dead object:" << fullid << llendl; #if LL_RECORD_VIEWER_STATS - const BOOL success = FALSE; - stats_recorder.recordObjectUpdateEvent(regionp, local_id, update_type, success, NULL); + LLViewerStatsRecorder::instance()->recordObjectUpdateFailure(local_id, update_type); #endif continue; } @@ -543,8 +539,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, if (!objectp) { #if LL_RECORD_VIEWER_STATS - const BOOL success = FALSE; - stats_recorder.recordObjectUpdateEvent(regionp, local_id, update_type, success, NULL); + LLViewerStatsRecorder::instance()->recordObjectUpdateFailure(local_id, update_type); #endif continue; } @@ -584,13 +579,12 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, processUpdateCore(objectp, user_data, i, update_type, NULL, justCreated); } #if LL_RECORD_VIEWER_STATS - const BOOL success = TRUE; - stats_recorder.recordObjectUpdateEvent(regionp, local_id, update_type, success, objectp); + LLViewerStatsRecorder::instance()->recordObjectUpdateEvent(local_id, update_type, objectp); #endif } #if LL_RECORD_VIEWER_STATS - stats_recorder.closeObjectUpdateEvents(regionp); + LLViewerStatsRecorder::instance()->endObjectUpdateEvents(); #endif LLVOAvatar::cullAvatarsByPixelArea(); diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index ca07e7c4cf..da2373c39d 100644 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -59,6 +59,7 @@ #include "llurldispatcher.h" #include "llviewerobjectlist.h" #include "llviewerparceloverlay.h" +#include "llviewerstatsrecorder.h" #include "llvlmanager.h" #include "llvlcomposition.h" #include "llvocache.h" @@ -1074,7 +1075,7 @@ void LLViewerRegion::cacheFullUpdate(LLViewerObject* objectp, LLDataPackerBinary // Get data packer for this object, if we have cached data // AND the CRC matches. JC -LLDataPacker *LLViewerRegion::getDP(U32 local_id, U32 crc) +LLDataPacker *LLViewerRegion::getDP(U32 local_id, U32 crc, U8 &cache_miss_type) { llassert(mCacheLoaded); @@ -1087,17 +1088,20 @@ LLDataPacker *LLViewerRegion::getDP(U32 local_id, U32 crc) { // Record a hit entry->recordHit(); + cache_miss_type = CACHE_MISS_TYPE_NONE; return entry->getDP(crc); } else { // llinfos << "CRC miss for " << local_id << llendl; + cache_miss_type = CACHE_MISS_TYPE_CRC; mCacheMissCRC.put(local_id); } } else { // llinfos << "Cache miss for " << local_id << llendl; + cache_miss_type = CACHE_MISS_TYPE_FULL; mCacheMissFull.put(local_id); } return NULL; @@ -1119,9 +1123,6 @@ void LLViewerRegion::requestCacheMisses() S32 blocks = 0; S32 i; - const U8 CACHE_MISS_TYPE_FULL = 0; - const U8 CACHE_MISS_TYPE_CRC = 1; - // Send full cache miss updates. For these, we KNOW we don't // have a viewer object. for (i = 0; i < full_count; i++) @@ -1184,6 +1185,11 @@ void LLViewerRegion::requestCacheMisses() mCacheDirty = TRUE ; // llinfos << "KILLDEBUG Sent cache miss full " << full_count << " crc " << crc_count << llendl; + #if LL_RECORD_VIEWER_STATS + LLViewerStatsRecorder::instance()->beginObjectUpdateEvents(this); + LLViewerStatsRecorder::instance()->recordRequestCacheMissesEvent(full_count + crc_count); + LLViewerStatsRecorder::instance()->endObjectUpdateEvents(); + #endif } void LLViewerRegion::dumpCache() diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h index 8b71998f60..7fac2020ee 100644 --- a/indra/newview/llviewerregion.h +++ b/indra/newview/llviewerregion.h @@ -274,9 +274,16 @@ public: void getInfo(LLSD& info); + typedef enum + { + CACHE_MISS_TYPE_FULL = 0, + CACHE_MISS_TYPE_CRC, + CACHE_MISS_TYPE_NONE + } eCacheMissType; + // handle a full update message void cacheFullUpdate(LLViewerObject* objectp, LLDataPackerBinaryBuffer &dp); - LLDataPacker *getDP(U32 local_id, U32 crc); + LLDataPacker *getDP(U32 local_id, U32 crc, U8 &cache_miss_type); void requestCacheMisses(); void addCacheMissFull(const U32 local_id); diff --git a/indra/newview/llviewerstatsrecorder.cpp b/indra/newview/llviewerstatsrecorder.cpp index 1b80a2bc1c..27bbc17b36 100644 --- a/indra/newview/llviewerstatsrecorder.cpp +++ b/indra/newview/llviewerstatsrecorder.cpp @@ -30,43 +30,73 @@ #include "llviewerregion.h" #include "llviewerobject.h" + +// To do - something using region name or global position +#if LL_WINDOWS + static const std::string STATS_FILE_NAME("C:\\ViewerObjectCacheStats.csv"); +#else + static const std::string STATS_FILE_NAME("/tmp/viewerstats.csv"); +#endif + + +LLViewerStatsRecorder* LLViewerStatsRecorder::sInstance = NULL; LLViewerStatsRecorder::LLViewerStatsRecorder() : mObjectCacheFile(NULL), - mTimer() + mTimer(), + mRegionp(NULL), + mStartTime(0.f), + mProcessingTime(0.f) { - mStartTime = LLTimer::getTotalTime(); + if (NULL != sInstance) + { + llerrs << "Attempted to create multiple instances of LLViewerStatsRecorder!" << llendl; + } + sInstance = this; + clearStats(); } LLViewerStatsRecorder::~LLViewerStatsRecorder() { - LLFile::close(mObjectCacheFile); - mObjectCacheFile = NULL; + if (mObjectCacheFile != NULL) + { + LLFile::close(mObjectCacheFile); + mObjectCacheFile = NULL; + } } +// static +void LLViewerStatsRecorder::initClass() +{ + sInstance = new LLViewerStatsRecorder(); +} -void LLViewerStatsRecorder::initStatsRecorder(LLViewerRegion *regionp) +// static +void LLViewerStatsRecorder::cleanupClass() { - // To do - something using region name or global position -#if LL_WINDOWS - std::string stats_file_name("C:\\ViewerObjectCacheStats.csv"); -#else - std::string stats_file_name("/tmp/viewerstats.csv"); -#endif + delete sInstance; + sInstance = NULL; +} + +void LLViewerStatsRecorder::initStatsRecorder(LLViewerRegion *regionp) +{ if (mObjectCacheFile == NULL) { - mObjectCacheFile = LLFile::fopen(stats_file_name, "wb"); + mStartTime = LLTimer::getTotalTime(); + mObjectCacheFile = LLFile::fopen(STATS_FILE_NAME, "wb"); if (mObjectCacheFile) { // Write column headers std::ostringstream data_msg; data_msg << "EventTime, " << "ProcessingTime, " << "CacheHits, " - << "CacheMisses, " + << "CacheFullMisses, " + << "CacheCrcMisses, " << "FullUpdates, " << "TerseUpdates, " + << "CacheMissRequests, " << "CacheMissResponses, " - << "TotalUpdates " + << "UpdateFailures" << "\n"; fwrite(data_msg.str().c_str(), 1, data_msg.str().size(), mObjectCacheFile ); @@ -74,58 +104,83 @@ void LLViewerStatsRecorder::initStatsRecorder(LLViewerRegion *regionp) } } - -void LLViewerStatsRecorder::initObjectUpdateEvents(LLViewerRegion *regionp) +void LLViewerStatsRecorder::beginObjectUpdateEvents(LLViewerRegion *regionp) { initStatsRecorder(regionp); + mRegionp = regionp; + mProcessingTime = LLTimer::getTotalTime(); + clearStats(); +} + +void LLViewerStatsRecorder::clearStats() +{ mObjectCacheHitCount = 0; - mObjectCacheMissCount = 0; + mObjectCacheMissFullCount = 0; + mObjectCacheMissCrcCount = 0; mObjectFullUpdates = 0; mObjectTerseUpdates = 0; + mObjectCacheMissRequests = 0; mObjectCacheMissResponses = 0; - mProcessingTime = LLTimer::getTotalTime(); + mObjectUpdateFailures = 0; } -void LLViewerStatsRecorder::recordObjectUpdateEvent(LLViewerRegion *regionp, U32 local_id, const EObjectUpdateType update_type, BOOL success, LLViewerObject * objectp) +void LLViewerStatsRecorder::recordObjectUpdateFailure(U32 local_id, const EObjectUpdateType update_type) +{ + mObjectUpdateFailures++; +} + +void LLViewerStatsRecorder::recordCacheMissEvent(U32 local_id, const EObjectUpdateType update_type, U8 cache_miss_type) { - if (!objectp) + if (LLViewerRegion::CACHE_MISS_TYPE_FULL == cache_miss_type) { - // no object, must be a miss - mObjectCacheMissCount++; + mObjectCacheMissFullCount++; } else - { - switch (update_type) - { - case OUT_FULL: - mObjectFullUpdates++; - break; - case OUT_TERSE_IMPROVED: - mObjectTerseUpdates++; - break; - case OUT_FULL_COMPRESSED: - mObjectCacheMissResponses++; - break; - case OUT_FULL_CACHED: - default: - mObjectCacheHitCount++; - break; - }; + { + mObjectCacheMissCrcCount++; } } -void LLViewerStatsRecorder::closeObjectUpdateEvents(LLViewerRegion *regionp) +void LLViewerStatsRecorder::recordObjectUpdateEvent(U32 local_id, const EObjectUpdateType update_type, LLViewerObject * objectp) +{ + switch (update_type) + { + case OUT_FULL: + mObjectFullUpdates++; + break; + case OUT_TERSE_IMPROVED: + mObjectTerseUpdates++; + break; + case OUT_FULL_COMPRESSED: + mObjectCacheMissResponses++; + break; + case OUT_FULL_CACHED: + default: + mObjectCacheHitCount++; + break; + }; +} + +void LLViewerStatsRecorder::recordRequestCacheMissesEvent(S32 count) +{ + mObjectCacheMissRequests += count; +} + +void LLViewerStatsRecorder::endObjectUpdateEvents() { llinfos << "ILX: " << mObjectCacheHitCount << " hits, " - << mObjectCacheMissCount << " misses, " + << mObjectCacheMissFullCount << " full misses, " + << mObjectCacheMissCrcCount << " crc misses, " << mObjectFullUpdates << " full updates, " << mObjectTerseUpdates << " terse updates, " - << mObjectCacheMissResponses << " cache miss responses" + << mObjectCacheMissRequests << " cache miss requests, " + << mObjectCacheMissResponses << " cache miss responses, " + << mObjectUpdateFailures << " update failures" << llendl; - S32 total_objects = mObjectCacheHitCount + mObjectCacheMissCount + mObjectFullUpdates + mObjectTerseUpdates + mObjectCacheMissResponses;; + S32 total_objects = mObjectCacheHitCount + mObjectCacheMissCrcCount + mObjectCacheMissFullCount + mObjectFullUpdates + mObjectTerseUpdates + mObjectCacheMissRequests + mObjectCacheMissResponses + mObjectUpdateFailures; if (mObjectCacheFile != NULL && total_objects > 0) { @@ -136,18 +191,19 @@ void LLViewerStatsRecorder::closeObjectUpdateEvents(LLViewerRegion *regionp) data_msg << now32 << ", " << processing32 << ", " << mObjectCacheHitCount - << ", " << mObjectCacheMissCount + << ", " << mObjectCacheMissFullCount + << ", " << mObjectCacheMissCrcCount << ", " << mObjectFullUpdates << ", " << mObjectTerseUpdates + << ", " << mObjectCacheMissRequests << ", " << mObjectCacheMissResponses - << ", " << total_objects + << ", " << mObjectUpdateFailures << "\n"; fwrite(data_msg.str().c_str(), 1, data_msg.str().size(), mObjectCacheFile ); } - mObjectCacheHitCount = 0; - mObjectCacheMissCount = 0; + clearStats(); } diff --git a/indra/newview/llviewerstatsrecorder.h b/indra/newview/llviewerstatsrecorder.h index 213d15f963..001b8d9bd6 100644 --- a/indra/newview/llviewerstatsrecorder.h +++ b/indra/newview/llviewerstatsrecorder.h @@ -39,6 +39,7 @@ #include "llframetimer.h" #include "llviewerobject.h" +class LLMutex; class LLViewerRegion; class LLViewerObject; @@ -48,24 +49,41 @@ class LLViewerStatsRecorder LLViewerStatsRecorder(); ~LLViewerStatsRecorder(); + static void initClass(); + static void cleanupClass(); + static LLViewerStatsRecorder* instance() {return sInstance; } + void initStatsRecorder(LLViewerRegion *regionp); - void initObjectUpdateEvents(LLViewerRegion *regionp); - void recordObjectUpdateEvent(LLViewerRegion *regionp, U32 local_id, const EObjectUpdateType update_type, BOOL success, LLViewerObject * objectp); - void closeObjectUpdateEvents(LLViewerRegion *regionp); + void beginObjectUpdateEvents(LLViewerRegion *regionp); + void recordObjectUpdateFailure(U32 local_id, const EObjectUpdateType update_type); + void recordCacheMissEvent(U32 local_id, const EObjectUpdateType update_type, U8 cache_miss_type); + void recordObjectUpdateEvent(U32 local_id, const EObjectUpdateType update_type, LLViewerObject * objectp); + void recordRequestCacheMissesEvent(S32 count); + void endObjectUpdateEvents(); private: - LLFrameTimer mTimer; - F64 mStartTime; - F64 mProcessingTime; - - LLFILE * mObjectCacheFile; // File to write data into - S32 mObjectCacheHitCount; - S32 mObjectCacheMissCount; - S32 mObjectFullUpdates; - S32 mObjectTerseUpdates; - S32 mObjectCacheMissResponses; + static LLViewerStatsRecorder* sInstance; + + LLFILE * mObjectCacheFile; // File to write data into + LLFrameTimer mTimer; + LLViewerRegion* mRegionp; + F64 mStartTime; + F64 mProcessingTime; + + S32 mObjectCacheHitCount; + S32 mObjectCacheMissFullCount; + S32 mObjectCacheMissCrcCount; + S32 mObjectFullUpdates; + S32 mObjectTerseUpdates; + S32 mObjectCacheMissRequests; + S32 mObjectCacheMissResponses; + S32 mObjectUpdateFailures; + + + void clearStats(); }; #endif // LL_RECORD_VIEWER_STATS #endif // LLVIEWERSTATSRECORDER_H + -- cgit v1.2.3 From b71b9ee08e0b59274346a3b4da2c33ff84a5eb90 Mon Sep 17 00:00:00 2001 From: Don Kjer Date: Mon, 13 Dec 2010 16:15:25 -0800 Subject: Added object update cache results to viewer stats recorder --- indra/newview/llviewerobjectlist.cpp | 12 ++++++--- indra/newview/llviewerregion.cpp | 9 +++++-- indra/newview/llviewerregion.h | 10 +++++++- indra/newview/llviewerstatsrecorder.cpp | 44 +++++++++++++++++++++++++++++++-- indra/newview/llviewerstatsrecorder.h | 6 +++++ 5 files changed, 72 insertions(+), 9 deletions(-) diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp index 249799bf55..64949ecc44 100644 --- a/indra/newview/llviewerobjectlist.cpp +++ b/indra/newview/llviewerobjectlist.cpp @@ -500,7 +500,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, { if (update_type == OUT_TERSE_IMPROVED) { - // llinfos << "terse update for an unknown object:" << fullid << llendl; + llinfos << "terse update for an unknown object (compressed):" << fullid << llendl; #if LL_RECORD_VIEWER_STATS LLViewerStatsRecorder::instance()->recordObjectUpdateFailure(local_id, update_type); #endif @@ -514,7 +514,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, { if (update_type != OUT_FULL) { - // llinfos << "terse update for an unknown object:" << fullid << llendl; + llinfos << "terse update for an unknown object:" << fullid << llendl; #if LL_RECORD_VIEWER_STATS LLViewerStatsRecorder::instance()->recordObjectUpdateFailure(local_id, update_type); #endif @@ -527,7 +527,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, if (mDeadObjects.find(fullid) != mDeadObjects.end()) { mNumDeadObjectUpdates++; - // llinfos << "update for a dead object:" << fullid << llendl; + llinfos << "update for a dead object:" << fullid << llendl; #if LL_RECORD_VIEWER_STATS LLViewerStatsRecorder::instance()->recordObjectUpdateFailure(local_id, update_type); #endif @@ -538,6 +538,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, objectp = createObject(pcode, regionp, fullid, local_id, gMessageSystem->getSender()); if (!objectp) { + llinfos << "createObject failure for object: " << fullid << llendl; #if LL_RECORD_VIEWER_STATS LLViewerStatsRecorder::instance()->recordObjectUpdateFailure(local_id, update_type); #endif @@ -562,7 +563,10 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, processUpdateCore(objectp, user_data, i, update_type, &compressed_dp, justCreated); if (update_type != OUT_TERSE_IMPROVED) // OUT_FULL_COMPRESSED only? { - objectp->mRegionp->cacheFullUpdate(objectp, compressed_dp); + LLViewerRegion::eCacheUpdateResult result = objectp->mRegionp->cacheFullUpdate(objectp, compressed_dp); + #if LL_RECORD_VIEWER_STATS + LLViewerStatsRecorder::instance()->recordCacheFullUpdate(local_id, update_type, result, objectp); + #endif } } else if (cached) // Cache hit only? diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index da2373c39d..ea6f1ab342 100644 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -1033,7 +1033,7 @@ void LLViewerRegion::getInfo(LLSD& info) info["Region"]["Handle"]["y"] = (LLSD::Integer)y; } -void LLViewerRegion::cacheFullUpdate(LLViewerObject* objectp, LLDataPackerBinaryBuffer &dp) +LLViewerRegion::eCacheUpdateResult LLViewerRegion::cacheFullUpdate(LLViewerObject* objectp, LLDataPackerBinaryBuffer &dp) { U32 local_id = objectp->getLocalID(); U32 crc = objectp->getCRC(); @@ -1047,6 +1047,7 @@ void LLViewerRegion::cacheFullUpdate(LLViewerObject* objectp, LLDataPackerBinary { // Record a hit entry->recordDupe(); + return CACHE_UPDATE_DUPE; } else { @@ -1055,6 +1056,7 @@ void LLViewerRegion::cacheFullUpdate(LLViewerObject* objectp, LLDataPackerBinary delete entry; entry = new LLVOCacheEntry(local_id, crc, dp); mCacheMap[local_id] = entry; + return CACHE_UPDATE_CHANGED; } } else @@ -1062,15 +1064,18 @@ void LLViewerRegion::cacheFullUpdate(LLViewerObject* objectp, LLDataPackerBinary // we haven't seen this object before // Create new entry and add to map + eCacheUpdateResult result = CACHE_UPDATE_ADDED; if (mCacheMap.size() > MAX_OBJECT_CACHE_ENTRIES) { mCacheMap.erase(mCacheMap.begin()); + result = CACHE_UPDATE_REPLACED; + } entry = new LLVOCacheEntry(local_id, crc, dp); mCacheMap[local_id] = entry; + return result; } - return ; } // Get data packer for this object, if we have cached data diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h index 7fac2020ee..5e17f3352d 100644 --- a/indra/newview/llviewerregion.h +++ b/indra/newview/llviewerregion.h @@ -281,8 +281,16 @@ public: CACHE_MISS_TYPE_NONE } eCacheMissType; + typedef enum + { + CACHE_UPDATE_DUPE = 0, + CACHE_UPDATE_CHANGED, + CACHE_UPDATE_ADDED, + CACHE_UPDATE_REPLACED + } eCacheUpdateResult; + // handle a full update message - void cacheFullUpdate(LLViewerObject* objectp, LLDataPackerBinaryBuffer &dp); + eCacheUpdateResult cacheFullUpdate(LLViewerObject* objectp, LLDataPackerBinaryBuffer &dp); LLDataPacker *getDP(U32 local_id, U32 crc, U8 &cache_miss_type); void requestCacheMisses(); void addCacheMissFull(const U32 local_id); diff --git a/indra/newview/llviewerstatsrecorder.cpp b/indra/newview/llviewerstatsrecorder.cpp index 27bbc17b36..b6ef260b6a 100644 --- a/indra/newview/llviewerstatsrecorder.cpp +++ b/indra/newview/llviewerstatsrecorder.cpp @@ -96,6 +96,10 @@ void LLViewerStatsRecorder::initStatsRecorder(LLViewerRegion *regionp) << "TerseUpdates, " << "CacheMissRequests, " << "CacheMissResponses, " + << "CacheUpdateDupes, " + << "CacheUpdateChanges, " + << "CacheUpdateAdds, " + << "CacheUpdateReplacements, " << "UpdateFailures" << "\n"; @@ -121,6 +125,10 @@ void LLViewerStatsRecorder::clearStats() mObjectTerseUpdates = 0; mObjectCacheMissRequests = 0; mObjectCacheMissResponses = 0; + mObjectCacheUpdateDupes = 0; + mObjectCacheUpdateChanges = 0; + mObjectCacheUpdateAdds = 0; + mObjectCacheUpdateReplacements = 0; mObjectUpdateFailures = 0; } @@ -156,9 +164,33 @@ void LLViewerStatsRecorder::recordObjectUpdateEvent(U32 local_id, const EObjectU mObjectCacheMissResponses++; break; case OUT_FULL_CACHED: - default: mObjectCacheHitCount++; break; + default: + llwarns << "Unknown update_type" << llendl; + break; + }; +} + +void LLViewerStatsRecorder::recordCacheFullUpdate(U32 local_id, const EObjectUpdateType update_type, LLViewerRegion::eCacheUpdateResult update_result, LLViewerObject* objectp) +{ + switch (update_result) + { + case LLViewerRegion::CACHE_UPDATE_DUPE: + mObjectCacheUpdateDupes++; + break; + case LLViewerRegion::CACHE_UPDATE_CHANGED: + mObjectCacheUpdateChanges++; + break; + case LLViewerRegion::CACHE_UPDATE_ADDED: + mObjectCacheUpdateAdds++; + break; + case LLViewerRegion::CACHE_UPDATE_REPLACED: + mObjectCacheUpdateReplacements++; + break; + default: + llwarns << "Unknown update_result type" << llendl; + break; }; } @@ -177,10 +209,14 @@ void LLViewerStatsRecorder::endObjectUpdateEvents() << mObjectTerseUpdates << " terse updates, " << mObjectCacheMissRequests << " cache miss requests, " << mObjectCacheMissResponses << " cache miss responses, " + << mObjectCacheUpdateDupes << " cache update dupes, " + << mObjectCacheUpdateChanges << " cache update changes, " + << mObjectCacheUpdateAdds << " cache update adds, " + << mObjectCacheUpdateReplacements << " cache update replacements, " << mObjectUpdateFailures << " update failures" << llendl; - S32 total_objects = mObjectCacheHitCount + mObjectCacheMissCrcCount + mObjectCacheMissFullCount + mObjectFullUpdates + mObjectTerseUpdates + mObjectCacheMissRequests + mObjectCacheMissResponses + mObjectUpdateFailures; + S32 total_objects = mObjectCacheHitCount + mObjectCacheMissCrcCount + mObjectCacheMissFullCount + mObjectFullUpdates + mObjectTerseUpdates + mObjectCacheMissRequests + mObjectCacheMissResponses + mObjectCacheUpdateDupes + mObjectCacheUpdateChanges + mObjectCacheUpdateAdds + mObjectCacheUpdateReplacements + mObjectUpdateFailures; if (mObjectCacheFile != NULL && total_objects > 0) { @@ -197,6 +233,10 @@ void LLViewerStatsRecorder::endObjectUpdateEvents() << ", " << mObjectTerseUpdates << ", " << mObjectCacheMissRequests << ", " << mObjectCacheMissResponses + << ", " << mObjectCacheUpdateDupes + << ", " << mObjectCacheUpdateChanges + << ", " << mObjectCacheUpdateAdds + << ", " << mObjectCacheUpdateReplacements << ", " << mObjectUpdateFailures << "\n"; diff --git a/indra/newview/llviewerstatsrecorder.h b/indra/newview/llviewerstatsrecorder.h index 001b8d9bd6..16e04fb11e 100644 --- a/indra/newview/llviewerstatsrecorder.h +++ b/indra/newview/llviewerstatsrecorder.h @@ -38,6 +38,7 @@ #if LL_RECORD_VIEWER_STATS #include "llframetimer.h" #include "llviewerobject.h" +#include "llviewerregion.h" class LLMutex; class LLViewerRegion; @@ -59,6 +60,7 @@ class LLViewerStatsRecorder void recordObjectUpdateFailure(U32 local_id, const EObjectUpdateType update_type); void recordCacheMissEvent(U32 local_id, const EObjectUpdateType update_type, U8 cache_miss_type); void recordObjectUpdateEvent(U32 local_id, const EObjectUpdateType update_type, LLViewerObject * objectp); + void recordCacheFullUpdate(U32 local_id, const EObjectUpdateType update_type, LLViewerRegion::eCacheUpdateResult update_result, LLViewerObject* objectp); void recordRequestCacheMissesEvent(S32 count); void endObjectUpdateEvents(); @@ -78,6 +80,10 @@ private: S32 mObjectTerseUpdates; S32 mObjectCacheMissRequests; S32 mObjectCacheMissResponses; + S32 mObjectCacheUpdateDupes; + S32 mObjectCacheUpdateChanges; + S32 mObjectCacheUpdateAdds; + S32 mObjectCacheUpdateReplacements; S32 mObjectUpdateFailures; -- cgit v1.2.3 From 01c13c3b9403991c04166f6ac57c93aaf5f17f83 Mon Sep 17 00:00:00 2001 From: Don Kjer Date: Mon, 13 Dec 2010 18:29:31 -0800 Subject: Added in-world color coding to objects based on update type --- indra/newview/llviewerobjectlist.cpp | 32 ++++++++++++++++++++++++++++++++ indra/newview/llviewerstatsrecorder.cpp | 7 +++++-- indra/newview/llviewerstatsrecorder.h | 2 ++ 3 files changed, 39 insertions(+), 2 deletions(-) diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp index 64949ecc44..285f067b0e 100644 --- a/indra/newview/llviewerobjectlist.cpp +++ b/indra/newview/llviewerobjectlist.cpp @@ -554,6 +554,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, llwarns << "Dead object " << objectp->mID << " in UUID map 1!" << llendl; } + bool bCached = false; if (compressed) { if (update_type != OUT_TERSE_IMPROVED) // OUT_FULL_COMPRESSED only? @@ -564,6 +565,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, if (update_type != OUT_TERSE_IMPROVED) // OUT_FULL_COMPRESSED only? { LLViewerRegion::eCacheUpdateResult result = objectp->mRegionp->cacheFullUpdate(objectp, compressed_dp); + bCached = true; #if LL_RECORD_VIEWER_STATS LLViewerStatsRecorder::instance()->recordCacheFullUpdate(local_id, update_type, result, objectp); #endif @@ -584,6 +586,36 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, } #if LL_RECORD_VIEWER_STATS LLViewerStatsRecorder::instance()->recordObjectUpdateEvent(local_id, update_type, objectp); + F32 color_strength = llmin((LLViewerStatsRecorder::instance()->getTimeSinceStart() / 1000.0f) + 64.0f, 255.0f); + LLColor4 color; + switch (update_type) + { + case OUT_FULL: + color[VGREEN] = color_strength; + break; + case OUT_TERSE_IMPROVED: + color[VGREEN] = color_strength; + color[VBLUE] = color_strength; + break; + case OUT_FULL_COMPRESSED: + color[VRED] = color_strength; + if (!bCached) + { + color[VGREEN] = color_strength; + } + break; + case OUT_FULL_CACHED: + color[VBLUE] = color_strength; + break; + default: + llwarns << "Unknown update_type " << update_type << llendl; + break; + }; + U8 te; + for (te = 0; te < objectp->getNumTEs(); ++te) + { + objectp->setTEColor(te, color); + } #endif } diff --git a/indra/newview/llviewerstatsrecorder.cpp b/indra/newview/llviewerstatsrecorder.cpp index b6ef260b6a..a8d1565742 100644 --- a/indra/newview/llviewerstatsrecorder.cpp +++ b/indra/newview/llviewerstatsrecorder.cpp @@ -221,10 +221,9 @@ void LLViewerStatsRecorder::endObjectUpdateEvents() total_objects > 0) { std::ostringstream data_msg; - F32 now32 = (F32) ((LLTimer::getTotalTime() - mStartTime) / 1000.0); F32 processing32 = (F32) ((LLTimer::getTotalTime() - mProcessingTime) / 1000.0); - data_msg << now32 + data_msg << getTimeSinceStart() << ", " << processing32 << ", " << mObjectCacheHitCount << ", " << mObjectCacheMissFullCount @@ -246,5 +245,9 @@ void LLViewerStatsRecorder::endObjectUpdateEvents() clearStats(); } +F32 LLViewerStatsRecorder::getTimeSinceStart() +{ + return (F32) ((LLTimer::getTotalTime() - mStartTime) / 1000.0); +} diff --git a/indra/newview/llviewerstatsrecorder.h b/indra/newview/llviewerstatsrecorder.h index 16e04fb11e..f9ccdd6e78 100644 --- a/indra/newview/llviewerstatsrecorder.h +++ b/indra/newview/llviewerstatsrecorder.h @@ -64,6 +64,8 @@ class LLViewerStatsRecorder void recordRequestCacheMissesEvent(S32 count); void endObjectUpdateEvents(); + F32 getTimeSinceStart(); + private: static LLViewerStatsRecorder* sInstance; -- cgit v1.2.3 From dc75235e38e3f2d74476607e6196b26d36955619 Mon Sep 17 00:00:00 2001 From: Xiaohong Bao Date: Mon, 13 Dec 2010 21:09:52 -0700 Subject: debug code for SH-639: http requests 3X more in viewer 2.4 --- indra/newview/lltexturefetch.cpp | 13 ++++++++++++- indra/newview/lltexturefetch.h | 4 ++++ indra/newview/lltextureview.cpp | 5 +++-- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp index d6d38de225..c1346b6768 100644 --- a/indra/newview/lltexturefetch.cpp +++ b/indra/newview/lltexturefetch.cpp @@ -862,7 +862,7 @@ bool LLTextureFetchWorker::doWork(S32 param) //1, not openning too many file descriptors at the same time; //2, control the traffic of http so udp gets bandwidth. // - static const S32 MAX_NUM_OF_HTTP_REQUESTS_IN_QUEUE = 32 ; + static const S32 MAX_NUM_OF_HTTP_REQUESTS_IN_QUEUE = 8 ; if(mFetcher->getNumHTTPRequests() > MAX_NUM_OF_HTTP_REQUESTS_IN_QUEUE) { return false ; //wait. @@ -1535,6 +1535,7 @@ LLTextureFetch::LLTextureFetch(LLTextureCache* cache, LLImageDecodeThread* image mImageDecodeThread(imagedecodethread), mTextureBandwidth(0), mHTTPTextureBits(0), + mTotalHTTPRequests(0), mCurlGetRequest(NULL) { mMaxBandwidth = gSavedSettings.getF32("ThrottleBandwidthKBPS"); @@ -1678,6 +1679,7 @@ void LLTextureFetch::addToHTTPQueue(const LLUUID& id) { LLMutexLock lock(&mNetworkQueueMutex); mHTTPTextureQueue.insert(id); + mTotalHTTPRequests++; } void LLTextureFetch::removeFromHTTPQueue(const LLUUID& id, S32 received_size) @@ -1740,6 +1742,15 @@ S32 LLTextureFetch::getNumHTTPRequests() return size ; } +U32 LLTextureFetch::getTotalNumHTTPRequests() +{ + mNetworkQueueMutex.lock() ; + U32 size = mTotalHTTPRequests ; + mNetworkQueueMutex.unlock() ; + + return size ; +} + // call lockQueue() first! LLTextureFetchWorker* LLTextureFetch::getWorkerAfterLock(const LLUUID& id) { diff --git a/indra/newview/lltexturefetch.h b/indra/newview/lltexturefetch.h index 796109df06..d25031666b 100644 --- a/indra/newview/lltexturefetch.h +++ b/indra/newview/lltexturefetch.h @@ -75,6 +75,7 @@ public: void dump(); S32 getNumRequests() ; S32 getNumHTTPRequests() ; + U32 getTotalNumHTTPRequests() ; // Public for access by callbacks void lockQueue() { mQueueMutex.lock(); } @@ -129,6 +130,9 @@ private: LLTextureInfo mTextureInfo; U32 mHTTPTextureBits; + + //debug use + U32 mTotalHTTPRequests ; }; #endif // LL_LLTEXTUREFETCH_H diff --git a/indra/newview/lltextureview.cpp b/indra/newview/lltextureview.cpp index b9a15fd1f4..0115115a23 100644 --- a/indra/newview/lltextureview.cpp +++ b/indra/newview/lltextureview.cpp @@ -516,6 +516,7 @@ void LLGLTexMemBar::draw() S32 v_offset = (S32)((texture_bar_height + 2.2f) * mTextureView->mNumTextureBars + 2.0f); F32 total_texture_downloaded = (F32)gTotalTextureBytes / (1024 * 1024); F32 total_object_downloaded = (F32)gTotalObjectBytes / (1024 * 1024); + U32 total_http_requests = LLAppViewer::getTextureFetch()->getTotalNumHTTPRequests() ; //---------------------------------------------------------------------------- LLGLSUIDefault gls_ui; LLColor4 text_color(1.f, 1.f, 1.f, 0.75f); @@ -526,13 +527,13 @@ void LLGLTexMemBar::draw() LLFontGL::getFontMonospace()->renderUTF8(text, 0, 0, v_offset + line_height*6, text_color, LLFontGL::LEFT, LLFontGL::TOP); - text = llformat("GL Tot: %d/%d MB Bound: %d/%d MB Raw Tot: %d MB Bias: %.2f Cache: %.1f/%.1f MB Net Tot Tex: %.1f MB Tot Obj: %.1f MB", + text = llformat("GL Tot: %d/%d MB Bound: %d/%d MB Raw Tot: %d MB Bias: %.2f Cache: %.1f/%.1f MB Net Tot Tex: %.1f MB Tot Obj: %.1f MB Tot Htp: %d", total_mem, max_total_mem, bound_mem, max_bound_mem, LLImageRaw::sGlobalRawMemory >> 20, discard_bias, - cache_usage, cache_max_usage, total_texture_downloaded, total_object_downloaded); + cache_usage, cache_max_usage, total_texture_downloaded, total_object_downloaded, total_http_requests); //, cache_entries, cache_max_entries LLFontGL::getFontMonospace()->renderUTF8(text, 0, 0, v_offset + line_height*3, -- cgit v1.2.3 From 64512b681e2f5582378d9943642a82c83cae30ac Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 14 Dec 2010 08:52:33 -0800 Subject: ER-398 viewer's encroachment logic only uses bounding box of root prim Adding LLBBox::join() to allow us to compute the bounding box of a linked object --- indra/llmath/llbbox.cpp | 13 +++++++++++++ indra/llmath/llbbox.h | 5 ++++- indra/newview/llviewerobject.cpp | 12 ++++++++++-- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/indra/llmath/llbbox.cpp b/indra/llmath/llbbox.cpp index 72c906b5ca..67a305d269 100644 --- a/indra/llmath/llbbox.cpp +++ b/indra/llmath/llbbox.cpp @@ -102,6 +102,19 @@ LLBBox LLBBox::getAxisAligned() const return aligned; } +// Increases the size to contain other_box +void LLBBox::join(const LLBBox& other_box) +{ + LLVector3 other_min = (other_box.mPosAgent - mPosAgent) - other_box.mMinLocal; + mMinLocal.mV[VX] = llmin( other_min.mV[VX], mMinLocal.mV[VX] ); + mMinLocal.mV[VY] = llmin( other_min.mV[VY], mMinLocal.mV[VY] ); + mMinLocal.mV[VZ] = llmin( other_min.mV[VZ], mMinLocal.mV[VZ] ); + + LLVector3 other_max = (other_box.mPosAgent - mPosAgent) + other_box.mMaxLocal; + mMaxLocal.mV[VX] = llmax( other_max.mV[VX], mMaxLocal.mV[VX] ); + mMaxLocal.mV[VY] = llmax( other_max.mV[VY], mMaxLocal.mV[VY] ); + mMaxLocal.mV[VZ] = llmax( other_max.mV[VZ], mMaxLocal.mV[VZ] ); +} void LLBBox::expand( F32 delta ) diff --git a/indra/llmath/llbbox.h b/indra/llmath/llbbox.h index a0d434b051..8616320381 100644 --- a/indra/llmath/llbbox.h +++ b/indra/llmath/llbbox.h @@ -83,7 +83,10 @@ public: LLVector3 agentToLocalBasis(const LLVector3& v) const; // Get the smallest possible axis aligned bbox that contains this bbox - LLBBox getAxisAligned() const; + LLBBox getAxisAligned() const; + + // Increases the size to contain other_box + void join(const LLBBox& other_box); // friend LLBBox operator*(const LLBBox& a, const LLMatrix4& b); diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index df89e6759d..15207e7346 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -518,10 +518,18 @@ void LLViewerObject::setNameValueList(const std::string& name_value_list) // agent. bool LLViewerObject::isReturnable() { - LLBBox box_in_region_frame(getPositionRegion(), getRotationRegion(), getScale() * -0.5f, getScale() * 0.5f); + LLBBox bounding_box(getPositionRegion(), getRotationRegion(), getScale() * -0.5f, getScale() * 0.5f); + for (child_list_t::iterator iter = mChildList.begin(); + iter != mChildList.end(); iter++) + { + LLViewerObject* child = *iter; + LLBBox child_box(child->getPositionRegion(), child->getRotationRegion(), child->getScale() * -0.5f, child->getScale() * 0.5f); + bounding_box.join(child_box); + } + return !isAttachment() && mRegionp - && mRegionp->objectIsReturnable(getPositionRegion(), box_in_region_frame); + && mRegionp->objectIsReturnable(getPositionRegion(), bounding_box); } BOOL LLViewerObject::setParent(LLViewerObject* parent) -- cgit v1.2.3 From da244c7cce6b3d84b011a87cbcabffb51abb3fc8 Mon Sep 17 00:00:00 2001 From: Xiaohong Bao Date: Tue, 14 Dec 2010 12:16:39 -0700 Subject: a try fix for SH-212: crash at LLViewerObjectList::removeFromLocalIDTable(LLViewerObject const &) [secondlife-bin llviewerobjectlist.cpp] line 173 --- indra/newview/llcapabilityprovider.h | 2 +- indra/newview/llviewerobjectlist.cpp | 22 ++++++++-------------- indra/newview/llviewerobjectlist.h | 2 +- indra/newview/llviewerregion.cpp | 6 ++++++ indra/newview/llviewerregion.h | 2 +- 5 files changed, 17 insertions(+), 17 deletions(-) diff --git a/indra/newview/llcapabilityprovider.h b/indra/newview/llcapabilityprovider.h index a6e743f625..9d91245597 100644 --- a/indra/newview/llcapabilityprovider.h +++ b/indra/newview/llcapabilityprovider.h @@ -46,7 +46,7 @@ public: /** * Get host to which to send that capability request. */ - virtual LLHost getHost() const = 0; + virtual const LLHost& getHost() const = 0; /** * Describe this LLCapabilityProvider for logging etc. */ diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp index f9bf0543c4..8d5015fd51 100644 --- a/indra/newview/llviewerobjectlist.cpp +++ b/indra/newview/llviewerobjectlist.cpp @@ -159,19 +159,13 @@ U64 LLViewerObjectList::getIndex(const U32 local_id, return (((U64)index) << 32) | (U64)local_id; } -BOOL LLViewerObjectList::removeFromLocalIDTable(const LLViewerObject &object) +BOOL LLViewerObjectList::removeFromLocalIDTable(const LLViewerObject* objectp) { - if(object.getRegion()) + if(objectp && objectp->getRegion()) { - U32 local_id = object.mLocalID; - LLHost region_host = object.getRegion()->getHost(); - if(!region_host.isOk()) - { - return FALSE ; - } - - U32 ip = region_host.getAddress(); - U32 port = region_host.getPort(); + U32 local_id = objectp->mLocalID; + U32 ip = objectp->getRegion()->getHost().getAddress(); + U32 port = objectp->getRegion()->getHost().getPort(); U64 ipport = (((U64)ip) << 32) | (U64)port; U32 index = sIPAndPortToIndex[ipport]; @@ -186,7 +180,7 @@ BOOL LLViewerObjectList::removeFromLocalIDTable(const LLViewerObject &object) } // Found existing entry - if (iter->second == object.getID()) + if (iter->second == objectp->getID()) { // Full UUIDs match, so remove the entry sIndexAndLocalIDToUUID.erase(iter); return TRUE; @@ -460,7 +454,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, // << ", regionp " << (U32) regionp << ", object region " << (U32) objectp->getRegion() // << llendl; //} - removeFromLocalIDTable(*objectp); + removeFromLocalIDTable(objectp); setUUIDAndLocal(fullid, local_id, gMessageSystem->getSenderIP(), @@ -849,7 +843,7 @@ void LLViewerObjectList::cleanupReferences(LLViewerObject *objectp) // << objectp->getRegion()->getHost().getPort() << llendl; //} - removeFromLocalIDTable(*objectp); + removeFromLocalIDTable(objectp); if (objectp->onActiveList()) { diff --git a/indra/newview/llviewerobjectlist.h b/indra/newview/llviewerobjectlist.h index eba5584b57..14e5d78839 100644 --- a/indra/newview/llviewerobjectlist.h +++ b/indra/newview/llviewerobjectlist.h @@ -161,7 +161,7 @@ public: const U32 ip, const U32 port); // Requires knowledge of message system info! - static BOOL removeFromLocalIDTable(const LLViewerObject &object); + static BOOL removeFromLocalIDTable(const LLViewerObject* objectp); // Used ONLY by the orphaned object code. static U64 getIndex(const U32 local_id, const U32 ip, const U32 port); diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index b684206960..e4dcfa1126 100644 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -321,6 +321,12 @@ LLViewerRegion::~LLViewerRegion() std::for_each(mObjectPartition.begin(), mObjectPartition.end(), DeletePointer()); } +/*virtual*/ +const LLHost& LLViewerRegion::getHost() const +{ + return mHost; +} + void LLViewerRegion::loadObjectCache() { if (mCacheLoaded) diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h index 8b71998f60..49ee061b71 100644 --- a/indra/newview/llviewerregion.h +++ b/indra/newview/llviewerregion.h @@ -244,7 +244,7 @@ public: LLEventPump& getCapAPI() { return mCapabilityListener.getCapAPI(); } /// implements LLCapabilityProvider - virtual LLHost getHost() const { return mHost; } + /*virtual*/ const LLHost& getHost() const; const U64 &getHandle() const { return mHandle; } LLSurface &getLand() const { return *mLandp; } -- cgit v1.2.3 From 2938086cdc8668913181ae4072866ae2993e0375 Mon Sep 17 00:00:00 2001 From: Don Kjer Date: Tue, 14 Dec 2010 15:56:09 -0800 Subject: Simple fix for color strength of viewer update goggles. --- indra/newview/llviewerobjectlist.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp index 285f067b0e..70631f9481 100644 --- a/indra/newview/llviewerobjectlist.cpp +++ b/indra/newview/llviewerobjectlist.cpp @@ -586,7 +586,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, } #if LL_RECORD_VIEWER_STATS LLViewerStatsRecorder::instance()->recordObjectUpdateEvent(local_id, update_type, objectp); - F32 color_strength = llmin((LLViewerStatsRecorder::instance()->getTimeSinceStart() / 1000.0f) + 64.0f, 255.0f); + F32 color_strength = llmin(((LLViewerStatsRecorder::instance()->getTimeSinceStart() / 1000.0f) + 128.0f) / 255.0f, 1.0f); LLColor4 color; switch (update_type) { -- cgit v1.2.3 From c3958f75d2ef6c998d99e8e97e76e4de0468ecef Mon Sep 17 00:00:00 2001 From: Don Kjer Date: Tue, 14 Dec 2010 23:56:35 -0800 Subject: First pass at fix for ER-401: Fix object cache header on the viewer --- indra/newview/llvocache.cpp | 162 +++++++++++++++++++++++++++----------------- indra/newview/llvocache.h | 9 +-- 2 files changed, 106 insertions(+), 65 deletions(-) diff --git a/indra/newview/llvocache.cpp b/indra/newview/llvocache.cpp index 145ee31260..6ea88abab8 100644 --- a/indra/newview/llvocache.cpp +++ b/indra/newview/llvocache.cpp @@ -40,6 +40,7 @@ BOOL check_write(LLAPRFile* apr_file, void* src, S32 n_bytes) return apr_file->write(src, n_bytes) == n_bytes ; } + //--------------------------------------------------------------------------- // LLVOCacheEntry //--------------------------------------------------------------------------- @@ -212,8 +213,8 @@ BOOL LLVOCacheEntry::writeToFile(LLAPRFile* apr_file) const if(success) { success = check_write(apr_file, (void*)mBuffer, size); + } } -} return success ; } @@ -224,7 +225,7 @@ BOOL LLVOCacheEntry::writeToFile(LLAPRFile* apr_file) const // Format string used to construct filename for the object cache static const char OBJECT_CACHE_FILENAME[] = "objects_%d_%d.slc"; -const U32 NUM_ENTRIES_TO_PURGE = 16 ; +const U32 NUM_ENTRIES_TO_PURGE = 50; const char* object_cache_dirname = "objectcache"; const char* header_filename = "object.cache"; @@ -259,7 +260,6 @@ void LLVOCache::destroyClass() LLVOCache::LLVOCache(): mInitialized(FALSE), mReadOnly(TRUE), - mNumEntries(0), mCacheSize(1) { mEnabled = gSavedSettings.getBOOL("ObjectCacheEnabled"); @@ -286,8 +286,15 @@ void LLVOCache::setDirNames(ELLPath location) void LLVOCache::initCache(ELLPath location, U32 size, U32 cache_version) { - if(mInitialized || !mEnabled) + if(!mEnabled) + { + llwarns << "Not initializing cache: Cache is currently disabled." << llendl; + return ; + } + + if(mInitialized) { + llwarns << "Cache already initialized." << llendl; return ; } @@ -321,6 +328,7 @@ void LLVOCache::removeCache(ELLPath location) { if(mReadOnly) { + llwarns << "Not removing cache at " << location << ": Cache is currently in read-only mode." << llendl; return ; } @@ -339,6 +347,7 @@ void LLVOCache::removeCache() llassert_always(mInitialized) ; if(mReadOnly) { + llwarns << "Not clearing object cache: Cache is currently in read-only mode." << llendl; return ; } @@ -352,16 +361,8 @@ void LLVOCache::removeCache() void LLVOCache::clearCacheInMemory() { - if(!mHeaderEntryQueue.empty()) - { - for(header_entry_queue_t::iterator iter = mHeaderEntryQueue.begin(); iter != mHeaderEntryQueue.end(); ++iter) - { - delete *iter ; - } - mHeaderEntryQueue.clear(); - mHandleEntryMap.clear(); - mNumEntries = 0 ; - } + std::for_each(mHandleEntryMap.begin(), mHandleEntryMap.end(), DeletePairedPointer()); + mHandleEntryMap.clear(); } void LLVOCache::getObjectCacheFilename(U64 handle, std::string& filename) @@ -379,6 +380,7 @@ void LLVOCache::removeFromCache(U64 handle) { if(mReadOnly) { + llwarns << "Not removing cache for handle " << handle << ": Cache is currently in read-only mode." << llendl; return ; } @@ -391,7 +393,6 @@ BOOL LLVOCache::checkRead(LLAPRFile* apr_file, void* src, S32 n_bytes) { if(!check_read(apr_file, src, n_bytes)) { - delete apr_file ; removeCache() ; return FALSE ; } @@ -403,7 +404,6 @@ BOOL LLVOCache::checkWrite(LLAPRFile* apr_file, void* src, S32 n_bytes) { if(!check_write(apr_file, src, n_bytes)) { - delete apr_file ; removeCache() ; return FALSE ; } @@ -415,7 +415,8 @@ void LLVOCache::readCacheHeader() { if(!mEnabled) { - return ; + llwarns << "Not reading cache header: Cache is currently disabled." << llendl; + return; } //clear stale info. @@ -428,28 +429,29 @@ void LLVOCache::readCacheHeader() //read the meta element if(!checkRead(apr_file, &mMetaInfo, sizeof(HeaderMetaInfo))) { - return ; + llwarns << "Error reading meta information from cache header." << llendl; + delete apr_file; + return; } HeaderEntryInfo* entry ; - mNumEntries = 0 ; - while(mNumEntries < mCacheSize) + for(U32 entry_index = 0; entry_index < mCacheSize; ++entry_index) { entry = new HeaderEntryInfo() ; if(!checkRead(apr_file, entry, sizeof(HeaderEntryInfo))) { + llwarns << "Error reading cache header entry. (entry_index=" << entry_index << ")" << llendl; delete entry ; - return ; + break; } else if(!entry->mTime) //end of the cache. { delete entry ; - return ; + break; } - entry->mIndex = mNumEntries++ ; - mHeaderEntryQueue.insert(entry) ; - mHandleEntryMap[entry->mHandle] = entry ; + entry->mIndex = entry_index; + mHandleEntryMap[entry->mHandle] = entry; } delete apr_file ; @@ -462,40 +464,57 @@ void LLVOCache::readCacheHeader() void LLVOCache::writeCacheHeader() { - if(mReadOnly || !mEnabled) + if (!mEnabled) { - return ; - } + llwarns << "Not writing cache header: Cache is currently disabled." << llendl; + return; + } + + if(mReadOnly) + { + llwarns << "Not writing cache header: Cache is currently in read-only mode." << llendl; + return; + } LLAPRFile* apr_file = new LLAPRFile(mHeaderFileName, APR_CREATE|APR_WRITE|APR_BINARY, mLocalAPRFilePoolp); //write the meta element if(!checkWrite(apr_file, &mMetaInfo, sizeof(HeaderMetaInfo))) { - return ; + llwarns << "Error writing meta information to cache header." << llendl; + delete apr_file; + return; } - mNumEntries = 0 ; - for(header_entry_queue_t::iterator iter = mHeaderEntryQueue.begin() ; iter != mHeaderEntryQueue.end(); ++iter) + U32 entry_index = 0; + handle_entry_map_t::iterator iter_end = mHandleEntryMap.end(); + for(handle_entry_map_t::iterator iter = mHandleEntryMap.begin(); + iter != iter_end; + ++iter) { - (*iter)->mIndex = mNumEntries++ ; - if(!checkWrite(apr_file, (void*)*iter, sizeof(HeaderEntryInfo))) + HeaderEntryInfo* entry = iter->second; + entry->mIndex = entry_index++; + if(!checkWrite(apr_file, (void*)entry, sizeof(HeaderEntryInfo))) { - return ; + llwarns << "Failed to write cache header for entry " << entry->mHandle << " (entry_index = " << entry_index << ")" << llendl; + delete apr_file; + return; } } - mNumEntries = mHeaderEntryQueue.size() ; - if(mNumEntries < mCacheSize) + // Why do we need to fill the cache header with default entries? DK 2010-12-14 + // It looks like we currently rely on the file being pre-allocated so we can seek during updateEntry(). + if(entry_index < mCacheSize) { HeaderEntryInfo* entry = new HeaderEntryInfo() ; - for(U32 i = mNumEntries ; i < mCacheSize; i++) + for(; entry_index < mCacheSize; ++entry_index) { //fill the cache with the default entry. if(!checkWrite(apr_file, entry, sizeof(HeaderEntryInfo))) { + llwarns << "Failed to fill cache header with default entries (entry_index = " << entry_index << "). Switching to read-only mode." << llendl; mReadOnly = TRUE ; //disable the cache. - return ; + break; } } delete entry ; @@ -508,13 +527,16 @@ BOOL LLVOCache::updateEntry(const HeaderEntryInfo* entry) LLAPRFile* apr_file = new LLAPRFile(mHeaderFileName, APR_WRITE|APR_BINARY, mLocalAPRFilePoolp); apr_file->seek(APR_SET, entry->mIndex * sizeof(HeaderEntryInfo) + sizeof(HeaderMetaInfo)) ; - return checkWrite(apr_file, (void*)entry, sizeof(HeaderEntryInfo)) ; + BOOL result = checkWrite(apr_file, (void*)entry, sizeof(HeaderEntryInfo)) ; + delete apr_file; + return result; } void LLVOCache::readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::vocache_entry_map_t& cache_entry_map) { if(!mEnabled) { + llwarns << "Not reading cache for handle " << handle << "): Cache is currently disabled." << llendl; return ; } llassert_always(mInitialized); @@ -522,6 +544,7 @@ void LLVOCache::readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::voca handle_entry_map_t::iterator iter = mHandleEntryMap.find(handle) ; if(iter == mHandleEntryMap.end()) //no cache { + llwarns << "No handle map entry for " << handle << llendl; return ; } @@ -532,12 +555,13 @@ void LLVOCache::readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::voca LLUUID cache_id ; if(!checkRead(apr_file, cache_id.mData, UUID_BYTES)) { + llwarns << "Error reading cache_id from " << filename << llendl; + delete apr_file; return ; } if(cache_id != id) { - llinfos << "Cache ID doesn't match for this region, discarding"<< llendl; - + llwarns << "Cache ID (" << cache_id << ") doesn't match id for this region (" << id << "), discarding. handle = " << handle << llendl; delete apr_file ; return ; } @@ -545,6 +569,8 @@ void LLVOCache::readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::voca S32 num_entries; if(!checkRead(apr_file, &num_entries, sizeof(S32))) { + llwarns << "Error reading num_entries from " << filename << llendl; + delete apr_file; return ; } @@ -553,13 +579,12 @@ void LLVOCache::readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::voca LLVOCacheEntry* entry = new LLVOCacheEntry(apr_file); if (!entry->getLocalID()) { - llwarns << "Aborting cache file load for " << filename << ", cache file corruption!" << llendl; + llwarns << "Aborting cache file load for " << filename << ", cache file corruption! (entry number = " << i << ")" << llendl; delete entry ; break; } cache_entry_map[entry->getLocalID()] = entry; } - num_entries = cache_entry_map.size() ; delete apr_file ; return ; @@ -568,40 +593,53 @@ void LLVOCache::readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::voca void LLVOCache::purgeEntries() { U32 limit = mCacheSize - NUM_ENTRIES_TO_PURGE ; - while(mHeaderEntryQueue.size() > limit) + // Construct a vector of entries out of the map so we can sort by time. + std::vector header_vector; + handle_entry_map_t::iterator iter_end = mHandleEntryMap.end(); + for (handle_entry_map_t::iterator iter = mHandleEntryMap.begin(); + iter != iter_end; + ++iter) + { + header_vector.push_back(iter->second); + } + // Sort by time, oldest first. + std::sort(header_vector.begin(), header_vector.end(), header_entry_less()); + while(header_vector.size() > limit) { - header_entry_queue_t::iterator iter = mHeaderEntryQueue.begin() ; - HeaderEntryInfo* entry = *iter ; + HeaderEntryInfo* entry = header_vector.front(); - removeFromCache(entry->mHandle) ; - mHandleEntryMap.erase(entry->mHandle) ; - mHeaderEntryQueue.erase(iter) ; - delete entry ; + removeFromCache(entry->mHandle); + mHandleEntryMap.erase(entry->mHandle); + header_vector.erase(header_vector.begin()); + delete entry; } writeCacheHeader() ; + // *TODO: Verify that we can avoid re-reading the cache header. DK 2010-12-14 readCacheHeader() ; - mNumEntries = mHandleEntryMap.size() ; } void LLVOCache::writeToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry::vocache_entry_map_t& cache_entry_map, BOOL dirty_cache) { if(!mEnabled) { + llwarns << "Not writing cache for handle " << handle << "): Cache is currently disabled." << llendl; return ; } llassert_always(mInitialized); if(mReadOnly) { + llwarns << "Not writing cache for handle " << handle << "): Cache is currently in read-only mode." << llendl; return ; } HeaderEntryInfo* entry; handle_entry_map_t::iterator iter = mHandleEntryMap.find(handle) ; + U32 num_handle_entries = mHandleEntryMap.size(); if(iter == mHandleEntryMap.end()) //new entry - { - if(mNumEntries >= mCacheSize) + { + if(num_handle_entries >= mCacheSize) { purgeEntries() ; } @@ -609,28 +647,26 @@ void LLVOCache::writeToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry: entry = new HeaderEntryInfo(); entry->mHandle = handle ; entry->mTime = time(NULL) ; - entry->mIndex = mNumEntries++ ; - mHeaderEntryQueue.insert(entry) ; + entry->mIndex = num_handle_entries++; mHandleEntryMap[handle] = entry ; } else { + // Update access time. entry = iter->second ; entry->mTime = time(NULL) ; - - //resort - mHeaderEntryQueue.erase(entry) ; - mHeaderEntryQueue.insert(entry) ; } //update cache header if(!updateEntry(entry)) { + llwarns << "Failed to update cache header index " << entry->mIndex << ". handle = " << handle << llendl; return ; //update failed. } if(!dirty_cache) { + llwarns << "Skipping write to cache for handle " << handle << ": cache not dirty" << llendl; return ; //nothing changed, no need to update. } @@ -641,12 +677,16 @@ void LLVOCache::writeToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry: if(!checkWrite(apr_file, (void*)id.mData, UUID_BYTES)) { + llwarns << "Error writing id to " << filename << llendl; + delete apr_file; return ; } S32 num_entries = cache_entry_map.size() ; if(!checkWrite(apr_file, &num_entries, sizeof(S32))) { + llwarns << "Error writing num_entries to " << filename << llendl; + delete apr_file; return ; } @@ -654,10 +694,10 @@ void LLVOCache::writeToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry: { if(!iter->second->writeToFile(apr_file)) { + llwarns << "Aborting cache file write for " << filename << ", error writing to file!" << llendl; //failed - delete apr_file ; removeCache() ; - return ; + break; } } diff --git a/indra/newview/llvocache.h b/indra/newview/llvocache.h index ed2bc8bafe..014112718e 100644 --- a/indra/newview/llvocache.h +++ b/indra/newview/llvocache.h @@ -95,10 +95,13 @@ private: { bool operator()(const HeaderEntryInfo* lhs, const HeaderEntryInfo* rhs) const { - return lhs->mTime < rhs->mTime; // older entry in front of queue (set) + if (lhs->mTime == rhs->mTime) + { + return lhs->mHandle < rhs->mHandle; + } + return lhs->mTime < rhs->mTime; // older entry in front } }; - typedef std::set header_entry_queue_t; typedef std::map handle_entry_map_t; private: LLVOCache() ; @@ -134,11 +137,9 @@ private: BOOL mReadOnly ; HeaderMetaInfo mMetaInfo; U32 mCacheSize; - U32 mNumEntries; std::string mHeaderFileName ; std::string mObjectCacheDirName; LLVolatileAPRPool* mLocalAPRFilePoolp ; - header_entry_queue_t mHeaderEntryQueue; handle_entry_map_t mHandleEntryMap; static LLVOCache* sInstance ; -- cgit v1.2.3 From 3e1f2083abe31d54b4b57ac7e8479b79461f6062 Mon Sep 17 00:00:00 2001 From: Don Kjer Date: Tue, 14 Dec 2010 23:56:35 -0800 Subject: First pass at fix for ER-401: Fix object cache header on the viewer --- indra/newview/llvocache.cpp | 162 +++++++++++++++++++++++++++----------------- indra/newview/llvocache.h | 9 +-- 2 files changed, 106 insertions(+), 65 deletions(-) diff --git a/indra/newview/llvocache.cpp b/indra/newview/llvocache.cpp index 145ee31260..6ea88abab8 100644 --- a/indra/newview/llvocache.cpp +++ b/indra/newview/llvocache.cpp @@ -40,6 +40,7 @@ BOOL check_write(LLAPRFile* apr_file, void* src, S32 n_bytes) return apr_file->write(src, n_bytes) == n_bytes ; } + //--------------------------------------------------------------------------- // LLVOCacheEntry //--------------------------------------------------------------------------- @@ -212,8 +213,8 @@ BOOL LLVOCacheEntry::writeToFile(LLAPRFile* apr_file) const if(success) { success = check_write(apr_file, (void*)mBuffer, size); + } } -} return success ; } @@ -224,7 +225,7 @@ BOOL LLVOCacheEntry::writeToFile(LLAPRFile* apr_file) const // Format string used to construct filename for the object cache static const char OBJECT_CACHE_FILENAME[] = "objects_%d_%d.slc"; -const U32 NUM_ENTRIES_TO_PURGE = 16 ; +const U32 NUM_ENTRIES_TO_PURGE = 50; const char* object_cache_dirname = "objectcache"; const char* header_filename = "object.cache"; @@ -259,7 +260,6 @@ void LLVOCache::destroyClass() LLVOCache::LLVOCache(): mInitialized(FALSE), mReadOnly(TRUE), - mNumEntries(0), mCacheSize(1) { mEnabled = gSavedSettings.getBOOL("ObjectCacheEnabled"); @@ -286,8 +286,15 @@ void LLVOCache::setDirNames(ELLPath location) void LLVOCache::initCache(ELLPath location, U32 size, U32 cache_version) { - if(mInitialized || !mEnabled) + if(!mEnabled) + { + llwarns << "Not initializing cache: Cache is currently disabled." << llendl; + return ; + } + + if(mInitialized) { + llwarns << "Cache already initialized." << llendl; return ; } @@ -321,6 +328,7 @@ void LLVOCache::removeCache(ELLPath location) { if(mReadOnly) { + llwarns << "Not removing cache at " << location << ": Cache is currently in read-only mode." << llendl; return ; } @@ -339,6 +347,7 @@ void LLVOCache::removeCache() llassert_always(mInitialized) ; if(mReadOnly) { + llwarns << "Not clearing object cache: Cache is currently in read-only mode." << llendl; return ; } @@ -352,16 +361,8 @@ void LLVOCache::removeCache() void LLVOCache::clearCacheInMemory() { - if(!mHeaderEntryQueue.empty()) - { - for(header_entry_queue_t::iterator iter = mHeaderEntryQueue.begin(); iter != mHeaderEntryQueue.end(); ++iter) - { - delete *iter ; - } - mHeaderEntryQueue.clear(); - mHandleEntryMap.clear(); - mNumEntries = 0 ; - } + std::for_each(mHandleEntryMap.begin(), mHandleEntryMap.end(), DeletePairedPointer()); + mHandleEntryMap.clear(); } void LLVOCache::getObjectCacheFilename(U64 handle, std::string& filename) @@ -379,6 +380,7 @@ void LLVOCache::removeFromCache(U64 handle) { if(mReadOnly) { + llwarns << "Not removing cache for handle " << handle << ": Cache is currently in read-only mode." << llendl; return ; } @@ -391,7 +393,6 @@ BOOL LLVOCache::checkRead(LLAPRFile* apr_file, void* src, S32 n_bytes) { if(!check_read(apr_file, src, n_bytes)) { - delete apr_file ; removeCache() ; return FALSE ; } @@ -403,7 +404,6 @@ BOOL LLVOCache::checkWrite(LLAPRFile* apr_file, void* src, S32 n_bytes) { if(!check_write(apr_file, src, n_bytes)) { - delete apr_file ; removeCache() ; return FALSE ; } @@ -415,7 +415,8 @@ void LLVOCache::readCacheHeader() { if(!mEnabled) { - return ; + llwarns << "Not reading cache header: Cache is currently disabled." << llendl; + return; } //clear stale info. @@ -428,28 +429,29 @@ void LLVOCache::readCacheHeader() //read the meta element if(!checkRead(apr_file, &mMetaInfo, sizeof(HeaderMetaInfo))) { - return ; + llwarns << "Error reading meta information from cache header." << llendl; + delete apr_file; + return; } HeaderEntryInfo* entry ; - mNumEntries = 0 ; - while(mNumEntries < mCacheSize) + for(U32 entry_index = 0; entry_index < mCacheSize; ++entry_index) { entry = new HeaderEntryInfo() ; if(!checkRead(apr_file, entry, sizeof(HeaderEntryInfo))) { + llwarns << "Error reading cache header entry. (entry_index=" << entry_index << ")" << llendl; delete entry ; - return ; + break; } else if(!entry->mTime) //end of the cache. { delete entry ; - return ; + break; } - entry->mIndex = mNumEntries++ ; - mHeaderEntryQueue.insert(entry) ; - mHandleEntryMap[entry->mHandle] = entry ; + entry->mIndex = entry_index; + mHandleEntryMap[entry->mHandle] = entry; } delete apr_file ; @@ -462,40 +464,57 @@ void LLVOCache::readCacheHeader() void LLVOCache::writeCacheHeader() { - if(mReadOnly || !mEnabled) + if (!mEnabled) { - return ; - } + llwarns << "Not writing cache header: Cache is currently disabled." << llendl; + return; + } + + if(mReadOnly) + { + llwarns << "Not writing cache header: Cache is currently in read-only mode." << llendl; + return; + } LLAPRFile* apr_file = new LLAPRFile(mHeaderFileName, APR_CREATE|APR_WRITE|APR_BINARY, mLocalAPRFilePoolp); //write the meta element if(!checkWrite(apr_file, &mMetaInfo, sizeof(HeaderMetaInfo))) { - return ; + llwarns << "Error writing meta information to cache header." << llendl; + delete apr_file; + return; } - mNumEntries = 0 ; - for(header_entry_queue_t::iterator iter = mHeaderEntryQueue.begin() ; iter != mHeaderEntryQueue.end(); ++iter) + U32 entry_index = 0; + handle_entry_map_t::iterator iter_end = mHandleEntryMap.end(); + for(handle_entry_map_t::iterator iter = mHandleEntryMap.begin(); + iter != iter_end; + ++iter) { - (*iter)->mIndex = mNumEntries++ ; - if(!checkWrite(apr_file, (void*)*iter, sizeof(HeaderEntryInfo))) + HeaderEntryInfo* entry = iter->second; + entry->mIndex = entry_index++; + if(!checkWrite(apr_file, (void*)entry, sizeof(HeaderEntryInfo))) { - return ; + llwarns << "Failed to write cache header for entry " << entry->mHandle << " (entry_index = " << entry_index << ")" << llendl; + delete apr_file; + return; } } - mNumEntries = mHeaderEntryQueue.size() ; - if(mNumEntries < mCacheSize) + // Why do we need to fill the cache header with default entries? DK 2010-12-14 + // It looks like we currently rely on the file being pre-allocated so we can seek during updateEntry(). + if(entry_index < mCacheSize) { HeaderEntryInfo* entry = new HeaderEntryInfo() ; - for(U32 i = mNumEntries ; i < mCacheSize; i++) + for(; entry_index < mCacheSize; ++entry_index) { //fill the cache with the default entry. if(!checkWrite(apr_file, entry, sizeof(HeaderEntryInfo))) { + llwarns << "Failed to fill cache header with default entries (entry_index = " << entry_index << "). Switching to read-only mode." << llendl; mReadOnly = TRUE ; //disable the cache. - return ; + break; } } delete entry ; @@ -508,13 +527,16 @@ BOOL LLVOCache::updateEntry(const HeaderEntryInfo* entry) LLAPRFile* apr_file = new LLAPRFile(mHeaderFileName, APR_WRITE|APR_BINARY, mLocalAPRFilePoolp); apr_file->seek(APR_SET, entry->mIndex * sizeof(HeaderEntryInfo) + sizeof(HeaderMetaInfo)) ; - return checkWrite(apr_file, (void*)entry, sizeof(HeaderEntryInfo)) ; + BOOL result = checkWrite(apr_file, (void*)entry, sizeof(HeaderEntryInfo)) ; + delete apr_file; + return result; } void LLVOCache::readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::vocache_entry_map_t& cache_entry_map) { if(!mEnabled) { + llwarns << "Not reading cache for handle " << handle << "): Cache is currently disabled." << llendl; return ; } llassert_always(mInitialized); @@ -522,6 +544,7 @@ void LLVOCache::readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::voca handle_entry_map_t::iterator iter = mHandleEntryMap.find(handle) ; if(iter == mHandleEntryMap.end()) //no cache { + llwarns << "No handle map entry for " << handle << llendl; return ; } @@ -532,12 +555,13 @@ void LLVOCache::readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::voca LLUUID cache_id ; if(!checkRead(apr_file, cache_id.mData, UUID_BYTES)) { + llwarns << "Error reading cache_id from " << filename << llendl; + delete apr_file; return ; } if(cache_id != id) { - llinfos << "Cache ID doesn't match for this region, discarding"<< llendl; - + llwarns << "Cache ID (" << cache_id << ") doesn't match id for this region (" << id << "), discarding. handle = " << handle << llendl; delete apr_file ; return ; } @@ -545,6 +569,8 @@ void LLVOCache::readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::voca S32 num_entries; if(!checkRead(apr_file, &num_entries, sizeof(S32))) { + llwarns << "Error reading num_entries from " << filename << llendl; + delete apr_file; return ; } @@ -553,13 +579,12 @@ void LLVOCache::readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::voca LLVOCacheEntry* entry = new LLVOCacheEntry(apr_file); if (!entry->getLocalID()) { - llwarns << "Aborting cache file load for " << filename << ", cache file corruption!" << llendl; + llwarns << "Aborting cache file load for " << filename << ", cache file corruption! (entry number = " << i << ")" << llendl; delete entry ; break; } cache_entry_map[entry->getLocalID()] = entry; } - num_entries = cache_entry_map.size() ; delete apr_file ; return ; @@ -568,40 +593,53 @@ void LLVOCache::readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::voca void LLVOCache::purgeEntries() { U32 limit = mCacheSize - NUM_ENTRIES_TO_PURGE ; - while(mHeaderEntryQueue.size() > limit) + // Construct a vector of entries out of the map so we can sort by time. + std::vector header_vector; + handle_entry_map_t::iterator iter_end = mHandleEntryMap.end(); + for (handle_entry_map_t::iterator iter = mHandleEntryMap.begin(); + iter != iter_end; + ++iter) + { + header_vector.push_back(iter->second); + } + // Sort by time, oldest first. + std::sort(header_vector.begin(), header_vector.end(), header_entry_less()); + while(header_vector.size() > limit) { - header_entry_queue_t::iterator iter = mHeaderEntryQueue.begin() ; - HeaderEntryInfo* entry = *iter ; + HeaderEntryInfo* entry = header_vector.front(); - removeFromCache(entry->mHandle) ; - mHandleEntryMap.erase(entry->mHandle) ; - mHeaderEntryQueue.erase(iter) ; - delete entry ; + removeFromCache(entry->mHandle); + mHandleEntryMap.erase(entry->mHandle); + header_vector.erase(header_vector.begin()); + delete entry; } writeCacheHeader() ; + // *TODO: Verify that we can avoid re-reading the cache header. DK 2010-12-14 readCacheHeader() ; - mNumEntries = mHandleEntryMap.size() ; } void LLVOCache::writeToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry::vocache_entry_map_t& cache_entry_map, BOOL dirty_cache) { if(!mEnabled) { + llwarns << "Not writing cache for handle " << handle << "): Cache is currently disabled." << llendl; return ; } llassert_always(mInitialized); if(mReadOnly) { + llwarns << "Not writing cache for handle " << handle << "): Cache is currently in read-only mode." << llendl; return ; } HeaderEntryInfo* entry; handle_entry_map_t::iterator iter = mHandleEntryMap.find(handle) ; + U32 num_handle_entries = mHandleEntryMap.size(); if(iter == mHandleEntryMap.end()) //new entry - { - if(mNumEntries >= mCacheSize) + { + if(num_handle_entries >= mCacheSize) { purgeEntries() ; } @@ -609,28 +647,26 @@ void LLVOCache::writeToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry: entry = new HeaderEntryInfo(); entry->mHandle = handle ; entry->mTime = time(NULL) ; - entry->mIndex = mNumEntries++ ; - mHeaderEntryQueue.insert(entry) ; + entry->mIndex = num_handle_entries++; mHandleEntryMap[handle] = entry ; } else { + // Update access time. entry = iter->second ; entry->mTime = time(NULL) ; - - //resort - mHeaderEntryQueue.erase(entry) ; - mHeaderEntryQueue.insert(entry) ; } //update cache header if(!updateEntry(entry)) { + llwarns << "Failed to update cache header index " << entry->mIndex << ". handle = " << handle << llendl; return ; //update failed. } if(!dirty_cache) { + llwarns << "Skipping write to cache for handle " << handle << ": cache not dirty" << llendl; return ; //nothing changed, no need to update. } @@ -641,12 +677,16 @@ void LLVOCache::writeToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry: if(!checkWrite(apr_file, (void*)id.mData, UUID_BYTES)) { + llwarns << "Error writing id to " << filename << llendl; + delete apr_file; return ; } S32 num_entries = cache_entry_map.size() ; if(!checkWrite(apr_file, &num_entries, sizeof(S32))) { + llwarns << "Error writing num_entries to " << filename << llendl; + delete apr_file; return ; } @@ -654,10 +694,10 @@ void LLVOCache::writeToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry: { if(!iter->second->writeToFile(apr_file)) { + llwarns << "Aborting cache file write for " << filename << ", error writing to file!" << llendl; //failed - delete apr_file ; removeCache() ; - return ; + break; } } diff --git a/indra/newview/llvocache.h b/indra/newview/llvocache.h index ed2bc8bafe..014112718e 100644 --- a/indra/newview/llvocache.h +++ b/indra/newview/llvocache.h @@ -95,10 +95,13 @@ private: { bool operator()(const HeaderEntryInfo* lhs, const HeaderEntryInfo* rhs) const { - return lhs->mTime < rhs->mTime; // older entry in front of queue (set) + if (lhs->mTime == rhs->mTime) + { + return lhs->mHandle < rhs->mHandle; + } + return lhs->mTime < rhs->mTime; // older entry in front } }; - typedef std::set header_entry_queue_t; typedef std::map handle_entry_map_t; private: LLVOCache() ; @@ -134,11 +137,9 @@ private: BOOL mReadOnly ; HeaderMetaInfo mMetaInfo; U32 mCacheSize; - U32 mNumEntries; std::string mHeaderFileName ; std::string mObjectCacheDirName; LLVolatileAPRPool* mLocalAPRFilePoolp ; - header_entry_queue_t mHeaderEntryQueue; handle_entry_map_t mHandleEntryMap; static LLVOCache* sInstance ; -- cgit v1.2.3 From 3be87bb04685e971965ab5ac4166165c3785476f Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 15 Dec 2010 11:23:00 -0800 Subject: ER-407 child bounding boxes not rotated properly for encroachment returnability Using the correct method for joining BBoxes in the agent frame ::addBBoxAgent() --- indra/llmath/llbbox.cpp | 14 -------------- indra/llmath/llbbox.h | 4 ---- indra/newview/llviewerobject.cpp | 2 +- 3 files changed, 1 insertion(+), 19 deletions(-) diff --git a/indra/llmath/llbbox.cpp b/indra/llmath/llbbox.cpp index 67a305d269..d2208f604e 100644 --- a/indra/llmath/llbbox.cpp +++ b/indra/llmath/llbbox.cpp @@ -102,20 +102,6 @@ LLBBox LLBBox::getAxisAligned() const return aligned; } -// Increases the size to contain other_box -void LLBBox::join(const LLBBox& other_box) -{ - LLVector3 other_min = (other_box.mPosAgent - mPosAgent) - other_box.mMinLocal; - mMinLocal.mV[VX] = llmin( other_min.mV[VX], mMinLocal.mV[VX] ); - mMinLocal.mV[VY] = llmin( other_min.mV[VY], mMinLocal.mV[VY] ); - mMinLocal.mV[VZ] = llmin( other_min.mV[VZ], mMinLocal.mV[VZ] ); - - LLVector3 other_max = (other_box.mPosAgent - mPosAgent) + other_box.mMaxLocal; - mMaxLocal.mV[VX] = llmax( other_max.mV[VX], mMaxLocal.mV[VX] ); - mMaxLocal.mV[VY] = llmax( other_max.mV[VY], mMaxLocal.mV[VY] ); - mMaxLocal.mV[VZ] = llmax( other_max.mV[VZ], mMaxLocal.mV[VZ] ); -} - void LLBBox::expand( F32 delta ) { diff --git a/indra/llmath/llbbox.h b/indra/llmath/llbbox.h index 8616320381..28e69b75e1 100644 --- a/indra/llmath/llbbox.h +++ b/indra/llmath/llbbox.h @@ -85,10 +85,6 @@ public: // Get the smallest possible axis aligned bbox that contains this bbox LLBBox getAxisAligned() const; - // Increases the size to contain other_box - void join(const LLBBox& other_box); - - // friend LLBBox operator*(const LLBBox& a, const LLMatrix4& b); private: diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 15207e7346..ae2154d63b 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -524,7 +524,7 @@ bool LLViewerObject::isReturnable() { LLViewerObject* child = *iter; LLBBox child_box(child->getPositionRegion(), child->getRotationRegion(), child->getScale() * -0.5f, child->getScale() * 0.5f); - bounding_box.join(child_box); + bounding_box.addBBoxAgent(child_box); } return !isAttachment() -- cgit v1.2.3 From 2192316803564b41a28d56481985597eb5d94fad Mon Sep 17 00:00:00 2001 From: Don Kjer Date: Wed, 15 Dec 2010 15:56:15 -0800 Subject: Modified cache purge entry threshold (part of ER-401) --- indra/newview/llvocache.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/indra/newview/llvocache.cpp b/indra/newview/llvocache.cpp index 6ea88abab8..10744991f4 100644 --- a/indra/newview/llvocache.cpp +++ b/indra/newview/llvocache.cpp @@ -225,7 +225,8 @@ BOOL LLVOCacheEntry::writeToFile(LLAPRFile* apr_file) const // Format string used to construct filename for the object cache static const char OBJECT_CACHE_FILENAME[] = "objects_%d_%d.slc"; -const U32 NUM_ENTRIES_TO_PURGE = 50; +// Throw out 1/20 (5%) of our cache entries if we run out of room. +const U32 ENTRIES_PURGE_FACTOR = 20; const char* object_cache_dirname = "objectcache"; const char* header_filename = "object.cache"; @@ -592,7 +593,8 @@ void LLVOCache::readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::voca void LLVOCache::purgeEntries() { - U32 limit = mCacheSize - NUM_ENTRIES_TO_PURGE ; + U32 limit = mCacheSize / ENTRIES_PURGE_FACTOR; + limit = llclamp(limit, 1, mCacheSize); // Construct a vector of entries out of the map so we can sort by time. std::vector header_vector; handle_entry_map_t::iterator iter_end = mHandleEntryMap.end(); -- cgit v1.2.3 From 57065fe5a9521158b79b7a313d6476b8dcaa13a5 Mon Sep 17 00:00:00 2001 From: Xiaohong Bao Date: Wed, 15 Dec 2010 17:20:58 -0700 Subject: fix for SH-367: mesh viewer lock up: Problem removing object.cache - errorcode: 13 --- indra/llvfs/lldir.cpp | 13 +- indra/newview/llvocache.cpp | 274 +++++++++++++++++++++++-------------------- indra/newview/llvocache.h | 4 +- indra/newview/llvovolume.cpp | 10 +- 4 files changed, 167 insertions(+), 134 deletions(-) diff --git a/indra/llvfs/lldir.cpp b/indra/llvfs/lldir.cpp index 938fb008c9..1a1f52df50 100644 --- a/indra/llvfs/lldir.cpp +++ b/indra/llvfs/lldir.cpp @@ -101,10 +101,18 @@ S32 LLDir::deleteFilesInDir(const std::string &dirname, const std::string &mask) { if (0 != LLFile::remove(fullpath)) { + retry_count++; result = errno; llwarns << "Problem removing " << fullpath << " - errorcode: " << result << " attempt " << retry_count << llendl; - ms_sleep(1000); + + if(retry_count >= 5) + { + llwarns << "Failed to remove " << fullpath << llendl ; + return count ; + } + + ms_sleep(100); } else { @@ -113,8 +121,7 @@ S32 LLDir::deleteFilesInDir(const std::string &dirname, const std::string &mask) llwarns << "Successfully removed " << fullpath << llendl; } break; - } - retry_count++; + } } count++; } diff --git a/indra/newview/llvocache.cpp b/indra/newview/llvocache.cpp index 1cb3962daa..bbe637d161 100644 --- a/indra/newview/llvocache.cpp +++ b/indra/newview/llvocache.cpp @@ -325,6 +325,8 @@ void LLVOCache::removeCache(ELLPath location) return ; } + llinfos << "about to remove the object cache due to settings." << llendl ; + std::string delem = gDirUtilp->getDirDelimiter(); std::string mask = delem + "*"; std::string cache_dir = gDirUtilp->getExpandedFilename(location, object_cache_dirname); @@ -343,6 +345,8 @@ void LLVOCache::removeCache() return ; } + llinfos << "about to remove the object cache due to some error." << llendl ; + std::string delem = gDirUtilp->getDirDelimiter(); std::string mask = delem + "*"; gDirUtilp->deleteFilesInDir(mObjectCacheDirName, mask); @@ -351,6 +355,43 @@ void LLVOCache::removeCache() writeCacheHeader(); } +void LLVOCache::removeEntry(HeaderEntryInfo* entry) +{ + llassert_always(mInitialized) ; + if(mReadOnly) + { + return ; + } + if(!entry) + { + return ; + } + + header_entry_queue_t::iterator iter = mHeaderEntryQueue.find(entry) ; + if(iter != mHeaderEntryQueue.end()) + { + removeFromCache(entry->mHandle) ; + mHandleEntryMap.erase(entry->mHandle) ; + mHeaderEntryQueue.erase(iter) ; + delete entry ; + + writeCacheHeader() ; + readCacheHeader() ; + mNumEntries = mHandleEntryMap.size() ; + } +} + +void LLVOCache::removeEntry(U64 handle) +{ + handle_entry_map_t::iterator iter = mHandleEntryMap.find(handle) ; + if(iter == mHandleEntryMap.end()) //no cache + { + return ; + } + HeaderEntryInfo* entry = iter->second ; + removeEntry(entry) ; +} + void LLVOCache::clearCacheInMemory() { if(!mHeaderEntryQueue.empty()) @@ -388,30 +429,6 @@ void LLVOCache::removeFromCache(U64 handle) LLAPRFile::remove(filename, mLocalAPRFilePoolp); } -BOOL LLVOCache::checkRead(LLAPRFile* apr_file, void* src, S32 n_bytes) -{ - if(!check_read(apr_file, src, n_bytes)) - { - delete apr_file ; - removeCache() ; - return FALSE ; - } - - return TRUE ; -} - -BOOL LLVOCache::checkWrite(LLAPRFile* apr_file, void* src, S32 n_bytes) -{ - if(!check_write(apr_file, src, n_bytes)) - { - delete apr_file ; - removeCache() ; - return FALSE ; - } - - return TRUE ; -} - void LLVOCache::readCacheHeader() { if(!mEnabled) @@ -422,43 +439,45 @@ void LLVOCache::readCacheHeader() //clear stale info. clearCacheInMemory(); + bool success = true ; if (LLAPRFile::isExist(mHeaderFileName, mLocalAPRFilePoolp)) { - LLAPRFile* apr_file = new LLAPRFile(mHeaderFileName, APR_READ|APR_BINARY, mLocalAPRFilePoolp); + LLAPRFile apr_file(mHeaderFileName, APR_READ|APR_BINARY, mLocalAPRFilePoolp); //read the meta element - if(!checkRead(apr_file, &mMetaInfo, sizeof(HeaderMetaInfo))) - { - return ; - } - - HeaderEntryInfo* entry ; - mNumEntries = 0 ; - while(mNumEntries < MAX_NUM_OBJECT_ENTRIES) + success = check_read(&apr_file, &mMetaInfo, sizeof(HeaderMetaInfo)) ; + + if(success) { - entry = new HeaderEntryInfo() ; - if(!checkRead(apr_file, entry, sizeof(HeaderEntryInfo))) - { - delete entry ; - return ; - } - else if(!entry->mTime) //end of the cache. + HeaderEntryInfo* entry ; + mNumEntries = 0 ; + while(mNumEntries < MAX_NUM_OBJECT_ENTRIES) { - delete entry ; - return ; + entry = new HeaderEntryInfo() ; + success = check_read(&apr_file, entry, sizeof(HeaderEntryInfo)); + + if(!success || !entry->mTime) //failed or end of the cache + { + delete entry ; + break ; + } + + entry->mIndex = mNumEntries++ ; + mHeaderEntryQueue.insert(entry) ; + mHandleEntryMap[entry->mHandle] = entry ; } - - entry->mIndex = mNumEntries++ ; - mHeaderEntryQueue.insert(entry) ; - mHandleEntryMap[entry->mHandle] = entry ; } - - delete apr_file ; } else { writeCacheHeader() ; } + + if(!success) + { + removeCache() ; //failed to read header, clear the cache + } + return ; } void LLVOCache::writeCacheHeader() @@ -468,48 +487,47 @@ void LLVOCache::writeCacheHeader() return ; } - LLAPRFile* apr_file = new LLAPRFile(mHeaderFileName, APR_CREATE|APR_WRITE|APR_BINARY, mLocalAPRFilePoolp); - - //write the meta element - if(!checkWrite(apr_file, &mMetaInfo, sizeof(HeaderMetaInfo))) + bool success = true ; { - return ; - } + LLAPRFile apr_file(mHeaderFileName, APR_CREATE|APR_WRITE|APR_BINARY, mLocalAPRFilePoolp); - mNumEntries = 0 ; - for(header_entry_queue_t::iterator iter = mHeaderEntryQueue.begin() ; iter != mHeaderEntryQueue.end(); ++iter) - { - (*iter)->mIndex = mNumEntries++ ; - if(!checkWrite(apr_file, (void*)*iter, sizeof(HeaderEntryInfo))) + //write the meta element + success = check_write(&apr_file, &mMetaInfo, sizeof(HeaderMetaInfo)) ; + + mNumEntries = 0 ; + for(header_entry_queue_t::iterator iter = mHeaderEntryQueue.begin() ; success && iter != mHeaderEntryQueue.end(); ++iter) { - return ; + (*iter)->mIndex = mNumEntries++ ; + success = check_write(&apr_file, (void*)*iter, sizeof(HeaderEntryInfo)); } - } - - mNumEntries = mHeaderEntryQueue.size() ; - if(mNumEntries < MAX_NUM_OBJECT_ENTRIES) - { - HeaderEntryInfo* entry = new HeaderEntryInfo() ; - for(S32 i = mNumEntries ; i < MAX_NUM_OBJECT_ENTRIES ; i++) + + mNumEntries = mHeaderEntryQueue.size() ; + if(success && mNumEntries < MAX_NUM_OBJECT_ENTRIES) { - //fill the cache with the default entry. - if(!checkWrite(apr_file, entry, sizeof(HeaderEntryInfo))) + HeaderEntryInfo* entry = new HeaderEntryInfo() ; + for(S32 i = mNumEntries ; success && i < MAX_NUM_OBJECT_ENTRIES ; i++) { - mReadOnly = TRUE ; //disable the cache. - return ; + //fill the cache with the default entry. + success = check_write(&apr_file, entry, sizeof(HeaderEntryInfo)) ; } + delete entry ; } - delete entry ; } - delete apr_file ; + + if(!success) + { + clearCacheInMemory() ; + mReadOnly = TRUE ; //disable the cache. + } + return ; } BOOL LLVOCache::updateEntry(const HeaderEntryInfo* entry) { - LLAPRFile* apr_file = new LLAPRFile(mHeaderFileName, APR_WRITE|APR_BINARY, mLocalAPRFilePoolp); - apr_file->seek(APR_SET, entry->mIndex * sizeof(HeaderEntryInfo) + sizeof(HeaderMetaInfo)) ; + LLAPRFile apr_file(mHeaderFileName, APR_WRITE|APR_BINARY, mLocalAPRFilePoolp); + apr_file.seek(APR_SET, entry->mIndex * sizeof(HeaderEntryInfo) + sizeof(HeaderMetaInfo)) ; - return checkWrite(apr_file, (void*)entry, sizeof(HeaderEntryInfo)) ; + return check_write(&apr_file, (void*)entry, sizeof(HeaderEntryInfo)) ; } void LLVOCache::readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::vocache_entry_map_t& cache_entry_map) @@ -526,43 +544,51 @@ void LLVOCache::readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::voca return ; } - std::string filename; - getObjectCacheFilename(handle, filename); - LLAPRFile* apr_file = new LLAPRFile(filename, APR_READ|APR_BINARY, mLocalAPRFilePoolp); - - LLUUID cache_id ; - if(!checkRead(apr_file, cache_id.mData, UUID_BYTES)) - { - return ; - } - if(cache_id != id) + bool success = true ; { - llinfos << "Cache ID doesn't match for this region, discarding"<< llendl; - - delete apr_file ; - return ; - } + std::string filename; + getObjectCacheFilename(handle, filename); + LLAPRFile apr_file(filename, APR_READ|APR_BINARY, mLocalAPRFilePoolp); + + LLUUID cache_id ; + success = check_read(&apr_file, cache_id.mData, UUID_BYTES) ; + + if(success) + { + if(cache_id != id) + { + llinfos << "Cache ID doesn't match for this region, discarding"<< llendl; + success = false ; + } - S32 num_entries; - if(!checkRead(apr_file, &num_entries, sizeof(S32))) - { - return ; + if(success) + { + S32 num_entries; + success = check_read(&apr_file, &num_entries, sizeof(S32)) ; + + for (S32 i = 0; success && i < num_entries; i++) + { + LLVOCacheEntry* entry = new LLVOCacheEntry(&apr_file); + if (!entry->getLocalID()) + { + llwarns << "Aborting cache file load for " << filename << ", cache file corruption!" << llendl; + delete entry ; + success = false ; + } + cache_entry_map[entry->getLocalID()] = entry; + } + } + } } - for (S32 i = 0; i < num_entries; i++) + if(!success) { - LLVOCacheEntry* entry = new LLVOCacheEntry(apr_file); - if (!entry->getLocalID()) + if(cache_entry_map.empty()) { - llwarns << "Aborting cache file load for " << filename << ", cache file corruption!" << llendl; - delete entry ; - break; + removeEntry(iter->second) ; } - cache_entry_map[entry->getLocalID()] = entry; } - num_entries = cache_entry_map.size() ; - delete apr_file ; return ; } @@ -636,33 +662,31 @@ void LLVOCache::writeToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry: } //write to cache file - std::string filename; - getObjectCacheFilename(handle, filename); - LLAPRFile* apr_file = new LLAPRFile(filename, APR_CREATE|APR_WRITE|APR_BINARY, mLocalAPRFilePoolp); - - if(!checkWrite(apr_file, (void*)id.mData, UUID_BYTES)) - { - return ; - } - - S32 num_entries = cache_entry_map.size() ; - if(!checkWrite(apr_file, &num_entries, sizeof(S32))) + bool success = true ; { - return ; + std::string filename; + getObjectCacheFilename(handle, filename); + LLAPRFile apr_file(filename, APR_CREATE|APR_WRITE|APR_BINARY, mLocalAPRFilePoolp); + + success = check_write(&apr_file, (void*)id.mData, UUID_BYTES) ; + + if(success) + { + S32 num_entries = cache_entry_map.size() ; + success = check_write(&apr_file, &num_entries, sizeof(S32)); + + for (LLVOCacheEntry::vocache_entry_map_t::const_iterator iter = cache_entry_map.begin(); success && iter != cache_entry_map.end(); ++iter) + { + success = iter->second->writeToFile(&apr_file) ; + } + } } - for (LLVOCacheEntry::vocache_entry_map_t::const_iterator iter = cache_entry_map.begin(); iter != cache_entry_map.end(); ++iter) + if(!success) { - if(!iter->second->writeToFile(apr_file)) - { - //failed - delete apr_file ; - removeCache() ; - return ; - } + removeEntry(entry) ; } - delete apr_file ; return ; } diff --git a/indra/newview/llvocache.h b/indra/newview/llvocache.h index ed2bc8bafe..6453886bc5 100644 --- a/indra/newview/llvocache.h +++ b/indra/newview/llvocache.h @@ -111,6 +111,7 @@ public: void readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::vocache_entry_map_t& cache_entry_map) ; void writeToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry::vocache_entry_map_t& cache_entry_map, BOOL dirty_cache) ; + void removeEntry(U64 handle) ; void setReadOnly(BOOL read_only) {mReadOnly = read_only;} @@ -123,10 +124,9 @@ private: void writeCacheHeader(); void clearCacheInMemory(); void removeCache() ; + void removeEntry(HeaderEntryInfo* entry) ; void purgeEntries(); BOOL updateEntry(const HeaderEntryInfo* entry); - BOOL checkRead(LLAPRFile* apr_file, void* src, S32 n_bytes) ; - BOOL checkWrite(LLAPRFile* apr_file, void* src, S32 n_bytes) ; private: BOOL mEnabled; diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 761e12020b..858e0321e1 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -388,10 +388,12 @@ U32 LLVOVolume::processUpdateMessage(LLMessageSystem *mesgsys, // There's something bogus in the data that we're unpacking. dp->dumpBufferToLog(); llwarns << "Flushing cache files" << llendl; - std::string mask; - mask = gDirUtilp->getDirDelimiter() + "*.slc"; - gDirUtilp->deleteFilesInDir(gDirUtilp->getExpandedFilename(LL_PATH_CACHE,""), mask); -// llerrs << "Bogus TE data in " << getID() << ", crashing!" << llendl; + + if(LLVOCache::hasInstance() && getRegion()) + { + LLVOCache::getInstance()->removeEntry(getRegion()->getHandle()) ; + } + llwarns << "Bogus TE data in " << getID() << llendl; } else -- cgit v1.2.3 From ac71884a446170a32ec557d5e9f85d0a73e8fa23 Mon Sep 17 00:00:00 2001 From: Xiaohong Bao Date: Wed, 15 Dec 2010 17:34:18 -0700 Subject: fix for SH-446: viewer crashed after clearing cache and relogging --- indra/newview/llvocache.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/indra/newview/llvocache.cpp b/indra/newview/llvocache.cpp index bbe637d161..cb48d1db73 100644 --- a/indra/newview/llvocache.cpp +++ b/indra/newview/llvocache.cpp @@ -291,6 +291,7 @@ void LLVOCache::initCache(ELLPath location, U32 size, U32 cache_version) { return ; } + mInitialized = TRUE ; setDirNames(location); if (!mReadOnly) @@ -301,8 +302,7 @@ void LLVOCache::initCache(ELLPath location, U32 size, U32 cache_version) MAX_NUM_OBJECT_ENTRIES, NUM_ENTRIES_TO_PURGE); mMetaInfo.mVersion = cache_version; - readCacheHeader(); - mInitialized = TRUE ; + readCacheHeader(); if(mMetaInfo.mVersion != cache_version) { -- cgit v1.2.3 From b87397938345b7dce30c3f10a4e54d9e0434b217 Mon Sep 17 00:00:00 2001 From: Don Kjer Date: Thu, 16 Dec 2010 02:06:39 -0800 Subject: Fix for compile issue --- indra/newview/llvocache.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/llvocache.cpp b/indra/newview/llvocache.cpp index 10744991f4..040139f3ab 100644 --- a/indra/newview/llvocache.cpp +++ b/indra/newview/llvocache.cpp @@ -594,7 +594,7 @@ void LLVOCache::readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::voca void LLVOCache::purgeEntries() { U32 limit = mCacheSize / ENTRIES_PURGE_FACTOR; - limit = llclamp(limit, 1, mCacheSize); + limit = llclamp(limit, (U32)1, mCacheSize); // Construct a vector of entries out of the map so we can sort by time. std::vector header_vector; handle_entry_map_t::iterator iter_end = mHandleEntryMap.end(); -- cgit v1.2.3 From 3aa8a883ebf5865045afb3b1577e1cfcaa6b9045 Mon Sep 17 00:00:00 2001 From: Don Kjer Date: Thu, 16 Dec 2010 02:06:39 -0800 Subject: Fix for compile issue --- indra/newview/llvocache.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/llvocache.cpp b/indra/newview/llvocache.cpp index 10744991f4..040139f3ab 100644 --- a/indra/newview/llvocache.cpp +++ b/indra/newview/llvocache.cpp @@ -594,7 +594,7 @@ void LLVOCache::readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::voca void LLVOCache::purgeEntries() { U32 limit = mCacheSize / ENTRIES_PURGE_FACTOR; - limit = llclamp(limit, 1, mCacheSize); + limit = llclamp(limit, (U32)1, mCacheSize); // Construct a vector of entries out of the map so we can sort by time. std::vector header_vector; handle_entry_map_t::iterator iter_end = mHandleEntryMap.end(); -- cgit v1.2.3 From f137dc0c2f928b81a90e59c58adefeb56f21393e Mon Sep 17 00:00:00 2001 From: Xiaohong Bao Date: Thu, 16 Dec 2010 17:13:07 -0700 Subject: fix for SH-445: debug settings -> "CacheNumberOfRegionsForObjects" does not limit the number of object cache files --- indra/newview/llvocache.cpp | 86 +++++++++++++++++++++++++++++---------------- indra/newview/llvocache.h | 9 +++-- 2 files changed, 62 insertions(+), 33 deletions(-) diff --git a/indra/newview/llvocache.cpp b/indra/newview/llvocache.cpp index cb48d1db73..b53f5c7a20 100644 --- a/indra/newview/llvocache.cpp +++ b/indra/newview/llvocache.cpp @@ -225,7 +225,8 @@ BOOL LLVOCacheEntry::writeToFile(LLAPRFile* apr_file) const static const char OBJECT_CACHE_FILENAME[] = "objects_%d_%d.slc"; const U32 MAX_NUM_OBJECT_ENTRIES = 128 ; -const U32 NUM_ENTRIES_TO_PURGE = 16 ; +const U32 MIN_ENTRIES_TO_PURGE = 16 ; +const U32 INVALID_TIME = 0 ; const char* object_cache_dirname = "objectcache"; const char* header_filename = "object.cache"; @@ -298,8 +299,7 @@ void LLVOCache::initCache(ELLPath location, U32 size, U32 cache_version) { LLFile::mkdir(mObjectCacheDirName); } - mCacheSize = llclamp(size, - MAX_NUM_OBJECT_ENTRIES, NUM_ENTRIES_TO_PURGE); + mCacheSize = llclamp(size, MIN_ENTRIES_TO_PURGE, MAX_NUM_OBJECT_ENTRIES); mMetaInfo.mVersion = cache_version; readCacheHeader(); @@ -369,14 +369,12 @@ void LLVOCache::removeEntry(HeaderEntryInfo* entry) header_entry_queue_t::iterator iter = mHeaderEntryQueue.find(entry) ; if(iter != mHeaderEntryQueue.end()) - { - removeFromCache(entry->mHandle) ; + { mHandleEntryMap.erase(entry->mHandle) ; mHeaderEntryQueue.erase(iter) ; + removeFromCache(entry) ; delete entry ; - writeCacheHeader() ; - readCacheHeader() ; mNumEntries = mHandleEntryMap.size() ; } } @@ -417,7 +415,7 @@ void LLVOCache::getObjectCacheFilename(U64 handle, std::string& filename) return ; } -void LLVOCache::removeFromCache(U64 handle) +void LLVOCache::removeFromCache(HeaderEntryInfo* entry) { if(mReadOnly) { @@ -425,8 +423,11 @@ void LLVOCache::removeFromCache(U64 handle) } std::string filename; - getObjectCacheFilename(handle, filename); - LLAPRFile::remove(filename, mLocalAPRFilePoolp); + getObjectCacheFilename(entry->mHandle, filename); + LLAPRFile::remove(filename, mLocalAPRFilePoolp); + + entry->mTime = INVALID_TIME ; + updateEntry(entry) ; //update the head file. } void LLVOCache::readCacheHeader() @@ -449,24 +450,49 @@ void LLVOCache::readCacheHeader() if(success) { - HeaderEntryInfo* entry ; + HeaderEntryInfo* entry = NULL ; mNumEntries = 0 ; - while(mNumEntries < MAX_NUM_OBJECT_ENTRIES) + U32 num_read = 0 ; + while(num_read++ < MAX_NUM_OBJECT_ENTRIES) { - entry = new HeaderEntryInfo() ; + if(!entry) + { + entry = new HeaderEntryInfo() ; + } success = check_read(&apr_file, entry, sizeof(HeaderEntryInfo)); - - if(!success || !entry->mTime) //failed or end of the cache + + if(!success) //failed { - delete entry ; + delete entry ; + entry = NULL ; break ; - } + } + else if(entry->mTime == INVALID_TIME) + { + continue ; //an empty entry + } entry->mIndex = mNumEntries++ ; mHeaderEntryQueue.insert(entry) ; mHandleEntryMap[entry->mHandle] = entry ; + entry = NULL ; + } + if(entry) + { + delete entry ; } } + + //--------- + //debug code + //---------- + //std::string name ; + //for(header_entry_queue_t::iterator iter = mHeaderEntryQueue.begin() ; success && iter != mHeaderEntryQueue.end(); ++iter) + //{ + // getObjectCacheFilename((*iter)->mHandle, name) ; + // llinfos << name << llendl ; + //} + //----------- } else { @@ -505,6 +531,7 @@ void LLVOCache::writeCacheHeader() if(success && mNumEntries < MAX_NUM_OBJECT_ENTRIES) { HeaderEntryInfo* entry = new HeaderEntryInfo() ; + entry->mTime = INVALID_TIME ; for(S32 i = mNumEntries ; success && i < MAX_NUM_OBJECT_ENTRIES ; i++) { //fill the cache with the default entry. @@ -594,20 +621,17 @@ void LLVOCache::readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::voca void LLVOCache::purgeEntries() { - U32 limit = mCacheSize - NUM_ENTRIES_TO_PURGE ; - while(mHeaderEntryQueue.size() > limit) + while(mHeaderEntryQueue.size() >= mCacheSize) { header_entry_queue_t::iterator iter = mHeaderEntryQueue.begin() ; HeaderEntryInfo* entry = *iter ; - - removeFromCache(entry->mHandle) ; + mHandleEntryMap.erase(entry->mHandle) ; mHeaderEntryQueue.erase(iter) ; + removeFromCache(entry) ; delete entry ; } - writeCacheHeader() ; - readCacheHeader() ; mNumEntries = mHandleEntryMap.size() ; } @@ -623,16 +647,15 @@ void LLVOCache::writeToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry: { return ; } + if(mNumEntries >= mCacheSize) + { + purgeEntries() ; + } HeaderEntryInfo* entry; handle_entry_map_t::iterator iter = mHandleEntryMap.find(handle) ; if(iter == mHandleEntryMap.end()) //new entry - { - if(mNumEntries >= mCacheSize) - { - purgeEntries() ; - } - + { entry = new HeaderEntryInfo(); entry->mHandle = handle ; entry->mTime = time(NULL) ; @@ -642,11 +665,12 @@ void LLVOCache::writeToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry: } else { - entry = iter->second ; - entry->mTime = time(NULL) ; + entry = iter->second ; //resort mHeaderEntryQueue.erase(entry) ; + + entry->mTime = time(NULL) ; mHeaderEntryQueue.insert(entry) ; } diff --git a/indra/newview/llvocache.h b/indra/newview/llvocache.h index 6453886bc5..1070fcaae9 100644 --- a/indra/newview/llvocache.h +++ b/indra/newview/llvocache.h @@ -95,7 +95,12 @@ private: { bool operator()(const HeaderEntryInfo* lhs, const HeaderEntryInfo* rhs) const { - return lhs->mTime < rhs->mTime; // older entry in front of queue (set) + if(lhs->mTime == rhs->mTime) + { + return lhs < rhs ; + } + + return lhs->mTime < rhs->mTime ; // older entry in front of queue (set) } }; typedef std::set header_entry_queue_t; @@ -119,7 +124,7 @@ private: void setDirNames(ELLPath location); // determine the cache filename for the region from the region handle void getObjectCacheFilename(U64 handle, std::string& filename); - void removeFromCache(U64 handle); + void removeFromCache(HeaderEntryInfo* entry); void readCacheHeader(); void writeCacheHeader(); void clearCacheInMemory(); -- cgit v1.2.3 From b9acc0285cd5026fdd22f4f35c1cfdcb1258155e Mon Sep 17 00:00:00 2001 From: Don Kjer Date: Thu, 16 Dec 2010 19:19:20 -0800 Subject: Dummy placeholder code for ER-414: Add object update type debug rendering view --- indra/newview/llspatialpartition.cpp | 19 +++++++++++++++++++ indra/newview/llviewermenu.cpp | 4 ++++ indra/newview/pipeline.h | 1 + indra/newview/skins/default/xui/en/menu_viewer.xml | 10 ++++++++++ 4 files changed, 34 insertions(+) diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp index 960e72ee42..3dd0e1081e 100644 --- a/indra/newview/llspatialpartition.cpp +++ b/indra/newview/llspatialpartition.cpp @@ -2578,6 +2578,20 @@ void renderCrossHairs(LLVector3 position, F32 size, LLColor4 color) gGL.end(); } +void renderUpdateType(LLDrawable* drawablep) +{ + S32 num_faces = drawablep->getNumFaces(); + if (num_faces) + { + LLGLEnable blend(GL_BLEND); + glColor4f(0,1,1,0.5f); + for (S32 i = 0; i < num_faces; ++i) + { + pushVerts(drawablep->getFace(i), LLVertexBuffer::MAP_VERTEX); + } + } +} + void renderBoundingBox(LLDrawable* drawable, BOOL set_color = TRUE) { @@ -3018,6 +3032,10 @@ public: { renderRaycast(drawable); } + if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_UPDATE_TYPE)) + { + renderUpdateType(drawable); + } LLVOAvatar* avatar = dynamic_cast(drawable->getVObj().get()); @@ -3180,6 +3198,7 @@ void LLSpatialPartition::renderDebug() LLPipeline::RENDER_DEBUG_OCCLUSION | LLPipeline::RENDER_DEBUG_LIGHTS | LLPipeline::RENDER_DEBUG_BATCH_SIZE | + LLPipeline::RENDER_DEBUG_UPDATE_TYPE | LLPipeline::RENDER_DEBUG_BBOXES | LLPipeline::RENDER_DEBUG_POINTS | LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY | diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index e18b4ec414..ee37594d9d 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -906,6 +906,10 @@ U32 info_display_from_string(std::string info_display) { return LLPipeline::RENDER_DEBUG_BATCH_SIZE; } + else if ("update type" == info_display) + { + return LLPipeline::RENDER_DEBUG_UPDATE_TYPE; + } else if ("texture anim" == info_display) { return LLPipeline::RENDER_DEBUG_TEXTURE_ANIM; diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h index 3f785a99fe..cef3d87f36 100644 --- a/indra/newview/pipeline.h +++ b/indra/newview/pipeline.h @@ -424,6 +424,7 @@ public: RENDER_DEBUG_AVATAR_VOLUME = 0x0100000, RENDER_DEBUG_BUILD_QUEUE = 0x0200000, RENDER_DEBUG_AGENT_TARGET = 0x0400000, + RENDER_DEBUG_UPDATE_TYPE = 0x0800000, }; public: diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index 907f68dc06..15616d1729 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -2129,6 +2129,16 @@ function="Advanced.ToggleInfoDisplay" parameter="render batches" /> + + + + -- cgit v1.2.3 From 84516e337d887bf871e361bfebfce2695e8f443c Mon Sep 17 00:00:00 2001 From: Don Kjer Date: Thu, 16 Dec 2010 19:20:47 -0800 Subject: Disabled debug viewer stats recorder --- indra/newview/llviewerstatsrecorder.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/llviewerstatsrecorder.h b/indra/newview/llviewerstatsrecorder.h index f9ccdd6e78..612ac380f7 100644 --- a/indra/newview/llviewerstatsrecorder.h +++ b/indra/newview/llviewerstatsrecorder.h @@ -32,7 +32,7 @@ // for analysis. // This is normally 0. Set to 1 to enable viewer stats recording -#define LL_RECORD_VIEWER_STATS 1 +#define LL_RECORD_VIEWER_STATS 0 #if LL_RECORD_VIEWER_STATS -- cgit v1.2.3 From 14e402cf5e8274caddaf1c763c2e044c53514b1e Mon Sep 17 00:00:00 2001 From: Don Kjer Date: Thu, 16 Dec 2010 22:09:49 -0800 Subject: ER-414: Add object update type debug rendering view --- indra/newview/llspatialpartition.cpp | 33 ++++++++++++++++++++++++++++-- indra/newview/llviewerobject.cpp | 24 +++++++++++++++++++++- indra/newview/llviewerobject.h | 8 ++++++++ indra/newview/llviewerobjectlist.cpp | 36 +++++---------------------------- indra/newview/llviewerstatsrecorder.cpp | 7 ++++++- 5 files changed, 73 insertions(+), 35 deletions(-) diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp index 3dd0e1081e..8adb8c30e0 100644 --- a/indra/newview/llspatialpartition.cpp +++ b/indra/newview/llspatialpartition.cpp @@ -2580,11 +2580,40 @@ void renderCrossHairs(LLVector3 position, F32 size, LLColor4 color) void renderUpdateType(LLDrawable* drawablep) { + LLViewerObject* vobj = drawablep->getVObj(); + if (!vobj || OUT_UNKNOWN == vobj->getLastUpdateType()) + { + return; + } + LLGLEnable blend(GL_BLEND); + switch (vobj->getLastUpdateType()) + { + case OUT_FULL: + glColor4f(0,1,0,0.5f); + break; + case OUT_TERSE_IMPROVED: + glColor4f(0,1,1,0.5f); + break; + case OUT_FULL_COMPRESSED: + if (vobj->getLastUpdateCached()) + { + glColor4f(1,0,0,0.5f); + } + else + { + glColor4f(1,1,0,0.5f); + } + break; + case OUT_FULL_CACHED: + glColor4f(0,0,1,0.5f); + break; + default: + llwarns << "Unknown update_type " << vobj->getLastUpdateType() << llendl; + break; + }; S32 num_faces = drawablep->getNumFaces(); if (num_faces) { - LLGLEnable blend(GL_BLEND); - glColor4f(0,1,1,0.5f); for (S32 i = 0; i < num_faces; ++i) { pushVerts(drawablep->getFace(i), LLVertexBuffer::MAP_VERTEX); diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 1804fac1b3..3c12cb66b2 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -234,7 +234,9 @@ LLViewerObject::LLViewerObject(const LLUUID &id, const LLPCode pcode, LLViewerRe mState(0), mMedia(NULL), mClickAction(0), - mAttachmentItemID(LLUUID::null) + mAttachmentItemID(LLUUID::null), + mLastUpdateType(OUT_UNKNOWN), + mLastUpdateCached(FALSE) { if (!is_global) { @@ -5400,6 +5402,26 @@ void LLViewerObject::setAttachmentItemID(const LLUUID &id) mAttachmentItemID = id; } +EObjectUpdateType LLViewerObject::getLastUpdateType() +{ + return mLastUpdateType; +} + +void LLViewerObject::setLastUpdateType(EObjectUpdateType last_update_type) +{ + mLastUpdateType = last_update_type; +} + +BOOL LLViewerObject::getLastUpdateCached() +{ + return mLastUpdateCached; +} + +void LLViewerObject::setLastUpdateCached(BOOL last_update_cached) +{ + mLastUpdateCached = last_update_cached; +} + const LLUUID &LLViewerObject::extractAttachmentItemID() { LLUUID item_id = LLUUID::null; diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index fe670f8827..c83cc06128 100644 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -77,6 +77,7 @@ typedef enum e_object_update_type OUT_TERSE_IMPROVED, OUT_FULL_COMPRESSED, OUT_FULL_CACHED, + OUT_UNKNOWN, } EObjectUpdateType; @@ -696,8 +697,15 @@ public: const LLUUID &getAttachmentItemID() const; void setAttachmentItemID(const LLUUID &id); const LLUUID &extractAttachmentItemID(); // find&set the inventory item ID of the attached object + EObjectUpdateType getLastUpdateType(); + void setLastUpdateType(EObjectUpdateType last_update_type); + BOOL getLastUpdateCached(); + void setLastUpdateCached(BOOL last_update_cached); + private: LLUUID mAttachmentItemID; // ItemID of the associated object is in user inventory. + EObjectUpdateType mLastUpdateType; + BOOL mLastUpdateCached; }; /////////////////// diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp index 70631f9481..77fbc08ca4 100644 --- a/indra/newview/llviewerobjectlist.cpp +++ b/indra/newview/llviewerobjectlist.cpp @@ -564,10 +564,12 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, processUpdateCore(objectp, user_data, i, update_type, &compressed_dp, justCreated); if (update_type != OUT_TERSE_IMPROVED) // OUT_FULL_COMPRESSED only? { - LLViewerRegion::eCacheUpdateResult result = objectp->mRegionp->cacheFullUpdate(objectp, compressed_dp); bCached = true; #if LL_RECORD_VIEWER_STATS + LLViewerRegion::eCacheUpdateResult result = objectp->mRegionp->cacheFullUpdate(objectp, compressed_dp); LLViewerStatsRecorder::instance()->recordCacheFullUpdate(local_id, update_type, result, objectp); + #else + objectp->mRegionp->cacheFullUpdate(objectp, compressed_dp); #endif } } @@ -586,37 +588,9 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, } #if LL_RECORD_VIEWER_STATS LLViewerStatsRecorder::instance()->recordObjectUpdateEvent(local_id, update_type, objectp); - F32 color_strength = llmin(((LLViewerStatsRecorder::instance()->getTimeSinceStart() / 1000.0f) + 128.0f) / 255.0f, 1.0f); - LLColor4 color; - switch (update_type) - { - case OUT_FULL: - color[VGREEN] = color_strength; - break; - case OUT_TERSE_IMPROVED: - color[VGREEN] = color_strength; - color[VBLUE] = color_strength; - break; - case OUT_FULL_COMPRESSED: - color[VRED] = color_strength; - if (!bCached) - { - color[VGREEN] = color_strength; - } - break; - case OUT_FULL_CACHED: - color[VBLUE] = color_strength; - break; - default: - llwarns << "Unknown update_type " << update_type << llendl; - break; - }; - U8 te; - for (te = 0; te < objectp->getNumTEs(); ++te) - { - objectp->setTEColor(te, color); - } #endif + objectp->setLastUpdateType(update_type); + objectp->setLastUpdateCached(bCached); } #if LL_RECORD_VIEWER_STATS diff --git a/indra/newview/llviewerstatsrecorder.cpp b/indra/newview/llviewerstatsrecorder.cpp index a8d1565742..e9d21b4848 100644 --- a/indra/newview/llviewerstatsrecorder.cpp +++ b/indra/newview/llviewerstatsrecorder.cpp @@ -26,6 +26,9 @@ #include "llviewerprecompiledheaders.h" #include "llviewerstatsrecorder.h" + +#if LL_RECORD_VIEWER_STATS + #include "llfile.h" #include "llviewerregion.h" #include "llviewerobject.h" @@ -38,7 +41,6 @@ static const std::string STATS_FILE_NAME("/tmp/viewerstats.csv"); #endif - LLViewerStatsRecorder* LLViewerStatsRecorder::sInstance = NULL; LLViewerStatsRecorder::LLViewerStatsRecorder() : mObjectCacheFile(NULL), @@ -250,4 +252,7 @@ F32 LLViewerStatsRecorder::getTimeSinceStart() return (F32) ((LLTimer::getTotalTime() - mStartTime) / 1000.0); } +#endif + + -- cgit v1.2.3 From 4e150d3271334e17bca0b9b47022fa3c529dc8c8 Mon Sep 17 00:00:00 2001 From: Seth ProductEngine Date: Fri, 17 Dec 2010 22:16:14 +0200 Subject: STORM-477 WIP Re-implemented LLDir::getNextFileInDir() as an iterator object. - Added a class implementing directory entries iteration with pattern matching which is used in unit tests instead of LLDir::getNextFileInDir. STORM-550 FIXED Fixed LLDir unit test which failed for some complex wildcard combinations. --- indra/cmake/Boost.cmake | 18 ++++ indra/llvfs/CMakeLists.txt | 7 ++ indra/llvfs/lldiriterator.cpp | 203 +++++++++++++++++++++++++++++++++++++++ indra/llvfs/lldiriterator.h | 87 +++++++++++++++++ indra/llvfs/tests/lldir_test.cpp | 38 +++++--- 5 files changed, 338 insertions(+), 15 deletions(-) create mode 100644 indra/llvfs/lldiriterator.cpp create mode 100644 indra/llvfs/lldiriterator.h diff --git a/indra/cmake/Boost.cmake b/indra/cmake/Boost.cmake index 7ce57a5572..012d3c2ab2 100644 --- a/indra/cmake/Boost.cmake +++ b/indra/cmake/Boost.cmake @@ -10,6 +10,8 @@ if (STANDALONE) set(BOOST_PROGRAM_OPTIONS_LIBRARY boost_program_options-mt) set(BOOST_REGEX_LIBRARY boost_regex-mt) set(BOOST_SIGNALS_LIBRARY boost_signals-mt) + set(BOOST_SYSTEM_LIBRARY boost_system-mt) + set(BOOST_FILESYSTEM_LIBRARY boost_filesystem-mt) else (STANDALONE) use_prebuilt_binary(boost) set(Boost_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include) @@ -26,6 +28,12 @@ else (STANDALONE) set(BOOST_SIGNALS_LIBRARY optimized libboost_signals-vc71-mt-s-${BOOST_VERSION} debug libboost_signals-vc71-mt-sgd-${BOOST_VERSION}) + set(BOOST_SYSTEM_LIBRARY + optimized libboost_system-vc71-mt-s-${BOOST_VERSION} + debug libboost_system-vc71-mt-sgd-${BOOST_VERSION}) + set(BOOST_FILESYSTEM_LIBRARY + optimized libboost_filesystem-vc71-mt-s-${BOOST_VERSION} + debug libboost_filesystem-vc71-mt-sgd-${BOOST_VERSION}) else (MSVC71) set(BOOST_PROGRAM_OPTIONS_LIBRARY optimized libboost_program_options-vc80-mt-${BOOST_VERSION} @@ -36,14 +44,24 @@ else (STANDALONE) set(BOOST_SIGNALS_LIBRARY optimized libboost_signals-vc80-mt-${BOOST_VERSION} debug libboost_signals-vc80-mt-gd-${BOOST_VERSION}) + set(BOOST_SYSTEM_LIBRARY + optimized libboost_system-vc80-mt-${BOOST_VERSION} + debug libboost_system-vc80-mt-gd-${BOOST_VERSION}) + set(BOOST_FILESYSTEM_LIBRARY + optimized libboost_filesystem-vc80-mt-${BOOST_VERSION} + debug libboost_filesystem-vc80-mt-gd-${BOOST_VERSION}) endif (MSVC71) elseif (DARWIN) set(BOOST_PROGRAM_OPTIONS_LIBRARY boost_program_options-xgcc40-mt) set(BOOST_REGEX_LIBRARY boost_regex-xgcc40-mt) set(BOOST_SIGNALS_LIBRARY boost_signals-xgcc40-mt) + set(BOOST_SYSTEM_LIBRARY boost_system-xgcc40-mt) + set(BOOST_FILESYSTEM_LIBRARY boost_filesystem-xgcc40-mt) elseif (LINUX) set(BOOST_PROGRAM_OPTIONS_LIBRARY boost_program_options-gcc41-mt) set(BOOST_REGEX_LIBRARY boost_regex-gcc41-mt) set(BOOST_SIGNALS_LIBRARY boost_signals-gcc41-mt) + set(BOOST_SYSTEM_LIBRARY boost_system-gcc41-mt) + set(BOOST_FILESYSTEM_LIBRARY boost_filesystem-gcc41-mt) endif (WINDOWS) endif (STANDALONE) diff --git a/indra/llvfs/CMakeLists.txt b/indra/llvfs/CMakeLists.txt index 722f4e2bfd..a3782d824b 100644 --- a/indra/llvfs/CMakeLists.txt +++ b/indra/llvfs/CMakeLists.txt @@ -12,6 +12,7 @@ include_directories( set(llvfs_SOURCE_FILES lldir.cpp + lldiriterator.cpp lllfsthread.cpp llpidlock.cpp llvfile.cpp @@ -24,6 +25,7 @@ set(llvfs_HEADER_FILES lldir.h lldirguard.h + lldiriterator.h lllfsthread.h llpidlock.h llvfile.h @@ -60,6 +62,11 @@ list(APPEND llvfs_SOURCE_FILES ${llvfs_HEADER_FILES}) add_library (llvfs ${llvfs_SOURCE_FILES}) +target_link_libraries(llvfs + ${BOOST_FILESYSTEM_LIBRARY} + ${BOOST_SYSTEM_LIBRARY} + ) + if (DARWIN) include(CMakeFindFrameworks) find_library(CARBON_LIBRARY Carbon) diff --git a/indra/llvfs/lldiriterator.cpp b/indra/llvfs/lldiriterator.cpp new file mode 100644 index 0000000000..5536ed8f69 --- /dev/null +++ b/indra/llvfs/lldiriterator.cpp @@ -0,0 +1,203 @@ +/** + * @file lldiriterator.cpp + * @brief Iterator through directory entries matching the search pattern. + * + * $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 "lldiriterator.h" + +#include +#include + +namespace fs = boost::filesystem; + +static std::string glob_to_regex(const std::string& glob); + +class LLDirIterator::Impl +{ +public: + Impl(const std::string &dirname, const std::string &mask); + ~Impl(); + + bool next(std::string &fname); + +private: + boost::regex mFilterExp; + fs::directory_iterator mIter; + bool mIsValid; +}; + +LLDirIterator::Impl::Impl(const std::string &dirname, const std::string &mask) + : mIsValid(false) +{ + fs::path dir_path(dirname); + + // Check if path exists. + if (!fs::exists(dir_path)) + { + llerrs << "Invalid path: \"" << dir_path.string() << "\"" << llendl; + return; + } + + // Initialize the directory iterator for the given path. + try + { + mIter = fs::directory_iterator(dir_path); + } + catch (fs::basic_filesystem_error& e) + { + llerrs << e.what() << llendl; + return; + } + + // Convert the glob mask to a regular expression + std::string exp = glob_to_regex(mask); + + // Initialize boost::regex with the expression converted from + // the glob mask. + // An exception is thrown if the expression is not valid. + try + { + mFilterExp.assign(exp); + } + catch (boost::regex_error& e) + { + llerrs << "\"" << exp << "\" is not a valid regular expression: " + << e.what() << llendl; + return; + } + + mIsValid = true; +} + +LLDirIterator::Impl::~Impl() +{ +} + +bool LLDirIterator::Impl::next(std::string &fname) +{ + fname = ""; + + if (!mIsValid) + { + llerrs << "The iterator is not correctly initialized." << llendl; + return false; + } + + fs::directory_iterator end_itr; // default construction yields past-the-end + bool found = false; + while (mIter != end_itr && !found) + { + boost::smatch match; + std::string name = mIter->path().filename(); + if (found = boost::regex_match(name, match, mFilterExp)) + { + fname = name; + } + + ++mIter; + } + + return found; +} + +std::string glob_to_regex(const std::string& glob) +{ + std::string regex; + regex.reserve(glob.size()<<1); + S32 braces = 0; + bool escaped = false; + bool square_brace_open = false; + + for (std::string::const_iterator i = glob.begin(); i != glob.end(); ++i) + { + char c = *i; + + switch (c) + { + case '.': + regex+="\\."; + break; + case '*': + if (glob.begin() == i) + { + regex+="[^.].*"; + } + else + { + regex+= escaped ? "*" : ".*"; + } + break; + case '?': + regex+= escaped ? '?' : '.'; + break; + case '{': + braces++; + regex+='('; + break; + case '}': + if (!braces) + { + llerrs << "glob_to_regex: Closing brace without an equivalent opening brace: " << glob << llendl; + } + + regex+=')'; + braces--; + break; + case ',': + regex+= braces ? '|' : c; + break; + case '!': + regex+= square_brace_open ? '^' : c; + break; + default: + regex+=c; + break; + } + + escaped = ('\\' == c); + square_brace_open = ('[' == c); + } + + if (braces) + { + llerrs << "glob_to_regex: Unterminated brace expression: " << glob << llendl; + } + + return regex; +} + +LLDirIterator::LLDirIterator(const std::string &dirname, const std::string &mask) +{ + mImpl = new Impl(dirname, mask); +} + +LLDirIterator::~LLDirIterator() +{ + delete mImpl; +} + +bool LLDirIterator::next(std::string &fname) +{ + return mImpl->next(fname); +} diff --git a/indra/llvfs/lldiriterator.h b/indra/llvfs/lldiriterator.h new file mode 100644 index 0000000000..0b48be41b3 --- /dev/null +++ b/indra/llvfs/lldiriterator.h @@ -0,0 +1,87 @@ +/** + * @file lldiriterator.h + * @brief Iterator through directory entries matching the search pattern. + * + * $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_LLDIRITERATOR_H +#define LL_LLDIRITERATOR_H + +#include "linden_common.h" + +/** + * Class LLDirIterator + * + * Iterates through directory entries matching the search pattern. + */ +class LLDirIterator +{ +public: + /** + * Constructs LLDirIterator object to search for glob pattern + * matches in a directory. + * + * @param dirname - name of a directory to search in. + * @param mask - search pattern, a glob expression + * + * Wildcards supported in glob expressions: + * -------------------------------------------------------------- + * | Wildcard | Matches | + * -------------------------------------------------------------- + * | * |zero or more characters | + * | ? |exactly one character | + * | [abcde] |exactly one character listed | + * | [a-e] |exactly one character in the given range | + * | [!abcde] |any character that is not listed | + * | [!a-e] |any character that is not in the given range | + * | {abc,xyz} |exactly one entire word in the options given | + * -------------------------------------------------------------- + */ + LLDirIterator(const std::string &dirname, const std::string &mask); + + ~LLDirIterator(); + + /** + * Searches for the next directory entry matching the glob mask + * specified upon iterator construction. + * Returns true if a match is found, sets fname + * parameter to the name of the matched directory entry and + * increments the iterator position. + * + * Typical usage: + * + * LLDirIterator iter(directory, pattern); + * if ( iter.next(scanResult) ) + * + * + * @param fname - name of the matched directory entry. + * @return true if a match is found, false otherwise. + */ + bool next(std::string &fname); + +protected: + class Impl; + Impl* mImpl; +}; + +#endif //LL_LLDIRITERATOR_H diff --git a/indra/llvfs/tests/lldir_test.cpp b/indra/llvfs/tests/lldir_test.cpp index 8788bd63e8..ea321c5ae9 100644 --- a/indra/llvfs/tests/lldir_test.cpp +++ b/indra/llvfs/tests/lldir_test.cpp @@ -28,6 +28,7 @@ #include "linden_common.h" #include "../lldir.h" +#include "../lldiriterator.h" #include "../test/lltut.h" @@ -259,13 +260,12 @@ namespace tut std::string makeTestFile( const std::string& dir, const std::string& file ) { - std::string delim = gDirUtilp->getDirDelimiter(); - std::string path = dir + delim + file; + std::string path = dir + file; LLFILE* handle = LLFile::fopen( path, "w" ); ensure("failed to open test file '"+path+"'", handle != NULL ); // Harbison & Steele, 4th ed., p. 366: "If an error occurs, fputs // returns EOF; otherwise, it returns some other, nonnegative value." - ensure("failed to write to test file '"+path+"'", fputs("test file", handle) >= 0); + ensure("failed to write to test file '"+path+"'", EOF != fputs("test file", handle) ); fclose(handle); return path; } @@ -290,7 +290,7 @@ namespace tut } static const char* DirScanFilename[5] = { "file1.abc", "file2.abc", "file1.xyz", "file2.xyz", "file1.mno" }; - + void scanTest(const std::string& directory, const std::string& pattern, bool correctResult[5]) { @@ -300,7 +300,8 @@ namespace tut bool filesFound[5] = { false, false, false, false, false }; //std::cerr << "searching '"+directory+"' for '"+pattern+"'\n"; - while ( found <= 5 && gDirUtilp->getNextFileInDir(directory, pattern, scanResult) ) + LLDirIterator iter(directory, pattern); + while ( found <= 5 && iter.next(scanResult) ) { found++; //std::cerr << " found '"+scanResult+"'\n"; @@ -334,15 +335,15 @@ namespace tut template<> template<> void LLDirTest_object_t::test<5>() - // getNextFileInDir + // LLDirIterator::next { std::string delim = gDirUtilp->getDirDelimiter(); std::string dirTemp = LLFile::tmpdir(); // Create the same 5 file names of the two directories - std::string dir1 = makeTestDir(dirTemp + "getNextFileInDir"); - std::string dir2 = makeTestDir(dirTemp + "getNextFileInDir"); + std::string dir1 = makeTestDir(dirTemp + "LLDirIterator"); + std::string dir2 = makeTestDir(dirTemp + "LLDirIterator"); std::string dir1files[5]; std::string dir2files[5]; for (int i=0; i<5; i++) @@ -380,19 +381,17 @@ namespace tut scanTest(dir2, "file?.x?z", expected7); // Scan dir2 and see if any file?.??c files are found - // THESE FAIL ON Mac and Windows, SO ARE COMMENTED OUT FOR NOW - // bool expected8[5] = { true, true, false, false, false }; - // scanTest(dir2, "file?.??c", expected8); - // scanTest(dir2, "*.??c", expected8); + bool expected8[5] = { true, true, false, false, false }; + scanTest(dir2, "file?.??c", expected8); + scanTest(dir2, "*.??c", expected8); // Scan dir1 and see if any *.?n? files are found bool expected9[5] = { false, false, false, false, true }; scanTest(dir1, "*.?n?", expected9); // Scan dir1 and see if any *.???? files are found - // THIS ONE FAILS ON WINDOWS (returns three charater suffixes) SO IS COMMENTED OUT FOR NOW - // bool expected10[5] = { false, false, false, false, false }; - // scanTest(dir1, "*.????", expected10); + bool expected10[5] = { false, false, false, false, false }; + scanTest(dir1, "*.????", expected10); // Scan dir1 and see if any ?????.* files are found bool expected11[5] = { true, true, true, true, true }; @@ -402,6 +401,15 @@ namespace tut bool expected12[5] = { false, false, true, true, false }; scanTest(dir1, "??l??.xyz", expected12); + bool expected13[5] = { true, false, true, false, false }; + scanTest(dir1, "file1.{abc,xyz}", expected13); + + bool expected14[5] = { true, true, false, false, false }; + scanTest(dir1, "file[0-9].abc", expected14); + + bool expected15[5] = { true, true, false, false, false }; + scanTest(dir1, "file[!a-z].abc", expected15); + // clean up all test files and directories for (int i=0; i<5; i++) { -- cgit v1.2.3 From 7fc9d701190a75c8f96a0a808d793dbc34860916 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 17 Dec 2010 19:52:45 -0800 Subject: For object-vs-parcel overlap we now use list of axis aligned boxes one box for each prim, for less slop on queries --- indra/newview/llviewerobject.cpp | 15 ++++++++----- indra/newview/llviewerparceloverlay.cpp | 39 +++++++++++++++++---------------- indra/newview/llviewerparceloverlay.h | 6 ++--- indra/newview/llviewerregion.cpp | 4 ++-- indra/newview/llviewerregion.h | 2 +- 5 files changed, 35 insertions(+), 31 deletions(-) diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index ae2154d63b..18d6e4c8c8 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -518,18 +518,21 @@ void LLViewerObject::setNameValueList(const std::string& name_value_list) // agent. bool LLViewerObject::isReturnable() { - LLBBox bounding_box(getPositionRegion(), getRotationRegion(), getScale() * -0.5f, getScale() * 0.5f); + if (isAttachment()) + { + return false; + } + std::vector boxes; + boxes.push_back(LLBBox(getPositionRegion(), getRotationRegion(), getScale() * -0.5f, getScale() * 0.5f).getAxisAligned()); for (child_list_t::iterator iter = mChildList.begin(); iter != mChildList.end(); iter++) { LLViewerObject* child = *iter; - LLBBox child_box(child->getPositionRegion(), child->getRotationRegion(), child->getScale() * -0.5f, child->getScale() * 0.5f); - bounding_box.addBBoxAgent(child_box); + boxes.push_back(LLBBox(child->getPositionRegion(), child->getRotationRegion(), child->getScale() * -0.5f, child->getScale() * 0.5f).getAxisAligned()); } - return !isAttachment() - && mRegionp - && mRegionp->objectIsReturnable(getPositionRegion(), bounding_box); + return mRegionp + && mRegionp->objectIsReturnable(getPositionRegion(), boxes); } BOOL LLViewerObject::setParent(LLViewerObject* parent) diff --git a/indra/newview/llviewerparceloverlay.cpp b/indra/newview/llviewerparceloverlay.cpp index 58d9009c90..395da5a036 100644 --- a/indra/newview/llviewerparceloverlay.cpp +++ b/indra/newview/llviewerparceloverlay.cpp @@ -145,27 +145,28 @@ BOOL LLViewerParcelOverlay::isOwnedOther(const LLVector3& pos) const return (PARCEL_OWNED == overlay || PARCEL_FOR_SALE == overlay); } -bool LLViewerParcelOverlay::encroachesOwned(const LLBBox& bbox) const +bool LLViewerParcelOverlay::encroachesOwned(const std::vector& boxes) const { - LLBBox bbox_aligned = bbox.getAxisAligned(); - - LLVector3 min = bbox_aligned.getMinAgent(); - LLVector3 max = bbox_aligned.getMaxAgent(); + // boxes are expected to already be axis aligned + for (S32 i = 0; i < boxes.size(); ++i) + { + LLVector3 min = boxes[i].getMinAgent(); + LLVector3 max = boxes[i].getMaxAgent(); + + S32 left = S32(llclamp((min.mV[VX] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1)); + S32 right = S32(llclamp((max.mV[VX] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1)); + S32 top = S32(llclamp((min.mV[VY] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1)); + S32 bottom = S32(llclamp((max.mV[VY] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1)); - S32 left = S32(llclamp((min.mV[VX] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1)); - S32 right = S32(llclamp((max.mV[VX] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1)); - S32 top = S32(llclamp((min.mV[VY] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1)); - S32 bottom = S32(llclamp((max.mV[VY] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1)); - - for (S32 row = top; row <= bottom; row++) - for (S32 column = left; column <= right; column++) - { - U8 type = ownership(row, column); - if (PARCEL_SELF == type - || PARCEL_GROUP == type ) - return true; - } - + for (S32 row = top; row <= bottom; row++) + for (S32 column = left; column <= right; column++) + { + U8 type = ownership(row, column); + if (PARCEL_SELF == type + || PARCEL_GROUP == type ) + return true; + } + } return false; } diff --git a/indra/newview/llviewerparceloverlay.h b/indra/newview/llviewerparceloverlay.h index 4aa42eb8a4..c80baedda6 100644 --- a/indra/newview/llviewerparceloverlay.h +++ b/indra/newview/llviewerparceloverlay.h @@ -57,9 +57,9 @@ public: BOOL isOwnedOther(const LLVector3& pos) const; // "encroaches" means the prim hangs over the parcel, but its center - // might be in another parcel. for now, we simply test bounding boxes - // which isn't perfect, but is close - bool encroachesOwned(const LLBBox& bbox) const; + // might be in another parcel. for now, we simply test axis aligned + // bounding boxes which isn't perfect, but is close + bool encroachesOwned(const std::vector& boxes) const; BOOL isSoundLocal(const LLVector3& pos) const; diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index 43b26fe830..32e7cc3468 100644 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -1500,13 +1500,13 @@ LLSpatialPartition* LLViewerRegion::getSpatialPartition(U32 type) const U32 ALLOW_RETURN_ENCROACHING_OBJECT = REGION_FLAGS_ALLOW_RETURN_ENCROACHING_OBJECT | REGION_FLAGS_ALLOW_RETURN_ENCROACHING_ESTATE_OBJECT; -bool LLViewerRegion::objectIsReturnable(const LLVector3& pos, const LLBBox& bbox) +bool LLViewerRegion::objectIsReturnable(const LLVector3& pos, const std::vector& boxes) const { return (mParcelOverlay != NULL) && (mParcelOverlay->isOwnedSelf(pos) || mParcelOverlay->isOwnedGroup(pos) || ((mRegionFlags & ALLOW_RETURN_ENCROACHING_OBJECT) - && mParcelOverlay->encroachesOwned(bbox)) ); + && mParcelOverlay->encroachesOwned(boxes)) ); } void LLViewerRegion::showReleaseNotes() diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h index 76228c0d2a..3d3f1d62a6 100644 --- a/indra/newview/llviewerregion.h +++ b/indra/newview/llviewerregion.h @@ -295,7 +295,7 @@ public: LLSpatialPartition* getSpatialPartition(U32 type); - bool objectIsReturnable(const LLVector3& pos, const LLBBox& bbox); + bool objectIsReturnable(const LLVector3& pos, const std::vector& boxes) const; public: struct CompareDistance { -- cgit v1.2.3 From 049b00a6f10d50609055810b0800f49476b351d2 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 20 Dec 2010 09:03:59 -0800 Subject: Fixing windows build error about inequality comparison between S32 and U32. --- indra/newview/llviewerparceloverlay.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/llviewerparceloverlay.cpp b/indra/newview/llviewerparceloverlay.cpp index 395da5a036..1207ef3340 100644 --- a/indra/newview/llviewerparceloverlay.cpp +++ b/indra/newview/llviewerparceloverlay.cpp @@ -148,7 +148,7 @@ BOOL LLViewerParcelOverlay::isOwnedOther(const LLVector3& pos) const bool LLViewerParcelOverlay::encroachesOwned(const std::vector& boxes) const { // boxes are expected to already be axis aligned - for (S32 i = 0; i < boxes.size(); ++i) + for (U32 i = 0; i < boxes.size(); ++i) { LLVector3 min = boxes[i].getMinAgent(); LLVector3 max = boxes[i].getMaxAgent(); -- cgit v1.2.3 From 9b3893d9d1a66aa97b33d5f024e5c015735d93f7 Mon Sep 17 00:00:00 2001 From: Paul Guslisty Date: Mon, 20 Dec 2010 19:39:32 +0200 Subject: STORM-387 FIXED Part of the table is hided after increasing firsts column width in the floater and then dock it to the SP - Replaced absolute width of columns with relative --- indra/newview/skins/default/xui/en/panel_group_land_money.xml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/indra/newview/skins/default/xui/en/panel_group_land_money.xml b/indra/newview/skins/default/xui/en/panel_group_land_money.xml index 1270a21710..2c1880cac6 100644 --- a/indra/newview/skins/default/xui/en/panel_group_land_money.xml +++ b/indra/newview/skins/default/xui/en/panel_group_land_money.xml @@ -67,23 +67,23 @@ + relative_width="0.2" /> + relative_width="0.2" /> + relative_width="0.2" /> + relative_width="0.2" /> + relative_width="0.2" /> Date: Mon, 20 Dec 2010 13:54:32 -0500 Subject: fix for ER-350; wait until connection is finished before send update. rvw'd by Nyx --- indra/newview/llviewermessage.cpp | 69 ++++++++++++++++++++------------------- 1 file changed, 35 insertions(+), 34 deletions(-) diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 5cbd5ffa0b..f2fee88f56 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -4055,54 +4055,55 @@ void send_agent_update(BOOL force_send, BOOL send_reliable) if (duplicate_count < DUP_MSGS && !gDisconnected) { - LLFastTimer t(FTM_AGENT_UPDATE_SEND); - // Build the message - msg->newMessageFast(_PREHASH_AgentUpdate); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->addQuatFast(_PREHASH_BodyRotation, body_rotation); - msg->addQuatFast(_PREHASH_HeadRotation, head_rotation); - msg->addU8Fast(_PREHASH_State, render_state); - msg->addU8Fast(_PREHASH_Flags, flags); + if (LLStartUp::getStartupState() >= STATE_STARTED) + { + LLFastTimer t(FTM_AGENT_UPDATE_SEND); + // Build the message + msg->newMessageFast(_PREHASH_AgentUpdate); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->addQuatFast(_PREHASH_BodyRotation, body_rotation); + msg->addQuatFast(_PREHASH_HeadRotation, head_rotation); + msg->addU8Fast(_PREHASH_State, render_state); + msg->addU8Fast(_PREHASH_Flags, flags); // if (camera_pos_agent.mV[VY] > 255.f) // { // LL_INFOS("Messaging") << "Sending camera center " << camera_pos_agent << LL_ENDL; // } - msg->addVector3Fast(_PREHASH_CameraCenter, camera_pos_agent); - msg->addVector3Fast(_PREHASH_CameraAtAxis, LLViewerCamera::getInstance()->getAtAxis()); - msg->addVector3Fast(_PREHASH_CameraLeftAxis, LLViewerCamera::getInstance()->getLeftAxis()); - msg->addVector3Fast(_PREHASH_CameraUpAxis, LLViewerCamera::getInstance()->getUpAxis()); - msg->addF32Fast(_PREHASH_Far, gAgentCamera.mDrawDistance); + msg->addVector3Fast(_PREHASH_CameraCenter, camera_pos_agent); + msg->addVector3Fast(_PREHASH_CameraAtAxis, LLViewerCamera::getInstance()->getAtAxis()); + msg->addVector3Fast(_PREHASH_CameraLeftAxis, LLViewerCamera::getInstance()->getLeftAxis()); + msg->addVector3Fast(_PREHASH_CameraUpAxis, LLViewerCamera::getInstance()->getUpAxis()); + msg->addF32Fast(_PREHASH_Far, gAgentCamera.mDrawDistance); - msg->addU32Fast(_PREHASH_ControlFlags, control_flags); + msg->addU32Fast(_PREHASH_ControlFlags, control_flags); - if (gDebugClicks) - { - if (control_flags & AGENT_CONTROL_LBUTTON_DOWN) + if (gDebugClicks) { - LL_INFOS("Messaging") << "AgentUpdate left button down" << LL_ENDL; + if (control_flags & AGENT_CONTROL_LBUTTON_DOWN) + { + LL_INFOS("Messaging") << "AgentUpdate left button down" << LL_ENDL; + } + + if (control_flags & AGENT_CONTROL_LBUTTON_UP) + { + LL_INFOS("Messaging") << "AgentUpdate left button up" << LL_ENDL; + } } - if (control_flags & AGENT_CONTROL_LBUTTON_UP) + gAgent.enableControlFlagReset(); + if (!send_reliable) { - LL_INFOS("Messaging") << "AgentUpdate left button up" << LL_ENDL; + gAgent.sendMessage(); + } + else + { + gAgent.sendReliableMessage(); } } - - gAgent.enableControlFlagReset(); - - if (!send_reliable) - { - gAgent.sendMessage(); - } - else - { - gAgent.sendReliableMessage(); - } - // LL_DEBUGS("Messaging") << "agent " << avatar_pos_agent << " cam " << camera_pos_agent << LL_ENDL; // Copy the old data -- cgit v1.2.3 From 375bdb6d1eb58e7f9f84be947d05ca44e550752d Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 22 Dec 2010 10:06:36 -0800 Subject: removing some very old debug spam --- indra/newview/llvoavatar.cpp | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index bb4c5b1804..fd89044995 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -2106,31 +2106,6 @@ void LLVOAvatar::computeBodySize() gAgent.sendAgentSetAppearance(); } } - -/* debug spam - std::cout << "skull = " << skull << std::endl; // adebug - std::cout << "head = " << head << std::endl; // adebug - std::cout << "head_scale = " << head_scale << std::endl; // adebug - std::cout << "neck = " << neck << std::endl; // adebug - std::cout << "neck_scale = " << neck_scale << std::endl; // adebug - std::cout << "chest = " << chest << std::endl; // adebug - std::cout << "chest_scale = " << chest_scale << std::endl; // adebug - std::cout << "torso = " << torso << std::endl; // adebug - std::cout << "torso_scale = " << torso_scale << std::endl; // adebug - std::cout << std::endl; // adebug - - std::cout << "pelvis_scale = " << pelvis_scale << std::endl;// adebug - std::cout << std::endl; // adebug - - std::cout << "hip = " << hip << std::endl; // adebug - std::cout << "hip_scale = " << hip_scale << std::endl; // adebug - std::cout << "ankle = " << ankle << std::endl; // adebug - std::cout << "ankle_scale = " << ankle_scale << std::endl; // adebug - std::cout << "foot = " << foot << std::endl; // adebug - std::cout << "mBodySize = " << mBodySize << std::endl; // adebug - std::cout << "mPelvisToFoot = " << mPelvisToFoot << std::endl; // adebug - std::cout << std::endl; // adebug -*/ } //------------------------------------------------------------------------ -- cgit v1.2.3 From 9b0e4d20a96ad01de33ec6d4ff87cb2a15d36d58 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 22 Dec 2010 10:47:18 -0800 Subject: Setting viewer version numbers back to what they were as per Merov's review request. --- indra/llcommon/llversionviewer.h | 2 +- indra/newview/English.lproj/InfoPlist.strings | 4 ++-- indra/newview/Info-SecondLife.plist | 2 +- indra/newview/res/viewerRes.rc | 8 ++++---- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/indra/llcommon/llversionviewer.h b/indra/llcommon/llversionviewer.h index 356e0f4c0f..d6fa5b1997 100644 --- a/indra/llcommon/llversionviewer.h +++ b/indra/llcommon/llversionviewer.h @@ -35,7 +35,7 @@ const S32 LL_VERSION_BUILD = 0; const char * const LL_CHANNEL = "Second Life Developer"; #if LL_DARWIN -const char * const LL_VERSION_BUNDLE_ID = "com.secondlife.indra.viewer"; +const char * const LL_VERSION_BUNDLE_ID = "com.secondlife.snowglobe.viewer"; #endif #endif diff --git a/indra/newview/English.lproj/InfoPlist.strings b/indra/newview/English.lproj/InfoPlist.strings index fb1c465493..4bf67b1367 100644 --- a/indra/newview/English.lproj/InfoPlist.strings +++ b/indra/newview/English.lproj/InfoPlist.strings @@ -2,6 +2,6 @@ CFBundleName = "Second Life"; -CFBundleShortVersionString = "Second Life version 2.4.0.211776"; -CFBundleGetInfoString = "Second Life version 2.4.0.211776, Copyright 2004-2010 Linden Research, Inc."; +CFBundleShortVersionString = "Second Life version 2.1.1.0"; +CFBundleGetInfoString = "Second Life version 2.1.1.0, Copyright 2004-2010 Linden Research, Inc."; diff --git a/indra/newview/Info-SecondLife.plist b/indra/newview/Info-SecondLife.plist index 5412fd5d5c..3cda7467dd 100644 --- a/indra/newview/Info-SecondLife.plist +++ b/indra/newview/Info-SecondLife.plist @@ -60,7 +60,7 @@ CFBundleVersion - 2.4.0.211776 + 2.1.1.0 CSResourcesFileMapped diff --git a/indra/newview/res/viewerRes.rc b/indra/newview/res/viewerRes.rc index d71a4abe3c..5e8cee1f5f 100644 --- a/indra/newview/res/viewerRes.rc +++ b/indra/newview/res/viewerRes.rc @@ -129,8 +129,8 @@ TOOLSIT CURSOR "toolsit.cur" // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,4,0,211776 - PRODUCTVERSION 2,4,0,211776 + FILEVERSION 2,1,1,0 + PRODUCTVERSION 2,1,1,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -147,12 +147,12 @@ BEGIN BEGIN VALUE "CompanyName", "Linden Lab" VALUE "FileDescription", "Second Life" - VALUE "FileVersion", "2.4.0.211776" + VALUE "FileVersion", "2.1.1.0" VALUE "InternalName", "Second Life" VALUE "LegalCopyright", "Copyright � 2001-2010, Linden Research, Inc." VALUE "OriginalFilename", "SecondLife.exe" VALUE "ProductName", "Second Life" - VALUE "ProductVersion", "2.4.0.211776" + VALUE "ProductVersion", "2.1.1.0" END END BLOCK "VarFileInfo" -- cgit v1.2.3 From 649dd6eb74023d48379ebaadd2ff000801306f17 Mon Sep 17 00:00:00 2001 From: Don Kjer Date: Wed, 22 Dec 2010 14:23:35 -0800 Subject: Cleanup from review with Andrew and Merov --- indra/newview/llviewerobject.cpp | 4 ++-- indra/newview/llviewerobject.h | 4 ++-- indra/newview/llviewerobjectlist.cpp | 12 +++++------ indra/newview/llviewerregion.cpp | 42 ++++++++++++++++-------------------- indra/newview/llvocache.cpp | 2 +- 5 files changed, 30 insertions(+), 34 deletions(-) diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 3c12cb66b2..4b7e518af3 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -5402,7 +5402,7 @@ void LLViewerObject::setAttachmentItemID(const LLUUID &id) mAttachmentItemID = id; } -EObjectUpdateType LLViewerObject::getLastUpdateType() +EObjectUpdateType LLViewerObject::getLastUpdateType() const { return mLastUpdateType; } @@ -5412,7 +5412,7 @@ void LLViewerObject::setLastUpdateType(EObjectUpdateType last_update_type) mLastUpdateType = last_update_type; } -BOOL LLViewerObject::getLastUpdateCached() +BOOL LLViewerObject::getLastUpdateCached() const { return mLastUpdateCached; } diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index c83cc06128..78837ec0a1 100644 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -697,9 +697,9 @@ public: const LLUUID &getAttachmentItemID() const; void setAttachmentItemID(const LLUUID &id); const LLUUID &extractAttachmentItemID(); // find&set the inventory item ID of the attached object - EObjectUpdateType getLastUpdateType(); + EObjectUpdateType getLastUpdateType() const; void setLastUpdateType(EObjectUpdateType last_update_type); - BOOL getLastUpdateCached(); + BOOL getLastUpdateCached() const; void setLastUpdateCached(BOOL last_update_cached); private: diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp index 77fbc08ca4..5849ab4307 100644 --- a/indra/newview/llviewerobjectlist.cpp +++ b/indra/newview/llviewerobjectlist.cpp @@ -306,7 +306,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, // I don't think this case is ever hit. TODO* Test this. if (!cached && !compressed && update_type != OUT_FULL) { - llinfos << "TEST: !cached && !compressed && update_type != OUT_FULL" << llendl; + //llinfos << "TEST: !cached && !compressed && update_type != OUT_FULL" << llendl; gTerseObjectUpdates += num_objects; S32 size; if (mesgsys->getReceiveCompressedSize()) @@ -317,7 +317,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, { size = mesgsys->getReceiveSize(); } - llinfos << "Received terse " << num_objects << " in " << size << " byte (" << size/num_objects << ")" << llendl; + //llinfos << "Received terse " << num_objects << " in " << size << " byte (" << size/num_objects << ")" << llendl; } else { @@ -403,7 +403,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, // I don't think we ever use this flag from the server. DK 2010/12/09 if (flags & FLAGS_ZLIB_COMPRESSED) { - llinfos << "TEST: flags & FLAGS_ZLIB_COMPRESSED" << llendl; + //llinfos << "TEST: flags & FLAGS_ZLIB_COMPRESSED" << llendl; compressed_length = mesgsys->getSizeFast(_PREHASH_ObjectData, i, _PREHASH_Data); mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_Data, compbuffer, 0, i); uncompressed_length = 2048; @@ -500,7 +500,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, { if (update_type == OUT_TERSE_IMPROVED) { - llinfos << "terse update for an unknown object (compressed):" << fullid << llendl; + // llinfos << "terse update for an unknown object (compressed):" << fullid << llendl; #if LL_RECORD_VIEWER_STATS LLViewerStatsRecorder::instance()->recordObjectUpdateFailure(local_id, update_type); #endif @@ -514,7 +514,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, { if (update_type != OUT_FULL) { - llinfos << "terse update for an unknown object:" << fullid << llendl; + //llinfos << "terse update for an unknown object:" << fullid << llendl; #if LL_RECORD_VIEWER_STATS LLViewerStatsRecorder::instance()->recordObjectUpdateFailure(local_id, update_type); #endif @@ -527,7 +527,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, if (mDeadObjects.find(fullid) != mDeadObjects.end()) { mNumDeadObjectUpdates++; - llinfos << "update for a dead object:" << fullid << llendl; + //llinfos << "update for a dead object:" << fullid << llendl; #if LL_RECORD_VIEWER_STATS LLViewerStatsRecorder::instance()->recordObjectUpdateFailure(local_id, update_type); #endif diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index ea6f1ab342..4648f318d4 100644 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -1049,33 +1049,29 @@ LLViewerRegion::eCacheUpdateResult LLViewerRegion::cacheFullUpdate(LLViewerObjec entry->recordDupe(); return CACHE_UPDATE_DUPE; } - else - { - // Update the cache entry - mCacheMap.erase(local_id); - delete entry; - entry = new LLVOCacheEntry(local_id, crc, dp); - mCacheMap[local_id] = entry; - return CACHE_UPDATE_CHANGED; - } - } - else - { - // we haven't seen this object before - // Create new entry and add to map - eCacheUpdateResult result = CACHE_UPDATE_ADDED; - if (mCacheMap.size() > MAX_OBJECT_CACHE_ENTRIES) - { - mCacheMap.erase(mCacheMap.begin()); - result = CACHE_UPDATE_REPLACED; - - } + // Update the cache entry + mCacheMap.erase(local_id); + delete entry; entry = new LLVOCacheEntry(local_id, crc, dp); - mCacheMap[local_id] = entry; - return result; + return CACHE_UPDATE_CHANGED; + } + + // we haven't seen this object before + + // Create new entry and add to map + eCacheUpdateResult result = CACHE_UPDATE_ADDED; + if (mCacheMap.size() > MAX_OBJECT_CACHE_ENTRIES) + { + mCacheMap.erase(mCacheMap.begin()); + result = CACHE_UPDATE_REPLACED; + } + entry = new LLVOCacheEntry(local_id, crc, dp); + + mCacheMap[local_id] = entry; + return result; } // Get data packer for this object, if we have cached data diff --git a/indra/newview/llvocache.cpp b/indra/newview/llvocache.cpp index 040139f3ab..d372fd0212 100644 --- a/indra/newview/llvocache.cpp +++ b/indra/newview/llvocache.cpp @@ -593,7 +593,7 @@ void LLVOCache::readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::voca void LLVOCache::purgeEntries() { - U32 limit = mCacheSize / ENTRIES_PURGE_FACTOR; + U32 limit = mCacheSize - (mCacheSize / ENTRIES_PURGE_FACTOR); limit = llclamp(limit, (U32)1, mCacheSize); // Construct a vector of entries out of the map so we can sort by time. std::vector header_vector; -- cgit v1.2.3 From 8dad2e56f3d87769a47e9b89455274a130267cc9 Mon Sep 17 00:00:00 2001 From: Xiaohong Bao Date: Thu, 23 Dec 2010 11:42:17 -0700 Subject: fix for SH-416: crash at LLFace::getGeometryVolume line 1003 --- indra/llprimitive/lltextureentry.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/llprimitive/lltextureentry.cpp b/indra/llprimitive/lltextureentry.cpp index 3c1d031ff5..861bde5c89 100644 --- a/indra/llprimitive/lltextureentry.cpp +++ b/indra/llprimitive/lltextureentry.cpp @@ -403,7 +403,7 @@ S32 LLTextureEntry::setOffsetT(F32 t) S32 LLTextureEntry::setRotation(F32 theta) { - if (mRotation != theta) + if (mRotation != theta && llfinite(theta)) { mRotation = theta; return TEM_CHANGE_TEXTURE; -- cgit v1.2.3 From 0c0f3d8f5c36d1616113785f73f6404edfcb6d90 Mon Sep 17 00:00:00 2001 From: Don Kjer Date: Thu, 23 Dec 2010 14:50:38 -0800 Subject: Bumping max number of objects to cache per region to 20k, from 10k. --- indra/newview/llviewerregion.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h index 5e17f3352d..782e48b716 100644 --- a/indra/newview/llviewerregion.h +++ b/indra/newview/llviewerregion.h @@ -50,7 +50,7 @@ // Surface id's #define LAND 1 #define WATER 2 -const U32 MAX_OBJECT_CACHE_ENTRIES = 10000; +const U32 MAX_OBJECT_CACHE_ENTRIES = 20000; class LLEventPoll; -- cgit v1.2.3 From 4aeb27232e6da5f2e00da8671e05bb5a8f277ba9 Mon Sep 17 00:00:00 2001 From: Don Kjer Date: Thu, 23 Dec 2010 14:54:41 -0800 Subject: Bumping max object cache entries per region to 50k, from 20k (per conversation with maestro about attachments also being included in this set) --- indra/newview/llviewerregion.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h index 782e48b716..dcefe87b69 100644 --- a/indra/newview/llviewerregion.h +++ b/indra/newview/llviewerregion.h @@ -50,7 +50,7 @@ // Surface id's #define LAND 1 #define WATER 2 -const U32 MAX_OBJECT_CACHE_ENTRIES = 20000; +const U32 MAX_OBJECT_CACHE_ENTRIES = 50000; class LLEventPoll; -- cgit v1.2.3 From 6150e4ed7cf86a2afc0061ba89b0cb049d6f036e Mon Sep 17 00:00:00 2001 From: Jonathan Yap Date: Wed, 29 Dec 2010 18:25:40 -0500 Subject: VWR-24347 Fix reversion--allow VS2005 Express user to specify location of msvc* files --- indra/cmake/Copy3rdPartyLibs.cmake | 2 ++ 1 file changed, 2 insertions(+) diff --git a/indra/cmake/Copy3rdPartyLibs.cmake b/indra/cmake/Copy3rdPartyLibs.cmake index 176ae9787e..1b08c3fd2e 100644 --- a/indra/cmake/Copy3rdPartyLibs.cmake +++ b/indra/cmake/Copy3rdPartyLibs.cmake @@ -66,6 +66,7 @@ if(WINDOWS) if (MSVC80) FIND_PATH(debug_msvc8_redist_path msvcr80d.dll PATHS + ${MSVC_DEBUG_REDIST_PATH} [HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\8.0\\Setup\\VC;ProductDir]/redist/Debug_NonRedist/x86/Microsoft.VC80.DebugCRT NO_DEFAULT_PATH NO_DEFAULT_PATH @@ -90,6 +91,7 @@ if (MSVC80) FIND_PATH(release_msvc8_redist_path msvcr80.dll PATHS + ${MSVC_REDIST_PATH} [HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\8.0\\Setup\\VC;ProductDir]/redist/x86/Microsoft.VC80.CRT NO_DEFAULT_PATH NO_DEFAULT_PATH -- cgit v1.2.3 From 376ee7a3f9a07f584386e45516645ce3acbe3cb6 Mon Sep 17 00:00:00 2001 From: Seth ProductEngine Date: Thu, 30 Dec 2010 18:18:33 +0200 Subject: STORM-797 FIXED Added parcel SLURL rendering with human readable parcel names. - Added parcel info observer to LLUrlEntryParcel. - Added notifying LLUrlEntryParcel by LLRemoteParcelInfoProcessor when parcel data arrives. - Added notifying LLUrlEntryParcel about user login, changing host and viewer connection state to use this data in remote parcel requests. --- indra/llui/llurlentry.cpp | 83 ++++++++++++++++++++++ indra/llui/llurlentry.h | 39 ++++++++++ indra/llui/tests/llurlentry_stub.cpp | 18 +++++ indra/newview/llagent.cpp | 5 ++ indra/newview/llappviewer.cpp | 5 ++ indra/newview/llremoteparcelrequest.cpp | 13 ++++ indra/newview/llstartup.cpp | 9 +++ indra/newview/tests/llremoteparcelrequest_test.cpp | 2 + 8 files changed, 174 insertions(+) diff --git a/indra/llui/llurlentry.cpp b/indra/llui/llurlentry.cpp index 4f7b4be526..06b3c17967 100644 --- a/indra/llui/llurlentry.cpp +++ b/indra/llui/llurlentry.cpp @@ -36,6 +36,7 @@ #include "llcachename.h" #include "lltrans.h" #include "lluicolortable.h" +#include "message.h" #define APP_HEADER_REGEX "((x-grid-location-info://[-\\w\\.]+/app)|(secondlife:///app))" @@ -740,6 +741,13 @@ std::string LLUrlEntryObjectIM::getLocation(const std::string &url) const return LLUrlEntryBase::getLocation(url); } +// LLUrlEntryParcel statics. +LLUUID LLUrlEntryParcel::sAgentID(LLUUID::null); +LLUUID LLUrlEntryParcel::sSessionID(LLUUID::null); +LLHost LLUrlEntryParcel::sRegionHost(LLHost::invalid); +bool LLUrlEntryParcel::sDisconnected(false); +std::set LLUrlEntryParcel::sParcelInfoObservers; + /// /// LLUrlEntryParcel Describes a Second Life parcel Url, e.g., /// secondlife:///app/parcel/0000060e-4b39-e00b-d0c3-d98b1934e3a8/about @@ -751,13 +759,88 @@ LLUrlEntryParcel::LLUrlEntryParcel() boost::regex::perl|boost::regex::icase); mMenuName = "menu_url_parcel.xml"; mTooltip = LLTrans::getString("TooltipParcelUrl"); + + sParcelInfoObservers.insert(this); +} + +LLUrlEntryParcel::~LLUrlEntryParcel() +{ + sParcelInfoObservers.erase(this); } std::string LLUrlEntryParcel::getLabel(const std::string &url, const LLUrlLabelCallback &cb) { + LLSD path_array = LLURI(url).pathArray(); + S32 path_parts = path_array.size(); + + if (path_parts < 3) // no parcel id + { + llwarns << "Failed to parse url [" << url << "]" << llendl; + return url; + } + + std::string parcel_id_string = unescapeUrl(path_array[2]); // parcel id + + // Add an observer to call LLUrlLabelCallback when we have parcel name. + addObserver(parcel_id_string, url, cb); + + LLUUID parcel_id(parcel_id_string); + + sendParcelInfoRequest(parcel_id); + return unescapeUrl(url); } +void LLUrlEntryParcel::sendParcelInfoRequest(const LLUUID& parcel_id) +{ + if (sRegionHost == LLHost::invalid || sDisconnected) return; + + LLMessageSystem *msg = gMessageSystem; + msg->newMessage("ParcelInfoRequest"); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, sAgentID ); + msg->addUUID("SessionID", sSessionID); + msg->nextBlock("Data"); + msg->addUUID("ParcelID", parcel_id); + msg->sendReliable(sRegionHost); +} + +void LLUrlEntryParcel::onParcelInfoReceived(const std::string &id, const std::string &label) +{ + callObservers(id, label.empty() ? LLTrans::getString("RegionInfoError") : label, mIcon); +} + +// static +void LLUrlEntryParcel::processParcelInfo(const LLParcelData& parcel_data) +{ + std::string label(LLStringUtil::null); + if (!parcel_data.name.empty()) + { + label = parcel_data.name; + } + // If parcel name is empty use Sim_name (x, y, z) for parcel label. + else if (!parcel_data.sim_name.empty()) + { + S32 region_x = llround(parcel_data.global_x) % REGION_WIDTH_UNITS; + S32 region_y = llround(parcel_data.global_y) % REGION_WIDTH_UNITS; + S32 region_z = llround(parcel_data.global_z); + + label = llformat("%s (%d, %d, %d)", + parcel_data.sim_name.c_str(), region_x, region_y, region_z); + } + + for (std::set::iterator iter = sParcelInfoObservers.begin(); + iter != sParcelInfoObservers.end(); + ++iter) + { + LLUrlEntryParcel* url_entry = *iter; + if (url_entry) + { + url_entry->onParcelInfoReceived(parcel_data.parcel_id.asString(), label); + } + } +} + // // LLUrlEntryPlace Describes secondlife:// URLs // diff --git a/indra/llui/llurlentry.h b/indra/llui/llurlentry.h index 1791739061..5f82721c0f 100644 --- a/indra/llui/llurlentry.h +++ b/indra/llui/llurlentry.h @@ -31,6 +31,9 @@ #include "lluuid.h" #include "lluicolor.h" #include "llstyle.h" + +#include "llhost.h" // for resolving parcel name by parcel id + #include #include #include @@ -285,8 +288,44 @@ private: class LLUrlEntryParcel : public LLUrlEntryBase { public: + struct LLParcelData + { + LLUUID parcel_id; + std::string name; + std::string sim_name; + F32 global_x; + F32 global_y; + F32 global_z; + }; + LLUrlEntryParcel(); + ~LLUrlEntryParcel(); /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); + + // Sends a parcel info request to sim. + void sendParcelInfoRequest(const LLUUID& parcel_id); + + // Calls observers of certain parcel id providing them with parcel label. + void onParcelInfoReceived(const std::string &id, const std::string &label); + + // Processes parcel label and triggers notifying observers. + static void processParcelInfo(const LLParcelData& parcel_data); + + // Next 4 setters are used to update agent and viewer connection information + // upon events like user login, viewer disconnect and user changing region host. + // These setters are made public to be accessible from newview and should not be + // used in other cases. + static void setAgentID(const LLUUID& id) { sAgentID = id; } + static void setSessionID(const LLUUID& id) { sSessionID = id; } + static void setRegionHost(const LLHost& host) { sRegionHost = host; } + static void setDisconnected(bool disconnected) { sDisconnected = disconnected; } + +private: + static LLUUID sAgentID; + static LLUUID sSessionID; + static LLHost sRegionHost; + static bool sDisconnected; + static std::set sParcelInfoObservers; }; /// diff --git a/indra/llui/tests/llurlentry_stub.cpp b/indra/llui/tests/llurlentry_stub.cpp index f30704cb22..96ebe83826 100644 --- a/indra/llui/tests/llurlentry_stub.cpp +++ b/indra/llui/tests/llurlentry_stub.cpp @@ -30,6 +30,7 @@ #include "llavatarnamecache.h" #include "llcachename.h" #include "lluuid.h" +#include "message.h" #include @@ -191,3 +192,20 @@ LLFontGL* LLFontGL::getFontDefault() { return NULL; } + +char* _PREHASH_AgentData = "AgentData"; +char* _PREHASH_AgentID = "AgentID"; + +LLHost LLHost::invalid(INVALID_PORT,INVALID_HOST_IP_ADDRESS); + +LLMessageSystem* gMessageSystem = NULL; + +// +// Stub implementation for LLMessageSystem +// +void LLMessageSystem::newMessage(const char *name) { } +void LLMessageSystem::nextBlockFast(const char *blockname) { } +void LLMessageSystem::nextBlock(const char *blockname) { } +void LLMessageSystem::addUUIDFast( const char *varname, const LLUUID& uuid) { } +void LLMessageSystem::addUUID( const char *varname, const LLUUID& uuid) { } +S32 LLMessageSystem::sendReliable(const LLHost &host) { return 0; } diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index 77552663ab..7d908df5ce 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -64,6 +64,7 @@ #include "lltool.h" #include "lltoolmgr.h" #include "lltrans.h" +#include "llurlentry.h" #include "llviewercontrol.h" #include "llviewerdisplay.h" #include "llviewerjoystick.h" @@ -649,6 +650,10 @@ void LLAgent::setRegion(LLViewerRegion *regionp) } mRegionp = regionp; + // Pass the region host to LLUrlEntryParcel to resolve parcel name + // with a server request. + LLUrlEntryParcel::setRegionHost(getRegionHost()); + // Must shift hole-covering water object locations because local // coordinate frame changed. LLWorld::getInstance()->updateWaterObjects(); diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 3a98c23e05..729f83a2b1 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -93,6 +93,7 @@ #include "llmemory.h" #include "llprimitive.h" #include "llurlaction.h" +#include "llurlentry.h" #include "llvfile.h" #include "llvfsthread.h" #include "llvolumemgr.h" @@ -4567,6 +4568,10 @@ void LLAppViewer::disconnectViewer() cleanup_xfer_manager(); gDisconnected = TRUE; + + // Pass the connection state to LLUrlEntryParcel not to attempt + // parcel info requests while disconnected. + LLUrlEntryParcel::setDisconnected(gDisconnected); } void LLAppViewer::forceErrorLLError() diff --git a/indra/newview/llremoteparcelrequest.cpp b/indra/newview/llremoteparcelrequest.cpp index e5ef51bdd1..3862dac340 100644 --- a/indra/newview/llremoteparcelrequest.cpp +++ b/indra/newview/llremoteparcelrequest.cpp @@ -33,6 +33,7 @@ #include "llpanel.h" #include "llhttpclient.h" #include "llsdserialize.h" +#include "llurlentry.h" #include "llviewerregion.h" #include "llview.h" @@ -168,6 +169,18 @@ void LLRemoteParcelInfoProcessor::processParcelInfoReply(LLMessageSystem* msg, v { observers.erase(*i); } + + LLUrlEntryParcel::LLParcelData url_data; + url_data.parcel_id = parcel_data.parcel_id; + url_data.name = parcel_data.name; + url_data.sim_name = parcel_data.sim_name; + url_data.global_x = parcel_data.global_x; + url_data.global_y = parcel_data.global_y; + url_data.global_z = parcel_data.global_z; + + // Pass the parcel data to LLUrlEntryParcel to render + // human readable parcel name. + LLUrlEntryParcel::processParcelInfo(url_data); } void LLRemoteParcelInfoProcessor::sendParcelInfoRequest(const LLUUID& parcel_id) diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 611f9de2e6..5617eea4c3 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -139,6 +139,7 @@ #include "lltrans.h" #include "llui.h" #include "llurldispatcher.h" +#include "llurlentry.h" #include "llslurl.h" #include "llurlhistory.h" #include "llurlwhitelist.h" @@ -2882,9 +2883,17 @@ bool process_login_success_response() if(!text.empty()) gAgentID.set(text); gDebugInfo["AgentID"] = text; + // Agent id needed for parcel info request in LLUrlEntryParcel + // to resolve parcel name. + LLUrlEntryParcel::setAgentID(gAgentID); + text = response["session_id"].asString(); if(!text.empty()) gAgentSessionID.set(text); gDebugInfo["SessionID"] = text; + + // Session id needed for parcel info request in LLUrlEntryParcel + // to resolve parcel name. + LLUrlEntryParcel::setSessionID(gAgentSessionID); text = response["secure_session_id"].asString(); if(!text.empty()) gAgent.mSecureSessionID.set(text); diff --git a/indra/newview/tests/llremoteparcelrequest_test.cpp b/indra/newview/tests/llremoteparcelrequest_test.cpp index dae22521bb..7862cce3a1 100644 --- a/indra/newview/tests/llremoteparcelrequest_test.cpp +++ b/indra/newview/tests/llremoteparcelrequest_test.cpp @@ -32,6 +32,7 @@ #include "../llagent.h" #include "message.h" +#include "llurlentry.h" namespace { LLControlGroup s_saved_settings("dummy_settings"); @@ -72,6 +73,7 @@ LLUIColor::LLUIColor(void) { } LLAgentAccess::LLAgentAccess(LLControlGroup & settings) : mSavedSettings(settings) { } LLControlGroup::LLControlGroup(std::string const & name) : LLInstanceTracker(name) { } LLControlGroup::~LLControlGroup(void) { } +void LLUrlEntryParcel::processParcelInfo(const LLUrlEntryParcel::LLParcelData& parcel_data) { } namespace tut { -- cgit v1.2.3 From 05c14aa5588596a3bef49cee45e648c1f5ef18b7 Mon Sep 17 00:00:00 2001 From: Vadim ProductEngine Date: Tue, 4 Jan 2011 13:52:29 +0200 Subject: STORM-702 FIXED Made it possible to wear partial outfits Enabled the "Replace Current Outfit" option for incomplete outfits (i.e. those that don't contain full set of body parts). --- indra/newview/llappearancemgr.cpp | 12 ++++++++++-- indra/newview/llinventoryfunctions.cpp | 6 ++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index 80734b0d41..f40fed5ad3 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -1300,8 +1300,16 @@ bool LLAppearanceMgr::getCanReplaceCOF(const LLUUID& outfit_cat_id) return false; } - // Check whether the outfit contains the full set of body parts (shape+skin+hair+eyes). - return getCanMakeFolderIntoOutfit(outfit_cat_id); + // Check whether the outfit contains any wearables we aren't wearing already (STORM-702). + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + LLFindWearablesEx is_worn(/*is_worn=*/ false, /*include_body_parts=*/ true); + gInventory.collectDescendentsIf(outfit_cat_id, + cats, + items, + LLInventoryModel::EXCLUDE_TRASH, + is_worn); + return items.size() > 0; } void LLAppearanceMgr::purgeBaseOutfitLink(const LLUUID& category) diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index ef20869114..61d0a150b7 100644 --- a/indra/newview/llinventoryfunctions.cpp +++ b/indra/newview/llinventoryfunctions.cpp @@ -686,6 +686,12 @@ bool LLFindWearablesEx::operator()(LLInventoryCategory* cat, LLInventoryItem* it return false; } + // Skip broken links. + if (vitem->getIsBrokenLink()) + { + return false; + } + return (bool) get_is_item_worn(item->getUUID()) == mIsWorn; } -- cgit v1.2.3 From 66c34a162a78e23f46816f4c616726ec82e6f20c Mon Sep 17 00:00:00 2001 From: Don Kjer Date: Tue, 4 Jan 2011 12:37:11 -0800 Subject: Backed out changeset 95afdecc1b05 --- indra/newview/llviewermessage.cpp | 69 +++++++++++++++++++-------------------- 1 file changed, 34 insertions(+), 35 deletions(-) diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index f2fee88f56..5cbd5ffa0b 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -4055,55 +4055,54 @@ void send_agent_update(BOOL force_send, BOOL send_reliable) if (duplicate_count < DUP_MSGS && !gDisconnected) { - if (LLStartUp::getStartupState() >= STATE_STARTED) - { - LLFastTimer t(FTM_AGENT_UPDATE_SEND); - // Build the message - msg->newMessageFast(_PREHASH_AgentUpdate); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->addQuatFast(_PREHASH_BodyRotation, body_rotation); - msg->addQuatFast(_PREHASH_HeadRotation, head_rotation); - msg->addU8Fast(_PREHASH_State, render_state); - msg->addU8Fast(_PREHASH_Flags, flags); + LLFastTimer t(FTM_AGENT_UPDATE_SEND); + // Build the message + msg->newMessageFast(_PREHASH_AgentUpdate); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->addQuatFast(_PREHASH_BodyRotation, body_rotation); + msg->addQuatFast(_PREHASH_HeadRotation, head_rotation); + msg->addU8Fast(_PREHASH_State, render_state); + msg->addU8Fast(_PREHASH_Flags, flags); // if (camera_pos_agent.mV[VY] > 255.f) // { // LL_INFOS("Messaging") << "Sending camera center " << camera_pos_agent << LL_ENDL; // } - msg->addVector3Fast(_PREHASH_CameraCenter, camera_pos_agent); - msg->addVector3Fast(_PREHASH_CameraAtAxis, LLViewerCamera::getInstance()->getAtAxis()); - msg->addVector3Fast(_PREHASH_CameraLeftAxis, LLViewerCamera::getInstance()->getLeftAxis()); - msg->addVector3Fast(_PREHASH_CameraUpAxis, LLViewerCamera::getInstance()->getUpAxis()); - msg->addF32Fast(_PREHASH_Far, gAgentCamera.mDrawDistance); + msg->addVector3Fast(_PREHASH_CameraCenter, camera_pos_agent); + msg->addVector3Fast(_PREHASH_CameraAtAxis, LLViewerCamera::getInstance()->getAtAxis()); + msg->addVector3Fast(_PREHASH_CameraLeftAxis, LLViewerCamera::getInstance()->getLeftAxis()); + msg->addVector3Fast(_PREHASH_CameraUpAxis, LLViewerCamera::getInstance()->getUpAxis()); + msg->addF32Fast(_PREHASH_Far, gAgentCamera.mDrawDistance); - msg->addU32Fast(_PREHASH_ControlFlags, control_flags); + msg->addU32Fast(_PREHASH_ControlFlags, control_flags); - if (gDebugClicks) + if (gDebugClicks) + { + if (control_flags & AGENT_CONTROL_LBUTTON_DOWN) { - if (control_flags & AGENT_CONTROL_LBUTTON_DOWN) - { - LL_INFOS("Messaging") << "AgentUpdate left button down" << LL_ENDL; - } - - if (control_flags & AGENT_CONTROL_LBUTTON_UP) - { - LL_INFOS("Messaging") << "AgentUpdate left button up" << LL_ENDL; - } + LL_INFOS("Messaging") << "AgentUpdate left button down" << LL_ENDL; } - gAgent.enableControlFlagReset(); - if (!send_reliable) + if (control_flags & AGENT_CONTROL_LBUTTON_UP) { - gAgent.sendMessage(); - } - else - { - gAgent.sendReliableMessage(); + LL_INFOS("Messaging") << "AgentUpdate left button up" << LL_ENDL; } } + + gAgent.enableControlFlagReset(); + + if (!send_reliable) + { + gAgent.sendMessage(); + } + else + { + gAgent.sendReliableMessage(); + } + // LL_DEBUGS("Messaging") << "agent " << avatar_pos_agent << " cam " << camera_pos_agent << LL_ENDL; // Copy the old data -- cgit v1.2.3 From 5d5c6b637a8524403ee0db0f8dfcc836f7f91086 Mon Sep 17 00:00:00 2001 From: Seth ProductEngine Date: Thu, 6 Jan 2011 01:01:21 +0200 Subject: STORM-514 FIXED Replaced missing textures names in Side Tray params. --- indra/newview/llsidetray.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/indra/newview/llsidetray.cpp b/indra/newview/llsidetray.cpp index aef665a35c..19d1bdee86 100644 --- a/indra/newview/llsidetray.cpp +++ b/indra/newview/llsidetray.cpp @@ -498,8 +498,8 @@ private: LLSideTray::Params::Params() : collapsed("collapsed",false), - tab_btn_image_normal("tab_btn_image",LLUI::getUIImage("sidebar_tab_left.tga")), - tab_btn_image_selected("tab_btn_image_selected",LLUI::getUIImage("button_enabled_selected_32x128.tga")), + tab_btn_image_normal("tab_btn_image",LLUI::getUIImage("taskpanel/TaskPanel_Tab_Off.png")), + tab_btn_image_selected("tab_btn_image_selected",LLUI::getUIImage("taskpanel/TaskPanel_Tab_Selected.png")), default_button_width("tab_btn_width",32), default_button_height("tab_btn_height",32), default_button_margin("tab_btn_margin",0) -- cgit v1.2.3 From d0b5e6b0b4acebd1b11685dea290b830957ba9dc Mon Sep 17 00:00:00 2001 From: Jonathan Yap Date: Thu, 6 Jan 2011 06:07:11 -0500 Subject: STORM-829 Viewer 2 does not parse /me in object Instant Messages --- doc/contributions.txt | 3 ++- indra/newview/llviewermessage.cpp | 8 ++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/doc/contributions.txt b/doc/contributions.txt index 0954704c26..4e6c662e4f 100644 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -370,8 +370,9 @@ Jonathan Yap STORM-679 STORM-737 STORM-726 - VWR-17801 STORM-785 + STORM-829 + VWR-17801 Kage Pixel VWR-11 Ken March diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 7dc5d96689..7f7855c08c 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -2746,6 +2746,14 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) LLSD args; args["slurl"] = location; args["type"] = LLNotificationsUI::NT_NEARBYCHAT; + + // Look for IRC-style emotes here so object name formatting is correct + std::string prefix = message.substr(0, 4); + if (prefix == "/me " || prefix == "/me'") + { + chat.mChatStyle = CHAT_STYLE_IRC; + } + LLNotificationsUI::LLNotificationManager::instance().onChat(chat, args); } -- cgit v1.2.3 From dda4150e01fdad5de5720c756e29169a6ce635f7 Mon Sep 17 00:00:00 2001 From: Vadim ProductEngine Date: Thu, 6 Jan 2011 15:51:38 +0200 Subject: STORM-393 FIXED Changed group SLURL color to be the same as in other URLs. By the way, removed "AgentLinkColor" color which has been used since STORM-579 was fixed. --- indra/llui/llurlentry.cpp | 4 ++-- indra/newview/skins/default/colors.xml | 6 ------ 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/indra/llui/llurlentry.cpp b/indra/llui/llurlentry.cpp index 4f7b4be526..049a45c3bc 100644 --- a/indra/llui/llurlentry.cpp +++ b/indra/llui/llurlentry.cpp @@ -684,8 +684,8 @@ std::string LLUrlEntryGroup::getLabel(const std::string &url, const LLUrlLabelCa LLStyle::Params LLUrlEntryGroup::getStyle() const { LLStyle::Params style_params = LLUrlEntryBase::getStyle(); - style_params.color = LLUIColorTable::instance().getColor("GroupLinkColor"); - style_params.readonly_color = LLUIColorTable::instance().getColor("GroupLinkColor"); + style_params.color = LLUIColorTable::instance().getColor("HTMLLinkColor"); + style_params.readonly_color = LLUIColorTable::instance().getColor("HTMLLinkColor"); return style_params; } diff --git a/indra/newview/skins/default/colors.xml b/indra/newview/skins/default/colors.xml index 62441fd984..75aec21f93 100644 --- a/indra/newview/skins/default/colors.xml +++ b/indra/newview/skins/default/colors.xml @@ -114,9 +114,6 @@ - @@ -348,9 +345,6 @@ - -- cgit v1.2.3 From a4d5e38535f1a749011d849e93b8b0010933fdf4 Mon Sep 17 00:00:00 2001 From: Oz Linden Date: Thu, 6 Jan 2011 11:06:20 -0500 Subject: STORM-826 (workaround): correct mixed and dos-style line endings --- indra/cmake/GetPrerequisites_2_8.cmake | 1572 ++++++++++---------- indra/cmake/LLAddBuildTest.cmake | 552 +++---- indra/newview/llfloaterwebcontent.cpp | 804 +++++----- indra/newview/llfloaterwebcontent.h | 162 +- indra/newview/llimview.cpp | 26 +- indra/newview/llimview.h | 2 +- indra/newview/lllogchat.cpp | 18 +- indra/newview/tests/llremoteparcelrequest_test.cpp | 268 ++-- .../updater/tests/llupdaterservice_test.cpp | 400 ++--- 9 files changed, 1902 insertions(+), 1902 deletions(-) diff --git a/indra/cmake/GetPrerequisites_2_8.cmake b/indra/cmake/GetPrerequisites_2_8.cmake index 5a24842c89..05ec1539ba 100644 --- a/indra/cmake/GetPrerequisites_2_8.cmake +++ b/indra/cmake/GetPrerequisites_2_8.cmake @@ -1,786 +1,786 @@ -# GetPrerequisites.cmake -# -# This script provides functions to list the .dll, .dylib or .so files that an -# executable or shared library file depends on. (Its prerequisites.) -# -# It uses various tools to obtain the list of required shared library files: -# dumpbin (Windows) -# ldd (Linux/Unix) -# otool (Mac OSX) -# -# The following functions are provided by this script: -# gp_append_unique -# is_file_executable -# gp_item_default_embedded_path -# (projects can override with gp_item_default_embedded_path_override) -# gp_resolve_item -# (projects can override with gp_resolve_item_override) -# gp_resolved_file_type -# gp_file_type -# get_prerequisites -# list_prerequisites -# list_prerequisites_by_glob -# -# Requires CMake 2.6 or greater because it uses function, break, return and -# PARENT_SCOPE. - -#============================================================================= -# Copyright 2008-2009 Kitware, Inc. -# -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. -#============================================================================= -# (To distributed this file outside of CMake, substitute the full -# License text for the above reference.) - -# gp_append_unique list_var value -# -# Append value to the list variable ${list_var} only if the value is not -# already in the list. -# -function(gp_append_unique list_var value) - set(contains 0) - - foreach(item ${${list_var}}) - if("${item}" STREQUAL "${value}") - set(contains 1) - break() - endif("${item}" STREQUAL "${value}") - endforeach(item) - - if(NOT contains) - set(${list_var} ${${list_var}} "${value}" PARENT_SCOPE) - endif(NOT contains) -endfunction(gp_append_unique) - - -# is_file_executable file result_var -# -# Return 1 in ${result_var} if ${file} is a binary executable. -# -# Return 0 in ${result_var} otherwise. -# -function(is_file_executable file result_var) - # - # A file is not executable until proven otherwise: - # - set(${result_var} 0 PARENT_SCOPE) - - get_filename_component(file_full "${file}" ABSOLUTE) - string(TOLOWER "${file_full}" file_full_lower) - - # If file name ends in .exe on Windows, *assume* executable: - # - if(WIN32) - if("${file_full_lower}" MATCHES "\\.exe$") - set(${result_var} 1 PARENT_SCOPE) - return() - endif("${file_full_lower}" MATCHES "\\.exe$") - - # A clause could be added here that uses output or return value of dumpbin - # to determine ${result_var}. In 99%+? practical cases, the exe name - # match will be sufficient... - # - endif(WIN32) - - # Use the information returned from the Unix shell command "file" to - # determine if ${file_full} should be considered an executable file... - # - # If the file command's output contains "executable" and does *not* contain - # "text" then it is likely an executable suitable for prerequisite analysis - # via the get_prerequisites macro. - # - if(UNIX) - if(NOT file_cmd) - find_program(file_cmd "file") - endif(NOT file_cmd) - - if(file_cmd) - execute_process(COMMAND "${file_cmd}" "${file_full}" - OUTPUT_VARIABLE file_ov - OUTPUT_STRIP_TRAILING_WHITESPACE - ) - - # Replace the name of the file in the output with a placeholder token - # (the string " _file_full_ ") so that just in case the path name of - # the file contains the word "text" or "executable" we are not fooled - # into thinking "the wrong thing" because the file name matches the - # other 'file' command output we are looking for... - # - string(REPLACE "${file_full}" " _file_full_ " file_ov "${file_ov}") - string(TOLOWER "${file_ov}" file_ov) - - #message(STATUS "file_ov='${file_ov}'") - if("${file_ov}" MATCHES "executable") - #message(STATUS "executable!") - if("${file_ov}" MATCHES "text") - #message(STATUS "but text, so *not* a binary executable!") - else("${file_ov}" MATCHES "text") - set(${result_var} 1 PARENT_SCOPE) - return() - endif("${file_ov}" MATCHES "text") - endif("${file_ov}" MATCHES "executable") - else(file_cmd) - message(STATUS "warning: No 'file' command, skipping execute_process...") - endif(file_cmd) - endif(UNIX) -endfunction(is_file_executable) - - -# gp_item_default_embedded_path item default_embedded_path_var -# -# Return the path that others should refer to the item by when the item -# is embedded inside a bundle. -# -# Override on a per-project basis by providing a project-specific -# gp_item_default_embedded_path_override function. -# -function(gp_item_default_embedded_path item default_embedded_path_var) - - # On Windows and Linux, "embed" prerequisites in the same directory - # as the executable by default: - # - set(path "@executable_path") - set(overridden 0) - - # On the Mac, relative to the executable depending on the type - # of the thing we are embedding: - # - if(APPLE) - # - # The assumption here is that all executables in the bundle will be - # in same-level-directories inside the bundle. The parent directory - # of an executable inside the bundle should be MacOS or a sibling of - # MacOS and all embedded paths returned from here will begin with - # "@executable_path/../" and will work from all executables in all - # such same-level-directories inside the bundle. - # - - # By default, embed things right next to the main bundle executable: - # - set(path "@executable_path/../../Contents/MacOS") - - # Embed .dylibs right next to the main bundle executable: - # - if(item MATCHES "\\.dylib$") - set(path "@executable_path/../MacOS") - set(overridden 1) - endif(item MATCHES "\\.dylib$") - - # Embed frameworks in the embedded "Frameworks" directory (sibling of MacOS): - # - if(NOT overridden) - if(item MATCHES "[^/]+\\.framework/") - set(path "@executable_path/../Frameworks") - set(overridden 1) - endif(item MATCHES "[^/]+\\.framework/") - endif(NOT overridden) - endif() - - # Provide a hook so that projects can override the default embedded location - # of any given library by whatever logic they choose: - # - if(COMMAND gp_item_default_embedded_path_override) - gp_item_default_embedded_path_override("${item}" path) - endif(COMMAND gp_item_default_embedded_path_override) - - set(${default_embedded_path_var} "${path}" PARENT_SCOPE) -endfunction(gp_item_default_embedded_path) - - -# gp_resolve_item context item exepath dirs resolved_item_var -# -# Resolve an item into an existing full path file. -# -# Override on a per-project basis by providing a project-specific -# gp_resolve_item_override function. -# -function(gp_resolve_item context item exepath dirs resolved_item_var) - set(resolved 0) - set(resolved_item "${item}") - - # Is it already resolved? - # - if(EXISTS "${resolved_item}") - set(resolved 1) - endif(EXISTS "${resolved_item}") - - if(NOT resolved) - if(item MATCHES "@executable_path") - # - # @executable_path references are assumed relative to exepath - # - string(REPLACE "@executable_path" "${exepath}" ri "${item}") - get_filename_component(ri "${ri}" ABSOLUTE) - - if(EXISTS "${ri}") - #message(STATUS "info: embedded item exists (${ri})") - set(resolved 1) - set(resolved_item "${ri}") - else(EXISTS "${ri}") - message(STATUS "warning: embedded item does not exist '${ri}'") - endif(EXISTS "${ri}") - endif(item MATCHES "@executable_path") - endif(NOT resolved) - - if(NOT resolved) - if(item MATCHES "@loader_path") - # - # @loader_path references are assumed relative to the - # PATH of the given "context" (presumably another library) - # - get_filename_component(contextpath "${context}" PATH) - string(REPLACE "@loader_path" "${contextpath}" ri "${item}") - get_filename_component(ri "${ri}" ABSOLUTE) - - if(EXISTS "${ri}") - #message(STATUS "info: embedded item exists (${ri})") - set(resolved 1) - set(resolved_item "${ri}") - else(EXISTS "${ri}") - message(STATUS "warning: embedded item does not exist '${ri}'") - endif(EXISTS "${ri}") - endif(item MATCHES "@loader_path") - endif(NOT resolved) - - if(NOT resolved) - set(ri "ri-NOTFOUND") - find_file(ri "${item}" ${exepath} ${dirs} NO_DEFAULT_PATH) - find_file(ri "${item}" ${exepath} ${dirs} /usr/lib) - if(ri) - #message(STATUS "info: 'find_file' in exepath/dirs (${ri})") - set(resolved 1) - set(resolved_item "${ri}") - set(ri "ri-NOTFOUND") - endif(ri) - endif(NOT resolved) - - if(NOT resolved) - if(item MATCHES "[^/]+\\.framework/") - set(fw "fw-NOTFOUND") - find_file(fw "${item}" - "~/Library/Frameworks" - "/Library/Frameworks" - "/System/Library/Frameworks" - ) - if(fw) - #message(STATUS "info: 'find_file' found framework (${fw})") - set(resolved 1) - set(resolved_item "${fw}") - set(fw "fw-NOTFOUND") - endif(fw) - endif(item MATCHES "[^/]+\\.framework/") - endif(NOT resolved) - - # Using find_program on Windows will find dll files that are in the PATH. - # (Converting simple file names into full path names if found.) - # - if(WIN32) - if(NOT resolved) - set(ri "ri-NOTFOUND") - find_program(ri "${item}" PATHS "${exepath};${dirs}" NO_DEFAULT_PATH) - find_program(ri "${item}" PATHS "${exepath};${dirs}") - if(ri) - #message(STATUS "info: 'find_program' in exepath/dirs (${ri})") - set(resolved 1) - set(resolved_item "${ri}") - set(ri "ri-NOTFOUND") - endif(ri) - endif(NOT resolved) - endif(WIN32) - - # Provide a hook so that projects can override item resolution - # by whatever logic they choose: - # - if(COMMAND gp_resolve_item_override) - gp_resolve_item_override("${context}" "${item}" "${exepath}" "${dirs}" resolved_item resolved) - endif(COMMAND gp_resolve_item_override) - - if(NOT resolved) - message(STATUS " -warning: cannot resolve item '${item}' - - possible problems: - need more directories? - need to use InstallRequiredSystemLibraries? - run in install tree instead of build tree? -") -# message(STATUS " -#****************************************************************************** -#warning: cannot resolve item '${item}' -# -# possible problems: -# need more directories? -# need to use InstallRequiredSystemLibraries? -# run in install tree instead of build tree? -# -# context='${context}' -# item='${item}' -# exepath='${exepath}' -# dirs='${dirs}' -# resolved_item_var='${resolved_item_var}' -#****************************************************************************** -#") - endif(NOT resolved) - - set(${resolved_item_var} "${resolved_item}" PARENT_SCOPE) -endfunction(gp_resolve_item) - - -# gp_resolved_file_type original_file file exepath dirs type_var -# -# Return the type of ${file} with respect to ${original_file}. String -# describing type of prerequisite is returned in variable named ${type_var}. -# -# Use ${exepath} and ${dirs} if necessary to resolve non-absolute ${file} -# values -- but only for non-embedded items. -# -# Possible types are: -# system -# local -# embedded -# other -# -function(gp_resolved_file_type original_file file exepath dirs type_var) - #message(STATUS "**") - - if(NOT IS_ABSOLUTE "${original_file}") - message(STATUS "warning: gp_resolved_file_type expects absolute full path for first arg original_file") - endif() - - set(is_embedded 0) - set(is_local 0) - set(is_system 0) - - set(resolved_file "${file}") - - if("${file}" MATCHES "^@(executable|loader)_path") - set(is_embedded 1) - endif() - - if(NOT is_embedded) - if(NOT IS_ABSOLUTE "${file}") - gp_resolve_item("${original_file}" "${file}" "${exepath}" "${dirs}" resolved_file) - endif() - - string(TOLOWER "${original_file}" original_lower) - string(TOLOWER "${resolved_file}" lower) - - if(UNIX) - if(resolved_file MATCHES "^(/lib/|/lib32/|/lib64/|/usr/lib/|/usr/lib32/|/usr/lib64/|/usr/X11R6/)") - set(is_system 1) - endif() - endif() - - if(APPLE) - if(resolved_file MATCHES "^(/System/Library/|/usr/lib/)") - set(is_system 1) - endif() - endif() - - if(WIN32) - string(TOLOWER "$ENV{SystemRoot}" sysroot) - string(REGEX REPLACE "\\\\" "/" sysroot "${sysroot}") - - string(TOLOWER "$ENV{windir}" windir) - string(REGEX REPLACE "\\\\" "/" windir "${windir}") - - if(lower MATCHES "^(${sysroot}/system|${windir}/system|${sysroot}/syswow|${windir}/syswow|(.*/)*msvc[^/]+dll)") - set(is_system 1) - endif() - endif() - - if(NOT is_system) - get_filename_component(original_path "${original_lower}" PATH) - get_filename_component(path "${lower}" PATH) - if("${original_path}" STREQUAL "${path}") - set(is_local 1) - endif() - endif() - endif() - - # Return type string based on computed booleans: - # - set(type "other") - - if(is_system) - set(type "system") - elseif(is_embedded) - set(type "embedded") - elseif(is_local) - set(type "local") - endif() - - #message(STATUS "gp_resolved_file_type: '${file}' '${resolved_file}'") - #message(STATUS " type: '${type}'") - - if(NOT is_embedded) - if(NOT IS_ABSOLUTE "${resolved_file}") - if(lower MATCHES "^msvc[^/]+dll" AND is_system) - message(STATUS "info: non-absolute msvc file '${file}' returning type '${type}'") - else() - message(STATUS "warning: gp_resolved_file_type non-absolute file '${file}' returning type '${type}' -- possibly incorrect") - endif() - endif() - endif() - - set(${type_var} "${type}" PARENT_SCOPE) - - #message(STATUS "**") -endfunction() - - -# gp_file_type original_file file type_var -# -# Return the type of ${file} with respect to ${original_file}. String -# describing type of prerequisite is returned in variable named ${type_var}. -# -# Possible types are: -# system -# local -# embedded -# other -# -function(gp_file_type original_file file type_var) - if(NOT IS_ABSOLUTE "${original_file}") - message(STATUS "warning: gp_file_type expects absolute full path for first arg original_file") - endif() - - get_filename_component(exepath "${original_file}" PATH) - - set(type "") - gp_resolved_file_type("${original_file}" "${file}" "${exepath}" "" type) - - set(${type_var} "${type}" PARENT_SCOPE) -endfunction(gp_file_type) - - -# get_prerequisites target prerequisites_var exclude_system recurse dirs -# -# Get the list of shared library files required by ${target}. The list in -# the variable named ${prerequisites_var} should be empty on first entry to -# this function. On exit, ${prerequisites_var} will contain the list of -# required shared library files. -# -# target is the full path to an executable file -# -# prerequisites_var is the name of a CMake variable to contain the results -# -# exclude_system is 0 or 1: 0 to include "system" prerequisites , 1 to -# exclude them -# -# recurse is 0 or 1: 0 for direct prerequisites only, 1 for all prerequisites -# recursively -# -# exepath is the path to the top level executable used for @executable_path -# replacment on the Mac -# -# dirs is a list of paths where libraries might be found: these paths are -# searched first when a target without any path info is given. Then standard -# system locations are also searched: PATH, Framework locations, /usr/lib... -# -function(get_prerequisites target prerequisites_var exclude_system recurse exepath dirs) - set(verbose 0) - set(eol_char "E") - - if(NOT IS_ABSOLUTE "${target}") - message("warning: target '${target}' is not absolute...") - endif(NOT IS_ABSOLUTE "${target}") - - if(NOT EXISTS "${target}") - message("warning: target '${target}' does not exist...") - endif(NOT EXISTS "${target}") - - # - # - # Try to choose the right tool by default. Caller can set gp_tool prior to - # calling this function to force using a different tool. - # - if("${gp_tool}" STREQUAL "") - set(gp_tool "ldd") - if(APPLE) - set(gp_tool "otool") - endif(APPLE) - if(WIN32) - set(gp_tool "dumpbin") - endif(WIN32) - endif("${gp_tool}" STREQUAL "") - - set(gp_tool_known 0) - - if("${gp_tool}" STREQUAL "ldd") - set(gp_cmd_args "") - set(gp_regex "^[\t ]*[^\t ]+ => ([^\t ]+).*${eol_char}$") - set(gp_regex_cmp_count 1) - set(gp_tool_known 1) - endif("${gp_tool}" STREQUAL "ldd") - - if("${gp_tool}" STREQUAL "otool") - set(gp_cmd_args "-L") - set(gp_regex "^\t([^\t]+) \\(compatibility version ([0-9]+.[0-9]+.[0-9]+), current version ([0-9]+.[0-9]+.[0-9]+)\\)${eol_char}$") - set(gp_regex_cmp_count 3) - set(gp_tool_known 1) - endif("${gp_tool}" STREQUAL "otool") - - if("${gp_tool}" STREQUAL "dumpbin") - set(gp_cmd_args "/dependents") - set(gp_regex "^ ([^ ].*[Dd][Ll][Ll])${eol_char}$") - set(gp_regex_cmp_count 1) - set(gp_tool_known 1) - set(ENV{VS_UNICODE_OUTPUT} "") # Block extra output from inside VS IDE. - endif("${gp_tool}" STREQUAL "dumpbin") - - if(NOT gp_tool_known) - message(STATUS "warning: gp_tool='${gp_tool}' is an unknown tool...") - message(STATUS "CMake function get_prerequisites needs more code to handle '${gp_tool}'") - message(STATUS "Valid gp_tool values are dumpbin, ldd and otool.") - return() - endif(NOT gp_tool_known) - - set(gp_cmd_paths ${gp_cmd_paths} - "C:/Program Files/Microsoft Visual Studio 9.0/VC/bin" - "C:/Program Files (x86)/Microsoft Visual Studio 9.0/VC/bin" - "C:/Program Files/Microsoft Visual Studio 8/VC/BIN" - "C:/Program Files (x86)/Microsoft Visual Studio 8/VC/BIN" - "C:/Program Files/Microsoft Visual Studio .NET 2003/VC7/BIN" - "C:/Program Files (x86)/Microsoft Visual Studio .NET 2003/VC7/BIN" - "/usr/local/bin" - "/usr/bin" - ) - - find_program(gp_cmd ${gp_tool} PATHS ${gp_cmd_paths}) - - if(NOT gp_cmd) - message(STATUS "warning: could not find '${gp_tool}' - cannot analyze prerequisites...") - return() - endif(NOT gp_cmd) - - if("${gp_tool}" STREQUAL "dumpbin") - # When running dumpbin, it also needs the "Common7/IDE" directory in the - # PATH. It will already be in the PATH if being run from a Visual Studio - # command prompt. Add it to the PATH here in case we are running from a - # different command prompt. - # - get_filename_component(gp_cmd_dir "${gp_cmd}" PATH) - get_filename_component(gp_cmd_dlls_dir "${gp_cmd_dir}/../../Common7/IDE" ABSOLUTE) - if(EXISTS "${gp_cmd_dlls_dir}") - # only add to the path if it is not already in the path - if(NOT "$ENV{PATH}" MATCHES "${gp_cmd_dlls_dir}") - set(ENV{PATH} "$ENV{PATH};${gp_cmd_dlls_dir}") - endif(NOT "$ENV{PATH}" MATCHES "${gp_cmd_dlls_dir}") - endif(EXISTS "${gp_cmd_dlls_dir}") - endif("${gp_tool}" STREQUAL "dumpbin") - # - # - - if("${gp_tool}" STREQUAL "ldd") - set(old_ld_env "$ENV{LD_LIBRARY_PATH}") - foreach(dir ${exepath} ${dirs}) - set(ENV{LD_LIBRARY_PATH} "${dir}:$ENV{LD_LIBRARY_PATH}") - endforeach(dir) - endif("${gp_tool}" STREQUAL "ldd") - - - # Track new prerequisites at each new level of recursion. Start with an - # empty list at each level: - # - set(unseen_prereqs) - - # Run gp_cmd on the target: - # - execute_process( - COMMAND ${gp_cmd} ${gp_cmd_args} ${target} - OUTPUT_VARIABLE gp_cmd_ov - ) - - if("${gp_tool}" STREQUAL "ldd") - set(ENV{LD_LIBRARY_PATH} "${old_ld_env}") - endif("${gp_tool}" STREQUAL "ldd") - - if(verbose) - message(STATUS "") - message(STATUS "gp_cmd_ov='${gp_cmd_ov}'") - message(STATUS "") - endif(verbose) - - get_filename_component(target_dir "${target}" PATH) - - # Convert to a list of lines: - # - string(REGEX REPLACE ";" "\\\\;" candidates "${gp_cmd_ov}") - string(REGEX REPLACE "\n" "${eol_char};" candidates "${candidates}") - - # Analyze each line for file names that match the regular expression: - # - foreach(candidate ${candidates}) - if("${candidate}" MATCHES "${gp_regex}") - # Extract information from each candidate: - string(REGEX REPLACE "${gp_regex}" "\\1" raw_item "${candidate}") - - if(gp_regex_cmp_count GREATER 1) - string(REGEX REPLACE "${gp_regex}" "\\2" raw_compat_version "${candidate}") - string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\1" compat_major_version "${raw_compat_version}") - string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\2" compat_minor_version "${raw_compat_version}") - string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\3" compat_patch_version "${raw_compat_version}") - endif(gp_regex_cmp_count GREATER 1) - - if(gp_regex_cmp_count GREATER 2) - string(REGEX REPLACE "${gp_regex}" "\\3" raw_current_version "${candidate}") - string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\1" current_major_version "${raw_current_version}") - string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\2" current_minor_version "${raw_current_version}") - string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\3" current_patch_version "${raw_current_version}") - endif(gp_regex_cmp_count GREATER 2) - - # Use the raw_item as the list entries returned by this function. Use the - # gp_resolve_item function to resolve it to an actual full path file if - # necessary. - # - set(item "${raw_item}") - - # Add each item unless it is excluded: - # - set(add_item 1) - - if(${exclude_system}) - set(type "") - gp_resolved_file_type("${target}" "${item}" "${exepath}" "${dirs}" type) - if("${type}" STREQUAL "system") - set(add_item 0) - endif("${type}" STREQUAL "system") - endif(${exclude_system}) - - if(add_item) - list(LENGTH ${prerequisites_var} list_length_before_append) - gp_append_unique(${prerequisites_var} "${item}") - list(LENGTH ${prerequisites_var} list_length_after_append) - - if(${recurse}) - # If item was really added, this is the first time we have seen it. - # Add it to unseen_prereqs so that we can recursively add *its* - # prerequisites... - # - # But first: resolve its name to an absolute full path name such - # that the analysis tools can simply accept it as input. - # - if(NOT list_length_before_append EQUAL list_length_after_append) - gp_resolve_item("${target}" "${item}" "${exepath}" "${dirs}" resolved_item) - set(unseen_prereqs ${unseen_prereqs} "${resolved_item}") - endif(NOT list_length_before_append EQUAL list_length_after_append) - endif(${recurse}) - endif(add_item) - else("${candidate}" MATCHES "${gp_regex}") - if(verbose) - message(STATUS "ignoring non-matching line: '${candidate}'") - endif(verbose) - endif("${candidate}" MATCHES "${gp_regex}") - endforeach(candidate) - - list(LENGTH ${prerequisites_var} prerequisites_var_length) - if(prerequisites_var_length GREATER 0) - list(SORT ${prerequisites_var}) - endif(prerequisites_var_length GREATER 0) - if(${recurse}) - set(more_inputs ${unseen_prereqs}) - foreach(input ${more_inputs}) - get_prerequisites("${input}" ${prerequisites_var} ${exclude_system} ${recurse} "${exepath}" "${dirs}") - endforeach(input) - endif(${recurse}) - - set(${prerequisites_var} ${${prerequisites_var}} PARENT_SCOPE) -endfunction(get_prerequisites) - - -# list_prerequisites target all exclude_system verbose -# -# ARGV0 (target) is the full path to an executable file -# -# optional ARGV1 (all) is 0 or 1: 0 for direct prerequisites only, -# 1 for all prerequisites recursively -# -# optional ARGV2 (exclude_system) is 0 or 1: 0 to include "system" -# prerequisites , 1 to exclude them -# -# optional ARGV3 (verbose) is 0 or 1: 0 to print only full path -# names of prerequisites, 1 to print extra information -# -function(list_prerequisites target) - if("${ARGV1}" STREQUAL "") - set(all 1) - else("${ARGV1}" STREQUAL "") - set(all "${ARGV1}") - endif("${ARGV1}" STREQUAL "") - - if("${ARGV2}" STREQUAL "") - set(exclude_system 0) - else("${ARGV2}" STREQUAL "") - set(exclude_system "${ARGV2}") - endif("${ARGV2}" STREQUAL "") - - if("${ARGV3}" STREQUAL "") - set(verbose 0) - else("${ARGV3}" STREQUAL "") - set(verbose "${ARGV3}") - endif("${ARGV3}" STREQUAL "") - - set(count 0) - set(count_str "") - set(print_count "${verbose}") - set(print_prerequisite_type "${verbose}") - set(print_target "${verbose}") - set(type_str "") - - get_filename_component(exepath "${target}" PATH) - - set(prereqs "") - get_prerequisites("${target}" prereqs ${exclude_system} ${all} "${exepath}" "") - - if(print_target) - message(STATUS "File '${target}' depends on:") - endif(print_target) - - foreach(d ${prereqs}) - math(EXPR count "${count} + 1") - - if(print_count) - set(count_str "${count}. ") - endif(print_count) - - if(print_prerequisite_type) - gp_file_type("${target}" "${d}" type) - set(type_str " (${type})") - endif(print_prerequisite_type) - - message(STATUS "${count_str}${d}${type_str}") - endforeach(d) -endfunction(list_prerequisites) - - -# list_prerequisites_by_glob glob_arg glob_exp -# -# glob_arg is GLOB or GLOB_RECURSE -# -# glob_exp is a globbing expression used with "file(GLOB" to retrieve a list -# of matching files. If a matching file is executable, its prerequisites are -# listed. -# -# Any additional (optional) arguments provided are passed along as the -# optional arguments to the list_prerequisites calls. -# -function(list_prerequisites_by_glob glob_arg glob_exp) - message(STATUS "=============================================================================") - message(STATUS "List prerequisites of executables matching ${glob_arg} '${glob_exp}'") - message(STATUS "") - file(${glob_arg} file_list ${glob_exp}) - foreach(f ${file_list}) - is_file_executable("${f}" is_f_executable) - if(is_f_executable) - message(STATUS "=============================================================================") - list_prerequisites("${f}" ${ARGN}) - message(STATUS "") - endif(is_f_executable) - endforeach(f) -endfunction(list_prerequisites_by_glob) +# GetPrerequisites.cmake +# +# This script provides functions to list the .dll, .dylib or .so files that an +# executable or shared library file depends on. (Its prerequisites.) +# +# It uses various tools to obtain the list of required shared library files: +# dumpbin (Windows) +# ldd (Linux/Unix) +# otool (Mac OSX) +# +# The following functions are provided by this script: +# gp_append_unique +# is_file_executable +# gp_item_default_embedded_path +# (projects can override with gp_item_default_embedded_path_override) +# gp_resolve_item +# (projects can override with gp_resolve_item_override) +# gp_resolved_file_type +# gp_file_type +# get_prerequisites +# list_prerequisites +# list_prerequisites_by_glob +# +# Requires CMake 2.6 or greater because it uses function, break, return and +# PARENT_SCOPE. + +#============================================================================= +# Copyright 2008-2009 Kitware, Inc. +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distributed this file outside of CMake, substitute the full +# License text for the above reference.) + +# gp_append_unique list_var value +# +# Append value to the list variable ${list_var} only if the value is not +# already in the list. +# +function(gp_append_unique list_var value) + set(contains 0) + + foreach(item ${${list_var}}) + if("${item}" STREQUAL "${value}") + set(contains 1) + break() + endif("${item}" STREQUAL "${value}") + endforeach(item) + + if(NOT contains) + set(${list_var} ${${list_var}} "${value}" PARENT_SCOPE) + endif(NOT contains) +endfunction(gp_append_unique) + + +# is_file_executable file result_var +# +# Return 1 in ${result_var} if ${file} is a binary executable. +# +# Return 0 in ${result_var} otherwise. +# +function(is_file_executable file result_var) + # + # A file is not executable until proven otherwise: + # + set(${result_var} 0 PARENT_SCOPE) + + get_filename_component(file_full "${file}" ABSOLUTE) + string(TOLOWER "${file_full}" file_full_lower) + + # If file name ends in .exe on Windows, *assume* executable: + # + if(WIN32) + if("${file_full_lower}" MATCHES "\\.exe$") + set(${result_var} 1 PARENT_SCOPE) + return() + endif("${file_full_lower}" MATCHES "\\.exe$") + + # A clause could be added here that uses output or return value of dumpbin + # to determine ${result_var}. In 99%+? practical cases, the exe name + # match will be sufficient... + # + endif(WIN32) + + # Use the information returned from the Unix shell command "file" to + # determine if ${file_full} should be considered an executable file... + # + # If the file command's output contains "executable" and does *not* contain + # "text" then it is likely an executable suitable for prerequisite analysis + # via the get_prerequisites macro. + # + if(UNIX) + if(NOT file_cmd) + find_program(file_cmd "file") + endif(NOT file_cmd) + + if(file_cmd) + execute_process(COMMAND "${file_cmd}" "${file_full}" + OUTPUT_VARIABLE file_ov + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + + # Replace the name of the file in the output with a placeholder token + # (the string " _file_full_ ") so that just in case the path name of + # the file contains the word "text" or "executable" we are not fooled + # into thinking "the wrong thing" because the file name matches the + # other 'file' command output we are looking for... + # + string(REPLACE "${file_full}" " _file_full_ " file_ov "${file_ov}") + string(TOLOWER "${file_ov}" file_ov) + + #message(STATUS "file_ov='${file_ov}'") + if("${file_ov}" MATCHES "executable") + #message(STATUS "executable!") + if("${file_ov}" MATCHES "text") + #message(STATUS "but text, so *not* a binary executable!") + else("${file_ov}" MATCHES "text") + set(${result_var} 1 PARENT_SCOPE) + return() + endif("${file_ov}" MATCHES "text") + endif("${file_ov}" MATCHES "executable") + else(file_cmd) + message(STATUS "warning: No 'file' command, skipping execute_process...") + endif(file_cmd) + endif(UNIX) +endfunction(is_file_executable) + + +# gp_item_default_embedded_path item default_embedded_path_var +# +# Return the path that others should refer to the item by when the item +# is embedded inside a bundle. +# +# Override on a per-project basis by providing a project-specific +# gp_item_default_embedded_path_override function. +# +function(gp_item_default_embedded_path item default_embedded_path_var) + + # On Windows and Linux, "embed" prerequisites in the same directory + # as the executable by default: + # + set(path "@executable_path") + set(overridden 0) + + # On the Mac, relative to the executable depending on the type + # of the thing we are embedding: + # + if(APPLE) + # + # The assumption here is that all executables in the bundle will be + # in same-level-directories inside the bundle. The parent directory + # of an executable inside the bundle should be MacOS or a sibling of + # MacOS and all embedded paths returned from here will begin with + # "@executable_path/../" and will work from all executables in all + # such same-level-directories inside the bundle. + # + + # By default, embed things right next to the main bundle executable: + # + set(path "@executable_path/../../Contents/MacOS") + + # Embed .dylibs right next to the main bundle executable: + # + if(item MATCHES "\\.dylib$") + set(path "@executable_path/../MacOS") + set(overridden 1) + endif(item MATCHES "\\.dylib$") + + # Embed frameworks in the embedded "Frameworks" directory (sibling of MacOS): + # + if(NOT overridden) + if(item MATCHES "[^/]+\\.framework/") + set(path "@executable_path/../Frameworks") + set(overridden 1) + endif(item MATCHES "[^/]+\\.framework/") + endif(NOT overridden) + endif() + + # Provide a hook so that projects can override the default embedded location + # of any given library by whatever logic they choose: + # + if(COMMAND gp_item_default_embedded_path_override) + gp_item_default_embedded_path_override("${item}" path) + endif(COMMAND gp_item_default_embedded_path_override) + + set(${default_embedded_path_var} "${path}" PARENT_SCOPE) +endfunction(gp_item_default_embedded_path) + + +# gp_resolve_item context item exepath dirs resolved_item_var +# +# Resolve an item into an existing full path file. +# +# Override on a per-project basis by providing a project-specific +# gp_resolve_item_override function. +# +function(gp_resolve_item context item exepath dirs resolved_item_var) + set(resolved 0) + set(resolved_item "${item}") + + # Is it already resolved? + # + if(EXISTS "${resolved_item}") + set(resolved 1) + endif(EXISTS "${resolved_item}") + + if(NOT resolved) + if(item MATCHES "@executable_path") + # + # @executable_path references are assumed relative to exepath + # + string(REPLACE "@executable_path" "${exepath}" ri "${item}") + get_filename_component(ri "${ri}" ABSOLUTE) + + if(EXISTS "${ri}") + #message(STATUS "info: embedded item exists (${ri})") + set(resolved 1) + set(resolved_item "${ri}") + else(EXISTS "${ri}") + message(STATUS "warning: embedded item does not exist '${ri}'") + endif(EXISTS "${ri}") + endif(item MATCHES "@executable_path") + endif(NOT resolved) + + if(NOT resolved) + if(item MATCHES "@loader_path") + # + # @loader_path references are assumed relative to the + # PATH of the given "context" (presumably another library) + # + get_filename_component(contextpath "${context}" PATH) + string(REPLACE "@loader_path" "${contextpath}" ri "${item}") + get_filename_component(ri "${ri}" ABSOLUTE) + + if(EXISTS "${ri}") + #message(STATUS "info: embedded item exists (${ri})") + set(resolved 1) + set(resolved_item "${ri}") + else(EXISTS "${ri}") + message(STATUS "warning: embedded item does not exist '${ri}'") + endif(EXISTS "${ri}") + endif(item MATCHES "@loader_path") + endif(NOT resolved) + + if(NOT resolved) + set(ri "ri-NOTFOUND") + find_file(ri "${item}" ${exepath} ${dirs} NO_DEFAULT_PATH) + find_file(ri "${item}" ${exepath} ${dirs} /usr/lib) + if(ri) + #message(STATUS "info: 'find_file' in exepath/dirs (${ri})") + set(resolved 1) + set(resolved_item "${ri}") + set(ri "ri-NOTFOUND") + endif(ri) + endif(NOT resolved) + + if(NOT resolved) + if(item MATCHES "[^/]+\\.framework/") + set(fw "fw-NOTFOUND") + find_file(fw "${item}" + "~/Library/Frameworks" + "/Library/Frameworks" + "/System/Library/Frameworks" + ) + if(fw) + #message(STATUS "info: 'find_file' found framework (${fw})") + set(resolved 1) + set(resolved_item "${fw}") + set(fw "fw-NOTFOUND") + endif(fw) + endif(item MATCHES "[^/]+\\.framework/") + endif(NOT resolved) + + # Using find_program on Windows will find dll files that are in the PATH. + # (Converting simple file names into full path names if found.) + # + if(WIN32) + if(NOT resolved) + set(ri "ri-NOTFOUND") + find_program(ri "${item}" PATHS "${exepath};${dirs}" NO_DEFAULT_PATH) + find_program(ri "${item}" PATHS "${exepath};${dirs}") + if(ri) + #message(STATUS "info: 'find_program' in exepath/dirs (${ri})") + set(resolved 1) + set(resolved_item "${ri}") + set(ri "ri-NOTFOUND") + endif(ri) + endif(NOT resolved) + endif(WIN32) + + # Provide a hook so that projects can override item resolution + # by whatever logic they choose: + # + if(COMMAND gp_resolve_item_override) + gp_resolve_item_override("${context}" "${item}" "${exepath}" "${dirs}" resolved_item resolved) + endif(COMMAND gp_resolve_item_override) + + if(NOT resolved) + message(STATUS " +warning: cannot resolve item '${item}' + + possible problems: + need more directories? + need to use InstallRequiredSystemLibraries? + run in install tree instead of build tree? +") +# message(STATUS " +#****************************************************************************** +#warning: cannot resolve item '${item}' +# +# possible problems: +# need more directories? +# need to use InstallRequiredSystemLibraries? +# run in install tree instead of build tree? +# +# context='${context}' +# item='${item}' +# exepath='${exepath}' +# dirs='${dirs}' +# resolved_item_var='${resolved_item_var}' +#****************************************************************************** +#") + endif(NOT resolved) + + set(${resolved_item_var} "${resolved_item}" PARENT_SCOPE) +endfunction(gp_resolve_item) + + +# gp_resolved_file_type original_file file exepath dirs type_var +# +# Return the type of ${file} with respect to ${original_file}. String +# describing type of prerequisite is returned in variable named ${type_var}. +# +# Use ${exepath} and ${dirs} if necessary to resolve non-absolute ${file} +# values -- but only for non-embedded items. +# +# Possible types are: +# system +# local +# embedded +# other +# +function(gp_resolved_file_type original_file file exepath dirs type_var) + #message(STATUS "**") + + if(NOT IS_ABSOLUTE "${original_file}") + message(STATUS "warning: gp_resolved_file_type expects absolute full path for first arg original_file") + endif() + + set(is_embedded 0) + set(is_local 0) + set(is_system 0) + + set(resolved_file "${file}") + + if("${file}" MATCHES "^@(executable|loader)_path") + set(is_embedded 1) + endif() + + if(NOT is_embedded) + if(NOT IS_ABSOLUTE "${file}") + gp_resolve_item("${original_file}" "${file}" "${exepath}" "${dirs}" resolved_file) + endif() + + string(TOLOWER "${original_file}" original_lower) + string(TOLOWER "${resolved_file}" lower) + + if(UNIX) + if(resolved_file MATCHES "^(/lib/|/lib32/|/lib64/|/usr/lib/|/usr/lib32/|/usr/lib64/|/usr/X11R6/)") + set(is_system 1) + endif() + endif() + + if(APPLE) + if(resolved_file MATCHES "^(/System/Library/|/usr/lib/)") + set(is_system 1) + endif() + endif() + + if(WIN32) + string(TOLOWER "$ENV{SystemRoot}" sysroot) + string(REGEX REPLACE "\\\\" "/" sysroot "${sysroot}") + + string(TOLOWER "$ENV{windir}" windir) + string(REGEX REPLACE "\\\\" "/" windir "${windir}") + + if(lower MATCHES "^(${sysroot}/system|${windir}/system|${sysroot}/syswow|${windir}/syswow|(.*/)*msvc[^/]+dll)") + set(is_system 1) + endif() + endif() + + if(NOT is_system) + get_filename_component(original_path "${original_lower}" PATH) + get_filename_component(path "${lower}" PATH) + if("${original_path}" STREQUAL "${path}") + set(is_local 1) + endif() + endif() + endif() + + # Return type string based on computed booleans: + # + set(type "other") + + if(is_system) + set(type "system") + elseif(is_embedded) + set(type "embedded") + elseif(is_local) + set(type "local") + endif() + + #message(STATUS "gp_resolved_file_type: '${file}' '${resolved_file}'") + #message(STATUS " type: '${type}'") + + if(NOT is_embedded) + if(NOT IS_ABSOLUTE "${resolved_file}") + if(lower MATCHES "^msvc[^/]+dll" AND is_system) + message(STATUS "info: non-absolute msvc file '${file}' returning type '${type}'") + else() + message(STATUS "warning: gp_resolved_file_type non-absolute file '${file}' returning type '${type}' -- possibly incorrect") + endif() + endif() + endif() + + set(${type_var} "${type}" PARENT_SCOPE) + + #message(STATUS "**") +endfunction() + + +# gp_file_type original_file file type_var +# +# Return the type of ${file} with respect to ${original_file}. String +# describing type of prerequisite is returned in variable named ${type_var}. +# +# Possible types are: +# system +# local +# embedded +# other +# +function(gp_file_type original_file file type_var) + if(NOT IS_ABSOLUTE "${original_file}") + message(STATUS "warning: gp_file_type expects absolute full path for first arg original_file") + endif() + + get_filename_component(exepath "${original_file}" PATH) + + set(type "") + gp_resolved_file_type("${original_file}" "${file}" "${exepath}" "" type) + + set(${type_var} "${type}" PARENT_SCOPE) +endfunction(gp_file_type) + + +# get_prerequisites target prerequisites_var exclude_system recurse dirs +# +# Get the list of shared library files required by ${target}. The list in +# the variable named ${prerequisites_var} should be empty on first entry to +# this function. On exit, ${prerequisites_var} will contain the list of +# required shared library files. +# +# target is the full path to an executable file +# +# prerequisites_var is the name of a CMake variable to contain the results +# +# exclude_system is 0 or 1: 0 to include "system" prerequisites , 1 to +# exclude them +# +# recurse is 0 or 1: 0 for direct prerequisites only, 1 for all prerequisites +# recursively +# +# exepath is the path to the top level executable used for @executable_path +# replacment on the Mac +# +# dirs is a list of paths where libraries might be found: these paths are +# searched first when a target without any path info is given. Then standard +# system locations are also searched: PATH, Framework locations, /usr/lib... +# +function(get_prerequisites target prerequisites_var exclude_system recurse exepath dirs) + set(verbose 0) + set(eol_char "E") + + if(NOT IS_ABSOLUTE "${target}") + message("warning: target '${target}' is not absolute...") + endif(NOT IS_ABSOLUTE "${target}") + + if(NOT EXISTS "${target}") + message("warning: target '${target}' does not exist...") + endif(NOT EXISTS "${target}") + + # + # + # Try to choose the right tool by default. Caller can set gp_tool prior to + # calling this function to force using a different tool. + # + if("${gp_tool}" STREQUAL "") + set(gp_tool "ldd") + if(APPLE) + set(gp_tool "otool") + endif(APPLE) + if(WIN32) + set(gp_tool "dumpbin") + endif(WIN32) + endif("${gp_tool}" STREQUAL "") + + set(gp_tool_known 0) + + if("${gp_tool}" STREQUAL "ldd") + set(gp_cmd_args "") + set(gp_regex "^[\t ]*[^\t ]+ => ([^\t ]+).*${eol_char}$") + set(gp_regex_cmp_count 1) + set(gp_tool_known 1) + endif("${gp_tool}" STREQUAL "ldd") + + if("${gp_tool}" STREQUAL "otool") + set(gp_cmd_args "-L") + set(gp_regex "^\t([^\t]+) \\(compatibility version ([0-9]+.[0-9]+.[0-9]+), current version ([0-9]+.[0-9]+.[0-9]+)\\)${eol_char}$") + set(gp_regex_cmp_count 3) + set(gp_tool_known 1) + endif("${gp_tool}" STREQUAL "otool") + + if("${gp_tool}" STREQUAL "dumpbin") + set(gp_cmd_args "/dependents") + set(gp_regex "^ ([^ ].*[Dd][Ll][Ll])${eol_char}$") + set(gp_regex_cmp_count 1) + set(gp_tool_known 1) + set(ENV{VS_UNICODE_OUTPUT} "") # Block extra output from inside VS IDE. + endif("${gp_tool}" STREQUAL "dumpbin") + + if(NOT gp_tool_known) + message(STATUS "warning: gp_tool='${gp_tool}' is an unknown tool...") + message(STATUS "CMake function get_prerequisites needs more code to handle '${gp_tool}'") + message(STATUS "Valid gp_tool values are dumpbin, ldd and otool.") + return() + endif(NOT gp_tool_known) + + set(gp_cmd_paths ${gp_cmd_paths} + "C:/Program Files/Microsoft Visual Studio 9.0/VC/bin" + "C:/Program Files (x86)/Microsoft Visual Studio 9.0/VC/bin" + "C:/Program Files/Microsoft Visual Studio 8/VC/BIN" + "C:/Program Files (x86)/Microsoft Visual Studio 8/VC/BIN" + "C:/Program Files/Microsoft Visual Studio .NET 2003/VC7/BIN" + "C:/Program Files (x86)/Microsoft Visual Studio .NET 2003/VC7/BIN" + "/usr/local/bin" + "/usr/bin" + ) + + find_program(gp_cmd ${gp_tool} PATHS ${gp_cmd_paths}) + + if(NOT gp_cmd) + message(STATUS "warning: could not find '${gp_tool}' - cannot analyze prerequisites...") + return() + endif(NOT gp_cmd) + + if("${gp_tool}" STREQUAL "dumpbin") + # When running dumpbin, it also needs the "Common7/IDE" directory in the + # PATH. It will already be in the PATH if being run from a Visual Studio + # command prompt. Add it to the PATH here in case we are running from a + # different command prompt. + # + get_filename_component(gp_cmd_dir "${gp_cmd}" PATH) + get_filename_component(gp_cmd_dlls_dir "${gp_cmd_dir}/../../Common7/IDE" ABSOLUTE) + if(EXISTS "${gp_cmd_dlls_dir}") + # only add to the path if it is not already in the path + if(NOT "$ENV{PATH}" MATCHES "${gp_cmd_dlls_dir}") + set(ENV{PATH} "$ENV{PATH};${gp_cmd_dlls_dir}") + endif(NOT "$ENV{PATH}" MATCHES "${gp_cmd_dlls_dir}") + endif(EXISTS "${gp_cmd_dlls_dir}") + endif("${gp_tool}" STREQUAL "dumpbin") + # + # + + if("${gp_tool}" STREQUAL "ldd") + set(old_ld_env "$ENV{LD_LIBRARY_PATH}") + foreach(dir ${exepath} ${dirs}) + set(ENV{LD_LIBRARY_PATH} "${dir}:$ENV{LD_LIBRARY_PATH}") + endforeach(dir) + endif("${gp_tool}" STREQUAL "ldd") + + + # Track new prerequisites at each new level of recursion. Start with an + # empty list at each level: + # + set(unseen_prereqs) + + # Run gp_cmd on the target: + # + execute_process( + COMMAND ${gp_cmd} ${gp_cmd_args} ${target} + OUTPUT_VARIABLE gp_cmd_ov + ) + + if("${gp_tool}" STREQUAL "ldd") + set(ENV{LD_LIBRARY_PATH} "${old_ld_env}") + endif("${gp_tool}" STREQUAL "ldd") + + if(verbose) + message(STATUS "") + message(STATUS "gp_cmd_ov='${gp_cmd_ov}'") + message(STATUS "") + endif(verbose) + + get_filename_component(target_dir "${target}" PATH) + + # Convert to a list of lines: + # + string(REGEX REPLACE ";" "\\\\;" candidates "${gp_cmd_ov}") + string(REGEX REPLACE "\n" "${eol_char};" candidates "${candidates}") + + # Analyze each line for file names that match the regular expression: + # + foreach(candidate ${candidates}) + if("${candidate}" MATCHES "${gp_regex}") + # Extract information from each candidate: + string(REGEX REPLACE "${gp_regex}" "\\1" raw_item "${candidate}") + + if(gp_regex_cmp_count GREATER 1) + string(REGEX REPLACE "${gp_regex}" "\\2" raw_compat_version "${candidate}") + string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\1" compat_major_version "${raw_compat_version}") + string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\2" compat_minor_version "${raw_compat_version}") + string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\3" compat_patch_version "${raw_compat_version}") + endif(gp_regex_cmp_count GREATER 1) + + if(gp_regex_cmp_count GREATER 2) + string(REGEX REPLACE "${gp_regex}" "\\3" raw_current_version "${candidate}") + string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\1" current_major_version "${raw_current_version}") + string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\2" current_minor_version "${raw_current_version}") + string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\3" current_patch_version "${raw_current_version}") + endif(gp_regex_cmp_count GREATER 2) + + # Use the raw_item as the list entries returned by this function. Use the + # gp_resolve_item function to resolve it to an actual full path file if + # necessary. + # + set(item "${raw_item}") + + # Add each item unless it is excluded: + # + set(add_item 1) + + if(${exclude_system}) + set(type "") + gp_resolved_file_type("${target}" "${item}" "${exepath}" "${dirs}" type) + if("${type}" STREQUAL "system") + set(add_item 0) + endif("${type}" STREQUAL "system") + endif(${exclude_system}) + + if(add_item) + list(LENGTH ${prerequisites_var} list_length_before_append) + gp_append_unique(${prerequisites_var} "${item}") + list(LENGTH ${prerequisites_var} list_length_after_append) + + if(${recurse}) + # If item was really added, this is the first time we have seen it. + # Add it to unseen_prereqs so that we can recursively add *its* + # prerequisites... + # + # But first: resolve its name to an absolute full path name such + # that the analysis tools can simply accept it as input. + # + if(NOT list_length_before_append EQUAL list_length_after_append) + gp_resolve_item("${target}" "${item}" "${exepath}" "${dirs}" resolved_item) + set(unseen_prereqs ${unseen_prereqs} "${resolved_item}") + endif(NOT list_length_before_append EQUAL list_length_after_append) + endif(${recurse}) + endif(add_item) + else("${candidate}" MATCHES "${gp_regex}") + if(verbose) + message(STATUS "ignoring non-matching line: '${candidate}'") + endif(verbose) + endif("${candidate}" MATCHES "${gp_regex}") + endforeach(candidate) + + list(LENGTH ${prerequisites_var} prerequisites_var_length) + if(prerequisites_var_length GREATER 0) + list(SORT ${prerequisites_var}) + endif(prerequisites_var_length GREATER 0) + if(${recurse}) + set(more_inputs ${unseen_prereqs}) + foreach(input ${more_inputs}) + get_prerequisites("${input}" ${prerequisites_var} ${exclude_system} ${recurse} "${exepath}" "${dirs}") + endforeach(input) + endif(${recurse}) + + set(${prerequisites_var} ${${prerequisites_var}} PARENT_SCOPE) +endfunction(get_prerequisites) + + +# list_prerequisites target all exclude_system verbose +# +# ARGV0 (target) is the full path to an executable file +# +# optional ARGV1 (all) is 0 or 1: 0 for direct prerequisites only, +# 1 for all prerequisites recursively +# +# optional ARGV2 (exclude_system) is 0 or 1: 0 to include "system" +# prerequisites , 1 to exclude them +# +# optional ARGV3 (verbose) is 0 or 1: 0 to print only full path +# names of prerequisites, 1 to print extra information +# +function(list_prerequisites target) + if("${ARGV1}" STREQUAL "") + set(all 1) + else("${ARGV1}" STREQUAL "") + set(all "${ARGV1}") + endif("${ARGV1}" STREQUAL "") + + if("${ARGV2}" STREQUAL "") + set(exclude_system 0) + else("${ARGV2}" STREQUAL "") + set(exclude_system "${ARGV2}") + endif("${ARGV2}" STREQUAL "") + + if("${ARGV3}" STREQUAL "") + set(verbose 0) + else("${ARGV3}" STREQUAL "") + set(verbose "${ARGV3}") + endif("${ARGV3}" STREQUAL "") + + set(count 0) + set(count_str "") + set(print_count "${verbose}") + set(print_prerequisite_type "${verbose}") + set(print_target "${verbose}") + set(type_str "") + + get_filename_component(exepath "${target}" PATH) + + set(prereqs "") + get_prerequisites("${target}" prereqs ${exclude_system} ${all} "${exepath}" "") + + if(print_target) + message(STATUS "File '${target}' depends on:") + endif(print_target) + + foreach(d ${prereqs}) + math(EXPR count "${count} + 1") + + if(print_count) + set(count_str "${count}. ") + endif(print_count) + + if(print_prerequisite_type) + gp_file_type("${target}" "${d}" type) + set(type_str " (${type})") + endif(print_prerequisite_type) + + message(STATUS "${count_str}${d}${type_str}") + endforeach(d) +endfunction(list_prerequisites) + + +# list_prerequisites_by_glob glob_arg glob_exp +# +# glob_arg is GLOB or GLOB_RECURSE +# +# glob_exp is a globbing expression used with "file(GLOB" to retrieve a list +# of matching files. If a matching file is executable, its prerequisites are +# listed. +# +# Any additional (optional) arguments provided are passed along as the +# optional arguments to the list_prerequisites calls. +# +function(list_prerequisites_by_glob glob_arg glob_exp) + message(STATUS "=============================================================================") + message(STATUS "List prerequisites of executables matching ${glob_arg} '${glob_exp}'") + message(STATUS "") + file(${glob_arg} file_list ${glob_exp}) + foreach(f ${file_list}) + is_file_executable("${f}" is_f_executable) + if(is_f_executable) + message(STATUS "=============================================================================") + list_prerequisites("${f}" ${ARGN}) + message(STATUS "") + endif(is_f_executable) + endforeach(f) +endfunction(list_prerequisites_by_glob) diff --git a/indra/cmake/LLAddBuildTest.cmake b/indra/cmake/LLAddBuildTest.cmake index 62b764bb30..05f0492234 100644 --- a/indra/cmake/LLAddBuildTest.cmake +++ b/indra/cmake/LLAddBuildTest.cmake @@ -1,276 +1,276 @@ -# -*- cmake -*- -include(LLTestCommand) -include(GoogleMock) - -MACRO(LL_ADD_PROJECT_UNIT_TESTS project sources) - # Given a project name and a list of sourcefiles (with optional properties on each), - # add targets to build and run the tests specified. - # ASSUMPTIONS: - # * this macro is being executed in the project file that is passed in - # * current working SOURCE dir is that project dir - # * there is a subfolder tests/ with test code corresponding to the filenames passed in - # * properties for each sourcefile passed in indicate what libs to link that file with (MAKE NO ASSUMPTIONS ASIDE FROM TUT) - # - # More info and examples at: https://wiki.secondlife.com/wiki/How_to_add_unit_tests_to_indra_code - # - # WARNING: do NOT modify this code without working with poppy - - # there is another branch that will conflict heavily with any changes here. -INCLUDE(GoogleMock) - - - IF(LL_TEST_VERBOSE) - MESSAGE("LL_ADD_PROJECT_UNIT_TESTS UNITTEST_PROJECT_${project} sources: ${sources}") - ENDIF(LL_TEST_VERBOSE) - - # Start with the header and project-wide setup before making targets - #project(UNITTEST_PROJECT_${project}) - # Setup includes, paths, etc - SET(alltest_SOURCE_FILES - ${CMAKE_SOURCE_DIR}/test/test.cpp - ${CMAKE_SOURCE_DIR}/test/lltut.cpp - ) - SET(alltest_DEP_TARGETS - # needed by the test harness itself - ${APRUTIL_LIBRARIES} - ${APR_LIBRARIES} - llcommon - ) - IF(NOT "${project}" STREQUAL "llmath") - # add llmath as a dep unless the tested module *is* llmath! - LIST(APPEND alltest_DEP_TARGETS - llmath - ) - ENDIF(NOT "${project}" STREQUAL "llmath") - SET(alltest_INCLUDE_DIRS - ${LLMATH_INCLUDE_DIRS} - ${LLCOMMON_INCLUDE_DIRS} - ${LIBS_OPEN_DIR}/test - ${GOOGLEMOCK_INCLUDE_DIRS} - ) - SET(alltest_LIBRARIES - ${GOOGLEMOCK_LIBRARIES} - ${PTHREAD_LIBRARY} - ${WINDOWS_LIBRARIES} - ) - # Headers, for convenience in targets. - SET(alltest_HEADER_FILES - ${CMAKE_SOURCE_DIR}/test/test.h - ) - - # Use the default flags - if (LINUX) - SET(CMAKE_EXE_LINKER_FLAGS "") - endif (LINUX) - - # start the source test executable definitions - SET(${project}_TEST_OUTPUT "") - FOREACH (source ${sources}) - STRING( REGEX REPLACE "(.*)\\.[^.]+$" "\\1" name ${source} ) - STRING( REGEX REPLACE ".*\\.([^.]+)$" "\\1" extension ${source} ) - IF(LL_TEST_VERBOSE) - MESSAGE("LL_ADD_PROJECT_UNIT_TESTS UNITTEST_PROJECT_${project} individual source: ${source} (${name}.${extension})") - ENDIF(LL_TEST_VERBOSE) - - # - # Per-codefile additional / external source, header, and include dir property extraction - # - # Source - GET_SOURCE_FILE_PROPERTY(${name}_test_additional_SOURCE_FILES ${source} LL_TEST_ADDITIONAL_SOURCE_FILES) - IF(${name}_test_additional_SOURCE_FILES MATCHES NOTFOUND) - SET(${name}_test_additional_SOURCE_FILES "") - ENDIF(${name}_test_additional_SOURCE_FILES MATCHES NOTFOUND) - SET(${name}_test_SOURCE_FILES ${source} tests/${name}_test.${extension} ${alltest_SOURCE_FILES} ${${name}_test_additional_SOURCE_FILES} ) - IF(LL_TEST_VERBOSE) - MESSAGE("LL_ADD_PROJECT_UNIT_TESTS ${name}_test_SOURCE_FILES ${${name}_test_SOURCE_FILES}") - ENDIF(LL_TEST_VERBOSE) - # Headers - GET_SOURCE_FILE_PROPERTY(${name}_test_additional_HEADER_FILES ${source} LL_TEST_ADDITIONAL_HEADER_FILES) - IF(${name}_test_additional_HEADER_FILES MATCHES NOTFOUND) - SET(${name}_test_additional_HEADER_FILES "") - ENDIF(${name}_test_additional_HEADER_FILES MATCHES NOTFOUND) - SET(${name}_test_HEADER_FILES ${name}.h ${${name}_test_additional_HEADER_FILES}) - set_source_files_properties(${${name}_test_HEADER_FILES} PROPERTIES HEADER_FILE_ONLY TRUE) - LIST(APPEND ${name}_test_SOURCE_FILES ${${name}_test_HEADER_FILES}) - IF(LL_TEST_VERBOSE) - MESSAGE("LL_ADD_PROJECT_UNIT_TESTS ${name}_test_HEADER_FILES ${${name}_test_HEADER_FILES}") - ENDIF(LL_TEST_VERBOSE) - # Include dirs - GET_SOURCE_FILE_PROPERTY(${name}_test_additional_INCLUDE_DIRS ${source} LL_TEST_ADDITIONAL_INCLUDE_DIRS) - IF(${name}_test_additional_INCLUDE_DIRS MATCHES NOTFOUND) - SET(${name}_test_additional_INCLUDE_DIRS "") - ENDIF(${name}_test_additional_INCLUDE_DIRS MATCHES NOTFOUND) - INCLUDE_DIRECTORIES(${alltest_INCLUDE_DIRS} ${name}_test_additional_INCLUDE_DIRS ) - IF(LL_TEST_VERBOSE) - MESSAGE("LL_ADD_PROJECT_UNIT_TESTS ${name}_test_additional_INCLUDE_DIRS ${${name}_test_additional_INCLUDE_DIRS}") - ENDIF(LL_TEST_VERBOSE) - - - # Setup target - ADD_EXECUTABLE(PROJECT_${project}_TEST_${name} ${${name}_test_SOURCE_FILES}) - SET_TARGET_PROPERTIES(PROJECT_${project}_TEST_${name} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${EXE_STAGING_DIR}") - - # - # Per-codefile additional / external project dep and lib dep property extraction - # - # WARNING: it's REALLY IMPORTANT to not mix these. I guarantee it will not work in the future. + poppy 2009-04-19 - # Projects - GET_SOURCE_FILE_PROPERTY(${name}_test_additional_PROJECTS ${source} LL_TEST_ADDITIONAL_PROJECTS) - IF(${name}_test_additional_PROJECTS MATCHES NOTFOUND) - SET(${name}_test_additional_PROJECTS "") - ENDIF(${name}_test_additional_PROJECTS MATCHES NOTFOUND) - # Libraries - GET_SOURCE_FILE_PROPERTY(${name}_test_additional_LIBRARIES ${source} LL_TEST_ADDITIONAL_LIBRARIES) - IF(${name}_test_additional_LIBRARIES MATCHES NOTFOUND) - SET(${name}_test_additional_LIBRARIES "") - ENDIF(${name}_test_additional_LIBRARIES MATCHES NOTFOUND) - IF(LL_TEST_VERBOSE) - MESSAGE("LL_ADD_PROJECT_UNIT_TESTS ${name}_test_additional_PROJECTS ${${name}_test_additional_PROJECTS}") - MESSAGE("LL_ADD_PROJECT_UNIT_TESTS ${name}_test_additional_LIBRARIES ${${name}_test_additional_LIBRARIES}") - ENDIF(LL_TEST_VERBOSE) - # Add to project - TARGET_LINK_LIBRARIES(PROJECT_${project}_TEST_${name} ${alltest_LIBRARIES} ${alltest_DEP_TARGETS} ${${name}_test_additional_PROJECTS} ${${name}_test_additional_LIBRARIES} ) - # Compile-time Definitions - GET_SOURCE_FILE_PROPERTY(${name}_test_additional_CFLAGS ${source} LL_TEST_ADDITIONAL_CFLAGS) - IF(NOT ${name}_test_additional_CFLAGS MATCHES NOTFOUND) - SET_TARGET_PROPERTIES(PROJECT_${project}_TEST_${name} PROPERTIES COMPILE_FLAGS ${${name}_test_additional_CFLAGS} ) - IF(LL_TEST_VERBOSE) - MESSAGE("LL_ADD_PROJECT_UNIT_TESTS ${name}_test_additional_CFLAGS ${${name}_test_additional_CFLAGS}") - ENDIF(LL_TEST_VERBOSE) - ENDIF(NOT ${name}_test_additional_CFLAGS MATCHES NOTFOUND) - - # - # Setup test targets - # - GET_TARGET_PROPERTY(TEST_EXE PROJECT_${project}_TEST_${name} LOCATION) - SET(TEST_OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/PROJECT_${project}_TEST_${name}_ok.txt) - SET(TEST_CMD ${TEST_EXE} --touch=${TEST_OUTPUT} --sourcedir=${CMAKE_CURRENT_SOURCE_DIR}) - - # daveh - what configuration does this use? Debug? it's cmake-time, not build time. + poppy 2009-04-19 - IF(LL_TEST_VERBOSE) - MESSAGE(STATUS "LL_ADD_PROJECT_UNIT_TESTS ${name} test_cmd = ${TEST_CMD}") - ENDIF(LL_TEST_VERBOSE) - - SET_TEST_PATH(LD_LIBRARY_PATH) - LL_TEST_COMMAND(TEST_SCRIPT_CMD "${LD_LIBRARY_PATH}" ${TEST_CMD}) - IF(LL_TEST_VERBOSE) - MESSAGE(STATUS "LL_ADD_PROJECT_UNIT_TESTS ${name} test_script = ${TEST_SCRIPT_CMD}") - ENDIF(LL_TEST_VERBOSE) - # Add test - ADD_CUSTOM_COMMAND( - OUTPUT ${TEST_OUTPUT} - COMMAND ${TEST_SCRIPT_CMD} - DEPENDS PROJECT_${project}_TEST_${name} - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - ) - # Why not add custom target and add POST_BUILD command? - # Slightly less uncertain behavior - # (OUTPUT commands run non-deterministically AFAIK) + poppy 2009-04-19 - # > I did not use a post build step as I could not make it notify of a - # > failure after the first time you build and fail a test. - daveh 2009-04-20 - LIST(APPEND ${project}_TEST_OUTPUT ${TEST_OUTPUT}) - ENDFOREACH (source) - - # Add the test runner target per-project - # (replaces old _test_ok targets all over the place) - ADD_CUSTOM_TARGET(${project}_tests ALL DEPENDS ${${project}_TEST_OUTPUT}) - ADD_DEPENDENCIES(${project} ${project}_tests) -ENDMACRO(LL_ADD_PROJECT_UNIT_TESTS) - -FUNCTION(LL_ADD_INTEGRATION_TEST - testname - additional_source_files - library_dependencies -# variable args - ) - if(TEST_DEBUG) - message(STATUS "Adding INTEGRATION_TEST_${testname} - debug output is on") - endif(TEST_DEBUG) - - SET(source_files - tests/${testname}_test.cpp - ${CMAKE_SOURCE_DIR}/test/test.cpp - ${CMAKE_SOURCE_DIR}/test/lltut.cpp - ${additional_source_files} - ) - - SET(libraries - ${library_dependencies} - ${GOOGLEMOCK_LIBRARIES} - ${PTHREAD_LIBRARY} - ) - - # Add test executable build target - if(TEST_DEBUG) - message(STATUS "ADD_EXECUTABLE(INTEGRATION_TEST_${testname} ${source_files})") - endif(TEST_DEBUG) - ADD_EXECUTABLE(INTEGRATION_TEST_${testname} ${source_files}) - SET_TARGET_PROPERTIES(INTEGRATION_TEST_${testname} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${EXE_STAGING_DIR}") - if(STANDALONE) - SET_TARGET_PROPERTIES(INTEGRATION_TEST_${testname} PROPERTIES COMPILE_FLAGS -I"${TUT_INCLUDE_DIR}") - endif(STANDALONE) - - # Add link deps to the executable - if(TEST_DEBUG) - message(STATUS "TARGET_LINK_LIBRARIES(INTEGRATION_TEST_${testname} ${libraries})") - endif(TEST_DEBUG) - TARGET_LINK_LIBRARIES(INTEGRATION_TEST_${testname} ${libraries}) - - # Create the test running command - SET(test_command ${ARGN}) - GET_TARGET_PROPERTY(TEST_EXE INTEGRATION_TEST_${testname} LOCATION) - LIST(FIND test_command "{}" test_exe_pos) - IF(test_exe_pos LESS 0) - # The {} marker means "the full pathname of the test executable." - # test_exe_pos -1 means we didn't find it -- so append the test executable - # name to $ARGN, the variable part of the arg list. This is convenient - # shorthand for both straightforward execution of the test program (empty - # $ARGN) and for running a "wrapper" program of some kind accepting the - # pathname of the test program as the last of its args. You need specify - # {} only if the test program's pathname isn't the last argument in the - # desired command line. - LIST(APPEND test_command "${TEST_EXE}") - ELSE (test_exe_pos LESS 0) - # Found {} marker at test_exe_pos. Remove the {}... - LIST(REMOVE_AT test_command test_exe_pos) - # ...and replace it with the actual name of the test executable. - LIST(INSERT test_command test_exe_pos "${TEST_EXE}") - ENDIF (test_exe_pos LESS 0) - - SET_TEST_PATH(LD_LIBRARY_PATH) - LL_TEST_COMMAND(TEST_SCRIPT_CMD "${LD_LIBRARY_PATH}" ${test_command}) - - if(TEST_DEBUG) - message(STATUS "TEST_SCRIPT_CMD: ${TEST_SCRIPT_CMD}") - endif(TEST_DEBUG) - - ADD_CUSTOM_COMMAND( - TARGET INTEGRATION_TEST_${testname} - POST_BUILD - COMMAND ${TEST_SCRIPT_CMD} - ) - - # Use CTEST? Not sure how to yet... - # ADD_TEST(INTEGRATION_TEST_RUNNER_${testname} ${TEST_SCRIPT_CMD}) - -ENDFUNCTION(LL_ADD_INTEGRATION_TEST) - -MACRO(SET_TEST_PATH LISTVAR) - IF(WINDOWS) - # We typically build/package only Release variants of third-party - # libraries, so append the Release staging dir in case the library being - # sought doesn't have a debug variant. - set(${LISTVAR} ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR} ${SHARED_LIB_STAGING_DIR}/Release) - ELSEIF(DARWIN) - # We typically build/package only Release variants of third-party - # libraries, so append the Release staging dir in case the library being - # sought doesn't have a debug variant. - set(${LISTVAR} ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/Resources ${SHARED_LIB_STAGING_DIR}/Release/Resources /usr/lib) - ELSE(WINDOWS) - # Linux uses a single staging directory anyway. - IF (STANDALONE) - set(${LISTVAR} ${CMAKE_BINARY_DIR}/llcommon /usr/lib /usr/local/lib) - ELSE (STANDALONE) - set(${LISTVAR} ${SHARED_LIB_STAGING_DIR} /usr/lib) - ENDIF (STANDALONE) - ENDIF(WINDOWS) -ENDMACRO(SET_TEST_PATH) +# -*- cmake -*- +include(LLTestCommand) +include(GoogleMock) + +MACRO(LL_ADD_PROJECT_UNIT_TESTS project sources) + # Given a project name and a list of sourcefiles (with optional properties on each), + # add targets to build and run the tests specified. + # ASSUMPTIONS: + # * this macro is being executed in the project file that is passed in + # * current working SOURCE dir is that project dir + # * there is a subfolder tests/ with test code corresponding to the filenames passed in + # * properties for each sourcefile passed in indicate what libs to link that file with (MAKE NO ASSUMPTIONS ASIDE FROM TUT) + # + # More info and examples at: https://wiki.secondlife.com/wiki/How_to_add_unit_tests_to_indra_code + # + # WARNING: do NOT modify this code without working with poppy - + # there is another branch that will conflict heavily with any changes here. +INCLUDE(GoogleMock) + + + IF(LL_TEST_VERBOSE) + MESSAGE("LL_ADD_PROJECT_UNIT_TESTS UNITTEST_PROJECT_${project} sources: ${sources}") + ENDIF(LL_TEST_VERBOSE) + + # Start with the header and project-wide setup before making targets + #project(UNITTEST_PROJECT_${project}) + # Setup includes, paths, etc + SET(alltest_SOURCE_FILES + ${CMAKE_SOURCE_DIR}/test/test.cpp + ${CMAKE_SOURCE_DIR}/test/lltut.cpp + ) + SET(alltest_DEP_TARGETS + # needed by the test harness itself + ${APRUTIL_LIBRARIES} + ${APR_LIBRARIES} + llcommon + ) + IF(NOT "${project}" STREQUAL "llmath") + # add llmath as a dep unless the tested module *is* llmath! + LIST(APPEND alltest_DEP_TARGETS + llmath + ) + ENDIF(NOT "${project}" STREQUAL "llmath") + SET(alltest_INCLUDE_DIRS + ${LLMATH_INCLUDE_DIRS} + ${LLCOMMON_INCLUDE_DIRS} + ${LIBS_OPEN_DIR}/test + ${GOOGLEMOCK_INCLUDE_DIRS} + ) + SET(alltest_LIBRARIES + ${GOOGLEMOCK_LIBRARIES} + ${PTHREAD_LIBRARY} + ${WINDOWS_LIBRARIES} + ) + # Headers, for convenience in targets. + SET(alltest_HEADER_FILES + ${CMAKE_SOURCE_DIR}/test/test.h + ) + + # Use the default flags + if (LINUX) + SET(CMAKE_EXE_LINKER_FLAGS "") + endif (LINUX) + + # start the source test executable definitions + SET(${project}_TEST_OUTPUT "") + FOREACH (source ${sources}) + STRING( REGEX REPLACE "(.*)\\.[^.]+$" "\\1" name ${source} ) + STRING( REGEX REPLACE ".*\\.([^.]+)$" "\\1" extension ${source} ) + IF(LL_TEST_VERBOSE) + MESSAGE("LL_ADD_PROJECT_UNIT_TESTS UNITTEST_PROJECT_${project} individual source: ${source} (${name}.${extension})") + ENDIF(LL_TEST_VERBOSE) + + # + # Per-codefile additional / external source, header, and include dir property extraction + # + # Source + GET_SOURCE_FILE_PROPERTY(${name}_test_additional_SOURCE_FILES ${source} LL_TEST_ADDITIONAL_SOURCE_FILES) + IF(${name}_test_additional_SOURCE_FILES MATCHES NOTFOUND) + SET(${name}_test_additional_SOURCE_FILES "") + ENDIF(${name}_test_additional_SOURCE_FILES MATCHES NOTFOUND) + SET(${name}_test_SOURCE_FILES ${source} tests/${name}_test.${extension} ${alltest_SOURCE_FILES} ${${name}_test_additional_SOURCE_FILES} ) + IF(LL_TEST_VERBOSE) + MESSAGE("LL_ADD_PROJECT_UNIT_TESTS ${name}_test_SOURCE_FILES ${${name}_test_SOURCE_FILES}") + ENDIF(LL_TEST_VERBOSE) + # Headers + GET_SOURCE_FILE_PROPERTY(${name}_test_additional_HEADER_FILES ${source} LL_TEST_ADDITIONAL_HEADER_FILES) + IF(${name}_test_additional_HEADER_FILES MATCHES NOTFOUND) + SET(${name}_test_additional_HEADER_FILES "") + ENDIF(${name}_test_additional_HEADER_FILES MATCHES NOTFOUND) + SET(${name}_test_HEADER_FILES ${name}.h ${${name}_test_additional_HEADER_FILES}) + set_source_files_properties(${${name}_test_HEADER_FILES} PROPERTIES HEADER_FILE_ONLY TRUE) + LIST(APPEND ${name}_test_SOURCE_FILES ${${name}_test_HEADER_FILES}) + IF(LL_TEST_VERBOSE) + MESSAGE("LL_ADD_PROJECT_UNIT_TESTS ${name}_test_HEADER_FILES ${${name}_test_HEADER_FILES}") + ENDIF(LL_TEST_VERBOSE) + # Include dirs + GET_SOURCE_FILE_PROPERTY(${name}_test_additional_INCLUDE_DIRS ${source} LL_TEST_ADDITIONAL_INCLUDE_DIRS) + IF(${name}_test_additional_INCLUDE_DIRS MATCHES NOTFOUND) + SET(${name}_test_additional_INCLUDE_DIRS "") + ENDIF(${name}_test_additional_INCLUDE_DIRS MATCHES NOTFOUND) + INCLUDE_DIRECTORIES(${alltest_INCLUDE_DIRS} ${name}_test_additional_INCLUDE_DIRS ) + IF(LL_TEST_VERBOSE) + MESSAGE("LL_ADD_PROJECT_UNIT_TESTS ${name}_test_additional_INCLUDE_DIRS ${${name}_test_additional_INCLUDE_DIRS}") + ENDIF(LL_TEST_VERBOSE) + + + # Setup target + ADD_EXECUTABLE(PROJECT_${project}_TEST_${name} ${${name}_test_SOURCE_FILES}) + SET_TARGET_PROPERTIES(PROJECT_${project}_TEST_${name} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${EXE_STAGING_DIR}") + + # + # Per-codefile additional / external project dep and lib dep property extraction + # + # WARNING: it's REALLY IMPORTANT to not mix these. I guarantee it will not work in the future. + poppy 2009-04-19 + # Projects + GET_SOURCE_FILE_PROPERTY(${name}_test_additional_PROJECTS ${source} LL_TEST_ADDITIONAL_PROJECTS) + IF(${name}_test_additional_PROJECTS MATCHES NOTFOUND) + SET(${name}_test_additional_PROJECTS "") + ENDIF(${name}_test_additional_PROJECTS MATCHES NOTFOUND) + # Libraries + GET_SOURCE_FILE_PROPERTY(${name}_test_additional_LIBRARIES ${source} LL_TEST_ADDITIONAL_LIBRARIES) + IF(${name}_test_additional_LIBRARIES MATCHES NOTFOUND) + SET(${name}_test_additional_LIBRARIES "") + ENDIF(${name}_test_additional_LIBRARIES MATCHES NOTFOUND) + IF(LL_TEST_VERBOSE) + MESSAGE("LL_ADD_PROJECT_UNIT_TESTS ${name}_test_additional_PROJECTS ${${name}_test_additional_PROJECTS}") + MESSAGE("LL_ADD_PROJECT_UNIT_TESTS ${name}_test_additional_LIBRARIES ${${name}_test_additional_LIBRARIES}") + ENDIF(LL_TEST_VERBOSE) + # Add to project + TARGET_LINK_LIBRARIES(PROJECT_${project}_TEST_${name} ${alltest_LIBRARIES} ${alltest_DEP_TARGETS} ${${name}_test_additional_PROJECTS} ${${name}_test_additional_LIBRARIES} ) + # Compile-time Definitions + GET_SOURCE_FILE_PROPERTY(${name}_test_additional_CFLAGS ${source} LL_TEST_ADDITIONAL_CFLAGS) + IF(NOT ${name}_test_additional_CFLAGS MATCHES NOTFOUND) + SET_TARGET_PROPERTIES(PROJECT_${project}_TEST_${name} PROPERTIES COMPILE_FLAGS ${${name}_test_additional_CFLAGS} ) + IF(LL_TEST_VERBOSE) + MESSAGE("LL_ADD_PROJECT_UNIT_TESTS ${name}_test_additional_CFLAGS ${${name}_test_additional_CFLAGS}") + ENDIF(LL_TEST_VERBOSE) + ENDIF(NOT ${name}_test_additional_CFLAGS MATCHES NOTFOUND) + + # + # Setup test targets + # + GET_TARGET_PROPERTY(TEST_EXE PROJECT_${project}_TEST_${name} LOCATION) + SET(TEST_OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/PROJECT_${project}_TEST_${name}_ok.txt) + SET(TEST_CMD ${TEST_EXE} --touch=${TEST_OUTPUT} --sourcedir=${CMAKE_CURRENT_SOURCE_DIR}) + + # daveh - what configuration does this use? Debug? it's cmake-time, not build time. + poppy 2009-04-19 + IF(LL_TEST_VERBOSE) + MESSAGE(STATUS "LL_ADD_PROJECT_UNIT_TESTS ${name} test_cmd = ${TEST_CMD}") + ENDIF(LL_TEST_VERBOSE) + + SET_TEST_PATH(LD_LIBRARY_PATH) + LL_TEST_COMMAND(TEST_SCRIPT_CMD "${LD_LIBRARY_PATH}" ${TEST_CMD}) + IF(LL_TEST_VERBOSE) + MESSAGE(STATUS "LL_ADD_PROJECT_UNIT_TESTS ${name} test_script = ${TEST_SCRIPT_CMD}") + ENDIF(LL_TEST_VERBOSE) + # Add test + ADD_CUSTOM_COMMAND( + OUTPUT ${TEST_OUTPUT} + COMMAND ${TEST_SCRIPT_CMD} + DEPENDS PROJECT_${project}_TEST_${name} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + ) + # Why not add custom target and add POST_BUILD command? + # Slightly less uncertain behavior + # (OUTPUT commands run non-deterministically AFAIK) + poppy 2009-04-19 + # > I did not use a post build step as I could not make it notify of a + # > failure after the first time you build and fail a test. - daveh 2009-04-20 + LIST(APPEND ${project}_TEST_OUTPUT ${TEST_OUTPUT}) + ENDFOREACH (source) + + # Add the test runner target per-project + # (replaces old _test_ok targets all over the place) + ADD_CUSTOM_TARGET(${project}_tests ALL DEPENDS ${${project}_TEST_OUTPUT}) + ADD_DEPENDENCIES(${project} ${project}_tests) +ENDMACRO(LL_ADD_PROJECT_UNIT_TESTS) + +FUNCTION(LL_ADD_INTEGRATION_TEST + testname + additional_source_files + library_dependencies +# variable args + ) + if(TEST_DEBUG) + message(STATUS "Adding INTEGRATION_TEST_${testname} - debug output is on") + endif(TEST_DEBUG) + + SET(source_files + tests/${testname}_test.cpp + ${CMAKE_SOURCE_DIR}/test/test.cpp + ${CMAKE_SOURCE_DIR}/test/lltut.cpp + ${additional_source_files} + ) + + SET(libraries + ${library_dependencies} + ${GOOGLEMOCK_LIBRARIES} + ${PTHREAD_LIBRARY} + ) + + # Add test executable build target + if(TEST_DEBUG) + message(STATUS "ADD_EXECUTABLE(INTEGRATION_TEST_${testname} ${source_files})") + endif(TEST_DEBUG) + ADD_EXECUTABLE(INTEGRATION_TEST_${testname} ${source_files}) + SET_TARGET_PROPERTIES(INTEGRATION_TEST_${testname} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${EXE_STAGING_DIR}") + if(STANDALONE) + SET_TARGET_PROPERTIES(INTEGRATION_TEST_${testname} PROPERTIES COMPILE_FLAGS -I"${TUT_INCLUDE_DIR}") + endif(STANDALONE) + + # Add link deps to the executable + if(TEST_DEBUG) + message(STATUS "TARGET_LINK_LIBRARIES(INTEGRATION_TEST_${testname} ${libraries})") + endif(TEST_DEBUG) + TARGET_LINK_LIBRARIES(INTEGRATION_TEST_${testname} ${libraries}) + + # Create the test running command + SET(test_command ${ARGN}) + GET_TARGET_PROPERTY(TEST_EXE INTEGRATION_TEST_${testname} LOCATION) + LIST(FIND test_command "{}" test_exe_pos) + IF(test_exe_pos LESS 0) + # The {} marker means "the full pathname of the test executable." + # test_exe_pos -1 means we didn't find it -- so append the test executable + # name to $ARGN, the variable part of the arg list. This is convenient + # shorthand for both straightforward execution of the test program (empty + # $ARGN) and for running a "wrapper" program of some kind accepting the + # pathname of the test program as the last of its args. You need specify + # {} only if the test program's pathname isn't the last argument in the + # desired command line. + LIST(APPEND test_command "${TEST_EXE}") + ELSE (test_exe_pos LESS 0) + # Found {} marker at test_exe_pos. Remove the {}... + LIST(REMOVE_AT test_command test_exe_pos) + # ...and replace it with the actual name of the test executable. + LIST(INSERT test_command test_exe_pos "${TEST_EXE}") + ENDIF (test_exe_pos LESS 0) + + SET_TEST_PATH(LD_LIBRARY_PATH) + LL_TEST_COMMAND(TEST_SCRIPT_CMD "${LD_LIBRARY_PATH}" ${test_command}) + + if(TEST_DEBUG) + message(STATUS "TEST_SCRIPT_CMD: ${TEST_SCRIPT_CMD}") + endif(TEST_DEBUG) + + ADD_CUSTOM_COMMAND( + TARGET INTEGRATION_TEST_${testname} + POST_BUILD + COMMAND ${TEST_SCRIPT_CMD} + ) + + # Use CTEST? Not sure how to yet... + # ADD_TEST(INTEGRATION_TEST_RUNNER_${testname} ${TEST_SCRIPT_CMD}) + +ENDFUNCTION(LL_ADD_INTEGRATION_TEST) + +MACRO(SET_TEST_PATH LISTVAR) + IF(WINDOWS) + # We typically build/package only Release variants of third-party + # libraries, so append the Release staging dir in case the library being + # sought doesn't have a debug variant. + set(${LISTVAR} ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR} ${SHARED_LIB_STAGING_DIR}/Release) + ELSEIF(DARWIN) + # We typically build/package only Release variants of third-party + # libraries, so append the Release staging dir in case the library being + # sought doesn't have a debug variant. + set(${LISTVAR} ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/Resources ${SHARED_LIB_STAGING_DIR}/Release/Resources /usr/lib) + ELSE(WINDOWS) + # Linux uses a single staging directory anyway. + IF (STANDALONE) + set(${LISTVAR} ${CMAKE_BINARY_DIR}/llcommon /usr/lib /usr/local/lib) + ELSE (STANDALONE) + set(${LISTVAR} ${SHARED_LIB_STAGING_DIR} /usr/lib) + ENDIF (STANDALONE) + ENDIF(WINDOWS) +ENDMACRO(SET_TEST_PATH) diff --git a/indra/newview/llfloaterwebcontent.cpp b/indra/newview/llfloaterwebcontent.cpp index 51726112a0..058567492b 100644 --- a/indra/newview/llfloaterwebcontent.cpp +++ b/indra/newview/llfloaterwebcontent.cpp @@ -1,402 +1,402 @@ -/** - * @file llfloaterwebcontent.cpp - * @brief floater for displaying web content - e.g. profiles and search (eventually) - * - * $LicenseInfo:firstyear=2006&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 "llcombobox.h" -#include "lliconctrl.h" -#include "llfloaterreg.h" -#include "lllayoutstack.h" -#include "llpluginclassmedia.h" -#include "llprogressbar.h" -#include "lltextbox.h" -#include "llurlhistory.h" -#include "llviewercontrol.h" -#include "llweb.h" -#include "llwindow.h" - -#include "llfloaterwebcontent.h" - -LLFloaterWebContent::LLFloaterWebContent( const LLSD& key ) - : LLFloater( key ) -{ - mCommitCallbackRegistrar.add( "WebContent.Back", boost::bind( &LLFloaterWebContent::onClickBack, this )); - mCommitCallbackRegistrar.add( "WebContent.Forward", boost::bind( &LLFloaterWebContent::onClickForward, this )); - mCommitCallbackRegistrar.add( "WebContent.Reload", boost::bind( &LLFloaterWebContent::onClickReload, this )); - mCommitCallbackRegistrar.add( "WebContent.Stop", boost::bind( &LLFloaterWebContent::onClickStop, this )); - mCommitCallbackRegistrar.add( "WebContent.EnterAddress", boost::bind( &LLFloaterWebContent::onEnterAddress, this )); - mCommitCallbackRegistrar.add( "WebContent.PopExternal", boost::bind( &LLFloaterWebContent::onPopExternal, this )); -} - -BOOL LLFloaterWebContent::postBuild() -{ - // these are used in a bunch of places so cache them - mWebBrowser = getChild< LLMediaCtrl >( "webbrowser" ); - mAddressCombo = getChild< LLComboBox >( "address" ); - mStatusBarText = getChild< LLTextBox >( "statusbartext" ); - mStatusBarProgress = getChild("statusbarprogress" ); - - // observe browser events - mWebBrowser->addObserver( this ); - - // these buttons are always enabled - getChildView("reload")->setEnabled( true ); - getChildView("popexternal")->setEnabled( true ); - - // cache image for secure browsing - mSecureLockIcon = getChild< LLIconCtrl >("media_secure_lock_flag"); - - // initialize the URL history using the system URL History manager - initializeURLHistory(); - - return TRUE; -} - -void LLFloaterWebContent::initializeURLHistory() -{ - // start with an empty list - LLCtrlListInterface* url_list = childGetListInterface("address"); - if (url_list) - { - url_list->operateOnAll(LLCtrlListInterface::OP_DELETE); - } - - // Get all of the entries in the "browser" collection - LLSD browser_history = LLURLHistory::getURLHistory("browser"); - LLSD::array_iterator iter_history = - browser_history.beginArray(); - LLSD::array_iterator end_history = - browser_history.endArray(); - for(; iter_history != end_history; ++iter_history) - { - std::string url = (*iter_history).asString(); - if(! url.empty()) - url_list->addSimpleElement(url); - } -} - -//static -void LLFloaterWebContent::create( const std::string &url, const std::string& target, const std::string& uuid ) -{ - lldebugs << "url = " << url << ", target = " << target << ", uuid = " << uuid << llendl; - - std::string tag = target; - - if(target.empty() || target == "_blank") - { - if(!uuid.empty()) - { - tag = uuid; - } - else - { - // create a unique tag for this instance - LLUUID id; - id.generate(); - tag = id.asString(); - } - } - - S32 browser_window_limit = gSavedSettings.getS32("WebContentWindowLimit"); - - if(LLFloaterReg::findInstance("web_content", tag) != NULL) - { - // There's already a web browser for this tag, so we won't be opening a new window. - } - else if(browser_window_limit != 0) - { - // showInstance will open a new window. Figure out how many web browsers are already open, - // and close the least recently opened one if this will put us over the limit. - - LLFloaterReg::const_instance_list_t &instances = LLFloaterReg::getFloaterList("web_content"); - lldebugs << "total instance count is " << instances.size() << llendl; - - for(LLFloaterReg::const_instance_list_t::const_iterator iter = instances.begin(); iter != instances.end(); iter++) - { - lldebugs << " " << (*iter)->getKey() << llendl; - } - - if(instances.size() >= (size_t)browser_window_limit) - { - // Destroy the least recently opened instance - (*instances.begin())->closeFloater(); - } - } - - LLFloaterWebContent *browser = dynamic_cast (LLFloaterReg::showInstance("web_content", tag)); - llassert(browser); - if(browser) - { - browser->mUUID = uuid; - - // tell the browser instance to load the specified URL - browser->open_media(url, target); - LLViewerMedia::proxyWindowOpened(target, uuid); - } -} - -//static -void LLFloaterWebContent::closeRequest(const std::string &uuid) -{ - LLFloaterReg::const_instance_list_t& inst_list = LLFloaterReg::getFloaterList("web_content"); - lldebugs << "instance list size is " << inst_list.size() << ", incoming uuid is " << uuid << llendl; - for (LLFloaterReg::const_instance_list_t::const_iterator iter = inst_list.begin(); iter != inst_list.end(); ++iter) - { - LLFloaterWebContent* i = dynamic_cast(*iter); - lldebugs << " " << i->mUUID << llendl; - if (i && i->mUUID == uuid) - { - i->closeFloater(false); - return; - } - } -} - -//static -void LLFloaterWebContent::geometryChanged(const std::string &uuid, S32 x, S32 y, S32 width, S32 height) -{ - LLFloaterReg::const_instance_list_t& inst_list = LLFloaterReg::getFloaterList("web_content"); - lldebugs << "instance list size is " << inst_list.size() << ", incoming uuid is " << uuid << llendl; - for (LLFloaterReg::const_instance_list_t::const_iterator iter = inst_list.begin(); iter != inst_list.end(); ++iter) - { - LLFloaterWebContent* i = dynamic_cast(*iter); - lldebugs << " " << i->mUUID << llendl; - if (i && i->mUUID == uuid) - { - i->geometryChanged(x, y, width, height); - return; - } - } -} - -void LLFloaterWebContent::geometryChanged(S32 x, S32 y, S32 width, S32 height) -{ - // Make sure the layout of the browser control is updated, so this calculation is correct. - LLLayoutStack::updateClass(); - - // TODO: need to adjust size and constrain position to make sure floaters aren't moved outside the window view, etc. - LLCoordWindow window_size; - getWindow()->getSize(&window_size); - - // Adjust width and height for the size of the chrome on the web Browser window. - width += getRect().getWidth() - mWebBrowser->getRect().getWidth(); - height += getRect().getHeight() - mWebBrowser->getRect().getHeight(); - - LLRect geom; - geom.setOriginAndSize(x, window_size.mY - (y + height), width, height); - - lldebugs << "geometry change: " << geom << llendl; - - handleReshape(geom,false); -} - -void LLFloaterWebContent::open_media(const std::string& web_url, const std::string& target) -{ - // Specifying a mime type of text/html here causes the plugin system to skip the MIME type probe and just open a browser plugin. - mWebBrowser->setHomePageUrl(web_url, "text/html"); - mWebBrowser->setTarget(target); - mWebBrowser->navigateTo(web_url, "text/html"); - set_current_url(web_url); -} - -//virtual -void LLFloaterWebContent::onClose(bool app_quitting) -{ - LLViewerMedia::proxyWindowClosed(mUUID); - destroy(); -} - -// virtual -void LLFloaterWebContent::draw() -{ - // this is asychronous so we need to keep checking - getChildView( "back" )->setEnabled( mWebBrowser->canNavigateBack() ); - getChildView( "forward" )->setEnabled( mWebBrowser->canNavigateForward() ); - - LLFloater::draw(); -} - -// virtual -void LLFloaterWebContent::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event) -{ - if(event == MEDIA_EVENT_LOCATION_CHANGED) - { - const std::string url = self->getLocation(); - - if ( url.length() ) - mStatusBarText->setText( url ); - - set_current_url( url ); - } - else if(event == MEDIA_EVENT_NAVIGATE_BEGIN) - { - // flags are sent with this event - getChildView("back")->setEnabled( self->getHistoryBackAvailable() ); - getChildView("forward")->setEnabled( self->getHistoryForwardAvailable() ); - - // toggle visibility of these buttons based on browser state - getChildView("reload")->setVisible( false ); - getChildView("stop")->setVisible( true ); - - // turn "on" progress bar now we're about to start loading - mStatusBarProgress->setVisible( true ); - } - else if(event == MEDIA_EVENT_NAVIGATE_COMPLETE) - { - // flags are sent with this event - getChildView("back")->setEnabled( self->getHistoryBackAvailable() ); - getChildView("forward")->setEnabled( self->getHistoryForwardAvailable() ); - - // toggle visibility of these buttons based on browser state - getChildView("reload")->setVisible( true ); - getChildView("stop")->setVisible( false ); - - // turn "off" progress bar now we're loaded - mStatusBarProgress->setVisible( false ); - - // we populate the status bar with URLs as they change so clear it now we're done - const std::string end_str = ""; - mStatusBarText->setText( end_str ); - - // decide if secure browsing icon should be displayed - std::string prefix = std::string("https://"); - std::string test_prefix = mCurrentURL.substr(0, prefix.length()); - LLStringUtil::toLower(test_prefix); - if(test_prefix == prefix) - { - mSecureLockIcon->setVisible(true); - } - else - { - mSecureLockIcon->setVisible(false); - } - } - else if(event == MEDIA_EVENT_CLOSE_REQUEST) - { - // The browser instance wants its window closed. - closeFloater(); - } - else if(event == MEDIA_EVENT_GEOMETRY_CHANGE) - { - geometryChanged(self->getGeometryX(), self->getGeometryY(), self->getGeometryWidth(), self->getGeometryHeight()); - } - else if(event == MEDIA_EVENT_STATUS_TEXT_CHANGED ) - { - const std::string text = self->getStatusText(); - if ( text.length() ) - mStatusBarText->setText( text ); - } - else if(event == MEDIA_EVENT_PROGRESS_UPDATED ) - { - int percent = (int)self->getProgressPercent(); - mStatusBarProgress->setValue( percent ); - } - else if(event == MEDIA_EVENT_NAME_CHANGED ) - { - std::string page_title = self->getMediaName(); - // simulate browser behavior - title is empty, use the current URL - if ( page_title.length() > 0 ) - setTitle( page_title ); - else - setTitle( mCurrentURL ); - } - else if(event == MEDIA_EVENT_LINK_HOVERED ) - { - const std::string link = self->getHoverLink(); - mStatusBarText->setText( link ); - } -} - -void LLFloaterWebContent::set_current_url(const std::string& url) -{ - mCurrentURL = url; - - // serialize url history into the system URL History manager - LLURLHistory::removeURL("browser", mCurrentURL); - LLURLHistory::addURL("browser", mCurrentURL); - - mAddressCombo->remove( mCurrentURL ); - mAddressCombo->add( mCurrentURL ); - mAddressCombo->selectByValue( mCurrentURL ); -} - -void LLFloaterWebContent::onClickForward() -{ - mWebBrowser->navigateForward(); -} - -void LLFloaterWebContent::onClickBack() -{ - mWebBrowser->navigateBack(); -} - -void LLFloaterWebContent::onClickReload() -{ - - if( mWebBrowser->getMediaPlugin() ) - { - bool ignore_cache = true; - mWebBrowser->getMediaPlugin()->browse_reload( ignore_cache ); - } - else - { - mWebBrowser->navigateTo(mCurrentURL); - } -} - -void LLFloaterWebContent::onClickStop() -{ - if( mWebBrowser->getMediaPlugin() ) - mWebBrowser->getMediaPlugin()->browse_stop(); - - // still should happen when we catch the navigate complete event - // but sometimes (don't know why) that event isn't sent from Qt - // and we getto a point where the stop button stays active. - getChildView("reload")->setVisible( true ); - getChildView("stop")->setVisible( false ); -} - -void LLFloaterWebContent::onEnterAddress() -{ - // make sure there is at least something there. - // (perhaps this test should be for minimum length of a URL) - std::string url = mAddressCombo->getValue().asString(); - if ( url.length() > 0 ) - { - mWebBrowser->navigateTo( url, "text/html"); - }; -} - -void LLFloaterWebContent::onPopExternal() -{ - // make sure there is at least something there. - // (perhaps this test should be for minimum length of a URL) - std::string url = mAddressCombo->getValue().asString(); - if ( url.length() > 0 ) - { - LLWeb::loadURLExternal( url ); - }; -} +/** + * @file llfloaterwebcontent.cpp + * @brief floater for displaying web content - e.g. profiles and search (eventually) + * + * $LicenseInfo:firstyear=2006&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 "llcombobox.h" +#include "lliconctrl.h" +#include "llfloaterreg.h" +#include "lllayoutstack.h" +#include "llpluginclassmedia.h" +#include "llprogressbar.h" +#include "lltextbox.h" +#include "llurlhistory.h" +#include "llviewercontrol.h" +#include "llweb.h" +#include "llwindow.h" + +#include "llfloaterwebcontent.h" + +LLFloaterWebContent::LLFloaterWebContent( const LLSD& key ) + : LLFloater( key ) +{ + mCommitCallbackRegistrar.add( "WebContent.Back", boost::bind( &LLFloaterWebContent::onClickBack, this )); + mCommitCallbackRegistrar.add( "WebContent.Forward", boost::bind( &LLFloaterWebContent::onClickForward, this )); + mCommitCallbackRegistrar.add( "WebContent.Reload", boost::bind( &LLFloaterWebContent::onClickReload, this )); + mCommitCallbackRegistrar.add( "WebContent.Stop", boost::bind( &LLFloaterWebContent::onClickStop, this )); + mCommitCallbackRegistrar.add( "WebContent.EnterAddress", boost::bind( &LLFloaterWebContent::onEnterAddress, this )); + mCommitCallbackRegistrar.add( "WebContent.PopExternal", boost::bind( &LLFloaterWebContent::onPopExternal, this )); +} + +BOOL LLFloaterWebContent::postBuild() +{ + // these are used in a bunch of places so cache them + mWebBrowser = getChild< LLMediaCtrl >( "webbrowser" ); + mAddressCombo = getChild< LLComboBox >( "address" ); + mStatusBarText = getChild< LLTextBox >( "statusbartext" ); + mStatusBarProgress = getChild("statusbarprogress" ); + + // observe browser events + mWebBrowser->addObserver( this ); + + // these buttons are always enabled + getChildView("reload")->setEnabled( true ); + getChildView("popexternal")->setEnabled( true ); + + // cache image for secure browsing + mSecureLockIcon = getChild< LLIconCtrl >("media_secure_lock_flag"); + + // initialize the URL history using the system URL History manager + initializeURLHistory(); + + return TRUE; +} + +void LLFloaterWebContent::initializeURLHistory() +{ + // start with an empty list + LLCtrlListInterface* url_list = childGetListInterface("address"); + if (url_list) + { + url_list->operateOnAll(LLCtrlListInterface::OP_DELETE); + } + + // Get all of the entries in the "browser" collection + LLSD browser_history = LLURLHistory::getURLHistory("browser"); + LLSD::array_iterator iter_history = + browser_history.beginArray(); + LLSD::array_iterator end_history = + browser_history.endArray(); + for(; iter_history != end_history; ++iter_history) + { + std::string url = (*iter_history).asString(); + if(! url.empty()) + url_list->addSimpleElement(url); + } +} + +//static +void LLFloaterWebContent::create( const std::string &url, const std::string& target, const std::string& uuid ) +{ + lldebugs << "url = " << url << ", target = " << target << ", uuid = " << uuid << llendl; + + std::string tag = target; + + if(target.empty() || target == "_blank") + { + if(!uuid.empty()) + { + tag = uuid; + } + else + { + // create a unique tag for this instance + LLUUID id; + id.generate(); + tag = id.asString(); + } + } + + S32 browser_window_limit = gSavedSettings.getS32("WebContentWindowLimit"); + + if(LLFloaterReg::findInstance("web_content", tag) != NULL) + { + // There's already a web browser for this tag, so we won't be opening a new window. + } + else if(browser_window_limit != 0) + { + // showInstance will open a new window. Figure out how many web browsers are already open, + // and close the least recently opened one if this will put us over the limit. + + LLFloaterReg::const_instance_list_t &instances = LLFloaterReg::getFloaterList("web_content"); + lldebugs << "total instance count is " << instances.size() << llendl; + + for(LLFloaterReg::const_instance_list_t::const_iterator iter = instances.begin(); iter != instances.end(); iter++) + { + lldebugs << " " << (*iter)->getKey() << llendl; + } + + if(instances.size() >= (size_t)browser_window_limit) + { + // Destroy the least recently opened instance + (*instances.begin())->closeFloater(); + } + } + + LLFloaterWebContent *browser = dynamic_cast (LLFloaterReg::showInstance("web_content", tag)); + llassert(browser); + if(browser) + { + browser->mUUID = uuid; + + // tell the browser instance to load the specified URL + browser->open_media(url, target); + LLViewerMedia::proxyWindowOpened(target, uuid); + } +} + +//static +void LLFloaterWebContent::closeRequest(const std::string &uuid) +{ + LLFloaterReg::const_instance_list_t& inst_list = LLFloaterReg::getFloaterList("web_content"); + lldebugs << "instance list size is " << inst_list.size() << ", incoming uuid is " << uuid << llendl; + for (LLFloaterReg::const_instance_list_t::const_iterator iter = inst_list.begin(); iter != inst_list.end(); ++iter) + { + LLFloaterWebContent* i = dynamic_cast(*iter); + lldebugs << " " << i->mUUID << llendl; + if (i && i->mUUID == uuid) + { + i->closeFloater(false); + return; + } + } +} + +//static +void LLFloaterWebContent::geometryChanged(const std::string &uuid, S32 x, S32 y, S32 width, S32 height) +{ + LLFloaterReg::const_instance_list_t& inst_list = LLFloaterReg::getFloaterList("web_content"); + lldebugs << "instance list size is " << inst_list.size() << ", incoming uuid is " << uuid << llendl; + for (LLFloaterReg::const_instance_list_t::const_iterator iter = inst_list.begin(); iter != inst_list.end(); ++iter) + { + LLFloaterWebContent* i = dynamic_cast(*iter); + lldebugs << " " << i->mUUID << llendl; + if (i && i->mUUID == uuid) + { + i->geometryChanged(x, y, width, height); + return; + } + } +} + +void LLFloaterWebContent::geometryChanged(S32 x, S32 y, S32 width, S32 height) +{ + // Make sure the layout of the browser control is updated, so this calculation is correct. + LLLayoutStack::updateClass(); + + // TODO: need to adjust size and constrain position to make sure floaters aren't moved outside the window view, etc. + LLCoordWindow window_size; + getWindow()->getSize(&window_size); + + // Adjust width and height for the size of the chrome on the web Browser window. + width += getRect().getWidth() - mWebBrowser->getRect().getWidth(); + height += getRect().getHeight() - mWebBrowser->getRect().getHeight(); + + LLRect geom; + geom.setOriginAndSize(x, window_size.mY - (y + height), width, height); + + lldebugs << "geometry change: " << geom << llendl; + + handleReshape(geom,false); +} + +void LLFloaterWebContent::open_media(const std::string& web_url, const std::string& target) +{ + // Specifying a mime type of text/html here causes the plugin system to skip the MIME type probe and just open a browser plugin. + mWebBrowser->setHomePageUrl(web_url, "text/html"); + mWebBrowser->setTarget(target); + mWebBrowser->navigateTo(web_url, "text/html"); + set_current_url(web_url); +} + +//virtual +void LLFloaterWebContent::onClose(bool app_quitting) +{ + LLViewerMedia::proxyWindowClosed(mUUID); + destroy(); +} + +// virtual +void LLFloaterWebContent::draw() +{ + // this is asychronous so we need to keep checking + getChildView( "back" )->setEnabled( mWebBrowser->canNavigateBack() ); + getChildView( "forward" )->setEnabled( mWebBrowser->canNavigateForward() ); + + LLFloater::draw(); +} + +// virtual +void LLFloaterWebContent::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event) +{ + if(event == MEDIA_EVENT_LOCATION_CHANGED) + { + const std::string url = self->getLocation(); + + if ( url.length() ) + mStatusBarText->setText( url ); + + set_current_url( url ); + } + else if(event == MEDIA_EVENT_NAVIGATE_BEGIN) + { + // flags are sent with this event + getChildView("back")->setEnabled( self->getHistoryBackAvailable() ); + getChildView("forward")->setEnabled( self->getHistoryForwardAvailable() ); + + // toggle visibility of these buttons based on browser state + getChildView("reload")->setVisible( false ); + getChildView("stop")->setVisible( true ); + + // turn "on" progress bar now we're about to start loading + mStatusBarProgress->setVisible( true ); + } + else if(event == MEDIA_EVENT_NAVIGATE_COMPLETE) + { + // flags are sent with this event + getChildView("back")->setEnabled( self->getHistoryBackAvailable() ); + getChildView("forward")->setEnabled( self->getHistoryForwardAvailable() ); + + // toggle visibility of these buttons based on browser state + getChildView("reload")->setVisible( true ); + getChildView("stop")->setVisible( false ); + + // turn "off" progress bar now we're loaded + mStatusBarProgress->setVisible( false ); + + // we populate the status bar with URLs as they change so clear it now we're done + const std::string end_str = ""; + mStatusBarText->setText( end_str ); + + // decide if secure browsing icon should be displayed + std::string prefix = std::string("https://"); + std::string test_prefix = mCurrentURL.substr(0, prefix.length()); + LLStringUtil::toLower(test_prefix); + if(test_prefix == prefix) + { + mSecureLockIcon->setVisible(true); + } + else + { + mSecureLockIcon->setVisible(false); + } + } + else if(event == MEDIA_EVENT_CLOSE_REQUEST) + { + // The browser instance wants its window closed. + closeFloater(); + } + else if(event == MEDIA_EVENT_GEOMETRY_CHANGE) + { + geometryChanged(self->getGeometryX(), self->getGeometryY(), self->getGeometryWidth(), self->getGeometryHeight()); + } + else if(event == MEDIA_EVENT_STATUS_TEXT_CHANGED ) + { + const std::string text = self->getStatusText(); + if ( text.length() ) + mStatusBarText->setText( text ); + } + else if(event == MEDIA_EVENT_PROGRESS_UPDATED ) + { + int percent = (int)self->getProgressPercent(); + mStatusBarProgress->setValue( percent ); + } + else if(event == MEDIA_EVENT_NAME_CHANGED ) + { + std::string page_title = self->getMediaName(); + // simulate browser behavior - title is empty, use the current URL + if ( page_title.length() > 0 ) + setTitle( page_title ); + else + setTitle( mCurrentURL ); + } + else if(event == MEDIA_EVENT_LINK_HOVERED ) + { + const std::string link = self->getHoverLink(); + mStatusBarText->setText( link ); + } +} + +void LLFloaterWebContent::set_current_url(const std::string& url) +{ + mCurrentURL = url; + + // serialize url history into the system URL History manager + LLURLHistory::removeURL("browser", mCurrentURL); + LLURLHistory::addURL("browser", mCurrentURL); + + mAddressCombo->remove( mCurrentURL ); + mAddressCombo->add( mCurrentURL ); + mAddressCombo->selectByValue( mCurrentURL ); +} + +void LLFloaterWebContent::onClickForward() +{ + mWebBrowser->navigateForward(); +} + +void LLFloaterWebContent::onClickBack() +{ + mWebBrowser->navigateBack(); +} + +void LLFloaterWebContent::onClickReload() +{ + + if( mWebBrowser->getMediaPlugin() ) + { + bool ignore_cache = true; + mWebBrowser->getMediaPlugin()->browse_reload( ignore_cache ); + } + else + { + mWebBrowser->navigateTo(mCurrentURL); + } +} + +void LLFloaterWebContent::onClickStop() +{ + if( mWebBrowser->getMediaPlugin() ) + mWebBrowser->getMediaPlugin()->browse_stop(); + + // still should happen when we catch the navigate complete event + // but sometimes (don't know why) that event isn't sent from Qt + // and we getto a point where the stop button stays active. + getChildView("reload")->setVisible( true ); + getChildView("stop")->setVisible( false ); +} + +void LLFloaterWebContent::onEnterAddress() +{ + // make sure there is at least something there. + // (perhaps this test should be for minimum length of a URL) + std::string url = mAddressCombo->getValue().asString(); + if ( url.length() > 0 ) + { + mWebBrowser->navigateTo( url, "text/html"); + }; +} + +void LLFloaterWebContent::onPopExternal() +{ + // make sure there is at least something there. + // (perhaps this test should be for minimum length of a URL) + std::string url = mAddressCombo->getValue().asString(); + if ( url.length() > 0 ) + { + LLWeb::loadURLExternal( url ); + }; +} diff --git a/indra/newview/llfloaterwebcontent.h b/indra/newview/llfloaterwebcontent.h index 001d822ada..ecc7e970d8 100644 --- a/indra/newview/llfloaterwebcontent.h +++ b/indra/newview/llfloaterwebcontent.h @@ -1,82 +1,82 @@ -/** - * @file llfloaterwebcontent.h - * @brief floater for displaying web content - e.g. profiles and search (eventually) - * - * $LicenseInfo:firstyear=2006&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_LLFLOATERWEBCONTENT_H -#define LL_LLFLOATERWEBCONTENT_H - -#include "llfloater.h" -#include "llmediactrl.h" - -class LLMediaCtrl; -class LLComboBox; -class LLTextBox; -class LLProgressBar; -class LLIconCtrl; - -class LLFloaterWebContent : - public LLFloater, - public LLViewerMediaObserver -{ -public: - LOG_CLASS(LLFloaterWebContent); - LLFloaterWebContent(const LLSD& key); - +/** + * @file llfloaterwebcontent.h + * @brief floater for displaying web content - e.g. profiles and search (eventually) + * + * $LicenseInfo:firstyear=2006&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_LLFLOATERWEBCONTENT_H +#define LL_LLFLOATERWEBCONTENT_H + +#include "llfloater.h" +#include "llmediactrl.h" + +class LLMediaCtrl; +class LLComboBox; +class LLTextBox; +class LLProgressBar; +class LLIconCtrl; + +class LLFloaterWebContent : + public LLFloater, + public LLViewerMediaObserver +{ +public: + LOG_CLASS(LLFloaterWebContent); + LLFloaterWebContent(const LLSD& key); + void initializeURLHistory(); - - static void create(const std::string &url, const std::string& target, const std::string& uuid = LLStringUtil::null); - - static void closeRequest(const std::string &uuid); - static void geometryChanged(const std::string &uuid, S32 x, S32 y, S32 width, S32 height); - void geometryChanged(S32 x, S32 y, S32 width, S32 height); - - /* virtual */ BOOL postBuild(); - /* virtual */ void onClose(bool app_quitting); - /* virtual */ void draw(); - - // inherited from LLViewerMediaObserver - /*virtual*/ void handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event); - - void onClickBack(); - void onClickForward(); - void onClickReload(); - void onClickStop(); - void onEnterAddress(); - void onPopExternal(); - -private: - void open_media(const std::string& media_url, const std::string& target); - void set_current_url(const std::string& url); - - LLMediaCtrl* mWebBrowser; - LLComboBox* mAddressCombo; - LLIconCtrl *mSecureLockIcon; - LLTextBox* mStatusBarText; - LLProgressBar* mStatusBarProgress; - std::string mCurrentURL; - std::string mUUID; -}; - -#endif // LL_LLFLOATERWEBCONTENT_H + + static void create(const std::string &url, const std::string& target, const std::string& uuid = LLStringUtil::null); + + static void closeRequest(const std::string &uuid); + static void geometryChanged(const std::string &uuid, S32 x, S32 y, S32 width, S32 height); + void geometryChanged(S32 x, S32 y, S32 width, S32 height); + + /* virtual */ BOOL postBuild(); + /* virtual */ void onClose(bool app_quitting); + /* virtual */ void draw(); + + // inherited from LLViewerMediaObserver + /*virtual*/ void handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event); + + void onClickBack(); + void onClickForward(); + void onClickReload(); + void onClickStop(); + void onEnterAddress(); + void onPopExternal(); + +private: + void open_media(const std::string& media_url, const std::string& target); + void set_current_url(const std::string& url); + + LLMediaCtrl* mWebBrowser; + LLComboBox* mAddressCombo; + LLIconCtrl *mSecureLockIcon; + LLTextBox* mStatusBarText; + LLProgressBar* mStatusBarProgress; + std::string mCurrentURL; + std::string mUUID; +}; + +#endif // LL_LLFLOATERWEBCONTENT_H diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp index ce305dcd89..afd565bb26 100644 --- a/indra/newview/llimview.cpp +++ b/indra/newview/llimview.cpp @@ -280,19 +280,19 @@ LLIMModel::LLIMSession::LLIMSession(const LLUUID& session_id, const std::string& void LLIMModel::LLIMSession::onAdHocNameCache(const LLAvatarName& av_name) { if (av_name.mIsDummy) - { - S32 separator_index = mName.rfind(" "); - std::string name = mName.substr(0, separator_index); - ++separator_index; - std::string conference_word = mName.substr(separator_index, mName.length()); - - // additional check that session name is what we expected - if ("Conference" == conference_word) - { - LLStringUtil::format_map_t args; - args["[AGENT_NAME]"] = name; - LLTrans::findString(mName, "conference-title-incoming", args); - } + { + S32 separator_index = mName.rfind(" "); + std::string name = mName.substr(0, separator_index); + ++separator_index; + std::string conference_word = mName.substr(separator_index, mName.length()); + + // additional check that session name is what we expected + if ("Conference" == conference_word) + { + LLStringUtil::format_map_t args; + args["[AGENT_NAME]"] = name; + LLTrans::findString(mName, "conference-title-incoming", args); + } } else { diff --git a/indra/newview/llimview.h b/indra/newview/llimview.h index e765a8da2f..a15776c207 100644 --- a/indra/newview/llimview.h +++ b/indra/newview/llimview.h @@ -100,7 +100,7 @@ public: void onAvatarNameCache(const LLUUID& avatar_id, const LLAvatarName& av_name); - void onAdHocNameCache(const LLAvatarName& av_name); + void onAdHocNameCache(const LLAvatarName& av_name); //*TODO make private static std::string generateHash(const std::set& sorted_uuids); diff --git a/indra/newview/lllogchat.cpp b/indra/newview/lllogchat.cpp index 0121bbb1ed..9adf374c71 100644 --- a/indra/newview/lllogchat.cpp +++ b/indra/newview/lllogchat.cpp @@ -89,15 +89,15 @@ const static boost::regex TIMESTAMP_AND_STUFF("^(\\[\\d{4}/\\d{1,2}/\\d{1,2}\\s+ */ const static boost::regex NAME_AND_TEXT("([^:]+[:]{1})?(\\s*)(.*)"); -/** - * These are recognizers for matching the names of ad-hoc conferences when generating the log file name - * On invited side, an ad-hoc is named like " Conference 2010/11/19 03:43 f0f4" - * On initiating side, an ad-hoc is named like Ad-hoc Conference hash" - * If the naming system for ad-hoc conferences are change in LLIMModel::LLIMSession::buildHistoryFileName() - * then these definition need to be adjusted as well. - */ -const static boost::regex INBOUND_CONFERENCE("^[a-zA-Z]{1,31} [a-zA-Z]{1,31} Conference [0-9]{4}/[0-9]{2}/[0-9]{2} [0-9]{2}:[0-9]{2} [0-9a-f]{4}"); -const static boost::regex OUTBOUND_CONFERENCE("^Ad-hoc Conference hash[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}"); +/** + * These are recognizers for matching the names of ad-hoc conferences when generating the log file name + * On invited side, an ad-hoc is named like " Conference 2010/11/19 03:43 f0f4" + * On initiating side, an ad-hoc is named like Ad-hoc Conference hash" + * If the naming system for ad-hoc conferences are change in LLIMModel::LLIMSession::buildHistoryFileName() + * then these definition need to be adjusted as well. + */ +const static boost::regex INBOUND_CONFERENCE("^[a-zA-Z]{1,31} [a-zA-Z]{1,31} Conference [0-9]{4}/[0-9]{2}/[0-9]{2} [0-9]{2}:[0-9]{2} [0-9a-f]{4}"); +const static boost::regex OUTBOUND_CONFERENCE("^Ad-hoc Conference hash[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}"); //is used to parse complex object names like "Xstreet SL Terminal v2.2.5 st" const static std::string NAME_TEXT_DIVIDER(": "); diff --git a/indra/newview/tests/llremoteparcelrequest_test.cpp b/indra/newview/tests/llremoteparcelrequest_test.cpp index a6c1f69c82..dae22521bb 100644 --- a/indra/newview/tests/llremoteparcelrequest_test.cpp +++ b/indra/newview/tests/llremoteparcelrequest_test.cpp @@ -1,134 +1,134 @@ -/** - * @file llremoteparcelrequest_test.cpp - * @author Brad Kittenbrink - * - * $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 "linden_common.h" - -#include "../test/lltut.h" - -#include "../llremoteparcelrequest.h" - -#include "../llagent.h" -#include "message.h" - -namespace { - LLControlGroup s_saved_settings("dummy_settings"); - const LLUUID TEST_PARCEL_ID("11111111-1111-1111-1111-111111111111"); -} - -LLCurl::Responder::Responder() { } -LLCurl::Responder::~Responder() { } -void LLCurl::Responder::error(U32,std::string const &) { } -void LLCurl::Responder::result(LLSD const &) { } -void LLCurl::Responder::errorWithContent(U32 status,std::string const &,LLSD const &) { } -void LLCurl::Responder::completedRaw(U32 status, std::string const &, LLChannelDescriptors const &,boost::shared_ptr const &) { } -void LLCurl::Responder::completed(U32 status, std::string const &, LLSD const &) { } -void LLCurl::Responder::completedHeader(U32 status, std::string const &, LLSD const &) { } -void LLMessageSystem::getF32(char const *,char const *,F32 &,S32) { } -void LLMessageSystem::getU8(char const *,char const *,U8 &,S32) { } -void LLMessageSystem::getS32(char const *,char const *,S32 &,S32) { } -void LLMessageSystem::getString(char const *,char const *, std::string &,S32) { } -void LLMessageSystem::getUUID(char const *,char const *, LLUUID & out_id,S32) -{ - out_id = TEST_PARCEL_ID; -} -void LLMessageSystem::nextBlock(char const *) { } -void LLMessageSystem::addUUID(char const *,LLUUID const &) { } -void LLMessageSystem::addUUIDFast(char const *,LLUUID const &) { } -void LLMessageSystem::nextBlockFast(char const *) { } -void LLMessageSystem::newMessage(char const *) { } -LLMessageSystem * gMessageSystem; -char * _PREHASH_AgentID; -char * _PREHASH_AgentData; -LLAgent gAgent; -LLAgent::LLAgent() : mAgentAccess(s_saved_settings) { } -LLAgent::~LLAgent() { } -void LLAgent::sendReliableMessage(void) { } -LLUUID gAgentSessionID; -LLUUID gAgentID; -LLUIColor::LLUIColor(void) { } -LLAgentAccess::LLAgentAccess(LLControlGroup & settings) : mSavedSettings(settings) { } -LLControlGroup::LLControlGroup(std::string const & name) : LLInstanceTracker(name) { } -LLControlGroup::~LLControlGroup(void) { } - -namespace tut -{ - struct TestObserver : public LLRemoteParcelInfoObserver { - TestObserver() : mProcessed(false) { } - - virtual void processParcelInfo(const LLParcelData& parcel_data) - { - mProcessed = true; - } - - virtual void setParcelID(const LLUUID& parcel_id) { } - - virtual void setErrorStatus(U32 status, const std::string& reason) { } - - bool mProcessed; - }; - - struct RemoteParcelRequestData - { - RemoteParcelRequestData() - { - } - }; - - typedef test_group remoteparcelrequest_t; - typedef remoteparcelrequest_t::object remoteparcelrequest_object_t; - tut::remoteparcelrequest_t tut_remoteparcelrequest("LLRemoteParcelRequest"); - - template<> template<> - void remoteparcelrequest_object_t::test<1>() - { - set_test_name("observer pointer"); - - boost::scoped_ptr observer(new TestObserver()); - - LLRemoteParcelInfoProcessor & processor = LLRemoteParcelInfoProcessor::instance(); - processor.addObserver(LLUUID(TEST_PARCEL_ID), observer.get()); - - processor.processParcelInfoReply(gMessageSystem, NULL); - - ensure(observer->mProcessed); - } - - template<> template<> - void remoteparcelrequest_object_t::test<2>() - { - set_test_name("CHOP-220: dangling observer pointer"); - - LLRemoteParcelInfoObserver * observer = new TestObserver(); - - LLRemoteParcelInfoProcessor & processor = LLRemoteParcelInfoProcessor::instance(); - processor.addObserver(LLUUID(TEST_PARCEL_ID), observer); - - delete observer; - observer = NULL; - - processor.processParcelInfoReply(gMessageSystem, NULL); - } -} +/** + * @file llremoteparcelrequest_test.cpp + * @author Brad Kittenbrink + * + * $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 "linden_common.h" + +#include "../test/lltut.h" + +#include "../llremoteparcelrequest.h" + +#include "../llagent.h" +#include "message.h" + +namespace { + LLControlGroup s_saved_settings("dummy_settings"); + const LLUUID TEST_PARCEL_ID("11111111-1111-1111-1111-111111111111"); +} + +LLCurl::Responder::Responder() { } +LLCurl::Responder::~Responder() { } +void LLCurl::Responder::error(U32,std::string const &) { } +void LLCurl::Responder::result(LLSD const &) { } +void LLCurl::Responder::errorWithContent(U32 status,std::string const &,LLSD const &) { } +void LLCurl::Responder::completedRaw(U32 status, std::string const &, LLChannelDescriptors const &,boost::shared_ptr const &) { } +void LLCurl::Responder::completed(U32 status, std::string const &, LLSD const &) { } +void LLCurl::Responder::completedHeader(U32 status, std::string const &, LLSD const &) { } +void LLMessageSystem::getF32(char const *,char const *,F32 &,S32) { } +void LLMessageSystem::getU8(char const *,char const *,U8 &,S32) { } +void LLMessageSystem::getS32(char const *,char const *,S32 &,S32) { } +void LLMessageSystem::getString(char const *,char const *, std::string &,S32) { } +void LLMessageSystem::getUUID(char const *,char const *, LLUUID & out_id,S32) +{ + out_id = TEST_PARCEL_ID; +} +void LLMessageSystem::nextBlock(char const *) { } +void LLMessageSystem::addUUID(char const *,LLUUID const &) { } +void LLMessageSystem::addUUIDFast(char const *,LLUUID const &) { } +void LLMessageSystem::nextBlockFast(char const *) { } +void LLMessageSystem::newMessage(char const *) { } +LLMessageSystem * gMessageSystem; +char * _PREHASH_AgentID; +char * _PREHASH_AgentData; +LLAgent gAgent; +LLAgent::LLAgent() : mAgentAccess(s_saved_settings) { } +LLAgent::~LLAgent() { } +void LLAgent::sendReliableMessage(void) { } +LLUUID gAgentSessionID; +LLUUID gAgentID; +LLUIColor::LLUIColor(void) { } +LLAgentAccess::LLAgentAccess(LLControlGroup & settings) : mSavedSettings(settings) { } +LLControlGroup::LLControlGroup(std::string const & name) : LLInstanceTracker(name) { } +LLControlGroup::~LLControlGroup(void) { } + +namespace tut +{ + struct TestObserver : public LLRemoteParcelInfoObserver { + TestObserver() : mProcessed(false) { } + + virtual void processParcelInfo(const LLParcelData& parcel_data) + { + mProcessed = true; + } + + virtual void setParcelID(const LLUUID& parcel_id) { } + + virtual void setErrorStatus(U32 status, const std::string& reason) { } + + bool mProcessed; + }; + + struct RemoteParcelRequestData + { + RemoteParcelRequestData() + { + } + }; + + typedef test_group remoteparcelrequest_t; + typedef remoteparcelrequest_t::object remoteparcelrequest_object_t; + tut::remoteparcelrequest_t tut_remoteparcelrequest("LLRemoteParcelRequest"); + + template<> template<> + void remoteparcelrequest_object_t::test<1>() + { + set_test_name("observer pointer"); + + boost::scoped_ptr observer(new TestObserver()); + + LLRemoteParcelInfoProcessor & processor = LLRemoteParcelInfoProcessor::instance(); + processor.addObserver(LLUUID(TEST_PARCEL_ID), observer.get()); + + processor.processParcelInfoReply(gMessageSystem, NULL); + + ensure(observer->mProcessed); + } + + template<> template<> + void remoteparcelrequest_object_t::test<2>() + { + set_test_name("CHOP-220: dangling observer pointer"); + + LLRemoteParcelInfoObserver * observer = new TestObserver(); + + LLRemoteParcelInfoProcessor & processor = LLRemoteParcelInfoProcessor::instance(); + processor.addObserver(LLUUID(TEST_PARCEL_ID), observer); + + delete observer; + observer = NULL; + + processor.processParcelInfoReply(gMessageSystem, NULL); + } +} diff --git a/indra/viewer_components/updater/tests/llupdaterservice_test.cpp b/indra/viewer_components/updater/tests/llupdaterservice_test.cpp index 5f8cd28f29..88ab5a2284 100644 --- a/indra/viewer_components/updater/tests/llupdaterservice_test.cpp +++ b/indra/viewer_components/updater/tests/llupdaterservice_test.cpp @@ -1,200 +1,200 @@ -/** - * @file llupdaterservice_test.cpp - * @brief Tests of llupdaterservice.cpp. - * - * $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$ - */ - -// Precompiled header -#include "linden_common.h" -// associated header -#include "../llupdaterservice.h" -#include "../llupdatechecker.h" -#include "../llupdatedownloader.h" -#include "../llupdateinstaller.h" - -#include "../../../test/lltut.h" -//#define DEBUG_ON -#include "../../../test/debug.h" - -#include "llevents.h" -#include "lldir.h" - -/***************************************************************************** -* MOCK'd -*****************************************************************************/ -LLUpdateChecker::LLUpdateChecker(LLUpdateChecker::Client & client) -{} -void LLUpdateChecker::check(std::string const & protocolVersion, std::string const & hostUrl, - std::string const & servicePath, std::string channel, std::string version) -{} -LLUpdateDownloader::LLUpdateDownloader(Client & ) {} -void LLUpdateDownloader::download(LLURI const & , std::string const &, std::string const &, bool){} - -class LLDir_Mock : public LLDir -{ - void initAppDirs(const std::string &app_name, - const std::string& app_read_only_data_dir = "") {} - U32 countFilesInDir(const std::string &dirname, const std::string &mask) - { - return 0; - } - - BOOL getNextFileInDir(const std::string &dirname, - const std::string &mask, - std::string &fname) - { - return false; - } - void getRandomFileInDir(const std::string &dirname, - const std::string &mask, - std::string &fname) {} - std::string getCurPath() { return ""; } - BOOL fileExists(const std::string &filename) const { return false; } - std::string getLLPluginLauncher() { return ""; } - std::string getLLPluginFilename(std::string base_name) { return ""; } - -} gDirUtil; -LLDir* gDirUtilp = &gDirUtil; -LLDir::LLDir() {} -LLDir::~LLDir() {} -S32 LLDir::deleteFilesInDir(const std::string &dirname, - const std::string &mask) -{ return 0; } - -void LLDir::setChatLogsDir(const std::string &path){} -void LLDir::setPerAccountChatLogsDir(const std::string &username){} -void LLDir::setLindenUserDir(const std::string &username){} -void LLDir::setSkinFolder(const std::string &skin_folder){} -bool LLDir::setCacheDir(const std::string &path){ return true; } -void LLDir::dumpCurrentDirectories() {} - -std::string LLDir::getExpandedFilename(ELLPath location, - const std::string &filename) const -{ - return ""; -} - -std::string LLUpdateDownloader::downloadMarkerPath(void) -{ - return ""; -} - -void LLUpdateDownloader::resume(void) {} -void LLUpdateDownloader::cancel(void) {} -void LLUpdateDownloader::setBandwidthLimit(U64 bytesPerSecond) {} - -int ll_install_update(std::string const &, std::string const &, bool, LLInstallScriptMode) -{ - return 0; -} - -std::string const & ll_install_failed_marker_path() -{ - static std::string wubba; - return wubba; -} - -/* -#pragma warning(disable: 4273) -llus_mock_llifstream::llus_mock_llifstream(const std::string& _Filename, - ios_base::openmode _Mode, - int _Prot) : - std::basic_istream >(NULL,true) -{} - -llus_mock_llifstream::~llus_mock_llifstream() {} -bool llus_mock_llifstream::is_open() const {return true;} -void llus_mock_llifstream::close() {} -*/ - -/***************************************************************************** -* TUT -*****************************************************************************/ -namespace tut -{ - struct llupdaterservice_data - { - llupdaterservice_data() : - pumps(LLEventPumps::instance()), - test_url("dummy_url"), - test_channel("dummy_channel"), - test_version("dummy_version") - {} - LLEventPumps& pumps; - std::string test_url; - std::string test_channel; - std::string test_version; - }; - - typedef test_group llupdaterservice_group; - typedef llupdaterservice_group::object llupdaterservice_object; - llupdaterservice_group llupdaterservicegrp("LLUpdaterService"); - - template<> template<> - void llupdaterservice_object::test<1>() - { - DEBUG; - LLUpdaterService updater; - bool got_usage_error = false; - try - { - updater.startChecking(); - } - catch(LLUpdaterService::UsageError) - { - got_usage_error = true; - } - ensure("Caught start before params", got_usage_error); - } - - template<> template<> - void llupdaterservice_object::test<2>() - { - DEBUG; - LLUpdaterService updater; - bool got_usage_error = false; - try - { - updater.initialize("1.0",test_url, "update" ,test_channel, test_version); - updater.startChecking(); - updater.initialize("1.0", "other_url", "update", test_channel, test_version); - } - catch(LLUpdaterService::UsageError) - { - got_usage_error = true; - } - ensure("Caught params while running", got_usage_error); - } - - template<> template<> - void llupdaterservice_object::test<3>() - { - DEBUG; - LLUpdaterService updater; - updater.initialize("1.0", test_url, "update", test_channel, test_version); - updater.startChecking(); - ensure(updater.isChecking()); - updater.stopChecking(); - ensure(!updater.isChecking()); - } -} +/** + * @file llupdaterservice_test.cpp + * @brief Tests of llupdaterservice.cpp. + * + * $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$ + */ + +// Precompiled header +#include "linden_common.h" +// associated header +#include "../llupdaterservice.h" +#include "../llupdatechecker.h" +#include "../llupdatedownloader.h" +#include "../llupdateinstaller.h" + +#include "../../../test/lltut.h" +//#define DEBUG_ON +#include "../../../test/debug.h" + +#include "llevents.h" +#include "lldir.h" + +/***************************************************************************** +* MOCK'd +*****************************************************************************/ +LLUpdateChecker::LLUpdateChecker(LLUpdateChecker::Client & client) +{} +void LLUpdateChecker::check(std::string const & protocolVersion, std::string const & hostUrl, + std::string const & servicePath, std::string channel, std::string version) +{} +LLUpdateDownloader::LLUpdateDownloader(Client & ) {} +void LLUpdateDownloader::download(LLURI const & , std::string const &, std::string const &, bool){} + +class LLDir_Mock : public LLDir +{ + void initAppDirs(const std::string &app_name, + const std::string& app_read_only_data_dir = "") {} + U32 countFilesInDir(const std::string &dirname, const std::string &mask) + { + return 0; + } + + BOOL getNextFileInDir(const std::string &dirname, + const std::string &mask, + std::string &fname) + { + return false; + } + void getRandomFileInDir(const std::string &dirname, + const std::string &mask, + std::string &fname) {} + std::string getCurPath() { return ""; } + BOOL fileExists(const std::string &filename) const { return false; } + std::string getLLPluginLauncher() { return ""; } + std::string getLLPluginFilename(std::string base_name) { return ""; } + +} gDirUtil; +LLDir* gDirUtilp = &gDirUtil; +LLDir::LLDir() {} +LLDir::~LLDir() {} +S32 LLDir::deleteFilesInDir(const std::string &dirname, + const std::string &mask) +{ return 0; } + +void LLDir::setChatLogsDir(const std::string &path){} +void LLDir::setPerAccountChatLogsDir(const std::string &username){} +void LLDir::setLindenUserDir(const std::string &username){} +void LLDir::setSkinFolder(const std::string &skin_folder){} +bool LLDir::setCacheDir(const std::string &path){ return true; } +void LLDir::dumpCurrentDirectories() {} + +std::string LLDir::getExpandedFilename(ELLPath location, + const std::string &filename) const +{ + return ""; +} + +std::string LLUpdateDownloader::downloadMarkerPath(void) +{ + return ""; +} + +void LLUpdateDownloader::resume(void) {} +void LLUpdateDownloader::cancel(void) {} +void LLUpdateDownloader::setBandwidthLimit(U64 bytesPerSecond) {} + +int ll_install_update(std::string const &, std::string const &, bool, LLInstallScriptMode) +{ + return 0; +} + +std::string const & ll_install_failed_marker_path() +{ + static std::string wubba; + return wubba; +} + +/* +#pragma warning(disable: 4273) +llus_mock_llifstream::llus_mock_llifstream(const std::string& _Filename, + ios_base::openmode _Mode, + int _Prot) : + std::basic_istream >(NULL,true) +{} + +llus_mock_llifstream::~llus_mock_llifstream() {} +bool llus_mock_llifstream::is_open() const {return true;} +void llus_mock_llifstream::close() {} +*/ + +/***************************************************************************** +* TUT +*****************************************************************************/ +namespace tut +{ + struct llupdaterservice_data + { + llupdaterservice_data() : + pumps(LLEventPumps::instance()), + test_url("dummy_url"), + test_channel("dummy_channel"), + test_version("dummy_version") + {} + LLEventPumps& pumps; + std::string test_url; + std::string test_channel; + std::string test_version; + }; + + typedef test_group llupdaterservice_group; + typedef llupdaterservice_group::object llupdaterservice_object; + llupdaterservice_group llupdaterservicegrp("LLUpdaterService"); + + template<> template<> + void llupdaterservice_object::test<1>() + { + DEBUG; + LLUpdaterService updater; + bool got_usage_error = false; + try + { + updater.startChecking(); + } + catch(LLUpdaterService::UsageError) + { + got_usage_error = true; + } + ensure("Caught start before params", got_usage_error); + } + + template<> template<> + void llupdaterservice_object::test<2>() + { + DEBUG; + LLUpdaterService updater; + bool got_usage_error = false; + try + { + updater.initialize("1.0",test_url, "update" ,test_channel, test_version); + updater.startChecking(); + updater.initialize("1.0", "other_url", "update", test_channel, test_version); + } + catch(LLUpdaterService::UsageError) + { + got_usage_error = true; + } + ensure("Caught params while running", got_usage_error); + } + + template<> template<> + void llupdaterservice_object::test<3>() + { + DEBUG; + LLUpdaterService updater; + updater.initialize("1.0", test_url, "update", test_channel, test_version); + updater.startChecking(); + ensure(updater.isChecking()); + updater.stopChecking(); + ensure(!updater.isChecking()); + } +} -- cgit v1.2.3 From b48c003d60ad1358ade39bd321bb901afda24ee6 Mon Sep 17 00:00:00 2001 From: Seth ProductEngine Date: Thu, 6 Jan 2011 22:19:27 +0200 Subject: STORM-387 FIXED Return key handling by Favorites bar overflow menu. Pressing Return in Favorites bar overflow menu now acts as mouse double click, i.e. performs teleport to selected landmark. --- indra/llui/llmenugl.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp index 6c0d47ef63..32d7be377a 100644 --- a/indra/llui/llmenugl.cpp +++ b/indra/llui/llmenugl.cpp @@ -1637,6 +1637,10 @@ LLMenuScrollItem::LLMenuScrollItem(const Params& p) } LLButton::Params bparams; + + // Disabled the Return key handling by LLMenuScrollItem instead of + // passing the key press to the currently selected menu item. See STORM-385. + bparams.commit_on_return(false); bparams.mouse_opaque(true); bparams.scale_image(false); bparams.click_callback(p.scroll_callback); -- cgit v1.2.3 From c53ce73469a1cbb25e72511a8a2e23b7bfe4dfb8 Mon Sep 17 00:00:00 2001 From: Jonathan Yap Date: Thu, 6 Jan 2011 16:53:31 -0500 Subject: STORM-830 Volume slider isn't properly remembered if set to zero There is an edge case in setMasterGain during startup which prevents setInternalGain from being called if the master volume setting and mInternalGain both equal 0. In llaudioengine.cpp setting mInternalGain to a very low but non-zero value fixes this issue. --- indra/llaudio/llaudioengine.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/indra/llaudio/llaudioengine.cpp b/indra/llaudio/llaudioengine.cpp index c9cb1cd6e7..8baba79f59 100644 --- a/indra/llaudio/llaudioengine.cpp +++ b/indra/llaudio/llaudioengine.cpp @@ -97,7 +97,10 @@ void LLAudioEngine::setDefaults() } mMasterGain = 1.f; - mInternalGain = 0.f; + // Setting mInternalGain to a very low but non-zero value fixes the issue reported in STORM-830. + // There is an edge case in setMasterGain during startup which prevents setInternalGain from + // being called if the master volume setting and mInternalGain both equal 0. + mInternalGain = 0.0000000001f; mNextWindUpdate = 0.f; mStreamingAudioImpl = NULL; -- cgit v1.2.3 From 346082965ac922a90f7c24bd97be807906b6a35f Mon Sep 17 00:00:00 2001 From: Oz Linden Date: Fri, 7 Jan 2011 11:26:16 -0500 Subject: STORM-826: fix line endings and mixed tabs/spaces --- .../skins/default/xui/en/floater_web_content.xml | 380 ++++++++++----------- 1 file changed, 190 insertions(+), 190 deletions(-) diff --git a/indra/newview/skins/default/xui/en/floater_web_content.xml b/indra/newview/skins/default/xui/en/floater_web_content.xml index 2ad46824c2..d90d0feda9 100644 --- a/indra/newview/skins/default/xui/en/floater_web_content.xml +++ b/indra/newview/skins/default/xui/en/floater_web_content.xml @@ -1,190 +1,190 @@ - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + -- cgit v1.2.3 From c132d20a7433e2d09e3521a15497f661fcbd18b8 Mon Sep 17 00:00:00 2001 From: Oz Linden Date: Fri, 7 Jan 2011 12:46:55 -0500 Subject: increment minor revision number to make version "2.6.0" --- indra/llcommon/llversionviewer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/llcommon/llversionviewer.h b/indra/llcommon/llversionviewer.h index 356e0f4c0f..7d5afe92dc 100644 --- a/indra/llcommon/llversionviewer.h +++ b/indra/llcommon/llversionviewer.h @@ -28,7 +28,7 @@ #define LL_LLVERSIONVIEWER_H const S32 LL_VERSION_MAJOR = 2; -const S32 LL_VERSION_MINOR = 5; +const S32 LL_VERSION_MINOR = 6; const S32 LL_VERSION_PATCH = 0; const S32 LL_VERSION_BUILD = 0; -- cgit v1.2.3 From 40cd5370541638c509111b90dd35e52b87d3e497 Mon Sep 17 00:00:00 2001 From: Aaron Stone Date: Fri, 7 Jan 2011 18:30:03 +0000 Subject: Switch inventory capabilities to FetchInventory2 and family. --- etc/message.xml | 17 +++++++---------- indra/newview/llinventorymodelbackgroundfetch.cpp | 4 ++-- indra/newview/llinventoryobserver.cpp | 4 ++-- indra/newview/llviewerinventory.cpp | 8 ++++---- indra/newview/llviewerregion.cpp | 8 ++++---- 5 files changed, 19 insertions(+), 22 deletions(-) diff --git a/etc/message.xml b/etc/message.xml index 7c4a927cc5..764aea3879 100644 --- a/etc/message.xml +++ b/etc/message.xml @@ -678,20 +678,17 @@ EstateChangeInfo true - FetchInventoryDescendents + FetchInventoryDescendents2 false - WebFetchInventoryDescendents - true - - FetchInventory - true + FetchInventory2 + false - FetchLibDescendents - true + FetchLibDescendents2 + false - FetchLib - true + FetchLib2 + false UploadBakedTexture true diff --git a/indra/newview/llinventorymodelbackgroundfetch.cpp b/indra/newview/llinventorymodelbackgroundfetch.cpp index eab8f187a7..570e48d526 100644 --- a/indra/newview/llinventorymodelbackgroundfetch.cpp +++ b/indra/newview/llinventorymodelbackgroundfetch.cpp @@ -181,7 +181,7 @@ void LLInventoryModelBackgroundFetch::backgroundFetch() if (mBackgroundFetchActive && gAgent.getRegion()) { // If we'll be using the capability, we'll be sending batches and the background thing isn't as important. - std::string url = gAgent.getRegion()->getCapability("WebFetchInventoryDescendents"); + std::string url = gAgent.getRegion()->getCapability("FetchInventoryDescendents2"); if (!url.empty()) { bulkFetch(url); @@ -604,7 +604,7 @@ void LLInventoryModelBackgroundFetch::bulkFetch(std::string url) } if (body_lib["folders"].size()) { - std::string url_lib = gAgent.getRegion()->getCapability("FetchLibDescendents"); + std::string url_lib = gAgent.getRegion()->getCapability("FetchLibDescendents2"); LLInventoryModelFetchDescendentsResponder *fetcher = new LLInventoryModelFetchDescendentsResponder(body_lib, recursive_cats); LLHTTPClient::post(url_lib, body_lib, fetcher, 300.0); diff --git a/indra/newview/llinventoryobserver.cpp b/indra/newview/llinventoryobserver.cpp index 91ff8c7867..0fd4b2bee5 100644 --- a/indra/newview/llinventoryobserver.cpp +++ b/indra/newview/llinventoryobserver.cpp @@ -203,8 +203,8 @@ void fetch_items_from_llsd(const LLSD& items_llsd) { if (!items_llsd.size() || gDisconnected) return; LLSD body; - body[0]["cap_name"] = "FetchInventory"; - body[1]["cap_name"] = "FetchLib"; + body[0]["cap_name"] = "FetchInventory2"; + body[1]["cap_name"] = "FetchLib2"; for (S32 i=0; igetCapability("FetchLib"); + url = region->getCapability("FetchLib2"); } else { - url = region->getCapability("FetchInventory"); + url = region->getCapability("FetchInventory2"); } } else @@ -648,7 +648,7 @@ bool LLViewerInventoryCategory::fetch() std::string url; if (gAgent.getRegion()) { - url = gAgent.getRegion()->getCapability("WebFetchInventoryDescendents"); + url = gAgent.getRegion()->getCapability("FetchInventoryDescendents2"); } else { @@ -660,7 +660,7 @@ bool LLViewerInventoryCategory::fetch() } else { //Deprecated, but if we don't have a capability, use the old system. - llinfos << "WebFetchInventoryDescendents capability not found. Using deprecated UDP message." << llendl; + llinfos << "FetchInventoryDescendents2 capability not found. Using deprecated UDP message." << llendl; LLMessageSystem* msg = gMessageSystem; msg->newMessage("FetchInventoryDescendents"); msg->nextBlock("AgentData"); diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index 3b2cfe656f..c7649001c5 100644 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -1379,11 +1379,12 @@ void LLViewerRegion::setSeedCapability(const std::string& url) capabilityNames.append("DispatchRegionInfo"); capabilityNames.append("EstateChangeInfo"); capabilityNames.append("EventQueueGet"); - capabilityNames.append("FetchInventory"); capabilityNames.append("ObjectMedia"); capabilityNames.append("ObjectMediaNavigate"); - capabilityNames.append("FetchLib"); - capabilityNames.append("FetchLibDescendents"); + capabilityNames.append("FetchLib2"); + capabilityNames.append("FetchLibDescendents2"); + capabilityNames.append("FetchInventory2"); + capabilityNames.append("FetchInventoryDescendents2"); capabilityNames.append("GetDisplayNames"); capabilityNames.append("GetTexture"); capabilityNames.append("GroupProposalBallot"); @@ -1423,7 +1424,6 @@ void LLViewerRegion::setSeedCapability(const std::string& url) capabilityNames.append("ViewerMetrics"); capabilityNames.append("ViewerStartAuction"); capabilityNames.append("ViewerStats"); - capabilityNames.append("WebFetchInventoryDescendents"); // Please add new capabilities alphabetically to reduce // merge conflicts. -- cgit v1.2.3 From a9bc51e6416dd637080c0307de99d5e09d06dcc4 Mon Sep 17 00:00:00 2001 From: Don Kjer Date: Fri, 7 Jan 2011 10:46:41 -0800 Subject: Fix for ER-425: Viewer object cache list gets corrupted when CacheNumberOfRegionsForObjects is exceeded --- indra/newview/llvocache.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/indra/newview/llvocache.cpp b/indra/newview/llvocache.cpp index d372fd0212..22199be82d 100644 --- a/indra/newview/llvocache.cpp +++ b/indra/newview/llvocache.cpp @@ -425,7 +425,7 @@ void LLVOCache::readCacheHeader() if (LLAPRFile::isExist(mHeaderFileName, mLocalAPRFilePoolp)) { - LLAPRFile* apr_file = new LLAPRFile(mHeaderFileName, APR_READ|APR_BINARY, mLocalAPRFilePoolp); + LLAPRFile* apr_file = new LLAPRFile(mHeaderFileName, APR_FOPEN_READ|APR_FOPEN_BINARY, mLocalAPRFilePoolp); //read the meta element if(!checkRead(apr_file, &mMetaInfo, sizeof(HeaderMetaInfo))) @@ -477,7 +477,7 @@ void LLVOCache::writeCacheHeader() return; } - LLAPRFile* apr_file = new LLAPRFile(mHeaderFileName, APR_CREATE|APR_WRITE|APR_BINARY, mLocalAPRFilePoolp); + LLAPRFile* apr_file = new LLAPRFile(mHeaderFileName, APR_FOPEN_CREATE|APR_FOPEN_WRITE|APR_FOPEN_BINARY|APR_FOPEN_TRUNCATE, mLocalAPRFilePoolp); //write the meta element if(!checkWrite(apr_file, &mMetaInfo, sizeof(HeaderMetaInfo))) @@ -525,7 +525,7 @@ void LLVOCache::writeCacheHeader() BOOL LLVOCache::updateEntry(const HeaderEntryInfo* entry) { - LLAPRFile* apr_file = new LLAPRFile(mHeaderFileName, APR_WRITE|APR_BINARY, mLocalAPRFilePoolp); + LLAPRFile* apr_file = new LLAPRFile(mHeaderFileName, APR_FOPEN_WRITE|APR_FOPEN_BINARY, mLocalAPRFilePoolp); apr_file->seek(APR_SET, entry->mIndex * sizeof(HeaderEntryInfo) + sizeof(HeaderMetaInfo)) ; BOOL result = checkWrite(apr_file, (void*)entry, sizeof(HeaderEntryInfo)) ; @@ -551,7 +551,7 @@ void LLVOCache::readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::voca std::string filename; getObjectCacheFilename(handle, filename); - LLAPRFile* apr_file = new LLAPRFile(filename, APR_READ|APR_BINARY, mLocalAPRFilePoolp); + LLAPRFile* apr_file = new LLAPRFile(filename, APR_FOPEN_READ|APR_FOPEN_BINARY, mLocalAPRFilePoolp); LLUUID cache_id ; if(!checkRead(apr_file, cache_id.mData, UUID_BYTES)) @@ -636,14 +636,16 @@ void LLVOCache::writeToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry: return ; } + U32 num_handle_entries = mHandleEntryMap.size(); + HeaderEntryInfo* entry; handle_entry_map_t::iterator iter = mHandleEntryMap.find(handle) ; - U32 num_handle_entries = mHandleEntryMap.size(); if(iter == mHandleEntryMap.end()) //new entry { if(num_handle_entries >= mCacheSize) { purgeEntries() ; + num_handle_entries = mHandleEntryMap.size(); } entry = new HeaderEntryInfo(); @@ -675,7 +677,7 @@ void LLVOCache::writeToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry: //write to cache file std::string filename; getObjectCacheFilename(handle, filename); - LLAPRFile* apr_file = new LLAPRFile(filename, APR_CREATE|APR_WRITE|APR_BINARY, mLocalAPRFilePoolp); + LLAPRFile* apr_file = new LLAPRFile(filename, APR_FOPEN_CREATE|APR_FOPEN_WRITE|APR_FOPEN_BINARY|APR_FOPEN_TRUNCATE, mLocalAPRFilePoolp); if(!checkWrite(apr_file, (void*)id.mData, UUID_BYTES)) { -- cgit v1.2.3 From 8cfea0bab14afc29887de4b61350e6268b793622 Mon Sep 17 00:00:00 2001 From: Coaldust Numbers Date: Fri, 7 Jan 2011 15:08:42 -0500 Subject: VWR-1095 fix for problems with uploads following bulk upload failure de minimus contribution accepted without CA - Oz Linden --- doc/contributions.txt | 2 ++ indra/newview/llassetuploadresponders.cpp | 1 + 2 files changed, 3 insertions(+) diff --git a/doc/contributions.txt b/doc/contributions.txt index 3b14ce5125..9266ae3c5b 100644 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -219,6 +219,8 @@ Catherine Pfeffer Celierra Darling VWR-1274 VWR-6975 +Coaldust Numbers + VWR-1095 Cron Stardust VWR-10579 Cypren Christenson diff --git a/indra/newview/llassetuploadresponders.cpp b/indra/newview/llassetuploadresponders.cpp index f12bc16d4b..dd5bc74b2a 100644 --- a/indra/newview/llassetuploadresponders.cpp +++ b/indra/newview/llassetuploadresponders.cpp @@ -126,6 +126,7 @@ void LLAssetUploadResponder::error(U32 statusNum, const std::string& reason) break; } LLUploadDialog::modalUploadFinished(); + LLFilePicker::instance().reset(); // unlock file picker when bulk upload fails } //virtual -- cgit v1.2.3 From ba1266043f36fd0a576fe888120bbb3f7b7dc2f3 Mon Sep 17 00:00:00 2001 From: Xiaohong Bao Date: Fri, 7 Jan 2011 15:04:36 -0700 Subject: trivial: for VWR-22353: remove debug code for EXT-6791. --- indra/llrender/llimagegl.cpp | 10 ---------- indra/newview/lldynamictexture.cpp | 10 ---------- 2 files changed, 20 deletions(-) diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index 65940cb067..e8e98211f1 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -1063,16 +1063,6 @@ BOOL LLImageGL::setSubImageFromFrameBuffer(S32 fb_x, S32 fb_y, S32 x_pos, S32 y_ { if (gGL.getTexUnit(0)->bind(this, false, true)) { - if(gGLManager.mDebugGPU) - { - llinfos << "Calling glCopyTexSubImage2D(...)" << llendl ; - checkTexSize(true) ; - llcallstacks << fb_x << " : " << fb_y << " : " << x_pos << " : " << y_pos << " : " << width << " : " << height << - " : " << (S32)mComponents << llcallstacksendl ; - - log_glerror() ; - } - glCopyTexSubImage2D(GL_TEXTURE_2D, 0, fb_x, fb_y, x_pos, y_pos, width, height); mGLTextureCreated = true; stop_glerror(); diff --git a/indra/newview/lldynamictexture.cpp b/indra/newview/lldynamictexture.cpp index a3d2941114..f781d5f3ff 100644 --- a/indra/newview/lldynamictexture.cpp +++ b/indra/newview/lldynamictexture.cpp @@ -177,10 +177,6 @@ void LLViewerDynamicTexture::postRender(BOOL success) generateGLTexture() ; } - if(gGLManager.mDebugGPU) - { - LLGLState::dumpStates() ; - } success = mGLTexturep->setSubImageFromFrameBuffer(0, 0, mOrigin.mX, mOrigin.mY, mFullWidth, mFullHeight); } } @@ -220,12 +216,6 @@ BOOL LLViewerDynamicTexture::updateAllInstances() LLViewerDynamicTexture *dynamicTexture = *iter; if (dynamicTexture->needsRender()) { - if(gGLManager.mDebugGPU) - { - llinfos << "class type: " << (S32)dynamicTexture->getType() << llendl; - LLGLState::dumpStates() ; - } - glClear(GL_DEPTH_BUFFER_BIT); gDepthDirty = TRUE; -- cgit v1.2.3 From d8b4363c1d3f60741422419b386b79df23a6da6a Mon Sep 17 00:00:00 2001 From: Don Kjer Date: Fri, 7 Jan 2011 14:36:59 -0800 Subject: Fix for viewer crash when making the object viewer cache larger --- indra/newview/llvocache.cpp | 22 +++++++++++++++------- indra/newview/llvocache.h | 4 ++-- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/indra/newview/llvocache.cpp b/indra/newview/llvocache.cpp index 22199be82d..c26008d640 100644 --- a/indra/newview/llvocache.cpp +++ b/indra/newview/llvocache.cpp @@ -307,7 +307,6 @@ void LLVOCache::initCache(ELLPath location, U32 size, U32 cache_version) mCacheSize = size; - mMetaInfo.mVersion = cache_version; readCacheHeader(); mInitialized = TRUE ; @@ -336,6 +335,7 @@ void LLVOCache::removeCache(ELLPath location) std::string delem = gDirUtilp->getDirDelimiter(); std::string mask = delem + "*"; std::string cache_dir = gDirUtilp->getExpandedFilename(location, object_cache_dirname); + llinfos << "Removing cache at " << cache_dir << llendl; gDirUtilp->deleteFilesInDir(cache_dir, mask); //delete all files LLFile::rmdir(cache_dir); @@ -354,6 +354,7 @@ void LLVOCache::removeCache() std::string delem = gDirUtilp->getDirDelimiter(); std::string mask = delem + "*"; + llinfos << "Removing cache at " << mObjectCacheDirName << llendl; gDirUtilp->deleteFilesInDir(mObjectCacheDirName, mask); clearCacheInMemory() ; @@ -390,22 +391,28 @@ void LLVOCache::removeFromCache(U64 handle) LLAPRFile::remove(filename, mLocalAPRFilePoolp); } -BOOL LLVOCache::checkRead(LLAPRFile* apr_file, void* src, S32 n_bytes) +BOOL LLVOCache::checkRead(LLAPRFile* apr_file, void* src, S32 n_bytes, bool remove_cache_on_error) { if(!check_read(apr_file, src, n_bytes)) { - removeCache() ; + if (remove_cache_on_error) + { + removeCache() ; + } return FALSE ; } return TRUE ; } -BOOL LLVOCache::checkWrite(LLAPRFile* apr_file, void* src, S32 n_bytes) +BOOL LLVOCache::checkWrite(LLAPRFile* apr_file, void* src, S32 n_bytes, bool remove_cache_on_error) { if(!check_write(apr_file, src, n_bytes)) { - removeCache() ; + if (remove_cache_on_error) + { + removeCache() ; + } return FALSE ; } @@ -428,7 +435,8 @@ void LLVOCache::readCacheHeader() LLAPRFile* apr_file = new LLAPRFile(mHeaderFileName, APR_FOPEN_READ|APR_FOPEN_BINARY, mLocalAPRFilePoolp); //read the meta element - if(!checkRead(apr_file, &mMetaInfo, sizeof(HeaderMetaInfo))) + bool remove_cache_on_error = false; + if(!checkRead(apr_file, &mMetaInfo, sizeof(HeaderMetaInfo), remove_cache_on_error)) { llwarns << "Error reading meta information from cache header." << llendl; delete apr_file; @@ -439,7 +447,7 @@ void LLVOCache::readCacheHeader() for(U32 entry_index = 0; entry_index < mCacheSize; ++entry_index) { entry = new HeaderEntryInfo() ; - if(!checkRead(apr_file, entry, sizeof(HeaderEntryInfo))) + if(!checkRead(apr_file, entry, sizeof(HeaderEntryInfo), remove_cache_on_error)) { llwarns << "Error reading cache header entry. (entry_index=" << entry_index << ")" << llendl; delete entry ; diff --git a/indra/newview/llvocache.h b/indra/newview/llvocache.h index 014112718e..e103007979 100644 --- a/indra/newview/llvocache.h +++ b/indra/newview/llvocache.h @@ -128,8 +128,8 @@ private: void removeCache() ; void purgeEntries(); BOOL updateEntry(const HeaderEntryInfo* entry); - BOOL checkRead(LLAPRFile* apr_file, void* src, S32 n_bytes) ; - BOOL checkWrite(LLAPRFile* apr_file, void* src, S32 n_bytes) ; + BOOL checkRead(LLAPRFile* apr_file, void* src, S32 n_bytes, bool remove_cache_on_error = true) ; + BOOL checkWrite(LLAPRFile* apr_file, void* src, S32 n_bytes, bool remove_cache_on_error = true) ; private: BOOL mEnabled; -- cgit v1.2.3 From db1a63e99eb76527e86b071c84f8473417a02a6b Mon Sep 17 00:00:00 2001 From: Thickbrick Sleaford Date: Sun, 9 Jan 2011 01:13:38 +0200 Subject: FIX VWR-24420 Keep alpha channel in PNG images with background color. Remove code that composites RGBA PNG images that specify a background color down to RGB. --- doc/contributions.txt | 1 + indra/llimage/llpngwrapper.cpp | 18 ++++-------------- indra/llimage/llpngwrapper.h | 3 --- 3 files changed, 5 insertions(+), 17 deletions(-) diff --git a/doc/contributions.txt b/doc/contributions.txt index 3b14ce5125..7f467696de 100644 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -732,6 +732,7 @@ Thickbrick Sleaford VWR-9287 VWR-13483 VWR-13947 + VWR-24420 Thraxis Epsilon SVC-371 VWR-383 diff --git a/indra/llimage/llpngwrapper.cpp b/indra/llimage/llpngwrapper.cpp index fe737e2072..2cc7d3c460 100644 --- a/indra/llimage/llpngwrapper.cpp +++ b/indra/llimage/llpngwrapper.cpp @@ -50,8 +50,6 @@ LLPngWrapper::LLPngWrapper() mCompressionType( 0 ), mFilterMethod( 0 ), mFinalSize( 0 ), - mHasBKGD(false), - mBackgroundColor(), mGamma(0.f) { } @@ -111,9 +109,9 @@ void LLPngWrapper::writeFlush(png_structp png_ptr) } // Read the PNG file using the libpng. The low-level interface is used here -// because we want to do various transformations (including setting the -// matte background if any, and applying gama) which can't be done with -// the high-level interface. The scanline also begins at the bottom of +// because we want to do various transformations (including applying gama) +// which can't be done with the high-level interface. +// The scanline also begins at the bottom of // the image (per SecondLife conventions) instead of at the top, so we // must assign row-pointers in "reverse" order. BOOL LLPngWrapper::readPng(U8* src, LLImageRaw* rawImage, ImageInfo *infop) @@ -201,8 +199,7 @@ void LLPngWrapper::normalizeImage() // 2. Convert grayscales to RGB // 3. Create alpha layer from transparency // 4. Ensure 8-bpp for all images - // 5. Apply background matte if any - // 6. Set (or guess) gamma + // 5. Set (or guess) gamma if (mColorType == PNG_COLOR_TYPE_PALETTE) { @@ -229,12 +226,6 @@ void LLPngWrapper::normalizeImage() { png_set_strip_16(mReadPngPtr); } - mHasBKGD = png_get_bKGD(mReadPngPtr, mReadInfoPtr, &mBackgroundColor); - if (mHasBKGD) - { - png_set_background(mReadPngPtr, mBackgroundColor, - PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); - } #if LL_DARWIN const F64 SCREEN_GAMMA = 1.8; @@ -261,7 +252,6 @@ void LLPngWrapper::updateMetaData() mBitDepth = png_get_bit_depth(mReadPngPtr, mReadInfoPtr); mColorType = png_get_color_type(mReadPngPtr, mReadInfoPtr); mChannels = png_get_channels(mReadPngPtr, mReadInfoPtr); - mHasBKGD = png_get_bKGD(mReadPngPtr, mReadInfoPtr, &mBackgroundColor); } // Method to write raw image into PNG at dest. The raw scanline begins diff --git a/indra/llimage/llpngwrapper.h b/indra/llimage/llpngwrapper.h index 47a4207d66..739f435996 100644 --- a/indra/llimage/llpngwrapper.h +++ b/indra/llimage/llpngwrapper.h @@ -88,9 +88,6 @@ private: U32 mFinalSize; - bool mHasBKGD; - png_color_16p mBackgroundColor; - F64 mGamma; std::string mErrorMessage; -- cgit v1.2.3 From 410359b48d535f97043ded7542fb4c8c46c450f2 Mon Sep 17 00:00:00 2001 From: Paul Guslisty Date: Mon, 10 Jan 2011 19:15:17 +0200 Subject: STORM-370 FIXED Human-readable name of region disappears from Location Bar after pressing ESC - When location input control loses focus setting cursor to 0 to show the left edge of the text. --- indra/newview/lllocationinputctrl.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/indra/newview/lllocationinputctrl.cpp b/indra/newview/lllocationinputctrl.cpp index 1527f8f4c9..55164f6094 100644 --- a/indra/newview/lllocationinputctrl.cpp +++ b/indra/newview/lllocationinputctrl.cpp @@ -547,6 +547,10 @@ void LLLocationInputCtrl::onFocusLost() { LLUICtrl::onFocusLost(); refreshLocation(); + + // Setting cursor to 0 to show the left edge of the text. See STORM-370. + mTextEntry->setCursor(0); + if(mTextEntry->hasSelection()){ mTextEntry->deselect(); } -- cgit v1.2.3 From 97dea390ec9dcf7c51631f77df521fa9f0241250 Mon Sep 17 00:00:00 2001 From: Vadim ProductEngine Date: Mon, 10 Jan 2011 22:25:22 +0200 Subject: STORM-720 FIXED Disabled highlighting URLs in inventory items names in the share confirmation dialog. --- indra/newview/skins/default/xui/da/notifications.xml | 2 +- indra/newview/skins/default/xui/de/notifications.xml | 2 +- indra/newview/skins/default/xui/en/notifications.xml | 2 +- indra/newview/skins/default/xui/es/notifications.xml | 2 +- indra/newview/skins/default/xui/fr/notifications.xml | 2 +- indra/newview/skins/default/xui/it/notifications.xml | 2 +- indra/newview/skins/default/xui/ja/notifications.xml | 2 +- indra/newview/skins/default/xui/pl/notifications.xml | 2 +- indra/newview/skins/default/xui/pt/notifications.xml | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/indra/newview/skins/default/xui/da/notifications.xml b/indra/newview/skins/default/xui/da/notifications.xml index 70299c61b4..593e686d4c 100644 --- a/indra/newview/skins/default/xui/da/notifications.xml +++ b/indra/newview/skins/default/xui/da/notifications.xml @@ -1636,7 +1636,7 @@ Knappen vil blive vist når der er nok plads til den. Er du sikker på at du vil dele følgende genstande: -[ITEMS] +<nolink>[ITEMS]</nolink> Med følgende beboere: diff --git a/indra/newview/skins/default/xui/de/notifications.xml b/indra/newview/skins/default/xui/de/notifications.xml index 06cc02cd84..a2d0b5a170 100644 --- a/indra/newview/skins/default/xui/de/notifications.xml +++ b/indra/newview/skins/default/xui/de/notifications.xml @@ -2747,7 +2747,7 @@ Die Schaltfläche wird angezeigt, wenn genügend Platz vorhanden ist. Möchten Sie diese Objekte wirklich für andere freigeben: -[ITEMS] +<nolink>[ITEMS]</nolink> Für folgende Einwohner: diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index 3df53ac442..6f21938bdb 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -6431,7 +6431,7 @@ Select residents to share with. type="alertmodal"> Are you sure you want to share the following items: -[ITEMS] +<nolink>[ITEMS]</nolink> With the following Residents: diff --git a/indra/newview/skins/default/xui/es/notifications.xml b/indra/newview/skins/default/xui/es/notifications.xml index 2dd7a6b0f5..14ce39e8fc 100644 --- a/indra/newview/skins/default/xui/es/notifications.xml +++ b/indra/newview/skins/default/xui/es/notifications.xml @@ -2734,7 +2734,7 @@ Se mostrará cuando haya suficiente espacio. ¿Estás seguro de que quieres compartir los elementos siguientes? -[ITEMS] +<nolink>[ITEMS]</nolink> Con los siguientes residentes: diff --git a/indra/newview/skins/default/xui/fr/notifications.xml b/indra/newview/skins/default/xui/fr/notifications.xml index ec362d7f22..f0b0e63af0 100644 --- a/indra/newview/skins/default/xui/fr/notifications.xml +++ b/indra/newview/skins/default/xui/fr/notifications.xml @@ -2730,7 +2730,7 @@ Le bouton sera affiché quand il y aura suffisamment de place. Voulez-vous vraiment partager les articles suivants : -[ITEMS] +<nolink>[ITEMS]</nolink> avec les résidents suivants : diff --git a/indra/newview/skins/default/xui/it/notifications.xml b/indra/newview/skins/default/xui/it/notifications.xml index 32483881b2..5e53080c77 100644 --- a/indra/newview/skins/default/xui/it/notifications.xml +++ b/indra/newview/skins/default/xui/it/notifications.xml @@ -2679,7 +2679,7 @@ Il pulsante verrà visualizzato quando lo spazio sarà sufficiente. Sei sicuro di volere condividere gli oggetti -[ITEMS] +<nolink>[ITEMS]</nolink> Con i seguenti residenti? diff --git a/indra/newview/skins/default/xui/ja/notifications.xml b/indra/newview/skins/default/xui/ja/notifications.xml index c0af0e03ff..f133bb361a 100644 --- a/indra/newview/skins/default/xui/ja/notifications.xml +++ b/indra/newview/skins/default/xui/ja/notifications.xml @@ -2731,7 +2731,7 @@ M キーを押して変更します。 次のアイテムを共有しますか: -[ITEMS] +<nolink>[ITEMS]</nolink> 次の住人と共有しますか: diff --git a/indra/newview/skins/default/xui/pl/notifications.xml b/indra/newview/skins/default/xui/pl/notifications.xml index 8151c7eb93..57a6b8b8ef 100644 --- a/indra/newview/skins/default/xui/pl/notifications.xml +++ b/indra/newview/skins/default/xui/pl/notifications.xml @@ -2691,7 +2691,7 @@ Przycisk zostanie wyświetlony w przypadku dostatecznej ilości przestrzeni. Jesteś pewien/pewna, że chcesz udostępnić następujące obiekty: -[ITEMS] +<nolink>[ITEMS]</nolink> następującym Rezydentom: diff --git a/indra/newview/skins/default/xui/pt/notifications.xml b/indra/newview/skins/default/xui/pt/notifications.xml index dc38b740aa..0c3bfe2ed0 100644 --- a/indra/newview/skins/default/xui/pt/notifications.xml +++ b/indra/newview/skins/default/xui/pt/notifications.xml @@ -2714,7 +2714,7 @@ O botão será exibido quando houver espaço suficente. Tem certeza de que quer compartilhar os items abaixo? -[ITENS] +<nolink>[ITEMS]</nolink> Com os seguintes residentes: -- cgit v1.2.3 From ac877d1a7050163b850692468cfd2bf7ef544e82 Mon Sep 17 00:00:00 2001 From: Vadim ProductEngine Date: Mon, 10 Jan 2011 22:29:29 +0200 Subject: STORM-720 ADDITIONAL_FIX Typo in PT locale --- indra/newview/skins/default/xui/pt/notifications.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/skins/default/xui/pt/notifications.xml b/indra/newview/skins/default/xui/pt/notifications.xml index 0c3bfe2ed0..a1855f2e89 100644 --- a/indra/newview/skins/default/xui/pt/notifications.xml +++ b/indra/newview/skins/default/xui/pt/notifications.xml @@ -477,7 +477,7 @@ Para aumentar a qualidade do vídeo, vá para Preferências > Vídeo. Você não tem autorização para copiar os itens abaixo: -[ITENS] +[ITEMS] ao dá-los, você ficará sem eles no seu inventário. Deseja realmente dar estes itens? -- cgit v1.2.3 From d67f04da83c11707f2c4214b94c24d9cd12a16b6 Mon Sep 17 00:00:00 2001 From: Jonathan Yap Date: Mon, 10 Jan 2011 17:24:34 -0500 Subject: STORM-830 Per Aleric's and Q's suggestion set initial value of mInternalGain to -1 --- indra/llaudio/llaudioengine.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/indra/llaudio/llaudioengine.cpp b/indra/llaudio/llaudioengine.cpp index 8baba79f59..5e540ad8c5 100644 --- a/indra/llaudio/llaudioengine.cpp +++ b/indra/llaudio/llaudioengine.cpp @@ -97,10 +97,11 @@ void LLAudioEngine::setDefaults() } mMasterGain = 1.f; - // Setting mInternalGain to a very low but non-zero value fixes the issue reported in STORM-830. + // Setting mInternalGain to an out of range value fixes the issue reported in STORM-830. // There is an edge case in setMasterGain during startup which prevents setInternalGain from - // being called if the master volume setting and mInternalGain both equal 0. - mInternalGain = 0.0000000001f; + // being called if the master volume setting and mInternalGain both equal 0, so using -1 forces + // the if statement in setMasterGain to execute when the viewer starts up. + mInternalGain = -1.f; mNextWindUpdate = 0.f; mStreamingAudioImpl = NULL; -- cgit v1.2.3 From c8457f266423370e6f8e84c1b23ef95ed69a2997 Mon Sep 17 00:00:00 2001 From: Merov Linden Date: Mon, 10 Jan 2011 18:01:16 -0800 Subject: STORM-807 : Clean up code as discussed with Andrew --- indra/llmath/llbbox.cpp | 2 +- indra/llmessage/llregionflags.h | 13 ------------- indra/newview/llviewerobject.h | 2 +- indra/newview/llviewerparceloverlay.cpp | 8 ++++++-- 4 files changed, 8 insertions(+), 17 deletions(-) diff --git a/indra/llmath/llbbox.cpp b/indra/llmath/llbbox.cpp index d2208f604e..3e2c05a6e6 100644 --- a/indra/llmath/llbbox.cpp +++ b/indra/llmath/llbbox.cpp @@ -91,7 +91,7 @@ void LLBBox::addBBoxAgent(const LLBBox& b) LLBBox LLBBox::getAxisAligned() const { - // no rotiation = axis aligned rotation + // no rotation = axis aligned rotation LLBBox aligned(mPosAgent, LLQuaternion(), LLVector3(), LLVector3()); // add the center point so that it's not empty diff --git a/indra/llmessage/llregionflags.h b/indra/llmessage/llregionflags.h index aa47f1b524..7b796a0fa8 100644 --- a/indra/llmessage/llregionflags.h +++ b/indra/llmessage/llregionflags.h @@ -42,8 +42,6 @@ const U32 REGION_FLAGS_RESET_HOME_ON_TELEPORT = (1 << 3); // Does the sun move? const U32 REGION_FLAGS_SUN_FIXED = (1 << 4); -//const U32 REGION_FLAGS_TAX_FREE = (1 << 5); // legacy - // Can't change the terrain heightfield, even on owned parcels, // but can plant trees and grass. const U32 REGION_FLAGS_BLOCK_TERRAFORM = (1 << 6); @@ -53,9 +51,6 @@ const U32 REGION_FLAGS_BLOCK_LAND_RESELL = (1 << 7); // All content wiped once per night const U32 REGION_FLAGS_SANDBOX = (1 << 8); -//const U32 REGION_FLAGS_NULL_LAYER = (1 << 9); -//const U32 REGION_FLAGS_HARD_ALLOW_LAND_TRANSFER = (1 << 10); -//const U32 REGION_FLAGS_SKIP_UPDATE_INTEREST_LIST= (1 << 11); const U32 REGION_FLAGS_SKIP_COLLISIONS = (1 << 12); // Pin all non agent rigid bodies const U32 REGION_FLAGS_SKIP_SCRIPTS = (1 << 13); const U32 REGION_FLAGS_SKIP_PHYSICS = (1 << 14); // Skip all physics @@ -78,21 +73,13 @@ const U32 REGION_FLAGS_ESTATE_SKIP_SCRIPTS = (1 << 21); const U32 REGION_FLAGS_RESTRICT_PUSHOBJECT = (1 << 22); const U32 REGION_FLAGS_DENY_ANONYMOUS = (1 << 23); -//const U32 REGION_FLAGS_DENY_IDENTIFIED = (1 << 24); -//const U32 REGION_FLAGS_DENY_TRANSACTED = (1 << 25); const U32 REGION_FLAGS_ALLOW_PARCEL_CHANGES = (1 << 26); -// Deprecated. Phoeinx 2009-12-11 -// REGION_FLAGS_ABUSE_EMAIL_TO_ESTATE_OWNER is unused beyond viewer-1.23 -//const U32 REGION_FLAGS_ABUSE_EMAIL_TO_ESTATE_OWNER = (1 << 27); - const U32 REGION_FLAGS_ALLOW_VOICE = (1 << 28); const U32 REGION_FLAGS_BLOCK_PARCEL_SEARCH = (1 << 29); const U32 REGION_FLAGS_DENY_AGEUNVERIFIED = (1 << 30); -//const U32 REGION_FLAGS_SKIP_MONO_SCRIPTS = (1 << 31); - const U32 REGION_FLAGS_DEFAULT = REGION_FLAGS_ALLOW_LANDMARK | REGION_FLAGS_ALLOW_SET_HOME | diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index 21de5d28be..5c1a34d555 100644 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -226,7 +226,7 @@ public: virtual BOOL hasLightTexture() const { return FALSE; } // This method returns true if the object is over land owned by - // the agent, one of its groups, or it it encroaches and + // the agent, one of its groups, or it encroaches and // anti-encroachment is enabled bool isReturnable(); diff --git a/indra/newview/llviewerparceloverlay.cpp b/indra/newview/llviewerparceloverlay.cpp index 1207ef3340..d07e06f6a7 100644 --- a/indra/newview/llviewerparceloverlay.cpp +++ b/indra/newview/llviewerparceloverlay.cpp @@ -159,13 +159,17 @@ bool LLViewerParcelOverlay::encroachesOwned(const std::vector& boxes) co S32 bottom = S32(llclamp((max.mV[VY] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1)); for (S32 row = top; row <= bottom; row++) + { for (S32 column = left; column <= right; column++) { U8 type = ownership(row, column); - if (PARCEL_SELF == type - || PARCEL_GROUP == type ) + if ((PARCEL_SELF == type) + || (PARCEL_GROUP == type)) + { return true; + } } + } } return false; } -- cgit v1.2.3 From e3e1d9b4c3446ea87d1938d1cb0c4a5a9e5d448d Mon Sep 17 00:00:00 2001 From: Vadim ProductEngine Date: Tue, 11 Jan 2011 18:55:22 +0200 Subject: STORM-715 FIXED Don't expand default ("Clothing") accordion tab when docking/undocking the Appearance SP. There is a side effect: we don't reset the accordion when switching between sidepanels anymore. But I guess it's ok because other sidepanels (People, Me) don't reset their state either (e.g. if you open a group profile, then switch to My Inventory, then back to People, the group profile will still be opened). --- indra/newview/llsidepanelappearance.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/llsidepanelappearance.cpp b/indra/newview/llsidepanelappearance.cpp index b316171604..363fe5f12b 100644 --- a/indra/newview/llsidepanelappearance.cpp +++ b/indra/newview/llsidepanelappearance.cpp @@ -185,7 +185,7 @@ void LLSidepanelAppearance::onVisibilityChange(const LLSD &new_visibility) { LLSD visibility; visibility["visible"] = new_visibility.asBoolean(); - visibility["reset_accordion"] = true; + visibility["reset_accordion"] = false; updateToVisibility(visibility); } -- cgit v1.2.3 From 4af9db7b79f5721d1be6b8b94dd1e0ce97782d79 Mon Sep 17 00:00:00 2001 From: Seth ProductEngine Date: Tue, 11 Jan 2011 19:50:58 +0200 Subject: STORM-477 FIXED Re-implemented LLDir::getNextFileInDir() as an iterator object. - Replaced all existing usages of LLDir::getNextFileInDir() with the new directory iterator object. - Removed platform specific LLDir::getNextFileInDir() implementation. --- .../llui_libtest/llui_libtest.cpp | 5 +- indra/linux_updater/linux_updater.cpp | 15 ++++-- indra/llvfs/lldir.cpp | 6 ++- indra/llvfs/lldir.h | 25 --------- indra/llvfs/lldir_linux.cpp | 62 ---------------------- indra/llvfs/lldir_linux.h | 1 - indra/llvfs/lldir_mac.cpp | 61 --------------------- indra/llvfs/lldir_mac.h | 1 - indra/llvfs/lldir_solaris.cpp | 62 ---------------------- indra/llvfs/lldir_solaris.h | 1 - indra/llvfs/lldir_win32.cpp | 61 --------------------- indra/llvfs/lldir_win32.h | 3 -- indra/newview/llappviewer.cpp | 8 ++- indra/newview/llappviewerlinux.cpp | 5 +- indra/newview/llfloateruipreview.cpp | 26 ++++++--- indra/newview/lllogchat.cpp | 4 +- indra/newview/llviewermedia.cpp | 4 +- indra/newview/llwaterparammanager.cpp | 11 ++-- indra/newview/llwlparammanager.cpp | 11 ++-- .../updater/tests/llupdaterservice_test.cpp | 6 --- 20 files changed, 68 insertions(+), 310 deletions(-) diff --git a/indra/integration_tests/llui_libtest/llui_libtest.cpp b/indra/integration_tests/llui_libtest/llui_libtest.cpp index c34115ee80..217e26c3ca 100644 --- a/indra/integration_tests/llui_libtest/llui_libtest.cpp +++ b/indra/integration_tests/llui_libtest/llui_libtest.cpp @@ -33,6 +33,7 @@ // linden library includes #include "llcontrol.h" // LLControlGroup #include "lldir.h" +#include "lldiriterator.h" #include "llerrorcontrol.h" #include "llfloater.h" #include "llfontfreetype.h" @@ -174,7 +175,9 @@ void export_test_floaters() std::string delim = gDirUtilp->getDirDelimiter(); std::string xui_dir = get_xui_dir() + "en" + delim; std::string filename; - while (gDirUtilp->getNextFileInDir(xui_dir, "floater_test_*.xml", filename)) + + LLDirIterator iter(xui_dir, "floater_test_*.xml"); + while (iter.next(filename)) { if (filename.find("_new.xml") != std::string::npos) { diff --git a/indra/linux_updater/linux_updater.cpp b/indra/linux_updater/linux_updater.cpp index d909516bf8..808ab3f64f 100644 --- a/indra/linux_updater/linux_updater.cpp +++ b/indra/linux_updater/linux_updater.cpp @@ -33,6 +33,7 @@ #include "llerrorcontrol.h" #include "llfile.h" #include "lldir.h" +#include "lldiriterator.h" #include "llxmlnode.h" #include "lltrans.h" @@ -55,6 +56,8 @@ typedef struct _updater_app_state { std::string strings_dirs; std::string strings_file; + LLDirIterator *image_dir_iter; + GtkWidget *window; GtkWidget *progress_bar; GtkWidget *image; @@ -108,7 +111,7 @@ bool translate_init(std::string comma_delim_path_list, void updater_app_ui_init(void); void updater_app_quit(UpdaterAppState *app_state); void parse_args_and_init(int argc, char **argv, UpdaterAppState *app_state); -std::string next_image_filename(std::string& image_path); +std::string next_image_filename(std::string& image_path, LLDirIterator& iter); void display_error(GtkWidget *parent, std::string title, std::string message); BOOL install_package(std::string package_file, std::string destination); BOOL spawn_viewer(UpdaterAppState *app_state); @@ -174,7 +177,7 @@ void updater_app_ui_init(UpdaterAppState *app_state) // load the first image app_state->image = gtk_image_new_from_file - (next_image_filename(app_state->image_dir).c_str()); + (next_image_filename(app_state->image_dir, *app_state->image_dir_iter).c_str()); gtk_widget_set_size_request(app_state->image, 340, 310); gtk_container_add(GTK_CONTAINER(frame), app_state->image); @@ -205,7 +208,7 @@ gboolean rotate_image_cb(gpointer data) llassert(data != NULL); app_state = (UpdaterAppState *) data; - filename = next_image_filename(app_state->image_dir); + filename = next_image_filename(app_state->image_dir, *app_state->image_dir_iter); gdk_threads_enter(); gtk_image_set_from_file(GTK_IMAGE(app_state->image), filename.c_str()); @@ -214,10 +217,10 @@ gboolean rotate_image_cb(gpointer data) return TRUE; } -std::string next_image_filename(std::string& image_path) +std::string next_image_filename(std::string& image_path, LLDirIterator& iter) { std::string image_filename; - gDirUtilp->getNextFileInDir(image_path, "/*.jpg", image_filename); + iter.next(image_filename); return image_path + "/" + image_filename; } @@ -741,6 +744,7 @@ void parse_args_and_init(int argc, char **argv, UpdaterAppState *app_state) else if ((!strcmp(argv[i], "--image-dir")) && (++i < argc)) { app_state->image_dir = argv[i]; + app_state->image_dir_iter = new LLDirIterator(argv[i], "/*.jpg"); } else if ((!strcmp(argv[i], "--dest")) && (++i < argc)) { @@ -825,6 +829,7 @@ int main(int argc, char **argv) } bool success = !app_state->failure; + delete app_state->image_dir_iter; delete app_state; return success ? 0 : 1; } diff --git a/indra/llvfs/lldir.cpp b/indra/llvfs/lldir.cpp index 64556bcb4c..ab7d15dfef 100644 --- a/indra/llvfs/lldir.cpp +++ b/indra/llvfs/lldir.cpp @@ -40,6 +40,8 @@ #include "lltimer.h" // ms_sleep() #include "lluuid.h" +#include "lldiriterator.h" + #if LL_WINDOWS #include "lldir_win32.h" LLDir_Win32 gDirUtil; @@ -83,7 +85,9 @@ S32 LLDir::deleteFilesInDir(const std::string &dirname, const std::string &mask) std::string filename; std::string fullpath; S32 result; - while (getNextFileInDir(dirname, mask, filename)) + + LLDirIterator iter(dirname, mask); + while (iter.next(filename)) { fullpath = dirname; fullpath += getDirDelimiter(); diff --git a/indra/llvfs/lldir.h b/indra/llvfs/lldir.h index 42996fd051..5ee8bdb542 100644 --- a/indra/llvfs/lldir.h +++ b/indra/llvfs/lldir.h @@ -75,31 +75,6 @@ class LLDir // pure virtual functions virtual U32 countFilesInDir(const std::string &dirname, const std::string &mask) = 0; - /// Walk the files in a directory, with file pattern matching - virtual BOOL getNextFileInDir(const std::string& dirname, ///< directory path - must end in trailing slash! - const std::string& mask, ///< file pattern string (use "*" for all) - std::string& fname ///< output: found file name - ) = 0; - /**< - * @returns true if a file was found, false if the entire directory has been scanned. - * - * @note that this function is NOT thread safe - * - * This function may not be used to scan part of a directory, then start a new search of a different - * directory, and then restart the first search where it left off; the entire search must run to - * completion or be abandoned - there is no restart. - * - * @bug: See http://jira.secondlife.com/browse/VWR-23697 - * and/or the tests in test/lldir_test.cpp - * This is known to fail with patterns that have both: - * a wildcard left of a . and more than one sequential ? right of a . - * the pattern foo.??x appears to work - * but *.??x or foo?.??x do not - * - * @todo this really should be rewritten as an iterator object, and the - * filtering should be done in a platform-independent way. - */ - virtual std::string getCurPath() = 0; virtual BOOL fileExists(const std::string &filename) const = 0; diff --git a/indra/llvfs/lldir_linux.cpp b/indra/llvfs/lldir_linux.cpp index 73f2336f94..4ba2f519b0 100644 --- a/indra/llvfs/lldir_linux.cpp +++ b/indra/llvfs/lldir_linux.cpp @@ -242,68 +242,6 @@ U32 LLDir_Linux::countFilesInDir(const std::string &dirname, const std::string & return (file_count); } -// get the next file in the directory -BOOL LLDir_Linux::getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname) -{ - glob_t g; - BOOL result = FALSE; - fname = ""; - - if(!(dirname == mCurrentDir)) - { - // different dir specified, close old search - mCurrentDirIndex = -1; - mCurrentDirCount = -1; - mCurrentDir = dirname; - } - - std::string tmp_str; - tmp_str = dirname; - tmp_str += mask; - - if(glob(tmp_str.c_str(), GLOB_NOSORT, NULL, &g) == 0) - { - if(g.gl_pathc > 0) - { - if((int)g.gl_pathc != mCurrentDirCount) - { - // Number of matches has changed since the last search, meaning a file has been added or deleted. - // Reset the index. - mCurrentDirIndex = -1; - mCurrentDirCount = g.gl_pathc; - } - - mCurrentDirIndex++; - - if(mCurrentDirIndex < (int)g.gl_pathc) - { -// llinfos << "getNextFileInDir: returning number " << mCurrentDirIndex << ", path is " << g.gl_pathv[mCurrentDirIndex] << llendl; - - // The API wants just the filename, not the full path. - //fname = g.gl_pathv[mCurrentDirIndex]; - - char *s = strrchr(g.gl_pathv[mCurrentDirIndex], '/'); - - if(s == NULL) - s = g.gl_pathv[mCurrentDirIndex]; - else if(s[0] == '/') - s++; - - fname = s; - - result = TRUE; - } - } - - globfree(&g); - } - - return(result); -} - - - - std::string LLDir_Linux::getCurPath() { char tmp_str[LL_MAX_PATH]; /* Flawfinder: ignore */ diff --git a/indra/llvfs/lldir_linux.h b/indra/llvfs/lldir_linux.h index 451e81ae93..ff4c48759a 100644 --- a/indra/llvfs/lldir_linux.h +++ b/indra/llvfs/lldir_linux.h @@ -43,7 +43,6 @@ public: public: virtual std::string getCurPath(); virtual U32 countFilesInDir(const std::string &dirname, const std::string &mask); - virtual BOOL getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname); /*virtual*/ BOOL fileExists(const std::string &filename) const; /*virtual*/ std::string getLLPluginLauncher(); diff --git a/indra/llvfs/lldir_mac.cpp b/indra/llvfs/lldir_mac.cpp index 445285aa43..2d039527c0 100644 --- a/indra/llvfs/lldir_mac.cpp +++ b/indra/llvfs/lldir_mac.cpp @@ -258,67 +258,6 @@ U32 LLDir_Mac::countFilesInDir(const std::string &dirname, const std::string &ma return (file_count); } -// get the next file in the directory -BOOL LLDir_Mac::getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname) -{ - glob_t g; - BOOL result = FALSE; - fname = ""; - - if(!(dirname == mCurrentDir)) - { - // different dir specified, close old search - mCurrentDirIndex = -1; - mCurrentDirCount = -1; - mCurrentDir = dirname; - } - - std::string tmp_str; - tmp_str = dirname; - tmp_str += mask; - - if(glob(tmp_str.c_str(), GLOB_NOSORT, NULL, &g) == 0) - { - if(g.gl_pathc > 0) - { - if(g.gl_pathc != mCurrentDirCount) - { - // Number of matches has changed since the last search, meaning a file has been added or deleted. - // Reset the index. - mCurrentDirIndex = -1; - mCurrentDirCount = g.gl_pathc; - } - - mCurrentDirIndex++; - - if(mCurrentDirIndex < g.gl_pathc) - { -// llinfos << "getNextFileInDir: returning number " << mCurrentDirIndex << ", path is " << g.gl_pathv[mCurrentDirIndex] << llendl; - - // The API wants just the filename, not the full path. - //fname = g.gl_pathv[mCurrentDirIndex]; - - char *s = strrchr(g.gl_pathv[mCurrentDirIndex], '/'); - - if(s == NULL) - s = g.gl_pathv[mCurrentDirIndex]; - else if(s[0] == '/') - s++; - - fname = s; - - result = TRUE; - } - } - - globfree(&g); - } - - return(result); -} - - - S32 LLDir_Mac::deleteFilesInDir(const std::string &dirname, const std::string &mask) { glob_t g; diff --git a/indra/llvfs/lldir_mac.h b/indra/llvfs/lldir_mac.h index 4eac3c3ae6..e60d5e41c2 100644 --- a/indra/llvfs/lldir_mac.h +++ b/indra/llvfs/lldir_mac.h @@ -43,7 +43,6 @@ public: virtual S32 deleteFilesInDir(const std::string &dirname, const std::string &mask); virtual std::string getCurPath(); virtual U32 countFilesInDir(const std::string &dirname, const std::string &mask); - virtual BOOL getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname); virtual BOOL fileExists(const std::string &filename) const; /*virtual*/ std::string getLLPluginLauncher(); diff --git a/indra/llvfs/lldir_solaris.cpp b/indra/llvfs/lldir_solaris.cpp index 515fd66b6e..21f8c3acdb 100644 --- a/indra/llvfs/lldir_solaris.cpp +++ b/indra/llvfs/lldir_solaris.cpp @@ -260,68 +260,6 @@ U32 LLDir_Solaris::countFilesInDir(const std::string &dirname, const std::string return (file_count); } -// get the next file in the directory -BOOL LLDir_Solaris::getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname) -{ - glob_t g; - BOOL result = FALSE; - fname = ""; - - if(!(dirname == mCurrentDir)) - { - // different dir specified, close old search - mCurrentDirIndex = -1; - mCurrentDirCount = -1; - mCurrentDir = dirname; - } - - std::string tmp_str; - tmp_str = dirname; - tmp_str += mask; - - if(glob(tmp_str.c_str(), GLOB_NOSORT, NULL, &g) == 0) - { - if(g.gl_pathc > 0) - { - if((int)g.gl_pathc != mCurrentDirCount) - { - // Number of matches has changed since the last search, meaning a file has been added or deleted. - // Reset the index. - mCurrentDirIndex = -1; - mCurrentDirCount = g.gl_pathc; - } - - mCurrentDirIndex++; - - if(mCurrentDirIndex < (int)g.gl_pathc) - { -// llinfos << "getNextFileInDir: returning number " << mCurrentDirIndex << ", path is " << g.gl_pathv[mCurrentDirIndex] << llendl; - - // The API wants just the filename, not the full path. - //fname = g.gl_pathv[mCurrentDirIndex]; - - char *s = strrchr(g.gl_pathv[mCurrentDirIndex], '/'); - - if(s == NULL) - s = g.gl_pathv[mCurrentDirIndex]; - else if(s[0] == '/') - s++; - - fname = s; - - result = TRUE; - } - } - - globfree(&g); - } - - return(result); -} - - - - std::string LLDir_Solaris::getCurPath() { char tmp_str[LL_MAX_PATH]; /* Flawfinder: ignore */ diff --git a/indra/llvfs/lldir_solaris.h b/indra/llvfs/lldir_solaris.h index 4a1794f539..f7e1a6301d 100644 --- a/indra/llvfs/lldir_solaris.h +++ b/indra/llvfs/lldir_solaris.h @@ -43,7 +43,6 @@ public: public: virtual std::string getCurPath(); virtual U32 countFilesInDir(const std::string &dirname, const std::string &mask); - virtual BOOL getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname); /*virtual*/ BOOL fileExists(const std::string &filename) const; private: diff --git a/indra/llvfs/lldir_win32.cpp b/indra/llvfs/lldir_win32.cpp index 33718e520d..2f96fbbbc1 100644 --- a/indra/llvfs/lldir_win32.cpp +++ b/indra/llvfs/lldir_win32.cpp @@ -236,67 +236,6 @@ U32 LLDir_Win32::countFilesInDir(const std::string &dirname, const std::string & return (file_count); } - -// get the next file in the directory -BOOL LLDir_Win32::getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname) -{ - BOOL fileFound = FALSE; - fname = ""; - - WIN32_FIND_DATAW FileData; - llutf16string pathname = utf8str_to_utf16str(dirname) + utf8str_to_utf16str(mask); - - if (pathname != mCurrentDir) - { - // different dir specified, close old search - if (mCurrentDir[0]) - { - FindClose(mDirSearch_h); - } - mCurrentDir = pathname; - - // and open new one - // Check error opening Directory structure - if ((mDirSearch_h = FindFirstFile(pathname.c_str(), &FileData)) != INVALID_HANDLE_VALUE) - { - fileFound = TRUE; - } - } - - // Loop to skip over the current (.) and parent (..) directory entries - // (apparently returned in Win7 but not XP) - do - { - if ( fileFound - && ( (lstrcmp(FileData.cFileName, (LPCTSTR)TEXT(".")) == 0) - ||(lstrcmp(FileData.cFileName, (LPCTSTR)TEXT("..")) == 0) - ) - ) - { - fileFound = FALSE; - } - } while ( mDirSearch_h != INVALID_HANDLE_VALUE - && !fileFound - && (fileFound = FindNextFile(mDirSearch_h, &FileData) - ) - ); - - if (!fileFound && GetLastError() == ERROR_NO_MORE_FILES) - { - // No more files, so reset to beginning of directory - FindClose(mDirSearch_h); - mCurrentDir[0] = '\000'; - } - - if (fileFound) - { - // convert from TCHAR to char - fname = utf16str_to_utf8str(FileData.cFileName); - } - - return fileFound; -} - std::string LLDir_Win32::getCurPath() { WCHAR w_str[MAX_PATH]; diff --git a/indra/llvfs/lldir_win32.h b/indra/llvfs/lldir_win32.h index 4c932c932c..19c610eb8b 100644 --- a/indra/llvfs/lldir_win32.h +++ b/indra/llvfs/lldir_win32.h @@ -40,15 +40,12 @@ public: /*virtual*/ std::string getCurPath(); /*virtual*/ U32 countFilesInDir(const std::string &dirname, const std::string &mask); - /*virtual*/ BOOL getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname); /*virtual*/ BOOL fileExists(const std::string &filename) const; /*virtual*/ std::string getLLPluginLauncher(); /*virtual*/ std::string getLLPluginFilename(std::string base_name); private: - BOOL LLDir_Win32::getNextFileInDir(const llutf16string &dirname, const std::string &mask, std::string &fname); - void* mDirSearch_h; llutf16string mCurrentDir; }; diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 3a98c23e05..b5248316a1 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -89,6 +89,7 @@ // Linden library includes #include "llavatarnamecache.h" +#include "lldiriterator.h" #include "llimagej2c.h" #include "llmemory.h" #include "llprimitive.h" @@ -3290,7 +3291,9 @@ void LLAppViewer::migrateCacheDirectory() S32 file_count = 0; std::string file_name; std::string mask = delimiter + "*.*"; - while (gDirUtilp->getNextFileInDir(old_cache_dir, mask, file_name)) + + LLDirIterator iter(old_cache_dir, mask); + while (iter.next(file_name)) { if (file_name == "." || file_name == "..") continue; std::string source_path = old_cache_dir + delimiter + file_name; @@ -3509,7 +3512,8 @@ bool LLAppViewer::initCache() dir = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,""); std::string found_file; - if (gDirUtilp->getNextFileInDir(dir, mask, found_file)) + LLDirIterator iter(dir, mask); + if (iter.next(found_file)) { old_vfs_data_file = dir + gDirUtilp->getDirDelimiter() + found_file; diff --git a/indra/newview/llappviewerlinux.cpp b/indra/newview/llappviewerlinux.cpp index 898cc1c0ba..fc7a27e5e0 100644 --- a/indra/newview/llappviewerlinux.cpp +++ b/indra/newview/llappviewerlinux.cpp @@ -30,6 +30,7 @@ #include "llcommandlineparser.h" +#include "lldiriterator.h" #include "llmemtype.h" #include "llurldispatcher.h" // SLURL from other app instance #include "llviewernetwork.h" @@ -504,7 +505,9 @@ std::string LLAppViewerLinux::generateSerialNumber() // trawl /dev/disk/by-uuid looking for a good-looking UUID to grab std::string this_name; - while (gDirUtilp->getNextFileInDir(uuiddir, "*", this_name)) + + LLDirIterator iter(uuiddir, "*"); + while (iter.next(this_name)) { if (this_name.length() > best.length() || (this_name.length() == best.length() && diff --git a/indra/newview/llfloateruipreview.cpp b/indra/newview/llfloateruipreview.cpp index 11b3379814..182d3d23f1 100644 --- a/indra/newview/llfloateruipreview.cpp +++ b/indra/newview/llfloateruipreview.cpp @@ -35,6 +35,7 @@ #include "llfloateruipreview.h" // Own header // Internal utility +#include "lldiriterator.h" #include "lleventtimer.h" #include "llexternaleditor.h" #include "llrender.h" @@ -481,9 +482,11 @@ BOOL LLFloaterUIPreview::postBuild() std::string language_directory; std::string xui_dir = get_xui_dir(); // directory containing localizations -- don't forget trailing delim mLanguageSelection->removeall(); // clear out anything temporarily in list from XML + + LLDirIterator iter(xui_dir, "*"); while(found) // for every directory { - if((found = gDirUtilp->getNextFileInDir(xui_dir, "*", language_directory))) // get next directory + if((found = iter.next(language_directory))) // get next directory { std::string full_path = xui_dir + language_directory; if(LLFile::isfile(full_path.c_str())) // if it's not a directory, skip it @@ -635,42 +638,51 @@ void LLFloaterUIPreview::refreshList() mFileList->clearRows(); // empty list std::string name; BOOL found = TRUE; + + LLDirIterator floater_iter(getLocalizedDirectory(), "floater_*.xml"); while(found) // for every floater file that matches the pattern { - if((found = gDirUtilp->getNextFileInDir(getLocalizedDirectory(), "floater_*.xml", name))) // get next file matching pattern + if((found = floater_iter.next(name))) // get next file matching pattern { addFloaterEntry(name.c_str()); // and add it to the list (file name only; localization code takes care of rest of path) } } found = TRUE; + + LLDirIterator inspect_iter(getLocalizedDirectory(), "inspect_*.xml"); while(found) // for every inspector file that matches the pattern { - if((found = gDirUtilp->getNextFileInDir(getLocalizedDirectory(), "inspect_*.xml", name))) // get next file matching pattern + if((found = inspect_iter.next(name))) // get next file matching pattern { addFloaterEntry(name.c_str()); // and add it to the list (file name only; localization code takes care of rest of path) } } found = TRUE; + + LLDirIterator menu_iter(getLocalizedDirectory(), "menu_*.xml"); while(found) // for every menu file that matches the pattern { - if((found = gDirUtilp->getNextFileInDir(getLocalizedDirectory(), "menu_*.xml", name))) // get next file matching pattern + if((found = menu_iter.next(name))) // get next file matching pattern { addFloaterEntry(name.c_str()); // and add it to the list (file name only; localization code takes care of rest of path) } } found = TRUE; + + LLDirIterator panel_iter(getLocalizedDirectory(), "panel_*.xml"); while(found) // for every panel file that matches the pattern { - if((found = gDirUtilp->getNextFileInDir(getLocalizedDirectory(), "panel_*.xml", name))) // get next file matching pattern + if((found = panel_iter.next(name))) // get next file matching pattern { addFloaterEntry(name.c_str()); // and add it to the list (file name only; localization code takes care of rest of path) } } - found = TRUE; + + LLDirIterator sidepanel_iter(getLocalizedDirectory(), "sidepanel_*.xml"); while(found) // for every sidepanel file that matches the pattern { - if((found = gDirUtilp->getNextFileInDir(getLocalizedDirectory(), "sidepanel_*.xml", name))) // get next file matching pattern + if((found = sidepanel_iter.next(name))) // get next file matching pattern { addFloaterEntry(name.c_str()); // and add it to the list (file name only; localization code takes care of rest of path) } diff --git a/indra/newview/lllogchat.cpp b/indra/newview/lllogchat.cpp index 9adf374c71..b09cfbe907 100644 --- a/indra/newview/lllogchat.cpp +++ b/indra/newview/lllogchat.cpp @@ -32,6 +32,7 @@ #include "lltrans.h" #include "llviewercontrol.h" +#include "lldiriterator.h" #include "llinstantmessage.h" #include "llsingleton.h" // for LLSingleton @@ -601,7 +602,8 @@ std::string LLLogChat::oldLogFileName(std::string filename) //LL_INFOS("") << "Checking:" << directory << " for " << pattern << LL_ENDL;/* uncomment if you want to verify step, delete on commit */ std::vector allfiles; - while (gDirUtilp->getNextFileInDir(directory, pattern, scanResult)) + LLDirIterator iter(directory, pattern); + while (iter.next(scanResult)) { //LL_INFOS("") << "Found :" << scanResult << LL_ENDL; allfiles.push_back(scanResult); diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index d3b6dcd86f..8a0d0a6623 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -54,6 +54,7 @@ #include "llfilepicker.h" #include "llnotifications.h" +#include "lldiriterator.h" #include "llevent.h" // LLSimpleListener #include "llnotificationsutil.h" #include "lluuid.h" @@ -1115,7 +1116,8 @@ void LLViewerMedia::clearAllCookies() } // the hard part: iterate over all user directories and delete the cookie file from each one - while(gDirUtilp->getNextFileInDir(base_dir, "*_*", filename)) + LLDirIterator dir_iter(base_dir, "*_*"); + while (dir_iter.next(filename)) { target = base_dir; target += filename; diff --git a/indra/newview/llwaterparammanager.cpp b/indra/newview/llwaterparammanager.cpp index d239347810..4f6ec4ca61 100644 --- a/indra/newview/llwaterparammanager.cpp +++ b/indra/newview/llwaterparammanager.cpp @@ -33,6 +33,7 @@ #include "pipeline.h" #include "llsky.h" +#include "lldiriterator.h" #include "llfloaterreg.h" #include "llsliderctrl.h" #include "llspinctrl.h" @@ -85,11 +86,12 @@ void LLWaterParamManager::loadAllPresets(const std::string& file_name) std::string path_name(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight/water", "")); LL_DEBUGS2("AppInit", "Shaders") << "Loading Default water settings from " << path_name << LL_ENDL; - bool found = true; + bool found = true; + LLDirIterator app_settings_iter(path_name, "*.xml"); while(found) { std::string name; - found = gDirUtilp->getNextFileInDir(path_name, "*.xml", name); + found = app_settings_iter.next(name); if(found) { @@ -111,11 +113,12 @@ void LLWaterParamManager::loadAllPresets(const std::string& file_name) std::string path_name2(gDirUtilp->getExpandedFilename( LL_PATH_USER_SETTINGS , "windlight/water", "")); LL_DEBUGS2("AppInit", "Shaders") << "Loading User water settings from " << path_name2 << LL_ENDL; - found = true; + found = true; + LLDirIterator user_settings_iter(path_name2, "*.xml"); while(found) { std::string name; - found = gDirUtilp->getNextFileInDir(path_name2, "*.xml", name); + found = user_settings_iter.next(name); if(found) { name=name.erase(name.length()-4); diff --git a/indra/newview/llwlparammanager.cpp b/indra/newview/llwlparammanager.cpp index e5f52dfc97..848efcbb49 100644 --- a/indra/newview/llwlparammanager.cpp +++ b/indra/newview/llwlparammanager.cpp @@ -31,6 +31,7 @@ #include "pipeline.h" #include "llsky.h" +#include "lldiriterator.h" #include "llfloaterreg.h" #include "llsliderctrl.h" #include "llspinctrl.h" @@ -100,11 +101,12 @@ void LLWLParamManager::loadPresets(const std::string& file_name) std::string path_name(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight/skies", "")); LL_DEBUGS2("AppInit", "Shaders") << "Loading Default WindLight settings from " << path_name << LL_ENDL; - bool found = true; + bool found = true; + LLDirIterator app_settings_iter(path_name, "*.xml"); while(found) { std::string name; - found = gDirUtilp->getNextFileInDir(path_name, "*.xml", name); + found = app_settings_iter.next(name); if(found) { @@ -126,11 +128,12 @@ void LLWLParamManager::loadPresets(const std::string& file_name) std::string path_name2(gDirUtilp->getExpandedFilename( LL_PATH_USER_SETTINGS , "windlight/skies", "")); LL_DEBUGS2("AppInit", "Shaders") << "Loading User WindLight settings from " << path_name2 << LL_ENDL; - found = true; + found = true; + LLDirIterator user_settings_iter(path_name2, "*.xml"); while(found) { std::string name; - found = gDirUtilp->getNextFileInDir(path_name2, "*.xml", name); + found = user_settings_iter.next(name); if(found) { name=name.erase(name.length()-4); diff --git a/indra/viewer_components/updater/tests/llupdaterservice_test.cpp b/indra/viewer_components/updater/tests/llupdaterservice_test.cpp index 88ab5a2284..e19d5724f1 100644 --- a/indra/viewer_components/updater/tests/llupdaterservice_test.cpp +++ b/indra/viewer_components/updater/tests/llupdaterservice_test.cpp @@ -59,12 +59,6 @@ class LLDir_Mock : public LLDir return 0; } - BOOL getNextFileInDir(const std::string &dirname, - const std::string &mask, - std::string &fname) - { - return false; - } void getRandomFileInDir(const std::string &dirname, const std::string &mask, std::string &fname) {} -- cgit v1.2.3 From 7a1d7d15b9658b6bde224bd87e476ac152925413 Mon Sep 17 00:00:00 2001 From: Richard Linden Date: Tue, 11 Jan 2011 16:56:05 -0800 Subject: STORM-823 FIX Tab Key not working properly set focus root to true by default for all floaters via floater.xml template existing calls to setIsChrome will turn off focus root for chrome floaters after initializing it from the focus_root parameter --- indra/llui/llfloater.cpp | 5 ----- indra/newview/skins/default/xui/en/widgets/floater.xml | 1 + 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp index d30697e178..c425782715 100644 --- a/indra/llui/llfloater.cpp +++ b/indra/llui/llfloater.cpp @@ -272,9 +272,6 @@ LLFloater::LLFloater(const LLSD& key, const LLFloater::Params& p) initFromParams(p); - // chrome floaters don't take focus at all - setFocusRoot(!getIsChrome()); - initFloater(p); } @@ -2910,8 +2907,6 @@ bool LLFloater::initFloaterXML(LLXMLNodePtr node, LLView *parent, const std::str params.from_xui = true; applyXUILayout(params, parent); initFromParams(params); - // chrome floaters don't take focus at all - setFocusRoot(!getIsChrome()); initFloater(params); diff --git a/indra/newview/skins/default/xui/en/widgets/floater.xml b/indra/newview/skins/default/xui/en/widgets/floater.xml index 85d0c633af..2e5ebafe46 100644 --- a/indra/newview/skins/default/xui/en/widgets/floater.xml +++ b/indra/newview/skins/default/xui/en/widgets/floater.xml @@ -21,4 +21,5 @@ tear_off_pressed_image="tearoff_pressed.tga" dock_pressed_image="Icon_Dock_Press" help_pressed_image="Icon_Help_Press" + focus_root="true" /> -- cgit v1.2.3 From 3703f0bb0d7cd20c801d88cb77632c239010d26b Mon Sep 17 00:00:00 2001 From: Jonathan Yap Date: Wed, 12 Jan 2011 08:24:38 -0500 Subject: STORM-844 "More" should be "Less" when Media Control is open --- doc/contributions.txt | 7 ++++--- indra/newview/skins/default/xui/en/panel_nearby_media.xml | 6 +++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/doc/contributions.txt b/doc/contributions.txt index 9266ae3c5b..0d7bed2f78 100644 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -366,15 +366,16 @@ JB Kraft Joghert LeSabre VWR-64 Jonathan Yap - STORM-596 STORM-523 + STORM-596 STORM-616 STORM-679 - STORM-737 STORM-726 + STORM-737 + STORM-785 STORM-812 + STORM-844 VWR-17801 - STORM-785 Kage Pixel VWR-11 Ken March diff --git a/indra/newview/skins/default/xui/en/panel_nearby_media.xml b/indra/newview/skins/default/xui/en/panel_nearby_media.xml index 8c13ced8f3..aac3608e13 100644 --- a/indra/newview/skins/default/xui/en/panel_nearby_media.xml +++ b/indra/newview/skins/default/xui/en/panel_nearby_media.xml @@ -69,7 +69,7 @@ width="66" height="22" label="More >>" - label_selected="Less <<"> + label_selected="More >>"> @@ -81,8 +81,8 @@ right="-8" width="66" height="22" - label="More >>" - label_selected="Less <<"> + label="<< Less" + label_selected="<< Less"> -- cgit v1.2.3 From e27ae655c6859f947d92c789f189b52940dae877 Mon Sep 17 00:00:00 2001 From: Jonathan Yap Date: Wed, 12 Jan 2011 10:37:15 -0500 Subject: STORM-844 Minor adjustment to contributions.txt --- doc/contributions.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/contributions.txt b/doc/contributions.txt index 0d7bed2f78..f4831a1947 100644 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -366,16 +366,16 @@ JB Kraft Joghert LeSabre VWR-64 Jonathan Yap - STORM-523 STORM-596 + STORM-523 STORM-616 STORM-679 - STORM-726 STORM-737 - STORM-785 + STORM-726 STORM-812 - STORM-844 VWR-17801 + STORM-785 + STORM-844 Kage Pixel VWR-11 Ken March -- cgit v1.2.3 From ad555098bf599bbb9bdb4db945baef56674c0f2d Mon Sep 17 00:00:00 2001 From: Paul Guslisty Date: Thu, 13 Jan 2011 16:52:25 +0200 Subject: STORM-832 FIXED Two Roles are selected after made changes in one - Clear selection from role that was changed --- indra/newview/llpanelgrouproles.cpp | 21 ++++++++++++++++----- indra/newview/llpanelgrouproles.h | 2 +- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/indra/newview/llpanelgrouproles.cpp b/indra/newview/llpanelgrouproles.cpp index d1362d7922..3dbc637318 100644 --- a/indra/newview/llpanelgrouproles.cpp +++ b/indra/newview/llpanelgrouproles.cpp @@ -1843,7 +1843,8 @@ bool LLPanelGroupRolesSubTab::apply(std::string& mesg) { lldebugs << "LLPanelGroupRolesSubTab::apply()" << llendl; - saveRoleChanges(); + saveRoleChanges(true); + LLGroupMgr::getInstance()->sendGroupRoleChanges(mGroupID); notifyObservers(); @@ -2022,7 +2023,7 @@ void LLPanelGroupRolesSubTab::handleRoleSelect() return; } - saveRoleChanges(); + saveRoleChanges(false); // Check if there is anything selected. LLScrollListItem* item = mRolesList->getFirstSelected(); @@ -2385,7 +2386,7 @@ void LLPanelGroupRolesSubTab::handleDeleteRole() notifyObservers(); } -void LLPanelGroupRolesSubTab::saveRoleChanges() +void LLPanelGroupRolesSubTab::saveRoleChanges(bool select_saved_role) { LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID); @@ -2400,13 +2401,23 @@ void LLPanelGroupRolesSubTab::saveRoleChanges() rd.mRoleDescription = mRoleDescription->getText(); rd.mRoleTitle = mRoleTitle->getText(); + S32 role_members_count = 0; + if (mSelectedRole.isNull()) + { + role_members_count = gdatap->mMemberCount; + } + else if(LLGroupRoleData* grd = get_ptr_in_map(gdatap->mRoles, mSelectedRole)) + { + role_members_count = grd->getTotalMembersInRole(); + } + gdatap->setRoleData(mSelectedRole,rd); mRolesList->deleteSingleItem(mRolesList->getItemIndex(mSelectedRole)); - LLSD row = createRoleItem(mSelectedRole,rd.mRoleName,rd.mRoleTitle,0); + LLSD row = createRoleItem(mSelectedRole,rd.mRoleName,rd.mRoleTitle,role_members_count); LLScrollListItem* item = mRolesList->addElement(row, ADD_BOTTOM, this); - item->setSelected(TRUE); + item->setSelected(select_saved_role); mHasRoleChange = FALSE; } diff --git a/indra/newview/llpanelgrouproles.h b/indra/newview/llpanelgrouproles.h index 270259c16f..a55e264150 100644 --- a/indra/newview/llpanelgrouproles.h +++ b/indra/newview/llpanelgrouproles.h @@ -257,7 +257,7 @@ public: static void onDeleteRole(void*); void handleDeleteRole(); - void saveRoleChanges(); + void saveRoleChanges(bool select_saved_role); virtual void setGroupID(const LLUUID& id); protected: -- cgit v1.2.3 From 804495ad41cbd0eb511c02d5306fc3b8f9be0b89 Mon Sep 17 00:00:00 2001 From: Merov Linden Date: Thu, 13 Jan 2011 11:15:47 -0800 Subject: STORM-477 : backout changeset 6f5cb303d3e2 --- .../llui_libtest/llui_libtest.cpp | 5 +- indra/linux_updater/linux_updater.cpp | 15 ++---- indra/llvfs/lldir.cpp | 6 +-- indra/llvfs/lldir.h | 25 +++++++++ indra/llvfs/lldir_linux.cpp | 62 ++++++++++++++++++++++ indra/llvfs/lldir_linux.h | 1 + indra/llvfs/lldir_mac.cpp | 61 +++++++++++++++++++++ indra/llvfs/lldir_mac.h | 1 + indra/llvfs/lldir_solaris.cpp | 62 ++++++++++++++++++++++ indra/llvfs/lldir_solaris.h | 1 + indra/llvfs/lldir_win32.cpp | 61 +++++++++++++++++++++ indra/llvfs/lldir_win32.h | 3 ++ indra/newview/llappviewer.cpp | 8 +-- indra/newview/llappviewerlinux.cpp | 5 +- indra/newview/llfloateruipreview.cpp | 26 +++------ indra/newview/lllogchat.cpp | 4 +- indra/newview/llviewermedia.cpp | 4 +- indra/newview/llwaterparammanager.cpp | 11 ++-- indra/newview/llwlparammanager.cpp | 11 ++-- .../updater/tests/llupdaterservice_test.cpp | 6 +++ 20 files changed, 310 insertions(+), 68 deletions(-) diff --git a/indra/integration_tests/llui_libtest/llui_libtest.cpp b/indra/integration_tests/llui_libtest/llui_libtest.cpp index 217e26c3ca..c34115ee80 100644 --- a/indra/integration_tests/llui_libtest/llui_libtest.cpp +++ b/indra/integration_tests/llui_libtest/llui_libtest.cpp @@ -33,7 +33,6 @@ // linden library includes #include "llcontrol.h" // LLControlGroup #include "lldir.h" -#include "lldiriterator.h" #include "llerrorcontrol.h" #include "llfloater.h" #include "llfontfreetype.h" @@ -175,9 +174,7 @@ void export_test_floaters() std::string delim = gDirUtilp->getDirDelimiter(); std::string xui_dir = get_xui_dir() + "en" + delim; std::string filename; - - LLDirIterator iter(xui_dir, "floater_test_*.xml"); - while (iter.next(filename)) + while (gDirUtilp->getNextFileInDir(xui_dir, "floater_test_*.xml", filename)) { if (filename.find("_new.xml") != std::string::npos) { diff --git a/indra/linux_updater/linux_updater.cpp b/indra/linux_updater/linux_updater.cpp index 808ab3f64f..d909516bf8 100644 --- a/indra/linux_updater/linux_updater.cpp +++ b/indra/linux_updater/linux_updater.cpp @@ -33,7 +33,6 @@ #include "llerrorcontrol.h" #include "llfile.h" #include "lldir.h" -#include "lldiriterator.h" #include "llxmlnode.h" #include "lltrans.h" @@ -56,8 +55,6 @@ typedef struct _updater_app_state { std::string strings_dirs; std::string strings_file; - LLDirIterator *image_dir_iter; - GtkWidget *window; GtkWidget *progress_bar; GtkWidget *image; @@ -111,7 +108,7 @@ bool translate_init(std::string comma_delim_path_list, void updater_app_ui_init(void); void updater_app_quit(UpdaterAppState *app_state); void parse_args_and_init(int argc, char **argv, UpdaterAppState *app_state); -std::string next_image_filename(std::string& image_path, LLDirIterator& iter); +std::string next_image_filename(std::string& image_path); void display_error(GtkWidget *parent, std::string title, std::string message); BOOL install_package(std::string package_file, std::string destination); BOOL spawn_viewer(UpdaterAppState *app_state); @@ -177,7 +174,7 @@ void updater_app_ui_init(UpdaterAppState *app_state) // load the first image app_state->image = gtk_image_new_from_file - (next_image_filename(app_state->image_dir, *app_state->image_dir_iter).c_str()); + (next_image_filename(app_state->image_dir).c_str()); gtk_widget_set_size_request(app_state->image, 340, 310); gtk_container_add(GTK_CONTAINER(frame), app_state->image); @@ -208,7 +205,7 @@ gboolean rotate_image_cb(gpointer data) llassert(data != NULL); app_state = (UpdaterAppState *) data; - filename = next_image_filename(app_state->image_dir, *app_state->image_dir_iter); + filename = next_image_filename(app_state->image_dir); gdk_threads_enter(); gtk_image_set_from_file(GTK_IMAGE(app_state->image), filename.c_str()); @@ -217,10 +214,10 @@ gboolean rotate_image_cb(gpointer data) return TRUE; } -std::string next_image_filename(std::string& image_path, LLDirIterator& iter) +std::string next_image_filename(std::string& image_path) { std::string image_filename; - iter.next(image_filename); + gDirUtilp->getNextFileInDir(image_path, "/*.jpg", image_filename); return image_path + "/" + image_filename; } @@ -744,7 +741,6 @@ void parse_args_and_init(int argc, char **argv, UpdaterAppState *app_state) else if ((!strcmp(argv[i], "--image-dir")) && (++i < argc)) { app_state->image_dir = argv[i]; - app_state->image_dir_iter = new LLDirIterator(argv[i], "/*.jpg"); } else if ((!strcmp(argv[i], "--dest")) && (++i < argc)) { @@ -829,7 +825,6 @@ int main(int argc, char **argv) } bool success = !app_state->failure; - delete app_state->image_dir_iter; delete app_state; return success ? 0 : 1; } diff --git a/indra/llvfs/lldir.cpp b/indra/llvfs/lldir.cpp index ab7d15dfef..64556bcb4c 100644 --- a/indra/llvfs/lldir.cpp +++ b/indra/llvfs/lldir.cpp @@ -40,8 +40,6 @@ #include "lltimer.h" // ms_sleep() #include "lluuid.h" -#include "lldiriterator.h" - #if LL_WINDOWS #include "lldir_win32.h" LLDir_Win32 gDirUtil; @@ -85,9 +83,7 @@ S32 LLDir::deleteFilesInDir(const std::string &dirname, const std::string &mask) std::string filename; std::string fullpath; S32 result; - - LLDirIterator iter(dirname, mask); - while (iter.next(filename)) + while (getNextFileInDir(dirname, mask, filename)) { fullpath = dirname; fullpath += getDirDelimiter(); diff --git a/indra/llvfs/lldir.h b/indra/llvfs/lldir.h index 5ee8bdb542..42996fd051 100644 --- a/indra/llvfs/lldir.h +++ b/indra/llvfs/lldir.h @@ -75,6 +75,31 @@ class LLDir // pure virtual functions virtual U32 countFilesInDir(const std::string &dirname, const std::string &mask) = 0; + /// Walk the files in a directory, with file pattern matching + virtual BOOL getNextFileInDir(const std::string& dirname, ///< directory path - must end in trailing slash! + const std::string& mask, ///< file pattern string (use "*" for all) + std::string& fname ///< output: found file name + ) = 0; + /**< + * @returns true if a file was found, false if the entire directory has been scanned. + * + * @note that this function is NOT thread safe + * + * This function may not be used to scan part of a directory, then start a new search of a different + * directory, and then restart the first search where it left off; the entire search must run to + * completion or be abandoned - there is no restart. + * + * @bug: See http://jira.secondlife.com/browse/VWR-23697 + * and/or the tests in test/lldir_test.cpp + * This is known to fail with patterns that have both: + * a wildcard left of a . and more than one sequential ? right of a . + * the pattern foo.??x appears to work + * but *.??x or foo?.??x do not + * + * @todo this really should be rewritten as an iterator object, and the + * filtering should be done in a platform-independent way. + */ + virtual std::string getCurPath() = 0; virtual BOOL fileExists(const std::string &filename) const = 0; diff --git a/indra/llvfs/lldir_linux.cpp b/indra/llvfs/lldir_linux.cpp index 4ba2f519b0..73f2336f94 100644 --- a/indra/llvfs/lldir_linux.cpp +++ b/indra/llvfs/lldir_linux.cpp @@ -242,6 +242,68 @@ U32 LLDir_Linux::countFilesInDir(const std::string &dirname, const std::string & return (file_count); } +// get the next file in the directory +BOOL LLDir_Linux::getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname) +{ + glob_t g; + BOOL result = FALSE; + fname = ""; + + if(!(dirname == mCurrentDir)) + { + // different dir specified, close old search + mCurrentDirIndex = -1; + mCurrentDirCount = -1; + mCurrentDir = dirname; + } + + std::string tmp_str; + tmp_str = dirname; + tmp_str += mask; + + if(glob(tmp_str.c_str(), GLOB_NOSORT, NULL, &g) == 0) + { + if(g.gl_pathc > 0) + { + if((int)g.gl_pathc != mCurrentDirCount) + { + // Number of matches has changed since the last search, meaning a file has been added or deleted. + // Reset the index. + mCurrentDirIndex = -1; + mCurrentDirCount = g.gl_pathc; + } + + mCurrentDirIndex++; + + if(mCurrentDirIndex < (int)g.gl_pathc) + { +// llinfos << "getNextFileInDir: returning number " << mCurrentDirIndex << ", path is " << g.gl_pathv[mCurrentDirIndex] << llendl; + + // The API wants just the filename, not the full path. + //fname = g.gl_pathv[mCurrentDirIndex]; + + char *s = strrchr(g.gl_pathv[mCurrentDirIndex], '/'); + + if(s == NULL) + s = g.gl_pathv[mCurrentDirIndex]; + else if(s[0] == '/') + s++; + + fname = s; + + result = TRUE; + } + } + + globfree(&g); + } + + return(result); +} + + + + std::string LLDir_Linux::getCurPath() { char tmp_str[LL_MAX_PATH]; /* Flawfinder: ignore */ diff --git a/indra/llvfs/lldir_linux.h b/indra/llvfs/lldir_linux.h index ff4c48759a..451e81ae93 100644 --- a/indra/llvfs/lldir_linux.h +++ b/indra/llvfs/lldir_linux.h @@ -43,6 +43,7 @@ public: public: virtual std::string getCurPath(); virtual U32 countFilesInDir(const std::string &dirname, const std::string &mask); + virtual BOOL getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname); /*virtual*/ BOOL fileExists(const std::string &filename) const; /*virtual*/ std::string getLLPluginLauncher(); diff --git a/indra/llvfs/lldir_mac.cpp b/indra/llvfs/lldir_mac.cpp index 2d039527c0..445285aa43 100644 --- a/indra/llvfs/lldir_mac.cpp +++ b/indra/llvfs/lldir_mac.cpp @@ -258,6 +258,67 @@ U32 LLDir_Mac::countFilesInDir(const std::string &dirname, const std::string &ma return (file_count); } +// get the next file in the directory +BOOL LLDir_Mac::getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname) +{ + glob_t g; + BOOL result = FALSE; + fname = ""; + + if(!(dirname == mCurrentDir)) + { + // different dir specified, close old search + mCurrentDirIndex = -1; + mCurrentDirCount = -1; + mCurrentDir = dirname; + } + + std::string tmp_str; + tmp_str = dirname; + tmp_str += mask; + + if(glob(tmp_str.c_str(), GLOB_NOSORT, NULL, &g) == 0) + { + if(g.gl_pathc > 0) + { + if(g.gl_pathc != mCurrentDirCount) + { + // Number of matches has changed since the last search, meaning a file has been added or deleted. + // Reset the index. + mCurrentDirIndex = -1; + mCurrentDirCount = g.gl_pathc; + } + + mCurrentDirIndex++; + + if(mCurrentDirIndex < g.gl_pathc) + { +// llinfos << "getNextFileInDir: returning number " << mCurrentDirIndex << ", path is " << g.gl_pathv[mCurrentDirIndex] << llendl; + + // The API wants just the filename, not the full path. + //fname = g.gl_pathv[mCurrentDirIndex]; + + char *s = strrchr(g.gl_pathv[mCurrentDirIndex], '/'); + + if(s == NULL) + s = g.gl_pathv[mCurrentDirIndex]; + else if(s[0] == '/') + s++; + + fname = s; + + result = TRUE; + } + } + + globfree(&g); + } + + return(result); +} + + + S32 LLDir_Mac::deleteFilesInDir(const std::string &dirname, const std::string &mask) { glob_t g; diff --git a/indra/llvfs/lldir_mac.h b/indra/llvfs/lldir_mac.h index e60d5e41c2..4eac3c3ae6 100644 --- a/indra/llvfs/lldir_mac.h +++ b/indra/llvfs/lldir_mac.h @@ -43,6 +43,7 @@ public: virtual S32 deleteFilesInDir(const std::string &dirname, const std::string &mask); virtual std::string getCurPath(); virtual U32 countFilesInDir(const std::string &dirname, const std::string &mask); + virtual BOOL getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname); virtual BOOL fileExists(const std::string &filename) const; /*virtual*/ std::string getLLPluginLauncher(); diff --git a/indra/llvfs/lldir_solaris.cpp b/indra/llvfs/lldir_solaris.cpp index 21f8c3acdb..515fd66b6e 100644 --- a/indra/llvfs/lldir_solaris.cpp +++ b/indra/llvfs/lldir_solaris.cpp @@ -260,6 +260,68 @@ U32 LLDir_Solaris::countFilesInDir(const std::string &dirname, const std::string return (file_count); } +// get the next file in the directory +BOOL LLDir_Solaris::getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname) +{ + glob_t g; + BOOL result = FALSE; + fname = ""; + + if(!(dirname == mCurrentDir)) + { + // different dir specified, close old search + mCurrentDirIndex = -1; + mCurrentDirCount = -1; + mCurrentDir = dirname; + } + + std::string tmp_str; + tmp_str = dirname; + tmp_str += mask; + + if(glob(tmp_str.c_str(), GLOB_NOSORT, NULL, &g) == 0) + { + if(g.gl_pathc > 0) + { + if((int)g.gl_pathc != mCurrentDirCount) + { + // Number of matches has changed since the last search, meaning a file has been added or deleted. + // Reset the index. + mCurrentDirIndex = -1; + mCurrentDirCount = g.gl_pathc; + } + + mCurrentDirIndex++; + + if(mCurrentDirIndex < (int)g.gl_pathc) + { +// llinfos << "getNextFileInDir: returning number " << mCurrentDirIndex << ", path is " << g.gl_pathv[mCurrentDirIndex] << llendl; + + // The API wants just the filename, not the full path. + //fname = g.gl_pathv[mCurrentDirIndex]; + + char *s = strrchr(g.gl_pathv[mCurrentDirIndex], '/'); + + if(s == NULL) + s = g.gl_pathv[mCurrentDirIndex]; + else if(s[0] == '/') + s++; + + fname = s; + + result = TRUE; + } + } + + globfree(&g); + } + + return(result); +} + + + + std::string LLDir_Solaris::getCurPath() { char tmp_str[LL_MAX_PATH]; /* Flawfinder: ignore */ diff --git a/indra/llvfs/lldir_solaris.h b/indra/llvfs/lldir_solaris.h index f7e1a6301d..4a1794f539 100644 --- a/indra/llvfs/lldir_solaris.h +++ b/indra/llvfs/lldir_solaris.h @@ -43,6 +43,7 @@ public: public: virtual std::string getCurPath(); virtual U32 countFilesInDir(const std::string &dirname, const std::string &mask); + virtual BOOL getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname); /*virtual*/ BOOL fileExists(const std::string &filename) const; private: diff --git a/indra/llvfs/lldir_win32.cpp b/indra/llvfs/lldir_win32.cpp index 2f96fbbbc1..33718e520d 100644 --- a/indra/llvfs/lldir_win32.cpp +++ b/indra/llvfs/lldir_win32.cpp @@ -236,6 +236,67 @@ U32 LLDir_Win32::countFilesInDir(const std::string &dirname, const std::string & return (file_count); } + +// get the next file in the directory +BOOL LLDir_Win32::getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname) +{ + BOOL fileFound = FALSE; + fname = ""; + + WIN32_FIND_DATAW FileData; + llutf16string pathname = utf8str_to_utf16str(dirname) + utf8str_to_utf16str(mask); + + if (pathname != mCurrentDir) + { + // different dir specified, close old search + if (mCurrentDir[0]) + { + FindClose(mDirSearch_h); + } + mCurrentDir = pathname; + + // and open new one + // Check error opening Directory structure + if ((mDirSearch_h = FindFirstFile(pathname.c_str(), &FileData)) != INVALID_HANDLE_VALUE) + { + fileFound = TRUE; + } + } + + // Loop to skip over the current (.) and parent (..) directory entries + // (apparently returned in Win7 but not XP) + do + { + if ( fileFound + && ( (lstrcmp(FileData.cFileName, (LPCTSTR)TEXT(".")) == 0) + ||(lstrcmp(FileData.cFileName, (LPCTSTR)TEXT("..")) == 0) + ) + ) + { + fileFound = FALSE; + } + } while ( mDirSearch_h != INVALID_HANDLE_VALUE + && !fileFound + && (fileFound = FindNextFile(mDirSearch_h, &FileData) + ) + ); + + if (!fileFound && GetLastError() == ERROR_NO_MORE_FILES) + { + // No more files, so reset to beginning of directory + FindClose(mDirSearch_h); + mCurrentDir[0] = '\000'; + } + + if (fileFound) + { + // convert from TCHAR to char + fname = utf16str_to_utf8str(FileData.cFileName); + } + + return fileFound; +} + std::string LLDir_Win32::getCurPath() { WCHAR w_str[MAX_PATH]; diff --git a/indra/llvfs/lldir_win32.h b/indra/llvfs/lldir_win32.h index 19c610eb8b..4c932c932c 100644 --- a/indra/llvfs/lldir_win32.h +++ b/indra/llvfs/lldir_win32.h @@ -40,12 +40,15 @@ public: /*virtual*/ std::string getCurPath(); /*virtual*/ U32 countFilesInDir(const std::string &dirname, const std::string &mask); + /*virtual*/ BOOL getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname); /*virtual*/ BOOL fileExists(const std::string &filename) const; /*virtual*/ std::string getLLPluginLauncher(); /*virtual*/ std::string getLLPluginFilename(std::string base_name); private: + BOOL LLDir_Win32::getNextFileInDir(const llutf16string &dirname, const std::string &mask, std::string &fname); + void* mDirSearch_h; llutf16string mCurrentDir; }; diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index f0711db3bd..729f83a2b1 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -89,7 +89,6 @@ // Linden library includes #include "llavatarnamecache.h" -#include "lldiriterator.h" #include "llimagej2c.h" #include "llmemory.h" #include "llprimitive.h" @@ -3292,9 +3291,7 @@ void LLAppViewer::migrateCacheDirectory() S32 file_count = 0; std::string file_name; std::string mask = delimiter + "*.*"; - - LLDirIterator iter(old_cache_dir, mask); - while (iter.next(file_name)) + while (gDirUtilp->getNextFileInDir(old_cache_dir, mask, file_name)) { if (file_name == "." || file_name == "..") continue; std::string source_path = old_cache_dir + delimiter + file_name; @@ -3513,8 +3510,7 @@ bool LLAppViewer::initCache() dir = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,""); std::string found_file; - LLDirIterator iter(dir, mask); - if (iter.next(found_file)) + if (gDirUtilp->getNextFileInDir(dir, mask, found_file)) { old_vfs_data_file = dir + gDirUtilp->getDirDelimiter() + found_file; diff --git a/indra/newview/llappviewerlinux.cpp b/indra/newview/llappviewerlinux.cpp index fc7a27e5e0..898cc1c0ba 100644 --- a/indra/newview/llappviewerlinux.cpp +++ b/indra/newview/llappviewerlinux.cpp @@ -30,7 +30,6 @@ #include "llcommandlineparser.h" -#include "lldiriterator.h" #include "llmemtype.h" #include "llurldispatcher.h" // SLURL from other app instance #include "llviewernetwork.h" @@ -505,9 +504,7 @@ std::string LLAppViewerLinux::generateSerialNumber() // trawl /dev/disk/by-uuid looking for a good-looking UUID to grab std::string this_name; - - LLDirIterator iter(uuiddir, "*"); - while (iter.next(this_name)) + while (gDirUtilp->getNextFileInDir(uuiddir, "*", this_name)) { if (this_name.length() > best.length() || (this_name.length() == best.length() && diff --git a/indra/newview/llfloateruipreview.cpp b/indra/newview/llfloateruipreview.cpp index 182d3d23f1..11b3379814 100644 --- a/indra/newview/llfloateruipreview.cpp +++ b/indra/newview/llfloateruipreview.cpp @@ -35,7 +35,6 @@ #include "llfloateruipreview.h" // Own header // Internal utility -#include "lldiriterator.h" #include "lleventtimer.h" #include "llexternaleditor.h" #include "llrender.h" @@ -482,11 +481,9 @@ BOOL LLFloaterUIPreview::postBuild() std::string language_directory; std::string xui_dir = get_xui_dir(); // directory containing localizations -- don't forget trailing delim mLanguageSelection->removeall(); // clear out anything temporarily in list from XML - - LLDirIterator iter(xui_dir, "*"); while(found) // for every directory { - if((found = iter.next(language_directory))) // get next directory + if((found = gDirUtilp->getNextFileInDir(xui_dir, "*", language_directory))) // get next directory { std::string full_path = xui_dir + language_directory; if(LLFile::isfile(full_path.c_str())) // if it's not a directory, skip it @@ -638,51 +635,42 @@ void LLFloaterUIPreview::refreshList() mFileList->clearRows(); // empty list std::string name; BOOL found = TRUE; - - LLDirIterator floater_iter(getLocalizedDirectory(), "floater_*.xml"); while(found) // for every floater file that matches the pattern { - if((found = floater_iter.next(name))) // get next file matching pattern + if((found = gDirUtilp->getNextFileInDir(getLocalizedDirectory(), "floater_*.xml", name))) // get next file matching pattern { addFloaterEntry(name.c_str()); // and add it to the list (file name only; localization code takes care of rest of path) } } found = TRUE; - - LLDirIterator inspect_iter(getLocalizedDirectory(), "inspect_*.xml"); while(found) // for every inspector file that matches the pattern { - if((found = inspect_iter.next(name))) // get next file matching pattern + if((found = gDirUtilp->getNextFileInDir(getLocalizedDirectory(), "inspect_*.xml", name))) // get next file matching pattern { addFloaterEntry(name.c_str()); // and add it to the list (file name only; localization code takes care of rest of path) } } found = TRUE; - - LLDirIterator menu_iter(getLocalizedDirectory(), "menu_*.xml"); while(found) // for every menu file that matches the pattern { - if((found = menu_iter.next(name))) // get next file matching pattern + if((found = gDirUtilp->getNextFileInDir(getLocalizedDirectory(), "menu_*.xml", name))) // get next file matching pattern { addFloaterEntry(name.c_str()); // and add it to the list (file name only; localization code takes care of rest of path) } } found = TRUE; - - LLDirIterator panel_iter(getLocalizedDirectory(), "panel_*.xml"); while(found) // for every panel file that matches the pattern { - if((found = panel_iter.next(name))) // get next file matching pattern + if((found = gDirUtilp->getNextFileInDir(getLocalizedDirectory(), "panel_*.xml", name))) // get next file matching pattern { addFloaterEntry(name.c_str()); // and add it to the list (file name only; localization code takes care of rest of path) } } - found = TRUE; - LLDirIterator sidepanel_iter(getLocalizedDirectory(), "sidepanel_*.xml"); + found = TRUE; while(found) // for every sidepanel file that matches the pattern { - if((found = sidepanel_iter.next(name))) // get next file matching pattern + if((found = gDirUtilp->getNextFileInDir(getLocalizedDirectory(), "sidepanel_*.xml", name))) // get next file matching pattern { addFloaterEntry(name.c_str()); // and add it to the list (file name only; localization code takes care of rest of path) } diff --git a/indra/newview/lllogchat.cpp b/indra/newview/lllogchat.cpp index b09cfbe907..9adf374c71 100644 --- a/indra/newview/lllogchat.cpp +++ b/indra/newview/lllogchat.cpp @@ -32,7 +32,6 @@ #include "lltrans.h" #include "llviewercontrol.h" -#include "lldiriterator.h" #include "llinstantmessage.h" #include "llsingleton.h" // for LLSingleton @@ -602,8 +601,7 @@ std::string LLLogChat::oldLogFileName(std::string filename) //LL_INFOS("") << "Checking:" << directory << " for " << pattern << LL_ENDL;/* uncomment if you want to verify step, delete on commit */ std::vector allfiles; - LLDirIterator iter(directory, pattern); - while (iter.next(scanResult)) + while (gDirUtilp->getNextFileInDir(directory, pattern, scanResult)) { //LL_INFOS("") << "Found :" << scanResult << LL_ENDL; allfiles.push_back(scanResult); diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 8a0d0a6623..d3b6dcd86f 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -54,7 +54,6 @@ #include "llfilepicker.h" #include "llnotifications.h" -#include "lldiriterator.h" #include "llevent.h" // LLSimpleListener #include "llnotificationsutil.h" #include "lluuid.h" @@ -1116,8 +1115,7 @@ void LLViewerMedia::clearAllCookies() } // the hard part: iterate over all user directories and delete the cookie file from each one - LLDirIterator dir_iter(base_dir, "*_*"); - while (dir_iter.next(filename)) + while(gDirUtilp->getNextFileInDir(base_dir, "*_*", filename)) { target = base_dir; target += filename; diff --git a/indra/newview/llwaterparammanager.cpp b/indra/newview/llwaterparammanager.cpp index 4f6ec4ca61..d239347810 100644 --- a/indra/newview/llwaterparammanager.cpp +++ b/indra/newview/llwaterparammanager.cpp @@ -33,7 +33,6 @@ #include "pipeline.h" #include "llsky.h" -#include "lldiriterator.h" #include "llfloaterreg.h" #include "llsliderctrl.h" #include "llspinctrl.h" @@ -86,12 +85,11 @@ void LLWaterParamManager::loadAllPresets(const std::string& file_name) std::string path_name(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight/water", "")); LL_DEBUGS2("AppInit", "Shaders") << "Loading Default water settings from " << path_name << LL_ENDL; - bool found = true; - LLDirIterator app_settings_iter(path_name, "*.xml"); + bool found = true; while(found) { std::string name; - found = app_settings_iter.next(name); + found = gDirUtilp->getNextFileInDir(path_name, "*.xml", name); if(found) { @@ -113,12 +111,11 @@ void LLWaterParamManager::loadAllPresets(const std::string& file_name) std::string path_name2(gDirUtilp->getExpandedFilename( LL_PATH_USER_SETTINGS , "windlight/water", "")); LL_DEBUGS2("AppInit", "Shaders") << "Loading User water settings from " << path_name2 << LL_ENDL; - found = true; - LLDirIterator user_settings_iter(path_name2, "*.xml"); + found = true; while(found) { std::string name; - found = user_settings_iter.next(name); + found = gDirUtilp->getNextFileInDir(path_name2, "*.xml", name); if(found) { name=name.erase(name.length()-4); diff --git a/indra/newview/llwlparammanager.cpp b/indra/newview/llwlparammanager.cpp index 848efcbb49..e5f52dfc97 100644 --- a/indra/newview/llwlparammanager.cpp +++ b/indra/newview/llwlparammanager.cpp @@ -31,7 +31,6 @@ #include "pipeline.h" #include "llsky.h" -#include "lldiriterator.h" #include "llfloaterreg.h" #include "llsliderctrl.h" #include "llspinctrl.h" @@ -101,12 +100,11 @@ void LLWLParamManager::loadPresets(const std::string& file_name) std::string path_name(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight/skies", "")); LL_DEBUGS2("AppInit", "Shaders") << "Loading Default WindLight settings from " << path_name << LL_ENDL; - bool found = true; - LLDirIterator app_settings_iter(path_name, "*.xml"); + bool found = true; while(found) { std::string name; - found = app_settings_iter.next(name); + found = gDirUtilp->getNextFileInDir(path_name, "*.xml", name); if(found) { @@ -128,12 +126,11 @@ void LLWLParamManager::loadPresets(const std::string& file_name) std::string path_name2(gDirUtilp->getExpandedFilename( LL_PATH_USER_SETTINGS , "windlight/skies", "")); LL_DEBUGS2("AppInit", "Shaders") << "Loading User WindLight settings from " << path_name2 << LL_ENDL; - found = true; - LLDirIterator user_settings_iter(path_name2, "*.xml"); + found = true; while(found) { std::string name; - found = user_settings_iter.next(name); + found = gDirUtilp->getNextFileInDir(path_name2, "*.xml", name); if(found) { name=name.erase(name.length()-4); diff --git a/indra/viewer_components/updater/tests/llupdaterservice_test.cpp b/indra/viewer_components/updater/tests/llupdaterservice_test.cpp index e19d5724f1..88ab5a2284 100644 --- a/indra/viewer_components/updater/tests/llupdaterservice_test.cpp +++ b/indra/viewer_components/updater/tests/llupdaterservice_test.cpp @@ -59,6 +59,12 @@ class LLDir_Mock : public LLDir return 0; } + BOOL getNextFileInDir(const std::string &dirname, + const std::string &mask, + std::string &fname) + { + return false; + } void getRandomFileInDir(const std::string &dirname, const std::string &mask, std::string &fname) {} -- cgit v1.2.3 From a4e775e54cd1ae3f5be80e73eef6b629384a00c5 Mon Sep 17 00:00:00 2001 From: Merov Linden Date: Thu, 13 Jan 2011 11:17:04 -0800 Subject: STORM-477 : backout changeset 959f9340da92 --- indra/cmake/Boost.cmake | 18 ---- indra/llvfs/CMakeLists.txt | 7 -- indra/llvfs/lldiriterator.cpp | 203 --------------------------------------- indra/llvfs/lldiriterator.h | 87 ----------------- indra/llvfs/tests/lldir_test.cpp | 38 +++----- 5 files changed, 15 insertions(+), 338 deletions(-) delete mode 100644 indra/llvfs/lldiriterator.cpp delete mode 100644 indra/llvfs/lldiriterator.h diff --git a/indra/cmake/Boost.cmake b/indra/cmake/Boost.cmake index 012d3c2ab2..7ce57a5572 100644 --- a/indra/cmake/Boost.cmake +++ b/indra/cmake/Boost.cmake @@ -10,8 +10,6 @@ if (STANDALONE) set(BOOST_PROGRAM_OPTIONS_LIBRARY boost_program_options-mt) set(BOOST_REGEX_LIBRARY boost_regex-mt) set(BOOST_SIGNALS_LIBRARY boost_signals-mt) - set(BOOST_SYSTEM_LIBRARY boost_system-mt) - set(BOOST_FILESYSTEM_LIBRARY boost_filesystem-mt) else (STANDALONE) use_prebuilt_binary(boost) set(Boost_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include) @@ -28,12 +26,6 @@ else (STANDALONE) set(BOOST_SIGNALS_LIBRARY optimized libboost_signals-vc71-mt-s-${BOOST_VERSION} debug libboost_signals-vc71-mt-sgd-${BOOST_VERSION}) - set(BOOST_SYSTEM_LIBRARY - optimized libboost_system-vc71-mt-s-${BOOST_VERSION} - debug libboost_system-vc71-mt-sgd-${BOOST_VERSION}) - set(BOOST_FILESYSTEM_LIBRARY - optimized libboost_filesystem-vc71-mt-s-${BOOST_VERSION} - debug libboost_filesystem-vc71-mt-sgd-${BOOST_VERSION}) else (MSVC71) set(BOOST_PROGRAM_OPTIONS_LIBRARY optimized libboost_program_options-vc80-mt-${BOOST_VERSION} @@ -44,24 +36,14 @@ else (STANDALONE) set(BOOST_SIGNALS_LIBRARY optimized libboost_signals-vc80-mt-${BOOST_VERSION} debug libboost_signals-vc80-mt-gd-${BOOST_VERSION}) - set(BOOST_SYSTEM_LIBRARY - optimized libboost_system-vc80-mt-${BOOST_VERSION} - debug libboost_system-vc80-mt-gd-${BOOST_VERSION}) - set(BOOST_FILESYSTEM_LIBRARY - optimized libboost_filesystem-vc80-mt-${BOOST_VERSION} - debug libboost_filesystem-vc80-mt-gd-${BOOST_VERSION}) endif (MSVC71) elseif (DARWIN) set(BOOST_PROGRAM_OPTIONS_LIBRARY boost_program_options-xgcc40-mt) set(BOOST_REGEX_LIBRARY boost_regex-xgcc40-mt) set(BOOST_SIGNALS_LIBRARY boost_signals-xgcc40-mt) - set(BOOST_SYSTEM_LIBRARY boost_system-xgcc40-mt) - set(BOOST_FILESYSTEM_LIBRARY boost_filesystem-xgcc40-mt) elseif (LINUX) set(BOOST_PROGRAM_OPTIONS_LIBRARY boost_program_options-gcc41-mt) set(BOOST_REGEX_LIBRARY boost_regex-gcc41-mt) set(BOOST_SIGNALS_LIBRARY boost_signals-gcc41-mt) - set(BOOST_SYSTEM_LIBRARY boost_system-gcc41-mt) - set(BOOST_FILESYSTEM_LIBRARY boost_filesystem-gcc41-mt) endif (WINDOWS) endif (STANDALONE) diff --git a/indra/llvfs/CMakeLists.txt b/indra/llvfs/CMakeLists.txt index a3782d824b..722f4e2bfd 100644 --- a/indra/llvfs/CMakeLists.txt +++ b/indra/llvfs/CMakeLists.txt @@ -12,7 +12,6 @@ include_directories( set(llvfs_SOURCE_FILES lldir.cpp - lldiriterator.cpp lllfsthread.cpp llpidlock.cpp llvfile.cpp @@ -25,7 +24,6 @@ set(llvfs_HEADER_FILES lldir.h lldirguard.h - lldiriterator.h lllfsthread.h llpidlock.h llvfile.h @@ -62,11 +60,6 @@ list(APPEND llvfs_SOURCE_FILES ${llvfs_HEADER_FILES}) add_library (llvfs ${llvfs_SOURCE_FILES}) -target_link_libraries(llvfs - ${BOOST_FILESYSTEM_LIBRARY} - ${BOOST_SYSTEM_LIBRARY} - ) - if (DARWIN) include(CMakeFindFrameworks) find_library(CARBON_LIBRARY Carbon) diff --git a/indra/llvfs/lldiriterator.cpp b/indra/llvfs/lldiriterator.cpp deleted file mode 100644 index 5536ed8f69..0000000000 --- a/indra/llvfs/lldiriterator.cpp +++ /dev/null @@ -1,203 +0,0 @@ -/** - * @file lldiriterator.cpp - * @brief Iterator through directory entries matching the search pattern. - * - * $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 "lldiriterator.h" - -#include -#include - -namespace fs = boost::filesystem; - -static std::string glob_to_regex(const std::string& glob); - -class LLDirIterator::Impl -{ -public: - Impl(const std::string &dirname, const std::string &mask); - ~Impl(); - - bool next(std::string &fname); - -private: - boost::regex mFilterExp; - fs::directory_iterator mIter; - bool mIsValid; -}; - -LLDirIterator::Impl::Impl(const std::string &dirname, const std::string &mask) - : mIsValid(false) -{ - fs::path dir_path(dirname); - - // Check if path exists. - if (!fs::exists(dir_path)) - { - llerrs << "Invalid path: \"" << dir_path.string() << "\"" << llendl; - return; - } - - // Initialize the directory iterator for the given path. - try - { - mIter = fs::directory_iterator(dir_path); - } - catch (fs::basic_filesystem_error& e) - { - llerrs << e.what() << llendl; - return; - } - - // Convert the glob mask to a regular expression - std::string exp = glob_to_regex(mask); - - // Initialize boost::regex with the expression converted from - // the glob mask. - // An exception is thrown if the expression is not valid. - try - { - mFilterExp.assign(exp); - } - catch (boost::regex_error& e) - { - llerrs << "\"" << exp << "\" is not a valid regular expression: " - << e.what() << llendl; - return; - } - - mIsValid = true; -} - -LLDirIterator::Impl::~Impl() -{ -} - -bool LLDirIterator::Impl::next(std::string &fname) -{ - fname = ""; - - if (!mIsValid) - { - llerrs << "The iterator is not correctly initialized." << llendl; - return false; - } - - fs::directory_iterator end_itr; // default construction yields past-the-end - bool found = false; - while (mIter != end_itr && !found) - { - boost::smatch match; - std::string name = mIter->path().filename(); - if (found = boost::regex_match(name, match, mFilterExp)) - { - fname = name; - } - - ++mIter; - } - - return found; -} - -std::string glob_to_regex(const std::string& glob) -{ - std::string regex; - regex.reserve(glob.size()<<1); - S32 braces = 0; - bool escaped = false; - bool square_brace_open = false; - - for (std::string::const_iterator i = glob.begin(); i != glob.end(); ++i) - { - char c = *i; - - switch (c) - { - case '.': - regex+="\\."; - break; - case '*': - if (glob.begin() == i) - { - regex+="[^.].*"; - } - else - { - regex+= escaped ? "*" : ".*"; - } - break; - case '?': - regex+= escaped ? '?' : '.'; - break; - case '{': - braces++; - regex+='('; - break; - case '}': - if (!braces) - { - llerrs << "glob_to_regex: Closing brace without an equivalent opening brace: " << glob << llendl; - } - - regex+=')'; - braces--; - break; - case ',': - regex+= braces ? '|' : c; - break; - case '!': - regex+= square_brace_open ? '^' : c; - break; - default: - regex+=c; - break; - } - - escaped = ('\\' == c); - square_brace_open = ('[' == c); - } - - if (braces) - { - llerrs << "glob_to_regex: Unterminated brace expression: " << glob << llendl; - } - - return regex; -} - -LLDirIterator::LLDirIterator(const std::string &dirname, const std::string &mask) -{ - mImpl = new Impl(dirname, mask); -} - -LLDirIterator::~LLDirIterator() -{ - delete mImpl; -} - -bool LLDirIterator::next(std::string &fname) -{ - return mImpl->next(fname); -} diff --git a/indra/llvfs/lldiriterator.h b/indra/llvfs/lldiriterator.h deleted file mode 100644 index 0b48be41b3..0000000000 --- a/indra/llvfs/lldiriterator.h +++ /dev/null @@ -1,87 +0,0 @@ -/** - * @file lldiriterator.h - * @brief Iterator through directory entries matching the search pattern. - * - * $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_LLDIRITERATOR_H -#define LL_LLDIRITERATOR_H - -#include "linden_common.h" - -/** - * Class LLDirIterator - * - * Iterates through directory entries matching the search pattern. - */ -class LLDirIterator -{ -public: - /** - * Constructs LLDirIterator object to search for glob pattern - * matches in a directory. - * - * @param dirname - name of a directory to search in. - * @param mask - search pattern, a glob expression - * - * Wildcards supported in glob expressions: - * -------------------------------------------------------------- - * | Wildcard | Matches | - * -------------------------------------------------------------- - * | * |zero or more characters | - * | ? |exactly one character | - * | [abcde] |exactly one character listed | - * | [a-e] |exactly one character in the given range | - * | [!abcde] |any character that is not listed | - * | [!a-e] |any character that is not in the given range | - * | {abc,xyz} |exactly one entire word in the options given | - * -------------------------------------------------------------- - */ - LLDirIterator(const std::string &dirname, const std::string &mask); - - ~LLDirIterator(); - - /** - * Searches for the next directory entry matching the glob mask - * specified upon iterator construction. - * Returns true if a match is found, sets fname - * parameter to the name of the matched directory entry and - * increments the iterator position. - * - * Typical usage: - * - * LLDirIterator iter(directory, pattern); - * if ( iter.next(scanResult) ) - * - * - * @param fname - name of the matched directory entry. - * @return true if a match is found, false otherwise. - */ - bool next(std::string &fname); - -protected: - class Impl; - Impl* mImpl; -}; - -#endif //LL_LLDIRITERATOR_H diff --git a/indra/llvfs/tests/lldir_test.cpp b/indra/llvfs/tests/lldir_test.cpp index ea321c5ae9..8788bd63e8 100644 --- a/indra/llvfs/tests/lldir_test.cpp +++ b/indra/llvfs/tests/lldir_test.cpp @@ -28,7 +28,6 @@ #include "linden_common.h" #include "../lldir.h" -#include "../lldiriterator.h" #include "../test/lltut.h" @@ -260,12 +259,13 @@ namespace tut std::string makeTestFile( const std::string& dir, const std::string& file ) { - std::string path = dir + file; + std::string delim = gDirUtilp->getDirDelimiter(); + std::string path = dir + delim + file; LLFILE* handle = LLFile::fopen( path, "w" ); ensure("failed to open test file '"+path+"'", handle != NULL ); // Harbison & Steele, 4th ed., p. 366: "If an error occurs, fputs // returns EOF; otherwise, it returns some other, nonnegative value." - ensure("failed to write to test file '"+path+"'", EOF != fputs("test file", handle) ); + ensure("failed to write to test file '"+path+"'", fputs("test file", handle) >= 0); fclose(handle); return path; } @@ -290,7 +290,7 @@ namespace tut } static const char* DirScanFilename[5] = { "file1.abc", "file2.abc", "file1.xyz", "file2.xyz", "file1.mno" }; - + void scanTest(const std::string& directory, const std::string& pattern, bool correctResult[5]) { @@ -300,8 +300,7 @@ namespace tut bool filesFound[5] = { false, false, false, false, false }; //std::cerr << "searching '"+directory+"' for '"+pattern+"'\n"; - LLDirIterator iter(directory, pattern); - while ( found <= 5 && iter.next(scanResult) ) + while ( found <= 5 && gDirUtilp->getNextFileInDir(directory, pattern, scanResult) ) { found++; //std::cerr << " found '"+scanResult+"'\n"; @@ -335,15 +334,15 @@ namespace tut template<> template<> void LLDirTest_object_t::test<5>() - // LLDirIterator::next + // getNextFileInDir { std::string delim = gDirUtilp->getDirDelimiter(); std::string dirTemp = LLFile::tmpdir(); // Create the same 5 file names of the two directories - std::string dir1 = makeTestDir(dirTemp + "LLDirIterator"); - std::string dir2 = makeTestDir(dirTemp + "LLDirIterator"); + std::string dir1 = makeTestDir(dirTemp + "getNextFileInDir"); + std::string dir2 = makeTestDir(dirTemp + "getNextFileInDir"); std::string dir1files[5]; std::string dir2files[5]; for (int i=0; i<5; i++) @@ -381,17 +380,19 @@ namespace tut scanTest(dir2, "file?.x?z", expected7); // Scan dir2 and see if any file?.??c files are found - bool expected8[5] = { true, true, false, false, false }; - scanTest(dir2, "file?.??c", expected8); - scanTest(dir2, "*.??c", expected8); + // THESE FAIL ON Mac and Windows, SO ARE COMMENTED OUT FOR NOW + // bool expected8[5] = { true, true, false, false, false }; + // scanTest(dir2, "file?.??c", expected8); + // scanTest(dir2, "*.??c", expected8); // Scan dir1 and see if any *.?n? files are found bool expected9[5] = { false, false, false, false, true }; scanTest(dir1, "*.?n?", expected9); // Scan dir1 and see if any *.???? files are found - bool expected10[5] = { false, false, false, false, false }; - scanTest(dir1, "*.????", expected10); + // THIS ONE FAILS ON WINDOWS (returns three charater suffixes) SO IS COMMENTED OUT FOR NOW + // bool expected10[5] = { false, false, false, false, false }; + // scanTest(dir1, "*.????", expected10); // Scan dir1 and see if any ?????.* files are found bool expected11[5] = { true, true, true, true, true }; @@ -401,15 +402,6 @@ namespace tut bool expected12[5] = { false, false, true, true, false }; scanTest(dir1, "??l??.xyz", expected12); - bool expected13[5] = { true, false, true, false, false }; - scanTest(dir1, "file1.{abc,xyz}", expected13); - - bool expected14[5] = { true, true, false, false, false }; - scanTest(dir1, "file[0-9].abc", expected14); - - bool expected15[5] = { true, true, false, false, false }; - scanTest(dir1, "file[!a-z].abc", expected15); - // clean up all test files and directories for (int i=0; i<5; i++) { -- cgit v1.2.3 From 20b983afe0d7f66a1db036c60e4c53b6141eb0cd Mon Sep 17 00:00:00 2001 From: Joshua Bell Date: Thu, 13 Jan 2011 11:52:58 -0800 Subject: VWR-24401 Show TOS and other login dialogs when --login is used --- indra/newview/lllogininstance.cpp | 94 ++++++++++++++++++--------------------- indra/newview/lllogininstance.h | 7 --- indra/newview/llstartup.cpp | 1 - 3 files changed, 43 insertions(+), 59 deletions(-) diff --git a/indra/newview/lllogininstance.cpp b/indra/newview/lllogininstance.cpp index d866db1829..f93bfb61d3 100644 --- a/indra/newview/lllogininstance.cpp +++ b/indra/newview/lllogininstance.cpp @@ -468,7 +468,6 @@ LLLoginInstance::LLLoginInstance() : mLoginModule(new LLLogin()), mNotifications(NULL), mLoginState("offline"), - mUserInteraction(true), mSkipOptionalUpdate(false), mAttemptComplete(false), mTransferRate(0.0f), @@ -637,64 +636,57 @@ void LLLoginInstance::handleLoginFailure(const LLSD& event) LLSD response = event["data"]; std::string reason_response = response["reason"].asString(); std::string message_response = response["message"].asString(); - if(mUserInteraction) + // For the cases of critical message or TOS agreement, + // start the TOS dialog. The dialog response will be handled + // by the LLLoginInstance::handleTOSResponse() callback. + // The callback intiates the login attempt next step, either + // to reconnect or to end the attempt in failure. + if(reason_response == "tos") { - // For the cases of critical message or TOS agreement, - // start the TOS dialog. The dialog response will be handled - // by the LLLoginInstance::handleTOSResponse() callback. - // The callback intiates the login attempt next step, either - // to reconnect or to end the attempt in failure. - if(reason_response == "tos") - { - LLSD data(LLSD::emptyMap()); - data["message"] = message_response; - data["reply_pump"] = TOS_REPLY_PUMP; - gViewerWindow->setShowProgress(FALSE); - LLFloaterReg::showInstance("message_tos", data); - LLEventPumps::instance().obtain(TOS_REPLY_PUMP) - .listen(TOS_LISTENER_NAME, - boost::bind(&LLLoginInstance::handleTOSResponse, - this, _1, "agree_to_tos")); - } - else if(reason_response == "critical") - { - LLSD data(LLSD::emptyMap()); - data["message"] = message_response; - data["reply_pump"] = TOS_REPLY_PUMP; - if(response.has("error_code")) - { - data["error_code"] = response["error_code"]; - } - if(response.has("certificate")) - { - data["certificate"] = response["certificate"]; - } - - gViewerWindow->setShowProgress(FALSE); - LLFloaterReg::showInstance("message_critical", data); - LLEventPumps::instance().obtain(TOS_REPLY_PUMP) - .listen(TOS_LISTENER_NAME, - boost::bind(&LLLoginInstance::handleTOSResponse, - this, _1, "read_critical")); - } - else if(reason_response == "update" || gSavedSettings.getBOOL("ForceMandatoryUpdate")) + LLSD data(LLSD::emptyMap()); + data["message"] = message_response; + data["reply_pump"] = TOS_REPLY_PUMP; + gViewerWindow->setShowProgress(FALSE); + LLFloaterReg::showInstance("message_tos", data); + LLEventPumps::instance().obtain(TOS_REPLY_PUMP) + .listen(TOS_LISTENER_NAME, + boost::bind(&LLLoginInstance::handleTOSResponse, + this, _1, "agree_to_tos")); + } + else if(reason_response == "critical") + { + LLSD data(LLSD::emptyMap()); + data["message"] = message_response; + data["reply_pump"] = TOS_REPLY_PUMP; + if(response.has("error_code")) { - gSavedSettings.setBOOL("ForceMandatoryUpdate", FALSE); - updateApp(true, message_response); + data["error_code"] = response["error_code"]; } - else if(reason_response == "optional") + if(response.has("certificate")) { - updateApp(false, message_response); + data["certificate"] = response["certificate"]; } - else - { - attemptComplete(); - } + + gViewerWindow->setShowProgress(FALSE); + LLFloaterReg::showInstance("message_critical", data); + LLEventPumps::instance().obtain(TOS_REPLY_PUMP) + .listen(TOS_LISTENER_NAME, + boost::bind(&LLLoginInstance::handleTOSResponse, + this, _1, "read_critical")); } - else // no user interaction + else if(reason_response == "update" || gSavedSettings.getBOOL("ForceMandatoryUpdate")) { - attemptComplete(); + gSavedSettings.setBOOL("ForceMandatoryUpdate", FALSE); + updateApp(true, message_response); + } + else if(reason_response == "optional") + { + updateApp(false, message_response); } + else + { + attemptComplete(); + } } void LLLoginInstance::handleLoginSuccess(const LLSD& event) diff --git a/indra/newview/lllogininstance.h b/indra/newview/lllogininstance.h index b872d7d1b1..8b53431219 100644 --- a/indra/newview/lllogininstance.h +++ b/indra/newview/lllogininstance.h @@ -61,12 +61,6 @@ public: // Only valid when authSuccess == true. const F64 getLastTransferRateBPS() { return mTransferRate; } - // Set whether this class will drive user interaction. - // If not, login failures like 'need tos agreement' will - // end the login attempt. - void setUserInteraction(bool state) { mUserInteraction = state; } - bool getUserInteraction() { return mUserInteraction; } - // Whether to tell login to skip optional update request. // False by default. void setSkipOptionalUpdate(bool state) { mSkipOptionalUpdate = state; } @@ -100,7 +94,6 @@ private: std::string mLoginState; LLSD mRequestData; LLSD mResponseData; - bool mUserInteraction; bool mSkipOptionalUpdate; bool mAttemptComplete; F64 mTransferRate; diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 611f9de2e6..8cdc9843ab 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -980,7 +980,6 @@ bool idle_startup() login->setSkipOptionalUpdate(true); } - login->setUserInteraction(show_connect_box); login->setSerialNumber(LLAppViewer::instance()->getSerialNumber()); login->setLastExecEvent(gLastExecEvent); login->setUpdaterLauncher(boost::bind(&LLAppViewer::launchUpdater, LLAppViewer::instance())); -- cgit v1.2.3 From 8864a1b4db54b1ae5b335dec6372ee763b05ece9 Mon Sep 17 00:00:00 2001 From: Paul Guslisty Date: Fri, 14 Jan 2011 18:10:46 +0200 Subject: STORM-834 FIXED Color picker remains opened after 'Undo changes' button was pressed on 'Edit weareble' panel - Close color picker after color swatch's value updated --- indra/newview/llcolorswatch.cpp | 2 +- indra/newview/llcolorswatch.h | 2 +- indra/newview/llpaneleditwearable.cpp | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/indra/newview/llcolorswatch.cpp b/indra/newview/llcolorswatch.cpp index 4a1ba6f1b5..6f02192d0a 100644 --- a/indra/newview/llcolorswatch.cpp +++ b/indra/newview/llcolorswatch.cpp @@ -319,7 +319,7 @@ void LLColorSwatchCtrl::onColorChanged ( void* data, EColorPickOp pick_op ) // This is called when the main floatercustomize panel is closed. // Since this class has pointers up to its parents, we need to cleanup // this class first in order to avoid a crash. -void LLColorSwatchCtrl::onParentFloaterClosed() +void LLColorSwatchCtrl::closeFloaterColorPicker() { LLFloaterColorPicker* pickerp = (LLFloaterColorPicker*)mPickerHandle.get(); if (pickerp) diff --git a/indra/newview/llcolorswatch.h b/indra/newview/llcolorswatch.h index cd859ea128..5bdd1712d2 100644 --- a/indra/newview/llcolorswatch.h +++ b/indra/newview/llcolorswatch.h @@ -100,7 +100,7 @@ public: /*virtual*/ void setEnabled( BOOL enabled ); static void onColorChanged ( void* data, EColorPickOp pick_op = COLOR_CHANGE ); - void onParentFloaterClosed(); + void closeFloaterColorPicker(); protected: BOOL mValid; diff --git a/indra/newview/llpaneleditwearable.cpp b/indra/newview/llpaneleditwearable.cpp index 90ed8b9e58..4a74b7925c 100644 --- a/indra/newview/llpaneleditwearable.cpp +++ b/indra/newview/llpaneleditwearable.cpp @@ -569,6 +569,7 @@ static void update_color_swatch_ctrl(LLPanelEditWearable* self, LLPanel* panel, if (color_swatch_ctrl) { color_swatch_ctrl->set(self->getWearable()->getClothesColor(entry->mTextureIndex)); + color_swatch_ctrl->closeFloaterColorPicker(); } } -- cgit v1.2.3 From 6a3d06deca73683514d4668f78adf684d760708c Mon Sep 17 00:00:00 2001 From: Jonathan Yap Date: Sun, 16 Jan 2011 12:10:44 -0500 Subject: STORM-844 Better way of doing "More" should be "Less" when Media Control is open thanks to Twisted Laws --- doc/contributions.txt | 1 + indra/newview/llpanelnearbymedia.cpp | 5 ++--- .../newview/skins/default/xui/en/panel_nearby_media.xml | 16 ++-------------- 3 files changed, 5 insertions(+), 17 deletions(-) diff --git a/doc/contributions.txt b/doc/contributions.txt index f4831a1947..42e030ac66 100644 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -755,6 +755,7 @@ Twisted Laws SNOW-352 STORM-466 STORM-467 + STORM-844 Vadim Bigbear VWR-2681 Vector Hastings diff --git a/indra/newview/llpanelnearbymedia.cpp b/indra/newview/llpanelnearbymedia.cpp index fcc67d6840..14e39f2c48 100644 --- a/indra/newview/llpanelnearbymedia.cpp +++ b/indra/newview/llpanelnearbymedia.cpp @@ -958,7 +958,7 @@ void LLPanelNearByMedia::onAdvancedButtonClick() void LLPanelNearByMedia::onMoreLess() { - bool is_more = getChild("more_btn")->getVisible(); + bool is_more = getChild("more_btn")->getToggleState(); mNearbyMediaPanel->setVisible(is_more); // enable resizing when expanded @@ -969,8 +969,7 @@ void LLPanelNearByMedia::onMoreLess() setShape(new_rect); - getChild("more_btn")->setVisible(!is_more); - getChild("less_btn")->setVisible(is_more); + getChild("more_btn")->setVisible(true); } void LLPanelNearByMedia::updateControls() diff --git a/indra/newview/skins/default/xui/en/panel_nearby_media.xml b/indra/newview/skins/default/xui/en/panel_nearby_media.xml index aac3608e13..9bd60b935f 100644 --- a/indra/newview/skins/default/xui/en/panel_nearby_media.xml +++ b/indra/newview/skins/default/xui/en/panel_nearby_media.xml @@ -68,24 +68,12 @@ right="-8" width="66" height="22" + is_toggle="true" label="More >>" - label_selected="More >>"> + label_selected="<< Less"> - Date: Mon, 17 Jan 2011 10:09:52 -0500 Subject: VWR-24217: allow Contents folder from object to be dragged to inventory --- doc/contributions.txt | 1 + indra/newview/llpanelobjectinventory.cpp | 20 +++++--------------- 2 files changed, 6 insertions(+), 15 deletions(-) diff --git a/doc/contributions.txt b/doc/contributions.txt index f21354b406..839e92e086 100644 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -393,6 +393,7 @@ Kitty Barnett STORM-288 STORM-799 STORM-800 + VWR-24217 Kunnis Basiat VWR-82 VWR-102 diff --git a/indra/newview/llpanelobjectinventory.cpp b/indra/newview/llpanelobjectinventory.cpp index 211b9cf4b1..0b6267c9e6 100644 --- a/indra/newview/llpanelobjectinventory.cpp +++ b/indra/newview/llpanelobjectinventory.cpp @@ -766,22 +766,12 @@ BOOL LLTaskCategoryBridge::startDrag(EDragAndDropType* type, LLUUID* id) const LLViewerObject* object = gObjectList.findObject(mPanel->getTaskUUID()); if(object) { - const LLInventoryItem *inv = dynamic_cast(object->getInventoryObject(mUUID)); - if (inv) + const LLInventoryObject* cat = object->getInventoryObject(mUUID); + if ( (cat) && (move_inv_category_world_to_agent(mUUID, LLUUID::null, FALSE)) ) { - const LLPermissions& perm = inv->getPermissions(); - bool can_copy = gAgent.allowOperation(PERM_COPY, perm, - GP_OBJECT_MANIPULATE); - if((can_copy && perm.allowTransferTo(gAgent.getID())) - || object->permYouOwner()) -// || gAgent.isGodlike()) - - { - *type = LLViewerAssetType::lookupDragAndDropType(inv->getType()); - - *id = inv->getUUID(); - return TRUE; - } + *type = LLViewerAssetType::lookupDragAndDropType(cat->getType()); + *id = mUUID; + return TRUE; } } } -- cgit v1.2.3 From 1ae76ea43e3ad57ce58e1b432490de531e01dab3 Mon Sep 17 00:00:00 2001 From: Paul Guslisty Date: Mon, 17 Jan 2011 18:01:55 +0200 Subject: STORM-484 FIXED The long name is not truncated in Build tools - Decreased height of text box containing name - Enabled ellipses for these text boxes --- indra/newview/skins/default/xui/en/floater_tools.xml | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/indra/newview/skins/default/xui/en/floater_tools.xml b/indra/newview/skins/default/xui/en/floater_tools.xml index e70e1eb61b..1808fea445 100644 --- a/indra/newview/skins/default/xui/en/floater_tools.xml +++ b/indra/newview/skins/default/xui/en/floater_tools.xml @@ -872,12 +872,13 @@ length="1" follows="left|top" left_pad="0" - height="30" + height="20" layout="topleft" name="Creator Name" top_delta="0" width="190" - word_wrap="true"> + word_wrap="true" + use_ellipses="ture"> Mrs. Esbee Linden (esbee.linden) Owner: @@ -897,13 +898,14 @@ type="string" length="1" follows="left|top" - height="30" + height="20" layout="topleft" name="Owner Name" left_pad="0" top_delta="0" width="190" - word_wrap="true"> + word_wrap="true" + use_ellipses="true"> Mrs. Erica "Moose" Linden (erica.linden) Group: -- cgit v1.2.3 From 7461f1ca2be2851b76ded50d2eb9c0fcc46cfd5f Mon Sep 17 00:00:00 2001 From: Seth ProductEngine Date: Mon, 17 Jan 2011 19:03:49 +0200 Subject: STORM-383 FIXED Added "Restore Item" context menu entry for landmarks and folders in Trash category in Places->My Landmarks->My Inventory accordion tab. --- indra/newview/llpanellandmarks.cpp | 85 ++++++++++++++++++++++ indra/newview/llpanellandmarks.h | 8 ++ .../default/xui/en/menu_places_gear_folder.xml | 8 ++ .../default/xui/en/menu_places_gear_landmark.xml | 8 ++ 4 files changed, 109 insertions(+) diff --git a/indra/newview/llpanellandmarks.cpp b/indra/newview/llpanellandmarks.cpp index e8c8273a9d..80f6862169 100644 --- a/indra/newview/llpanellandmarks.cpp +++ b/indra/newview/llpanellandmarks.cpp @@ -71,6 +71,7 @@ static void collapse_all_folders(LLFolderView* root_folder); static void expand_all_folders(LLFolderView* root_folder); static bool has_expanded_folders(LLFolderView* root_folder); static bool has_collapsed_folders(LLFolderView* root_folder); +static void toggle_restore_menu(LLMenuGL* menu, BOOL visible, BOOL enabled); /** * Functor counting expanded and collapsed folders in folder view tree to know @@ -708,6 +709,9 @@ void LLLandmarksPanel::initListCommandsHandlers() mGearFolderMenu = LLUICtrlFactory::getInstance()->createFromFile("menu_places_gear_folder.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); mMenuAdd = LLUICtrlFactory::getInstance()->createFromFile("menu_place_add_button.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); + mGearLandmarkMenu->setVisibilityChangeCallback(boost::bind(&LLLandmarksPanel::onMenuVisibilityChange, this, _1, _2)); + mGearFolderMenu->setVisibilityChangeCallback(boost::bind(&LLLandmarksPanel::onMenuVisibilityChange, this, _1, _2)); + mListCommands->childSetAction(ADD_BUTTON_NAME, boost::bind(&LLLandmarksPanel::showActionMenu, this, mMenuAdd, ADD_BUTTON_NAME)); } @@ -1079,6 +1083,60 @@ void LLLandmarksPanel::onCustomAction(const LLSD& userdata) { doActionOnCurSelectedLandmark(boost::bind(&LLLandmarksPanel::doCreatePick, this, _1)); } + else if ("restore" == command_name && mCurrentSelectedList) + { + mCurrentSelectedList->doToSelected(userdata); + } +} + +void LLLandmarksPanel::onMenuVisibilityChange(LLUICtrl* ctrl, const LLSD& param) +{ + bool new_visibility = param["visibility"].asBoolean(); + + // We don't have to update items visibility if the menu is hiding. + if (!new_visibility) return; + + BOOL are_any_items_in_trash = FALSE; + BOOL are_all_items_in_trash = TRUE; + + LLFolderView* root_folder_view = mCurrentSelectedList ? mCurrentSelectedList->getRootFolder() : NULL; + if(root_folder_view) + { + const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH); + + std::set selected_uuids = root_folder_view->getSelectionList(); + + // Iterate through selected items to find out if any of these items are in Trash + // or all the items are in Trash category. + for (std::set::const_iterator iter = selected_uuids.begin(); iter != selected_uuids.end(); ++iter) + { + LLFolderViewItem* item = root_folder_view->getItemByID(*iter); + + // If no item is found it might be a folder id. + if (!item) + { + item = root_folder_view->getFolderByID(*iter); + } + if (!item) continue; + + LLFolderViewEventListener* listenerp = item->getListener(); + if(!listenerp) continue; + + // Trash category itself should not be included because it can't be + // actually restored from trash. + are_all_items_in_trash &= listenerp->isItemInTrash() && *iter != trash_id; + + // If there are any selected items in Trash including the Trash category itself + // we show "Restore Item" in context menu and hide other irrelevant items. + are_any_items_in_trash |= listenerp->isItemInTrash(); + } + } + + // Display "Restore Item" menu entry if at least one of the selected items + // is in Trash or the Trash category itself is among selected items. + // Hide other menu entries in this case. + // Enable this menu entry only if all selected items are in the Trash category. + toggle_restore_menu((LLMenuGL*)ctrl, are_any_items_in_trash, are_all_items_in_trash); } /* @@ -1414,4 +1472,31 @@ static bool has_collapsed_folders(LLFolderView* root_folder) return true; } + +// Displays "Restore Item" context menu entry while hiding +// all other entries or vice versa. +// Sets "Restore Item" enabled state. +void toggle_restore_menu(LLMenuGL *menu, BOOL visible, BOOL enabled) +{ + if (!menu) return; + + const LLView::child_list_t *list = menu->getChildList(); + for (LLView::child_list_t::const_iterator itor = list->begin(); + itor != list->end(); + ++itor) + { + LLView *menu_item = (*itor); + std::string name = menu_item->getName(); + + if ("restore_item" == name) + { + menu_item->setVisible(visible); + menu_item->setEnabled(enabled); + } + else + { + menu_item->setVisible(!visible); + } + } +} // EOF diff --git a/indra/newview/llpanellandmarks.h b/indra/newview/llpanellandmarks.h index 8dcbca0440..b2f4e92473 100644 --- a/indra/newview/llpanellandmarks.h +++ b/indra/newview/llpanellandmarks.h @@ -128,6 +128,14 @@ private: bool isActionEnabled(const LLSD& command_name) const; void onCustomAction(const LLSD& command_name); + /** + * Updates context menu depending on the selected items location. + * + * For items in Trash category the menu includes the "Restore Item" + * context menu entry. + */ + void onMenuVisibilityChange(LLUICtrl* ctrl, const LLSD& param); + /** * Determines if an item can be modified via context/gear menu. * diff --git a/indra/newview/skins/default/xui/en/menu_places_gear_folder.xml b/indra/newview/skins/default/xui/en/menu_places_gear_folder.xml index 6f46165883..1aeb166e01 100644 --- a/indra/newview/skins/default/xui/en/menu_places_gear_folder.xml +++ b/indra/newview/skins/default/xui/en/menu_places_gear_folder.xml @@ -25,6 +25,14 @@ function="Places.LandmarksGear.Enable" parameter="category" /> + + + + + + Date: Tue, 18 Jan 2011 18:46:35 +0200 Subject: STORM-243 FIXED Disabled the "You just entered a region using a different server version..." pop-up notification. --- indra/newview/app_settings/settings.xml | 11 ----- indra/newview/llviewermessage.cpp | 50 ---------------------- .../newview/skins/default/xui/da/notifications.xml | 3 -- .../newview/skins/default/xui/de/notifications.xml | 3 -- .../newview/skins/default/xui/en/notifications.xml | 9 ---- .../newview/skins/default/xui/es/notifications.xml | 3 -- .../newview/skins/default/xui/fr/notifications.xml | 3 -- .../newview/skins/default/xui/it/notifications.xml | 3 -- .../newview/skins/default/xui/ja/notifications.xml | 3 -- .../newview/skins/default/xui/nl/notifications.xml | 3 -- .../newview/skins/default/xui/pl/notifications.xml | 3 -- .../newview/skins/default/xui/pt/notifications.xml | 3 -- 12 files changed, 97 deletions(-) diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index ef6f8fd3ee..a22f197b85 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -12445,16 +12445,5 @@ Value name - ReleaseNotesURL - - Comment - Release notes URL template - Persist - 1 - Type - String - Value - http://secondlife.com/app/releasenotes/?channel=[CHANNEL]&version=[VERSION] - diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 7dc5d96689..6fc85a3944 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -171,31 +171,6 @@ const BOOL SCRIPT_QUESTION_IS_CAUTION[SCRIPT_PERMISSION_EOF] = FALSE // ControlYourCamera }; -// Extract channel and version from a string like "SL Web Viewer Beta 10.11.29.215604". -// (channel: "SL Web Viewer Beta", version: "10.11.29.215604") -static bool parse_version_info(const std::string& version_info, std::string& channel, std::string& ver) -{ - size_t last_space = version_info.rfind(" "); - channel = version_info; - - if (last_space != std::string::npos) - { - try - { - ver = version_info.substr(last_space + 1); - channel.replace(last_space, ver.length() + 1, ""); // strip version - } - catch (std::out_of_range) - { - return false; - } - - return true; - } - - return false; -} - bool friendship_offer_callback(const LLSD& notification, const LLSD& response) { S32 option = LLNotificationsUtil::getSelectedOption(notification, response); @@ -3848,31 +3823,6 @@ void process_agent_movement_complete(LLMessageSystem* msg, void**) return; } - if (!gLastVersionChannel.empty()) - { - std::string url = regionp->getCapability("ServerReleaseNotes"); - if (url.empty()) - { - // The capability hasn't arrived yet or is not supported, - // fall back to parsing server version channel. - std::string channel, ver; - if (!parse_version_info(version_channel, channel, ver)) - { - llwarns << "Failed to parse server version channel (" << version_channel << ")" << llendl; - } - - url = gSavedSettings.getString("ReleaseNotesURL"); - LLSD args; - args["CHANNEL"] = LLWeb::escapeURL(channel); - args["VERSION"] = LLWeb::escapeURL(ver); - LLStringUtil::format(url, args); - } - - LLSD args; - args["URL"] = url; - LLNotificationsUtil::add("ServerVersionChanged", args); - } - gLastVersionChannel = version_channel; } diff --git a/indra/newview/skins/default/xui/da/notifications.xml b/indra/newview/skins/default/xui/da/notifications.xml index 593e686d4c..27024f4eaa 100644 --- a/indra/newview/skins/default/xui/da/notifications.xml +++ b/indra/newview/skins/default/xui/da/notifications.xml @@ -1580,9 +1580,6 @@ Klik på Acceptér for at deltage eller Afvis for at afvise invitationen. Klik p En fejl er opstået under forsøget på at koble sig på stemme chatten [VOICE_CHANNEL_NAME]. Pråv venligst senere. - - Du er netop ankommet til en region der benytter en anden server version, hvilket kan influere på hastigheden. [[URL] For at se yderligere.] - Den SLurl du klikkede på understøttes ikke. diff --git a/indra/newview/skins/default/xui/de/notifications.xml b/indra/newview/skins/default/xui/de/notifications.xml index a2d0b5a170..c26b02ec8f 100644 --- a/indra/newview/skins/default/xui/de/notifications.xml +++ b/indra/newview/skins/default/xui/de/notifications.xml @@ -2691,9 +2691,6 @@ Klicken Sie auf 'Akzeptieren ', um dem Chat beizutreten, oder auf &a Fehler beim Versuch, eine Voice-Chat-Verbindung zu [VOICE_CHANNEL_NAME] herzustellen. Bitte versuchen Sie es erneut. - - Sie haben eine Region betreten, die eine andere Server-Version verwendet. Dies kann sich auf die Leistung auswirken. [[URL] Versionshinweise anzeigen.] - Die SLurl, auf die Sie geklickt haben, wird nicht unterstützt. diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index 6f21938bdb..f008042a81 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -6303,15 +6303,6 @@ An error has occurred while trying to connect to voice chat for [VOICE_CHANNEL_N - -You just entered a region using a different server version, which may affect performance. [[URL] View the release notes.] - - Se ha producido un error al intentar conectarte al [VOICE_CHANNEL_NAME]. Por favor, inténtalo más tarde. - - Acabas de entrar en una región que usa un servidor con una versión distinta, y esto puede influir en el funcionamiento. [[URL] Ver las notas de desarrollo]. - No se admite el formato de la SLurl que has pulsado. diff --git a/indra/newview/skins/default/xui/fr/notifications.xml b/indra/newview/skins/default/xui/fr/notifications.xml index f0b0e63af0..2ccac5c19a 100644 --- a/indra/newview/skins/default/xui/fr/notifications.xml +++ b/indra/newview/skins/default/xui/fr/notifications.xml @@ -2674,9 +2674,6 @@ Pour y participer, cliquez sur Accepter. Sinon, cliquez sur Refuser. Pour ignore Une erreur est survenue pendant la connexion au chat vocal pour [VOICE_CHANNEL_NAME]. Veuillez réessayer ultérieurement. - - La région dans laquelle vous avez pénétré utilise une version de serveur différente, ce qui peut avoir un impact sur votre performance. [[URL] Consultez les notes de version.] - La SLurl que vous avez saisie n'est pas prise en charge. diff --git a/indra/newview/skins/default/xui/it/notifications.xml b/indra/newview/skins/default/xui/it/notifications.xml index 5e53080c77..cce5888598 100644 --- a/indra/newview/skins/default/xui/it/notifications.xml +++ b/indra/newview/skins/default/xui/it/notifications.xml @@ -2623,9 +2623,6 @@ Clicca su Accetta per unirti alla chat oppure su Declina per declinare l'in Si è verificato un errore durante il tentativo di collegarti a una voice chat con [VOICE_CHANNEL_NAME]. Riprova più tardi. - - Sei appena entrato in una regione che usa una versione differente del server: ciò potrebbe incidere sule prestazioni. [[URL] Visualizza le note sulla versione.] - Lo SLurl su cui hai cliccato non è valido. diff --git a/indra/newview/skins/default/xui/ja/notifications.xml b/indra/newview/skins/default/xui/ja/notifications.xml index f133bb361a..baec8c073c 100644 --- a/indra/newview/skins/default/xui/ja/notifications.xml +++ b/indra/newview/skins/default/xui/ja/notifications.xml @@ -2675,9 +2675,6 @@ M キーを押して変更します。 [VOICE_CHANNEL_NAME] のボイスチャットに接続中に、エラーが発生しました。後でもう一度お試しください。 - - サーバーのバージョンが異なるリージョンに来ました。パフォーマンスに影響することがあります。 [[URL] リリースノートを確認] - クリックした SLurl はサポートされていません。 diff --git a/indra/newview/skins/default/xui/nl/notifications.xml b/indra/newview/skins/default/xui/nl/notifications.xml index be0c17d2ff..f27b83d3f9 100644 --- a/indra/newview/skins/default/xui/nl/notifications.xml +++ b/indra/newview/skins/default/xui/nl/notifications.xml @@ -3012,9 +3012,6 @@ Klik Accepteren om deel te nemen aan de chat of Afwijzen om de uitnodiging af te Er is een fout opgetreden tijdens het verbinden met voice chat voor [VOICE_CHANNEL_NAME]. Probeert u het later alstublieft opnieuw. - - De regio die u bent binnengetreden wordt onder een andere simulatorversie uitgevoerd. Klik dit bericht voor meer details. - De URL die u heeft geklikt kan niet binnen deze webbrowser worden geopend. diff --git a/indra/newview/skins/default/xui/pl/notifications.xml b/indra/newview/skins/default/xui/pl/notifications.xml index 57a6b8b8ef..138125ff0b 100644 --- a/indra/newview/skins/default/xui/pl/notifications.xml +++ b/indra/newview/skins/default/xui/pl/notifications.xml @@ -2635,9 +2635,6 @@ Wybierz Zaakceptuj żeby zacząć czat albo Odmów żeby nie przyjąć zaproszen Błąd podczas łączenia z rozmową [VOICE_CHANNEL_NAME]. Spróbuj póżniej. - - Ten region używa innej wersji symulatora. Kliknij na tą wiadomość żeby uzyskać więcej informacji: [[URL] View the release notes.] - Nie można otworzyć wybranego SLurl. diff --git a/indra/newview/skins/default/xui/pt/notifications.xml b/indra/newview/skins/default/xui/pt/notifications.xml index a1855f2e89..9c3b9386e0 100644 --- a/indra/newview/skins/default/xui/pt/notifications.xml +++ b/indra/newview/skins/default/xui/pt/notifications.xml @@ -2658,9 +2658,6 @@ Clique em Aceitar para atender ou em Recusar para recusar este convite. Clique Ocorreu um erro enquanto você tentava se conectar à conversa de voz de [VOICE_CHANNEL_NAME]. Favor tentar novamente mais tarde. - - Você chegou a uma região com uma versão diferente de servidor, que pode afetar o desempenho. [[URL] Consultar notas da versão.] - O SLurl no qual você clicou não é suportado. -- cgit v1.2.3 From feb5fbc66e0a4941489a7c0d92cb51341a1c4f39 Mon Sep 17 00:00:00 2001 From: Xiaohong Bao Date: Tue, 18 Jan 2011 10:41:37 -0700 Subject: debug tool to show texture info for SH-659: small textures not loaded. --- indra/newview/app_settings/settings.xml | 13 +++++- indra/newview/llviewerwindow.cpp | 54 ++++++++++++++++++++-- indra/newview/skins/default/xui/en/menu_viewer.xml | 10 ++++ 3 files changed, 73 insertions(+), 4 deletions(-) diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 7b3f50e4e2..c7302ea607 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -1851,10 +1851,21 @@ Value 0 + DebugShowTextureInfo + + Comment + Show inertested texture info + Persist + 1 + Type + Boolean + Value + 0 + DebugShowTime Comment - Show depth buffer contents + Show time info Persist 1 Type diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index fda6f316e6..ed0789bc50 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -296,13 +296,15 @@ private: line_list_t mLineList; LLColor4 mTextColor; -public: - LLDebugText(LLViewerWindow* window) : mWindow(window) {} - void addText(S32 x, S32 y, const std::string &text) { mLineList.push_back(Line(text, x, y)); } + + void clearText() { mLineList.clear(); } + +public: + LLDebugText(LLViewerWindow* window) : mWindow(window) {} void update() { @@ -323,6 +325,8 @@ public: U32 ypos = 64; const U32 y_inc = 20; + clearText(); + if (gSavedSettings.getBOOL("DebugShowTime")) { const U32 y_inc2 = 15; @@ -601,6 +605,50 @@ public: ypos += y_inc; } } + + if (gSavedSettings.getBOOL("DebugShowTextureInfo")) + { + LLViewerObject* objectp = NULL ; + //objectp = = gAgentCamera.getFocusObject(); + + LLSelectNode* nodep = LLSelectMgr::instance().getHoverNode(); + if (nodep) + { + objectp = nodep->getObject(); + } + if (objectp && !objectp->isDead()) + { + S32 num_faces = objectp->mDrawable->getNumFaces() ; + + for(S32 i = 0 ; i < num_faces; i++) + { + LLFace* facep = objectp->mDrawable->getFace(i) ; + if(facep) + { + //addText(xpos, ypos, llformat("ts_min: %.3f ts_max: %.3f tt_min: %.3f tt_max: %.3f", facep->mTexExtents[0].mV[0], facep->mTexExtents[1].mV[0], + // facep->mTexExtents[0].mV[1], facep->mTexExtents[1].mV[1])); + //ypos += y_inc; + + addText(xpos, ypos, llformat("v_size: %.3f: p_size: %.3f", facep->getVirtualSize(), facep->getPixelArea())); + ypos += y_inc; + + //const LLTextureEntry *tep = facep->getTextureEntry(); + //if(tep) + //{ + // addText(xpos, ypos, llformat("scale_s: %.3f: scale_t: %.3f", tep->mScaleS, tep->mScaleT)) ; + // ypos += y_inc; + //} + + LLViewerTexture* tex = facep->getTexture() ; + if(tex) + { + addText(xpos, ypos, llformat("ID: %s v_size: %.3f", tex->getID().asString().c_str(), tex->getMaxVirtualSize())); + ypos += y_inc; + } + } + } + } + } } void draw() diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index b36cf13f1b..e2a3067796 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -1916,6 +1916,16 @@ + + + + Date: Tue, 18 Jan 2011 14:08:21 -0700 Subject: fix for SH-659: small textures not loaded --- indra/llmath/llvolume.cpp | 41 ++++++++++++++++++++++++++++++++++++++--- indra/llmath/llvolume.h | 1 + indra/newview/llface.cpp | 11 +++++++++-- 3 files changed, 48 insertions(+), 5 deletions(-) diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index 14e1ca8d43..71b92962fb 100644 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -4406,19 +4406,54 @@ std::ostream& operator<<(std::ostream &s, const LLVolume *volumep) BOOL LLVolumeFace::create(LLVolume* volume, BOOL partial_build) { + BOOL ret = FALSE ; if (mTypeMask & CAP_MASK) { - return createCap(volume, partial_build); + ret = createCap(volume, partial_build); } else if ((mTypeMask & END_MASK) || (mTypeMask & SIDE_MASK)) { - return createSide(volume, partial_build); + ret = createSide(volume, partial_build); } else { llerrs << "Unknown/uninitialized face type!" << llendl; - return FALSE; } + + //update the range of the texture coordinates + if(ret) + { + mTexCoordExtents[0].setVec(1.f, 1.f) ; + mTexCoordExtents[1].setVec(0.f, 0.f) ; + + U32 end = mVertices.size() ; + for(U32 i = 0 ; i < end ; i++) + { + if(mTexCoordExtents[0].mV[0] > mVertices[i].mTexCoord.mV[0]) + { + mTexCoordExtents[0].mV[0] = mVertices[i].mTexCoord.mV[0] ; + } + if(mTexCoordExtents[1].mV[0] < mVertices[i].mTexCoord.mV[0]) + { + mTexCoordExtents[1].mV[0] = mVertices[i].mTexCoord.mV[0] ; + } + + if(mTexCoordExtents[0].mV[1] > mVertices[i].mTexCoord.mV[1]) + { + mTexCoordExtents[0].mV[1] = mVertices[i].mTexCoord.mV[1] ; + } + if(mTexCoordExtents[1].mV[1] < mVertices[i].mTexCoord.mV[1]) + { + mTexCoordExtents[1].mV[1] = mVertices[i].mTexCoord.mV[1] ; + } + } + mTexCoordExtents[0].mV[0] = llmax(0.f, mTexCoordExtents[0].mV[0]) ; + mTexCoordExtents[0].mV[1] = llmax(0.f, mTexCoordExtents[0].mV[1]) ; + mTexCoordExtents[1].mV[0] = llmin(1.f, mTexCoordExtents[1].mV[0]) ; + mTexCoordExtents[1].mV[1] = llmin(1.f, mTexCoordExtents[1].mV[1]) ; + } + + return ret ; } void LerpPlanarVertex(LLVolumeFace::VertexData& v0, diff --git a/indra/llmath/llvolume.h b/indra/llmath/llvolume.h index d48a79ee46..28b9895ff3 100644 --- a/indra/llmath/llvolume.h +++ b/indra/llmath/llvolume.h @@ -831,6 +831,7 @@ public: S32 mNumT; LLVector3 mExtents[2]; //minimum and maximum point of face + LLVector2 mTexCoordExtents[2]; //minimum and maximum of texture coordinates of the face. std::vector mVertices; std::vector mIndices; diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp index d22950cad3..6ba957870c 100644 --- a/indra/newview/llface.cpp +++ b/indra/newview/llface.cpp @@ -1233,7 +1233,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, if (rebuild_tcoord) { LLVector2 tc = vf.mVertices[i].mTexCoord; - + if (texgen != LLTextureEntry::TEX_GEN_DEFAULT) { LLVector3 vec = vf.mVertices[i].mPosition; @@ -1409,7 +1409,14 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, mTexExtents[0].setVec(0,0); mTexExtents[1].setVec(1,1); xform(mTexExtents[0], cos_ang, sin_ang, os, ot, ms, mt); - xform(mTexExtents[1], cos_ang, sin_ang, os, ot, ms, mt); + xform(mTexExtents[1], cos_ang, sin_ang, os, ot, ms, mt); + + F32 es = vf.mTexCoordExtents[1].mV[0] - vf.mTexCoordExtents[0].mV[0] ; + F32 et = vf.mTexCoordExtents[1].mV[1] - vf.mTexCoordExtents[0].mV[1] ; + mTexExtents[0][0] *= es ; + mTexExtents[1][0] *= es ; + mTexExtents[0][1] *= et ; + mTexExtents[1][1] *= et ; } mLastVertexBuffer = mVertexBuffer; -- cgit v1.2.3 From c46cbafb15ff48515fdff8f1fd78b99391ddd4d7 Mon Sep 17 00:00:00 2001 From: Xiaohong Bao Date: Tue, 18 Jan 2011 16:46:33 -0700 Subject: fix for SH-761: Texture Saving Does Not Work --- indra/newview/llpreviewtexture.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/indra/newview/llpreviewtexture.cpp b/indra/newview/llpreviewtexture.cpp index fd6b326ef1..ced699b6b2 100644 --- a/indra/newview/llpreviewtexture.cpp +++ b/indra/newview/llpreviewtexture.cpp @@ -273,6 +273,8 @@ void LLPreviewTexture::saveAs() mSaveFileName = file_picker.getFirstFile(); mLoadingFullImage = TRUE; getWindow()->incBusyCount(); + + mImage->forceToSaveRawImage(0) ;//re-fetch the raw image if the old one is removed. mImage->setLoadedCallback( LLPreviewTexture::onFileLoadedForSave, 0, TRUE, FALSE, new LLUUID( mItemUUID ), &mCallbackTextureList ); } -- cgit v1.2.3 From 3571e83b6413e0c1050540a6cddeeaa7c6ca91c1 Mon Sep 17 00:00:00 2001 From: Jonathan Yap Date: Wed, 19 Jan 2011 06:02:08 -0500 Subject: STORM-869 Minor irregulaties in settings.xml -- remove duplicate entries, formatting cleanup --- doc/contributions.txt | 1 + indra/newview/app_settings/settings.xml | 81 +-------------------------------- 2 files changed, 2 insertions(+), 80 deletions(-) diff --git a/doc/contributions.txt b/doc/contributions.txt index 4c33834a46..c82d2c2a9d 100644 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -359,6 +359,7 @@ Jonathan Yap STORM-679 STORM-596 STORM-726 + STORM-869 Kage Pixel VWR-11 Ken March diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 06992d2b52..ec094eaeb8 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -917,39 +917,6 @@ Value 1 - BulkChangeIncludeAnimations - - Comment - Bulk permission changes affect animations - Persist - 1 - Type - Boolean - Value - 1 - - BulkChangeIncludeAnimations - - Comment - Bulk permission changes affect animations - Persist - 1 - Type - Boolean - Value - 1 - - BulkChangeIncludeAnimations - - Comment - Bulk permission changes affect animations - Persist - 1 - Type - Boolean - Value - 1 - BulkChangeIncludeBodyParts Comment @@ -1162,18 +1129,7 @@ CacheLocationTopFolder Comment - Controls the top folder location of the local disk cache - Persist - 1 - Type - String - Value - - - CacheLocationTopFolder - - Comment - Controls the location of the local disk cache + Controls the top folder location of the the local disk cache Persist 1 Type @@ -3085,17 +3041,6 @@ Value http://viewer-settings.secondlife.com - FPSLogFrequency - - Comment - Seconds between display of FPS in log (0 for never) - Persist - 1 - Type - F32 - Value - 60.0 - FPSLogFrequency Comment @@ -6027,17 +5972,6 @@ 0 OutBandwidth - - Comment - Expand render stats display - Persist - 1 - Type - Boolean - Value - 1 - - OutBandwidth Comment Outgoing bandwidth throttle (bps) @@ -11375,8 +11309,6 @@ Type LLSD Value - - VFSOldSize @@ -11532,17 +11464,6 @@ Value - VivoxDebugSIPURIHostName - - Comment - Hostname portion of vivox SIP URIs (empty string for the default). - Persist - 1 - Type - String - Value - - VivoxDebugVoiceAccountServerURI Comment -- cgit v1.2.3 From 4f801f729dbaf65edba93a7152c6f21ba2269ee0 Mon Sep 17 00:00:00 2001 From: Vadim ProductEngine Date: Wed, 19 Jan 2011 13:30:05 +0200 Subject: STORM-373 FIXED "Rename" context menu option was disabled for incomplete inventory items. Refresh the inventory context menu (which enables the "Rename" option) after the selected item(s) gets fetched. --- indra/newview/llfolderview.cpp | 63 ++++++++++++++++++++------------ indra/newview/llfolderview.h | 3 ++ indra/newview/llinventorypanel.cpp | 73 ++++++++++++++++++++++++++++++++++++++ indra/newview/llinventorypanel.h | 3 ++ 4 files changed, 119 insertions(+), 23 deletions(-) diff --git a/indra/newview/llfolderview.cpp b/indra/newview/llfolderview.cpp index 62ba746a02..b3b1ce5743 100644 --- a/indra/newview/llfolderview.cpp +++ b/indra/newview/llfolderview.cpp @@ -1854,31 +1854,9 @@ BOOL LLFolderView::handleRightMouseDown( S32 x, S32 y, MASK mask ) { if (mCallbackRegistrar) mCallbackRegistrar->pushScope(); - //menu->empty(); - const LLView::child_list_t *list = menu->getChildList(); - LLView::child_list_t::const_iterator menu_itor; - for (menu_itor = list->begin(); menu_itor != list->end(); ++menu_itor) - { - (*menu_itor)->setVisible(FALSE); - (*menu_itor)->pushVisible(TRUE); - (*menu_itor)->setEnabled(TRUE); - } - - // Successively filter out invalid options - - U32 flags = FIRST_SELECTED_ITEM; - for (selected_items_t::iterator item_itor = mSelectedItems.begin(); - item_itor != mSelectedItems.end(); - ++item_itor) - { - LLFolderViewItem* selected_item = (*item_itor); - selected_item->buildContextMenu(*menu, flags); - flags = 0x0; - } + updateMenuOptions(menu); - addNoOptions(menu); - menu->updateParent(LLMenuGL::sMenuContainer); LLMenuGL::showPopup(this, menu, x, y); if (mCallbackRegistrar) @@ -2365,6 +2343,45 @@ void LLFolderView::updateRenamerPosition() } } +// Update visibility and availability (i.e. enabled/disabled) of context menu items. +void LLFolderView::updateMenuOptions(LLMenuGL* menu) +{ + const LLView::child_list_t *list = menu->getChildList(); + + LLView::child_list_t::const_iterator menu_itor; + for (menu_itor = list->begin(); menu_itor != list->end(); ++menu_itor) + { + (*menu_itor)->setVisible(FALSE); + (*menu_itor)->pushVisible(TRUE); + (*menu_itor)->setEnabled(TRUE); + } + + // Successively filter out invalid options + + U32 flags = FIRST_SELECTED_ITEM; + for (selected_items_t::iterator item_itor = mSelectedItems.begin(); + item_itor != mSelectedItems.end(); + ++item_itor) + { + LLFolderViewItem* selected_item = (*item_itor); + selected_item->buildContextMenu(*menu, flags); + flags = 0x0; + } + + addNoOptions(menu); +} + +// Refresh the context menu (that is already shown). +void LLFolderView::updateMenu() +{ + LLMenuGL* menu = (LLMenuGL*)mPopupMenuHandle.get(); + if (menu && menu->getVisible()) + { + updateMenuOptions(menu); + menu->needsArrange(); // update menu height if needed + } +} + bool LLFolderView::selectFirstItem() { for (folders_t::iterator iter = mFolders.begin(); diff --git a/indra/newview/llfolderview.h b/indra/newview/llfolderview.h index afaac86b04..210ba9eb3c 100644 --- a/indra/newview/llfolderview.h +++ b/indra/newview/llfolderview.h @@ -269,7 +269,10 @@ public: virtual S32 notify(const LLSD& info) ; bool useLabelSuffix() { return mUseLabelSuffix; } + void updateMenu(); + private: + void updateMenuOptions(LLMenuGL* menu); void updateRenamerPosition(); protected: diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp index 5a9d1524f3..1dcb91ad4d 100644 --- a/indra/newview/llinventorypanel.cpp +++ b/indra/newview/llinventorypanel.cpp @@ -60,6 +60,7 @@ static const LLInventoryFVBridgeBuilder INVENTORY_BRIDGE_BUILDER; // // Bridge to support knowing when the inventory has changed. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + class LLInventoryPanelObserver : public LLInventoryObserver { public: @@ -73,9 +74,57 @@ protected: LLInventoryPanel* mIP; }; +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLInvPanelComplObserver +// +// Calls specified callback when all specified items become complete. +// +// Usage: +// observer = new LLInvPanelComplObserver(boost::bind(onComplete)); +// inventory->addObserver(observer); +// observer->reset(); // (optional) +// observer->watchItem(incomplete_item1_id); +// observer->watchItem(incomplete_item2_id); +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +class LLInvPanelComplObserver : public LLInventoryCompletionObserver +{ +public: + typedef boost::function callback_t; + + LLInvPanelComplObserver(callback_t cb) + : mCallback(cb) + { + } + + void reset(); + +private: + /*virtual*/ void done(); + + /// Called when all the items are complete. + callback_t mCallback; +}; + +void LLInvPanelComplObserver::reset() +{ + mIncomplete.clear(); + mComplete.clear(); +} + +void LLInvPanelComplObserver::done() +{ + mCallback(); +} + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLInventoryPanel +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + LLInventoryPanel::LLInventoryPanel(const LLInventoryPanel::Params& p) : LLPanel(p), mInventoryObserver(NULL), + mCompletionObserver(NULL), mFolderRoot(NULL), mScroller(NULL), mSortOrderSetting(p.sort_order_setting), @@ -152,6 +201,9 @@ void LLInventoryPanel::initFromParams(const LLInventoryPanel::Params& params) mInventoryObserver = new LLInventoryPanelObserver(this); mInventory->addObserver(mInventoryObserver); + mCompletionObserver = new LLInvPanelComplObserver(boost::bind(&LLInventoryPanel::onItemsCompletion, this)); + mInventory->addObserver(mCompletionObserver); + // Build view of inventory if we need default full hierarchy and inventory ready, // otherwise wait for idle callback. if (mBuildDefaultHierarchy && mInventory->isInventoryUsable() && !mViewsInitialized) @@ -189,7 +241,10 @@ LLInventoryPanel::~LLInventoryPanel() // LLView destructor will take care of the sub-views. mInventory->removeObserver(mInventoryObserver); + mInventory->removeObserver(mCompletionObserver); delete mInventoryObserver; + delete mCompletionObserver; + mScroller = NULL; } @@ -654,6 +709,11 @@ void LLInventoryPanel::openStartFolderOrMyInventory() } } +void LLInventoryPanel::onItemsCompletion() +{ + if (mFolderRoot) mFolderRoot->updateMenu(); +} + void LLInventoryPanel::openSelected() { LLFolderViewItem* folder_item = mFolderRoot->getCurSelectedItem(); @@ -757,6 +817,19 @@ void LLInventoryPanel::clearSelection() void LLInventoryPanel::onSelectionChange(const std::deque& items, BOOL user_action) { + // Schedule updating the folder view context menu when all selected items become complete (STORM-373). + mCompletionObserver->reset(); + for (std::deque::const_iterator it = items.begin(); it != items.end(); ++it) + { + LLUUID id = (*it)->getListener()->getUUID(); + LLViewerInventoryItem* inv_item = mInventory->getItem(id); + + if (inv_item && !inv_item->isFinished()) + { + mCompletionObserver->watchItem(id); + } + } + LLFolderView* fv = getRootFolder(); if (fv->needsAutoRename()) // auto-selecting a new user-created asset and preparing to rename { diff --git a/indra/newview/llinventorypanel.h b/indra/newview/llinventorypanel.h index 6545fc0d5e..9da9f7d8ba 100644 --- a/indra/newview/llinventorypanel.h +++ b/indra/newview/llinventorypanel.h @@ -52,6 +52,7 @@ class LLIconCtrl; class LLSaveFolderState; class LLFilterEditor; class LLTabContainer; +class LLInvPanelComplObserver; class LLInventoryPanel : public LLPanel { @@ -167,9 +168,11 @@ public: protected: void openStartFolderOrMyInventory(); // open the first level of inventory + void onItemsCompletion(); // called when selected items are complete LLInventoryModel* mInventory; LLInventoryObserver* mInventoryObserver; + LLInvPanelComplObserver* mCompletionObserver; BOOL mAllowMultiSelect; BOOL mShowItemLinkOverlays; // Shows link graphic over inventory item icons -- cgit v1.2.3 From ff0e3e6177812cdb6b3e044500d50f5d8d10434a Mon Sep 17 00:00:00 2001 From: Paul Guslisty Date: Wed, 19 Jan 2011 13:55:39 +0200 Subject: STORM-547 FIXED Name of blocked person is not presented in list if person was blocked from Inspector - Replaced method call which returns empty string with member containing display name --- indra/newview/llinspectavatar.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/llinspectavatar.cpp b/indra/newview/llinspectavatar.cpp index 91ede6d221..2bb6dbf277 100644 --- a/indra/newview/llinspectavatar.cpp +++ b/indra/newview/llinspectavatar.cpp @@ -704,7 +704,7 @@ void LLInspectAvatar::onClickShare() void LLInspectAvatar::onToggleMute() { - LLMute mute(mAvatarID, mAvatarName.getLegacyName(), LLMute::AGENT); + LLMute mute(mAvatarID, mAvatarName.mDisplayName, LLMute::AGENT); if (LLMuteList::getInstance()->isMuted(mute.mID, mute.mName)) { -- cgit v1.2.3 From ec0eafbaa0e4c4fbf25bab31ed38d90e998e9dbd Mon Sep 17 00:00:00 2001 From: Vadim ProductEngine Date: Wed, 19 Jan 2011 21:41:53 +0200 Subject: STORM-348 FIXED "Edit" and "Lock" buttons appearing on body part items in outfit editor before they are hovered with mouse. Added buttons reshaping code that exists in postBuild() methods of the other LLPanelWearableListItem descendants. --- indra/newview/llwearableitemslist.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/indra/newview/llwearableitemslist.cpp b/indra/newview/llwearableitemslist.cpp index a49dc1b59d..66a6ab5e94 100644 --- a/indra/newview/llwearableitemslist.cpp +++ b/indra/newview/llwearableitemslist.cpp @@ -287,6 +287,9 @@ BOOL LLPanelBodyPartsListItem::postBuild() addWidgetToRightSide("btn_lock"); addWidgetToRightSide("btn_edit_panel"); + setWidgetsVisible(false); + reshapeWidgets(); + return TRUE; } -- cgit v1.2.3 From f91a9c87e5e758ecd32111d901ff32d282b73fa7 Mon Sep 17 00:00:00 2001 From: Dave SIMmONs Date: Wed, 19 Jan 2011 12:54:05 -0800 Subject: ER-428 / CTS-422 : [PUBLIC] movement updates are lost when walking. Changed code to detect if the circuit has stopped getting packets. Reviewed by Andrew --- indra/llmessage/llcircuit.cpp | 3 +++ indra/llmessage/llcircuit.h | 4 +++- indra/newview/llviewerobject.cpp | 14 ++++++-------- indra/newview/llviewerobject.h | 1 - 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/indra/llmessage/llcircuit.cpp b/indra/llmessage/llcircuit.cpp index 3ba2dfb104..e0410906fb 100644 --- a/indra/llmessage/llcircuit.cpp +++ b/indra/llmessage/llcircuit.cpp @@ -87,6 +87,7 @@ LLCircuitData::LLCircuitData(const LLHost &host, TPACKETID in_id, mPingDelayAveraged((F32)INITIAL_PING_VALUE_MSEC), mUnackedPacketCount(0), mUnackedPacketBytes(0), + mLastPacketInTime(0.0), mLocalEndPointID(), mPacketsOut(0), mPacketsIn(0), @@ -667,6 +668,8 @@ void LLCircuitData::checkPacketInID(TPACKETID id, BOOL receive_resent) mHighestPacketID = llmax(mHighestPacketID, id); } + // Save packet arrival time + mLastPacketInTime = LLMessageSystem::getMessageTimeSeconds(); // Have we received anything on this circuit yet? if (0 == mPacketsIn) diff --git a/indra/llmessage/llcircuit.h b/indra/llmessage/llcircuit.h index 874c0c0bee..d1c400c6a2 100644 --- a/indra/llmessage/llcircuit.h +++ b/indra/llmessage/llcircuit.h @@ -122,7 +122,7 @@ public: U32 getPacketsLost() const; TPACKETID getPacketOutID() const; BOOL getTrusted() const; - F32 getAgeInSeconds() const; + F32 getAgeInSeconds() const; S32 getUnackedPacketCount() const { return mUnackedPacketCount; } S32 getUnackedPacketBytes() const { return mUnackedPacketBytes; } F64 getNextPingSendTime() const { return mNextPingSendTime; } @@ -130,6 +130,7 @@ public: { return mOutOfOrderRate.meanValue(scale); } U32 getLastPacketGap() const { return mLastPacketGap; } LLHost getHost() const { return mHost; } + F64 getLastPacketInTime() const { return mLastPacketInTime; } LLThrottleGroup &getThrottleGroup() { return mThrottles; } @@ -248,6 +249,7 @@ protected: S32 mUnackedPacketCount; S32 mUnackedPacketBytes; + F64 mLastPacketInTime; // Time of last packet arrival LLUUID mLocalEndPointID; diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 48794c4c9d..090d3cadd4 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -210,7 +210,6 @@ LLViewerObject::LLViewerObject(const LLUUID &id, const LLPCode pcode, LLViewerRe mLastInterpUpdateSecs(0.f), mLastMessageUpdateSecs(0.f), mLatestRecvPacketID(0), - mCircuitPacketCount(0), mData(NULL), mAudioSourcep(NULL), mAudioGain(1.f), @@ -1884,7 +1883,6 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, } mLatestRecvPacketID = packet_id; - mCircuitPacketCount = 0; // Set the change flags for scale if (new_scale != getScale()) @@ -2207,7 +2205,8 @@ void LLViewerObject::interpolateLinearMotion(const F64 & time, const F32 & dt) LLVector3 new_pos = (vel + (0.5f * (dt-PHYSICS_TIMESTEP)) * accel) * dt; LLVector3 new_v = accel * dt; - if (time_since_last_update > sPhaseOutUpdateInterpolationTime) + if (time_since_last_update > sPhaseOutUpdateInterpolationTime && + sPhaseOutUpdateInterpolationTime > 0.0) { // Haven't seen a viewer update in a while, check to see if the ciruit is still active if (mRegionp) { // The simulator will NOT send updates if the object continues normally on the path @@ -2216,9 +2215,12 @@ void LLViewerObject::interpolateLinearMotion(const F64 & time, const F32 & dt) LLCircuitData *cdp = gMessageSystem->mCircuitInfo.findCircuit( mRegionp->getHost() ); if (cdp) { + // Find out how many seconds since last packet arrived on the circuit + F64 time_since_last_packet = LLMessageSystem::getMessageTimeSeconds() - cdp->getLastPacketInTime(); + if (!cdp->isAlive() || // Circuit is dead or blocked cdp->isBlocked() || // or doesn't seem to be getting any packets - (mCircuitPacketCount > 0 && mCircuitPacketCount == cdp->getPacketsIn())) + (time_since_last_packet > sPhaseOutUpdateInterpolationTime)) { // Start to reduce motion interpolation since we haven't seen a server update in a while F64 time_since_last_interpolation = time - mLastInterpUpdateSecs; @@ -2249,9 +2251,6 @@ void LLViewerObject::interpolateLinearMotion(const F64 & time, const F32 & dt) new_pos = new_pos * ((F32) phase_out); new_v = new_v * ((F32) phase_out); } - - // Save current circuit packet count to see if it changes - mCircuitPacketCount = cdp->getPacketsIn(); } } } @@ -5105,7 +5104,6 @@ void LLViewerObject::setRegion(LLViewerRegion *regionp) } mLatestRecvPacketID = 0; - mCircuitPacketCount = 0; mRegionp = regionp; for (child_list_t::iterator i = mChildList.begin(); i != mChildList.end(); ++i) diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index 614a5e59fa..7afb7f464b 100644 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -613,7 +613,6 @@ protected: F64 mLastInterpUpdateSecs; // Last update for purposes of interpolation F64 mLastMessageUpdateSecs; // Last update from a message from the simulator TPACKETID mLatestRecvPacketID; // Latest time stamp on message from simulator - U32 mCircuitPacketCount; // Packet tracking for early detection of a stopped simulator circuit // extra data sent from the sim...currently only used for tree species info U8* mData; -- cgit v1.2.3 From 47e31543932815adf89712229c0ad71b17d8a0f1 Mon Sep 17 00:00:00 2001 From: Xiaohong Bao Date: Wed, 19 Jan 2011 21:17:38 -0700 Subject: fix for SH-730: sculpted prim attachment shapes on impostored avatars load very slowly --- indra/newview/llviewertexture.cpp | 3 +++ indra/newview/llvovolume.cpp | 32 +++++++++++++++++++++++--------- indra/newview/llvovolume.h | 1 + indra/newview/pipeline.cpp | 34 +++++++++++++++++----------------- 4 files changed, 44 insertions(+), 26 deletions(-) diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index f96b93da4d..1c246a5c87 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -1205,12 +1205,15 @@ void LLViewerFetchedTexture::cleanup() void LLViewerFetchedTexture::setForSculpt() { + static const S32 MAX_INTERVAL = 8 ; //frames + mForSculpt = TRUE ; if(isForSculptOnly() && !getBoundRecently()) { destroyGLTexture() ; //sculpt image does not need gl texture. } checkCachedRawSculptImage() ; + setMaxVirtualSizeResetInterval(MAX_INTERVAL) ; } BOOL LLViewerFetchedTexture::isForSculptOnly() const diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 858e0321e1..f67e3a9770 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -669,11 +669,32 @@ void LLVOVolume::updateTextures() } } +BOOL LLVOVolume::isVisible() const +{ + if(mDrawable.notNull() && mDrawable->isVisible()) + { + return TRUE ; + } + + if(isAttachment()) + { + LLViewerObject* objp = (LLViewerObject*)getParent() ; + while(objp && !objp->isAvatar()) + { + objp = (LLViewerObject*)objp->getParent() ; + } + + return objp && objp->mDrawable.notNull() && objp->mDrawable->isVisible() ; + } + + return FALSE ; +} + void LLVOVolume::updateTextureVirtualSize() { // Update the pixel area of all faces - if(mDrawable.isNull() || !mDrawable->isVisible()) + if(!isVisible()) { return ; } @@ -2740,14 +2761,7 @@ void LLVOVolume::updateRadius() BOOL LLVOVolume::isAttachment() const { - if (mState == 0) - { - return FALSE; - } - else - { - return TRUE; - } + return mState != 0 ; } BOOL LLVOVolume::isHUDAttachment() const diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h index 1e9b9737b1..8b68e7c78a 100644 --- a/indra/newview/llvovolume.h +++ b/indra/newview/llvovolume.h @@ -102,6 +102,7 @@ public: void animateTextures(); /*virtual*/ BOOL idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time); + BOOL isVisible() const ; /*virtual*/ BOOL isActive() const; /*virtual*/ BOOL isAttachment() const; /*virtual*/ BOOL isRootEdit() const; // overridden for sake of attachments treating themselves as a root object diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index e6c6c74fce..db5d6ac4ef 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -1969,12 +1969,12 @@ void LLPipeline::markVisible(LLDrawable *drawablep, LLCamera& camera) if(drawablep && !drawablep->isDead()) { - if (drawablep->isSpatialBridge()) - { + if (drawablep->isSpatialBridge()) + { const LLDrawable* root = ((LLSpatialBridge*) drawablep)->mDrawable; llassert(root); // trying to catch a bad assumption if (root && // // this test may not be needed, see above - root->getVObj()->isAttachment()) + root->getVObj()->isAttachment()) { LLDrawable* rootparent = root->getParent(); if (rootparent) // this IS sometimes NULL @@ -1982,24 +1982,24 @@ void LLPipeline::markVisible(LLDrawable *drawablep, LLCamera& camera) LLViewerObject *vobj = rootparent->getVObj(); llassert(vobj); // trying to catch a bad assumption if (vobj) // this test may not be needed, see above - { + { const LLVOAvatar* av = vobj->asAvatar(); - if (av && av->isImpostor()) - { - return; - } - } + if (av && av->isImpostor()) + { + return; + } + } } } - sCull->pushBridge((LLSpatialBridge*) drawablep); - } - else - { - sCull->pushDrawable(drawablep); - } + sCull->pushBridge((LLSpatialBridge*) drawablep); + } + else + { + sCull->pushDrawable(drawablep); + } - drawablep->setVisible(camera); -} + drawablep->setVisible(camera); + } } void LLPipeline::markMoved(LLDrawable *drawablep, BOOL damped_motion) -- cgit v1.2.3 From 80d7432ce6f0f16f31bb103965b64b39575728a2 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Thu, 20 Jan 2011 14:26:57 -0500 Subject: VWR-13040 - clean up LLObjectSelection iterator --- doc/contributions.txt | 1 + indra/newview/llselectmgr.h | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/contributions.txt b/doc/contributions.txt index 361560a0ed..d533486936 100644 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -72,6 +72,7 @@ Aleric Inglewood VWR-10837 VWR-12691 VWR-12984 + VWR-13040 VWR-13996 VWR-14426 VWR-24247 diff --git a/indra/newview/llselectmgr.h b/indra/newview/llselectmgr.h index 7478ed5f9a..65a9a493f6 100644 --- a/indra/newview/llselectmgr.h +++ b/indra/newview/llselectmgr.h @@ -235,7 +235,7 @@ public: { bool operator()(LLSelectNode* node); }; - typedef boost::filter_iterator valid_root_iterator; + typedef boost::filter_iterator valid_root_iterator; valid_root_iterator valid_root_begin() { return valid_root_iterator(mList.begin(), mList.end()); } valid_root_iterator valid_root_end() { return valid_root_iterator(mList.end(), mList.end()); } -- cgit v1.2.3 From 42604a1080d2080be748bca80ff84fec24024c63 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Thu, 20 Jan 2011 14:35:04 -0500 Subject: VWR-24315: update cached control values when resetting debug setting to default --- doc/contributions.txt | 1 + indra/newview/llfloatersettingsdebug.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/contributions.txt b/doc/contributions.txt index d533486936..0c83be89c2 100644 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -80,6 +80,7 @@ Aleric Inglewood VWR-24252 VWR-24254 VWR-24261 + VWR-24315 SNOW-84 SNOW-477 SNOW-744 diff --git a/indra/newview/llfloatersettingsdebug.cpp b/indra/newview/llfloatersettingsdebug.cpp index 71882fbb83..07f5220ab7 100644 --- a/indra/newview/llfloatersettingsdebug.cpp +++ b/indra/newview/llfloatersettingsdebug.cpp @@ -178,7 +178,7 @@ void LLFloaterSettingsDebug::onClickDefault() if (controlp) { - controlp->resetToDefault(); + controlp->resetToDefault(true); updateControl(controlp); } } -- cgit v1.2.3 From 466413cdf094c78c85a509e70739417d5950210c Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Thu, 20 Jan 2011 14:44:06 -0500 Subject: VWR-24317: clean up incorrect warnings prior to login in log file --- indra/newview/llappviewer.cpp | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index d1e9b24ef6..88c57a1433 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -3076,35 +3076,32 @@ void LLAppViewer::initMarkerFile() std::string llerror_marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, LLERROR_MARKER_FILE_NAME); std::string error_marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, ERROR_MARKER_FILE_NAME); - if (LLAPRFile::isExist(mMarkerFileName, NULL, LL_APR_RB) && !anotherInstanceRunning()) { gLastExecEvent = LAST_EXEC_FROZE; LL_INFOS("MarkerFile") << "Exec marker found: program froze on previous execution" << LL_ENDL; } - if(LLAPRFile::isExist(logout_marker_file, NULL, LL_APR_RB)) { - LL_INFOS("MarkerFile") << "Last exec LLError crashed, setting LastExecEvent to " << LAST_EXEC_LLERROR_CRASH << LL_ENDL; gLastExecEvent = LAST_EXEC_LOGOUT_FROZE; + LL_INFOS("MarkerFile") << "Last exec LLError crashed, setting LastExecEvent to " << gLastExecEvent << LL_ENDL; + LLAPRFile::remove(logout_marker_file); } if(LLAPRFile::isExist(llerror_marker_file, NULL, LL_APR_RB)) { - llinfos << "Last exec LLError crashed, setting LastExecEvent to " << LAST_EXEC_LLERROR_CRASH << llendl; if(gLastExecEvent == LAST_EXEC_LOGOUT_FROZE) gLastExecEvent = LAST_EXEC_LOGOUT_CRASH; else gLastExecEvent = LAST_EXEC_LLERROR_CRASH; + LL_INFOS("MarkerFile") << "Last exec LLError crashed, setting LastExecEvent to " << gLastExecEvent << LL_ENDL; + LLAPRFile::remove(llerror_marker_file); } if(LLAPRFile::isExist(error_marker_file, NULL, LL_APR_RB)) { - LL_INFOS("MarkerFile") << "Last exec crashed, setting LastExecEvent to " << LAST_EXEC_OTHER_CRASH << LL_ENDL; if(gLastExecEvent == LAST_EXEC_LOGOUT_FROZE) gLastExecEvent = LAST_EXEC_LOGOUT_CRASH; else gLastExecEvent = LAST_EXEC_OTHER_CRASH; + LL_INFOS("MarkerFile") << "Last exec crashed, setting LastExecEvent to " << gLastExecEvent << LL_ENDL; + LLAPRFile::remove(error_marker_file); } - - LLAPRFile::remove(logout_marker_file); - LLAPRFile::remove(llerror_marker_file); - LLAPRFile::remove(error_marker_file); - + // No new markers if another instance is running. if(anotherInstanceRunning()) { -- cgit v1.2.3 From e9c6800e231f85266521d36f0fba427420dd632a Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Thu, 20 Jan 2011 14:57:33 -0500 Subject: VWR-24317: remove warnings for deleting non-existant texture file on startup --- indra/newview/lltexturecache.cpp | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/indra/newview/lltexturecache.cpp b/indra/newview/lltexturecache.cpp index 6a213309a0..92080d1fd7 100644 --- a/indra/newview/lltexturecache.cpp +++ b/indra/newview/lltexturecache.cpp @@ -1858,8 +1858,22 @@ void LLTextureCache::removeCachedTexture(const LLUUID& id) //called after mHeaderMutex is locked. void LLTextureCache::removeEntry(S32 idx, Entry& entry, std::string& filename) { + bool file_maybe_exists = true; // Always attempt to remove when idx is invalid. + if(idx >= 0) //valid entry { + if (entry.mBodySize == 0) // Always attempt to remove when mBodySize > 0. + { + if (LLAPRFile::isExist(filename, getLocalAPRFilePool())) // Sanity check. Shouldn't exist when body size is 0. + { + LL_WARNS("TextureCache") << "Entry has body size of zero but file " << filename << " exists. Deleting this file, too." << LL_ENDL; + } + else + { + file_maybe_exists = false; + } + } + entry.mImageSize = -1; entry.mBodySize = 0; mHeaderIDMap.erase(entry.mID); @@ -1869,7 +1883,10 @@ void LLTextureCache::removeEntry(S32 idx, Entry& entry, std::string& filename) mFreeList.insert(idx); } - LLAPRFile::remove(filename, getLocalAPRFilePool()); + if (file_maybe_exists) + { + LLAPRFile::remove(filename, getLocalAPRFilePool()); + } } bool LLTextureCache::removeFromCache(const LLUUID& id) -- cgit v1.2.3 From 9b341ec012a832bfcc98eb3f273ffc749ae95d47 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Thu, 20 Jan 2011 15:03:48 -0500 Subject: VWR-24317: remove warning caused by reading the last line of the featuretable twice --- indra/newview/llfeaturemanager.cpp | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/indra/newview/llfeaturemanager.cpp b/indra/newview/llfeaturemanager.cpp index ca2ef5f5b8..4e16cc4217 100644 --- a/indra/newview/llfeaturemanager.cpp +++ b/indra/newview/llfeaturemanager.cpp @@ -290,11 +290,9 @@ BOOL LLFeatureManager::parseFeatureTable(std::string filename) mTableVersion = version; LLFeatureList *flp = NULL; - while (!file.eof() && file.good()) + while (file >> name) { char buffer[MAX_STRING]; /*Flawfinder: ignore*/ - - file >> name; if (name.substr(0,2) == "//") { @@ -303,13 +301,6 @@ BOOL LLFeatureManager::parseFeatureTable(std::string filename) continue; } - if (name.empty()) - { - // This is a blank line - file.getline(buffer, MAX_STRING); - continue; - } - if (name == "list") { if (flp) -- cgit v1.2.3 From ad34f858dc5047a5e4c2fc3dcabbd24f7663e00d Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Thu, 20 Jan 2011 15:52:37 -0500 Subject: VWR-24317: remove warning re: RenderCubeMap by deferring initialization --- indra/newview/llappviewer.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 88c57a1433..e2af22a678 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -473,8 +473,6 @@ static void settings_to_globals() gDebugWindowProc = gSavedSettings.getBOOL("DebugWindowProc"); gShowObjectUpdates = gSavedSettings.getBOOL("ShowObjectUpdates"); LLWorldMapView::sMapScale = gSavedSettings.getF32("MapScale"); - - LLCubeMap::sUseCubeMaps = LLFeatureManager::getInstance()->isFeatureAvailable("RenderCubeMap"); } static void settings_modify() @@ -854,6 +852,9 @@ bool LLAppViewer::init() gGLActive = TRUE; initWindow(); + // initWindow also initializes the Feature List, so now we can initialize this global. + LLCubeMap::sUseCubeMaps = LLFeatureManager::getInstance()->isFeatureAvailable("RenderCubeMap"); + // call all self-registered classes LLInitClassList::instance().fireCallbacks(); -- cgit v1.2.3 From a873ae55a36c4470d7e03e3544545ac164edee29 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Thu, 20 Jan 2011 15:57:07 -0500 Subject: VWR-24317: remove warning due to unassigned variable --- doc/contributions.txt | 1 + indra/llui/llnotifications.cpp | 6 ++---- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/doc/contributions.txt b/doc/contributions.txt index 0c83be89c2..3b2e2239d2 100644 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -81,6 +81,7 @@ Aleric Inglewood VWR-24254 VWR-24261 VWR-24315 + VWR-24317 SNOW-84 SNOW-477 SNOW-744 diff --git a/indra/llui/llnotifications.cpp b/indra/llui/llnotifications.cpp index cd0f0e36b0..cc9edfcdea 100644 --- a/indra/llui/llnotifications.cpp +++ b/indra/llui/llnotifications.cpp @@ -1367,7 +1367,6 @@ LLNotifications::TemplateNames LLNotifications::getTemplateNames() const typedef std::map StringMap; void replaceSubstitutionStrings(LLXMLNodePtr node, StringMap& replacements) { - //llwarns << "replaceSubstitutionStrings" << llendl; // walk the list of attributes looking for replacements for (LLXMLAttribList::iterator it=node->mAttributes.begin(); it != node->mAttributes.end(); ++it) @@ -1381,13 +1380,12 @@ void replaceSubstitutionStrings(LLXMLNodePtr node, StringMap& replacements) if (found != replacements.end()) { replacement = found->second; - //llwarns << "replaceSubstituionStrings: value: " << value << " repl: " << replacement << llendl; - + lldebugs << "replaceSubstitutionStrings: value: \"" << value << "\" repl: \"" << replacement << "\"." << llendl; it->second->setValue(replacement); } else { - llwarns << "replaceSubstituionStrings FAILURE: value: " << value << " repl: " << replacement << llendl; + llwarns << "replaceSubstitutionStrings FAILURE: could not find replacement \"" << value << "\"." << llendl; } } } -- cgit v1.2.3 From c47ab36b20e102a918257e5fa5452f13bc55a393 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Thu, 20 Jan 2011 16:01:27 -0500 Subject: VWR-24320: remove dump of call stack on clean exit --- doc/contributions.txt | 1 + indra/newview/llappviewer.cpp | 10 ---------- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/doc/contributions.txt b/doc/contributions.txt index 3b2e2239d2..1ec878846d 100644 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -82,6 +82,7 @@ Aleric Inglewood VWR-24261 VWR-24315 VWR-24317 + VWR-24320 SNOW-84 SNOW-477 SNOW-744 diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index e2af22a678..6a9dfaf21b 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -1398,16 +1398,6 @@ bool LLAppViewer::cleanup() } mPlugins.clear(); - //---------------------------------------------- - //this test code will be removed after the test - //test manual call stack tracer - if(gSavedSettings.getBOOL("QAMode")) - { - LLError::LLCallStacks::print() ; - } - //end of the test code - //---------------------------------------------- - //flag all elements as needing to be destroyed immediately // to ensure shutdown order LLMortician::setZealous(TRUE); -- cgit v1.2.3 From e3f5b66d5a649b061e470bba44fa29a56f7b93b5 Mon Sep 17 00:00:00 2001 From: Xiaohong Bao Date: Thu, 20 Jan 2011 15:20:27 -0700 Subject: fix for SH-829: Viewer attempting to load precached images in file types that are not being used. --- indra/llimage/llimage.cpp | 18 +++++++++--------- indra/llimage/llimage.h | 4 ++-- indra/newview/lltexturecache.cpp | 6 ++++++ 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index 5c33b675ca..38396916c7 100644 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -276,11 +276,11 @@ LLImageRaw::LLImageRaw(U8 *data, U16 width, U16 height, S8 components) ++sRawImageCount; } -LLImageRaw::LLImageRaw(const std::string& filename, bool j2c_lowest_mip_only) - : LLImageBase() -{ - createFromFile(filename, j2c_lowest_mip_only); -} +//LLImageRaw::LLImageRaw(const std::string& filename, bool j2c_lowest_mip_only) +// : LLImageBase() +//{ +// createFromFile(filename, j2c_lowest_mip_only); +//} LLImageRaw::~LLImageRaw() { @@ -1180,7 +1180,7 @@ file_extensions[] = { "png", IMG_CODEC_PNG } }; #define NUM_FILE_EXTENSIONS LL_ARRAY_SIZE(file_extensions) - +#if 0 static std::string find_file(std::string &name, S8 *codec) { std::string tname; @@ -1198,7 +1198,7 @@ static std::string find_file(std::string &name, S8 *codec) } return std::string(""); } - +#endif EImageCodec LLImageBase::getCodecFromExtension(const std::string& exten) { for (int i=0; i<(int)(NUM_FILE_EXTENSIONS); i++) @@ -1208,7 +1208,7 @@ EImageCodec LLImageBase::getCodecFromExtension(const std::string& exten) } return IMG_CODEC_INVALID; } - +#if 0 bool LLImageRaw::createFromFile(const std::string &filename, bool j2c_lowest_mip_only) { std::string name = filename; @@ -1315,7 +1315,7 @@ bool LLImageRaw::createFromFile(const std::string &filename, bool j2c_lowest_mip return true; } - +#endif //--------------------------------------------------------------------------- // LLImageFormatted //--------------------------------------------------------------------------- diff --git a/indra/llimage/llimage.h b/indra/llimage/llimage.h index bca7e915fa..825b9aab1a 100644 --- a/indra/llimage/llimage.h +++ b/indra/llimage/llimage.h @@ -164,7 +164,7 @@ public: LLImageRaw(U16 width, U16 height, S8 components); LLImageRaw(U8 *data, U16 width, U16 height, S8 components); // Construct using createFromFile (used by tools) - LLImageRaw(const std::string& filename, bool j2c_lowest_mip_only = false); + //LLImageRaw(const std::string& filename, bool j2c_lowest_mip_only = false); /*virtual*/ void deleteData(); /*virtual*/ U8* allocateData(S32 size = -1); @@ -226,7 +226,7 @@ public: protected: // Create an image from a local file (generally used in tools) - bool createFromFile(const std::string& filename, bool j2c_lowest_mip_only = false); + //bool createFromFile(const std::string& filename, bool j2c_lowest_mip_only = false); void copyLineScaled( U8* in, U8* out, S32 in_pixel_len, S32 out_pixel_len, S32 in_pixel_step, S32 out_pixel_step ); void compositeRowScaled4onto3( U8* in, U8* out, S32 in_pixel_len, S32 out_pixel_len ); diff --git a/indra/newview/lltexturecache.cpp b/indra/newview/lltexturecache.cpp index 6a213309a0..83772496d5 100644 --- a/indra/newview/lltexturecache.cpp +++ b/indra/newview/lltexturecache.cpp @@ -326,6 +326,7 @@ bool LLTextureCacheRemoteWorker::doRead() // First state / stage : find out if the file is local if (mState == INIT) { +#if 0 std::string filename = mCache->getLocalFileName(mID); // Is it a JPEG2000 file? { @@ -360,6 +361,11 @@ bool LLTextureCacheRemoteWorker::doRead() } // Determine the next stage: if we found a file, then LOCAL else CACHE mState = (local_size > 0 ? LOCAL : CACHE); + + llassert_always(mState == CACHE) ; +#else + mState = CACHE; +#endif } // Second state / stage : if the file is local, load it and leave -- cgit v1.2.3 From 97a9211d87fac90994846e5bf91a78a708ec5a9c Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Fri, 21 Jan 2011 15:48:12 -0500 Subject: VWR-24354: correct manifest dependencies to prevent parallel install problem --- doc/contributions.txt | 1 + indra/newview/CMakeLists.txt | 34 ++++++++++++++++++++++------------ 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/doc/contributions.txt b/doc/contributions.txt index 70ae5a2ba5..b601f93806 100644 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -83,6 +83,7 @@ Aleric Inglewood VWR-24315 VWR-24317 VWR-24320 + VWR-24354 SNOW-84 SNOW-477 SNOW-744 diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 5d2342e925..af6beacdfa 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -1718,6 +1718,17 @@ set(ARTWORK_DIR ${CMAKE_CURRENT_SOURCE_DIR} CACHE PATH if (LINUX) set(product SecondLife-${ARCH}-${viewer_VERSION}) + # These are the generated targets that are copied to package/ + set(COPY_INPUT_DEPENDENCIES + ${VIEWER_BINARY_NAME} + linux-crash-logger + linux-updater + SLPlugin + media_plugin_webkit + media_plugin_gstreamer010 + llcommon + ) + add_custom_command( OUTPUT ${product}.tar.bz2 COMMAND ${PYTHON_EXECUTABLE} @@ -1735,18 +1746,11 @@ if (LINUX) --login_channel=${VIEWER_LOGIN_CHANNEL} --source=${CMAKE_CURRENT_SOURCE_DIR} --touch=${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/.${product}.touched - DEPENDS ${VIEWER_BINARY_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py + DEPENDS + ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py + ${COPY_INPUT_DEPENDENCIES} ) - add_dependencies(${VIEWER_BINARY_NAME} SLPlugin media_plugin_gstreamer010 media_plugin_webkit) - - if (PACKAGE) - add_custom_target(package ALL DEPENDS ${product}.tar.bz2) - add_dependencies(package linux-crash-logger-target) - add_dependencies(package linux-updater-target) - check_message_template(package) - endif (PACKAGE) - add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/.${product}.copy_touched COMMAND ${PYTHON_EXECUTABLE} @@ -1766,9 +1770,15 @@ if (LINUX) ${COPY_INPUT_DEPENDENCIES} COMMENT "Performing viewer_manifest copy" ) - + add_custom_target(copy_l_viewer_manifest ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/.${product}.copy_touched) - add_dependencies(copy_l_viewer_manifest "${VIEWER_BINARY_NAME}" linux-crash-logger-target linux-updater-target) + + if (PACKAGE) + add_custom_target(package ALL DEPENDS ${product}.tar.bz2) + # Make sure we don't run two instances of viewer_manifest.py at the same time. + add_dependencies(package copy_l_viewer_manifest) + check_message_template(package) + endif (PACKAGE) endif (LINUX) if (DARWIN) -- cgit v1.2.3 From ee6a40beb102819fcd2e95106fe7892d2d25193f Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Fri, 21 Jan 2011 16:02:38 -0500 Subject: VWR-24519: make debugging easier by not spawning spare process --- doc/contributions.txt | 1 + indra/newview/llviewermedia.cpp | 10 +++++++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/doc/contributions.txt b/doc/contributions.txt index b601f93806..66533d8da9 100644 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -84,6 +84,7 @@ Aleric Inglewood VWR-24317 VWR-24320 VWR-24354 + VWR-24519 SNOW-84 SNOW-477 SNOW-744 diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index d3b6dcd86f..ed18d67b62 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -1436,9 +1436,12 @@ void LLViewerMedia::proxyWindowClosed(const std::string &uuid) // static void LLViewerMedia::createSpareBrowserMediaSource() { - if(!sSpareBrowserMediaSource) + // If we don't have a spare browser media source, create one. + // However, if PluginAttachDebuggerToPlugins is set then don't spawn a spare + // SLPlugin process in order to not be confused by an unrelated gdb terminal + // popping up at the moment we start a media plugin. + if (!sSpareBrowserMediaSource && !gSavedSettings.getBOOL("PluginAttachDebuggerToPlugins")) { - // If we don't have a spare browser media source, create one. // The null owner will keep the browser plugin from fully initializing // (specifically, it keeps LLPluginClassMedia from negotiating a size change, // which keeps MediaPluginWebkit::initBrowserWindow from doing anything until we have some necessary data, like the background color) @@ -1694,7 +1697,8 @@ LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_ LLPluginClassMedia* media_source = NULL; // HACK: we always try to keep a spare running webkit plugin around to improve launch times. - if(plugin_basename == "media_plugin_webkit") + // If a spare was already created before PluginAttachDebuggerToPlugins was set, don't use it. + if(plugin_basename == "media_plugin_webkit" && !gSavedSettings.getBOOL("PluginAttachDebuggerToPlugins")) { media_source = LLViewerMedia::getSpareBrowserMediaSource(); if(media_source) -- cgit v1.2.3 From 7a453b7c9351a743b222bbb2b94809cf7c6b3ce8 Mon Sep 17 00:00:00 2001 From: Oz Linden Date: Fri, 21 Jan 2011 16:20:29 -0500 Subject: add missing entry in contributions.txt for VWR-24347 --- doc/contributions.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/contributions.txt b/doc/contributions.txt index 66533d8da9..5255acc041 100644 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -384,6 +384,7 @@ Jonathan Yap STORM-785 STORM-812 VWR-17801 + VWR-24347 STORM-844 Kage Pixel VWR-11 -- cgit v1.2.3 From 295536ae98cb88bfa551ac73ae2e19a8c2ddfc88 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Mon, 24 Jan 2011 09:35:41 -0500 Subject: VWR-24321: fix validation of textures that start with 00 --- doc/contributions.txt | 1 + indra/newview/lltexturecache.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/contributions.txt b/doc/contributions.txt index 5255acc041..4e91bbdd36 100644 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -83,6 +83,7 @@ Aleric Inglewood VWR-24315 VWR-24317 VWR-24320 + VWR-24321 VWR-24354 VWR-24519 SNOW-84 diff --git a/indra/newview/lltexturecache.cpp b/indra/newview/lltexturecache.cpp index 92080d1fd7..6ddbdbf783 100644 --- a/indra/newview/lltexturecache.cpp +++ b/indra/newview/lltexturecache.cpp @@ -1592,7 +1592,7 @@ void LLTextureCache::purgeTextures(bool validate) if (validate) { validate_idx = gSavedSettings.getU32("CacheValidateCounter"); - U32 next_idx = (++validate_idx) % 256; + U32 next_idx = (validate_idx + 1) % 256; gSavedSettings.setU32("CacheValidateCounter", next_idx); LL_DEBUGS("TextureCache") << "TEXTURE CACHE: Validating: " << validate_idx << LL_ENDL; } -- cgit v1.2.3 From 5322021746582195df6b7ad5843a7da09e617917 Mon Sep 17 00:00:00 2001 From: Jonathan Yap Date: Mon, 24 Jan 2011 16:22:03 -0500 Subject: STORM-845 Icon for nearby chat and nearby voice now is a down arrow when floater is open --- doc/contributions.txt | 1 + indra/newview/skins/default/textures/textures.xml | 1 + indra/newview/skins/default/xui/en/panel_nearby_chat_bar.xml | 4 ++-- indra/newview/skins/default/xui/en/widgets/talk_button.xml | 10 +++++----- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/doc/contributions.txt b/doc/contributions.txt index 5255acc041..83d7e573a8 100644 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -386,6 +386,7 @@ Jonathan Yap VWR-17801 VWR-24347 STORM-844 + STORM-845 Kage Pixel VWR-11 Ken March diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml index 2c00120177..7b3cc7bdfa 100644 --- a/indra/newview/skins/default/textures/textures.xml +++ b/indra/newview/skins/default/textures/textures.xml @@ -107,6 +107,7 @@ with the same filename but different name + diff --git a/indra/newview/skins/default/xui/en/panel_nearby_chat_bar.xml b/indra/newview/skins/default/xui/en/panel_nearby_chat_bar.xml index 5871eb0654..21c627cdfb 100644 --- a/indra/newview/skins/default/xui/en/panel_nearby_chat_bar.xml +++ b/indra/newview/skins/default/xui/en/panel_nearby_chat_bar.xml @@ -45,9 +45,9 @@ left_pad="4" image_disabled="ComboButton_UpOff" image_unselected="ComboButton_UpOff" - image_selected="ComboButton_Up_On_Selected" + image_selected="ComboButton_On" image_pressed="ComboButton_UpSelected" - image_pressed_selected="ComboButton_Up_On_Selected" + image_pressed_selected="ComboButton_Selected" height="23" name="show_nearby_chat" tool_tip="Shows/hides nearby chat log"> diff --git a/indra/newview/skins/default/xui/en/widgets/talk_button.xml b/indra/newview/skins/default/xui/en/widgets/talk_button.xml index a7e271a1ff..d792e9f29c 100644 --- a/indra/newview/skins/default/xui/en/widgets/talk_button.xml +++ b/indra/newview/skins/default/xui/en/widgets/talk_button.xml @@ -23,11 +23,11 @@ bottom="0" tab_stop="false" is_toggle="true" - image_selected="SegmentedBtn_Right_Selected_Press" - image_unselected="SegmentedBtn_Right_Off" - image_pressed="SegmentedBtn_Right_Press" - image_pressed_selected="SegmentedBtn_Right_Selected_Press" - image_overlay="Arrow_Small_Up" + image_disabled="ComboButton_UpOff" + image_unselected="ComboButton_UpOff" + image_selected="ComboButton_On" + image_pressed="ComboButton_UpSelected" + image_pressed_selected="ComboButton_Selected" /> Date: Mon, 24 Jan 2011 15:50:46 -0700 Subject: fix for SH-445: debug settings -> "CacheNumberOfRegionsForObjects" does not limit the number of object cache files --- indra/newview/app_settings/settings.xml | 2 +- indra/newview/llvocache.cpp | 20 +++++++++++++------- indra/newview/llvocache.h | 2 +- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 819808ec40..ced46c7294 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -1179,7 +1179,7 @@ Type U32 Value - 20000 + 128 CacheSize diff --git a/indra/newview/llvocache.cpp b/indra/newview/llvocache.cpp index 1e2736f7d9..b3312db4a0 100644 --- a/indra/newview/llvocache.cpp +++ b/indra/newview/llvocache.cpp @@ -517,6 +517,11 @@ void LLVOCache::readCacheHeader() { removeCache() ; //failed to read header, clear the cache } + else if(mNumEntries >= mCacheSize) + { + purgeEntries(mCacheSize) ; + } + return ; } @@ -644,9 +649,9 @@ void LLVOCache::readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::voca return ; } -void LLVOCache::purgeEntries() +void LLVOCache::purgeEntries(U32 size) { - while(mHeaderEntryQueue.size() >= mCacheSize) + while(mHeaderEntryQueue.size() >= size) { header_entry_queue_t::iterator iter = mHeaderEntryQueue.begin() ; HeaderEntryInfo* entry = *iter ; @@ -671,16 +676,17 @@ void LLVOCache::writeToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry: { llwarns << "Not writing cache for handle " << handle << "): Cache is currently in read-only mode." << llendl; return ; - } - if(mNumEntries >= mCacheSize) - { - purgeEntries() ; - } + } HeaderEntryInfo* entry; handle_entry_map_t::iterator iter = mHandleEntryMap.find(handle) ; if(iter == mHandleEntryMap.end()) //new entry { + if(mNumEntries >= mCacheSize - 1) + { + purgeEntries(mCacheSize - 1) ; + } + entry = new HeaderEntryInfo(); entry->mHandle = handle ; entry->mTime = time(NULL) ; diff --git a/indra/newview/llvocache.h b/indra/newview/llvocache.h index 1070fcaae9..14e3b4c793 100644 --- a/indra/newview/llvocache.h +++ b/indra/newview/llvocache.h @@ -130,7 +130,7 @@ private: void clearCacheInMemory(); void removeCache() ; void removeEntry(HeaderEntryInfo* entry) ; - void purgeEntries(); + void purgeEntries(U32 size); BOOL updateEntry(const HeaderEntryInfo* entry); private: -- cgit v1.2.3 From 39a609a7ae04e2177e5dd522fe880e3aac9a685c Mon Sep 17 00:00:00 2001 From: Seth ProductEngine Date: Tue, 25 Jan 2011 01:28:46 +0200 Subject: Fixed TestCapabilityProvider build issue. --- indra/newview/tests/llcapabilitylistener_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/tests/llcapabilitylistener_test.cpp b/indra/newview/tests/llcapabilitylistener_test.cpp index 9da851ffc4..d691bb6c44 100644 --- a/indra/newview/tests/llcapabilitylistener_test.cpp +++ b/indra/newview/tests/llcapabilitylistener_test.cpp @@ -72,7 +72,7 @@ struct TestCapabilityProvider: public LLCapabilityProvider { mCaps[cap] = url; } - LLHost getHost() const { return mHost; } + const LLHost& getHost() const { return mHost; } std::string getDescription() const { return "TestCapabilityProvider"; } LLHost mHost; -- cgit v1.2.3 From 358a091724d8df9a792c4aea73bd708b28400513 Mon Sep 17 00:00:00 2001 From: Seth ProductEngine Date: Tue, 25 Jan 2011 01:13:39 +0200 Subject: STORM-843 FIXED incremental inventory search to use more restrictive or less restrictive filtering. Stored filter sub-string comparison with new string failed because of non-matching register of compared strings. Transforming the new search term to uppercase before comparing it with previous one allows to determine if filter became more or less restrictive and not to restart the search over. Used patch provided by Satomi Ahn. --- indra/newview/llinventoryfilter.cpp | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/indra/newview/llinventoryfilter.cpp b/indra/newview/llinventoryfilter.cpp index ef4774a06d..e22363c2f6 100644 --- a/indra/newview/llinventoryfilter.cpp +++ b/indra/newview/llinventoryfilter.cpp @@ -393,18 +393,22 @@ void LLInventoryFilter::setFilterUUID(const LLUUID& object_id) void LLInventoryFilter::setFilterSubString(const std::string& string) { - if (mFilterSubString != string) + std::string filter_sub_string_new = string; + mFilterSubStringOrig = string; + LLStringUtil::trimHead(filter_sub_string_new); + LLStringUtil::toUpper(filter_sub_string_new); + + if (mFilterSubString != filter_sub_string_new) { // hitting BACKSPACE, for example - const BOOL less_restrictive = mFilterSubString.size() >= string.size() && !mFilterSubString.substr(0, string.size()).compare(string); + const BOOL less_restrictive = mFilterSubString.size() >= filter_sub_string_new.size() + && !mFilterSubString.substr(0, filter_sub_string_new.size()).compare(filter_sub_string_new); // appending new characters - const BOOL more_restrictive = mFilterSubString.size() < string.size() && !string.substr(0, mFilterSubString.size()).compare(mFilterSubString); + const BOOL more_restrictive = mFilterSubString.size() < filter_sub_string_new.size() + && !filter_sub_string_new.substr(0, mFilterSubString.size()).compare(mFilterSubString); - mFilterSubStringOrig = string; - LLStringUtil::trimHead(mFilterSubStringOrig); - mFilterSubString = mFilterSubStringOrig; - LLStringUtil::toUpper(mFilterSubString); + mFilterSubString = filter_sub_string_new; if (less_restrictive) { setModified(FILTER_LESS_RESTRICTIVE); -- cgit v1.2.3 From 714ba52df0397b58769e02ae9a7d9877a4505d34 Mon Sep 17 00:00:00 2001 From: Vadim ProductEngine Date: Tue, 25 Jan 2011 17:10:23 -0500 Subject: correct build error --- indra/newview/tests/llcapabilitylistener_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/tests/llcapabilitylistener_test.cpp b/indra/newview/tests/llcapabilitylistener_test.cpp index 9da851ffc4..d691bb6c44 100644 --- a/indra/newview/tests/llcapabilitylistener_test.cpp +++ b/indra/newview/tests/llcapabilitylistener_test.cpp @@ -72,7 +72,7 @@ struct TestCapabilityProvider: public LLCapabilityProvider { mCaps[cap] = url; } - LLHost getHost() const { return mHost; } + const LLHost& getHost() const { return mHost; } std::string getDescription() const { return "TestCapabilityProvider"; } LLHost mHost; -- cgit v1.2.3 From 8f54dc2958e75587165623b0292940200fb49f59 Mon Sep 17 00:00:00 2001 From: Xiaohong Bao Date: Wed, 26 Jan 2011 11:13:04 -0700 Subject: for SH-846: design and implement the debug code to locate memory leaking --- indra/llcommon/llmemory.cpp | 170 ++++++++++++++++++++- indra/llcommon/llmemory.h | 46 +++++- indra/llcommon/llmemtype.cpp | 1 + indra/newview/app_settings/settings.xml | 11 ++ indra/newview/llappviewer.cpp | 15 +- indra/newview/llmemoryview.cpp | 51 ++++++- indra/newview/llviewerwindow.cpp | 8 + indra/newview/skins/default/xui/en/menu_viewer.xml | 10 ++ 8 files changed, 304 insertions(+), 8 deletions(-) diff --git a/indra/llcommon/llmemory.cpp b/indra/llcommon/llmemory.cpp index a502d1a7eb..e4ece78d53 100644 --- a/indra/llcommon/llmemory.cpp +++ b/indra/llcommon/llmemory.cpp @@ -26,6 +26,12 @@ #include "linden_common.h" +#include "llmemory.h" + +#if MEM_TRACK_MEM +#include "llthread.h" +#endif + #if defined(LL_WINDOWS) # include # include @@ -37,8 +43,6 @@ # include #endif -#include "llmemory.h" - //---------------------------------------------------------------------------- //static @@ -105,6 +109,20 @@ U64 LLMemory::getCurrentRSS() return counters.WorkingSetSize; } +//static +U32 LLMemory::getWorkingSetSize() +{ + PROCESS_MEMORY_COUNTERS pmc ; + U32 ret = 0 ; + + if (GetProcessMemoryInfo( GetCurrentProcess(), &pmc, sizeof(pmc)) ) + { + ret = pmc.WorkingSetSize ; + } + + return ret ; +} + #elif defined(LL_DARWIN) /* @@ -151,6 +169,11 @@ U64 LLMemory::getCurrentRSS() return residentSize; } +U32 LLMemory::getWorkingSetSize() +{ + return 0 ; +} + #elif defined(LL_LINUX) U64 LLMemory::getCurrentRSS() @@ -185,6 +208,11 @@ bail: return rss; } +U32 LLMemory::getWorkingSetSize() +{ + return 0 ; +} + #elif LL_SOLARIS #include #include @@ -213,6 +241,12 @@ U64 LLMemory::getCurrentRSS() return((U64)proc_psinfo.pr_rssize * 1024); } + +U32 LLMemory::getWorkingSetSize() +{ + return 0 ; +} + #else U64 LLMemory::getCurrentRSS() @@ -220,4 +254,136 @@ U64 LLMemory::getCurrentRSS() return 0; } +U32 LLMemory::getWorkingSetSize() +{ + return 0 ; +} + #endif + +//-------------------------------------------------------------------------------------------------- +#if MEM_TRACK_MEM +#include "llframetimer.h" + +//static +LLMemTracker* LLMemTracker::sInstance = NULL ; + +LLMemTracker::LLMemTracker() +{ + mLastAllocatedMem = LLMemory::getWorkingSetSize() ; + mCapacity = 128 ; + mCurIndex = 0 ; + mCounter = 0 ; + mDrawnIndex = 0 ; + + mMutexp = new LLMutex(NULL) ; + mStringBuffer = new char*[128] ; + mStringBuffer[0] = new char[mCapacity * 128] ; + for(S32 i = 1 ; i < mCapacity ; i++) + { + mStringBuffer[i] = mStringBuffer[i-1] + 128 ; + } +} + +LLMemTracker::~LLMemTracker() +{ + delete[] mStringBuffer[0] ; + delete[] mStringBuffer; + delete mMutexp ; +} + +//static +LLMemTracker* LLMemTracker::getInstance() +{ + if(!sInstance) + { + sInstance = new LLMemTracker() ; + } + return sInstance ; +} + +//static +void LLMemTracker::release() +{ + if(sInstance) + { + delete sInstance ; + sInstance = NULL ; + } +} + +//static +void LLMemTracker::track(const char* function, const int line) +{ + static const S32 MIN_ALLOCATION = 1024 ; //1KB + + U32 allocated_mem = LLMemory::getWorkingSetSize() ; + + LLMutexLock lock(mMutexp) ; + + if(allocated_mem <= mLastAllocatedMem) + { + return ; //occupied memory does not grow + } + + S32 delta_mem = allocated_mem - mLastAllocatedMem ; + mLastAllocatedMem = allocated_mem ; + if(delta_mem < MIN_ALLOCATION) + { + return ; + } + + char* buffer = mStringBuffer[mCurIndex++] ; + F32 time = (F32)LLFrameTimer::getElapsedSeconds() ; + S32 hours = (S32)(time / (60*60)); + S32 mins = (S32)((time - hours*(60*60)) / 60); + S32 secs = (S32)((time - hours*(60*60) - mins*60)); + strcpy(buffer, function) ; + sprintf(buffer + strlen(function), " line: %d DeltaMem: %d (bytes) Time: %d:%02d:%02d", line, delta_mem, hours,mins,secs) ; + + if(mCounter < mCapacity) + { + mCounter++ ; + } + if(mCurIndex >= mCapacity) + { + mCurIndex = 0 ; + } +} + + +//static +void LLMemTracker::preDraw() +{ + mMutexp->lock() ; + + mDrawnIndex = mCurIndex - 1; + mNumOfDrawn = 0 ; +} + +//static +void LLMemTracker::postDraw() +{ + mMutexp->unlock() ; +} + +//static +const char* LLMemTracker::getNextLine() +{ + if(mNumOfDrawn >= mCounter) + { + return NULL ; + } + mNumOfDrawn++; + + if(mDrawnIndex < 0) + { + mDrawnIndex = mCapacity - 1 ; + } + + return mStringBuffer[mDrawnIndex--] ; +} + +#endif //MEM_TRACK_MEM +//-------------------------------------------------------------------------------------------------- + diff --git a/indra/llcommon/llmemory.h b/indra/llcommon/llmemory.h index 9bf4248bb7..e6a6a8c3da 100644 --- a/indra/llcommon/llmemory.h +++ b/indra/llcommon/llmemory.h @@ -26,7 +26,7 @@ #ifndef LLMEMORY_H #define LLMEMORY_H - +#include "llmemtype.h" extern S32 gTotalDAlloc; extern S32 gTotalDAUse; @@ -44,10 +44,54 @@ public: // Return the resident set size of the current process, in bytes. // Return value is zero if not known. static U64 getCurrentRSS(); + static U32 getWorkingSetSize(); private: static char* reserveMem; }; +//---------------------------------------------------------------------------- +#if MEM_TRACK_MEM +class LLMutex ; +class LL_COMMON_API LLMemTracker +{ +private: + LLMemTracker() ; + ~LLMemTracker() ; + +public: + static void release() ; + static LLMemTracker* getInstance() ; + + void track(const char* function, const int line) ; + void preDraw() ; + void postDraw() ; + const char* getNextLine() ; + +private: + static LLMemTracker* sInstance ; + + char** mStringBuffer ; + S32 mCapacity ; + U32 mLastAllocatedMem ; + S32 mCurIndex ; + S32 mCounter; + S32 mDrawnIndex; + S32 mNumOfDrawn; + LLMutex* mMutexp ; +}; + +#define MEM_TRACK_RELEASE LLMemTracker::release() ; +#define MEM_TRACK LLMemTracker::getInstance()->track(__FUNCTION__, __LINE__) ; + +#else // MEM_TRACK_MEM + +#define MEM_TRACK_RELEASE +#define MEM_TRACK + +#endif // MEM_TRACK_MEM + +//---------------------------------------------------------------------------- + // LLRefCount moved to llrefcount.h // LLPointer moved to llpointer.h diff --git a/indra/llcommon/llmemtype.cpp b/indra/llcommon/llmemtype.cpp index fe83f87d4b..6290a7158f 100644 --- a/indra/llcommon/llmemtype.cpp +++ b/indra/llcommon/llmemtype.cpp @@ -229,3 +229,4 @@ char const * LLMemType::getNameFromID(S32 id) return DeclareMemType::mNameList[id]; } +//-------------------------------------------------------------------------------------------------- diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index ced46c7294..72d83ad024 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -1852,6 +1852,17 @@ Value 0 + DebugShowMemory + + Comment + Show Total Allocated Memory + Persist + 1 + Type + Boolean + Value + 0 + DebugShowRenderInfo Comment diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 6a9dfaf21b..87c0085226 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -1057,6 +1057,8 @@ bool LLAppViewer::mainLoop() //clear call stack records llclearcallstacks; + MEM_TRACK + //check memory availability information { if(memory_check_interval < memCheckTimer.getElapsedTimeF32()) @@ -1101,6 +1103,8 @@ bool LLAppViewer::mainLoop() } #endif + MEM_TRACK + //memory leaking simulation LLFloaterMemLeak* mem_leak_instance = LLFloaterReg::findTypedInstance("mem_leaking"); @@ -1162,6 +1166,8 @@ bool LLAppViewer::mainLoop() resumeMainloopTimeout(); } + MEM_TRACK + if (gDoDisconnect && (LLStartUp::getStartupState() == STATE_STARTED)) { pauseMainloopTimeout(); @@ -1183,6 +1189,8 @@ bool LLAppViewer::mainLoop() } + MEM_TRACK + pingMainloopTimeout("Main:Sleep"); pauseMainloopTimeout(); @@ -1296,7 +1304,10 @@ bool LLAppViewer::mainLoop() resumeMainloopTimeout(); pingMainloopTimeout("Main:End"); - } + } + + MEM_TRACK + } catch(std::bad_alloc) { @@ -1779,6 +1790,8 @@ bool LLAppViewer::cleanup() ll_close_fail_log(); + MEM_TRACK_RELEASE + llinfos << "Goodbye!" << llendflush; // return 0; diff --git a/indra/newview/llmemoryview.cpp b/indra/newview/llmemoryview.cpp index 9a244e2562..397a77c4e3 100644 --- a/indra/newview/llmemoryview.cpp +++ b/indra/newview/llmemoryview.cpp @@ -37,6 +37,7 @@ #include #include +#include "llmemory.h" LLMemoryView::LLMemoryView(const LLMemoryView::Params& p) : LLView(p), @@ -148,13 +149,14 @@ void LLMemoryView::draw() // cut off lines on bottom U32 max_lines = U32((height - 2 * line_height) / line_height); - std::vector::const_iterator end = mLines.end(); + y_pos = height - MARGIN_AMT - line_height; + y_off = 0.f; + +#if !MEM_TRACK_MEM + std::vector::const_iterator end = mLines.end(); if(mLines.size() > max_lines) { end = mLines.begin() + max_lines; } - - y_pos = height - MARGIN_AMT - line_height; - y_off = 0.f; for (std::vector::const_iterator i = mLines.begin(); i != end; ++i) { font->render(*i, 0, MARGIN_AMT, y_pos - y_off, @@ -169,6 +171,47 @@ void LLMemoryView::draw() y_off += line_height; } +#else + LLMemTracker::getInstance()->preDraw() ; + + { + F32 x_pos = MARGIN_AMT ; + U32 lines = 0 ; + const char* str = LLMemTracker::getInstance()->getNextLine() ; + while(str != NULL) + { + lines++ ; + font->renderUTF8(str, 0, x_pos, y_pos - y_off, + LLColor4::white, + LLFontGL::LEFT, + LLFontGL::BASELINE, + LLFontGL::NORMAL, + LLFontGL::DROP_SHADOW, + S32_MAX, + target_width, + NULL, FALSE); + + str = LLMemTracker::getInstance()->getNextLine() ; + y_off += line_height; + + if(lines >= max_lines) + { + lines = 0 ; + x_pos += 512.f ; + if(x_pos + 512.f > target_width) + { + break ; + } + + y_pos = height - MARGIN_AMT - line_height; + y_off = 0.f; + } + } + } + + LLMemTracker::getInstance()->postDraw() ; +#endif + #if MEM_TRACK_TYPE S32 left, top, right, bottom; diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 166b110412..ca0478ee0c 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -351,6 +351,14 @@ public: addText(xpos, ypos, llformat("Time: %d:%02d:%02d", hours,mins,secs)); ypos += y_inc; } +#if LL_WINDOWS + if (gSavedSettings.getBOOL("DebugShowMemory")) + { + addText(xpos, ypos, llformat("Memory: %d (KB)", LLMemory::getWorkingSetSize() / 1024)); + ypos += y_inc; + } +#endif + if (gDisplayCameraPos) { std::string camera_view_text; diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index c2735c85e4..08ae0c233e 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -1990,6 +1990,16 @@ function="ToggleControl" parameter="DebugShowColor" /> + + + + -- cgit v1.2.3 From 5e6b4b5ad0dc56869430bcd31a942bdc7f8a2899 Mon Sep 17 00:00:00 2001 From: paul_productengine Date: Wed, 26 Jan 2011 20:24:49 +0200 Subject: STORM-351 FIXED Scrolling flat list by mouse wheel changes zoom level in-world - Prevent passing scroll event to in-world --- indra/newview/llsidetray.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/indra/newview/llsidetray.cpp b/indra/newview/llsidetray.cpp index 19d1bdee86..eb537c7d7b 100644 --- a/indra/newview/llsidetray.cpp +++ b/indra/newview/llsidetray.cpp @@ -141,6 +141,8 @@ public: void toggleTabDocked(); + BOOL handleScrollWheel(S32 x, S32 y, S32 clicks); + LLPanel *getPanel(); private: std::string mTabTitle; @@ -269,6 +271,15 @@ void LLSideTrayTab::toggleTabDocked() LLFloaterReg::toggleInstance("side_bar_tab", tab_name); } +BOOL LLSideTrayTab::handleScrollWheel(S32 x, S32 y, S32 clicks) +{ + // Let children handle the event + LLUICtrl::handleScrollWheel(x, y, clicks); + + // and then eat it to prevent in-world scrolling (STORM-351). + return TRUE; +} + void LLSideTrayTab::dock(LLFloater* floater_tab) { LLSideTray* side_tray = getSideTray(); -- cgit v1.2.3 From 3eba59e963d87f54e1b33b0a34de3fe37e67ebe1 Mon Sep 17 00:00:00 2001 From: David Kaprielian Date: Wed, 26 Jan 2011 15:07:54 -0800 Subject: Adding run_tests buildparam and setting to false for coverity builds so coverity can run. Reviewed by CG. --- BuildParams | 1 + build.sh | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/BuildParams b/BuildParams index 0a4271f7a8..8e036ab56b 100644 --- a/BuildParams +++ b/BuildParams @@ -26,6 +26,7 @@ viewer-development.show_changes_since = last_sprint # Build Settings viewer-development_coverity.coverity_product = viewer +viewer-development_coverity.run_tests = false viewer-development.build_debug_release_separately = true # Notifications - to configure email notices, add a setting like this: diff --git a/build.sh b/build.sh index cd1d9df6f3..1c28f5a255 100755 --- a/build.sh +++ b/build.sh @@ -66,7 +66,8 @@ pre_build() -DRELEASE_CRASH_REPORTING:BOOL=ON \ -DLOCALIZESETUP:BOOL=ON \ -DPACKAGE:BOOL=ON \ - -DCMAKE_VERBOSE_MAKEFILE:BOOL=TRUE + -DCMAKE_VERBOSE_MAKEFILE:BOOL=TRUE \ + -DLL_TESTS:BOOL="$run_tests" end_section "Pre$variant" } -- cgit v1.2.3 From 6531eed04e24239233f79624572219e88017f476 Mon Sep 17 00:00:00 2001 From: Xiaohong Bao Date: Wed, 26 Jan 2011 17:03:30 -0700 Subject: add "pause" function for SH-846: design and implement the debug code to locate memory leaking --- indra/llcommon/llmemory.cpp | 18 +++++++++++++----- indra/llcommon/llmemory.h | 3 ++- indra/newview/llmemoryview.cpp | 4 +++- indra/newview/llmemoryview.h | 1 + 4 files changed, 19 insertions(+), 7 deletions(-) diff --git a/indra/llcommon/llmemory.cpp b/indra/llcommon/llmemory.cpp index e4ece78d53..f340105f57 100644 --- a/indra/llcommon/llmemory.cpp +++ b/indra/llcommon/llmemory.cpp @@ -275,6 +275,7 @@ LLMemTracker::LLMemTracker() mCurIndex = 0 ; mCounter = 0 ; mDrawnIndex = 0 ; + mPaused = FALSE ; mMutexp = new LLMutex(NULL) ; mStringBuffer = new char*[128] ; @@ -315,19 +316,25 @@ void LLMemTracker::release() //static void LLMemTracker::track(const char* function, const int line) { - static const S32 MIN_ALLOCATION = 1024 ; //1KB + static const S32 MIN_ALLOCATION = 0 ; //1KB + + if(mPaused) + { + return ; + } U32 allocated_mem = LLMemory::getWorkingSetSize() ; LLMutexLock lock(mMutexp) ; - if(allocated_mem <= mLastAllocatedMem) + S32 delta_mem = allocated_mem - mLastAllocatedMem ; + mLastAllocatedMem = allocated_mem ; + + if(delta_mem <= 0) { return ; //occupied memory does not grow } - S32 delta_mem = allocated_mem - mLastAllocatedMem ; - mLastAllocatedMem = allocated_mem ; if(delta_mem < MIN_ALLOCATION) { return ; @@ -353,10 +360,11 @@ void LLMemTracker::track(const char* function, const int line) //static -void LLMemTracker::preDraw() +void LLMemTracker::preDraw(BOOL pause) { mMutexp->lock() ; + mPaused = pause ; mDrawnIndex = mCurIndex - 1; mNumOfDrawn = 0 ; } diff --git a/indra/llcommon/llmemory.h b/indra/llcommon/llmemory.h index e6a6a8c3da..11406f59b0 100644 --- a/indra/llcommon/llmemory.h +++ b/indra/llcommon/llmemory.h @@ -63,7 +63,7 @@ public: static LLMemTracker* getInstance() ; void track(const char* function, const int line) ; - void preDraw() ; + void preDraw(BOOL pause) ; void postDraw() ; const char* getNextLine() ; @@ -77,6 +77,7 @@ private: S32 mCounter; S32 mDrawnIndex; S32 mNumOfDrawn; + BOOL mPaused; LLMutex* mMutexp ; }; diff --git a/indra/newview/llmemoryview.cpp b/indra/newview/llmemoryview.cpp index 397a77c4e3..7e9c3c84a7 100644 --- a/indra/newview/llmemoryview.cpp +++ b/indra/newview/llmemoryview.cpp @@ -41,6 +41,7 @@ LLMemoryView::LLMemoryView(const LLMemoryView::Params& p) : LLView(p), + mPaused(FALSE), //mDelay(120), mAlloc(NULL) { @@ -60,6 +61,7 @@ BOOL LLMemoryView::handleMouseDown(S32 x, S32 y, MASK mask) } else { + mPaused = !mPaused; } return TRUE; } @@ -172,7 +174,7 @@ void LLMemoryView::draw() } #else - LLMemTracker::getInstance()->preDraw() ; + LLMemTracker::getInstance()->preDraw(mPaused) ; { F32 x_pos = MARGIN_AMT ; diff --git a/indra/newview/llmemoryview.h b/indra/newview/llmemoryview.h index 24ea058279..9bdc59ab10 100644 --- a/indra/newview/llmemoryview.h +++ b/indra/newview/llmemoryview.h @@ -55,6 +55,7 @@ public: private: std::vector mLines; LLAllocator* mAlloc; + BOOL mPaused ; }; -- cgit v1.2.3 From 0d5b0cad146d2ce4a24256845b36c4eee847f7ad Mon Sep 17 00:00:00 2001 From: Twisted Laws Date: Wed, 26 Jan 2011 19:22:42 -0500 Subject: Embed Minimap into the Nearby list of the People Sidebar --- doc/contributions.txt | 2 + indra/newview/llfloatermap.cpp | 3 +- indra/newview/llnetmap.cpp | 149 ++++++++++++++++++++- indra/newview/llnetmap.h | 18 ++- indra/newview/llpanelpeople.cpp | 13 +- indra/newview/llpanelpeople.h | 1 + indra/newview/skins/default/xui/en/floater_map.xml | 6 +- .../newview/skins/default/xui/en/panel_people.xml | 26 +++- 8 files changed, 205 insertions(+), 13 deletions(-) diff --git a/doc/contributions.txt b/doc/contributions.txt index 4e91bbdd36..3ac9da3e65 100644 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -387,6 +387,7 @@ Jonathan Yap VWR-17801 VWR-24347 STORM-844 + STORM-643 Kage Pixel VWR-11 Ken March @@ -769,6 +770,7 @@ Twisted Laws STORM-466 STORM-467 STORM-844 + STORM-643 Vadim Bigbear VWR-2681 Vector Hastings diff --git a/indra/newview/llfloatermap.cpp b/indra/newview/llfloatermap.cpp index 1b94d8cbcd..80920c80d6 100644 --- a/indra/newview/llfloatermap.cpp +++ b/indra/newview/llfloatermap.cpp @@ -83,7 +83,8 @@ LLFloaterMap::~LLFloaterMap() BOOL LLFloaterMap::postBuild() { mMap = getChild("Net Map"); - mMap->setToolTipMsg(getString("ToolTipMsg")); + mMap->setToolTipMsg(gSavedSettings.getBOOL("DoubleClickTeleport") ? + getString("AltToolTipMsg") : getString("ToolTipMsg")); sendChildToBack(mMap); mTextBoxNorth = getChild ("floater_map_north"); diff --git a/indra/newview/llnetmap.cpp b/indra/newview/llnetmap.cpp index 1a8ec4991d..93039d935d 100644 --- a/indra/newview/llnetmap.cpp +++ b/indra/newview/llnetmap.cpp @@ -47,6 +47,7 @@ #include "llagentcamera.h" #include "llappviewer.h" // for gDisconnected #include "llcallingcard.h" // LLAvatarTracker +#include "llfloaterworldmap.h" #include "lltracker.h" #include "llsurface.h" #include "llviewercamera.h" @@ -91,7 +92,8 @@ LLNetMap::LLNetMap (const Params & p) mObjectImagep(), mClosestAgentToCursor(), mClosestAgentAtLastRightClick(), - mToolTipMsg() + mToolTipMsg(), + mPopupMenu(NULL) { mDotRadius = llmax(DOT_SCALE * mPixelsPerMeter, MIN_DOT_RADIUS); setScale(gSavedSettings.getF32("MiniMapScale")); @@ -102,6 +104,21 @@ LLNetMap::~LLNetMap() gSavedSettings.setF32("MiniMapScale", mScale); } +BOOL LLNetMap::postBuild() +{ + LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; + + registrar.add("Minimap.Zoom", boost::bind(&LLNetMap::handleZoom, this, _2)); + registrar.add("Minimap.Tracker", boost::bind(&LLNetMap::handleStopTracking, this, _2)); + + mPopupMenu = LLUICtrlFactory::getInstance()->createFromFile("menu_mini_map.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); + if (mPopupMenu && !LLTracker::isTracking(0)) + { + mPopupMenu->setItemEnabled ("Stop Tracking", false); + } + return TRUE; +} + void LLNetMap::setScale( F32 scale ) { scale = llclamp(scale, MAP_SCALE_MIN, MAP_SCALE_MAX); @@ -354,16 +371,49 @@ void LLNetMap::draw() pos_map = globalPosToView(pos_global); + LLUUID uuid(NULL); BOOL show_as_friend = FALSE; if( i < regionp->mMapAvatarIDs.count()) { - show_as_friend = (LLAvatarTracker::instance().getBuddyInfo(regionp->mMapAvatarIDs.get(i)) != NULL); + uuid = regionp->mMapAvatarIDs.get(i); + show_as_friend = (LLAvatarTracker::instance().getBuddyInfo(uuid) != NULL); } + + LLColor4 color = show_as_friend ? map_avatar_friend_color : map_avatar_color; LLWorldMapView::drawAvatar( pos_map.mV[VX], pos_map.mV[VY], - show_as_friend ? map_avatar_friend_color : map_avatar_color, + color, pos_map.mV[VZ], mDotRadius); + if(uuid.notNull()) + { + bool selected = false; + uuid_vec_t::iterator sel_iter = gmSelected.begin(); + for (; sel_iter != gmSelected.end(); sel_iter++) + { + if(*sel_iter == uuid) + { + selected = true; + break; + } + } + if(selected) + { + if( (pos_map.mV[VX] < 0) || + (pos_map.mV[VY] < 0) || + (pos_map.mV[VX] >= getRect().getWidth()) || + (pos_map.mV[VY] >= getRect().getHeight()) ) + { + S32 x = llround( pos_map.mV[VX] ); + S32 y = llround( pos_map.mV[VY] ); + LLWorldMapView::drawTrackingCircle( getRect(), x, y, color, 1, 10); + } else + { + LLWorldMapView::drawTrackingDot(pos_map.mV[VX],pos_map.mV[VY],color,0.f); + } + } + } + F32 dist_to_cursor = dist_vec(LLVector2(pos_map.mV[VX], pos_map.mV[VY]), LLVector2(local_mouse_x,local_mouse_y)); if(dist_to_cursor < min_pick_dist && dist_to_cursor < closest_dist) @@ -460,6 +510,13 @@ void LLNetMap::draw() gGL.popUIMatrix(); LLUICtrl::draw(); + + if (LLTracker::isTracking(0)) + { + mPopupMenu->setItemEnabled ("Stop Tracking", true); + } + + } void LLNetMap::reshape(S32 width, S32 height, BOOL called_from_parent) @@ -600,7 +657,6 @@ BOOL LLNetMap::handleToolTip( S32 x, S32 y, MASK mask ) args["[REGION]"] = region_name; std::string msg = mToolTipMsg; LLStringUtil::format(msg, args); - LLToolTipMgr::instance().show(LLToolTip::Params() .message(msg) .sticky_rect(sticky_rect)); @@ -793,6 +849,9 @@ BOOL LLNetMap::handleMouseDown( S32 x, S32 y, MASK mask ) BOOL LLNetMap::handleMouseUp( S32 x, S32 y, MASK mask ) { + if(abs(mMouseDown.mX-x)<3 && abs(mMouseDown.mY-y)<3) + handleClick(x,y,mask); + if (hasMouseCapture()) { if (mPanning) @@ -821,6 +880,53 @@ BOOL LLNetMap::handleMouseUp( S32 x, S32 y, MASK mask ) return FALSE; } +BOOL LLNetMap::handleRightMouseDown(S32 x, S32 y, MASK mask) +{ + if (mPopupMenu) + { + mPopupMenu->buildDrawLabels(); + mPopupMenu->updateParent(LLMenuGL::sMenuContainer); + LLMenuGL::showPopup(this, mPopupMenu, x, y); + } + return TRUE; +} + +BOOL LLNetMap::handleClick(S32 x, S32 y, MASK mask) +{ + // TODO: allow clicking an avatar on minimap to select avatar in the nearby avatar list + // if(mClosestAgentToCursor.notNull()) + // mNearbyList->selectUser(mClosestAgentToCursor); + // Needs a registered observer i guess to accomplish this without using + // globals to tell the mNearbyList in llpeoplepanel to select the user + return TRUE; +} + +BOOL LLNetMap::handleDoubleClick(S32 x, S32 y, MASK mask) +{ + LLVector3d pos_global = viewPosToGlobal(x, y); + + // If we're not tracking a beacon already, double-click will set one + if (!LLTracker::isTracking(NULL)) + { + LLFloaterWorldMap* world_map = LLFloaterWorldMap::getInstance(); + if (world_map) + { + world_map->trackLocation(pos_global); + } + } + + if (gSavedSettings.getBOOL("DoubleClickTeleport")) + { + // If DoubleClickTeleport is on, double clicking the minimap will teleport there + gAgent.teleportViaLocationLookAt(pos_global); + } + else + { + LLFloaterReg::showInstance("world_map"); + } + return TRUE; +} + // static bool LLNetMap::outsideSlop( S32 x, S32 y, S32 start_x, S32 start_y, S32 slop ) { @@ -871,3 +977,38 @@ BOOL LLNetMap::handleHover( S32 x, S32 y, MASK mask ) return TRUE; } + +void LLNetMap::handleZoom(const LLSD& userdata) +{ + std::string level = userdata.asString(); + + F32 scale = 0.0f; + if (level == std::string("default")) + { + LLControlVariable *pvar = gSavedSettings.getControl("MiniMapScale"); + if(pvar) + { + pvar->resetToDefault(); + scale = gSavedSettings.getF32("MiniMapScale"); + } + } + else if (level == std::string("close")) + scale = LLNetMap::MAP_SCALE_MAX; + else if (level == std::string("medium")) + scale = LLNetMap::MAP_SCALE_MID; + else if (level == std::string("far")) + scale = LLNetMap::MAP_SCALE_MIN; + if (scale != 0.0f) + { + setScale(scale); + } +} + +void LLNetMap::handleStopTracking (const LLSD& userdata) +{ + if (mPopupMenu) + { + mPopupMenu->setItemEnabled ("Stop Tracking", false); + LLTracker::stopTracking ((void*)LLTracker::isTracking(NULL)); + } +} diff --git a/indra/newview/llnetmap.h b/indra/newview/llnetmap.h index e053b1c177..20fcee0814 100644 --- a/indra/newview/llnetmap.h +++ b/indra/newview/llnetmap.h @@ -39,6 +39,7 @@ class LLCoordGL; class LLImageRaw; class LLViewerTexture; class LLFloaterMap; +class LLMenuGL; class LLNetMap : public LLUICtrl { @@ -72,7 +73,12 @@ public: /*virtual*/ BOOL handleHover( S32 x, S32 y, MASK mask ); /*virtual*/ BOOL handleToolTip( S32 x, S32 y, MASK mask); /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); - + + /*virtual*/ BOOL postBuild(); + /*virtual*/ BOOL handleRightMouseDown( S32 x, S32 y, MASK mask ); + /*virtual*/ BOOL handleClick(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleDoubleClick( S32 x, S32 y, MASK mask ); + void setScale( F32 scale ); void setToolTipMsg(const std::string& msg) { mToolTipMsg = msg; } void renderScaledPointGlobal( const LLVector3d& pos, const LLColor4U &color, F32 radius ); @@ -120,6 +126,16 @@ private: LLUUID mClosestAgentAtLastRightClick; std::string mToolTipMsg; + +public: + void setSelected(uuid_vec_t uuids) { gmSelected=uuids; }; + +private: + void handleZoom(const LLSD& userdata); + void handleStopTracking (const LLSD& userdata); + + LLMenuGL* mPopupMenu; + uuid_vec_t gmSelected; }; diff --git a/indra/newview/llpanelpeople.cpp b/indra/newview/llpanelpeople.cpp index 54198d6aa4..b07a46a222 100644 --- a/indra/newview/llpanelpeople.cpp +++ b/indra/newview/llpanelpeople.cpp @@ -54,6 +54,7 @@ #include "llgroupactions.h" #include "llgrouplist.h" #include "llinventoryobserver.h" +#include "llnetmap.h" #include "llpanelpeoplemenus.h" #include "llsidetray.h" #include "llsidetraypanelcontainer.h" @@ -494,7 +495,8 @@ LLPanelPeople::LLPanelPeople() mNearbyGearButton(NULL), mFriendsGearButton(NULL), mGroupsGearButton(NULL), - mRecentGearButton(NULL) + mRecentGearButton(NULL), + mMiniMap(NULL) { mFriendListUpdater = new LLFriendListUpdater(boost::bind(&LLPanelPeople::updateFriendList, this)); mNearbyListUpdater = new LLNearbyListUpdater(boost::bind(&LLPanelPeople::updateNearbyList, this)); @@ -567,6 +569,9 @@ BOOL LLPanelPeople::postBuild() mNearbyList->setNoItemsMsg(getString("no_one_near")); mNearbyList->setNoFilteredItemsMsg(getString("no_one_filtered_near")); mNearbyList->setShowIcons("NearbyListShowIcons"); + mMiniMap = (LLNetMap*)getChildView("Net Map",true); + mMiniMap->setToolTipMsg(gSavedSettings.getBOOL("DoubleClickTeleport") ? + getString("AltMiniMapToolTipMsg") : getString("MiniMapToolTipMsg")); mRecentList = getChild(RECENT_TAB_NAME)->getChild("avatar_list"); mRecentList->setNoItemsCommentText(getString("no_recent_people")); @@ -1088,6 +1093,12 @@ void LLPanelPeople::onAvatarListDoubleClicked(LLUICtrl* ctrl) void LLPanelPeople::onAvatarListCommitted(LLAvatarList* list) { + if (getActiveTabName() == NEARBY_TAB_NAME) + { + uuid_vec_t selected_uuids; + getCurrentItemIDs(selected_uuids); + mMiniMap->setSelected(selected_uuids); + } else // Make sure only one of the friends lists (online/all) has selection. if (getActiveTabName() == FRIENDS_TAB_NAME) { diff --git a/indra/newview/llpanelpeople.h b/indra/newview/llpanelpeople.h index b496bb3779..46c58cd139 100644 --- a/indra/newview/llpanelpeople.h +++ b/indra/newview/llpanelpeople.h @@ -142,6 +142,7 @@ private: LLAvatarList* mNearbyList; LLAvatarList* mRecentList; LLGroupList* mGroupList; + LLNetMap* mMiniMap; LLHandle mGroupPlusMenuHandle; LLHandle mNearbyViewSortMenuHandle; diff --git a/indra/newview/skins/default/xui/en/floater_map.xml b/indra/newview/skins/default/xui/en/floater_map.xml index 6370ff9243..ae99fa8dd5 100644 --- a/indra/newview/skins/default/xui/en/floater_map.xml +++ b/indra/newview/skins/default/xui/en/floater_map.xml @@ -22,7 +22,11 @@ name="ToolTipMsg"> [REGION](Double-click to open Map, shift-drag to pan) - + + [REGION](Double-click to teleport, shift-drag to pan) + + MINIMAP - + + - + Date: Fri, 28 Jan 2011 17:01:18 -0700 Subject: trivial: convert to "unix return" --- indra/llcommon/llmemory.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/llcommon/llmemory.cpp b/indra/llcommon/llmemory.cpp index f340105f57..51fcd5b717 100644 --- a/indra/llcommon/llmemory.cpp +++ b/indra/llcommon/llmemory.cpp @@ -114,7 +114,7 @@ U32 LLMemory::getWorkingSetSize() { PROCESS_MEMORY_COUNTERS pmc ; U32 ret = 0 ; - + if (GetProcessMemoryInfo( GetCurrentProcess(), &pmc, sizeof(pmc)) ) { ret = pmc.WorkingSetSize ; -- cgit v1.2.3 From c111288a23825de8e00d252f98652c362a054251 Mon Sep 17 00:00:00 2001 From: Xiaohong Bao Date: Fri, 28 Jan 2011 17:19:42 -0700 Subject: fixed the major memory leaking for SH-723/SH-847: memoy leaking --- indra/newview/llfirstuse.cpp | 58 +++++++++++++++++++++++++------------------- indra/newview/llfirstuse.h | 9 ++++--- 2 files changed, 38 insertions(+), 29 deletions(-) diff --git a/indra/newview/llfirstuse.cpp b/indra/newview/llfirstuse.cpp index 4c17199895..4d252dc662 100644 --- a/indra/newview/llfirstuse.cpp +++ b/indra/newview/llfirstuse.cpp @@ -41,35 +41,36 @@ // static -std::set LLFirstUse::sConfigVariables; +//std::set LLFirstUse::sConfigVariables; +std::set LLFirstUse::sConfigVariablesEnabled; // static -void LLFirstUse::addConfigVariable(const std::string& var) -{ - sConfigVariables.insert(var); -} +//void LLFirstUse::addConfigVariable(const std::string& var) +//{ +// sConfigVariables.insert(var); +//} // static -void LLFirstUse::disableFirstUse() -{ - // Set all first-use warnings to disabled - for (std::set::iterator iter = sConfigVariables.begin(); - iter != sConfigVariables.end(); ++iter) - { - gWarningSettings.setBOOL(*iter, FALSE); - } -} +//void LLFirstUse::disableFirstUse() +//{ +// // Set all first-use warnings to disabled +// for (std::set::iterator iter = sConfigVariables.begin(); +// iter != sConfigVariables.end(); ++iter) +// { +// gWarningSettings.setBOOL(*iter, FALSE); +// } +//} // static -void LLFirstUse::resetFirstUse() -{ - // Set all first-use warnings to disabled - for (std::set::iterator iter = sConfigVariables.begin(); - iter != sConfigVariables.end(); ++iter) - { - gWarningSettings.setBOOL(*iter, TRUE); - } -} +//void LLFirstUse::resetFirstUse() +//{ +// // Set all first-use warnings to disabled +// for (std::set::iterator iter = sConfigVariables.begin(); +// iter != sConfigVariables.end(); ++iter) +// { +// gWarningSettings.setBOOL(*iter, TRUE); +// } +//} // static void LLFirstUse::otherAvatarChatFirst(bool enable) @@ -151,13 +152,21 @@ void LLFirstUse::firstUseNotification(const std::string& control_var, bool enabl if (enable) { + if(sConfigVariablesEnabled.find(control_var) != sConfigVariablesEnabled.end()) + { + return ; //already added + } + if (gSavedSettings.getBOOL("EnableUIHints")) { LL_DEBUGS("LLFirstUse") << "Trigger first use notification " << notification_name << LL_ENDL; // if notification doesn't already exist and this notification hasn't been disabled... if (gWarningSettings.getBOOL(control_var)) - { // create new notification + { + sConfigVariablesEnabled.insert(control_var) ; + + // create new notification LLNotifications::instance().add(LLNotification::Params().name(notification_name).substitutions(args).payload(payload.with("control_var", control_var))); } } @@ -169,7 +178,6 @@ void LLFirstUse::firstUseNotification(const std::string& control_var, bool enabl // redundantly clear settings var here, in case there are no notifications to cancel gWarningSettings.setBOOL(control_var, FALSE); } - } // static diff --git a/indra/newview/llfirstuse.h b/indra/newview/llfirstuse.h index 81659988e6..489f58626a 100644 --- a/indra/newview/llfirstuse.h +++ b/indra/newview/llfirstuse.h @@ -78,11 +78,11 @@ class LLFirstUse public: // Add a config variable to be reset on resetFirstUse() - static void addConfigVariable(const std::string& var); + //static void addConfigVariable(const std::string& var); // Sets all controls back to show the dialogs. - static void disableFirstUse(); - static void resetFirstUse(); + //static void disableFirstUse(); + //static void resetFirstUse(); static void otherAvatarChatFirst(bool enable = true); static void sit(bool enable = true); @@ -98,7 +98,8 @@ public: protected: static void firstUseNotification(const std::string& control_var, bool enable, const std::string& notification_name, LLSD args = LLSD(), LLSD payload = LLSD()); - static std::set sConfigVariables; + //static std::set sConfigVariables; + static std::set sConfigVariablesEnabled; static void init(); static bool processNotification(const LLSD& notify); -- cgit v1.2.3 From 948afb8ef436f661dd84e3c343e22934f92570ec Mon Sep 17 00:00:00 2001 From: Xiaohong Bao Date: Fri, 28 Jan 2011 21:23:19 -0700 Subject: trivial: remove some debug code. --- indra/newview/llappviewer.cpp | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 87c0085226..69333ff4a3 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -1057,8 +1057,6 @@ bool LLAppViewer::mainLoop() //clear call stack records llclearcallstacks; - MEM_TRACK - //check memory availability information { if(memory_check_interval < memCheckTimer.getElapsedTimeF32()) @@ -1103,8 +1101,6 @@ bool LLAppViewer::mainLoop() } #endif - MEM_TRACK - //memory leaking simulation LLFloaterMemLeak* mem_leak_instance = LLFloaterReg::findTypedInstance("mem_leaking"); @@ -1166,8 +1162,6 @@ bool LLAppViewer::mainLoop() resumeMainloopTimeout(); } - MEM_TRACK - if (gDoDisconnect && (LLStartUp::getStartupState() == STATE_STARTED)) { pauseMainloopTimeout(); @@ -1189,8 +1183,6 @@ bool LLAppViewer::mainLoop() } - MEM_TRACK - pingMainloopTimeout("Main:Sleep"); pauseMainloopTimeout(); @@ -1305,9 +1297,6 @@ bool LLAppViewer::mainLoop() pingMainloopTimeout("Main:End"); } - - MEM_TRACK - } catch(std::bad_alloc) { -- cgit v1.2.3 From 2e2d990eb10d101982b4f1915780a49615b55d6e Mon Sep 17 00:00:00 2001 From: Oz Linden Date: Sat, 29 Jan 2011 13:09:55 -0500 Subject: correct DOS line endings --- indra/newview/llpanelavatar.cpp | 62 +- indra/newview/llpanelavatar.h | 596 ++-- indra/newview/lltexturefetch.cpp | 6022 +++++++++++++++++++------------------- 3 files changed, 3340 insertions(+), 3340 deletions(-) diff --git a/indra/newview/llpanelavatar.cpp b/indra/newview/llpanelavatar.cpp index 94b2340c93..53529b9f8b 100644 --- a/indra/newview/llpanelavatar.cpp +++ b/indra/newview/llpanelavatar.cpp @@ -625,10 +625,10 @@ void LLPanelAvatarProfile::processGroupProperties(const LLAvatarGroups* avatar_g getChild("sl_groups")->setValue(groups); } -void LLPanelAvatarProfile::got_full_name_callback( const LLUUID& id, const std::string& full_name, bool is_group ) -{ - LLStringUtil::format_map_t args; - +void LLPanelAvatarProfile::got_full_name_callback( const LLUUID& id, const std::string& full_name, bool is_group ) +{ + LLStringUtil::format_map_t args; + std::string name; if (LLAvatarNameCache::useDisplayNames()) { @@ -637,21 +637,21 @@ void LLPanelAvatarProfile::got_full_name_callback( const LLUUID& id, const std:: else { name = full_name; - } - - args["[NAME]"] = name; - - std::string linden_name = getString("name_text_args", args); - getChild("name_descr_text")->setValue(linden_name); -} + } + + args["[NAME]"] = name; + + std::string linden_name = getString("name_text_args", args); + getChild("name_descr_text")->setValue(linden_name); +} void LLPanelAvatarProfile::onNameCache(const LLUUID& agent_id, const LLAvatarName& av_name) { - LLStringUtil::format_map_t args; - args["[DISPLAY_NAME]"] = av_name.mDisplayName; - - std::string display_name = getString("display_name_text_args", args); - getChild("display_name_descr_text")->setValue(display_name); + LLStringUtil::format_map_t args; + args["[DISPLAY_NAME]"] = av_name.mDisplayName; + + std::string display_name = getString("display_name_text_args", args); + getChild("display_name_descr_text")->setValue(display_name); } void LLPanelAvatarProfile::fillCommonData(const LLAvatarData* avatar_data) @@ -667,22 +667,22 @@ void LLPanelAvatarProfile::fillCommonData(const LLAvatarData* avatar_data) } // ask (asynchronously) for the avatar name - std::string full_name; - if (gCacheName->getFullName(avatar_data->agent_id, full_name)) - { - // name in cache, call callback directly - got_full_name_callback( avatar_data->agent_id, full_name, false ); - } - else - { - // not in cache, lookup name - gCacheName->get(avatar_data->agent_id, false, boost::bind( &LLPanelAvatarProfile::got_full_name_callback, this, _1, _2, _3 )); - } - - // get display name + std::string full_name; + if (gCacheName->getFullName(avatar_data->agent_id, full_name)) + { + // name in cache, call callback directly + got_full_name_callback( avatar_data->agent_id, full_name, false ); + } + else + { + // not in cache, lookup name + gCacheName->get(avatar_data->agent_id, false, boost::bind( &LLPanelAvatarProfile::got_full_name_callback, this, _1, _2, _3 )); + } + + // get display name LLAvatarNameCache::get(avatar_data->avatar_id, - boost::bind(&LLPanelAvatarProfile::onNameCache, this, _1, _2)); - + boost::bind(&LLPanelAvatarProfile::onNameCache, this, _1, _2)); + args["[AGE]"] = LLDateUtil::ageFromDate( avatar_data->born_on, LLDate::now()); std::string register_date = getString("RegisterDateFormat", args); getChild("register_date")->setValue(register_date ); diff --git a/indra/newview/llpanelavatar.h b/indra/newview/llpanelavatar.h index 070fe4579a..5f36d1026f 100644 --- a/indra/newview/llpanelavatar.h +++ b/indra/newview/llpanelavatar.h @@ -1,298 +1,298 @@ -/** - * @file llpanelavatar.h - * @brief LLPanelAvatar and related class definitions - * - * $LicenseInfo:firstyear=2004&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_LLPANELAVATAR_H -#define LL_LLPANELAVATAR_H - -#include "llpanel.h" -#include "llavatarpropertiesprocessor.h" -#include "llcallingcard.h" -#include "llvoiceclient.h" -#include "llavatarnamecache.h" - -class LLComboBox; -class LLLineEditor; - -enum EOnlineStatus -{ - ONLINE_STATUS_NO = 0, - ONLINE_STATUS_YES = 1 -}; - -/** -* Base class for any Profile View or My Profile Panel. -*/ -class LLPanelProfileTab - : public LLPanel - , public LLAvatarPropertiesObserver -{ -public: - - /** - * Sets avatar ID, sets panel as observer of avatar related info replies from server. - */ - virtual void setAvatarId(const LLUUID& id); - - /** - * Returns avatar ID. - */ - virtual const LLUUID& getAvatarId() { return mAvatarId; } - - /** - * Sends update data request to server. - */ - virtual void updateData() = 0; - - /** - * Clears panel data if viewing avatar info for first time and sends update data request. - */ - virtual void onOpen(const LLSD& key); - - /** - * Profile tabs should close any opened panels here. - * - * Called from LLPanelProfile::onOpen() before opening new profile. - * See LLPanelPicks::onClosePanel for example. LLPanelPicks closes picture info panel - * before new profile is displayed, otherwise new profile will - * be hidden behind picture info panel. - */ - virtual void onClosePanel() {} - - /** - * Resets controls visibility, state, etc. - */ - virtual void resetControls(){}; - - /** - * Clears all data received from server. - */ - virtual void resetData(){}; - - /*virtual*/ ~LLPanelProfileTab(); - -protected: - - LLPanelProfileTab(); - - /** - * Scrolls panel to top when viewing avatar info for first time. - */ - void scrollToTop(); - - virtual void onMapButtonClick(); - - virtual void updateButtons(); - -private: - - LLUUID mAvatarId; -}; - -/** -* Panel for displaying Avatar's first and second life related info. -*/ -class LLPanelAvatarProfile - : public LLPanelProfileTab - , public LLFriendObserver - , public LLVoiceClientStatusObserver -{ -public: - LLPanelAvatarProfile(); - /*virtual*/ ~LLPanelAvatarProfile(); - - /*virtual*/ void onOpen(const LLSD& key); - - /** - * LLFriendObserver trigger - */ - virtual void changed(U32 mask); - - // Implements LLVoiceClientStatusObserver::onChange() to enable the call - // button when voice is available - /*virtual*/ void onChange(EStatusType status, const std::string &channelURI, bool proximal); - - /*virtual*/ void setAvatarId(const LLUUID& id); - - /** - * Processes data received from server. - */ - /*virtual*/ void processProperties(void* data, EAvatarProcessorType type); - - /*virtual*/ BOOL postBuild(); - - /*virtual*/ void updateData(); - - /*virtual*/ void resetControls(); - - /*virtual*/ void resetData(); - -protected: - - /** - * Process profile related data received from server. - */ - virtual void processProfileProperties(const LLAvatarData* avatar_data); - - /** - * Processes group related data received from server. - */ - virtual void processGroupProperties(const LLAvatarGroups* avatar_groups); - - /** - * Fills common for Avatar profile and My Profile fields. - */ - virtual void fillCommonData(const LLAvatarData* avatar_data); - - /** - * Fills partner data. - */ - virtual void fillPartnerData(const LLAvatarData* avatar_data); - - /** - * Fills account status. - */ - virtual void fillAccountStatus(const LLAvatarData* avatar_data); - - /** - * Opens "Pay Resident" dialog. - */ - void pay(); - - /** - * opens inventory and IM for sharing items - */ - void share(); - - /** - * Add/remove resident to/from your block list. - */ - void toggleBlock(); - - void kick(); - void freeze(); - void unfreeze(); - void csr(); - - bool enableShowOnMap(); - bool enableBlock(); - bool enableUnblock(); - bool enableGod(); - - void onSeeProfileBtnClick(); - void onAddFriendButtonClick(); - void onIMButtonClick(); - void onCallButtonClick(); - void onTeleportButtonClick(); - void onShareButtonClick(); - -private: - void got_full_name_callback( const LLUUID& id, const std::string& full_name, bool is_group ); - void onNameCache(const LLUUID& agent_id, const LLAvatarName& av_name); - - typedef std::map< std::string,LLUUID> group_map_t; - group_map_t mGroups; -}; - -/** - * Panel for displaying own first and second life related info. - */ -class LLPanelMyProfile - : public LLPanelAvatarProfile -{ -public: - LLPanelMyProfile(); - - /*virtual*/ BOOL postBuild(); - -protected: - - /*virtual*/ void onOpen(const LLSD& key); - - /*virtual*/ void processProfileProperties(const LLAvatarData* avatar_data); - - /*virtual*/ void resetControls(); - -protected: - void onStatusMessageChanged(); -}; - -/** - * Panel for displaying Avatar's notes and modifying friend's rights. - */ -class LLPanelAvatarNotes - : public LLPanelProfileTab - , public LLFriendObserver - , public LLVoiceClientStatusObserver -{ -public: - LLPanelAvatarNotes(); - /*virtual*/ ~LLPanelAvatarNotes(); - - virtual void setAvatarId(const LLUUID& id); - - /** - * LLFriendObserver trigger - */ - virtual void changed(U32 mask); - - // Implements LLVoiceClientStatusObserver::onChange() to enable the call - // button when voice is available - /*virtual*/ void onChange(EStatusType status, const std::string &channelURI, bool proximal); - - /*virtual*/ void onOpen(const LLSD& key); - - /*virtual*/ BOOL postBuild(); - - /*virtual*/ void processProperties(void* data, EAvatarProcessorType type); - - /*virtual*/ void updateData(); - -protected: - - /*virtual*/ void resetControls(); - - /*virtual*/ void resetData(); - - /** - * Fills rights data for friends. - */ - void fillRightsData(); - - void rightsConfirmationCallback(const LLSD& notification, - const LLSD& response, S32 rights); - void confirmModifyRights(bool grant, S32 rights); - void onCommitRights(); - void onCommitNotes(); - - void onAddFriendButtonClick(); - void onIMButtonClick(); - void onCallButtonClick(); - void onTeleportButtonClick(); - void onShareButtonClick(); - void enableCheckboxes(bool enable); -}; - -#endif // LL_LLPANELAVATAR_H +/** + * @file llpanelavatar.h + * @brief LLPanelAvatar and related class definitions + * + * $LicenseInfo:firstyear=2004&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_LLPANELAVATAR_H +#define LL_LLPANELAVATAR_H + +#include "llpanel.h" +#include "llavatarpropertiesprocessor.h" +#include "llcallingcard.h" +#include "llvoiceclient.h" +#include "llavatarnamecache.h" + +class LLComboBox; +class LLLineEditor; + +enum EOnlineStatus +{ + ONLINE_STATUS_NO = 0, + ONLINE_STATUS_YES = 1 +}; + +/** +* Base class for any Profile View or My Profile Panel. +*/ +class LLPanelProfileTab + : public LLPanel + , public LLAvatarPropertiesObserver +{ +public: + + /** + * Sets avatar ID, sets panel as observer of avatar related info replies from server. + */ + virtual void setAvatarId(const LLUUID& id); + + /** + * Returns avatar ID. + */ + virtual const LLUUID& getAvatarId() { return mAvatarId; } + + /** + * Sends update data request to server. + */ + virtual void updateData() = 0; + + /** + * Clears panel data if viewing avatar info for first time and sends update data request. + */ + virtual void onOpen(const LLSD& key); + + /** + * Profile tabs should close any opened panels here. + * + * Called from LLPanelProfile::onOpen() before opening new profile. + * See LLPanelPicks::onClosePanel for example. LLPanelPicks closes picture info panel + * before new profile is displayed, otherwise new profile will + * be hidden behind picture info panel. + */ + virtual void onClosePanel() {} + + /** + * Resets controls visibility, state, etc. + */ + virtual void resetControls(){}; + + /** + * Clears all data received from server. + */ + virtual void resetData(){}; + + /*virtual*/ ~LLPanelProfileTab(); + +protected: + + LLPanelProfileTab(); + + /** + * Scrolls panel to top when viewing avatar info for first time. + */ + void scrollToTop(); + + virtual void onMapButtonClick(); + + virtual void updateButtons(); + +private: + + LLUUID mAvatarId; +}; + +/** +* Panel for displaying Avatar's first and second life related info. +*/ +class LLPanelAvatarProfile + : public LLPanelProfileTab + , public LLFriendObserver + , public LLVoiceClientStatusObserver +{ +public: + LLPanelAvatarProfile(); + /*virtual*/ ~LLPanelAvatarProfile(); + + /*virtual*/ void onOpen(const LLSD& key); + + /** + * LLFriendObserver trigger + */ + virtual void changed(U32 mask); + + // Implements LLVoiceClientStatusObserver::onChange() to enable the call + // button when voice is available + /*virtual*/ void onChange(EStatusType status, const std::string &channelURI, bool proximal); + + /*virtual*/ void setAvatarId(const LLUUID& id); + + /** + * Processes data received from server. + */ + /*virtual*/ void processProperties(void* data, EAvatarProcessorType type); + + /*virtual*/ BOOL postBuild(); + + /*virtual*/ void updateData(); + + /*virtual*/ void resetControls(); + + /*virtual*/ void resetData(); + +protected: + + /** + * Process profile related data received from server. + */ + virtual void processProfileProperties(const LLAvatarData* avatar_data); + + /** + * Processes group related data received from server. + */ + virtual void processGroupProperties(const LLAvatarGroups* avatar_groups); + + /** + * Fills common for Avatar profile and My Profile fields. + */ + virtual void fillCommonData(const LLAvatarData* avatar_data); + + /** + * Fills partner data. + */ + virtual void fillPartnerData(const LLAvatarData* avatar_data); + + /** + * Fills account status. + */ + virtual void fillAccountStatus(const LLAvatarData* avatar_data); + + /** + * Opens "Pay Resident" dialog. + */ + void pay(); + + /** + * opens inventory and IM for sharing items + */ + void share(); + + /** + * Add/remove resident to/from your block list. + */ + void toggleBlock(); + + void kick(); + void freeze(); + void unfreeze(); + void csr(); + + bool enableShowOnMap(); + bool enableBlock(); + bool enableUnblock(); + bool enableGod(); + + void onSeeProfileBtnClick(); + void onAddFriendButtonClick(); + void onIMButtonClick(); + void onCallButtonClick(); + void onTeleportButtonClick(); + void onShareButtonClick(); + +private: + void got_full_name_callback( const LLUUID& id, const std::string& full_name, bool is_group ); + void onNameCache(const LLUUID& agent_id, const LLAvatarName& av_name); + + typedef std::map< std::string,LLUUID> group_map_t; + group_map_t mGroups; +}; + +/** + * Panel for displaying own first and second life related info. + */ +class LLPanelMyProfile + : public LLPanelAvatarProfile +{ +public: + LLPanelMyProfile(); + + /*virtual*/ BOOL postBuild(); + +protected: + + /*virtual*/ void onOpen(const LLSD& key); + + /*virtual*/ void processProfileProperties(const LLAvatarData* avatar_data); + + /*virtual*/ void resetControls(); + +protected: + void onStatusMessageChanged(); +}; + +/** + * Panel for displaying Avatar's notes and modifying friend's rights. + */ +class LLPanelAvatarNotes + : public LLPanelProfileTab + , public LLFriendObserver + , public LLVoiceClientStatusObserver +{ +public: + LLPanelAvatarNotes(); + /*virtual*/ ~LLPanelAvatarNotes(); + + virtual void setAvatarId(const LLUUID& id); + + /** + * LLFriendObserver trigger + */ + virtual void changed(U32 mask); + + // Implements LLVoiceClientStatusObserver::onChange() to enable the call + // button when voice is available + /*virtual*/ void onChange(EStatusType status, const std::string &channelURI, bool proximal); + + /*virtual*/ void onOpen(const LLSD& key); + + /*virtual*/ BOOL postBuild(); + + /*virtual*/ void processProperties(void* data, EAvatarProcessorType type); + + /*virtual*/ void updateData(); + +protected: + + /*virtual*/ void resetControls(); + + /*virtual*/ void resetData(); + + /** + * Fills rights data for friends. + */ + void fillRightsData(); + + void rightsConfirmationCallback(const LLSD& notification, + const LLSD& response, S32 rights); + void confirmModifyRights(bool grant, S32 rights); + void onCommitRights(); + void onCommitNotes(); + + void onAddFriendButtonClick(); + void onIMButtonClick(); + void onCallButtonClick(); + void onTeleportButtonClick(); + void onShareButtonClick(); + void enableCheckboxes(bool enable); +}; + +#endif // LL_LLPANELAVATAR_H diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp index 5cdf1706e6..18c3a3b87d 100644 --- a/indra/newview/lltexturefetch.cpp +++ b/indra/newview/lltexturefetch.cpp @@ -1,3011 +1,3011 @@ -/** - * @file lltexturefetch.cpp - * @brief Object which fetches textures from the cache and/or network - * - * $LicenseInfo:firstyear=2000&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 -#include - -#include "llstl.h" - -#include "lltexturefetch.h" - -#include "llcurl.h" -#include "lldir.h" -#include "llhttpclient.h" -#include "llhttpstatuscodes.h" -#include "llimage.h" -#include "llimagej2c.h" -#include "llimageworker.h" -#include "llworkerthread.h" -#include "message.h" - -#include "llagent.h" -#include "lltexturecache.h" -#include "llviewercontrol.h" -#include "llviewertexturelist.h" -#include "llviewertexture.h" -#include "llviewerregion.h" -#include "llviewerstats.h" -#include "llviewerassetstats.h" -#include "llworld.h" - -////////////////////////////////////////////////////////////////////////////// -class LLTextureFetchWorker : public LLWorkerClass -{ - friend class LLTextureFetch; - friend class HTTPGetResponder; - -private: - class CacheReadResponder : public LLTextureCache::ReadResponder - { - public: - CacheReadResponder(LLTextureFetch* fetcher, const LLUUID& id, LLImageFormatted* image) - : mFetcher(fetcher), mID(id) - { - setImage(image); - } - virtual void completed(bool success) - { - LLTextureFetchWorker* worker = mFetcher->getWorker(mID); - if (worker) - { - worker->callbackCacheRead(success, mFormattedImage, mImageSize, mImageLocal); - } - } - private: - LLTextureFetch* mFetcher; - LLUUID mID; - }; - - class CacheWriteResponder : public LLTextureCache::WriteResponder - { - public: - CacheWriteResponder(LLTextureFetch* fetcher, const LLUUID& id) - : mFetcher(fetcher), mID(id) - { - } - virtual void completed(bool success) - { - LLTextureFetchWorker* worker = mFetcher->getWorker(mID); - if (worker) - { - worker->callbackCacheWrite(success); - } - } - private: - LLTextureFetch* mFetcher; - LLUUID mID; - }; - - class DecodeResponder : public LLImageDecodeThread::Responder - { - public: - DecodeResponder(LLTextureFetch* fetcher, const LLUUID& id, LLTextureFetchWorker* worker) - : mFetcher(fetcher), mID(id), mWorker(worker) - { - } - virtual void completed(bool success, LLImageRaw* raw, LLImageRaw* aux) - { - LLTextureFetchWorker* worker = mFetcher->getWorker(mID); - if (worker) - { - worker->callbackDecoded(success, raw, aux); - } - } - private: - LLTextureFetch* mFetcher; - LLUUID mID; - LLTextureFetchWorker* mWorker; // debug only (may get deleted from under us, use mFetcher/mID) - }; - - struct Compare - { - // lhs < rhs - bool operator()(const LLTextureFetchWorker* lhs, const LLTextureFetchWorker* rhs) const - { - // greater priority is "less" - const F32 lpriority = lhs->mImagePriority; - const F32 rpriority = rhs->mImagePriority; - if (lpriority > rpriority) // higher priority - return true; - else if (lpriority < rpriority) - return false; - else - return lhs < rhs; - } - }; - -public: - /*virtual*/ bool doWork(S32 param); // Called from LLWorkerThread::processRequest() - /*virtual*/ void finishWork(S32 param, bool completed); // called from finishRequest() (WORK THREAD) - /*virtual*/ bool deleteOK(); // called from update() (WORK THREAD) - - ~LLTextureFetchWorker(); - // void relese() { --mActiveCount; } - - S32 callbackHttpGet(const LLChannelDescriptors& channels, - const LLIOPipe::buffer_ptr_t& buffer, - bool partial, bool success); - void callbackCacheRead(bool success, LLImageFormatted* image, - S32 imagesize, BOOL islocal); - void callbackCacheWrite(bool success); - void callbackDecoded(bool success, LLImageRaw* raw, LLImageRaw* aux); - - void setGetStatus(U32 status, const std::string& reason) - { - LLMutexLock lock(&mWorkMutex); - - mGetStatus = status; - mGetReason = reason; - } - - void setCanUseHTTP(bool can_use_http) { mCanUseHTTP = can_use_http; } - bool getCanUseHTTP() const { return mCanUseHTTP; } - - LLTextureFetch & getFetcher() { return *mFetcher; } - -protected: - LLTextureFetchWorker(LLTextureFetch* fetcher, const std::string& url, const LLUUID& id, const LLHost& host, - F32 priority, S32 discard, S32 size); - -private: - /*virtual*/ void startWork(S32 param); // called from addWork() (MAIN THREAD) - /*virtual*/ void endWork(S32 param, bool aborted); // called from doWork() (MAIN THREAD) - - void resetFormattedData(); - - void setImagePriority(F32 priority); - void setDesiredDiscard(S32 discard, S32 size); - bool insertPacket(S32 index, U8* data, S32 size); - void clearPackets(); - void setupPacketData(); - U32 calcWorkPriority(); - void removeFromCache(); - bool processSimulatorPackets(); - bool writeToCacheComplete(); - - void lockWorkMutex() { mWorkMutex.lock(); } - void unlockWorkMutex() { mWorkMutex.unlock(); } - -private: - enum e_state // mState - { - // NOTE: Affects LLTextureBar::draw in lltextureview.cpp (debug hack) - INVALID = 0, - INIT, - LOAD_FROM_TEXTURE_CACHE, - CACHE_POST, - LOAD_FROM_NETWORK, - LOAD_FROM_SIMULATOR, - SEND_HTTP_REQ, - WAIT_HTTP_REQ, - DECODE_IMAGE, - DECODE_IMAGE_UPDATE, - WRITE_TO_CACHE, - WAIT_ON_WRITE, - DONE - }; - enum e_request_state // mSentRequest - { - UNSENT = 0, - QUEUED = 1, - SENT_SIM = 2 - }; - enum e_write_to_cache_state //mWriteToCacheState - { - NOT_WRITE = 0, - CAN_WRITE = 1, - SHOULD_WRITE = 2 - }; - static const char* sStateDescs[]; - e_state mState; - e_write_to_cache_state mWriteToCacheState; - LLTextureFetch* mFetcher; - LLPointer mFormattedImage; - LLPointer mRawImage; - LLPointer mAuxImage; - LLUUID mID; - LLHost mHost; - std::string mUrl; - U8 mType; - F32 mImagePriority; - U32 mWorkPriority; - F32 mRequestedPriority; - S32 mDesiredDiscard; - S32 mSimRequestedDiscard; - S32 mRequestedDiscard; - S32 mLoadedDiscard; - S32 mDecodedDiscard; - LLFrameTimer mRequestedTimer; - LLFrameTimer mFetchTimer; - LLTextureCache::handle_t mCacheReadHandle; - LLTextureCache::handle_t mCacheWriteHandle; - U8* mBuffer; - S32 mBufferSize; - S32 mRequestedSize; - S32 mDesiredSize; - S32 mFileSize; - S32 mCachedSize; - e_request_state mSentRequest; - handle_t mDecodeHandle; - BOOL mLoaded; - BOOL mDecoded; - BOOL mWritten; - BOOL mNeedsAux; - BOOL mHaveAllData; - BOOL mInLocalCache; - bool mCanUseHTTP ; - bool mCanUseNET ; //can get from asset server. - S32 mHTTPFailCount; - S32 mRetryAttempt; - S32 mActiveCount; - U32 mGetStatus; - std::string mGetReason; - - // Work Data - LLMutex mWorkMutex; - struct PacketData - { - PacketData(U8* data, S32 size) { mData = data; mSize = size; } - ~PacketData() { clearData(); } - void clearData() { delete[] mData; mData = NULL; } - U8* mData; - U32 mSize; - }; - std::vector mPackets; - S32 mFirstPacket; - S32 mLastPacket; - U16 mTotalPackets; - U8 mImageCodec; - - LLViewerAssetStats::duration_t mMetricsStartTime; -}; - -////////////////////////////////////////////////////////////////////////////// - -class HTTPGetResponder : public LLCurl::Responder -{ - LOG_CLASS(HTTPGetResponder); -public: - HTTPGetResponder(LLTextureFetch* fetcher, const LLUUID& id, U64 startTime, S32 requestedSize, U32 offset, bool redir) - : mFetcher(fetcher), mID(id), mStartTime(startTime), mRequestedSize(requestedSize), mOffset(offset), mFollowRedir(redir) - { - } - ~HTTPGetResponder() - { - } - - virtual void completedRaw(U32 status, const std::string& reason, - const LLChannelDescriptors& channels, - const LLIOPipe::buffer_ptr_t& buffer) - { - static LLCachedControl log_to_viewer_log(gSavedSettings,"LogTextureDownloadsToViewerLog"); - static LLCachedControl log_to_sim(gSavedSettings,"LogTextureDownloadsToSimulator"); - static LLCachedControl log_texture_traffic(gSavedSettings,"LogTextureNetworkTraffic") ; - - if (log_to_viewer_log || log_to_sim) - { - mFetcher->mTextureInfo.setRequestStartTime(mID, mStartTime); - U64 timeNow = LLTimer::getTotalTime(); - mFetcher->mTextureInfo.setRequestType(mID, LLTextureInfoDetails::REQUEST_TYPE_HTTP); - mFetcher->mTextureInfo.setRequestSize(mID, mRequestedSize); - mFetcher->mTextureInfo.setRequestOffset(mID, mOffset); - mFetcher->mTextureInfo.setRequestCompleteTimeAndLog(mID, timeNow); - } - - lldebugs << "HTTP COMPLETE: " << mID << llendl; - LLTextureFetchWorker* worker = mFetcher->getWorker(mID); - if (worker) - { - bool success = false; - bool partial = false; - if (HTTP_OK <= status && status < HTTP_MULTIPLE_CHOICES) - { - success = true; - if (HTTP_PARTIAL_CONTENT == status) // partial information - { - partial = true; - } - } - - if (!success) - { - worker->setGetStatus(status, reason); -// llwarns << "CURL GET FAILED, status:" << status << " reason:" << reason << llendl; - } - - S32 data_size = worker->callbackHttpGet(channels, buffer, partial, success); - - if(log_texture_traffic && data_size > 0) - { - LLViewerTexture* tex = LLViewerTextureManager::findTexture(mID) ; - if(tex) - { - gTotalTextureBytesPerBoostLevel[tex->getBoostLevel()] += data_size ; - } - } - - mFetcher->removeFromHTTPQueue(mID, data_size); - - if (worker->mMetricsStartTime) - { - LLViewerAssetStatsFF::record_response_thread1(LLViewerAssetType::AT_TEXTURE, - true, - LLImageBase::TYPE_AVATAR_BAKE == worker->mType, - LLViewerAssetStatsFF::get_timestamp() - worker->mMetricsStartTime); - worker->mMetricsStartTime = 0; - } - LLViewerAssetStatsFF::record_dequeue_thread1(LLViewerAssetType::AT_TEXTURE, - true, - LLImageBase::TYPE_AVATAR_BAKE == worker->mType); - } - else - { - mFetcher->removeFromHTTPQueue(mID); - llwarns << "Worker not found: " << mID << llendl; - } - } - - virtual bool followRedir() - { - return mFollowRedir; - } - -private: - LLTextureFetch* mFetcher; - LLUUID mID; - U64 mStartTime; - S32 mRequestedSize; - U32 mOffset; - bool mFollowRedir; -}; - -////////////////////////////////////////////////////////////////////////////// - -// 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 -const char* LLTextureFetchWorker::sStateDescs[] = { - "INVALID", - "INIT", - "LOAD_FROM_TEXTURE_CACHE", - "CACHE_POST", - "LOAD_FROM_NETWORK", - "LOAD_FROM_SIMULATOR", - "SEND_HTTP_REQ", - "WAIT_HTTP_REQ", - "DECODE_IMAGE", - "DECODE_IMAGE_UPDATE", - "WRITE_TO_CACHE", - "WAIT_ON_WRITE", - "DONE", -}; - -// static -volatile bool LLTextureFetch::svMetricsDataBreak(true); // Start with a data break - -// called from MAIN THREAD - -LLTextureFetchWorker::LLTextureFetchWorker(LLTextureFetch* fetcher, - const std::string& url, // Optional URL - const LLUUID& id, // Image UUID - const LLHost& host, // Simulator host - F32 priority, // Priority - S32 discard, // Desired discard - S32 size) // Desired size - : LLWorkerClass(fetcher, "TextureFetch"), - mState(INIT), - mWriteToCacheState(NOT_WRITE), - mFetcher(fetcher), - mID(id), - mHost(host), - mUrl(url), - mImagePriority(priority), - mWorkPriority(0), - mRequestedPriority(0.f), - mDesiredDiscard(-1), - mSimRequestedDiscard(-1), - mRequestedDiscard(-1), - mLoadedDiscard(-1), - mDecodedDiscard(-1), - mCacheReadHandle(LLTextureCache::nullHandle()), - mCacheWriteHandle(LLTextureCache::nullHandle()), - mBuffer(NULL), - mBufferSize(0), - mRequestedSize(0), - mDesiredSize(TEXTURE_CACHE_ENTRY_SIZE), - mFileSize(0), - mCachedSize(0), - mLoaded(FALSE), - mSentRequest(UNSENT), - mDecodeHandle(0), - mDecoded(FALSE), - mWritten(FALSE), - mNeedsAux(FALSE), - mHaveAllData(FALSE), - mInLocalCache(FALSE), - mCanUseHTTP(true), - mHTTPFailCount(0), - mRetryAttempt(0), - mActiveCount(0), - mGetStatus(0), - mWorkMutex(NULL), - mFirstPacket(0), - mLastPacket(-1), - mTotalPackets(0), - mImageCodec(IMG_CODEC_INVALID), - mMetricsStartTime(0) -{ - mCanUseNET = mUrl.empty() ; - - calcWorkPriority(); - mType = host.isOk() ? LLImageBase::TYPE_AVATAR_BAKE : LLImageBase::TYPE_NORMAL; -// llinfos << "Create: " << mID << " mHost:" << host << " Discard=" << discard << llendl; - if (!mFetcher->mDebugPause) - { - U32 work_priority = mWorkPriority | LLWorkerThread::PRIORITY_HIGH; - addWork(0, work_priority ); - } - setDesiredDiscard(discard, size); -} - -LLTextureFetchWorker::~LLTextureFetchWorker() -{ -// llinfos << "Destroy: " << mID -// << " Decoded=" << mDecodedDiscard -// << " Requested=" << mRequestedDiscard -// << " Desired=" << mDesiredDiscard << llendl; - llassert_always(!haveWork()); - lockWorkMutex(); - if (mCacheReadHandle != LLTextureCache::nullHandle() && mFetcher->mTextureCache) - { - mFetcher->mTextureCache->readComplete(mCacheReadHandle, true); - } - if (mCacheWriteHandle != LLTextureCache::nullHandle() && mFetcher->mTextureCache) - { - mFetcher->mTextureCache->writeComplete(mCacheWriteHandle, true); - } - mFormattedImage = NULL; - clearPackets(); - unlockWorkMutex(); - mFetcher->removeFromHTTPQueue(mID); -} - -void LLTextureFetchWorker::clearPackets() -{ - for_each(mPackets.begin(), mPackets.end(), DeletePointer()); - mPackets.clear(); - mTotalPackets = 0; - mLastPacket = -1; - mFirstPacket = 0; -} - -void LLTextureFetchWorker::setupPacketData() -{ - S32 data_size = 0; - if (mFormattedImage.notNull()) - { - data_size = mFormattedImage->getDataSize(); - } - if (data_size > 0) - { - // Only used for simulator requests - mFirstPacket = (data_size - FIRST_PACKET_SIZE) / MAX_IMG_PACKET_SIZE + 1; - if (FIRST_PACKET_SIZE + (mFirstPacket-1) * MAX_IMG_PACKET_SIZE != data_size) - { - llwarns << "Bad CACHED TEXTURE size: " << data_size << " removing." << llendl; - removeFromCache(); - resetFormattedData(); - clearPackets(); - } - else if (mFileSize > 0) - { - mLastPacket = mFirstPacket-1; - mTotalPackets = (mFileSize - FIRST_PACKET_SIZE + MAX_IMG_PACKET_SIZE-1) / MAX_IMG_PACKET_SIZE + 1; - } - else - { - // This file was cached using HTTP so we have to refetch the first packet - resetFormattedData(); - clearPackets(); - } - } -} - -U32 LLTextureFetchWorker::calcWorkPriority() -{ - //llassert_always(mImagePriority >= 0 && mImagePriority <= LLViewerFetchedTexture::maxDecodePriority()); - static const F32 PRIORITY_SCALE = (F32)LLWorkerThread::PRIORITY_LOWBITS / LLViewerFetchedTexture::maxDecodePriority(); - - mWorkPriority = llmin((U32)LLWorkerThread::PRIORITY_LOWBITS, (U32)(mImagePriority * PRIORITY_SCALE)); - return mWorkPriority; -} - -// mWorkMutex is locked -void LLTextureFetchWorker::setDesiredDiscard(S32 discard, S32 size) -{ - bool prioritize = false; - if (mDesiredDiscard != discard) - { - if (!haveWork()) - { - calcWorkPriority(); - if (!mFetcher->mDebugPause) - { - U32 work_priority = mWorkPriority | LLWorkerThread::PRIORITY_HIGH; - addWork(0, work_priority); - } - } - else if (mDesiredDiscard < discard) - { - prioritize = true; - } - mDesiredDiscard = discard; - mDesiredSize = size; - } - else if (size > mDesiredSize) - { - mDesiredSize = size; - prioritize = true; - } - mDesiredSize = llmax(mDesiredSize, TEXTURE_CACHE_ENTRY_SIZE); - if ((prioritize && mState == INIT) || mState == DONE) - { - mState = INIT; - U32 work_priority = mWorkPriority | LLWorkerThread::PRIORITY_HIGH; - setPriority(work_priority); - } -} - -void LLTextureFetchWorker::setImagePriority(F32 priority) -{ -// llassert_always(priority >= 0 && priority <= LLViewerTexture::maxDecodePriority()); - F32 delta = fabs(priority - mImagePriority); - if (delta > (mImagePriority * .05f) || mState == DONE) - { - mImagePriority = priority; - calcWorkPriority(); - U32 work_priority = mWorkPriority | (getPriority() & LLWorkerThread::PRIORITY_HIGHBITS); - setPriority(work_priority); - } -} - -void LLTextureFetchWorker::resetFormattedData() -{ - delete[] mBuffer; - mBuffer = NULL; - mBufferSize = 0; - if (mFormattedImage.notNull()) - { - mFormattedImage->deleteData(); - } - mHaveAllData = FALSE; -} - -// Called from MAIN thread -void LLTextureFetchWorker::startWork(S32 param) -{ - llassert(mFormattedImage.isNull()); -} - -#include "llviewertexturelist.h" // debug - -// Called from LLWorkerThread::processRequest() -bool LLTextureFetchWorker::doWork(S32 param) -{ - LLMutexLock lock(&mWorkMutex); - - if ((mFetcher->isQuitting() || getFlags(LLWorkerClass::WCF_DELETE_REQUESTED))) - { - if (mState < DECODE_IMAGE) - { - return true; // abort - } - } - - if(mImagePriority < F_ALMOST_ZERO) - { - if (mState == INIT || mState == LOAD_FROM_NETWORK || mState == LOAD_FROM_SIMULATOR) - { - return true; // abort - } - } - if(mState > CACHE_POST && !mCanUseNET && !mCanUseHTTP) - { - //nowhere to get data, abort. - return true ; - } - - if (mFetcher->mDebugPause) - { - return false; // debug: don't do any work - } - if (mID == mFetcher->mDebugID) - { - mFetcher->mDebugCount++; // for setting breakpoints - } - - if (mState != DONE) - { - mFetchTimer.reset(); - } - - if (mState == INIT) - { - mRawImage = NULL ; - mRequestedDiscard = -1; - mLoadedDiscard = -1; - mDecodedDiscard = -1; - mRequestedSize = 0; - mFileSize = 0; - mCachedSize = 0; - mLoaded = FALSE; - mSentRequest = UNSENT; - mDecoded = FALSE; - mWritten = FALSE; - delete[] mBuffer; - mBuffer = NULL; - mBufferSize = 0; - mHaveAllData = FALSE; - clearPackets(); // TODO: Shouldn't be necessary - mCacheReadHandle = LLTextureCache::nullHandle(); - mCacheWriteHandle = LLTextureCache::nullHandle(); - mState = LOAD_FROM_TEXTURE_CACHE; - mDesiredSize = llmax(mDesiredSize, TEXTURE_CACHE_ENTRY_SIZE); // min desired size is TEXTURE_CACHE_ENTRY_SIZE - LL_DEBUGS("Texture") << mID << ": Priority: " << llformat("%8.0f",mImagePriority) - << " Desired Discard: " << mDesiredDiscard << " Desired Size: " << mDesiredSize << LL_ENDL; - // fall through - } - - if (mState == LOAD_FROM_TEXTURE_CACHE) - { - if (mCacheReadHandle == LLTextureCache::nullHandle()) - { - U32 cache_priority = mWorkPriority; - S32 offset = mFormattedImage.notNull() ? mFormattedImage->getDataSize() : 0; - S32 size = mDesiredSize - offset; - if (size <= 0) - { - mState = CACHE_POST; - return false; - } - mFileSize = 0; - mLoaded = FALSE; - - if (mUrl.compare(0, 7, "file://") == 0) - { - setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); // Set priority first since Responder may change it - - // read file from local disk - std::string filename = mUrl.substr(7, std::string::npos); - CacheReadResponder* responder = new CacheReadResponder(mFetcher, mID, mFormattedImage); - mCacheReadHandle = mFetcher->mTextureCache->readFromCache(filename, mID, cache_priority, - offset, size, responder); - } - else if (mUrl.empty()) - { - setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); // Set priority first since Responder may change it - - CacheReadResponder* responder = new CacheReadResponder(mFetcher, mID, mFormattedImage); - mCacheReadHandle = mFetcher->mTextureCache->readFromCache(mID, cache_priority, - offset, size, responder); - } - else if(mCanUseHTTP) - { - if (!(mUrl.compare(0, 7, "http://") == 0)) - { - // *TODO:?remove this warning - llwarns << "Unknown URL Type: " << mUrl << llendl; - } - setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority); - mState = SEND_HTTP_REQ; - } - else - { - setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority); - mState = LOAD_FROM_NETWORK; - } - } - - if (mLoaded) - { - // Make sure request is complete. *TODO: make this auto-complete - if (mFetcher->mTextureCache->readComplete(mCacheReadHandle, false)) - { - mCacheReadHandle = LLTextureCache::nullHandle(); - mState = CACHE_POST; - // fall through - } - else - { - return false; - } - } - else - { - return false; - } - } - - if (mState == CACHE_POST) - { - mCachedSize = mFormattedImage.notNull() ? mFormattedImage->getDataSize() : 0; - // Successfully loaded - if ((mCachedSize >= mDesiredSize) || mHaveAllData) - { - // we have enough data, decode it - llassert_always(mFormattedImage->getDataSize() > 0); - mLoadedDiscard = mDesiredDiscard; - mState = DECODE_IMAGE; - mWriteToCacheState = NOT_WRITE ; - LL_DEBUGS("Texture") << mID << ": Cached. Bytes: " << mFormattedImage->getDataSize() - << " Size: " << llformat("%dx%d",mFormattedImage->getWidth(),mFormattedImage->getHeight()) - << " Desired Discard: " << mDesiredDiscard << " Desired Size: " << mDesiredSize << LL_ENDL; - // fall through - } - else - { - if (mUrl.compare(0, 7, "file://") == 0) - { - // failed to load local file, we're done. - return true; - } - // need more data - else - { - LL_DEBUGS("Texture") << mID << ": Not in Cache" << LL_ENDL; - mState = LOAD_FROM_NETWORK; - } - // fall through - } - } - - if (mState == LOAD_FROM_NETWORK) - { - static LLCachedControl use_http(gSavedSettings,"ImagePipelineUseHTTP"); - -// if (mHost != LLHost::invalid) get_url = false; - if ( use_http && mCanUseHTTP && mUrl.empty())//get http url. - { - LLViewerRegion* region = NULL; - if (mHost == LLHost::invalid) - region = gAgent.getRegion(); - else - region = LLWorld::getInstance()->getRegion(mHost); - - if (region) - { - std::string http_url = region->getHttpUrl() ; - if (!http_url.empty()) - { - mUrl = http_url + "/?texture_id=" + mID.asString().c_str(); - mWriteToCacheState = CAN_WRITE ; //because this texture has a fixed texture id. - } - else - { - mCanUseHTTP = false ; - } - } - else - { - // This will happen if not logged in or if a region deoes not have HTTP Texture enabled - //llwarns << "Region not found for host: " << mHost << llendl; - mCanUseHTTP = false; - } - } - if (mCanUseHTTP && !mUrl.empty()) - { - mState = LLTextureFetchWorker::SEND_HTTP_REQ; - setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority); - if(mWriteToCacheState != NOT_WRITE) - { - mWriteToCacheState = CAN_WRITE ; - } - // don't return, fall through to next state - } - else if (mSentRequest == UNSENT && mCanUseNET) - { - // Add this to the network queue and sit here. - // LLTextureFetch::update() will send off a request which will change our state - mWriteToCacheState = CAN_WRITE ; - mRequestedSize = mDesiredSize; - mRequestedDiscard = mDesiredDiscard; - mSentRequest = QUEUED; - mFetcher->addToNetworkQueue(this); - if (! mMetricsStartTime) - { - mMetricsStartTime = LLViewerAssetStatsFF::get_timestamp(); - } - LLViewerAssetStatsFF::record_enqueue_thread1(LLViewerAssetType::AT_TEXTURE, - false, - LLImageBase::TYPE_AVATAR_BAKE == mType); - setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); - - return false; - } - else - { - // Shouldn't need to do anything here - //llassert_always(mFetcher->mNetworkQueue.find(mID) != mFetcher->mNetworkQueue.end()); - // Make certain this is in the network queue - //mFetcher->addToNetworkQueue(this); - //if (! mMetricsStartTime) - //{ - // mMetricsStartTime = LLViewerAssetStatsFF::get_timestamp(); - //} - //LLViewerAssetStatsFF::record_enqueue_thread1(LLViewerAssetType::AT_TEXTURE, false, - // LLImageBase::TYPE_AVATAR_BAKE == mType); - //setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); - return false; - } - } - - if (mState == LOAD_FROM_SIMULATOR) - { - if (mFormattedImage.isNull()) - { - mFormattedImage = new LLImageJ2C; - } - if (processSimulatorPackets()) - { - LL_DEBUGS("Texture") << mID << ": Loaded from Sim. Bytes: " << mFormattedImage->getDataSize() << LL_ENDL; - mFetcher->removeFromNetworkQueue(this, false); - if (mFormattedImage.isNull() || !mFormattedImage->getDataSize()) - { - // processSimulatorPackets() failed -// llwarns << "processSimulatorPackets() failed to load buffer" << llendl; - return true; // failed - } - setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority); - mState = DECODE_IMAGE; - mWriteToCacheState = SHOULD_WRITE; - - if (mMetricsStartTime) - { - LLViewerAssetStatsFF::record_response_thread1(LLViewerAssetType::AT_TEXTURE, - false, - LLImageBase::TYPE_AVATAR_BAKE == mType, - LLViewerAssetStatsFF::get_timestamp() - mMetricsStartTime); - mMetricsStartTime = 0; - } - LLViewerAssetStatsFF::record_dequeue_thread1(LLViewerAssetType::AT_TEXTURE, - false, - LLImageBase::TYPE_AVATAR_BAKE == mType); - } - else - { - mFetcher->addToNetworkQueue(this); // failsafe - if (! mMetricsStartTime) - { - mMetricsStartTime = LLViewerAssetStatsFF::get_timestamp(); - } - LLViewerAssetStatsFF::record_enqueue_thread1(LLViewerAssetType::AT_TEXTURE, - false, - LLImageBase::TYPE_AVATAR_BAKE == mType); - setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); - } - return false; - } - - if (mState == SEND_HTTP_REQ) - { - if(mCanUseHTTP) - { - //NOTE: - //control the number of the http requests issued for: - //1, not openning too many file descriptors at the same time; - //2, control the traffic of http so udp gets bandwidth. - // - static const S32 MAX_NUM_OF_HTTP_REQUESTS_IN_QUEUE = 8 ; - if(mFetcher->getNumHTTPRequests() > MAX_NUM_OF_HTTP_REQUESTS_IN_QUEUE) - { - return false ; //wait. - } - - mFetcher->removeFromNetworkQueue(this, false); - - S32 cur_size = 0; - if (mFormattedImage.notNull()) - { - cur_size = mFormattedImage->getDataSize(); // amount of data we already have - if (mFormattedImage->getDiscardLevel() == 0) - { - if(cur_size > 0) - { - // We already have all the data, just decode it - mLoadedDiscard = mFormattedImage->getDiscardLevel(); - mState = DECODE_IMAGE; - return false; - } - else - { - return true ; //abort. - } - } - } - mRequestedSize = mDesiredSize; - mRequestedDiscard = mDesiredDiscard; - mRequestedSize -= cur_size; - S32 offset = cur_size; - mBufferSize = cur_size; // This will get modified by callbackHttpGet() - - bool res = false; - if (!mUrl.empty()) - { - mLoaded = FALSE; - mGetStatus = 0; - mGetReason.clear(); - LL_DEBUGS("Texture") << "HTTP GET: " << mID << " Offset: " << offset - << " Bytes: " << mRequestedSize - << " Bandwidth(kbps): " << mFetcher->getTextureBandwidth() << "/" << mFetcher->mMaxBandwidth - << LL_ENDL; - setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); - mState = WAIT_HTTP_REQ; - - mFetcher->addToHTTPQueue(mID); - if (! mMetricsStartTime) - { - mMetricsStartTime = LLViewerAssetStatsFF::get_timestamp(); - } - LLViewerAssetStatsFF::record_enqueue_thread1(LLViewerAssetType::AT_TEXTURE, - true, - LLImageBase::TYPE_AVATAR_BAKE == mType); - - // Will call callbackHttpGet when curl request completes - std::vector headers; - headers.push_back("Accept: image/x-j2c"); - res = mFetcher->mCurlGetRequest->getByteRange(mUrl, headers, offset, mRequestedSize, - new HTTPGetResponder(mFetcher, mID, LLTimer::getTotalTime(), mRequestedSize, offset, true)); - } - if (!res) - { - llwarns << "HTTP GET request failed for " << mID << llendl; - resetFormattedData(); - ++mHTTPFailCount; - return true; // failed - } - // fall through - } - else //can not use http fetch. - { - return true ; //abort - } - } - - if (mState == WAIT_HTTP_REQ) - { - if (mLoaded) - { - S32 cur_size = mFormattedImage.notNull() ? mFormattedImage->getDataSize() : 0; - if (mRequestedSize < 0) - { - S32 max_attempts; - if (mGetStatus == HTTP_NOT_FOUND) - { - mHTTPFailCount = max_attempts = 1; // Don't retry - llwarns << "Texture missing from server (404): " << mUrl << llendl; - - //roll back to try UDP - if(mCanUseNET) - { - mState = INIT ; - mCanUseHTTP = false ; - setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority); - return false ; - } - } - else if (mGetStatus == HTTP_SERVICE_UNAVAILABLE) - { - // *TODO: Should probably introduce a timer here to delay future HTTP requsts - // for a short time (~1s) to ease server load? Ideally the server would queue - // requests instead of returning 503... we already limit the number pending. - ++mHTTPFailCount; - max_attempts = mHTTPFailCount+1; // Keep retrying - LL_INFOS_ONCE("Texture") << "Texture server busy (503): " << mUrl << LL_ENDL; - } - else - { - const S32 HTTP_MAX_RETRY_COUNT = 3; - max_attempts = HTTP_MAX_RETRY_COUNT + 1; - ++mHTTPFailCount; - llinfos << "HTTP GET failed for: " << mUrl - << " Status: " << mGetStatus << " Reason: '" << mGetReason << "'" - << " Attempt:" << mHTTPFailCount+1 << "/" << max_attempts << llendl; - } - - if (mHTTPFailCount >= max_attempts) - { - if (cur_size > 0) - { - // Use available data - mLoadedDiscard = mFormattedImage->getDiscardLevel(); - mState = DECODE_IMAGE; - return false; - } - else - { - resetFormattedData(); - mState = DONE; - return true; // failed - } - } - else - { - mState = SEND_HTTP_REQ; - return false; // retry - } - } - - llassert_always(mBufferSize == cur_size + mRequestedSize); - if(!mBufferSize)//no data received. - { - delete[] mBuffer; - mBuffer = NULL; - - //abort. - mState = DONE; - return true; - } - - if (mFormattedImage.isNull()) - { - // For now, create formatted image based on extension - std::string extension = gDirUtilp->getExtension(mUrl); - mFormattedImage = LLImageFormatted::createFromType(LLImageBase::getCodecFromExtension(extension)); - if (mFormattedImage.isNull()) - { - mFormattedImage = new LLImageJ2C; // default - } - } - - if (mHaveAllData && mRequestedDiscard == 0) //the image file is fully loaded. - { - mFileSize = mBufferSize; - } - else //the file size is unknown. - { - mFileSize = mBufferSize + 1 ; //flag the file is not fully loaded. - } - - U8* buffer = new U8[mBufferSize]; - if (cur_size > 0) - { - memcpy(buffer, mFormattedImage->getData(), cur_size); - } - memcpy(buffer + cur_size, mBuffer, mRequestedSize); // append - // NOTE: setData releases current data and owns new data (buffer) - mFormattedImage->setData(buffer, mBufferSize); - // delete temp data - delete[] mBuffer; // Note: not 'buffer' (assigned in setData()) - mBuffer = NULL; - mBufferSize = 0; - mLoadedDiscard = mRequestedDiscard; - mState = DECODE_IMAGE; - if(mWriteToCacheState != NOT_WRITE) - { - mWriteToCacheState = SHOULD_WRITE ; - } - setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority); - return false; - } - else - { - setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); - return false; - } - } - - if (mState == DECODE_IMAGE) - { - static LLCachedControl textures_decode_disabled(gSavedSettings,"TextureDecodeDisabled"); - if(textures_decode_disabled) - { - // for debug use, don't decode - mState = DONE; - setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); - return true; - } - - if (mDesiredDiscard < 0) - { - // We aborted, don't decode - mState = DONE; - setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); - return true; - } - - if (mFormattedImage->getDataSize() <= 0) - { - //llerrs << "Decode entered with invalid mFormattedImage. ID = " << mID << llendl; - - //abort, don't decode - mState = DONE; - setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); - return true; - } - if (mLoadedDiscard < 0) - { - //llerrs << "Decode entered with invalid mLoadedDiscard. ID = " << mID << llendl; - - //abort, don't decode - mState = DONE; - setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); - return true; - } - setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); // Set priority first since Responder may change it - mRawImage = NULL; - mAuxImage = NULL; - llassert_always(mFormattedImage.notNull()); - S32 discard = mHaveAllData ? 0 : mLoadedDiscard; - U32 image_priority = LLWorkerThread::PRIORITY_NORMAL | mWorkPriority; - mDecoded = FALSE; - mState = DECODE_IMAGE_UPDATE; - LL_DEBUGS("Texture") << mID << ": Decoding. Bytes: " << mFormattedImage->getDataSize() << " Discard: " << discard - << " All Data: " << mHaveAllData << LL_ENDL; - mDecodeHandle = mFetcher->mImageDecodeThread->decodeImage(mFormattedImage, image_priority, discard, mNeedsAux, - new DecodeResponder(mFetcher, mID, this)); - // fall though - } - - if (mState == DECODE_IMAGE_UPDATE) - { - if (mDecoded) - { - if (mDecodedDiscard < 0) - { - LL_DEBUGS("Texture") << mID << ": Failed to Decode." << LL_ENDL; - if (mCachedSize > 0 && !mInLocalCache && mRetryAttempt == 0) - { - // Cache file should be deleted, try again -// llwarns << mID << ": Decode of cached file failed (removed), retrying" << llendl; - llassert_always(mDecodeHandle == 0); - mFormattedImage = NULL; - ++mRetryAttempt; - setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority); - mState = INIT; - return false; - } - else - { -// llwarns << "UNABLE TO LOAD TEXTURE: " << mID << " RETRIES: " << mRetryAttempt << llendl; - mState = DONE; // failed - } - } - else - { - llassert_always(mRawImage.notNull()); - LL_DEBUGS("Texture") << mID << ": Decoded. Discard: " << mDecodedDiscard - << " Raw Image: " << llformat("%dx%d",mRawImage->getWidth(),mRawImage->getHeight()) << LL_ENDL; - setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority); - mState = WRITE_TO_CACHE; - } - // fall through - } - else - { - return false; - } - } - - if (mState == WRITE_TO_CACHE) - { - if (mWriteToCacheState != SHOULD_WRITE || mFormattedImage.isNull()) - { - // If we're in a local cache or we didn't actually receive any new data, - // or we failed to load anything, skip - mState = DONE; - return false; - } - S32 datasize = mFormattedImage->getDataSize(); - if(mFileSize < datasize)//This could happen when http fetching and sim fetching mixed. - { - if(mHaveAllData) - { - mFileSize = datasize ; - } - else - { - mFileSize = datasize + 1 ; //flag not fully loaded. - } - } - llassert_always(datasize); - setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); // Set priority first since Responder may change it - U32 cache_priority = mWorkPriority; - mWritten = FALSE; - mState = WAIT_ON_WRITE; - CacheWriteResponder* responder = new CacheWriteResponder(mFetcher, mID); - mCacheWriteHandle = mFetcher->mTextureCache->writeToCache(mID, cache_priority, - mFormattedImage->getData(), datasize, - mFileSize, responder); - // fall through - } - - if (mState == WAIT_ON_WRITE) - { - if (writeToCacheComplete()) - { - mState = DONE; - // fall through - } - else - { - if (mDesiredDiscard < mDecodedDiscard) - { - // We're waiting for this write to complete before we can receive more data - // (we can't touch mFormattedImage until the write completes) - // Prioritize the write - mFetcher->mTextureCache->prioritizeWrite(mCacheWriteHandle); - } - return false; - } - } - - if (mState == DONE) - { - if (mDecodedDiscard >= 0 && mDesiredDiscard < mDecodedDiscard) - { - // More data was requested, return to INIT - mState = INIT; - setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority); - return false; - } - else - { - setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); - return true; - } - } - - return false; -} - -// Called from MAIN thread -void LLTextureFetchWorker::endWork(S32 param, bool aborted) -{ - if (mDecodeHandle != 0) - { - mFetcher->mImageDecodeThread->abortRequest(mDecodeHandle, false); - mDecodeHandle = 0; - } - mFormattedImage = NULL; -} - -////////////////////////////////////////////////////////////////////////////// - -// virtual -void LLTextureFetchWorker::finishWork(S32 param, bool completed) -{ - // The following are required in case the work was aborted - if (mCacheReadHandle != LLTextureCache::nullHandle()) - { - mFetcher->mTextureCache->readComplete(mCacheReadHandle, true); - mCacheReadHandle = LLTextureCache::nullHandle(); - } - if (mCacheWriteHandle != LLTextureCache::nullHandle()) - { - mFetcher->mTextureCache->writeComplete(mCacheWriteHandle, true); - mCacheWriteHandle = LLTextureCache::nullHandle(); - } -} - -// virtual -bool LLTextureFetchWorker::deleteOK() -{ - bool delete_ok = true; - // Allow any pending reads or writes to complete - if (mCacheReadHandle != LLTextureCache::nullHandle()) - { - if (mFetcher->mTextureCache->readComplete(mCacheReadHandle, true)) - { - mCacheReadHandle = LLTextureCache::nullHandle(); - } - else - { - delete_ok = false; - } - } - if (mCacheWriteHandle != LLTextureCache::nullHandle()) - { - if (mFetcher->mTextureCache->writeComplete(mCacheWriteHandle)) - { - mCacheWriteHandle = LLTextureCache::nullHandle(); - } - else - { - delete_ok = false; - } - } - - if ((haveWork() && - // not ok to delete from these states - ((mState >= WRITE_TO_CACHE && mState <= WAIT_ON_WRITE)))) - { - delete_ok = false; - } - - return delete_ok; -} - -void LLTextureFetchWorker::removeFromCache() -{ - if (!mInLocalCache) - { - mFetcher->mTextureCache->removeFromCache(mID); - } -} - - -////////////////////////////////////////////////////////////////////////////// - -bool LLTextureFetchWorker::processSimulatorPackets() -{ - if (mFormattedImage.isNull() || mRequestedSize < 0) - { - // not sure how we got here, but not a valid state, abort! - llassert_always(mDecodeHandle == 0); - mFormattedImage = NULL; - return true; - } - - if (mLastPacket >= mFirstPacket) - { - S32 buffer_size = mFormattedImage->getDataSize(); - for (S32 i = mFirstPacket; i<=mLastPacket; i++) - { - llassert_always(mPackets[i]); - buffer_size += mPackets[i]->mSize; - } - bool have_all_data = mLastPacket >= mTotalPackets-1; - if (mRequestedSize <= 0) - { - // We received a packed but haven't requested anything yet (edge case) - // Return true (we're "done") since we didn't request anything - return true; - } - if (buffer_size >= mRequestedSize || have_all_data) - { - /// We have enough (or all) data - if (have_all_data) - { - mHaveAllData = TRUE; - } - S32 cur_size = mFormattedImage->getDataSize(); - if (buffer_size > cur_size) - { - /// We have new data - U8* buffer = new U8[buffer_size]; - S32 offset = 0; - if (cur_size > 0 && mFirstPacket > 0) - { - memcpy(buffer, mFormattedImage->getData(), cur_size); - offset = cur_size; - } - for (S32 i=mFirstPacket; i<=mLastPacket; i++) - { - memcpy(buffer + offset, mPackets[i]->mData, mPackets[i]->mSize); - offset += mPackets[i]->mSize; - } - // NOTE: setData releases current data - mFormattedImage->setData(buffer, buffer_size); - } - mLoadedDiscard = mRequestedDiscard; - return true; - } - } - return false; -} - -////////////////////////////////////////////////////////////////////////////// - -S32 LLTextureFetchWorker::callbackHttpGet(const LLChannelDescriptors& channels, - const LLIOPipe::buffer_ptr_t& buffer, - bool partial, bool success) -{ - S32 data_size = 0 ; - - LLMutexLock lock(&mWorkMutex); - - if (mState != WAIT_HTTP_REQ) - { - llwarns << "callbackHttpGet for unrequested fetch worker: " << mID - << " req=" << mSentRequest << " state= " << mState << llendl; - return data_size; - } - if (mLoaded) - { - llwarns << "Duplicate callback for " << mID.asString() << llendl; - return data_size ; // ignore duplicate callback - } - if (success) - { - // get length of stream: - data_size = buffer->countAfter(channels.in(), NULL); - - LL_DEBUGS("Texture") << "HTTP RECEIVED: " << mID.asString() << " Bytes: " << data_size << LL_ENDL; - if (data_size > 0) - { - // *TODO: set the formatted image data here directly to avoid the copy - mBuffer = new U8[data_size]; - buffer->readAfter(channels.in(), NULL, mBuffer, data_size); - mBufferSize += data_size; - if (data_size < mRequestedSize && mRequestedDiscard == 0) - { - mHaveAllData = TRUE; - } - else if (data_size > mRequestedSize) - { - // *TODO: This shouldn't be happening any more - llwarns << "data_size = " << data_size << " > requested: " << mRequestedSize << llendl; - mHaveAllData = TRUE; - llassert_always(mDecodeHandle == 0); - mFormattedImage = NULL; // discard any previous data we had - mBufferSize = data_size; - } - } - else - { - // We requested data but received none (and no error), - // so presumably we have all of it - mHaveAllData = TRUE; - } - mRequestedSize = data_size; - } - else - { - mRequestedSize = -1; // error - } - mLoaded = TRUE; - setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority); - - return data_size ; -} - -////////////////////////////////////////////////////////////////////////////// - -void LLTextureFetchWorker::callbackCacheRead(bool success, LLImageFormatted* image, - S32 imagesize, BOOL islocal) -{ - LLMutexLock lock(&mWorkMutex); - if (mState != LOAD_FROM_TEXTURE_CACHE) - { -// llwarns << "Read callback for " << mID << " with state = " << mState << llendl; - return; - } - if (success) - { - llassert_always(imagesize >= 0); - mFileSize = imagesize; - mFormattedImage = image; - mImageCodec = image->getCodec(); - mInLocalCache = islocal; - if (mFileSize != 0 && mFormattedImage->getDataSize() >= mFileSize) - { - mHaveAllData = TRUE; - } - } - mLoaded = TRUE; - setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority); -} - -void LLTextureFetchWorker::callbackCacheWrite(bool success) -{ - LLMutexLock lock(&mWorkMutex); - if (mState != WAIT_ON_WRITE) - { -// llwarns << "Write callback for " << mID << " with state = " << mState << llendl; - return; - } - mWritten = TRUE; - setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority); -} - -////////////////////////////////////////////////////////////////////////////// - -void LLTextureFetchWorker::callbackDecoded(bool success, LLImageRaw* raw, LLImageRaw* aux) -{ - LLMutexLock lock(&mWorkMutex); - if (mDecodeHandle == 0) - { - return; // aborted, ignore - } - if (mState != DECODE_IMAGE_UPDATE) - { -// llwarns << "Decode callback for " << mID << " with state = " << mState << llendl; - mDecodeHandle = 0; - return; - } - llassert_always(mFormattedImage.notNull()); - - mDecodeHandle = 0; - if (success) - { - llassert_always(raw); - mRawImage = raw; - mAuxImage = aux; - mDecodedDiscard = mFormattedImage->getDiscardLevel(); - LL_DEBUGS("Texture") << mID << ": Decode Finished. Discard: " << mDecodedDiscard - << " Raw Image: " << llformat("%dx%d",mRawImage->getWidth(),mRawImage->getHeight()) << LL_ENDL; - } - else - { - llwarns << "DECODE FAILED: " << mID << " Discard: " << (S32)mFormattedImage->getDiscardLevel() << llendl; - removeFromCache(); - mDecodedDiscard = -1; // Redundant, here for clarity and paranoia - } - mDecoded = TRUE; -// llinfos << mID << " : DECODE COMPLETE " << llendl; - setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority); -} - -////////////////////////////////////////////////////////////////////////////// - -bool LLTextureFetchWorker::writeToCacheComplete() -{ - // Complete write to cache - if (mCacheWriteHandle != LLTextureCache::nullHandle()) - { - if (!mWritten) - { - return false; - } - if (mFetcher->mTextureCache->writeComplete(mCacheWriteHandle)) - { - mCacheWriteHandle = LLTextureCache::nullHandle(); - } - else - { - return false; - } - } - return true; -} - - -////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// -// public - -LLTextureFetch::LLTextureFetch(LLTextureCache* cache, LLImageDecodeThread* imagedecodethread, bool threaded, bool qa_mode) - : LLWorkerThread("TextureFetch", threaded), - mDebugCount(0), - mDebugPause(FALSE), - mPacketCount(0), - mBadPacketCount(0), - mQueueMutex(getAPRPool()), - mNetworkQueueMutex(getAPRPool()), - mTextureCache(cache), - mImageDecodeThread(imagedecodethread), - mTextureBandwidth(0), - mHTTPTextureBits(0), - mTotalHTTPRequests(0), - mCurlGetRequest(NULL), - mQAMode(qa_mode) -{ - mCurlPOSTRequestCount = 0; - mMaxBandwidth = gSavedSettings.getF32("ThrottleBandwidthKBPS"); - mTextureInfo.setUpLogging(gSavedSettings.getBOOL("LogTextureDownloadsToViewerLog"), gSavedSettings.getBOOL("LogTextureDownloadsToSimulator"), gSavedSettings.getU32("TextureLoggingThreshold")); -} - -LLTextureFetch::~LLTextureFetch() -{ - clearDeleteList() ; - - while (! mCommands.empty()) - { - TFRequest * req(mCommands.front()); - mCommands.erase(mCommands.begin()); - delete req; - } - - // ~LLQueuedThread() called here -} - -bool LLTextureFetch::createRequest(const std::string& url, const LLUUID& id, const LLHost& host, F32 priority, - S32 w, S32 h, S32 c, S32 desired_discard, bool needs_aux, bool can_use_http) -{ - if (mDebugPause) - { - return false; - } - - LLTextureFetchWorker* worker = getWorker(id) ; - if (worker) - { - if (worker->mHost != host) - { - llwarns << "LLTextureFetch::createRequest " << id << " called with multiple hosts: " - << host << " != " << worker->mHost << llendl; - removeRequest(worker, true); - worker = NULL; - return false; - } - } - - S32 desired_size; - std::string exten = gDirUtilp->getExtension(url); - if (!url.empty() && (!exten.empty() && LLImageBase::getCodecFromExtension(exten) != IMG_CODEC_J2C)) - { - // Only do partial requests for J2C at the moment - desired_size = MAX_IMAGE_DATA_SIZE; - desired_discard = 0; - } - else if (desired_discard == 0) - { - // if we want the entire image, and we know its size, then get it all - // (calcDataSizeJ2C() below makes assumptions about how the image - // was compressed - this code ensures that when we request the entire image, - // we really do get it.) - desired_size = MAX_IMAGE_DATA_SIZE; - } - else if (w*h*c > 0) - { - // If the requester knows the dimensions of the image, - // this will calculate how much data we need without having to parse the header - - desired_size = LLImageJ2C::calcDataSizeJ2C(w, h, c, desired_discard); - } - else - { - desired_size = TEXTURE_CACHE_ENTRY_SIZE; - desired_discard = MAX_DISCARD_LEVEL; - } - - - if (worker) - { - if (worker->wasAborted()) - { - return false; // need to wait for previous aborted request to complete - } - worker->lockWorkMutex(); - worker->mActiveCount++; - worker->mNeedsAux = needs_aux; - worker->setImagePriority(priority); - worker->setDesiredDiscard(desired_discard, desired_size); - worker->setCanUseHTTP(can_use_http) ; - if (!worker->haveWork()) - { - worker->mState = LLTextureFetchWorker::INIT; - worker->unlockWorkMutex(); - - worker->addWork(0, LLWorkerThread::PRIORITY_HIGH | worker->mWorkPriority); - } - else - { - worker->unlockWorkMutex(); - } - } - else - { - worker = new LLTextureFetchWorker(this, url, id, host, priority, desired_discard, desired_size); - lockQueue() ; - mRequestMap[id] = worker; - unlockQueue() ; - - worker->lockWorkMutex(); - worker->mActiveCount++; - worker->mNeedsAux = needs_aux; - worker->setCanUseHTTP(can_use_http) ; - worker->unlockWorkMutex(); - } - -// llinfos << "REQUESTED: " << id << " Discard: " << desired_discard << llendl; - return true; -} - -// protected -void LLTextureFetch::addToNetworkQueue(LLTextureFetchWorker* worker) -{ - lockQueue() ; - bool in_request_map = (mRequestMap.find(worker->mID) != mRequestMap.end()) ; - unlockQueue() ; - - LLMutexLock lock(&mNetworkQueueMutex); - if (in_request_map) - { - // only add to the queue if in the request map - // i.e. a delete has not been requested - mNetworkQueue.insert(worker->mID); - } - for (cancel_queue_t::iterator iter1 = mCancelQueue.begin(); - iter1 != mCancelQueue.end(); ++iter1) - { - iter1->second.erase(worker->mID); - } -} - -void LLTextureFetch::removeFromNetworkQueue(LLTextureFetchWorker* worker, bool cancel) -{ - LLMutexLock lock(&mNetworkQueueMutex); - size_t erased = mNetworkQueue.erase(worker->mID); - if (cancel && erased > 0) - { - mCancelQueue[worker->mHost].insert(worker->mID); - } -} - -// protected -void LLTextureFetch::addToHTTPQueue(const LLUUID& id) -{ - LLMutexLock lock(&mNetworkQueueMutex); - mHTTPTextureQueue.insert(id); - mTotalHTTPRequests++; -} - -void LLTextureFetch::removeFromHTTPQueue(const LLUUID& id, S32 received_size) -{ - LLMutexLock lock(&mNetworkQueueMutex); - mHTTPTextureQueue.erase(id); - mHTTPTextureBits += received_size * 8; // Approximate - does not include header bits -} - -void LLTextureFetch::deleteRequest(const LLUUID& id, bool cancel) -{ - lockQueue() ; - LLTextureFetchWorker* worker = getWorkerAfterLock(id); - if (worker) - { - size_t erased_1 = mRequestMap.erase(worker->mID); - unlockQueue() ; - - llassert_always(erased_1 > 0) ; - - removeFromNetworkQueue(worker, cancel); - llassert_always(!(worker->getFlags(LLWorkerClass::WCF_DELETE_REQUESTED))) ; - - worker->scheduleDelete(); - } - else - { - unlockQueue() ; - } -} - -void LLTextureFetch::removeRequest(LLTextureFetchWorker* worker, bool cancel) -{ - lockQueue() ; - size_t erased_1 = mRequestMap.erase(worker->mID); - unlockQueue() ; - - llassert_always(erased_1 > 0) ; - removeFromNetworkQueue(worker, cancel); - llassert_always(!(worker->getFlags(LLWorkerClass::WCF_DELETE_REQUESTED))) ; - - worker->scheduleDelete(); -} - -S32 LLTextureFetch::getNumRequests() -{ - lockQueue() ; - S32 size = (S32)mRequestMap.size(); - unlockQueue() ; - - return size ; -} - -S32 LLTextureFetch::getNumHTTPRequests() -{ - mNetworkQueueMutex.lock() ; - S32 size = (S32)mHTTPTextureQueue.size(); - mNetworkQueueMutex.unlock() ; - - return size ; -} - -U32 LLTextureFetch::getTotalNumHTTPRequests() -{ - mNetworkQueueMutex.lock() ; - U32 size = mTotalHTTPRequests ; - mNetworkQueueMutex.unlock() ; - - return size ; -} - -// call lockQueue() first! -LLTextureFetchWorker* LLTextureFetch::getWorkerAfterLock(const LLUUID& id) -{ - LLTextureFetchWorker* res = NULL; - map_t::iterator iter = mRequestMap.find(id); - if (iter != mRequestMap.end()) - { - res = iter->second; - } - return res; -} - -LLTextureFetchWorker* LLTextureFetch::getWorker(const LLUUID& id) -{ - LLMutexLock lock(&mQueueMutex) ; - - return getWorkerAfterLock(id) ; -} - - -bool LLTextureFetch::getRequestFinished(const LLUUID& id, S32& discard_level, - LLPointer& raw, LLPointer& aux) -{ - bool res = false; - LLTextureFetchWorker* worker = getWorker(id); - if (worker) - { - if (worker->wasAborted()) - { - res = true; - } - else if (!worker->haveWork()) - { - // Should only happen if we set mDebugPause... - if (!mDebugPause) - { -// llwarns << "Adding work for inactive worker: " << id << llendl; - worker->addWork(0, LLWorkerThread::PRIORITY_HIGH | worker->mWorkPriority); - } - } - else if (worker->checkWork()) - { - worker->lockWorkMutex(); - discard_level = worker->mDecodedDiscard; - raw = worker->mRawImage; - aux = worker->mAuxImage; - res = true; - LL_DEBUGS("Texture") << id << ": Request Finished. State: " << worker->mState << " Discard: " << discard_level << LL_ENDL; - worker->unlockWorkMutex(); - } - else - { - worker->lockWorkMutex(); - if ((worker->mDecodedDiscard >= 0) && - (worker->mDecodedDiscard < discard_level || discard_level < 0) && - (worker->mState >= LLTextureFetchWorker::WAIT_ON_WRITE)) - { - // Not finished, but data is ready - discard_level = worker->mDecodedDiscard; - raw = worker->mRawImage; - aux = worker->mAuxImage; - } - worker->unlockWorkMutex(); - } - } - else - { - res = true; - } - return res; -} - -bool LLTextureFetch::updateRequestPriority(const LLUUID& id, F32 priority) -{ - bool res = false; - LLTextureFetchWorker* worker = getWorker(id); - if (worker) - { - worker->lockWorkMutex(); - worker->setImagePriority(priority); - worker->unlockWorkMutex(); - res = true; - } - return res; -} - -// Replicates and expands upon the base class's -// getPending() implementation. getPending() and -// runCondition() replicate one another's logic to -// an extent and are sometimes used for the same -// function (deciding whether or not to sleep/pause -// a thread). So the implementations need to stay -// in step, at least until this can be refactored and -// the redundancy eliminated. -// -// May be called from any thread - -//virtual -S32 LLTextureFetch::getPending() -{ - S32 res; - lockData(); - { - LLMutexLock lock(&mQueueMutex); - - res = mRequestQueue.size(); - res += mCurlPOSTRequestCount; - res += mCommands.size(); - } - unlockData(); - return res; -} - -// virtual -bool LLTextureFetch::runCondition() -{ - // Caller is holding the lock on LLThread's condition variable. - - // LLQueuedThread, unlike its base class LLThread, makes this a - // private method which is unfortunate. I want to use it directly - // but I'm going to have to re-implement the logic here (or change - // declarations, which I don't want to do right now). - // - // Changes here may need to be reflected in getPending(). - - bool have_no_commands(false); - { - LLMutexLock lock(&mQueueMutex); - - have_no_commands = mCommands.empty(); - } - - bool have_no_curl_requests(0 == mCurlPOSTRequestCount); - - return ! (have_no_commands - && have_no_curl_requests - && (mRequestQueue.empty() && mIdleThread)); // From base class -} - -////////////////////////////////////////////////////////////////////////////// - -// MAIN THREAD (unthreaded envs), WORKER THREAD (threaded envs) -void LLTextureFetch::commonUpdate() -{ - // Run a cross-thread command, if any. - cmdDoWork(); - - // Update Curl on same thread as mCurlGetRequest was constructed - S32 processed = mCurlGetRequest->process(); - if (processed > 0) - { - lldebugs << "processed: " << processed << " messages." << llendl; - } -} - - -// MAIN THREAD -//virtual -S32 LLTextureFetch::update(U32 max_time_ms) -{ - static LLCachedControl band_width(gSavedSettings,"ThrottleBandwidthKBPS"); - - { - mNetworkQueueMutex.lock() ; - mMaxBandwidth = band_width ; - - gTextureList.sTextureBits += mHTTPTextureBits ; - mHTTPTextureBits = 0 ; - - mNetworkQueueMutex.unlock() ; - } - - S32 res = LLWorkerThread::update(max_time_ms); - - if (!mDebugPause) - { - sendRequestListToSimulators(); - } - - if (!mThreaded) - { - commonUpdate(); - } - - return res; -} - -//called in the MAIN thread after the TextureCacheThread shuts down. -void LLTextureFetch::shutDownTextureCacheThread() -{ - if(mTextureCache) - { - llassert_always(mTextureCache->isQuitting() || mTextureCache->isStopped()) ; - mTextureCache = NULL ; - } -} - -//called in the MAIN thread after the ImageDecodeThread shuts down. -void LLTextureFetch::shutDownImageDecodeThread() -{ - if(mImageDecodeThread) - { - llassert_always(mImageDecodeThread->isQuitting() || mImageDecodeThread->isStopped()) ; - mImageDecodeThread = NULL ; - } -} - -// WORKER THREAD -void LLTextureFetch::startThread() -{ - // Construct mCurlGetRequest from Worker Thread - mCurlGetRequest = new LLCurlRequest(); -} - -// WORKER THREAD -void LLTextureFetch::endThread() -{ - // Destroy mCurlGetRequest from Worker Thread - delete mCurlGetRequest; - mCurlGetRequest = NULL; -} - -// WORKER THREAD -void LLTextureFetch::threadedUpdate() -{ - llassert_always(mCurlGetRequest); - - // Limit update frequency - const F32 PROCESS_TIME = 0.05f; - static LLFrameTimer process_timer; - if (process_timer.getElapsedTimeF32() < PROCESS_TIME) - { - return; - } - process_timer.reset(); - - commonUpdate(); - -#if 0 - const F32 INFO_TIME = 1.0f; - static LLFrameTimer info_timer; - if (info_timer.getElapsedTimeF32() >= INFO_TIME) - { - S32 q = mCurlGetRequest->getQueued(); - if (q > 0) - { - llinfos << "Queued gets: " << q << llendl; - info_timer.reset(); - } - } -#endif - -} - -////////////////////////////////////////////////////////////////////////////// - -void LLTextureFetch::sendRequestListToSimulators() -{ - // All requests - const F32 REQUEST_DELTA_TIME = 0.10f; // 10 fps - - // Sim requests - const S32 IMAGES_PER_REQUEST = 50; - const F32 SIM_LAZY_FLUSH_TIMEOUT = 10.0f; // temp - const F32 MIN_REQUEST_TIME = 1.0f; - const F32 MIN_DELTA_PRIORITY = 1000.f; - - // Periodically, gather the list of textures that need data from the network - // And send the requests out to the simulators - static LLFrameTimer timer; - if (timer.getElapsedTimeF32() < REQUEST_DELTA_TIME) - { - return; - } - timer.reset(); - - // Send requests - typedef std::set request_list_t; - typedef std::map< LLHost, request_list_t > work_request_map_t; - work_request_map_t requests; - { - LLMutexLock lock2(&mNetworkQueueMutex); - for (queue_t::iterator iter = mNetworkQueue.begin(); iter != mNetworkQueue.end(); ) - { - queue_t::iterator curiter = iter++; - LLTextureFetchWorker* req = getWorker(*curiter); - if (!req) - { - mNetworkQueue.erase(curiter); - continue; // paranoia - } - if ((req->mState != LLTextureFetchWorker::LOAD_FROM_NETWORK) && - (req->mState != LLTextureFetchWorker::LOAD_FROM_SIMULATOR)) - { - // We already received our URL, remove from the queue - llwarns << "Worker: " << req->mID << " in mNetworkQueue but in wrong state: " << req->mState << llendl; - mNetworkQueue.erase(curiter); - continue; - } - if (req->mID == mDebugID) - { - mDebugCount++; // for setting breakpoints - } - if (req->mSentRequest == LLTextureFetchWorker::SENT_SIM && - req->mTotalPackets > 0 && - req->mLastPacket >= req->mTotalPackets-1) - { - // We have all the packets... make sure this is high priority -// req->setPriority(LLWorkerThread::PRIORITY_HIGH | req->mWorkPriority); - continue; - } - F32 elapsed = req->mRequestedTimer.getElapsedTimeF32(); - { - F32 delta_priority = llabs(req->mRequestedPriority - req->mImagePriority); - if ((req->mSimRequestedDiscard != req->mDesiredDiscard) || - (delta_priority > MIN_DELTA_PRIORITY && elapsed >= MIN_REQUEST_TIME) || - (elapsed >= SIM_LAZY_FLUSH_TIMEOUT)) - { - requests[req->mHost].insert(req); - } - } - } - } - - for (work_request_map_t::iterator iter1 = requests.begin(); - iter1 != requests.end(); ++iter1) - { - LLHost host = iter1->first; - // invalid host = use agent host - if (host == LLHost::invalid) - { - host = gAgent.getRegionHost(); - } - - S32 sim_request_count = 0; - - for (request_list_t::iterator iter2 = iter1->second.begin(); - iter2 != iter1->second.end(); ++iter2) - { - LLTextureFetchWorker* req = *iter2; - if (gMessageSystem) - { - if (req->mSentRequest != LLTextureFetchWorker::SENT_SIM) - { - // Initialize packet data based on data read from cache - req->lockWorkMutex(); - req->setupPacketData(); - req->unlockWorkMutex(); - } - if (0 == sim_request_count) - { - gMessageSystem->newMessageFast(_PREHASH_RequestImage); - gMessageSystem->nextBlockFast(_PREHASH_AgentData); - gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - } - S32 packet = req->mLastPacket + 1; - gMessageSystem->nextBlockFast(_PREHASH_RequestImage); - gMessageSystem->addUUIDFast(_PREHASH_Image, req->mID); - gMessageSystem->addS8Fast(_PREHASH_DiscardLevel, (S8)req->mDesiredDiscard); - gMessageSystem->addF32Fast(_PREHASH_DownloadPriority, req->mImagePriority); - gMessageSystem->addU32Fast(_PREHASH_Packet, packet); - gMessageSystem->addU8Fast(_PREHASH_Type, req->mType); -// llinfos << "IMAGE REQUEST: " << req->mID << " Discard: " << req->mDesiredDiscard -// << " Packet: " << packet << " Priority: " << req->mImagePriority << llendl; - - static LLCachedControl log_to_viewer_log(gSavedSettings,"LogTextureDownloadsToViewerLog"); - static LLCachedControl log_to_sim(gSavedSettings,"LogTextureDownloadsToSimulator"); - if (log_to_viewer_log || log_to_sim) - { - mTextureInfo.setRequestStartTime(req->mID, LLTimer::getTotalTime()); - mTextureInfo.setRequestOffset(req->mID, 0); - mTextureInfo.setRequestSize(req->mID, 0); - mTextureInfo.setRequestType(req->mID, LLTextureInfoDetails::REQUEST_TYPE_UDP); - } - - req->lockWorkMutex(); - req->mSentRequest = LLTextureFetchWorker::SENT_SIM; - req->mSimRequestedDiscard = req->mDesiredDiscard; - req->mRequestedPriority = req->mImagePriority; - req->mRequestedTimer.reset(); - req->unlockWorkMutex(); - sim_request_count++; - if (sim_request_count >= IMAGES_PER_REQUEST) - { -// llinfos << "REQUESTING " << sim_request_count << " IMAGES FROM HOST: " << host.getIPString() << llendl; - - gMessageSystem->sendSemiReliable(host, NULL, NULL); - sim_request_count = 0; - } - } - } - if (gMessageSystem && sim_request_count > 0 && sim_request_count < IMAGES_PER_REQUEST) - { -// llinfos << "REQUESTING " << sim_request_count << " IMAGES FROM HOST: " << host.getIPString() << llendl; - gMessageSystem->sendSemiReliable(host, NULL, NULL); - sim_request_count = 0; - } - } - - // Send cancelations - { - LLMutexLock lock2(&mNetworkQueueMutex); - if (gMessageSystem && !mCancelQueue.empty()) - { - for (cancel_queue_t::iterator iter1 = mCancelQueue.begin(); - iter1 != mCancelQueue.end(); ++iter1) - { - LLHost host = iter1->first; - if (host == LLHost::invalid) - { - host = gAgent.getRegionHost(); - } - S32 request_count = 0; - for (queue_t::iterator iter2 = iter1->second.begin(); - iter2 != iter1->second.end(); ++iter2) - { - if (0 == request_count) - { - gMessageSystem->newMessageFast(_PREHASH_RequestImage); - gMessageSystem->nextBlockFast(_PREHASH_AgentData); - gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - } - gMessageSystem->nextBlockFast(_PREHASH_RequestImage); - gMessageSystem->addUUIDFast(_PREHASH_Image, *iter2); - gMessageSystem->addS8Fast(_PREHASH_DiscardLevel, -1); - gMessageSystem->addF32Fast(_PREHASH_DownloadPriority, 0); - gMessageSystem->addU32Fast(_PREHASH_Packet, 0); - gMessageSystem->addU8Fast(_PREHASH_Type, 0); -// llinfos << "CANCELING IMAGE REQUEST: " << (*iter2) << llendl; - - request_count++; - if (request_count >= IMAGES_PER_REQUEST) - { - gMessageSystem->sendSemiReliable(host, NULL, NULL); - request_count = 0; - } - } - if (request_count > 0 && request_count < IMAGES_PER_REQUEST) - { - gMessageSystem->sendSemiReliable(host, NULL, NULL); - } - } - mCancelQueue.clear(); - } - } -} - -////////////////////////////////////////////////////////////////////////////// - -bool LLTextureFetchWorker::insertPacket(S32 index, U8* data, S32 size) -{ - mRequestedTimer.reset(); - if (index >= mTotalPackets) - { -// llwarns << "Received Image Packet " << index << " > max: " << mTotalPackets << " for image: " << mID << llendl; - return false; - } - if (index > 0 && index < mTotalPackets-1 && size != MAX_IMG_PACKET_SIZE) - { -// llwarns << "Received bad sized packet: " << index << ", " << size << " != " << MAX_IMG_PACKET_SIZE << " for image: " << mID << llendl; - return false; - } - - if (index >= (S32)mPackets.size()) - { - mPackets.resize(index+1, (PacketData*)NULL); // initializes v to NULL pointers - } - else if (mPackets[index] != NULL) - { -// llwarns << "Received duplicate packet: " << index << " for image: " << mID << llendl; - return false; - } - - mPackets[index] = new PacketData(data, size); - while (mLastPacket+1 < (S32)mPackets.size() && mPackets[mLastPacket+1] != NULL) - { - ++mLastPacket; - } - return true; -} - -bool LLTextureFetch::receiveImageHeader(const LLHost& host, const LLUUID& id, U8 codec, U16 packets, U32 totalbytes, - U16 data_size, U8* data) -{ - LLTextureFetchWorker* worker = getWorker(id); - bool res = true; - - ++mPacketCount; - - if (!worker) - { -// llwarns << "Received header for non active worker: " << id << llendl; - res = false; - } - else if (worker->mState != LLTextureFetchWorker::LOAD_FROM_NETWORK || - worker->mSentRequest != LLTextureFetchWorker::SENT_SIM) - { -// llwarns << "receiveImageHeader for worker: " << id -// << " in state: " << LLTextureFetchWorker::sStateDescs[worker->mState] -// << " sent: " << worker->mSentRequest << llendl; - res = false; - } - else if (worker->mLastPacket != -1) - { - // check to see if we've gotten this packet before -// llwarns << "Received duplicate header for: " << id << llendl; - res = false; - } - else if (!data_size) - { -// llwarns << "Img: " << id << ":" << " Empty Image Header" << llendl; - res = false; - } - if (!res) - { - ++mBadPacketCount; - mNetworkQueueMutex.lock() ; - mCancelQueue[host].insert(id); - mNetworkQueueMutex.unlock() ; - return false; - } - - worker->lockWorkMutex(); - - // Copy header data into image object - worker->mImageCodec = codec; - worker->mTotalPackets = packets; - worker->mFileSize = (S32)totalbytes; - llassert_always(totalbytes > 0); - llassert_always(data_size == FIRST_PACKET_SIZE || data_size == worker->mFileSize); - res = worker->insertPacket(0, data, data_size); - worker->setPriority(LLWorkerThread::PRIORITY_HIGH | worker->mWorkPriority); - worker->mState = LLTextureFetchWorker::LOAD_FROM_SIMULATOR; - worker->unlockWorkMutex(); - return res; -} - -bool LLTextureFetch::receiveImagePacket(const LLHost& host, const LLUUID& id, U16 packet_num, U16 data_size, U8* data) -{ - LLTextureFetchWorker* worker = getWorker(id); - bool res = true; - - ++mPacketCount; - - if (!worker) - { -// llwarns << "Received packet " << packet_num << " for non active worker: " << id << llendl; - res = false; - } - else if (worker->mLastPacket == -1) - { -// llwarns << "Received packet " << packet_num << " before header for: " << id << llendl; - res = false; - } - else if (!data_size) - { -// llwarns << "Img: " << id << ":" << " Empty Image Header" << llendl; - res = false; - } - if (!res) - { - ++mBadPacketCount; - mNetworkQueueMutex.lock() ; - mCancelQueue[host].insert(id); - mNetworkQueueMutex.unlock() ; - return false; - } - - worker->lockWorkMutex(); - - res = worker->insertPacket(packet_num, data, data_size); - - if ((worker->mState == LLTextureFetchWorker::LOAD_FROM_SIMULATOR) || - (worker->mState == LLTextureFetchWorker::LOAD_FROM_NETWORK)) - { - worker->setPriority(LLWorkerThread::PRIORITY_HIGH | worker->mWorkPriority); - worker->mState = LLTextureFetchWorker::LOAD_FROM_SIMULATOR; - } - else - { -// llwarns << "receiveImagePacket " << packet_num << "/" << worker->mLastPacket << " for worker: " << id -// << " in state: " << LLTextureFetchWorker::sStateDescs[worker->mState] << llendl; - removeFromNetworkQueue(worker, true); // failsafe - } - - if(packet_num >= (worker->mTotalPackets - 1)) - { - static LLCachedControl log_to_viewer_log(gSavedSettings,"LogTextureDownloadsToViewerLog"); - static LLCachedControl log_to_sim(gSavedSettings,"LogTextureDownloadsToSimulator"); - - if (log_to_viewer_log || log_to_sim) - { - U64 timeNow = LLTimer::getTotalTime(); - mTextureInfo.setRequestSize(id, worker->mFileSize); - mTextureInfo.setRequestCompleteTimeAndLog(id, timeNow); - } - } - worker->unlockWorkMutex(); - - return res; -} - -////////////////////////////////////////////////////////////////////////////// -BOOL LLTextureFetch::isFromLocalCache(const LLUUID& id) -{ - BOOL from_cache = FALSE ; - - LLTextureFetchWorker* worker = getWorker(id); - if (worker) - { - worker->lockWorkMutex() ; - from_cache = worker->mInLocalCache ; - worker->unlockWorkMutex() ; - } - - return from_cache ; -} - -S32 LLTextureFetch::getFetchState(const LLUUID& id, F32& data_progress_p, F32& requested_priority_p, - U32& fetch_priority_p, F32& fetch_dtime_p, F32& request_dtime_p, bool& can_use_http) -{ - S32 state = LLTextureFetchWorker::INVALID; - F32 data_progress = 0.0f; - F32 requested_priority = 0.0f; - F32 fetch_dtime = 999999.f; - F32 request_dtime = 999999.f; - U32 fetch_priority = 0; - - LLTextureFetchWorker* worker = getWorker(id); - if (worker && worker->haveWork()) - { - worker->lockWorkMutex(); - state = worker->mState; - fetch_dtime = worker->mFetchTimer.getElapsedTimeF32(); - request_dtime = worker->mRequestedTimer.getElapsedTimeF32(); - if (worker->mFileSize > 0) - { - if (state == LLTextureFetchWorker::LOAD_FROM_SIMULATOR) - { - S32 data_size = FIRST_PACKET_SIZE + (worker->mLastPacket-1) * MAX_IMG_PACKET_SIZE; - data_size = llmax(data_size, 0); - data_progress = (F32)data_size / (F32)worker->mFileSize; - } - else if (worker->mFormattedImage.notNull()) - { - data_progress = (F32)worker->mFormattedImage->getDataSize() / (F32)worker->mFileSize; - } - } - if (state >= LLTextureFetchWorker::LOAD_FROM_NETWORK && state <= LLTextureFetchWorker::WAIT_HTTP_REQ) - { - requested_priority = worker->mRequestedPriority; - } - else - { - requested_priority = worker->mImagePriority; - } - fetch_priority = worker->getPriority(); - can_use_http = worker->getCanUseHTTP() ; - worker->unlockWorkMutex(); - } - data_progress_p = data_progress; - requested_priority_p = requested_priority; - fetch_priority_p = fetch_priority; - fetch_dtime_p = fetch_dtime; - request_dtime_p = request_dtime; - return state; -} - -void LLTextureFetch::dump() -{ - llinfos << "LLTextureFetch REQUESTS:" << llendl; - for (request_queue_t::iterator iter = mRequestQueue.begin(); - iter != mRequestQueue.end(); ++iter) - { - LLQueuedThread::QueuedRequest* qreq = *iter; - LLWorkerThread::WorkRequest* wreq = (LLWorkerThread::WorkRequest*)qreq; - LLTextureFetchWorker* worker = (LLTextureFetchWorker*)wreq->getWorkerClass(); - llinfos << " ID: " << worker->mID - << " PRI: " << llformat("0x%08x",wreq->getPriority()) - << " STATE: " << worker->sStateDescs[worker->mState] - << llendl; - } -} - -////////////////////////////////////////////////////////////////////////////// - -// cross-thread command methods - -void LLTextureFetch::commandSetRegion(U64 region_handle) -{ - TFReqSetRegion * req = new TFReqSetRegion(region_handle); - - cmdEnqueue(req); -} - -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); -} - -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; -} - -void LLTextureFetch::cmdEnqueue(TFRequest * req) -{ - lockQueue(); - mCommands.push_back(req); - unlockQueue(); - - unpause(); -} - -LLTextureFetch::TFRequest * LLTextureFetch::cmdDequeue() -{ - TFRequest * ret = 0; - - lockQueue(); - if (! mCommands.empty()) - { - ret = mCommands.front(); - mCommands.erase(mCommands.begin()); - } - unlockQueue(); - - return ret; -} - -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 -{ - -/** - * 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) -{ - /* - * HTTP POST responder. Doesn't do much but tries to - * detect simple breaks in recording the metrics stream. - * - * The 'volatile' modifiers don't indicate signals, - * mmap'd memory or threads, really. They indicate that - * the referenced data is part of a pseudo-closure for - * this responder rather than being required for correct - * operation. - * - * We don't try very hard with the POST request. We give - * it one shot and that's more-or-less it. With a proper - * refactoring of the LLQueuedThread usage, these POSTs - * could be put in a request object and made more reliable. - */ - class lcl_responder : public LLCurl::Responder - { - public: - lcl_responder(LLTextureFetch * fetcher, - S32 expected_sequence, - volatile const S32 & live_sequence, - volatile bool & reporting_break, - volatile bool & reporting_started) - : LLCurl::Responder(), - mFetcher(fetcher), - mExpectedSequence(expected_sequence), - mLiveSequence(live_sequence), - mReportingBreak(reporting_break), - mReportingStarted(reporting_started) - { - mFetcher->incrCurlPOSTCount(); - } - - ~lcl_responder() - { - mFetcher->decrCurlPOSTCount(); - } - - // virtual - void error(U32 status_num, const std::string & reason) - { - if (mLiveSequence == mExpectedSequence) - { - mReportingBreak = true; - } - LL_WARNS("Texture") << "Break in metrics stream due to POST failure to metrics collection service. Reason: " - << reason << LL_ENDL; - } - - // virtual - void result(const LLSD & content) - { - if (mLiveSequence == mExpectedSequence) - { - mReportingBreak = false; - mReportingStarted = true; - } - } - - private: - LLTextureFetch * mFetcher; - S32 mExpectedSequence; - volatile const S32 & mLiveSequence; - volatile bool & mReportingBreak; - volatile bool & mReportingStarted; - - }; // class lcl_responder - - 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; - - // Limit the size of the stats report if necessary. - merged_llsd["truncated"] = truncate_viewer_metrics(10, merged_llsd); - - if (! mCapsURL.empty()) - { - LLCurlRequest::headers_t headers; - fetcher->getCurlRequest().post(mCapsURL, - headers, - merged_llsd, - new lcl_responder(fetcher, - report_sequence, - report_sequence, - LLTextureFetch::svMetricsDataBreak, - reporting_started)); - } - else - { - LLTextureFetch::svMetricsDataBreak = true; - } - - // In QA mode, Metrics submode, log the result for ease of testing - if (fetcher->isQAMode()) - { - LL_INFOS("Textures") << 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 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 - - - +/** + * @file lltexturefetch.cpp + * @brief Object which fetches textures from the cache and/or network + * + * $LicenseInfo:firstyear=2000&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 +#include + +#include "llstl.h" + +#include "lltexturefetch.h" + +#include "llcurl.h" +#include "lldir.h" +#include "llhttpclient.h" +#include "llhttpstatuscodes.h" +#include "llimage.h" +#include "llimagej2c.h" +#include "llimageworker.h" +#include "llworkerthread.h" +#include "message.h" + +#include "llagent.h" +#include "lltexturecache.h" +#include "llviewercontrol.h" +#include "llviewertexturelist.h" +#include "llviewertexture.h" +#include "llviewerregion.h" +#include "llviewerstats.h" +#include "llviewerassetstats.h" +#include "llworld.h" + +////////////////////////////////////////////////////////////////////////////// +class LLTextureFetchWorker : public LLWorkerClass +{ + friend class LLTextureFetch; + friend class HTTPGetResponder; + +private: + class CacheReadResponder : public LLTextureCache::ReadResponder + { + public: + CacheReadResponder(LLTextureFetch* fetcher, const LLUUID& id, LLImageFormatted* image) + : mFetcher(fetcher), mID(id) + { + setImage(image); + } + virtual void completed(bool success) + { + LLTextureFetchWorker* worker = mFetcher->getWorker(mID); + if (worker) + { + worker->callbackCacheRead(success, mFormattedImage, mImageSize, mImageLocal); + } + } + private: + LLTextureFetch* mFetcher; + LLUUID mID; + }; + + class CacheWriteResponder : public LLTextureCache::WriteResponder + { + public: + CacheWriteResponder(LLTextureFetch* fetcher, const LLUUID& id) + : mFetcher(fetcher), mID(id) + { + } + virtual void completed(bool success) + { + LLTextureFetchWorker* worker = mFetcher->getWorker(mID); + if (worker) + { + worker->callbackCacheWrite(success); + } + } + private: + LLTextureFetch* mFetcher; + LLUUID mID; + }; + + class DecodeResponder : public LLImageDecodeThread::Responder + { + public: + DecodeResponder(LLTextureFetch* fetcher, const LLUUID& id, LLTextureFetchWorker* worker) + : mFetcher(fetcher), mID(id), mWorker(worker) + { + } + virtual void completed(bool success, LLImageRaw* raw, LLImageRaw* aux) + { + LLTextureFetchWorker* worker = mFetcher->getWorker(mID); + if (worker) + { + worker->callbackDecoded(success, raw, aux); + } + } + private: + LLTextureFetch* mFetcher; + LLUUID mID; + LLTextureFetchWorker* mWorker; // debug only (may get deleted from under us, use mFetcher/mID) + }; + + struct Compare + { + // lhs < rhs + bool operator()(const LLTextureFetchWorker* lhs, const LLTextureFetchWorker* rhs) const + { + // greater priority is "less" + const F32 lpriority = lhs->mImagePriority; + const F32 rpriority = rhs->mImagePriority; + if (lpriority > rpriority) // higher priority + return true; + else if (lpriority < rpriority) + return false; + else + return lhs < rhs; + } + }; + +public: + /*virtual*/ bool doWork(S32 param); // Called from LLWorkerThread::processRequest() + /*virtual*/ void finishWork(S32 param, bool completed); // called from finishRequest() (WORK THREAD) + /*virtual*/ bool deleteOK(); // called from update() (WORK THREAD) + + ~LLTextureFetchWorker(); + // void relese() { --mActiveCount; } + + S32 callbackHttpGet(const LLChannelDescriptors& channels, + const LLIOPipe::buffer_ptr_t& buffer, + bool partial, bool success); + void callbackCacheRead(bool success, LLImageFormatted* image, + S32 imagesize, BOOL islocal); + void callbackCacheWrite(bool success); + void callbackDecoded(bool success, LLImageRaw* raw, LLImageRaw* aux); + + void setGetStatus(U32 status, const std::string& reason) + { + LLMutexLock lock(&mWorkMutex); + + mGetStatus = status; + mGetReason = reason; + } + + void setCanUseHTTP(bool can_use_http) { mCanUseHTTP = can_use_http; } + bool getCanUseHTTP() const { return mCanUseHTTP; } + + LLTextureFetch & getFetcher() { return *mFetcher; } + +protected: + LLTextureFetchWorker(LLTextureFetch* fetcher, const std::string& url, const LLUUID& id, const LLHost& host, + F32 priority, S32 discard, S32 size); + +private: + /*virtual*/ void startWork(S32 param); // called from addWork() (MAIN THREAD) + /*virtual*/ void endWork(S32 param, bool aborted); // called from doWork() (MAIN THREAD) + + void resetFormattedData(); + + void setImagePriority(F32 priority); + void setDesiredDiscard(S32 discard, S32 size); + bool insertPacket(S32 index, U8* data, S32 size); + void clearPackets(); + void setupPacketData(); + U32 calcWorkPriority(); + void removeFromCache(); + bool processSimulatorPackets(); + bool writeToCacheComplete(); + + void lockWorkMutex() { mWorkMutex.lock(); } + void unlockWorkMutex() { mWorkMutex.unlock(); } + +private: + enum e_state // mState + { + // NOTE: Affects LLTextureBar::draw in lltextureview.cpp (debug hack) + INVALID = 0, + INIT, + LOAD_FROM_TEXTURE_CACHE, + CACHE_POST, + LOAD_FROM_NETWORK, + LOAD_FROM_SIMULATOR, + SEND_HTTP_REQ, + WAIT_HTTP_REQ, + DECODE_IMAGE, + DECODE_IMAGE_UPDATE, + WRITE_TO_CACHE, + WAIT_ON_WRITE, + DONE + }; + enum e_request_state // mSentRequest + { + UNSENT = 0, + QUEUED = 1, + SENT_SIM = 2 + }; + enum e_write_to_cache_state //mWriteToCacheState + { + NOT_WRITE = 0, + CAN_WRITE = 1, + SHOULD_WRITE = 2 + }; + static const char* sStateDescs[]; + e_state mState; + e_write_to_cache_state mWriteToCacheState; + LLTextureFetch* mFetcher; + LLPointer mFormattedImage; + LLPointer mRawImage; + LLPointer mAuxImage; + LLUUID mID; + LLHost mHost; + std::string mUrl; + U8 mType; + F32 mImagePriority; + U32 mWorkPriority; + F32 mRequestedPriority; + S32 mDesiredDiscard; + S32 mSimRequestedDiscard; + S32 mRequestedDiscard; + S32 mLoadedDiscard; + S32 mDecodedDiscard; + LLFrameTimer mRequestedTimer; + LLFrameTimer mFetchTimer; + LLTextureCache::handle_t mCacheReadHandle; + LLTextureCache::handle_t mCacheWriteHandle; + U8* mBuffer; + S32 mBufferSize; + S32 mRequestedSize; + S32 mDesiredSize; + S32 mFileSize; + S32 mCachedSize; + e_request_state mSentRequest; + handle_t mDecodeHandle; + BOOL mLoaded; + BOOL mDecoded; + BOOL mWritten; + BOOL mNeedsAux; + BOOL mHaveAllData; + BOOL mInLocalCache; + bool mCanUseHTTP ; + bool mCanUseNET ; //can get from asset server. + S32 mHTTPFailCount; + S32 mRetryAttempt; + S32 mActiveCount; + U32 mGetStatus; + std::string mGetReason; + + // Work Data + LLMutex mWorkMutex; + struct PacketData + { + PacketData(U8* data, S32 size) { mData = data; mSize = size; } + ~PacketData() { clearData(); } + void clearData() { delete[] mData; mData = NULL; } + U8* mData; + U32 mSize; + }; + std::vector mPackets; + S32 mFirstPacket; + S32 mLastPacket; + U16 mTotalPackets; + U8 mImageCodec; + + LLViewerAssetStats::duration_t mMetricsStartTime; +}; + +////////////////////////////////////////////////////////////////////////////// + +class HTTPGetResponder : public LLCurl::Responder +{ + LOG_CLASS(HTTPGetResponder); +public: + HTTPGetResponder(LLTextureFetch* fetcher, const LLUUID& id, U64 startTime, S32 requestedSize, U32 offset, bool redir) + : mFetcher(fetcher), mID(id), mStartTime(startTime), mRequestedSize(requestedSize), mOffset(offset), mFollowRedir(redir) + { + } + ~HTTPGetResponder() + { + } + + virtual void completedRaw(U32 status, const std::string& reason, + const LLChannelDescriptors& channels, + const LLIOPipe::buffer_ptr_t& buffer) + { + static LLCachedControl log_to_viewer_log(gSavedSettings,"LogTextureDownloadsToViewerLog"); + static LLCachedControl log_to_sim(gSavedSettings,"LogTextureDownloadsToSimulator"); + static LLCachedControl log_texture_traffic(gSavedSettings,"LogTextureNetworkTraffic") ; + + if (log_to_viewer_log || log_to_sim) + { + mFetcher->mTextureInfo.setRequestStartTime(mID, mStartTime); + U64 timeNow = LLTimer::getTotalTime(); + mFetcher->mTextureInfo.setRequestType(mID, LLTextureInfoDetails::REQUEST_TYPE_HTTP); + mFetcher->mTextureInfo.setRequestSize(mID, mRequestedSize); + mFetcher->mTextureInfo.setRequestOffset(mID, mOffset); + mFetcher->mTextureInfo.setRequestCompleteTimeAndLog(mID, timeNow); + } + + lldebugs << "HTTP COMPLETE: " << mID << llendl; + LLTextureFetchWorker* worker = mFetcher->getWorker(mID); + if (worker) + { + bool success = false; + bool partial = false; + if (HTTP_OK <= status && status < HTTP_MULTIPLE_CHOICES) + { + success = true; + if (HTTP_PARTIAL_CONTENT == status) // partial information + { + partial = true; + } + } + + if (!success) + { + worker->setGetStatus(status, reason); +// llwarns << "CURL GET FAILED, status:" << status << " reason:" << reason << llendl; + } + + S32 data_size = worker->callbackHttpGet(channels, buffer, partial, success); + + if(log_texture_traffic && data_size > 0) + { + LLViewerTexture* tex = LLViewerTextureManager::findTexture(mID) ; + if(tex) + { + gTotalTextureBytesPerBoostLevel[tex->getBoostLevel()] += data_size ; + } + } + + mFetcher->removeFromHTTPQueue(mID, data_size); + + if (worker->mMetricsStartTime) + { + LLViewerAssetStatsFF::record_response_thread1(LLViewerAssetType::AT_TEXTURE, + true, + LLImageBase::TYPE_AVATAR_BAKE == worker->mType, + LLViewerAssetStatsFF::get_timestamp() - worker->mMetricsStartTime); + worker->mMetricsStartTime = 0; + } + LLViewerAssetStatsFF::record_dequeue_thread1(LLViewerAssetType::AT_TEXTURE, + true, + LLImageBase::TYPE_AVATAR_BAKE == worker->mType); + } + else + { + mFetcher->removeFromHTTPQueue(mID); + llwarns << "Worker not found: " << mID << llendl; + } + } + + virtual bool followRedir() + { + return mFollowRedir; + } + +private: + LLTextureFetch* mFetcher; + LLUUID mID; + U64 mStartTime; + S32 mRequestedSize; + U32 mOffset; + bool mFollowRedir; +}; + +////////////////////////////////////////////////////////////////////////////// + +// 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 +const char* LLTextureFetchWorker::sStateDescs[] = { + "INVALID", + "INIT", + "LOAD_FROM_TEXTURE_CACHE", + "CACHE_POST", + "LOAD_FROM_NETWORK", + "LOAD_FROM_SIMULATOR", + "SEND_HTTP_REQ", + "WAIT_HTTP_REQ", + "DECODE_IMAGE", + "DECODE_IMAGE_UPDATE", + "WRITE_TO_CACHE", + "WAIT_ON_WRITE", + "DONE", +}; + +// static +volatile bool LLTextureFetch::svMetricsDataBreak(true); // Start with a data break + +// called from MAIN THREAD + +LLTextureFetchWorker::LLTextureFetchWorker(LLTextureFetch* fetcher, + const std::string& url, // Optional URL + const LLUUID& id, // Image UUID + const LLHost& host, // Simulator host + F32 priority, // Priority + S32 discard, // Desired discard + S32 size) // Desired size + : LLWorkerClass(fetcher, "TextureFetch"), + mState(INIT), + mWriteToCacheState(NOT_WRITE), + mFetcher(fetcher), + mID(id), + mHost(host), + mUrl(url), + mImagePriority(priority), + mWorkPriority(0), + mRequestedPriority(0.f), + mDesiredDiscard(-1), + mSimRequestedDiscard(-1), + mRequestedDiscard(-1), + mLoadedDiscard(-1), + mDecodedDiscard(-1), + mCacheReadHandle(LLTextureCache::nullHandle()), + mCacheWriteHandle(LLTextureCache::nullHandle()), + mBuffer(NULL), + mBufferSize(0), + mRequestedSize(0), + mDesiredSize(TEXTURE_CACHE_ENTRY_SIZE), + mFileSize(0), + mCachedSize(0), + mLoaded(FALSE), + mSentRequest(UNSENT), + mDecodeHandle(0), + mDecoded(FALSE), + mWritten(FALSE), + mNeedsAux(FALSE), + mHaveAllData(FALSE), + mInLocalCache(FALSE), + mCanUseHTTP(true), + mHTTPFailCount(0), + mRetryAttempt(0), + mActiveCount(0), + mGetStatus(0), + mWorkMutex(NULL), + mFirstPacket(0), + mLastPacket(-1), + mTotalPackets(0), + mImageCodec(IMG_CODEC_INVALID), + mMetricsStartTime(0) +{ + mCanUseNET = mUrl.empty() ; + + calcWorkPriority(); + mType = host.isOk() ? LLImageBase::TYPE_AVATAR_BAKE : LLImageBase::TYPE_NORMAL; +// llinfos << "Create: " << mID << " mHost:" << host << " Discard=" << discard << llendl; + if (!mFetcher->mDebugPause) + { + U32 work_priority = mWorkPriority | LLWorkerThread::PRIORITY_HIGH; + addWork(0, work_priority ); + } + setDesiredDiscard(discard, size); +} + +LLTextureFetchWorker::~LLTextureFetchWorker() +{ +// llinfos << "Destroy: " << mID +// << " Decoded=" << mDecodedDiscard +// << " Requested=" << mRequestedDiscard +// << " Desired=" << mDesiredDiscard << llendl; + llassert_always(!haveWork()); + lockWorkMutex(); + if (mCacheReadHandle != LLTextureCache::nullHandle() && mFetcher->mTextureCache) + { + mFetcher->mTextureCache->readComplete(mCacheReadHandle, true); + } + if (mCacheWriteHandle != LLTextureCache::nullHandle() && mFetcher->mTextureCache) + { + mFetcher->mTextureCache->writeComplete(mCacheWriteHandle, true); + } + mFormattedImage = NULL; + clearPackets(); + unlockWorkMutex(); + mFetcher->removeFromHTTPQueue(mID); +} + +void LLTextureFetchWorker::clearPackets() +{ + for_each(mPackets.begin(), mPackets.end(), DeletePointer()); + mPackets.clear(); + mTotalPackets = 0; + mLastPacket = -1; + mFirstPacket = 0; +} + +void LLTextureFetchWorker::setupPacketData() +{ + S32 data_size = 0; + if (mFormattedImage.notNull()) + { + data_size = mFormattedImage->getDataSize(); + } + if (data_size > 0) + { + // Only used for simulator requests + mFirstPacket = (data_size - FIRST_PACKET_SIZE) / MAX_IMG_PACKET_SIZE + 1; + if (FIRST_PACKET_SIZE + (mFirstPacket-1) * MAX_IMG_PACKET_SIZE != data_size) + { + llwarns << "Bad CACHED TEXTURE size: " << data_size << " removing." << llendl; + removeFromCache(); + resetFormattedData(); + clearPackets(); + } + else if (mFileSize > 0) + { + mLastPacket = mFirstPacket-1; + mTotalPackets = (mFileSize - FIRST_PACKET_SIZE + MAX_IMG_PACKET_SIZE-1) / MAX_IMG_PACKET_SIZE + 1; + } + else + { + // This file was cached using HTTP so we have to refetch the first packet + resetFormattedData(); + clearPackets(); + } + } +} + +U32 LLTextureFetchWorker::calcWorkPriority() +{ + //llassert_always(mImagePriority >= 0 && mImagePriority <= LLViewerFetchedTexture::maxDecodePriority()); + static const F32 PRIORITY_SCALE = (F32)LLWorkerThread::PRIORITY_LOWBITS / LLViewerFetchedTexture::maxDecodePriority(); + + mWorkPriority = llmin((U32)LLWorkerThread::PRIORITY_LOWBITS, (U32)(mImagePriority * PRIORITY_SCALE)); + return mWorkPriority; +} + +// mWorkMutex is locked +void LLTextureFetchWorker::setDesiredDiscard(S32 discard, S32 size) +{ + bool prioritize = false; + if (mDesiredDiscard != discard) + { + if (!haveWork()) + { + calcWorkPriority(); + if (!mFetcher->mDebugPause) + { + U32 work_priority = mWorkPriority | LLWorkerThread::PRIORITY_HIGH; + addWork(0, work_priority); + } + } + else if (mDesiredDiscard < discard) + { + prioritize = true; + } + mDesiredDiscard = discard; + mDesiredSize = size; + } + else if (size > mDesiredSize) + { + mDesiredSize = size; + prioritize = true; + } + mDesiredSize = llmax(mDesiredSize, TEXTURE_CACHE_ENTRY_SIZE); + if ((prioritize && mState == INIT) || mState == DONE) + { + mState = INIT; + U32 work_priority = mWorkPriority | LLWorkerThread::PRIORITY_HIGH; + setPriority(work_priority); + } +} + +void LLTextureFetchWorker::setImagePriority(F32 priority) +{ +// llassert_always(priority >= 0 && priority <= LLViewerTexture::maxDecodePriority()); + F32 delta = fabs(priority - mImagePriority); + if (delta > (mImagePriority * .05f) || mState == DONE) + { + mImagePriority = priority; + calcWorkPriority(); + U32 work_priority = mWorkPriority | (getPriority() & LLWorkerThread::PRIORITY_HIGHBITS); + setPriority(work_priority); + } +} + +void LLTextureFetchWorker::resetFormattedData() +{ + delete[] mBuffer; + mBuffer = NULL; + mBufferSize = 0; + if (mFormattedImage.notNull()) + { + mFormattedImage->deleteData(); + } + mHaveAllData = FALSE; +} + +// Called from MAIN thread +void LLTextureFetchWorker::startWork(S32 param) +{ + llassert(mFormattedImage.isNull()); +} + +#include "llviewertexturelist.h" // debug + +// Called from LLWorkerThread::processRequest() +bool LLTextureFetchWorker::doWork(S32 param) +{ + LLMutexLock lock(&mWorkMutex); + + if ((mFetcher->isQuitting() || getFlags(LLWorkerClass::WCF_DELETE_REQUESTED))) + { + if (mState < DECODE_IMAGE) + { + return true; // abort + } + } + + if(mImagePriority < F_ALMOST_ZERO) + { + if (mState == INIT || mState == LOAD_FROM_NETWORK || mState == LOAD_FROM_SIMULATOR) + { + return true; // abort + } + } + if(mState > CACHE_POST && !mCanUseNET && !mCanUseHTTP) + { + //nowhere to get data, abort. + return true ; + } + + if (mFetcher->mDebugPause) + { + return false; // debug: don't do any work + } + if (mID == mFetcher->mDebugID) + { + mFetcher->mDebugCount++; // for setting breakpoints + } + + if (mState != DONE) + { + mFetchTimer.reset(); + } + + if (mState == INIT) + { + mRawImage = NULL ; + mRequestedDiscard = -1; + mLoadedDiscard = -1; + mDecodedDiscard = -1; + mRequestedSize = 0; + mFileSize = 0; + mCachedSize = 0; + mLoaded = FALSE; + mSentRequest = UNSENT; + mDecoded = FALSE; + mWritten = FALSE; + delete[] mBuffer; + mBuffer = NULL; + mBufferSize = 0; + mHaveAllData = FALSE; + clearPackets(); // TODO: Shouldn't be necessary + mCacheReadHandle = LLTextureCache::nullHandle(); + mCacheWriteHandle = LLTextureCache::nullHandle(); + mState = LOAD_FROM_TEXTURE_CACHE; + mDesiredSize = llmax(mDesiredSize, TEXTURE_CACHE_ENTRY_SIZE); // min desired size is TEXTURE_CACHE_ENTRY_SIZE + LL_DEBUGS("Texture") << mID << ": Priority: " << llformat("%8.0f",mImagePriority) + << " Desired Discard: " << mDesiredDiscard << " Desired Size: " << mDesiredSize << LL_ENDL; + // fall through + } + + if (mState == LOAD_FROM_TEXTURE_CACHE) + { + if (mCacheReadHandle == LLTextureCache::nullHandle()) + { + U32 cache_priority = mWorkPriority; + S32 offset = mFormattedImage.notNull() ? mFormattedImage->getDataSize() : 0; + S32 size = mDesiredSize - offset; + if (size <= 0) + { + mState = CACHE_POST; + return false; + } + mFileSize = 0; + mLoaded = FALSE; + + if (mUrl.compare(0, 7, "file://") == 0) + { + setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); // Set priority first since Responder may change it + + // read file from local disk + std::string filename = mUrl.substr(7, std::string::npos); + CacheReadResponder* responder = new CacheReadResponder(mFetcher, mID, mFormattedImage); + mCacheReadHandle = mFetcher->mTextureCache->readFromCache(filename, mID, cache_priority, + offset, size, responder); + } + else if (mUrl.empty()) + { + setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); // Set priority first since Responder may change it + + CacheReadResponder* responder = new CacheReadResponder(mFetcher, mID, mFormattedImage); + mCacheReadHandle = mFetcher->mTextureCache->readFromCache(mID, cache_priority, + offset, size, responder); + } + else if(mCanUseHTTP) + { + if (!(mUrl.compare(0, 7, "http://") == 0)) + { + // *TODO:?remove this warning + llwarns << "Unknown URL Type: " << mUrl << llendl; + } + setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority); + mState = SEND_HTTP_REQ; + } + else + { + setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority); + mState = LOAD_FROM_NETWORK; + } + } + + if (mLoaded) + { + // Make sure request is complete. *TODO: make this auto-complete + if (mFetcher->mTextureCache->readComplete(mCacheReadHandle, false)) + { + mCacheReadHandle = LLTextureCache::nullHandle(); + mState = CACHE_POST; + // fall through + } + else + { + return false; + } + } + else + { + return false; + } + } + + if (mState == CACHE_POST) + { + mCachedSize = mFormattedImage.notNull() ? mFormattedImage->getDataSize() : 0; + // Successfully loaded + if ((mCachedSize >= mDesiredSize) || mHaveAllData) + { + // we have enough data, decode it + llassert_always(mFormattedImage->getDataSize() > 0); + mLoadedDiscard = mDesiredDiscard; + mState = DECODE_IMAGE; + mWriteToCacheState = NOT_WRITE ; + LL_DEBUGS("Texture") << mID << ": Cached. Bytes: " << mFormattedImage->getDataSize() + << " Size: " << llformat("%dx%d",mFormattedImage->getWidth(),mFormattedImage->getHeight()) + << " Desired Discard: " << mDesiredDiscard << " Desired Size: " << mDesiredSize << LL_ENDL; + // fall through + } + else + { + if (mUrl.compare(0, 7, "file://") == 0) + { + // failed to load local file, we're done. + return true; + } + // need more data + else + { + LL_DEBUGS("Texture") << mID << ": Not in Cache" << LL_ENDL; + mState = LOAD_FROM_NETWORK; + } + // fall through + } + } + + if (mState == LOAD_FROM_NETWORK) + { + static LLCachedControl use_http(gSavedSettings,"ImagePipelineUseHTTP"); + +// if (mHost != LLHost::invalid) get_url = false; + if ( use_http && mCanUseHTTP && mUrl.empty())//get http url. + { + LLViewerRegion* region = NULL; + if (mHost == LLHost::invalid) + region = gAgent.getRegion(); + else + region = LLWorld::getInstance()->getRegion(mHost); + + if (region) + { + std::string http_url = region->getHttpUrl() ; + if (!http_url.empty()) + { + mUrl = http_url + "/?texture_id=" + mID.asString().c_str(); + mWriteToCacheState = CAN_WRITE ; //because this texture has a fixed texture id. + } + else + { + mCanUseHTTP = false ; + } + } + else + { + // This will happen if not logged in or if a region deoes not have HTTP Texture enabled + //llwarns << "Region not found for host: " << mHost << llendl; + mCanUseHTTP = false; + } + } + if (mCanUseHTTP && !mUrl.empty()) + { + mState = LLTextureFetchWorker::SEND_HTTP_REQ; + setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority); + if(mWriteToCacheState != NOT_WRITE) + { + mWriteToCacheState = CAN_WRITE ; + } + // don't return, fall through to next state + } + else if (mSentRequest == UNSENT && mCanUseNET) + { + // Add this to the network queue and sit here. + // LLTextureFetch::update() will send off a request which will change our state + mWriteToCacheState = CAN_WRITE ; + mRequestedSize = mDesiredSize; + mRequestedDiscard = mDesiredDiscard; + mSentRequest = QUEUED; + mFetcher->addToNetworkQueue(this); + if (! mMetricsStartTime) + { + mMetricsStartTime = LLViewerAssetStatsFF::get_timestamp(); + } + LLViewerAssetStatsFF::record_enqueue_thread1(LLViewerAssetType::AT_TEXTURE, + false, + LLImageBase::TYPE_AVATAR_BAKE == mType); + setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); + + return false; + } + else + { + // Shouldn't need to do anything here + //llassert_always(mFetcher->mNetworkQueue.find(mID) != mFetcher->mNetworkQueue.end()); + // Make certain this is in the network queue + //mFetcher->addToNetworkQueue(this); + //if (! mMetricsStartTime) + //{ + // mMetricsStartTime = LLViewerAssetStatsFF::get_timestamp(); + //} + //LLViewerAssetStatsFF::record_enqueue_thread1(LLViewerAssetType::AT_TEXTURE, false, + // LLImageBase::TYPE_AVATAR_BAKE == mType); + //setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); + return false; + } + } + + if (mState == LOAD_FROM_SIMULATOR) + { + if (mFormattedImage.isNull()) + { + mFormattedImage = new LLImageJ2C; + } + if (processSimulatorPackets()) + { + LL_DEBUGS("Texture") << mID << ": Loaded from Sim. Bytes: " << mFormattedImage->getDataSize() << LL_ENDL; + mFetcher->removeFromNetworkQueue(this, false); + if (mFormattedImage.isNull() || !mFormattedImage->getDataSize()) + { + // processSimulatorPackets() failed +// llwarns << "processSimulatorPackets() failed to load buffer" << llendl; + return true; // failed + } + setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority); + mState = DECODE_IMAGE; + mWriteToCacheState = SHOULD_WRITE; + + if (mMetricsStartTime) + { + LLViewerAssetStatsFF::record_response_thread1(LLViewerAssetType::AT_TEXTURE, + false, + LLImageBase::TYPE_AVATAR_BAKE == mType, + LLViewerAssetStatsFF::get_timestamp() - mMetricsStartTime); + mMetricsStartTime = 0; + } + LLViewerAssetStatsFF::record_dequeue_thread1(LLViewerAssetType::AT_TEXTURE, + false, + LLImageBase::TYPE_AVATAR_BAKE == mType); + } + else + { + mFetcher->addToNetworkQueue(this); // failsafe + if (! mMetricsStartTime) + { + mMetricsStartTime = LLViewerAssetStatsFF::get_timestamp(); + } + LLViewerAssetStatsFF::record_enqueue_thread1(LLViewerAssetType::AT_TEXTURE, + false, + LLImageBase::TYPE_AVATAR_BAKE == mType); + setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); + } + return false; + } + + if (mState == SEND_HTTP_REQ) + { + if(mCanUseHTTP) + { + //NOTE: + //control the number of the http requests issued for: + //1, not openning too many file descriptors at the same time; + //2, control the traffic of http so udp gets bandwidth. + // + static const S32 MAX_NUM_OF_HTTP_REQUESTS_IN_QUEUE = 8 ; + if(mFetcher->getNumHTTPRequests() > MAX_NUM_OF_HTTP_REQUESTS_IN_QUEUE) + { + return false ; //wait. + } + + mFetcher->removeFromNetworkQueue(this, false); + + S32 cur_size = 0; + if (mFormattedImage.notNull()) + { + cur_size = mFormattedImage->getDataSize(); // amount of data we already have + if (mFormattedImage->getDiscardLevel() == 0) + { + if(cur_size > 0) + { + // We already have all the data, just decode it + mLoadedDiscard = mFormattedImage->getDiscardLevel(); + mState = DECODE_IMAGE; + return false; + } + else + { + return true ; //abort. + } + } + } + mRequestedSize = mDesiredSize; + mRequestedDiscard = mDesiredDiscard; + mRequestedSize -= cur_size; + S32 offset = cur_size; + mBufferSize = cur_size; // This will get modified by callbackHttpGet() + + bool res = false; + if (!mUrl.empty()) + { + mLoaded = FALSE; + mGetStatus = 0; + mGetReason.clear(); + LL_DEBUGS("Texture") << "HTTP GET: " << mID << " Offset: " << offset + << " Bytes: " << mRequestedSize + << " Bandwidth(kbps): " << mFetcher->getTextureBandwidth() << "/" << mFetcher->mMaxBandwidth + << LL_ENDL; + setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); + mState = WAIT_HTTP_REQ; + + mFetcher->addToHTTPQueue(mID); + if (! mMetricsStartTime) + { + mMetricsStartTime = LLViewerAssetStatsFF::get_timestamp(); + } + LLViewerAssetStatsFF::record_enqueue_thread1(LLViewerAssetType::AT_TEXTURE, + true, + LLImageBase::TYPE_AVATAR_BAKE == mType); + + // Will call callbackHttpGet when curl request completes + std::vector headers; + headers.push_back("Accept: image/x-j2c"); + res = mFetcher->mCurlGetRequest->getByteRange(mUrl, headers, offset, mRequestedSize, + new HTTPGetResponder(mFetcher, mID, LLTimer::getTotalTime(), mRequestedSize, offset, true)); + } + if (!res) + { + llwarns << "HTTP GET request failed for " << mID << llendl; + resetFormattedData(); + ++mHTTPFailCount; + return true; // failed + } + // fall through + } + else //can not use http fetch. + { + return true ; //abort + } + } + + if (mState == WAIT_HTTP_REQ) + { + if (mLoaded) + { + S32 cur_size = mFormattedImage.notNull() ? mFormattedImage->getDataSize() : 0; + if (mRequestedSize < 0) + { + S32 max_attempts; + if (mGetStatus == HTTP_NOT_FOUND) + { + mHTTPFailCount = max_attempts = 1; // Don't retry + llwarns << "Texture missing from server (404): " << mUrl << llendl; + + //roll back to try UDP + if(mCanUseNET) + { + mState = INIT ; + mCanUseHTTP = false ; + setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority); + return false ; + } + } + else if (mGetStatus == HTTP_SERVICE_UNAVAILABLE) + { + // *TODO: Should probably introduce a timer here to delay future HTTP requsts + // for a short time (~1s) to ease server load? Ideally the server would queue + // requests instead of returning 503... we already limit the number pending. + ++mHTTPFailCount; + max_attempts = mHTTPFailCount+1; // Keep retrying + LL_INFOS_ONCE("Texture") << "Texture server busy (503): " << mUrl << LL_ENDL; + } + else + { + const S32 HTTP_MAX_RETRY_COUNT = 3; + max_attempts = HTTP_MAX_RETRY_COUNT + 1; + ++mHTTPFailCount; + llinfos << "HTTP GET failed for: " << mUrl + << " Status: " << mGetStatus << " Reason: '" << mGetReason << "'" + << " Attempt:" << mHTTPFailCount+1 << "/" << max_attempts << llendl; + } + + if (mHTTPFailCount >= max_attempts) + { + if (cur_size > 0) + { + // Use available data + mLoadedDiscard = mFormattedImage->getDiscardLevel(); + mState = DECODE_IMAGE; + return false; + } + else + { + resetFormattedData(); + mState = DONE; + return true; // failed + } + } + else + { + mState = SEND_HTTP_REQ; + return false; // retry + } + } + + llassert_always(mBufferSize == cur_size + mRequestedSize); + if(!mBufferSize)//no data received. + { + delete[] mBuffer; + mBuffer = NULL; + + //abort. + mState = DONE; + return true; + } + + if (mFormattedImage.isNull()) + { + // For now, create formatted image based on extension + std::string extension = gDirUtilp->getExtension(mUrl); + mFormattedImage = LLImageFormatted::createFromType(LLImageBase::getCodecFromExtension(extension)); + if (mFormattedImage.isNull()) + { + mFormattedImage = new LLImageJ2C; // default + } + } + + if (mHaveAllData && mRequestedDiscard == 0) //the image file is fully loaded. + { + mFileSize = mBufferSize; + } + else //the file size is unknown. + { + mFileSize = mBufferSize + 1 ; //flag the file is not fully loaded. + } + + U8* buffer = new U8[mBufferSize]; + if (cur_size > 0) + { + memcpy(buffer, mFormattedImage->getData(), cur_size); + } + memcpy(buffer + cur_size, mBuffer, mRequestedSize); // append + // NOTE: setData releases current data and owns new data (buffer) + mFormattedImage->setData(buffer, mBufferSize); + // delete temp data + delete[] mBuffer; // Note: not 'buffer' (assigned in setData()) + mBuffer = NULL; + mBufferSize = 0; + mLoadedDiscard = mRequestedDiscard; + mState = DECODE_IMAGE; + if(mWriteToCacheState != NOT_WRITE) + { + mWriteToCacheState = SHOULD_WRITE ; + } + setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority); + return false; + } + else + { + setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); + return false; + } + } + + if (mState == DECODE_IMAGE) + { + static LLCachedControl textures_decode_disabled(gSavedSettings,"TextureDecodeDisabled"); + if(textures_decode_disabled) + { + // for debug use, don't decode + mState = DONE; + setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); + return true; + } + + if (mDesiredDiscard < 0) + { + // We aborted, don't decode + mState = DONE; + setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); + return true; + } + + if (mFormattedImage->getDataSize() <= 0) + { + //llerrs << "Decode entered with invalid mFormattedImage. ID = " << mID << llendl; + + //abort, don't decode + mState = DONE; + setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); + return true; + } + if (mLoadedDiscard < 0) + { + //llerrs << "Decode entered with invalid mLoadedDiscard. ID = " << mID << llendl; + + //abort, don't decode + mState = DONE; + setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); + return true; + } + setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); // Set priority first since Responder may change it + mRawImage = NULL; + mAuxImage = NULL; + llassert_always(mFormattedImage.notNull()); + S32 discard = mHaveAllData ? 0 : mLoadedDiscard; + U32 image_priority = LLWorkerThread::PRIORITY_NORMAL | mWorkPriority; + mDecoded = FALSE; + mState = DECODE_IMAGE_UPDATE; + LL_DEBUGS("Texture") << mID << ": Decoding. Bytes: " << mFormattedImage->getDataSize() << " Discard: " << discard + << " All Data: " << mHaveAllData << LL_ENDL; + mDecodeHandle = mFetcher->mImageDecodeThread->decodeImage(mFormattedImage, image_priority, discard, mNeedsAux, + new DecodeResponder(mFetcher, mID, this)); + // fall though + } + + if (mState == DECODE_IMAGE_UPDATE) + { + if (mDecoded) + { + if (mDecodedDiscard < 0) + { + LL_DEBUGS("Texture") << mID << ": Failed to Decode." << LL_ENDL; + if (mCachedSize > 0 && !mInLocalCache && mRetryAttempt == 0) + { + // Cache file should be deleted, try again +// llwarns << mID << ": Decode of cached file failed (removed), retrying" << llendl; + llassert_always(mDecodeHandle == 0); + mFormattedImage = NULL; + ++mRetryAttempt; + setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority); + mState = INIT; + return false; + } + else + { +// llwarns << "UNABLE TO LOAD TEXTURE: " << mID << " RETRIES: " << mRetryAttempt << llendl; + mState = DONE; // failed + } + } + else + { + llassert_always(mRawImage.notNull()); + LL_DEBUGS("Texture") << mID << ": Decoded. Discard: " << mDecodedDiscard + << " Raw Image: " << llformat("%dx%d",mRawImage->getWidth(),mRawImage->getHeight()) << LL_ENDL; + setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority); + mState = WRITE_TO_CACHE; + } + // fall through + } + else + { + return false; + } + } + + if (mState == WRITE_TO_CACHE) + { + if (mWriteToCacheState != SHOULD_WRITE || mFormattedImage.isNull()) + { + // If we're in a local cache or we didn't actually receive any new data, + // or we failed to load anything, skip + mState = DONE; + return false; + } + S32 datasize = mFormattedImage->getDataSize(); + if(mFileSize < datasize)//This could happen when http fetching and sim fetching mixed. + { + if(mHaveAllData) + { + mFileSize = datasize ; + } + else + { + mFileSize = datasize + 1 ; //flag not fully loaded. + } + } + llassert_always(datasize); + setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); // Set priority first since Responder may change it + U32 cache_priority = mWorkPriority; + mWritten = FALSE; + mState = WAIT_ON_WRITE; + CacheWriteResponder* responder = new CacheWriteResponder(mFetcher, mID); + mCacheWriteHandle = mFetcher->mTextureCache->writeToCache(mID, cache_priority, + mFormattedImage->getData(), datasize, + mFileSize, responder); + // fall through + } + + if (mState == WAIT_ON_WRITE) + { + if (writeToCacheComplete()) + { + mState = DONE; + // fall through + } + else + { + if (mDesiredDiscard < mDecodedDiscard) + { + // We're waiting for this write to complete before we can receive more data + // (we can't touch mFormattedImage until the write completes) + // Prioritize the write + mFetcher->mTextureCache->prioritizeWrite(mCacheWriteHandle); + } + return false; + } + } + + if (mState == DONE) + { + if (mDecodedDiscard >= 0 && mDesiredDiscard < mDecodedDiscard) + { + // More data was requested, return to INIT + mState = INIT; + setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority); + return false; + } + else + { + setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); + return true; + } + } + + return false; +} + +// Called from MAIN thread +void LLTextureFetchWorker::endWork(S32 param, bool aborted) +{ + if (mDecodeHandle != 0) + { + mFetcher->mImageDecodeThread->abortRequest(mDecodeHandle, false); + mDecodeHandle = 0; + } + mFormattedImage = NULL; +} + +////////////////////////////////////////////////////////////////////////////// + +// virtual +void LLTextureFetchWorker::finishWork(S32 param, bool completed) +{ + // The following are required in case the work was aborted + if (mCacheReadHandle != LLTextureCache::nullHandle()) + { + mFetcher->mTextureCache->readComplete(mCacheReadHandle, true); + mCacheReadHandle = LLTextureCache::nullHandle(); + } + if (mCacheWriteHandle != LLTextureCache::nullHandle()) + { + mFetcher->mTextureCache->writeComplete(mCacheWriteHandle, true); + mCacheWriteHandle = LLTextureCache::nullHandle(); + } +} + +// virtual +bool LLTextureFetchWorker::deleteOK() +{ + bool delete_ok = true; + // Allow any pending reads or writes to complete + if (mCacheReadHandle != LLTextureCache::nullHandle()) + { + if (mFetcher->mTextureCache->readComplete(mCacheReadHandle, true)) + { + mCacheReadHandle = LLTextureCache::nullHandle(); + } + else + { + delete_ok = false; + } + } + if (mCacheWriteHandle != LLTextureCache::nullHandle()) + { + if (mFetcher->mTextureCache->writeComplete(mCacheWriteHandle)) + { + mCacheWriteHandle = LLTextureCache::nullHandle(); + } + else + { + delete_ok = false; + } + } + + if ((haveWork() && + // not ok to delete from these states + ((mState >= WRITE_TO_CACHE && mState <= WAIT_ON_WRITE)))) + { + delete_ok = false; + } + + return delete_ok; +} + +void LLTextureFetchWorker::removeFromCache() +{ + if (!mInLocalCache) + { + mFetcher->mTextureCache->removeFromCache(mID); + } +} + + +////////////////////////////////////////////////////////////////////////////// + +bool LLTextureFetchWorker::processSimulatorPackets() +{ + if (mFormattedImage.isNull() || mRequestedSize < 0) + { + // not sure how we got here, but not a valid state, abort! + llassert_always(mDecodeHandle == 0); + mFormattedImage = NULL; + return true; + } + + if (mLastPacket >= mFirstPacket) + { + S32 buffer_size = mFormattedImage->getDataSize(); + for (S32 i = mFirstPacket; i<=mLastPacket; i++) + { + llassert_always(mPackets[i]); + buffer_size += mPackets[i]->mSize; + } + bool have_all_data = mLastPacket >= mTotalPackets-1; + if (mRequestedSize <= 0) + { + // We received a packed but haven't requested anything yet (edge case) + // Return true (we're "done") since we didn't request anything + return true; + } + if (buffer_size >= mRequestedSize || have_all_data) + { + /// We have enough (or all) data + if (have_all_data) + { + mHaveAllData = TRUE; + } + S32 cur_size = mFormattedImage->getDataSize(); + if (buffer_size > cur_size) + { + /// We have new data + U8* buffer = new U8[buffer_size]; + S32 offset = 0; + if (cur_size > 0 && mFirstPacket > 0) + { + memcpy(buffer, mFormattedImage->getData(), cur_size); + offset = cur_size; + } + for (S32 i=mFirstPacket; i<=mLastPacket; i++) + { + memcpy(buffer + offset, mPackets[i]->mData, mPackets[i]->mSize); + offset += mPackets[i]->mSize; + } + // NOTE: setData releases current data + mFormattedImage->setData(buffer, buffer_size); + } + mLoadedDiscard = mRequestedDiscard; + return true; + } + } + return false; +} + +////////////////////////////////////////////////////////////////////////////// + +S32 LLTextureFetchWorker::callbackHttpGet(const LLChannelDescriptors& channels, + const LLIOPipe::buffer_ptr_t& buffer, + bool partial, bool success) +{ + S32 data_size = 0 ; + + LLMutexLock lock(&mWorkMutex); + + if (mState != WAIT_HTTP_REQ) + { + llwarns << "callbackHttpGet for unrequested fetch worker: " << mID + << " req=" << mSentRequest << " state= " << mState << llendl; + return data_size; + } + if (mLoaded) + { + llwarns << "Duplicate callback for " << mID.asString() << llendl; + return data_size ; // ignore duplicate callback + } + if (success) + { + // get length of stream: + data_size = buffer->countAfter(channels.in(), NULL); + + LL_DEBUGS("Texture") << "HTTP RECEIVED: " << mID.asString() << " Bytes: " << data_size << LL_ENDL; + if (data_size > 0) + { + // *TODO: set the formatted image data here directly to avoid the copy + mBuffer = new U8[data_size]; + buffer->readAfter(channels.in(), NULL, mBuffer, data_size); + mBufferSize += data_size; + if (data_size < mRequestedSize && mRequestedDiscard == 0) + { + mHaveAllData = TRUE; + } + else if (data_size > mRequestedSize) + { + // *TODO: This shouldn't be happening any more + llwarns << "data_size = " << data_size << " > requested: " << mRequestedSize << llendl; + mHaveAllData = TRUE; + llassert_always(mDecodeHandle == 0); + mFormattedImage = NULL; // discard any previous data we had + mBufferSize = data_size; + } + } + else + { + // We requested data but received none (and no error), + // so presumably we have all of it + mHaveAllData = TRUE; + } + mRequestedSize = data_size; + } + else + { + mRequestedSize = -1; // error + } + mLoaded = TRUE; + setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority); + + return data_size ; +} + +////////////////////////////////////////////////////////////////////////////// + +void LLTextureFetchWorker::callbackCacheRead(bool success, LLImageFormatted* image, + S32 imagesize, BOOL islocal) +{ + LLMutexLock lock(&mWorkMutex); + if (mState != LOAD_FROM_TEXTURE_CACHE) + { +// llwarns << "Read callback for " << mID << " with state = " << mState << llendl; + return; + } + if (success) + { + llassert_always(imagesize >= 0); + mFileSize = imagesize; + mFormattedImage = image; + mImageCodec = image->getCodec(); + mInLocalCache = islocal; + if (mFileSize != 0 && mFormattedImage->getDataSize() >= mFileSize) + { + mHaveAllData = TRUE; + } + } + mLoaded = TRUE; + setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority); +} + +void LLTextureFetchWorker::callbackCacheWrite(bool success) +{ + LLMutexLock lock(&mWorkMutex); + if (mState != WAIT_ON_WRITE) + { +// llwarns << "Write callback for " << mID << " with state = " << mState << llendl; + return; + } + mWritten = TRUE; + setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority); +} + +////////////////////////////////////////////////////////////////////////////// + +void LLTextureFetchWorker::callbackDecoded(bool success, LLImageRaw* raw, LLImageRaw* aux) +{ + LLMutexLock lock(&mWorkMutex); + if (mDecodeHandle == 0) + { + return; // aborted, ignore + } + if (mState != DECODE_IMAGE_UPDATE) + { +// llwarns << "Decode callback for " << mID << " with state = " << mState << llendl; + mDecodeHandle = 0; + return; + } + llassert_always(mFormattedImage.notNull()); + + mDecodeHandle = 0; + if (success) + { + llassert_always(raw); + mRawImage = raw; + mAuxImage = aux; + mDecodedDiscard = mFormattedImage->getDiscardLevel(); + LL_DEBUGS("Texture") << mID << ": Decode Finished. Discard: " << mDecodedDiscard + << " Raw Image: " << llformat("%dx%d",mRawImage->getWidth(),mRawImage->getHeight()) << LL_ENDL; + } + else + { + llwarns << "DECODE FAILED: " << mID << " Discard: " << (S32)mFormattedImage->getDiscardLevel() << llendl; + removeFromCache(); + mDecodedDiscard = -1; // Redundant, here for clarity and paranoia + } + mDecoded = TRUE; +// llinfos << mID << " : DECODE COMPLETE " << llendl; + setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority); +} + +////////////////////////////////////////////////////////////////////////////// + +bool LLTextureFetchWorker::writeToCacheComplete() +{ + // Complete write to cache + if (mCacheWriteHandle != LLTextureCache::nullHandle()) + { + if (!mWritten) + { + return false; + } + if (mFetcher->mTextureCache->writeComplete(mCacheWriteHandle)) + { + mCacheWriteHandle = LLTextureCache::nullHandle(); + } + else + { + return false; + } + } + return true; +} + + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// +// public + +LLTextureFetch::LLTextureFetch(LLTextureCache* cache, LLImageDecodeThread* imagedecodethread, bool threaded, bool qa_mode) + : LLWorkerThread("TextureFetch", threaded), + mDebugCount(0), + mDebugPause(FALSE), + mPacketCount(0), + mBadPacketCount(0), + mQueueMutex(getAPRPool()), + mNetworkQueueMutex(getAPRPool()), + mTextureCache(cache), + mImageDecodeThread(imagedecodethread), + mTextureBandwidth(0), + mHTTPTextureBits(0), + mTotalHTTPRequests(0), + mCurlGetRequest(NULL), + mQAMode(qa_mode) +{ + mCurlPOSTRequestCount = 0; + mMaxBandwidth = gSavedSettings.getF32("ThrottleBandwidthKBPS"); + mTextureInfo.setUpLogging(gSavedSettings.getBOOL("LogTextureDownloadsToViewerLog"), gSavedSettings.getBOOL("LogTextureDownloadsToSimulator"), gSavedSettings.getU32("TextureLoggingThreshold")); +} + +LLTextureFetch::~LLTextureFetch() +{ + clearDeleteList() ; + + while (! mCommands.empty()) + { + TFRequest * req(mCommands.front()); + mCommands.erase(mCommands.begin()); + delete req; + } + + // ~LLQueuedThread() called here +} + +bool LLTextureFetch::createRequest(const std::string& url, const LLUUID& id, const LLHost& host, F32 priority, + S32 w, S32 h, S32 c, S32 desired_discard, bool needs_aux, bool can_use_http) +{ + if (mDebugPause) + { + return false; + } + + LLTextureFetchWorker* worker = getWorker(id) ; + if (worker) + { + if (worker->mHost != host) + { + llwarns << "LLTextureFetch::createRequest " << id << " called with multiple hosts: " + << host << " != " << worker->mHost << llendl; + removeRequest(worker, true); + worker = NULL; + return false; + } + } + + S32 desired_size; + std::string exten = gDirUtilp->getExtension(url); + if (!url.empty() && (!exten.empty() && LLImageBase::getCodecFromExtension(exten) != IMG_CODEC_J2C)) + { + // Only do partial requests for J2C at the moment + desired_size = MAX_IMAGE_DATA_SIZE; + desired_discard = 0; + } + else if (desired_discard == 0) + { + // if we want the entire image, and we know its size, then get it all + // (calcDataSizeJ2C() below makes assumptions about how the image + // was compressed - this code ensures that when we request the entire image, + // we really do get it.) + desired_size = MAX_IMAGE_DATA_SIZE; + } + else if (w*h*c > 0) + { + // If the requester knows the dimensions of the image, + // this will calculate how much data we need without having to parse the header + + desired_size = LLImageJ2C::calcDataSizeJ2C(w, h, c, desired_discard); + } + else + { + desired_size = TEXTURE_CACHE_ENTRY_SIZE; + desired_discard = MAX_DISCARD_LEVEL; + } + + + if (worker) + { + if (worker->wasAborted()) + { + return false; // need to wait for previous aborted request to complete + } + worker->lockWorkMutex(); + worker->mActiveCount++; + worker->mNeedsAux = needs_aux; + worker->setImagePriority(priority); + worker->setDesiredDiscard(desired_discard, desired_size); + worker->setCanUseHTTP(can_use_http) ; + if (!worker->haveWork()) + { + worker->mState = LLTextureFetchWorker::INIT; + worker->unlockWorkMutex(); + + worker->addWork(0, LLWorkerThread::PRIORITY_HIGH | worker->mWorkPriority); + } + else + { + worker->unlockWorkMutex(); + } + } + else + { + worker = new LLTextureFetchWorker(this, url, id, host, priority, desired_discard, desired_size); + lockQueue() ; + mRequestMap[id] = worker; + unlockQueue() ; + + worker->lockWorkMutex(); + worker->mActiveCount++; + worker->mNeedsAux = needs_aux; + worker->setCanUseHTTP(can_use_http) ; + worker->unlockWorkMutex(); + } + +// llinfos << "REQUESTED: " << id << " Discard: " << desired_discard << llendl; + return true; +} + +// protected +void LLTextureFetch::addToNetworkQueue(LLTextureFetchWorker* worker) +{ + lockQueue() ; + bool in_request_map = (mRequestMap.find(worker->mID) != mRequestMap.end()) ; + unlockQueue() ; + + LLMutexLock lock(&mNetworkQueueMutex); + if (in_request_map) + { + // only add to the queue if in the request map + // i.e. a delete has not been requested + mNetworkQueue.insert(worker->mID); + } + for (cancel_queue_t::iterator iter1 = mCancelQueue.begin(); + iter1 != mCancelQueue.end(); ++iter1) + { + iter1->second.erase(worker->mID); + } +} + +void LLTextureFetch::removeFromNetworkQueue(LLTextureFetchWorker* worker, bool cancel) +{ + LLMutexLock lock(&mNetworkQueueMutex); + size_t erased = mNetworkQueue.erase(worker->mID); + if (cancel && erased > 0) + { + mCancelQueue[worker->mHost].insert(worker->mID); + } +} + +// protected +void LLTextureFetch::addToHTTPQueue(const LLUUID& id) +{ + LLMutexLock lock(&mNetworkQueueMutex); + mHTTPTextureQueue.insert(id); + mTotalHTTPRequests++; +} + +void LLTextureFetch::removeFromHTTPQueue(const LLUUID& id, S32 received_size) +{ + LLMutexLock lock(&mNetworkQueueMutex); + mHTTPTextureQueue.erase(id); + mHTTPTextureBits += received_size * 8; // Approximate - does not include header bits +} + +void LLTextureFetch::deleteRequest(const LLUUID& id, bool cancel) +{ + lockQueue() ; + LLTextureFetchWorker* worker = getWorkerAfterLock(id); + if (worker) + { + size_t erased_1 = mRequestMap.erase(worker->mID); + unlockQueue() ; + + llassert_always(erased_1 > 0) ; + + removeFromNetworkQueue(worker, cancel); + llassert_always(!(worker->getFlags(LLWorkerClass::WCF_DELETE_REQUESTED))) ; + + worker->scheduleDelete(); + } + else + { + unlockQueue() ; + } +} + +void LLTextureFetch::removeRequest(LLTextureFetchWorker* worker, bool cancel) +{ + lockQueue() ; + size_t erased_1 = mRequestMap.erase(worker->mID); + unlockQueue() ; + + llassert_always(erased_1 > 0) ; + removeFromNetworkQueue(worker, cancel); + llassert_always(!(worker->getFlags(LLWorkerClass::WCF_DELETE_REQUESTED))) ; + + worker->scheduleDelete(); +} + +S32 LLTextureFetch::getNumRequests() +{ + lockQueue() ; + S32 size = (S32)mRequestMap.size(); + unlockQueue() ; + + return size ; +} + +S32 LLTextureFetch::getNumHTTPRequests() +{ + mNetworkQueueMutex.lock() ; + S32 size = (S32)mHTTPTextureQueue.size(); + mNetworkQueueMutex.unlock() ; + + return size ; +} + +U32 LLTextureFetch::getTotalNumHTTPRequests() +{ + mNetworkQueueMutex.lock() ; + U32 size = mTotalHTTPRequests ; + mNetworkQueueMutex.unlock() ; + + return size ; +} + +// call lockQueue() first! +LLTextureFetchWorker* LLTextureFetch::getWorkerAfterLock(const LLUUID& id) +{ + LLTextureFetchWorker* res = NULL; + map_t::iterator iter = mRequestMap.find(id); + if (iter != mRequestMap.end()) + { + res = iter->second; + } + return res; +} + +LLTextureFetchWorker* LLTextureFetch::getWorker(const LLUUID& id) +{ + LLMutexLock lock(&mQueueMutex) ; + + return getWorkerAfterLock(id) ; +} + + +bool LLTextureFetch::getRequestFinished(const LLUUID& id, S32& discard_level, + LLPointer& raw, LLPointer& aux) +{ + bool res = false; + LLTextureFetchWorker* worker = getWorker(id); + if (worker) + { + if (worker->wasAborted()) + { + res = true; + } + else if (!worker->haveWork()) + { + // Should only happen if we set mDebugPause... + if (!mDebugPause) + { +// llwarns << "Adding work for inactive worker: " << id << llendl; + worker->addWork(0, LLWorkerThread::PRIORITY_HIGH | worker->mWorkPriority); + } + } + else if (worker->checkWork()) + { + worker->lockWorkMutex(); + discard_level = worker->mDecodedDiscard; + raw = worker->mRawImage; + aux = worker->mAuxImage; + res = true; + LL_DEBUGS("Texture") << id << ": Request Finished. State: " << worker->mState << " Discard: " << discard_level << LL_ENDL; + worker->unlockWorkMutex(); + } + else + { + worker->lockWorkMutex(); + if ((worker->mDecodedDiscard >= 0) && + (worker->mDecodedDiscard < discard_level || discard_level < 0) && + (worker->mState >= LLTextureFetchWorker::WAIT_ON_WRITE)) + { + // Not finished, but data is ready + discard_level = worker->mDecodedDiscard; + raw = worker->mRawImage; + aux = worker->mAuxImage; + } + worker->unlockWorkMutex(); + } + } + else + { + res = true; + } + return res; +} + +bool LLTextureFetch::updateRequestPriority(const LLUUID& id, F32 priority) +{ + bool res = false; + LLTextureFetchWorker* worker = getWorker(id); + if (worker) + { + worker->lockWorkMutex(); + worker->setImagePriority(priority); + worker->unlockWorkMutex(); + res = true; + } + return res; +} + +// Replicates and expands upon the base class's +// getPending() implementation. getPending() and +// runCondition() replicate one another's logic to +// an extent and are sometimes used for the same +// function (deciding whether or not to sleep/pause +// a thread). So the implementations need to stay +// in step, at least until this can be refactored and +// the redundancy eliminated. +// +// May be called from any thread + +//virtual +S32 LLTextureFetch::getPending() +{ + S32 res; + lockData(); + { + LLMutexLock lock(&mQueueMutex); + + res = mRequestQueue.size(); + res += mCurlPOSTRequestCount; + res += mCommands.size(); + } + unlockData(); + return res; +} + +// virtual +bool LLTextureFetch::runCondition() +{ + // Caller is holding the lock on LLThread's condition variable. + + // LLQueuedThread, unlike its base class LLThread, makes this a + // private method which is unfortunate. I want to use it directly + // but I'm going to have to re-implement the logic here (or change + // declarations, which I don't want to do right now). + // + // Changes here may need to be reflected in getPending(). + + bool have_no_commands(false); + { + LLMutexLock lock(&mQueueMutex); + + have_no_commands = mCommands.empty(); + } + + bool have_no_curl_requests(0 == mCurlPOSTRequestCount); + + return ! (have_no_commands + && have_no_curl_requests + && (mRequestQueue.empty() && mIdleThread)); // From base class +} + +////////////////////////////////////////////////////////////////////////////// + +// MAIN THREAD (unthreaded envs), WORKER THREAD (threaded envs) +void LLTextureFetch::commonUpdate() +{ + // Run a cross-thread command, if any. + cmdDoWork(); + + // Update Curl on same thread as mCurlGetRequest was constructed + S32 processed = mCurlGetRequest->process(); + if (processed > 0) + { + lldebugs << "processed: " << processed << " messages." << llendl; + } +} + + +// MAIN THREAD +//virtual +S32 LLTextureFetch::update(U32 max_time_ms) +{ + static LLCachedControl band_width(gSavedSettings,"ThrottleBandwidthKBPS"); + + { + mNetworkQueueMutex.lock() ; + mMaxBandwidth = band_width ; + + gTextureList.sTextureBits += mHTTPTextureBits ; + mHTTPTextureBits = 0 ; + + mNetworkQueueMutex.unlock() ; + } + + S32 res = LLWorkerThread::update(max_time_ms); + + if (!mDebugPause) + { + sendRequestListToSimulators(); + } + + if (!mThreaded) + { + commonUpdate(); + } + + return res; +} + +//called in the MAIN thread after the TextureCacheThread shuts down. +void LLTextureFetch::shutDownTextureCacheThread() +{ + if(mTextureCache) + { + llassert_always(mTextureCache->isQuitting() || mTextureCache->isStopped()) ; + mTextureCache = NULL ; + } +} + +//called in the MAIN thread after the ImageDecodeThread shuts down. +void LLTextureFetch::shutDownImageDecodeThread() +{ + if(mImageDecodeThread) + { + llassert_always(mImageDecodeThread->isQuitting() || mImageDecodeThread->isStopped()) ; + mImageDecodeThread = NULL ; + } +} + +// WORKER THREAD +void LLTextureFetch::startThread() +{ + // Construct mCurlGetRequest from Worker Thread + mCurlGetRequest = new LLCurlRequest(); +} + +// WORKER THREAD +void LLTextureFetch::endThread() +{ + // Destroy mCurlGetRequest from Worker Thread + delete mCurlGetRequest; + mCurlGetRequest = NULL; +} + +// WORKER THREAD +void LLTextureFetch::threadedUpdate() +{ + llassert_always(mCurlGetRequest); + + // Limit update frequency + const F32 PROCESS_TIME = 0.05f; + static LLFrameTimer process_timer; + if (process_timer.getElapsedTimeF32() < PROCESS_TIME) + { + return; + } + process_timer.reset(); + + commonUpdate(); + +#if 0 + const F32 INFO_TIME = 1.0f; + static LLFrameTimer info_timer; + if (info_timer.getElapsedTimeF32() >= INFO_TIME) + { + S32 q = mCurlGetRequest->getQueued(); + if (q > 0) + { + llinfos << "Queued gets: " << q << llendl; + info_timer.reset(); + } + } +#endif + +} + +////////////////////////////////////////////////////////////////////////////// + +void LLTextureFetch::sendRequestListToSimulators() +{ + // All requests + const F32 REQUEST_DELTA_TIME = 0.10f; // 10 fps + + // Sim requests + const S32 IMAGES_PER_REQUEST = 50; + const F32 SIM_LAZY_FLUSH_TIMEOUT = 10.0f; // temp + const F32 MIN_REQUEST_TIME = 1.0f; + const F32 MIN_DELTA_PRIORITY = 1000.f; + + // Periodically, gather the list of textures that need data from the network + // And send the requests out to the simulators + static LLFrameTimer timer; + if (timer.getElapsedTimeF32() < REQUEST_DELTA_TIME) + { + return; + } + timer.reset(); + + // Send requests + typedef std::set request_list_t; + typedef std::map< LLHost, request_list_t > work_request_map_t; + work_request_map_t requests; + { + LLMutexLock lock2(&mNetworkQueueMutex); + for (queue_t::iterator iter = mNetworkQueue.begin(); iter != mNetworkQueue.end(); ) + { + queue_t::iterator curiter = iter++; + LLTextureFetchWorker* req = getWorker(*curiter); + if (!req) + { + mNetworkQueue.erase(curiter); + continue; // paranoia + } + if ((req->mState != LLTextureFetchWorker::LOAD_FROM_NETWORK) && + (req->mState != LLTextureFetchWorker::LOAD_FROM_SIMULATOR)) + { + // We already received our URL, remove from the queue + llwarns << "Worker: " << req->mID << " in mNetworkQueue but in wrong state: " << req->mState << llendl; + mNetworkQueue.erase(curiter); + continue; + } + if (req->mID == mDebugID) + { + mDebugCount++; // for setting breakpoints + } + if (req->mSentRequest == LLTextureFetchWorker::SENT_SIM && + req->mTotalPackets > 0 && + req->mLastPacket >= req->mTotalPackets-1) + { + // We have all the packets... make sure this is high priority +// req->setPriority(LLWorkerThread::PRIORITY_HIGH | req->mWorkPriority); + continue; + } + F32 elapsed = req->mRequestedTimer.getElapsedTimeF32(); + { + F32 delta_priority = llabs(req->mRequestedPriority - req->mImagePriority); + if ((req->mSimRequestedDiscard != req->mDesiredDiscard) || + (delta_priority > MIN_DELTA_PRIORITY && elapsed >= MIN_REQUEST_TIME) || + (elapsed >= SIM_LAZY_FLUSH_TIMEOUT)) + { + requests[req->mHost].insert(req); + } + } + } + } + + for (work_request_map_t::iterator iter1 = requests.begin(); + iter1 != requests.end(); ++iter1) + { + LLHost host = iter1->first; + // invalid host = use agent host + if (host == LLHost::invalid) + { + host = gAgent.getRegionHost(); + } + + S32 sim_request_count = 0; + + for (request_list_t::iterator iter2 = iter1->second.begin(); + iter2 != iter1->second.end(); ++iter2) + { + LLTextureFetchWorker* req = *iter2; + if (gMessageSystem) + { + if (req->mSentRequest != LLTextureFetchWorker::SENT_SIM) + { + // Initialize packet data based on data read from cache + req->lockWorkMutex(); + req->setupPacketData(); + req->unlockWorkMutex(); + } + if (0 == sim_request_count) + { + gMessageSystem->newMessageFast(_PREHASH_RequestImage); + gMessageSystem->nextBlockFast(_PREHASH_AgentData); + gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + } + S32 packet = req->mLastPacket + 1; + gMessageSystem->nextBlockFast(_PREHASH_RequestImage); + gMessageSystem->addUUIDFast(_PREHASH_Image, req->mID); + gMessageSystem->addS8Fast(_PREHASH_DiscardLevel, (S8)req->mDesiredDiscard); + gMessageSystem->addF32Fast(_PREHASH_DownloadPriority, req->mImagePriority); + gMessageSystem->addU32Fast(_PREHASH_Packet, packet); + gMessageSystem->addU8Fast(_PREHASH_Type, req->mType); +// llinfos << "IMAGE REQUEST: " << req->mID << " Discard: " << req->mDesiredDiscard +// << " Packet: " << packet << " Priority: " << req->mImagePriority << llendl; + + static LLCachedControl log_to_viewer_log(gSavedSettings,"LogTextureDownloadsToViewerLog"); + static LLCachedControl log_to_sim(gSavedSettings,"LogTextureDownloadsToSimulator"); + if (log_to_viewer_log || log_to_sim) + { + mTextureInfo.setRequestStartTime(req->mID, LLTimer::getTotalTime()); + mTextureInfo.setRequestOffset(req->mID, 0); + mTextureInfo.setRequestSize(req->mID, 0); + mTextureInfo.setRequestType(req->mID, LLTextureInfoDetails::REQUEST_TYPE_UDP); + } + + req->lockWorkMutex(); + req->mSentRequest = LLTextureFetchWorker::SENT_SIM; + req->mSimRequestedDiscard = req->mDesiredDiscard; + req->mRequestedPriority = req->mImagePriority; + req->mRequestedTimer.reset(); + req->unlockWorkMutex(); + sim_request_count++; + if (sim_request_count >= IMAGES_PER_REQUEST) + { +// llinfos << "REQUESTING " << sim_request_count << " IMAGES FROM HOST: " << host.getIPString() << llendl; + + gMessageSystem->sendSemiReliable(host, NULL, NULL); + sim_request_count = 0; + } + } + } + if (gMessageSystem && sim_request_count > 0 && sim_request_count < IMAGES_PER_REQUEST) + { +// llinfos << "REQUESTING " << sim_request_count << " IMAGES FROM HOST: " << host.getIPString() << llendl; + gMessageSystem->sendSemiReliable(host, NULL, NULL); + sim_request_count = 0; + } + } + + // Send cancelations + { + LLMutexLock lock2(&mNetworkQueueMutex); + if (gMessageSystem && !mCancelQueue.empty()) + { + for (cancel_queue_t::iterator iter1 = mCancelQueue.begin(); + iter1 != mCancelQueue.end(); ++iter1) + { + LLHost host = iter1->first; + if (host == LLHost::invalid) + { + host = gAgent.getRegionHost(); + } + S32 request_count = 0; + for (queue_t::iterator iter2 = iter1->second.begin(); + iter2 != iter1->second.end(); ++iter2) + { + if (0 == request_count) + { + gMessageSystem->newMessageFast(_PREHASH_RequestImage); + gMessageSystem->nextBlockFast(_PREHASH_AgentData); + gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + } + gMessageSystem->nextBlockFast(_PREHASH_RequestImage); + gMessageSystem->addUUIDFast(_PREHASH_Image, *iter2); + gMessageSystem->addS8Fast(_PREHASH_DiscardLevel, -1); + gMessageSystem->addF32Fast(_PREHASH_DownloadPriority, 0); + gMessageSystem->addU32Fast(_PREHASH_Packet, 0); + gMessageSystem->addU8Fast(_PREHASH_Type, 0); +// llinfos << "CANCELING IMAGE REQUEST: " << (*iter2) << llendl; + + request_count++; + if (request_count >= IMAGES_PER_REQUEST) + { + gMessageSystem->sendSemiReliable(host, NULL, NULL); + request_count = 0; + } + } + if (request_count > 0 && request_count < IMAGES_PER_REQUEST) + { + gMessageSystem->sendSemiReliable(host, NULL, NULL); + } + } + mCancelQueue.clear(); + } + } +} + +////////////////////////////////////////////////////////////////////////////// + +bool LLTextureFetchWorker::insertPacket(S32 index, U8* data, S32 size) +{ + mRequestedTimer.reset(); + if (index >= mTotalPackets) + { +// llwarns << "Received Image Packet " << index << " > max: " << mTotalPackets << " for image: " << mID << llendl; + return false; + } + if (index > 0 && index < mTotalPackets-1 && size != MAX_IMG_PACKET_SIZE) + { +// llwarns << "Received bad sized packet: " << index << ", " << size << " != " << MAX_IMG_PACKET_SIZE << " for image: " << mID << llendl; + return false; + } + + if (index >= (S32)mPackets.size()) + { + mPackets.resize(index+1, (PacketData*)NULL); // initializes v to NULL pointers + } + else if (mPackets[index] != NULL) + { +// llwarns << "Received duplicate packet: " << index << " for image: " << mID << llendl; + return false; + } + + mPackets[index] = new PacketData(data, size); + while (mLastPacket+1 < (S32)mPackets.size() && mPackets[mLastPacket+1] != NULL) + { + ++mLastPacket; + } + return true; +} + +bool LLTextureFetch::receiveImageHeader(const LLHost& host, const LLUUID& id, U8 codec, U16 packets, U32 totalbytes, + U16 data_size, U8* data) +{ + LLTextureFetchWorker* worker = getWorker(id); + bool res = true; + + ++mPacketCount; + + if (!worker) + { +// llwarns << "Received header for non active worker: " << id << llendl; + res = false; + } + else if (worker->mState != LLTextureFetchWorker::LOAD_FROM_NETWORK || + worker->mSentRequest != LLTextureFetchWorker::SENT_SIM) + { +// llwarns << "receiveImageHeader for worker: " << id +// << " in state: " << LLTextureFetchWorker::sStateDescs[worker->mState] +// << " sent: " << worker->mSentRequest << llendl; + res = false; + } + else if (worker->mLastPacket != -1) + { + // check to see if we've gotten this packet before +// llwarns << "Received duplicate header for: " << id << llendl; + res = false; + } + else if (!data_size) + { +// llwarns << "Img: " << id << ":" << " Empty Image Header" << llendl; + res = false; + } + if (!res) + { + ++mBadPacketCount; + mNetworkQueueMutex.lock() ; + mCancelQueue[host].insert(id); + mNetworkQueueMutex.unlock() ; + return false; + } + + worker->lockWorkMutex(); + + // Copy header data into image object + worker->mImageCodec = codec; + worker->mTotalPackets = packets; + worker->mFileSize = (S32)totalbytes; + llassert_always(totalbytes > 0); + llassert_always(data_size == FIRST_PACKET_SIZE || data_size == worker->mFileSize); + res = worker->insertPacket(0, data, data_size); + worker->setPriority(LLWorkerThread::PRIORITY_HIGH | worker->mWorkPriority); + worker->mState = LLTextureFetchWorker::LOAD_FROM_SIMULATOR; + worker->unlockWorkMutex(); + return res; +} + +bool LLTextureFetch::receiveImagePacket(const LLHost& host, const LLUUID& id, U16 packet_num, U16 data_size, U8* data) +{ + LLTextureFetchWorker* worker = getWorker(id); + bool res = true; + + ++mPacketCount; + + if (!worker) + { +// llwarns << "Received packet " << packet_num << " for non active worker: " << id << llendl; + res = false; + } + else if (worker->mLastPacket == -1) + { +// llwarns << "Received packet " << packet_num << " before header for: " << id << llendl; + res = false; + } + else if (!data_size) + { +// llwarns << "Img: " << id << ":" << " Empty Image Header" << llendl; + res = false; + } + if (!res) + { + ++mBadPacketCount; + mNetworkQueueMutex.lock() ; + mCancelQueue[host].insert(id); + mNetworkQueueMutex.unlock() ; + return false; + } + + worker->lockWorkMutex(); + + res = worker->insertPacket(packet_num, data, data_size); + + if ((worker->mState == LLTextureFetchWorker::LOAD_FROM_SIMULATOR) || + (worker->mState == LLTextureFetchWorker::LOAD_FROM_NETWORK)) + { + worker->setPriority(LLWorkerThread::PRIORITY_HIGH | worker->mWorkPriority); + worker->mState = LLTextureFetchWorker::LOAD_FROM_SIMULATOR; + } + else + { +// llwarns << "receiveImagePacket " << packet_num << "/" << worker->mLastPacket << " for worker: " << id +// << " in state: " << LLTextureFetchWorker::sStateDescs[worker->mState] << llendl; + removeFromNetworkQueue(worker, true); // failsafe + } + + if(packet_num >= (worker->mTotalPackets - 1)) + { + static LLCachedControl log_to_viewer_log(gSavedSettings,"LogTextureDownloadsToViewerLog"); + static LLCachedControl log_to_sim(gSavedSettings,"LogTextureDownloadsToSimulator"); + + if (log_to_viewer_log || log_to_sim) + { + U64 timeNow = LLTimer::getTotalTime(); + mTextureInfo.setRequestSize(id, worker->mFileSize); + mTextureInfo.setRequestCompleteTimeAndLog(id, timeNow); + } + } + worker->unlockWorkMutex(); + + return res; +} + +////////////////////////////////////////////////////////////////////////////// +BOOL LLTextureFetch::isFromLocalCache(const LLUUID& id) +{ + BOOL from_cache = FALSE ; + + LLTextureFetchWorker* worker = getWorker(id); + if (worker) + { + worker->lockWorkMutex() ; + from_cache = worker->mInLocalCache ; + worker->unlockWorkMutex() ; + } + + return from_cache ; +} + +S32 LLTextureFetch::getFetchState(const LLUUID& id, F32& data_progress_p, F32& requested_priority_p, + U32& fetch_priority_p, F32& fetch_dtime_p, F32& request_dtime_p, bool& can_use_http) +{ + S32 state = LLTextureFetchWorker::INVALID; + F32 data_progress = 0.0f; + F32 requested_priority = 0.0f; + F32 fetch_dtime = 999999.f; + F32 request_dtime = 999999.f; + U32 fetch_priority = 0; + + LLTextureFetchWorker* worker = getWorker(id); + if (worker && worker->haveWork()) + { + worker->lockWorkMutex(); + state = worker->mState; + fetch_dtime = worker->mFetchTimer.getElapsedTimeF32(); + request_dtime = worker->mRequestedTimer.getElapsedTimeF32(); + if (worker->mFileSize > 0) + { + if (state == LLTextureFetchWorker::LOAD_FROM_SIMULATOR) + { + S32 data_size = FIRST_PACKET_SIZE + (worker->mLastPacket-1) * MAX_IMG_PACKET_SIZE; + data_size = llmax(data_size, 0); + data_progress = (F32)data_size / (F32)worker->mFileSize; + } + else if (worker->mFormattedImage.notNull()) + { + data_progress = (F32)worker->mFormattedImage->getDataSize() / (F32)worker->mFileSize; + } + } + if (state >= LLTextureFetchWorker::LOAD_FROM_NETWORK && state <= LLTextureFetchWorker::WAIT_HTTP_REQ) + { + requested_priority = worker->mRequestedPriority; + } + else + { + requested_priority = worker->mImagePriority; + } + fetch_priority = worker->getPriority(); + can_use_http = worker->getCanUseHTTP() ; + worker->unlockWorkMutex(); + } + data_progress_p = data_progress; + requested_priority_p = requested_priority; + fetch_priority_p = fetch_priority; + fetch_dtime_p = fetch_dtime; + request_dtime_p = request_dtime; + return state; +} + +void LLTextureFetch::dump() +{ + llinfos << "LLTextureFetch REQUESTS:" << llendl; + for (request_queue_t::iterator iter = mRequestQueue.begin(); + iter != mRequestQueue.end(); ++iter) + { + LLQueuedThread::QueuedRequest* qreq = *iter; + LLWorkerThread::WorkRequest* wreq = (LLWorkerThread::WorkRequest*)qreq; + LLTextureFetchWorker* worker = (LLTextureFetchWorker*)wreq->getWorkerClass(); + llinfos << " ID: " << worker->mID + << " PRI: " << llformat("0x%08x",wreq->getPriority()) + << " STATE: " << worker->sStateDescs[worker->mState] + << llendl; + } +} + +////////////////////////////////////////////////////////////////////////////// + +// cross-thread command methods + +void LLTextureFetch::commandSetRegion(U64 region_handle) +{ + TFReqSetRegion * req = new TFReqSetRegion(region_handle); + + cmdEnqueue(req); +} + +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); +} + +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; +} + +void LLTextureFetch::cmdEnqueue(TFRequest * req) +{ + lockQueue(); + mCommands.push_back(req); + unlockQueue(); + + unpause(); +} + +LLTextureFetch::TFRequest * LLTextureFetch::cmdDequeue() +{ + TFRequest * ret = 0; + + lockQueue(); + if (! mCommands.empty()) + { + ret = mCommands.front(); + mCommands.erase(mCommands.begin()); + } + unlockQueue(); + + return ret; +} + +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 +{ + +/** + * 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) +{ + /* + * HTTP POST responder. Doesn't do much but tries to + * detect simple breaks in recording the metrics stream. + * + * The 'volatile' modifiers don't indicate signals, + * mmap'd memory or threads, really. They indicate that + * the referenced data is part of a pseudo-closure for + * this responder rather than being required for correct + * operation. + * + * We don't try very hard with the POST request. We give + * it one shot and that's more-or-less it. With a proper + * refactoring of the LLQueuedThread usage, these POSTs + * could be put in a request object and made more reliable. + */ + class lcl_responder : public LLCurl::Responder + { + public: + lcl_responder(LLTextureFetch * fetcher, + S32 expected_sequence, + volatile const S32 & live_sequence, + volatile bool & reporting_break, + volatile bool & reporting_started) + : LLCurl::Responder(), + mFetcher(fetcher), + mExpectedSequence(expected_sequence), + mLiveSequence(live_sequence), + mReportingBreak(reporting_break), + mReportingStarted(reporting_started) + { + mFetcher->incrCurlPOSTCount(); + } + + ~lcl_responder() + { + mFetcher->decrCurlPOSTCount(); + } + + // virtual + void error(U32 status_num, const std::string & reason) + { + if (mLiveSequence == mExpectedSequence) + { + mReportingBreak = true; + } + LL_WARNS("Texture") << "Break in metrics stream due to POST failure to metrics collection service. Reason: " + << reason << LL_ENDL; + } + + // virtual + void result(const LLSD & content) + { + if (mLiveSequence == mExpectedSequence) + { + mReportingBreak = false; + mReportingStarted = true; + } + } + + private: + LLTextureFetch * mFetcher; + S32 mExpectedSequence; + volatile const S32 & mLiveSequence; + volatile bool & mReportingBreak; + volatile bool & mReportingStarted; + + }; // class lcl_responder + + 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; + + // Limit the size of the stats report if necessary. + merged_llsd["truncated"] = truncate_viewer_metrics(10, merged_llsd); + + if (! mCapsURL.empty()) + { + LLCurlRequest::headers_t headers; + fetcher->getCurlRequest().post(mCapsURL, + headers, + merged_llsd, + new lcl_responder(fetcher, + report_sequence, + report_sequence, + LLTextureFetch::svMetricsDataBreak, + reporting_started)); + } + else + { + LLTextureFetch::svMetricsDataBreak = true; + } + + // In QA mode, Metrics submode, log the result for ease of testing + if (fetcher->isQAMode()) + { + LL_INFOS("Textures") << 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 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 + + + -- cgit v1.2.3