From b36dc363061ec5bf6b092c14193198e9a5eef816 Mon Sep 17 00:00:00 2001 From: Josh Bell Date: Fri, 9 Mar 2007 01:09:20 +0000 Subject: svn merge -r 58902:58986 svn+ssh://svn.lindenlab.com/svn/linden/branches/maintenance --> release --- indra/llcommon/llavatarconstants.h | 12 +- indra/llcommon/llbase64.cpp | 86 +- indra/llcommon/llbase64.h | 38 +- indra/llcommon/llfasttimer.h | 1 + indra/llcommon/llliveappconfig.cpp | 92 +- indra/llcommon/llliveappconfig.h | 66 +- indra/llcommon/lluri.cpp | 3 +- indra/llcommon/metaproperty.cpp | 2 +- indra/llimage/llimageworker.cpp | 330 ++-- indra/llimage/llimageworker.h | 114 +- indra/llmath/lloctree.h | 4 + indra/llrender/llimagegl.cpp | 2 + indra/llrender/llvertexbuffer.cpp | 32 +- indra/llrender/llvertexbuffer.h | 6 +- indra/llui/llctrlselectioninterface.cpp | 88 +- indra/llui/llctrlselectioninterface.h | 168 +- indra/llui/llscrolllistctrl.cpp | 9 +- indra/llui/llviewquery.cpp | 252 +-- indra/llui/llviewquery.h | 178 +- indra/newview/lldrawable.cpp | 4 +- indra/newview/llface.cpp | 10 +- indra/newview/llfasttimerview.cpp | 2 +- indra/newview/llflexibleobject.cpp | 17 +- indra/newview/llfloaterinspect.cpp | 441 ++--- indra/newview/llfloaterinspect.h | 100 +- indra/newview/llfloaterland.cpp | 4 +- indra/newview/llfloaterpostcard.cpp | 2 +- indra/newview/llfloaterproperties.cpp | 4 +- indra/newview/llfloatertools.cpp | 2 +- indra/newview/llgroupmgr.cpp | 4 +- indra/newview/llinventorybridge.cpp | 8 +- indra/newview/llmaniptranslate.cpp | 2 + indra/newview/llpanelavatar.cpp | 22 +- indra/newview/llpanelclassified.cpp | 9 +- indra/newview/llpanelgroup.cpp | 2 +- indra/newview/llpanelgrouproles.cpp | 7 +- indra/newview/llpreview.cpp | 2 +- indra/newview/llselectmgr.cpp | 2 +- indra/newview/llspatialpartition.cpp | 118 +- indra/newview/llspatialpartition.h | 3 + indra/newview/lltexturecache.cpp | 2730 +++++++++++++++---------------- indra/newview/lltexturecache.h | 298 ++-- indra/newview/lltexturefetch.cpp | 6 +- indra/newview/lltexturefetch.h | 2 +- indra/newview/llviewerdisplay.cpp | 10 +- indra/newview/llviewermenu.cpp | 3 + indra/newview/llviewermessage.cpp | 2 +- indra/newview/llviewernetwork.cpp | 2 +- indra/newview/llviewerparcelmgr.cpp | 10 +- indra/newview/llviewerwindow.cpp | 7 - indra/newview/llvoavatar.cpp | 10 +- indra/newview/llvovolume.cpp | 64 +- indra/newview/llvovolume.h | 2 +- indra/newview/pipeline.cpp | 11 +- indra/newview/pipeline.h | 3 +- 55 files changed, 2754 insertions(+), 2654 deletions(-) (limited to 'indra') diff --git a/indra/llcommon/llavatarconstants.h b/indra/llcommon/llavatarconstants.h index 67bd329732..d66627c4b0 100644 --- a/indra/llcommon/llavatarconstants.h +++ b/indra/llcommon/llavatarconstants.h @@ -20,16 +20,16 @@ const char* const BLACKLIST_PROFILE_WEB_URL = "http://secondlife.com/app/webdisa // Maximum number of avatar picks const S32 MAX_AVATAR_PICKS = 10; -// For Flags in AvatarPropertiesReply -const U32 AVATAR_ALLOW_PUBLISH = 0x1 << 0; // whether profile is externally visible or not -const U32 AVATAR_MATURE_PUBLISH = 0x1 << 1; // profile is "mature" -const U32 AVATAR_IDENTIFIED = 0x1 << 2; // whether avatar has provided payment info +// For Flags in AvatarPropertiesReply +const U32 AVATAR_ALLOW_PUBLISH = 0x1 << 0; // whether profile is externally visible or not +const U32 AVATAR_MATURE_PUBLISH = 0x1 << 1; // profile is "mature" +const U32 AVATAR_IDENTIFIED = 0x1 << 2; // whether avatar has provided payment info const U32 AVATAR_TRANSACTED = 0x1 << 3; // whether avatar has actively used payment info const U32 AVATAR_ONLINE = 0x1 << 4; // the online status of this avatar, if known. -static const std::string VISIBILITY_DEFAULT("default"); +static const std::string VISIBILITY_DEFAULT("default"); static const std::string VISIBILITY_HIDDEN("hidden"); -static const std::string VISIBILITY_VISIBLE("visible"); +static const std::string VISIBILITY_VISIBLE("visible"); static const std::string VISIBILITY_INVISIBLE("invisible"); #endif diff --git a/indra/llcommon/llbase64.cpp b/indra/llcommon/llbase64.cpp index 88e9d960a2..6c4bc59e68 100644 --- a/indra/llcommon/llbase64.cpp +++ b/indra/llcommon/llbase64.cpp @@ -1,43 +1,43 @@ -/** - * @file llbase64.cpp - * @brief Wrapper for apr base64 encoding that returns a std::string - * @author James Cook - * - * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc. - * $License$ - */ - -#include "linden_common.h" - -#include "llbase64.h" - -#include - -#include "apr-1/apr_base64.h" - - -// static -std::string LLBase64::encode(const U8* input, size_t input_size) -{ - std::string output; - if (input - && input_size > 0) - { - // Yes, it returns int. - int b64_buffer_length = apr_base64_encode_len(input_size); - char* b64_buffer = new char[b64_buffer_length]; - - // This is faster than apr_base64_encode() if you know - // you're not on an EBCDIC machine. Also, the output is - // null terminated, even though the documentation doesn't - // specify. See apr_base64.c for details. JC - b64_buffer_length = apr_base64_encode_binary( - b64_buffer, - input, - input_size); - output.assign(b64_buffer); - delete[] b64_buffer; - } - return output; -} - +/** + * @file llbase64.cpp + * @brief Wrapper for apr base64 encoding that returns a std::string + * @author James Cook + * + * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc. + * $License$ + */ + +#include "linden_common.h" + +#include "llbase64.h" + +#include + +#include "apr-1/apr_base64.h" + + +// static +std::string LLBase64::encode(const U8* input, size_t input_size) +{ + std::string output; + if (input + && input_size > 0) + { + // Yes, it returns int. + int b64_buffer_length = apr_base64_encode_len(input_size); + char* b64_buffer = new char[b64_buffer_length]; + + // This is faster than apr_base64_encode() if you know + // you're not on an EBCDIC machine. Also, the output is + // null terminated, even though the documentation doesn't + // specify. See apr_base64.c for details. JC + b64_buffer_length = apr_base64_encode_binary( + b64_buffer, + input, + input_size); + output.assign(b64_buffer); + delete[] b64_buffer; + } + return output; +} + diff --git a/indra/llcommon/llbase64.h b/indra/llcommon/llbase64.h index 6e8b817ba7..4f59ceded6 100644 --- a/indra/llcommon/llbase64.h +++ b/indra/llcommon/llbase64.h @@ -1,19 +1,19 @@ -/** - * @file llbase64.h - * @brief Wrapper for apr base64 encoding that returns a std::string - * @author James Cook - * - * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc. - * $License$ - */ - -#ifndef LLBASE64_H -#define LLBASE64_h - -class LLBase64 -{ -public: - static std::string encode(const U8* input, size_t input_size); -}; - -#endif +/** + * @file llbase64.h + * @brief Wrapper for apr base64 encoding that returns a std::string + * @author James Cook + * + * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc. + * $License$ + */ + +#ifndef LLBASE64_H +#define LLBASE64_h + +class LLBase64 +{ +public: + static std::string encode(const U8* input, size_t input_size); +}; + +#endif diff --git a/indra/llcommon/llfasttimer.h b/indra/llcommon/llfasttimer.h index 16af098ed5..3e88784d3c 100644 --- a/indra/llcommon/llfasttimer.h +++ b/indra/llcommon/llfasttimer.h @@ -25,6 +25,7 @@ public: FTM_UPDATE, FTM_RENDER, FTM_SWAP, + FTM_CLIENT_COPY, FTM_IDLE, FTM_SLEEP, diff --git a/indra/llcommon/llliveappconfig.cpp b/indra/llcommon/llliveappconfig.cpp index 8bcaeb898f..b446c1f18e 100644 --- a/indra/llcommon/llliveappconfig.cpp +++ b/indra/llcommon/llliveappconfig.cpp @@ -1,46 +1,46 @@ -/** - * @file llliveappconfig.cpp - * @brief Configuration information for an LLApp that overrides indra.xml - * - * Copyright (c) 2003-$CurrentYear$, Linden Research, Inc. - * $License$ - */ - -#include "linden_common.h" - -#include "llliveappconfig.h" - -#include "llapp.h" -#include "llsd.h" -#include "llsdserialize.h" - -LLLiveAppConfig::LLLiveAppConfig(LLApp* app, const std::string& filename, F32 refresh_period) -: LLLiveFile(filename, refresh_period), - mApp(app) -{ } - - -LLLiveAppConfig::~LLLiveAppConfig() -{ } - -// virtual -void LLLiveAppConfig::loadFile() -{ - llinfos << "LLLiveAppConfig::loadFile(): reading from " - << filename() << llendl; - llifstream file(filename().c_str()); - LLSD config; - if (file.is_open()) - { - LLSDSerialize::fromXML(config, file); - if(!config.isMap()) - { - llinfos << "LLDataserverConfig::loadFile(): not an map!" - << " Ignoring the data." << llendl; - return; - } - file.close(); - } - mApp->setOptionData( - LLApp::PRIORITY_SPECIFIC_CONFIGURATION, config); -} +/** + * @file llliveappconfig.cpp + * @brief Configuration information for an LLApp that overrides indra.xml + * + * Copyright (c) 2003-$CurrentYear$, Linden Research, Inc. + * $License$ + */ + +#include "linden_common.h" + +#include "llliveappconfig.h" + +#include "llapp.h" +#include "llsd.h" +#include "llsdserialize.h" + +LLLiveAppConfig::LLLiveAppConfig(LLApp* app, const std::string& filename, F32 refresh_period) +: LLLiveFile(filename, refresh_period), + mApp(app) +{ } + + +LLLiveAppConfig::~LLLiveAppConfig() +{ } + +// virtual +void LLLiveAppConfig::loadFile() +{ + llinfos << "LLLiveAppConfig::loadFile(): reading from " + << filename() << llendl; + llifstream file(filename().c_str()); + LLSD config; + if (file.is_open()) + { + LLSDSerialize::fromXML(config, file); + if(!config.isMap()) + { + llinfos << "LLDataserverConfig::loadFile(): not an map!" + << " Ignoring the data." << llendl; + return; + } + file.close(); + } + mApp->setOptionData( + LLApp::PRIORITY_SPECIFIC_CONFIGURATION, config); +} diff --git a/indra/llcommon/llliveappconfig.h b/indra/llcommon/llliveappconfig.h index ceceda5b18..8875f3adc3 100644 --- a/indra/llcommon/llliveappconfig.h +++ b/indra/llcommon/llliveappconfig.h @@ -1,33 +1,33 @@ -/** - * @file llliveappconfig.h - * @brief Configuration information for an LLApp that overrides indra.xml - * - * Copyright (c) 2003-$CurrentYear$, Linden Research, Inc. - * $License$ - */ - -#ifndef LLLIVEAPPCONFIG_H -#define LLLIVEAPPCONFIG_H - -#include "lllivefile.h" - -class LLApp; - -class LLLiveAppConfig : public LLLiveFile -{ -public: - // To use this, instantiate a LLLiveAppConfig object inside your main loop. - // The traditional name for it is live_config. - // Be sure to call live_config.checkAndReload() periodically. - - LLLiveAppConfig(LLApp* app, const std::string& filename, F32 refresh_period); - ~LLLiveAppConfig(); - -protected: - /*virtual*/ void loadFile(); - -private: - LLApp* mApp; -}; - -#endif +/** + * @file llliveappconfig.h + * @brief Configuration information for an LLApp that overrides indra.xml + * + * Copyright (c) 2003-$CurrentYear$, Linden Research, Inc. + * $License$ + */ + +#ifndef LLLIVEAPPCONFIG_H +#define LLLIVEAPPCONFIG_H + +#include "lllivefile.h" + +class LLApp; + +class LLLiveAppConfig : public LLLiveFile +{ +public: + // To use this, instantiate a LLLiveAppConfig object inside your main loop. + // The traditional name for it is live_config. + // Be sure to call live_config.checkAndReload() periodically. + + LLLiveAppConfig(LLApp* app, const std::string& filename, F32 refresh_period); + ~LLLiveAppConfig(); + +protected: + /*virtual*/ void loadFile(); + +private: + LLApp* mApp; +}; + +#endif diff --git a/indra/llcommon/lluri.cpp b/indra/llcommon/lluri.cpp index cf06fe3f40..1f64c3bde3 100644 --- a/indra/llcommon/lluri.cpp +++ b/indra/llcommon/lluri.cpp @@ -359,8 +359,7 @@ LLURI LLURI::buildHTTP(const std::string& host_port, LLURI result; // TODO: deal with '/' '?' '#' in host_port - S32 index = host_port.find("://"); - if (index != host_port.npos) + if (host_port.find("://") != host_port.npos) { // The scheme is part of the host_port result.mScheme = ""; diff --git a/indra/llcommon/metaproperty.cpp b/indra/llcommon/metaproperty.cpp index befee61a8a..adcda03389 100644 --- a/indra/llcommon/metaproperty.cpp +++ b/indra/llcommon/metaproperty.cpp @@ -25,7 +25,7 @@ const LLMetaClass& LLMetaProperty::getObjectMetaClass() const { return mObjectClass; } - + void LLMetaProperty::checkObjectClass(const LLReflective* object) const { if(! mObjectClass.isInstance(object)) diff --git a/indra/llimage/llimageworker.cpp b/indra/llimage/llimageworker.cpp index b44bf19227..297482a222 100644 --- a/indra/llimage/llimageworker.cpp +++ b/indra/llimage/llimageworker.cpp @@ -1,165 +1,165 @@ -/** - * @file llimage.cpp - * @brief Base class for images. - * - * Copyright (c) 2001-$CurrentYear$, Linden Research, Inc. - * $License$ - */ - -#include "linden_common.h" - -#include "llimageworker.h" -#include "llimagedxt.h" - -//---------------------------------------------------------------------------- - -//static -LLWorkerThread* LLImageWorker::sWorkerThread = NULL; -S32 LLImageWorker::sCount = 0; - -//static -void LLImageWorker::initClass(LLWorkerThread* workerthread) -{ - sWorkerThread = workerthread; -} - -//static -void LLImageWorker::cleanupClass() -{ -} - -//---------------------------------------------------------------------------- - -LLImageWorker::LLImageWorker(LLImageFormatted* image, U32 priority, S32 discard, LLResponder* responder) - : LLWorkerClass(sWorkerThread, "Image"), - mFormattedImage(image), - mDecodedType(-1), - mDiscardLevel(discard), - mPriority(priority), - mResponder(responder) -{ - ++sCount; -} - -LLImageWorker::~LLImageWorker() -{ - mDecodedImage = NULL; - mFormattedImage = NULL; - --sCount; -} - -//---------------------------------------------------------------------------- - -//virtual, main thread -void LLImageWorker::startWork(S32 param) -{ - llassert_always(mDecodedImage.isNull()); - mDecodedType = -1; -} - -bool LLImageWorker::doWork(S32 param) -{ - bool decoded = false; - if(mDecodedImage.isNull()) - { - if (!mFormattedImage->updateData()) - { - mDecodedType = -2; // failed - return true; - } - if (mDiscardLevel >= 0) - { - mFormattedImage->setDiscardLevel(mDiscardLevel); - } - if (!(mFormattedImage->getWidth() * mFormattedImage->getHeight() * mFormattedImage->getComponents())) - { - decoded = true; // failed - } - else - { - S32 nc = param ? 1 : mFormattedImage->getComponents(); - mDecodedImage = new LLImageRaw(mFormattedImage->getWidth(), - mFormattedImage->getHeight(), - nc); - } - } - if (!decoded) - { - if (param == 0) - { - // Decode primary channels - decoded = mFormattedImage->decode(mDecodedImage, .1f); // 1ms - } - else - { - // Decode aux channel - decoded = mFormattedImage->decode(mDecodedImage, .1f, param, param); // 1ms - } - } - if (decoded) - { - // Call the callback immediately; endWork doesn't get called until ckeckWork - if (mResponder.notNull()) - { - bool success = (!wasAborted() && mDecodedImage.notNull() && mDecodedImage->getDataSize() != 0); - mResponder->completed(success); - } - } - return decoded; -} - -void LLImageWorker::endWork(S32 param, bool aborted) -{ - if (mDecodedType != -2) - { - mDecodedType = aborted ? -2 : param; - } -} - -//---------------------------------------------------------------------------- - - -BOOL LLImageWorker::requestDecodedAuxData(LLPointer& raw, S32 channel, S32 discard) -{ - // For most codecs, only mDiscardLevel data is available. - // (see LLImageDXT for exception) - if (discard >= 0 && discard != mFormattedImage->getDiscardLevel()) - { - llerrs << "Request for invalid discard level" << llendl; - } - checkWork(); - if (mDecodedType == -2) - { - return TRUE; // aborted, done - } - if (mDecodedType != channel) - { - if (!haveWork()) - { - addWork(channel, mPriority); - } - return FALSE; - } - else - { - llassert_always(!haveWork()); - llassert_always(mDecodedType == channel); - raw = mDecodedImage; // smart pointer acquires ownership of data - mDecodedImage = NULL; - return TRUE; - } -} - -BOOL LLImageWorker::requestDecodedData(LLPointer& raw, S32 discard) -{ - if (mFormattedImage->getCodec() == IMG_CODEC_DXT) - { - // special case - LLImageDXT* imagedxt = (LLImageDXT*)((LLImageFormatted*)mFormattedImage); - return imagedxt->getMipData(raw, discard); - } - else - { - return requestDecodedAuxData(raw, 0, discard); - } -} +/** + * @file llimage.cpp + * @brief Base class for images. + * + * Copyright (c) 2001-$CurrentYear$, Linden Research, Inc. + * $License$ + */ + +#include "linden_common.h" + +#include "llimageworker.h" +#include "llimagedxt.h" + +//---------------------------------------------------------------------------- + +//static +LLWorkerThread* LLImageWorker::sWorkerThread = NULL; +S32 LLImageWorker::sCount = 0; + +//static +void LLImageWorker::initClass(LLWorkerThread* workerthread) +{ + sWorkerThread = workerthread; +} + +//static +void LLImageWorker::cleanupClass() +{ +} + +//---------------------------------------------------------------------------- + +LLImageWorker::LLImageWorker(LLImageFormatted* image, U32 priority, S32 discard, LLResponder* responder) + : LLWorkerClass(sWorkerThread, "Image"), + mFormattedImage(image), + mDecodedType(-1), + mDiscardLevel(discard), + mPriority(priority), + mResponder(responder) +{ + ++sCount; +} + +LLImageWorker::~LLImageWorker() +{ + mDecodedImage = NULL; + mFormattedImage = NULL; + --sCount; +} + +//---------------------------------------------------------------------------- + +//virtual, main thread +void LLImageWorker::startWork(S32 param) +{ + llassert_always(mDecodedImage.isNull()); + mDecodedType = -1; +} + +bool LLImageWorker::doWork(S32 param) +{ + bool decoded = false; + if(mDecodedImage.isNull()) + { + if (!mFormattedImage->updateData()) + { + mDecodedType = -2; // failed + return true; + } + if (mDiscardLevel >= 0) + { + mFormattedImage->setDiscardLevel(mDiscardLevel); + } + if (!(mFormattedImage->getWidth() * mFormattedImage->getHeight() * mFormattedImage->getComponents())) + { + decoded = true; // failed + } + else + { + S32 nc = param ? 1 : mFormattedImage->getComponents(); + mDecodedImage = new LLImageRaw(mFormattedImage->getWidth(), + mFormattedImage->getHeight(), + nc); + } + } + if (!decoded) + { + if (param == 0) + { + // Decode primary channels + decoded = mFormattedImage->decode(mDecodedImage, .1f); // 1ms + } + else + { + // Decode aux channel + decoded = mFormattedImage->decode(mDecodedImage, .1f, param, param); // 1ms + } + } + if (decoded) + { + // Call the callback immediately; endWork doesn't get called until ckeckWork + if (mResponder.notNull()) + { + bool success = (!wasAborted() && mDecodedImage.notNull() && mDecodedImage->getDataSize() != 0); + mResponder->completed(success); + } + } + return decoded; +} + +void LLImageWorker::endWork(S32 param, bool aborted) +{ + if (mDecodedType != -2) + { + mDecodedType = aborted ? -2 : param; + } +} + +//---------------------------------------------------------------------------- + + +BOOL LLImageWorker::requestDecodedAuxData(LLPointer& raw, S32 channel, S32 discard) +{ + // For most codecs, only mDiscardLevel data is available. + // (see LLImageDXT for exception) + if (discard >= 0 && discard != mFormattedImage->getDiscardLevel()) + { + llerrs << "Request for invalid discard level" << llendl; + } + checkWork(); + if (mDecodedType == -2) + { + return TRUE; // aborted, done + } + if (mDecodedType != channel) + { + if (!haveWork()) + { + addWork(channel, mPriority); + } + return FALSE; + } + else + { + llassert_always(!haveWork()); + llassert_always(mDecodedType == channel); + raw = mDecodedImage; // smart pointer acquires ownership of data + mDecodedImage = NULL; + return TRUE; + } +} + +BOOL LLImageWorker::requestDecodedData(LLPointer& raw, S32 discard) +{ + if (mFormattedImage->getCodec() == IMG_CODEC_DXT) + { + // special case + LLImageDXT* imagedxt = (LLImageDXT*)((LLImageFormatted*)mFormattedImage); + return imagedxt->getMipData(raw, discard); + } + else + { + return requestDecodedAuxData(raw, 0, discard); + } +} diff --git a/indra/llimage/llimageworker.h b/indra/llimage/llimageworker.h index cdd30417ce..6e9ecacc89 100644 --- a/indra/llimage/llimageworker.h +++ b/indra/llimage/llimageworker.h @@ -1,57 +1,57 @@ -/** - * @file llimageworker.h - * @brief Object for managing images and their textures. - * - * Copyright (c) 2000-$CurrentYear$, Linden Research, Inc. - * $License$ - */ - -#ifndef LL_LLIMAGEWORKER_H -#define LL_LLIMAGEWORKER_H - -#include "llimage.h" -#include "llworkerthread.h" - -class LLImageWorker : public LLWorkerClass -{ -public: - static void initClass(LLWorkerThread* workerthread); - static void cleanupClass(); - static LLWorkerThread* getWorkerThread() { return sWorkerThread; } - - // LLWorkerThread -public: - LLImageWorker(LLImageFormatted* image, U32 priority, S32 discard, LLResponder* responder = NULL); - ~LLImageWorker(); - - // called from WORKER THREAD, returns TRUE if done - /*virtual*/ bool doWork(S32 param); - - BOOL requestDecodedData(LLPointer& raw, S32 discard = -1); - BOOL requestDecodedAuxData(LLPointer& raw, S32 channel, S32 discard = -1); - void releaseDecodedData(); - void cancelDecode(); - -private: - // called from MAIN THREAD - /*virtual*/ void startWork(S32 param); // called from addWork() - /*virtual*/ void endWork(S32 param, bool aborted); // called from doWork() - -protected: - LLPointer mFormattedImage; - LLPointer mDecodedImage; - S32 mDecodedType; - S32 mDiscardLevel; - -private: - U32 mPriority; - LLPointer mResponder; - -protected: - static LLWorkerThread* sWorkerThread; - -public: - static S32 sCount; -}; - -#endif +/** + * @file llimageworker.h + * @brief Object for managing images and their textures. + * + * Copyright (c) 2000-$CurrentYear$, Linden Research, Inc. + * $License$ + */ + +#ifndef LL_LLIMAGEWORKER_H +#define LL_LLIMAGEWORKER_H + +#include "llimage.h" +#include "llworkerthread.h" + +class LLImageWorker : public LLWorkerClass +{ +public: + static void initClass(LLWorkerThread* workerthread); + static void cleanupClass(); + static LLWorkerThread* getWorkerThread() { return sWorkerThread; } + + // LLWorkerThread +public: + LLImageWorker(LLImageFormatted* image, U32 priority, S32 discard, LLResponder* responder = NULL); + ~LLImageWorker(); + + // called from WORKER THREAD, returns TRUE if done + /*virtual*/ bool doWork(S32 param); + + BOOL requestDecodedData(LLPointer& raw, S32 discard = -1); + BOOL requestDecodedAuxData(LLPointer& raw, S32 channel, S32 discard = -1); + void releaseDecodedData(); + void cancelDecode(); + +private: + // called from MAIN THREAD + /*virtual*/ void startWork(S32 param); // called from addWork() + /*virtual*/ void endWork(S32 param, bool aborted); // called from doWork() + +protected: + LLPointer mFormattedImage; + LLPointer mDecodedImage; + S32 mDecodedType; + S32 mDiscardLevel; + +private: + U32 mPriority; + LLPointer mResponder; + +protected: + static LLWorkerThread* sWorkerThread; + +public: + static S32 sCount; +}; + +#endif diff --git a/indra/llmath/lloctree.h b/indra/llmath/lloctree.h index e5b2a5f312..f7ad363206 100644 --- a/indra/llmath/lloctree.h +++ b/indra/llmath/lloctree.h @@ -21,7 +21,11 @@ #endif #define LL_OCTREE_PARANOIA_CHECK 0 +#if LL_DARWIN +#define LL_OCTREE_MAX_CAPACITY 32 +#else #define LL_OCTREE_MAX_CAPACITY 256 +#endif template class LLOctreeState; template class LLOctreeNode; diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index 9c1178b9f7..1196db18fa 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -713,6 +713,8 @@ BOOL LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S3 if (!res) llerrs << "LLImageGL::setSubImage(): bindTexture failed" << llendl; stop_glerror(); + LLGLEnable tex( GL_TEXTURE_2D ); + glTexSubImage2D(mTarget, 0, x_pos, y_pos, width, height, mFormatPrimary, mFormatType, datap); stop_glerror(); diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp index d6477d69ec..b94f593d7f 100644 --- a/indra/llrender/llvertexbuffer.cpp +++ b/indra/llrender/llvertexbuffer.cpp @@ -12,8 +12,8 @@ S32 LLVertexBuffer::sCount = 0; S32 LLVertexBuffer::sGLCount = 0; BOOL LLVertexBuffer::sEnableVBOs = TRUE; -S32 LLVertexBuffer::sGLRenderBuffer = 0; -S32 LLVertexBuffer::sGLRenderIndices = 0; +U32 LLVertexBuffer::sGLRenderBuffer = 0; +U32 LLVertexBuffer::sGLRenderIndices = 0; U32 LLVertexBuffer::sLastMask = 0; BOOL LLVertexBuffer::sVBOActive = FALSE; BOOL LLVertexBuffer::sIBOActive = FALSE; @@ -92,7 +92,7 @@ void LLVertexBuffer::stopRender() sRenderActive = FALSE; } -void LLVertexBuffer::clientCopy() +void LLVertexBuffer::clientCopy(F64 max_time) { if (!sDeleteList.empty()) { @@ -122,7 +122,7 @@ void LLVertexBuffer::clientCopy() } else { - if (timer.getElapsedTimeF64() > 0.005) + if (timer.getElapsedTimeF64() > max_time) { break; } @@ -191,7 +191,10 @@ LLVertexBuffer::LLVertexBuffer(U32 typemask, S32 usage) : mNumVerts(0), mNumIndices(0), mUsage(usage), mGLBuffer(0), mGLIndices(0), mMappedData(NULL), mMappedIndexData(NULL), mLocked(FALSE), - mResized(FALSE), mEmpty(TRUE), mFinal(FALSE), mFilthy(FALSE) + mFinal(FALSE), + mFilthy(FALSE), + mEmpty(TRUE), + mResized(FALSE) { LLMemType mt(LLMemType::MTYPE_VERTEX_DATA); if (!sEnableVBOs) @@ -614,7 +617,6 @@ void LLVertexBuffer::unmapBuffer() { DirtyRegion& region = *i; glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, region.mIndex*mStride, region.mCount*mStride, mMappedData + region.mIndex*mStride); - glFlush(); } } } @@ -639,7 +641,6 @@ void LLVertexBuffer::unmapBuffer() DirtyRegion& region = *i; glBufferSubDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, region.mIndicesIndex*sizeof(U32), region.mIndicesCount*sizeof(U32), mMappedIndexData + region.mIndicesIndex*sizeof(U32)); - glFlush(); } } } @@ -786,13 +787,7 @@ void LLVertexBuffer::setBuffer(U32 data_mask) unmapBuffer(); } else - { - if (!mDirtyRegions.empty()) - { - mFilthy = TRUE; - mDirtyRegions.clear(); - } - + { if (mGLBuffer) { if (sEnableVBOs && sVBOActive) @@ -890,6 +885,15 @@ void LLVertexBuffer::markDirty(U32 vert_index, U32 vert_count, U32 indices_index if (!mDirtyRegions.empty()) { DirtyRegion& region = *(mDirtyRegions.rbegin()); + + if (region.mIndex+region.mCount > vert_index) + { + //this buffer has received multiple updates since the last copy, mark it filthy + mFilthy = TRUE; + mDirtyRegions.clear(); + return; + } + if (region.mIndex + region.mCount == vert_index && region.mIndicesIndex + region.mIndicesCount == indices_index) { diff --git a/indra/llrender/llvertexbuffer.h b/indra/llrender/llvertexbuffer.h index e672321e76..b221d35ee3 100644 --- a/indra/llrender/llvertexbuffer.h +++ b/indra/llrender/llvertexbuffer.h @@ -29,7 +29,7 @@ public: static void cleanupClass(); static void startRender(); //between start and stop render, no client copies will occur static void stopRender(); //any buffer not copied to GL will be rendered from client memory - static void clientCopy(); //copy data from client to GL + static void clientCopy(F64 max_time = 0.005); //copy data from client to GL static void unbind(); //unbind any bound vertex buffer enum { @@ -167,8 +167,8 @@ public: static BOOL sEnableVBOs; static S32 sTypeOffsets[TYPE_MAX]; - static S32 sGLRenderBuffer; - static S32 sGLRenderIndices; + static U32 sGLRenderBuffer; + static U32 sGLRenderIndices; static BOOL sVBOActive; static BOOL sIBOActive; static U32 sLastMask; diff --git a/indra/llui/llctrlselectioninterface.cpp b/indra/llui/llctrlselectioninterface.cpp index a58fb88e75..61044aa7da 100644 --- a/indra/llui/llctrlselectioninterface.cpp +++ b/indra/llui/llctrlselectioninterface.cpp @@ -1,44 +1,44 @@ -/** - * @file llctrlselectioninterface.cpp - * @brief Programmatic selection of items in a list. - * - * Copyright (c) 2006-$CurrentYear$, Linden Research, Inc. - * $License$ - */ - -#include "llctrlselectioninterface.h" - -#include "llsd.h" - -// virtual -LLCtrlSelectionInterface::~LLCtrlSelectionInterface() -{ } - -BOOL LLCtrlSelectionInterface::selectByValue(LLSD value) -{ - return setSelectedByValue(value, TRUE); -} - -BOOL LLCtrlSelectionInterface::deselectByValue(LLSD value) -{ - return setSelectedByValue(value, FALSE); -} - - -// virtual -LLCtrlListInterface::~LLCtrlListInterface() -{ } - -LLScrollListItem* LLCtrlListInterface::addSimpleElement(const LLString& value) -{ - return addSimpleElement(value, ADD_BOTTOM, LLSD()); -} - -LLScrollListItem* LLCtrlListInterface::addSimpleElement(const LLString& value, EAddPosition pos) -{ - return addSimpleElement(value, pos, LLSD()); -} - -// virtual -LLCtrlScrollInterface::~LLCtrlScrollInterface() -{ } +/** + * @file llctrlselectioninterface.cpp + * @brief Programmatic selection of items in a list. + * + * Copyright (c) 2006-$CurrentYear$, Linden Research, Inc. + * $License$ + */ + +#include "llctrlselectioninterface.h" + +#include "llsd.h" + +// virtual +LLCtrlSelectionInterface::~LLCtrlSelectionInterface() +{ } + +BOOL LLCtrlSelectionInterface::selectByValue(LLSD value) +{ + return setSelectedByValue(value, TRUE); +} + +BOOL LLCtrlSelectionInterface::deselectByValue(LLSD value) +{ + return setSelectedByValue(value, FALSE); +} + + +// virtual +LLCtrlListInterface::~LLCtrlListInterface() +{ } + +LLScrollListItem* LLCtrlListInterface::addSimpleElement(const LLString& value) +{ + return addSimpleElement(value, ADD_BOTTOM, LLSD()); +} + +LLScrollListItem* LLCtrlListInterface::addSimpleElement(const LLString& value, EAddPosition pos) +{ + return addSimpleElement(value, pos, LLSD()); +} + +// virtual +LLCtrlScrollInterface::~LLCtrlScrollInterface() +{ } diff --git a/indra/llui/llctrlselectioninterface.h b/indra/llui/llctrlselectioninterface.h index 4e2807e9a1..698d609593 100644 --- a/indra/llui/llctrlselectioninterface.h +++ b/indra/llui/llctrlselectioninterface.h @@ -1,84 +1,84 @@ -/** - * @file llctrlselectioninterface.h - * @brief Programmatic selection of items in a list. - * - * Copyright (c) 2006-$CurrentYear$, Linden Research, Inc. - * $License$ - */ - -#ifndef LLCTRLSELECTIONINTERFACE_H -#define LLCTRLSELECTIONINTERFACE_H - -#include "stdtypes.h" -#include "stdenums.h" -#include "llstring.h" - -class LLSD; -class LLUUID; -class LLScrollListItem; - -class LLCtrlSelectionInterface -{ -public: - virtual ~LLCtrlSelectionInterface(); - - enum EOperation - { - OP_DELETE = 1, - OP_SELECT, - OP_DESELECT, - }; - - virtual BOOL getCanSelect() const = 0; - - virtual BOOL selectFirstItem() = 0; - virtual BOOL selectNthItem( S32 index ) = 0; - - virtual S32 getFirstSelectedIndex() = 0; - - // TomY TODO: Simply cast the UUIDs to LLSDs, using the selectByValue function - virtual BOOL setCurrentByID( const LLUUID& id ) = 0; - virtual LLUUID getCurrentID() = 0; - - BOOL selectByValue(LLSD value); - BOOL deselectByValue(LLSD value); - virtual BOOL setSelectedByValue(LLSD value, BOOL selected) = 0; - virtual LLSD getSimpleSelectedValue() = 0; - - virtual BOOL isSelected(LLSD value) = 0; - - virtual BOOL operateOnSelection(EOperation op) = 0; - virtual BOOL operateOnAll(EOperation op) = 0; -}; - -class LLCtrlListInterface : public LLCtrlSelectionInterface -{ -public: - virtual ~LLCtrlListInterface(); - - virtual S32 getItemCount() const = 0; - virtual void addColumn(const LLSD& column, EAddPosition pos = ADD_BOTTOM) = 0; - virtual void clearColumns() = 0; - virtual void setColumnLabel(const LLString& column, const LLString& label) = 0; - // TomY TODO: Document this - virtual LLScrollListItem* addElement(const LLSD& value, EAddPosition pos = ADD_BOTTOM, void* userdata = NULL) = 0; - - LLScrollListItem* addSimpleElement(const LLString& value); // defaults to bottom - LLScrollListItem* addSimpleElement(const LLString& value, EAddPosition pos); // defaults to no LLSD() id - virtual LLScrollListItem* addSimpleElement(const LLString& value, EAddPosition pos, const LLSD& id) = 0; - - virtual void clearRows() = 0; - virtual void sortByColumn(LLString name, BOOL ascending) = 0; -}; - -class LLCtrlScrollInterface -{ -public: - virtual ~LLCtrlScrollInterface(); - - virtual S32 getScrollPos() = 0; - virtual void setScrollPos( S32 pos ) = 0; - virtual void scrollToShowSelected() = 0; -}; - -#endif +/** + * @file llctrlselectioninterface.h + * @brief Programmatic selection of items in a list. + * + * Copyright (c) 2006-$CurrentYear$, Linden Research, Inc. + * $License$ + */ + +#ifndef LLCTRLSELECTIONINTERFACE_H +#define LLCTRLSELECTIONINTERFACE_H + +#include "stdtypes.h" +#include "stdenums.h" +#include "llstring.h" + +class LLSD; +class LLUUID; +class LLScrollListItem; + +class LLCtrlSelectionInterface +{ +public: + virtual ~LLCtrlSelectionInterface(); + + enum EOperation + { + OP_DELETE = 1, + OP_SELECT, + OP_DESELECT, + }; + + virtual BOOL getCanSelect() const = 0; + + virtual BOOL selectFirstItem() = 0; + virtual BOOL selectNthItem( S32 index ) = 0; + + virtual S32 getFirstSelectedIndex() = 0; + + // TomY TODO: Simply cast the UUIDs to LLSDs, using the selectByValue function + virtual BOOL setCurrentByID( const LLUUID& id ) = 0; + virtual LLUUID getCurrentID() = 0; + + BOOL selectByValue(LLSD value); + BOOL deselectByValue(LLSD value); + virtual BOOL setSelectedByValue(LLSD value, BOOL selected) = 0; + virtual LLSD getSimpleSelectedValue() = 0; + + virtual BOOL isSelected(LLSD value) = 0; + + virtual BOOL operateOnSelection(EOperation op) = 0; + virtual BOOL operateOnAll(EOperation op) = 0; +}; + +class LLCtrlListInterface : public LLCtrlSelectionInterface +{ +public: + virtual ~LLCtrlListInterface(); + + virtual S32 getItemCount() const = 0; + virtual void addColumn(const LLSD& column, EAddPosition pos = ADD_BOTTOM) = 0; + virtual void clearColumns() = 0; + virtual void setColumnLabel(const LLString& column, const LLString& label) = 0; + // TomY TODO: Document this + virtual LLScrollListItem* addElement(const LLSD& value, EAddPosition pos = ADD_BOTTOM, void* userdata = NULL) = 0; + + LLScrollListItem* addSimpleElement(const LLString& value); // defaults to bottom + LLScrollListItem* addSimpleElement(const LLString& value, EAddPosition pos); // defaults to no LLSD() id + virtual LLScrollListItem* addSimpleElement(const LLString& value, EAddPosition pos, const LLSD& id) = 0; + + virtual void clearRows() = 0; + virtual void sortByColumn(LLString name, BOOL ascending) = 0; +}; + +class LLCtrlScrollInterface +{ +public: + virtual ~LLCtrlScrollInterface(); + + virtual S32 getScrollPos() = 0; + virtual void setScrollPos( S32 pos ) = 0; + virtual void scrollToShowSelected() = 0; +}; + +#endif diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp index f2ae318dca..35d5affa5d 100644 --- a/indra/llui/llscrolllistctrl.cpp +++ b/indra/llui/llscrolllistctrl.cpp @@ -377,20 +377,21 @@ LLScrollListCtrl::LLScrollListCtrl(const LLString& name, const LLRect& rect, mFgUnselectedColor( LLUI::sColorsGroup->getColor("ScrollUnselectedColor") ), mFgDisabledColor( LLUI::sColorsGroup->getColor("ScrollDisabledColor") ), mHighlightedColor( LLUI::sColorsGroup->getColor("ScrollHighlightedColor") ), - mHighlightedItem(-1), mBorderThickness( 2 ), mOnDoubleClickCallback( NULL ), mOnMaximumSelectCallback( NULL ), mOnSortChangedCallback( NULL ), - mDrewSelected(FALSE), + mHighlightedItem(-1), mBorder(NULL), - mSearchColumn(0), mDefaultColumn("SIMPLE"), + mSearchColumn(0), mNumDynamicWidthColumns(0), mTotalStaticColumnWidth(0), mSortColumn(0), - mSortAscending(TRUE) + mSortAscending(TRUE), + + mDrewSelected(FALSE) { mItemListRect.setOriginAndSize( mBorderThickness + LIST_BORDER_PAD, diff --git a/indra/llui/llviewquery.cpp b/indra/llui/llviewquery.cpp index 416ca623bc..650125d486 100644 --- a/indra/llui/llviewquery.cpp +++ b/indra/llui/llviewquery.cpp @@ -1,126 +1,126 @@ -/** - * @file llviewquery.cpp - * @brief Implementation of view query class. - * - * Copyright (c) 2001-$CurrentYear$, Linden Research, Inc. - * $License$ - */ - -#include "llview.h" -#include "lluictrl.h" -#include "llviewquery.h" - -void LLQuerySorter::operator() (LLView * parent, viewList_t &children) const {} - -filterResult_t LLNoLeavesFilter::operator() (const LLView* const view, const viewList_t & children) const -{ - return filterResult_t(!(view->getChildList()->size() == 0), TRUE); -} - -filterResult_t LLVisibleFilter::operator() (const LLView* const view, const viewList_t & children) const -{ - return filterResult_t(view->getVisible(), view->getVisible()); -} -filterResult_t LLEnabledFilter::operator() (const LLView* const view, const viewList_t & children) const -{ - return filterResult_t(view->getEnabled(), view->getEnabled()); -} -filterResult_t LLTabStopFilter::operator() (const LLView* const view, const viewList_t & children) const -{ - return filterResult_t(view->isCtrl() && static_cast(view)->hasTabStop(), - view->canFocusChildren()); -} - -// LLViewQuery - -LLViewQuery::LLViewQuery(): mPreFilters(), mPostFilters(), mSorterp() -{ -} - -void LLViewQuery::addPreFilter(const LLQueryFilter* prefilter) { mPreFilters.push_back(prefilter); } - -void LLViewQuery::addPostFilter(const LLQueryFilter* postfilter) { mPostFilters.push_back(postfilter); } - -const LLViewQuery::filterList_t & LLViewQuery::getPreFilters() const { return mPreFilters; } - -const LLViewQuery::filterList_t & LLViewQuery::getPostFilters() const { return mPostFilters; } - -void LLViewQuery::setSorter(const LLQuerySorter* sorterp) { mSorterp = sorterp; } -const LLQuerySorter* LLViewQuery::getSorter() const { return mSorterp; } - -viewList_t LLViewQuery::run(LLView * view) const -{ - viewList_t result; - - filterResult_t pre = runFilters(view, viewList_t(), mPreFilters); - if(!pre.first && !pre.second) - { - // skip post filters completely if we're not including ourselves or the children - return result; - } - if(pre.second) - { - // run filters on children - viewList_t filtered_children; - filterChildren(view, filtered_children); - filterResult_t post = runFilters(view, filtered_children, mPostFilters); - if(pre.first && post.first) - { - result.push_back(view); - } - if(post.second) - { - result.insert(result.end(), filtered_children.begin(), filtered_children.end()); - } - } - else - { - if(pre.first) - { - result.push_back(view); - } - } - return result; -} - -void LLViewQuery::filterChildren(LLView * view, viewList_t & filtered_children) const -{ - LLView::child_list_t views(*(view->getChildList())); - (*mSorterp)(view, views); // sort the children per the sorter - for(LLView::child_list_iter_t iter = views.begin(); - iter != views.end(); - iter++) - { - viewList_t indiv_children = this->run(*iter); - filtered_children.insert(filtered_children.end(), indiv_children.begin(), indiv_children.end()); - } -} - -filterResult_t LLViewQuery::runFilters(LLView * view, const viewList_t children, const filterList_t filters) const -{ - filterResult_t result = filterResult_t(TRUE, TRUE); - for(filterList_const_iter_t iter = filters.begin(); - iter != filters.end(); - iter++) - { - filterResult_t filtered = (**iter)(view, children); - result.first = result.first && filtered.first; - result.second = result.second && filtered.second; - } - return result; -} - -class SortByTabOrder : public LLQuerySorter, public LLSingleton -{ - /*virtual*/ void operator() (LLView * parent, LLView::child_list_t &children) const - { - children.sort(LLCompareByTabOrder(parent->getCtrlOrder())); - } -}; - -LLCtrlQuery::LLCtrlQuery() : - LLViewQuery() -{ - setSorter(SortByTabOrder::getInstance()); -} - +/** + * @file llviewquery.cpp + * @brief Implementation of view query class. + * + * Copyright (c) 2001-$CurrentYear$, Linden Research, Inc. + * $License$ + */ + +#include "llview.h" +#include "lluictrl.h" +#include "llviewquery.h" + +void LLQuerySorter::operator() (LLView * parent, viewList_t &children) const {} + +filterResult_t LLNoLeavesFilter::operator() (const LLView* const view, const viewList_t & children) const +{ + return filterResult_t(!(view->getChildList()->size() == 0), TRUE); +} + +filterResult_t LLVisibleFilter::operator() (const LLView* const view, const viewList_t & children) const +{ + return filterResult_t(view->getVisible(), view->getVisible()); +} +filterResult_t LLEnabledFilter::operator() (const LLView* const view, const viewList_t & children) const +{ + return filterResult_t(view->getEnabled(), view->getEnabled()); +} +filterResult_t LLTabStopFilter::operator() (const LLView* const view, const viewList_t & children) const +{ + return filterResult_t(view->isCtrl() && static_cast(view)->hasTabStop(), + view->canFocusChildren()); +} + +// LLViewQuery + +LLViewQuery::LLViewQuery(): mPreFilters(), mPostFilters(), mSorterp() +{ +} + +void LLViewQuery::addPreFilter(const LLQueryFilter* prefilter) { mPreFilters.push_back(prefilter); } + +void LLViewQuery::addPostFilter(const LLQueryFilter* postfilter) { mPostFilters.push_back(postfilter); } + +const LLViewQuery::filterList_t & LLViewQuery::getPreFilters() const { return mPreFilters; } + +const LLViewQuery::filterList_t & LLViewQuery::getPostFilters() const { return mPostFilters; } + +void LLViewQuery::setSorter(const LLQuerySorter* sorterp) { mSorterp = sorterp; } +const LLQuerySorter* LLViewQuery::getSorter() const { return mSorterp; } + +viewList_t LLViewQuery::run(LLView * view) const +{ + viewList_t result; + + filterResult_t pre = runFilters(view, viewList_t(), mPreFilters); + if(!pre.first && !pre.second) + { + // skip post filters completely if we're not including ourselves or the children + return result; + } + if(pre.second) + { + // run filters on children + viewList_t filtered_children; + filterChildren(view, filtered_children); + filterResult_t post = runFilters(view, filtered_children, mPostFilters); + if(pre.first && post.first) + { + result.push_back(view); + } + if(post.second) + { + result.insert(result.end(), filtered_children.begin(), filtered_children.end()); + } + } + else + { + if(pre.first) + { + result.push_back(view); + } + } + return result; +} + +void LLViewQuery::filterChildren(LLView * view, viewList_t & filtered_children) const +{ + LLView::child_list_t views(*(view->getChildList())); + (*mSorterp)(view, views); // sort the children per the sorter + for(LLView::child_list_iter_t iter = views.begin(); + iter != views.end(); + iter++) + { + viewList_t indiv_children = this->run(*iter); + filtered_children.insert(filtered_children.end(), indiv_children.begin(), indiv_children.end()); + } +} + +filterResult_t LLViewQuery::runFilters(LLView * view, const viewList_t children, const filterList_t filters) const +{ + filterResult_t result = filterResult_t(TRUE, TRUE); + for(filterList_const_iter_t iter = filters.begin(); + iter != filters.end(); + iter++) + { + filterResult_t filtered = (**iter)(view, children); + result.first = result.first && filtered.first; + result.second = result.second && filtered.second; + } + return result; +} + +class SortByTabOrder : public LLQuerySorter, public LLSingleton +{ + /*virtual*/ void operator() (LLView * parent, LLView::child_list_t &children) const + { + children.sort(LLCompareByTabOrder(parent->getCtrlOrder())); + } +}; + +LLCtrlQuery::LLCtrlQuery() : + LLViewQuery() +{ + setSorter(SortByTabOrder::getInstance()); +} + diff --git a/indra/llui/llviewquery.h b/indra/llui/llviewquery.h index ba59965c59..32852791af 100644 --- a/indra/llui/llviewquery.h +++ b/indra/llui/llviewquery.h @@ -1,89 +1,89 @@ -/** - * @file llviewquery.h - * @brief Query algorithm for flattening and filtering the view hierarchy. - * - * Copyright (c) 2001-$CurrentYear$, Linden Research, Inc. - * $License$ - */ - -#ifndef LL_LLVIEWQUERY_H -#define LL_LLVIEWQUERY_H - -#include - -#include "llmemory.h" - -class LLView; - -typedef std::list viewList_t; -typedef std::pair filterResult_t; - -// Abstract base class for all filters. -class LLQueryFilter : public LLRefCount -{ -public: - virtual filterResult_t operator() (const LLView* const view, const viewList_t & children) const =0; -}; - -class LLQuerySorter : public LLRefCount -{ -public: - virtual void operator() (LLView * parent, viewList_t &children) const; -}; - -class LLNoLeavesFilter : public LLQueryFilter, public LLSingleton -{ - /*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const; -}; -class LLVisibleFilter : public LLQueryFilter, public LLSingleton -{ - /*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const; -}; -class LLEnabledFilter : public LLQueryFilter, public LLSingleton -{ - /*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const; -}; -class LLTabStopFilter : public LLQueryFilter, public LLSingleton -{ - /*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const; -}; - -// Algorithm for flattening -class LLViewQuery -{ -public: - typedef std::list filterList_t; - typedef filterList_t::iterator filterList_iter_t; - typedef filterList_t::const_iterator filterList_const_iter_t; - - LLViewQuery(); - virtual ~LLViewQuery() {} - - void addPreFilter(const LLQueryFilter* prefilter); - void addPostFilter(const LLQueryFilter* postfilter); - const filterList_t & getPreFilters() const; - const filterList_t & getPostFilters() const; - - void setSorter(const LLQuerySorter* sorter); - const LLQuerySorter* getSorter() const; - - viewList_t run(LLView * view) const; - // syntactic sugar - viewList_t operator () (LLView * view) const { return run(view); } -protected: - // override this method to provide iteration over other types of children - virtual void filterChildren(LLView * view, viewList_t & filtered_children) const; - filterResult_t runFilters(LLView * view, const viewList_t children, const filterList_t filters) const; -protected: - filterList_t mPreFilters; - filterList_t mPostFilters; - const LLQuerySorter* mSorterp; -}; - -class LLCtrlQuery : public LLViewQuery -{ -public: - LLCtrlQuery(); -}; - -#endif +/** + * @file llviewquery.h + * @brief Query algorithm for flattening and filtering the view hierarchy. + * + * Copyright (c) 2001-$CurrentYear$, Linden Research, Inc. + * $License$ + */ + +#ifndef LL_LLVIEWQUERY_H +#define LL_LLVIEWQUERY_H + +#include + +#include "llmemory.h" + +class LLView; + +typedef std::list viewList_t; +typedef std::pair filterResult_t; + +// Abstract base class for all filters. +class LLQueryFilter : public LLRefCount +{ +public: + virtual filterResult_t operator() (const LLView* const view, const viewList_t & children) const =0; +}; + +class LLQuerySorter : public LLRefCount +{ +public: + virtual void operator() (LLView * parent, viewList_t &children) const; +}; + +class LLNoLeavesFilter : public LLQueryFilter, public LLSingleton +{ + /*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const; +}; +class LLVisibleFilter : public LLQueryFilter, public LLSingleton +{ + /*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const; +}; +class LLEnabledFilter : public LLQueryFilter, public LLSingleton +{ + /*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const; +}; +class LLTabStopFilter : public LLQueryFilter, public LLSingleton +{ + /*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const; +}; + +// Algorithm for flattening +class LLViewQuery +{ +public: + typedef std::list filterList_t; + typedef filterList_t::iterator filterList_iter_t; + typedef filterList_t::const_iterator filterList_const_iter_t; + + LLViewQuery(); + virtual ~LLViewQuery() {} + + void addPreFilter(const LLQueryFilter* prefilter); + void addPostFilter(const LLQueryFilter* postfilter); + const filterList_t & getPreFilters() const; + const filterList_t & getPostFilters() const; + + void setSorter(const LLQuerySorter* sorter); + const LLQuerySorter* getSorter() const; + + viewList_t run(LLView * view) const; + // syntactic sugar + viewList_t operator () (LLView * view) const { return run(view); } +protected: + // override this method to provide iteration over other types of children + virtual void filterChildren(LLView * view, viewList_t & filtered_children) const; + filterResult_t runFilters(LLView * view, const viewList_t children, const filterList_t filters) const; +protected: + filterList_t mPreFilters; + filterList_t mPostFilters; + const LLQuerySorter* mSorterp; +}; + +class LLCtrlQuery : public LLViewQuery +{ +public: + LLCtrlQuery(); +}; + +#endif diff --git a/indra/newview/lldrawable.cpp b/indra/newview/lldrawable.cpp index 868d61942d..3418007d41 100644 --- a/indra/newview/lldrawable.cpp +++ b/indra/newview/lldrawable.cpp @@ -908,8 +908,8 @@ void LLDrawable::updateLightSet() // mLightSet points to nearby lights mLightSet.clear(); part->getLights(getPositionAgent(), getRadius(), mLightSet); - const S32 max_lights = 16; - if (mLightSet.size() > max_lights) + const drawable_set_t::size_type MAX_LIGHTS = 16; + if (mLightSet.size() > MAX_LIGHTS) { typedef std::set > > sorted_pair_set_t; sorted_pair_set_t sorted_set; diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp index 64edcecdc6..bb76957da1 100644 --- a/indra/newview/llface.cpp +++ b/indra/newview/llface.cpp @@ -711,11 +711,13 @@ BOOL LLFace::genVolumeBBoxes(const LLVolume &volume, S32 f, const LLVolumeFace &face = volume.getVolumeFace(f); //get bounding box - if (mDrawablep->isState(LLDrawable::REBUILD_ALL)) + if (mDrawablep->isState(LLDrawable::REBUILD_VOLUME | LLDrawable::REBUILD_POSITION)) { - //vertex buffer no longer valid - mVertexBuffer = NULL; - mLastVertexBuffer = NULL; + if (mDrawablep->isState(LLDrawable::REBUILD_VOLUME)) + { //vertex buffer no longer valid + mVertexBuffer = NULL; + mLastVertexBuffer = NULL; + } LLVector3 min,max; diff --git a/indra/newview/llfasttimerview.cpp b/indra/newview/llfasttimerview.cpp index 85b8bbebd4..cbcdfaa55c 100644 --- a/indra/newview/llfasttimerview.cpp +++ b/indra/newview/llfasttimerview.cpp @@ -159,7 +159,7 @@ static struct ft_display_info ft_display_table[] = // { LLFastTimer::FTM_RENDER_FONTS, " Fonts", &LLColor4::pink1, 0 }, // { LLFastTimer::FTM_UPDATE_TEXTURES, " Textures", &LLColor4::pink2, 0 }, { LLFastTimer::FTM_SWAP, " Swap", &LLColor4::pink1, 0 }, -// { LLFastTimer::FTM_TEMP6, " Client Copy", &LLColor4::red1, 1}, + { LLFastTimer::FTM_CLIENT_COPY, " Client Copy", &LLColor4::red1, 1}, // { LLFastTimer::FTM_TEMP1, " Temp1", &LLColor4::red1, 0 }, // { LLFastTimer::FTM_TEMP2, " Temp2", &LLColor4::magenta1, 0 }, diff --git a/indra/newview/llflexibleobject.cpp b/indra/newview/llflexibleobject.cpp index 4e03e34663..020ce00bab 100644 --- a/indra/newview/llflexibleobject.cpp +++ b/indra/newview/llflexibleobject.cpp @@ -216,12 +216,6 @@ void LLVolumeImplFlexible::setAttributesOfAllSections() void LLVolumeImplFlexible::onSetVolume(const LLVolumeParams &volume_params, const S32 detail) { - if (mVO && mVO->mDrawable.notNull()) - { - LLVOVolume* volume = (LLVOVolume*) mVO; - volume->regenFaces(); - } - /*doIdleUpdate(gAgent, *gWorldp, 0.0); if (mVO && mVO->mDrawable.notNull()) { @@ -615,11 +609,19 @@ BOOL LLVolumeImplFlexible::doUpdateGeometry(LLDrawable *drawable) { LLVolumeParams volume_params = volume->getVolume()->getParams(); volume->setVolume(volume_params, 0); + mUpdated = FALSE; } volume->updateRelativeXform(); doFlexibleUpdate(); - if (!mUpdated || volume->mFaceMappingChanged) + + if (volume->mLODChanged || volume->mFaceMappingChanged || + volume->mVolumeChanged) + { + volume->regenFaces(); + } + + if (!mUpdated || volume->mFaceMappingChanged || volume->mVolumeChanged) { doFlexibleRebuild(); volume->genBBoxes(isVolumeGlobal()); @@ -629,6 +631,7 @@ BOOL LLVolumeImplFlexible::doUpdateGeometry(LLDrawable *drawable) volume->mLODChanged = FALSE; volume->mFaceMappingChanged = FALSE; + // clear UV flag drawable->clearState(LLDrawable::UV); diff --git a/indra/newview/llfloaterinspect.cpp b/indra/newview/llfloaterinspect.cpp index 0b9d836a1a..8bb73e3a9b 100644 --- a/indra/newview/llfloaterinspect.cpp +++ b/indra/newview/llfloaterinspect.cpp @@ -1,220 +1,221 @@ -#include "llviewerprecompiledheaders.h" -#include "llfloateravatarinfo.h" -#include "llfloaterinspect.h" -#include "llfloatertools.h" -#include "llcachename.h" -#include "llscrolllistctrl.h" -#include "llselectmgr.h" -#include "lltoolcomp.h" -#include "lltoolmgr.h" -#include "llviewercontrol.h" -#include "llviewerobject.h" -#include "llvieweruictrlfactory.h" - -LLFloaterInspect* LLFloaterInspect::sInstance = NULL; - -LLFloaterInspect::LLFloaterInspect(void) : - LLFloater("Inspect Object"), - mDirty(FALSE) -{ - sInstance = this; - gUICtrlFactory->buildFloater(this, "floater_inspect.xml"); -} - -LLFloaterInspect::~LLFloaterInspect(void) -{ - if(!gFloaterTools->getVisible()) - { - if(gToolMgr->getBaseTool() == gToolInspect) - { - select_tool(gToolNull); - } - // Switch back to basic toolset - gToolMgr->setCurrentToolset(gBasicToolset); - } - else - { - gFloaterTools->setFocus(TRUE); - } - sInstance = NULL; -} - -BOOL LLFloaterInspect::isVisible() -{ - return (!!sInstance); -} - -void LLFloaterInspect::show(void* ignored) -{ - if(sInstance) - { - sInstance->open(); - } - else - { - LLFloaterInspect* self = new LLFloaterInspect; - self->open(); - } - - sInstance->mObjectSelection = gSelectMgr->getSelection(); - select_tool(gToolInspect); - sInstance->refresh(); -} - -void LLFloaterInspect::onClickCreatorProfile(void* ctrl) -{ - if(sInstance->mObjectList->getAllSelected().size() == 0) return; - LLSelectNode* obj = sInstance->mObjectSelection->getFirstNode(); - LLUUID obj_id, creator_id; - obj_id = sInstance->mObjectList->getFirstSelected()->getUUID(); - while(obj) - { - if(obj_id == obj->getObject()->getID()) - { - creator_id = obj->mPermissions->getCreator(); - break; - } - obj = sInstance->mObjectSelection->getNextNode(); - } - if(obj) - { - LLFloaterAvatarInfo::showFromDirectory(creator_id); - } -} - -void LLFloaterInspect::onClickOwnerProfile(void* ctrl) -{ - if(sInstance->mObjectList->getAllSelected().size() == 0) return; - LLSelectNode* obj = sInstance->mObjectSelection->getFirstNode(); - LLUUID obj_id, owner_id; - obj_id = sInstance->mObjectList->getFirstSelected()->getUUID(); - while(obj) - { - if(obj_id == obj->getObject()->getID()) - { - owner_id = obj->mPermissions->getOwner(); - break; - } - obj = sInstance->mObjectSelection->getNextNode(); - } - if(obj) - { - LLFloaterAvatarInfo::showFromDirectory(owner_id); - } -} - -BOOL LLFloaterInspect::postBuild() -{ - mObjectList = LLUICtrlFactory::getScrollListByName(this, "object_list"); - childSetAction("button owner",onClickOwnerProfile, this); - childSetAction("button creator",onClickCreatorProfile, this); - childSetCommitCallback("object_list", onSelectObject); - return TRUE; -} - -void LLFloaterInspect::onSelectObject(LLUICtrl* ctrl, void* user_data) -{ - if(LLFloaterInspect::getSelectedUUID() != LLUUID::null) - { - sInstance->childSetEnabled("button owner", true); - sInstance->childSetEnabled("button creator", true); - } -} - -LLUUID LLFloaterInspect::getSelectedUUID() -{ - if(sInstance) - { - if(sInstance->mObjectList->getAllSelected().size() > 0) return sInstance->mObjectList->getFirstSelected()->getUUID(); - } - return LLUUID::null; -} - -void LLFloaterInspect::refresh() -{ - LLUUID creator_id; - LLString creator_name; - S32 pos = mObjectList->getScrollPos(); - childSetEnabled("button owner", false); - childSetEnabled("button creator", false); - LLUUID selected_uuid; - S32 selected_index = mObjectList->getFirstSelectedIndex(); - if(selected_index > -1) selected_uuid = mObjectList->getFirstSelected()->getUUID(); - mObjectList->operateOnAll(LLScrollListCtrl::OP_DELETE); - //List all transient objects, then all linked objects - LLSelectNode* obj = mObjectSelection->getFirstNode(); - LLSD row; - while(obj) - { - char owner_first_name[MAX_STRING], owner_last_name[MAX_STRING]; - char creator_first_name[MAX_STRING], creator_last_name[MAX_STRING]; - char time[MAX_STRING]; - std::ostringstream owner_name, creator_name, date; - time_t timestamp = (time_t) (obj->mCreationDate/1000000); - LLString::copy(time, ctime(×tamp), MAX_STRING); - time[24] = '\0'; - date << obj->mCreationDate; - gCacheName->getName(obj->mPermissions->getOwner(), owner_first_name, owner_last_name); - owner_name << owner_first_name << " " << owner_last_name; - gCacheName->getName(obj->mPermissions->getCreator(), creator_first_name, creator_last_name); - creator_name << creator_first_name << " " << creator_last_name; - row["id"] = obj->getObject()->getID(); - row["columns"][0]["column"] = "object_name"; - row["columns"][0]["type"] = "text"; - // make sure we're either at the top of the link chain - // or top of the editable chain, for attachments - if(!(obj->getObject()->isRoot() || obj->getObject()->isRootEdit())) - { - row["columns"][0]["value"] = LLString(" ") + obj->mName; - } - else - { - row["columns"][0]["value"] = obj->mName; - } - row["columns"][1]["column"] = "owner_name"; - row["columns"][1]["type"] = "text"; - row["columns"][1]["value"] = owner_name.str().c_str(); - row["columns"][2]["column"] = "creator_name"; - row["columns"][2]["type"] = "text"; - row["columns"][2]["value"] = creator_name.str().c_str(); - row["columns"][3]["column"] = "creation_date"; - row["columns"][3]["type"] = "text"; - row["columns"][3]["value"] = time; - mObjectList->addElement(row, ADD_TOP); - obj = mObjectSelection->getNextNode(); - } - if(selected_index > -1 && mObjectList->getItemIndex(selected_uuid) == selected_index) - { - mObjectList->selectNthItem(selected_index); - } - else - { - mObjectList->selectNthItem(0); - } - onSelectObject(this, NULL); - mObjectList->setScrollPos(pos); -} - -void LLFloaterInspect::onFocusReceived() -{ - select_tool(gToolInspect); -} - -void LLFloaterInspect::dirty() -{ - if(sInstance) - { - sInstance->setDirty(); - } -} - -void LLFloaterInspect::draw() -{ - if (mDirty) - { - refresh(); - mDirty = FALSE; - } - - LLFloater::draw(); -} \ No newline at end of file +#include "llviewerprecompiledheaders.h" +#include "llfloateravatarinfo.h" +#include "llfloaterinspect.h" +#include "llfloatertools.h" +#include "llcachename.h" +#include "llscrolllistctrl.h" +#include "llselectmgr.h" +#include "lltoolcomp.h" +#include "lltoolmgr.h" +#include "llviewercontrol.h" +#include "llviewerobject.h" +#include "llvieweruictrlfactory.h" + +LLFloaterInspect* LLFloaterInspect::sInstance = NULL; + +LLFloaterInspect::LLFloaterInspect(void) : + LLFloater("Inspect Object"), + mDirty(FALSE) +{ + sInstance = this; + gUICtrlFactory->buildFloater(this, "floater_inspect.xml"); +} + +LLFloaterInspect::~LLFloaterInspect(void) +{ + if(!gFloaterTools->getVisible()) + { + if(gToolMgr->getBaseTool() == gToolInspect) + { + select_tool(gToolNull); + } + // Switch back to basic toolset + gToolMgr->setCurrentToolset(gBasicToolset); + } + else + { + gFloaterTools->setFocus(TRUE); + } + sInstance = NULL; +} + +BOOL LLFloaterInspect::isVisible() +{ + return (!!sInstance); +} + +void LLFloaterInspect::show(void* ignored) +{ + if(sInstance) + { + sInstance->open(); + } + else + { + LLFloaterInspect* self = new LLFloaterInspect; + self->open(); + } + + sInstance->mObjectSelection = gSelectMgr->getSelection(); + select_tool(gToolInspect); + sInstance->refresh(); +} + +void LLFloaterInspect::onClickCreatorProfile(void* ctrl) +{ + if(sInstance->mObjectList->getAllSelected().size() == 0) return; + LLSelectNode* obj = sInstance->mObjectSelection->getFirstNode(); + LLUUID obj_id, creator_id; + obj_id = sInstance->mObjectList->getFirstSelected()->getUUID(); + while(obj) + { + if(obj_id == obj->getObject()->getID()) + { + creator_id = obj->mPermissions->getCreator(); + break; + } + obj = sInstance->mObjectSelection->getNextNode(); + } + if(obj) + { + LLFloaterAvatarInfo::showFromDirectory(creator_id); + } +} + +void LLFloaterInspect::onClickOwnerProfile(void* ctrl) +{ + if(sInstance->mObjectList->getAllSelected().size() == 0) return; + LLSelectNode* obj = sInstance->mObjectSelection->getFirstNode(); + LLUUID obj_id, owner_id; + obj_id = sInstance->mObjectList->getFirstSelected()->getUUID(); + while(obj) + { + if(obj_id == obj->getObject()->getID()) + { + owner_id = obj->mPermissions->getOwner(); + break; + } + obj = sInstance->mObjectSelection->getNextNode(); + } + if(obj) + { + LLFloaterAvatarInfo::showFromDirectory(owner_id); + } +} + +BOOL LLFloaterInspect::postBuild() +{ + mObjectList = LLUICtrlFactory::getScrollListByName(this, "object_list"); + childSetAction("button owner",onClickOwnerProfile, this); + childSetAction("button creator",onClickCreatorProfile, this); + childSetCommitCallback("object_list", onSelectObject); + return TRUE; +} + +void LLFloaterInspect::onSelectObject(LLUICtrl* ctrl, void* user_data) +{ + if(LLFloaterInspect::getSelectedUUID() != LLUUID::null) + { + sInstance->childSetEnabled("button owner", true); + sInstance->childSetEnabled("button creator", true); + } +} + +LLUUID LLFloaterInspect::getSelectedUUID() +{ + if(sInstance) + { + if(sInstance->mObjectList->getAllSelected().size() > 0) return sInstance->mObjectList->getFirstSelected()->getUUID(); + } + return LLUUID::null; +} + +void LLFloaterInspect::refresh() +{ + LLUUID creator_id; + LLString creator_name; + S32 pos = mObjectList->getScrollPos(); + childSetEnabled("button owner", false); + childSetEnabled("button creator", false); + LLUUID selected_uuid; + S32 selected_index = mObjectList->getFirstSelectedIndex(); + if(selected_index > -1) selected_uuid = mObjectList->getFirstSelected()->getUUID(); + mObjectList->operateOnAll(LLScrollListCtrl::OP_DELETE); + //List all transient objects, then all linked objects + LLSelectNode* obj = mObjectSelection->getFirstNode(); + LLSD row; + while(obj) + { + char owner_first_name[MAX_STRING], owner_last_name[MAX_STRING]; + char creator_first_name[MAX_STRING], creator_last_name[MAX_STRING]; + char time[MAX_STRING]; + std::ostringstream owner_name, creator_name, date; + time_t timestamp = (time_t) (obj->mCreationDate/1000000); + LLString::copy(time, ctime(×tamp), MAX_STRING); + time[24] = '\0'; + date << obj->mCreationDate; + gCacheName->getName(obj->mPermissions->getOwner(), owner_first_name, owner_last_name); + owner_name << owner_first_name << " " << owner_last_name; + gCacheName->getName(obj->mPermissions->getCreator(), creator_first_name, creator_last_name); + creator_name << creator_first_name << " " << creator_last_name; + row["id"] = obj->getObject()->getID(); + row["columns"][0]["column"] = "object_name"; + row["columns"][0]["type"] = "text"; + // make sure we're either at the top of the link chain + // or top of the editable chain, for attachments + if(!(obj->getObject()->isRoot() || obj->getObject()->isRootEdit())) + { + row["columns"][0]["value"] = LLString(" ") + obj->mName; + } + else + { + row["columns"][0]["value"] = obj->mName; + } + row["columns"][1]["column"] = "owner_name"; + row["columns"][1]["type"] = "text"; + row["columns"][1]["value"] = owner_name.str().c_str(); + row["columns"][2]["column"] = "creator_name"; + row["columns"][2]["type"] = "text"; + row["columns"][2]["value"] = creator_name.str().c_str(); + row["columns"][3]["column"] = "creation_date"; + row["columns"][3]["type"] = "text"; + row["columns"][3]["value"] = time; + mObjectList->addElement(row, ADD_TOP); + obj = mObjectSelection->getNextNode(); + } + if(selected_index > -1 && mObjectList->getItemIndex(selected_uuid) == selected_index) + { + mObjectList->selectNthItem(selected_index); + } + else + { + mObjectList->selectNthItem(0); + } + onSelectObject(this, NULL); + mObjectList->setScrollPos(pos); +} + +void LLFloaterInspect::onFocusReceived() +{ + select_tool(gToolInspect); +} + +void LLFloaterInspect::dirty() +{ + if(sInstance) + { + sInstance->setDirty(); + } +} + +void LLFloaterInspect::draw() +{ + if (mDirty) + { + refresh(); + mDirty = FALSE; + } + + LLFloater::draw(); +} + diff --git a/indra/newview/llfloaterinspect.h b/indra/newview/llfloaterinspect.h index 6a3f494978..d221879d0e 100644 --- a/indra/newview/llfloaterinspect.h +++ b/indra/newview/llfloaterinspect.h @@ -1,50 +1,50 @@ -/** -* @file llfloaterfriends.h -* @author Cube -* @date 2006-12-16 -* @brief Declaration of class for displaying object attributes -* -* Copyright (c) 2005-$CurrentYear$, Linden Research, Inc. -* $License$ -*/ - -#ifndef LL_LLFLOATERINSPECT_H -#define LL_LLFLOATERINSPECT_H - -#include "llfloater.h" - -//class LLTool; -class LLObjectSelection; -class LLScrollListCtrl; -class LLUICtrl; - -class LLFloaterInspect : public LLFloater -{ -public: - virtual ~LLFloaterInspect(void); - static void show(void* ignored = NULL); - virtual BOOL postBuild(); - static void dirty(); - static LLUUID getSelectedUUID(); - virtual void draw(); - virtual void refresh(); - static BOOL isVisible(); - virtual void onFocusReceived(); - static void onClickCreatorProfile(void* ctrl); - static void onClickOwnerProfile(void* ctrl); - static void onSelectObject(LLUICtrl* ctrl, void* user_data); - LLScrollListCtrl* mObjectList; -protected: - // protected members - LLFloaterInspect(); - void setDirty() { mDirty = TRUE; } - bool mDirty; - -private: - // static data - static LLFloaterInspect* sInstance; - - LLHandle mObjectSelection; -}; - -#endif //LL_LLFLOATERINSPECT_H \ No newline at end of file +/** +* @file llfloaterfriends.h +* @author Cube +* @date 2006-12-16 +* @brief Declaration of class for displaying object attributes +* +* Copyright (c) 2005-$CurrentYear$, Linden Research, Inc. +* $License$ +*/ + +#ifndef LL_LLFLOATERINSPECT_H +#define LL_LLFLOATERINSPECT_H + +#include "llfloater.h" + +//class LLTool; +class LLObjectSelection; +class LLScrollListCtrl; +class LLUICtrl; + +class LLFloaterInspect : public LLFloater +{ +public: + virtual ~LLFloaterInspect(void); + static void show(void* ignored = NULL); + virtual BOOL postBuild(); + static void dirty(); + static LLUUID getSelectedUUID(); + virtual void draw(); + virtual void refresh(); + static BOOL isVisible(); + virtual void onFocusReceived(); + static void onClickCreatorProfile(void* ctrl); + static void onClickOwnerProfile(void* ctrl); + static void onSelectObject(LLUICtrl* ctrl, void* user_data); + LLScrollListCtrl* mObjectList; +protected: + // protected members + LLFloaterInspect(); + void setDirty() { mDirty = TRUE; } + bool mDirty; + +private: + // static data + static LLFloaterInspect* sInstance; + + LLHandle mObjectSelection; +}; + +#endif //LL_LLFLOATERINSPECT_H diff --git a/indra/newview/llfloaterland.cpp b/indra/newview/llfloaterland.cpp index 6f698d2734..3492f4fff8 100644 --- a/indra/newview/llfloaterland.cpp +++ b/indra/newview/llfloaterland.cpp @@ -346,8 +346,8 @@ void* LLFloaterLand::createPanelLandBan(void* data) LLPanelLandGeneral::LLPanelLandGeneral(LLParcelSelectionHandle& parcel) : LLPanel("land_general_panel"), - mParcel(parcel), - mUncheckedSell(FALSE) + mUncheckedSell(FALSE), + mParcel(parcel) { } diff --git a/indra/newview/llfloaterpostcard.cpp b/indra/newview/llfloaterpostcard.cpp index f6fcda29a3..f82978c5fc 100644 --- a/indra/newview/llfloaterpostcard.cpp +++ b/indra/newview/llfloaterpostcard.cpp @@ -51,8 +51,8 @@ LLLinkedList LLFloaterPostcard::sInstances; LLFloaterPostcard::LLFloaterPostcard(LLImageJPEG* jpeg, LLImageGL *img, const LLVector2& img_scale, const LLVector3d& pos_taken_global) : LLFloater("Postcard Floater"), - mViewerImage(img), mJPEGImage(jpeg), + mViewerImage(img), mImageScale(img_scale), mPosTakenGlobal(pos_taken_global) { diff --git a/indra/newview/llfloaterproperties.cpp b/indra/newview/llfloaterproperties.cpp index 793884e008..feeedc5190 100644 --- a/indra/newview/llfloaterproperties.cpp +++ b/indra/newview/llfloaterproperties.cpp @@ -214,7 +214,7 @@ void LLFloaterProperties::refresh() "RadioSaleType", "EditPrice" }; - for(int t=0;tmMembers.size() == group_datap->mMemberCount) + if (group_datap->mMembers.size() == (U32)group_datap->mMemberCount) { group_datap->mMemberDataComplete = TRUE; group_datap->mMemberRequestID.setNull(); @@ -979,7 +979,7 @@ void LLGroupMgr::processGroupRoleDataReply(LLMessageSystem* msg, void** data) group_data->mRoles[role_id] = rd; } - if (group_data->mRoles.size() == group_data->mRoleCount) + if (group_data->mRoles.size() == (U32)group_data->mRoleCount) { group_data->mRoleDataComplete = TRUE; group_data->mRoleDataRequestID.setNull(); diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index f090cea5f2..4de746fd4f 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -2174,6 +2174,8 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, case LLAssetType::AT_CATEGORY: is_movable = ( LLAssetType::AT_NONE == ((LLInventoryCategory*)inv_item)->getPreferredType() ); break; + default: + break; } LLUUID trash_id = model->findCategoryUUIDForType(LLAssetType::AT_TRASH); @@ -2190,6 +2192,8 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, case LLAssetType::AT_OBJECT: is_movable = !avatar->isWearingAttachment(inv_item->getUUID()); break; + default: + break; } } @@ -2759,6 +2763,8 @@ BOOL LLCallingCardBridge::dragOrDrop(MASK mask, BOOL drop, } break; } + default: + break; } } return rv; @@ -3407,8 +3413,8 @@ struct LLFoundData LLAssetType::EType asset_type) : mItemID(item_id), mAssetID(asset_id), - mAssetType(asset_type), mName(name), + mAssetType(asset_type), mWearable( NULL ) {} LLUUID mItemID; diff --git a/indra/newview/llmaniptranslate.cpp b/indra/newview/llmaniptranslate.cpp index 93ae74db22..9e26d951bc 100644 --- a/indra/newview/llmaniptranslate.cpp +++ b/indra/newview/llmaniptranslate.cpp @@ -1120,6 +1120,8 @@ void LLManipTranslate::renderSnapGuides() inner_color.setVec(1,1,0,line_alpha); mManipPart = LL_XY_PLANE; break; + default: + break; } highlightIntersection(normal, selection_center, grid_rotation, inner_color); diff --git a/indra/newview/llpanelavatar.cpp b/indra/newview/llpanelavatar.cpp index 810e026d2a..3ec14b6117 100644 --- a/indra/newview/llpanelavatar.cpp +++ b/indra/newview/llpanelavatar.cpp @@ -512,25 +512,25 @@ BOOL LLPanelAvatarPicks::postBuild(void) return TRUE; } -BOOL LLPanelAvatarAdvanced::postBuild() +BOOL LLPanelAvatarAdvanced::postBuild() { - for( S32 i = 0; i < kArraySize(mWantToCheck); i++ ) - mWantToCheck[i] = NULL; - for( S32 i = 0; i < kArraySize(mSkillsCheck); i++ ) - mSkillsCheck[i] = NULL; + for(size_t ii = 0; ii < kArraySize(mWantToCheck); ++ii) + mWantToCheck[ii] = NULL; + for(size_t ii = 0; ii < kArraySize(mSkillsCheck); ++ii) + mSkillsCheck[ii] = NULL; mWantToCount = (8>kArraySize(mWantToCheck))?kArraySize(mWantToCheck):8; - for(int t=0;t < mWantToCount ;t++) + for(S32 tt=0; tt < mWantToCount; ++tt) { - LLString ctlname = llformat("chk%d",t); - mWantToCheck[t] = LLUICtrlFactory::getCheckBoxByName(this,ctlname); + LLString ctlname = llformat("chk%d", tt); + mWantToCheck[tt] = LLUICtrlFactory::getCheckBoxByName(this,ctlname); } mSkillsCount = (6>kArraySize(mSkillsCheck))?kArraySize(mSkillsCheck):6; - for(int t=0;tsetCommitCallback(onRoleCheck); check->setCallbackUserData(this); check->set( count > 0 ); - check->setTentative(0 != count && selected_members.size() != count); + check->setTentative( + (0 != count) + && (selected_members.size() != + (std::vector::size_type)count)); //NOTE: as of right now a user can break the group //by removing himself from a role if he is the @@ -1996,7 +1999,7 @@ void LLPanelGroupRolesSubTab::update(LLGroupChange gc) mRolesList->sortByColumn("name", TRUE); - if ( (gdatap->mRoles.size() < MAX_ROLES) + if ( (gdatap->mRoles.size() < (U32)MAX_ROLES) && gAgent.hasPowerInGroup(mGroupID, GP_ROLE_CREATE) ) { mCreateRoleButton->setEnabled(TRUE); diff --git a/indra/newview/llpreview.cpp b/indra/newview/llpreview.cpp index c5e589529c..91df61ca91 100644 --- a/indra/newview/llpreview.cpp +++ b/indra/newview/llpreview.cpp @@ -513,4 +513,4 @@ void LLMultiPreview::setAutoOpenInstance(LLMultiPreview* previewp, const LLUUID& { sAutoOpenPreviewHandles[id] = previewp->getHandle(); } -} \ No newline at end of file +} diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index 950ed61b25..3eddc04259 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -5770,8 +5770,8 @@ BOOL LLSelectMgr::canSelectObject(LLViewerObject* object) LLObjectSelection::LLObjectSelection() : std::list(), LLRefCount(), - mCurrentTE(-1), mCurrentNode(end()), + mCurrentTE(-1), mSelectType(SELECT_TYPE_WORLD) { } diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp index 739d30bfe6..62903011cf 100644 --- a/indra/newview/llspatialpartition.cpp +++ b/indra/newview/llspatialpartition.cpp @@ -289,6 +289,7 @@ void LLSpatialGroup::validateDrawMap() void LLSpatialGroup::makeStatic() { +#if !LL_DARWIN if (isState(GEOM_DIRTY | ALPHA_DIRTY)) { return; @@ -309,6 +310,7 @@ void LLSpatialGroup::makeStatic() mBuilt = 1.f; } +#endif } BOOL LLSpatialGroup::updateInGroup(LLDrawable *drawablep, BOOL immediate) @@ -318,7 +320,12 @@ BOOL LLSpatialGroup::updateInGroup(LLDrawable *drawablep, BOOL immediate) drawablep->updateSpatialExtents(); validate_drawable(drawablep); - if (mOctreeNode->isInside(drawablep) && mOctreeNode->contains(drawablep)) + OctreeNode* parent = mOctreeNode->getOctParent(); + + if (mOctreeNode->isInside(drawablep->getPositionGroup()) && + (mOctreeNode->contains(drawablep) || + (drawablep->getBinRadius() > mOctreeNode->getSize().mdV[0] && + parent && parent->getElementCount() >= LL_OCTREE_MAX_CAPACITY))) { unbound(); setState(OBJECT_DIRTY); @@ -697,14 +704,21 @@ void LLSpatialGroup::clearState(U32 state, S32 mode) // Octree Listener Implementation //====================================== -LLSpatialGroup::LLSpatialGroup(OctreeNode* node, LLSpatialPartition* part) -: mOctreeNode(node), mState(0), mSpatialPartition(part), mVertexBuffer(NULL), - mDistance(0.f), mLastUpdateDistance(-1.f), - mViewAngle(0.f), mLastUpdateViewAngle(-1.f), - mDepth(0.f), mBuilt(0.f), - mLastUpdateTime(gFrameTimeSeconds), mLastRenderTime(gFrameTimeSeconds), - mLastAddTime(gFrameTimeSeconds), - mBufferUsage(GL_STATIC_DRAW_ARB) +LLSpatialGroup::LLSpatialGroup(OctreeNode* node, LLSpatialPartition* part) : + mState(0), + mBuilt(0.f), + mOctreeNode(node), + mSpatialPartition(part), + mVertexBuffer(NULL), + mBufferUsage(GL_STATIC_DRAW_ARB), + mDistance(0.f), + mDepth(0.f), + mLastUpdateDistance(-1.f), + mLastUpdateTime(gFrameTimeSeconds), + mLastAddTime(gFrameTimeSeconds), + mLastRenderTime(gFrameTimeSeconds), + mViewAngle(0.f), + mLastUpdateViewAngle(-1.f) { LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); @@ -898,6 +912,31 @@ void LLSpatialGroup::handleChildRemoval(const OctreeNode* parent, const OctreeNo unbound(); } +void LLSpatialGroup::destroyGL() +{ + setState(LLSpatialGroup::GEOM_DIRTY | + LLSpatialGroup::OCCLUSION_DIRTY | + LLSpatialGroup::IMAGE_DIRTY); + mLastUpdateTime = gFrameTimeSeconds; + mVertexBuffer = NULL; + mBufferMap.clear(); + + mOcclusionVerts = NULL; + mReflectionMap = NULL; + clearDrawMap(); + + for (LLSpatialGroup::element_iter i = getData().begin(); i != getData().end(); ++i) + { + LLDrawable* drawable = *i; + for (S32 j = 0; j < drawable->getNumFaces(); j++) + { + LLFace* facep = drawable->getFace(j); + facep->mVertexBuffer = NULL; + facep->mLastVertexBuffer = NULL; + } + } +} + BOOL LLSpatialGroup::rebound() { if (!isState(DIRTY)) @@ -1423,28 +1462,11 @@ public: virtual void visit(const LLOctreeState* state) { LLSpatialGroup* group = (LLSpatialGroup*) state->getListener(0); + group->destroyGL(); - group->setState(LLSpatialGroup::GEOM_DIRTY | - LLSpatialGroup::OCCLUSION_DIRTY | - LLSpatialGroup::IMAGE_DIRTY); - group->mLastUpdateTime = gFrameTimeSeconds; - group->mVertexBuffer = NULL; - group->mBufferMap.clear(); - - group->mOcclusionVerts = NULL; - group->mReflectionMap = NULL; - group->clearDrawMap(); - for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i) { LLDrawable* drawable = *i; - for (S32 j = 0; j < drawable->getNumFaces(); j++) - { - LLFace* facep = drawable->getFace(j); - facep->mVertexBuffer = NULL; - facep->mLastVertexBuffer = NULL; - } - if (drawable->getVObj() && !group->mSpatialPartition->mRenderByGroup) { gPipeline.markRebuild(drawable, LLDrawable::REBUILD_ALL, TRUE); @@ -1458,6 +1480,7 @@ public: } } }; + void LLSpatialPartition::restoreGL() { LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); @@ -1597,7 +1620,7 @@ void LLSpatialPartition::processGeometry(LLCamera* camera) U32 process_count = 8; LLSpatialGroup* root = (LLSpatialGroup*) mOctree->getListener(0); - if (!root->isState(LLSpatialGroup::IN_GEOMETRY_QUEUE)) + if (mUpdateQueue.empty()) { root->setState(LLSpatialGroup::IN_GEOMETRY_QUEUE); mUpdateQueue.push(root); @@ -1628,18 +1651,19 @@ void LLSpatialPartition::processGeometry(LLCamera* camera) } } - if (!group->isDead() && - !group->isVisible() && - !group->isState(LLSpatialGroup::OBJECT_DIRTY) && - group->mBufferUsage != GL_STREAM_DRAW_ARB) + if (!group->isDead() && !group->isVisible()) { - group->updateDistance(*camera); - for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i) + if (!group->isState(LLSpatialGroup::OBJECT_DIRTY) && + group->mBufferUsage != GL_STREAM_DRAW_ARB) { - LLDrawable* drawablep = *i; - if (!drawablep->isDead()) + group->updateDistance(*camera); + for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i) { - drawablep->updateDistance(*camera); + LLDrawable* drawablep = *i; + if (!drawablep->isDead()) + { + drawablep->updateDistance(*camera); + } } } } @@ -1703,7 +1727,7 @@ void LLSpatialPartition::processImagery(LLCamera* camera) } gPipeline.generateReflectionMap(gPipeline.mCubeBuffer, cube_cam, 128); - gPipeline.blurReflectionMap(gPipeline.mCubeBuffer, cube_map, 32); + gPipeline.blurReflectionMap(gPipeline.mCubeBuffer, cube_map, 64); group->mReflectionMap = cube_map; group->setState(LLSpatialGroup::GEOM_DIRTY); gPipeline.markRebuild(group); @@ -2821,11 +2845,19 @@ LLDrawable* LLSpatialPartition::pickDrawable(const LLVector3& start, const LLVec LLDrawInfo::LLDrawInfo(U32 start, U32 end, U32 count, U32 offset, LLViewerImage* texture, LLVertexBuffer* buffer, BOOL fullbright, U8 bump, BOOL particle, F32 part_size) -: mStart(start), mEnd(end), mCount(count), mOffset(offset), - mTexture(texture), mVertexBuffer(buffer), - mFullbright(fullbright), mBump(bump), - mParticle(particle), mPartSize(part_size), - mVSize(0.f), mTextureMatrix(NULL) +: + mVertexBuffer(buffer), + mTexture(texture), + mTextureMatrix(NULL), + mStart(start), + mEnd(end), + mCount(count), + mOffset(offset), + mFullbright(fullbright), + mBump(bump), + mParticle(particle), + mPartSize(part_size), + mVSize(0.f) { } diff --git a/indra/newview/llspatialpartition.h b/indra/newview/llspatialpartition.h index ea0802985e..6a795d4c6c 100644 --- a/indra/newview/llspatialpartition.h +++ b/indra/newview/llspatialpartition.h @@ -173,6 +173,7 @@ public: BOOL boundObjects(BOOL empty, LLVector3& newMin, LLVector3& newMax); void unbound(); BOOL rebound(); + void destroyGL(); void updateDistance(LLCamera& camera); BOOL changeLOD(); @@ -273,6 +274,8 @@ public: BOOL isVolatile() const { return mVolatile; } virtual LLSpatialBridge* asBridge() { return NULL; } + virtual BOOL isBridge() { return asBridge() != NULL; } + S32 getObjects(const LLVector3& pos, F32 rad, LLDrawable::drawable_set_t &results ); S32 getLights(const LLVector3& pos, F32 rad, LLDrawable::drawable_set_t &results ); diff --git a/indra/newview/lltexturecache.cpp b/indra/newview/lltexturecache.cpp index 13efadf213..cb846a43fe 100644 --- a/indra/newview/lltexturecache.cpp +++ b/indra/newview/lltexturecache.cpp @@ -1,1365 +1,1365 @@ -/** - * @file texturecache.cpp - * @brief Object which handles local texture caching - * - * Copyright (c) 2000-$CurrentYear$, Linden Research, Inc. - * $License$ - */ - -#include "llviewerprecompiledheaders.h" - -#include "lltexturecache.h" - -#include "llapr.h" -#include "lldir.h" -#include "llimage.h" -#include "lllfsthread.h" -#include "llviewercontrol.h" - -#define USE_LFS_READ 0 -#define USE_LFS_WRITE 0 - -// Note: first 4 bytes store file size, rest is j2c data -const S32 TEXTURE_CACHE_ENTRY_SIZE = FIRST_PACKET_SIZE; //1024; - -class LLTextureCacheWorker : public LLWorkerClass -{ - friend class LLTextureCache; - -private: - enum e_state - { - INIT = 0, - LOCAL = 1, - CACHE = 2, - HEADER = 3, - BODY = 4 - }; - - class ReadResponder : public LLLFSThread::Responder - { - public: - ReadResponder(LLTextureCache* cache, handle_t handle) : mCache(cache), mHandle(handle) {} - ~ReadResponder() {} - void completed(S32 bytes) - { - mCache->lockWorkers(); - LLTextureCacheWorker* reader = mCache->getReader(mHandle); - if (reader) reader->ioComplete(bytes); - mCache->unlockWorkers(); - } - LLTextureCache* mCache; - LLTextureCacheWorker::handle_t mHandle; - }; - - class WriteResponder : public LLLFSThread::Responder - { - public: - WriteResponder(LLTextureCache* cache, handle_t handle) : mCache(cache), mHandle(handle) {} - ~WriteResponder() {} - void completed(S32 bytes) - { - mCache->lockWorkers(); - LLTextureCacheWorker* writer = mCache->getWriter(mHandle); - if (writer) writer->ioComplete(bytes); - mCache->unlockWorkers(); - } - LLTextureCache* mCache; - LLTextureCacheWorker::handle_t mHandle; - }; - -public: - LLTextureCacheWorker(LLTextureCache* cache, U32 priority, const LLUUID& id, - U8* data, S32 datasize, S32 offset, - S32 imagesize, // for writes - LLTextureCache::Responder* responder) - : LLWorkerClass(cache, "LLTextureCacheWorker"), - mCache(cache), - mPriority(priority), - mID(id), - mState(INIT), - mReadData(NULL), - mWriteData(data), - mDataSize(datasize), - mOffset(offset), - mImageSize(imagesize), - mImageFormat(IMG_CODEC_J2C), - mImageLocal(FALSE), - mResponder(responder), - mFileHandle(LLLFSThread::nullHandle()), - mBytesToRead(0), - mBytesRead(0) - { - mPriority &= LLWorkerThread::PRIORITY_LOWBITS; - } - ~LLTextureCacheWorker() - { - llassert_always(!haveWork()); - delete[] mReadData; - } - - bool doRead(); - bool doWrite(); - virtual bool doWork(S32 param); // Called from LLWorkerThread::processRequest() - - handle_t read() { addWork(0, LLWorkerThread::PRIORITY_HIGH | mPriority); return mRequestHandle; } - handle_t write() { addWork(1, LLWorkerThread::PRIORITY_HIGH | mPriority); return mRequestHandle; } - bool complete() { return checkWork(); } - void ioComplete(S32 bytes) - { - mBytesRead = bytes; - setPriority(LLWorkerThread::PRIORITY_HIGH | mPriority); - } - -private: - virtual void startWork(S32 param); // called from addWork() (MAIN THREAD) - virtual void finishWork(S32 param, bool completed); // called from finishRequest() (WORK THREAD) - virtual void endWork(S32 param, bool aborted); // called from doWork() (MAIN THREAD) - -private: - LLTextureCache* mCache; - U32 mPriority; - LLUUID mID; - e_state mState; - - U8* mReadData; - U8* mWriteData; - S32 mDataSize; - S32 mOffset; - S32 mImageSize; - S32 mImageFormat; - BOOL mImageLocal; - LLPointer mResponder; - LLLFSThread::handle_t mFileHandle; - S32 mBytesToRead; - LLAtomicS32 mBytesRead; -}; - -//virtual -void LLTextureCacheWorker::startWork(S32 param) -{ -} - -bool LLTextureCacheWorker::doRead() -{ - S32 local_size = 0; - std::string local_filename; - - if (mState == INIT) - { - std::string filename = mCache->getLocalFileName(mID); - local_filename = filename + ".j2c"; - local_size = ll_apr_file_size(local_filename, mCache->getFileAPRPool()); - if (local_size == 0) - { - local_filename = filename + ".tga"; - local_size = ll_apr_file_size(local_filename, mCache->getFileAPRPool()); - if (local_size > 0) - { - mImageFormat = IMG_CODEC_TGA; - mDataSize = local_size; // Only a complete .tga file is valid - } - } - if (local_size > 0) - { - mState = LOCAL; - } - else - { - mState = CACHE; - } - } - - if (mState == LOCAL) - { -#if USE_LFS_READ - if (mFileHandle == LLLFSThread::nullHandle()) - { - mImageLocal = TRUE; - mImageSize = local_size; - if (!mDataSize || mDataSize + mOffset > local_size) - { - mDataSize = local_size - mOffset; - } - if (mDataSize <= 0) - { - // no more data to read - mDataSize = 0; - return true; - } - mReadData = new U8[mDataSize]; - mBytesRead = -1; - mBytesToRead = mDataSize; - setPriority(LLWorkerThread::PRIORITY_LOW | mPriority); - mFileHandle = LLLFSThread::sLocal->read(local_filename, mReadData, mOffset, mDataSize, - new ReadResponder(mCache, mRequestHandle)); - return false; - } - else - { - if (mBytesRead >= 0) - { - if (mBytesRead != mBytesToRead) - { - llwarns << "Error reading file from local cache: " << local_filename - << " Bytes: " << mDataSize << " Offset: " << mOffset - << " / " << mDataSize << llendl; - mDataSize = 0; // failed - delete[] mReadData; - mReadData = NULL; - } - return true; - } - else - { - return false; - } - } -#else - if (!mDataSize || mDataSize > local_size) - { - mDataSize = local_size; - } - mReadData = new U8[mDataSize]; - S32 bytes_read = ll_apr_file_read_ex(local_filename, mCache->getFileAPRPool(), - mReadData, mOffset, mDataSize); - if (bytes_read != mDataSize) - { - llwarns << "Error reading file from local cache: " << local_filename - << " Bytes: " << mDataSize << " Offset: " << mOffset - << " / " << mDataSize << llendl; - mDataSize = 0; - delete[] mReadData; - mReadData = NULL; - } - else - { - mImageSize = local_size; - mImageLocal = TRUE; - } - return true; -#endif - } - - S32 idx = -1; - - if (mState == CACHE) - { - llassert_always(mImageSize == 0); - idx = mCache->getHeaderCacheEntry(mID, false, &mImageSize); - if (idx >= 0 && mImageSize > mOffset) - { - llassert_always(mImageSize > 0); - if (!mDataSize || mDataSize > mImageSize) - { - mDataSize = mImageSize; - } - mState = mOffset < TEXTURE_CACHE_ENTRY_SIZE ? HEADER : BODY; - } - else - { - mDataSize = 0; // no data - return true; - } - } - - if (mState == HEADER) - { -#if USE_LFS_READ - if (mFileHandle == LLLFSThread::nullHandle()) - { - llassert_always(idx >= 0); - llassert_always(mOffset < TEXTURE_CACHE_ENTRY_SIZE); - S32 offset = idx * TEXTURE_CACHE_ENTRY_SIZE + mOffset; - S32 size = TEXTURE_CACHE_ENTRY_SIZE - mOffset; - llassert_always(mReadData == NULL); - mReadData = new U8[size]; - mBytesRead = -1; - mBytesToRead = size; - setPriority(LLWorkerThread::PRIORITY_LOW | mPriority); - mFileHandle = LLLFSThread::sLocal->read(mCache->mHeaderDataFileName, - mReadData, offset, mBytesToRead, - new ReadResponder(mCache, mRequestHandle)); - return false; - } - else - { - if (mBytesRead >= 0) - { - if (mBytesRead != mBytesToRead) - { - llwarns << "LLTextureCacheWorker: " << mID - << " incorrect number of bytes read from header: " << mBytesRead - << " != " << mBytesToRead << llendl; - mDataSize = -1; // failed - return true; - } - if (mDataSize <= TEXTURE_CACHE_ENTRY_SIZE) - { - return true; // done - } - else - { - mFileHandle = LLLFSThread::nullHandle(); - mState = BODY; - } - } - else - { - return false; - } - } -#else - llassert_always(idx >= 0); - llassert_always(mOffset < TEXTURE_CACHE_ENTRY_SIZE); - S32 offset = idx * TEXTURE_CACHE_ENTRY_SIZE + mOffset; - S32 size = TEXTURE_CACHE_ENTRY_SIZE - mOffset; - mReadData = new U8[size]; - S32 bytes_read = ll_apr_file_read_ex(mCache->mHeaderDataFileName, mCache->getFileAPRPool(), - mReadData, offset, size); - if (bytes_read != size) - { - llwarns << "LLTextureCacheWorker: " << mID - << " incorrect number of bytes read from header: " << bytes_read - << " / " << size << llendl; - mDataSize = -1; // failed - return true; - } - if (mDataSize <= TEXTURE_CACHE_ENTRY_SIZE) - { - return true; // done - } - else - { - mState = BODY; - } -#endif - } - - if (mState == BODY) - { -#if USE_LFS_READ - if (mFileHandle == LLLFSThread::nullHandle()) - { - std::string filename = mCache->getTextureFileName(mID); - S32 filesize = ll_apr_file_size(filename, mCache->getFileAPRPool()); - if (filesize > mOffset) - { - S32 datasize = TEXTURE_CACHE_ENTRY_SIZE + filesize; - mDataSize = llmin(datasize, mDataSize); - S32 data_offset = TEXTURE_CACHE_ENTRY_SIZE - mOffset; - data_offset = llmax(data_offset, 0); - S32 file_size = mDataSize - data_offset; - S32 file_offset = mOffset - TEXTURE_CACHE_ENTRY_SIZE; - file_offset = llmax(file_offset, 0); - - llassert_always(mDataSize > 0); - U8* data = new U8[mDataSize]; - if (data_offset > 0) - { - llassert_always(mReadData); - llassert_always(data_offset <= mDataSize); - memcpy(data, mReadData, data_offset); - delete[] mReadData; - mReadData = NULL; - } - llassert_always(mReadData == NULL); - mReadData = data; - - mBytesRead = -1; - mBytesToRead = file_size; - setPriority(LLWorkerThread::PRIORITY_LOW | mPriority); - llassert_always(data_offset + mBytesToRead <= mDataSize); - mFileHandle = LLLFSThread::sLocal->read(filename, - mReadData + data_offset, file_offset, mBytesToRead, - new ReadResponder(mCache, mRequestHandle)); - return false; - } - else - { - mDataSize = TEXTURE_CACHE_ENTRY_SIZE; - return true; // done - } - } - else - { - if (mBytesRead >= 0) - { - if (mBytesRead != mBytesToRead) - { - llwarns << "LLTextureCacheWorker: " << mID - << " incorrect number of bytes read from body: " << mBytesRead - << " != " << mBytesToRead << llendl; - mDataSize = -1; // failed - } - return true; - } - else - { - return false; - } - } -#else - std::string filename = mCache->getTextureFileName(mID); - S32 filesize = ll_apr_file_size(filename, mCache->getFileAPRPool()); - S32 bytes_read = 0; - if (filesize > mOffset) - { - S32 datasize = TEXTURE_CACHE_ENTRY_SIZE + filesize; - mDataSize = llmin(datasize, mDataSize); - S32 data_offset = TEXTURE_CACHE_ENTRY_SIZE - mOffset; - data_offset = llmax(data_offset, 0); - S32 file_size = mDataSize - data_offset; - S32 file_offset = mOffset - TEXTURE_CACHE_ENTRY_SIZE; - file_offset = llmax(file_offset, 0); - - U8* data = new U8[mDataSize]; - if (data_offset > 0) - { - llassert_always(mReadData); - memcpy(data, mReadData, data_offset); - delete[] mReadData; - } - mReadData = data; - bytes_read = ll_apr_file_read_ex(filename, mCache->getFileAPRPool(), - mReadData + data_offset, - file_offset, file_size); - if (bytes_read != file_size) - { - llwarns << "LLTextureCacheWorker: " << mID - << " incorrect number of bytes read from body: " << bytes_read - << " / " << file_size << llendl; - mDataSize = -1; // failed - return true; - } - } - else - { - mDataSize = TEXTURE_CACHE_ENTRY_SIZE; - } - - return true; -#endif - } - - return false; -} - -bool LLTextureCacheWorker::doWrite() -{ - S32 idx = -1; - - if (mState == INIT) - { - llassert_always(mOffset == 0); // Currently don't support offsets - mState = CACHE; - } - - // No LOCAL state for write() - - if (mState == CACHE) - { - S32 cur_imagesize = 0; - S32 offset = mOffset; - idx = mCache->getHeaderCacheEntry(mID, false, &cur_imagesize); - if (idx >= 0 && cur_imagesize > 0) - { - offset = TEXTURE_CACHE_ENTRY_SIZE; // don't re-write header - } - idx = mCache->getHeaderCacheEntry(mID, true, &mImageSize); // touch entry - if (idx >= 0) - { - llassert_always(cur_imagesize <= 0 || mImageSize == cur_imagesize); - mState = offset < TEXTURE_CACHE_ENTRY_SIZE ? HEADER : BODY; - } - else - { - mDataSize = -1; // failed - return true; - } - } - - if (mState == HEADER) - { -#if USE_LFS_WRITE - if (mFileHandle == LLLFSThread::nullHandle()) - { - llassert_always(idx >= 0); - llassert_always(mOffset < TEXTURE_CACHE_ENTRY_SIZE); - S32 offset = idx * TEXTURE_CACHE_ENTRY_SIZE + mOffset; - S32 size = TEXTURE_CACHE_ENTRY_SIZE - mOffset; - mBytesRead = -1; - mBytesToRead = size; - setPriority(LLWorkerThread::PRIORITY_LOW | mPriority); - mFileHandle = LLLFSThread::sLocal->write(mCache->mHeaderDataFileName, - mWriteData, offset, mBytesToRead, - new WriteResponder(mCache, mRequestHandle)); - return false; - } - else - { - if (mBytesRead >= 0) - { - if (mBytesRead != mBytesToRead) - { - llwarns << "LLTextureCacheWorker: " << mID - << " incorrect number of bytes written to header: " << mBytesRead - << " != " << mBytesToRead << llendl; - mDataSize = -1; // failed - return true; - } - if (mDataSize <= mBytesToRead) - { - return true; // done - } - else - { - mFileHandle = LLLFSThread::nullHandle(); - mState = BODY; - } - } - else - { - return false; - } - } -#else - llassert_always(idx >= 0); - llassert_always(mOffset < TEXTURE_CACHE_ENTRY_SIZE); - S32 offset = idx * TEXTURE_CACHE_ENTRY_SIZE + mOffset; - S32 size = TEXTURE_CACHE_ENTRY_SIZE - mOffset; - S32 bytes_written = ll_apr_file_write_ex(mCache->mHeaderDataFileName, mCache->getFileAPRPool(), - mWriteData, offset, size); - - if (bytes_written <= 0) - { - llwarns << "LLTextureCacheWorker: missing entry: " << mID << llendl; - mDataSize = -1; // failed - return true; - } - - if (mDataSize <= size) - { - return true; // done - } - else - { - mState = BODY; - } -#endif - } - - if (mState == BODY) - { -#if USE_LFS_WRITE - if (mFileHandle == LLLFSThread::nullHandle()) - { - S32 data_offset = TEXTURE_CACHE_ENTRY_SIZE - mOffset; - data_offset = llmax(data_offset, 0); - S32 file_size = mDataSize - data_offset; - S32 file_offset = mOffset - TEXTURE_CACHE_ENTRY_SIZE; - file_offset = llmax(file_offset, 0); - if (file_size > 0 && mCache->appendToTextureEntryList(mID, file_size)) - { - std::string filename = mCache->getTextureFileName(mID); - mBytesRead = -1; - mBytesToRead = file_size; - setPriority(LLWorkerThread::PRIORITY_LOW | mPriority); - mFileHandle = LLLFSThread::sLocal->write(filename, - mWriteData + data_offset, file_offset, mBytesToRead, - new WriteResponder(mCache, mRequestHandle)); - return false; - } - else - { - mDataSize = 0; // no data written - return true; // done - } - } - else - { - if (mBytesRead >= 0) - { - if (mBytesRead != mBytesToRead) - { - llwarns << "LLTextureCacheWorker: " << mID - << " incorrect number of bytes written to body: " << mBytesRead - << " != " << mBytesToRead << llendl; - mDataSize = -1; // failed - } - return true; - } - else - { - return false; - } - } -#else - S32 data_offset = TEXTURE_CACHE_ENTRY_SIZE - mOffset; - data_offset = llmax(data_offset, 0); - S32 file_size = mDataSize - data_offset; - S32 file_offset = mOffset - TEXTURE_CACHE_ENTRY_SIZE; - file_offset = llmax(file_offset, 0); - S32 bytes_written = 0; - if (file_size > 0 && mCache->appendToTextureEntryList(mID, file_size)) - { - std::string filename = mCache->getTextureFileName(mID); - bytes_written = ll_apr_file_write_ex(filename, mCache->getFileAPRPool(), - mWriteData + data_offset, - file_offset, file_size); - if (bytes_written <= 0) - { - mDataSize = -1; // failed - } - } - else - { - mDataSize = 0; // no data written - } - - return true; -#endif - } - - return false; -} - -//virtual -bool LLTextureCacheWorker::doWork(S32 param) -{ - bool res = false; - if (param == 0) // read - { - res = doRead(); - } - else if (param == 1) // write - { - res = doWrite(); - } - else - { - llassert_always(0); - } - return res; -} - -//virtual (WORKER THREAD) -void LLTextureCacheWorker::finishWork(S32 param, bool completed) -{ - if (mResponder.notNull()) - { - bool success = (completed && mDataSize > 0); - if (param == 0) - { - // read - if (success) - { - mResponder->setData(mReadData, mDataSize, mImageSize, mImageFormat, mImageLocal); - mReadData = NULL; // responder owns data - mDataSize = 0; - } - else - { - delete[] mReadData; - mReadData = NULL; - - } - } - else - { - // write - mWriteData = NULL; // we never owned data - mDataSize = 0; - } - mResponder->completed(success); - } -} - -//virtual (MAIN THREAD) -void LLTextureCacheWorker::endWork(S32 param, bool aborted) -{ - if (aborted) - { - // Let the destructor handle any cleanup - return; - } - switch(param) - { - default: - case 0: // read - case 1: // write - { - if (mDataSize < 0) - { - // failed - mCache->removeFromCache(mID); - } - break; - } - } -} - -////////////////////////////////////////////////////////////////////////////// - -LLTextureCache::LLTextureCache(bool threaded) - : LLWorkerThread("TextureCache", threaded), - mWorkersMutex(getAPRPool()), - mHeaderMutex(getAPRPool()), - mFileAPRPool(NULL), - mReadOnly(FALSE), - mTexturesSizeTotal(0), - mDoPurge(FALSE) -{ - apr_pool_create(&mFileAPRPool, NULL); -} - -LLTextureCache::~LLTextureCache() -{ - apr_pool_destroy(mFileAPRPool); -} - -////////////////////////////////////////////////////////////////////////////// - -//virtual -S32 LLTextureCache::update(U32 max_time_ms) -{ - S32 res; - res = LLWorkerThread::update(max_time_ms); - - lockWorkers(); - for (std::vector::iterator iter1 = mPrioritizeWriteList.begin(); - iter1 != mPrioritizeWriteList.end(); ++iter1) - { - handle_t handle = *iter1; - handle_map_t::iterator iter2 = mWriters.find(handle); - if(iter2 != mWriters.end()) - { - LLTextureCacheWorker* worker = iter2->second; - worker->setPriority(LLWorkerThread::PRIORITY_HIGH | worker->mPriority); - } - } - mPrioritizeWriteList.clear(); - unlockWorkers(); - return res; -} - -////////////////////////////////////////////////////////////////////////////// - -std::string LLTextureCache::getLocalFileName(const LLUUID& id) -{ - // Does not include extension - std::string idstr = id.asString(); - std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_SKINS, "textures", idstr); - return filename; -} - -std::string LLTextureCache::getTextureFileName(const LLUUID& id) -{ - std::string idstr = id.asString(); - std::string delem = gDirUtilp->getDirDelimiter(); - std::string filename = mTexturesDirName + delem + idstr[0] + delem + idstr; - return filename; -} - -bool LLTextureCache::appendToTextureEntryList(const LLUUID& id, S32 bodysize) -{ - bool res = false; - bool purge = false; - // Append UUID to end of texture entries - { - LLMutexLock lock(&mHeaderMutex); - size_map_t::iterator iter = mTexturesSizeMap.find(id); - if (iter == mTexturesSizeMap.end() || iter->second < bodysize) - { - llassert_always(bodysize > 0); - Entry* entry = new Entry(id, bodysize, time(NULL)); - ll_apr_file_write_ex(mTexturesDirEntriesFileName, getFileAPRPool(), - (U8*)entry, -1, 1*sizeof(Entry)); - delete entry; - if (iter != mTexturesSizeMap.end()) - { - mTexturesSizeTotal -= iter->second; - } - mTexturesSizeTotal += bodysize; - mTexturesSizeMap[id] = bodysize; - if (mTexturesSizeTotal > sCacheMaxTexturesSize) - { - purge = true; - } - res = true; - } - } - if (purge) - { - mDoPurge = TRUE; - } - return res; -} - -////////////////////////////////////////////////////////////////////////////// - -//static -const S32 MAX_REASONABLE_FILE_SIZE = 512*1024*1024; // 512 MB -F32 LLTextureCache::sHeaderCacheVersion = 1.0f; -U32 LLTextureCache::sCacheMaxEntries = MAX_REASONABLE_FILE_SIZE / TEXTURE_CACHE_ENTRY_SIZE; -S64 LLTextureCache::sCacheMaxTexturesSize = 0; // no limit -const char* entries_filename = "texture.entries"; -const char* cache_filename = "texture.cache"; -const char* textures_dirname = "textures"; - -void LLTextureCache::setDirNames(ELLPath location) -{ - std::string delem = gDirUtilp->getDirDelimiter(); - mHeaderEntriesFileName = gDirUtilp->getExpandedFilename(location, entries_filename); - mHeaderDataFileName = gDirUtilp->getExpandedFilename(location, cache_filename); - mTexturesDirName = gDirUtilp->getExpandedFilename(location, textures_dirname); - mTexturesDirEntriesFileName = mTexturesDirName + delem + entries_filename; -} - -void LLTextureCache::purgeCache(ELLPath location) -{ - if (!mReadOnly) - { - setDirNames(location); - - ll_apr_file_remove(mHeaderEntriesFileName, NULL); - ll_apr_file_remove(mHeaderDataFileName, NULL); - } - purgeAllTextures(true); -} - -S64 LLTextureCache::initCache(ELLPath location, S64 max_size, BOOL read_only) -{ - mReadOnly = read_only; - - S64 header_size = (max_size * 2) / 10; - S64 max_entries = header_size / TEXTURE_CACHE_ENTRY_SIZE; - sCacheMaxEntries = (S32)(llmin((S64)sCacheMaxEntries, max_entries)); - header_size = sCacheMaxEntries * TEXTURE_CACHE_ENTRY_SIZE; - max_size -= header_size; - if (sCacheMaxTexturesSize > 0) - sCacheMaxTexturesSize = llmin(sCacheMaxTexturesSize, max_size); - else - sCacheMaxTexturesSize = max_size; - max_size -= sCacheMaxTexturesSize; - - llinfos << "TEXTURE CACHE: Headers: " << sCacheMaxEntries - << " Textures size: " << sCacheMaxTexturesSize/(1024*1024) << " MB" << llendl; - - setDirNames(location); - - if (!mReadOnly) - { - LLFile::mkdir(mTexturesDirName.c_str()); - const char* subdirs = "0123456789abcdef"; - for (S32 i=0; i<16; i++) - { - std::string dirname = mTexturesDirName + gDirUtilp->getDirDelimiter() + subdirs[i]; - LLFile::mkdir(dirname.c_str()); - } - } - readHeaderCache(); - purgeTextures(true); // calc mTexturesSize and make some room in the texture cache if we need it - - return max_size; // unused cache space -} - -struct lru_data -{ - lru_data(U32 t, S32 i, const LLUUID& id) { time=t; index=i; uuid=id; } - U32 time; - S32 index; - LLUUID uuid; - struct Compare - { - // lhs < rhs - typedef const lru_data* lru_data_ptr; - bool operator()(const lru_data_ptr& a, const lru_data_ptr& b) const - { - if (!(a->time < b->time)) - return true; - else if (!(b->time < a->time)) - return false; - else - return a->index < b->index; - } - }; -}; - -// Called from either the main thread or the worker thread -void LLTextureCache::readHeaderCache(apr_pool_t* poolp) -{ - LLMutexLock lock(&mHeaderMutex); - mHeaderEntriesInfo.mVersion = 0.f; - mHeaderEntriesInfo.mEntries = 0; - if (ll_apr_file_exists(mHeaderEntriesFileName, poolp)) - { - ll_apr_file_read_ex(mHeaderEntriesFileName, poolp, - (U8*)&mHeaderEntriesInfo, 0, sizeof(EntriesInfo)); - } - if (mHeaderEntriesInfo.mVersion != sHeaderCacheVersion) - { - if (!mReadOnly) - { - // Info with 0 entries - mHeaderEntriesInfo.mVersion = sHeaderCacheVersion; - ll_apr_file_write_ex(mHeaderEntriesFileName, poolp, - (U8*)&mHeaderEntriesInfo, 0, sizeof(EntriesInfo)); - } - } - else - { - S32 num_entries = mHeaderEntriesInfo.mEntries; - if (num_entries) - { - Entry* entries = new Entry[num_entries]; - ll_apr_file_read_ex(mHeaderEntriesFileName, poolp, - (U8*)entries, sizeof(EntriesInfo), num_entries*sizeof(Entry)); - typedef std::set lru_set_t; - lru_set_t lru; - for (S32 i=0; i= 0) // -1 indicates erased entry, skip - { - const LLUUID& id = entries[i].mID; - lru.insert(new lru_data(entries[i].mTime, i, id)); - mHeaderIDMap[id] = i; - } - } - mLRU.clear(); - S32 lru_entries = sCacheMaxEntries / 10; - for (lru_set_t::iterator iter = lru.begin(); iter != lru.end(); ++iter) - { - lru_data* data = *iter; - mLRU[data->index] = data->uuid; - if (--lru_entries <= 0) - break; - } - for_each(lru.begin(), lru.end(), DeletePointer()); - delete[] entries; - } - } -} - -////////////////////////////////////////////////////////////////////////////// - -void LLTextureCache::purgeAllTextures(bool purge_directories) -{ - if (!mReadOnly) - { - const char* subdirs = "0123456789abcdef"; - std::string delem = gDirUtilp->getDirDelimiter(); - std::string mask = delem + "*"; - for (S32 i=0; i<16; i++) - { - std::string dirname = mTexturesDirName + delem + subdirs[i]; - gDirUtilp->deleteFilesInDir(dirname.c_str(),mask); - if (purge_directories) - { - LLFile::rmdir(dirname.c_str()); - } - } - ll_apr_file_remove(mTexturesDirEntriesFileName, NULL); - if (purge_directories) - { - LLFile::rmdir(mTexturesDirName.c_str()); - } - } - mTexturesSizeMap.clear(); -} - -void LLTextureCache::purgeTextures(bool validate) -{ - if (mReadOnly) - { - return; - } - - LLMutexLock lock(&mHeaderMutex); - - S32 filesize = ll_apr_file_size(mTexturesDirEntriesFileName, NULL); - S32 num_entries = filesize / sizeof(Entry); - if (num_entries * sizeof(Entry) != filesize) - { - llwarns << "Bad cache file: " << mTexturesDirEntriesFileName << " Purging." << llendl; - purgeAllTextures(false); - return; - } - if (num_entries == 0) - { - return; // nothing to do - } - - Entry* entries = new Entry[num_entries]; - S32 bytes_read = ll_apr_file_read_ex(mTexturesDirEntriesFileName, NULL, - (U8*)entries, 0, num_entries*sizeof(Entry)); - if (bytes_read != filesize) - { - llwarns << "Bad cache file (2): " << mTexturesDirEntriesFileName << " Purging." << llendl; - purgeAllTextures(false); - return; - } - - llinfos << "TEXTURE CACHE: Reading Entries..." << llendl; - - std::map entry_idx_map; - S64 total_size = 0; - for (S32 idx=0; idx::iterator iter = entry_idx_map.find(id); - if (iter != entry_idx_map.end()) - { - // Newer entry replacing older entry - S32 pidx = iter->second; - total_size -= entries[pidx].mSize; - entries[pidx].mSize = 0; // flag: skip older entry - } - entry_idx_map[id] = idx; - total_size += entries[idx].mSize; - } - - U32 validate_idx = 0; - if (validate) - { - validate_idx = gSavedSettings.getU32("CacheValidateCounter"); - U32 next_idx = (++validate_idx) % 256; - gSavedSettings.setU32("CacheValidateCounter", next_idx); - llinfos << "TEXTURE CACHE: Validating: " << validate_idx << llendl; - } - - S64 min_cache_size = (sCacheMaxTexturesSize * 9) / 10; - S32 purge_count = 0; - S32 next_idx = 0; - for (S32 idx=0; idx= min_cache_size) - { - purge_entry = true; - } - else if (validate) - { - // make sure file exists and is the correct size - S32 uuididx = entries[idx].mID.mData[0]; - if (uuididx == validate_idx) - { -// llinfos << "Validating: " << filename << "Size: " << entries[idx].mSize << llendl; - S32 bodysize = ll_apr_file_size(filename, NULL); - if (bodysize != entries[idx].mSize) - { - llwarns << "TEXTURE CACHE BODY HAS BAD SIZE: " << bodysize << " != " << entries[idx].mSize - << filename << llendl; - purge_entry = true; - } - } - } - if (purge_entry) - { - purge_count++; -// llinfos << "PURGING: " << filename << llendl; - ll_apr_file_remove(filename, NULL); - total_size -= entries[idx].mSize; - entries[idx].mSize = 0; - } - else - { - if (next_idx != idx) - { - entries[next_idx] = entries[idx]; - } - ++next_idx; - } - } - num_entries = next_idx; - - llinfos << "TEXTURE CACHE: Writing Entries: " << num_entries << llendl; - - ll_apr_file_remove(mTexturesDirEntriesFileName, NULL); - ll_apr_file_write_ex(mTexturesDirEntriesFileName, NULL, - (U8*)&entries[0], 0, num_entries*sizeof(Entry)); - - mTexturesSizeTotal = 0; - mTexturesSizeMap.clear(); - for (S32 idx=0; idxsecond; - } - return res; -} - -LLTextureCacheWorker* LLTextureCache::getWriter(handle_t handle) -{ - LLTextureCacheWorker* res = NULL; - handle_map_t::iterator iter = mWriters.find(handle); - if (iter != mWriters.end()) - { - res = iter->second; - } - return res; -} - -////////////////////////////////////////////////////////////////////////////// - -// Called from work thread -S32 LLTextureCache::getHeaderCacheEntry(const LLUUID& id, bool touch, S32* imagesize) -{ - bool retry = false; - S32 idx = -1; - - { - LLMutexLock lock(&mHeaderMutex); - id_map_t::iterator iter = mHeaderIDMap.find(id); - if (iter != mHeaderIDMap.end()) - { - idx = iter->second; - } - else if (touch && !mReadOnly) - { - if (mHeaderEntriesInfo.mEntries < sCacheMaxEntries) - { - // Add an entry - idx = mHeaderEntriesInfo.mEntries++; - mHeaderIDMap[id] = idx; - // Update Info - ll_apr_file_write_ex(mHeaderEntriesFileName, getFileAPRPool(), - (U8*)&mHeaderEntriesInfo, 0, sizeof(EntriesInfo)); - } - else if (!mLRU.empty()) - { - idx = mLRU.begin()->first; // will be erased below - const LLUUID& oldid = mLRU.begin()->second; - mHeaderIDMap.erase(oldid); - mTexturesSizeMap.erase(oldid); - mHeaderIDMap[id] = idx; - } - else - { - idx = -1; - retry = true; - } - } - if (idx >= 0) - { - if (touch && !mReadOnly) - { - // Update the lru entry - mLRU.erase(idx); - llassert_always(imagesize && *imagesize > 0); - Entry* entry = new Entry(id, *imagesize, time(NULL)); - S32 offset = sizeof(EntriesInfo) + idx * sizeof(Entry); - ll_apr_file_write_ex(mHeaderEntriesFileName, getFileAPRPool(), - (U8*)entry, offset, sizeof(Entry)); - delete entry; - } - else if (imagesize) - { - // Get the image size - Entry entry; - S32 offset = sizeof(EntriesInfo) + idx * sizeof(Entry); - ll_apr_file_read_ex(mHeaderEntriesFileName, getFileAPRPool(), - (U8*)&entry, offset, sizeof(Entry)); - *imagesize = entry.mSize; - } - } - } - if (retry) - { - readHeaderCache(getFileAPRPool()); // updates the lru - llassert_always(!mLRU.empty() || mHeaderEntriesInfo.mEntries < sCacheMaxEntries); - idx = getHeaderCacheEntry(id, touch, imagesize); // assert above ensures no inf. recursion - } - return idx; -} - -////////////////////////////////////////////////////////////////////////////// - -// Calls from texture pipeline thread (i.e. LLTextureFetch) - -LLTextureCache::handle_t LLTextureCache::readFromCache(const LLUUID& id, U32 priority, - S32 offset, S32 size, ReadResponder* responder) -{ - // Note: checking to see if an entry exists can cause a stall, - // so let the thread handle it - LLMutexLock lock(&mWorkersMutex); - LLTextureCacheWorker* worker = new LLTextureCacheWorker(this, priority, id, - NULL, size, offset, 0, - responder); - handle_t handle = worker->read(); - mReaders[handle] = worker; - return handle; -} - -bool LLTextureCache::readComplete(handle_t handle, bool abort) -{ - lockWorkers(); - handle_map_t::iterator iter = mReaders.find(handle); - llassert_always(iter != mReaders.end()); - LLTextureCacheWorker* worker = iter->second; - bool res = worker->complete(); - if (res || abort) - { - mReaders.erase(handle); - unlockWorkers(); - worker->scheduleDelete(); - return true; - } - else - { - unlockWorkers(); - return false; - } -} - -LLTextureCache::handle_t LLTextureCache::writeToCache(const LLUUID& id, U32 priority, - U8* data, S32 datasize, S32 imagesize, - WriteResponder* responder) -{ - if (mReadOnly) - { - return LLWorkerThread::nullHandle(); - } - if (mDoPurge) - { - // NOTE: This may cause an occasional hiccup, - // but it really needs to be done on the control thread - // (i.e. here) - purgeTextures(false); - mDoPurge = FALSE; - } - if (datasize >= TEXTURE_CACHE_ENTRY_SIZE) - { - LLMutexLock lock(&mWorkersMutex); - llassert_always(imagesize > 0); - LLTextureCacheWorker* worker = new LLTextureCacheWorker(this, priority, id, - data, datasize, 0, - imagesize, responder); - handle_t handle = worker->write(); - mWriters[handle] = worker; - return handle; - } - return LLWorkerThread::nullHandle(); -} - -bool LLTextureCache::writeComplete(handle_t handle, bool abort) -{ - lockWorkers(); - handle_map_t::iterator iter = mWriters.find(handle); - llassert_always(iter != mWriters.end()); - LLTextureCacheWorker* worker = iter->second; - if (worker->complete() || abort) - { - mWriters.erase(handle); - unlockWorkers(); - worker->scheduleDelete(); - return true; - } - else - { - unlockWorkers(); - return false; - } -} - -void LLTextureCache::prioritizeWrite(handle_t handle) -{ - // Don't prioritize yet, we might be working on this now - // which could create a deadlock - mPrioritizeWriteList.push_back(handle); -} - -////////////////////////////////////////////////////////////////////////////// - -// Called from MAIN thread (endWork()) - -bool LLTextureCache::removeHeaderCacheEntry(const LLUUID& id) -{ - if (mReadOnly) - { - return false; - } - LLMutexLock lock(&mHeaderMutex); - id_map_t::iterator iter = mHeaderIDMap.find(id); - if (iter != mHeaderIDMap.end()) - { - S32 idx = iter->second; - if (idx >= 0) - { - Entry* entry = new Entry(id, -1, time(NULL)); - S32 offset = sizeof(EntriesInfo) + idx * sizeof(Entry); - ll_apr_file_write_ex(mHeaderEntriesFileName, NULL, - (U8*)entry, offset, sizeof(Entry)); - delete entry; - mLRU[idx] = id; - mHeaderIDMap.erase(id); - mTexturesSizeMap.erase(id); - return true; - } - } - return false; -} - -void LLTextureCache::removeFromCache(const LLUUID& id) -{ - llwarns << "Removing texture from cache: " << id << llendl; - if (!mReadOnly) - { - removeHeaderCacheEntry(id); - ll_apr_file_remove(getTextureFileName(id), NULL); - } -} - -////////////////////////////////////////////////////////////////////////////// - -LLTextureCache::ReadResponder::ReadResponder() - : mImageSize(0), - mImageLocal(FALSE) -{ -} - -void LLTextureCache::ReadResponder::setData(U8* data, S32 datasize, S32 imagesize, S32 imageformat, BOOL imagelocal) -{ - if (mFormattedImage.notNull()) - { - llassert_always(mFormattedImage->getCodec() == imageformat); - mFormattedImage->appendData(data, datasize); - } - else - { - mFormattedImage = LLImageFormatted::createFromType(imageformat); - mFormattedImage->setData(data,datasize); - } - mImageSize = imagesize; - mImageLocal = imagelocal; -} - -////////////////////////////////////////////////////////////////////////////// +/** + * @file texturecache.cpp + * @brief Object which handles local texture caching + * + * Copyright (c) 2000-$CurrentYear$, Linden Research, Inc. + * $License$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "lltexturecache.h" + +#include "llapr.h" +#include "lldir.h" +#include "llimage.h" +#include "lllfsthread.h" +#include "llviewercontrol.h" + +#define USE_LFS_READ 0 +#define USE_LFS_WRITE 0 + +// Note: first 4 bytes store file size, rest is j2c data +const S32 TEXTURE_CACHE_ENTRY_SIZE = FIRST_PACKET_SIZE; //1024; + +class LLTextureCacheWorker : public LLWorkerClass +{ + friend class LLTextureCache; + +private: + enum e_state + { + INIT = 0, + LOCAL = 1, + CACHE = 2, + HEADER = 3, + BODY = 4 + }; + + class ReadResponder : public LLLFSThread::Responder + { + public: + ReadResponder(LLTextureCache* cache, handle_t handle) : mCache(cache), mHandle(handle) {} + ~ReadResponder() {} + void completed(S32 bytes) + { + mCache->lockWorkers(); + LLTextureCacheWorker* reader = mCache->getReader(mHandle); + if (reader) reader->ioComplete(bytes); + mCache->unlockWorkers(); + } + LLTextureCache* mCache; + LLTextureCacheWorker::handle_t mHandle; + }; + + class WriteResponder : public LLLFSThread::Responder + { + public: + WriteResponder(LLTextureCache* cache, handle_t handle) : mCache(cache), mHandle(handle) {} + ~WriteResponder() {} + void completed(S32 bytes) + { + mCache->lockWorkers(); + LLTextureCacheWorker* writer = mCache->getWriter(mHandle); + if (writer) writer->ioComplete(bytes); + mCache->unlockWorkers(); + } + LLTextureCache* mCache; + LLTextureCacheWorker::handle_t mHandle; + }; + +public: + LLTextureCacheWorker(LLTextureCache* cache, U32 priority, const LLUUID& id, + U8* data, S32 datasize, S32 offset, + S32 imagesize, // for writes + LLTextureCache::Responder* responder) + : LLWorkerClass(cache, "LLTextureCacheWorker"), + mCache(cache), + mPriority(priority), + mID(id), + mState(INIT), + mReadData(NULL), + mWriteData(data), + mDataSize(datasize), + mOffset(offset), + mImageSize(imagesize), + mImageFormat(IMG_CODEC_J2C), + mImageLocal(FALSE), + mResponder(responder), + mFileHandle(LLLFSThread::nullHandle()), + mBytesToRead(0), + mBytesRead(0) + { + mPriority &= LLWorkerThread::PRIORITY_LOWBITS; + } + ~LLTextureCacheWorker() + { + llassert_always(!haveWork()); + delete[] mReadData; + } + + bool doRead(); + bool doWrite(); + virtual bool doWork(S32 param); // Called from LLWorkerThread::processRequest() + + handle_t read() { addWork(0, LLWorkerThread::PRIORITY_HIGH | mPriority); return mRequestHandle; } + handle_t write() { addWork(1, LLWorkerThread::PRIORITY_HIGH | mPriority); return mRequestHandle; } + bool complete() { return checkWork(); } + void ioComplete(S32 bytes) + { + mBytesRead = bytes; + setPriority(LLWorkerThread::PRIORITY_HIGH | mPriority); + } + +private: + virtual void startWork(S32 param); // called from addWork() (MAIN THREAD) + virtual void finishWork(S32 param, bool completed); // called from finishRequest() (WORK THREAD) + virtual void endWork(S32 param, bool aborted); // called from doWork() (MAIN THREAD) + +private: + LLTextureCache* mCache; + U32 mPriority; + LLUUID mID; + e_state mState; + + U8* mReadData; + U8* mWriteData; + S32 mDataSize; + S32 mOffset; + S32 mImageSize; + S32 mImageFormat; + BOOL mImageLocal; + LLPointer mResponder; + LLLFSThread::handle_t mFileHandle; + S32 mBytesToRead; + LLAtomicS32 mBytesRead; +}; + +//virtual +void LLTextureCacheWorker::startWork(S32 param) +{ +} + +bool LLTextureCacheWorker::doRead() +{ + S32 local_size = 0; + std::string local_filename; + + if (mState == INIT) + { + std::string filename = mCache->getLocalFileName(mID); + local_filename = filename + ".j2c"; + local_size = ll_apr_file_size(local_filename, mCache->getFileAPRPool()); + if (local_size == 0) + { + local_filename = filename + ".tga"; + local_size = ll_apr_file_size(local_filename, mCache->getFileAPRPool()); + if (local_size > 0) + { + mImageFormat = IMG_CODEC_TGA; + mDataSize = local_size; // Only a complete .tga file is valid + } + } + if (local_size > 0) + { + mState = LOCAL; + } + else + { + mState = CACHE; + } + } + + if (mState == LOCAL) + { +#if USE_LFS_READ + if (mFileHandle == LLLFSThread::nullHandle()) + { + mImageLocal = TRUE; + mImageSize = local_size; + if (!mDataSize || mDataSize + mOffset > local_size) + { + mDataSize = local_size - mOffset; + } + if (mDataSize <= 0) + { + // no more data to read + mDataSize = 0; + return true; + } + mReadData = new U8[mDataSize]; + mBytesRead = -1; + mBytesToRead = mDataSize; + setPriority(LLWorkerThread::PRIORITY_LOW | mPriority); + mFileHandle = LLLFSThread::sLocal->read(local_filename, mReadData, mOffset, mDataSize, + new ReadResponder(mCache, mRequestHandle)); + return false; + } + else + { + if (mBytesRead >= 0) + { + if (mBytesRead != mBytesToRead) + { + llwarns << "Error reading file from local cache: " << local_filename + << " Bytes: " << mDataSize << " Offset: " << mOffset + << " / " << mDataSize << llendl; + mDataSize = 0; // failed + delete[] mReadData; + mReadData = NULL; + } + return true; + } + else + { + return false; + } + } +#else + if (!mDataSize || mDataSize > local_size) + { + mDataSize = local_size; + } + mReadData = new U8[mDataSize]; + S32 bytes_read = ll_apr_file_read_ex(local_filename, mCache->getFileAPRPool(), + mReadData, mOffset, mDataSize); + if (bytes_read != mDataSize) + { + llwarns << "Error reading file from local cache: " << local_filename + << " Bytes: " << mDataSize << " Offset: " << mOffset + << " / " << mDataSize << llendl; + mDataSize = 0; + delete[] mReadData; + mReadData = NULL; + } + else + { + mImageSize = local_size; + mImageLocal = TRUE; + } + return true; +#endif + } + + S32 idx = -1; + + if (mState == CACHE) + { + llassert_always(mImageSize == 0); + idx = mCache->getHeaderCacheEntry(mID, false, &mImageSize); + if (idx >= 0 && mImageSize > mOffset) + { + llassert_always(mImageSize > 0); + if (!mDataSize || mDataSize > mImageSize) + { + mDataSize = mImageSize; + } + mState = mOffset < TEXTURE_CACHE_ENTRY_SIZE ? HEADER : BODY; + } + else + { + mDataSize = 0; // no data + return true; + } + } + + if (mState == HEADER) + { +#if USE_LFS_READ + if (mFileHandle == LLLFSThread::nullHandle()) + { + llassert_always(idx >= 0); + llassert_always(mOffset < TEXTURE_CACHE_ENTRY_SIZE); + S32 offset = idx * TEXTURE_CACHE_ENTRY_SIZE + mOffset; + S32 size = TEXTURE_CACHE_ENTRY_SIZE - mOffset; + llassert_always(mReadData == NULL); + mReadData = new U8[size]; + mBytesRead = -1; + mBytesToRead = size; + setPriority(LLWorkerThread::PRIORITY_LOW | mPriority); + mFileHandle = LLLFSThread::sLocal->read(mCache->mHeaderDataFileName, + mReadData, offset, mBytesToRead, + new ReadResponder(mCache, mRequestHandle)); + return false; + } + else + { + if (mBytesRead >= 0) + { + if (mBytesRead != mBytesToRead) + { + llwarns << "LLTextureCacheWorker: " << mID + << " incorrect number of bytes read from header: " << mBytesRead + << " != " << mBytesToRead << llendl; + mDataSize = -1; // failed + return true; + } + if (mDataSize <= TEXTURE_CACHE_ENTRY_SIZE) + { + return true; // done + } + else + { + mFileHandle = LLLFSThread::nullHandle(); + mState = BODY; + } + } + else + { + return false; + } + } +#else + llassert_always(idx >= 0); + llassert_always(mOffset < TEXTURE_CACHE_ENTRY_SIZE); + S32 offset = idx * TEXTURE_CACHE_ENTRY_SIZE + mOffset; + S32 size = TEXTURE_CACHE_ENTRY_SIZE - mOffset; + mReadData = new U8[size]; + S32 bytes_read = ll_apr_file_read_ex(mCache->mHeaderDataFileName, mCache->getFileAPRPool(), + mReadData, offset, size); + if (bytes_read != size) + { + llwarns << "LLTextureCacheWorker: " << mID + << " incorrect number of bytes read from header: " << bytes_read + << " / " << size << llendl; + mDataSize = -1; // failed + return true; + } + if (mDataSize <= TEXTURE_CACHE_ENTRY_SIZE) + { + return true; // done + } + else + { + mState = BODY; + } +#endif + } + + if (mState == BODY) + { +#if USE_LFS_READ + if (mFileHandle == LLLFSThread::nullHandle()) + { + std::string filename = mCache->getTextureFileName(mID); + S32 filesize = ll_apr_file_size(filename, mCache->getFileAPRPool()); + if (filesize > mOffset) + { + S32 datasize = TEXTURE_CACHE_ENTRY_SIZE + filesize; + mDataSize = llmin(datasize, mDataSize); + S32 data_offset = TEXTURE_CACHE_ENTRY_SIZE - mOffset; + data_offset = llmax(data_offset, 0); + S32 file_size = mDataSize - data_offset; + S32 file_offset = mOffset - TEXTURE_CACHE_ENTRY_SIZE; + file_offset = llmax(file_offset, 0); + + llassert_always(mDataSize > 0); + U8* data = new U8[mDataSize]; + if (data_offset > 0) + { + llassert_always(mReadData); + llassert_always(data_offset <= mDataSize); + memcpy(data, mReadData, data_offset); + delete[] mReadData; + mReadData = NULL; + } + llassert_always(mReadData == NULL); + mReadData = data; + + mBytesRead = -1; + mBytesToRead = file_size; + setPriority(LLWorkerThread::PRIORITY_LOW | mPriority); + llassert_always(data_offset + mBytesToRead <= mDataSize); + mFileHandle = LLLFSThread::sLocal->read(filename, + mReadData + data_offset, file_offset, mBytesToRead, + new ReadResponder(mCache, mRequestHandle)); + return false; + } + else + { + mDataSize = TEXTURE_CACHE_ENTRY_SIZE; + return true; // done + } + } + else + { + if (mBytesRead >= 0) + { + if (mBytesRead != mBytesToRead) + { + llwarns << "LLTextureCacheWorker: " << mID + << " incorrect number of bytes read from body: " << mBytesRead + << " != " << mBytesToRead << llendl; + mDataSize = -1; // failed + } + return true; + } + else + { + return false; + } + } +#else + std::string filename = mCache->getTextureFileName(mID); + S32 filesize = ll_apr_file_size(filename, mCache->getFileAPRPool()); + S32 bytes_read = 0; + if (filesize > mOffset) + { + S32 datasize = TEXTURE_CACHE_ENTRY_SIZE + filesize; + mDataSize = llmin(datasize, mDataSize); + S32 data_offset = TEXTURE_CACHE_ENTRY_SIZE - mOffset; + data_offset = llmax(data_offset, 0); + S32 file_size = mDataSize - data_offset; + S32 file_offset = mOffset - TEXTURE_CACHE_ENTRY_SIZE; + file_offset = llmax(file_offset, 0); + + U8* data = new U8[mDataSize]; + if (data_offset > 0) + { + llassert_always(mReadData); + memcpy(data, mReadData, data_offset); + delete[] mReadData; + } + mReadData = data; + bytes_read = ll_apr_file_read_ex(filename, mCache->getFileAPRPool(), + mReadData + data_offset, + file_offset, file_size); + if (bytes_read != file_size) + { + llwarns << "LLTextureCacheWorker: " << mID + << " incorrect number of bytes read from body: " << bytes_read + << " / " << file_size << llendl; + mDataSize = -1; // failed + return true; + } + } + else + { + mDataSize = TEXTURE_CACHE_ENTRY_SIZE; + } + + return true; +#endif + } + + return false; +} + +bool LLTextureCacheWorker::doWrite() +{ + S32 idx = -1; + + if (mState == INIT) + { + llassert_always(mOffset == 0); // Currently don't support offsets + mState = CACHE; + } + + // No LOCAL state for write() + + if (mState == CACHE) + { + S32 cur_imagesize = 0; + S32 offset = mOffset; + idx = mCache->getHeaderCacheEntry(mID, false, &cur_imagesize); + if (idx >= 0 && cur_imagesize > 0) + { + offset = TEXTURE_CACHE_ENTRY_SIZE; // don't re-write header + } + idx = mCache->getHeaderCacheEntry(mID, true, &mImageSize); // touch entry + if (idx >= 0) + { + llassert_always(cur_imagesize <= 0 || mImageSize == cur_imagesize); + mState = offset < TEXTURE_CACHE_ENTRY_SIZE ? HEADER : BODY; + } + else + { + mDataSize = -1; // failed + return true; + } + } + + if (mState == HEADER) + { +#if USE_LFS_WRITE + if (mFileHandle == LLLFSThread::nullHandle()) + { + llassert_always(idx >= 0); + llassert_always(mOffset < TEXTURE_CACHE_ENTRY_SIZE); + S32 offset = idx * TEXTURE_CACHE_ENTRY_SIZE + mOffset; + S32 size = TEXTURE_CACHE_ENTRY_SIZE - mOffset; + mBytesRead = -1; + mBytesToRead = size; + setPriority(LLWorkerThread::PRIORITY_LOW | mPriority); + mFileHandle = LLLFSThread::sLocal->write(mCache->mHeaderDataFileName, + mWriteData, offset, mBytesToRead, + new WriteResponder(mCache, mRequestHandle)); + return false; + } + else + { + if (mBytesRead >= 0) + { + if (mBytesRead != mBytesToRead) + { + llwarns << "LLTextureCacheWorker: " << mID + << " incorrect number of bytes written to header: " << mBytesRead + << " != " << mBytesToRead << llendl; + mDataSize = -1; // failed + return true; + } + if (mDataSize <= mBytesToRead) + { + return true; // done + } + else + { + mFileHandle = LLLFSThread::nullHandle(); + mState = BODY; + } + } + else + { + return false; + } + } +#else + llassert_always(idx >= 0); + llassert_always(mOffset < TEXTURE_CACHE_ENTRY_SIZE); + S32 offset = idx * TEXTURE_CACHE_ENTRY_SIZE + mOffset; + S32 size = TEXTURE_CACHE_ENTRY_SIZE - mOffset; + S32 bytes_written = ll_apr_file_write_ex(mCache->mHeaderDataFileName, mCache->getFileAPRPool(), + mWriteData, offset, size); + + if (bytes_written <= 0) + { + llwarns << "LLTextureCacheWorker: missing entry: " << mID << llendl; + mDataSize = -1; // failed + return true; + } + + if (mDataSize <= size) + { + return true; // done + } + else + { + mState = BODY; + } +#endif + } + + if (mState == BODY) + { +#if USE_LFS_WRITE + if (mFileHandle == LLLFSThread::nullHandle()) + { + S32 data_offset = TEXTURE_CACHE_ENTRY_SIZE - mOffset; + data_offset = llmax(data_offset, 0); + S32 file_size = mDataSize - data_offset; + S32 file_offset = mOffset - TEXTURE_CACHE_ENTRY_SIZE; + file_offset = llmax(file_offset, 0); + if (file_size > 0 && mCache->appendToTextureEntryList(mID, file_size)) + { + std::string filename = mCache->getTextureFileName(mID); + mBytesRead = -1; + mBytesToRead = file_size; + setPriority(LLWorkerThread::PRIORITY_LOW | mPriority); + mFileHandle = LLLFSThread::sLocal->write(filename, + mWriteData + data_offset, file_offset, mBytesToRead, + new WriteResponder(mCache, mRequestHandle)); + return false; + } + else + { + mDataSize = 0; // no data written + return true; // done + } + } + else + { + if (mBytesRead >= 0) + { + if (mBytesRead != mBytesToRead) + { + llwarns << "LLTextureCacheWorker: " << mID + << " incorrect number of bytes written to body: " << mBytesRead + << " != " << mBytesToRead << llendl; + mDataSize = -1; // failed + } + return true; + } + else + { + return false; + } + } +#else + S32 data_offset = TEXTURE_CACHE_ENTRY_SIZE - mOffset; + data_offset = llmax(data_offset, 0); + S32 file_size = mDataSize - data_offset; + S32 file_offset = mOffset - TEXTURE_CACHE_ENTRY_SIZE; + file_offset = llmax(file_offset, 0); + S32 bytes_written = 0; + if (file_size > 0 && mCache->appendToTextureEntryList(mID, file_size)) + { + std::string filename = mCache->getTextureFileName(mID); + bytes_written = ll_apr_file_write_ex(filename, mCache->getFileAPRPool(), + mWriteData + data_offset, + file_offset, file_size); + if (bytes_written <= 0) + { + mDataSize = -1; // failed + } + } + else + { + mDataSize = 0; // no data written + } + + return true; +#endif + } + + return false; +} + +//virtual +bool LLTextureCacheWorker::doWork(S32 param) +{ + bool res = false; + if (param == 0) // read + { + res = doRead(); + } + else if (param == 1) // write + { + res = doWrite(); + } + else + { + llassert_always(0); + } + return res; +} + +//virtual (WORKER THREAD) +void LLTextureCacheWorker::finishWork(S32 param, bool completed) +{ + if (mResponder.notNull()) + { + bool success = (completed && mDataSize > 0); + if (param == 0) + { + // read + if (success) + { + mResponder->setData(mReadData, mDataSize, mImageSize, mImageFormat, mImageLocal); + mReadData = NULL; // responder owns data + mDataSize = 0; + } + else + { + delete[] mReadData; + mReadData = NULL; + + } + } + else + { + // write + mWriteData = NULL; // we never owned data + mDataSize = 0; + } + mResponder->completed(success); + } +} + +//virtual (MAIN THREAD) +void LLTextureCacheWorker::endWork(S32 param, bool aborted) +{ + if (aborted) + { + // Let the destructor handle any cleanup + return; + } + switch(param) + { + default: + case 0: // read + case 1: // write + { + if (mDataSize < 0) + { + // failed + mCache->removeFromCache(mID); + } + break; + } + } +} + +////////////////////////////////////////////////////////////////////////////// + +LLTextureCache::LLTextureCache(bool threaded) + : LLWorkerThread("TextureCache", threaded), + mWorkersMutex(getAPRPool()), + mHeaderMutex(getAPRPool()), + mFileAPRPool(NULL), + mReadOnly(FALSE), + mTexturesSizeTotal(0), + mDoPurge(FALSE) +{ + apr_pool_create(&mFileAPRPool, NULL); +} + +LLTextureCache::~LLTextureCache() +{ + apr_pool_destroy(mFileAPRPool); +} + +////////////////////////////////////////////////////////////////////////////// + +//virtual +S32 LLTextureCache::update(U32 max_time_ms) +{ + S32 res; + res = LLWorkerThread::update(max_time_ms); + + lockWorkers(); + for (std::vector::iterator iter1 = mPrioritizeWriteList.begin(); + iter1 != mPrioritizeWriteList.end(); ++iter1) + { + handle_t handle = *iter1; + handle_map_t::iterator iter2 = mWriters.find(handle); + if(iter2 != mWriters.end()) + { + LLTextureCacheWorker* worker = iter2->second; + worker->setPriority(LLWorkerThread::PRIORITY_HIGH | worker->mPriority); + } + } + mPrioritizeWriteList.clear(); + unlockWorkers(); + return res; +} + +////////////////////////////////////////////////////////////////////////////// + +std::string LLTextureCache::getLocalFileName(const LLUUID& id) +{ + // Does not include extension + std::string idstr = id.asString(); + std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_SKINS, "textures", idstr); + return filename; +} + +std::string LLTextureCache::getTextureFileName(const LLUUID& id) +{ + std::string idstr = id.asString(); + std::string delem = gDirUtilp->getDirDelimiter(); + std::string filename = mTexturesDirName + delem + idstr[0] + delem + idstr; + return filename; +} + +bool LLTextureCache::appendToTextureEntryList(const LLUUID& id, S32 bodysize) +{ + bool res = false; + bool purge = false; + // Append UUID to end of texture entries + { + LLMutexLock lock(&mHeaderMutex); + size_map_t::iterator iter = mTexturesSizeMap.find(id); + if (iter == mTexturesSizeMap.end() || iter->second < bodysize) + { + llassert_always(bodysize > 0); + Entry* entry = new Entry(id, bodysize, time(NULL)); + ll_apr_file_write_ex(mTexturesDirEntriesFileName, getFileAPRPool(), + (U8*)entry, -1, 1*sizeof(Entry)); + delete entry; + if (iter != mTexturesSizeMap.end()) + { + mTexturesSizeTotal -= iter->second; + } + mTexturesSizeTotal += bodysize; + mTexturesSizeMap[id] = bodysize; + if (mTexturesSizeTotal > sCacheMaxTexturesSize) + { + purge = true; + } + res = true; + } + } + if (purge) + { + mDoPurge = TRUE; + } + return res; +} + +////////////////////////////////////////////////////////////////////////////// + +//static +const S32 MAX_REASONABLE_FILE_SIZE = 512*1024*1024; // 512 MB +F32 LLTextureCache::sHeaderCacheVersion = 1.0f; +U32 LLTextureCache::sCacheMaxEntries = MAX_REASONABLE_FILE_SIZE / TEXTURE_CACHE_ENTRY_SIZE; +S64 LLTextureCache::sCacheMaxTexturesSize = 0; // no limit +const char* entries_filename = "texture.entries"; +const char* cache_filename = "texture.cache"; +const char* textures_dirname = "textures"; + +void LLTextureCache::setDirNames(ELLPath location) +{ + std::string delem = gDirUtilp->getDirDelimiter(); + mHeaderEntriesFileName = gDirUtilp->getExpandedFilename(location, entries_filename); + mHeaderDataFileName = gDirUtilp->getExpandedFilename(location, cache_filename); + mTexturesDirName = gDirUtilp->getExpandedFilename(location, textures_dirname); + mTexturesDirEntriesFileName = mTexturesDirName + delem + entries_filename; +} + +void LLTextureCache::purgeCache(ELLPath location) +{ + if (!mReadOnly) + { + setDirNames(location); + + ll_apr_file_remove(mHeaderEntriesFileName, NULL); + ll_apr_file_remove(mHeaderDataFileName, NULL); + } + purgeAllTextures(true); +} + +S64 LLTextureCache::initCache(ELLPath location, S64 max_size, BOOL read_only) +{ + mReadOnly = read_only; + + S64 header_size = (max_size * 2) / 10; + S64 max_entries = header_size / TEXTURE_CACHE_ENTRY_SIZE; + sCacheMaxEntries = (S32)(llmin((S64)sCacheMaxEntries, max_entries)); + header_size = sCacheMaxEntries * TEXTURE_CACHE_ENTRY_SIZE; + max_size -= header_size; + if (sCacheMaxTexturesSize > 0) + sCacheMaxTexturesSize = llmin(sCacheMaxTexturesSize, max_size); + else + sCacheMaxTexturesSize = max_size; + max_size -= sCacheMaxTexturesSize; + + llinfos << "TEXTURE CACHE: Headers: " << sCacheMaxEntries + << " Textures size: " << sCacheMaxTexturesSize/(1024*1024) << " MB" << llendl; + + setDirNames(location); + + if (!mReadOnly) + { + LLFile::mkdir(mTexturesDirName.c_str()); + const char* subdirs = "0123456789abcdef"; + for (S32 i=0; i<16; i++) + { + std::string dirname = mTexturesDirName + gDirUtilp->getDirDelimiter() + subdirs[i]; + LLFile::mkdir(dirname.c_str()); + } + } + readHeaderCache(); + purgeTextures(true); // calc mTexturesSize and make some room in the texture cache if we need it + + return max_size; // unused cache space +} + +struct lru_data +{ + lru_data(U32 t, S32 i, const LLUUID& id) { time=t; index=i; uuid=id; } + U32 time; + S32 index; + LLUUID uuid; + struct Compare + { + // lhs < rhs + typedef const lru_data* lru_data_ptr; + bool operator()(const lru_data_ptr& a, const lru_data_ptr& b) const + { + if (!(a->time < b->time)) + return true; + else if (!(b->time < a->time)) + return false; + else + return a->index < b->index; + } + }; +}; + +// Called from either the main thread or the worker thread +void LLTextureCache::readHeaderCache(apr_pool_t* poolp) +{ + LLMutexLock lock(&mHeaderMutex); + mHeaderEntriesInfo.mVersion = 0.f; + mHeaderEntriesInfo.mEntries = 0; + if (ll_apr_file_exists(mHeaderEntriesFileName, poolp)) + { + ll_apr_file_read_ex(mHeaderEntriesFileName, poolp, + (U8*)&mHeaderEntriesInfo, 0, sizeof(EntriesInfo)); + } + if (mHeaderEntriesInfo.mVersion != sHeaderCacheVersion) + { + if (!mReadOnly) + { + // Info with 0 entries + mHeaderEntriesInfo.mVersion = sHeaderCacheVersion; + ll_apr_file_write_ex(mHeaderEntriesFileName, poolp, + (U8*)&mHeaderEntriesInfo, 0, sizeof(EntriesInfo)); + } + } + else + { + S32 num_entries = mHeaderEntriesInfo.mEntries; + if (num_entries) + { + Entry* entries = new Entry[num_entries]; + ll_apr_file_read_ex(mHeaderEntriesFileName, poolp, + (U8*)entries, sizeof(EntriesInfo), num_entries*sizeof(Entry)); + typedef std::set lru_set_t; + lru_set_t lru; + for (S32 i=0; i= 0) // -1 indicates erased entry, skip + { + const LLUUID& id = entries[i].mID; + lru.insert(new lru_data(entries[i].mTime, i, id)); + mHeaderIDMap[id] = i; + } + } + mLRU.clear(); + S32 lru_entries = sCacheMaxEntries / 10; + for (lru_set_t::iterator iter = lru.begin(); iter != lru.end(); ++iter) + { + lru_data* data = *iter; + mLRU[data->index] = data->uuid; + if (--lru_entries <= 0) + break; + } + for_each(lru.begin(), lru.end(), DeletePointer()); + delete[] entries; + } + } +} + +////////////////////////////////////////////////////////////////////////////// + +void LLTextureCache::purgeAllTextures(bool purge_directories) +{ + if (!mReadOnly) + { + const char* subdirs = "0123456789abcdef"; + std::string delem = gDirUtilp->getDirDelimiter(); + std::string mask = delem + "*"; + for (S32 i=0; i<16; i++) + { + std::string dirname = mTexturesDirName + delem + subdirs[i]; + gDirUtilp->deleteFilesInDir(dirname.c_str(),mask); + if (purge_directories) + { + LLFile::rmdir(dirname.c_str()); + } + } + ll_apr_file_remove(mTexturesDirEntriesFileName, NULL); + if (purge_directories) + { + LLFile::rmdir(mTexturesDirName.c_str()); + } + } + mTexturesSizeMap.clear(); +} + +void LLTextureCache::purgeTextures(bool validate) +{ + if (mReadOnly) + { + return; + } + + LLMutexLock lock(&mHeaderMutex); + + S32 filesize = ll_apr_file_size(mTexturesDirEntriesFileName, NULL); + S32 num_entries = filesize / sizeof(Entry); + if (num_entries * (S32)sizeof(Entry) != filesize) + { + llwarns << "Bad cache file: " << mTexturesDirEntriesFileName << " Purging." << llendl; + purgeAllTextures(false); + return; + } + if (num_entries == 0) + { + return; // nothing to do + } + + Entry* entries = new Entry[num_entries]; + S32 bytes_read = ll_apr_file_read_ex(mTexturesDirEntriesFileName, NULL, + (U8*)entries, 0, num_entries*sizeof(Entry)); + if (bytes_read != filesize) + { + llwarns << "Bad cache file (2): " << mTexturesDirEntriesFileName << " Purging." << llendl; + purgeAllTextures(false); + return; + } + + llinfos << "TEXTURE CACHE: Reading Entries..." << llendl; + + std::map entry_idx_map; + S64 total_size = 0; + for (S32 idx=0; idx::iterator iter = entry_idx_map.find(id); + if (iter != entry_idx_map.end()) + { + // Newer entry replacing older entry + S32 pidx = iter->second; + total_size -= entries[pidx].mSize; + entries[pidx].mSize = 0; // flag: skip older entry + } + entry_idx_map[id] = idx; + total_size += entries[idx].mSize; + } + + U32 validate_idx = 0; + if (validate) + { + validate_idx = gSavedSettings.getU32("CacheValidateCounter"); + U32 next_idx = (++validate_idx) % 256; + gSavedSettings.setU32("CacheValidateCounter", next_idx); + llinfos << "TEXTURE CACHE: Validating: " << validate_idx << llendl; + } + + S64 min_cache_size = (sCacheMaxTexturesSize * 9) / 10; + S32 purge_count = 0; + S32 next_idx = 0; + for (S32 idx=0; idx= min_cache_size) + { + purge_entry = true; + } + else if (validate) + { + // make sure file exists and is the correct size + S32 uuididx = entries[idx].mID.mData[0]; + if (uuididx == validate_idx) + { +// llinfos << "Validating: " << filename << "Size: " << entries[idx].mSize << llendl; + S32 bodysize = ll_apr_file_size(filename, NULL); + if (bodysize != entries[idx].mSize) + { + llwarns << "TEXTURE CACHE BODY HAS BAD SIZE: " << bodysize << " != " << entries[idx].mSize + << filename << llendl; + purge_entry = true; + } + } + } + if (purge_entry) + { + purge_count++; +// llinfos << "PURGING: " << filename << llendl; + ll_apr_file_remove(filename, NULL); + total_size -= entries[idx].mSize; + entries[idx].mSize = 0; + } + else + { + if (next_idx != idx) + { + entries[next_idx] = entries[idx]; + } + ++next_idx; + } + } + num_entries = next_idx; + + llinfos << "TEXTURE CACHE: Writing Entries: " << num_entries << llendl; + + ll_apr_file_remove(mTexturesDirEntriesFileName, NULL); + ll_apr_file_write_ex(mTexturesDirEntriesFileName, NULL, + (U8*)&entries[0], 0, num_entries*sizeof(Entry)); + + mTexturesSizeTotal = 0; + mTexturesSizeMap.clear(); + for (S32 idx=0; idxsecond; + } + return res; +} + +LLTextureCacheWorker* LLTextureCache::getWriter(handle_t handle) +{ + LLTextureCacheWorker* res = NULL; + handle_map_t::iterator iter = mWriters.find(handle); + if (iter != mWriters.end()) + { + res = iter->second; + } + return res; +} + +////////////////////////////////////////////////////////////////////////////// + +// Called from work thread +S32 LLTextureCache::getHeaderCacheEntry(const LLUUID& id, bool touch, S32* imagesize) +{ + bool retry = false; + S32 idx = -1; + + { + LLMutexLock lock(&mHeaderMutex); + id_map_t::iterator iter = mHeaderIDMap.find(id); + if (iter != mHeaderIDMap.end()) + { + idx = iter->second; + } + else if (touch && !mReadOnly) + { + if (mHeaderEntriesInfo.mEntries < sCacheMaxEntries) + { + // Add an entry + idx = mHeaderEntriesInfo.mEntries++; + mHeaderIDMap[id] = idx; + // Update Info + ll_apr_file_write_ex(mHeaderEntriesFileName, getFileAPRPool(), + (U8*)&mHeaderEntriesInfo, 0, sizeof(EntriesInfo)); + } + else if (!mLRU.empty()) + { + idx = mLRU.begin()->first; // will be erased below + const LLUUID& oldid = mLRU.begin()->second; + mHeaderIDMap.erase(oldid); + mTexturesSizeMap.erase(oldid); + mHeaderIDMap[id] = idx; + } + else + { + idx = -1; + retry = true; + } + } + if (idx >= 0) + { + if (touch && !mReadOnly) + { + // Update the lru entry + mLRU.erase(idx); + llassert_always(imagesize && *imagesize > 0); + Entry* entry = new Entry(id, *imagesize, time(NULL)); + S32 offset = sizeof(EntriesInfo) + idx * sizeof(Entry); + ll_apr_file_write_ex(mHeaderEntriesFileName, getFileAPRPool(), + (U8*)entry, offset, sizeof(Entry)); + delete entry; + } + else if (imagesize) + { + // Get the image size + Entry entry; + S32 offset = sizeof(EntriesInfo) + idx * sizeof(Entry); + ll_apr_file_read_ex(mHeaderEntriesFileName, getFileAPRPool(), + (U8*)&entry, offset, sizeof(Entry)); + *imagesize = entry.mSize; + } + } + } + if (retry) + { + readHeaderCache(getFileAPRPool()); // updates the lru + llassert_always(!mLRU.empty() || mHeaderEntriesInfo.mEntries < sCacheMaxEntries); + idx = getHeaderCacheEntry(id, touch, imagesize); // assert above ensures no inf. recursion + } + return idx; +} + +////////////////////////////////////////////////////////////////////////////// + +// Calls from texture pipeline thread (i.e. LLTextureFetch) + +LLTextureCache::handle_t LLTextureCache::readFromCache(const LLUUID& id, U32 priority, + S32 offset, S32 size, ReadResponder* responder) +{ + // Note: checking to see if an entry exists can cause a stall, + // so let the thread handle it + LLMutexLock lock(&mWorkersMutex); + LLTextureCacheWorker* worker = new LLTextureCacheWorker(this, priority, id, + NULL, size, offset, 0, + responder); + handle_t handle = worker->read(); + mReaders[handle] = worker; + return handle; +} + +bool LLTextureCache::readComplete(handle_t handle, bool abort) +{ + lockWorkers(); + handle_map_t::iterator iter = mReaders.find(handle); + llassert_always(iter != mReaders.end()); + LLTextureCacheWorker* worker = iter->second; + bool res = worker->complete(); + if (res || abort) + { + mReaders.erase(handle); + unlockWorkers(); + worker->scheduleDelete(); + return true; + } + else + { + unlockWorkers(); + return false; + } +} + +LLTextureCache::handle_t LLTextureCache::writeToCache(const LLUUID& id, U32 priority, + U8* data, S32 datasize, S32 imagesize, + WriteResponder* responder) +{ + if (mReadOnly) + { + return LLWorkerThread::nullHandle(); + } + if (mDoPurge) + { + // NOTE: This may cause an occasional hiccup, + // but it really needs to be done on the control thread + // (i.e. here) + purgeTextures(false); + mDoPurge = FALSE; + } + if (datasize >= TEXTURE_CACHE_ENTRY_SIZE) + { + LLMutexLock lock(&mWorkersMutex); + llassert_always(imagesize > 0); + LLTextureCacheWorker* worker = new LLTextureCacheWorker(this, priority, id, + data, datasize, 0, + imagesize, responder); + handle_t handle = worker->write(); + mWriters[handle] = worker; + return handle; + } + return LLWorkerThread::nullHandle(); +} + +bool LLTextureCache::writeComplete(handle_t handle, bool abort) +{ + lockWorkers(); + handle_map_t::iterator iter = mWriters.find(handle); + llassert_always(iter != mWriters.end()); + LLTextureCacheWorker* worker = iter->second; + if (worker->complete() || abort) + { + mWriters.erase(handle); + unlockWorkers(); + worker->scheduleDelete(); + return true; + } + else + { + unlockWorkers(); + return false; + } +} + +void LLTextureCache::prioritizeWrite(handle_t handle) +{ + // Don't prioritize yet, we might be working on this now + // which could create a deadlock + mPrioritizeWriteList.push_back(handle); +} + +////////////////////////////////////////////////////////////////////////////// + +// Called from MAIN thread (endWork()) + +bool LLTextureCache::removeHeaderCacheEntry(const LLUUID& id) +{ + if (mReadOnly) + { + return false; + } + LLMutexLock lock(&mHeaderMutex); + id_map_t::iterator iter = mHeaderIDMap.find(id); + if (iter != mHeaderIDMap.end()) + { + S32 idx = iter->second; + if (idx >= 0) + { + Entry* entry = new Entry(id, -1, time(NULL)); + S32 offset = sizeof(EntriesInfo) + idx * sizeof(Entry); + ll_apr_file_write_ex(mHeaderEntriesFileName, NULL, + (U8*)entry, offset, sizeof(Entry)); + delete entry; + mLRU[idx] = id; + mHeaderIDMap.erase(id); + mTexturesSizeMap.erase(id); + return true; + } + } + return false; +} + +void LLTextureCache::removeFromCache(const LLUUID& id) +{ + llwarns << "Removing texture from cache: " << id << llendl; + if (!mReadOnly) + { + removeHeaderCacheEntry(id); + ll_apr_file_remove(getTextureFileName(id), NULL); + } +} + +////////////////////////////////////////////////////////////////////////////// + +LLTextureCache::ReadResponder::ReadResponder() + : mImageSize(0), + mImageLocal(FALSE) +{ +} + +void LLTextureCache::ReadResponder::setData(U8* data, S32 datasize, S32 imagesize, S32 imageformat, BOOL imagelocal) +{ + if (mFormattedImage.notNull()) + { + llassert_always(mFormattedImage->getCodec() == imageformat); + mFormattedImage->appendData(data, datasize); + } + else + { + mFormattedImage = LLImageFormatted::createFromType(imageformat); + mFormattedImage->setData(data,datasize); + } + mImageSize = imagesize; + mImageLocal = imagelocal; +} + +////////////////////////////////////////////////////////////////////////////// diff --git a/indra/newview/lltexturecache.h b/indra/newview/lltexturecache.h index 3b16b26b4a..f9eb8cb177 100644 --- a/indra/newview/lltexturecache.h +++ b/indra/newview/lltexturecache.h @@ -1,149 +1,149 @@ -/** - * @file lltexturecache.h - * @brief Object for managing texture cachees. - * - * Copyright (c) 2000-$CurrentYear$, Linden Research, Inc. - * $License$ - */ - -#ifndef LL_LLTEXTURECACHE_ -#define LL_LLTEXTURECACHE_H - -#include "lldir.h" -#include "llstl.h" -#include "llstring.h" -#include "lluuid.h" - -#include "llworkerthread.h" - -class LLTextureCacheWorker; - -class LLTextureCache : public LLWorkerThread -{ - friend class LLTextureCacheWorker; - -public: - - class Responder : public LLResponder - { - public: - virtual void setData(U8* data, S32 datasize, S32 imagesize, S32 imageformat, BOOL imagelocal) = 0; - }; - - class ReadResponder : public Responder - { - public: - ReadResponder(); - void setData(U8* data, S32 datasize, S32 imagesize, S32 imageformat, BOOL imagelocal); - void setImage(LLImageFormatted* image) { mFormattedImage = image; } - protected: - LLPointer mFormattedImage; - S32 mImageSize; - BOOL mImageLocal; - }; - - class WriteResponder : public Responder - { - void setData(U8* data, S32 datasize, S32 imagesize, S32 imageformat, BOOL imagelocal) - { - // not used - } - }; - - LLTextureCache(bool threaded); - ~LLTextureCache(); - - /*virtual*/ S32 update(U32 max_time_ms); - - void purgeCache(ELLPath location); - S64 initCache(ELLPath location, S64 maxsize, BOOL read_only); - - handle_t readFromCache(const LLUUID& id, U32 priority, S32 offset, S32 size, - ReadResponder* responder); - bool readComplete(handle_t handle, bool abort); - handle_t writeToCache(const LLUUID& id, U32 priority, U8* data, S32 datasize, S32 imagesize, - WriteResponder* responder); - bool writeComplete(handle_t handle, bool abort = false); - void prioritizeWrite(handle_t handle); - - void removeFromCache(const LLUUID& id); - - // For LLTextureCacheWorker::Responder - LLTextureCacheWorker* getReader(handle_t handle); - LLTextureCacheWorker* getWriter(handle_t handle); - void lockWorkers() { mWorkersMutex.lock(); } - void unlockWorkers() { mWorkersMutex.unlock(); } - - // debug - S32 getNumReads() { return mReaders.size(); } - S32 getNumWrites() { return mWriters.size(); } - -protected: - // Accessed by LLTextureCacheWorker - apr_pool_t* getFileAPRPool() { return mFileAPRPool; } - bool appendToTextureEntryList(const LLUUID& id, S32 size); - std::string getLocalFileName(const LLUUID& id); - std::string getTextureFileName(const LLUUID& id); - -private: - void setDirNames(ELLPath location); - void readHeaderCache(apr_pool_t* poolp = NULL); - void purgeAllTextures(bool purge_directories); - void purgeTextures(bool validate); - S32 getHeaderCacheEntry(const LLUUID& id, bool touch, S32* imagesize = NULL); - bool removeHeaderCacheEntry(const LLUUID& id); - void lockHeaders() { mHeaderMutex.lock(); } - void unlockHeaders() { mHeaderMutex.unlock(); } - -private: - // Internal - LLMutex mWorkersMutex; - LLMutex mHeaderMutex; - apr_pool_t* mFileAPRPool; - - typedef std::map handle_map_t; - handle_map_t mReaders; - handle_map_t mWriters; - std::vector mPrioritizeWriteList; - - BOOL mReadOnly; - - // Entries - struct EntriesInfo - { - F32 mVersion; - U32 mEntries; - }; - struct Entry - { - Entry() {} - Entry(const LLUUID& id, S32 size, U32 time) : mID(id), mSize(size), mTime(time) {} - LLUUID mID; // 128 bits - S32 mSize; // total size of image if known (NOT size cached) - U32 mTime; // seconds since 1/1/1970 - }; - - // HEADERS (Include first mip) - std::string mHeaderEntriesFileName; - std::string mHeaderDataFileName; - EntriesInfo mHeaderEntriesInfo; - typedef std::map index_map_t; - index_map_t mLRU; // index, id; stored as a map for fast removal - typedef std::map id_map_t; - id_map_t mHeaderIDMap; - - // BODIES (TEXTURES minus headers) - std::string mTexturesDirName; - std::string mTexturesDirEntriesFileName; - typedef std::map size_map_t; - size_map_t mTexturesSizeMap; - S64 mTexturesSizeTotal; - LLAtomic32 mDoPurge; - - // Statics - static F32 sHeaderCacheVersion; - static U32 sCacheMaxEntries; - static S64 sCacheMaxTexturesSize; -}; - -#endif // LL_LLTEXTURECACHE_H +/** + * @file lltexturecache.h + * @brief Object for managing texture cachees. + * + * Copyright (c) 2000-$CurrentYear$, Linden Research, Inc. + * $License$ + */ + +#ifndef LL_LLTEXTURECACHE_ +#define LL_LLTEXTURECACHE_H + +#include "lldir.h" +#include "llstl.h" +#include "llstring.h" +#include "lluuid.h" + +#include "llworkerthread.h" + +class LLTextureCacheWorker; + +class LLTextureCache : public LLWorkerThread +{ + friend class LLTextureCacheWorker; + +public: + + class Responder : public LLResponder + { + public: + virtual void setData(U8* data, S32 datasize, S32 imagesize, S32 imageformat, BOOL imagelocal) = 0; + }; + + class ReadResponder : public Responder + { + public: + ReadResponder(); + void setData(U8* data, S32 datasize, S32 imagesize, S32 imageformat, BOOL imagelocal); + void setImage(LLImageFormatted* image) { mFormattedImage = image; } + protected: + LLPointer mFormattedImage; + S32 mImageSize; + BOOL mImageLocal; + }; + + class WriteResponder : public Responder + { + void setData(U8* data, S32 datasize, S32 imagesize, S32 imageformat, BOOL imagelocal) + { + // not used + } + }; + + LLTextureCache(bool threaded); + ~LLTextureCache(); + + /*virtual*/ S32 update(U32 max_time_ms); + + void purgeCache(ELLPath location); + S64 initCache(ELLPath location, S64 maxsize, BOOL read_only); + + handle_t readFromCache(const LLUUID& id, U32 priority, S32 offset, S32 size, + ReadResponder* responder); + bool readComplete(handle_t handle, bool abort); + handle_t writeToCache(const LLUUID& id, U32 priority, U8* data, S32 datasize, S32 imagesize, + WriteResponder* responder); + bool writeComplete(handle_t handle, bool abort = false); + void prioritizeWrite(handle_t handle); + + void removeFromCache(const LLUUID& id); + + // For LLTextureCacheWorker::Responder + LLTextureCacheWorker* getReader(handle_t handle); + LLTextureCacheWorker* getWriter(handle_t handle); + void lockWorkers() { mWorkersMutex.lock(); } + void unlockWorkers() { mWorkersMutex.unlock(); } + + // debug + S32 getNumReads() { return mReaders.size(); } + S32 getNumWrites() { return mWriters.size(); } + +protected: + // Accessed by LLTextureCacheWorker + apr_pool_t* getFileAPRPool() { return mFileAPRPool; } + bool appendToTextureEntryList(const LLUUID& id, S32 size); + std::string getLocalFileName(const LLUUID& id); + std::string getTextureFileName(const LLUUID& id); + +private: + void setDirNames(ELLPath location); + void readHeaderCache(apr_pool_t* poolp = NULL); + void purgeAllTextures(bool purge_directories); + void purgeTextures(bool validate); + S32 getHeaderCacheEntry(const LLUUID& id, bool touch, S32* imagesize = NULL); + bool removeHeaderCacheEntry(const LLUUID& id); + void lockHeaders() { mHeaderMutex.lock(); } + void unlockHeaders() { mHeaderMutex.unlock(); } + +private: + // Internal + LLMutex mWorkersMutex; + LLMutex mHeaderMutex; + apr_pool_t* mFileAPRPool; + + typedef std::map handle_map_t; + handle_map_t mReaders; + handle_map_t mWriters; + std::vector mPrioritizeWriteList; + + BOOL mReadOnly; + + // Entries + struct EntriesInfo + { + F32 mVersion; + U32 mEntries; + }; + struct Entry + { + Entry() {} + Entry(const LLUUID& id, S32 size, U32 time) : mID(id), mSize(size), mTime(time) {} + LLUUID mID; // 128 bits + S32 mSize; // total size of image if known (NOT size cached) + U32 mTime; // seconds since 1/1/1970 + }; + + // HEADERS (Include first mip) + std::string mHeaderEntriesFileName; + std::string mHeaderDataFileName; + EntriesInfo mHeaderEntriesInfo; + typedef std::map index_map_t; + index_map_t mLRU; // index, id; stored as a map for fast removal + typedef std::map id_map_t; + id_map_t mHeaderIDMap; + + // BODIES (TEXTURES minus headers) + std::string mTexturesDirName; + std::string mTexturesDirEntriesFileName; + typedef std::map size_map_t; + size_map_t mTexturesSizeMap; + S64 mTexturesSizeTotal; + LLAtomic32 mDoPurge; + + // Statics + static F32 sHeaderCacheVersion; + static U32 sCacheMaxEntries; + static S64 sCacheMaxTexturesSize; +}; + +#endif // LL_LLTEXTURECACHE_H diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp index db747c60fc..4c90c3624b 100644 --- a/indra/newview/lltexturefetch.cpp +++ b/indra/newview/lltexturefetch.cpp @@ -1205,9 +1205,9 @@ bool LLTextureFetchWorker::writeToCacheComplete() LLTextureFetch::LLTextureFetch(LLTextureCache* cache, bool threaded) : LLWorkerThread("TextureFetch", threaded), mDebugCount(0), - mDebugPause(0), - mTextureCache(cache), - mQueueMutex(getAPRPool()) + mDebugPause(FALSE), + mQueueMutex(getAPRPool()), + mTextureCache(cache) { } diff --git a/indra/newview/lltexturefetch.h b/indra/newview/lltexturefetch.h index b3510d9e82..7cf7cb45f2 100644 --- a/indra/newview/lltexturefetch.h +++ b/indra/newview/lltexturefetch.h @@ -82,4 +82,4 @@ private: LLFrameTimer mNetworkTimer; }; -#endif LL_LLTEXTUREFETCH_H +#endif // LL_LLTEXTUREFETCH_H diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp index 837eaa90e9..f6fa23c6f6 100644 --- a/indra/newview/llviewerdisplay.cpp +++ b/indra/newview/llviewerdisplay.cpp @@ -582,6 +582,11 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield) gPipeline.stateSort(hud_cam); } + if (LLVertexBuffer::sEnableVBOs) + { + LLImageGL::sBoundTextureMemory += LLVertexBuffer::sAllocatedBytes; + } + gPipeline.renderGeom(hud_cam); //restore type mask @@ -716,9 +721,10 @@ void render_ui_and_swap() } { -// LLFastTimer ftm(LLFastTimer::FTM_TEMP6); - LLVertexBuffer::clientCopy(); + LLFastTimer ftm(LLFastTimer::FTM_CLIENT_COPY); + LLVertexBuffer::clientCopy(0.016); } + } } diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 275db0f906..64560efd67 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -1134,6 +1134,9 @@ void init_debug_rendering_menu(LLMenuGL* menu) sub_menu->append(new LLMenuItemCheckGL("Texture Area (sqrt(A))",&LLPipeline::toggleRenderDebug, NULL, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_TEXTURE_AREA)); + sub_menu->append(new LLMenuItemCheckGL("Face Area (sqrt(A))",&LLPipeline::toggleRenderDebug, NULL, + &LLPipeline::toggleRenderDebugControl, + (void*)LLPipeline::RENDER_DEBUG_FACE_AREA)); sub_menu->append(new LLMenuItemCheckGL("Pick Render", &LLPipeline::toggleRenderDebug, NULL, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_PICKING)); diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 8ed5406e85..6d4170e437 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -1357,7 +1357,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) // Make sure the binary bucket is big enough to hold the header // and a null terminated item name. - if ( (binary_bucket_size < (sizeof(notice_bucket_header_t) + sizeof(U8))) + if ( (binary_bucket_size < (S32)((sizeof(notice_bucket_header_t) + sizeof(U8)))) || (binary_bucket[binary_bucket_size - 1] != '\0') ) { llwarns << "Malformed group notice binary bucket" << llendl; diff --git a/indra/newview/llviewernetwork.cpp b/indra/newview/llviewernetwork.cpp index b02985ddfa..189b314e55 100644 --- a/indra/newview/llviewernetwork.cpp +++ b/indra/newview/llviewernetwork.cpp @@ -71,4 +71,4 @@ F32 gPacketDropPercentage = 0.f; F32 gInBandwidth = 0.f; F32 gOutBandwidth = 0.f; -unsigned char gMACAddress[MAC_ADDRESS_BYTES]; /* Flawfinder: ignore */ \ No newline at end of file +unsigned char gMACAddress[MAC_ADDRESS_BYTES]; /* Flawfinder: ignore */ diff --git a/indra/newview/llviewerparcelmgr.cpp b/indra/newview/llviewerparcelmgr.cpp index cd915317ba..ee29876274 100644 --- a/indra/newview/llviewerparcelmgr.cpp +++ b/indra/newview/llviewerparcelmgr.cpp @@ -2523,9 +2523,9 @@ LLParcelSelection::LLParcelSelection() : mParcel(NULL), mSelectedMultipleOwners(FALSE), mWholeParcelSelected(FALSE), - mSelectedPublicCount(0), mSelectedSelfCount(0), - mSelectedOtherCount(0) + mSelectedOtherCount(0), + mSelectedPublicCount(0) { } @@ -2533,9 +2533,9 @@ LLParcelSelection::LLParcelSelection(LLParcel* parcel) : mParcel(parcel), mSelectedMultipleOwners(FALSE), mWholeParcelSelected(FALSE), - mSelectedPublicCount(0), mSelectedSelfCount(0), - mSelectedOtherCount(0) + mSelectedOtherCount(0), + mSelectedPublicCount(0) { } @@ -2570,4 +2570,4 @@ LLParcelSelection* get_null_parcel_selection() { static LLParcelSelectionHandle null_ptr = new LLParcelSelection(); return null_ptr; -} \ No newline at end of file +} diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index aebcfdb9ce..36c08321ed 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -1842,13 +1842,6 @@ void LLViewerWindow::reshape(S32 width, S32 height) gViewerStats->setStat(LLViewerStats::ST_WINDOW_WIDTH, (F64)width); gViewerStats->setStat(LLViewerStats::ST_WINDOW_HEIGHT, (F64)height); - - //reposition HUD attachments - LLVOAvatar* avatarp = gAgent.getAvatarObject(); - if (avatarp) - { - avatarp->resetHUDAttachments(); - } } } diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 507a1468c7..afeffa0aec 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -748,9 +748,9 @@ LLVOAvatar::LLVOAvatar( mLastSkirtBakedID( IMG_DEFAULT_AVATAR ), mIsDummy(FALSE), mSpecialRenderMode(0), + mTurning(FALSE), mPelvisToFoot(0.f), mLastSkeletonSerialNum( 0 ), - mTurning(FALSE), mHeadOffset(), mIsSitting(FALSE), mTimeVisible(), @@ -3005,8 +3005,12 @@ void LLVOAvatar::updateCharacter(LLAgent &agent) { F32 aspect = gCamera->getAspect(); LLVector3 scale(1.f, aspect, 1.f); - mScreenp->setScale(scale); - mScreenp->updateWorldMatrixChildren(); + if (mScreenp->getScale() != scale) + { + mScreenp->setScale(scale); + mScreenp->updateWorldMatrixChildren(); + resetHUDAttachments(); + } } // clear debug text diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 2d898a1a5d..d08c5311d7 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -244,7 +244,7 @@ BOOL LLVOVolume::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) S32 result; if (result = mTextureAnimp->animateTextures(off_s, off_t, scale_s, scale_t, rot)) { - mTexAnimMode = result | mTextureAnimp->mMode; + mTexAnimMode = mTextureAnimp->mMode | result; S32 start, end; if (mTextureAnimp->mFace == -1) @@ -309,6 +309,13 @@ BOOL LLVOVolume::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) tex_mat.translate(trans); } } + else + { + if (mTextureAnimp->mRate == 0) + { + mTexAnimMode = 0; + } + } } // Dispatch to implementation @@ -349,17 +356,18 @@ void LLVOVolume::updateTextures() mTextureUpdateTimer.reset(); + F32 old_area = mPixelArea; mPixelArea = 0.f; - const S32 num_faces = mDrawable->getNumFaces(); + const S32 num_faces = mDrawable->getNumFaces(); F32 min_vsize=999999999.f, max_vsize=0.f; for (S32 i = 0; i < num_faces; i++) { LLFace* face = mDrawable->getFace(i); const LLTextureEntry *te = face->getTextureEntry(); LLViewerImage *imagep = face->getTexture(); - - if (!imagep || !te) + if (!imagep || !te || + face->mExtents[0] == face->mExtents[1]) { continue; } @@ -392,11 +400,12 @@ void LLVOVolume::updateTextures() if (pri < min_vsize) min_vsize = pri; if (pri > max_vsize) max_vsize = pri; } - // U8 bump = te->getBumpmap(); - // if( te && bump) - // { - // gBumpImageList.addTextureStats( bump, imagep->getID(), vsize, 1, 1); - // } + else if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_FACE_AREA)) + { + F32 pri = mPixelArea; + if (pri < min_vsize) min_vsize = pri; + if (pri > max_vsize) max_vsize = pri; + } } if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_AREA)) @@ -407,15 +416,22 @@ void LLVOVolume::updateTextures() { setDebugText(llformat("%.0f:%.0f", fsqrtf(min_vsize),fsqrtf(max_vsize))); } + else if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_FACE_AREA)) + { + setDebugText(llformat("%.0f:%.0f", fsqrtf(min_vsize),fsqrtf(max_vsize))); + } + + if (mPixelArea == 0) + { //flexi phasing issues make this happen + mPixelArea = old_area; + } } F32 LLVOVolume::getTextureVirtualSize(LLFace* face) { //get area of circle around face LLVector3 center = face->getPositionAgent(); - LLVector3 size = //isFlexible() ? - // getScale()*3.f : - (face->mExtents[1] - face->mExtents[0]) * 0.5f; + LLVector3 size = (face->mExtents[1] - face->mExtents[0]) * 0.5f; F32 face_area = LLPipeline::calcPixelArea(center, size, *gCamera); @@ -585,9 +601,6 @@ BOOL LLVOVolume::calcLOD() return FALSE; } - //update textures here as well - updateTextures(); - S32 cur_detail = 0; F32 radius = mVolumep->mLODScaleBias.scaledVec(getScale()).magVec(); @@ -689,6 +702,17 @@ void LLVOVolume::updateFaceFlags() } } +void LLVOVolume::setParent(LLViewerObject* parent) +{ + LLViewerObject::setParent(parent); + if (mDrawable) + { + gPipeline.markMoved(mDrawable); + mVolumeChanged = TRUE; + gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, TRUE); + } +} + // NOTE: regenFaces() MUST be followed by genTriangles()! void LLVOVolume::regenFaces() { @@ -748,6 +772,8 @@ BOOL LLVOVolume::genBBoxes(BOOL force_global) { mDrawable->setSpatialExtents(min,max); mDrawable->setPositionGroup((min+max)*0.5f); + //bounding boxes changed, update texture priorities + updateTextures(); } updateRadius(); @@ -1918,8 +1944,10 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, draw_vec[idx]->mVertexBuffer == facep->mVertexBuffer && draw_vec[idx]->mEnd == facep->getGeomIndex()-1 && draw_vec[idx]->mTexture == tex && - //draw_vec[idx]->mEnd - draw_vec[idx]->mStart + facep->getGeomCount() <= (U32) gGLManager.mGLMaxVertexRange && - //draw_vec[idx]->mCount + facep->getIndicesCount() <= (U32) gGLManager.mGLMaxIndexRange && +#if LL_DARWIN + draw_vec[idx]->mEnd - draw_vec[idx]->mStart + facep->getGeomCount() <= (U32) gGLManager.mGLMaxVertexRange && + draw_vec[idx]->mCount + facep->getIndicesCount() <= (U32) gGLManager.mGLMaxIndexRange && +#endif draw_vec[idx]->mFullbright == fullbright && draw_vec[idx]->mBump == bump && draw_vec[idx]->mTextureMatrix == tex_mat) @@ -2220,7 +2248,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) registerFace(group, facep, LLRenderPass::PASS_BUMP); } - if (!force_simple && vobj->getIsLight()) + if (vobj->getIsLight()) { registerFace(group, facep, LLRenderPass::PASS_GLOW); } diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h index 3eb8ad6c14..76b469e6aa 100644 --- a/indra/newview/llvovolume.h +++ b/indra/newview/llvovolume.h @@ -79,7 +79,7 @@ public: /*virtual*/ BOOL isHUDAttachment() const; void generateSilhouette(LLSelectNode* nodep, const LLVector3& view_point); - + /*virtual*/ void setParent(LLViewerObject* parent); F32 getIndividualRadius() { return mRadius; } S32 getLOD() const { return mLOD; } const LLVector3 getPivotPositionAgent() const; diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 250b9bc7df..d7abae32c8 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -212,6 +212,8 @@ BOOL LLPipeline::sSkipUpdate = FALSE; BOOL LLPipeline::sDynamicReflections = FALSE; LLPipeline::LLPipeline() : + mCubeBuffer(NULL), + mCubeList(0), mVertexShadersEnabled(FALSE), mVertexShadersLoaded(0), mLastRebuildPool(NULL), @@ -225,9 +227,7 @@ LLPipeline::LLPipeline() : mSimplePool(NULL), mBumpPool(NULL), mLightMask(0), - mLightMovingMask(0), - mCubeBuffer(NULL), - mCubeList(0) + mLightMovingMask(0) { } @@ -1710,7 +1710,6 @@ void LLPipeline::updateMove() F32 LLPipeline::calcPixelArea(LLVector3 center, LLVector3 size, LLCamera &camera) { LLVector3 lookAt = center - camera.getOrigin(); - LLVector3 cross_vec = size * 2.f; F32 dist = lookAt.magVec(); //ramp down distance for nearby objects @@ -1722,7 +1721,7 @@ F32 LLPipeline::calcPixelArea(LLVector3 center, LLVector3 size, LLCamera &camera } //get area of circle around node - F32 app_angle = atanf((cross_vec*0.5f).magVec()/dist); + F32 app_angle = atanf(size.magVec()/dist); F32 radius = app_angle*LLDrawable::sCurPixelAngle; return radius*radius * 3.14159f; } @@ -2196,10 +2195,12 @@ void LLPipeline::stateSort(LLSpatialGroup* group, LLCamera& camera) } } +#if !LL_DARWIN if (gFrameTimeSeconds - group->mLastUpdateTime > 4.f) { group->makeStatic(); } +#endif } void LLPipeline::stateSort(LLSpatialBridge* bridge, LLCamera& camera) diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h index c744a29bec..0fadae0a61 100644 --- a/indra/newview/pipeline.h +++ b/indra/newview/pipeline.h @@ -325,7 +325,8 @@ public: RENDER_DEBUG_POINTS = 0x02000, RENDER_DEBUG_TEXTURE_PRIORITY = 0x04000, RENDER_DEBUG_TEXTURE_AREA = 0x08000, - RENDER_DEBUG_PARTICLES = 0x10000, + RENDER_DEBUG_FACE_AREA = 0x10000, + RENDER_DEBUG_PARTICLES = 0x20000, }; LLPointer mAlphaSizzleImagep; -- cgit v1.2.3