diff --git a/etc/message.xml b/etc/message.xml index 8dfd75e13..690103bb7 100644 --- a/etc/message.xml +++ b/etc/message.xml @@ -670,19 +670,19 @@ EstateChangeInfo true - FetchInventoryDescendents + FetchInventoryDescendents2 false WebFetchInventoryDescendents false - FetchInventory + FetchInventory2 true - FetchLibDescendents + FetchLibDescendents2 true - FetchLib + FetchLib2 true diff --git a/indra/llcharacter/llcharacter.cpp b/indra/llcharacter/llcharacter.cpp index 288bf1ff5..36e3d99f1 100644 --- a/indra/llcharacter/llcharacter.cpp +++ b/indra/llcharacter/llcharacter.cpp @@ -195,15 +195,19 @@ void LLCharacter::requestStopMotion( LLMotion* motion) //----------------------------------------------------------------------------- // updateMotions() //----------------------------------------------------------------------------- +static LLFastTimer::DeclareTimer FTM_UPDATE_ANIMATION("Update Animation"); +static LLFastTimer::DeclareTimer FTM_UPDATE_HIDDEN_ANIMATION("Update Hidden Anim"); + void LLCharacter::updateMotions(e_update_t update_type) { - LLFastTimer t(LLFastTimer::FTM_UPDATE_ANIMATION); if (update_type == HIDDEN_UPDATE) { + LLFastTimer t(FTM_UPDATE_HIDDEN_ANIMATION); mMotionController.updateMotionsMinimal(); } else { + LLFastTimer t(FTM_UPDATE_ANIMATION); // unpause if the number of outstanding pause requests has dropped to the initial one if (mMotionController.isPaused() && mPauseRequest->getNumRefs() == 1) { diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index 89db80b1c..60f21b25e 100644 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -35,7 +35,7 @@ set(llcommon_SOURCE_FILES llerrorthread.cpp llevent.cpp lleventtimer.cpp - llfasttimer.cpp + llfasttimer_class.cpp llfile.cpp llfindlocale.cpp llfixedbuffer.cpp @@ -54,6 +54,7 @@ set(llcommon_SOURCE_FILES llmetrics.cpp llmortician.cpp lloptioninterface.cpp + llptrto.cpp llprocesslauncher.cpp llprocessor.cpp llqueuedthread.cpp @@ -136,6 +137,7 @@ set(llcommon_HEADER_FILES llextendedstatus.h lleventtimer.h llfasttimer.h + llfasttimer_class.h llfile.h llfindlocale.h llfixedbuffer.h @@ -171,6 +173,7 @@ set(llcommon_HEADER_FILES llprocessor.h llptrskiplist.h llptrskipmap.h + llptrto.h llqueuedthread.h llrand.h llrefcount.h diff --git a/indra/llcommon/llfasttimer.cpp b/indra/llcommon/llfasttimer.cpp deleted file mode 100644 index f1d7eb305..000000000 --- a/indra/llcommon/llfasttimer.cpp +++ /dev/null @@ -1,135 +0,0 @@ -/** - * @file llfasttimer.cpp - * @brief Implementation of the fast timer. - * - * $LicenseInfo:firstyear=2004&license=viewergpl$ - * - * Copyright (c) 2004-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#include "linden_common.h" - -#include "llfasttimer.h" -#include "llmemory.h" -#include "llprocessor.h" - -#if LL_WINDOWS -#define WIN32_LEAN_AND_MEAN -#include -#endif -#include "lltimer.h" - -////////////////////////////////////////////////////////////////////////////// -// statics - -LLFastTimer::EFastTimerType LLFastTimer::sCurType = LLFastTimer::FTM_OTHER; -int LLFastTimer::sCurDepth = 0; -U64 LLFastTimer::sStart[LLFastTimer::FTM_MAX_DEPTH]; -U64 LLFastTimer::sCounter[LLFastTimer::FTM_NUM_TYPES]; -U64 LLFastTimer::sCountHistory[LLFastTimer::FTM_HISTORY_NUM][LLFastTimer::FTM_NUM_TYPES]; -U64 LLFastTimer::sCountAverage[LLFastTimer::FTM_NUM_TYPES]; -U64 LLFastTimer::sCalls[LLFastTimer::FTM_NUM_TYPES]; -U64 LLFastTimer::sCallHistory[LLFastTimer::FTM_HISTORY_NUM][LLFastTimer::FTM_NUM_TYPES]; -U64 LLFastTimer::sCallAverage[LLFastTimer::FTM_NUM_TYPES]; -S32 LLFastTimer::sCurFrameIndex = -1; -S32 LLFastTimer::sLastFrameIndex = -1; -int LLFastTimer::sPauseHistory = 0; -int LLFastTimer::sResetHistory = 0; - -U64 LLFastTimer::sClockResolution = calc_clock_frequency(50U); // Resolution of get_clock_count() - -U64 LLFastTimer::countsPerSecond() // counts per second for the *32-bit* timer -{ - return sClockResolution >> 8; -} - -void LLFastTimer::reset() -{ - countsPerSecond(); // good place to calculate clock frequency - - if (sCurDepth != 0) - { - llerrs << "LLFastTimer::Reset() when sCurDepth != 0" << llendl; - } - if (sPauseHistory) - { - sResetHistory = 1; - } - else if (sResetHistory) - { - sCurFrameIndex = -1; - sResetHistory = 0; - } - else if (sCurFrameIndex >= 0) - { - int hidx = sCurFrameIndex % FTM_HISTORY_NUM; - for (S32 i=0; i> 8; -} - -U64 LLFastTimer::getCPUClockCount64() -{ - return get_clock_count(); -} diff --git a/indra/llcommon/llfasttimer.h b/indra/llcommon/llfasttimer.h index 395ee8060..2b25f2fab 100644 --- a/indra/llcommon/llfasttimer.h +++ b/indra/llcommon/llfasttimer.h @@ -1,306 +1,35 @@ -/** +/** * @file llfasttimer.h - * @brief Declaration of a fast timer. + * @brief Inline implementations of fast timers. * - * $LicenseInfo:firstyear=2004&license=viewergpl$ - * - * Copyright (c) 2004-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2004&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ -#ifndef LL_LLFASTTIMER_H -#define LL_LLFASTTIMER_H +#ifndef LL_FASTTIMER_H +#define LL_FASTTIMER_H -#define FAST_TIMER_ON 1 - - -class LL_COMMON_API LLFastTimer -{ -public: - enum EFastTimerType - { - // high level - FTM_FRAME, - FTM_UPDATE, - FTM_RENDER, - FTM_SWAP, - FTM_CLIENT_COPY, - FTM_IDLE, - FTM_SLEEP, - - // general timers - FT_STRING_FORMAT, - - // common messaging components - FTM_PUMP, - FTM_CURL, - FTM_PUMPIO, - - // common simulation components - FTM_UPDATE_ANIMATION, - FTM_UPDATE_TERRAIN, - FTM_UPDATE_PRIMITIVES, - FTM_UPDATE_PARTICLES, - FTM_SIMULATE_PARTICLES, - FTM_UPDATE_SKY, - FTM_UPDATE_TEXTURES, - FTM_UPDATE_WLPARAM, - FTM_UPDATE_WATER, - FTM_UPDATE_CLOUDS, - FTM_UPDATE_GRASS, - FTM_UPDATE_TREE, - FTM_UPDATE_AVATAR, - FTM_UPDATE_RIGGED_VOLUME, - FTM_SKIN_RIGGED, - FTM_RIGGED_OCTREE, - - // common render components - FTM_SHADOW_GEOMETRY, - FTM_SHADOW_RENDER, - FTM_SHADOW_TERRAIN, - FTM_SHADOW_AVATAR, - FTM_SHADOW_SIMPLE, - FTM_SHADOW_ALPHA, - FTM_SHADOW_TREE, - - FTM_RENDER_GEOMETRY, - FTM_RENDER_TERRAIN, - FTM_RENDER_SIMPLE, - FTM_RENDER_FULLBRIGHT, - FTM_RENDER_GLOW, - FTM_RENDER_GRASS, - FTM_RENDER_INVISIBLE, - FTM_RENDER_SHINY, - FTM_RENDER_BUMP, - FTM_RENDER_TREES, - FTM_RENDER_CHARACTERS, - FTM_RENDER_OCCLUSION, - FTM_RENDER_ALPHA, - FTM_RENDER_CLOUDS, - FTM_RENDER_HUD, - FTM_RENDER_PARTICLES, - FTM_RENDER_WATER, - FTM_RENDER_WL_SKY, - FTM_RENDER_FAKE_VBO_UPDATE, - FTM_RENDER_TIMER, - FTM_RENDER_UI, - FTM_RENDER_BLOOM, - FTM_RENDER_BLOOM_FBO, - FTM_RENDER_FONTS, - - // deferred rendering - FTM_RENDER_DEFERRED, - FTM_BIND_DEFERRED, - FTM_SUN_SHADOW, - FTM_SOFTEN_SHADOW, - FTM_EDGE_DETECTION, - FTM_GI_TRACE, - FTM_GI_GATHER, - FTM_ATMOSPHERICS, - FTM_LOCAL_LIGHTS, - FTM_FULLSCREEN_LIGHTS, - FTM_PROJECTORS, - FTM_POST, - - FTM_VISIBLE_CLOUD, - - // newview specific - FTM_MESSAGES, - FTM_MOUSEHANDLER, - FTM_KEYHANDLER, - FTM_REBUILD, - FTM_STATESORT, - FTM_STATESORT_DRAWABLE, - FTM_STATESORT_POSTSORT, - FTM_MESH_UPDATE, - FTM_MESH_LOCK1, - FTM_MESH_LOCK2, - FTM_LOAD_MESH_LOD, - FTM_REBUILD_VBO, - FTM_REBUILD_VOLUME_VB, - FTM_FACE_GET_GEOM, - FTM_FACE_GEOM_POSITION, - FTM_FACE_GEOM_NORMAL, - FTM_FACE_GEOM_TEXTURE, - FTM_FACE_GEOM_COLOR, - FTM_FACE_GEOM_EMISSIVE, - FTM_FACE_GEOM_WEIGHTS, - FTM_FACE_GEOM_BINORMAL, - FTM_FACE_GEOM_INDEX, - FTM_REBUILD_BRIDGE_VB, - FTM_REBUILD_HUD_VB, - FTM_REBUILD_TERRAIN_VB, - FTM_REBUILD_WATER_VB, - FTM_REBUILD_TREE_VB, - FTM_REBUILD_PARTICLE_VB, - FTM_REBUILD_CLOUD_VB, - FTM_REBUILD_GRASS_VB, - FTM_REBUILD_NONE_VB, - FTM_REBUILD_OCCLUSION_VB, - FTM_POOLS, - FTM_POOLRENDER, - FTM_IDLE_CB, - FTM_WORLD_UPDATE, - FTM_UPDATE_MOVE, - FTM_OCTREE_BALANCE, - FTM_UPDATE_LIGHTS, - FTM_CULL, - FTM_CULL_REBOUND, - FTM_FRUSTUM_CULL, - FTM_GEO_UPDATE, - FTM_GEO_RESERVE, - FTM_GEO_LIGHT, - FTM_GEO_SHADOW, - FTM_GEO_SKY, - FTM_GEN_VOLUME, - FTM_GEN_TRIANGLES, - FTM_GEN_FLEX, - FTM_AUDIO_UPDATE, - FTM_RESET_DRAWORDER, - FTM_OBJECTLIST_UPDATE, - FTM_AVATAR_UPDATE, - FTM_JOINT_UPDATE, - FTM_ATTACHMENT_UPDATE, - FTM_LOD_UPDATE, - FTM_REGION_UPDATE, - FTM_CLEANUP, - FTM_NETWORK, - FTM_IDLE_NETWORK, - FTM_CREATE_OBJECT, - FTM_LOAD_AVATAR, - FTM_PROCESS_MESSAGES, - FTM_PROCESS_OBJECTS, - FTM_PROCESS_IMAGES, - FTM_IMAGE_UPDATE, - FTM_IMAGE_CREATE, - FTM_IMAGE_DECODE, - FTM_IMAGE_READBACK, - FTM_IMAGE_MARK_DIRTY, - FTM_PIPELINE, - FTM_VFILE_WAIT, - FTM_FLEXIBLE_UPDATE, - FTM_OCCLUSION_READBACK, - FTM_HUD_EFFECTS, - FTM_HUD_UPDATE, - FTM_INVENTORY, - FTM_AUTO_SELECT, - FTM_ARRANGE, - FTM_FILTER, - FTM_REFRESH, - FTM_SORT, - FTM_PICK, - FTM_STATEMACHINE, - - // Temp - FTM_TEMP1, - FTM_TEMP2, - FTM_TEMP3, - FTM_TEMP4, - FTM_TEMP5, - FTM_TEMP6, - FTM_TEMP7, - FTM_TEMP8, - FTM_TEMP9, - FTM_TEMP10, - FTM_TEMP11, - FTM_TEMP12, - FTM_TEMP13, - FTM_TEMP14, - FTM_TEMP15, - - FTM_OTHER, // Special, used by display code - - FTM_NUM_TYPES - }; - enum { FTM_HISTORY_NUM = 60 }; - enum { FTM_MAX_DEPTH = 64 }; - -public: - static EFastTimerType sCurType; - - LLFastTimer(EFastTimerType type) - { -#if FAST_TIMER_ON - mType = type; - sCurType = type; - // These don't get counted, because they use CPU clockticks - //gTimerBins[gCurTimerBin]++; - //LLTimer::sNumTimerCalls++; - - U64 cpu_clocks = getCPUClockCount32(); - - sStart[sCurDepth] = cpu_clocks; - sCurDepth++; -#endif - }; - ~LLFastTimer() - { -#if FAST_TIMER_ON - U64 end,delta; - int i; - - // These don't get counted, because they use CPU clockticks - //gTimerBins[gCurTimerBin]++; - //LLTimer::sNumTimerCalls++; - end = getCPUClockCount32(); - - sCurDepth--; - delta = end - sStart[sCurDepth]; - sCounter[mType] += delta; - sCalls[mType]++; - // Subtract delta from parents - for (i=0; i + + +#if LL_WINDOWS +#include "lltimer.h" +#elif LL_LINUX || LL_SOLARIS +#include +#include +#include "lltimer.h" +#elif LL_DARWIN +#include +#include "lltimer.h" // get_clock_count() +#else +#error "architecture not supported" +#endif + +////////////////////////////////////////////////////////////////////////////// +// statics + +S32 LLFastTimer::sCurFrameIndex = -1; +S32 LLFastTimer::sLastFrameIndex = -1; +U64 LLFastTimer::sLastFrameTime = LLFastTimer::getCPUClockCount64(); +bool LLFastTimer::sPauseHistory = 0; +bool LLFastTimer::sResetHistory = 0; +LLFastTimer::CurTimerData LLFastTimer::sCurTimerData; +BOOL LLFastTimer::sLog = FALSE; +std::string LLFastTimer::sLogName = ""; +BOOL LLFastTimer::sMetricLog = FALSE; +LLMutex* LLFastTimer::sLogLock = NULL; +std::queue LLFastTimer::sLogQueue; + +#define USE_RDTSC 0 + +#if LL_LINUX || LL_SOLARIS +U64 LLFastTimer::sClockResolution = 1000000000; // Nanosecond resolution +#else +U64 LLFastTimer::sClockResolution = 1000000; // Microsecond resolution +#endif + +std::vector* LLFastTimer::sTimerInfos = NULL; +U64 LLFastTimer::sTimerCycles = 0; +U32 LLFastTimer::sTimerCalls = 0; + + +// FIXME: move these declarations to the relevant modules + +// helper functions +typedef LLTreeDFSPostIter timer_tree_bottom_up_iterator_t; + +static timer_tree_bottom_up_iterator_t begin_timer_tree_bottom_up(LLFastTimer::NamedTimer& id) +{ + return timer_tree_bottom_up_iterator_t(&id, + boost::bind(boost::mem_fn(&LLFastTimer::NamedTimer::beginChildren), _1), + boost::bind(boost::mem_fn(&LLFastTimer::NamedTimer::endChildren), _1)); +} + +static timer_tree_bottom_up_iterator_t end_timer_tree_bottom_up() +{ + return timer_tree_bottom_up_iterator_t(); +} + +typedef LLTreeDFSIter timer_tree_dfs_iterator_t; + + +static timer_tree_dfs_iterator_t begin_timer_tree(LLFastTimer::NamedTimer& id) +{ + return timer_tree_dfs_iterator_t(&id, + boost::bind(boost::mem_fn(&LLFastTimer::NamedTimer::beginChildren), _1), + boost::bind(boost::mem_fn(&LLFastTimer::NamedTimer::endChildren), _1)); +} + +static timer_tree_dfs_iterator_t end_timer_tree() +{ + return timer_tree_dfs_iterator_t(); +} + + + +// factory class that creates NamedTimers via static DeclareTimer objects +class NamedTimerFactory : public LLSingleton +{ +public: + NamedTimerFactory() + : mActiveTimerRoot(NULL), + mTimerRoot(NULL), + mAppTimer(NULL), + mRootFrameState(NULL) + {} + + /*virtual */ void initSingleton() + { + mTimerRoot = new LLFastTimer::NamedTimer("root"); + + mActiveTimerRoot = new LLFastTimer::NamedTimer("Frame"); + mActiveTimerRoot->setCollapsed(false); + + mRootFrameState = new LLFastTimer::FrameState(mActiveTimerRoot); + mRootFrameState->mParent = &mTimerRoot->getFrameState(); + mActiveTimerRoot->setParent(mTimerRoot); + + mAppTimer = new LLFastTimer(mRootFrameState); + } + + ~NamedTimerFactory() + { + std::for_each(mTimers.begin(), mTimers.end(), DeletePairedPointer()); + + delete mAppTimer; + delete mActiveTimerRoot; + delete mTimerRoot; + delete mRootFrameState; + } + + LLFastTimer::NamedTimer& createNamedTimer(const std::string& name) + { + timer_map_t::iterator found_it = mTimers.find(name); + if (found_it != mTimers.end()) + { + return *found_it->second; + } + + LLFastTimer::NamedTimer* timer = new LLFastTimer::NamedTimer(name); + timer->setParent(mTimerRoot); + mTimers.insert(std::make_pair(name, timer)); + + return *timer; + } + + LLFastTimer::NamedTimer* getTimerByName(const std::string& name) + { + timer_map_t::iterator found_it = mTimers.find(name); + if (found_it != mTimers.end()) + { + return found_it->second; + } + return NULL; + } + + LLFastTimer::NamedTimer* getActiveRootTimer() { return mActiveTimerRoot; } + LLFastTimer::NamedTimer* getRootTimer() { return mTimerRoot; } + const LLFastTimer* getAppTimer() { return mAppTimer; } + LLFastTimer::FrameState& getRootFrameState() { return *mRootFrameState; } + + typedef std::map timer_map_t; + timer_map_t::iterator beginTimers() { return mTimers.begin(); } + timer_map_t::iterator endTimers() { return mTimers.end(); } + S32 timerCount() { return mTimers.size(); } + +private: + timer_map_t mTimers; + + LLFastTimer::NamedTimer* mActiveTimerRoot; + LLFastTimer::NamedTimer* mTimerRoot; + LLFastTimer* mAppTimer; + LLFastTimer::FrameState* mRootFrameState; +}; + +void update_cached_pointers_if_changed() +{ + // detect when elements have moved and update cached pointers + static LLFastTimer::FrameState* sFirstTimerAddress = NULL; + if (&*(LLFastTimer::getFrameStateList().begin()) != sFirstTimerAddress) + { + LLFastTimer::DeclareTimer::updateCachedPointers(); + } + sFirstTimerAddress = &*(LLFastTimer::getFrameStateList().begin()); +} + +LLFastTimer::DeclareTimer::DeclareTimer(const std::string& name, bool open ) +: mTimer(NamedTimerFactory::instance().createNamedTimer(name)) +{ + mTimer.setCollapsed(!open); + mFrameState = &mTimer.getFrameState(); + update_cached_pointers_if_changed(); +} + +LLFastTimer::DeclareTimer::DeclareTimer(const std::string& name) +: mTimer(NamedTimerFactory::instance().createNamedTimer(name)) +{ + mFrameState = &mTimer.getFrameState(); + update_cached_pointers_if_changed(); +} + +// static +void LLFastTimer::DeclareTimer::updateCachedPointers() +{ + // propagate frame state pointers to timer declarations + for (instance_iter it = beginInstances(); it != endInstances(); ++it) + { + // update cached pointer + it->mFrameState = &it->mTimer.getFrameState(); + } + + // also update frame states of timers on stack + LLFastTimer* cur_timerp = LLFastTimer::sCurTimerData.mCurTimer; + while(cur_timerp->mLastTimerData.mCurTimer != cur_timerp) + { + cur_timerp->mFrameState = &cur_timerp->mFrameState->mTimer->getFrameState(); + cur_timerp = cur_timerp->mLastTimerData.mCurTimer; + } +} + +//static +#if (LL_DARWIN || LL_LINUX || LL_SOLARIS) && !(defined(__i386__) || defined(__amd64__)) +U64 LLFastTimer::countsPerSecond() // counts per second for the *32-bit* timer +{ + return sClockResolution >> 8; +} +#else // windows or x86-mac or x86-linux or x86-solaris +U64 LLFastTimer::countsPerSecond() // counts per second for the *32-bit* timer +{ +#if USE_RDTSC || !LL_WINDOWS + //getCPUFrequency returns MHz and sCPUClockFrequency wants to be in Hz + static U64 sCPUClockFrequency = U64(LLProcessorInfo().getCPUFrequency()*1000000.0); + + // we drop the low-order byte in our timers, so report a lower frequency +#else + // If we're not using RDTSC, each fasttimer tick is just a performance counter tick. + // Not redefining the clock frequency itself (in llprocessor.cpp/calculate_cpu_frequency()) + // since that would change displayed MHz stats for CPUs + static bool firstcall = true; + static U64 sCPUClockFrequency; + if (firstcall) + { + QueryPerformanceFrequency((LARGE_INTEGER*)&sCPUClockFrequency); + firstcall = false; + } +#endif + return sCPUClockFrequency >> 8; +} +#endif + +LLFastTimer::FrameState::FrameState(LLFastTimer::NamedTimer* timerp) +: mActiveCount(0), + mCalls(0), + mSelfTimeCounter(0), + mParent(NULL), + mLastCaller(NULL), + mMoveUpTree(false), + mTimer(timerp) +{} + + +LLFastTimer::NamedTimer::NamedTimer(const std::string& name) +: mName(name), + mCollapsed(true), + mParent(NULL), + mTotalTimeCounter(0), + mCountAverage(0), + mCallAverage(0), + mNeedsSorting(false) +{ + info_list_t& frame_state_list = getFrameStateList(); + mFrameStateIndex = frame_state_list.size(); + getFrameStateList().push_back(FrameState(this)); + + mCountHistory = new U32[HISTORY_NUM]; + memset(mCountHistory, 0, sizeof(U32) * HISTORY_NUM); + mCallHistory = new U32[HISTORY_NUM]; + memset(mCallHistory, 0, sizeof(U32) * HISTORY_NUM); +} + +LLFastTimer::NamedTimer::~NamedTimer() +{ + delete[] mCountHistory; + delete[] mCallHistory; +} + +std::string LLFastTimer::NamedTimer::getToolTip(S32 history_idx) +{ + F64 ms_multiplier = 1000.0 / (F64)LLFastTimer::countsPerSecond(); + if (history_idx < 0) + { + // by default, show average number of call + return llformat("%s (%d ms, %d calls)", getName().c_str(), (S32)(getCountAverage() * ms_multiplier), (S32)getCallAverage()); + } + else + { + return llformat("%s (%d ms, %d calls)", getName().c_str(), (S32)(getHistoricalCount(history_idx) * ms_multiplier), (S32)getHistoricalCalls(history_idx)); + } +} + +void LLFastTimer::NamedTimer::setParent(NamedTimer* parent) +{ + llassert_always(parent != this); + llassert_always(parent != NULL); + + if (mParent) + { + // subtract our accumulated from previous parent + for (S32 i = 0; i < HISTORY_NUM; i++) + { + mParent->mCountHistory[i] -= mCountHistory[i]; + } + + // subtract average timing from previous parent + mParent->mCountAverage -= mCountAverage; + + std::vector& children = mParent->getChildren(); + std::vector::iterator found_it = std::find(children.begin(), children.end(), this); + if (found_it != children.end()) + { + children.erase(found_it); + } + } + + mParent = parent; + if (parent) + { + getFrameState().mParent = &parent->getFrameState(); + parent->getChildren().push_back(this); + parent->mNeedsSorting = true; + } +} + +S32 LLFastTimer::NamedTimer::getDepth() +{ + S32 depth = 0; + NamedTimer* timerp = mParent; + while(timerp) + { + depth++; + timerp = timerp->mParent; + } + return depth; +} + +// static +void LLFastTimer::NamedTimer::processTimes() +{ + if (sCurFrameIndex < 0) return; + + buildHierarchy(); + accumulateTimings(); +} + +// sort timer info structs by depth first traversal order +struct SortTimersDFS +{ + bool operator()(const LLFastTimer::FrameState& i1, const LLFastTimer::FrameState& i2) + { + return i1.mTimer->getFrameStateIndex() < i2.mTimer->getFrameStateIndex(); + } +}; + +// sort child timers by name +struct SortTimerByName +{ + bool operator()(const LLFastTimer::NamedTimer* i1, const LLFastTimer::NamedTimer* i2) + { + return i1->getName() < i2->getName(); + } +}; + +//static +void LLFastTimer::NamedTimer::buildHierarchy() +{ + if (sCurFrameIndex < 0 ) return; + + // set up initial tree + { + for (instance_iter it = beginInstances(); it != endInstances(); ++it) + { + NamedTimer& timer = *it; + if (&timer == NamedTimerFactory::instance().getRootTimer()) continue; + + // bootstrap tree construction by attaching to last timer to be on stack + // when this timer was called + if (timer.getFrameState().mLastCaller && timer.mParent == NamedTimerFactory::instance().getRootTimer()) + { + timer.setParent(timer.getFrameState().mLastCaller->mTimer); + // no need to push up tree on first use, flag can be set spuriously + timer.getFrameState().mMoveUpTree = false; + } + } + } + + // bump timers up tree if they've been flagged as being in the wrong place + // do this in a bottom up order to promote descendants first before promoting ancestors + // this preserves partial order derived from current frame's observations + for(timer_tree_bottom_up_iterator_t it = begin_timer_tree_bottom_up(*NamedTimerFactory::instance().getRootTimer()); + it != end_timer_tree_bottom_up(); + ++it) + { + NamedTimer* timerp = *it; + // skip root timer + if (timerp == NamedTimerFactory::instance().getRootTimer()) continue; + + if (timerp->getFrameState().mMoveUpTree) + { + // since ancestors have already been visited, reparenting won't affect tree traversal + //step up tree, bringing our descendants with us + //llinfos << "Moving " << timerp->getName() << " from child of " << timerp->getParent()->getName() << + // " to child of " << timerp->getParent()->getParent()->getName() << llendl; + timerp->setParent(timerp->getParent()->getParent()); + timerp->getFrameState().mMoveUpTree = false; + + // don't bubble up any ancestors until descendants are done bubbling up + it.skipAncestors(); + } + } + + // sort timers by time last called, so call graph makes sense + for(timer_tree_dfs_iterator_t it = begin_timer_tree(*NamedTimerFactory::instance().getRootTimer()); + it != end_timer_tree(); + ++it) + { + NamedTimer* timerp = (*it); + if (timerp->mNeedsSorting) + { + std::sort(timerp->getChildren().begin(), timerp->getChildren().end(), SortTimerByName()); + } + timerp->mNeedsSorting = false; + } +} + +//static +void LLFastTimer::NamedTimer::accumulateTimings() +{ + U32 cur_time = getCPUClockCount32(); + + // walk up stack of active timers and accumulate current time while leaving timing structures active + LLFastTimer* cur_timer = sCurTimerData.mCurTimer; + // root defined by parent pointing to self + CurTimerData* cur_data = &sCurTimerData; + while(cur_timer->mLastTimerData.mCurTimer != cur_timer) + { + U32 cumulative_time_delta = cur_time - cur_timer->mStartTime; + U32 self_time_delta = cumulative_time_delta - cur_data->mChildTime; + cur_data->mChildTime = 0; + cur_timer->mFrameState->mSelfTimeCounter += self_time_delta; + cur_timer->mStartTime = cur_time; + + cur_data = &cur_timer->mLastTimerData; + cur_data->mChildTime += cumulative_time_delta; + + cur_timer = cur_timer->mLastTimerData.mCurTimer; + } + + // traverse tree in DFS post order, or bottom up + for(timer_tree_bottom_up_iterator_t it = begin_timer_tree_bottom_up(*NamedTimerFactory::instance().getActiveRootTimer()); + it != end_timer_tree_bottom_up(); + ++it) + { + NamedTimer* timerp = (*it); + timerp->mTotalTimeCounter = timerp->getFrameState().mSelfTimeCounter; + for (child_const_iter child_it = timerp->beginChildren(); child_it != timerp->endChildren(); ++child_it) + { + timerp->mTotalTimeCounter += (*child_it)->mTotalTimeCounter; + } + + S32 cur_frame = sCurFrameIndex; + if (cur_frame >= 0) + { + // update timer history + int hidx = cur_frame % HISTORY_NUM; + + timerp->mCountHistory[hidx] = timerp->mTotalTimeCounter; + timerp->mCountAverage = ((U64)timerp->mCountAverage * cur_frame + timerp->mTotalTimeCounter) / (cur_frame+1); + timerp->mCallHistory[hidx] = timerp->getFrameState().mCalls; + timerp->mCallAverage = ((U64)timerp->mCallAverage * cur_frame + timerp->getFrameState().mCalls) / (cur_frame+1); + } + } +} + +// static +void LLFastTimer::NamedTimer::resetFrame() +{ + if (sLog) + { //output current frame counts to performance log + + static S32 call_count = 0; + if (call_count % 100 == 0) + { + llinfos << "countsPerSecond (32 bit): " << countsPerSecond() << llendl; + llinfos << "get_clock_count (64 bit): " << get_clock_count() << llendl; + llinfos << "LLProcessorInfo().getCPUFrequency() " << LLProcessorInfo().getCPUFrequency() << llendl; + llinfos << "getCPUClockCount32() " << getCPUClockCount32() << llendl; + llinfos << "getCPUClockCount64() " << getCPUClockCount64() << llendl; + llinfos << "elapsed sec " << ((F64)getCPUClockCount64())/((F64)LLProcessorInfo().getCPUFrequency()*1000000.0) << llendl; + } + call_count++; + + F64 iclock_freq = 1000.0 / countsPerSecond(); // good place to calculate clock frequency + + F64 total_time = 0; + LLSD sd; + + { + for (instance_iter it = beginInstances(); it != endInstances(); ++it) + { + NamedTimer& timer = *it; + FrameState& info = timer.getFrameState(); + sd[timer.getName()]["Time"] = (LLSD::Real) (info.mSelfTimeCounter*iclock_freq); + sd[timer.getName()]["Calls"] = (LLSD::Integer) info.mCalls; + + // computing total time here because getting the root timer's getCountHistory + // doesn't work correctly on the first frame + total_time = total_time + info.mSelfTimeCounter * iclock_freq; + } + } + + sd["Total"]["Time"] = (LLSD::Real) total_time; + sd["Total"]["Calls"] = (LLSD::Integer) 1; + + { + LLMutexLock lock(sLogLock); + sLogQueue.push(sd); + } + } + + + // tag timers by position in depth first traversal of tree + S32 index = 0; + for(timer_tree_dfs_iterator_t it = begin_timer_tree(*NamedTimerFactory::instance().getRootTimer()); + it != end_timer_tree(); + ++it) + { + NamedTimer* timerp = (*it); + + timerp->mFrameStateIndex = index; + index++; + + llassert_always(timerp->mFrameStateIndex < (S32)getFrameStateList().size()); + } + + // sort timers by DFS traversal order to improve cache coherency + std::sort(getFrameStateList().begin(), getFrameStateList().end(), SortTimersDFS()); + + // update pointers into framestatelist now that we've sorted it + DeclareTimer::updateCachedPointers(); + + // reset for next frame + { + for (instance_iter it = beginInstances(); it != endInstances(); ++it) + { + NamedTimer& timer = *it; + + FrameState& info = timer.getFrameState(); + info.mSelfTimeCounter = 0; + info.mCalls = 0; + info.mLastCaller = NULL; + info.mMoveUpTree = false; + // update parent pointer in timer state struct + if (timer.mParent) + { + info.mParent = &timer.mParent->getFrameState(); + } + } + } + + //sTimerCycles = 0; + //sTimerCalls = 0; +} + +//static +void LLFastTimer::NamedTimer::reset() +{ + resetFrame(); // reset frame data + + // walk up stack of active timers and reset start times to current time + // effectively zeroing out any accumulated time + U32 cur_time = getCPUClockCount32(); + + // root defined by parent pointing to self + CurTimerData* cur_data = &sCurTimerData; + LLFastTimer* cur_timer = cur_data->mCurTimer; + while(cur_timer->mLastTimerData.mCurTimer != cur_timer) + { + cur_timer->mStartTime = cur_time; + cur_data->mChildTime = 0; + + cur_data = &cur_timer->mLastTimerData; + cur_timer = cur_data->mCurTimer; + } + + // reset all history + { + for (instance_iter it = beginInstances(); it != endInstances(); ++it) + { + NamedTimer& timer = *it; + if (&timer != NamedTimerFactory::instance().getRootTimer()) + { + timer.setParent(NamedTimerFactory::instance().getRootTimer()); + } + + timer.mCountAverage = 0; + timer.mCallAverage = 0; + memset(timer.mCountHistory, 0, sizeof(U32) * HISTORY_NUM); + memset(timer.mCallHistory, 0, sizeof(U32) * HISTORY_NUM); + } + } + + sLastFrameIndex = 0; + sCurFrameIndex = 0; +} + +//static +LLFastTimer::info_list_t& LLFastTimer::getFrameStateList() +{ + if (!sTimerInfos) + { + sTimerInfos = new info_list_t(); + } + return *sTimerInfos; +} + + +U32 LLFastTimer::NamedTimer::getHistoricalCount(S32 history_index) const +{ + S32 history_idx = (getLastFrameIndex() + history_index) % LLFastTimer::NamedTimer::HISTORY_NUM; + return mCountHistory[history_idx]; +} + +U32 LLFastTimer::NamedTimer::getHistoricalCalls(S32 history_index ) const +{ + S32 history_idx = (getLastFrameIndex() + history_index) % LLFastTimer::NamedTimer::HISTORY_NUM; + return mCallHistory[history_idx]; +} + +LLFastTimer::FrameState& LLFastTimer::NamedTimer::getFrameState() const +{ + llassert_always(mFrameStateIndex >= 0); + if (this == NamedTimerFactory::instance().getActiveRootTimer()) + { + return NamedTimerFactory::instance().getRootFrameState(); + } + return getFrameStateList()[mFrameStateIndex]; +} + +// static +LLFastTimer::NamedTimer& LLFastTimer::NamedTimer::getRootNamedTimer() +{ + return *NamedTimerFactory::instance().getActiveRootTimer(); +} + +std::vector::const_iterator LLFastTimer::NamedTimer::beginChildren() +{ + return mChildren.begin(); +} + +std::vector::const_iterator LLFastTimer::NamedTimer::endChildren() +{ + return mChildren.end(); +} + +std::vector& LLFastTimer::NamedTimer::getChildren() +{ + return mChildren; +} + +//static +void LLFastTimer::nextFrame() +{ + countsPerSecond(); // good place to calculate clock frequency + U64 frame_time = getCPUClockCount64(); + if ((frame_time - sLastFrameTime) >> 8 > 0xffffffff) + { + llinfos << "Slow frame, fast timers inaccurate" << llendl; + } + + if (!sPauseHistory) + { + NamedTimer::processTimes(); + sLastFrameIndex = sCurFrameIndex++; + } + + // get ready for next frame + NamedTimer::resetFrame(); + sLastFrameTime = frame_time; +} + +//static +void LLFastTimer::dumpCurTimes() +{ + // accumulate timings, etc. + NamedTimer::processTimes(); + + F64 clock_freq = (F64)countsPerSecond(); + F64 iclock_freq = 1000.0 / clock_freq; // clock_ticks -> milliseconds + + // walk over timers in depth order and output timings + for(timer_tree_dfs_iterator_t it = begin_timer_tree(*NamedTimerFactory::instance().getRootTimer()); + it != end_timer_tree(); + ++it) + { + NamedTimer* timerp = (*it); + F64 total_time_ms = ((F64)timerp->getHistoricalCount(0) * iclock_freq); + // Don't bother with really brief times, keep output concise + if (total_time_ms < 0.1) continue; + + std::ostringstream out_str; + for (S32 i = 0; i < timerp->getDepth(); i++) + { + out_str << "\t"; + } + + + out_str << timerp->getName() << " " + << std::setprecision(3) << total_time_ms << " ms, " + << timerp->getHistoricalCalls(0) << " calls"; + + llinfos << out_str.str() << llendl; + } +} + +//static +void LLFastTimer::reset() +{ + NamedTimer::reset(); +} + + +//static +void LLFastTimer::writeLog(std::ostream& os) +{ + while (!sLogQueue.empty()) + { + LLSD& sd = sLogQueue.front(); + LLSDSerialize::toXML(sd, os); + LLMutexLock lock(sLogLock); + sLogQueue.pop(); + } +} + +//static +const LLFastTimer::NamedTimer* LLFastTimer::getTimerByName(const std::string& name) +{ + return NamedTimerFactory::instance().getTimerByName(name); +} + +LLFastTimer::LLFastTimer(LLFastTimer::FrameState* state) +: mFrameState(state) +{ + U32 start_time = getCPUClockCount32(); + mStartTime = start_time; + mFrameState->mActiveCount++; + LLFastTimer::sCurTimerData.mCurTimer = this; + LLFastTimer::sCurTimerData.mFrameState = mFrameState; + LLFastTimer::sCurTimerData.mChildTime = 0; + mLastTimerData = LLFastTimer::sCurTimerData; +} + + +////////////////////////////////////////////////////////////////////////////// +// +// Important note: These implementations must be FAST! +// + + +//LL_COMMON_API U64 get_clock_count(); // in lltimer.cpp +// These use QueryPerformanceCounter, which is arguably fine and also works on AMD architectures. +U32 LLFastTimer::getCPUClockCount32() +{ + return (U32)(get_clock_count()>>8); +} + +U64 LLFastTimer::getCPUClockCount64() +{ + return get_clock_count(); +} + +#if LL_WINDOWS +std::string LLFastTimer::sClockType = "QueryPerformanceCounter"; +#else +std::string LLFastTimer::sClockType = "gettimeofday"; +#endif + diff --git a/indra/llcommon/llfasttimer_class.h b/indra/llcommon/llfasttimer_class.h new file mode 100644 index 000000000..9e7fdaec6 --- /dev/null +++ b/indra/llcommon/llfasttimer_class.h @@ -0,0 +1,277 @@ +/** + * @file llfasttimer_class.h + * @brief Declaration of a fast timer. + * + * $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_FASTTIMER_CLASS_H +#define LL_FASTTIMER_CLASS_H + +#include "llinstancetracker.h" + +#define FAST_TIMER_ON 1 +#define TIME_FAST_TIMERS 0 +#define DEBUG_FAST_TIMER_THREADS 1 + +class LLMutex; + +#include +#include "llsd.h" + +LL_COMMON_API void assert_main_thread(); + +class LL_COMMON_API LLFastTimer +{ +public: + class NamedTimer; + + struct LL_COMMON_API FrameState + { + FrameState(NamedTimer* timerp); + + U32 mSelfTimeCounter; + U32 mCalls; + FrameState* mParent; // info for caller timer + FrameState* mLastCaller; // used to bootstrap tree construction + NamedTimer* mTimer; + U16 mActiveCount; // number of timers with this ID active on stack + bool mMoveUpTree; // needs to be moved up the tree of timers at the end of frame + }; + + // stores a "named" timer instance to be reused via multiple LLFastTimer stack instances + class LL_COMMON_API NamedTimer + : public LLInstanceTracker + { + friend class DeclareTimer; + public: + ~NamedTimer(); + + enum { HISTORY_NUM = 300 }; + + const std::string& getName() const { return mName; } + NamedTimer* getParent() const { return mParent; } + void setParent(NamedTimer* parent); + S32 getDepth(); + std::string getToolTip(S32 history_index = -1); + + typedef std::vector::const_iterator child_const_iter; + child_const_iter beginChildren(); + child_const_iter endChildren(); + std::vector& getChildren(); + + void setCollapsed(bool collapsed) { mCollapsed = collapsed; } + bool getCollapsed() const { return mCollapsed; } + + U32 getCountAverage() const { return mCountAverage; } + U32 getCallAverage() const { return mCallAverage; } + + U32 getHistoricalCount(S32 history_index = 0) const; + U32 getHistoricalCalls(S32 history_index = 0) const; + + static NamedTimer& getRootNamedTimer(); + + S32 getFrameStateIndex() const { return mFrameStateIndex; } + + FrameState& getFrameState() const; + + private: + friend class LLFastTimer; + friend class NamedTimerFactory; + + // + // methods + // + NamedTimer(const std::string& name); + // recursive call to gather total time from children + static void accumulateTimings(); + + // updates cumulative times and hierarchy, + // can be called multiple times in a frame, at any point + static void processTimes(); + + static void buildHierarchy(); + static void resetFrame(); + static void reset(); + + // + // members + // + S32 mFrameStateIndex; + + std::string mName; + + U32 mTotalTimeCounter; + + U32 mCountAverage; + U32 mCallAverage; + + U32* mCountHistory; + U32* mCallHistory; + + // tree structure + NamedTimer* mParent; // NamedTimer of caller(parent) + std::vector mChildren; + bool mCollapsed; // don't show children + bool mNeedsSorting; // sort children whenever child added + }; + + // used to statically declare a new named timer + class LL_COMMON_API DeclareTimer + : public LLInstanceTracker + { + friend class LLFastTimer; + public: + DeclareTimer(const std::string& name, bool open); + DeclareTimer(const std::string& name); + + static void updateCachedPointers(); + + private: + NamedTimer& mTimer; + FrameState* mFrameState; + }; + +public: + LLFastTimer(LLFastTimer::FrameState* state); + + LL_FORCE_INLINE LLFastTimer(LLFastTimer::DeclareTimer& timer) + : mFrameState(timer.mFrameState) + { +#if TIME_FAST_TIMERS + U64 timer_start = getCPUClockCount64(); +#endif +#if FAST_TIMER_ON + LLFastTimer::FrameState* frame_state = mFrameState; + mStartTime = getCPUClockCount32(); + + frame_state->mActiveCount++; + frame_state->mCalls++; + // keep current parent as long as it is active when we are + frame_state->mMoveUpTree |= (frame_state->mParent->mActiveCount == 0); + + LLFastTimer::CurTimerData* cur_timer_data = &LLFastTimer::sCurTimerData; + mLastTimerData = *cur_timer_data; + cur_timer_data->mCurTimer = this; + cur_timer_data->mFrameState = frame_state; + cur_timer_data->mChildTime = 0; +#endif +#if TIME_FAST_TIMERS + U64 timer_end = getCPUClockCount64(); + sTimerCycles += timer_end - timer_start; +#endif +#if DEBUG_FAST_TIMER_THREADS +#if !LL_RELEASE + assert_main_thread(); +#endif +#endif + } + + LL_FORCE_INLINE ~LLFastTimer() + { +#if TIME_FAST_TIMERS + U64 timer_start = getCPUClockCount64(); +#endif +#if FAST_TIMER_ON + LLFastTimer::FrameState* frame_state = mFrameState; + U32 total_time = getCPUClockCount32() - mStartTime; + + frame_state->mSelfTimeCounter += total_time - LLFastTimer::sCurTimerData.mChildTime; + frame_state->mActiveCount--; + + // store last caller to bootstrap tree creation + // do this in the destructor in case of recursion to get topmost caller + frame_state->mLastCaller = mLastTimerData.mFrameState; + + // we are only tracking self time, so subtract our total time delta from parents + mLastTimerData.mChildTime += total_time; + + LLFastTimer::sCurTimerData = mLastTimerData; +#endif +#if TIME_FAST_TIMERS + U64 timer_end = getCPUClockCount64(); + sTimerCycles += timer_end - timer_start; + sTimerCalls++; +#endif + } + +public: + static LLMutex* sLogLock; + static std::queue sLogQueue; + static BOOL sLog; + static BOOL sMetricLog; + static std::string sLogName; + static bool sPauseHistory; + static bool sResetHistory; + static U64 sTimerCycles; + static U32 sTimerCalls; + + typedef std::vector info_list_t; + static info_list_t& getFrameStateList(); + + + // call this once a frame to reset timers + static void nextFrame(); + + // dumps current cumulative frame stats to log + // call nextFrame() to reset timers + static void dumpCurTimes(); + + // call this to reset timer hierarchy, averages, etc. + static void reset(); + + static U64 countsPerSecond(); + static S32 getLastFrameIndex() { return sLastFrameIndex; } + static S32 getCurFrameIndex() { return sCurFrameIndex; } + + static void writeLog(std::ostream& os); + static const NamedTimer* getTimerByName(const std::string& name); + + struct CurTimerData + { + LLFastTimer* mCurTimer; + FrameState* mFrameState; + U32 mChildTime; + }; + static CurTimerData sCurTimerData; + static std::string sClockType; + +public: + static U32 getCPUClockCount32(); + static U64 getCPUClockCount64(); + static U64 sClockResolution; + +private: + static S32 sCurFrameIndex; + static S32 sLastFrameIndex; + static U64 sLastFrameTime; + static info_list_t* sTimerInfos; + + U32 mStartTime; + LLFastTimer::FrameState* mFrameState; + LLFastTimer::CurTimerData mLastTimerData; + +}; + +typedef class LLFastTimer LLFastTimer; + +#endif // LL_LLFASTTIMER_H diff --git a/indra/llcommon/llptrto.cpp b/indra/llcommon/llptrto.cpp new file mode 100644 index 000000000..b270291bd --- /dev/null +++ b/indra/llcommon/llptrto.cpp @@ -0,0 +1,102 @@ +/** + * @file llptrto.cpp + * @author Nat Goodspeed + * @date 2008-08-20 + * @brief Test for llptrto.h + * + * $LicenseInfo:firstyear=2008&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 "llptrto.h" +// STL headers +// std headers +// external library headers +#include +#include +// other Linden headers +#include "llmemory.h" + +// a refcounted class +class RCFoo: public LLRefCount +{ +public: + RCFoo() {} +}; + +// a refcounted subclass +class RCSubFoo: public RCFoo +{ +public: + RCSubFoo() {} +}; + +// a refcounted class using the other refcount base class +class TSRCFoo: public LLThreadSafeRefCount +{ +public: + TSRCFoo() {} +}; + +// a non-refcounted class +class Bar +{ +public: + Bar() {} +}; + +// a non-refcounted subclass +class SubBar: public Bar +{ +public: + SubBar() {} +}; + +int main(int argc, char *argv[]) +{ + // test LLPtrTo<> + BOOST_STATIC_ASSERT((boost::is_same::type, LLPointer >::value)); + BOOST_STATIC_ASSERT((boost::is_same::type, LLPointer >::value)); + BOOST_STATIC_ASSERT((boost::is_same::type, LLPointer >::value)); + BOOST_STATIC_ASSERT((boost::is_same::type, Bar*>::value)); + BOOST_STATIC_ASSERT((boost::is_same::type, SubBar*>::value)); + BOOST_STATIC_ASSERT((boost::is_same::type, int*>::value)); + + // Test LLRemovePointer<>. Note that we remove both pointer variants from + // each kind of type, regardless of whether the variant makes sense. + BOOST_STATIC_ASSERT((boost::is_same::type, RCFoo>::value)); + BOOST_STATIC_ASSERT((boost::is_same >::type, RCFoo>::value)); + BOOST_STATIC_ASSERT((boost::is_same::type, RCSubFoo>::value)); + BOOST_STATIC_ASSERT((boost::is_same >::type, RCSubFoo>::value)); + BOOST_STATIC_ASSERT((boost::is_same::type, TSRCFoo>::value)); + BOOST_STATIC_ASSERT((boost::is_same >::type, TSRCFoo>::value)); + BOOST_STATIC_ASSERT((boost::is_same::type, Bar>::value)); + BOOST_STATIC_ASSERT((boost::is_same >::type, Bar>::value)); + BOOST_STATIC_ASSERT((boost::is_same::type, SubBar>::value)); + BOOST_STATIC_ASSERT((boost::is_same >::type, SubBar>::value)); + BOOST_STATIC_ASSERT((boost::is_same::type, int>::value)); + BOOST_STATIC_ASSERT((boost::is_same >::type, int>::value)); + + return 0; +} diff --git a/indra/llcommon/llptrto.h b/indra/llcommon/llptrto.h new file mode 100644 index 000000000..7091d36f6 --- /dev/null +++ b/indra/llcommon/llptrto.h @@ -0,0 +1,87 @@ +/** + * @file llptrto.h + * @author Nat Goodspeed + * @date 2008-08-19 + * @brief LLPtrTo is a template helper to pick either TARGET* or -- when + * TARGET is a subclass of LLRefCount or LLThreadSafeRefCount -- + * LLPointer. LLPtrTo<> chooses whichever pointer type is best. + * + * $LicenseInfo:firstyear=2008&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$ + */ + +#if ! defined(LL_LLPTRTO_H) +#define LL_LLPTRTO_H + +#include "llpointer.h" +#include "llrefcount.h" // LLRefCount +#include "llthread.h" // LLThreadSafeRefCount +#include +#include +#include + +/** + * LLPtrTo::type is either of two things: + * + * * When TARGET is a subclass of either LLRefCount or LLThreadSafeRefCount, + * LLPtrTo::type is LLPointer. + * * Otherwise, LLPtrTo::type is TARGET*. + * + * This way, a class template can use LLPtrTo::type to select an + * appropriate pointer type to store. + */ +template +struct LLPtrTo +{ + typedef T* type; +}; + +/// specialize for subclasses of LLRefCount +template +struct LLPtrTo >::type> +{ + typedef LLPointer type; +}; + +/// specialize for subclasses of LLThreadSafeRefCount +template +struct LLPtrTo >::type> +{ + typedef LLPointer type; +}; + +/** + * LLRemovePointer::type gets you the underlying (pointee) type. + */ +template +struct LLRemovePointer +{ + typedef typename boost::remove_pointer::type type; +}; + +/// specialize for LLPointer +template +struct LLRemovePointer< LLPointer > +{ + typedef SOMECLASS type; +}; + +#endif /* ! defined(LL_LLPTRTO_H) */ diff --git a/indra/llcommon/llstring.cpp b/indra/llcommon/llstring.cpp index 27bbf7e98..f9128b574 100644 --- a/indra/llcommon/llstring.cpp +++ b/indra/llcommon/llstring.cpp @@ -43,6 +43,9 @@ #include // for WideCharToMultiByte #endif +LLFastTimer::DeclareTimer FT_STRING_FORMAT("String Format"); + + std::string ll_safe_string(const char* in) { if(in) return std::string(in); @@ -1196,7 +1199,7 @@ bool LLStringUtil::formatDatetime(std::string& replacement, std::string token, template<> S32 LLStringUtil::format(std::string& s, const format_map_t& substitutions) { - LLFastTimer ft(LLFastTimer::FT_STRING_FORMAT); + LLFastTimer ft(FT_STRING_FORMAT); S32 res = 0; std::string output; @@ -1269,7 +1272,7 @@ S32 LLStringUtil::format(std::string& s, const format_map_t& substitutions) template<> S32 LLStringUtil::format(std::string& s, const LLSD& substitutions) { - LLFastTimer ft(LLFastTimer::FT_STRING_FORMAT); + LLFastTimer ft(FT_STRING_FORMAT); S32 res = 0; if (!substitutions.isMap()) diff --git a/indra/llmath/llmath.h b/indra/llmath/llmath.h index 89ef7d616..9842f4da1 100644 --- a/indra/llmath/llmath.h +++ b/indra/llmath/llmath.h @@ -531,13 +531,13 @@ inline void ll_remove_outliers(std::vector& data, F32 k) i++; } - S32 j = data.size()-1; + S32 j = (S32)data.size()-1; while (j > 0 && data[j] > max) { j--; } - if (j < data.size()-1) + if (j < (S32)data.size()-1) { data.erase(data.begin()+j, data.end()); } diff --git a/indra/llmath/v4coloru.h b/indra/llmath/v4coloru.h index 8b7df774e..1324b49df 100644 --- a/indra/llmath/v4coloru.h +++ b/indra/llmath/v4coloru.h @@ -57,8 +57,8 @@ public: { U8 mV[LENGTHOFCOLOR4U]; U32 mAll; - LLColor4* mSources; - LLColor4U* mSourcesU; + //LLColor4* mSources; + //LLColor4U* mSourcesU; }; diff --git a/indra/llmessage/llfiltersd2xmlrpc.cpp b/indra/llmessage/llfiltersd2xmlrpc.cpp index 0560a319b..6d13e8f73 100644 --- a/indra/llmessage/llfiltersd2xmlrpc.cpp +++ b/indra/llmessage/llfiltersd2xmlrpc.cpp @@ -91,6 +91,8 @@ #include "llsdserialize.h" #include "lluuid.h" +#include "llfasttimer.h" + // spammy mode //#define LL_SPEW_STREAM_OUT_DEBUGGING 1 @@ -314,6 +316,7 @@ LLFilterSD2XMLRPCResponse::~LLFilterSD2XMLRPCResponse() } +static LLFastTimer::DeclareTimer FTM_PROCESS_SD2XMLRPC_RESPONSE("SD2XMLRPC Response"); // virtual LLIOPipe::EStatus LLFilterSD2XMLRPCResponse::process_impl( const LLChannelDescriptors& channels, @@ -322,6 +325,8 @@ LLIOPipe::EStatus LLFilterSD2XMLRPCResponse::process_impl( LLSD& context, LLPumpIO* pump) { + LLFastTimer t(FTM_PROCESS_SD2XMLRPC_RESPONSE); + PUMP_DEBUG; // This pipe does not work if it does not have everyting. This // could be addressed by making a stream parser for llsd which @@ -388,6 +393,8 @@ LLFilterSD2XMLRPCRequest::~LLFilterSD2XMLRPCRequest() { } +static LLFastTimer::DeclareTimer FTM_PROCESS_SD2XMLRPC_REQUEST("S22XMLRPC Request"); + // virtual LLIOPipe::EStatus LLFilterSD2XMLRPCRequest::process_impl( const LLChannelDescriptors& channels, @@ -396,6 +403,7 @@ LLIOPipe::EStatus LLFilterSD2XMLRPCRequest::process_impl( LLSD& context, LLPumpIO* pump) { + LLFastTimer t(FTM_PROCESS_SD2XMLRPC_REQUEST); // This pipe does not work if it does not have everyting. This // could be addressed by making a stream parser for llsd which // handled partial information. @@ -592,6 +600,8 @@ LLFilterXMLRPCResponse2LLSD::~LLFilterXMLRPCResponse2LLSD() { } +static LLFastTimer::DeclareTimer FTM_PROCESS_XMLRPC2LLSD_RESPONSE("XMLRPC2LLSD Response"); + LLIOPipe::EStatus LLFilterXMLRPCResponse2LLSD::process_impl( const LLChannelDescriptors& channels, buffer_ptr_t& buffer, @@ -599,6 +609,8 @@ LLIOPipe::EStatus LLFilterXMLRPCResponse2LLSD::process_impl( LLSD& context, LLPumpIO* pump) { + LLFastTimer t(FTM_PROCESS_XMLRPC2LLSD_RESPONSE); + PUMP_DEBUG; if(!eos) return STATUS_BREAK; if(!buffer) return STATUS_ERROR; @@ -674,6 +686,7 @@ LLFilterXMLRPCRequest2LLSD::~LLFilterXMLRPCRequest2LLSD() { } +static LLFastTimer::DeclareTimer FTM_PROCESS_XMLRPC2LLSD_REQUEST("XMLRPC2LLSD Request"); LLIOPipe::EStatus LLFilterXMLRPCRequest2LLSD::process_impl( const LLChannelDescriptors& channels, buffer_ptr_t& buffer, @@ -681,6 +694,7 @@ LLIOPipe::EStatus LLFilterXMLRPCRequest2LLSD::process_impl( LLSD& context, LLPumpIO* pump) { + LLFastTimer t(FTM_PROCESS_XMLRPC2LLSD_REQUEST); PUMP_DEBUG; if(!eos) return STATUS_BREAK; if(!buffer) return STATUS_ERROR; diff --git a/indra/llmessage/lliohttpserver.cpp b/indra/llmessage/lliohttpserver.cpp index a659027ad..eb9fd80b8 100644 --- a/indra/llmessage/lliohttpserver.cpp +++ b/indra/llmessage/lliohttpserver.cpp @@ -51,6 +51,7 @@ #include "llstat.h" #include "llstl.h" #include "lltimer.h" +#include "llfasttimer.h" #include @@ -146,6 +147,7 @@ private: LLSD mHeaders; }; +static LLFastTimer::DeclareTimer FTM_PROCESS_HTTP_PIPE("HTTP Pipe"); LLIOPipe::EStatus LLHTTPPipe::process_impl( const LLChannelDescriptors& channels, buffer_ptr_t& buffer, @@ -153,6 +155,7 @@ LLIOPipe::EStatus LLHTTPPipe::process_impl( LLSD& context, LLPumpIO* pump) { + LLFastTimer t(FTM_PROCESS_HTTP_PIPE); PUMP_DEBUG; lldebugs << "LLSDHTTPServer::process_impl" << llendl; @@ -434,6 +437,9 @@ protected: /** * LLHTTPResponseHeader */ + +static LLFastTimer::DeclareTimer FTM_PROCESS_HTTP_HEADER("HTTP Header"); + // virtual LLIOPipe::EStatus LLHTTPResponseHeader::process_impl( const LLChannelDescriptors& channels, @@ -442,6 +448,7 @@ LLIOPipe::EStatus LLHTTPResponseHeader::process_impl( LLSD& context, LLPumpIO* pump) { + LLFastTimer t(FTM_PROCESS_HTTP_HEADER); PUMP_DEBUG; LLMemType m1(LLMemType::MTYPE_IO_HTTP_SERVER); if(eos) @@ -636,6 +643,8 @@ void LLHTTPResponder::markBad( << "\n\n"; } +static LLFastTimer::DeclareTimer FTM_PROCESS_HTTP_RESPONDER("HTTP Responder"); + // virtual LLIOPipe::EStatus LLHTTPResponder::process_impl( const LLChannelDescriptors& channels, @@ -644,6 +653,7 @@ LLIOPipe::EStatus LLHTTPResponder::process_impl( LLSD& context, LLPumpIO* pump) { + LLFastTimer t(FTM_PROCESS_HTTP_RESPONDER); PUMP_DEBUG; LLMemType m1(LLMemType::MTYPE_IO_HTTP_SERVER); LLIOPipe::EStatus status = STATUS_OK; diff --git a/indra/llmessage/lliosocket.cpp b/indra/llmessage/lliosocket.cpp index 774950162..d80ca402c 100644 --- a/indra/llmessage/lliosocket.cpp +++ b/indra/llmessage/lliosocket.cpp @@ -42,6 +42,7 @@ #include "llmemtype.h" #include "llpumpio.h" #include "llthread.h" +#include "llfasttimer.h" // // constants @@ -290,6 +291,8 @@ LLIOSocketReader::~LLIOSocketReader() //lldebugs << "Destroying LLIOSocketReader" << llendl; } +static LLFastTimer::DeclareTimer FTM_PROCESS_SOCKET_READER("Socket Reader"); + // virtual LLIOPipe::EStatus LLIOSocketReader::process_impl( const LLChannelDescriptors& channels, @@ -298,6 +301,7 @@ LLIOPipe::EStatus LLIOSocketReader::process_impl( LLSD& context, LLPumpIO* pump) { + LLFastTimer t(FTM_PROCESS_SOCKET_READER); PUMP_DEBUG; LLMemType m1(LLMemType::MTYPE_IO_TCP); if(!mSource) return STATUS_PRECONDITION_NOT_MET; @@ -390,6 +394,7 @@ LLIOSocketWriter::~LLIOSocketWriter() //lldebugs << "Destroying LLIOSocketWriter" << llendl; } +static LLFastTimer::DeclareTimer FTM_PROCESS_SOCKET_WRITER("Socket Writer"); // virtual LLIOPipe::EStatus LLIOSocketWriter::process_impl( const LLChannelDescriptors& channels, @@ -398,6 +403,7 @@ LLIOPipe::EStatus LLIOSocketWriter::process_impl( LLSD& context, LLPumpIO* pump) { + LLFastTimer t(FTM_PROCESS_SOCKET_WRITER); PUMP_DEBUG; LLMemType m1(LLMemType::MTYPE_IO_TCP); if(!mDestination) return STATUS_PRECONDITION_NOT_MET; @@ -542,6 +548,7 @@ void LLIOServerSocket::setResponseTimeout(F32 timeout_secs) mResponseTimeout = timeout_secs; } +static LLFastTimer::DeclareTimer FTM_PROCESS_SERVER_SOCKET("Server Socket"); // virtual LLIOPipe::EStatus LLIOServerSocket::process_impl( const LLChannelDescriptors& channels, @@ -550,6 +557,7 @@ LLIOPipe::EStatus LLIOServerSocket::process_impl( LLSD& context, LLPumpIO* pump) { + LLFastTimer t(FTM_PROCESS_SERVER_SOCKET); PUMP_DEBUG; LLMemType m1(LLMemType::MTYPE_IO_TCP); if(!pump) diff --git a/indra/llmessage/llioutil.cpp b/indra/llmessage/llioutil.cpp index d282a7d2e..25d5759a2 100644 --- a/indra/llmessage/llioutil.cpp +++ b/indra/llmessage/llioutil.cpp @@ -34,6 +34,7 @@ #include "linden_common.h" #include "llioutil.h" +#include "llfasttimer.h" /** * LLIOFlush @@ -49,6 +50,8 @@ LLIOPipe::EStatus LLIOFlush::process_impl( return STATUS_OK; } + +static LLFastTimer::DeclareTimer FTM_PROCESS_SLEEP("IO Sleep"); /** * @class LLIOSleep */ @@ -59,6 +62,7 @@ LLIOPipe::EStatus LLIOSleep::process_impl( LLSD& context, LLPumpIO* pump) { + LLFastTimer t(FTM_PROCESS_SLEEP); if(mSeconds > 0.0) { if(pump) pump->sleepChain(mSeconds); @@ -68,6 +72,7 @@ LLIOPipe::EStatus LLIOSleep::process_impl( return STATUS_DONE; } +static LLFastTimer::DeclareTimer FTM_PROCESS_ADD_CHAIN("Add Chain"); /** * @class LLIOAddChain */ @@ -78,6 +83,7 @@ LLIOPipe::EStatus LLIOAddChain::process_impl( LLSD& context, LLPumpIO* pump) { + LLFastTimer t(FTM_PROCESS_ADD_CHAIN); pump->addChain(mChain, mTimeout); return STATUS_DONE; } diff --git a/indra/llmessage/llpumpio.cpp b/indra/llmessage/llpumpio.cpp index d9dc8789c..48e581c64 100644 --- a/indra/llmessage/llpumpio.cpp +++ b/indra/llmessage/llpumpio.cpp @@ -191,18 +191,7 @@ LLPumpIO::LLPumpIO(void) : LLPumpIO::~LLPumpIO() { LLMemType m1(LLMemType::MTYPE_IO_PUMP); -#if LL_THREADS_APR - if (mChainsMutex) apr_thread_mutex_destroy(mChainsMutex); - if (mCallbackMutex) apr_thread_mutex_destroy(mCallbackMutex); -#endif - mChainsMutex = NULL; - mCallbackMutex = NULL; - if(mPollset) - { -// lldebugs << "cleaning up pollset" << llendl; - apr_pollset_destroy(mPollset); - mPollset = NULL; - } + cleanup(); } bool LLPumpIO::addChain(const chain_t& chain, F32 timeout) @@ -447,11 +436,13 @@ void LLPumpIO::pump() pump(DEFAULT_POLL_TIMEOUT); } +static LLFastTimer::DeclareTimer FTM_PUMP_IO("Pump IO"); + //timeout is in microseconds void LLPumpIO::pump(const S32& poll_timeout) { LLMemType m1(LLMemType::MTYPE_IO_PUMP); - LLFastTimer t1(LLFastTimer::FTM_PUMPIO); + LLFastTimer t1(FTM_PUMP_IO); //llinfos << "LLPumpIO::pump()" << llendl; // Run any pending runners. @@ -779,6 +770,8 @@ bool LLPumpIO::respond( return true; } +static LLFastTimer::DeclareTimer FTM_PUMP_CALLBACK_CHAIN("Chain"); + void LLPumpIO::callback() { LLMemType m1(LLMemType::MTYPE_IO_PUMP); @@ -800,6 +793,7 @@ void LLPumpIO::callback() callbacks_t::iterator end = mCallbacks.end(); for(; it != end; ++it) { + LLFastTimer t(FTM_PUMP_CALLBACK_CHAIN); // it's always the first and last time for respone chains (*it).mHead = (*it).mChainLinks.begin(); (*it).mInit = true; @@ -839,6 +833,22 @@ void LLPumpIO::initialize(void) apr_thread_mutex_create(&mCallbackMutex, APR_THREAD_MUTEX_UNNESTED, mPool()); #endif } +void LLPumpIO::cleanup() +{ + LLMemType m1(LLMemType::MTYPE_IO_PUMP); +#if LL_THREADS_APR + if (mChainsMutex) apr_thread_mutex_destroy(mChainsMutex); + if (mCallbackMutex) apr_thread_mutex_destroy(mCallbackMutex); +#endif + mChainsMutex = NULL; + mCallbackMutex = NULL; + if(mPollset) + { +// lldebugs << "cleaning up pollset" << llendl; + apr_pollset_destroy(mPollset); + mPollset = NULL; + } +} void LLPumpIO::rebuildPollset() { diff --git a/indra/llmessage/llpumpio.h b/indra/llmessage/llpumpio.h index 0009a08f9..4e6d59b39 100644 --- a/indra/llmessage/llpumpio.h +++ b/indra/llmessage/llpumpio.h @@ -397,6 +397,7 @@ protected: protected: void initialize(); + void cleanup(); /** * @brief Given the internal state of the chains, rebuild the pollset diff --git a/indra/llmessage/llsdrpcclient.cpp b/indra/llmessage/llsdrpcclient.cpp index 3f36d238c..471369671 100644 --- a/indra/llmessage/llsdrpcclient.cpp +++ b/indra/llmessage/llsdrpcclient.cpp @@ -42,6 +42,7 @@ #include "llsd.h" #include "llsdserialize.h" #include "llurlrequest.h" +#include "llfasttimer.h" /** * String constants @@ -88,6 +89,8 @@ bool LLSDRPCResponse::extractResponse(const LLSD& sd) return rv; } +static LLFastTimer::DeclareTimer FTM_SDRPC_RESPONSE("SDRPC Response"); + // virtual LLIOPipe::EStatus LLSDRPCResponse::process_impl( const LLChannelDescriptors& channels, @@ -96,6 +99,7 @@ LLIOPipe::EStatus LLSDRPCResponse::process_impl( LLSD& context, LLPumpIO* pump) { + LLFastTimer t(FTM_SDRPC_RESPONSE); PUMP_DEBUG; LLMemType m1(LLMemType::MTYPE_IO_SD_CLIENT); if(mIsError) @@ -184,6 +188,8 @@ bool LLSDRPCClient::call( return true; } +static LLFastTimer::DeclareTimer FTM_PROCESS_SDRPC_CLIENT("SDRPC Client"); + // virtual LLIOPipe::EStatus LLSDRPCClient::process_impl( const LLChannelDescriptors& channels, @@ -192,6 +198,7 @@ LLIOPipe::EStatus LLSDRPCClient::process_impl( LLSD& context, LLPumpIO* pump) { + LLFastTimer t(FTM_PROCESS_SDRPC_CLIENT); PUMP_DEBUG; LLMemType m1(LLMemType::MTYPE_IO_SD_CLIENT); if((STATE_NONE == mState) || (!pump)) diff --git a/indra/llmessage/llsdrpcserver.cpp b/indra/llmessage/llsdrpcserver.cpp index 0c92e7ddd..4fc95eff0 100644 --- a/indra/llmessage/llsdrpcserver.cpp +++ b/indra/llmessage/llsdrpcserver.cpp @@ -41,6 +41,7 @@ #include "llpumpio.h" #include "llsdserialize.h" #include "llstl.h" +#include "llfasttimer.h" static const char FAULT_PART_1[] = "{'fault':{'code':i"; static const char FAULT_PART_2[] = ", 'description':'"; @@ -103,6 +104,8 @@ void LLSDRPCServer::clearLock() } } +static LLFastTimer::DeclareTimer FTM_PROCESS_SDRPC_SERVER("SDRPC Server"); + // virtual LLIOPipe::EStatus LLSDRPCServer::process_impl( const LLChannelDescriptors& channels, @@ -111,6 +114,7 @@ LLIOPipe::EStatus LLSDRPCServer::process_impl( LLSD& context, LLPumpIO* pump) { + LLFastTimer t(FTM_PROCESS_SDRPC_SERVER); PUMP_DEBUG; LLMemType m1(LLMemType::MTYPE_IO_SD_SERVER); // lldebugs << "LLSDRPCServer::process_impl" << llendl; diff --git a/indra/llmessage/lltemplatemessagereader.cpp b/indra/llmessage/lltemplatemessagereader.cpp index 3bcbb070e..9c5ce1534 100644 --- a/indra/llmessage/lltemplatemessagereader.cpp +++ b/indra/llmessage/lltemplatemessagereader.cpp @@ -544,6 +544,7 @@ void LLTemplateMessageReader::logRanOffEndOfPacket( const LLHost& host, const S3 gMessageSystem->callExceptionFunc(MX_RAN_OFF_END_OF_PACKET); } +static LLFastTimer::DeclareTimer FTM_PROCESS_MESSAGES("Process Messages"); // decode a given message //BOOL LLTemplateMessageReader::decodeData(const U8* buffer, const LLHost& sender ) BOOL LLTemplateMessageReader::decodeData(const U8* buffer, const LLHost& sender, BOOL custom) @@ -736,7 +737,7 @@ BOOL LLTemplateMessageReader::decodeData(const U8* buffer, const LLHost& sender, } { - LLFastTimer t(LLFastTimer::FTM_PROCESS_MESSAGES); + LLFastTimer t(FTM_PROCESS_MESSAGES); if( !mCurrentRMessageTemplate->callHandlerFunc(gMessageSystem) ) { llwarns << "Message from " << sender << " with no handler function received: " << mCurrentRMessageTemplate->mName << llendl; diff --git a/indra/llmessage/llurlrequest.cpp b/indra/llmessage/llurlrequest.cpp index e204eaf2f..bc0fe04bf 100644 --- a/indra/llmessage/llurlrequest.cpp +++ b/indra/llmessage/llurlrequest.cpp @@ -46,6 +46,7 @@ #include "apr_env.h" #include "llapr.h" #include "llscopedvolatileaprpool.h" +#include "llfasttimer.h" static const U32 HTTP_STATUS_PIPE_ERROR = 499; /** @@ -143,6 +144,7 @@ LLURLRequest::~LLURLRequest() { LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST); delete mDetail; + mDetail = NULL ; } void LLURLRequest::setURL(const std::string& url) @@ -253,6 +255,8 @@ LLIOPipe::EStatus LLURLRequest::handleError( return status; } +static LLFastTimer::DeclareTimer FTM_PROCESS_URL_REQUEST("URL Request"); + // virtual LLIOPipe::EStatus LLURLRequest::process_impl( const LLChannelDescriptors& channels, @@ -261,6 +265,7 @@ LLIOPipe::EStatus LLURLRequest::process_impl( LLSD& context, LLPumpIO* pump) { + LLFastTimer t(FTM_PROCESS_URL_REQUEST); PUMP_DEBUG; LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST); //llinfos << "LLURLRequest::process_impl()" << llendl; @@ -272,6 +277,8 @@ LLIOPipe::EStatus LLURLRequest::process_impl( const S32 MIN_ACCUMULATION = 100000; if(pump && (mDetail->mByteAccumulator > MIN_ACCUMULATION)) { + static LLFastTimer::DeclareTimer FTM_URL_ADJUST_TIMEOUT("Adjust Timeout"); + LLFastTimer t(FTM_URL_ADJUST_TIMEOUT); // This is a pretty sloppy calculation, but this // tries to make the gross assumption that if data // is coming in at 56kb/s, then this transfer will @@ -319,16 +326,30 @@ LLIOPipe::EStatus LLURLRequest::process_impl( { PUMP_DEBUG; LLIOPipe::EStatus status = STATUS_BREAK; - mDetail->mCurlRequest->perform(); + static LLFastTimer::DeclareTimer FTM_URL_PERFORM("Perform"); + { + LLFastTimer t(FTM_URL_PERFORM); + mDetail->mCurlRequest->perform(); + } + while(1) { CURLcode result; - bool newmsg = mDetail->mCurlRequest->getResult(&result); + + static LLFastTimer::DeclareTimer FTM_PROCESS_URL_REQUEST_GET_RESULT("Get Result"); + + bool newmsg = false; + { + LLFastTimer t(FTM_PROCESS_URL_REQUEST_GET_RESULT); + newmsg = mDetail->mCurlRequest->getResult(&result); + } + if(!newmsg) { // keep processing break; } + mState = STATE_HAVE_RESPONSE; context[CONTEXT_REQUEST][CONTEXT_TRANSFERED_BYTES] = mRequestTransferedBytes; @@ -354,7 +375,11 @@ LLIOPipe::EStatus LLURLRequest::process_impl( link.mChannels = LLBufferArray::makeChannelConsumer( channels); chain.push_back(link); - pump->respond(chain, buffer, context); + static LLFastTimer::DeclareTimer FTM_PROCESS_URL_PUMP_RESPOND("Pump Respond"); + { + LLFastTimer t(FTM_PROCESS_URL_PUMP_RESPOND); + pump->respond(chain, buffer, context); + } mCompletionCallback = NULL; } break; @@ -406,8 +431,11 @@ void LLURLRequest::initialize() mResponseTransferedBytes = 0; } +static LLFastTimer::DeclareTimer FTM_URL_REQUEST_CONFIGURE("URL Configure"); bool LLURLRequest::configure() { + LLFastTimer t(FTM_URL_REQUEST_CONFIGURE); + LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST); bool rv = false; S32 bytes = mDetail->mResponseBuffer->countAfter( @@ -608,6 +636,7 @@ static size_t headerCallback(void* data, size_t size, size_t nmemb, void* user) return header_len; } +static LLFastTimer::DeclareTimer FTM_PROCESS_URL_EXTRACTOR("URL Extractor"); /** * LLContextURLExtractor */ @@ -619,6 +648,7 @@ LLIOPipe::EStatus LLContextURLExtractor::process_impl( LLSD& context, LLPumpIO* pump) { + LLFastTimer t(FTM_PROCESS_URL_EXTRACTOR); PUMP_DEBUG; LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST); // The destination host is in the context. @@ -697,6 +727,7 @@ void LLURLRequestComplete::responseStatus(LLIOPipe::EStatus status) mRequestStatus = status; } +static LLFastTimer::DeclareTimer FTM_PROCESS_URL_COMPLETE("URL Complete"); // virtual LLIOPipe::EStatus LLURLRequestComplete::process_impl( const LLChannelDescriptors& channels, @@ -705,6 +736,7 @@ LLIOPipe::EStatus LLURLRequestComplete::process_impl( LLSD& context, LLPumpIO* pump) { + LLFastTimer t(FTM_PROCESS_URL_COMPLETE); PUMP_DEBUG; complete(channels, buffer); return STATUS_OK; diff --git a/indra/llrender/llfontgl.cpp b/indra/llrender/llfontgl.cpp index 1c79ab2e9..2148f6d94 100644 --- a/indra/llrender/llfontgl.cpp +++ b/indra/llrender/llfontgl.cpp @@ -158,6 +158,8 @@ BOOL LLFontGL::addChar(const llwchar wch) const return TRUE; } +static LLFastTimer::DeclareTimer FTM_RENDER_FONTS("Fonts"); + S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, const LLRect& rect, const LLColor4 &color, HAlign halign, VAlign valign, U8 style, ShadowType shadow, S32 max_chars, F32* right_x, BOOL use_embedded, BOOL use_ellipses) const { @@ -186,6 +188,8 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, const LLRect& rect S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, const LLColor4 &color, HAlign halign, VAlign valign, U8 style, ShadowType shadow, S32 max_chars, S32 max_pixels, F32* right_x, BOOL use_embedded, BOOL use_ellipses) const { + LLFastTimer _(FTM_RENDER_FONTS); + if(!sDisplayFont) //do not display texts { return wstr.length() ; @@ -224,7 +228,6 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons F32 pixel_offset_y = llround((F32)sCurOrigin.mY) - (sCurOrigin.mY); gGL.translatef(-pixel_offset_x, -pixel_offset_y, 0.f); - LLFastTimer t(LLFastTimer::FTM_RENDER_FONTS); gGL.color4fv( color.mV ); diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index 9cb9a2dcd..5c04d6e82 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -676,19 +676,19 @@ void LLImageGL::setImage(const LLImageRaw* imageraw) void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) { -// LLFastTimer t1(LLFastTimer::FTM_TEMP1); +// LLFastTimer t1(FTM_TEMP1); bool is_compressed = false; if (mFormatPrimary >= GL_COMPRESSED_RGBA_S3TC_DXT1_EXT && mFormatPrimary <= GL_COMPRESSED_RGBA_S3TC_DXT5_EXT) { is_compressed = true; } -// LLFastTimer t2(LLFastTimer::FTM_TEMP2); +// LLFastTimer t2(FTM_TEMP2); llverify(gGL.getTexUnit(0)->bind(this)); if (mUseMipMaps) { -// LLFastTimer t2(LLFastTimer::FTM_TEMP3); +// LLFastTimer t2(FTM_TEMP3); if (data_hasmips) { // NOTE: data_in points to largest image; smaller images @@ -705,14 +705,14 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) } if (is_compressed) { -// LLFastTimer t2(LLFastTimer::FTM_TEMP4); +// LLFastTimer t2(FTM_TEMP4); S32 tex_size = dataFormatBytes(mFormatPrimary, w, h); glCompressedTexImage2DARB(mTarget, gl_level, mFormatPrimary, w, h, 0, tex_size, (GLvoid *)data_in); stop_glerror(); } else { -// LLFastTimer t2(LLFastTimer::FTM_TEMP4); +// LLFastTimer t2(FTM_TEMP4); if(mFormatSwapBytes) { @@ -748,7 +748,7 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) } stop_glerror(); { -// LLFastTimer t2(LLFastTimer::FTM_TEMP4); +// LLFastTimer t2(FTM_TEMP4); if(mFormatSwapBytes) { @@ -814,7 +814,7 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) } llassert(w > 0 && h > 0 && cur_mip_data); { -// LLFastTimer t1(LLFastTimer::FTM_TEMP4); +// LLFastTimer t1(FTM_TEMP4); if(mFormatSwapBytes) { glPixelStorei(GL_UNPACK_SWAP_BYTES, 1); @@ -862,7 +862,7 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) } else { -// LLFastTimer t2(LLFastTimer::FTM_TEMP5); +// LLFastTimer t2(FTM_TEMP5); S32 w = getWidth(); S32 h = getHeight(); if (is_compressed) diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp index 133614e0d..5eec0c553 100644 --- a/indra/llrender/llrender.cpp +++ b/indra/llrender/llrender.cpp @@ -1446,8 +1446,6 @@ void LLRender::loadIdentity() flush(); { - llassert_always(mMatrixMode < NUM_MATRIX_MODES) ; - mMatrix[mMatrixMode][mMatIdx[mMatrixMode]].make_identity(); mMatHash[mMatrixMode]++; } diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp index 51543c924..d183d95de 100644 --- a/indra/llrender/llvertexbuffer.cpp +++ b/indra/llrender/llvertexbuffer.cpp @@ -2,31 +2,25 @@ * @file llvertexbuffer.cpp * @brief LLVertexBuffer implementation * - * $LicenseInfo:firstyear=2003&license=viewergpl$ - * - * Copyright (c) 2003-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2003&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -44,6 +38,7 @@ #include "llshadermgr.h" #include "llglslshader.h" #include "llmemory.h" +#include "llfasttimer.h" //Next Highest Power Of Two //helper function, returns first number > v that is a power of 2, or v if v is already a power of 2 @@ -155,7 +150,7 @@ U32 wpo2(U32 i) return r; } -U8* LLVBOPool::allocate(U32& name, U32 size) +volatile U8* LLVBOPool::allocate(U32& name, U32 size) { llassert(nhpo2(size) == size); @@ -166,20 +161,24 @@ U8* LLVBOPool::allocate(U32& name, U32 size) mFreeList.resize(i+1); } - U8* ret = NULL; + volatile U8* ret = NULL; if (mFreeList[i].empty()) { //make a new buffer glGenBuffersARB(1, &name); glBindBufferARB(mType, name); - glBufferDataARB(mType, size, 0, mUsage); LLVertexBuffer::sAllocatedBytes += size; - if (LLVertexBuffer::sDisableVBOMapping) + if (LLVertexBuffer::sDisableVBOMapping || mUsage != GL_DYNAMIC_DRAW_ARB) { + glBufferDataARB(mType, size, 0, mUsage); ret = (U8*) ll_aligned_malloc_16(size); } + else + { //always use a true hint of static draw when allocating non-client-backed buffers + glBufferDataARB(mType, size, 0, GL_STATIC_DRAW_ARB); + } glBindBufferARB(mType, 0); } else @@ -195,7 +194,7 @@ U8* LLVBOPool::allocate(U32& name, U32 size) return ret; } -void LLVBOPool::release(U32 name, U8* buffer, U32 size) +void LLVBOPool::release(U32 name, volatile U8* buffer, U32 size) { llassert(nhpo2(size) == size); @@ -208,8 +207,15 @@ void LLVBOPool::release(U32 name, U8* buffer, U32 size) rec.mClientData = buffer; sBytesPooled += size; - - mFreeList[i].push_back(rec); + + if (!LLVertexBuffer::sDisableVBOMapping && mUsage == GL_DYNAMIC_DRAW_ARB) + { + glDeleteBuffersARB(1, &rec.mGLName); + } + else + { + mFreeList[i].push_back(rec); + } } void LLVBOPool::cleanup() @@ -228,7 +234,7 @@ void LLVBOPool::cleanup() if (r.mClientData) { - ll_aligned_free_16(r.mClientData); + ll_aligned_free_16((void*) r.mClientData); } l.pop_front(); @@ -543,7 +549,7 @@ void LLVertexBuffer::validateRange(U32 start, U32 end, U32 count, U32 indices_of void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indices_offset) const { validateRange(start, end, count, indices_offset); - + mMappable = FALSE; gGL.syncMatrices(); llassert(mNumVerts >= 0); @@ -598,7 +604,7 @@ void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indi void LLVertexBuffer::draw(U32 mode, U32 count, U32 indices_offset) const { llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL); - + mMappable = FALSE; gGL.syncMatrices(); llassert(mNumIndices >= 0); @@ -644,7 +650,7 @@ void LLVertexBuffer::draw(U32 mode, U32 count, U32 indices_offset) const void LLVertexBuffer::drawArrays(U32 mode, U32 first, U32 count) const { llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL); - + mMappable = FALSE; gGL.syncMatrices(); llassert(mNumVerts >= 0); @@ -794,9 +800,25 @@ LLVertexBuffer::LLVertexBuffer(U32 typemask, S32 usage) : if (mUsage && mUsage != GL_STREAM_DRAW_ARB) { //only stream_draw and dynamic_draw are supported when using VBOs, dynamic draw is the default - mUsage = GL_DYNAMIC_DRAW_ARB; + if (sDisableVBOMapping) + { //always use stream draw if VBO mapping is disabled + mUsage = GL_STREAM_DRAW_ARB; + } + else + { + mUsage = GL_DYNAMIC_DRAW_ARB; + } } + if (mUsage == GL_DYNAMIC_DRAW_ARB && !sDisableVBOMapping) + { + mMappable = TRUE; + } + else + { + mMappable = FALSE; + } + //zero out offsets for (U32 i = 0; i < TYPE_MAX; i++) { @@ -812,6 +834,7 @@ LLVertexBuffer::LLVertexBuffer(U32 typemask, S32 usage) : sCount++; } +//static S32 LLVertexBuffer::calcOffsets(const U32& typemask, S32* offsets, S32 num_vertices) { S32 offset = 0; @@ -944,11 +967,11 @@ void LLVertexBuffer::releaseBuffer() { if (mUsage == GL_STREAM_DRAW_ARB) { - sStreamVBOPool.release(mGLBuffer, /*(U8*)*/mMappedData, mSize); + sStreamVBOPool.release(mGLBuffer, mMappedData, mSize); } else { - sDynamicVBOPool.release(mGLBuffer, /*(U8*)*/mMappedData, mSize); + sDynamicVBOPool.release(mGLBuffer, mMappedData, mSize); } mGLBuffer = 0; @@ -961,11 +984,11 @@ void LLVertexBuffer::releaseIndices() { if (mUsage == GL_STREAM_DRAW_ARB) { - sStreamIBOPool.release(mGLIndices, /*(U8*)*/mMappedIndexData, mIndicesSize); + sStreamIBOPool.release(mGLIndices, mMappedIndexData, mIndicesSize); } else { - sDynamicIBOPool.release(mGLIndices, /*(U8*)*/mMappedIndexData, mIndicesSize); + sDynamicIBOPool.release(mGLIndices, mMappedIndexData, mIndicesSize); } mGLIndices = 0; @@ -1048,7 +1071,7 @@ void LLVertexBuffer::destroyGLBuffer() } else { - FREE_MEM(sPrivatePoolp, /*(U8*)*/mMappedData) ; + FREE_MEM(sPrivatePoolp, (void*) mMappedData) ; mMappedData = NULL; mEmpty = TRUE; } @@ -1069,7 +1092,7 @@ void LLVertexBuffer::destroyGLIndices() } else { - FREE_MEM(sPrivatePoolp, /*(U8*)*/mMappedIndexData) ; + FREE_MEM(sPrivatePoolp, (void*) mMappedIndexData) ; mMappedIndexData = NULL; mEmpty = TRUE; } @@ -1147,7 +1170,7 @@ void LLVertexBuffer::allocateBuffer(S32 nverts, S32 nindices, bool create) } } -//static LLFastTimer::DeclareTimer FTM_SETUP_VERTEX_ARRAY("Setup VAO"); +static LLFastTimer::DeclareTimer FTM_SETUP_VERTEX_ARRAY("Setup VAO"); void LLVertexBuffer::setupVertexArray() { @@ -1156,7 +1179,7 @@ void LLVertexBuffer::setupVertexArray() return; } - //LLFastTimer t(FTM_SETUP_VERTEX_ARRAY); + LLFastTimer t(FTM_SETUP_VERTEX_ARRAY); #if GL_ARB_vertex_array_object glBindVertexArray(mGLArray); #endif @@ -1288,8 +1311,10 @@ bool expand_region(LLVertexBuffer::MappedRegion& region, S32 index, S32 count) return true; } +static LLFastTimer::DeclareTimer FTM_VBO_MAP_BUFFER_RANGE("VBO Map Range"); +static LLFastTimer::DeclareTimer FTM_VBO_MAP_BUFFER("VBO Map"); // Map for data access -/*volatile */U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, bool map_range) +volatile U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, bool map_range) { bindGLBuffer(true); LLMemType mt(LLMemType::MTYPE_VERTEX_DATA); @@ -1304,7 +1329,7 @@ bool expand_region(LLVertexBuffer::MappedRegion& region, S32 index, S32 count) if (useVBOs()) { - if (sDisableVBOMapping || gGLManager.mHasMapBufferRange || gGLManager.mHasFlushBufferRange) + if (!mMappable || gGLManager.mHasMapBufferRange || gGLManager.mHasFlushBufferRange) { if (count == -1) { @@ -1329,7 +1354,7 @@ bool expand_region(LLVertexBuffer::MappedRegion& region, S32 index, S32 count) if (!mapped) { //not already mapped, map new region - MappedRegion region(type, !sDisableVBOMapping && map_range ? -1 : index, count); + MappedRegion region(type, mMappable && map_range ? -1 : index, count); mMappedVertexRegions.push_back(region); } } @@ -1345,19 +1370,20 @@ bool expand_region(LLVertexBuffer::MappedRegion& region, S32 index, S32 count) sMappedCount++; stop_glerror(); - if(sDisableVBOMapping) + if(!mMappable) { map_range = false; } else { - U8* src = NULL; + volatile U8* src = NULL; waitFence(); if (gGLManager.mHasMapBufferRange) { if (map_range) { #ifdef GL_ARB_map_buffer_range + LLFastTimer t(FTM_VBO_MAP_BUFFER_RANGE); S32 offset = mOffsets[type] + sTypeSize[type]*index; S32 length = (sTypeSize[type]*count+0xF) & ~0xF; src = (U8*) glMapBufferRange(GL_ARRAY_BUFFER_ARB, offset, length, @@ -1381,6 +1407,7 @@ bool expand_region(LLVertexBuffer::MappedRegion& region, S32 index, S32 count) } } + LLFastTimer t(FTM_VBO_MAP_BUFFER); src = (U8*) glMapBufferRange(GL_ARRAY_BUFFER_ARB, 0, mSize, GL_MAP_WRITE_BIT | GL_MAP_FLUSH_EXPLICIT_BIT); @@ -1408,7 +1435,7 @@ bool expand_region(LLVertexBuffer::MappedRegion& region, S32 index, S32 count) llassert(src != NULL); - mMappedData = LL_NEXT_ALIGNED_ADDRESS(src); + mMappedData = LL_NEXT_ALIGNED_ADDRESS(src); mAlignedOffset = mMappedData - src; stop_glerror(); @@ -1421,7 +1448,7 @@ bool expand_region(LLVertexBuffer::MappedRegion& region, S32 index, S32 count) //check the availability of memory LLMemory::logMemoryInfo(TRUE) ; - if(!sDisableVBOMapping) + if(mMappable) { //-------------------- //print out more debug info before crash @@ -1453,7 +1480,7 @@ bool expand_region(LLVertexBuffer::MappedRegion& region, S32 index, S32 count) map_range = false; } - if (map_range && gGLManager.mHasMapBufferRange && !sDisableVBOMapping) + if (map_range && gGLManager.mHasMapBufferRange && mMappable) { return mMappedData; } @@ -1463,7 +1490,10 @@ bool expand_region(LLVertexBuffer::MappedRegion& region, S32 index, S32 count) } } -/*volatile */U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range) + +static LLFastTimer::DeclareTimer FTM_VBO_MAP_INDEX_RANGE("IBO Map Range"); +static LLFastTimer::DeclareTimer FTM_VBO_MAP_INDEX("IBO Map"); +volatile U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range) { LLMemType mt(LLMemType::MTYPE_VERTEX_DATA); bindGLIndices(true); @@ -1478,7 +1508,7 @@ bool expand_region(LLVertexBuffer::MappedRegion& region, S32 index, S32 count) if (useVBOs()) { - if (sDisableVBOMapping || gGLManager.mHasMapBufferRange || gGLManager.mHasFlushBufferRange) + if (!mMappable || gGLManager.mHasMapBufferRange || gGLManager.mHasFlushBufferRange) { if (count == -1) { @@ -1500,7 +1530,7 @@ bool expand_region(LLVertexBuffer::MappedRegion& region, S32 index, S32 count) if (!mapped) { //not already mapped, map new region - MappedRegion region(TYPE_INDEX, !sDisableVBOMapping && map_range ? -1 : index, count); + MappedRegion region(TYPE_INDEX, mMappable && map_range ? -1 : index, count); mMappedIndexRegions.push_back(region); } } @@ -1529,19 +1559,20 @@ bool expand_region(LLVertexBuffer::MappedRegion& region, S32 index, S32 count) } } - if(sDisableVBOMapping) + if(!mMappable) { map_range = false; } else { - U8* src = NULL; + volatile U8* src = NULL; waitFence(); if (gGLManager.mHasMapBufferRange) { if (map_range) { #ifdef GL_ARB_map_buffer_range + LLFastTimer t(FTM_VBO_MAP_INDEX_RANGE); S32 offset = sizeof(U16)*index; S32 length = sizeof(U16)*count; src = (U8*) glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER_ARB, offset, length, @@ -1553,6 +1584,7 @@ bool expand_region(LLVertexBuffer::MappedRegion& region, S32 index, S32 count) else { #ifdef GL_ARB_map_buffer_range + LLFastTimer t(FTM_VBO_MAP_INDEX); src = (U8*) glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER_ARB, 0, sizeof(U16)*mNumIndices, GL_MAP_WRITE_BIT | GL_MAP_FLUSH_EXPLICIT_BIT); @@ -1574,6 +1606,7 @@ bool expand_region(LLVertexBuffer::MappedRegion& region, S32 index, S32 count) } else { + LLFastTimer t(FTM_VBO_MAP_INDEX); map_range = false; src = (U8*) glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); } @@ -1592,7 +1625,7 @@ bool expand_region(LLVertexBuffer::MappedRegion& region, S32 index, S32 count) log_glerror(); LLMemory::logMemoryInfo(TRUE) ; - if(!sDisableVBOMapping) + if(mMappable) { GLint buff; glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, &buff); @@ -1614,7 +1647,7 @@ bool expand_region(LLVertexBuffer::MappedRegion& region, S32 index, S32 count) map_range = false; } - if (map_range && gGLManager.mHasMapBufferRange && !sDisableVBOMapping) + if (map_range && gGLManager.mHasMapBufferRange && mMappable) { return mMappedIndexData; } @@ -1624,6 +1657,13 @@ bool expand_region(LLVertexBuffer::MappedRegion& region, S32 index, S32 count) } } +static LLFastTimer::DeclareTimer FTM_VBO_UNMAP("VBO Unmap"); +static LLFastTimer::DeclareTimer FTM_VBO_FLUSH_RANGE("Flush VBO Range"); + + +static LLFastTimer::DeclareTimer FTM_IBO_UNMAP("IBO Unmap"); +static LLFastTimer::DeclareTimer FTM_IBO_FLUSH_RANGE("Flush IBO Range"); + void LLVertexBuffer::unmapBuffer() { LLMemType mt(LLMemType::MTYPE_VERTEX_DATA); @@ -1636,10 +1676,11 @@ void LLVertexBuffer::unmapBuffer() if (mMappedData && mVertexLocked) { + LLFastTimer t(FTM_VBO_UNMAP); bindGLBuffer(true); updated_all = mIndexLocked; //both vertex and index buffers done updating - if(sDisableVBOMapping) + if(!mMappable) { if (!mMappedVertexRegions.empty()) { @@ -1649,7 +1690,7 @@ void LLVertexBuffer::unmapBuffer() const MappedRegion& region = mMappedVertexRegions[i]; S32 offset = region.mIndex >= 0 ? mOffsets[region.mType]+sTypeSize[region.mType]*region.mIndex : 0; S32 length = sTypeSize[region.mType]*region.mCount; - glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, offset, length, /*(U8*)*/mMappedData+offset); + glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, offset, length, (U8*) mMappedData+offset); stop_glerror(); } @@ -1658,7 +1699,7 @@ void LLVertexBuffer::unmapBuffer() else { stop_glerror(); - glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, getSize(), /*(U8*)*/mMappedData); + glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, getSize(), (U8*) mMappedData); stop_glerror(); } } @@ -1676,6 +1717,7 @@ void LLVertexBuffer::unmapBuffer() S32 length = sTypeSize[region.mType]*region.mCount; if (gGLManager.mHasMapBufferRange) { + LLFastTimer t(FTM_VBO_FLUSH_RANGE); #ifdef GL_ARB_map_buffer_range glFlushMappedBufferRange(GL_ARRAY_BUFFER_ARB, offset, length); #endif @@ -1704,7 +1746,7 @@ void LLVertexBuffer::unmapBuffer() if (mMappedIndexData && mIndexLocked) { bindGLIndices(); - if(sDisableVBOMapping) + if(!mMappable) { if (!mMappedIndexRegions.empty()) { @@ -1713,7 +1755,7 @@ void LLVertexBuffer::unmapBuffer() const MappedRegion& region = mMappedIndexRegions[i]; S32 offset = region.mIndex >= 0 ? sizeof(U16)*region.mIndex : 0; S32 length = sizeof(U16)*region.mCount; - glBufferSubDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, offset, length, /*(U8*)*/mMappedIndexData+offset); + glBufferSubDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, offset, length, (U8*) mMappedIndexData+offset); stop_glerror(); } @@ -1722,7 +1764,7 @@ void LLVertexBuffer::unmapBuffer() else { stop_glerror(); - glBufferSubDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0, getIndicesSize(), /*(U8*)*/mMappedIndexData); + glBufferSubDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0, getIndicesSize(), (U8*) mMappedIndexData); stop_glerror(); } } @@ -1739,6 +1781,7 @@ void LLVertexBuffer::unmapBuffer() S32 length = sizeof(U16)*region.mCount; if (gGLManager.mHasMapBufferRange) { + LLFastTimer t(FTM_IBO_FLUSH_RANGE); #ifdef GL_ARB_map_buffer_range glFlushMappedBufferRange(GL_ELEMENT_ARRAY_BUFFER_ARB, offset, length); #endif @@ -1783,7 +1826,7 @@ template struct VertexBufferStrider { if (type == LLVertexBuffer::TYPE_INDEX) { - /*volatile*/ U8* ptr = vbo.mapIndexBuffer(index, count, map_range); + volatile U8* ptr = vbo.mapIndexBuffer(index, count, map_range); if (ptr == NULL) { @@ -1798,8 +1841,8 @@ template struct VertexBufferStrider else if (vbo.hasDataType(type)) { S32 stride = LLVertexBuffer::sTypeSize[type]; - - /*volatile */U8* ptr = vbo.mapVertexBuffer(type, index, count, map_range); + + volatile U8* ptr = vbo.mapVertexBuffer(type, index, count, map_range); if (ptr == NULL) { @@ -1876,13 +1919,13 @@ bool LLVertexBuffer::getClothWeightStrider(LLStrider& strider, S32 in //---------------------------------------------------------------------------- -//static LLFastTimer::DeclareTimer FTM_BIND_GL_ARRAY("Bind Array"); +static LLFastTimer::DeclareTimer FTM_BIND_GL_ARRAY("Bind Array"); bool LLVertexBuffer::bindGLArray() { if (mGLArray && sGLRenderArray != mGLArray) { { - //LLFastTimer t(FTM_BIND_GL_ARRAY); + LLFastTimer t(FTM_BIND_GL_ARRAY); #if GL_ARB_vertex_array_object glBindVertexArray(mGLArray); #endif @@ -1899,7 +1942,7 @@ bool LLVertexBuffer::bindGLArray() return false; } -//static LLFastTimer::DeclareTimer FTM_BIND_GL_BUFFER("Bind Buffer"); +static LLFastTimer::DeclareTimer FTM_BIND_GL_BUFFER("Bind Buffer"); bool LLVertexBuffer::bindGLBuffer(bool force_bind) { @@ -1909,7 +1952,7 @@ bool LLVertexBuffer::bindGLBuffer(bool force_bind) if (useVBOs() && (force_bind || (mGLBuffer && (mGLBuffer != sGLRenderBuffer || !sVBOActive)))) { - //LLFastTimer t(FTM_BIND_GL_BUFFER); + LLFastTimer t(FTM_BIND_GL_BUFFER); /*if (sMapped) { llerrs << "VBO bound while another VBO mapped!" << llendl; @@ -1931,7 +1974,7 @@ bool LLVertexBuffer::bindGLBuffer(bool force_bind) return ret; } -//static LLFastTimer::DeclareTimer FTM_BIND_GL_INDICES("Bind Indices"); +static LLFastTimer::DeclareTimer FTM_BIND_GL_INDICES("Bind Indices"); bool LLVertexBuffer::bindGLIndices(bool force_bind) { @@ -1940,7 +1983,7 @@ bool LLVertexBuffer::bindGLIndices(bool force_bind) bool ret = false; if (useVBOs() && (force_bind || (mGLIndices && (mGLIndices != sGLRenderIndices || !sIBOActive)))) { - //LLFastTimer t(FTM_BIND_GL_INDICES); + LLFastTimer t(FTM_BIND_GL_INDICES); /*if (sMapped) { llerrs << "VBO bound while another VBO mapped!" << llendl; @@ -2117,7 +2160,7 @@ void LLVertexBuffer::setupVertexBuffer(U32 data_mask) { LLMemType mt(LLMemType::MTYPE_VERTEX_DATA); stop_glerror(); - U8* base = useVBOs() ? (U8*)mAlignedOffset : /*(U8*)*/mMappedData; + volatile U8* base = useVBOs() ? (U8*) mAlignedOffset : mMappedData; /*if ((data_mask & mTypeMask) != data_mask) { diff --git a/indra/llrender/llvertexbuffer.h b/indra/llrender/llvertexbuffer.h index 85ad44693..baff56286 100644 --- a/indra/llrender/llvertexbuffer.h +++ b/indra/llrender/llvertexbuffer.h @@ -2,31 +2,25 @@ * @file llvertexbuffer.h * @brief LLVertexBuffer wrapper for OpengGL vertex buffer objects * - * $LicenseInfo:firstyear=2003&license=viewergpl$ - * - * Copyright (c) 2003-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2003&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -67,10 +61,10 @@ public: U32 mType; //size MUST be a power of 2 - U8* allocate(U32& name, U32 size); + volatile U8* allocate(U32& name, U32 size); //size MUST be the size provided to allocate that returned the given name - void release(U32 name, U8* buffer, U32 size); + void release(U32 name, volatile U8* buffer, U32 size); //destroy all records in mFreeList void cleanup(); @@ -79,7 +73,7 @@ public: { public: U32 mGLName; - U8* mClientData; + volatile U8* mClientData; }; typedef std::list record_list_t; @@ -215,8 +209,8 @@ public: LLVertexBuffer(U32 typemask, S32 usage); // map for data access - /*volatile */U8* mapVertexBuffer(S32 type, S32 index, S32 count, bool map_range); - /*volatile */U8* mapIndexBuffer(S32 index, S32 count, bool map_range); + volatile U8* mapVertexBuffer(S32 type, S32 index, S32 count, bool map_range); + volatile U8* mapIndexBuffer(S32 index, S32 count, bool map_range); // set for rendering virtual void setBuffer(U32 data_mask); // calls setupVertexBuffer() if data_mask is not 0 @@ -251,17 +245,18 @@ public: S32 getNumVerts() const { return mNumVerts; } S32 getNumIndices() const { return mNumIndices; } - /*volatile */U8* getIndicesPointer() const { return useVBOs() ? (U8*) mAlignedIndexOffset : mMappedIndexData; } - /*volatile */U8* getVerticesPointer() const { return useVBOs() ? (U8*) mAlignedOffset : mMappedData; } + volatile U8* getIndicesPointer() const { return useVBOs() ? (U8*) mAlignedIndexOffset : mMappedIndexData; } + volatile U8* getVerticesPointer() const { return useVBOs() ? (U8*) mAlignedOffset : mMappedData; } U32 getTypeMask() const { return mTypeMask; } bool hasDataType(S32 type) const { return ((1 << type) & getTypeMask()); } S32 getSize() const; S32 getIndicesSize() const { return mIndicesSize; } - /*volatile */U8* getMappedData() const { return mMappedData; } - /*volatile */U8* getMappedIndices() const { return mMappedIndexData; } + volatile U8* getMappedData() const { return mMappedData; } + volatile U8* getMappedIndices() const { return mMappedIndexData; } S32 getOffset(S32 type) const { return mOffsets[type]; } S32 getUsage() const { return mUsage; } - + BOOL isWriteable() const { return (mMappable || mUsage == GL_STREAM_DRAW_ARB) ? TRUE : FALSE; } + void draw(U32 mode, U32 count, U32 indices_offset) const; void drawArrays(U32 mode, U32 offset, U32 count) const; void drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indices_offset) const; @@ -285,12 +280,13 @@ protected: U32 mGLIndices; // GL IBO handle U32 mGLArray; // GL VAO handle - /*volatile */U8* mMappedData; // pointer to currently mapped data (NULL if unmapped) - /*volatile */U8* mMappedIndexData; // pointer to currently mapped indices (NULL if unmapped) + volatile U8* mMappedData; // pointer to currently mapped data (NULL if unmapped) + volatile U8* mMappedIndexData; // pointer to currently mapped indices (NULL if unmapped) BOOL mVertexLocked; // if TRUE, vertex buffer is being or has been written to in client memory BOOL mIndexLocked; // if TRUE, index buffer is being or has been written to in client memory BOOL mFinal; // if TRUE, buffer can not be mapped again BOOL mEmpty; // if TRUE, client buffer is empty (or NULL). Old values have been discarded. + mutable BOOL mMappable; // if TRUE, use memory mapping to upload data (otherwise doublebuffer and use glBufferSubData) S32 mOffsets[TYPE_MAX]; std::vector mMappedVertexRegions; diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt index 22625a260..42fa88495 100644 --- a/indra/llui/CMakeLists.txt +++ b/indra/llui/CMakeLists.txt @@ -39,6 +39,7 @@ set(llui_SOURCE_FILES lliconctrl.cpp llkeywords.cpp lllineeditor.cpp + lllocalcliprect.cpp llmenugl.cpp llmodaldialog.cpp llmultifloater.cpp @@ -99,6 +100,7 @@ set(llui_HEADER_FILES lliconctrl.h llkeywords.h lllineeditor.h + lllocalcliprect.h llmemberlistener.h llmenugl.h llmodaldialog.h diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp index 90a633a8e..3145c3cf1 100644 --- a/indra/llui/llfloater.cpp +++ b/indra/llui/llfloater.cpp @@ -56,6 +56,7 @@ #include "llcontrol.h" #include "lltabcontainer.h" #include "v2math.h" +#include "llfasttimer.h" const S32 MINIMIZED_WIDTH = 160; const S32 CLOSE_BOX_FROM_TOP = 1; @@ -2548,6 +2549,7 @@ LLView* LLFloater::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *f return floaterp; } +LLFastTimer::DeclareTimer POST_BUILD("Floater Post Build"); void LLFloater::initFloaterXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory, BOOL open) /* Flawfinder: ignore */ { std::string name(getName()); @@ -2617,7 +2619,12 @@ void LLFloater::initFloaterXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactor LLFloater::setFloaterHost(last_host); } - BOOL result = postBuild(); + BOOL result; + { + LLFastTimer ft(POST_BUILD); + + result = postBuild(); + } if (!result) { diff --git a/indra/llui/lllocalcliprect.cpp b/indra/llui/lllocalcliprect.cpp new file mode 100644 index 000000000..684130121 --- /dev/null +++ b/indra/llui/lllocalcliprect.cpp @@ -0,0 +1,110 @@ +/** +* @file lllocalcliprect.cpp +* +* $LicenseInfo:firstyear=2009&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 "lllocalcliprect.h" + +#include "llfontgl.h" +#include "llui.h" + +/*static*/ std::stack LLScreenClipRect::sClipRectStack; + + +LLScreenClipRect::LLScreenClipRect(const LLRect& rect, BOOL enabled) +: mScissorState(GL_SCISSOR_TEST), + mEnabled(enabled) +{ + if (mEnabled) + { + pushClipRect(rect); + mScissorState.setEnabled(!sClipRectStack.empty()); + updateScissorRegion(); + } +} + +LLScreenClipRect::~LLScreenClipRect() +{ + if (mEnabled) + { + popClipRect(); + updateScissorRegion(); + } +} + +//static +void LLScreenClipRect::pushClipRect(const LLRect& rect) +{ + LLRect combined_clip_rect = rect; + if (!sClipRectStack.empty()) + { + LLRect top = sClipRectStack.top(); + combined_clip_rect.intersectWith(top); + + if(combined_clip_rect.isEmpty()) + { + // avoid artifacts where zero area rects show up as lines + combined_clip_rect = LLRect::null; + } + } + sClipRectStack.push(combined_clip_rect); +} + +//static +void LLScreenClipRect::popClipRect() +{ + sClipRectStack.pop(); +} + +//static +void LLScreenClipRect::updateScissorRegion() +{ + if (sClipRectStack.empty()) return; + + // finish any deferred calls in the old clipping region + gGL.flush(); + + LLRect rect = sClipRectStack.top(); + stop_glerror(); + S32 x,y,w,h; + x = llfloor(rect.mLeft * LLUI::sGLScaleFactor.mV[VX]); + y = llfloor(rect.mBottom * LLUI::sGLScaleFactor.mV[VY]); + w = llmax(0, llceil(rect.getWidth() * LLUI::sGLScaleFactor.mV[VX])) + 1; + h = llmax(0, llceil(rect.getHeight() * LLUI::sGLScaleFactor.mV[VY])) + 1; + glScissor( x,y,w,h ); + stop_glerror(); +} + +//--------------------------------------------------------------------------- +// LLLocalClipRect +//--------------------------------------------------------------------------- +LLLocalClipRect::LLLocalClipRect(const LLRect& rect, BOOL enabled /* = TRUE */) +: LLScreenClipRect(LLRect(rect.mLeft + LLFontGL::sCurOrigin.mX, + rect.mTop + LLFontGL::sCurOrigin.mY, + rect.mRight + LLFontGL::sCurOrigin.mX, + rect.mBottom + LLFontGL::sCurOrigin.mY), enabled) +{} + +LLLocalClipRect::~LLLocalClipRect() +{} diff --git a/indra/llui/lllocalcliprect.h b/indra/llui/lllocalcliprect.h new file mode 100644 index 000000000..ebd6c1858 --- /dev/null +++ b/indra/llui/lllocalcliprect.h @@ -0,0 +1,64 @@ +/** +* @file lllocalcliprect.h +* +* $LicenseInfo:firstyear=2009&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 LLLOCALCLIPRECT_H +#define LLLOCALCLIPRECT_H + +#include "llgl.h" +#include "lllocalcliprect.h" +#include "llrect.h" // can't forward declare, it's templated +#include + +// Clip rendering to a specific rectangle using GL scissor +// Just create one of these on the stack: +// { +// LLLocalClipRect(rect); +// draw(); +// } +class LLScreenClipRect +{ +public: + LLScreenClipRect(const LLRect& rect, BOOL enabled = TRUE); + virtual ~LLScreenClipRect(); + +private: + static void pushClipRect(const LLRect& rect); + static void popClipRect(); + static void updateScissorRegion(); + +private: + LLGLState mScissorState; + BOOL mEnabled; + + static std::stack sClipRectStack; +}; + +class LLLocalClipRect : public LLScreenClipRect +{ +public: + LLLocalClipRect(const LLRect& rect, BOOL enabled = TRUE); + ~LLLocalClipRect(); +}; + +#endif diff --git a/indra/llui/llpanel.cpp b/indra/llui/llpanel.cpp index cc0b9faf5..9dc217e21 100644 --- a/indra/llui/llpanel.cpp +++ b/indra/llui/llpanel.cpp @@ -39,6 +39,7 @@ #include "llalertdialog.h" #include "llfocusmgr.h" #include "llfontgl.h" +#include "lllocalcliprect.h" #include "llrect.h" #include "llerror.h" #include "lltimer.h" @@ -56,6 +57,7 @@ #include "llviewborder.h" #include "llbutton.h" #include "llnotificationsutil.h" +#include "llfasttimer.h" // LLLayoutStack #include "llresizebar.h" @@ -415,13 +417,13 @@ void LLPanel::setBorderVisible(BOOL b) } } +LLFastTimer::DeclareTimer FTM_PANEL_CONSTRUCTION("Panel Construction"); // virtual LLXMLNodePtr LLPanel::getXML(bool save_children) const { LLXMLNodePtr node = LLUICtrl::getXML(); node->setName(LL_PANEL_TAG); - if (mBorder && mBorder->getVisible()) { node->createChild("border", TRUE)->setBoolValue(TRUE); @@ -471,6 +473,7 @@ LLView* LLPanel::fromXML(LLXMLNodePtr node, LLView* parent, LLUICtrlFactory *fac node->getAttributeString("name", name); LLPanel* panelp = factory->createFactoryPanel(name); + LLFastTimer _(FTM_PANEL_CONSTRUCTION); // Fall back on a default panel, if there was no special factory. if (!panelp) { diff --git a/indra/llui/llscrollcontainer.cpp b/indra/llui/llscrollcontainer.cpp index 13c8ed4a2..28890b199 100644 --- a/indra/llui/llscrollcontainer.cpp +++ b/indra/llui/llscrollcontainer.cpp @@ -35,6 +35,7 @@ #include "llrender.h" #include "llscrollcontainer.h" +#include "lllocalcliprect.h" #include "llscrollbar.h" #include "llui.h" #include "llkeyboard.h" diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp index e356d3c44..01c3a4731 100644 --- a/indra/llui/llscrolllistctrl.cpp +++ b/indra/llui/llscrolllistctrl.cpp @@ -43,6 +43,7 @@ #include "llcheckboxctrl.h" #include "llclipboard.h" #include "llfocusmgr.h" +#include "lllocalcliprect.h" #include "llrender.h" #include "llresmgr.h" #include "llscrollbar.h" diff --git a/indra/llui/lltabcontainer.cpp b/indra/llui/lltabcontainer.cpp index ebef5bb5d..eeff21cdf 100644 --- a/indra/llui/lltabcontainer.cpp +++ b/indra/llui/lltabcontainer.cpp @@ -31,9 +31,11 @@ */ #include "linden_common.h" + #include "lltabcontainer.h" #include "llfocusmgr.h" #include "llbutton.h" +#include "lllocalcliprect.h" #include "llrect.h" #include "llresmgr.h" #include "llresizehandle.h" diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp index c225b3a87..cd9d06c58 100644 --- a/indra/llui/lltexteditor.cpp +++ b/indra/llui/lltexteditor.cpp @@ -37,6 +37,7 @@ #include "lltexteditor.h" #include "llfontgl.h" +#include "lllocalcliprect.h" #include "llrender.h" #include "llui.h" #include "lluictrlfactory.h" @@ -54,6 +55,7 @@ #include "llkeywords.h" #include "llundo.h" #include "llviewborder.h" +#include "llfasttimer.h" #include "llcontrol.h" #include "llimagegl.h" @@ -4352,18 +4354,25 @@ void LLTextEditor::loadKeywords(const std::string& filename, } } +static LLFastTimer::DeclareTimer FTM_SYNTAX_HIGHLIGHTING("Syntax Highlighting"); +static LLFastTimer::DeclareTimer FTM_UPDATE_TEXT_SEGMENTS("Update Text Segments"); + void LLTextEditor::updateSegments() { - if (mKeywords.isLoaded()) { - // HACK: No non-ascii keywords for now - mKeywords.findSegments(&mSegments, mWText, mDefaultColor); - } - else if (mAllowEmbeddedItems) - { - findEmbeddedItemSegments(); + LLFastTimer ft(FTM_SYNTAX_HIGHLIGHTING); + if (mKeywords.isLoaded()) + { + // HACK: No non-ascii keywords for now + mKeywords.findSegments(&mSegments, mWText, mDefaultColor); + } + else if (mAllowEmbeddedItems) + { + findEmbeddedItemSegments(); + } } + LLFastTimer ft(FTM_UPDATE_TEXT_SEGMENTS); // Make sure we have at least one segment if (mSegments.size() == 1 && mSegments[0]->getIsDefault()) { diff --git a/indra/llui/llui.cpp b/indra/llui/llui.cpp index de34a0c8a..fa1411f23 100644 --- a/indra/llui/llui.cpp +++ b/indra/llui/llui.cpp @@ -73,7 +73,6 @@ LLVector2 LLUI::sGLScaleFactor(1.f, 1.f); LLWindow* LLUI::sWindow = NULL; LLHtmlHelp* LLUI::sHtmlHelp = NULL; BOOL LLUI::sShowXUINames = FALSE; -std::stack LLScreenClipRect::sClipRectStack; BOOL LLUI::sQAMode = FALSE; // @@ -1856,66 +1855,3 @@ void LLUI::setQAMode(BOOL b) LLUI::sQAMode = b; } -LLScreenClipRect::LLScreenClipRect(const LLRect& rect, BOOL enabled) : mScissorState(GL_SCISSOR_TEST), mEnabled(enabled) -{ - if (mEnabled) - { - pushClipRect(rect); - } - mScissorState.setEnabled(!sClipRectStack.empty()); - updateScissorRegion(); -} - -LLScreenClipRect::~LLScreenClipRect() -{ - if (mEnabled) - { - popClipRect(); - } - updateScissorRegion(); -} - -//static -void LLScreenClipRect::pushClipRect(const LLRect& rect) -{ - LLRect combined_clip_rect = rect; - if (!sClipRectStack.empty()) - { - LLRect top = sClipRectStack.top(); - combined_clip_rect.intersectWith(top); - } - sClipRectStack.push(combined_clip_rect); -} - -//static -void LLScreenClipRect::popClipRect() -{ - sClipRectStack.pop(); -} - -//static -void LLScreenClipRect::updateScissorRegion() -{ - if (sClipRectStack.empty()) return; - - LLRect rect = sClipRectStack.top(); - stop_glerror(); - S32 x,y,w,h; - x = llfloor(rect.mLeft * LLUI::sGLScaleFactor.mV[VX]); - y = llfloor(rect.mBottom * LLUI::sGLScaleFactor.mV[VY]); - w = llmax(0, llceil(rect.getWidth() * LLUI::sGLScaleFactor.mV[VX])) + 1; - h = llmax(0, llceil(rect.getHeight() * LLUI::sGLScaleFactor.mV[VY])) + 1; - glScissor( x,y,w,h ); - stop_glerror(); -} - - -LLLocalClipRect::LLLocalClipRect(const LLRect &rect, BOOL enabled) -: LLScreenClipRect(LLRect(rect.mLeft + LLFontGL::sCurOrigin.mX, - rect.mTop + LLFontGL::sCurOrigin.mY, - rect.mRight + LLFontGL::sCurOrigin.mX, - rect.mBottom + LLFontGL::sCurOrigin.mY), - enabled) -{ -} - diff --git a/indra/llui/llui.h b/indra/llui/llui.h index 3c31ed27b..556a3b895 100644 --- a/indra/llui/llui.h +++ b/indra/llui/llui.h @@ -388,30 +388,6 @@ private: template T* LLUISingleton::sInstance = NULL; -class LLScreenClipRect -{ -public: - LLScreenClipRect(const LLRect& rect, BOOL enabled = TRUE); - virtual ~LLScreenClipRect(); - -private: - static void pushClipRect(const LLRect& rect); - static void popClipRect(); - static void updateScissorRegion(); - -private: - LLGLState mScissorState; - BOOL mEnabled; - - static std::stack sClipRectStack; -}; - -class LLLocalClipRect : public LLScreenClipRect -{ -public: - LLLocalClipRect(const LLRect& rect, BOOL enabled = TRUE); -}; - //RN: maybe this needs to moved elsewhere? class LLImageProviderInterface diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp index d7ef321a1..29894db6c 100644 --- a/indra/llui/llview.cpp +++ b/indra/llui/llview.cpp @@ -57,6 +57,7 @@ #include "lllineeditor.h" #include "lltexteditor.h" #include "lltextbox.h" +#include "llfasttimer.h" // #include "lldelayeduidelete.h" @@ -1664,8 +1665,11 @@ BOOL LLView::hasChild(const std::string& childname, BOOL recurse) const //----------------------------------------------------------------------------- // getChildView() //----------------------------------------------------------------------------- +static LLFastTimer::DeclareTimer FTM_FIND_VIEWS("Find Views"); + LLView* LLView::getChildView(const std::string& name, BOOL recurse, BOOL create_if_missing) const { + LLFastTimer ft(FTM_FIND_VIEWS); //richard: should we allow empty names? //if(name.empty()) // return NULL; diff --git a/indra/llvfs/llvfile.cpp b/indra/llvfs/llvfile.cpp index 4336cf542..7e60c0fd5 100644 --- a/indra/llvfs/llvfile.cpp +++ b/indra/llvfs/llvfile.cpp @@ -38,12 +38,15 @@ #include "llthread.h" #include "llstat.h" #include "llvfs.h" +#include "llfasttimer.h" const S32 LLVFile::READ = 0x00000001; const S32 LLVFile::WRITE = 0x00000002; const S32 LLVFile::READ_WRITE = 0x00000003; // LLVFile::READ & LLVFile::WRITE const S32 LLVFile::APPEND = 0x00000006; // 0x00000004 & LLVFile::WRITE +static LLFastTimer::DeclareTimer FTM_VFILE_WAIT("VFile Wait"); + //---------------------------------------------------------------------------- LLVFSThread* LLVFile::sVFSThread = NULL; BOOL LLVFile::sAllocdVFSThread = FALSE; diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index 5263d68c1..d73fb3a0a 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -1769,6 +1769,9 @@ void LLWindowWin32::gatherInput() mMousePositionModified = FALSE; } +static LLFastTimer::DeclareTimer FTM_KEYHANDLER("Handle Keyboard"); +static LLFastTimer::DeclareTimer FTM_MOUSEHANDLER("Handle Mouse"); + LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_param, LPARAM l_param) { LLWindowWin32 *window_imp = (LLWindowWin32 *)GetWindowLong(h_wnd, GWL_USERDATA); @@ -2009,7 +2012,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ window_imp->mKeyVirtualKey = w_param; window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_KEYUP"); - LLFastTimer t2(LLFastTimer::FTM_KEYHANDLER); + LLFastTimer t2(FTM_KEYHANDLER); if (gDebugWindowProc) { @@ -2120,7 +2123,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ case WM_LBUTTONDOWN: { window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_LBUTTONDOWN"); - LLFastTimer t2(LLFastTimer::FTM_MOUSEHANDLER); + LLFastTimer t2(FTM_MOUSEHANDLER); if (LLWinImm::isAvailable() && window_imp->mPreeditor) { window_imp->interruptLanguageTextInput(); @@ -2184,7 +2187,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ case WM_LBUTTONUP: { window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_LBUTTONUP"); - LLFastTimer t2(LLFastTimer::FTM_MOUSEHANDLER); + LLFastTimer t2(FTM_MOUSEHANDLER); //if (gDebugClicks) //{ // LL_INFOS("Window") << "WndProc left button up" << LL_ENDL; @@ -2218,7 +2221,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ case WM_RBUTTONDOWN: { window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_RBUTTONDOWN"); - LLFastTimer t2(LLFastTimer::FTM_MOUSEHANDLER); + LLFastTimer t2(FTM_MOUSEHANDLER); if (LLWinImm::isAvailable() && window_imp->mPreeditor) { window_imp->interruptLanguageTextInput(); @@ -2252,7 +2255,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ case WM_RBUTTONUP: { window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_RBUTTONUP"); - LLFastTimer t2(LLFastTimer::FTM_MOUSEHANDLER); + LLFastTimer t2(FTM_MOUSEHANDLER); // Because we move the cursor position in the app, we need to query // to find out where the cursor at the time the event is handled. // If we don't do this, many clicks could get buffered up, and if the @@ -2282,7 +2285,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ // case WM_MBUTTONDBLCLK: { window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_MBUTTONDOWN"); - LLFastTimer t2(LLFastTimer::FTM_MOUSEHANDLER); + LLFastTimer t2(FTM_MOUSEHANDLER); if (LLWinImm::isAvailable() && window_imp->mPreeditor) { window_imp->interruptLanguageTextInput(); @@ -2316,7 +2319,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ case WM_MBUTTONUP: { window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_MBUTTONUP"); - LLFastTimer t2(LLFastTimer::FTM_MOUSEHANDLER); + LLFastTimer t2(FTM_MOUSEHANDLER); // Because we move the cursor position in tllviewerhe app, we need to query // to find out where the cursor at the time the event is handled. // If we don't do this, many clicks could get buffered up, and if the diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 577b646ff..6dd54e686 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -291,9 +291,11 @@ set(viewer_SOURCE_FILES llinventorybackup.cpp llinventorybridge.cpp llinventoryclipboard.cpp + llinventoryfilter.cpp llinventoryfunctions.cpp llinventoryicon.cpp llinventorymodel.cpp + llinventorymodelbackgroundfetch.cpp llinventoryobserver.cpp llinventoryview.cpp lljoystickbutton.cpp @@ -765,9 +767,11 @@ set(viewer_HEADER_FILES llinventorybackup.h llinventorybridge.h llinventoryclipboard.h + llinventoryfilter.h llinventoryfunctions.h llinventoryicon.h llinventorymodel.h + llinventorymodelbackgroundfetch.h llinventoryobserver.h llinventoryview.h lljoystickbutton.h diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index b9c6cae29..71c2f0779 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -14459,6 +14459,17 @@ Value 1 + UseHTTPInventory + + Comment + Allow use of http inventory transfers instead of UDP + Persist + 1 + Type + Boolean + Value + 1 + FloaterUploadRect Comment diff --git a/indra/newview/ascentdaycyclemanager.cpp b/indra/newview/ascentdaycyclemanager.cpp index 4462435cf..159d486d5 100644 --- a/indra/newview/ascentdaycyclemanager.cpp +++ b/indra/newview/ascentdaycyclemanager.cpp @@ -204,9 +204,10 @@ void AscentDayCycleManager::savePreset(const std::string & name) presetsXML.close(); } +static LLFastTimer::DeclareTimer FTM_UPDATE_WLPARAM("Ascent WLMenu Sync"); void AscentDayCycleManager::update(LLViewerCamera * cam) { - LLFastTimer ftm(LLFastTimer::FTM_UPDATE_WLPARAM); + LLFastTimer ftm(FTM_UPDATE_WLPARAM); // sync menus if they exist if(LLFloaterWindLight::isOpen()) diff --git a/indra/newview/cofmgr.cpp b/indra/newview/cofmgr.cpp index 3820517ae..2b7da5ddf 100644 --- a/indra/newview/cofmgr.cpp +++ b/indra/newview/cofmgr.cpp @@ -56,7 +56,7 @@ public: class LLCOFFetcher : public LLInventoryFetchDescendentsObserver { public: - LLCOFFetcher() {} + LLCOFFetcher(const LLUUID& cat_id) : LLInventoryFetchDescendentsObserver(cat_id) {} /*virtual*/ ~LLCOFFetcher() {} /*virtual*/ void done() @@ -84,7 +84,7 @@ public: // Add all currently worn wearables for (S32 idxType = 0; idxType < LLWearableType::WT_COUNT; idxType++) { - const LLUUID& idItem = gAgentWearables.getWearableItemID((LLWearableType::EType)idxType); + const LLUUID& idItem = gAgentWearables.getWearableItemID((LLWearableType::EType)idxType,0); // TODO: MULTI-WEARABLE if (idItem.isNull()) continue; idItems.push_back(idItem); @@ -216,12 +216,9 @@ void LLCOFMgr::fetchCOF() return; } - LLInventoryFetchDescendentsObserver::folder_ref_t fetchFolders; - fetchFolders.push_back(idCOF); - - LLCOFFetcher* pFetcher = new LLCOFFetcher(); - pFetcher->fetchDescendents(fetchFolders); - if (pFetcher->isEverythingComplete()) + LLCOFFetcher* pFetcher = new LLCOFFetcher(idCOF); + pFetcher->startFetch(); + if (pFetcher->isFinished()) pFetcher->done(); else gInventory.addObserver(pFetcher); @@ -489,7 +486,7 @@ void LLCOFMgr::synchWearables() uuid_vec_t newItems; for (S32 idxType = 0; idxType < LLWearableType::WT_COUNT; idxType++) { - const LLUUID& idItem = gAgentWearables.getWearableItemID((LLWearableType::EType)idxType); + const LLUUID& idItem = gAgentWearables.getWearableItemID((LLWearableType::EType)idxType, 0); // TODO: MULTI-WEARABLE if (idItem.isNull()) continue; newItems.push_back(idItem); diff --git a/indra/newview/dohexeditor.cpp b/indra/newview/dohexeditor.cpp index d03053957..071ff7d88 100644 --- a/indra/newview/dohexeditor.cpp +++ b/indra/newview/dohexeditor.cpp @@ -15,6 +15,7 @@ #include "llfocusmgr.h" #include "llkeyboard.h" #include "llclipboard.h" +#include "lllocalcliprect.h" #include "llwindow.h" // setCursor #include "lllocalinventory.h" diff --git a/indra/newview/floaterao.cpp b/indra/newview/floaterao.cpp index 3d3ee5847..d15b20e92 100644 --- a/indra/newview/floaterao.cpp +++ b/indra/newview/floaterao.cpp @@ -26,6 +26,7 @@ #include "llinventory.h" #include "llinventoryfunctions.h" +#include "llinventorymodelbackgroundfetch.h" #include "llinventoryview.h" #include "roles_constants.h" #include "llviewerregion.h" @@ -126,7 +127,7 @@ BOOL AOInvTimer::tick() if (!(gSavedSettings.getBOOL("AOEnabled"))) return TRUE; if(LLStartUp::getStartupState() >= STATE_INVENTORY_SEND) { - if(gInventory.isEverythingFetched()) + if(LLInventoryModelBackgroundFetch::instance().isEverythingFetched()) { // cmdline_printchat("Inventory fetched, loading AO."); LLFloaterAO::init(); @@ -667,7 +668,7 @@ void LLFloaterAO::init() if(LLStartUp::getStartupState() >= STATE_INVENTORY_SEND) { - if(gInventory.isEverythingFetched()) + if(LLInventoryModelBackgroundFetch::instance().isEverythingFetched()) { LLUUID configncitem = (LLUUID)gSavedPerAccountSettings.getString("AOConfigNotecardID"); if (configncitem.notNull()) @@ -964,7 +965,7 @@ BOOL LLFloaterAO::stopMotion(const LLUUID& id, BOOL stop_immediate, BOOL stand) void LLFloaterAO::onClickReloadCard(void* user_data) { - if(gInventory.isEverythingFetched()) + if(LLInventoryModelBackgroundFetch::instance().isEverythingFetched()) { LLFloaterAO::init(); } @@ -972,7 +973,7 @@ void LLFloaterAO::onClickReloadCard(void* user_data) void LLFloaterAO::onClickOpenCard(void* user_data) { - if(gInventory.isEverythingFetched()) + if(LLInventoryModelBackgroundFetch::instance().isEverythingFetched()) { LLUUID configncitem = (LLUUID)gSavedPerAccountSettings.getString("AOConfigNotecardID"); if (configncitem.notNull()) @@ -1419,7 +1420,7 @@ private: const LLUUID& LLFloaterAO::getAssetIDByName(const std::string& name) { - if (name.empty() || !(gInventory.isEverythingFetched())) return LLUUID::null; + if (name.empty() || !(LLInventoryModelBackgroundFetch::instance().isEverythingFetched())) return LLUUID::null; LLViewerInventoryCategory::cat_array_t cats; LLViewerInventoryItem::item_array_t items; diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index c432e3a4b..e36cc20bb 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -3950,7 +3950,7 @@ void LLAgent::sendAgentSetAppearance() static bool send_physics_params = false; - send_physics_params |= !!gAgentWearables.getWearable(LLWearableType::WT_PHYSICS); + send_physics_params |= !!gAgentWearables.selfHasWearable(LLWearableType::WT_PHYSICS); S32 transmitted_params = 0; for (LLViewerVisualParam* param = (LLViewerVisualParam*)gAgentAvatarp->getFirstVisualParam(); param; diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp index e625e1b4c..610c7af61 100644 --- a/indra/newview/llagentwearables.cpp +++ b/indra/newview/llagentwearables.cpp @@ -105,22 +105,39 @@ LLAgentWearables::sendAgentWearablesUpdateCallback::~sendAgentWearablesUpdateCal gAgentWearables.sendAgentWearablesUpdate(); } +/** + * @brief Construct a callback for dealing with the wearables. + * + * Would like to pass the agent in here, but we can't safely + * count on it being around later. Just use gAgent directly. + * @param cb callback to execute on completion (??? unused ???) + * @param type Type for the wearable in the agent + * @param wearable The wearable data. + * @param todo Bitmask of actions to take on completion. + */ LLAgentWearables::addWearableToAgentInventoryCallback::addWearableToAgentInventoryCallback( - LLPointer cb, LLWearableType::EType type, LLWearable* wearable, U32 todo) : + LLPointer cb, LLWearableType::EType type, U32 index, LLWearable* wearable, U32 todo) : mType(type), + mIndex(index), mWearable(wearable), mTodo(todo), mCB(cb) { + llassert_always(index == 0); llinfos << "constructor" << llendl; } void LLAgentWearables::addWearableToAgentInventoryCallback::fire(const LLUUID& inv_item) { + if (mTodo & CALL_CREATESTANDARDDONE) + { + llinfos << "callback fired, inv_item " << inv_item.asString() << llendl; + } + if (inv_item.isNull()) return; - gAgentWearables.addWearabletoAgentInventoryDone(mType, inv_item, mWearable); + gAgentWearables.addWearabletoAgentInventoryDone(mType, mIndex, inv_item, mWearable); if (mTodo & CALL_UPDATE) { @@ -135,24 +152,28 @@ void LLAgentWearables::addWearableToAgentInventoryCallback::fire(const LLUUID& i */ if (mTodo & CALL_CREATESTANDARDDONE) { - gAgentWearables.createStandardWearablesDone(mType); + gAgentWearables.createStandardWearablesDone(mType, mIndex); } if (mTodo & CALL_MAKENEWOUTFITDONE) { - gAgentWearables.makeNewOutfitDone(mType); + gAgentWearables.makeNewOutfitDone(mType, mIndex); } } void LLAgentWearables::addWearabletoAgentInventoryDone(const LLWearableType::EType type, - const LLUUID& item_id, - LLWearable* wearable) + const U32 index, + const LLUUID& item_id, + LLWearable* wearable) { - llinfos << "type " << type << " item " << item_id.asString() << llendl; + llassert_always(index == 0); + + llinfos << "type " << type << " index " << index << " item " << item_id.asString() << llendl; if (item_id.isNull()) return; + + LLUUID old_item_id = getWearableItemID(type,index); - LLUUID old_item_id = getWearableItemID(type); if (wearable) { wearable->setItemID(item_id); @@ -160,7 +181,7 @@ void LLAgentWearables::addWearabletoAgentInventoryDone(const LLWearableType::ETy if (old_item_id.notNull()) { gInventory.addChangedMask(LLInventoryObserver::LABEL, old_item_id); - setWearable(type,wearable); + setWearable(type,index,wearable); } else { @@ -189,8 +210,9 @@ void LLAgentWearables::sendAgentWearablesUpdate() // First make sure that we have inventory items for each wearable for (S32 type=0; type < LLWearableType::WT_COUNT; ++type) { + for (U32 index=0; index < getWearableCount((LLWearableType::EType)type); ++index) { - LLWearable* wearable = getWearable((LLWearableType::EType)type); + LLWearable* wearable = getWearable((LLWearableType::EType)type,index); if (wearable) { if (wearable->getItemID().isNull()) @@ -199,6 +221,7 @@ void LLAgentWearables::sendAgentWearablesUpdate() new addWearableToAgentInventoryCallback( LLPointer(NULL), (LLWearableType::EType)type, + index, wearable, addWearableToAgentInventoryCallback::CALL_NONE); addWearableToAgentInventory(cb, wearable); @@ -226,18 +249,19 @@ void LLAgentWearables::sendAgentWearablesUpdate() gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); lldebugs << "sendAgentWearablesUpdate()" << llendl; - for (S32 type=0; type < LLWearableType::WT_COUNT; ++type) + // MULTI-WEARABLE: DEPRECATED: HACK: index to 0- server database tables don't support concept of multiwearables. + for (S32 type=0; type < LLWearableType::WT_COUNT; ++type) { gMessageSystem->nextBlockFast(_PREHASH_WearableData); U8 type_u8 = (U8)type; gMessageSystem->addU8Fast(_PREHASH_WearableType, type_u8 ); - LLWearable* wearable = getWearable((LLWearableType::EType)type); + LLWearable* wearable = getWearable((LLWearableType::EType)type, 0); if( wearable ) { + //llinfos << "Sending wearable " << wearable->getName() << llendl; LLUUID item_id = wearable->getItemID(); - LL_DEBUGS("Wearables") << "Sending wearable " << wearable->getName() << " mItemID = " << item_id << LL_ENDL; const LLViewerInventoryItem *item = gInventory.getItem(item_id); if (item && item->getIsLinkType()) { @@ -249,8 +273,8 @@ void LLAgentWearables::sendAgentWearablesUpdate() } else { - LL_DEBUGS("Wearables") << "Not wearing wearable type " << LLWearableType::getTypeName((LLWearableType::EType)type) << LL_ENDL; - gMessageSystem->addUUIDFast(_PREHASH_ItemID, LLUUID::null ); + //llinfos << "Not wearing wearable type " << LLWearableType::getTypeName((LLWearableType::EType)i) << llendl; + gMessageSystem->addUUIDFast(_PREHASH_ItemID, LLUUID::null); } lldebugs << " " << LLWearableType::getTypeLabel((LLWearableType::EType)type) << ": " << (wearable ? wearable->getAssetID() : LLUUID::null) << llendl; @@ -258,10 +282,11 @@ void LLAgentWearables::sendAgentWearablesUpdate() gAgent.sendReliableMessage(); } -void LLAgentWearables::saveWearable(const LLWearableType::EType type, BOOL send_update, +void LLAgentWearables::saveWearable(const LLWearableType::EType type, const U32 index, BOOL send_update, const std::string new_name) { - LLWearable* old_wearable = getWearable(type); + llassert_always(index == 0); + LLWearable* old_wearable = getWearable(type, index); if(!old_wearable) return; bool name_changed = !new_name.empty() && (new_name != old_wearable->getName()); if (name_changed || old_wearable->isDirty() || old_wearable->isOldVersion()) @@ -269,7 +294,7 @@ void LLAgentWearables::saveWearable(const LLWearableType::EType type, BOOL send_ LLUUID old_item_id = old_wearable->getItemID(); LLWearable* new_wearable = LLWearableList::instance().createCopyFromAvatar( old_wearable ); new_wearable->setItemID(old_item_id); // should this be in LLWearable::copyDataFrom()? - setWearable(type,new_wearable); + setWearable(type,index,new_wearable); LLInventoryItem* item = gInventory.getItem(old_item_id); if( item ) @@ -313,6 +338,7 @@ void LLAgentWearables::saveWearable(const LLWearableType::EType type, BOOL send_ new addWearableToAgentInventoryCallback( LLPointer(NULL), type, + index, new_wearable, todo); addWearableToAgentInventory(cb, new_wearable); @@ -329,23 +355,25 @@ void LLAgentWearables::saveWearable(const LLWearableType::EType type, BOOL send_ } void LLAgentWearables::saveWearableAs(const LLWearableType::EType type, + const U32 index, const std::string& new_name, BOOL save_in_lost_and_found) { - if(!isWearableCopyable(type)) + llassert_always(index == 0); + if (!isWearableCopyable(type, index)) { llwarns << "LLAgent::saveWearableAs() not copyable." << llendl; return; } - LLWearable* old_wearable = getWearable(type); - if(!old_wearable) + LLWearable* old_wearable = getWearable(type, index); + if (!old_wearable) { llwarns << "LLAgent::saveWearableAs() no old wearable." << llendl; return; } - LLInventoryItem* item = gInventory.getItem(getWearableItemID(type)); - if(!item) + LLInventoryItem* item = gInventory.getItem(getWearableItemID(type,index)); + if (!item) { llwarns << "LLAgent::saveWearableAs() no inventory item." << llendl; return; @@ -359,6 +387,7 @@ void LLAgentWearables::saveWearableAs(const LLWearableType::EType type, new addWearableToAgentInventoryCallback( LLPointer(NULL), type, + index, new_wearable, addWearableToAgentInventoryCallback::CALL_UPDATE); LLUUID category_id; @@ -422,9 +451,10 @@ void LLAgentWearables::saveWearableAs(const LLWearableType::EType type, */ } -void LLAgentWearables::revertWearable( LLWearableType::EType type ) +void LLAgentWearables::revertWearable(const LLWearableType::EType type, const U32 index) { - LLWearable* wearable = getWearable(type); + llassert_always(index == 0); + LLWearable* wearable = getWearable(type, index); llassert(wearable); if( wearable ) { @@ -438,7 +468,8 @@ void LLAgentWearables::revertAllWearables() { for( S32 i=0; i < LLWearableType::WT_COUNT; i++ ) { - revertWearable( (LLWearableType::EType)i ); + for (U32 j=0; j < getWearableCount((LLWearableType::EType)i); j++) + revertWearable( (LLWearableType::EType)i, j); } } @@ -451,7 +482,8 @@ void LLAgentWearables::saveAllWearables() for( S32 i=0; i < LLWearableType::WT_COUNT; i++ ) { - saveWearable( (LLWearableType::EType)i, FALSE ); + for (U32 j=0; j < getWearableCount((LLWearableType::EType)i); j++) + saveWearable((LLWearableType::EType)i, j, FALSE); } sendAgentWearablesUpdate(); } @@ -461,35 +493,39 @@ void LLAgentWearables::setWearableName( const LLUUID& item_id, const std::string { for( S32 i=0; i < LLWearableType::WT_COUNT; i++ ) { - LLUUID curr_item_id = getWearableItemID((LLWearableType::EType)i); - if( curr_item_id == item_id ) + for (U32 j=0; j < getWearableCount((LLWearableType::EType)i); j++) { - LLWearable* old_wearable = getWearable((LLWearableType::EType)i); - llassert( old_wearable ); - if (!old_wearable) continue; - - std::string old_name = old_wearable->getName(); - old_wearable->setName( new_name ); - LLWearable* new_wearable = LLWearableList::instance().createCopy(old_wearable); - new_wearable->setItemID(item_id); - LLInventoryItem* item = gInventory.getItem(item_id); - if(item) + LLUUID curr_item_id = getWearableItemID((LLWearableType::EType)i,j); + if (curr_item_id == item_id) { - new_wearable->setPermissions(item->getPermissions()); - } - old_wearable->setName( old_name ); + LLWearable* old_wearable = getWearable((LLWearableType::EType)i,j); + llassert(old_wearable); + if (!old_wearable) continue; - setWearable((LLWearableType::EType)i,new_wearable); - sendAgentWearablesUpdate(); - break; + std::string old_name = old_wearable->getName(); + old_wearable->setName(new_name); + LLWearable* new_wearable = LLWearableList::instance().createCopy(old_wearable); + new_wearable->setItemID(item_id); + LLInventoryItem* item = gInventory.getItem(item_id); + if (item) + { + new_wearable->setPermissions(item->getPermissions()); + } + old_wearable->setName(old_name); + + setWearable((LLWearableType::EType)i,j,new_wearable); + sendAgentWearablesUpdate(); + break; + } } } } -BOOL LLAgentWearables::isWearableModifiable(LLWearableType::EType type) const +BOOL LLAgentWearables::isWearableModifiable(LLWearableType::EType type, U32 index) const { - LLUUID item_id = getWearableItemID(type); + llassert_always(index == 0); + LLUUID item_id = getWearableItemID(type, index); return item_id.notNull() ? isWearableModifiable(item_id) : FALSE; } @@ -508,10 +544,11 @@ BOOL LLAgentWearables::isWearableModifiable(const LLUUID& item_id) const return FALSE; } -BOOL LLAgentWearables::isWearableCopyable(LLWearableType::EType type) const +BOOL LLAgentWearables::isWearableCopyable(LLWearableType::EType type, U32 index) const { - LLUUID item_id = getWearableItemID(type); - if(!item_id.isNull()) + llassert_always(index == 0); + LLUUID item_id = getWearableItemID(type, index); + if (!item_id.isNull()) { LLInventoryItem* item = gInventory.getItem(item_id); if(item && item->getPermissions().allowCopyBy(gAgent.getID(), @@ -530,7 +567,7 @@ BOOL LLAgentWearables::areWearablesLoaded() const return mWearablesLoaded; } -U32 LLAgentWearables::getWearablePermMask(LLWearableType::EType type) const +/*U32 LLAgentWearables::getWearablePermMask(LLWearableType::EType type) const { LLUUID item_id = getWearableItemID(type); if(!item_id.isNull()) @@ -543,10 +580,12 @@ U32 LLAgentWearables::getWearablePermMask(LLWearableType::EType type) const } return PERM_NONE; } +*/ -LLInventoryItem* LLAgentWearables::getWearableInventoryItem(LLWearableType::EType type) +LLInventoryItem* LLAgentWearables::getWearableInventoryItem(LLWearableType::EType type, U32 index) { - LLUUID item_id = getWearableItemID(type); + llassert_always(index == 0); + LLUUID item_id = getWearableItemID(type,index); LLInventoryItem* item = NULL; if(item_id.notNull()) { @@ -558,12 +597,15 @@ LLInventoryItem* LLAgentWearables::getWearableInventoryItem(LLWearableType::ETyp const LLWearable* LLAgentWearables::getWearableFromItemID( const LLUUID& item_id ) const { const LLUUID& base_item_id = gInventory.getLinkedItemID(item_id); - for( S32 i=0; i < LLWearableType::WT_COUNT; i++ ) + for (S32 i=0; i < LLWearableType::WT_COUNT; i++) { - const LLWearable * curr_wearable = getWearable((LLWearableType::EType)i); - if (curr_wearable && (curr_wearable->getItemID() == base_item_id)) + for (U32 j=0; j < getWearableCount((LLWearableType::EType)i); j++) { - return curr_wearable; + const LLWearable * curr_wearable = getWearable((LLWearableType::EType)i, j); + if (curr_wearable && (curr_wearable->getItemID() == base_item_id)) + { + return curr_wearable; + } } } return NULL; @@ -572,12 +614,15 @@ const LLWearable* LLAgentWearables::getWearableFromItemID( const LLUUID& item_id LLWearable* LLAgentWearables::getWearableFromItemID( const LLUUID& item_id ) { const LLUUID& base_item_id = gInventory.getLinkedItemID(item_id); - for( S32 i=0; i < LLWearableType::WT_COUNT; i++ ) + for (S32 i=0; i < LLWearableType::WT_COUNT; i++) { - LLWearable * curr_wearable = getWearable((LLWearableType::EType)i); - if (curr_wearable && (curr_wearable->getItemID() == base_item_id)) + for (U32 j=0; j < getWearableCount((LLWearableType::EType)i); j++) { - return curr_wearable; + LLWearable * curr_wearable = getWearable((LLWearableType::EType)i, j); + if (curr_wearable && (curr_wearable->getItemID() == base_item_id)) + { + return curr_wearable; + } } } return NULL; @@ -587,10 +632,13 @@ LLWearable* LLAgentWearables::getWearableFromAssetID(const LLUUID& asset_id) { for (S32 i=0; i < LLWearableType::WT_COUNT; i++) { - LLWearable * curr_wearable = getWearable((LLWearableType::EType)i); - if (curr_wearable && (curr_wearable->getAssetID() == asset_id)) + for (U32 j=0; j < getWearableCount((LLWearableType::EType)i); j++) { - return curr_wearable; + LLWearable * curr_wearable = getWearable((LLWearableType::EType)i, j); + if (curr_wearable && (curr_wearable->getAssetID() == asset_id)) + { + return curr_wearable; + } } } return NULL; @@ -612,14 +660,14 @@ BOOL LLAgentWearables::selfHasWearable(LLWearableType::EType type) return (gAgentWearables.getWearableCount(type) > 0); } -LLWearable* LLAgentWearables::getWearable(const LLWearableType::EType type) +LLWearable* LLAgentWearables::getWearable(const LLWearableType::EType type, U32 index) { + llassert_always(index == 0); wearableentry_map_t::iterator wearable_iter = mWearableDatas.find(type); if (wearable_iter == mWearableDatas.end()) { return NULL; } - U32 index = 0; //Remove when multi-wearables are implemented. wearableentry_vec_t& wearable_vec = wearable_iter->second; if (index>=wearable_vec.size()) { @@ -631,17 +679,16 @@ LLWearable* LLAgentWearables::getWearable(const LLWearableType::EType type) } } -void LLAgentWearables::setWearable(const LLWearableType::EType type, LLWearable *wearable) +void LLAgentWearables::setWearable(const LLWearableType::EType type, U32 index, LLWearable *wearable) { - - LLWearable *old_wearable = getWearable(type); + llassert_always(index == 0); + LLWearable *old_wearable = getWearable(type,index); if (!old_wearable) { pushWearable(type,wearable); return; } - U32 index = 0; //Remove when multi-wearables are implemented. wearableentry_map_t::iterator wearable_iter = mWearableDatas.find(type); if (wearable_iter == mWearableDatas.end()) { @@ -692,22 +739,23 @@ void LLAgentWearables::popWearable(LLWearable *wearable) // nothing to do here. move along. return; } - - U32 index = 0; //Remove when multi-wearables are implemented. + + U32 index = getWearableIndex(wearable); LLWearableType::EType type = wearable->getType(); if (index < MAX_CLOTHING_PER_TYPE && index < getWearableCount(type)) { - popWearable(type); + popWearable(type, index); } } -void LLAgentWearables::popWearable(const LLWearableType::EType type) +void LLAgentWearables::popWearable(const LLWearableType::EType type, U32 index) { - LLWearable *wearable = getWearable(type); + llassert_always(index == 0); + LLWearable *wearable = getWearable(type, index); if (wearable) { - mWearableDatas[type].erase(mWearableDatas[type].begin()); + mWearableDatas[type].erase(mWearableDatas[type].begin() + index); gAgentAvatarp->wearableUpdated(wearable->getType(), TRUE); wearable->setLabelUpdated(); } @@ -739,15 +787,14 @@ U32 LLAgentWearables::getWearableIndex(const LLWearable *wearable) const return MAX_CLOTHING_PER_TYPE; } - -const LLWearable* LLAgentWearables::getWearable(const LLWearableType::EType type) const +const LLWearable* LLAgentWearables::getWearable(const LLWearableType::EType type, U32 index) const { + llassert_always(index == 0); wearableentry_map_t::const_iterator wearable_iter = mWearableDatas.find(type); if (wearable_iter == mWearableDatas.end()) { return NULL; } - U32 index = 0; //Remove when multi-wearables are implemented. const wearableentry_vec_t& wearable_vec = wearable_iter->second; if (index>=wearable_vec.size()) { @@ -767,7 +814,7 @@ LLWearable* LLAgentWearables::getTopWearable(const LLWearableType::EType type) return NULL; } - return getWearable(type); + return getWearable(type, count-1); } LLWearable* LLAgentWearables::getBottomWearable(const LLWearableType::EType type) @@ -777,7 +824,7 @@ LLWearable* LLAgentWearables::getBottomWearable(const LLWearableType::EType type return NULL; } - return getWearable(type); + return getWearable(type, 0); } U32 LLAgentWearables::getWearableCount(const LLWearableType::EType type) const @@ -798,18 +845,20 @@ U32 LLAgentWearables::getWearableCount(const U32 tex_index) const } -const LLUUID LLAgentWearables::getWearableItemID(LLWearableType::EType type) const +const LLUUID LLAgentWearables::getWearableItemID(LLWearableType::EType type, U32 index) const { - const LLWearable *wearable = getWearable(type); + llassert_always(index == 0); + const LLWearable *wearable = getWearable(type,index); if (wearable) return wearable->getItemID(); else return LLUUID(); } -const LLUUID LLAgentWearables::getWearableAssetID(LLWearableType::EType type) const +const LLUUID LLAgentWearables::getWearableAssetID(LLWearableType::EType type, U32 index) const { - const LLWearable *wearable = getWearable(type); + llassert_always(index == 0); + const LLWearable *wearable = getWearable(type,index); if (wearable) return wearable->getAssetID(); else @@ -822,8 +871,12 @@ BOOL LLAgentWearables::isWearingItem( const LLUUID& item_id ) const return (getWearableFromItemID(base_item_id) != NULL); } +// MULTI-WEARABLE: DEPRECATED (see backwards compatibility) // static -void LLAgentWearables::processAgentInitialWearablesUpdate( LLMessageSystem* mesgsys, void** user_data ) +// ! BACKWARDS COMPATIBILITY ! When we stop supporting viewer1.23, we can assume +// that viewers have a Current Outfit Folder and won't need this message, and thus +// we can remove/ignore this whole function. EXCEPT gAgentWearables.notifyLoadingStarted +void LLAgentWearables::processAgentInitialWearablesUpdate(LLMessageSystem* mesgsys, void** user_data) { // We should only receive this message a single time. Ignore subsequent AgentWearablesUpdates // that may result from AgentWearablesRequest having been sent more than once. @@ -881,7 +934,7 @@ void LLAgentWearables::processAgentInitialWearablesUpdate( LLMessageSystem* mesg asset_id_array[type] = std::pair(asset_id,item_id); } - LL_DEBUGS("Wearables") << " " << LLWearableType::getTypeLabel(type) << " " << asset_id << " item id " << gAgentWearables.getWearableItemID(type).asString() << LL_ENDL; + LL_DEBUGS("Wearables") << " " << LLWearableType::getTypeLabel(type) << " " << asset_id << " item id " << gAgentWearables.getWearableItemID(type, 0).asString() << LL_ENDL; } LLCOFMgr::instance().fetchCOF(); @@ -928,7 +981,7 @@ void LLAgentWearables::onInitialWearableAssetArrived( LLWearable* wearable, void { llassert( type == wearable->getType() ); wearable->setItemID(item_id); - gAgentWearables.setWearable(type,wearable); + gAgentWearables.setWearable(type,0,wearable); // disable composites if initial textures are baked avatar->setupComposites(); @@ -941,7 +994,7 @@ void LLAgentWearables::onInitialWearableAssetArrived( LLWearable* wearable, void else { // Somehow the asset doesn't exist in the database. - gAgentWearables.recoverMissingWearable( type ); + gAgentWearables.recoverMissingWearable( type, 0 ); } gInventory.notifyObservers(); @@ -952,7 +1005,7 @@ void LLAgentWearables::onInitialWearableAssetArrived( LLWearable* wearable, void gAgentWearables.mWearablesLoaded = TRUE; for( S32 i = 0; i < LLWearableType::WT_COUNT; i++ ) { - if( !gAgentWearables.getWearableItemID((LLWearableType::EType)i).isNull() && !gAgentWearables.getWearable((LLWearableType::EType)i) ) + if( !gAgentWearables.getWearableItemID((LLWearableType::EType)i, 0).isNull() && !gAgentWearables.getWearable((LLWearableType::EType)i, 0) ) { gAgentWearables.mWearablesLoaded = FALSE; break; @@ -977,14 +1030,15 @@ void LLAgentWearables::onInitialWearableAssetArrived( LLWearable* wearable, void // Normally, all wearables referred to "AgentWearablesUpdate" will correspond to actual assets in the // database. If for some reason, we can't load one of those assets, we can try to reconstruct it so that // the user isn't left without a shape, for example. (We can do that only after the inventory has loaded.) -void LLAgentWearables::recoverMissingWearable( LLWearableType::EType type ) +void LLAgentWearables::recoverMissingWearable(const LLWearableType::EType type, U32 index) { + llassert_always(index == 0); // Try to recover by replacing missing wearable with a new one. LLNotificationsUtil::add("ReplacedMissingWearable"); lldebugs << "Wearable " << LLWearableType::getTypeLabel( type ) << " could not be downloaded. Replaced inventory item with default wearable." << llendl; LLWearable* new_wearable = LLWearableList::instance().createNewWearable(type); - setWearable(type,new_wearable); + setWearable(type,index,new_wearable); new_wearable->writeToAvatar( TRUE ); // Add a new one in the lost and found folder. @@ -995,6 +1049,7 @@ void LLAgentWearables::recoverMissingWearable( LLWearableType::EType type ) new addWearableToAgentInventoryCallback( LLPointer(NULL), type, + index, new_wearable, addWearableToAgentInventoryCallback::CALL_RECOVERDONE); addWearableToAgentInventory( cb, new_wearable, lost_and_found_id, TRUE); @@ -1063,15 +1118,16 @@ void LLAgentWearables::createStandardWearables(BOOL female) new addWearableToAgentInventoryCallback( donecb, (LLWearableType::EType)i, + 0, wearable, addWearableToAgentInventoryCallback::CALL_CREATESTANDARDDONE); addWearableToAgentInventory(cb, wearable, LLUUID::null, FALSE); } } } -void LLAgentWearables::createStandardWearablesDone(S32 index) +void LLAgentWearables::createStandardWearablesDone(S32 type, U32 index) { - LLWearable* wearable = getWearable((LLWearableType::EType)index); + LLWearable* wearable = getWearable((LLWearableType::EType)type, index); if (wearable) { @@ -1126,10 +1182,10 @@ void LLAgentWearables::makeNewOutfit( for( i = 0; i < count; ++i ) { S32 index = wearables_to_include[i]; - LLWearable* old_wearable = getWearable((LLWearableType::EType)index); + LLWearable* old_wearable = getWearable((LLWearableType::EType)index, 0); if( old_wearable ) { - LLViewerInventoryItem* item = gInventory.getItem(getWearableItemID((LLWearableType::EType)index)); + LLViewerInventoryItem* item = gInventory.getItem(getWearableItemID((LLWearableType::EType)index, 0)); llassert(item); if (!item) continue; @@ -1157,7 +1213,7 @@ void LLAgentWearables::makeNewOutfit( LLStringUtil::truncate(new_name, DB_INV_ITEM_NAME_STR_LEN); } - if (fUseLinks || isWearableCopyable((LLWearableType::EType)index)) + if (fUseLinks || isWearableCopyable((LLWearableType::EType)index, 0)) { LLWearable* new_wearable = LLWearableList::instance().createCopy(old_wearable); if (rename_clothing) @@ -1178,9 +1234,10 @@ void LLAgentWearables::makeNewOutfit( new addWearableToAgentInventoryCallback( cbdone, (LLWearableType::EType)index, + 0, new_wearable, todo); - if (isWearableCopyable((LLWearableType::EType)index)) + if (isWearableCopyable((LLWearableType::EType)index, 0)) { copy_inventory_item( gAgent.getID(), @@ -1292,9 +1349,9 @@ void LLAgentWearables::makeNewOutfit( } } -void LLAgentWearables::makeNewOutfitDone(S32 type) +void LLAgentWearables::makeNewOutfitDone(S32 type, U32 index) { - LLUUID first_item_id = getWearableItemID((LLWearableType::EType)type); + LLUUID first_item_id = getWearableItemID((LLWearableType::EType)type, index); // Open the inventory and select the first item we added. if( first_item_id.notNull() ) { @@ -1325,15 +1382,16 @@ void LLAgentWearables::addWearableToAgentInventory(LLPointerisDirty() ) + removeWearableFinal(type, do_remove_all, index); + } + else + { + LLWearable* old_wearable = getWearable(type,index); + + if (old_wearable) { - LLSD payload; - payload["wearable_type"] = (S32)type; - // Bring up view-modal dialog: Save changes? Yes, No, Cancel - LLNotificationsUtil::add("WearableSave", LLSD(), payload, &LLAgentWearables::onRemoveWearableDialog); - return; - } - else - { - removeWearableFinal( type ); + if (old_wearable->isDirty()) + { + LLSD payload; + payload["wearable_type"] = (S32)type; + payload["wearable_index"] = (S32)index; + // Bring up view-modal dialog: Save changes? Yes, No, Cancel + LLNotificationsUtil::add("WearableSave", LLSD(), payload, &LLAgentWearables::onRemoveWearableDialog); + return; + } + else + { + removeWearableFinal(type, do_remove_all, index); + } } } } + // static -bool LLAgentWearables::onRemoveWearableDialog(const LLSD& notification, const LLSD& response ) +bool LLAgentWearables::onRemoveWearableDialog(const LLSD& notification, const LLSD& response) { S32 option = LLNotificationsUtil::getSelectedOption(notification, response); LLWearableType::EType type = (LLWearableType::EType)notification["payload"]["wearable_type"].asInteger(); - switch( option ) + S32 index = (S32)notification["payload"]["wearable_index"].asInteger(); + switch(option) { - case 0: // "Save" - gAgentWearables.saveWearable( type ); - gAgentWearables.removeWearableFinal( type ); - break; + case 0: // "Save" + gAgentWearables.saveWearable(type, index); + gAgentWearables.removeWearableFinal(type, false, index); + break; - case 1: // "Don't Save" - gAgentWearables.removeWearableFinal( type ); - break; + case 1: // "Don't Save" + gAgentWearables.removeWearableFinal(type, false, index); + break; case 2: // "Cancel" break; @@ -1393,17 +1460,35 @@ bool LLAgentWearables::onRemoveWearableDialog(const LLSD& notification, const LL } // Called by removeWearable() and onRemoveWearableDialog() to actually do the removal. -void LLAgentWearables::removeWearableFinal( LLWearableType::EType type ) +void LLAgentWearables::removeWearableFinal( LLWearableType::EType type, bool do_remove_all, U32 index) { - gInventory.addChangedMask( LLInventoryObserver::LABEL, getWearableItemID(type) ); - - LLWearable* old_wearable = getWearable(type); - //queryWearableCache(); - - if( old_wearable ) + llassert_always(index == 0); + gInventory.addChangedMask( LLInventoryObserver::LABEL, getWearableItemID(type, index) ); + if (do_remove_all) { - popWearable(old_wearable); - old_wearable->removeFromAvatar( TRUE ); + S32 max_entry = mWearableDatas[type].size()-1; + for (S32 i=max_entry; i>=0; i--) + { + LLWearable* old_wearable = getWearable(type,i); + //queryWearableCache(); // moved below + if (old_wearable) + { + popWearable(old_wearable); + old_wearable->removeFromAvatar(TRUE); + } + } + mWearableDatas[type].clear(); + } + else + { + LLWearable* old_wearable = getWearable(type, index); + //queryWearableCache(); // moved below + + if (old_wearable) + { + popWearable(old_wearable); + old_wearable->removeFromAvatar(TRUE); + } } queryWearableCache(); @@ -1413,47 +1498,6 @@ void LLAgentWearables::removeWearableFinal( LLWearableType::EType type ) gInventory.notifyObservers(); } -void LLAgentWearables::copyWearableToInventory( LLWearableType::EType type ) -{ - LLWearable* wearable = getWearable(type); - if( wearable ) - { - // Save the old wearable if it has changed. - if( wearable->isDirty() ) - { - LLWearable * new_wearable = LLWearableList::instance().createCopyFromAvatar( wearable ); - new_wearable->setItemID(wearable->getItemID()); - setWearable(type,new_wearable); - wearable = new_wearable; - } - - // Make a new entry in the inventory. (Put it in the same folder as the original item if possible.) - LLUUID category_id; - LLInventoryItem* item = gInventory.getItem( wearable->getItemID() ); - if( item ) - { - category_id = item->getParentUUID(); - wearable->setPermissions(item->getPermissions()); - } - LLPointer cb = - new addWearableToAgentInventoryCallback( - LLPointer(NULL), - type, - wearable); - addWearableToAgentInventory(cb, wearable, category_id); - } -} - - -// A little struct to let setWearable() communicate more than one value with onSetWearableDialog(). -struct LLSetWearableData -{ - LLSetWearableData( const LLUUID& new_item_id, LLWearable* new_wearable ) : - mNewItemID( new_item_id ), mNewWearable( new_wearable ) {} - LLUUID mNewItemID; - LLWearable* mNewWearable; -}; - static bool isFirstPhysicsWearable(LLWearableType::EType type, LLInventoryItem *new_item, LLWearable *new_wearable) { if (type == LLWearableType::WT_PHYSICS && gSavedSettings.getWarning("FirstPhysicsWearable")) @@ -1529,10 +1573,10 @@ void LLAgentWearables::setWearableOutfit(const LLInventoryItem::item_array_t& it LLWearableType::EType type = new_wearable->getType(); wearables_to_remove[type] = FALSE; - LLWearable* old_wearable = getWearable(type); + LLWearable* old_wearable = getWearable(type, 0); if( old_wearable ) { - const LLUUID& old_item_id = getWearableItemID(type); + const LLUUID& old_item_id = getWearableItemID(type, 0); if( (old_wearable->getAssetID() == new_wearable->getAssetID()) && (old_item_id == new_item->getUUID()) ) { @@ -1561,11 +1605,11 @@ void LLAgentWearables::setWearableOutfit(const LLInventoryItem::item_array_t& it if (LLWearableType::getAssetType(type) == LLAssetType::AT_BODYPART) { // exactly one wearable per body part - setWearable(type,new_wearable); + setWearable(type,0,new_wearable); } else if(old_wearable) //Remove when multi-wearables are implemented. { - setWearable(type,new_wearable); + setWearable(type,0,new_wearable); } else { @@ -1580,8 +1624,8 @@ void LLAgentWearables::setWearableOutfit(const LLInventoryItem::item_array_t& it { if( wearables_to_remove[i] ) { - LLWearable* wearable = getWearable((LLWearableType::EType)i); - wearables_being_removed.push_back(getWearable((LLWearableType::EType)i)); + LLWearable* wearable = getWearable((LLWearableType::EType)i, 0); + wearables_being_removed.push_back(getWearable((LLWearableType::EType)i, 0)); popWearable(wearable); gInventory.addChangedMask(LLInventoryObserver::LABEL, wearable->getItemID()); @@ -1644,7 +1688,7 @@ void LLAgentWearables::setWearableItem( LLInventoryItem* new_item, LLWearable* n return; } - LLWearable* old_wearable = getWearable(type); + LLWearable* old_wearable = getWearable(type,0); if( old_wearable ) { const LLUUID& old_item_id = old_wearable->getItemID(); @@ -1673,6 +1717,7 @@ bool LLAgentWearables::onSetWearableDialog( const LLSD& notification, const LLSD { S32 option = LLNotificationsUtil::getSelectedOption(notification, response); LLInventoryItem* new_item = gInventory.getItem( notification["payload"]["item_id"].asUUID()); + U32 index = gAgentWearables.getWearableIndex(wearable); if( !new_item ) { delete wearable; @@ -1682,7 +1727,7 @@ bool LLAgentWearables::onSetWearableDialog( const LLSD& notification, const LLSD switch( option ) { case 0: // "Save" - gAgentWearables.saveWearable( wearable->getType() ); + gAgentWearables.saveWearable(wearable->getType(),index); gAgentWearables.setWearableFinal( new_item, wearable ); break; @@ -1707,24 +1752,29 @@ void LLAgentWearables::setWearableFinal( LLInventoryItem* new_item, LLWearable* { const LLWearableType::EType type = new_wearable->getType(); - // Replace the old wearable with a new one. - llassert( new_item->getAssetUUID() == new_wearable->getAssetID() ); - LLWearable *old_wearable = getWearable(type); - LLUUID old_item_id; - if (old_wearable) { - old_item_id = old_wearable->getItemID(); - } - new_wearable->setItemID(new_item->getUUID()); - setWearable(type,new_wearable); + // Replace the old wearable with a new one. + llassert(new_item->getAssetUUID() == new_wearable->getAssetID()); - if (old_item_id.notNull()) - { - gInventory.addChangedMask( LLInventoryObserver::LABEL, old_item_id ); - gInventory.notifyObservers(); + LLWearable *old_wearable = getWearable(type,0); + LLUUID old_item_id; + if (old_wearable) + { + old_item_id = old_wearable->getItemID(); + } + new_wearable->setItemID(new_item->getUUID()); + setWearable(type,0,new_wearable); + + if (old_item_id.notNull()) + { + gInventory.addChangedMask(LLInventoryObserver::LABEL, old_item_id); + gInventory.notifyObservers(); + } + llinfos << "Replaced current element 0 for type " << type + << " size is now " << mWearableDatas[type].size() << llendl; } - //llinfos << "LLVOAvatar::setWearable()" << llendl; + //llinfos << "LLVOAvatar::setWearableItem()" << llendl; queryWearableCache(); new_wearable->writeToAvatar( TRUE ); @@ -1793,13 +1843,16 @@ LLUUID LLAgentWearables::computeBakedTextureHash(LLVOAvatarDefines::EBakedTextur for (U8 i=0; i < baked_dict->mWearables.size(); i++) { const LLWearableType::EType baked_type = baked_dict->mWearables[i]; - //TO-DO: MULTI-WEARABLE - const LLWearable* wearable = getWearable(baked_type); - if (wearable) + const U32 num_wearables = getWearableCount(baked_type); + for (U32 index = 0; index < num_wearables; ++index) { - LLUUID asset_id = wearable->getAssetID(); - hash.update((const unsigned char*)asset_id.mData, UUID_BYTES); - hash_computed = true; + const LLWearable* wearable = getWearable(baked_type,index); + if (wearable) + { + LLUUID asset_id = wearable->getAssetID(); + hash.update((const unsigned char*)asset_id.mData, UUID_BYTES); + hash_computed = true; + } } } if (hash_computed) @@ -1823,12 +1876,22 @@ LLUUID LLAgentWearables::computeBakedTextureHash(LLVOAvatarDefines::EBakedTextur // User has picked "remove from avatar" from a menu. // static -void LLAgentWearables::userRemoveWearable(const LLWearableType::EType &type) +void LLAgentWearables::userRemoveWearable(const LLWearableType::EType &type, const U32 &index) { if( !(type==LLWearableType::WT_SHAPE || type==LLWearableType::WT_SKIN || type==LLWearableType::WT_HAIR || type==LLWearableType::WT_EYES) ) //&& //!((!gAgent.isTeen()) && ( type==WT_UNDERPANTS || type==WT_UNDERSHIRT )) ) { - gAgentWearables.removeWearable( type ); + gAgentWearables.removeWearable(type,false,index); + } +} + +//static +void LLAgentWearables::userRemoveWearablesOfType(const LLWearableType::EType &type) +{ + if (!(type==LLWearableType::WT_SHAPE || type==LLWearableType::WT_SKIN || type==LLWearableType::WT_HAIR || type==LLWearableType::WT_EYES)) //&& + //!((!gAgent.isTeen()) && (type==LLWearableType::WT_UNDERPANTS || type==LLWearableType::WT_UNDERSHIRT))) + { + gAgentWearables.removeWearable(type,true,0); } } @@ -1849,18 +1912,18 @@ void LLAgentWearables::userRemoveAllClothesStep2( BOOL proceed, void* userdata ) { if( proceed ) { - gAgentWearables.removeWearable( LLWearableType::WT_SHIRT ); - gAgentWearables.removeWearable( LLWearableType::WT_PANTS ); - gAgentWearables.removeWearable( LLWearableType::WT_SHOES ); - gAgentWearables.removeWearable( LLWearableType::WT_SOCKS ); - gAgentWearables.removeWearable( LLWearableType::WT_JACKET ); - gAgentWearables.removeWearable( LLWearableType::WT_GLOVES ); - gAgentWearables.removeWearable( LLWearableType::WT_UNDERSHIRT ); - gAgentWearables.removeWearable( LLWearableType::WT_UNDERPANTS ); - gAgentWearables.removeWearable( LLWearableType::WT_SKIRT ); - gAgentWearables.removeWearable( LLWearableType::WT_ALPHA ); - gAgentWearables.removeWearable( LLWearableType::WT_TATTOO ); - gAgentWearables.removeWearable( LLWearableType::WT_PHYSICS ); + gAgentWearables.userRemoveWearablesOfType( LLWearableType::WT_SHIRT ); + gAgentWearables.userRemoveWearablesOfType( LLWearableType::WT_PANTS ); + gAgentWearables.userRemoveWearablesOfType( LLWearableType::WT_SHOES ); + gAgentWearables.userRemoveWearablesOfType( LLWearableType::WT_SOCKS ); + gAgentWearables.userRemoveWearablesOfType( LLWearableType::WT_JACKET ); + gAgentWearables.userRemoveWearablesOfType( LLWearableType::WT_GLOVES ); + gAgentWearables.userRemoveWearablesOfType( LLWearableType::WT_UNDERSHIRT ); + gAgentWearables.userRemoveWearablesOfType( LLWearableType::WT_UNDERPANTS ); + gAgentWearables.userRemoveWearablesOfType( LLWearableType::WT_SKIRT ); + gAgentWearables.userRemoveWearablesOfType( LLWearableType::WT_ALPHA ); + gAgentWearables.userRemoveWearablesOfType( LLWearableType::WT_TATTOO ); + gAgentWearables.userRemoveWearablesOfType( LLWearableType::WT_PHYSICS ); } } @@ -2099,7 +2162,7 @@ void LLAgentWearables::updateWearablesLoaded() mWearablesLoaded = TRUE; for( S32 i = 0; i < LLWearableType::WT_COUNT; i++ ) { - if( !getWearableItemID((LLWearableType::EType)i).isNull() && !getWearable((LLWearableType::EType)i) ) + if( !getWearableItemID((LLWearableType::EType)i, 0).isNull() && !getWearable((LLWearableType::EType)i, 0) ) { mWearablesLoaded = FALSE; break; diff --git a/indra/newview/llagentwearables.h b/indra/newview/llagentwearables.h index 70f9b0969..630d57525 100644 --- a/indra/newview/llagentwearables.h +++ b/indra/newview/llagentwearables.h @@ -70,7 +70,7 @@ public: // LLInitClass interface static void initClass(); protected: - void createStandardWearablesDone(S32 type); + void createStandardWearablesDone(S32 type, U32 index/* = 0*/); void createStandardWearablesAllDone(); //-------------------------------------------------------------------- @@ -78,10 +78,10 @@ protected: //-------------------------------------------------------------------- public: BOOL isWearingItem(const LLUUID& item_id) const; - BOOL isWearableModifiable(LLWearableType::EType type) const; + BOOL isWearableModifiable(LLWearableType::EType type, U32 index /*= 0*/) const; BOOL isWearableModifiable(const LLUUID& item_id) const; - BOOL isWearableCopyable(LLWearableType::EType type) const; + BOOL isWearableCopyable(LLWearableType::EType type, U32 index /*= 0*/) const; BOOL areWearablesLoaded() const; void updateWearablesLoaded(); //void checkWearablesLoaded() const; @@ -93,28 +93,26 @@ public: //void animateAllWearableParams(F32 delta, BOOL upload_bake); BOOL needsReplacement(LLWearableType::EType wearableType, S32 remove); - U32 getWearablePermMask(LLWearableType::EType type) const; + //U32 getWearablePermMask(LLWearableType::EType type) const; //-------------------------------------------------------------------- // Accessors //-------------------------------------------------------------------- public: - const LLUUID getWearableItemID(LLWearableType::EType type ) const; - const LLUUID getWearableAssetID(LLWearableType::EType type) const; + const LLUUID getWearableItemID(LLWearableType::EType type, U32 index /*= 0*/) const; + const LLUUID getWearableAssetID(LLWearableType::EType type, U32 index /*= 0*/) const; const LLWearable* getWearableFromItemID(const LLUUID& item_id) const; - LLWearable* getWearableFromItemID(const LLUUID& item_id); - LLWearable* getWearableFromAssetID(const LLUUID& asset_id); - LLInventoryItem* getWearableInventoryItem(LLWearableType::EType type); + LLWearable* getWearableFromItemID(const LLUUID& item_id); + LLWearable* getWearableFromAssetID(const LLUUID& asset_id); + LLInventoryItem* getWearableInventoryItem(LLWearableType::EType type, U32 index /*= 0*/); static BOOL selfHasWearable(LLWearableType::EType type); - LLWearable* getWearable( const LLWearableType::EType type ); - const LLWearable* getWearable( const LLWearableType::EType type ) const; - LLWearable* getTopWearable(const LLWearableType::EType type); + LLWearable* getWearable(const LLWearableType::EType type, U32 index /*= 0*/); + const LLWearable* getWearable(const LLWearableType::EType type, U32 index /*= 0*/) const; + LLWearable* getTopWearable(const LLWearableType::EType type); LLWearable* getBottomWearable(const LLWearableType::EType type); U32 getWearableCount(const LLWearableType::EType type) const; U32 getWearableCount(const U32 tex_index) const; - void copyWearableToInventory( LLWearableType::EType type ); - static const U32 MAX_CLOTHING_PER_TYPE = 1; @@ -124,11 +122,11 @@ public: private: // Low-level data structure setter - public access is via setWearableItem, etc. - void setWearable(const LLWearableType::EType type, LLWearable *wearable); + void setWearable(const LLWearableType::EType type, U32 index, LLWearable *wearable); U32 pushWearable(const LLWearableType::EType type, LLWearable *wearable); void wearableUpdated(LLWearable *wearable); void popWearable(LLWearable *wearable); - void popWearable(const LLWearableType::EType type); + void popWearable(const LLWearableType::EType type, U32 index); public: void setWearableItem(LLInventoryItem* new_item, LLWearable* wearable); @@ -156,11 +154,11 @@ protected: * @param item_id The inventory item id of the new wearable to wear. * @param wearable The actual wearable data. */ - void addWearabletoAgentInventoryDone(const LLWearableType::EType type, - const LLUUID& item_id, - LLWearable* wearable); - - void recoverMissingWearable(LLWearableType::EType type); + void addWearabletoAgentInventoryDone(const LLWearableType::EType type, + const U32 index, + const LLUUID& item_id, + LLWearable* wearable); + void recoverMissingWearable(const LLWearableType::EType type, U32 index /*= 0*/); void recoverMissingWearableDone(); //-------------------------------------------------------------------- @@ -182,9 +180,9 @@ private: // Removing wearables //-------------------------------------------------------------------- public: - void removeWearable( LLWearableType::EType type ); + void removeWearable(const LLWearableType::EType type, bool do_remove_all /*= false*/, U32 index /*= 0*/); private: - void removeWearableFinal( LLWearableType::EType type ); + void removeWearableFinal(const LLWearableType::EType type, bool do_remove_all /*= false*/, U32 index /*= 0*/); protected: static bool onRemoveWearableDialog(const LLSD& notification, const LLSD& response); static void userRemoveAllClothesStep2(BOOL proceed, void* userdata ); // userdata is NULL @@ -220,25 +218,26 @@ public: BOOL rename_clothing); private: - void makeNewOutfitDone(S32 type); + void makeNewOutfitDone(S32 type, U32 index); //-------------------------------------------------------------------- // Save Wearables //-------------------------------------------------------------------- public: - void saveWearableAs(const LLWearableType::EType type, const std::string& new_name, BOOL save_in_lost_and_found ); - void saveWearable(const LLWearableType::EType type, BOOL send_update = TRUE, + void saveWearableAs(const LLWearableType::EType type, const U32 index, const std::string& new_name, BOOL save_in_lost_and_found ); + void saveWearable(const LLWearableType::EType type, const U32 index, BOOL send_update = TRUE, const std::string new_name = ""); void saveAllWearables(); - void revertWearable( LLWearableType::EType type ); + void revertWearable( LLWearableType::EType type, const U32 index); void revertAllWearables(); //-------------------------------------------------------------------- // Static UI hooks //-------------------------------------------------------------------- public: - static void userRemoveWearable(const LLWearableType::EType &type); + static void userRemoveWearable(const LLWearableType::EType &type, const U32 &index); + static void userRemoveWearablesOfType(const LLWearableType::EType &type); static void userRemoveAllClothes(); typedef std::vector llvo_vec_t; @@ -321,12 +320,14 @@ private: */ addWearableToAgentInventoryCallback(LLPointer cb, LLWearableType::EType type, + U32 index, LLWearable* wearable, U32 todo = CALL_NONE); virtual void fire(const LLUUID& inv_item); private: LLWearableType::EType mType; + U32 mIndex; LLWearable* mWearable; U32 mTodo; LLPointer mCB; diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 568f6a4e6..53ed265eb 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -592,6 +592,7 @@ bool LLAppViewer::init() // into the log files during normal startup until AFTER // we run the "program crashed last time" error handler below. // + LLFastTimer::reset(); // initialize SSE options LLVector4a::initClass(); @@ -1004,6 +1005,21 @@ void LLAppViewer::checkMemory() LLMemory::logMemoryInfo() ; } } + +static LLFastTimer::DeclareTimer FTM_MESSAGES("System Messages"); +static LLFastTimer::DeclareTimer FTM_SLEEP("Sleep"); +static LLFastTimer::DeclareTimer FTM_TEXTURE_CACHE("Texture Cache"); +static LLFastTimer::DeclareTimer FTM_DECODE("Image Decode"); +static LLFastTimer::DeclareTimer FTM_VFS("VFS Thread"); +static LLFastTimer::DeclareTimer FTM_LFS("LFS Thread"); +static LLFastTimer::DeclareTimer FTM_PAUSE_THREADS("Pause Threads"); +static LLFastTimer::DeclareTimer FTM_IDLE("Idle"); +static LLFastTimer::DeclareTimer FTM_PUMP("Pump"); +static LLFastTimer::DeclareTimer FTM_PUMP_ARES("Ares"); +static LLFastTimer::DeclareTimer FTM_PUMP_SERVICE("Service"); +static LLFastTimer::DeclareTimer FTM_SERVICE_CALLBACK("Callback"); +static LLFastTimer::DeclareTimer FTM_AGENT_AUTOPILOT("Autopilot"); +static LLFastTimer::DeclareTimer FTM_AGENT_UPDATE("Update"); bool LLAppViewer::mainLoop() { mMainloopTimeout = new LLWatchdogTimeout(); @@ -1035,7 +1051,7 @@ bool LLAppViewer::mainLoop() // Handle messages while (!LLApp::isExiting()) { - LLFastTimer::reset(); // Should be outside of any timer instances + LLFastTimer::nextFrame(); // Should be outside of any timer instances //clear call stack records llclearcallstacks; @@ -1045,26 +1061,25 @@ bool LLAppViewer::mainLoop() try { - LLFastTimer t(LLFastTimer::FTM_FRAME); pingMainloopTimeout("Main:MiscNativeWindowEvents"); if (gViewerWindow) { - LLFastTimer t2(LLFastTimer::FTM_MESSAGES); - gViewerWindow->mWindow->processMiscNativeEvents(); + LLFastTimer t2(FTM_MESSAGES); + gViewerWindow->getWindow()->processMiscNativeEvents(); } pingMainloopTimeout("Main:GatherInput"); if (gViewerWindow) { - LLFastTimer t2(LLFastTimer::FTM_MESSAGES); + LLFastTimer t2(FTM_MESSAGES); if (!restoreErrorTrap()) { llwarns << " Someone took over my signal/exception handler (post messagehandling)!" << llendl; } - gViewerWindow->mWindow->gatherInput(); + gViewerWindow->getWindow()->gatherInput(); } #if 1 && !LL_RELEASE_FOR_DOWNLOAD @@ -1110,18 +1125,28 @@ bool LLAppViewer::mainLoop() { pauseMainloopTimeout(); // *TODO: Remove. Messages shouldn't be stalling for 20+ seconds! - LLFastTimer t3(LLFastTimer::FTM_IDLE); + LLFastTimer t3(FTM_IDLE); // bad_alloc!! idle(); if (gAres != NULL && gAres->isInitialized()) { pingMainloopTimeout("Main:ServicePump"); - LLFastTimer t4(LLFastTimer::FTM_PUMP); - gAres->process(); - // this pump is necessary to make the login screen show up - gServicePump->pump(); - gServicePump->callback(); + LLFastTimer t4(FTM_PUMP); + { + LLFastTimer t(FTM_PUMP_ARES); + gAres->process(); + } + { + LLFastTimer t(FTM_PUMP_SERVICE); + // this pump is necessary to make the login screen show up + gServicePump->pump(); + + { + LLFastTimer t(FTM_SERVICE_CALLBACK); + gServicePump->callback(); + } + } } resumeMainloopTimeout(); @@ -1160,7 +1185,7 @@ bool LLAppViewer::mainLoop() // Sleep and run background threads { - LLFastTimer t2(LLFastTimer::FTM_SLEEP); + LLFastTimer t2(FTM_SLEEP); static const LLCachedControl run_multiple_threads("RunMultipleThreads",false); // yield some time to the os based on command line option @@ -1206,11 +1231,28 @@ bool LLAppViewer::mainLoop() { S32 work_pending = 0; S32 io_pending = 0; - work_pending += LLAppViewer::getTextureCache()->update(1); // unpauses the texture cache thread - work_pending += LLAppViewer::getImageDecodeThread()->update(1); // unpauses the image thread - work_pending += LLAppViewer::getTextureFetch()->update(1); // unpauses the texture fetch thread - io_pending += LLVFSThread::updateClass(1); - io_pending += LLLFSThread::updateClass(1); + { + LLFastTimer ftm(FTM_TEXTURE_CACHE); + work_pending += LLAppViewer::getTextureCache()->update(1); // unpauses the texture cache thread + } + { + LLFastTimer ftm(FTM_DECODE); + work_pending += LLAppViewer::getImageDecodeThread()->update(1); // unpauses the image thread + } + { + LLFastTimer ftm(FTM_DECODE); + work_pending += LLAppViewer::getTextureFetch()->update(1); // unpauses the texture fetch thread + } + + { + LLFastTimer ftm(FTM_VFS); + io_pending += LLVFSThread::updateClass(1); + } + { + LLFastTimer ftm(FTM_LFS); + io_pending += LLLFSThread::updateClass(1); + } + if (io_pending > 1000) { ms_sleep(llmin(io_pending/100,100)); // give the vfs some time to catch up @@ -1762,6 +1804,8 @@ bool LLAppViewer::initThreads() LLWatchdog::getInstance()->init(watchdog_killer_callback); } + LLImage::initClass(); + LLVFSThread::initClass(enable_threads && false); LLLFSThread::initClass(enable_threads && false); @@ -1769,7 +1813,7 @@ bool LLAppViewer::initThreads() LLAppViewer::sImageDecodeThread = new LLImageDecodeThread(enable_threads && true); LLAppViewer::sTextureCache = new LLTextureCache(enable_threads && true); LLAppViewer::sTextureFetch = new LLTextureFetch(LLAppViewer::getTextureCache(), sImageDecodeThread, enable_threads && true); - LLImage::initClass(); + // Mesh streaming and caching gMeshRepo.init(); @@ -2655,6 +2699,8 @@ void LLAppViewer::writeSystemInfo() LL_INFOS("SystemInfo") << "OS: " << getOSInfo().getOSStringSimple() << LL_ENDL; LL_INFOS("SystemInfo") << "OS info: " << getOSInfo() << LL_ENDL; + LL_INFOS("SystemInfo") << "Timers: " << LLFastTimer::sClockType << LL_ENDL; + writeDebugInfo(); // Save out debug_info.log early, in case of crash. } @@ -3638,6 +3684,18 @@ public: } }; +static LLFastTimer::DeclareTimer FTM_AUDIO_UPDATE("Update Audio"); +static LLFastTimer::DeclareTimer FTM_CLEANUP("Cleanup"); +static LLFastTimer::DeclareTimer FTM_CLEANUP_DRAWABLES("Drawables"); +static LLFastTimer::DeclareTimer FTM_CLEANUP_OBJECTS("Objects"); +static LLFastTimer::DeclareTimer FTM_IDLE_CB("Idle Callbacks"); +static LLFastTimer::DeclareTimer FTM_LOD_UPDATE("Update LOD"); +static LLFastTimer::DeclareTimer FTM_OBJECTLIST_UPDATE("Update Objectlist"); +static LLFastTimer::DeclareTimer FTM_REGION_UPDATE("Update Region"); +static LLFastTimer::DeclareTimer FTM_WORLD_UPDATE("Update World"); +static LLFastTimer::DeclareTimer FTM_NETWORK("Network"); +static LLFastTimer::DeclareTimer FTM_AGENT_NETWORK("Agent Network"); +static LLFastTimer::DeclareTimer FTM_VLMANAGER("VL Manager"); /////////////////////////////////////////////////////// // idle() // @@ -3706,7 +3764,7 @@ void LLAppViewer::idle() if (!gDisconnected) { - LLFastTimer t(LLFastTimer::FTM_NETWORK); + LLFastTimer t(FTM_NETWORK); // Update spaceserver timeinfo LLWorld::getInstance()->setSpaceTimeUSec(LLWorld::getInstance()->getSpaceTimeUSec() + (U32)(dt_raw * SEC_TO_MICROSEC)); @@ -3721,9 +3779,12 @@ void LLAppViewer::idle() gAgent.moveYaw(-1.f); } - // Handle automatic walking towards points - gAgentPilot.updateTarget(); - gAgent.autoPilot(&yaw); + { + LLFastTimer t(FTM_AGENT_AUTOPILOT); + // Handle automatic walking towards points + gAgentPilot.updateTarget(); + gAgent.autoPilot(&yaw); + } static LLFrameTimer agent_update_timer; static U32 last_control_flags; @@ -3734,6 +3795,7 @@ void LLAppViewer::idle() if (flags_changed || (agent_update_time > (1.0f / (F32) AGENT_UPDATES_PER_SECOND))) { + LLFastTimer t(FTM_AGENT_UPDATE); // Send avatar and camera info last_control_flags = gAgent.getControlFlags(); if(!gAgent.getPhantom()) @@ -3792,7 +3854,7 @@ void LLAppViewer::idle() if (!gDisconnected) { - LLFastTimer t(LLFastTimer::FTM_NETWORK); + LLFastTimer t(FTM_NETWORK); //////////////////////////////////////////////// // @@ -3824,7 +3886,7 @@ void LLAppViewer::idle() // { -// LLFastTimer t(LLFastTimer::FTM_IDLE_CB); +// LLFastTimer t(FTM_IDLE_CB); // Do event notifications if necessary. Yes, we may want to move this elsewhere. gEventNotifier.update(); @@ -3854,13 +3916,15 @@ void LLAppViewer::idle() { // Handle pending gesture processing + static LLFastTimer::DeclareTimer ftm("Agent Position"); + LLFastTimer t(ftm); LLGestureMgr::instance().update(); gAgent.updateAgentPosition(gFrameDTClamped, yaw, current_mouse.mX, current_mouse.mY); } { - LLFastTimer t(LLFastTimer::FTM_OBJECTLIST_UPDATE); // Actually "object update" + LLFastTimer t(FTM_OBJECTLIST_UPDATE); gFrameStats.start(LLFrameStats::OBJECT_UPDATE); if (!(logoutRequestSent() && hasSavedFinalSnapshot())) @@ -3876,10 +3940,16 @@ void LLAppViewer::idle() // { - LLFastTimer t(LLFastTimer::FTM_CLEANUP); gFrameStats.start(LLFrameStats::CLEAN_DEAD); - gObjectList.cleanDeadObjects(); - LLDrawable::cleanupDeadDrawables(); + LLFastTimer t(FTM_CLEANUP); + { + LLFastTimer t(FTM_CLEANUP_OBJECTS); + gObjectList.cleanDeadObjects(); + } + { + LLFastTimer t(FTM_CLEANUP_DRAWABLES); + LLDrawable::cleanupDeadDrawables(); + } } // @@ -3897,6 +3967,8 @@ void LLAppViewer::idle() { gFrameStats.start(LLFrameStats::UPDATE_EFFECTS); + static LLFastTimer::DeclareTimer ftm("HUD Effects"); + LLFastTimer t(ftm); LLSelectMgr::getInstance()->updateEffects(); LLHUDManager::getInstance()->cleanupEffects(); LLHUDManager::getInstance()->sendEffects(); @@ -3910,7 +3982,7 @@ void LLAppViewer::idle() // { - LLFastTimer t(LLFastTimer::FTM_NETWORK); + LLFastTimer t(FTM_NETWORK); gVLManager.unpackData(); } @@ -3922,7 +3994,7 @@ void LLAppViewer::idle() LLWorld::getInstance()->updateVisibilities(); { const F32 max_region_update_time = .001f; // 1ms - LLFastTimer t(LLFastTimer::FTM_REGION_UPDATE); + LLFastTimer t(FTM_REGION_UPDATE); LLWorld::getInstance()->updateRegions(max_region_update_time); } @@ -3969,7 +4041,7 @@ void LLAppViewer::idle() if (!gNoRender) { - LLFastTimer t(LLFastTimer::FTM_WORLD_UPDATE); + LLFastTimer t(FTM_WORLD_UPDATE); gFrameStats.start(LLFrameStats::UPDATE_MOVE); gPipeline.updateMove(); @@ -3997,13 +4069,13 @@ void LLAppViewer::idle() // objects and camera should be in sync, do LOD calculations now { - LLFastTimer t(LLFastTimer::FTM_LOD_UPDATE); + LLFastTimer t(FTM_LOD_UPDATE); gObjectList.updateApparentAngles(gAgent); } { gFrameStats.start(LLFrameStats::AUDIO); - LLFastTimer t(LLFastTimer::FTM_AUDIO_UPDATE); + LLFastTimer t(FTM_AUDIO_UPDATE); if (gAudiop) { @@ -4204,6 +4276,12 @@ void LLAppViewer::idleNameCache() static F32 CheckMessagesMaxTime = CHECK_MESSAGES_DEFAULT_MAX_TIME; #endif +static LLFastTimer::DeclareTimer FTM_IDLE_NETWORK("Idle Network"); +static LLFastTimer::DeclareTimer FTM_MESSAGE_ACKS("Message Acks"); +static LLFastTimer::DeclareTimer FTM_RETRANSMIT("Retransmit"); +static LLFastTimer::DeclareTimer FTM_TIMEOUT_CHECK("Timeout Check"); +static LLFastTimer::DeclareTimer FTM_DYNAMIC_THROTTLE("Dynamic Throttle"); +static LLFastTimer::DeclareTimer FTM_CHECK_REGION_CIRCUIT("Check Region Circuit"); void LLAppViewer::idleNetwork() { pingMainloopTimeout("idleNetwork"); @@ -4213,7 +4291,7 @@ void LLAppViewer::idleNetwork() if (!gSavedSettings.getBOOL("SpeedTest")) { - LLFastTimer t(LLFastTimer::FTM_IDLE_NETWORK); // decode + LLFastTimer t(FTM_IDLE_NETWORK); // decode llpushcallstacks ; LLTimer check_message_timer; diff --git a/indra/newview/lldrawable.cpp b/indra/newview/lldrawable.cpp index 059198597..946f21fef 100644 --- a/indra/newview/lldrawable.cpp +++ b/indra/newview/lldrawable.cpp @@ -61,6 +61,9 @@ const F32 MAX_INTERPOLATE_DISTANCE_SQUARED = 10.f * 10.f; const F32 OBJECT_DAMPING_TIME_CONSTANT = 0.06f; const F32 MIN_SHADOW_CASTER_RADIUS = 2.0f; +static LLFastTimer::DeclareTimer FTM_CULL_REBOUND("Cull Rebound"); + + //////////////////////// // // Inline implementations. @@ -198,12 +201,16 @@ BOOL LLDrawable::isLight() const } } +static LLFastTimer::DeclareTimer FTM_CLEANUP_DRAWABLE("Cleanup Drawable"); +static LLFastTimer::DeclareTimer FTM_DEREF_DRAWABLE("Deref"); +static LLFastTimer::DeclareTimer FTM_DELETE_FACES("Faces"); + void LLDrawable::cleanupReferences() { - LLFastTimer t(LLFastTimer::FTM_PIPELINE); + LLFastTimer t(FTM_CLEANUP_DRAWABLE); { - //LLFastTimer t(FTM_DELETE_FACES); + LLFastTimer t(FTM_DELETE_FACES); std::for_each(mFaces.begin(), mFaces.end(), DeletePointer()); mFaces.clear(); } @@ -213,7 +220,7 @@ void LLDrawable::cleanupReferences() gPipeline.unlinkDrawable(this); { - //LLFastTimer t(FTM_DEREF_DRAWABLE); + LLFastTimer t(FTM_DEREF_DRAWABLE); // Cleanup references to other objects mVObjp = NULL; mParent = NULL; @@ -1109,7 +1116,7 @@ void LLSpatialBridge::updateSpatialExtents() LLSpatialGroup* root = (LLSpatialGroup*) mOctree->getListener(0); { - LLFastTimer ftm(LLFastTimer::FTM_CULL_REBOUND); + LLFastTimer ftm(FTM_CULL_REBOUND); root->rebound(); } diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp index 4355e4abd..4eba9292e 100644 --- a/indra/newview/lldrawpoolalpha.cpp +++ b/indra/newview/lldrawpoolalpha.cpp @@ -95,7 +95,7 @@ void LLDrawPoolAlpha::endDeferredPass(S32 pass) void LLDrawPoolAlpha::renderDeferred(S32 pass) { - LLFastTimer t(LLFastTimer::FTM_RENDER_GRASS); + LLFastTimer t(FTM_RENDER_GRASS); gDeferredDiffuseAlphaMaskProgram.bind(); gDeferredDiffuseAlphaMaskProgram.setMinimumAlpha(0.33f); @@ -123,7 +123,7 @@ S32 LLDrawPoolAlpha::getNumPostDeferredPasses() void LLDrawPoolAlpha::beginPostDeferredPass(S32 pass) { - LLFastTimer t(LLFastTimer::FTM_RENDER_ALPHA); + LLFastTimer t(FTM_RENDER_ALPHA); if (pass == 0) { @@ -176,7 +176,7 @@ void LLDrawPoolAlpha::renderPostDeferred(S32 pass) void LLDrawPoolAlpha::beginRenderPass(S32 pass) { - LLFastTimer t(LLFastTimer::FTM_RENDER_ALPHA); + LLFastTimer t(FTM_RENDER_ALPHA); if (LLPipeline::sUnderWaterRender) { @@ -202,7 +202,7 @@ void LLDrawPoolAlpha::beginRenderPass(S32 pass) void LLDrawPoolAlpha::endRenderPass( S32 pass ) { - LLFastTimer t(LLFastTimer::FTM_RENDER_ALPHA); + LLFastTimer t(FTM_RENDER_ALPHA); LLRenderPass::endRenderPass(pass); if(gPipeline.canUseWindLightShaders()) @@ -213,7 +213,7 @@ void LLDrawPoolAlpha::endRenderPass( S32 pass ) void LLDrawPoolAlpha::render(S32 pass) { - LLFastTimer t(LLFastTimer::FTM_RENDER_ALPHA); + LLFastTimer t(FTM_RENDER_ALPHA); LLGLSPipelineAlpha gls_pipeline_alpha; diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp index 162c2e33f..e0f2fd89c 100644 --- a/indra/newview/lldrawpoolavatar.cpp +++ b/indra/newview/lldrawpoolavatar.cpp @@ -106,11 +106,11 @@ S32 normal_channel = -1; S32 specular_channel = -1; S32 cube_channel = -1; -LLDrawPoolAvatar::LLDrawPoolAvatar() : -LLFacePool(POOL_AVATAR) +static LLFastTimer::DeclareTimer FTM_SHADOW_AVATAR("Avatar Shadow"); + +LLDrawPoolAvatar::LLDrawPoolAvatar() : + LLFacePool(POOL_AVATAR) { - //LLDebugVarMessageBox::show("acceleration", &CLOTHING_ACCEL_FORCE_FACTOR, 10.f, 0.1f); - //LLDebugVarMessageBox::show("gravity", &CLOTHING_GRAVITY_EFFECT, 10.f, 0.1f); } //----------------------------------------------------------------------------- @@ -162,6 +162,7 @@ LLMatrix4& LLDrawPoolAvatar::getModelView() //----------------------------------------------------------------------------- void LLDrawPoolAvatar::beginDeferredPass(S32 pass) { + LLFastTimer t(FTM_RENDER_CHARACTERS); sSkipTransparent = TRUE; is_deferred_render = true; @@ -193,6 +194,7 @@ void LLDrawPoolAvatar::beginDeferredPass(S32 pass) void LLDrawPoolAvatar::endDeferredPass(S32 pass) { + LLFastTimer t(FTM_RENDER_CHARACTERS); sSkipTransparent = FALSE; is_deferred_render = false; @@ -351,7 +353,7 @@ S32 LLDrawPoolAvatar::getNumShadowPasses() void LLDrawPoolAvatar::beginShadowPass(S32 pass) { - LLFastTimer t(LLFastTimer::FTM_SHADOW_AVATAR); + LLFastTimer t(FTM_SHADOW_AVATAR); if (pass == 0) { @@ -377,8 +379,7 @@ void LLDrawPoolAvatar::beginShadowPass(S32 pass) void LLDrawPoolAvatar::endShadowPass(S32 pass) { - LLFastTimer t(LLFastTimer::FTM_SHADOW_AVATAR); - + LLFastTimer t(FTM_SHADOW_AVATAR); if (pass == 0) { if (sShaderLevel > 0) @@ -397,7 +398,7 @@ void LLDrawPoolAvatar::endShadowPass(S32 pass) void LLDrawPoolAvatar::renderShadow(S32 pass) { - LLFastTimer t(LLFastTimer::FTM_SHADOW_AVATAR); + LLFastTimer t(FTM_SHADOW_AVATAR); if (mDrawFace.empty()) { @@ -465,7 +466,7 @@ S32 LLDrawPoolAvatar::getNumDeferredPasses() void LLDrawPoolAvatar::render(S32 pass) { - LLFastTimer t(LLFastTimer::FTM_RENDER_CHARACTERS); + LLFastTimer t(FTM_RENDER_CHARACTERS); if (LLPipeline::sImpostorRender) { renderAvatars(NULL, pass+2); @@ -477,7 +478,7 @@ void LLDrawPoolAvatar::render(S32 pass) void LLDrawPoolAvatar::beginRenderPass(S32 pass) { - LLFastTimer t(LLFastTimer::FTM_RENDER_CHARACTERS); + LLFastTimer t(FTM_RENDER_CHARACTERS); //reset vertex buffer mappings LLVertexBuffer::unbind(); @@ -528,7 +529,7 @@ void LLDrawPoolAvatar::beginRenderPass(S32 pass) void LLDrawPoolAvatar::endRenderPass(S32 pass) { - LLFastTimer t(LLFastTimer::FTM_RENDER_CHARACTERS); + LLFastTimer t(FTM_RENDER_CHARACTERS); if (LLPipeline::sImpostorRender) { @@ -1301,7 +1302,7 @@ void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer(LLVOAvatar* avatar, LLFace* face->setGeomIndex(0); face->setIndicesIndex(0); - if (buffer.isNull() || buffer->getTypeMask() != data_mask) + if (buffer.isNull() || buffer->getTypeMask() != data_mask || !buffer->isWriteable()) { //make a new buffer if (sShaderLevel > 0) { @@ -1335,7 +1336,9 @@ void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer(LLVOAvatar* avatar, LLFace* LLMatrix3 mat_normal(mat3); //let getGeometryVolume know if alpha should override shiny - if (face->getFaceColor().mV[3] < 1.f) + U32 type = gPipeline.getPoolTypeFromTE(face->getTextureEntry(), face->getTexture()); + + if (type == LLDrawPool::POOL_ALPHA) { face->setPoolType(LLDrawPool::POOL_ALPHA); } diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp index f9d6de0d6..6c4efe5ea 100644 --- a/indra/newview/lldrawpoolbump.cpp +++ b/indra/newview/lldrawpoolbump.cpp @@ -242,7 +242,7 @@ S32 LLDrawPoolBump::getNumPasses() void LLDrawPoolBump::beginRenderPass(S32 pass) { - LLFastTimer t(LLFastTimer::FTM_RENDER_BUMP); + LLFastTimer t(FTM_RENDER_BUMP); switch( pass ) { case 0: @@ -269,7 +269,7 @@ void LLDrawPoolBump::beginRenderPass(S32 pass) void LLDrawPoolBump::render(S32 pass) { - LLFastTimer t(LLFastTimer::FTM_RENDER_BUMP); + LLFastTimer t(FTM_RENDER_BUMP); if (!gPipeline.hasRenderType(LLDrawPool::POOL_SIMPLE)) { @@ -302,7 +302,7 @@ void LLDrawPoolBump::render(S32 pass) void LLDrawPoolBump::endRenderPass(S32 pass) { - LLFastTimer t(LLFastTimer::FTM_RENDER_BUMP); + LLFastTimer t(FTM_RENDER_BUMP); switch( pass ) { case 0: @@ -333,7 +333,7 @@ void LLDrawPoolBump::endRenderPass(S32 pass) //static void LLDrawPoolBump::beginShiny(bool invisible) { - LLFastTimer t(LLFastTimer::FTM_RENDER_SHINY); + LLFastTimer t(FTM_RENDER_SHINY); if ((!invisible && !gPipeline.hasRenderBatches(LLRenderPass::PASS_SHINY))|| (invisible && !gPipeline.hasRenderBatches(LLRenderPass::PASS_INVISI_SHINY))) { @@ -426,7 +426,7 @@ void LLDrawPoolBump::bindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& di void LLDrawPoolBump::renderShiny(bool invisible) { - LLFastTimer t(LLFastTimer::FTM_RENDER_SHINY); + LLFastTimer t(FTM_RENDER_SHINY); if ((!invisible && !gPipeline.hasRenderBatches(LLRenderPass::PASS_SHINY))|| (invisible && !gPipeline.hasRenderBatches(LLRenderPass::PASS_INVISI_SHINY))) { @@ -486,7 +486,7 @@ void LLDrawPoolBump::unbindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& void LLDrawPoolBump::endShiny(bool invisible) { - LLFastTimer t(LLFastTimer::FTM_RENDER_SHINY); + LLFastTimer t(FTM_RENDER_SHINY); if ((!invisible && !gPipeline.hasRenderBatches(LLRenderPass::PASS_SHINY))|| (invisible && !gPipeline.hasRenderBatches(LLRenderPass::PASS_INVISI_SHINY))) { @@ -506,7 +506,7 @@ void LLDrawPoolBump::endShiny(bool invisible) void LLDrawPoolBump::beginFullbrightShiny() { - LLFastTimer t(LLFastTimer::FTM_RENDER_SHINY); + LLFastTimer t(FTM_RENDER_SHINY); if (!gPipeline.hasRenderBatches(LLRenderPass::PASS_FULLBRIGHT_SHINY)) { return; @@ -561,7 +561,7 @@ void LLDrawPoolBump::beginFullbrightShiny() void LLDrawPoolBump::renderFullbrightShiny() { - LLFastTimer t(LLFastTimer::FTM_RENDER_SHINY); + LLFastTimer t(FTM_RENDER_SHINY); if (!gPipeline.hasRenderBatches(LLRenderPass::PASS_FULLBRIGHT_SHINY)) { return; @@ -584,7 +584,7 @@ void LLDrawPoolBump::renderFullbrightShiny() void LLDrawPoolBump::endFullbrightShiny() { - LLFastTimer t(LLFastTimer::FTM_RENDER_SHINY); + LLFastTimer t(FTM_RENDER_SHINY); if (!gPipeline.hasRenderBatches(LLRenderPass::PASS_FULLBRIGHT_SHINY)) { return; @@ -715,7 +715,7 @@ void LLDrawPoolBump::beginBump(U32 pass) } sVertexMask = VERTEX_MASK_BUMP; - LLFastTimer t(LLFastTimer::FTM_RENDER_BUMP); + LLFastTimer t(FTM_RENDER_BUMP); // Optional second pass: emboss bump map stop_glerror(); @@ -767,7 +767,7 @@ void LLDrawPoolBump::renderBump(U32 pass) return; } - LLFastTimer ftm(LLFastTimer::FTM_RENDER_BUMP); + LLFastTimer ftm(FTM_RENDER_BUMP); LLGLDisable fog(GL_FOG); LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE, GL_LEQUAL); LLGLEnable blend(GL_BLEND); @@ -817,7 +817,7 @@ void LLDrawPoolBump::beginDeferredPass(S32 pass) { return; } - LLFastTimer ftm(LLFastTimer::FTM_RENDER_BUMP); + LLFastTimer ftm(FTM_RENDER_BUMP); mShiny = TRUE; gDeferredBumpProgram.bind(); diffuse_channel = gDeferredBumpProgram.enableTexture(LLViewerShaderMgr::DIFFUSE_MAP); @@ -832,7 +832,7 @@ void LLDrawPoolBump::endDeferredPass(S32 pass) { return; } - LLFastTimer ftm(LLFastTimer::FTM_RENDER_BUMP); + LLFastTimer ftm(FTM_RENDER_BUMP); mShiny = FALSE; gDeferredBumpProgram.disableTexture(LLViewerShaderMgr::DIFFUSE_MAP); gDeferredBumpProgram.disableTexture(LLViewerShaderMgr::BUMP_MAP); @@ -846,7 +846,7 @@ void LLDrawPoolBump::renderDeferred(S32 pass) { return; } - LLFastTimer ftm(LLFastTimer::FTM_RENDER_BUMP); + LLFastTimer ftm(FTM_RENDER_BUMP); U32 type = LLRenderPass::PASS_BUMP; LLCullResult::drawinfo_list_t::iterator begin = gPipeline.beginRenderMap(type); @@ -1089,6 +1089,8 @@ LLViewerTexture* LLBumpImageList::getBrightnessDarknessImage(LLViewerFetchedText } +static LLFastTimer::DeclareTimer FTM_BUMP_SOURCE_STANDARD_LOADED("Bump Standard Callback"); + // static void LLBumpImageList::onSourceBrightnessLoaded( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata ) { @@ -1111,19 +1113,22 @@ void LLBumpImageList::onSourceDarknessLoaded( BOOL success, LLViewerFetchedTextu } } +static LLFastTimer::DeclareTimer FTM_BUMP_GEN_NORMAL("Generate Normal Map"); +static LLFastTimer::DeclareTimer FTM_BUMP_CREATE_TEXTURE("Create GL Normal Map"); + void LLBumpImageList::onSourceStandardLoaded( BOOL success, LLViewerFetchedTexture* src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata) { if (success && LLPipeline::sRenderDeferred) { - //LLFastTimer t(FTM_BUMP_SOURCE_STANDARD_LOADED); + LLFastTimer t(FTM_BUMP_SOURCE_STANDARD_LOADED); LLPointer nrm_image = new LLImageRaw(src->getWidth(), src->getHeight(), 4); { - //LLFastTimer t(FTM_BUMP_GEN_NORMAL); + LLFastTimer t(FTM_BUMP_GEN_NORMAL); generateNormalMapFromAlpha(src, nrm_image); } src_vi->setExplicitFormat(GL_RGBA, GL_RGBA); { - //LLFastTimer t(FTM_BUMP_CREATE_TEXTURE); + LLFastTimer t(FTM_BUMP_CREATE_TEXTURE); src_vi->createGLTexture(src_vi->getDiscardLevel(), nrm_image); } } @@ -1184,19 +1189,28 @@ void LLBumpImageList::generateNormalMapFromAlpha(LLImageRaw* src, LLImageRaw* nr } } + +static LLFastTimer::DeclareTimer FTM_BUMP_SOURCE_LOADED("Bump Source Loaded"); +static LLFastTimer::DeclareTimer FTM_BUMP_SOURCE_ENTRIES_UPDATE("Entries Update"); +static LLFastTimer::DeclareTimer FTM_BUMP_SOURCE_MIN_MAX("Min/Max"); +static LLFastTimer::DeclareTimer FTM_BUMP_SOURCE_RGB2LUM("RGB to Luminance"); +static LLFastTimer::DeclareTimer FTM_BUMP_SOURCE_RESCALE("Rescale"); +static LLFastTimer::DeclareTimer FTM_BUMP_SOURCE_GEN_NORMAL("Generate Normal"); +static LLFastTimer::DeclareTimer FTM_BUMP_SOURCE_CREATE("Create"); + // static void LLBumpImageList::onSourceLoaded( BOOL success, LLViewerTexture *src_vi, LLImageRaw* src, LLUUID& source_asset_id, EBumpEffect bump_code ) { if( success ) { - // LLFastTimer t(FTM_BUMP_SOURCE_LOADED); + LLFastTimer t(FTM_BUMP_SOURCE_LOADED); bump_image_map_t& entries_list(bump_code == BE_BRIGHTNESS ? gBumpImageList.mBrightnessEntries : gBumpImageList.mDarknessEntries ); bump_image_map_t::iterator iter = entries_list.find(source_asset_id); { - //LLFastTimer t(FTM_BUMP_SOURCE_ENTRIES_UPDATE); + LLFastTimer t(FTM_BUMP_SOURCE_ENTRIES_UPDATE); if (iter == entries_list.end() || iter->second.isNull() || iter->second->getWidth() != src->getWidth() || @@ -1239,7 +1253,7 @@ void LLBumpImageList::onSourceLoaded( BOOL success, LLViewerTexture *src_vi, LLI case 1: case 2: { - //LLFastTimer t(FTM_BUMP_SOURCE_MIN_MAX); + LLFastTimer t(FTM_BUMP_SOURCE_MIN_MAX); if( src_data_size == dst_data_size * src_components ) { for( S32 i = 0, j=0; i < dst_data_size; i++, j+= src_components ) @@ -1265,7 +1279,7 @@ void LLBumpImageList::onSourceLoaded( BOOL success, LLViewerTexture *src_vi, LLI case 3: case 4: { - //LLFastTimer t(FTM_BUMP_SOURCE_RGB2LUM); + LLFastTimer t(FTM_BUMP_SOURCE_RGB2LUM); if( src_data_size == dst_data_size * src_components ) { for( S32 i = 0, j=0; i < dst_data_size; i++, j+= src_components ) @@ -1298,6 +1312,7 @@ void LLBumpImageList::onSourceLoaded( BOOL success, LLViewerTexture *src_vi, LLI if( maximum > minimum ) { + LLFastTimer t(FTM_BUMP_SOURCE_RESCALE); U8 bias_and_scale_lut[256]; F32 twice_one_over_range = 2.f / (maximum - minimum); S32 i; @@ -1335,20 +1350,20 @@ void LLBumpImageList::onSourceLoaded( BOOL success, LLViewerTexture *src_vi, LLI if (!LLPipeline::sRenderDeferred) { - //LLFastTimer t(FTM_BUMP_SOURCE_CREATE); + LLFastTimer t(FTM_BUMP_SOURCE_CREATE); bump->setExplicitFormat(GL_ALPHA8, GL_ALPHA); bump->createGLTexture(0, dst_image); } - else + else { //convert to normal map { - //LLFastTimer t(FTM_BUMP_SOURCE_CREATE); + LLFastTimer t(FTM_BUMP_SOURCE_CREATE); bump->setExplicitFormat(GL_RGBA8, GL_ALPHA); bump->createGLTexture(0, dst_image); } { - //LLFastTimer t(FTM_BUMP_SOURCE_GEN_NORMAL); + LLFastTimer t(FTM_BUMP_SOURCE_GEN_NORMAL); gPipeline.mScreen.bindTarget(); LLGLDepthTest depth(GL_FALSE); @@ -1539,7 +1554,7 @@ void LLDrawPoolBump::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL void LLDrawPoolInvisible::render(S32 pass) { //render invisiprims - LLFastTimer t(LLFastTimer::FTM_RENDER_INVISIBLE); + LLFastTimer t(FTM_RENDER_INVISIBLE); if (gPipeline.canUseVertexShaders()) { @@ -1579,7 +1594,7 @@ void LLDrawPoolInvisible::endDeferredPass( S32 pass ) void LLDrawPoolInvisible::renderDeferred( S32 pass ) { //render invisiprims; this doesn't work becaue it also blocks all the post-deferred stuff #if 0 - LLFastTimer t(LLFastTimer::FTM_RENDER_INVISIBLE); + LLFastTimer t(FTM_RENDER_INVISIBLE); U32 invisi_mask = LLVertexBuffer::MAP_VERTEX; glStencilMask(0); diff --git a/indra/newview/lldrawpoolclouds.cpp b/indra/newview/lldrawpoolclouds.cpp index 8844c3c71..0ded5695d 100644 --- a/indra/newview/lldrawpoolclouds.cpp +++ b/indra/newview/lldrawpoolclouds.cpp @@ -76,7 +76,7 @@ void LLDrawPoolClouds::prerender() void LLDrawPoolClouds::render(S32 pass) { - LLFastTimer ftm(LLFastTimer::FTM_RENDER_CLOUDS); + LLFastTimer ftm(FTM_RENDER_CLOUDS); if (!(gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_CLOUDS))) { return; diff --git a/indra/newview/lldrawpoolsimple.cpp b/indra/newview/lldrawpoolsimple.cpp index 6c96be0ca..79f2932ec 100644 --- a/indra/newview/lldrawpoolsimple.cpp +++ b/indra/newview/lldrawpoolsimple.cpp @@ -48,14 +48,19 @@ static LLGLSLShader* simple_shader = NULL; static LLGLSLShader* fullbright_shader = NULL; +static LLFastTimer::DeclareTimer FTM_RENDER_SIMPLE_DEFERRED("Deferred Simple"); +static LLFastTimer::DeclareTimer FTM_RENDER_GRASS_DEFERRED("Deferred Grass"); + void LLDrawPoolGlow::beginPostDeferredPass(S32 pass) { gDeferredEmissiveProgram.bind(); } +static LLFastTimer::DeclareTimer FTM_RENDER_GLOW_PUSH("Glow Push"); + void LLDrawPoolGlow::renderPostDeferred(S32 pass) { - LLFastTimer t(LLFastTimer::FTM_RENDER_GLOW); + LLFastTimer t(FTM_RENDER_GLOW); LLGLEnable blend(GL_BLEND); LLGLDisable test(GL_ALPHA_TEST); gGL.flush(); @@ -68,7 +73,7 @@ void LLDrawPoolGlow::renderPostDeferred(S32 pass) gGL.setColorMask(false, true); { - //LLFastTimer t(FTM_RENDER_GLOW_PUSH); + LLFastTimer t(FTM_RENDER_GLOW_PUSH); pushBatches(LLRenderPass::PASS_GLOW, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE); } @@ -96,7 +101,7 @@ S32 LLDrawPoolGlow::getNumPasses() void LLDrawPoolGlow::render(S32 pass) { - LLFastTimer t(LLFastTimer::FTM_RENDER_GLOW); + LLFastTimer t(FTM_RENDER_GLOW); LLGLEnable blend(GL_BLEND); LLGLDisable test(GL_ALPHA_TEST); gGL.flush(); @@ -146,7 +151,7 @@ void LLDrawPoolSimple::prerender() void LLDrawPoolSimple::beginRenderPass(S32 pass) { - LLFastTimer t(LLFastTimer::FTM_RENDER_SIMPLE); + LLFastTimer t(FTM_RENDER_SIMPLE); if (LLPipeline::sUnderWaterRender) { @@ -173,7 +178,7 @@ void LLDrawPoolSimple::beginRenderPass(S32 pass) void LLDrawPoolSimple::endRenderPass(S32 pass) { - LLFastTimer t(LLFastTimer::FTM_RENDER_SIMPLE); + LLFastTimer t(FTM_RENDER_SIMPLE); stop_glerror(); LLRenderPass::endRenderPass(pass); stop_glerror(); @@ -188,7 +193,7 @@ void LLDrawPoolSimple::render(S32 pass) LLGLDisable blend(GL_BLEND); { //render simple - LLFastTimer t(LLFastTimer::FTM_RENDER_SIMPLE); + LLFastTimer t(FTM_RENDER_SIMPLE); gPipeline.enableLightsDynamic(); if (mVertexShaderLevel > 0) @@ -218,13 +223,13 @@ void LLDrawPoolSimple::render(S32 pass) void LLDrawPoolSimple::beginDeferredPass(S32 pass) { - LLFastTimer t(LLFastTimer::FTM_RENDER_SIMPLE); + LLFastTimer t(FTM_RENDER_SIMPLE_DEFERRED); gDeferredDiffuseProgram.bind(); } void LLDrawPoolSimple::endDeferredPass(S32 pass) { - LLFastTimer t(LLFastTimer::FTM_RENDER_SIMPLE); + LLFastTimer t(FTM_RENDER_SIMPLE_DEFERRED); LLRenderPass::endRenderPass(pass); gDeferredDiffuseProgram.unbind(); @@ -236,7 +241,7 @@ void LLDrawPoolSimple::renderDeferred(S32 pass) LLGLDisable alpha_test(GL_ALPHA_TEST); { //render simple - LLFastTimer t(LLFastTimer::FTM_RENDER_SIMPLE); + LLFastTimer t(FTM_RENDER_SIMPLE_DEFERRED); pushBatches(LLRenderPass::PASS_SIMPLE, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE); } } @@ -256,7 +261,7 @@ void LLDrawPoolGrass::prerender() void LLDrawPoolGrass::beginRenderPass(S32 pass) { - LLFastTimer t(LLFastTimer::FTM_RENDER_GRASS); + LLFastTimer t(FTM_RENDER_GRASS); stop_glerror(); if (LLPipeline::sUnderWaterRender) @@ -286,7 +291,7 @@ void LLDrawPoolGrass::beginRenderPass(S32 pass) void LLDrawPoolGrass::endRenderPass(S32 pass) { - LLFastTimer t(LLFastTimer::FTM_RENDER_GRASS); + LLFastTimer t(FTM_RENDER_GRASS); LLRenderPass::endRenderPass(pass); if (mVertexShaderLevel > 0) @@ -304,7 +309,7 @@ void LLDrawPoolGrass::render(S32 pass) LLGLDisable blend(GL_BLEND); { - LLFastTimer t(LLFastTimer::FTM_RENDER_GRASS); + LLFastTimer t(FTM_RENDER_GRASS); LLGLEnable test(GL_ALPHA_TEST); gGL.setSceneBlendType(LLRender::BT_ALPHA); //render grass @@ -325,8 +330,7 @@ void LLDrawPoolGrass::endDeferredPass(S32 pass) void LLDrawPoolGrass::renderDeferred(S32 pass) { { - LLFastTimer t(LLFastTimer::FTM_RENDER_GRASS); - //LLFastTimer t(FTM_RENDER_GRASS_DEFERRED); + LLFastTimer t(FTM_RENDER_GRASS_DEFERRED); gDeferredNonIndexedDiffuseAlphaMaskProgram.bind(); gDeferredNonIndexedDiffuseAlphaMaskProgram.setMinimumAlpha(0.5f); //render grass @@ -353,7 +357,7 @@ void LLDrawPoolFullbright::beginPostDeferredPass(S32 pass) void LLDrawPoolFullbright::renderPostDeferred(S32 pass) { - LLFastTimer t(LLFastTimer::FTM_RENDER_FULLBRIGHT); + LLFastTimer t(FTM_RENDER_FULLBRIGHT); gGL.setSceneBlendType(LLRender::BT_ALPHA); U32 fullbright_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_COLOR | LLVertexBuffer::MAP_TEXTURE_INDEX; @@ -368,7 +372,7 @@ void LLDrawPoolFullbright::endPostDeferredPass(S32 pass) void LLDrawPoolFullbright::beginRenderPass(S32 pass) { - LLFastTimer t(LLFastTimer::FTM_RENDER_FULLBRIGHT); + LLFastTimer t(FTM_RENDER_FULLBRIGHT); if (LLPipeline::sUnderWaterRender) { @@ -382,7 +386,7 @@ void LLDrawPoolFullbright::beginRenderPass(S32 pass) void LLDrawPoolFullbright::endRenderPass(S32 pass) { - LLFastTimer t(LLFastTimer::FTM_RENDER_FULLBRIGHT); + LLFastTimer t(FTM_RENDER_FULLBRIGHT); LLRenderPass::endRenderPass(pass); stop_glerror(); @@ -397,7 +401,7 @@ void LLDrawPoolFullbright::endRenderPass(S32 pass) void LLDrawPoolFullbright::render(S32 pass) { //render fullbright - LLFastTimer t(LLFastTimer::FTM_RENDER_FULLBRIGHT); + LLFastTimer t(FTM_RENDER_FULLBRIGHT); gGL.setSceneBlendType(LLRender::BT_ALPHA); stop_glerror(); diff --git a/indra/newview/lldrawpoolterrain.cpp b/indra/newview/lldrawpoolterrain.cpp index 8d22b05e4..5225af4e7 100644 --- a/indra/newview/lldrawpoolterrain.cpp +++ b/indra/newview/lldrawpoolterrain.cpp @@ -61,6 +61,8 @@ int DebugDetailMap = 0; S32 LLDrawPoolTerrain::sDetailMode = 1; F32 LLDrawPoolTerrain::sDetailScale = DETAIL_SCALE; static LLGLSLShader* sShader = NULL; +static LLFastTimer::DeclareTimer FTM_SHADOW_TERRAIN("Terrain Shadow"); + LLDrawPoolTerrain::LLDrawPoolTerrain(LLViewerTexture *texturep) : LLFacePool(POOL_TERRAIN), @@ -131,7 +133,7 @@ void LLDrawPoolTerrain::prerender() void LLDrawPoolTerrain::beginRenderPass( S32 pass ) { - LLFastTimer t(LLFastTimer::FTM_RENDER_TERRAIN); + LLFastTimer t(FTM_RENDER_TERRAIN); LLFacePool::beginRenderPass(pass); sShader = LLPipeline::sUnderWaterRender ? @@ -146,7 +148,7 @@ void LLDrawPoolTerrain::beginRenderPass( S32 pass ) void LLDrawPoolTerrain::endRenderPass( S32 pass ) { - LLFastTimer t(LLFastTimer::FTM_RENDER_TERRAIN); + LLFastTimer t(FTM_RENDER_TERRAIN); //LLFacePool::endRenderPass(pass); if (mVertexShaderLevel > 1 && sShader->mShaderLevel > 0) { @@ -162,7 +164,7 @@ S32 LLDrawPoolTerrain::getDetailMode() void LLDrawPoolTerrain::render(S32 pass) { - LLFastTimer t(LLFastTimer::FTM_RENDER_TERRAIN); + LLFastTimer t(FTM_RENDER_TERRAIN); if (mDrawFace.empty()) { @@ -246,7 +248,7 @@ void LLDrawPoolTerrain::render(S32 pass) void LLDrawPoolTerrain::beginDeferredPass(S32 pass) { - LLFastTimer t(LLFastTimer::FTM_RENDER_TERRAIN); + LLFastTimer t(FTM_RENDER_TERRAIN); LLFacePool::beginRenderPass(pass); sShader = &gDeferredTerrainProgram; @@ -256,14 +258,14 @@ void LLDrawPoolTerrain::beginDeferredPass(S32 pass) void LLDrawPoolTerrain::endDeferredPass(S32 pass) { - LLFastTimer t(LLFastTimer::FTM_RENDER_TERRAIN); + LLFastTimer t(FTM_RENDER_TERRAIN); LLFacePool::endRenderPass(pass); sShader->unbind(); } void LLDrawPoolTerrain::renderDeferred(S32 pass) { - LLFastTimer t(LLFastTimer::FTM_RENDER_TERRAIN); + LLFastTimer t(FTM_RENDER_TERRAIN); if (mDrawFace.empty()) { return; @@ -273,7 +275,7 @@ void LLDrawPoolTerrain::renderDeferred(S32 pass) void LLDrawPoolTerrain::beginShadowPass(S32 pass) { - LLFastTimer t(LLFastTimer::FTM_SHADOW_TERRAIN); + LLFastTimer t(FTM_SHADOW_TERRAIN); LLFacePool::beginRenderPass(pass); gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); gDeferredShadowProgram.bind(); @@ -281,14 +283,14 @@ void LLDrawPoolTerrain::beginShadowPass(S32 pass) void LLDrawPoolTerrain::endShadowPass(S32 pass) { - LLFastTimer t(LLFastTimer::FTM_SHADOW_TERRAIN); + LLFastTimer t(FTM_SHADOW_TERRAIN); LLFacePool::endRenderPass(pass); gDeferredShadowProgram.unbind(); } void LLDrawPoolTerrain::renderShadow(S32 pass) { - LLFastTimer t(LLFastTimer::FTM_SHADOW_TERRAIN); + LLFastTimer t(FTM_SHADOW_TERRAIN); if (mDrawFace.empty()) { return; diff --git a/indra/newview/lldrawpooltree.cpp b/indra/newview/lldrawpooltree.cpp index 97d757875..9500f5aff 100644 --- a/indra/newview/lldrawpooltree.cpp +++ b/indra/newview/lldrawpooltree.cpp @@ -46,6 +46,7 @@ S32 LLDrawPoolTree::sDiffTex = 0; static LLGLSLShader* shader = NULL; +static LLFastTimer::DeclareTimer FTM_SHADOW_TREE("Tree Shadow"); LLDrawPoolTree::LLDrawPoolTree(LLViewerTexture *texturep) : LLFacePool(POOL_TREE), @@ -66,7 +67,7 @@ void LLDrawPoolTree::prerender() void LLDrawPoolTree::beginRenderPass(S32 pass) { - LLFastTimer t(LLFastTimer::FTM_RENDER_TREES); + LLFastTimer t(FTM_RENDER_TREES); if (LLPipeline::sUnderWaterRender) { @@ -92,7 +93,7 @@ void LLDrawPoolTree::beginRenderPass(S32 pass) void LLDrawPoolTree::render(S32 pass) { - LLFastTimer t(LLPipeline::sShadowRender ? LLFastTimer::FTM_SHADOW_TREE : LLFastTimer::FTM_RENDER_TREES); + LLFastTimer t(LLPipeline::sShadowRender ? FTM_SHADOW_TREE : FTM_RENDER_TREES); if (mDrawFace.empty()) { @@ -126,7 +127,7 @@ void LLDrawPoolTree::render(S32 pass) void LLDrawPoolTree::endRenderPass(S32 pass) { - LLFastTimer t(LLFastTimer::FTM_RENDER_TREES); + LLFastTimer t(FTM_RENDER_TREES); if (gPipeline.canUseWindLightShadersOnObjects()) { @@ -144,7 +145,7 @@ void LLDrawPoolTree::endRenderPass(S32 pass) //============================================ void LLDrawPoolTree::beginDeferredPass(S32 pass) { - LLFastTimer t(LLFastTimer::FTM_RENDER_TREES); + LLFastTimer t(FTM_RENDER_TREES); shader = &gDeferredTreeProgram; shader->bind(); @@ -158,7 +159,7 @@ void LLDrawPoolTree::renderDeferred(S32 pass) void LLDrawPoolTree::endDeferredPass(S32 pass) { - LLFastTimer t(LLFastTimer::FTM_RENDER_TREES); + LLFastTimer t(FTM_RENDER_TREES); shader->unbind(); } @@ -168,7 +169,7 @@ void LLDrawPoolTree::endDeferredPass(S32 pass) //============================================ void LLDrawPoolTree::beginShadowPass(S32 pass) { - LLFastTimer t(LLFastTimer::FTM_SHADOW_TREE); + LLFastTimer t(FTM_SHADOW_TREE); static const LLCachedControl render_deferred_offset("RenderDeferredTreeShadowOffset",1.f); static const LLCachedControl render_deferred_bias("RenderDeferredTreeShadowBias",1.f); @@ -184,7 +185,7 @@ void LLDrawPoolTree::renderShadow(S32 pass) void LLDrawPoolTree::endShadowPass(S32 pass) { - LLFastTimer t(LLFastTimer::FTM_SHADOW_TREE); + LLFastTimer t(FTM_SHADOW_TREE); static const LLCachedControl render_deferred_offset("RenderDeferredSpotShadowOffset",1.f); static const LLCachedControl render_deferred_bias("RenderDeferredSpotShadowBias",1.f); diff --git a/indra/newview/lldrawpoolwater.cpp b/indra/newview/lldrawpoolwater.cpp index 956f1cef5..438e40524 100644 --- a/indra/newview/lldrawpoolwater.cpp +++ b/indra/newview/lldrawpoolwater.cpp @@ -148,7 +148,7 @@ void LLDrawPoolWater::endPostDeferredPass(S32 pass) //=============================== void LLDrawPoolWater::renderDeferred(S32 pass) { - LLFastTimer t(LLFastTimer::FTM_RENDER_WATER); + LLFastTimer t(FTM_RENDER_WATER); deferred_render = TRUE; shade(); deferred_render = FALSE; @@ -158,7 +158,7 @@ void LLDrawPoolWater::renderDeferred(S32 pass) void LLDrawPoolWater::render(S32 pass) { - LLFastTimer ftm(LLFastTimer::FTM_RENDER_WATER); + LLFastTimer ftm(FTM_RENDER_WATER); if (mDrawFace.empty() || LLDrawable::getCurrentFrame() <= 1) { return; diff --git a/indra/newview/lldrawpoolwlsky.cpp b/indra/newview/lldrawpoolwlsky.cpp index c6f219323..df9895906 100644 --- a/indra/newview/lldrawpoolwlsky.cpp +++ b/indra/newview/lldrawpoolwlsky.cpp @@ -316,7 +316,7 @@ void LLDrawPoolWLSky::renderDeferred(S32 pass) { return; } - LLFastTimer ftm(LLFastTimer::FTM_RENDER_WL_SKY); + LLFastTimer ftm(FTM_RENDER_WL_SKY); const F32 camHeightLocal = LLWLParamManager::getInstance()->getDomeOffset() * LLWLParamManager::getInstance()->getDomeRadius(); @@ -363,7 +363,7 @@ void LLDrawPoolWLSky::render(S32 pass) { return; } - LLFastTimer ftm(LLFastTimer::FTM_RENDER_WL_SKY); + LLFastTimer ftm(FTM_RENDER_WL_SKY); const F32 camHeightLocal = LLWLParamManager::getInstance()->getDomeOffset() * LLWLParamManager::getInstance()->getDomeRadius(); diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp index 06d4bdc03..28f781077 100644 --- a/indra/newview/llface.cpp +++ b/indra/newview/llface.cpp @@ -695,6 +695,49 @@ static void xform(LLVector2 &tex_coord, F32 cosAng, F32 sinAng, F32 offS, F32 of tex_coord.mV[1] = t; } +// Transform the texture coordinates for this face. +static void xform4a(LLVector4a &tex_coord, const LLVector4a& trans, const LLVector4Logical& mask, const LLVector4a& rot0, const LLVector4a& rot1, const LLVector4a& offset, const LLVector4a& scale) +{ + //tex coord is two coords, + LLVector4a st; + + // Texture transforms are done about the center of the face. + st.setAdd(tex_coord, trans); + + // Handle rotation + LLVector4a rot_st; + + // + LLVector4a s0; + s0.splat(st, 0); + LLVector4a s1; + s1.splat(st, 2); + LLVector4a ss; + ss.setSelectWithMask(mask, s1, s0); + + LLVector4a a; + a.setMul(rot0, ss); + + // + LLVector4a t0; + t0.splat(st, 1); + LLVector4a t1; + t1.splat(st, 3); + LLVector4a tt; + tt.setSelectWithMask(mask, t1, t0); + + LLVector4a b; + b.setMul(rot1, tt); + + st.setAdd(a,b); + + // Then scale + st.mul(scale); + + // Then offset + tex_coord.setAdd(st, offset); +} + bool less_than_max_mag(const LLVector4a& vec) { @@ -1052,13 +1095,33 @@ bool LLFace::canRenderAsMask() return false; } + +static LLFastTimer::DeclareTimer FTM_FACE_GET_GEOM("Face Geom"); +static LLFastTimer::DeclareTimer FTM_FACE_GEOM_POSITION("Position"); +static LLFastTimer::DeclareTimer FTM_FACE_GEOM_NORMAL("Normal"); +static LLFastTimer::DeclareTimer FTM_FACE_GEOM_TEXTURE("Texture"); +static LLFastTimer::DeclareTimer FTM_FACE_GEOM_COLOR("Color"); +static LLFastTimer::DeclareTimer FTM_FACE_GEOM_EMISSIVE("Emissive"); +static LLFastTimer::DeclareTimer FTM_FACE_GEOM_WEIGHTS("Weights"); +static LLFastTimer::DeclareTimer FTM_FACE_GEOM_BINORMAL("Binormal"); +static LLFastTimer::DeclareTimer FTM_FACE_GEOM_INDEX("Index"); +static LLFastTimer::DeclareTimer FTM_FACE_GEOM_INDEX_TAIL("Tail"); +static LLFastTimer::DeclareTimer FTM_FACE_POSITION_STORE("Pos"); +static LLFastTimer::DeclareTimer FTM_FACE_TEXTURE_INDEX_STORE("TexIdx"); +static LLFastTimer::DeclareTimer FTM_FACE_POSITION_PAD("Pad"); +static LLFastTimer::DeclareTimer FTM_FACE_TEX_DEFAULT("Default"); +static LLFastTimer::DeclareTimer FTM_FACE_TEX_QUICK("Quick"); +static LLFastTimer::DeclareTimer FTM_FACE_TEX_QUICK_NO_XFORM("No Xform"); +static LLFastTimer::DeclareTimer FTM_FACE_TEX_QUICK_XFORM("Xform"); + +static LLFastTimer::DeclareTimer FTM_FACE_TEX_QUICK_PLANAR("Quick Planar"); BOOL LLFace::getGeometryVolume(const LLVolume& volume, const S32 &f, const LLMatrix4& mat_vert_in, const LLMatrix3& mat_norm_in, const U16 &index_offset, bool force_rebuild) { - LLFastTimer t(LLFastTimer::FTM_FACE_GET_GEOM); + LLFastTimer t(FTM_FACE_GET_GEOM); llassert(verify()); const LLVolumeFace &vf = volume.getVolumeFace(f); S32 num_vertices = (S32)vf.mNumVertices; @@ -1069,7 +1132,9 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, updateRebuildFlags(); } - bool map_range = gGLManager.mHasMapBufferRange || gGLManager.mHasFlushBufferRange; + + //don't use map range (generates many redundant unmap calls) + bool map_range = false; //gGLManager.mHasMapBufferRange || gGLManager.mHasFlushBufferRange; if (mVertexBuffer.notNull()) { @@ -1095,16 +1160,12 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, } LLStrider vert; - LLVector4a* vertices = NULL; LLStrider tex_coords; LLStrider tex_coords2; - LLVector4a* normals = NULL; LLStrider norm; LLStrider colors; - LLVector4a* binormals = NULL; LLStrider binorm; LLStrider indicesp; - LLVector4a* weights = NULL; LLStrider wght; BOOL full_rebuild = force_rebuild || mDrawablep->isState(LLDrawable::REBUILD_VOLUME); @@ -1169,10 +1230,10 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, // INDICES if (full_rebuild) { - LLFastTimer t(LLFastTimer::FTM_FACE_GEOM_INDEX); + LLFastTimer t(FTM_FACE_GEOM_INDEX); mVertexBuffer->getIndexStrider(indicesp, mIndicesIndex, mIndicesCount, map_range); - __m128i* dst = (__m128i*) indicesp.get(); + volatile __m128i* dst = (__m128i*) indicesp.get(); __m128i* src = (__m128i*) vf.mIndices; __m128i offset = _mm_set1_epi16(index_offset); @@ -1181,12 +1242,17 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, for (S32 i = 0; i < end; i++) { __m128i res = _mm_add_epi16(src[i], offset); - _mm_storeu_si128(dst+i, res); + _mm_storeu_si128((__m128i*) dst++, res); } - for (S32 i = end*8; i < num_indices; ++i) { - indicesp[i] = vf.mIndices[i]+index_offset; + LLFastTimer t(FTM_FACE_GEOM_INDEX_TAIL); + U16* idx = (U16*) dst; + + for (S32 i = end*8; i < num_indices; ++i) + { + *idx++ = vf.mIndices[i]+index_offset; + } } if (map_range) @@ -1206,7 +1272,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, if (rebuild_tcoord) { - LLFastTimer t(LLFastTimer::FTM_FACE_GEOM_TEXTURE); + LLFastTimer t(FTM_FACE_GEOM_TEXTURE); bool do_xform; if (tep) @@ -1343,19 +1409,48 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, if (texgen != LLTextureEntry::TEX_GEN_PLANAR) { + LLFastTimer t(FTM_FACE_TEX_QUICK); if (!do_tex_mat) { if (!do_xform) { + LLFastTimer t(FTM_FACE_TEX_QUICK_NO_XFORM); LLVector4a::memcpyNonAliased16((F32*) tex_coords.get(), (F32*) vf.mTexCoords, num_vertices*2*sizeof(F32)); } else { - for (S32 i = 0; i < num_vertices; i++) + LLFastTimer t(FTM_FACE_TEX_QUICK_XFORM); + F32* dst = (F32*) tex_coords.get(); + LLVector4a* src = (LLVector4a*) vf.mTexCoords; + + LLVector4a trans; + trans.splat(-0.5f); + + LLVector4a rot0; + rot0.set(cos_ang, -sin_ang, cos_ang, -sin_ang); + + LLVector4a rot1; + rot1.set(sin_ang, cos_ang, sin_ang, cos_ang); + + LLVector4a scale; + scale.set(ms, mt, ms, mt); + + LLVector4a offset; + offset.set(os+0.5f, ot+0.5f, os+0.5f, ot+0.5f); + + LLVector4Logical mask; + mask.clear(); + mask.setElement<2>(); + mask.setElement<3>(); + + U32 count = num_vertices/2 + num_vertices%2; + + for (U32 i = 0; i < count; i++) { - LLVector2 tc(vf.mTexCoords[i]); - xform(tc, cos_ang, sin_ang, os, ot, ms, mt); - *tex_coords++ = tc; + LLVector4a res = *src++; + xform4a(res, trans, mask, rot0, rot1, offset, scale); + res.store4a(dst); + dst += 4; } } } @@ -1377,6 +1472,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, } else { //no bump, no atlas, tex gen planar + LLFastTimer t(FTM_FACE_TEX_QUICK_PLANAR); if (do_tex_mat) { for (S32 i = 0; i < num_vertices; i++) @@ -1421,6 +1517,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, } else { //either bump mapped or in atlas, just do the whole expensive loop + LLFastTimer t(FTM_FACE_TEX_DEFAULT); mVertexBuffer->getTexCoord0Strider(tex_coords, mGeomIndex, mGeomCount, map_range); std::vector bump_tc; @@ -1522,48 +1619,59 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, if (rebuild_pos) { - LLFastTimer t(LLFastTimer::FTM_FACE_GEOM_POSITION); + LLFastTimer t(FTM_FACE_GEOM_POSITION); llassert(num_vertices > 0); mVertexBuffer->getVertexStrider(vert, mGeomIndex, mGeomCount, map_range); - vertices = (LLVector4a*) vert.get(); - + + LLMatrix4a mat_vert; mat_vert.loadu(mat_vert_in); LLVector4a* src = vf.mPositions; - LLVector4a* dst = vertices; + volatile F32* dst = (volatile F32*) vert.get(); - LLVector4a* end = dst+num_vertices; - do - { - mat_vert.affineTransform(*src++, *dst++); - } - while(dst < end); + volatile F32* end = dst+num_vertices*4; + LLVector4a res; + + LLVector4a texIdx; F32 index = (F32) (mTextureIndex < 255 ? mTextureIndex : 0); - llassert(index <= LLGLSLShader::sIndexedTextureChannels-1); - F32 *index_dst = (F32*) vertices; - F32 *index_end = (F32*) end; - index_dst += 3; - index_end += 3; - do - { - *index_dst = index; - index_dst += 4; - } - while (index_dst < index_end); + LLVector4Logical mask; + mask.clear(); + mask.setElement<3>(); - S32 aligned_pad_vertices = mGeomCount - num_vertices; - LLVector4a* last_vec = end - 1; - while (aligned_pad_vertices > 0) + texIdx.set(0,0,0,index); + { - --aligned_pad_vertices; - *dst++ = *last_vec; + LLFastTimer t(FTM_FACE_POSITION_STORE); + LLVector4a tmp; + + do + { + mat_vert.affineTransform(*src++, res); + tmp.setSelectWithMask(mask, texIdx, res); + tmp.store4a((F32*) dst); + dst += 4; + } + while(dst < end); } - + + { + LLFastTimer t(FTM_FACE_POSITION_PAD); + S32 aligned_pad_vertices = mGeomCount - num_vertices; + res.set(res[0], res[1], res[2], 0.f); + + while (aligned_pad_vertices > 0) + { + --aligned_pad_vertices; + res.store4a((F32*) dst); + dst += 4; + } + } + if (map_range) { mVertexBuffer->flush(); @@ -1572,16 +1680,17 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, if (rebuild_normal) { - LLFastTimer t(LLFastTimer::FTM_FACE_GEOM_NORMAL); + LLFastTimer t(FTM_FACE_GEOM_NORMAL); mVertexBuffer->getNormalStrider(norm, mGeomIndex, mGeomCount, map_range); - normals = (LLVector4a*) norm.get(); + F32* normals = (F32*) norm.get(); for (S32 i = 0; i < num_vertices; i++) { LLVector4a normal; mat_normal.rotate(vf.mNormals[i], normal); normal.normalize3fast(); - normals[i] = normal; + normal.store4a(normals); + normals += 4; } if (map_range) @@ -1592,16 +1701,17 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, if (rebuild_binormal) { - LLFastTimer t(LLFastTimer::FTM_FACE_GEOM_BINORMAL); + LLFastTimer t(FTM_FACE_GEOM_BINORMAL); mVertexBuffer->getBinormalStrider(binorm, mGeomIndex, mGeomCount, map_range); - binormals = (LLVector4a*) binorm.get(); + F32* binormals = (F32*) binorm.get(); for (S32 i = 0; i < num_vertices; i++) { LLVector4a binormal; mat_normal.rotate(vf.mBinormals[i], binormal); binormal.normalize3fast(); - binormals[i] = binormal; + binormal.store4a(binormals); + binormals += 4; } if (map_range) @@ -1612,10 +1722,10 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, if (rebuild_weights && vf.mWeights) { - LLFastTimer t(LLFastTimer::FTM_FACE_GEOM_WEIGHTS); + LLFastTimer t(FTM_FACE_GEOM_WEIGHTS); mVertexBuffer->getWeight4Strider(wght, mGeomIndex, mGeomCount, map_range); - weights = (LLVector4a*) wght.get(); - LLVector4a::memcpyNonAliased16((F32*) weights, (F32*) vf.mWeights, num_vertices*4*sizeof(F32)); + F32* weights = (F32*) wght.get(); + LLVector4a::memcpyNonAliased16(weights, (F32*) vf.mWeights, num_vertices*4*sizeof(F32)); if (map_range) { mVertexBuffer->flush(); @@ -1624,7 +1734,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, if (rebuild_color) { - LLFastTimer t(LLFastTimer::FTM_FACE_GEOM_COLOR); + LLFastTimer t(FTM_FACE_GEOM_COLOR); mVertexBuffer->getColorStrider(colors, mGeomIndex, mGeomCount, map_range); LLVector4a src; @@ -1634,7 +1744,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, src.loadua((F32*) vec); - LLVector4a* dst = (LLVector4a*) colors.get(); + F32* dst = (F32*) colors.get(); S32 num_vecs = num_vertices/4; if (num_vertices%4 > 0) { @@ -1643,7 +1753,8 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, for (S32 i = 0; i < num_vecs; i++) { - dst[i] = src; + src.store4a(dst); + dst += 4; } if (map_range) @@ -1654,7 +1765,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, if (rebuild_emissive) { - LLFastTimer t(LLFastTimer::FTM_FACE_GEOM_EMISSIVE); + LLFastTimer t(FTM_FACE_GEOM_EMISSIVE); LLStrider emissive; mVertexBuffer->getEmissiveStrider(emissive, mGeomIndex, mGeomCount, map_range); @@ -1673,7 +1784,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, src.loadua((F32*) vec); - LLVector4a* dst = (LLVector4a*) emissive.get(); + F32* dst = (F32*) emissive.get(); S32 num_vecs = num_vertices/4; if (num_vertices%4 > 0) { @@ -1682,7 +1793,8 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, for (S32 i = 0; i < num_vecs; i++) { - dst[i] = src; + src.store4a(dst); + dst += 4; } if (map_range) diff --git a/indra/newview/llfasttimerview.cpp b/indra/newview/llfasttimerview.cpp index b85b21d14..47a490ecc 100644 --- a/indra/newview/llfasttimerview.cpp +++ b/indra/newview/llfasttimerview.cpp @@ -32,364 +32,177 @@ #include "llviewerprecompiledheaders.h" -#include "indra_constants.h" #include "llfasttimerview.h" + #include "llviewerwindow.h" #include "llrect.h" #include "llerror.h" #include "llgl.h" +#include "llimagepng.h" #include "llrender.h" +#include "llrendertarget.h" +#include "lllocalcliprect.h" #include "llmath.h" #include "llfontgl.h" +#include "llsdserialize.h" +#include "llbutton.h" #include "llappviewer.h" #include "llviewertexturelist.h" #include "llui.h" +#include "lluictrlfactory.h" #include "llviewercontrol.h" #include "llstat.h" #include "llfasttimer.h" +#include "lltreeiterators.h" +#include "llviewerstats.h" ////////////////////////////////////////////////////////////////////////////// static const S32 MAX_VISIBLE_HISTORY = 10; static const S32 LINE_GRAPH_HEIGHT = 240; -struct ft_display_info { - int timer; - const char *desc; - const LLColor4 *color; - S32 disabled; // initialized to 0 - int level; // calculated based on desc - int parent; // calculated -}; +//static const int FTV_DISPLAY_NUM = (sizeof(ft_display_table)/sizeof(ft_display_table[0])); +static S32 FTV_NUM_TIMERS; +const S32 FTV_MAX_DEPTH = 8; -static const LLColor4 red0(0.5f, 0.0f, 0.0f, 1.0f); -static const LLColor4 green0(0.0f, 0.5f, 0.0f, 1.0f); -static const LLColor4 blue0(0.0f, 0.0f, 0.5f, 1.0f); -static const LLColor4 blue7(0.0f, 0.0f, 0.5f, 1.0f); +std::vector ft_display_idx; // line of table entry for display purposes (for collapse) -static const LLColor4 green7(0.6f, 1.0f, 0.4f, 1.0f); -static const LLColor4 green8(0.4f, 1.0f, 0.6f, 1.0f); -static const LLColor4 green9(0.6f, 1.0f, 0.6f, 1.0f); +typedef LLTreeDFSIter timer_tree_iterator_t; -// green(6), blue, yellow, orange, pink(2), cyan -// red (5) magenta (4) -static struct ft_display_info ft_display_table[] = -{ - { LLFastTimer::FTM_FRAME, "Frame", &LLColor4::white, 0 }, - { LLFastTimer::FTM_MESSAGES, " System Messages", &LLColor4::grey1, 1 }, - { LLFastTimer::FTM_MOUSEHANDLER, " Mouse", &LLColor4::grey1, 0 }, - { LLFastTimer::FTM_KEYHANDLER, " Keyboard", &LLColor4::grey1, 0 }, - { LLFastTimer::FT_STRING_FORMAT, " String Format", &LLColor4::grey3, 0 }, - { LLFastTimer::FTM_SLEEP, " Sleep", &LLColor4::grey2, 0 }, - { LLFastTimer::FTM_IDLE, " Idle", &blue0, 0 }, - { LLFastTimer::FTM_STATEMACHINE, " State Machines", &LLColor4::yellow1, 0 }, - { LLFastTimer::FTM_PUMP, " Pump", &LLColor4::magenta2, 1 }, - { LLFastTimer::FTM_CURL, " Curl", &LLColor4::magenta3, 0 }, - { LLFastTimer::FTM_PUMPIO, " PumpIO", &LLColor4::magenta1, 0 }, - { LLFastTimer::FTM_INVENTORY, " Inventory Update", &LLColor4::purple6, 1 }, - { LLFastTimer::FTM_AUTO_SELECT, " Open and Select", &LLColor4::red, 0 }, - { LLFastTimer::FTM_FILTER, " Filter", &LLColor4::red2, 0 }, - { LLFastTimer::FTM_ARRANGE, " Arrange", &LLColor4::red3, 0 }, - { LLFastTimer::FTM_REFRESH, " Refresh", &LLColor4::red4, 0 }, - { LLFastTimer::FTM_SORT, " Sort", &LLColor4::red5, 0 }, - { LLFastTimer::FTM_RESET_DRAWORDER, " ResetDrawOrder", &LLColor4::pink1, 0 }, - { LLFastTimer::FTM_WORLD_UPDATE, " World Update", &LLColor4::blue1, 1 }, - { LLFastTimer::FTM_UPDATE_MOVE, " Move Objects", &LLColor4::pink2, 0 }, - { LLFastTimer::FTM_OCTREE_BALANCE, " Octree Balance", &LLColor4::red3, 0 }, - { LLFastTimer::FTM_SIMULATE_PARTICLES, " Particle Sim", &LLColor4::blue4, 0 }, - { LLFastTimer::FTM_OBJECTLIST_UPDATE, " Object Update", &LLColor4::purple1, 1 }, - { LLFastTimer::FTM_AVATAR_UPDATE, " Avatars", &LLColor4::purple2, 0 }, - { LLFastTimer::FTM_JOINT_UPDATE, " Joints", &LLColor4::purple3, 0 }, - { LLFastTimer::FTM_ATTACHMENT_UPDATE, " Attachments", &LLColor4::purple4, 0 }, - { LLFastTimer::FTM_UPDATE_ANIMATION, " Animation", &LLColor4::purple5, 0 }, - { LLFastTimer::FTM_FLEXIBLE_UPDATE, " Flex Update", &LLColor4::pink2, 0 }, - { LLFastTimer::FTM_LOD_UPDATE, " LOD Update", &LLColor4::magenta1, 0 }, - { LLFastTimer::FTM_REGION_UPDATE, " Region Update", &LLColor4::cyan2, 0 }, - { LLFastTimer::FTM_NETWORK, " Network", &LLColor4::orange1, 1 }, - { LLFastTimer::FTM_IDLE_NETWORK, " Decode Msgs", &LLColor4::orange2, 0 }, - { LLFastTimer::FTM_PROCESS_MESSAGES, " Process Msgs", &LLColor4::orange3, 0 }, - { LLFastTimer::FTM_PROCESS_OBJECTS, " Object Updates",&LLColor4::orange4, 0 }, - { LLFastTimer::FTM_CREATE_OBJECT, " Create Obj", &LLColor4::orange5, 0 }, -// { LLFastTimer::FTM_LOAD_AVATAR, " Load Avatar", &LLColor4::pink2, 0 }, - { LLFastTimer::FTM_PROCESS_IMAGES, " Image Updates",&LLColor4::orange6, 0 }, - { LLFastTimer::FTM_PIPELINE, " Pipeline", &LLColor4::magenta4, 0 }, - { LLFastTimer::FTM_CLEANUP, " Cleanup", &LLColor4::cyan3, 0 }, - { LLFastTimer::FTM_AUDIO_UPDATE, " Audio Update", &LLColor4::yellow3, 0 }, - { LLFastTimer::FTM_VFILE_WAIT, " VFile Wait", &LLColor4::cyan6, 0 }, -// { LLFastTimer::FTM_IDLE_CB, " Callbacks", &LLColor4::pink1, 0 }, - { LLFastTimer::FTM_RENDER, " Render", &green0, 1 }, - { LLFastTimer::FTM_PICK, " Pick", &LLColor4::purple, 1 }, - { LLFastTimer::FTM_HUD_EFFECTS, " HUD Effects", &LLColor4::orange1, 0 }, - { LLFastTimer::FTM_HUD_UPDATE, " HUD Update", &LLColor4::orange2, 0 }, - { LLFastTimer::FTM_UPDATE_SKY, " Sky Update", &LLColor4::cyan1, 0 }, - { LLFastTimer::FTM_UPDATE_TEXTURES, " Textures", &LLColor4::pink2, 0 }, - { LLFastTimer::FTM_GEO_UPDATE, " Geo Update", &LLColor4::blue3, 1 }, - { LLFastTimer::FTM_UPDATE_PRIMITIVES, " Volumes", &LLColor4::blue4, 0 }, - { LLFastTimer::FTM_UPDATE_RIGGED_VOLUME," Rigged", &LLColor4::red3, 0 }, - { LLFastTimer::FTM_SKIN_RIGGED, " Skin", &LLColor4::green1, 0 }, - { LLFastTimer::FTM_RIGGED_OCTREE, " Octree", &LLColor4::green5, 0 }, - { LLFastTimer::FTM_GEN_VOLUME, " Gen Volume", &LLColor4::yellow3, 0 }, - { LLFastTimer::FTM_GEN_FLEX, " Flexible", &LLColor4::yellow4, 0 }, - { LLFastTimer::FTM_GEN_TRIANGLES, " Triangles", &LLColor4::yellow5, 0 }, - { LLFastTimer::FTM_UPDATE_AVATAR, " Avatar", &LLColor4::yellow1, 0 }, - { LLFastTimer::FTM_UPDATE_TREE, " Tree", &LLColor4::yellow2, 0 }, - { LLFastTimer::FTM_UPDATE_TERRAIN, " Terrain", &LLColor4::yellow6, 0 }, - { LLFastTimer::FTM_UPDATE_CLOUDS, " Clouds", &LLColor4::yellow7, 0 }, - { LLFastTimer::FTM_UPDATE_GRASS, " Grass", &LLColor4::yellow8, 0 }, - { LLFastTimer::FTM_UPDATE_WATER, " Water", &LLColor4::yellow9, 0 }, - { LLFastTimer::FTM_GEO_LIGHT, " Lighting", &LLColor4::yellow1, 0 }, - { LLFastTimer::FTM_GEO_SHADOW, " Shadow", &LLColor4::black, 0 }, - { LLFastTimer::FTM_UPDATE_PARTICLES, " Particles", &LLColor4::blue5, 0 }, - { LLFastTimer::FTM_GEO_RESERVE, " Reserve", &LLColor4::blue6, 0 }, - { LLFastTimer::FTM_UPDATE_LIGHTS, " Lights", &LLColor4::yellow2, 0 }, - { LLFastTimer::FTM_GEO_SKY, " Sky", &LLColor4::yellow3, 0 }, - { LLFastTimer::FTM_UPDATE_WLPARAM, " Windlight Param",&LLColor4::magenta2, 0 }, - { LLFastTimer::FTM_CULL, " Object Cull", &LLColor4::blue2, 1 }, - { LLFastTimer::FTM_CULL_REBOUND, " Rebound", &LLColor4::blue3, 0 }, - { LLFastTimer::FTM_FRUSTUM_CULL, " Frustum Cull", &LLColor4::blue4, 0 }, - { LLFastTimer::FTM_OCCLUSION_READBACK, " Occlusion Read", &LLColor4::red2, 0 }, - { LLFastTimer::FTM_IMAGE_UPDATE, " Image Update", &LLColor4::yellow4, 1 }, - { LLFastTimer::FTM_IMAGE_CREATE, " Image CreateGL",&LLColor4::yellow5, 0 }, - { LLFastTimer::FTM_IMAGE_DECODE, " Image Decode", &LLColor4::yellow6, 0 }, - { LLFastTimer::FTM_IMAGE_READBACK, " Image Readback",&LLColor4::red2, 0 }, - { LLFastTimer::FTM_IMAGE_MARK_DIRTY, " Dirty Textures",&LLColor4::red1, 0 }, - { LLFastTimer::FTM_STATESORT, " State Sort", &LLColor4::orange1, 1 }, - { LLFastTimer::FTM_STATESORT_DRAWABLE, " Drawable", &LLColor4::orange2, 0 }, - { LLFastTimer::FTM_STATESORT_POSTSORT, " Post Sort", &LLColor4::orange3, 0 }, +BOOL LLFastTimerView::sAnalyzePerformance = FALSE; - { LLFastTimer::FTM_MESH_UPDATE, " Mesh Update", &LLColor4::orange4, 0 }, - { LLFastTimer::FTM_MESH_LOCK1, " Lock 1", &LLColor4::orange5, 0 }, - { LLFastTimer::FTM_MESH_LOCK2, " Lock 2", &LLColor4::orange6, 0 }, - { LLFastTimer::FTM_LOAD_MESH_LOD, " Load LOD", &LLColor4::yellow3, 0 }, +static timer_tree_iterator_t begin_timer_tree(LLFastTimer::NamedTimer& id) +{ + return timer_tree_iterator_t(&id, + boost::bind(boost::mem_fn(&LLFastTimer::NamedTimer::beginChildren), _1), + boost::bind(boost::mem_fn(&LLFastTimer::NamedTimer::endChildren), _1)); +} - { LLFastTimer::FTM_REBUILD_OCCLUSION_VB," Occlusion", &LLColor4::cyan5, 0 }, - { LLFastTimer::FTM_REBUILD_VBO, " VBO Rebuild", &LLColor4::red4, 0 }, - { LLFastTimer::FTM_REBUILD_VOLUME_VB, " Volume", &LLColor4::blue1, 0 }, - { LLFastTimer::FTM_FACE_GET_GEOM, " Face Geom", &LLColor4::green1, 0 }, - { LLFastTimer::FTM_FACE_GEOM_POSITION, " Position", &LLColor4::green2, 0 }, - { LLFastTimer::FTM_FACE_GEOM_NORMAL, " Normal", &LLColor4::green3, 0 }, - { LLFastTimer::FTM_FACE_GEOM_TEXTURE, " Texture", &LLColor4::green4, 0 }, - { LLFastTimer::FTM_FACE_GEOM_COLOR, " Color", &LLColor4::green5, 0 }, - { LLFastTimer::FTM_FACE_GEOM_EMISSIVE, " Emissive", &LLColor4::green6, 0 }, - { LLFastTimer::FTM_FACE_GEOM_WEIGHTS, " Weights", &LLColor4::magenta1, 0 }, - { LLFastTimer:: FTM_FACE_GEOM_BINORMAL, " Binormal", &LLColor4::magenta2, 0 }, - { LLFastTimer:: FTM_FACE_GEOM_INDEX, " Index", &LLColor4::magenta3, 0 }, - { LLFastTimer::FTM_TEMP1, " Temp1", &LLColor4::blue2, 0 }, - { LLFastTimer::FTM_TEMP2, " Temp2", &LLColor4::blue3, 0 }, - { LLFastTimer::FTM_TEMP3, " Temp3", &LLColor4::blue4, 0 }, - { LLFastTimer::FTM_TEMP4, " Temp4", &LLColor4::blue5, 0 }, - { LLFastTimer::FTM_TEMP5, " Temp5", &LLColor4::cyan1, 0 }, - { LLFastTimer::FTM_TEMP6, " Temp6", &LLColor4::cyan2, 0 }, - { LLFastTimer::FTM_TEMP7, " Temp7", &LLColor4::cyan3, 0 }, - { LLFastTimer::FTM_TEMP8, " Temp8", &LLColor4::cyan4, 0 }, - { LLFastTimer::FTM_TEMP9, " Temp9", &LLColor4::cyan5, 0 }, - { LLFastTimer::FTM_TEMP10, " Temp10", &LLColor4::green1, 0 }, - { LLFastTimer::FTM_TEMP11, " Temp11", &LLColor4::green2, 0 }, - { LLFastTimer::FTM_TEMP12, " Temp12", &LLColor4::green3, 0 }, - { LLFastTimer::FTM_TEMP13, " Temp13", &LLColor4::green4, 0 }, - { LLFastTimer::FTM_TEMP14, " Temp14", &LLColor4::green5, 0 }, - { LLFastTimer::FTM_TEMP15, " Temp15", &LLColor4::green6, 0 }, +static timer_tree_iterator_t end_timer_tree() +{ + return timer_tree_iterator_t(); +} -// { LLFastTimer::FTM_REBUILD_NONE_VB, " Unknown", &LLColor4::cyan5, 0 }, -// { LLFastTimer::FTM_REBUILD_BRIDGE_VB, " Bridge", &LLColor4::blue2, 0 }, -// { LLFastTimer::FTM_REBUILD_HUD_VB, " HUD", &LLColor4::blue3, 0 }, - { LLFastTimer::FTM_REBUILD_TERRAIN_VB, " Terrain", &LLColor4::blue4, 0 }, -// { LLFastTimer::FTM_REBUILD_WATER_VB, " Water", &LLColor4::blue5, 0 }, -// { LLFastTimer::FTM_REBUILD_TREE_VB, " Tree", &LLColor4::cyan1, 0 }, - { LLFastTimer::FTM_REBUILD_PARTICLE_VB, " Particle", &LLColor4::cyan2, 0 }, -// { LLFastTimer::FTM_REBUILD_CLOUD_VB, " Cloud", &LLColor4::cyan3, 0 }, - { LLFastTimer::FTM_REBUILD_GRASS_VB, " Grass", &LLColor4::cyan4, 0 }, - { LLFastTimer::FTM_SHADOW_RENDER, " Shadow", &LLColor4::green5, 1 }, - { LLFastTimer::FTM_SHADOW_SIMPLE, " Simple", &LLColor4::yellow2, 1 }, - { LLFastTimer::FTM_SHADOW_ALPHA, " Alpha", &LLColor4::yellow6, 1 }, - { LLFastTimer::FTM_SHADOW_TERRAIN, " Terrain", &LLColor4::green6, 1 }, - { LLFastTimer::FTM_SHADOW_AVATAR, " Avatar", &LLColor4::yellow1, 1 }, - { LLFastTimer::FTM_SHADOW_TREE, " Tree", &LLColor4::yellow8, 1 }, - { LLFastTimer::FTM_RENDER_GEOMETRY, " Geometry", &LLColor4::green2, 1 }, - { LLFastTimer::FTM_POOLS, " Pools", &LLColor4::green3, 1 }, - { LLFastTimer::FTM_POOLRENDER, " RenderPool", &LLColor4::green4, 1 }, - { LLFastTimer::FTM_RENDER_TERRAIN, " Terrain", &LLColor4::green6, 0 }, - { LLFastTimer::FTM_RENDER_CHARACTERS, " Avatars", &LLColor4::yellow1, 0 }, - { LLFastTimer::FTM_RENDER_SIMPLE, " Simple", &LLColor4::yellow2, 0 }, - { LLFastTimer::FTM_RENDER_FULLBRIGHT, " Fullbright", &LLColor4::yellow5, 0 }, - { LLFastTimer::FTM_RENDER_GLOW, " Glow", &LLColor4::orange1, 0 }, - { LLFastTimer::FTM_RENDER_GRASS, " Grass", &LLColor4::yellow6, 0 }, - { LLFastTimer::FTM_RENDER_INVISIBLE, " Invisible", &LLColor4::red2, 0 }, - { LLFastTimer::FTM_RENDER_SHINY, " Shiny", &LLColor4::yellow3, 0 }, - { LLFastTimer::FTM_RENDER_BUMP, " Bump", &LLColor4::yellow4, 0 }, - { LLFastTimer::FTM_RENDER_TREES, " Trees", &LLColor4::yellow8, 0 }, - { LLFastTimer::FTM_RENDER_OCCLUSION, " Occlusion", &LLColor4::red1, 0 }, - { LLFastTimer::FTM_RENDER_CLOUDS, " Clouds", &LLColor4::yellow5, 0 }, - { LLFastTimer::FTM_RENDER_ALPHA, " Alpha", &LLColor4::yellow6, 0 }, - { LLFastTimer::FTM_RENDER_HUD, " HUD", &LLColor4::yellow7, 0 }, - { LLFastTimer::FTM_RENDER_WATER, " Water", &LLColor4::yellow9, 0 }, - { LLFastTimer::FTM_RENDER_WL_SKY, " WL Sky", &LLColor4::blue3, 0 }, - { LLFastTimer::FTM_RENDER_FAKE_VBO_UPDATE," Fake VBO update", &LLColor4::red2, 0 }, - { LLFastTimer::FTM_RENDER_BLOOM, " Bloom", &LLColor4::blue4, 0 }, - { LLFastTimer::FTM_RENDER_BLOOM_FBO, " First FBO", &LLColor4::blue, 0 }, - { LLFastTimer::FTM_RENDER_DEFERRED, " Deferred", &LLColor4::cyan4, 1 }, - { LLFastTimer::FTM_BIND_DEFERRED, " Bind", &LLColor4::pink2, 0 }, - { LLFastTimer::FTM_SUN_SHADOW, " Sun Shadow", &LLColor4::cyan5, 0 }, - { LLFastTimer::FTM_SOFTEN_SHADOW, " Soften Shadow", &LLColor4::yellow1, 0 }, - { LLFastTimer::FTM_EDGE_DETECTION, " Edge Detect", &LLColor4::cyan2, 0 }, - { LLFastTimer::FTM_GI_TRACE, " GI Trace", &LLColor4::green6, 0 }, - { LLFastTimer::FTM_GI_GATHER, " GI Gather", &LLColor4::cyan1, 0 }, - { LLFastTimer::FTM_ATMOSPHERICS, " Atmos", &LLColor4::pink1, 0 }, - { LLFastTimer::FTM_LOCAL_LIGHTS, " Local Lights", &LLColor4::blue2, 0 }, - { LLFastTimer::FTM_FULLSCREEN_LIGHTS, " FS Lights", &LLColor4::purple4, 0 }, - { LLFastTimer::FTM_PROJECTORS, " Project", &LLColor4::orange2, 0 }, - { LLFastTimer::FTM_POST, " Postprocess", &LLColor4::red4, 0 }, - { LLFastTimer::FTM_VISIBLE_CLOUD, " Visible Cloud", &LLColor4::blue5, 0 }, - { LLFastTimer::FTM_RENDER_UI, " UI", &LLColor4::cyan4, 1 }, - { LLFastTimer::FTM_RENDER_TIMER, " Timers", &LLColor4::cyan5, 1, 0 }, - { LLFastTimer::FTM_RENDER_FONTS, " Fonts", &LLColor4::pink1, 0 }, - { LLFastTimer::FTM_SWAP, " Swap", &LLColor4::pink2, 0 }, - { LLFastTimer::FTM_CLIENT_COPY, " Client Copy", &LLColor4::red1, 1}, - -#if 0 || !LL_RELEASE_FOR_DOWNLOAD - { LLFastTimer::FTM_TEMP1, " Temp1", &LLColor4::red1, 0 }, - { LLFastTimer::FTM_TEMP2, " Temp2", &LLColor4::magenta1, 0 }, - { LLFastTimer::FTM_TEMP3, " Temp3", &LLColor4::red2, 0 }, - { LLFastTimer::FTM_TEMP4, " Temp4", &LLColor4::magenta2, 0 }, - { LLFastTimer::FTM_TEMP5, " Temp5", &LLColor4::red3, 0 }, - { LLFastTimer::FTM_TEMP6, " Temp6", &LLColor4::magenta3, 0 }, - { LLFastTimer::FTM_TEMP7, " Temp7", &LLColor4::red4, 0 }, - { LLFastTimer::FTM_TEMP8, " Temp8", &LLColor4::magenta4, 0 }, -#endif - - { LLFastTimer::FTM_OTHER, " Other", &red0 } -}; -static int ft_display_didcalc = 0; -static const int FTV_DISPLAY_NUM = LL_ARRAY_SIZE(ft_display_table); - -S32 ft_display_idx[FTV_DISPLAY_NUM]; // line of table entry for display purposes (for collapse) LLFastTimerView::LLFastTimerView(const std::string& name, const LLRect& rect) - : LLFloater(name, rect, std::string(), FALSE, 1, 1, FALSE, FALSE, TRUE) + : LLFloater(name, rect, std::string(), FALSE, 1, 1, FALSE, FALSE, TRUE), + mHoverTimer(NULL) { setVisible(FALSE); mDisplayMode = 0; mAvgCountTotal = 0; mMaxCountTotal = 0; - mDisplayCenter = 1; + mDisplayCenter = ALIGN_CENTER; mDisplayCalls = 0; mDisplayHz = 0; mScrollIndex = 0; - mHoverIndex = -1; + mHoverID = NULL; mHoverBarIndex = -1; - mBarStart = new S32[(MAX_VISIBLE_HISTORY + 1) * FTV_DISPLAY_NUM]; - memset(mBarStart, 0, (MAX_VISIBLE_HISTORY + 1) * FTV_DISPLAY_NUM * sizeof(S32)); - mBarEnd = new S32[(MAX_VISIBLE_HISTORY + 1) * FTV_DISPLAY_NUM]; - memset(mBarEnd, 0, (MAX_VISIBLE_HISTORY + 1) * FTV_DISPLAY_NUM * sizeof(S32)); - mSubtractHidden = 0; + FTV_NUM_TIMERS = LLFastTimer::NamedTimer::instanceCount(); mPrintStats = -1; + mAverageCyclesPerTimer = 0; + LLUICtrlFactory::getInstance()->buildFloater(this, "floater_fast_timers.xml"); +} - // One-time setup - if (!ft_display_didcalc) +void LLFastTimerView::onPause() +{ + LLFastTimer::sPauseHistory = !LLFastTimer::sPauseHistory; + // reset scroll to bottom when unpausing + if (!LLFastTimer::sPauseHistory) { - int pidx[FTV_DISPLAY_NUM]; - int pdisabled[FTV_DISPLAY_NUM]; - for (S32 i=0; i < FTV_DISPLAY_NUM; i++) - { - int level = 0; - const char *text = ft_display_table[i].desc; - while(text[0] == ' ') - { - text++; - level++; - } - llassert(level < FTV_DISPLAY_NUM); - ft_display_table[i].desc = text; - ft_display_table[i].level = level; - if (level > 0) - { - ft_display_table[i].parent = pidx[level-1]; - if (pdisabled[level-1]) - { - ft_display_table[i].disabled = 3; - } - } - else - { - ft_display_table[i].parent = -1; - } - ft_display_idx[i] = i; - pidx[level] = i; - pdisabled[level] = ft_display_table[i].disabled; - } - ft_display_didcalc = 1; + mScrollIndex = 0; + LLFastTimer::sResetHistory = true; + getChild("pause_btn")->setLabel(getString("pause")); + } + else + { + getChild("pause_btn")->setLabel(getString("run")); } } -LLFastTimerView::~LLFastTimerView() +void LLFastTimerView::onPauseHandler(void *data) { - delete[] mBarStart; - delete[] mBarEnd; + ((LLFastTimerView*)data)->onPause(); +} + +BOOL LLFastTimerView::postBuild() +{ + LLButton& pause_btn = getChildRef("pause_btn"); + + pause_btn.setClickedCallback(&LLFastTimerView::onPauseHandler,this); + //pause_btn.setCommitCallback(boost::bind(&LLFastTimerView::onPause, this)); + + return TRUE; } BOOL LLFastTimerView::handleRightMouseDown(S32 x, S32 y, MASK mask) { - if (mBarRect.pointInRect(x, y)) + if (mHoverTimer ) + { + // right click collapses timers + if (!mHoverTimer->getCollapsed()) + { + mHoverTimer->setCollapsed(true); + } + else if (mHoverTimer->getParent()) + { + mHoverTimer->getParent()->setCollapsed(true); + } + return TRUE; + } + else if (mBarRect.pointInRect(x, y)) { S32 bar_idx = MAX_VISIBLE_HISTORY - ((y - mBarRect.mBottom) * (MAX_VISIBLE_HISTORY + 2) / mBarRect.getHeight()); bar_idx = llclamp(bar_idx, 0, MAX_VISIBLE_HISTORY); - mPrintStats = bar_idx; -// return TRUE; // for now, pass all mouse events through + mPrintStats = LLFastTimer::NamedTimer::HISTORY_NUM - mScrollIndex - bar_idx; + return TRUE; } - return FALSE; + return LLFloater::handleRightMouseDown(x, y, mask); } -S32 LLFastTimerView::getLegendIndex(S32 y) +LLFastTimer::NamedTimer* LLFastTimerView::getLegendID(S32 y) { S32 idx = (getRect().getHeight() - y) / ((S32) LLFontGL::getFontMonospace()->getLineHeight()+2) - 5; - if (idx >= 0 && idx < FTV_DISPLAY_NUM) + + if (idx >= 0 && idx < (S32)ft_display_idx.size()) { return ft_display_idx[idx]; } - return -1; + return NULL; +} + +BOOL LLFastTimerView::handleDoubleClick(S32 x, S32 y, MASK mask) +{ + for(timer_tree_iterator_t it = begin_timer_tree(LLFastTimer::NamedTimer::getRootNamedTimer()); + it != end_timer_tree(); + ++it) + { + (*it)->setCollapsed(false); + } + return TRUE; } BOOL LLFastTimerView::handleMouseDown(S32 x, S32 y, MASK mask) { - { - S32 local_x = x - mButtons[BUTTON_CLOSE]->getRect().mLeft; - S32 local_y = y - mButtons[BUTTON_CLOSE]->getRect().mBottom; - if (mButtons[BUTTON_CLOSE]->getVisible() && - mButtons[BUTTON_CLOSE]->pointInView(local_x, local_y)) - { - return LLFloater::handleMouseDown(x, y, mask); - } - } if (x < mBarRect.mLeft) { - S32 legend_index = getLegendIndex(y); - if (legend_index >= 0 && legend_index < FTV_DISPLAY_NUM) + LLFastTimer::NamedTimer* idp = getLegendID(y); + if (idp) { - S32 disabled = ft_display_table[legend_index].disabled; - if (++disabled > 2) - disabled = 0; - ft_display_table[legend_index].disabled = disabled; - S32 level = ft_display_table[legend_index].level; - - // propagate enable/disable to all children - legend_index++; - while (legend_index < FTV_DISPLAY_NUM && ft_display_table[legend_index].level > level) - { - ft_display_table[legend_index].disabled = disabled ? 3 : 0; - legend_index++; - } + idp->setCollapsed(!idp->getCollapsed()); } } + else if (mHoverTimer) + { + //left click drills down by expanding timers + mHoverTimer->setCollapsed(false); + } else if (mask & MASK_ALT) { - if (mask & MASK_SHIFT) - { - mSubtractHidden = !mSubtractHidden; - } - else if (mask & MASK_CONTROL) + if (mask & MASK_CONTROL) { mDisplayHz = !mDisplayHz; } @@ -405,44 +218,51 @@ BOOL LLFastTimerView::handleMouseDown(S32 x, S32 y, MASK mask) } else if (mask & MASK_CONTROL) { - if (++mDisplayCenter > 2) - mDisplayCenter = 0; + mDisplayCenter = (ChildAlignment)((mDisplayCenter + 1) % ALIGN_COUNT); } - else + else if (mGraphRect.pointInRect(x, y)) { - // pause/unpause - LLFastTimer::sPauseHistory = !LLFastTimer::sPauseHistory; - // reset scroll to bottom when unpausing - if (!LLFastTimer::sPauseHistory) - { - mScrollIndex = 0; - } + gFocusMgr.setMouseCapture(this); + return TRUE; } - // SJB: Don't pass mouse clicks through the display - return TRUE; + //else + //{ + // // pause/unpause + // LLFastTimer::sPauseHistory = !LLFastTimer::sPauseHistory; + // // reset scroll to bottom when unpausing + // if (!LLFastTimer::sPauseHistory) + // { + // mScrollIndex = 0; + // } + //} + return LLFloater::handleMouseDown(x, y, mask); } BOOL LLFastTimerView::handleMouseUp(S32 x, S32 y, MASK mask) { + if (hasMouseCapture()) { - S32 local_x = x - mButtons[BUTTON_CLOSE]->getRect().mLeft; - S32 local_y = y - mButtons[BUTTON_CLOSE]->getRect().mBottom; - if (mButtons[BUTTON_CLOSE]->getVisible() && - mButtons[BUTTON_CLOSE]->pointInView(local_x, local_y)) - { - return LLFloater::handleMouseUp(x, y, mask); - } + gFocusMgr.setMouseCapture(NULL); } - return FALSE; + return LLFloater::handleMouseUp(x, y, mask);; } - BOOL LLFastTimerView::handleHover(S32 x, S32 y, MASK mask) { + if (hasMouseCapture()) + { + F32 lerp = llclamp(1.f - (F32) (x - mGraphRect.mLeft) / (F32) mGraphRect.getWidth(), 0.f, 1.f); + mScrollIndex = llround( lerp * (F32)(LLFastTimer::NamedTimer::HISTORY_NUM - MAX_VISIBLE_HISTORY)); + mScrollIndex = llclamp( mScrollIndex, 0, LLFastTimer::getLastFrameIndex()); + return TRUE; + } + mHoverTimer = NULL; + mHoverID = NULL; + if(LLFastTimer::sPauseHistory && mBarRect.pointInRect(x, y)) { - mHoverIndex = -1; - mHoverBarIndex = MAX_VISIBLE_HISTORY - ((y - mBarRect.mBottom) * (MAX_VISIBLE_HISTORY + 2) / mBarRect.getHeight()); + mHoverBarIndex = llmin(LLFastTimer::getCurFrameIndex() - 1, + MAX_VISIBLE_HISTORY - ((y - mBarRect.mBottom) * (MAX_VISIBLE_HISTORY + 2) / mBarRect.getHeight())); if (mHoverBarIndex == 0) { return TRUE; @@ -451,51 +271,106 @@ BOOL LLFastTimerView::handleHover(S32 x, S32 y, MASK mask) { mHoverBarIndex = 0; } - for (S32 i = 0; i < FTV_DISPLAY_NUM; i++) + + S32 i = 0; + for(timer_tree_iterator_t it = begin_timer_tree(LLFastTimer::NamedTimer::getRootNamedTimer()); + it != end_timer_tree(); + ++it, ++i) { - if (x > mBarStart[mHoverBarIndex * FTV_DISPLAY_NUM + i] && - x < mBarEnd[mHoverBarIndex * FTV_DISPLAY_NUM + i] && - ft_display_table[i].disabled <= 1) + // is mouse over bar for this timer? + if (x > mBarStart[mHoverBarIndex][i] && + x < mBarEnd[mHoverBarIndex][i]) { - mHoverIndex = i; + mHoverID = (*it); + if (mHoverTimer != *it) + { + // could be that existing tooltip is for a parent and is thus + // covering region for this new timer, go ahead and unblock + // so we can create a new tooltip + //LLToolTipMgr::instance().unblockToolTips(); + mHoverTimer = (*it); + } + + mToolTipRect.set(mBarStart[mHoverBarIndex][i], + mBarRect.mBottom + llround(((F32)(MAX_VISIBLE_HISTORY - mHoverBarIndex + 1)) * ((F32)mBarRect.getHeight() / ((F32)MAX_VISIBLE_HISTORY + 2.f))), + mBarEnd[mHoverBarIndex][i], + mBarRect.mBottom + llround((F32)(MAX_VISIBLE_HISTORY - mHoverBarIndex) * ((F32)mBarRect.getHeight() / ((F32)MAX_VISIBLE_HISTORY + 2.f)))); + } + + if ((*it)->getCollapsed()) + { + it.skipDescendants(); } } } else if (x < mBarRect.mLeft) { - S32 legend_index = getLegendIndex(y); - if (legend_index >= 0 && legend_index < FTV_DISPLAY_NUM) + LLFastTimer::NamedTimer* timer_id = getLegendID(y); + if (timer_id) { - mHoverIndex = legend_index; + mHoverID = timer_id; } } - return FALSE; + return LLFloater::handleHover(x, y, mask); +} + + +BOOL LLFastTimerView::handleToolTip(S32 x, S32 y, std::string& msg, LLRect* sticky_rect_screen) +{ + std::string tool_tip; + if(LLFastTimer::sPauseHistory && mBarRect.pointInRect(x, y)) + { + // tooltips for timer bars + if (mHoverTimer) + { + tool_tip = mHoverTimer->getToolTip(LLFastTimer::NamedTimer::HISTORY_NUM - mScrollIndex - mHoverBarIndex); + } + } + else + { + // tooltips for timer legend + if (x < mBarRect.mLeft) + { + LLFastTimer::NamedTimer* idp = getLegendID(y); + if (idp) + { + tool_tip = idp->getToolTip(); + } + } + } + + if(!tool_tip.empty()) + { + msg = tool_tip; + localPointToScreen( + 0, 0, + &(sticky_rect_screen->mLeft), &(sticky_rect_screen->mBottom) ); + localPointToScreen( + getRect().getWidth(), getRect().getHeight(), + &(sticky_rect_screen->mRight), &(sticky_rect_screen->mTop) ); + return TRUE; + } + else + return LLFloater::handleToolTip(x, y, msg, sticky_rect_screen); } BOOL LLFastTimerView::handleScrollWheel(S32 x, S32 y, S32 clicks) { LLFastTimer::sPauseHistory = TRUE; - mScrollIndex = llclamp(mScrollIndex - clicks, - 0, llmin(LLFastTimer::sLastFrameIndex, (S32)LLFastTimer::FTM_HISTORY_NUM-MAX_VISIBLE_HISTORY)); + mScrollIndex = llclamp( mScrollIndex + clicks, + 0, + llmin(LLFastTimer::getLastFrameIndex(), (S32)LLFastTimer::NamedTimer::HISTORY_NUM - MAX_VISIBLE_HISTORY)); return TRUE; } -void LLFastTimerView::onClose(bool app_quitting) -{ - if (app_quitting) - { - LLFloater::close(app_quitting); - } - else - { - setVisible(FALSE); - } -} +static LLFastTimer::DeclareTimer FTM_RENDER_TIMER("Timers", true); + +static std::map sTimerColors; void LLFastTimerView::draw() { - LLFastTimer t(LLFastTimer::FTM_RENDER_TIMER); + LLFastTimer t(FTM_RENDER_TIMER); std::string tdesc; @@ -503,8 +378,8 @@ void LLFastTimerView::draw() F64 iclock_freq = 1000.0 / clock_freq; S32 margin = 10; - S32 height = (S32) (gViewerWindow->getVirtualWindowRect().getHeight()*0.75f); - S32 width = (S32) (gViewerWindow->getVirtualWindowRect().getWidth() * 0.75f); + S32 height = getRect().getHeight(); + S32 width = getRect().getWidth(); LLRect new_rect; new_rect.setLeftTopAndSize(getRect().mLeft, getRect().mTop, width, height); @@ -515,51 +390,19 @@ void LLFastTimerView::draw() S32 texth, textw; LLPointer box_imagep = LLUI::getUIImage("rounded_square.tga"); - // Make sure all timers are accounted for - // Set 'FTM_OTHER' to unaccounted ticks last frame - { - S32 display_timer[LLFastTimer::FTM_NUM_TYPES]; - S32 hidx = LLFastTimer::sLastFrameIndex % LLFastTimer::FTM_HISTORY_NUM; - for (S32 i=0; i < LLFastTimer::FTM_NUM_TYPES; i++) - { - display_timer[i] = 0; - } - for (S32 i=0; i < FTV_DISPLAY_NUM; i++) - { - S32 tidx = ft_display_table[i].timer; - display_timer[tidx] = 1; - } - LLFastTimer::sCountHistory[hidx][LLFastTimer::FTM_OTHER] = 0; - LLFastTimer::sCallHistory[hidx][LLFastTimer::FTM_OTHER] = 0; - for (S32 tidx = 0; tidx < LLFastTimer::FTM_NUM_TYPES; tidx++) - { - U64 counts = LLFastTimer::sCountHistory[hidx][tidx]; - if (counts > 0 && display_timer[tidx] == 0) - { - LLFastTimer::sCountHistory[hidx][LLFastTimer::FTM_OTHER] += counts; - LLFastTimer::sCallHistory[hidx][LLFastTimer::FTM_OTHER] += 1; - } - } - LLFastTimer::sCountAverage[LLFastTimer::FTM_OTHER] = 0; - LLFastTimer::sCallAverage[LLFastTimer::FTM_OTHER] = 0; - for (S32 h = 0; h < LLFastTimer::FTM_HISTORY_NUM; h++) - { - LLFastTimer::sCountAverage[LLFastTimer::FTM_OTHER] += LLFastTimer::sCountHistory[h][LLFastTimer::FTM_OTHER]; - LLFastTimer::sCallAverage[LLFastTimer::FTM_OTHER] += LLFastTimer::sCallHistory[h][LLFastTimer::FTM_OTHER]; - } - LLFastTimer::sCountAverage[LLFastTimer::FTM_OTHER] /= LLFastTimer::FTM_HISTORY_NUM; - LLFastTimer::sCallAverage[LLFastTimer::FTM_OTHER] /= LLFastTimer::FTM_HISTORY_NUM; - } - // Draw the window background - { - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - gl_rect_2d(0, getRect().getHeight(), getRect().getWidth(), 0, LLColor4(0.f, 0.f, 0.f, 0.25f)); - } + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + gl_rect_2d(0, getRect().getHeight(), getRect().getWidth(), 0, LLColor4(0.f, 0.f, 0.f, 0.25f)); S32 xleft = margin; S32 ytop = margin; + mAverageCyclesPerTimer = LLFastTimer::sTimerCalls == 0 + ? 0 + : llround(lerp((F32)mAverageCyclesPerTimer, (F32)(LLFastTimer::sTimerCycles / (U64)LLFastTimer::sTimerCalls), 0.1f)); + LLFastTimer::sTimerCycles = 0; + LLFastTimer::sTimerCalls = 0; + // Draw some help { @@ -567,6 +410,10 @@ void LLFastTimerView::draw() y = height - ytop; texth = (S32)LLFontGL::getFontMonospace()->getLineHeight(); +#if TIME_FAST_TIMERS + tdesc = llformat("Cycles per timer call: %d", mAverageCyclesPerTimer); + LLFontGL::getFontMonospace()->renderUTF8(tdesc, 0, x, y, LLColor4::white, LLFontGL::LEFT, LLFontGL::TOP); +#else char modedesc[][32] = { "2 x Average ", "Max ", @@ -581,7 +428,6 @@ void LLFastTimerView::draw() tdesc = llformat("Full bar = %s [Click to pause/reset] [SHIFT-Click to toggle]",modedesc[mDisplayMode]); LLFontGL::getFontMonospace()->renderUTF8(tdesc, 0, x, y, LLColor4::white, LLFontGL::LEFT, LLFontGL::TOP); - textw = LLFontGL::getFontMonospace()->getWidth(tdesc); x = xleft, y -= (texth + 2); @@ -591,162 +437,139 @@ void LLFastTimerView::draw() LLFontGL::getFontMonospace()->renderUTF8(std::string("[Right-Click log selected] [ALT-Click toggle counts] [ALT-SHIFT-Click sub hidden]"), 0, x, y, LLColor4::white, LLFontGL::LEFT, LLFontGL::TOP); +#endif y -= (texth + 2); } - // Calc the total ticks - S32 histmax = llmin(LLFastTimer::sLastFrameIndex+1, MAX_VISIBLE_HISTORY); - U64 ticks_sum[LLFastTimer::FTM_HISTORY_NUM+1][FTV_DISPLAY_NUM]; - for (S32 j=-1; j= 0) - hidx = (LLFastTimer::sLastFrameIndex+j) % LLFastTimer::FTM_HISTORY_NUM; - else - hidx = -1; - - // calculate tick info by adding child ticks to parents - for (S32 i=0; i < FTV_DISPLAY_NUM; i++) - { - if (mSubtractHidden && ft_display_table[i].disabled > 1) - { - continue; - } - // Get ticks - S32 tidx = ft_display_table[i].timer; - if (hidx >= 0) - ticks_sum[j+1][i] = LLFastTimer::sCountHistory[hidx][tidx]; - else - ticks_sum[j+1][i] = LLFastTimer::sCountAverage[tidx]; - S32 pidx = ft_display_table[i].parent; - // Add ticks to parents - while (pidx >= 0) - { - ticks_sum[j+1][pidx] += ticks_sum[j+1][i]; - pidx = ft_display_table[pidx].parent; - } - } - } + S32 histmax = llmin(LLFastTimer::getLastFrameIndex()+1, MAX_VISIBLE_HISTORY); // Draw the legend - - S32 legendwidth = 0; xleft = margin; ytop = y; y -= (texth + 2); - S32 cur_line = 0; - S32 display_line[FTV_DISPLAY_NUM]; - for (S32 i=0; i 3 * texth) + F32 hue = 0.f; + + for (timer_tree_iterator_t it = begin_timer_tree(LLFastTimer::NamedTimer::getRootNamedTimer()); + it != timer_tree_iterator_t(); + ++it) + { + LLFastTimer::NamedTimer* idp = (*it); + + const F32 HUE_INCREMENT = 0.23f; + hue = fmodf(hue + HUE_INCREMENT, 1.f); + // saturation increases with depth + F32 saturation = clamp_rescale((F32)idp->getDepth(), 0.f, 3.f, 0.f, 1.f); + // lightness alternates with depth + F32 lightness = idp->getDepth() % 2 ? 0.5f : 0.6f; + + LLColor4 child_color; + child_color.setHSL(hue, saturation, lightness); + + sTimerColors[idp] = child_color; + } + + const S32 LEGEND_WIDTH = 220; + { + LLLocalClipRect clip(LLRect(margin, y, LEGEND_WIDTH, margin)); + S32 cur_line = 0; + ft_display_idx.clear(); + std::map display_line; + for (timer_tree_iterator_t it = begin_timer_tree(LLFastTimer::NamedTimer::getRootNamedTimer()); + it != timer_tree_iterator_t(); + ++it) { - if (i == mHoverIndex) + LLFastTimer::NamedTimer* idp = (*it); + display_line[idp] = cur_line; + ft_display_idx.push_back(idp); + cur_line++; + + x = xleft; + + left = x; right = x + texth; + top = y; bottom = y - texth; + S32 scale_offset = 0; + if (idp == mHoverID) { scale_offset = llfloor(sinf(mHighlightTimer.getElapsedTimeF32() * 6.f) * 2.f); } - gl_rect_2d(left - scale_offset, top + scale_offset, right + scale_offset, bottom - scale_offset, *ft_display_table[i].color); - } + gl_rect_2d(left - scale_offset, top + scale_offset, right + scale_offset, bottom - scale_offset, sTimerColors[idp]); - int tidx = ft_display_table[i].timer; - F32 ms = 0; - S32 calls = 0; - if (mHoverBarIndex > 0 && mHoverIndex >= 0) - { - S32 hidx = (LLFastTimer::sLastFrameIndex + (mHoverBarIndex - 1) - mScrollIndex) % LLFastTimer::FTM_HISTORY_NUM; - S32 bidx = LLFastTimer::FTM_HISTORY_NUM - mScrollIndex - mHoverBarIndex; - U64 ticks = ticks_sum[bidx+1][i]; // : LLFastTimer::sCountHistory[hidx][tidx]; - ms = (F32)((F64)ticks * iclock_freq); - calls = (S32)LLFastTimer::sCallHistory[hidx][tidx]; - } - else - { - U64 ticks = ticks_sum[0][i]; - ms = (F32)((F64)ticks * iclock_freq); - calls = (S32)LLFastTimer::sCallAverage[tidx]; - } - if (mDisplayCalls) - { - tdesc = llformat("%s (%d)",ft_display_table[i].desc,calls); - } - else - { - tdesc = llformat("%s [%.1f]",ft_display_table[i].desc,ms); - } - dx = (texth+4) + level*8; - - LLColor4 color = disabled > 1 ? LLColor4::grey : LLColor4::white; - if (level > 0 && y > 3 * texth) - { - S32 line_start_y = (top + bottom) / 2; - S32 line_end_y = line_start_y + ((texth + 2) * (display_line[i] - display_line[parent])) - (texth / 2); - gl_line_2d(x + dx - 8, line_start_y, x + dx, line_start_y, color); - S32 line_x = x + (texth + 4) + ((level - 1) * 8); - gl_line_2d(line_x, line_start_y, line_x, line_end_y, color); - if (disabled == 1) + F32 ms = 0; + S32 calls = 0; + if (mHoverBarIndex > 0 && mHoverID) { - gl_line_2d(line_x+4, line_start_y-3, line_x+4, line_start_y+4, color); - } - } - - x += dx; - BOOL is_child_of_hover_item = (i == mHoverIndex); - S32 next_parent = ft_display_table[i].parent; - while(!is_child_of_hover_item && next_parent >= 0) - { - is_child_of_hover_item = (mHoverIndex == next_parent); - next_parent = ft_display_table[next_parent].parent; - } - - if (y > 3 * texth) - { - if (is_child_of_hover_item) - { - LLFontGL::getFontMonospace()->renderUTF8(tdesc, 0, x, y, color, LLFontGL::LEFT, LLFontGL::TOP, LLFontGL::BOLD); + S32 hidx = LLFastTimer::NamedTimer::HISTORY_NUM - mScrollIndex - mHoverBarIndex; + U64 ticks = idp->getHistoricalCount(hidx); + ms = (F32)((F64)ticks * iclock_freq); + calls = (S32)idp->getHistoricalCalls(hidx); } else { - LLFontGL::getFontMonospace()->renderUTF8(tdesc, 0, x, y, color, LLFontGL::LEFT, LLFontGL::TOP); + U64 ticks = idp->getCountAverage(); + ms = (F32)((F64)ticks * iclock_freq); + calls = (S32)idp->getCallAverage(); + } + + if (mDisplayCalls) + { + tdesc = llformat("%s (%d)",idp->getName().c_str(),calls); + } + else + { + tdesc = llformat("%s [%.1f]",idp->getName().c_str(),ms); + } + dx = (texth+4) + idp->getDepth()*8; + + LLColor4 color = LLColor4::white; + if (idp->getDepth() > 0) + { + S32 line_start_y = (top + bottom) / 2; + S32 line_end_y = line_start_y + ((texth + 2) * (cur_line - display_line[idp->getParent()])) - texth; + gl_line_2d(x + dx - 8, line_start_y, x + dx, line_start_y, color); + S32 line_x = x + (texth + 4) + ((idp->getDepth() - 1) * 8); + gl_line_2d(line_x, line_start_y, line_x, line_end_y, color); + if (idp->getCollapsed() && !idp->getChildren().empty()) + { + gl_line_2d(line_x+4, line_start_y-3, line_x+4, line_start_y+4, color); + } + } + + x += dx; + BOOL is_child_of_hover_item = (idp == mHoverID); + LLFastTimer::NamedTimer* next_parent = idp->getParent(); + while(!is_child_of_hover_item && next_parent) + { + is_child_of_hover_item = (mHoverID == next_parent); + next_parent = next_parent->getParent(); + } + + LLFontGL::getFontSansSerifSmall()->renderUTF8(tdesc, 0, + x, y, + color, + LLFontGL::LEFT, LLFontGL::TOP, + is_child_of_hover_item ? LLFontGL::BOLD : LLFontGL::NORMAL); + + y -= (texth + 2); + + textw = dx + LLFontGL::getFontMonospace()->getWidth(idp->getName()) + 40; + + if (idp->getCollapsed()) + { + it.skipDescendants(); } } - y -= (texth + 2); - - textw = dx + LLFontGL::getFontMonospace()->getWidth(std::string(ft_display_table[i].desc)) + 40; - if (textw > legendwidth) - legendwidth = textw; - } - if (y <= 3 * texth) - { - LLFontGL::getFontMonospace()->renderUTF8("", 0, 3 * texth, 2 * texth, LLColor4::white, LLFontGL::LEFT, LLFontGL::TOP, LLFontGL::BOLD); } - for (S32 i=cur_line; igetLineHeight() + 4); mBarRect.mBottom = margin + LINE_GRAPH_HEIGHT; @@ -758,25 +581,18 @@ void LLFastTimerView::draw() barw = width - xleft - margin; // Draw the history bars - if (LLFastTimer::sLastFrameIndex >= 0) + if (LLFastTimer::getLastFrameIndex() >= 0) { + LLLocalClipRect clip(LLRect(xleft, ytop, getRect().getWidth() - margin, margin)); + U64 totalticks; if (!LLFastTimer::sPauseHistory) { - U64 ticks = 0; - int hidx = (LLFastTimer::sLastFrameIndex - mScrollIndex) % LLFastTimer::FTM_HISTORY_NUM; - for (S32 i=0; i= 10) { - if (mSubtractHidden && ft_display_table[i].disabled > 1) - { - continue; - } - int tidx = ft_display_table[i].timer; - ticks += LLFastTimer::sCountHistory[hidx][tidx]; - } - if (LLFastTimer::sCurFrameIndex >= 10) - { - U64 framec = LLFastTimer::sCurFrameIndex; + U64 framec = LLFastTimer::getCurFrameIndex(); U64 avg = (U64)mAvgCountTotal; mAvgCountTotal = (avg*framec + ticks) / (framec + 1); if (ticks > mMaxCountTotal) @@ -784,14 +600,17 @@ void LLFastTimerView::draw() mMaxCountTotal = ticks; } } -#if 1 + if (ticks < mAvgCountTotal/100 || ticks > mAvgCountTotal*100) - LLFastTimer::sResetHistory = 1; -#endif - if (LLFastTimer::sCurFrameIndex < 10 || LLFastTimer::sResetHistory) + { + LLFastTimer::sResetHistory = true; + } + + if (LLFastTimer::getCurFrameIndex() < 10 || LLFastTimer::sResetHistory) { mAvgCountTotal = ticks; mMaxCountTotal = ticks; + LLFastTimer::sResetHistory = false; } } @@ -809,16 +628,8 @@ void LLFastTimerView::draw() totalticks = 0; for (S32 j=0; j 1) - { - continue; - } - int tidx = ft_display_table[i].timer; - ticks += LLFastTimer::sCountHistory[j][tidx]; - } + U64 ticks = LLFastTimer::NamedTimer::getRootNamedTimer().getHistoricalCount(j); + if (ticks > totalticks) totalticks = ticks; } @@ -853,7 +664,6 @@ void LLFastTimerView::draw() LLFontGL::LEFT, LLFontGL::TOP); } - LLRect graph_rect; // Draw borders { gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); @@ -886,23 +696,28 @@ void LLFastTimerView::draw() by = LINE_GRAPH_HEIGHT-barh-dy-7; //line graph - graph_rect = LLRect(xleft-5, by, getRect().getWidth()-5, 5); + mGraphRect = LLRect(xleft-5, by, getRect().getWidth()-5, 5); - gl_rect_2d(graph_rect, FALSE); + gl_rect_2d(mGraphRect, FALSE); } + mBarStart.clear(); + mBarEnd.clear(); + // Draw bars for each history entry // Special: -1 = show running average gGL.getTexUnit(0)->bind(box_imagep->getImage()); for (S32 j=-1; j LINE_GRAPH_HEIGHT; j++) { - int sublevel_dx[FTV_DISPLAY_NUM+1]; - int sublevel_left[FTV_DISPLAY_NUM+1]; - int sublevel_right[FTV_DISPLAY_NUM+1]; + mBarStart.push_back(std::vector()); + mBarEnd.push_back(std::vector()); + int sublevel_dx[FTV_MAX_DEPTH]; + int sublevel_left[FTV_MAX_DEPTH]; + int sublevel_right[FTV_MAX_DEPTH]; S32 tidx; if (j >= 0) { - tidx = LLFastTimer::FTM_HISTORY_NUM - j - 1 - mScrollIndex; + tidx = LLFastTimer::NamedTimer::HISTORY_NUM - j - 1 - mScrollIndex; } else { @@ -912,88 +727,75 @@ void LLFastTimerView::draw() x = xleft; // draw the bars for each stat - int xpos[FTV_DISPLAY_NUM+1]; - int deltax[FTV_DISPLAY_NUM+1]; - xpos[0] = xleft; + std::vector xpos; + std::vector deltax; + xpos.push_back(xleft); + + LLFastTimer::NamedTimer* prev_id = NULL; - for (S32 i = 0; i < FTV_DISPLAY_NUM; i++) + S32 i = 0; + for(timer_tree_iterator_t it = begin_timer_tree(LLFastTimer::NamedTimer::getRootNamedTimer()); + it != end_timer_tree(); + ++it, ++i) { - if (ft_display_table[i].disabled > 1) - { - continue; - } - - F32 frac = (F32)ticks_sum[tidx+1][i] / (F32)totalticks; + LLFastTimer::NamedTimer* idp = (*it); + F32 frac = tidx == -1 + ? (F32)idp->getCountAverage() / (F32)totalticks + : (F32)idp->getHistoricalCount(tidx) / (F32)totalticks; dx = llround(frac * (F32)barw); - deltax[i] = dx; + S32 prev_delta_x = deltax.empty() ? 0 : deltax.back(); + deltax.push_back(dx); - int level = ft_display_table[i].level; - int parent = ft_display_table[i].parent; - llassert(level < FTV_DISPLAY_NUM); - llassert(parent < FTV_DISPLAY_NUM); + int level = idp->getDepth() - 1; - left = xpos[level]; - - S32 prev_idx = i - 1; - while (prev_idx > 0) + while ((S32)xpos.size() > level + 1) { - if (ft_display_table[prev_idx].disabled <= 1) - { - break; - } - prev_idx--; + xpos.pop_back(); } - S32 next_idx = i + 1; - while (next_idx < FTV_DISPLAY_NUM) - { - if (ft_display_table[next_idx].disabled <= 1) - { - break; - } - next_idx++; - } - + left = xpos.back(); + if (level == 0) - { + { sublevel_left[level] = xleft; sublevel_dx[level] = dx; sublevel_right[level] = sublevel_left[level] + sublevel_dx[level]; - } - else if (i==0 || ft_display_table[prev_idx].level < level) + } + else if (prev_id && prev_id->getDepth() < idp->getDepth()) { - // If we are the first entry at a new sublevel block, calc the - // total width of this sublevel and modify left to align block. - U64 sublevelticks = ticks_sum[tidx+1][i]; - for (S32 k=i+1; kbeginChildren(); + it != prev_id->endChildren(); + ++it) + { + sublevelticks += (tidx == -1) + ? (*it)->getCountAverage() + : (*it)->getHistoricalCount(tidx); + } + + F32 subfrac = (F32)sublevelticks / (F32)totalticks; sublevel_dx[level] = (int)(subfrac * (F32)barw + .5f); - if (mDisplayCenter == 1) // center aligned + if (mDisplayCenter == ALIGN_CENTER) { - left += (deltax[parent] - sublevel_dx[level])/2; + left += (prev_delta_x - sublevel_dx[level])/2; } - else if (mDisplayCenter == 2) // right aligned + else if (mDisplayCenter == ALIGN_RIGHT) { - left += (deltax[parent] - sublevel_dx[level]); - } + left += (prev_delta_x - sublevel_dx[level]); + } sublevel_left[level] = left; sublevel_right[level] = sublevel_left[level] + sublevel_dx[level]; } right = left + dx; - xpos[level] = right; - xpos[level+1] = left; + xpos.back() = right; + xpos.push_back(left); - mBarStart[(j + 1) * FTV_DISPLAY_NUM + i] = left; - mBarEnd[(j + 1) * FTV_DISPLAY_NUM + i] = right; + mBarStart.back().push_back(left); + mBarEnd.back().push_back(right); top = y; bottom = y - barh; @@ -1001,23 +803,23 @@ void LLFastTimerView::draw() if (right > left) { //U32 rounded_edges = 0; - LLColor4 color = *ft_display_table[i].color; + LLColor4 color = sTimerColors[idp];// *ft_display_table[i].color; S32 scale_offset = 0; - BOOL is_child_of_hover_item = (i == mHoverIndex); - S32 next_parent = ft_display_table[i].parent; - while(!is_child_of_hover_item && next_parent >= 0) + BOOL is_child_of_hover_item = (idp == mHoverID); + LLFastTimer::NamedTimer* next_parent = idp->getParent(); + while(!is_child_of_hover_item && next_parent) { - is_child_of_hover_item = (mHoverIndex == next_parent); - next_parent = ft_display_table[next_parent].parent; + is_child_of_hover_item = (mHoverID == next_parent); + next_parent = next_parent->getParent(); } - if (i == mHoverIndex) + if (idp == mHoverID) { scale_offset = llfloor(sinf(mHighlightTimer.getElapsedTimeF32() * 6.f) * 3.f); //color = lerp(color, LLColor4::black, -0.4f); } - else if (mHoverIndex >= 0 && !is_child_of_hover_item) + else if (mHoverID != NULL && !is_child_of_hover_item) { color = lerp(color, LLColor4::grey, 0.8f); } @@ -1028,7 +830,13 @@ void LLFastTimerView::draw() gl_segmented_rect_2d_fragment_tex(sublevel_left[level], top - level + scale_offset, sublevel_right[level], bottom + level - scale_offset, box_imagep->getTextureWidth(), box_imagep->getTextureHeight(), 16, start_fragment, end_fragment); } - + + if ((*it)->getCollapsed()) + { + it.skipDescendants(); + } + + prev_id = idp; } y -= (barh + dy); if (j < 0) @@ -1038,7 +846,7 @@ void LLFastTimerView::draw() //draw line graph history { gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - LLLocalClipRect clip(graph_rect); + LLLocalClipRect clip(mGraphRect); //normalize based on last frame's maximum static U64 last_max = 0; @@ -1055,72 +863,73 @@ void LLFastTimerView::draw() else tdesc = llformat("%4.2f ms", ms); - x = graph_rect.mRight - LLFontGL::getFontMonospace()->getWidth(tdesc)-5; - y = graph_rect.mTop - ((S32)LLFontGL::getFontMonospace()->getLineHeight()); + x = mGraphRect.mRight - LLFontGL::getFontMonospace()->getWidth(tdesc)-5; + y = mGraphRect.mTop - ((S32)LLFontGL::getFontMonospace()->getLineHeight()); LLFontGL::getFontMonospace()->renderUTF8(tdesc, 0, x, y, LLColor4::white, LLFontGL::LEFT, LLFontGL::TOP); //highlight visible range { - S32 first_frame = LLFastTimer::FTM_HISTORY_NUM - mScrollIndex; + S32 first_frame = LLFastTimer::NamedTimer::HISTORY_NUM - mScrollIndex; S32 last_frame = first_frame - MAX_VISIBLE_HISTORY; - F32 frame_delta = ((F32) (graph_rect.getWidth()))/(LLFastTimer::FTM_HISTORY_NUM-1); + F32 frame_delta = ((F32) (mGraphRect.getWidth()))/(LLFastTimer::NamedTimer::HISTORY_NUM-1); - F32 right = (F32) graph_rect.mLeft + frame_delta*first_frame; - F32 left = (F32) graph_rect.mLeft + frame_delta*last_frame; + F32 right = (F32) mGraphRect.mLeft + frame_delta*first_frame; + F32 left = (F32) mGraphRect.mLeft + frame_delta*last_frame; gGL.color4f(0.5f,0.5f,0.5f,0.3f); - gl_rect_2d((S32) left, graph_rect.mTop, (S32) right, graph_rect.mBottom); + gl_rect_2d((S32) left, mGraphRect.mTop, (S32) right, mGraphRect.mBottom); if (mHoverBarIndex >= 0) { S32 bar_frame = first_frame - mHoverBarIndex; - F32 bar = (F32) graph_rect.mLeft + frame_delta*bar_frame; + F32 bar = (F32) mGraphRect.mLeft + frame_delta*bar_frame; gGL.color4f(0.5f,0.5f,0.5f,1); gGL.begin(LLRender::LINES); - gGL.vertex2i((S32)bar, graph_rect.mBottom); - gGL.vertex2i((S32)bar, graph_rect.mTop); + gGL.vertex2i((S32)bar, mGraphRect.mBottom); + gGL.vertex2i((S32)bar, mGraphRect.mTop); gGL.end(); } } U64 cur_max = 0; - for (S32 idx = 0; idx < FTV_DISPLAY_NUM; ++idx) + for(timer_tree_iterator_t it = begin_timer_tree(LLFastTimer::NamedTimer::getRootNamedTimer()); + it != end_timer_tree(); + ++it) { - if (ft_display_table[idx].disabled > 1) - { //skip disabled timers - continue; - } + LLFastTimer::NamedTimer* idp = (*it); //fatten highlighted timer - if (mHoverIndex == idx) + if (mHoverID == idp) { gGL.flush(); glLineWidth(3); } - const F32 * col = ft_display_table[idx].color->mV; + const F32 * col = sTimerColors[idp].mV;// ft_display_table[idx].color->mV; F32 alpha = 1.f; - if (mHoverIndex >= 0 && - idx != mHoverIndex) - { //fade out non-hihglighted timers - if (ft_display_table[idx].parent != mHoverIndex) + if (mHoverID != NULL && + idp != mHoverID) + { //fade out non-highlighted timers + if (idp->getParent() != mHoverID) { alpha = alpha_interp; } } gGL.color4f(col[0], col[1], col[2], alpha); - gGL.begin(LLRender::LINE_STRIP); - for (U32 j = 0; j < LLFastTimer::FTM_HISTORY_NUM; j++) + gGL.begin(LLRender::TRIANGLE_STRIP); + for (U32 j = llmax(0, LLFastTimer::NamedTimer::HISTORY_NUM - LLFastTimer::getLastFrameIndex()); + j < LLFastTimer::NamedTimer::HISTORY_NUM; + j++) { - U64 ticks = ticks_sum[j+1][idx]; + U64 ticks = idp->getHistoricalCount(j); if (mDisplayHz) { @@ -1130,43 +939,55 @@ void LLFastTimerView::draw() } else if (mDisplayCalls) { - S32 tidx = ft_display_table[idx].timer; - S32 hidx = (LLFastTimer::sLastFrameIndex + j) % LLFastTimer::FTM_HISTORY_NUM; - ticks = (S32)LLFastTimer::sCallHistory[hidx][tidx]; + ticks = (S32)idp->getHistoricalCalls(j); } if (alpha == 1.f) - { //normalize to highlighted timer + { + //normalize to highlighted timer cur_max = llmax(cur_max, ticks); } - F32 x = graph_rect.mLeft + ((F32) (graph_rect.getWidth()))/(LLFastTimer::FTM_HISTORY_NUM-1)*j; - F32 y = graph_rect.mBottom + (F32) graph_rect.getHeight()/max_ticks*ticks; + F32 x = mGraphRect.mLeft + ((F32) (mGraphRect.getWidth()))/(LLFastTimer::NamedTimer::HISTORY_NUM-1)*j; + F32 y = mGraphRect.mBottom + (F32) mGraphRect.getHeight()/max_ticks*ticks; gGL.vertex2f(x,y); + gGL.vertex2f(x,mGraphRect.mBottom); } gGL.end(); - if (mHoverIndex == idx) + if (mHoverID == idp) { gGL.flush(); glLineWidth(1); } + + if (idp->getCollapsed()) + { + //skip hidden timers + it.skipDescendants(); + } } //interpolate towards new maximum - F32 dt = gFrameIntervalSeconds*3.f; - last_max = (U64) ((F32) last_max + ((F32) cur_max- (F32) last_max) * dt); + last_max = (U64) lerp((F32)last_max, (F32) cur_max, LLCriticalDamp::getInterpolant(0.1f)); + if (last_max - cur_max <= 1 || cur_max - last_max <= 1) + { + last_max = cur_max; + } F32 alpha_target = last_max > cur_max ? llmin((F32) last_max/ (F32) cur_max - 1.f,1.f) : llmin((F32) cur_max/ (F32) last_max - 1.f,1.f); - - alpha_interp = alpha_interp + (alpha_target-alpha_interp) * dt; + alpha_interp = lerp(alpha_interp, alpha_target, LLCriticalDamp::getInterpolant(0.1f)); - if (mHoverIndex >= 0) + if (mHoverID != NULL) { - x = (graph_rect.mRight + graph_rect.mLeft)/2; - y = graph_rect.mBottom + 8; + x = (mGraphRect.mRight + mGraphRect.mLeft)/2; + y = mGraphRect.mBottom + 8; - LLFontGL::getFontMonospace()->renderUTF8(std::string(ft_display_table[mHoverIndex].desc), 0, x, y, LLColor4::white, + LLFontGL::getFontMonospace()->renderUTF8( + mHoverID->getName(), + 0, + x, y, + LLColor4::white, LLFontGL::LEFT, LLFontGL::BOTTOM); } } @@ -1176,87 +997,594 @@ void LLFastTimerView::draw() if (mPrintStats >= 0) { std::string legend_stat; - S32 stat_num; - S32 first = 1; - for (stat_num = 0; stat_num < FTV_DISPLAY_NUM; stat_num++) + bool first = true; + for(timer_tree_iterator_t it = begin_timer_tree(LLFastTimer::NamedTimer::getRootNamedTimer()); + it != end_timer_tree(); + ++it) { - if (ft_display_table[stat_num].disabled > 1) - continue; + LLFastTimer::NamedTimer* idp = (*it); + if (!first) + { legend_stat += ", "; - first=0; - legend_stat += ft_display_table[stat_num].desc; + } + first = false; + legend_stat += idp->getName(); + + if (idp->getCollapsed()) + { + it.skipDescendants(); + } } llinfos << legend_stat << llendl; std::string timer_stat; - first = 1; - for (stat_num = 0; stat_num < FTV_DISPLAY_NUM; stat_num++) + first = true; + for(timer_tree_iterator_t it = begin_timer_tree(LLFastTimer::NamedTimer::getRootNamedTimer()); + it != end_timer_tree(); + ++it) { - S32 disabled = ft_display_table[stat_num].disabled; - if (disabled > 1) - continue; + LLFastTimer::NamedTimer* idp = (*it); + if (!first) + { timer_stat += ", "; - first=0; + } + first = false; + U64 ticks; - S32 tidx = ft_display_table[stat_num].timer; if (mPrintStats > 0) { - S32 hidx = (LLFastTimer::sLastFrameIndex+(mPrintStats-1)-mScrollIndex) % LLFastTimer::FTM_HISTORY_NUM; - ticks = disabled >= 1 ? ticks_sum[mPrintStats][stat_num] : LLFastTimer::sCountHistory[hidx][tidx]; + ticks = idp->getHistoricalCount(mPrintStats); } else { - ticks = disabled >= 1 ? ticks_sum[0][stat_num] : LLFastTimer::sCountAverage[tidx]; + ticks = idp->getCountAverage(); } F32 ms = (F32)((F64)ticks * iclock_freq); timer_stat += llformat("%.1f",ms); + + if (idp->getCollapsed()) + { + it.skipDescendants(); + } } llinfos << timer_stat << llendl; mPrintStats = -1; } - mHoverIndex = -1; + mHoverID = NULL; mHoverBarIndex = -1; LLView::draw(); } -F64 LLFastTimerView::getTime(LLFastTimer::EFastTimerType tidx) +F64 LLFastTimerView::getTime(const std::string& name) { - // Find table index - S32 i; - for (i=0; igetCountAverage() / (F64)LLFastTimer::countsPerSecond(); } - - if (i == FTV_DISPLAY_NUM) - { - // walked off the end of ft_display_table without finding - // the desired timer type - llwarns << "Timer type " << tidx << " not known." << llendl; - return F64(0.0); - } - - S32 table_idx = i; - - // Add child ticks to parent - U64 ticks = LLFastTimer::sCountAverage[tidx]; - S32 level = ft_display_table[table_idx].level; - for (i=table_idx+1; igetData()); + + //write results to disk + LLPointer result = new LLImagePNG(); + result->encode(scratch, 0.f); + + std::string ext = result->getExtension(); + std::string filename = llformat("%s_%s.%s", label.c_str(), suffix, ext.c_str()); + + std::string out_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, filename); + result->save(out_file); +} + +//static +void LLFastTimerView::exportCharts(const std::string& base, const std::string& target) +{ + //allocate render target for drawing charts + LLRenderTarget buffer; + buffer.allocate(1024,512, GL_RGB, FALSE, FALSE); + + + LLSD cur; + + LLSD base_data; + + { //read base log into memory + S32 i = 0; + std::ifstream is(base.c_str()); + while (!is.eof() && LLSDSerialize::fromXML(cur, is)) + { + base_data[i++] = cur; + } + is.close(); + } + + LLSD cur_data; + std::set chart_names; + + { //read current log into memory + S32 i = 0; + std::ifstream is(target.c_str()); + while (!is.eof() && LLSDSerialize::fromXML(cur, is)) + { + cur_data[i++] = cur; + + for (LLSD::map_iterator iter = cur.beginMap(); iter != cur.endMap(); ++iter) + { + std::string label = iter->first; + chart_names.insert(label); + } + } + is.close(); + } + + //get time domain + LLSD::Real cur_total_time = 0.0; + + for (U32 i = 0; i < (U32)cur_data.size(); ++i) + { + cur_total_time += cur_data[i]["Total"]["Time"].asReal(); + } + + LLSD::Real base_total_time = 0.0; + for (U32 i = 0; i < (U32)base_data.size(); ++i) + { + base_total_time += base_data[i]["Total"]["Time"].asReal(); + } + + //allocate raw scratch space + LLPointer scratch = new LLImageRaw(1024, 512, 3); + + gGL.pushMatrix(); + gGL.loadIdentity(); + gGL.matrixMode(LLRender::MM_PROJECTION); + gGL.loadIdentity(); + gGL.ortho(-0.05f, 1.05f, -0.05f, 1.05f, -1.0f, 1.0f); + + //render charts + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + + buffer.bindTarget(); + + for (std::set::iterator iter = chart_names.begin(); iter != chart_names.end(); ++iter) + { + std::string label = *iter; + + LLSD::Real max_time = 0.0; + LLSD::Integer max_calls = 0; + LLSD::Real max_execution = 0.0; + + std::vector cur_execution; + std::vector cur_times; + std::vector cur_calls; + + std::vector base_execution; + std::vector base_times; + std::vector base_calls; + + for (U32 i = 0; i < (U32)cur_data.size(); ++i) + { + LLSD::Real time = cur_data[i][label]["Time"].asReal(); + LLSD::Integer calls = cur_data[i][label]["Calls"].asInteger(); + + LLSD::Real execution = 0.0; + if (calls > 0) + { + execution = time/calls; + cur_execution.push_back(execution); + cur_times.push_back(time); + } + + cur_calls.push_back(calls); + } + + for (U32 i = 0; i < (U32)base_data.size(); ++i) + { + LLSD::Real time = base_data[i][label]["Time"].asReal(); + LLSD::Integer calls = base_data[i][label]["Calls"].asInteger(); + + LLSD::Real execution = 0.0; + if (calls > 0) + { + execution = time/calls; + base_execution.push_back(execution); + base_times.push_back(time); + } + + base_calls.push_back(calls); + } + + std::sort(base_calls.begin(), base_calls.end()); + std::sort(base_times.begin(), base_times.end()); + std::sort(base_execution.begin(), base_execution.end()); + + std::sort(cur_calls.begin(), cur_calls.end()); + std::sort(cur_times.begin(), cur_times.end()); + std::sort(cur_execution.begin(), cur_execution.end()); + + //remove outliers + const U32 OUTLIER_CUTOFF = 512; + if (base_times.size() > OUTLIER_CUTOFF) + { + ll_remove_outliers(base_times, 1.f); + } + + if (base_execution.size() > OUTLIER_CUTOFF) + { + ll_remove_outliers(base_execution, 1.f); + } + + if (cur_times.size() > OUTLIER_CUTOFF) + { + ll_remove_outliers(cur_times, 1.f); + } + + if (cur_execution.size() > OUTLIER_CUTOFF) + { + ll_remove_outliers(cur_execution, 1.f); + } + + + max_time = llmax(base_times.empty() ? 0.0 : *base_times.rbegin(), cur_times.empty() ? 0.0 : *cur_times.rbegin()); + max_calls = llmax(base_calls.empty() ? 0 : *base_calls.rbegin(), cur_calls.empty() ? 0 : *cur_calls.rbegin()); + max_execution = llmax(base_execution.empty() ? 0.0 : *base_execution.rbegin(), cur_execution.empty() ? 0.0 : *cur_execution.rbegin()); + + + LLVector3 last_p; + + //==================================== + // basic + //==================================== + buffer.clear(); + + last_p.clear(); + + LLGLDisable cull(GL_CULL_FACE); + + LLVector3 base_col(0, 0.7f, 0.f); + LLVector3 cur_col(1.f, 0.f, 0.f); + + gGL.setSceneBlendType(LLRender::BT_ADD); + + gGL.color3fv(base_col.mV); + for (U32 i = 0; i < base_times.size(); ++i) + { + gGL.begin(LLRender::TRIANGLE_STRIP); + gGL.vertex3fv(last_p.mV); + gGL.vertex3f(last_p.mV[0], 0.f, 0.f); + last_p.set((F32)i/(F32) base_times.size(), base_times[i]/max_time, 0.f); + gGL.vertex3fv(last_p.mV); + gGL.vertex3f(last_p.mV[0], 0.f, 0.f); + gGL.end(); + } + + gGL.flush(); + + + last_p.clear(); + { + LLGLEnable blend(GL_BLEND); + + gGL.color3fv(cur_col.mV); + for (U32 i = 0; i < cur_times.size(); ++i) + { + gGL.begin(LLRender::TRIANGLE_STRIP); + gGL.vertex3f(last_p.mV[0], 0.f, 0.f); + gGL.vertex3fv(last_p.mV); + last_p.set((F32) i / (F32) cur_times.size(), cur_times[i]/max_time, 0.f); + gGL.vertex3f(last_p.mV[0], 0.f, 0.f); + gGL.vertex3fv(last_p.mV); + gGL.end(); + } + + gGL.flush(); + } + + saveChart(label, "time", scratch); + + //====================================== + // calls + //====================================== + buffer.clear(); + + last_p.clear(); + + gGL.color3fv(base_col.mV); + for (U32 i = 0; i < base_calls.size(); ++i) + { + gGL.begin(LLRender::TRIANGLE_STRIP); + gGL.vertex3fv(last_p.mV); + gGL.vertex3f(last_p.mV[0], 0.f, 0.f); + last_p.set((F32) i / (F32) base_calls.size(), (F32)base_calls[i]/max_calls, 0.f); + gGL.vertex3fv(last_p.mV); + gGL.vertex3f(last_p.mV[0], 0.f, 0.f); + gGL.end(); + } + + gGL.flush(); + + { + LLGLEnable blend(GL_BLEND); + gGL.color3fv(cur_col.mV); + last_p.clear(); + + for (U32 i = 0; i < cur_calls.size(); ++i) + { + gGL.begin(LLRender::TRIANGLE_STRIP); + gGL.vertex3f(last_p.mV[0], 0.f, 0.f); + gGL.vertex3fv(last_p.mV); + last_p.set((F32) i / (F32) cur_calls.size(), (F32) cur_calls[i]/max_calls, 0.f); + gGL.vertex3f(last_p.mV[0], 0.f, 0.f); + gGL.vertex3fv(last_p.mV); + gGL.end(); + + } + + gGL.flush(); + } + + saveChart(label, "calls", scratch); + + //====================================== + // execution + //====================================== + buffer.clear(); + + + gGL.color3fv(base_col.mV); + U32 count = 0; + U32 total_count = base_execution.size(); + + last_p.clear(); + + for (std::vector::iterator iter = base_execution.begin(); iter != base_execution.end(); ++iter) + { + gGL.begin(LLRender::TRIANGLE_STRIP); + gGL.vertex3fv(last_p.mV); + gGL.vertex3f(last_p.mV[0], 0.f, 0.f); + last_p.set((F32)count/(F32)total_count, *iter/max_execution, 0.f); + gGL.vertex3fv(last_p.mV); + gGL.vertex3f(last_p.mV[0], 0.f, 0.f); + gGL.end(); + count++; + } + + last_p.clear(); + + { + LLGLEnable blend(GL_BLEND); + gGL.color3fv(cur_col.mV); + count = 0; + total_count = cur_execution.size(); + + for (std::vector::iterator iter = cur_execution.begin(); iter != cur_execution.end(); ++iter) + { + gGL.begin(LLRender::TRIANGLE_STRIP); + gGL.vertex3f(last_p.mV[0], 0.f, 0.f); + gGL.vertex3fv(last_p.mV); + last_p.set((F32)count/(F32)total_count, *iter/max_execution, 0.f); + gGL.vertex3f(last_p.mV[0], 0.f, 0.f); + gGL.vertex3fv(last_p.mV); + gGL.end(); + count++; + } + + gGL.flush(); + } + + saveChart(label, "execution", scratch); + } + + buffer.flush(); + + gGL.popMatrix(); + gGL.matrixMode(LLRender::MM_MODELVIEW); + gGL.popMatrix(); +} + +//static +LLSD LLFastTimerView::analyzePerformanceLogDefault(std::istream& is) +{ + LLSD ret; + + LLSD cur; + + LLSD::Real total_time = 0.0; + LLSD::Integer total_frames = 0; + + typedef std::map stats_map_t; + stats_map_t time_stats; + stats_map_t sample_stats; + + while (!is.eof() && LLSDSerialize::fromXML(cur, is)) + { + for (LLSD::map_iterator iter = cur.beginMap(); iter != cur.endMap(); ++iter) + { + std::string label = iter->first; + + F64 time = iter->second["Time"].asReal(); + + // Skip the total figure + if(label.compare("Total") != 0) + { + total_time += time; + } + + if (time > 0.0) + { + LLSD::Integer samples = iter->second["Calls"].asInteger(); + + time_stats[label].push(time); + sample_stats[label].push(samples); + } + } + total_frames++; + } + + for(stats_map_t::iterator it = time_stats.begin(); it != time_stats.end(); ++it) + { + std::string label = it->first; + ret[label]["TotalTime"] = time_stats[label].mSum; + ret[label]["MeanTime"] = time_stats[label].getMean(); + ret[label]["MaxTime"] = time_stats[label].getMaxValue(); + ret[label]["MinTime"] = time_stats[label].getMinValue(); + ret[label]["StdDevTime"] = time_stats[label].getStdDev(); + + ret[label]["Samples"] = sample_stats[label].mSum; + ret[label]["MaxSamples"] = sample_stats[label].getMaxValue(); + ret[label]["MinSamples"] = sample_stats[label].getMinValue(); + ret[label]["StdDevSamples"] = sample_stats[label].getStdDev(); + + ret[label]["Frames"] = (LLSD::Integer)time_stats[label].getCount(); + } + + ret["SessionTime"] = total_time; + ret["FrameCount"] = total_frames; + + return ret; + +} + +//static +void LLFastTimerView::doAnalysisDefault(std::string baseline, std::string target, std::string output) +{ + // Open baseline and current target, exit if one is inexistent + std::ifstream base_is(baseline.c_str()); + std::ifstream target_is(target.c_str()); + if (!base_is.is_open() || !target_is.is_open()) + { + llwarns << "'-analyzeperformance' error : baseline or current target file inexistent" << llendl; + base_is.close(); + target_is.close(); + return; + } + + //analyze baseline + LLSD base = analyzePerformanceLogDefault(base_is); + base_is.close(); + + //analyze current + LLSD current = analyzePerformanceLogDefault(target_is); + target_is.close(); + + //output comparision + std::ofstream os(output.c_str()); + + LLSD::Real session_time = current["SessionTime"].asReal(); + os << + "Label, " + "% Change, " + "% of Session, " + "Cur Min, " + "Cur Max, " + "Cur Mean/sample, " + "Cur Mean/frame, " + "Cur StdDev/frame, " + "Cur Total, " + "Cur Frames, " + "Cur Samples, " + "Base Min, " + "Base Max, " + "Base Mean/sample, " + "Base Mean/frame, " + "Base StdDev/frame, " + "Base Total, " + "Base Frames, " + "Base Samples\n"; + + for (LLSD::map_iterator iter = base.beginMap(); iter != base.endMap(); ++iter) + { + LLSD::String label = iter->first; + + if (current[label]["Samples"].asInteger() == 0 || + base[label]["Samples"].asInteger() == 0) + { + //cannot compare + continue; + } + LLSD::Real a = base[label]["TotalTime"].asReal() / base[label]["Samples"].asReal(); + LLSD::Real b = current[label]["TotalTime"].asReal() / current[label]["Samples"].asReal(); + + LLSD::Real diff = b-a; + + LLSD::Real perc = diff/a * 100; + + os << llformat("%s, %.2f, %.4f, %.4f, %.4f, %.4f, %.4f, %.4f, %.4f, %d, %d, %.4f, %.4f, %.4f, %.4f, %.4f, %.4f, %d, %d\n", + label.c_str(), + (F32) perc, + (F32) (current[label]["TotalTime"].asReal()/session_time * 100.0), + + (F32) current[label]["MinTime"].asReal(), + (F32) current[label]["MaxTime"].asReal(), + (F32) b, + (F32) current[label]["MeanTime"].asReal(), + (F32) current[label]["StdDevTime"].asReal(), + (F32) current[label]["TotalTime"].asReal(), + current[label]["Frames"].asInteger(), + current[label]["Samples"].asInteger(), + (F32) base[label]["MinTime"].asReal(), + (F32) base[label]["MaxTime"].asReal(), + (F32) a, + (F32) base[label]["MeanTime"].asReal(), + (F32) base[label]["StdDevTime"].asReal(), + (F32) base[label]["TotalTime"].asReal(), + base[label]["Frames"].asInteger(), + base[label]["Samples"].asInteger()); + } + + exportCharts(baseline, target); + + os.flush(); + os.close(); +} + +//static +void LLFastTimerView::outputAllMetrics() +{ + /*if (LLMetricPerformanceTesterBasic::hasMetricPerformanceTesters()) + { + for (LLMetricPerformanceTesterBasic::name_tester_map_t::iterator iter = LLMetricPerformanceTesterBasic::sTesterMap.begin(); + iter != LLMetricPerformanceTesterBasic::sTesterMap.end(); ++iter) + { + LLMetricPerformanceTesterBasic* tester = ((LLMetricPerformanceTesterBasic*)iter->second); + tester->outputTestResults(); + } + }*/ +} + +//static +void LLFastTimerView::doAnalysis(std::string baseline, std::string target, std::string output) +{ + if(LLFastTimer::sLog) + { + doAnalysisDefault(baseline, target, output) ; + return ; + } + + /*if(LLFastTimer::sMetricLog) + { + LLMetricPerformanceTesterBasic::doAnalysisMetrics(baseline, target, output) ; + return ; + }*/ +} +void LLFastTimerView::onClose(bool app_quitting) +{ + if(app_quitting) + { + LLFloater::close(app_quitting); + } + else + { + setVisible(false); + } +} + diff --git a/indra/newview/llfasttimerview.h b/indra/newview/llfasttimerview.h index b25a1da15..04fa500e1 100644 --- a/indra/newview/llfasttimerview.h +++ b/indra/newview/llfasttimerview.h @@ -34,41 +34,71 @@ #define LL_LLFASTTIMERVIEW_H #include "llfloater.h" -#include "llframetimer.h" +#include "llfasttimer.h" class LLFastTimerView : public LLFloater { public: LLFastTimerView(const std::string& name, const LLRect& rect); - virtual ~LLFastTimerView(); + /*virtual*/ BOOL postBuild(); + + static BOOL sAnalyzePerformance; + + static void outputAllMetrics(); + static void doAnalysis(std::string baseline, std::string target, std::string output); + +private: + static void doAnalysisDefault(std::string baseline, std::string target, std::string output) ; + static LLSD analyzePerformanceLogDefault(std::istream& is) ; + static void exportCharts(const std::string& base, const std::string& target); + void onPause(); + static void onPauseHandler(void *data); + +public: virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); + virtual BOOL handleDoubleClick(S32 x, S32 y, MASK mask); virtual BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); virtual BOOL handleHover(S32 x, S32 y, MASK mask); + virtual BOOL handleToolTip(S32 x, S32 y, std::string& msg, LLRect* sticky_rect_screen); virtual BOOL handleScrollWheel(S32 x, S32 y, S32 clicks); - virtual void onClose(bool app_quitting); virtual void draw(); - S32 getLegendIndex(S32 y); - F64 getTime(LLFastTimer::EFastTimerType tidx); - + LLFastTimer::NamedTimer* getLegendID(S32 y); + F64 getTime(const std::string& name); + +protected: + virtual void onClose(bool app_quitting); private: - S32* mBarStart; - S32* mBarEnd; + typedef std::vector > bar_positions_t; + bar_positions_t mBarStart; + bar_positions_t mBarEnd; S32 mDisplayMode; - S32 mDisplayCenter; + + typedef enum child_alignment + { + ALIGN_LEFT, + ALIGN_CENTER, + ALIGN_RIGHT, + ALIGN_COUNT + } ChildAlignment; + + ChildAlignment mDisplayCenter; S32 mDisplayCalls; S32 mDisplayHz; U64 mAvgCountTotal; U64 mMaxCountTotal; LLRect mBarRect; S32 mScrollIndex; - S32 mHoverIndex; + LLFastTimer::NamedTimer* mHoverID; + LLFastTimer::NamedTimer* mHoverTimer; + LLRect mToolTipRect; S32 mHoverBarIndex; LLFrameTimer mHighlightTimer; - S32 mSubtractHidden; S32 mPrintStats; + S32 mAverageCyclesPerTimer; + LLRect mGraphRect; }; #endif diff --git a/indra/newview/llflexibleobject.cpp b/indra/newview/llflexibleobject.cpp index ed3d6debf..c2776df5a 100644 --- a/indra/newview/llflexibleobject.cpp +++ b/indra/newview/llflexibleobject.cpp @@ -51,6 +51,9 @@ /*static*/ F32 LLVolumeImplFlexible::sUpdateFactor = 1.0f; +static LLFastTimer::DeclareTimer FTM_FLEXIBLE_REBUILD("Rebuild"); +static LLFastTimer::DeclareTimer FTM_DO_FLEXIBLE_UPDATE("Update"); + // LLFlexibleObjectData::pack/unpack now in llprimitive.cpp //----------------------------------------------- @@ -263,6 +266,7 @@ void LLVolumeImplFlexible::onSetVolume(const LLVolumeParams &volume_params, cons // updated every time step. In the future, perhaps there could be an // optimization similar to what Havok does for objects that are stationary. //--------------------------------------------------------------------------------- +static LLFastTimer::DeclareTimer FTM_FLEXIBLE_UPDATE("Update Flexies"); BOOL LLVolumeImplFlexible::doIdleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) { if (mVO->mDrawable.isNull()) @@ -281,7 +285,7 @@ BOOL LLVolumeImplFlexible::doIdleUpdate(LLAgent &agent, LLWorld &world, const F6 parent->mDrawable->mQuietCount = 0; } - LLFastTimer ftm(LLFastTimer::FTM_FLEXIBLE_UPDATE); + LLFastTimer ftm(FTM_FLEXIBLE_UPDATE); S32 new_res = mAttributes->getSimulateLOD(); @@ -365,6 +369,7 @@ inline S32 log2(S32 x) void LLVolumeImplFlexible::doFlexibleUpdate() { + LLFastTimer ftm(FTM_DO_FLEXIBLE_UPDATE); LLVolume* volume = mVO->getVolume(); LLPath *path = &volume->getPath(); if ((mSimulateRes == 0 || !mInitialized) && mVO->mDrawable->isVisible()) @@ -702,6 +707,7 @@ BOOL LLVolumeImplFlexible::doUpdateGeometry(LLDrawable *drawable) if (mRenderRes > -1) { + LLFastTimer t(FTM_DO_FLEXIBLE_UPDATE); doFlexibleUpdate(); } @@ -721,7 +727,7 @@ BOOL LLVolumeImplFlexible::doUpdateGeometry(LLDrawable *drawable) volume->mDrawable->setState(LLDrawable::REBUILD_VOLUME); volume->dirtySpatialGroup(); { - //LLFastTimer t(FTM_FLEXIBLE_REBUILD); + LLFastTimer t(FTM_FLEXIBLE_REBUILD); doFlexibleRebuild(); } volume->genBBoxes(isVolumeGlobal()); diff --git a/indra/newview/llfloatercustomize.cpp b/indra/newview/llfloatercustomize.cpp index 9fdb2bea4..fc72e7e17 100644 --- a/indra/newview/llfloatercustomize.cpp +++ b/indra/newview/llfloatercustomize.cpp @@ -590,7 +590,7 @@ void LLPanelEditWearable::setSubpart( ESubpart subpart ) LLVOAvatar* avatar = gAgentAvatarp; ESex avatar_sex = avatar->getSex(); LLViewerInventoryItem* item; - item = (LLViewerInventoryItem*)gAgentWearables.getWearableInventoryItem(mType); + item = (LLViewerInventoryItem*)gAgentWearables.getWearableInventoryItem(mType,0); // TODO: MULTI-WEARABLE U32 perm_mask = 0x0; BOOL is_complete = FALSE; bool can_export = false; @@ -656,27 +656,27 @@ void LLPanelEditWearable::onBtnTakeOff( void* userdata ) { LLPanelEditWearable* self = (LLPanelEditWearable*) userdata; - LLWearable* wearable = gAgentWearables.getWearable( self->mType ); + LLWearable* wearable = gAgentWearables.getWearable( self->mType, 0 ); // TODO: MULTI-WEARABLE if( !wearable ) { return; } - gAgentWearables.removeWearable( self->mType ); + gAgentWearables.removeWearable( self->mType, false, 0 ); // TODO: MULTI-WEARABLE } // static void LLPanelEditWearable::onBtnSave( void* userdata ) { LLPanelEditWearable* self = (LLPanelEditWearable*) userdata; - gAgentWearables.saveWearable( self->mType ); + gAgentWearables.saveWearable( self->mType, 0 ); // TODO: MULTI-WEARABLE } // static void LLPanelEditWearable::onBtnSaveAs( void* userdata ) { LLPanelEditWearable* self = (LLPanelEditWearable*) userdata; - LLWearable* wearable = gAgentWearables.getWearable( self->getType() ); + LLWearable* wearable = gAgentWearables.getWearable( self->getType(), 0 ); // TODO: MULTI-WEARABLE if( wearable ) { LLWearableSaveAsDialog* save_as_dialog = new LLWearableSaveAsDialog( wearable->getName(), onSaveAsCommit, self ); @@ -692,7 +692,7 @@ void LLPanelEditWearable::onSaveAsCommit( LLWearableSaveAsDialog* save_as_dialog LLVOAvatar* avatar = gAgentAvatarp; if( avatar ) { - gAgentWearables.saveWearableAs( self->getType(), save_as_dialog->getItemName(), FALSE ); + gAgentWearables.saveWearableAs( self->getType(), 0, save_as_dialog->getItemName(), FALSE ); // TODO: MULTI-WEARABLE } } @@ -701,7 +701,7 @@ void LLPanelEditWearable::onSaveAsCommit( LLWearableSaveAsDialog* save_as_dialog void LLPanelEditWearable::onBtnRevert( void* userdata ) { LLPanelEditWearable* self = (LLPanelEditWearable*) userdata; - gAgentWearables.revertWearable( self->mType ); + gAgentWearables.revertWearable( self->mType, 0 ); // TODO: MULTI-WEARABLE } // static @@ -740,7 +740,7 @@ bool LLPanelEditWearable::onSelectAutoWearOption(const LLSD& notification, const bool LLPanelEditWearable::textureIsInvisible(ETextureIndex te) { - if (gAgentWearables.getWearable(mType)) + if (gAgentWearables.getWearable(mType, 0)) // TODO: MULTI-WEARABLE { LLVOAvatar *avatar = gAgentAvatarp; if (avatar) @@ -876,7 +876,7 @@ void LLPanelEditWearable::addTextureDropTarget( ETextureIndex te, const std::str LLVOAvatar* avatar = gAgentAvatarp; if (avatar) { - LLWearable* wearable = gAgentWearables.getWearable(mType); + LLWearable* wearable = gAgentWearables.getWearable(mType, 0); // TODO: MULTI-WEARABLE if (wearable && mType == LLWearableType::WT_ALPHA) { const LLTextureEntry* current_te = avatar->getTE(te); @@ -906,7 +906,7 @@ void LLPanelEditWearable::onTextureCommit( LLUICtrl* ctrl, void* userdata ) image = LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT_AVATAR); } self->mTextureList[ctrl->getName()] = te; - if (gAgentWearables.getWearable(self->mType)) + if (gAgentWearables.getWearable(self->mType, 0)) // TODO: MULTI-WEARABLE { avatar->setLocTexTE(te, image, TRUE); avatar->wearableUpdated(self->mType, FALSE); @@ -958,14 +958,14 @@ void LLPanelEditWearable::draw() return; } - LLWearable* wearable = gAgentWearables.getWearable( mType ); + LLWearable* wearable = gAgentWearables.getWearable( mType, 0 ); // TODO: MULTI-WEARABLE BOOL has_wearable = (wearable != NULL ); BOOL is_dirty = isDirty(); BOOL is_modifiable = FALSE; BOOL is_copyable = FALSE; BOOL is_complete = FALSE; LLViewerInventoryItem* item; - item = (LLViewerInventoryItem*)gAgentWearables.getWearableInventoryItem(mType); + item = (LLViewerInventoryItem*)gAgentWearables.getWearableInventoryItem(mType, 0); // TODO: MULTI-WEARABLE if(item) { const LLPermissions& perm = item->getPermissions(); @@ -1041,7 +1041,7 @@ void LLPanelEditWearable::draw() childSetTextArg("title_loading", "[DESC]", std::string(LLWearableType::getTypeLabel( mType ))); std::string path; - const LLUUID& item_id = gAgentWearables.getWearableItemID( wearable->getType() ); + const LLUUID& item_id = gAgentWearables.getWearableItemID( wearable->getType(), 0 ); // TODO: MULTI-WEARABLE append_path(item_id, path); childSetVisible("path", TRUE); childSetTextArg("path", "[PATH]", path); @@ -1054,7 +1054,7 @@ void LLPanelEditWearable::draw() childSetTextArg("title", "[DESC]", wearable->getName() ); std::string path; - const LLUUID& item_id = gAgentWearables.getWearableItemID( wearable->getType() ); + const LLUUID& item_id = gAgentWearables.getWearableItemID( wearable->getType(), 0 ); // TODO: MULTI-WEARABLE append_path(item_id, path); childSetVisible("path", TRUE); childSetTextArg("path", "[PATH]", path); @@ -1201,7 +1201,7 @@ void LLPanelEditWearable::setVisible(BOOL visible) BOOL LLPanelEditWearable::isDirty() const { - LLWearable* wearable = gAgentWearables.getWearable( mType ); + LLWearable* wearable = gAgentWearables.getWearable( mType, 0 ); // TODO: MULTI-WEARABLE if( !wearable ) { return FALSE; @@ -1226,7 +1226,7 @@ void LLPanelEditWearable::onCommitSexChange( LLUICtrl*, void* userdata ) return; } - if( !gAgentWearables.isWearableModifiable(self->mType)) + if( !gAgentWearables.isWearableModifiable(self->mType, 0)) // TODO: MULTI-WEARABLE { return; } @@ -1936,10 +1936,10 @@ void LLFloaterCustomize::onBtnExport_continued(AIFilePicker* filepicker) for( S32 i=0; i < LLWearableType::WT_COUNT; i++ ) { is_modifiable = FALSE; - LLWearable* old_wearable = gAgentWearables.getWearable((LLWearableType::EType)i); + LLWearable* old_wearable = gAgentWearables.getWearable((LLWearableType::EType)i, 0); // TODO: MULTI-WEARABLE if( old_wearable ) { - item = (LLViewerInventoryItem*)gAgentWearables.getWearableInventoryItem((LLWearableType::EType)i); + item = (LLViewerInventoryItem*)gAgentWearables.getWearableInventoryItem((LLWearableType::EType)i, 0); // TODO: MULTI-WEARABLE if(item) { const LLPermissions& perm = item->getPermissions(); @@ -1960,10 +1960,10 @@ void LLFloaterCustomize::onBtnExport_continued(AIFilePicker* filepicker) for( S32 i=0; i < LLWearableType::WT_COUNT; i++ ) { is_modifiable = FALSE; - LLWearable* old_wearable = gAgentWearables.getWearable((LLWearableType::EType)i); + LLWearable* old_wearable = gAgentWearables.getWearable((LLWearableType::EType)i, 0); // TODO: MULTI-WEARABLE if( old_wearable ) { - item = (LLViewerInventoryItem*)gAgentWearables.getWearableInventoryItem((LLWearableType::EType)i); + item = (LLViewerInventoryItem*)gAgentWearables.getWearableInventoryItem((LLWearableType::EType)i, 0); // TODO: MULTI-WEARABLE if(item) { const LLPermissions& perm = item->getPermissions(); @@ -2015,7 +2015,7 @@ void LLFloaterCustomize::onBtnMakeOutfit( void* userdata ) for( S32 i = 0; i < LLWearableType::WT_COUNT; i++ ) { - BOOL enabled = (gAgentWearables.getWearable( (LLWearableType::EType) i ) != NULL); + BOOL enabled = (gAgentWearables.getWearable( (LLWearableType::EType) i, 0 ) != NULL); // TODO: MULTI-WEARABLE BOOL selected = (enabled && (LLWearableType::WT_SHIRT <= i) && (i < LLWearableType::WT_COUNT)); // only select clothing by default if (gAgent.isTeen() && !edit_wearable_for_teens((LLWearableType::EType)i)) @@ -2748,13 +2748,13 @@ bool LLFloaterCustomize::onSaveDialog(const LLSD& notification, const LLSD& resp switch( option ) { case 0: // "Save" - gAgentWearables.saveWearable( cur ); + gAgentWearables.saveWearable( cur, 0 ); // TODO: MULTI-WEARABLE proceed = TRUE; break; case 1: // "Don't Save" { - gAgentWearables.revertWearable( cur ); + gAgentWearables.revertWearable( cur, 0 ); // TODO: MULTI-WEARABLE proceed = TRUE; } break; @@ -2775,10 +2775,10 @@ bool LLFloaterCustomize::onSaveDialog(const LLSD& notification, const LLSD& resp } // fetch observer -class LLCurrentlyWorn : public LLInventoryFetchObserver +class LLCurrentlyWorn : public LLInventoryFetchItemsObserver { public: - LLCurrentlyWorn() {} + LLCurrentlyWorn(const uuid_vec_t& item_ids) : LLInventoryFetchItemsObserver(item_ids){} ~LLCurrentlyWorn() {} virtual void done() { /* no operation necessary */} }; @@ -2790,7 +2790,7 @@ void LLFloaterCustomize::fetchInventory() LLUUID item_id; for(S32 type = (S32)LLWearableType::WT_SHAPE; type < (S32)LLWearableType::WT_COUNT; ++type) { - item_id = gAgentWearables.getWearableItemID((LLWearableType::EType)type); + item_id = gAgentWearables.getWearableItemID((LLWearableType::EType)type, 0); // TODO: MULTI-WEARABLE if(item_id.notNull()) { ids.push_back(item_id); @@ -2799,8 +2799,8 @@ void LLFloaterCustomize::fetchInventory() // Fire & forget. The mInventoryObserver will catch inventory // updates and correct the UI as necessary. - LLCurrentlyWorn worn; - worn.fetchItems(ids); + LLCurrentlyWorn worn(ids); + worn.startFetch(); } void LLFloaterCustomize::updateInventoryUI() @@ -2816,7 +2816,7 @@ void LLFloaterCustomize::updateInventoryUI() panel = mWearablePanelList[i]; if(panel) { - item = (LLViewerInventoryItem*)gAgentWearables.getWearableInventoryItem(panel->getType()); + item = (LLViewerInventoryItem*)gAgentWearables.getWearableInventoryItem(panel->getType(), 0); // TODO: MULTI-WEARABLE } if(item) { @@ -2851,7 +2851,7 @@ void LLFloaterCustomize::updateScrollingPanelUI() LLPanelEditWearable* panel = mWearablePanelList[sCurrentWearableType]; if(panel) { - LLViewerInventoryItem* item = (LLViewerInventoryItem*)gAgentWearables.getWearableInventoryItem(panel->getType()); + LLViewerInventoryItem* item = (LLViewerInventoryItem*)gAgentWearables.getWearableInventoryItem(panel->getType(), 0); // TODO: MULTI-WEARABLE if(item) { U32 perm_mask = item->getPermissions().getMaskOwner(); diff --git a/indra/newview/llfloatersnapshot.cpp b/indra/newview/llfloatersnapshot.cpp index 08044fa8d..2164a9eac 100644 --- a/indra/newview/llfloatersnapshot.cpp +++ b/indra/newview/llfloatersnapshot.cpp @@ -41,6 +41,7 @@ #include "v3dmath.h" #include "llmath.h" #include "lldir.h" +#include "lllocalcliprect.h" #include "llsdserialize.h" #include "llagent.h" diff --git a/indra/newview/llfloaterworldmap.cpp b/indra/newview/llfloaterworldmap.cpp index 6e1db8a0a..5e6ecf2b4 100644 --- a/indra/newview/llfloaterworldmap.cpp +++ b/indra/newview/llfloaterworldmap.cpp @@ -52,6 +52,10 @@ #include "lldraghandle.h" #include "llfirstuse.h" #include "llfocusmgr.h" +#include "llinventoryfunctions.h" +#include "llinventorymodel.h" +#include "llinventorymodelbackgroundfetch.h" +#include "llinventoryobserver.h" #include "lllandmarklist.h" #include "llnotificationsutil.h" #include "lllineeditor.h" @@ -70,7 +74,7 @@ #include "llappviewer.h" #include "llmapimagetype.h" #include "llweb.h" -#include "llinventoryfunctions.h" + #include "llglheaders.h" @@ -314,7 +318,7 @@ void LLFloaterWorldMap::show(void*, BOOL center_on_target) // Start speculative download of landmarks LLUUID landmark_folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_LANDMARK); - gInventory.startBackgroundFetch(landmark_folder_id); + LLInventoryModelBackgroundFetch::instance().start(landmark_folder_id); gFloaterWorldMap->childSetFocus("location", TRUE); gFocusMgr.triggerFocusFlash(); diff --git a/indra/newview/llfolderview.cpp b/indra/newview/llfolderview.cpp index 16b26bb26..7473d8c2d 100644 --- a/indra/newview/llfolderview.cpp +++ b/indra/newview/llfolderview.cpp @@ -49,6 +49,7 @@ #include "llinventoryclipboard.h" // *TODO: remove this once hack below gone. #include "llinventoryview.h"// hacked in for the bonus context menu items. #include "llinventoryfunctions.h" +#include "llinventorymodelbackgroundfetch.h" #include "llkeyboard.h" #include "lllineeditor.h" #include "llmenugl.h" @@ -1308,7 +1309,7 @@ void LLFolderViewFolder::filter( LLInventoryFilter& filter) // when applying a filter, matching folders get their contents downloaded first if (filter.isNotDefault() && getFiltered(filter.getMinRequiredGeneration()) && (mListener && !gInventory.isCategoryComplete(mListener->getUUID()))) { - gInventory.startBackgroundFetch(mListener->getUUID()); + LLInventoryModelBackgroundFetch::instance().start(mListener->getUUID()); } // now query children @@ -2715,11 +2716,13 @@ void LLFolderView::checkTreeResortForModelChanged() } } +static LLFastTimer::DeclareTimer FTM_SORT("Sort Inventory"); + void LLFolderView::setSortOrder(U32 order) { if (order != mSortOrder) { - LLFastTimer t(LLFastTimer::FTM_SORT); + LLFastTimer t(FTM_SORT); mSortOrder = order; for (folders_t::iterator iter = mFolders.begin(); @@ -2840,10 +2843,12 @@ void LLFolderView::setOpenArrangeRecursively(BOOL openitem, ERecurseType recurse mIsOpen = TRUE; } +static LLFastTimer::DeclareTimer FTM_ARRANGE("Arrange"); + // This view grows and shinks to enclose all of its children items and folders. S32 LLFolderView::arrange( S32* unused_width, S32* unused_height, S32 filter_generation ) { - LLFastTimer t2(LLFastTimer::FTM_ARRANGE); + LLFastTimer t2(FTM_ARRANGE); filter_generation = mFilter.getMinRequiredGeneration(); mMinWidth = 0; @@ -2933,9 +2938,11 @@ const std::string LLFolderView::getFilterSubString(BOOL trim) return mFilter.getFilterSubString(trim); } +static LLFastTimer::DeclareTimer FTM_FILTER("Filter Inventory"); + void LLFolderView::filter( LLInventoryFilter& filter ) { - LLFastTimer t2(LLFastTimer::FTM_FILTER); + LLFastTimer t2(FTM_FILTER); filter.setFilterCount(llclamp(gSavedSettings.getS32("FilterItemsPerFrame"), 1, 5000)); if (getCompletedFilterGeneration() < filter.getCurrentGeneration()) @@ -3108,8 +3115,10 @@ void LLFolderView::extendSelection(LLFolderViewItem* selection, LLFolderViewItem mSignalSelectCallback = SIGNAL_KEYBOARD_FOCUS; } +static LLFastTimer::DeclareTimer FTM_SANITIZE_SELECTION("Sanitize Selection"); void LLFolderView::sanitizeSelection() { + LLFastTimer _(FTM_SANITIZE_SELECTION); // store off current item in case it is automatically deselected // and we want to preserve context LLFolderViewItem* original_selected_item = getCurSelectedItem(); @@ -3319,7 +3328,7 @@ void LLFolderView::draw() } else { - if (gInventory.backgroundFetchActive() || mCompletedFilterGeneration < mFilter.getMinRequiredGeneration()) + if (LLInventoryModelBackgroundFetch::instance().backgroundFetchActive() || mCompletedFilterGeneration < mFilter.getMinRequiredGeneration()) { mStatusText = std::string("Searching..."); // *TODO:translate sFont->renderUTF8(mStatusText, 0, 2, 1, sSearchStatusColor, LLFontGL::LEFT, LLFontGL::TOP, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE ); @@ -4360,8 +4369,10 @@ void LLFolderView::removeItemID(const LLUUID& id) mItemMap.erase(id); } +LLFastTimer::DeclareTimer FTM_GET_ITEM_BY_ID("Get FolderViewItem by ID"); LLFolderViewItem* LLFolderView::getItemByID(const LLUUID& id) { + LLFastTimer _(FTM_GET_ITEM_BY_ID); if (id.isNull()) { return this; @@ -4378,10 +4389,13 @@ LLFolderViewItem* LLFolderView::getItemByID(const LLUUID& id) } + +static LLFastTimer::DeclareTimer FTM_AUTO_SELECT("Open and Select"); +static LLFastTimer::DeclareTimer FTM_INVENTORY("Inventory"); // Main idle routine void LLFolderView::doIdle() { - LLFastTimer t2(LLFastTimer::FTM_INVENTORY); + LLFastTimer t2(FTM_INVENTORY); BOOL debug_filters = gSavedSettings.getBOOL("DebugInventoryFilters"); if (debug_filters != getDebugFilters()) @@ -4406,7 +4420,7 @@ void LLFolderView::doIdle() // potentially changed if (mNeedsAutoSelect) { - LLFastTimer t3(LLFastTimer::FTM_AUTO_SELECT); + LLFastTimer t3(FTM_AUTO_SELECT); // select new item only if a filtered item not currently selected LLFolderViewItem* selected_itemp = mSelectedItems.empty() ? NULL : mSelectedItems.back(); if (selected_itemp != NULL && sFolderViewItems.count(selected_itemp) == 0) @@ -4629,581 +4643,3 @@ void LLFolderViewEventListener::arrangeAndSet(LLFolderViewItem* focus, } -///---------------------------------------------------------------------------- -/// Class LLInventoryFilter -///---------------------------------------------------------------------------- -LLInventoryFilter::LLInventoryFilter(const std::string& name) : - mName(name), - mModified(FALSE), - mNeedTextRebuild(TRUE) -{ - mFilterOps.mFilterTypes = 0xffffffff; - mFilterOps.mMinDate = time_min(); - mFilterOps.mMaxDate = time_max(); - mFilterOps.mHoursAgo = 0; - mFilterOps.mShowFolderState = SHOW_NON_EMPTY_FOLDERS; - mFilterOps.mPermissions = PERM_NONE; - - mOrder = SO_FOLDERS_BY_NAME; // This gets overridden by a pref immediately - - mSubStringMatchOffset = 0; - mFilterSubString.clear(); - mFilterWorn = false; - mFilterGeneration = 0; - mMustPassGeneration = S32_MAX; - mMinRequiredGeneration = 0; - mFilterCount = 0; - mNextFilterGeneration = mFilterGeneration + 1; - - mLastLogoff = gSavedPerAccountSettings.getU32("LastLogoff"); - mFilterBehavior = FILTER_NONE; - - // copy mFilterOps into mDefaultFilterOps - markDefault(); -} - -LLInventoryFilter::~LLInventoryFilter() -{ -} - -BOOL LLInventoryFilter::check(LLFolderViewItem* item) -{ - LLFolderViewEventListener* listener = item->getListener(); - const LLUUID& item_id = listener->getUUID(); - const LLInventoryObject *obj = gInventory.getObject(item_id); - if (isActive() && obj && obj->getIsLinkType()) - { - // When filtering is active, omit links. - return FALSE; - } - - time_t earliest; - - earliest = time_corrected() - mFilterOps.mHoursAgo * 3600; - if (mFilterOps.mMinDate > time_min() && mFilterOps.mMinDate < earliest) - { - earliest = mFilterOps.mMinDate; - } - else if (!mFilterOps.mHoursAgo) - { - earliest = 0; - } - mSubStringMatchOffset = mFilterSubString.size() ? item->getSearchableLabel().find(mFilterSubString) : std::string::npos; - BOOL passed = (0x1 << listener->getInventoryType() & mFilterOps.mFilterTypes || listener->getInventoryType() == LLInventoryType::IT_NONE) - && (mFilterSubString.size() == 0 || mSubStringMatchOffset != std::string::npos) - && (mFilterWorn == false || gAgentWearables.isWearingItem(item_id) || - (gAgentAvatarp && gAgentAvatarp->isWearingAttachment(item_id))) - && ((listener->getPermissionMask() & mFilterOps.mPermissions) == mFilterOps.mPermissions) - && (listener->getCreationDate() >= earliest && listener->getCreationDate() <= mFilterOps.mMaxDate); - return passed; -} - -const std::string LLInventoryFilter::getFilterSubString(BOOL trim) -{ - return mFilterSubString; -} - -std::string::size_type LLInventoryFilter::getStringMatchOffset() const -{ - return mSubStringMatchOffset; -} - -// has user modified default filter params? -BOOL LLInventoryFilter::isNotDefault() -{ - return mFilterOps.mFilterTypes != mDefaultFilterOps.mFilterTypes - || mFilterSubString.size() - || mFilterWorn - || mFilterOps.mPermissions != mDefaultFilterOps.mPermissions - || mFilterOps.mMinDate != mDefaultFilterOps.mMinDate - || mFilterOps.mMaxDate != mDefaultFilterOps.mMaxDate - || mFilterOps.mHoursAgo != mDefaultFilterOps.mHoursAgo; -} - -BOOL LLInventoryFilter::isActive() -{ - return mFilterOps.mFilterTypes != 0xffffffff - || mFilterSubString.size() - || mFilterWorn - || mFilterOps.mPermissions != PERM_NONE - || mFilterOps.mMinDate != time_min() - || mFilterOps.mMaxDate != time_max() - || mFilterOps.mHoursAgo != 0; -} - -BOOL LLInventoryFilter::isModified() -{ - return mModified; -} - -BOOL LLInventoryFilter::isModifiedAndClear() -{ - BOOL ret = mModified; - mModified = FALSE; - return ret; -} - -void LLInventoryFilter::setFilterTypes(U32 types) -{ - if (mFilterOps.mFilterTypes != types) - { - // keep current items only if no type bits getting turned off - BOOL fewer_bits_set = (mFilterOps.mFilterTypes & ~types); - BOOL more_bits_set = (~mFilterOps.mFilterTypes & types); - - mFilterOps.mFilterTypes = types; - if (more_bits_set && fewer_bits_set) - { - // neither less or more restrive, both simultaneously - // so we need to filter from scratch - setModified(FILTER_RESTART); - } - else if (more_bits_set) - { - // target is only one of all requested types so more type bits == less restrictive - setModified(FILTER_LESS_RESTRICTIVE); - } - else if (fewer_bits_set) - { - setModified(FILTER_MORE_RESTRICTIVE); - } - - } -} - -void LLInventoryFilter::setFilterSubString(const std::string& string) -{ - if (mFilterSubString != string) - { - // hitting BACKSPACE, for example - BOOL less_restrictive = mFilterSubString.size() >= string.size() && !mFilterSubString.substr(0, string.size()).compare(string); - // appending new characters - BOOL more_restrictive = mFilterSubString.size() < string.size() && !string.substr(0, mFilterSubString.size()).compare(mFilterSubString); - mFilterSubString = string; - LLStringUtil::toUpper(mFilterSubString); - LLStringUtil::trimHead(mFilterSubString); - - if (less_restrictive) - { - setModified(FILTER_LESS_RESTRICTIVE); - } - else if (more_restrictive) - { - setModified(FILTER_MORE_RESTRICTIVE); - } - else - { - setModified(FILTER_RESTART); - } - } -} - -void LLInventoryFilter::setFilterPermissions(PermissionMask perms) -{ - if (mFilterOps.mPermissions != perms) - { - // keep current items only if no perm bits getting turned off - BOOL fewer_bits_set = (mFilterOps.mPermissions & ~perms); - BOOL more_bits_set = (~mFilterOps.mPermissions & perms); - mFilterOps.mPermissions = perms; - - if (more_bits_set && fewer_bits_set) - { - setModified(FILTER_RESTART); - } - else if (more_bits_set) - { - // target must have all requested permission bits, so more bits == more restrictive - setModified(FILTER_MORE_RESTRICTIVE); - } - else if (fewer_bits_set) - { - setModified(FILTER_LESS_RESTRICTIVE); - } - } -} - -void LLInventoryFilter::setDateRange(time_t min_date, time_t max_date) -{ - mFilterOps.mHoursAgo = 0; - if (mFilterOps.mMinDate != min_date) - { - mFilterOps.mMinDate = min_date; - setModified(); - } - if (mFilterOps.mMaxDate != llmax(mFilterOps.mMinDate, max_date)) - { - mFilterOps.mMaxDate = llmax(mFilterOps.mMinDate, max_date); - setModified(); - } -} - -void LLInventoryFilter::setDateRangeLastLogoff(BOOL sl) -{ - if (sl && !isSinceLogoff()) - { - setDateRange(mLastLogoff, time_max()); - setModified(); - } - if (!sl && isSinceLogoff()) - { - setDateRange(0, time_max()); - setModified(); - } -} - -BOOL LLInventoryFilter::isSinceLogoff() -{ - return (mFilterOps.mMinDate == mLastLogoff) && - (mFilterOps.mMaxDate == time_max()); -} - -void LLInventoryFilter::setHoursAgo(U32 hours) -{ - if (mFilterOps.mHoursAgo != hours) - { - // *NOTE: need to cache last filter time, in case filter goes stale - BOOL less_restrictive = (mFilterOps.mMinDate == time_min() && mFilterOps.mMaxDate == time_max() && hours > mFilterOps.mHoursAgo); - BOOL more_restrictive = (mFilterOps.mMinDate == time_min() && mFilterOps.mMaxDate == time_max() && hours <= mFilterOps.mHoursAgo); - mFilterOps.mHoursAgo = hours; - mFilterOps.mMinDate = time_min(); - mFilterOps.mMaxDate = time_max(); - if (less_restrictive) - { - setModified(FILTER_LESS_RESTRICTIVE); - } - else if (more_restrictive) - { - setModified(FILTER_MORE_RESTRICTIVE); - } - else - { - setModified(FILTER_RESTART); - } - } -} -void LLInventoryFilter::setShowFolderState(EFolderShow state) -{ - if (mFilterOps.mShowFolderState != state) - { - mFilterOps.mShowFolderState = state; - if (state == SHOW_NON_EMPTY_FOLDERS) - { - // showing fewer folders than before - setModified(FILTER_MORE_RESTRICTIVE); - } - else if (state == SHOW_ALL_FOLDERS) - { - // showing same folders as before and then some - setModified(FILTER_LESS_RESTRICTIVE); - } - else - { - setModified(); - } - } -} - -void LLInventoryFilter::setSortOrder(U32 order) -{ - if (mOrder != order) - { - mOrder = order; - setModified(); - } -} - -void LLInventoryFilter::markDefault() -{ - mDefaultFilterOps = mFilterOps; -} - -void LLInventoryFilter::resetDefault() -{ - mFilterOps = mDefaultFilterOps; - setModified(); -} - -void LLInventoryFilter::setModified(EFilterBehavior behavior) -{ - mModified = TRUE; - mNeedTextRebuild = TRUE; - mFilterGeneration = mNextFilterGeneration++; - - if (mFilterBehavior == FILTER_NONE) - { - mFilterBehavior = behavior; - } - else if (mFilterBehavior != behavior) - { - // trying to do both less restrictive and more restrictive filter - // basically means restart from scratch - mFilterBehavior = FILTER_RESTART; - } - - if (isNotDefault()) - { - // if not keeping current filter results, update last valid as well - switch(mFilterBehavior) - { - case FILTER_RESTART: - mMustPassGeneration = mFilterGeneration; - mMinRequiredGeneration = mFilterGeneration; - break; - case FILTER_LESS_RESTRICTIVE: - mMustPassGeneration = mFilterGeneration; - break; - case FILTER_MORE_RESTRICTIVE: - mMinRequiredGeneration = mFilterGeneration; - // must have passed either current filter generation (meaningless, as it hasn't been run yet) - // or some older generation, so keep the value - mMustPassGeneration = llmin(mMustPassGeneration, mFilterGeneration); - break; - default: - llerrs << "Bad filter behavior specified" << llendl; - } - } - else - { - // shortcut disabled filters to show everything immediately - mMinRequiredGeneration = 0; - mMustPassGeneration = S32_MAX; - } -} - -BOOL LLInventoryFilter::isFilterWith(LLInventoryType::EType t) -{ - return mFilterOps.mFilterTypes & (0x01 << t); -} - -std::string LLInventoryFilter::getFilterText() -{ - if (!mNeedTextRebuild) - { - return mFilterText; - } - - mNeedTextRebuild = FALSE; - std::string filtered_types; - std::string not_filtered_types; - BOOL filtered_by_type = FALSE; - BOOL filtered_by_all_types = TRUE; - S32 num_filter_types = 0; - mFilterText.clear(); - - if (isFilterWith(LLInventoryType::IT_ANIMATION)) - { - filtered_types += " Animations,"; - filtered_by_type = TRUE; - num_filter_types++; - } - else - { - not_filtered_types += " Animations,"; - filtered_by_all_types = FALSE; - } - - if (isFilterWith(LLInventoryType::IT_CALLINGCARD)) - { - filtered_types += " Calling Cards,"; - filtered_by_type = TRUE; - num_filter_types++; - } - else - { - not_filtered_types += " Calling Cards,"; - filtered_by_all_types = FALSE; - } - - if (isFilterWith(LLInventoryType::IT_WEARABLE)) - { - filtered_types += " Clothing,"; - filtered_by_type = TRUE; - num_filter_types++; - } - else - { - not_filtered_types += " Clothing,"; - filtered_by_all_types = FALSE; - } - - if (isFilterWith(LLInventoryType::IT_GESTURE)) - { - filtered_types += " Gestures,"; - filtered_by_type = TRUE; - num_filter_types++; - } - else - { - not_filtered_types += " Gestures,"; - filtered_by_all_types = FALSE; - } - - if (isFilterWith(LLInventoryType::IT_LANDMARK)) - { - filtered_types += " Landmarks,"; - filtered_by_type = TRUE; - num_filter_types++; - } - else - { - not_filtered_types += " Landmarks,"; - filtered_by_all_types = FALSE; - } - - if (isFilterWith(LLInventoryType::IT_NOTECARD)) - { - filtered_types += " Notecards,"; - filtered_by_type = TRUE; - num_filter_types++; - } - else - { - not_filtered_types += " Notecards,"; - filtered_by_all_types = FALSE; - } - - if (isFilterWith(LLInventoryType::IT_OBJECT) && isFilterWith(LLInventoryType::IT_ATTACHMENT)) - { - filtered_types += " Objects,"; - filtered_by_type = TRUE; - num_filter_types++; - } - else - { - not_filtered_types += " Objects,"; - filtered_by_all_types = FALSE; - } - - if (isFilterWith(LLInventoryType::IT_LSL)) - { - filtered_types += " Scripts,"; - filtered_by_type = TRUE; - num_filter_types++; - } - else - { - not_filtered_types += " Scripts,"; - filtered_by_all_types = FALSE; - } - - if (isFilterWith(LLInventoryType::IT_SOUND)) - { - filtered_types += " Sounds,"; - filtered_by_type = TRUE; - num_filter_types++; - } - else - { - not_filtered_types += " Sounds,"; - filtered_by_all_types = FALSE; - } - - if (isFilterWith(LLInventoryType::IT_TEXTURE)) - { - filtered_types += " Textures,"; - filtered_by_type = TRUE; - num_filter_types++; - } - else - { - not_filtered_types += " Textures,"; - filtered_by_all_types = FALSE; - } - - if (isFilterWith(LLInventoryType::IT_SNAPSHOT)) - { - filtered_types += " Snapshots,"; - filtered_by_type = TRUE; - num_filter_types++; - } - else - { - not_filtered_types += " Snapshots,"; - filtered_by_all_types = FALSE; - } - - if (!gInventory.backgroundFetchActive() && filtered_by_type && !filtered_by_all_types) - { - mFilterText += " - "; - if (num_filter_types < 5) - { - mFilterText += filtered_types; - } - else - { - mFilterText += "No "; - mFilterText += not_filtered_types; - } - // remove the ',' at the end - mFilterText.erase(mFilterText.size() - 1, 1); - } - - if (isSinceLogoff()) - { - mFilterText += " - Since Logoff"; - } - - if (getFilterWorn()) - { - mFilterText += " - Worn"; - } - - return mFilterText; -} - -void LLInventoryFilter::toLLSD(LLSD& data) -{ - data["filter_types"] = (LLSD::Integer)getFilterTypes(); - data["min_date"] = (LLSD::Integer)getMinDate(); - data["max_date"] = (LLSD::Integer)getMaxDate(); - data["hours_ago"] = (LLSD::Integer)getHoursAgo(); - data["show_folder_state"] = (LLSD::Integer)getShowFolderState(); - data["permissions"] = (LLSD::Integer)getFilterPermissions(); - data["substring"] = (LLSD::String)getFilterSubString(); - data["sort_order"] = (LLSD::Integer)getSortOrder(); - data["since_logoff"] = (LLSD::Boolean)isSinceLogoff(); -} - -void LLInventoryFilter::fromLLSD(LLSD& data) -{ - if(data.has("filter_types")) - { - setFilterTypes((U32)data["filter_types"].asInteger()); - } - - if(data.has("min_date") && data.has("max_date")) - { - setDateRange(data["min_date"].asInteger(), data["max_date"].asInteger()); - } - - if(data.has("hours_ago")) - { - setHoursAgo((U32)data["hours_ago"].asInteger()); - } - - if(data.has("show_folder_state")) - { - setShowFolderState((EFolderShow)data["show_folder_state"].asInteger()); - } - - if(data.has("permissions")) - { - setFilterPermissions((PermissionMask)data["permissions"].asInteger()); - } - - if(data.has("substring")) - { - setFilterSubString(std::string(data["substring"].asString())); - } - - if(data.has("sort_order")) - { - setSortOrder((U32)data["sort_order"].asInteger()); - } - - if(data.has("since_logoff")) - { - setDateRangeLastLogoff((bool)data["since_logoff"].asBoolean()); - } -} diff --git a/indra/newview/llfolderview.h b/indra/newview/llfolderview.h index 7eda4f691..5ef029e32 100644 --- a/indra/newview/llfolderview.h +++ b/indra/newview/llfolderview.h @@ -55,6 +55,7 @@ #include "llviewertexture.h" #include "lldepthstack.h" #include "lltooldraganddrop.h" +#include "llinventoryfilter.h" class LLMenuGL; @@ -74,7 +75,6 @@ class LLFolderViewFunctor; class LLScrollableContainerView; class LLFolderViewEventListener; - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLFolderViewListenerFunctor // @@ -102,117 +102,7 @@ class LLFolderViewItem; class LLFolderViewFolder; -class LLInventoryFilter -{ -public: - typedef enum e_folder_show - { - SHOW_ALL_FOLDERS, - SHOW_NON_EMPTY_FOLDERS, - SHOW_NO_FOLDERS - } EFolderShow; - typedef enum e_filter_behavior - { - FILTER_NONE, // nothing to do, already filtered - FILTER_RESTART, // restart filtering from scratch - FILTER_LESS_RESTRICTIVE, // existing filtered items will certainly pass this filter - FILTER_MORE_RESTRICTIVE // if you didn't pass the previous filter, you definitely won't pass this one - } EFilterBehavior; - - static const U32 SO_DATE = 1; - static const U32 SO_FOLDERS_BY_NAME = 2; - static const U32 SO_SYSTEM_FOLDERS_TO_TOP = 4; - - LLInventoryFilter(const std::string& name); - virtual ~LLInventoryFilter(); - - void setFilterTypes(U32 types); - U32 getFilterTypes() const { return mFilterOps.mFilterTypes; } - - void setFilterSubString(const std::string& string); - const std::string getFilterSubString(BOOL trim = FALSE); - - void setFilterWorn(bool worn) { mFilterWorn = worn; } - bool getFilterWorn() const { return mFilterWorn; } - - void setFilterPermissions(PermissionMask perms); - PermissionMask getFilterPermissions() const { return mFilterOps.mPermissions; } - - void setDateRange(time_t min_date, time_t max_date); - void setDateRangeLastLogoff(BOOL sl); - time_t getMinDate() const { return mFilterOps.mMinDate; } - time_t getMaxDate() const { return mFilterOps.mMaxDate; } - - void setHoursAgo(U32 hours); - U32 getHoursAgo() const { return mFilterOps.mHoursAgo; } - - void setShowFolderState( EFolderShow state); - EFolderShow getShowFolderState() { return mFilterOps.mShowFolderState; } - - void setSortOrder(U32 order); - U32 getSortOrder() { return mOrder; } - - BOOL check(LLFolderViewItem* item); - std::string::size_type getStringMatchOffset() const; - BOOL isActive(); - BOOL isNotDefault(); - BOOL isModified(); - BOOL isModifiedAndClear(); - BOOL isSinceLogoff(); - void clearModified() { mModified = FALSE; mFilterBehavior = FILTER_NONE; } - const std::string getName() const { return mName; } - std::string getFilterText(); - - void setFilterCount(S32 count) { mFilterCount = count; } - S32 getFilterCount() { return mFilterCount; } - void decrementFilterCount() { mFilterCount--; } - - void markDefault(); - void resetDefault(); - - BOOL isFilterWith(LLInventoryType::EType t); - - S32 getCurrentGeneration() const { return mFilterGeneration; } - S32 getMinRequiredGeneration() const { return mMinRequiredGeneration; } - S32 getMustPassGeneration() const { return mMustPassGeneration; } - - //RN: this is public to allow system to externally force a global refilter - void setModified(EFilterBehavior behavior = FILTER_RESTART); - - void toLLSD(LLSD& data); - void fromLLSD(LLSD& data); - -protected: - struct filter_ops - { - U32 mFilterTypes; - time_t mMinDate; - time_t mMaxDate; - U32 mHoursAgo; - EFolderShow mShowFolderState; - PermissionMask mPermissions; - }; - filter_ops mFilterOps; - filter_ops mDefaultFilterOps; - std::string::size_type mSubStringMatchOffset; - std::string mFilterSubString; - bool mFilterWorn; - U32 mOrder; - const std::string mName; - S32 mFilterGeneration; - S32 mMustPassGeneration; - S32 mMinRequiredGeneration; - S32 mFilterCount; - S32 mNextFilterGeneration; - EFilterBehavior mFilterBehavior; - -private: - U32 mLastLogoff; - BOOL mModified; - BOOL mNeedTextRebuild; - std::string mFilterText; -}; // These are grouping of inventory types. // Order matters when sorting system folders to the top. diff --git a/indra/newview/llgiveinventory.cpp b/indra/newview/llgiveinventory.cpp index 8e61b9298..b922f7710 100644 --- a/indra/newview/llgiveinventory.cpp +++ b/indra/newview/llgiveinventory.cpp @@ -219,11 +219,15 @@ bool LLGiveInventory::doGiveInventoryItem(const LLUUID& to_agent, else { // ask if the agent is sure. + LLSD substitutions; + substitutions["ITEMS"] = item->getName(); LLSD payload; payload["agent_id"] = to_agent; - payload["item_id"] = item->getUUID(); - LLNotificationsUtil::add("CannotCopyWarning", LLSD(), payload, - &LLGiveInventory::handleCopyProtectedItem); + LLSD items = LLSD::emptyArray(); + items.append(item->getUUID()); + payload["items"] = items; + LLNotificationsUtil::add("CannotCopyWarning", substitutions, payload, + &LLGiveInventory::handleCopyProtectedItem); res = false; } @@ -302,9 +306,10 @@ void LLGiveInventory::doGiveInventoryCategory(const LLUUID& to_agent, void LLGiveInventory::logInventoryOffer(const LLUUID& to_agent, const LLUUID &im_session_id) { // If this item was given by drag-and-drop into an IM panel, log this action in the IM panel chat. + LLSD args; + args["user_id"] = to_agent; if (im_session_id.notNull()) { - LLSD args; gIMMgr->addSystemMessage(im_session_id, "inventory_item_offered", args); } } @@ -312,24 +317,28 @@ void LLGiveInventory::logInventoryOffer(const LLUUID& to_agent, const LLUUID &im // static bool LLGiveInventory::handleCopyProtectedItem(const LLSD& notification, const LLSD& response) { - S32 option = LLNotification::getSelectedOption(notification, response); + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + LLSD itmes = notification["payload"]["items"]; LLInventoryItem* item = NULL; switch(option) { case 0: // "Yes" - item = gInventory.getItem(notification["payload"]["item_id"].asUUID()); - if(item) + for (LLSD::array_iterator it = itmes.beginArray(); it != itmes.endArray(); it++) { - LLGiveInventory::commitGiveInventoryItem(notification["payload"]["agent_id"].asUUID(), - item); - // delete it for now - it will be deleted on the server - // quickly enough. - gInventory.deleteObject(notification["payload"]["item_id"].asUUID()); - gInventory.notifyObservers(); - } - else - { - LLNotificationsUtil::add("CannotGiveItem"); + item = gInventory.getItem((*it).asUUID()); + if (item) + { + LLGiveInventory::commitGiveInventoryItem(notification["payload"]["agent_id"].asUUID(), + item); + // delete it for now - it will be deleted on the server + // quickly enough. + gInventory.deleteObject(item->getUUID()); + gInventory.notifyObservers(); + } + else + { + LLNotificationsUtil::add("CannotGiveItem"); + } } break; diff --git a/indra/newview/llhudmanager.cpp b/indra/newview/llhudmanager.cpp index 038e4ae2c..cb9a2c1d3 100644 --- a/indra/newview/llhudmanager.cpp +++ b/indra/newview/llhudmanager.cpp @@ -61,10 +61,11 @@ LLHUDManager::~LLHUDManager() { } +static LLFastTimer::DeclareTimer FTM_HUD_EFFECTS("Hud Effects"); void LLHUDManager::updateEffects() { - LLFastTimer ftm(LLFastTimer::FTM_HUD_EFFECTS); + LLFastTimer ftm(FTM_HUD_EFFECTS); S32 i; for (i = 0; i < mHUDEffects.count(); i++) { diff --git a/indra/newview/llhudobject.cpp b/indra/newview/llhudobject.cpp index 67dbb4784..b5aafcd03 100644 --- a/indra/newview/llhudobject.cpp +++ b/indra/newview/llhudobject.cpp @@ -257,10 +257,12 @@ LLHUDEffect *LLHUDObject::addHUDEffect(const U8 type) return hud_objectp; } +static LLFastTimer::DeclareTimer FTM_HUD_UPDATE("Update Hud"); + // static void LLHUDObject::updateAll() { - LLFastTimer ftm(LLFastTimer::FTM_HUD_UPDATE); + LLFastTimer ftm(FTM_HUD_UPDATE); LLHUDText::updateAll(); LLHUDIcon::updateAll(); LLHUDNameTag::updateAll(); diff --git a/indra/newview/llinventoryactions.cpp b/indra/newview/llinventoryactions.cpp index 14cad7cc6..27c9dc56e 100644 --- a/indra/newview/llinventoryactions.cpp +++ b/indra/newview/llinventoryactions.cpp @@ -63,6 +63,7 @@ #include "lliconctrl.h" #include "llinventoryfunctions.h" #include "llinventoryclipboard.h" +#include "llinventorymodelbackgroundfetch.h" #include "lllineeditor.h" #include "llmenugl.h" #include "llpreviewanim.h" @@ -525,7 +526,7 @@ class LLRefreshInvModel : public inventory_listener_t LLInventoryModel* model = mPtr->getPanel()->getModel(); if(!model) return false; model->empty(); - model->startBackgroundFetch(); + LLInventoryModelBackgroundFetch::instance().start(); return true; } }; diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 08ee59a0c..84d47a3f2 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -39,6 +39,7 @@ #include "llinventorydefines.h" #include "llinventoryfunctions.h" #include "llinventoryicon.h" +#include "llinventorymodelbackgroundfetch.h" #include "message.h" @@ -193,15 +194,6 @@ struct LLWearInfo // | LLInvFVBridge | // +=================================================+ -/*virtual*/ void LLInventoryPanelObserver::changed(U32 mask) -{ - mIP->modelChanged(mask); -} - -// +=================================================+ -// | LLInvFVBridge | -// +=================================================+ - LLInvFVBridge::LLInvFVBridge(LLInventoryPanel* inventory, //LLFolderView* root, const LLUUID& uuid) : @@ -811,7 +803,7 @@ BOOL LLInvFVBridge::startDrag(EDragAndDropType* type, LLUUID* id) const if (*type == DAD_CATEGORY) { - gInventory.startBackgroundFetch(obj->getUUID()); + LLInventoryModelBackgroundFetch::instance().start(obj->getUUID()); } rv = TRUE; @@ -1885,13 +1877,17 @@ BOOL move_inv_category_world_to_agent(const LLUUID& object_id, } //Used by LLFolderBridge as callback for directory recursion. -class LLRightClickInventoryFetchObserver : public LLInventoryFetchObserver +class LLRightClickInventoryFetchObserver : public LLInventoryFetchItemsObserver { public: - LLRightClickInventoryFetchObserver() : + LLRightClickInventoryFetchObserver(const uuid_vec_t& ids) : + LLInventoryFetchItemsObserver(ids), mCopyItems(false) { }; - LLRightClickInventoryFetchObserver(const LLUUID& cat_id, bool copy_items) : + LLRightClickInventoryFetchObserver(const uuid_vec_t& ids, + const LLUUID& cat_id, + bool copy_items) : + LLInventoryFetchItemsObserver(ids), mCatID(cat_id), mCopyItems(copy_items) { }; @@ -1915,7 +1911,11 @@ protected: class LLRightClickInventoryFetchDescendentsObserver : public LLInventoryFetchDescendentsObserver { public: - LLRightClickInventoryFetchDescendentsObserver(bool copy_items) : mCopyItems(copy_items) {} + LLRightClickInventoryFetchDescendentsObserver(const uuid_vec_t& ids, + bool copy_items) : + LLInventoryFetchDescendentsObserver(ids), + mCopyItems(copy_items) + {} ~LLRightClickInventoryFetchDescendentsObserver() {} virtual void done(); protected: @@ -1926,7 +1926,7 @@ void LLRightClickInventoryFetchDescendentsObserver::done() { // Avoid passing a NULL-ref as mCompleteFolders.front() down to // gInventory.collectDescendents() - if( mCompleteFolders.empty() ) + if( mComplete.empty() ) { llwarns << "LLRightClickInventoryFetchDescendentsObserver::done with empty mCompleteFolders" << llendl; dec_busy_count(); @@ -1940,7 +1940,7 @@ void LLRightClickInventoryFetchDescendentsObserver::done() // happen. LLInventoryModel::cat_array_t cat_array; LLInventoryModel::item_array_t item_array; - gInventory.collectDescendents(mCompleteFolders.front(), + gInventory.collectDescendents(mComplete.front(), cat_array, item_array, LLInventoryModel::EXCLUDE_TRASH); @@ -1949,7 +1949,7 @@ void LLRightClickInventoryFetchDescendentsObserver::done() // This early causes a giant menu to get produced, and doesn't seem to be needed. if(!count) { - llwarns << "Nothing fetched in category " << mCompleteFolders.front() + llwarns << "Nothing fetched in category " << mComplete.front() << llendl; dec_busy_count(); gInventory.removeObserver(this); @@ -1964,7 +1964,7 @@ void LLRightClickInventoryFetchDescendentsObserver::done() ids.push_back(item_array.get(i)->getUUID()); } - LLRightClickInventoryFetchObserver* outfit = new LLRightClickInventoryFetchObserver(mCompleteFolders.front(), mCopyItems); + LLRightClickInventoryFetchObserver* outfit = new LLRightClickInventoryFetchObserver(ids, mComplete.front(), mCopyItems); // clean up, and remove this as an observer since the call to the // outfit could notify observers and throw us into an infinite @@ -1978,7 +1978,7 @@ void LLRightClickInventoryFetchDescendentsObserver::done() inc_busy_count(); // do the fetch - outfit->fetchItems(ids); + outfit->startFetch(); outfit->done(); //Not interested in waiting and this will be right 99% of the time. //Uncomment the following code for laggy Inventory UI. /* if(outfit->isEverythingComplete()) @@ -2557,10 +2557,10 @@ void LLFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags) mMenu = menu.getHandle(); sSelf = getHandle(); - LLRightClickInventoryFetchDescendentsObserver* fetch = new LLRightClickInventoryFetchDescendentsObserver(FALSE); - fetch->fetchDescendents(folders); + LLRightClickInventoryFetchDescendentsObserver* fetch = new LLRightClickInventoryFetchDescendentsObserver(folders, FALSE); + fetch->startFetch(); inc_busy_count(); - if(fetch->isEverythingComplete()) + if(fetch->isFinished()) { // everything is already here - call done. fetch->done(); @@ -4366,10 +4366,11 @@ struct LLWearableHoldingPattern */ // [/RLVa:KB] -class LLOutfitObserver : public LLInventoryFetchObserver +class LLOutfitObserver : public LLInventoryFetchItemsObserver { public: - LLOutfitObserver(const LLUUID& cat_id, bool copy_items, bool append) : + LLOutfitObserver(const uuid_vec_t& ids, const LLUUID& cat_id, bool copy_items, bool append) : + LLInventoryFetchItemsObserver(ids), mCatID(cat_id), mCopyItems(copy_items), mAppend(append) @@ -4498,7 +4499,7 @@ void LLOutfitObserver::done() class LLOutfitFetch : public LLInventoryFetchDescendentsObserver { public: - LLOutfitFetch(bool copy_items, bool append) : mCopyItems(copy_items), mAppend(append) {} + LLOutfitFetch(const LLUUID& id, bool copy_items, bool append) : mCopyItems(copy_items), mAppend(append) {} ~LLOutfitFetch() {} virtual void done(); protected: @@ -4513,14 +4514,14 @@ void LLOutfitFetch::done() // happen. LLInventoryModel::cat_array_t cat_array; LLInventoryModel::item_array_t item_array; - gInventory.collectDescendents(mCompleteFolders.front(), + gInventory.collectDescendents(mComplete.front(), cat_array, item_array, LLInventoryModel::EXCLUDE_TRASH); S32 count = item_array.count(); if(!count) { - llwarns << "Nothing fetched in category " << mCompleteFolders.front() + llwarns << "Nothing fetched in category " << mComplete.front() << llendl; dec_busy_count(); gInventory.removeObserver(this); @@ -4528,14 +4529,15 @@ void LLOutfitFetch::done() return; } - LLOutfitObserver* outfit; - outfit = new LLOutfitObserver(mCompleteFolders.front(), mCopyItems, mAppend); uuid_vec_t ids; for(S32 i = 0; i < count; ++i) { ids.push_back(item_array.get(i)->getUUID()); } + LLOutfitObserver* outfit = new LLOutfitObserver(ids, mComplete.front(), mCopyItems, mAppend); + + // clean up, and remove this as an observer since the call to the // outfit could notify observers and throw us into an infinite // loop. @@ -4548,8 +4550,8 @@ void LLOutfitFetch::done() inc_busy_count(); // do the fetch - outfit->fetchItems(ids); - if(outfit->isEverythingComplete()) + outfit->startFetch(); + if(outfit->isFinished()) { // everything is already here - call done. outfit->done(); @@ -4618,13 +4620,10 @@ void wear_inventory_category(LLInventoryCategory* category, bool copy, bool appe // What we do here is get the complete information on the items in // the inventory, and set up an observer that will wait for that to // happen. - LLOutfitFetch* outfit; - outfit = new LLOutfitFetch(copy, append); - LLInventoryFetchDescendentsObserver::folder_ref_t folders; - folders.push_back(category->getUUID()); - outfit->fetchDescendents(folders); + LLOutfitFetch* outfit = new LLOutfitFetch(category->getUUID(), copy, append); + outfit->startFetch(); inc_busy_count(); - if(outfit->isEverythingComplete()) + if(outfit->isFinished()) { // everything is already here - call done. outfit->done(); @@ -5423,7 +5422,7 @@ void LLWearableBridge::onRemoveFromAvatarArrived(LLWearable* wearable, if( !(type==LLWearableType::WT_SHAPE || type==LLWearableType::WT_SKIN || type==LLWearableType::WT_HAIR || type==LLWearableType::WT_EYES) ) //&& //!((!gAgent.isTeen()) && ( type==WT_UNDERPANTS || type==WT_UNDERSHIRT )) ) { - gAgentWearables.removeWearable( type ); + gAgentWearables.removeWearable( type, false, 0 ); // TODO: MULTI-WEARABLE } } } diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h index 0279c850f..381646b39 100644 --- a/indra/newview/llinventorybridge.h +++ b/indra/newview/llinventorybridge.h @@ -117,21 +117,6 @@ public: } }; -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLInventoryPanelObserver -// -// Bridge to support knowing when the inventory has changed. -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -class LLInventoryPanelObserver : public LLInventoryObserver -{ -public: - LLInventoryPanelObserver(LLInventoryPanel* ip) : mIP(ip) {} - virtual ~LLInventoryPanelObserver() {} - virtual void changed(U32 mask); -protected: - LLInventoryPanel* mIP; -}; - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLInvFVBridge (& it's derived classes) // diff --git a/indra/newview/llinventoryfilter.cpp b/indra/newview/llinventoryfilter.cpp new file mode 100644 index 000000000..3849286cd --- /dev/null +++ b/indra/newview/llinventoryfilter.cpp @@ -0,0 +1,706 @@ +/** +* @file llinventoryfilter.cpp +* @brief Support for filtering your inventory to only display a subset of the +* available items. +* +* $LicenseInfo:firstyear=2005&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 "llinventoryfilter.h" + +// viewer includes +#include "llfoldervieweventlistener.h" +#include "llfolderview.h" +#include "llinventorymodel.h" +#include "llinventorymodelbackgroundfetch.h" +#include "llviewercontrol.h" +#include "llfolderview.h" +#include "llinventorybridge.h" +#include "llviewerfoldertype.h" +#include "llagentwearables.h" +#include "llvoavatarself.h" + +// linden library includes +#include "lltrans.h" + +LLInventoryFilter::FilterOps::FilterOps() : + mFilterTypes(0xffffffff), + mMinDate(time_min()), + mMaxDate(time_max()), + mHoursAgo(0), + mShowFolderState(SHOW_NON_EMPTY_FOLDERS), + mPermissions(PERM_NONE) {} +///---------------------------------------------------------------------------- +/// Class LLInventoryFilter +///---------------------------------------------------------------------------- +LLInventoryFilter::LLInventoryFilter(const std::string& name) +: mName(name), + mModified(FALSE), + mNeedTextRebuild(TRUE) +{ + mOrder = SO_FOLDERS_BY_NAME; // This gets overridden by a pref immediately + + mSubStringMatchOffset = 0; + mFilterSubString.clear(); + mFilterWorn = false; + mFilterGeneration = 0; + mMustPassGeneration = S32_MAX; + mMinRequiredGeneration = 0; + mFilterCount = 0; + mNextFilterGeneration = mFilterGeneration + 1; + + mLastLogoff = gSavedPerAccountSettings.getU32("LastLogoff"); + mFilterBehavior = FILTER_NONE; + + // copy mFilterOps into mDefaultFilterOps + markDefault(); +} + +LLInventoryFilter::~LLInventoryFilter() +{ +} + +BOOL LLInventoryFilter::check(LLFolderViewItem* item) +{ + LLFolderViewEventListener* listener = item->getListener(); + const LLUUID& item_id = listener->getUUID(); + const LLInventoryObject *obj = gInventory.getObject(item_id); + if (isActive() && obj && obj->getIsLinkType()) + { + // When filtering is active, omit links. + return FALSE; + } + + time_t earliest; + + earliest = time_corrected() - mFilterOps.mHoursAgo * 3600; + if (mFilterOps.mMinDate > time_min() && mFilterOps.mMinDate < earliest) + { + earliest = mFilterOps.mMinDate; + } + else if (!mFilterOps.mHoursAgo) + { + earliest = 0; + } + mSubStringMatchOffset = mFilterSubString.size() ? item->getSearchableLabel().find(mFilterSubString) : std::string::npos; + BOOL passed = (0x1 << listener->getInventoryType() & mFilterOps.mFilterTypes || listener->getInventoryType() == LLInventoryType::IT_NONE) + && (mFilterSubString.size() == 0 || mSubStringMatchOffset != std::string::npos) + && (mFilterWorn == false || gAgentWearables.isWearingItem(item_id) || + (gAgentAvatarp && gAgentAvatarp->isWearingAttachment(item_id))) + && ((listener->getPermissionMask() & mFilterOps.mPermissions) == mFilterOps.mPermissions) + && (listener->getCreationDate() >= earliest && listener->getCreationDate() <= mFilterOps.mMaxDate); + return passed; +} + +const std::string& LLInventoryFilter::getFilterSubString(BOOL trim) const +{ + return mFilterSubString; +} + +std::string::size_type LLInventoryFilter::getStringMatchOffset() const +{ + return mSubStringMatchOffset; +} + +// has user modified default filter params? +BOOL LLInventoryFilter::isNotDefault() const +{ + return mFilterOps.mFilterTypes != mDefaultFilterOps.mFilterTypes + || mFilterSubString.size() + || mFilterWorn + || mFilterOps.mPermissions != mDefaultFilterOps.mPermissions + || mFilterOps.mMinDate != mDefaultFilterOps.mMinDate + || mFilterOps.mMaxDate != mDefaultFilterOps.mMaxDate + || mFilterOps.mHoursAgo != mDefaultFilterOps.mHoursAgo; +} + +BOOL LLInventoryFilter::isActive() const +{ + return mFilterOps.mFilterTypes != 0xffffffff + || mFilterSubString.size() + || mFilterWorn + || mFilterOps.mPermissions != PERM_NONE + || mFilterOps.mMinDate != time_min() + || mFilterOps.mMaxDate != time_max() + || mFilterOps.mHoursAgo != 0; +} + +BOOL LLInventoryFilter::isModified() const +{ + return mModified; +} + +BOOL LLInventoryFilter::isModifiedAndClear() +{ + BOOL ret = mModified; + mModified = FALSE; + return ret; +} + +void LLInventoryFilter::setFilterTypes(U32 types) +{ + if (mFilterOps.mFilterTypes != types) + { + // keep current items only if no type bits getting turned off + BOOL fewer_bits_set = (mFilterOps.mFilterTypes & ~types); + BOOL more_bits_set = (~mFilterOps.mFilterTypes & types); + + mFilterOps.mFilterTypes = types; + if (more_bits_set && fewer_bits_set) + { + // neither less or more restrive, both simultaneously + // so we need to filter from scratch + setModified(FILTER_RESTART); + } + else if (more_bits_set) + { + // target is only one of all requested types so more type bits == less restrictive + setModified(FILTER_LESS_RESTRICTIVE); + } + else if (fewer_bits_set) + { + setModified(FILTER_MORE_RESTRICTIVE); + } + + } +} + +void LLInventoryFilter::setFilterSubString(const std::string& 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() >= 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() < filter_sub_string_new.size() + && !filter_sub_string_new.substr(0, mFilterSubString.size()).compare(mFilterSubString); + + mFilterSubString = filter_sub_string_new; + if (less_restrictive) + { + setModified(FILTER_LESS_RESTRICTIVE); + } + else if (more_restrictive) + { + setModified(FILTER_MORE_RESTRICTIVE); + } + else + { + setModified(FILTER_RESTART); + } + } +} + +void LLInventoryFilter::setFilterPermissions(PermissionMask perms) +{ + if (mFilterOps.mPermissions != perms) + { + // keep current items only if no perm bits getting turned off + BOOL fewer_bits_set = (mFilterOps.mPermissions & ~perms); + BOOL more_bits_set = (~mFilterOps.mPermissions & perms); + mFilterOps.mPermissions = perms; + + if (more_bits_set && fewer_bits_set) + { + setModified(FILTER_RESTART); + } + else if (more_bits_set) + { + // target must have all requested permission bits, so more bits == more restrictive + setModified(FILTER_MORE_RESTRICTIVE); + } + else if (fewer_bits_set) + { + setModified(FILTER_LESS_RESTRICTIVE); + } + } +} + +void LLInventoryFilter::setDateRange(time_t min_date, time_t max_date) +{ + mFilterOps.mHoursAgo = 0; + if (mFilterOps.mMinDate != min_date) + { + mFilterOps.mMinDate = min_date; + setModified(); + } + if (mFilterOps.mMaxDate != llmax(mFilterOps.mMinDate, max_date)) + { + mFilterOps.mMaxDate = llmax(mFilterOps.mMinDate, max_date); + setModified(); + } +} + +void LLInventoryFilter::setDateRangeLastLogoff(BOOL sl) +{ + if (sl && !isSinceLogoff()) + { + setDateRange(mLastLogoff, time_max()); + setModified(); + } + if (!sl && isSinceLogoff()) + { + setDateRange(0, time_max()); + setModified(); + } +} + +BOOL LLInventoryFilter::isSinceLogoff() const +{ + return (mFilterOps.mMinDate == (time_t)mLastLogoff) && + (mFilterOps.mMaxDate == time_max()); +} + +void LLInventoryFilter::clearModified() +{ + mModified = FALSE; + mFilterBehavior = FILTER_NONE; +} + +void LLInventoryFilter::setHoursAgo(U32 hours) +{ + if (mFilterOps.mHoursAgo != hours) + { + bool are_date_limits_valid = mFilterOps.mMinDate == time_min() && mFilterOps.mMaxDate == time_max(); + + bool is_increasing = hours > mFilterOps.mHoursAgo; + bool is_increasing_from_zero = is_increasing && !mFilterOps.mHoursAgo; + + // *NOTE: need to cache last filter time, in case filter goes stale + BOOL less_restrictive = (are_date_limits_valid && ((is_increasing && mFilterOps.mHoursAgo)) || !hours); + BOOL more_restrictive = (are_date_limits_valid && (!is_increasing && hours) || is_increasing_from_zero); + + mFilterOps.mHoursAgo = hours; + mFilterOps.mMinDate = time_min(); + mFilterOps.mMaxDate = time_max(); + if (less_restrictive) + { + setModified(FILTER_LESS_RESTRICTIVE); + } + else if (more_restrictive) + { + setModified(FILTER_MORE_RESTRICTIVE); + } + else + { + setModified(FILTER_RESTART); + } + } +} +void LLInventoryFilter::setShowFolderState(EFolderShow state) +{ + if (mFilterOps.mShowFolderState != state) + { + mFilterOps.mShowFolderState = state; + if (state == SHOW_NON_EMPTY_FOLDERS) + { + // showing fewer folders than before + setModified(FILTER_MORE_RESTRICTIVE); + } + else if (state == SHOW_ALL_FOLDERS) + { + // showing same folders as before and then some + setModified(FILTER_LESS_RESTRICTIVE); + } + else + { + setModified(); + } + } +} + +void LLInventoryFilter::setSortOrder(U32 order) +{ + if (mOrder != order) + { + mOrder = order; + setModified(); + } +} + +void LLInventoryFilter::markDefault() +{ + mDefaultFilterOps = mFilterOps; +} + +void LLInventoryFilter::resetDefault() +{ + mFilterOps = mDefaultFilterOps; + setModified(); +} + +void LLInventoryFilter::setModified(EFilterBehavior behavior) +{ + mModified = TRUE; + mNeedTextRebuild = TRUE; + mFilterGeneration = mNextFilterGeneration++; + + if (mFilterBehavior == FILTER_NONE) + { + mFilterBehavior = behavior; + } + else if (mFilterBehavior != behavior) + { + // trying to do both less restrictive and more restrictive filter + // basically means restart from scratch + mFilterBehavior = FILTER_RESTART; + } + + if (isNotDefault()) + { + // if not keeping current filter results, update last valid as well + switch(mFilterBehavior) + { + case FILTER_RESTART: + mMustPassGeneration = mFilterGeneration; + mMinRequiredGeneration = mFilterGeneration; + break; + case FILTER_LESS_RESTRICTIVE: + mMustPassGeneration = mFilterGeneration; + break; + case FILTER_MORE_RESTRICTIVE: + mMinRequiredGeneration = mFilterGeneration; + // must have passed either current filter generation (meaningless, as it hasn't been run yet) + // or some older generation, so keep the value + mMustPassGeneration = llmin(mMustPassGeneration, mFilterGeneration); + break; + default: + llerrs << "Bad filter behavior specified" << llendl; + } + } + else + { + // shortcut disabled filters to show everything immediately + mMinRequiredGeneration = 0; + mMustPassGeneration = S32_MAX; + } +} + +BOOL LLInventoryFilter::isFilterWith(LLInventoryType::EType t) const +{ + return mFilterOps.mFilterTypes & (0x01 << t); +} + +const std::string& LLInventoryFilter::getFilterText() +{ + if (!mNeedTextRebuild) + { + return mFilterText; + } + + mNeedTextRebuild = FALSE; + std::string filtered_types; + std::string not_filtered_types; + BOOL filtered_by_type = FALSE; + BOOL filtered_by_all_types = TRUE; + S32 num_filter_types = 0; + mFilterText.clear(); + + if (isFilterWith(LLInventoryType::IT_ANIMATION)) + { + filtered_types += " Animations,"; + filtered_by_type = TRUE; + num_filter_types++; + } + else + { + not_filtered_types += " Animations,"; + filtered_by_all_types = FALSE; + } + + if (isFilterWith(LLInventoryType::IT_CALLINGCARD)) + { + filtered_types += " Calling Cards,"; + filtered_by_type = TRUE; + num_filter_types++; + } + else + { + not_filtered_types += " Calling Cards,"; + filtered_by_all_types = FALSE; + } + + if (isFilterWith(LLInventoryType::IT_WEARABLE)) + { + filtered_types += " Clothing,"; + filtered_by_type = TRUE; + num_filter_types++; + } + else + { + not_filtered_types += " Clothing,"; + filtered_by_all_types = FALSE; + } + + if (isFilterWith(LLInventoryType::IT_GESTURE)) + { + filtered_types += " Gestures,"; + filtered_by_type = TRUE; + num_filter_types++; + } + else + { + not_filtered_types += " Gestures,"; + filtered_by_all_types = FALSE; + } + + if (isFilterWith(LLInventoryType::IT_LANDMARK)) + { + filtered_types += " Landmarks,"; + filtered_by_type = TRUE; + num_filter_types++; + } + else + { + not_filtered_types += " Landmarks,"; + filtered_by_all_types = FALSE; + } + + if (isFilterWith(LLInventoryType::IT_NOTECARD)) + { + filtered_types += " Notecards,"; + filtered_by_type = TRUE; + num_filter_types++; + } + else + { + not_filtered_types += " Notecards,"; + filtered_by_all_types = FALSE; + } + + if (isFilterWith(LLInventoryType::IT_OBJECT) && isFilterWith(LLInventoryType::IT_ATTACHMENT)) + { + filtered_types += " Objects,"; + filtered_by_type = TRUE; + num_filter_types++; + } + else + { + not_filtered_types += " Objects,"; + filtered_by_all_types = FALSE; + } + + if (isFilterWith(LLInventoryType::IT_LSL)) + { + filtered_types += " Scripts,"; + filtered_by_type = TRUE; + num_filter_types++; + } + else + { + not_filtered_types += " Scripts,"; + filtered_by_all_types = FALSE; + } + + if (isFilterWith(LLInventoryType::IT_SOUND)) + { + filtered_types += " Sounds,"; + filtered_by_type = TRUE; + num_filter_types++; + } + else + { + not_filtered_types += " Sounds,"; + filtered_by_all_types = FALSE; + } + + if (isFilterWith(LLInventoryType::IT_TEXTURE)) + { + filtered_types += " Textures,"; + filtered_by_type = TRUE; + num_filter_types++; + } + else + { + not_filtered_types += " Textures,"; + filtered_by_all_types = FALSE; + } + + if (isFilterWith(LLInventoryType::IT_SNAPSHOT)) + { + filtered_types += " Snapshots,"; + filtered_by_type = TRUE; + num_filter_types++; + } + else + { + not_filtered_types += " Snapshots,"; + filtered_by_all_types = FALSE; + } + + if (!LLInventoryModelBackgroundFetch::instance().backgroundFetchActive() + && filtered_by_type + && !filtered_by_all_types) + { + mFilterText += " - "; + if (num_filter_types < 5) + { + mFilterText += filtered_types; + } + else + { + mFilterText += "No "; + mFilterText += not_filtered_types; + } + // remove the ',' at the end + mFilterText.erase(mFilterText.size() - 1, 1); + } + + if (isSinceLogoff()) + { + mFilterText += " - Since Logoff"; + } + + if (getFilterWorn()) + { + mFilterText += " - Worn"; + } + + return mFilterText; +} + +void LLInventoryFilter::toLLSD(LLSD& data) const +{ + data["filter_types"] = (LLSD::Integer)getFilterTypes(); + data["min_date"] = (LLSD::Integer)getMinDate(); + data["max_date"] = (LLSD::Integer)getMaxDate(); + data["hours_ago"] = (LLSD::Integer)getHoursAgo(); + data["show_folder_state"] = (LLSD::Integer)getShowFolderState(); + data["permissions"] = (LLSD::Integer)getFilterPermissions(); + data["substring"] = (LLSD::String)getFilterSubString(); + data["sort_order"] = (LLSD::Integer)getSortOrder(); + data["since_logoff"] = (LLSD::Boolean)isSinceLogoff(); +} + +void LLInventoryFilter::fromLLSD(LLSD& data) +{ + if(data.has("filter_types")) + { + setFilterTypes((U32)data["filter_types"].asInteger()); + } + + if(data.has("min_date") && data.has("max_date")) + { + setDateRange(data["min_date"].asInteger(), data["max_date"].asInteger()); + } + + if(data.has("hours_ago")) + { + setHoursAgo((U32)data["hours_ago"].asInteger()); + } + + if(data.has("show_folder_state")) + { + setShowFolderState((EFolderShow)data["show_folder_state"].asInteger()); + } + + if(data.has("permissions")) + { + setFilterPermissions((PermissionMask)data["permissions"].asInteger()); + } + + if(data.has("substring")) + { + setFilterSubString(std::string(data["substring"].asString())); + } + + if(data.has("sort_order")) + { + setSortOrder((U32)data["sort_order"].asInteger()); + } + + if(data.has("since_logoff")) + { + setDateRangeLastLogoff((bool)data["since_logoff"].asBoolean()); + } +} + +BOOL LLInventoryFilter::hasFilterString() const +{ + return mFilterSubString.size() > 0; +} + +PermissionMask LLInventoryFilter::getFilterPermissions() const +{ + return mFilterOps.mPermissions; +} + +time_t LLInventoryFilter::getMinDate() const +{ + return mFilterOps.mMinDate; +} + +time_t LLInventoryFilter::getMaxDate() const +{ + return mFilterOps.mMaxDate; +} +U32 LLInventoryFilter::getHoursAgo() const +{ + return mFilterOps.mHoursAgo; +} +LLInventoryFilter::EFolderShow LLInventoryFilter::getShowFolderState() const +{ + return mFilterOps.mShowFolderState; +} +U32 LLInventoryFilter::getSortOrder() const +{ + return mOrder; +} +const std::string& LLInventoryFilter::getName() const +{ + return mName; +} + +void LLInventoryFilter::setFilterCount(S32 count) +{ + mFilterCount = count; +} +S32 LLInventoryFilter::getFilterCount() const +{ + return mFilterCount; +} + +void LLInventoryFilter::decrementFilterCount() +{ + mFilterCount--; +} + +S32 LLInventoryFilter::getCurrentGeneration() const +{ + return mFilterGeneration; +} +S32 LLInventoryFilter::getMinRequiredGeneration() const +{ + return mMinRequiredGeneration; +} +S32 LLInventoryFilter::getMustPassGeneration() const +{ + return mMustPassGeneration; +} diff --git a/indra/newview/llinventoryfilter.h b/indra/newview/llinventoryfilter.h new file mode 100644 index 000000000..2d6ef39e1 --- /dev/null +++ b/indra/newview/llinventoryfilter.h @@ -0,0 +1,183 @@ +/** +* @file llinventoryfilter.h +* @brief Support for filtering your inventory to only display a subset of the +* available items. +* +* $LicenseInfo:firstyear=2005&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 LLINVENTORYFILTER_H +#define LLINVENTORYFILTER_H + +#include "llinventorytype.h" +#include "llpermissionsflags.h" + +class LLFolderViewItem; +class LLFolderViewFolder; + +class LLInventoryFilter +{ +public: + enum EFolderShow + { + SHOW_ALL_FOLDERS, + SHOW_NON_EMPTY_FOLDERS, + SHOW_NO_FOLDERS + }; + + enum EFilterBehavior + { + FILTER_NONE, // nothing to do, already filtered + FILTER_RESTART, // restart filtering from scratch + FILTER_LESS_RESTRICTIVE, // existing filtered items will certainly pass this filter + FILTER_MORE_RESTRICTIVE // if you didn't pass the previous filter, you definitely won't pass this one + }; + + enum ESortOrderType + { + SO_DATE = 0x1, // Sort inventory by date + SO_FOLDERS_BY_NAME = 0x1 << 1, // Force folder sort by name + SO_SYSTEM_FOLDERS_TO_TOP = 0x1 << 2 // Force system folders to be on top + }; + + LLInventoryFilter(const std::string& name); + virtual ~LLInventoryFilter(); + + void setFilterTypes(U32 types); + BOOL isFilterWith(LLInventoryType::EType t) const; + U32 getFilterTypes() const { return mFilterOps.mFilterTypes; } + + void setFilterSubString(const std::string& string); + const std::string& getFilterSubString(BOOL trim = FALSE) const; + const std::string& getFilterSubStringOrig() const { return mFilterSubStringOrig; } + BOOL hasFilterString() const; + + void setFilterWorn(bool worn) { mFilterWorn = worn; } + bool getFilterWorn() const { return mFilterWorn; } + + void setFilterPermissions(PermissionMask perms); + PermissionMask getFilterPermissions() const; + + void setDateRange(time_t min_date, time_t max_date); + void setDateRangeLastLogoff(BOOL sl); + time_t getMinDate() const; + time_t getMaxDate() const; + + void setHoursAgo(U32 hours); + U32 getHoursAgo() const; + + // +-------------------------------------------------------------------+ + // + Execution And Results + // +-------------------------------------------------------------------+ + BOOL check(LLFolderViewItem* item); + std::string::size_type getStringMatchOffset() const; + + // +-------------------------------------------------------------------+ + // + Presentation + // +-------------------------------------------------------------------+ + void setShowFolderState( EFolderShow state); + EFolderShow getShowFolderState() const; + + void setSortOrder(U32 order); + U32 getSortOrder() const; + + + + // +-------------------------------------------------------------------+ + // + Status + // +-------------------------------------------------------------------+ + BOOL isActive() const; + + BOOL isModified() const; + BOOL isModifiedAndClear(); + BOOL isSinceLogoff() const; + void clearModified(); + const std::string& getName() const; + const std::string& getFilterText(); + //RN: this is public to allow system to externally force a global refilter + void setModified(EFilterBehavior behavior = FILTER_RESTART); + + // +-------------------------------------------------------------------+ + // + Count + // +-------------------------------------------------------------------+ + void setFilterCount(S32 count); + S32 getFilterCount() const; + void decrementFilterCount(); + + // +-------------------------------------------------------------------+ + // + Default + // +-------------------------------------------------------------------+ + BOOL isNotDefault() const; + void markDefault(); + void resetDefault(); + + // +-------------------------------------------------------------------+ + // + Generation + // +-------------------------------------------------------------------+ + S32 getCurrentGeneration() const; + S32 getMinRequiredGeneration() const; + S32 getMustPassGeneration() const; + + + + + void toLLSD(LLSD& data) const; + void fromLLSD(LLSD& data); + +private: + struct FilterOps + { + FilterOps(); + U32 mFilterTypes; + time_t mMinDate; + time_t mMaxDate; + U32 mHoursAgo; + EFolderShow mShowFolderState; + PermissionMask mPermissions; + }; + + U32 mOrder; + U32 mLastLogoff; + + FilterOps mFilterOps; + FilterOps mDefaultFilterOps; + + std::string::size_type mSubStringMatchOffset; + std::string mFilterSubString; + std::string mFilterSubStringOrig; + bool mFilterWorn; + + const std::string mName; + S32 mFilterGeneration; + S32 mMustPassGeneration; + S32 mMinRequiredGeneration; + S32 mNextFilterGeneration; + + S32 mFilterCount; + EFilterBehavior mFilterBehavior; + + BOOL mModified; + BOOL mNeedTextRebuild; + std::string mFilterText; +}; + + +#endif diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 5745b5704..5b4dab172 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -78,22 +78,6 @@ #include "process.h" #endif -const F32 MAX_TIME_FOR_SINGLE_FETCH = 10.f; -const S32 MAX_FETCH_RETRIES = 10; -BOOL LLInventoryModel::sBackgroundFetchActive = FALSE; -BOOL LLInventoryModel::sAllFoldersFetched = FALSE; -BOOL LLInventoryModel::sFullFetchStarted = FALSE; -S32 LLInventoryModel::sNumFetchRetries = 0; -F32 LLInventoryModel::sMinTimeBetweenFetches = 0.3f; -F32 LLInventoryModel::sMaxTimeBetweenFetches = 10.f; -BOOL LLInventoryModel::sTimelyFetchPending = FALSE; -LLFrameTimer LLInventoryModel::sFetchTimer; -S16 LLInventoryModel::sBulkFetchCount = 0; - -// RN: for some reason, using std::queue in the header file confuses the compiler which things it's an xmlrpc_queue -static std::deque sFetchQueue; - - // Increment this if the inventory contents change in a non-backwards-compatible way. // For viewers with link items support, former caches are incorrect. const S32 LLInventoryModel::sCurrentInvCacheVersion = 2; @@ -1381,524 +1365,7 @@ bool LLInventoryModel::fetchDescendentsOf(const LLUUID& folder_id) const //{ // known_descendents += items->count(); //} - return cat->fetchDescendents(); -} - -//Initialize statics. -bool LLInventoryModel::isBulkFetchProcessingComplete() -{ - return ( (sFetchQueue.empty() - && sBulkFetchCount<=0) ? TRUE : FALSE ) ; -} - -class fetchDescendentsResponder: public LLHTTPClient::Responder -{ - public: - fetchDescendentsResponder(const LLSD& request_sd) : mRequestSD(request_sd) {}; - //fetchDescendentsResponder() {}; - void result(const LLSD& content); - void error(U32 status, const std::string& reason); - public: - typedef std::vector folder_ref_t; - protected: - LLSD mRequestSD; -}; - -//If we get back a normal response, handle it here -// Note: this is the handler for WebFetchInventoryDescendents and agent/inventory caps -void fetchDescendentsResponder::result(const LLSD& content) -{ - if (content.has("folders")) - { - - for(LLSD::array_const_iterator folder_it = content["folders"].beginArray(); - folder_it != content["folders"].endArray(); - ++folder_it) - { - LLSD folder_sd = *folder_it; - - - //LLUUID agent_id = folder_sd["agent_id"]; - - //if(agent_id != gAgent.getID()) //This should never happen. - //{ - // llwarns << "Got a UpdateInventoryItem for the wrong agent." - // << llendl; - // break; - //} - - LLUUID parent_id = folder_sd["folder_id"]; - LLUUID owner_id = folder_sd["owner_id"]; - S32 version = (S32)folder_sd["version"].asInteger(); - S32 descendents = (S32)folder_sd["descendents"].asInteger(); - LLPointer tcategory = new LLViewerInventoryCategory(owner_id); - - if (parent_id.isNull()) - { - LLPointer titem = new LLViewerInventoryItem; - for(LLSD::array_const_iterator item_it = folder_sd["items"].beginArray(); - item_it != folder_sd["items"].endArray(); - ++item_it) - { - LLUUID lost_uuid = gInventory.findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND); - if (lost_uuid.notNull()) - { - LLSD item = *item_it; - titem->unpackMessage(item); - - LLInventoryModel::update_list_t update; - LLInventoryModel::LLCategoryUpdate new_folder(lost_uuid, 1); - update.push_back(new_folder); - gInventory.accountForUpdate(update); - - titem->setParent(lost_uuid); - titem->updateParentOnServer(FALSE); - gInventory.updateItem(titem); - gInventory.notifyObservers(); - - } - } - } - - LLViewerInventoryCategory* pcat = gInventory.getCategory(parent_id); - if (!pcat) - { - continue; - } - - for(LLSD::array_const_iterator category_it = folder_sd["categories"].beginArray(); - category_it != folder_sd["categories"].endArray(); - ++category_it) - { - LLSD category = *category_it; - tcategory->fromLLSD(category); - - if (LLInventoryModel::sFullFetchStarted) - { - sFetchQueue.push_back(tcategory->getUUID()); - } - else if ( !gInventory.isCategoryComplete(tcategory->getUUID()) ) - { - gInventory.updateCategory(tcategory); - } - - } - LLPointer titem = new LLViewerInventoryItem; - for(LLSD::array_const_iterator item_it = folder_sd["items"].beginArray(); - item_it != folder_sd["items"].endArray(); - ++item_it) - { - LLSD item = *item_it; - titem->unpackMessage(item); - - gInventory.updateItem(titem); - } - - // set version and descendentcount according to message. - LLViewerInventoryCategory* cat = gInventory.getCategory(parent_id); - if(cat) - { - cat->setVersion(version); - cat->setDescendentCount(descendents); - } - - } - } - - if (content.has("bad_folders")) - { - for(LLSD::array_const_iterator folder_it = content["bad_folders"].beginArray(); - folder_it != content["bad_folders"].endArray(); - ++folder_it) - { - LLSD folder_sd = *folder_it; - - //These folders failed on the dataserver. We probably don't want to retry them. - LL_INFOS("Inventory") << "Folder " << folder_sd["folder_id"].asString() - << "Error: " << folder_sd["error"].asString() << LL_ENDL; - } - } - - LLInventoryModel::incrBulkFetch(-1); - - if (LLInventoryModel::isBulkFetchProcessingComplete()) - { - LL_DEBUGS("Inventory") << "Inventory fetch completed" << LL_ENDL; - if (LLInventoryModel::sFullFetchStarted) - { - LLInventoryModel::sAllFoldersFetched = TRUE; - } - LLInventoryModel::stopBackgroundFetch(); - } - - gInventory.notifyObservers(); -} - -//If we get back an error (not found, etc...), handle it here -void fetchDescendentsResponder::error(U32 status, const std::string& reason) -{ - LL_INFOS("Inventory") << "fetchDescendentsResponder::error " - << status << ": " << reason << LL_ENDL; - - LLInventoryModel::incrBulkFetch(-1); - - if (status==499) //timed out. Let's be awesome! - { - for(LLSD::array_const_iterator folder_it = mRequestSD["folders"].beginArray(); - folder_it != mRequestSD["folders"].endArray(); - ++folder_it) - { - LLSD folder_sd = *folder_it; - LLUUID folder_id = folder_sd["folder_id"]; - sFetchQueue.push_front(folder_id); - } - } - else - { - if (LLInventoryModel::isBulkFetchProcessingComplete()) - { - if (LLInventoryModel::sFullFetchStarted) - { - LLInventoryModel::sAllFoldersFetched = TRUE; - } - LLInventoryModel::stopBackgroundFetch(); - } - } - gInventory.notifyObservers(); -} - -//static Bundle up a bunch of requests to send all at once. -void LLInventoryModel::bulkFetch(std::string url) -{ - //Background fetch is called from gIdleCallbacks in a loop until background fetch is stopped. - //If there are items in sFetchQueue, we want to check the time since the last bulkFetch was - //sent. If it exceeds our retry time, go ahead and fire off another batch. - //Stopbackgroundfetch will be run from the Responder instead of here. - - S16 max_concurrent_fetches=8; - F32 new_min_time = 0.5f; //HACK! Clean this up when old code goes away entirely. - if (sMinTimeBetweenFetches < new_min_time) sMinTimeBetweenFetches=new_min_time; //HACK! See above. - - if(gDisconnected - || sBulkFetchCount > max_concurrent_fetches - || sFetchTimer.getElapsedTimeF32() < sMinTimeBetweenFetches) - { - return; // just bail if we are disconnected. - } - - U32 folder_count=0; - U32 max_batch_size=5; - - U32 sort_order = gSavedSettings.getU32("InventorySortOrder") & 0x1; - - LLSD body; - LLSD body_lib; - while( !(sFetchQueue.empty() ) && (folder_count < max_batch_size) ) - { - if (sFetchQueue.front().isNull()) //DEV-17797 - { - LLSD folder_sd; - folder_sd["folder_id"] = LLUUID::null.asString(); - folder_sd["owner_id"] = gAgent.getID(); - folder_sd["sort_order"] = (LLSD::Integer)sort_order; - folder_sd["fetch_folders"] = (LLSD::Boolean)FALSE; - folder_sd["fetch_items"] = (LLSD::Boolean)TRUE; - body["folders"].append(folder_sd); - folder_count++; - } - else - { - - - LLViewerInventoryCategory* cat = gInventory.getCategory(sFetchQueue.front()); - - if (cat) - { - // Pre-emptive strike - //if(!(gInventory.isObjectDescendentOf(cat->getUUID(), gSystemFolderRoot))) - if(true) - { - // - if ( LLViewerInventoryCategory::VERSION_UNKNOWN == cat->getVersion()) - { - LLSD folder_sd; - folder_sd["folder_id"] = cat->getUUID(); - folder_sd["owner_id"] = cat->getOwnerID(); - folder_sd["sort_order"] = (LLSD::Integer)sort_order; - folder_sd["fetch_folders"] = TRUE; //(LLSD::Boolean)sFullFetchStarted; - folder_sd["fetch_items"] = (LLSD::Boolean)TRUE; - - LL_DEBUGS("Inventory") << " fetching "<getUUID()<<" with cat owner "<getOwnerID()<<" and agent" << gAgent.getID() << LL_ENDL; - if (ALEXANDRIA_LINDEN_ID == cat->getOwnerID()) - body_lib["folders"].append(folder_sd); - else - body["folders"].append(folder_sd); - folder_count++; - } - if (sFullFetchStarted) - { //Already have this folder but append child folders to list. - // add all children to queue - parent_cat_map_t::iterator cat_it = gInventory.mParentChildCategoryTree.find(cat->getUUID()); - if (cat_it != gInventory.mParentChildCategoryTree.end()) - { - cat_array_t* child_categories = cat_it->second; - - for (S32 child_num = 0; child_num < child_categories->count(); child_num++) - { - sFetchQueue.push_back(child_categories->get(child_num)->getUUID()); - } - } - - } - // - } - // - } - } - sFetchQueue.pop_front(); - } - - if (folder_count > 0) - { - sBulkFetchCount++; - if (body["folders"].size()) - { - LLHTTPClient::post(url, body, new fetchDescendentsResponder(body),300.0); - } - if (body_lib["folders"].size()) - { - std::string url_lib; - url_lib = gAgent.getRegion()->getCapability("FetchLibDescendents"); - LLHTTPClient::post(url_lib, body_lib, new fetchDescendentsResponder(body_lib),300.0); - } - sFetchTimer.reset(); - } - else if (isBulkFetchProcessingComplete()) - { - if (sFullFetchStarted) - { - sAllFoldersFetched = TRUE; - } - stopBackgroundFetch(); - } -} - -// static -bool LLInventoryModel::isEverythingFetched() -{ - return (sAllFoldersFetched ? true : false); -} - -//static -BOOL LLInventoryModel::backgroundFetchActive() -{ - return sBackgroundFetchActive; -} - -//static -void LLInventoryModel::startBackgroundFetch(const LLUUID& cat_id) -{ - if (!sAllFoldersFetched) - { - if (cat_id.isNull()) - { - if (!sFullFetchStarted) - { - sFullFetchStarted = TRUE; - sFetchQueue.push_back(gInventory.getLibraryRootFolderID()); - sFetchQueue.push_back(gInventory.getRootFolderID()); - if (!sBackgroundFetchActive) - { - sBackgroundFetchActive = TRUE; - gIdleCallbacks.addFunction(&LLInventoryModel::backgroundFetch, NULL); - } - } - } - else - { - // specific folder requests go to front of queue - // Remove it from the queue first, to avoid getting it twice. - if (!sFetchQueue.empty() && sFetchQueue.front() != cat_id) - { - std::deque::iterator old_entry = std::find(sFetchQueue.begin(), sFetchQueue.end(), cat_id); - if (old_entry != sFetchQueue.end()) - { - sFetchQueue.erase(old_entry); - } - } - sFetchQueue.push_front(cat_id); - if (!sBackgroundFetchActive) - { - sBackgroundFetchActive = TRUE; - gIdleCallbacks.addFunction(&LLInventoryModel::backgroundFetch, NULL); - } - } - } -} - -//static -void LLInventoryModel::findLostItems() -{ - sFetchQueue.push_back(LLUUID::null); - if (!sBackgroundFetchActive) - { - sBackgroundFetchActive = TRUE; - gIdleCallbacks.addFunction(&LLInventoryModel::backgroundFetch, NULL); - } -} - -//static -void LLInventoryModel::stopBackgroundFetch() -{ - if (sBackgroundFetchActive) - { - sBackgroundFetchActive = FALSE; - gIdleCallbacks.deleteFunction(&LLInventoryModel::backgroundFetch, NULL); - sBulkFetchCount=0; - sMinTimeBetweenFetches=0.0f; - if (!sAllFoldersFetched) - { - // We didn't finish this, so set it to FALSE in order to be able to start it again. - sFullFetchStarted=FALSE; - } - } -} - -//static -void LLInventoryModel::backgroundFetch(void*) -{ - if (sBackgroundFetchActive && 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("FetchInventoryDescendents"); - if (false /*gSavedSettings.getBOOL("UseHTTPInventory")*/ && !url.empty()) - { - bulkFetch(url); - return; - } - -#if 1 - //DEPRECATED OLD CODE FOLLOWS. - // no more categories to fetch, stop fetch process - if (sFetchQueue.empty()) - { - llinfos << "Inventory fetch completed" << llendl; - if (sFullFetchStarted) - { - sAllFoldersFetched = TRUE; - } - stopBackgroundFetch(); - return; - } - - F32 fast_fetch_time = lerp(sMinTimeBetweenFetches, sMaxTimeBetweenFetches, 0.1f); - F32 slow_fetch_time = lerp(sMinTimeBetweenFetches, sMaxTimeBetweenFetches, 0.5f); - if (sTimelyFetchPending && sFetchTimer.getElapsedTimeF32() > slow_fetch_time) - { - // double timeouts on failure - sMinTimeBetweenFetches = llmin(sMinTimeBetweenFetches * 2.f, 10.f); - sMaxTimeBetweenFetches = llmin(sMaxTimeBetweenFetches * 2.f, 120.f); - llinfos << "Inventory fetch times grown to (" << sMinTimeBetweenFetches << ", " << sMaxTimeBetweenFetches << ")" << llendl; - // fetch is no longer considered "timely" although we will wait for full time-out - sTimelyFetchPending = FALSE; - } - - while(1) - { - if (sFetchQueue.empty()) - { - break; - } - - if(gDisconnected) - { - // just bail if we are disconnected. - break; - } - - LLViewerInventoryCategory* cat = gInventory.getCategory(sFetchQueue.front()); - - // category has been deleted, remove from queue. - if (!cat) - { - sFetchQueue.pop_front(); - continue; - } - - if (sFetchTimer.getElapsedTimeF32() > sMinTimeBetweenFetches && - LLViewerInventoryCategory::VERSION_UNKNOWN == cat->getVersion()) - { - // category exists but has no children yet, fetch the descendants - // for now, just request every time and rely on retry timer to throttle - if (cat->fetchDescendents()) - { - sFetchTimer.reset(); - sTimelyFetchPending = TRUE; - } - else - { - // The catagory also tracks if it has expired and here it says it hasn't - // yet. Get out of here because nothing is going to happen until we - // update the timers. - break; - } - } - // do I have all my children? - else if (gInventory.isCategoryComplete(sFetchQueue.front())) - { - // finished with this category, remove from queue - sFetchQueue.pop_front(); - - // add all children to queue - parent_cat_map_t::iterator cat_it = gInventory.mParentChildCategoryTree.find(cat->getUUID()); - if (cat_it != gInventory.mParentChildCategoryTree.end()) - { - cat_array_t* child_categories = cat_it->second; - - for (S32 child_num = 0; child_num < child_categories->count(); child_num++) - { - sFetchQueue.push_back(child_categories->get(child_num)->getUUID()); - } - } - - // we received a response in less than the fast time - if (sTimelyFetchPending && sFetchTimer.getElapsedTimeF32() < fast_fetch_time) - { - // shrink timeouts based on success - sMinTimeBetweenFetches = llmax(sMinTimeBetweenFetches * 0.8f, 0.3f); - sMaxTimeBetweenFetches = llmax(sMaxTimeBetweenFetches * 0.8f, 10.f); - //llinfos << "Inventory fetch times shrunk to (" << sMinTimeBetweenFetches << ", " << sMaxTimeBetweenFetches << ")" << llendl; - } - - sTimelyFetchPending = FALSE; - continue; - } - else if (sFetchTimer.getElapsedTimeF32() > sMaxTimeBetweenFetches) - { - // received first packet, but our num descendants does not match db's num descendants - // so try again later - LLUUID fetch_id = sFetchQueue.front(); - sFetchQueue.pop_front(); - - if (sNumFetchRetries++ < MAX_FETCH_RETRIES) - { - // push on back of queue - sFetchQueue.push_back(fetch_id); - } - sTimelyFetchPending = FALSE; - sFetchTimer.reset(); - break; - } - - // not enough time has elapsed to do a new fetch - break; - } - - // - // DEPRECATED OLD CODE - //-------------------------------------------------------------------------------- -#endif - } + return cat->fetch(); } void LLInventoryModel::cache( @@ -2659,6 +2126,9 @@ void LLInventoryModel::buildParentChildMap() // The inv tree is built. mIsAgentInvUsable = true; AIEvent::trigger(AIEvent::LLInventoryModel_mIsAgentInvUsable_true); + llinfos << "Inventory initialized, notifying observers" << llendl; + addChangedMask(LLInventoryObserver::ALL, LLUUID::null); + notifyObservers(); } } llinfos << " finished buildParentChildMap " << llendl; diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h index 95983ffc8..ae4e9451c 100644 --- a/indra/newview/llinventorymodel.h +++ b/indra/newview/llinventorymodel.h @@ -353,8 +353,6 @@ public: //void mock(const LLUUID& root_id); - // Add categories to a list to be fetched in bulk. - static void bulkFetch(std::string url); // call this method to request the inventory. //void requestFromServer(const LLUUID& agent_id); @@ -368,10 +366,10 @@ public: // name based on type, pass in a NULL to the 'name' parameter. LLUUID createNewCategory(const LLUUID& parent_id, LLFolderType::EType preferred_type, - const std::string& namevoid, + const std::string& name, void (*callback)(const LLSD&, void*) = NULL, void* user_data = NULL); - +public: // Internal methods that add inventory and make sure that all of // the internal data structures are consistent. These methods // should be passed pointers of newly created objects, and the @@ -384,6 +382,7 @@ public: typedef std::map response_t; typedef std::vector options_t; + //OGPX really screwed with the login process. This is needed until it's all sorted out. bool loadSkeleton(const options_t& options, const LLUUID& owner_id); /** Mutators @@ -477,14 +476,6 @@ private: typedef std::set observer_list_t; observer_list_t mObservers; -public: - // this gets triggered when performing a filter-search - static void startBackgroundFetch(const LLUUID& cat_id = LLUUID::null); // start fetch process - static void findLostItems(); - static BOOL backgroundFetchActive(); - static bool isEverythingFetched(); - static void backgroundFetch(void*); // background fetch idle function - static void incrBulkFetch(S16 fetching) { sBulkFetchCount+=fetching; if (sBulkFetchCount<0) sBulkFetchCount=0; } /** Notifications ** ** *******************************************************************************/ @@ -551,25 +542,11 @@ private: std::map mCategoryLock; std::map mItemLock; - // completing the fetch once per session should be sufficient - static BOOL sBackgroundFetchActive; - static BOOL sTimelyFetchPending; - static S32 sNumFetchRetries; - static LLFrameTimer sFetchTimer; - static F32 sMinTimeBetweenFetches; - static F32 sMaxTimeBetweenFetches; - static S16 sBulkFetchCount; public: // *NOTE: DEBUG functionality void dumpInventory() const; - static bool isBulkFetchProcessingComplete(); - static void stopBackgroundFetch(); // stop fetch process - - static BOOL sFullFetchStarted; - static BOOL sAllFoldersFetched; - /** Miscellaneous ** ** *******************************************************************************/ diff --git a/indra/newview/llinventorymodelbackgroundfetch.cpp b/indra/newview/llinventorymodelbackgroundfetch.cpp new file mode 100644 index 000000000..5c67d5017 --- /dev/null +++ b/indra/newview/llinventorymodelbackgroundfetch.cpp @@ -0,0 +1,632 @@ +/** + * @file llinventorymodel.cpp + * @brief Implementation of the inventory model used to track agent inventory. + * + * $LicenseInfo:firstyear=2002&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 "llinventorymodelbackgroundfetch.h" + +#include "llagent.h" +#include "llappviewer.h" +#include "llcallbacklist.h" +#include "llinventoryview.h" +#include "llinventorymodel.h" +#include "llviewercontrol.h" +#include "llviewerinventory.h" +#include "llviewermessage.h" +#include "llviewerregion.h" +#include "llviewerwindow.h" + +const F32 MAX_TIME_FOR_SINGLE_FETCH = 10.f; +const S32 MAX_FETCH_RETRIES = 10; + +LLInventoryModelBackgroundFetch::LLInventoryModelBackgroundFetch() : + mBackgroundFetchActive(FALSE), + mAllFoldersFetched(FALSE), + mRecursiveInventoryFetchStarted(FALSE), + mRecursiveLibraryFetchStarted(FALSE), + mNumFetchRetries(0), + mMinTimeBetweenFetches(0.3f), + mMaxTimeBetweenFetches(10.f), + mTimelyFetchPending(FALSE), + mBulkFetchCount(0) +{ +} + +LLInventoryModelBackgroundFetch::~LLInventoryModelBackgroundFetch() +{ +} + +bool LLInventoryModelBackgroundFetch::isBulkFetchProcessingComplete() const +{ + return mFetchQueue.empty() && mBulkFetchCount<=0; +} + +bool LLInventoryModelBackgroundFetch::libraryFetchStarted() const +{ + return mRecursiveLibraryFetchStarted; +} + +bool LLInventoryModelBackgroundFetch::libraryFetchCompleted() const +{ + return libraryFetchStarted() && fetchQueueContainsNoDescendentsOf(gInventory.getLibraryRootFolderID()); +} + +bool LLInventoryModelBackgroundFetch::libraryFetchInProgress() const +{ + return libraryFetchStarted() && !libraryFetchCompleted(); +} + +bool LLInventoryModelBackgroundFetch::inventoryFetchStarted() const +{ + return mRecursiveInventoryFetchStarted; +} + +bool LLInventoryModelBackgroundFetch::inventoryFetchCompleted() const +{ + return inventoryFetchStarted() && fetchQueueContainsNoDescendentsOf(gInventory.getRootFolderID()); +} + +bool LLInventoryModelBackgroundFetch::inventoryFetchInProgress() const +{ + return inventoryFetchStarted() && !inventoryFetchCompleted(); +} + +bool LLInventoryModelBackgroundFetch::isEverythingFetched() const +{ + return mAllFoldersFetched; +} + +BOOL LLInventoryModelBackgroundFetch::backgroundFetchActive() const +{ + return mBackgroundFetchActive; +} + +void LLInventoryModelBackgroundFetch::start(const LLUUID& cat_id, BOOL recursive) +{ + if (!mAllFoldersFetched || cat_id.notNull()) + { + LL_DEBUGS("InventoryFetch") << "Start fetching category: " << cat_id << ", recursive: " << recursive << LL_ENDL; + + mBackgroundFetchActive = TRUE; + if (cat_id.isNull()) + { + if (!mRecursiveInventoryFetchStarted) + { + mRecursiveInventoryFetchStarted |= recursive; + mFetchQueue.push_back(FetchQueueInfo(gInventory.getRootFolderID(), recursive)); + gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL); + } + if (!mRecursiveLibraryFetchStarted) + { + mRecursiveLibraryFetchStarted |= recursive; + mFetchQueue.push_back(FetchQueueInfo(gInventory.getLibraryRootFolderID(), recursive)); + gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL); + } + } + else + { + // Specific folder requests go to front of queue. + if (mFetchQueue.empty() || mFetchQueue.front().mCatUUID != cat_id) + { + mFetchQueue.push_front(FetchQueueInfo(cat_id, recursive)); + gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL); + } + if (cat_id == gInventory.getLibraryRootFolderID()) + { + mRecursiveLibraryFetchStarted |= recursive; + } + if (cat_id == gInventory.getRootFolderID()) + { + mRecursiveInventoryFetchStarted |= recursive; + } + } + } +} + +//static +void LLInventoryModelBackgroundFetch::findLostItems() +{ + mBackgroundFetchActive = TRUE; + mFetchQueue.push_back(FetchQueueInfo(LLUUID::null, TRUE)); + gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL); +} + +void LLInventoryModelBackgroundFetch::stopBackgroundFetch() +{ + if (mBackgroundFetchActive) + { + mBackgroundFetchActive = FALSE; + gIdleCallbacks.deleteFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL); + mBulkFetchCount=0; + mMinTimeBetweenFetches=0.0f; + } +} + +void LLInventoryModelBackgroundFetch::setAllFoldersFetched() +{ + if (mRecursiveInventoryFetchStarted && + mRecursiveLibraryFetchStarted) + { + mAllFoldersFetched = TRUE; + } + stopBackgroundFetch(); +} + +void LLInventoryModelBackgroundFetch::backgroundFetchCB(void *) +{ + LLInventoryModelBackgroundFetch::instance().backgroundFetch(); +} + +//static +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("FetchInventoryDescendents2"); + if (gSavedSettings.getBOOL("UseHTTPInventory") && !url.empty()) + { + bulkFetch(url); + return; + } + +#if 1 + //-------------------------------------------------------------------------------- + // DEPRECATED OLD CODE + // + + // No more categories to fetch, stop fetch process. + if (mFetchQueue.empty()) + { + llinfos << "Inventory fetch completed" << llendl; + + setAllFoldersFetched(); + return; + } + + F32 fast_fetch_time = lerp(mMinTimeBetweenFetches, mMaxTimeBetweenFetches, 0.1f); + F32 slow_fetch_time = lerp(mMinTimeBetweenFetches, mMaxTimeBetweenFetches, 0.5f); + if (mTimelyFetchPending && mFetchTimer.getElapsedTimeF32() > slow_fetch_time) + { + // double timeouts on failure + mMinTimeBetweenFetches = llmin(mMinTimeBetweenFetches * 2.f, 10.f); + mMaxTimeBetweenFetches = llmin(mMaxTimeBetweenFetches * 2.f, 120.f); + lldebugs << "Inventory fetch times grown to (" << mMinTimeBetweenFetches << ", " << mMaxTimeBetweenFetches << ")" << llendl; + // fetch is no longer considered "timely" although we will wait for full time-out. + mTimelyFetchPending = FALSE; + } + + while(1) + { + if (mFetchQueue.empty()) + { + break; + } + + if(gDisconnected) + { + // just bail if we are disconnected. + break; + } + + const FetchQueueInfo info = mFetchQueue.front(); + LLViewerInventoryCategory* cat = gInventory.getCategory(info.mCatUUID); + + // category has been deleted, remove from queue. + if (!cat) + { + mFetchQueue.pop_front(); + continue; + } + + if (mFetchTimer.getElapsedTimeF32() > mMinTimeBetweenFetches && + LLViewerInventoryCategory::VERSION_UNKNOWN == cat->getVersion()) + { + // category exists but has no children yet, fetch the descendants + // for now, just request every time and rely on retry timer to throttle + if (cat->fetch()) + { + mFetchTimer.reset(); + mTimelyFetchPending = TRUE; + } + else + { + // The catagory also tracks if it has expired and here it says it hasn't + // yet. Get out of here because nothing is going to happen until we + // update the timers. + break; + } + } + // do I have all my children? + else if (gInventory.isCategoryComplete(info.mCatUUID)) + { + // finished with this category, remove from queue + mFetchQueue.pop_front(); + + // Add all children to queue. + LLInventoryModel::cat_array_t* categories; + gInventory.getDirectDescendentsOf(cat->getUUID(), categories); + for (LLInventoryModel::cat_array_t::const_iterator it = categories->begin(); + it != categories->end(); + ++it) + { + mFetchQueue.push_back(FetchQueueInfo((*it)->getUUID(),info.mRecursive)); + } + + // we received a response in less than the fast time + if (mTimelyFetchPending && mFetchTimer.getElapsedTimeF32() < fast_fetch_time) + { + // shrink timeouts based on success + mMinTimeBetweenFetches = llmax(mMinTimeBetweenFetches * 0.8f, 0.3f); + mMaxTimeBetweenFetches = llmax(mMaxTimeBetweenFetches * 0.8f, 10.f); + lldebugs << "Inventory fetch times shrunk to (" << mMinTimeBetweenFetches << ", " << mMaxTimeBetweenFetches << ")" << llendl; + } + + mTimelyFetchPending = FALSE; + continue; + } + else if (mFetchTimer.getElapsedTimeF32() > mMaxTimeBetweenFetches) + { + // received first packet, but our num descendants does not match db's num descendants + // so try again later. + mFetchQueue.pop_front(); + + if (mNumFetchRetries++ < MAX_FETCH_RETRIES) + { + // push on back of queue + mFetchQueue.push_back(info); + } + mTimelyFetchPending = FALSE; + mFetchTimer.reset(); + break; + } + + // not enough time has elapsed to do a new fetch + break; + } + + // + // DEPRECATED OLD CODE + //-------------------------------------------------------------------------------- +#endif + } +} + +void LLInventoryModelBackgroundFetch::incrBulkFetch(S16 fetching) +{ + mBulkFetchCount += fetching; + if (mBulkFetchCount < 0) + { + mBulkFetchCount = 0; + } +} + + +class LLInventoryModelFetchDescendentsResponder: public LLHTTPClient::Responder +{ + public: + LLInventoryModelFetchDescendentsResponder(const LLSD& request_sd, uuid_vec_t recursive_cats) : + mRequestSD(request_sd), + mRecursiveCatUUIDs(recursive_cats) + {}; + //LLInventoryModelFetchDescendentsResponder() {}; + void result(const LLSD& content); + void error(U32 status, const std::string& reason); +protected: + BOOL getIsRecursive(const LLUUID& cat_id) const; +private: + LLSD mRequestSD; + uuid_vec_t mRecursiveCatUUIDs; // hack for storing away which cat fetches are recursive +}; + +// If we get back a normal response, handle it here. +void LLInventoryModelFetchDescendentsResponder::result(const LLSD& content) +{ + LLInventoryModelBackgroundFetch *fetcher = LLInventoryModelBackgroundFetch::getInstance(); + if (content.has("folders")) + { + + for(LLSD::array_const_iterator folder_it = content["folders"].beginArray(); + folder_it != content["folders"].endArray(); + ++folder_it) + { + LLSD folder_sd = *folder_it; + + + //LLUUID agent_id = folder_sd["agent_id"]; + + //if(agent_id != gAgent.getID()) //This should never happen. + //{ + // llwarns << "Got a UpdateInventoryItem for the wrong agent." + // << llendl; + // break; + //} + + LLUUID parent_id = folder_sd["folder_id"]; + LLUUID owner_id = folder_sd["owner_id"]; + S32 version = (S32)folder_sd["version"].asInteger(); + S32 descendents = (S32)folder_sd["descendents"].asInteger(); + LLPointer tcategory = new LLViewerInventoryCategory(owner_id); + + if (parent_id.isNull()) + { + LLPointer titem = new LLViewerInventoryItem; + for(LLSD::array_const_iterator item_it = folder_sd["items"].beginArray(); + item_it != folder_sd["items"].endArray(); + ++item_it) + { + LLUUID lost_uuid = gInventory.findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND); + if (lost_uuid.notNull()) + { + LLSD item = *item_it; + titem->unpackMessage(item); + + LLInventoryModel::update_list_t update; + LLInventoryModel::LLCategoryUpdate new_folder(lost_uuid, 1); + update.push_back(new_folder); + gInventory.accountForUpdate(update); + + titem->setParent(lost_uuid); + titem->updateParentOnServer(FALSE); + gInventory.updateItem(titem); + gInventory.notifyObservers(); + + } + } + } + + LLViewerInventoryCategory* pcat = gInventory.getCategory(parent_id); + if (!pcat) + { + continue; + } + + for(LLSD::array_const_iterator category_it = folder_sd["categories"].beginArray(); + category_it != folder_sd["categories"].endArray(); + ++category_it) + { + LLSD category = *category_it; + tcategory->fromLLSD(category); + + const BOOL recursive = getIsRecursive(tcategory->getUUID()); + + if (recursive) + { + fetcher->mFetchQueue.push_back(LLInventoryModelBackgroundFetch::FetchQueueInfo(tcategory->getUUID(), recursive)); + } + else if ( !gInventory.isCategoryComplete(tcategory->getUUID()) ) + { + gInventory.updateCategory(tcategory); + } + + } + LLPointer titem = new LLViewerInventoryItem; + for(LLSD::array_const_iterator item_it = folder_sd["items"].beginArray(); + item_it != folder_sd["items"].endArray(); + ++item_it) + { + LLSD item = *item_it; + titem->unpackMessage(item); + + gInventory.updateItem(titem); + } + + // set version and descendentcount according to message. + LLViewerInventoryCategory* cat = gInventory.getCategory(parent_id); + if(cat) + { + cat->setVersion(version); + cat->setDescendentCount(descendents); + } + + } + } + + if (content.has("bad_folders")) + { + for(LLSD::array_const_iterator folder_it = content["bad_folders"].beginArray(); + folder_it != content["bad_folders"].endArray(); + ++folder_it) + { + LLSD folder_sd = *folder_it; + + //These folders failed on the dataserver. We probably don't want to retry them. + llinfos << "Folder " << folder_sd["folder_id"].asString() + << "Error: " << folder_sd["error"].asString() << llendl; + } + } + + fetcher->incrBulkFetch(-1); + + if (fetcher->isBulkFetchProcessingComplete()) + { + llinfos << "Inventory fetch completed" << llendl; + fetcher->setAllFoldersFetched(); + } + + gInventory.notifyObservers(); +} + +//If we get back an error (not found, etc...), handle it here +void LLInventoryModelFetchDescendentsResponder::error(U32 status, const std::string& reason) +{ + LLInventoryModelBackgroundFetch *fetcher = LLInventoryModelBackgroundFetch::getInstance(); + + llinfos << "LLInventoryModelFetchDescendentsResponder::error " + << status << ": " << reason << llendl; + + fetcher->incrBulkFetch(-1); + + if (status==499) //timed out. Let's be awesome! + { + for(LLSD::array_const_iterator folder_it = mRequestSD["folders"].beginArray(); + folder_it != mRequestSD["folders"].endArray(); + ++folder_it) + { + LLSD folder_sd = *folder_it; + LLUUID folder_id = folder_sd["folder_id"]; + const BOOL recursive = getIsRecursive(folder_id); + fetcher->mFetchQueue.push_front(LLInventoryModelBackgroundFetch::FetchQueueInfo(folder_id, recursive)); + } + } + else + { + if (fetcher->isBulkFetchProcessingComplete()) + { + fetcher->setAllFoldersFetched(); + } + } + gInventory.notifyObservers(); +} + +BOOL LLInventoryModelFetchDescendentsResponder::getIsRecursive(const LLUUID& cat_id) const +{ + return (std::find(mRecursiveCatUUIDs.begin(),mRecursiveCatUUIDs.end(), cat_id) != mRecursiveCatUUIDs.end()); +} + +// Bundle up a bunch of requests to send all at once. +// static +void LLInventoryModelBackgroundFetch::bulkFetch(std::string url) +{ + //Background fetch is called from gIdleCallbacks in a loop until background fetch is stopped. + //If there are items in sFetchQueue, we want to check the time since the last bulkFetch was + //sent. If it exceeds our retry time, go ahead and fire off another batch. + //Stopbackgroundfetch will be run from the Responder instead of here. + + S16 max_concurrent_fetches=8; + F32 new_min_time = 0.5f; //HACK! Clean this up when old code goes away entirely. + if (mMinTimeBetweenFetches < new_min_time) + { + mMinTimeBetweenFetches=new_min_time; //HACK! See above. + } + + if (gDisconnected || + (mBulkFetchCount > max_concurrent_fetches) || + (mFetchTimer.getElapsedTimeF32() < mMinTimeBetweenFetches)) + { + return; // just bail if we are disconnected. + } + + U32 folder_count=0; + U32 max_batch_size=5; + + U32 sort_order = gSavedSettings.getU32("InventorySortOrder") & 0x1; + + uuid_vec_t recursive_cats; + + LLSD body; + LLSD body_lib; + + while( !(mFetchQueue.empty() ) && (folder_count < max_batch_size) ) + { + const FetchQueueInfo& fetch_info = mFetchQueue.front(); + const LLUUID &cat_id = fetch_info.mCatUUID; + if (cat_id.isNull()) //DEV-17797 + { + LLSD folder_sd; + folder_sd["folder_id"] = LLUUID::null.asString(); + folder_sd["owner_id"] = gAgent.getID(); + folder_sd["sort_order"] = (LLSD::Integer)sort_order; + folder_sd["fetch_folders"] = (LLSD::Boolean)FALSE; + folder_sd["fetch_items"] = (LLSD::Boolean)TRUE; + body["folders"].append(folder_sd); + folder_count++; + } + else + { + LLViewerInventoryCategory* cat = gInventory.getCategory(cat_id); + + if (cat) + { + if (LLViewerInventoryCategory::VERSION_UNKNOWN == cat->getVersion()) + { + LLSD folder_sd; + folder_sd["folder_id"] = cat->getUUID(); + folder_sd["owner_id"] = cat->getOwnerID(); + folder_sd["sort_order"] = (LLSD::Integer)sort_order; + folder_sd["fetch_folders"] = TRUE; //(LLSD::Boolean)sFullFetchStarted; + folder_sd["fetch_items"] = (LLSD::Boolean)TRUE; + + if (ALEXANDRIA_LINDEN_ID == cat->getOwnerID()) + body_lib["folders"].append(folder_sd); + else + body["folders"].append(folder_sd); + folder_count++; + } + // May already have this folder, but append child folders to list. + if (fetch_info.mRecursive) + { + LLInventoryModel::cat_array_t* categories; + gInventory.getDirectDescendentsOf(cat->getUUID(), categories); + for (LLInventoryModel::cat_array_t::const_iterator it = categories->begin(); + it != categories->end(); + ++it) + { + mFetchQueue.push_back(FetchQueueInfo((*it)->getUUID(), fetch_info.mRecursive)); + } + } + } + } + if (fetch_info.mRecursive) + recursive_cats.push_back(cat_id); + + mFetchQueue.pop_front(); + } + + if (folder_count > 0) + { + mBulkFetchCount++; + if (body["folders"].size()) + { + LLInventoryModelFetchDescendentsResponder *fetcher = new LLInventoryModelFetchDescendentsResponder(body, recursive_cats); + LLHTTPClient::post(url, body, fetcher, 300.0); + } + if (body_lib["folders"].size()) + { + 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); + } + mFetchTimer.reset(); + } + else if (isBulkFetchProcessingComplete()) + { + setAllFoldersFetched(); + } +} + +bool LLInventoryModelBackgroundFetch::fetchQueueContainsNoDescendentsOf(const LLUUID& cat_id) const +{ + for (fetch_queue_t::const_iterator it = mFetchQueue.begin(); + it != mFetchQueue.end(); ++it) + { + const LLUUID& fetch_id = (*it).mCatUUID; + if (gInventory.isObjectDescendentOf(fetch_id, cat_id)) + return false; + } + return true; +} + diff --git a/indra/newview/llinventorymodelbackgroundfetch.h b/indra/newview/llinventorymodelbackgroundfetch.h new file mode 100644 index 000000000..0fac2c7a2 --- /dev/null +++ b/indra/newview/llinventorymodelbackgroundfetch.h @@ -0,0 +1,102 @@ +/** + * @file llinventorymodelbackgroundfetch.h + * @brief LLInventoryModelBackgroundFetch class header file + * + * $LicenseInfo:firstyear=2002&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_LLINVENTORYMODELBACKGROUNDFETCH_H +#define LL_LLINVENTORYMODELBACKGROUNDFETCH_H + +#include "llsingleton.h" +#include "lluuid.h" + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLInventoryModelBackgroundFetch +// +// This class handles background fetches, which are fetches of +// inventory folder. Fetches can be recursive or not. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class LLInventoryModelBackgroundFetch : public LLSingleton +{ + friend class LLInventoryModelFetchDescendentsResponder; + +public: + LLInventoryModelBackgroundFetch(); + ~LLInventoryModelBackgroundFetch(); + + // Start and stop background breadth-first fetching of inventory contents. + // This gets triggered when performing a filter-search. + void start(const LLUUID& cat_id = LLUUID::null, BOOL recursive = TRUE); + + BOOL backgroundFetchActive() const; + bool isEverythingFetched() const; // completing the fetch once per session should be sufficient + + bool libraryFetchStarted() const; + bool libraryFetchCompleted() const; + bool libraryFetchInProgress() const; + + bool inventoryFetchStarted() const; + bool inventoryFetchCompleted() const; + bool inventoryFetchInProgress() const; + + void findLostItems(); +protected: + void incrBulkFetch(S16 fetching); + bool isBulkFetchProcessingComplete() const; + void bulkFetch(std::string url); + + void backgroundFetch(); + static void backgroundFetchCB(void*); // background fetch idle function + void stopBackgroundFetch(); // stop fetch process + + void setAllFoldersFetched(); + bool fetchQueueContainsNoDescendentsOf(const LLUUID& cat_id) const; +private: + BOOL mRecursiveInventoryFetchStarted; + BOOL mRecursiveLibraryFetchStarted; + BOOL mAllFoldersFetched; + + BOOL mBackgroundFetchActive; + S16 mBulkFetchCount; + BOOL mTimelyFetchPending; + S32 mNumFetchRetries; + + LLFrameTimer mFetchTimer; + F32 mMinTimeBetweenFetches; + F32 mMaxTimeBetweenFetches; + + struct FetchQueueInfo + { + FetchQueueInfo(const LLUUID& id, BOOL recursive) : + mCatUUID(id), mRecursive(recursive) + { + } + LLUUID mCatUUID; + BOOL mRecursive; + }; + typedef std::deque fetch_queue_t; + fetch_queue_t mFetchQueue; +}; + +#endif // LL_LLINVENTORYMODELBACKGROUNDFETCH_H + diff --git a/indra/newview/llinventoryobserver.cpp b/indra/newview/llinventoryobserver.cpp index c16e96dbd..887f0a474 100644 --- a/indra/newview/llinventoryobserver.cpp +++ b/indra/newview/llinventoryobserver.cpp @@ -40,7 +40,7 @@ #include "llfloater.h" #include "llfocusmgr.h" #include "llinventorybridge.h" -//#include "llinventoryfunctions.h" +#include "llinventoryfunctions.h" #include "llinventorymodel.h" #include "llviewermessage.h" #include "llviewerwindow.h" @@ -58,7 +58,45 @@ const F32 LLInventoryFetchItemsObserver::FETCH_TIMER_EXPIRY = 60.0f; -void fetch_items_from_llsd(const LLSD& items_llsd); + +LLInventoryObserver::LLInventoryObserver() +{ +} + +// virtual +LLInventoryObserver::~LLInventoryObserver() +{ +} + +LLInventoryFetchObserver::LLInventoryFetchObserver(const LLUUID& id) +{ + mIDs.clear(); + if (id != LLUUID::null) + { + setFetchID(id); + } +} + +LLInventoryFetchObserver::LLInventoryFetchObserver(const uuid_vec_t& ids) +{ + setFetchIDs(ids); +} + +BOOL LLInventoryFetchObserver::isFinished() const +{ + return mIncomplete.empty(); +} + +void LLInventoryFetchObserver::setFetchIDs(const uuid_vec_t& ids) +{ + mIDs = ids; +} +void LLInventoryFetchObserver::setFetchID(const LLUUID& id) +{ + mIDs.clear(); + mIDs.push_back(id); +} + void LLInventoryCompletionObserver::changed(U32 mask) { @@ -74,7 +112,7 @@ void LLInventoryCompletionObserver::changed(U32 mask) it = mIncomplete.erase(it); continue; } - if(item->isComplete()) + if (item->isFinished()) { mComplete.push_back(*it); it = mIncomplete.erase(it); @@ -97,25 +135,18 @@ void LLInventoryCompletionObserver::watchItem(const LLUUID& id) } } -LLInventoryFetchItemsObserver::LLInventoryFetchItemsObserver(const LLUUID& item_id) +LLInventoryFetchItemsObserver::LLInventoryFetchItemsObserver(const LLUUID& item_id) : + LLInventoryFetchObserver(item_id) { mIDs.clear(); - if (item_id != LLUUID::null) - { - mIDs.push_back(item_id); - } + mIDs.push_back(item_id); } -LLInventoryFetchItemsObserver::LLInventoryFetchItemsObserver(const uuid_vec_t& item_ids) - : mIDs(item_ids) +LLInventoryFetchItemsObserver::LLInventoryFetchItemsObserver(const uuid_vec_t& item_ids) : + LLInventoryFetchObserver(item_ids) { } -BOOL LLInventoryFetchItemsObserver::isFinished() const -{ - return mIncomplete.empty(); -} - void LLInventoryFetchItemsObserver::changed(U32 mask) { lldebugs << this << " remaining incomplete " << mIncomplete.size() @@ -134,7 +165,7 @@ void LLInventoryFetchItemsObserver::changed(U32 mask) { const LLUUID& item_id = (*it); LLViewerInventoryItem* item = gInventory.getItem(item_id); - if (item && item->isComplete()) + if (item && item->isFinished()) { mComplete.push_back(item_id); it = mIncomplete.erase(it); @@ -167,103 +198,12 @@ void LLInventoryFetchItemsObserver::changed(U32 mask) //llinfos << "LLInventoryFetchItemsObserver::changed() mIncomplete size " << mIncomplete.size() << llendl; } -void LLInventoryFetchItemsObserver::startFetch() -{ - LLUUID owner_id; - LLSD items_llsd; - for (uuid_vec_t::const_iterator it = mIDs.begin(); it < mIDs.end(); ++it) - { - LLViewerInventoryItem* item = gInventory.getItem(*it); - if (item) - { - if (item->isComplete()) - { - // It's complete, so put it on the complete container. - mComplete.push_back(*it); - continue; - } - else - { - owner_id = item->getPermissions().getOwner(); - } - } - else - { - // assume it's agent inventory. - owner_id = gAgent.getID(); - } - - // Ignore categories since they're not items. We - // could also just add this to mComplete but not sure what the - // side-effects would be, so ignoring to be safe. - LLViewerInventoryCategory* cat = gInventory.getCategory(*it); - if (cat) - { - continue; - } - - // It's incomplete, so put it on the incomplete container, and - // pack this on the message. - mIncomplete.push_back(*it); - - // Prepare the data to fetch - LLSD item_entry; - item_entry["owner_id"] = owner_id; - item_entry["item_id"] = (*it); - items_llsd.append(item_entry); - } - - mFetchingPeriod.reset(); - mFetchingPeriod.setTimerExpirySec(FETCH_TIMER_EXPIRY); - - fetch_items_from_llsd(items_llsd); -} - -void LLInventoryFetchObserver::changed(U32 mask) -{ - // scan through the incomplete items and move or erase them as - // appropriate. - if(!mIncomplete.empty()) - { - for(uuid_vec_t::iterator it = mIncomplete.begin(); it < mIncomplete.end(); ) - { - LLViewerInventoryItem* item = gInventory.getItem(*it); - if(!item) - { - // BUG: This can cause done() to get called prematurely below. - // This happens with the LLGestureInventoryFetchObserver that - // loads gestures at startup. JC - it = mIncomplete.erase(it); - continue; - } - if(item->isComplete()) - { - mComplete.push_back(*it); - it = mIncomplete.erase(it); - continue; - } - ++it; - } - if(mIncomplete.empty()) - { - done(); - } - } - //llinfos << "LLInventoryFetchObserver::changed() mComplete size " << mComplete.size() << llendl; - //llinfos << "LLInventoryFetchObserver::changed() mIncomplete size " << mIncomplete.size() << llendl; -} - -bool LLInventoryFetchObserver::isEverythingComplete() const -{ - return mIncomplete.empty(); -} - 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; iisComplete()) + if (item->isFinished()) { // It's complete, so put it on the complete container. mComplete.push_back(*it); @@ -354,206 +293,174 @@ void LLInventoryFetchObserver::fetchItems( // assume it's agent inventory. owner_id = gAgent.getID(); } - + + // Ignore categories since they're not items. We + // could also just add this to mComplete but not sure what the + // side-effects would be, so ignoring to be safe. + LLViewerInventoryCategory* cat = gInventory.getCategory(*it); + if (cat) + { + continue; + } + // It's incomplete, so put it on the incomplete container, and // pack this on the message. mIncomplete.push_back(*it); - + // Prepare the data to fetch LLSD item_entry; item_entry["owner_id"] = owner_id; item_entry["item_id"] = (*it); items_llsd.append(item_entry); } + + mFetchingPeriod.reset(); + mFetchingPeriod.setTimerExpirySec(FETCH_TIMER_EXPIRY); + fetch_items_from_llsd(items_llsd); } + +LLInventoryFetchDescendentsObserver::LLInventoryFetchDescendentsObserver(const LLUUID& cat_id) : + LLInventoryFetchObserver(cat_id) +{ +} + +LLInventoryFetchDescendentsObserver::LLInventoryFetchDescendentsObserver(const uuid_vec_t& cat_ids) : + LLInventoryFetchObserver(cat_ids) +{ +} + // virtual void LLInventoryFetchDescendentsObserver::changed(U32 mask) { - for(folder_ref_t::iterator it = mIncompleteFolders.begin(); it < mIncompleteFolders.end();) + for (uuid_vec_t::iterator it = mIncomplete.begin(); it < mIncomplete.end();) { LLViewerInventoryCategory* cat = gInventory.getCategory(*it); if(!cat) { - it = mIncompleteFolders.erase(it); + it = mIncomplete.erase(it); continue; } - if(isComplete(cat)) + if (isCategoryComplete(cat)) { - mCompleteFolders.push_back(*it); - it = mIncompleteFolders.erase(it); + mComplete.push_back(*it); + it = mIncomplete.erase(it); continue; } ++it; } - if(mIncompleteFolders.empty()) + if (mIncomplete.empty()) { done(); } } -void LLInventoryFetchDescendentsObserver::fetchDescendents( - const folder_ref_t& ids) +void LLInventoryFetchDescendentsObserver::startFetch() { - for(folder_ref_t::const_iterator it = ids.begin(); it != ids.end(); ++it) + for (uuid_vec_t::const_iterator it = mIDs.begin(); it != mIDs.end(); ++it) { LLViewerInventoryCategory* cat = gInventory.getCategory(*it); - if(!cat) continue; - if(!isComplete(cat)) + if (!cat) continue; + if (!isCategoryComplete(cat)) { - cat->fetchDescendents(); //blindly fetch it without seeing if anything else is fetching it. - mIncompleteFolders.push_back(*it); //Add to list of things being downloaded for this observer. + cat->fetch(); //blindly fetch it without seeing if anything else is fetching it. + mIncomplete.push_back(*it); //Add to list of things being downloaded for this observer. } else { - mCompleteFolders.push_back(*it); + mComplete.push_back(*it); } } } -bool LLInventoryFetchDescendentsObserver::isEverythingComplete() const +BOOL LLInventoryFetchDescendentsObserver::isCategoryComplete(const LLViewerInventoryCategory* cat) const { - return mIncompleteFolders.empty(); -} - -bool LLInventoryFetchDescendentsObserver::isComplete(LLViewerInventoryCategory* cat) -{ - S32 version = cat->getVersion(); - S32 descendents = cat->getDescendentCount(); - if((LLViewerInventoryCategory::VERSION_UNKNOWN == version) - || (LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN == descendents)) + const S32 version = cat->getVersion(); + const S32 expected_num_descendents = cat->getDescendentCount(); + if ((version == LLViewerInventoryCategory::VERSION_UNKNOWN) || + (expected_num_descendents == LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN)) { - return false; + return FALSE; } // it might be complete - check known descendents against // currently available. LLInventoryModel::cat_array_t* cats; LLInventoryModel::item_array_t* items; gInventory.getDirectDescendentsOf(cat->getUUID(), cats, items); - if(!cats || !items) + if (!cats || !items) { - // bit of a hack - pretend we're done if they are gone or - // incomplete. should never know, but it would suck if this - // kept tight looping because of a corrupt memory state. - return true; + llwarns << "Category '" << cat->getName() << "' descendents corrupted, fetch failed." << llendl; + // NULL means the call failed -- cats/items map doesn't exist (note: this does NOT mean + // that the cat just doesn't have any items or subfolders). + // Unrecoverable, so just return done so that this observer can be cleared + // from memory. + return TRUE; } - S32 known = cats->count() + items->count(); - if(descendents == known) + const S32 current_num_known_descendents = cats->count() + items->count(); + + // Got the number of descendents that we were expecting, so we're done. + if (current_num_known_descendents == expected_num_descendents) { - // hey - we're done. - return true; + return TRUE; } - return false; + + // Error condition, but recoverable. This happens if something was added to the + // category before it was initialized, so accountForUpdate didn't update descendent + // count and thus the category thinks it has fewer descendents than it actually has. + if (current_num_known_descendents >= expected_num_descendents) + { + llwarns << "Category '" << cat->getName() << "' expected descendentcount:" << expected_num_descendents << " descendents but got descendentcount:" << current_num_known_descendents << llendl; + const_cast(cat)->setDescendentCount(current_num_known_descendents); + return TRUE; + } + return FALSE; +} + +LLInventoryFetchComboObserver::LLInventoryFetchComboObserver(const uuid_vec_t& folder_ids, + const uuid_vec_t& item_ids) +{ + mFetchDescendents = new LLInventoryFetchDescendentsObserver(folder_ids); + + uuid_vec_t pruned_item_ids; + for (uuid_vec_t::const_iterator item_iter = item_ids.begin(); + item_iter != item_ids.end(); + ++item_iter) + { + const LLUUID& item_id = (*item_iter); + const LLViewerInventoryItem* item = gInventory.getItem(item_id); + if (item && std::find(folder_ids.begin(), folder_ids.end(), item->getParentUUID()) == folder_ids.end()) + { + continue; + } + pruned_item_ids.push_back(item_id); + } + + mFetchItems = new LLInventoryFetchItemsObserver(pruned_item_ids); + mFetchDescendents = new LLInventoryFetchDescendentsObserver(folder_ids); +} + +LLInventoryFetchComboObserver::~LLInventoryFetchComboObserver() +{ + mFetchItems->done(); + mFetchDescendents->done(); + delete mFetchItems; + delete mFetchDescendents; } void LLInventoryFetchComboObserver::changed(U32 mask) { - if(!mIncompleteItems.empty()) + mFetchItems->changed(mask); + mFetchDescendents->changed(mask); + if (mFetchItems->isFinished() && mFetchDescendents->isFinished()) { - for(item_ref_t::iterator it = mIncompleteItems.begin(); it < mIncompleteItems.end(); ) - { - LLViewerInventoryItem* item = gInventory.getItem(*it); - if(!item) - { - it = mIncompleteItems.erase(it); - continue; - } - if(item->isComplete()) - { - mCompleteItems.push_back(*it); - it = mIncompleteItems.erase(it); - continue; - } - ++it; - } - } - if(!mIncompleteFolders.empty()) - { - for(folder_ref_t::iterator it = mIncompleteFolders.begin(); it < mIncompleteFolders.end();) - { - LLViewerInventoryCategory* cat = gInventory.getCategory(*it); - if(!cat) - { - it = mIncompleteFolders.erase(it); - continue; - } - if(gInventory.isCategoryComplete(*it)) - { - mCompleteFolders.push_back(*it); - it = mIncompleteFolders.erase(it); - continue; - } - ++it; - } - } - if(!mDone && mIncompleteItems.empty() && mIncompleteFolders.empty()) - { - mDone = true; done(); } } -void LLInventoryFetchComboObserver::fetch( - const folder_ref_t& folder_ids, - const item_ref_t& item_ids) +void LLInventoryFetchComboObserver::startFetch() { - lldebugs << "LLInventoryFetchComboObserver::fetch()" << llendl; - for(folder_ref_t::const_iterator fit = folder_ids.begin(); fit != folder_ids.end(); ++fit) - { - LLViewerInventoryCategory* cat = gInventory.getCategory(*fit); - if(!cat) continue; - if(!gInventory.isCategoryComplete(*fit)) - { - cat->fetchDescendents(); - lldebugs << "fetching folder " << *fit <isComplete()) - { - // It's complete, so put it on the complete container. - mCompleteItems.push_back(*iit); - lldebugs << "completing item " << *iit << llendl; - continue; - } - else - { - mIncompleteItems.push_back(*iit); - owner_id = item->getPermissions().getOwner(); - } - if(std::find(mIncompleteFolders.begin(), mIncompleteFolders.end(), item->getParentUUID()) == mIncompleteFolders.end()) - { - LLSD item_entry; - item_entry["owner_id"] = owner_id; - item_entry["item_id"] = (*iit); - items_llsd.append(item_entry); - } - else - { - lldebugs << "not worrying about " << *iit << llendl; - } - } - fetch_items_from_llsd(items_llsd); + mFetchItems->startFetch(); + mFetchDescendents->startFetch(); } void LLInventoryExistenceObserver::watchItem(const LLUUID& id) @@ -587,13 +494,83 @@ void LLInventoryExistenceObserver::changed(U32 mask) } } } -void LLInventoryAddedObserver::changed(U32 mask) + +void LLInventoryAddItemByAssetObserver::changed(U32 mask) { if(!(mask & LLInventoryObserver::ADD)) { return; } + // nothing is watched + if (mWatchedAssets.size() == 0) + { + return; + } + + LLMessageSystem* msg = gMessageSystem; + if (!(msg->getMessageName() && (0 == strcmp(msg->getMessageName(), "UpdateCreateInventoryItem")))) + { + // this is not our message + return; // to prevent a crash. EXT-7921; + } + + LLPointer item = new LLViewerInventoryItem; + S32 num_blocks = msg->getNumberOfBlocksFast(_PREHASH_InventoryData); + for(S32 i = 0; i < num_blocks; ++i) + { + item->unpackMessage(msg, _PREHASH_InventoryData, i); + const LLUUID& asset_uuid = item->getAssetUUID(); + if (item->getUUID().notNull() && asset_uuid.notNull()) + { + if (isAssetWatched(asset_uuid)) + { + LL_DEBUGS("Inventory_Move") << "Found asset UUID: " << asset_uuid << LL_ENDL; + mAddedItems.push_back(item->getUUID()); + } + } + } + + if (mAddedItems.size() == mWatchedAssets.size()) + { + done(); + LL_DEBUGS("Inventory_Move") << "All watched items are added & processed." << LL_ENDL; + mAddedItems.clear(); + + // Unable to clean watched items here due to somebody can require to check them in current frame. + // set dirty state to clean them while next watch cycle. + mIsDirty = true; + } +} + +void LLInventoryAddItemByAssetObserver::watchAsset(const LLUUID& asset_id) +{ + if(asset_id.notNull()) + { + if (mIsDirty) + { + LL_DEBUGS("Inventory_Move") << "Watched items are dirty. Clean them." << LL_ENDL; + mWatchedAssets.clear(); + mIsDirty = false; + } + + mWatchedAssets.push_back(asset_id); + onAssetAdded(asset_id); + } +} + +bool LLInventoryAddItemByAssetObserver::isAssetWatched( const LLUUID& asset_id ) +{ + return std::find(mWatchedAssets.begin(), mWatchedAssets.end(), asset_id) != mWatchedAssets.end(); +} + +void LLInventoryAddedObserver::changed(U32 mask) +{ + if (!(mask & LLInventoryObserver::ADD)) + { + return; + } + // *HACK: If this was in response to a packet off // the network, figure out which item was updated. LLMessageSystem* msg = gMessageSystem; @@ -627,6 +604,34 @@ void LLInventoryAddedObserver::changed(U32 mask) } } +void LLInventoryCategoryAddedObserver::changed(U32 mask) +{ + if (!(mask & LLInventoryObserver::ADD)) + { + return; + } + + const LLInventoryModel::changed_items_t& changed_ids = gInventory.getChangedIDs(); + + for (LLInventoryModel::changed_items_t::const_iterator cit = changed_ids.begin(); cit != changed_ids.end(); ++cit) + { + LLViewerInventoryCategory* cat = gInventory.getCategory(*cit); + + if (cat) + { + mAddedCategories.push_back(cat); + } + } + + if (!mAddedCategories.empty()) + { + done(); + + mAddedCategories.clear(); + } +} + + LLInventoryTransactionObserver::LLInventoryTransactionObserver(const LLTransactionID& transaction_id) : mTransactionID(transaction_id) { @@ -676,4 +681,140 @@ void LLInventoryTransactionObserver::changed(U32 mask) } } } -} \ No newline at end of file +} + +void LLInventoryCategoriesObserver::changed(U32 mask) +{ + if (!mCategoryMap.size()) + return; + + for (category_map_t::iterator iter = mCategoryMap.begin(); + iter != mCategoryMap.end(); + ++iter) + { + const LLUUID& cat_id = (*iter).first; + + LLViewerInventoryCategory* category = gInventory.getCategory(cat_id); + if (!category) + continue; + + const S32 version = category->getVersion(); + const S32 expected_num_descendents = category->getDescendentCount(); + if ((version == LLViewerInventoryCategory::VERSION_UNKNOWN) || + (expected_num_descendents == LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN)) + { + continue; + } + + // Check number of known descendents to find out whether it has changed. + LLInventoryModel::cat_array_t* cats; + LLInventoryModel::item_array_t* items; + gInventory.getDirectDescendentsOf(cat_id, cats, items); + if (!cats || !items) + { + llwarns << "Category '" << category->getName() << "' descendents corrupted, fetch failed." << llendl; + // NULL means the call failed -- cats/items map doesn't exist (note: this does NOT mean + // that the cat just doesn't have any items or subfolders). + // Unrecoverable, so just skip this category. + + llassert(cats != NULL && items != NULL); + + continue; + } + + const S32 current_num_known_descendents = cats->count() + items->count(); + + LLCategoryData& cat_data = (*iter).second; + + bool cat_changed = false; + + // If category version or descendents count has changed + // update category data in mCategoryMap + if (version != cat_data.mVersion || current_num_known_descendents != cat_data.mDescendentsCount) + { + cat_data.mVersion = version; + cat_data.mDescendentsCount = current_num_known_descendents; + cat_changed = true; + } + + // If any item names have changed, update the name hash + // Only need to check if (a) name hash has not previously been + // computed, or (b) a name has changed. + if (!cat_data.mIsNameHashInitialized || (mask & LLInventoryObserver::LABEL)) + { + LLMD5 item_name_hash = gInventory.hashDirectDescendentNames(cat_id); + if (cat_data.mItemNameHash != item_name_hash) + { + cat_data.mIsNameHashInitialized = true; + cat_data.mItemNameHash = item_name_hash; + cat_changed = true; + } + } + + // If anything has changed above, fire the callback. + if (cat_changed) + cat_data.mCallback(); + } +} + +bool LLInventoryCategoriesObserver::addCategory(const LLUUID& cat_id, callback_t cb) +{ + S32 version = LLViewerInventoryCategory::VERSION_UNKNOWN; + S32 current_num_known_descendents = LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN; + bool can_be_added = true; + + LLViewerInventoryCategory* category = gInventory.getCategory(cat_id); + // If category could not be retrieved it might mean that + // inventory is unusable at the moment so the category is + // stored with VERSION_UNKNOWN and DESCENDENT_COUNT_UNKNOWN, + // it may be updated later. + if (category) + { + // Inventory category version is used to find out if some changes + // to a category have been made. + version = category->getVersion(); + + LLInventoryModel::cat_array_t* cats; + LLInventoryModel::item_array_t* items; + gInventory.getDirectDescendentsOf(cat_id, cats, items); + if (!cats || !items) + { + llwarns << "Category '" << category->getName() << "' descendents corrupted, fetch failed." << llendl; + // NULL means the call failed -- cats/items map doesn't exist (note: this does NOT mean + // that the cat just doesn't have any items or subfolders). + // Unrecoverable, so just return "false" meaning that the category can't be observed. + can_be_added = false; + + llassert(cats != NULL && items != NULL); + } + else + { + current_num_known_descendents = cats->count() + items->count(); + } + } + + if (can_be_added) + { + mCategoryMap.insert(category_map_value_t( + cat_id,LLCategoryData(cat_id, cb, version, current_num_known_descendents))); + } + + return can_be_added; +} + +void LLInventoryCategoriesObserver::removeCategory(const LLUUID& cat_id) +{ + mCategoryMap.erase(cat_id); +} + +LLInventoryCategoriesObserver::LLCategoryData::LLCategoryData( + const LLUUID& cat_id, callback_t cb, S32 version, S32 num_descendents) + + : mCatID(cat_id) + , mCallback(cb) + , mVersion(version) + , mDescendentsCount(num_descendents) + , mIsNameHashInitialized(false) +{ + mItemNameHash.finalize(); +} diff --git a/indra/newview/llinventoryobserver.h b/indra/newview/llinventoryobserver.h index e07beabd4..bf45db43d 100644 --- a/indra/newview/llinventoryobserver.h +++ b/indra/newview/llinventoryobserver.h @@ -58,49 +58,48 @@ public: GESTURE = 64, ALL = 0xffffffff }; - virtual ~LLInventoryObserver() {}; + LLInventoryObserver(); + virtual ~LLInventoryObserver(); virtual void changed(U32 mask) = 0; }; - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLInventoryFetchObserver // -// This class is much like the LLInventoryCompletionObserver, except -// that it handles all the the fetching necessary. Override the done() -// method to do the thing you want. +// Abstract class to handle fetching items, folders, etc. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - class LLInventoryFetchObserver : public LLInventoryObserver { public: - LLInventoryFetchObserver() {} - virtual void changed(U32 mask); - - bool isEverythingComplete() const; - void fetchItems(const uuid_vec_t& ids); - virtual void done() = 0; - -protected: - uuid_vec_t mComplete; - uuid_vec_t mIncomplete; -}; - -class LLInventoryFetchItemsObserver : public LLInventoryObserver -{ -public: - LLInventoryFetchItemsObserver(const LLUUID& item_id = LLUUID::null); - LLInventoryFetchItemsObserver(const uuid_vec_t& item_ids); + LLInventoryFetchObserver(const LLUUID& id = LLUUID::null); // single item + LLInventoryFetchObserver(const uuid_vec_t& ids); // multiple items + void setFetchID(const LLUUID& id); + void setFetchIDs(const uuid_vec_t& ids); BOOL isFinished() const; - virtual void startFetch(); - virtual void changed(U32 mask); + virtual void startFetch() = 0; + virtual void changed(U32 mask) = 0; virtual void done() {}; protected: uuid_vec_t mComplete; uuid_vec_t mIncomplete; uuid_vec_t mIDs; +}; + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLInventoryFetchItemsObserver +// +// Fetches inventory items, calls done() when all inventory has arrived. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class LLInventoryFetchItemsObserver : public LLInventoryFetchObserver +{ +public: + LLInventoryFetchItemsObserver(const LLUUID& item_id = LLUUID::null); + LLInventoryFetchItemsObserver(const uuid_vec_t& item_ids); + + /*virtual*/ void startFetch(); + /*virtual*/ void changed(U32 mask); private: LLTimer mFetchingPeriod; @@ -113,120 +112,147 @@ private: //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLInventoryFetchDescendentsObserver // -// This class is much like the LLInventoryCompletionObserver, except -// that it handles fetching based on category. Override the done() -// method to do the thing you want. +// Fetches children of a category/folder, calls done() when all +// inventory has arrived. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -class LLInventoryFetchDescendentsObserver : public LLInventoryObserver +class LLInventoryFetchDescendentsObserver : public LLInventoryFetchObserver { public: - LLInventoryFetchDescendentsObserver() {} - virtual void changed(U32 mask); - - typedef std::vector folder_ref_t; - void fetchDescendents(const folder_ref_t& ids); - bool isEverythingComplete() const; - virtual void done() = 0; + LLInventoryFetchDescendentsObserver(const LLUUID& cat_id = LLUUID::null); + LLInventoryFetchDescendentsObserver(const uuid_vec_t& cat_ids); + /*virtual*/ void startFetch(); + /*virtual*/ void changed(U32 mask); protected: - bool isComplete(LLViewerInventoryCategory* cat); - folder_ref_t mIncompleteFolders; - folder_ref_t mCompleteFolders; + BOOL isCategoryComplete(const LLViewerInventoryCategory* cat) const; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLInventoryFetchComboObserver // -// This class does an appropriate combination of fetch descendents and -// item fetches based on completion of categories and items. Much like -// the fetch and fetch descendents, this will call done() when everything -// has arrived. +// Does an appropriate combination of fetch descendents and +// item fetches based on completion of categories and items. This is optimized +// to not fetch item_ids that are descendents of any of the folder_ids. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ class LLInventoryFetchComboObserver : public LLInventoryObserver { public: - LLInventoryFetchComboObserver() : mDone(false) {} - virtual void changed(U32 mask); - - typedef std::vector folder_ref_t; - typedef std::vector item_ref_t; - void fetch(const folder_ref_t& folder_ids, const item_ref_t& item_ids); + LLInventoryFetchComboObserver(const uuid_vec_t& folder_ids, + const uuid_vec_t& item_ids); + ~LLInventoryFetchComboObserver(); + /*virtual*/ void changed(U32 mask); + void startFetch(); virtual void done() = 0; - protected: - bool mDone; - folder_ref_t mCompleteFolders; - folder_ref_t mIncompleteFolders; - item_ref_t mCompleteItems; - item_ref_t mIncompleteItems; + LLInventoryFetchItemsObserver *mFetchItems; + LLInventoryFetchDescendentsObserver *mFetchDescendents; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLInventoryExistenceObserver // -// This class is used as a base class for doing somethign when all the -// observed item ids exist in the inventory somewhere. You can derive -// a class from this class and implement the done() method to do -// something useful. +// Used as a base class for doing something when all the +// observed item ids exist in the inventory somewhere. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - class LLInventoryExistenceObserver : public LLInventoryObserver { public: LLInventoryExistenceObserver() {} - virtual void changed(U32 mask); + /*virtual*/ void changed(U32 mask); void watchItem(const LLUUID& id); - protected: virtual void done() = 0; - uuid_vec_t mExist; uuid_vec_t mMIA; }; + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLInventoryMovedObserver +// +// This class is used as a base class for doing something when all the +// item for observed asset ids were added into the inventory. +// Derive a class from this class and implement the done() method to do +// something useful. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +class LLInventoryAddItemByAssetObserver : public LLInventoryObserver +{ +public: + LLInventoryAddItemByAssetObserver() : mIsDirty(false) {} + virtual void changed(U32 mask); + + void watchAsset(const LLUUID& asset_id); + bool isAssetWatched(const LLUUID& asset_id); + +protected: + virtual void onAssetAdded(const LLUUID& asset_id) {} + virtual void done() = 0; + + typedef std::vector item_ref_t; + item_ref_t mAddedItems; + item_ref_t mWatchedAssets; + +private: + bool mIsDirty; +}; + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLInventoryAddedObserver // -// This class is used as a base class for doing something when -// a new item arrives in inventory. -// It does not watch for a certain UUID, rather it acts when anything is added -// Derive a class from this class and implement the done() method to do -// something useful. +// Base class for doing something when a new item arrives in inventory. +// It does not watch for a certain UUID, rather it acts when anything is added //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ class LLInventoryAddedObserver : public LLInventoryObserver { public: LLInventoryAddedObserver() : mAdded() {} - virtual void changed(U32 mask); + /*virtual*/ void changed(U32 mask); protected: virtual void done() = 0; - typedef std::vector item_ref_t; - item_ref_t mAdded; + uuid_vec_t mAdded; +}; + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLInventoryCategoryAddedObserver +// +// Base class for doing something when a new category is created in the +// inventory. +// It does not watch for a certain UUID, rather it acts when anything is added +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class LLInventoryCategoryAddedObserver : public LLInventoryObserver +{ +public: + + typedef std::vector cat_vec_t; + + LLInventoryCategoryAddedObserver() : mAddedCategories() {} + /*virtual*/ void changed(U32 mask); + +protected: + virtual void done() = 0; + + cat_vec_t mAddedCategories; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLInventoryTransactionObserver // -// Class which can be used as a base class for doing something when an -// inventory transaction completes. -// -// *NOTE: This class is not quite complete. Avoid using unless you fix up it's -// functionality gaps. +// Base class for doing something when an inventory transaction completes. +// NOTE: This class is not quite complete. Avoid using unless you fix up its +// functionality gaps. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - class LLInventoryTransactionObserver : public LLInventoryObserver { public: LLInventoryTransactionObserver(const LLTransactionID& transaction_id); - virtual void changed(U32 mask); + /*virtual*/ void changed(U32 mask); protected: - typedef std::vector folder_ref_t; - typedef std::vector item_ref_t; - virtual void done(const folder_ref_t& folders, const item_ref_t& items) = 0; + virtual void done(const uuid_vec_t& folders, const uuid_vec_t& items) = 0; LLTransactionID mTransactionID; }; @@ -234,17 +260,16 @@ protected: //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLInventoryCompletionObserver // -// Class which can be used as a base class for doing something when -// when all observed items are locally complete. This class implements -// the changed() method of LLInventoryObserver and declares a new -// method named done() which is called when all watched items have -// complete information in the inventory model. +// Base class for doing something when when all observed items are locally +// complete. Implements the changed() method of LLInventoryObserver +// and declares a new method named done() which is called when all watched items +// have complete information in the inventory model. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ class LLInventoryCompletionObserver : public LLInventoryObserver { public: LLInventoryCompletionObserver() {} - virtual void changed(U32 mask); + /*virtual*/ void changed(U32 mask); void watchItem(const LLUUID& id); @@ -255,4 +280,47 @@ protected: uuid_vec_t mIncomplete; }; +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLInventoryCategoriesObserver +// +// This class is used for monitoring a list of inventory categories +// and firing a callback when there are changes in any of them. +// Categories are identified by their UUIDs. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class LLInventoryCategoriesObserver : public LLInventoryObserver +{ +public: + typedef boost::function callback_t; + + LLInventoryCategoriesObserver() {}; + virtual void changed(U32 mask); + + /** + * Add cat_id to the list of observed categories with a + * callback fired on category being changed. + * + * @return "true" if category was added, "false" if it could + * not be found. + */ + bool addCategory(const LLUUID& cat_id, callback_t cb); + void removeCategory(const LLUUID& cat_id); + +protected: + struct LLCategoryData + { + LLCategoryData(const LLUUID& cat_id, callback_t cb, S32 version, S32 num_descendents); + + callback_t mCallback; + S32 mVersion; + S32 mDescendentsCount; + LLMD5 mItemNameHash; + bool mIsNameHashInitialized; + LLUUID mCatID; + }; + + typedef std::map category_map_t; + typedef category_map_t::value_type category_map_value_t; + + category_map_t mCategoryMap; +}; #endif // LL_LLINVENTORYOBSERVERS_H diff --git a/indra/newview/llinventoryview.cpp b/indra/newview/llinventoryview.cpp index bbfc1c515..a373a4697 100644 --- a/indra/newview/llinventoryview.cpp +++ b/indra/newview/llinventoryview.cpp @@ -59,6 +59,7 @@ #include "lliconctrl.h" #include "llinventoryfunctions.h" #include "llinventoryclipboard.h" +#include "llinventorymodelbackgroundfetch.h" #include "lllineeditor.h" #include "llmenugl.h" #include "llpreviewanim.h" @@ -109,6 +110,25 @@ const S32 INV_MIN_HEIGHT = 150; const S32 INV_FINDER_WIDTH = 160; const S32 INV_FINDER_HEIGHT = 408; +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLInventoryPanelObserver +// +// Bridge to support knowing when the inventory has changed. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +class LLInventoryPanelObserver : public LLInventoryObserver +{ +public: + LLInventoryPanelObserver(LLInventoryPanel* ip) : mIP(ip) {} + virtual ~LLInventoryPanelObserver() {} + virtual void changed(U32 mask) + { + mIP->modelChanged(mask); + } +protected: + LLInventoryPanel* mIP; +}; + ///---------------------------------------------------------------------------- /// LLInventoryViewFinder ///---------------------------------------------------------------------------- @@ -600,7 +620,7 @@ LLInventoryView::~LLInventoryView( void ) void LLInventoryView::draw() { - if (LLInventoryModel::isEverythingFetched()) + if (LLInventoryModelBackgroundFetch::instance().isEverythingFetched()) { LLLocale locale(LLLocale::USER_LOCALE); std::ostringstream title; @@ -710,7 +730,7 @@ void LLInventoryView::changed(U32 mask) { std::ostringstream title; title << "Inventory"; - if (LLInventoryModel::backgroundFetchActive()) + if (LLInventoryModelBackgroundFetch::instance().backgroundFetchActive()) { LLLocale locale(LLLocale::USER_LOCALE); std::string item_count_string; @@ -851,7 +871,7 @@ void LLInventoryView::toggleFindOptions() addDependentFloater(mFinderHandle); // start background fetch of folders - gInventory.startBackgroundFetch(); + LLInventoryModelBackgroundFetch::instance().start(); mFloaterControls[std::string("Inventory.ShowFilters")]->setValue(TRUE); } @@ -927,7 +947,7 @@ void LLInventoryView::onSearchEdit(const std::string& search_string, void* user_ return; } - gInventory.startBackgroundFetch(); + LLInventoryModelBackgroundFetch::instance().start(); std::string filter_text = search_string; std::string uppercase_search_string = filter_text; @@ -1282,7 +1302,7 @@ void LLInventoryView::onFilterSelected(void* userdata, bool from_click) if (filter->isActive()) { // If our filter is active we may be the first thing requiring a fetch so we better start it here. - gInventory.startBackgroundFetch(); + LLInventoryModelBackgroundFetch::instance().start(); } self->setFilterTextFromFilter(); self->updateSortControls(); @@ -1339,7 +1359,7 @@ LLInventoryPanel::LLInventoryPanel(const std::string& name, LLPanel(name, rect, TRUE), mInventory(inventory), mInventoryObserver(NULL), - mFolders(NULL), + mFolderRoot(NULL), mScroller(NULL), mAllowMultiSelect(allow_multi_select), mSortOrderSetting(sort_order_setting) @@ -1357,19 +1377,19 @@ BOOL LLInventoryPanel::postBuild() 0, getRect().getWidth(), 0); - mFolders = new LLFolderView(getName(), NULL, folder_rect, LLUUID::null, this); - mFolders->setAllowMultiSelect(mAllowMultiSelect); + mFolderRoot = new LLFolderView(getName(), NULL, folder_rect, LLUUID::null, this); + mFolderRoot->setAllowMultiSelect(mAllowMultiSelect); // scroller LLRect scroller_view_rect = getRect(); scroller_view_rect.translate(-scroller_view_rect.mLeft, -scroller_view_rect.mBottom); mScroller = new LLScrollableContainerView(std::string("Inventory Scroller"), scroller_view_rect, - mFolders); + mFolderRoot); mScroller->setFollowsAll(); mScroller->setReserveScrollCorner(TRUE); addChild(mScroller); - mFolders->setScrollContainer(mScroller); + mFolderRoot->setScrollContainer(mScroller); // set up the callbacks from the inventory we're viewing, and then // build everything. @@ -1378,7 +1398,7 @@ BOOL LLInventoryPanel::postBuild() rebuildViewsFor(LLUUID::null, LLInventoryObserver::ADD); // bit of a hack to make sure the inventory is open. - mFolders->openFolder(std::string("My Inventory")); + mFolderRoot->openFolder(std::string("My Inventory")); if (mSortOrderSetting != INHERIT_SORT_ORDER) { @@ -1388,7 +1408,7 @@ BOOL LLInventoryPanel::postBuild() { setSortOrder(gSavedSettings.getU32(DEFAULT_SORT_ORDER)); } - mFolders->setSortOrder(mFolders->getFilter()->getSortOrder()); + mFolderRoot->setSortOrder(mFolderRoot->getFilter()->getSortOrder()); return TRUE; @@ -1396,11 +1416,13 @@ BOOL LLInventoryPanel::postBuild() LLInventoryPanel::~LLInventoryPanel() { - // should this be a global setting? - U32 sort_order = mFolders->getSortOrder(); - if (mSortOrderSetting != INHERIT_SORT_ORDER) + if (mFolderRoot) { - gSavedSettings.setU32(mSortOrderSetting, sort_order); + U32 sort_order = mFolderRoot->getSortOrder(); + if (mSortOrderSetting != INHERIT_SORT_ORDER) + { + gSavedSettings.setU32(mSortOrderSetting, sort_order); + } } // LLView destructor will take care of the sub-views. @@ -1416,7 +1438,7 @@ LLXMLNodePtr LLInventoryPanel::getXML(bool save_children) const node->setName(LL_INVENTORY_PANEL_TAG); - node->createChild("allow_multi_select", TRUE)->setBoolValue(mFolders->getAllowMultiSelect()); + node->createChild("allow_multi_select", TRUE)->setBoolValue(mFolderRoot->getAllowMultiSelect()); return node; } @@ -1458,60 +1480,99 @@ void LLInventoryPanel::draw() LLPanel::draw(); } +LLInventoryFilter* LLInventoryPanel::getFilter() +{ + if (mFolderRoot) + { + return mFolderRoot->getFilter(); + } + return NULL; +} + +const LLInventoryFilter* LLInventoryPanel::getFilter() const +{ + if (mFolderRoot) + { + return mFolderRoot->getFilter(); + } + return NULL; +} + void LLInventoryPanel::setFilterTypes(U32 filter_types) { - mFolders->getFilter()->setFilterTypes(filter_types); + getFilter()->setFilterTypes(filter_types); } +U32 LLInventoryPanel::getFilterTypes() const +{ + return mFolderRoot->getFilterTypes(); +} + +U32 LLInventoryPanel::getFilterPermMask() const +{ + return mFolderRoot->getFilterPermissions(); +} + void LLInventoryPanel::setFilterPermMask(PermissionMask filter_perm_mask) { - mFolders->getFilter()->setFilterPermissions(filter_perm_mask); -} - -void LLInventoryPanel::setFilterSubString(const std::string& string) -{ - mFolders->getFilter()->setFilterSubString(string); + getFilter()->setFilterPermissions(filter_perm_mask); } void LLInventoryPanel::setFilterWorn(bool worn) { - mFolders->getFilter()->setFilterWorn(worn); + getFilter()->setFilterWorn(worn); +} + +void LLInventoryPanel::setFilterSubString(const std::string& string) +{ + getFilter()->setFilterSubString(string); +} + +const std::string LLInventoryPanel::getFilterSubString() +{ + return mFolderRoot->getFilterSubString(); } void LLInventoryPanel::setSortOrder(U32 order) { - mFolders->getFilter()->setSortOrder(order); - if (mFolders->getFilter()->isModified()) + getFilter()->setSortOrder(order); + if (getFilter()->isModified()) { - mFolders->setSortOrder(order); + mFolderRoot->setSortOrder(order); // try to keep selection onscreen, even if it wasn't to start with - mFolders->scrollToShowSelection(); + mFolderRoot->scrollToShowSelection(); } } +U32 LLInventoryPanel::getSortOrder() const +{ + return mFolderRoot->getSortOrder(); +} + void LLInventoryPanel::setSinceLogoff(BOOL sl) { - mFolders->getFilter()->setDateRangeLastLogoff(sl); + getFilter()->setDateRangeLastLogoff(sl); } void LLInventoryPanel::setHoursAgo(U32 hours) { - mFolders->getFilter()->setHoursAgo(hours); + getFilter()->setHoursAgo(hours); } void LLInventoryPanel::setShowFolderState(LLInventoryFilter::EFolderShow show) { - mFolders->getFilter()->setShowFolderState(show); + getFilter()->setShowFolderState(show); } LLInventoryFilter::EFolderShow LLInventoryPanel::getShowFolderState() { - return mFolders->getFilter()->getShowFolderState(); + return getFilter()->getShowFolderState(); } void LLInventoryPanel::modelChanged(U32 mask) { - LLFastTimer t2(LLFastTimer::FTM_REFRESH); + static LLFastTimer::DeclareTimer FTM_REFRESH("Inventory Refresh"); + LLFastTimer t2(FTM_REFRESH); bool handled = false; @@ -1529,7 +1590,7 @@ void LLInventoryPanel::modelChanged(U32 mask) { const LLUUID& item_id = (*items_iter); const LLInventoryObject* model_item = model->getObject(item_id); - LLFolderViewItem* view_item = getRootFolder()->getItemByID(item_id); + LLFolderViewItem* view_item = mFolderRoot->getItemByID(item_id); // LLFolderViewFolder is derived from LLFolderViewItem so dynamic_cast from item // to folder is the fast way to get a folder without searching through folders tree. @@ -1609,7 +1670,7 @@ void LLInventoryPanel::modelChanged(U32 mask) // Add the UI element for this item. buildNewViews(item_id); // Select any newly created object that has the auto rename at top of folder root set. - if(getRootFolder()->getRoot()->needsAutoRename()) + if(mFolderRoot->getRoot()->needsAutoRename()) { setSelection(item_id, FALSE); } @@ -1623,7 +1684,7 @@ void LLInventoryPanel::modelChanged(U32 mask) // Don't process the item if it is the root if (view_item->getRoot() != view_item) { - LLFolderViewFolder* new_parent = (LLFolderViewFolder*)getRootFolder()->getItemByID(model_item->getParentUUID()); + LLFolderViewFolder* new_parent = (LLFolderViewFolder*)mFolderRoot->getItemByID(model_item->getParentUUID()); // Item has been moved. if (view_item->getParentFolder() != new_parent) { @@ -1631,7 +1692,7 @@ void LLInventoryPanel::modelChanged(U32 mask) { // Item is to be moved and we found its new parent in the panel's directory, so move the item's UI. view_item->getParentFolder()->extractItem(view_item); - view_item->addToFolder(new_parent, getRootFolder()); + view_item->addToFolder(new_parent, mFolderRoot); } else { @@ -1655,12 +1716,18 @@ void LLInventoryPanel::modelChanged(U32 mask) } } +LLFolderView* LLInventoryPanel::getRootFolder() +{ + return mFolderRoot; +} +const LLUUID& LLInventoryPanel::getRootFolderID() const +{ + return mFolderRoot->getListener()->getUUID(); +} void LLInventoryPanel::rebuildViewsFor(const LLUUID& id, U32 mask) { - LLFolderViewItem* old_view = NULL; - - // get old LLFolderViewItem - old_view = mFolders->getItemByID(id); + // Destroy the old view for this ID so we can rebuild it. + LLFolderViewItem* old_view = mFolderRoot->getItemByID(id); if (old_view && id.notNull()) { old_view->destroyView(); @@ -1669,19 +1736,41 @@ void LLInventoryPanel::rebuildViewsFor(const LLUUID& id, U32 mask) buildNewViews(id); } +LLFolderViewFolder * LLInventoryPanel::createFolderViewFolder(LLInvFVBridge * bridge) +{ + return new LLFolderViewFolder( + bridge->getDisplayName(), + bridge->getIcon(), + mFolderRoot, + bridge); +} + +LLFolderViewItem * LLInventoryPanel::createFolderViewItem(LLInvFVBridge * bridge) +{ + return new LLFolderViewItem( + bridge->getDisplayName(), + bridge->getIcon(), + bridge->getCreationDate(), + mFolderRoot, + bridge); +} + void LLInventoryPanel::buildNewViews(const LLUUID& id) { + LLInventoryObject* const objectp = gInventory.getObject(id); LLFolderViewItem* itemp = NULL; - LLInventoryObject* objectp = gInventory.getObject(id); + if (objectp) - { + { + const LLUUID &parent_id = objectp->getParentUUID(); + LLFolderViewFolder* parent_folder = (LLFolderViewFolder*)mFolderRoot->getItemByID(parent_id); if (objectp->getType() <= LLAssetType::AT_NONE || objectp->getType() >= LLAssetType::AT_COUNT) { - llwarns << "LLInventoryPanel::buildNewViews called with objectp->mType == " - << ((S32) objectp->getType()) - << " (shouldn't happen)" << llendl; + llwarns << "LLInventoryPanel::buildNewViews called with invalid objectp->mType : " + << ((S32) objectp->getType()) << " name " << objectp->getName() << " UUID " << objectp->getUUID() + << llendl; } else if ((objectp->getType() == LLAssetType::AT_CATEGORY) && (objectp->getActualType() != LLAssetType::AT_LINK_FOLDER)) // build new view for category @@ -1693,13 +1782,9 @@ void LLInventoryPanel::buildNewViews(const LLUUID& id) objectp->getUUID()); if (new_listener) - { - LLFolderViewFolder* folderp = new LLFolderViewFolder(new_listener->getDisplayName(), - new_listener->getIcon(), - mFolders, - new_listener); - - folderp->setItemSortOrder(mFolders->getSortOrder()); + { + LLFolderViewFolder* folderp = createFolderViewFolder(new_listener); + folderp->setItemSortOrder(mFolderRoot->getSortOrder()); itemp = folderp; } } @@ -1713,23 +1798,19 @@ void LLInventoryPanel::buildNewViews(const LLUUID& id) this, item->getUUID(), item->getFlags()); - if (new_listener) - { - itemp = new LLFolderViewItem(new_listener->getDisplayName(), - new_listener->getIcon(), - new_listener->getCreationDate(), - mFolders, - new_listener); - } + if (new_listener) + { + itemp = createFolderViewItem(new_listener); + } } - LLFolderViewFolder* parent_folder = (LLFolderViewFolder*)mFolders->getItemByID(objectp->getParentUUID()); + if (itemp) { if (parent_folder) { - itemp->addToFolder(parent_folder, mFolders); + itemp->addToFolder(parent_folder, mFolderRoot); } else { @@ -1739,28 +1820,34 @@ void LLInventoryPanel::buildNewViews(const LLUUID& id) } } - if ((id.isNull() || - (objectp && objectp->getType() == LLAssetType::AT_CATEGORY))) + // If this is a folder, add the children of the folder and recursively add any + // child folders. + if (id.isNull() + || (objectp + && objectp->getType() == LLAssetType::AT_CATEGORY)) { LLViewerInventoryCategory::cat_array_t* categories; LLViewerInventoryItem::item_array_t* items; - mInventory->lockDirectDescendentArrays(id, categories, items); + if(categories) { - S32 count = categories->count(); - for(S32 i = 0; i < count; ++i) + for (LLViewerInventoryCategory::cat_array_t::const_iterator cat_iter = categories->begin(); + cat_iter != categories->end(); + ++cat_iter) { - LLInventoryCategory* cat = categories->get(i); + const LLViewerInventoryCategory* cat = (*cat_iter); buildNewViews(cat->getUUID()); } } + if(items) { - S32 count = items->count(); - for(S32 i = 0; i < count; ++i) + for (LLViewerInventoryItem::item_array_t::const_iterator item_iter = items->begin(); + item_iter != items->end(); + ++item_iter) { - LLInventoryItem* item = items->get(i); + const LLViewerInventoryItem* item = (*item_iter); buildNewViews(item->getUUID()); } } @@ -1803,20 +1890,26 @@ protected: void LLInventoryPanel::openSelected() { - LLFolderViewItem* folder_item = mFolders->getCurSelectedItem(); + LLFolderViewItem* folder_item = mFolderRoot->getCurSelectedItem(); if(!folder_item) return; LLInvFVBridge* bridge = (LLInvFVBridge*)folder_item->getListener(); if(!bridge) return; bridge->openItem(); } +void LLInventoryPanel::unSelectAll() +{ + mFolderRoot->setSelection(NULL, FALSE, FALSE); +} + + BOOL LLInventoryPanel::handleHover(S32 x, S32 y, MASK mask) { BOOL handled = LLView::handleHover(x, y, mask); if(handled) { ECursorType cursor = getWindow()->getCursor(); - if (LLInventoryModel::backgroundFetchActive() && cursor == UI_CURSOR_ARROW) + if (LLInventoryModelBackgroundFetch::instance().backgroundFetchActive() && cursor == UI_CURSOR_ARROW) { // replace arrow cursor with arrow and hourglass cursor getWindow()->setCursor(UI_CURSOR_WORKING); @@ -1840,7 +1933,7 @@ BOOL LLInventoryPanel::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, if (handled) { - mFolders->setDragAndDropThisFrame(); + mFolderRoot->setDragAndDropThisFrame(); } return handled; @@ -1849,26 +1942,26 @@ BOOL LLInventoryPanel::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, void LLInventoryPanel::openAllFolders() { - mFolders->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_DOWN); - mFolders->arrangeAll(); + mFolderRoot->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_DOWN); + mFolderRoot->arrangeAll(); } void LLInventoryPanel::closeAllFolders() { - mFolders->setOpenArrangeRecursively(FALSE, LLFolderViewFolder::RECURSE_DOWN); - mFolders->arrangeAll(); + mFolderRoot->setOpenArrangeRecursively(FALSE, LLFolderViewFolder::RECURSE_DOWN); + mFolderRoot->arrangeAll(); } void LLInventoryPanel::openDefaultFolderForType(LLAssetType::EType type) { LLUUID category_id = mInventory->findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(type)); LLOpenFolderByID opener(category_id); - mFolders->applyFunctorRecursively(opener); + mFolderRoot->applyFunctorRecursively(opener); } void LLInventoryPanel::setSelection(const LLUUID& obj_id, BOOL take_keyboard_focus) { - LLFolderViewItem* itemp = mFolders->getItemByID(obj_id); + LLFolderViewItem* itemp = mFolderRoot->getItemByID(obj_id); if(itemp && itemp->getListener()) { itemp->getListener()->arrangeAndSet(itemp, TRUE, take_keyboard_focus); @@ -1881,10 +1974,16 @@ void LLInventoryPanel::setSelection(const LLUUID& obj_id, BOOL take_keyboard_foc mSelectThisID = obj_id; } } - +void LLInventoryPanel::setSelectCallback(LLFolderView::SelectCallback callback, void* user_data) +{ + if (mFolderRoot) + { + mFolderRoot->setSelectCallback(callback, user_data); + } +} void LLInventoryPanel::clearSelection() { - mFolders->clearSelection(); + mFolderRoot->clearSelection(); mSelectThisID.setNull(); } @@ -1916,9 +2015,15 @@ void LLInventoryPanel::createNewItem(const std::string& name, } -// static DEBUG ONLY: +BOOL LLInventoryPanel::getSinceLogoff() +{ + return getFilter()->isSinceLogoff(); +} + +// DEBUG ONLY +// static void LLInventoryPanel::dumpSelectionInformation(void* user_data) { LLInventoryPanel* iv = (LLInventoryPanel*)user_data; - iv->mFolders->dumpSelectionInformation(); + iv->mFolderRoot->dumpSelectionInformation(); } diff --git a/indra/newview/llinventoryview.h b/indra/newview/llinventoryview.h index 24fd127c0..1a48ccd94 100644 --- a/indra/newview/llinventoryview.h +++ b/indra/newview/llinventoryview.h @@ -69,11 +69,6 @@ class LLSearchEditor; class LLInventoryPanel : public LLPanel { public: - static const std::string DEFAULT_SORT_ORDER; - static const std::string RECENTITEMS_SORT_ORDER; - static const std::string WORNITEMS_SORT_ORDER; - static const std::string INHERIT_SORT_ORDER; - LLInventoryPanel(const std::string& name, const std::string& sort_order_setting, const LLRect& rect, @@ -103,38 +98,36 @@ public: void closeAllFolders(); void openDefaultFolderForType(LLAssetType::EType); void setSelection(const LLUUID& obj_id, BOOL take_keyboard_focus); - void setSelectCallback(LLFolderView::SelectCallback callback, void* user_data) { if (mFolders) mFolders->setSelectCallback(callback, user_data); } + void setSelectCallback(LLFolderView::SelectCallback callback, void* user_data); void clearSelection(); - LLInventoryFilter* getFilter() { return mFolders->getFilter(); } + LLInventoryFilter* getFilter(); + const LLInventoryFilter* getFilter() const; void setFilterTypes(U32 filter); - U32 getFilterTypes() const { return mFolders->getFilterTypes(); } + U32 getFilterTypes() const; void setFilterPermMask(PermissionMask filter_perm_mask); - U32 getFilterPermMask() const { return mFolders->getFilterPermissions(); } + U32 getFilterPermMask() const; void setFilterSubString(const std::string& string); - const std::string getFilterSubString() { return mFolders->getFilterSubString(); } + const std::string getFilterSubString(); void setFilterWorn(bool worn); - bool getFilterWorn() const { return mFolders->getFilterWorn(); } + bool getFilterWorn() const { return mFolderRoot->getFilterWorn(); } - void setSortOrder(U32 order); - U32 getSortOrder() { return mFolders->getSortOrder(); } void setSinceLogoff(BOOL sl); void setHoursAgo(U32 hours); - BOOL getSinceLogoff() { return mFolders->getFilter()->isSinceLogoff(); } + BOOL getSinceLogoff(); void setShowFolderState(LLInventoryFilter::EFolderShow show); LLInventoryFilter::EFolderShow getShowFolderState(); - void setAllowMultiSelect(BOOL allow) { mFolders->setAllowMultiSelect(allow); } + void setAllowMultiSelect(BOOL allow) { mFolderRoot->setAllowMultiSelect(allow); } // This method is called when something has changed about the inventory. void modelChanged(U32 mask); - LLFolderView* getRootFolder() { return mFolders; } + LLFolderView* getRootFolder(); LLScrollableContainerView* getScrollableContainer() { return mScroller; } // DEBUG ONLY: static void dumpSelectionInformation(void* user_data); void openSelected(); - - void unSelectAll() { mFolders->setSelection(NULL, FALSE, FALSE); } + void unSelectAll(); protected: // Given the id and the parent, build all of the folder views. @@ -155,11 +148,31 @@ public: protected: LLInventoryModel* mInventory; LLInventoryObserver* mInventoryObserver; - LLFolderView* mFolders; - LLScrollableContainerView* mScroller; + + BOOL mAllowMultiSelect; + LLFolderView* mFolderRoot; + LLScrollableContainerView* mScroller; + //-------------------------------------------------------------------- + // Sorting + //-------------------------------------------------------------------- +public: + static const std::string DEFAULT_SORT_ORDER; + static const std::string RECENTITEMS_SORT_ORDER; + static const std::string WORNITEMS_SORT_ORDER; + static const std::string INHERIT_SORT_ORDER; + + void setSortOrder(U32 order); + U32 getSortOrder() const; +private: const std::string mSortOrderSetting; LLUUID mSelectThisID; // if non null, select this item + +public: + const LLUUID& getRootFolderID() const; +protected: + virtual LLFolderViewFolder* createFolderViewFolder(LLInvFVBridge * bridge); + virtual LLFolderViewItem* createFolderViewItem(LLInvFVBridge * bridge); }; class LLInventoryView; diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 8036d18bc..ea8bbd009 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -34,6 +34,7 @@ #include "llagent.h" #include "llappviewer.h" #include "llbufferstream.h" +#include "llcallbacklist.h" #include "llcurl.h" #include "lldatapacker.h" #include "llfasttimer.h" @@ -73,8 +74,8 @@ #include -//LLFastTimer::DeclareTimer FTM_MESH_UPDATE("Mesh Update"); -//LLFastTimer::DeclareTimer FTM_LOAD_MESH("Load Mesh"); +LLFastTimer::DeclareTimer FTM_MESH_UPDATE("Mesh Update"); +LLFastTimer::DeclareTimer FTM_LOAD_MESH("Load Mesh"); LLMeshRepository gMeshRepo; @@ -2164,7 +2165,7 @@ S32 LLMeshRepository::loadMesh(LLVOVolume* vobj, const LLVolumeParams& mesh_para return detail; } - //LLFastTimer t(LLFastTimer::FTM_LOAD_MESH); + LLFastTimer t(FTM_LOAD_MESH); { LLMutexLock lock(mMeshMutex); @@ -2236,10 +2237,10 @@ S32 LLMeshRepository::loadMesh(LLVOVolume* vobj, const LLVolumeParams& mesh_para return detail; } -/*static LLFastTimer::DeclareTimer FTM_START_MESH_THREAD("Start Thread"); +//static LLFastTimer::DeclareTimer FTM_START_MESH_THREAD("Start Thread"); static LLFastTimer::DeclareTimer FTM_LOAD_MESH_LOD("Load LOD"); static LLFastTimer::DeclareTimer FTM_MESH_LOCK1("Lock 1"); -static LLFastTimer::DeclareTimer FTM_MESH_LOCK2("Lock 2");*/ +static LLFastTimer::DeclareTimer FTM_MESH_LOCK2("Lock 2"); void LLMeshRepository::notifyLoadedMeshes() { //called from main thread @@ -2342,15 +2343,15 @@ void LLMeshRepository::notifyLoadedMeshes() } } - LLFastTimer t(LLFastTimer::FTM_MESH_UPDATE); + LLFastTimer t(FTM_MESH_UPDATE); { - LLFastTimer t(LLFastTimer::FTM_MESH_LOCK1); + LLFastTimer t(FTM_MESH_LOCK1); mMeshMutex->lock(); } { - LLFastTimer t(LLFastTimer::FTM_MESH_LOCK2); + LLFastTimer t(FTM_MESH_LOCK2); mThread->mMutex->lock(); } @@ -2405,7 +2406,7 @@ void LLMeshRepository::notifyLoadedMeshes() while (!mPendingRequests.empty() && push_count > 0) { - LLFastTimer t(LLFastTimer::FTM_LOAD_MESH_LOD); + LLFastTimer t(FTM_LOAD_MESH_LOD); LLMeshRepoThread::LODRequest& request = mPendingRequests.front(); mThread->loadMeshLOD(request.mMeshParams, request.mLOD); mPendingRequests.erase(mPendingRequests.begin()); diff --git a/indra/newview/llnetmap.cpp b/indra/newview/llnetmap.cpp index 1adf1f6a0..716dc1b8b 100644 --- a/indra/newview/llnetmap.cpp +++ b/indra/newview/llnetmap.cpp @@ -39,6 +39,7 @@ #include "llui.h" #include "llmath.h" // clampf() #include "llfocusmgr.h" +#include "lllocalcliprect.h" #include "llrender.h" #include "llfloateravatarlist.h" diff --git a/indra/newview/llpreviewgesture.cpp b/indra/newview/llpreviewgesture.cpp index ad22dce4c..a968f6e12 100644 --- a/indra/newview/llpreviewgesture.cpp +++ b/indra/newview/llpreviewgesture.cpp @@ -56,6 +56,7 @@ #include "llfloatergesture.h" // for some label constants #include "llgesturemgr.h" #include "llinventoryfunctions.h" +#include "llinventorymodelbackgroundfetch.h" #include "llkeyboard.h" #include "lllineeditor.h" #include "llnotificationsutil.h" @@ -158,10 +159,10 @@ LLPreviewGesture* LLPreviewGesture::show(const std::string& title, const LLUUID& // Start speculative download of sounds and animations LLUUID animation_folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_ANIMATION); - gInventory.startBackgroundFetch(animation_folder_id); + LLInventoryModelBackgroundFetch::instance().start(animation_folder_id); LLUUID sound_folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_SOUND); - gInventory.startBackgroundFetch(sound_folder_id); + LLInventoryModelBackgroundFetch::instance().start(sound_folder_id); // this will call refresh when we have everything. LLViewerInventoryItem* item = (LLViewerInventoryItem*)self->getItem(); diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index 72de68d0c..1733cac0d 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -5571,38 +5571,37 @@ BOOL LLSelectNode::allowOperationOnNode(PermissionBit op, U64 group_proxy_power) //helper function for pushing relevant vertices from drawable to GL void pushWireframe(LLDrawable* drawable) { - if (drawable->isState(LLDrawable::RIGGED)) - { //render straight from rigged volume if this is a rigged attachment - LLVOVolume* vobj = drawable->getVOVolume(); - if (vobj) - { - vobj->updateRiggedVolume(); - LLRiggedVolume* rigged_volume = vobj->getRiggedVolume(); - if (rigged_volume) - { - LLVertexBuffer::unbind(); - gGL.pushMatrix(); - gGL.multMatrix((F32*) vobj->getRelativeXform().mMatrix); - for (S32 i = 0; i < rigged_volume->getNumVolumeFaces(); ++i) - { - const LLVolumeFace& face = rigged_volume->getVolumeFace(i); - LLVertexBuffer::drawElements(LLRender::TRIANGLES, face.mPositions, face.mTexCoords, face.mNumIndices, face.mIndices); - } - gGL.popMatrix(); - } - } - } - else + LLVOVolume* vobj = drawable->getVOVolume(); + if (vobj) { - for (S32 i = 0; i < drawable->getNumFaces(); ++i) + LLVertexBuffer::unbind(); + gGL.pushMatrix(); + gGL.multMatrix((F32*) vobj->getRelativeXform().mMatrix); + + LLVolume* volume = NULL; + + if (drawable->isState(LLDrawable::RIGGED)) { - LLFace* face = drawable->getFace(i); - if (face->verify()) + vobj->updateRiggedVolume(); + volume = vobj->getRiggedVolume(); + } + else + { + volume = vobj->getVolume(); + } + + if (volume) + { + for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i) { - pushVerts(face, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0); + const LLVolumeFace& face = volume->getVolumeFace(i); + LLVertexBuffer::drawElements(LLRender::TRIANGLES, face.mPositions, face.mTexCoords, face.mNumIndices, face.mIndices); } } + + gGL.popMatrix(); } + } void LLSelectNode::renderOneWireframe(const LLColor4& color) diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp index 83c9833c4..2cdaefa2f 100644 --- a/indra/newview/llspatialpartition.cpp +++ b/indra/newview/llspatialpartition.cpp @@ -34,6 +34,10 @@ #include "llspatialpartition.h" +#include "llappviewer.h" +#include "lltexturecache.h" +#include "lltexturefetch.h" +#include "llimageworker.h" #include "llviewerwindow.h" #include "llviewerobjectlist.h" #include "llvovolume.h" @@ -43,19 +47,21 @@ #include "llface.h" #include "llfloatertools.h" #include "llviewercontrol.h" -#include "llagent.h" #include "llviewerregion.h" #include "llcamera.h" #include "pipeline.h" #include "llmeshrepository.h" #include "llrender.h" #include "lloctree.h" -#include "llvoavatar.h" +#include "llphysicsshapebuilderutil.h" #include "llvoavatar.h" #include "llvolumemgr.h" #include "llglslshader.h" #include "llviewershadermgr.h" +static LLFastTimer::DeclareTimer FTM_FRUSTUM_CULL("Frustum Culling"); +static LLFastTimer::DeclareTimer FTM_CULL_REBOUND("Cull Rebound"); + const F32 SG_OCCLUSION_FUDGE = 0.25f; #define SG_DISCARD_TOLERANCE 0.01f @@ -260,11 +266,11 @@ U8* get_box_fan_indices_ptr(LLCamera* camera, const LLVector4a& center) return (U8*) (sOcclusionIndices+cypher*8); } +static LLFastTimer::DeclareTimer FTM_BUILD_OCCLUSION("Build Occlusion"); void LLSpatialGroup::buildOcclusion() { - if (mOcclusionVerts.isNull()) + //if (mOcclusionVerts.isNull()) { - mOcclusionVerts = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX, LLVertexBuffer::sUseStreamDraw ? mBufferUsage : 0); //if GL has a hard time with VBOs, don't use them for occlusion culling. mOcclusionVerts->allocateBuffer(8, 64, true); @@ -286,7 +292,7 @@ void LLSpatialGroup::buildOcclusion() LLStrider pos; { - //LLFastTimer t(LLFastTimer::FTM_BUILD_OCCLUSION); + LLFastTimer t(FTM_BUILD_OCCLUSION); mOcclusionVerts->getVertexStrider(pos); } @@ -573,6 +579,8 @@ void LLSpatialGroup::rebuildMesh() } } +static LLFastTimer::DeclareTimer FTM_REBUILD_VBO("VBO Rebuilt"); + void LLSpatialPartition::rebuildGeom(LLSpatialGroup* group) { /*if (!gPipeline.hasRenderType(mDrawableType)) @@ -595,7 +603,7 @@ void LLSpatialPartition::rebuildGeom(LLSpatialGroup* group) group->mLastUpdateViewAngle = group->mViewAngle; } - LLFastTimer ftm(LLFastTimer::FTM_REBUILD_VBO); + LLFastTimer ftm(FTM_REBUILD_VBO); group->clearDrawMap(); @@ -608,7 +616,9 @@ void LLSpatialPartition::rebuildGeom(LLSpatialGroup* group) if (vertex_count > 0 && index_count > 0) { //create vertex buffer containing volume geometry for this node group->mBuilt = 1.f; - if (group->mVertexBuffer.isNull() || (group->mBufferUsage != group->mVertexBuffer->getUsage() && LLVertexBuffer::sEnableVBOs)) + if (group->mVertexBuffer.isNull() || + !group->mVertexBuffer->isWriteable() || + (group->mBufferUsage != group->mVertexBuffer->getUsage() && LLVertexBuffer::sEnableVBOs)) { group->mVertexBuffer = createVertexBuffer(mVertexDataMask, group->mBufferUsage); group->mVertexBuffer->allocateBuffer(vertex_count, index_count, true); @@ -1106,6 +1116,7 @@ LLSpatialGroup::LLSpatialGroup(OctreeNode* node, LLSpatialPartition* part) : for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++) { mOcclusionQuery[i] = 0; + mOcclusionIssued[i] = 0; mOcclusionState[i] = parent ? SG_STATE_INHERIT_MASK & parent->mOcclusionState[i] : 0; mVisible[i] = 0; } @@ -1428,11 +1439,13 @@ BOOL LLSpatialGroup::rebound() return TRUE; } +static LLFastTimer::DeclareTimer FTM_OCCLUSION_READBACK("Readback Occlusion"); +static LLFastTimer::DeclareTimer FTM_OCCLUSION_WAIT("Wait"); void LLSpatialGroup::checkOcclusion() { if (LLPipeline::sUseOcclusion > 1) { - LLFastTimer t( LLFastTimer::FTM_OCCLUSION_READBACK); + LLFastTimer t(FTM_OCCLUSION_READBACK); LLSpatialGroup* parent = getParent(); if (parent && parent->isOcclusionState(LLSpatialGroup::OCCLUDED)) { //if the parent has been marked as occluded, the child is implicitly occluded @@ -1440,10 +1453,27 @@ void LLSpatialGroup::checkOcclusion() } else if (isOcclusionState(QUERY_PENDING)) { //otherwise, if a query is pending, read it back + GLuint available = 0; if (mOcclusionQuery[LLViewerCamera::sCurCameraID]) { glGetQueryObjectuivARB(mOcclusionQuery[LLViewerCamera::sCurCameraID], GL_QUERY_RESULT_AVAILABLE_ARB, &available); + + if (mOcclusionIssued[LLViewerCamera::sCurCameraID] < gFrameCount) + { //query was issued last frame, wait until it's available + S32 max_loop = 1024; + LLFastTimer t(FTM_OCCLUSION_WAIT); + while (!available && max_loop-- > 0) + { + F32 max_time = llmin(gFrameIntervalSeconds*10.f, 1.f); + //do some usefu work while we wait + LLAppViewer::getTextureCache()->update(max_time); // unpauses the texture cache thread + LLAppViewer::getImageDecodeThread()->update(max_time); // unpauses the image thread + LLAppViewer::getTextureFetch()->update(max_time); // unpauses the texture fetch thread + + glGetQueryObjectuivARB(mOcclusionQuery[LLViewerCamera::sCurCameraID], GL_QUERY_RESULT_AVAILABLE_ARB, &available); + } + } } else { @@ -1496,6 +1526,19 @@ void LLSpatialGroup::checkOcclusion() } } +static LLFastTimer::DeclareTimer FTM_PUSH_OCCLUSION_VERTS("Push Occlusion"); +static LLFastTimer::DeclareTimer FTM_SET_OCCLUSION_STATE("Occlusion State"); +static LLFastTimer::DeclareTimer FTM_OCCLUSION_EARLY_FAIL("Occlusion Early Fail"); +static LLFastTimer::DeclareTimer FTM_OCCLUSION_ALLOCATE("Allocate"); +static LLFastTimer::DeclareTimer FTM_OCCLUSION_BUILD("Build"); +static LLFastTimer::DeclareTimer FTM_OCCLUSION_BEGIN_QUERY("Begin Query"); +static LLFastTimer::DeclareTimer FTM_OCCLUSION_END_QUERY("End Query"); +static LLFastTimer::DeclareTimer FTM_OCCLUSION_SET_BUFFER("Set Buffer"); +static LLFastTimer::DeclareTimer FTM_OCCLUSION_DRAW_WATER("Draw Water"); +static LLFastTimer::DeclareTimer FTM_OCCLUSION_DRAW("Draw"); + + + void LLSpatialGroup::doOcclusion(LLCamera* camera) { if (mSpatialPartition->isOcclusionEnabled() && LLPipeline::sUseOcclusion > 1) @@ -1506,6 +1549,7 @@ void LLSpatialGroup::doOcclusion(LLCamera* camera) // earlyFail(camera, this)) if (earlyFail(camera, this)) { + LLFastTimer t(FTM_OCCLUSION_EARLY_FAIL); setOcclusionState(LLSpatialGroup::DISCARD_QUERY); assert_states_valid(this); clearOcclusionState(LLSpatialGroup::OCCLUDED, LLSpatialGroup::STATE_MODE_DIFF); @@ -1516,15 +1560,17 @@ void LLSpatialGroup::doOcclusion(LLCamera* camera) if (!isOcclusionState(QUERY_PENDING) || isOcclusionState(DISCARD_QUERY)) { { //no query pending, or previous query to be discarded - //LLFastTimer t(FTM_RENDER_OCCLUSION); + LLFastTimer t(FTM_RENDER_OCCLUSION); if (!mOcclusionQuery[LLViewerCamera::sCurCameraID]) { + LLFastTimer t(FTM_OCCLUSION_ALLOCATE); mOcclusionQuery[LLViewerCamera::sCurCameraID] = sQueryPool.allocate(); } if (mOcclusionVerts.isNull() || isState(LLSpatialGroup::OCCLUSION_DIRTY)) { + LLFastTimer t(FTM_OCCLUSION_BUILD); buildOcclusion(); } @@ -1548,13 +1594,25 @@ void LLSpatialGroup::doOcclusion(LLCamera* camera) #endif { - //LLFastTimer t(FTM_PUSH_OCCLUSION_VERTS); - glBeginQueryARB(mode, mOcclusionQuery[LLViewerCamera::sCurCameraID]); + LLFastTimer t(FTM_PUSH_OCCLUSION_VERTS); + + //store which frame this query was issued on + mOcclusionIssued[LLViewerCamera::sCurCameraID] = gFrameCount; + + { + LLFastTimer t(FTM_OCCLUSION_BEGIN_QUERY); + glBeginQueryARB(mode, mOcclusionQuery[LLViewerCamera::sCurCameraID]); + } - mOcclusionVerts->setBuffer(LLVertexBuffer::MAP_VERTEX); + { + LLFastTimer t(FTM_OCCLUSION_SET_BUFFER); + mOcclusionVerts->setBuffer(LLVertexBuffer::MAP_VERTEX); + } if (!use_depth_clamp && mSpatialPartition->mDrawableType == LLDrawPool::POOL_VOIDWATER) { + LLFastTimer t(FTM_OCCLUSION_DRAW_WATER); + LLGLSquashToFarClip squash(glh_get_current_projection(), 1); if (camera->getOrigin().isExactlyZero()) { //origin is invalid, draw entire box @@ -1568,6 +1626,7 @@ void LLSpatialGroup::doOcclusion(LLCamera* camera) } else { + LLFastTimer t(FTM_OCCLUSION_DRAW); if (camera->getOrigin().isExactlyZero()) { //origin is invalid, draw entire box mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, 0); @@ -1578,13 +1637,17 @@ void LLSpatialGroup::doOcclusion(LLCamera* camera) mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, mBounds[0])); } } - - glEndQueryARB(mode); + + + { + LLFastTimer t(FTM_OCCLUSION_END_QUERY); + glEndQueryARB(mode); + } } } - + { - //LLFastTimer t(FTM_SET_OCCLUSION_STATE); + LLFastTimer t(FTM_SET_OCCLUSION_STATE); setOcclusionState(LLSpatialGroup::QUERY_PENDING); clearOcclusionState(LLSpatialGroup::DISCARD_QUERY); } @@ -2162,7 +2225,7 @@ BOOL LLSpatialPartition::getVisibleExtents(LLCamera& camera, LLVector3& visMin, visMina.load3(visMin.mV); visMaxa.load3(visMax.mV); { - LLFastTimer ftm( LLFastTimer::FTM_CULL_REBOUND); + LLFastTimer ftm(FTM_CULL_REBOUND); LLSpatialGroup* group = (LLSpatialGroup*) mOctree->getListener(0); group->rebound(); } @@ -2191,7 +2254,7 @@ S32 LLSpatialPartition::cull(LLCamera &camera, std::vector* result { //BOOL temp = sFreezeState; //sFreezeState = FALSE; - LLFastTimer ftm(LLFastTimer::FTM_CULL_REBOUND); + LLFastTimer ftm(FTM_CULL_REBOUND); LLSpatialGroup* group = (LLSpatialGroup*) mOctree->getListener(0); group->rebound(); //sFreezeState = temp; @@ -2209,19 +2272,19 @@ S32 LLSpatialPartition::cull(LLCamera &camera, std::vector* result } else if (LLPipeline::sShadowRender) { - LLFastTimer ftm(LLFastTimer::FTM_FRUSTUM_CULL); + LLFastTimer ftm(FTM_FRUSTUM_CULL); LLOctreeCullShadow culler(&camera); culler.traverse(mOctree); } else if (mInfiniteFarClip || !LLPipeline::sUseFarClip) { - LLFastTimer ftm(LLFastTimer::FTM_FRUSTUM_CULL); + LLFastTimer ftm(FTM_FRUSTUM_CULL); LLOctreeCullNoFarClip culler(&camera); culler.traverse(mOctree); } else { - LLFastTimer ftm(LLFastTimer::FTM_FRUSTUM_CULL); + LLFastTimer ftm(FTM_FRUSTUM_CULL); LLOctreeCull culler(&camera); culler.traverse(mOctree); } @@ -2987,11 +3050,7 @@ void renderRaycast(LLDrawable* drawablep) for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i) { const LLVolumeFace& face = volume->getVolumeFace(i); - if (!face.mOctree) - { - ((LLVolumeFace*) &face)->createOctree(); - } - + gGL.pushMatrix(); gGL.translatef(trans.mV[0], trans.mV[1], trans.mV[2]); gGL.multMatrix((F32*) vobj->getRelativeXform().mMatrix); @@ -3014,9 +3073,6 @@ void renderRaycast(LLDrawable* drawablep) LLVector4a dir; dir.setSub(enda, starta); - F32 t = 1.f; - - LLRenderOctreeRaycast render(starta, dir, &t); gGL.flush(); glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); @@ -3028,8 +3084,20 @@ void renderRaycast(LLDrawable* drawablep) gGL.syncMatrices(); glDrawElements(GL_TRIANGLES, face.mNumIndices, GL_UNSIGNED_SHORT, face.mIndices); } - - render.traverse(face.mOctree); + + if (!volume->isUnique()) + { + F32 t = 1.f; + + if (!face.mOctree) + { + ((LLVolumeFace*) &face)->createOctree(); + } + + LLRenderOctreeRaycast render(starta, dir, &t); + + render.traverse(face.mOctree); + } gGL.popMatrix(); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); } diff --git a/indra/newview/llspatialpartition.h b/indra/newview/llspatialpartition.h index f43a21d6a..c36b29752 100644 --- a/indra/newview/llspatialpartition.h +++ b/indra/newview/llspatialpartition.h @@ -46,7 +46,7 @@ #include "lldrawpool.h" #include "llface.h" #include "llviewercamera.h" - +#include "llvector4a.h" #include #define SG_STATE_INHERIT_MASK (OCCLUDED) @@ -368,6 +368,7 @@ protected: U32 mState; U32 mOcclusionState[LLViewerCamera::NUM_CAMERAS]; + U32 mOcclusionIssued[LLViewerCamera::NUM_CAMERAS]; S32 mLODHash; static S32 sLODSeed; diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 885a07e44..d678dc490 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -129,6 +129,7 @@ #include "llimagebmp.h" #include "llimview.h" // for gIMMgr #include "llinventoryfunctions.h" +#include "llinventorymodelbackgroundfetch.h" #include "llinventoryview.h" #include "llkeyboard.h" #include "llloginhandler.h" // gLoginHandler, SLURL support @@ -322,10 +323,10 @@ namespace }; } -class LLGestureInventoryFetchObserver : public LLInventoryFetchObserver +class LLGestureInventoryFetchObserver : public LLInventoryFetchItemsObserver { public: - LLGestureInventoryFetchObserver() {} + LLGestureInventoryFetchObserver(const uuid_vec_t& item_ids) : LLInventoryFetchItemsObserver(item_ids) {} virtual void done() { // we've downloaded all the items, so repaint the dialog @@ -845,10 +846,13 @@ bool idle_startup() { // Initialize all our tools. Must be done after saved settings loaded. // NOTE: This also is where gToolMgr used to be instantiated before being turned into a singleton. + display_startup(); LLToolMgr::getInstance()->initTools(); + display_startup(); // Quickly get something onscreen to look at. gViewerWindow->initWorldUI(); + display_startup(); } if (show_connect_box) @@ -863,15 +867,18 @@ bool idle_startup() LL_ERRS("AppInit") << "Need to autologin or use command line with norender!" << LL_ENDL; } // Make sure the process dialog doesn't hide things + display_startup(); gViewerWindow->setShowProgress(FALSE); - + display_startup(); + // Load login history std::string login_hist_filepath = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "saved_logins_sg2.xml"); LLSavedLogins login_history = LLSavedLogins::loadFile(login_hist_filepath); - + display_startup(); + // Show the login dialog. login_show(login_history); - + display_startup(); if (login_history.size() > 0) { LLPanelLogin::setFields(*login_history.getEntries().rbegin()); @@ -884,6 +891,7 @@ bool idle_startup() // LLPanelLogin::giveFocus(); } + display_startup(); gSavedSettings.setBOOL("FirstRunThisInstall", FALSE); @@ -895,9 +903,13 @@ bool idle_startup() LLStartUp::setStartupState( STATE_LOGIN_CLEANUP ); } + display_startup(); gViewerWindow->setNormalControlsVisible( FALSE ); + display_startup(); gLoginMenuBarView->setVisible( TRUE ); + display_startup(); gLoginMenuBarView->setEnabled( TRUE ); + display_startup(); // Push our window frontmost gViewerWindow->getWindow()->show(); @@ -907,7 +919,10 @@ bool idle_startup() // first made visible. #ifdef _WIN32 MSG msg; - while( PeekMessage( &msg, /*All hWnds owned by this thread */ NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE ) ); + while( PeekMessage( &msg, /*All hWnds owned by this thread */ NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE ) ) + { + display_startup(); + } #endif timeout.reset(); return FALSE; @@ -917,7 +932,7 @@ bool idle_startup() { // Don't do anything. Wait for the login view to call the login_callback, // which will push us to the next state. - + display_startup(); // Sleep so we don't spin the CPU ms_sleep(1); return FALSE; @@ -1926,8 +1941,11 @@ bool idle_startup() // Finish agent initialization. (Requires gSavedSettings, builds camera) gAgent.init(); + display_startup(); gAgentCamera.init(); + display_startup(); set_underclothes_menu_options(); + display_startup(); // Since we connected, save off the settings so the user doesn't have to // type the name/password again if we crash. @@ -1937,18 +1955,24 @@ bool idle_startup() // Initialize classes w/graphics stuff. // gTextureList.doPrefetchImages(); + display_startup(); + LLSurface::initClasses(); + display_startup(); + LLFace::initClass(); + display_startup(); LLDrawable::initClass(); + display_startup(); // init the shader managers AscentDayCycleManager::initClass(); + display_startup(); // RN: don't initialize VO classes in drone mode, they are too closely tied to rendering LLViewerObject::initVOClasses(); - display_startup(); // This is where we used to initialize gWorldp. Original comment said: @@ -1956,24 +1980,26 @@ bool idle_startup() // User might have overridden far clip LLWorld::getInstance()->setLandFarClip( gAgentCamera.mDrawDistance ); - + display_startup(); // Before we create the first region, we need to set the agent's mOriginGlobal // This is necessary because creating objects before this is set will result in a // bad mPositionAgent cache. gAgent.initOriginGlobal(from_region_handle(gFirstSimHandle)); + display_startup(); LLWorld::getInstance()->addRegion(gFirstSimHandle, gFirstSim); + display_startup(); LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(gFirstSimHandle); LL_INFOS("AppInit") << "Adding initial simulator " << regionp->getOriginGlobal() << LL_ENDL; regionp->setSeedCapability(gFirstSimSeedCap); LL_DEBUGS("AppInit") << "Waiting for seed grant ...." << LL_ENDL; - + display_startup(); // Set agent's initial region to be the one we just created. gAgent.setRegion(regionp); - + display_startup(); // Set agent's initial position, which will be read by LLVOAvatar when the avatar // object is created. I think this must be done after setting the region. JC gAgent.setPositionAgent(agent_start_position_region); @@ -1994,6 +2020,7 @@ bool idle_startup() { LLStartUp::multimediaInit(); LLStartUp::setStartupState( STATE_FONT_INIT ); + display_startup(); return FALSE; } @@ -2002,6 +2029,7 @@ bool idle_startup() { LLStartUp::fontInit(); LLStartUp::setStartupState( STATE_SEED_GRANTED_WAIT ); + display_startup(); return FALSE; } @@ -2039,7 +2067,9 @@ bool idle_startup() //--------------------------------------------------------------------- if (STATE_SEED_CAP_GRANTED == LLStartUp::getStartupState()) { + display_startup(); update_texture_fetch(); + display_startup(); if ( gViewerWindow != NULL) { // This isn't the first logon attempt, so show the UI @@ -2047,7 +2077,7 @@ bool idle_startup() } gLoginMenuBarView->setVisible( FALSE ); gLoginMenuBarView->setEnabled( FALSE ); - + display_startup(); LLRect window(0, gViewerWindow->getWindowHeight(), gViewerWindow->getWindowWidth(), 0); gViewerWindow->adjustControlRectanglesForFirstUse(window); @@ -2094,17 +2124,22 @@ bool idle_startup() { //Set up cloud rendertypes. Passed argument is unused. handleCloudSettingsChanged(LLSD()); - + display_startup(); + // Move the progress view in front of the UI gViewerWindow->moveProgressViewToFront(); - + display_startup(); + LLError::logToFixedBuffer(gDebugView->mDebugConsolep); + display_startup(); // set initial visibility of debug console gDebugView->mDebugConsolep->setVisible(gSavedSettings.getBOOL("ShowDebugConsole")); + display_startup(); if (gSavedSettings.getBOOL("ShowDebugStats")) { LLFloaterStats::showInstance(); + display_startup(); } } @@ -2115,24 +2150,30 @@ bool idle_startup() // register callbacks for messages. . . do this after initial handshake to make sure that we don't catch any unwanted register_viewer_callbacks(gMessageSystem); + display_startup(); // Debugging info parameters gMessageSystem->setMaxMessageTime( 0.5f ); // Spam if decoding all msgs takes more than 500 ms + display_startup(); #ifndef LL_RELEASE_FOR_DOWNLOAD gMessageSystem->setTimeDecodes( TRUE ); // Time the decode of each msg gMessageSystem->setTimeDecodesSpamThreshold( 0.05f ); // Spam if a single msg takes over 50ms to decode #endif + display_startup(); gXferManager->registerCallbacks(gMessageSystem); + display_startup(); LLStartUp::initNameCache(); + display_startup(); // *Note: this is where gWorldMap used to be initialized. // register null callbacks for audio until the audio system is initialized gMessageSystem->setHandlerFuncFast(_PREHASH_SoundTrigger, null_message_callback, NULL); gMessageSystem->setHandlerFuncFast(_PREHASH_AttachedSound, null_message_callback, NULL); + display_startup(); //reset statistics LLViewerStats::getInstance()->resetStats(); @@ -2142,6 +2183,7 @@ bool idle_startup() // // Set up all of our statistics UI stuff. // + display_startup(); init_stat_view(); } @@ -2177,6 +2219,7 @@ bool idle_startup() } // Initialize FOV LLViewerCamera::getInstance()->setDefaultFOV(gSavedSettings.getF32("CameraAngle")); + display_startup(); // Move agent to starting location. The position handed to us by // the space server is in global coordinates, but the agent frame @@ -2187,6 +2230,7 @@ bool idle_startup() gAgent.resetAxes(agent_start_look_at); gAgentCamera.stopCameraAnimation(); gAgentCamera.resetCamera(); + display_startup(); // Initialize global class data needed for surfaces (i.e. textures) if (!gNoRender) @@ -2202,6 +2246,8 @@ bool idle_startup() LLGLState::checkTextureChannels(); } + display_startup(); + LL_DEBUGS("AppInit") << "Decoding images..." << LL_ENDL; // For all images pre-loaded into viewer cache, decode them. // Need to do this AFTER we init the sky @@ -2215,6 +2261,8 @@ bool idle_startup() } LLStartUp::setStartupState( STATE_WORLD_WAIT ); + display_startup(); + // JC - Do this as late as possible to increase likelihood Purify // will run. LLMessageSystem* msg = gMessageSystem; @@ -2242,6 +2290,7 @@ bool idle_startup() NULL); timeout.reset(); + display_startup(); return FALSE; } @@ -2260,8 +2309,10 @@ bool idle_startup() LLMessageSystem* msg = gMessageSystem; while (msg->checkAllMessages(gFrameCount, gServicePump)) { + display_startup(); } msg->processAcks(); + display_startup(); return FALSE; } @@ -2272,6 +2323,7 @@ bool idle_startup() { LL_DEBUGS("AppInit") << "Connecting to region..." << LL_ENDL; set_startup_status(0.60f, LLTrans::getString("LoginConnectingToRegion"), gAgent.mMOTD); + display_startup(); // register with the message system so it knows we're // expecting this message LLMessageSystem* msg = gMessageSystem; @@ -2287,6 +2339,7 @@ bool idle_startup() msg->newMessageFast(_PREHASH_EconomyDataRequest); gAgent.sendReliableMessage(); } + display_startup(); // Create login effect // But not on first login, because you can't see your avatar then @@ -2301,6 +2354,7 @@ bool idle_startup() LLStartUp::setStartupState( STATE_AGENT_WAIT ); // Go to STATE_AGENT_WAIT timeout.reset(); + display_startup(); return FALSE; } @@ -2325,14 +2379,16 @@ bool idle_startup() LL_DEBUGS("AppInit") << "Awaiting AvatarInitComplete, got " << msg->getMessageName() << LL_ENDL; } + display_startup(); } msg->processAcks(); + display_startup(); if (gAgentMovementCompleted) { LLStartUp::setStartupState( STATE_INVENTORY_SEND ); } - + display_startup(); return FALSE; } @@ -2341,9 +2397,10 @@ bool idle_startup() //--------------------------------------------------------------------- if (STATE_INVENTORY_SEND == LLStartUp::getStartupState()) { + display_startup(); // Inform simulator of our language preference LLAgentLanguage::update(); - + display_startup(); // unpack thin inventory LLUserAuth::options_t options; options.clear(); @@ -2382,6 +2439,7 @@ bool idle_startup() } } options.clear(); + display_startup(); if(LLUserAuth::getInstance()->getOptions("inventory-skeleton", options)) { if(!gInventory.loadSkeleton(options, gAgent.getID())) @@ -2389,6 +2447,7 @@ bool idle_startup() LL_WARNS("AppInit") << "Problem loading inventory-skel-targets" << LL_ENDL; } } + display_startup(); // testing adding a local inventory folder... if (gSavedSettings.getBOOL("AscentUseSystemFolder")) @@ -2422,6 +2481,7 @@ bool idle_startup() assets_folder->setPreferredType(LLFolderType::FT_NONE); gInventory.addCategory(assets_folder); } + display_startup(); // options.clear(); @@ -2454,7 +2514,7 @@ bool idle_startup() } LLAvatarTracker::instance().addBuddyList(list); } - + display_startup(); options.clear(); if(LLUserAuth::getInstance()->getOptions("ui-config", options)) { @@ -2473,6 +2533,7 @@ bool idle_startup() } } } + display_startup(); options.clear(); bool show_hud = false; if(LLUserAuth::getInstance()->getOptions("tutorial_setting", options)) @@ -2498,6 +2559,7 @@ bool idle_startup() } } } + display_startup(); // Either we want to show tutorial because this is the first login // to a Linden Help Island or the user quit with the tutorial // visible. JC @@ -2516,12 +2578,15 @@ bool idle_startup() { gEventNotifier.load(options); } + display_startup(); options.clear(); if(LLUserAuth::getInstance()->getOptions("classified_categories", options)) { LLClassifiedInfo::loadCategories(options); } + display_startup(); gInventory.buildParentChildMap(); + display_startup(); llinfos << "Setting Inventory changed mask and notifying observers" << llendl; gInventory.addChangedMask(LLInventoryObserver::ALL, LLUUID::null); @@ -2536,30 +2601,33 @@ bool idle_startup() LLAvatarTracker::instance().registerCallbacks(msg); llinfos << " Landmark" << llendl; LLLandmark::registerCallbacks(msg); + display_startup(); // request mute list llinfos << "Requesting Mute List" << llendl; LLMuteList::getInstance()->requestFromServer(gAgent.getID()); - + display_startup(); // Get L$ and ownership credit information llinfos << "Requesting Money Balance" << llendl; LLStatusBar::sendMoneyBalanceRequest(); - + display_startup(); // request all group information llinfos << "Requesting Agent Data" << llendl; gAgent.sendAgentDataUpdateRequest(); - + display_startup(); bool shown_at_exit = gSavedSettings.getBOOL("ShowInventory"); // Create the inventory views llinfos << "Creating Inventory Views" << llendl; LLInventoryView::showAgentInventory(); - + display_startup(); + // Hide the inventory if it wasn't shown at exit if(!shown_at_exit) { LLInventoryView::toggleVisibility(NULL); } + display_startup(); // [RLVa:KB] - Checked: 2009-11-27 (RLVa-1.1.0f) | Added: RLVa-1.1.0f if (rlv_handler_t::isEnabled()) @@ -2570,6 +2638,7 @@ bool idle_startup() // [/RLVa:KB] LLStartUp::setStartupState( STATE_MISC ); + display_startup(); return FALSE; } @@ -2609,6 +2678,7 @@ bool idle_startup() } } + display_startup(); // We're successfully logged in. gSavedSettings.setBOOL("FirstLoginThisInstall", FALSE); @@ -2624,11 +2694,14 @@ bool idle_startup() // and make sure it's saved gSavedSettings.saveToFile( gSavedSettings.getString("ClientSettingsFile") , TRUE ); }; + + display_startup(); if (!gNoRender) { // JC: Initializing audio requests many sounds for download. init_audio(); + display_startup(); // JC: Initialize "active" gestures. This may also trigger // many gesture downloads, if this is the user's first @@ -2676,13 +2749,13 @@ bool idle_startup() } } - LLGestureInventoryFetchObserver* fetch = new LLGestureInventoryFetchObserver(); - fetch->fetchItems(item_ids); + LLGestureInventoryFetchObserver* fetch = new LLGestureInventoryFetchObserver(item_ids); // deletes itself when done gInventory.addObserver(fetch); } } gDisplaySwapBuffers = TRUE; + display_startup(); LLMessageSystem* msg = gMessageSystem; msg->setHandlerFuncFast(_PREHASH_SoundTrigger, hooked_process_sound_trigger); @@ -2699,7 +2772,7 @@ bool idle_startup() ) { // Fetch inventory in the background - gInventory.startBackgroundFetch(); + LLInventoryModelBackgroundFetch::instance().start(); } // HACK: Inform simulator of window size. @@ -2763,8 +2836,10 @@ bool idle_startup() } } + display_startup(); //DEV-17797. get null folder. Any items found here moved to Lost and Found - LLInventoryModel::findLostItems(); + LLInventoryModelBackgroundFetch::instance().findLostItems(); + display_startup(); LLStartUp::setStartupState( STATE_PRECACHE ); timeout.reset(); @@ -2773,6 +2848,7 @@ bool idle_startup() if (STATE_PRECACHE == LLStartUp::getStartupState()) { + display_startup(); F32 timeout_frac = timeout.getElapsedTimeF32()/PRECACHING_DELAY; // We now have an inventory skeleton, so if this is a user's first @@ -2789,7 +2865,7 @@ bool idle_startup() LLStartUp::loadInitialOutfit( sInitialOutfit, sInitialOutfitGender ); } - + display_startup(); // We now have an inventory skeleton, so if this is a user's first // login, we can start setting up their clothing and avatar // appearance. This helps to avoid the generic "Ruth" avatar in @@ -2803,7 +2879,9 @@ bool idle_startup() // Start loading the wearables, textures, gestures LLStartUp::loadInitialOutfit( sInitialOutfit, sInitialOutfitGender ); } - + + display_startup(); + // wait precache-delay and for agent's avatar or a lot longer. if(((timeout_frac > 1.f) && isAgentAvatarValid()) || (timeout_frac > 3.f)) @@ -2821,6 +2899,7 @@ bool idle_startup() { LLViewerShaderMgr::sInitialized = TRUE; LLViewerShaderMgr::instance()->setShaders(); + display_startup(); } } @@ -2850,6 +2929,8 @@ bool idle_startup() return TRUE; } + display_startup(); + if (wearables_time > MAX_WEARABLES_TIME) { LLNotificationsUtil::add("ClothingLoading"); @@ -2881,17 +2962,20 @@ bool idle_startup() } } + display_startup(); update_texture_fetch(); + display_startup(); set_startup_status(0.9f + 0.1f * wearables_time / MAX_WEARABLES_TIME, LLTrans::getString("LoginDownloadingClothing").c_str(), gAgent.mMOTD.c_str()); + display_startup(); return TRUE; } if (STATE_CLEANUP == LLStartUp::getStartupState()) { set_startup_status(1.0, "", ""); - + display_startup(); LLViewerParcelMedia::loadDomainFilterList(); // Let the map know about the inventory. @@ -2913,6 +2997,7 @@ bool idle_startup() LL_DEBUGS("AppInit") << "Done releasing bitmap" << LL_ENDL; gViewerWindow->setShowProgress(FALSE); gViewerWindow->setProgressCancelButtonVisible(FALSE); + display_startup(); // We're not away from keyboard, even though login might have taken // a while. JC @@ -2944,6 +3029,7 @@ bool idle_startup() LLUserAuth::getInstance()->reset(); LLStartUp::setStartupState( STATE_STARTED ); + display_startup(); if (gSavedSettings.getBOOL("SpeedRez")) { @@ -2972,6 +3058,9 @@ bool idle_startup() LLAppViewer::instance()->handleLoginComplete(); + // reset timers now that we are running "logged in" logic + LLFastTimer::reset(); + display_startup(); return TRUE; } diff --git a/indra/newview/lltexlayer.cpp b/indra/newview/lltexlayer.cpp index 795d1433f..06f72c774 100644 --- a/indra/newview/lltexlayer.cpp +++ b/indra/newview/lltexlayer.cpp @@ -84,7 +84,7 @@ LLBakedUploadData::LLBakedUploadData( LLVOAvatar* avatar, mStartTime = LLFrameTimer::getTotalTime(); // Record starting time for( S32 i = 0; i < LLWearableType::WT_COUNT; i++ ) { - LLWearable* wearable = gAgentWearables.getWearable( (LLWearableType::EType)i); + LLWearable* wearable = gAgentWearables.getWearable( (LLWearableType::EType)i, 0); // TODO: MULTI-WEARABLE if( wearable ) { mWearableAssets[i] = wearable->getAssetID(); diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp index d09dbdb4c..267c838ec 100644 --- a/indra/newview/lltexturectrl.cpp +++ b/indra/newview/lltexturectrl.cpp @@ -47,6 +47,7 @@ #include "llfoldervieweventlistener.h" #include "llinventory.h" #include "llinventoryfunctions.h" +#include "llinventorymodelbackgroundfetch.h" #include "llinventoryview.h" #include "lllineeditor.h" #include "llui.h" @@ -1336,20 +1337,6 @@ void LLTextureCtrl::closeFloater() } } -// Allow us to download textures quickly when floater is shown -class LLTextureFetchDescendentsObserver : public LLInventoryFetchDescendentsObserver -{ -public: - virtual void done() - { - // We need to find textures in all folders, so get the main - // background download going. - gInventory.startBackgroundFetch(); - gInventory.removeObserver(this); - delete this; - } -}; - BOOL LLTextureCtrl::handleHover(S32 x, S32 y, MASK mask) { getWindow()->setCursor(UI_CURSOR_HAND); @@ -1368,9 +1355,9 @@ BOOL LLTextureCtrl::handleMouseDown(S32 x, S32 y, MASK mask) showPicker(FALSE); //grab textures first... - gInventory.startBackgroundFetch(gInventory.findCategoryUUIDForType(LLFolderType::FT_TEXTURE)); + LLInventoryModelBackgroundFetch::instance().start(gInventory.findCategoryUUIDForType(LLFolderType::FT_TEXTURE)); //...then start full inventory fetch. - gInventory.startBackgroundFetch(); + LLInventoryModelBackgroundFetch::instance().start(); } return handled; } diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp index a6dd6f028..af8847436 100644 --- a/indra/newview/lltexturefetch.cpp +++ b/indra/newview/lltexturefetch.cpp @@ -53,6 +53,7 @@ #include "lltexturecache.h" #include "llviewercontrol.h" #include "llviewertexturelist.h" +#include "llviewertexture.h" #include "llviewerregion.h" #include "llviewerstats.h" #include "llworld.h" diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp index 42ffd4a6b..c4967c2e9 100644 --- a/indra/newview/lltooldraganddrop.cpp +++ b/indra/newview/lltooldraganddrop.cpp @@ -190,10 +190,16 @@ bool LLDropCopyableItems::operator()( return allowed; } +// Starts a fetch on folders and items. This is really not used +// as an observer in the traditional sense; we're just using it to +// request a fetch and we don't care about when/if the response arrives. class LLCategoryFireAndForget : public LLInventoryFetchComboObserver { public: - LLCategoryFireAndForget() {} + LLCategoryFireAndForget(const uuid_vec_t& folder_ids, + const uuid_vec_t& item_ids) : + LLInventoryFetchComboObserver(folder_ids, item_ids) + {} ~LLCategoryFireAndForget() {} virtual void done() { @@ -202,11 +208,13 @@ public: } }; -class LLCategoryDropObserver : public LLInventoryFetchObserver +class LLCategoryDropObserver : public LLInventoryFetchItemsObserver { public: LLCategoryDropObserver( + const uuid_vec_t& ids, const LLUUID& obj_id, LLToolDragAndDrop::ESource src) : + LLInventoryFetchItemsObserver(ids), mObjectID(obj_id), mSource(src) {} @@ -243,7 +251,7 @@ void LLCategoryDropObserver::done() } delete this; } - +/* Doesn't seem to be used anymore. class LLCategoryDropDescendentsObserver : public LLInventoryFetchDescendentsObserver { public: @@ -264,8 +272,8 @@ void LLCategoryDropDescendentsObserver::done() { gInventory.removeObserver(this); - folder_ref_t::iterator it = mCompleteFolders.begin(); - folder_ref_t::iterator end = mCompleteFolders.end(); + uuid_vec_t::iterator it = mComplete.begin(); + uuid_vec_t::iterator end = mComplete.end(); LLViewerInventoryCategory::cat_array_t cats; LLViewerInventoryItem::item_array_t items; for(; it != end; ++it) @@ -302,6 +310,7 @@ void LLCategoryDropDescendentsObserver::done() } delete this; } +*/ // This array is used to more easily control what happens when a 3d // drag and drop event occurs. Since there's an array of drop target @@ -522,8 +531,9 @@ void LLToolDragAndDrop::beginDrag(EDragAndDropType type, } if(!folder_ids.empty() || !item_ids.empty()) { - LLCategoryFireAndForget fetcher; - fetcher.fetch(folder_ids, item_ids); + LLCategoryFireAndForget *fetcher = new LLCategoryFireAndForget(folder_ids, item_ids); + fetcher->startFetch(); + delete fetcher; } } } @@ -531,7 +541,7 @@ void LLToolDragAndDrop::beginDrag(EDragAndDropType type, void LLToolDragAndDrop::beginMultiDrag( const std::vector types, - const std::vector& cargo_ids, + const uuid_vec_t& cargo_ids, ESource source, const LLUUID& source_id) { @@ -592,8 +602,7 @@ void LLToolDragAndDrop::beginMultiDrag( uuid_vec_t item_ids; std::back_insert_iterator copier(folder_ids); std::copy(cat_ids.begin(), cat_ids.end(), copier); - LLCategoryFireAndForget fetcher; - fetcher.fetch(folder_ids, item_ids); + LLCategoryFireAndForget fetcher(folder_ids, item_ids); } } } @@ -1256,7 +1265,7 @@ void LLToolDragAndDrop::dropObject(LLViewerObject* raycast_target, LLViewerInventoryItem* item; LLViewerInventoryCategory* cat; locateInventory(item, cat); - if(!item || !item->isComplete()) return; + if (!item || !item->isFinished()) return; if (regionp && (regionp->getRegionFlags() & REGION_FLAGS_SANDBOX)) @@ -1289,9 +1298,8 @@ void LLToolDragAndDrop::dropObject(LLViewerObject* raycast_target, // Check if it's in the trash. bool is_in_trash = false; - LLUUID trash_id; - trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH); - if(gInventory.isObjectDescendentOf(item->getUUID(), trash_id)) + const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH); + if (gInventory.isObjectDescendentOf(item->getUUID(), trash_id)) { is_in_trash = true; remove_from_inventory = TRUE; @@ -1509,8 +1517,8 @@ EAcceptance LLToolDragAndDrop::willObjectAcceptInventory(LLViewerObject* obj, LL // HACK: downcast LLViewerInventoryItem* vitem = (LLViewerInventoryItem*)item; // - //if(!vitem->isComplete()) return ACCEPT_NO; - if(!vitem->isComplete() && !(gInventory.isObjectDescendentOf(vitem->getUUID(), gSystemFolderRoot))) return ACCEPT_NO; + //if(!vitem->isFinished()) return ACCEPT_NO; + if(!vitem->isFinished() && !(gInventory.isObjectDescendentOf(vitem->getUUID(), gSystemFolderRoot))) return ACCEPT_NO; // if (vitem->getIsLinkType()) return ACCEPT_NO; // No giving away links @@ -1527,7 +1535,7 @@ EAcceptance LLToolDragAndDrop::willObjectAcceptInventory(LLViewerObject* obj, LL // gAgent.getGroupID()) // && (obj->mPermModify || obj->mFlagAllowInventoryAdd)); BOOL worn = FALSE; - LLVOAvatar* my_avatar = NULL; + LLVOAvatarSelf* my_avatar = NULL; switch(item->getType()) { case LLAssetType::AT_OBJECT: @@ -1691,10 +1699,10 @@ EAcceptance LLToolDragAndDrop::dad3dRezAttachmentFromInv( LLViewerInventoryItem* item; LLViewerInventoryCategory* cat; locateInventory(item, cat); - if(!item || !item->isComplete()) return ACCEPT_NO; + if (!item || !item->isFinished()) return ACCEPT_NO; // must not be in the trash - LLUUID trash_id(gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH)); + const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH); if( gInventory.isObjectDescendentOf( item->getUUID(), trash_id ) ) { return ACCEPT_NO; @@ -1768,7 +1776,7 @@ EAcceptance LLToolDragAndDrop::dad3dRezObjectOnLand( LLViewerInventoryItem* item; LLViewerInventoryCategory* cat; locateInventory(item, cat); - if(!item || !item->isComplete()) return ACCEPT_NO; + if (!item || !item->isFinished()) return ACCEPT_NO; // //LLVOAvatar* my_avatar = gAgentAvatarp; @@ -1804,8 +1812,7 @@ EAcceptance LLToolDragAndDrop::dad3dRezObjectOnLand( } // Check if it's in the trash. - LLUUID trash_id; - trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH); + const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH); if(gInventory.isObjectDescendentOf(item->getUUID(), trash_id)) { accept = ACCEPT_YES_SINGLE; @@ -1845,7 +1852,7 @@ EAcceptance LLToolDragAndDrop::dad3dRezObjectOnObject( LLViewerInventoryItem* item; LLViewerInventoryCategory* cat; locateInventory(item, cat); - if(!item || !item->isComplete()) return ACCEPT_NO; + if(!item || !item->isFinished()) return ACCEPT_NO; // //LLVOAvatar* my_avatar = gAgentAvatarp; //if( !my_avatar || my_avatar->isWearingAttachment( item->getUUID() ) ) @@ -1897,8 +1904,7 @@ EAcceptance LLToolDragAndDrop::dad3dRezObjectOnObject( } // Check if it's in the trash. - LLUUID trash_id; - trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH); + const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH); if(gInventory.isObjectDescendentOf(item->getUUID(), trash_id)) { accept = ACCEPT_YES_SINGLE; @@ -1928,7 +1934,7 @@ EAcceptance LLToolDragAndDrop::dad3dRezScript( LLViewerInventoryItem* item; LLViewerInventoryCategory* cat; locateInventory(item, cat); - if(!item || !item->isComplete()) return ACCEPT_NO; + if (!item || !item->isFinished()) return ACCEPT_NO; EAcceptance rv = willObjectAcceptInventory(obj, item); if(drop && (ACCEPT_YES_SINGLE <= rv)) { @@ -1971,8 +1977,8 @@ EAcceptance LLToolDragAndDrop::dad3dTextureObject( LLViewerInventoryCategory* cat; locateInventory(item, cat); // - //if(!item || !item->isComplete()) return ACCEPT_NO; - if( !item || (!item->isComplete() && !(gInventory.isObjectDescendentOf(item->getUUID(), gSystemFolderRoot))) ) return ACCEPT_NO; + //if(!item || !item->isFinished()) return ACCEPT_NO; + if( !item || (!item->isFinished() && !(gInventory.isObjectDescendentOf(item->getUUID(), gSystemFolderRoot))) ) return ACCEPT_NO; // EAcceptance rv = willObjectAcceptInventory(obj, item); if((mask & MASK_CONTROL)) @@ -2003,6 +2009,7 @@ EAcceptance LLToolDragAndDrop::dad3dTextureObject( { dropTextureOneFace(obj, face, item, mSource, mSourceID); } + // VEFFECT: SetTexture LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_BEAM, TRUE); @@ -2038,7 +2045,7 @@ EAcceptance LLToolDragAndDrop::dad3dWearItem( LLViewerInventoryItem* item; LLViewerInventoryCategory* cat; locateInventory(item, cat); - if(!item || !item->isComplete()) return ACCEPT_NO; + if(!item || !item->isFinished()) return ACCEPT_NO; if(mSource == SOURCE_AGENT || mSource == SOURCE_LIBRARY) { @@ -2100,7 +2107,7 @@ EAcceptance LLToolDragAndDrop::dad3dActivateGesture( LLViewerInventoryItem* item; LLViewerInventoryCategory* cat; locateInventory(item, cat); - if(!item || !item->isComplete()) return ACCEPT_NO; + if (!item || !item->isFinished()) return ACCEPT_NO; if(mSource == SOURCE_AGENT || mSource == SOURCE_LIBRARY) { @@ -2164,7 +2171,7 @@ EAcceptance LLToolDragAndDrop::dad3dWearCategory( if(mSource == SOURCE_AGENT) { - LLUUID trash_id(gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH)); + const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH); if( gInventory.isObjectDescendentOf( category->getUUID(), trash_id ) ) { return ACCEPT_NO; @@ -2208,7 +2215,7 @@ EAcceptance LLToolDragAndDrop::dad3dUpdateInventory( LLViewerInventoryItem* item; LLViewerInventoryCategory* cat; locateInventory(item, cat); - if(!item || !item->isComplete()) return ACCEPT_NO; + if (!item || !item->isFinished()) return ACCEPT_NO; LLViewerObject* root_object = obj; if (obj && obj->getParent()) { @@ -2237,24 +2244,30 @@ EAcceptance LLToolDragAndDrop::dad3dUpdateInventoryCategory( LLViewerObject* obj, S32 face, MASK mask, BOOL drop) { lldebugs << "LLToolDragAndDrop::dad3dUpdateInventoryCategory()" << llendl; - if (NULL==obj) + if (obj == NULL) { llwarns << "obj is NULL; aborting func with ACCEPT_NO" << llendl; return ACCEPT_NO; } - if (mSource != SOURCE_AGENT && mSource != SOURCE_LIBRARY) + if ((mSource != SOURCE_AGENT) && (mSource != SOURCE_LIBRARY)) { return ACCEPT_NO; } - if(obj->isAttachment()) return ACCEPT_NO_LOCKED; - LLViewerInventoryItem* item; - LLViewerInventoryCategory* cat; - locateInventory(item, cat); - if(!cat) return ACCEPT_NO; - EAcceptance rv = ACCEPT_NO; + if (obj->isAttachment()) + { + return ACCEPT_NO_LOCKED; + } - // find all the items in the category + LLViewerInventoryItem* item = NULL; + LLViewerInventoryCategory* cat = NULL; + locateInventory(item, cat); + if (!cat) + { + return ACCEPT_NO; + } + + // Find all the items in the category LLDroppableItem droppable(!obj->permYouOwner()); LLInventoryModel::cat_array_t cats; LLInventoryModel::item_array_t items; @@ -2278,29 +2291,40 @@ EAcceptance LLToolDragAndDrop::dad3dUpdateInventoryCategory( } } + EAcceptance rv = ACCEPT_NO; + // Check for accept - S32 i; - S32 count = cats.count(); - for(i = 0; i < count; ++i) + for (LLInventoryModel::cat_array_t::const_iterator cat_iter = cats.begin(); + cat_iter != cats.end(); + ++cat_iter) { - rv = gInventory.isCategoryComplete(cats.get(i)->getUUID()) ? ACCEPT_YES_MULTI : ACCEPT_NO; + const LLViewerInventoryCategory *cat = (*cat_iter); + rv = gInventory.isCategoryComplete(cat->getUUID()) ? ACCEPT_YES_MULTI : ACCEPT_NO; if(rv < ACCEPT_YES_SINGLE) { - lldebugs << "Category " << cats.get(i)->getUUID() - << "is not complete." << llendl; + lldebugs << "Category " << cat->getUUID() << "is not complete." << llendl; break; } } - if(ACCEPT_YES_COPY_SINGLE <= rv) + if (ACCEPT_YES_COPY_SINGLE <= rv) { - count = items.count(); - for(i = 0; i < count; ++i) + for (LLInventoryModel::item_array_t::const_iterator item_iter = items.begin(); + item_iter != items.end(); + ++item_iter) { - rv = willObjectAcceptInventory(root_object, items.get(i)); - if(rv < ACCEPT_YES_COPY_SINGLE) + LLViewerInventoryItem *item = (*item_iter); + /* + // Pass the base objects, not the links. + if (item && item->getIsLinkType()) { - lldebugs << "Object will not accept " - << items.get(i)->getUUID() << llendl; + item = item->getLinkedItem(); + (*item_iter) = item; + } + */ + rv = willObjectAcceptInventory(root_object, item); + if (rv < ACCEPT_YES_COPY_SINGLE) + { + lldebugs << "Object will not accept " << item->getUUID() << llendl; break; } } @@ -2309,17 +2333,17 @@ EAcceptance LLToolDragAndDrop::dad3dUpdateInventoryCategory( // if every item is accepted, go ahead and send it on. if(drop && (ACCEPT_YES_COPY_SINGLE <= rv)) { - S32 count = items.count(); uuid_vec_t ids; - for(i = 0; i < count; ++i) + for (LLInventoryModel::item_array_t::const_iterator item_iter = items.begin(); + item_iter != items.end(); + ++item_iter) { - //dropInventory(root_object, items.get(i), mSource, mSourceID); - ids.push_back(items.get(i)->getUUID()); + const LLViewerInventoryItem *item = (*item_iter); + ids.push_back(item->getUUID()); } - LLCategoryDropObserver* dropper; - dropper = new LLCategoryDropObserver(obj->getID(), mSource); - dropper->fetchItems(ids); - if(dropper->isEverythingComplete()) + LLCategoryDropObserver* dropper = new LLCategoryDropObserver(ids, obj->getID(), mSource); + dropper->startFetch(); + if (dropper->isFinished()) { dropper->done(); } @@ -2350,13 +2374,13 @@ EAcceptance LLToolDragAndDrop::dad3dGiveInventoryObject( LLViewerInventoryItem* item; LLViewerInventoryCategory* cat; locateInventory(item, cat); - if(!item || !item->isComplete()) return ACCEPT_NO; + if (!item || !item->isFinished()) return ACCEPT_NO; if(!item->getPermissions().allowOperationBy(PERM_TRANSFER, gAgent.getID())) { // cannot give away no-transfer objects return ACCEPT_NO; } - LLVOAvatar* avatar = gAgentAvatarp; + LLVOAvatarSelf* avatar = gAgentAvatarp; if(avatar && avatar->isWearingAttachment( item->getUUID() ) ) { // You can't give objects that are attached to you @@ -2385,7 +2409,7 @@ EAcceptance LLToolDragAndDrop::dad3dGiveInventory( LLViewerInventoryItem* item; LLViewerInventoryCategory* cat; locateInventory(item, cat); - if(!item || !item->isComplete()) return ACCEPT_NO; + if (!item || !item->isFinished()) return ACCEPT_NO; if(!LLGiveInventory::isInventoryGiveAcceptable(item)) { return ACCEPT_NO; @@ -2424,7 +2448,7 @@ EAcceptance LLToolDragAndDrop::dad3dRezFromObjectOnLand( LLViewerInventoryItem* item = NULL; LLViewerInventoryCategory* cat = NULL; locateInventory(item, cat); - if(!item || !item->isComplete()) return ACCEPT_NO; + if (!item || !item->isFinished()) return ACCEPT_NO; if(!gAgent.allowOperation(PERM_COPY, item->getPermissions()) || !item->getPermissions().allowTransferTo(LLUUID::null)) @@ -2445,7 +2469,7 @@ EAcceptance LLToolDragAndDrop::dad3dRezFromObjectOnObject( LLViewerInventoryItem* item; LLViewerInventoryCategory* cat; locateInventory(item, cat); - if(!item || !item->isComplete()) return ACCEPT_NO; + if (!item || !item->isFinished()) return ACCEPT_NO; if((mask & MASK_CONTROL)) { // *HACK: In order to resolve SL-22177, we need to block drags diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp index 331a946ad..b7114edd6 100644 --- a/indra/newview/llviewerdisplay.cpp +++ b/indra/newview/llviewerdisplay.cpp @@ -233,10 +233,19 @@ void display_stats() } } +static LLFastTimer::DeclareTimer FTM_PICK("Picking"); +static LLFastTimer::DeclareTimer FTM_RENDER("Render", true); +static LLFastTimer::DeclareTimer FTM_UPDATE_SKY("Update Sky"); +static LLFastTimer::DeclareTimer FTM_UPDATE_TEXTURES("Update Textures"); +static LLFastTimer::DeclareTimer FTM_IMAGE_UPDATE("Update Images"); +static LLFastTimer::DeclareTimer FTM_IMAGE_UPDATE_CLASS("Class"); +static LLFastTimer::DeclareTimer FTM_IMAGE_UPDATE_BUMP("Bump"); +static LLFastTimer::DeclareTimer FTM_IMAGE_UPDATE_LIST("List"); +static LLFastTimer::DeclareTimer FTM_IMAGE_UPDATE_DELETE("Delete"); // Paint the display! void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot, bool tiling) { - LLFastTimer t(LLFastTimer::FTM_RENDER); + LLFastTimer t(FTM_RENDER); if (gWindowResized) { //skip render on frames where window has been resized @@ -302,7 +311,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot, boo gViewerWindow->checkSettings(); { - LLFastTimer ftm(LLFastTimer::FTM_PICK); + LLFastTimer ftm(FTM_PICK); LLAppViewer::instance()->pingMainloopTimeout("Display:Pick"); gViewerWindow->performPick(); } @@ -591,7 +600,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot, boo if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_DYNAMIC_TEXTURES)) { LLAppViewer::instance()->pingMainloopTimeout("Display:DynamicTextures"); - LLFastTimer t(LLFastTimer::FTM_UPDATE_TEXTURES); + LLFastTimer t(FTM_UPDATE_TEXTURES); if (LLViewerDynamicTexture::updateAllInstances()) { gGL.setColorMask(true, true); @@ -770,20 +779,33 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot, boo gFrameStats.start(LLFrameStats::IMAGE_UPDATE); { - LLFastTimer t(LLFastTimer::FTM_IMAGE_UPDATE); + LLFastTimer t(FTM_IMAGE_UPDATE); - LLViewerTexture::updateClass(LLViewerCamera::getInstance()->getVelocityStat()->getMean(), - LLViewerCamera::getInstance()->getAngularVelocityStat()->getMean()); + { + LLFastTimer t(FTM_IMAGE_UPDATE_CLASS); + LLViewerTexture::updateClass(LLViewerCamera::getInstance()->getVelocityStat()->getMean(), + LLViewerCamera::getInstance()->getAngularVelocityStat()->getMean()); + } - gBumpImageList.updateImages(); // must be called before gTextureList version so that it's textures are thrown out first. + + { + LLFastTimer t(FTM_IMAGE_UPDATE_BUMP); + gBumpImageList.updateImages(); // must be called before gTextureList version so that it's textures are thrown out first. + } - F32 max_image_decode_time = 0.050f*gFrameIntervalSeconds; // 50 ms/second decode time - max_image_decode_time = llclamp(max_image_decode_time, 0.001f, 0.005f ); // min 1ms/frame, max 5ms/frame) - gTextureList.updateImages(max_image_decode_time); + { + LLFastTimer t(FTM_IMAGE_UPDATE_LIST); + F32 max_image_decode_time = 0.050f*gFrameIntervalSeconds; // 50 ms/second decode time + max_image_decode_time = llclamp(max_image_decode_time, 0.002f, 0.005f ); // min 2ms/frame, max 5ms/frame) + gTextureList.updateImages(max_image_decode_time); + } - //remove dead textures from GL - LLImageGL::deleteDeadTextures(); - stop_glerror(); + { + LLFastTimer t(FTM_IMAGE_UPDATE_DELETE); + //remove dead textures from GL + LLImageGL::deleteDeadTextures(); + stop_glerror(); + } } llpushcallstacks ; LLGLState::checkStates(); @@ -823,7 +845,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot, boo { LLAppViewer::instance()->pingMainloopTimeout("Display:Sky"); - LLFastTimer t(LLFastTimer::FTM_UPDATE_SKY); + LLFastTimer t(FTM_UPDATE_SKY); gSky.updateSky(); } @@ -983,6 +1005,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot, boo LLAppViewer::instance()->pingMainloopTimeout("Display:RenderUI"); if (!for_snapshot) { + LLFastTimer t(FTM_RENDER_UI); gFrameStats.start(LLFrameStats::RENDER_UI); render_ui(); } @@ -1199,6 +1222,8 @@ BOOL setup_hud_matrices(const LLRect& screen_region) glh_set_current_modelview(model); return TRUE; } + +static LLFastTimer::DeclareTimer FTM_SWAP("Swap"); void render_ui(F32 zoom_factor, int subfield, bool tiling) { LLGLState::checkStates(); @@ -1243,7 +1268,7 @@ void render_ui(F32 zoom_factor, int subfield, bool tiling) gGL.color4f(1,1,1,1); if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI)) { - LLFastTimer t(LLFastTimer::FTM_RENDER_UI); + LLFastTimer t(FTM_RENDER_UI); if (!gDisconnected) { @@ -1277,7 +1302,7 @@ void render_ui(F32 zoom_factor, int subfield, bool tiling) if (gDisplaySwapBuffers) { - LLFastTimer t(LLFastTimer::FTM_SWAP); + LLFastTimer t(FTM_SWAP); gViewerWindow->getWindow()->swapBuffers(); } gDisplaySwapBuffers = TRUE; diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp index b640b34e7..417bbb234 100644 --- a/indra/newview/llviewerinventory.cpp +++ b/indra/newview/llviewerinventory.cpp @@ -48,6 +48,7 @@ #include "llinventorybridge.h" #include "llinventorydefines.h" +#include "llinventorymodelbackgroundfetch.h" #include "llinventoryview.h" #include "llviewerregion.h" @@ -218,10 +219,23 @@ void LLViewerInventoryItem::fetchFromServer(void) const { std::string url; - if( ALEXANDRIA_LINDEN_ID.getString() == mPermissions.getOwner().getString()) - url = gAgent.getRegion()->getCapability("FetchLib"); - else - url = gAgent.getRegion()->getCapability("FetchInventory"); + LLViewerRegion* region = gAgent.getRegion(); + // we have to check region. It can be null after region was destroyed. See EXT-245 + if (region) + { + if(gAgent.getID() != mPermissions.getOwner()) + { + url = region->getCapability("FetchLib2"); + } + else + { + url = region->getCapability("FetchInventory2"); + } + } + else + { + llwarns << "Agent Region is absent" << llendl; + } if (!url.empty()) { @@ -471,15 +485,16 @@ void LLViewerInventoryCategory::removeFromServer( void ) gAgent.sendReliableMessage(); } -bool LLViewerInventoryCategory::fetchDescendents() +bool LLViewerInventoryCategory::fetch() { // if((mUUID == gSystemFolderRoot) || (gInventory.isObjectDescendentOf(mUUID, gSystemFolderRoot))) return false; // - if (VERSION_UNKNOWN == mVersion && - (!mDescendentsRequested.getStarted() || - mDescendentsRequested.hasExpired())) // Expired check prevents multiple downloads. + if((VERSION_UNKNOWN == mVersion) && + (!mDescendentsRequested.getStarted() || + mDescendentsRequested.hasExpired())) //Expired check prevents multiple downloads. { + LL_DEBUGS("InventoryFetch") << "Fetching category children: " << mName << ", UUID: " << mUUID << LL_ENDL; const F32 FETCH_TIMER_EXPIRY = 10.0f; mDescendentsRequested.start(FETCH_TIMER_EXPIRY); @@ -499,7 +514,7 @@ bool LLViewerInventoryCategory::fetchDescendents() std::string url; if (gAgent.getRegion()) { - url = gAgent.getRegion()->getCapability("FetchInventoryDescendents"); + url = gAgent.getRegion()->getCapability("FetchInventoryDescendents2"); } else { @@ -507,11 +522,11 @@ bool LLViewerInventoryCategory::fetchDescendents() } if (!url.empty()) //Capability found. Build up LLSD and use it. { - LLInventoryModel::startBackgroundFetch(mUUID); + LLInventoryModelBackgroundFetch::instance().start(mUUID, false); } else { //Deprecated, but if we don't have a capability, use the old system. - //llinfos << "FetchInventoryDescendents 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"); @@ -710,6 +725,11 @@ void ActivateGestureCallback::fire(const LLUUID& inv_item) { if (inv_item.isNull()) return; + LLViewerInventoryItem* item = gInventory.getItem(inv_item); + if (!item) + return; + if (item->getType() != LLAssetType::AT_GESTURE) + return; LLGestureMgr::instance().activateGesture(inv_item); } diff --git a/indra/newview/llviewerinventory.h b/indra/newview/llviewerinventory.h index 31f6c6c3f..95b4d1519 100644 --- a/indra/newview/llviewerinventory.h +++ b/indra/newview/llviewerinventory.h @@ -199,7 +199,7 @@ public: void setVersion(S32 version) { mVersion = version; } // Returns true if a fetch was issued. - bool fetchDescendents(); + bool fetch(); // used to help make cacheing more robust - for example, if // someone is getting 4 packets but logs out after 3. the viewer diff --git a/indra/newview/llviewerjointmesh.cpp b/indra/newview/llviewerjointmesh.cpp index 431abf544..7b1fe947d 100644 --- a/indra/newview/llviewerjointmesh.cpp +++ b/indra/newview/llviewerjointmesh.cpp @@ -672,6 +672,7 @@ void LLViewerJointMesh::updateFaceSizes(U32 &num_vertices, U32& num_indices, F32 //----------------------------------------------------------------------------- // updateFaceData() //----------------------------------------------------------------------------- +static LLFastTimer::DeclareTimer FTM_AVATAR_FACE("Avatar Face"); void LLViewerJointMesh::updateFaceData(LLFace *face, F32 pixel_area, BOOL damp_wind, bool terse_update) { @@ -694,6 +695,8 @@ void LLViewerJointMesh::updateFaceData(LLFace *face, F32 pixel_area, BOOL damp_w } + LLFastTimer t(FTM_AVATAR_FACE); + LLStrider verticesp; LLStrider normalsp; LLStrider tex_coordsp; diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 4836e5323..658c62ec1 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -7122,10 +7122,12 @@ class LLAttachmentDetach : public view_listener_t //Adding an observer for a Jira 2422 and needs to be a fetch observer //for Jira 3119 -class LLWornItemFetchedObserver : public LLInventoryFetchObserver +class LLWornItemFetchedObserver : public LLInventoryFetchItemsObserver { public: - LLWornItemFetchedObserver() {} + LLWornItemFetchedObserver(const LLUUID& worn_item_id) : + LLInventoryFetchItemsObserver(worn_item_id) + {} virtual ~LLWornItemFetchedObserver() {} protected: @@ -7178,13 +7180,9 @@ class LLAttachmentEnableDrop : public view_listener_t // when the item finishes fetching worst case scenario // if a fetch is already out there (being sent from a slow sim) // we refetch and there are 2 fetches - LLWornItemFetchedObserver* wornItemFetched = new LLWornItemFetchedObserver(); - uuid_vec_t items; //add item to the inventory item to be fetched - - items.push_back((*attachment_iter)->getAttachmentItemID()); - - wornItemFetched->fetchItems(items); - gInventory.addObserver(wornItemFetched); + LLWornItemFetchedObserver* worn_item_fetched = new LLWornItemFetchedObserver((*attachment_iter)->getAttachmentItemID()); + worn_item_fetched->startFetch(); + gInventory.addObserver(worn_item_fetched); } } } @@ -9186,7 +9184,7 @@ class LLEditTakeOff : public view_listener_t LLWearableType::EType type = LLWearableType::typeNameToType(clothing); if (type >= LLWearableType::WT_SHAPE && type < LLWearableType::WT_COUNT) - LLAgentWearables::userRemoveWearable(type); + LLAgentWearables::userRemoveWearable(type,0); // TODO: MULTI-WEARABLE } return true; } diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 1d07ebae5..fadfa3732 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -814,10 +814,13 @@ static LLNotificationFunctorRegistration jgr_3("JoinGroupCanAfford", join_group_ //----------------------------------------------------------------------------- // Instant Message //----------------------------------------------------------------------------- -class LLOpenAgentOffer : public LLInventoryFetchObserver +class LLOpenAgentOffer : public LLInventoryFetchItemsObserver { public: - LLOpenAgentOffer(const std::string& from_name) : mFromName(from_name) {} + LLOpenAgentOffer(const LLUUID& object_id, + const std::string& from_name) : + LLInventoryFetchItemsObserver(object_id), + mFromName(from_name) {} /*virtual*/ void done() { open_offer(mComplete, mFromName); @@ -856,13 +859,14 @@ void start_new_inventory_observer() } } -class LLDiscardAgentOffer : public LLInventoryFetchComboObserver +class LLDiscardAgentOffer : public LLInventoryFetchItemsObserver { public: LLDiscardAgentOffer(const LLUUID& folder_id, const LLUUID& object_id) : + LLInventoryFetchItemsObserver(object_id), mFolderID(folder_id), mObjectID(object_id) {} - virtual ~LLDiscardAgentOffer() {} + virtual void done() { LL_DEBUGS("Messaging") << "LLDiscardAgentOffer::done()" << LL_ENDL; @@ -875,6 +879,7 @@ public: gInventory.removeObserver(this); delete this; } + protected: LLUUID mFolderID; LLUUID mObjectID; @@ -1299,11 +1304,9 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD& if ( (rlv_handler_t::isEnabled()) && (!RlvSettings::getForbidGiveToRLV()) && (LLAssetType::AT_CATEGORY == mType) && (RlvInventory::instance().getSharedRoot()) && (mDesc.find(RLV_PUTINV_PREFIX) == 0) ) { - RlvGiveToRLVAgentOffer* pOffer = new RlvGiveToRLVAgentOffer(); - LLInventoryFetchComboObserver::folder_ref_t folders; - folders.push_back(mObjectID); - pOffer->fetchDescendents(folders); - if (pOffer->isEverythingComplete()) + RlvGiveToRLVAgentOffer* pOffer = new RlvGiveToRLVAgentOffer(mObjectID); + pOffer->startFetch(); + if (pOffer->isFinished()) pOffer->done(); else gInventory.addObserver(pOffer); @@ -1311,11 +1314,9 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD& #endif // RLV_EXTENSION_GIVETORLV_A2A // [/RLVa:KB] - uuid_vec_t items; - items.push_back(mObjectID); - LLOpenAgentOffer* open_agent_offer = new LLOpenAgentOffer(from_string); - open_agent_offer->fetchItems(items); - if(catp || (itemp && itemp->isComplete())) + LLOpenAgentOffer* open_agent_offer = new LLOpenAgentOffer(mObjectID, from_string); + open_agent_offer->startFetch(); + if(catp || (itemp && itemp->isFinished())) { open_agent_offer->done(); } @@ -1382,13 +1383,9 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD& // request will suffice to discard the item. if(IM_INVENTORY_OFFERED == mIM) { - LLInventoryFetchComboObserver::folder_ref_t folders; - LLInventoryFetchComboObserver::item_ref_t items; - items.push_back(mObjectID); - LLDiscardAgentOffer* discard_agent_offer; - discard_agent_offer = new LLDiscardAgentOffer(mFolderID, mObjectID); - discard_agent_offer->fetch(folders, items); - if(catp || (itemp && itemp->isComplete())) + LLDiscardAgentOffer* discard_agent_offer = new LLDiscardAgentOffer(mFolderID, mObjectID); + discard_agent_offer->startFetch(); + if (catp || (itemp && itemp->isFinished())) { discard_agent_offer->done(); } @@ -3623,7 +3620,9 @@ void process_teleport_progress(LLMessageSystem* msg, void**) class LLFetchInWelcomeArea : public LLInventoryFetchDescendentsObserver { public: - LLFetchInWelcomeArea() {} + LLFetchInWelcomeArea(const uuid_vec_t &ids) : + LLInventoryFetchDescendentsObserver(ids) + {} virtual void done() { LLIsType is_landmark(LLAssetType::AT_LANDMARK); @@ -3634,8 +3633,8 @@ public: LLInventoryModel::cat_array_t land_cats; LLInventoryModel::item_array_t land_items; - folder_ref_t::iterator it = mCompleteFolders.begin(); - folder_ref_t::iterator end = mCompleteFolders.end(); + uuid_vec_t::iterator it = mComplete.begin(); + uuid_vec_t::iterator end = mComplete.end(); for(; it != end; ++it) { gInventory.collectDescendentsIf( @@ -3696,19 +3695,18 @@ BOOL LLPostTeleportNotifiers::tick() if ( gAgent.getTeleportState() == LLAgent::TELEPORT_NONE ) { // get callingcards and landmarks available to the user arriving. - LLInventoryFetchDescendentsObserver::folder_ref_t folders; - LLUUID folder_id; - folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_CALLINGCARD); - if(folder_id.notNull()) - folders.push_back(folder_id); - folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_LANDMARK); + uuid_vec_t folders; + const LLUUID callingcard_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_CALLINGCARD); + if(callingcard_id.notNull()) + folders.push_back(callingcard_id); + const LLUUID folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_LANDMARK); if(folder_id.notNull()) folders.push_back(folder_id); if(!folders.empty()) { - LLFetchInWelcomeArea* fetcher = new LLFetchInWelcomeArea; - fetcher->fetchDescendents(folders); - if(fetcher->isEverythingComplete()) + LLFetchInWelcomeArea* fetcher = new LLFetchInWelcomeArea(folders); + fetcher->startFetch(); + if(fetcher->isFinished()) { fetcher->done(); } @@ -4101,6 +4099,7 @@ const F32 THRESHOLD_HEAD_ROT_QDOT = 0.9997f; // ~= 2.5 degrees -- if its less th const F32 MAX_HEAD_ROT_QDOT = 0.99999f; // ~= 0.5 degrees -- if its greater than this then no need to update head_rot // between these values we delay the updates (but no more than one second) +static LLFastTimer::DeclareTimer FTM_AGENT_UPDATE_SEND("Send Message"); void send_agent_update(BOOL force_send, BOOL send_reliable) { @@ -4265,6 +4264,7 @@ 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); @@ -4399,11 +4399,12 @@ void process_terse_object_update_improved(LLMessageSystem *mesgsys, void **user_ gObjectList.processCompressedObjectUpdate(mesgsys, user_data, OUT_TERSE_IMPROVED); } +static LLFastTimer::DeclareTimer FTM_PROCESS_OBJECTS("Process Objects"); void process_kill_object(LLMessageSystem *mesgsys, void **user_data) { - LLFastTimer t(LLFastTimer::FTM_PROCESS_OBJECTS); + LLFastTimer t(FTM_PROCESS_OBJECTS); LLUUID id; U32 local_id; diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index d7ae2822a..c1a461ca7 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -124,11 +124,14 @@ BOOL LLViewerObject::sUseSharedDrawables(FALSE); // TRUE F64 LLViewerObject::sMaxUpdateInterpolationTime = 3.0; // For motion interpolation: after X seconds with no updates, don't predict object motion F64 LLViewerObject::sPhaseOutUpdateInterpolationTime = 2.0; // For motion interpolation: after Y seconds with no updates, taper off motion prediction + +static LLFastTimer::DeclareTimer FTM_CREATE_OBJECT("Create Object"); + // static LLViewerObject *LLViewerObject::createObject(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp) { LLViewerObject *res = NULL; - LLFastTimer t1(LLFastTimer::FTM_CREATE_OBJECT); + LLFastTimer t1(FTM_CREATE_OBJECT); switch (pcode) { @@ -2095,6 +2098,8 @@ BOOL LLViewerObject::isActive() const BOOL LLViewerObject::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) { + static LLFastTimer::DeclareTimer ftm("Viewer Object"); + LLFastTimer t(ftm); if (mDead) { // It's dead. Don't update it. @@ -5457,11 +5462,12 @@ void LLViewerObject::dirtyMesh() { if (mDrawable) { - LLSpatialGroup* group = mDrawable->getSpatialGroup(); + gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_ALL); + /*LLSpatialGroup* group = mDrawable->getSpatialGroup(); if (group) { group->dirtyMesh(); - } + }*/ } } diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp index c203c4afc..3236c4717 100644 --- a/indra/newview/llviewerobjectlist.cpp +++ b/indra/newview/llviewerobjectlist.cpp @@ -291,12 +291,14 @@ void LLViewerObjectList::processUpdateCore(LLViewerObject* objectp, } } +static LLFastTimer::DeclareTimer FTM_PROCESS_OBJECTS("Process Objects"); + void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, void **user_data, const EObjectUpdateType update_type, bool cached, bool compressed) { - LLFastTimer t(LLFastTimer::FTM_PROCESS_OBJECTS); + LLFastTimer t(FTM_PROCESS_OBJECTS); LLVector3d camera_global = gAgentCamera.getCameraPositionGlobal(); LLViewerObject *objectp; @@ -909,20 +911,26 @@ void LLViewerObjectList::update(LLAgent &agent, LLWorld &world) // Make a copy of the list in case something in idleUpdate() messes with it std::vector idle_list; - idle_list.reserve( mActiveObjects.size() ); + + static LLFastTimer::DeclareTimer idle_copy("Idle Copy"); - for (std::set >::iterator active_iter = mActiveObjects.begin(); - active_iter != mActiveObjects.end(); active_iter++) { - objectp = *active_iter; - if (objectp) + LLFastTimer t(idle_copy); + idle_list.reserve( mActiveObjects.size() ); + + for (std::set >::iterator active_iter = mActiveObjects.begin(); + active_iter != mActiveObjects.end(); active_iter++) { - idle_list.push_back( objectp ); - } - else - { // There shouldn't be any NULL pointers in the list, but they have caused - // crashes before. This may be idleUpdate() messing with the list. - llwarns << "LLViewerObjectList::update has a NULL objectp" << llendl; + objectp = *active_iter; + if (objectp) + { + idle_list.push_back( objectp ); + } + else + { // There shouldn't be any NULL pointers in the list, but they have caused + // crashes before. This may be idleUpdate() messing with the list. + llwarns << "LLViewerObjectList::update has a NULL objectp" << llendl; + } } } @@ -1211,8 +1219,12 @@ void LLViewerObjectList::cleanupReferences(LLViewerObject *objectp) mNumDeadObjects++; } +static LLFastTimer::DeclareTimer FTM_REMOVE_DRAWABLE("Remove Drawable"); + void LLViewerObjectList::removeDrawable(LLDrawable* drawablep) { + LLFastTimer t(FTM_REMOVE_DRAWABLE); + if (!drawablep) { return; @@ -1857,12 +1869,13 @@ LLViewerObject *LLViewerObjectList::createObjectViewer(const LLPCode pcode, LLVi } +static LLFastTimer::DeclareTimer FTM_CREATE_OBJECT("Create Object"); LLViewerObject *LLViewerObjectList::createObject(const LLPCode pcode, LLViewerRegion *regionp, const LLUUID &uuid, const U32 local_id, const LLHost &sender) { LLMemType mt(LLMemType::MTYPE_OBJECT); - LLFastTimer t(LLFastTimer::FTM_CREATE_OBJECT); + LLFastTimer t(FTM_CREATE_OBJECT); LLUUID fullid; if (uuid == LLUUID::null) diff --git a/indra/newview/llviewerpartsim.cpp b/indra/newview/llviewerpartsim.cpp index 21c180e09..4759454ee 100644 --- a/indra/newview/llviewerpartsim.cpp +++ b/indra/newview/llviewerpartsim.cpp @@ -634,6 +634,8 @@ void LLViewerPartSim::shift(const LLVector3 &offset) } } +static LLFastTimer::DeclareTimer FTM_SIMULATE_PARTICLES("Simulate Particles"); + void LLViewerPartSim::updateSimulation() { LLMemType mt(LLMemType::MTYPE_PARTICLES); @@ -647,7 +649,7 @@ void LLViewerPartSim::updateSimulation() return; } - LLFastTimer ftm(LLFastTimer::FTM_SIMULATE_PARTICLES); + LLFastTimer ftm(FTM_SIMULATE_PARTICLES); // Start at a random particle system so the same // particle system doesn't always get first pick at the diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index f5a82f9d0..a678e14bb 100644 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -1499,12 +1499,12 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames) capabilityNames.append("ObjectMedia"); capabilityNames.append("ObjectMediaNavigate");*/ - if (false)//gSavedSettings.getBOOL("UseHTTPInventory")) //Caps suffixed with 2 by LL. Don't update until rest of fetch system is updated first. + if (gSavedSettings.getBOOL("UseHTTPInventory")) //Caps suffixed with 2 by LL. Don't update until rest of fetch system is updated first. { - capabilityNames.append("FetchLib"); - capabilityNames.append("FetchLibDescendents"); - capabilityNames.append("FetchInventory"); - capabilityNames.append("FetchInventoryDescendents"); + capabilityNames.append("FetchLib2"); + capabilityNames.append("FetchLibDescendents2"); + capabilityNames.append("FetchInventory2"); + capabilityNames.append("FetchInventoryDescendents2"); } capabilityNames.append("GetDisplayNames"); diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp index ca4606f7c..11cb1a868 100644 --- a/indra/newview/llviewerstats.cpp +++ b/indra/newview/llviewerstats.cpp @@ -616,14 +616,14 @@ void update_statistics(U32 frame_count) LLViewerStats::getInstance()->setStat(LLViewerStats::ST_SHADER_AVATAR, (F64)gSavedSettings.getBOOL("VertexShaderLevelAvatar")); LLViewerStats::getInstance()->setStat(LLViewerStats::ST_SHADER_ENVIRONMENT, (F64)gSavedSettings.getBOOL("VertexShaderLevelEnvironment")); #endif - LLViewerStats::getInstance()->setStat(LLViewerStats::ST_FRAME_SECS, gDebugView->mFastTimerView->getTime(LLFastTimer::FTM_FRAME)); - F64 idle_secs = gDebugView->mFastTimerView->getTime(LLFastTimer::FTM_IDLE); - F64 network_secs = gDebugView->mFastTimerView->getTime(LLFastTimer::FTM_NETWORK); + LLViewerStats::getInstance()->setStat(LLViewerStats::ST_FRAME_SECS, gDebugView->mFastTimerView->getTime("Frame")); + F64 idle_secs = gDebugView->mFastTimerView->getTime("Idle"); + F64 network_secs = gDebugView->mFastTimerView->getTime("Network"); LLViewerStats::getInstance()->setStat(LLViewerStats::ST_UPDATE_SECS, idle_secs - network_secs); LLViewerStats::getInstance()->setStat(LLViewerStats::ST_NETWORK_SECS, network_secs); - LLViewerStats::getInstance()->setStat(LLViewerStats::ST_IMAGE_SECS, gDebugView->mFastTimerView->getTime(LLFastTimer::FTM_IMAGE_UPDATE)); - LLViewerStats::getInstance()->setStat(LLViewerStats::ST_REBUILD_SECS, gDebugView->mFastTimerView->getTime(LLFastTimer::FTM_STATESORT )); - LLViewerStats::getInstance()->setStat(LLViewerStats::ST_RENDER_SECS, gDebugView->mFastTimerView->getTime(LLFastTimer::FTM_RENDER_GEOMETRY)); + LLViewerStats::getInstance()->setStat(LLViewerStats::ST_IMAGE_SECS, gDebugView->mFastTimerView->getTime("Update Images")); + LLViewerStats::getInstance()->setStat(LLViewerStats::ST_REBUILD_SECS, gDebugView->mFastTimerView->getTime("Sort Draw State")); + LLViewerStats::getInstance()->setStat(LLViewerStats::ST_RENDER_SECS, gDebugView->mFastTimerView->getTime("Geometry")); LLCircuitData *cdp = gMessageSystem->mCircuitInfo.findCircuit(gAgent.getRegion()->getHost()); if (cdp) diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index 2faefc19b..66c79505b 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -440,9 +440,20 @@ const S32 min_non_tex_system_mem = (128<<20); // 128 MB F32 texmem_lower_bound_scale = 0.85f; F32 texmem_middle_bound_scale = 0.925f; +static LLFastTimer::DeclareTimer FTM_TEXTURE_MEMORY_CHECK("Memory Check"); //static bool LLViewerTexture::isMemoryForTextureLow() { + const F32 WAIT_TIME = 1.0f ; //second + static LLFrameTimer timer ; + + if(timer.getElapsedTimeF32() < WAIT_TIME) //call this once per second. + { + return false; + } + timer.reset() ; + + LLFastTimer t(FTM_TEXTURE_MEMORY_CHECK); const static S32 MIN_FREE_TEXTURE_MEMORY = 5 ; //MB const static S32 MIN_FREE_MAIN_MEMORy = 100 ; //MB @@ -456,6 +467,15 @@ bool LLViewerTexture::isMemoryForTextureLow() { low_mem = true ; } + + if(!low_mem) //check main memory, only works for windows. + { + LLMemory::updateMemoryInfo() ; + if(LLMemory::getAvailableMemKB() / 1024 < MIN_FREE_MAIN_MEMORy) + { + low_mem = true ; + } + } } #if 0 //ignore nVidia cards else if (gGLManager.mHasNVXMemInfo) @@ -470,18 +490,15 @@ bool LLViewerTexture::isMemoryForTextureLow() } #endif - if(!low_mem) //check main memory, only works for windows. - { - LLMemory::updateMemoryInfo() ; - if(LLMemory::getAvailableMemKB() / 1024 < MIN_FREE_MAIN_MEMORy) - { - low_mem = true ; - } - } - return low_mem ; } +#if NEW_MEDIA_TEXTURE +static LLFastTimer::DeclareTimer FTM_TEXTURE_UPDATE_MEDIA("Media"); +#endif //NEW_MEDIA_TEXTURE +#if 0 +static LLFastTimer::DeclareTimer FTM_TEXTURE_UPDATE_TEST("Test"); +#endif //static void LLViewerTexture::updateClass(const F32 velocity, const F32 angular_velocity) { @@ -491,11 +508,15 @@ void LLViewerTexture::updateClass(const F32 velocity, const F32 angular_velocity LLTexturePipelineTester* tester = (LLTexturePipelineTester*)LLMetricPerformanceTesterBasic::getTester(sTesterName); if (tester) { + LLFastTimer t(FTM_TEXTURE_UPDATE_TEST); tester->update() ; } #endif #if NEW_MEDIA_TEXTURE - LLViewerMediaTexture::updateClass() ; + { + LLFastTimer t(FTM_TEXTURE_UPDATE_MEDIA); + LLViewerMediaTexture::updateClass() ; + } #endif //NEW_MEDIA_TEXTURE sBoundTextureMemoryInBytes = LLImageGL::sBoundTextureMemoryInBytes;//in bytes diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp index f3a0c6bb8..041716435 100644 --- a/indra/newview/llviewertexturelist.cpp +++ b/indra/newview/llviewertexturelist.cpp @@ -74,6 +74,7 @@ U32 LLViewerTextureList::sTexturePackets = 0; S32 LLViewerTextureList::sNumImages = 0; LLViewerTextureList gTextureList; +static LLFastTimer::DeclareTimer FTM_PROCESS_IMAGES("Process Images"); /////////////////////////////////////////////////////////////////////////////// @@ -610,7 +611,13 @@ void LLViewerTextureList::dirtyImage(LLViewerFetchedTexture *image) } //////////////////////////////////////////////////////////////////////////// -//static LLFastTimer::DeclareTimer FTM_IMAGE_MARK_DIRTY("Dirty Images"); +static LLFastTimer::DeclareTimer FTM_IMAGE_MARK_DIRTY("Dirty Images"); +static LLFastTimer::DeclareTimer FTM_IMAGE_UPDATE_PRIORITIES("Prioritize"); +static LLFastTimer::DeclareTimer FTM_IMAGE_CALLBACKS("Callbacks"); +static LLFastTimer::DeclareTimer FTM_IMAGE_FETCH("Fetch"); +static LLFastTimer::DeclareTimer FTM_IMAGE_CREATE("Create"); +static LLFastTimer::DeclareTimer FTM_IMAGE_STATS("Stats"); +static LLFastTimer::DeclareTimer FTM_IMAGE_MEDIA("Media"); void LLViewerTextureList::updateImages(F32 max_time) { @@ -626,44 +633,63 @@ void LLViewerTextureList::updateImages(F32 max_time) LLViewerStats::getInstance()->mGLBoundMemStat.addValue((F32)BYTES_TO_MEGA_BYTES(LLImageGL::sBoundTextureMemoryInBytes)); LLViewerStats::getInstance()->mRawMemStat.addValue((F32)BYTES_TO_MEGA_BYTES(global_raw_memory)); LLViewerStats::getInstance()->mFormattedMemStat.addValue((F32)BYTES_TO_MEGA_BYTES(LLImageFormatted::sGlobalFormattedMemory)); - - updateImagesDecodePriorities(); + + + { + LLFastTimer t(FTM_IMAGE_UPDATE_PRIORITIES); + updateImagesDecodePriorities(); + } F32 total_max_time = max_time; - max_time -= updateImagesFetchTextures(max_time); + + { + LLFastTimer t(FTM_IMAGE_FETCH); + max_time -= updateImagesFetchTextures(max_time); + } - max_time = llmax(max_time, total_max_time*.50f); // at least 50% of max_time - max_time -= updateImagesCreateTextures(max_time); + { + LLFastTimer t(FTM_IMAGE_CREATE); + max_time = llmax(max_time, total_max_time*.50f); // at least 50% of max_time + max_time -= updateImagesCreateTextures(max_time); + } if (!mDirtyTextureList.empty()) { - LLFastTimer t(LLFastTimer::FTM_IMAGE_MARK_DIRTY); + LLFastTimer t(FTM_IMAGE_MARK_DIRTY); gPipeline.dirtyPoolObjectTextures(mDirtyTextureList); mDirtyTextureList.clear(); } - bool didone = false; - for (image_list_t::iterator iter = mCallbackList.begin(); - iter != mCallbackList.end(); ) + { - //trigger loaded callbacks on local textures immediately - LLViewerFetchedTexture* image = *iter++; - if (!image->getUrl().empty()) + LLFastTimer t(FTM_IMAGE_CALLBACKS); + bool didone = false; + for (image_list_t::iterator iter = mCallbackList.begin(); + iter != mCallbackList.end(); ) { - // Do stuff to handle callbacks, update priorities, etc. - didone = image->doLoadedCallbacks(); - } - else if (!didone) - { - // Do stuff to handle callbacks, update priorities, etc. - didone = image->doLoadedCallbacks(); + //trigger loaded callbacks on local textures immediately + LLViewerFetchedTexture* image = *iter++; + if (!image->getUrl().empty()) + { + // Do stuff to handle callbacks, update priorities, etc. + didone = image->doLoadedCallbacks(); + } + else if (!didone) + { + // Do stuff to handle callbacks, update priorities, etc. + didone = image->doLoadedCallbacks(); + } } } //Required for old media system if (!gNoRender && !gGLManager.mIsDisabled) { + LLFastTimer t(FTM_IMAGE_MEDIA); LLViewerMedia::updateMedia(); } - updateImagesUpdateStats(); + { + LLFastTimer t(FTM_IMAGE_STATS); + updateImagesUpdateStats(); + } } void LLViewerTextureList::updateImagesDecodePriorities() @@ -781,7 +807,6 @@ void LLViewerTextureList::updateImagesDecodePriorities() return type_from_host; } */ -//static LLFastTimer::DeclareTimer FTM_IMAGE_CREATE("Create Images"); F32 LLViewerTextureList::updateImagesCreateTextures(F32 max_time) { @@ -791,7 +816,7 @@ F32 LLViewerTextureList::updateImagesCreateTextures(F32 max_time) // Create GL textures for all textures that need them (images which have been // decoded, but haven't been pushed into GL). // - LLFastTimer t(LLFastTimer::FTM_IMAGE_CREATE); + LLFastTimer t(FTM_IMAGE_CREATE); LLTimer create_timer; image_list_t::iterator enditer = mCreateTextureList.begin(); @@ -1181,7 +1206,7 @@ void LLViewerTextureList::receiveImageHeader(LLMessageSystem *msg, void **user_d { static LLCachedControl log_texture_traffic(gSavedSettings,"LogTextureNetworkTraffic") ; - LLFastTimer t(LLFastTimer::FTM_PROCESS_IMAGES); + LLFastTimer t(FTM_PROCESS_IMAGES); // Receive image header, copy into image object and decompresses // if this is a one-packet image. @@ -1254,7 +1279,7 @@ void LLViewerTextureList::receiveImagePacket(LLMessageSystem *msg, void **user_d static LLCachedControl log_texture_traffic(gSavedSettings,"LogTextureNetworkTraffic") ; LLMemType mt1(LLMemType::MTYPE_APPFMTIMAGE); - LLFastTimer t(LLFastTimer::FTM_PROCESS_IMAGES); + LLFastTimer t(FTM_PROCESS_IMAGES); // Receives image packet, copy into image object, // checks if all packets received, decompresses if so. @@ -1326,7 +1351,7 @@ void LLViewerTextureList::receiveImagePacket(LLMessageSystem *msg, void **user_d // static void LLViewerTextureList::processImageNotInDatabase(LLMessageSystem *msg,void **user_data) { - LLFastTimer t(LLFastTimer::FTM_PROCESS_IMAGES); + LLFastTimer t(FTM_PROCESS_IMAGES); LLUUID image_id; msg->getUUIDFast(_PREHASH_ImageID, _PREHASH_ID, image_id); diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 582107ddb..7c7dc6c99 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -2791,6 +2791,9 @@ void LLViewerWindow::moveCursorToCenter() // event processing. BOOL LLViewerWindow::handlePerFrameHover() { + static LLFastTimer::DeclareTimer ftm("Update UI"); + LLFastTimer t(ftm); + static std::string last_handle_msg; LLView::sMouseHandlerMessage.clear(); diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h index 6e8bf7e56..86ca05fb4 100644 --- a/indra/newview/llviewerwindow.h +++ b/indra/newview/llviewerwindow.h @@ -398,6 +398,8 @@ private: public: LLWindow* mWindow; // graphical window object + void unblockToolTips(){mToolTipBlocked = FALSE;} //hack until LLToolTipMgr is ported. + protected: BOOL mActive; BOOL mWantFullscreen; diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 27a22670e..87005a669 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -2483,6 +2483,8 @@ S32 LLVOAvatar::setTETexture(const U8 te, const LLUUID& uuid) } } +static LLFastTimer::DeclareTimer FTM_AVATAR_UPDATE("Update Avatar"); +static LLFastTimer::DeclareTimer FTM_JOINT_UPDATE("Update Joints"); // setTEImage @@ -2492,7 +2494,7 @@ S32 LLVOAvatar::setTETexture(const U8 te, const LLUUID& uuid) BOOL LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) { LLMemType mt(LLMemType::MTYPE_AVATAR); - LLFastTimer t(LLFastTimer::FTM_AVATAR_UPDATE); + LLFastTimer t(FTM_AVATAR_UPDATE); if (isDead()) { @@ -2511,7 +2513,7 @@ BOOL LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) // force asynchronous drawable update if(mDrawable.notNull() && !gNoRender) { - LLFastTimer t(LLFastTimer::FTM_JOINT_UPDATE); + LLFastTimer t(FTM_JOINT_UPDATE); if (mIsSitting && getParent()) { @@ -2721,20 +2723,23 @@ void LLVOAvatar::idleUpdateVoiceVisualizer(bool voice_enabled) // here we get the approximate head position and set as sound source for the voice symbol // (the following version uses a tweak of "mHeadOffset" which handle sitting vs. standing) //-------------------------------------------------------------------------------------------- - if( !mIsSitting ) - { - LLVector3 tagPos = mRoot.getWorldPosition(); - tagPos[VZ] -= mPelvisToFoot; - tagPos[VZ] += ( mBodySize[VZ] + 0.125f ); - mVoiceVisualizer->setVoiceSourceWorldPosition( tagPos ); - } - else - { - LLVector3 headOffset = LLVector3( 0.0f, 0.0f, mHeadOffset.mV[2] ); - mVoiceVisualizer->setVoiceSourceWorldPosition( mRoot.getWorldPosition() + headOffset ); - } + + if ( mIsSitting ) + { + LLVector3 headOffset = LLVector3( 0.0f, 0.0f, mHeadOffset.mV[2] ); + mVoiceVisualizer->setVoiceSourceWorldPosition( mRoot.getWorldPosition() + headOffset ); + } + else + { + LLVector3 tagPos = mRoot.getWorldPosition(); + tagPos[VZ] -= mPelvisToFoot; + tagPos[VZ] += ( mBodySize[VZ] + 0.125f ); + mVoiceVisualizer->setVoiceSourceWorldPosition( tagPos ); + } }//if ( voiceEnabled ) -} +} + +static LLFastTimer::DeclareTimer FTM_ATTACHMENT_UPDATE("Update Attachments"); void LLVOAvatar::idleUpdateMisc(bool detailed_update) { @@ -2758,7 +2763,7 @@ void LLVOAvatar::idleUpdateMisc(bool detailed_update) // update attachments positions if (detailed_update || !sUseImpostors) { - LLFastTimer t(LLFastTimer::FTM_ATTACHMENT_UPDATE); + LLFastTimer t(FTM_ATTACHMENT_UPDATE); for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); iter != mAttachmentPoints.end(); ++iter) @@ -6003,9 +6008,11 @@ void LLVOAvatar::requestStopMotion( LLMotion* motion ) //----------------------------------------------------------------------------- // loadAvatar() //----------------------------------------------------------------------------- +static LLFastTimer::DeclareTimer FTM_LOAD_AVATAR("Load Avatar"); + BOOL LLVOAvatar::loadAvatar() { -// LLFastTimer t(LLFastTimer::FTM_LOAD_AVATAR); +// LLFastTimer t(FTM_LOAD_AVATAR); // avatar_skeleton.xml if( !buildSkeleton(sAvatarSkeletonInfo) ) @@ -6564,9 +6571,10 @@ void LLVOAvatar::updateGL() //----------------------------------------------------------------------------- // updateGeometry() //----------------------------------------------------------------------------- +static LLFastTimer::DeclareTimer FTM_UPDATE_AVATAR("Update Avatar"); BOOL LLVOAvatar::updateGeometry(LLDrawable *drawable) { - LLFastTimer ftm(LLFastTimer::FTM_UPDATE_AVATAR); + LLFastTimer ftm(FTM_UPDATE_AVATAR); if (!(gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_AVATAR))) { return TRUE; diff --git a/indra/newview/llvoclouds.cpp b/indra/newview/llvoclouds.cpp index 9bfe6f8e9..18e597b15 100644 --- a/indra/newview/llvoclouds.cpp +++ b/indra/newview/llvoclouds.cpp @@ -115,9 +115,10 @@ LLDrawable* LLVOClouds::createDrawable(LLPipeline *pipeline) return mDrawable; } +static LLFastTimer::DeclareTimer FTM_UPDATE_CLOUDS("Cloud Update"); BOOL LLVOClouds::updateGeometry(LLDrawable *drawable) { - LLFastTimer ftm(LLFastTimer::FTM_UPDATE_CLOUDS); + LLFastTimer ftm(FTM_UPDATE_CLOUDS); if (!(gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_CLASSIC_CLOUDS))) { return TRUE; diff --git a/indra/newview/llvograss.cpp b/indra/newview/llvograss.cpp index 225c83a54..70c67ee94 100644 --- a/indra/newview/llvograss.cpp +++ b/indra/newview/llvograss.cpp @@ -430,9 +430,12 @@ LLDrawable* LLVOGrass::createDrawable(LLPipeline *pipeline) return mDrawable; } +static LLFastTimer::DeclareTimer FTM_UPDATE_GRASS("Update Grass"); + BOOL LLVOGrass::updateGeometry(LLDrawable *drawable) { - LLFastTimer ftm(LLFastTimer::FTM_UPDATE_GRASS); + LLFastTimer ftm(FTM_UPDATE_GRASS); + dirtySpatialGroup(); if(!mNumBlades)//stop rendering grass diff --git a/indra/newview/llvopartgroup.cpp b/indra/newview/llvopartgroup.cpp index 8eb22554c..64ab53b88 100644 --- a/indra/newview/llvopartgroup.cpp +++ b/indra/newview/llvopartgroup.cpp @@ -141,9 +141,10 @@ LLVector3 LLVOPartGroup::getCameraPosition() const return gAgentCamera.getCameraPositionAgent(); } +static LLFastTimer::DeclareTimer FTM_UPDATE_PARTICLES("Update Particles"); BOOL LLVOPartGroup::updateGeometry(LLDrawable *drawable) { - LLFastTimer ftm(LLFastTimer::FTM_UPDATE_PARTICLES); + LLFastTimer ftm(FTM_UPDATE_PARTICLES); dirtySpatialGroup(); @@ -460,12 +461,15 @@ void LLParticlePartition::addGeometryCount(LLSpatialGroup* group, U32& vertex_co } } +static LLFastTimer::DeclareTimer FTM_REBUILD_GRASS_VB("Grass VB"); +static LLFastTimer::DeclareTimer FTM_REBUILD_PARTICLE_VB("Particle VB"); + void LLParticlePartition::getGeometry(LLSpatialGroup* group) { LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); LLFastTimer ftm(mDrawableType == LLPipeline::RENDER_TYPE_GRASS ? - LLFastTimer::FTM_REBUILD_GRASS_VB : - LLFastTimer::FTM_REBUILD_PARTICLE_VB); + FTM_REBUILD_GRASS_VB : + FTM_REBUILD_PARTICLE_VB); std::sort(mFaceList.begin(), mFaceList.end(), LLFace::CompareDistanceGreater()); diff --git a/indra/newview/llvosky.cpp b/indra/newview/llvosky.cpp index f5b15f5e3..4571df755 100644 --- a/indra/newview/llvosky.cpp +++ b/indra/newview/llvosky.cpp @@ -1255,6 +1255,7 @@ void LLVOSky::createDummyVertexBuffer() } } +static LLFastTimer::DeclareTimer FTM_RENDER_FAKE_VBO_UPDATE("Fake VBO Update"); void LLVOSky::updateDummyVertexBuffer() { if(!LLVertexBuffer::sEnableVBOs) @@ -1266,7 +1267,7 @@ void LLVOSky::updateDummyVertexBuffer() return ; } - LLFastTimer t(LLFastTimer::FTM_RENDER_FAKE_VBO_UPDATE) ; + LLFastTimer t(FTM_RENDER_FAKE_VBO_UPDATE) ; if(!mFace[FACE_DUMMY] || !mFace[FACE_DUMMY]->getVertexBuffer()) createDummyVertexBuffer() ; @@ -1279,10 +1280,11 @@ void LLVOSky::updateDummyVertexBuffer() //---------------------------------- //end of fake vertex buffer updating //---------------------------------- +static LLFastTimer::DeclareTimer FTM_GEO_SKY("Sky Geometry"); BOOL LLVOSky::updateGeometry(LLDrawable *drawable) { - LLFastTimer ftm(LLFastTimer::FTM_GEO_SKY); + LLFastTimer ftm(FTM_GEO_SKY); if (mFace[FACE_REFLECTION] == NULL) { LLDrawPoolWater *poolp = (LLDrawPoolWater*) gPipeline.getPool(LLDrawPool::POOL_WATER); diff --git a/indra/newview/llvosurfacepatch.cpp b/indra/newview/llvosurfacepatch.cpp index 0381a7c90..610697742 100644 --- a/indra/newview/llvosurfacepatch.cpp +++ b/indra/newview/llvosurfacepatch.cpp @@ -71,7 +71,7 @@ public: return; } - U8* base = useVBOs() ? (U8*) mAlignedOffset : /*(U8*)*/ mMappedData; + volatile U8* base = useVBOs() ? (U8*) mAlignedOffset : mMappedData; //assume tex coords 2 and 3 are present U32 type_mask = mTypeMask | MAP_TEXCOORD2 | MAP_TEXCOORD3; @@ -218,6 +218,7 @@ LLDrawable *LLVOSurfacePatch::createDrawable(LLPipeline *pipeline) return mDrawable; } +static LLFastTimer::DeclareTimer FTM_UPDATE_TERRAIN("Update Terrain"); void LLVOSurfacePatch::updateGL() { @@ -229,7 +230,7 @@ void LLVOSurfacePatch::updateGL() BOOL LLVOSurfacePatch::updateGeometry(LLDrawable *drawable) { - LLFastTimer ftm(LLFastTimer::FTM_UPDATE_TERRAIN); + LLFastTimer ftm(FTM_UPDATE_TERRAIN); dirtySpatialGroup(TRUE); @@ -1068,9 +1069,10 @@ LLVertexBuffer* LLTerrainPartition::createVertexBuffer(U32 type_mask, U32 usage) return new LLVertexBufferTerrain(); } +static LLFastTimer::DeclareTimer FTM_REBUILD_TERRAIN_VB("Terrain VB"); void LLTerrainPartition::getGeometry(LLSpatialGroup* group) { - LLFastTimer ftm(LLFastTimer::FTM_REBUILD_TERRAIN_VB); + LLFastTimer ftm(FTM_REBUILD_TERRAIN_VB); LLVertexBuffer* buffer = group->mVertexBuffer; diff --git a/indra/newview/llvotree.cpp b/indra/newview/llvotree.cpp index 030ff156a..39886e8fb 100644 --- a/indra/newview/llvotree.cpp +++ b/indra/newview/llvotree.cpp @@ -495,9 +495,11 @@ LLDrawable* LLVOTree::createDrawable(LLPipeline *pipeline) const S32 LEAF_INDICES = 24; const S32 LEAF_VERTICES = 16; +static LLFastTimer::DeclareTimer FTM_UPDATE_TREE("Update Tree"); + BOOL LLVOTree::updateGeometry(LLDrawable *drawable) { - LLFastTimer ftm(LLFastTimer::FTM_UPDATE_TREE); + LLFastTimer ftm(FTM_UPDATE_TREE); if(mTrunkLOD >= sMAX_NUM_TREE_LOD_LEVELS) //do not display the tree. { diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 79c560088..98c2f6661 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -94,6 +94,9 @@ F32 LLVOVolume::sDistanceFactor = 1.0f; S32 LLVOVolume::sNumLODChanges = 0; S32 LLVOVolume::mRenderComplexity_last = 0; S32 LLVOVolume::mRenderComplexity_current = 0; +static LLFastTimer::DeclareTimer FTM_GEN_TRIANGLES("Generate Triangles"); +static LLFastTimer::DeclareTimer FTM_GEN_VOLUME("Generate Volumes"); +static LLFastTimer::DeclareTimer FTM_VOLUME_TEXTURES("Volume Textures"); LLVOVolume::LLVOVolume(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp) : LLViewerObject(id, pcode, regionp), @@ -425,6 +428,9 @@ BOOL LLVOVolume::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) { LLViewerObject::idleUpdate(agent, world, time); + static LLFastTimer::DeclareTimer ftm("Volume"); + LLFastTimer t(ftm); + if (mDead || mDrawable.isNull()) { return TRUE; @@ -493,6 +499,7 @@ BOOL LLVOVolume::isVisible() const void LLVOVolume::updateTextureVirtualSize(bool forced) { + LLFastTimer ftm(FTM_VOLUME_TEXTURES); // Update the pixel area of all faces if(mDrawable.isNull()) @@ -1333,14 +1340,18 @@ void LLVOVolume::updateRelativeXform() } } +static LLFastTimer::DeclareTimer FTM_GEN_FLEX("Generate Flexies"); +static LLFastTimer::DeclareTimer FTM_UPDATE_PRIMITIVES("Update Primitives"); +static LLFastTimer::DeclareTimer FTM_UPDATE_RIGGED_VOLUME("Update Rigged"); + BOOL LLVOVolume::updateGeometry(LLDrawable *drawable) { - LLFastTimer t(LLFastTimer::FTM_UPDATE_PRIMITIVES); + LLFastTimer t(FTM_UPDATE_PRIMITIVES); if (mDrawable->isState(LLDrawable::REBUILD_RIGGED)) { { - LLFastTimer t2(LLFastTimer::FTM_UPDATE_RIGGED_VOLUME); + LLFastTimer t(FTM_UPDATE_RIGGED_VOLUME); updateRiggedVolume(); } genBBoxes(FALSE); @@ -1351,7 +1362,7 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable) { BOOL res; { - LLFastTimer t(LLFastTimer::FTM_GEN_FLEX); + LLFastTimer t(FTM_GEN_FLEX); res = mVolumeImpl->doUpdateGeometry(drawable); } updateFaceFlags(); @@ -1375,14 +1386,14 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable) if (mVolumeChanged) { - LLFastTimer ftm(LLFastTimer::FTM_GEN_VOLUME); + LLFastTimer ftm(FTM_GEN_VOLUME); LLVolumeParams volume_params = getVolume()->getParams(); setVolume(volume_params, 0); drawable->setState(LLDrawable::REBUILD_VOLUME); } { - LLFastTimer t(LLFastTimer::FTM_GEN_TRIANGLES); + LLFastTimer t(FTM_GEN_TRIANGLES); regenFaces(); genBBoxes(FALSE); } @@ -1399,7 +1410,7 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable) old_volumep = NULL ; { - LLFastTimer ftm(LLFastTimer::FTM_GEN_VOLUME); + LLFastTimer ftm(FTM_GEN_VOLUME); LLVolumeParams volume_params = getVolume()->getParams(); setVolume(volume_params, 0); } @@ -1422,7 +1433,7 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable) drawable->setState(LLDrawable::REBUILD_VOLUME); // for face->genVolumeTriangles() { - LLFastTimer t(LLFastTimer::FTM_GEN_TRIANGLES); + LLFastTimer t(FTM_GEN_TRIANGLES); if (new_num_faces != old_num_faces || mNumFaces != (S32)getNumTEs()) { regenFaces(); @@ -1447,7 +1458,7 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable) { compiled = TRUE; // All it did was move or we changed the texture coordinate offset - LLFastTimer t(LLFastTimer::FTM_GEN_TRIANGLES); + LLFastTimer t(FTM_GEN_TRIANGLES); genBBoxes(FALSE); } @@ -2949,9 +2960,8 @@ void LLVOVolume::updateRiggedVolume() } - -//static LLFastTimer::DeclareTimer FTM_SKIN_RIGGED("Skin"); -//static LLFastTimer::DeclareTimer FTM_RIGGED_OCTREE("Octree"); +static LLFastTimer::DeclareTimer FTM_SKIN_RIGGED("Skin"); +static LLFastTimer::DeclareTimer FTM_RIGGED_OCTREE("Octree"); void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, const LLVolume* volume) { @@ -3006,7 +3016,7 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons LLVector4a* pos = dst_face.mPositions; { - LLFastTimer t(LLFastTimer::FTM_SKIN_RIGGED); + LLFastTimer t(FTM_SKIN_RIGGED); for (U32 j = 0; j < (U32)dst_face.mNumVertices; ++j) { @@ -3067,7 +3077,7 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons } { - LLFastTimer t(LLFastTimer::FTM_RIGGED_OCTREE); + LLFastTimer t(FTM_RIGGED_OCTREE); delete dst_face.mOctree; dst_face.mOctree = NULL; @@ -3273,6 +3283,9 @@ void LLVolumeGeometryManager::getGeometry(LLSpatialGroup* group) } +static LLFastTimer::DeclareTimer FTM_REBUILD_VOLUME_VB("Volume"); +static LLFastTimer::DeclareTimer FTM_REBUILD_VBO("VBO Rebuilt"); + static LLDrawPoolAvatar* get_avatar_drawpool(LLViewerObject* vobj) { LLVOAvatar* avatar = vobj->getAvatar(); @@ -3318,8 +3331,8 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) { if (group->isState(LLSpatialGroup::MESH_DIRTY) && !LLPipeline::sDelayVBUpdate) { - LLFastTimer ftm(LLFastTimer::FTM_REBUILD_VBO); - LLFastTimer ftm2(LLFastTimer::FTM_REBUILD_VOLUME_VB); + LLFastTimer ftm(FTM_REBUILD_VBO); + LLFastTimer ftm2(FTM_REBUILD_VOLUME_VB); rebuildMesh(group); } @@ -3327,9 +3340,9 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) } group->mBuilt = 1.f; - LLFastTimer ftm(LLFastTimer::FTM_REBUILD_VBO); + LLFastTimer ftm(FTM_REBUILD_VBO); - LLFastTimer ftm2(LLFastTimer::FTM_REBUILD_VOLUME_VB); + LLFastTimer ftm2(FTM_REBUILD_VOLUME_VB); group->clearDrawMap(); @@ -3748,12 +3761,15 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) mFaceList.clear(); } +static LLFastTimer::DeclareTimer FTM_VOLUME_GEOM("Volume Geometry"); +static LLFastTimer::DeclareTimer FTM_VOLUME_GEOM_PARTIAL("Terse Rebuild"); void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group) { llassert(group); static int warningsCount = 20; if (group && group->isState(LLSpatialGroup::MESH_DIRTY) && !group->isState(LLSpatialGroup::GEOM_DIRTY)) { + LLFastTimer tm(FTM_VOLUME_GEOM); S32 num_mapped_vertex_buffer = LLVertexBuffer::sMappedCount ; group->mBuilt = 1.f; @@ -3762,6 +3778,7 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group) for (LLSpatialGroup::element_iter drawable_iter = group->getData().begin(); drawable_iter != group->getData().end(); ++drawable_iter) { + LLFastTimer t(FTM_VOLUME_GEOM_PARTIAL); LLDrawable* drawablep = *drawable_iter; /*if (drawablep->isState(LLDrawable::FORCE_INVISIBLE) ) @@ -3961,7 +3978,6 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std:: if (batch_textures) { - LLFastTimer t_ftm(LLFastTimer::FTM_TEMP6); U8 cur_tex = 0; facep->setTextureIndex(cur_tex); texture_list.push_back(tex); @@ -4052,17 +4068,20 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std:: //create/delete/resize vertex buffer if needed LLVertexBuffer* buffer = NULL; - LLSpatialGroup::buffer_texture_map_t::iterator found_iter = group->mBufferMap[mask].find(*face_iter); + + { //try to find a buffer to reuse + LLSpatialGroup::buffer_texture_map_t::iterator found_iter = group->mBufferMap[mask].find(*face_iter); - if (found_iter != group->mBufferMap[mask].end()) - { - if ((U32) buffer_index < found_iter->second.size()) + if (found_iter != group->mBufferMap[mask].end()) { - buffer = found_iter->second[buffer_index]; + if ((U32) buffer_index < found_iter->second.size()) + { + buffer = found_iter->second[buffer_index]; + } } } - if (!buffer) + if (!buffer || !buffer->isWriteable()) { //create new buffer if needed buffer = createVertexBuffer(mask, buffer_usage); buffer->allocateBuffer(geom_count, index_count, TRUE); diff --git a/indra/newview/llvowater.cpp b/indra/newview/llvowater.cpp index 3d9422e90..f84bd75e1 100644 --- a/indra/newview/llvowater.cpp +++ b/indra/newview/llvowater.cpp @@ -139,9 +139,10 @@ LLDrawable *LLVOWater::createDrawable(LLPipeline *pipeline) return mDrawable; } +static LLFastTimer::DeclareTimer FTM_UPDATE_WATER("Update Water"); BOOL LLVOWater::updateGeometry(LLDrawable *drawable) { - LLFastTimer ftm(LLFastTimer::FTM_UPDATE_WATER); + LLFastTimer ftm(FTM_UPDATE_WATER); LLFace *face; if (drawable->getNumFaces() < 1) @@ -171,7 +172,7 @@ BOOL LLVOWater::updateGeometry(LLDrawable *drawable) indices_per_quad * num_quads); LLVertexBuffer* buff = face->getVertexBuffer(); - if (!buff) + if (!buff || !buff->isWriteable()) { buff = new LLVertexBuffer(LLDrawPoolWater::VERTEX_DATA_MASK, GL_DYNAMIC_DRAW_ARB); buff->allocateBuffer(face->getGeomCount(), face->getIndicesCount(), TRUE); diff --git a/indra/newview/llvowlsky.cpp b/indra/newview/llvowlsky.cpp index bdfe68f2d..e9a03fee8 100644 --- a/indra/newview/llvowlsky.cpp +++ b/indra/newview/llvowlsky.cpp @@ -307,9 +307,11 @@ void LLVOWLSky::restoreGL() gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_ALL, TRUE); } +static LLFastTimer::DeclareTimer FTM_GEO_SKY("Sky Geometry"); + BOOL LLVOWLSky::updateGeometry(LLDrawable * drawable) { - LLFastTimer ftm(LLFastTimer::FTM_GEO_SKY); + LLFastTimer ftm(FTM_GEO_SKY); LLStrider vertices; LLStrider texCoords; LLStrider indices; @@ -775,7 +777,7 @@ BOOL LLVOWLSky::updateStarGeometry(LLDrawable *drawable) LLStrider colorsp; LLStrider texcoordsp; - if (mStarsVerts.isNull()) + if (mStarsVerts.isNull() || !mStarsVerts->isWriteable()) { mStarsVerts = new LLVertexBuffer(LLDrawPoolWLSky::STAR_VERTEX_DATA_MASK, GL_DYNAMIC_DRAW); mStarsVerts->allocateBuffer(getStarsNumVerts()*6, 0, TRUE); diff --git a/indra/newview/llwaterparammanager.cpp b/indra/newview/llwaterparammanager.cpp index ee8b9a00f..782f70e1f 100644 --- a/indra/newview/llwaterparammanager.cpp +++ b/indra/newview/llwaterparammanager.cpp @@ -277,9 +277,11 @@ void LLWaterParamManager::updateShaderLinks() } } +static LLFastTimer::DeclareTimer FTM_UPDATE_WATERPARAM("Update Water Params"); + void LLWaterParamManager::update(LLViewerCamera * cam) { - LLFastTimer ftm(LLFastTimer::FTM_UPDATE_WLPARAM); + LLFastTimer ftm(FTM_UPDATE_WATERPARAM); // update the shaders and the menu propagateParameters(); diff --git a/indra/newview/llwearable.cpp b/indra/newview/llwearable.cpp index cf8157c64..5f7c79786 100644 --- a/indra/newview/llwearable.cpp +++ b/indra/newview/llwearable.cpp @@ -659,7 +659,7 @@ void LLWearable::writeToAvatar( BOOL set_by_user ) if( gFloaterCustomize ) { LLViewerInventoryItem* item; - item = (LLViewerInventoryItem*)gInventory.getItem(gAgentWearables.getWearableItemID(mType)); + item = (LLViewerInventoryItem*)gInventory.getItem(gAgentWearables.getWearableItemID(mType, 0)); // TODO: MULTI-WEARABLE U32 perm_mask = PERM_NONE; BOOL is_complete = FALSE; if(item) diff --git a/indra/newview/llwearablelist.h b/indra/newview/llwearablelist.h index 890bf18f5..6f64549ae 100644 --- a/indra/newview/llwearablelist.h +++ b/indra/newview/llwearablelist.h @@ -33,6 +33,7 @@ #ifndef LL_LLWEARABLELIST_H #define LL_LLWEARABLELIST_H +#include "llmemory.h" #include "llwearable.h" #include "lluuid.h" #include "llassetstorage.h" diff --git a/indra/newview/llwlparammanager.cpp b/indra/newview/llwlparammanager.cpp index 35ee41de8..a79c83b44 100644 --- a/indra/newview/llwlparammanager.cpp +++ b/indra/newview/llwlparammanager.cpp @@ -286,6 +286,7 @@ void LLWLParamManager::updateShaderUniforms(LLGLSLShader * shader) shader->uniform1f("scene_light_strength", mSceneLightStrength); } +static LLFastTimer::DeclareTimer FTM_UPDATE_WLPARAM("Update Windlight Params"); void LLWLParamManager::updateShaderLinks() { @@ -308,7 +309,7 @@ void LLWLParamManager::updateShaderLinks() void LLWLParamManager::propagateParameters(void) { - LLFastTimer ftm(LLFastTimer::FTM_UPDATE_WLPARAM); + LLFastTimer ftm(FTM_UPDATE_WLPARAM); LLVector4 sunDir; LLVector4 moonDir; @@ -373,7 +374,7 @@ void LLWLParamManager::propagateParameters(void) void LLWLParamManager::update(LLViewerCamera * cam) { - LLFastTimer ftm(LLFastTimer::FTM_UPDATE_WLPARAM); + LLFastTimer ftm(FTM_UPDATE_WLPARAM); // update clouds, sun, and general mCurParams.updateCloudScrolling(); diff --git a/indra/newview/llwlparamset.cpp b/indra/newview/llwlparamset.cpp index 4f62db627..6345cbdd8 100644 --- a/indra/newview/llwlparamset.cpp +++ b/indra/newview/llwlparamset.cpp @@ -75,8 +75,12 @@ LLWLParamSet::LLWLParamSet(void) : */ } +static LLFastTimer::DeclareTimer FTM_WL_PARAM_UPDATE("WL Param Update"); + void LLWLParamSet::update(LLGLSLShader * shader) const { + LLFastTimer t(FTM_WL_PARAM_UPDATE); + for(LLSD::map_const_iterator i = mParamValues.beginMap(); i != mParamValues.endMap(); ++i) diff --git a/indra/newview/llworldmapview.cpp b/indra/newview/llworldmapview.cpp index 7ca97a0c1..c88b58389 100644 --- a/indra/newview/llworldmapview.cpp +++ b/indra/newview/llworldmapview.cpp @@ -36,6 +36,7 @@ #include "indra_constants.h" #include "llui.h" +#include "lllocalcliprect.h" #include "llmath.h" // clampf() #include "llregionhandle.h" #include "lleventflags.h" diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 71d345192..3fe1cc896 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -166,6 +166,35 @@ BOOL gDebugPipeline = FALSE; LLPipeline gPipeline; const LLMatrix4* gGLLastMatrix = NULL; +LLFastTimer::DeclareTimer FTM_RENDER_GEOMETRY("Geometry"); +LLFastTimer::DeclareTimer FTM_RENDER_GRASS("Grass"); +LLFastTimer::DeclareTimer FTM_RENDER_INVISIBLE("Invisible"); +LLFastTimer::DeclareTimer FTM_RENDER_OCCLUSION("Occlusion"); +LLFastTimer::DeclareTimer FTM_RENDER_SHINY("Shiny"); +LLFastTimer::DeclareTimer FTM_RENDER_SIMPLE("Simple"); +LLFastTimer::DeclareTimer FTM_RENDER_TERRAIN("Terrain"); +LLFastTimer::DeclareTimer FTM_RENDER_TREES("Trees"); +LLFastTimer::DeclareTimer FTM_RENDER_UI("UI"); +LLFastTimer::DeclareTimer FTM_RENDER_WATER("Water"); +LLFastTimer::DeclareTimer FTM_RENDER_WL_SKY("Windlight Sky"); +LLFastTimer::DeclareTimer FTM_RENDER_ALPHA("Alpha Objects"); +LLFastTimer::DeclareTimer FTM_RENDER_CHARACTERS("Avatars"); +LLFastTimer::DeclareTimer FTM_RENDER_BUMP("Bump"); +LLFastTimer::DeclareTimer FTM_RENDER_FULLBRIGHT("Fullbright"); +LLFastTimer::DeclareTimer FTM_RENDER_GLOW("Glow"); +LLFastTimer::DeclareTimer FTM_GEO_UPDATE("Geo Update"); +LLFastTimer::DeclareTimer FTM_POOLRENDER("RenderPool"); +LLFastTimer::DeclareTimer FTM_POOLS("Pools"); +LLFastTimer::DeclareTimer FTM_RENDER_BLOOM_FBO("First FBO"); +LLFastTimer::DeclareTimer FTM_STATESORT("Sort Draw State"); +LLFastTimer::DeclareTimer FTM_PIPELINE("Pipeline"); +LLFastTimer::DeclareTimer FTM_CLIENT_COPY("Client Copy"); +LLFastTimer::DeclareTimer FTM_RENDER_DEFERRED("Deferred Shading"); + + +static LLFastTimer::DeclareTimer FTM_STATESORT_DRAWABLE("Sort Drawables"); +static LLFastTimer::DeclareTimer FTM_STATESORT_POSTSORT("Post Sort"); + //---------------------------------------- std::string gPoolNames[] = { @@ -531,6 +560,7 @@ void LLPipeline::destroyGL() } } +static LLFastTimer::DeclareTimer FTM_RESIZE_SCREEN_TEXTURE("Resize Screen Texture"); //static void LLPipeline::throttleNewMemoryAllocation(BOOL disable) @@ -551,6 +581,7 @@ void LLPipeline::throttleNewMemoryAllocation(BOOL disable) } void LLPipeline::resizeScreenTexture() { + LLFastTimer ft(FTM_RESIZE_SCREEN_TEXTURE); if (gPipeline.canUseVertexShaders() && assertInitialized()) { GLuint resX = gViewerWindow->getWorldViewWidthRaw(); @@ -1279,9 +1310,15 @@ void LLPipeline::allocDrawable(LLViewerObject *vobj) } +static LLFastTimer::DeclareTimer FTM_UNLINK("Unlink"); +static LLFastTimer::DeclareTimer FTM_REMOVE_FROM_MOVE_LIST("Movelist"); +static LLFastTimer::DeclareTimer FTM_REMOVE_FROM_SPATIAL_PARTITION("Spatial Partition"); +static LLFastTimer::DeclareTimer FTM_REMOVE_FROM_LIGHT_SET("Light Set"); +//static LLFastTimer::DeclareTimer FTM_REMOVE_FROM_HIGHLIGHT_SET("Highlight Set"); + void LLPipeline::unlinkDrawable(LLDrawable *drawable) { - LLFastTimer t(LLFastTimer::FTM_PIPELINE); + LLFastTimer t(FTM_UNLINK); assertInitialized(); @@ -1290,6 +1327,7 @@ void LLPipeline::unlinkDrawable(LLDrawable *drawable) // Based on flags, remove the drawable from the queues that it's on. if (drawablep->isState(LLDrawable::ON_MOVE_LIST)) { + LLFastTimer t(FTM_REMOVE_FROM_MOVE_LIST); LLDrawable::drawable_vector_t::iterator iter = std::find(mMovedList.begin(), mMovedList.end(), drawablep); if (iter != mMovedList.end()) { @@ -1299,6 +1337,7 @@ void LLPipeline::unlinkDrawable(LLDrawable *drawable) if (drawablep->getSpatialGroup()) { + LLFastTimer t(FTM_REMOVE_FROM_SPATIAL_PARTITION); if (!drawablep->getSpatialGroup()->mSpatialPartition->remove(drawablep, drawablep->getSpatialGroup())) { #ifdef LL_RELEASE_FOR_DOWNLOAD @@ -1309,14 +1348,18 @@ void LLPipeline::unlinkDrawable(LLDrawable *drawable) } } - mLights.erase(drawablep); - for (light_set_t::iterator iter = mNearbyLights.begin(); - iter != mNearbyLights.end(); iter++) { - if (iter->drawable == drawablep) + LLFastTimer t(FTM_REMOVE_FROM_LIGHT_SET); + mLights.erase(drawablep); + + for (light_set_t::iterator iter = mNearbyLights.begin(); + iter != mNearbyLights.end(); iter++) { - mNearbyLights.erase(iter); - break; + if (iter->drawable == drawablep) + { + mNearbyLights.erase(iter); + break; + } } } @@ -1359,7 +1402,7 @@ U32 LLPipeline::addObject(LLViewerObject *vobj) void LLPipeline::createObjects(F32 max_dtime) { - LLFastTimer ftm(LLFastTimer::FTM_GEO_UPDATE); + LLFastTimer ftm(FTM_GEO_UPDATE); LLMemType mt(LLMemType::MTYPE_DRAWABLE); LLTimer update_timer; @@ -1529,9 +1572,12 @@ void LLPipeline::updateMovedList(LLDrawable::drawable_vector_t& moved_list) } } +static LLFastTimer::DeclareTimer FTM_OCTREE_BALANCE("Balance Octree"); +static LLFastTimer::DeclareTimer FTM_UPDATE_MOVE("Update Move"); + void LLPipeline::updateMove() { - LLFastTimer t(LLFastTimer::FTM_UPDATE_MOVE); + LLFastTimer t(FTM_UPDATE_MOVE); LLMemType mt(LLMemType::MTYPE_PIPELINE); static const LLCachedControl freeze_time("FreezeTime",false); @@ -1542,23 +1588,31 @@ void LLPipeline::updateMove() assertInitialized(); - for (LLDrawable::drawable_set_t::iterator iter = mRetexturedList.begin(); - iter != mRetexturedList.end(); ++iter) { - LLDrawable* drawablep = *iter; - if (drawablep && !drawablep->isDead()) + static LLFastTimer::DeclareTimer ftm("Retexture"); + LLFastTimer t(ftm); + + for (LLDrawable::drawable_set_t::iterator iter = mRetexturedList.begin(); + iter != mRetexturedList.end(); ++iter) { - drawablep->updateTexture(); + LLDrawable* drawablep = *iter; + if (drawablep && !drawablep->isDead()) + { + drawablep->updateTexture(); + } } + mRetexturedList.clear(); } - mRetexturedList.clear(); + { + static LLFastTimer::DeclareTimer ftm("Moved List"); + LLFastTimer t(ftm); updateMovedList(mMovedList); } //balance octrees { - LLFastTimer ot(LLFastTimer::FTM_OCTREE_BALANCE); + LLFastTimer ot(FTM_OCTREE_BALANCE); for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); iter != LLWorld::getInstance()->getRegionList().end(); ++iter) @@ -1873,11 +1927,12 @@ BOOL LLPipeline::getVisibleExtents(LLCamera& camera, LLVector3& min, LLVector3& return res; } +static LLFastTimer::DeclareTimer FTM_CULL("Object Culling"); void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, S32 water_clip, LLPlane* planep) { - LLFastTimer t(LLFastTimer::FTM_CULL); - LLMemType mt(LLMemType::MTYPE_PIPELINE); + LLFastTimer t(FTM_CULL); + LLMemType mt_uc(LLMemType::MTYPE_PIPELINE); grabReferences(result); @@ -2249,7 +2304,7 @@ void LLPipeline::updateGeom(F32 max_dtime) LLMemType mt(LLMemType::MTYPE_PIPELINE); LLPointer drawablep; - LLFastTimer t(LLFastTimer::FTM_GEO_UPDATE); + LLFastTimer t(FTM_GEO_UPDATE); assertInitialized(); @@ -2627,6 +2682,8 @@ void LLPipeline::markRebuild(LLDrawable *drawablep, LLDrawable::EDrawableFlags f } } +static LLFastTimer::DeclareTimer FTM_RESET_DRAWORDER("Reset Draw Order"); + void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result) { if (hasAnyRenderType(LLPipeline::RENDER_TYPE_AVATAR, @@ -2639,11 +2696,11 @@ void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result) LLPipeline::END_RENDER_TYPES)) { //clear faces from face pools - LLFastTimer t(LLFastTimer::FTM_RESET_DRAWORDER); + LLFastTimer t(FTM_RESET_DRAWORDER); gPipeline.resetDrawOrders(); } - LLFastTimer ftm(LLFastTimer::FTM_STATESORT); + LLFastTimer ftm(FTM_STATESORT); LLMemType mt(LLMemType::MTYPE_PIPELINE); //LLVertexBuffer::unbind(); @@ -2728,7 +2785,7 @@ void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result) } { - LLFastTimer ftm(LLFastTimer::FTM_STATESORT_DRAWABLE); + LLFastTimer ftm(FTM_STATESORT_DRAWABLE); for (LLCullResult::drawable_list_t::iterator iter = sCull->beginVisibleList(); iter != sCull->endVisibleList(); ++iter) { @@ -3022,7 +3079,7 @@ void renderSoundHighlights(LLDrawable* drawablep) void LLPipeline::postSort(LLCamera& camera) { LLMemType mt(LLMemType::MTYPE_PIPELINE); - LLFastTimer ftm(LLFastTimer::FTM_STATESORT_POSTSORT); + LLFastTimer ftm(FTM_STATESORT_POSTSORT); assertInitialized(); @@ -3261,7 +3318,7 @@ void LLPipeline::postSort(LLCamera& camera) void render_hud_elements() { - LLFastTimer t(LLFastTimer::FTM_RENDER_UI); + LLFastTimer t(FTM_RENDER_UI); gPipeline.disableLights(); LLGLDisable fog(GL_FOG); @@ -3387,7 +3444,7 @@ U32 LLPipeline::sCurRenderPoolType = 0 ; void LLPipeline::renderGeom(LLCamera& camera, BOOL forceVBOUpdate) { LLMemType mt(LLMemType::MTYPE_PIPELINE); - LLFastTimer t(LLFastTimer::FTM_RENDER_GEOMETRY); + LLFastTimer t(FTM_RENDER_GEOMETRY); assertInitialized(); @@ -3432,6 +3489,7 @@ void LLPipeline::renderGeom(LLCamera& camera, BOOL forceVBOUpdate) gFrameStats.start(LLFrameStats::RENDER_GEOM); // Initialize lots of GL state to "safe" values + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); gGL.matrixMode(LLRender::MM_TEXTURE); gGL.loadIdentity(); gGL.matrixMode(LLRender::MM_MODELVIEW); @@ -3476,7 +3534,7 @@ void LLPipeline::renderGeom(LLCamera& camera, BOOL forceVBOUpdate) } { - LLFastTimer t(LLFastTimer::FTM_POOLS); + LLFastTimer t(FTM_POOLS); // HACK: don't calculate local lights if we're rendering the HUD! // Removing this check will cause bad flickering when there are @@ -3512,7 +3570,7 @@ void LLPipeline::renderGeom(LLCamera& camera, BOOL forceVBOUpdate) pool_set_t::iterator iter2 = iter1; if (hasRenderType(poolp->getType()) && poolp->getNumPasses() > 0) { - LLFastTimer t(LLFastTimer::FTM_POOLRENDER); + LLFastTimer t(FTM_POOLRENDER); gGLLastMatrix = NULL; gGL.loadMatrix(gGLModelView); @@ -3650,9 +3708,9 @@ void LLPipeline::renderGeom(LLCamera& camera, BOOL forceVBOUpdate) void LLPipeline::renderGeomDeferred(LLCamera& camera) { LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderGeomDeferred"); - LLFastTimer t(LLFastTimer::FTM_RENDER_GEOMETRY); + LLFastTimer t(FTM_RENDER_GEOMETRY); - LLFastTimer t2(LLFastTimer::FTM_POOLS); + LLFastTimer t2(FTM_POOLS); LLGLEnable cull(GL_CULL_FACE); @@ -3695,7 +3753,7 @@ void LLPipeline::renderGeomDeferred(LLCamera& camera) pool_set_t::iterator iter2 = iter1; if (hasRenderType(poolp->getType()) && poolp->getNumDeferredPasses() > 0) { - LLFastTimer t(LLFastTimer::FTM_POOLRENDER); + LLFastTimer t(FTM_POOLRENDER); gGLLastMatrix = NULL; gGL.loadMatrix(gGLModelView); @@ -3749,7 +3807,7 @@ void LLPipeline::renderGeomDeferred(LLCamera& camera) void LLPipeline::renderGeomPostDeferred(LLCamera& camera) { - LLFastTimer t(LLFastTimer::FTM_POOLS); + LLFastTimer t(FTM_POOLS); U32 cur_type = 0; LLGLEnable cull(GL_CULL_FACE); @@ -3784,7 +3842,7 @@ void LLPipeline::renderGeomPostDeferred(LLCamera& camera) pool_set_t::iterator iter2 = iter1; if (hasRenderType(poolp->getType()) && poolp->getNumPostDeferredPasses() > 0) { - LLFastTimer t(LLFastTimer::FTM_POOLRENDER); + LLFastTimer t(FTM_POOLRENDER); gGLLastMatrix = NULL; gGL.loadMatrix(gGLModelView); @@ -5925,6 +5983,7 @@ void LLPipeline::bindScreenToTexture() } +static LLFastTimer::DeclareTimer FTM_RENDER_BLOOM("Bloom"); void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield, bool tiling) { if (!(gPipeline.canUseVertexShaders() && @@ -5974,7 +6033,7 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield, b tc2 /= (F32) res_mod; } - LLFastTimer ftm(LLFastTimer::FTM_RENDER_BLOOM); + LLFastTimer ftm(FTM_RENDER_BLOOM); gGL.color4f(1,1,1,1); LLGLDepthTest depth(GL_FALSE); LLGLDisable blend(GL_BLEND); @@ -6048,7 +6107,7 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield, b { { - LLFastTimer ftm(LLFastTimer::FTM_RENDER_BLOOM_FBO); + LLFastTimer ftm(FTM_RENDER_BLOOM_FBO); mGlow[2].bindTarget(); mGlow[2].clear(); } @@ -6116,7 +6175,7 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield, b for (S32 i = 0; i < kernel; i++) { { - LLFastTimer ftm(LLFastTimer::FTM_RENDER_BLOOM_FBO); + LLFastTimer ftm(FTM_RENDER_BLOOM_FBO); mGlow[i%2].bindTarget(); mGlow[i%2].clear(); } @@ -6158,7 +6217,7 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield, b if (LLRenderTarget::sUseFBO) { - LLFastTimer ftm(LLFastTimer::FTM_RENDER_BLOOM_FBO); + LLFastTimer ftm(FTM_RENDER_BLOOM_FBO); glBindFramebuffer(GL_FRAMEBUFFER, 0); } @@ -6597,9 +6656,11 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield, b } +static LLFastTimer::DeclareTimer FTM_BIND_DEFERRED("Bind Deferred"); + void LLPipeline::bindDeferredShader(LLGLSLShader& shader, U32 light_index, U32 noise_map) { - LLFastTimer t(LLFastTimer::FTM_BIND_DEFERRED); + LLFastTimer t(FTM_BIND_DEFERRED); static const LLCachedControl RenderDeferredSunWash("RenderDeferredSunWash",.5f); static const LLCachedControl RenderShadowNoise("RenderShadowNoise",-.0001f); @@ -6822,6 +6883,18 @@ void LLPipeline::bindDeferredShader(LLGLSLShader& shader, U32 light_index, U32 n } } +static LLFastTimer::DeclareTimer FTM_GI_TRACE("Trace"); +static LLFastTimer::DeclareTimer FTM_GI_GATHER("Gather"); +static LLFastTimer::DeclareTimer FTM_SUN_SHADOW("Shadow Map"); +static LLFastTimer::DeclareTimer FTM_SOFTEN_SHADOW("Shadow Soften"); +static LLFastTimer::DeclareTimer FTM_EDGE_DETECTION("Find Edges"); +static LLFastTimer::DeclareTimer FTM_LOCAL_LIGHTS("Local Lights"); +static LLFastTimer::DeclareTimer FTM_ATMOSPHERICS("Atmospherics"); +static LLFastTimer::DeclareTimer FTM_FULLSCREEN_LIGHTS("Fullscreen Lights"); +static LLFastTimer::DeclareTimer FTM_PROJECTORS("Projectors"); +static LLFastTimer::DeclareTimer FTM_POST("Post"); + + void LLPipeline::renderDeferredLighting() { if (!sCull) @@ -6839,7 +6912,7 @@ void LLPipeline::renderDeferredLighting() static const LLCachedControl RenderLocalLights("RenderLocalLights",false); { - LLFastTimer ftm(LLFastTimer::FTM_RENDER_DEFERRED); + LLFastTimer ftm(FTM_RENDER_DEFERRED); LLViewerCamera* camera = LLViewerCamera::getInstance(); { @@ -6899,7 +6972,7 @@ void LLPipeline::renderDeferredLighting() { mDeferredLight.bindTarget(); { //paint shadow/SSAO light map (direct lighting lightmap) - LLFastTimer ftm(LLFastTimer::FTM_SUN_SHADOW); + LLFastTimer ftm(FTM_SUN_SHADOW); bindDeferredShader(gDeferredSunProgram, 0); mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX); glClearColor(1,1,1,1); @@ -6943,7 +7016,7 @@ void LLPipeline::renderDeferredLighting() if (RenderDeferredSSAO) { //soften direct lighting lightmap - LLFastTimer ftm(LLFastTimer::FTM_SOFTEN_SHADOW); + LLFastTimer ftm(FTM_SOFTEN_SHADOW); //blur lightmap mScreen.bindTarget(); glClearColor(1,1,1,1); @@ -7022,7 +7095,7 @@ void LLPipeline::renderDeferredLighting() if (RenderDeferredAtmospheric) { //apply sunlight contribution - LLFastTimer ftm(LLFastTimer::FTM_ATMOSPHERICS); + LLFastTimer ftm(FTM_ATMOSPHERICS); bindDeferredShader(gDeferredSoftenProgram); { LLGLDepthTest depth(GL_FALSE); @@ -7168,7 +7241,7 @@ void LLPipeline::renderDeferredLighting() continue; } - LLFastTimer ftm(LLFastTimer::FTM_LOCAL_LIGHTS); + LLFastTimer ftm(FTM_LOCAL_LIGHTS); //glTexCoord4f(tc.v[0], tc.v[1], tc.v[2], s*s); gDeferredLightProgram.uniform3fv(LLShaderMgr::LIGHT_CENTER, 1, tc.v); gDeferredLightProgram.uniform1f(LLShaderMgr::LIGHT_SIZE, s*s); @@ -7209,7 +7282,7 @@ void LLPipeline::renderDeferredLighting() for (LLDrawable::drawable_list_t::iterator iter = spot_lights.begin(); iter != spot_lights.end(); ++iter) { - LLFastTimer ftm(LLFastTimer::FTM_PROJECTORS); + LLFastTimer ftm(FTM_PROJECTORS); LLDrawable* drawablep = *iter; LLVOVolume* volume = drawablep->getVOVolume(); @@ -7288,7 +7361,7 @@ void LLPipeline::renderDeferredLighting() while (!fullscreen_lights.empty()) { - LLFastTimer ftm(LLFastTimer::FTM_FULLSCREEN_LIGHTS); + LLFastTimer ftm(FTM_FULLSCREEN_LIGHTS); light[count] = fullscreen_lights.front(); fullscreen_lights.pop_front(); col[count] = light_colors.front(); @@ -7319,7 +7392,7 @@ void LLPipeline::renderDeferredLighting() for (LLDrawable::drawable_list_t::iterator iter = fullscreen_spot_lights.begin(); iter != fullscreen_spot_lights.end(); ++iter) { - LLFastTimer ftm(LLFastTimer::FTM_PROJECTORS); + LLFastTimer ftm(FTM_PROJECTORS); LLDrawable* drawablep = *iter; LLVOVolume* volume = drawablep->getVOVolume(); @@ -7908,9 +7981,13 @@ glh::matrix4f scale_translate_to_fit(const LLVector3 min, const LLVector3 max) return ret; } +static LLFastTimer::DeclareTimer FTM_SHADOW_RENDER("Render Shadows"); +static LLFastTimer::DeclareTimer FTM_SHADOW_ALPHA("Alpha Shadow"); +static LLFastTimer::DeclareTimer FTM_SHADOW_SIMPLE("Simple Shadow"); + void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera& shadow_cam, LLCullResult &result, BOOL use_shader, BOOL use_occlusion) { - LLFastTimer t(LLFastTimer::FTM_SHADOW_RENDER); + LLFastTimer t(FTM_SHADOW_RENDER); //clip out geometry on the same side of water as the camera S32 occlude = LLPipeline::sUseOcclusion; @@ -7971,7 +8048,7 @@ void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera gGL.diffuseColor4f(1,1,1,1); gGL.setColorMask(false, false); - LLFastTimer ftm(LLFastTimer::FTM_SHADOW_SIMPLE); + LLFastTimer ftm(FTM_SHADOW_SIMPLE); gGL.getTexUnit(0)->disable(); for (U32 i = 0; i < sizeof(types)/sizeof(U32); ++i) { @@ -7996,7 +8073,7 @@ void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera } { - LLFastTimer ftm(LLFastTimer::FTM_SHADOW_ALPHA); + LLFastTimer ftm(FTM_SHADOW_ALPHA); gDeferredShadowAlphaMaskProgram.bind(); gDeferredShadowAlphaMaskProgram.setMinimumAlpha(0.598f); @@ -8037,9 +8114,10 @@ void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera LLPipeline::sShadowRender = FALSE; } +static LLFastTimer::DeclareTimer FTM_VISIBLE_CLOUD("Visible Cloud"); BOOL LLPipeline::getVisiblePointCloud(LLCamera& camera, LLVector3& min, LLVector3& max, std::vector& fp, LLVector3 light_dir) { - LLFastTimer t(LLFastTimer::FTM_VISIBLE_CLOUD); + LLFastTimer t(FTM_VISIBLE_CLOUD); //get point cloud of intersection of frust and min, max if (getVisibleExtents(camera, min, max)) diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h index e51969bc3..5d76cebb8 100644 --- a/indra/newview/pipeline.h +++ b/indra/newview/pipeline.h @@ -80,6 +80,27 @@ glh::matrix4f gl_ortho(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, glh::matrix4f gl_perspective(GLfloat fovy, GLfloat aspect, GLfloat zNear, GLfloat zFar); glh::matrix4f gl_lookat(LLVector3 eye, LLVector3 center, LLVector3 up); +extern LLFastTimer::DeclareTimer FTM_RENDER_GEOMETRY; +extern LLFastTimer::DeclareTimer FTM_RENDER_GRASS; +extern LLFastTimer::DeclareTimer FTM_RENDER_INVISIBLE; +extern LLFastTimer::DeclareTimer FTM_RENDER_OCCLUSION; +extern LLFastTimer::DeclareTimer FTM_RENDER_SHINY; +extern LLFastTimer::DeclareTimer FTM_RENDER_SIMPLE; +extern LLFastTimer::DeclareTimer FTM_RENDER_TERRAIN; +extern LLFastTimer::DeclareTimer FTM_RENDER_TREES; +extern LLFastTimer::DeclareTimer FTM_RENDER_UI; +extern LLFastTimer::DeclareTimer FTM_RENDER_WATER; +extern LLFastTimer::DeclareTimer FTM_RENDER_WL_SKY; +extern LLFastTimer::DeclareTimer FTM_RENDER_ALPHA; +extern LLFastTimer::DeclareTimer FTM_RENDER_CHARACTERS; +extern LLFastTimer::DeclareTimer FTM_RENDER_BUMP; +extern LLFastTimer::DeclareTimer FTM_RENDER_FULLBRIGHT; +extern LLFastTimer::DeclareTimer FTM_RENDER_GLOW; +extern LLFastTimer::DeclareTimer FTM_STATESORT; +extern LLFastTimer::DeclareTimer FTM_PIPELINE; +extern LLFastTimer::DeclareTimer FTM_CLIENT_COPY; + + class LLPipeline { public: diff --git a/indra/newview/rlvhandler.cpp b/indra/newview/rlvhandler.cpp index 475e0c821..0d4d623a6 100644 --- a/indra/newview/rlvhandler.cpp +++ b/indra/newview/rlvhandler.cpp @@ -2005,7 +2005,7 @@ ERlvCmdRet RlvHandler::onGetOutfit(const RlvCommand& rlvCmd, std::string& strRep { // We never hide body parts, even if they're "locked" and we're hiding locked layers // (nor do we hide a layer if the issuing object is the only one that has this layer locked) - bool fWorn = (gAgentWearables.getWearable(wtRlvTypes[idxType])) && + bool fWorn = (gAgentWearables.getWearable(wtRlvTypes[idxType], 0)) && // TODO: MULTI-WEARABLE ( (!RlvSettings::getHideLockedLayers()) || (LLAssetType::AT_BODYPART == LLWearableType::getAssetType(wtRlvTypes[idxType])) || (RlvForceWear::isForceRemovable(wtRlvTypes[idxType], true, rlvCmd.getObjectID())) ); @@ -2033,7 +2033,7 @@ ERlvCmdRet RlvHandler::onGetOutfitNames(const RlvCommand& rlvCmd, std::string& s switch (rlvCmd.getBehaviourType()) { case RLV_BHVR_GETOUTFITNAMES: // Every layer that's worn - fAdd = (gAgentWearables.getWearable(wtType) != NULL); + fAdd = (gAgentWearables.getWearable(wtType, 0) != NULL); // TODO: MULTI-WEARABLE break; /* case RLV_BHVR_GETADDOUTFITNAMES: // Every layer that can be worn on (but ignore any locks set by the issuer) diff --git a/indra/newview/rlvhelper.cpp b/indra/newview/rlvhelper.cpp index 6f5a00e11..671b640b1 100644 --- a/indra/newview/rlvhelper.cpp +++ b/indra/newview/rlvhelper.cpp @@ -213,7 +213,7 @@ RlvCommandOptionGetPath::RlvCommandOptionGetPath(const RlvCommand& rlvCmd) if (rlvCmdOption.isWearableType()) //